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