diff --git a/hwe/api.php b/hwe/api.php new file mode 100644 index 00000000..af91d505 --- /dev/null +++ b/hwe/api.php @@ -0,0 +1,90 @@ +getMessage()); +} + +if (!key_exists('path', $input)) { + Json::dieWithReason('path가 지정되지 않았습니다.'); +} + +if (key_exists('args', $input) && !is_array($input['args'])) { + Json::dieWithReason('args가 array가 아닙니다.' . gettype($input['args'])); +} + +try { + $obj = buildAPIExecutorClass($input['path'], $input['args'] ?? []); + $api = + $validateResult = $obj->validateArgs(); + if ($validateResult !== null) { + Json::dieWithReason($validateResult); + } + + $sessionMode = $obj->getRequiredSessionMode(); + if ($sessionMode === BaseAPI::NO_SESSION) { + $session = null; + } else { + if ($sessionMode & BaseAPI::REQ_GAME_LOGIN) { + $session = Session::requireGameLogin(); + } else if ($sessionMode & BaseAPI::REQ_LOGIN) { + $session = Session::requireLogin(); + } else { + Json::dieWithReason("올바르지 않은 SessionMode: {$sessionMode}"); + } + + if ($sessionMode & BaseAPI::REQ_READ_ONLY) { + $session->setReadOnly(); + } + } + + $modifiedSince = isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) + ? new \DateTimeImmutable($_SERVER['HTTP_IF_MODIFIED_SINCE'], new \DateTimeZone("UTC")) + : null; + $reqEtags = isset($_SERVER['HTTP_IF_NONE_MATCH']) ? trim($_SERVER['HTTP_IF_NONE_MATCH']) : null; + + $result = $obj->launch($session, $modifiedSince, $reqEtags); + if (is_string($result)) { + Json::dieWithReason($result); + } + + $cacheResult = $obj->tryCache(); + if ($cacheResult !== null) { + /** @var \DateTimeInterface $lastModified */ + [$lastModified, $etag] = $cacheResult; + + if ($lastModified !== null) { + header("Last-Modified: " . gmdate("D, d M Y H:i:s", TimeUtil::DateTimeToSeconds($lastModified, true)) . " GMT"); + } + if ($etag !== null) { + header("Etag: $etag"); + } + + if ($modifiedSince !== null && $lastModified !== null && TimeUtil::DateIntervalToSeconds($modifiedSince->diff($lastModified)) == 0) { + header("HTTP/1.1 304 Not Modified"); + die(); + } + if ($reqEtags !== null && $reqEtags === $etag) { + header("HTTP/1.1 304 Not Modified"); + die(); + } + } + + if ($result === null) { + Json::die([ + 'result' => true, + 'reason' => 'success' + ], $cacheResult === null ? Json::NO_CACHE : 0); + } + Json::die($result, $cacheResult === null ? Json::NO_CACHE : 0); +} catch (\Exception $e) { + Json::dieWithReason($e->getMessage()); +} catch (mixed $e) { + Json::dieWithReason($e); +} diff --git a/hwe/func.php b/hwe/func.php index 3867a236..ddf8fa49 100644 --- a/hwe/func.php +++ b/hwe/func.php @@ -2345,7 +2345,7 @@ function getRandTurn($term, ?\DateTimeInterface $baseDateTime = null) $randSecond = Util::randRangeInt(0, 60 * $term - 1); $randFraction = Util::randRangeInt(0, 999999) / 1000000; //6자리 소수 - return $baseDateTime->add(TimeUtil::secondsToDateInterval($randSecond + $randFraction))->format('Y-m-d H:i:s'); + return $baseDateTime->add(TimeUtil::secondsToDateInterval($randSecond + $randFraction))->format('Y-m-d H:i:s.u'); } function getRandTurn2($term, ?\DateTimeInterface $baseDateTime = null) @@ -2360,5 +2360,5 @@ function getRandTurn2($term, ?\DateTimeInterface $baseDateTime = null) $randSecond = Util::randRangeInt(0, 60 * $term - 1); $randFraction = Util::randRangeInt(0, 999999) / 1000000; //6자리 소수 - return $baseDateTime->sub(TimeUtil::secondsToDateInterval($randSecond + $randFraction))->format('Y-m-d H:i:s'); + return $baseDateTime->sub(TimeUtil::secondsToDateInterval($randSecond + $randFraction))->format('Y-m-d H:i:s.u'); } diff --git a/hwe/func_converter.php b/hwe/func_converter.php index 7c696083..9508b13a 100644 --- a/hwe/func_converter.php +++ b/hwe/func_converter.php @@ -1,4 +1,4 @@ -0.5, ]; $inheritStor = KVStorage::getStorage(DB::db(), "inheritance_{$userID}"); $totalPoint = 0; - foreach($inheritStor->getAll() as $key=>[$value,]){ - if(key_exists($key, $rebirthDegraded)){ + $allPoints = $inheritStor->getAll(); + if(count($allPoints) == 0){ + //비었으므로 리셋 안함 + return 0; + } + if(count($allPoints) == 1 && key_exists('previous', $allPoints)){ + //이미 리셋되었으므로 리셋 안함 + return $allPoints['previous']; + } + foreach($allPoints as $key=>[$value,]){ + if($isRebirth && key_exists($key, $rebirthDegraded)){ $value *= $rebirthDegraded[$key]; } $totalPoint += $value; @@ -1166,6 +1175,7 @@ function resetInheritanceUser(int $userID, bool $isRebirth=false){ $totalPoint = Util::toInt($totalPoint); $inheritStor->resetValues(); $inheritStor->setValue('previous', [$totalPoint, null]); + return $totalPoint; } function updateMaxDomesticCritical(General $general, $score){ diff --git a/hwe/join_post.php b/hwe/join_post.php index fbd6b58a..e9fb0d22 100644 --- a/hwe/join_post.php +++ b/hwe/join_post.php @@ -1,39 +1,50 @@ "; + exit(1); +} + $v = new Validator($_POST); $v -->rule('required', [ - 'name', - 'leadership', - 'strength', - 'intel' -]) -->rule('integer', [ - 'leadership', - 'strength', - 'intel', -]) -->rule('stringWidthBetween', 'name', 1, 18) -->rule('min', [ - 'leadership', - 'strength', - 'intel' -], GameConst::$defaultStatMin) -->rule('max', [ - 'leadership', - 'strength', - 'intel' -], GameConst::$defaultStatMax) -->rule('in', 'character', array_merge(GameConst::$availablePersonality, ['Random'])); + ->rule('required', [ + 'name', + 'leadership', + 'strength', + 'intel' + ]) + ->rule('integer', [ + 'leadership', + 'strength', + 'intel', + ]) + ->rule('stringWidthBetween', 'name', 1, 18) + ->rule('min', [ + 'leadership', + 'strength', + 'intel' + ], GameConst::$defaultStatMin) + ->rule('max', [ + 'leadership', + 'strength', + 'intel' + ], GameConst::$defaultStatMax) + ->rule('in', 'character', array_merge(GameConst::$availablePersonality, ['Random'])) + ->rule('in', 'inheritSpecial', GameConst::$availableSpecialWar) + ->rule('integer', 'inheritTurntime') + ->rule('min', 'inheritTurntime', 0) + ->rule('in', 'inheritCity', array_keys(CityConst::all())) + ->rule('integerArray', 'inheritBonusStat'); if (!$v->validate()) { - MessageBox($v->errorStr()); - echo ""; - exit(1); + dieMsg($v->errorStr()); } $session = Session::requireLogin()->setReadOnly(); @@ -52,6 +63,11 @@ $leadership = Util::getPost('leadership', 'int', 50); $strength = Util::getPost('strength', 'int', 50); $intel = Util::getPost('intel', 'int', 50); +$inheritSpecial = Util::getPost('inheritSpecial'); +$inheritTurntime = Util::getPost('inheritTurntime', 'int'); +$inheritCity = Util::getPost('inheritCity', 'int'); +$inheritBonusStat = Util::getPost('inheritBonusStat', 'array_int'); + $join = Util::getPost('join'); //쓸모 없음 $rootDB = RootDB::db(); @@ -59,14 +75,12 @@ $rootDB = RootDB::db(); $member = $rootDB->queryFirstRow('SELECT `no`, id, picture, grade, `name`, imgsvr FROM member WHERE no=%i', $userID); if (!$member) { - MessageBox("잘못된 접근입니다!!!"); - echo ""; - exit(1); + dieMsg("잘못된 접근입니다!!!"); } $db = DB::db(); $gameStor = KVStorage::getStorage($db, 'game_env'); -$gameStor->cacheValues(['year','month','maxgeneral','scenario','show_img_level','turnterm','turntime','genius','npcmode']); +$gameStor->cacheValues(['year', 'month', 'maxgeneral', 'scenario', 'show_img_level', 'turnterm', 'turntime', 'genius', 'npcmode']); ########## 동일 정보 존재여부 확인. ########## $gencount = $db->queryFirstField('SELECT count(`no`) FROM general WHERE npc<2'); @@ -74,76 +88,110 @@ $oldGeneral = $db->queryFirstField('SELECT `no` FROM general WHERE `owner`=%i', $oldName = $db->queryFirstField('SELECT `no` FROM general WHERE `name`=%s', $name); if ($oldGeneral) { - echo(""); - exit; + dieMsg("이미 등록하셨습니다!"); } if ($oldName) { - echo(""); - exit; + dieMsg("이미 있는 장수입니다. 다른 이름으로 등록해 주세요!"); } if ($gameStor->maxgeneral <= $gencount) { - echo(""); - exit; + dieMsg("더이상 등록할 수 없습니다!"); } if ($name == '') { - echo(""); - exit; + dieMsg("이름이 짧습니다. 다시 가입해주세요!"); } if (mb_strwidth($name) > 18) { - echo(""); - exit; + dieMsg("이름이 유효하지 않습니다. 다시 가입해주세요!"); } if ($leadership + $strength + $intel > GameConst::$defaultStatTotal) { - echo(""); - exit; + dieMsg("능력치가 " . GameConst::$defaultStatTotal . "을 넘어섰습니다. 다시 가입해주세요!"); +} + +if ($inheritBonusStat) { + if (count($inheritBonusStat) != 3) { + dieMsg("보너스 능력치가 잘못 지정되었습니다. 다시 가입해주세요!"); + } + $sum = array_sum($inheritBonusStat); + if ($sum < 3 || $sum > 5) { + dieMsg("보너스 능력치 합이 잘못 지정되었습니다. 다시 가입해주세요!"); + } + foreach ($inheritBonusStat as $stat) { + if ($stat < 0) { + dieMsg("보너스 능력치가 음수입니다. 다시 가입해주세요!"); + } + } +} + +$admin = $gameStor->getValues(['scenario', 'turnterm', 'turntime', 'show_img_level', 'startyear', 'year']); + +$inheritTotalPoint = resetInheritanceUser($userID); +$inheritRequiredPoint = 0; + +if ($inheritCity !== null) { + $inheritRequiredPoint += GameConst::$inheritBornCityPoint; +} +if ($inheritBonusStat !== null) { + $inheritRequiredPoint += GameConst::$inheritBornMaxBonusStat; +} +if ($inheritSpecial !== null) { + $inheritRequiredPoint += GameConst::$inheritBornSpecialPoint; +} +if ($inheritTurntime !== null) { + $inheritRequiredPoint += GameConst::$inheritBornTurntimePoint; +} + +if ($inheritTotalPoint < $inheritRequiredPoint) { + dieMsg("유산 포인트가 부족합니다. 다시 가입해주세요!"); +} + +if ($inheritSpecial !== null && $gameStor->genius == 0) { + dieMsg("이미 천재가 모두 나타났습니다. 다시 가입해주세요!"); +} + +if ($inheritCity !== null && !key_exists($inheritCity, CityConst::all())) { + dieMsg("도시가 잘못 지정되었습니다. 다시 가입해주세요!"); +} + +if ($inheritSpecial) { + $genius = true; +} else { + // 현재 1% + $genius = Util::randBool(0.01); } -$genius = Util::randBool(0.01); -// 현재 1% if ($genius && $gameStor->genius > 0) { - $gameStor->genius = $gameStor->genius-1; + $gameStor->genius = $gameStor->genius - 1; } else { $genius = false; } -// 공백지에서만 태어나게 -$city = $db->queryFirstField("select city from city where level>=5 and level<=6 and nation=0 order by rand() limit 0,1"); -if (!$city) { - $city = $db->queryFirstField("select city from city where level>=5 and level<=6 order by rand() limit 0,1"); +if ($inheritCity !== null) { + $city = $inheritCity; +} else { + // 공백지에서만 태어나게 + $city = $db->queryFirstField("select city from city where level>=5 and level<=6 and nation=0 order by rand() limit 0,1"); + if (!$city) { + $city = $db->queryFirstField("select city from city where level>=5 and level<=6 order by rand() limit 0,1"); + } } -$pleadership = 0; -$pstrength = 0; -$pintel = 0; -foreach(Util::range(Util::randRangeInt(3, 5)) as $statIdx){ - switch (Util::choiceRandomUsingWeight([$leadership, $strength, $intel])) { - case 0: - $pleadership++; - break; - case 1: - $pstrength++; - break; - case 2: - $pintel++; - break; +if ($inheritBonusStat) { + [$pleadership, $pstrength, $pintel] = $inheritBonusStat; +} else { + $pleadership = 0; + $pstrength = 0; + $pintel = 0; + foreach (Util::range(Util::randRangeInt(3, 5)) as $statIdx) { + switch (Util::choiceRandomUsingWeight([$leadership, $strength, $intel])) { + case 0: + $pleadership++; + break; + case 1: + $pstrength++; + break; + case 2: + $pintel++; + break; + } } } @@ -151,29 +199,32 @@ $leadership = $leadership + $pleadership; $strength = $strength + $pstrength; $intel = $intel + $pintel; -$admin = $gameStor->getValues(['scenario', 'turnterm', 'turntime', 'show_img_level', 'startyear', 'year']); $relYear = Util::valueFit($admin['year'] - $admin['startyear'], 0); $age = 20 + ($pleadership + $pstrength + $pintel) * 2 - (mt_rand(0, 1)); // 아직 남았고 천재등록상태이면 특기 부여 if ($genius) { $specage2 = $age; - $special2 = SpecialityHelper::pickSpecialWar([ - 'leadership'=>$leadership, - 'strength'=>$strength, - 'intel'=>$intel, - 'dex1'=>0, - 'dex2'=>0, - 'dex3'=>0, - 'dex4'=>0, - 'dex5'=>0 - ]); + if ($inheritSpecial) { + $special2 = $inheritSpecial; + } else { + $special2 = SpecialityHelper::pickSpecialWar([ + 'leadership' => $leadership, + 'strength' => $strength, + 'intel' => $intel, + 'dex1' => 0, + 'dex2' => 0, + 'dex3' => 0, + 'dex4' => 0, + 'dex5' => 0 + ]); + } } else { - $specage2 = Util::valueFit(Util::round((GameConst::$retirementYear - $age)/6 - $relYear / 2), 3) + $age; + $specage2 = Util::valueFit(Util::round((GameConst::$retirementYear - $age) / 6 - $relYear / 2), 3) + $age; $special2 = GameConst::$defaultSpecialWar; } //내특 -$specage = Util::valueFit(Util::round((GameConst::$retirementYear - $age)/12 - $relYear / 2), 3) + $age; +$specage = Util::valueFit(Util::round((GameConst::$retirementYear - $age) / 12 - $relYear / 2), 3) + $age; $special = GameConst::$defaultSpecialDomestic; if ($admin['scenario'] >= 1000) { @@ -181,22 +232,29 @@ if ($admin['scenario'] >= 1000) { $specage = $age + 3; } -if($relYear < 3){ +if ($relYear < 3) { $experience = 0; -} -else{ +} else { $expGenCount = $db->queryFirstField('SELECT count(*) FROM general WHERE nation != 0 AND npc < 4'); $targetGenOrder = Util::round($expGenCount * 0.2); $experience = $db->queryFirstField( - 'SELECT experience FROM general WHERE nation != 0 AND npc < 4 ORDER BY experience ASC LIMIT %i, 1', + 'SELECT experience FROM general WHERE nation != 0 AND npc < 4 ORDER BY experience ASC LIMIT %i, 1', $targetGenOrder - 1 ); $experience *= 0.8; } -$turntime = getRandTurn($admin['turnterm'], new \DateTimeImmutable($admin['turntime'])); +if ($inheritTurntime === null) { + $inheritTurntime = $inheritTurntime % ($gameStor->turnterm * 60); + $inheritTurntime += Util::randRangeInt(0, 999999) / 1000000; + $turntime = cutTurn($admin['turntime'], $admin['turnterm']); + $turntime = TimeUtil::nowAddSeconds($inheritTurntime, true); +} else { + $turntime = getRandTurn($admin['turnterm'], new \DateTimeImmutable($admin['turntime'])); +} -$now = date('Y-m-d H:i:s'); + +$now = TimeUtil::now(true); if ($now >= $turntime) { $turntime = addTurn($turntime, $admin['turnterm']); } @@ -211,11 +269,11 @@ if ($admin['show_img_level'] >= 1 && $member['grade'] >= 1 && $member['picture'] } //성격 랜덤시 -if (!in_array($character, GameConst::$availablePersonality)){ +if (!in_array($character, GameConst::$availablePersonality)) { $character = Util::choiceRandom(GameConst::$availablePersonality); } //상성 랜덤 -$affinity = rand()%150 + 1; +$affinity = rand() % 150 + 1; ########## 회원정보 테이블에 입력값을 등록한다. ########## $db->insert('general', [ @@ -243,7 +301,7 @@ $db->insert('general', [ 'killturn' => 6, 'lastconnect' => $now, 'lastrefresh' => $now, - 'crewtype'=>GameUnitConst::DEFAULT_CREWTYPE, + 'crewtype' => GameUnitConst::DEFAULT_CREWTYPE, 'makelimit' => 0, 'age' => $age, 'startage' => $age, @@ -255,36 +313,34 @@ $db->insert('general', [ ]); $generalID = $db->insertId(); $turnRows = []; -foreach(Util::range(GameConst::$maxTurn) as $turnIdx){ +foreach (Util::range(GameConst::$maxTurn) as $turnIdx) { $turnRows[] = [ - 'general_id'=>$generalID, - 'turn_idx'=>$turnIdx, - 'action'=>'휴식', - 'arg'=>null, - 'brief'=>'휴식' + 'general_id' => $generalID, + 'turn_idx' => $turnIdx, + 'action' => '휴식', + 'arg' => null, + 'brief' => '휴식' ]; } $db->insert('general_turn', $turnRows); -resetInheritanceUser($userID); - $rank_data = []; -foreach(array_keys(General::RANK_COLUMN) as $rankColumn){ +foreach (array_keys(General::RANK_COLUMN) as $rankColumn) { $rank_data[] = [ - 'general_id'=>$generalID, - 'nation_id'=>0, - 'type'=>$rankColumn, - 'value'=>0 + 'general_id' => $generalID, + 'nation_id' => 0, + 'type' => $rankColumn, + 'value' => 0 ]; } $db->insert('rank_data', $rank_data); $db->insert('betting', [ - 'general_id'=>$generalID, + 'general_id' => $generalID, ]); $cityname = CityConst::byID($city)->name; $me = [ - 'no'=>$generalID + 'no' => $generalID ]; $log = []; @@ -295,7 +351,7 @@ $logger = new ActionLogger($generalID, 0, $gameStor->year, $gameStor->month); $josaRa = JosaUtil::pick($name, '라'); $speicalText = getGeneralSpecialWarName($special2); if ($genius) { - + $logger->pushGlobalActionLog("{$cityname}에서 {$name}{$josaRa}는 기재가 천하에 이름을 알립니다."); $logger->pushGlobalActionLog("{$speicalText} 특기를 가진 천재의 등장으로 온 천하가 떠들썩합니다."); $logger->pushGlobalHistoryLog("【천재】{$cityname}에 천재가 등장했습니다."); @@ -318,24 +374,37 @@ if ($genius) { $logger->flush(); -pushAdminLog(["가입 : {$userID} // {$name} // {$generalID}".getenv("REMOTE_ADDR")]); +pushAdminLog(["가입 : {$userID} // {$name} // {$generalID}" . getenv("REMOTE_ADDR")]); $rootDB->insert('member_log', [ 'member_no' => $userID, - 'date'=>TimeUtil::now(), - 'action_type'=>'make_general', - 'action'=>Json::encode([ - 'server'=>DB::prefix(), - 'type'=>'general', - 'generalID'=>$generalID, - 'generalName'=>$name + 'date' => TimeUtil::now(), + 'action_type' => 'make_general', + 'action' => Json::encode([ + 'server' => DB::prefix(), + 'type' => 'general', + 'generalID' => $generalID, + 'generalName' => $name ]) ]); ?> - - + + + + + + + + + \ No newline at end of file diff --git a/hwe/sammo/API/General/Join.php b/hwe/sammo/API/General/Join.php new file mode 100644 index 00000000..63d1ab8f --- /dev/null +++ b/hwe/sammo/API/General/Join.php @@ -0,0 +1,426 @@ +args); + $v + ->rule('required', [ + 'name', + 'leadership', + 'strength', + 'intel', + 'pic', + 'character', + ]) + ->rule('integer', [ + 'leadership', + 'strength', + 'intel', + 'inheritTurntime', + ]) + ->rule('boolean', [ + 'pic' + ]) + ->rule('stringWidthBetween', 'name', 1, 18) + ->rule('min', [ + 'leadership', + 'strength', + 'intel' + ], GameConst::$defaultStatMin) + ->rule('max', [ + 'leadership', + 'strength', + 'intel' + ], GameConst::$defaultStatMax) + ->rule('in', 'character', array_merge(GameConst::$availablePersonality, ['Random'])) + ->rule('in', 'inheritSpecial', GameConst::$availableSpecialWar) + ->rule('min', 'inheritTurntime', 0) + ->rule('in', 'inheritCity', array_keys(CityConst::all())) + ->rule('integerArray', 'inheritBonusStat'); + + if (!$v->validate()) { + return $v->errorStr(); + } + return null; + } + + public function getRequiredSessionMode(): int + { + return static::REQ_LOGIN | static::REQ_READ_ONLY; + } + + public function launch(?Session $session, ?\DateTimeInterface $modifiedSince, ?string $reqEtag) + { + if($session === null){ + throw "invalid session"; + } + + $userID = $session->userID; + + $name = $this->args['name']; + $name = htmlspecialchars($name); + $name = StringUtil::removeSpecialCharacter($name); + $name = WebUtil::htmlPurify($name); + $name = StringUtil::textStrip($name); + $pic = $this->args['pic']; + $character = $this->args['character']; + + $leadership = $this->args['leadership']; + $strength = $this->args['strength']; + $intel = $this->args['intel']; + + $inheritSpecial = $this->args['inheritSpecial']??null; + $inheritTurntime =$this->args['inheritTurntime']??null; + $inheritCity = $this->args['inheritCity']??null; + $inheritBonusStat = $this->args['inheritBonusStat']??null; + + $rootDB = RootDB::db(); + //회원 테이블에서 정보확인 + $member = $rootDB->queryFirstRow('SELECT `no`, id, picture, grade, `name`, imgsvr FROM member WHERE no=%i', $userID); + + if (!$member) { + return "잘못된 접근입니다!!!"; + } + + $db = DB::db(); + $gameStor = KVStorage::getStorage($db, 'game_env'); + $gameStor->cacheValues(['year', 'month', 'maxgeneral', 'scenario', 'show_img_level', 'turnterm', 'turntime', 'genius', 'npcmode']); + ########## 동일 정보 존재여부 확인. ########## + + $gencount = $db->queryFirstField('SELECT count(`no`) FROM general WHERE npc<2'); + $oldGeneral = $db->queryFirstField('SELECT `no` FROM general WHERE `owner`=%i', $userID); + $oldName = $db->queryFirstField('SELECT `no` FROM general WHERE `name`=%s', $name); + + if ($oldGeneral) { + return "이미 등록하셨습니다!"; + } + if ($oldName) { + return "이미 있는 장수입니다. 다른 이름으로 등록해 주세요!"; + } + if ($gameStor->maxgeneral <= $gencount) { + return "더이상 등록할 수 없습니다!"; + } + if ($name == '') { + return "이름이 짧습니다. 다시 가입해주세요!"; + } + if (mb_strwidth($name) > 18) { + return "이름이 유효하지 않습니다. 다시 가입해주세요!"; + } + if ($leadership + $strength + $intel > GameConst::$defaultStatTotal) { + return "능력치가 " . GameConst::$defaultStatTotal . "을 넘어섰습니다. 다시 가입해주세요!"; + } + + if ($inheritBonusStat) { + if (count($inheritBonusStat) != 3) { + return "보너스 능력치가 잘못 지정되었습니다. 다시 가입해주세요!"; + } + $sum = array_sum($inheritBonusStat); + if ($sum < 3 || $sum > 5) { + return "보너스 능력치 합이 잘못 지정되었습니다. 다시 가입해주세요!"; + } + foreach ($inheritBonusStat as $stat) { + if ($stat < 0) { + return "보너스 능력치가 음수입니다. 다시 가입해주세요!"; + } + } + } + + $admin = $gameStor->getValues(['scenario', 'turnterm', 'turntime', 'show_img_level', 'startyear', 'year']); + + $inheritTotalPoint = resetInheritanceUser($userID); + $inheritRequiredPoint = 0; + + if ($inheritCity !== null) { + $inheritRequiredPoint += GameConst::$inheritBornCityPoint; + } + if ($inheritBonusStat !== null) { + $inheritRequiredPoint += GameConst::$inheritBornMaxBonusStat; + } + if ($inheritSpecial !== null) { + $inheritRequiredPoint += GameConst::$inheritBornSpecialPoint; + } + if ($inheritTurntime !== null) { + $inheritRequiredPoint += GameConst::$inheritBornTurntimePoint; + } + + if ($inheritTotalPoint < $inheritRequiredPoint) { + return "유산 포인트가 부족합니다. 다시 가입해주세요!"; + } + + if ($inheritSpecial !== null && $gameStor->genius == 0) { + return "이미 천재가 모두 나타났습니다. 다시 가입해주세요!"; + } + + if ($inheritCity !== null && !key_exists($inheritCity, CityConst::all())) { + return "도시가 잘못 지정되었습니다. 다시 가입해주세요!"; + } + + if ($inheritSpecial) { + $genius = true; + } else { + // 현재 1% + $genius = Util::randBool(0.01); + } + + if ($genius && $gameStor->genius > 0) { + $gameStor->genius = $gameStor->genius - 1; + } else { + $genius = false; + } + + if ($inheritCity !== null) { + $city = $inheritCity; + } else { + // 공백지에서만 태어나게 + $city = $db->queryFirstField("select city from city where level>=5 and level<=6 and nation=0 order by rand() limit 0,1"); + if (!$city) { + $city = $db->queryFirstField("select city from city where level>=5 and level<=6 order by rand() limit 0,1"); + } + } + + if ($inheritBonusStat) { + [$pleadership, $pstrength, $pintel] = $inheritBonusStat; + } else { + $pleadership = 0; + $pstrength = 0; + $pintel = 0; + foreach (Util::range(Util::randRangeInt(3, 5)) as $statIdx) { + switch (Util::choiceRandomUsingWeight([$leadership, $strength, $intel])) { + case 0: + $pleadership++; + break; + case 1: + $pstrength++; + break; + case 2: + $pintel++; + break; + } + } + } + + $leadership = $leadership + $pleadership; + $strength = $strength + $pstrength; + $intel = $intel + $pintel; + + $relYear = Util::valueFit($admin['year'] - $admin['startyear'], 0); + + $age = 20 + ($pleadership + $pstrength + $pintel) * 2 - (mt_rand(0, 1)); + // 아직 남았고 천재등록상태이면 특기 부여 + if ($genius) { + $specage2 = $age; + if ($inheritSpecial) { + $special2 = $inheritSpecial; + } else { + $special2 = SpecialityHelper::pickSpecialWar([ + 'leadership' => $leadership, + 'strength' => $strength, + 'intel' => $intel, + 'dex1' => 0, + 'dex2' => 0, + 'dex3' => 0, + 'dex4' => 0, + 'dex5' => 0 + ]); + } + } else { + $specage2 = Util::valueFit(Util::round((GameConst::$retirementYear - $age) / 6 - $relYear / 2), 3) + $age; + $special2 = GameConst::$defaultSpecialWar; + } + //내특 + $specage = Util::valueFit(Util::round((GameConst::$retirementYear - $age) / 12 - $relYear / 2), 3) + $age; + $special = GameConst::$defaultSpecialDomestic; + + if ($admin['scenario'] >= 1000) { + $specage2 = $age + 3; + $specage = $age + 3; + } + + if ($relYear < 3) { + $experience = 0; + } else { + $expGenCount = $db->queryFirstField('SELECT count(*) FROM general WHERE nation != 0 AND npc < 4'); + $targetGenOrder = Util::round($expGenCount * 0.2); + $experience = $db->queryFirstField( + 'SELECT experience FROM general WHERE nation != 0 AND npc < 4 ORDER BY experience ASC LIMIT %i, 1', + $targetGenOrder - 1 + ); + $experience *= 0.8; + } + + if ($inheritTurntime === null) { + $inheritTurntime = $inheritTurntime % ($gameStor->turnterm * 60); + $inheritTurntime += Util::randRangeInt(0, 999999) / 1000000; + $turntime = cutTurn($admin['turntime'], $admin['turnterm']); + $turntime = TimeUtil::nowAddSeconds($inheritTurntime, true); + } else { + $turntime = getRandTurn($admin['turnterm'], new \DateTimeImmutable($admin['turntime'])); + } + + + $now = TimeUtil::now(true); + if ($now >= $turntime) { + $turntime = addTurn($turntime, $admin['turnterm']); + } + + //특회 전콘 + if ($admin['show_img_level'] >= 1 && $member['grade'] >= 1 && $member['picture'] != "" && $pic) { + $face = $member['picture']; + $imgsvr = $member['imgsvr']; + } else { + $face = "default.jpg"; + $imgsvr = 0; + } + + //성격 랜덤시 + if (!in_array($character, GameConst::$availablePersonality)) { + $character = Util::choiceRandom(GameConst::$availablePersonality); + } + //상성 랜덤 + $affinity = rand() % 150 + 1; + + ########## 회원정보 테이블에 입력값을 등록한다. ########## + $db->insert('general', [ + 'owner' => $userID, + 'name' => $name, + 'owner_name' => $member['name'], + 'picture' => $face, + 'imgsvr' => $imgsvr, + 'nation' => 0, + 'city' => $city, + 'troop' => 0, + 'affinity' => $affinity, + 'leadership' => $leadership, + 'strength' => $strength, + 'intel' => $intel, + 'experience' => $experience, + 'dedication' => 0, + 'gold' => GameConst::$defaultGold, + 'rice' => GameConst::$defaultRice, + 'crew' => 0, + 'train' => 0, + 'atmos' => 0, + 'officer_level' => 0, + 'turntime' => $turntime, + 'killturn' => 6, + 'lastconnect' => $now, + 'lastrefresh' => $now, + 'crewtype' => GameUnitConst::DEFAULT_CREWTYPE, + 'makelimit' => 0, + 'age' => $age, + 'startage' => $age, + 'personal' => $character, + 'specage' => $specage, + 'special' => $special, + 'specage2' => $specage2, + 'special2' => $special2 + ]); + $generalID = $db->insertId(); + $turnRows = []; + foreach (Util::range(GameConst::$maxTurn) as $turnIdx) { + $turnRows[] = [ + 'general_id' => $generalID, + 'turn_idx' => $turnIdx, + 'action' => '휴식', + 'arg' => null, + 'brief' => '휴식' + ]; + } + $db->insert('general_turn', $turnRows); + + $rank_data = []; + foreach (array_keys(General::RANK_COLUMN) as $rankColumn) { + $rank_data[] = [ + 'general_id' => $generalID, + 'nation_id' => 0, + 'type' => $rankColumn, + 'value' => 0 + ]; + } + $db->insert('rank_data', $rank_data); + $db->insert('betting', [ + 'general_id' => $generalID, + ]); + $cityname = CityConst::byID($city)->name; + + $me = [ + 'no' => $generalID + ]; + + $log = []; + $mylog = []; + + $logger = new ActionLogger($generalID, 0, $gameStor->year, $gameStor->month); + + $josaRa = JosaUtil::pick($name, '라'); + $speicalText = getGeneralSpecialWarName($special2); + if ($genius) { + + $logger->pushGlobalActionLog("{$cityname}에서 {$name}{$josaRa}는 기재가 천하에 이름을 알립니다."); + $logger->pushGlobalActionLog("{$speicalText} 특기를 가진 천재의 등장으로 온 천하가 떠들썩합니다."); + $logger->pushGlobalHistoryLog("【천재】{$cityname}에 천재가 등장했습니다."); + } else { + $logger->pushGlobalActionLog("{$cityname}에서 {$name}{$josaRa}는 호걸이 천하에 이름을 알립니다."); + } + + $logger->pushGeneralHistoryLog("{$name}, {$cityname}에서 큰 뜻을 품다."); + $logger->pushGeneralActionLog("삼국지 모의전투 PHP의 세계에 오신 것을 환영합니다 ^o^", ActionLogger::PLAIN); + $logger->pushGeneralActionLog("처음 하시는 경우에는 도움말을 참고하시고,", ActionLogger::PLAIN); + $logger->pushGeneralActionLog("문의사항이 있으시면 게시판에 글을 남겨주시면 되겠네요~", ActionLogger::PLAIN); + $logger->pushGeneralActionLog("부디 즐거운 삼모전 되시길 바랍니다 ^^", ActionLogger::PLAIN); + $logger->pushGeneralActionLog("통솔 $pleadership 무력 $pstrength 지력 $pintel 의 보너스를 받으셨습니다.", ActionLogger::PLAIN); + $logger->pushGeneralActionLog("연령은 $age세로 시작합니다.", ActionLogger::PLAIN); + + if ($genius) { + $logger->pushGeneralActionLog("축하합니다! 천재로 태어나 처음부터 {$speicalText} 특기를 가지게 됩니다!", ActionLogger::PLAIN); + $logger->pushGeneralHistoryLog("{$speicalText} 특기를 가진 천재로 탄생."); + } + + $logger->flush(); + + pushAdminLog(["가입 : {$userID} // {$name} // {$generalID}" . getenv("REMOTE_ADDR")]); + + $rootDB->insert('member_log', [ + 'member_no' => $userID, + 'date' => TimeUtil::now(), + 'action_type' => 'make_general', + 'action' => Json::encode([ + 'server' => DB::prefix(), + 'type' => 'general', + 'generalID' => $generalID, + 'generalName' => $name + ]) + ]); + + return null; + } +} diff --git a/hwe/sammo/BaseAPI.php b/hwe/sammo/BaseAPI.php new file mode 100644 index 00000000..32f6d512 --- /dev/null +++ b/hwe/sammo/BaseAPI.php @@ -0,0 +1,26 @@ +args = $args; + } + abstract public function getRequiredSessionMode(): int; + abstract function validateArgs(): ?string; + + /** @return null|string|array */ + abstract function launch(?Session $session, ?\DateTimeInterface $modifiedSince, ?string $reqEtag); + + public function tryCache():?string{ + return null; + } +} diff --git a/hwe/sammo/GameConstBase.php b/hwe/sammo/GameConstBase.php index b02df648..b90b2715 100644 --- a/hwe/sammo/GameConstBase.php +++ b/hwe/sammo/GameConstBase.php @@ -1,15 +1,16 @@ Credit"; - /** @var string 사용중인 지도명 */ - public static $mapName = 'che'; - /** @var string 사용중인 유닛셋 */ + /** @var string 게임명 */ + public static $title = "삼국지 모의전투 PHP HiDCHe"; + /** @var string 코드 아래에 붙는 설명 코드 */ + public static $banner = "KOEI의 이미지를 사용, 응용하였습니다 / 제작 : HideD(hided62@gmail.com) / Credit"; + /** @var string 사용중인 지도명 */ + public static $mapName = 'che'; + /** @var string 사용중인 유닛셋 */ public static $unitSet = 'che'; /** @var int 내정시 최하 민심 설정*/ public static $develrate = 50; @@ -137,7 +138,7 @@ class GameConstBase public static $maxChiefTurn = 12; public static $statGradeLevel = 5; - + /** @var int 초반 제한 기간 */ public static $openingPartYear = 3; /** @var int 거병,임관 제한 기간 */ @@ -166,83 +167,88 @@ class GameConstBase public static $defaultSpecialWar = 'None'; /** @var array 선택 가능한 장수 전투 특기 */ public static $availableSpecialWar = [ - 'che_귀병', 'che_신산', 'che_환술', 'che_집중', 'che_신중', 'che_반계', + 'che_귀병', 'che_신산', 'che_환술', 'che_집중', 'che_신중', 'che_반계', 'che_보병', 'che_궁병', 'che_기병', 'che_공성', - 'che_돌격', 'che_무쌍', 'che_견고', 'che_위압', + 'che_돌격', 'che_무쌍', 'che_견고', 'che_위압', 'che_저격', 'che_필살', 'che_징병', 'che_의술', 'che_격노', 'che_척사', ]; /** @var array 선택할 수 없으나 게임 내에 유효한 장수 전투 특기 */ public static $optionalSpecialWar = [ 'None', ]; - + /** @var string 기본 성향(공용) */ public static $neutralPersonality = 'None'; /** @var array 선택 가능한 성향 */ public static $availablePersonality = [ 'che_안전', 'che_유지', 'che_재간', 'che_출세', 'che_할거', 'che_정복', - 'che_패권', 'che_의협', 'che_대의', 'che_왕좌' + 'che_패권', 'che_의협', 'che_대의', 'che_왕좌' ]; /** @var array 존재하는 모든 성향 */ public static $optionalPersonality = [ 'che_은둔', 'None' ]; + public static $inheritBornSpecialPoint = 12000; + public static $inheritBornTurntimePoint = 3000; + public static $inheritBornCityPoint = 1000; + public static $inheritBornMaxBonusStat = 1000; + public static $allItems = [ 'horse' => [ - 'che_명마_01_노기'=>0, 'che_명마_02_조랑'=>0, 'che_명마_03_노새'=>0, - 'che_명마_04_나귀'=>0, 'che_명마_05_갈색마'=>0, 'che_명마_06_흑색마'=>0, - - 'che_명마_07_백마'=>2, 'che_명마_07_기주마'=>2, - 'che_명마_08_양주마'=>2, 'che_명마_09_과하마'=>2, - 'che_명마_10_대완마'=>2, 'che_명마_11_서량마'=>2, - 'che_명마_12_사륜거'=>2, 'che_명마_13_절영'=>1, 'che_명마_13_적로'=>1, - 'che_명마_14_적란마'=>1, 'che_명마_14_조황비전'=>1, 'che_명마_15_한혈마'=>1, 'che_명마_15_적토마'=>1, + 'che_명마_01_노기' => 0, 'che_명마_02_조랑' => 0, 'che_명마_03_노새' => 0, + 'che_명마_04_나귀' => 0, 'che_명마_05_갈색마' => 0, 'che_명마_06_흑색마' => 0, + + 'che_명마_07_백마' => 2, 'che_명마_07_기주마' => 2, + 'che_명마_08_양주마' => 2, 'che_명마_09_과하마' => 2, + 'che_명마_10_대완마' => 2, 'che_명마_11_서량마' => 2, + 'che_명마_12_사륜거' => 2, 'che_명마_13_절영' => 1, 'che_명마_13_적로' => 1, + 'che_명마_14_적란마' => 1, 'che_명마_14_조황비전' => 1, 'che_명마_15_한혈마' => 1, 'che_명마_15_적토마' => 1, ], 'weapon' => [ - 'che_무기_01_단도'=>0, 'che_무기_02_단궁'=>0, 'che_무기_03_단극'=>0, - 'che_무기_04_목검'=>0, 'che_무기_05_죽창'=>0, 'che_무기_06_소부'=>0, - - 'che_무기_07_동추'=>1, 'che_무기_07_철편'=>1, 'che_무기_07_철쇄'=>1, 'che_무기_07_맥궁'=>1, - 'che_무기_08_유성추'=>1, 'che_무기_08_철질여골'=>1, 'che_무기_09_쌍철극'=>1, 'che_무기_09_동호비궁'=>1, 'che_무기_10_삼첨도'=>1, 'che_무기_10_대부'=>1, 'che_무기_11_고정도'=>1, 'che_무기_11_이광궁'=>1, 'che_무기_12_철척사모'=>1, 'che_무기_12_칠성검'=>1, 'che_무기_13_사모'=>1, 'che_무기_13_양유기궁'=>1, - 'che_무기_14_언월도'=>1, 'che_무기_14_방천화극'=>1, 'che_무기_15_청홍검'=>1, 'che_무기_15_의천검'=>1 + 'che_무기_01_단도' => 0, 'che_무기_02_단궁' => 0, 'che_무기_03_단극' => 0, + 'che_무기_04_목검' => 0, 'che_무기_05_죽창' => 0, 'che_무기_06_소부' => 0, + + 'che_무기_07_동추' => 1, 'che_무기_07_철편' => 1, 'che_무기_07_철쇄' => 1, 'che_무기_07_맥궁' => 1, + 'che_무기_08_유성추' => 1, 'che_무기_08_철질여골' => 1, 'che_무기_09_쌍철극' => 1, 'che_무기_09_동호비궁' => 1, 'che_무기_10_삼첨도' => 1, 'che_무기_10_대부' => 1, 'che_무기_11_고정도' => 1, 'che_무기_11_이광궁' => 1, 'che_무기_12_철척사모' => 1, 'che_무기_12_칠성검' => 1, 'che_무기_13_사모' => 1, 'che_무기_13_양유기궁' => 1, + 'che_무기_14_언월도' => 1, 'che_무기_14_방천화극' => 1, 'che_무기_15_청홍검' => 1, 'che_무기_15_의천검' => 1 ], 'book' => [ - 'che_서적_01_효경전'=>0, 'che_서적_02_회남자'=>0, 'che_서적_03_변도론'=>0, - 'che_서적_04_건상역주'=>0, 'che_서적_05_여씨춘추'=>0, 'che_서적_06_사민월령'=>0, + 'che_서적_01_효경전' => 0, 'che_서적_02_회남자' => 0, 'che_서적_03_변도론' => 0, + 'che_서적_04_건상역주' => 0, 'che_서적_05_여씨춘추' => 0, 'che_서적_06_사민월령' => 0, - 'che_서적_07_위료자'=>1, 'che_서적_07_사마법'=>1, 'che_서적_07_한서'=>1, 'che_서적_07_논어'=>1, - 'che_서적_08_전론'=>1, 'che_서적_08_사기'=>1, 'che_서적_09_장자'=>1, 'che_서적_09_역경'=>1, - 'che_서적_10_시경'=>1, 'che_서적_10_구국론'=>1, 'che_서적_11_상군서'=>1, 'che_서적_11_춘추전'=>1, - 'che_서적_12_산해경'=>1, 'che_서적_12_맹덕신서'=>1, 'che_서적_13_관자'=>1, 'che_서적_13_병법24편'=>1, - 'che_서적_14_한비자'=>1, 'che_서적_14_오자병법'=>1, 'che_서적_15_노자'=>1, 'che_서적_15_손자병법'=>1, + 'che_서적_07_위료자' => 1, 'che_서적_07_사마법' => 1, 'che_서적_07_한서' => 1, 'che_서적_07_논어' => 1, + 'che_서적_08_전론' => 1, 'che_서적_08_사기' => 1, 'che_서적_09_장자' => 1, 'che_서적_09_역경' => 1, + 'che_서적_10_시경' => 1, 'che_서적_10_구국론' => 1, 'che_서적_11_상군서' => 1, 'che_서적_11_춘추전' => 1, + 'che_서적_12_산해경' => 1, 'che_서적_12_맹덕신서' => 1, 'che_서적_13_관자' => 1, 'che_서적_13_병법24편' => 1, + 'che_서적_14_한비자' => 1, 'che_서적_14_오자병법' => 1, 'che_서적_15_노자' => 1, 'che_서적_15_손자병법' => 1, ], 'item' => [ - 'che_치료_환약'=>0, 'che_저격_수극'=>0, 'che_사기_탁주'=>0, - 'che_훈련_청주'=>0, 'che_계략_이추'=>0, 'che_계략_향낭'=>0, + 'che_치료_환약' => 0, 'che_저격_수극' => 0, 'che_사기_탁주' => 0, + 'che_훈련_청주' => 0, 'che_계략_이추' => 0, 'che_계략_향낭' => 0, - 'che_의술_청낭서'=>1, 'che_의술_태평청령'=>1, 'che_의술_상한잡병론'=>1, - 'che_부적_태현청생부'=>1, - 'che_저격_매화수전'=>1, 'che_저격_비도'=>1, - 'che_계략_육도'=>1, 'che_계략_삼략'=>1, - 'che_반계_백우선'=>1, - 'che_행동_서촉지형도'=>1, + 'che_의술_청낭서' => 1, 'che_의술_태평청령' => 1, 'che_의술_상한잡병론' => 1, + 'che_부적_태현청생부' => 1, + 'che_저격_매화수전' => 1, 'che_저격_비도' => 1, + 'che_계략_육도' => 1, 'che_계략_삼략' => 1, + 'che_반계_백우선' => 1, + 'che_행동_서촉지형도' => 1, - 'che_훈련_과실주'=>1, 'che_훈련_이강주'=>1, 'che_사기_두강주'=>1, 'che_사기_보령압주'=>1, - 'che_훈련_철벽서'=>1, 'che_훈련_단결도'=>1, 'che_사기_춘화첩'=>1, 'che_사기_초선화'=>1, - 'che_회피_태평요술'=>1, 'che_회피_둔갑천서'=>1, + 'che_훈련_과실주' => 1, 'che_훈련_이강주' => 1, 'che_사기_두강주' => 1, 'che_사기_보령압주' => 1, + 'che_훈련_철벽서' => 1, 'che_훈련_단결도' => 1, 'che_사기_춘화첩' => 1, 'che_사기_초선화' => 1, + 'che_회피_태평요술' => 1, 'che_회피_둔갑천서' => 1, ] ]; /** @var array 선택 가능한 커맨드 */ public static $availableGeneralCommand = [ - ''=>[ + '' => [ '휴식', 'che_요양' ], - '내정'=>[ + '내정' => [ 'che_농지개간', 'che_상업투자', 'che_기술연구', @@ -253,7 +259,7 @@ class GameConstBase 'che_주민선정', 'che_물자조달', ], - '군사'=>[ + '군사' => [ 'che_소집해제', 'che_첩보', 'che_징병', @@ -262,7 +268,7 @@ class GameConstBase 'che_사기진작', 'che_출병', ], - '인사'=>[ + '인사' => [ 'che_이동', 'che_강행', 'che_인재탐색', @@ -273,13 +279,13 @@ class GameConstBase 'che_랜덤임관', 'che_장수대상임관', ], - '계략'=>[ + '계략' => [ 'che_화계', 'che_파괴', 'che_탈취', 'che_선동', ], - '개인'=>[ + '개인' => [ 'che_내정특기초기화', 'che_전투특기초기화', 'che_단련', @@ -301,28 +307,28 @@ class GameConstBase /** @var array 선택 가능한 커맨드 */ public static $availableChiefCommand = [ - '휴식'=>[ + '휴식' => [ '휴식', ], - '인사'=>[ + '인사' => [ 'che_발령', 'che_포상', 'che_몰수', ], - '외교'=>[ + '외교' => [ 'che_물자원조', 'che_불가침제의', 'che_선전포고', 'che_종전제의', 'che_불가침파기제의', ], - '특수'=>[ + '특수' => [ 'che_초토화', 'che_천도', 'che_증축', 'che_감축', ], - '전략'=>[ + '전략' => [ 'che_필사즉생', 'che_백성동원', 'che_수몰', @@ -331,7 +337,7 @@ class GameConstBase 'che_이호경식', 'che_급습', ], - '기타'=>[ + '기타' => [ 'che_피장파장', 'che_국기변경', 'che_국호변경', diff --git a/hwe/sammo/TurnExecutionHelper.php b/hwe/sammo/TurnExecutionHelper.php index 077e4ac2..1ba6fd94 100644 --- a/hwe/sammo/TurnExecutionHelper.php +++ b/hwe/sammo/TurnExecutionHelper.php @@ -1,7 +1,9 @@ applyDB(); } - public function applyDB(){ + public function applyDB() + { $db = DB::db(); $this->generalObj->applyDB($db); } - public function getGeneral():General{ + public function getGeneral(): General + { return $this->generalObj; } - public function preprocessCommand(array $env){ + public function preprocessCommand(array $env) + { $general = $this->getGeneral(); $caller = $general->getPreTurnExecuteTriggerList($general); $caller->merge(new GeneralTriggerCaller( @@ -37,37 +42,37 @@ class TurnExecutionHelper $caller->fire($env); } - public function processBlocked():bool{ + public function processBlocked(): bool + { $general = $this->getGeneral(); $blocked = $general->getVar('block'); - if($blocked < 2){ + if ($blocked < 2) { return false; } $date = $general->getTurnTime($general::TURNTIME_HM); $logger = $general->getLogger(); - if($blocked == 2){ + if ($blocked == 2) { $general->increaseVarWithLimit('killturn', -1, 0); $logger->pushGeneralActionLog("현재 멀티, 또는 비매너로 인한블럭 대상자입니다. <1>$date"); - } - else if($blocked == 3){ + } else if ($blocked == 3) { $general->increaseVarWithLimit('killturn', -1, 0); $logger->pushGeneralActionLog("현재 악성유저로 분류되어 블럭 대상자입니다. <1>$date"); - } - else{ + } else { //Hmm? return false; } - + return true; } - public function processNationCommand(Command\NationCommand $commandObj):LastTurn{ + public function processNationCommand(Command\NationCommand $commandObj): LastTurn + { $general = $this->getGeneral(); - while(true){ - if(!$commandObj->hasFullConditionMet()){ + while (true) { + if (!$commandObj->hasFullConditionMet()) { $date = $general->getTurnTime($general::TURNTIME_HM); $failString = $commandObj->getFailString(); $text = "{$failString} <1>{$date}"; @@ -75,7 +80,7 @@ class TurnExecutionHelper break; } - if(!$commandObj->addTermStack()){ + if (!$commandObj->addTermStack()) { $date = $general->getTurnTime($general::TURNTIME_HM); $termString = $commandObj->getTermString(); $text = "{$termString} <1>{$date}"; @@ -84,14 +89,14 @@ class TurnExecutionHelper } $result = $commandObj->run(); - if($result){ + if ($result) { $commandObj->setNextAvailable(); break; } - - + + $alt = $commandObj->getAlternativeCommand(); - if($alt === null){ + if ($alt === null) { break; } $commandObj = $alt; @@ -101,7 +106,8 @@ class TurnExecutionHelper return $commandObj->getResultTurn(); } - public function processCommand(Command\GeneralCommand $commandObj, bool $autorunMode){ + public function processCommand(Command\GeneralCommand $commandObj, bool $autorunMode) + { $general = $this->getGeneral(); @@ -109,16 +115,16 @@ class TurnExecutionHelper $gameStor = KVStorage::getStorage($db, 'game_env'); $commandClassName = $commandObj->getName(); - while(true){ - if(!$commandObj->hasFullConditionMet()){ + while (true) { + if (!$commandObj->hasFullConditionMet()) { $date = $general->getTurnTime($general::TURNTIME_HM); $failString = $commandObj->getFailString(); $text = "{$failString} <1>{$date}"; $general->getLogger()->pushGeneralActionLog($text); break; } - - if(!$commandObj->addTermStack()){ + + if (!$commandObj->addTermStack()) { $date = $general->getTurnTime($general::TURNTIME_HM); $termString = $commandObj->getTermString(); $text = "{$termString} <1>{$date}"; @@ -127,43 +133,40 @@ class TurnExecutionHelper } $result = $commandObj->run(); - if($result){ + if ($result) { $commandObj->setNextAvailable(); break; } $alt = $commandObj->getAlternativeCommand(); - if($alt === null){ + if ($alt === null) { break; } $commandObj = $alt; $commandClassName = $alt->getName(); } - + $general->clearActivatedSkill(); $killTurn = $gameStor->killturn; - if($general->getNPCType() >= 2){ + if ($general->getNPCType() >= 2) { $general->increaseVarWithLimit('killturn', -1); - } - else if($general->getVar('killturn') > $killTurn){ + } else if ($general->getVar('killturn') > $killTurn) { $general->increaseVarWithLimit('killturn', -1); - } - else if($autorunMode){ + } else if ($autorunMode) { $general->increaseVarWithLimit('killturn', -1); - } - else if($commandClassName == '휴식'){ + } else if ($commandClassName == '휴식') { $general->increaseVarWithLimit('killturn', -1); - } - else{ + } else { $general->setVar('killturn', $killTurn); } return $commandObj->getResultTurn(); } - function updateTurnTime(){ + function updateTurnTime() + { $db = DB::db(); $gameStor = KVStorage::getStorage($db, 'game_env'); @@ -175,13 +178,13 @@ class TurnExecutionHelper $generalName = $general->getName(); // 삭턴장수 삭제처리 - if($general->getVar('killturn') <= 0){ + if ($general->getVar('killturn') <= 0) { // npc유저 삭턴시 npc로 전환 - if($general->getNPCType() == 1 && $general->getVar('deadyear') > $gameStor->year){ + if ($general->getNPCType() == 1 && $general->getVar('deadyear') > $gameStor->year) { $ownerName = $general->getVar('owner_name'); $josaYi = JosaUtil::pick($ownerName, '이'); - + $logger->pushGlobalActionLog("{$ownerName}{$josaYi} {$generalName}의 육체에서 유체이탈합니다!"); $general->setVar('killturn', ($general->getVar('deadyear') - $gameStor->year) * 12); @@ -189,8 +192,7 @@ class TurnExecutionHelper $general->setVar('owner', 0); $general->setVar('defence_train', 80); $general->setVar('owner_name', null); - } - else{ + } else { $general->applyDB($db); storeOldGeneral($generalID, $gameStor->year, $gameStor->month); $general->kill($db); @@ -199,8 +201,8 @@ class TurnExecutionHelper } //은퇴 - if($general->getVar('age') >= GameConst::$retirementYear && $general->getNPCType() == 0) { - if($gameStor->isunited == 0) { + if ($general->getVar('age') >= GameConst::$retirementYear && $general->getNPCType() == 0) { + if ($gameStor->isunited == 0) { $general->applyDB($db); CheckHall($generalID); } @@ -210,11 +212,11 @@ class TurnExecutionHelper $turntime = addTurn($general->getTurnTime(), $gameStor->turnterm); $general->setVar('turntime', $turntime); - } - static public function executeGeneralCommandUntil(string $date, \DateTimeInterface $limitActionTime, int $year, int $month){ + static public function executeGeneralCommandUntil(string $date, \DateTimeInterface $limitActionTime, int $year, int $month) + { $db = DB::db(); $generalsTodo = $db->query( 'SELECT no,name,turntime,killturn,block,npc,deadyear FROM general WHERE turntime < %s ORDER BY turntime ASC, `no` ASC', @@ -226,9 +228,9 @@ class TurnExecutionHelper $gameStor = KVStorage::getStorage($db, 'game_env'); $autorun_user = $gameStor->autorun_user; - foreach($generalsTodo as $rawGeneral){ + foreach ($generalsTodo as $rawGeneral) { $currActionTime = new \DateTimeImmutable(); - if($currActionTime > $limitActionTime){ + if ($currActionTime > $limitActionTime) { return [true, $currentTurn]; } @@ -238,7 +240,7 @@ class TurnExecutionHelper $env = $gameStor->getAll(true); $hasNationTurn = false; - if($general->getVar('nation') != 0 && $general->getVar('officer_level') >= 5){ + if ($general->getVar('nation') != 0 && $general->getVar('officer_level') >= 5) { $nationStor = KVStorage::getStorage($db, $general->getNationID(), 'nation_env'); $lastNationTurnKey = "turn_last_{$general->getVar('officer_level')}"; //수뇌 몇 없는데 매번 left join 하는건 낭비인것 같다. @@ -246,10 +248,10 @@ class TurnExecutionHelper 'SELECT action, arg FROM nation_turn WHERE nation_id = %i AND officer_level = %i AND turn_idx =0', $general->getVar('nation'), $general->getVar('officer_level') - )??[]; + ) ?? []; $hasNationTurn = true; - $nationCommand = $rawNationTurn['action']??null; - $nationArg = Json::decode($rawNationTurn['arg']??null); + $nationCommand = $rawNationTurn['action'] ?? null; + $nationArg = Json::decode($rawNationTurn['arg'] ?? null); $lastNationTurn = LastTurn::fromRaw($nationStor->getValue($lastNationTurnKey)); $nationCommandObj = buildNationCommandClass($nationCommand, $general, $env, $lastNationTurn, $nationArg); } @@ -260,16 +262,15 @@ class TurnExecutionHelper $general->increaseInheritancePoint('lived_month', 1); $turnObj->preprocessCommand($env); - $generalCommandObj = $general->getReservedTurn(0, $env); - if($general->getNPCType() >= 2 || ($autorun_user['limit_minutes']??false)){ + if ($general->getNPCType() >= 2 || ($autorun_user['limit_minutes'] ?? false)) { $ai = new GeneralAI($turnObj->getGeneral()); } - - if(!$turnObj->processBlocked()){ - - if($hasNationTurn){ - if($ai && ($general->getAuxVar('use_auto_nation_turn')??1)){ + + if (!$turnObj->processBlocked()) { + + if ($hasNationTurn) { + if ($ai && ($general->getAuxVar('use_auto_nation_turn') ?? 1)) { $nationCommandObj = $ai->chooseNationTurn($nationCommandObj); $cityName = CityConst::byID($general->getCityID())->name; LogText("NationTurn", "General, {$general->getName()}, {$general->getID()}, {$cityName}, {$general->getStaticNation()['name']}, {$nationCommandObj->getBrief()}, {$nationCommandObj->reason}, "); @@ -278,18 +279,21 @@ class TurnExecutionHelper $nationCommandObj ); $nationStor->setValue($lastNationTurnKey, $resultNationTurn->toRaw()); + $general->setRawCity(null); } - if($ai){ + $generalCommandObj = $general->getReservedTurn(0, $env); + + if ($ai) { $newGeneralCommandObj = $ai->chooseGeneralTurn($generalCommandObj); // npc AI 처리 - if($generalCommandObj !== $newGeneralCommandObj){ + if ($generalCommandObj !== $newGeneralCommandObj) { $autorunMode = true; $generalCommandObj = $newGeneralCommandObj; } $cityName = CityConst::byID($general->getCityID())->name; LogText("turn", "General, {$general->getName()}, {$general->getID()}, {$cityName}, {$general->getStaticNation()['name']}, {$generalCommandObj->getBrief()}, {$generalCommandObj->reason}, "); } - + $turnObj->processCommand($generalCommandObj, $autorunMode); } pullNationCommand($general->getVar('nation'), $general->getVar('officer_level')); @@ -300,26 +304,25 @@ class TurnExecutionHelper $turnObj->updateTurnTime(); $turnObj->applyDB(); - - } return [false, $currentTurn]; } - static public function executeAllCommand(){ + static public function executeAllCommand() + { //if(!timeover()) { return; } $db = DB::db(); $gameStor = KVStorage::getStorage($db, 'game_env'); - if(TimeUtil::now(true) < $gameStor->turntime){ + if (TimeUtil::now(true) < $gameStor->turntime) { //턴 시각 이전이면 아무것도 하지 않음 return true; } - if(!tryLock()){ + if (!tryLock()) { return; } @@ -342,13 +345,12 @@ class TurnExecutionHelper $nextTurn = addTurn($prevTurn, $gameStor->turnterm); $maxActionTime = Util::toInt(ini_get('max_execution_time')); - if($maxActionTime == 0){ + if ($maxActionTime == 0) { $maxActionTime = 60; - } - else { + } else { $maxActionTime = max($maxActionTime * 2 / 3, $maxActionTime - 10); } - + $limitActionTime = (new \DateTimeImmutable())->add(TimeUtil::secondsToDateInterval($maxActionTime)); // 현재 턴 이전 월턴까지 모두처리. @@ -356,23 +358,26 @@ class TurnExecutionHelper while ($nextTurn <= $date) { [$executionOver, $currentTurn] = static::executeGeneralCommandUntil( - $nextTurn, $limitActionTime, $gameStor->year, $gameStor->month + $nextTurn, + $limitActionTime, + $gameStor->year, + $gameStor->month ); // 트래픽 업데이트 updateTraffic(); - if($executionOver){ - if($currentTurn !== null){ + if ($executionOver) { + if ($currentTurn !== null) { $gameStor->turntime = $currentTurn; } unlock(); return; } - + // 1달마다 처리하는 것들, 벌점 감소 및 건국,전턴,합병 -1, 군량 소모 - if(!preUpdateMonthly()){ + if (!preUpdateMonthly()) { $gameStor->resetCache(true); unlock(); throw new \RuntimeException('preUpdateMonthly() 처리 에러'); @@ -383,7 +388,7 @@ class TurnExecutionHelper $logger = new ActionLogger(0, 0, $gameStor->year, $gameStor->month, false); // 분기계산. 장수들 턴보다 먼저 있다면 먼저처리 - if($gameStor->month == 1) { + if ($gameStor->month == 1) { processSpring(); processGoldIncome(); updateYearly(); @@ -394,16 +399,16 @@ class TurnExecutionHelper // 새해 알림 $logger->pushGlobalActionLog("{$gameStor->year}년이 되었습니다."); $logger->flush(); //TODO: globalAction류는 전역에서 관리하는것이 좋을 듯. - } elseif($gameStor->month == 4) { + } elseif ($gameStor->month == 4) { updateQuaterly(); disaster(); - } elseif($gameStor->month == 7) { + } elseif ($gameStor->month == 7) { processFall(); processRiceIncome(); updateQuaterly(); disaster(); tradeRate(); - } elseif($gameStor->month == 10) { + } elseif ($gameStor->month == 10) { updateQuaterly(); disaster(); } @@ -411,7 +416,7 @@ class TurnExecutionHelper // 이벤트 핸들러 동작 $e_env = null; foreach (DB::db()->query('SELECT * from event') as $rawEvent) { - if($e_env === null){ + if ($e_env === null) { $e_env = $gameStor->getAll(false); } $eventID = $rawEvent['id']; @@ -423,7 +428,7 @@ class TurnExecutionHelper $event->tryRunEvent($e_env); } - if($e_env !== null){ + if ($e_env !== null) { $gameStor->resetCache(true); } @@ -440,13 +445,16 @@ class TurnExecutionHelper // 현재시간의 월턴시간 이후 분단위 장수 처리 [$executionOver, $currentTurn] = static::executeGeneralCommandUntil( - $date, $limitActionTime, $gameStor->year, $gameStor->month + $date, + $limitActionTime, + $gameStor->year, + $gameStor->month ); - if($currentTurn !== null){ + if ($currentTurn !== null) { $gameStor->turntime = $currentTurn; } - + //토너먼트 처리 processTournament(); //거래 처리 @@ -455,4 +463,4 @@ class TurnExecutionHelper $gameStor->resetCache(true); unlock(); } -} \ No newline at end of file +} diff --git a/src/sammo/Json.php b/src/sammo/Json.php index 88866e2d..28a879ce 100644 --- a/src/sammo/Json.php +++ b/src/sammo/Json.php @@ -34,7 +34,7 @@ class Json } public static function decodeObj($value){ - //NOTE: 구 코드가 모두 '배열'을 가정하기 때문에 decode는 연관배열로 반환하였으나, + //NOTE: 구 코드가 모두 '배열'을 가정하기 때문에 decode는 연관배열로 반환하였으나, //호환을 위해서는object로 반환하는 것이 더 나을것 return json_decode($value); } @@ -45,12 +45,20 @@ class Json if ($flag & static::NO_CACHE) { WebUtil::setHeaderNoCache(); } - + header('Content-Type: application/json'); - + if($flag & static::PASS_THROUGH){ die($value); } die(Json::encode($value, $flag)); } + + /** @return never */ + public static function dieWithReason(string $reason){ + static::die([ + 'result'=>false, + 'reason'=>$reason + ]); + } } diff --git a/src/sammo/TimeUtil.php b/src/sammo/TimeUtil.php index 46881e14..e451c35b 100644 --- a/src/sammo/TimeUtil.php +++ b/src/sammo/TimeUtil.php @@ -1,6 +1,9 @@ format('Y-m-d'); } - public static function now(bool $withFraction=false):string + public static function now(bool $withFraction = false): string { $obj = new \DateTime(); - if(!$withFraction){ + if (!$withFraction) { return $obj->format('Y-m-d H:i:s'); } return $obj->format('Y-m-d H:i:s.u'); } - public static function nowAddDays($day, bool $withFraction=false):string + public static function nowAddDays($day, bool $withFraction = false): string { $obj = new \DateTime(); $obj->add(static::secondsToDateInterval($day * 3600 * 24)); - if(!$withFraction){ + if (!$withFraction) { return $obj->format('Y-m-d H:i:s'); } return $obj->format('Y-m-d H:i:s.u'); } - public static function nowAddHours($hour, bool $withFraction=false):string + public static function nowAddHours($hour, bool $withFraction = false): string { $obj = new \DateTime(); $obj->add(static::secondsToDateInterval($hour * 3600)); - if(!$withFraction){ + if (!$withFraction) { return $obj->format('Y-m-d H:i:s'); } return $obj->format('Y-m-d H:i:s.u'); } - public static function nowAddMinutes($minute, bool $withFraction=false):string + public static function nowAddMinutes($minute, bool $withFraction = false): string { $obj = new \DateTime(); $obj->add(static::secondsToDateInterval($minute * 60)); - if(!$withFraction){ + if (!$withFraction) { return $obj->format('Y-m-d H:i:s'); } return $obj->format('Y-m-d H:i:s.u'); } - public static function nowAddSeconds($second, bool $withFraction=false):string + public static function nowAddSeconds($second, bool $withFraction = false): string { $obj = new \DateTime(); $obj->add(static::secondsToDateInterval($second)); - if(!$withFraction){ + if (!$withFraction) { return $obj->format('Y-m-d H:i:s'); } return $obj->format('Y-m-d H:i:s.u'); } - public static function secondsToDateTime(float $fullSeconds, bool $isDateTimeImmutable=false): \DateTimeInterface{ + public static function secondsToDateTime(float $fullSeconds, bool $isDateTimeImmutable = false, bool $isUTC = false): \DateTimeInterface + { $seconds = floor($fullSeconds); $fraction = $fullSeconds - $seconds; @@ -139,70 +143,73 @@ class TimeUtil $interval->s = $seconds; $interval->f = $fraction; - if($isDateTimeImmutable){ - $dateTime = new \DateTimeImmutable("@0"); + if ($isDateTimeImmutable) { + $dateTime = new \DateTimeImmutable("@0", $isUTC ? new \DateTimeZone("UTC") : null); return $dateTime->add($interval); } - $dateTime = new \DateTime("@0"); + $dateTime = new \DateTime("@0", $isUTC ? new \DateTimeZone("UTC") : null); $dateTime->add($interval); return $dateTime; } - public static function secondsToDateInterval(float $fullSeconds): \DateInterval{ + public static function secondsToDateInterval(float $fullSeconds): \DateInterval + { $d0 = new \DateTime("@0"); return $d0->diff(static::secondsToDateTime($fullSeconds, true)); } - public static function DateTimeToSeconds(\DateTimeInterface $dateTime): float{ - $d0 = new \DateTimeImmutable("@0"); + public static function DateTimeToSeconds(\DateTimeInterface $dateTime, bool $isUTC = false): float + { + $d0 = new \DateTimeImmutable("@0", $isUTC ? new \DateTimeZone("UTC") : null); return static::DateIntervalToSeconds($d0->diff($dateTime)); } - public static function DateIntervalToSeconds(\DateInterval $interval): float{ - if($interval->days !== FALSE){ + public static function DateIntervalToSeconds(\DateInterval $interval): float + { + if ($interval->days !== FALSE) { $days = $interval->days; - } - else{ - if($interval->y != 0){ + } else { + if ($interval->y != 0) { throw new \InvalidArgumentException('Year argument conversion is not supported'); } - if($interval->m != 0){ + if ($interval->m != 0) { throw new \InvalidArgumentException('Month argument conversion is not supported'); } $days = $interval->d; } - + $hours = $days * 24 + $interval->h; $minutes = $hours * 60 + $interval->i; $seconds = $minutes * 60 + $interval->s + $interval->f; - + return $seconds; } /** * $baseYear, $baseMonth 부터 $afterMonth 개월 이내인지. $afterMonth 포함. - * + * */ - public static function IsRangeMonth(int $baseYear, int $baseMonth, int $afterMonth, int $askYear, int $askMonth):bool{ - if($baseMonth < 1 || $baseMonth > 12){ + public static function IsRangeMonth(int $baseYear, int $baseMonth, int $afterMonth, int $askYear, int $askMonth): bool + { + if ($baseMonth < 1 || $baseMonth > 12) { throw new \InvalidArgumentException('개월이 올바르지 않음'); } - if($askMonth < 1 || $askMonth > 12){ + if ($askMonth < 1 || $askMonth > 12) { throw new \InvalidArgumentException('개월이 올바르지 않음'); } $minMonth = $baseYear * 12 + $baseMonth; - if($afterMonth < 0){ + if ($afterMonth < 0) { $maxMonth = $minMonth; $minMonth = $maxMonth - $afterMonth; } $maxMonth = $minMonth + $afterMonth; $askMonth = $askYear * 12 + $askMonth; - if($askMonth < $minMonth || $maxMonth < $askMonth){ + if ($askMonth < $minMonth || $maxMonth < $askMonth) { return false; } return true;