AI 구현중
This commit is contained in:
+24
-12
@@ -1,6 +1,9 @@
|
||||
<?php
|
||||
namespace sammo;
|
||||
|
||||
use sammo\Command\GeneralCommand;
|
||||
use sammo\Command\NationCommand;
|
||||
|
||||
function getGeneralTurnBrief(General $generalObj, array $turnList) {
|
||||
$result = [];
|
||||
|
||||
@@ -164,29 +167,40 @@ function pullNationCommand(int $nationID, int $level, int $turnCnt=1){
|
||||
], 'nation_id=%i AND level=%i ORDER BY turn_idx ASC', $nationID, $level);
|
||||
}
|
||||
|
||||
function _setGeneralCommand(int $generalID, array $turnList, string $command, ?array $arg, string $brief) {
|
||||
function _setGeneralCommand(GeneralCommand $command, array $turnList):void {
|
||||
if(!$turnList){
|
||||
return;
|
||||
}
|
||||
|
||||
$db = DB::db();
|
||||
|
||||
$generalID = $command->getGeneral()->getID();
|
||||
$commandName = $command->getRawClassName();
|
||||
$arg = $command->getArg();
|
||||
$brief = $command->getBrief();
|
||||
|
||||
$db->update('general_turn', [
|
||||
'action'=>$command,
|
||||
'action'=>$commandName,
|
||||
'arg'=>Json::encode($arg, JSON::EMPTY_ARRAY_IS_DICT),
|
||||
'brief'=>$brief
|
||||
], 'general_id = %i AND turn_idx IN %li', $generalID, $turnList);
|
||||
}
|
||||
|
||||
function _setNationCommand(int $nationID, int $level, array $turnList, string $command, ?array $arg, string $brief) {
|
||||
function _setNationCommand(NationCommand $command, array $turnList):void {
|
||||
if(!$turnList){
|
||||
return;
|
||||
}
|
||||
|
||||
$db = DB::db();
|
||||
|
||||
$nationID = $command->getNationID();
|
||||
$level = $command->getGeneralLevel();
|
||||
$commandName = $command->getRawClassName();
|
||||
$arg = $command->getArg();
|
||||
$brief = $command->getBrief();
|
||||
|
||||
$db->update('nation_turn', [
|
||||
'action'=>$command,
|
||||
'action'=>$commandName,
|
||||
'arg'=>Json::encode($arg, JSON::EMPTY_ARRAY_IS_DICT),
|
||||
'brief'=>$brief
|
||||
], 'nation_id = %i AND level = %i AND turn_idx IN %li', $nationID, $level, $turnList);
|
||||
@@ -313,18 +327,16 @@ function setGeneralCommand(int $generalID, array $rawTurnList, string $command,
|
||||
];
|
||||
}
|
||||
|
||||
/*if(!$commandObj->isReservable()){
|
||||
if(!$commandObj->isReservable()){
|
||||
return [
|
||||
'result'=>false,
|
||||
'reason'=>'예약 불가능한 커맨드 :'.$commandObj->testReservable(),
|
||||
'test'=>'isReservable',
|
||||
'target'=>'command'
|
||||
];
|
||||
}*/
|
||||
}
|
||||
|
||||
$brief = $commandObj->getBrief();
|
||||
|
||||
_setGeneralCommand($generalID, $turnList, $command, $arg, $brief);
|
||||
_setGeneralCommand($commandObj, $turnList);
|
||||
return [
|
||||
'result'=>true,
|
||||
'reason'=>'success'
|
||||
@@ -395,20 +407,20 @@ function setNationCommand(int $generalID, array $turnList, string $command, ?arr
|
||||
];
|
||||
}
|
||||
|
||||
/*if(!$commandObj->isReservable()){
|
||||
if(!$commandObj->isReservable()){
|
||||
return [
|
||||
'result'=>false,
|
||||
'reason'=>'예약 불가능한 커맨드 :'.$commandObj->testReservable(),
|
||||
'test'=>'isReservable',
|
||||
'target'=>'command'
|
||||
];
|
||||
}*/
|
||||
}
|
||||
//TODO: Reservable은 '정말로 입력 불가'이고, '입력은 가능하지만 실행은 안될 것 같은' 군을 하나더 추가해야함
|
||||
// Runnable은 Arg를 모두 받아서 처리해야 하는 것이고, Arg를 받지 않아도 안될 것 같지만 입력 자체는 가능할 것 같은 커맨드.
|
||||
|
||||
$brief = $commandObj->getBrief();
|
||||
|
||||
_setNationCommand($general->getNationID(), $general->getVar('level'), $turnList, $command, $arg, $brief);
|
||||
_setNationCommand($commandObj, $turnList);
|
||||
return [
|
||||
'result'=>true,
|
||||
'arg_test'=>true,
|
||||
|
||||
+16
-4
@@ -229,11 +229,23 @@ function updateQuaterly() {
|
||||
$connect=$db->get();
|
||||
|
||||
//천도 제한 해제, 관직 변경 제한 해제
|
||||
$query = "update nation set capset='0',l12set='0',l11set='0',l10set='0',l9set='0',l8set='0',l7set='0',l6set='0',l5set='0'";
|
||||
MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
|
||||
$db->update('nation', [
|
||||
'capset'=>0,
|
||||
'l12set'=>0,
|
||||
'l11set'=>0,
|
||||
'l10set'=>0,
|
||||
'l9set'=>0,
|
||||
'l8set'=>0,
|
||||
'l7set'=>0,
|
||||
'l6set'=>0,
|
||||
'l5set'=>0,
|
||||
], true);
|
||||
//관직 변경 제한 해제
|
||||
$query = "update city set officer4set='0',officer3set='0',officer2set='0'";
|
||||
MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
|
||||
$db->update('city', [
|
||||
'officer4set'=>0,
|
||||
'officer3set'=>0,
|
||||
'officer2set'=>0,
|
||||
], true);
|
||||
}
|
||||
|
||||
// 벌점 감소와 건국제한-1 전턴제한-1 외교제한-1, 1달마다 실행, 병사 있는 장수의 군량 감소, 수입비율 조정
|
||||
|
||||
@@ -218,6 +218,17 @@ abstract class BaseCommand{
|
||||
return $this->arg;
|
||||
}
|
||||
|
||||
public function getGeneral():General{
|
||||
return $this->generalObj;
|
||||
}
|
||||
|
||||
public function getNationID(){
|
||||
return $this->generalObj->getNationID();
|
||||
}
|
||||
|
||||
public function getGeneralLevel(){
|
||||
return $this->generalObj->getVar('level');
|
||||
}
|
||||
|
||||
public function getBrief():string{
|
||||
return static::getName();
|
||||
|
||||
@@ -9,13 +9,15 @@ use \sammo\{
|
||||
LastTurn,
|
||||
GameUnitConst,
|
||||
CityConst,
|
||||
Command
|
||||
Command,
|
||||
TimeUtil
|
||||
};
|
||||
|
||||
use function \sammo\{
|
||||
getDomesticExpLevelBonus,
|
||||
CriticalRatioDomestic,
|
||||
CriticalScoreEx
|
||||
CriticalScoreEx,
|
||||
function cutTurn
|
||||
};
|
||||
|
||||
use \sammo\Constraint\Constraint;
|
||||
@@ -131,7 +133,12 @@ class che_발령 extends Command\NationCommand{
|
||||
$josaUl = JosaUtil::pick($destGeneralName, '을');
|
||||
$josaRo = JosaUtil::pick($destCityName, '로');
|
||||
$destGeneral->getLogger()->pushGeneralActionLog("<Y>{$generalName}</>에 의해 <G><b>{$destCityName}</b></>{$josaRo} 발령됐습니다. <1>$date</>");
|
||||
$destGeneral->setAuxVar('last발령', $general->getTurnTime());
|
||||
|
||||
$yearMonth = Util::joinYearMonth($this->env['year'], $this->env['month']);
|
||||
if(cutTurn($general->getTurnTime(), $this->env['turnterm']) != cutTurn($destGeneral->getTurnTime(), $this->env['turnterm'])){
|
||||
$yearMonth+=1;
|
||||
}
|
||||
$destGeneral->setAuxVar('last발령', $yearMonth);
|
||||
$logger->pushGeneralActionLog("<Y>{$destGeneralName}</>{$josaUl} <G><b>{$destCityName}</b></>{$josaRo} 발령했습니다. <1>$date</>");
|
||||
|
||||
$this->setResultTurn(new LastTurn(static::getName(), $this->arg));
|
||||
|
||||
+214
-185
@@ -65,6 +65,8 @@ class GeneralAI
|
||||
protected $userWarGenerals;
|
||||
/** @var General[] */
|
||||
protected $userCivilGenerals;
|
||||
/** @var General[] */
|
||||
protected $chiefGenerals;
|
||||
|
||||
/** @var General[] */
|
||||
protected $lostGenerals;
|
||||
@@ -96,7 +98,7 @@ class GeneralAI
|
||||
}
|
||||
$this->city = $general->getRawCity();
|
||||
$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,type,aux FROM nation WHERE nation = %i',
|
||||
'SELECT nation,name,color,capital,capset,gennum,gold,rice,bill,rate,rate_tmp,scout,war,strategic_cmd_limit,surlimit,tech,power,level,l12set,l11set,l10set,l9set,l8set,l7set,l6set,l5set,type,aux FROM nation WHERE nation = %i',
|
||||
$general->getNationID()
|
||||
) ?? [
|
||||
'nation' => 0,
|
||||
@@ -243,6 +245,9 @@ class GeneralAI
|
||||
$this->calcWarRoute();
|
||||
$troopCandidate = [];
|
||||
|
||||
$chiefTurn = cutTurn($this->general->getTurnTime(), $this->env['turnterm']);
|
||||
$yearMonth = Util::joinYearMonth($this->env['year'], $this->env['month']);
|
||||
|
||||
foreach($this->troopLeaders as $troopLeader){
|
||||
$leaderID = $troopLeader->getID();
|
||||
if(!key_exists($leaderID, $this->nationPolicy->CombatForce)){
|
||||
@@ -255,6 +260,19 @@ class GeneralAI
|
||||
continue;
|
||||
}
|
||||
|
||||
$last발령 = $troopLeader->getAuxVar('last발령');
|
||||
if($last발령){
|
||||
$leaderTurn = cutTurn($troopLeader->getTurnTime(), $this->env['turnterm']);
|
||||
$compYearMonth = $yearMonth;
|
||||
if($chiefTurn < $leaderTurn){
|
||||
$compYearMonth += 1;
|
||||
}
|
||||
if($compYearMonth === $yearMonth){
|
||||
//한턴마다 한번씩만 발령하자.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
[$fromCityID, $toCityID] = $this->nationPolicy->CombatForce[$leaderID];
|
||||
|
||||
if(!key_exists($fromCityID, $this->warRoute) && !key_exists($toCityID, $this->warRoute)){
|
||||
@@ -326,6 +344,9 @@ class GeneralAI
|
||||
if(!$this->frontCities){
|
||||
return null;
|
||||
}
|
||||
|
||||
$chiefTurn = cutTurn($this->general->getTurnTime(), $this->env['turnterm']);
|
||||
$yearMonth = Util::joinYearMonth($this->env['year'], $this->env['month']);
|
||||
|
||||
$troopCandidate = [];
|
||||
foreach($this->troopLeaders as $troopLeader){
|
||||
@@ -344,6 +365,20 @@ class GeneralAI
|
||||
continue;
|
||||
}
|
||||
|
||||
$last발령 = $troopLeader->getAuxVar('last발령');
|
||||
if($last발령){
|
||||
$leaderTurn = cutTurn($troopLeader->getTurnTime(), $this->env['turnterm']);
|
||||
$compYearMonth = $yearMonth;
|
||||
if($chiefTurn < $leaderTurn){
|
||||
$compYearMonth += 1;
|
||||
}
|
||||
if($compYearMonth === $yearMonth){
|
||||
//한턴마다 한번씩만 발령하자.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$troopCandidate[$leaderID] = $troopLeader;
|
||||
}
|
||||
|
||||
@@ -708,8 +743,9 @@ class GeneralAI
|
||||
$cityCandidiates = [];
|
||||
foreach($this->supplyCities as $city){
|
||||
$dev = min($city['dev'], 0.999);
|
||||
$score = (1 - $dev)**2;
|
||||
$score /= \count($city['generals'])+1;
|
||||
$score = 1 - $dev;
|
||||
$score **= 2;
|
||||
$score /= sqrt(count($city['generals']) + 1);
|
||||
$cityCandidiates[$city['city']] = $score;
|
||||
}
|
||||
|
||||
@@ -924,8 +960,9 @@ class GeneralAI
|
||||
$cityCandidiates = [];
|
||||
foreach($this->supplyCities as $city){
|
||||
$dev = min($city['dev'], 0.999);
|
||||
$score = (1 - $dev)**2;
|
||||
$score /= \count($city['generals'])+1;
|
||||
$score = 1 - $dev;
|
||||
$score **= 2;
|
||||
$score /= sqrt(count($city['generals']) + 1);
|
||||
$cityCandidiates[$city['city']] = $score;
|
||||
}
|
||||
|
||||
@@ -1667,6 +1704,8 @@ class GeneralAI
|
||||
return $cmd;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function do전쟁내정(GeneralCommand $reservedCommand): ?GeneralCommand
|
||||
@@ -1776,6 +1815,10 @@ class GeneralAI
|
||||
}
|
||||
}
|
||||
|
||||
if(!$cmdList){
|
||||
return null;
|
||||
}
|
||||
|
||||
return Util::choiceRandomUsingWeightPair($cmdList);
|
||||
}
|
||||
|
||||
@@ -1943,6 +1986,13 @@ class GeneralAI
|
||||
$type = GameUnitConst::DEFAULT_CREWTYPE;
|
||||
}
|
||||
|
||||
if($this->generalPolicy->can고급병종){
|
||||
$currType = $general->getCrewTypeObj()->id;
|
||||
if(key_exists($currType, $typesAll) && $typesAll[$currType][1] >= $typesAll[$type][1]){
|
||||
$type = $currType;
|
||||
}
|
||||
}
|
||||
|
||||
//NOTE: 훈련과 사기진작은 '금만 사용한다'는 가정을 하고 있음
|
||||
$obj훈련 = buildGeneralCommandClass('che_훈련', $general, $env);
|
||||
$obj사기진작 = buildGeneralCommandClass('che_사기진작', $general, $env);
|
||||
@@ -2125,10 +2175,9 @@ class GeneralAI
|
||||
{
|
||||
$cmd = $reservedCommand;
|
||||
$general = $this->general;
|
||||
$generalID = $general->getID();
|
||||
|
||||
$cmd = buildGeneralCommandClass('che_집합', $general, $this->env);
|
||||
_setGeneralCommand($generalID, iterator_to_array(Util::range(GameConst::$maxTurn)), $cmd->getRawClassName(), $cmd->getArg(), $cmd->getBrief());
|
||||
_setGeneralCommand($cmd, iterator_to_array(Util::range(GameConst::$maxTurn)));
|
||||
|
||||
return $cmd;
|
||||
}
|
||||
@@ -2140,12 +2189,56 @@ class GeneralAI
|
||||
|
||||
protected function do거병(GeneralCommand $reservedCommand): ?GeneralCommand
|
||||
{
|
||||
return null;
|
||||
$general = $this->general;
|
||||
// 초반이면서 능력이 좋은놈 위주로 1.4%확률로 거병
|
||||
if($general->getVar('makelimit')){
|
||||
return null;
|
||||
}
|
||||
if(!$this->generalPolicy->can건국){
|
||||
return null;
|
||||
}
|
||||
|
||||
$prop = Util::randF() * (GameConst::$defaultStatNPCMax + GameConst::$chiefStatMin) / 2;
|
||||
$ratio = ($this->fullLeadership + $this->fullStrength + $this->fullIntel) / 3;
|
||||
|
||||
|
||||
if($prop >= $ratio){
|
||||
return null;
|
||||
}
|
||||
|
||||
if(Util::randBool(1 - 0.014)){
|
||||
return null;
|
||||
}
|
||||
|
||||
$cmd = buildGeneralCommandClass('che_거병', $general, $this->env, null);
|
||||
if(!$cmd->isRunnable()){
|
||||
return null;
|
||||
}
|
||||
return $cmd;
|
||||
}
|
||||
|
||||
protected function do해산(GeneralCommand $reservedCommand): ?GeneralCommand
|
||||
{
|
||||
$cmd = buildGeneralCommandClass('che_해산', $this->general, $this->env, null);
|
||||
if(!$cmd->isRunnable()){
|
||||
return null;
|
||||
}
|
||||
return $cmd;
|
||||
}
|
||||
|
||||
protected function do건국(GeneralCommand $reservedCommand): ?GeneralCommand
|
||||
{
|
||||
return null;
|
||||
$nationType = Util::choiceRandom(GameConst::$availableNationType);
|
||||
$nationColor = Util::choiceRandom(array_keys(GetNationColors()));
|
||||
$cmd = buildGeneralCommandClass('che_건국', $this->general, $this->env, [
|
||||
'nationName' => "㉿" . mb_substr($this->general->getName(), 1),
|
||||
'nationType' => $nationType,
|
||||
'colorType' => $nationColor
|
||||
]);
|
||||
if(!$cmd->isRunnable()){
|
||||
return null;
|
||||
}
|
||||
return $cmd;
|
||||
}
|
||||
|
||||
protected function do선양(GeneralCommand $reservedCommand): ?GeneralCommand
|
||||
@@ -2161,8 +2254,6 @@ class GeneralAI
|
||||
|
||||
$db = DB::db();
|
||||
|
||||
$arg = null;
|
||||
|
||||
// 오랑캐는 바로 임관
|
||||
if ($general->getVar('npc') == 9) {
|
||||
$rulerNation = $db->queryFirstField(
|
||||
@@ -2179,80 +2270,42 @@ class GeneralAI
|
||||
}
|
||||
}
|
||||
|
||||
switch (Util::choiceRandomUsingWeight([
|
||||
'임관' => 11.4,
|
||||
'거병_견문' => 40,
|
||||
'이동' => 20,
|
||||
'기타' => 28.6
|
||||
])) {
|
||||
//임관
|
||||
case '임관':
|
||||
|
||||
$available = true;
|
||||
|
||||
if ($env['startyear'] + 3 > $env['year']) {
|
||||
//초기 임관 기간에서는 국가가 적을수록 임관 시도가 적음
|
||||
$nationCnt = $db->queryFirstField('SELECT count(nation) FROM nation');
|
||||
$notFullNationCnt = $db->queryFirstField('SELECT count(nation) FROM nation WHERE gennum < %i', GameConst::$initialNationGenLimit);
|
||||
if ($nationCnt == 0 || $notFullNationCnt == 0) {
|
||||
$available = false;
|
||||
} else if (Util::randBool(pow(1 / $nationCnt / pow($notFullNationCnt, 3), 1 / 4))) {
|
||||
//국가가 1개일 경우에는 '임관하지 않음'
|
||||
$available = false;
|
||||
}
|
||||
}
|
||||
|
||||
if ($general->getVar('affinity') == 999 || !$available) {
|
||||
if(Util::randBool(0.3)){
|
||||
if ($env['startyear'] + 3 > $env['year']) {
|
||||
//초기 임관 기간에서는 국가가 적을수록 임관 시도가 적음
|
||||
$nationCnt = $db->queryFirstField('SELECT count(nation) FROM nation');
|
||||
$notFullNationCnt = $db->queryFirstField('SELECT count(nation) FROM nation WHERE gennum < %i', GameConst::$initialNationGenLimit);
|
||||
if ($nationCnt == 0 || $notFullNationCnt == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
//랜임 커맨드 입력.
|
||||
$cmd = buildGeneralCommandClass('che_랜덤임관', $general, $env, ['destNationID' => $rulerNation]);
|
||||
if(!$cmd->isRunnable()){
|
||||
return null;
|
||||
}
|
||||
return $cmd;
|
||||
|
||||
break;
|
||||
case '거병_견문': //거병이나 견문
|
||||
// 초반이면서 능력이 좋은놈 위주로 1.4%확률로 거병
|
||||
|
||||
if($general->getVar('makelimit')){
|
||||
return null;
|
||||
}
|
||||
|
||||
if(!$this->generalPolicy->can건국){
|
||||
return null;
|
||||
}
|
||||
|
||||
$prop = Util::randF() * (GameConst::$defaultStatNPCMax + GameConst::$chiefStatMin) / 2;
|
||||
$ratio = ($general->getVar('leadership') + $general->getVar('strength') + $general->getVar('intel')) / 3;
|
||||
|
||||
|
||||
if($prop >= $ratio){
|
||||
if (Util::randBool(pow(1 / $nationCnt / pow($notFullNationCnt, 3), 1 / 4))) {
|
||||
//국가가 1개일 경우에는 '임관하지 않음'
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if(Util::randBool(1 - 0.014)){
|
||||
return null;
|
||||
}
|
||||
if ($general->getVar('affinity') == 999) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$cmd = buildGeneralCommandClass('che_거병', $general, $env, null);
|
||||
if(!$cmd->isRunnable()){
|
||||
return null;
|
||||
}
|
||||
return $cmd;
|
||||
break;
|
||||
case '이동': //이동
|
||||
//랜임 커맨드 입력.
|
||||
$cmd = buildGeneralCommandClass('che_랜덤임관', $general, $env, ['destNationID' => $rulerNation]);
|
||||
if(!$cmd->isRunnable()){
|
||||
return null;
|
||||
}
|
||||
return $cmd;
|
||||
}
|
||||
|
||||
$paths = array_keys(CityConst::byID($city['city'])->path);
|
||||
if(Util::randBool(0.2)){
|
||||
$paths = array_keys(CityConst::byID($city['city'])->path);
|
||||
|
||||
$cmd = buildGeneralCommandClass('che_이동', $general, $env, ['destCityID' => Util::choiceRandom($paths)]);
|
||||
if(!$cmd->isRunnable()){
|
||||
return null;
|
||||
}
|
||||
return $cmd;
|
||||
break;
|
||||
$cmd = buildGeneralCommandClass('che_이동', $general, $env, ['destCityID' => Util::choiceRandom($paths)]);
|
||||
if(!$cmd->isRunnable()){
|
||||
return null;
|
||||
}
|
||||
|
||||
return $cmd;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -2382,6 +2435,7 @@ class GeneralAI
|
||||
$npcCivilGenerals = [];
|
||||
$npcWarGenerals = [];
|
||||
$troopLeaders = [];
|
||||
$chiefGenerals = [];
|
||||
|
||||
$nationID = $this->nation['nation'];
|
||||
|
||||
@@ -2408,6 +2462,11 @@ class GeneralAI
|
||||
$generalID = $nationGeneral->getID();
|
||||
$cityID = $nationGeneral->getCityID();
|
||||
$npcType = $nationGeneral->getVar('npc');
|
||||
$generalLevel = $nationGeneral->getVar('level');
|
||||
|
||||
if($generalLevel > 4){
|
||||
$chiefGenerals[$generalLevel] = $nationGeneral;
|
||||
}
|
||||
|
||||
if (key_exists($cityID, $nationCities)) {
|
||||
$nationCities[$cityID]['generals'][$generalID] = $nationGeneral;
|
||||
@@ -2461,6 +2520,7 @@ class GeneralAI
|
||||
$this->npcCivilGenerals = $npcCivilGenerals;
|
||||
$this->npcWarGenerals = $npcWarGenerals;
|
||||
$this->troopLeaders = $troopLeaders;
|
||||
$this->chiefGenerals = $chiefGenerals;
|
||||
}
|
||||
|
||||
|
||||
@@ -2469,6 +2529,9 @@ class GeneralAI
|
||||
$lastTurn = $reservedCommand->getLastTurn();
|
||||
$general = $this->general;
|
||||
|
||||
$this->categorizeNationGeneral();
|
||||
$this->categorizeNationCities();
|
||||
|
||||
if($general->getVar('level') == 12){
|
||||
$month = $this->env['month'];
|
||||
if (in_array($month, [1, 4, 7, 10])) {
|
||||
@@ -2481,12 +2544,15 @@ class GeneralAI
|
||||
$this->calcRiceBillRate();
|
||||
}
|
||||
}
|
||||
else if(in_array($month, [3, 6, 9, 12])){
|
||||
$this->calcNonLordPromotion();
|
||||
}
|
||||
|
||||
if($reservedCommand->isRunnable()){
|
||||
return $reservedCommand;
|
||||
}
|
||||
|
||||
$this->categorizeNationGeneral();
|
||||
|
||||
|
||||
foreach($this->nationPolicy->priority as $actionName){
|
||||
if(!$this->nationPolicy->{'can'.$actionName}){
|
||||
@@ -2549,29 +2615,34 @@ class GeneralAI
|
||||
if($result !== null){
|
||||
return $result;
|
||||
}
|
||||
return $this->do중립($reservedCommand);
|
||||
}
|
||||
else {
|
||||
if($npcType >= 2 && $general->getVar('level') == 12 && !$this->nation['capital']){
|
||||
//방랑군 건국
|
||||
$result = $this->do건국($reservedCommand);
|
||||
if($result !== null){
|
||||
return $result;
|
||||
}
|
||||
$result = $this->do방랑군이동($reservedCommand);
|
||||
if($result !== null){
|
||||
return $result;
|
||||
}
|
||||
|
||||
if($npcType >= 2 && $general->getVar('level') == 12 && !$this->nation['capital']){
|
||||
//방랑군 건국
|
||||
$result = $this->do건국($reservedCommand);
|
||||
if($result !== null){
|
||||
return $result;
|
||||
}
|
||||
$result = $this->do방랑군이동($reservedCommand);
|
||||
if($result !== null){
|
||||
return $result;
|
||||
}
|
||||
|
||||
foreach($this->generalPolicy->priority as $actionName){
|
||||
if(!$this->generalPolicy->{'can'.$actionName}){
|
||||
continue;
|
||||
}
|
||||
/** @var ?GeneralCommand */
|
||||
$result = $this->{'do'.$actionName}($reservedCommand);
|
||||
if($result !== null){
|
||||
return $result;
|
||||
}
|
||||
$result = $this->do해산($reservedCommand);
|
||||
if($result !== null){
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
foreach($this->generalPolicy->priority as $actionName){
|
||||
if(!$this->generalPolicy->{'can'.$actionName}){
|
||||
continue;
|
||||
}
|
||||
/** @var ?GeneralCommand */
|
||||
$result = $this->{'do'.$actionName}($reservedCommand);
|
||||
if($result !== null){
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3087,88 +3158,6 @@ class GeneralAI
|
||||
return Util::choiceRandomUsingWeightPair($commandList);
|
||||
}
|
||||
|
||||
public function chooseNeutralTurn(): array
|
||||
{
|
||||
|
||||
$general = $this->getGeneralObj();
|
||||
$city = $this->city;
|
||||
$env = $this->env;
|
||||
|
||||
$db = DB::db();
|
||||
|
||||
$arg = null;
|
||||
|
||||
// 오랑캐는 바로 임관
|
||||
if ($general->getVar('npc') == 9) {
|
||||
$rulerNation = $db->queryFirstField(
|
||||
'SELECT nation FROM general WHERE `level`=12 AND npc=9 and nation not in %li ORDER BY RAND() limit 1',
|
||||
$general->getAuxVar('joinedNations') ?? [0]
|
||||
);
|
||||
|
||||
if ($rulerNation) {
|
||||
return ['che_임관', ['destNationID' => $rulerNation]];
|
||||
}
|
||||
return ['che_견문', null];
|
||||
}
|
||||
|
||||
switch (Util::choiceRandomUsingWeight([
|
||||
'임관' => 11.4,
|
||||
'거병_견문' => 40,
|
||||
'이동' => 20,
|
||||
'기타' => 28.6
|
||||
])) {
|
||||
//임관
|
||||
case '임관':
|
||||
|
||||
$available = true;
|
||||
|
||||
if ($env['startyear'] + 3 > $env['year']) {
|
||||
//초기 임관 기간에서는 국가가 적을수록 임관 시도가 적음
|
||||
$nationCnt = $db->queryFirstField('SELECT count(nation) FROM nation');
|
||||
$notFullNationCnt = $db->queryFirstField('SELECT count(nation) FROM nation WHERE gennum < %i', GameConst::$initialNationGenLimit);
|
||||
if ($nationCnt == 0 || $notFullNationCnt == 0) {
|
||||
$available = false;
|
||||
} else if (Util::randBool(pow(1 / $nationCnt / pow($notFullNationCnt, 3), 1 / 4))) {
|
||||
//국가가 1개일 경우에는 '임관하지 않음'
|
||||
$available = false;
|
||||
}
|
||||
}
|
||||
|
||||
if ($general->getVar('affinity') == 999 || !$available) {
|
||||
$command = 'che_견문'; //견문
|
||||
} else {
|
||||
//랜임 커맨드 입력.
|
||||
$command = 'che_랜덤임관';
|
||||
$arg = [
|
||||
'destNationIDList' => []
|
||||
];
|
||||
}
|
||||
break;
|
||||
case '거병_견문': //거병이나 견문
|
||||
// 초반이면서 능력이 좋은놈 위주로 1.4%확률로 거병
|
||||
$prop = Util::randF() * (GameConst::$defaultStatNPCMax + GameConst::$chiefStatMin) / 2;
|
||||
$ratio = ($general->getVar('leadership') + $general->getVar('strength') + $general->getVar('intel')) / 3;
|
||||
if ($env['startyear'] + 2 > $env['year'] && $prop < $ratio && Util::randBool(0.014) && $general->getVar('makelimit') == 0) {
|
||||
//거병
|
||||
$command = 'che_거병';
|
||||
} else {
|
||||
//견문
|
||||
$command = 'che_견문';
|
||||
}
|
||||
break;
|
||||
case '이동': //이동
|
||||
|
||||
$paths = array_keys(CityConst::byID($city['city'])->path);
|
||||
$command = 'che_이동';
|
||||
$arg = ['destCityID' => Util::choiceRandom($paths)];
|
||||
break;
|
||||
default:
|
||||
$command = 'che_견문';
|
||||
break;
|
||||
}
|
||||
return [$command, $arg];
|
||||
}
|
||||
|
||||
public function old_chooseGeneralTurn($command, $arg): array
|
||||
{
|
||||
$general = $this->getGeneralObj();
|
||||
@@ -3205,11 +3194,7 @@ class GeneralAI
|
||||
$arg = [];
|
||||
$general->setVar('killturn', rand(70, 75));
|
||||
//NOTE: 부대 편성에 보여야 하므로 이것만 DB에 직접 접근함.
|
||||
$db->update('general_turn', [
|
||||
'action' => 'che_집합',
|
||||
'arg' => '{}',
|
||||
'brief' => '집합'
|
||||
], 'general_ID=%i AND turn_idx < 6', $general->getID());
|
||||
//_setGeneralCommand($general->getID, [0,1,2,3,4,5], 'che_집합', null, '집합');
|
||||
}
|
||||
|
||||
return [$command, $arg];
|
||||
@@ -3694,6 +3679,50 @@ class GeneralAI
|
||||
return Util::choiceRandomUsingWeight($nations);
|
||||
}
|
||||
|
||||
protected function calcNonLordPromotion(){
|
||||
//빈자리는 아무나 채움
|
||||
$db = DB::db();
|
||||
foreach(Util::range(getNationChiefLevel($this->nation['level']), 12) as $chiefLevel){
|
||||
if($this->nation["l{$chiefLevel}set"]){
|
||||
continue;
|
||||
}
|
||||
if(key_exists($chiefLevel, $this->chiefGenerals)){
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
$picked = false;
|
||||
foreach(Util::range(5) as $idx){
|
||||
/** @var General */
|
||||
$randGeneral = Util::choiceRandom($this->npcWarGenerals);
|
||||
if($chiefLevel == 11){
|
||||
$picked = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if($chiefLevel % 2 == 0){
|
||||
if($randGeneral->getStrength(false, false, false, false) < GameConst::$chiefStatMin){
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else{
|
||||
if($randGeneral->getIntel(false, false, false, false) < GameConst::$chiefStatMin){
|
||||
continue;
|
||||
}
|
||||
}
|
||||
$picked = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if(!$picked){
|
||||
continue;
|
||||
}
|
||||
|
||||
$randGeneral->setVar('level', $chiefLevel);
|
||||
$randGeneral->applyDB($db);
|
||||
}
|
||||
}
|
||||
|
||||
protected function calcPromotion()
|
||||
{
|
||||
$db = DB::db();
|
||||
@@ -3712,7 +3741,7 @@ class GeneralAI
|
||||
'permission' => 'ambassador',
|
||||
], 'nation=%i AND npc < 2 AND level > 4', $nationID);
|
||||
|
||||
foreach ($db->query(
|
||||
foreach($db->query(
|
||||
'SELECT no, npc, level, killturn FROM general WHERE nation = %i AND 12 > level AND level > 4',
|
||||
$nationID
|
||||
) as $chief) {
|
||||
|
||||
@@ -655,6 +655,10 @@ class Util extends \utilphp\util
|
||||
return $year * 12 + $month - 1;
|
||||
}
|
||||
|
||||
public static function parseYearMonth(int $yearMonth):array{
|
||||
return [intdiv($yearMonth, 12), $yearMonth%12 + 1];
|
||||
}
|
||||
|
||||
/**
|
||||
* 변수의 값을 첫번째 값부터 비교해서 대소를 반환
|
||||
* 길이가 다른 경우, 앞의 결과를 먼저 비교한 뒤, 짧은쪽의 값을 null으로 가정하여 길이 처리
|
||||
|
||||
Reference in New Issue
Block a user