290 lines
10 KiB
PHP
290 lines
10 KiB
PHP
<?php
|
|
|
|
namespace sammo\Command\General;
|
|
|
|
use \sammo\DB;
|
|
use \sammo\Util;
|
|
use \sammo\JosaUtil;
|
|
use \sammo\TimeUtil;
|
|
use \sammo\Json;
|
|
use \sammo\General;
|
|
use \sammo\ActionLogger;
|
|
use \sammo\GameConst;
|
|
use \sammo\GameUnitConst;
|
|
use \sammo\LastTurn;
|
|
use \sammo\Command;
|
|
|
|
use function sammo\genGenericUniqueRNGFromGeneral;
|
|
use function \sammo\tryUniqueItemLottery;
|
|
|
|
use \sammo\Constraint\Constraint;
|
|
use \sammo\Constraint\ConstraintHelper;
|
|
use sammo\CityConst;
|
|
use sammo\Enums\InheritanceKey;
|
|
use sammo\MustNotBeReachedException;
|
|
use sammo\StaticEventHandler;
|
|
|
|
class che_랜덤임관 extends Command\GeneralCommand
|
|
{
|
|
static protected $actionName = '무작위 국가로 임관';
|
|
|
|
protected function argTest(): bool
|
|
{
|
|
$this->arg = null;
|
|
return true;
|
|
|
|
//TODO: 구현
|
|
/*if($this->arg === null){
|
|
return true;
|
|
}
|
|
|
|
$destNationIDList = $this->arg['destNationIDList']??null;
|
|
//null은 에러, []는 정상
|
|
|
|
if($destNationIDList === null || !is_array($destNationIDList)){
|
|
return true;
|
|
}
|
|
if($destNationIDList && Util::isDict($destNationIDList)){
|
|
return false;
|
|
}
|
|
foreach($destNationIDList as $nationID){
|
|
if(!is_int($nationID)){
|
|
return false;
|
|
}
|
|
if($nationID < 1){
|
|
return false;
|
|
}
|
|
}
|
|
$this->arg = [
|
|
'destNationIDList' => $destNationIDList
|
|
];
|
|
|
|
return true;*/
|
|
}
|
|
|
|
protected function init()
|
|
{
|
|
|
|
$general = $this->generalObj;
|
|
$env = $this->env;
|
|
|
|
$this->setCity();
|
|
$this->setNation();
|
|
|
|
$relYear = $env['year'] - $env['startyear'];
|
|
|
|
$this->fullConditionConstraints = [
|
|
ConstraintHelper::BeNeutral(),
|
|
ConstraintHelper::AllowJoinAction(),
|
|
];
|
|
|
|
/*
|
|
if($this->arg['destNationIDList']??false){
|
|
$this->fullConditionConstraints[] = ConstraintHelper::ExistsAllowJoinNation($relYear, $this->arg['destNationIDList']);
|
|
}
|
|
*/
|
|
}
|
|
|
|
public function getCommandDetailTitle(): string
|
|
{
|
|
return '무작위 국가로 임관';
|
|
}
|
|
|
|
public function getBrief(): string
|
|
{
|
|
return '무작위 국가로 임관';
|
|
}
|
|
|
|
public function getCost(): array
|
|
{
|
|
return [0, 0];
|
|
}
|
|
|
|
public function getPreReqTurn(): int
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
public function getPostReqTurn(): int
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
public function run(\Sammo\RandUtil $rng): bool
|
|
{
|
|
if (!$this->hasFullConditionMet()) {
|
|
throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도');
|
|
}
|
|
|
|
$db = DB::db();
|
|
$env = $this->env;
|
|
|
|
$general = $this->generalObj;
|
|
$date = $general->getTurnTime($general::TURNTIME_HM);
|
|
$generalName = $general->getName();
|
|
$josaYi = JosaUtil::pick($generalName, '이');
|
|
|
|
$relYear = $env['year'] - $env['startyear'];
|
|
|
|
/*
|
|
$notIn = $this->arg['destNationIDList']);
|
|
*/
|
|
$notIn = null;
|
|
|
|
$destNation = null;
|
|
|
|
if ($general->getNPCType() >= 2 && !$env['fiction'] && 1000 <= $env['scenario'] && $env['scenario'] < 2000) {
|
|
if ($notIn) {
|
|
$nations = $db->query(
|
|
'SELECT nation.`name` as `name`,nation.nation as nation,scout,gennum,`affinity` FROM nation join general on general.nation = nation.nation and general.officer_level = 12 WHERE scout=0 and gennum<%i and nation.nation not in %li',
|
|
$relYear < 3 ? GameConst::$initialNationGenLimit : GameConst::$defaultMaxGeneral,
|
|
$notIn
|
|
);
|
|
} else {
|
|
$nations = $db->query(
|
|
'SELECT nation.`name` as `name`,nation.nation as nation,scout,gennum,`affinity` FROM nation join general on general.nation = nation.nation and general.officer_level = 12 WHERE scout=0 and gennum<%i',
|
|
$relYear < 3 ? GameConst::$initialNationGenLimit : GameConst::$defaultMaxGeneral
|
|
);
|
|
}
|
|
|
|
shuffle($nations);
|
|
|
|
$allGen = Util::arraySum($nations, 'gennum');
|
|
|
|
$maxScore = 1 << 30;
|
|
|
|
$affinity = $general->getVar('affinity');
|
|
|
|
foreach ($nations as $testNation) {
|
|
$affinity = abs($affinity - $testNation['affinity']);
|
|
$affinity = min($affinity, abs($affinity - 150));
|
|
|
|
$score = log($affinity + 1, 2); //0~
|
|
|
|
//쉐킷쉐킷
|
|
$score += $rng->nextFloat1();
|
|
|
|
$score += sqrt($testNation['gennum'] / $allGen);
|
|
|
|
if ($score < $maxScore) {
|
|
$maxScore = $score;
|
|
$destNation = $testNation;
|
|
}
|
|
}
|
|
} else {
|
|
$genLimit = GameConst::$defaultMaxGeneral;
|
|
if ($relYear < 3) {
|
|
$genLimit = GameConst::$initialNationGenLimit;
|
|
}
|
|
|
|
$generalsCnt = [];
|
|
if ($notIn) {
|
|
|
|
$rawGeneralsCnt = $db->query(
|
|
"SELECT g.`nation`, n.`gennum`, n.name, SUM((ra.value + 50000)/(rb.value + 50000)*(CASE WHEN g.`npc` < 2 THEN 1.15 ELSE 1 END)*(CASE WHEN g.`leadership` >= 40 THEN g.`leadership` ELSE 0 END)) AS warpower, SUM(SQRT(g.intel * g.strength) * 2 + g.leadership / 2)/5 AS develpower
|
|
FROM general AS g
|
|
LEFT JOIN `rank_data` AS ra ON g.`no` = ra.general_id AND ra.`type` = 'killcrew_person'
|
|
LEFT JOIN `rank_data` AS rb ON g.`no` = rb.general_id AND rb.`type` = 'deathcrew_person'
|
|
LEFT JOIN `nation` AS n ON g.`nation` = n.`nation`
|
|
WHERE g.`npc` IN (0, 1, 2, 3, 6) AND g.nation != 0 AND n.scout=0 AND n.gennum < %i AND n.nation NOT IN %li
|
|
GROUP BY g.`nation`",
|
|
$genLimit,
|
|
$notIn
|
|
);
|
|
} else {
|
|
$rawGeneralsCnt = $db->query(
|
|
"SELECT g.`nation`, n.`gennum`, n.name, SUM((ra.value + 50000)/(rb.value + 50000)*(CASE WHEN g.`npc` < 2 THEN 1.15 ELSE 1 END)*(CASE WHEN g.`leadership` >= 40 THEN g.`leadership` ELSE 0 END)) AS warpower, SUM(SQRT(g.intel * g.strength) * 2 + g.leadership / 2)/5 AS develpower
|
|
FROM general AS g
|
|
LEFT JOIN `rank_data` AS ra ON g.`no` = ra.general_id AND ra.`type` = 'killcrew_person'
|
|
LEFT JOIN `rank_data` AS rb ON g.`no` = rb.general_id AND rb.`type` = 'deathcrew_person'
|
|
LEFT JOIN `nation` AS n ON g.`nation` = n.`nation`
|
|
WHERE g.`npc` IN (0, 1, 2, 3, 6) AND g.nation != 0 AND n.scout=0 AND n.gennum < %i
|
|
GROUP BY g.`nation`",
|
|
$genLimit
|
|
);
|
|
}
|
|
|
|
|
|
foreach ($rawGeneralsCnt as $nation) {
|
|
$calcCnt = $nation['warpower'] + $nation['develpower'];
|
|
|
|
if ($general->getNPCType() < 2 && str_starts_with($nation['name'], 'ⓤ')) {
|
|
$calcCnt *= 100;
|
|
}
|
|
|
|
$generalsCnt[] = [$nation, (1 / $calcCnt)**3];
|
|
}
|
|
|
|
if ($generalsCnt) {
|
|
$destNation = $rng->choiceUsingWeightPair($generalsCnt);
|
|
}
|
|
}
|
|
|
|
$logger = $general->getLogger();
|
|
|
|
if (!$destNation) {
|
|
//임관 가능한 국가가 없다!
|
|
$logger->pushGeneralActionLog("임관 가능한 국가가 없습니다. <1>$date</>");
|
|
$this->alternative = new che_인재탐색($general, $this->env, null);
|
|
return false;
|
|
}
|
|
|
|
$gennum = $destNation['gennum'];
|
|
$destNationID = $destNation['nation'];
|
|
$destNationName = $destNation['name'];
|
|
|
|
|
|
|
|
$talkList = [
|
|
'어쩌다 보니',
|
|
'인연이 닿아',
|
|
'발길이 닿는 대로',
|
|
'소문을 듣고',
|
|
'점괘에 따라',
|
|
'천거를 받아',
|
|
'유명한',
|
|
'뜻을 펼칠 곳을 찾아',
|
|
'고향에 가까운',
|
|
'천하의 균형을 맞추기 위해',
|
|
'오랜 은거를 마치고',
|
|
];
|
|
$randomTalk = $rng->choice($talkList);
|
|
|
|
$logger->pushGeneralActionLog("<D>{$destNationName}</>에 랜덤 임관했습니다. <1>$date</>");
|
|
$logger->pushGeneralHistoryLog("<D><b>{$destNationName}</b></>에 랜덤 임관");
|
|
$logger->pushGlobalActionLog("<Y>{$generalName}</>{$josaYi} {$randomTalk} <D><b>{$destNationName}</b></>에 <S>임관</>했습니다.");
|
|
|
|
if ($gennum < GameConst::$initialNationGenLimit) {
|
|
$exp = 700;
|
|
} else {
|
|
$exp = 100;
|
|
}
|
|
|
|
$general->setVar('nation', $destNationID);
|
|
$general->setVar('officer_level', 1);
|
|
$general->setVar('officer_city', 0);
|
|
$general->setVar('belong', 1);
|
|
|
|
if ($this->destGeneralObj !== null) {
|
|
$general->setVar('city', $this->destGeneralObj->getCityID());
|
|
} else {
|
|
$targetCityID = $db->queryFirstField('SELECT city FROM general WHERE nation = %i AND officer_level=12', $destNationID);
|
|
$general->setVar('city', $targetCityID);
|
|
}
|
|
|
|
$db->update('nation', [
|
|
'gennum' => $db->sqleval('gennum + 1')
|
|
], 'nation=%i', $destNationID);
|
|
|
|
$general->increaseInheritancePoint(InheritanceKey::active_action, 1);
|
|
$general->addExperience($exp);
|
|
$this->setResultTurn(new LastTurn(static::getName(), $this->arg));
|
|
$general->checkStatChange();
|
|
StaticEventHandler::handleEvent($this->generalObj, $this->destGeneralObj, $this::class, $this->env, $this->arg ?? []);
|
|
tryUniqueItemLottery(genGenericUniqueRNGFromGeneral($general, static::$actionName), $general, '랜덤 임관');
|
|
$general->applyDB($db);
|
|
|
|
return true;
|
|
}
|
|
}
|