From a09511defbfa2b08b2316124c00d0103dd7a7846 Mon Sep 17 00:00:00 2001 From: hide_d Date: Mon, 13 Jul 2020 21:54:28 +0900 Subject: [PATCH] =?UTF-8?q?=EC=A0=84=EB=9E=B5=20=EC=82=AC=EC=9A=A9=20?= =?UTF-8?q?=EB=B0=A9=EC=8B=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hwe/func_command.php | 2 +- hwe/func_gamerule.php | 2277 +++++++++-------- hwe/js/processing.js | 2 +- hwe/sammo/Command/BaseCommand.php | 35 +- .../Command/General/che_전투특기초기화.php | 22 +- hwe/sammo/Command/GeneralCommand.php | 40 +- hwe/sammo/Command/Nation/che_급습.php | 502 ++-- hwe/sammo/Command/Nation/che_물자원조.php | 9 + hwe/sammo/Command/Nation/che_백성동원.php | 387 ++- hwe/sammo/Command/Nation/che_수몰.php | 6 +- hwe/sammo/Command/Nation/che_의병모집.php | 486 ++-- hwe/sammo/Command/Nation/che_이호경식.php | 500 ++-- hwe/sammo/Command/Nation/che_초토화.php | 9 + hwe/sammo/Command/Nation/che_피장파장.php | 494 ++-- hwe/sammo/Command/Nation/che_필사즉생.php | 266 +- hwe/sammo/Command/Nation/che_허보.php | 478 ++-- hwe/sammo/Command/NationCommand.php | 86 +- .../Constraint/AvailableStrategicCommand.php | 62 +- hwe/sammo/Constraint/ConstraintHelper.php | 546 ++-- hwe/sammo/DiplomaticMessage.php | 557 ++-- hwe/sammo/GameConstBase.php | 710 ++--- hwe/sammo/ResetHelper.php | 3 + hwe/sammo/ScoutMessage.php | 453 ++-- hwe/sammo/TurnExecutionHelper.php | 2 + 24 files changed, 4024 insertions(+), 3910 deletions(-) diff --git a/hwe/func_command.php b/hwe/func_command.php index 0801abb2..a42e78f3 100644 --- a/hwe/func_command.php +++ b/hwe/func_command.php @@ -232,7 +232,7 @@ function checkCommandArg(?array $arg):?string{ } $defaultCheck = [ /*'string'=>[ - 'nationName', 'optionText', 'itemType', 'nationType' + 'nationName', 'optionText', 'itemType', 'nationType', 'commandType', ],*/ 'integer'=>[ 'crewType', 'destGeneralID', 'destCityID', 'destNationID', diff --git a/hwe/func_gamerule.php b/hwe/func_gamerule.php index c4aae7f8..c0d74ec6 100644 --- a/hwe/func_gamerule.php +++ b/hwe/func_gamerule.php @@ -1,1138 +1,1139 @@ - ['방랑군', 2, 0], - 1 => ['호족', 2, 1], - 2 => ['군벌', 4, 2], - 3 => ['주자사', 4, 5], - 4 => ['주목', 6, 8], - 5 => ['공', 6, 11], - 6 => ['왕', 8, 16], - 7 => ['황제', 8, 21], - ]; - return $table; -} - -function getCityLevelList(): array -{ - return [ - 1 => '수', - 2 => '진', - 3 => '관', - 4 => '이', - 5 => '소', - 6 => '중', - 7 => '대', - 8 => '특' - ]; -} - -//한국가의 전체 전방 설정 -function SetNationFront($nationNo) -{ - if (!$nationNo) { - return; - } - // 도시소유 국가와 선포,교전중인 국가 - - $adj3 = []; - $adj2 = []; - $adj1 = []; - - $db = DB::db(); - foreach ($db->queryFirstColumn( - 'SELECT city FROM city JOIN diplomacy ON diplomacy.you = city.nation WHERE diplomacy.state = 0 AND me = %i', - $nationNo - ) as $city) { - foreach (CityConst::byID($city)->path as $adjKey => $adjVal) { - $adj3[$adjKey] = $adjVal; - } - }; - foreach ($db->queryFirstColumn( - 'SELECT city FROM city JOIN diplomacy ON diplomacy.you = city.nation WHERE diplomacy.state = 1 AND diplomacy.term <= 5 AND me = %i', - $nationNo - ) as $city) { - foreach (CityConst::byID($city)->path as $adjKey => $adjVal) { - $adj1[$adjKey] = $adjVal; - } - } - if (!$adj3 && !$adj1) { - //평시이면 공백지 - //NOTE: if, else일 경우 NPC는 전쟁시에는 공백지로 출병하지 않는다는 뜻이 된다. - foreach ($db->queryFirstColumn('SELECT city from city where nation=0') as $city) { - foreach (CityConst::byID($city)->path as $adjKey => $adjVal) { - $adj2[$adjKey] = $adjVal; - } - } - } - - $db->update('city', [ - 'front' => 0 - ], 'nation=%i', $nationNo); - - if ($adj1) { - $db->update('city', [ - 'front' => 1, - ], 'nation=%i and city in %li', $nationNo, array_keys($adj1)); - } - if ($adj2) { - $db->update('city', [ - 'front' => 2, - ], 'nation=%i and city in %li', $nationNo, array_keys($adj2)); - } - if ($adj3) { - $db->update('city', [ - 'front' => 3, - ], 'nation=%i and city in %li', $nationNo, array_keys($adj3)); - } -} - -function checkSupply() -{ - $db = DB::db(); - - $cities = []; - foreach ($db->query('SELECT city, nation FROM city WHERE nation != 0') as $city) { - $newCity = new \stdClass(); - $newCity->id = Util::toInt($city['city']); - $newCity->nation = Util::toInt($city['nation']); - $newCity->supply = false; - - $cities[$newCity->id] = $newCity; - } - - $queue = new \SplQueue(); - foreach ($db->queryAllLists('SELECT capital, nation FROM nation WHERE `level` > 0') as list($capitalID, $nationID)) { - if (!key_exists($capitalID, $cities)) { - continue; - } - $city = $cities[$capitalID]; - if ($nationID != $city->nation) { - continue; - } - $city->supply = true; - $queue->enqueue($city); - } - - while (!$queue->isEmpty()) { - $cityLink = $queue->dequeue(); - $city = CityConst::byID($cityLink->id); - - foreach (array_keys($city->path) as $connCityID) { - if (!key_exists($connCityID, $cities)) { - continue; - } - $connCity = $cities[$connCityID]; - if ($connCity->nation != $cityLink->nation) { - continue; - } - if ($connCity->supply) { - continue; - } - $connCity->supply = true; - $queue->enqueue($connCity); - } - } - - $db->update('city', [ - 'supply' => 1 - ], 'nation=0'); - - $db->update('city', [ - 'supply' => 0 - ], 'nation!=0'); - - $supply = []; - - foreach ($cities as $city) { - if ($city->supply) { - $supply[] = $city->id; - } - } - - if ($supply) { - $db->update('city', [ - 'supply' => 1 - ], 'city IN %li', $supply); - } -} - -function updateGeneralNumber(){ - $db = DB::db(); - foreach($db->queryAllLists('SELECT nation, count(*) FROM general WHERE npc != 5 GROUP BY nation') as [$nationID, $gennum]){ - if($nationID === 0){ - continue; - } - $db->update('nation', [ - 'gennum'=>$gennum - ], 'nation=%i', $nationID); - } - refreshNationStaticInfo(); -} - -function updateYearly() -{ - //통계 - checkStatistic(); -} - -//관직 변경 해제 -function updateQuaterly() -{ - $db = DB::db(); - - //천도 제한 해제, 관직 변경 제한 해제 - $db->update('nation', [ - 'chief_set' => 0, - ], true); - //관직 변경 제한 해제 - $db->update('city', [ - 'officer_set' => 0, - ], true); -} - -// 벌점 감소와 건국제한-1 전턴제한-1 외교제한-1, 1달마다 실행, 병사 있는 장수의 군량 감소, 수입비율 조정 -function preUpdateMonthly() -{ - $db = DB::db(); - $gameStor = KVStorage::getStorage($db, 'game_env'); - - //연감 월결산 - $result = LogHistory(); - - if ($result == false) { - return false; - } - - - $admin = $gameStor->getValues(['startyear', 'year', 'month']); - $logger = new ActionLogger(0, 0, $admin['year'], $admin['month']); - - //보급선 체크 - checkSupply(); - //미보급도시 10% 감소 - $db->update('city', [ - 'pop' => $db->sqleval('pop * 0.9'), - 'trust' => $db->sqleval('trust * 0.9'), - 'agri' => $db->sqleval('agri * 0.9'), - 'comm' => $db->sqleval('comm * 0.9'), - 'secu' => $db->sqleval('secu * 0.9'), - 'def' => $db->sqleval('def * 0.9'), - 'wall' => $db->sqleval('wall * 0.9'), - ], 'supply = 0'); - //미보급도시 장수 병 훈 사 5%감소 - //NOTE: update inner join도 가능하지만, meekrodb 기준으로 깔끔하게. - $unsuppliedCities = $db->query('SELECT city, nation, trust, name FROM city WHERE supply = 0'); - foreach (Util::arrayGroupBy($unsuppliedCities, 'nation') as $nationID => $cityList) { - $cityIDList = Util::squeezeFromArray($cityList, 'city'); - $db->update('general', [ - 'crew' => $db->sqleval('crew*0.95'), - 'atmos' => $db->sqleval('atmos*0.95'), - 'train' => $db->sqleval('train*0.95'), - ], 'city IN %li AND nation = %i', $cityIDList, $nationID); - } - - //민심30이하 공백지 처리 - $lostCities = []; - foreach ($unsuppliedCities as $unsuppliedCity) { - if ($unsuppliedCity['trust'] >= 30) { - continue; - } - $lostCities[$unsuppliedCity['city']] = $unsuppliedCity; - } - - if ($lostCities) { - foreach ($lostCities as $lostCity) { - $josaYi = JosaUtil::pick($lostCity['name'], '이'); - $logger->pushGlobalHistoryLog("【고립】{$lostCity['name']}{$josaYi} 보급이 끊겨 미지배 도시가 되었습니다."); - } - $db->update('general', [ - 'officer_level' => 1, - 'officer_city' => 0 - ], 'officer_city IN %li', array_keys($lostCities)); - $db->update('city', [ - 'nation' => 0, - 'officer_set' => 0, - 'conflict' => '{}', - 'term' => 0, - 'front' => 0 - ], 'city IN %li', array_keys($lostCities)); - } - - //접률감소, 건국제한-1 - $db->update('general', [ - 'connect' => $db->sqleval('floor(connect*0.99)'), - 'makelimit' => $db->sqleval('greatest(0, makelimit - 1)'), - ], true); - //전략제한-1, 외교제한-1, 세율동기화 - $db->update('nation', [ - 'strategic_cmd_limit' => $db->sqleval('greatest(0, strategic_cmd_limit - 1)'), - 'surlimit' => $db->sqleval('greatest(0, surlimit - 1)'), - 'rate_tmp' => $db->sqleval('rate') - ], true); - - //도시훈사 180년 60, 220년 87, 240년 100 - $rate = Util::round(($admin['year'] - $admin['startyear']) / 1.5) + 60; - if ($rate > 100) $rate = 100; - - // 20 ~ 140원 - $develcost = ($admin['year'] - $admin['startyear'] + 10) * 2; - $gameStor->city_rate = $rate; - $gameStor->develcost = $develcost; - - //매달 사망자 수입 결산 - processWarIncome(); - - //계략, 전쟁표시 해제 - $db->update('city', [ - 'state' => $db->sqleval(<< $db->sqleval('greatest(0, term - 1)'), - 'conflict' => $db->sqleval('if(term = 0,%s,conflict)', '{}'), - ], true); - - //첩보-1 - foreach ($db->queryAllLists("SELECT nation, spy FROM nation WHERE spy!='' AND spy!='{}'") as [$nationNo, $rawSpy]) { - $spyInfo = Json::decode($rawSpy); - - foreach ($spyInfo as $cityNo => $remainMonth) { - if ($remainMonth <= 1) { - unset($spyInfo[$cityNo]); - } else { - $spyInfo[$cityNo] -= 1; - } - } - - $db->update('nation', [ - 'spy' => Json::encode($spyInfo, Json::EMPTY_ARRAY_IS_DICT) - ], 'nation=%i', $nationNo); - } - - return true; -} - -// 외교 로그처리, 외교 상태 처리 -function postUpdateMonthly() -{ - $db = DB::db(); - $gameStor = KVStorage::getStorage($db, 'game_env'); - - $admin = $gameStor->getValues(['startyear', 'year', 'month', 'scenario']); - $globalLogger = new ActionLogger(0, 0, $admin['year'], $admin['month']); - - //도시 수 측정 - $cityNations = []; - foreach ($db->queryAllLists('SELECT city, name, nation FROM city') as [$cityID, $cityName, $cityNation]) { - if (!key_exists($cityNation, $cityNations)) { - $cityNations[$cityNation] = []; - } - $cityNations[$cityNation][] = $cityName; - } - - //각 국가 전월 장수수 대비 당월 장수수로 단합도 산정 - //각 국가 장수수를 구하고 국력 산정 - // $query = "select nation,gennum from nation where level>0"; - // 국력= - // 자원(국가/장수의 금,쌀) - // 기술력 - // 인구수*내정% - // 장수능력 - // 접속률 - // 숙련도 - // 명성,공헌 - $nations = Util::convertArrayToDict($db->query('SELECT - A.nation, - A.gennum, - round(( - round(((A.gold+A.rice)+(select sum(gold+rice) from general where nation=A.nation))/100) - +A.tech - +if(A.level=0,0,( - select round( - sum(pop)*sum(pop+agri+comm+secu+wall+def)/sum(pop_max+agri_max+comm_max+secu_max+wall_max+def_max)/100 - ) from city where nation=A.nation and supply=1 - )) - +(select sum(leadership+strength+intel) from general where nation=A.nation) - +(select round(sum(dex1+dex2+dex3+dex4+dex5)/1000) from general where nation=A.nation) - +(select round(sum(experience+dedication)/100) from general where nation=A.nation) - +(select round(avg(connect)) from general where nation=A.nation) - )/10) - as power, - (select sum(crew) from general where nation=A.nation) as totalCrew - from nation A - group by A.nation'), 'nation'); - $maxPowerValues = KVStorage::getValuesFromInterNamespace($db, 'nation_env', 'max_power'); - - foreach ($nations as $nation) { - $nationID = $nation['nation']; - $nationStor = KVStorage::getStorage($db, $nationID, 'nation_env'); - $genNum[$nationID] = $nation['gennum']; - - $powerValues = $maxPowerValues[$nationID]??[]; - - //약간의 랜덤치 부여 (95% ~ 105%) - - $nation['power'] = Util::round($nation['power'] * (rand() % 101 + 950) / 1000); - $powerValues['maxPower'] = max($powerValues['maxPower'] ?? 0, $nation['power']); - $powerValues['maxCrew'] = max($powerValues['maxCrew'] ?? 0, Util::toInt($nation['totalCrew'])); - - if (count($cityNations[$nationID] ?? []) > count($powerValues['maxCities'] ?? [])) { - $powerValues['maxCities'] = $cityNations[$nationID]; - } - - $db->update('nation', [ - 'power' => $nation['power'] - ], 'nation=%i', $nationID); - $nationStor->max_power = $powerValues; - } - - // 전쟁기한 세팅 - foreach($db->query('SELECT me, you, dead, term FROM diplomacy WHERE state = 0') as $dip) { - $genCount = $genNum[$dip['me']]; - // 25% 참여율일때 두당 10턴에 4000명 소모한다고 계산 - // 4000 / 10 * 0.25 = 100 - $term = floor($dip['dead'] / 100 / $genCount); - $dip['dead'] -= $term * 100 * $genCount; - $term = Util::valueFit($dip['term'] + $term, 0, 13); - - $db->update('diplomacy', [ - 'term' => $term, - 'dead' => $dip['dead'], - ], 'me = %i AND you = %i', $dip['me'], $dip['you']); - } - - //개전국 로그 - foreach($db->query('SELECT me, you FROM diplomacy WHERE state = 1 AND term <= 1 AND me < you') as $dip){ - $nation1 = getNationStaticInfo($dip['me']); - $name1 = $nation1['name']; - $nation2 = getNationStaticInfo($dip['you']); - $name2 = $nation2['name']; - - $josaYi = JosaUtil::pick($name2, '이'); - $josaWa = JosaUtil::pick($name1, '와'); - $globalLogger->pushGlobalHistoryLog("【개전】$name1{$josaWa} $name2{$josaYi} 전쟁을 시작합니다."); - } - //휴전국 로그 - $stopWarList = []; - foreach($db->queryAllLists('SELECT me,you FROM diplomacy WHERE state=0 AND term <= 1 ORDER BY me desc, you desc') as [$me, $you]){ - if($me < $you){ - $key = "{$me}_{$you}"; - } - else{ - $key = "{$you}_{$me}"; - } - if(!key_exists($key, $stopWarList)){ - $stopWarList[$key] = true; - continue; - } - - //양측 기간 모두 0이 되는 상황이면 휴전 - $nation1 = getNationStaticInfo($me); - $name1 = $nation1['name']; - $nation2 = getNationStaticInfo($you); - $name2 = $nation2['name']; - - $josaWa = JosaUtil::pick($name1, '와'); - $josaYi = JosaUtil::pick($name2, '이'); - - $globalLogger->pushGlobalHistoryLog("【휴전】$name1{$josaWa} $name2{$josaYi} 휴전합니다."); - $db->update('diplomacy', [ - 'state'=>2, - 'term'=>0, - ], '(me=%i AND you=%i) OR (you=%i AND me=%i)', $me, $you, $me, $you); - } - - $globalLogger->flush(); - - //사상자 초기화, 외교 기한-1 - $db->update('diplomacy', [ - 'dead'=>$db->sqleval('if(state!=0, 0, dead)'), - 'term'=>$db->sqleval('greatest(0, term-1)'), - ], true); - //불가침 끝나면 통상으로 - $db->update('diplomacy', [ - 'state'=>2, - ], 'state = 7 AND term = 0'); - //선포 끝나면 교전으로 - $db->update('diplomacy', [ - 'state'=>0, - 'term'=>6, - ], 'state = 1 AND term = 0'); - - //초반이후 방랑군 자동 해체 - if ($admin['year'] >= $admin['startyear'] + 2) { - checkWander(); - } - // 작위 업데이트 - updateNationState(); - updateGeneralNumber(); - refreshNationStaticInfo(); - // 천통여부 검사 - checkEmperior(); - //토너먼트 개시 - triggerTournament(); - // 시스템 거래건 등록 - registerAuction(); - //전방설정 - foreach (getAllNationStaticInfo() as $nation) { - if ($nation['level'] <= 0) { - continue; - } - SetNationFront($nation['nation']); - } -} - - -function checkWander() -{ - $db = DB::db(); - $gameStor = KVStorage::getStorage($db, 'game_env'); - - $admin = $gameStor->getValues(['year', 'month']); - - $wanderers = $db->queryFirstColumn('SELECT general.`no` FROM general LEFT JOIN nation ON general.nation = nation.nation WHERE nation.`level` = 0 AND general.`officer_level` = 12'); - - foreach (General::createGeneralObjListFromDB($wanderers) as $wanderer) { - $wanderCmd = buildGeneralCommandClass('che_해산', $wanderer, $admin); - if ($wanderCmd->hasFullConditionMet()) { - $logger = $wanderer->getLogger(); - $logger->pushGeneralActionLog('초반 제한후 방랑군은 자동 해산됩니다.', ActionLogger::PLAIN); - $wanderCmd->run(); - } - } - - if ($wanderers) { - refreshNationStaticInfo(); - } -} - -function updateNationState() -{ - $db = DB::db(); - $gameStor = KVStorage::getStorage($db, 'game_env'); - - $history = array(); - $admin = $gameStor->getValues(['killturn', 'year', 'month', 'fiction', 'startyear', 'show_img_level', 'turnterm', 'turntime']); - - $assemblerCnts = []; - foreach ($db->queryAllLists('SELECT nation,count(no) FROM general WHERE npc = 5 GROUP BY nation') as [$nationID, $assemblerCnt]) { - $assemblerCnts[$nationID] = $assemblerCnt; - }; - - foreach ($db->query('SELECT nation,name,level,tech,aux FROM nation') as $nation) { - //TODO: level이 진관수이소중대특 체계를 벗어날 수 있음 - $citycount = $db->queryFirstField('SELECT count(*) FROM city WHERE nation=%i AND level>=4', $nation['nation']); - - if ($citycount == 0) { - $nationlevel = 0; // 방랑군 - } elseif ($citycount == 1) { - $nationlevel = 1; // 호족 - } elseif ($citycount <= 4) { - $nationlevel = 2; // 군벌 - } elseif ($citycount <= 7) { - $nationlevel = 3; // 주자사 - } elseif ($citycount <= 10) { - $nationlevel = 4; // 주목 - } elseif ($citycount <= 15) { - $nationlevel = 5; // 공 - } elseif ($citycount <= 20) { - $nationlevel = 6; // 왕 - } else { - $nationlevel = 7; // 황제 - } - - if ($nationlevel > $nation['level']) { - $levelDiff = $nationlevel - $nation['level']; - $oldLevel = $nation['level']; - $nation['level'] = $nationlevel; - - $updateVals = [ - 'level' => $nationlevel, - 'gold'=>$db->sqleval('gold + %i', $nationlevel*1000), - 'rice'=>$db->sqleval('rice + %i', $nationlevel*1000), - ]; - - switch ($nationlevel) { - case 7: - $josaUl = JosaUtil::pick(getNationLevel($nationlevel), '을'); - $history[] = "●{$admin['year']}년 {$admin['month']}월:【작위】{$nation['name']}의 군주가 " . getNationLevel($nationlevel) . "{$josaUl} 자칭하였습니다."; - pushNationHistoryLog($nation['nation'], ["●{$admin['year']}년 {$admin['month']}월:{$nation['name']}의 군주가 " . getNationLevel($nationlevel) . "{$josaUl} 자칭"]); - $auxVal = Json::decode($nation['aux']); - $auxVal['can_국기변경'] = 1; - $auxVal['can_국호변경'] = 1; - $updateVals['aux'] = Json::encode($auxVal); - break; - case 6: - $history[] = "●{$admin['year']}년 {$admin['month']}월:【작위】{$nation['name']}의 군주가 " . getNationLevel($nationlevel) . "에 등극하였습니다."; - pushNationHistoryLog($nation['nation'], ["●{$admin['year']}년 {$admin['month']}월:{$nation['name']}의 군주가 " . getNationLevel($nationlevel) . "에 등극"]); - break; - case 5: - case 4: - case 3: - $history[] = "●{$admin['year']}년 {$admin['month']}월:【작위】{$nation['name']}의 군주가 " . getNationLevel($nationlevel) . "에 임명되었습니다."; - pushNationHistoryLog($nation['nation'], ["●{$admin['year']}년 {$admin['month']}월:{$nation['name']}의 군주가 " . getNationLevel($nationlevel) . "에 임명됨"]); - break; - case 2: - $history[] = "●{$admin['year']}년 {$admin['month']}월:【작위】{$nation['name']}의 군주가 독립하여 " . getNationLevel($nationlevel) . "로 나섰습니다."; - pushNationHistoryLog($nation['nation'], ["●{$admin['year']}년 {$admin['month']}월:{$nation['name']}의 군주가 " . getNationLevel($nationlevel) . "로 나서다"]); - break; - } - - $db->update('nation', $updateVals, 'nation=%i', $nation['nation']); - - $turnRows = []; - foreach (Util::range(getNationChiefLevel($nation['level']), 12) as $chiefLevel) { - foreach (Util::range(GameConst::$maxChiefTurn) as $turnIdx) { - $turnRows[] = [ - 'nation_id' => $nation['nation'], - 'officer_level' => $chiefLevel, - 'turn_idx' => $turnIdx, - 'action' => '휴식', - 'arg' => null, - 'brief' => '휴식' - ]; - } - } - $db->insertIgnore('nation_turn', $turnRows); - - if ($levelDiff) { - //유니크 아이템 하나 돌리자 - $targetKillTurn = $admin['killturn']; - $targetKillTurn -= 24 * 60 / $admin['turnterm']; - $nationGenIDList = $db->queryFirstColumn( - 'SELECT no FROM general WHERE nation = %i AND killturn >= %i AND npc < 2', - $nation['nation'], - $targetKillTurn - ); - $nationGenList = General::createGeneralObjListFromDB($nationGenIDList, ['belong'], 2); - - $uniqueLotteryWeightList = []; - foreach ($nationGenList as $nationGen) { - $hasUnique = false; - foreach ($nationGen->getItems() as $item) { - if (!$item->isBuyable()) { - $hasUnique = true; - break; - } - } - if ($hasUnique) { - continue; - } - - $score = $nationGen->getVar('belong') + 5; - - if ($nationGen->getVar('officer_level') == 12) { - $score += 200; //NOTE: 꼬우면 군주하세요. - } else if ($nationGen->getVar('officer_level') == 11) { - $score += 70; - } else if ($nationGen->getVar('officer_level') > 4) { - $score += 35; - } - $uniqueLotteryWeightList[$nationGen->getID()] = [$nationGen, $score]; - } - - foreach (Util::range($levelDiff) as $idx) { - if (!$uniqueLotteryWeightList) { - break; - } - - /** @var General */ - $winnerObj = Util::choiceRandomUsingWeightPair($uniqueLotteryWeightList); - unset($uniqueLotteryWeightList[$winnerObj->getID()]); - giveRandomUniqueItem($winnerObj, '작위보상'); - $winnerObj->applyDB($db); - } - } - } - - $assemblerCnt = $assemblerCnts[$nation['nation']] ?? 0; - $maxAssemblerCnt = [ - 1 => 0, - 2 => 1, - 3 => 3, - 4 => 4, - 5 => 6, - 6 => 7, - 7 => 9 - ][$nationlevel] ?? 0; - - if ($assemblerCnt < $maxAssemblerCnt) { - $lastAssemblerID = $gameStor->assembler_id ?? 0; - - while ($assemblerCnt < $maxAssemblerCnt) { - $lastAssemblerID += 1; - $npcObj = new Scenario\NPC( - 999, - sprintf('부대장%4d', $lastAssemblerID), - null, - $nation['nation'], - null, - 10, - 10, - 10, - 1, - $admin['year'] - 15, - $admin['year'] + 15, - '은둔', - '척사' - ); - $npcObj->killturn = 70; - $npcObj->gold = 0; - $npcObj->rice = 0; - $npcObj->npc = 5; - $npcObj->build($admin); - $npcID = $npcObj->generalID; - - $db->insert('troop', [ - 'troop_leader' => $npcID, - 'name' => $npcObj->realName, - 'nation' => $nation['nation'], - ]); - $db->update('general', [ - 'troop' => $npcID - ], 'no=%i', $npcID); - - $cmd = buildGeneralCommandClass('che_집합', General::createGeneralObjFromDB($npcID), $admin); - _setGeneralCommand($cmd, iterator_to_array(Util::range(GameConst::$maxTurn))); - $assemblerCnt += 1; - $gameStor->assembler_id = $lastAssemblerID; - } - } - } - pushGlobalHistoryLog($history, $admin['year'], $admin['month']); -} - -function checkStatistic() -{ - $db = DB::db(); - $gameStor = KVStorage::getStorage($db, 'game_env'); - - $admin = $gameStor->getValues(['year', 'month']); - - $nationHists = []; - $specialHists = []; - $personalHists = []; - $specialHists2 = []; - $crewtypeHists = []; - - $etc = ''; - - $auxData = [ - 'generals' => [], - 'nations' => [], - ]; - - $avgGeneral = $db->queryFirstRow( - 'SELECT avg(gold) as avggold, avg(rice) as avgrice, avg(dex1+dex2+dex3+dex4) as avgdex, - max(dex1+dex2+dex3+dex4) as maxdex, avg(experience+dedication) as avgexpded, max(experience+dedication) as maxexpded - FROM general' - ); - $auxData['generals']['avg'] = $avgGeneral; - - $avgGeneral['avggold'] = Util::round($avgGeneral['avggold']); - $avgGeneral['avgrice'] = Util::round($avgGeneral['avgrice']); - $avgGeneral['avgdex'] = Util::round($avgGeneral['avgdex']); - $avgGeneral['avgexpded'] = Util::round($avgGeneral['avgexpded']); - $etc .= "평균 금/쌀 ({$avgGeneral['avggold']}/{$avgGeneral['avgrice']}), 평균/최고 숙련({$avgGeneral['avgdex']}/{$avgGeneral['maxdex']}), 평균/최고 경험공헌({$avgGeneral['avgexpded']}/{$avgGeneral['maxexpded']}), "; - - $avgNation = $db->queryFirstRow( - 'SELECT min(tech) as mintech, max(tech) as maxtech, avg(tech) as avgtech, - min(power) as minpower, max(power) as maxpower, avg(power) as avgpower from nation where level>0' - ); - $auxData['nations']['avg'] = $avgNation; - - $avgNation['mintech'] = floor($avgNation['mintech']); - $avgNation['maxtech'] = floor($avgNation['maxtech']); - $avgNation['avgtech'] = Util::round($avgNation['avgtech']); - $avgNation['avgpower'] = Util::round($avgNation['avgpower']); - $etc .= "최저/평균/최고 기술({$avgNation['mintech']}/{$avgNation['avgtech']}/{$avgNation['maxtech']}), "; - $etc .= "최저/평균/최고 국력({$avgNation['minpower']}/{$avgNation['avgpower']}/{$avgNation['maxpower']}), "; - - $nationName = ''; - $powerHist = ''; - - $nations = Util::convertArrayToDict( - $db->query( - 'SELECT nation,name,type,power,gennum,gold+rice as goldrice from nation where level>0 order by power desc', - 'nation' - ), - 'nation' - ); - $nationCount = count($nations); - - $nationGeneralInfos = Util::convertArrayToDict( - $db->query( - 'SELECT nation, sum(leadership+strength+intel) as abil,sum(gold+rice) as goldrice, - sum(dex1+dex2+dex3+dex4) as dex,sum(experience+dedication) as expded - from general GROUP BY nation' - ), - 'nation' - ); - - $nationCityInfos = Util::convertArrayToDict( - $db->query('SELECT nation, count(*) as cnt, sum(pop) as pop,sum(pop_max) as pop_max from city GROUP BY nation'), - 'nation' - ); - - foreach ($nations as $nationNo => &$nation) { - $general = $nationGeneralInfos[$nationNo]; - $city = $nationCityInfos[$nationNo]; - - $nation['generalInfo'] = $general; - $nation['cityInfo'] = $city; - - $nationName .= $nation['name'] . '(' . getNationType($nation['type']) . '), '; - $powerHist .= "{$nation['name']}({$nation['power']}/{$nation['gennum']}/{$city['cnt']}/{$city['pop']}/{$city['pop_max']}/{$nation['goldrice']}/{$general['goldrice']}/{$general['abil']}/{$general['dex']}/{$general['expded']}), "; - - if (!isset($nationHists[$nation['type']])) { - $nationHists[$nation['type']] = 0; - } - $nationHists[$nation['type']]++; - } - unset($nation); - - $auxData['nations']['all'] = $nations; - - $nationHist = ''; - foreach (GameConst::$availableNationType as $nationType) { - if (!Util::array_get($nationHists[$nationType])) { - $nationHists[$nationType] = '-'; - } - $nationHist .= getNationType($nationType) . "({$nationHists[$nationType]}), "; - } - - $generals = $db->query('SELECT `no`,npc,personal,special,special2,crewtype FROM general'); - - $genCount = 0; - $npcCount = 0; - $generalCount = count($generals); - - foreach ($generals as $general) { - if (!isset($personalHists[$general['personal']])) { - $personalHists[$general['personal']] = 0; - } - - if (!isset($specialHists[$general['special']])) { - $specialHists[$general['special']] = 0; - } - - if (!isset($specialHists2[$general['special2']])) { - $specialHists2[$general['special2']] = 0; - } - - if ($general['npc'] < 2) { - $genCount += 1; - } else { - $npcCount += 1; - } - - $personalHists[$general['personal']]++; - $specialHists[$general['special']]++; - $specialHists2[$general['special2']]++; - } - - foreach ($db->queryAllLists( - 'SELECT crewtype, count(crewtype) AS cnt FROM general WHERE recent_war != NULL GROUP BY crewtype' - ) as [$crewtype, $cnt]) { - $crewtypeHists[$crewtype] = $cnt; - } - - $auxData['generals']['hists'] = [ - 'personal' => $personalHists, - 'special' => $specialHists, - 'special2' => $specialHists2, - 'crewtype' => $crewtypeHists, - 'userCnt' => $genCount, - 'npcCnt' => $npcCount, - ]; - - $generalCountStr = "{$generalCount}({$genCount}+{$npcCount})"; - - $personalHistStr = join(', ', array_map(function ($histPair) { - [$histKey, $cnt] = $histPair; - return getGenChar($histKey) . '(' . $cnt . ')'; - }, Util::convertDictToArray($personalHists))); - - $specialHistsStr = join(', ', array_map(function ($histPair) { - [$histKey, $cnt] = $histPair; - return getGeneralSpecialDomesticName($histKey) . '(' . $cnt . ')'; - }, Util::convertDictToArray($specialHists))); - - $specialHists2Str = join(', ', array_map(function ($histPair) { - [$histKey, $cnt] = $histPair; - return getGeneralSpecialWarName($histKey) . '(' . $cnt . ')'; - }, Util::convertDictToArray($specialHists2))); - - $specialHistsAllStr = "$specialHistsStr // $specialHists2Str"; - - $crewtypeHistsStr = join(', ', array_map(function ($histPair) { - [$histKey, $cnt] = $histPair; - return GameUnitConst::byID($histKey)->getShortName() . '(' . $cnt . ')'; - }, Util::convertDictToArray($crewtypeHists))); - - $db->insert('statistic', [ - 'year' => $admin['year'], - 'month' => $admin['month'], - 'nation_count' => $nationCount, - 'nation_name' => $nationName, - 'nation_hist' => $nationHist, - 'gen_count' => $generalCountStr, - 'personal_hist' => $personalHistStr, - 'special_hist' => $specialHistsAllStr, - 'power_hist' => $powerHist, - 'crewtype' => $crewtypeHistsStr, - 'etc' => $etc, - 'aux' => Json::encode($auxData) - ]); -} - - -function convForOldGeneral(array $general, int $year, int $month) -{ - $general['history'] = getGeneralHistoryLogAll($general['no']); - return [ - 'server_id' => UniqueConst::$serverID, - 'general_no' => $general['no'], - 'owner' => $general['owner'], - 'name' => $general['name'], - 'last_yearmonth' => $year * 100 + $month, - 'turntime' => $general['turntime'], - 'data' => Json::encode($general) - ]; -} - -function storeOldGeneral(int $no, int $year, int $month) -{ - $db = DB::db(); - $general = $db->queryFirstRow('SELECT * FROM general WHERE `no` = %i', $no); - if (!$general) { - return; - } - $data = convForOldGeneral($general, $year, $month); - $db->insertUpdate( - 'ng_old_generals', - $data, - $data - ); -} - -function storeOldGenerals(int $nation, int $year, int $month) -{ - $db = DB::db(); - foreach ($db->query('SELECT * FROM general WHERE nation = %i', $nation) as $general) { - $data = convForOldGeneral($general, $year, $month); - $db->insertUpdate( - 'ng_old_generals', - $data, - $data - ); - } -} - -function checkEmperior() -{ - $db = DB::db(); - $gameStor = KVStorage::getStorage($db, 'game_env'); - - $admin = $gameStor->getValues(['year', 'month', 'isunited', 'conlimit']); - if ($admin['isunited'] != 0) { - return; - } - - $remainNations = $db->queryFirstColumn('SELECT nation FROM nation WHERE level > 0 LIMIT 2'); - - if (!$remainNations || count($remainNations) != 1) { - return; - } - - $nationID = $remainNations[0]; - - $nationStor = KVStorage::getStorage($db, $nationID, 'nation_env'); - - $cityCnt = $db->queryFirstField('SELECT count(city) FROM city WHERE nation=%i', $nationID); - if (!$cityCnt) { - return; - } - - if ($cityCnt != count(CityConst::all())) { - return; - } - - checkStatistic(); - - $nation = $db->queryFirstRow('SELECT * FROM nation WHERE nation=%i', $nationID); - $nationName = $nation['name']; - - $josaYi = JosaUtil::pick($nationName, '이'); - - $nationLogger = new ActionLogger(0, $nationID, $admin['year'], $admin['month']); - $nationLogger->pushNationalHistoryLog("{$nationName}{$josaYi} 전토를 통일"); - - $gameStor->isunited = 2; - $gameStor->conlimit = $gameStor->conlimit * 100; - - foreach ($db->queryFirstColumn('SELECT no FROM general WHERE npc<2 AND age>=%i', GameConst::$minPushHallAge) as $hallGeneralNo) { - CheckHall($hallGeneralNo); - } - - [$totalPop, $totalMaxPop] = $db->queryFirstList('SELECT SUM(pop), SUM(pop_max) FROM city'); - $pop = "{$totalPop} / {$totalMaxPop}"; - $poprate = round($totalPop / $totalMaxPop * 100, 2). " %"; - - $chiefs = Util::convertArrayToDict( - $db->query( - 'SELECT no,name,picture,belong,officer_level FROM general WHERE nation=%i AND officer_level >= 5', - $nationID - ), - 'officer_level' - ); - - $nationGenerals = $db->queryFirstColumn('SELECT `no` FROM general WHERE nation=%i', $nationID); - $nation['generals'] = $nationGenerals; - - $tigers = $db->query( - 'SELECT value, name - FROM rank_data LEFT JOIN general ON rank_data.general_id = general.no - WHERE rank_data.nation_id = %i AND rank_data.type = "killnum" AND value > 0 ORDER BY value DESC LIMIT 5', - $nationID - ); // 오호장군 - - $tigerstr = join(', ', array_map(function ($arr) { - $number = number_format($arr['value']); - return "{$arr['name']}【{$number}】"; - }, $tigers)); - - $eagles = $db->query( - 'SELECT value, name - FROM rank_data LEFT JOIN general ON rank_data.general_id = general.no - WHERE rank_data.nation_id = %i AND rank_data.type = "firenum" AND value > 0 ORDER BY value DESC LIMIT 7', - $nationID - ); // 건안칠자 - - $eaglestr = join(', ', array_map(function ($arr) { - $number = number_format($arr['value']); - return "{$arr['name']}【{$number}】"; - }, $eagles)); - - $rawGeneralList = $db->query('SELECT no, name, npc, owner FROM general WHERE nation=%i ORDER BY dedication DESC', $nationID); - foreach ($rawGeneralList as $rawGeneral) { - $generalLogger = new ActionLogger($rawGeneral['no'], $nationID, $admin['year'], $admin['month']); - $generalLogger->pushGeneralActionLog("{$nationName}{$josaYi} 전토를 통일하였습니다.", ActionLogger::YEAR_MONTH); - $generalLogger->flush(); - } - - $gen = join(', ', array_column($rawGeneral, 'name')); - - $stat = $db->queryFirstRow('SELECT max(nation_count) as nc, max(gen_count) as gc FROM statistic'); - $genCnt = $db->queryFirstField('SELECT count(*) FROM general'); - - $statNC = "1 / {$stat['nc']}"; - $statGC = "{$genCnt} / {$stat['gc']}"; - $statNation = $db->queryFirstRow('SELECT nation_count,nation_name,nation_hist from statistic where nation_count=%i LIMIT 1', $stat['nc']); - $statGeneral = $db->queryFirstRow('SELECT gen_count,personal_hist,special_hist,aux from statistic order by no desc LIMIT 1'); - - $nation = $nation; - $nation['generals'] = $db->queryFirstColumn('SELECT `no` FROM general WHERE nation=%i', $nation['nation']); - $nation['aux'] = Json::decode($nation['aux']); - $nation['msg'] = $nationStor->notice; - $nation['scout_msg'] = $nationStor->scout_msg; - $nation['aux'] += $nationStor->max_power; - $nation['history'] = getNationHistoryLogAll($nation['nation']); - - storeOldGenerals(0, $admin['year'], $admin['month']); - storeOldGenerals($nation['nation'], $admin['year'], $admin['month']); - - $db->insert('ng_old_nations', [ - 'server_id' => UniqueConst::$serverID, - 'nation' => $nation['nation'], - 'data' => Json::encode($nation) - ]); - - $noNationGeneral = $db->queryFirstColumn('SELECT `no` FROM general WHERE nation=0'); - $db->insert('ng_old_nations', [ - 'server_id' => UniqueConst::$serverID, - 'nation' => 0, - 'data' => Json::encode([ - 'nation' => 0, - 'name' => '재야', - 'generals' => $noNationGeneral - ]) - ]); - - $nationHistory = getNationHistoryLogAll($nation['nation']); - - $serverCnt = $db->queryFirstField('SELECT count(*) FROM ng_games'); - $serverName = UniqueConst::$serverName; - - $db->update('ng_games', [ - 'winner_nation' => $nation['nation'] - ], 'server_id=%s', UniqueConst::$serverID); - - $db->insert('emperior', [ - 'phase' => $serverName . $serverCnt . '기', - 'server_id' => UniqueConst::$serverID, - 'nation_count' => $statNC, - 'nation_name' => $statNation['nation_name'], - 'nation_hist' => $statNation['nation_hist'], - 'gen_count' => $statGC, - 'personal_hist' => $statGeneral['personal_hist'], - 'special_hist' => $statGeneral['special_hist'], - 'name' => $nation['name'], - 'type' => $nation['type'], - 'color' => $nation['color'], - 'year' => $admin['year'], - 'month' => $admin['month'], - 'power' => $nation['power'], - 'gennum' => $nation['gennum'], - 'citynum' => $cityCnt, - 'pop' => $pop, - 'poprate' => $poprate, - 'gold' => $nation['gold'], - 'rice' => $nation['rice'], - 'l12name' => $chiefs[12]['name'], - 'l12pic' => $chiefs[12]['picture'], - 'l11name' => $chiefs[11]['name'], - 'l11pic' => $chiefs[11]['picture'], - 'l10name' => $chiefs[10]['name'], - 'l10pic' => $chiefs[10]['picture'], - 'l9name' => $chiefs[9]['name'], - 'l9pic' => $chiefs[9]['picture'], - 'l8name' => $chiefs[8]['name'], - 'l8pic' => $chiefs[8]['picture'], - 'l7name' => $chiefs[7]['name'], - 'l7pic' => $chiefs[7]['picture'], - 'l6name' => $chiefs[6]['name'], - 'l6pic' => $chiefs[6]['picture'], - 'l5name' => $chiefs[5]['name'], - 'l5pic' => $chiefs[5]['picture'], - 'tiger' => $tigerstr, - 'eagle' => $eaglestr, - 'gen' => $gen, - 'history' => JSON::encode($nationHistory), - 'aux' => $statGeneral['aux'] - ]); - - $history = ["●{$admin['year']}년 {$admin['month']}월:【통일】{$nation['name']}{$josaYi} 전토를 통일하였습니다."]; - pushGlobalHistoryLog($history, $admin['year'], $admin['month']); - - //연감 월결산 - LogHistory(); -} + ['방랑군', 2, 0], + 1 => ['호족', 2, 1], + 2 => ['군벌', 4, 2], + 3 => ['주자사', 4, 5], + 4 => ['주목', 6, 8], + 5 => ['공', 6, 11], + 6 => ['왕', 8, 16], + 7 => ['황제', 8, 21], + ]; + return $table; +} + +function getCityLevelList(): array +{ + return [ + 1 => '수', + 2 => '진', + 3 => '관', + 4 => '이', + 5 => '소', + 6 => '중', + 7 => '대', + 8 => '특' + ]; +} + +//한국가의 전체 전방 설정 +function SetNationFront($nationNo) +{ + if (!$nationNo) { + return; + } + // 도시소유 국가와 선포,교전중인 국가 + + $adj3 = []; + $adj2 = []; + $adj1 = []; + + $db = DB::db(); + foreach ($db->queryFirstColumn( + 'SELECT city FROM city JOIN diplomacy ON diplomacy.you = city.nation WHERE diplomacy.state = 0 AND me = %i', + $nationNo + ) as $city) { + foreach (CityConst::byID($city)->path as $adjKey => $adjVal) { + $adj3[$adjKey] = $adjVal; + } + }; + foreach ($db->queryFirstColumn( + 'SELECT city FROM city JOIN diplomacy ON diplomacy.you = city.nation WHERE diplomacy.state = 1 AND diplomacy.term <= 5 AND me = %i', + $nationNo + ) as $city) { + foreach (CityConst::byID($city)->path as $adjKey => $adjVal) { + $adj1[$adjKey] = $adjVal; + } + } + if (!$adj3 && !$adj1) { + //평시이면 공백지 + //NOTE: if, else일 경우 NPC는 전쟁시에는 공백지로 출병하지 않는다는 뜻이 된다. + foreach ($db->queryFirstColumn('SELECT city from city where nation=0') as $city) { + foreach (CityConst::byID($city)->path as $adjKey => $adjVal) { + $adj2[$adjKey] = $adjVal; + } + } + } + + $db->update('city', [ + 'front' => 0 + ], 'nation=%i', $nationNo); + + if ($adj1) { + $db->update('city', [ + 'front' => 1, + ], 'nation=%i and city in %li', $nationNo, array_keys($adj1)); + } + if ($adj2) { + $db->update('city', [ + 'front' => 2, + ], 'nation=%i and city in %li', $nationNo, array_keys($adj2)); + } + if ($adj3) { + $db->update('city', [ + 'front' => 3, + ], 'nation=%i and city in %li', $nationNo, array_keys($adj3)); + } +} + +function checkSupply() +{ + $db = DB::db(); + + $cities = []; + foreach ($db->query('SELECT city, nation FROM city WHERE nation != 0') as $city) { + $newCity = new \stdClass(); + $newCity->id = Util::toInt($city['city']); + $newCity->nation = Util::toInt($city['nation']); + $newCity->supply = false; + + $cities[$newCity->id] = $newCity; + } + + $queue = new \SplQueue(); + foreach ($db->queryAllLists('SELECT capital, nation FROM nation WHERE `level` > 0') as list($capitalID, $nationID)) { + if (!key_exists($capitalID, $cities)) { + continue; + } + $city = $cities[$capitalID]; + if ($nationID != $city->nation) { + continue; + } + $city->supply = true; + $queue->enqueue($city); + } + + while (!$queue->isEmpty()) { + $cityLink = $queue->dequeue(); + $city = CityConst::byID($cityLink->id); + + foreach (array_keys($city->path) as $connCityID) { + if (!key_exists($connCityID, $cities)) { + continue; + } + $connCity = $cities[$connCityID]; + if ($connCity->nation != $cityLink->nation) { + continue; + } + if ($connCity->supply) { + continue; + } + $connCity->supply = true; + $queue->enqueue($connCity); + } + } + + $db->update('city', [ + 'supply' => 1 + ], 'nation=0'); + + $db->update('city', [ + 'supply' => 0 + ], 'nation!=0'); + + $supply = []; + + foreach ($cities as $city) { + if ($city->supply) { + $supply[] = $city->id; + } + } + + if ($supply) { + $db->update('city', [ + 'supply' => 1 + ], 'city IN %li', $supply); + } +} + +function updateGeneralNumber(){ + $db = DB::db(); + foreach($db->queryAllLists('SELECT nation, count(*) FROM general WHERE npc != 5 GROUP BY nation') as [$nationID, $gennum]){ + if($nationID === 0){ + continue; + } + $db->update('nation', [ + 'gennum'=>$gennum + ], 'nation=%i', $nationID); + } + refreshNationStaticInfo(); +} + +function updateYearly() +{ + //통계 + checkStatistic(); +} + +//관직 변경 해제 +function updateQuaterly() +{ + $db = DB::db(); + + //천도 제한 해제, 관직 변경 제한 해제 + $db->update('nation', [ + 'chief_set' => 0, + ], true); + //관직 변경 제한 해제 + $db->update('city', [ + 'officer_set' => 0, + ], true); +} + +// 벌점 감소와 건국제한-1 전턴제한-1 외교제한-1, 1달마다 실행, 병사 있는 장수의 군량 감소, 수입비율 조정 +function preUpdateMonthly() +{ + $db = DB::db(); + $gameStor = KVStorage::getStorage($db, 'game_env'); + + //연감 월결산 + $result = LogHistory(); + + if ($result == false) { + return false; + } + + + $admin = $gameStor->getValues(['startyear', 'year', 'month']); + $logger = new ActionLogger(0, 0, $admin['year'], $admin['month']); + + //보급선 체크 + checkSupply(); + //미보급도시 10% 감소 + $db->update('city', [ + 'pop' => $db->sqleval('pop * 0.9'), + 'trust' => $db->sqleval('trust * 0.9'), + 'agri' => $db->sqleval('agri * 0.9'), + 'comm' => $db->sqleval('comm * 0.9'), + 'secu' => $db->sqleval('secu * 0.9'), + 'def' => $db->sqleval('def * 0.9'), + 'wall' => $db->sqleval('wall * 0.9'), + ], 'supply = 0'); + //미보급도시 장수 병 훈 사 5%감소 + //NOTE: update inner join도 가능하지만, meekrodb 기준으로 깔끔하게. + $unsuppliedCities = $db->query('SELECT city, nation, trust, name FROM city WHERE supply = 0'); + foreach (Util::arrayGroupBy($unsuppliedCities, 'nation') as $nationID => $cityList) { + $cityIDList = Util::squeezeFromArray($cityList, 'city'); + $db->update('general', [ + 'crew' => $db->sqleval('crew*0.95'), + 'atmos' => $db->sqleval('atmos*0.95'), + 'train' => $db->sqleval('train*0.95'), + ], 'city IN %li AND nation = %i', $cityIDList, $nationID); + } + + //민심30이하 공백지 처리 + $lostCities = []; + foreach ($unsuppliedCities as $unsuppliedCity) { + if ($unsuppliedCity['trust'] >= 30) { + continue; + } + $lostCities[$unsuppliedCity['city']] = $unsuppliedCity; + } + + if ($lostCities) { + foreach ($lostCities as $lostCity) { + $josaYi = JosaUtil::pick($lostCity['name'], '이'); + $logger->pushGlobalHistoryLog("【고립】{$lostCity['name']}{$josaYi} 보급이 끊겨 미지배 도시가 되었습니다."); + } + $db->update('general', [ + 'officer_level' => 1, + 'officer_city' => 0 + ], 'officer_city IN %li', array_keys($lostCities)); + $db->update('city', [ + 'nation' => 0, + 'officer_set' => 0, + 'conflict' => '{}', + 'term' => 0, + 'front' => 0 + ], 'city IN %li', array_keys($lostCities)); + } + + //접률감소, 건국제한-1 + $db->update('general', [ + 'connect' => $db->sqleval('floor(connect*0.99)'), + 'makelimit' => $db->sqleval('greatest(0, makelimit - 1)'), + ], true); + //전략제한-1, 외교제한-1, 세율동기화 + $db->update('nation', [ + 'strategic_cmd_limit' => $db->sqleval('greatest(0, strategic_cmd_limit - 1)'), + 'surlimit' => $db->sqleval('greatest(0, surlimit - 1)'), + 'rate_tmp' => $db->sqleval('rate') + ], true); + + //도시훈사 180년 60, 220년 87, 240년 100 + $rate = Util::round(($admin['year'] - $admin['startyear']) / 1.5) + 60; + if ($rate > 100) $rate = 100; + + // 20 ~ 140원 + $develcost = ($admin['year'] - $admin['startyear'] + 10) * 2; + $gameStor->city_rate = $rate; + $gameStor->develcost = $develcost; + + //매달 사망자 수입 결산 + processWarIncome(); + + //계략, 전쟁표시 해제 + $db->update('city', [ + 'state' => $db->sqleval(<< $db->sqleval('greatest(0, term - 1)'), + 'conflict' => $db->sqleval('if(term = 0,%s,conflict)', '{}'), + ], true); + + //첩보-1 + foreach ($db->queryAllLists("SELECT nation, spy FROM nation WHERE spy!='' AND spy!='{}'") as [$nationNo, $rawSpy]) { + $spyInfo = Json::decode($rawSpy); + + foreach ($spyInfo as $cityNo => $remainMonth) { + if ($remainMonth <= 1) { + unset($spyInfo[$cityNo]); + } else { + $spyInfo[$cityNo] -= 1; + } + } + + $db->update('nation', [ + 'spy' => Json::encode($spyInfo, Json::EMPTY_ARRAY_IS_DICT) + ], 'nation=%i', $nationNo); + } + + return true; +} + +// 외교 로그처리, 외교 상태 처리 +function postUpdateMonthly() +{ + $db = DB::db(); + $gameStor = KVStorage::getStorage($db, 'game_env'); + + $admin = $gameStor->getValues(['startyear', 'year', 'month', 'scenario']); + $globalLogger = new ActionLogger(0, 0, $admin['year'], $admin['month']); + + //도시 수 측정 + $cityNations = []; + foreach ($db->queryAllLists('SELECT city, name, nation FROM city') as [$cityID, $cityName, $cityNation]) { + if (!key_exists($cityNation, $cityNations)) { + $cityNations[$cityNation] = []; + } + $cityNations[$cityNation][] = $cityName; + } + + //각 국가 전월 장수수 대비 당월 장수수로 단합도 산정 + //각 국가 장수수를 구하고 국력 산정 + // $query = "select nation,gennum from nation where level>0"; + // 국력= + // 자원(국가/장수의 금,쌀) + // 기술력 + // 인구수*내정% + // 장수능력 + // 접속률 + // 숙련도 + // 명성,공헌 + $nations = Util::convertArrayToDict($db->query('SELECT + A.nation, + A.gennum, + round(( + round(((A.gold+A.rice)+(select sum(gold+rice) from general where nation=A.nation))/100) + +A.tech + +if(A.level=0,0,( + select round( + sum(pop)*sum(pop+agri+comm+secu+wall+def)/sum(pop_max+agri_max+comm_max+secu_max+wall_max+def_max)/100 + ) from city where nation=A.nation and supply=1 + )) + +(select sum(leadership+strength+intel) from general where nation=A.nation) + +(select round(sum(dex1+dex2+dex3+dex4+dex5)/1000) from general where nation=A.nation) + +(select round(sum(experience+dedication)/100) from general where nation=A.nation) + +(select round(avg(connect)) from general where nation=A.nation) + )/10) + as power, + (select sum(crew) from general where nation=A.nation) as totalCrew + from nation A + group by A.nation'), 'nation'); + $maxPowerValues = KVStorage::getValuesFromInterNamespace($db, 'nation_env', 'max_power'); + + foreach ($nations as $nation) { + $nationID = $nation['nation']; + $nationStor = KVStorage::getStorage($db, $nationID, 'nation_env'); + $genNum[$nationID] = $nation['gennum']; + + $powerValues = $maxPowerValues[$nationID]??[]; + + //약간의 랜덤치 부여 (95% ~ 105%) + + $nation['power'] = Util::round($nation['power'] * (rand() % 101 + 950) / 1000); + $powerValues['maxPower'] = max($powerValues['maxPower'] ?? 0, $nation['power']); + $powerValues['maxCrew'] = max($powerValues['maxCrew'] ?? 0, Util::toInt($nation['totalCrew'])); + + if (count($cityNations[$nationID] ?? []) > count($powerValues['maxCities'] ?? [])) { + $powerValues['maxCities'] = $cityNations[$nationID]; + } + + $db->update('nation', [ + 'power' => $nation['power'] + ], 'nation=%i', $nationID); + $nationStor->max_power = $powerValues; + } + + // 전쟁기한 세팅 + foreach($db->query('SELECT me, you, dead, term FROM diplomacy WHERE state = 0') as $dip) { + $genCount = $genNum[$dip['me']]; + // 25% 참여율일때 두당 10턴에 4000명 소모한다고 계산 + // 4000 / 10 * 0.25 = 100 + $term = floor($dip['dead'] / 100 / $genCount); + $dip['dead'] -= $term * 100 * $genCount; + $term = Util::valueFit($dip['term'] + $term, 0, 13); + + $db->update('diplomacy', [ + 'term' => $term, + 'dead' => $dip['dead'], + ], 'me = %i AND you = %i', $dip['me'], $dip['you']); + } + + //개전국 로그 + foreach($db->query('SELECT me, you FROM diplomacy WHERE state = 1 AND term <= 1 AND me < you') as $dip){ + $nation1 = getNationStaticInfo($dip['me']); + $name1 = $nation1['name']; + $nation2 = getNationStaticInfo($dip['you']); + $name2 = $nation2['name']; + + $josaYi = JosaUtil::pick($name2, '이'); + $josaWa = JosaUtil::pick($name1, '와'); + $globalLogger->pushGlobalHistoryLog("【개전】$name1{$josaWa} $name2{$josaYi} 전쟁을 시작합니다."); + } + //휴전국 로그 + $stopWarList = []; + foreach($db->queryAllLists('SELECT me,you FROM diplomacy WHERE state=0 AND term <= 1 ORDER BY me desc, you desc') as [$me, $you]){ + if($me < $you){ + $key = "{$me}_{$you}"; + } + else{ + $key = "{$you}_{$me}"; + } + if(!key_exists($key, $stopWarList)){ + $stopWarList[$key] = true; + continue; + } + + //양측 기간 모두 0이 되는 상황이면 휴전 + $nation1 = getNationStaticInfo($me); + $name1 = $nation1['name']; + $nation2 = getNationStaticInfo($you); + $name2 = $nation2['name']; + + $josaWa = JosaUtil::pick($name1, '와'); + $josaYi = JosaUtil::pick($name2, '이'); + + $globalLogger->pushGlobalHistoryLog("【휴전】$name1{$josaWa} $name2{$josaYi} 휴전합니다."); + $db->update('diplomacy', [ + 'state'=>2, + 'term'=>0, + ], '(me=%i AND you=%i) OR (you=%i AND me=%i)', $me, $you, $me, $you); + } + + $globalLogger->flush(); + + //사상자 초기화, 외교 기한-1 + $db->update('diplomacy', [ + 'dead'=>$db->sqleval('if(state!=0, 0, dead)'), + 'term'=>$db->sqleval('greatest(0, term-1)'), + ], true); + //불가침 끝나면 통상으로 + $db->update('diplomacy', [ + 'state'=>2, + ], 'state = 7 AND term = 0'); + //선포 끝나면 교전으로 + $db->update('diplomacy', [ + 'state'=>0, + 'term'=>6, + ], 'state = 1 AND term = 0'); + + //초반이후 방랑군 자동 해체 + if ($admin['year'] >= $admin['startyear'] + 2) { + checkWander(); + } + // 작위 업데이트 + updateNationState(); + updateGeneralNumber(); + refreshNationStaticInfo(); + // 천통여부 검사 + checkEmperior(); + //토너먼트 개시 + triggerTournament(); + // 시스템 거래건 등록 + registerAuction(); + //전방설정 + foreach (getAllNationStaticInfo() as $nation) { + if ($nation['level'] <= 0) { + continue; + } + SetNationFront($nation['nation']); + } +} + + +function checkWander() +{ + $db = DB::db(); + $gameStor = KVStorage::getStorage($db, 'game_env'); + + $admin = $gameStor->getValues(['year', 'month']); + + $wanderers = $db->queryFirstColumn('SELECT general.`no` FROM general LEFT JOIN nation ON general.nation = nation.nation WHERE nation.`level` = 0 AND general.`officer_level` = 12'); + + foreach (General::createGeneralObjListFromDB($wanderers) as $wanderer) { + $wanderCmd = buildGeneralCommandClass('che_해산', $wanderer, $admin); + if ($wanderCmd->hasFullConditionMet()) { + $logger = $wanderer->getLogger(); + $logger->pushGeneralActionLog('초반 제한후 방랑군은 자동 해산됩니다.', ActionLogger::PLAIN); + $wanderCmd->run(); + $wanderCmd->setNextAvailable(); + } + } + + if ($wanderers) { + refreshNationStaticInfo(); + } +} + +function updateNationState() +{ + $db = DB::db(); + $gameStor = KVStorage::getStorage($db, 'game_env'); + + $history = array(); + $admin = $gameStor->getValues(['killturn', 'year', 'month', 'fiction', 'startyear', 'show_img_level', 'turnterm', 'turntime']); + + $assemblerCnts = []; + foreach ($db->queryAllLists('SELECT nation,count(no) FROM general WHERE npc = 5 GROUP BY nation') as [$nationID, $assemblerCnt]) { + $assemblerCnts[$nationID] = $assemblerCnt; + }; + + foreach ($db->query('SELECT nation,name,level,tech,aux FROM nation') as $nation) { + //TODO: level이 진관수이소중대특 체계를 벗어날 수 있음 + $citycount = $db->queryFirstField('SELECT count(*) FROM city WHERE nation=%i AND level>=4', $nation['nation']); + + if ($citycount == 0) { + $nationlevel = 0; // 방랑군 + } elseif ($citycount == 1) { + $nationlevel = 1; // 호족 + } elseif ($citycount <= 4) { + $nationlevel = 2; // 군벌 + } elseif ($citycount <= 7) { + $nationlevel = 3; // 주자사 + } elseif ($citycount <= 10) { + $nationlevel = 4; // 주목 + } elseif ($citycount <= 15) { + $nationlevel = 5; // 공 + } elseif ($citycount <= 20) { + $nationlevel = 6; // 왕 + } else { + $nationlevel = 7; // 황제 + } + + if ($nationlevel > $nation['level']) { + $levelDiff = $nationlevel - $nation['level']; + $oldLevel = $nation['level']; + $nation['level'] = $nationlevel; + + $updateVals = [ + 'level' => $nationlevel, + 'gold'=>$db->sqleval('gold + %i', $nationlevel*1000), + 'rice'=>$db->sqleval('rice + %i', $nationlevel*1000), + ]; + + switch ($nationlevel) { + case 7: + $josaUl = JosaUtil::pick(getNationLevel($nationlevel), '을'); + $history[] = "●{$admin['year']}년 {$admin['month']}월:【작위】{$nation['name']}의 군주가 " . getNationLevel($nationlevel) . "{$josaUl} 자칭하였습니다."; + pushNationHistoryLog($nation['nation'], ["●{$admin['year']}년 {$admin['month']}월:{$nation['name']}의 군주가 " . getNationLevel($nationlevel) . "{$josaUl} 자칭"]); + $auxVal = Json::decode($nation['aux']); + $auxVal['can_국기변경'] = 1; + $auxVal['can_국호변경'] = 1; + $updateVals['aux'] = Json::encode($auxVal); + break; + case 6: + $history[] = "●{$admin['year']}년 {$admin['month']}월:【작위】{$nation['name']}의 군주가 " . getNationLevel($nationlevel) . "에 등극하였습니다."; + pushNationHistoryLog($nation['nation'], ["●{$admin['year']}년 {$admin['month']}월:{$nation['name']}의 군주가 " . getNationLevel($nationlevel) . "에 등극"]); + break; + case 5: + case 4: + case 3: + $history[] = "●{$admin['year']}년 {$admin['month']}월:【작위】{$nation['name']}의 군주가 " . getNationLevel($nationlevel) . "에 임명되었습니다."; + pushNationHistoryLog($nation['nation'], ["●{$admin['year']}년 {$admin['month']}월:{$nation['name']}의 군주가 " . getNationLevel($nationlevel) . "에 임명됨"]); + break; + case 2: + $history[] = "●{$admin['year']}년 {$admin['month']}월:【작위】{$nation['name']}의 군주가 독립하여 " . getNationLevel($nationlevel) . "로 나섰습니다."; + pushNationHistoryLog($nation['nation'], ["●{$admin['year']}년 {$admin['month']}월:{$nation['name']}의 군주가 " . getNationLevel($nationlevel) . "로 나서다"]); + break; + } + + $db->update('nation', $updateVals, 'nation=%i', $nation['nation']); + + $turnRows = []; + foreach (Util::range(getNationChiefLevel($nation['level']), 12) as $chiefLevel) { + foreach (Util::range(GameConst::$maxChiefTurn) as $turnIdx) { + $turnRows[] = [ + 'nation_id' => $nation['nation'], + 'officer_level' => $chiefLevel, + 'turn_idx' => $turnIdx, + 'action' => '휴식', + 'arg' => null, + 'brief' => '휴식' + ]; + } + } + $db->insertIgnore('nation_turn', $turnRows); + + if ($levelDiff) { + //유니크 아이템 하나 돌리자 + $targetKillTurn = $admin['killturn']; + $targetKillTurn -= 24 * 60 / $admin['turnterm']; + $nationGenIDList = $db->queryFirstColumn( + 'SELECT no FROM general WHERE nation = %i AND killturn >= %i AND npc < 2', + $nation['nation'], + $targetKillTurn + ); + $nationGenList = General::createGeneralObjListFromDB($nationGenIDList, ['belong'], 2); + + $uniqueLotteryWeightList = []; + foreach ($nationGenList as $nationGen) { + $hasUnique = false; + foreach ($nationGen->getItems() as $item) { + if (!$item->isBuyable()) { + $hasUnique = true; + break; + } + } + if ($hasUnique) { + continue; + } + + $score = $nationGen->getVar('belong') + 5; + + if ($nationGen->getVar('officer_level') == 12) { + $score += 200; //NOTE: 꼬우면 군주하세요. + } else if ($nationGen->getVar('officer_level') == 11) { + $score += 70; + } else if ($nationGen->getVar('officer_level') > 4) { + $score += 35; + } + $uniqueLotteryWeightList[$nationGen->getID()] = [$nationGen, $score]; + } + + foreach (Util::range($levelDiff) as $idx) { + if (!$uniqueLotteryWeightList) { + break; + } + + /** @var General */ + $winnerObj = Util::choiceRandomUsingWeightPair($uniqueLotteryWeightList); + unset($uniqueLotteryWeightList[$winnerObj->getID()]); + giveRandomUniqueItem($winnerObj, '작위보상'); + $winnerObj->applyDB($db); + } + } + } + + $assemblerCnt = $assemblerCnts[$nation['nation']] ?? 0; + $maxAssemblerCnt = [ + 1 => 0, + 2 => 1, + 3 => 3, + 4 => 4, + 5 => 6, + 6 => 7, + 7 => 9 + ][$nationlevel] ?? 0; + + if ($assemblerCnt < $maxAssemblerCnt) { + $lastAssemblerID = $gameStor->assembler_id ?? 0; + + while ($assemblerCnt < $maxAssemblerCnt) { + $lastAssemblerID += 1; + $npcObj = new Scenario\NPC( + 999, + sprintf('부대장%4d', $lastAssemblerID), + null, + $nation['nation'], + null, + 10, + 10, + 10, + 1, + $admin['year'] - 15, + $admin['year'] + 15, + '은둔', + '척사' + ); + $npcObj->killturn = 70; + $npcObj->gold = 0; + $npcObj->rice = 0; + $npcObj->npc = 5; + $npcObj->build($admin); + $npcID = $npcObj->generalID; + + $db->insert('troop', [ + 'troop_leader' => $npcID, + 'name' => $npcObj->realName, + 'nation' => $nation['nation'], + ]); + $db->update('general', [ + 'troop' => $npcID + ], 'no=%i', $npcID); + + $cmd = buildGeneralCommandClass('che_집합', General::createGeneralObjFromDB($npcID), $admin); + _setGeneralCommand($cmd, iterator_to_array(Util::range(GameConst::$maxTurn))); + $assemblerCnt += 1; + $gameStor->assembler_id = $lastAssemblerID; + } + } + } + pushGlobalHistoryLog($history, $admin['year'], $admin['month']); +} + +function checkStatistic() +{ + $db = DB::db(); + $gameStor = KVStorage::getStorage($db, 'game_env'); + + $admin = $gameStor->getValues(['year', 'month']); + + $nationHists = []; + $specialHists = []; + $personalHists = []; + $specialHists2 = []; + $crewtypeHists = []; + + $etc = ''; + + $auxData = [ + 'generals' => [], + 'nations' => [], + ]; + + $avgGeneral = $db->queryFirstRow( + 'SELECT avg(gold) as avggold, avg(rice) as avgrice, avg(dex1+dex2+dex3+dex4) as avgdex, + max(dex1+dex2+dex3+dex4) as maxdex, avg(experience+dedication) as avgexpded, max(experience+dedication) as maxexpded + FROM general' + ); + $auxData['generals']['avg'] = $avgGeneral; + + $avgGeneral['avggold'] = Util::round($avgGeneral['avggold']); + $avgGeneral['avgrice'] = Util::round($avgGeneral['avgrice']); + $avgGeneral['avgdex'] = Util::round($avgGeneral['avgdex']); + $avgGeneral['avgexpded'] = Util::round($avgGeneral['avgexpded']); + $etc .= "평균 금/쌀 ({$avgGeneral['avggold']}/{$avgGeneral['avgrice']}), 평균/최고 숙련({$avgGeneral['avgdex']}/{$avgGeneral['maxdex']}), 평균/최고 경험공헌({$avgGeneral['avgexpded']}/{$avgGeneral['maxexpded']}), "; + + $avgNation = $db->queryFirstRow( + 'SELECT min(tech) as mintech, max(tech) as maxtech, avg(tech) as avgtech, + min(power) as minpower, max(power) as maxpower, avg(power) as avgpower from nation where level>0' + ); + $auxData['nations']['avg'] = $avgNation; + + $avgNation['mintech'] = floor($avgNation['mintech']); + $avgNation['maxtech'] = floor($avgNation['maxtech']); + $avgNation['avgtech'] = Util::round($avgNation['avgtech']); + $avgNation['avgpower'] = Util::round($avgNation['avgpower']); + $etc .= "최저/평균/최고 기술({$avgNation['mintech']}/{$avgNation['avgtech']}/{$avgNation['maxtech']}), "; + $etc .= "최저/평균/최고 국력({$avgNation['minpower']}/{$avgNation['avgpower']}/{$avgNation['maxpower']}), "; + + $nationName = ''; + $powerHist = ''; + + $nations = Util::convertArrayToDict( + $db->query( + 'SELECT nation,name,type,power,gennum,gold+rice as goldrice from nation where level>0 order by power desc', + 'nation' + ), + 'nation' + ); + $nationCount = count($nations); + + $nationGeneralInfos = Util::convertArrayToDict( + $db->query( + 'SELECT nation, sum(leadership+strength+intel) as abil,sum(gold+rice) as goldrice, + sum(dex1+dex2+dex3+dex4) as dex,sum(experience+dedication) as expded + from general GROUP BY nation' + ), + 'nation' + ); + + $nationCityInfos = Util::convertArrayToDict( + $db->query('SELECT nation, count(*) as cnt, sum(pop) as pop,sum(pop_max) as pop_max from city GROUP BY nation'), + 'nation' + ); + + foreach ($nations as $nationNo => &$nation) { + $general = $nationGeneralInfos[$nationNo]; + $city = $nationCityInfos[$nationNo]; + + $nation['generalInfo'] = $general; + $nation['cityInfo'] = $city; + + $nationName .= $nation['name'] . '(' . getNationType($nation['type']) . '), '; + $powerHist .= "{$nation['name']}({$nation['power']}/{$nation['gennum']}/{$city['cnt']}/{$city['pop']}/{$city['pop_max']}/{$nation['goldrice']}/{$general['goldrice']}/{$general['abil']}/{$general['dex']}/{$general['expded']}), "; + + if (!isset($nationHists[$nation['type']])) { + $nationHists[$nation['type']] = 0; + } + $nationHists[$nation['type']]++; + } + unset($nation); + + $auxData['nations']['all'] = $nations; + + $nationHist = ''; + foreach (GameConst::$availableNationType as $nationType) { + if (!Util::array_get($nationHists[$nationType])) { + $nationHists[$nationType] = '-'; + } + $nationHist .= getNationType($nationType) . "({$nationHists[$nationType]}), "; + } + + $generals = $db->query('SELECT `no`,npc,personal,special,special2,crewtype FROM general'); + + $genCount = 0; + $npcCount = 0; + $generalCount = count($generals); + + foreach ($generals as $general) { + if (!isset($personalHists[$general['personal']])) { + $personalHists[$general['personal']] = 0; + } + + if (!isset($specialHists[$general['special']])) { + $specialHists[$general['special']] = 0; + } + + if (!isset($specialHists2[$general['special2']])) { + $specialHists2[$general['special2']] = 0; + } + + if ($general['npc'] < 2) { + $genCount += 1; + } else { + $npcCount += 1; + } + + $personalHists[$general['personal']]++; + $specialHists[$general['special']]++; + $specialHists2[$general['special2']]++; + } + + foreach ($db->queryAllLists( + 'SELECT crewtype, count(crewtype) AS cnt FROM general WHERE recent_war != NULL GROUP BY crewtype' + ) as [$crewtype, $cnt]) { + $crewtypeHists[$crewtype] = $cnt; + } + + $auxData['generals']['hists'] = [ + 'personal' => $personalHists, + 'special' => $specialHists, + 'special2' => $specialHists2, + 'crewtype' => $crewtypeHists, + 'userCnt' => $genCount, + 'npcCnt' => $npcCount, + ]; + + $generalCountStr = "{$generalCount}({$genCount}+{$npcCount})"; + + $personalHistStr = join(', ', array_map(function ($histPair) { + [$histKey, $cnt] = $histPair; + return getGenChar($histKey) . '(' . $cnt . ')'; + }, Util::convertDictToArray($personalHists))); + + $specialHistsStr = join(', ', array_map(function ($histPair) { + [$histKey, $cnt] = $histPair; + return getGeneralSpecialDomesticName($histKey) . '(' . $cnt . ')'; + }, Util::convertDictToArray($specialHists))); + + $specialHists2Str = join(', ', array_map(function ($histPair) { + [$histKey, $cnt] = $histPair; + return getGeneralSpecialWarName($histKey) . '(' . $cnt . ')'; + }, Util::convertDictToArray($specialHists2))); + + $specialHistsAllStr = "$specialHistsStr // $specialHists2Str"; + + $crewtypeHistsStr = join(', ', array_map(function ($histPair) { + [$histKey, $cnt] = $histPair; + return GameUnitConst::byID($histKey)->getShortName() . '(' . $cnt . ')'; + }, Util::convertDictToArray($crewtypeHists))); + + $db->insert('statistic', [ + 'year' => $admin['year'], + 'month' => $admin['month'], + 'nation_count' => $nationCount, + 'nation_name' => $nationName, + 'nation_hist' => $nationHist, + 'gen_count' => $generalCountStr, + 'personal_hist' => $personalHistStr, + 'special_hist' => $specialHistsAllStr, + 'power_hist' => $powerHist, + 'crewtype' => $crewtypeHistsStr, + 'etc' => $etc, + 'aux' => Json::encode($auxData) + ]); +} + + +function convForOldGeneral(array $general, int $year, int $month) +{ + $general['history'] = getGeneralHistoryLogAll($general['no']); + return [ + 'server_id' => UniqueConst::$serverID, + 'general_no' => $general['no'], + 'owner' => $general['owner'], + 'name' => $general['name'], + 'last_yearmonth' => $year * 100 + $month, + 'turntime' => $general['turntime'], + 'data' => Json::encode($general) + ]; +} + +function storeOldGeneral(int $no, int $year, int $month) +{ + $db = DB::db(); + $general = $db->queryFirstRow('SELECT * FROM general WHERE `no` = %i', $no); + if (!$general) { + return; + } + $data = convForOldGeneral($general, $year, $month); + $db->insertUpdate( + 'ng_old_generals', + $data, + $data + ); +} + +function storeOldGenerals(int $nation, int $year, int $month) +{ + $db = DB::db(); + foreach ($db->query('SELECT * FROM general WHERE nation = %i', $nation) as $general) { + $data = convForOldGeneral($general, $year, $month); + $db->insertUpdate( + 'ng_old_generals', + $data, + $data + ); + } +} + +function checkEmperior() +{ + $db = DB::db(); + $gameStor = KVStorage::getStorage($db, 'game_env'); + + $admin = $gameStor->getValues(['year', 'month', 'isunited', 'conlimit']); + if ($admin['isunited'] != 0) { + return; + } + + $remainNations = $db->queryFirstColumn('SELECT nation FROM nation WHERE level > 0 LIMIT 2'); + + if (!$remainNations || count($remainNations) != 1) { + return; + } + + $nationID = $remainNations[0]; + + $nationStor = KVStorage::getStorage($db, $nationID, 'nation_env'); + + $cityCnt = $db->queryFirstField('SELECT count(city) FROM city WHERE nation=%i', $nationID); + if (!$cityCnt) { + return; + } + + if ($cityCnt != count(CityConst::all())) { + return; + } + + checkStatistic(); + + $nation = $db->queryFirstRow('SELECT * FROM nation WHERE nation=%i', $nationID); + $nationName = $nation['name']; + + $josaYi = JosaUtil::pick($nationName, '이'); + + $nationLogger = new ActionLogger(0, $nationID, $admin['year'], $admin['month']); + $nationLogger->pushNationalHistoryLog("{$nationName}{$josaYi} 전토를 통일"); + + $gameStor->isunited = 2; + $gameStor->conlimit = $gameStor->conlimit * 100; + + foreach ($db->queryFirstColumn('SELECT no FROM general WHERE npc<2 AND age>=%i', GameConst::$minPushHallAge) as $hallGeneralNo) { + CheckHall($hallGeneralNo); + } + + [$totalPop, $totalMaxPop] = $db->queryFirstList('SELECT SUM(pop), SUM(pop_max) FROM city'); + $pop = "{$totalPop} / {$totalMaxPop}"; + $poprate = round($totalPop / $totalMaxPop * 100, 2). " %"; + + $chiefs = Util::convertArrayToDict( + $db->query( + 'SELECT no,name,picture,belong,officer_level FROM general WHERE nation=%i AND officer_level >= 5', + $nationID + ), + 'officer_level' + ); + + $nationGenerals = $db->queryFirstColumn('SELECT `no` FROM general WHERE nation=%i', $nationID); + $nation['generals'] = $nationGenerals; + + $tigers = $db->query( + 'SELECT value, name + FROM rank_data LEFT JOIN general ON rank_data.general_id = general.no + WHERE rank_data.nation_id = %i AND rank_data.type = "killnum" AND value > 0 ORDER BY value DESC LIMIT 5', + $nationID + ); // 오호장군 + + $tigerstr = join(', ', array_map(function ($arr) { + $number = number_format($arr['value']); + return "{$arr['name']}【{$number}】"; + }, $tigers)); + + $eagles = $db->query( + 'SELECT value, name + FROM rank_data LEFT JOIN general ON rank_data.general_id = general.no + WHERE rank_data.nation_id = %i AND rank_data.type = "firenum" AND value > 0 ORDER BY value DESC LIMIT 7', + $nationID + ); // 건안칠자 + + $eaglestr = join(', ', array_map(function ($arr) { + $number = number_format($arr['value']); + return "{$arr['name']}【{$number}】"; + }, $eagles)); + + $rawGeneralList = $db->query('SELECT no, name, npc, owner FROM general WHERE nation=%i ORDER BY dedication DESC', $nationID); + foreach ($rawGeneralList as $rawGeneral) { + $generalLogger = new ActionLogger($rawGeneral['no'], $nationID, $admin['year'], $admin['month']); + $generalLogger->pushGeneralActionLog("{$nationName}{$josaYi} 전토를 통일하였습니다.", ActionLogger::YEAR_MONTH); + $generalLogger->flush(); + } + + $gen = join(', ', array_column($rawGeneral, 'name')); + + $stat = $db->queryFirstRow('SELECT max(nation_count) as nc, max(gen_count) as gc FROM statistic'); + $genCnt = $db->queryFirstField('SELECT count(*) FROM general'); + + $statNC = "1 / {$stat['nc']}"; + $statGC = "{$genCnt} / {$stat['gc']}"; + $statNation = $db->queryFirstRow('SELECT nation_count,nation_name,nation_hist from statistic where nation_count=%i LIMIT 1', $stat['nc']); + $statGeneral = $db->queryFirstRow('SELECT gen_count,personal_hist,special_hist,aux from statistic order by no desc LIMIT 1'); + + $nation = $nation; + $nation['generals'] = $db->queryFirstColumn('SELECT `no` FROM general WHERE nation=%i', $nation['nation']); + $nation['aux'] = Json::decode($nation['aux']); + $nation['msg'] = $nationStor->notice; + $nation['scout_msg'] = $nationStor->scout_msg; + $nation['aux'] += $nationStor->max_power; + $nation['history'] = getNationHistoryLogAll($nation['nation']); + + storeOldGenerals(0, $admin['year'], $admin['month']); + storeOldGenerals($nation['nation'], $admin['year'], $admin['month']); + + $db->insert('ng_old_nations', [ + 'server_id' => UniqueConst::$serverID, + 'nation' => $nation['nation'], + 'data' => Json::encode($nation) + ]); + + $noNationGeneral = $db->queryFirstColumn('SELECT `no` FROM general WHERE nation=0'); + $db->insert('ng_old_nations', [ + 'server_id' => UniqueConst::$serverID, + 'nation' => 0, + 'data' => Json::encode([ + 'nation' => 0, + 'name' => '재야', + 'generals' => $noNationGeneral + ]) + ]); + + $nationHistory = getNationHistoryLogAll($nation['nation']); + + $serverCnt = $db->queryFirstField('SELECT count(*) FROM ng_games'); + $serverName = UniqueConst::$serverName; + + $db->update('ng_games', [ + 'winner_nation' => $nation['nation'] + ], 'server_id=%s', UniqueConst::$serverID); + + $db->insert('emperior', [ + 'phase' => $serverName . $serverCnt . '기', + 'server_id' => UniqueConst::$serverID, + 'nation_count' => $statNC, + 'nation_name' => $statNation['nation_name'], + 'nation_hist' => $statNation['nation_hist'], + 'gen_count' => $statGC, + 'personal_hist' => $statGeneral['personal_hist'], + 'special_hist' => $statGeneral['special_hist'], + 'name' => $nation['name'], + 'type' => $nation['type'], + 'color' => $nation['color'], + 'year' => $admin['year'], + 'month' => $admin['month'], + 'power' => $nation['power'], + 'gennum' => $nation['gennum'], + 'citynum' => $cityCnt, + 'pop' => $pop, + 'poprate' => $poprate, + 'gold' => $nation['gold'], + 'rice' => $nation['rice'], + 'l12name' => $chiefs[12]['name'], + 'l12pic' => $chiefs[12]['picture'], + 'l11name' => $chiefs[11]['name'], + 'l11pic' => $chiefs[11]['picture'], + 'l10name' => $chiefs[10]['name'], + 'l10pic' => $chiefs[10]['picture'], + 'l9name' => $chiefs[9]['name'], + 'l9pic' => $chiefs[9]['picture'], + 'l8name' => $chiefs[8]['name'], + 'l8pic' => $chiefs[8]['picture'], + 'l7name' => $chiefs[7]['name'], + 'l7pic' => $chiefs[7]['picture'], + 'l6name' => $chiefs[6]['name'], + 'l6pic' => $chiefs[6]['picture'], + 'l5name' => $chiefs[5]['name'], + 'l5pic' => $chiefs[5]['picture'], + 'tiger' => $tigerstr, + 'eagle' => $eaglestr, + 'gen' => $gen, + 'history' => JSON::encode($nationHistory), + 'aux' => $statGeneral['aux'] + ]); + + $history = ["●{$admin['year']}년 {$admin['month']}월:【통일】{$nation['name']}{$josaYi} 전토를 통일하였습니다."]; + pushGlobalHistoryLog($history, $admin['year'], $admin['month']); + + //연감 월결산 + LogHistory(); +} diff --git a/hwe/js/processing.js b/hwe/js/processing.js index 9ef63016..1276bd71 100644 --- a/hwe/js/processing.js +++ b/hwe/js/processing.js @@ -35,7 +35,7 @@ jQuery(function($) { //checkCommandArg 참고 var availableArgumentList = { 'string': [ - 'nationName', 'optionText', 'itemType', 'nationType', 'itemCode', + 'nationName', 'optionText', 'itemType', 'nationType', 'itemCode', 'commandType', ], 'int': [ 'crewType', 'destGeneralID', 'destCityID', 'destNationID', diff --git a/hwe/sammo/Command/BaseCommand.php b/hwe/sammo/Command/BaseCommand.php index d80e951d..d811a757 100644 --- a/hwe/sammo/Command/BaseCommand.php +++ b/hwe/sammo/Command/BaseCommand.php @@ -17,6 +17,7 @@ use \sammo\Constraint\ConstraintHelper; abstract class BaseCommand{ static protected $actionName = 'CommandName'; static public $reqArg = false; + static protected $isLazyCalcReqTurn = false; public function getCommandDetailTitle():string{ return $this->getName(); @@ -54,7 +55,6 @@ abstract class BaseCommand{ static protected $isInitStatic = true; protected static function initStatic(){ - } public function __construct(General $generalObj, array $env, $arg = null){ @@ -271,6 +271,29 @@ abstract class BaseCommand{ return $this->logger; } + abstract protected function getNextExecuteKey():string; + abstract public function getNextAvailable():?int; + abstract public function setNextAvailable(?int $yearMonth=null); + + protected function testPostReqTurn():?array{ + if(!$this->getPostReqTurn()){ + return null; + } + + $nextAvailable = $this->getNextAvailable(); + if($nextAvailable === null){ + return null; + } + + $yearMonth = Util::joinYearMonth($this->env['year'], $this->env['month']); + $remainTurn = $nextAvailable - $yearMonth - $this->getPreReqTurn(); + if($remainTurn <= 0){ + return null; + } + + return ['testPostReqTurn', "{$remainTurn}턴 더 기다려야 합니다"]; + } + public function testPermissionToReserve():?string{ if($this->cachedPermissionToReserve){ return $this->reasonNoPermissionToReserve; @@ -331,6 +354,11 @@ abstract class BaseCommand{ ]; [$this->reasonConstraint, $this->reasonNotMinConditionMet] = Constraint::testAll($this->minConditionConstraints??[], $constraintInput, $this->env); + + if($this->reasonNotMinConditionMet === null && !self::$isLazyCalcReqTurn){ + [$this->reasonConstraint, $this->reasonNotMinConditionMet] = $this->testPostReqTurn(); + } + $this->cachedMinConditionMet = true; return $this->reasonNotMinConditionMet; @@ -364,6 +392,11 @@ abstract class BaseCommand{ ]; [$this->reasonConstraint, $this->reasonNotFullConditionMet] = Constraint::testAll($this->fullConditionConstraints??[], $constraintInput, $this->env); + + if($this->reasonNotFullConditionMet === null){ + [$this->reasonConstraint, $this->reasonNotFullConditionMet] = $this->testPostReqTurn(); + } + $this->cachedFullConditionMet = true; return $this->reasonNotFullConditionMet; diff --git a/hwe/sammo/Command/General/che_전투특기초기화.php b/hwe/sammo/Command/General/che_전투특기초기화.php index 3d3d5fab..64e58cfc 100644 --- a/hwe/sammo/Command/General/che_전투특기초기화.php +++ b/hwe/sammo/Command/General/che_전투특기초기화.php @@ -32,24 +32,6 @@ class che_전투특기초기화 extends Command\GeneralCommand{ } protected function init(){ - - $general = $this->generalObj; - $env = $this->env; - $yearMonth = Util::joinYearMonth($env['year'], $env['month']); - $auxYearMonth = $general->getAuxVar('used_'.$this->getName())??-999; - - if($yearMonth < $auxYearMonth + 60 - $this->getPreReqTurn()){ - $this->minConditionConstraints=[ - ConstraintHelper::AlwaysFail('초기화한 지 5년이 지나야합니다') - ]; - - $this->fullConditionConstraints=[ - ConstraintHelper::AlwaysFail('초기화한 지 5년이 지나야합니다') - ]; - return; - } - - $this->minConditionConstraints=[ ConstraintHelper::ReqGeneralValue(static::$specialType, static::$specialText, '!=', 'None', '특기가 없습니다.'), ]; @@ -57,7 +39,6 @@ class che_전투특기초기화 extends Command\GeneralCommand{ $this->fullConditionConstraints=[ ConstraintHelper::ReqGeneralValue(static::$specialType, static::$specialText, '!=', 'None', '특기가 없습니다.') ]; - } public function getCommandDetailTitle():string{ @@ -82,7 +63,7 @@ class che_전투특기초기화 extends Command\GeneralCommand{ } public function getPostReqTurn():int{ - return 0; + return 60; } public function getTermString():string{ @@ -113,7 +94,6 @@ class che_전투특기초기화 extends Command\GeneralCommand{ $general->setVar(static::$specialType, 'None'); $general->setVar(static::$speicalAge, $general->getVar('age') + 1); - $general->setAuxVar('used_'.$this->getName(), $yearMonth); $logger = $general->getLogger(); diff --git a/hwe/sammo/Command/GeneralCommand.php b/hwe/sammo/Command/GeneralCommand.php index 443613bb..fe40b8b7 100644 --- a/hwe/sammo/Command/GeneralCommand.php +++ b/hwe/sammo/Command/GeneralCommand.php @@ -1,6 +1,36 @@ -getGeneral()->getID(); + $executeKey = "next_execute_{$generalID}_{$turnKey}"; + return $executeKey; + } + + public function getNextAvailable():?int{ + if($this->isArgValid && !$this->getPostReqTurn()){ + return null; + } + $db = \sammo\DB::db(); + $lastExecuteStor = \sammo\KVStorage::getStorage($db, 'next_execute'); + return $lastExecuteStor->getValue($this->getNextExecuteKey()); + } + + public function setNextAvailable(?int $yearMonth=null){ + if(!$this->getPostReqTurn()){ + return; + } + if($yearMonth === null){ + $yearMonth = Util::joinYearMonth($this->env['year'], $this->env['month']) + $this->getPostReqTurn(); + } + + $db = \sammo\DB::db(); + $lastExecuteStor = \sammo\KVStorage::getStorage($db, 'next_execute'); + $lastExecuteStor->setValue($this->getNextExecuteKey(), $yearMonth); + } + }; \ No newline at end of file diff --git a/hwe/sammo/Command/Nation/che_급습.php b/hwe/sammo/Command/Nation/che_급습.php index d2220773..d43096ac 100644 --- a/hwe/sammo/Command/Nation/che_급습.php +++ b/hwe/sammo/Command/Nation/che_급습.php @@ -1,251 +1,251 @@ -arg === null) { - return false; - } - //NOTE: 멸망 직전에 턴을 넣을 수 있으므로, 존재하지 않는 국가여도 argTest에서 바로 탈락시키지 않음 - if (!key_exists('destNationID', $this->arg)) { - return false; - } - $destNationID = $this->arg['destNationID']; - - if (!is_int($destNationID)) { - return false; - } - if ($destNationID < 1) { - return false; - } - - $this->arg = [ - 'destNationID' => $destNationID - ]; - return true; - } - - protected function init() - { - $general = $this->generalObj; - - $env = $this->env; - - $this->setCity(); - $this->setNation(['strategic_cmd_limit']); - - - - $this->minConditionConstraints = [ - ConstraintHelper::OccupiedCity(), - ConstraintHelper::BeChief(), - ConstraintHelper::AvailableStrategicCommand(), - ]; - } - - protected function initWithArg() - { - $this->setDestNation($this->arg['destNationID'], null); - - $this->fullConditionConstraints = [ - ConstraintHelper::OccupiedCity(), - ConstraintHelper::BeChief(), - ConstraintHelper::ExistsDestNation(), - ConstraintHelper::AllowDiplomacyWithTerm( - 1, - 12, - '선포 12개월 이상인 상대국에만 가능합니다.' - ), - ConstraintHelper::AvailableStrategicCommand(), - ]; - } - - public function getCommandDetailTitle(): string - { - $name = $this->getName(); - $reqTurn = $this->getPreReqTurn() + 1; - $postReqTurn = $this->getPostReqTurn(); - - return "{$name}/{$reqTurn}턴(전략$postReqTurn)"; - } - - public function getCost(): array - { - return [0, 0]; - } - - public function getPreReqTurn(): int - { - return 0; - } - - public function getPostReqTurn(): int - { - $genCount = Util::valueFit($this->nation['gennum'], GameConst::$initialNationGenLimit); - $nextTerm = Util::round(sqrt($genCount * 16) * 10); - - $nextTerm = $this->generalObj->onCalcStrategic($this->getName(), 'delay', $nextTerm); - return $nextTerm; - } - - public function getBrief(): string - { - $commandName = $this->getName(); - $destNationName = getNationStaticInfo($this->arg['destNationID'])['name']; - return "【{$destNationName}】에 {$commandName}"; - } - - - public function run(): bool - { - if (!$this->hasFullConditionMet()) { - throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); - } - - $db = DB::db(); - $env = $this->env; - - $general = $this->generalObj; - $generalID = $general->getID(); - $generalName = $general->getName(); - $date = $general->getTurnTime($general::TURNTIME_HM); - - $year = $this->env['year']; - $month = $this->env['month']; - - $nation = $this->nation; - $nationID = $nation['nation']; - $nationName = $nation['name']; - - $destNation = $this->destNation; - $destNationID = $destNation['nation']; - $destNationName = $destNation['name']; - - $josaYi = JosaUtil::pick($generalName, '이'); - $josaYiNation = JosaUtil::pick($nationName, '이'); - - $commandName = $this->getName(); - $josaUl = JosaUtil::pick($commandName, '을'); - - $logger = $general->getLogger(); - $logger->pushGeneralActionLog("{$commandName} 발동! <1>$date"); - - $general->addExperience(5 * ($this->getPreReqTurn() + 1)); - $general->addDedication(5 * ($this->getPreReqTurn() + 1)); - - $broadcastMessage = "{$generalName}{$josaYi} {$destNationName}{$commandName}{$josaUl} 발동하였습니다."; - - $nationGeneralList = $db->queryFirstColumn('SELECT no FROM general WHERE nation=%i AND no != %i', $nationID, $generalID); - foreach ($nationGeneralList as $nationGeneralID) { - $nationGeneralLogger = new ActionLogger($nationGeneralID, $nationID, $year, $month); - $nationGeneralLogger->pushGeneralActionLog($broadcastMessage, ActionLogger::PLAIN); - $nationGeneralLogger->flush(); - } - - $josaYiCommand = JosaUtil::pick($commandName, '이'); - - $broadcastMessage = "아국에 {$commandName}{$josaYiCommand} 발동되었습니다."; - - $destNationGeneralList = $db->queryFirstColumn('SELECT no FROM general WHERE nation=%i AND no != %i', $nationID, $generalID); - foreach ($destNationGeneralList as $destNationGeneralID) { - $destNationGeneralLogger = new ActionLogger($destNationGeneralID, $destNationID, $year, $month); - $destNationGeneralLogger->pushGeneralActionLog($broadcastMessage, ActionLogger::PLAIN); - $destNationGeneralLogger->flush(); - } - - $destNationLogger = new ActionLogger(0, $destNationID, $year, $month); - $destNationLogger->pushNationalHistoryLog("{$nationName}{$generalName}{$josaYi} 아국에 {$commandName}{$josaUl} 발동"); - $destNationLogger->flush(); - - $logger->pushNationalHistoryLog("{$generalName}{$josaYi} {$destNationName}{$commandName}{$josaUl} 발동"); - - $db->update('nation', [ - 'strategic_cmd_limit' => $this->getPostReqTurn() - ], 'nation=%i', $nationID); - $db->update('diplomacy', [ - 'term' => $db->sqleval('`term` - %i', 3), - ], '(me = %i AND you = %i) OR (you = %i AND me = %i)', $nationID, $destNationID, $nationID, $destNationID); - $this->setResultTurn(new LastTurn(static::getName(), $this->arg)); - $general->applyDB($db); - - return true; - } - - public function getJSFiles(): array - { - return [ - 'js/defaultSelectNationByMap.js' - ]; - } - - public function getForm(): string - { - $generalObj = $this->generalObj; - $nationID = $generalObj->getNationID(); - $nationList = []; - $testTurn = new LastTurn($this->getName(), null, $this->getPreReqTurn()); - foreach (getAllNationStaticInfo() as $destNation) { - if ($destNation['nation'] == $nationID) { - continue; - } - - $testTurn->setArg(['destNationID' => $destNation['nation']]); - $testCommand = new static($generalObj, $this->env, $testTurn, ['destNationID' => $destNation['nation']]); - if ($testCommand->hasFullConditionMet()) { - $destNation['availableCommand'] = true; - } else { - $destNation['availableCommand'] = false; - } - - $nationList[] = $destNation; - } - - ob_start(); -?> -
- 선택된 국가에 급습을 발동합니다.
- 선포, 전쟁중인 상대국에만 가능합니다.
- 상대 국가를 목록에서 선택하세요.
- 배경색은 현재 급습 불가능 국가는 붉은색으로 표시됩니다.
- - arg === null) { + return false; + } + //NOTE: 멸망 직전에 턴을 넣을 수 있으므로, 존재하지 않는 국가여도 argTest에서 바로 탈락시키지 않음 + if (!key_exists('destNationID', $this->arg)) { + return false; + } + $destNationID = $this->arg['destNationID']; + + if (!is_int($destNationID)) { + return false; + } + if ($destNationID < 1) { + return false; + } + + $this->arg = [ + 'destNationID' => $destNationID + ]; + return true; + } + + protected function init() + { + $general = $this->generalObj; + + $env = $this->env; + + $this->setCity(); + $this->setNation(['strategic_cmd_limit']); + + + + $this->minConditionConstraints = [ + ConstraintHelper::OccupiedCity(), + ConstraintHelper::BeChief(), + ConstraintHelper::AvailableStrategicCommand($this->getPreReqTurn()), + ]; + } + + protected function initWithArg() + { + $this->setDestNation($this->arg['destNationID'], null); + + $this->fullConditionConstraints = [ + ConstraintHelper::OccupiedCity(), + ConstraintHelper::BeChief(), + ConstraintHelper::ExistsDestNation(), + ConstraintHelper::AllowDiplomacyWithTerm( + 1, + 12, + '선포 12개월 이상인 상대국에만 가능합니다.' + ), + ConstraintHelper::AvailableStrategicCommand($this->getPreReqTurn()), + ]; + } + + public function getCommandDetailTitle(): string + { + $name = $this->getName(); + $reqTurn = $this->getPreReqTurn() + 1; + $postReqTurn = $this->getPostReqTurn(); + + return "{$name}/{$reqTurn}턴(전략$postReqTurn)"; + } + + public function getCost(): array + { + return [0, 0]; + } + + public function getPreReqTurn(): int + { + return 0; + } + + public function getPostReqTurn(): int + { + $genCount = Util::valueFit($this->nation['gennum'], GameConst::$initialNationGenLimit); + $nextTerm = Util::round(sqrt($genCount * 16) * 10); + + $nextTerm = $this->generalObj->onCalcStrategic($this->getName(), 'delay', $nextTerm); + return $nextTerm; + } + + public function getBrief(): string + { + $commandName = $this->getName(); + $destNationName = getNationStaticInfo($this->arg['destNationID'])['name']; + return "【{$destNationName}】에 {$commandName}"; + } + + + public function run(): bool + { + if (!$this->hasFullConditionMet()) { + throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); + } + + $db = DB::db(); + $env = $this->env; + + $general = $this->generalObj; + $generalID = $general->getID(); + $generalName = $general->getName(); + $date = $general->getTurnTime($general::TURNTIME_HM); + + $year = $this->env['year']; + $month = $this->env['month']; + + $nation = $this->nation; + $nationID = $nation['nation']; + $nationName = $nation['name']; + + $destNation = $this->destNation; + $destNationID = $destNation['nation']; + $destNationName = $destNation['name']; + + $josaYi = JosaUtil::pick($generalName, '이'); + $josaYiNation = JosaUtil::pick($nationName, '이'); + + $commandName = $this->getName(); + $josaUl = JosaUtil::pick($commandName, '을'); + + $logger = $general->getLogger(); + $logger->pushGeneralActionLog("{$commandName} 발동! <1>$date"); + + $general->addExperience(5 * ($this->getPreReqTurn() + 1)); + $general->addDedication(5 * ($this->getPreReqTurn() + 1)); + + $broadcastMessage = "{$generalName}{$josaYi} {$destNationName}{$commandName}{$josaUl} 발동하였습니다."; + + $nationGeneralList = $db->queryFirstColumn('SELECT no FROM general WHERE nation=%i AND no != %i', $nationID, $generalID); + foreach ($nationGeneralList as $nationGeneralID) { + $nationGeneralLogger = new ActionLogger($nationGeneralID, $nationID, $year, $month); + $nationGeneralLogger->pushGeneralActionLog($broadcastMessage, ActionLogger::PLAIN); + $nationGeneralLogger->flush(); + } + + $josaYiCommand = JosaUtil::pick($commandName, '이'); + + $broadcastMessage = "아국에 {$commandName}{$josaYiCommand} 발동되었습니다."; + + $destNationGeneralList = $db->queryFirstColumn('SELECT no FROM general WHERE nation=%i AND no != %i', $nationID, $generalID); + foreach ($destNationGeneralList as $destNationGeneralID) { + $destNationGeneralLogger = new ActionLogger($destNationGeneralID, $destNationID, $year, $month); + $destNationGeneralLogger->pushGeneralActionLog($broadcastMessage, ActionLogger::PLAIN); + $destNationGeneralLogger->flush(); + } + + $destNationLogger = new ActionLogger(0, $destNationID, $year, $month); + $destNationLogger->pushNationalHistoryLog("{$nationName}{$generalName}{$josaYi} 아국에 {$commandName}{$josaUl} 발동"); + $destNationLogger->flush(); + + $logger->pushNationalHistoryLog("{$generalName}{$josaYi} {$destNationName}{$commandName}{$josaUl} 발동"); + + $db->update('nation', [ + 'strategic_cmd_limit' => $this->getPostReqTurn() + ], 'nation=%i', $nationID); + $db->update('diplomacy', [ + 'term' => $db->sqleval('`term` - %i', 3), + ], '(me = %i AND you = %i) OR (you = %i AND me = %i)', $nationID, $destNationID, $nationID, $destNationID); + $this->setResultTurn(new LastTurn(static::getName(), $this->arg)); + $general->applyDB($db); + + return true; + } + + public function getJSFiles(): array + { + return [ + 'js/defaultSelectNationByMap.js' + ]; + } + + public function getForm(): string + { + $generalObj = $this->generalObj; + $nationID = $generalObj->getNationID(); + $nationList = []; + $testTurn = new LastTurn($this->getName(), null, $this->getPreReqTurn()); + foreach (getAllNationStaticInfo() as $destNation) { + if ($destNation['nation'] == $nationID) { + continue; + } + + $testTurn->setArg(['destNationID' => $destNation['nation']]); + $testCommand = new static($generalObj, $this->env, $testTurn, ['destNationID' => $destNation['nation']]); + if ($testCommand->hasFullConditionMet()) { + $destNation['availableCommand'] = true; + } else { + $destNation['availableCommand'] = false; + } + + $nationList[] = $destNation; + } + + ob_start(); +?> +
+ 선택된 국가에 급습을 발동합니다.
+ 선포, 전쟁중인 상대국에만 가능합니다.
+ 상대 국가를 목록에서 선택하세요.
+ 배경색은 현재 급습 불가능 국가는 붉은색으로 표시됩니다.
+ + arg['amountList']; $goldAmountText = number_format($goldAmount); diff --git a/hwe/sammo/Command/Nation/che_백성동원.php b/hwe/sammo/Command/Nation/che_백성동원.php index 63c19ff9..1a7d704b 100644 --- a/hwe/sammo/Command/Nation/che_백성동원.php +++ b/hwe/sammo/Command/Nation/che_백성동원.php @@ -1,196 +1,193 @@ -arg === null){ - return false; - } - - if(!key_exists('destCityID', $this->arg)){ - return false; - } - if(CityConst::byID($this->arg['destCityID']) === null){ - return false; - } - $destCityID = $this->arg['destCityID']; - - $this->arg = [ - 'destCityID'=>$destCityID, - ]; - return true; - } - - protected function init(){ - $general = $this->generalObj; - - $env = $this->env; - - $this->setCity(); - $this->setNation(['strategic_cmd_limit']); - - $this->minConditionConstraints=[ - ConstraintHelper::OccupiedCity(), - ConstraintHelper::BeChief(), - ConstraintHelper::AvailableStrategicCommand() - ]; - } - - protected function initWithArg() - { - $this->setDestCity($this->arg['destCityID']); - $this->setDestNation($this->destCity['nation']); - - $this->fullConditionConstraints=[ - ConstraintHelper::OccupiedCity(), - ConstraintHelper::BeChief(), - ConstraintHelper::AllowDiplomacyStatus($this->generalObj->getNationID(), [ - 0, 1 - ], '전쟁중이 아닙니다.'), - ConstraintHelper::OccupiedDestCity(), - ConstraintHelper::AvailableStrategicCommand() - ]; - } - - public function getCommandDetailTitle():string{ - $name = $this->getName(); - $reqTurn = $this->getPreReqTurn()+1; - $postReqTurn = $this->getPostReqTurn(); - - return "{$name}/{$reqTurn}턴(전략$postReqTurn)"; - } - - public function getCost():array{ - return [0, 0]; - } - - public function getPreReqTurn():int{ - return 0; - } - - public function getPostReqTurn():int{ - $genCount = Util::valueFit($this->nation['gennum'], GameConst::$initialNationGenLimit); - $nextTerm = Util::round(sqrt($genCount*4)*10); - - $nextTerm = $this->generalObj->onCalcStrategic($this->getName(), 'delay', $nextTerm); - return $nextTerm; - } - - public function getBrief():string{ - $commandName = $this->getName(); - $destCityName = CityConst::byID($this->arg['destCityID'])->name; - return "【{$destCityName}】에 {$commandName}"; - } - - public function run():bool{ - if(!$this->hasFullConditionMet()){ - throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); - } - - $db = DB::db(); - - $general = $this->generalObj; - $generalID = $general->getID(); - $generalName = $general->getName(); - $date = $general->getTurnTime($general::TURNTIME_HM); - - $year = $this->env['year']; - $month = $this->env['month']; - - $destCity = $this->destCity; - $destCityID = $destCity['city']; - $destCityName = $destCity['name']; - - $nationID = $general->getNationID(); - $nationName = $this->nation['name']; - - $logger = $general->getLogger(); - $logger->pushGeneralActionLog("백성동원 발동! <1>$date"); - - $general->addExperience(5 * ($this->getPreReqTurn() + 1)); - $general->addDedication(5 * ($this->getPreReqTurn() + 1)); - - $josaYi = JosaUtil::pick($generalName, '이'); - - $broadcastMessage = "{$generalName}{$josaYi} {$destCityName}백성동원을 하였습니다."; - - $targetGeneralList = $db->queryFirstColumn('SELECT no FROM general WHERE nation=%i AND no != %i', $nationID, $generalID); - foreach($targetGeneralList as $targetGeneralID){ - $targetLogger = new ActionLogger($targetGeneralID, $nationID, $year, $month); - $targetLogger->pushGeneralActionLog($broadcastMessage, ActionLogger::PLAIN); - $targetLogger->flush(); - } - - $db->update('city', [ - 'def' => $db->sqleval('GREATEST(def_max * 0.8, def)'), - 'wall' => $db->sqleval('GREATEST(wall_max * 0.8, wall)'), - ], 'city=%i', $destCityID); - - $josaYiNation = JosaUtil::pick($nationName, '이'); - - - $logger->pushGeneralHistoryLog('백성동원을 발동'); - $logger->pushNationalHistoryLog("【전략】{$nationName}{$josaYiNation} {$destCityName}백성동원을 하였습니다."); - - $db->update('nation', [ - 'strategic_cmd_limit' => $this->getPostReqTurn() - ], 'nation=%i', $nationID); - - $this->setResultTurn(new LastTurn($this->getName(), $this->arg, 0)); - $general->applyDB($db); - - return true; - } - - public function getJSFiles(): array - { - return [ - 'js/defaultSelectCityByMap.js' - ]; - } - - - public function getForm(): string - { - ob_start(); -?> -
-선택된 도시에 백성을 동원해 성벽을 쌓습니다.
-아국 도시만 가능합니다.
-목록을 선택하거나 도시를 클릭하세요.
-
-
-arg === null){ + return false; + } + + if(!key_exists('destCityID', $this->arg)){ + return false; + } + if(CityConst::byID($this->arg['destCityID']) === null){ + return false; + } + $destCityID = $this->arg['destCityID']; + + $this->arg = [ + 'destCityID'=>$destCityID, + ]; + return true; + } + + protected function init(){ + $general = $this->generalObj; + + $env = $this->env; + + $this->setCity(); + $this->setNation(['strategic_cmd_limit']); + + $this->minConditionConstraints=[ + ConstraintHelper::OccupiedCity(), + ConstraintHelper::BeChief(), + ConstraintHelper::AvailableStrategicCommand($this->getPreReqTurn()) + ]; + } + + protected function initWithArg() + { + $this->setDestCity($this->arg['destCityID']); + $this->setDestNation($this->destCity['nation']); + + $this->fullConditionConstraints=[ + ConstraintHelper::OccupiedCity(), + ConstraintHelper::BeChief(), + ConstraintHelper::OccupiedDestCity(), + ConstraintHelper::AvailableStrategicCommand($this->getPreReqTurn()) + ]; + } + + public function getCommandDetailTitle():string{ + $name = $this->getName(); + $reqTurn = $this->getPreReqTurn()+1; + $postReqTurn = $this->getPostReqTurn(); + + return "{$name}/{$reqTurn}턴(전략$postReqTurn)"; + } + + public function getCost():array{ + return [0, 0]; + } + + public function getPreReqTurn():int{ + return 0; + } + + public function getPostReqTurn():int{ + $genCount = Util::valueFit($this->nation['gennum'], GameConst::$initialNationGenLimit); + $nextTerm = Util::round(sqrt($genCount*4)*10); + + $nextTerm = $this->generalObj->onCalcStrategic($this->getName(), 'delay', $nextTerm); + return $nextTerm; + } + + public function getBrief():string{ + $commandName = $this->getName(); + $destCityName = CityConst::byID($this->arg['destCityID'])->name; + return "【{$destCityName}】에 {$commandName}"; + } + + public function run():bool{ + if(!$this->hasFullConditionMet()){ + throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); + } + + $db = DB::db(); + + $general = $this->generalObj; + $generalID = $general->getID(); + $generalName = $general->getName(); + $date = $general->getTurnTime($general::TURNTIME_HM); + + $year = $this->env['year']; + $month = $this->env['month']; + + $destCity = $this->destCity; + $destCityID = $destCity['city']; + $destCityName = $destCity['name']; + + $nationID = $general->getNationID(); + $nationName = $this->nation['name']; + + $logger = $general->getLogger(); + $logger->pushGeneralActionLog("백성동원 발동! <1>$date"); + + $general->addExperience(5 * ($this->getPreReqTurn() + 1)); + $general->addDedication(5 * ($this->getPreReqTurn() + 1)); + + $josaYi = JosaUtil::pick($generalName, '이'); + + $broadcastMessage = "{$generalName}{$josaYi} {$destCityName}백성동원을 하였습니다."; + + $targetGeneralList = $db->queryFirstColumn('SELECT no FROM general WHERE nation=%i AND no != %i', $nationID, $generalID); + foreach($targetGeneralList as $targetGeneralID){ + $targetLogger = new ActionLogger($targetGeneralID, $nationID, $year, $month); + $targetLogger->pushGeneralActionLog($broadcastMessage, ActionLogger::PLAIN); + $targetLogger->flush(); + } + + $db->update('city', [ + 'def' => $db->sqleval('GREATEST(def_max * 0.8, def)'), + 'wall' => $db->sqleval('GREATEST(wall_max * 0.8, wall)'), + ], 'city=%i', $destCityID); + + $josaYiNation = JosaUtil::pick($nationName, '이'); + + + $logger->pushGeneralHistoryLog('백성동원을 발동'); + $logger->pushNationalHistoryLog("【전략】{$nationName}{$josaYiNation} {$destCityName}백성동원을 하였습니다."); + + $db->update('nation', [ + 'strategic_cmd_limit' => 12 + ], 'nation=%i', $nationID); + + $this->setResultTurn(new LastTurn($this->getName(), $this->arg, 0)); + $general->applyDB($db); + + return true; + } + + public function getJSFiles(): array + { + return [ + 'js/defaultSelectCityByMap.js' + ]; + } + + + public function getForm(): string + { + ob_start(); +?> +
+선택된 도시에 백성을 동원해 성벽을 쌓습니다.
+아국 도시만 가능합니다.
+목록을 선택하거나 도시를 클릭하세요.
+
+
+minConditionConstraints=[ ConstraintHelper::OccupiedCity(), ConstraintHelper::BeChief(), - ConstraintHelper::AvailableStrategicCommand(), + ConstraintHelper::AvailableStrategicCommand($this->getPreReqTurn()), ]; } @@ -75,7 +75,7 @@ class che_수몰 extends Command\NationCommand{ ConstraintHelper::NotNeutralDestCity(), ConstraintHelper::NotOccupiedDestCity(), ConstraintHelper::BattleGroundCity(), - ConstraintHelper::AvailableStrategicCommand(), + ConstraintHelper::AvailableStrategicCommand($this->getPreReqTurn()), ]; } @@ -179,7 +179,7 @@ class che_수몰 extends Command\NationCommand{ $logger->pushNationalHistoryLog("{$generalName}{$josaYi} {$destCityName}수몰을 발동"); $db->update('nation', [ - 'strategic_cmd_limit' => $this->getPostReqTurn() + 'strategic_cmd_limit' => 12 ], 'nation=%i', $nationID); $this->setResultTurn(new LastTurn($this->getName(), $this->arg, 0)); diff --git a/hwe/sammo/Command/Nation/che_의병모집.php b/hwe/sammo/Command/Nation/che_의병모집.php index 43ff6db9..5ea6c162 100644 --- a/hwe/sammo/Command/Nation/che_의병모집.php +++ b/hwe/sammo/Command/Nation/che_의병모집.php @@ -1,243 +1,243 @@ -arg = null; - return true; - } - - protected function init() - { - - $general = $this->generalObj; - - $this->setNation(['strategic_cmd_limit']); - $this->setCity(); - $env = $this->env; - $relYear = $env['year'] - $env['startyear']; - - $this->fullConditionConstraints = [ - ConstraintHelper::BeChief(), - ConstraintHelper::NotBeNeutral(), - ConstraintHelper::OccupiedCity(), - ConstraintHelper::AvailableStrategicCommand(), - ConstraintHelper::NotOpeningPart($relYear), - ]; - } - - public function getCommandDetailTitle(): string - { - $name = $this->getName(); - $reqTurn = $this->getPreReqTurn() + 1; - $postReqTurn = $this->getPostReqTurn(); - - return "{$name}/{$reqTurn}턴(전략$postReqTurn)"; - } - - public function getCost(): array - { - return [0, 0]; - } - - public function getPreReqTurn(): int - { - return 2; - } - - public function getPostReqTurn(): int - { - $genCount = Util::valueFit($this->nation['gennum'], GameConst::$initialNationGenLimit); - $nextTerm = Util::round(sqrt($genCount * 10) * 10); - - $nextTerm = $this->generalObj->onCalcStrategic($this->getName(), 'delay', $nextTerm); - return $nextTerm; - } - - public function run(): bool - { - if (!$this->hasFullConditionMet()) { - throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); - } - - $db = DB::db(); - $env = $this->env; - - $general = $this->generalObj; - $generalID = $general->getID(); - $generalName = $general->getName(); - $date = $general->getTurnTime($general::TURNTIME_HM); - - $year = $this->env['year']; - $month = $this->env['month']; - - $nation = $this->nation; - $nationID = $nation['nation']; - $nationName = $nation['name']; - - $commandName = $this->getName(); - $josaUl = JosaUtil::pick($commandName, '을'); - - $genCount = $db->queryFirstField('SELECT count(no) FROM general WHERE nation=%i AND npc < 2', $nationID); - $npcCount = $db->queryFirstField('SELECT count(no) FROM general WHERE nation=%i AND npc = 3', $nationID); - $npcOtherCount = $db->queryFirstField('SELECT count(no) FROM general WHERE nation!=%i AND npc = 3', $nationID); - - - $genCount = Util::valueFit($genCount, 1); - $npcCount = Util::valueFit($npcCount, 1); - $npcOtherCountScore = Util::round(sqrt($npcOtherCount + 1)) - 1; - - $logger = $general->getLogger(); - $logger->pushGeneralActionLog("{$commandName} 발동! <1>$date"); - - $josaYi = JosaUtil::pick($generalName, '이'); - $josaYiNation = JosaUtil::pick($nationName, '이'); - - $broadcastMessage = "{$generalName}{$josaYi} {$commandName}{$josaUl} 발동하였습니다."; - - $nationGeneralList = $db->queryFirstColumn('SELECT no FROM general WHERE nation=%i AND no != %i', $nationID, $generalID); - foreach ($nationGeneralList as $nationGeneralID) { - $nationGeneralLogger = new ActionLogger($nationGeneralID, $nationID, $year, $month); - $nationGeneralLogger->pushGeneralActionLog($broadcastMessage, ActionLogger::PLAIN); - $nationGeneralLogger->flush(); - } - - $logger->pushGeneralHistoryLog("{$commandName}{$josaUl} 발동"); - $logger->pushNationalHistoryLog("{$generalName}{$josaYi} {$commandName}{$josaUl} 발동"); - - $general->addExperience(5 * ($this->getPreReqTurn() + 1)); - $general->addDedication(5 * ($this->getPreReqTurn() + 1)); - - $gameStor = KVStorage::getStorage($db, 'game_env'); //TODO: 차라리 env가 이거여야..? - - $avgGenCnt = $db->queryFirstField('SELECT avg(gennum) FROM nation WHERE level > 0'); - $createGenCnt = 5 + Util::round($avgGenCnt / 10); - $createGenIdx = $gameStor->npccount + 1; - $lastCreatGenIdx = $createGenIdx + $createGenCnt; - - $pickTypeList = ['무' => 5, '지' => 5]; - - $avgGen = $db->queryFirstRow( - 'SELECT avg(dedication) as ded,avg(experience) as exp, - avg(dex1+dex2+dex3+dex4) as dex_t, avg(age) as age, avg(dex5) as dex5 - from general where nation=%i', - $nationID - ); - $dexTotal = $avgGen['dex_t']; - - for (; $createGenIdx <= $lastCreatGenIdx; $createGenIdx++) { - $pickType = Util::choiceRandomUsingWeight($pickTypeList); - - $totalStat = GameConst::$defaultStatNPCMax * 2 + 10; - $minStat = 10; - $mainStat = GameConst::$defaultStatNPCMax - Util::randRangeInt(0, 10); - //TODO: defaultStatNPCTotal, defaultStatNPCMin 추가 - $otherStat = $minStat + Util::randRangeInt(0, 5); - $subStat = $totalStat - $mainStat - $otherStat; - if ($subStat < $minStat) { - $subStat = $otherStat; - $otherStat = $minStat; - $mainStat = $totalStat - $subStat - $otherStat; - if ($mainStat) { - throw new \LogicException('기본 스탯 설정값이 잘못되어 있음'); - } - } - - if ($pickType == '무') { - $leadership = $subStat; - $strength = $mainStat; - $intel = $otherStat; - $dexVal = Util::choiceRandom([ - [$dexTotal * 5 / 8, $dexTotal / 8, $dexTotal / 8, $dexTotal / 8], - [$dexTotal / 8, $dexTotal * 5 / 8, $dexTotal / 8, $dexTotal / 8], - [$dexTotal / 8, $dexTotal / 8, $dexTotal * 5 / 8, $dexTotal / 8], - ]); - } else if ($pickType == '지') { - $leadership = $subStat; - $strength = $otherStat; - $intel = $mainStat; - $dexVal = [$dexTotal / 8, $dexTotal / 8, $dexTotal * 5 / 8, $dexTotal / 8]; - } else { - $leadership = $otherStat; - $strength = $subStat; - $intel = $mainStat; - $dexVal = [$dexTotal / 4, $dexTotal / 4, $dexTotal / 4, $dexTotal / 4]; - } - - $leadership = Util::round($leadership); - $strength = Util::round($strength); - $intel = Util::round($intel); - - $age = $avgGen['age']; - - $newNPC = new \sammo\Scenario\NPC( - Util::randRangeInt(1, 150), - "의병장{$createGenIdx}", - null, - $nationID, - $general->getCityID(), - $leadership, - $strength, - $intel, - 1, - $env['year'] - 20, - $env['year'] + 6, - null, - null - ); - $newNPC->killturn = Util::randRangeInt(64, 70); - $newNPC->npc = 4; - $newNPC->setMoney(1000, 1000); - $newNPC->setExpDed($avgGen['exp'], $avgGen['ded']); - $newNPC->setDex( - $dexVal[0], - $dexVal[1], - $dexVal[2], - $dexVal[3], - $avgGen['dex5'] - ); - - $newNPC->build($this->env); - } - - $gameStor->npccount = $lastCreatGenIdx; - $db->update('nation', [ - 'gennum' => $db->sqleval('gennum + %i', $createGenCnt), - 'strategic_cmd_limit' => $this->getPostReqTurn() - ], 'nation=%i', $nationID); - - $this->setResultTurn(new LastTurn(static::getName(), $this->arg)); - $general->applyDB($db); - - return true; - } -} +arg = null; + return true; + } + + protected function init() + { + + $general = $this->generalObj; + + $this->setNation(['strategic_cmd_limit']); + $this->setCity(); + $env = $this->env; + $relYear = $env['year'] - $env['startyear']; + + $this->fullConditionConstraints = [ + ConstraintHelper::BeChief(), + ConstraintHelper::NotBeNeutral(), + ConstraintHelper::OccupiedCity(), + ConstraintHelper::AvailableStrategicCommand($this->getPreReqTurn()), + ConstraintHelper::NotOpeningPart($relYear), + ]; + } + + public function getCommandDetailTitle(): string + { + $name = $this->getName(); + $reqTurn = $this->getPreReqTurn() + 1; + $postReqTurn = $this->getPostReqTurn(); + + return "{$name}/{$reqTurn}턴(전략$postReqTurn)"; + } + + public function getCost(): array + { + return [0, 0]; + } + + public function getPreReqTurn(): int + { + return 2; + } + + public function getPostReqTurn(): int + { + $genCount = Util::valueFit($this->nation['gennum'], GameConst::$initialNationGenLimit); + $nextTerm = Util::round(sqrt($genCount * 10) * 10); + + $nextTerm = $this->generalObj->onCalcStrategic($this->getName(), 'delay', $nextTerm); + return $nextTerm; + } + + public function run(): bool + { + if (!$this->hasFullConditionMet()) { + throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); + } + + $db = DB::db(); + $env = $this->env; + + $general = $this->generalObj; + $generalID = $general->getID(); + $generalName = $general->getName(); + $date = $general->getTurnTime($general::TURNTIME_HM); + + $year = $this->env['year']; + $month = $this->env['month']; + + $nation = $this->nation; + $nationID = $nation['nation']; + $nationName = $nation['name']; + + $commandName = $this->getName(); + $josaUl = JosaUtil::pick($commandName, '을'); + + $genCount = $db->queryFirstField('SELECT count(no) FROM general WHERE nation=%i AND npc < 2', $nationID); + $npcCount = $db->queryFirstField('SELECT count(no) FROM general WHERE nation=%i AND npc = 3', $nationID); + $npcOtherCount = $db->queryFirstField('SELECT count(no) FROM general WHERE nation!=%i AND npc = 3', $nationID); + + + $genCount = Util::valueFit($genCount, 1); + $npcCount = Util::valueFit($npcCount, 1); + $npcOtherCountScore = Util::round(sqrt($npcOtherCount + 1)) - 1; + + $logger = $general->getLogger(); + $logger->pushGeneralActionLog("{$commandName} 발동! <1>$date"); + + $josaYi = JosaUtil::pick($generalName, '이'); + $josaYiNation = JosaUtil::pick($nationName, '이'); + + $broadcastMessage = "{$generalName}{$josaYi} {$commandName}{$josaUl} 발동하였습니다."; + + $nationGeneralList = $db->queryFirstColumn('SELECT no FROM general WHERE nation=%i AND no != %i', $nationID, $generalID); + foreach ($nationGeneralList as $nationGeneralID) { + $nationGeneralLogger = new ActionLogger($nationGeneralID, $nationID, $year, $month); + $nationGeneralLogger->pushGeneralActionLog($broadcastMessage, ActionLogger::PLAIN); + $nationGeneralLogger->flush(); + } + + $logger->pushGeneralHistoryLog("{$commandName}{$josaUl} 발동"); + $logger->pushNationalHistoryLog("{$generalName}{$josaYi} {$commandName}{$josaUl} 발동"); + + $general->addExperience(5 * ($this->getPreReqTurn() + 1)); + $general->addDedication(5 * ($this->getPreReqTurn() + 1)); + + $gameStor = KVStorage::getStorage($db, 'game_env'); //TODO: 차라리 env가 이거여야..? + + $avgGenCnt = $db->queryFirstField('SELECT avg(gennum) FROM nation WHERE level > 0'); + $createGenCnt = 5 + Util::round($avgGenCnt / 10); + $createGenIdx = $gameStor->npccount + 1; + $lastCreatGenIdx = $createGenIdx + $createGenCnt; + + $pickTypeList = ['무' => 5, '지' => 5]; + + $avgGen = $db->queryFirstRow( + 'SELECT avg(dedication) as ded,avg(experience) as exp, + avg(dex1+dex2+dex3+dex4) as dex_t, avg(age) as age, avg(dex5) as dex5 + from general where nation=%i', + $nationID + ); + $dexTotal = $avgGen['dex_t']; + + for (; $createGenIdx <= $lastCreatGenIdx; $createGenIdx++) { + $pickType = Util::choiceRandomUsingWeight($pickTypeList); + + $totalStat = GameConst::$defaultStatNPCMax * 2 + 10; + $minStat = 10; + $mainStat = GameConst::$defaultStatNPCMax - Util::randRangeInt(0, 10); + //TODO: defaultStatNPCTotal, defaultStatNPCMin 추가 + $otherStat = $minStat + Util::randRangeInt(0, 5); + $subStat = $totalStat - $mainStat - $otherStat; + if ($subStat < $minStat) { + $subStat = $otherStat; + $otherStat = $minStat; + $mainStat = $totalStat - $subStat - $otherStat; + if ($mainStat) { + throw new \LogicException('기본 스탯 설정값이 잘못되어 있음'); + } + } + + if ($pickType == '무') { + $leadership = $subStat; + $strength = $mainStat; + $intel = $otherStat; + $dexVal = Util::choiceRandom([ + [$dexTotal * 5 / 8, $dexTotal / 8, $dexTotal / 8, $dexTotal / 8], + [$dexTotal / 8, $dexTotal * 5 / 8, $dexTotal / 8, $dexTotal / 8], + [$dexTotal / 8, $dexTotal / 8, $dexTotal * 5 / 8, $dexTotal / 8], + ]); + } else if ($pickType == '지') { + $leadership = $subStat; + $strength = $otherStat; + $intel = $mainStat; + $dexVal = [$dexTotal / 8, $dexTotal / 8, $dexTotal * 5 / 8, $dexTotal / 8]; + } else { + $leadership = $otherStat; + $strength = $subStat; + $intel = $mainStat; + $dexVal = [$dexTotal / 4, $dexTotal / 4, $dexTotal / 4, $dexTotal / 4]; + } + + $leadership = Util::round($leadership); + $strength = Util::round($strength); + $intel = Util::round($intel); + + $age = $avgGen['age']; + + $newNPC = new \sammo\Scenario\NPC( + Util::randRangeInt(1, 150), + "의병장{$createGenIdx}", + null, + $nationID, + $general->getCityID(), + $leadership, + $strength, + $intel, + 1, + $env['year'] - 20, + $env['year'] + 6, + null, + null + ); + $newNPC->killturn = Util::randRangeInt(64, 70); + $newNPC->npc = 4; + $newNPC->setMoney(1000, 1000); + $newNPC->setExpDed($avgGen['exp'], $avgGen['ded']); + $newNPC->setDex( + $dexVal[0], + $dexVal[1], + $dexVal[2], + $dexVal[3], + $avgGen['dex5'] + ); + + $newNPC->build($this->env); + } + + $gameStor->npccount = $lastCreatGenIdx; + $db->update('nation', [ + 'gennum' => $db->sqleval('gennum + %i', $createGenCnt), + 'strategic_cmd_limit' => 12 + ], 'nation=%i', $nationID); + + $this->setResultTurn(new LastTurn(static::getName(), $this->arg)); + $general->applyDB($db); + + return true; + } +} diff --git a/hwe/sammo/Command/Nation/che_이호경식.php b/hwe/sammo/Command/Nation/che_이호경식.php index a25c4aaf..0eb2ba26 100644 --- a/hwe/sammo/Command/Nation/che_이호경식.php +++ b/hwe/sammo/Command/Nation/che_이호경식.php @@ -1,250 +1,250 @@ -arg === null) { - return false; - } - //NOTE: 멸망 직전에 턴을 넣을 수 있으므로, 존재하지 않는 국가여도 argTest에서 바로 탈락시키지 않음 - if (!key_exists('destNationID', $this->arg)) { - return false; - } - $destNationID = $this->arg['destNationID']; - - if (!is_int($destNationID)) { - return false; - } - if ($destNationID < 1) { - return false; - } - - $this->arg = [ - 'destNationID' => $destNationID - ]; - return true; - } - - protected function init() - { - $general = $this->generalObj; - - $env = $this->env; - - $this->setCity(); - $this->setNation(['strategic_cmd_limit']); - - $this->minConditionConstraints = [ - ConstraintHelper::OccupiedCity(), - ConstraintHelper::BeChief(), - ConstraintHelper::AvailableStrategicCommand(), - ]; - } - - protected function initWithArg() - { - $this->setDestNation($this->arg['destNationID'], null); - - $this->fullConditionConstraints = [ - ConstraintHelper::OccupiedCity(), - ConstraintHelper::BeChief(), - ConstraintHelper::ExistsDestNation(), - ConstraintHelper::AllowDiplomacyBetweenStatus( - [0, 1], - '선포, 전쟁중인 상대국에게만 가능합니다.' - ), - ConstraintHelper::AvailableStrategicCommand(), - ]; - } - - public function getCommandDetailTitle(): string - { - $name = $this->getName(); - $reqTurn = $this->getPreReqTurn() + 1; - $postReqTurn = $this->getPostReqTurn(); - - return "{$name}/{$reqTurn}턴(전략$postReqTurn)"; - } - - public function getCost(): array - { - return [0, 0]; - } - - public function getPreReqTurn(): int - { - return 0; - } - - public function getPostReqTurn(): int - { - $genCount = Util::valueFit($this->nation['gennum'], GameConst::$initialNationGenLimit); - $nextTerm = Util::round(sqrt($genCount * 16) * 10); - - $nextTerm = $this->generalObj->onCalcStrategic($this->getName(), 'delay', $nextTerm); - return $nextTerm; - } - - public function getBrief(): string - { - $commandName = $this->getName(); - $destNationName = getNationStaticInfo($this->arg['destNationID'])['name']; - return "【{$destNationName}】에 {$commandName}"; - } - - - public function run(): bool - { - if (!$this->hasFullConditionMet()) { - throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); - } - - $db = DB::db(); - $env = $this->env; - - $general = $this->generalObj; - $generalID = $general->getID(); - $generalName = $general->getName(); - $date = $general->getTurnTime($general::TURNTIME_HM); - - $year = $this->env['year']; - $month = $this->env['month']; - - $nation = $this->nation; - $nationID = $nation['nation']; - $nationName = $nation['name']; - - $destNation = $this->destNation; - $destNationID = $destNation['nation']; - $destNationName = $destNation['name']; - - $josaYi = JosaUtil::pick($generalName, '이'); - $josaYiNation = JosaUtil::pick($nationName, '이'); - - $commandName = $this->getName(); - $josaUl = JosaUtil::pick($commandName, '을'); - - $logger = $general->getLogger(); - $logger->pushGeneralActionLog("{$commandName} 발동! <1>$date"); - - $general->addExperience(5 * ($this->getPreReqTurn() + 1)); - $general->addDedication(5 * ($this->getPreReqTurn() + 1)); - - $broadcastMessage = "{$generalName}{$josaYi} {$destNationName}{$commandName}{$josaUl} 발동하였습니다."; - - $nationGeneralList = $db->queryFirstColumn('SELECT no FROM general WHERE nation=%i AND no != %i', $nationID, $generalID); - foreach ($nationGeneralList as $nationGeneralID) { - $nationGeneralLogger = new ActionLogger($nationGeneralID, $nationID, $year, $month); - $nationGeneralLogger->pushGeneralActionLog($broadcastMessage, ActionLogger::PLAIN); - $nationGeneralLogger->flush(); - } - - $josaYiCommand = JosaUtil::pick($commandName, '이'); - - $broadcastMessage = "아국에 {$commandName}{$josaYiCommand} 발동되었습니다."; - - $destNationGeneralList = $db->queryFirstColumn('SELECT no FROM general WHERE nation=%i AND no != %i', $nationID, $generalID); - foreach ($destNationGeneralList as $destNationGeneralID) { - $destNationGeneralLogger = new ActionLogger($destNationGeneralID, $destNationID, $year, $month); - $destNationGeneralLogger->pushGeneralActionLog($broadcastMessage, ActionLogger::PLAIN); - $destNationGeneralLogger->flush(); - } - - $destNationLogger = new ActionLogger(0, $destNationID, $year, $month); - $destNationLogger->pushNationalHistoryLog("{$nationName}{$generalName}{$josaYi} 아국에 {$commandName}{$josaUl} 발동"); - $destNationLogger->flush(); - - $logger->pushNationalHistoryLog("{$generalName}{$josaYi} {$destNationName}{$commandName}{$josaUl} 발동"); - - $db->update('nation', [ - 'strategic_cmd_limit' => $this->getPostReqTurn() - ], 'nation=%i', $nationID); - $db->update('diplomacy', [ - 'term' => $db->sqleval('IF(`state`=0, %i, `term`+ %i)', 3, 3), - 'state' => 1, - ], '(me = %i AND you = %i) OR (you = %i AND me = %i)', $nationID, $destNationID, $nationID, $destNationID); - - $this->setResultTurn(new LastTurn(static::getName(), $this->arg)); - $general->applyDB($db); - - return true; - } - - public function getJSFiles(): array - { - return [ - 'js/defaultSelectNationByMap.js' - ]; - } - - public function getForm(): string - { - $generalObj = $this->generalObj; - $nationID = $generalObj->getNationID(); - $nationList = []; - $testTurn = new LastTurn($this->getName(), null, $this->getPreReqTurn()); - foreach (getAllNationStaticInfo() as $destNation) { - if ($destNation['nation'] == $nationID) { - continue; - } - - $testTurn->setArg(['destNationID' => $destNation['nation']]); - $testCommand = new static($generalObj, $this->env, $testTurn, ['destNationID' => $destNation['nation']]); - if ($testCommand->hasFullConditionMet()) { - $destNation['availableCommand'] = true; - } else { - $destNation['availableCommand'] = false; - } - - $nationList[] = $destNation; - } - - ob_start(); -?> -
- 선택된 국가에 이호경식을 발동합니다.
- 선포, 전쟁중인 상대국에만 가능합니다.
- 상대 국가를 목록에서 선택하세요.
- 배경색은 현재 이호경식 불가능 국가는 붉은색으로 표시됩니다.
- - arg === null) { + return false; + } + //NOTE: 멸망 직전에 턴을 넣을 수 있으므로, 존재하지 않는 국가여도 argTest에서 바로 탈락시키지 않음 + if (!key_exists('destNationID', $this->arg)) { + return false; + } + $destNationID = $this->arg['destNationID']; + + if (!is_int($destNationID)) { + return false; + } + if ($destNationID < 1) { + return false; + } + + $this->arg = [ + 'destNationID' => $destNationID + ]; + return true; + } + + protected function init() + { + $general = $this->generalObj; + + $env = $this->env; + + $this->setCity(); + $this->setNation(['strategic_cmd_limit']); + + $this->minConditionConstraints = [ + ConstraintHelper::OccupiedCity(), + ConstraintHelper::BeChief(), + ConstraintHelper::AvailableStrategicCommand($this->getPreReqTurn()), + ]; + } + + protected function initWithArg() + { + $this->setDestNation($this->arg['destNationID'], null); + + $this->fullConditionConstraints = [ + ConstraintHelper::OccupiedCity(), + ConstraintHelper::BeChief(), + ConstraintHelper::ExistsDestNation(), + ConstraintHelper::AllowDiplomacyBetweenStatus( + [0, 1], + '선포, 전쟁중인 상대국에게만 가능합니다.' + ), + ConstraintHelper::AvailableStrategicCommand($this->getPreReqTurn()), + ]; + } + + public function getCommandDetailTitle(): string + { + $name = $this->getName(); + $reqTurn = $this->getPreReqTurn() + 1; + $postReqTurn = $this->getPostReqTurn(); + + return "{$name}/{$reqTurn}턴(전략$postReqTurn)"; + } + + public function getCost(): array + { + return [0, 0]; + } + + public function getPreReqTurn(): int + { + return 0; + } + + public function getPostReqTurn(): int + { + $genCount = Util::valueFit($this->nation['gennum'], GameConst::$initialNationGenLimit); + $nextTerm = Util::round(sqrt($genCount * 16) * 10); + + $nextTerm = $this->generalObj->onCalcStrategic($this->getName(), 'delay', $nextTerm); + return $nextTerm; + } + + public function getBrief(): string + { + $commandName = $this->getName(); + $destNationName = getNationStaticInfo($this->arg['destNationID'])['name']; + return "【{$destNationName}】에 {$commandName}"; + } + + + public function run(): bool + { + if (!$this->hasFullConditionMet()) { + throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); + } + + $db = DB::db(); + $env = $this->env; + + $general = $this->generalObj; + $generalID = $general->getID(); + $generalName = $general->getName(); + $date = $general->getTurnTime($general::TURNTIME_HM); + + $year = $this->env['year']; + $month = $this->env['month']; + + $nation = $this->nation; + $nationID = $nation['nation']; + $nationName = $nation['name']; + + $destNation = $this->destNation; + $destNationID = $destNation['nation']; + $destNationName = $destNation['name']; + + $josaYi = JosaUtil::pick($generalName, '이'); + $josaYiNation = JosaUtil::pick($nationName, '이'); + + $commandName = $this->getName(); + $josaUl = JosaUtil::pick($commandName, '을'); + + $logger = $general->getLogger(); + $logger->pushGeneralActionLog("{$commandName} 발동! <1>$date"); + + $general->addExperience(5 * ($this->getPreReqTurn() + 1)); + $general->addDedication(5 * ($this->getPreReqTurn() + 1)); + + $broadcastMessage = "{$generalName}{$josaYi} {$destNationName}{$commandName}{$josaUl} 발동하였습니다."; + + $nationGeneralList = $db->queryFirstColumn('SELECT no FROM general WHERE nation=%i AND no != %i', $nationID, $generalID); + foreach ($nationGeneralList as $nationGeneralID) { + $nationGeneralLogger = new ActionLogger($nationGeneralID, $nationID, $year, $month); + $nationGeneralLogger->pushGeneralActionLog($broadcastMessage, ActionLogger::PLAIN); + $nationGeneralLogger->flush(); + } + + $josaYiCommand = JosaUtil::pick($commandName, '이'); + + $broadcastMessage = "아국에 {$commandName}{$josaYiCommand} 발동되었습니다."; + + $destNationGeneralList = $db->queryFirstColumn('SELECT no FROM general WHERE nation=%i AND no != %i', $nationID, $generalID); + foreach ($destNationGeneralList as $destNationGeneralID) { + $destNationGeneralLogger = new ActionLogger($destNationGeneralID, $destNationID, $year, $month); + $destNationGeneralLogger->pushGeneralActionLog($broadcastMessage, ActionLogger::PLAIN); + $destNationGeneralLogger->flush(); + } + + $destNationLogger = new ActionLogger(0, $destNationID, $year, $month); + $destNationLogger->pushNationalHistoryLog("{$nationName}{$generalName}{$josaYi} 아국에 {$commandName}{$josaUl} 발동"); + $destNationLogger->flush(); + + $logger->pushNationalHistoryLog("{$generalName}{$josaYi} {$destNationName}{$commandName}{$josaUl} 발동"); + + $db->update('nation', [ + 'strategic_cmd_limit' => 12 + ], 'nation=%i', $nationID); + $db->update('diplomacy', [ + 'term' => $db->sqleval('IF(`state`=0, %i, `term`+ %i)', 3, 3), + 'state' => 1, + ], '(me = %i AND you = %i) OR (you = %i AND me = %i)', $nationID, $destNationID, $nationID, $destNationID); + + $this->setResultTurn(new LastTurn(static::getName(), $this->arg)); + $general->applyDB($db); + + return true; + } + + public function getJSFiles(): array + { + return [ + 'js/defaultSelectNationByMap.js' + ]; + } + + public function getForm(): string + { + $generalObj = $this->generalObj; + $nationID = $generalObj->getNationID(); + $nationList = []; + $testTurn = new LastTurn($this->getName(), null, $this->getPreReqTurn()); + foreach (getAllNationStaticInfo() as $destNation) { + if ($destNation['nation'] == $nationID) { + continue; + } + + $testTurn->setArg(['destNationID' => $destNation['nation']]); + $testCommand = new static($generalObj, $this->env, $testTurn, ['destNationID' => $destNation['nation']]); + if ($testCommand->hasFullConditionMet()) { + $destNation['availableCommand'] = true; + } else { + $destNation['availableCommand'] = false; + } + + $nationList[] = $destNation; + } + + ob_start(); +?> +
+ 선택된 국가에 이호경식을 발동합니다.
+ 선포, 전쟁중인 상대국에만 가능합니다.
+ 상대 국가를 목록에서 선택하세요.
+ 배경색은 현재 이호경식 불가능 국가는 붉은색으로 표시됩니다.
+ + getName(); diff --git a/hwe/sammo/Command/Nation/che_피장파장.php b/hwe/sammo/Command/Nation/che_피장파장.php index 616f8d53..1e8af5d4 100644 --- a/hwe/sammo/Command/Nation/che_피장파장.php +++ b/hwe/sammo/Command/Nation/che_피장파장.php @@ -1,239 +1,257 @@ -arg === null){ - return false; - } - //NOTE: 멸망 직전에 턴을 넣을 수 있으므로, 존재하지 않는 국가여도 argTest에서 바로 탈락시키지 않음 - if(!key_exists('destNationID', $this->arg)){ - return false; - } - $destNationID = $this->arg['destNationID']; - - if(!is_int($destNationID)){ - return false; - } - if($destNationID < 1){ - return false; - } - - $this->arg = [ - 'destNationID'=>$destNationID - ]; - return true; - } - - protected function init(){ - $general = $this->generalObj; - - $env = $this->env; - - $this->setCity(); - $this->setNation(['strategic_cmd_limit']); - - $this->minConditionConstraints=[ - ConstraintHelper::OccupiedCity(), - ConstraintHelper::BeChief(), - ConstraintHelper::AvailableStrategicCommand(), - ]; - } - - protected function initWithArg() - { - $this->setDestNation($this->arg['destNationID'], null); - - $this->fullConditionConstraints=[ - ConstraintHelper::OccupiedCity(), - ConstraintHelper::BeChief(), - ConstraintHelper::ExistsDestNation(), - ConstraintHelper::AllowDiplomacyBetweenStatus( - [0, 1], - '선포, 전쟁중인 상대국에게만 가능합니다.' - ), - ConstraintHelper::AvailableStrategicCommand(), - ]; - } - - public function getCommandDetailTitle():string{ - $name = $this->getName(); - $reqTurn = $this->getPreReqTurn()+1; - $postReqTurn = $this->getPostReqTurn(); - - return "{$name}/{$reqTurn}턴(전략$postReqTurn)"; - } - - public function getCost():array{ - return [0, 0]; - } - - public function getPreReqTurn():int{ - return 2; - } - - public function getPostReqTurn():int{ - $genCount = Util::valueFit($this->nation['gennum'], GameConst::$initialNationGenLimit); - $nextTerm = Util::round(sqrt($genCount*2)*10); - - $nextTerm = $this->generalObj->onCalcStrategic($this->getName(), 'delay', $nextTerm); - return $nextTerm; - } - - public function getBrief():string{ - $commandName = $this->getName(); - $destNationName = getNationStaticInfo($this->arg['destNationID'])['name']; - return "【{$destNationName}】에 {$commandName}"; - } - - - public function run():bool{ - if(!$this->hasFullConditionMet()){ - throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); - } - - $db = DB::db(); - $env = $this->env; - - $general = $this->generalObj; - $generalID = $general->getID(); - $generalName = $general->getName(); - $date = $general->getTurnTime($general::TURNTIME_HM); - - $year = $this->env['year']; - $month = $this->env['month']; - - $nation = $this->nation; - $nationID = $nation['nation']; - $nationName = $nation['name']; - - $destNation = $this->destNation; - $destNationID = $destNation['nation']; - $destNationName = $destNation['name']; - - $josaYi = JosaUtil::pick($generalName, '이'); - $josaYiNation = JosaUtil::pick($nationName, '이'); - - $commandName = $this->getName(); - $josaUl = JosaUtil::pick($commandName, '을'); - - $logger = $general->getLogger(); - $logger->pushGeneralActionLog("{$commandName} 발동! <1>$date"); - - $general->addExperience(5 * ($this->getPreReqTurn() + 1)); - $general->addDedication(5 * ($this->getPreReqTurn() + 1)); - - $broadcastMessage = "{$generalName}{$josaYi} {$destNationName}{$commandName}{$josaUl} 발동하였습니다."; - - $nationGeneralList = $db->queryFirstColumn('SELECT no FROM general WHERE nation=%i AND no != %i', $nationID, $generalID); - foreach($nationGeneralList as $nationGeneralID){ - $nationGeneralLogger = new ActionLogger($nationGeneralID, $nationID, $year, $month); - $nationGeneralLogger->pushGeneralActionLog($broadcastMessage, ActionLogger::PLAIN); - $nationGeneralLogger->flush(); - } - - $josaYiCommand = JosaUtil::pick($commandName, '이'); - - $broadcastMessage = "아국에 {$commandName}{$josaYiCommand} 발동되었습니다."; - - $destNationGeneralList = $db->queryFirstColumn('SELECT no FROM general WHERE nation=%i AND no != %i', $nationID, $generalID); - foreach($destNationGeneralList as $destNationGeneralID){ - $destNationGeneralLogger = new ActionLogger($destNationGeneralID, $destNationID, $year, $month); - $destNationGeneralLogger->pushGeneralActionLog($broadcastMessage, ActionLogger::PLAIN); - $destNationGeneralLogger->flush(); - } - - $destNationLogger = new ActionLogger(0, $destNationID, $year, $month); - $destNationLogger->pushNationalHistoryLog("{$nationName}{$generalName}{$josaYi} 아국에 {$commandName}{$josaUl} 발동"); - $destNationLogger->flush(); - - $logger->pushNationalHistoryLog("{$generalName}{$josaYi} {$destNationName}{$commandName}{$josaUl} 발동"); - - $db->update('nation', [ - 'strategic_cmd_limit' => $this->getPostReqTurn() - ], 'nation=%i', $nationID); - $db->update('nation', [ - 'strategic_cmd_limit' => $db->sqleval('strategic_cmd_limit + %i', static::$delayCnt) - ], 'nation = %i', $destNationID); - - $general->applyDB($db); - - return true; - } - - public function getJSFiles(): array - { - return [ - 'js/defaultSelectNationByMap.js' - ]; - } - - public function getForm(): string - { - $generalObj = $this->generalObj; - $nationID = $generalObj->getNationID(); - $nationList = []; - $testTurn = new LastTurn($this->getName(), null, $this->getPreReqTurn()); - foreach(getAllNationStaticInfo() as $destNation){ - if($destNation['nation'] == $nationID){ - continue; - } - - $testTurn->setArg(['destNationID'=>$destNation['nation']]); - $testCommand = new static($generalObj, $this->env, $testTurn, ['destNationID'=>$destNation['nation']]); - if($testCommand->hasFullConditionMet()){ - $destNation['availableCommand'] = true; - } - else{ - $destNation['availableCommand'] = false; - } - - $nationList[] = $destNation; - } - - ob_start(); -?> -
-선택된 국가에 피장파장을 발동합니다.
-선포, 전쟁중인 상대국에만 가능합니다.
-상대 국가를 목록에서 선택하세요.
-배경색은 현재 피장파장 불가능 국가는 붉은색으로 표시됩니다.
- -arg === null){ + return false; + } + //NOTE: 멸망 직전에 턴을 넣을 수 있으므로, 존재하지 않는 국가여도 argTest에서 바로 탈락시키지 않음 + if(!key_exists('destNationID', $this->arg)){ + return false; + } + $destNationID = $this->arg['destNationID']; + + if(!is_int($destNationID)){ + return false; + } + if($destNationID < 1){ + return false; + } + + $this->arg = [ + 'destNationID'=>$destNationID + ]; + return true; + } + + protected function init(){ + $general = $this->generalObj; + + $env = $this->env; + + $this->setCity(); + $this->setNation(); + + $this->minConditionConstraints=[ + ConstraintHelper::OccupiedCity(), + ConstraintHelper::BeChief(), + ]; + } + + protected function initWithArg() + { + $this->setDestNation($this->arg['destNationID'], null); + + $this->fullConditionConstraints=[ + ConstraintHelper::OccupiedCity(), + ConstraintHelper::BeChief(), + ConstraintHelper::ExistsDestNation(), + ConstraintHelper::AllowDiplomacyBetweenStatus( + [0, 1], + '선포, 전쟁중인 상대국에게만 가능합니다.' + ), + ]; + } + + public function getCommandDetailTitle():string{ + $name = $this->getName(); + $reqTurn = $this->getPreReqTurn()+1; + $postReqTurn = $this->getPostReqTurn(); + + return "{$name}/{$reqTurn}턴"; + } + + public function getCost():array{ + return [0, 0]; + } + + public function getPreReqTurn():int{ + return 1; + } + + public function getPostReqTurn():int{ + return 0; + } + + public function getBrief():string{ + $commandName = $this->getName(); + $destNationName = getNationStaticInfo($this->arg['destNationID'])['name']; + return "【{$destNationName}】에 {$commandName}"; + } + + + public function run():bool{ + if(!$this->hasFullConditionMet()){ + throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); + } + + $db = DB::db(); + $env = $this->env; + + $general = $this->generalObj; + $generalID = $general->getID(); + $generalName = $general->getName(); + $date = $general->getTurnTime($general::TURNTIME_HM); + + $year = $this->env['year']; + $month = $this->env['month']; + + $nation = $this->nation; + $nationID = $nation['nation']; + $nationName = $nation['name']; + + $destNation = $this->destNation; + $destNationID = $destNation['nation']; + $destNationName = $destNation['name']; + + $josaYi = JosaUtil::pick($generalName, '이'); + $josaYiNation = JosaUtil::pick($nationName, '이'); + + $commandName = $this->getName(); + $josaUl = JosaUtil::pick($commandName, '을'); + + $logger = $general->getLogger(); + $logger->pushGeneralActionLog("{$commandName} 발동! <1>$date"); + + $general->addExperience(5 * ($this->getPreReqTurn() + 1)); + $general->addDedication(5 * ($this->getPreReqTurn() + 1)); + + $broadcastMessage = "{$generalName}{$josaYi} {$destNationName}{$commandName}{$josaUl} 발동하였습니다."; + + $nationGeneralList = $db->queryFirstColumn('SELECT no FROM general WHERE nation=%i AND no != %i', $nationID, $generalID); + foreach($nationGeneralList as $nationGeneralID){ + $nationGeneralLogger = new ActionLogger($nationGeneralID, $nationID, $year, $month); + $nationGeneralLogger->pushGeneralActionLog($broadcastMessage, ActionLogger::PLAIN); + $nationGeneralLogger->flush(); + } + + $josaYiCommand = JosaUtil::pick($commandName, '이'); + + $broadcastMessage = "아국에 {$commandName}{$josaYiCommand} 발동되었습니다."; + + $destNationGeneralList = $db->queryFirstColumn('SELECT no FROM general WHERE nation=%i AND no != %i', $nationID, $generalID); + foreach($destNationGeneralList as $destNationGeneralID){ + $destNationGeneralLogger = new ActionLogger($destNationGeneralID, $destNationID, $year, $month); + $destNationGeneralLogger->pushGeneralActionLog($broadcastMessage, ActionLogger::PLAIN); + $destNationGeneralLogger->flush(); + } + + $destNationLogger = new ActionLogger(0, $destNationID, $year, $month); + $destNationLogger->pushNationalHistoryLog("{$nationName}{$generalName}{$josaYi} 아국에 {$commandName}{$josaUl} 발동"); + $destNationLogger->flush(); + + $logger->pushNationalHistoryLog("{$generalName}{$josaYi} {$destNationName}{$commandName}{$josaUl} 발동"); + + + + $general->applyDB($db); + + return true; + } + + public function getJSFiles(): array + { + return [ + 'js/defaultSelectNationByMap.js' + ]; + } + + public function getForm(): string + { + $generalObj = $this->generalObj; + $nationID = $generalObj->getNationID(); + $nationList = []; + $testTurn = new LastTurn($this->getName(), null, $this->getPreReqTurn()); + foreach(getAllNationStaticInfo() as $destNation){ + if($destNation['nation'] == $nationID){ + continue; + } + + $testTurn->setArg(['destNationID'=>$destNation['nation']]); + $testCommand = new static($generalObj, $this->env, $testTurn, ['destNationID'=>$destNation['nation']]); + if($testCommand->hasFullConditionMet()){ + $destNation['availableCommand'] = true; + } + else{ + $destNation['availableCommand'] = false; + } + + $nationList[] = $destNation; + } + + $availableCommandTypeList = []; + $currYearMonth = Util::joinYearMonth($this->env['year'], $this->env['month']); + foreach(GameConst::$availableChiefCommand['전략'] as $commandType){ + $cmd = buildNationCommandClass($commandType, $generalObj, $this->env, new LastTurn()); + if($cmd->getName() == $this->getName()){ + continue; + } + $cmdName = $cmd->getName(); + $available = true; + $nextAvailable = $cmd->getNextAvailable(); + + if($nextAvailable !== null && $currYearMonth < $cmd->getNextAvailable() - $cmd->getPreReqTurn()){ + $available = false; + } + $availableCommandTypeList[$commandType] = [$cmdName, $available]; + } + + ob_start(); +?> +
+선택된 국가에 피장파장을 발동합니다.
+지정한 전략을 상대국이 턴 동안 사용할 수 없게됩니다.
+선포, 전쟁중인 상대국에만 가능합니다.
+상대 국가를 목록에서 선택하세요.
+배경색은 현재 피장파장 불가능 국가는 붉은색으로 표시됩니다.
+ +[$cmdName, $cmdAvailable]): + /** @var \sammo\Command\NationCommand $cmdObj */ +?> + + + + +arg = []; - - return true; - } - - protected function init(){ - $general = $this->generalObj; - - $env = $this->env; - - $this->setCity(); - $this->setNation(['strategic_cmd_limit']); - - $this->fullConditionConstraints=[ - ConstraintHelper::OccupiedCity(), - ConstraintHelper::BeChief(), - ConstraintHelper::AllowDiplomacyStatus($this->generalObj->getNationID(), [ - 0 - ], '전쟁중이 아닙니다.'), - ConstraintHelper::AvailableStrategicCommand() - ]; - } - - public function getCommandDetailTitle():string{ - $name = $this->getName(); - $reqTurn = $this->getPreReqTurn()+1; - $postReqTurn = $this->getPostReqTurn(); - - return "{$name}/{$reqTurn}턴(전략$postReqTurn)"; - } - - public function getCost():array{ - return [0, 0]; - } - - public function getPreReqTurn():int{ - return 2; - } - - public function getPostReqTurn():int{ - $genCount = Util::valueFit($this->nation['gennum'], GameConst::$initialNationGenLimit); - $nextTerm = Util::round(sqrt($genCount*8)*10); - - $nextTerm = $this->generalObj->onCalcStrategic($this->getName(), 'delay', $nextTerm); - return $nextTerm; - } - - public function run():bool{ - if(!$this->hasFullConditionMet()){ - throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); - } - - $db = DB::db(); - - $general = $this->generalObj; - $generalID = $general->getID(); - $generalName = $general->getName(); - $date = $general->getTurnTime($general::TURNTIME_HM); - - $nationID = $general->getNationID(); - $nationName = $this->nation['name']; - - $logger = $general->getLogger(); - $logger->pushGeneralActionLog("필사즉생 발동! <1>$date"); - - $general->addExperience(5 * ($this->getPreReqTurn() + 1)); - $general->addDedication(5 * ($this->getPreReqTurn() + 1)); - - $josaYi = JosaUtil::pick($generalName, '이'); - - $broadcastMessage = "{$generalName}{$josaYi} 필사즉생을 발동하였습니다."; - - $targetGeneralList = $db->queryFirstColumn('SELECT no FROM general WHERE nation=%i AND no != %i', $nationID, $generalID); - foreach(General::createGeneralObjListFromDB($targetGeneralList, ['train', 'atmos'], 1) as $targetGeneral){ - $targetGeneral->getLogger()->pushGeneralActionLog($broadcastMessage, ActionLogger::PLAIN); - if($targetGeneral->getVar('train') < 100){ - $targetGeneral->setVar('train', 100); - } - if($targetGeneral->getVar('atmos') < 100){ - $targetGeneral->setVar('atmos', 100); - } - - $targetGeneral->applyDB($db); - } - - if($general->getVar('train') < 100){ - $general->setVar('train', 100); - } - if($general->getVar('atmos') < 100){ - $general->setVar('atmos', 100); - } - $logger->pushGeneralHistoryLog('필사즉생을 발동'); - $logger->pushNationalHistoryLog("{$generalName}{$josaYi} 필사즉생을 발동"); - - $db->update('nation', [ - 'strategic_cmd_limit' => $this->getPostReqTurn() - ], 'nation=%i', $nationID); - - $this->setResultTurn(new LastTurn($this->getName(), $this->arg, 0)); - $general->applyDB($db); - - return true; - } +arg = []; + + return true; + } + + protected function init(){ + $general = $this->generalObj; + + $env = $this->env; + + $this->setCity(); + $this->setNation(['strategic_cmd_limit']); + + $this->fullConditionConstraints=[ + ConstraintHelper::OccupiedCity(), + ConstraintHelper::BeChief(), + ConstraintHelper::AllowDiplomacyStatus($this->generalObj->getNationID(), [ + 0 + ], '전쟁중이 아닙니다.'), + ConstraintHelper::AvailableStrategicCommand($this->getPreReqTurn()) + ]; + } + + public function getCommandDetailTitle():string{ + $name = $this->getName(); + $reqTurn = $this->getPreReqTurn()+1; + $postReqTurn = $this->getPostReqTurn(); + + return "{$name}/{$reqTurn}턴(전략$postReqTurn)"; + } + + public function getCost():array{ + return [0, 0]; + } + + public function getPreReqTurn():int{ + return 2; + } + + public function getPostReqTurn():int{ + $genCount = Util::valueFit($this->nation['gennum'], GameConst::$initialNationGenLimit); + $nextTerm = Util::round(sqrt($genCount*8)*10); + + $nextTerm = $this->generalObj->onCalcStrategic($this->getName(), 'delay', $nextTerm); + return $nextTerm; + } + + public function run():bool{ + if(!$this->hasFullConditionMet()){ + throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); + } + + $db = DB::db(); + + $general = $this->generalObj; + $generalID = $general->getID(); + $generalName = $general->getName(); + $date = $general->getTurnTime($general::TURNTIME_HM); + + $nationID = $general->getNationID(); + $nationName = $this->nation['name']; + + $logger = $general->getLogger(); + $logger->pushGeneralActionLog("필사즉생 발동! <1>$date"); + + $general->addExperience(5 * ($this->getPreReqTurn() + 1)); + $general->addDedication(5 * ($this->getPreReqTurn() + 1)); + + $josaYi = JosaUtil::pick($generalName, '이'); + + $broadcastMessage = "{$generalName}{$josaYi} 필사즉생을 발동하였습니다."; + + $targetGeneralList = $db->queryFirstColumn('SELECT no FROM general WHERE nation=%i AND no != %i', $nationID, $generalID); + foreach(General::createGeneralObjListFromDB($targetGeneralList, ['train', 'atmos'], 1) as $targetGeneral){ + $targetGeneral->getLogger()->pushGeneralActionLog($broadcastMessage, ActionLogger::PLAIN); + if($targetGeneral->getVar('train') < 100){ + $targetGeneral->setVar('train', 100); + } + if($targetGeneral->getVar('atmos') < 100){ + $targetGeneral->setVar('atmos', 100); + } + + $targetGeneral->applyDB($db); + } + + if($general->getVar('train') < 100){ + $general->setVar('train', 100); + } + if($general->getVar('atmos') < 100){ + $general->setVar('atmos', 100); + } + $logger->pushGeneralHistoryLog('필사즉생을 발동'); + $logger->pushNationalHistoryLog("{$generalName}{$josaYi} 필사즉생을 발동"); + + $db->update('nation', [ + 'strategic_cmd_limit' => $this->getPostReqTurn() + ], 'nation=%i', $nationID); + + $this->setResultTurn(new LastTurn($this->getName(), $this->arg, 0)); + $general->applyDB($db); + + return true; + } } \ No newline at end of file diff --git a/hwe/sammo/Command/Nation/che_허보.php b/hwe/sammo/Command/Nation/che_허보.php index e3cce769..f219c9d3 100644 --- a/hwe/sammo/Command/Nation/che_허보.php +++ b/hwe/sammo/Command/Nation/che_허보.php @@ -1,239 +1,239 @@ -arg === null) { - return false; - } - if (!key_exists('destCityID', $this->arg)) { - return false; - } - if (CityConst::byID($this->arg['destCityID']) === null) { - return false; - } - $destCityID = $this->arg['destCityID']; - - $this->arg = [ - 'destCityID' => $destCityID, - ]; - - return true; - } - - protected function init() - { - $general = $this->generalObj; - - $env = $this->env; - - $this->setCity(); - $this->setNation(['strategic_cmd_limit']); - - $this->minConditionConstraints = [ - ConstraintHelper::OccupiedCity(), - ConstraintHelper::BeChief(), - ConstraintHelper::AvailableStrategicCommand(), - ]; - } - - protected function initWithArg() - { - $this->setDestCity($this->arg['destCityID']); - $this->setDestNation($this->destCity['nation']); - - $this->fullConditionConstraints = [ - ConstraintHelper::OccupiedCity(), - ConstraintHelper::BeChief(), - ConstraintHelper::NotNeutralDestCity(), - ConstraintHelper::NotOccupiedDestCity(), - ConstraintHelper::AllowDiplomacyBetweenStatus( - [0, 1], - '선포, 전쟁중인 상대국에게만 가능합니다.' - ), - ConstraintHelper::AvailableStrategicCommand(), - ]; - } - - public function getCommandDetailTitle(): string - { - $name = $this->getName(); - $reqTurn = $this->getPreReqTurn() + 1; - $postReqTurn = $this->getPostReqTurn(); - - return "{$name}/{$reqTurn}턴(전략$postReqTurn)"; - } - - public function getCost(): array - { - return [0, 0]; - } - - public function getPreReqTurn(): int - { - return 1; - } - - public function getPostReqTurn(): int - { - $genCount = Util::valueFit($this->nation['gennum'], GameConst::$initialNationGenLimit); - $nextTerm = Util::round(sqrt($genCount * 4) * 10); - - $nextTerm = $this->generalObj->onCalcStrategic($this->getName(), 'delay', $nextTerm); - return $nextTerm; - } - - public function getBrief(): string - { - $commandName = $this->getName(); - $destCityName = CityConst::byID($this->arg['destCityID'])->name; - return "【{$destCityName}】에 {$commandName}"; - } - - public function run(): bool - { - if (!$this->hasFullConditionMet()) { - throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); - } - - $db = DB::db(); - - $general = $this->generalObj; - $generalID = $general->getID(); - $generalName = $general->getName(); - $date = $general->getTurnTime($general::TURNTIME_HM); - - $year = $this->env['year']; - $month = $this->env['month']; - - $destCity = $this->destCity; - $destCityID = $destCity['city']; - $destCityName = $destCity['name']; - - $destNationID = $destCity['nation']; - $destNationName = getNationStaticInfo($destNationID)['name']; - - $nationID = $general->getNationID(); - $nationName = $this->nation['name']; - - $logger = $general->getLogger(); - $logger->pushGeneralActionLog("허보 발동! <1>$date"); - - $general->addExperience(5 * ($this->getPreReqTurn() + 1)); - $general->addDedication(5 * ($this->getPreReqTurn() + 1)); - - $josaYi = JosaUtil::pick($generalName, '이'); - - $broadcastMessage = "{$generalName}{$josaYi} {$destCityName}허보를 발동하였습니다."; - - $targetGeneralList = $db->queryFirstColumn('SELECT no FROM general WHERE nation=%i AND no != %i', $nationID, $generalID); - foreach ($targetGeneralList as $targetGeneralID) { - $targetLogger = new ActionLogger($targetGeneralID, $nationID, $year, $month); - $targetLogger->pushGeneralActionLog($broadcastMessage, ActionLogger::PLAIN); - $targetLogger->flush(); - } - - $destBroadcastMessage = "상대의 허보에 당했다! <1>$date"; - $destNationCityList = $db->queryFirstColumn('SELECT city FROM city WHERE nation = %i AND supply = 1', $destNationID); - - $targetGeneralList = $db->queryFirstColumn('SELECT no FROM general WHERE nation=%i AND city=%i', $destNationID, $destCityID); - foreach (General::createGeneralObjListFromDB($targetGeneralList) as $targetGeneralID => $targetGeneral) { - $targetLogger = $targetGeneral->getLogger(); - $targetLogger->pushGeneralActionLog($destBroadcastMessage, ActionLogger::PLAIN); - - $moveCityID = Util::choiceRandom($destNationCityList); - if ($moveCityID == $destCityID) { - //현재도시면 다시 랜덤 추첨 - $moveCityID = Util::choiceRandom($destNationCityList); - } - - $targetGeneral->setVar('city', $moveCityID); - $targetGeneral->applyDB($db); - } - - $destNationLogger = new ActionLogger(0, $destNationID, $year, $month); - $destNationLogger->pushNationalHistoryLog( - "{$nationName}{$generalName}{$josaYi} 아국의 {$destCityName}허보를 발동", - ActionLogger::PLAIN - ); - $destNationLogger->flush(); - - - $db->update('city', [ - 'def' => $db->sqleval('def * 0.2'), - 'wall' => $db->sqleval('wall * 0.2'), - ], 'city=%i', $destCityID); - - $josaYiNation = JosaUtil::pick($nationName, '이'); - - $logger->pushGeneralHistoryLog("{$destCityName}허보를 발동"); - $logger->pushNationalHistoryLog("{$generalName}{$josaYi} {$destCityName}허보를 발동"); - - $db->update('nation', [ - 'strategic_cmd_limit' => $this->getPostReqTurn() - ], 'nation=%i', $nationID); - - $this->setResultTurn(new LastTurn($this->getName(), $this->arg, 0)); - $general->applyDB($db); - - return true; - } - - public function getJSFiles(): array - { - return [ - 'js/defaultSelectCityByMap.js' - ]; - } - - - public function getForm(): string - { - ob_start(); -?> -
- 선택된 도시에 허보를 발동합니다.
- 전쟁중인 상대국 도시만 가능합니다.
- 목록을 선택하거나 도시를 클릭하세요.
-
-
-arg === null) { + return false; + } + if (!key_exists('destCityID', $this->arg)) { + return false; + } + if (CityConst::byID($this->arg['destCityID']) === null) { + return false; + } + $destCityID = $this->arg['destCityID']; + + $this->arg = [ + 'destCityID' => $destCityID, + ]; + + return true; + } + + protected function init() + { + $general = $this->generalObj; + + $env = $this->env; + + $this->setCity(); + $this->setNation(['strategic_cmd_limit']); + + $this->minConditionConstraints = [ + ConstraintHelper::OccupiedCity(), + ConstraintHelper::BeChief(), + ConstraintHelper::AvailableStrategicCommand($this->getPreReqTurn()), + ]; + } + + protected function initWithArg() + { + $this->setDestCity($this->arg['destCityID']); + $this->setDestNation($this->destCity['nation']); + + $this->fullConditionConstraints = [ + ConstraintHelper::OccupiedCity(), + ConstraintHelper::BeChief(), + ConstraintHelper::NotNeutralDestCity(), + ConstraintHelper::NotOccupiedDestCity(), + ConstraintHelper::AllowDiplomacyBetweenStatus( + [0, 1], + '선포, 전쟁중인 상대국에게만 가능합니다.' + ), + ConstraintHelper::AvailableStrategicCommand($this->getPreReqTurn()), + ]; + } + + public function getCommandDetailTitle(): string + { + $name = $this->getName(); + $reqTurn = $this->getPreReqTurn() + 1; + $postReqTurn = $this->getPostReqTurn(); + + return "{$name}/{$reqTurn}턴(전략$postReqTurn)"; + } + + public function getCost(): array + { + return [0, 0]; + } + + public function getPreReqTurn(): int + { + return 1; + } + + public function getPostReqTurn(): int + { + $genCount = Util::valueFit($this->nation['gennum'], GameConst::$initialNationGenLimit); + $nextTerm = Util::round(sqrt($genCount * 4) * 10); + + $nextTerm = $this->generalObj->onCalcStrategic($this->getName(), 'delay', $nextTerm); + return $nextTerm; + } + + public function getBrief(): string + { + $commandName = $this->getName(); + $destCityName = CityConst::byID($this->arg['destCityID'])->name; + return "【{$destCityName}】에 {$commandName}"; + } + + public function run(): bool + { + if (!$this->hasFullConditionMet()) { + throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); + } + + $db = DB::db(); + + $general = $this->generalObj; + $generalID = $general->getID(); + $generalName = $general->getName(); + $date = $general->getTurnTime($general::TURNTIME_HM); + + $year = $this->env['year']; + $month = $this->env['month']; + + $destCity = $this->destCity; + $destCityID = $destCity['city']; + $destCityName = $destCity['name']; + + $destNationID = $destCity['nation']; + $destNationName = getNationStaticInfo($destNationID)['name']; + + $nationID = $general->getNationID(); + $nationName = $this->nation['name']; + + $logger = $general->getLogger(); + $logger->pushGeneralActionLog("허보 발동! <1>$date"); + + $general->addExperience(5 * ($this->getPreReqTurn() + 1)); + $general->addDedication(5 * ($this->getPreReqTurn() + 1)); + + $josaYi = JosaUtil::pick($generalName, '이'); + + $broadcastMessage = "{$generalName}{$josaYi} {$destCityName}허보를 발동하였습니다."; + + $targetGeneralList = $db->queryFirstColumn('SELECT no FROM general WHERE nation=%i AND no != %i', $nationID, $generalID); + foreach ($targetGeneralList as $targetGeneralID) { + $targetLogger = new ActionLogger($targetGeneralID, $nationID, $year, $month); + $targetLogger->pushGeneralActionLog($broadcastMessage, ActionLogger::PLAIN); + $targetLogger->flush(); + } + + $destBroadcastMessage = "상대의 허보에 당했다! <1>$date"; + $destNationCityList = $db->queryFirstColumn('SELECT city FROM city WHERE nation = %i AND supply = 1', $destNationID); + + $targetGeneralList = $db->queryFirstColumn('SELECT no FROM general WHERE nation=%i AND city=%i', $destNationID, $destCityID); + foreach (General::createGeneralObjListFromDB($targetGeneralList) as $targetGeneralID => $targetGeneral) { + $targetLogger = $targetGeneral->getLogger(); + $targetLogger->pushGeneralActionLog($destBroadcastMessage, ActionLogger::PLAIN); + + $moveCityID = Util::choiceRandom($destNationCityList); + if ($moveCityID == $destCityID) { + //현재도시면 다시 랜덤 추첨 + $moveCityID = Util::choiceRandom($destNationCityList); + } + + $targetGeneral->setVar('city', $moveCityID); + $targetGeneral->applyDB($db); + } + + $destNationLogger = new ActionLogger(0, $destNationID, $year, $month); + $destNationLogger->pushNationalHistoryLog( + "{$nationName}{$generalName}{$josaYi} 아국의 {$destCityName}허보를 발동", + ActionLogger::PLAIN + ); + $destNationLogger->flush(); + + + $db->update('city', [ + 'def' => $db->sqleval('def * 0.2'), + 'wall' => $db->sqleval('wall * 0.2'), + ], 'city=%i', $destCityID); + + $josaYiNation = JosaUtil::pick($nationName, '이'); + + $logger->pushGeneralHistoryLog("{$destCityName}허보를 발동"); + $logger->pushNationalHistoryLog("{$generalName}{$josaYi} {$destCityName}허보를 발동"); + + $db->update('nation', [ + 'strategic_cmd_limit' => $this->getPostReqTurn() + ], 'nation=%i', $nationID); + + $this->setResultTurn(new LastTurn($this->getName(), $this->arg, 0)); + $general->applyDB($db); + + return true; + } + + public function getJSFiles(): array + { + return [ + 'js/defaultSelectCityByMap.js' + ]; + } + + + public function getForm(): string + { + ob_start(); +?> +
+ 선택된 도시에 허보를 발동합니다.
+ 전쟁중인 상대국 도시만 가능합니다.
+ 목록을 선택하거나 도시를 클릭하세요.
+
+
+lastTurn = $lastTurn; - $this->resultTurn = $lastTurn->duplicate(); - parent::__construct($generalObj, $env, $arg); - } - - public function getLastTurn():LastTurn{ - return $this->lastTurn; - } - - public function setResultTurn(LastTurn $lastTurn){ - $this->resultTurn = $lastTurn; - } - - public function getResultTurn():LastTurn{ - return $this->resultTurn; - } - - - +lastTurn = $lastTurn; + $this->resultTurn = $lastTurn->duplicate(); + parent::__construct($generalObj, $env, $arg); + } + + public function getLastTurn():LastTurn{ + return $this->lastTurn; + } + + public function setResultTurn(LastTurn $lastTurn){ + $this->resultTurn = $lastTurn; + } + + public function getResultTurn():LastTurn{ + return $this->resultTurn; + } + + protected function getNextExecuteKey():string{ + $turnKey = static::$actionName; + $executeKey = "next_execute_{$turnKey}"; + return $executeKey; + } + + public function getNextAvailable():?int{ + if($this->isArgValid && !$this->getPostReqTurn()){ + return null; + } + $db = \sammo\DB::db(); + $nationStor = \sammo\KVStorage::getStorage($db, $this->getNationID(), 'nation_env'); + return $nationStor->getValue($this->getNextExecuteKey()); + } + + public function setNextAvailable(?int $yearMonth=null){ + if(!$this->getPostReqTurn()){ + return; + } + if($yearMonth === null){ + $yearMonth = Util::joinYearMonth($this->env['year'], $this->env['month']) + $this->getPostReqTurn(); + } + + $db = \sammo\DB::db(); + $nationStor = \sammo\KVStorage::getStorage($db, $this->getNationID(), 'nation_env'); + $nationStor->setValue($this->getNextExecuteKey(), $yearMonth); + } + }; \ No newline at end of file diff --git a/hwe/sammo/Constraint/AvailableStrategicCommand.php b/hwe/sammo/Constraint/AvailableStrategicCommand.php index f0c33eb9..2095f735 100644 --- a/hwe/sammo/Constraint/AvailableStrategicCommand.php +++ b/hwe/sammo/Constraint/AvailableStrategicCommand.php @@ -1,32 +1,32 @@ -nation)){ - if(!$throwExeception){return false; } - throw new \InvalidArgumentException("require strategic_cmd_limit in nation"); - } - - return true; - } - - public function test():bool{ - $this->checkInputValues(); - $this->tested = true; - - if($this->nation['strategic_cmd_limit'] == 0){ - return true; - } - - $this->reason = "전략기한이 남았습니다."; - return false; - } +nation)){ + if(!$throwExeception){return false; } + throw new \InvalidArgumentException("require strategic_cmd_limit in nation"); + } + + return true; + } + + public function test():bool{ + $this->checkInputValues(); + $this->tested = true; + + if($this->nation['strategic_cmd_limit'] <= $this->arg){ + return true; + } + + $this->reason = "전략기한이 남았습니다."; + return false; + } } \ No newline at end of file diff --git a/hwe/sammo/Constraint/ConstraintHelper.php b/hwe/sammo/Constraint/ConstraintHelper.php index 82e7e16f..b3842a88 100644 --- a/hwe/sammo/Constraint/ConstraintHelper.php +++ b/hwe/sammo/Constraint/ConstraintHelper.php @@ -1,274 +1,274 @@ -diplomaticType = Util::array_get($msgOption['action']); - switch($this->diplomaticType){ - case self::TYPE_NO_AGGRESSION: $this->diplomacyName = '불가침'; break; - case self::TYPE_CANCEL_NA: $this->diplomacyName = '불가침 파기'; break; - case self::TYPE_STOP_WAR: $this->diplomacyName = '종전'; break; - default: throw new \RuntimeException('diplomaticType이 올바르지 않음'); - } - - parent::__construct(...func_get_args()); - - - if(Util::array_get($msgOption['used'])){ - $this->validDiplomacy = false; - } - - if($this->validUntil < (new \DateTime())){ - $this->validDiplomacy = false; - } - } - - protected function checkDiplomaticMessageValidation(array $general){ - if(!$this->validDiplomacy){ - return [self::INVALID, '유효하지 않은 외교서신입니다.']; - } - - if($this->mailbox !== $this->dest->nationID + static::MAILBOX_NATIONAL){ - return [self::INVALID, '송신자가 외교서신을 처리할 수 없습니다.']; - } - - $permission = checkSecretPermission($general, false); - - if(!$general || $permission < 4){ - return [self::INVALID, '해당 국가의 외교권자가 아닙니다.']; - } - - return [self::ACCEPTED, '']; - } - - protected function noAggression(){ - - $gameStor = KVStorage::getStorage(DB::db(), 'game_env'); - - $destGeneralObj = General::createGeneralObjFromDB($this->dest->generalID, ['picture', 'imgsvr', 'aux'], 1); - - $commandObj = buildNationCommandClass('che_불가침수락', $destGeneralObj, $gameStor->getAll(true), new LastTurn(), [ - 'destNationID'=>$this->src->nationID, - 'destGeneralID'=>$this->src->generalID, - 'year'=>$this->msgOption['year'], - 'month'=>$this->msgOption['month'] - ]); - - $this->diplomacyDetail = $commandObj->getBrief(); - - if(!$commandObj->hasFullConditionMet()){ - return [self::DECLINED, $commandObj->getFailString()]; - } - - $commandObj->run(); - - return [self::ACCEPTED, '']; - } - - protected function cancelNA(){ - $gameStor = KVStorage::getStorage(DB::db(), 'game_env'); - - $destGeneralObj = General::createGeneralObjFromDB($this->dest->generalID, ['picture', 'imgsvr', 'aux'], 1); - - $commandObj = buildNationCommandClass('che_불가침파기수락', $destGeneralObj, $gameStor->getAll(true), new LastTurn(), [ - 'destNationID'=>$this->src->nationID, - 'destGeneralID'=>$this->src->generalID, - ]); - - $this->diplomacyDetail = $commandObj->getBrief(); - - if(!$commandObj->hasFullConditionMet()){ - return [self::DECLINED, $commandObj->getFailString()]; - } - - $commandObj->run(); - - return [self::ACCEPTED, '']; - } - - protected function stopWar(){ - $gameStor = KVStorage::getStorage(DB::db(), 'game_env'); - - $destGeneralObj = General::createGeneralObjFromDB($this->dest->generalID, ['picture', 'imgsvr', 'aux'], 1); - - $commandObj = buildNationCommandClass('che_종전수락', $destGeneralObj, $gameStor->getAll(true), new LastTurn(), [ - 'destNationID'=>$this->src->nationID, - 'destGeneralID'=>$this->src->generalID, - ]); - - $this->diplomacyDetail = $commandObj->getBrief(); - - if(!$commandObj->hasFullConditionMet()){ - return [self::DECLINED, $commandObj->getFailString()]; - } - - $commandObj->run(); - - return [self::ACCEPTED, '']; - } - - /** - * @return int 수행 결과 반환, ACCEPTED(등용장 소모), DECLINED(등용장 소모), INVALID 중 반환 - */ - public function agreeMessage(int $receiverID, string &$reason):int{ - //NOTE: 올바른 유저가 agreeMessage() 호출을 한건지는 외부에서 체크 필요(Session->userID 등) - - if(!$this->id){ - throw new \RuntimeException('전송되지 않은 메시지에 수락 진행 중'); - } - - - - $db = DB::db(); - $gameStor = KVStorage::getStorage($db, 'game_env'); - [$year, $month] = $gameStor->getValuesAsArray(['year', 'month']); - - - $general = $db->queryFirstRow( - 'SELECT `name`, nation, `officer_level`, `permission`, `penalty`,belong FROM general WHERE `no`=%i AND nation=%i', - $receiverID, - $this->dest->nationID - ); - - if($general){ - $this->dest->generalID = $receiverID; - $this->dest->generalName = $general['name']; - } - - - list($result, $reason) = $this->checkDiplomaticMessageValidation($general); - if($result !== self::ACCEPTED){ - (new ActionLogger($receiverID, 0, $year, $month))->pushGeneralActionLog("{$reason} {$this->diplomacyName} 실패", ActionLogger::PLAIN); - if($result === self::DECLINED){ - $this->_declineMessage(); - } - return $result; - } - - switch($this->diplomaticType){ - case self::TYPE_NO_AGGRESSION: - list($result, $reason) = $this->noAggression(); - break; - case self::TYPE_CANCEL_NA: - list($result, $reason) = $this->cancelNA(); - break; - case self::TYPE_STOP_WAR: - list($result, $reason) = $this->stopWar(); - break; - default: - throw new \RuntimeException('diplomaticType이 올바르지 않음'); - } - - if($result !== self::ACCEPTED){ - (new ActionLogger($receiverID, 0, $year, $month))->pushGeneralActionLog($reason, ActionLogger::PLAIN); - if($result === self::DECLINED){ - $this->_declineMessage(); - } - return $result; - } - - - - - $this->dest->generalID = $receiverID; - $this->dest->generalName = $general['name']; - $this->msgOption['used'] = true; - $this->validDiplomacy = false; - - $josaYi = JosaUtil::pick($this->src->nationName, '이'); - $newMsg = new Message( - self::MSGTYPE_NATIONAL, - $this->dest, - $this->src, - "【외교】{$year}년 {$month}월: {$this->src->nationName}{$josaYi} {$this->dest->nationName}에게 제안한 {$this->diplomacyDetail}", - new \DateTime(), - new \DateTime('9999-12-31'), - [ - 'delete'=>$this->id, - 'silence'=>true, - 'deletable' => false - ] - ); - $this->invalidate(); - $newMsg->send(); - - $newMsg = new Message( - self::MSGTYPE_DIPLOMACY, - $this->dest, - $this->src, - "【외교】{$year}년 {$month}월: {$this->src->nationName}{$josaYi} {$this->dest->nationName}에게 제안한 {$this->diplomacyDetail}", - new \DateTime(), - new \DateTime('9999-12-31'), - [ - 'delete'=>$this->id, - 'silence'=>true, - 'deletable' => false - ] - ); - $newMsg->send(); - - return self::ACCEPTED; - - } - - protected function _declineMessage(){ - $this->msgOption['used'] = true; - $this->invalidate(); - $this->validDiplomacy = false; - - return self::DECLINED; - } - - public function declineMessage(int $receiverID, string &$reason):int{ - if(!$this->id){ - throw new \RuntimeException('전송되지 않은 메시지에 거절 진행 중'); - } - - $db = DB::db(); - $gameStor = KVStorage::getStorage($db, 'game_env'); - [$year, $month] = $gameStor->getValuesAsArray(['year', 'month']); - - $general = $db->queryFirstRow( - 'SELECT `name`, nation, `officer_level`, `permission`, `penalty`,belong FROM general WHERE `no`=%i AND nation=%i', - $receiverID, - $this->dest->nationID - ); - list($result, $reason) = $this->checkDiplomaticMessageValidation($general); - - if($result === self::INVALID){ - (new ActionLogger($receiverID, 0, $year, $month))->pushGeneralActionLog("{$reason} {$this->diplomacyName} 거절 불가.", ActionLogger::PLAIN); - return $result; - } - - $josaYi = JosaUtil::pick($this->dest->nationName, '이'); - (new ActionLogger($receiverID, 0, $year, $month))->pushGeneralActionLog("{$this->src->nationName}의 {$this->diplomacyName} 제안을 거절했습니다.", ActionLogger::PLAIN); - (new ActionLogger($this->src->generalID, 0, $year, $month))->pushGeneralActionLog("{$this->dest->nationName}{$josaYi} {$this->diplomacyName} 제안을 거절했습니다.", ActionLogger::PLAIN); - $this->_declineMessage(); - return self::DECLINED; - } - +diplomaticType = Util::array_get($msgOption['action']); + switch($this->diplomaticType){ + case self::TYPE_NO_AGGRESSION: $this->diplomacyName = '불가침'; break; + case self::TYPE_CANCEL_NA: $this->diplomacyName = '불가침 파기'; break; + case self::TYPE_STOP_WAR: $this->diplomacyName = '종전'; break; + default: throw new \RuntimeException('diplomaticType이 올바르지 않음'); + } + + parent::__construct(...func_get_args()); + + + if(Util::array_get($msgOption['used'])){ + $this->validDiplomacy = false; + } + + if($this->validUntil < (new \DateTime())){ + $this->validDiplomacy = false; + } + } + + protected function checkDiplomaticMessageValidation(array $general){ + if(!$this->validDiplomacy){ + return [self::INVALID, '유효하지 않은 외교서신입니다.']; + } + + if($this->mailbox !== $this->dest->nationID + static::MAILBOX_NATIONAL){ + return [self::INVALID, '송신자가 외교서신을 처리할 수 없습니다.']; + } + + $permission = checkSecretPermission($general, false); + + if(!$general || $permission < 4){ + return [self::INVALID, '해당 국가의 외교권자가 아닙니다.']; + } + + return [self::ACCEPTED, '']; + } + + protected function noAggression(){ + + $gameStor = KVStorage::getStorage(DB::db(), 'game_env'); + + $destGeneralObj = General::createGeneralObjFromDB($this->dest->generalID, ['picture', 'imgsvr', 'aux'], 1); + + $commandObj = buildNationCommandClass('che_불가침수락', $destGeneralObj, $gameStor->getAll(true), new LastTurn(), [ + 'destNationID'=>$this->src->nationID, + 'destGeneralID'=>$this->src->generalID, + 'year'=>$this->msgOption['year'], + 'month'=>$this->msgOption['month'] + ]); + + $this->diplomacyDetail = $commandObj->getBrief(); + + if(!$commandObj->hasFullConditionMet()){ + return [self::DECLINED, $commandObj->getFailString()]; + } + + $commandObj->run(); + $commandObj->setNextAvailable(); + + return [self::ACCEPTED, '']; + } + + protected function cancelNA(){ + $gameStor = KVStorage::getStorage(DB::db(), 'game_env'); + + $destGeneralObj = General::createGeneralObjFromDB($this->dest->generalID, ['picture', 'imgsvr', 'aux'], 1); + + $commandObj = buildNationCommandClass('che_불가침파기수락', $destGeneralObj, $gameStor->getAll(true), new LastTurn(), [ + 'destNationID'=>$this->src->nationID, + 'destGeneralID'=>$this->src->generalID, + ]); + + $this->diplomacyDetail = $commandObj->getBrief(); + + if(!$commandObj->hasFullConditionMet()){ + return [self::DECLINED, $commandObj->getFailString()]; + } + + $commandObj->run(); + $commandObj->setNextAvailable(); + + return [self::ACCEPTED, '']; + } + + protected function stopWar(){ + $gameStor = KVStorage::getStorage(DB::db(), 'game_env'); + + $destGeneralObj = General::createGeneralObjFromDB($this->dest->generalID, ['picture', 'imgsvr', 'aux'], 1); + + $commandObj = buildNationCommandClass('che_종전수락', $destGeneralObj, $gameStor->getAll(true), new LastTurn(), [ + 'destNationID'=>$this->src->nationID, + 'destGeneralID'=>$this->src->generalID, + ]); + + $this->diplomacyDetail = $commandObj->getBrief(); + + if(!$commandObj->hasFullConditionMet()){ + return [self::DECLINED, $commandObj->getFailString()]; + } + + $commandObj->run(); + $commandObj->setNextAvailable(); + + return [self::ACCEPTED, '']; + } + + /** + * @return int 수행 결과 반환, ACCEPTED(등용장 소모), DECLINED(등용장 소모), INVALID 중 반환 + */ + public function agreeMessage(int $receiverID, string &$reason):int{ + //NOTE: 올바른 유저가 agreeMessage() 호출을 한건지는 외부에서 체크 필요(Session->userID 등) + + if(!$this->id){ + throw new \RuntimeException('전송되지 않은 메시지에 수락 진행 중'); + } + + + + $db = DB::db(); + $gameStor = KVStorage::getStorage($db, 'game_env'); + [$year, $month] = $gameStor->getValuesAsArray(['year', 'month']); + + + $general = $db->queryFirstRow( + 'SELECT `name`, nation, `officer_level`, `permission`, `penalty`,belong FROM general WHERE `no`=%i AND nation=%i', + $receiverID, + $this->dest->nationID + ); + + if($general){ + $this->dest->generalID = $receiverID; + $this->dest->generalName = $general['name']; + } + + + list($result, $reason) = $this->checkDiplomaticMessageValidation($general); + if($result !== self::ACCEPTED){ + (new ActionLogger($receiverID, 0, $year, $month))->pushGeneralActionLog("{$reason} {$this->diplomacyName} 실패", ActionLogger::PLAIN); + if($result === self::DECLINED){ + $this->_declineMessage(); + } + return $result; + } + + switch($this->diplomaticType){ + case self::TYPE_NO_AGGRESSION: + list($result, $reason) = $this->noAggression(); + break; + case self::TYPE_CANCEL_NA: + list($result, $reason) = $this->cancelNA(); + break; + case self::TYPE_STOP_WAR: + list($result, $reason) = $this->stopWar(); + break; + default: + throw new \RuntimeException('diplomaticType이 올바르지 않음'); + } + + if($result !== self::ACCEPTED){ + (new ActionLogger($receiverID, 0, $year, $month))->pushGeneralActionLog($reason, ActionLogger::PLAIN); + if($result === self::DECLINED){ + $this->_declineMessage(); + } + return $result; + } + + + + + $this->dest->generalID = $receiverID; + $this->dest->generalName = $general['name']; + $this->msgOption['used'] = true; + $this->validDiplomacy = false; + + $josaYi = JosaUtil::pick($this->src->nationName, '이'); + $newMsg = new Message( + self::MSGTYPE_NATIONAL, + $this->dest, + $this->src, + "【외교】{$year}년 {$month}월: {$this->src->nationName}{$josaYi} {$this->dest->nationName}에게 제안한 {$this->diplomacyDetail}", + new \DateTime(), + new \DateTime('9999-12-31'), + [ + 'delete'=>$this->id, + 'silence'=>true, + 'deletable' => false + ] + ); + $this->invalidate(); + $newMsg->send(); + + $newMsg = new Message( + self::MSGTYPE_DIPLOMACY, + $this->dest, + $this->src, + "【외교】{$year}년 {$month}월: {$this->src->nationName}{$josaYi} {$this->dest->nationName}에게 제안한 {$this->diplomacyDetail}", + new \DateTime(), + new \DateTime('9999-12-31'), + [ + 'delete'=>$this->id, + 'silence'=>true, + 'deletable' => false + ] + ); + $newMsg->send(); + + return self::ACCEPTED; + + } + + protected function _declineMessage(){ + $this->msgOption['used'] = true; + $this->invalidate(); + $this->validDiplomacy = false; + + return self::DECLINED; + } + + public function declineMessage(int $receiverID, string &$reason):int{ + if(!$this->id){ + throw new \RuntimeException('전송되지 않은 메시지에 거절 진행 중'); + } + + $db = DB::db(); + $gameStor = KVStorage::getStorage($db, 'game_env'); + [$year, $month] = $gameStor->getValuesAsArray(['year', 'month']); + + $general = $db->queryFirstRow( + 'SELECT `name`, nation, `officer_level`, `permission`, `penalty`,belong FROM general WHERE `no`=%i AND nation=%i', + $receiverID, + $this->dest->nationID + ); + list($result, $reason) = $this->checkDiplomaticMessageValidation($general); + + if($result === self::INVALID){ + (new ActionLogger($receiverID, 0, $year, $month))->pushGeneralActionLog("{$reason} {$this->diplomacyName} 거절 불가.", ActionLogger::PLAIN); + return $result; + } + + $josaYi = JosaUtil::pick($this->dest->nationName, '이'); + (new ActionLogger($receiverID, 0, $year, $month))->pushGeneralActionLog("{$this->src->nationName}의 {$this->diplomacyName} 제안을 거절했습니다.", ActionLogger::PLAIN); + (new ActionLogger($this->src->generalID, 0, $year, $month))->pushGeneralActionLog("{$this->dest->nationName}{$josaYi} {$this->diplomacyName} 제안을 거절했습니다.", ActionLogger::PLAIN); + $this->_declineMessage(); + return self::DECLINED; + } + } \ No newline at end of file diff --git a/hwe/sammo/GameConstBase.php b/hwe/sammo/GameConstBase.php index 6d7b24cc..387eaa52 100644 --- a/hwe/sammo/GameConstBase.php +++ b/hwe/sammo/GameConstBase.php @@ -1,355 +1,355 @@ -Credit"; - /** @var string 사용중인 지도명 */ - public static $mapName = 'che'; - /** @var string 사용중인 유닛셋 */ - public static $unitSet = 'che'; - /** @var int 내정시 최하 민심 설정*/ - public static $develrate = 50; - /** @var int 능력치 상승 경험치*/ - public static $upgradeLimit = 30; - /** @var int 숙련도 제한치*/ - public static $dexLimit = 1000000; - /** @var int 초기 징병 사기치*/ - public static $defaultAtmosLow = 40; - /** @var int 초기 징병 훈련치*/ - public static $defaultTrainLow = 40; - /** @var int 초기 모병 사기치*/ - public static $defaultAtmosHigh = 70; - /** @var int 초기 모병 훈련치*/ - public static $defaultTrainHigh = 70; - /** @var int 사기진작으로 올릴 수 있는 최대 사기치*/ - public static $maxAtmosByCommand = 100; - /** @var int 훈련으로 올릴 수 있는 최대 사기치*/ - public static $maxTrainByCommand = 100; - /** @var int 전투로 올릴 수 있는 최대 사기치*/ - public static $maxAtmosByWar = 150; - /** @var int 전투로 올릴 수 훈련치*/ - public static $maxTrainByWar = 110; - /** @var int 풀징병시 훈련 1회 상승량*/ - public static $trainDelta = 30; - /** @var int 풀징병시 훈련 1회 상승량*/ - public static $atmosDelta = 30; - /** @var float 훈련시 사기 감소율*/ - public static $atmosSideEffectByTraining = 1; - /** @var float 사기시 훈련 감소율*/ - public static $trainSideEffectByAtmosTurn = 1; - /** @var float 계략 기본 성공률*/ - public static $sabotageDefaultProb = 0.35; - /** @var int 계략시 확률 가중치(수치가 클수록 변화가 적음 : (지력차/$firing + $basefiring)*/ - public static $sabotageProbCoefByStat = 300; - /** @var int 계략시 최소 수치 감소량*/ - public static $sabotageDamageMin = 100; - /** @var int 계략시 최대 수치 감소량*/ - public static $sabotageDamageMax = 500; - /** @var string 기본 배경색깔 푸른색*/ - public static $basecolor = "#000044"; - /** @var string 기본 배경색깔 초록색*/ - public static $basecolor2 = "#225500"; - /** @var string 기본 배경색깔 붉은색*/ - public static $basecolor3 = "#660000"; - /** @var string 기본 배경색깔 검붉은색*/ - public static $basecolor4 = "#330000"; - /** @var int 페이즈당 표준 감소 병사 수*/ - public static $armperphase = 500; - /** @var int 기본 국고*/ - public static $basegold = 0; - /** @var int 기본 병량*/ - public static $baserice = 2000; - /** @var int 최저 국고(긴급시) */ - public static $minNationalGold = 0; - /** @var int 최저 병량(긴급시) */ - public static $minNationalRice = 0; - /** @var float 군량 매매시 세율*/ - public static $exchangeFee = 0.01; - /** @var float 성인 연령 */ - public static $adultAge = 14; - /** @var float 명전 등록 가능 연령 */ - public static $minPushHallAge = 40; - /** @var int 최대 계급 */ - public static $maxDedLevel = 30; - /** @var int 최대 기술 레벨 */ - public static $maxTechLevel = 12; - /** @var int 최대 하야 패널티 수 */ - public static $maxBetrayCnt = 9; - - /** @var int 최소 인구 증가량 */ - public static $basePopIncreaseAmount = 5000; - /** @var int 증축시 인구 증가량 */ - public static $expandCityPopIncreaseAmount = 100000; - /** @var int 증축시 내정 증가량 */ - public static $expandCityDevelIncreaseAmount = 2000; - /** @var int 증축시 성벽 증가량 */ - public static $expandCityWallIncreaseAmount = 2000; - /** @var int 증축시 최소 비용 */ - public static $expandCityDefaultCost = 60000; - /** @var int 증축시 비용 계수 */ - public static $expandCityCostCoef = 500; - /** @var int 징병 허용 최소 인구 */ - public static $minAvailableRecruitPop = 30000; - - /** @var int 초기 제한시 장수 제한 */ - public static $initialNationGenLimitForRandInit = 3; - - /** @var int 초기 제한시 장수 제한 */ - public static $initialNationGenLimit = 10; - - /** @var int 초기 최대 장수수 */ - public static $defaultMaxGeneral = 500; - /** @var int 초기 최대 국가 수 */ - public static $defaultMaxNation = 55; - /** @var int 초기 최대 천재 수 */ - public static $defaultMaxGenius = 5; - /** @var int 초기 시작 년도. 실제 값은 시나리오에서 정해지므로 딱히 의미는 없음. */ - public static $defaultStartYear = 180; - - /** @var float 멸망한 NPC 장수의 임관 확률 */ - public static $joinRuinedNPCProp = 0.1; - - /** @var int 시작시 금 */ - public static $defaultGold = 1000; - /** @var int 시작시 쌀 */ - public static $defaultRice = 1000; - - /** @var int 원조 계수 */ - public static $coefAidAmount = 10000; - - /** @var int 최대 개별 자원 금액 */ - public static $maxResourceActionAmount = 10000; - /** @var int[] 포상/몰수 가이드 금액 */ - public static $resourceActionAmountGuide = [ - 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, - 1200, 1500, 2000, 2500, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000 - ]; - - public static $generalMinimumGold = 0; - public static $generalMinimumRice = 500; - - /** @var int 최대 턴 */ - public static $maxTurn = 30; - public static $maxChiefTurn = 12; - - public static $statGradeLevel = 5; - - /** @var int 초반 제한 기간 */ - public static $openingPartYear = 3; - /** @var int 거병,임관 제한 기간 */ - public static $joinActionLimit = 12; - - /** @var array 선택 가능한 국가 성향 */ - public static $availableNationType = [ - 'che_도적', 'che_명가', 'che_음양가', 'che_종횡가', 'che_불가', 'che_오두미도', 'che_태평도', 'che_도가', - 'che_묵가', 'che_덕가', 'che_병가', 'che_유가', 'che_법가' - ]; - /** @var array 기본 국가 성향 */ - public static $neutralNationType = 'che_중립'; - - /** @var string 기본 내정 특기 */ - public static $defaultSpecialDomestic = 'None'; - /** @var array 선택 가능한 장수 내정 특기 */ - public static $availableSpecialDomestic = [ - 'che_경작', 'che_상재', 'che_발명', 'che_축성', 'che_수비', 'che_통찰', 'che_인덕', 'che_귀모', - ]; - /** @var array 선택할 수 없으나 게임 내에 유효한 장수 내정 특기 */ - public static $optionalSpecialDomestic = [ - 'None', - ]; - - /** @var string 기본 전투 특기 */ - public static $defaultSpecialWar = 'None'; - /** @var array 선택 가능한 장수 전투 특기 */ - public static $availableSpecialWar = [ - 'che_귀병', 'che_신산', 'che_환술', 'che_집중', 'che_신중', 'che_반계', - 'che_보병', 'che_궁병', 'che_기병', 'che_공성', - 'che_돌격', 'che_무쌍', 'che_견고', 'che_위압', - 'che_저격', 'che_필살', 'che_징병', 'che_의술', 'che_격노', 'che_척사', - ]; - /** @var array 선택할 수 없으나 게임 내에 유효한 장수 전투 특기 */ - public static $optionalSpecialWar = [ - 'None', - ]; - - - /** @var string 기본 성향(공용) */ - public static $neutralPersonality = 'None'; - /** @var array 선택 가능한 성향 */ - public static $availablePersonality = [ - 'che_안전', 'che_유지', 'che_재간', 'che_출세', 'che_할거', 'che_정복', - 'che_패권', 'che_의협', 'che_대의', 'che_왕좌' - ]; - /** @var array 존재하는 모든 성향 */ - public static $optionalPersonality = [ - 'che_은둔', 'None' - ]; - - public static $allItems = [ - 'horse' => [ - 'che_명마_01_노기'=>0, 'che_명마_02_조랑'=>0, 'che_명마_03_노새'=>0, - 'che_명마_04_나귀'=>0, 'che_명마_05_갈색마'=>0, 'che_명마_06_흑색마'=>0, - - 'che_명마_07_백마'=>2, 'che_명마_07_기주마'=>2, - 'che_명마_08_양주마'=>2, 'che_명마_09_과하마'=>2, - 'che_명마_10_대완마'=>2, 'che_명마_11_서량마'=>2, - 'che_명마_12_사륜거'=>2, 'che_명마_13_절영'=>1, 'che_명마_13_적로'=>1, - 'che_명마_14_적란마'=>1, 'che_명마_14_조황비전'=>1, 'che_명마_15_한혈마'=>1, 'che_명마_15_적토마'=>1, - ], - 'weapon' => [ - 'che_무기_01_단도'=>0, 'che_무기_02_단궁'=>0, 'che_무기_03_단극'=>0, - 'che_무기_04_목검'=>0, 'che_무기_05_죽창'=>0, 'che_무기_06_소부'=>0, - - 'che_무기_07_동추'=>1, 'che_무기_07_철편'=>1, 'che_무기_07_철쇄'=>1, 'che_무기_07_맥궁'=>1, - 'che_무기_08_유성추'=>1, 'che_무기_08_철질여골'=>1, 'che_무기_09_쌍철극'=>1, 'che_무기_09_동호비궁'=>1, 'che_무기_10_삼첨도'=>1, 'che_무기_10_대부'=>1, 'che_무기_11_고정도'=>1, 'che_무기_11_이광궁'=>1, 'che_무기_12_철척사모'=>1, 'che_무기_12_칠성검'=>1, 'che_무기_13_사모'=>1, 'che_무기_13_양유기궁'=>1, - 'che_무기_14_언월도'=>1, 'che_무기_14_방천화극'=>1, 'che_무기_15_청홍검'=>1, 'che_무기_15_의천검'=>1 - ], - 'book' => [ - 'che_서적_01_효경전'=>0, 'che_서적_02_회남자'=>0, 'che_서적_03_변도론'=>0, - 'che_서적_04_건상역주'=>0, 'che_서적_05_여씨춘추'=>0, 'che_서적_06_사민월령'=>0, - - 'che_서적_07_위료자'=>1, 'che_서적_07_사마법'=>1, 'che_서적_07_한서'=>1, 'che_서적_07_논어'=>1, - 'che_서적_08_전론'=>1, 'che_서적_08_사기'=>1, 'che_서적_09_장자'=>1, 'che_서적_09_역경'=>1, - 'che_서적_10_시경'=>1, 'che_서적_10_구국론'=>1, 'che_서적_11_상군서'=>1, 'che_서적_11_춘추전'=>1, - 'che_서적_12_산해경'=>1, 'che_서적_12_맹덕신서'=>1, 'che_서적_13_관자'=>1, 'che_서적_13_병법24편'=>1, - 'che_서적_14_한비자'=>1, 'che_서적_14_오자병법'=>1, 'che_서적_15_노자'=>1, 'che_서적_15_손자병법'=>1, - ], - 'item' => [ - 'che_치료_환약'=>0, 'che_저격_수극'=>0, 'che_사기_탁주'=>0, - 'che_훈련_청주'=>0, 'che_계략_이추'=>0, 'che_계략_향낭'=>0, - - 'che_치료_오석산'=>1, 'che_치료_무후행군'=>1, 'che_치료_도소연명'=>1, - 'che_치료_칠엽청점'=>1, 'che_치료_정력견혈'=>1, - 'che_훈련_과실주'=>1, 'che_훈련_이강주'=>1, - 'che_사기_의적주'=>1, 'che_사기_두강주'=>1, 'che_사기_보령압주'=>1, - - 'che_훈련_철벽서'=>1, 'che_훈련_단결도'=>1, 'che_사기_춘화첩'=>1, 'che_사기_초선화'=>1, - 'che_계략_육도'=>1, 'che_계략_삼략'=>1, - 'che_의술_청낭서'=>1, 'che_의술_태평청령'=>1, - 'che_회피_태평요술'=>1, 'che_회피_둔갑천서'=>1, - ] - ]; - - /** @var array 선택 가능한 커맨드 */ - public static $availableGeneralCommand = [ - ''=>[ - '휴식', - 'che_요양' - ], - '내정'=>[ - 'che_농지개간', - 'che_상업투자', - 'che_기술연구', - 'che_수비강화', - 'che_성벽보수', - 'che_치안강화', - 'che_정착장려', - 'che_주민선정', - 'che_물자조달', - ], - '군사'=>[ - 'che_소집해제', - 'che_첩보', - 'che_징병', - 'che_모병', - 'che_훈련', - 'che_사기진작', - 'che_출병', - ], - '인사'=>[ - 'che_이동', - 'che_강행', - 'che_인재탐색', - 'che_등용', - 'che_집합', - 'che_귀환', - 'che_임관', - 'che_랜덤임관', - 'che_장수대상임관', - ], - '계략'=>[ - 'che_화계', - 'che_파괴', - 'che_탈취', - 'che_선동', - ], - '개인'=>[ - 'che_내정특기초기화', - 'che_전투특기초기화', - 'che_단련', - 'che_숙련전환', - 'che_견문', - 'che_장비매매', - 'che_군량매매', - 'che_증여', - 'che_헌납', - 'che_하야', - 'che_거병', - 'che_건국', - 'che_선양', - 'che_방랑', - 'che_해산', - 'che_모반시도', - ] - ]; - - /** @var array 선택 가능한 커맨드 */ - public static $availableChiefCommand = [ - '휴식'=>[ - '휴식', - ], - '인사'=>[ - 'che_발령', - 'che_포상', - 'che_몰수', - ], - '외교'=>[ - 'che_물자원조', - 'che_불가침제의', - 'che_선전포고', - 'che_종전제의', - 'che_불가침파기제의', - ], - '특수'=>[ - 'che_초토화', - 'che_천도', - 'che_증축', - 'che_감축', - ], - '전략'=>[ - 'che_필사즉생', - 'che_백성동원', - 'che_수몰', - 'che_허보', - 'che_피장파장', - 'che_의병모집', - 'che_이호경식', - 'che_급습', - ], - '기타'=>[ - 'che_국기변경', - 'che_국호변경', - ] - ]; - public static $retirementYear = 80; - - public static $randGenFirstName = [ - '가', '간', '감', '강', '고', '공', '공손', '곽', '관', '괴', '교', '금', '노', '뇌', '능', '도', '동', '두', - '등', '마', '맹', '문', '미', '반', '방', '부', '비', '사', '사마', '서', '설', '성', '소', '손', '송', '순', - '신', '심', '악', '안', '양', '엄', '여', '염', '오', '왕', '요', '우', '원', '위', '유', '육', '윤', '이', - '장', '저', '전', '정', '제갈', '조', '종', '주', '진', '채', '태사', '하', '하후', '학', '한', '향', '허', - '호', '화', '황', '공손', '손', '왕', '유', '장', '조' - ]; - public static $randGenMiddleName = ['']; - public static $randGenLastName = [ - '가', '간', '강', '거', '건', '검', '견', '경', '공', '광', '권', '규', '녕', '단', '대', '도', '등', '람', - '량', '례', '로', '료', '모', '민', '박', '범', '보', '비', '사', '상', '색', '서', '소', '속', '송', '수', - '순', '습', '승', '양', '연', '영', '온', '옹', '완', '우', '웅', '월', '위', '유', '윤', '융', '이', '익', - '임', '정', '제', '조', '주', '준', '지', '찬', '책', '충', '탁', '택', '통', '패', '평', '포', '합', '해', - '혁', '현', '화', '환', '회', '횡', '후', '훈', '휴', '흠', '흥' - ]; -} +Credit"; + /** @var string 사용중인 지도명 */ + public static $mapName = 'che'; + /** @var string 사용중인 유닛셋 */ + public static $unitSet = 'che'; + /** @var int 내정시 최하 민심 설정*/ + public static $develrate = 50; + /** @var int 능력치 상승 경험치*/ + public static $upgradeLimit = 30; + /** @var int 숙련도 제한치*/ + public static $dexLimit = 1000000; + /** @var int 초기 징병 사기치*/ + public static $defaultAtmosLow = 40; + /** @var int 초기 징병 훈련치*/ + public static $defaultTrainLow = 40; + /** @var int 초기 모병 사기치*/ + public static $defaultAtmosHigh = 70; + /** @var int 초기 모병 훈련치*/ + public static $defaultTrainHigh = 70; + /** @var int 사기진작으로 올릴 수 있는 최대 사기치*/ + public static $maxAtmosByCommand = 100; + /** @var int 훈련으로 올릴 수 있는 최대 사기치*/ + public static $maxTrainByCommand = 100; + /** @var int 전투로 올릴 수 있는 최대 사기치*/ + public static $maxAtmosByWar = 150; + /** @var int 전투로 올릴 수 훈련치*/ + public static $maxTrainByWar = 110; + /** @var int 풀징병시 훈련 1회 상승량*/ + public static $trainDelta = 30; + /** @var int 풀징병시 훈련 1회 상승량*/ + public static $atmosDelta = 30; + /** @var float 훈련시 사기 감소율*/ + public static $atmosSideEffectByTraining = 1; + /** @var float 사기시 훈련 감소율*/ + public static $trainSideEffectByAtmosTurn = 1; + /** @var float 계략 기본 성공률*/ + public static $sabotageDefaultProb = 0.35; + /** @var int 계략시 확률 가중치(수치가 클수록 변화가 적음 : (지력차/$firing + $basefiring)*/ + public static $sabotageProbCoefByStat = 300; + /** @var int 계략시 최소 수치 감소량*/ + public static $sabotageDamageMin = 100; + /** @var int 계략시 최대 수치 감소량*/ + public static $sabotageDamageMax = 500; + /** @var string 기본 배경색깔 푸른색*/ + public static $basecolor = "#000044"; + /** @var string 기본 배경색깔 초록색*/ + public static $basecolor2 = "#225500"; + /** @var string 기본 배경색깔 붉은색*/ + public static $basecolor3 = "#660000"; + /** @var string 기본 배경색깔 검붉은색*/ + public static $basecolor4 = "#330000"; + /** @var int 페이즈당 표준 감소 병사 수*/ + public static $armperphase = 500; + /** @var int 기본 국고*/ + public static $basegold = 0; + /** @var int 기본 병량*/ + public static $baserice = 2000; + /** @var int 최저 국고(긴급시) */ + public static $minNationalGold = 0; + /** @var int 최저 병량(긴급시) */ + public static $minNationalRice = 0; + /** @var float 군량 매매시 세율*/ + public static $exchangeFee = 0.01; + /** @var float 성인 연령 */ + public static $adultAge = 14; + /** @var float 명전 등록 가능 연령 */ + public static $minPushHallAge = 40; + /** @var int 최대 계급 */ + public static $maxDedLevel = 30; + /** @var int 최대 기술 레벨 */ + public static $maxTechLevel = 12; + /** @var int 최대 하야 패널티 수 */ + public static $maxBetrayCnt = 9; + + /** @var int 최소 인구 증가량 */ + public static $basePopIncreaseAmount = 5000; + /** @var int 증축시 인구 증가량 */ + public static $expandCityPopIncreaseAmount = 100000; + /** @var int 증축시 내정 증가량 */ + public static $expandCityDevelIncreaseAmount = 2000; + /** @var int 증축시 성벽 증가량 */ + public static $expandCityWallIncreaseAmount = 2000; + /** @var int 증축시 최소 비용 */ + public static $expandCityDefaultCost = 60000; + /** @var int 증축시 비용 계수 */ + public static $expandCityCostCoef = 500; + /** @var int 징병 허용 최소 인구 */ + public static $minAvailableRecruitPop = 30000; + + /** @var int 초기 제한시 장수 제한 */ + public static $initialNationGenLimitForRandInit = 3; + + /** @var int 초기 제한시 장수 제한 */ + public static $initialNationGenLimit = 10; + + /** @var int 초기 최대 장수수 */ + public static $defaultMaxGeneral = 500; + /** @var int 초기 최대 국가 수 */ + public static $defaultMaxNation = 55; + /** @var int 초기 최대 천재 수 */ + public static $defaultMaxGenius = 5; + /** @var int 초기 시작 년도. 실제 값은 시나리오에서 정해지므로 딱히 의미는 없음. */ + public static $defaultStartYear = 180; + + /** @var float 멸망한 NPC 장수의 임관 확률 */ + public static $joinRuinedNPCProp = 0.1; + + /** @var int 시작시 금 */ + public static $defaultGold = 1000; + /** @var int 시작시 쌀 */ + public static $defaultRice = 1000; + + /** @var int 원조 계수 */ + public static $coefAidAmount = 10000; + + /** @var int 최대 개별 자원 금액 */ + public static $maxResourceActionAmount = 10000; + /** @var int[] 포상/몰수 가이드 금액 */ + public static $resourceActionAmountGuide = [ + 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, + 1200, 1500, 2000, 2500, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000 + ]; + + public static $generalMinimumGold = 0; + public static $generalMinimumRice = 500; + + /** @var int 최대 턴 */ + public static $maxTurn = 30; + public static $maxChiefTurn = 12; + + public static $statGradeLevel = 5; + + /** @var int 초반 제한 기간 */ + public static $openingPartYear = 3; + /** @var int 거병,임관 제한 기간 */ + public static $joinActionLimit = 12; + + /** @var array 선택 가능한 국가 성향 */ + public static $availableNationType = [ + 'che_도적', 'che_명가', 'che_음양가', 'che_종횡가', 'che_불가', 'che_오두미도', 'che_태평도', 'che_도가', + 'che_묵가', 'che_덕가', 'che_병가', 'che_유가', 'che_법가' + ]; + /** @var array 기본 국가 성향 */ + public static $neutralNationType = 'che_중립'; + + /** @var string 기본 내정 특기 */ + public static $defaultSpecialDomestic = 'None'; + /** @var array 선택 가능한 장수 내정 특기 */ + public static $availableSpecialDomestic = [ + 'che_경작', 'che_상재', 'che_발명', 'che_축성', 'che_수비', 'che_통찰', 'che_인덕', 'che_귀모', + ]; + /** @var array 선택할 수 없으나 게임 내에 유효한 장수 내정 특기 */ + public static $optionalSpecialDomestic = [ + 'None', + ]; + + /** @var string 기본 전투 특기 */ + public static $defaultSpecialWar = 'None'; + /** @var array 선택 가능한 장수 전투 특기 */ + public static $availableSpecialWar = [ + 'che_귀병', 'che_신산', 'che_환술', 'che_집중', 'che_신중', 'che_반계', + 'che_보병', 'che_궁병', 'che_기병', 'che_공성', + 'che_돌격', 'che_무쌍', 'che_견고', 'che_위압', + 'che_저격', 'che_필살', 'che_징병', 'che_의술', 'che_격노', 'che_척사', + ]; + /** @var array 선택할 수 없으나 게임 내에 유효한 장수 전투 특기 */ + public static $optionalSpecialWar = [ + 'None', + ]; + + + /** @var string 기본 성향(공용) */ + public static $neutralPersonality = 'None'; + /** @var array 선택 가능한 성향 */ + public static $availablePersonality = [ + 'che_안전', 'che_유지', 'che_재간', 'che_출세', 'che_할거', 'che_정복', + 'che_패권', 'che_의협', 'che_대의', 'che_왕좌' + ]; + /** @var array 존재하는 모든 성향 */ + public static $optionalPersonality = [ + 'che_은둔', 'None' + ]; + + public static $allItems = [ + 'horse' => [ + 'che_명마_01_노기'=>0, 'che_명마_02_조랑'=>0, 'che_명마_03_노새'=>0, + 'che_명마_04_나귀'=>0, 'che_명마_05_갈색마'=>0, 'che_명마_06_흑색마'=>0, + + 'che_명마_07_백마'=>2, 'che_명마_07_기주마'=>2, + 'che_명마_08_양주마'=>2, 'che_명마_09_과하마'=>2, + 'che_명마_10_대완마'=>2, 'che_명마_11_서량마'=>2, + 'che_명마_12_사륜거'=>2, 'che_명마_13_절영'=>1, 'che_명마_13_적로'=>1, + 'che_명마_14_적란마'=>1, 'che_명마_14_조황비전'=>1, 'che_명마_15_한혈마'=>1, 'che_명마_15_적토마'=>1, + ], + 'weapon' => [ + 'che_무기_01_단도'=>0, 'che_무기_02_단궁'=>0, 'che_무기_03_단극'=>0, + 'che_무기_04_목검'=>0, 'che_무기_05_죽창'=>0, 'che_무기_06_소부'=>0, + + 'che_무기_07_동추'=>1, 'che_무기_07_철편'=>1, 'che_무기_07_철쇄'=>1, 'che_무기_07_맥궁'=>1, + 'che_무기_08_유성추'=>1, 'che_무기_08_철질여골'=>1, 'che_무기_09_쌍철극'=>1, 'che_무기_09_동호비궁'=>1, 'che_무기_10_삼첨도'=>1, 'che_무기_10_대부'=>1, 'che_무기_11_고정도'=>1, 'che_무기_11_이광궁'=>1, 'che_무기_12_철척사모'=>1, 'che_무기_12_칠성검'=>1, 'che_무기_13_사모'=>1, 'che_무기_13_양유기궁'=>1, + 'che_무기_14_언월도'=>1, 'che_무기_14_방천화극'=>1, 'che_무기_15_청홍검'=>1, 'che_무기_15_의천검'=>1 + ], + 'book' => [ + 'che_서적_01_효경전'=>0, 'che_서적_02_회남자'=>0, 'che_서적_03_변도론'=>0, + 'che_서적_04_건상역주'=>0, 'che_서적_05_여씨춘추'=>0, 'che_서적_06_사민월령'=>0, + + 'che_서적_07_위료자'=>1, 'che_서적_07_사마법'=>1, 'che_서적_07_한서'=>1, 'che_서적_07_논어'=>1, + 'che_서적_08_전론'=>1, 'che_서적_08_사기'=>1, 'che_서적_09_장자'=>1, 'che_서적_09_역경'=>1, + 'che_서적_10_시경'=>1, 'che_서적_10_구국론'=>1, 'che_서적_11_상군서'=>1, 'che_서적_11_춘추전'=>1, + 'che_서적_12_산해경'=>1, 'che_서적_12_맹덕신서'=>1, 'che_서적_13_관자'=>1, 'che_서적_13_병법24편'=>1, + 'che_서적_14_한비자'=>1, 'che_서적_14_오자병법'=>1, 'che_서적_15_노자'=>1, 'che_서적_15_손자병법'=>1, + ], + 'item' => [ + 'che_치료_환약'=>0, 'che_저격_수극'=>0, 'che_사기_탁주'=>0, + 'che_훈련_청주'=>0, 'che_계략_이추'=>0, 'che_계략_향낭'=>0, + + 'che_치료_오석산'=>1, 'che_치료_무후행군'=>1, 'che_치료_도소연명'=>1, + 'che_치료_칠엽청점'=>1, 'che_치료_정력견혈'=>1, + 'che_훈련_과실주'=>1, 'che_훈련_이강주'=>1, + 'che_사기_의적주'=>1, 'che_사기_두강주'=>1, 'che_사기_보령압주'=>1, + + 'che_훈련_철벽서'=>1, 'che_훈련_단결도'=>1, 'che_사기_춘화첩'=>1, 'che_사기_초선화'=>1, + 'che_계략_육도'=>1, 'che_계략_삼략'=>1, + 'che_의술_청낭서'=>1, 'che_의술_태평청령'=>1, + 'che_회피_태평요술'=>1, 'che_회피_둔갑천서'=>1, + ] + ]; + + /** @var array 선택 가능한 커맨드 */ + public static $availableGeneralCommand = [ + ''=>[ + '휴식', + 'che_요양' + ], + '내정'=>[ + 'che_농지개간', + 'che_상업투자', + 'che_기술연구', + 'che_수비강화', + 'che_성벽보수', + 'che_치안강화', + 'che_정착장려', + 'che_주민선정', + 'che_물자조달', + ], + '군사'=>[ + 'che_소집해제', + 'che_첩보', + 'che_징병', + 'che_모병', + 'che_훈련', + 'che_사기진작', + 'che_출병', + ], + '인사'=>[ + 'che_이동', + 'che_강행', + 'che_인재탐색', + 'che_등용', + 'che_집합', + 'che_귀환', + 'che_임관', + 'che_랜덤임관', + 'che_장수대상임관', + ], + '계략'=>[ + 'che_화계', + 'che_파괴', + 'che_탈취', + 'che_선동', + ], + '개인'=>[ + 'che_내정특기초기화', + 'che_전투특기초기화', + 'che_단련', + 'che_숙련전환', + 'che_견문', + 'che_장비매매', + 'che_군량매매', + 'che_증여', + 'che_헌납', + 'che_하야', + 'che_거병', + 'che_건국', + 'che_선양', + 'che_방랑', + 'che_해산', + 'che_모반시도', + ] + ]; + + /** @var array 선택 가능한 커맨드 */ + public static $availableChiefCommand = [ + '휴식'=>[ + '휴식', + ], + '인사'=>[ + 'che_발령', + 'che_포상', + 'che_몰수', + ], + '외교'=>[ + 'che_물자원조', + 'che_불가침제의', + 'che_선전포고', + 'che_종전제의', + 'che_불가침파기제의', + ], + '특수'=>[ + 'che_초토화', + 'che_천도', + 'che_증축', + 'che_감축', + ], + '전략'=>[ + 'che_피장파장', + 'che_필사즉생', + 'che_백성동원', + 'che_수몰', + 'che_허보', + 'che_의병모집', + 'che_이호경식', + 'che_급습', + ], + '기타'=>[ + 'che_국기변경', + 'che_국호변경', + ] + ]; + public static $retirementYear = 80; + + public static $randGenFirstName = [ + '가', '간', '감', '강', '고', '공', '공손', '곽', '관', '괴', '교', '금', '노', '뇌', '능', '도', '동', '두', + '등', '마', '맹', '문', '미', '반', '방', '부', '비', '사', '사마', '서', '설', '성', '소', '손', '송', '순', + '신', '심', '악', '안', '양', '엄', '여', '염', '오', '왕', '요', '우', '원', '위', '유', '육', '윤', '이', + '장', '저', '전', '정', '제갈', '조', '종', '주', '진', '채', '태사', '하', '하후', '학', '한', '향', '허', + '호', '화', '황', '공손', '손', '왕', '유', '장', '조' + ]; + public static $randGenMiddleName = ['']; + public static $randGenLastName = [ + '가', '간', '강', '거', '건', '검', '견', '경', '공', '광', '권', '규', '녕', '단', '대', '도', '등', '람', + '량', '례', '로', '료', '모', '민', '박', '범', '보', '비', '사', '상', '색', '서', '소', '속', '송', '수', + '순', '습', '승', '양', '연', '영', '온', '옹', '완', '우', '웅', '월', '위', '유', '윤', '융', '이', '익', + '임', '정', '제', '조', '주', '준', '지', '찬', '책', '충', '탁', '택', '통', '패', '평', '포', '합', '해', + '혁', '현', '화', '환', '회', '횡', '후', '훈', '휴', '흠', '흥' + ]; +} diff --git a/hwe/sammo/ResetHelper.php b/hwe/sammo/ResetHelper.php index 94c0ecd7..72c1c401 100644 --- a/hwe/sammo/ResetHelper.php +++ b/hwe/sammo/ResetHelper.php @@ -132,6 +132,9 @@ class ResetHelper{ $gameStor->resetValues(); $gameStor->next_season_idx = $seasonIdx; + $lastExecuteStor = KVStorage::getStorage($db, 'next_execute'); + $lastExecuteStor->resetValues(); + return [ 'result'=>true, 'serverID'=>$serverID, diff --git a/hwe/sammo/ScoutMessage.php b/hwe/sammo/ScoutMessage.php index 19e54151..a99033e7 100644 --- a/hwe/sammo/ScoutMessage.php +++ b/hwe/sammo/ScoutMessage.php @@ -1,227 +1,228 @@ -validScout = false; - } - - if($this->validUntil <= new \DateTime()){ - $this->validScout = false; - } - } - - protected function checkScoutMessageValidation(int $receiverID){ - if(!$this->validScout){ - return [self::INVALID, '유효하지 않은 등용장입니다.']; - } - if($this->mailbox !== $this->dest->generalID){ - return [self::INVALID, '송신자가 등용장을 처리할 수 없습니다.']; - } - - if($this->mailbox !== $receiverID){ - return [self::INVALID, '올바른 수신자가 아닙니다.']; - } - - return [self::ACCEPTED, '성공']; - } - - /** - * @return int 수행 결과 반환, ACCEPTED(등용장 소모), DECLINED(등용장 소모), INVALID 중 반환 - */ - public function agreeMessage(int $receiverID, string &$reason):int{ - //NOTE: 올바른 유저가 agreeMessage() 호출을 한건지는 외부에서 체크 필요(Session->userID 등) - - if(!$this->id){ - throw new \RuntimeException('전송되지 않은 메시지에 수락 진행 중'); - } - - $gameStor = KVStorage::getStorage(DB::db(), 'game_env'); - $general = \sammo\General::createGeneralObjFromDB($receiverID, null, 2); - - $logger = $general->getLogger(); - - list($result, $reason) = $this->checkScoutMessageValidation($receiverID); - - if($result !== self::ACCEPTED){ - $logger->pushGeneralActionLog("{$reason} 등용 수락 불가."); - if($result === self::DECLINED){ - $this->_declineMessage(); - } - return $result; - } - - $commandObj = buildGeneralCommandClass('che_등용수락', $general, $gameStor->getAll(true), [ - 'destNationID'=>$this->src->nationID, - 'destGeneralID'=>$this->src->generalID, - ]); - - if(!$commandObj->hasFullConditionMet()){ - $logger->pushGeneralActionLog($commandObj->getFailString()); - $reason = $commandObj->getFailString(); - return self::DECLINED; - } - - $commandObj->run(); - - //메시지 비 활성화 - $this->msgOption['used'] = true; - $this->invalidate(); - $this->validScout = false; - - $josaRo = JosaUtil::pick($this->src->nationName, '로'); - $newMsg = new Message( - self::MSGTYPE_PRIVATE, - $this->src, - $this->dest, - "{$this->src->nationName}{$josaRo} 등용 제의 수락", - new \DateTime(), - new \DateTime('9999-12-31'), - [ - 'delete'=>$this->id - ] - ); - $newMsg->send(true); - - return self::ACCEPTED; - } - - protected function _declineMessage(){ - $this->msgOption['used'] = true; - $this->invalidate(); - $this->validScout = false; - - $josaRo = JosaUtil::pick($this->src->nationName, '로'); - $newMsg = new Message( - self::MSGTYPE_PRIVATE, - $this->src, - $this->dest, - "{$this->src->nationName}{$josaRo} 등용 제의 거부", - new \DateTime(), - new \DateTime('9999-12-31'), - [ - 'delete'=>$this->id - ] - ); - $newMsg->send(true); - - return self::DECLINED; - } - - public function declineMessage(int $receiverID, string &$reason):int{ - if(!$this->id){ - throw new \RuntimeException('전송되지 않은 메시지에 거절 진행 중'); - } - - $db = DB::db(); - $gameStor = KVStorage::getStorage($db, 'game_env'); - [$year, $month] = $gameStor->getValuesAsArray(['year', 'month']); - - list($result, $reason) = $this->checkScoutMessageValidation($receiverID); - - if($result === self::INVALID){ - (new ActionLogger($receiverID, 0, $year, $month))->pushGeneralActionLog("{$reason} 등용 취소 불가.", ActionLogger::PLAIN); - return $result; - } - - $josaRo = JosaUtil::pick($this->src->nationName, '로'); - $josaYi = JosaUtil::pick($this->dest->generalName, '이'); - (new ActionLogger($receiverID, 0, $year, $month))->pushGeneralActionLog("{$this->src->nationName}{$josaRo} 망명을 거부했습니다.", ActionLogger::PLAIN); - (new ActionLogger($this->src->generalID, 0, $year, $month))->pushGeneralActionLog("{$this->dest->generalName}{$josaYi} 등용을 거부했습니다.", ActionLogger::PLAIN); - $this->_declineMessage(); - - return self::DECLINED; - } - - public static function buildScoutMessage(int $srcGeneralID, int $destGeneralID, &$reason = null, \DateTime $date = null):?self{ - if($srcGeneralID == $destGeneralID){ - if($reason !== null){ - $reason = '같은 장수에게 등용장을 보낼 수 없습니다'; - } - return null; - } - - $db = DB::db(); - $srcGeneral = $db->queryFirstRow('SELECT `name`, nation FROM general WHERE `no`=%i', $srcGeneralID); - $destGeneral = $db->queryFirstRow('SELECT `name`, nation, `officer_level` FROM general WHERE `no`=%i', $destGeneralID); - if($date === null){ - $date = new \DateTime(); - } - - if($destGeneral['officer_level'] == 12){ - if($reason !== null){ - $reason = '군주에게 등용장을 보낼 수 없습니다'; - } - return null; - } - - if(!$srcGeneral['nation']){ - if($reason !== null){ - $reason = '재야 상태일 때에는 등용장을 보낼 수 없습니다'; - } - return null; - } - - if($srcGeneral['nation'] === $destGeneral['nation']){ - if($reason !== null){ - $reason = '같은 소속의 장수에게 등용장을 보낼 수 없습니다'; - } - return null; - } - - $srcNationInfo = getNationStaticInfo($srcGeneral['nation']); - $destNationInfo = getNationStaticInfo($destGeneral['nation']); - - $src = new MessageTarget( - $srcGeneralID, - $srcGeneral['name'], - $srcGeneral['nation'], - $srcNationInfo['name'], - $srcNationInfo['color'] - ); - - $dest = new MessageTarget( - $destGeneralID, - $destGeneral['name'], - $destGeneral['nation'], - $destNationInfo['name'], - $destNationInfo['color'] - ); - - $josaRo = JosaUtil::pick($src->nationName, '로'); - $msg = "{$src->nationName}{$josaRo} 망명 권유 서신"; - $validUntil = new \DateTime("9999-12-31 12:59:59"); - - $msgOption = [ - 'action'=>'scout' - ]; - - return new ScoutMessage(Message::MSGTYPE_PRIVATE, $src, $dest, $msg, $date, $validUntil, $msgOption); - } +validScout = false; + } + + if($this->validUntil <= new \DateTime()){ + $this->validScout = false; + } + } + + protected function checkScoutMessageValidation(int $receiverID){ + if(!$this->validScout){ + return [self::INVALID, '유효하지 않은 등용장입니다.']; + } + if($this->mailbox !== $this->dest->generalID){ + return [self::INVALID, '송신자가 등용장을 처리할 수 없습니다.']; + } + + if($this->mailbox !== $receiverID){ + return [self::INVALID, '올바른 수신자가 아닙니다.']; + } + + return [self::ACCEPTED, '성공']; + } + + /** + * @return int 수행 결과 반환, ACCEPTED(등용장 소모), DECLINED(등용장 소모), INVALID 중 반환 + */ + public function agreeMessage(int $receiverID, string &$reason):int{ + //NOTE: 올바른 유저가 agreeMessage() 호출을 한건지는 외부에서 체크 필요(Session->userID 등) + + if(!$this->id){ + throw new \RuntimeException('전송되지 않은 메시지에 수락 진행 중'); + } + + $gameStor = KVStorage::getStorage(DB::db(), 'game_env'); + $general = \sammo\General::createGeneralObjFromDB($receiverID, null, 2); + + $logger = $general->getLogger(); + + list($result, $reason) = $this->checkScoutMessageValidation($receiverID); + + if($result !== self::ACCEPTED){ + $logger->pushGeneralActionLog("{$reason} 등용 수락 불가."); + if($result === self::DECLINED){ + $this->_declineMessage(); + } + return $result; + } + + $commandObj = buildGeneralCommandClass('che_등용수락', $general, $gameStor->getAll(true), [ + 'destNationID'=>$this->src->nationID, + 'destGeneralID'=>$this->src->generalID, + ]); + + if(!$commandObj->hasFullConditionMet()){ + $logger->pushGeneralActionLog($commandObj->getFailString()); + $reason = $commandObj->getFailString(); + return self::DECLINED; + } + + $commandObj->run(); + $commandObj->setNextAvailable(); + + //메시지 비 활성화 + $this->msgOption['used'] = true; + $this->invalidate(); + $this->validScout = false; + + $josaRo = JosaUtil::pick($this->src->nationName, '로'); + $newMsg = new Message( + self::MSGTYPE_PRIVATE, + $this->src, + $this->dest, + "{$this->src->nationName}{$josaRo} 등용 제의 수락", + new \DateTime(), + new \DateTime('9999-12-31'), + [ + 'delete'=>$this->id + ] + ); + $newMsg->send(true); + + return self::ACCEPTED; + } + + protected function _declineMessage(){ + $this->msgOption['used'] = true; + $this->invalidate(); + $this->validScout = false; + + $josaRo = JosaUtil::pick($this->src->nationName, '로'); + $newMsg = new Message( + self::MSGTYPE_PRIVATE, + $this->src, + $this->dest, + "{$this->src->nationName}{$josaRo} 등용 제의 거부", + new \DateTime(), + new \DateTime('9999-12-31'), + [ + 'delete'=>$this->id + ] + ); + $newMsg->send(true); + + return self::DECLINED; + } + + public function declineMessage(int $receiverID, string &$reason):int{ + if(!$this->id){ + throw new \RuntimeException('전송되지 않은 메시지에 거절 진행 중'); + } + + $db = DB::db(); + $gameStor = KVStorage::getStorage($db, 'game_env'); + [$year, $month] = $gameStor->getValuesAsArray(['year', 'month']); + + list($result, $reason) = $this->checkScoutMessageValidation($receiverID); + + if($result === self::INVALID){ + (new ActionLogger($receiverID, 0, $year, $month))->pushGeneralActionLog("{$reason} 등용 취소 불가.", ActionLogger::PLAIN); + return $result; + } + + $josaRo = JosaUtil::pick($this->src->nationName, '로'); + $josaYi = JosaUtil::pick($this->dest->generalName, '이'); + (new ActionLogger($receiverID, 0, $year, $month))->pushGeneralActionLog("{$this->src->nationName}{$josaRo} 망명을 거부했습니다.", ActionLogger::PLAIN); + (new ActionLogger($this->src->generalID, 0, $year, $month))->pushGeneralActionLog("{$this->dest->generalName}{$josaYi} 등용을 거부했습니다.", ActionLogger::PLAIN); + $this->_declineMessage(); + + return self::DECLINED; + } + + public static function buildScoutMessage(int $srcGeneralID, int $destGeneralID, &$reason = null, \DateTime $date = null):?self{ + if($srcGeneralID == $destGeneralID){ + if($reason !== null){ + $reason = '같은 장수에게 등용장을 보낼 수 없습니다'; + } + return null; + } + + $db = DB::db(); + $srcGeneral = $db->queryFirstRow('SELECT `name`, nation FROM general WHERE `no`=%i', $srcGeneralID); + $destGeneral = $db->queryFirstRow('SELECT `name`, nation, `officer_level` FROM general WHERE `no`=%i', $destGeneralID); + if($date === null){ + $date = new \DateTime(); + } + + if($destGeneral['officer_level'] == 12){ + if($reason !== null){ + $reason = '군주에게 등용장을 보낼 수 없습니다'; + } + return null; + } + + if(!$srcGeneral['nation']){ + if($reason !== null){ + $reason = '재야 상태일 때에는 등용장을 보낼 수 없습니다'; + } + return null; + } + + if($srcGeneral['nation'] === $destGeneral['nation']){ + if($reason !== null){ + $reason = '같은 소속의 장수에게 등용장을 보낼 수 없습니다'; + } + return null; + } + + $srcNationInfo = getNationStaticInfo($srcGeneral['nation']); + $destNationInfo = getNationStaticInfo($destGeneral['nation']); + + $src = new MessageTarget( + $srcGeneralID, + $srcGeneral['name'], + $srcGeneral['nation'], + $srcNationInfo['name'], + $srcNationInfo['color'] + ); + + $dest = new MessageTarget( + $destGeneralID, + $destGeneral['name'], + $destGeneral['nation'], + $destNationInfo['name'], + $destNationInfo['color'] + ); + + $josaRo = JosaUtil::pick($src->nationName, '로'); + $msg = "{$src->nationName}{$josaRo} 망명 권유 서신"; + $validUntil = new \DateTime("9999-12-31 12:59:59"); + + $msgOption = [ + 'action'=>'scout' + ]; + + return new ScoutMessage(Message::MSGTYPE_PRIVATE, $src, $dest, $msg, $date, $validUntil, $msgOption); + } } \ No newline at end of file diff --git a/hwe/sammo/TurnExecutionHelper.php b/hwe/sammo/TurnExecutionHelper.php index 1710f7c5..d53f492c 100644 --- a/hwe/sammo/TurnExecutionHelper.php +++ b/hwe/sammo/TurnExecutionHelper.php @@ -85,6 +85,7 @@ class TurnExecutionHelper $result = $commandObj->run(); if($result){ + $commandObj->setNextAvailable(); break; } @@ -127,6 +128,7 @@ class TurnExecutionHelper $result = $commandObj->run(); if($result){ + $commandObj->setNextAvailable(); break; } $alt = $commandObj->getAlternativeCommand();