파일 위치를 twe에서 hwe로 옮김.
This commit is contained in:
@@ -0,0 +1 @@
|
||||
Deny from all
|
||||
@@ -0,0 +1,343 @@
|
||||
<?php
|
||||
namespace sammo;
|
||||
|
||||
class CityConst{
|
||||
private function __construct(){
|
||||
|
||||
}
|
||||
|
||||
private static $constID = null;
|
||||
private static $constName = null;
|
||||
private static $constRegion = null;
|
||||
|
||||
|
||||
public static $regionMap = [
|
||||
'하북'=>1,1=>'하북',
|
||||
'중원'=>2,2=>'중원',
|
||||
'서북'=>3,3=>'서북',
|
||||
'서촉'=>4,4=>'서촉',
|
||||
'남중'=>5,5=>'남중',
|
||||
'초'=>6,6=>'초',
|
||||
'오월'=>7,7=>'오월',
|
||||
'동이'=>8,8=>'동이'
|
||||
];
|
||||
|
||||
public static $levelMap = [
|
||||
'수'=>1,1=>'수',
|
||||
'진'=>2,2=>'진',
|
||||
'관'=>3,3=>'관',
|
||||
'이'=>4,4=>'이',
|
||||
'소'=>5,5=>'소',
|
||||
'중'=>6,6=>'중',
|
||||
'대'=>7,7=>'대',
|
||||
'특'=>8,8=>'특'
|
||||
];
|
||||
|
||||
/**
|
||||
* @return \sammo\CityInitialDetail[]
|
||||
*/
|
||||
public static function all(){
|
||||
static::_generate();
|
||||
return static::$constID;
|
||||
}
|
||||
public static function byID(int $id): CityInitialDetail{
|
||||
static::_generate();
|
||||
return static::$constID[$id];
|
||||
}
|
||||
|
||||
public static function byName(string $name): CityInitialDetail{
|
||||
static::_generate();
|
||||
return static::$constName[$name];
|
||||
}
|
||||
|
||||
public static function byRegion(int $region): CityInitialDetail{
|
||||
static::_generate();
|
||||
return static::$constRegion[$region];
|
||||
}
|
||||
|
||||
private static $initCity = [
|
||||
//id, 도시, 규모, 인구, 농, 상, 치, 성, 수,(x100) 지역, 연결도시
|
||||
[ 1, '업', '특', 6205, 125, 113, 100, 117, 122, '하북', ['남피', '복양', '호관', '계교', '관도']],
|
||||
[ 2, '허창', '특', 5876, 121, 124, 100, 117, 125, '중원', ['완', '진류', '초', '호로', '사수', '관도']],
|
||||
[ 3, '낙양', '특', 8357, 117, 120, 100, 121, 124, '중원', ['호관', '호로', '사곡', '사수']],
|
||||
[ 4, '장안', '특', 5923, 116, 123, 100, 120, 118, '서북', ['안정', '함곡', '기산']],
|
||||
[ 5, '성도', '특', 6525, 123, 125, 100, 125, 123, '서촉', ['덕양', '강주', '면죽']],
|
||||
[ 6, '양양', '특', 5837, 120, 126, 100, 115, 117, '초', ['신야', '장판']],
|
||||
[ 7, '건업', '특', 6386, 116, 123, 100, 115, 119, '오월', ['오', '합비', '광릉']],
|
||||
|
||||
[ 8, '북평', '대', 4862, 102, 95, 80, 103, 99, '하북', ['역경', '백랑']],
|
||||
[ 9, '남피', '대', 5032, 99, 101, 80, 101, 105, '하북', ['업', '평원', '역경']],
|
||||
[10, '완', '대', 4724, 103, 100, 80, 101, 99, '중원', ['허창', '여남', '신야', '호로']],
|
||||
[11, '수춘', '대', 5143, 99, 96, 80, 99, 95, '중원', ['서주', '여남', '초', '합비']],
|
||||
[12, '서주', '대', 4853, 101, 98, 80, 102, 97, '중원', ['수춘', '하비', '초', '패']],
|
||||
[13, '강릉', '대', 4850, 105, 96, 80, 95, 96, '초', ['장사', '무릉', '이릉', '장판']],
|
||||
[14, '장사', '대', 4710, 97, 99, 80, 100, 105, '초', ['강릉', '시상', '계양', '무릉', '영릉']],
|
||||
[15, '시상', '대', 5252, 98, 100, 100, 99, 96, '오월', ['장사', '여강', '고창', '적벽', '파양']],
|
||||
[16, '위례', '대', 4926, 100, 93, 80, 98, 103, '동이', ['평양', '사비', '계림', '안평', '동황']],
|
||||
|
||||
[17, '계', '중', 3885, 75, 80, 60, 78, 81, '하북', ['진양', '역경']],
|
||||
[18, '복양', '중', 4185, 80, 83, 60, 82, 80, '중원', ['업', '진류', '계교', '정도']],
|
||||
[19, '진류', '중', 3957, 82, 80, 60, 80, 83, '중원', ['허창', '복양', '사수', '관도', '정도']],
|
||||
[20, '여남', '중', 3831, 77, 81, 60, 84, 77, '중원', ['완', '수춘', '초']],
|
||||
[21, '하비', '중', 4278, 85, 83, 60, 82, 78, '중원', ['서주', '광릉']],
|
||||
[22, '서량', '중', 3874, 77, 79, 60, 83, 80, '서북', ['천수', '강', '저']],
|
||||
[23, '하내', '중', 3736, 77, 81, 60, 81, 80, '서북', ['진양', '홍농', '흉노', '호관']],
|
||||
[24, '한중', '중', 4027, 77, 84, 60, 80, 85, '서촉', ['상용', '양평', '기산']],
|
||||
[25, '상용', '중', 3687, 78, 76, 60, 77, 81, '서촉', ['한중', '신야']],
|
||||
[26, '덕양', '중', 3803, 81, 84, 60, 79, 77, '서촉', ['성도', '강주', '자동', '영안']],
|
||||
[27, '강주', '중', 4126, 79, 80, 60, 84, 81, '서촉', ['성도', '덕양', '영안', '귀양', '주시']],
|
||||
[28, '건녕', '중', 3765, 82, 80, 60, 86, 81, '남중', ['귀양', '운남', '남영']],
|
||||
[29, '남해', '중', 3803, 82, 76, 60, 80, 81, '남중', ['교지', '상동', '대', '산월']],
|
||||
[30, '계양', '중', 3955, 83, 80, 60, 81, 77, '초', ['장사', '영릉', '상동']],
|
||||
[31, '오', '중', 4355, 77, 81, 60, 77, 76, '오월', ['건업', '회계', '파양', '탐라']],
|
||||
[32, '평양', '중', 3982, 78, 80, 60, 83, 78, '동이', ['위례', '졸본']],
|
||||
[33, '사비', '중', 4157, 77, 79, 60, 78, 80, '동이', ['위례', '계림', '탐라']],
|
||||
[34, '계림', '중', 3911, 80, 74, 60, 81, 78, '동이', ['위례', '사비', '이도', '탐라']],
|
||||
|
||||
[35, '진양', '소', 3074, 56, 59, 40, 64, 59, '하북', ['계', '하내', '호관']],
|
||||
[36, '평원', '소', 3074, 62, 65, 40, 61, 63, '하북', ['남피', '북해', '계교']],
|
||||
[37, '북해', '소', 3146, 55, 63, 40, 63, 58, '하북', ['평원', '패', '동황']],
|
||||
[38, '초', '소', 3286, 60, 62, 40, 62, 57, '중원', ['허창', '수춘', '서주', '여남', '정도']],
|
||||
[39, '패', '소', 2877, 64, 58, 40, 58, 59, '중원', ['서주', '북해', '정도']],
|
||||
[40, '천수', '소', 2985, 59, 64, 40, 60, 58, '서북', ['서량', '안정', '저', '적도']],
|
||||
[41, '안정', '소', 2764, 57, 59, 40, 57, 62, '서북', ['장안', '천수', '가정']],
|
||||
[42, '홍농', '소', 2748, 57, 63, 40, 58, 63, '서북', ['하내', '사곡', '함곡']],
|
||||
[43, '하변', '소', 2785, 58, 62, 40, 60, 56, '서촉', ['가맹', '가정']],
|
||||
[44, '자동', '소', 2870, 57, 55, 40, 60, 58, '서촉', ['덕양', '양평', '가맹', '면죽']],
|
||||
[45, '영안', '소', 3153, 62, 59, 40, 58, 59, '서촉', ['덕양', '강주', '이릉']],
|
||||
[46, '귀양', '소', 2746, 58, 61, 40, 61, 58, '남중', ['강주', '건녕', '주시']],
|
||||
[47, '주시', '소', 2828, 60, 59, 40, 58, 63, '남중', ['강주', '귀양', '운남']],
|
||||
[48, '운남', '소', 3258, 62, 60, 40, 64, 61, '남중', ['건녕', '주시', '남만']],
|
||||
[49, '남영', '소', 2853, 59, 62, 40, 58, 57, '남중', ['건녕', '영릉', '남만']],
|
||||
[50, '교지', '소', 3195, 58, 59, 40, 58, 59, '남중', ['남해', '남만']],
|
||||
[51, '신야', '소', 2786, 60, 62, 40, 58, 55, '초', ['양양', '완', '상용']],
|
||||
[52, '강하', '소', 3074, 55, 56, 40, 57, 60, '초', ['장판', '적벽']],
|
||||
[53, '무릉', '소', 3196, 58, 63, 40, 63, 58, '초', ['강릉', '장사', '영릉']],
|
||||
[54, '영릉', '소', 2849, 62, 58, 40, 62, 62, '초', ['장사', '계양', '남영', '무릉']],
|
||||
[55, '상동', '소', 2767, 58, 59, 40, 62, 58, '초', ['남해', '계양', '고창']],
|
||||
[56, '여강', '소', 2905, 56, 58, 40, 60, 55, '오월', ['시상', '합비', '적벽', '파양']],
|
||||
[57, '회계', '소', 3005, 64, 59, 40, 62, 64, '오월', ['오', '산월']],
|
||||
[58, '고창', '소', 2802, 57, 62, 40, 58, 63, '오월', ['시상', '상동', '산월']],
|
||||
[59, '대', '소', 3256, 60, 62, 40, 57, 60, '오월', ['남해', '산월', '유구']],
|
||||
[60, '안평', '소', 2937, 63, 59, 40, 59, 63, '동이', ['위례', '졸본', '동황', '백랑']],
|
||||
[61, '졸본', '소', 2939, 55, 59, 40, 60, 58, '동이', ['평양', '안평', '오환']],
|
||||
[62, '이도', '소', 3174, 58, 61, 40, 58, 56, '동이', ['계림', '왜', '탐라']],
|
||||
|
||||
[63, '강', '이', 2095, 40, 42, 20, 43, 40, '서북', ['서량', '적도']],
|
||||
[64, '저', '이', 1957, 40, 42, 20, 43, 42, '서북', ['서량', '천수', '가정']],
|
||||
[65, '흉노', '이', 2064, 40, 41, 20, 40, 38, '서북', ['하내', '적도']],
|
||||
[66, '남만', '이', 2378, 40, 42, 20, 43, 45, '남중', ['운남', '남영', '교지']],
|
||||
[67, '산월', '이', 2275, 40, 37, 20, 43, 38, '오월', ['남해', '회계', '고창', '대']],
|
||||
[68, '오환', '이', 2153, 42, 37, 20, 43, 40, '동이', ['졸본', '백랑']],
|
||||
[69, '왜', '이', 2065, 39, 37, 20, 43, 41, '동이', ['이도', '유구']],
|
||||
|
||||
[70, '호관', '관', 887, 19, 18, 20, 95, 96, '하북', ['업', '낙양', '하내', '진양']],
|
||||
[71, '호로', '관', 1112, 22, 21, 20, 103, 98, '중원', ['허창', '낙양', '완']],
|
||||
[72, '사곡', '관', 1008, 21, 19, 20, 99, 101, '서북', ['낙양', '홍농']],
|
||||
[73, '함곡', '관', 1081, 20, 22, 20, 101, 102, '서북', ['장안', '홍농']],
|
||||
[74, '사수', '관', 958, 17, 19, 20, 95, 96, '중원', ['허창', '낙양', '진류', '관도']],
|
||||
[75, '양평', '관', 868, 19, 19, 20, 97, 96, '서촉', ['한중', '자동', '기산']],
|
||||
[76, '가맹', '관', 855, 17, 18, 20, 96, 95, '서촉', ['하변', '자동']],
|
||||
|
||||
[77, '역경', '진', 985, 18, 19, 20, 39, 41, '하북', ['북평', '남피', '계']],
|
||||
[78, '계교', '진', 1012, 21, 19, 20, 40, 42, '하북', ['업', '복양', '평원']],
|
||||
[79, '동황', '진', 992, 19, 21, 20, 38, 40, '하북', ['위례', '북해', '안평']],
|
||||
[80, '관도', '진', 1123, 22, 20, 20, 42, 43, '중원', ['업', '허창', '진류', '사수']],
|
||||
[81, '정도', '진', 1085, 21, 21, 20, 41, 38, '중원', ['복양', '진류', '초', '패']],
|
||||
[82, '합비', '진', 998, 20, 19, 20, 39, 41, '중원', ['건업', '수춘', '여강']],
|
||||
[83, '광릉', '진', 1001, 20, 21, 20, 41, 40, '중원', ['건업', '하비']],
|
||||
[84, '적도', '진', 952, 18, 17, 20, 38, 37, '서북', ['천수', '강', '흉노']],
|
||||
[85, '가정', '진', 931, 17, 17, 20, 36, 38, '서북', ['안정', '하변', '저']],
|
||||
[86, '기산', '진', 1005, 19, 18, 20, 41, 40, '서촉', ['장안', '한중', '양평']],
|
||||
[87, '면죽', '관', 1093, 22, 21, 20, 108, 99, '서촉', ['성도', '자동']],
|
||||
[88, '이릉', '진', 968, 18, 19, 20, 39, 41, '초', ['강릉', '영안']],
|
||||
[89, '장판', '진', 1032, 21, 20, 20, 40, 37, '초', ['양양', '강릉', '강하', '적벽']],
|
||||
[90, '백랑', '진', 1052, 22, 19, 20, 38, 42, '동이', ['북평', '안평', '오환']],
|
||||
|
||||
[91, '적벽', '수', 1117, 23, 21, 20, 42, 41, '오월', ['시상', '강하', '여강', '장판']],
|
||||
[92, '파양', '수', 1037, 20, 22, 20, 38, 38, '오월', ['시상', '오', '여강']],
|
||||
[93, '탐라', '수', 1130, 22, 21, 20, 43, 41, '동이', ['오', '사비', '계림', '이도']],
|
||||
[94, '유구', '수', 921, 17, 18, 20, 37, 37, '동이', ['대', '왜']],
|
||||
];
|
||||
|
||||
private static function _generate(){
|
||||
if(static::$constID || static::$constName || static::$constRegion){
|
||||
return;
|
||||
}
|
||||
|
||||
$constID = [];
|
||||
$constName = [];
|
||||
$constCity = [];
|
||||
$constRegion = [];
|
||||
|
||||
$nameMap = [];
|
||||
|
||||
foreach (static::$initCity as $rawCity) {
|
||||
$nameMap[$rawCity[1]] = $rawCity[0];
|
||||
}
|
||||
|
||||
foreach (static::$buildInit as $key=>$val){
|
||||
$key2 = static::$levelMap[$key];
|
||||
if(key_exists($key2, static::$buildInit)){
|
||||
continue;//혹시 모를 버그 방지
|
||||
}
|
||||
|
||||
static::$buildInit[$key2] = $val;
|
||||
}
|
||||
|
||||
foreach(static::$initCity as $rawCity){
|
||||
list(
|
||||
$id,
|
||||
$name,
|
||||
$level,
|
||||
$population,
|
||||
$agriculture,
|
||||
$commerce,
|
||||
$security,
|
||||
$defence,
|
||||
$wall,
|
||||
$region,
|
||||
$path
|
||||
) = $rawCity;
|
||||
|
||||
$level = static::$levelMap[$level];
|
||||
$population *= 100;
|
||||
$agriculture *= 100;
|
||||
$commerce *= 100;
|
||||
$security *= 100;
|
||||
$defence *= 100;
|
||||
$wall *= 100;
|
||||
$region = static::$regionMap[$region];
|
||||
$newPath = [];
|
||||
foreach($path as $pathName){
|
||||
$pathID = $nameMap[$pathName];
|
||||
$newPath[$pathID] = $pathName;
|
||||
}
|
||||
|
||||
$city = new CityInitialDetail(
|
||||
$id,
|
||||
$name,
|
||||
$level,
|
||||
$population,
|
||||
$agriculture,
|
||||
$commerce,
|
||||
$security,
|
||||
$defence,
|
||||
$wall,
|
||||
$region,
|
||||
$newPath
|
||||
);
|
||||
|
||||
$constID[$id] = $city;
|
||||
$constName[$name] = $city;
|
||||
if(!key_exists($region, $constRegion)){
|
||||
$constRegion[$region] = [];
|
||||
}
|
||||
$constRegion[$region] = $city;
|
||||
}
|
||||
|
||||
static::$constID = $constID;
|
||||
static::$constName = $constName;
|
||||
static::$constRegion = $constRegion;
|
||||
|
||||
}
|
||||
|
||||
private static $buildInitCommon = [
|
||||
'rate'=>50,
|
||||
'trade'=>100,
|
||||
'gen1'=>0,
|
||||
'gen2'=>0,
|
||||
'gen3'=>0
|
||||
];
|
||||
|
||||
private static $buildInit = [
|
||||
'수'=>[
|
||||
'pop' => 5000,
|
||||
'agri'=> 100,
|
||||
'comm'=> 100,
|
||||
'secu'=> 100,
|
||||
'def' => 500,
|
||||
'wall'=> 500,
|
||||
],
|
||||
'진'=>[
|
||||
'pop' => 5000,
|
||||
'agri'=> 100,
|
||||
'comm'=> 100,
|
||||
'secu'=> 100,
|
||||
'def' => 500,
|
||||
'wall'=> 500,
|
||||
],
|
||||
'관'=>[
|
||||
'pop' => 10000,
|
||||
'agri'=> 100,
|
||||
'comm'=> 100,
|
||||
'secu'=> 100,
|
||||
'def' => 1000,
|
||||
'wall'=> 1000,
|
||||
],
|
||||
'이'=>[
|
||||
'pop' => 50000,
|
||||
'agri'=> 1000,
|
||||
'comm'=> 1000,
|
||||
'secu'=> 1000,
|
||||
'def' => 1000,
|
||||
'wall'=> 1000,
|
||||
],
|
||||
'소'=>[
|
||||
'pop' =>100000,
|
||||
'agri'=> 1000,
|
||||
'comm'=> 1000,
|
||||
'secu'=> 1000,
|
||||
'def' => 2000,
|
||||
'wall'=> 2000,
|
||||
],
|
||||
'중'=>[
|
||||
'pop' =>100000,
|
||||
'agri'=> 1000,
|
||||
'comm'=> 1000,
|
||||
'secu'=> 1000,
|
||||
'def' => 3000,
|
||||
'wall'=> 3000,
|
||||
],
|
||||
'대'=>[
|
||||
'pop' =>150000,
|
||||
'agri'=> 1000,
|
||||
'comm'=> 1000,
|
||||
'secu'=> 1000,
|
||||
'def' => 4000,
|
||||
'wall'=> 4000,
|
||||
],
|
||||
'특'=>[
|
||||
'pop' =>150000,
|
||||
'agri'=> 1000,
|
||||
'comm'=> 1000,
|
||||
'secu'=> 1000,
|
||||
'def' => 5000,
|
||||
'wall'=> 5000,
|
||||
]
|
||||
];
|
||||
|
||||
public static function build(){
|
||||
static::_generate();
|
||||
|
||||
$queries = array_map(function(CityInitialDetail $city){
|
||||
$initValue = static::$buildInit[$city->level];
|
||||
$path = join('|', array_keys($city->path));
|
||||
return array_merge(static::$buildInitCommon, $initValue, [
|
||||
'city'=>$city->id,
|
||||
'name'=>$city->name,
|
||||
'level'=>$city->level,
|
||||
'path'=>$path,
|
||||
'pop2'=>$city->population,
|
||||
'agri2'=>$city->agriculture,
|
||||
'comm2'=>$city->commerce,
|
||||
'secu2'=>$city->security,
|
||||
'def2'=>$city->defence,
|
||||
'wall2'=>$city->wall,
|
||||
'region'=>$city->region
|
||||
]);
|
||||
}, array_values(static::$constID));
|
||||
|
||||
DB::db()->insert('city', $queries);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
namespace sammo;
|
||||
|
||||
class CityHelper{
|
||||
//Just Helper
|
||||
private static $list = null;
|
||||
private static $listInv = null;
|
||||
private static $listByNation = null;
|
||||
|
||||
private function __construct(){
|
||||
|
||||
}
|
||||
|
||||
public static function flushCache(){
|
||||
self::$list = null;
|
||||
self::$listInv = null;
|
||||
self::$listByNation = null;
|
||||
}
|
||||
|
||||
public static function generateCache(){
|
||||
$list = [];
|
||||
$listInv = [];
|
||||
$listByNation = [];
|
||||
|
||||
foreach (DB::db()->query('SELECT `city` as `id`, `name`, `level`, `nation` from city') as $city) {
|
||||
$id = $city['id'];
|
||||
$name = $city['name'];
|
||||
$list[$id] = $city;
|
||||
$listInv[$city['name']] = $city;
|
||||
|
||||
if(!key_exists($id, $listByNation)){
|
||||
$listByNation[$id] = [];
|
||||
}
|
||||
$listByNation[$id][] = $city;
|
||||
}
|
||||
|
||||
self::$list = $list;
|
||||
self::$listInv = $listInv;
|
||||
self::$listByNation = $listByNation;
|
||||
}
|
||||
|
||||
public static function getAllCities(){
|
||||
if(self::$list === null){
|
||||
self::generateCache();
|
||||
}
|
||||
|
||||
return self::$list;
|
||||
}
|
||||
|
||||
public static function getAllNationCities(int $nationID){
|
||||
if(self::$listByNation === null){
|
||||
self::generateCache();
|
||||
}
|
||||
|
||||
return Util::array_get(self::$listByNation[$nationID], []);
|
||||
}
|
||||
|
||||
public static function getCity(int $cityID){
|
||||
if(self::$list === null){
|
||||
self::generateCache();
|
||||
}
|
||||
|
||||
return self::$list[$cityID];
|
||||
}
|
||||
|
||||
public static function getCityByName(string $cityName){
|
||||
if(self::$listInv === null){
|
||||
self::generateCache();
|
||||
}
|
||||
|
||||
return self::$listInv[$cityName];
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
namespace sammo;
|
||||
|
||||
class CityInitialDetail{
|
||||
public $id;
|
||||
public $name;
|
||||
public $level;
|
||||
public $population;
|
||||
public $agriculture;
|
||||
public $commerce;
|
||||
public $security;
|
||||
public $defence;
|
||||
public $wall;
|
||||
public $region;
|
||||
public $path;
|
||||
|
||||
public function __construct(
|
||||
int $id,
|
||||
string $name,
|
||||
int $level,
|
||||
int $population,
|
||||
int $agriculture,
|
||||
int $commerce,
|
||||
int $security,
|
||||
int $defence,
|
||||
int $wall,
|
||||
int $region,
|
||||
array $path
|
||||
){
|
||||
$this->id = $id;
|
||||
$this->name = $name;
|
||||
$this->level = $level;
|
||||
$this->population = $population;
|
||||
$this->agriculture = $agriculture;
|
||||
$this->commerce = $commerce;
|
||||
$this->security = $security;
|
||||
$this->defence = $defence;
|
||||
$this->wall = $wall;
|
||||
$this->region = $region;
|
||||
$this->path = $path;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
namespace sammo\Event;
|
||||
|
||||
abstract class Action{
|
||||
//public abstract function __construct(...$args);
|
||||
public abstract function run($env=null);
|
||||
|
||||
public static function build($actionArgs){
|
||||
if(!is_array($actionArgs)){
|
||||
throw new \InvalidArgumentException('action을 입력해야 합니다.');
|
||||
}
|
||||
|
||||
$className = __NAMESPACE__.'\\Action\\'.$actionArgs[0];
|
||||
if(!class_exists($className)){
|
||||
throw new \InvalidArgumentException('존재하지 않는 Action입니다 :'.$actionArgs[0]);
|
||||
}
|
||||
|
||||
$args = array_slice($actionArgs, 1);
|
||||
$ref = new \ReflectionClass($className);
|
||||
return $ref->newInstanceArgs($args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
<?php
|
||||
namespace sammo\Event\Action;
|
||||
use sammo\Util;
|
||||
use sammo\DB;
|
||||
|
||||
//기존 시나리오에서 개시 1월에 내정을 깎는 것을 모사.
|
||||
class ChangeCity extends \sammo\Event\Action{
|
||||
const AVAILABLE_KEY = [
|
||||
'pop'=>true,
|
||||
'agri'=>true,
|
||||
'comm'=>true,
|
||||
'secu'=>true,
|
||||
'rate'=>true,
|
||||
'def'=>true,
|
||||
'wall'=>true
|
||||
];
|
||||
const REGEXP_PERCENT = '/^(\d+(\.\d+)?)%$/';// 123.5% [1]=float
|
||||
const REGEXP_MATH = '/^([\+\-\/\*])(\d+(\.\d+)?)$/'; //+30 [1]=기호, [2]=float
|
||||
|
||||
private $queries;
|
||||
private $targetType = 'all';
|
||||
private $targetArgs = [];
|
||||
public function __construct($target = null, array $actions){
|
||||
|
||||
//values 포맷은 key, value로
|
||||
|
||||
if(!$target){
|
||||
$this->targetType = 'all';
|
||||
}
|
||||
else if(is_string($target)){
|
||||
$this->targetType = $target;
|
||||
}
|
||||
else if(is_array($target)){
|
||||
$this->targetType = $target[0];
|
||||
$this->targetArgs = array_slice($target, 1);
|
||||
}
|
||||
else{
|
||||
throw new \InvalidArgumentException('올바르지 않은 targetType 입니다.');
|
||||
}
|
||||
|
||||
|
||||
$queries = [];
|
||||
foreach($actions as $key => $value){
|
||||
if(!key_exists($key, self::AVAILABLE_KEY)){
|
||||
throw new \InvalidArgumentException('지원하지 않는 city 인자입니다 :'.$key);
|
||||
}
|
||||
|
||||
if(!is_int($value) && !is_float($value) && !is_string($value)){
|
||||
throw new \InvalidArgumentException('int, float, string이어야 합니다.');
|
||||
}
|
||||
|
||||
if($key == 'rate'){
|
||||
$queries['rate'] = $this->genSQLRate($value);
|
||||
continue;
|
||||
}
|
||||
|
||||
$queries[$key] = $this->genSQLGeneric($key, $value);
|
||||
}
|
||||
|
||||
$this->queries = $queries;
|
||||
}
|
||||
|
||||
private function genSQLRate($value){
|
||||
//민심은 max값이 100으로 고정이므로 처리 방식이 다름.
|
||||
if(is_float($value)){
|
||||
if($value < 0){
|
||||
throw new \InvalidArgumentException('음수를 곱할 수 없습니다.');
|
||||
}
|
||||
return DB::db()->sqleval('least(100, ROUND(`rate` * %d, 0))', $value);
|
||||
}
|
||||
if(is_int($value)){
|
||||
return DB::db()->sqleval('%i', Util::valueFit($value, 0, 100));
|
||||
}
|
||||
|
||||
$matches = null;
|
||||
if(preg_match(self::REGEXP_PERCENT, $value, $matches)){
|
||||
$value = round($matches[1], 0);
|
||||
return DB::db()->sqleval('%i', Util::valueFit($value, 0, 100));
|
||||
}
|
||||
|
||||
if(preg_match(self::REGEXP_MATH, $value, $matches)){
|
||||
$op = $matches[1];
|
||||
$value = $matches[2];
|
||||
if($op == '/' && $value == 0){
|
||||
throw new \InvalidArgumentException('0으로 나눌 수 없습니다.');
|
||||
}
|
||||
return DB::db()->sqleval('least(100, greatest(0, ROUND(`rate` %l %d, 0)))', $op, $value);
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException('알 수 없는 패턴입니다.');
|
||||
|
||||
}
|
||||
|
||||
private function genSQLGeneric($key, $value){
|
||||
$keyMax = $key.'2'; //comm, comm2
|
||||
|
||||
if(is_float($value)){
|
||||
if($value < 0){
|
||||
throw new \InvalidArgumentException('음수를 곱할 수 없습니다.');
|
||||
}
|
||||
return DB::db()->sqleval('least(%b, ROUND(%b * %d, 0))', $keyMax, $key, $value);
|
||||
}
|
||||
if(is_int($value)){
|
||||
return DB::db()->sqleval('least(%b, %i)', $keyMax, max(0, $value));
|
||||
}
|
||||
|
||||
$matches = null;
|
||||
if(preg_match(self::REGEXP_PERCENT, $value, $matches)){
|
||||
$value = round($matches[1], 0);
|
||||
return DB::db()->sqleval('ROUND(%b * %d, 0)', $keyMax, $value/100);
|
||||
}
|
||||
|
||||
if(preg_match(self::REGEXP_MATH, $value, $matches)){
|
||||
$op = $matches[1];
|
||||
$value = $matches[2];
|
||||
if($op == '/' && $value == 0){
|
||||
throw new \InvalidArgumentException('0으로 나눌 수 없습니다.');
|
||||
}
|
||||
return DB::db()->sqleval('least(%b, greatest(0, ROUND($b %l %d, 0)))', $keyMax, $key, $op, $value);
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException('알 수 없는 패턴입니다.');
|
||||
|
||||
}
|
||||
|
||||
private function getTargetCities($env){
|
||||
|
||||
$targetType = $this->targetType;
|
||||
if($targetType == 'all'){
|
||||
return DB::db()->queryFirstColumn('SELECT city FROM city');
|
||||
}
|
||||
|
||||
if($targetType == 'free'){
|
||||
return DB::db()->queryFirstColumn('SELECT city FROM city WHERE nation = 0');
|
||||
}
|
||||
|
||||
if($targetType == 'occupied'){
|
||||
return DB::db()->queryFirstColumn('SELECT city FROM city WHERE nation != 0');
|
||||
}
|
||||
|
||||
if($targetType == 'cities'){
|
||||
if(is_numeric($this->targetArgs)){
|
||||
return DB::db()->queryFirstColumn('SELECT city FROM city WHERE city IN (%ls)', $this->targetArgs);
|
||||
}
|
||||
else{
|
||||
return DB::db()->queryFirstColumn('SELECT city FROM city WHERE name IN (%ls)', $this->targetArgs);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException('올바르지 않은 cond 입니다.');
|
||||
}
|
||||
|
||||
public function run($env=null){
|
||||
$cities = $this->getTargetCities($env);
|
||||
|
||||
DB::db()->update('city',
|
||||
$this->queries
|
||||
, 'city IN %li', $cities);
|
||||
return [__CLASS__, DB::db()->affectedRows()];
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
namespace sammo\Event\Action;
|
||||
|
||||
//기존 event_4.php
|
||||
class CreateAdminNPC extends \sammo\Event\Action{
|
||||
public function __construct(){
|
||||
|
||||
}
|
||||
|
||||
public function run($env=null){
|
||||
return [__CLASS__, 'NYI'];
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
namespace sammo\Event\Action;
|
||||
|
||||
//기존 event_3.php
|
||||
class CreateManyNPC extends \sammo\Event\Action{
|
||||
public function __construct($npcCount = 200){
|
||||
|
||||
}
|
||||
|
||||
public function run($env=null){
|
||||
return [__CLASS__, 'NYI'];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
namespace sammo\Event\Action;
|
||||
|
||||
//1회용 event임을 의미함
|
||||
class DeleteEvent extends \sammo\Event\Action{
|
||||
|
||||
public function __construct(){
|
||||
}
|
||||
|
||||
public function run($env){
|
||||
|
||||
$eventID = \sammo\Util::array_get($env['currentEventID']);
|
||||
if(!$eventID){
|
||||
throw new \RuntimeException('currentEventID가 지정되지 않았습니다.');
|
||||
//NOTE: 이걸 에러 내야할지 아닐지는 아직 판단 필요
|
||||
}
|
||||
$db = \sammo\DB::db();
|
||||
$db->delete('event', 'id = %i', $eventID);
|
||||
return [__CLASS__, $db->affectedRows()];
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
<?php
|
||||
namespace sammo\Event\Action;
|
||||
use sammo\Util;
|
||||
use sammo\DB;
|
||||
|
||||
/**
|
||||
* 이민족 침입을 모사
|
||||
*
|
||||
* 양수 : 정해진 값. [절대값]
|
||||
* 음수 : 합산(장수 등), 혹은 평균(기술 등)을 나누어 적용한 값 [상대값]
|
||||
*
|
||||
* event_1.php, 센 이민족 : npcEachCount = -0.5, specAvg = 195, specDist = 5, tech = 15000, dex = 450000
|
||||
* event_2.php, 약한 이민족 : npcEachCount = -0.5, specAvg = 150, specDist = 20, tech = -1, dex = 0
|
||||
* event_3.php, 엄청 약한 이민족 : npcEachCount = 100, specAvg = 50, specDist = 5, tech = 0, dex = 0
|
||||
*/
|
||||
class RaiseInvader extends \sammo\Event\Action{
|
||||
private $npcEachCount;
|
||||
private $specAvg;
|
||||
private $specDist;
|
||||
private $tech;
|
||||
private $dex;
|
||||
|
||||
const INVADER_LIST = [
|
||||
'강'=>63,
|
||||
'저'=>64,
|
||||
'흉노'=>65,
|
||||
'남만'=>66,
|
||||
'산월'=>67,
|
||||
'오환'=>68,
|
||||
'왜'=>69
|
||||
];
|
||||
|
||||
public function __construct(
|
||||
$npcEachCount = -0.5,
|
||||
int $specAvg = 150,
|
||||
int $specDist = 20,
|
||||
int $tech = -1,
|
||||
int $dex = 0
|
||||
){
|
||||
$this->npcEachCount = $npcEachCount;
|
||||
$this->specAvg = $specAvg;
|
||||
$this->specDist = $specDist;
|
||||
$this->tech = $tech;
|
||||
$this->dex = $dex;
|
||||
|
||||
if($specDist < 0){
|
||||
throw new \InvalidArgumentException('specDist는 음수를 지원하지 않습니다.');
|
||||
}
|
||||
}
|
||||
|
||||
private function moveCapital(){
|
||||
$cities = array_map(function ($value) {
|
||||
return $value;
|
||||
}, INVADER_LIST);
|
||||
|
||||
$db = DB::db();
|
||||
|
||||
|
||||
foreach($db->queryFirstColumn('SELECT capital, nation from nation WHERE capital in %li', $cities) as $row){
|
||||
list($oldCapital, $nation) = $row;
|
||||
$newCapital = $db->queryFirstRow('SELECT city from city where nation=%i and city !=%i \
|
||||
order by rand() limit 1', $nation, $oldCapital);
|
||||
$db->update('nation', ['capital'=>$newCapital], 'nation=%i', $nation);
|
||||
|
||||
$db->update('general', ['city'=>$newCapital], 'nation=%i and city=%i', $nation, $city);
|
||||
}
|
||||
|
||||
$generals = [];
|
||||
foreach($db->query('SELECT gen1, gen2, gen3 from city where city in %li', $cities) as $city){
|
||||
list($gen1, $gen2, $gen3) = $city;
|
||||
if($gen1 != 0) $generals[]=$gen1;
|
||||
if($gen2 != 0) $generals[]=$gen2;
|
||||
if($gen3 != 0) $generals[]=$gen3;
|
||||
}
|
||||
|
||||
$db->update('general', [
|
||||
'level'=>1
|
||||
], 'no in %li', $generals);
|
||||
|
||||
$db->update('city', [
|
||||
'gen1'=>0,
|
||||
'gen2'=>0,
|
||||
'gen3'=>0,
|
||||
'nation'=>0
|
||||
], 'city in %li', $cities);
|
||||
}
|
||||
|
||||
public function run($env=null){
|
||||
$db = DB::db();
|
||||
$npcEachCount = $this->npcEachCount;
|
||||
|
||||
if($npcEachCount < 0){
|
||||
$npcEachCount =
|
||||
$db->queryFirstField('SELECT count(no) from general where npc<5') / count(self::INVADER_LIST);
|
||||
$npcEachCount /= -1 * $this->npcEachCount;
|
||||
}
|
||||
|
||||
$specAvg = $this->specAvg;
|
||||
if($specAvg < 0){
|
||||
$specAvg = $db->queryFirstField('SELECT avg(sum(`leader` + `power` + `intel`)) from general where npc<5');
|
||||
$specAvg /= -1 * $this->specAvg;
|
||||
}
|
||||
|
||||
$tech = $this->tech;
|
||||
if($tech < 0){
|
||||
$tech = $db->queryFirstField("SELECT avg(tech) from nation where `level`>0");
|
||||
$tech /= -1 * $this->tech;
|
||||
}
|
||||
|
||||
$dex = $this->dex;
|
||||
if($dex < 0){
|
||||
$dex = $db->queryFirstField("SELECT avg(dex0 + dex10 + dex20 + dex30 + dex40)/5 from nation where `level`>0");
|
||||
$dex /= -1 * $this->dex;
|
||||
}
|
||||
|
||||
$this->moveCapital();
|
||||
//TODO:국가를 만들고
|
||||
//TODO:장수를 세팅하고
|
||||
//TODO:외교를 설정한다.
|
||||
|
||||
//TODO: 시나리오 구현 후 마무리.
|
||||
|
||||
return [__CLASS__, 'NYI'];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
namespace sammo\Event\Action;
|
||||
|
||||
//이전 RegNPC 함수를 EventAction으로 재구성
|
||||
class RegNPC extends \sammo\Event\Action{
|
||||
|
||||
private $npc;
|
||||
|
||||
public function __construct(
|
||||
int $affinity,
|
||||
string $name,
|
||||
int $pictureID,
|
||||
int $nationID,
|
||||
string $locatedCity,
|
||||
int $leadership,
|
||||
int $power,
|
||||
int $intel,
|
||||
int $birth = 160,
|
||||
int $death = 300,
|
||||
string $ego = null,
|
||||
string $char = null,
|
||||
string $text = null
|
||||
){
|
||||
$this->npc = new \sammo\Scenario\NPC(
|
||||
$affinity,
|
||||
$name,
|
||||
$pictureID,
|
||||
$nationID,
|
||||
$locatedCity,
|
||||
$leadership,
|
||||
$power,
|
||||
$intel,
|
||||
$birth,
|
||||
$death,
|
||||
$ego,
|
||||
$char,
|
||||
$text
|
||||
);
|
||||
}
|
||||
|
||||
public function run($env=null){
|
||||
$result = $this->npc->build($env);
|
||||
return [__CLASS__, $result];
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
namespace sammo\Event;
|
||||
|
||||
abstract class Condition{
|
||||
public abstract function eval($env=null);
|
||||
|
||||
public static function build($conditionChain){
|
||||
|
||||
if(is_bool($conditionChain)){
|
||||
return new Condition\ConstBool($conditionChain);
|
||||
}
|
||||
|
||||
if(!is_array($conditionChain)){
|
||||
return $conditionChain;
|
||||
}
|
||||
|
||||
$key = $conditionChain[0];
|
||||
if(\array_key_exists(strtolower($key), Condition\Logic::AVAILABLE_LOGIC_NAME)){
|
||||
//logic 단축 명령.
|
||||
$ref = new \ReflectionClass('sammo\\Event\\Condition\\Logic');
|
||||
return $ref->newInstanceArgs($conditionChain);
|
||||
}
|
||||
|
||||
$className = 'sammo\\Event\\Condition\\'.$key;
|
||||
if(class_exists($className)){
|
||||
$args = [];
|
||||
|
||||
reset($conditionChain);
|
||||
while (next($conditionChain) !== FALSE)
|
||||
{
|
||||
$args[] = static::build(current($conditionChain));
|
||||
}
|
||||
|
||||
$ref = new \ReflectionClass($className);
|
||||
return $ref->newInstanceArgs($args);
|
||||
}
|
||||
|
||||
//array의 첫번째 값이 Condition이 아닌 경우에는 그냥 배열로 처리함.
|
||||
return array_map(static::build, $conditionChain);
|
||||
}
|
||||
|
||||
protected static function _eval($arg, $env=null){
|
||||
if(is_bool($arg)){
|
||||
return [
|
||||
'value'=>$arg,
|
||||
'chain'=>['boolean']
|
||||
];
|
||||
}
|
||||
if($arg instanceof Condition){
|
||||
return $arg->checkCondition($env);
|
||||
}
|
||||
throw new \InvalidArgumentException('평가 인자는 boolean이거나 Condition 클래스여야 합니다.');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
namespace sammo\Event\Condition;
|
||||
|
||||
class ConstBool extends \sammo\Event\Condition{
|
||||
private $fixedResult = true;
|
||||
|
||||
public function __construct(bool $value){
|
||||
$this->fixedResult = $value;
|
||||
}
|
||||
|
||||
public function eval($env=null){
|
||||
return [
|
||||
'value'=>$this->fixedResult,
|
||||
'chain'=>['ConstBool']
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
namespace sammo\Event\Condition;
|
||||
|
||||
class Date extends sammo\Event\Condition{
|
||||
|
||||
const AVAILABLE_CMP = [
|
||||
'=='=>true,
|
||||
'!='=>true,
|
||||
'<'=>true,
|
||||
'>'=>true,
|
||||
'<='=>true,
|
||||
'>='=>true,
|
||||
];
|
||||
|
||||
private $cmp;
|
||||
private $year;
|
||||
private $month;
|
||||
|
||||
//TODO:구현
|
||||
|
||||
public function __construct(string $cmp, int $year, int $month){
|
||||
//Cmp('==', '!=', '<=', '>=', '<', '>'), Year, Month(Optional)
|
||||
if(!array_key_exists($cmp, self::AVAILABLE_CMP)){
|
||||
throw new \InvalidArgumentException('올바르지 않은 비교연산자입니다');
|
||||
}
|
||||
|
||||
if($year === null && $month === null){
|
||||
throw new \InvalidArgumentException('year과 month가 둘다 null일 수 없습니다.');
|
||||
}
|
||||
|
||||
$this->cmp = $cmp;
|
||||
$this->year = $year;
|
||||
$this->month = $month;
|
||||
}
|
||||
|
||||
public function eval(array $env=null){
|
||||
if($env === null){
|
||||
return [
|
||||
'value'=>false,
|
||||
'chain'=>[__CLASS__]
|
||||
];
|
||||
}
|
||||
|
||||
if($this->year !== null && !isset($env['year'])){
|
||||
throw new \InvalidArgumentException('env에 year가 없습니다.');
|
||||
}
|
||||
|
||||
if($this->month !== null && !isset($env['month'])){
|
||||
throw new \InvalidArgumentException('env에 month가 없습니다.');
|
||||
}
|
||||
|
||||
$lhs = [
|
||||
$this->$year,
|
||||
$this->month
|
||||
];
|
||||
$rhs = [
|
||||
$this->year!==null?(int)$env['year']:null,
|
||||
$this->month!==null?(int)$env['month']:null
|
||||
];
|
||||
|
||||
$value = false;
|
||||
switch($this->cmp){
|
||||
case '==': $value = ($lhs == $rhs); break;
|
||||
case '!=': $value = ($lhs != $rhs); break;
|
||||
case '<=': $value = ($lhs <= $rhs); break;
|
||||
case '>=': $value = ($lhs >= $rhs); break;
|
||||
case '<': $value = ($lhs < $rhs); break;
|
||||
case '>': $value = ($lhs > $rhs); break;
|
||||
}
|
||||
|
||||
return [
|
||||
'value'=>$value,
|
||||
'chain'=>[__CLASS__]
|
||||
];
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
namespace sammo\Event\Condition;
|
||||
|
||||
class Interval extends sammo\Event\Condition{
|
||||
//TODO:구현
|
||||
public function __construct(...$args){
|
||||
throw new \BadMethodCallException('Not Yet Implmented.');
|
||||
|
||||
//from Year, from Month, Interval, to Year, to Month
|
||||
|
||||
}
|
||||
|
||||
public function eval($env=null){
|
||||
throw new \BadMethodCallException('Not Yet Implmented.');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
namespace sammo\Event\Condition;
|
||||
|
||||
class Logic extends sammo\Event\Condition{
|
||||
private $mode = 'and';
|
||||
private $conditions = [];
|
||||
const AVAILABLE_LOGIC_NAME = [
|
||||
'not'=>false,
|
||||
'and'=>true,
|
||||
'or'=>true,
|
||||
'xor'=>true
|
||||
];
|
||||
|
||||
public function __construct(string $mode, ...$conditions){
|
||||
$mode = strtolower($mode);
|
||||
if(!array_key_exists($mode, self::AVAILABLE_LOGIC_NAME)){
|
||||
throw new \InvalidArgumentException('첫번째 인자는 not, and, or, xor 중 하나여야 합니다.');
|
||||
}
|
||||
|
||||
if(!self::AVAILABLE_LOGIC_NAME[$mode] && count($conditions)>1){
|
||||
throw new \InvalidArgumentException('조건을 하나만 받을 수 있습니다.');
|
||||
}
|
||||
|
||||
$this->mode = $mode;
|
||||
$this->conditions = $conditions;
|
||||
}
|
||||
|
||||
public function eval($env=null){
|
||||
switch($this->$mode){
|
||||
case 'not':
|
||||
return $this->logicNot($env);
|
||||
case 'and':
|
||||
return $this->logicAnd($env);
|
||||
case 'or':
|
||||
return $this->logicOr($env);
|
||||
case 'xor':
|
||||
return $this->logicXor($env);
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException('올바르지 않은 mode.');
|
||||
}
|
||||
|
||||
private function logicNot($env){
|
||||
$sub = self::_eval($this->conditions[0], $env);
|
||||
$result['value'] = !$result['value'];
|
||||
$result['chain'][] = 'not';
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function logicAnd($env){
|
||||
$value = true;
|
||||
$chain = [];
|
||||
|
||||
foreach($this->conditions as $cond){
|
||||
$sub = self::_eval($cond, $env);
|
||||
$chain[] = $sub['chain'];
|
||||
if(!$sub['value']){
|
||||
$result['value'] = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'value'=>$value,
|
||||
'chain'=>[$chain, 'and']
|
||||
];
|
||||
}
|
||||
|
||||
private function logicOr($env){
|
||||
$value = false;
|
||||
$chain = [];
|
||||
|
||||
foreach($this->conditions as $cond){
|
||||
$sub = self::_eval($cond, $env);
|
||||
$chain[] = $sub['chain'];
|
||||
if($sub['value']){
|
||||
$result['value'] = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'value'=>$value,
|
||||
'chain'=>[$chain, 'or']
|
||||
];
|
||||
}
|
||||
|
||||
private function logicXor($env){
|
||||
$value = false;
|
||||
$chain = [];
|
||||
|
||||
foreach($this->conditions as $cond){
|
||||
$sub = self::_eval($cond, $env);
|
||||
$chain[] = $sub['chain'];
|
||||
$value ^= $sub['value'];
|
||||
}
|
||||
|
||||
return [
|
||||
'value'=>$value,
|
||||
'chain'=>[$chain, 'xor']
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
namespace sammo\Event;
|
||||
|
||||
/**
|
||||
* 게임 내에서 매 월마다 EventHandler들을 점검하고, 이벤트를 일으키는 이벤트 엔진.
|
||||
* 조건 방식이 '무식'하므로, 게임 내부에서 사용하지는 않고, 특수 시나리오를 구동하는데 사용.
|
||||
* (예: 칠종칠금?)
|
||||
*/
|
||||
class Engine{
|
||||
//TODO: 구현하라. 미래의 누군가. =P (메롱!)
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
namespace sammo\Event;
|
||||
|
||||
class EventHandler{
|
||||
|
||||
private $condition = null;
|
||||
private $actions = [];
|
||||
|
||||
public function __construct($rawCondition, $rawActions){
|
||||
$this->condition = Condition::build($rawCondition);
|
||||
foreach($rawActions as $rawAction){
|
||||
$this->actions[] = Action::build($rawAction);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function tryRunEvent(array $env=null){
|
||||
$result = $this->condition->eval($env);
|
||||
|
||||
if(!$result['value']){
|
||||
return $result;
|
||||
}
|
||||
|
||||
$resultAction = [];
|
||||
foreach($this->actions as $action){
|
||||
$resultAction[] = $action->run();
|
||||
}
|
||||
$result['action'] = $resultAction;
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
namespace sammo;
|
||||
|
||||
class GameConst{
|
||||
/** @var string 버전 */
|
||||
public static $version = "삼국지 모의전투 PHP HideD v0.1";
|
||||
/** @var string 코드 아래에 붙는 설명 코드 */
|
||||
public static $banner = "KOEI의 이미지를 사용, 응용하였습니다 / 제작 : 유기체(jwh1807@gmail.com), HideD(hided62@gmail.com)";
|
||||
/** @var string 코드 아래에 붙는 설명 코드 */
|
||||
public static $helper = "도움 주신 분들";
|
||||
/** @var int 내정시 최하 민심 설정*/
|
||||
public static $develrate = 50;
|
||||
/** @var int 능력치 상승 경험치*/
|
||||
public static $upgradeLimit = 30;
|
||||
/** @var int 숙련도 제한치*/
|
||||
public static $dexLimit = 1000000;
|
||||
/** @var int 초기 사기치*/
|
||||
public static $defaultatmos = 40;
|
||||
/** @var int 초기 훈련치*/
|
||||
public static $defaulttrain = 40;
|
||||
/** @var int 초기 사기치*/
|
||||
public static $defaultatmos2 = 70;
|
||||
/** @var int 초기 훈련치*/
|
||||
public static $defaulttrain2 = 70;
|
||||
/** @var int 최대 훈련치*/
|
||||
public static $maxtrain = 100;
|
||||
/** @var int 인위적으로 올릴 수 있는 최대 사기치*/
|
||||
public static $maxatmos = 100;
|
||||
/** @var int 최대 사기치*/
|
||||
public static $maximumatmos = 150;
|
||||
/** @var int 최대 훈련치*/
|
||||
public static $maximumtrain = 110;
|
||||
/** @var int 풀징병시 훈련 1회 상승량*/
|
||||
public static $training = 30;
|
||||
/** @var float 훈련시 사기 감소율*/
|
||||
public static $atmosing = 0.98;
|
||||
/** @var float 계략 기본 성공률*/
|
||||
public static $basefiring = 0.25;
|
||||
/** @var int 계략시 확률 가중치(수치가 클수록 변화가 적음 : (지력차/public static $firing + public static $basefiring)*/
|
||||
public static $firing = 300;
|
||||
/** @var int 계략시 기본 수치 감소량*/
|
||||
public static $firingbase = 100;
|
||||
/** @var int 계략시 수치 감소량(public static $firingbase ~ public static $firingpower)*/
|
||||
public static $firingpower = 400;
|
||||
/** @var int 명장,지장에 사용될 통솔 제한*/
|
||||
public static $goodgenleader = 65;
|
||||
/** @var int 명장에 사용될 무력 제한*/
|
||||
public static $goodgenpower = 65;
|
||||
/** @var int 지장에 사용될 지력 제한*/
|
||||
public static $goodgenintel = 65;
|
||||
/** @var string 기본 배경색깔 푸른색*/
|
||||
public static $basecolor = "#000044";
|
||||
/** @var string 기본 배경색깔 초록색*/
|
||||
public static $basecolor2 = "#225500";
|
||||
/** @var string 기본 배경색깔 붉은색*/
|
||||
public static $basecolor3 = "#660000";
|
||||
/** @var string 기본 배경색깔 검붉은색*/
|
||||
public static $basecolor4 = "#330000";
|
||||
/** @var int 페이즈당 표준 감소 병사 수*/
|
||||
public static $armperphase = 500;
|
||||
/** @var int 기본 국고*/
|
||||
public static $basegold = 0;
|
||||
/** @var int 기본 병량*/
|
||||
public static $baserice = 2000;
|
||||
/** @var int 최저 국고(긴급시) */
|
||||
public static $minNationalgold = 0;
|
||||
/** @var int 최저 병량(긴급시) */
|
||||
public static $minNationalRice = 0;
|
||||
/** @var float 군량 매매시 세율*/
|
||||
public static $taxrate = 0.01;
|
||||
/** @var float 성인 연령 */
|
||||
public static $adultAge = 14;
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
<?php
|
||||
namespace sammo;
|
||||
|
||||
class GameUnitConst{
|
||||
private function __construct(){
|
||||
|
||||
}
|
||||
|
||||
private static $constID = null;
|
||||
private static $constName = null;
|
||||
private static $constCity = null;
|
||||
private static $constRegion = null;
|
||||
|
||||
/**
|
||||
* @return \sammo\GameUnitDetail[]
|
||||
*/
|
||||
public static function all(): array{
|
||||
static::_generate();
|
||||
return static::$constID;
|
||||
}
|
||||
public static function byID($id): GameUnitDetail{
|
||||
static::_generate();
|
||||
return static::$constID[$id];
|
||||
}
|
||||
|
||||
public static function byName($name): GameUnitDetail{
|
||||
static::_generate();
|
||||
return static::$constName[$name];
|
||||
}
|
||||
|
||||
public static function byCity($city): GameUnitDetail{
|
||||
static::_generate();
|
||||
return static::$constCity[$city];
|
||||
}
|
||||
|
||||
public static function byRegion($region): GameUnitDetail{
|
||||
static::_generate();
|
||||
return static::$constRegion[$region];
|
||||
}
|
||||
|
||||
private static function _generate(){
|
||||
|
||||
if(static::$constID || static::$constName || static::$constCity || static::$constRegion){
|
||||
return;
|
||||
}
|
||||
|
||||
$list = [
|
||||
[ 0, '보병', 100, 150, 7, 10, 9, 9, 0, 0, true, ['표준적인 보병입니다.','보병은 방어특화입니다.']],
|
||||
[ 1, '청주병', 100, 200, 7, 10, 10, 11, 1, '중원', true, ['저렴하고 튼튼합니다.']],
|
||||
[ 2, '수병', 150, 150, 7, 10, 11, 10, 1, '오월', true, ['저렴하고 강력합니다.']],
|
||||
[ 3, '자객병', 100, 150, 7, 20, 10, 10, 2, '저', true, ['은밀하고 날쌥니다.']],
|
||||
[ 4, '근위병', 150, 200, 7, 10, 12, 12, 2, '낙양', true, ['최강의 보병입니다.']],
|
||||
[ 5, '등갑병', 100, 250, 7, 5, 13, 10, 1, '남중', true, ['등갑을 두른 보병입니다.']],
|
||||
|
||||
[10, '궁병', 100, 100, 7, 20, 10, 10, 0, 0, true, ['표준적인 궁병입니다.','궁병은 회피특화입니다.']],
|
||||
[11, '궁기병', 100, 100, 8, 30, 11, 12, 1, '동이', true, ['말을 타고 잘 피합니다.']],
|
||||
[12, '연노병', 150, 100, 8, 20, 12, 11, 1, '서촉', true, ['화살을 연사합니다.']],
|
||||
[13, '강궁병', 150, 150, 7, 20, 13, 13, 2, '양양', true, ['강건한 궁병입니다.']],
|
||||
[14, '석궁병', 200, 100, 7, 20, 13, 13, 2, '건업', true, ['강력한 화살을 쏩니다.']],
|
||||
|
||||
[20, '기병', 150, 100, 7, 5, 11, 11, 0, 0, true, ['표준적인 기병입니다.','기병은 공격특화입니다.']],
|
||||
[21, '백마병', 200, 100, 7, 5, 12, 13, 1, '하북', true, ['백마의 위용을 보여줍니다.']],
|
||||
[22, '중장기병', 150, 150, 7, 5, 13, 12, 1, '서북', true, ['갑주를 두른 기병입니다.']],
|
||||
[23, '돌격기병', 200, 100, 8, 5, 13, 11, 2,'흉노', true, ['저돌적으로 공격합니다.']],
|
||||
[24, '철기병', 100, 200, 7, 5, 11, 13, 2, '강', true, ['철갑을 두른 기병입니다.']],
|
||||
[25, '수렵기병', 150, 100, 8, 15, 12, 12, 2, '산월', true, ['날쎄고 빠른 기병입니다.']],
|
||||
[26, '맹수병', 250, 200, 6, 0, 16, 16, 2, '남만', true, ['어느 누구보다 강력합니다.']],
|
||||
[27, '호표기병', 200, 150, 7, 5, 14, 14, 2, '허창', true, ['정예 기병입니다.']],
|
||||
|
||||
[30, '귀병', 80, 80, 7, 5, 9, 9, 0, 0, true, ['계략을 사용하는 병종입니다.']],
|
||||
[31, '신귀병', 80, 80, 7, 20, 10, 10, 1,'초', true, ['신출귀몰한 귀병입니다.']],
|
||||
[32, '백귀병', 80, 130, 7, 5, 9, 11, 2, '오환', true, ['저렴하고 튼튼합니다.']],
|
||||
[33, '흑귀병', 130, 80, 7, 5, 11, 9, 2, '왜', true, ['저렴하고 강력합니다.']],
|
||||
[34, '악귀병', 130, 130, 7, 0, 12, 12, 2, '장안', true, ['백병전에도 능숙합니다.']],
|
||||
[35, '남귀병', 60, 60, 7, 10, 8, 8, 0, 0, false, ['전투를 포기하고 계략에 몰두합니다.']],
|
||||
[36, '황귀병', 110, 110, 7, 0, 13, 10, 2, '낙양', true, ['고도로 훈련된 귀병입니다.']],
|
||||
[37, '천귀병', 80, 130, 7, 15, 11, 12, 2, '성도', true, ['갑주를 두른 귀병입니다.']],
|
||||
[38, '마귀병', 130, 80, 7, 15, 12, 11, 2, '업', true, ['날카로운 무기를 가진 귀병입니다.']],
|
||||
|
||||
[40, '정란', 100, 100, 6, 0, 15, 5, 0, 0, false, ['높은 구조물 위에서 공격합니다.']],
|
||||
[41, '충차', 150, 100, 6, 0, 20, 5, 0, 1000, false, ['엄청난 위력으로 성벽을 부수어버립니다.']],
|
||||
[42, '벽력거', 200, 100, 6, 0, 25, 5, 2, '업', true, ['상대에게 돌덩이를 날립니다.']],
|
||||
[43, '목우', 50, 200, 5, 0, 30, 5, 2, '성도', true, ['상대를 저지하는 특수병기입니다.']]
|
||||
];
|
||||
|
||||
$constID = [];
|
||||
$constName = [];
|
||||
$constCity = [];
|
||||
$constRegion = [];
|
||||
|
||||
foreach($list as $rawUnit){
|
||||
list(
|
||||
$id,
|
||||
$name,
|
||||
$attack,
|
||||
$defence,
|
||||
$speed,
|
||||
$avoid,
|
||||
$cost,
|
||||
$rice,
|
||||
$recruitType,
|
||||
$recruitCondition,
|
||||
$recruitFirst,
|
||||
$info
|
||||
) = $rawUnit;
|
||||
|
||||
//0인 경우는 기술치이다.
|
||||
if(!$recruitFirst){
|
||||
$info[] = "일정 시간이 지나야 사용 가능";
|
||||
}
|
||||
|
||||
if($recruitType == 1){
|
||||
$info[] = "{$recruitCondition}지역 소유시 가능";
|
||||
$recruitCondition = CityConst::byName($recruitCondition)->id;
|
||||
}
|
||||
else if($recruitType == 2){
|
||||
$info[] = "{$recruitCondition} 소유시 가능";
|
||||
$recruitCondition = CityConst::$regionMap[$recruitCondition]->id;
|
||||
}
|
||||
|
||||
|
||||
|
||||
$unit = new GameUnitDetail(
|
||||
$id,
|
||||
$name,
|
||||
$attack,
|
||||
$defence,
|
||||
$speed,
|
||||
$avoid,
|
||||
$cost,
|
||||
$rice,
|
||||
$recruitType,
|
||||
$recruitCondition,
|
||||
$recruitFirst,
|
||||
$info
|
||||
);
|
||||
|
||||
$constID[$id] = $unit;
|
||||
$constName[$name] = $unit;
|
||||
if($recruitType == 1){
|
||||
if(!key_exists($recruitCondition, $constRegion)){
|
||||
$constRegion[$recruitCondition] = [];
|
||||
}
|
||||
$constRegion[$recruitCondition][] = $unit;
|
||||
}
|
||||
if($recruitType == 2){
|
||||
if(!key_exists($recruitCondition, $constCity)){
|
||||
$constCity[$recruitCondition] = [];
|
||||
}
|
||||
$constCity[$recruitCondition][] = $unit;
|
||||
}
|
||||
}
|
||||
|
||||
static::$constID = $constID;
|
||||
static::$constName = $constName;
|
||||
static::$constCity = $constCity;
|
||||
static::$constRegion = $constRegion;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
namespace sammo;
|
||||
|
||||
class GameUnitDetail{
|
||||
public $id;
|
||||
public $name;
|
||||
public $attack;
|
||||
public $defence;
|
||||
public $speed;
|
||||
public $avoid;
|
||||
public $cost;
|
||||
public $rice;
|
||||
public $recruitType;
|
||||
public $recruitCondition;
|
||||
public $recruitFirst;
|
||||
|
||||
public function __construct(
|
||||
int $id,
|
||||
string $name,
|
||||
int $attack,
|
||||
int $defence,
|
||||
int $speed,
|
||||
int $avoid,
|
||||
int $cost,
|
||||
int $rice,
|
||||
int $recruitType,
|
||||
int $recruitCondition,
|
||||
bool $recruitFirst,
|
||||
array $info
|
||||
){
|
||||
$this->name = $name;
|
||||
$this->attack = $attack;
|
||||
$this->defence = $defence;
|
||||
$this->speed = $speed;
|
||||
$this->avoid = $avoid;
|
||||
$this->cost = $cost;
|
||||
$this->rice = $rice;
|
||||
$this->recruitType = $recruitType;
|
||||
$this->recruitCondition = $recruitCondition;
|
||||
$this->recruitFirst = $recruitFirst;
|
||||
$this->info = $info;
|
||||
}
|
||||
|
||||
public function isValid($ownCities, $ownRegions, $relativeYear, $tech){
|
||||
if($relativeYear < 3 && !$this->recruitFirst){
|
||||
return false;
|
||||
}
|
||||
|
||||
if($this->recruitType == 0){
|
||||
if($tech < $this->recruitCondition){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if($this->recruitType == 1){
|
||||
if(!key_exists($this->recruitCondition, $ownRegions)){
|
||||
return false;
|
||||
}
|
||||
if ($tech < 1000) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if($this->recruitType == 2){
|
||||
$cityLevel = CityConst::byID($id)->level;
|
||||
$cityLevel = CityConst::$regionMap[$cityLevel];
|
||||
|
||||
if(!key_exists($this->recruitCondition, $ownCities)){
|
||||
return false;
|
||||
}
|
||||
if($cityLevel == '특'){
|
||||
if ($tech < 3000) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else{ //if($cityLevel == '이')
|
||||
if ($tech < 2000) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,373 @@
|
||||
<?php
|
||||
namespace sammo;
|
||||
|
||||
class Scenario{
|
||||
const SCENARIO_PATH = __dir__.'/../scenario';
|
||||
|
||||
private $scenarioIdx;
|
||||
private $scenarioPath;
|
||||
|
||||
private $data;
|
||||
|
||||
private $year;
|
||||
private $title;
|
||||
|
||||
private $history;
|
||||
|
||||
private $nations;
|
||||
private $diplomacy;
|
||||
|
||||
private $generals;
|
||||
private $generalsEx;
|
||||
|
||||
private $tmpGeneralQueue = [];
|
||||
|
||||
private $initialEvents;
|
||||
private $events;
|
||||
|
||||
private $initOK = false;
|
||||
|
||||
private function initFull(){
|
||||
if($this->initOK){
|
||||
return;
|
||||
}
|
||||
$this->initOK = true;
|
||||
$data = $this->data;
|
||||
|
||||
$this->nations = [];
|
||||
$this->nations[0] = new Scenario\Nation(0, '재야', '#ffffff', 0, 0);
|
||||
foreach (Util::array_get($data['nation'],[]) as $idx=>$rawNation) {
|
||||
list($name, $color, $gold, $rice, $infoText, $tech, $type, $nationLevel, $cities) = $rawNation;
|
||||
$nationID = $idx+1;
|
||||
|
||||
$this->nations[$nationID] = new Scenario\Nation(
|
||||
$nationID,
|
||||
$name,
|
||||
$color,
|
||||
$gold,
|
||||
$rice,
|
||||
$infoText,
|
||||
$tech,
|
||||
$type,
|
||||
$nationLevel,
|
||||
$cities
|
||||
);
|
||||
}
|
||||
|
||||
$this->diplomacy = Util::array_get($data['diplomacy'], []);
|
||||
|
||||
|
||||
$this->generals = array_map(function($rawGeneral){
|
||||
while(count($rawGeneral) < 14){
|
||||
$rawGeneral[] = null;
|
||||
}
|
||||
|
||||
list(
|
||||
$affinity, $name, $pictureID, $nationID, $locatedCity,
|
||||
$leadership, $power, $intel, $birth, $death, $ego,
|
||||
$char, $text
|
||||
) = $rawGeneral;
|
||||
|
||||
if(!key_exists($nationID, $this->nations)){
|
||||
$nationID = 0;
|
||||
}
|
||||
|
||||
$this->tmpGeneralQueue[$name] = $rawGeneral;
|
||||
|
||||
return new Scenario\NPC(
|
||||
$affinity,
|
||||
$name,
|
||||
$pictureID,
|
||||
$nationID,
|
||||
$locatedCity,
|
||||
$leadership,
|
||||
$power,
|
||||
$intel,
|
||||
$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, $pictureID, $nationID, $locatedCity,
|
||||
$leadership, $power, $intel, $level, $birth, $death, $ego,
|
||||
$char, $text
|
||||
) = $rawGeneral;
|
||||
|
||||
if(!key_exists($nationID, $this->nations)){
|
||||
$nationID = 0;
|
||||
}
|
||||
|
||||
$this->tmpGeneralQueue[$name] = $rawGeneral;
|
||||
|
||||
return new Scenario\NPC(
|
||||
$affinity,
|
||||
$name,
|
||||
$pictureID,
|
||||
$nationID,
|
||||
$locatedCity,
|
||||
$leadership,
|
||||
$power,
|
||||
$intel,
|
||||
$level,
|
||||
$birth,
|
||||
$death,
|
||||
$ego,
|
||||
$char,
|
||||
$text
|
||||
);
|
||||
|
||||
}, Util::array_get($data['generalEx'], []));
|
||||
|
||||
$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 __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->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 getNPC(){
|
||||
$this->initFull();
|
||||
return $this->generals;
|
||||
}
|
||||
|
||||
public function getNPCex(){
|
||||
$this->initFull();
|
||||
return $this->generalsEx;
|
||||
}
|
||||
|
||||
public function getNation(){
|
||||
$this->initFull();
|
||||
return $this->nations;
|
||||
}
|
||||
|
||||
public function getScenarioBrief(){
|
||||
$this->initFull();
|
||||
|
||||
$nations = [];
|
||||
$nationGeneralCnt = [];
|
||||
$nationGeneralExCnt = [];
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'year'=>$this->getYear(),
|
||||
'title'=>$this->getTitle(),
|
||||
'npc_cnt'=>count($this->getNPC()),
|
||||
'npcEx_cnt'=>count($this->getNPCex()),
|
||||
'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);
|
||||
|
||||
return $brief;
|
||||
},$this->getNation())
|
||||
];
|
||||
}
|
||||
|
||||
private function buildGenerals($env){
|
||||
$this->initFull();
|
||||
|
||||
$remainGenerals = [];
|
||||
foreach($this->generals as $general){
|
||||
if($general->build($env)){
|
||||
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)){
|
||||
continue;
|
||||
}
|
||||
|
||||
$rawGeneral = $this->tmpGeneralQueue[$general->name];
|
||||
$birth = $general->birth;
|
||||
if(!key_exists($birth, $remainGenerals)){
|
||||
$remainGenerals[$birth] = [];
|
||||
}
|
||||
$remainGenerals[$birth][] = array_merge(['RegNPC'], $rawGeneral);
|
||||
}
|
||||
}
|
||||
return $remainGenerals;
|
||||
}
|
||||
|
||||
private function buildDiplomacy($env){
|
||||
$this->initFull();
|
||||
|
||||
$db = DB::db();
|
||||
foreach($this->diplomacy as $diplomacy){
|
||||
list($me, $you, $state, $remain) = $diplomacy;
|
||||
$db->update('diplomacy', [
|
||||
'state'=>$state,
|
||||
'term'=>$remain
|
||||
], '(me = %i AND you = %i) OR (me = %i AND you = %i)', $me, $you, $you, $me);
|
||||
}
|
||||
}
|
||||
|
||||
public function build($env=[]){
|
||||
$this->initFull();
|
||||
|
||||
//NOTE: 초기화가 되어있다고 가정함.
|
||||
|
||||
/*
|
||||
env로 사용된 것들,
|
||||
게임 변수 : year, month
|
||||
game 테이블 변수 : startyear, year, month, genius, turnterm, show_img_level, extend, fiction, npcmode
|
||||
install 변수 : npcmode, show_img_level, extend, scenario, fiction
|
||||
|
||||
event변수 : currentEventID
|
||||
*/
|
||||
|
||||
$db = DB::db();
|
||||
|
||||
foreach($this->nations as $id=>$nation){
|
||||
if($id == 0){
|
||||
continue;
|
||||
}
|
||||
|
||||
$nation->build($env);
|
||||
}
|
||||
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
|
||||
];
|
||||
}
|
||||
|
||||
$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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
pushHistory($this->history);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
<?php
|
||||
namespace sammo\Scenario;
|
||||
use \sammo\Util;
|
||||
use \sammo\DB;
|
||||
use \sammo\CityHelper;
|
||||
|
||||
class NPC{
|
||||
|
||||
public $affinity;
|
||||
public $name;
|
||||
public $pictureID;
|
||||
public $nationID;
|
||||
public $locatedCity;
|
||||
public $leadership;
|
||||
public $power;
|
||||
public $intel;
|
||||
public $level;
|
||||
public $birth;
|
||||
public $death;
|
||||
public $ego;
|
||||
public $charDomestic = 0;
|
||||
public $charWar = 0;
|
||||
public $text;
|
||||
|
||||
//[ 1, "헌제",1002, 1, null, 17, 13, 61, 0, 170, 250, "안전", null, "산 넘어 산이로구나..."],
|
||||
public function __construct(
|
||||
int $affinity,
|
||||
string $name,
|
||||
int $pictureID,
|
||||
int $nationID,
|
||||
$locatedCity, //FIXME: 7.1로 올릴 때 ?string 으로 변경
|
||||
int $leadership,
|
||||
int $power,
|
||||
int $intel,
|
||||
int $level = 0,
|
||||
int $birth = 160,
|
||||
int $death = 300,
|
||||
$ego = null,
|
||||
$char = null,
|
||||
$text = null
|
||||
){
|
||||
$this->affinity = $affinity;
|
||||
$this->name = $name;
|
||||
$this->pictureID = $pictureID;
|
||||
$this->nationID = $nationID;
|
||||
$this->locatedCity = $locatedCity;
|
||||
$this->leadership = $leadership;
|
||||
$this->power = $power;
|
||||
$this->intel = $intel;
|
||||
$this->level = $level;
|
||||
$this->birth = $birth;
|
||||
$this->death = $death;
|
||||
$this->ego = $ego;
|
||||
$this->text = $text;
|
||||
|
||||
$char = \sammo\SpecCall($char);
|
||||
if($char < 40){
|
||||
$this->charDomestic = $char;
|
||||
}
|
||||
else{
|
||||
$this->charWar = $char;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function build($env=[]){
|
||||
//scenario에 life==1인 경우 수명 제한이 없어지는 모양.
|
||||
$nationID = $this->nationID;
|
||||
if(!\sammo\getNationStaticInfo($nationID)){
|
||||
$nationID = 0;
|
||||
};
|
||||
|
||||
$year = $env['year'];
|
||||
$month = $env['month'];
|
||||
$age = $year - $this->birth;
|
||||
$name = $this->name;
|
||||
|
||||
if($this->death < $year){
|
||||
return true; //죽었으니 넘어간다.
|
||||
}
|
||||
if($age < \sammo\GameConst::$adultAge){
|
||||
return false; //예약.
|
||||
}
|
||||
|
||||
$db = DB::db();
|
||||
|
||||
if($age == \sammo\GameConst::$adultAge && $month == 1){//FIXME: 14가 어디서 튀어나왔나?
|
||||
\sammo\pushHistory(["<C>●</>1월:<Y>$name</>(이)가 성인이 되어 <S>등장</>했습니다."]);
|
||||
}
|
||||
|
||||
if($this->ego == null){
|
||||
$ego = mt_rand(0, 9);//TODO: 나중에 성격을 따로 분리할 경우 클래스를 참조.
|
||||
}
|
||||
else{
|
||||
$ego = \sammo\CharCall($this->ego);
|
||||
}
|
||||
|
||||
$name = 'ⓝ'.$this->name;
|
||||
|
||||
if($env['show_img_level'] == 3 && $pictureID > 0){
|
||||
$picture = "{$pictureID}.jpg";
|
||||
}
|
||||
else{
|
||||
$picture = 'default.jpg';
|
||||
}
|
||||
|
||||
$city = $this->locatedCity;
|
||||
if($city === null){
|
||||
if($nationID == 0){
|
||||
$city = Util::choiceRandom(CityHelper::getAllCities())['id'];
|
||||
}
|
||||
else{
|
||||
$city = Util::choiceRandom(CityHelper::getAllNationCities($nationID))['id'];
|
||||
}
|
||||
}
|
||||
|
||||
$experience = $age * 100;
|
||||
$dedication = $age * 100;
|
||||
$level = $nationID?1:$this->level;
|
||||
|
||||
$turntime = \sammo\getRandTurn($env['turnterm']);
|
||||
|
||||
$killturn = ($this->death - $year) * 12 + mt_rand(0, 11);
|
||||
|
||||
$specage = $age + 1;
|
||||
$specage2 = $age + 1;
|
||||
|
||||
$npcID = $db->queryFirstField('SELECT max(npcid)+1 FROM general');
|
||||
|
||||
$db->insert('general',[
|
||||
'npcid'=>$npcID,
|
||||
'npc'=>2,
|
||||
'npc_org'=>2,
|
||||
'affinity'=>$this->affinity,
|
||||
'name'=>$name,
|
||||
'picture'=>$picture,
|
||||
'nation'=>$nationID,
|
||||
'city'=>$city,
|
||||
'leader'=>$this->leadership,
|
||||
'power'=>$this->power,
|
||||
'intel'=>$this->intel,
|
||||
'experience'=>$experience,
|
||||
'dedication'=>$dedication,
|
||||
'level'=>$level,
|
||||
'gold'=>1000,
|
||||
'rice'=>1000,
|
||||
'crew'=>0,
|
||||
'crewtype'=>0,
|
||||
'train'=>0,
|
||||
'atmos'=>0,
|
||||
'weap'=>0,
|
||||
'book'=>0,
|
||||
'horse'=>0,
|
||||
'turntime'=>$turntime,
|
||||
'killturn'=>$killturn,
|
||||
'age'=>$age,
|
||||
'belong'=>1,
|
||||
'personal'=>$ego,
|
||||
'special'=>$this->charDomestic,
|
||||
'specage'=>$specage,
|
||||
'special2'=>$this->charWar,
|
||||
'specage2'=>$specage2,
|
||||
'npcmsg'=>$this->text,
|
||||
'makelimit'=>0,
|
||||
'bornyear'=>$this->birth,
|
||||
'deadyear'=>$this->death
|
||||
]);
|
||||
|
||||
return true; //생성되었다.
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
namespace sammo\Scenario;
|
||||
use \sammo\DB;
|
||||
use \sammo\Util;
|
||||
|
||||
class Nation{
|
||||
private $id;
|
||||
private $name;
|
||||
private $color;
|
||||
private $gold;
|
||||
private $rice;
|
||||
private $infoText;
|
||||
private $tech;
|
||||
private $type;
|
||||
private $nationLevel;
|
||||
|
||||
private $capital;
|
||||
|
||||
private $cities = [];
|
||||
|
||||
public function __construct(
|
||||
int $id = null,
|
||||
string $name = '국가',
|
||||
string $color = '#ffffff',
|
||||
int $gold = 0,
|
||||
int $rice = 2000,
|
||||
string $infoText = '국가 설명',
|
||||
int $tech = 0,
|
||||
string $type = '유가',
|
||||
int $nationLevel = 0,
|
||||
array $cities = []
|
||||
){
|
||||
$this->id = $id;
|
||||
$this->name = $name;
|
||||
$this->color = $color;
|
||||
$this->gold = $gold;
|
||||
$this->rice = $rice;
|
||||
$this->infoText = $infoText;
|
||||
$this->tech = $tech;
|
||||
$this->type = $type;
|
||||
$this->nationLevel = $nationLevel;
|
||||
$this->cities = $cities;
|
||||
|
||||
$this->capital = count($cities)>0?$cities[0]:null;
|
||||
}
|
||||
|
||||
public function setID(int $id){
|
||||
$this->id = $id;
|
||||
}
|
||||
|
||||
public function getID(){
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function build($env=[]){
|
||||
//NOTE: NPC의 숫자는 아직 확정된 것이 아니다.
|
||||
$cities = array_map(function($cityName){
|
||||
return \sammo\CityHelper::getCityByName($cityName)['id'];
|
||||
}, $this->cities);
|
||||
$capital = \sammo\CityHelper::getCityByName($this->capital)['id'];
|
||||
|
||||
$type = \sammo\NationCharCall($this->type);
|
||||
|
||||
$db = DB::db();
|
||||
$otherNations = $db->queryFirstColumn('SELECT nation FROM nation');
|
||||
|
||||
$db->insert('nation', [
|
||||
'nation'=>$this->id,
|
||||
'name'=>$this->name,
|
||||
'color'=>$this->color,
|
||||
'capital'=>$capital,
|
||||
'gennum'=>0,
|
||||
'gold'=>$this->gold,
|
||||
'rice'=>$this->rice,
|
||||
'bill'=>100,
|
||||
'rate'=>15,
|
||||
'scout'=>0,
|
||||
'war'=>0,
|
||||
'tricklimit'=>24,
|
||||
'surlimit'=>72,
|
||||
'scoutmsg'=>$this->infoText,
|
||||
'tech'=>$this->tech,
|
||||
'totaltech'=>0,
|
||||
'level'=>$this->nationLevel,
|
||||
'type'=>$type,
|
||||
]);
|
||||
|
||||
$db->update('city', [
|
||||
'nation'=>$this->id
|
||||
], 'city IN %li', $cities);
|
||||
|
||||
|
||||
$diplomacy = [];
|
||||
foreach($otherNations as $nation){
|
||||
$diplomacy[] = [
|
||||
'me'=>$this->id,
|
||||
'you'=>$nation,
|
||||
'state'=>2
|
||||
];
|
||||
$diplomacy[] = [
|
||||
'me'=>$nation,
|
||||
'you'=>$this->id,
|
||||
'state'=>2
|
||||
];
|
||||
}
|
||||
if(count($diplomacy) > 0){
|
||||
$db->insert('diplomacy', $diplomacy);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function postBuild($env=[]){
|
||||
$npc_cnt = count($this->generals);
|
||||
if($env['extended_general']){
|
||||
$npc_cnt += count($this->generalsEx);
|
||||
}
|
||||
|
||||
$db->update('nation', [
|
||||
'gennum'=>$npc_cnt,
|
||||
'totaltech'=>$this->tech*$npc_cnt
|
||||
], 'nation=%i', $this->id);
|
||||
}
|
||||
|
||||
public function getBrief(){
|
||||
return [
|
||||
'id'=>$this->id,
|
||||
'name'=>$this->name,
|
||||
'color'=>$this->color,
|
||||
'gold'=>$this->gold,
|
||||
'rice'=>$this->rice,
|
||||
'infoText'=>$this->infoText,
|
||||
'tech'=>$this->tech,
|
||||
'type'=>$this->type,
|
||||
'nationLevel'=>$this->nationLevel,
|
||||
'cities'=>$this->cities
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user