From 6eb67b1a3c3a94b4e646e3abdb0056312afeabc8 Mon Sep 17 00:00:00 2001 From: hide_d Date: Mon, 17 Sep 2018 02:57:44 +0900 Subject: [PATCH] =?UTF-8?q?=EC=9D=BC=EB=8B=A8=20push?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hwe/a_status.php | 2 +- hwe/b_battleCenter.php | 2 +- hwe/b_betting.php | 2 +- hwe/b_myBossInfo.php | 2 +- hwe/b_tournament.php | 2 +- hwe/func.old.php | 2984 ++++++++++++++++++++++++++ hwe/func.php | 256 +-- hwe/index.php | 2 +- hwe/proc.php | 4 +- hwe/sammo/DefaultActionTrigger.php | 2 +- hwe/sammo/General.php | 6 +- hwe/sammo/TriggerSpecialWar/None.php | 20 + hwe/sammo/TurnExecutionHelper.php | 232 +- hwe/sammo/iActionTrigger.php | 2 +- hwe/sql/schema.sql | 16 +- 15 files changed, 3269 insertions(+), 265 deletions(-) create mode 100644 hwe/func.old.php create mode 100644 hwe/sammo/TriggerSpecialWar/None.php diff --git a/hwe/a_status.php b/hwe/a_status.php index 4e5f3b35..a7178e4d 100644 --- a/hwe/a_status.php +++ b/hwe/a_status.php @@ -12,7 +12,7 @@ $gameStor = KVStorage::getStorage($db, 'game_env'); $connect=$db->get(); increaseRefresh("세력도", 2); -checkTurn(); +TurnExecutionHelper::executeAllCommand(); $mapTheme = $gameStor->map_theme??'che'; diff --git a/hwe/b_battleCenter.php b/hwe/b_battleCenter.php index 99be6501..149980d3 100644 --- a/hwe/b_battleCenter.php +++ b/hwe/b_battleCenter.php @@ -28,7 +28,7 @@ $connect=$db->get(); increaseRefresh("감찰부", 2); //전투 추진을 위해 갱신 -checkTurn(); +TurnExecutionHelper::executeAllCommand(); $gameStor->resetCache(); $query = "select nation from general where no='$gen'"; diff --git a/hwe/b_betting.php b/hwe/b_betting.php index f89ad6f5..13b40dff 100644 --- a/hwe/b_betting.php +++ b/hwe/b_betting.php @@ -12,7 +12,7 @@ $gameStor = KVStorage::getStorage($db, 'game_env'); $connect=$db->get(); increaseRefresh("베팅장", 1); -checkTurn(); +TurnExecutionHelper::executeAllCommand(); $query = "select no,tournament,con,turntime,bet0+bet1+bet2+bet3+bet4+bet5+bet6+bet7+bet8+bet9+bet10+bet11+bet12+bet13+bet14+bet15 as bet from general where owner='{$userID}'"; $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect), ""); diff --git a/hwe/b_myBossInfo.php b/hwe/b_myBossInfo.php index da998868..2847a2bb 100644 --- a/hwe/b_myBossInfo.php +++ b/hwe/b_myBossInfo.php @@ -12,7 +12,7 @@ $connect=$db->get(); increaseRefresh("인사부", 1); //훼섭 추방을 위해 갱신 -checkTurn(); +TurnExecutionHelper::executeAllCommand(); $query = "select no,nation,level from general where owner='{$userID}'"; $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); diff --git a/hwe/b_tournament.php b/hwe/b_tournament.php index 013c615f..1bad6b0f 100644 --- a/hwe/b_tournament.php +++ b/hwe/b_tournament.php @@ -12,7 +12,7 @@ $gameStor = KVStorage::getStorage($db, 'game_env'); $connect=$db->get(); increaseRefresh("토너먼트", 1); -checkTurn(); +TurnExecutionHelper::executeAllCommand(); $query = "select no,tournament,con,turntime from general where owner='{$userID}'"; $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect), ""); diff --git a/hwe/func.old.php b/hwe/func.old.php new file mode 100644 index 00000000..7bffa121 --- /dev/null +++ b/hwe/func.old.php @@ -0,0 +1,2984 @@ +0, + 'name'=>'재야', + 'color'=>'#000000', + 'type'=>GameConst::$neutralNationType, + 'level'=>0, + 'capital'=>0 + ]; + } + + if($nationList === null){ + $nationAll = DB::db()->query("select nation, name, color, type, level, capital from nation"); + $nationList = Util::convertArrayToDict($nationAll, "nation"); + $nationList[-1] = $nationAll; + } + + if(isset($nationList[$nationID])){ + return $nationList[$nationID]; + } + return null; +} + +/** + * getNationStaticInfo() 함수의 국가 캐시를 초기화 + */ +function refreshNationStaticInfo(){ + getNationStaticInfo(null, true); +} + +/** + * getNationStaticInfo(-1) 의 단축형 + */ +function getAllNationStaticInfo(){ + return getNationStaticInfo(-1); +} + +function GetImageURL($imgsvr, $filepath='') { + if($imgsvr == 0) { + return ServConfig::getSharedIconPath($filepath); + } else { + return AppConf::getUserIconPathWeb($filepath); + } +} + +/** + * @param null|int $con 장수의 벌점 + * @param null|int $conlimit 최대 벌점 + */ +function checkLimit($con = null) { + $session = Session::getInstance(); + if($session->userGrade>=4){ + return 0; + } + + $db = DB::db(); + $gameStor = KVStorage::getStorage($db, 'game_env'); + + if($con === null){ + $con = $db->queryFirstField('SELECT con FROM general WHERE `owner`=%i', Session::getUserID()); + } + $conlimit = $gameStor->conlimit; + + if($con > $conlimit) { + return 2; + //접속제한 90%이면 경고문구 + } elseif($con > $conlimit * 0.9) { + return 1; + } else { + return 0; + } +} + +function getBlockLevel() { + return DB::db()->queryFirstField('select block from general where no = %i', Session::getInstance()->generalID); +} + +function getRandGenName() { + $first = array('가', '간', '감', '강', '고', '공', '공손', '곽', '관', '괴', '교', '금', '노', '뇌', '능', '도', '동', '두', + '등', '마', '맹', '문', '미', '반', '방', '부', '비', '사', '사마', '서', '설', '성', '소', '손', '송', '순', '신', '심', + '악', '안', '양', '엄', '여', '염', '오', '왕', '요', '우', '원', '위', '유', '육', '윤', '이', '장', '저', '전', '정', + '제갈', '조', '종', '주', '진', '채', '태사', '하', '하후', '학', '한', '향', '허', '호', '화', '황', + '공손', '손', '왕', '유', '장', '조'); + $last = array('가', '간', '강', '거', '건', '검', '견', '경', '공', '광', '권', '규', '녕', '단', '대', '도', '등', '람', + '량', '례', '로', '료', '모', '민', '박', '범', '보', '비', '사', '상', '색', '서', '소', '속', '송', '수', '순', '습', + '승', '양', '연', '영', '온', '옹', '완', '우', '웅', '월', '위', '유', '윤', '융', '이', '익', '임', '정', '제', '조', + '주', '준', '지', '찬', '책', '충', '탁', '택', '통', '패', '평', '포', '합', '해', '혁', '현', '화', '환', '회', '횡', + '후', '훈', '휴', '흠', '흥'); + + $firstname = $first[rand()%count($first)]; + $lastname = $last[rand()%count($last)]; + + $fullname = "{$firstname}{$lastname}"; + return $fullname; +} + + + +function cityInfo() { + $db = DB::db(); + $connect=$db->get(); + $userID = Session::getUserID(); + + $query = "select no,city from general where owner='{$userID}'"; + $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + $me = MYDB_fetch_array($result); + + // 도시 정보 + $city = getCity($me['city']); + + $nation = getNationStaticInfo($city['nation']); + + $pop = $city['pop'] / $city['pop2'] * 100; + $trust = $city['trust']; + $agri = $city['agri'] / $city['agri2'] * 100; + $comm = $city['comm'] / $city['comm2'] * 100; + $secu = $city['secu'] / $city['secu2'] * 100; + $def = $city['def'] / $city['def2'] * 100; + $wall = $city['wall'] / $city['wall2'] * 100; + if($city['trade'] == 0) { + $trade = 0; + $tradeStr = "상인없음"; + } else { + $trade = ($city['trade']-95) * 10; + $tradeStr = $city['trade'] . "%"; + } + + if(!$nation){ + $nation = getNationStaticInfo(0); + } + + if($nation['color'] == "" ) { $nation['color'] = "#000000"; } + echo " + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
【 ".CityConst::$regionMap[$city['region']]." | ".CityConst::$levelMap[$city['level']]." 】 {$city['name']}
"; + + if($city['nation'] == 0) { + echo "공 백 지"; + } else { + echo "지배 국가 【 {$nation['name']} 】"; + } + + if($city['gen1'] > 0) { + $query = "select name from general where no='{$city['gen1']}'"; + $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + $gen1 = MYDB_fetch_array($result); + } else { + $gen1 = ['name'=>'-']; + } + + if($city['gen2'] > 0) { + $query = "select name from general where no='{$city['gen2']}'"; + $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + $gen2 = MYDB_fetch_array($result); + } else { + $gen2 = ['name'=>'-']; + } + + if($city['gen3'] > 0) { + $query = "select name from general where no='{$city['gen3']}'"; + $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + $gen3 = MYDB_fetch_array($result); + } else { + $gen3 = ['name'=>'-']; + } + + echo " +
주민".bar($pop)."민심".bar($trust)."태수{$gen1['name']}
{$city['pop']}/{$city['pop2']}".round($city['trust'], 1)."
농업".bar($agri)."상업".bar($comm)."치안".bar($secu)."군사{$gen2['name']}
{$city['agri']}/{$city['agri2']}{$city['comm']}/{$city['comm2']}{$city['secu']}/{$city['secu2']}
수비".bar($def)."성벽".bar($wall)."시세".bar($trade)."시중{$gen3['name']}
{$city['def']}/{$city['def2']}{$city['wall']}/{$city['wall2']}{$tradeStr}
+"; +} + +function myNationInfo() { + $db = DB::db(); + $gameStor = KVStorage::getStorage($db, 'game_env'); + $connect=$db->get(); + $userID = Session::getUserID(); + + $admin = $gameStor->getValues(['startyear','year']); + + $query = "select no,nation from general where owner='{$userID}'"; + $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + $me = MYDB_fetch_array($result); + + $query = "select nation,name,color,power,msg,gold,rice,bill,rate,scout,war,sabotagelimit,surlimit,tech,level,type from nation where nation='{$me['nation']}'"; + $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + $nation = MYDB_fetch_array($result); + + $query = "select COUNT(*) as cnt, SUM(pop) as totpop, SUM(pop2) as maxpop from city where nation='{$nation['nation']}'"; // 도시 이름 목록 + $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + $city = MYDB_fetch_array($result); + + $query = "select COUNT(*) as cnt, SUM(crew) as totcrew,SUM(leader)*100 as maxcrew from general where nation='{$nation['nation']}'"; // 장수 목록 + $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + $general = MYDB_fetch_array($result); + + $query = "select name from general where nation='{$nation['nation']}' and level='12'"; + $genresult = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + $level12 = MYDB_fetch_array($genresult); + + $query = "select name from general where nation='{$nation['nation']}' and level='11'"; + $genresult = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + $level11 = MYDB_fetch_array($genresult); + + echo " + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
【재 야】"; } + else { echo "style='color:".newColor($nation['color']).";background-color:{$nation['color']};font-weight:bold;font-size:13px;text-align:center'>국가【 {$nation['name']} 】"; } + + echo " +
성 향".getNationType($nation['type'])." (".getNationType2($nation['type']).")
".getLevel(12, $nation['level'])."";echo $level12?$level12['name']:"-"; echo "".getLevel(11, $nation['level'])."";echo $level11?$level11['name']:"-"; echo "
총주민";echo $me['nation']==0?"해당 없음":"{$city['totpop']}/{$city['maxpop']}";echo "총병사";echo $me['nation']==0?"해당 없음":"{$general['totcrew']}/{$general['maxcrew']}"; echo "
국 고";echo $me['nation']==0?"해당 없음":"{$nation['gold']}";echo "병 량";echo $me['nation']==0?"해당 없음":"{$nation['rice']}";echo "
지급율"; + if($me['nation'] == 0) { + echo "해당 없음"; + } else { + echo $nation['bill']==0?"0 %":"{$nation['bill']} %"; + } + echo " + 세 율"; + if($me['nation'] == 0) { + echo "해당 없음"; + } else { + echo $nation['rate']==0?"0 %":"{$nation['rate']} %"; + } + + $techCall = getTechCall($nation['tech']); + + if(TechLimit($admin['startyear'], $admin['year'], $nation['tech'])) { $nation['tech'] = "".floor($nation['tech']).""; } + else { $nation['tech'] = "".floor($nation['tech']).""; } + + $nation['tech'] = "$techCall / {$nation['tech']}"; + + if($me['nation']==0){ + $nation['sabotagelimit'] = "해당 없음"; + $nation['surlimit'] = "해당 없음"; + $nation['scout'] = "해당 없음"; + $nation['war'] = "해당 없음"; + $nation['power'] = "해당 없음"; + } else { + if($nation['sabotagelimit'] != 0) { $nation['sabotagelimit'] = "{$nation['sabotagelimit']}턴"; } + else { $nation['sabotagelimit'] = "가 능"; } + + if($nation['surlimit'] != 0) { $nation['surlimit'] = "{$nation['surlimit']}턴"; } + else { $nation['surlimit'] = "가 능"; } + + if($nation['scout'] != 0) { $nation['scout'] = "금 지"; } + else { $nation['scout'] = "허 가"; } + + if($nation['war'] != 0) { $nation['war'] = "금 지"; } + else { $nation['war'] = "허 가"; } + + + } + + echo " +
속 령";echo $me['nation']==0?"-":"{$city['cnt']}"; echo "장 수";echo $me['nation']==0?"-":"{$general['cnt']}"; echo "
국 력{$nation['power']}기술력";echo $me['nation']==0?"-":"{$nation['tech']}"; echo "
전 략{$nation['sabotagelimit']}외 교{$nation['surlimit']}
임 관{$nation['scout']}전 쟁{$nation['war']}
+"; +} + +function addCommand($typename, $value, $valid = 1, $color=0) { + if($valid == 1) { + switch($color) { + case 0: + echo " + "; + break; + case 1: + echo " + "; + break; + case 2: + echo " + "; + break; + } + } else { + echo " + "; + } +} + +function commandGroup($typename, $type=0) { + if($type == 0) { + echo " + "; + } else { + echo " + "; + } +} + +function commandTable() { + $db = DB::db(); + $gameStor = KVStorage::getStorage($db, 'game_env'); + $connect=$db->get(); + $userID = Session::getUserID(); + + $admin = $gameStor->getValues(['startyear', 'year', 'month', 'develcost', 'scenario']); + + $query = "select no,npc,troop,city,nation,level,crew,makelimit,special from general where owner='{$userID}'"; + $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + $me = MYDB_fetch_array($result); + + $troop = getTroop($me['troop']); + $city = getCity($me['city']); + + $nationcount = count(getAllNationStaticInfo()); + + $query = "select city from city where nation='{$me['nation']}'"; + $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + $citycount = MYDB_num_rows($result); + + $query = "select no from general where nation='{$me['nation']}'"; + $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + $gencount = MYDB_num_rows($result); + + $nation = getNationStaticInfo($me['nation']); + + $develcost = $admin['develcost']; + $develcostA = $admin['develcost']; $colorA = 0; + $develcostB = $admin['develcost']; $colorB = 0; + $develcostC = $admin['develcost']; $colorC = 0; + $develcostD = $admin['develcost']; $colorD = 0; + $develcostE = $admin['develcost']*2; $colorE = 0; + $develcost3 = $admin['develcost']*3; + $develcost5 = $admin['develcost']*5; + + // 농상 국가보정 + if($nation['type'] == 2 || $nation['type'] == 12) { $develcostA *= 0.8; $colorA = 1; } + if($nation['type'] == 8 || $nation['type'] == 11) { $develcostA *= 1.2; $colorA = 2; } + // 기술 국가보정 + if($nation['type'] == 3 || $nation['type'] == 13) { $develcostB *= 0.8; $colorB = 1; } + if($nation['type'] == 5 || $nation['type'] == 6 || $nation['type'] == 7 || $nation['type'] == 8 || $nation['type'] == 12) { $develcostB *= 1.2; $colorB = 2; } + // 수성 국가보정 + if($nation['type'] == 3 || $nation['type'] == 5 || $nation['type'] == 10 || $nation['type'] == 11) { $develcostC *= 0.8; $colorC = 1; } + if($nation['type'] == 4 || $nation['type'] == 7 || $nation['type'] == 8 || $nation['type'] == 13) { $develcostC *= 1.2; $colorC = 2; } + // 치안 국가보정 + if($nation['type'] == 1 || $nation['type'] == 4) { $develcostD *= 0.8; $colorD = 1; } + if($nation['type'] == 6 || $nation['type'] == 9) { $develcostD *= 1.2; $colorD = 2; } + // 민심,정착장려 국가보정 + if($nation['type'] == 2 || $nation['type'] == 4 || $nation['type'] == 7 || $nation['type'] == 10) { $develcostE *= 0.8; $colorE = 1; } + if($nation['type'] == 1 || $nation['type'] == 3 || $nation['type'] == 9) { $develcostE *= 1.2; $colorE = 2; } + + $develcostA = Util::round($develcostA); + $develcostB = Util::round($develcostB); + $develcostC = Util::round($develcostC); + $develcostD = Util::round($develcostD); + $develcostE = Util::round($develcostE); + + echo " + +"; +} + +function CoreCommandTable() { + $db = DB::db(); + $gameStor = KVStorage::getStorage($db, 'game_env'); + $connect=$db->get(); + $userID = Session::getUserID(); + + $develcost = $gameStor->develcost; + + $query = "select no,nation,city,level from general where owner='{$userID}'"; + $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + $me = MYDB_fetch_array($result); + + $query = "select level,can_change_flag from nation where nation='{$me['nation']}'"; + $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + $nation = MYDB_fetch_array($result); + + $query = "select no from general where nation='{$me['nation']}'"; + $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + $genCount = MYDB_num_rows($result); + + $query = "select supply from city where city='{$me['city']}'"; + $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + $city = MYDB_fetch_array($result); + + if($nation['level'] > 0) { $valid = 1; } + else { $valid = 0; } + if($city['supply'] == 0) { $valid = 0; } + + echo " + +"; +} + +function myInfo() { + $db = DB::db(); + $connect=$db->get(); + $userID = Session::getUserID(); + + $query = "select no from general where owner='{$userID}'"; + $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + $me = MYDB_fetch_array($result); + + generalInfo($me['no']); +} + +function generalInfo($no) { + $db = DB::db(); + $gameStor = KVStorage::getStorage($db, 'game_env'); + $connect=$db->get(); + + $show_img_level = $gameStor->show_img_level; + + $query = "select block,no,name,picture,imgsvr,injury,nation,city,troop,leader,leader2,power,power2,intel,intel2,explevel,experience,level,gold,rice,crew,crewtype,train,atmos,weap,book,horse,item,turntime,killturn,age,personal,special,specage,special2,specage2,mode,con,connect from general where no='$no'"; + $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + $general = MYDB_fetch_array($result); + + $nation = getNationStaticInfo($general['nation']); + + if($general['level'] == 12) { + $lbonus = $nation['level'] * 2; + } elseif($general['level'] >= 5) { + $lbonus = $nation['level']; + } else { + $lbonus = 0; + } + if($lbonus > 0) { + $lbonus = "+{$lbonus}"; + } else { + $lbonus = ""; + } + + $troop = getTroop($general['troop']); + + $level = getLevel($general['level'], $nation['level']); + if($general['level'] == 2) { + $query = "select name from city where gen3='{$general['no']}'"; + $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + $city = MYDB_fetch_array($result); + $level = $city['name']." ".$level; + } elseif($general['level'] == 3) { + $query = "select name from city where gen2='{$general['no']}'"; + $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + $city = MYDB_fetch_array($result); + $level = $city['name']." ".$level; + } elseif($general['level'] == 4) { + $query = "select name from city where gen1='{$general['no']}'"; + $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + $city = MYDB_fetch_array($result); + $level = $city['name']." ".$level; + } + $call = getCall($general['leader'], $general['power'], $general['intel']); + $typename = GameUnitConst::byId($general['crewtype'])->name; + $weapname = getWeapName($general['weap']); + $bookname = getBookName($general['book']); + $horsename = getHorseName($general['horse']); + $itemname = displayItemInfo($general['item']); + if($general['injury'] > 0) { + $leader = intdiv($general['leader'] * (100 - $general['injury']), 100); + $power = intdiv($general['power'] * (100 - $general['injury']), 100); + $intel = intdiv($general['intel'] * (100 - $general['injury']), 100); + } else { + $leader = $general['leader']; + $power = $general['power']; + $intel = $general['intel']; + } + if($general['injury'] > 60) { $color = ""; $injury = "위독"; } + elseif($general['injury'] > 40) { $color = ""; $injury = "심각"; } + elseif($general['injury'] > 20) { $color = ""; $injury = "중상"; } + elseif($general['injury'] > 0) { $color = ""; $injury = "경상"; } + else { $color = ""; $injury = "건강"; } + + $remaining = substr($general['turntime'], 14, 2) - date('i'); + if($remaining < 0) { $remaining = 60 + $remaining; } + + if($nation['color'] == "") { $nation['color'] = "#000000"; } + + if($general['age'] < 60) { $general['age'] = "{$general['age']} 세"; } + elseif($general['age'] < 80) { $general['age'] = "{$general['age']} 세"; } + else { $general['age'] = "{$general['age']} 세"; } + + $general['connect'] = Util::round($general['connect'] / 10) * 10; + $special = $general['special'] == GameConst::$defaultSpecial ? "{$general['specage']}세" : "".displaySpecialDomesticInfo($general['special']).""; + $special2 = $general['special2'] == 0 ? "{$general['specage2']}세" : "".displaySpecialWarInfo($general['special2']).""; + + switch($general['personal']) { + case 2: case 4: + $atmos = "{$general['atmos']} (+5)"; break; + case 0: case 9: case 10: + $atmos = "{$general['atmos']} (-5)"; break; + default: + $atmos = "{$general['atmos']}"; break; + } + switch($general['personal']) { + case 3: case 5: + $train = "{$general['train']} (+5)"; break; + case 1: case 8: case 10: + $train = "{$general['train']} (-5)"; break; + default: + $train = "{$general['train']}"; break; + } + if($general['troop'] == 0) { $troop['name'] = "-"; } + if($general['mode'] == 2) { $general['mode'] = "수비 함(훈사80)"; } + elseif($general['mode'] == 1) { $general['mode'] = "수비 함(훈사60)"; } + else { $general['mode'] = "수비 안함"; } + + $weapImage = ServConfig::$gameImagePath."/weap{$general['crewtype']}.png"; + if($show_img_level < 2) { $weapImage = ServConfig::$sharedIconPath."/default.jpg"; }; + $imageTemp = GetImageURL($general['imgsvr']); + echo " + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 {$general['name']} 【 {$level} | {$call} | {$color}{$injury} 】 ".substr($general['turntime'], 11)."
통솔 {$color}{$leader}{$lbonus} ".bar(expStatus($general['leader2']), 20)."무력 {$color}{$power} ".bar(expStatus($general['power2']), 20)."지력 {$color}{$intel} ".bar(expStatus($general['intel2']), 20)."
명마$horsename무기$weapname서적$bookname
자금{$general['gold']}군량{$general['rice']}도구$itemname
병종$typename병사{$general['crew']}성격".displayCharInfo($general['personal'])."
훈련$train사기$atmos특기$special / $special2
Lv {$general['explevel']} ".bar(getLevelPer($general['experience'], $general['explevel']), 20)."연령{$general['age']}
수비{$general['mode']}삭턴{$general['killturn']} 턴실행$remaining 분 남음
부대{$troop['name']}벌점".getConnect($general['connect'])." {$general['connect']}({$general['con']})
"; +} + +function myInfo2() { + $db = DB::db(); + $connect=$db->get(); + $userID = Session::getUserID(); + + $query = "select no from general where owner='{$userID}'"; + $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + $me = MYDB_fetch_array($result); + + generalInfo2($me['no']); +} + +function generalInfo2($no) { + $db = DB::db(); + $connect=$db->get(); + + $query = "select personal,experience,dedication,firenum,warnum,killnum,deathnum,killcrew,deathcrew,belong,killnum*100/warnum as winrate,killcrew/deathcrew*100 as killrate,dex0,dex10,dex20,dex30,dex40 from general where no='$no'"; + $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + $general = MYDB_fetch_array($result); + + $general['winrate'] = round($general['winrate'], 2); + $general['killrate'] = round($general['killrate'], 2); + + switch($general['personal']) { + case 0: case 1; case 6: + $experience = "".getHonor($general['experience'])." ({$general['experience']})"; break; + case 4: case 5: case 7: case 10: + $experience = "".getHonor($general['experience'])." ({$general['experience']})"; break; + default: + $experience = getHonor($general['experience'])." ({$general['experience']})"; break; + } + switch($general['personal']) { + case 10: + $dedication = "".getDed($general['dedication'])." ({$general['dedication']})"; break; + default: + $dedication = getDed($general['dedication'])." ({$general['dedication']})"; break; + } + + $dex0 = $general['dex0'] / GameConst::$dexLimit * 100; + $dex10 = $general['dex10'] / GameConst::$dexLimit * 100; + $dex20 = $general['dex20'] / GameConst::$dexLimit * 100; + $dex30 = $general['dex30'] / GameConst::$dexLimit * 100; + $dex40 = $general['dex40'] / GameConst::$dexLimit * 100; + + if($dex0 > 100) { $dex0 = 100; } + if($dex10 > 100) { $dex10 = 100; } + if($dex20 > 100) { $dex20 = 100; } + if($dex30 > 100) { $dex30 = 100; } + if($dex40 > 100) { $dex40 = 100; } + + $general['dex0_text'] = getDexCall($general['dex0']); + $general['dex10_text'] = getDexCall($general['dex10']); + $general['dex20_text'] = getDexCall($general['dex20']); + $general['dex30_text'] = getDexCall($general['dex30']); + $general['dex40_text'] = getDexCall($general['dex40']); + + $general['dex0_short'] = sprintf('%.1fK', $general['dex0']/1000); + $general['dex10_short'] = sprintf('%.1fK', $general['dex10']/1000); + $general['dex20_short'] = sprintf('%.1fK', $general['dex20']/1000); + $general['dex30_short'] = sprintf('%.1fK', $general['dex30']/1000); + $general['dex40_short'] = sprintf('%.1fK', $general['dex40']/1000); + + echo " + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
추 가 정 보
명성$experience계급$dedication
전투{$general['warnum']}계략{$general['firenum']}사관{$general['belong']}년
승률{$general['winrate']} %승리{$general['killnum']}패배{$general['deathnum']}
살상률{$general['killrate']} %사살{$general['killcrew']}피살{$general['deathcrew']}
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
숙 련 도
보병 {$general['dex0_text']}{$general['dex0_short']} ".bar($dex0, 16)."
궁병 {$general['dex10_text']}{$general['dex10_short']} ".bar($dex10, 16)."
기병 {$general['dex20_text']}{$general['dex20_short']} ".bar($dex20, 16)."
귀병 {$general['dex30_text']}{$general['dex30_short']} ".bar($dex30, 16)."
차병 {$general['dex40_text']}{$general['dex40_short']} ".bar($dex40, 16)."
"; +} + +function adminMsg() { + $db = DB::db(); + $gameStor = KVStorage::getStorage($db, 'game_env'); + $msg = $gameStor->msg; + + return "운영자 메세지 : $msg"; +} + +function getOnlineNum() { + return KVStorage::getStorage(DB::db(), 'game_env')->online; +} + +function onlinegen() { + $db = DB::db(); + $gameStor = KVStorage::getStorage($db, 'game_env'); + + $onlinegen = ""; + $generalID = Session::getInstance()->generalID; + $nationID = DB::db()->queryFirstField('select `nation` from `general` where `no` = %i', $generalID); + if($nationID === null || Util::toInt($nationID) === 0) { + $onlinegen = $gameStor->onlinegen; + } else { + $onlinegen = DB::db()->queryFirstField('select onlinegen from nation where nation=%i',$nationID); + } + return $onlinegen; +} + +function onlineNation() { + $db = DB::db(); + $gameStor = KVStorage::getStorage($db, 'game_env'); + + return $gameStor->onlinenation; +} + +function nationMsg() { + $db = DB::db(); + $connect=$db->get(); + $userID = Session::getUserID(); + + $msg = $db->queryFirstField( + 'SELECT msg FROM nation WHERE nation = (SELECT nation FROM general WHERE `owner` = %i)', + $userID + ); + + return $msg?:''; +} + +function msgprint($msg, $name, $picture, $imgsvr, $when, $num, $type) { + $db = DB::db(); + $connect=$db->get(); + + $message = explode('|', $msg); + $count = (count($message) - 2)/2; + $message[0] = Tag2Code($message[0]); + $message[1] = Tag2Code($message[1]); +// $message[0] = str_replace("\n", "
", $message[0]); +// $message[1] = str_replace("\n", "
", $message[1]); + + if($type == 0) { $board = "c_nationboard.php"; } + else { $board = "c_chiefboard.php"; } + + $imageTemp = GetImageURL($imgsvr); + echo " + + + + + + + + + + "; + for($i=0; $i < $count; $i++) { + $who = Tag2Code($message[2+$i*2]); + $reply = Tag2Code($message[3+$i*2]); + $query = "select name from general where no='$who'"; + $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + $regen = MYDB_fetch_array($result); + echo " + + + + "; + } + echo " + + + + + + +
$name$message[0]$when
$message[1]
{$regen['name']}$reply
댓글달기 + + + +
+
"; +} + +function banner() { + + return sprintf( + '%s %s / %s', + GameConst::$title, + VersionGit::$version, + GameConst::$banner); +} + +function addTurn($date, int $turnterm, int $turn=1, bool $withFraction=true) { + $date = new \DateTime($date); + $target = $turnterm*$turn; + $date->add(new \DateInterval("PT{$target}M")); + if($withFraction){ + return $date->format('Y-m-d H:i:s.u'); + } + return $date->format('Y-m-d H:i:s'); +} + +function subTurn($date, int $turnterm, int $turn=1, bool $withFraction=true) { + $date = new \DateTime($date); + $target = $turnterm*$turn; + $date->sub(new \DateInterval("PT{$target}M")); + if($withFraction){ + return $date->format('Y-m-d H:i:s.u'); + } + return $date->format('Y-m-d H:i:s'); +} + +function cutTurn($date, int $turnterm, bool $withFraction=true) { + $date = new \DateTime($date); + + $baseDate = new \DateTime($date->format('Y-m-d')); + $baseDate->sub(new \DateInterval("P1D")); + $baseDate->add(new \DateInterval("PT1H")); + + $diffMin = intdiv($date->getTimeStamp() - $baseDate->getTimeStamp(), 60); + $diffMin -= $diffMin % $turnterm; + + $baseDate->add(new \DateInterval("PT{$diffMin}M")); + if($withFraction){ + return $baseDate->format('Y-m-d H:i:s.u'); + } + return $baseDate->format('Y-m-d H:i:s'); + +} + +function cutDay($date, int $turnterm, bool $withFraction=true) { + $date = new \DateTime($date); + + $baseDate = new \DateTime($date->format('Y-m-d')); + $baseDate->sub(new \DateInterval("P1D")); + $baseDate->add(new \DateInterval("PT1H")); + + $baseGap = 12 * $turnterm; + + $diffMin = intdiv($date->getTimeStamp() - $baseDate->getTimeStamp(), 60); + + $timeAdjust = $diffMin % $baseGap; + $newMonth = intdiv($timeAdjust, $turnterm) + 1; + + $yearPulled = false; + if($newMonth > 3){//3월 이후일때는 + $yearPulled = true; + $diffMin += $baseGap; + } + $diffMin -= $timeAdjust; + + $baseDate->add(new \DateInterval("PT{$diffMin}M")); + if($withFraction){ + $dateTimeString = $baseDate->format('Y-m-d H:i:s.u'); + } + else{ + $dateTimeString = $baseDate->format('Y-m-d H:i:s'); + } + + return [$dateTimeString, $yearPulled, $newMonth]; +} + +function increaseRefresh($type="", $cnt=1) { + //FIXME: 로그인, 비로그인 시 처리가 명확하지 않음 + $session = Session::getInstance(); + $userID = $session->userID; + $generalID = $session->generalID; + $userGrade = $session->userGrade; + + $date = TimeUtil::now(); + + $db = DB::db(); + $gameStor = KVStorage::getStorage($db, 'game_env'); + $gameStor->refresh = $gameStor->refresh+$cnt; //TODO: +로 증가하는 값은 별도로 분리 + + if($generalID && $userGrade < 6) { + $db->update('general', [ + 'lastrefresh'=>$date, + 'con'=>$db->sqleval('con + %i', $cnt), + 'connect'=>$db->sqleval('connect + %i', $cnt), + 'refcnt'=>$db->sqleval('refcnt + %i', $cnt), + 'refresh'=>$db->sqleval('refresh + %i', $cnt) + ], 'owner=%i', $userID); + } + + $date = date('Y_m_d H:i:s'); + $date2 = substr($date, 0, 10); + $online = getOnlineNum(); + file_put_contents( + __dir__."/logs/".UniqueConst::$serverID."/_{$date2}_refresh.txt", + sprintf( + "%s, %s, %s, %s, %s, %d\n", + $date, + $session->userName, + $session->generalName, + $session->ip, + $type, + $online + ), + FILE_APPEND + ); + + $proxy_headers = array( + 'HTTP_VIA', + 'HTTP_X_FORWARDED_FOR', + 'HTTP_FORWARDED_FOR', + 'HTTP_X_FORWARDED', + 'HTTP_FORWARDED', + 'HTTP_CLIENT_IP', + 'HTTP_FORWARDED_FOR_IP', + 'VIA', + 'X_FORWARDED_FOR', + 'FORWARDED_FOR', + 'X_FORWARDED', + 'FORWARDED', + 'CLIENT_IP', + 'FORWARDED_FOR_IP', + 'HTTP_PROXY_CONNECTION' + ); + + $str = ""; + foreach($proxy_headers as $x) { + if(isset($_SERVER[$x])) $str .= "//{$x}:{$_SERVER[$x]}"; + } + if($str != "") { + file_put_contents( + __dir__."/logs/".UniqueConst::$serverID."/_{$date2}_ipcheck.txt", + sprintf( + "%s, %s, %s%s\n", + $session->userName, + $session->generalName, + $_SERVER['REMOTE_ADDR'], + $str + ), + FILE_APPEND); + } +} + +function updateTraffic() { + $online = getOnlineNum(); + $db = DB::db(); + $gameStor = KVStorage::getStorage($db, 'game_env'); + $admin = $gameStor->getValues(['year','month','refresh','maxonline','maxrefresh']); + + //최다갱신자 + $user = $db->queryFirstRow('select name,refresh from general order by refresh desc limit 1'); + + if($admin['maxrefresh'] < $admin['refresh']) { + $admin['maxrefresh'] = $admin['refresh']; + } + if($admin['maxonline'] < $online) { + $admin['maxonline'] = $online; + } + $gameStor->refresh = 0; + $gameStor->maxrefresh = $admin['maxrefresh']; + $gameStor->maxonline = $admin['maxonline']; + + $db->update('general', ['refresh'=>0], true); + + $date = TimeUtil::now(); + //일시|년|월|총갱신|접속자|최다갱신자 + file_put_contents(__dir__."/logs/".UniqueConst::$serverID."/_traffic.txt", + Json::encode([ + $date, + $admin['year'], + $admin['month'], + $admin['refresh'], + $online, + $user['name']."(".$user['refresh'].")" + ])."\n" + , FILE_APPEND); +} + +function CheckOverhead() { + //서버정보 + $db = DB::db(); + $gameStor = KVStorage::getStorage($db, 'game_env'); + list($turnterm, $conlimit) = $gameStor->getValuesAsArray(['turnterm', 'conlimit']); + + $con = Util::round(pow($turnterm, 0.6) * 3) * 10; + + + if($con != $conlimit){ + $gameStor->conlimit = $con; + } +} + +function isLock() { + return DB::db()->queryFirstField("SELECT plock from plock limit 1") != 0; +} + +function tryLock():bool{ + //NOTE: 게임 로직과 관련한 모든 insert, update 함수들은 lock을 거칠것을 권장함. + $db = DB::db(); + + // 잠금 + $db->update('plock', [ + 'plock'=>1, + 'locktime'=>TimeUtil::now(true) + ], 'plock=1'); + + return $db->affectedRows() > 0; +} + +function unlock():bool{ + // 풀림 + $db = DB::db(); + $db->update('plock', [ + 'plock'=>0 + ], true); + + return $db->affectedRows() > 0; +} + +function timeover():bool { + $db = DB::db(); + $gameStor = KVStorage::getStorage($db, 'game_env'); + + list($turnterm, $turntime) = $gameStor->getValuesAsArray(['turnterm', 'turntime']); + $diff = (new \DateTime())->getTimestamp() - (new \DateTime($turntime))->getTimestamp(); + + $t = min($turnterm, 5); + + $term = $diff; + if($term >= $t || $term < 0) { return true; } + else { return false; } +} + +function checkDelay() { + $db = DB::db(); + $gameStor = KVStorage::getStorage($db, 'game_env'); + + //서버정보 + $now = new \DateTimeImmutable(); + $turntime = new \DateTimeImmutable($gameStor->turntime); + $timeMinDiff = intdiv($now->getTimestamp() - $turntime->getTimestamp(), 60); + + // 1턴이상 갱신 없었으면 서버 지연 + $term = $gameStor->turnterm; + if($term >= 20){ + $threshold = 1; + } + else if($term >= 10){ + $threshold = 2; + } + else{ + $threshold = 3; + } + //지연 해야할 밀린 턴 횟수 + $iter = intdiv($timeMinDiff, $term); + if($iter > $threshold) { + $minute = ($iter - $threshold) * $term; + $newTurntime = $turntime->add(new \DateInterval("PT{$minute}M")); + $newNextTurntime = $turntime->add(new \DateInterval("PT{$term}M")); + $gameStor->turntime = $newTurntime->format('Y-m-d H:i:s'); + $gameStor->starttime = (new \DateTimeImmutable($gameStor->starttime)) + ->add(new \DateInterval("PT{$minute}M")) + ->format('Y-m-d H:i:s'); + $db->update('general', [ + 'turntime'=> $db->sqleval('DATE_ADD(turntime, INTERVAL %i MINUTE)', $minute) + ], true); + $db->update('auction', [ + 'expire'=> $db->sqleval('DATE_ADD(expire, INTERVAL %i MINUTE)', $minute) + ], true); + } +} + +function updateOnline() { + $db = DB::db(); + $gameStor = KVStorage::getStorage($db, 'game_env'); + $connect=$db->get(); + $nationname = ["재야"]; + + //국가별 이름 매핑 + foreach(getAllNationStaticInfo() as $nation) { + $nationname[$nation['nation']] = $nation['name']; + } + + + //동접수 + $query = "select no,name,nation from general where lastrefresh > DATE_SUB(NOW(), INTERVAL 5 MINUTE)"; + $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + $onlinenum = MYDB_num_rows($result); + + $onnation = array(); + $onnationstr = ""; + + //국가별 접속중인 장수 + for($i=0; $i < $onlinenum; $i++) { + $general = MYDB_fetch_array($result); + if(isset($onnation[$general['nation']])){ + $onnation[$general['nation']] .= $general['name'].', '; + }else { + $onnation[$general['nation']] = $general['name'].', '; + } + } + + //$onnation이 empty라면 굳이 foreach를 수행 할 이유가 없음. + if(!empty($onnation)){ + foreach($onnation as $key => $val) { + $onnationstr .= "【{$nationname[$key]}】, "; + + if($key == 0) { + $gameStor->onlinegen = $onnation[0]; + } else { + $query = "update nation set onlinegen='$onnation[$key]' where nation='$key'"; + MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + } + } + } + + //접속중인 국가 + $gameStor->online = $onlinenum; + $gameStor->onlinenation = $onnationstr; +} + +function checkTurn() { + $db = DB::db(); + $gameStor = KVStorage::getStorage($db, 'game_env'); + $connect=$db->get(); + + $alllog = []; + + // 잦은 갱신 금지 현재 5초당 1회 + if(!timeover()) { return; } + // 현재 처리중이면 접근 불가 + + // 파일락 획득 + //FIXME:이미 DB 테이블로 lock을 시도하는데 이게 따로 필요한가? + $fp = fopen(__dir__.'/lock.txt', 'r'); + if(!flock($fp, LOCK_EX)) { + return; + } + + if(!tryLock()){ + return; + } + + $session = Session::getInstance(); + + pushLockLog(["- checkTurn() : ".TimeUtil::now()." : ".$session->userName]); + + // 파일락 해제 + if(!flock($fp, LOCK_UN)) { return; } + // 세마포어 해제 + //if(!@sem_release($sema)) { echo "치명적 에러! Hide_D에게 문의하세요!"; exit(1); } + + pushLockLog(["- checkTurn() 입 : ".TimeUtil::now()." : ".$session->userName]); + + //if(STEP_LOG) delStepLog(); + //if(STEP_LOG) pushStepLog(TimeUtil::now().', 진입'); + + + if($gameStor->isunited == 2) { + $db->update('plock', ['plock'=>1], true); + return; + } + $gameStor->cacheAll(); + // 1턴이상 갱신 없었으면 서버 지연 + //if(STEP_LOG) pushStepLog(TimeUtil::now().', checkDelay'); + checkDelay(); + // 접속자수, 접속국가, 국가별 접속장수 갱신 + //if(STEP_LOG) pushStepLog(TimeUtil::now().', checkDelay'); + updateOnline(); + //접속자 수 따라서 갱신제한 변경 + //if(STEP_LOG) pushStepLog(TimeUtil::now().', CheckOverhead'); + CheckOverhead(); + //서버정보 + + $date = TimeUtil::now(); + // 최종 처리 월턴의 다음 월턴시간 구함 + $prevTurn = cutTurn($gameStor->turntime, $gameStor->turnterm); + $nextTurn = addTurn($prevTurn, $gameStor->turnterm); + // 현재 턴 이전 월턴까지 모두처리. + //최종 처리 이후 다음 월턴이 현재 시간보다 전이라면 + while($nextTurn <= $date) { + // 월턴이전 장수 모두 처리 + $query = "select no,name,turntime,turn0,npc from general where turntime < '$nextTurn' order by turntime"; + $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + $gencount = MYDB_num_rows($result); + for($i=0; $i < $gencount; $i++) { + $general = MYDB_fetch_array($result); + + //if(PROCESS_LOG) $processlog[0] = "[{$date}] 월턴 이전 갱신: name({$general['name']}), no({$general['no']}), turntime({$general['turntime']}), turn0({$general['turn0']})"; + //if(PROCESS_LOG) pushProcessLog($processlog); + + //if(STEP_LOG) pushStepLog(TimeUtil::now().', processAI'); + if($general['npc'] >= 2) { processAI($general['no']); } // npc AI 처리 + //if(STEP_LOG) pushStepLog(TimeUtil::now().', PreprocessCommand'); + PreprocessCommand($general['no']); + //if(STEP_LOG) pushStepLog(TimeUtil::now().', processCommand'); + processCommand($general['no']); + //if(STEP_LOG) pushStepLog(TimeUtil::now().', updateCommand'); + updateCommand($general['no']); + //if(STEP_LOG) pushStepLog(TimeUtil::now().', updateTurntime'); + updateTurntime($general['no']); + + } + + // 트래픽 업데이트 + //if(STEP_LOG) pushStepLog(TimeUtil::now().', updateTraffic'); + updateTraffic(); + // 1달마다 처리하는 것들, 벌점 감소 및 건국,전턴,합병 -1, 군량 소모 + //if(STEP_LOG) pushStepLog(TimeUtil::now().', preUpdateMonthly'); + $result = preUpdateMonthly(); + if($result == false) { + pushLockLog(["-- checkTurn() 오류출 : ".TimeUtil::now()." : ".$session->userName]); + + // 잡금 해제 + //if(STEP_LOG) pushStepLog(TimeUtil::now().', unlock'); + $gameStor->resetCache(true); + unlock(); + return false; + } + + // 그 시각 년도,월 저장 + list($gameStor->year, $gameStor->month) = turnDate($nextTurn); + + pushLockLog(["-- checkTurn() ".$gameStor->month."월 : ".TimeUtil::now()." : ".$session->userName]); + + // 이벤트 핸들러 동작 + foreach (DB::db()->query('SELECT * from event') as $rawEvent) { + $eventID = $rawEvent['id']; + $cond = Json::decode($rawEvent['condition']); + $action = Json::decode($rawEvent['action']); + $event = new Event\EventHandler($cond, $action); + + $event->tryRunEvent(['currentEventID'=>$eventID] + $gameStor->getAll(true)); + } + + // 분기계산. 장수들 턴보다 먼저 있다면 먼저처리 + if($gameStor->month == 1) { + // NPC 등장 + //if(STEP_LOG) pushStepLog(TimeUtil::now().', processGoldIncome'); + processGoldIncome(); + //if(STEP_LOG) pushStepLog(TimeUtil::now().', processSpring'); + processSpring(); + //if(STEP_LOG) pushStepLog(TimeUtil::now().', updateYearly'); + updateYearly(); + //if(STEP_LOG) pushStepLog(TimeUtil::now().', updateQuaterly'); + updateQuaterly(); + //if(STEP_LOG) pushStepLog(TimeUtil::now().', disaster'); + disaster(); + //if(STEP_LOG) pushStepLog(TimeUtil::now().', tradeRate'); + tradeRate(); + //if(STEP_LOG) pushStepLog(TimeUtil::now().', addAge'); + addAge(); + // 새해 알림 + $alllog[] = "◆{$gameStor->month}월:{$gameStor->year}년이 되었습니다."; + pushGeneralPublicRecord($alllog, $gameStor->year, $gameStor->month); + } elseif($gameStor->month == 4) { + //if(STEP_LOG) pushStepLog(TimeUtil::now().', updateQuaterly'); + updateQuaterly(); + //if(STEP_LOG) pushStepLog(TimeUtil::now().', disaster'); + disaster(); + } elseif($gameStor->month == 7) { + //if(STEP_LOG) pushStepLog(TimeUtil::now().', processRiceIncome'); + processRiceIncome(); + //if(STEP_LOG) pushStepLog(TimeUtil::now().', processFall'); + processFall(); + //if(STEP_LOG) pushStepLog(TimeUtil::now().', updateQuaterly'); + updateQuaterly(); + //if(STEP_LOG) pushStepLog(TimeUtil::now().', disaster'); + disaster(); + //if(STEP_LOG) pushStepLog(TimeUtil::now().', tradeRate'); + tradeRate(); + } elseif($gameStor->month == 10) { + //if(STEP_LOG) pushStepLog(TimeUtil::now().', updateQuaterly'); + updateQuaterly(); + //if(STEP_LOG) pushStepLog(TimeUtil::now().', disaster'); + disaster(); + } + //if(STEP_LOG) pushStepLog(TimeUtil::now().', postUpdateMonthly'); + postUpdateMonthly(); + + // 다음달로 넘김 + $prevTurn = $nextTurn; + $nextTurn = addTurn($prevTurn, $gameStor->turnterm); + } + + //if(STEP_LOG) pushStepLog(TimeUtil::now().', '.__LINE__); + + // 이시각 정각 시까지 업데이트 완료했음 + $gameStor->turntime = $prevTurn; + + // 그 시각 년도,월 저장 + list($gameStor->year, $gameStor->month) = turnDate($prevTurn); + // 현재시간의 월턴시간 이후 분단위 장수 처리 + do { + $query = "select no,name,turntime,turn0,npc from general where turntime<='$date' order by turntime"; + $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + $gencount = MYDB_num_rows($result); + + for($i=0; $i < $gencount; $i++) { + $general = MYDB_fetch_array($result); + + //if(PROCESS_LOG) $processlog[0] = "[{$date}] 월턴 이후 갱신: name({$general['name']}), no({$general['no']}), turntime({$general['turntime']}), turn0({$general['turn0']})"; + //if(PROCESS_LOG) pushProcessLog($processlog); + + //if(STEP_LOG) pushStepLog(TimeUtil::now().', processAI'); + if($general['npc'] >= 2) { processAI($general['no']); } // npc AI 처리 + //if(STEP_LOG) pushStepLog(TimeUtil::now().', PreprocessCommand'); + PreprocessCommand($general['no']); + //if(STEP_LOG) pushStepLog(TimeUtil::now().', processCommand'); + processCommand($general['no']); + //if(STEP_LOG) pushStepLog(TimeUtil::now().', updateCommand'); + updateCommand($general['no']); + //if(STEP_LOG) pushStepLog(TimeUtil::now().', updateTurntime'); + updateTurntime($general['no']); + } + } while($gencount > 0); + + //if(STEP_LOG) pushStepLog(TimeUtil::now().', '.__LINE__); + + $gameStor->turntime = $date; + + // 부상 과도 제한 + $query = "update general set injury='80' where injury>'80'"; + MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + //토너먼트 처리 + //if(STEP_LOG) pushStepLog(TimeUtil::now().', processTournament'); + processTournament(); + //거래 처리 + //if(STEP_LOG) pushStepLog(TimeUtil::now().', processAuction'); + processAuction(); + // 잡금 해제 + //if(STEP_LOG) pushStepLog(TimeUtil::now().', unlock'); + $gameStor->resetCache(true); + unlock(); + + pushLockLog(["- checkTurn() 출 : ".TimeUtil::now()." : ".$session->userName]); + + //if(STEP_LOG) pushStepLog(TimeUtil::now().', finish'); + + return true; +} + +function addAge() { + $db = DB::db(); + $gameStor = KVStorage::getStorage($db, 'game_env'); + $connect=$db->get(); + + //나이와 호봉 증가 + $query = "update general set age=age+1,belong=belong+1"; + MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + + $admin = $gameStor->getValues(['startyear', 'year', 'month']); + + if($admin['year'] >= $admin['startyear']+3) { + foreach($db->query('SELECT no,name,nation,leader,power,intel from general where specage<=age and special=%s', GameConst::$defaultSpecial) as $general){ + $special = getSpecial($general['leader'], $general['power'], $general['intel']); + $specialClass = getGeneralSpecialDomesticClass($special); + $specialText = $specialClass::$name; + $db->update('general', [ + 'special'=>$special + ], 'no=%i',$general['no']); + + $josaUl = JosaUtil::pick($specialText, '을'); + pushGeneralHistory($general, "●{$admin['year']}년 {$admin['month']}월:특기 【{$specialText}】{$josaUl} 습득"); + pushGenLog($general, "●특기 【{$specialText}】{$josaUl} 익혔습니다!"); + } + + $query = "select no,name,nation,leader,power,intel,npc,dex0,dex10,dex20,dex30,dex40 from general where specage2<=age and special2='0'"; + $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + $gencount = MYDB_num_rows($result); + + for($i=0; $i < $gencount; $i++) { + $general = MYDB_fetch_array($result); + $special2 = getSpecial2($general['leader'], $general['power'], $general['intel'], 0, $general['dex0'], $general['dex10'], $general['dex20'], $general['dex30'], $general['dex40']); + + $query = "update general set special2='$special2' where no='{$general['no']}'"; + MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + + $josaUl = JosaUtil::pick($special2, '을'); + pushGeneralHistory($general, "●{$admin['year']}년 {$admin['month']}월:특기 【".getGenSpecial($special2)."】{$josaUl} 습득"); + pushGenLog($general, "●특기 【".getGenSpecial($special2)."】{$josaUl} 익혔습니다!"); + } + } +} + +function turnDate($curtime) { + $db = DB::db(); + $gameStor = KVStorage::getStorage($db, 'game_env'); + $admin = $gameStor->getValues(['startyear', 'starttime', 'turnterm', 'year', 'month']); + + $turn = $admin['starttime']; + $curturn = cutTurn($curtime, $admin['turnterm']); + $term = $admin['turnterm']; + + $num = intdiv((strtotime($curturn) - strtotime($turn)), $term*60); + + $date = $admin['startyear'] * 12; + $date += $num; + + $year = intdiv($date, 12); + $month = 1 + $date % 12; + + // 바뀐 경우만 업데이트 + if($admin['month'] != $month || $admin['year'] != $year) { + $gameStor->year = $year; + $gameStor->month = $month; + } + + return [$year, $month]; +} + + +function triggerTournament() { + $db = DB::db(); + $gameStor = KVStorage::getStorage($db, 'game_env'); + + $admin = $gameStor->getValues(['tournament', 'tnmt_trig']); + + //현재 토너먼트 없고, 자동개시 걸려있을때, 40%확률 + if($admin['tournament'] == 0 && $admin['tnmt_trig'] > 0 && rand() % 100 < 40) { + $type = rand() % 5; // 0 : 전력전, 1 : 통솔전, 2 : 일기토, 3 : 설전 + //전력전 40%, 통, 일, 설 각 20% + if($type > 3) { $type = 0; } + startTournament($admin['tnmt_trig'], $type); + } +} + +function PreprocessCommand($no) { + $db = DB::db(); + $connect=$db->get(); + $log = []; + + $query = "select no,name,city,injury,special2,item,turn0,rice,crew from general where no='$no'"; + $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + $general = MYDB_fetch_array($result); + + if($general['special2'] == 73 || $general['item'] == 23 || $general['item'] == 24) { + //특기보정 : 의술 + //의서 사용 + if($general['injury'] > 0) { + $general['injury'] = 0; + $query = "update general set injury=0 where no='$no'"; + MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + + pushGenLog($general, "의술을 펼쳐 스스로 치료합니다!"); + } + + $query = "select no,name,injury from general where city='{$general['city']}' and injury>10 order by rand()"; + $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + $patientCount = MYDB_num_rows($result); + + if($patientCount > 0) { + // 50% 확률로 치료 + $patientCount = Util::round($patientCount * 0.5); + + $patientName = ""; + for($i=0; $i < $patientCount; $i++) { + $patient = MYDB_fetch_array($result); + + //부상 치료 + $query = "update general set injury=0 where no='{$patient['no']}'"; + MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + + $josaYi = JosaUtil::pick($general['name'], '이'); + pushGenLog($patient, "{$general['name']}{$josaYi} 의술로써 치료해줍니다!"); + + if($patientName == "") { + $patientName = $patient['name']; + } + } + + if($patientCount == 1) { + $josaUl = JosaUtil::pick($patientName, '을'); + pushGenLog($general, "의술을 펼쳐 도시의 장수 {$patientName}{$josaUl} 치료합니다!"); + } else { + $patientCount -= 1; + pushGenLog($general, "의술을 펼쳐 도시의 장수들 {$patientName} 외 {$patientCount}명을 치료합니다!"); + } + } + } + + if($general['injury'] > 0) { + if($general['item'] >=7 && $general['item'] <= 11) { + //영구약 사용 + $query = "update general set injury=0 where no='$no'"; + MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + + $josaUl = JosaUtil::pick($general['item'], '을'); + $log[0] = "".getItemName($general['item'])."{$josaUl} 사용하여 치료합니다!"; + pushGenLog($general, $log); + } elseif($general['injury'] > 10 && $general['item'] == 1 && DecodeCommand($general['turn0'])[0] != 50) { + //환약 사용 + $query = "update general set injury=0,item=0 where no='$no'"; + MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + + $log[0] = "환약을 사용하여 치료합니다!"; + pushGenLog($general, $log); + } elseif($general['injury'] > 10) { + //부상 감소 + $query = "update general set injury=injury-10 where no='$no'"; + MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + } else { + //부상 감소 + $query = "update general set injury=0 where no='$no'"; + MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + } + } + + + if($general['crew'] >= 100){ + $newRice = $general['rice'] - $general['crew'] / 100; + if($newRice >= 0){ + $db->update('general', [ + 'rice'=>Util::round($newRice) + ], 'no=%i',$general['no']); + } + else{ + $db->update('city', [ + 'pop'=>$db->sqleval('pop + %i', $general['crew']) + ], 'city=%i', $general['city']); + $db->update('general', [ + 'crew'=>0, + 'rice'=>0 + ], 'no=%i',$general['no']); + pushGenLog($general, ["●군량이 모자라 병사들이 소집해제되었습니다!"]); + } + } + +} + + +function updateTurntime($no) { + $db = DB::db(); + $gameStor = KVStorage::getStorage($db, 'game_env'); + $connect=$db->get(); + $alllog = []; + $log = []; + + $admin = $gameStor->getValues(['year', 'month', 'isunited', 'turnterm']); + + $query = "select no,name,name2,nation,troop,age,turntime,killturn,level,deadyear,npc,npc_org,affinity,npcid from general where no='$no'"; + $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + $general = MYDB_fetch_array($result); + + // 삭턴장수 삭제처리 + if($general['killturn'] <= 0) { + // npc유저 삭턴시 npc로 전환 + if($general['npc'] == 1 && $general['deadyear'] > $admin['year']) { + $general['killturn'] = ($general['deadyear'] - $admin['year']) * 12; + $general['npc'] = $general['npc_org']; + + $db->update('general', [ + 'owner'=>-1, + 'npc'=>$general['npc_org'], + 'killturn'=>$general['killturn'], + 'mode'=>2, + 'name2'=>null + ], 'no=%i',$no); + + $josaYi = JosaUtil::pick($general['name2'], '이'); + $alllog[0] = "●{$admin['month']}월:{$general['name2']}{$josaYi} {$general['name']}의 육체에서 유체이탈합니다!"; + pushGeneralPublicRecord($alllog, $admin['year'], $admin['month']); + } else { + + storeOldGeneral($general['no'], $admin['year'], $admin['month']); + + // 군주였으면 유지 이음 + if($general['level'] == 12) { + nextRuler($general); + } + + //도시의 태수, 군사, 시중직도 초기화 + $query = "update city set gen1='0' where gen1='{$general['no']}'"; + MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + $query = "update city set gen2='0' where gen2='{$general['no']}'"; + MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + $query = "update city set gen3='0' where gen3='{$general['no']}'"; + MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + + // 부대 처리 + $query = "select no from troop where troop='{$general['troop']}'"; + $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + $troop = MYDB_fetch_array($result); + + //부대장일 경우 + if($troop['no'] == $general['no']) { + // 모두 탈퇴 + $query = "update general set troop='0' where troop='{$general['troop']}'"; + MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + // 부대 삭제 + $query = "delete from troop where troop='{$general['troop']}'"; + MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + } else { + $query = "update general set troop='0' where no='{$general['no']}'"; + MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + } + // 장수 삭제 + $query = "delete from general where no='{$general['no']}'"; + MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + + $db->update('nation', [ + 'gennum'=>$db->sqleval('gennum - 1') + ], 'nation=%i', $general['nation']); + + // 병, 요절, 객사, 번개, 사채, 일확천금, 호랑이, 곰, 수영, 처형, 발견 + $josaYi = JosaUtil::pick($general['name'], '이'); + switch(rand()%42) { + case 0: $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} 역병에 걸려 죽고 말았습니다."; break; + case 1: $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} 요절하고 말았습니다."; break; + case 2: $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} 거리에서 갑자기 객사하고 말았습니다."; break; + case 3: $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} 안타깝게도 번개에 맞아 죽고 말았습니다."; break; + case 4: $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} 고리대금에 시달리다가 자살하고 말았습니다."; break; + case 5: $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} 일확천금에 놀라 심장마비로 죽고 말았습니다."; break; + case 6: $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} 산속에서 호랑이에게 물려 죽고 말았습니다."; break; + case 7: $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} 산책중 곰에게 할퀴어 죽고 말았습니다."; break; + case 8: $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} 수영을 하다 익사하고 말았습니다."; break; + case 9: $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} 황제를 모독하다가 처형당하고 말았습니다."; break; + case 10: $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} 이튿날 침실에서 죽은채로발견되었습니다."; break; + case 11: $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} 색에 빠져 기력이 쇠진해 죽고말았습니다."; break; + case 12: $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} 미녀를 보고 심장마비로 죽고말았습니다."; break; + case 13: $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} 우울증에 걸려 자살하고 말았습니다."; break; + case 14: $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} 천하 정세를 비관하며 분신하고 말았습니다."; break; + case 15: $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} 어떤 관심도 못받고 쓸쓸히 죽고말았습니다."; break; + case 16: $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} 유산 상속 문제로 다투다가 살해당했습니다."; break; + case 17: $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} 누군가의 사주로 자객에게 암살당했습니다."; break; + case 18: $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} 바람난 배우자에게 독살당하고 말았습니다."; break; + case 19: $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} 농약을 술인줄 알고 마셔 죽고말았습니다."; break; + case 20: $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} 아무 이유 없이 죽고말았습니다."; break; + case 21: $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} 전재산을 잃고 화병으로 죽고말았습니다."; break; + case 22: $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} 단식운동을 하다가 굶어 죽고말았습니다."; break; + case 23: $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} 귀신에게 홀려 시름 앓다가 죽고말았습니다."; break; + case 24: $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} 사람들에게 집단으로 맞아서 죽고말았습니다."; break; + case 25: $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} 갑자기 성벽에서 뛰어내려 죽고말았습니다."; break; + case 26: $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} 농사중 호미에 머리를 맞아 죽고말았습니다."; break; + case 27: $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} 저세상이 궁금하다며 자살하고 말았습니다."; break; + case 28: $alllog[0] = "●{$admin['month']}월:운좋기로 소문난 {$general['name']}{$josaYi} 불운하게도 죽고말았습니다."; break; + case 29: $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} 무리하게 단련을 하다가 죽고말았습니다."; break; + case 30: $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} 생활고를 비관하며 자살하고 말았습니다."; break; + case 31: $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} 평생 결혼도 못해보고 죽고 말았습니다."; break; + case 32: $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} 과식하다 배가 터져 죽고 말았습니다."; break; + case 33: $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} 웃다가 숨이 넘어가 죽고 말았습니다."; break; + case 34: $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} 추녀를 보고 놀라서 죽고 말았습니다."; break; + case 35: $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} 물에 빠진 사람을 구하려다 같이 죽고 말았습니다."; break; + case 36: $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} 독살을 준비하다 독에 걸려 죽고 말았습니다."; break; + case 37: $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} 뒷간에서 너무 힘을 주다가 죽고 말았습니다."; break; + case 38: $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} 돌팔이 의사에게 치료받다가 죽고 말았습니다."; break; + case 39: $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} 남의 보약을 훔쳐먹다 부작용으로 죽고 말았습니다."; break; + case 40: $alllog[0] = "●{$admin['month']}월:희대의 사기꾼 {$general['name']}{$josaYi} 사망했습니다."; break; + case 41: $alllog[0] = "●{$admin['month']}월:희대의 호색한 {$general['name']}{$josaYi} 사망했습니다."; break; + default: $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} 사망했습니다."; break; + } + // 엔피씨,엠피씨,의병 사망로그 + if($general['npc'] == 2 || $general['npc'] == 6) { + $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} 사망했습니다."; + } elseif($general['npc'] >= 3) { + switch(rand()%10) { + case 0: $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} 푸대접에 실망하여 떠났습니다."; break; + case 1: $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} 갑자기 화를 내며 떠났습니다."; break; + case 2: $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} 의견차이를 좁히지 못하고 떠났습니다."; break; + case 3: $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} 판단 착오였다며 떠났습니다."; break; + case 4: $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} 생활고가 나아지지 않는다며 떠났습니다."; break; + case 5: $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} 기대가 너무 컸다며 떠났습니다."; break; + case 6: $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} 아무 이유 없이 떠났습니다."; break; + case 7: $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} 자기 목적은 달성했다며 떠났습니다."; break; + case 8: $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} 자기가 없어도 될것 같다며 떠났습니다."; break; + case 9: $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} 처자식이 그립다며 떠났습니다."; break; + } + } + + pushGeneralPublicRecord($alllog, $admin['year'], $admin['month']); + + return; + } + } + + if($general['age'] >= 80 && $general['npc'] == 0) { + if($admin['isunited'] == 0) { + CheckHall($no); + } + + $query = "update general set leader=leader*0.85,power=power*0.85,intel=intel*0.85,injury=0,experience=experience*0.5,dedication=dedication*0.5,firenum=0,warnum=0,killnum=0,deathnum=0,killcrew=0,deathcrew=0,age=20,specage=0,specage2=0,crew=crew*0.85,dex0=dex0*0.5,dex10=dex10*0.5,dex20=dex20*0.5,dex30=dex30*0.5,dex40=dex40*0.5 where no='$no'"; + MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + + $josaYi = JosaUtil::pick($general['name'], '이'); + $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} 은퇴하고 그 자손이 유지를 이어받았습니다."; + pushGeneralPublicRecord($alllog, $admin['year'], $admin['month']); + + $log[0] = "●나이가 들어 은퇴하고 자손에게 자리를 물려줍니다."; + pushGenLog($general, $log); + pushGeneralHistory($general, "●{$admin['year']}년 {$admin['month']}월:나이가 들어 은퇴하고, 자손에게 관직을 물려줌"); + } + + $turntime = addTurn($general['turntime'], $admin['turnterm']); + + $query = "update general set turntime='$turntime' where no='$no'"; + MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); +} + +function CheckHall($no) { + $db = DB::db(); + $gameStor = KVStorage::getStorage($db, 'game_env'); + + $types = array( + "experience", + "dedication", + "firenum", + "warnum", + "killnum", + "winrate", + "killcrew", + "killrate", + "dex0", + "dex10", + "dex20", + "dex30", + "dex40", + "ttrate", + "tlrate", + "tprate", + "tirate", + "betgold", + "betwin", + "betwingold", + "betrate" + ); + + $general = $db->queryFirstRow('SELECT name,name2,owner,nation,picture,imgsvr, + experience,dedication,warnum,firenum,killnum, + killnum/warnum as winrate,killcrew,killcrew/deathcrew as killrate, + dex0,dex10,dex20,dex30,dex40, + ttw/(ttw+ttd+ttl) as ttrate, ttw+ttd+ttl as tt, + tlw/(tlw+tld+tll) as tlrate, tlw+tld+tll as tl, + tpw/(tpw+tpd+tpl) as tprate, tpw+tpd+tpl as tp, + tiw/(tiw+tid+til) as tirate, tiw+tid+til as ti, + betgold, betwin, betwingold, betwingold/betgold as betrate + from general where no=%i', $no); + + if(!$general){ + return; + } + + $unitedDate = TimeUtil::now(); + $nation = getNationStaticInfo($general['nation']); + + $serverCnt = $db->queryFirstField('SELECT count(*) FROM ng_games'); + + [$scenarioIdx, $scenarioName, $startTime] = $gameStor->getValuesAsArray(['scenario', 'scenario_text', 'starttime']); + + foreach($types as $idx=>$typeName) { + + + //승률,살상률인데 10회 미만 전투시 스킵 + if(($typeName === 'winrate' || $typeName === 'killrate') && $general['warnum']<10) { continue; } + //토너승률인데 50회 미만시 스킵 + if($typeName === 'ttrate' && $general['tt'] < 50) { continue; } + //토너승률인데 50회 미만시 스킵 + if($typeName === 'tlrate' && $general['tl'] < 50) { continue; } + //토너승률인데 50회 미만시 스킵 + if($typeName === 'tprate' && $general['tp'] < 50) { continue; } + //토너승률인데 50회 미만시 스킵 + if($typeName === 'tirate' && $general['ti'] < 50) { continue; } + //수익률인데 1000미만시 스킵 + if($typeName === 'betrate' && $general['betgold'] < 1000) { continue; } + + if($general[$typeName]<=0){ + continue; + } + + $aux = [ + 'name'=>$general['name'], + 'nationName'=>$nation['name'], + 'bgColor'=>$nation['color'], + 'fgColor'=>newColor($nation['color']), + 'picture'=>$general['picture'], + 'imgsvr'=>$general['imgsvr'], + 'startTime'=>$startTime, + 'unitedTime'=>$unitedDate, + 'owner_name'=>$general['name2'], + 'serverID'=>UniqueConst::$serverID, + 'serverIdx'=>$serverCnt, + 'serverName'=>UniqueConst::$serverName, + 'scenarioName'=>$scenarioName, + ]; + $jsonAux = Json::encode($aux); + + $db->insertUpdate('ng_hall', [ + 'server_id'=>UniqueConst::$serverID, + 'scenario'=>$scenarioIdx, + 'general_no'=>$no, + 'type'=>$idx, + 'value'=>$general[$typeName]??0, + 'owner'=>$general['owner']??null, + 'aux'=>$jsonAux + ],[ + 'value'=>$general[$typeName]??0, + 'aux'=>$jsonAux + ]); + } +} + +function uniqueItemEx(int $generalID, ActionLogger $logger, string $acquireType='아이템'):bool { + //TODO: 이름 바꾸기 + $db = DB::db(); + $gameStor = KVStorage::getStorage($db, 'game_env'); + + $general = $db->queryFirstRow('SELECT no,name,nation,npc,weap,book,horse,item FROM general WHERE no=%i', $generalID); + if(!$general){ + return false; + } + + if($general['npc'] >= 2) { + return false; + } + if($general['horse'] > 6 || $general['weap'] > 6 || $general['book'] > 6 || $general['item'] > 6){ + return false; + } + + $scenario = $gameStor->scenario; + + $genCount = $db->queryFirstField('SELECT count(*) FROM general WHERE npc<2'); + + if ($scenario < 100) { + $prob = 1 / ($genCount * 5); // 5~6개월에 하나씩 등장 + } + else { + $prob = 1 / $genCount; // 1~2개월에 하나씩 등장 + } + + if($acquireType == '투표'){ + $prob = 1 / ($genCount * 0.7 / 3); // 투표율 70%, 투표 한번에 2~3개 등장 + } + else if($acquireType == '랜덤 임관'){ + $prob = 1 / ($genCount / 10/ 2); // 랜임시 2개(10%) 등장(200명중 20명 랜임시도?) + } + else if($acquireType == '건국'){ + $prob = 1 / ($genCount / 10/ 4); // 건국시 4개(20%) 등장(200명시 20국 정도 됨) + } + + $prob = Util::valueFit($prob, 1/3, 1); + + if(!Util::randBool($prob)){ + return false; + } + + //아이템 습득 상황 + $availableUnique = []; + $itemTypes = [ + 'horse'=>'getHorseName', + 'weap'=>'getWeapName', + 'book'=>'getBookName', + 'item'=>'getItemName' + ]; + $itemCodeList = range(7, 26); // [7, 26] 20개 + + foreach($itemTypes as $itemType=>$itemNameFunc){ + foreach($itemCodeList as $itemCode){ + $availableUnique["{$itemType}_{$itemCode}"] = [$itemType, $itemCode]; + } + } + + //TODO: 너무 바보 같다. 장기적으로는 유니크 아이템 테이블 같은게 필요하지 않을까? + foreach ($itemTypes as $itemType=>$itemNameFunc) { + foreach($db->queryFirstColumn('SELECT %b FROM general WHERE %b > 6', $itemType, $itemType) as $itemCode){ + unset($availableUnique["{$itemType}_{$itemCode}"]); + } + } + + if(!$availableUnique){ + return false; + } + + [$itemType, $itemCode] = Util::choiceRandom($availableUnique); + + $nationName = getNationStaticInfo($general['nation'])['name']; + $generalName = $general['name']; + $josaYi = JosaUtil::pick($generalName, '이'); + $itemName = ($itemTypes[$itemType])($itemCode); + $josaUl = JosaUtil::pick($itemName, '을'); + + + $db->update('general', [ + $itemType=>$itemCode + ], 'no=%i', $generalID); + + $logger->pushGeneralActionLog("{$itemName}{$josaUl} 습득했습니다!"); + $logger->pushGlobalActionLog("{$generalName}{$josaYi} {$itemName}{$josaUl} 습득했습니다!"); + $logger->pushGlobalHistoryLog("【{$acquireType}】{$nationName}{$generalName}{$josaYi} {$itemName}{$josaUl} 습득했습니다!"); + + return true; +} + +function uniqueItem($general, $log, $vote=0) { + //TODO: uniqueItem 을 쓰는 경우를 모두 제거. + $db = DB::db(); + $gameStor = KVStorage::getStorage($db, 'game_env'); + $connect=$db->get(); + $alllog = []; + $history = []; + $occupied = []; + $item = []; + + if($general['npc'] >= 2) { return $log; } + if($general['weap'] > 6 || $general['book'] > 6 || $general['horse'] > 6 || $general['item'] > 6) { return $log; } + + $admin = $gameStor->getValues(['year', 'month', 'scenario']); + + $query = "select count(*) as cnt from general where npc<2"; + $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + $gen = MYDB_fetch_array($result); + + if($admin['scenario'] < 100) { $prob = $gen['cnt'] * 5; } // 5~6개월에 하나씩 등장 + else { $prob = $gen['cnt']; } // 1~2개월에 하나씩 등장 + + if($vote == 1) { $prob = Util::round($gen['cnt'] * 0.7 / 3); } // 투표율 70%, 투표 한번에 2~3개 등장 + elseif($vote == 2) { $prob = Util::round($gen['cnt'] / 10 / 2); } // 랜임시 2개(10%) 등장(200명중 20명 랜임시도?) + elseif($vote == 3) { $prob = Util::round($gen['cnt'] / 10 / 4); } // 건국시 4개(20%) 등장(200명시 20국 정도 됨) + + if($prob < 3) { $prob = 3; } + //아이템 습득 상황 + if(rand() % $prob == 0) { + //셋중 선택 + $sel = rand() % 4; + switch($sel) { + case 0: $type = "weap"; break; + case 1: $type = "book"; break; + case 2: $type = "horse"; break; + case 3: $type = "item"; break; + } + $query = "select no,{$type} from general where {$type}>6"; + $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + $count = MYDB_num_rows($result); + if($count < 20) { + for($i=0; $i < $count; $i++) { + $gen = MYDB_fetch_array($result); + $occupied[$gen[$type]] = 1; + } + for($i=7; $i <= 26; $i++) { + if(!Util::array_get($occupied[$i])) { + $item[] = $i; + } + } + $it = $item[rand() % count($item)]??0; + + $query = "update general set {$type}='$it' where no='{$general['no']}'"; + MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + + $nation = getNationStaticInfo($general['nation']); + + switch($sel) { + case 0: + $josaUl = JosaUtil::pick(getWeapName($it), '을'); + $josaYi = JosaUtil::pick($general['name'], '이'); + $log[] = "".getWeapName($it)."{$josaUl} 습득했습니다!"; + $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} ".getWeapName($it)."{$josaUl} 습득했습니다!"; + pushGeneralHistory($general, "●{$admin['year']}년 {$admin['month']}월:".getWeapName($it)."{$josaUl} 습득"); + if($vote == 0) { + $history[] = "●{$admin['year']}년 {$admin['month']}월:【아이템】{$nation['name']}{$general['name']}{$josaYi} ".getWeapName($it)."{$josaUl} 습득했습니다!"; + } elseif($vote == 1) { + $history[] = "●{$admin['year']}년 {$admin['month']}월:【설문상품】{$nation['name']}{$general['name']}{$josaYi} ".getWeapName($it)."{$josaUl} 습득했습니다!"; + } elseif($vote == 2) { + $history[] = "●{$admin['year']}년 {$admin['month']}월:【랜덤임관상품】{$nation['name']}{$general['name']}{$josaYi} ".getWeapName($it)."{$josaUl} 습득했습니다!"; + } elseif($vote == 3) { + $history[] = "●{$admin['year']}년 {$admin['month']}월:【건국상품】{$nation['name']}{$general['name']}{$josaYi} ".getWeapName($it)."{$josaUl} 습득했습니다!"; + } + break; + case 1: + $josaUl = JosaUtil::pick(getBookName($it), '을'); + $josaYi = JosaUtil::pick($general['name'], '이'); + $log[] = "".getBookName($it)."{$josaUl} 습득했습니다!"; + $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} ".getBookName($it)."{$josaUl} 습득했습니다!"; + pushGeneralHistory($general, "●{$admin['year']}년 {$admin['month']}월:".getBookName($it)."{$josaUl} 습득"); + if($vote == 0) { + $history[] = "●{$admin['year']}년 {$admin['month']}월:【아이템】{$nation['name']}{$general['name']}{$josaYi} ".getBookName($it)."{$josaUl} 습득했습니다!"; + } elseif($vote == 1) { + $history[] = "●{$admin['year']}년 {$admin['month']}월:【설문상품】{$nation['name']}{$general['name']}{$josaYi} ".getBookName($it)."{$josaUl} 습득했습니다!"; + } elseif($vote == 2) { + $history[] = "●{$admin['year']}년 {$admin['month']}월:【랜덤임관상품】{$nation['name']}{$general['name']}{$josaYi} ".getBookName($it)."{$josaUl} 습득했습니다!"; + } elseif($vote == 3) { + $history[] = "●{$admin['year']}년 {$admin['month']}월:【건국상품】{$nation['name']}{$general['name']}{$josaYi} ".getBookName($it)."{$josaUl} 습득했습니다!"; + } + break; + case 2: + $josaUl = JosaUtil::pick(getHorseName($it), '을'); + $josaYi = JosaUtil::pick($general['name'], '이'); + $log[] = "".getHorseName($it)."{$josaUl} 습득했습니다!"; + $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} ".getHorseName($it)."{$josaUl} 습득했습니다!"; + pushGeneralHistory($general, "●{$admin['year']}년 {$admin['month']}월:".getHorseName($it)."{$josaUl} 습득"); + if($vote == 0) { + $history[] = "●{$admin['year']}년 {$admin['month']}월:【아이템】{$nation['name']}{$general['name']}{$josaYi} ".getHorseName($it)."{$josaUl} 습득했습니다!"; + } elseif($vote == 1) { + $history[] = "●{$admin['year']}년 {$admin['month']}월:【설문상품】{$nation['name']}{$general['name']}{$josaYi} ".getHorseName($it)."{$josaUl} 습득했습니다!"; + } elseif($vote == 2) { + $history[] = "●{$admin['year']}년 {$admin['month']}월:【랜덤임관상품】{$nation['name']}{$general['name']}{$josaYi} ".getHorseName($it)."{$josaUl} 습득했습니다!"; + } elseif($vote == 3) { + $history[] = "●{$admin['year']}년 {$admin['month']}월:【건국상품】{$nation['name']}{$general['name']}{$josaYi} ".getHorseName($it)."{$josaUl} 습득했습니다!"; + } + break; + case 3: + $josaUl = JosaUtil::pick(getItemName($it), '을'); + $josaYi = JosaUtil::pick($general['name'], '이'); + $log[] = "".getItemName($it)."{$josaUl} 습득했습니다!"; + $alllog[0] = "●{$admin['month']}월:{$general['name']}{$josaYi} ".getItemName($it)."{$josaUl} 습득했습니다!"; + pushGeneralHistory($general, "●{$admin['year']}년 {$admin['month']}월:".getItemName($it)."{$josaUl} 습득"); + if($vote == 0) { + $history[] = "●{$admin['year']}년 {$admin['month']}월:【아이템】{$nation['name']}{$general['name']}{$josaYi} ".getItemName($it)."{$josaUl} 습득했습니다!"; + } elseif($vote == 1) { + $history[] = "●{$admin['year']}년 {$admin['month']}월:【설문상품】{$nation['name']}{$general['name']}{$josaYi} ".getItemName($it)."{$josaUl} 습득했습니다!"; + } elseif($vote == 2) { + $history[] = "●{$admin['year']}년 {$admin['month']}월:【랜덤임관상품】{$nation['name']}{$general['name']}{$josaYi} ".getItemName($it)."{$josaUl} 습득했습니다!"; + } elseif($vote == 3) { + $history[] = "●{$admin['year']}년 {$admin['month']}월:【건국상품】{$nation['name']}{$general['name']}{$josaYi} ".getItemName($it)."{$josaUl} 습득했습니다!"; + } + break; + } + pushGeneralPublicRecord($alllog, $admin['year'], $admin['month']); + pushWorldHistory($history, $admin['year'], $admin['month']); + } + } + return $log; +} + +function checkAbilityEx(int $generalID, ActionLogger $actLog){ + $db = DB::db(); + $general = $db->queryFirstRow('SELECT leader,leader2,power,power2,intel,intel2 FROM general WHERE no = %i',$generalID); + + if(!$general){ + return; + } + + if($general['leader2'] < 0){ + $db->update('general',[ + 'leader2'=>$db->sqleval('leader2 + %i', GameConst::$upgradeLimit), + 'leader'=>$db->sqleval('leader - 1') + ], 'no=%i', $generalID); + $actLog->pushGeneralActionLog('통솔이 1 떨어졌습니다!', ActionLogger::PLAIN); + return; + } + + if($general['power2'] < 0){ + $db->update('general',[ + 'power2'=>$db->sqleval('power2 + %i', GameConst::$upgradeLimit), + 'power'=>$db->sqleval('power - 1') + ], 'no=%i', $generalID); + $actLog->pushGeneralActionLog('무력이 1 떨어졌습니다!', ActionLogger::PLAIN); + return; + } + + if($general['intel2'] < 0){ + $db->update('general',[ + 'intel2'=>$db->sqleval('intel2 + %i', GameConst::$upgradeLimit), + 'intel'=>$db->sqleval('intel - 1') + ], 'no=%i', $generalID); + $actLog->pushGeneralActionLog('지력이 1 떨어졌습니다!', ActionLogger::PLAIN); + return; + } + + if($general['leader2'] >= GameConst::$upgradeLimit){ + $db->update('general',[ + 'leader2'=>$db->sqleval('leader2 - %i', GameConst::$upgradeLimit), + 'leader'=>$db->sqleval('leader + 1') + ], 'no=%i', $generalID); + $actLog->pushGeneralActionLog('통솔이 1 올랐습니다!', ActionLogger::PLAIN); + return; + } + + if($general['power2'] >= GameConst::$upgradeLimit){ + $db->update('general',[ + 'power2'=>$db->sqleval('power2 - %i', GameConst::$upgradeLimit), + 'power'=>$db->sqleval('power + 1') + ], 'no=%i', $generalID); + $actLog->pushGeneralActionLog('무력이 1 올랐습니다!', ActionLogger::PLAIN); + return; + } + + if($general['intel2'] >= GameConst::$upgradeLimit){ + $db->update('general',[ + 'intel2'=>$db->sqleval('intel2 - %i', GameConst::$upgradeLimit), + 'intel'=>$db->sqleval('intel + 1') + ], 'no=%i', $generalID); + $actLog->pushGeneralActionLog('지력이 1 올랐습니다!', ActionLogger::PLAIN); + return; + } +} + +function checkAbility($general, $log) { + $db = DB::db(); + $connect=$db->get(); + + $limit = GameConst::$upgradeLimit; + + $query = "select no,leader,leader2,power,power2,intel,intel2 from general where no='{$general['no']}'"; + $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + $general = MYDB_fetch_array($result); + + if($general['leader2'] < 0) { + $query = "update general set leader2='$limit'+leader2,leader=leader-1 where no='{$general['no']}'"; + MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + + $log[] = "통솔이 1 떨어졌습니다!"; + } elseif($general['leader2'] >= $limit) { + $query = "update general set leader2=leader2-'$limit',leader=leader+1 where no='{$general['no']}'"; + MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + + $log[] = "통솔이 1 올랐습니다!"; + } + + if($general['power2'] < 0) { + $query = "update general set power2='$limit'+power2,power=power-1 where no='{$general['no']}'"; + MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + + $log[] = "무력이 1 떨어졌습니다!"; + } elseif($general['power2'] >= $limit) { + $query = "update general set power2=power2-'$limit',power=power+1 where no='{$general['no']}'"; + MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + + $log[] = "무력이 1 올랐습니다!"; + } + + if($general['intel2'] < 0) { + $query = "update general set intel2='$limit'+intel2,intel=intel-1 where no='{$general['no']}'"; + MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + + $log[] = "지력이 1 떨어졌습니다!"; + } elseif($general['intel2'] >= $limit) { + $query = "update general set intel2=intel2-'$limit',intel=intel+1 where no='{$general['no']}'"; + MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + + $log[] = "지력이 1 올랐습니다!"; + } + + return $log; +} + +function checkDedication($general, $log) { + $db = DB::db(); + $connect=$db->get(); + + $dedlevel = getDedLevel($general['dedication']); + + $query = "update general set dedlevel='$dedlevel' where no='{$general['no']}'"; + MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + + // 승급했다면 + $josaRoDed = JosaUtil::pick(getDed($general['dedication']), '로'); + $josaRoBill = JosaUtil::pick(getBill($general['dedication']), '로'); + if($general['dedlevel'] < $dedlevel) { + $log[] = "".getDed($general['dedication'])."{$josaRoDed} 승급하여 봉록이 ".getBill($general['dedication'])."{$josaRoBill} 상승했습니다!"; + // 강등했다면 + } elseif($general['dedlevel'] > $dedlevel) { + $log[] = "".getDed($general['dedication'])."{$josaRoDed} 강등되어 봉록이 ".getBill($general['dedication'])."{$josaRoBill} 하락했습니다!"; + } + + return $log; +} + +function checkExperience($general, $log) { + $db = DB::db(); + $connect=$db->get(); + + $explevel = getExpLevel($general['experience']); + + $query = "update general set explevel='$explevel' where no='{$general['no']}'"; + MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + + // 승급했다면 + if($general['explevel'] < $explevel) { + $log[] = "Lv $explevel로 레벨업!"; + // 강등했다면 + } elseif($general['explevel'] > $explevel) { + $log[] = "Lv $explevel로 레벨다운!"; + } + + return $log; +} + +function getAdmin() { + $db = DB::db(); + $gameStor = KVStorage::getStorage($db, 'game_env'); + return $gameStor->getAll(); +} + +function getMe() { + $db = DB::db(); + $connect=$db->get(); + $userID = Session::getUserID(); + + $query = "select * from general where owner='{$userID}'"; + $result = MYDB_query($query, $connect) or Error("접속자가 많아 접속을 중단합니다. 잠시후 갱신해주세요.
getMe : ".MYDB_error($connect),""); + $me = MYDB_fetch_array($result); + + return $me; +} + +function getTroop($troop) { + $db = DB::db(); + $connect=$db->get(); + + $query = "select * from troop where troop='$troop'"; + $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + $troop = MYDB_fetch_array($result); + + return $troop; +} + +function getCity($city, $sel="*") { + $db = DB::db(); + $connect=$db->get(); + + $query = "select {$sel} from city where city='$city'"; + $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + $city = MYDB_fetch_array($result); + + return $city; +} + +function getNation($nation) { + $db = DB::db(); + $connect=$db->get(); + + $query = "select * from nation where nation='$nation'"; + $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + $nation = MYDB_fetch_array($result); + + return $nation; +} + +function deleteNation($general) { + $db = DB::db(); + $gameStor = KVStorage::getStorage($db, 'game_env'); + $connect=$db->get(); + + $history = []; + $date = substr($general['turntime'],11,5); + + $admin = $gameStor->getValues(['year', 'month']); + + $nation = getNationStaticInfo($general['nation']); + + $josaUn = JosaUtil::pick($nation['name'], '은'); + $history[] = "●{$admin['year']}년 {$admin['month']}월:【멸망】{$nation['name']}{$josaUn} 멸망했습니다."; + + $oldNation = $db->queryFirstRow('SELECT * FROM nation WHERE nation=%i', $general['nation']); + $oldNationGenerals = $db->queryFirstColumn('SELECT `no` FROM general WHERE nation=%i', $general['nation']); + $oldNation['generals'] = $oldNationGenerals; + $oldNation['aux'] = Json::decode($oldNation['aux']); + + // 전 장수 재야로 // 전 장수 소속 무소속으로 + $query = "update general set belong=0,troop=0,level=0,nation=0,makelimit=12 where nation='{$general['nation']}'"; + MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + // 도시 공백지로 + $query = "update city set nation=0,front=0,gen1=0,gen2=0,gen3=0 where nation='{$general['nation']}'"; + MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + // 부대 삭제 + $query = "delete from troop where nation='{$general['nation']}'"; + MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + // 국가 삭제 + + $db->insert('ng_old_nations', [ + 'server_id'=>UniqueConst::$serverID, + 'nation'=>$general['nation'], + 'data'=>Json::encode($oldNation) + ]); + + $query = "delete from nation where nation='{$general['nation']}'"; + MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + // 외교 삭제 + $query = "delete from diplomacy where me='{$general['nation']}' or you='{$general['nation']}'"; + MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + + pushWorldHistory($history, $admin['year'], $admin['month']); + refreshNationStaticInfo(); +} + +function nextRuler($general) { + $db = DB::db(); + $gameStor = KVStorage::getStorage($db, 'game_env'); + $connect=$db->get(); + + $admin = $gameStor->getValues(['year', 'month']); + + $query = "select nation,name from nation where nation='{$general['nation']}'"; + $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + $nation = MYDB_fetch_array($result); + + $query = "select no,name from general where nation='{$general['nation']}' and level!='12' and level>='9' order by level desc"; + $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + $corecount = MYDB_num_rows($result); + + //npc or npc유저인 경우 후계 찾기 + if($general['npc'] > 0) { + $query = "select no,name,nation,IF(ABS(affinity-'{$general['affinity']}')>75,150-ABS(affinity-'{$general['affinity']}'),ABS(affinity-'{$general['affinity']}')) as npcmatch2 from general where nation='{$general['nation']}' and level!=12 and npc>0 order by npcmatch2,rand() limit 0,1"; + $npcresult = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + $npccount = MYDB_num_rows($npcresult); + } else { + $npccount = 0; + } + + // 수뇌부가 없으면 공헌도 최고 장수 + if($npccount > 0) { + $nextruler = MYDB_fetch_array($npcresult); + //국명 교체 + //$query = "update nation set name='{$nextruler['name']}' where nation='{$general['nation']}'"; + //MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + } elseif($corecount == 0) { + $query = "select no,name from general where nation='{$general['nation']}' and level!='12' order by dedication desc"; + $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + $corecount = MYDB_num_rows($result); + + // 아무도 없으면 국가 삭제 + if($corecount == 0) { + //분쟁기록 모두 지움 + DeleteConflict($general['nation']); + deleteNation($general); + return; + } else { + $nextruler = MYDB_fetch_array($result); + } + } else { + $nextruler = MYDB_fetch_array($result); + } + + //군주 교체 + $query = "update general set level='12' where no='{$nextruler['no']}'"; + MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + //도시관직해제 + $query = "update city set gen1=0 where gen1='{$nextruler['no']}'"; + MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + //도시관직해제 + $query = "update city set gen2=0 where gen2='{$nextruler['no']}'"; + MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + //도시관직해제 + $query = "update city set gen3=0 where gen3='{$nextruler['no']}'"; + MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + + $josaYi = JosaUtil::pick($nextruler['name'], '이'); + $history = ["●{$admin['year']}년 {$admin['month']}월:【유지】{$nextruler['name']}{$josaYi} {$nation['name']}의 유지를 이어 받았습니다"]; + + pushWorldHistory($history, $admin['year'], $admin['month']); + pushNationHistory($nation, "●{$admin['year']}년 {$admin['month']}월:【유지】{$nextruler['name']}{$josaYi} {$nation['name']}의 유지를 이어 받음."); + // 장수 삭제 및 부대처리는 checkTurn에서 +} + +/** + * $maxDist 이내의 도시를 검색하는 함수 + * @param $from 기준 도시 코드 + * @param $maxDist 검색하고자 하는 최대 거리 + * @param $distForm 리턴 타입. true일 경우 $result[$dist] = [...$city] 이며, false일 경우 $result[$city] = $dist 임 + */ +function searchDistance(int $from, int $maxDist=99, bool $distForm = false) { + $queue = new \SplQueue(); + + $cities = []; + $distanceList = []; + + $queue->enqueue([$from, 0]); + + while(!$queue->isEmpty()){ + list($cityID, $dist) = $queue->dequeue(); + if(key_exists($cityID, $cities)){ + continue; + } + + if(!key_exists($dist, $distanceList)){ + $distanceList[$dist] = []; + } + $distanceList[$dist][] = $cityID; + + $cities[$cityID] = $dist; + if($dist >= $maxDist){ + continue; + } + + foreach(array_keys(CityConst::byID($cityID)->path) as $connCityID){ + if(key_exists($connCityID, $cities)){ + continue; + } + $queue->enqueue([$connCityID, $dist+1]); + } + } + + if($distForm){ + unset($distanceList[0]); + return $distanceList; + } + else{ + return $cities; + } +} + +function isNeighbor(int $nation1, int $nation2, bool $includeNoSupply=true) { + if($nation1 === $nation2){ + return false; + } + $db = DB::db(); + + $nation1Cities = []; + + if($includeNoSupply){ + $supplySql = ''; + } + else{ + $supplySql = 'AND supply = 1'; + } + + foreach($db->queryFirstColumn('SELECT city FROM city WHERE nation = %i %l', $nation1, $supplySql) as $city){ + $nation1Cities[$city] = $city; + } + + foreach($db->queryFirstColumn('SELECT city FROM city WHERE nation = %i %l', $nation2, $supplySql) as $city){ + foreach(array_keys(CityConst::byID($city)->path) as $adjCity){ + if(key_exists($adjCity, $nation1Cities)){ + return true; + } + } + } + + return false; +} + +function CharExperience($exp, $personal) { + switch($personal) { + case 0: case 1; case 6: + $exp *= 1.1; break; + case 4: case 5: case 7: case 10: + $exp *= 0.9; break; + } + $exp = Util::round($exp); + + return $exp; +} + +function getCharExpMultiplier($personal):float{ + static $table = [ + 0 => 1.1, + 1 => 1.1, + 4 => 0.9, + 5 => 0.9, + 6 => 1.1, + 7 => 0.9, + 10 => 0.9 + ]; + return $table[$personal] ?? 1; +} + +function getNationTechMultiplier($nationType):float{ + static $table = [ + 3 => 1.1, + 5 => 0.9, + 6 => 0.9, + 7 => 0.9, + 8 => 0.9, + 12 => 0.9, + 13 => 1.1, + ]; + return $table[$nationType] ?? 1; +} + +function getNationWallMultiplier($nationType):float{ + static $table = [ + 3 => 1.1, + 5 => 1.1, + 10 => 1.1, + 11 => 1.1, + 4 => 0.9, + 7 => 0.9, + 8 => 0.9, + 13 => 0.9, + ]; + return $table[$nationType] ?? 1; +} + +function getNationPeopleMultiplier($nationType):float{ + static $table = [ + 1 => 0.9, + 2 => 1.1, + 3 => 0.9, + 4 => 1.1, + 7 => 1.1, + 9 => 0.9, + 10 => 1.1, + ]; + return $table[$nationType] ?? 1; +} + + +function CharDedication($ded, $personal) { + switch($personal) { + case 10: + $ded *= 0.9; break; + } + $ded = Util::round($ded); + + return $ded; +} + +function getCharDedMultiplier($personal):float{ + static $table = [ + 10 => 0.9 + ]; + return $table[$personal] ?? 1; +} + +function CharAtmos($atmos, $personal) { + switch($personal) { + case 2: case 4: + $atmos += 5; break; + case 0: case 9: case 10: + $atmos -= 5; break; + } + + return $atmos; +} + +function CharTrain($train, $personal) { + switch($personal) { + case 3: case 5: + $train += 5; break; + case 1: case 8: case 10: + $train -= 5; break; + } + + return $train; +} + +function CharCost($cost, $personal) { + switch($personal) { + case 7: case 8: case 9: + $cost *= 0.8; break; + case 2: case 3: case 6: + $cost *= 1.2; break; + } + + return $cost; +} + +function CharCritical($rate, $personal) { + switch($personal) { + case 10: + $rate += 10; break; + } + + return $rate; +} + +function SabotageInjury($city, $type=0) { + $db = DB::db(); + $gameStor = KVStorage::getStorage($db, 'game_env'); + $connect=$db->get(); + $log = []; + + $injuryCount = 0; + + $admin = $gameStor->getValues(['year', 'month']); + + $query = "select no,name,nation from general where city='$city'"; + $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + $gencount = MYDB_num_rows($result); + if($type == 0) { + $log[0] = "●{$admin['month']}월:계략으로 인해 부상을 당했습니다."; + } else { + $log[0] = "●{$admin['month']}월:재난으로 인해 부상을 당했습니다."; + } + for($i=0; $i < $gencount; $i++) { + $general = MYDB_fetch_array($result); + + $injury = rand() % 100; + if($injury < 30) { // 부상률 30% + $injury = intdiv($injury, 2) + 1; // 부상 1~16 + + $query = "update general set crew=crew*0.98,atmos=atmos*0.98,train=train*0.98,injury=injury+'$injury' where no='{$general['no']}'"; + MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); + + pushGenLog($general, $log); + $injuryCount += 1; + } + } + + return $injuryCount; +} + +function getRandTurn($term) { + $randSecond = Util::randRangeInt(0, 60 * $term - 1); + $randFraction = Util::randRangeInt(0, 999999) / 1000000;//6자리 소수 + + return TimeUtil::nowAddSeconds($randSecond + $randFraction, true); +} + +function getRandTurn2($term) { + $randSecond = Util::randRangeInt(0, 60 * $term - 1); + $randFraction = Util::randRangeInt(0, 999999) / 1000000;//6자리 소수 + + return TimeUtil::nowAddSeconds(- $randSecond - $randFraction, true); +} diff --git a/hwe/func.php b/hwe/func.php index 339a964e..18e1cc24 100644 --- a/hwe/func.php +++ b/hwe/func.php @@ -1385,36 +1385,30 @@ function isLock() { return DB::db()->queryFirstField("SELECT plock from plock limit 1") != 0; } -function tryLock() { +function tryLock():bool{ //NOTE: 게임 로직과 관련한 모든 insert, update 함수들은 lock을 거칠것을 권장함. $db = DB::db(); - //테이블 락 - $db->query("lock tables plock write"); + // 잠금 $db->update('plock', [ - 'plock'=>1 - ], true); + 'plock'=>1, + 'locktime'=>TimeUtil::now(true) + ], 'plock=1'); - $isUnlocked = $db->affectedRows() > 0; - - //테이블 언락 - $db->query("unlock tables"); - - return $isUnlocked; + return $db->affectedRows() > 0; } -function unlock() { +function unlock():bool{ // 풀림 - //NOTE: unlock에는 table lock이 필요없는가? $db = DB::db(); - $db->query("lock tables plock write"); $db->update('plock', [ 'plock'=>0 ], true); - $db->query("unlock tables"); + + return $db->affectedRows() > 0; } -function timeover() { +function timeover():bool { $db = DB::db(); $gameStor = KVStorage::getStorage($db, 'game_env'); @@ -1424,8 +1418,8 @@ function timeover() { $t = min($turnterm, 5); $term = $diff; - if($term >= $t || $term < 0) { return 1; } - else { return 0; } + if($term >= $t || $term < 0) { return true; } + else { return false; } } function checkDelay() { @@ -1451,17 +1445,16 @@ function checkDelay() { //지연 해야할 밀린 턴 횟수 $iter = intdiv($timeMinDiff, $term); if($iter > $threshold) { - $minute = $iter * $term; + $minute = ($iter - $threshold) * $term; $newTurntime = $turntime->add(new \DateInterval("PT{$minute}M")); $newNextTurntime = $turntime->add(new \DateInterval("PT{$term}M")); $gameStor->turntime = $newTurntime->format('Y-m-d H:i:s'); $gameStor->starttime = (new \DateTimeImmutable($gameStor->starttime)) ->add(new \DateInterval("PT{$minute}M")) ->format('Y-m-d H:i:s'); - $db->update('general', [ 'turntime'=> $db->sqleval('DATE_ADD(turntime, INTERVAL %i MINUTE)', $minute) - ], 'turntime<=DATE_ADD(turntime, INTERVAL %i MINUTE)', $term); + ], true); $db->update('auction', [ 'expire'=> $db->sqleval('DATE_ADD(expire, INTERVAL %i MINUTE)', $minute) ], true); @@ -1517,227 +1510,6 @@ function updateOnline() { $gameStor->onlinenation = $onnationstr; } -function checkTurn() { - $db = DB::db(); - $gameStor = KVStorage::getStorage($db, 'game_env'); - $connect=$db->get(); - - $alllog = []; - - // 잦은 갱신 금지 현재 5초당 1회 - if(!timeover()) { return; } - // 현재 처리중이면 접근 불가 - - // 파일락 획득 - //FIXME:이미 DB 테이블로 lock을 시도하는데 이게 따로 필요한가? - $fp = fopen(__dir__.'/lock.txt', 'r'); - if(!flock($fp, LOCK_EX)) { - return; - } - - if(!tryLock()){ - return; - } - - $session = Session::getInstance(); - - pushLockLog(["- checkTurn() : ".TimeUtil::now()." : ".$session->userName]); - - // 파일락 해제 - if(!flock($fp, LOCK_UN)) { return; } - // 세마포어 해제 - //if(!@sem_release($sema)) { echo "치명적 에러! Hide_D에게 문의하세요!"; exit(1); } - - pushLockLog(["- checkTurn() 입 : ".TimeUtil::now()." : ".$session->userName]); - - //if(STEP_LOG) delStepLog(); - //if(STEP_LOG) pushStepLog(TimeUtil::now().', 진입'); - - //천통시에는 동결 - if($gameStor->isunited == 2) { - $db->update('plock', ['plock'=>1], true); - return; - } - $gameStor->cacheAll(); - // 1턴이상 갱신 없었으면 서버 지연 - //if(STEP_LOG) pushStepLog(TimeUtil::now().', checkDelay'); - checkDelay(); - // 접속자수, 접속국가, 국가별 접속장수 갱신 - //if(STEP_LOG) pushStepLog(TimeUtil::now().', checkDelay'); - updateOnline(); - //접속자 수 따라서 갱신제한 변경 - //if(STEP_LOG) pushStepLog(TimeUtil::now().', CheckOverhead'); - CheckOverhead(); - //서버정보 - - $date = TimeUtil::now(); - // 최종 처리 월턴의 다음 월턴시간 구함 - $prevTurn = cutTurn($gameStor->turntime, $gameStor->turnterm); - $nextTurn = addTurn($prevTurn, $gameStor->turnterm); - // 현재 턴 이전 월턴까지 모두처리. - //최종 처리 이후 다음 월턴이 현재 시간보다 전이라면 - while($nextTurn <= $date) { - // 월턴이전 장수 모두 처리 - $query = "select no,name,turntime,turn0,npc from general where turntime < '$nextTurn' order by turntime"; - $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); - $gencount = MYDB_num_rows($result); - for($i=0; $i < $gencount; $i++) { - $general = MYDB_fetch_array($result); - - //if(PROCESS_LOG) $processlog[0] = "[{$date}] 월턴 이전 갱신: name({$general['name']}), no({$general['no']}), turntime({$general['turntime']}), turn0({$general['turn0']})"; - //if(PROCESS_LOG) pushProcessLog($processlog); - - //if(STEP_LOG) pushStepLog(TimeUtil::now().', processAI'); - if($general['npc'] >= 2) { processAI($general['no']); } // npc AI 처리 - //if(STEP_LOG) pushStepLog(TimeUtil::now().', PreprocessCommand'); - PreprocessCommand($general['no']); - //if(STEP_LOG) pushStepLog(TimeUtil::now().', processCommand'); - processCommand($general['no']); - //if(STEP_LOG) pushStepLog(TimeUtil::now().', updateCommand'); - updateCommand($general['no']); - //if(STEP_LOG) pushStepLog(TimeUtil::now().', updateTurntime'); - updateTurntime($general['no']); - - } - - // 트래픽 업데이트 - //if(STEP_LOG) pushStepLog(TimeUtil::now().', updateTraffic'); - updateTraffic(); - // 1달마다 처리하는 것들, 벌점 감소 및 건국,전턴,합병 -1, 군량 소모 - //if(STEP_LOG) pushStepLog(TimeUtil::now().', preUpdateMonthly'); - $result = preUpdateMonthly(); - if($result == false) { - pushLockLog(["-- checkTurn() 오류출 : ".TimeUtil::now()." : ".$session->userName]); - - // 잡금 해제 - //if(STEP_LOG) pushStepLog(TimeUtil::now().', unlock'); - $gameStor->resetCache(true); - unlock(); - return false; - } - - // 그 시각 년도,월 저장 - list($gameStor->year, $gameStor->month) = turnDate($nextTurn); - - pushLockLog(["-- checkTurn() ".$gameStor->month."월 : ".TimeUtil::now()." : ".$session->userName]); - - // 이벤트 핸들러 동작 - foreach (DB::db()->query('SELECT * from event') as $rawEvent) { - $eventID = $rawEvent['id']; - $cond = Json::decode($rawEvent['condition']); - $action = Json::decode($rawEvent['action']); - $event = new Event\EventHandler($cond, $action); - - $event->tryRunEvent(['currentEventID'=>$eventID] + $gameStor->getAll(true)); - } - - // 분기계산. 장수들 턴보다 먼저 있다면 먼저처리 - if($gameStor->month == 1) { - // NPC 등장 - //if(STEP_LOG) pushStepLog(TimeUtil::now().', processGoldIncome'); - processGoldIncome(); - //if(STEP_LOG) pushStepLog(TimeUtil::now().', processSpring'); - processSpring(); - //if(STEP_LOG) pushStepLog(TimeUtil::now().', updateYearly'); - updateYearly(); - //if(STEP_LOG) pushStepLog(TimeUtil::now().', updateQuaterly'); - updateQuaterly(); - //if(STEP_LOG) pushStepLog(TimeUtil::now().', disaster'); - disaster(); - //if(STEP_LOG) pushStepLog(TimeUtil::now().', tradeRate'); - tradeRate(); - //if(STEP_LOG) pushStepLog(TimeUtil::now().', addAge'); - addAge(); - // 새해 알림 - $alllog[] = "◆{$gameStor->month}월:{$gameStor->year}년이 되었습니다."; - pushGeneralPublicRecord($alllog, $gameStor->year, $gameStor->month); - } elseif($gameStor->month == 4) { - //if(STEP_LOG) pushStepLog(TimeUtil::now().', updateQuaterly'); - updateQuaterly(); - //if(STEP_LOG) pushStepLog(TimeUtil::now().', disaster'); - disaster(); - } elseif($gameStor->month == 7) { - //if(STEP_LOG) pushStepLog(TimeUtil::now().', processRiceIncome'); - processRiceIncome(); - //if(STEP_LOG) pushStepLog(TimeUtil::now().', processFall'); - processFall(); - //if(STEP_LOG) pushStepLog(TimeUtil::now().', updateQuaterly'); - updateQuaterly(); - //if(STEP_LOG) pushStepLog(TimeUtil::now().', disaster'); - disaster(); - //if(STEP_LOG) pushStepLog(TimeUtil::now().', tradeRate'); - tradeRate(); - } elseif($gameStor->month == 10) { - //if(STEP_LOG) pushStepLog(TimeUtil::now().', updateQuaterly'); - updateQuaterly(); - //if(STEP_LOG) pushStepLog(TimeUtil::now().', disaster'); - disaster(); - } - //if(STEP_LOG) pushStepLog(TimeUtil::now().', postUpdateMonthly'); - postUpdateMonthly(); - - // 다음달로 넘김 - $prevTurn = $nextTurn; - $nextTurn = addTurn($prevTurn, $gameStor->turnterm); - } - - //if(STEP_LOG) pushStepLog(TimeUtil::now().', '.__LINE__); - - // 이시각 정각 시까지 업데이트 완료했음 - $gameStor->turntime = $prevTurn; - - // 그 시각 년도,월 저장 - list($gameStor->year, $gameStor->month) = turnDate($prevTurn); - // 현재시간의 월턴시간 이후 분단위 장수 처리 - do { - $query = "select no,name,turntime,turn0,npc from general where turntime<='$date' order by turntime"; - $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); - $gencount = MYDB_num_rows($result); - - for($i=0; $i < $gencount; $i++) { - $general = MYDB_fetch_array($result); - - //if(PROCESS_LOG) $processlog[0] = "[{$date}] 월턴 이후 갱신: name({$general['name']}), no({$general['no']}), turntime({$general['turntime']}), turn0({$general['turn0']})"; - //if(PROCESS_LOG) pushProcessLog($processlog); - - //if(STEP_LOG) pushStepLog(TimeUtil::now().', processAI'); - if($general['npc'] >= 2) { processAI($general['no']); } // npc AI 처리 - //if(STEP_LOG) pushStepLog(TimeUtil::now().', PreprocessCommand'); - PreprocessCommand($general['no']); - //if(STEP_LOG) pushStepLog(TimeUtil::now().', processCommand'); - processCommand($general['no']); - //if(STEP_LOG) pushStepLog(TimeUtil::now().', updateCommand'); - updateCommand($general['no']); - //if(STEP_LOG) pushStepLog(TimeUtil::now().', updateTurntime'); - updateTurntime($general['no']); - } - } while($gencount > 0); - - //if(STEP_LOG) pushStepLog(TimeUtil::now().', '.__LINE__); - - $gameStor->turntime = $date; - - // 부상 과도 제한 - $query = "update general set injury='80' where injury>'80'"; - MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),""); - //토너먼트 처리 - //if(STEP_LOG) pushStepLog(TimeUtil::now().', processTournament'); - processTournament(); - //거래 처리 - //if(STEP_LOG) pushStepLog(TimeUtil::now().', processAuction'); - processAuction(); - // 잡금 해제 - //if(STEP_LOG) pushStepLog(TimeUtil::now().', unlock'); - $gameStor->resetCache(true); - unlock(); - - pushLockLog(["- checkTurn() 출 : ".TimeUtil::now()." : ".$session->userName]); - - //if(STEP_LOG) pushStepLog(TimeUtil::now().', finish'); - - return true; -} - function addAge() { $db = DB::db(); $gameStor = KVStorage::getStorage($db, 'game_env'); diff --git a/hwe/index.php b/hwe/index.php index c3ab5887..2922756f 100644 --- a/hwe/index.php +++ b/hwe/index.php @@ -23,7 +23,7 @@ $me = $db->queryFirstRow( ); //턴 실행. -checkTurn(); +TurnExecutionHelper::executeAllCommand(); if(!$session->isGameLoggedIn()){ header('Location:..'); diff --git a/hwe/proc.php b/hwe/proc.php index 008db50c..497d393d 100644 --- a/hwe/proc.php +++ b/hwe/proc.php @@ -7,7 +7,5 @@ include "func.php"; $session = Session::getInstance()->setReadOnly(); $db = DB::db(); -$connect=$db->get(); -//increaseRefresh("자동", 2); -checkTurn(); +TurnExecutionHelper::executeAllCommand(); diff --git a/hwe/sammo/DefaultActionTrigger.php b/hwe/sammo/DefaultActionTrigger.php index 03bf5cfc..23416d53 100644 --- a/hwe/sammo/DefaultActionTrigger.php +++ b/hwe/sammo/DefaultActionTrigger.php @@ -2,7 +2,7 @@ namespace sammo; trait DefaultActionTrigger{ - public function onPreTurnExecute(General $general, ?array $nation):array{ + public function onPreTurnExecute(General $general):array{ return []; } public function onCalcDomestic(string $turnType, string $varType, float $value):float{ diff --git a/hwe/sammo/General.php b/hwe/sammo/General.php index 1e3ee449..df173194 100644 --- a/hwe/sammo/General.php +++ b/hwe/sammo/General.php @@ -58,7 +58,7 @@ class General implements iActionTrigger{ $this->personalityObj = new $personalityClass; } - protected function clearActivatedSkill(){ + function clearActivatedSkill(){ foreach ($this->activatedSkill as $skillName=>$state) { if (!$state) { continue; @@ -190,7 +190,7 @@ class General implements iActionTrigger{ return $result; } - public function onPreTurnExecute(General $general, ?array $nation):array{ + public function onPreTurnExecute(General $general):array{ $chain = []; foreach(array_merge([ $this->nationType, @@ -202,7 +202,7 @@ class General implements iActionTrigger{ if(!$iObj){ continue; } - $chain[] = $iObj->onPreTurnExecute($general, $nation); + $chain[] = $iObj->onPreTurnExecute($general); } return array_merge([], ...$chain); } diff --git a/hwe/sammo/TriggerSpecialWar/None.php b/hwe/sammo/TriggerSpecialWar/None.php new file mode 100644 index 00000000..6a68d528 --- /dev/null +++ b/hwe/sammo/TriggerSpecialWar/None.php @@ -0,0 +1,20 @@ +generalObj = new General($rawGeneral, null, $year, $month); + $this->turn = $turn; + } + + public function getGeneral():General{ + return $this->generalObj; + } + + public function preprocessCommand(){ + $general = $this->getGeneral(); + $general->onPreTurnExecute($general); + + if($general->getVar('injury') && !$general->hasActivatedSkill('pre.부상경감')){ + $general->increaseVarWithLimit('injury', -10, 0); + $general->activateSkill('pre.부상경감'); + } + + if($general->getVar('crew') >= 100){ + $currentRice = $general->getVar('rice'); + $consumeRice = Util::toInt($general->getVar('crew') / 100); + if($consumeRice <= $currentRice){ + $general->increaseVar('rice', -$consumeRice); + } + else{ + $general->setVar('rice', 0); + $general->getLogger()->pushGeneralActionLog( + '군량이 모자라 병사들이 소집해제되었습니다!', ActionLogger::PLAIN + ); + } + $general->activateSkill('pre.소집해제'); + } + + $general->clearActivatedSkill(); + } + + public function processCommand(){ + + } + + public function updateCommand(){ + + } + + function updateTurnTime(){ + + } + + + static public function executeGeneralCommandUntil(string $date, \DateTimeInterface $limitActionTime, int $year, int $month){ + $generalsTodo = $db->queryFirstRow( + 'SELECT npc,no,name,picture,imgsvr,nation,nations,city,troop,injury,affinity, +leader,leader2,power,power2,intel,intel2,weap,book,horse,item, +experience,dedication,level,gold,rice,crew,crewtype,train,atmos, +turntime,makenation,makelimit,killturn,block,dedlevel,explevel, +age,belong,personal,special,special2,term, +dex0,dex10,dex20,dex30,dex40, +warnum,killnum,deathnum,killcrew,deathcrew,recwar, +general_turn.`action` AS `action`, general_turn.arg AS arg +FROM general LEFT JOIN general_turn ON general.`no` = general_turn.general_id +WHERE turntime < %s AND general_turn.turn_idx = 0 ORDER BY turntime ASC, `no` ASC', + $date + ); + + $currentTurn = null; + + foreach($generalsTodo as $generalWork){ + $currActionTime = new \DateTimeImmutable(); + if($currActionTime > $limitActionTime){ + return [true, $currentTurn]; + } + + $turn = [ + 'action'=>$generalWork['action'], + 'arg'=>Json::decode($generalWork['arg']) + ]; + unset($generalWork['action']); + unset($generalWork['arg']); + + if($generalWork['npc'] >= 2){ + processAI($generalID); // npc AI 처리 + } + + $turnObj = new static($generalWork, $turn, $year, $month); + $turnObj->preprocessCommand(); + $turnObj->processCommand(); + $turnObj->updateCommand(); + $turnObj->updateTurntime(); + + $currentTurn = $generalWork['turntime']; + } + + return [false, $currentTurn]; + } + + static public function executeAllCommand(){ + if(!timeover()) { return; } + $db = DB::db(); - $this->generalObj = new General(); + + $gameStor = KVStorage::getStorage($db, 'game_env'); + + DB::db(); + + if(!tryLock()){ + return; + } + + if ($gameStor->isunited == 2) { + //천통시에는 동결 + return; + } + + $gameStor->cacheAll(); + // 1턴이상 갱신 없었으면 서버 지연 + checkDelay(); + // 접속자수, 접속국가, 국가별 접속장수 갱신 + updateOnline(); + //접속자 수 따라서 갱신제한 변경 + CheckOverhead(); + + $date = TimeUtil::now(true); + // 최종 처리 월턴의 다음 월턴시간 구함 + $prevTurn = cutTurn($gameStor->turntime, $gameStor->turnterm); + $nextTurn = addTurn($prevTurn, $gameStor->turnterm); + + $maxActionTime = ini_get('max_execution_time'); + $maxActionTime = max($maxActionTime * 2 / 3, $maxActionTime - 10); + $limitActionTime = (new \DateTimeImmutable())->add(TimeUtil::secondsToDateInterval($maxActionTime)); + + // 현재 턴 이전 월턴까지 모두처리. + //최종 처리 이후 다음 월턴이 현재 시간보다 전이라면 + while ($nextTurn <= $date) { + + [$executionOver, $currentTurn] = static::executeGeneralCommandUntil( + $nextTurn, $limitActionTime, $gameStor->year, $gameStor->month + ); + + // 트래픽 업데이트 + updateTraffic(); + + if($executionOver){ + if($currentTurn !== null){ + $gameStor->turntime = $currentTurn; + } + return; + } + + // 1달마다 처리하는 것들, 벌점 감소 및 건국,전턴,합병 -1, 군량 소모 + if(!preUpdateMonthly()){ + $gameStor->resetCache(true); + unlock(); + throw new \RuntimeException('preUpdateMonthly() 처리 에러'); + } + + [$gameStor->year, $gameStor->month] = turnDate($nextTurn); + + // 이벤트 핸들러 동작 + foreach (DB::db()->query('SELECT * from event') as $rawEvent) { + $eventID = $rawEvent['id']; + $cond = Json::decode($rawEvent['condition']); + $action = Json::decode($rawEvent['action']); + $event = new Event\EventHandler($cond, $action); + + $event->tryRunEvent(['currentEventID'=>$eventID] + $gameStor->getAll(true)); + } + + $logger = new ActionLogger(0, 0, $gameStor->year, $gameStor->month, false); + + // 분기계산. 장수들 턴보다 먼저 있다면 먼저처리 + if($gameStor->month == 1) { + processGoldIncome(); + processSpring(); + updateYearly(); + updateQuaterly(); + disaster(); + tradeRate(); + addAge(); + // 새해 알림 + $logger->pushGlobalActionLog("{$gameStor->year}년이 되었습니다."); + $logger->flush(); //TODO: globalAction류는 전역에서 관리하는것이 좋을 듯. + } elseif($gameStor->month == 4) { + updateQuaterly(); + disaster(); + } elseif($gameStor->month == 7) { + processRiceIncome(); + processFall(); + updateQuaterly(); + disaster(); + tradeRate(); + } elseif($gameStor->month == 10) { + updateQuaterly(); + disaster(); + } + + postUpdateMonthly(); + + // 다음달로 넘김 + $prevTurn = $nextTurn; + $nextTurn = addTurn($prevTurn, $gameStor->turnterm); + } + + // 이시각까지는 업데이트 완료했음 + $gameStor->turntime = $prevTurn; + // 그 시각 년도,월 저장 + [$gameStor->year, $gameStor->month] = turnDate($prevTurn); + // 현재시간의 월턴시간 이후 분단위 장수 처리 + + [$executionOver, $currentTurn] = static::executeGeneralCommandUntil( + $nextTurn, $limitActionTime, $gameStor->year, $gameStor->month + ); + + // 부상 과도 제한 + //TODO: 없애고, 부상 자체가 80 이상 넘지 않도록 처리 + $db->update('general', [ + 'injury'=>80 + ], 'injury>%i', 80); + + //토너먼트 처리 + processTournament(); + //거래 처리 + processAuction(); + // 잡금 해제 + $gameStor->resetCache(true); + unlock(); } } \ No newline at end of file diff --git a/hwe/sammo/iActionTrigger.php b/hwe/sammo/iActionTrigger.php index c8ad9b77..bbfbdbb3 100644 --- a/hwe/sammo/iActionTrigger.php +++ b/hwe/sammo/iActionTrigger.php @@ -10,7 +10,7 @@ interface iActionTrigger{ const PRIORITY_FINAL = 10000; //TODO: 능력치는? - public function onPreTurnExecute(General $general, ?array $nation):array; + public function onPreTurnExecute(General $general):array; public function onCalcDomestic(string $turnType, string $varType, float $value):float; public function onPreGeneralStatUpdate(General $general, string $statName, $value); diff --git a/hwe/sql/schema.sql b/hwe/sql/schema.sql index be2a72a4..7a3d57e9 100644 --- a/hwe/sql/schema.sql +++ b/hwe/sql/schema.sql @@ -126,6 +126,7 @@ CREATE TABLE `general` ( `term` INT(4) NULL DEFAULT '0', `recturn` TEXT NULL DEFAULT '', `resturn` VARCHAR(30) NULL DEFAULT '', + `aux` TEXT NOT NULL DEFAULT '{}' COMMENT 'JSON', PRIMARY KEY (`no`), INDEX `nation` (`nation`, `npc`), INDEX `city` (`city`), @@ -483,12 +484,15 @@ create table troop ( ## 락 테이블 ########################################################################## -create table plock ( - no int(11) not null auto_increment, - plock int(1) default 0, - - PRIMARY KEY (no) - ) ENGINE=INNODB DEFAULT CHARSET=utf8mb4; +CREATE TABLE `plock` ( + `no` INT(11) NOT NULL AUTO_INCREMENT, + `plock` INT(1) NOT NULL DEFAULT '0', + `locktime` DATETIME(6) NOT NULL, + PRIMARY KEY (`no`) +) +DEFAULT CHARSET=utf8mb4 +ENGINE=MyISAM +; ########################################################################### ## 메시지 테이블