diff --git a/hwe/sammo/Event/Action/MergeInheritPointRank.php b/hwe/sammo/Event/Action/MergeInheritPointRank.php new file mode 100644 index 00000000..a93d1e55 --- /dev/null +++ b/hwe/sammo/Event/Action/MergeInheritPointRank.php @@ -0,0 +1,66 @@ +allocate(count($generals)); + foreach($generals as $general){ + $generalID = $general->getID(); + $points[$generalID] = 0; + } + + foreach(InheritanceKey::cases() as $key){ + if($key === InheritanceKey::previous){ + continue; + } + $subPoints = InheritancePointManager::getInstance()->getInheritancePointFromAll($generals, $key); + foreach($generals as $general){ + $generalID = $general->getID(); + $points[$generalID] += $subPoints[$generalID] ?? 0; + } + } + + $pointsPairs = []; + foreach($points as $generalID => $point){ + $pointsPairs[] = [ + 'nation_id' => $generals[$generalID]->getNationID(), + 'general_id' => $generalID, + 'type' => RankColumn::inherit_point_earned_by_merge->value, + 'value' => $point, + ]; + } + //XXX: multiple batch update가 제공되지 않으므로.. + $db->delete('rank_data', '`type` = %s', RankColumn::inherit_point_earned_by_merge->value); + $db->insert('rank_data', $pointsPairs); + + $db->query( + 'UPDATE `rank_data` D SET `value` = (SELECT SUM(`value`) FROM `rank_data` S WHERE S.general_id = D.general_id AND S.`type` IN %ls) WHERE D.`type` = %s', + [RankColumn::inherit_point_earned_by_action->value, RankColumn::inherit_point_earned_by_merge->value], + RankColumn::inherit_point_earned->value + ); + + $db->query( + 'UPDATE `rank_data` D SET `value` = (SELECT `value` FROM `rank_data` S WHERE S.general_id = D.general_id AND S.`type` = %s) WHERE D.`type` = %s', + RankColumn::inherit_point_spent_dynamic->value, + RankColumn::inherit_point_spent->value + ); + } +} diff --git a/hwe/sammo/Event/Action/ProcessIncome.php b/hwe/sammo/Event/Action/ProcessIncome.php new file mode 100644 index 00000000..f0ad251d --- /dev/null +++ b/hwe/sammo/Event/Action/ProcessIncome.php @@ -0,0 +1,201 @@ +query('SELECT name,nation,capital,gold,level,rate_tmp,bill,type from nation'); + $cityListByNation = Util::arrayGroupBy($db->query('SELECT * FROM city'), 'nation'); + $generalRawListByNation = Util::arrayGroupBy($db->query('SELECT no,name,nation,gold,officer_level,dedication,city FROM general WHERE npc != 5'), 'nation'); + + //국가별 처리 + foreach ($nationList as $nation) { + $nationID = $nation['nation']; + + $generalRawList = $generalRawListByNation[$nationID]; + $income = getGoldIncome($nationID, $nation['level'], $nation['rate_tmp'], $nation['capital'], $nation['type'], $cityListByNation[$nationID] ?? []); + $originoutcome = getOutcome(100, $generalRawList); + $outcome = Util::round($nation['bill'] / 100 * $originoutcome); + + // 실제 지급량 계산 + $nation['gold'] += $income; + // 기본량도 안될경우 + if ($nation['gold'] < GameConst::$basegold) { + $realoutcome = 0; + // 실지급률 + $ratio = 0; + //기본량은 넘지만 요구량이 안될경우 + } elseif ($nation['gold'] - GameConst::$basegold < $outcome) { + $realoutcome = $nation['gold'] - GameConst::$basegold; + $nation['gold'] = GameConst::$basegold; + // 실지급률 + $ratio = $realoutcome / $originoutcome; + } else { + $realoutcome = $outcome; + $nation['gold'] -= $realoutcome; + // 실지급률 + $ratio = $realoutcome / $originoutcome; + } + $nation['gold'] = Util::valueFit($nation['gold'], GameConst::$basegold); + $adminLog[] = StringUtil::padStringAlignRight((string)$nation['name'], 12, " ") + . " // 세금 : " . StringUtil::padStringAlignRight((string)$income, 6, " ") + . " // 세출 : " . StringUtil::padStringAlignRight((string)$originoutcome, 6, " ") + . " // 실제 : " . tab2((string)$realoutcome, 6, " ") + . " // 지급률 : " . tab2((string)round($ratio * 100, 2), 5, " ") + . " % // 결과금 : " . tab2((string)$nation['gold'], 6, " "); + + $incomeText = number_format($income); + $incomeLog = "이번 수입은 금 $incomeText입니다."; + $nationStor = KVStorage::getStorage($db, $nationID, 'nation_env'); + $nationStor->prev_income_gold = $income; + + $db->update('nation', [ + 'gold' => $nation['gold'] + ], 'nation=%i', $nationID); + + // 각 장수들에게 지급 + foreach ($generalRawList as $rawGeneral) { + $generalObj = new General($rawGeneral, null, null, null, $year, $month, false); + $gold = Util::round(getBill($generalObj->getVar('dedication')) * $ratio); + $generalObj->increaseVar('gold', $gold); + + $logger = $generalObj->getLogger(); + if ($generalObj->getVar('officer_level') > 4) { + $logger->pushGeneralActionLog($incomeLog, $logger::PLAIN); + } + + $goldText = number_format($gold); + $logger->pushGeneralActionLog("봉급으로 금 $goldText을 받았습니다.", $logger::PLAIN); + $generalObj->applyDB($db); + } + } + + $logger = new ActionLogger(0, 0, $year, $month); + $logger->pushGlobalHistoryLog('【지급】봄이 되어 봉록에 따라 자금이 지급됩니다.'); + $logger->flush(); + + pushAdminLog($adminLog); + } + + private function processRiceIncome(array $env) + { + $db = DB::db(); + + [$year, $month] = [$env['year'], $env['month']]; + $adminLog = []; + + $nationList = $db->query('SELECT name,level,nation,capital,rice,rate_tmp,bill,type from nation'); + $cityListByNation = Util::arrayGroupBy($db->query('SELECT * FROM city'), 'nation'); + $generalRawListByNation = Util::arrayGroupBy($db->query('SELECT no,name,nation,rice,officer_level,dedication,city FROM general WHERE npc != 5'), 'nation'); + + //국가별 처리 + foreach ($nationList as $nation) { + $nationID = $nation['nation']; + + $generalRawList = $generalRawListByNation[$nationID]; + $income = getRiceIncome($nation['nation'], $nation['level'], $nation['rate_tmp'], $nation['capital'], $nation['type'], $cityListByNation[$nationID] ?? []); + $income += getWallIncome($nation['nation'], $nation['level'], $nation['rate_tmp'], $nation['capital'], $nation['type'], $cityListByNation[$nationID] ?? []); + $originoutcome = getOutcome(100, $generalRawList); + $outcome = Util::round($nation['bill'] / 100 * $originoutcome); + + // 실제 지급량 계산 + $nation['rice'] += $income; + // 기본량도 안될경우 + if ($nation['rice'] < GameConst::$baserice) { + $realoutcome = 0; + // 실지급률 + $ratio = 0; + //기본량은 넘지만 요구량이 안될경우 + } elseif ($nation['rice'] - GameConst::$baserice < $outcome) { + $realoutcome = $nation['rice'] - GameConst::$baserice; + $nation['rice'] = GameConst::$baserice; + // 실지급률 + $ratio = $realoutcome / $originoutcome; + } else { + $realoutcome = $outcome; + $nation['rice'] -= $realoutcome; + // 실지급률 + $ratio = $realoutcome / $originoutcome; + } + $nation['rice'] = Util::valueFit($nation['rice'], GameConst::$baserice); + $adminLog[] = StringUtil::padStringAlignRight($nation['name'], 12, " ") + . " // 세곡 : " . StringUtil::padStringAlignRight((string)$income, 6, " ") + . " // 세출 : " . StringUtil::padStringAlignRight((string)$originoutcome, 6, " ") + . " // 실제 : " . tab2((string)$realoutcome, 6, " ") + . " // 지급률 : " . tab2((string)round($ratio * 100, 2), 5, " ") + . " % // 결과곡 : " . tab2((string)$nation['rice'], 6, " "); + + $incomeText = number_format($income); + $incomeLog = "이번 수입은 쌀 $incomeText입니다."; + $nationStor = KVStorage::getStorage($db, $nationID, 'nation_env'); + $nationStor->prev_income_rice = $income; + + $db->update('nation', [ + 'rice' => $nation['rice'] + ], 'nation=%i', $nationID); + + // 각 장수들에게 지급 + foreach ($generalRawList as $rawGeneral) { + $generalObj = new General($rawGeneral, null, null, null, $year, $month, false); + $rice = Util::round(getBill($generalObj->getVar('dedication')) * $ratio); + $generalObj->increaseVar('rice', $rice); + + $logger = $generalObj->getLogger(); + if ($generalObj->getVar('officer_level') > 4) { + $logger->pushGeneralActionLog($incomeLog, $logger::PLAIN); + } + $riceText = number_format($rice); + $logger->pushGeneralActionLog("봉급으로 쌀 $riceText을 받았습니다.", $logger::PLAIN); + $generalObj->applyDB($db); + } + } + + $logger = new ActionLogger(0, 0, $year, $month); + $logger->pushGlobalHistoryLog('【지급】가을이 되어 봉록에 따라 군량이 지급됩니다.'); + $logger->flush(); + + pushAdminLog($adminLog); + } + + public function run(array $env) + { + if ($this->resource === ResourceType::gold->value) { + $this->processGoldIncome($env); + } else { + $this->processRiceIncome($env); + } + } +} diff --git a/hwe/sammo/Event/Action/ProcessSemiAnnual.php b/hwe/sammo/Event/Action/ProcessSemiAnnual.php new file mode 100644 index 00000000..e83a76d4 --- /dev/null +++ b/hwe/sammo/Event/Action/ProcessSemiAnnual.php @@ -0,0 +1,104 @@ +queryAllLists('SELECT nation,rate_tmp,type FROM nation'); + + // 인구 및 민심 + + $db->update('city', [ + 'trust' => 50, + 'agri' => $db->sqleval('agri * 0.99'), + 'comm' => $db->sqleval('comm * 0.99'), + 'secu' => $db->sqleval('secu * 0.99'), + 'def' => $db->sqleval('def * 0.99'), + 'wall' => $db->sqleval('wall * 0.99'), + ], 'nation=0'); + + foreach ($nationList as [$nationID, $taxRate, $nationType]) { + $nationTypeObj = buildNationTypeClass($nationType); + + + $popRatio = (30 - $taxRate) / 200; // 20일때 5% 5일때 12.5% 50일때 -10% + $popRatio = $nationTypeObj->onCalcNationalIncome('pop', $popRatio); + + $updateVar = []; + if ($popRatio >= 0) { + $updateVar['pop'] = $db->sqleval('least(pop_max, %i + pop * (1 + %d * (1 + secu / secu_max / 10)))', GameConst::$basePopIncreaseAmount, $popRatio); + } else { + $updateVar['pop'] = $db->sqleval('least(pop_max, %i + pop * (1 + %d * (1 - secu / secu_max / 10)))', GameConst::$basePopIncreaseAmount, $popRatio); + } + + $genericRatio = (20 - $taxRate) / 200; // 20일때 0% 0일때 10% 100일때 -40% + foreach (['agri', 'comm', 'secu', 'def', 'wall'] as $key) { + $updateVar[$key] = $db->sqleval('least(%b, %b * (1 + %d))', $key . '_max', $key, $genericRatio); + } + + $trustDiff = 20 - $taxRate; + $updateVar['trust'] = $db->sqleval('greatest(0, least(100, trust + %i))', $trustDiff); + + $db->update('city', $updateVar, 'nation = %i AND supply = 1', $nationID); + } + } + + public function run(array $env) + { + $db = DB::db(); + + + $resource = $this->resource; + + // 내정 1% 감소 + $db->update('city', [ + 'dead' => 0, + 'agri' => $db->sqleval('agri * 0.99'), + 'comm' => $db->sqleval('comm * 0.99'), + 'secu' => $db->sqleval('secu * 0.99'), + 'def' => $db->sqleval('def * 0.99'), + 'wall' => $db->sqleval('wall * 0.99'), + ], true); + + //인구 증가 + popIncrease(); + + // > 10000 유지비 3%, > 1000 유지비 1% + // 유지비 1% + $db->update('general', [ + $resource => $db->sqleval('IF(%b > 10000, %b * 0.97, %b * 0.99)', $resource, $resource, $resource) + ], '%b > 1000', $resource); + + // > 100000 유지비 5%, > 100000 유지비 3%, > 1000 유지비 1% + $db->update('nation', [ + $resource => $db->sqleval('IF(%b > 100000, %b * 0.95, IF(%b > 10000, %b * 0.97, %b * 0.99))', $resource, $resource, $resource, $resource, $resource) + ], '%b > 1000', $resource); + + [$year, $month] = [$env['year'], $env['month']]; + if($month == 1){ + pushGlobalHistoryLog(["★{$year}년 {$month}월: 모두들 즐거운 게임 하고 계신가요? ^^ 매너 있는 플레이 부탁드리고, 지나친 훼접은 삼가주세요~"], $year, $month); + } + + } +} diff --git a/hwe/sammo/Event/Action/UpdateCitySupply.php b/hwe/sammo/Event/Action/UpdateCitySupply.php new file mode 100644 index 00000000..5365ea09 --- /dev/null +++ b/hwe/sammo/Event/Action/UpdateCitySupply.php @@ -0,0 +1,79 @@ +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); + } + } + +} \ No newline at end of file