Files
core/hwe/sammo/Scenario.php
T

576 lines
17 KiB
PHP

<?php
namespace sammo;
class Scenario{
const SCENARIO_PATH = __dir__.'/../scenario';
private $scenarioIdx;
private $scenarioPath;
private $iconPath = '.';
private $data;
private $year;
private $title;
private $history;
private $nations;
private $nationsInv;
private $diplomacy;
private $generals;
private $generalsEx;
private $generalsNeutral;
private $tmpGeneralQueue = [];
private $initialEvents;
private $events;
private $initOK = false;
private $gameConf = null;
private function initFull(){
if($this->initOK){
return;
}
$this->initOK = true;
$data = $this->data;
$neutralNation = new Scenario\Nation(0, '재야', '#000000', 0, 0);
$this->nations = [];
$this->nations[0] = $neutralNation;
$this->nationsInv = [$neutralNation->getName() => $neutralNation];
foreach (Util::array_get($data['nation'],[]) as $idx=>$rawNation) {
list($name, $color, $gold, $rice, $infoText, $tech, $type, $nationLevel, $cities) = $rawNation;
$nationID = $idx+1;
$nation = new Scenario\Nation(
$nationID,
$name,
$color,
$gold,
$rice,
$infoText,
$tech,
$type,
$nationLevel,
$cities
);
$this->nations[$nationID] = $nation;
$this->nationsInv[$nation->getName()] = $nation;
}
$this->diplomacy = Util::array_get($data['diplomacy'], []);
$this->generals = array_map(function($rawGeneral){
while(count($rawGeneral) < 14){
$rawGeneral[] = null;
}
list(
$affinity, $name, $picturePath, $nationName, $locatedCity,
$leadership, $power, $intel, $level, $birth, $death, $ego,
$char, $text
) = $rawGeneral;
if(key_exists($nationName, $this->nationsInv)){
$nationID = $this->nationsInv[$nationName]->getID();
}
else if(key_exists($nationName, $this->nations)){
$nationID = (int)$nationName;
}
else{
$nationID = 0;
}
$this->tmpGeneralQueue[$name] = $rawGeneral;
return new Scenario\NPC(
$affinity,
$name,
$picturePath,
$nationID,
$locatedCity,
$leadership,
$power,
$intel,
$level,
$birth,
$death,
$ego,
$char,
$text
);
}, Util::array_get($data['general'], []));
$this->generalsEx = array_map(function($rawGeneral){
while(count($rawGeneral) < 14){
$rawGeneral[] = null;
}
list(
$affinity, $name, $picturePath, $nationName, $locatedCity,
$leadership, $power, $intel, $level, $birth, $death, $ego,
$char, $text
) = $rawGeneral;
if(key_exists($nationName, $this->nationsInv)){
$nationID = $this->nationsInv[$nationName]->id;;
}
else if(key_exists($nationName, $this->nations)){
$nationID = (int)$nationName;
}
else{
$nationID = 0;
}
$this->tmpGeneralQueue[$name] = $rawGeneral;
return new Scenario\NPC(
$affinity,
$name,
$picturePath,
$nationID,
$locatedCity,
$leadership,
$power,
$intel,
$level,
$birth,
$death,
$ego,
$char,
$text
);
}, Util::array_get($data['general_ex'], []));
$this->generalsNeutral = array_map(function($rawGeneral){
while(count($rawGeneral) < 14){
$rawGeneral[] = null;
}
list(
$affinity, $name, $picturePath, $nationName, $locatedCity,
$leadership, $power, $intel, $level, $birth, $death, $ego,
$char, $text
) = $rawGeneral;
if(key_exists($nationName, $this->nationsInv)){
$nationID = $this->nationsInv[$nationName]->id;;
}
else if(key_exists($nationName, $this->nations)){
$nationID = (int)$nationName;
}
else{
$nationID = 0;
}
$this->tmpGeneralQueue[$name] = $rawGeneral;
$npc = new Scenario\NPC(
$affinity,
$name,
$picturePath,
$nationID,
$locatedCity,
$leadership,
$power,
$intel,
$level,
$birth,
$death,
$ego,
$char,
$text
);
$npc->npc = 6;
return $npc;
}, Util::array_get($data['general_neutral'], []));
$this->initialEvents = array_map(function($rawEvent){
$cond = $rawEvent[0];
$action = array_slice($rawEvent, 1);
return new \sammo\Event\EventHandler($cond, $action);
}, Util::array_get($data['initialEvents'], []));
$this->events = array_map(function($rawEvent){
//event는 여기서 풀지 않는다. 평가만 한다.
$cond = $rawEvent[0];
$action = array_slice($rawEvent, 1);
new \sammo\Event\EventHandler($cond, $action);
return [
'cond' => $cond,
'action' => $action
];
}, Util::array_get($data['events'], []));
}
public function getGameConf(){
if($this->gameConf){
return $this->gameConf;
}
$defaultPath = self::SCENARIO_PATH."/default.json";
if(!file_exists($defaultPath)){
throw new \RuntimeException('기본 시나리오 설정 파일 없음!');
}
$default = Json::decode(file_get_contents($defaultPath));
$stat = [
'defaultStatTotal'=>$this->data['stat']['total']??$default['stat']['total'],
'defaultStatMin'=>$this->data['stat']['min']??$default['stat']['min'],
'defaultStatMax'=>$this->data['stat']['max']??$default['stat']['max'],
'defaultStatNPCMax'=>$this->data['stat']['npcMax']??$default['stat']['npcMax'],
'chiefStatMin'=>$this->data['stat']['chiefMin']??$default['stat']['chiefMin'],
];
$this->gameConf = array_merge($stat, $this->data['map']??[], $this->data['const']??[]);
$this->iconPath = $this->data['iconPath']??$default['iconPath'];
$this->gameConf['mapName'] = $this->gameConf['mapName']??'che';
$this->gameConf['unitSet'] = $this->gameConf['unitSet']??'che';
return $this->gameConf;
}
public function __construct(int $scenarioIdx, bool $lazyInit = true){
$scenarioPath = self::SCENARIO_PATH."/scenario_{$scenarioIdx}.json";
$this->scenarioIdx = $scenarioIdx;
$this->scenarioPath = $scenarioPath;
$data = Json::decode(file_get_contents($scenarioPath));
$this->data = $data;
$this->getGameConf();
$this->year = Util::array_get($data['startYear']);
$this->title = Util::array_get($data['title'] , '');
$this->history = Util::array_get($data['history'], []);
if(!$lazyInit){
$this->initFull();
}
}
public function getScenarioIdx(){
return $this->scenarioIdx;
}
public function getYear(){
return $this->year;
}
public function getTitle(){
return $this->title;
}
public function getIconPath(){
return $this->iconPath;
}
public function getNPC(){
$this->initFull();
return $this->generals;
}
public function getNPCex(){
$this->initFull();
return $this->generalsEx;
}
public function getNPCneutral(){
$this->initFull();
return $this->generalsNeutral;
}
public function getNation(){
$this->initFull();
return $this->nations;
}
public function getMapTheme(){
return $this->gameConf['mapName'];
}
public function getUnitSet(){
return $this->gameConf['unitSet'];
}
public function getScenarioBrief(){
$this->initFull();
$nations = [];
$nationGeneralCnt = [];
$nationGeneralExCnt = [];
$nationGeneralNeutralCnt = [];
foreach($this->generals as $general){
$nationID = $general->nationID;
if(!key_exists($nationID, $nationGeneralCnt)){
$nationGeneralCnt[$nationID] = 1;
}
else{
$nationGeneralCnt[$nationID] += 1;
}
}
foreach($this->generalsEx as $general){
$nationID = $general->nationID;
if(!key_exists($nationID, $nationGeneralExCnt)){
$nationGeneralExCnt[$nationID] = 1;
}
else{
$nationGeneralExCnt[$nationID] += 1;
}
}
foreach($this->generalsNeutral as $general){
$nationID = $general->nationID;
if(!key_exists($nationID, $nationGeneralNeutralCnt)){
$nationGeneralNeutralCnt[$nationID] = 1;
}
else{
$nationGeneralNeutralCnt[$nationID] += 1;
}
}
return [
'year'=>$this->getYear(),
'title'=>$this->getTitle(),
'npc_cnt'=>count($this->getNPC()),
'npcEx_cnt'=>count($this->getNPCex()),
'npcNeutral_cnt'=>count($this->getNPCneutral()),
'nation'=>array_map(function($nation) use ($nationGeneralCnt, $nationGeneralExCnt){
$brief = $nation->getBrief();
$brief['generals'] = Util::array_get($nationGeneralCnt[$nation->getID()], 0);
$brief['generalsEx'] = Util::array_get($nationGeneralExCnt[$nation->getID()], 0);
$brief['generalsNeutral'] = Util::array_get($nationGeneralNeutralCnt[$nation->getID()], 0);
return $brief;
},$this->getNation())
];
}
private function buildGenerals($env){
$this->initFull();
try{
$text = \file_get_contents(ServConfig::getSharedIconPath('../hook/list.json?1'));
$storedIcons = Json::decode($text);
}
catch(\Exception $e){
$storedIcons = [];
}
$env['stored_icons'] = $storedIcons;
$remainGenerals = [];
foreach($this->generals as $general){
if($general->build($env)){
if($general->nationID){
$this->nations[$general->nationID]->addGeneral($general);
}
continue;
}
$rawGeneral = $this->tmpGeneralQueue[$general->name];
$birth = $general->birth;
if(!key_exists($birth, $remainGenerals)){
$remainGenerals[$birth] = [];
}
$remainGenerals[$birth][] = array_merge(['RegNPC'], $rawGeneral);
}
if($env['extended_general']){
foreach($this->generalsEx as $general){
if($general->build($env)){
if($general->nationID){
$this->nations[$general->nationID]->addGeneral($general);
}
continue;
}
$rawGeneral = $this->tmpGeneralQueue[$general->name];
$birth = $general->birth;
if(!key_exists($birth, $remainGenerals)){
$remainGenerals[$birth] = [];
}
$remainGenerals[$birth][] = array_merge(['RegNPC'], $rawGeneral);
}
}
foreach($this->generalsNeutral as $general){
if($general->build($env)){
if($general->nationID){
$this->nations[$general->nationID]->addGeneral($general);
}
continue;
}
$rawGeneral = $this->tmpGeneralQueue[$general->name];
$birth = $general->birth;
if(!key_exists($birth, $remainGenerals)){
$remainGenerals[$birth] = [];
}
$remainGenerals[$birth][] = array_merge(['RegNeutralNPC'], $rawGeneral);
}
return $remainGenerals;
}
private function buildDiplomacy($env){
$this->initFull();
$monthDiff = ($env['year'] * 12) + ($env['month'] - 1) - ($env['startyear'] * 12);
$db = DB::db();
foreach($this->diplomacy as $diplomacy){
list($me, $you, $state, $remain) = $diplomacy;
$db->update('diplomacy', [
'state'=>$state,
'term'=>$remain - $monthDiff
], '(me = %i AND you = %i) OR (me = %i AND you = %i)', $me, $you, $you, $me);
}
}
public function buildConf(){
$path = __dir__.'/../d_setting';
$mapPath = __dir__.'/../scenario/map';
$unitPath = __dir__.'/../scenario/unit';
$mapName = $this->gameConf['mapName'];
$unitSet = $this->gameConf['unitSet'];
if(!file_exists("$mapPath/$mapName.php")){
throw new \RuntimeException('맵 파일이 올바르게 지정되지 않음! : '.$mapName);
}
if(!file_exists("$unitPath/$unitSet.php")){
throw new \RuntimeException('유닛 파일이 올바르게 지정되지 않음! : '.$unitSet);
}
Util::generatePHPClassFile($path.'/GameConst.php', $this->gameConf, 'GameConstBase', 'sammo');
copy("$mapPath/$mapName.php", $path.'/CityConst.php');
copy("$unitPath/$unitSet.php", $path.'/GameUnitConst.php');
}
public function build($env=[]){
$this->initFull();
//NOTE: 초기화가 되어있다고 가정함.
/*
env로 사용된 것들,
게임 변수 : year, month
gameStor 변수 : startyear, year, month, genius, turnterm, show_img_level, extended_general, fiction, npcmode
install 변수 : npcmode, show_img_level, extended_general, scenario, fiction
event변수 : currentEventID
*/
$db = DB::db();
foreach($this->nations as $id=>$nation){
if($id == 0){
continue;
}
$nation->build($env);
}
refreshNationStaticInfo();
CityHelper::flushCache();
$remainGenerals = $this->buildGenerals($env);
foreach($remainGenerals as $birth=>$actions){
$targetYear = $birth + \sammo\GameConst::$adultAge;
$actions[] = ['DeleteEvent'];
$this->events[] = [
'cond'=>['Date', '>=', $targetYear, '1'],
'action'=>$actions
];
}
foreach($this->nations as $id=>$nation){
if($id == 0){
continue;
}
$nation->postBuild($env);
}
$this->buildDiplomacy($env);
foreach($this->initialEvents as $event){
$event->tryRunEvent($env);
}
$events = array_map(function($rawEvent){
return [
'condition'=>Json::encode($rawEvent['cond']),
'action'=>Json::encode($rawEvent['action'])
];
}, $this->events);
if(count($events) > 0){
$db->insert('event', $events);
}
pushWorldHistory($this->history, $env['year'], $env['month']);
refreshNationStaticInfo();
foreach(getAllNationStaticInfo() as $nation){
SetNationFront($nation['nation']);
}
}
/**
* @return \sammo\Scenario[]
*/
public static function getAllScenarios(){
$result = [];
foreach(glob(self::SCENARIO_PATH.'/scenario_*.json') as $scenarioPath){
$scenarioName = pathinfo(basename($scenarioPath), PATHINFO_FILENAME);
$scenarioIdx = Util::array_last(explode('_', $scenarioName));
if(!is_numeric($scenarioIdx)){
continue;
}
$scenarioIdx = Util::toInt($scenarioIdx);
if($scenarioIdx === null){
continue;
}
$result[$scenarioIdx] = new Scenario($scenarioIdx);
}
return $result;
}
}