AI턴 추가 구현
This commit is contained in:
@@ -1903,6 +1903,76 @@ function searchDistanceListToDest(int $from, int $to, array $linkNationList) {
|
|||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 지정된 도시 내의 최단 거리를 계산해 줌(Floyd-Warshall)
|
||||||
|
* @param $cityIDList 이동 가능한 도시 리스트.
|
||||||
|
* @return array [from][to] 로 표시되는 거리값
|
||||||
|
*/
|
||||||
|
function searchAllDistanceByCityList(array $cityIDList):array {
|
||||||
|
if(!$cityIDList){
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
$cityList = [];
|
||||||
|
foreach($cityIDList as $cityID){
|
||||||
|
$cityList[$cityID] = $cityID;
|
||||||
|
}
|
||||||
|
|
||||||
|
$distanceList = [];
|
||||||
|
foreach($cityIDList as $cityID){
|
||||||
|
$nearList = [$cityID=>0];
|
||||||
|
foreach(CityConst::byID($cityID)->path as $nextCityID){
|
||||||
|
if(!key_exists($nextCityID, $cityList)){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$nearList[$nextCityID] = 1;
|
||||||
|
}
|
||||||
|
$distanceList[$cityID] = $nearList;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Floyd-Warshall
|
||||||
|
foreach($cityList as $cityStop){
|
||||||
|
foreach($cityList as $cityFrom){
|
||||||
|
foreach($cityList as $cityTo){
|
||||||
|
if(!key_exists($cityStop, $distanceList[$cityFrom])){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(!key_exists($cityTo, $distanceList[$cityStop])){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!key_exists($cityTo, $distanceList[$cityFrom])){
|
||||||
|
$distanceList[$cityFrom][$cityTo] = $distanceList[$cityFrom][$cityStop] + $distanceList[$cityStop][$cityTo];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$distanceList[$cityFrom][$cityTo] = min($distanceList[$cityFrom][$cityStop] + $distanceList[$cityStop][$cityTo], $distanceList[$cityFrom][$cityTo]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $distanceList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 지정된 국가 내의 모든 도시들의 최단 거리를 계산해 줌(Floyd-Warshall)
|
||||||
|
* @param $linkNationList 경로에 해당하는 국가 리스트
|
||||||
|
* @param $suppliedCityOnly 보급된 도시만을 이용해 검색
|
||||||
|
* @return array [from][to] 로 표시되는 거리값
|
||||||
|
*/
|
||||||
|
function searchAllDistanceByNationList(array $linkNationList, bool $suppliedCityOnly=false):array {
|
||||||
|
if(!$linkNationList){
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
$db = DB::db();
|
||||||
|
if($suppliedCityOnly){
|
||||||
|
$cityIDList = $db->queryFirstColumn('SELECT city FROM city WHERE nation IN %li AND supply=1',$linkNationList);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
$cityIDList = $db->queryFirstColumn('SELECT city FROM city WHERE nation IN %li',$linkNationList);
|
||||||
|
}
|
||||||
|
return searchAllDistanceByCityList($cityIDList);
|
||||||
|
}
|
||||||
|
|
||||||
function isNeighbor(int $nation1, int $nation2, bool $includeNoSupply=true) {
|
function isNeighbor(int $nation1, int $nation2, bool $includeNoSupply=true) {
|
||||||
if($nation1 === $nation2){
|
if($nation1 === $nation2){
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ class AutorunGeneralPolicy{
|
|||||||
|
|
||||||
//static $NPC증여 = 'NPC증여';
|
//static $NPC증여 = 'NPC증여';
|
||||||
static $NPC헌납 = 'NPC헌납';
|
static $NPC헌납 = 'NPC헌납';
|
||||||
|
static $NPC사망대비 = 'NPC사망대비';
|
||||||
|
|
||||||
static $후방워프 = '후방워프';
|
static $후방워프 = '후방워프';
|
||||||
static $전방워프 = '전방워프';
|
static $전방워프 = '전방워프';
|
||||||
@@ -37,7 +38,9 @@ class AutorunGeneralPolicy{
|
|||||||
static $선양 = '선양';
|
static $선양 = '선양';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static public $priority = [
|
static public $priority = [
|
||||||
|
'NPC사망대비',
|
||||||
'귀환',
|
'귀환',
|
||||||
'금쌀구매',
|
'금쌀구매',
|
||||||
'출병',
|
'출병',
|
||||||
@@ -55,6 +58,7 @@ class AutorunGeneralPolicy{
|
|||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
|
public $canNPC사망대비 = true;
|
||||||
public $can일반내정 = true;
|
public $can일반내정 = true;
|
||||||
public $can긴급내정 = true;
|
public $can긴급내정 = true;
|
||||||
public $can전쟁내정 = true;
|
public $can전쟁내정 = true;
|
||||||
@@ -90,12 +94,17 @@ class AutorunGeneralPolicy{
|
|||||||
$nationID = $general->getNationID();
|
$nationID = $general->getNationID();
|
||||||
|
|
||||||
if($npc==5){
|
if($npc==5){
|
||||||
|
$this->can집합 = true;
|
||||||
$this->can선양 = true;
|
$this->can선양 = true;
|
||||||
$this->can집합 = true;
|
$this->can집합 = true;
|
||||||
$this->can국가선택 = false;
|
$this->can국가선택 = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if($npc==1){
|
||||||
|
$this->canNPC사망대비 = false;
|
||||||
|
}
|
||||||
|
|
||||||
if($nationID != 0){
|
if($nationID != 0){
|
||||||
$this->can국가선택 = false;
|
$this->can국가선택 = false;
|
||||||
$this->can건국 = false;
|
$this->can건국 = false;
|
||||||
|
|||||||
@@ -10,9 +10,13 @@ class AutorunNationPolicy {
|
|||||||
static $부대유저장후방발령 = '부대유저장후방발령';
|
static $부대유저장후방발령 = '부대유저장후방발령';
|
||||||
static $유저장후방발령 = '유저장후방발령';
|
static $유저장후방발령 = '유저장후방발령';
|
||||||
static $유저장전방발령 = '유저장전방발령';
|
static $유저장전방발령 = '유저장전방발령';
|
||||||
|
static $유저장구출발령 = '유저장구출발령';
|
||||||
|
static $유저장내정발령 = '유저장내정발령';
|
||||||
|
|
||||||
static $NPC후방발령 = 'NPC후방발령';
|
static $NPC후방발령 = 'NPC후방발령';
|
||||||
static $NPC전방발령 = 'NPC전방발령';
|
static $NPC전방발령 = 'NPC전방발령';
|
||||||
|
static $NPC구출발령 = 'NPC구출발령';
|
||||||
|
static $NPC내정발령 = 'NPC내정발령';
|
||||||
|
|
||||||
static $유저장긴급포상 = '유저장긴급포상';
|
static $유저장긴급포상 = '유저장긴급포상';
|
||||||
static $유저장포상 = '유저장포상';
|
static $유저장포상 = '유저장포상';
|
||||||
@@ -35,6 +39,7 @@ class AutorunNationPolicy {
|
|||||||
|
|
||||||
'유저장긴급포상',
|
'유저장긴급포상',
|
||||||
'부대전방발령',
|
'부대전방발령',
|
||||||
|
'유저장구출발령',
|
||||||
|
|
||||||
'유저장후방발령',
|
'유저장후방발령',
|
||||||
'부대유저장후방발령',
|
'부대유저장후방발령',
|
||||||
@@ -46,23 +51,30 @@ class AutorunNationPolicy {
|
|||||||
'부대후방발령',
|
'부대후방발령',
|
||||||
|
|
||||||
'NPC긴급포상',
|
'NPC긴급포상',
|
||||||
|
'NPC구출발령',
|
||||||
'NPC후방발령',
|
'NPC후방발령',
|
||||||
|
|
||||||
'NPC포상',
|
'NPC포상',
|
||||||
'NPC몰수',
|
'NPC몰수',
|
||||||
|
|
||||||
'NPC전방발령',
|
'NPC전방발령',
|
||||||
|
|
||||||
|
'유저장내정발령',
|
||||||
|
'NPC내정발령',
|
||||||
];
|
];
|
||||||
|
|
||||||
//순서는 중요하지 않음
|
//순서는 중요하지 않음
|
||||||
static public $availableInstantTurn = [
|
static public $availableInstantTurn = [
|
||||||
'유저장긴급포상'=>true,
|
'유저장긴급포상'=>true,
|
||||||
|
'유저장구출발령'=>true,
|
||||||
'유저장후방발령'=>true,
|
'유저장후방발령'=>true,
|
||||||
'유저장전방발령'=>true,
|
'유저장전방발령'=>true,
|
||||||
|
'유저장내정발령'=>true,
|
||||||
'유저장포상'=>true,
|
'유저장포상'=>true,
|
||||||
'NPC긴급포상'=>true,
|
'NPC긴급포상'=>true,
|
||||||
|
'NPC구출발령'=>true,
|
||||||
'NPC후방발령'=>true,
|
'NPC후방발령'=>true,
|
||||||
|
'NPC내정발령'=>true,
|
||||||
'NPC포상'=>true,
|
'NPC포상'=>true,
|
||||||
'NPC전방발령'=>true,
|
'NPC전방발령'=>true,
|
||||||
];
|
];
|
||||||
@@ -75,9 +87,13 @@ class AutorunNationPolicy {
|
|||||||
public $can부대유저장후방발령 = true;
|
public $can부대유저장후방발령 = true;
|
||||||
public $can유저장후방발령 = true;
|
public $can유저장후방발령 = true;
|
||||||
public $can유저장전방발령 = true;
|
public $can유저장전방발령 = true;
|
||||||
|
public $can유저장구출발령 = true;
|
||||||
|
public $can유저장내정발령 = true;
|
||||||
|
|
||||||
public $canNPC후방발령 = true;
|
public $canNPC후방발령 = true;
|
||||||
public $canNPC전방발령 = true;
|
public $canNPC전방발령 = true;
|
||||||
|
public $canNPC구출발령 = true;
|
||||||
|
public $canNPC내정발령 = true;
|
||||||
|
|
||||||
public $can유저장긴급포상 = true;
|
public $can유저장긴급포상 = true;
|
||||||
public $can유저장포상 = true;
|
public $can유저장포상 = true;
|
||||||
@@ -94,14 +110,14 @@ class AutorunNationPolicy {
|
|||||||
public $reqNationGold = 10000;
|
public $reqNationGold = 10000;
|
||||||
public $reqNationRice = 10000;
|
public $reqNationRice = 10000;
|
||||||
public $CombatForce = [
|
public $CombatForce = [
|
||||||
[200, 10, 24],//troopLeader, fromCity, toCity
|
//200 => [10, 24],//troopLeader, fromCity, toCity
|
||||||
[242, 10, 24]
|
//242 => [10, 24]
|
||||||
];
|
];
|
||||||
public $SupportForce = [
|
public $SupportForce = [
|
||||||
211
|
//211=>true
|
||||||
];
|
];
|
||||||
public $DevelopForce = [
|
public $DevelopForce = [
|
||||||
123
|
//123=>true
|
||||||
];
|
];
|
||||||
public $reqHumanWarGold = [10000, 30000];
|
public $reqHumanWarGold = [10000, 30000];
|
||||||
public $reqHumanWarRice = [10000, 30000];
|
public $reqHumanWarRice = [10000, 30000];
|
||||||
@@ -113,10 +129,11 @@ class AutorunNationPolicy {
|
|||||||
public $reqNPCDevelRice = 0;
|
public $reqNPCDevelRice = 0;
|
||||||
|
|
||||||
public $minNPCWarLeadership = 40;
|
public $minNPCWarLeadership = 40;
|
||||||
|
public $minWarCrew = 1500;
|
||||||
|
|
||||||
public $allowNpcAttackCity = true;
|
public $allowNpcAttackCity = true;
|
||||||
public $minNPCRecruitCityPopulation = 50000;
|
public $minNPCRecruitCityPopulation = 50000;
|
||||||
public $safeRecruitCityPopulation = 50000;
|
public $safeRecruitCityPopulationRatio = 0.5;
|
||||||
public $properWarTrainAtmos = 90;
|
public $properWarTrainAtmos = 90;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace sammo;
|
namespace sammo;
|
||||||
|
|
||||||
|
use sammo\Command\GeneralCommand;
|
||||||
use sammo\WarUnitTrigger as WarUnitTrigger;
|
use sammo\WarUnitTrigger as WarUnitTrigger;
|
||||||
|
|
||||||
class General implements iAction{
|
class General implements iAction{
|
||||||
@@ -266,6 +268,30 @@ class General implements iAction{
|
|||||||
return GameUnitConst::byID($this->getVar('crewtype'));
|
return GameUnitConst::byID($this->getVar('crewtype'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function calcRecentWarTurn(int $turnTerm):int{
|
||||||
|
if(!$this->getVar('recent_war')){
|
||||||
|
return 12*1000;
|
||||||
|
}
|
||||||
|
$recwar = new \DateTimeImmutable($this->getVar('recent_war'));
|
||||||
|
$turnNow = new \DateTimeImmutable($this->getVar('turntime'));
|
||||||
|
$secDiff = TimeUtil::DateIntervalToSeconds($recwar->diff($turnNow));
|
||||||
|
|
||||||
|
if($secDiff <= 0){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return intdiv($secDiff, 60 * $turnTerm);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getReservedTurn(int $turnIdx, array $env):?GeneralCommand{
|
||||||
|
$db = DB::db();
|
||||||
|
$rawCmd = $db->queryFirstRow('SELECT * FROM general_turn WHERE general_id = %i AND turn_idx = %i', $this->getID(), $turnIdx);
|
||||||
|
if(!$rawCmd){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return buildGeneralCommandClass($rawCmd['action'], $this, $env, $rawCmd['arg']);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 장수의 스탯을 계산해옴
|
* 장수의 스탯을 계산해옴
|
||||||
*
|
*
|
||||||
|
|||||||
+442
-234
@@ -51,6 +51,7 @@ class GeneralAI
|
|||||||
protected $supplyCities;
|
protected $supplyCities;
|
||||||
protected $backupCities;
|
protected $backupCities;
|
||||||
|
|
||||||
|
protected $warRoute;
|
||||||
|
|
||||||
/** @var General[] */
|
/** @var General[] */
|
||||||
protected $nationGenerals;
|
protected $nationGenerals;
|
||||||
@@ -60,6 +61,11 @@ class GeneralAI
|
|||||||
protected $npcWarGenerals;
|
protected $npcWarGenerals;
|
||||||
/** @var General[] */
|
/** @var General[] */
|
||||||
protected $userGenerals;
|
protected $userGenerals;
|
||||||
|
/** @var General[] */
|
||||||
|
protected $userWarGenerals;
|
||||||
|
/** @var General[] */
|
||||||
|
protected $userCivilGenerals;
|
||||||
|
|
||||||
/** @var General[] */
|
/** @var General[] */
|
||||||
protected $lostGenerals;
|
protected $lostGenerals;
|
||||||
/** @var General[] */
|
/** @var General[] */
|
||||||
@@ -81,7 +87,7 @@ class GeneralAI
|
|||||||
{
|
{
|
||||||
$db = DB::db();
|
$db = DB::db();
|
||||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||||
$this->env = $gameStor->getValues(['startyear', 'year', 'month', 'turnterm', 'killturn', 'scenario', 'gold_rate', 'rice_rate', 'develcost']);
|
$this->env = $gameStor->getValues(['startyear', 'year', 'month', 'turnterm', 'killturn', 'scenario', 'gold_rate', 'rice_rate', 'develcost', 'autorun_user']);
|
||||||
$this->baseDevelCost = $this->env['develcost'] * 12;
|
$this->baseDevelCost = $this->env['develcost'] * 12;
|
||||||
$this->general = $general;
|
$this->general = $general;
|
||||||
if ($general->getRawCity() === null) {
|
if ($general->getRawCity() === null) {
|
||||||
@@ -90,11 +96,14 @@ class GeneralAI
|
|||||||
}
|
}
|
||||||
$this->city = $general->getRawCity();
|
$this->city = $general->getRawCity();
|
||||||
$this->nation = $db->queryFirstRow(
|
$this->nation = $db->queryFirstRow(
|
||||||
'SELECT nation,level,capital,tech,gold,rice,rate,type,color,name,war 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,type,aux FROM nation WHERE nation = %i',
|
||||||
$general->getNationID()
|
$general->getNationID()
|
||||||
) ?? [
|
) ?? [
|
||||||
'nation' => 0,
|
'nation' => 0,
|
||||||
'level' => 0,
|
'level' => 0,
|
||||||
|
'capital' => 0,
|
||||||
|
'capset' => false,
|
||||||
|
'gennum' => 0,
|
||||||
'tech' => 0,
|
'tech' => 0,
|
||||||
'gold' => 0,
|
'gold' => 0,
|
||||||
'rice' => 0,
|
'rice' => 0,
|
||||||
@@ -102,6 +111,7 @@ class GeneralAI
|
|||||||
'color' => '#000000',
|
'color' => '#000000',
|
||||||
'name' => '재야',
|
'name' => '재야',
|
||||||
];
|
];
|
||||||
|
$this->nation['aux'] = Json::decode($this->nation['aux']??'{}');
|
||||||
|
|
||||||
$this->leadership = $general->getLeadership();
|
$this->leadership = $general->getLeadership();
|
||||||
$this->strength = $general->getStrength();
|
$this->strength = $general->getStrength();
|
||||||
@@ -114,6 +124,12 @@ class GeneralAI
|
|||||||
$this->genType = $this::calcGenType($general);
|
$this->genType = $this::calcGenType($general);
|
||||||
|
|
||||||
$this->calcDiplomacyState();
|
$this->calcDiplomacyState();
|
||||||
|
|
||||||
|
$serverPolicy = KVStorage::getStorage($db, 'autorun_nation_policy_0');
|
||||||
|
$nationPolicy = KVStorage::getStorage($db, "autorun_nation_policy_{$this->nation['nation']}");
|
||||||
|
|
||||||
|
$this->nationPolicy = new AutorunNationPolicy($general, $nationPolicy->getAll(), $serverPolicy->getAll());
|
||||||
|
$this->generalPolicy = new AutorunGeneralPolicy($general, $this->env['autorun_user']['options']??[]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getGeneralObj(): General
|
public function getGeneralObj(): General
|
||||||
@@ -209,24 +225,353 @@ class GeneralAI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function calcWarRoute(){
|
||||||
|
if($this->warRoute !== null){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$target = $this->warTargetNation;
|
||||||
|
$target[] = $this->nation['nation'];
|
||||||
|
|
||||||
|
$this->warRoute = searchAllDistanceByNationList($target, false);
|
||||||
|
}
|
||||||
|
|
||||||
protected function do부대전방발령(LastTurn $lastTurn): ?NationCommand
|
protected function do부대전방발령(LastTurn $lastTurn): ?NationCommand
|
||||||
{
|
{
|
||||||
return null;
|
$this->calcWarRoute();
|
||||||
|
$troopCandidate = [];
|
||||||
|
|
||||||
|
foreach($this->troopLeaders as $troopLeader){
|
||||||
|
$leaderID = $troopLeader->getID();
|
||||||
|
if(!key_exists($leaderID, $this->nationPolicy->CombatForce)){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$currentCityID = $troopLeader->getCityID();
|
||||||
|
|
||||||
|
if(key_exists($currentCityID, $this->frontCities)){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
[$fromCityID, $toCityID] = $this->nationPolicy->CombatForce[$leaderID];
|
||||||
|
|
||||||
|
if(!key_exists($fromCityID, $this->warRoute) && !key_exists($toCityID, $this->warRoute)){
|
||||||
|
//공격 루트 상실, 전방 아무데나
|
||||||
|
$troopCandidate[] = [$leaderID, Util::choiceRandom($this->frontCities)['city']];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!key_exists($toCityID, $this->warRoute[$fromCityID])){
|
||||||
|
//공격 루트 상실, 전방 아무데나
|
||||||
|
$troopCandidate[] = [$leaderID, Util::choiceRandom($this->frontCities)['city']];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(key_exists($fromCityID, $this->supplyCities) && key_exists($toCityID, $this->supplyCities)){
|
||||||
|
//점령 완료, 전방 아무데나
|
||||||
|
$troopCandidate[] = [$leaderID, Util::choiceRandom($this->frontCities)['city']];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//출발지가 아국땅이 아닌경우 수도->출발지
|
||||||
|
if(!key_exists($fromCityID, $this->supplyCities)){
|
||||||
|
$toCityID = $fromCityID;
|
||||||
|
$fromCityID = $this->nation['capital'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$targetCityID = $fromCityID;
|
||||||
|
//접경에 도달할때까지 전진
|
||||||
|
while(!key_exists($targetCityID, $this->frontCities)){
|
||||||
|
$distance = $this->warRoute[$targetCityID][$toCityID];
|
||||||
|
$nextCityCandidate = [];
|
||||||
|
foreach(CityConst::byID($targetCityID)->path as $nearCityID){
|
||||||
|
if(!key_exists($nearCityID, $this->warRoute) || !key_exists($toCityID, $this->warRoute[$nearCityID])){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if($this->warRoute[$nearCityID][$toCityID] + 1 > $distance){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$nextCityCandidate[] = $nearCityID;
|
||||||
|
}
|
||||||
|
if(!$nextCityCandidate){
|
||||||
|
throw new MustNotBeReachedException('경로 계산 버그');
|
||||||
|
}
|
||||||
|
if(count($nextCityCandidate) == 1){
|
||||||
|
$targetCityID = $nextCityCandidate[0];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$targetCityID = Util::choiceRandom($nextCityCandidate);
|
||||||
|
}
|
||||||
|
|
||||||
|
$troopCandidate[] = ['destGenaralID'=>$leaderID, 'destCityID'=>$targetCityID];
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!$troopCandidate){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$cmd = buildNationCommandClass('che_발령', $this->general, $this->env, $lastTurn, Util::choiceRandom($troopCandidate));
|
||||||
|
if(!$cmd->isRunnable()){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function do부대후방발령(LastTurn $lastTurn): ?NationCommand
|
protected function do부대후방발령(LastTurn $lastTurn): ?NationCommand
|
||||||
{
|
{
|
||||||
return null;
|
$troopCandidate = [];
|
||||||
|
foreach($this->troopLeaders as $troopLeader){
|
||||||
|
$leaderID = $troopLeader->getID();
|
||||||
|
if(key_exists($leaderID, $this->nationPolicy->CombatForce)){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$currentCityID = $troopLeader->getCityID();
|
||||||
|
if(!key_exists($currentCityID, $this->supplyCities)){
|
||||||
|
$troopCandidate[$leaderID] = $troopLeader;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$city = $this->supplyCities[$currentCityID];
|
||||||
|
if($city['pop'] / $city['pop2'] >= $this->nationPolicy->safeRecruitCityPopulationRatio){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$troopCandidate[$leaderID] = $troopLeader;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!$troopCandidate){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(count($this->supplyCities) == 1){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$cityCandidates = [];
|
||||||
|
|
||||||
|
foreach($this->backupCities as $city){
|
||||||
|
if($city['pop'] / $city['pop_max'] < $this->nationPolicy->safeRecruitCityPopulationRatio){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$cityCandidates[] = $city;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!$cityCandidates){
|
||||||
|
foreach($this->supplyCities as $city){
|
||||||
|
if($city['pop'] / $city['pop_max'] < $this->nationPolicy->safeRecruitCityPopulationRatio){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$cityCandidates[] = $city;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!$cityCandidates){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$cmd = buildNationCommandClass('che_발령', $this->general, $this->env, $lastTurn, [
|
||||||
|
'destGeneralID'=>Util::choiceRandom($troopCandidate)->getID(),
|
||||||
|
'destCityID'=>Util::choiceRandom($cityCandidates)['city']
|
||||||
|
]);
|
||||||
|
|
||||||
|
if(!$cmd->isRunnable()){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected function do부대유저장후방발령(LastTurn $lastTurn): ?NationCommand
|
protected function do부대유저장후방발령(LastTurn $lastTurn): ?NationCommand
|
||||||
{
|
{
|
||||||
return null;
|
if($this->dipState !== self::d전쟁){
|
||||||
}
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$generalCadidates = [];
|
||||||
|
$db = DB::db();
|
||||||
|
|
||||||
|
$chiefTurnTime = new \DateTimeImmutable($this->general->getVar('turntime'));
|
||||||
|
|
||||||
|
foreach($this->userWarGenerals as $userGeneral){
|
||||||
|
$generalID = $userGeneral->getID();
|
||||||
|
if($generalID == $this->general->getID()){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$city = $this->supplyCities[$userGeneral->getCityID()];
|
||||||
|
if(!key_exists($generalID, $this->supplyCities)){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if($userGeneral->getVar('troop') === 0){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if($userGeneral->getVar('troop') === $userGeneral->getID()){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if($city['pop'] / $city['pop_max'] >= $this->nationPolicy->safeRecruitCityPopulationRatio){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if($userGeneral->getVar('crew') >= $this->nationPolicy->minWarCrew){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$generalTurnTime = new \DateTimeImmutable($userGeneral->getVar('turntime'));
|
||||||
|
$troopLeader = $this->nationGenerals[$userGeneral->getVar('troop')];
|
||||||
|
$troopTurnTime = new \DateTimeImmutable($troopLeader->getVar('turntime'));
|
||||||
|
|
||||||
|
if($chiefTurnTime < $generalTurnTime && $generalTurnTime < $troopTurnTime){
|
||||||
|
$generalCadidates[$generalID] = $userGeneral;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!$generalCadidates){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$rawTurn = Util::convertArrayToDict($db->query('SELECT * FROM general_turn WHERE general_id IN %li AND turn_idx = 0', array_keys($generalCadidates)), 'no');
|
||||||
|
$generalCadidates = array_filter($generalCadidates, function(General $general)use($rawTurn){
|
||||||
|
$generalID = $general->getID();
|
||||||
|
if(in_array($rawTurn[$generalID]??null, ['che_징병', 'che_모병'])){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}, ARRAY_FILTER_USE_KEY);
|
||||||
|
|
||||||
|
if(count($this->supplyCities) == 1){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$cityCandidates = [];
|
||||||
|
|
||||||
|
foreach($this->backupCities as $city){
|
||||||
|
if($city['pop'] / $city['pop_max'] < $this->nationPolicy->safeRecruitCityPopulationRatio){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$cityCandidates[] = $city;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!$cityCandidates){
|
||||||
|
foreach($this->supplyCities as $city){
|
||||||
|
if($city['pop'] / $city['pop_max'] < $this->nationPolicy->safeRecruitCityPopulationRatio){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$cityCandidates[] = $city;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!$cityCandidates){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$cmd = buildNationCommandClass('che_발령', $this->general, $this->env, $lastTurn, [
|
||||||
|
'destGeneralID'=>Util::choiceRandom($generalCadidates)->getID(),
|
||||||
|
'destCityID'=>Util::choiceRandom($cityCandidates)['city']
|
||||||
|
]);
|
||||||
|
|
||||||
|
if(!$cmd->isRunnable()){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $cmd;
|
||||||
|
}
|
||||||
protected function do유저장후방발령(LastTurn $lastTurn): ?NationCommand
|
protected function do유저장후방발령(LastTurn $lastTurn): ?NationCommand
|
||||||
{
|
{
|
||||||
|
if($this->dipState !== self::d전쟁){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$generalCadidates = [];
|
||||||
|
|
||||||
|
foreach($this->userWarGenerals as $userGeneral){
|
||||||
|
$generalID = $userGeneral->getID();
|
||||||
|
if($generalID == $this->general->getID()){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$city = $this->supplyCities[$userGeneral->getCityID()];
|
||||||
|
if(!key_exists($generalID, $this->supplyCities)){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if($userGeneral->getVar('troop') !== 0){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if($city['pop'] / $city['pop_max'] >= $this->nationPolicy->safeRecruitCityPopulationRatio){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if($userGeneral->getVar('crew') >= $this->nationPolicy->minWarCrew){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$generalCadidates[$generalID] = $userGeneral;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!$generalCadidates){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(count($this->supplyCities) == 1){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$cityCandidates = [];
|
||||||
|
|
||||||
|
if($this->backupCities){
|
||||||
|
$cities = $this->backupCities;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
$cities = $this->supplyCities;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach($cities as $city){
|
||||||
|
if($city['pop'] / $city['pop_max'] < $this->nationPolicy->safeRecruitCityPopulationRatio){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$cityCandidates[] = $city;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!$cityCandidates){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$cmd = buildNationCommandClass('che_발령', $this->general, $this->env, $lastTurn, [
|
||||||
|
'destGeneralID'=>Util::choiceRandom($generalCadidates)->getID(),
|
||||||
|
'destCityID'=>Util::choiceRandom($cityCandidates)['city']
|
||||||
|
]);
|
||||||
|
|
||||||
|
if(!$cmd->isRunnable()){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function do유저장구출발령(LastTurn $lastTurn): ?NationCommand
|
||||||
|
{
|
||||||
|
//고립 도시 장수 발령
|
||||||
|
$args = [];
|
||||||
|
foreach ($this->lostGenerals as $lostGeneral) {
|
||||||
|
if ($lostGeneral->getVar('npc') >= 2) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (in_array($this->dipState, [self::d직전, self::d전쟁]) && count($this->frontCities) > 2) {
|
||||||
|
$selCity = Util::choiceRandom($this->frontCities);
|
||||||
|
} else {
|
||||||
|
$selCity = Util::choiceRandom($this->supplyCities);
|
||||||
|
}
|
||||||
|
//고립된 장수가 많을 수록 발령 확률 증가
|
||||||
|
$args = [
|
||||||
|
'destGeneralID' => $lostGeneral->getID(),
|
||||||
|
'destCityID' => $selCity['city']
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if(!$args){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$cmd = buildNationCommandClass('che_발령', $this->general, $this->env, $lastTurn, Util::choiceRandom($args));
|
||||||
|
if(!$cmd->isRunnable()){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,17 +580,56 @@ class GeneralAI
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function do유저장내정발령(LastTurn $lastTurn): ?NationCommand
|
||||||
|
{
|
||||||
|
$env = $this->env;
|
||||||
|
$args = [];
|
||||||
|
foreach($this->userCivilGenerals as $userGeneral){
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
protected function doNPC후방발령(LastTurn $lastTurn): ?NationCommand
|
protected function doNPC후방발령(LastTurn $lastTurn): ?NationCommand
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected function doNPC구출발령(LastTurn $lastTurn): ?NationCommand
|
||||||
|
{
|
||||||
|
//고립 도시 장수 발령
|
||||||
|
$args = [];
|
||||||
|
foreach ($this->lostGenerals as $lostGeneral) {
|
||||||
|
if ($lostGeneral->getVar('npc') < 2 || $lostGeneral->getVar('npc') == 5) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$selCity = Util::choiceRandom($this->supplyCities);
|
||||||
|
//고립된 장수가 많을 수록 발령 확률 증가
|
||||||
|
$args = [
|
||||||
|
'destGeneralID' => $lostGeneral->getID(),
|
||||||
|
'destCityID' => $selCity['city']
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if(!$args){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$cmd = buildNationCommandClass('che_발령', $this->general, $this->env, $lastTurn, Util::choiceRandom($args));
|
||||||
|
if(!$cmd->isRunnable()){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
protected function doNPC전방발령(LastTurn $lastTurn): ?NationCommand
|
protected function doNPC전방발령(LastTurn $lastTurn): ?NationCommand
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function doNPC내정발령(LastTurn $lastTurn): ?NationCommand
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
protected function do유저장긴급포상(LastTurn $lastTurn): ?NationCommand
|
protected function do유저장긴급포상(LastTurn $lastTurn): ?NationCommand
|
||||||
{
|
{
|
||||||
@@ -267,29 +651,18 @@ class GeneralAI
|
|||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
$userGenerals = $this->userGenerals;
|
$userWarGenerals = $this->userWarGenerals;
|
||||||
|
|
||||||
foreach($remainResource as $resName=>[$resVal,$reqHumanMinRes]){
|
foreach($remainResource as $resName=>[$resVal,$reqHumanMinRes]){
|
||||||
usort($userGenerals, function ($lhs, $rhs) use ($resName) {
|
usort($userWarGenerals, function ($lhs, $rhs) use ($resName) {
|
||||||
return $lhs->getVar($resName) <=> $rhs->getVar($resName);
|
return $lhs->getVar($resName) <=> $rhs->getVar($resName);
|
||||||
});
|
});
|
||||||
|
|
||||||
foreach($userGenerals as $idx=>$targetUserGeneral){
|
foreach($userWarGenerals as $idx=>$targetUserGeneral){
|
||||||
if($targetUserGeneral->getVar($resName) >= $reqHumanMinRes){
|
if($targetUserGeneral->getVar($resName) >= $reqHumanMinRes){
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if($targetUserGeneral->getVar('recent_war') === null){
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$recent_war = new \DateTimeImmutable($targetUserGeneral->getVar('recent_war'));
|
|
||||||
$turnTime = new \DateTimeImmutable($targetUserGeneral->getVar('turntime'));
|
|
||||||
$timeDiffSecRecentWar = TimeUtil::DateIntervalToSeconds($recent_war->diff($turnTime));
|
|
||||||
|
|
||||||
if($timeDiffSecRecentWar > $this->env['turnterm'] * 60 * 12){
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$crewtype = $targetUserGeneral->getCrewTypeObj();
|
$crewtype = $targetUserGeneral->getCrewTypeObj();
|
||||||
$reqMoney = $crewtype->costWithTech($this->nation['tech'], $targetUserGeneral->getLeadership()) * 2 * 4 * 1.1;
|
$reqMoney = $crewtype->costWithTech($this->nation['tech'], $targetUserGeneral->getLeadership()) * 2 * 4 * 1.1;
|
||||||
if ($this->env['year'] > $this->env['startyear'] + 5) {
|
if ($this->env['year'] > $this->env['startyear'] + 5) {
|
||||||
@@ -312,7 +685,7 @@ class GeneralAI
|
|||||||
'isGold' => $resName == 'gold',
|
'isGold' => $resName == 'gold',
|
||||||
'amount' => Util::valueFit($payAmount, 100, GameConst::$maxResourceActionAmount)
|
'amount' => Util::valueFit($payAmount, 100, GameConst::$maxResourceActionAmount)
|
||||||
],
|
],
|
||||||
count($userGenerals)-$idx
|
count($userWarGenerals)-$idx
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -359,15 +732,11 @@ class GeneralAI
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
$isWarGeneral = false;
|
if(key_exists($targetUserGeneral->getID(), $this->userWarGenerals)){
|
||||||
if($targetUserGeneral->getVar('recent_war') !== null){
|
$isWarGeneral = true;
|
||||||
$recent_war = new \DateTimeImmutable($targetUserGeneral->getVar('recent_war'));
|
}
|
||||||
$turnTime = new \DateTimeImmutable($targetUserGeneral->getVar('turntime'));
|
else{
|
||||||
$timeDiffSecRecentWar = TimeUtil::DateIntervalToSeconds($recent_war->diff($turnTime));
|
$isWarGeneral = false;
|
||||||
|
|
||||||
if($timeDiffSecRecentWar <= $this->env['turnterm'] * 60 * 12){
|
|
||||||
$isWarGeneral = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if($isWarGeneral){
|
if($isWarGeneral){
|
||||||
@@ -749,7 +1118,6 @@ class GeneralAI
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//TODO: 누군가 천도를 했는지 체크해야함.
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
도시 점수 공식
|
도시 점수 공식
|
||||||
@@ -778,8 +1146,6 @@ class GeneralAI
|
|||||||
];
|
];
|
||||||
|
|
||||||
$queue->enqueue($capital);
|
$queue->enqueue($capital);
|
||||||
$distanceList = [
|
|
||||||
];
|
|
||||||
|
|
||||||
//수도와 연결된 도시 탐색
|
//수도와 연결된 도시 탐색
|
||||||
while(!$queue->isEmpty()){
|
while(!$queue->isEmpty()){
|
||||||
@@ -804,38 +1170,8 @@ class GeneralAI
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
//기본 간선
|
$distanceList = searchAllDistanceByCityList($cityList);
|
||||||
foreach(array_keys($cityList) as $cityID){
|
|
||||||
$nearList = [$cityID=>0];
|
|
||||||
foreach(CityConst::byID($cityID)->path as $nextCityID){
|
|
||||||
if(!key_exists($nextCityID, $cityList)){
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$nearList[$nextCityID] = 1;
|
|
||||||
}
|
|
||||||
$distanceList[$cityID] = $nearList;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Floyd-Warshall
|
|
||||||
foreach($cityList as $cityStop){
|
|
||||||
foreach($cityList as $cityFrom){
|
|
||||||
foreach($cityList as $cityTo){
|
|
||||||
if(!key_exists($cityStop, $distanceList[$cityFrom])){
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if(!key_exists($cityTo, $distanceList[$cityStop])){
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!key_exists($cityTo, $distanceList[$cityFrom])){
|
|
||||||
$distanceList[$cityFrom][$cityTo] = $distanceList[$cityFrom][$cityStop] + $distanceList[$cityStop][$cityTo];
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$distanceList[$cityFrom][$cityTo] = min($distanceList[$cityFrom][$cityStop] + $distanceList[$cityStop][$cityTo], $distanceList[$cityFrom][$cityTo]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$maxDistance = 0;
|
$maxDistance = 0;
|
||||||
foreach($distanceList as $cityID=>$subDistanceList){
|
foreach($distanceList as $cityID=>$subDistanceList){
|
||||||
@@ -1310,7 +1646,6 @@ class GeneralAI
|
|||||||
}
|
}
|
||||||
$cmdList = [];
|
$cmdList = [];
|
||||||
$general = $this->general;
|
$general = $this->general;
|
||||||
$cmd사기진작 = buildGeneralCommandClass('che_사기진작', $general, $this->env);
|
|
||||||
|
|
||||||
$train = $general->getVar('train');
|
$train = $general->getVar('train');
|
||||||
$atmos = $general->getVar('atmos');
|
$atmos = $general->getVar('atmos');
|
||||||
@@ -1558,6 +1893,37 @@ class GeneralAI
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function NPC사망대비(): ?GeneralCommand
|
||||||
|
{
|
||||||
|
$general = $this->getGeneralObj();
|
||||||
|
|
||||||
|
if($general->getVar('killturn') > 5){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if($general->getNationID() == 0){
|
||||||
|
return buildGeneralCommandClass('che_견문', $general, $this->env);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($general->getVar('gold') + $general->getVar('rice') == 0) {
|
||||||
|
return buildGeneralCommandClass('che_물자조달', $general, $this->env);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($general->getVar('gold') >= $general->getVar('rice')) {
|
||||||
|
return buildGeneralCommandClass('che_헌납', $general, $this->env, [
|
||||||
|
'isGold' => true,
|
||||||
|
'amount' => GameConst::$maxResourceActionAmount
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
return buildGeneralCommandClass('che_헌납', $general, $this->env, [
|
||||||
|
'isGold' => false,
|
||||||
|
'amount' => GameConst::$maxResourceActionAmount
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
protected function do중립(GeneralCommand $reservedCommand): GeneralCommand
|
protected function do중립(GeneralCommand $reservedCommand): GeneralCommand
|
||||||
{
|
{
|
||||||
$general = $this->general;
|
$general = $this->general;
|
||||||
@@ -1645,6 +2011,9 @@ class GeneralAI
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$userGenerals = [];
|
$userGenerals = [];
|
||||||
|
$userCivilGenerals = [];
|
||||||
|
$userWarGenerals = [];
|
||||||
|
|
||||||
$lostGenerals = [];
|
$lostGenerals = [];
|
||||||
$npcCivilGenerals = [];
|
$npcCivilGenerals = [];
|
||||||
$npcWarGenerals = [];
|
$npcWarGenerals = [];
|
||||||
@@ -1682,6 +2051,12 @@ class GeneralAI
|
|||||||
}
|
}
|
||||||
else if($npcType < 2) {
|
else if($npcType < 2) {
|
||||||
$userGenerals[$generalID] = $nationGeneral;
|
$userGenerals[$generalID] = $nationGeneral;
|
||||||
|
if($nationGeneral->calcRecentWarTurn($this->env['turnterm']) <= 12){
|
||||||
|
$userWarGenerals[$generalID] = $nationGeneral;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
$userCivilGenerals[$generalID] = $nationGeneral;
|
||||||
|
}
|
||||||
} else if ($nationGeneral->getLeadership() >= $this->nationPolicy->minNPCWarLeadership) {
|
} else if ($nationGeneral->getLeadership() >= $this->nationPolicy->minNPCWarLeadership) {
|
||||||
$npcWarGenerals[$generalID] = $nationGeneral;
|
$npcWarGenerals[$generalID] = $nationGeneral;
|
||||||
} else {
|
} else {
|
||||||
@@ -1690,6 +2065,8 @@ class GeneralAI
|
|||||||
}
|
}
|
||||||
|
|
||||||
$this->userGenerals = $userGenerals;
|
$this->userGenerals = $userGenerals;
|
||||||
|
$this->userCivilGenerals = $userCivilGenerals;
|
||||||
|
$this->userWarGenerals = $userWarGenerals;
|
||||||
$this->lostGenerals = $lostGenerals;
|
$this->lostGenerals = $lostGenerals;
|
||||||
$this->npcCivilGenerals = $npcCivilGenerals;
|
$this->npcCivilGenerals = $npcCivilGenerals;
|
||||||
$this->npcWarGenerals = $npcWarGenerals;
|
$this->npcWarGenerals = $npcWarGenerals;
|
||||||
@@ -1808,129 +2185,6 @@ class GeneralAI
|
|||||||
return $this->do중립($reservedCommand);
|
return $this->do중립($reservedCommand);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function chooseDevelopTurn(bool &$cityFull): array
|
|
||||||
{
|
|
||||||
$general = $this->general;
|
|
||||||
$city = $this->city;
|
|
||||||
$nation = $this->nation;
|
|
||||||
$env = $this->env;
|
|
||||||
|
|
||||||
$genType = $this->genType;
|
|
||||||
$leadership = $this->leadership;
|
|
||||||
$strength = $this->strength;
|
|
||||||
$intel = $this->intel;
|
|
||||||
|
|
||||||
$cityFull = false;
|
|
||||||
|
|
||||||
$develRate = [
|
|
||||||
'trust' => $city['trust'],
|
|
||||||
'pop' => $city['pop'] / $city['pop_max'],
|
|
||||||
'agri' => $city['agri'] / $city['agri_max'],
|
|
||||||
'comm' => $city['comm'] / $city['comm_max'],
|
|
||||||
'secu' => $city['secu'] / $city['secu_max'],
|
|
||||||
'def' => $city['def'] / $city['def_max'],
|
|
||||||
'wall' => $city['wall'] / $city['wall_max'],
|
|
||||||
];
|
|
||||||
|
|
||||||
// 우선 선정
|
|
||||||
if ($develRate['trust'] < 1 && Util::randBool($leadership / 60)) {
|
|
||||||
return ['che_주민선정', null];
|
|
||||||
}
|
|
||||||
|
|
||||||
$commandList = [];
|
|
||||||
|
|
||||||
if ($genType & self::t무장) {
|
|
||||||
if ($develRate['secu'] < 0.99) {
|
|
||||||
$commandObj = buildGeneralCommandClass('che_치안강화', $general, $env);
|
|
||||||
if ($commandObj->isRunnable()) {
|
|
||||||
$commandList['che_치안강화'] = $strength / 3;
|
|
||||||
if (in_array($city['front'], [1, 3])) {
|
|
||||||
$commandList['che_치안강화'] /= 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($develRate['def'] < 0.99) {
|
|
||||||
$commandObj = buildGeneralCommandClass('che_수비강화', $general, $env);
|
|
||||||
if ($commandObj->isRunnable()) {
|
|
||||||
$commandList['che_수비강화'] = $strength / 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($develRate['wall'] < 0.99) {
|
|
||||||
$commandObj = buildGeneralCommandClass('che_성벽보수', $general, $env);
|
|
||||||
if ($commandObj->isRunnable()) {
|
|
||||||
$commandList['che_성벽보수'] = $strength / 3;
|
|
||||||
if (in_array($city['front'], [1, 3])) {
|
|
||||||
$commandList['che_성벽보수'] /= 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($genType & self::t지장) {
|
|
||||||
if ($develRate['agri'] < 0.99) {
|
|
||||||
$commandObj = buildGeneralCommandClass('che_농지개간', $general, $env);
|
|
||||||
if ($commandObj->isRunnable()) {
|
|
||||||
$commandList['che_농지개간'] = $intel / 2;
|
|
||||||
if (in_array($city['front'], [1, 3])) {
|
|
||||||
$commandList['che_농지개간'] /= 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($develRate['comm'] < 0.99) {
|
|
||||||
$commandObj = buildGeneralCommandClass('che_상업투자', $general, $env);
|
|
||||||
if ($commandObj->isRunnable()) {
|
|
||||||
$commandList['che_상업투자'] = $intel / 2;
|
|
||||||
if (in_array($city['front'], [1, 3])) {
|
|
||||||
$commandList['che_상업투자'] /= 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!TechLimit($env['startyear'], $env['year'], $nation['tech'])) {
|
|
||||||
$commandObj = buildGeneralCommandClass('che_기술연구', $general, $env);
|
|
||||||
if ($commandObj->isRunnable()) {
|
|
||||||
if (!TechLimit($env['startyear'], $env['year'], $nation['tech'] + 1000)) {
|
|
||||||
//한등급 이상 뒤쳐져 있다면, 조금 더 열심히 하자.
|
|
||||||
$commandList['che_기술연구'] = $intel;
|
|
||||||
} else {
|
|
||||||
$commandList['che_기술연구'] = $intel / 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($genType & self::t통솔장) {
|
|
||||||
if ($develRate['trust'] < 1) {
|
|
||||||
$commandObj = buildGeneralCommandClass('che_주민선정', $general, $env);
|
|
||||||
if ($commandObj->isRunnable()) {
|
|
||||||
$commandList['che_주민선정'] = pow($leadership * 2, 1 / ($develRate['trust'] + 0.001));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($develRate['pop'] < 0.99) {
|
|
||||||
$commandObj = buildGeneralCommandClass('che_정착장려', $general, $env);
|
|
||||||
if ($commandObj->isRunnable()) {
|
|
||||||
$commandList['che_정착장려'] = $leadership / 2;
|
|
||||||
if (in_array($city['front'], [1, 3])) {
|
|
||||||
$commandList['che_정착장려'] *= 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$commandList) {
|
|
||||||
$cityFull = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
$genCount = DB::db()->queryFirstField('SELECT count(no) FROM general');
|
|
||||||
$commandList['che_인재탐색'] = 500 / $genCount * 10;
|
|
||||||
if (in_array($city['front'], [1, 3])) {
|
|
||||||
$commandList['che_인재탐색'] /= 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
$commandList['che_물자조달'] = (
|
|
||||||
(GameConst::$minNationalGold + GameConst::$minNationalRice + 24 * 5 * $env['develcost']) /
|
|
||||||
Util::valueFit($nation['gold'] + $nation['rice'], (GameConst::$defaultGold + GameConst::$defaultRice) / 2));
|
|
||||||
|
|
||||||
return [Util::choiceRandomUsingWeight($commandList), null];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function old_chooseNationTurn($command, $arg): array
|
public function old_chooseNationTurn($command, $arg): array
|
||||||
{
|
{
|
||||||
$generalObj = $this->getGeneralObj();
|
$generalObj = $this->getGeneralObj();
|
||||||
@@ -2522,52 +2776,6 @@ class GeneralAI
|
|||||||
return [$command, $arg];
|
return [$command, $arg];
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function chooseEndOfNPCTurn(): array
|
|
||||||
{
|
|
||||||
$general = $this->getGeneralObj();
|
|
||||||
$city = $this->city;
|
|
||||||
$nation = $this->nation;
|
|
||||||
|
|
||||||
if ($general->getVar('gold') + $general->getVar('rice') == 0) {
|
|
||||||
return ['che_물자조달', null];
|
|
||||||
}
|
|
||||||
|
|
||||||
[$baseArmGold, $baseArmRice] = $this->getBaseArmCost();
|
|
||||||
|
|
||||||
if (
|
|
||||||
$this->dipState == self::d전쟁 &&
|
|
||||||
$general->getVar('killturn') > 2 &&
|
|
||||||
$general->getVar('gold') >= $baseArmGold / 3 &&
|
|
||||||
$general->getVar('rice') >= $baseArmRice &&
|
|
||||||
$general->getVar('crew') >= $general->getLeadership(false) / 3
|
|
||||||
) {
|
|
||||||
//사망 직전 마지막 불꽃
|
|
||||||
$trainAndAtmos = $general->getVar('train') + $general->getVar('atmos');
|
|
||||||
if (
|
|
||||||
$trainAndAtmos >= 180 &&
|
|
||||||
$city['front'] >= 2 &&
|
|
||||||
$general->getVar('rice') >= $baseArmRice &&
|
|
||||||
$nation['war'] == 0
|
|
||||||
) {
|
|
||||||
return $this->processAttack();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (180 >= $trainAndAtmos && $trainAndAtmos >= 160) {
|
|
||||||
if ($general->getVar('train') < 80) {
|
|
||||||
return ['che_훈련', null];
|
|
||||||
} else {
|
|
||||||
return ['che_사기진작', null];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($general->getVar('gold') >= $general->getVar('rice')) {
|
|
||||||
return ['che_헌납', ['isGold' => true, 'amount' => GameConst::$maxResourceActionAmount]];
|
|
||||||
} else {
|
|
||||||
return ['che_헌납', ['isGold' => false, 'amount' => GameConst::$maxResourceActionAmount]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function old_chooseGeneralTurn($command, $arg): array
|
public function old_chooseGeneralTurn($command, $arg): array
|
||||||
{
|
{
|
||||||
$general = $this->getGeneralObj();
|
$general = $this->getGeneralObj();
|
||||||
|
|||||||
Reference in New Issue
Block a user