diff --git a/hwe/_admin2.php b/hwe/_admin2.php index 2ccb1358..4281e2eb 100644 --- a/hwe/_admin2.php +++ b/hwe/_admin2.php @@ -109,10 +109,6 @@ $db = DB::db(); 강제 사망 - - 이벤트 - - 이벤트2 @@ -121,10 +117,6 @@ $db = DB::db(); 접속제한 - - 턴 시각 설정 - - 명령 설정 diff --git a/hwe/_admin2_submit.php b/hwe/_admin2_submit.php index 8c9476e8..fb0b717f 100644 --- a/hwe/_admin2_submit.php +++ b/hwe/_admin2_submit.php @@ -107,28 +107,6 @@ switch ($btn) { 'arg' => '{}', 'brief' => '휴식', ], 'general_id IN %li AND turn_idx = 0', $genlist); - break; - case "특기 부여": - [$year, $month] = $gameStor->getValuesAsArray(['year', 'month']); - $text = "특기 부여!"; - - foreach ($db->query("SELECT `no`,leadership,strength,intel,dex1,dex2,dex3,dex4,dex5 FROM general WHERE `no` IN %li", $genlist) as $general) { - $msg = new Message(Message::MSGTYPE_PRIVATE, $src, MessageTarget::buildQuick($general['no']), $text, new \DateTime(), new \DateTime('9999-12-31'), []); - $msg->send(true); - - $specialWar = SpecialityHelper::pickSpecialWar($general); - $db->update('general', [ - 'specage2' => $db->sqleval('age'), - 'special2' => $specialWar - ], 'no=%i', $general['no']); - $specialWarName = buildGeneralSpecialWarClass($specialWar)->getName(); - $josaUl = JosaUtil::pick($specialWarName, '을'); - $logger = new ActionLogger($general['no'], 0, $year, $month); - $logger->pushGeneralHistoryLog("특기 【{$specialWarName}】{$josaUl} 습득"); - $logger->pushGeneralActionLog("특기 【{$specialWarName}】{$josaUl} 익혔습니다!",ActionLogger::PLAIN); - $logger->flush(); - } - break; case "경험치1000": $text = $btn . " 지급!"; @@ -330,26 +308,6 @@ switch ($btn) { 'brief' => '해산', ], 'general_id IN %li AND turn_idx = 1', $genlist); break; - case "00턴": - $turnterm = $gameStor->turnterm; - - foreach ($genlist as $generalID) { - $turntime = getRandTurn($turnterm); - $cutTurn = cutTurn($turntime, $turnterm); - $db->update('general', [ - 'turntime' => $cutTurn - ], '`no` IN %li', $genlist); - } - break; - case "랜덤턴": - $turnterm = $gameStor->turnterm; - foreach ($genlist as $generalID) { - $turntime = getRandTurn($turnterm); - $db->update('general', [ - 'turntime' => $turntime - ], '`no` IN %li', $genlist); - } - break; } header('location:_admin2.php'); diff --git a/hwe/func.php b/hwe/func.php index bde7ffc5..8680cf94 100644 --- a/hwe/func.php +++ b/hwe/func.php @@ -135,11 +135,11 @@ function getBlockLevel() return DB::db()->queryFirstField('select block from general where no = %i', Session::getInstance()->generalID); } -function getRandGenName() +function getRandGenName(RandUtil $rng) { - $firstname = Util::choiceRandom(GameConst::$randGenFirstName); - $middlename = Util::choiceRandom(GameConst::$randGenMiddleName); - $lastname = Util::choiceRandom(GameConst::$randGenLastName); + $firstname = $rng->choice(GameConst::$randGenFirstName); + $middlename = $rng->choice(GameConst::$randGenMiddleName); + $lastname = $rng->choice(GameConst::$randGenLastName); return "{$firstname}{$middlename}{$lastname}"; } @@ -1343,7 +1343,7 @@ function turnDate($curtime) } -function triggerTournament() +function triggerTournament(RandUtil $rng) { $db = DB::db(); $gameStor = KVStorage::getStorage($db, 'game_env'); @@ -1357,7 +1357,7 @@ function triggerTournament() if ($tnmt_trig == 0) { return; } - if (!Util::randBool(0.4)) { + if (!$rng->nextBool(0.4)) { return; } @@ -1552,7 +1552,7 @@ function CheckHall($no) } } -function giveRandomUniqueItem(General $general, string $acquireType): bool +function giveRandomUniqueItem(RandUtil $rng, General $general, string $acquireType): bool { $db = DB::db(); //아이템 습득 상황 @@ -1643,7 +1643,7 @@ function giveRandomUniqueItem(General $general, string $acquireType): bool } } - [$itemType, $itemCode] = Util::choiceRandomUsingWeightPair($availableUnique); + [$itemType, $itemCode] = $rng->choiceUsingWeightPair($availableUnique); $nationName = $general->getStaticNation()['name']; $generalName = $general->getName(); @@ -1722,12 +1722,12 @@ function rollbackInheritUniqueTrial(General $general, string $itemKey, string $r $msg->send(true); } -function tryRollbackInheritUniqueItem(General $general): void +function tryRollbackInheritUniqueItem(RandUtil $rng, General $general): void { - tryInheritUniqueItem($general, 'Rollback', true); + tryInheritUniqueItem($rng, $general, 'Rollback', true); } -function tryInheritUniqueItem(General $general, string $acquireType = '아이템', bool $justRollback = false): bool +function tryInheritUniqueItem(RandUtil $rng, General $general, string $acquireType = '아이템', bool $justRollback = false): bool { $ownerID = $general->getVar('owner'); if (!$ownerID) { @@ -1779,7 +1779,7 @@ function tryInheritUniqueItem(General $general, string $acquireType = '아이템 } $reasons = []; - $itemType = Util::choiceRandom($availableItemTypes); + $itemType = $rng->choice($availableItemTypes); $trialStor = KVStorage::getStorage($db, "ut_{$itemKey}"); //혹시 itemKey의 크기가 37이 넘을 수 있을까? $anyTrials = $trialStor->getAll(); @@ -1865,12 +1865,12 @@ function tryInheritUniqueItem(General $general, string $acquireType = '아이템 $general->applyDB($db); //같은 종류의 유니크를 입찰했을 수 있으니 한번 더 검사한다. - tryRollbackInheritUniqueItem($general); + tryRollbackInheritUniqueItem($rng, $general); return true; } -function tryUniqueItemLottery(General $general, string $acquireType = '아이템'): bool +function tryUniqueItemLottery(RandUtil $rng, General $general, string $acquireType = '아이템'): bool { $db = DB::db(); $gameStor = KVStorage::getStorage($db, 'game_env'); @@ -1915,13 +1915,13 @@ function tryUniqueItemLottery(General $general, string $acquireType = '아이템 $userLogger = new UserLogger($general->getVar('owner')); $userLogger->push(sprintf("유니크를 얻을 공간이 없어 %d 포인트 반환", GameConst::$inheritItemRandomPoint), "inheritPoint"); } - tryRollbackInheritUniqueItem($general); + tryRollbackInheritUniqueItem($rng, $general); return false; } $inheritUnique = $general->getAuxVar('inheritUniqueTrial'); if ($acquireType != '설문조사' && $inheritUnique && count($inheritUnique) && $availableBuyUnique) { - $trialResult = tryInheritUniqueItem($general, $acquireType); + $trialResult = tryInheritUniqueItem($rng, $general, $acquireType); if ($trialResult) { return true; } @@ -1956,7 +1956,7 @@ function tryUniqueItemLottery(General $general, string $acquireType = '아이템 } foreach (Util::range($maxCnt) as $_idx) { - if (Util::randBool($prob)) { + if ($rng->nextBool($prob)) { $result = true; break; } @@ -1968,7 +1968,7 @@ function tryUniqueItemLottery(General $general, string $acquireType = '아이템 } LogText("{$general->getName()}, {$general->getID()} 유니크 성공 {$maxCnt}", $prob); - return giveRandomUniqueItem($general, $acquireType); + return giveRandomUniqueItem($rng, $general, $acquireType); } function getAdmin() @@ -2415,7 +2415,7 @@ function isNeighbor(int $nation1, int $nation2, bool $includeNoSupply = true) return false; } -function SabotageInjury(array $cityGeneralList, string $reason): int +function SabotageInjury(RandUtil $rng, array $cityGeneralList, string $reason): int { $injuryCount = 0; $josaRo = JosaUtil::pick($reason, '로'); @@ -2427,12 +2427,12 @@ function SabotageInjury(array $cityGeneralList, string $reason): int /** @var General $general */ $injuryProb = 0.3; $injuryProb = $general->onCalcStat($general, 'injuryProb', $injuryProb); - if (!Util::randBool($injuryProb)) { + if (!$rng->nextBool($injuryProb)) { continue; } $general->getLogger()->pushGeneralActionLog($text); - $general->increaseVarWithLimit('injury', Util::randRangeInt(1, 16), 0, 80); + $general->increaseVarWithLimit('injury', $rng->nextRangeInt(1, 16), 0, 80); $general->multiplyVar('crew', 0.98); $general->multiplyVar('atmos', 0.98); $general->multiplyVar('train', 0.98); @@ -2445,7 +2445,7 @@ function SabotageInjury(array $cityGeneralList, string $reason): int return $injuryCount; } -function getRandTurn($term, ?\DateTimeInterface $baseDateTime = null) +function getRandTurn(RandUtil $rng, $term, ?\DateTimeInterface $baseDateTime = null) { if ($baseDateTime === null) { $baseDateTime = new \DateTimeImmutable(); @@ -2457,13 +2457,13 @@ function getRandTurn($term, ?\DateTimeInterface $baseDateTime = null) throw new MustNotBeReachedException(); } - $randSecond = Util::randRangeInt(0, 60 * $term - 1); - $randFraction = Util::randRangeInt(0, 999999) / 1000000; //6자리 소수 + $randSecond = $rng->nextRangeInt(0, 60 * $term - 1); + $randFraction = $rng->nextRangeInt(0, 999999) / 1000000; //6자리 소수 return TimeUtil::format($baseDateTime->add(TimeUtil::secondsToDateInterval($randSecond + $randFraction)), true); } -function getRandTurn2($term, ?\DateTimeInterface $baseDateTime = null) +function getRandTurn2(RandUtil $rng, $term, ?\DateTimeInterface $baseDateTime = null) { if ($baseDateTime === null) { $baseDateTime = new \DateTimeImmutable(); @@ -2472,8 +2472,8 @@ function getRandTurn2($term, ?\DateTimeInterface $baseDateTime = null) } else { throw new MustNotBeReachedException(); } - $randSecond = Util::randRangeInt(0, 60 * $term - 1); - $randFraction = Util::randRangeInt(0, 999999) / 1000000; //6자리 소수 + $randSecond = $rng->nextRangeInt(0, 60 * $term - 1); + $randFraction = $rng->nextRangeInt(0, 999999) / 1000000; //6자리 소수 return $baseDateTime->sub(TimeUtil::secondsToDateInterval($randSecond + $randFraction))->format('Y-m-d H:i:s.u'); } diff --git a/hwe/func_converter.php b/hwe/func_converter.php index 8969efab..bc603fc9 100644 --- a/hwe/func_converter.php +++ b/hwe/func_converter.php @@ -405,10 +405,10 @@ function getGeneralPoolClass(string $type){ * @param null|string $prefix * @return AbsGeneralPool[] */ -function pickGeneralFromPool(\MeekroDB $db, int $owner, int $pickCnt, ?string $prefix=null):array{ +function pickGeneralFromPool(\MeekroDB $db, RandUtil $rng, int $owner, int $pickCnt, ?string $prefix=null):array{ /** @var AbsGeneralPool */ $class = getGeneralPoolClass(GameConst::$targetGeneralPool); - return $class::pickGeneralFromPool($db, $owner, $pickCnt, $prefix); + return $class::pickGeneralFromPool($db, $rng, $owner, $pickCnt, $prefix); } function countPureGeneralFromRawList(?array $rawGeneralList=null):int{ diff --git a/hwe/func_gamerule.php b/hwe/func_gamerule.php index 06abca85..da488e7c 100644 --- a/hwe/func_gamerule.php +++ b/hwe/func_gamerule.php @@ -333,7 +333,7 @@ EOD), } // 외교 로그처리, 외교 상태 처리 -function postUpdateMonthly() +function postUpdateMonthly(RandUtil $rng) { $db = DB::db(); $gameStor = KVStorage::getStorage($db, 'game_env'); @@ -485,12 +485,12 @@ function postUpdateMonthly() $availableWarSettingCnt = KVStorage::getValuesFromInterNamespace($db, 'nation_env', 'available_war_setting_cnt'); foreach ($nations as $nation) { $nationID = $nation['nation']; - if(!key_exists($nationID, $availableWarSettingCnt)){ + if (!key_exists($nationID, $availableWarSettingCnt)) { $availableWarSettingCnt[$nationID] = 0; } } - foreach($availableWarSettingCnt as $nationID=>$cnt){ - if($cnt >= GameConst::$maxAvailableWarSettingCnt){ + foreach ($availableWarSettingCnt as $nationID => $cnt) { + if ($cnt >= GameConst::$maxAvailableWarSettingCnt) { continue; } $cnt = Util::valueFit($cnt + GameConst::$incAvailableWarSettingCnt, 0, GameConst::$maxAvailableWarSettingCnt); @@ -499,7 +499,7 @@ function postUpdateMonthly() //초반이후 방랑군 자동 해체 if ($admin['year'] >= $admin['startyear'] + 2) { - checkWander(); + checkWander($rng); } // 작위 업데이트 updateNationState(); @@ -508,7 +508,7 @@ function postUpdateMonthly() // 천통여부 검사 checkEmperior(); //토너먼트 개시 - triggerTournament(); + triggerTournament($rng); // 시스템 거래건 등록 registerAuction(); //전방설정 @@ -521,7 +521,7 @@ function postUpdateMonthly() } -function checkWander() +function checkWander(RandUtil $rng) { $db = DB::db(); $gameStor = KVStorage::getStorage($db, 'game_env'); @@ -535,7 +535,7 @@ function checkWander() if ($wanderCmd->hasFullConditionMet()) { $logger = $wanderer->getLogger(); $logger->pushGeneralActionLog('초반 제한후 방랑군은 자동 해산됩니다.', ActionLogger::PLAIN); - $wanderCmd->run(); + $wanderCmd->run($rng); $wanderCmd->setNextAvailable(); } } @@ -552,6 +552,9 @@ function updateNationState() $history = array(); $admin = $gameStor->getValues(['killturn', 'year', 'month', 'fiction', 'startyear', 'show_img_level', 'turnterm', 'turntime']); + $year = $admin['year']; + $month = $admin['month']; + $startYear = $admin['startyear']; $assemblerCnts = []; foreach ($db->queryAllLists('SELECT nation,count(no) FROM general WHERE npc = 5 GROUP BY nation') as [$nationID, $assemblerCnt]) { @@ -560,7 +563,9 @@ function updateNationState() 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']); + $nationID = $nation['nation']; + $citycount = $db->queryFirstField('SELECT count(*) FROM city WHERE nation=%i AND level>=4', $nationID); + if ($citycount == 0) { $nationlevel = 0; // 방랑군 @@ -594,26 +599,26 @@ function updateNationState() 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} 자칭"]); + $history[] = "●{$year}년 {$month}월:【작위】{$nation['name']}의 군주가 " . getNationLevel($nationlevel) . "{$josaUl} 자칭하였습니다."; + pushNationHistoryLog($nation['nation'], ["●{$year}년 {$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) . "에 등극"]); + $history[] = "●{$year}년 {$month}월:【작위】{$nation['name']}의 군주가 " . getNationLevel($nationlevel) . "에 등극하였습니다."; + pushNationHistoryLog($nation['nation'], ["●{$year}년 {$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) . "에 임명됨"]); + $history[] = "●{$year}년 {$month}월:【작위】{$nation['name']}의 군주가 " . getNationLevel($nationlevel) . "에 임명되었습니다."; + pushNationHistoryLog($nation['nation'], ["●{$year}년 {$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) . "로 나서다"]); + $history[] = "●{$year}년 {$month}월:【작위】{$nation['name']}의 군주가 독립하여 " . getNationLevel($nationlevel) . "로 나섰습니다."; + pushNationHistoryLog($nation['nation'], ["●{$year}년 {$month}월:{$nation['name']}의 군주가 " . getNationLevel($nationlevel) . "로 나서다"]); break; } @@ -648,7 +653,6 @@ function updateNationState() $uniqueLotteryWeightList = []; - [$startYear, $year] = $gameStor->getValuesAsArray(['startyear', 'year']); $relYear = $year - $startYear; $maxTrialCountByYear = 1; foreach (GameConst::$maxUniqueItemLimit as $tmpVals) { @@ -684,20 +688,37 @@ function updateNationState() $score += 15; } - $score *= 2**$trialCnt; + $score *= 2 ** $trialCnt; $uniqueLotteryWeightList[$nationGen->getID()] = [$nationGen, $score]; } + $nationLevelUpRNG = new RandUtil(new LiteHashDRBG(Util::simpleSerialize( + UniqueConst::$hiddenSeed, + 'nationLevelUp', + $year, + $month, + $nationID + ))); + foreach (Util::range($levelDiff) as $idx) { if (!$uniqueLotteryWeightList) { break; } /** @var General */ - $winnerObj = Util::choiceRandomUsingWeightPair($uniqueLotteryWeightList); + $winnerObj = $nationLevelUpRNG->choiceUsingWeightPair($uniqueLotteryWeightList); unset($uniqueLotteryWeightList[$winnerObj->getID()]); - giveRandomUniqueItem($winnerObj, '작위보상'); + + $givenUniqueRNG = new RandUtil(new LiteHashDRBG(Util::simpleSerialize( + UniqueConst::$hiddenSeed, + 'givenUnique', + $year, + $month, + $nationID, + $winnerObj->getID(), + ))); + giveRandomUniqueItem($givenUniqueRNG, $winnerObj, '작위보상'); $winnerObj->applyDB($db); } @@ -723,9 +744,18 @@ function updateNationState() if ($assemblerCnt < $maxAssemblerCnt) { $lastAssemblerID = $gameStor->assembler_id ?? 0; + $troopLeaderRng = new RandUtil(new LiteHashDRBG(Util::simpleSerialize( + UniqueConst::$hiddenSeed, + 'troopLeader', + $year, + $month, + $nationID + ))); + while ($assemblerCnt < $maxAssemblerCnt) { $lastAssemblerID += 1; $npcObj = new Scenario\GeneralBuilder( + $troopLeaderRng, sprintf('부대장%4d', $lastAssemblerID), false, null, @@ -1183,7 +1213,8 @@ function checkEmperior() 'aux' => $statGeneral['aux'] ]); - $history = ["●{$admin['year']}년 {$admin['month']}월:【통일】{$nation['name']}{$josaYi} 전토를 통일하였습니다."]; + $hiddenSeed = UniqueConst::$hiddenSeed; + $history = ["●{$admin['year']}년 {$admin['month']}월:【통일】{$nation['name']}{$josaYi} 전토를 통일하였습니다. (서버시드: $hiddenSeed})"]; pushGlobalHistoryLog($history, $admin['year'], $admin['month']); //연감 월결산 @@ -1201,3 +1232,26 @@ function updateMaxDomesticCritical(General $general, $score) $general->setInheritancePoint(InheritanceKey::max_domestic_critical, $maxDomesticCritical); } } + +function genGenericUniqueRNG(int $year, int $month, int $generalID): RandUtil +{ + return new RandUtil(new LiteHashDRBG(Util::simpleSerialize( + UniqueConst::$hiddenSeed, + 'unique', + $year, + $month, + $generalID + ))); +} + +function genGenericUniqueRNGFromGeneral(General $general): RandUtil +{ + $logger = $general->getLogger(); + if (!$logger) { + throw new \Exception('정식 초기화된 객체가 아닙니다.'); + } + $year = $logger->getYear(); + $month = $logger->getMonth(); + $generalID = $general->getID(); + return genGenericUniqueRNG($year, $month, $generalID); +} diff --git a/hwe/func_process.php b/hwe/func_process.php index fd4ab027..41c8a4b8 100644 --- a/hwe/func_process.php +++ b/hwe/func_process.php @@ -3,10 +3,10 @@ namespace sammo; /** * 내정 커맨드 사용시 성공 확률 계산 - * + * * @param General $general 장수 정보 * @param string $type 내정 커맨드 타입, 'leadership' = 통솔 기반, 'strength' = 무력 기반, 'intel' = 지력 기반 - * + * * @return array 계산된 실패, 성공 확률 ('success' => 성공 확률, 'fail' => 실패 확률) */ function CriticalRatioDomestic(General $general, string $type) { @@ -24,7 +24,7 @@ function CriticalRatioDomestic(General $general, string $type) { 506040(33%/30%), 505050(43%/40%), 504060(50%/50%) * 통솔 내정 기준 - 756510(25%/22%), 707010(31%/28%), 657510(38%,35%), + 756510(25%/22%), 707010(31%/28%), 657510(38%,35%), 505050(50%,50%), 107070(50%,50%) */ switch($type) { @@ -60,13 +60,12 @@ function calcLeadershipBonus($officerLevel, $nationLevel):int{ return $lbonus; } -function CriticalScoreEx(string $type):float { +function CriticalScoreEx(RandUtil $rng, string $type):float { if ($type == 'success') { - return Util::randRange(2.2, 3.0); + return $rng->nextRange(2.2, 3.0); } if ($type == 'fail') { - return Util::randRange(0.2, 0.4); + return $rng->nextRange(0.2, 0.4); } return 1; } - diff --git a/hwe/func_template.php b/hwe/func_template.php index 26e5c7a7..f44e18e9 100644 --- a/hwe/func_template.php +++ b/hwe/func_template.php @@ -60,7 +60,8 @@ function chiefTurnTable() "; } -function templateLimitMsg(string $turntime): string{ +function templateLimitMsg(string $turntime): string +{ return "이미 너무 많은 접속을 하셨습니다. 다음 턴에 다시 시도해주세요. (턴시간: {$turntime})"; } @@ -165,7 +166,7 @@ function commandButton(array $opts = []) 'color' => '#000000' ]; - $bgColor = Util::array_get($nation['color']) ?: '#000000'; + $bgColor = $nation['color'] ?? '#000000'; $fgColor = newColor($bgColor); $templates = new \League\Plates\Engine(__DIR__ . '/templates'); @@ -173,16 +174,16 @@ function commandButton(array $opts = []) $permission = checkSecretPermission($me); $btnClassForTournament = $opts['btnClass']; if ($opts['isTournamentApplicationOpen']) { - if ($btnClassForTournament != 'dropdown-item') { - $btnClassForTournament = 'toolbarButton2'; - } + if ($btnClassForTournament != 'dropdown-item') { + $btnClassForTournament = 'toolbarButton2'; + } } $btnClassForBetting = $opts['btnClass']; if ($opts['isBettingActive']) { - if ($btnClassForTournament != 'dropdown-item') { - $btnClassForBetting = 'toolbarButton2'; - } + if ($btnClassForTournament != 'dropdown-item') { + $btnClassForBetting = 'toolbarButton2'; + } } if ($permission >= 1) { @@ -246,7 +247,7 @@ function getMapHtml(?string $mapName = null) { $templates = new \League\Plates\Engine(__DIR__ . '/templates'); - if($mapName === null){ + if ($mapName === null) { $mapName = GameConst::$mapName; } diff --git a/hwe/func_time_event.php b/hwe/func_time_event.php index 5ed7e025..f0d6912a 100644 --- a/hwe/func_time_event.php +++ b/hwe/func_time_event.php @@ -513,7 +513,7 @@ function getOutcome(float $billRate, array $generalList) { return $outcome; } -function tradeRate() { +function tradeRate(RandUtil $rng) { $db = DB::db(); foreach($db->query('SELECT city,level FROM city') as $city){ @@ -528,8 +528,8 @@ function tradeRate() { 7=>0.8, 8=>1 ][$city['level']]; - if($prob > 0 && Util::randBool($prob)) { - $trade = Util::randRangeInt(95, 105); + if($prob > 0 && $rng->nextBool($prob)) { + $trade = $rng->nextRangeInt(95, 105); } else { $trade = null; } @@ -539,7 +539,7 @@ function tradeRate() { } } -function disaster() { +function disaster(RandUtil $rng) { $db = DB::db(); $gameStor = KVStorage::getStorage($db, 'game_env'); @@ -560,7 +560,7 @@ function disaster() { 10=>0 ]; - $isGood = Util::randBool($boomingRate[$month]); + $isGood = $rng->nextBool($boomingRate[$month]); $targetCityList = []; @@ -575,7 +575,7 @@ function disaster() { $raiseProp = 0.06 - ($city['secu'] / $city['secu_max']) * 0.05; // 1 ~ 6% } - if(Util::randBool($raiseProp)) { + if($rng->nextBool($raiseProp)) { $targetCityList[] = $city; } } @@ -621,7 +621,7 @@ function disaster() { 10 => null ]; - [$logTitle, $stateCode, $logBody] = Util::choiceRandom(($isGood?$boomingTextList:$disasterTextList)[$month]); + [$logTitle, $stateCode, $logBody] = $rng->choice(($isGood?$boomingTextList:$disasterTextList)[$month]); $logger = new ActionLogger(0, 0, $year, $month, false); @@ -653,7 +653,7 @@ function disaster() { $generalListByCity[$city['city']]??[] ); - SabotageInjury($generalList, '재난'); + SabotageInjury($rng, $generalList, '재난'); } } else{ diff --git a/hwe/func_tournament.php b/hwe/func_tournament.php index 5c4d9ecb..ffdaef12 100644 --- a/hwe/func_tournament.php +++ b/hwe/func_tournament.php @@ -448,12 +448,18 @@ function startBetting($type, $unit) $betGold = Util::valueFit(floor((3 + $year - $startyear) * 0.334) * 10, 10); + $rng = new RandUtil(new LiteHashDRBG(Util::simpleSerialize( + UniqueConst::$hiddenSeed, + 'OpenBettingTournament', + $bettingID, + ))); + $npcList = $db->queryFirstColumn('SELECT no FROM general WHERE npc >= 2 AND gold >= (500 + %i)', $betGold); $npcBet = []; $targetList = array_keys($candidates); foreach ($npcList as $npcID) { - $target = Util::choiceRandom($targetList); + $target = $rng->choice($targetList); $npcBet[] = [$npcID, $target]; } diff --git a/hwe/j_get_select_npc_token.php b/hwe/j_get_select_npc_token.php index 03c6398c..ec6d0344 100644 --- a/hwe/j_get_select_npc_token.php +++ b/hwe/j_get_select_npc_token.php @@ -110,10 +110,17 @@ foreach($db->queryFirstColumn('SELECT pick_result FROM select_npc_token WHERE `o } } +$rng = new RandUtil(new LiteHashDRBG(Util::simpleSerialize( + UniqueConst::$hiddenSeed, + 'SelectNPCToken', + $userID, + $now, +))); + $pickLimit = min(count($candidates), 5); while(count($pickResult) < $pickLimit){ - $generalID = Util::choiceRandomUsingWeight($weight); + $generalID = $rng->choiceUsingWeight($weight); if(!key_exists($generalID, $pickResult)){ $pickResult[$generalID] = $candidates[$generalID]; } diff --git a/hwe/j_get_select_pool.php b/hwe/j_get_select_pool.php index 5c2d838d..3696f142 100644 --- a/hwe/j_get_select_pool.php +++ b/hwe/j_get_select_pool.php @@ -74,9 +74,13 @@ if($tokens){ ]); } +$rng = new RandUtil(new LiteHashDRBG(Util::simpleSerialize( + UniqueConst::$hiddenSeed, 'selectPool', $userID, $now +))); + $pick = []; $valid_until = null; -foreach(pickGeneralFromPool($db, $userID, 14) as $pickObj){ +foreach(pickGeneralFromPool($db, $rng, $userID, 14) as $pickObj){ $valid_until = $pickObj->getValidUntil(); $info = $pickObj->getInfo(); putInfoText($info); diff --git a/hwe/j_install.php b/hwe/j_install.php index c5f3547d..43301a3d 100644 --- a/hwe/j_install.php +++ b/hwe/j_install.php @@ -144,7 +144,7 @@ $autorun_user = $autorun_user_minutes?[ if($reserve_open){ $reserve_open = new \DateTime($reserve_open); $db = DB::db(); - + if (!$db->queryFirstField("SHOW TABLES LIKE 'storage'")) { $clearResult = ResetHelper::clearDB(); if(!$clearResult['result']){ @@ -159,7 +159,9 @@ if($reserve_open){ ]); } - $scenarioObj = new Scenario($scenario, true); + $rng = new RandUtil(new LiteHashDRBG(random_bytes(16))); + + $scenarioObj = new Scenario($rng, $scenario, true); $open_date = $reserve_open->format('Y-m-d H:i:s'); $reserveInfo = [ @@ -179,14 +181,14 @@ if($reserve_open){ 'autorun_user'=>$autorun_user ]; - + if($pre_reserve_open){ $pre_reserve_open = new \DateTime($pre_reserve_open); $open_date = $pre_reserve_open->format('Y-m-d H:i:s'); } - + $db->delete('reserved_open', true); $db->insert('reserved_open', [ 'options'=>Json::encode($reserveInfo), diff --git a/hwe/j_select_picked_general.php b/hwe/j_select_picked_general.php index af50d30a..d5f99e96 100644 --- a/hwe/j_select_picked_general.php +++ b/hwe/j_select_picked_general.php @@ -103,7 +103,7 @@ foreach(GameConst::$generalPoolAllowOption as $allowOption){ } else if($allowOption == 'ego'){ if(!$personal || $personal == 'Random'){ - $personal = Util::choiceRandom(GameConst::$availablePersonality); + $personal = Util::choiceRandom(GameConst::$availablePersonality); } if(!array_search($personal, GameConst::$availablePersonality)){ Json::die([ diff --git a/hwe/j_simulate_battle.php b/hwe/j_simulate_battle.php index ac89c241..ab9ffccf 100644 --- a/hwe/j_simulate_battle.php +++ b/hwe/j_simulate_battle.php @@ -300,12 +300,17 @@ function simulateBattle( $rawDefenderList, $rawDefenderCity, $rawDefenderNation, $startYear, $year, $month, $cityRate ){ + + $warSeed = bin2hex(random_bytes(16)); + $warRng = new RandUtil(new LiteHashDRBG($warSeed)); + $attacker = new WarUnitGeneral( + $warRng, new General($rawAttacker, extractRankVar($rawAttacker), $rawAttackerCity, $rawAttackerNation, $year, $month), $rawAttackerNation, true ); - $city = new WarUnitCity($rawDefenderCity, $rawDefenderNation, $year, $month, $cityRate); + $city = new WarUnitCity($warRng, $rawDefenderCity, $rawDefenderNation, $year, $month, $cityRate); $iterDefender = new \ArrayIterator($rawDefenderList); $iterDefender->rewind(); @@ -316,7 +321,7 @@ function simulateBattle( $defenderRice = 0; $getNextDefender = function(?WarUnit $prevDefender, bool $reqNext) - use ($iterDefender, $rawDefenderCity, $rawDefenderNation, $year, $month, &$battleResult, &$defenderRice) { + use ($warRng, $iterDefender, $rawDefenderCity, $rawDefenderNation, $year, $month, &$battleResult, &$defenderRice) { if($prevDefender !== null){ $prevDefender->getLogger()->rollback(); $battleResult[] = $prevDefender; @@ -341,6 +346,7 @@ function simulateBattle( $defenderRice += $defenderObj->getVar('rice'); $retVal = new WarUnitGeneral( + $warRng, $defenderObj, $rawDefenderNation, false @@ -349,7 +355,7 @@ function simulateBattle( return $retVal; }; - $conquerCity = processWar_NG($attacker, $getNextDefender, $city, $year - $startYear); + $conquerCity = processWar_NG($warSeed, $attacker, $getNextDefender, $city, $year - $startYear); $rawDefenderCity = $city->getRaw(); $updateAttackerNation = []; diff --git a/hwe/process_war.php b/hwe/process_war.php index 4c600456..d910ade6 100644 --- a/hwe/process_war.php +++ b/hwe/process_war.php @@ -3,9 +3,10 @@ namespace sammo; -function processWar(General $attackerGeneral, array $rawAttackerNation, array $rawDefenderCity) +function processWar(string $warSeed, General $attackerGeneral, array $rawAttackerNation, array $rawDefenderCity) { + $rng = new RandUtil(new LiteHashDRBG($warSeed)); $db = DB::db(); $attackerNationID = $attackerGeneral->getNationID(); @@ -30,9 +31,9 @@ function processWar(General $attackerGeneral, array $rawAttackerNation, array $r $gameStor = KVStorage::getStorage($db, 'game_env'); [$startYear, $year, $month, $cityRate, $joinMode] = $gameStor->getValuesAsArray(['startyear', 'year', 'month', 'city_rate', 'join_mode']); - $attacker = new WarUnitGeneral($attackerGeneral, $rawAttackerNation, true); + $attacker = new WarUnitGeneral($rng, $attackerGeneral,$rawAttackerNation, true); - $city = new WarUnitCity($rawDefenderCity, $rawDefenderNation, $year, $month, $cityRate); + $city = new WarUnitCity($rng, $rawDefenderCity, $rawDefenderNation, $year, $month, $cityRate); $defenderIDList = $db->queryFirstColumn('SELECT no FROM general WHERE nation=%i AND city=%i AND nation!=0 and crew > 0 and rice>(crew/100) and train>=defence_train and atmos>=defence_train', $city->getVar('nation'), $city->getVar('city')); $defenderList = General::createGeneralObjListFromDB($defenderIDList, null, 2); @@ -44,7 +45,7 @@ function processWar(General $attackerGeneral, array $rawAttackerNation, array $r $iterDefender = new \ArrayIterator($defenderList); $iterDefender->rewind(); - $getNextDefender = function (?WarUnit $prevDefender, bool $reqNext) use ($iterDefender, $rawDefenderNation, $rawDefenderCity, $db) { + $getNextDefender = function (?WarUnit $prevDefender, bool $reqNext) use ($rng, $iterDefender, $rawDefenderNation, $rawDefenderCity, $db) { if ($prevDefender !== null) { $prevDefender->applyDB($db); } @@ -65,6 +66,7 @@ function processWar(General $attackerGeneral, array $rawAttackerNation, array $r $retVal = new WarUnitGeneral( + $rng, $nextDefender, $rawDefenderNation, false @@ -73,7 +75,7 @@ function processWar(General $attackerGeneral, array $rawAttackerNation, array $r return $retVal; }; - $conquerCity = processWar_NG($attacker, $getNextDefender, $city, $year - $startYear); + $conquerCity = processWar_NG($warSeed, $attacker, $getNextDefender, $city, $year - $startYear); $attacker->applyDB($db); @@ -206,6 +208,7 @@ function extractBattleOrder(General $general) } function processWar_NG( + string $warSeed, WarUnitGeneral $attacker, callable $getNextDefender, WarUnitCity $city, @@ -228,8 +231,8 @@ function processWar_NG( $josaRo = JosaUtil::pick($city->getName(), '로'); $josaYi = JosaUtil::pick($attacker->getName(), '이'); - $logger->pushGlobalActionLog("{$attacker->getNationVar('name')}{$attacker->getName()}{$josaYi} {$city->getName()}{$josaRo} 진격합니다."); - $logger->pushGeneralActionLog("{$city->getName()}{$josaRo} 진격합니다. <1>$date"); + $logger->pushGlobalActionLog("{$attacker->getNationVar('name')}{$attacker->getName()}{$josaYi} {$city->getName()}{$josaRo} 진격합니다.(전투시드: {$warSeed})"); + $logger->pushGeneralActionLog("{$city->getName()}{$josaRo} 진격합니다.(전투시드: {$warSeed}) <1>$date"); $logWritten = false; @@ -309,7 +312,7 @@ function processWar_NG( $initCaller = $attacker->getGeneral()->getBattleInitSkillTriggerList($attacker); $initCaller->merge($defender->getGeneral()->getBattleInitSkillTriggerList($defender)); - $initCaller->fire([], [$attacker, $defender]); + $initCaller->fire($attacker->rng, [], [$attacker, $defender]); } $attacker->beginPhase(); @@ -318,7 +321,7 @@ function processWar_NG( $battleCaller = $attacker->getGeneral()->getBattlePhaseSkillTriggerList($attacker); $battleCaller->merge($defender->getGeneral()->getBattlePhaseSkillTriggerList($defender)); - $battleCaller->fire([], [$attacker, $defender]); + $battleCaller->fire($attacker->rng, [], [$attacker, $defender]); $deadDefender = $attacker->calcDamage(); $deadAttacker = $defender->calcDamage(); @@ -510,6 +513,16 @@ function ConquerCity(array $admin, General $general, array $city) $cityID = $city['city']; $cityName = $city['name']; + $rng = new RandUtil(new LiteHashDRBG(Util::simpleSerialize( + UniqueConst::$hiddenSeed, + 'ConquerCity', + $year, + $month, + $attackerNationID, + $attackerID, + $cityID + ))); + $defenderNationID = $city['nation']; $defenderStaticNation = getNationStaticInfo($defenderNationID); $defenderNationName = $defenderStaticNation['name']; @@ -594,7 +607,7 @@ function ConquerCity(array $admin, General $general, array $city) $oldGeneral->applyDB($db); //모두 등용장 발부 - if ($admin['join_mode'] != 'onlyRandom' && Util::randBool(0.5)) { + if ($admin['join_mode'] != 'onlyRandom' && $rng->nextBool(0.5)) { $msg = ScoutMessage::buildScoutMessage($attackerID, $oldGeneral->getID()); if ($msg) { $msg->send(true); @@ -603,11 +616,11 @@ function ConquerCity(array $admin, General $general, array $city) //NPC인 경우 일정 확률로 임관(엔장, 인재, 의병) $npcType = $oldGeneral->getNPCType(); - if ($admin['join_mode'] != 'onlyRandom' && 2 <= $npcType && $npcType <= 8 && $npcType != 5 && Util::randBool(GameConst::$joinRuinedNPCProp)) { + if ($admin['join_mode'] != 'onlyRandom' && 2 <= $npcType && $npcType <= 8 && $npcType != 5 && $rng->nextBool(GameConst::$joinRuinedNPCProp)) { $cmd = buildGeneralCommandClass('che_임관', $oldGeneral, $admin, [ 'destNationID' => $attackerNationID ]); - $joinTurn = Util::randRangeInt(0, 12); + $joinTurn = $rng->nextRangeInt(0, 12); if ($joinTurn) { _setGeneralCommand(buildGeneralCommandClass('che_견문', $oldGeneral, $admin), iterator_to_array(Util::range($joinTurn))); } diff --git a/hwe/sammo/API/General/Join.php b/hwe/sammo/API/General/Join.php index 8c8563b3..b54cafab 100644 --- a/hwe/sammo/API/General/Join.php +++ b/hwe/sammo/API/General/Join.php @@ -13,11 +13,14 @@ use sammo\InheritancePointManager; use sammo\JosaUtil; use sammo\Json; use sammo\KVStorage; +use sammo\LiteHashDRBG; +use sammo\RandUtil; use sammo\RootDB; use sammo\Session; use sammo\SpecialityHelper; use sammo\StringUtil; use sammo\TimeUtil; +use sammo\UniqueConst; use sammo\UserLogger; use sammo\Util; use sammo\Validator; @@ -162,6 +165,14 @@ class Join extends \sammo\BaseAPI $userLogger = new UserLogger($userID, $admin['year'], $admin['month'], false); + $now = TimeUtil::now(false); + $rng = new RandUtil(new LiteHashDRBG(Util::simpleSerialize( + UniqueConst::$hiddenSeed, + 'MakeGeneral', + $userID, + $now + ))); + if ($inheritCity !== null) { $inheritRequiredPoint += GameConst::$inheritBornCityPoint; } @@ -193,7 +204,7 @@ class Join extends \sammo\BaseAPI $genius = true; } else { // 현재 1% - $genius = Util::randBool(0.01); + $genius = $rng->nextBool(0.01); } if ($genius && $gameStor->genius > 0) { @@ -208,10 +219,12 @@ class Join extends \sammo\BaseAPI $city = $inheritCity; } else { // 공백지에서만 태어나게 - $city = $db->queryFirstField("select city from city where level>=5 and level<=6 and nation=0 order by rand() limit 0,1"); - if (!$city) { - $city = $db->queryFirstField("select city from city where level>=5 and level<=6 order by rand() limit 0,1"); + $cities = $db->queryFirstColumn('SELECT city FROM city where `level`>=5 and `level`<=6 and nation=0'); + if (!$cities) { + $db->queryFirstColumn('SELECT city FROM city where `level`>=5 and `level`<=6'); + $cities = $db->queryFirstField("SELECT city from city where `level`>=5 and `level`<=6"); } + $city = $rng->choice($cities); } if ($inheritBonusStat) { @@ -221,8 +234,8 @@ class Join extends \sammo\BaseAPI $pleadership = 0; $pstrength = 0; $pintel = 0; - foreach (Util::range(Util::randRangeInt(3, 5)) as $statIdx) { - switch (Util::choiceRandomUsingWeight([$leadership, $strength, $intel])) { + foreach (Util::range($rng->nextRangeInt(3, 5)) as $statIdx) { + switch ($rng->choiceUsingWeight([$leadership, $strength, $intel])) { case 0: $pleadership++; break; @@ -242,14 +255,14 @@ class Join extends \sammo\BaseAPI $relYear = Util::valueFit($admin['year'] - $admin['startyear'], 0); - $age = 20 + ($pleadership + $pstrength + $pintel) * 2 - (mt_rand(0, 1)); + $age = 20 + ($pleadership + $pstrength + $pintel) * 2 - $rng->nextRangeInt(0, 1); // 아직 남았고 천재등록상태이면 특기 부여 if ($genius) { $specage2 = $age; if ($inheritSpecial) { $special2 = $inheritSpecial; } else { - $special2 = SpecialityHelper::pickSpecialWar([ + $special2 = SpecialityHelper::pickSpecialWar($rng, [ 'leadership' => $leadership, 'strength' => $strength, 'intel' => $intel, @@ -290,12 +303,12 @@ class Join extends \sammo\BaseAPI $userLogger->push(sprintf("턴 시간 %02d:%02d 로 지정", intdiv($inheritTurntime, 60), $inheritTurntime%60), "inheritPoint"); - $inheritTurntime += Util::randRangeInt(0, 999999) / 1000000; + $inheritTurntime += $rng->nextRangeInt(0, 999999) / 1000000; $turntime = new \DateTimeImmutable(cutTurn($admin['turntime'], $admin['turnterm'])); $turntime = $turntime->add(TimeUtil::secondsToDateInterval($inheritTurntime)); $turntime = TimeUtil::format($turntime, true); } else { - $turntime = getRandTurn($admin['turnterm'], new \DateTimeImmutable($admin['turntime'])); + $turntime = getRandTurn($rng, $admin['turnterm'], new \DateTimeImmutable($admin['turntime'])); } @@ -315,7 +328,7 @@ class Join extends \sammo\BaseAPI //성격 랜덤시 if (!in_array($character, GameConst::$availablePersonality)) { - $character = Util::choiceRandom(GameConst::$availablePersonality); + $character = $rng->choice(GameConst::$availablePersonality); } //상성 랜덤 $affinity = rand() % 150 + 1; diff --git a/hwe/sammo/API/InheritAction/ResetTurnTime.php b/hwe/sammo/API/InheritAction/ResetTurnTime.php index 89a44e0f..479608a6 100644 --- a/hwe/sammo/API/InheritAction/ResetTurnTime.php +++ b/hwe/sammo/API/InheritAction/ResetTurnTime.php @@ -10,7 +10,10 @@ use sammo\Enums\RankColumn; use sammo\GameConst; use sammo\General; use sammo\KVStorage; +use sammo\LiteHashDRBG; +use sammo\RandUtil; use sammo\TimeUtil; +use sammo\UniqueConst; use sammo\UserLogger; use sammo\Util; @@ -59,7 +62,14 @@ class ResetTurnTime extends \sammo\BaseAPI $currTurnTime = new DateTimeImmutable($general->getTurnTime()); $serverTurnTimeObj = new DateTimeImmutable($serverTurnTime); - $afterTurn = Util::randRange($turnTerm * -60 / 2, $turnTerm * 60 / 2); + $rng = new RandUtil(new LiteHashDRBG(Util::simpleSerialize( + UniqueConst::$hiddenSeed, + 'ResetTurnTime', + $userID, + $general->getTurnTime() + ))); + + $afterTurn = $rng->nextRange($turnTerm * -60 / 2, $turnTerm * 60 / 2); $userLogger = new UserLogger($userID); if($afterTurn >= 0){ diff --git a/hwe/sammo/API/Vote/Vote.php b/hwe/sammo/API/Vote/Vote.php index d70c4334..7ecc5220 100644 --- a/hwe/sammo/API/Vote/Vote.php +++ b/hwe/sammo/API/Vote/Vote.php @@ -8,7 +8,11 @@ use sammo\DTO\VoteInfo; use sammo\General; use sammo\Json; use sammo\KVStorage; +use sammo\LiteHashDRBG; +use sammo\RandUtil; use sammo\Session; +use sammo\UniqueConst; +use sammo\Util; use sammo\Validator; use Symfony\Component\Lock\LockFactory; use Symfony\Component\Lock\Store\SemaphoreStore; @@ -102,7 +106,13 @@ class Vote extends \sammo\BaseAPI $general = General::createGeneralObjFromDB($generalID, ['gold', 'horse', 'weapon', 'book', 'item', 'npc', 'imgsvr', 'picture', 'aux'], 2); $general->increaseVar('gold', $voteReward); - $wonLottery = tryUniqueItemLottery($general, '설문조사'); + $uniqueRng = new RandUtil(new LiteHashDRBG(Util::simpleSerialize( + UniqueConst::$hiddenSeed, + 'voteUnique', + $voteID, + $generalID + ))); + $wonLottery = tryUniqueItemLottery($uniqueRng, $general, '설문조사'); $general->applyDB($db); diff --git a/hwe/sammo/AbsFromUserPool.php b/hwe/sammo/AbsFromUserPool.php index 344f6957..4fca0fac 100644 --- a/hwe/sammo/AbsFromUserPool.php +++ b/hwe/sammo/AbsFromUserPool.php @@ -24,7 +24,7 @@ abstract class AbsFromUserPool extends AbsGeneralPool{ return $db->affectedRows()!=0; } - static public function pickGeneralFromPool(\MeekroDB $db, int $owner, int $pickCnt, ?string $prefix=null):array{ + static public function pickGeneralFromPool(\MeekroDB $db, RandUtil $rng, int $owner, int $pickCnt, ?string $prefix=null):array{ $oNow = new \DateTimeImmutable(); $now = $oNow->format('Y-m-d H:i:s'); @@ -48,7 +48,7 @@ abstract class AbsFromUserPool extends AbsGeneralPool{ $result = []; $validUntil = TimeUtil::nowAddMinutes(2 * $gameStor->turnterm); while(count($result) < $pickCnt){ - $cand = Util::choiceRandomUsingWeightPair($pool); + $cand = $rng->choiceUsingWeightPair($pool); $poolID = $cand['id']; if(key_exists($poolID, $result)){ continue; @@ -64,7 +64,7 @@ abstract class AbsFromUserPool extends AbsGeneralPool{ if($db->affectedRows()==0){ continue; } - $result[$poolID] = new static($db, $candInfo, $validUntil); + $result[$poolID] = new static($db, $rng, $candInfo, $validUntil); } return array_values($result); diff --git a/hwe/sammo/AbsGeneralPool.php b/hwe/sammo/AbsGeneralPool.php index 805f16f4..64252ed3 100644 --- a/hwe/sammo/AbsGeneralPool.php +++ b/hwe/sammo/AbsGeneralPool.php @@ -20,27 +20,28 @@ abstract class AbsGeneralPool{ * generalName * imgsvr * picture - * + * * leadership * strength * intel - * + * * experience * dedication - * + * * dex[5] - * + * * specialDomestic * specialWar */ - public function __construct(\MeekroDB $db, array $info, string $validUntil) + public function __construct(\MeekroDB $db, RandUtil $rng, array $info, string $validUntil) { $this->db = $db; $this->info = $info; $this->uniqueName = $info['uniqueName']; $this->generalName = $info['generalName']; $this->builder = new GeneralBuilder( + $rng, $info['generalName'], $info['imgsvr'], $info['picture'], @@ -97,14 +98,14 @@ abstract class AbsGeneralPool{ /** * @param \MeekroDB $db - * @param int $owner - * @param int $pickCnt + * @param int $owner + * @param int $pickCnt * @param null|string $prefix * @return AbsGeneralPool[] */ - static abstract public function pickGeneralFromPool(\MeekroDB $db, int $owner, int $pickCnt, ?string $prefix=null):array; + static abstract public function pickGeneralFromPool(\MeekroDB $db, RandUtil $rng, int $owner, int $pickCnt, ?string $prefix=null):array; abstract public function occupyGeneralName():bool; - + abstract public static function getPoolName():string; abstract public static function initPool(\MeekroDB $db); diff --git a/hwe/sammo/ActionItem/che_보물_도기.php b/hwe/sammo/ActionItem/che_보물_도기.php index d85da20d..ee1d67c4 100644 --- a/hwe/sammo/ActionItem/che_보물_도기.php +++ b/hwe/sammo/ActionItem/che_보물_도기.php @@ -6,6 +6,7 @@ use sammo\DB; use \sammo\iAction; use \sammo\General; use sammo\KVStorage; +use sammo\RandUtil; use sammo\Util; class che_보물_도기 extends \sammo\BaseItem @@ -17,7 +18,7 @@ class che_보물_도기 extends \sammo\BaseItem protected $cost = 200; protected $consumable = false; - public function onArbitraryAction(General $general, string $actionType, ?string $phase = null, $aux = null): ?array + public function onArbitraryAction(General $general, RandUtil $rng, string $actionType, ?string $phase = null, $aux = null): ?array { if ($aux === null){ return $aux; @@ -39,7 +40,7 @@ class che_보물_도기 extends \sammo\BaseItem $score = 10000 + 5000 * Util::valueFit(intdiv($relYear, 2), 0); - [$resName, $resKey] = Util::choiceRandom([ + [$resName, $resKey] = $rng->choice([ ['금', 'gold'], ['쌀', 'rice'] ]); diff --git a/hwe/sammo/ActionItem/che_저지_삼황내문.php b/hwe/sammo/ActionItem/che_저지_삼황내문.php index 19576c22..f444c0bd 100644 --- a/hwe/sammo/ActionItem/che_저지_삼황내문.php +++ b/hwe/sammo/ActionItem/che_저지_삼황내문.php @@ -22,7 +22,7 @@ class che_저지_삼황내문 extends \sammo\BaseItem{ if($unit->getPhase() >= 2){ return null; } - if($unit->getPhase() == 1 && Util::randBool(0.5)){ + if($unit->getPhase() == 1 && $unit->rng->nextBool(0.5)){ return null; } diff --git a/hwe/sammo/ActionItem/che_치료_환약.php b/hwe/sammo/ActionItem/che_치료_환약.php index 59b4b704..719728af 100644 --- a/hwe/sammo/ActionItem/che_치료_환약.php +++ b/hwe/sammo/ActionItem/che_치료_환약.php @@ -4,6 +4,7 @@ use \sammo\iAction; use \sammo\General; use \sammo\GeneralTrigger; use \sammo\GeneralTriggerCaller; +use sammo\RandUtil; class che_치료_환약 extends \sammo\BaseItem{ @@ -23,7 +24,7 @@ class che_치료_환약 extends \sammo\BaseItem{ ); } - function onArbitraryAction(General $general, string $actionType, ?string $phase = null, $aux = null): ?array + function onArbitraryAction(General $general, RandUtil $rng, string $actionType, ?string $phase = null, $aux = null): ?array { if($actionType != '장비매매'){ return $aux; diff --git a/hwe/sammo/BaseWarUnitTrigger.php b/hwe/sammo/BaseWarUnitTrigger.php index eeb80f44..504683f3 100644 --- a/hwe/sammo/BaseWarUnitTrigger.php +++ b/hwe/sammo/BaseWarUnitTrigger.php @@ -28,7 +28,7 @@ abstract class BaseWarUnitTrigger extends ObjectTrigger{ return "{$priority}_{$fqn}_{$objID}_{$this->raiseType}"; } - public function action(?array $env=null, $arg=null):?array{ + public function action(\sammo\RandUtil $rng, ?array $env=null, $arg=null):?array{ if($env === null){ $env = []; } @@ -46,7 +46,7 @@ abstract class BaseWarUnitTrigger extends ObjectTrigger{ /** @var WarUnitGeneral $attacker */ /** @var WarUnit $defender */ [$attacker, $defender] = $arg; - + /** @var WarUnit $self */ $self = $this->object; $isAttacker = $self->isAttacker(); diff --git a/hwe/sammo/Command/BaseCommand.php b/hwe/sammo/Command/BaseCommand.php index 469d07be..ba49666e 100644 --- a/hwe/sammo/Command/BaseCommand.php +++ b/hwe/sammo/Command/BaseCommand.php @@ -6,7 +6,8 @@ use \sammo\{ General, GameConst, ActionLogger, LastTurn, - NotInheritedMethodException + NotInheritedMethodException, + RandUtil }; use function \sammo\getNationStaticInfo; @@ -473,7 +474,7 @@ abstract class BaseCommand{ abstract public function getPreReqTurn():int; abstract public function getPostReqTurn():int; - abstract public function run():bool; + abstract public function run(RandUtil $rng):bool; public function exportJSVars():array { return []; diff --git a/hwe/sammo/Command/General/che_NPC능동.php b/hwe/sammo/Command/General/che_NPC능동.php index 1b3d8de9..70815485 100644 --- a/hwe/sammo/Command/General/che_NPC능동.php +++ b/hwe/sammo/Command/General/che_NPC능동.php @@ -75,7 +75,7 @@ class che_NPC능동 extends Command\GeneralCommand{ return 0; } - public function run():bool{ + public function run(\Sammo\RandUtil $rng):bool{ if(!$this->hasFullConditionMet()){ throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); } @@ -98,7 +98,7 @@ class che_NPC능동 extends Command\GeneralCommand{ $this->setResultTurn(new LastTurn(static::getName(), $this->arg)); } - tryRollbackInheritUniqueItem($general); + tryRollbackInheritUniqueItem($rng, $general); $general->applyDB($db); return true; diff --git a/hwe/sammo/Command/General/che_강행.php b/hwe/sammo/Command/General/che_강행.php index 23b79c05..ff2ec0b5 100644 --- a/hwe/sammo/Command/General/che_강행.php +++ b/hwe/sammo/Command/General/che_강행.php @@ -111,7 +111,7 @@ class che_강행 extends Command\GeneralCommand return "{$failReason} {$destCityName}{$josaRo} {$commandName} 실패."; } - public function run(): bool + public function run(\Sammo\RandUtil $rng): bool { if (!$this->hasFullConditionMet()) { throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); @@ -156,7 +156,7 @@ class che_강행 extends Command\GeneralCommand $general->increaseVar('leadership_exp', 1); $this->setResultTurn(new LastTurn(static::getName(), $this->arg)); $general->checkStatChange(); - tryUniqueItemLottery($general); + tryUniqueItemLottery(\sammo\genGenericUniqueRNGFromGeneral($general), $general); $general->applyDB($db); diff --git a/hwe/sammo/Command/General/che_거병.php b/hwe/sammo/Command/General/che_거병.php index 2fd6a285..2914f430 100644 --- a/hwe/sammo/Command/General/che_거병.php +++ b/hwe/sammo/Command/General/che_거병.php @@ -59,7 +59,7 @@ class che_거병 extends Command\GeneralCommand{ return 0; } - public function run():bool{ + public function run(\Sammo\RandUtil $rng):bool{ if(!$this->hasFullConditionMet()){ throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); } @@ -174,7 +174,7 @@ class che_거병 extends Command\GeneralCommand{ $this->setResultTurn(new LastTurn(static::getName(), $this->arg)); $general->checkStatChange(); - tryUniqueItemLottery($general); + tryUniqueItemLottery(\sammo\genGenericUniqueRNGFromGeneral($general), $general); $general->applyDB($db); diff --git a/hwe/sammo/Command/General/che_건국.php b/hwe/sammo/Command/General/che_건국.php index 5495d397..7fc17f98 100644 --- a/hwe/sammo/Command/General/che_건국.php +++ b/hwe/sammo/Command/General/che_건국.php @@ -20,6 +20,7 @@ use \sammo\Constraint\ConstraintHelper; use sammo\Enums\InheritanceKey; use function sammo\buildNationTypeClass; +use function sammo\genGenericUniqueRNGFromGeneral; use function sammo\refreshNationStaticInfo; use function sammo\GetNationColors; @@ -126,7 +127,7 @@ class che_건국 extends Command\GeneralCommand return 0; } - public function run(): bool + public function run(\Sammo\RandUtil $rng): bool { if (!$this->hasFullConditionMet()) { throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); @@ -190,7 +191,7 @@ class che_건국 extends Command\GeneralCommand $general->increaseInheritancePoint(InheritanceKey::active_action, 1); $this->setResultTurn(new LastTurn(static::getName(), $this->arg)); $general->checkStatChange(); - tryUniqueItemLottery($general, '건국'); + tryUniqueItemLottery(genGenericUniqueRNGFromGeneral($general), $general, '건국'); $general->applyDB($db); return true; diff --git a/hwe/sammo/Command/General/che_견문.php b/hwe/sammo/Command/General/che_견문.php index c7903fd5..1af237da 100644 --- a/hwe/sammo/Command/General/che_견문.php +++ b/hwe/sammo/Command/General/che_견문.php @@ -51,7 +51,7 @@ class che_견문 extends Command\GeneralCommand{ return 0; } - public function run():bool{ + public function run(\Sammo\RandUtil $rng):bool{ if(!$this->hasFullConditionMet()){ throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); } @@ -99,10 +99,10 @@ class che_견문 extends Command\GeneralCommand{ $text = str_replace(':riceAmount:', '200', $text); } if($type & SightseeingMessage::Wounded){ - $general->increaseVarWithLimit('injury', Util::randRangeInt(10, 20), null, 80); + $general->increaseVarWithLimit('injury', $rng->nextRangeInt(10, 20), null, 80); } if($type & SightseeingMessage::HeavyWounded){ - $general->increaseVarWithLimit('injury', Util::randRangeInt(20, 50), null, 80); + $general->increaseVarWithLimit('injury', $rng->nextRangeInt(20, 50), null, 80); } $logger = $general->getLogger(); @@ -112,7 +112,7 @@ class che_견문 extends Command\GeneralCommand{ $general->addExperience($exp); $this->setResultTurn(new LastTurn(static::getName(), $this->arg)); $general->checkStatChange(); - tryUniqueItemLottery($general); + tryUniqueItemLottery(\sammo\genGenericUniqueRNGFromGeneral($general), $general); $general->applyDB($db); diff --git a/hwe/sammo/Command/General/che_군량매매.php b/hwe/sammo/Command/General/che_군량매매.php index f0af7ca8..1bdad1a1 100644 --- a/hwe/sammo/Command/General/che_군량매매.php +++ b/hwe/sammo/Command/General/che_군량매매.php @@ -98,7 +98,7 @@ class che_군량매매 extends Command\GeneralCommand{ return 0; } - public function run():bool{ + public function run(\Sammo\RandUtil $rng):bool{ if(!$this->hasFullConditionMet()){ throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); } @@ -166,7 +166,7 @@ class che_군량매매 extends Command\GeneralCommand{ $exp = 30; $ded = 50; - $incStat = Util::choiceRandomUsingWeight([ + $incStat = $rng->choiceUsingWeight([ 'leadership_exp'=>$general->getLeadership(false, false, false, false), 'strength_exp'=>$general->getStrength(false, false, false, false), 'intel_exp'=>$general->getIntel(false, false, false, false) @@ -178,7 +178,7 @@ class che_군량매매 extends Command\GeneralCommand{ $this->setResultTurn(new LastTurn(static::getName(), $this->arg)); $general->checkStatChange(); - tryUniqueItemLottery($general); + tryUniqueItemLottery(\sammo\genGenericUniqueRNGFromGeneral($general), $general); $general->applyDB($db); diff --git a/hwe/sammo/Command/General/che_귀환.php b/hwe/sammo/Command/General/che_귀환.php index 7ca7c1f4..30096673 100644 --- a/hwe/sammo/Command/General/che_귀환.php +++ b/hwe/sammo/Command/General/che_귀환.php @@ -58,7 +58,7 @@ class che_귀환 extends Command\GeneralCommand{ return 0; } - public function run():bool{ + public function run(\Sammo\RandUtil $rng):bool{ if(!$this->hasFullConditionMet()){ throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); } @@ -95,7 +95,7 @@ class che_귀환 extends Command\GeneralCommand{ $general->increaseVar('leadership_exp', 1); $this->setResultTurn(new LastTurn(static::getName(), $this->arg)); $general->checkStatChange(); - tryUniqueItemLottery($general); + tryUniqueItemLottery(\sammo\genGenericUniqueRNGFromGeneral($general), $general); $general->applyDB($db); diff --git a/hwe/sammo/Command/General/che_기술연구.php b/hwe/sammo/Command/General/che_기술연구.php index 2ed2c351..6bb824b3 100644 --- a/hwe/sammo/Command/General/che_기술연구.php +++ b/hwe/sammo/Command/General/che_기술연구.php @@ -3,7 +3,7 @@ namespace sammo\Command\General; use \sammo\{ DB, Util, JosaUtil, - General, + General, ActionLogger, LastTurn, Command, GameConst @@ -11,7 +11,7 @@ use \sammo\{ use function sammo\{ TechLimit, - CriticalRatioDomestic, + CriticalRatioDomestic, CriticalScoreEx, tryUniqueItemLottery, updateMaxDomesticCritical @@ -38,11 +38,11 @@ class che_기술연구 extends che_상업투자{ $this->setCity(); $this->setNation(['tech']); - + [$reqGold, $reqRice] = $this->getCost(); $this->fullConditionConstraints=[ - ConstraintHelper::NotBeNeutral(), + ConstraintHelper::NotBeNeutral(), ConstraintHelper::NotWanderingNation(), ConstraintHelper::OccupiedCity(), ConstraintHelper::SuppliedCity(), @@ -53,7 +53,7 @@ class che_기술연구 extends che_상업투자{ $this->reqGold = $reqGold; } - public function run():bool{ + public function run(\Sammo\RandUtil $rng):bool{ if(!$this->hasFullConditionMet()){ throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); } @@ -64,7 +64,7 @@ class che_기술연구 extends che_상업투자{ $trust = Util::valueFit($this->city['trust'], 50); - $score = Util::valueFit($this->calcBaseScore(), 1); + $score = Util::valueFit($this->calcBaseScore($rng), 1); ['success'=>$successRatio, 'fail'=>$failRatio] = CriticalRatioDomestic($general, static::$statKey); if($trust < 80){ @@ -77,9 +77,9 @@ class che_기술연구 extends che_상업투자{ $failRatio = Util::valueFit($failRatio, 0, 1 - $successRatio); $normalRatio = 1 - $failRatio - $successRatio; - $pick = Util::choiceRandomUsingWeight([ - 'fail'=>$failRatio, - 'success'=>$successRatio, + $pick = $rng->choiceUsingWeight([ + 'fail'=>$failRatio, + 'success'=>$successRatio, 'normal'=>$normalRatio ]); @@ -87,14 +87,14 @@ class che_기술연구 extends che_상업투자{ $date = $general->getTurnTime($general::TURNTIME_HM); - $score *= CriticalScoreEx($pick); + $score *= CriticalScoreEx($rng, $pick); $score = Util::round($score); $exp = $score * 0.7; $ded = $score * 1.0; if($pick == 'success'){ - updateMaxDomesticCritical($general, $score); + updateMaxDomesticCritical($general, $score); } else{ $general->setAuxVar('max_domestic_critical', 0); @@ -134,11 +134,11 @@ class che_기술연구 extends che_상업투자{ $this->setResultTurn(new LastTurn(static::getName(), $this->arg)); $general->checkStatChange(); - tryUniqueItemLottery($general); + tryUniqueItemLottery(\sammo\genGenericUniqueRNGFromGeneral($general), $general); $general->applyDB($db); return true; } - + } \ No newline at end of file diff --git a/hwe/sammo/Command/General/che_단련.php b/hwe/sammo/Command/General/che_단련.php index c5fa2d63..b4d18345 100644 --- a/hwe/sammo/Command/General/che_단련.php +++ b/hwe/sammo/Command/General/che_단련.php @@ -3,7 +3,7 @@ namespace sammo\Command\General; use \sammo\{ DB, Util, JosaUtil, - General, + General, ActionLogger, GameConst, GameUnitConst, LastTurn, @@ -35,9 +35,9 @@ class che_단련 extends Command\GeneralCommand{ $this->setNation(); [$reqGold, $reqRice] = $this->getCost(); - + $this->fullConditionConstraints=[ - ConstraintHelper::NotBeNeutral(), + ConstraintHelper::NotBeNeutral(), ConstraintHelper::ReqGeneralCrew(), ConstraintHelper::ReqGeneralValue('train', '훈련', '>=', GameConst::$defaultTrainLow), ConstraintHelper::ReqGeneralValue('atmos', '사기', '>=', GameConst::$defaultAtmosLow), @@ -66,7 +66,7 @@ class che_단련 extends Command\GeneralCommand{ $env = $this->env; return [$env['develcost'], $env['develcost']]; } - + public function getPreReqTurn():int{ return 0; } @@ -75,7 +75,7 @@ class che_단련 extends Command\GeneralCommand{ return 0; } - public function run():bool{ + public function run(\Sammo\RandUtil $rng):bool{ if(!$this->hasFullConditionMet()){ throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); } @@ -85,7 +85,7 @@ class che_단련 extends Command\GeneralCommand{ $general = $this->generalObj; $date = $general->getTurnTime($general::TURNTIME_HM); - [$pick, $multiplier] = Util::choiceRandomUsingWeightPair([ + [$pick, $multiplier] = $rng->choiceUsingWeightPair([ [['success', 3], 0.34], [['normal', 2], 0.33], [['fail', 1], 0.33] @@ -113,7 +113,7 @@ class che_단련 extends Command\GeneralCommand{ $general->addDex($general->getCrewTypeObj(), $score, false); - $incStat = Util::choiceRandomUsingWeight([ + $incStat = $rng->choiceUsingWeight([ 'leadership_exp'=>$general->getLeadership(false, false, false, false), 'strength_exp'=>$general->getStrength(false, false, false, false), 'intel_exp'=>$general->getIntel(false, false, false, false) @@ -126,11 +126,11 @@ class che_단련 extends Command\GeneralCommand{ $general->increaseVar($incStat, 1); $this->setResultTurn(new LastTurn(static::getName(), $this->arg)); $general->checkStatChange(); - tryUniqueItemLottery($general); + tryUniqueItemLottery(\sammo\genGenericUniqueRNGFromGeneral($general), $general); $general->applyDB($db); return true; } - + } \ No newline at end of file diff --git a/hwe/sammo/Command/General/che_등용.php b/hwe/sammo/Command/General/che_등용.php index 8c0d5c70..196f6c6a 100644 --- a/hwe/sammo/Command/General/che_등용.php +++ b/hwe/sammo/Command/General/che_등용.php @@ -136,7 +136,7 @@ class che_등용 extends Command\GeneralCommand return "【{$destGeneralName}】{$josaUl} {$name}"; } - public function run(): bool + public function run(\Sammo\RandUtil $rng): bool { if (!$this->hasFullConditionMet()) { throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); @@ -173,7 +173,7 @@ class che_등용 extends Command\GeneralCommand $this->setResultTurn(new LastTurn(static::getName(), $this->arg)); $general->checkStatChange(); - tryUniqueItemLottery($general); + tryUniqueItemLottery(\sammo\genGenericUniqueRNGFromGeneral($general), $general); $general->applyDB($db); diff --git a/hwe/sammo/Command/General/che_등용수락.php b/hwe/sammo/Command/General/che_등용수락.php index d50b8b35..223eab6f 100644 --- a/hwe/sammo/Command/General/che_등용수락.php +++ b/hwe/sammo/Command/General/che_등용수락.php @@ -100,7 +100,7 @@ class che_등용수락 extends Command\GeneralCommand{ return 0; } - public function run():bool{ + public function run(\Sammo\RandUtil $rng):bool{ if(!$this->hasFullConditionMet()){ throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); } diff --git a/hwe/sammo/Command/General/che_랜덤임관.php b/hwe/sammo/Command/General/che_랜덤임관.php index 6e6ca261..ad9a6624 100644 --- a/hwe/sammo/Command/General/che_랜덤임관.php +++ b/hwe/sammo/Command/General/che_랜덤임관.php @@ -14,6 +14,7 @@ use \sammo\GameUnitConst; use \sammo\LastTurn; use \sammo\Command; +use function sammo\genGenericUniqueRNGFromGeneral; use function \sammo\tryUniqueItemLottery; use \sammo\Constraint\Constraint; @@ -110,7 +111,7 @@ class che_랜덤임관 extends Command\GeneralCommand return 0; } - public function run(): bool + public function run(\Sammo\RandUtil $rng): bool { if (!$this->hasFullConditionMet()) { throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); @@ -162,7 +163,7 @@ class che_랜덤임관 extends Command\GeneralCommand $score = log($affinity + 1, 2); //0~ //쉐킷쉐킷 - $score += Util::randF(); + $score += $rng->nextFloat1(); $score += sqrt($testNation['gennum'] / $allGen); @@ -219,7 +220,7 @@ class che_랜덤임관 extends Command\GeneralCommand } if ($generalsCnt) { - $destNation = Util::choiceRandomUsingWeightPair($generalsCnt); + $destNation = $rng->choiceUsingWeightPair($generalsCnt); } } @@ -251,7 +252,7 @@ class che_랜덤임관 extends Command\GeneralCommand '천하의 균형을 맞추기 위해', '오랜 은거를 마치고', ]; - $randomTalk = Util::choiceRandom($talkList); + $randomTalk = $rng->choice($talkList); $logger->pushGeneralActionLog("{$destNationName}에 랜덤 임관했습니다. <1>$date"); $logger->pushGeneralHistoryLog("{$destNationName}에 랜덤 임관"); @@ -290,7 +291,7 @@ class che_랜덤임관 extends Command\GeneralCommand $general->addExperience($exp); $this->setResultTurn(new LastTurn(static::getName(), $this->arg)); $general->checkStatChange(); - tryUniqueItemLottery($general, '랜덤 임관'); + tryUniqueItemLottery(genGenericUniqueRNGFromGeneral($general), $general, '랜덤 임관'); $general->applyDB($db); return true; diff --git a/hwe/sammo/Command/General/che_모반시도.php b/hwe/sammo/Command/General/che_모반시도.php index 2e11afda..0be42d50 100644 --- a/hwe/sammo/Command/General/che_모반시도.php +++ b/hwe/sammo/Command/General/che_모반시도.php @@ -55,7 +55,7 @@ class che_모반시도 extends Command\GeneralCommand{ return 0; } - public function run():bool{ + public function run(\Sammo\RandUtil $rng):bool{ if(!$this->hasFullConditionMet()){ throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); } @@ -99,7 +99,7 @@ class che_모반시도 extends Command\GeneralCommand{ $this->setResultTurn(new LastTurn(static::getName(), $this->arg)); $general->increaseInheritancePoint(InheritanceKey::active_action, 1); $general->checkStatChange(); - tryRollbackInheritUniqueItem($general); + tryRollbackInheritUniqueItem($rng, $general); $general->applyDB($db); $lordGeneral->applyDB($db); diff --git a/hwe/sammo/Command/General/che_물자조달.php b/hwe/sammo/Command/General/che_물자조달.php index 6ef41490..182bb300 100644 --- a/hwe/sammo/Command/General/che_물자조달.php +++ b/hwe/sammo/Command/General/che_물자조달.php @@ -60,7 +60,7 @@ class che_물자조달 extends Command\GeneralCommand{ return 0; } - public function run():bool{ + public function run(\Sammo\RandUtil $rng):bool{ if(!$this->hasFullConditionMet()){ throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); } @@ -70,14 +70,14 @@ class che_물자조달 extends Command\GeneralCommand{ $general = $this->generalObj; $date = $general->getTurnTime($general::TURNTIME_HM); - [$resName, $resKey] = Util::choiceRandom([ + [$resName, $resKey] = $rng->choice([ ['금', 'gold'], ['쌀', 'rice'] ]); $score = $general->getLeadership() + $general->getStrength() + $general->getIntel(); $score *= getDomesticExpLevelBonus($general->getVar('explevel')); - $score *= Util::randRange(0.8, 1.2); + $score *= $rng->nextRange(0.8, 1.2); $successRatio = 0.1; $failRatio = 0.3; @@ -86,12 +86,12 @@ class che_물자조달 extends Command\GeneralCommand{ $failRatio = $general->onCalcDomestic('조달', 'fail', $failRatio); $normalRatio = 1 - $failRatio - $successRatio; - $pick = Util::choiceRandomUsingWeight([ + $pick = $rng->choiceUsingWeight([ 'fail'=>$failRatio, 'success'=>$successRatio, 'normal'=>$normalRatio ]); - $score *= CriticalScoreEx($pick); + $score *= CriticalScoreEx($rng, $pick); $score = $general->onCalcDomestic('조달', 'score', $score); $score = Util::round($score); @@ -112,7 +112,7 @@ class che_물자조달 extends Command\GeneralCommand{ $exp = $score * 0.7 / 3; $ded = $score * 1.0 / 3; - $incStat = Util::choiceRandomUsingWeight([ + $incStat = $rng->choiceUsingWeight([ 'leadership_exp'=>$general->getLeadership(false, false, false, false), 'strength_exp'=>$general->getStrength(false, false, false, false), 'intel_exp'=>$general->getIntel(false, false, false, false) @@ -128,7 +128,7 @@ class che_물자조달 extends Command\GeneralCommand{ $this->setResultTurn(new LastTurn(static::getName(), $this->arg)); $general->checkStatChange(); - tryUniqueItemLottery($general); + tryUniqueItemLottery(\sammo\genGenericUniqueRNGFromGeneral($general), $general); $general->applyDB($db); diff --git a/hwe/sammo/Command/General/che_방랑.php b/hwe/sammo/Command/General/che_방랑.php index 0daf2e2a..74a559be 100644 --- a/hwe/sammo/Command/General/che_방랑.php +++ b/hwe/sammo/Command/General/che_방랑.php @@ -59,7 +59,7 @@ class che_방랑 extends Command\GeneralCommand{ return 0; } - public function run():bool{ + public function run(\Sammo\RandUtil $rng):bool{ if(!$this->hasFullConditionMet()){ throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); } @@ -125,7 +125,7 @@ class che_방랑 extends Command\GeneralCommand{ refreshNationStaticInfo(); $general->increaseInheritancePoint(InheritanceKey::active_action, 1); $this->setResultTurn(new LastTurn(static::getName(), $this->arg)); - tryRollbackInheritUniqueItem($general); + tryRollbackInheritUniqueItem($rng, $general); $general->applyDB($db); return true; diff --git a/hwe/sammo/Command/General/che_사기진작.php b/hwe/sammo/Command/General/che_사기진작.php index f44a58de..f4dc8829 100644 --- a/hwe/sammo/Command/General/che_사기진작.php +++ b/hwe/sammo/Command/General/che_사기진작.php @@ -3,7 +3,7 @@ namespace sammo\Command\General; use \sammo\{ DB, Util, JosaUtil, - General, + General, ActionLogger, GameConst, GameUnitConst, LastTurn, @@ -34,13 +34,13 @@ class che_사기진작 extends Command\GeneralCommand{ [$reqGold, $reqRice] = $this->getCost(); $this->minConditionConstraints=[ - ConstraintHelper::NotBeNeutral(), + ConstraintHelper::NotBeNeutral(), ConstraintHelper::NotWanderingNation(), ConstraintHelper::OccupiedCity(), ]; - + $this->fullConditionConstraints=[ - ConstraintHelper::NotBeNeutral(), + ConstraintHelper::NotBeNeutral(), ConstraintHelper::NotWanderingNation(), ConstraintHelper::OccupiedCity(), ConstraintHelper::ReqGeneralCrew(), @@ -62,7 +62,7 @@ class che_사기진작 extends Command\GeneralCommand{ $general = $this->generalObj; return [Util::round($general->getVar('crew')/100), 0]; } - + public function getPreReqTurn():int{ return 0; } @@ -71,7 +71,7 @@ class che_사기진작 extends Command\GeneralCommand{ return 0; } - public function run():bool{ + public function run(\Sammo\RandUtil $rng):bool{ if(!$this->hasFullConditionMet()){ throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); } @@ -103,11 +103,11 @@ class che_사기진작 extends Command\GeneralCommand{ $general->increaseVar('leadership_exp', 1); $this->setResultTurn(new LastTurn(static::getName(), $this->arg)); $general->checkStatChange(); - tryUniqueItemLottery($general); + tryUniqueItemLottery(\sammo\genGenericUniqueRNGFromGeneral($general), $general); $general->applyDB($db); return true; } - + } \ No newline at end of file diff --git a/hwe/sammo/Command/General/che_상업투자.php b/hwe/sammo/Command/General/che_상업투자.php index 0a986e07..3838ca9a 100644 --- a/hwe/sammo/Command/General/che_상업투자.php +++ b/hwe/sammo/Command/General/che_상업투자.php @@ -3,12 +3,13 @@ namespace sammo\Command\General; use \sammo\{ DB, Util, JosaUtil, - General, + General, ActionLogger, GameConst, LastTurn, GameUnitConst, - Command + Command, + RandUtil }; use function \sammo\getDomesticExpLevelBonus; @@ -41,11 +42,11 @@ class che_상업투자 extends Command\GeneralCommand{ $this->setCity(); $this->setNation(); - + [$reqGold, $reqRice] = $this->getCost(); $this->fullConditionConstraints=[ - ConstraintHelper::NotBeNeutral(), + ConstraintHelper::NotBeNeutral(), ConstraintHelper::NotWanderingNation(), ConstraintHelper::OccupiedCity(), ConstraintHelper::SuppliedCity(), @@ -82,15 +83,15 @@ class che_상업투자 extends Command\GeneralCommand{ $develCost = $this->env['develcost']; $reqGold = Util::round($this->generalObj->onCalcDomestic(static::$actionKey, 'cost', $develCost)); $reqRice = 0; - + return [$reqGold, $reqRice]; } - + public function getCompensationStyle():?int{ return $this->generalObj->onCalcDomestic(static::$actionKey, 'score', 100)<=>100; } - + public function getPreReqTurn():int{ return 0; } @@ -99,7 +100,7 @@ class che_상업투자 extends Command\GeneralCommand{ return 0; } - protected function calcBaseScore():float{ + protected function calcBaseScore(RandUtil $rng):float{ $trust = Util::valueFit($this->city['trust'], 50); $general = $this->generalObj; @@ -115,16 +116,16 @@ class che_상업투자 extends Command\GeneralCommand{ else{ throw new \sammo\MustNotBeReachedException(); } - + $score *= $trust / 100; $score *= getDomesticExpLevelBonus($general->getVar('explevel')); - $score *= Util::randRange(0.8, 1.2); + $score *= $rng->nextRange(0.8, 1.2); $score = $general->onCalcDomestic(static::$actionKey, 'score', $score); return $score; } - public function run():bool{ + public function run(\Sammo\RandUtil $rng):bool{ if(!$this->hasFullConditionMet()){ throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); } @@ -135,7 +136,7 @@ class che_상업투자 extends Command\GeneralCommand{ $trust = Util::valueFit($this->city['trust'], 50); - $score = Util::valueFit($this->calcBaseScore(), 1); + $score = Util::valueFit($this->calcBaseScore($rng), 1); ['success'=>$successRatio, 'fail'=>$failRatio] = CriticalRatioDomestic($general, static::$statKey); if($trust < 80){ @@ -148,9 +149,9 @@ class che_상업투자 extends Command\GeneralCommand{ $failRatio = Util::valueFit($failRatio, 0, 1 - $successRatio); $normalRatio = 1 - $failRatio - $successRatio; - $pick = Util::choiceRandomUsingWeight([ - 'fail'=>$failRatio, - 'success'=>$successRatio, + $pick = $rng->choiceUsingWeight([ + 'fail'=>$failRatio, + 'success'=>$successRatio, 'normal'=>$normalRatio ]); @@ -158,14 +159,14 @@ class che_상업투자 extends Command\GeneralCommand{ $date = $general->getTurnTime($general::TURNTIME_HM); - $score *= CriticalScoreEx($pick); + $score *= CriticalScoreEx($rng, $pick); $score = Util::round($score); $exp = $score * 0.7; $ded = $score * 1.0; if($pick == 'success'){ - updateMaxDomesticCritical($general, $score); + updateMaxDomesticCritical($general, $score); } else{ $general->setAuxVar('max_domestic_critical', 0); @@ -204,7 +205,7 @@ class che_상업투자 extends Command\GeneralCommand{ $general->increaseVar(static::$statKey.'_exp', 1); $this->setResultTurn(new LastTurn(static::getName(), $this->arg)); $general->checkStatChange(); - tryUniqueItemLottery($general); + tryUniqueItemLottery(\sammo\genGenericUniqueRNGFromGeneral($general), $general); $general->applyDB($db); return true; diff --git a/hwe/sammo/Command/General/che_선동.php b/hwe/sammo/Command/General/che_선동.php index de193a7b..a8195716 100644 --- a/hwe/sammo/Command/General/che_선동.php +++ b/hwe/sammo/Command/General/che_선동.php @@ -9,6 +9,7 @@ use \sammo\ActionLogger; use \sammo\GameConst; use \sammo\GameUnitConst; use \sammo\Command; +use sammo\RandUtil; class che_선동 extends che_화계{ static protected $actionName = '선동'; @@ -16,7 +17,7 @@ class che_선동 extends che_화계{ static protected $statType = 'leadership'; static protected $injuryGeneral = true; - protected function affectDestCity(int $injuryCount){ + protected function affectDestCity(RandUtil $rng, int $injuryCount){ $general = $this->generalObj; $date = $general->getTurnTime($general::TURNTIME_HM); @@ -30,15 +31,15 @@ class che_선동 extends che_화계{ $commandName = $this->getName(); // 선동 최대 10 - $secuAmount = Util::valueFit(Util::randRangeInt(GameConst::$sabotageDamageMin, GameConst::$sabotageDamageMax), null, $destCity['secu']); + $secuAmount = Util::valueFit($rng->nextRangeInt(GameConst::$sabotageDamageMin, GameConst::$sabotageDamageMax), null, $destCity['secu']); $trustAmount = Util::valueFit( - Util::randRange(GameConst::$sabotageDamageMin, GameConst::$sabotageDamageMax) / 50, - null, + $rng->nextRange(GameConst::$sabotageDamageMin, GameConst::$sabotageDamageMax) / 50, + null, $destCity['trust'] ); $destCity['secu'] -= $secuAmount; $destCity['trust'] -= $trustAmount; - + DB::db()->update('city', [ 'state'=>32, 'secu'=>$destCity['secu'], @@ -57,5 +58,5 @@ class che_선동 extends che_화계{ ActionLogger::PLAIN ); } - + } \ No newline at end of file diff --git a/hwe/sammo/Command/General/che_선양.php b/hwe/sammo/Command/General/che_선양.php index 7c4d8239..922dcc48 100644 --- a/hwe/sammo/Command/General/che_선양.php +++ b/hwe/sammo/Command/General/che_선양.php @@ -99,7 +99,7 @@ class che_선양 extends Command\GeneralCommand return "【{$destGeneralName}】에게 {$name}"; } - public function run(): bool + public function run(\Sammo\RandUtil $rng): bool { if (!$this->hasFullConditionMet()) { throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); @@ -139,7 +139,7 @@ class che_선양 extends Command\GeneralCommand $general->increaseInheritancePoint(InheritanceKey::active_action, 1); $this->setResultTurn(new LastTurn(static::getName(), $this->arg)); $general->checkStatChange(); - tryRollbackInheritUniqueItem($general); + tryRollbackInheritUniqueItem($rng, $general); $general->applyDB($db); $destGeneral->applyDB($db); diff --git a/hwe/sammo/Command/General/che_소집해제.php b/hwe/sammo/Command/General/che_소집해제.php index 3a8d57e3..6d474a4b 100644 --- a/hwe/sammo/Command/General/che_소집해제.php +++ b/hwe/sammo/Command/General/che_소집해제.php @@ -54,7 +54,7 @@ class che_소집해제 extends Command\GeneralCommand{ return 0; } - public function run():bool{ + public function run(\Sammo\RandUtil $rng):bool{ if(!$this->hasFullConditionMet()){ throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); } @@ -82,7 +82,7 @@ class che_소집해제 extends Command\GeneralCommand{ $general->addDedication($ded); $this->setResultTurn(new LastTurn(static::getName(), $this->arg)); $general->checkStatChange(); - tryRollbackInheritUniqueItem($general); + tryRollbackInheritUniqueItem($rng, $general); $general->applyDB($db); return true; diff --git a/hwe/sammo/Command/General/che_숙련전환.php b/hwe/sammo/Command/General/che_숙련전환.php index 1b4d0e0f..b5a5a2fa 100644 --- a/hwe/sammo/Command/General/che_숙련전환.php +++ b/hwe/sammo/Command/General/che_숙련전환.php @@ -144,7 +144,7 @@ class che_숙련전환 extends Command\GeneralCommand return 0; } - public function run(): bool + public function run(\Sammo\RandUtil $rng): bool { if (!$this->hasFullConditionMet()) { throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); @@ -179,7 +179,7 @@ class che_숙련전환 extends Command\GeneralCommand $general->increaseVar('leadership_exp', 2); $this->setResultTurn(new LastTurn(static::getName(), $this->arg)); $general->checkStatChange(); - tryUniqueItemLottery($general); + tryUniqueItemLottery(\sammo\genGenericUniqueRNGFromGeneral($general), $general); $general->applyDB($db); return true; diff --git a/hwe/sammo/Command/General/che_요양.php b/hwe/sammo/Command/General/che_요양.php index 48d31bfc..b316240e 100644 --- a/hwe/sammo/Command/General/che_요양.php +++ b/hwe/sammo/Command/General/che_요양.php @@ -46,7 +46,7 @@ class che_요양 extends Command\GeneralCommand{ return 0; } - public function run():bool{ + public function run(\Sammo\RandUtil $rng):bool{ if(!$this->hasFullConditionMet()){ throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); } @@ -71,7 +71,7 @@ class che_요양 extends Command\GeneralCommand{ $general->addDedication($ded); $this->setResultTurn(new LastTurn(static::getName(), $this->arg)); $general->checkStatChange(); - tryRollbackInheritUniqueItem($general); + tryRollbackInheritUniqueItem($rng, $general); $general->applyDB($db); return true; diff --git a/hwe/sammo/Command/General/che_은퇴.php b/hwe/sammo/Command/General/che_은퇴.php index 570a73f7..4abc5648 100644 --- a/hwe/sammo/Command/General/che_은퇴.php +++ b/hwe/sammo/Command/General/che_은퇴.php @@ -53,7 +53,7 @@ class che_은퇴 extends Command\GeneralCommand{ return 0; } - public function run():bool{ + public function run(\Sammo\RandUtil $rng):bool{ if(!$this->hasFullConditionMet()){ throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); } @@ -69,7 +69,7 @@ class che_은퇴 extends Command\GeneralCommand{ $logger->pushGeneralActionLog("은퇴하였습니다. <1>$date"); $this->setResultTurn(new LastTurn(static::getName(), $this->arg)); - tryUniqueItemLottery($general); + tryUniqueItemLottery(\sammo\genGenericUniqueRNGFromGeneral($general), $general); $general->applyDB($db); return true; diff --git a/hwe/sammo/Command/General/che_이동.php b/hwe/sammo/Command/General/che_이동.php index b3ff7583..edbd88eb 100644 --- a/hwe/sammo/Command/General/che_이동.php +++ b/hwe/sammo/Command/General/che_이동.php @@ -119,7 +119,7 @@ class che_이동 extends Command\GeneralCommand return "{$failReason} {$destCityName}{$josaRo} {$commandName} 실패."; } - public function run(): bool + public function run(\Sammo\RandUtil $rng): bool { if (!$this->hasFullConditionMet()) { throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); @@ -164,7 +164,7 @@ class che_이동 extends Command\GeneralCommand $general->increaseVar('leadership_exp', 1); $this->setResultTurn(new LastTurn(static::getName(), $this->arg)); $general->checkStatChange(); - tryUniqueItemLottery($general); + tryUniqueItemLottery(\sammo\genGenericUniqueRNGFromGeneral($general), $general); $general->applyDB($db); diff --git a/hwe/sammo/Command/General/che_인재탐색.php b/hwe/sammo/Command/General/che_인재탐색.php index a1507c19..6d1a33c1 100644 --- a/hwe/sammo/Command/General/che_인재탐색.php +++ b/hwe/sammo/Command/General/che_인재탐색.php @@ -109,7 +109,7 @@ class che_인재탐색 extends Command\GeneralCommand return $foundProp; } - public function run(): bool + public function run(\Sammo\RandUtil $rng): bool { if (!$this->hasFullConditionMet()) { throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); @@ -128,14 +128,14 @@ class che_인재탐색 extends Command\GeneralCommand $totalNpcCnt = $db->queryFirstField('SELECT count(`no`) FROM general WHERE 3 <= npc AND npc <= 4'); $foundProp = $this->calcFoundProp($env['maxgeneral'], $totalGenCnt, $totalNpcCnt); - $foundNpc = Util::randBool($foundProp); + $foundNpc = $rng->nextBool($foundProp); $logger = $general->getLogger(); if (!$foundNpc) { $logger->pushGeneralActionLog("인재를 찾을 수 없었습니다. <1>$date"); - $incStat = Util::choiceRandomUsingWeight([ + $incStat = $rng->choiceUsingWeight([ 'leadership_exp' => $general->getLeadership(false, false, false, false), 'strength_exp' => $general->getStrength(false, false, false, false), 'intel_exp' => $general->getIntel(false, false, false, false) @@ -152,7 +152,7 @@ class che_인재탐색 extends Command\GeneralCommand $general->increaseVar($incStat, 1); $this->setResultTurn(new LastTurn(static::getName(), $this->arg)); $general->checkStatChange(); - tryUniqueItemLottery($general); + tryUniqueItemLottery(\sammo\genGenericUniqueRNGFromGeneral($general), $general); $general->applyDB($db); return true; } @@ -163,9 +163,9 @@ class che_인재탐색 extends Command\GeneralCommand $scoutType = "발견"; - $age = Util::randRangeInt(20, 25); + $age = $rng->nextRangeInt(20, 25); $birthYear = $env['year'] - $age; - $deathYear = $env['year'] + Util::randRangeInt(10, 50); + $deathYear = $env['year'] + $rng->nextRangeInt(10, 50); $avgGen = $db->queryFirstRow( 'SELECT avg(dedication) as ded,avg(experience) as exp, @@ -175,7 +175,7 @@ class che_인재탐색 extends Command\GeneralCommand $pickTypeList = ['무' => 6, '지' => 6, '무지' => 3]; - $pickedNPC = pickGeneralFromPool($db, 0, 1)[0]; + $pickedNPC = pickGeneralFromPool($db, $rng, 0, 1)[0]; $newNPC = $pickedNPC->getGeneralBuilder(); $newNPC->setSpecial('None', 'None'); @@ -200,7 +200,7 @@ class che_인재탐색 extends Command\GeneralCommand $logger->pushGlobalActionLog("{$generalName}{$josaYi} $npcName{$josaRa}는 인재를 {$scoutType}하였습니다!"); $logger->pushGeneralHistoryLog("$npcName{$josaRa}는 인재를 {$scoutType}"); - $incStat = Util::choiceRandomUsingWeight([ + $incStat = $rng->choiceUsingWeight([ 'leadership_exp' => $general->getLeadership(false, false, false, false), 'strength_exp' => $general->getStrength(false, false, false, false), 'intel_exp' => $general->getIntel(false, false, false, false) @@ -218,7 +218,7 @@ class che_인재탐색 extends Command\GeneralCommand $general->increaseVar($incStat, 3); $this->setResultTurn(new LastTurn(static::getName(), $this->arg)); $general->checkStatChange(); - tryUniqueItemLottery($general); + tryUniqueItemLottery(\sammo\genGenericUniqueRNGFromGeneral($general), $general); $general->applyDB($db); return true; } diff --git a/hwe/sammo/Command/General/che_임관.php b/hwe/sammo/Command/General/che_임관.php index c4333c0a..2a7e4e20 100644 --- a/hwe/sammo/Command/General/che_임관.php +++ b/hwe/sammo/Command/General/che_임관.php @@ -119,7 +119,7 @@ class che_임관 extends Command\GeneralCommand return "【{$destNationName}】{$josaRo} {$commandName}"; } - public function run(): bool + public function run(\Sammo\RandUtil $rng): bool { if (!$this->hasFullConditionMet()) { throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); @@ -179,7 +179,7 @@ class che_임관 extends Command\GeneralCommand $general->addExperience($exp); $this->setResultTurn(new LastTurn(static::getName(), $this->arg)); $general->checkStatChange(); - tryUniqueItemLottery($general); + tryUniqueItemLottery(\sammo\genGenericUniqueRNGFromGeneral($general), $general); $general->applyDB($db); return true; diff --git a/hwe/sammo/Command/General/che_장비매매.php b/hwe/sammo/Command/General/che_장비매매.php index ae7f1e7b..2204dae9 100644 --- a/hwe/sammo/Command/General/che_장비매매.php +++ b/hwe/sammo/Command/General/che_장비매매.php @@ -141,7 +141,7 @@ class che_장비매매 extends Command\GeneralCommand return "【{$itemName}】{$josaUl} 구입"; } - public function run(): bool + public function run(\sammo\RandUtil $rng): bool { if (!$this->hasFullConditionMet()) { throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); @@ -174,11 +174,11 @@ class che_장비매매 extends Command\GeneralCommand $logger->pushGeneralActionLog("{$itemName}{$josaUl} 구입했습니다. <1>$date"); $general->increaseVarWithLimit('gold', -$cost, 0); $general->setItem($itemType, $itemCode); - $general->onArbitraryAction($general, '장비매매', '구매', ['itemCode' => $itemCode]); + $general->onArbitraryAction($general, $rng, '장비매매', '구매', ['itemCode' => $itemCode]); } else { $logger->pushGeneralActionLog("{$itemName}{$josaUl} 판매했습니다. <1>$date"); $general->increaseVarWithLimit('gold', $cost / 2); - $general->onArbitraryAction($general, '장비매매', '판매', ['itemCode' => $itemCode]); + $general->onArbitraryAction($general, $rng, '장비매매', '판매', ['itemCode' => $itemCode]); $general->setItem($itemType, null); if(!$itemObj->isBuyable()){ @@ -195,7 +195,7 @@ class che_장비매매 extends Command\GeneralCommand $general->addExperience($exp); $this->setResultTurn(new LastTurn(static::getName(), $this->arg)); $general->checkStatChange(); - tryUniqueItemLottery($general); + tryUniqueItemLottery(\sammo\genGenericUniqueRNGFromGeneral($general), $general); $general->applyDB($db); return true; diff --git a/hwe/sammo/Command/General/che_장수대상임관.php b/hwe/sammo/Command/General/che_장수대상임관.php index e2c299aa..480be561 100644 --- a/hwe/sammo/Command/General/che_장수대상임관.php +++ b/hwe/sammo/Command/General/che_장수대상임관.php @@ -116,7 +116,7 @@ class che_장수대상임관 extends Command\GeneralCommand{ return "【{$destGeneralName}】{$josaUl} 따라 임관"; } - public function run():bool{ + public function run(\Sammo\RandUtil $rng):bool{ if(!$this->hasFullConditionMet()){ throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); } @@ -176,7 +176,7 @@ class che_장수대상임관 extends Command\GeneralCommand{ $general->addExperience($exp); $this->setResultTurn(new LastTurn(static::getName(), $this->arg)); $general->checkStatChange(); - tryUniqueItemLottery($general); + tryUniqueItemLottery(\sammo\genGenericUniqueRNGFromGeneral($general), $general); $general->applyDB($db); return true; diff --git a/hwe/sammo/Command/General/che_전투태세.php b/hwe/sammo/Command/General/che_전투태세.php index 331e35a0..bd96e9ba 100644 --- a/hwe/sammo/Command/General/che_전투태세.php +++ b/hwe/sammo/Command/General/che_전투태세.php @@ -3,7 +3,7 @@ namespace sammo\Command\General; use \sammo\{ DB, Util, JosaUtil, - General, + General, ActionLogger, GameConst, GameUnitConst, LastTurn, @@ -34,9 +34,9 @@ class che_전투태세 extends Command\GeneralCommand{ $this->setNation(); [$reqGold, $reqRice] = $this->getCost(); - + $this->fullConditionConstraints=[ - ConstraintHelper::NotBeNeutral(), + ConstraintHelper::NotBeNeutral(), ConstraintHelper::NotWanderingNation(), ConstraintHelper::OccupiedCity(), ConstraintHelper::ReqGeneralCrew(), @@ -53,7 +53,7 @@ class che_전투태세 extends Command\GeneralCommand{ $techCost = getTechCost($this->nation['tech']); return [Util::round($crew / 100 * 3 * $techCost), 0]; } - + public function getPreReqTurn():int{ return 3; } @@ -62,7 +62,7 @@ class che_전투태세 extends Command\GeneralCommand{ return 0; } - public function run():bool{ + public function run(\Sammo\RandUtil $rng):bool{ if(!$this->hasFullConditionMet()){ throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); } @@ -102,7 +102,7 @@ class che_전투태세 extends Command\GeneralCommand{ return true; } - + $logger->pushGeneralActionLog("전투태세 완료! ({$term}/3) <1>$date"); $general->increaseVarWithLimit('train', 0, GameConst::$maxTrainByCommand - 5); //95보다 높으면 '깎이지는 않음' @@ -117,15 +117,15 @@ class che_전투태세 extends Command\GeneralCommand{ $crew = $general->getVar('crew'); $general->addDex($general->getCrewTypeObj(), $crew / 100 * 3, false); - + $general->increaseVar('leadership_exp', 3); $this->setResultTurn($turnResult); $general->checkStatChange(); - tryUniqueItemLottery($general); + tryUniqueItemLottery(\sammo\genGenericUniqueRNGFromGeneral($general), $general); $general->applyDB($db); return true; } - + } \ No newline at end of file diff --git a/hwe/sammo/Command/General/che_전투특기초기화.php b/hwe/sammo/Command/General/che_전투특기초기화.php index 72a431d3..cf5bfa5f 100644 --- a/hwe/sammo/Command/General/che_전투특기초기화.php +++ b/hwe/sammo/Command/General/che_전투특기초기화.php @@ -3,7 +3,7 @@ namespace sammo\Command\General; use \sammo\{ DB, Util, JosaUtil, - General, + General, ActionLogger, GameConst, GameUnitConst, LastTurn, @@ -32,7 +32,7 @@ class che_전투특기초기화 extends Command\GeneralCommand{ $this->minConditionConstraints=[ ConstraintHelper::ReqGeneralValue(static::$specialType, static::$specialText, '!=', 'None', '특기가 없습니다.'), ]; - + $this->fullConditionConstraints=[ ConstraintHelper::ReqGeneralValue(static::$specialType, static::$specialText, '!=', 'None', '특기가 없습니다.') ]; @@ -54,7 +54,7 @@ class che_전투특기초기화 extends Command\GeneralCommand{ public function getCost():array{ return [0, 0]; } - + public function getPreReqTurn():int{ return 1; } @@ -69,7 +69,7 @@ class che_전투특기초기화 extends Command\GeneralCommand{ return "새로운 적성을 찾는 중... ({$term}/{$termMax})"; } - public function run():bool{ + public function run(\Sammo\RandUtil $rng):bool{ if(!$this->hasFullConditionMet()){ throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); } @@ -83,7 +83,7 @@ class che_전투특기초기화 extends Command\GeneralCommand{ $specialName = static::$specialText; $env = $this->env; - + $yearMonth = Util::joinYearMonth($env['year'], $env['month']); $oldSpecialList = $general->getAuxVar($oldTypeKey)??[]; $oldSpecialList[] = $general->getVar(static::$specialType); @@ -97,11 +97,11 @@ class che_전투특기초기화 extends Command\GeneralCommand{ $logger->pushGeneralActionLog("새로운 {$specialName}를 가질 준비가 되었습니다. <1>$date"); $this->setResultTurn(new LastTurn(static::getName(), $this->arg)); - tryUniqueItemLottery($general); + tryUniqueItemLottery(\sammo\genGenericUniqueRNGFromGeneral($general), $general); $general->applyDB($db); return true; } - + } \ No newline at end of file diff --git a/hwe/sammo/Command/General/che_정착장려.php b/hwe/sammo/Command/General/che_정착장려.php index dc9c6009..6df6de64 100644 --- a/hwe/sammo/Command/General/che_정착장려.php +++ b/hwe/sammo/Command/General/che_정착장려.php @@ -3,12 +3,13 @@ namespace sammo\Command\General; use \sammo\{ DB, Util, JosaUtil, - General, + General, ActionLogger, GameConst, LastTurn, GameUnitConst, - Command + Command, + RandUtil }; use function \sammo\getDomesticExpLevelBonus; @@ -40,11 +41,11 @@ class che_정착장려 extends Command\GeneralCommand{ $this->setCity(); $this->setNation(); - + [$reqGold, $reqRice] = $this->getCost(); $this->fullConditionConstraints=[ - ConstraintHelper::NotBeNeutral(), + ConstraintHelper::NotBeNeutral(), ConstraintHelper::NotWanderingNation(), ConstraintHelper::OccupiedCity(), ConstraintHelper::SuppliedCity(), @@ -81,14 +82,14 @@ class che_정착장려 extends Command\GeneralCommand{ $develCost = $this->env['develcost'] * 2; $reqGold = 0; $reqRice = Util::round($this->generalObj->onCalcDomestic(static::$actionKey, 'cost', $develCost)); - + return [$reqGold, $reqRice]; } public function getCompensationStyle():?int{ return $this->generalObj->onCalcDomestic(static::$actionKey, 'score', 100)<=>100; } - + public function getPreReqTurn():int{ return 0; } @@ -97,7 +98,7 @@ class che_정착장려 extends Command\GeneralCommand{ return 0; } - protected function calcBaseScore():float{ + protected function calcBaseScore(RandUtil $rng):float{ $general = $this->generalObj; if(static::$statKey == 'leadership'){ @@ -106,15 +107,15 @@ class che_정착장려 extends Command\GeneralCommand{ else{ throw new \sammo\MustNotBeReachedException(); } - + $score *= getDomesticExpLevelBonus($general->getVar('explevel')); - $score *= Util::randRange(0.8, 1.2); + $score *= $rng->nextRange(0.8, 1.2); $score = $general->onCalcDomestic(static::$actionKey, 'score', $score); return $score; } - public function run():bool{ + public function run(\Sammo\RandUtil $rng):bool{ if(!$this->hasFullConditionMet()){ throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); } @@ -123,7 +124,7 @@ class che_정착장려 extends Command\GeneralCommand{ $general = $this->generalObj; - $score = Util::valueFit($this->calcBaseScore(), 1); + $score = Util::valueFit($this->calcBaseScore($rng), 1); ['success'=>$successRatio, 'fail'=>$failRatio] = CriticalRatioDomestic($general, static::$statKey); $successRatio = $general->onCalcDomestic(static::$actionKey, 'success', $successRatio); @@ -133,9 +134,9 @@ class che_정착장려 extends Command\GeneralCommand{ $failRatio = Util::valueFit($failRatio, 0, 1 - $successRatio); $normalRatio = 1 - $failRatio - $successRatio; - $pick = Util::choiceRandomUsingWeight([ - 'fail'=>$failRatio, - 'success'=>$successRatio, + $pick = $rng->choiceUsingWeight([ + 'fail'=>$failRatio, + 'success'=>$successRatio, 'normal'=>$normalRatio ]); @@ -143,14 +144,14 @@ class che_정착장려 extends Command\GeneralCommand{ $date = $general->getTurnTime($general::TURNTIME_HM); - $score *= CriticalScoreEx($pick); + $score *= CriticalScoreEx($rng, $pick); $score = Util::round($score); $exp = $score * 0.7; $ded = $score * 1.0; if($pick == 'success'){ - updateMaxDomesticCritical($general, $score); + updateMaxDomesticCritical($general, $score); } else{ $general->setAuxVar('max_domestic_critical', 0); @@ -187,7 +188,7 @@ class che_정착장려 extends Command\GeneralCommand{ $general->increaseVar(static::$statKey.'_exp', 1); $this->setResultTurn(new LastTurn(static::getName(), $this->arg)); $general->checkStatChange(); - tryUniqueItemLottery($general); + tryUniqueItemLottery(\sammo\genGenericUniqueRNGFromGeneral($general), $general); $general->applyDB($db); return true; diff --git a/hwe/sammo/Command/General/che_주민선정.php b/hwe/sammo/Command/General/che_주민선정.php index 1b70b6ea..af8f7009 100644 --- a/hwe/sammo/Command/General/che_주민선정.php +++ b/hwe/sammo/Command/General/che_주민선정.php @@ -3,12 +3,13 @@ namespace sammo\Command\General; use \sammo\{ DB, Util, JosaUtil, - General, + General, ActionLogger, GameConst, LastTurn, GameUnitConst, - Command + Command, + RandUtil }; use function \sammo\getDomesticExpLevelBonus; @@ -40,11 +41,11 @@ class che_주민선정 extends Command\GeneralCommand{ $this->setCity(); $this->setNation(); - + [$reqGold, $reqRice] = $this->getCost(); $this->fullConditionConstraints=[ - ConstraintHelper::NotBeNeutral(), + ConstraintHelper::NotBeNeutral(), ConstraintHelper::NotWanderingNation(), ConstraintHelper::OccupiedCity(), ConstraintHelper::SuppliedCity(), @@ -81,14 +82,14 @@ class che_주민선정 extends Command\GeneralCommand{ $develCost = $this->env['develcost'] * 2; $reqGold = 0; $reqRice = $this->generalObj->onCalcDomestic(static::$actionKey, 'cost', $develCost); - + return [$reqGold, Util::round($reqRice)]; } public function getCompensationStyle():?int{ return $this->generalObj->onCalcDomestic(static::$actionKey, 'score', 100)<=>100; } - + public function getPreReqTurn():int{ return 0; } @@ -97,7 +98,7 @@ class che_주민선정 extends Command\GeneralCommand{ return 0; } - protected function calcBaseScore():float{ + protected function calcBaseScore(RandUtil $rng):float{ $general = $this->generalObj; if(static::$statKey == 'leadership'){ @@ -106,16 +107,16 @@ class che_주민선정 extends Command\GeneralCommand{ else{ throw new \sammo\MustNotBeReachedException(); } - + $score *= getDomesticExpLevelBonus($general->getVar('explevel')); - $score *= Util::randRange(0.8, 1.2); + $score *= $rng->nextRange(0.8, 1.2); $score = $general->onCalcDomestic(static::$actionKey, 'score', $score); $score = Util::valueFit($score, 1); return $score; } - public function run():bool{ + public function run(\Sammo\RandUtil $rng):bool{ if(!$this->hasFullConditionMet()){ throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); } @@ -124,7 +125,7 @@ class che_주민선정 extends Command\GeneralCommand{ $general = $this->generalObj; - $score = Util::valueFit($this->calcBaseScore(), 1); + $score = Util::valueFit($this->calcBaseScore($rng), 1); ['success'=>$successRatio, 'fail'=>$failRatio] = CriticalRatioDomestic($general, static::$statKey); $successRatio = $general->onCalcDomestic(static::$actionKey, 'success', $successRatio); @@ -134,9 +135,9 @@ class che_주민선정 extends Command\GeneralCommand{ $failRatio = Util::valueFit($failRatio, 0, 1 - $successRatio); $normalRatio = 1 - $failRatio - $successRatio; - $pick = Util::choiceRandomUsingWeight([ - 'fail'=>$failRatio, - 'success'=>$successRatio, + $pick = $rng->choiceUsingWeight([ + 'fail'=>$failRatio, + 'success'=>$successRatio, 'normal'=>$normalRatio ]); @@ -144,13 +145,13 @@ class che_주민선정 extends Command\GeneralCommand{ $date = $general->getTurnTime($general::TURNTIME_HM); - $score *= CriticalScoreEx($pick); + $score *= CriticalScoreEx($rng, $pick); $exp = $score * 0.7; $ded = $score * 1.0; if($pick == 'success'){ - updateMaxDomesticCritical($general, $score); + updateMaxDomesticCritical($general, $score); } else{ $general->setAuxVar('max_domestic_critical', 0); @@ -187,11 +188,11 @@ class che_주민선정 extends Command\GeneralCommand{ $general->increaseVar(static::$statKey.'_exp', 1); $this->setResultTurn(new LastTurn(static::getName(), $this->arg)); $general->checkStatChange(); - tryUniqueItemLottery($general); + tryUniqueItemLottery(\sammo\genGenericUniqueRNGFromGeneral($general), $general); $general->applyDB($db); return true; } - + } \ No newline at end of file diff --git a/hwe/sammo/Command/General/che_증여.php b/hwe/sammo/Command/General/che_증여.php index 81521971..a1f1426a 100644 --- a/hwe/sammo/Command/General/che_증여.php +++ b/hwe/sammo/Command/General/che_증여.php @@ -132,7 +132,7 @@ class che_증여 extends Command\GeneralCommand return "【{$destGeneralName}】에게 {$resText} {$this->arg['amount']}을 {$name}"; } - public function run(): bool + public function run(\Sammo\RandUtil $rng): bool { if (!$this->hasFullConditionMet()) { throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); @@ -169,7 +169,7 @@ class che_증여 extends Command\GeneralCommand $this->setResultTurn(new LastTurn(static::getName(), $this->arg)); $general->checkStatChange(); - tryUniqueItemLottery($general); + tryUniqueItemLottery(\sammo\genGenericUniqueRNGFromGeneral($general), $general); $general->applyDB($db); $destGeneral->applyDB($db); diff --git a/hwe/sammo/Command/General/che_집합.php b/hwe/sammo/Command/General/che_집합.php index 3afccf61..f7497099 100644 --- a/hwe/sammo/Command/General/che_집합.php +++ b/hwe/sammo/Command/General/che_집합.php @@ -3,7 +3,7 @@ namespace sammo\Command\General; use \sammo\{ DB, Util, JosaUtil, - General, + General, ActionLogger, GameConst, GameUnitConst, LastTurn, @@ -34,9 +34,9 @@ class che_집합 extends Command\GeneralCommand{ $this->setNation(); [$reqGold, $reqRice] = $this->getCost(); - + $this->fullConditionConstraints=[ - ConstraintHelper::NotBeNeutral(), + ConstraintHelper::NotBeNeutral(), ConstraintHelper::OccupiedCity(), ConstraintHelper::SuppliedCity(), ConstraintHelper::MustBeTroopLeader(), @@ -52,7 +52,7 @@ class che_집합 extends Command\GeneralCommand{ public function getCost():array{ return [0, 0]; } - + public function getPreReqTurn():int{ return 0; } @@ -61,7 +61,7 @@ class che_집합 extends Command\GeneralCommand{ return 0; } - public function run():bool{ + public function run(\Sammo\RandUtil $rng):bool{ if(!$this->hasFullConditionMet()){ throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); } @@ -103,11 +103,11 @@ class che_집합 extends Command\GeneralCommand{ $general->increaseVar('leadership_exp', 1); $this->setResultTurn(new LastTurn(static::getName(), $this->arg)); $general->checkStatChange(); - tryUniqueItemLottery($general); + tryUniqueItemLottery(\sammo\genGenericUniqueRNGFromGeneral($general), $general); $general->applyDB($db); return true; } - + } \ No newline at end of file diff --git a/hwe/sammo/Command/General/che_징병.php b/hwe/sammo/Command/General/che_징병.php index b2d56703..3e538c9c 100644 --- a/hwe/sammo/Command/General/che_징병.php +++ b/hwe/sammo/Command/General/che_징병.php @@ -162,7 +162,7 @@ class che_징병 extends Command\GeneralCommand return 0; } - public function run(): bool + public function run(\Sammo\RandUtil $rng): bool { if (!$this->hasFullConditionMet()) { throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); @@ -222,7 +222,7 @@ class che_징병 extends Command\GeneralCommand $this->setResultTurn(new LastTurn(static::getName(), $this->arg)); $general->checkStatChange(); $general->setAuxVar('armType', $reqCrewType->armType); - tryUniqueItemLottery($general); + tryUniqueItemLottery(\sammo\genGenericUniqueRNGFromGeneral($general), $general); $general->applyDB($db); return true; diff --git a/hwe/sammo/Command/General/che_첩보.php b/hwe/sammo/Command/General/che_첩보.php index 276441a3..5102d1aa 100644 --- a/hwe/sammo/Command/General/che_첩보.php +++ b/hwe/sammo/Command/General/che_첩보.php @@ -120,7 +120,7 @@ class che_첩보 extends Command\GeneralCommand return "{$failReason} {$destCityName}에 {$commandName} 실패."; } - public function run(): bool + public function run(\Sammo\RandUtil $rng): bool { if (!$this->hasFullConditionMet()) { throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); @@ -202,8 +202,8 @@ class che_첩보 extends Command\GeneralCommand 'spy'=>Json::encode($spyInfo) ], 'nation=%i',$nationID); - $exp = Util::randRangeInt(1, 100); - $ded = Util::randRangeInt(1, 70); + $exp = $rng->nextRangeInt(1, 100); + $ded = $rng->nextRangeInt(1, 70); [$reqGold, $reqRice] = $this->getCost(); $general->increaseInheritancePoint(InheritanceKey::active_action, 0.5);//NOTE: 첩보만 예외! @@ -214,7 +214,7 @@ class che_첩보 extends Command\GeneralCommand $general->increaseVar('leadership_exp', 1); $this->setResultTurn(new LastTurn(static::getName(), $this->arg)); $general->checkStatChange(); - tryRollbackInheritUniqueItem($general); + tryRollbackInheritUniqueItem($rng, $general); $general->applyDB($db); return true; diff --git a/hwe/sammo/Command/General/che_출병.php b/hwe/sammo/Command/General/che_출병.php index ccfa306b..7cfcacf7 100644 --- a/hwe/sammo/Command/General/che_출병.php +++ b/hwe/sammo/Command/General/che_출병.php @@ -20,6 +20,9 @@ use \sammo\Constraint\Constraint; use \sammo\Constraint\ConstraintHelper; use sammo\CityConst; use sammo\Enums\InheritanceKey; +use sammo\LiteHashDRBG; +use sammo\RandUtil; +use sammo\UniqueConst; class che_출병 extends Command\GeneralCommand { @@ -127,7 +130,7 @@ class che_출병 extends Command\GeneralCommand return "{$failReason} {$destCityName}{$josaRo} {$commandName} 실패."; } - public function run(): bool + public function run(RandUtil $rng): bool { if (!$this->hasFullConditionMet()) { throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); @@ -188,7 +191,7 @@ class che_출병 extends Command\GeneralCommand } } while (false); - $defenderCityID = (int) Util::choiceRandom($candidateCities); + $defenderCityID = (int) $rng->choice($candidateCities); $this->setDestCity($defenderCityID); $defenderCityName = $this->destCity['name']; $josaRo = JosaUtil::pick($defenderCityName, '로'); @@ -236,9 +239,21 @@ class che_출병 extends Command\GeneralCommand $general->applyDB($db); - processWar($general, $this->nation, $this->destCity); - tryUniqueItemLottery($general); + //어디로 출병하느냐에 따라 사실 결과가 다르다 + $warRngPre = new LiteHashDRBG(Util::simpleSerialize( + UniqueConst::$hiddenSeed, + 'war', + $logger->getYear(), + $logger->getMonth(), + $general->getID(), + $defenderCityID, + )); + $warRngSeed = bin2hex($warRngPre->nextBytes(16)); + + processWar($warRngSeed, $general, $this->nation, $this->destCity); + + tryUniqueItemLottery(\sammo\genGenericUniqueRNGFromGeneral($general), $general); $general->applyDB($db); return true; diff --git a/hwe/sammo/Command/General/che_탈취.php b/hwe/sammo/Command/General/che_탈취.php index 57440220..2c1f9668 100644 --- a/hwe/sammo/Command/General/che_탈취.php +++ b/hwe/sammo/Command/General/che_탈취.php @@ -6,7 +6,8 @@ use \sammo\{ General, ActionLogger, GameConst, GameUnitConst, - Command + Command, + RandUtil }; class che_탈취 extends che_화계{ @@ -15,7 +16,7 @@ class che_탈취 extends che_화계{ static protected $statType = 'strength'; static protected $injuryGeneral = false; - protected function affectDestCity(int $injuryCount){ + protected function affectDestCity(RandUtil $rng, int $injuryCount){ $general = $this->generalObj; $nationID = $general->getNationID(); $date = $general->getTurnTime($general::TURNTIME_HM); @@ -35,8 +36,8 @@ class che_탈취 extends che_화계{ $yearCoef = sqrt(1 + ($this->env['year'] - $this->env['startyear']) / 4) / 2; $commRatio = $destCity['comm'] / $destCity['comm_max']; $agriRatio = $destCity['agri'] / $destCity['agri_max']; - $gold = Util::randRangeInt(GameConst::$sabotageDamageMin, GameConst::$sabotageDamageMax) * $destCity['level'] * $yearCoef * (0.25 + $commRatio / 4); - $rice = Util::randRangeInt(GameConst::$sabotageDamageMin, GameConst::$sabotageDamageMax) * $destCity['level'] * $yearCoef * (0.25 + $agriRatio / 4); + $gold = $rng->nextRangeInt(GameConst::$sabotageDamageMin, GameConst::$sabotageDamageMax) * $destCity['level'] * $yearCoef * (0.25 + $commRatio / 4); + $rice = $rng->nextRangeInt(GameConst::$sabotageDamageMin, GameConst::$sabotageDamageMax) * $destCity['level'] * $yearCoef * (0.25 + $agriRatio / 4); if($destCity['supply']){ [$destNationGold, $destNationRice] = $db->queryFirstList('SELECT gold,rice FROM nation WHERE nation=%i', $destNationID); diff --git a/hwe/sammo/Command/General/che_파괴.php b/hwe/sammo/Command/General/che_파괴.php index 54ffd3ed..98b60473 100644 --- a/hwe/sammo/Command/General/che_파괴.php +++ b/hwe/sammo/Command/General/che_파괴.php @@ -3,10 +3,11 @@ namespace sammo\Command\General; use \sammo\{ DB, Util, JosaUtil, - General, + General, ActionLogger, GameConst, GameUnitConst, - Command + Command, + RandUtil }; class che_파괴 extends che_화계{ @@ -15,7 +16,7 @@ class che_파괴 extends che_화계{ static protected $statType = 'strength'; static protected $injuryGeneral = true; - protected function affectDestCity(int $injuryCount){ + protected function affectDestCity(RandUtil $rng, int $injuryCount){ $general = $this->generalObj; $date = $general->getTurnTime($general::TURNTIME_HM); @@ -29,8 +30,8 @@ class che_파괴 extends che_화계{ $commandName = $this->getName(); // 파괴 - $defAmount = Util::valueFit(Util::randRangeInt(GameConst::$sabotageDamageMin, GameConst::$sabotageDamageMax), null, $destCity['def']); - $wallAmount = Util::valueFit(Util::randRangeInt(GameConst::$sabotageDamageMin, GameConst::$sabotageDamageMax), null, $destCity['wall']); + $defAmount = Util::valueFit($rng->nextRangeInt(GameConst::$sabotageDamageMin, GameConst::$sabotageDamageMax), null, $destCity['def']); + $wallAmount = Util::valueFit($rng->nextRangeInt(GameConst::$sabotageDamageMin, GameConst::$sabotageDamageMax), null, $destCity['wall']); if($defAmount < 0){ $defAmount = 0; } if($wallAmount < 0){ $wallAmount = 0; } @@ -56,5 +57,5 @@ class che_파괴 extends che_화계{ ActionLogger::PLAIN ); } - + } \ No newline at end of file diff --git a/hwe/sammo/Command/General/che_하야.php b/hwe/sammo/Command/General/che_하야.php index 8658dc19..5cbcbd69 100644 --- a/hwe/sammo/Command/General/che_하야.php +++ b/hwe/sammo/Command/General/che_하야.php @@ -53,7 +53,7 @@ class che_하야 extends Command\GeneralCommand{ return 0; } - public function run():bool{ + public function run(\Sammo\RandUtil $rng):bool{ if(!$this->hasFullConditionMet()){ throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); } @@ -118,7 +118,7 @@ class che_하야 extends Command\GeneralCommand{ $this->setResultTurn(new LastTurn(static::getName(), $this->arg)); $general->checkStatChange(); - tryRollbackInheritUniqueItem($general); + tryRollbackInheritUniqueItem($rng, $general); $general->applyDB($db); return true; diff --git a/hwe/sammo/Command/General/che_해산.php b/hwe/sammo/Command/General/che_해산.php index a848e160..48389b07 100644 --- a/hwe/sammo/Command/General/che_해산.php +++ b/hwe/sammo/Command/General/che_해산.php @@ -57,7 +57,7 @@ class che_해산 extends Command\GeneralCommand{ return 0; } - public function run():bool{ + public function run(\Sammo\RandUtil $rng):bool{ if(!$this->hasFullConditionMet()){ throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); } @@ -99,7 +99,7 @@ class che_해산 extends Command\GeneralCommand{ $oldGeneral->setVar('makelimit', 12); $oldGeneral->applyDB($db); } - tryRollbackInheritUniqueItem($general); + tryRollbackInheritUniqueItem($rng, $general); $general->applyDB($db); // 이벤트 핸들러 동작 diff --git a/hwe/sammo/Command/General/che_헌납.php b/hwe/sammo/Command/General/che_헌납.php index 424e3807..c95f6912 100644 --- a/hwe/sammo/Command/General/che_헌납.php +++ b/hwe/sammo/Command/General/che_헌납.php @@ -107,7 +107,7 @@ class che_헌납 extends Command\GeneralCommand return 0; } - public function run(): bool + public function run(\Sammo\RandUtil $rng): bool { if (!$this->hasFullConditionMet()) { throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); @@ -146,7 +146,7 @@ class che_헌납 extends Command\GeneralCommand $this->setResultTurn(new LastTurn(static::getName(), $this->arg)); $general->checkStatChange(); - tryUniqueItemLottery($general); + tryUniqueItemLottery(\sammo\genGenericUniqueRNGFromGeneral($general), $general); $general->applyDB($db); return true; diff --git a/hwe/sammo/Command/General/che_화계.php b/hwe/sammo/Command/General/che_화계.php index 5b33bd5f..0b2cd114 100644 --- a/hwe/sammo/Command/General/che_화계.php +++ b/hwe/sammo/Command/General/che_화계.php @@ -17,6 +17,7 @@ use function sammo\tryRollbackInheritUniqueItem; use \sammo\Constraint\ConstraintHelper; use sammo\CityConst; use sammo\Enums\RankColumn; +use sammo\RandUtil; class che_화계 extends Command\GeneralCommand { @@ -200,7 +201,7 @@ class che_화계 extends Command\GeneralCommand return "{$failReason} {$destCityName}에 {$commandName} 실패."; } - protected function affectDestCity(int $injuryCount) + protected function affectDestCity(RandUtil $rng, int $injuryCount) { $general = $this->generalObj; $date = $general->getTurnTime($general::TURNTIME_HM); @@ -214,8 +215,8 @@ class che_화계 extends Command\GeneralCommand $commandName = $this->getName(); - $agriAmount = Util::valueFit(Util::randRangeInt(GameConst::$sabotageDamageMin, GameConst::$sabotageDamageMax), null, $destCity['agri']); - $commAmount = Util::valueFit(Util::randRangeInt(GameConst::$sabotageDamageMin, GameConst::$sabotageDamageMax), null, $destCity['comm']); + $agriAmount = Util::valueFit($rng->nextRangeInt(GameConst::$sabotageDamageMin, GameConst::$sabotageDamageMax), null, $destCity['agri']); + $commAmount = Util::valueFit($rng->nextRangeInt(GameConst::$sabotageDamageMin, GameConst::$sabotageDamageMax), null, $destCity['comm']); $destCity['agri'] -= $agriAmount; $destCity['comm'] -= $commAmount; @@ -239,7 +240,7 @@ class che_화계 extends Command\GeneralCommand ); } - public function run(): bool + public function run(\Sammo\RandUtil $rng): bool { if (!$this->hasFullConditionMet()) { throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); @@ -279,12 +280,12 @@ class che_화계 extends Command\GeneralCommand $prob /= $dist; $prob = Util::valueFit($prob, 0, 0.5); - if (!Util::randBool($prob)) { + if (!$rng->nextBool($prob)) { $josaYi = JosaUtil::pick($commandName, '이'); $logger->pushGeneralActionLog("{$destCityName}에 {$commandName}{$josaYi} 실패했습니다. <1>$date"); - $exp = Util::randRangeInt(1, 100); - $ded = Util::randRangeInt(1, 70); + $exp = $rng->nextRangeInt(1, 100); + $ded = $rng->nextRangeInt(1, 70); [$reqGold, $reqRice] = $this->getCost(); $general->increaseVarWithLimit('gold', -$reqGold, 0); @@ -295,18 +296,18 @@ class che_화계 extends Command\GeneralCommand $this->setResultTurn(new LastTurn(static::getName(), $this->arg)); $general->checkStatChange(); - tryRollbackInheritUniqueItem($general); + tryRollbackInheritUniqueItem($rng, $general); $general->applyDB($db); return false; } if (static::$injuryGeneral) { - $injuryCount = \sammo\SabotageInjury($destCityGeneralList, '계략'); + $injuryCount = \sammo\SabotageInjury($rng, $destCityGeneralList, '계략'); } else { $injuryCount = 0; } - $this->affectDestCity($injuryCount); + $this->affectDestCity($rng, $injuryCount); $itemObj = $general->getItem(); if ($itemObj->tryConsumeNow($general, 'GeneralCommand', '계략')) { @@ -317,8 +318,8 @@ class che_화계 extends Command\GeneralCommand $general->deleteItem(); } - $exp = Util::randRangeInt(201, 300); - $ded = Util::randRangeInt(141, 210); + $exp = $rng->nextRangeInt(201, 300); + $ded = $rng->nextRangeInt(141, 210); [$reqGold, $reqRice] = $this->getCost(); $general->increaseVarWithLimit('gold', -$reqGold, 0); @@ -329,7 +330,7 @@ class che_화계 extends Command\GeneralCommand $general->increaseRankVar(RankColumn::firenum, 1); $this->setResultTurn(new LastTurn(static::getName(), $this->arg)); $general->checkStatChange(); - tryRollbackInheritUniqueItem($general); + tryRollbackInheritUniqueItem($rng, $general); $general->applyDB($db); return true; diff --git a/hwe/sammo/Command/General/che_훈련.php b/hwe/sammo/Command/General/che_훈련.php index 52292f88..528f23e9 100644 --- a/hwe/sammo/Command/General/che_훈련.php +++ b/hwe/sammo/Command/General/che_훈련.php @@ -3,7 +3,7 @@ namespace sammo\Command\General; use \sammo\{ DB, Util, JosaUtil, - General, + General, ActionLogger, GameConst, GameUnitConst, LastTurn, @@ -33,13 +33,13 @@ class che_훈련 extends Command\GeneralCommand{ $this->setNation(); $this->minConditionConstraints=[ - ConstraintHelper::NotBeNeutral(), + ConstraintHelper::NotBeNeutral(), ConstraintHelper::NotWanderingNation(), ConstraintHelper::OccupiedCity(), ]; - + $this->fullConditionConstraints=[ - ConstraintHelper::NotBeNeutral(), + ConstraintHelper::NotBeNeutral(), ConstraintHelper::NotWanderingNation(), ConstraintHelper::OccupiedCity(), ConstraintHelper::ReqGeneralCrew(), @@ -66,7 +66,7 @@ class che_훈련 extends Command\GeneralCommand{ public function getCost():array{ return [0, 0]; } - + public function getPreReqTurn():int{ return 0; } @@ -75,7 +75,7 @@ class che_훈련 extends Command\GeneralCommand{ return 0; } - public function run():bool{ + public function run(\Sammo\RandUtil $rng):bool{ if(!$this->hasFullConditionMet()){ throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); } @@ -107,11 +107,11 @@ class che_훈련 extends Command\GeneralCommand{ $general->increaseVar('leadership_exp', 1); $this->setResultTurn(new LastTurn(static::getName(), $this->arg)); $general->checkStatChange(); - tryUniqueItemLottery($general); + tryUniqueItemLottery(\sammo\genGenericUniqueRNGFromGeneral($general), $general); $general->applyDB($db); return true; } - + } \ No newline at end of file diff --git a/hwe/sammo/Command/General/휴식.php b/hwe/sammo/Command/General/휴식.php index 5b02f96c..ecdb0b83 100644 --- a/hwe/sammo/Command/General/휴식.php +++ b/hwe/sammo/Command/General/휴식.php @@ -34,14 +34,14 @@ class 휴식 extends Command\GeneralCommand{ return 0; } - public function run():bool{ + public function run(\Sammo\RandUtil $rng):bool{ $general = $this->generalObj; $logger = $general->getLogger(); $date = $general->getTurnTime($general::TURNTIME_HM); $logger->pushGeneralActionLog("아무것도 실행하지 않았습니다. <1>$date"); $this->setResultTurn(new LastTurn()); - tryRollbackInheritUniqueItem($general); + tryRollbackInheritUniqueItem($rng, $general); $general->applyDB(DB::db()); return true; } diff --git a/hwe/sammo/Command/Nation/che_감축.php b/hwe/sammo/Command/Nation/che_감축.php index 575f7d4e..a54af37b 100644 --- a/hwe/sammo/Command/Nation/che_감축.php +++ b/hwe/sammo/Command/Nation/che_감축.php @@ -136,7 +136,7 @@ class che_감축 extends Command\NationCommand{ return "수도를 {$commandName}"; } - public function run():bool{ + public function run(\Sammo\RandUtil $rng):bool{ if(!$this->hasFullConditionMet()){ throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); } diff --git a/hwe/sammo/Command/Nation/che_국기변경.php b/hwe/sammo/Command/Nation/che_국기변경.php index 9250a228..5bea215e 100644 --- a/hwe/sammo/Command/Nation/che_국기변경.php +++ b/hwe/sammo/Command/Nation/che_국기변경.php @@ -91,7 +91,7 @@ class che_국기변경 extends Command\NationCommand return "【국기】를 변경"; } - public function run(): bool + public function run(\Sammo\RandUtil $rng): bool { if (!$this->hasFullConditionMet()) { throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); diff --git a/hwe/sammo/Command/Nation/che_국호변경.php b/hwe/sammo/Command/Nation/che_국호변경.php index 68e53db8..10bd40fa 100644 --- a/hwe/sammo/Command/Nation/che_국호변경.php +++ b/hwe/sammo/Command/Nation/che_국호변경.php @@ -103,7 +103,7 @@ class che_국호변경 extends Command\NationCommand return "국호를 【{$newNationName}】{$josaRo} 변경"; } - public function run(): bool + public function run(\Sammo\RandUtil $rng): bool { if (!$this->hasFullConditionMet()) { throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); diff --git a/hwe/sammo/Command/Nation/che_급습.php b/hwe/sammo/Command/Nation/che_급습.php index 8ef601f3..7a178e9c 100644 --- a/hwe/sammo/Command/Nation/che_급습.php +++ b/hwe/sammo/Command/Nation/che_급습.php @@ -121,7 +121,7 @@ class che_급습 extends Command\NationCommand } - public function run(): bool + public function run(\Sammo\RandUtil $rng): bool { if (!$this->hasFullConditionMet()) { throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); diff --git a/hwe/sammo/Command/Nation/che_몰수.php b/hwe/sammo/Command/Nation/che_몰수.php index 6f90ea69..2d563afb 100644 --- a/hwe/sammo/Command/Nation/che_몰수.php +++ b/hwe/sammo/Command/Nation/che_몰수.php @@ -141,7 +141,7 @@ class che_몰수 extends Command\NationCommand } - public function run(): bool + public function run(\Sammo\RandUtil $rng): bool { if (!$this->hasFullConditionMet()) { throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); @@ -168,7 +168,7 @@ class che_몰수 extends Command\NationCommand ); $amountText = number_format($amount, 0); - if ($destGeneral->getNPCType() >= 2 && Util::randBool(GameConst::$npcSeizureMessageProb)) { + if ($destGeneral->getNPCType() >= 2 && $rng->nextBool(GameConst::$npcSeizureMessageProb)) { $npcTexts = [ '몰수를 하다니... 이것이 윗사람이 할 짓이란 말입니까...', '사유재산까지 몰수해가면서 이 나라가 잘 될거라 믿습니까? 정말 이해할 수가 없군요...', @@ -176,7 +176,7 @@ class che_몰수 extends Command\NationCommand '몰수해간 내 자금... 언젠가 몰래 다시 빼내올 것이다...', '몰수로 인한 사기 저하는 몰수로 얻은 물자보다 더 손해란걸 모른단 말인가!' ]; - $text = Util::choiceRandom($npcTexts); + $text = $rng->choice($npcTexts); $src = new MessageTarget( $destGeneral->getID(), $destGeneral->getName(), diff --git a/hwe/sammo/Command/Nation/che_물자원조.php b/hwe/sammo/Command/Nation/che_물자원조.php index 2dcdba61..bfaad9d1 100644 --- a/hwe/sammo/Command/Nation/che_물자원조.php +++ b/hwe/sammo/Command/Nation/che_물자원조.php @@ -155,7 +155,7 @@ class che_물자원조 extends Command\NationCommand } - public function run(): bool + public function run(\Sammo\RandUtil $rng): bool { if (!$this->hasFullConditionMet()) { throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); diff --git a/hwe/sammo/Command/Nation/che_발령.php b/hwe/sammo/Command/Nation/che_발령.php index 26ad01a3..7acf90dd 100644 --- a/hwe/sammo/Command/Nation/che_발령.php +++ b/hwe/sammo/Command/Nation/che_발령.php @@ -129,7 +129,7 @@ class che_발령 extends Command\NationCommand } - public function run(): bool + public function run(\Sammo\RandUtil $rng): bool { if (!$this->hasFullConditionMet()) { throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); diff --git a/hwe/sammo/Command/Nation/che_백성동원.php b/hwe/sammo/Command/Nation/che_백성동원.php index de54dc2f..64d8dffd 100644 --- a/hwe/sammo/Command/Nation/che_백성동원.php +++ b/hwe/sammo/Command/Nation/che_백성동원.php @@ -111,7 +111,7 @@ class che_백성동원 extends Command\NationCommand return "【{$destCityName}】에 {$commandName}"; } - public function run(): bool + public function run(\Sammo\RandUtil $rng): bool { if (!$this->hasFullConditionMet()) { throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); diff --git a/hwe/sammo/Command/Nation/che_불가침수락.php b/hwe/sammo/Command/Nation/che_불가침수락.php index 89ee1965..dbf923a4 100644 --- a/hwe/sammo/Command/Nation/che_불가침수락.php +++ b/hwe/sammo/Command/Nation/che_불가침수락.php @@ -22,6 +22,7 @@ use \sammo\Constraint\Constraint; use \sammo\Constraint\ConstraintHelper; use sammo\Json; use sammo\KVStorage; +use sammo\RandUtil; class che_불가침수락 extends Command\NationCommand { @@ -165,7 +166,7 @@ class che_불가침수락 extends Command\NationCommand return "{$year}년 {$month}월까지 불가침 합의"; } - public function run(): bool + public function run(RandUtil $rng): bool { if (!$this->hasFullConditionMet()) { throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); diff --git a/hwe/sammo/Command/Nation/che_불가침제의.php b/hwe/sammo/Command/Nation/che_불가침제의.php index e8ea5359..ba8fe753 100644 --- a/hwe/sammo/Command/Nation/che_불가침제의.php +++ b/hwe/sammo/Command/Nation/che_불가침제의.php @@ -148,7 +148,7 @@ class che_불가침제의 extends Command\NationCommand } - public function run(): bool + public function run(\Sammo\RandUtil $rng): bool { if (!$this->hasFullConditionMet()) { throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); diff --git a/hwe/sammo/Command/Nation/che_불가침파기수락.php b/hwe/sammo/Command/Nation/che_불가침파기수락.php index 0e4ecc56..3ca9f794 100644 --- a/hwe/sammo/Command/Nation/che_불가침파기수락.php +++ b/hwe/sammo/Command/Nation/che_불가침파기수락.php @@ -20,6 +20,7 @@ use function \sammo\getNationStaticInfo; use \sammo\Constraint\Constraint; use \sammo\Constraint\ConstraintHelper; +use sammo\RandUtil; class che_불가침파기수락 extends Command\NationCommand { @@ -71,7 +72,7 @@ class che_불가침파기수락 extends Command\NationCommand $this->permissionConstraints = [ ConstraintHelper::AlwaysFail('예약 불가능 커맨드') - ]; + ]; } protected function initWithArg() @@ -120,7 +121,7 @@ class che_불가침파기수락 extends Command\NationCommand return "{$destNationName}국과 불가침 파기 합의"; } - public function run(): bool + public function run(RandUtil $rng): bool { if (!$this->hasFullConditionMet()) { throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); diff --git a/hwe/sammo/Command/Nation/che_불가침파기제의.php b/hwe/sammo/Command/Nation/che_불가침파기제의.php index 4d500534..9a22b215 100644 --- a/hwe/sammo/Command/Nation/che_불가침파기제의.php +++ b/hwe/sammo/Command/Nation/che_불가침파기제의.php @@ -102,7 +102,7 @@ class che_불가침파기제의 extends Command\NationCommand{ } - public function run():bool{ + public function run(\Sammo\RandUtil $rng):bool{ if(!$this->hasFullConditionMet()){ throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); } diff --git a/hwe/sammo/Command/Nation/che_선전포고.php b/hwe/sammo/Command/Nation/che_선전포고.php index 6df46ec8..69d90988 100644 --- a/hwe/sammo/Command/Nation/che_선전포고.php +++ b/hwe/sammo/Command/Nation/che_선전포고.php @@ -116,7 +116,7 @@ class che_선전포고 extends Command\NationCommand } - public function run(): bool + public function run(\Sammo\RandUtil $rng): bool { if (!$this->hasFullConditionMet()) { throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); diff --git a/hwe/sammo/Command/Nation/che_수몰.php b/hwe/sammo/Command/Nation/che_수몰.php index 6305d33e..62ca5cbd 100644 --- a/hwe/sammo/Command/Nation/che_수몰.php +++ b/hwe/sammo/Command/Nation/che_수몰.php @@ -116,7 +116,7 @@ class che_수몰 extends Command\NationCommand return "【{$destCityName}】{$josaUl} {$commandName}"; } - public function run(): bool + public function run(\Sammo\RandUtil $rng): bool { if (!$this->hasFullConditionMet()) { throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); diff --git a/hwe/sammo/Command/Nation/che_의병모집.php b/hwe/sammo/Command/Nation/che_의병모집.php index 5bfc12c6..2453c6e7 100644 --- a/hwe/sammo/Command/Nation/che_의병모집.php +++ b/hwe/sammo/Command/Nation/che_의병모집.php @@ -74,7 +74,7 @@ class che_의병모집 extends Command\NationCommand return $nextTerm; } - public function run(): bool + public function run(\Sammo\RandUtil $rng): bool { if (!$this->hasFullConditionMet()) { throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); @@ -143,8 +143,8 @@ class che_의병모집 extends Command\NationCommand from general where nation=%i', $nationID ); - foreach(\sammo\pickGeneralFromPool($db, 0, $createGenCnt) as $pickedNPC){ - + foreach(\sammo\pickGeneralFromPool($db, $rng, 0, $createGenCnt) as $pickedNPC){ + $newNPC = $pickedNPC->getGeneralBuilder(); $newNPC->setCityID($general->getCityID()); @@ -152,12 +152,12 @@ class che_의병모집 extends Command\NationCommand $newNPC->setSpecial('None', 'None'); $newNPC->setLifeSpan($env['year']-20, $env['year']+10); - $newNPC->setKillturn(Util::randRangeInt(64, 70)); + $newNPC->setKillturn($rng->nextRangeInt(64, 70)); $newNPC->setNPCType(4); $newNPC->setMoney(1000, 1000); $newNPC->setSpecYear(19, 19); $newNPC->fillRemainSpecAsRandom($pickTypeList, $avgGen, $env); - + $newNPC->build($this->env); $pickedNPC->occupyGeneralName(); } diff --git a/hwe/sammo/Command/Nation/che_이호경식.php b/hwe/sammo/Command/Nation/che_이호경식.php index 5ffc6094..afb61b10 100644 --- a/hwe/sammo/Command/Nation/che_이호경식.php +++ b/hwe/sammo/Command/Nation/che_이호경식.php @@ -118,7 +118,7 @@ class che_이호경식 extends Command\NationCommand } - public function run(): bool + public function run(\Sammo\RandUtil $rng): bool { if (!$this->hasFullConditionMet()) { throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); diff --git a/hwe/sammo/Command/Nation/che_종전수락.php b/hwe/sammo/Command/Nation/che_종전수락.php index 017a0f2d..dfbee08c 100644 --- a/hwe/sammo/Command/Nation/che_종전수락.php +++ b/hwe/sammo/Command/Nation/che_종전수락.php @@ -76,7 +76,7 @@ class che_종전수락 extends Command\NationCommand $this->setCity(); $this->setNation(); - + $nationID = $this->nation['nation']; $this->permissionConstraints = [ @@ -129,7 +129,7 @@ class che_종전수락 extends Command\NationCommand return "{$destNationName}국과 종전 합의"; } - public function run(): bool + public function run(\Sammo\RandUtil $rng): bool { if (!$this->hasFullConditionMet()) { throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); diff --git a/hwe/sammo/Command/Nation/che_종전제의.php b/hwe/sammo/Command/Nation/che_종전제의.php index a738957a..63370d8b 100644 --- a/hwe/sammo/Command/Nation/che_종전제의.php +++ b/hwe/sammo/Command/Nation/che_종전제의.php @@ -100,7 +100,7 @@ class che_종전제의 extends Command\NationCommand{ } - public function run():bool{ + public function run(\Sammo\RandUtil $rng):bool{ if(!$this->hasFullConditionMet()){ throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); } diff --git a/hwe/sammo/Command/Nation/che_증축.php b/hwe/sammo/Command/Nation/che_증축.php index b1ce0487..84cfbee5 100644 --- a/hwe/sammo/Command/Nation/che_증축.php +++ b/hwe/sammo/Command/Nation/che_증축.php @@ -134,7 +134,7 @@ class che_증축 extends Command\NationCommand{ return "수도를 {$commandName}"; } - public function run():bool{ + public function run(\Sammo\RandUtil $rng):bool{ if(!$this->hasFullConditionMet()){ throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); } diff --git a/hwe/sammo/Command/Nation/che_천도.php b/hwe/sammo/Command/Nation/che_천도.php index ec6738bd..f9a85165 100644 --- a/hwe/sammo/Command/Nation/che_천도.php +++ b/hwe/sammo/Command/Nation/che_천도.php @@ -180,7 +180,7 @@ class che_천도 extends Command\NationCommand return "【{$destCityName}】{$josaRo} {$commandName}"; } - public function run(): bool + public function run(\Sammo\RandUtil $rng): bool { if (!$this->hasFullConditionMet()) { throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); diff --git a/hwe/sammo/Command/Nation/che_초토화.php b/hwe/sammo/Command/Nation/che_초토화.php index 5cb63e07..805ef47b 100644 --- a/hwe/sammo/Command/Nation/che_초토화.php +++ b/hwe/sammo/Command/Nation/che_초토화.php @@ -124,7 +124,7 @@ class che_초토화 extends Command\NationCommand{ return Util::toInt($amount); } - public function run():bool{ + public function run(\Sammo\RandUtil $rng):bool{ if(!$this->hasFullConditionMet()){ throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); } diff --git a/hwe/sammo/Command/Nation/che_포상.php b/hwe/sammo/Command/Nation/che_포상.php index 6d57c02c..f69a4f55 100644 --- a/hwe/sammo/Command/Nation/che_포상.php +++ b/hwe/sammo/Command/Nation/che_포상.php @@ -133,7 +133,7 @@ class che_포상 extends Command\NationCommand } - public function run(): bool + public function run(\Sammo\RandUtil $rng): bool { if (!$this->hasFullConditionMet()) { throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); diff --git a/hwe/sammo/Command/Nation/che_피장파장.php b/hwe/sammo/Command/Nation/che_피장파장.php index c2a3421e..2507e2d3 100644 --- a/hwe/sammo/Command/Nation/che_피장파장.php +++ b/hwe/sammo/Command/Nation/che_피장파장.php @@ -159,7 +159,7 @@ class che_피장파장 extends Command\NationCommand } - public function run(): bool + public function run(\Sammo\RandUtil $rng): bool { if (!$this->hasFullConditionMet()) { throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); diff --git a/hwe/sammo/Command/Nation/che_필사즉생.php b/hwe/sammo/Command/Nation/che_필사즉생.php index 61b93fb6..431b0c63 100644 --- a/hwe/sammo/Command/Nation/che_필사즉생.php +++ b/hwe/sammo/Command/Nation/che_필사즉생.php @@ -33,7 +33,7 @@ class che_필사즉생 extends Command\NationCommand{ $this->setCity(); $this->setNation(['strategic_cmd_limit']); - + $this->fullConditionConstraints=[ ConstraintHelper::OccupiedCity(), ConstraintHelper::BeChief(), @@ -43,7 +43,7 @@ class che_필사즉생 extends Command\NationCommand{ ConstraintHelper::AvailableStrategicCommand() ]; } - + public function getCommandDetailTitle():string{ $name = $this->getName(); $reqTurn = $this->getPreReqTurn()+1; @@ -51,24 +51,24 @@ class che_필사즉생 extends Command\NationCommand{ 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 = Util::round(sqrt($genCount*8)*10); $nextTerm = $this->generalObj->onCalcStrategic($this->getName(), 'delay', $nextTerm); return $nextTerm; } - public function run():bool{ + public function run(\Sammo\RandUtil $rng):bool{ if(!$this->hasFullConditionMet()){ throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); } @@ -79,7 +79,7 @@ class che_필사즉생 extends Command\NationCommand{ $generalID = $general->getID(); $generalName = $general->getName(); $date = $general->getTurnTime($general::TURNTIME_HM); - + $nationID = $general->getNationID(); $nationName = $this->nation['name']; @@ -101,8 +101,8 @@ class che_필사즉생 extends Command\NationCommand{ } if($targetGeneral->getVar('atmos') < 100){ $targetGeneral->setVar('atmos', 100); - } - + } + $targetGeneral->applyDB($db); } diff --git a/hwe/sammo/Command/Nation/che_허보.php b/hwe/sammo/Command/Nation/che_허보.php index 5cfbf580..b3c201b7 100644 --- a/hwe/sammo/Command/Nation/che_허보.php +++ b/hwe/sammo/Command/Nation/che_허보.php @@ -116,7 +116,7 @@ class che_허보 extends Command\NationCommand return "【{$destCityName}】에 {$commandName}"; } - public function run(): bool + public function run(\Sammo\RandUtil $rng): bool { if (!$this->hasFullConditionMet()) { throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); @@ -167,10 +167,10 @@ class che_허보 extends Command\NationCommand $targetLogger = $targetGeneral->getLogger(); $targetLogger->pushGeneralActionLog($destBroadcastMessage, ActionLogger::PLAIN); - $moveCityID = Util::choiceRandom($destNationCityList); + $moveCityID = $rng->choice($destNationCityList); if ($moveCityID == $destCityID) { //현재도시면 다시 랜덤 추첨 - $moveCityID = Util::choiceRandom($destNationCityList); + $moveCityID = $rng->choice($destNationCityList); } $targetGeneral->setVar('city', $moveCityID); diff --git a/hwe/sammo/Command/Nation/휴식.php b/hwe/sammo/Command/Nation/휴식.php index 952e68d6..4f5af13c 100644 --- a/hwe/sammo/Command/Nation/휴식.php +++ b/hwe/sammo/Command/Nation/휴식.php @@ -16,7 +16,7 @@ class 휴식 extends Command\NationCommand{ protected function init(){ //아무것도 하지 않음 $this->fullConditionConstraints=[]; - + } public function getPreReqTurn():int{ @@ -31,7 +31,7 @@ class 휴식 extends Command\NationCommand{ return [0, 0]; } - public function run():bool{ + public function run(\Sammo\RandUtil $rng):bool{ $this->setResultTurn(new LastTurn(static::getName(), $this->arg)); return true; } diff --git a/hwe/sammo/DefaultAction.php b/hwe/sammo/DefaultAction.php index a50f5927..612e7832 100644 --- a/hwe/sammo/DefaultAction.php +++ b/hwe/sammo/DefaultAction.php @@ -50,7 +50,7 @@ trait DefaultAction{ return null; } - public function onArbitraryAction(General $general, string $actionType, ?string $phase=null, $aux=null): null|array{ + public function onArbitraryAction(General $general, RandUtil $rng, string $actionType, ?string $phase=null, $aux=null): null|array{ return $aux; } } \ No newline at end of file diff --git a/hwe/sammo/DiplomaticMessage.php b/hwe/sammo/DiplomaticMessage.php index 199d2e91..dc53bbe5 100644 --- a/hwe/sammo/DiplomaticMessage.php +++ b/hwe/sammo/DiplomaticMessage.php @@ -88,7 +88,7 @@ class DiplomaticMessage extends Message{ return [self::INVALID, $commandObj->getFailString()]; } - $commandObj->run(); + $commandObj->run(NoRNG::rngInstance()); $commandObj->setNextAvailable(); return [self::ACCEPTED, '']; @@ -110,7 +110,7 @@ class DiplomaticMessage extends Message{ return [self::INVALID, $commandObj->getFailString()]; } - $commandObj->run(); + $commandObj->run(NoRNG::rngInstance()); $commandObj->setNextAvailable(); return [self::ACCEPTED, '']; @@ -132,7 +132,7 @@ class DiplomaticMessage extends Message{ return [self::INVALID, $commandObj->getFailString()]; } - $commandObj->run(); + $commandObj->run(NoRNG::rngInstance()); $commandObj->setNextAvailable(); return [self::ACCEPTED, '']; diff --git a/hwe/sammo/Event/Action/CreateManyNPC.php b/hwe/sammo/Event/Action/CreateManyNPC.php index 3c50b046..c7292165 100644 --- a/hwe/sammo/Event/Action/CreateManyNPC.php +++ b/hwe/sammo/Event/Action/CreateManyNPC.php @@ -1,37 +1,51 @@ npcCount = $npcCount; $this->fillCnt = $fillCnt; } - protected function generateNPC($env, int $cnt){ - $pickTypeList = ['무'=>1, '지'=>1]; + protected function generateNPC($env, int $cnt) + { + $pickTypeList = ['무' => 1, '지' => 1]; - $age = Util::randRangeInt(20, 25); + $rng = new RandUtil(new LiteHashDRBG(Util::simpleSerialize( + UniqueConst::$hiddenSeed, + 'CreateManyNPC', + $env['year'], + $env['month'] + ))); + $age = $rng->nextRangeInt(20, 25); $birthYear = $env['year'] - $age; - $deathYear = $env['year'] + Util::randRangeInt(10, 50); + $deathYear = $env['year'] + $rng->nextRangeInt(10, 50); $result = []; - foreach(pickGeneralFromPool(DB::db(), 0, $cnt) as $pickedNPC){ + foreach (pickGeneralFromPool(DB::db(), $rng, 0, $cnt) as $pickedNPC) { $newNPC = $pickedNPC->getGeneralBuilder(); $newNPC->setNationID(0) - ->setNPCType(3) - ->setMoney(1000, 1000) - ->setExpDed(0, 0) - ->setLifeSpan($birthYear, $deathYear); - if($newNPC->getStat()[0]===null){ + ->setNPCType(3) + ->setMoney(1000, 1000) + ->setExpDed(0, 0) + ->setLifeSpan($birthYear, $deathYear); + if ($newNPC->getStat()[0] === null) { $newNPC->fillRandomStat($pickTypeList); } $newNPC->fillRemainSpecAsZero($env); @@ -45,14 +59,15 @@ class CreateManyNPC extends \sammo\Event\Action{ } - public function run(array $env){ - if($this->npcCount <= 0 && $this->fillCnt <= 0){ + public function run(array $env) + { + if ($this->npcCount <= 0 && $this->fillCnt <= 0) { return [__CLASS__, []]; } $moreGenCnt = 0; - if($this->fillCnt){ + if ($this->fillCnt) { $db = DB::db(); $nations = $db->queryFirstColumn('SELECT nation FROM general WHERE npc < 3 AND officer_level = 12'); $regGens = $db->queryFirstField('SELECT count(*) FROM general WHERE nation IN %li AND npc < 4', $nations); @@ -63,12 +78,11 @@ class CreateManyNPC extends \sammo\Event\Action{ $logger = new \sammo\ActionLogger(0, 0, $env['year'], $env['month']); $genCnt = count($result); - if($genCnt == 1){ + if ($genCnt == 1) { $npcName = $result[0][0]; $josaRa = \sammo\JosaUtil::pick($npcName, '라'); $logger->pushGlobalActionLog("$npcName{$josaRa}는 장수가 등장하였습니다."); - } - else{ + } else { $logger->pushGlobalActionLog("장수 {$genCnt}명이 등장하였습니다."); } $logger->pushGlobalHistoryLog("장수 {$genCnt}명이 등장했습니다.", \sammo\ActionLogger::NOTICE_YEAR_MONTH); @@ -76,4 +90,4 @@ class CreateManyNPC extends \sammo\Event\Action{ return [__CLASS__, $result]; } -} \ No newline at end of file +} diff --git a/hwe/sammo/Event/Action/RaiseInvader.php b/hwe/sammo/Event/Action/RaiseInvader.php index a4849868..880bfc72 100644 --- a/hwe/sammo/Event/Action/RaiseInvader.php +++ b/hwe/sammo/Event/Action/RaiseInvader.php @@ -7,6 +7,8 @@ use sammo\CityConst; use sammo\DB; use sammo\Json; use sammo\KVStorage; +use sammo\LiteHashDRBG; +use sammo\RandUtil; use sammo\Scenario\GeneralBuilder; use sammo\Scenario\Nation; use sammo\UniqueConst; @@ -140,6 +142,14 @@ class RaiseInvader extends \sammo\Event\Action ], true); $year = $env['year']; + $month = $env['month']; + + $rng = new RandUtil(new LiteHashDRBG(Util::simpleSerialize( + UniqueConst::$hiddenSeed, + 'RaiseInvader', + $year, + $month, + ))); $invaderNationIDList = []; refreshNationStaticInfo(); @@ -154,10 +164,10 @@ class RaiseInvader extends \sammo\Event\Action $invaderName = $cityObj->name; $nationName = "ⓞ{$invaderName}족"; - $nationObj = new Nation($invaderNationID, $nationName, '#800080', 9999999, 9999999, "중원의 부패를 물리쳐라! 이민족 침범!", $tech, "che_병가", 2, [$cityObj->name]); + $nationObj = new Nation($rng, $invaderNationID, $nationName, '#800080', 9999999, 9999999, "중원의 부패를 물리쳐라! 이민족 침범!", $tech, "che_병가", 2, [$cityObj->name]); $nationObj->build($env); - $ruler = (new GeneralBuilder("{$invaderName}대왕", false, null, $lastNationID)) + $ruler = (new GeneralBuilder($rng, "{$invaderName}대왕", false, null, $lastNationID)) ->setEgo('che_패권') ->setSpecial('che_인덕', 'che_척사') ->setLifeSpan($year - 20, $year + 20) @@ -172,7 +182,7 @@ class RaiseInvader extends \sammo\Event\Action $nationObj->addGeneral($ruler); foreach (Util::range(1, $npcEachCount) as $invaderGenIdx) { - $gen = (new GeneralBuilder("{$invaderName}장수{$invaderGenIdx}", false, null, $invaderNationID)) + $gen = (new GeneralBuilder($rng, "{$invaderName}장수{$invaderGenIdx}", false, null, $invaderNationID)) ->setEgo('che_패권') ->setSpecial('che_인덕', 'che_척사') ->setLifeSpan($year - 20, $year + 20) @@ -182,11 +192,11 @@ class RaiseInvader extends \sammo\Event\Action ->setExpDed($exp, null) ->setGoldRice(99999, 99999); - $leadership = Util::randRangeInt(Util::toInt($specAvg * 1.2), Util::toInt($specAvg * 1.4)); - $mainStat = Util::randRangeInt(Util::toInt($specAvg * 1.2), Util::toInt($specAvg * 1.4)); + $leadership = $rng->nextRangeInt(Util::toInt($specAvg * 1.2), Util::toInt($specAvg * 1.4)); + $mainStat = $rng->nextRangeInt(Util::toInt($specAvg * 1.2), Util::toInt($specAvg * 1.4)); $subStat = $specAvg * 3 - $leadership - $mainStat; - if (Util::randBool()) { + if ($rng->nextBit()) { //무장 $dexTable = [$dex * 2, $dex, $dex]; shuffle($dexTable); diff --git a/hwe/sammo/Event/Action/RaiseNPCNation.php b/hwe/sammo/Event/Action/RaiseNPCNation.php index 74605c5b..b090cb50 100644 --- a/hwe/sammo/Event/Action/RaiseNPCNation.php +++ b/hwe/sammo/Event/Action/RaiseNPCNation.php @@ -9,6 +9,8 @@ use sammo\DB; use sammo\GameConst; use sammo\Json; use sammo\KVStorage; +use sammo\LiteHashDRBG; +use sammo\RandUtil; use sammo\Scenario\GeneralBuilder; use sammo\Scenario\Nation; use sammo\UniqueConst; @@ -28,7 +30,7 @@ class RaiseNPCNation extends \sammo\Event\Action const MIN_DIST_USERNATION = 3; const MIN_DIST_NPCNATION = 2; - private function calcAvgNationCity(array $cities) + private function calcAvgNationCity(RandUtil $rng, array $cities) { if (count($cities) == 0) { throw new InvalidArgumentException(); @@ -55,7 +57,7 @@ class RaiseNPCNation extends \sammo\Event\Action $cityCnt = count($targetCities); if ($cityCnt == 0) { - $target = Util::choiceRandom($cities); + $target = $rng->choice($cities); $randCity = []; foreach (static::CITY_KEYS as $key) { $randCity[$key] = $target["{$key}_max"]; @@ -136,7 +138,7 @@ class RaiseNPCNation extends \sammo\Event\Action return Util::toInt($techSum / $nationCnt); } - private function buildNation(int $nationID, int $tech, array $baseCity, array $avgCity, int $genCnt, $env) + private function buildNation(RandUtil $rng, int $nationID, int $tech, array $baseCity, array $avgCity, int $genCnt, $env) { $db = DB::db(); @@ -153,11 +155,11 @@ class RaiseNPCNation extends \sammo\Event\Action $cityName = $baseCity['name']; $nationName = "ⓤ{$cityName}"; - $color = Util::choiceRandom(GetNationColors()); - $nationObj = new Nation($nationID, $nationName, $color, 0, 2000, "우리도 할 수 있다! {$cityName}군", $tech, null, 2, [$cityName]); + $color = $rng->choice(GetNationColors()); + $nationObj = new Nation($rng, $nationID, $nationName, $color, 0, 2000, "우리도 할 수 있다! {$cityName}군", $tech, null, 2, [$cityName]); $nationObj->build($env); - $ruler = (new GeneralBuilder("{$cityName}태수", false, null, $nationID)) + $ruler = (new GeneralBuilder($rng, "{$cityName}태수", false, null, $nationID)) ->setOfficerLevel(12) ->setCityID($cityID) ->setNPCType(6) @@ -172,9 +174,9 @@ class RaiseNPCNation extends \sammo\Event\Action $birthYear = $env['year'] - 20; $deadYearMin = $env['year'] + 10; - foreach (pickGeneralFromPool(DB::db(), 0, $genCnt - 1) as $pickedNPC) { + foreach (pickGeneralFromPool(DB::db(), $rng, 0, $genCnt - 1) as $pickedNPC) { //대충 10년후부터 6년마다 절반? - $deadYear = $deadYearMin + Util::toInt(60 * (1 - log(Util::randRange(1, 1024), 2) / 10)); + $deadYear = $deadYearMin + Util::toInt(60 * (1 - log($rng->nextRange(1, 1024), 2) / 10)); $newNPC = $pickedNPC->getGeneralBuilder(); $newNPC->setNationID($nationID) ->setCityID($cityID) @@ -204,7 +206,11 @@ class RaiseNPCNation extends \sammo\Event\Action $occupiedCities = []; $npcCities = []; - $avgCity = $this->calcAvgNationCity($allCities); + $rng = new RandUtil(new LiteHashDRBG(Util::simpleSerialize( + UniqueConst::$hiddenSeed, 'RaiseNPCNation', $env['year'], $env['month'] + ))); + + $avgCity = $this->calcAvgNationCity($rng, $allCities); foreach ($allCities as $city) { if ($city['nation'] == 0) { @@ -257,7 +263,7 @@ class RaiseNPCNation extends \sammo\Event\Action //TODO: 거리 측정 $lastNationID += 1; - $this->buildNation($lastNationID, $avgTech, $emptyCity, $avgCity, $avgGenCnt, $env); + $this->buildNation($rng, $lastNationID, $avgTech, $emptyCity, $avgCity, $avgGenCnt, $env); $npcCities[$cityID] = $emptyCity; $npcCitiesID[] = $cityID; } diff --git a/hwe/sammo/Event/Action/RegNPC.php b/hwe/sammo/Event/Action/RegNPC.php index 10ef70c7..8d3bc4a1 100644 --- a/hwe/sammo/Event/Action/RegNPC.php +++ b/hwe/sammo/Event/Action/RegNPC.php @@ -1,33 +1,38 @@ npc=(new \sammo\Scenario\GeneralBuilder( - $name, + $rng, + $name, false, - $picturePath, - $nationID + $picturePath, + $nationID )) ->setCity($locatedCity) ->setStat($leadership, $strength, $intel) diff --git a/hwe/sammo/Event/Action/RegNeutralNPC.php b/hwe/sammo/Event/Action/RegNeutralNPC.php index 46e857dc..1c4d51ac 100644 --- a/hwe/sammo/Event/Action/RegNeutralNPC.php +++ b/hwe/sammo/Event/Action/RegNeutralNPC.php @@ -1,31 +1,39 @@ npc=(new \sammo\Scenario\GeneralBuilder( - $name, + $rng, + $name, false, - $picturePath, - $nationID + $picturePath, + $nationID )) ->setCity($locatedCity) ->setStat($leadership, $strength, $intel) diff --git a/hwe/sammo/General.php b/hwe/sammo/General.php index 22021dfe..cb9bab77 100644 --- a/hwe/sammo/General.php +++ b/hwe/sammo/General.php @@ -987,7 +987,7 @@ class General implements iAction return $amount; } - public function onArbitraryAction(General $general, string $actionType, ?string $phase = null, $aux = null): null|array + public function onArbitraryAction(General $general, RandUtil $rng, string $actionType, ?string $phase = null, $aux = null): null|array { foreach (array_merge([ $this->nationType, @@ -1002,7 +1002,7 @@ class General implements iAction continue; } /** @var iAction $iObj */ - $aux = $iObj->onArbitraryAction($general, $actionType, $phase, $aux); + $aux = $iObj->onArbitraryAction($general, $rng, $actionType, $phase, $aux); } return $aux; } diff --git a/hwe/sammo/GeneralAI.php b/hwe/sammo/GeneralAI.php index e666b61b..35415fe0 100644 --- a/hwe/sammo/GeneralAI.php +++ b/hwe/sammo/GeneralAI.php @@ -9,6 +9,8 @@ use sammo\Scenario\NPC; class GeneralAI { + protected RandUtil $rng; + /** @var General */ protected $general; protected array $city; @@ -94,6 +96,14 @@ class GeneralAI } $this->city = $city; + $this->rng = new RandUtil(new LiteHashDRBG(Util::simpleSerialize( + UniqueConst::$hiddenSeed, + 'GeneralAI', + $this->env['year'], + $this->env['month'], + $general->getID(), + ))); + $this->nation = $db->queryFirstRow( 'SELECT nation,name,color,capital,capset,gennum,gold,rice,bill,rate,rate_tmp,scout,war,strategic_cmd_limit,surlimit,tech,power,level,chief_set,type,aux FROM nation WHERE nation = %i', $general->getNationID() @@ -161,7 +171,7 @@ class GeneralAI if ($strength >= $intel) { $genType = self::t무장; if ($intel >= $strength * 0.8) { //무지장 - if (Util::randBool($intel / $strength / 2)) { + if ($this->rng->nextBool($intel / $strength / 2)) { $genType |= self::t지장; } } @@ -169,7 +179,7 @@ class GeneralAI } else { $genType = self::t지장; if ($strength >= $intel * 0.8) { //지무장 - if (Util::randBool($strength / $intel / 2)) { + if ($this->rng->nextBool($strength / $intel / 2)) { $genType |= self::t무장; } } @@ -310,19 +320,19 @@ class GeneralAI if (!key_exists($fromCityID, $this->warRoute) && !key_exists($toCityID, $this->warRoute)) { //공격 루트 상실, 전방 아무데나 - $troopCandidate[] = [$leaderID, Util::choiceRandom($this->frontCities)['city']]; + $troopCandidate[] = [$leaderID, $this->rng->choice($this->frontCities)['city']]; continue; } if (!key_exists($toCityID, $this->warRoute[$fromCityID])) { //공격 루트 상실, 전방 아무데나 - $troopCandidate[] = [$leaderID, Util::choiceRandom($this->frontCities)['city']]; + $troopCandidate[] = [$leaderID, $this->rng->choice($this->frontCities)['city']]; continue; } if (key_exists($fromCityID, $this->supplyCities) && key_exists($toCityID, $this->supplyCities)) { //점령 완료, 전방 아무데나 - $troopCandidate[] = [$leaderID, Util::choiceRandom($this->frontCities)['city']]; + $troopCandidate[] = [$leaderID, $this->rng->choice($this->frontCities)['city']]; continue; } @@ -354,7 +364,7 @@ class GeneralAI $targetCityID = $nextCityCandidate[0]; continue; } - $targetCityID = Util::choiceRandom($nextCityCandidate); + $targetCityID = $this->rng->choice($nextCityCandidate); } $troopCandidate[] = ['destGenaralID' => $leaderID, 'destCityID' => $targetCityID]; @@ -364,7 +374,7 @@ class GeneralAI return null; } - $cmd = buildNationCommandClass('che_발령', $this->general, $this->env, $lastTurn, Util::choiceRandom($troopCandidate)); + $cmd = buildNationCommandClass('che_발령', $this->general, $this->env, $lastTurn, $this->rng->choice($troopCandidate)); if (!$cmd->hasFullConditionMet()) { return null; } @@ -450,8 +460,8 @@ class GeneralAI } $cmd = buildNationCommandClass('che_발령', $this->general, $this->env, $lastTurn, [ - 'destGeneralID' => Util::choiceRandom($troopCandidate)->getID(), - 'destCityID' => Util::choiceRandom($cityCandidates)['city'] + 'destGeneralID' => $this->rng->choice($troopCandidate)->getID(), + 'destCityID' => $this->rng->choice($cityCandidates)['city'] ]); if (!$cmd->hasFullConditionMet()) { @@ -503,8 +513,8 @@ class GeneralAI } $cmd = buildNationCommandClass('che_발령', $this->general, $this->env, $lastTurn, [ - 'destGeneralID' => Util::choiceRandom($troopCandidate)->getID(), - 'destCityID' => Util::choiceRandom($cityCandidates)['city'] + 'destGeneralID' => $this->rng->choice($troopCandidate)->getID(), + 'destCityID' => $this->rng->choice($cityCandidates)['city'] ]); if (!$cmd->hasFullConditionMet()) { @@ -612,8 +622,8 @@ class GeneralAI } $cmd = buildNationCommandClass('che_발령', $this->general, $this->env, $lastTurn, [ - 'destGeneralID' => Util::choiceRandom($generalCadidates)->getID(), - 'destCityID' => Util::choiceRandom($cityCandidates)['city'] + 'destGeneralID' => $this->rng->choice($generalCadidates)->getID(), + 'destCityID' => $this->rng->choice($cityCandidates)['city'] ]); if (!$cmd->hasFullConditionMet()) { @@ -663,7 +673,7 @@ class GeneralAI } /** @var General */ - $pickedGeneral = Util::choiceRandom($generalCadidates); + $pickedGeneral = $this->rng->choice($generalCadidates); $minRecruitPop = $this->fullLeadership * 100 + GameConst::$minAvailableRecruitPop; if (!$this->generalPolicy->can한계징병) { $minRecruitPop = max($minRecruitPop, $this->fullLeadership * 100 + $this->nationPolicy->minNPCRecruitCityPopulation); @@ -717,7 +727,7 @@ class GeneralAI $cmd = buildNationCommandClass('che_발령', $this->general, $this->env, $lastTurn, [ 'destGeneralID' => $pickedGeneral->getID(), - 'destCityID' => Util::choiceRandomUsingWeight($recruitableCityList) + 'destCityID' => $this->rng->choiceUsingWeight($recruitableCityList) ]); if (!$cmd->hasFullConditionMet()) { @@ -762,9 +772,9 @@ class GeneralAI } if (in_array($this->dipState, [self::d직전, self::d전쟁]) && count($this->frontCities) > 2) { - $selCity = Util::choiceRandom($this->frontCities); + $selCity = $this->rng->choice($this->frontCities); } else { - $selCity = Util::choiceRandom($this->supplyCities); + $selCity = $this->rng->choice($this->supplyCities); } //고립된 장수가 많을 수록 발령 확률 증가 $args[] = [ @@ -776,7 +786,7 @@ class GeneralAI return null; } - $arg = Util::choiceRandom($args); + $arg = $this->rng->choice($args); $cmd = buildNationCommandClass('che_발령', $this->general, $this->env, $lastTurn, $arg); if (!$cmd->hasFullConditionMet()) { @@ -835,8 +845,8 @@ class GeneralAI } $cmd = buildNationCommandClass('che_발령', $this->general, $this->env, $lastTurn, [ - 'destGeneralID' => Util::choiceRandom($generalCandidates)->getID(), - 'destCityID' => Util::choiceRandomUsingWeight($cityCandidates) + 'destGeneralID' => $this->rng->choice($generalCandidates)->getID(), + 'destCityID' => $this->rng->choiceUsingWeight($cityCandidates) ]); if (!$cmd->hasFullConditionMet()) { @@ -898,9 +908,9 @@ class GeneralAI } /** @var General */ - $destGeneral = Util::choiceRandom($generalCandidates); + $destGeneral = $this->rng->choice($generalCandidates); $srcCity = $this->supplyCities[$destGeneral->getCityID()]; - $destCity = $this->supplyCities[Util::choiceRandomUsingWeight($cityCandidiates)]; + $destCity = $this->supplyCities[$this->rng->choiceUsingWeight($cityCandidiates)]; if ($srcCity['dev'] <= $destCity['dev']) { return null; @@ -962,7 +972,7 @@ class GeneralAI } /** @var General */ - $pickedGeneral = Util::choiceRandom($generalCadidates); + $pickedGeneral = $this->rng->choice($generalCadidates); $minRecruitPop = $this->fullLeadership * 100 + GameConst::$minAvailableRecruitPop; if (!$this->generalPolicy->can한계징병) { $minRecruitPop = max($minRecruitPop, $this->fullLeadership * 100 + $this->nationPolicy->minNPCRecruitCityPopulation); @@ -1020,7 +1030,7 @@ class GeneralAI $cmd = buildNationCommandClass('che_발령', $this->general, $this->env, $lastTurn, [ 'destGeneralID' => $pickedGeneral->getID(), - 'destCityID' => Util::choiceRandomUsingWeight($recruitableCityList) + 'destCityID' => $this->rng->choiceUsingWeight($recruitableCityList) ]); if (!$cmd->hasFullConditionMet()) { @@ -1042,7 +1052,7 @@ class GeneralAI if ($lostGeneral->getNPCType() < 2 || $lostGeneral->getNPCType() == 5) { continue; } - $selCity = Util::choiceRandom($this->supplyCities); + $selCity = $this->rng->choice($this->supplyCities); //고립된 장수가 많을 수록 발령 확률 증가 $args[] = [ 'destGeneralID' => $lostGeneral->getID(), @@ -1052,7 +1062,7 @@ class GeneralAI if (!$args) { return null; } - $cmd = buildNationCommandClass('che_발령', $this->general, $this->env, $lastTurn, Util::choiceRandom($args)); + $cmd = buildNationCommandClass('che_발령', $this->general, $this->env, $lastTurn, $this->rng->choice($args)); if (!$cmd->hasFullConditionMet()) { return null; } @@ -1111,8 +1121,8 @@ class GeneralAI } $cmd = buildNationCommandClass('che_발령', $this->general, $this->env, $lastTurn, [ - 'destGeneralID' => Util::choiceRandom($generalCandidates)->getID(), - 'destCityID' => Util::choiceRandomUsingWeight($cityCandidates) + 'destGeneralID' => $this->rng->choice($generalCandidates)->getID(), + 'destCityID' => $this->rng->choiceUsingWeight($cityCandidates) ]); if (!$cmd->hasFullConditionMet()) { @@ -1170,9 +1180,9 @@ class GeneralAI } /** @var General */ - $destGeneral = Util::choiceRandom($generalCandidates); + $destGeneral = $this->rng->choice($generalCandidates); $srcCity = $this->supplyCities[$destGeneral->getCityID()]; - $destCity = $this->supplyCities[Util::choiceRandomUsingWeight($cityCandidiates)]; + $destCity = $this->supplyCities[$this->rng->choiceUsingWeight($cityCandidiates)]; if ($srcCity['dev'] <= $destCity['dev']) { return null; @@ -1269,7 +1279,7 @@ class GeneralAI $this->general, $this->env, $lastTurn, - Util::choiceRandomUsingWeightPair($candidateArgs) + $this->rng->choiceUsingWeightPair($candidateArgs) ); if (!$cmd->hasFullConditionMet()) { return null; @@ -1376,7 +1386,7 @@ class GeneralAI $this->general, $this->env, $lastTurn, - Util::choiceRandomUsingWeightPair($candidateArgs) + $this->rng->choiceUsingWeightPair($candidateArgs) ); if (!$cmd->hasFullConditionMet()) { return null; @@ -1469,7 +1479,7 @@ class GeneralAI $this->general, $this->env, $lastTurn, - Util::choiceRandomUsingWeightPair($candidateArgs) + $this->rng->choiceUsingWeightPair($candidateArgs) ); if (!$cmd->hasFullConditionMet()) { return null; @@ -1590,7 +1600,7 @@ class GeneralAI $this->general, $this->env, $lastTurn, - Util::choiceRandomUsingWeightPair($candidateArgs) + $this->rng->choiceUsingWeightPair($candidateArgs) ); if (!$cmd->hasFullConditionMet()) { return null; @@ -1720,7 +1730,7 @@ class GeneralAI $this->general, $this->env, $lastTurn, - Util::choiceRandomUsingWeightPair($candidateArgs) + $this->rng->choiceUsingWeightPair($candidateArgs) ); if (!$cmd->hasFullConditionMet()) { return null; @@ -1888,7 +1898,7 @@ class GeneralAI $trialProp /= 4; $trialProp = $trialProp ** 6; - if (!Util::randBool($trialProp)) { + if (!$this->rng->nextBool($trialProp)) { return null; } @@ -1924,14 +1934,14 @@ class GeneralAI if (!$lowTargetNations) { return null; } - if (Util::randBool(1 / count($lowTargetNations))) { + if ($this->rng->nextBool(1 / count($lowTargetNations))) { return null; } $nations = $warNations; } $cmd = buildNationCommandClass('che_선전포고', $this->general, $this->env, $lastTurn, [ - 'destNationID' => Util::choiceRandomUsingWeight($nations) + 'destNationID' => $this->rng->choiceUsingWeight($nations) ]); if (!$cmd->hasFullConditionMet()) { return null; @@ -2063,7 +2073,7 @@ class GeneralAI $candidates[] = $stopID; } } - $targetCityID = Util::choiceRandom($candidates); + $targetCityID = $this->rng->choice($candidates); } $cmd = buildNationCommandClass('che_천도', $this->general, $this->env, $lastTurn, [ @@ -2098,7 +2108,7 @@ class GeneralAI $cmdList = []; - if (($nation['rice'] < GameConst::$baserice) && Util::randBool(0.3)) { + if (($nation['rice'] < GameConst::$baserice) && $this->rng->nextBool(0.3)) { return null; } @@ -2179,7 +2189,7 @@ class GeneralAI return null; } - return Util::choiceRandomUsingWeightPair($cmdList); + return $this->rng->choiceUsingWeightPair($cmdList); } protected function do긴급내정(): ?GeneralCommand @@ -2198,14 +2208,14 @@ class GeneralAI $city = $this->city; - if ($city['trust'] < 70 && Util::randBool($leadership / GameConst::$chiefStatMin)) { + if ($city['trust'] < 70 && $this->rng->nextBool($leadership / GameConst::$chiefStatMin)) { $cmd = buildGeneralCommandClass('che_주민선정', $general, $env); if ($cmd->hasFullConditionMet()) { return $cmd; } } - if ($city['pop'] < $this->nationPolicy->minNPCRecruitCityPopulation && Util::randBool($leadership / GameConst::$chiefStatMin / 2)) { + if ($city['pop'] < $this->nationPolicy->minNPCRecruitCityPopulation && $this->rng->nextBool($leadership / GameConst::$chiefStatMin / 2)) { $cmd = buildGeneralCommandClass('che_정착장려', $general, $env); if ($cmd->hasFullConditionMet()) { return $cmd; @@ -2233,7 +2243,7 @@ class GeneralAI $city = $this->city; $nation = $this->nation; - if (($nation['rice'] < GameConst::$baserice) && Util::randBool(0.3)) { + if (($nation['rice'] < GameConst::$baserice) && $this->rng->nextBool(0.3)) { return null; } @@ -2241,7 +2251,7 @@ class GeneralAI $isSpringSummer = $this->env['month'] <= 6; $cmdList = []; - if (Util::randBool(0.3)) { + if ($this->rng->nextBool(0.3)) { return null; } @@ -2324,7 +2334,7 @@ class GeneralAI return null; } - $cmd = Util::choiceRandomUsingWeightPair($cmdList); + $cmd = $this->rng->choiceUsingWeightPair($cmdList); return $cmd; } @@ -2474,7 +2484,7 @@ class GeneralAI $maxPop = $city['pop_max'] - $this->nationPolicy->minNPCRecruitCityPopulation; if (($city['pop'] / $city['pop_max'] < $this->nationPolicy->safeRecruitCityPopulationRatio) && - (Util::randF($remainPop / $maxPop)) + ($this->rng->nextFloat1($remainPop / $maxPop)) ) { return null; } @@ -2516,7 +2526,7 @@ class GeneralAI $availableArmType[GameUnitConst::T_WIZARD] = $dex[GameUnitConst::T_WIZARD] * $this->fullIntel * 3; } - $armType = Util::choiceRandomUsingWeight($availableArmType); + $armType = $this->rng->choiceUsingWeight($availableArmType); } @@ -2539,7 +2549,7 @@ class GeneralAI } if ($types) { - $type = Util::choiceRandomUsingWeight($types); + $type = $this->rng->choiceUsingWeight($types); } else { throw new MustNotBeReachedException('에러:' . print_r([$general->getName(), $general->getAuxVar('armType'), $armType, $cities, $regions, $relYear, $tech], true)); } @@ -2636,7 +2646,7 @@ class GeneralAI if (!$cmdList) { return null; } - return Util::choiceRandomUsingWeightPair($cmdList); + return $this->rng->choiceUsingWeightPair($cmdList); } public function do소집해제(): ?GeneralCommand @@ -2650,7 +2660,7 @@ class GeneralAI if ($this->general->getVar('crew') == 0) { return null; } - if (Util::randBool(0.75)) { + if ($this->rng->nextBool(0.75)) { return null; } $cmd = buildGeneralCommandClass('che_소집해제', $this->general, $this->env); @@ -2675,7 +2685,7 @@ class GeneralAI $city = $this->city; $nation = $this->nation; - if (($nation['rice'] < GameConst::$baserice) && Util::randBool(0.7)) { + if (($nation['rice'] < GameConst::$baserice) && $this->rng->nextBool(0.7)) { return null; } @@ -2724,7 +2734,7 @@ class GeneralAI throw new \RuntimeException('출병 불가' . $cityID . var_export($attackableNations, true) . var_export($nearCities, true)); } - $cmd = buildGeneralCommandClass('che_출병', $general, $this->env, ['destCityID' => Util::choiceRandom($attackableCities)]); + $cmd = buildGeneralCommandClass('che_출병', $general, $this->env, ['destCityID' => $this->rng->choice($attackableCities)]); if (!$cmd->hasFullConditionMet()) { return null; } @@ -2796,7 +2806,7 @@ class GeneralAI if ($genRes < $reqRes * 1.5) { continue; } - if ($reqRes > 0 && !Util::randBool(($genRes / $reqRes) - 0.5)) { + if ($reqRes > 0 && !$this->rng->nextBool(($genRes / $reqRes) - 0.5)) { continue; } $amount = $genRes - $reqRes; @@ -2813,7 +2823,7 @@ class GeneralAI return null; } - $cmd = buildGeneralCommandClass('che_헌납', $general, $this->env, Util::choiceRandomUsingWeightPair($args)); + $cmd = buildGeneralCommandClass('che_헌납', $general, $this->env, $this->rng->choiceUsingWeightPair($args)); if (!$cmd->hasFullConditionMet()) { return null; } @@ -2915,7 +2925,7 @@ class GeneralAI $cmd = buildGeneralCommandClass('che_NPC능동', $this->general, $this->env, [ 'optionText' => '순간이동', - 'destCityID' => Util::choiceRandomUsingWeight($recruitableCityList), + 'destCityID' => $this->rng->choiceUsingWeight($recruitableCityList), ]); @@ -2963,7 +2973,7 @@ class GeneralAI $cmd = buildGeneralCommandClass('che_NPC능동', $this->general, $this->env, [ 'optionText' => '순간이동', - 'destCityID' => Util::choiceRandomUsingWeight($candidateCities), + 'destCityID' => $this->rng->choiceUsingWeight($candidateCities), ]); @@ -2981,7 +2991,7 @@ class GeneralAI } $city = $this->city; - if (Util::randBool(0.6)) { + if ($this->rng->nextBool(0.6)) { return null; } @@ -3002,7 +3012,7 @@ class GeneralAI return null; } - if (!Util::randBool($warpProp)) { + if (!$this->rng->nextBool($warpProp)) { return null; } @@ -3037,7 +3047,7 @@ class GeneralAI $cmd = buildGeneralCommandClass('che_NPC능동', $this->general, $this->env, [ 'optionText' => '순간이동', - 'destCityID' => Util::choiceRandomUsingWeight($candidateCities), + 'destCityID' => $this->rng->choiceUsingWeight($candidateCities), ]); if (!$cmd->hasFullConditionMet()) { return null; @@ -3068,7 +3078,7 @@ class GeneralAI $general = $this->general; if ($general->getNPCType() == 5) { - $newKillTurn = ($general->getVar('killturn') + Util::randRangeInt(2, 4)) % 5; + $newKillTurn = ($general->getVar('killturn') + $this->rng->nextRangeInt(2, 4)) % 5; $newKillTurn += 70; $general->setVar('killturn', $newKillTurn); } @@ -3121,7 +3131,7 @@ class GeneralAI if (!$candidateCities) { return null; } - $movingTargetCityID = Util::choiceRandomUsingWeightPair($candidateCities); + $movingTargetCityID = $this->rng->choiceUsingWeightPair($candidateCities); $general->setAuxVar('movingTargetCityID', $movingTargetCityID); } @@ -3149,7 +3159,7 @@ class GeneralAI } $cmd = buildGeneralCommandClass('che_이동', $general, $this->env, [ - 'destCityID' => Util::choiceRandomUsingWeightPair($candidateCities) + 'destCityID' => $this->rng->choiceUsingWeightPair($candidateCities) ]); if (!$cmd->hasFullConditionMet()) { return null; @@ -3173,7 +3183,7 @@ class GeneralAI } $currentCityLevel = CityConst::byID($general->getCityID())->level; - if (($currentCityLevel < 5 || 6 < $currentCityLevel) && Util::randBool(0.5)) { + if (($currentCityLevel < 5 || 6 < $currentCityLevel) && $this->rng->nextBool(0.5)) { return null; } @@ -3199,7 +3209,7 @@ class GeneralAI if ($cityLevel < 5 || 6 < $cityLevel) { continue; } - if ($dist == 3 && Util::randBool()) { + if ($dist == 3 && $this->rng->nextBool()) { continue; } $availableNearCity = true; @@ -3209,7 +3219,7 @@ class GeneralAI return null; } - $prop = Util::randF() * (GameConst::$defaultStatNPCMax + GameConst::$chiefStatMin) / 2; + $prop = $this->rng->nextFloat1() * (GameConst::$defaultStatNPCMax + GameConst::$chiefStatMin) / 2; $ratio = ($this->fullLeadership + $this->fullStrength + $this->fullIntel) / 3; @@ -3219,7 +3229,7 @@ class GeneralAI //XXX: 건국기한 2년 $more = Util::valueFit(3 - $this->env['year'] + $this->env['init_year'], 1, 3); - if (!Util::randBool(0.0075 * $more)) { + if (!$this->rng->nextBool(0.0075 * $more)) { return null; } @@ -3245,8 +3255,8 @@ class GeneralAI protected function do건국(): ?GeneralCommand { - $nationType = Util::choiceRandom(GameConst::$availableNationType); - $nationColor = Util::choiceRandom(array_keys(GetNationColors())); + $nationType = $this->rng->choice(GameConst::$availableNationType); + $nationColor = $this->rng->choice(array_keys(GetNationColors())); $cmd = buildGeneralCommandClass('che_건국', $this->general, $this->env, [ 'nationName' => "㉿" . mb_substr($this->general->getName(), 1), 'nationType' => $nationType, @@ -3300,7 +3310,7 @@ class GeneralAI } } - if (Util::randBool(0.3)) { + if ($this->rng->nextBool(0.3)) { if ($env['startyear'] + 3 > $env['year']) { //초기 임관 기간에서는 국가가 적을수록 임관 시도가 적음 $nationCnt = $db->queryFirstField('SELECT count(nation) FROM nation'); @@ -3309,7 +3319,7 @@ class GeneralAI return null; } - if (Util::randBool(pow(1 / ($nationCnt + 1) / pow($notFullNationCnt, 3), 1 / 4))) { + if ($this->rng->nextBool(pow(1 / ($nationCnt + 1) / pow($notFullNationCnt, 3), 1 / 4))) { return null; } } @@ -3327,10 +3337,10 @@ class GeneralAI return $cmd; } - if (Util::randBool(0.2)) { + if ($this->rng->nextBool(0.2)) { $paths = array_keys(CityConst::byID($city['city'])->path); - $cmd = buildGeneralCommandClass('che_이동', $general, $env, ['destCityID' => Util::choiceRandom($paths)]); + $cmd = buildGeneralCommandClass('che_이동', $general, $env, ['destCityID' => $this->rng->choice($paths)]); if (!$cmd->hasFullConditionMet()) { return null; } @@ -3350,7 +3360,7 @@ class GeneralAI if ($general->getNationID() == 0) { $cmd = buildGeneralCommandClass('che_인재탐색', $general, $this->env); - if (!$cmd->hasFullConditionMet() || Util::randBool()) { + if (!$cmd->hasFullConditionMet() || $this->rng->nextBool()) { $cmd = buildGeneralCommandClass('che_견문', $general, $this->env); } return $cmd; @@ -3378,7 +3388,7 @@ class GeneralAI $general = $this->general; if ($general->getNationID() == 0) { $cmd = buildGeneralCommandClass('che_인재탐색', $general, $this->env); - if (!$cmd->hasFullConditionMet() || Util::randBool(0.8)) { + if (!$cmd->hasFullConditionMet() || $this->rng->nextBool(0.8)) { $cmd = buildGeneralCommandClass('che_견문', $general, $this->env); } return $cmd; @@ -3395,7 +3405,7 @@ class GeneralAI } - $cmd = buildGeneralCommandClass(Util::choiceRandom($candidate), $this->general, $this->env); + $cmd = buildGeneralCommandClass($this->rng->choice($candidate), $this->general, $this->env); if (!$cmd->hasFullConditionMet()) { return buildGeneralCommandClass('che_물자조달', $this->general, $this->env); } @@ -3646,7 +3656,7 @@ class GeneralAI //특별 메세지 있는 경우 출력 $term = $this->env['turnterm']; - if ($general->getVar('npcmsg') && Util::randBool(GameConst::$npcMessageFreqByDay * $term / (60 * 24))) { + if ($general->getVar('npcmsg') && $this->rng->nextBool(GameConst::$npcMessageFreqByDay * $term / (60 * 24))) { $src = new MessageTarget( $general->getID(), $general->getVar('name'), @@ -3830,16 +3840,16 @@ class GeneralAI /** @var General */ if ($this->npcWarGenerals) { /** @var General */ - $randGeneral = Util::choiceRandom($this->npcWarGenerals); + $randGeneral = $this->rng->choice($this->npcWarGenerals); } else if ($this->npcCivilGenerals) { /** @var General */ - $randGeneral = Util::choiceRandom($this->npcCivilGenerals); + $randGeneral = $this->rng->choice($this->npcCivilGenerals); } else if ($this->userWarGenerals) { /** @var General */ - $randGeneral = Util::choiceRandom($this->userWarGenerals); + $randGeneral = $this->rng->choice($this->userWarGenerals); } else if ($this->userCivilGenerals) { /** @var General */ - $randGeneral = Util::choiceRandom($this->userCivilGenerals); + $randGeneral = $this->rng->choice($this->userCivilGenerals); } else { break; } @@ -3987,10 +3997,10 @@ class GeneralAI if (!key_exists($chiefLevel, $this->chiefGenerals) && !key_exists($chiefLevel, $nextChiefs)) { $newChiefProb = 1; } else { - $newChiefProb = Util::randF(0.1); + $newChiefProb = $this->rng->nextFloat1(0.1); } - if ($newChiefProb < 1 && !Util::randF($newChiefProb)) { + if ($newChiefProb < 1 && !$this->rng->nextFloat1($newChiefProb)) { continue; } diff --git a/hwe/sammo/GeneralPool/RandomNameGeneral.php b/hwe/sammo/GeneralPool/RandomNameGeneral.php index fcd15979..ffdd7012 100644 --- a/hwe/sammo/GeneralPool/RandomNameGeneral.php +++ b/hwe/sammo/GeneralPool/RandomNameGeneral.php @@ -4,6 +4,7 @@ namespace sammo\GeneralPool; use MeekroDB; use sammo\AbsGeneralPool; use sammo\GameConst; +use sammo\RandUtil; use sammo\Util; @@ -26,67 +27,14 @@ class RandomNameGeneral extends AbsGeneralPool{ return $db->affectedRows()!=0; } - public function giveGeneralSpec(array $pickTypeList, array $avgGen, array $env){ - //do Nothing - $dexTotal = $avgGen['dex_t']; - - $pickType = Util::choiceRandomUsingWeight($pickTypeList); - - $totalStat = GameConst::$defaultStatNPCTotal; - $minStat = GameConst::$defaultStatNPCMin; - $mainStat = GameConst::$defaultStatNPCMax - Util::randRangeInt(0, GameConst::$defaultStatNPCMin); - $otherStat = $minStat + Util::randRangeInt(0, Util::toInt(GameConst::$defaultStatNPCMin/2)); - $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 / 8, $dexTotal * 5 / 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); - - $builder = $this->getGeneralBuilder(); - $builder->setStat($leadership, $strength, $intel); - $builder->setDex($dexVal[0], $dexVal[1], $dexVal[2], $dexVal[3], $avgGen['dex5']); - $builder->setCityID(Util::choiceRandom(array_keys(\sammo\CityConst::all()))); - - $builder->setExpDed($avgGen['exp'], $avgGen['ded']); - } - - static protected function pickGeneral1FromPool(\MeekroDB $db, int $owner, ?string $prefix=null):self{ + static protected function pickGeneral1FromPool(\MeekroDB $db, RandUtil $rng, int $owner, ?string $prefix=null):self{ $loopCnt = 0; while(true){ - $firstname = Util::choiceRandom(GameConst::$randGenFirstName); - $middlename = Util::choiceRandom(GameConst::$randGenMiddleName); - $lastname = Util::choiceRandom(GameConst::$randGenLastName); + $firstname = $rng->choice(GameConst::$randGenFirstName); + $middlename = $rng->choice(GameConst::$randGenMiddleName); + $lastname = $rng->choice(GameConst::$randGenLastName); $generalName = "{$firstname}{$middlename}{$lastname}"; if($prefix){ @@ -106,7 +54,7 @@ class RandomNameGeneral extends AbsGeneralPool{ $uniqueName = $generalName; - return new static($db, [ + return new static($db, $rng, [ 'uniqueName'=>$uniqueName, 'generalName'=>$generalName, 'imgsvr'=>0, @@ -114,17 +62,17 @@ class RandomNameGeneral extends AbsGeneralPool{ ], '9999-12-31 12:00:00'); } - static public function pickGeneralFromPool(MeekroDB $db, int $owner, int $pickCnt, ?string $prefix = null): array + static public function pickGeneralFromPool(MeekroDB $db, RandUtil $rng, int $owner, int $pickCnt, ?string $prefix = null): array { /** @var RandomNameGeneral[] */ $result = []; $dbInsert = []; $oNow = new \DateTimeImmutable(); - - + + for($i=0;$i<$pickCnt;$i++){ - $result[] = static::pickGeneral1FromPool($db, $owner, $prefix); + $result[] = static::pickGeneral1FromPool($db, $rng, $owner, $prefix); } if($owner){ diff --git a/hwe/sammo/GeneralTrigger/che_도시치료.php b/hwe/sammo/GeneralTrigger/che_도시치료.php index 025b5352..865cda44 100644 --- a/hwe/sammo/GeneralTrigger/che_도시치료.php +++ b/hwe/sammo/GeneralTrigger/che_도시치료.php @@ -10,7 +10,7 @@ use sammo\JosaUtil; class che_도시치료 extends BaseGeneralTrigger{ protected $priority = 10010; - public function action(?array $env=null, $arg=null):?array{ + public function action(\sammo\RandUtil $rng, ?array $env=null, $arg=null):?array{ /** @var \sammo\General $general */ $general = $this->object; @@ -43,7 +43,7 @@ class che_도시치료 extends BaseGeneralTrigger{ /** @var string|null */ $curedPatientName = null; foreach($patients as [$patientID, $patientName, $patientNationID]){ - if (!Util::randBool(0.5)) { + if (!$rng->nextBool(0.5)) { continue; } diff --git a/hwe/sammo/GeneralTrigger/che_병력군량소모.php b/hwe/sammo/GeneralTrigger/che_병력군량소모.php index 31c0c433..5dc948cd 100644 --- a/hwe/sammo/GeneralTrigger/che_병력군량소모.php +++ b/hwe/sammo/GeneralTrigger/che_병력군량소모.php @@ -10,7 +10,7 @@ use sammo\JosaUtil; class che_병력군량소모 extends BaseGeneralTrigger{ protected $priority = 50000; - public function action(?array $env=null, $arg=null):?array{ + public function action(\sammo\RandUtil $rng, ?array $env=null, $arg=null):?array{ /** @var \sammo\General $general */ $general = $this->object; @@ -26,13 +26,13 @@ class che_병력군량소모 extends BaseGeneralTrigger{ $db->update('city', [ 'pop'=>$db->sqleval('pop + %i', $general->getVar('crew')) ], 'city=%i', $general->getCityID()); - + $general->setVar('crew', 0); $general->setVar('rice', 0); $general->getLogger()->pushGeneralActionLog( '군량이 모자라 병사들이 소집해제되었습니다!', ActionLogger::PLAIN ); - + $general->activateSkill('pre.소집해제'); } $general->activateSkill('pre.병력군량소모'); diff --git a/hwe/sammo/GeneralTrigger/che_부상경감.php b/hwe/sammo/GeneralTrigger/che_부상경감.php index 74a019dd..2c1e6121 100644 --- a/hwe/sammo/GeneralTrigger/che_부상경감.php +++ b/hwe/sammo/GeneralTrigger/che_부상경감.php @@ -10,7 +10,7 @@ use sammo\JosaUtil; class che_부상경감 extends BaseGeneralTrigger{ protected $priority = 10000; - public function action(?array $env=null, $arg=null):?array{ + public function action(\sammo\RandUtil $rng, ?array $env=null, $arg=null):?array{ /** @var \sammo\General $general */ $general = $this->object; diff --git a/hwe/sammo/GeneralTrigger/che_아이템치료.php b/hwe/sammo/GeneralTrigger/che_아이템치료.php index f236af1a..daad2606 100644 --- a/hwe/sammo/GeneralTrigger/che_아이템치료.php +++ b/hwe/sammo/GeneralTrigger/che_아이템치료.php @@ -16,7 +16,7 @@ class che_아이템치료 extends BaseGeneralTrigger{ $this->injuryTarget = $injuryTarget; } - public function action(?array $env=null, $arg=null):?array{ + public function action(\sammo\RandUtil $rng, ?array $env=null, $arg=null):?array{ /** @var \sammo\General $general */ $general = $this->object; diff --git a/hwe/sammo/ObjectTrigger.php b/hwe/sammo/ObjectTrigger.php index ad3754f7..82648ee9 100644 --- a/hwe/sammo/ObjectTrigger.php +++ b/hwe/sammo/ObjectTrigger.php @@ -22,7 +22,7 @@ abstract class ObjectTrigger{ return $this; } - abstract public function action(?array $env=null, $arg=null):?array; + abstract public function action(RandUtil $rng, ?array $env=null, $arg=null):?array; public function getUniqueID():string{ $priority = $this->priority; $fqn = static::class; diff --git a/hwe/sammo/ResetHelper.php b/hwe/sammo/ResetHelper.php index 9358a2a3..a23ed087 100644 --- a/hwe/sammo/ResetHelper.php +++ b/hwe/sammo/ResetHelper.php @@ -147,7 +147,8 @@ class ResetHelper{ return [ 'result'=>true, 'serverID'=>$serverID, - 'seasonIdx'=>$seasonIdx + 'seasonIdx'=>$seasonIdx, + 'hiddenSeed'=>$hiddenSeed, ]; } @@ -187,8 +188,14 @@ class ResetHelper{ $serverID = $clearResult['serverID']; $seasonIdx = $clearResult['seasonIdx']; + $hiddenSeed = $clearResult['hiddenSeed']; - $scenarioObj = new Scenario($scenario, true); + $rng = new RandUtil(new LiteHashDRBG(Util::simpleSerialize( + $hiddenSeed, + 'InitScenario' + ))); + + $scenarioObj = new Scenario($rng, $scenario, true); if(class_exists('\\sammo\GameConst', false)){ trigger_error("이미 GameConst가 호출되어있습니다", E_USER_NOTICE); diff --git a/hwe/sammo/Scenario.php b/hwe/sammo/Scenario.php index 05615037..9123b6a6 100644 --- a/hwe/sammo/Scenario.php +++ b/hwe/sammo/Scenario.php @@ -6,6 +6,8 @@ use sammo\Scenario\GeneralBuilder; class Scenario{ const SCENARIO_PATH = __DIR__.'/../scenario'; + private readonly RandUtil $rng; + private $scenarioIdx; private $scenarioPath; @@ -70,6 +72,7 @@ class Scenario{ $this->tmpGeneralQueue[$name] = $rawGeneral; $obj = (new Scenario\GeneralBuilder( + $this->rng, $name, false, $picturePath, @@ -106,7 +109,7 @@ class Scenario{ 'month'=>0 //포인트 ]; - $neutralNation = new Scenario\Nation(0, '재야', '#000000', 0, 0); + $neutralNation = new Scenario\Nation($this->rng, 0, '재야', '#000000', 0, 0); $this->nations = []; $this->nations[0] = $neutralNation; $this->nationsInv = [$neutralNation->getName() => $neutralNation]; @@ -117,6 +120,7 @@ class Scenario{ $nation = new Scenario\Nation( + $this->rng, $nationID, $name, $color, @@ -162,7 +166,7 @@ class Scenario{ 'month'=>0 //포인트 ]; - $neutralNation = new Scenario\Nation(0, '재야', '#000000', 0, 0); + $neutralNation = new Scenario\Nation($this->rng, 0, '재야', '#000000', 0, 0); $this->nations = []; $this->nations[0] = $neutralNation; $this->nationsInv = [$neutralNation->getName() => $neutralNation]; @@ -173,6 +177,7 @@ class Scenario{ $nation = new Scenario\Nation( + $this->rng, $nationID, $name, $color, @@ -263,7 +268,8 @@ class Scenario{ return $this->gameConf; } - public function __construct(int $scenarioIdx, bool $lazyInit = true){ + public function __construct(RandUtil $rng, int $scenarioIdx, bool $lazyInit = true){ + $this->rng = $rng; $scenarioPath = self::SCENARIO_PATH."/scenario_{$scenarioIdx}.json"; $this->scenarioIdx = $scenarioIdx; @@ -577,6 +583,8 @@ class Scenario{ public static function getAllScenarios(){ $result = []; + $rng = new RandUtil(new LiteHashDRBG(random_bytes(16))); + foreach(glob(self::SCENARIO_PATH.'/scenario_*.json') as $scenarioPath){ $scenarioName = pathinfo(basename($scenarioPath), PATHINFO_FILENAME); $scenarioIdx = Util::array_last(explode('_', $scenarioName)); @@ -590,7 +598,7 @@ class Scenario{ continue; } - $result[$scenarioIdx] = new Scenario($scenarioIdx); + $result[$scenarioIdx] = new Scenario($rng, $scenarioIdx); } return $result; } diff --git a/hwe/sammo/Scenario/GeneralBuilder.php b/hwe/sammo/Scenario/GeneralBuilder.php index 769eb354..190bc666 100644 --- a/hwe/sammo/Scenario/GeneralBuilder.php +++ b/hwe/sammo/Scenario/GeneralBuilder.php @@ -8,6 +8,7 @@ use \sammo\GameUnitConst; use \sammo\CityConst; use sammo\Enums\RankColumn; use \sammo\GameConst; +use sammo\RandUtil; use \sammo\SpecialityHelper; use sammo\TimeUtil; class GeneralBuilder{ @@ -67,6 +68,7 @@ class GeneralBuilder{ protected $aux = []; public function __construct( + public readonly RandUtil $rng, string $name, bool $isDynamicImageSvr, $picturePath, @@ -109,17 +111,17 @@ class GeneralBuilder{ 'intel'=>$this->intel ]; if($option === '랜덤전특'){ - $this->specialWar = SpecialityHelper::pickSpecialWar($general); + $this->specialWar = SpecialityHelper::pickSpecialWar($this->rng, $general); } else if($option === '랜덤내특'){ - $this->specialDomestic = SpecialityHelper::pickSpecialDomestic($general); + $this->specialDomestic = SpecialityHelper::pickSpecialDomestic($this->rng, $general); } else if($option === '랜덤'){ - if(Util::randBool(2/3)){ - $this->specialWar = SpecialityHelper::pickSpecialWar($general); + if($this->rng->nextBool(2/3)){ + $this->specialWar = SpecialityHelper::pickSpecialWar($this->rng, $general); } else{ - $this->specialDomestic = SpecialityHelper::pickSpecialDomestic($general); + $this->specialDomestic = SpecialityHelper::pickSpecialDomestic($this->rng, $general); } } return $this; @@ -165,7 +167,7 @@ class GeneralBuilder{ public function setAffinity(int $affinity):self{ if($affinity < 1){ - $this->affinity = Util::randRangeInt(1, 150); + $this->affinity = $this->rng->nextRangeInt(1, 150); } else if($affinity >= 900){ $this->affinity = 999; @@ -302,11 +304,11 @@ class GeneralBuilder{ } public function fillRandomStat(array $pickTypeList, &$pickedType=null):self{ - $pickType = Util::choiceRandomUsingWeight($pickTypeList); + $pickType = $this->rng->choiceUsingWeight($pickTypeList); $totalStat = GameConst::$defaultStatNPCTotal; $minStat = GameConst::$defaultStatNPCMin; - $mainStat = GameConst::$defaultStatNPCMax - Util::randRangeInt(0, GameConst::$defaultStatNPCMin); - $otherStat = $minStat + Util::randRangeInt(0, Util::toInt(GameConst::$defaultStatNPCMin/2)); + $mainStat = GameConst::$defaultStatNPCMax - $this->rng->nextRangeInt(0, GameConst::$defaultStatNPCMin); + $otherStat = $minStat + $this->rng->nextRangeInt(0, Util::toInt(GameConst::$defaultStatNPCMin/2)); $subStat = $totalStat - $mainStat - $otherStat; if ($subStat < $minStat) { $subStat = $otherStat; @@ -341,7 +343,7 @@ class GeneralBuilder{ } if($this->affinity === null || $this->affinity === 0){ - $this->affinity = Util::randRangeInt(1, 150); + $this->affinity = $this->rng->nextRangeInt(1, 150); } if($this->birth === null){ @@ -371,7 +373,7 @@ class GeneralBuilder{ } if($this->ego === null){ - $this->ego = Util::choiceRandom(GameConst::$availablePersonality); + $this->ego = $this->rng->choice(GameConst::$availablePersonality); } if($this->specialDomestic === null){ @@ -401,12 +403,12 @@ class GeneralBuilder{ } if($this->affinity === null || $this->affinity === 0 || $isFictionMode){ - $this->affinity = Util::randRangeInt(1, 150); + $this->affinity = $this->rng->nextRangeInt(1, 150); } if($this->birth === null){ - $this->birth = $env['year']+Util::randRange(-5, 5); - $this->death = $this->birth+Util::randRangeInt(60, 80); + $this->birth = $env['year']+$this->rng->nextRange(-5, 5); + $this->death = $this->birth+$this->rng->nextRangeInt(60, 80); } @@ -443,7 +445,7 @@ class GeneralBuilder{ $pickType = '무'; break; } - $pickType = Util::choiceRandomUsingWeight([ + $pickType = $this->rng->choiceUsingWeight([ '무'=>$strength, '지'=>$intel ]); @@ -463,7 +465,7 @@ class GeneralBuilder{ if(!$this->dex1 && key_exists('dex_t', $avgGen)){ $dexTotal = $avgGen['dex_t']; if ($pickType == '무') { - $dexVal = Util::choiceRandom([ + $dexVal = $this->rng->choice([ [$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], @@ -477,7 +479,7 @@ class GeneralBuilder{ } if($this->ego === null || $isFictionMode){ - $this->ego = Util::choiceRandom(GameConst::$availablePersonality); + $this->ego = $this->rng->choice(GameConst::$availablePersonality); } if($this->experience === null){ @@ -628,10 +630,10 @@ class GeneralBuilder{ if($this->cityID === null){ if($nationID == 0 || !CityHelper::getAllNationCities($nationID)){ - $cityObj = Util::choiceRandom(CityHelper::getAllCities()); + $cityObj = $this->rng->choice(CityHelper::getAllCities()); } else{ - $cityObj = Util::choiceRandom(CityHelper::getAllNationCities($nationID)); + $cityObj = $this->rng->choice(CityHelper::getAllNationCities($nationID)); } '@phan-var array $cityObj'; $this->cityID = $cityObj['id']; @@ -644,7 +646,7 @@ class GeneralBuilder{ $officerLevel = $nationID?1:0; } - $turntime = \sammo\getRandTurn($env['turnterm'], new \DateTimeImmutable($env['turntime'])); + $turntime = \sammo\getRandTurn($this->rng, $env['turnterm'], new \DateTimeImmutable($env['turntime'])); if($this->killturn){ $killturn = $this->killturn; diff --git a/hwe/sammo/Scenario/Nation.php b/hwe/sammo/Scenario/Nation.php index b6f74c76..fbf2267a 100644 --- a/hwe/sammo/Scenario/Nation.php +++ b/hwe/sammo/Scenario/Nation.php @@ -5,6 +5,8 @@ use \sammo\GameConst; use \sammo\Util; use \sammo\KVStorage; use \sammo\Json; +use sammo\RandUtil; + use function \sammo\getNationChiefLevel; class Nation{ @@ -25,6 +27,7 @@ class Nation{ private $generals = []; public function __construct( + private readonly RandUtil $rng, int $id = null, string $name = '국가', string $color = '#000000', @@ -77,7 +80,7 @@ class Nation{ } if($this->type === null){ - $type = Util::choiceRandom(GameConst::$availableNationType); + $type = $this->rng->choice(GameConst::$availableNationType); } else if(strpos($this->type, '_') === FALSE){ $type = 'che_'.$this->type; diff --git a/hwe/sammo/ScoutMessage.php b/hwe/sammo/ScoutMessage.php index a99033e7..b3ffe536 100644 --- a/hwe/sammo/ScoutMessage.php +++ b/hwe/sammo/ScoutMessage.php @@ -27,7 +27,7 @@ class ScoutMessage extends Message{ } parent::__construct(...func_get_args()); - + if(Util::array_get($msgOption['used'])){ $this->validScout = false; } @@ -66,7 +66,7 @@ class ScoutMessage extends Message{ $general = \sammo\General::createGeneralObjFromDB($receiverID, null, 2); $logger = $general->getLogger(); - + list($result, $reason) = $this->checkScoutMessageValidation($receiverID); if($result !== self::ACCEPTED){ @@ -88,7 +88,7 @@ class ScoutMessage extends Message{ return self::DECLINED; } - $commandObj->run(); + $commandObj->run(NoRNG::rngInstance()); $commandObj->setNextAvailable(); //메시지 비 활성화 @@ -98,9 +98,9 @@ class ScoutMessage extends Message{ $josaRo = JosaUtil::pick($this->src->nationName, '로'); $newMsg = new Message( - self::MSGTYPE_PRIVATE, - $this->src, - $this->dest, + self::MSGTYPE_PRIVATE, + $this->src, + $this->dest, "{$this->src->nationName}{$josaRo} 등용 제의 수락", new \DateTime(), new \DateTime('9999-12-31'), @@ -120,9 +120,9 @@ class ScoutMessage extends Message{ $josaRo = JosaUtil::pick($this->src->nationName, '로'); $newMsg = new Message( - self::MSGTYPE_PRIVATE, - $this->src, - $this->dest, + self::MSGTYPE_PRIVATE, + $this->src, + $this->dest, "{$this->src->nationName}{$josaRo} 등용 제의 거부", new \DateTime(), new \DateTime('9999-12-31'), @@ -155,7 +155,7 @@ class ScoutMessage extends Message{ $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(); + $this->_declineMessage(); return self::DECLINED; } @@ -200,18 +200,18 @@ class ScoutMessage extends Message{ $destNationInfo = getNationStaticInfo($destGeneral['nation']); $src = new MessageTarget( - $srcGeneralID, + $srcGeneralID, $srcGeneral['name'], - $srcGeneral['nation'], - $srcNationInfo['name'], + $srcGeneral['nation'], + $srcNationInfo['name'], $srcNationInfo['color'] ); $dest = new MessageTarget( - $destGeneralID, + $destGeneralID, $destGeneral['name'], $destGeneral['nation'], - $destNationInfo['name'], + $destNationInfo['name'], $destNationInfo['color'] ); diff --git a/hwe/sammo/SpecialityHelper.php b/hwe/sammo/SpecialityHelper.php index eaa21cc0..94105626 100644 --- a/hwe/sammo/SpecialityHelper.php +++ b/hwe/sammo/SpecialityHelper.php @@ -122,7 +122,7 @@ class SpecialityHelper{ return $myCond; } - private static function calcCondDexterity(array $general) : int { + private static function calcCondDexterity(RandUtil $rng, array $general) : int { $dex = [ static::ARMY_FOOTMAN => $general['dex1']??0, static::ARMY_ARCHER => $general['dex2']??0, @@ -134,19 +134,19 @@ class SpecialityHelper{ $dexSum = array_sum($dex); $dexBase = Util::round(sqrt($dexSum) / 4); - if(Util::randBool(0.8)){ + if($rng->nextBool(0.8)){ return 0; } - if(mt_rand(0, 99) < $dexBase){ + if($rng->nextRangeInt(0, 99) < $dexBase){ return 0; } if(!$dexSum){ - return array_rand($dex); + return $rng->choice($dex); } - return Util::choiceRandom(array_keys($dex, max($dex))); + return $rng->choice(array_keys($dex, max($dex))); } /** @return BaseSpecial[] */ @@ -195,7 +195,7 @@ class SpecialityHelper{ return $result; } - public static function pickSpecialDomestic(array $general, array $prevSpecials=[]) : string{ + public static function pickSpecialDomestic(RandUtil $rng, array $general, array $prevSpecials=[]) : string{ $pAbs = []; $pRel = []; @@ -234,31 +234,31 @@ class SpecialityHelper{ if($pRel){ $pAbs[0] = max(0, 100 - array_sum($pAbs)); } - $id = Util::choiceRandomUsingWeight($pAbs); + $id = $rng->choiceUsingWeight($pAbs); if($id){ return $id; } } - $id = Util::choiceRandomUsingWeight($pRel); + $id = $rng->choiceUsingWeight($pRel); if($id){ return $id; } if($prevSpecials){ - return static::pickSpecialDomestic($general, []); + return static::pickSpecialDomestic($rng, $general, []); } throw new MustNotBeReachedException("{$general['name']}, {$myCond}"); } - public static function pickSpecialWar(array $general, array $prevSpecials=[]) : string{ + public static function pickSpecialWar(RandUtil $rng, array $general, array $prevSpecials=[]) : string{ $reqDex = []; $pAbs = []; $pRel = []; $myCond = static::calcCondGeneric($general); - $myCond |= static::calcCondDexterity($general); + $myCond |= static::calcCondDexterity($rng, $general); $myCond |= static::REQ_DEXTERITY; foreach(static::getSpecialWarList() as $specialID=>$specialObj){ @@ -294,26 +294,26 @@ class SpecialityHelper{ } if($reqDex){ - return Util::choiceRandomUsingWeight($reqDex); + return $rng->choiceUsingWeight($reqDex); } if($pAbs){ if($pRel){ $pAbs[0] = max(0, 100 - array_sum($pAbs)); } - $id = Util::choiceRandomUsingWeight($pAbs); + $id = $rng->choiceUsingWeight($pAbs); if($id){ return $id; } } - $id = Util::choiceRandomUsingWeight($pRel); + $id = $rng->choiceUsingWeight($pRel); if($id){ return $id; } if($prevSpecials){ - return static::pickSpecialWar($general, []); + return static::pickSpecialWar($rng, $general, []); } throw new MustNotBeReachedException(); diff --git a/hwe/sammo/TriggerCaller.php b/hwe/sammo/TriggerCaller.php index 08137577..0f3d36b3 100644 --- a/hwe/sammo/TriggerCaller.php +++ b/hwe/sammo/TriggerCaller.php @@ -47,7 +47,7 @@ abstract class TriggerCaller{ if(!$sorted){ ksort($this->triggerListByPriority); } - + } function append(ObjectTrigger $trigger):self{ @@ -118,11 +118,11 @@ abstract class TriggerCaller{ return $this; } - function fire(array $env, $arg = null):?array{ + function fire(RandUtil $rng, array $env, $arg = null):?array{ foreach($this->triggerListByPriority as $priority=>$subTriggerList){ /** @var ObjectTrigger[] $subTriggerList */ foreach($subTriggerList as $trigger){ - $env = $trigger->action($env, $arg); + $env = $trigger->action($rng, $env, $arg); } } return $env; diff --git a/hwe/sammo/TurnExecutionHelper.php b/hwe/sammo/TurnExecutionHelper.php index 0c9cb2ec..112783a3 100644 --- a/hwe/sammo/TurnExecutionHelper.php +++ b/hwe/sammo/TurnExecutionHelper.php @@ -31,7 +31,7 @@ class TurnExecutionHelper return $this->generalObj; } - public function preprocessCommand(array $env) + public function preprocessCommand(RandUtil $rng, array $env) { $general = $this->getGeneral(); $caller = $general->getPreTurnExecuteTriggerList($general); @@ -40,7 +40,7 @@ class TurnExecutionHelper new GeneralTrigger\che_병력군량소모($general) )); - $caller->fire($env); + $caller->fire($rng, $env); } public function processBlocked(): bool @@ -68,7 +68,7 @@ class TurnExecutionHelper return true; } - public function processNationCommand(Command\NationCommand $commandObj): LastTurn + public function processNationCommand(RandUtil $rng, Command\NationCommand $commandObj): LastTurn { $general = $this->getGeneral(); @@ -89,7 +89,7 @@ class TurnExecutionHelper break; } - $result = $commandObj->run(); + $result = $commandObj->run($rng); if ($result) { $commandObj->setNextAvailable(); break; @@ -107,7 +107,7 @@ class TurnExecutionHelper return $commandObj->getResultTurn(); } - public function processCommand(Command\GeneralCommand $commandObj, bool $autorunMode) + public function processCommand(RandUtil $rng, Command\GeneralCommand $commandObj, bool $autorunMode) { $general = $this->getGeneral(); @@ -133,7 +133,7 @@ class TurnExecutionHelper break; } - $result = $commandObj->run(); + $result = $commandObj->run($rng); if ($result) { $commandObj->setNextAvailable(); break; @@ -263,7 +263,14 @@ class TurnExecutionHelper $general->increaseInheritancePoint(InheritanceKey::lived_month, 1); - $turnObj->preprocessCommand($env); + $rng = new RandUtil(new LiteHashDRBG(Util::simpleSerialize( + UniqueConst::$hiddenSeed, + 'preprocess', + $year, + $month, + $general->getID(), + ))); + $turnObj->preprocessCommand($rng, $env); if ($general->getNPCType() >= 2) { $ai = new GeneralAI($turnObj->getGeneral()); @@ -286,7 +293,16 @@ class TurnExecutionHelper $cityName = CityConst::byID($general->getCityID())->name; LogText("NationTurn", "General, {$general->getName()}, {$general->getID()}, {$cityName}, {$general->getStaticNation()['name']}, {$nationCommandObj->getBrief()}, {$nationCommandObj->reason}, "); } + $rng = new RandUtil(new LiteHashDRBG(Util::simpleSerialize( + UniqueConst::$hiddenSeed, + 'nationCommand', + $year, + $month, + $general->getID(), + $nationCommandObj->getRawClassName() + ))); $resultNationTurn = $turnObj->processNationCommand( + $rng, $nationCommandObj ); $nationStor->setValue($lastNationTurnKey, $resultNationTurn->toRaw()); @@ -307,8 +323,15 @@ class TurnExecutionHelper $cityName = CityConst::byID($general->getCityID())->name; LogText("turn", "General, {$general->getName()}, {$general->getID()}, {$cityName}, {$general->getStaticNation()['name']}, {$generalCommandObj->getBrief()}, {$generalCommandObj->reason}, "); } - - $turnObj->processCommand($generalCommandObj, $autorunMode); + $rng = new RandUtil(new LiteHashDRBG(Util::simpleSerialize( + UniqueConst::$hiddenSeed, + 'generalCommand', + $year, + $month, + $general->getID(), + $generalCommandObj->getRawClassName() + ))); + $turnObj->processCommand($rng, $generalCommandObj, $autorunMode); } pullNationCommand($general->getVar('nation'), $general->getVar('officer_level')); pullGeneralCommand($general->getID()); @@ -397,6 +420,12 @@ class TurnExecutionHelper return $currentTurn !== null && $lastExecuted !== $currentTurn; } + $monthlyRng = new RandUtil(new LiteHashDRBG(Util::simpleSerialize( + UniqueConst::$hiddenSeed, + 'monthly', + $gameStor->year, + $gameStor->month + ))); // 1달마다 처리하는 것들, 벌점 감소 및 건국,전턴,합병 -1, 군량 소모 if (!preUpdateMonthly()) { @@ -416,25 +445,25 @@ class TurnExecutionHelper processGoldIncome(); updateYearly(); updateQuaterly(); - disaster(); - tradeRate(); + disaster($monthlyRng); + tradeRate($monthlyRng); addAge(); // 새해 알림 $logger->pushGlobalActionLog("{$gameStor->year}년이 되었습니다."); $logger->flush(); //TODO: globalAction류는 전역에서 관리하는것이 좋을 듯. } elseif ($gameStor->month == 4) { updateQuaterly(); - disaster(); + disaster($monthlyRng); } elseif ($gameStor->month == 7) { processSumInheritPointRank(); processFall(); processRiceIncome(); updateQuaterly(); - disaster(); - tradeRate(); + disaster($monthlyRng); + tradeRate($monthlyRng); } elseif ($gameStor->month == 10) { updateQuaterly(); - disaster(); + disaster($monthlyRng); } // 이벤트 핸들러 동작 @@ -456,7 +485,7 @@ class TurnExecutionHelper $gameStor->resetCache(); } - postUpdateMonthly(); + postUpdateMonthly($monthlyRng); // 다음달로 넘김 $prevTurn = $nextTurn; diff --git a/hwe/sammo/WarUnit.php b/hwe/sammo/WarUnit.php index 42fe682b..7ad3c665 100644 --- a/hwe/sammo/WarUnit.php +++ b/hwe/sammo/WarUnit.php @@ -4,6 +4,7 @@ namespace sammo; class WarUnit { + public readonly RandUtil $rng; protected $general; protected $rawNation; @@ -33,8 +34,9 @@ class WarUnit protected $logActivatedSkill = []; protected $isFinished = false; - private function __construct(General $general) + private function __construct(RandUtil $rng, General $general) { + $this->rng = $rng; $this->general = $general; } @@ -413,7 +415,7 @@ class WarUnit function calcDamage(): int { $warPower = $this->getWarPower(); - $warPower *= Util::randRange(0.9, 1.1); + $warPower *= $this->rng->nextRange(0.9, 1.1); return Util::round($warPower); } @@ -443,7 +445,7 @@ class WarUnit $range = $general->onCalcStat($general, 'criticalDamageRange', $range); } //전특, 병종에 따라 필살 데미지가 달라질지도 모르므로 static 함수는 아닌 것으로 - return Util::randRange(...$range); + return $this->rng->nextRange(...$range); } function applyDB(\MeekroDB $db): bool diff --git a/hwe/sammo/WarUnitCity.php b/hwe/sammo/WarUnitCity.php index 6744ae80..994d9b4f 100644 --- a/hwe/sammo/WarUnitCity.php +++ b/hwe/sammo/WarUnitCity.php @@ -8,7 +8,8 @@ class WarUnitCity extends WarUnit{ protected $cityRate; - function __construct($raw, $rawNation, int $year, int $month, $cityRate){ + function __construct(RandUtil $rng, $raw, $rawNation, int $year, int $month, $cityRate){ + $this->rng = $rng; $general = new DummyGeneral(false); $general->setVar('city', $raw['city']); $general->setVar('nation', $raw['nation']); @@ -23,7 +24,7 @@ class WarUnitCity extends WarUnit{ $this->logger = $general->getLogger(); $this->crewType = GameUnitConst::byID(GameUnitConst::CREWTYPE_CASTLE); - $this->hp = $this->getCityVar('def') * 10; + $this->hp = $this->getCityVar('def') * 10; //수비자 보정 if($this->getCityVar('level') == 1){ @@ -78,7 +79,7 @@ class WarUnitCity extends WarUnit{ $this->deadCurr += $damage; $this->hp -= $damage; $this->increaseVarWithLimit('wall', -$damage/20, 0); - + return $this->hp; } @@ -123,7 +124,7 @@ class WarUnitCity extends WarUnit{ $nationID = $oppose->getNationVar('nation'); $newConflict = false; - + $dead = max(1, $this->dead); if(!$conflict || $this->getHP() == 0){ // 선타, 막타 보너스 @@ -147,7 +148,7 @@ class WarUnitCity extends WarUnit{ return $newConflict; } - + function applyDB(\MeekroDB $db):bool{ $updateVals = $this->getUpdatedValues(); @@ -156,7 +157,7 @@ class WarUnitCity extends WarUnit{ if(!$updateVals){ return false; } - + $db->update('city', $updateVals, 'city=%i', $this->raw['city']); $this->flushUpdateValues(); return $db->affectedRows() > 0; diff --git a/hwe/sammo/WarUnitGeneral.php b/hwe/sammo/WarUnitGeneral.php index d2417728..43824ae0 100644 --- a/hwe/sammo/WarUnitGeneral.php +++ b/hwe/sammo/WarUnitGeneral.php @@ -10,8 +10,9 @@ class WarUnitGeneral extends WarUnit protected $killedPerson = 0; protected $deadPerson = 0; - function __construct(General $general, array $rawNation, bool $isAttacker) + function __construct(RandUtil $rng, General $general, array $rawNation, bool $isAttacker) { + $this->rng = $rng; $this->general = $general; $this->raw = $general->getRaw(); $this->rawNation = $rawNation; //read-only @@ -302,13 +303,13 @@ class WarUnitGeneral extends WarUnit if ($this->hasActivatedSkillOnLog('퇴각부상무효')) { return false; } - if (!Util::randBool(0.05)) { + if (!$this->rng->nextBool(0.05)) { return false; } $this->activateSkill('부상'); - $general->increaseVarWithLimit('injury', Util::randRangeInt(10, 80), null, 80); + $general->increaseVarWithLimit('injury', $this->rng->nextRangeInt(10, 80), null, 80); $this->getLogger()->pushGeneralActionLog("전투중 부상당했다!", ActionLogger::PLAIN); return true; diff --git a/hwe/sammo/WarUnitTrigger/che_격노시도.php b/hwe/sammo/WarUnitTrigger/che_격노시도.php index 546bc516..6f48958f 100644 --- a/hwe/sammo/WarUnitTrigger/che_격노시도.php +++ b/hwe/sammo/WarUnitTrigger/che_격노시도.php @@ -22,14 +22,14 @@ class che_격노시도 extends BaseWarUnitTrigger{ if($oppose->hasActivatedSkill('필살')){ $self->activateSkill('격노'); $oppose->deactivateSkill('회피'); - if($self->isAttacker() && Util::randBool(1/2)){ + if($self->isAttacker() && $self->rng->nextBool(1/2)){ $self->activateSkill('진노'); } } - else if(Util::randBool(1/4)){ + else if($self->rng->nextBool(1/4)){ $self->activateSkill('격노'); $oppose->deactivateSkill('회피'); - if($self->isAttacker() && Util::randBool(1/2)){ + if($self->isAttacker() && $self->rng->nextBool(1/2)){ $self->activateSkill('진노'); } } diff --git a/hwe/sammo/WarUnitTrigger/che_계략시도.php b/hwe/sammo/WarUnitTrigger/che_계략시도.php index a348804d..a6bfb93f 100644 --- a/hwe/sammo/WarUnitTrigger/che_계략시도.php +++ b/hwe/sammo/WarUnitTrigger/che_계략시도.php @@ -48,7 +48,7 @@ class che_계략시도 extends BaseWarUnitTrigger{ $magicTrialProb *= 3; } - if(!Util::randBool($magicTrialProb)){ + if(!$self->rng->nextBool($magicTrialProb)){ return true; } @@ -57,11 +57,11 @@ class che_계략시도 extends BaseWarUnitTrigger{ $magicSuccessProb = $oppose->getGeneral()->onCalcOpposeStat($general, 'warMagicSuccessProb', $magicSuccessProb); if($oppose instanceof WarUnitCity){ - $magic = Util::choiceRandom(array_keys(static::$tableToCity)); + $magic = $self->rng->choice(array_keys(static::$tableToCity)); [$successDamage, $failDamage] = static::$tableToCity[$magic]; } else{ - $magic = Util::choiceRandom(array_keys(static::$tableToGeneral)); + $magic = $self->rng->choice(array_keys(static::$tableToGeneral)); [$successDamage, $failDamage] = static::$tableToGeneral[$magic]; } @@ -70,7 +70,7 @@ class che_계략시도 extends BaseWarUnitTrigger{ $self->activateSkill('계략시도', $magic); - if(Util::randBool($magicSuccessProb)){ + if($self->rng->nextBool($magicSuccessProb)){ $self->activateSkill('계략'); $selfEnv['magic'] = [$magic, $successDamage]; } diff --git a/hwe/sammo/WarUnitTrigger/che_반계시도.php b/hwe/sammo/WarUnitTrigger/che_반계시도.php index 8ed41609..f70daedd 100644 --- a/hwe/sammo/WarUnitTrigger/che_반계시도.php +++ b/hwe/sammo/WarUnitTrigger/che_반계시도.php @@ -26,7 +26,7 @@ class che_반계시도 extends BaseWarUnitTrigger{ return true; } - if(!Util::randBool($this->prob)){ + if(!$self->rng->nextBool($this->prob)){ return true; } diff --git a/hwe/sammo/WarUnitTrigger/che_약탈시도.php b/hwe/sammo/WarUnitTrigger/che_약탈시도.php index e22c6477..dc5a7705 100644 --- a/hwe/sammo/WarUnitTrigger/che_약탈시도.php +++ b/hwe/sammo/WarUnitTrigger/che_약탈시도.php @@ -35,7 +35,7 @@ class che_약탈시도 extends BaseWarUnitTrigger{ if($self->hasActivatedSkill('약탈불가')){ return true; } - if(!Util::randBool($this->ratio)){ + if(!$self->rng->nextBool($this->ratio)){ return true; } diff --git a/hwe/sammo/WarUnitTrigger/che_저격발동.php b/hwe/sammo/WarUnitTrigger/che_저격발동.php index f6b801e9..609abbb4 100644 --- a/hwe/sammo/WarUnitTrigger/che_저격발동.php +++ b/hwe/sammo/WarUnitTrigger/che_저격발동.php @@ -43,7 +43,7 @@ class che_저격발동 extends BaseWarUnitTrigger $general->increaseVarWithLimit('atmos', $selfEnv['addAtmos'], 0, GameConst::$maxAtmosByWar); if (!$oppose->hasActivatedSkill('부상무효') && $oppose instanceof WarUnitGeneral) { - $oppose->getGeneral()->increaseVarWithLimit('injury', Util::randRangeInt($selfEnv['woundMin'], $selfEnv['woundMax']), null, 80); + $oppose->getGeneral()->increaseVarWithLimit('injury', $self->rng->nextRangeInt($selfEnv['woundMin'], $selfEnv['woundMax']), null, 80); } $this->processConsumableItem(); diff --git a/hwe/sammo/WarUnitTrigger/che_저격시도.php b/hwe/sammo/WarUnitTrigger/che_저격시도.php index 332e49b7..d5cd9eb8 100644 --- a/hwe/sammo/WarUnitTrigger/che_저격시도.php +++ b/hwe/sammo/WarUnitTrigger/che_저격시도.php @@ -36,7 +36,7 @@ class che_저격시도 extends BaseWarUnitTrigger{ if($self->hasActivatedSkill('저격불가')){ return true; } - if(!Util::randBool($this->ratio)){ + if(!$self->rng->nextBool($this->ratio)){ return true; } diff --git a/hwe/sammo/WarUnitTrigger/che_저지시도.php b/hwe/sammo/WarUnitTrigger/che_저지시도.php index 2196b87e..ac1fbd2b 100644 --- a/hwe/sammo/WarUnitTrigger/che_저지시도.php +++ b/hwe/sammo/WarUnitTrigger/che_저지시도.php @@ -22,12 +22,12 @@ class che_저지시도 extends BaseWarUnitTrigger{ if($self->hasActivatedSkill('저지불가')){ return true; } - + $ratio = $self->getComputedAtmos() + $self->getComputedTrain(); - if(Util::randBool($ratio / 400)){ + if($self->rng->nextBool($ratio / 400)){ $self->activateSkill('특수', '저지'); } - + return true; } } \ No newline at end of file diff --git a/hwe/sammo/WarUnitTrigger/che_전투치료시도.php b/hwe/sammo/WarUnitTrigger/che_전투치료시도.php index 199b533e..fb255b0a 100644 --- a/hwe/sammo/WarUnitTrigger/che_전투치료시도.php +++ b/hwe/sammo/WarUnitTrigger/che_전투치료시도.php @@ -19,13 +19,13 @@ class che_전투치료시도 extends BaseWarUnitTrigger{ if($self->hasActivatedSkill('치료불가')){ return true; } - if(!Util::randBool(0.4)){ + if(!$self->rng->nextBool(0.4)){ return true; } $self->activateSkill('치료'); - + return true; } } \ No newline at end of file diff --git a/hwe/sammo/WarUnitTrigger/che_필살시도.php b/hwe/sammo/WarUnitTrigger/che_필살시도.php index 01b1801e..ab84a410 100644 --- a/hwe/sammo/WarUnitTrigger/che_필살시도.php +++ b/hwe/sammo/WarUnitTrigger/che_필살시도.php @@ -22,13 +22,13 @@ class che_필살시도 extends BaseWarUnitTrigger{ return true; } - if(!Util::randBool($self->getComputedCriticalRatio())){ + if(!$self->rng->nextBool($self->getComputedCriticalRatio())){ return true; } $self->activateSkill('필살시도', '필살'); - + return true; } } \ No newline at end of file diff --git a/hwe/sammo/WarUnitTrigger/che_회피시도.php b/hwe/sammo/WarUnitTrigger/che_회피시도.php index 8ce506ac..70476884 100644 --- a/hwe/sammo/WarUnitTrigger/che_회피시도.php +++ b/hwe/sammo/WarUnitTrigger/che_회피시도.php @@ -22,13 +22,13 @@ class che_회피시도 extends BaseWarUnitTrigger{ return true; } - if(!Util::randBool($self->getComputedAvoidRatio())){ + if(!$self->rng->nextBool($self->getComputedAvoidRatio())){ return true; } $self->activateSkill('회피시도', '회피'); - + return true; } } \ No newline at end of file diff --git a/hwe/sammo/iAction.php b/hwe/sammo/iAction.php index 54b5588e..4e37c835 100644 --- a/hwe/sammo/iAction.php +++ b/hwe/sammo/iAction.php @@ -19,5 +19,5 @@ interface iAction{ public function getBattlePhaseSkillTriggerList(WarUnit $unit):?WarUnitTriggerCaller; //NOTE: getBattleEndSkillTriggerList도 필요한가? - public function onArbitraryAction(General $general, string $actionType, ?string $phase=null, ?array $aux=null): null|array; + public function onArbitraryAction(General $general, RandUtil $rng, string $actionType, ?string $phase=null, ?array $aux=null): null|array; } \ No newline at end of file diff --git a/src/sammo/NoRNG.php b/src/sammo/NoRNG.php new file mode 100644 index 00000000..122fef26 --- /dev/null +++ b/src/sammo/NoRNG.php @@ -0,0 +1,50 @@ + $items 각 수치와 비중. [값, weight] 으로 보관 * @return array|object 선택된 랜덤 값의 첫번째 값 + * @deprecated */ public static function choiceRandomUsingWeightPair(array $items) { @@ -629,6 +635,7 @@ class Util extends \utilphp\util * @param array $items 선택하고자 하는 배열 * * @return int|float|string|array|object 선택된 value값. + * @deprecated */ public static function choiceRandom(array $items) {