npc 처리용 새 클래스 준비중

This commit is contained in:
2018-10-06 01:52:14 +09:00
parent f7b59f0140
commit b94081c45b
3 changed files with 126 additions and 81 deletions
+78 -73
View File
@@ -1,15 +1,14 @@
<?php
namespace sammo;
function SetDevelop($genType, $no, $city, $tech) {
function SetDevelop(General $generalObj, $genType, $city, $tech):array{
$db = DB::db();
$city = $db->queryFirstRow("SELECT trust,pop/pop2*100 as po,comm/comm2*100 as co,def/def2*100 as de,wall/wall2*100 as wa,secu/secu2*100 as se,agri/agri2*100 as ag from city where city=%i", $city);
// 우선 선정
if($city['trust'] < 95) {
setGeneralCommand($no, [0], 'che_선정');
return;
return ['che_선정', null];
}
$prob = rand() % 100;
@@ -52,7 +51,14 @@ function SetDevelop($genType, $no, $city, $tech) {
elseif($city['po'] < 99) { $command = 'che_정착장려'; } //정장
else { $command = 'che_물자조달'; } //조달
} else {
if($tech < GameConst::$maxTechLevel * 1000) { $command = EncodeCommand(0, 0, 0, 3 + (rand() % 2) * 6); } //기술, 조달
if($tech < GameConst::$maxTechLevel * 1000) {
if(Util::randBool()){
$command = 'che_기술연구';
}
else{
$command = 'che_물자조달';
}
} //기술, 조달
else { $command = 'che_인재탐색'; }
}
break;
@@ -68,13 +74,19 @@ function SetDevelop($genType, $no, $city, $tech) {
$command = 'che_물자조달';
}
}
setGeneralCommand($no, [0], $command);
return;
return [$command, $arg];
}
function SetCrew($no, $nationID, $personal, $gold, $leader, $genType, $tech, $dex0, $dex10, $dex20, $dex30, $dex40) {
function SetCrew(General $generalObj, $genType):array{
$db = DB::db();
$connect=$db->get();
$raw = $generalObj->getRaw();
[$no, $nationID, $personal, $gold, $leader, $tech, $dex0, $dex10, $dex20, $dex30, $dex40] = [
$raw['no'], $raw['nation'], $raw['personal'], $raw['gold'], $raw['leader'], $nation['tech'],
$raw['dex0'], $raw['dex10'], $raw['dex20'], $raw['dex30'], $raw['dex40']
];
$cities = [];
$regions = [];
@@ -164,14 +176,30 @@ function SetCrew($no, $nationID, $personal, $gold, $leader, $genType, $tech, $de
$crew = intdiv($gold, $cost);
if($leader < $crew) { $crew = $leader; }
$command = EncodeCommand(0, $type, $crew, 11);
$query = "update general set turn0='$command' where no='$no'";
MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
return;
$arg = [
'crewType'=>$type,
'amountCrew'=>$crew
];
return ['che_징병', $arg];
}
function processAI($no) {
function processAINationTurn(General $generalObj, $command, $arg):array{
$nation = $db->queryFirstRow(
'SELECT nation,level,tech,gold,rice,rate,type,color,name,war FROM nation WHERE nation = %i',
$generalObj->getNationID()
)??[
'nation'=>0,
'level'=>0,
'tech'=>0,
'gold'=>0,
'rice'=>0,
'type'=>GameConst::$neutralNationType,
'color'=>'#000000',
'name'=>'재야',
];
}
function processAI(General $generalObj, $command, $arg):array{
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$connect=$db->get();
@@ -184,59 +212,40 @@ function processAI($no) {
$isStart = 0;
}
$query = "select no,turn0,npcid,name,nation,nations,city,level,npcmsg,personal,leader,intel,power,gold,rice,crew,train,atmos,troop,npc,affinity,mode,injury,picture,imgsvr,killturn,makelimit,dex0,dex10,dex20,dex30,dex40 from general where no='$no'";
$result = MYDB_query($query, $connect) or Error("processAI01 ".MYDB_error($connect),"");
$general = MYDB_fetch_array($result);
$generalID = $general['no'];
[$command, $arg] = $db->queryFirstList('SELECT action, arg FROM general_turn WHERE general_id = %i AND turn_idx=0');
$command = 'che_물자조달';
$arg = null;
$general = $generalObj->getRaw();
$generalID = $generalObj->getID();
if($general['npc'] == 5){
if($general['nation'] == 0 && $general['killturn'] > 1){
$command = 'che_휴식'; //휴식
$db->update('general', [
'killturn'=>1
], 'no=%i', $generalID);
$arg = [];
$generalObj->setVar('killturn', 1);
}
else{
$command = 'che_집합'; //집합
$db->update('general', [
'turn0'=>$command,
'turn1'=>$command,
'turn2'=>$command,
'turn3'=>$command,
'turn4'=>$command,
'turn5'=>$command,
'killturn'=>rand(70,75),
], 'no=%i', $generalID);
$arg = [];
$generalObj->setVar('killturn', rand(70,75));
//NOTE: 부대 편성에 보여야 하므로 이것만 DB에 직접 접근함.
$db->update('general_turn', [
'action'=>'che_집합',
'arg'=>'{}'
], 'general_ID=%i AND turn_idx < 6', $generalID);
}
return;
return [$command, $arg];
}
// 입력된 턴이 있으면 그것 실행
if(DecodeCommand($general['turn0'])[0] != 0) {
return;
if($command && $command != '휴식') {
return [$command, $arg];
}
$query = "select city,region,nation,level,path,trust,gen1,gen2,gen3,pop,supply,front from city where city='{$general['city']}'";
$result = MYDB_query($query, $connect) or Error("processAI02 ".MYDB_error($connect),"");
$city = MYDB_fetch_array($result);
$command = 'che_물자조달';
$arg = [];
$query = "select nation,level,tech,gold,rice,rate,type,color,name,war from nation where nation='{$general['nation']}'";
$result = MYDB_query($query, $connect) or Error("processAI03 ".MYDB_error($connect),"");
$nation = MYDB_fetch_array($result)??[
'nation'=>0,
'color'=>'#000000',
'name'=>'재야',
'level'=>0,
'gold'=>0,
'rice'=>0,
'tech'=>0,
];
$city = $generalObj->getRawCity();
$nation = $generalObj->getStaticNation();
$coreCommand = array();
if($general['level'] >= 5) {
@@ -533,7 +542,7 @@ function processAI($no) {
}
}
$command = 'che_농지개간';
$command = '<내정>';
//일반 할일
if($general['killturn'] < 5) {
if($general['gold'] + $general['rice'] == 0) {
@@ -632,11 +641,11 @@ function processAI($no) {
elseif($general['gold'] < 100) { //금없으면 쌀팜
$amount = intdiv(($general['rice'] - $general['gold'])/2, 100); // 100단위
$command = EncodeCommand(0, 1, $amount, 49); //팜
} elseif($general['gold'] < 500 && $general['rice'] < 500) { $command = 'che_농지개간'; } //금쌀되면 내정
} elseif($general['gold'] < 500 && $general['rice'] < 500) { $command = '<내정>'; } //금쌀되면 내정
elseif($general['rice'] < 100) { //쌀없으면 쌀삼
$amount = intdiv(($general['gold'] - $general['rice'])/2, 100); // 100단위
$command = EncodeCommand(0, 2, $amount, 49); //삼
} elseif($genType >= 2) { $command = 'che_농지개간'; } //내정장일때 내정
} elseif($genType >= 2) { $command = '<내정>'; } //내정장일때 내정
else {
//현도시가 전방이면 공격 가능성 체크
if($city['front'] > 0) {
@@ -649,14 +658,14 @@ function processAI($no) {
//공백지이면 타겟에 포함
if($targetCity['nation'] == 0) { $target[] = $targetCity['city']; }
}
if(count($target) == 0 || $isStart == 1 || $nation['war'] == 1) { $command = 'che_농지개간'; } //공격 가능도시가 없으면 내정
if(count($target) == 0 || $isStart == 1 || $nation['war'] == 1) { $command = '<내정>'; } //공격 가능도시가 없으면 내정
else { $command = EncodeCommand(0, 0, $target[rand()%count($target)], 16); } //있으면 공격
} else {
//전방 아니면 내정
$command = 'che_농지개간';
$command = '<내정>';
}
if($command == 'che_농지개간') { // 공격아닌 경우
if($command == '<내정>') { // 공격아닌 경우
$query = "select city,(pop/10+agri+comm+secu+def+wall)/(pop2/10+agri2+comm2+secu2+def2+wall2)*100 as dev from city where city='{$general['city']}'";
$result = MYDB_query($query, $connect) or Error("processAI19 ".MYDB_error($connect),"");
$selCity = MYDB_fetch_array($result);
@@ -666,7 +675,7 @@ function processAI($no) {
elseif($selCity['dev'] < 70) { $sel = 0; }
switch($sel) {
case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: // 그대로 내정 80 %
$command = 'che_농지개간';
$command = '<내정>';
break;
case 8: case 9: // 저개발 도시로 워프 20%
//도시 선택, 30% 확률로 군사 있는 곳으로 워프
@@ -679,7 +688,7 @@ function processAI($no) {
$selCity = MYDB_fetch_array($result);
//이미 그 도시이거나, 그 도시도 고개발이면 내정
if($selCity['city'] == $general['city'] || $selCity['dev'] > 95) {
$command = 'che_농지개간';
$command = '<내정>';
} else {
//워프
$query = "update general set city='{$selCity['city']}' where no='{$generalID}'";
@@ -706,8 +715,8 @@ function processAI($no) {
} else { // 공격인 경우
if($general['crew'] < 1000 && $general['gold'] >= $resrc && $general['rice'] >= $resrc) { //자원되고, 병사없을때
if($city['pop'] > 40000) { $command = 'che_징병'; }
else { $command = 'che_농지개간'; }
if($city['pop'] > 40000) { $command = '<징병>'; }
else { $command = '<내정>'; }
} elseif($general['rice'] < $resrc && $general['rice'] <= $general['gold']) {
//금이 더 많으면 매매
$amount = intdiv(($general['gold'] - $general['rice']) / 2, 100); // 100단위
@@ -751,7 +760,7 @@ function processAI($no) {
$amount = intdiv(($general['gold'] - $general['rice'])/2, 100); // 100단위
if($amount > 0) { $command = EncodeCommand(0, 2, $amount, 49); }// 팜
else { $command = 'che_물자조달'; } // 조달
} elseif($genType >= 2) { $command = 'che_농지개간'; } //내정장일때 내정
} elseif($genType >= 2) { $command = '<내정>'; } //내정장일때 내정
elseif($general['crew'] < 1000 && $general['gold'] >= $resrc && $general['rice'] >= $resrc) {
$query = "select no from general where nation='{$general['nation']}'";
$result = MYDB_query($query, $connect) or Error("processAI16 ".MYDB_error($connect),"");
@@ -771,7 +780,7 @@ function processAI($no) {
$ratio3 = rand() % 100;
// 전체 인구 대비 확률로 현지에서 징병
if($city['pop'] > 40000 && 100 + $ratio - $ratio2 > $ratio3) {
$command = 'che_징병'; //인구 되면 징병
$command = '<징병>'; //인구 되면 징병
} else {
// 인구 안되면 4만 이상인 도시로 워프
$query = "select city from city where nation='{$general['nation']}' and pop>40000 and supply='1' order by rand() limit 0,1";
@@ -865,16 +874,12 @@ function processAI($no) {
}
switch($command) {
case 'che_농지개간': //내정
SetDevelop($genType, $generalID, $general['city'], $nation['tech']);
return;
case 'che_징병': //징병
SetCrew($generalID, $general['nation'], $general['personal'], $general['gold'], $general['leader'], $genType, $nation['tech'], $general['dex0'], $general['dex10'], $general['dex20'], $general['dex30'], $general['dex40']);
return;
case '<내정>': //내정
return SetDevelop($generalObj, $genType);
case '<징병>': //징병
return SetCrew($generalObj, $genType);
default:
$query = "update general set turn0='$command' where no='{$generalID}'";
MYDB_query($query, $connect) or Error("processAI23 ".MYDB_error($connect),"");
return;
return [$command, $arg];
}
}
+27
View File
@@ -0,0 +1,27 @@
<?php
namespace sammo;
class GeneralAI{
protected $general;
protected $nation;
protected $dipState;
protected $genType;
protected $env;
public function __construct(General $general){
$db = DB::db();
$this->general = $general;
if($general->getRawCity() === null){
$general->setRawCity($db->queryFirstRow('SELECT * FROM city WHERE city = %i', $general->getCityID()));
}
}
public function chooseNationTurn($nationCommand, $nationArg):array{
}
public function chooseGeneralTurn($generalCommand, $generalArg):array{
}
}
+21 -8
View File
@@ -192,8 +192,8 @@ class TurnExecutionHelper
leader,leader2,power,power2,intel,intel2,weap,book,horse,item,
experience,dedication,level,gold,rice,crew,crewtype,train,atmos,
turntime,makenation,makelimit,killturn,block,dedlevel,explevel,
age,belong,personal,special,special2,term,
npc,npc_org,npcid,deadyear,
age,belong,personal,special,special2,term,mode,
npc,npc_org,npcid,deadyear,npcmsg,
dex0,dex10,dex20,dex30,dex40,
warnum,killnum,deathnum,killcrew,deathcrew,recwar,last_turn
general_turn.`action` AS `action`, general_turn.arg AS arg
@@ -215,9 +215,7 @@ WHERE turntime < %s ORDER BY turntime ASC, `no` ASC',
unset($generalWork['action']);
unset($generalWork['arg']);
if($generalWork['npc'] >= 2){
processAI($generalID); // npc AI 처리
}
$turnObj = new static($generalWork, $year, $month);
$hasNationTurn = false;
if($generalWork['nation'] != 0 && $generalWork['level'] >= 5){
@@ -231,15 +229,30 @@ WHERE turntime < %s ORDER BY turntime ASC, `no` ASC',
$generalWork['level']
))??[];
$hasNationTurn = true;
$nationCommand = $rawNationTurn['action'];
$nationArg = Json::decode($rawNationTurn['arg']);
}
$turnObj = new static($generalWork, $year, $month);
if($generalWork['npc'] >= 2){
$ai = new GeneralAI($turnObj->getGeneral());
if($hasNationTurn){
[$nationCommand, $nationArg] = $ai->chooseNationTurn($generalObj, $nationCommand, $nationArg);
}
if($hasNationTurn){
[$nationCommand, $nationArg] = processAINationTurn($nationCommand, $nationArg);
}
[$generalCommand, $generalArg] = $ai->chooseGeneralTurn($generalCommand, $generalArg); // npc AI 처리
}
if(!$turnObj->processBlocked()){
$turnObj->preprocessCommand();
if($hasNationTurn){
$resultNationTurn = $turnObj->processNationCommand(
$rawNationTurn['action'],
Json::decode($rawNationTurn['arg']),
$nationCommand,
$nationArg,
$lastNationTurn
);
$nationStor->setValue($lastNationTurnKey, $resultNationTurn->toJson());