arg = null; return true; } protected function init(){ $general = $this->generalObj; $this->setNation(['gennum', 'scout']); $env = $this->env; [$reqGold, $reqRice] = $this->getCost(); $this->fullConditionConstraints=[ ConstraintHelper::NotBeNeutral(), ConstraintHelper::NotWanderingNation(), ConstraintHelper::ReqGeneralGold($reqGold), ConstraintHelper::ReqGeneralRice($reqRice), ]; $relYear = $env['year'] - $env['startyear']; if($this->nation['nation'] != 0 && $relYear < 3 && $this->nation['gennum'] >= GameConst::$initialNationGenLimit){ $nationName = $this->nation['name']; $josaUn = JosaUtil::pick($nationName, '은'); $this->fullConditionConstraints[] = ConstraintHelper::AlwaysFail("현재 {$nationName}{$josaUn} 탐색이 제한되고 있습니다."); } } public function getCommandDetailTitle():string{ $db = DB::db(); $env = $this->env; $maxGenCnt = $env['maxgeneral']; $totalGenCnt = $db->queryFirstField('SELECT count(no) FROM general WHERE npc <= 2'); $totalNpcCnt = $db->queryFirstField('SELECT count(`no`) FROM general WHERE 3 <= npc AND npc <= 4'); $name = $this->getName(); [$reqGold, $reqRice] = $this->getCost(); $foundProp = $this->calcFoundProp($maxGenCnt, $totalGenCnt, $totalNpcCnt); $foundPropText = number_format($foundProp*100, 1); $title = "{$name}(랜덤경험"; if($reqGold > 0){ $title .= ", 자금{$reqGold}"; } if($reqRice > 0){ $title .= ", 군량{$reqRice}"; } $title .= ", 확률 {$foundPropText}%)"; return $title; } public function getCost():array{ return [$this->env['develcost'], 0]; } public function getPreReqTurn():int{ return 0; } public function getPostReqTurn():int{ return 0; } public function calcFoundProp(int $maxGenCnt, int $totalGenCnt, int $totalNpcCnt):float{ $currCnt = Util::toInt($totalGenCnt + $totalNpcCnt / 2); $remainSlot = $maxGenCnt - $currCnt; if($remainSlot < 0){ $remainSlot = 0; } $foundPropMain = pow($remainSlot / $maxGenCnt, 6); $foundPropSmall = 1 / ($totalNpcCnt / 3 + 1); $foundPropBig = 1 / $maxGenCnt; if($totalNpcCnt < 50){ $foundProp = max($foundPropMain, $foundPropSmall); } else{ $foundProp = max($foundPropMain, $foundPropBig); } return $foundProp; } public function run():bool{ if(!$this->hasFullConditionMet()){ throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도'); } $db = DB::db(); $env = $this->env; $relYear = $env['year'] - $env['startyear']; $general = $this->generalObj; $date = $general->getTurnTime($general::TURNTIME_HM); $nationID = $general->getNationID(); $nationCnt = count(getAllNationStaticInfo()); $totalGenCnt = $db->queryFirstField('SELECT count(no) FROM general WHERE npc <= 2'); $totalNpcCnt = $db->queryFirstField('SELECT count(`no`) FROM general WHERE 3 <= npc AND npc <= 4'); $genCnt = $db->queryFirstField('SELECT count(no) FROM general WHERE nation=%i AND npc < 2', $nationID); $npcCnt = $db->queryFirstField('SELECT count(no) FROM general WHERE nation=%i AND 3 <= npc AND npc <= 4', $nationID); $currCnt = Util::toInt($totalGenCnt + $totalNpcCnt / 2); $avgCnt = $currCnt / $nationCnt; $foundNpc = Util::randBool($this->calcFoundProp($env['maxgeneral'], $totalGenCnt, $totalNpcCnt)); $logger = $general->getLogger(); if(!$foundNpc){ $logger->pushGeneralActionLog("인재를 찾을 수 없었습니다. <1>$date"); $incStat = Util::choiceRandomUsingWeight([ 'leadership_exp'=>$general->getLeadership(false, false, false, false), 'strength_exp'=>$general->getStrength(false, false, false, false), 'intel_exp'=>$general->getIntel(false, false, false, false) ]); [$reqGold, $reqRice] = $this->getCost(); $exp = 100; $ded = 70; $general->increaseVarWithLimit('gold', -$reqGold, 0); $general->increaseVarWithLimit('rice', -$reqRice, 0); $general->addExperience($exp); $general->addDedication($ded); $general->increaseVar($incStat, 1); $general->setResultTurn(new LastTurn(static::getName(), $this->arg)); $general->checkStatChange(); tryUniqueItemLottery($general); $general->applyDB($db); return true; } //인간적으로 너무 길어서 끊었다! $exp = 200; $ded = 300; $pickTypeList = ['무'=>6, '지'=>6, '무지'=>3]; $pickType = Util::choiceRandomUsingWeight($pickTypeList); $mainStat = GameConst::$defaultStatMax - Util::randRangeInt(0, 10); $otherStat = GameConst::$defaultStatMin + Util::randRangeInt(0, 5); $subStat = GameConst::$defaultStatTotal - $mainStat - $otherStat; if($subStat < GameConst::$defaultStatMin){ $subStat = $otherStat; $otherStat = GameConst::$defaultStatMin; $mainStat = GameConst::$defaultStatTotal - $subStat - $otherStat; if($mainStat){ throw new \LogicException('기본 스탯 설정값이 잘못되어 있음'); } } $avgGen = $db->queryFirstRow( 'SELECT max(leadership+strength+intel) as stat_sum, avg(dedication) as ded,avg(experience) as exp, avg(dex1+dex2+dex3+dex4) as dex_t, avg(age) as age, avg(dex5) as dex5 from general where nation=%i', $nationID ); $dexTotal = $avgGen['dex_t']; if($pickType == '무'){ $leadership = $subStat; $strength = $mainStat; $intel = $otherStat; $dexVal = Util::choiceRandom([ [$dexTotal*5/8, $dexTotal/8, $dexTotal/8, $dexTotal/8], [$dexTotal/8, $dexTotal*5/8, $dexTotal/8, $dexTotal/8], [$dexTotal/8, $dexTotal/8, $dexTotal*5/8, $dexTotal/8], ]); } else if($pickType == '지'){ $leadership = $subStat; $strength = $otherStat; $intel = $mainStat; $dexVal = [$dexTotal/8, $dexTotal/8, $dexTotal*5/8, $dexTotal/8]; } else{ $leadership = $otherStat; $strength = $subStat; $intel = $mainStat; $dexVal = [$dexTotal/4, $dexTotal/4, $dexTotal/4, $dexTotal/4]; } // 국내 최고능치 기준으로 랜덤성 스케일링 $maxLPI = $avgGen['stat_sum']; if($maxLPI > 210) { $leadership *= $maxLPI / GameConst::$defaultStatTotal * Util::randRange(0.6, 0.9); $strength *= $maxLPI / GameConst::$defaultStatTotal * Util::randRange(0.6, 0.9); $intel *= $maxLPI / GameConst::$defaultStatTotal * Util::randRange(0.6, 0.9); } elseif($maxLPI > 180) { $leadership *= $maxLPI / GameConst::$defaultStatTotal * Util::randRange(0.75, 0.95); $strength *= $maxLPI / GameConst::$defaultStatTotal * Util::randRange(0.75, 0.95); $intel *= $avgGen['stat_sum'] / GameConst::$defaultStatTotal * Util::randRange(0.75, 0.95); } else { $leadership *= $maxLPI / GameConst::$defaultStatTotal * Util::randRange(0.9, 1); $strength *= $maxLPI / GameConst::$defaultStatTotal * Util::randRange(0.9, 1); $intel *= $maxLPI / GameConst::$defaultStatTotal * Util::randRange(0.9, 1); } $leadership = Util::round($leadership); $strength = Util::round($strength); $intel = Util::round($intel); $joinProp = 0.55 * $avgCnt / (Util::valueFit($genCnt + $npcCnt, 1) / 2); $noScout = false; if($this->nation['scout'] != 0){ $noScout = true; } else if($relYear < 3 && $this->nation['gennum'] >= GameConst::$initialNationGenLimit){ $noScout = true; } if($noScout || !Util::randBool($joinProp)) { $scoutType = "발견"; $scoutLevel = 0; $scoutNation = 0; } else { $scoutType = "영입"; $scoutLevel = 1; $scoutNation = $nationID; $db->update('nation', [ 'gennum'=>$db->sqleval('gennum + 1') ], 'nation=%i', $nationID); } $age = $env['year'] - 20; $newNPC = new \sammo\Scenario\NPC( Util::randRangeInt(1, 150), \sammo\getRandGenName(), null, $scoutNation, $general->getCityID(), $leadership, $strength, $intel, $scoutLevel, $age, $env['year'] + Util::randRangeInt(10, 50), null, null ); $newNPC->npc = 3; $newNPC->setMoney(100, 100); $newNPC->setExpDed($avgGen['exp'], $avgGen['ded']); $newNPC->setSpecYear( Util::round((GameConst::$retirementYear - $age)/12) + $age, Util::round((GameConst::$retirementYear - $age)/3) + $age ); $newNPC->setDex( $dexVal[0], $dexVal[1], $dexVal[2], $dexVal[3], $avgGen['dex5'] ); $newNPC->build($this->env); $npcName = $newNPC->realName; $josaRa = JosaUtil::pick($npcName, '라'); $generalName = $general->getName(); $josaYi = JosaUtil::pick($generalName, '이'); $logger->pushGeneralActionLog("$npcName{$josaRa}는 인재를 {$scoutType}하였습니다! <1>$date"); $logger->pushGlobalActionLog("{$generalName}{$josaYi} $npcName{$josaRa}는 인재를 {$scoutType}하였습니다!"); $logger->pushGeneralHistoryLog("$npcName{$josaRa}는 인재를 {$scoutType}"); $incStat = Util::choiceRandomUsingWeight([ 'leadership_exp'=>$general->getLeadership(false, false, false, false), 'strength_exp'=>$general->getStrength(false, false, false, false), 'intel_exp'=>$general->getIntel(false, false, false, false) ]); [$reqGold, $reqRice] = $this->getCost(); $exp = 200; $ded = 300; $general->increaseVarWithLimit('gold', -$reqGold, 0); $general->increaseVarWithLimit('rice', -$reqRice, 0); $general->addExperience($exp); $general->addDedication($ded); $general->increaseVar($incStat, 3); $general->setResultTurn(new LastTurn(static::getName(), $this->arg)); $general->checkStatChange(); tryUniqueItemLottery($general); $general->applyDB($db); return true; } }