Compare commits

..
2 Commits
Author SHA1 Message Date
sars f0d7b5e257 Merge branch 'devel' into userName 2024-05-27 02:47:54 +09:00
sars a0771d804f iOS에서 hover가 먹히게 div에 onClick추가 2024-05-26 00:45:19 -07:00
363 changed files with 3443 additions and 135491 deletions
-1
View File
@@ -29,7 +29,6 @@ d_pic/*.jpg
d_pic/*.gif d_pic/*.gif
d_pic/*.png d_pic/*.png
d_pic/*.webp d_pic/*.webp
d_pic/*.avif
d_pic/uploaded_image d_pic/uploaded_image
/dist_js /dist_js
+1
View File
@@ -12,6 +12,7 @@
} }
}, },
"require": { "require": {
"brandonwamboldt/utilphp": "^1.1",
"sergeytsalkov/meekrodb": "^2.5", "sergeytsalkov/meekrodb": "^2.5",
"league/plates": "^3.5", "league/plates": "^3.5",
"vlucas/valitron": "^1.4", "vlucas/valitron": "^1.4",
Generated
+52 -2
View File
@@ -4,8 +4,58 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "7edae9b6be35e66ffd0d180f5fac6679", "content-hash": "deed9afdc95bc42f84784df67d295223",
"packages": [ "packages": [
{
"name": "brandonwamboldt/utilphp",
"version": "1.1.0",
"source": {
"type": "git",
"url": "https://github.com/brandonwamboldt/utilphp.git",
"reference": "36c32efc4f0679c05163464a550f45c8d83fe683"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/brandonwamboldt/utilphp/zipball/36c32efc4f0679c05163464a550f45c8d83fe683",
"reference": "36c32efc4f0679c05163464a550f45c8d83fe683",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"require-dev": {
"satooshi/php-coveralls": "dev-master"
},
"type": "library",
"autoload": {
"psr-0": {
"utilphp\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Brandon Wamboldt",
"email": "brandon.wamboldt@gmail.com"
}
],
"description": "util.php is a collection of useful functions and snippets that you need or could use every day, designed to avoid conflicts with existing projects",
"homepage": "https://github.com/brandonwamboldt/utilphp",
"keywords": [
"collection",
"helpers",
"php",
"utility"
],
"support": {
"issues": "https://github.com/brandonwamboldt/utilphp/issues",
"source": "https://github.com/brandonwamboldt/utilphp/tree/master"
},
"time": "2015-02-02T17:56:14+00:00"
},
{ {
"name": "brick/math", "name": "brick/math",
"version": "0.12.1", "version": "0.12.1",
@@ -5671,5 +5721,5 @@
"platform-overrides": { "platform-overrides": {
"php": "8.3" "php": "8.3"
}, },
"plugin-api-version": "2.6.0" "plugin-api-version": "2.3.0"
} }
+1 -4
View File
@@ -99,10 +99,7 @@ function logError(string $err, string $errstr, string $errpath, array $trace)
$err = str_replace(ROOT, '{ROOT}', $err); $err = str_replace(ROOT, '{ROOT}', $err);
$errstr = str_replace(ROOT, '{ROOT}', $errstr); $errstr = str_replace(ROOT, '{ROOT}', $errstr);
$errpath = str_replace(ROOT, '{ROOT}', $errpath); $errpath = str_replace(ROOT, '{ROOT}', $errpath);
$trace = array_map(function (string|array $text) { $trace = array_map(function (string $text) {
if (is_array($text)) {
$text = Json::encode($text);
}
return str_replace(ROOT, '{ROOT}', $text); return str_replace(ROOT, '{ROOT}', $text);
}, $trace); }, $trace);
+1 -1
View File
@@ -56,7 +56,7 @@ $rootDB->insert('member', [
'token_valid_until' => '2999-01-01 00:00:00', 'token_valid_until' => '2999-01-01 00:00:00',
'pw' => $finalPassword, 'pw' => $finalPassword,
'salt' => $userSalt, 'salt' => $userSalt,
'grade' => 7, 'grade' => 6,
'name' => $nickname, 'name' => $nickname,
'reg_date' => $nowDate 'reg_date' => $nowDate
]); ]);
-10
View File
@@ -93,13 +93,3 @@ CREATE TABLE `login_token` (
) )
COLLATE='utf8mb4_general_ci' COLLATE='utf8mb4_general_ci'
ENGINE=Aria; ENGINE=Aria;
CREATE TABLE `banned_member` (
`no` INT NOT NULL AUTO_INCREMENT,
`hashed_email` VARCHAR(128) NOT NULL COLLATE 'utf8mb4_general_ci' COMMENT 'SHA512(salt | email | salt )',
`info` TEXT NULL COLLATE 'utf8mb4_general_ci' COMMENT '부가정보',
PRIMARY KEY (`no`),
UNIQUE INDEX `email` (`hashed_email`(128))
)
COLLATE='utf8mb4_general_ci'
ENGINE = Aria;
+2 -5
View File
@@ -13,9 +13,6 @@ $db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env'); $gameStor = KVStorage::getStorage($db, 'game_env');
[$turntime, $tnmt_time] = $gameStor->getValuesAsArray(['turntime','tnmt_time']); [$turntime, $tnmt_time] = $gameStor->getValuesAsArray(['turntime','tnmt_time']);
$clock = GameClock::fromStorage($gameStor);
$turntimeDisplay = $clock->formatTick(Util::toInt($turntime), true);
$tnmtTimeDisplay = $tnmt_time === null ? '-' : $clock->formatTick(Util::toInt($tnmt_time), true);
$plock = $db->queryFirstField('SELECT plock FROM plock WHERE `type` ="GAME"'); $plock = $db->queryFirstField('SELECT plock FROM plock WHERE `type` ="GAME"');
?> ?>
@@ -33,8 +30,8 @@ $plock = $db->queryFirstField('SELECT plock FROM plock WHERE `type` ="GAME"');
</head> </head>
<body> <body>
<form action=_119_b.php method=post> <form action=_119_b.php method=post>
시간조정 : <input type=text size=3 name=minute><input type=submit name=btn value='분당김'><input type=submit name=btn value='분지연'> 최종갱신 : <?=$turntimeDisplay?> (tick <?=$turntime?>)<br> 시간조정 : <input type=text size=3 name=minute><input type=submit name=btn value='분당김'><input type=submit name=btn value='분지연'> 최종갱신 : <?=$turntime?><br>
시간조정 : <input type=text size=3 name=minute2><input type=submit name=btn value='토너분당김'><input type=submit name=btn value='토너분지연'> 토너먼트 : <?=$tnmtTimeDisplay?> (tick <?=$tnmt_time?>)<br> 시간조정 : <input type=text size=3 name=minute2><input type=submit name=btn value='토너분당김'><input type=submit name=btn value='토너분지연'> 토너먼트 : <?=$tnmt_time?><br>
봉급지급 : <input type=submit name=btn value='금지급'><input type=submit name=btn value='쌀지급'><br> 봉급지급 : <input type=submit name=btn value='금지급'><input type=submit name=btn value='쌀지급'><br>
락 풀 기 : <input type=submit name=btn value='락걸기'><input type=submit name=btn value='락풀기'> 현재 : <?=$plock>0?"동결중":"가동중"?><br> 락 풀 기 : <input type=submit name=btn value='락걸기'><input type=submit name=btn value='락풀기'> 현재 : <?=$plock>0?"동결중":"가동중"?><br>
</form> </form>
+36 -9
View File
@@ -38,9 +38,21 @@ switch ($btn) {
usleep(500000); usleep(500000);
} }
$clock = GameClock::fromStorage($gameStor); $gameStor->cacheValues(['turntime', 'starttime', 'tnmt_time']);
// 스케줄 전체를 벽시계에서 빼지 않고 논리 현재 tick만 앞으로 이동합니다. $turntime = (new \DateTimeImmutable($gameStor->turntime))->sub(new \DateInterval("PT{$minute}M"));
$clock->advance($gameStor, $clock->ticksFromMinutes($minute)); $starttime = (new \DateTimeImmutable($gameStor->starttime))->sub(new \DateInterval("PT{$minute}M"));
$tnmt_time = (new \DateTimeImmutable($gameStor->tnmt_time))->sub(new \DateInterval("PT{$minute}M"));
$gameStor->turntime = $turntime->format('Y-m-d H:i:s.u');
$gameStor->starttime = $starttime->format('Y-m-d H:i:s');
$gameStor->tnmt_time = $tnmt_time->format('Y-m-d H:i:s');
$db->update('general', [
'turntime' => $db->sqleval('DATE_SUB(turntime, INTERVAL %i MINUTE)', $minute)
], true);
$db->update('ng_auction', [
'close_date' => $db->sqleval('DATE_SUB(close_date, INTERVAL %i MINUTE)', $minute)
], 'finished = 0');
if ($locked) { if ($locked) {
unlock(); unlock();
} }
@@ -54,19 +66,34 @@ switch ($btn) {
} }
usleep(500000); usleep(500000);
} }
$clock = GameClock::fromStorage($gameStor); $gameStor->cacheValues(['turntime', 'starttime', 'tnmt_time']);
$clock->advance($gameStor, -$clock->ticksFromMinutes($minute)); $turntime = (new \DateTimeImmutable($gameStor->turntime))->add(new \DateInterval("PT{$minute}M"));
$starttime = (new \DateTimeImmutable($gameStor->starttime))->add(new \DateInterval("PT{$minute}M"));
$tnmt_time = (new \DateTimeImmutable($gameStor->tnmt_time))->add(new \DateInterval("PT{$minute}M"));
$gameStor->turntime = $turntime->format('Y-m-d H:i:s.u');
$gameStor->starttime = $starttime->format('Y-m-d H:i:s');
$gameStor->tnmt_time = $tnmt_time->format('Y-m-d H:i:s');
$db->update('general', [
'turntime' => $db->sqleval('DATE_ADD(turntime, INTERVAL %i MINUTE)', $minute)
], true);
$db->update('ng_auction', [
'close_date' => $db->sqleval('DATE_ADD(close_date, INTERVAL %i MINUTE)', $minute)
], 'finished = 0');
if ($locked) { if ($locked) {
unlock(); unlock();
} }
break; break;
case "토너분당김": case "토너분당김":
$clock = GameClock::fromStorage($gameStor); $tnmt_time = new \DateTime($gameStor->tnmt_time);
$gameStor->tnmt_time = Util::toInt($gameStor->tnmt_time) - $clock->ticksFromMinutes($minute2); $tnmt_time->sub(new \DateInterval("PT{$minute2}M"));
$gameStor->tnmt_time = $tnmt_time->format('Y-m-d H:i:s');
break; break;
case "토너분지연": case "토너분지연":
$clock = GameClock::fromStorage($gameStor); $tnmt_time = new \DateTimeImmutable($gameStor->tnmt_time);
$gameStor->tnmt_time = Util::toInt($gameStor->tnmt_time) + $clock->ticksFromMinutes($minute2); $tnmt_time->add(new \DateInterval("PT{$minute2}M"));
$gameStor->tnmt_time = $tnmt_time->format('Y-m-d H:i:s');
break; break;
case "금지급": case "금지급":
processGoldIncome(); processGoldIncome();
+3 -3
View File
@@ -6,7 +6,7 @@ include "func.php";
//로그인 검사 //로그인 검사
$session = Session::requireGameLogin()->setReadOnly(); $session = Session::requireGameLogin()->setReadOnly();
if($session->userGrade < 6) { if($session->userGrade < 5) {
die(requireAdminPermissionHTML()); die(requireAdminPermissionHTML());
} }
@@ -40,7 +40,7 @@ $admin = getAdmin();
</tr> </tr>
<tr> <tr>
<td width=110 align=right>시작시간변경</td> <td width=110 align=right>시작시간변경</td>
<td width=285><input type=text size=20 maxlength=20 style=color:white;background-color:black;text-align:right; name=starttime value='<?=substr($admin['starttime_display'], 0, 19)?>'><input type=submit name=btn value=변경1></td> <td width=285><input type=text size=20 maxlength=20 style=color:white;background-color:black;text-align:right; name=starttime value='<?=substr($admin['starttime'], 0, 19)?>'><input type=submit name=btn value=변경1></td>
</tr> </tr>
<tr> <tr>
<td width=110 align=right>최대 장수</td> <td width=110 align=right>최대 장수</td>
@@ -52,7 +52,7 @@ $admin = getAdmin();
<td width=110 align=right>시작 년도</td> <td width=110 align=right>시작 년도</td>
<td width=285><input type=text size=3 maxlength=3 style=color:white;background-color:black;text-align:right; name=startyear value='<?=$admin['startyear']?>'><input type=submit name=btn value=변경4></td> <td width=285><input type=text size=3 maxlength=3 style=color:white;background-color:black;text-align:right; name=startyear value='<?=$admin['startyear']?>'><input type=submit name=btn value=변경4></td>
<td width=110 align=right>최근 갱신 시간</td> <td width=110 align=right>최근 갱신 시간</td>
<td width=285>&nbsp;<?=$admin['turntime_display']?> (tick <?=$admin['turntime']?>)</td> <td width=285>&nbsp;<?=$admin['turntime']?></td>
</tr> </tr>
<tr> <tr>
<td width=110 align=right>턴시간</td> <td width=110 align=right>턴시간</td>
+3 -9
View File
@@ -6,7 +6,7 @@ include "func.php";
//로그인 검사 //로그인 검사
$session = Session::requireGameLogin()->setReadOnly(); $session = Session::requireGameLogin()->setReadOnly();
if ($session->userGrade < 6) { if ($session->userGrade < 5) {
header('location:_admin1.php'); header('location:_admin1.php');
die(); die();
} }
@@ -25,15 +25,13 @@ if (!$v->validate()) {
$msg = Util::getPost('msg'); $msg = Util::getPost('msg');
$btn = Util::getPost('btn'); $btn = Util::getPost('btn');
$log = Util::getPost('log'); $log = Util::getPost('log');
$starttime = Util::getPost('starttime', 'string', null); $starttime = Util::getPost('starttime', 'string', (new \DateTime())->format('Y-m-d H:i:s'));
$maxgeneral = Util::getPost('maxgeneral', 'int', GameConst::$defaultMaxGeneral); $maxgeneral = Util::getPost('maxgeneral', 'int', GameConst::$defaultMaxGeneral);
$maxnation = Util::getPost('maxnation', 'int', GameConst::$defaultMaxNation); $maxnation = Util::getPost('maxnation', 'int', GameConst::$defaultMaxNation);
$startyear = Util::getPost('startyear', 'int', GameConst::$defaultStartYear); $startyear = Util::getPost('startyear', 'int', GameConst::$defaultStartYear);
$db = DB::db(); $db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env'); $gameStor = KVStorage::getStorage($db, 'game_env');
$clock = GameClock::fromStorage($gameStor);
$starttime ??= $clock->formatTick($clock->nowTick());
$admin = getAdmin(); $admin = getAdmin();
@@ -45,11 +43,7 @@ switch ($btn) {
pushGlobalHistoryLog(["<R>★</><S>{$log}</>"]); pushGlobalHistoryLog(["<R>★</><S>{$log}</>"]);
break; break;
case "변경1": case "변경1":
$gameStor->clock_base_time = TimeUtil::format(GameClock::baseTimeForProjection( $gameStor->starttime = (new \DateTime($starttime))->format('Y-m-d H:i:s');
new \DateTimeImmutable($starttime),
Util::toInt($gameStor->starttime),
$clock->getTurnTermMinutes(),
), true);
break; break;
case "변경2": case "변경2":
$gameStor->maxgeneral = $maxgeneral; $gameStor->maxgeneral = $maxgeneral;
+1 -1
View File
@@ -7,7 +7,7 @@ include "func.php";
//로그인 검사 //로그인 검사
$session = Session::requireGameLogin()->setReadOnly(); $session = Session::requireGameLogin()->setReadOnly();
if ($session->userGrade < 6) { if ($session->userGrade < 5) {
die(requireAdminPermissionHTML()); die(requireAdminPermissionHTML());
} }
+10 -10
View File
@@ -15,7 +15,7 @@ $msg = Util::getPost('msg', 'string');
//로그인 검사 //로그인 검사
$session = Session::requireLogin()->loginGame()->setReadOnly(); $session = Session::requireLogin()->loginGame()->setReadOnly();
if ($session->userGrade < 6) { if ($session->userGrade < 5) {
header('location:_admin2.php'); header('location:_admin2.php');
} }
@@ -99,7 +99,7 @@ switch ($btn) {
], '`no` IN %li', $genlist); ], '`no` IN %li', $genlist);
break; break;
case "강제 사망": case "강제 사망":
$date = GameClock::fromStorage($gameStor)->nowTick(); $date = TimeUtil::now(true);
$db->update('general', [ $db->update('general', [
'killturn' => 0, 'killturn' => 0,
'turntime' => $date, 'turntime' => $date,
@@ -113,7 +113,7 @@ switch ($btn) {
case "경험치1000": case "경험치1000":
$text = $btn . " 지급!"; $text = $btn . " 지급!";
foreach ($genlist as $generalID) { foreach ($genlist as $generalID) {
$msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, Message::gameNow(), new \DateTime('9999-12-31'), []); $msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
$msg->send(true); $msg->send(true);
} }
$db->update('general', [ $db->update('general', [
@@ -124,7 +124,7 @@ switch ($btn) {
case "공헌치1000": case "공헌치1000":
$text = $btn . " 지급!"; $text = $btn . " 지급!";
foreach ($genlist as $generalID) { foreach ($genlist as $generalID) {
$msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, Message::gameNow(), new \DateTime('9999-12-31'), []); $msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
$msg->send(true); $msg->send(true);
} }
$db->update('general', [ $db->update('general', [
@@ -135,7 +135,7 @@ switch ($btn) {
case "보숙10000": case "보숙10000":
$text = "보병숙련도+10000 지급!"; $text = "보병숙련도+10000 지급!";
foreach ($genlist as $generalID) { foreach ($genlist as $generalID) {
$msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, Message::gameNow(), new \DateTime('9999-12-31'), []); $msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
$msg->send(true); $msg->send(true);
} }
$db->update('general', [ $db->update('general', [
@@ -145,7 +145,7 @@ switch ($btn) {
case "궁숙10000": case "궁숙10000":
$text = "궁병숙련도+10000 지급!"; $text = "궁병숙련도+10000 지급!";
foreach ($genlist as $generalID) { foreach ($genlist as $generalID) {
$msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, Message::gameNow(), new \DateTime('9999-12-31'), []); $msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
$msg->send(true); $msg->send(true);
} }
$db->update('general', [ $db->update('general', [
@@ -156,7 +156,7 @@ switch ($btn) {
$src = MessageTarget::buildQuick($session->generalID); $src = MessageTarget::buildQuick($session->generalID);
$text = "기병숙련도+10000 지급!"; $text = "기병숙련도+10000 지급!";
foreach ($genlist as $generalID) { foreach ($genlist as $generalID) {
$msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, Message::gameNow(), new \DateTime('9999-12-31'), []); $msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
$msg->send(true); $msg->send(true);
} }
$db->update('general', [ $db->update('general', [
@@ -167,7 +167,7 @@ switch ($btn) {
$src = MessageTarget::buildQuick($session->generalID); $src = MessageTarget::buildQuick($session->generalID);
$text = "귀병숙련도+10000 지급!"; $text = "귀병숙련도+10000 지급!";
foreach ($genlist as $generalID) { foreach ($genlist as $generalID) {
$msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, Message::gameNow(), new \DateTime('9999-12-31'), []); $msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
$msg->send(true); $msg->send(true);
} }
$db->update('general', [ $db->update('general', [
@@ -178,7 +178,7 @@ switch ($btn) {
$src = MessageTarget::buildQuick($session->generalID); $src = MessageTarget::buildQuick($session->generalID);
$text = "차병숙련도+10000 지급!"; $text = "차병숙련도+10000 지급!";
foreach ($genlist as $generalID) { foreach ($genlist as $generalID) {
$msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, Message::gameNow(), new \DateTime('9999-12-31'), []); $msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
$msg->send(true); $msg->send(true);
} }
$db->update('general', [ $db->update('general', [
@@ -198,7 +198,7 @@ switch ($btn) {
case "메세지 전달": case "메세지 전달":
$text = $msg ?? ''; $text = $msg ?? '';
foreach ($genlist as $generalID) { foreach ($genlist as $generalID) {
$msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, Message::gameNow(), new \DateTime('9999-12-31'), []); $msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
$msg->send(true); $msg->send(true);
} }
break; break;
+1 -1
View File
@@ -20,7 +20,7 @@ if ($type2 < 0 || $type2 > 6) {
//로그인 검사 //로그인 검사
$session = Session::requireGameLogin()->setReadOnly(); $session = Session::requireGameLogin()->setReadOnly();
if ($session->userGrade < 6) { if ($session->userGrade < 5) {
die(requireAdminPermissionHTML()); die(requireAdminPermissionHTML());
} }
+1 -1
View File
@@ -12,7 +12,7 @@ $nation = Util::getPost('nation', 'int');
$session = Session::requireGameLogin()->setReadOnly(); $session = Session::requireGameLogin()->setReadOnly();
$userID = Session::getUserID(); $userID = Session::getUserID();
if ($session->userGrade < 6) { if ($session->userGrade < 5) {
header('location:_admin5.php'); header('location:_admin5.php');
die(); die();
} }
+3 -4
View File
@@ -31,18 +31,17 @@ $queryMap = [
]; ];
if ($reqQueryType === null || !key_exists($reqQueryType, $queryMap)) { if ($reqQueryType === null || !key_exists($reqQueryType, $queryMap)) {
$reqQueryType = array_key_first($queryMap); $reqQueryType = Util::array_first_key($queryMap);
} }
//로그인 검사 //로그인 검사
$session = Session::requireGameLogin()->setReadOnly(); $session = Session::requireGameLogin()->setReadOnly();
if ($session->userGrade < 6) { if ($session->userGrade < 5) {
die(requireAdminPermissionHTML()); die(requireAdminPermissionHTML());
} }
$db = DB::db(); $db = DB::db();
$clock = GameClock::fromStorage(KVStorage::getStorage($db, 'game_env'));
if ($btn == '정렬하기') { if ($btn == '정렬하기') {
$gen = 0; $gen = 0;
@@ -112,7 +111,7 @@ $generalObj = General::createObjFromDB($gen, null, GeneralQueryMode::FullWithAcc
대상장수 : 대상장수 :
<select name=gen size=1> <select name=gen size=1>
<?php foreach ($generalBasicList as $general) : ?> <?php foreach ($generalBasicList as $general) : ?>
<option <?= $gen == $general['no'] ? 'selected' : '' ?> value='<?= $general['no'] ?>'><?= $general['name'] ?> (<?= substr($clock->formatTick(Util::toInt($general['turntime'])), 14, 5) ?>)</option> <option <?= $gen == $general['no'] ? 'selected' : '' ?> value='<?= $general['no'] ?>'><?= $general['name'] ?> (<?= substr($general['turntime'], 14, 5) ?>)</option>
<?php endforeach; ?> <?php endforeach; ?>
</select> </select>
<input type=submit name=btn value='조회하기'> <input type=submit name=btn value='조회하기'>
+3 -1
View File
@@ -12,7 +12,7 @@ $type = 0;
//로그인 검사 //로그인 검사
$session = Session::requireGameLogin()->setReadOnly(); $session = Session::requireGameLogin()->setReadOnly();
if ($session->userGrade < 6) { if ($session->userGrade < 5) {
die(requireAdminPermissionHTML()); die(requireAdminPermissionHTML());
} }
@@ -100,6 +100,8 @@ $sel[$type] = "selected";
throw new \Exception("알 수 없는 외교 상태: {$dip['state']}"); throw new \Exception("알 수 없는 외교 상태: {$dip['state']}");
} }
$date = TimeUtil::now();
echo " echo "
<tr> <tr>
<td align=center style=color:" . newColor($nationColor[$me]) . ";background-color:{$nationColor[$me]};>$nationName[$me]</td> <td align=center style=color:" . newColor($nationColor[$me]) . ";background-color:{$nationColor[$me]};>$nationName[$me]</td>
+1 -1
View File
@@ -7,7 +7,7 @@ include "func.php";
//로그인 검사 //로그인 검사
$session = Session::requireGameLogin()->setReadOnly(); $session = Session::requireGameLogin()->setReadOnly();
if ($session->userGrade < 6) { if ($session->userGrade < 5) {
die('권한 부족'); die('권한 부족');
} }
+1 -4
View File
@@ -243,14 +243,11 @@ $templates = new \League\Plates\Engine(__DIR__ . '/templates');
"SELECT nation,no,name,owner_name as ownerName, owner, picture, imgsvr, "SELECT nation,no,name,owner_name as ownerName, owner, picture, imgsvr,
experience, dedication, experience, dedication,
dex1, dex2, dex3, dex4, dex5, dex1, dex2, dex3, dex4, dex5,
horse, weapon, book, item, aux horse, weapon, book, item
FROM general WHERE %l", FROM general WHERE %l",
$btn == "NPC 보기" ? "npc>=2" : "npc<2" $btn == "NPC 보기" ? "npc>=2" : "npc<2"
) as $general) { ) as $general) {
$generalID = $general['no']; $generalID = $general['no'];
foreach (['dex1', 'dex2', 'dex3', 'dex4', 'dex5'] as $dexKey) {
$general[$dexKey] = CentennialAllStarGrowthService::recordableRawValue($general, $dexKey);
}
$general['bgColor'] = $nationColor[$general['nation']] ?? GameConst::$basecolor4; $general['bgColor'] = $nationColor[$general['nation']] ?? GameConst::$basecolor4;
$general['fgColor'] = newColor($general['bgColor']); $general['fgColor'] = newColor($general['bgColor']);
$general['nationName'] = $nationName[$general['nation']]; $general['nationName'] = $nationName[$general['nation']];
+15 -4
View File
@@ -32,11 +32,9 @@ if ($type <= 0 || $type > 15) {
} }
$ownerNameList = []; $ownerNameList = [];
if ($gameStor->isunited) {
foreach (RootDB::db()->queryAllLists('SELECT no, name FROM member') as [$ownerID, $ownerName]) { foreach (RootDB::db()->queryAllLists('SELECT no, name FROM member') as [$ownerID, $ownerName]) {
$ownerNameList[$ownerID] = $ownerName; $ownerNameList[$ownerID] = $ownerName;
} }
}
?> ?>
<!DOCTYPE html> <!DOCTYPE html>
@@ -54,6 +52,15 @@ if ($gameStor->isunited) {
<?= WebUtil::printDist('vue', [], true) ?> <?= WebUtil::printDist('vue', [], true) ?>
<?= WebUtil::printDist('ts', 'common') ?> <?= WebUtil::printDist('ts', 'common') ?>
<style>
.hidden {
display: none;
}
.generalName:hover > .hidden {
display: block;
}
</style>
</head> </head>
<body> <body>
@@ -168,7 +175,11 @@ if ($gameStor->isunited) {
$name = formatName($general['name'], $general['npc']); $name = formatName($general['name'], $general['npc']);
if (key_exists($general['owner'], $ownerNameList)) { if (key_exists($general['owner'], $ownerNameList)) {
$name = $name . '<br><small>(' . $ownerNameList[$general['owner']] . ')</small>'; if ($gameStor->isunited) {
$name = $name . '<br><small class=\'userName\'>(' . $ownerNameList[$general['owner']] . ')</small>';
} else {
$name = $name . '<br><small class=\'userName hidden\'>(' . $ownerNameList[$general['owner']] . ')</small>';
}
} }
$general['refresh_score_total'] = Util::round($general['refresh_score_total'], -1); $general['refresh_score_total'] = Util::round($general['refresh_score_total'], -1);
@@ -185,7 +196,7 @@ if ($gameStor->isunited) {
data-npc-type='{$general['npc']}' data-npc-type='{$general['npc']}'
> >
<td align=center><img class='generalIcon' width='64' height='64' src='{$imageTemp}/{$general['picture']}'></img></td> <td align=center><img class='generalIcon' width='64' height='64' src='{$imageTemp}/{$general['picture']}'></img></td>
<td align=center>$name</td> <td align=center class='generalName' onclick=''>$name</td>
<td align=center>{$general['age']}세</td> <td align=center>{$general['age']}세</td>
<td align=center>" . displayCharInfo($general['personal']) . "</td> <td align=center>" . displayCharInfo($general['personal']) . "</td>
<td align=center>" . displaySpecialDomesticInfo($general['special']) . " / " . displaySpecialWarInfo($general['special2']) . "</td> <td align=center>" . displaySpecialDomesticInfo($general['special']) . " / " . displaySpecialWarInfo($general['special2']) . "</td>
+1 -2
View File
@@ -9,7 +9,6 @@ include "func.php";
$db = DB::db(); $db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env'); $gameStor = KVStorage::getStorage($db, 'game_env');
$clock = GameClock::fromStorage($gameStor);
increaseRefresh("갱신정보", 1); increaseRefresh("갱신정보", 1);
@@ -24,7 +23,7 @@ $recentTraffic[] = [
'month' => $admin['month'], 'month' => $admin['month'],
'refresh' => $admin['refresh'], 'refresh' => $admin['refresh'],
'online' => $curonline, 'online' => $curonline,
'date' => $clock->formatNow() 'date' => TimeUtil::now()
]; ];
if ($admin['maxrefresh'] == 0) { if ($admin['maxrefresh'] == 0) {
+3 -3
View File
@@ -16,7 +16,7 @@ $db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env'); $gameStor = KVStorage::getStorage($db, 'game_env');
increaseRefresh("현재도시", 1); increaseRefresh("현재도시", 1);
$lastExecute = substr(GameClock::fromStorage($gameStor)->formatTick(Util::toInt($gameStor->turntime)), 5, 14); $lastExecute = substr($gameStor->turntime, 5, 14);
$me = $db->queryFirstRow('SELECT no,nation,officer_level,city from general where owner=%i', $userID); $me = $db->queryFirstRow('SELECT no,nation,officer_level,city from general where owner=%i', $userID);
$myNation = $db->queryFirstRow('SELECT nation,level,spy FROM nation WHERE nation=%i', $me['nation']) ?? [ $myNation = $db->queryFirstRow('SELECT nation,level,spy FROM nation WHERE nation=%i', $me['nation']) ?? [
@@ -177,7 +177,7 @@ $templates = new \League\Plates\Engine('templates');
$valid = 1; $valid = 1;
} }
if ($userGrade >= 6) { if ($userGrade >= 5) {
$valid = true; $valid = true;
$showDetailedInfo = true; $showDetailedInfo = true;
} }
@@ -275,7 +275,7 @@ $templates = new \League\Plates\Engine('templates');
$ourGeneral = false; $ourGeneral = false;
} }
if ($userGrade == 7) { if ($userGrade == 6) {
$ourGeneral = true; $ourGeneral = true;
} }
-2
View File
@@ -129,7 +129,6 @@ $templates = new \League\Plates\Engine('templates');
); );
$generalTurnList = []; $generalTurnList = [];
$clock = GameClock::fromStorage($gameStor);
foreach ($db->queryAllLists( foreach ($db->queryAllLists(
'SELECT general_id, turn_idx, brief FROM general_turn WHERE general_id IN %li AND turn_idx < 5 ORDER BY general_id ASC, turn_idx ASC', 'SELECT general_id, turn_idx, brief FROM general_turn WHERE general_id IN %li AND turn_idx < 5 ORDER BY general_id ASC, turn_idx ASC',
@@ -143,7 +142,6 @@ $templates = new \League\Plates\Engine('templates');
$genCntEff = 0; $genCntEff = 0;
foreach ($generals as &$general) { foreach ($generals as &$general) {
$general['turntime'] = $clock->formatTick(Util::toInt($general['turntime']), true);
$general['cityText'] = CityConst::byID($general['city'])->name; $general['cityText'] = CityConst::byID($general['city'])->name;
$general['troopText'] = $troopName[$general['troop']] ?? '-'; $general['troopText'] = $troopName[$general['troop']] ?? '-';
+6 -32
View File
@@ -21,8 +21,8 @@ $generalID = $session->generalID;
$db = DB::db(); $db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env'); $gameStor = KVStorage::getStorage($db, 'game_env');
$gameStor->cacheValues(['turntime', 'opentime', 'autorun_user', 'npcmode']); $gameStor->cacheValues(['turntime', 'opentime', 'autorun_user', 'npcmode']);
$clock = GameClock::fromStorage($gameStor);
$nowTick = $clock->nowTick(); increaseRefresh("내정보", 1);
$me = General::createObjFromDB($generalID, null, GeneralQueryMode::FullWithAccessLog); $me = General::createObjFromDB($generalID, null, GeneralQueryMode::FullWithAccessLog);
@@ -41,30 +41,12 @@ $lastRefresh = $db->queryFirstField(
$generalID $generalID
); );
$nextChange = $me->getAuxVar('next_change'); $targetTime = addTurn($lastRefresh, $gameStor->turnterm, GameConst::$minTurnDieOnPrestart);
if (!is_int($nextChange)) {
$nextChange = null;
}
$nextChangeDisplay = $nextChange === null ? null : $clock->formatTick($nextChange);
increaseRefresh("내정보", 1);
if ($gameStor->turntime <= $gameStor->opentime) { if ($gameStor->turntime <= $gameStor->opentime) {
$targetTime = $me->getAuxVar('prestart_delete_after');
if (!is_int($targetTime)) {
$targetTime = addTurn(
$lastRefresh === null ? $nowTick : Util::toInt($lastRefresh),
$gameStor->turnterm,
GameConst::$minTurnDieOnPrestart
);
$me->setAuxVar('prestart_delete_after', $targetTime);
$me->applyDB($db);
}
$targetTimeDisplay = $clock->formatTick($targetTime);
//서버 가오픈시 할 수 있는 행동 //서버 가오픈시 할 수 있는 행동
if ($me->getNPCType() == 0 && $me->getNationID() == 0) { if ($me->getNPCType() == 0 && $me->getNationID() == 0) {
$showDieOnPrestartBtn = true; $showDieOnPrestartBtn = true;
if ($targetTime <= $nowTick) { if ($targetTime <= TimeUtil::now()) {
$availableDieOnPrestart = true; $availableDieOnPrestart = true;
} }
} }
@@ -161,14 +143,6 @@ $changeDefence999Atmos = $me->onCalcDomestic('changeDefenceTrain', "atmos999", $
】<br><br> 】<br><br>
<input type=<?= $submit ?> id='set_my_setting' name=btn style=background-color:<?= GameConst::$basecolor2 ?>;color:white;width:160px;height:30px;font-size:14px; value=설정저장><br> <input type=<?= $submit ?> id='set_my_setting' name=btn style=background-color:<?= GameConst::$basecolor2 ?>;color:white;width:160px;height:30px;font-size:14px; value=설정저장><br>
∞<span style='color:orange'>설정저장은 이달중 <?= $myset ?>회 남았습니다.</span><br><br> ∞<span style='color:orange'>설정저장은 이달중 <?= $myset ?>회 남았습니다.</span><br><br>
<?php if ($me->getPenaltyList()->count()) : ?>
징계 목록(저장 시 갱신)<br>
<?php foreach ($me->getPenaltyList() as $penaltyKey => $penalty) : ?>
<span style='color:red'><?= $penaltyKey->getHelptext() ?> : <?= $penalty ?></span><br>
<?php endforeach; ?>
<br />
<?php endif; ?>
<?php if (!($gameStor->autorun_user['limit_minutes'] ?? false)) : ?> <?php if (!($gameStor->autorun_user['limit_minutes'] ?? false)) : ?>
휴 가 신 청<br> 휴 가 신 청<br>
<button type="button" id='vacation' style=background-color:<?= GameConst::$basecolor2 ?>;color:white;width:160px;height:30px;font-size:14px;>휴가 신청</button><br><br> <button type="button" id='vacation' style=background-color:<?= GameConst::$basecolor2 ?>;color:white;width:160px;height:30px;font-size:14px;>휴가 신청</button><br><br>
@@ -177,7 +151,7 @@ $changeDefence999Atmos = $me->onCalcDomestic('changeDefenceTrain', "atmos999", $
<a href="b_myPage.php?detachNPC=1"><button type="button" style=background-color:<?= GameConst::$basecolor2 ?>;color:white;width:160px;height:30px;font-size:14px;>빙의 해체 요청</button></a>--> <a href="b_myPage.php?detachNPC=1"><button type="button" style=background-color:<?= GameConst::$basecolor2 ?>;color:white;width:160px;height:30px;font-size:14px;>빙의 해체 요청</button></a>-->
<?php if ($showDieOnPrestartBtn) : ?> <?php if ($showDieOnPrestartBtn) : ?>
가오픈 기간 내 장수 삭제 (<?= $targetTimeDisplay ?> 부터)<br> 가오픈 기간 내 장수 삭제 (<?= substr($targetTime, 0, 19) ?> 부터)<br>
<button type="button" id='dieOnPrestart' style=background-color:<?= GameConst::$basecolor2 ?>;color:white;width:160px;height:30px;font-size:14px;>장수 삭제</button><br><br> <button type="button" id='dieOnPrestart' style=background-color:<?= GameConst::$basecolor2 ?>;color:white;width:160px;height:30px;font-size:14px;>장수 삭제</button><br><br>
<?php endif; ?> <?php endif; ?>
@@ -192,7 +166,7 @@ $changeDefence999Atmos = $me->onCalcDomestic('changeDefenceTrain', "atmos999", $
<?php endif; ?> <?php endif; ?>
<?php if ($gameStor->npcmode == 2 && $me->getNPCType() == 0) : ?> <?php if ($gameStor->npcmode == 2 && $me->getNPCType() == 0) : ?>
다른 장수 선택 (<?= $nextChangeDisplay ?? '지금' ?>부터)<br> 다른 장수 선택 (<?= substr($me->getAuxVar('next_change') ?? TimeUtil::now(), 0, 19) ?> 부터)<br>
<a href="select_general_from_pool.php" id='select_general_from_pool'><button type="button" style=background-color:<?= GameConst::$basecolor2 ?>;color:white;width:160px;height:30px;font-size:14px;>다른 장수 선택</button></a><br><br> <a href="select_general_from_pool.php" id='select_general_from_pool'><button type="button" style=background-color:<?= GameConst::$basecolor2 ?>;color:white;width:160px;height:30px;font-size:14px;>다른 장수 선택</button></a><br><br>
<?php endif; ?> <?php endif; ?>
+57 -1
View File
@@ -125,7 +125,63 @@ $globalBetTotal = array_sum($globalBet);
</tr> </tr>
</table> </table>
<table align=center class='tb_layout bg0'> <table align=center class='tb_layout bg0'>
<?php if ($me['no'] > 0 && $me['tournament'] == 0 && $admin['tournament'] == 1) : ?> <?php if ($session->userGrade >= 5) : ?>
<form method=post action=c_tournament.php>
<tr>
<td colspan=8><input type=textarea size=150 style=color:white;background-color:black; name=msg><input type=submit name=btn value='메시지'></td>
</tr>
<tr>
<td colspan=8>
<button type="button" class="btn btn-secondary" onclick='location.reload()'>갱신</button>
<?php if ($admin['tournament'] == 0) : ?>
<select name=trig size=1 style=color:white;background-color:black;>
<option style=color:white; value=0 <?= !$admin['tnmt_trig'] ? 'selected' : '' ?>>수동진행</option>
<option style=color:white; value=1 <?= $admin['tnmt_trig'] ? 'selected' : '' ?>>자동진행</option>
</select>
<input type=submit name=btn value='자동개최설정'>
<?php else : ?>
<input type=submit name=btn value='중단' onclick='return confirm("진짜 중단하시겠습니까?")'>
<?php endif; ?>
<?php switch ($admin['tournament']) {
case 1:
echo "<input type=submit name=btn value='랜덤투입'>";
echo "<input type=submit name=btn value='랜덤전부투입'>";
break;
case 2:
echo "<input type=submit name=btn value='예선'><input type=submit name=btn value='예선전부'>";
break;
case 3:
echo "<input type=submit name=btn value='추첨'><input type=submit name=btn value='추첨전부'>";
break;
case 4:
echo "<input type=submit name=btn value='본선'><input type=submit name=btn value='본선전부'>";
break;
case 5:
echo "<input type=submit name=btn value='배정'>";
break;
case 6:
echo "<input type=submit name=btn value='베팅마감'>";
break;
case 7:
echo "<input type=submit name=btn value='16강'>";
break;
case 8:
echo "<input type=submit name=btn value='8강'>";
break;
case 9:
echo "<input type=submit name=btn value='4강'>";
break;
case 10:
echo "<input type=submit name=btn value='결승'>";
break;
} ?>
</td>
</tr>
</form>
<?php elseif ($me['no'] > 0 && $me['tournament'] == 0 && $admin['tournament'] == 1) : ?>
<form method=post action=c_tournament.php> <form method=post action=c_tournament.php>
<tr> <tr>
<td colspan=8><button type="button" class="btn btn-secondary" onclick='location.reload()'>갱신</button><button type="submit" class="btn btn-sammo-base2" onclick='return confirm("참가비 금<?= $admin['develcost'] ?>이 필요합니다. 참가하시겠습니까?")'>참가</button><input type='hidden' name='btn' value='참가'/></td> <td colspan=8><button type="button" class="btn btn-secondary" onclick='location.reload()'>갱신</button><button type="submit" class="btn btn-sammo-base2" onclick='return confirm("참가비 금<?= $admin['develcost'] ?>이 필요합니다. 참가하시겠습니까?")'>참가</button><input type='hidden' name='btn' value='참가'/></td>
+2 -2
View File
@@ -228,10 +228,10 @@ if($btn == "자동개최설정") {
$phase = 0; $phase = 0;
startBetting($admin['tnmt_type'], 720); startBetting($admin['tnmt_type'], 720);
} elseif($btn == "베팅마감") { } elseif($btn == "베팅마감") {
$clock = GameClock::fromStorage($gameStor); $dt = date("Y-m-d H:i:s", time() + 60);
$gameStor->tournament=7; $gameStor->tournament=7;
$gameStor->phase=0; $gameStor->phase=0;
$gameStor->tnmt_time = $clock->nowTick() + $clock->ticksFromSeconds(60); $gameStor->tnmt_time = $dt;
} elseif($btn == "16강") { } elseif($btn == "16강") {
finalFight($admin['tnmt_type'], $admin['tournament'], $admin['phase'], 16); finalFight($admin['tnmt_type'], $admin['tournament'], $admin['phase'], 16);
} elseif($btn == "8강") { } elseif($btn == "8강") {
-16
View File
@@ -51,22 +51,6 @@
display: none; display: none;
} }
.picture_choice {
margin: 8px auto;
}
.picture_choice label,
.event_picture label {
display: inline-flex;
align-items: center;
gap: 4px;
margin: 4px 8px;
}
.picture_choice img {
object-fit: cover;
}
.custom_picture { .custom_picture {
display: none; display: none;
} }
+91 -92
View File
@@ -9,7 +9,6 @@ use sammo\Enums\GeneralAccessLogColumn;
use sammo\Enums\GeneralColumn; use sammo\Enums\GeneralColumn;
use sammo\Enums\GeneralQueryMode; use sammo\Enums\GeneralQueryMode;
use sammo\Enums\InheritanceKey; use sammo\Enums\InheritanceKey;
use sammo\Enums\PenaltyKey;
use sammo\Enums\RankColumn; use sammo\Enums\RankColumn;
require_once 'process_war.php'; require_once 'process_war.php';
@@ -112,7 +111,7 @@ function GetImageURL($imgsvr, $filepath = '')
function checkLimit($refreshScore = null) function checkLimit($refreshScore = null)
{ {
$session = Session::getInstance(); $session = Session::getInstance();
if ($session->userGrade >= 6) { if ($session->userGrade >= 4) {
return 0; return 0;
} }
@@ -377,11 +376,11 @@ function myNationInfo(General $generalObj)
function checkSecretMaxPermission($penalty) function checkSecretMaxPermission($penalty)
{ {
$secretMax = 4; $secretMax = 4;
if ($penalty[PenaltyKey::NoTopSecret->value] ?? false) { if ($penalty['noTopSecret'] ?? false) {
$secretMax = 1; $secretMax = 1;
} else if ($penalty[PenaltyKey::NoChief->value] ?? false) { } else if ($penalty['noChief'] ?? false) {
$secretMax = 1; $secretMax = 1;
} else if ($penalty[PenaltyKey::NoAmbassador->value] ?? false) { } else if ($penalty['noAmbassador'] ?? false) {
$secretMax = 2; $secretMax = 2;
} }
return $secretMax; return $secretMax;
@@ -404,7 +403,7 @@ function checkSecretPermission(array $me, $checkSecretLimit = true)
} }
if ($penalty[PenaltyKey::NoChief->value] ?? false) { if ($penalty['noSecret'] ?? false) {
return 0; return 0;
} }
@@ -630,11 +629,7 @@ function generalInfo(General $generalObj)
$injury = "건강"; $injury = "건강";
} }
$clock = GameClock::fromStorage(KVStorage::getStorage(DB::db(), 'game_env')); $remaining = (new \DateTimeImmutable($generalObj->getTurnTime()))->diff(new \DateTimeImmutable())->i;
$remaining = max(0, intdiv(
$generalObj->getTurnTick() - $clock->nowTick(),
$clock->ticksFromMinutes(1),
));
if ($nation['color'] == "") { if ($nation['color'] == "") {
$nation['color'] = "#000000"; $nation['color'] = "#000000";
@@ -925,36 +920,44 @@ function banner()
); );
} }
function addTurn(int $tick, int $turnterm, int $turn = 1, bool $withFraction = true): int function addTurn($date, int $turnterm, int $turn = 1, bool $withFraction = true)
{ {
return $tick + GameClock::TICKS_PER_TURN * $turn; $date = new \DateTime($date);
$target = $turnterm * $turn;
$date->add(new \DateInterval("PT{$target}M"));
if ($withFraction) {
return $date->format('Y-m-d H:i:s.u');
}
return $date->format('Y-m-d H:i:s');
} }
function subTurn(int $tick, int $turnterm, int $turn = 1, bool $withFraction = true): int function subTurn($date, int $turnterm, int $turn = 1, bool $withFraction = true)
{ {
return $tick - GameClock::TICKS_PER_TURN * $turn; $date = new \DateTime($date);
$target = $turnterm * $turn;
$date->sub(new \DateInterval("PT{$target}M"));
if ($withFraction) {
return $date->format('Y-m-d H:i:s.u');
}
return $date->format('Y-m-d H:i:s');
} }
function cutTurn(int $tick, int $turnterm, bool $withFraction = true): int function cutTurn($date, int $turnterm, bool $withFraction = true)
{ {
$remainder = $tick % GameClock::TICKS_PER_TURN; $date = new \DateTime($date);
if ($remainder < 0) {
$remainder += GameClock::TICKS_PER_TURN;
}
return $tick - $remainder;
}
/** 시나리오 초기화 입력인 벽시계를 기존 01:00 기준 월 경계로 정렬합니다. */ $baseDate = new \DateTime($date->format('Y-m-d'));
function cutTurnDateTime(string $date, int $turnterm, bool $withFraction = true): string $baseDate->sub(new \DateInterval("P1D"));
{ $baseDate->add(new \DateInterval("PT1H"));
$dateObj = new \DateTime($date);
$baseDate = new \DateTime($dateObj->format('Y-m-d')); $diffMin = intdiv($date->getTimeStamp() - $baseDate->getTimeStamp(), 60);
$baseDate->sub(new \DateInterval('P1D'));
$baseDate->add(new \DateInterval('PT1H'));
$diffMin = intdiv($dateObj->getTimestamp() - $baseDate->getTimestamp(), 60);
$diffMin -= $diffMin % $turnterm; $diffMin -= $diffMin % $turnterm;
$baseDate->add(new \DateInterval("PT{$diffMin}M")); $baseDate->add(new \DateInterval("PT{$diffMin}M"));
return $baseDate->format($withFraction ? 'Y-m-d H:i:s.u' : 'Y-m-d H:i:s'); if ($withFraction) {
return $baseDate->format('Y-m-d H:i:s.u');
}
return $baseDate->format('Y-m-d H:i:s');
} }
function cutDay($date, int $turnterm, bool $withFraction = true) function cutDay($date, int $turnterm, bool $withFraction = true)
@@ -997,13 +1000,15 @@ function increaseRefresh($type = "", $cnt = 1)
$generalID = $session->generalID; $generalID = $session->generalID;
$userGrade = $session->userGrade; $userGrade = $session->userGrade;
$dateObj = new \DateTimeImmutable();
$date = TimeUtil::format($dateObj, false);
$db = DB::db(); $db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env'); $gameStor = KVStorage::getStorage($db, 'game_env');
$date = GameClock::fromStorage($gameStor)->nowTick();
$isunited = $gameStor->isunited; $isunited = $gameStor->isunited;
$opentime = $gameStor->opentime; $opentime = $gameStor->opentime;
if ($userGrade >= 6) { if ($userGrade == 6) {
return; return;
} }
if ($isunited == 2) { if ($isunited == 2) {
@@ -1041,7 +1046,7 @@ function increaseRefresh($type = "", $cnt = 1)
$logDB = FileDB::db($logPath, $serverPath . '/../f_install/sql/api_log.sql'); $logDB = FileDB::db($logPath, $serverPath . '/../f_install/sql/api_log.sql');
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'] ?? $_SERVER['REMOTE_ADDR'] ?? 'local'; $ip = $_SERVER['REMOTE_ADDR'] ?? 'local';
$date = date('Y-m-d H:i:s'); $date = date('Y-m-d H:i:s');
$logDB->insert('api_log', [ $logDB->insert('api_log', [
@@ -1087,7 +1092,7 @@ function updateTraffic()
'month' => $admin['month'], 'month' => $admin['month'],
'refresh' => $admin['refresh'], 'refresh' => $admin['refresh'],
'online' => $online, 'online' => $online,
'date' => GameClock::fromStorage($gameStor)->formatNow(), 'date' => TimeUtil::now(),
]; ];
$gameStor->recentTraffic = $recentTraffic; $gameStor->recentTraffic = $recentTraffic;
@@ -1101,7 +1106,7 @@ function CheckOverhead()
$gameStor = KVStorage::getStorage($db, 'game_env'); $gameStor = KVStorage::getStorage($db, 'game_env');
[$turnterm, $refreshLimit] = $gameStor->getValuesAsArray(['turnterm', 'refreshLimit']); [$turnterm, $refreshLimit] = $gameStor->getValuesAsArray(['turnterm', 'refreshLimit']);
$nextRefreshLimit = Util::round(pow($turnterm, 0.6) * 3) * GameConst::$refreshLimitCoef; $nextRefreshLimit = Util::round(pow($turnterm, 0.6) * 3) * 10;
if ($nextRefreshLimit != $refreshLimit) { if ($nextRefreshLimit != $refreshLimit) {
@@ -1145,13 +1150,12 @@ function timeover(): bool
$gameStor = KVStorage::getStorage($db, 'game_env'); $gameStor = KVStorage::getStorage($db, 'game_env');
list($turnterm, $turntime) = $gameStor->getValuesAsArray(['turnterm', 'turntime']); list($turnterm, $turntime) = $gameStor->getValuesAsArray(['turnterm', 'turntime']);
$clock = GameClock::fromStorage($gameStor); $diff = (new \DateTime())->getTimestamp() - (new \DateTime($turntime))->getTimestamp();
$diff = $clock->nowTick() - Util::toInt($turntime);
$t = min($turnterm, 5); $t = min($turnterm, 5);
$term = $clock->ticksFromSeconds($t); $term = $diff;
if ($diff >= $term || $diff < 0) { if ($term >= $t || $term < 0) {
return true; return true;
} else { } else {
return false; return false;
@@ -1164,8 +1168,9 @@ function checkDelay()
$gameStor = KVStorage::getStorage($db, 'game_env'); $gameStor = KVStorage::getStorage($db, 'game_env');
//서버정보 //서버정보
$clock = GameClock::fromStorage($gameStor); $now = new \DateTimeImmutable();
$timeMinDiff = intdiv($clock->nowTick() - Util::toInt($gameStor->turntime), $clock->ticksFromMinutes(1)); $turntime = new \DateTimeImmutable($gameStor->turntime);
$timeMinDiff = intdiv($now->getTimestamp() - $turntime->getTimestamp(), 60);
// 1턴이상 갱신 없었으면 서버 지연 // 1턴이상 갱신 없었으면 서버 지연
$term = $gameStor->turnterm; $term = $gameStor->turnterm;
@@ -1180,15 +1185,18 @@ function checkDelay()
$iter = intdiv($timeMinDiff, $term); $iter = intdiv($timeMinDiff, $term);
if ($iter > $threshold) { if ($iter > $threshold) {
$minute = $iter * $term; $minute = $iter * $term;
$delayTick = $clock->ticksFromMinutes($minute); $newTurntime = $turntime->add(new \DateInterval("PT{$minute}M"));
$gameStor->turntime = Util::toInt($gameStor->turntime) + $delayTick; $newNextTurntime = $turntime->add(new \DateInterval("PT{$term}M"));
$gameStor->starttime = Util::toInt($gameStor->starttime) + $delayTick; $gameStor->turntime = $newTurntime->format('Y-m-d H:i:s');
$gameStor->starttime = (new \DateTimeImmutable($gameStor->starttime))
->add(new \DateInterval("PT{$minute}M"))
->format('Y-m-d H:i:s');
$db->update('general', [ $db->update('general', [
'turntime' => $db->sqleval('turntime + %i', $delayTick) 'turntime' => $db->sqleval('DATE_ADD(turntime, INTERVAL %i MINUTE)', $minute)
], true); ], 'turntime<=DATE_ADD(turntime, INTERVAL %i MINUTE)', $term);
$db->update('ng_auction', [ $db->update('ng_auction', [
'close_tick' => $db->sqleval('close_tick + %i', $delayTick) 'close_date' => $db->sqleval('DATE_ADD(close_date, INTERVAL %i MINUTE)', $minute)
], 'finished = 0'); ], 'finished = 0');
} }
} }
@@ -1245,8 +1253,10 @@ function turnDate($curtime)
$admin = $gameStor->getValues(['startyear', 'starttime', 'turnterm', 'year', 'month']); $admin = $gameStor->getValues(['startyear', 'starttime', 'turnterm', 'year', 'month']);
$turn = $admin['starttime']; $turn = $admin['starttime'];
$curturn = cutTurn(Util::toInt($curtime), $admin['turnterm']); $curturn = cutTurn($curtime, $admin['turnterm']);
$num = intdiv($curturn - Util::toInt($turn), GameClock::TICKS_PER_TURN); $term = $admin['turnterm'];
$num = intdiv((strtotime($curturn) - strtotime($turn)), $term * 60);
$date = $admin['startyear'] * 12; $date = $admin['startyear'] * 12;
$date += $num; $date += $num;
@@ -1376,14 +1386,12 @@ function CheckHall($no)
return; return;
} }
$clock = GameClock::fromStorage($gameStor); $unitedDate = TimeUtil::now();
$unitedDate = $clock->formatTick($clock->nowTick());
$nation = $generalObj->getStaticNation(); $nation = $generalObj->getStaticNation();
$serverCnt = $db->queryFirstField('SELECT count(*) FROM ng_games'); $serverCnt = $db->queryFirstField('SELECT count(*) FROM ng_games');
[$scenarioIdx, $scenarioName, $startTick] = $gameStor->getValuesAsArray(['scenario', 'scenario_text', 'starttime']); [$scenarioIdx, $scenarioName, $startTime] = $gameStor->getValuesAsArray(['scenario', 'scenario_text', 'starttime']);
$startTime = $clock->formatTick(Util::toInt($startTick));
$ownerName = $generalObj->getVar('owner_name'); $ownerName = $generalObj->getVar('owner_name');
if ($generalObj->getVar('owner')) { if ($generalObj->getVar('owner')) {
@@ -1394,9 +1402,6 @@ function CheckHall($no)
if ($valueType === 'natural') { if ($valueType === 'natural') {
$value = $generalObj->getVar($typeName); $value = $generalObj->getVar($typeName);
if (in_array($typeName, ['dex1', 'dex2', 'dex3', 'dex4', 'dex5'], true)) {
$value = CentennialAllStarGrowthService::recordableValue($generalObj, $typeName);
}
} else if ($valueType === 'rank') { } else if ($valueType === 'rank') {
$value = $generalObj->getRankVar(RankColumn::from($typeName)); $value = $generalObj->getRankVar(RankColumn::from($typeName));
} else if ($valueType === 'calc') { } else if ($valueType === 'calc') {
@@ -1663,6 +1668,8 @@ function tryUniqueItemLottery(RandUtil $rng, General $general, string $acquireTy
$prob = 1 / ($genCount * $itemTypeCnt * 0.7 / 3); // 투표율 70%, 설문조사 한번에 2~3개 등장 $prob = 1 / ($genCount * $itemTypeCnt * 0.7 / 3); // 투표율 70%, 설문조사 한번에 2~3개 등장
} else if ($acquireType == '랜덤 임관') { } else if ($acquireType == '랜덤 임관') {
$prob = 1 / ($genCount * $itemTypeCnt / 10 / 2); // 랜임시 2개(10%) 등장(200명중 20명 랜임시도?) $prob = 1 / ($genCount * $itemTypeCnt / 10 / 2); // 랜임시 2개(10%) 등장(200명중 20명 랜임시도?)
} else if ($acquireType == '건국') {
$prob = 1 / ($genCount * $itemTypeCnt / 10 / 4); // 건국시 4개(20%) 등장(200명시 20국 정도 됨)
} }
$prob *= GameConst::$uniqueTrialCoef; $prob *= GameConst::$uniqueTrialCoef;
@@ -1676,9 +1683,6 @@ function tryUniqueItemLottery(RandUtil $rng, General $general, string $acquireTy
//포인트로 랜덤 유니크 획득 //포인트로 랜덤 유니크 획득
$prob = 1; $prob = 1;
} }
else if ($acquireType == '건국') {
$prob = 1; // 건국시 100%
}
foreach (Util::range($maxCnt) as $_idx) { foreach (Util::range($maxCnt) as $_idx) {
if ($rng->nextBool($prob)) { if ($rng->nextBool($prob)) {
@@ -1700,16 +1704,7 @@ function getAdmin()
{ {
$db = DB::db(); $db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env'); $gameStor = KVStorage::getStorage($db, 'game_env');
$admin = $gameStor->getAll(); return $gameStor->getAll();
$clock = GameClock::fromStorage($gameStor);
foreach (['turntime', 'starttime', 'opentime', 'tnmt_time'] as $key) {
if (($admin[$key] ?? null) !== null) {
$admin["{$key}_display"] = $clock->formatTick(Util::toInt($admin[$key]), true);
}
}
$admin['clock_now_tick'] = $clock->nowTick();
$admin['clock_now_display'] = $clock->formatTick($admin['clock_now_tick'], true);
return $admin;
} }
/** @return General[] */ /** @return General[] */
@@ -1789,11 +1784,9 @@ function deleteNation(General $lord, bool $applyDB): array
$db->delete('troop', 'nation=%i', $nationID); $db->delete('troop', 'nation=%i', $nationID);
// 국가 삭제 // 국가 삭제
$gameDate = GameClock::fromStorage(KVStorage::getStorage($db, 'game_env'))->formatNow();
$db->insert('ng_old_nations', [ $db->insert('ng_old_nations', [
'server_id' => UniqueConst::$serverID, 'server_id' => UniqueConst::$serverID,
'nation' => $nationID, 'nation' => $nationID,
'date' => $gameDate,
'data' => Json::encode($nation) 'data' => Json::encode($nation)
]); ]);
$db->delete('nation', 'nation=%i', $nationID); $db->delete('nation', 'nation=%i', $nationID);
@@ -2201,29 +2194,35 @@ function SabotageInjury(RandUtil $rng, array $cityGeneralList, string $reason):
return $injuryCount; return $injuryCount;
} }
function getRandTurn(RandUtil $rng, int $term, ?int $baseTick = null): int function getRandTurn(RandUtil $rng, $term, ?\DateTimeInterface $baseDateTime = null)
{ {
$db = DB::db(); if ($baseDateTime === null) {
$clock = GameClock::fromStorage(KVStorage::getStorage($db, 'game_env')); $baseDateTime = new \DateTimeImmutable();
$baseTick ??= $clock->nowTick(); } else if ($baseDateTime instanceof \DateTime) {
$baseDateTime = \DateTimeImmutable::createFromMutable($baseDateTime);
$randSecond = $rng->nextRangeInt(0, 60 * $term - 1); } else if ($baseDateTime instanceof \DateTimeImmutable) {
$randMicrosecond = $rng->nextRangeInt(0, 999999); // 레거시 RNG 소비 6자리 유지 //do Nothing
} else {
return $baseTick throw new MustNotBeReachedException();
+ $clock->ticksFromSeconds($randSecond)
+ intdiv($randMicrosecond * $clock->ticksPerSecond(), 1_000_000);
} }
function getRandTurn2(RandUtil $rng, int $term, ?int $baseTick = null): int
{
$db = DB::db();
$clock = GameClock::fromStorage(KVStorage::getStorage($db, 'game_env'));
$baseTick ??= $clock->nowTick();
$randSecond = $rng->nextRangeInt(0, 60 * $term - 1); $randSecond = $rng->nextRangeInt(0, 60 * $term - 1);
$randMicrosecond = $rng->nextRangeInt(0, 999999); // 레거시 RNG 소비 6자리 유지 $randFraction = $rng->nextRangeInt(0, 999999) / 1000000; //6자리 소수
return $baseTick return TimeUtil::format($baseDateTime->add(TimeUtil::secondsToDateInterval($randSecond + $randFraction)), true);
- $clock->ticksFromSeconds($randSecond) }
- intdiv($randMicrosecond * $clock->ticksPerSecond(), 1_000_000);
function getRandTurn2(RandUtil $rng, $term, ?\DateTimeInterface $baseDateTime = null)
{
if ($baseDateTime === null) {
$baseDateTime = new \DateTimeImmutable();
} else if ($baseDateTime instanceof \DateTime) {
$baseDateTime = \DateTimeImmutable::createFromMutable($baseDateTime);
} else {
throw new MustNotBeReachedException();
}
$randSecond = $rng->nextRangeInt(0, 60 * $term - 1);
$randFraction = $rng->nextRangeInt(0, 999999) / 1000000; //6자리 소수
return $baseDateTime->sub(TimeUtil::secondsToDateInterval($randSecond + $randFraction))->format('Y-m-d H:i:s.u');
} }
+3 -4
View File
@@ -62,12 +62,11 @@ function processAuction()
{ {
$db = DB::db(); $db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env'); $now = TimeUtil::now();
$nowTick = GameClock::fromStorage($gameStor)->nowTick();
$auctionList = $db->queryAllLists( $auctionList = $db->queryAllLists(
'SELECT id, `type` FROM ng_auction WHERE `close_tick` <= %i AND finished = 0', 'SELECT id, `type` FROM ng_auction WHERE `close_date` <= %s AND finished = 0',
$nowTick $now
); );
if (!$auctionList) { if (!$auctionList) {
+36 -79
View File
@@ -3,7 +3,6 @@ namespace sammo;
use sammo\Command\GeneralCommand; use sammo\Command\GeneralCommand;
use sammo\Command\NationCommand; use sammo\Command\NationCommand;
use sammo\Enums\PenaltyKey;
function getGeneralTurnBrief(General $generalObj, array $turnList) { function getGeneralTurnBrief(General $generalObj, array $turnList) {
$result = []; $result = [];
@@ -42,21 +41,15 @@ function pushGeneralCommand(int $generalID, int $turnCnt=1){
$db = DB::db(); $db = DB::db();
$db->query( $db->update('general_turn', [
'UPDATE general_turn AS dst 'turn_idx'=>$db->sqleval('turn_idx + %i', $turnCnt)
LEFT JOIN general_turn AS src ], 'general_id=%i ORDER BY turn_idx DESC', $generalID);
ON src.general_id = dst.general_id $db->update('general_turn', [
AND src.turn_idx = dst.turn_idx - %i 'turn_idx'=>$db->sqleval('turn_idx - %i', GameConst::$maxTurn),
SET dst.action = IF(src.id IS NULL, %s, src.action), 'action'=>'휴식',
dst.arg = IF(src.id IS NULL, %s, src.arg), 'arg'=>'{}',
dst.brief = IF(src.id IS NULL, %s, src.brief) 'brief'=>'휴식'
WHERE dst.general_id = %i', ], 'general_id=%i AND turn_idx >= %i', $generalID, GameConst::$maxTurn);
$turnCnt,
'휴식',
'{}',
'휴식',
$generalID
);
} }
function pullGeneralCommand(int $generalID, int $turnCnt=1){ function pullGeneralCommand(int $generalID, int $turnCnt=1){
@@ -73,21 +66,15 @@ function pullGeneralCommand(int $generalID, int $turnCnt=1){
$db = DB::db(); $db = DB::db();
$db->query( $db->update('general_turn', [
'UPDATE general_turn AS dst 'turn_idx'=>$db->sqleval('turn_idx + %i', GameConst::$maxTurn),
LEFT JOIN general_turn AS src 'action'=>'휴식',
ON src.general_id = dst.general_id 'arg'=>'{}',
AND src.turn_idx = dst.turn_idx + %i 'brief'=>'휴식'
SET dst.action = IF(src.id IS NULL, %s, src.action), ], 'general_id=%i AND turn_idx < %i', $generalID, $turnCnt);
dst.arg = IF(src.id IS NULL, %s, src.arg), $db->update('general_turn', [
dst.brief = IF(src.id IS NULL, %s, src.brief) 'turn_idx'=>$db->sqleval('turn_idx - %i', $turnCnt)
WHERE dst.general_id = %i', ], 'general_id=%i ORDER BY turn_idx ASC', $generalID);
$turnCnt,
'휴식',
'{}',
'휴식',
$generalID
);
} }
function repeatGeneralCommand(int $generalId, int $turnCnt){ function repeatGeneralCommand(int $generalId, int $turnCnt){
@@ -138,23 +125,15 @@ function pushNationCommand(int $nationID, int $officerLevel, int $turnCnt=1){
$db = DB::db(); $db = DB::db();
$db->query( $db->update('nation_turn', [
'UPDATE nation_turn AS dst 'turn_idx'=>$db->sqleval('turn_idx + %i', $turnCnt)
LEFT JOIN nation_turn AS src ], 'nation_id=%i AND officer_level=%i ORDER BY turn_idx DESC', $nationID, $officerLevel);
ON src.nation_id = dst.nation_id $db->update('nation_turn', [
AND src.officer_level = dst.officer_level 'turn_idx'=>$db->sqleval('turn_idx - %i', GameConst::$maxChiefTurn),
AND src.turn_idx = dst.turn_idx - %i 'action'=>'휴식',
SET dst.action = IF(src.id IS NULL, %s, src.action), 'arg'=>'{}',
dst.arg = IF(src.id IS NULL, %s, src.arg), 'brief'=>'휴식'
dst.brief = IF(src.id IS NULL, %s, src.brief) ], 'nation_id=%i AND officer_level=%i AND turn_idx >= %i ORDER BY turn_idx ASC', $nationID, $officerLevel, GameConst::$maxChiefTurn);
WHERE dst.nation_id = %i AND dst.officer_level = %i',
$turnCnt,
'휴식',
'{}',
'휴식',
$nationID,
$officerLevel
);
} }
function pullNationCommand(int $nationID, int $officerLevel, int $turnCnt=1){ function pullNationCommand(int $nationID, int $officerLevel, int $turnCnt=1){
@@ -177,23 +156,15 @@ function pullNationCommand(int $nationID, int $officerLevel, int $turnCnt=1){
$db = DB::db(); $db = DB::db();
$db->query( $db->update('nation_turn', [
'UPDATE nation_turn AS dst 'turn_idx'=>$db->sqleval('turn_idx + %i', GameConst::$maxChiefTurn),
LEFT JOIN nation_turn AS src 'action'=>'휴식',
ON src.nation_id = dst.nation_id 'arg'=>'{}',
AND src.officer_level = dst.officer_level 'brief'=>'휴식',
AND src.turn_idx = dst.turn_idx + %i ], 'nation_id=%i AND officer_level=%i AND turn_idx < %i', $nationID, $officerLevel, $turnCnt);
SET dst.action = IF(src.id IS NULL, %s, src.action), $db->update('nation_turn', [
dst.arg = IF(src.id IS NULL, %s, src.arg), 'turn_idx'=>$db->sqleval('turn_idx - %i', $turnCnt)
dst.brief = IF(src.id IS NULL, %s, src.brief) ], 'nation_id=%i AND officer_level=%i ORDER BY turn_idx ASC', $nationID, $officerLevel);
WHERE dst.nation_id = %i AND dst.officer_level = %i',
$turnCnt,
'휴식',
'{}',
'휴식',
$nationID,
$officerLevel
);
} }
function repeatNationCommand(int $nationID, int $officerLevel, int $turnCnt){ function repeatNationCommand(int $nationID, int $officerLevel, int $turnCnt){
@@ -463,13 +434,6 @@ function setNationCommand(int $generalID, array $turnList, string $command, ?arr
]; ];
} }
if($general->hasPenalty(PenaltyKey::NoChiefTurnInput)){
return [
'result'=>false,
'reason'=>'수뇌 턴 입력 불가능'
];
}
try{ try{
$commandObj = buildNationCommandClass($command, $general, $env, $general->getLastTurn(), $arg); $commandObj = buildNationCommandClass($command, $general, $env, $general->getLastTurn(), $arg);
} }
@@ -509,13 +473,6 @@ function setNationCommand(int $generalID, array $turnList, string $command, ?arr
} }
_setNationCommand($commandObj, $turnList); _setNationCommand($commandObj, $turnList);
if($general->getNPCType() < 2){
//유저장인 경우에는 턴 리필
$general->updateVarWithLimit('killturn', $env['killturn'], $general->getVar('killturn'));
$general->applyDB($db);
}
return [ return [
'result'=>true, 'result'=>true,
'brief'=>$commandObj->getBrief(), 'brief'=>$commandObj->getBrief(),
+1 -24
View File
@@ -457,29 +457,6 @@ function buildWarUnitTriggerClass(?string $type, WarUnit $unit, ?array $args = n
return $class->newInstanceArgs(array_merge([$unit], $args)); return $class->newInstanceArgs(array_merge([$unit], $args));
} }
function getStaticEventClass(string $type){
static $basePath = __NAMESPACE__.'\\StaticEvent\\';
$classPath = ($basePath.$type);
if(class_exists($classPath)){
return $classPath;
}
throw new \InvalidArgumentException("{$type}은 StaticEvent가 아님");
}
function buildStaticEventClass(?string $type):BaseStaticEvent{
static $cache = [];
if(key_exists($type, $cache)){
return $cache[$type];
}
$class = getStaticEventClass($type);
$obj = new $class();
$cache[$type] = $obj;
return $obj;
}
function getGeneralPoolClass(string $type){ function getGeneralPoolClass(string $type){
static $basePath = __NAMESPACE__.'\\GeneralPool\\'; static $basePath = __NAMESPACE__.'\\GeneralPool\\';
$classPath = ($basePath.$type); $classPath = ($basePath.$type);
@@ -686,7 +663,7 @@ function TechLimit($startYear, $year, $tech) : bool {
$relYear = $year - $startYear; $relYear = $year - $startYear;
$relMaxTech = Util::valueFit( $relMaxTech = Util::valueFit(
floor($relYear / GameConst::$techLevelIncYear) + GameConst::$initialAllowedTechLevel, floor($relYear / 5) + 1,
1, 1,
GameConst::$maxTechLevel GameConst::$maxTechLevel
); );
+5 -16
View File
@@ -372,7 +372,7 @@ function postUpdateMonthly(RandUtil $rng)
continue; continue;
} }
//양측 기간 모두 0이 되는 상황이면 //양측 기간 모두 0이 되는 상황이면
$nation1 = getNationStaticInfo($me); $nation1 = getNationStaticInfo($me);
$name1 = $nation1['name']; $name1 = $nation1['name'];
$nation2 = getNationStaticInfo($you); $nation2 = getNationStaticInfo($you);
@@ -381,7 +381,7 @@ function postUpdateMonthly(RandUtil $rng)
$josaWa = JosaUtil::pick($name1, '와'); $josaWa = JosaUtil::pick($name1, '와');
$josaYi = JosaUtil::pick($name2, '이'); $josaYi = JosaUtil::pick($name2, '이');
$globalLogger->pushGlobalHistoryLog("<R><b>【전】</b></><D><b>$name1</b></>{$josaWa} <D><b>$name2</b></>{$josaYi} <S>전</>합니다."); $globalLogger->pushGlobalHistoryLog("<R><b>【전】</b></><D><b>$name1</b></>{$josaWa} <D><b>$name2</b></>{$josaYi} <S>전</>합니다.");
$db->update('diplomacy', [ $db->update('diplomacy', [
'state' => 2, 'state' => 2,
'term' => 0, 'term' => 0,
@@ -559,7 +559,7 @@ function checkStatistic()
$nationHist = ''; $nationHist = '';
foreach (GameConst::$availableNationType as $nationType) { foreach (GameConst::$availableNationType as $nationType) {
if (!($nationHists[$nationType] ?? null)) { if (!Util::array_get($nationHists[$nationType])) {
$nationHists[$nationType] = '-'; $nationHists[$nationType] = '-';
} }
$nationHist .= getNationType($nationType) . "({$nationHists[$nationType]}), "; $nationHist .= getNationType($nationType) . "({$nationHists[$nationType]}), ";
@@ -654,21 +654,13 @@ function checkStatistic()
function convForOldGeneral(array $general, int $year, int $month) function convForOldGeneral(array $general, int $year, int $month)
{ {
$general['history'] = getGeneralHistoryLogAll($general['no']); $general['history'] = getGeneralHistoryLogAll($general['no']);
$clock = GameClock::fromStorage(KVStorage::getStorage(DB::db(), 'game_env'));
$turnTimeDisplay = $clock->formatTick(Util::toInt($general['turntime']), true);
$general['turntime_tick'] = Util::toInt($general['turntime']);
$general['turntime'] = $turnTimeDisplay;
if ($general['recent_war'] !== null) {
$general['recent_war_tick'] = Util::toInt($general['recent_war']);
$general['recent_war'] = $clock->formatTick(Util::toInt($general['recent_war']), true);
}
return [ return [
'server_id' => UniqueConst::$serverID, 'server_id' => UniqueConst::$serverID,
'general_no' => $general['no'], 'general_no' => $general['no'],
'owner' => $general['owner'], 'owner' => $general['owner'],
'name' => $general['name'], 'name' => $general['name'],
'last_yearmonth' => $year * 100 + $month, 'last_yearmonth' => $year * 100 + $month,
'turntime' => $turnTimeDisplay, 'turntime' => $general['turntime'],
'data' => Json::encode($general) 'data' => Json::encode($general)
]; ];
} }
@@ -742,7 +734,7 @@ function checkEmperior()
/** @var int[] */ /** @var int[] */
$auctionList = $db->queryFirstColumn( $auctionList = $db->queryFirstColumn(
'SELECT `id` FROM `ng_auction` WHERE `type` = %s AND `finished` = 0 ORDER BY `close_tick` ASC', 'SELECT `id` FROM `ng_auction` WHERE `type` = %s AND `finished` = 0 ORDER BY `close_date` ASC',
AuctionType::UniqueItem->value AuctionType::UniqueItem->value
); );
foreach($auctionList as $auctionID){ foreach($auctionList as $auctionID){
@@ -840,12 +832,10 @@ function checkEmperior()
storeOldGenerals(0, $admin['year'], $admin['month']); storeOldGenerals(0, $admin['year'], $admin['month']);
storeOldGenerals($nation['nation'], $admin['year'], $admin['month']); storeOldGenerals($nation['nation'], $admin['year'], $admin['month']);
$gameDate = GameClock::fromStorage($gameStor)->formatNow();
$db->insert('ng_old_nations', [ $db->insert('ng_old_nations', [
'server_id' => UniqueConst::$serverID, 'server_id' => UniqueConst::$serverID,
'nation' => $nation['nation'], 'nation' => $nation['nation'],
'date' => $gameDate,
'data' => Json::encode($nation) 'data' => Json::encode($nation)
]); ]);
@@ -853,7 +843,6 @@ function checkEmperior()
$db->insert('ng_old_nations', [ $db->insert('ng_old_nations', [
'server_id' => UniqueConst::$serverID, 'server_id' => UniqueConst::$serverID,
'nation' => 0, 'nation' => 0,
'date' => $gameDate,
'data' => Json::encode([ 'data' => Json::encode([
'nation' => 0, 'nation' => 0,
'name' => '재야', 'name' => '재야',
+2 -6
View File
@@ -4,10 +4,6 @@ namespace sammo;
function printLimitMsg($turntime) function printLimitMsg($turntime)
{ {
if (is_int($turntime) || (is_string($turntime) && ctype_digit(ltrim($turntime, '-')))) {
$gameStor = KVStorage::getStorage(DB::db(), 'game_env');
$turntime = GameClock::fromStorage($gameStor)->formatTick(Util::toInt($turntime), true);
}
//FIXME: template로 이동. //FIXME: template로 이동.
?> ?>
<!DOCTYPE html> <!DOCTYPE html>
@@ -142,7 +138,7 @@ function JSCitiesBasedOnDistance(int $cityNo, int $maxDistance = 1): array{
$distanceList = searchDistance($cityNo, $maxDistance, true); $distanceList = searchDistance($cityNo, $maxDistance, true);
$result = []; $result = [];
for ($dist = 1; $dist <= $maxDistance; $dist++) { for ($dist = 1; $dist <= $maxDistance; $dist++) {
$result[$dist] = $distanceList[$dist] ?? []; $result[$dist] = Util::array_get($distanceList[$dist], []);
} }
return $result; return $result;
} }
@@ -156,7 +152,7 @@ function printCitiesBasedOnDistance(int $cityNo, int $maxDistance = 1): string
for ($dist = 1; $dist <= $maxDistance; $dist++) { for ($dist = 1; $dist <= $maxDistance; $dist++) {
$cityList = array_map(function ($cityID) { $cityList = array_map(function ($cityID) {
return CityConst::byID($cityID)->name; return CityConst::byID($cityID)->name;
}, $distanceList[$dist] ?? []); }, Util::array_get($distanceList[$dist], []));
$cityStr = join(', ', $cityList); $cityStr = join(', ', $cityList);
-4
View File
@@ -63,10 +63,6 @@ function chiefTurnTable()
function templateLimitMsg(string $turntime): string function templateLimitMsg(string $turntime): string
{ {
if (ctype_digit(ltrim($turntime, '-'))) {
$gameStor = KVStorage::getStorage(DB::db(), 'game_env');
$turntime = GameClock::fromStorage($gameStor)->formatTick(Util::toInt($turntime), true);
}
return "이미 너무 많은 접속을 하셨습니다. 다음 턴에 다시 시도해주세요. (턴시간: {$turntime})"; return "이미 너무 많은 접속을 하셨습니다. 다음 턴에 다시 시도해주세요. (턴시간: {$turntime})";
} }
+10 -17
View File
@@ -17,10 +17,10 @@ function processTournament()
{ {
$db = DB::db(); $db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env'); $gameStor = KVStorage::getStorage($db, 'game_env');
$clock = GameClock::fromStorage($gameStor);
$admin = $gameStor->getValues(['tournament', 'phase', 'tnmt_type', 'tnmt_auto', 'tnmt_time', 'turnterm', 'last_tournament_betting_id']); $admin = $gameStor->getValues(['tournament', 'phase', 'tnmt_type', 'tnmt_auto', 'tnmt_time', 'turnterm', 'last_tournament_betting_id']);
$offset = intdiv($clock->nowTick() - Util::toInt($admin['tnmt_time']), $clock->ticksPerSecond()); $now = new \DateTime();
$offset = $now->getTimestamp() - (new \DateTime($admin['tnmt_time']))->getTimestamp();
//수동일땐 무시 //수동일땐 무시
if (!$admin['tnmt_auto']) { if (!$admin['tnmt_auto']) {
@@ -122,10 +122,10 @@ function processTournament()
if ($tnmt == 6) { if ($tnmt == 6) {
$betTerm = Util::valueFit($unit * 60, null, 3600); $betTerm = Util::valueFit($unit * 60, null, 3600);
//처리 초 더한 날짜 //처리 초 더한 날짜
$dt = date("Y-m-d H:i:s", strtotime($admin['tnmt_time']) + $unit * $i + $betTerm);
$gameStor->tournament = $tnmt; $gameStor->tournament = $tnmt;
$gameStor->phase = $phase; $gameStor->phase = $phase;
$gameStor->tnmt_time = Util::toInt($admin['tnmt_time']) $gameStor->tnmt_time = $dt;
+ $clock->ticksFromSeconds($unit * $i + $betTerm);
return; return;
} }
} }
@@ -133,7 +133,7 @@ function processTournament()
$second = $unit * $iter; $second = $unit * $iter;
$gameStor->tournament = $tnmt; $gameStor->tournament = $tnmt;
$gameStor->phase = $phase; $gameStor->phase = $phase;
$gameStor->tnmt_time = Util::toInt($admin['tnmt_time']) + $clock->ticksFromSeconds($second); $gameStor->tnmt_time = (new \DateTimeImmutable($admin['tnmt_time']))->add(new \DateInterval("PT{$second}S"))->format('Y-m-d H:i:s');
} }
function getTournamentTermText(int $turnTerm) function getTournamentTermText(int $turnTerm)
@@ -160,8 +160,7 @@ function getTournamentTime()
$gameStor = KVStorage::getStorage($db, 'game_env'); $gameStor = KVStorage::getStorage($db, 'game_env');
list($tnmt, $tnmt_time) = $gameStor->getValuesAsArray(['tournament', 'tnmt_time']); list($tnmt, $tnmt_time) = $gameStor->getValuesAsArray(['tournament', 'tnmt_time']);
$clock = GameClock::fromStorage($gameStor); $dt = substr($tnmt_time, 11, 5);
$dt = substr($clock->formatTick(Util::toInt($tnmt_time)), 11, 5);
switch ($tnmt) { switch ($tnmt) {
case 1: case 1:
$tnmt = "개막시간 {$dt}"; $tnmt = "개막시간 {$dt}";
@@ -285,11 +284,9 @@ function startTournament($type)
$admin = $gameStor->getValues(['year', 'month', 'turnterm']); $admin = $gameStor->getValues(['year', 'month', 'turnterm']);
$turnTerm = $admin['turnterm']; $turnTerm = $admin['turnterm'];
$unit = calcTournamentTerm($turnTerm); $unit = calcTournamentTerm($turnTerm);
$clock = GameClock::fromStorage($gameStor);
$gameStor->tnmt_auto = true; $gameStor->tnmt_auto = true;
// 기존 startTournament은 unit을 분으로 더하므로 그 계약을 유지합니다. $gameStor->tnmt_time = (new \DateTimeImmutable())->add(new \DateInterval("PT{$unit}M"))->format('Y-m-d H:i:s');
$gameStor->tnmt_time = $clock->nowTick() + $clock->ticksFromMinutes($unit);
$gameStor->tournament = 1; $gameStor->tournament = 1;
$gameStor->tnmt_type = $type; $gameStor->tnmt_type = $type;
$gameStor->last_tournament_betting_id = 0; $gameStor->last_tournament_betting_id = 0;
@@ -1156,25 +1153,21 @@ function fight($tnmt_type, $tnmt, $phs, $group, $g1, $g2, $type)
]; ];
//막판 분노 //막판 분노
$factor1 = 1.0;
$factor2 = 1.0;
$ratio = rand() % 300; $ratio = rand() % 300;
if ($e1 / 5 > $energy1 && $damage1 > $damage2 && $gen1[$tp] >= $ratio) { if ($e1 / 5 > $energy1 && $damage1 > $damage2 && $gen1[$tp] >= $ratio) {
$factor2 = Util::round((rand() % 301 + 200) / 100); // 200 ~ 500% $damage2 *= Util::round((rand() % 301 + 200) / 100); // 200 ~ 500%
$critical1 = 1; $critical1 = 1;
$str = Util::choiceRandom($crticialSkillMap[$tnmt_type]); $str = Util::choiceRandom($crticialSkillMap[$tnmt_type]);
$log[] = "<S>●</> <Y>{$gen1['name']}</>의 분노의 <M>{$str}</> 공격!"; $log[] = "<S>●</> <Y>{$gen1['name']}</>의 분노의 <M>{$str}</> 공격!";
} }
$ratio = rand() % 300; $ratio = rand() % 300;
if ($e2 / 5 > $energy2 && $damage2 > $damage1 && $gen2[$tp] >= $ratio) { if ($e2 / 5 > $energy2 && $damage2 > $damage1 && $gen2[$tp] >= $ratio) {
$factor1 = Util::round((rand() % 301 + 200) / 100); // 200 ~ 500% $damage1 *= Util::round((rand() % 301 + 200) / 100); // 200 ~ 500%
$critical2 = 1; $critical2 = 1;
$str = Util::choiceRandom($crticialSkillMap[$tnmt_type]); $str = Util::choiceRandom($crticialSkillMap[$tnmt_type]);
$log[] = "<S>●</> <Y>{$gen2['name']}</>의 분노의 <M>{$str}</> 공격!"; $log[] = "<S>●</> <Y>{$gen2['name']}</>의 분노의 <M>{$str}</> 공격!";
} }
$damage1 *= $factor1;
$damage2 *= $factor2;
//1합 승부 //1합 승부
if ($phase == 1) { if ($phase == 1) {
+1 -2
View File
@@ -7,7 +7,6 @@ include "func.php";
Session::requireLogin()->loginGame()->setReadOnly(); Session::requireLogin()->loginGame()->setReadOnly();
$mapName = GameConst::$mapName; $mapName = GameConst::$mapName;
$frontClock = GameClock::fromStorage(KVStorage::getStorage(DB::db(), 'game_env'));
?> ?>
<!DOCTYPE html> <!DOCTYPE html>
@@ -29,7 +28,7 @@ $frontClock = GameClock::fromStorage(KVStorage::getStorage(DB::db(), 'game_env')
'maxTurn' => GameConst::$maxTurn, 'maxTurn' => GameConst::$maxTurn,
'maxPushTurn' => 12, 'maxPushTurn' => 12,
'serverNow' => $frontClock->formatTick($frontClock->nowTick()), 'serverNow' => TimeUtil::now(false),
] ]
], false) ?> ], false) ?>
<?= WebUtil::printJS('../d_shared/common_path.js') ?> <?= WebUtil::printJS('../d_shared/common_path.js') ?>
+2 -2
View File
@@ -7,10 +7,10 @@ include "func.php";
$session = Session::requireLogin(); $session = Session::requireLogin();
if ($session->userGrade < 6) { if ($session->userGrade < 5) {
die('관리자 아님'); die('관리자 아님');
} }
if ($session->userGrade == 6) { if ($session->userGrade == 5) {
die('DB 리셋 권한을 가지고 있지 않습니다.'); die('DB 리셋 권한을 가지고 있지 않습니다.');
} }
+8 -11
View File
@@ -25,23 +25,20 @@ if(!$reserved){
]); ]);
} }
$reservedDate = new \DateTimeImmutable($reserved['date']); $reservedDate = new \DateTime($reserved['date']);
$now = GameClock::readWallTime(); $now = new \DateTime();
$status = 'not_yet'; $status = 'not_yet';
list($isUnited, $unitedWallAnchor) = $gameStor->getValuesAsArray(['isunited', 'autoreset_united_wall_anchor']); list($isUnited, $lastTurn) = $gameStor->getValuesAsArray(['isunited', 'turntime']);
if($isUnited === null){ if($isUnited === null || $lastTurn === null){
$isUnited = 2; $isUnited = 2;
$lastTurn = '2000-01-01';
} }
$lastTurn = null;
if($isUnited > 0){ if($lastTurn !== null){
if(!is_string($unitedWallAnchor) || $unitedWallAnchor === ''){ $lastTurn = new \DateTime($lastTurn);
$unitedWallAnchor = TimeUtil::format($now, true);
$gameStor->autoreset_united_wall_anchor = $unitedWallAnchor;
}
$lastTurn = new \DateTimeImmutable($unitedWallAnchor);
} }
if($lastTurn === null){ if($lastTurn === null){
+1 -2
View File
@@ -10,7 +10,6 @@ $session = Session::requireGameLogin()->setReadOnly();
$userID = Session::getUserID(); $userID = Session::getUserID();
$db = DB::db(); $db = DB::db();
$clock = GameClock::fromStorage(KVStorage::getStorage($db, 'game_env'));
$isSecretBoard = Util::getPost('isSecret', 'bool', false); $isSecretBoard = Util::getPost('isSecret', 'bool', false);
$title = Util::getPost('title'); $title = Util::getPost('title');
@@ -68,7 +67,7 @@ $icon = GetImageURL($me['imgsvr'], $me['picture']);
$db->insert('board', [ $db->insert('board', [
'nation_no'=>$me['nation'], 'nation_no'=>$me['nation'],
'is_secret'=>$isSecretBoard, 'is_secret'=>$isSecretBoard,
'date'=>$clock->formatNow(), 'date'=>TimeUtil::now(),
'general_no'=>$me['no'], 'general_no'=>$me['no'],
'author'=>$me['name'], 'author'=>$me['name'],
'author_icon'=>$icon, 'author_icon'=>$icon,
+1 -2
View File
@@ -10,7 +10,6 @@ $session = Session::requireGameLogin()->setReadOnly();
$userID = Session::getUserID(); $userID = Session::getUserID();
$db = DB::db(); $db = DB::db();
$clock = GameClock::fromStorage(KVStorage::getStorage($db, 'game_env'));
$articleNo = Util::getPost('articleNo', 'int'); $articleNo = Util::getPost('articleNo', 'int');
$text = Util::getPost('text'); $text = Util::getPost('text');
@@ -74,7 +73,7 @@ else if ($isSecretBoard && $permission < 2) {
$db->insert('comment', [ $db->insert('comment', [
'nation_no'=>$me['nation'], 'nation_no'=>$me['nation'],
'is_secret'=>$isSecretBoard, 'is_secret'=>$isSecretBoard,
'date'=>$clock->formatNow(), 'date'=>TimeUtil::now(),
'document_no'=>$articleNo, 'document_no'=>$articleNo,
'general_no'=>$me['no'], 'general_no'=>$me['no'],
'author'=>$me['name'], 'author'=>$me['name'],
+1 -1
View File
@@ -83,7 +83,7 @@ else{
} }
$now = Message::gameNow(); $now = new \DateTime();
$unlimited = new \DateTime('9999-12-31'); $unlimited = new \DateTime('9999-12-31');
if(in_array($stateOpt, ['try_destroy_src', 'try_destroy_dest'])){ if(in_array($stateOpt, ['try_destroy_src', 'try_destroy_dest'])){
+1 -1
View File
@@ -69,7 +69,7 @@ $destNation = getNationStaticInfo($letter['dest_nation_id']);
$src = new MessageTarget($me['no'], $me['name'], $destNation['nation'], $destNation['name'], $destNation['color'], $me['icon']); $src = new MessageTarget($me['no'], $me['name'], $destNation['nation'], $destNation['name'], $destNation['color'], $me['icon']);
$dest = new MessageTarget(0, '', $srcNation['nation'], $srcNation['name'], $srcNation['color']); $dest = new MessageTarget(0, '', $srcNation['nation'], $srcNation['name'], $srcNation['color']);
$now = Message::gameNow(); $now = new \DateTime();
$unlimited = new \DateTime('9999-12-31'); $unlimited = new \DateTime('9999-12-31');
if($isAgree){ if($isAgree){
+1 -1
View File
@@ -63,7 +63,7 @@ $destNation = getNationStaticInfo($letter['dest_nation_id']);
$src = new MessageTarget($me['no'], $me['name'], $srcNation['nation'], $srcNation['name'], $srcNation['color'], $me['icon']); $src = new MessageTarget($me['no'], $me['name'], $srcNation['nation'], $srcNation['name'], $srcNation['color'], $me['icon']);
$dest = new MessageTarget(0, '', $destNation['nation'], $destNation['name'], $destNation['color']); $dest = new MessageTarget(0, '', $destNation['nation'], $destNation['name'], $destNation['color']);
$now = Message::gameNow(); $now = new \DateTime();
$unlimited = new \DateTime('9999-12-31'); $unlimited = new \DateTime('9999-12-31');
$aux['reason'] = [ $aux['reason'] = [
+2 -4
View File
@@ -140,8 +140,6 @@ else{
$me['icon'] = GetImageURL($me['imgsvr'], $me['picture']); $me['icon'] = GetImageURL($me['imgsvr'], $me['picture']);
$clock = GameClock::fromStorage($gameStor);
$gameNow = $clock->nowDateTime();
$db->insert('ng_diplomacy', [ $db->insert('ng_diplomacy', [
'src_nation_id'=>$srcNation['nation'], 'src_nation_id'=>$srcNation['nation'],
'dest_nation_id'=>$destNation['nation'], 'dest_nation_id'=>$destNation['nation'],
@@ -149,7 +147,7 @@ $db->insert('ng_diplomacy', [
'state'=>'proposed', 'state'=>'proposed',
'text_brief'=>$textBrief, 'text_brief'=>$textBrief,
'text_detail'=>$textDetail, 'text_detail'=>$textDetail,
'date'=>TimeUtil::format($gameNow), 'date'=>TimeUtil::now(),
'src_signer'=>$me['no'], 'src_signer'=>$me['no'],
'dest_signer'=>null, 'dest_signer'=>null,
'aux'=>Json::encode([ 'aux'=>Json::encode([
@@ -170,7 +168,7 @@ $newLetterNo = $db->insertId();
$src = new MessageTarget($me['no'], $me['name'], $srcNation['nation'], $srcNation['name'], $srcNation['color'], $me['icon']); $src = new MessageTarget($me['no'], $me['name'], $srcNation['nation'], $srcNation['name'], $srcNation['color'], $me['icon']);
$dest = new MessageTarget(0, '', $destNation['nation'], $destNation['name'], $destNation['color']); $dest = new MessageTarget(0, '', $destNation['nation'], $destNation['name'], $destNation['color']);
$now = \DateTime::createFromImmutable($gameNow); $now = new \DateTime();
$unlimited = new \DateTime('9999-12-31'); $unlimited = new \DateTime('9999-12-31');
$josaYi = JosaUtil::pick($newLetterNo, '이'); $josaYi = JosaUtil::pick($newLetterNo, '이');
+1 -1
View File
@@ -18,7 +18,7 @@ else{
$availableNextCall = $session->availableNextCallGetCityList??'2000-01-01 00:00:00'; $availableNextCall = $session->availableNextCallGetCityList??'2000-01-01 00:00:00';
$now = new \DateTimeImmutable(); $now = new \DateTimeImmutable();
if($now <= new \DateTimeImmutable($availableNextCall) && $session->userGrade < 6){ if($now <= new \DateTimeImmutable($availableNextCall) && $session->userGrade < 5){
Json::die([ Json::die([
'result'=>false, 'result'=>false,
'reason'=>"도시 목록은 10초에 한번 갱신 가능합니다.\n다음 시간 : ".$availableNextCall 'reason'=>"도시 목록은 10초에 한번 갱신 가능합니다.\n다음 시간 : ".$availableNextCall
+22 -22
View File
@@ -16,10 +16,12 @@ $session = Session::requireLogin([])->setReadOnly();
$userID = Session::getUserID(); $userID = Session::getUserID();
$oNow = new \DateTimeImmutable();
$now = $oNow->format('Y-m-d H:i:s');
$db = DB::db(); $db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env'); $gameStor = KVStorage::getStorage($db, 'game_env');
$clock = GameClock::fromStorage($gameStor);
$now = $clock->nowTick();
$oldGeneral = $db->queryFirstField('SELECT `no` FROM general WHERE `owner`=%i', $userID); $oldGeneral = $db->queryFirstField('SELECT `no` FROM general WHERE `owner`=%i', $userID);
if($oldGeneral !== null){ if($oldGeneral !== null){
@@ -42,14 +44,15 @@ if($npcmode!=1){
]); ]);
} }
$token = $db->queryFirstRow('SELECT * FROM select_npc_token WHERE `owner`=%i AND `valid_until`>=%i', $userID, $now); $token = $db->queryFirstRow('SELECT * FROM select_npc_token WHERE `owner`=%i AND `valid_until`>=%s', $userID, $now);
$pickResult = []; $pickResult = [];
if($token && $refresh){ if($token && $refresh){
$pickMoreFrom = Util::toInt($token['pick_more_from']); $pickMoreFrom = (new \DateTime($token['pick_more_from']))->getTimestamp();
$nowT = $oNow->getTimestamp();
if($now >= $pickMoreFrom){ if($nowT >= $pickMoreFrom){
$oldPickResult = Json::decode($token['pick_result']); $oldPickResult = Json::decode($token['pick_result']);
foreach($keepResult as $keepId){ foreach($keepResult as $keepId){
@@ -72,16 +75,15 @@ if($token && $refresh){
} }
if($token && !$refresh){ if($token && !$refresh){
$pickMoreFrom = Util::toInt($token['pick_more_from']); $pickMoreFrom = (new \DateTime($token['pick_more_from']))->getTimestamp();
$nowT = $oNow->getTimestamp();
Json::die([ Json::die([
'result'=>true, 'result'=>true,
'pick'=>Json::decode($token['pick_result']), 'pick'=>Json::decode($token['pick_result']),
'pickMoreFrom'=>$clock->formatTick($pickMoreFrom), 'pickMoreFrom'=>$token['pick_more_from'],
'pickMoreSeconds'=>intdiv($pickMoreFrom - $now, $clock->ticksPerSecond()), 'pickMoreSeconds'=>$pickMoreFrom-$nowT,
'validUntil'=>$clock->formatTick(Util::toInt($token['valid_until'])), 'validUntil'=>$token['valid_until']
'validForSeconds'=>max(0, intdiv(Util::toInt($token['valid_until']) - $now, $clock->ticksPerSecond())),
'clockMode'=>$clock->getMode(),
]); ]);
} }
@@ -98,7 +100,7 @@ foreach($db->query('SELECT `no`, `name`, leadership, strength, intel, nation, im
$weight[$general['no']] = pow($allStat, 1.5); $weight[$general['no']] = pow($allStat, 1.5);
} }
foreach($db->queryFirstColumn('SELECT pick_result FROM select_npc_token WHERE `owner`!=%i AND valid_until >=%i', $userID, $now) as $reserved){ foreach($db->queryFirstColumn('SELECT pick_result FROM select_npc_token WHERE `owner`!=%i AND valid_until >=%s', $userID, $now) as $reserved){
$reserved = Json::decode($reserved); $reserved = Json::decode($reserved);
foreach(array_keys($reserved) as $reservedNPC){ foreach(array_keys($reserved) as $reservedNPC){
if(key_exists($reservedNPC, $weight)){ if(key_exists($reservedNPC, $weight)){
@@ -129,8 +131,8 @@ $newNonce = random_int(0, 0xfffffff);
$validSecond = max(VALID_SECOND, $turnterm*40); $validSecond = max(VALID_SECOND, $turnterm*40);
$pickMoreSecond = max(PICK_MORE_SECOND, Util::round(pow($turnterm, 0.672)*8)); $pickMoreSecond = max(PICK_MORE_SECOND, Util::round(pow($turnterm, 0.672)*8));
$validUntil = $now + $clock->ticksFromSeconds($validSecond); $validUntil = $oNow->add(new \DateInterval(sprintf('PT%dS', $validSecond)));
$pickMoreFrom = $now + $clock->ticksFromSeconds($pickMoreSecond); $pickMoreFrom = $oNow->add(new \DateInterval(sprintf('PT%dS', $pickMoreSecond)));
$db->delete('select_npc_token', 'valid_until < %s', $now); $db->delete('select_npc_token', 'valid_until < %s', $now);
@@ -138,8 +140,8 @@ $inserted = 0;
if($token){ if($token){
$db->update('select_npc_token', [ $db->update('select_npc_token', [
'valid_until'=>$validUntil, 'valid_until'=>$validUntil->format('Y-m-d H:i:s'),
'pick_more_from'=>$pickMoreFrom, 'pick_more_from'=>$pickMoreFrom->format('Y-m-d H:i:s'),
'pick_result'=>Json::encode($pickResult), 'pick_result'=>Json::encode($pickResult),
'nonce'=>$newNonce 'nonce'=>$newNonce
], 'owner = %i AND nonce = %i', $userID, $token['nonce']); ], 'owner = %i AND nonce = %i', $userID, $token['nonce']);
@@ -150,8 +152,8 @@ if($token){
else{ else{
$db->insertIgnore('select_npc_token', [ $db->insertIgnore('select_npc_token', [
'owner'=>$userID, 'owner'=>$userID,
'valid_until'=>$validUntil, 'valid_until'=>$validUntil->format('Y-m-d H:i:s'),
'pick_more_from'=>$now, 'pick_more_from'=>'2000-01-01 01:00:00',
'pick_result'=>Json::encode($pickResult), 'pick_result'=>Json::encode($pickResult),
'nonce'=>$newNonce 'nonce'=>$newNonce
]); ]);
@@ -171,9 +173,7 @@ if($inserted === 0){
Json::die([ Json::die([
'result'=>true, 'result'=>true,
'pick'=>$pickResult, 'pick'=>$pickResult,
'pickMoreFrom'=>$clock->formatTick(($inserted===-1)?$pickMoreFrom:$now), 'pickMoreFrom'=>($inserted===-1)?$pickMoreFrom->format('Y-m-d H:i:s'):'2000-01-01 01:00:00',
'pickMoreSeconds'=>($inserted===-1)?$pickMoreSecond:0, 'pickMoreSeconds'=>($inserted===-1)?$pickMoreSecond:0,
'validUntil'=>$clock->formatTick($validUntil), 'validUntil'=>$validUntil->format('Y-m-d H:i:s')
'validForSeconds'=>max(0, intdiv($validUntil - $now, $clock->ticksPerSecond())),
'clockMode'=>$clock->getMode(),
]); ]);
+10 -30
View File
@@ -10,23 +10,7 @@ function sortTokens(&$tokens){
}); });
} }
function putInfoText(&$info, ?array $currentTargetEnv){ function putInfoText(&$info){
if (($info['event100Growth'] ?? false) === true) {
if ($currentTargetEnv === null) {
$displayStats = CentennialAllStarGrowthService::calculateUserInitialStats($info);
$info['selectionStatLabel'] = '시작 능력치';
} else {
$displayStats = CentennialAllStarGrowthService::calculateUserCurrentTargetStats(
$info,
$currentTargetEnv
);
$info['selectionStatLabel'] = '현재 변경 기준 능력치';
}
$info['selectionLeadership'] = $displayStats['leadership'];
$info['selectionStrength'] = $displayStats['strength'];
$info['selectionIntel'] = $displayStats['intel'];
}
if(key_exists('specialDomestic', $info)){ if(key_exists('specialDomestic', $info)){
$class = buildGeneralSpecialDomesticClass($info['specialDomestic']); $class = buildGeneralSpecialDomesticClass($info['specialDomestic']);
$info['specialDomesticName'] = $class->getName(); $info['specialDomesticName'] = $class->getName();
@@ -43,13 +27,14 @@ function putInfoText(&$info, ?array $currentTargetEnv){
$session = Session::requireLogin([])->setReadOnly(); $session = Session::requireLogin([])->setReadOnly();
$userID = Session::getUserID(); $userID = Session::getUserID();
$oNow = new \DateTimeImmutable();
$now = $oNow->format('Y-m-d H:i:s');
$db = DB::db(); $db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env'); $gameStor = KVStorage::getStorage($db, 'game_env');
$clock = GameClock::fromStorage($gameStor);
$now = $clock->nowTick();
$eventEnv = $gameStor->getValues(['npcmode', 'startyear', 'year', 'month']); $npcmode = $gameStor->getValue('npcmode');
$npcmode = $eventEnv['npcmode'];
if($npcmode!=2){ if($npcmode!=2){
Json::die([ Json::die([
'result'=>false, 'result'=>false,
@@ -58,7 +43,6 @@ if($npcmode!=2){
} }
$rawGeneral = $db->queryFirstRow('SELECT no, aux FROM general WHERE `owner` = %i', $userID); $rawGeneral = $db->queryFirstRow('SELECT no, aux FROM general WHERE `owner` = %i', $userID);
$currentTargetEnv = $rawGeneral ? $eventEnv : null;
if($rawGeneral){ if($rawGeneral){
$generalAux = Json::decode($rawGeneral['aux']); $generalAux = Json::decode($rawGeneral['aux']);
if(key_exists('next_change', $generalAux)&& $generalAux['next_change'] > $now){ if(key_exists('next_change', $generalAux)&& $generalAux['next_change'] > $now){
@@ -78,7 +62,7 @@ if($tokens){
foreach($tokens as $token){ foreach($tokens as $token){
$valid_until = $token['reserved_until']; $valid_until = $token['reserved_until'];
$info = Json::decode($token['info']); $info = Json::decode($token['info']);
putInfoText($info, $currentTargetEnv); putInfoText($info);
$info['uniqueName'] = $token['unique_name']; $info['uniqueName'] = $token['unique_name'];
$pick[] = $info; $pick[] = $info;
} }
@@ -86,9 +70,7 @@ if($tokens){
Json::die([ Json::die([
'result'=>true, 'result'=>true,
'pick'=>$pick, 'pick'=>$pick,
'validUntil'=>$clock->formatTick(Util::toInt($valid_until)), 'validUntil'=>$valid_until
'validForSeconds'=>max(0, intdiv(Util::toInt($valid_until) - $now, $clock->ticksPerSecond())),
'clockMode'=>$clock->getMode(),
]); ]);
} }
@@ -101,14 +83,12 @@ $valid_until = null;
foreach(pickGeneralFromPool($db, $rng, $userID, 14) as $pickObj){ foreach(pickGeneralFromPool($db, $rng, $userID, 14) as $pickObj){
$valid_until = $pickObj->getValidUntil(); $valid_until = $pickObj->getValidUntil();
$info = $pickObj->getInfo(); $info = $pickObj->getInfo();
putInfoText($info, $currentTargetEnv); putInfoText($info);
$pick[] = $info; $pick[] = $info;
} }
sortTokens($pick);//좀 무식하지만.. sortTokens($pick);//좀 무식하지만..
Json::die([ Json::die([
'result'=>true, 'result'=>true,
'pick'=>$pick, 'pick'=>$pick,
'validUntil'=>$valid_until === null ? null : $clock->formatTick(Util::toInt($valid_until)), 'validUntil'=>$valid_until
'validForSeconds'=>$valid_until === null ? 0 : max(0, intdiv(Util::toInt($valid_until) - $now, $clock->ticksPerSecond())),
'clockMode'=>$clock->getMode(),
]); ]);
+1 -1
View File
@@ -211,7 +211,7 @@ try{
$show_img_level, $show_img_level,
!!$tournament_trig, !!$tournament_trig,
$join_mode, $join_mode,
TimeUtil::format(GameClock::readWallTime(), false), TimeUtil::now(),
$autorun_user $autorun_user
)); ));
} }
+17 -48
View File
@@ -1,12 +1,9 @@
<?php <?php
namespace sammo; namespace sammo;
use sammo\Enums\GeneralColumn;
use sammo\Enums\GeneralLiteQueryMode; use sammo\Enums\GeneralLiteQueryMode;
use sammo\Enums\GeneralQueryMode; use sammo\Enums\GeneralQueryMode;
use sammo\Enums\MessageType; use sammo\Enums\MessageType;
use sammo\Enums\PenaltyKey;
include "lib.php"; include "lib.php";
include "func.php"; include "func.php";
@@ -24,12 +21,11 @@ $userID = Session::getUserID();
$db = DB::db(); $db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env'); $gameStor = KVStorage::getStorage($db, 'game_env');
$gameStor->cacheValues(['startyear', 'year', 'month', 'scenario', 'killturn']); $gameStor->cacheValues(['startyear','year','month','scenario']);
$me = $db->queryFirstRow('SELECT no,npc,nation,officer_level,penalty from general where owner=%i', $userID); $me = $db->queryFirstRow('SELECT no,nation,officer_level from general where owner=%i', $userID);
$myOfficerLevel = $me['officer_level']; $myOfficerLevel = $me['officer_level'];
$nationID = $me['nation']; $nationID = $me['nation'];
$myPenalty = Json::decode($me['penalty'] ?? '{}');
//수뇌가 아니면 아무것도 할 수 없음 //수뇌가 아니면 아무것도 할 수 없음
if($myOfficerLevel < 5){ if($myOfficerLevel < 5){
@@ -49,7 +45,8 @@ if ($action === '추방' && $destGeneralID == 0) {
if($destGeneralID==0){ if($destGeneralID==0){
$general = new DummyGeneral(true); $general = new DummyGeneral(true);
$general->setVar('nation', $nationID); $general->setVar('nation', $nationID);
} else { }
else{
$general = General::createObjFromDB($destGeneralID); $general = General::createObjFromDB($destGeneralID);
if($general instanceof DummyGeneral){ if($general instanceof DummyGeneral){
@@ -74,21 +71,10 @@ if ($officerLevel == 12) {
]); ]);
} }
function do수뇌임명(General $general, int $targetOfficerLevel): ?string function do수뇌임명(General $general, int $targetOfficerLevel):?string{
{
global $myPenalty;
if ($myPenalty[PenaltyKey::NoChiefChange->value] ?? false) {
return '수뇌를 임명할 수 없는 상태입니다.';
}
$generalID = $general->getID(); $generalID = $general->getID();
$nationID = $general->getNationID(); $nationID = $general->getNationID();
if($general->hasPenalty(PenaltyKey::NoChief)){
return '수뇌가 될 수 없는 상태입니다.';
}
$db = DB::db(); $db = DB::db();
[$chiefSet, $nationLevel] = $db->queryFirstList('SELECT chief_set,level FROM nation WHERE nation = %i',$nationID); [$chiefSet, $nationLevel] = $db->queryFirstList('SELECT chief_set,level FROM nation WHERE nation = %i',$nationID);
@@ -111,11 +97,15 @@ function do수뇌임명(General $general, int $targetOfficerLevel): ?string
], 'nation=%i AND officer_level=%i AND no!=%i', $nationID, $targetOfficerLevel, $generalID); ], 'nation=%i AND officer_level=%i AND no!=%i', $nationID, $targetOfficerLevel, $generalID);
if($targetOfficerLevel === 11){ if($targetOfficerLevel === 11){
} else if ($targetOfficerLevel % 2 == 0) {
}
else if($targetOfficerLevel % 2 == 0){
if($general->getVar('strength') < GameConst::$chiefStatMin){ if($general->getVar('strength') < GameConst::$chiefStatMin){
return '무력이 부족합니다.'; return '무력이 부족합니다.';
} }
} else {
}
else{
if($general->getVar('intel') < GameConst::$chiefStatMin){ if($general->getVar('intel') < GameConst::$chiefStatMin){
return '지력이 부족합니다.'; return '지력이 부족합니다.';
} }
@@ -132,10 +122,7 @@ function do수뇌임명(General $general, int $targetOfficerLevel): ?string
return null; return null;
} }
function do도시임명(General $general, int $cityID, int $targetOfficerLevel): ?string function do도시임명(General $general, int $cityID, int $targetOfficerLevel):?string{
{
global $myPenalty;
$nationID = $general->getNationID(); $nationID = $general->getNationID();
$db = DB::db(); $db = DB::db();
@@ -144,10 +131,6 @@ function do도시임명(General $general, int $cityID, int $targetOfficerLevel):
return '올바르지 않은 도시입니다'; return '올바르지 않은 도시입니다';
} }
if ($general->getVar(GeneralColumn::officer_level) >= 4 && ($myPenalty[PenaltyKey::NoChiefChange->value] ?? false)) {
return '수뇌인 장수를 변경할 수 없는 상태입니다.';
}
$officerSet = $db->queryFirstField('SELECT officer_set FROM city WHERE nation=%i AND city=%i', $nationID, $cityID); $officerSet = $db->queryFirstField('SELECT officer_set FROM city WHERE nation=%i AND city=%i', $nationID, $cityID);
if($officerSet === null){ if($officerSet === null){
return '아국 도시가 아닙니다'; return '아국 도시가 아닙니다';
@@ -186,15 +169,12 @@ function do도시임명(General $general, int $cityID, int $targetOfficerLevel):
return null; return null;
} }
function do추방(General $general, int $myOfficerLevel): ?string function do추방(General $general, int $myOfficerLevel):?string{
{
$generalID = $general->getID(); $generalID = $general->getID();
$generalName = $general->getVar('name'); $generalName = $general->getVar('name');
$nationID = $general->getNationID(); $nationID = $general->getNationID();
if ($myPenalty[PenaltyKey::NoBanGeneral->value] ?? false) {
return '추방할 수 없는 상태입니다.';
}
//추방할사람이 외교권자이면 불가 //추방할사람이 외교권자이면 불가
$permission = checkSecretPermission($general->getRaw()); $permission = checkSecretPermission($general->getRaw());
@@ -242,7 +222,8 @@ function do추방(General $general, int $myOfficerLevel): ?string
// 명성/공헌 N*10%감소 // 명성/공헌 N*10%감소
if($env['year'] <= $env['startyear'] && $general->getNPCType() < 2){ if($env['year'] <= $env['startyear'] && $general->getNPCType() < 2){
$general->setVar('makelimit', $oldMakeLimit); $general->setVar('makelimit', $oldMakeLimit);
} else { }
else{
$betrayCnt = $general->getVar('betray'); $betrayCnt = $general->getVar('betray');
$general->addExperience(-$general->getVar('experience')*0.15*$betrayCnt); $general->addExperience(-$general->getVar('experience')*0.15*$betrayCnt);
$general->addDedication(-$general->getVar('dedication')*0.15*$betrayCnt); $general->addDedication(-$general->getVar('dedication')*0.15*$betrayCnt);
@@ -290,7 +271,7 @@ function do추방(General $general, int $myOfficerLevel): ?string
$src, $src,
$src, $src,
$str, $str,
Message::gameNow(), new \DateTime(),
new \DateTime('9999-12-31'), new \DateTime('9999-12-31'),
[] []
); );
@@ -342,10 +323,6 @@ if ($action == "임명") {
'reason'=>$result 'reason'=>$result
]); ]);
} }
//수뇌의 삭턴 리필
$db->update('general', [
'killturn' => $db->sqleval('GREATEST(%b, %i)', 'killturn', $gameStor->getValue('killturn')),
], 'no=%i', $me['no']);
Json::die([ Json::die([
'result'=>true, 'result'=>true,
'reason'=>'success' 'reason'=>'success'
@@ -360,10 +337,6 @@ if ($action == "임명") {
'reason'=>$result 'reason'=>$result
]); ]);
} }
//수뇌의 삭턴 리필
$db->update('general', [
'killturn' => $db->sqleval('GREATEST(%b, %i)', 'killturn', $gameStor->getValue('killturn')),
], 'no=%i', $me['no']);
Json::die([ Json::die([
'result'=>true, 'result'=>true,
'reason'=>'success' 'reason'=>'success'
@@ -384,10 +357,6 @@ if ($action == "추방") {
'reason'=>$result 'reason'=>$result
]); ]);
} }
//수뇌의 삭턴 리필
$db->update('general', [
'killturn' => $db->sqleval('GREATEST(%b, %i)', 'killturn', $gameStor->getValue('killturn')),
], 'no=%i', $me['no']);
Json::die([ Json::die([
'result'=>true, 'result'=>true,
'reason'=>'success' 'reason'=>'success'
+1 -1
View File
@@ -8,7 +8,7 @@ include('func.php');
$session = Session::requireLogin([])->setReadOnly(); $session = Session::requireLogin([])->setReadOnly();
if(Session::getInstance()->userGrade < 6){ if(Session::getInstance()->userGrade < 5){
Json::die([ Json::die([
'reason'=>'권한이 부족합니다.' 'reason'=>'권한이 부족합니다.'
]); ]);
+3 -3
View File
@@ -24,8 +24,8 @@ $db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env'); $gameStor = KVStorage::getStorage($db, 'game_env');
$rootDB = RootDB::db(); $rootDB = RootDB::db();
$clock = GameClock::fromStorage($gameStor); $oNow = new \DateTimeImmutable();
$now = $clock->nowTick(); $now = $oNow->format('Y-m-d H:i:s');
$member = $rootDB->queryFirstRow('SELECT `name`, `penalty` FROM member WHERE `NO`=%i', $userID); $member = $rootDB->queryFirstRow('SELECT `name`, `penalty` FROM member WHERE `NO`=%i', $userID);
if(!$member){ if(!$member){
@@ -41,7 +41,7 @@ $penaltyInfo = array_merge($memberPenalty['any'] ?? [], $memberPenalty[DB::prefi
$penalty = []; $penalty = [];
foreach($penaltyInfo as $penaltyKey => $penaltyValue){ foreach($penaltyInfo as $penaltyKey => $penaltyValue){
if(($penaltyValue['expire'] ?? 0) > TimeUtil::now()){ if($penaltyValue['expire'] ?? 0 > TimeUtil::now()){
$penalty[$penaltyKey] = $penaltyValue['value']; $penalty[$penaltyKey] = $penaltyValue['value'];
} }
} }
+9 -85
View File
@@ -8,20 +8,10 @@ WebUtil::requireAJAX();
$pick = Util::getPost('pick'); $pick = Util::getPost('pick');
$leadership = Util::getPost('leadership', 'int', GameConst::$defaultStatMin); $leadership = Util::getPost('leadership', 'int', GameConst::$defaultStatMin);
$isCentennialAllStar = CentennialAllStarGrowthService::isActive(); $strength = Util::getPost('leadership', 'int', GameConst::$defaultStatMin);
$strength = Util::getPost( $intel = Util::getPost('leadership', 'int', GameConst::$defaultStatMin);
$isCentennialAllStar ? 'strength' : 'leadership',
'int',
GameConst::$defaultStatMin
);
$intel = Util::getPost(
$isCentennialAllStar ? 'intel' : 'leadership',
'int',
GameConst::$defaultStatMin
);
$personal = Util::getPost('personal', 'string', null); $personal = Util::getPost('personal', 'string', null);
$use_own_picture = Util::getPost('use_own_picture', 'bool', false); $use_own_picture = Util::getPost('use_own_picture', 'bool', false);
$pictureSource = Util::getPost('picture_source', 'string', 'selected');
if(!$pick){ if(!$pick){
@@ -37,8 +27,8 @@ $db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env'); $gameStor = KVStorage::getStorage($db, 'game_env');
$rootDB = RootDB::db(); $rootDB = RootDB::db();
$clock = GameClock::fromStorage($gameStor); $oNow = new \DateTimeImmutable();
$now = $clock->nowTick(); $now = $oNow->format('Y-m-d H:i:s');
$hasGeneralID = $db->queryFirstField('SELECT no FROM general WHERE owner = %i', $userID); $hasGeneralID = $db->queryFirstField('SELECT no FROM general WHERE owner = %i', $userID);
if($hasGeneralID){ if($hasGeneralID){
@@ -70,36 +60,13 @@ if(!$selectInfo){
} }
$selectInfo = Json::decode($selectInfo); $selectInfo = Json::decode($selectInfo);
$ownerInfo = RootDB::db()->queryFirstRow( $ownerInfo = RootDB::db()->queryFirstRow('SELECT `name`,`picture`,`imgsvr` FROM member WHERE `NO`=%i',$userID);
'SELECT `name`,`picture`,`imgsvr`,`grade` FROM member WHERE `NO`=%i',
$userID
);
if(!$ownerInfo){ if(!$ownerInfo){
Json::die([ Json::die([
'result'=>false, 'result'=>false,
'reason'=>'멤버 정보를 가져오지 못했습니다.' 'reason'=>'멤버 정보를 가져오지 못했습니다.'
]); ]);
} }
if ($isCentennialAllStar) {
if (!in_array($pictureSource, ['selected', 'own'], true)) {
Json::die([
'result' => false,
'reason' => '올바르지 않은 전콘 선택입니다.',
]);
}
if ($pictureSource === 'own') {
$canUseOwnPicture = in_array('picture', GameConst::$generalPoolAllowOption, true)
&& $env['show_img_level'] >= 1
&& $ownerInfo['grade'] >= 1
&& $ownerInfo['picture'] !== '';
if (!$canUseOwnPicture) {
Json::die([
'result' => false,
'reason' => '사용할 수 있는 내 전콘이 없습니다.',
]);
}
}
}
$gencount = $db->queryFirstField('SELECT count(`no`) FROM general WHERE npc<2'); $gencount = $db->queryFirstField('SELECT count(`no`) FROM general WHERE npc<2');
@@ -113,25 +80,12 @@ if ($gencount >= $maxgeneral) {
$poolClass = getGeneralPoolClass(GameConst::$targetGeneralPool); $poolClass = getGeneralPoolClass(GameConst::$targetGeneralPool);
/** @var AbsGeneralPool */ /** @var AbsGeneralPool */
if ($isCentennialAllStar) {
$rng = new RandUtil(new LiteHashDRBG(Util::simpleSerialize(
UniqueConst::$hiddenSeed,
'selectPickedGeneral',
$userID,
$pick
)));
$pickedGeneral = new $poolClass($db, $rng, $selectInfo, $now);
} else {
$pickedGeneral = new $poolClass($db, $selectInfo, $now); $pickedGeneral = new $poolClass($db, $selectInfo, $now);
}
$builder = $pickedGeneral->getGeneralBuilder(); $builder = $pickedGeneral->getGeneralBuilder();
if ($isCentennialAllStar) {
CentennialAllStarGrowthService::prepareInitialUser($builder, $selectInfo);
}
foreach(GameConst::$generalPoolAllowOption as $allowOption){ foreach(GameConst::$generalPoolAllowOption as $allowOption){
if($allowOption == 'stat' && !$isCentennialAllStar){ if($allowOption == 'stat'){
$leadership = Util::valueFit($leadership, GameConst::$defaultStatMin, GameConst::$defaultStatMax); $leadership = Util::valueFit($leadership, GameConst::$defaultStatMin, GameConst::$defaultStatMax);
$strength = Util::valueFit($strength, GameConst::$defaultStatMin, GameConst::$defaultStatMax); $strength = Util::valueFit($strength, GameConst::$defaultStatMin, GameConst::$defaultStatMax);
$intel = Util::valueFit($intel, GameConst::$defaultStatMin, GameConst::$defaultStatMax); $intel = Util::valueFit($intel, GameConst::$defaultStatMin, GameConst::$defaultStatMax);
@@ -144,23 +98,14 @@ foreach(GameConst::$generalPoolAllowOption as $allowOption){
} }
$builder->setStat($leadership, $strength, $intel); $builder->setStat($leadership, $strength, $intel);
} }
else if( else if($allowOption == 'picture' && $use_own_picture){
$allowOption == 'picture'
&& (
(!$isCentennialAllStar && $use_own_picture)
|| ($isCentennialAllStar && $pictureSource === 'own')
)
){
$builder->setPicture($ownerInfo['imgsvr'], $ownerInfo['picture']); $builder->setPicture($ownerInfo['imgsvr'], $ownerInfo['picture']);
} }
else if($allowOption == 'ego'){ else if($allowOption == 'ego'){
if(!$personal || $personal == 'Random'){ if(!$personal || $personal == 'Random'){
$personal = Util::choiceRandom(GameConst::$availablePersonality); $personal = Util::choiceRandom(GameConst::$availablePersonality);
} }
$invalidPersonal = $isCentennialAllStar if(!array_search($personal, GameConst::$availablePersonality)){
? !in_array($personal, GameConst::$availablePersonality, true)
: !array_search($personal, GameConst::$availablePersonality);
if($invalidPersonal){
Json::die([ Json::die([
'result'=>false, 'result'=>false,
'reason'=>'올바르지 않은 성격입니다.' 'reason'=>'올바르지 않은 성격입니다.'
@@ -176,29 +121,8 @@ $builder->setOwner($userID);
$builder->setOwnerName($userNick); $builder->setOwnerName($userNick);
$builder->setKillturn(5); $builder->setKillturn(5);
$builder->setNPCType(0); $builder->setNPCType(0);
$builder->setAuxVar('next_change', $now + GameClock::TICKS_PER_TURN * 12); $builder->setAuxVar('next_change', TimeUtil::nowAddMinutes(12 * $env['turnterm']));
$builder->setAuxVar(
'prestart_delete_after',
addTurn($now, $env['turnterm'], GameConst::$minTurnDieOnPrestart)
);
$builder->fillRemainSpecAsZero($env); $builder->fillRemainSpecAsZero($env);
if ($isCentennialAllStar) {
$candidateCities = $db->queryFirstColumn(
'SELECT city FROM city WHERE level >= 5 AND level <= 6 AND nation = 0'
);
if (!$candidateCities) {
$candidateCities = $db->queryFirstColumn(
'SELECT city FROM city WHERE level >= 5 AND level <= 6'
);
}
if (!$candidateCities) {
Json::die([
'result' => false,
'reason' => '장수를 생성할 소·중성이 없습니다.',
]);
}
$builder->setCityID($rng->choice($candidateCities));
}
$builder->build($env); $builder->build($env);
$generalID = $builder->getGeneralID(); $generalID = $builder->getGeneralID();
if(!$generalID){ if(!$generalID){
+1 -4
View File
@@ -19,7 +19,6 @@ if(!class_exists('\\sammo\\DB')){
$db = DB::db(); $db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env'); $gameStor = KVStorage::getStorage($db, 'game_env');
$clock = GameClock::fromStorage($gameStor);
if(file_exists(__DIR__.'/.htaccess')){ if(file_exists(__DIR__.'/.htaccess')){
$reserved = $db->queryFirstRow( $reserved = $db->queryFirstRow(
@@ -76,10 +75,8 @@ $admin['maxUserCnt'] = $admin['maxgeneral'];
$admin['npcMode'] = $admin['npcmode']; $admin['npcMode'] = $admin['npcmode'];
$admin['turnTerm'] = $admin['turnterm']; $admin['turnTerm'] = $admin['turnterm'];
$admin['isUnited'] = $admin['isunited']; $admin['isUnited'] = $admin['isunited'];
$admin['isOpen'] = $clock->nowTick() >= Util::toInt($admin['opentime']);
$admin['opentime'] = $clock->formatTick(Util::toInt($admin['opentime']));
$admin['starttime'] = substr($admin['opentime'], 5, 11); $admin['starttime'] = substr($admin['opentime'], 5, 11);
$admin['turntime'] = substr($clock->formatTick(Util::toInt($admin['turntime'])), 5, 11); $admin['turntime'] = substr($admin['turntime'], 5, 11);
unset($admin['npcmode']); unset($admin['npcmode']);
unset($admin['maxgeneral']); unset($admin['maxgeneral']);
unset($admin['turnterm']); unset($admin['turnterm']);
+6 -28
View File
@@ -1,5 +1,4 @@
<?php <?php
namespace sammo; namespace sammo;
include "lib.php"; include "lib.php";
@@ -27,7 +26,8 @@ if ($defence_train <= 40) {
if($defence_train <= 90){ if($defence_train <= 90){
$defence_train = Util::round($defence_train, -1); $defence_train = Util::round($defence_train, -1);
} else { }
else{
$defence_train = 999; $defence_train = 999;
} }
@@ -49,7 +49,8 @@ if ($defence_train !== $me->getVar('defence_train')) {
$affectedAtmos = $me->onCalcDomestic('changeDefenceTrain', "atmos{$defence_train}", $affectedAtmos); $affectedAtmos = $me->onCalcDomestic('changeDefenceTrain', "atmos{$defence_train}", $affectedAtmos);
$me->increaseVarWithLimit('train', $affectedTrain, 20, GameConst::$maxTrainByWar); $me->increaseVarWithLimit('train', $affectedTrain, 20, GameConst::$maxTrainByWar);
$me->increaseVarWithLimit('atmos', $affectedAtmos, 20, GameConst::$maxAtmosByWar); $me->increaseVarWithLimit('atmos', $affectedAtmos, 20, GameConst::$maxAtmosByWar);
} else { }
else{
$me->increaseVar('myset', -1); $me->increaseVar('myset', -1);
$me->setVar('defence_train', $defence_train); $me->setVar('defence_train', $defence_train);
} }
@@ -64,36 +65,13 @@ if ($me->getNPCType() == 1 && $detachNPC) {
if($turnterm < 10){ if($turnterm < 10){
$targetKillTurn = 30 / $turnterm; $targetKillTurn = 30 / $turnterm;
} else { }
else{
$targetKillTurn = 60 / $turnterm; $targetKillTurn = 60 / $turnterm;
} }
$me->setVar('killturn', $targetKillTurn); $me->setVar('killturn', $targetKillTurn);
} }
$rootDB = RootDB::db();
//회원 테이블에서 정보확인
$member = $rootDB->queryFirstRow('SELECT `no`, id, picture, grade, `name`, imgsvr, `penalty` FROM member WHERE no=%i', $userID);
if (!$member) {
//이런 경우가 있나?
//TODO: 로그 남겨둘 것
Json::die([
'result' => false,
'reason' => '회원 정보를 찾을 수 없습니다.'
]);
}
$memberPenalty = Json::decode($member['penalty'] ?? "{}");
$penaltyInfo = array_merge($memberPenalty['any'] ?? [], $memberPenalty[DB::prefix()] ?? []);
$penalty = [];
foreach ($penaltyInfo as $penaltyKey => $penaltyValue) {
if (($penaltyValue['expire'] ?? 0) > TimeUtil::now()) {
$penalty[$penaltyKey] = $penaltyValue['value'];
}
}
$me->setVar('penalty', Json::encode($penalty));
$me->applyDB($db); $me->applyDB($db);
Json::die([ Json::die([
+3 -6
View File
@@ -64,7 +64,6 @@ if ($permission < 3) {
function applyNationPolicy($policy, $nationID, $generalName): ?string function applyNationPolicy($policy, $nationID, $generalName): ?string
{ {
$db = DB::db(); $db = DB::db();
$gameNow = GameClock::fromStorage(KVStorage::getStorage($db, 'game_env'))->formatNow();
$nationStor = KVStorage::getStorage($db, $nationID, 'nation_env'); $nationStor = KVStorage::getStorage($db, $nationID, 'nation_env');
$defaultPolicy = AutorunNationPolicy::$defaultPolicy; $defaultPolicy = AutorunNationPolicy::$defaultPolicy;
@@ -140,7 +139,7 @@ function applyNationPolicy($policy, $nationID, $generalName): ?string
$nationPolicyRoot['values'] = $nationPolicy; $nationPolicyRoot['values'] = $nationPolicy;
$nationPolicyRoot['valueSetter'] = $generalName; $nationPolicyRoot['valueSetter'] = $generalName;
$nationPolicyRoot['valueSetTime'] = $gameNow; $nationPolicyRoot['valueSetTime'] = TimeUtil::now();
$nationStor->npc_nation_policy = $nationPolicyRoot; $nationStor->npc_nation_policy = $nationPolicyRoot;
return null; return null;
} }
@@ -148,7 +147,6 @@ function applyNationPolicy($policy, $nationID, $generalName): ?string
function applyNationPriority($priority, $nationID, $generalName): ?string function applyNationPriority($priority, $nationID, $generalName): ?string
{ {
$db = DB::db(); $db = DB::db();
$gameNow = GameClock::fromStorage(KVStorage::getStorage($db, 'game_env'))->formatNow();
$nationStor = KVStorage::getStorage($db, $nationID, 'nation_env'); $nationStor = KVStorage::getStorage($db, $nationID, 'nation_env');
$nationPolicyRoot = $nationStor->npc_nation_policy; $nationPolicyRoot = $nationStor->npc_nation_policy;
@@ -160,7 +158,7 @@ function applyNationPriority($priority, $nationID, $generalName): ?string
} }
$nationPolicyRoot['priority'] = $priority; $nationPolicyRoot['priority'] = $priority;
$nationPolicyRoot['prioritySetter'] = $generalName; $nationPolicyRoot['prioritySetter'] = $generalName;
$nationPolicyRoot['prioritySetTime'] = $gameNow; $nationPolicyRoot['prioritySetTime'] = TimeUtil::now();
$nationStor->npc_nation_policy = $nationPolicyRoot; $nationStor->npc_nation_policy = $nationPolicyRoot;
return null; return null;
} }
@@ -168,7 +166,6 @@ function applyNationPriority($priority, $nationID, $generalName): ?string
function applyGeneralPriority($priority, $nationID, $generalName): ?string function applyGeneralPriority($priority, $nationID, $generalName): ?string
{ {
$db = DB::db(); $db = DB::db();
$gameNow = GameClock::fromStorage(KVStorage::getStorage($db, 'game_env'))->formatNow();
$nationStor = KVStorage::getStorage($db, $nationID, 'nation_env'); $nationStor = KVStorage::getStorage($db, $nationID, 'nation_env');
$generalPolicyRoot = $nationStor->npc_general_policy; $generalPolicyRoot = $nationStor->npc_general_policy;
@@ -209,7 +206,7 @@ function applyGeneralPriority($priority, $nationID, $generalName): ?string
$generalPolicyRoot['priority'] = $priority; $generalPolicyRoot['priority'] = $priority;
$generalPolicyRoot['prioritySetter'] = $generalName; $generalPolicyRoot['prioritySetter'] = $generalName;
$generalPolicyRoot['prioritySetTime'] = $gameNow; $generalPolicyRoot['prioritySetTime'] = TimeUtil::now();
$nationStor->npc_general_policy = $generalPolicyRoot; $nationStor->npc_general_policy = $generalPolicyRoot;
return null; return null;
} }
+1 -2
View File
@@ -77,8 +77,7 @@ $month = $query['month'];
$repeatCnt = $query['repeatCnt']; $repeatCnt = $query['repeatCnt'];
$rawAttacker = $query['attackerGeneral']; $rawAttacker = $query['attackerGeneral'];
$battleClock = GameClock::fromStorage(KVStorage::getStorage(DB::db(), 'game_env')); $rawAttacker['turntime'] = TimeUtil::now();
$rawAttacker['turntime'] = $battleClock->formatTick($battleClock->nowTick());
$rawAttackerCity = $query['attackerCity']; $rawAttackerCity = $query['attackerCity'];
$rawAttackerNation = $query['attackerNation']; $rawAttackerNation = $query['attackerNation'];
+13 -65
View File
@@ -7,7 +7,6 @@ include "func.php";
WebUtil::requireAJAX(); WebUtil::requireAJAX();
$pick = Util::getPost('pick'); $pick = Util::getPost('pick');
$pictureSource = Util::getPost('picture_source', 'string', 'selected');
if(!$pick){ if(!$pick){
Json::die([ Json::die([
@@ -22,8 +21,8 @@ $db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env'); $gameStor = KVStorage::getStorage($db, 'game_env');
$rootDB = RootDB::db(); $rootDB = RootDB::db();
$clock = GameClock::fromStorage($gameStor); $oNow = new \DateTimeImmutable();
$now = $clock->nowTick(); $now = $oNow->format('Y-m-d H:i:s');
$generalID = $db->queryFirstField('SELECT no FROM general WHERE owner = %i', $userID); $generalID = $db->queryFirstField('SELECT no FROM general WHERE owner = %i', $userID);
if(!$generalID){ if(!$generalID){
@@ -36,20 +35,10 @@ if(!$generalID){
list( list(
$year, $year,
$month, $month,
$startYear,
$maxgeneral, $maxgeneral,
$npcmode, $npcmode,
$turnterm, $turnterm
$showImgLevel ) = $gameStor->getValuesAsArray(['year', 'month', 'maxgeneral', 'npcmode', 'turnterm']);
) = $gameStor->getValuesAsArray([
'year',
'month',
'startyear',
'maxgeneral',
'npcmode',
'turnterm',
'show_img_level',
]);
if($npcmode!=2){ if($npcmode!=2){
Json::die([ Json::die([
@@ -66,10 +55,7 @@ if(!$info){
]); ]);
} }
$ownerInfo = RootDB::db()->queryFirstRow( $ownerInfo = RootDB::db()->queryFirstRow('SELECT `name`,`picture`,`imgsvr` FROM member WHERE `NO`=%i',$userID);
'SELECT `name`,`picture`,`imgsvr`,`grade` FROM member WHERE `NO`=%i',
$userID
);
if(!$ownerInfo){ if(!$ownerInfo){
Json::die([ Json::die([
'result'=>false, 'result'=>false,
@@ -78,27 +64,6 @@ if(!$ownerInfo){
} }
$info = Json::decode($info); $info = Json::decode($info);
$isCentennialAllStar = CentennialAllStarGrowthService::isActive();
if ($isCentennialAllStar) {
if (!in_array($pictureSource, ['current', 'own', 'selected'], true)) {
Json::die([
'result' => false,
'reason' => '올바르지 않은 전콘 선택입니다.',
]);
}
if ($pictureSource === 'own') {
$canUseOwnPicture = in_array('picture', GameConst::$generalPoolAllowOption, true)
&& $showImgLevel >= 1
&& $ownerInfo['grade'] >= 1
&& $ownerInfo['picture'] !== '';
if (!$canUseOwnPicture) {
Json::die([
'result' => false,
'reason' => '사용할 수 있는 내 전콘이 없습니다.',
]);
}
}
}
$generalObj = General::createObjFromDB($generalID); $generalObj = General::createObjFromDB($generalID);
@@ -136,19 +101,18 @@ $db->update('select_pool',[
'reserved_until'=>null, 'reserved_until'=>null,
], '(owner=%i or reserved_until < %s) AND general_id is NULL', $userID, $now); ], '(owner=%i or reserved_until < %s) AND general_id is NULL', $userID, $now);
if ($isCentennialAllStar) {
CentennialAllStarGrowthService::prepareLegacyUserReselection($generalObj);
CentennialAllStarGrowthService::applyTarget($generalObj, $info, [
'startyear' => $startYear,
'year' => $year,
'month' => $month,
]);
} else {
if(key_exists('leadership', $info)){ if(key_exists('leadership', $info)){
$generalObj->updateVar('leadership', $info['leadership']); $generalObj->updateVar('leadership', $info['leadership']);
$generalObj->updateVar('strength', $info['strength']); $generalObj->updateVar('strength', $info['strength']);
$generalObj->updateVar('intel', $info['intel']); $generalObj->updateVar('intel', $info['intel']);
} }
if(key_exists('picture', $info)){
$generalObj->updateVar('imgsvr', $info['imgsvr']);
$generalObj->updateVar('picture', $info['picture']);
}
if(key_exists('generalName', $info)){
$generalObj->updateVar('name', $info['generalName']);
}
if(key_exists('dex', $info)){ if(key_exists('dex', $info)){
$generalObj->updateVar('dex1', $info['dex'][0]); $generalObj->updateVar('dex1', $info['dex'][0]);
$generalObj->updateVar('dex2', $info['dex'][1]); $generalObj->updateVar('dex2', $info['dex'][1]);
@@ -165,23 +129,7 @@ if ($isCentennialAllStar) {
if(key_exists('specialWar', $info)){ if(key_exists('specialWar', $info)){
$generalObj->updateVar('special2', $info['specialWar']); $generalObj->updateVar('special2', $info['specialWar']);
} }
} $generalObj->setAuxVar('next_change', TimeUtil::nowAddMinutes(12 * $turnterm));
if ($isCentennialAllStar) {
if ($pictureSource === 'own') {
$generalObj->updateVar('imgsvr', $ownerInfo['imgsvr']);
$generalObj->updateVar('picture', $ownerInfo['picture']);
} elseif ($pictureSource === 'selected' && key_exists('picture', $info)) {
$generalObj->updateVar('imgsvr', $info['imgsvr']);
$generalObj->updateVar('picture', $info['picture']);
}
} elseif(key_exists('picture', $info)){
$generalObj->updateVar('imgsvr', $info['imgsvr']);
$generalObj->updateVar('picture', $info['picture']);
}
if(key_exists('generalName', $info)){
$generalObj->updateVar('name', $info['generalName']);
}
$generalObj->setAuxVar('next_change', $now + GameClock::TICKS_PER_TURN * 12);
$userNick = $ownerInfo['name']; $userNick = $ownerInfo['name'];
$generalObj->setVar('owner_name', $userNick); $generalObj->setVar('owner_name', $userNick);
+2 -3
View File
@@ -51,9 +51,8 @@ function MessageBox($str)
function LogText($prefix, $variable) function LogText($prefix, $variable)
{ {
return; $text = sprintf('%s : %s'."\r\n", $prefix, TVarDumper::dump($variable));
//$text = sprintf('%s : %s'."\r\n", $prefix, TVarDumper::dump($variable)); file_put_contents(ROOT.'/d_log/'.UniqueConst::$serverName.'_dbg_logs.txt', $text, FILE_APPEND);
//file_put_contents(ROOT.'/d_log/'.UniqueConst::$serverName.'_dbg_logs.txt', $text, FILE_APPEND);
} }
function prepareDir(string $dirPath, bool $forceCreate=true):bool{ function prepareDir(string $dirPath, bool $forceCreate=true):bool{
+430
View File
@@ -0,0 +1,430 @@
<?php
namespace sammo;
use sammo\DTO\VoteInfo;
use sammo\Enums\GeneralQueryMode;
include "lib.php";
include "func.php";
$session = Session::requireLogin()->loginGame()->setReadOnly();
$userID = Session::getUserID();
increaseRefresh("메인", 1);
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
if (!$userID) {
header('Location:..');
die();
}
//턴 실행.
TurnExecutionHelper::executeAllCommand();
if (!$session->isGameLoggedIn()) {
header('Location:..');
die();
}
$me = $db->queryFirstRow(
'SELECT no,refresh_score,turntime,newmsg,newvote,`officer_level` FROM `general`
LEFT JOIN general_access_log AS l ON `general`.no = l.general_id WHERE owner = %i',
$userID
);
//그새 사망이면
if ($me === null) {
$session->logoutGame();
header('Location: ../');
die();
}
$gameStor->cacheAll(true);
if ($me['newmsg'] == 1 || $me['newvote'] == 1) {
$db->update('general', [
'newmsg' => 0,
'newvote' => 0
], 'owner=%i', $userID);
}
$plock = boolval($db->queryFirstField('SELECT plock FROM plock WHERE `type`="GAME" LIMIT 1'));
$limitState = checkLimit($me['refresh_score']);
if ($limitState >= 2) {
printLimitMsg($me['turntime']);
exit();
}
$generalObj = General::createObjFromDB($me['no'], null, GeneralQueryMode::FullWithAccessLog);
$generalObj->setRawCity($db->queryFirstRow('SELECT * FROM city WHERE city = %i', $generalObj->getCityID()));
$scenario = $gameStor->scenario_text;
$nationID = $generalObj->getNationID();
if ($nationID) {
$nationStor = KVStorage::getStorage($db, $nationID, 'nation_env');
$nationStor->cacheAll();
}
if ($gameStor->extended_general == 0) {
$extend = "표준";
} else {
$extend = "확장";
}
if ($gameStor->fiction == 0) {
$fiction = "사실";
} else {
$fiction = "가상";
}
if ($gameStor->npcmode == 0) {
$npcmode = "불가능";
} else if ($gameStor->npcmode == 1) {
$npcmode = "가능";
} else {
$npcmode = "선택 생성";
}
$color = "cyan";
$serverName = UniqueConst::$serverName;
$serverCnt = $gameStor->server_cnt;
$auctionCount = $db->queryFirstField('SELECT count(*) FROM ng_auction WHERE finished = 0');
$isTournamentActive = $gameStor->tournament > 0;
$isTournamentApplicationOpen = $gameStor->tournament == 1;
$isBettingActive = $gameStor->tournament == 6;
$myNationStatic = getNationStaticInfo($generalObj->getNationID());
$nationColorType = substr($myNationStatic['color'] ?? '#000000', 1);
$autorunUser = ($gameStor->autorun_user) ?? [];
$otherTextInfo = [];
if ($gameStor->join_mode == 'onlyRandom') {
$otherTextInfo[] = '랜덤 임관 전용';
}
if ($autorunUser['limit_minutes'] ?? false) {
$otherTextInfo[] = getAutorunInfo($autorunUser);
}
if (!$otherTextInfo) {
$otherTextInfo = '표준';
} else {
$otherTextInfo = join(', ', $otherTextInfo);
}
$lastVoteID = $gameStor->lastVote;
$lastVote = null;
if ($lastVoteID) {
$voteStor = KVStorage::getStorage($db, 'vote');
$lastVote = VoteInfo::fromArray($voteStor->getValue("vote_{$lastVoteID}"));
if ($lastVote->endDate && $lastVote->endDate < TimeUtil::now()) {
$lastVote = null;
}
}
?>
<!DOCTYPE html>
<html>
<head>
<title><?= $serverName ?>: 메인</title>
<meta charset="UTF-8">
<meta name="color-scheme" content="dark">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=500" />
<?= WebUtil::printJS('../d_shared/common_path.js') ?>
<?= WebUtil::printJS('d_shared/base_map.js') ?>
<?= WebUtil::printCSS('../d_shared/common.css') ?>
<?= WebUtil::printDist('vue', 'v_main', true) ?>
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard/dist/web/static/pretendard.css" />
<?= WebUtil::printCSS('css/map.css') ?>
<?= WebUtil::printStaticValues([
//deprecated, staticValues를 이용할 것
'serverName' => $serverName,
'serverCnt' => $serverCnt,
'serverNick' => DB::prefix(),
'serverID' => UniqueConst::$serverID,
'maxTurn' => GameConst::$maxTurn,
'maxPushTurn' => 12,
'serverNow' => TimeUtil::now(false),
'lastExecuted' => $gameStor->turntime,
'isLocked' => $plock,
'isTournamentActive' => $isTournamentActive,
'isBettingActive' => $isBettingActive,
'staticValues' => [
'serverName' => $serverName,
'serverCnt' => $serverCnt,
'serverNick' => DB::prefix(),
'serverID' => UniqueConst::$serverID,
'maxTurn' => GameConst::$maxTurn,
'maxPushTurn' => 12,
'serverNow' => TimeUtil::now(false),
'lastExecuted' => $gameStor->turntime,
'isLocked' => $plock,
'isTournamentActive' => $isTournamentActive,
'isBettingActive' => $isBettingActive,
'mapName' => GameConst::$mapName,
'unitSet' => GameConst::$unitSet,
]
]) ?>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.1/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
</head>
<body class="img_back sam-color-<?= $nationColorType ?>">
<div id="container" class="bg0">
<div class="row toolbars gx-0">
<div class="buttonPlate"><?= allButton($gameStor->npcmode == 1) ?></button></div>
</div>
<div class="tb_layout row gx-0">
<div id="server_title" class="row py-2 center">
<h3>삼국지 모의전투 HiDCHe <?= $serverName . $serverCnt ?>기 <span class="avoid-wrap">(<font color=cyan><?= $scenario ?></font>)</span></h3>
</div>
<div class="row center gx-0">
<div class="s-border-t col py-2 col-8 col-lg-4" style="color:<?= $color ?>;">
<?= $scenario ?>
</div>
<div class="s-border-t col py-2 col-4 col-lg-2" style="color:<?= $color ?>;">
NPC 수, 상성 : <?= $extend ?>,<?= $fiction ?>
</div>
<div class="s-border-t col py-2 col-4 col-lg-2" style="color:<?= $color ?>;">
NPC선택 : <?= $npcmode ?>
</div>
<div class="s-border-t col py-2 col-4 col-lg-2" style="color:<?= $color ?>;">
토너먼트 : <?= getTournamentTermText($gameStor->turnterm) ?>
</div>
<div class="s-border-t col py-2 col-4 col-lg-2" style="color:<?= $color ?>;">
기타 설정: <?= $otherTextInfo ?>
</div>
<div class="s-border-t col py-2 col-8 col-lg-4"><?= info(2) ?></div>
<div class="s-border-t col py-2 col-4 col-lg-2">전체 접속자 수 : <?= $gameStor->online_user_cnt ?> 명</div>
<div class="s-border-t col py-2 col-4 col-lg-2">턴당 갱신횟수 : <?= $gameStor->refreshLimit ?>회</div>
<div class="s-border-t col py-2 col-8 col-lg-4"><?= info(3) ?></div>
<div class="s-border-t py-2 col col-6 col-lg-4">
<?php if ($isTournamentActive) : ?>
↑<span style='color:cyan'><?= (['전력전', '통솔전', '일기토', '설전',])[$gameStor->tnmt_type] ?? '' ?> <?= getTournament($gameStor->tournament) ?> <?= getTournamentTime() ?></span>↑
<?php else : ?>
<span style='color:magenta'>현재 토너먼트 경기 없음</span>
<?php endif; ?>
</div>
<div class="s-border-t py-2 col col-6 col-lg-2">
<div style="display:inline-block;"><?= $plock ? ("<span style='color:magenta;'>동작 시각: " . substr($gameStor->turntime, 5, 14) . "</span>") : ("<span style='color:cyan;'>동작 시각: " . substr($gameStor->turntime, 5, 14) . "</span>") ?></div>
</div>
<div class="s-border-t py-2 col col-6 col-lg-2">
<?php if ($auctionCount > 0) : ?>
<span style='color:cyan'><?= $auctionCount ?>건</span> 거래 진행중
<?php else : ?>
<span style='color:magenta'>진행중 거래 없음</span>
<?php endif; ?>
</div>
<div class="s-border-t py-2 col col-6 col-lg-4 vote-cell">
<?php
?>
<?php if ($lastVote === null) : ?>
<span style='color:magenta'>진행중 설문 없음</span>
<?php else : ?>
<span style='color:cyan'>설문 진행중</span> : <span><?= $lastVote->title ?></span>
<?php endif; ?>
</div>
</div>
<div class="row gx-0">
<div class="col s-border-t px-2 py-2">접속중인 국가: <?= $gameStor->online_nation ?></div>
</div>
<div class="row gx-0">
<div class="col s-border-t px-2 py-2">운영자 메세지 : <span style='color:yellow;'><?= $gameStor->msg ?></span></div>
</div>
<div class="row gx-0">
<div class="col s-border-t py-2" id="nation-msg-position">
<div class="px-2">【 국가방침 】</div>
<div id='nation-msg-box'>
<div id='nation-msg'><?= nationMsg($generalObj) ?></div>
</div>
</div>
</div>
<div class="row gx-0">
<div class="col s-border-t px-2 py-2">
【 접속자 】<?= onlinegen($generalObj) ?>
</div>
</div>
<?php if ($session->userGrade >= 5) : ?>
<div class="row">
<div class="col">
<a href='_admin1.php' target='_blank'><button type='button'>게임관리</button></a>
<a href='_admin2.php' target='_blank'><button type='button'>회원관리</button></a>
<a href='_admin4.php' target='_blank'><button type='button'>멀티관리</button></a>
<a href='_admin5.php' target='_blank'><button type='button'>일제정보</button></a>
<a href='_admin7.php' target='_blank'><button type='button'>로그정보</button></a>
<a href='_admin8.php' target='_blank'><button type='button'>외교정보</button></a>
<a href='_119.php' target='_blank'><button type='button'>119</button></a>
</div>
</div>
<?php elseif ($session->userGrade == 4) : ?>
<div class="row">
<div class="col">
<a href='_119.php' target='_blank'><button type='button'>119</button></a>
</div>
</div>
<?php endif; ?>
<div id="map_view" class="gx-0">
<div id="mapZone" class="view-item"><?= getMapHtml() ?></div>
<div class="view-item" id="reservedCommandZone">
<div id="reservedCommandList"></div>
<div id="actionMiniPlate" class="gx-0 row">
<div class="col">
<div class="gx-1 row">
<div class="col-8 d-grid"><button type='button' class='btn btn-sammo-base2 refreshPage'>갱 신</button></div>
<div class="col-4 d-grid"><button type='button' class='btn btn-sammo-base2' onclick="location.replace('../')">로비로</button></div>
</div>
</div>
</div>
</div>
<div id="cityInfo" class="view-item" style="border:none;text-align:center;"><?= cityInfo($generalObj) ?></div>
<div id="nation-position"><?php myNationInfo($generalObj); ?></div>
<div id="general-position"><?php generalInfo($generalObj); ?></div>
<div id="generalCommandButton" class="row gx-0">
<div class="buttonPlate bg2">
?></div>
</div>
</div>
</div>
<div id="actionMiniPlateSub" class="gx-0 row">
<div class="col">
<div class="gx-1 row">
<div class="col-3 d-grid"><button type='button' class="btn btn-dark" onclick="scrollHardTo('reservedCommandList')">명령으로</button></div>
<div class="col-5 d-grid"><button type='button' class='btn btn-sammo-base2 refreshPage'>갱 신</button></div>
<div class="col-4 d-grid"><button type='button' class='btn btn-sammo-base2' onclick="location.replace('../')">로비로</button></div>
</div>
</div>
</div>
<div class="row gx-0">
<div class="col-lg-6" id="general_public_record-position">
<div class="bg1 center s-border-tb"><b>장수 동향</b></div>
<div id="general_public_record" style="text-align:left;"><?= formatHistoryToHTML(getGlobalActionLogRecent(15)) ?></div>
</div>
<div class="col-lg-6" id="general_log-position">
<div class="bg1 center s-border-tb"><b>개인 기록</b></div>
<div id="general_log" style="text-align:left;"><?= formatHistoryToHTML(getGeneralActionLogRecent($me['no'], 15)) ?></div>
</div>
<div class="col-12" id="world_history-position">
<div class="bg1 center s-border-tb"><b>중원 정세</b></div>
<div id="world_history" colspan=2 style="text-align:left;"><?= formatHistoryToHTML(getGlobalHistoryLogRecent(15)) ?></div>
</div>
</div>
<div class="row toolbars gx-0">
<div class="buttonPlate"><?= allButton($gameStor->npcmode == 1) ?></div>
<div id="message_board" class="row gx-0">
<div class="message_input_form bg0 gx-0 row">
<div id="mailbox_list-col" class="col-6 col-lg-2 d-grid">
<select id="mailbox_list" size="1" class="form-control bg-dark text-white">
</select>
</div>
<div id="msg_input-col" class="col-12 col-lg-8 d-grid">
<input type="text" id="msg_input" maxlength="99" class="form-control">
</div>
<div id="msg_submit-col" class="col-6 col-lg-2 d-grid"><button id="msg_submit" class="btn btn-primary">서신전달&amp;갱신</button></div>
</div>
<div class="col-lg-6 board_side bg0"><a id="public_talk_position"></a>
<div class="board_header bg0">전체 메시지(최고99자)</div>
<section class="public_message">
<div class="d-grid"><button type="button" class="load_old_message btn btn-secondary" data-msg_type="public">이전 메시지 불러오기</button></div>
</section>
</div>
<div class="col-lg-6 board_side bg0"><a id="national_talk_position"></a>
<div class="board_header bg0">국가 메시지(최고99자)</div>
<section class="national_message">
<div class="d-grid"><button type="button" class="load_old_message btn btn-secondary" data-msg_type="national">이전 메시지 불러오기</button></div>
</section>
</div>
<div class="col-lg-6 board_side bg0"><a id="private_talk_position"></a>
<div class="board_header bg0">개인 메시지(최고99자)</div>
<section class="private_message">
<div class="d-grid"><button type="button" class="load_old_message btn btn-secondary" data-msg_type="private">이전 메시지 불러오기</button></div>
</section>
</div>
<div class="col-lg-6 board_side bg0"><a id="diplomacy_talk_position"></a>
<div class="board_header bg0">외교 메시지(최고99자)</div>
<section class="diplomacy_message">
<div class="d-grid"><button type="button" class="load_old_message btn btn-secondary" data-msg_type="diplomacy">이전 메시지 불러오기</button></div>
</section>
</div>
</div>
<div class="row toolbars gx-0">
<div class="buttonPlate"><?= allButton($gameStor->npcmode == 1) ?></div><?= banner() ?>
</div>
</div>
<?php
if ($limitState == 1) {
MessageBox("접속제한이 얼마 남지 않았습니다!");
}
if ($me['newmsg'] == 1) {
MessageBox("새로운 서신이 도착했습니다!");
}
if ($me['newvote'] == 1) {
$develcost = $gameStor->develcost * 5;
MessageBox("설문조사에 참여하시면 금{$develcost}과 유니크템을 드립니다! (우측 상단 설문조사 메뉴)");
}
?>
</div>
<nav class="navbar navbar-expand fixed-bottom navbar-dark bg-dark d-sm-block d-lg-none p-0" id="navbar500">
<div class="container-fluid px-0">
<div class="collapse navbar-collapse">
<ul class="navbar-nav me-auto mx-auto">
<li class="nav-item dropup">
<div class="dropdown-toggle text-white btn btn-sammo-base2" id="navbarGlobal" role="button" data-bs-toggle="dropdown" aria-expanded="false">
외부 메뉴
</div>
<ul class="dropdown-menu dropdown-menu-start" aria-labelledby="navbarGlobal" id="navbarGlobalItems">
<?= allButton($gameStor->npcmode == 1, ['btnBegin' => '<li>', 'btnEnd' => '</li>', 'btnClass' => 'dropdown-item']) ?>
</ul>
</li>
<li class="nav-item dropup">
<div class="dropdown-toggle btn btn-sammo-nation" id="navbarNation" role="button" data-bs-toggle="dropdown" aria-expanded="false">
국가 메뉴
</div>
<ul class="dropdown-menu" aria-labelledby="navbarNation" id="navbarNationItems">
</ul>
</li>
<li class="nav-item dropup">
<div class="dropdown-toggle text-white btn btn-dark" id="navbarQuick" role="button" data-bs-toggle="dropdown" aria-expanded="false">
빠른 이동
</div>
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarDropdown" id="navbarQuickItems">
<li><a class="dropdown-item disabled">국가 정보</a></button></li>
<hr class="dropdown-divider">
</hr>
<li><button type="button" onclick="scrollHardTo('nation-msg-position')" class="dropdown-item">방침</button></li>
<li><button type="button" onclick="scrollHardTo('reservedCommandList')" class="dropdown-item">명령</button></li>
<li><button type="button" onclick="scrollHardTo('nation-position')" class="dropdown-item">국가</button></li>
<li><button type="button" onclick="scrollHardTo('general-position')" class="dropdown-item">장수</button></li>
<li><button type="button" onclick="scrollHardTo('cityInfo')" class="dropdown-item">도시</button></li>
<li><a class="dropdown-item disabled">동향 정보</a></button></li>
<hr class="dropdown-divider">
</hr>
<li><button type="button" onclick="scrollHardTo('mapZone')" class="dropdown-item">지도</button></li>
<li><button type="button" onclick="scrollHardTo('general_public_record-position')" class="dropdown-item">동향</button></li>
<li><button type="button" onclick="scrollHardTo('general_log-position')" class="dropdown-item">개인</button></li>
<li><button type="button" onclick="scrollHardTo('world_history-position')" class="dropdown-item">정세</button></li>
<li><span>&nbsp;</span></li>
<li><a class="dropdown-item disabled">메시지</a></button></li>
<hr class="dropdown-divider">
</hr>
<li><button type="button" onclick="scrollHardTo('public_talk_position')" class="dropdown-item">전체</button></li>
<li><button type="button" onclick="scrollHardTo('national_talk_position')" class="dropdown-item">국가</button></li>
<li><button type="button" onclick="scrollHardTo('private_talk_position')" class="dropdown-item">개인</button></li>
<li><button type="button" onclick="scrollHardTo('diplomacy_talk_position')" class="dropdown-item">외교</button></li>
<li><button type='button' class='btn btn-sammo-base2' onclick="location.replace('../')">로비로</button></li>
</ul>
</li>
<li class="nav-item">
<a class="refreshPage btn btn-sammo-base2 text-white" role="button">갱신</a>
</li>
</ul>
</div>
</div>
</nav>
</body>
</html>
+1 -11
View File
@@ -8,14 +8,4 @@ $session = Session::getInstance()->setReadOnly();
$db = DB::db(); $db = DB::db();
$updated = false; TurnExecutionHelper::executeAllCommand();
$locked = false;
$lastExecuted = TurnExecutionHelper::executeAllCommand($updated, $locked);
$clock = GameClock::fromStorage(KVStorage::getStorage($db, 'game_env'));
Json::die([
'result' => true,
'updated' => $updated,
'locked' => $locked,
'lastExecutedTick' => $lastExecuted,
'lastExecuted' => $clock->formatTick($lastExecuted, true),
]);
+10 -13
View File
@@ -526,7 +526,7 @@ function DeleteConflict($nation)
function getConquerNation($city): int function getConquerNation($city): int
{ {
$conflict = Json::decode($city['conflict']); $conflict = Json::decode($city['conflict']);
return array_key_first($conflict); return Util::array_first_key($conflict);
} }
function ConquerCity(array $admin, General $general, array $city, array $defenderCityGeneralList) function ConquerCity(array $admin, General $general, array $city, array $defenderCityGeneralList)
@@ -718,17 +718,14 @@ function ConquerCity(array $admin, General $general, array $city, array $defende
$attackerLogger->pushGlobalHistoryLog("<M><b>【긴급천도】</b></><D><b>{$defenderNationName}</b></>{$josaYi} 수도가 함락되어 <G><b>$minCityName</b></>{$josaRo} 긴급천도하였습니다."); $attackerLogger->pushGlobalHistoryLog("<M><b>【긴급천도】</b></><D><b>{$defenderNationName}</b></>{$josaYi} 수도가 함락되어 <G><b>$minCityName</b></>{$josaRo} 긴급천도하였습니다.");
$moveLog = "수도가 함락되어 <G><b>$minCityName</b></>{$josaRo} <M>긴급천도</>합니다."; $moveLog = "수도가 함락되어 <G><b>$minCityName</b></>{$josaRo} <M>긴급천도</>합니다.";
foreach ($db->queryAllLists( //아국 수뇌부에게 로그 전달
'SELECT no, officer_level FROM general WHERE nation=%i', foreach ($db->queryFirstColumn(
'SELECT no FROM general WHERE nation=%i AND officer_level>=5',
$defenderNationID $defenderNationID
) as [$defenderGeneralID, $defenderGeneralChiefLevel]) { ) as $defenderChiefID) {
$defenderLogger = new ActionLogger($defenderGeneralID, $defenderNationID, $year, $month); $chiefLogger = new ActionLogger($defenderChiefID, $defenderNationID, $year, $month);
$defenderLogger->pushGeneralActionLog($moveLog, ActionLogger::PLAIN); $chiefLogger->pushGeneralActionLog($moveLog, ActionLogger::PLAIN);
if($defenderGeneralChiefLevel >= 5){ $chiefLogger->flush();
$defenderLogger->pushGeneralActionLog("수뇌는 <G><b>{$minCityName}</b></>{$josaRo} 집합되었습니다.");
}
$defenderLogger->flush();
} }
//천도 //천도
@@ -785,8 +782,8 @@ function ConquerCity(array $admin, General $general, array $city, array $defende
'officer_set' => 0, 'officer_set' => 0,
]; ];
if ($city['level'] > 3) { if ($city['level'] > 3) {
$query['def'] = GameConst::$defaultCityWall; $query['def'] = 1000;
$query['wall'] = GameConst::$defaultCityWall; $query['wall'] = 1000;
} else { } else {
$query['def'] = $db->sqleval('def_max/2'); $query['def'] = $db->sqleval('def_max/2');
$query['wall'] = $db->sqleval('wall_max/2'); $query['wall'] = $db->sqleval('wall_max/2');
+2 -2
View File
@@ -21,7 +21,7 @@ class BidUniqueAuction extends \sammo\BaseAPI
]) ])
->rule('int', 'amount') ->rule('int', 'amount')
->rule('int', 'auctionID') ->rule('int', 'auctionID')
->rule('boolean', 'extendCloseTick'); ->rule('boolean', 'extendCloseDate');
if (!$v->validate()) { if (!$v->validate()) {
return $v->errorStr(); return $v->errorStr();
@@ -38,7 +38,7 @@ class BidUniqueAuction extends \sammo\BaseAPI
{ {
$auctionID = $this->args['auctionID']; $auctionID = $this->args['auctionID'];
$amount = $this->args['amount']; $amount = $this->args['amount'];
$tryExtendCloseDate = $this->args['extendCloseTick'] ?? false; $tryExtendCloseDate = $this->args['extendCloseDate'] ?? false;
$generalID = $session->generalID; $generalID = $session->generalID;
$general = General::createObjFromDB($generalID); $general = General::createObjFromDB($generalID);
@@ -15,8 +15,6 @@ use sammo\General;
use sammo\Json; use sammo\Json;
use sammo\TimeUtil; use sammo\TimeUtil;
use sammo\Util; use sammo\Util;
use sammo\GameClock;
use sammo\KVStorage;
use function sammo\getAuctionLogRecent; use function sammo\getAuctionLogRecent;
@@ -35,13 +33,12 @@ class GetActiveResourceAuctionList extends \sammo\BaseAPI
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag): null | string | array | APIRecoveryType public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag): null | string | array | APIRecoveryType
{ {
$db = DB::db(); $db = DB::db();
$clock = GameClock::fromStorage(KVStorage::getStorage($db, 'game_env'));
$buyRiceList = []; $buyRiceList = [];
$sellRiceList = []; $sellRiceList = [];
/** @var AuctionInfo[] */ /** @var AuctionInfo[] */
$auctions = array_map(fn ($raw) => AuctionInfo::fromArray($raw), $db->query( $auctions = array_map(fn ($raw) => AuctionInfo::fromArray($raw), $db->query(
'SELECT * FROM `ng_auction` WHERE `type` IN %ls AND `finished` = 0 ORDER BY `close_tick` ASC', 'SELECT * FROM `ng_auction` WHERE `type` IN %ls AND `finished` = 0 ORDER BY `close_date` ASC',
[ [
AuctionType::BuyRice->value, AuctionType::BuyRice->value,
AuctionType::SellRice->value, AuctionType::SellRice->value,
@@ -90,8 +87,8 @@ class GetActiveResourceAuctionList extends \sammo\BaseAPI
'type' => $auction->type->value, 'type' => $auction->type->value,
'hostGeneralID' => $auction->hostGeneralID, 'hostGeneralID' => $auction->hostGeneralID,
'hostName' => $auction->detail->hostName, 'hostName' => $auction->detail->hostName,
'openDate' => $clock->formatTick($auction->openTick), 'openDate' => TimeUtil::format($auction->openDate, false),
'closeDate' => $clock->formatTick($auction->closeTick), 'closeDate' => TimeUtil::format($auction->closeDate, false),
'amount' => $auction->detail->amount, 'amount' => $auction->detail->amount,
'startBidAmount' => $auction->detail->startBidAmount, 'startBidAmount' => $auction->detail->startBidAmount,
'finishBidAmount' => $auction->detail->finishBidAmount, 'finishBidAmount' => $auction->detail->finishBidAmount,
@@ -14,8 +14,6 @@ use sammo\Enums\GeneralQueryMode;
use sammo\Enums\InheritanceKey; use sammo\Enums\InheritanceKey;
use sammo\InheritancePointManager; use sammo\InheritancePointManager;
use sammo\TimeUtil; use sammo\TimeUtil;
use sammo\GameClock;
use sammo\KVStorage;
use sammo\Validator; use sammo\Validator;
use sammo\General; use sammo\General;
@@ -44,7 +42,6 @@ class GetUniqueItemAuctionDetail extends \sammo\BaseAPI
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag): null | string | array | APIRecoveryType public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag): null | string | array | APIRecoveryType
{ {
$db = DB::db(); $db = DB::db();
$clock = GameClock::fromStorage(KVStorage::getStorage($db, 'game_env'));
$generalID = $session->generalID; $generalID = $session->generalID;
$auctionID = $this->args['auctionID']; $auctionID = $this->args['auctionID'];
@@ -95,11 +92,9 @@ class GetUniqueItemAuctionDetail extends \sammo\BaseAPI
'target' => $auction->target, 'target' => $auction->target,
'isCallerHost' => $auction->hostGeneralID === $generalID, 'isCallerHost' => $auction->hostGeneralID === $generalID,
'hostName' => $auction->detail->hostName, 'hostName' => $auction->detail->hostName,
'closeDate' => $clock->formatTick($auction->closeTick), 'closeDate' => TimeUtil::format($auction->closeDate, false),
'remainCloseDateExtensionCnt' => $auction->detail->remainCloseDateExtensionCnt, 'remainCloseDateExtensionCnt' => $auction->detail->remainCloseDateExtensionCnt,
'availableLatestBidCloseDate' => $auction->detail->availableLatestBidCloseTick === null 'availableLatestBidCloseDate' => TimeUtil::format($auction->detail->availableLatestBidCloseDate, false),
? null
: $clock->formatTick($auction->detail->availableLatestBidCloseTick),
], ],
'bidList' => $responseBid, 'bidList' => $responseBid,
'obfuscatedName' => $obfuscatedName, 'obfuscatedName' => $obfuscatedName,
@@ -12,8 +12,6 @@ use sammo\Enums\APIRecoveryType;
use sammo\Enums\AuctionType; use sammo\Enums\AuctionType;
use sammo\TimeUtil; use sammo\TimeUtil;
use sammo\Util; use sammo\Util;
use sammo\GameClock;
use sammo\KVStorage;
class GetUniqueItemAuctionList extends \sammo\BaseAPI class GetUniqueItemAuctionList extends \sammo\BaseAPI
{ {
@@ -30,13 +28,12 @@ class GetUniqueItemAuctionList extends \sammo\BaseAPI
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag): null | string | array | APIRecoveryType public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag): null | string | array | APIRecoveryType
{ {
$db = DB::db(); $db = DB::db();
$clock = GameClock::fromStorage(KVStorage::getStorage($db, 'game_env'));
$generalID = $session->generalID; $generalID = $session->generalID;
/** @var AuctionInfo[] */ /** @var AuctionInfo[] */
$auctions = array_map(fn($raw)=>AuctionInfo::fromArray($raw), $db->query( $auctions = array_map(fn($raw)=>AuctionInfo::fromArray($raw), $db->query(
'SELECT * FROM `ng_auction` WHERE `type` = %s ORDER BY `close_tick` ASC', 'SELECT * FROM `ng_auction` WHERE `type` = %s ORDER BY `close_date` ASC',
AuctionType::UniqueItem->value AuctionType::UniqueItem->value
) ?? []); ) ?? []);
@@ -88,11 +85,9 @@ class GetUniqueItemAuctionList extends \sammo\BaseAPI
'target' => $auction->target, 'target' => $auction->target,
'isCallerHost' => $auction->hostGeneralID === $generalID, 'isCallerHost' => $auction->hostGeneralID === $generalID,
'hostName' => $auction->detail->hostName, 'hostName' => $auction->detail->hostName,
'closeDate' => $clock->formatTick($auction->closeTick), 'closeDate' => TimeUtil::format($auction->closeDate, false),
'remainCloseDateExtensionCnt' => $auction->detail->remainCloseDateExtensionCnt, 'remainCloseDateExtensionCnt' => $auction->detail->remainCloseDateExtensionCnt,
'availableLatestBidCloseDate' => $auction->detail->availableLatestBidCloseTick === null 'availableLatestBidCloseDate' => TimeUtil::format($auction->detail->availableLatestBidCloseDate, false),
? null
: $clock->formatTick($auction->detail->availableLatestBidCloseTick),
'highestBid' => [ 'highestBid' => [
'generalName' => $highestBid->aux->generalName, 'generalName' => $highestBid->aux->generalName,
'amount' => $highestBid->amount, 'amount' => $highestBid->amount,
+3 -7
View File
@@ -7,10 +7,9 @@ use DateTimeInterface;
use sammo\DB; use sammo\DB;
use sammo\Enums\APIRecoveryType; use sammo\Enums\APIRecoveryType;
use sammo\GameConst; use sammo\GameConst;
use sammo\GameClock;
use sammo\Json; use sammo\Json;
use sammo\KVStorage; use sammo\KVStorage;
use sammo\Util; use sammo\TimeUtil;
use function sammo\cutTurn; use function sammo\cutTurn;
@@ -32,7 +31,6 @@ class GetReservedCommand extends \sammo\BaseAPI
$commandList = []; $commandList = [];
$gameStor = KVStorage::getStorage($db, 'game_env'); $gameStor = KVStorage::getStorage($db, 'game_env');
$clock = GameClock::fromStorage($gameStor);
$generalID = $session->generalID; $generalID = $session->generalID;
$invalidTurnList = 0; $invalidTurnList = 0;
@@ -84,13 +82,11 @@ class GetReservedCommand extends \sammo\BaseAPI
return [ return [
'result' => true, 'result' => true,
'turnTimeTick' => Util::toInt($turnTime), 'turnTime' => $turnTime,
'turnTime' => $clock->formatTick(Util::toInt($turnTime)),
'turnTerm' => $turnTerm, 'turnTerm' => $turnTerm,
'year' => $year, 'year' => $year,
'month' => $month, 'month' => $month,
'date' => $clock->formatTick($clock->nowTick(), true), 'date' => TimeUtil::now(true),
'clockMode' => $clock->getMode(),
'turn' => $commandList, 'turn' => $commandList,
'autorun_limit' => $generalAux['autorun_limit'] ?? null, 'autorun_limit' => $generalAux['autorun_limit'] ?? null,
]; ];
+11 -24
View File
@@ -11,8 +11,7 @@ use sammo\Session;
use sammo\General; use sammo\General;
use sammo\JosaUtil; use sammo\JosaUtil;
use sammo\KVStorage; use sammo\KVStorage;
use sammo\GameClock; use sammo\TimeUtil;
use sammo\Util;
use function sammo\addTurn; use function sammo\addTurn;
use function sammo\increaseRefresh; use function sammo\increaseRefresh;
@@ -38,14 +37,8 @@ class DieOnPrestart extends \sammo\BaseAPI
$db = DB::db(); $db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env'); $gameStor = KVStorage::getStorage($db, 'game_env');
$gameStor->cacheValues(['turnterm', 'opentime', 'turntime', 'year', 'month']); $gameStor->cacheValues(['turnterm', 'opentime', 'turntime', 'year', 'month']);
$clock = GameClock::fromStorage($gameStor);
$nowTick = $clock->nowTick();
$general = $db->queryFirstRow('SELECT no,name,nation,owner_name,npc FROM general WHERE owner=%i AND npc = 0', $userID); $general = $db->queryFirstRow('SELECT no,name,nation,owner_name,npc FROM general WHERE owner=%i AND npc = 0', $userID);
if (!$general) {
return '장수가 없습니다';
}
$lastRefresh = $db->queryFirstField( $lastRefresh = $db->queryFirstField(
'SELECT %b FROM general_access_log WHERE %b = %i', 'SELECT %b FROM general_access_log WHERE %b = %i',
GeneralAccessLogColumn::lastRefresh->value, GeneralAccessLogColumn::lastRefresh->value,
@@ -53,9 +46,8 @@ class DieOnPrestart extends \sammo\BaseAPI
$general['no'] $general['no']
); );
$generalObj = General::createObjFromDB($general['no']); if (!$general) {
if ($generalObj instanceof DummyGeneral) { return '장수가 없습니다';
trigger_error("올바르지 않은 삭제 프로세스 $userID", E_USER_WARNING);
} }
increaseRefresh("장수 삭제", 1); increaseRefresh("장수 삭제", 1);
@@ -69,21 +61,16 @@ class DieOnPrestart extends \sammo\BaseAPI
return '이미 국가에 소속되어있습니다.'; return '이미 국가에 소속되어있습니다.';
} }
$targetTime = $generalObj->getAuxVar('prestart_delete_after'); //서버 가오픈시 할 수 있는 행동
if (!is_int($targetTime)) { $targetTime = addTurn($lastRefresh, $gameStor->turnterm, GameConst::$minTurnDieOnPrestart);
$targetTime = addTurn( if ($targetTime > TimeUtil::now()) {
$lastRefresh === null ? $nowTick : Util::toInt($lastRefresh), $targetTimeShort = substr($targetTime, 0, 19);
$gameStor->turnterm, return "아직 삭제할 수 없습니다. {$targetTimeShort} 부터 가능합니다.";
GameConst::$minTurnDieOnPrestart
);
$generalObj->setAuxVar('prestart_delete_after', $targetTime);
$generalObj->applyDB($db);
} }
//서버 가오픈시 할 수 있는 행동 $generalObj = General::createObjFromDB($general['no']);
if ($targetTime > $nowTick) { if ($generalObj instanceof DummyGeneral) {
$targetTimeShort = $clock->formatTick($targetTime); trigger_error("올바르지 않은 삭제 프로세스 $userID", E_USER_WARNING);
return "아직 삭제할 수 없습니다. {$targetTimeShort} 부터 가능합니다.";
} }
$generalName = $generalObj->getName(); $generalName = $generalObj->getName();
+8 -18
View File
@@ -14,13 +14,13 @@ use sammo\Enums\GeneralColumn;
use sammo\Enums\GeneralQueryMode; use sammo\Enums\GeneralQueryMode;
use sammo\Enums\RankColumn; use sammo\Enums\RankColumn;
use sammo\GameConst; use sammo\GameConst;
use sammo\GameClock;
use sammo\General; use sammo\General;
use sammo\KVStorage; use sammo\KVStorage;
use sammo\LastTurn; use sammo\LastTurn;
use sammo\Validator; use sammo\Validator;
use sammo\Session; use sammo\Session;
use sammo\TimeUtil;
use sammo\Util; use sammo\Util;
use function sammo\buildNationCommandClass; use function sammo\buildNationCommandClass;
@@ -105,7 +105,6 @@ class GetFrontInfo extends \sammo\BaseAPI
$db = DB::db(); $db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env'); $gameStor = KVStorage::getStorage($db, 'game_env');
$clock = GameClock::fromStorage($gameStor);
$gameStor->cacheValues(['isunited', 'opentime', 'refresh']); $gameStor->cacheValues(['isunited', 'opentime', 'refresh']);
$lastHistoryID = $this->args['lastWorldHistoryID']; $lastHistoryID = $this->args['lastWorldHistoryID'];
@@ -159,7 +158,6 @@ class GetFrontInfo extends \sammo\BaseAPI
private function generateGlobalInfo(MeekroDB $db): array private function generateGlobalInfo(MeekroDB $db): array
{ {
$gameStor = KVStorage::getStorage($db, 'game_env'); $gameStor = KVStorage::getStorage($db, 'game_env');
$clock = GameClock::fromStorage($gameStor);
[ [
$scenarioText, $extendedGeneral, $isFiction, $npcMode, $scenarioText, $extendedGeneral, $isFiction, $npcMode,
@@ -184,9 +182,8 @@ class GetFrontInfo extends \sammo\BaseAPI
$lastVote = null; $lastVote = null;
if ($lastVoteID) { if ($lastVoteID) {
$voteStor = KVStorage::getStorage($db, 'vote'); $voteStor = KVStorage::getStorage($db, 'vote');
$rawLastVote = VoteInfo::normalizeGameStorage($voteStor->getValue("vote_{$lastVoteID}"), $clock); $lastVote = VoteInfo::fromArray($voteStor->getValue("vote_{$lastVoteID}"));
$lastVote = VoteInfo::fromGameStorage($rawLastVote, $clock); if ($lastVote->endDate && $lastVote->endDate < TimeUtil::now()) {
if ($rawLastVote['endTick'] !== null && $rawLastVote['endTick'] < $clock->nowTick()) {
$lastVote = null; $lastVote = null;
} }
} }
@@ -213,8 +210,7 @@ class GetFrontInfo extends \sammo\BaseAPI
'month' => $month, 'month' => $month,
'autorunUser' => $autorunUser, 'autorunUser' => $autorunUser,
'turnterm' => $turnterm, 'turnterm' => $turnterm,
'lastExecutedTick' => $lastExecuted, 'lastExecuted' => $lastExecuted,
'lastExecuted' => $clock->formatTick(Util::toInt($lastExecuted), true),
'lastVoteID' => $lastVoteID, 'lastVoteID' => $lastVoteID,
'develCost' => $develCost, 'develCost' => $develCost,
'noticeMsg' => $noticeMsg, 'noticeMsg' => $noticeMsg,
@@ -228,8 +224,7 @@ class GetFrontInfo extends \sammo\BaseAPI
'isLocked' => $isLocked, 'isLocked' => $isLocked,
'tournamentType' => $tournamentType, 'tournamentType' => $tournamentType,
'tournamentState' => $tournamentState, 'tournamentState' => $tournamentState,
'tournamentTimeTick' => $tournamentTime, 'tournamentTime' => $tournamentTime,
'tournamentTime' => $tournamentTime === null ? null : $clock->formatTick(Util::toInt($tournamentTime)),
'genCount' => $globalGenCount, 'genCount' => $globalGenCount,
'generalCntLimit' => $generalCntLimit, 'generalCntLimit' => $generalCntLimit,
'serverCnt' => $serverCnt, 'serverCnt' => $serverCnt,
@@ -366,7 +361,6 @@ class GetFrontInfo extends \sammo\BaseAPI
public function generateGeneralInfo(MeekroDB $db, General $general, array $rawNation): array public function generateGeneralInfo(MeekroDB $db, General $general, array $rawNation): array
{ {
$clock = GameClock::fromStorage(KVStorage::getStorage($db, 'game_env'));
$permission = checkSecretPermission($general->getRaw()); $permission = checkSecretPermission($general->getRaw());
@@ -431,12 +425,8 @@ class GetFrontInfo extends \sammo\BaseAPI
'crew' => $general->getVar(GeneralColumn::crew), // number; 'crew' => $general->getVar(GeneralColumn::crew), // number;
'train' => $general->getVar(GeneralColumn::train), // number; 'train' => $general->getVar(GeneralColumn::train), // number;
'atmos' => $general->getVar(GeneralColumn::atmos), // number; 'atmos' => $general->getVar(GeneralColumn::atmos), // number;
'turntimeTick' => $general->getTurnTick(), // number; 'turntime' => $general->getVar(GeneralColumn::turntime), // string;
'turntime' => $general->getTurnTime(), // string; 'recent_war' => $general->getVar(GeneralColumn::recent_war), // string;
'recent_war_tick' => $general->getVar(GeneralColumn::recent_war), // number|null;
'recent_war' => $general->getVar(GeneralColumn::recent_war) === null
? null
: $clock->formatTick(Util::toInt($general->getVar(GeneralColumn::recent_war)), true), // string|null;
'horse' => $general->getVar(GeneralColumn::horse), // GameObjClassKey; 'horse' => $general->getVar(GeneralColumn::horse), // GameObjClassKey;
'weapon' => $general->getVar(GeneralColumn::weapon), // GameObjClassKey; 'weapon' => $general->getVar(GeneralColumn::weapon), // GameObjClassKey;
'book' => $general->getVar(GeneralColumn::book), // GameObjClassKey; 'book' => $general->getVar(GeneralColumn::book), // GameObjClassKey;
@@ -554,7 +544,7 @@ class GetFrontInfo extends \sammo\BaseAPI
'result' => false, 'result' => false,
'reason' => '접속 제한중입니다.', 'reason' => '접속 제한중입니다.',
'recovery' => APIRecoveryType::GameQuota, 'recovery' => APIRecoveryType::GameQuota,
'recovery_arg' => $general->getTurnTime(), 'recovery_arg' => $general->getVar('turntime'),
]; ];
} }
+11 -17
View File
@@ -11,7 +11,6 @@ use sammo\Enums\APIRecoveryType;
use sammo\Enums\GeneralAccessLogColumn; use sammo\Enums\GeneralAccessLogColumn;
use sammo\Enums\RankColumn; use sammo\Enums\RankColumn;
use sammo\GameConst; use sammo\GameConst;
use sammo\GameClock;
use sammo\GameUnitConst; use sammo\GameUnitConst;
use sammo\General; use sammo\General;
use sammo\InheritancePointManager; use sammo\InheritancePointManager;
@@ -100,7 +99,7 @@ class Join extends \sammo\BaseAPI
} }
$gameID = UniqueConst::$serverID; $gameID = UniqueConst::$serverID;
$alreadyJoined = $db->queryFirstField('SELECT COUNT(*) FROM `inheritance_result` WHERE `server_id` = %s AND `owner` = %i', $gameID, $userID); $alreadyJoined = $db->queryFirstField('SELECT count(*) FROM `storage` WHERE `namespace` = %s AND `key` LIKE %s', 'inheritance_result', "{$gameID}_{$userID}_%");
if ($alreadyJoined) { if ($alreadyJoined) {
//이미 받았음 //이미 받았음
return 0; return 0;
@@ -158,7 +157,7 @@ class Join extends \sammo\BaseAPI
$penalty = []; $penalty = [];
foreach($penaltyInfo as $penaltyKey => $penaltyValue){ foreach($penaltyInfo as $penaltyKey => $penaltyValue){
if(($penaltyValue['expire'] ?? 0) > TimeUtil::now()){ if($penaltyValue['expire'] ?? 0 > TimeUtil::now()){
$penalty[$penaltyKey] = $penaltyValue['value']; $penalty[$penaltyKey] = $penaltyValue['value'];
} }
} }
@@ -166,7 +165,6 @@ class Join extends \sammo\BaseAPI
$db = DB::db(); $db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env'); $gameStor = KVStorage::getStorage($db, 'game_env');
$gameStor->cacheValues(['year', 'month', 'maxgeneral', 'scenario', 'show_img_level', 'block_general_create', 'turnterm', 'turntime', 'genius', 'npcmode']); $gameStor->cacheValues(['year', 'month', 'maxgeneral', 'scenario', 'show_img_level', 'block_general_create', 'turnterm', 'turntime', 'genius', 'npcmode']);
$clock = GameClock::fromStorage($gameStor);
########## 동일 정보 존재여부 확인. ########## ########## 동일 정보 존재여부 확인. ##########
$block_general_create = $gameStor->getValue('block_general_create'); $block_general_create = $gameStor->getValue('block_general_create');
@@ -224,7 +222,7 @@ class Join extends \sammo\BaseAPI
$userLogger = new UserLogger($userID, $admin['year'], $admin['month'], false); $userLogger = new UserLogger($userID, $admin['year'], $admin['month'], false);
$now = $clock->nowTick(); $now = TimeUtil::now(false);
$rng = new RandUtil(new LiteHashDRBG(Util::simpleSerialize( $rng = new RandUtil(new LiteHashDRBG(Util::simpleSerialize(
UniqueConst::$hiddenSeed, UniqueConst::$hiddenSeed,
'MakeGeneral', 'MakeGeneral',
@@ -362,14 +360,17 @@ class Join extends \sammo\BaseAPI
$userLogger->push(sprintf("턴 시간 %02d:%02d 로 지정", intdiv($inheritTurntime, 60), $inheritTurntime % 60), "inheritPoint"); $userLogger->push(sprintf("턴 시간 %02d:%02d 로 지정", intdiv($inheritTurntime, 60), $inheritTurntime % 60), "inheritPoint");
$inheritTurnMicrosecond = $rng->nextRangeInt(0, 999999); $inheritTurntime += $rng->nextRangeInt(0, 999999) / 1000000;
$turntime = cutTurn(Util::toInt($admin['turntime']), $admin['turnterm'])
+ $clock->ticksFromSeconds($inheritTurntime) $turntime = new \DateTimeImmutable(cutTurn($admin['turntime'], $admin['turnterm']));
+ intdiv($inheritTurnMicrosecond * $clock->ticksPerSecond(), 1_000_000); $turntime = $turntime->add(TimeUtil::secondsToDateInterval($inheritTurntime));
$turntime = TimeUtil::format($turntime, true);
} else { } else {
$turntime = getRandTurn($rng, $admin['turnterm'], Util::toInt($admin['turntime'])); $turntime = getRandTurn($rng, $admin['turnterm'], new \DateTimeImmutable($admin['turntime']));
} }
$now = TimeUtil::now(true);
if ($now >= $turntime) { if ($now >= $turntime) {
$turntime = addTurn($turntime, $admin['turnterm']); $turntime = addTurn($turntime, $admin['turnterm']);
} }
@@ -434,13 +435,6 @@ class Join extends \sammo\BaseAPI
'specage2' => $specage2, 'specage2' => $specage2,
'special2' => $special2, 'special2' => $special2,
'penalty' => Json::encode($penalty), 'penalty' => Json::encode($penalty),
'aux' => Json::encode([
'prestart_delete_after' => addTurn(
$now,
$admin['turnterm'],
GameConst::$minTurnDieOnPrestart
),
]),
]); ]);
$generalID = $db->insertId(); $generalID = $db->insertId();
$db->insert('general_access_log', [ $db->insert('general_access_log', [
+1 -5
View File
@@ -8,8 +8,6 @@ use DateTimeInterface;
use sammo\Enums\APIRecoveryType; use sammo\Enums\APIRecoveryType;
use sammo\TurnExecutionHelper; use sammo\TurnExecutionHelper;
use sammo\UniqueConst; use sammo\UniqueConst;
use sammo\GameClock;
use sammo\KVStorage;
class ExecuteEngine extends \sammo\BaseAPI class ExecuteEngine extends \sammo\BaseAPI
{ {
@@ -37,13 +35,11 @@ class ExecuteEngine extends \sammo\BaseAPI
$updated = false; $updated = false;
$locked = false; $locked = false;
$lastExecuted = TurnExecutionHelper::executeAllCommand($updated, $locked); $lastExecuted = TurnExecutionHelper::executeAllCommand($updated, $locked);
$clock = GameClock::fromStorage(KVStorage::getStorage(DB::db(), 'game_env'));
return [ return [
'result' => true, 'result' => true,
'updated' => $updated, 'updated' => $updated,
'locked' => $locked, 'locked' => $locked,
'lastExecutedTick' => $lastExecuted, 'lastExecuted' => $lastExecuted,
'lastExecuted' => $clock->formatTick($lastExecuted, true),
]; ];
} }
} }
+2 -4
View File
@@ -3,7 +3,6 @@
namespace sammo\API\Global; namespace sammo\API\Global;
use sammo\DB; use sammo\DB;
use sammo\GameClock;
use sammo\Enums\APIRecoveryType; use sammo\Enums\APIRecoveryType;
use sammo\Json; use sammo\Json;
use sammo\KVStorage; use sammo\KVStorage;
@@ -55,7 +54,7 @@ class GeneralList extends \sammo\BaseAPI
$availableNextCall = $session->availableNextCallGetGeneralList ?? '2000-01-01 00:00:00'; $availableNextCall = $session->availableNextCallGetGeneralList ?? '2000-01-01 00:00:00';
$now = new \DateTimeImmutable(); $now = new \DateTimeImmutable();
if ($now <= new \DateTimeImmutable($availableNextCall) && $session->userGrade < 6) { if ($now <= new \DateTimeImmutable($availableNextCall) && $session->userGrade < 5) {
return "장수 리스트는 10초에 한번 갱신 가능합니다.\n다음 시간 : " . $availableNextCall; return "장수 리스트는 10초에 한번 갱신 가능합니다.\n다음 시간 : " . $availableNextCall;
} }
@@ -146,8 +145,7 @@ class GeneralList extends \sammo\BaseAPI
if (static::$withToken) { if (static::$withToken) {
$gameStor = KVStorage::getStorage($db, 'game_env'); $now = (new \DateTimeImmutable())->format('Y-m-d H:i:s');
$now = GameClock::fromStorage($gameStor)->nowTick();
$tokens = []; $tokens = [];
foreach ($db->query('SELECT * FROM select_npc_token WHERE `valid_until`>=%s', $now) as $token) { foreach ($db->query('SELECT * FROM select_npc_token WHERE `valid_until`>=%s', $now) as $token) {
$validUntil = $token['valid_until']; $validUntil = $token['valid_until'];
@@ -10,6 +10,7 @@ use sammo\Enums\RankColumn;
use sammo\GameConst; use sammo\GameConst;
use sammo\General; use sammo\General;
use sammo\KVStorage; use sammo\KVStorage;
use sammo\TimeUtil;
use sammo\UserLogger; use sammo\UserLogger;
class BuyRandomUnique extends \sammo\BaseAPI class BuyRandomUnique extends \sammo\BaseAPI
@@ -55,7 +56,7 @@ class BuyRandomUnique extends \sammo\BaseAPI
$userLogger->push("{$reqAmount} 포인트로 랜덤 유니크 구입", "inheritPoint"); $userLogger->push("{$reqAmount} 포인트로 랜덤 유니크 구입", "inheritPoint");
$userLogger->flush(); $userLogger->flush();
$general->setAuxVar('inheritRandomUnique', true); $general->setAuxVar('inheritRandomUnique', TimeUtil::now());
$inheritStor->setValue('previous', [$previousPoint - $reqAmount, null]); $inheritStor->setValue('previous', [$previousPoint - $reqAmount, null]);
$general->increaseRankVar(RankColumn::inherit_point_spent_dynamic, $reqAmount); $general->increaseRankVar(RankColumn::inherit_point_spent_dynamic, $reqAmount);
$general->applyDB($db); $general->applyDB($db);
-154
View File
@@ -1,154 +0,0 @@
<?php
namespace sammo\API\InheritAction;
use sammo\Session;
use DateTimeInterface;
use sammo\DB;
use sammo\Enums\APIRecoveryType;
use sammo\Enums\MessageType;
use sammo\Enums\RankColumn;
use sammo\GameConst;
use sammo\General;
use sammo\KVStorage;
use sammo\Message;
use sammo\MessageTarget;
use sammo\RootDB;
use sammo\TimeUtil;
use sammo\UserLogger;
use sammo\Validator;
use function sammo\GetImageURL;
use function sammo\getNationStaticInfo;
/**
*
* 유산 포인트 1000 포인트를 사용하면 지정한 상대의 본래 유저명을 확인 가능.
* 개인 메시지로 전달되며, 이 기능이 사용되었음을 상대에게도 알림.
*/
class CheckOwner extends \sammo\BaseAPI
{
public function validateArgs(): ?string
{
$v = new Validator($this->args);
$v->rule('required', [
'destGeneralID',
])
->rule('int', 'destGeneralID')
->rule('min', 'destGeneralID', 1);
if (!$v->validate()) {
return $v->errorStr();
}
return null;
}
public function getRequiredSessionMode(): int
{
return static::REQ_GAME_LOGIN;
}
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag): null|string|array|APIRecoveryType
{
$userID = $session->userID;
$generalID = $session->generalID;
$destGeneralID = $this->args['destGeneralID'];
if ($generalID == $destGeneralID) {
return '자신의 정보는 확인할 수 없습니다.';
}
$general = General::createObjFromDB($generalID);
if ($userID != $general->getVar('owner')) {
return '로그인 상태가 이상합니다. 다시 로그인해 주세요.';
}
$db = DB::db();
$destRawGeneral = $db->queryFirstRow('SELECT no,name,nation,owner,owner_name,imgsvr,picture FROM general WHERE no = %i', $destGeneralID);
if (!$destRawGeneral) {
return '대상 장수가 존재하지 않습니다.';
}
if (!$destRawGeneral['owner']) {
return '대상 장수는 NPC입니다.';
}
$gameStor = KVStorage::getStorage($db, 'game_env');
if ($gameStor->isunited) {
return '이미 천하가 통일되었습니다.';
}
$reqPoint = GameConst::$inheritCheckOwnerPoint;
$inheritStor = KVStorage::getStorage($db, "inheritance_{$userID}");
$previousPoint = ($inheritStor->getValue('previous') ?? [0, 0])[0];
if ($previousPoint < $reqPoint) {
return '충분한 유산 포인트를 가지고 있지 않습니다.';
}
$userLogger = new UserLogger($userID);
$userLogger->push("{$reqPoint} 포인트로 장수 소유자 확인", "inheritPoint");
$userLogger->flush();
$destGeneralName = $destRawGeneral['name'];
$destGeneralOwnerName = $destRawGeneral['owner_name'];
if (!$destGeneralOwnerName) {
$rootDB = RootDB::db();
$destGeneralOwnerName = $rootDB->queryFirstField('SELECT name FROM member WHERE no = %i', $destRawGeneral['owner']) ?? '알수없음';
}
$src = new MessageTarget(0, '', 0, 'System', '#000000');
if (true) {
$staticNation = $general->getStaticNation();
$dest = new MessageTarget(
$generalID,
$general->getName(),
$general->getNationID(),
$staticNation['name'],
$staticNation['color'],
GetImageURL($general->getVar('imgsvr'), $general->getVar('picture'))
);
$msg = new Message(
MessageType::private,
$src,
$dest,
"{$destGeneralName}의 소유자는 {$destGeneralOwnerName} 입니다.",
Message::gameNow(),
new \DateTime('9999-12-31'),
[]
);
$msg->send(true);
}
$inheritStor->setValue('previous', [$previousPoint - $reqPoint, null]);
$general->increaseRankVar(RankColumn::inherit_point_spent_dynamic, $reqPoint);
$general->applyDB($db);
if(true){
$destStaticNation = getNationStaticInfo($destRawGeneral['nation']);
$dest = new MessageTarget(
$destGeneralID,
$destGeneralName,
$destRawGeneral['nation'],
$destStaticNation['name'],
$destStaticNation['color'],
GetImageURL($destRawGeneral['imgsvr'], $destRawGeneral['picture'])
);
$msg = new Message(
MessageType::private,
$src,
$dest,
"소유자명이 누군가에 의해 확인되었습니다.",
Message::gameNow(),
new \DateTime('9999-12-31'),
[]
);
$msg->send(true);
}
return null;
}
}
-188
View File
@@ -1,188 +0,0 @@
<?php
namespace sammo\API\InheritAction;
use sammo\Session;
use DateTimeInterface;
use sammo\CentennialAllStarGrowthService;
use sammo\DB;
use sammo\Enums\APIRecoveryType;
use sammo\Enums\RankColumn;
use sammo\GameConst;
use sammo\General;
use sammo\KVStorage;
use sammo\LiteHashDRBG;
use sammo\RandUtil;
use sammo\UniqueConst;
use sammo\UserLogger;
use sammo\Util;
use sammo\Validator;
class ResetStat extends \sammo\BaseAPI
{
public function validateArgs(): ?string
{
$v = new Validator($this->args);
$v->rule('required', [
'leadership',
'strength',
'intel',
])
->rule('int', [
'leadership',
'strength',
'intel',
])
->rule('min', [
'leadership',
'strength',
'intel'
], GameConst::$defaultStatMin)
->rule('max', [
'leadership',
'strength',
'intel'
], GameConst::$defaultStatMax)
->rule('integerArray', 'inheritBonusStat');
if (!$v->validate()) {
return $v->errorStr();
}
return null;
}
public function getRequiredSessionMode(): int
{
//General.aux 쓰므로 lock;
return static::REQ_GAME_LOGIN;
}
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag): null | string | array | APIRecoveryType
{
$userID = $session->userID;
$generalID = $session->generalID;
$leadership = $this->args['leadership'];
$strength = $this->args['strength'];
$intel = $this->args['intel'];
$inheritBonusStat = $this->args['inheritBonusStat'] ?? null;
if ($leadership + $strength + $intel != GameConst::$defaultStatTotal) {
return "능력치 총합이 " . GameConst::$defaultStatTotal . "이 아닙니다. 다시 입력해주세요!";
}
if ($inheritBonusStat) {
if (count($inheritBonusStat) != 3) {
return "보너스 능력치가 잘못 지정되었습니다. 다시 입력해주세요!";
}
foreach ($inheritBonusStat as $stat) {
if ($stat < 0) {
return "보너스 능력치가 음수입니다. 다시 입력해주세요!";
}
}
$sum = array_sum($inheritBonusStat);
if ($sum == 0) {
$inheritBonusStat = null;
} else if ($sum < 3 || $sum > 5) {
return "보너스 능력치 합이 잘못 지정되었습니다. 다시 입력해주세요!";
}
}
$general = General::createObjFromDB($generalID);
if ($userID != $general->getVar('owner')) {
return '로그인 상태가 이상합니다. 다시 로그인해 주세요.';
}
$userLogger = new UserLogger($userID);
if($general->getNPCType() != 0){
return 'NPC는 능력치 초기화를 할 수 없습니다.';
}
if (!CentennialAllStarGrowthService::isStatResetAllowed()) {
return '100기 올스타 장수는 능력치 초기화를 사용할 수 없습니다.';
}
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$gameStor->cacheValues([
'isunited',
'season',
]);
if ($gameStor->isunited) {
return '이미 천하가 통일되었습니다.';
}
$userStor = KVStorage::getStorage($db, "user_{$userID}");
$lastUserStatReset = $userStor->getValue('last_stat_reset') ?? [];
$gameSeason = $gameStor->getValue('season');
if (array_search($gameSeason, $lastUserStatReset) !== false) {
return '이번 시즌에 이미 능력치를 초기화하셨습니다.';
}
$inheritStor = KVStorage::getStorage($db, "inheritance_{$userID}");
$previousPoint = ($inheritStor->getValue('previous') ?? [0, 0])[0];
$reqAmount = 0;
if ($inheritBonusStat !== null) {
$reqAmount += GameConst::$inheritBornStatPoint;
}
if ($previousPoint < $reqAmount) {
return '충분한 유산 포인트를 가지고 있지 않습니다.';
}
$userLogger->push("통솔 {$leadership}, 무력 {$strength}, 지력 {$intel} 스탯 재설정", "inheritPoint");
if ($inheritBonusStat) {
$pleadership = $inheritBonusStat[0] ?? 0;
$pstrength = $inheritBonusStat[1] ?? 0;
$pintel = $inheritBonusStat[2] ?? 0;
$userLogger->push("{$reqAmount}로 통솔 {$pleadership}, 무력 {$pstrength}, 지력 {$pintel} 보너스 능력치 적용", "inheritPoint");
} else {
$rng = new RandUtil(new LiteHashDRBG(Util::simpleSerialize(
UniqueConst::$hiddenSeed,
'ResetStat',
$userID,
)));
$pleadership = 0;
$pstrength = 0;
$pintel = 0;
foreach (Util::range($rng->nextRangeInt(3, 5)) as $statIdx) {
switch ($rng->choiceUsingWeight([$leadership, $strength, $intel])) {
case 0:
$pleadership++;
break;
case 1:
$pstrength++;
break;
case 2:
$pintel++;
break;
}
}
$userLogger->push("통솔 {$pleadership}, 무력 {$pstrength}, 지력 {$pintel} 보너스 능력치 적용", "inheritPoint");
}
$leadership += $pleadership;
$strength += $pstrength;
$intel += $pintel;
$lastUserStatReset[] = $gameSeason;
$general->setVar('leadership', $leadership);
$general->setVar('strength', $strength);
$general->setVar('intel', $intel);
$userLogger->flush();
$inheritStor->setValue('previous', [$previousPoint - $reqAmount, null]);
$userStor->setValue('last_stat_reset', $lastUserStatReset);
$general->increaseRankVar(RankColumn::inherit_point_spent_dynamic, $reqAmount);
$general->applyDB($db);
return null;
}
}
@@ -64,11 +64,13 @@ class ResetTurnTime extends \sammo\BaseAPI
$gameStor = KVStorage::getStorage($db, 'game_env'); $gameStor = KVStorage::getStorage($db, 'game_env');
$turnTerm = $gameStor->getValue('turnterm'); $turnTerm = $gameStor->getValue('turnterm');
$currTurnTime = new DateTimeImmutable($general->getTurnTime());
$rng = new RandUtil(new LiteHashDRBG(Util::simpleSerialize( $rng = new RandUtil(new LiteHashDRBG(Util::simpleSerialize(
UniqueConst::$hiddenSeed, UniqueConst::$hiddenSeed,
'ResetTurnTime', 'ResetTurnTime',
$userID, $userID,
$general->getAuxVar('nextTurnTimeBase') ?? $general->getTurnTick() $general->getAuxVar('nextTurnTimeBase') ?? $general->getTurnTime()
))); )));
$afterTurn = $rng->nextFloat1() * $turnTerm * 60; $afterTurn = $rng->nextFloat1() * $turnTerm * 60;
+5 -13
View File
@@ -7,7 +7,6 @@ use DateTimeInterface;
use sammo\DB; use sammo\DB;
use sammo\Enums\APIRecoveryType; use sammo\Enums\APIRecoveryType;
use sammo\Enums\MessageType; use sammo\Enums\MessageType;
use sammo\Enums\PenaltyKey;
use sammo\Json; use sammo\Json;
use sammo\Message; use sammo\Message;
use sammo\MessageTarget; use sammo\MessageTarget;
@@ -44,7 +43,7 @@ class SendMessage extends \sammo\BaseAPI
private function genPublicMessage(MessageTarget $src, string $text): Message private function genPublicMessage(MessageTarget $src, string $text): Message
{ {
$now = Message::gameNow(); $now = new \DateTime();
$unlimited = new \DateTime('9999-12-31'); $unlimited = new \DateTime('9999-12-31');
$msg = new Message( $msg = new Message(
@@ -62,7 +61,7 @@ class SendMessage extends \sammo\BaseAPI
private function genNationalMessage(MessageTarget $src, string $text): Message private function genNationalMessage(MessageTarget $src, string $text): Message
{ {
$now = Message::gameNow(); $now = new \DateTime();
$unlimited = new \DateTime('9999-12-31'); $unlimited = new \DateTime('9999-12-31');
$dest = new MessageTarget(0, '', $src->nationID, $src->nationName, $src->color); $dest = new MessageTarget(0, '', $src->nationID, $src->nationName, $src->color);
@@ -82,7 +81,7 @@ class SendMessage extends \sammo\BaseAPI
private function genDiplomacyMessage(MessageTarget $src, int $destNationID, string $text): Message|string private function genDiplomacyMessage(MessageTarget $src, int $destNationID, string $text): Message|string
{ {
$now = Message::gameNow(); $now = new \DateTime();
$unlimited = new \DateTime('9999-12-31'); $unlimited = new \DateTime('9999-12-31');
$destNation = getNationStaticInfo($destNationID); $destNation = getNationStaticInfo($destNationID);
@@ -107,7 +106,7 @@ class SendMessage extends \sammo\BaseAPI
private function genPrivateMessage(MessageTarget $src, int $destGeneralID, int $permission, string $text): Message|string private function genPrivateMessage(MessageTarget $src, int $destGeneralID, int $permission, string $text): Message|string
{ {
$now = Message::gameNow(); $now = new \DateTime();
$unlimited = new \DateTime('9999-12-31'); $unlimited = new \DateTime('9999-12-31');
$db = DB::db(); $db = DB::db();
@@ -192,9 +191,6 @@ class SendMessage extends \sammo\BaseAPI
// 전체 메세지 // 전체 메세지
if ($mailbox === Message::MAILBOX_PUBLIC) { if ($mailbox === Message::MAILBOX_PUBLIC) {
if($penalty[PenaltyKey::NoSendPublicMsg->value] ?? 0) {
return '공개 메세지를 보낼 수 없습니다.';
}
$msgID = $this->genPublicMessage($src, $text)->send(); $msgID = $this->genPublicMessage($src, $text)->send();
return [ return [
'msgType' => 'public', 'msgType' => 'public',
@@ -235,11 +231,7 @@ class SendMessage extends \sammo\BaseAPI
$lastMsg = new \DateTime($session->lastMsg ?? '0000-00-00'); $lastMsg = new \DateTime($session->lastMsg ?? '0000-00-00');
$msg_interval = $now->getTimestamp() - $lastMsg->getTimestamp(); $msg_interval = $now->getTimestamp() - $lastMsg->getTimestamp();
if($penalty[PenaltyKey::NoSendPrivateMsg->value] ?? 0) { $msg_min_interval = $penalty['sendPrivateMsgDelay'] ?? 2;
return '개인 메세지를 보낼 수 없습니다.';
}
$msg_min_interval = $penalty[PenaltyKey::SendPrivateMsgDelay->value] ?? 2;
if ($msg_interval < $msg_min_interval) { if ($msg_interval < $msg_min_interval) {
return "개인메세지는 {$msg_min_interval}초당 1건만 보낼 수 있습니다!"; return "개인메세지는 {$msg_min_interval}초당 1건만 보낼 수 있습니다!";
} }
+1 -1
View File
@@ -50,7 +50,7 @@ class UploadImage extends \sammo\BaseAPI
} }
$extension = ltrim($contentType, 'image/'); $extension = ltrim($contentType, 'image/');
$validExtensions = ['png', 'jpeg', 'jpg', 'gif', 'webp', 'avif']; $validExtensions = ['png', 'jpeg', 'jpg', 'gif', 'webp'];
if (!in_array(strtolower($extension), $validExtensions)) { if (!in_array(strtolower($extension), $validExtensions)) {
return '지원하지 않는 이미지 파일입니다: ' . $contentType; return '지원하지 않는 이미지 파일입니다: ' . $contentType;
} }
+2 -6
View File
@@ -8,7 +8,6 @@ use sammo\Enums\APIRecoveryType;
use sammo\Enums\GeneralLiteQueryMode; use sammo\Enums\GeneralLiteQueryMode;
use sammo\Enums\GeneralQueryMode; use sammo\Enums\GeneralQueryMode;
use sammo\General; use sammo\General;
use sammo\GameClock;
use sammo\GeneralLite; use sammo\GeneralLite;
use sammo\Session; use sammo\Session;
use sammo\Util; use sammo\Util;
@@ -265,11 +264,8 @@ class GeneralList extends \sammo\BaseAPI
'honorText' => fn ($rawGeneral) => getHonor($rawGeneral['experience']), 'honorText' => fn ($rawGeneral) => getHonor($rawGeneral['experience']),
'dedLevelText' => fn ($rawGeneral) => getDedLevelText($rawGeneral['dedlevel']), 'dedLevelText' => fn ($rawGeneral) => getDedLevelText($rawGeneral['dedlevel']),
//'0000-00-00 11:23'; //'0000-00-00 11:23';
'turntime' => fn ($rawGeneral) => GameClock::fromStorage($gameStor) 'turntime' => fn ($rawGeneral) => substr($rawGeneral['turntime'], 0, 19),
->formatTick(Util::toInt($rawGeneral['turntime'])), 'recent_war' => fn ($rawGeneral) => substr($rawGeneral['recent_war'], 0, 19),
'recent_war' => fn ($rawGeneral) => $rawGeneral['recent_war'] === null
? null
: GameClock::fromStorage($gameStor)->formatTick(Util::toInt($rawGeneral['recent_war'])),
'bill' => fn ($rawGeneral) => getBillByLevel($rawGeneral['dedlevel']), 'bill' => fn ($rawGeneral) => getBillByLevel($rawGeneral['dedlevel']),
'reservedCommand' => fn ($rawGeneral) => $reservedCommand[$rawGeneral['no']] ?? null, 'reservedCommand' => fn ($rawGeneral) => $reservedCommand[$rawGeneral['no']] ?? null,
'autorun_limit' => fn ($rawGeneral) => ($rawGeneral['aux'] ?? [])['autorun_limit'] ?? 0, 'autorun_limit' => fn ($rawGeneral) => ($rawGeneral['aux'] ?? [])['autorun_limit'] ?? 0,
+2 -3
View File
@@ -6,8 +6,8 @@ use sammo\Session;
use DateTimeInterface; use DateTimeInterface;
use sammo\DB; use sammo\DB;
use sammo\Enums\APIRecoveryType; use sammo\Enums\APIRecoveryType;
use sammo\GameClock;
use sammo\KVStorage; use sammo\KVStorage;
use sammo\TimeUtil;
use sammo\Validator; use sammo\Validator;
use sammo\WebUtil; use sammo\WebUtil;
@@ -51,9 +51,8 @@ class SetNotice extends \sammo\BaseAPI
$nationID = $me['nation']; $nationID = $me['nation'];
$nationStor = KVStorage::getStorage($db, $nationID, 'nation_env'); $nationStor = KVStorage::getStorage($db, $nationID, 'nation_env');
$gameNow = GameClock::fromStorage(KVStorage::getStorage($db, 'game_env'))->formatNow();
$nationStor->nationNotice = [ $nationStor->nationNotice = [
'date'=>$gameNow, 'date'=>TimeUtil::now(),
'msg'=>WebUtil::htmlPurify($msg), 'msg'=>WebUtil::htmlPurify($msg),
'author'=>$me['name'], 'author'=>$me['name'],
'authorID'=>$me['no'], 'authorID'=>$me['no'],
@@ -8,10 +8,10 @@ use sammo\DB;
use sammo\Enums\APIRecoveryType; use sammo\Enums\APIRecoveryType;
use sammo\Enums\GeneralQueryMode; use sammo\Enums\GeneralQueryMode;
use sammo\GameConst; use sammo\GameConst;
use sammo\GameClock;
use sammo\General; use sammo\General;
use sammo\Json; use sammo\Json;
use sammo\KVStorage; use sammo\KVStorage;
use sammo\TimeUtil;
use sammo\Util; use sammo\Util;
use function sammo\checkLimit; use function sammo\checkLimit;
@@ -39,7 +39,6 @@ class GetReservedCommand extends \sammo\BaseAPI
increaseRefresh("사령부", 1); increaseRefresh("사령부", 1);
$gameStor = KVStorage::getStorage($db, 'game_env'); $gameStor = KVStorage::getStorage($db, 'game_env');
$clock = GameClock::fromStorage($gameStor);
$userID = $session->userID; $userID = $session->userID;
$me = $db->queryFirstRow( $me = $db->queryFirstRow(
@@ -52,8 +51,7 @@ class GetReservedCommand extends \sammo\BaseAPI
$nationID = $me['nation']; $nationID = $me['nation'];
$limitState = checkLimit($me['refresh_score']); $limitState = checkLimit($me['refresh_score']);
if ($limitState >= 2) { if ($limitState >= 2) {
$limitTime = GameClock::fromStorage($gameStor)->formatTick(Util::toInt($me['turntime']), true); return "접속 제한중입니다. 1턴 이내에 너무 많은 갱신을 하셨습니다. (다음 갱신 가능 시각 : {$me['turntime']})";
return "접속 제한중입니다. 1턴 이내에 너무 많은 갱신을 하셨습니다. (다음 갱신 가능 시각 : {$limitTime})";
} }
$permission = checkSecretPermission($me); $permission = checkSecretPermission($me);
@@ -158,8 +156,7 @@ class GetReservedCommand extends \sammo\BaseAPI
'year' => $year, 'year' => $year,
'month' => $month, 'month' => $month,
'turnTerm' => $turnTerm, 'turnTerm' => $turnTerm,
'date' => $clock->formatTick($clock->nowTick(), true), 'date' => TimeUtil::now(true),
'clockMode' => $clock->getMode(),
'chiefList' => $nationChiefList, 'chiefList' => $nationChiefList,
'troopList' => $troopList, 'troopList' => $troopList,
'isChief' => ($me['officer_level'] > 4), 'isChief' => ($me['officer_level'] > 4),
+5 -20
View File
@@ -6,9 +6,6 @@ use sammo\Session;
use DateTimeInterface; use DateTimeInterface;
use sammo\DB; use sammo\DB;
use sammo\Enums\APIRecoveryType; use sammo\Enums\APIRecoveryType;
use sammo\Enums\GeneralLiteQueryMode;
use sammo\GeneralLite;
use sammo\StaticEventHandler;
class ExitTroop extends \sammo\BaseAPI class ExitTroop extends \sammo\BaseAPI
{ {
@@ -27,35 +24,23 @@ class ExitTroop extends \sammo\BaseAPI
$generalID = $session->generalID; $generalID = $session->generalID;
$db = DB::db(); $db = DB::db();
$me = GeneralLite::createObjFromDB($generalID, ['troop'], GeneralLiteQueryMode::Lite); $troopID = $db->queryFirstField('SELECT troop FROM general WHERE no = %i', $generalID);
if (!$me) {
return '장수 정보를 불러올 수 없습니다.';
}
$troopID = $me->getVar('troop');
if($troopID == 0){ if($troopID == 0){
return '부대에 소속되어 있지 않습니다.'; return '부대에 소속되어 있지 않습니다.';
} }
if($troopID != $generalID){ if($generalID != $troopID){
StaticEventHandler::handleEvent($me, null, $this::class, [ $db->update('general', [
"isTroopLeader" => false, 'troop' => 0,
], $this->args); ], '`no` = %i', $generalID);
$me->setVar('troop', 0);
$me->applyDB($db);
return null; return null;
} }
//부대장이다. //부대장이다.
StaticEventHandler::handleEvent($me, null, $this::class, [
"isTroopLeader" => true,
], $this->args);
$db->update('general', [ $db->update('general', [
'troop' => 0, 'troop' => 0,
], '`troop` = %i', $troopID); ], '`troop` = %i', $troopID);
$db->delete('troop', 'troop_leader = %i', $troopID); $db->delete('troop', 'troop_leader = %i', $troopID);
$me->setVar('troop', 0);
$me->applyDB($db);
return null; return null;
} }
+8 -16
View File
@@ -6,9 +6,6 @@ use sammo\Session;
use DateTimeInterface; use DateTimeInterface;
use sammo\DB; use sammo\DB;
use sammo\Enums\APIRecoveryType; use sammo\Enums\APIRecoveryType;
use sammo\Enums\GeneralLiteQueryMode;
use sammo\GeneralLite;
use sammo\StaticEventHandler;
use sammo\StringUtil; use sammo\StringUtil;
use sammo\Validator; use sammo\Validator;
@@ -35,21 +32,15 @@ class JoinTroop extends \sammo\BaseAPI
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag): null | string | array | APIRecoveryType public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag): null | string | array | APIRecoveryType
{ {
$generalID = $session->generalID; $userID = $session->userID;
$troopID = $this->args['troopID']; $troopID = $this->args['troopID'];
$db = DB::db(); $db = DB::db();
$me = $db->queryFirstRow('SELECT `no`,nation,`troop`,`officer_level`,permission,penalty FROM general WHERE `owner`=%i', $userID);
$me = GeneralLite::createObjFromDB($generalID, ['troop'], GeneralLiteQueryMode::Lite); if ($me['troop'] != 0) {
if(!$me){
return '장수 정보를 불러올 수 없습니다.';
}
if($me->getVar('troop') != 0){
return '이미 부대에 소속되어 있습니다.'; return '이미 부대에 소속되어 있습니다.';
} }
$nationID = $me['nation'];
$nationID = $me->getNationID();
if ($nationID == 0) { if ($nationID == 0) {
return '국가에 소속되어 있지 않습니다.'; return '국가에 소속되어 있지 않습니다.';
} }
@@ -58,10 +49,11 @@ class JoinTroop extends \sammo\BaseAPI
if (!$troopExists) { if (!$troopExists) {
return '부대가 올바르지 않습니다.'; return '부대가 올바르지 않습니다.';
} }
$generalID = $me['no'];
$me->setVar('troop', $troopID); $db->update('general', [
StaticEventHandler::handleEvent($me, null, $this::class, [], $this->args); 'troop' => $troopID,
$me->applyDB($db); ], '`no` = %i AND `troop` = %i', $generalID, 0);
return null; return null;
} }
+4 -9
View File
@@ -6,9 +6,6 @@ use sammo\Session;
use DateTimeInterface; use DateTimeInterface;
use sammo\DB; use sammo\DB;
use sammo\Enums\APIRecoveryType; use sammo\Enums\APIRecoveryType;
use sammo\Enums\GeneralLiteQueryMode;
use sammo\GeneralLite;
use sammo\StaticEventHandler;
use sammo\Validator; use sammo\Validator;
class KickFromTroop extends \sammo\BaseAPI class KickFromTroop extends \sammo\BaseAPI
@@ -40,8 +37,7 @@ class KickFromTroop extends \sammo\BaseAPI
$generalID = $this->args['generalID']; $generalID = $this->args['generalID'];
$db = DB::db(); $db = DB::db();
$destGeneral = GeneralLite::createObjFromDB($generalID, ['troop'], GeneralLiteQueryMode::Lite); $troopID = $db->queryFirstField('SELECT troop FROM general WHERE no = %i', $generalID);
$troopID = $destGeneral->getVar('troop');
if($troopID == 0){ if($troopID == 0){
return '부대에 소속되어 있지 않습니다.'; return '부대에 소속되어 있지 않습니다.';
} }
@@ -54,10 +50,9 @@ class KickFromTroop extends \sammo\BaseAPI
return '부대장을 추방할 수 없습니다.'; return '부대장을 추방할 수 없습니다.';
} }
StaticEventHandler::handleEvent($destGeneral, null, $this::class, [], $this->args); $db->update('general', [
$destGeneral->setVar('troop', 0); 'troop' => 0,
$destGeneral->applyDB($db); ], '`no` = %i AND `troop` = %i', $generalID, $troopID);
return null; return null;
} }
} }
+9 -11
View File
@@ -6,9 +6,6 @@ use sammo\Session;
use DateTimeInterface; use DateTimeInterface;
use sammo\DB; use sammo\DB;
use sammo\Enums\APIRecoveryType; use sammo\Enums\APIRecoveryType;
use sammo\Enums\GeneralLiteQueryMode;
use sammo\GeneralLite;
use sammo\StaticEventHandler;
use sammo\StringUtil; use sammo\StringUtil;
use sammo\Validator; use sammo\Validator;
@@ -35,23 +32,24 @@ class NewTroop extends \sammo\BaseAPI
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag): null | string | array | APIRecoveryType public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag): null | string | array | APIRecoveryType
{ {
$generalID = $session->generalID; $userID = $session->userID;
$troopName = StringUtil::neutralize($this->args['troopName']); $troopName = StringUtil::neutralize($this->args['troopName']);
if(!$troopName){ if(!$troopName){
return '부대 이름이 없습니다.'; return '부대 이름이 없습니다.';
} }
$db = DB::db(); $db = DB::db();
$me = GeneralLite::createObjFromDB($generalID, ['troop'], GeneralLiteQueryMode::Lite); $me = $db->queryFirstRow('SELECT `no`,nation,`troop`,`officer_level`,permission,penalty FROM general WHERE `owner`=%i', $userID);
$troopID = $me->getVar('troop'); if($me['troop'] != 0){
if($troopID != 0){
return '이미 부대에 소속되어 있습니다.'; return '이미 부대에 소속되어 있습니다.';
} }
$nationID = $me->getNationID(); $nationID = $me['nation'];
if($nationID == 0){ if($nationID == 0){
return '국가에 소속되어 있지 않습니다.'; return '국가에 소속되어 있지 않습니다.';
} }
$generalID = $me['no'];
$db->insert('troop', [ $db->insert('troop', [
'name'=>$troopName, 'name'=>$troopName,
'troop_leader'=>$generalID, 'troop_leader'=>$generalID,
@@ -62,9 +60,9 @@ class NewTroop extends \sammo\BaseAPI
return '부대가 생성되지 않았습니다. 버그일 수 있습니다.'; return '부대가 생성되지 않았습니다. 버그일 수 있습니다.';
} }
$me->setVar('troop', $generalID); $db->update('general', [
StaticEventHandler::handleEvent($me, null, $this::class, [], $this->args); 'troop'=>$generalID
$me->applyDB($db); ], '`no` = %i', $generalID);
return null; return null;
} }
+5 -8
View File
@@ -6,9 +6,6 @@ use sammo\Session;
use DateTimeInterface; use DateTimeInterface;
use sammo\DB; use sammo\DB;
use sammo\Enums\APIRecoveryType; use sammo\Enums\APIRecoveryType;
use sammo\Enums\GeneralLiteQueryMode;
use sammo\GeneralLite;
use sammo\StaticEventHandler;
use sammo\StringUtil; use sammo\StringUtil;
use sammo\Validator; use sammo\Validator;
@@ -39,12 +36,13 @@ class SetTroopName extends \sammo\BaseAPI
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag): null | string | array | APIRecoveryType public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag): null | string | array | APIRecoveryType
{ {
$generalID = $session->generalID; $userID = $session->userID;
$db = DB::db(); $db = DB::db();
$me = GeneralLite::createObjFromDB($generalID, ['troop', 'permission', 'penalty'], GeneralLiteQueryMode::Lite); $me = $db->queryFirstRow('SELECT `no`,nation,`officer_level`,permission,penalty FROM general WHERE `owner`=%i', $userID);
$permission = checkSecretPermission($me->getRaw(), false); $permission = checkSecretPermission($me, false);
$troopID = $this->args['troopID']; $troopID = $this->args['troopID'];
$generalID = $me['no'];
if($generalID != $troopID && $permission < 4){ if($generalID != $troopID && $permission < 4){
return "권한이 부족합니다."; return "권한이 부족합니다.";
} }
@@ -54,7 +52,7 @@ class SetTroopName extends \sammo\BaseAPI
return '부대 이름이 없습니다.'; return '부대 이름이 없습니다.';
} }
$nationID = $me->getNationID(); $nationID = $me['nation'];
$db->update('troop', [ $db->update('troop', [
'name'=>$troopName 'name'=>$troopName
], 'troop_leader=%i AND `nation`=%i',$troopID, $nationID); ], 'troop_leader=%i AND `nation`=%i',$troopID, $nationID);
@@ -62,7 +60,6 @@ class SetTroopName extends \sammo\BaseAPI
if($db->affectedRows() == 0){ if($db->affectedRows() == 0){
return '부대가 없습니다.'; return '부대가 없습니다.';
} }
StaticEventHandler::handleEvent($me, null, $this::class, [], $this->args);
return null; return null;
} }
+3 -4
View File
@@ -10,9 +10,8 @@ use sammo\Enums\GeneralLiteQueryMode;
use sammo\Enums\GeneralQueryMode; use sammo\Enums\GeneralQueryMode;
use sammo\General; use sammo\General;
use sammo\GeneralLite; use sammo\GeneralLite;
use sammo\GameClock;
use sammo\KVStorage;
use sammo\Session; use sammo\Session;
use sammo\TimeUtil;
use sammo\Validator; use sammo\Validator;
class AddComment extends \sammo\BaseAPI class AddComment extends \sammo\BaseAPI
@@ -48,8 +47,7 @@ class AddComment extends \sammo\BaseAPI
$generalName = $general->getName(); $generalName = $general->getName();
$nationID = $general->getNationID(); $nationID = $general->getNationID();
$nationName = $general->getStaticNation()['name']; $nationName = $general->getStaticNation()['name'];
$db = DB::db(); $date = TimeUtil::now();
$date = GameClock::fromStorage(KVStorage::getStorage($db, 'game_env'))->formatNow();
$comment = new VoteComment( $comment = new VoteComment(
@@ -63,6 +61,7 @@ class AddComment extends \sammo\BaseAPI
date: $date date: $date
); );
$db = DB::db();
$db->insert('vote_comment', $comment->toArray()); $db->insert('vote_comment', $comment->toArray());
return null; return null;
+1 -6
View File
@@ -8,7 +8,6 @@ use sammo\DB;
use sammo\DTO\VoteComment; use sammo\DTO\VoteComment;
use sammo\DTO\VoteInfo; use sammo\DTO\VoteInfo;
use sammo\Enums\APIRecoveryType; use sammo\Enums\APIRecoveryType;
use sammo\GameClock;
use sammo\Json; use sammo\Json;
use sammo\KVStorage; use sammo\KVStorage;
use sammo\Validator; use sammo\Validator;
@@ -36,16 +35,13 @@ class GetVoteDetail extends \sammo\BaseAPI
{ {
$voteID = $this->args['voteID']; $voteID = $this->args['voteID'];
$db = DB::db(); $db = DB::db();
$clock = GameClock::fromStorage(KVStorage::getStorage($db, 'game_env'));
$voteStor = KVStorage::getStorage($db, 'vote'); $voteStor = KVStorage::getStorage($db, 'vote');
$rawVote = $voteStor->getValue("vote_{$voteID}"); $rawVote = $voteStor->getValue("vote_{$voteID}");
if (!$rawVote) { if (!$rawVote) {
return '설문조사가 없습니다.'; return '설문조사가 없습니다.';
} }
$rawVote = VoteInfo::normalizeGameStorage($rawVote, $clock); $voteInfo = VoteInfo::fromArray($rawVote);
$voteInfo = VoteInfo::fromGameStorage($rawVote, $clock);
$isOpen = $rawVote['endTick'] === null || $rawVote['endTick'] >= $clock->nowTick();
$votes = array_map(fn ($arr) => [Json::decode($arr[0]), $arr[1]], $db->queryAllLists( $votes = array_map(fn ($arr) => [Json::decode($arr[0]), $arr[1]], $db->queryAllLists(
@@ -74,7 +70,6 @@ class GetVoteDetail extends \sammo\BaseAPI
'comments' => $comments, 'comments' => $comments,
'myVote' => $myVote, 'myVote' => $myVote,
'userCnt' => $userCnt, 'userCnt' => $userCnt,
'isOpen' => $isOpen,
]; ];
} }
} }
+3 -5
View File
@@ -6,7 +6,6 @@ use DateTimeInterface;
use sammo\DB; use sammo\DB;
use sammo\DTO\VoteInfo; use sammo\DTO\VoteInfo;
use sammo\Enums\APIRecoveryType; use sammo\Enums\APIRecoveryType;
use sammo\GameClock;
use sammo\KVStorage; use sammo\KVStorage;
use sammo\Session; use sammo\Session;
@@ -26,17 +25,16 @@ class GetVoteList extends \sammo\BaseAPI
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag): null | string | array | APIRecoveryType public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag): null | string | array | APIRecoveryType
{ {
$db = DB::db(); $db = DB::db();
$clock = GameClock::fromStorage(KVStorage::getStorage($db, 'game_env'));
$voteStor = KVStorage::getStorage($db, 'vote'); $voteStor = KVStorage::getStorage($db, 'vote');
$votes = []; $votes = [];
foreach($voteStor->getAll() as $voteKey => $rawVote){ foreach($voteStor->getAll() as $voteKey => $rawVote){
if(preg_match('/^vote_(\d+)$/D', $voteKey, $matches) !== 1){ if(!str_starts_with($voteKey, 'vote_')){
continue; continue;
} }
$voteID = (int)$matches[1]; $voteID = (int)substr($voteKey, 5);
$votes[$voteID] = VoteInfo::fromGameStorage($rawVote, $clock); $votes[$voteID] = VoteInfo::fromArray($rawVote);
} }
return [ return [
+14 -23
View File
@@ -7,9 +7,8 @@ use sammo\DB;
use sammo\DTO\VoteInfo; use sammo\DTO\VoteInfo;
use sammo\Enums\APIRecoveryType; use sammo\Enums\APIRecoveryType;
use sammo\KVStorage; use sammo\KVStorage;
use sammo\RootDB;
use sammo\Session; use sammo\Session;
use sammo\GameClock; use sammo\TimeUtil;
use sammo\Util; use sammo\Util;
use sammo\Validator; use sammo\Validator;
@@ -37,7 +36,7 @@ class NewVote extends \sammo\BaseAPI
return null; return null;
} }
function closeOldVote(int $voteID, KVStorage $voteStor, GameClock $clock) function closeOldVote(int $voteID, KVStorage $voteStor)
{ {
$db = DB::db(); $db = DB::db();
$voteStor = KVStorage::getStorage($db, 'vote'); $voteStor = KVStorage::getStorage($db, 'vote');
@@ -45,14 +44,13 @@ class NewVote extends \sammo\BaseAPI
if (!$rawLastVoteInfo) { if (!$rawLastVoteInfo) {
return; return;
} }
$rawLastVoteInfo = VoteInfo::normalizeGameStorage($rawLastVoteInfo, $clock); $lastVoteInfo = VoteInfo::fromArray($rawLastVoteInfo);
if ($rawLastVoteInfo['endTick'] !== null) { if ($lastVoteInfo->endDate) {
return; return;
} }
$rawLastVoteInfo['endTick'] = $clock->nowTick(); $lastVoteInfo->endDate = TimeUtil::now();
$rawLastVoteInfo['endDate'] = $clock->formatTick($rawLastVoteInfo['endTick']); $voteStor->setValue("vote_{$voteID}", $lastVoteInfo->toArray());
$voteStor->setValue("vote_{$voteID}", $rawLastVoteInfo);
} }
function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag): null | string | array | APIRecoveryType function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag): null | string | array | APIRecoveryType
@@ -72,11 +70,7 @@ class NewVote extends \sammo\BaseAPI
$multipleOptions = 0; $multipleOptions = 0;
} }
$db = DB::db(); $now = TimeUtil::now();
$gameStor = KVStorage::getStorage($db, 'game_env');
$clock = GameClock::fromStorage($gameStor);
$nowTick = $clock->nowTick();
$now = $clock->formatTick($nowTick);
/** @var ?string */ /** @var ?string */
$endDate = $this->args['endDate'] ?? null; $endDate = $this->args['endDate'] ?? null;
/** @var string[] */ /** @var string[] */
@@ -88,9 +82,9 @@ class NewVote extends \sammo\BaseAPI
if($endDate !== null){ if($endDate !== null){
try{ try{
$oNow = new \DateTimeImmutable($now);
$oEndDate = new \DateTimeImmutable($endDate); $oEndDate = new \DateTimeImmutable($endDate);
$endTick = $clock->dateTimeToTick($oEndDate); if($oEndDate < $oNow){
if($endTick < $nowTick){
return '종료일이 이미 지났습니다.'; return '종료일이 이미 지났습니다.';
} }
} }
@@ -99,7 +93,9 @@ class NewVote extends \sammo\BaseAPI
} }
} }
$userName = $session->userName; $db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$lastVote = $gameStor->getValue('lastVote') ?? 0; $lastVote = $gameStor->getValue('lastVote') ?? 0;
$voteID = $lastVote + 1; $voteID = $lastVote + 1;
@@ -107,26 +103,21 @@ class NewVote extends \sammo\BaseAPI
$voteStor = KVStorage::getStorage($db, 'vote'); $voteStor = KVStorage::getStorage($db, 'vote');
if (!($this->args['keepOldVote'] ?? false)) { if (!($this->args['keepOldVote'] ?? false)) {
$this->closeOldVote($lastVote, $voteStor, $clock); $this->closeOldVote($lastVote, $voteStor);
} }
$multipleOptions = Util::valueFit($multipleOptions, 0, count($options)); $multipleOptions = Util::valueFit($multipleOptions, 0, count($options));
$voteInfo = new VoteInfo( $voteInfo = new VoteInfo(
id: $voteID, id: $voteID,
title: $title, title: $title,
opener: $userName ?? '[SYSTEM]',
multipleOptions: $multipleOptions, multipleOptions: $multipleOptions,
startDate: $now, startDate: $now,
endDate: $endDate, endDate: $endDate,
options: $options, options: $options,
); );
$voteStor->setValue("vote_{$voteID}", $voteInfo->toArray() + [ $voteStor->setValue("vote_{$voteID}", $voteInfo->toArray());
'startTick' => $nowTick,
'endTick' => $endDate === null ? null : $clock->dateTimeToTick(new \DateTimeImmutable($endDate)),
]);
$gameStor->setValue('lastVote', $voteID); $gameStor->setValue('lastVote', $voteID);
$db->update('general', [ $db->update('general', [
+2 -5
View File
@@ -8,7 +8,6 @@ use sammo\DTO\VoteInfo;
use sammo\Enums\APIRecoveryType; use sammo\Enums\APIRecoveryType;
use sammo\Enums\GeneralQueryMode; use sammo\Enums\GeneralQueryMode;
use sammo\General; use sammo\General;
use sammo\GameClock;
use sammo\Json; use sammo\Json;
use sammo\KVStorage; use sammo\KVStorage;
use sammo\LiteHashDRBG; use sammo\LiteHashDRBG;
@@ -55,17 +54,15 @@ class Vote extends \sammo\BaseAPI
return '선택한 항목이 없습니다.'; return '선택한 항목이 없습니다.';
} }
$db = DB::db(); $db = DB::db();
$clock = GameClock::fromStorage(KVStorage::getStorage($db, 'game_env'));
$voteStor = KVStorage::getStorage($db, 'vote'); $voteStor = KVStorage::getStorage($db, 'vote');
$rawVoteInfo = $voteStor->getValue("vote_{$voteID}"); $rawVoteInfo = $voteStor->getValue("vote_{$voteID}");
if (!$rawVoteInfo) { if (!$rawVoteInfo) {
return '설문조사가 없습니다.'; return '설문조사가 없습니다.';
} }
$rawVoteInfo = VoteInfo::normalizeGameStorage($rawVoteInfo, $clock); $voteInfo = VoteInfo::fromArray($rawVoteInfo);
$voteInfo = VoteInfo::fromGameStorage($rawVoteInfo, $clock);
if ($rawVoteInfo['endTick'] !== null && $rawVoteInfo['endTick'] < $clock->nowTick()) { if ($voteInfo->endDate && $voteInfo->endDate < new \DateTimeImmutable()) {
return '설문조사가 종료되었습니다.'; return '설문조사가 종료되었습니다.';
} }
+6 -10
View File
@@ -8,11 +8,6 @@ use sammo\Util;
abstract class AbsFromUserPool extends AbsGeneralPool{ abstract class AbsFromUserPool extends AbsGeneralPool{
protected static function getCandidateWeight(array $info, int $owner): int|float
{
return array_sum($info['dex'] ?? []);
}
public function occupyGeneralName(): bool public function occupyGeneralName(): bool
{ {
$generalID = $this->getGeneralBuilder()->getGeneralID(); $generalID = $this->getGeneralBuilder()->getGeneralID();
@@ -30,9 +25,8 @@ abstract class AbsFromUserPool extends AbsGeneralPool{
} }
static public function pickGeneralFromPool(\MeekroDB $db, RandUtil $rng, int $owner, int $pickCnt, ?string $prefix=null):array{ static public function pickGeneralFromPool(\MeekroDB $db, RandUtil $rng, int $owner, int $pickCnt, ?string $prefix=null):array{
$gameStor = KVStorage::getStorage($db, 'game_env'); $oNow = new \DateTimeImmutable();
$clock = GameClock::fromStorage($gameStor); $now = $oNow->format('Y-m-d H:i:s');
$now = $clock->nowTick();
$db->update('select_pool', [ $db->update('select_pool', [
'reserved_until'=>null, 'reserved_until'=>null,
@@ -42,15 +36,17 @@ abstract class AbsFromUserPool extends AbsGeneralPool{
$pool = []; $pool = [];
foreach($db->query('SELECT id, unique_name, info FROM select_pool WHERE reserved_until IS NULL AND general_id IS NULL', $pickCnt) as $cand){ foreach($db->query('SELECT id, unique_name, info FROM select_pool WHERE reserved_until IS NULL AND general_id IS NULL', $pickCnt) as $cand){
$cand['info'] = Json::decode($cand['info']); $cand['info'] = Json::decode($cand['info']);
$pool[] = [$cand, static::getCandidateWeight($cand['info'], $owner)]; $dexTotal = array_sum($cand['info']['dex']);
$pool[] = [$cand, $dexTotal];
} }
if(count($pool) < $pickCnt){ if(count($pool) < $pickCnt){
throw new \RuntimeException('pool 부족'); throw new \RuntimeException('pool 부족');
} }
$gameStor = KVStorage::getStorage($db, 'game_env');
$result = []; $result = [];
$validUntil = $now + GameClock::TICKS_PER_TURN * 2; $validUntil = TimeUtil::nowAddMinutes(2 * $gameStor->turnterm);
while(count($result) < $pickCnt){ while(count($result) < $pickCnt){
$cand = $rng->choiceUsingWeightPair($pool); $cand = $rng->choiceUsingWeightPair($pool);
$poolID = $cand['id']; $poolID = $cand['id'];
+2 -2
View File
@@ -34,7 +34,7 @@ abstract class AbsGeneralPool{
* specialWar * specialWar
*/ */
public function __construct(\MeekroDB $db, RandUtil $rng, array $info, int $validUntil) public function __construct(\MeekroDB $db, RandUtil $rng, array $info, string $validUntil)
{ {
$this->db = $db; $this->db = $db;
$this->info = $info; $this->info = $info;
@@ -92,7 +92,7 @@ abstract class AbsGeneralPool{
return $this->builder; return $this->builder;
} }
public function getValidUntil():int{ public function getValidUntil():string{
return $this->validUntil; return $this->validUntil;
} }
@@ -19,14 +19,10 @@ class che_저지_삼황내문 extends \sammo\BaseItem{
if($unit->isAttacker()){ if($unit->isAttacker()){
return null; return null;
} }
if($unit->getPhase() >= 2){
if($unit->getPhase() > 0){
return null; return null;
} }
if($unit->hasActivatedSkillOnLog('저지') >= 2){ if($unit->getPhase() == 1 && $unit->rng->nextBool(0.5)){
return null;
}
if($unit->hasActivatedSkillOnLog('저지') == 1 && $unit->getPhase() == 0 && $unit->rng->nextBool(0.5)){
return null; return null;
} }
@@ -15,7 +15,7 @@ class che_척사_오악진형도 extends \sammo\BaseItem{
public function getWarPowerMultiplier(WarUnit $unit):array{ public function getWarPowerMultiplier(WarUnit $unit):array{
$opposeCrewType = $unit->getOppose()->getCrewType(); $opposeCrewType = $unit->getOppose()->getCrewType();
if($opposeCrewType->reqCities() || $opposeCrewType->reqRegions()){ if($opposeCrewType->reqCities || $opposeCrewType->reqRegions){
return [1.15, 0.85]; return [1.15, 0.85];
} }
return [1, 1]; return [1, 1];
@@ -33,7 +33,7 @@ class event_전투특기_공성 extends \sammo\BaseItem{
} }
public function onCalcStat(General $general, string $statName, $value, $aux=null){ public function onCalcStat(General $general, string $statName, $value, $aux=null){
if(str_starts_with($statName, 'dex')){ if(\sammo\Util::starts_with($statName, 'dex')){
$myArmType = 'dex'.GameUnitConst::T_SIEGE; $myArmType = 'dex'.GameUnitConst::T_SIEGE;
$opposeArmType = 'dex'.$aux['opposeType']->armType;; $opposeArmType = 'dex'.$aux['opposeType']->armType;;
if($aux['isAttacker'] && $opposeArmType === $statName){ if($aux['isAttacker'] && $opposeArmType === $statName){
@@ -28,7 +28,7 @@ class event_전투특기_궁병 extends \sammo\BaseItem{
if($statName === 'warAvoidRatio'){ if($statName === 'warAvoidRatio'){
return $value + 0.2; return $value + 0.2;
} }
if(str_starts_with($statName, 'dex')){ if(\sammo\Util::starts_with($statName, 'dex')){
$myArmType = 'dex'.GameUnitConst::T_ARCHER; $myArmType = 'dex'.GameUnitConst::T_ARCHER;
$opposeArmType = 'dex'.$aux['opposeType']->armType;; $opposeArmType = 'dex'.$aux['opposeType']->armType;;
if($aux['isAttacker'] && $opposeArmType === $statName){ if($aux['isAttacker'] && $opposeArmType === $statName){
@@ -28,7 +28,7 @@ class event_전투특기_귀병 extends \sammo\BaseItem{
if($statName === 'warMagicSuccessProb'){ if($statName === 'warMagicSuccessProb'){
return $value + 0.2; return $value + 0.2;
} }
if(str_starts_with($statName, 'dex')){ if(\sammo\Util::starts_with($statName, 'dex')){
$myArmType = 'dex'.GameUnitConst::T_WIZARD; $myArmType = 'dex'.GameUnitConst::T_WIZARD;
$opposeArmType = 'dex'.$aux['opposeType']->armType;; $opposeArmType = 'dex'.$aux['opposeType']->armType;;
if($aux['isAttacker'] && $opposeArmType === $statName){ if($aux['isAttacker'] && $opposeArmType === $statName){
@@ -32,7 +32,7 @@ class event_전투특기_기병 extends \sammo\BaseItem{
} }
public function onCalcStat(General $general, string $statName, $value, $aux=null){ public function onCalcStat(General $general, string $statName, $value, $aux=null){
if(str_starts_with($statName, 'dex')){ if(\sammo\Util::starts_with($statName, 'dex')){
$myArmType = 'dex'.GameUnitConst::T_CAVALRY; $myArmType = 'dex'.GameUnitConst::T_CAVALRY;
$opposeArmType = 'dex'.$aux['opposeType']->armType;; $opposeArmType = 'dex'.$aux['opposeType']->armType;;
if($aux['isAttacker'] && $opposeArmType === $statName){ if($aux['isAttacker'] && $opposeArmType === $statName){
@@ -33,7 +33,7 @@ class event_전투특기_보병 extends \sammo\BaseItem{
} }
public function onCalcStat(General $general, string $statName, $value, $aux=null){ public function onCalcStat(General $general, string $statName, $value, $aux=null){
if(str_starts_with($statName, 'dex')){ if(\sammo\Util::starts_with($statName, 'dex')){
$myArmType = 'dex'.GameUnitConst::T_FOOTMAN; $myArmType = 'dex'.GameUnitConst::T_FOOTMAN;
$opposeArmType = 'dex'.$aux['opposeType']->armType;; $opposeArmType = 'dex'.$aux['opposeType']->armType;;
if($aux['isAttacker'] && $opposeArmType === $statName){ if($aux['isAttacker'] && $opposeArmType === $statName){
@@ -17,7 +17,7 @@ class event_전투특기_척사 extends \sammo\BaseItem{
public function getWarPowerMultiplier(WarUnit $unit):array{ public function getWarPowerMultiplier(WarUnit $unit):array{
$opposeCrewType = $unit->getOppose()->getCrewType(); $opposeCrewType = $unit->getOppose()->getCrewType();
if($opposeCrewType->reqCities() || $opposeCrewType->reqRegions()){ if($opposeCrewType->reqCities || $opposeCrewType->reqRegions){
return [1.2, 0.8]; return [1.2, 0.8];
} }
return [1, 1]; return [1, 1];
-52
View File
@@ -1,52 +0,0 @@
<?php
namespace sammo\ActionItem;
use \sammo\iAction;
use \sammo\General;
use \sammo\SpecialityHelper;
use \sammo\GameUnitConst;
use \sammo\WarUnit;
use \sammo\WarUnitCity;
use sammo\RandUtil;
use \sammo\WarUnitTriggerCaller;
use \sammo\BaseWarUnitTrigger;
use sammo\WarUnitTrigger\event_충차아이템소모;
class event_충차 extends \sammo\BaseItem{
protected $rawName = '충차';
protected $name = '충차';
protected $info = '[전투] 성벽 공격 시 대미지 +50%, 2회용';
protected $cost = 2000;
protected $consumable = true;
protected $buyable = true;
protected $reqSecu = 3000;
const REMAIN_KEY = 'remain충차';
function onArbitraryAction(General $general, RandUtil $rng, string $actionType, ?string $phase = null, $aux = null): ?array
{
if($actionType != '장비매매'){
return $aux;
}
if($phase != '구매'){
return $aux;
}
$general->setAuxVar(static::REMAIN_KEY, 2);
return $aux;
}
public function getWarPowerMultiplier(WarUnit $unit):array{
if($unit->getOppose() instanceof WarUnitCity){
return [1.5, 1];
}
return [1, 1];
}
public function getBattlePhaseSkillTriggerList(WarUnit $unit):?WarUnitTriggerCaller{
return new WarUnitTriggerCaller(
new event_충차아이템소모($unit, BaseWarUnitTrigger::TYPE_CONSUMABLE_ITEM)
);
}
}

Some files were not shown because too many files have changed in this diff Show More