190 lines
6.3 KiB
PHP
190 lines
6.3 KiB
PHP
<?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,
|
|
'trust'=>true,
|
|
'def'=>true,
|
|
'wall'=>true,
|
|
'trade'=>true,
|
|
|
|
'pop_max'=>true,
|
|
'agri_max'=>true,
|
|
'comm_max'=>true,
|
|
'secu_max'=>true,
|
|
'def_max'=>true,
|
|
'wall_max'=>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, 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 == 'trust'){
|
|
$queries['trust'] = $this->genSQLTrust($value);
|
|
continue;
|
|
}
|
|
if($key == 'trade'){
|
|
if($value === null){
|
|
$queries['trade'] = null;
|
|
}
|
|
else{
|
|
$queries['trade'] = Util::valueFit((float)$value, 95, 105);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
$queries[$key] = $this->genSQLGeneric($key, $value);
|
|
}
|
|
|
|
$this->queries = $queries;
|
|
}
|
|
|
|
private function genSQLTrust($value){
|
|
//민심은 max값이 100으로 고정이므로 처리 방식이 다름.
|
|
if(is_float($value)){
|
|
if($value < 0){
|
|
throw new \InvalidArgumentException('음수를 곱할 수 없습니다.');
|
|
}
|
|
return DB::db()->sqleval('least(100, `trust` * %d)', $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 = Util::round((float)$matches[1]);
|
|
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, `trust` %l %d, 0)))', $op, $value);
|
|
}
|
|
|
|
throw new \InvalidArgumentException('알 수 없는 패턴입니다.');
|
|
|
|
}
|
|
|
|
private function genSQLGeneric($key, $value){
|
|
$keyMax = $key.'_max'; //comm, comm_max
|
|
|
|
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 = Util::round((float)$matches[1]);
|
|
return DB::db()->sqleval('ROUND(%b * %d, 0)', $keyMax, $value/100);
|
|
}
|
|
|
|
if(str_ends_with($key, '_max') && preg_match(self::REGEXP_MATH, $value, $matches)){
|
|
//key가 아예 최대치에 대한 값이면 연산은 결과값이 0보다만 높게.
|
|
$op = $matches[1];
|
|
$value = $matches[2];
|
|
if($op == '/' && $value == 0){
|
|
throw new \InvalidArgumentException('0으로 나눌 수 없습니다.');
|
|
}
|
|
return DB::db()->sqleval('greatest(0, ROUND(%b '.$op.' %i, 0))', $key, $value);
|
|
}
|
|
|
|
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 '.$op.' %i, 0)))', $keyMax, $key, $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(array $env){
|
|
$cities = $this->getTargetCities($env);
|
|
|
|
DB::db()->update('city',
|
|
$this->queries
|
|
, 'city IN %li', $cities);
|
|
return [__CLASS__, DB::db()->affectedRows()];
|
|
}
|
|
|
|
} |