Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dca341f35e | ||
|
|
d38ddcd79e | ||
|
|
03675349d8 | ||
|
|
72768ba7b5 | ||
|
|
a5477db6b6 | ||
|
|
c146e8587b | ||
|
|
24b65b0395 | ||
|
|
2f42691d2b | ||
|
|
ea619bd693 | ||
|
|
35a56e74bb | ||
|
|
6fb2358161 | ||
|
|
a039fb871b | ||
|
|
a19da6cda5 | ||
|
|
e5ba980865 | ||
|
|
f95ee8fab8 | ||
|
|
120706ef3f | ||
|
|
58da20f276 | ||
|
|
64af68e2d6 | ||
|
|
76a8740644 | ||
|
|
0863fafec0 | ||
|
|
42579810a2 | ||
|
|
47e6b91b82 | ||
|
|
dd38344319 | ||
|
|
7964aa5f6b | ||
|
|
85d372ecec | ||
|
|
6a2b27b875 | ||
|
|
3b8a82fa42 | ||
|
|
551e17b37b | ||
|
|
acccb74b4e | ||
|
|
39be8fa4b8 | ||
|
|
fc0c183ca3 | ||
|
|
329a461721 | ||
|
|
35b178fe3c | ||
|
|
7464629597 | ||
|
|
cb3982e57c | ||
|
|
08eae297fd | ||
|
|
c46128ed3e | ||
|
|
78a55fb87a | ||
|
|
43a5162a15 | ||
|
|
cb5cb68bf4 | ||
|
|
b79a655d56 | ||
|
|
5b19c24f84 | ||
|
|
e3716bda56 | ||
|
|
b710a26b3e | ||
|
|
e5507e1e61 | ||
|
|
85f3d0b500 | ||
|
|
27811f4891 | ||
|
|
b22987f21b | ||
|
|
8665838472 | ||
|
|
da3fb2c094 | ||
|
|
485d696e85 | ||
|
|
687f2b2edf | ||
|
|
296a27a409 | ||
|
|
c5ceff6fb5 | ||
|
|
2cb697f3dc | ||
|
|
56fd26935d | ||
|
|
002b528ef8 | ||
|
|
1f60f5b3a4 | ||
|
|
cbafa4af61 | ||
|
|
19f936b6c0 | ||
|
|
016f3c73e3 | ||
|
|
57541eca89 | ||
|
|
b7e568fb98 | ||
|
|
438cff532b | ||
|
|
3f71490d14 | ||
|
|
2221a8c9bf | ||
|
|
7255588bcc | ||
|
|
c732bcddb1 | ||
|
|
9f363e46fc | ||
|
|
99242ac3d3 | ||
|
|
3d6aabda06 | ||
|
|
d28a5e095a | ||
|
|
8104852abf | ||
|
|
459c108b13 | ||
|
|
d318ff7d90 | ||
|
|
1371b84687 | ||
|
|
2cc679dcac | ||
|
|
04f5a1bbe1 | ||
|
|
83c2fc918f | ||
|
|
63cfa5e298 | ||
|
|
3e815691df | ||
|
|
0fc0031574 | ||
|
|
6d335284ee | ||
|
|
1a9010ac06 |
@@ -29,6 +29,7 @@ d_pic/*.png
|
|||||||
d_pic/*.webp
|
d_pic/*.webp
|
||||||
d_pic/uploaded_image
|
d_pic/uploaded_image
|
||||||
|
|
||||||
|
/dist_js
|
||||||
*/dist_misc/*
|
*/dist_misc/*
|
||||||
*/dist_js/*
|
*/dist_js/*
|
||||||
*/dist_css/*
|
*/dist_css/*
|
||||||
|
|||||||
@@ -44,9 +44,7 @@ return [
|
|||||||
'hwe/a_npcList.php',
|
'hwe/a_npcList.php',
|
||||||
'hwe/api.php',
|
'hwe/api.php',
|
||||||
'hwe/a_traffic.php',
|
'hwe/a_traffic.php',
|
||||||
'hwe/a_vote.php',
|
|
||||||
'hwe/battle_simulator.php',
|
'hwe/battle_simulator.php',
|
||||||
'hwe/b_auction.php',
|
|
||||||
'hwe/b_battleCenter.php',
|
'hwe/b_battleCenter.php',
|
||||||
'hwe/b_betting.php',
|
'hwe/b_betting.php',
|
||||||
'hwe/v_chiefCenter.php',
|
'hwe/v_chiefCenter.php',
|
||||||
@@ -61,9 +59,7 @@ return [
|
|||||||
'hwe/v_processing.php',
|
'hwe/v_processing.php',
|
||||||
'hwe/b_tournament.php',
|
'hwe/b_tournament.php',
|
||||||
'hwe/b_troop.php',
|
'hwe/b_troop.php',
|
||||||
'hwe/c_auction.php',
|
|
||||||
'hwe/c_tournament.php',
|
'hwe/c_tournament.php',
|
||||||
'hwe/c_vote.php',
|
|
||||||
'hwe/func_auction.php',
|
'hwe/func_auction.php',
|
||||||
'hwe/func_command.php',
|
'hwe/func_command.php',
|
||||||
'hwe/func_converter.php',
|
'hwe/func_converter.php',
|
||||||
|
|||||||
+5
-9
@@ -8,28 +8,24 @@
|
|||||||
],
|
],
|
||||||
"config": {
|
"config": {
|
||||||
"platform": {
|
"platform": {
|
||||||
"php": "8.0"
|
"php": "8.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"brandonwamboldt/utilphp": "^1.1",
|
"brandonwamboldt/utilphp": "^1.1",
|
||||||
"sergeytsalkov/meekrodb": "^2.3",
|
"sergeytsalkov/meekrodb": "^2.3",
|
||||||
"league/plates": "^3.3",
|
"league/plates": "^3.3",
|
||||||
"guzzlehttp/guzzle": "^6.3",
|
|
||||||
"monolog/monolog": "^1.23",
|
|
||||||
"firephp/firephp-core": "^0.4.0",
|
|
||||||
"vlucas/valitron": "^1.4",
|
"vlucas/valitron": "^1.4",
|
||||||
"php-extended/php-tail": "^2.1",
|
"php-extended/php-tail": "^2.1",
|
||||||
"pguardiario/phpuri": "^1.0",
|
"pguardiario/phpuri": "^1.0",
|
||||||
"symfony/lock": "^4.1",
|
"symfony/lock": "^6.0",
|
||||||
"ezyang/htmlpurifier": "^4.10",
|
"ezyang/htmlpurifier": "^4.10",
|
||||||
"xemlock/htmlpurifier-html5": "^0.1.7",
|
"xemlock/htmlpurifier-html5": "^0.1.7",
|
||||||
"catfan/medoo": "^1.5",
|
"catfan/medoo": "^2.1",
|
||||||
"phan/phan": "^5.3",
|
"phan/phan": "^5.3",
|
||||||
"erusev/parsedown-extra": "^0.8.1",
|
|
||||||
"nette/caching": "^3.0",
|
"nette/caching": "^3.0",
|
||||||
"illuminate/database": "^8.61",
|
"illuminate/database": "^9.12",
|
||||||
"illuminate/events": "^8.61",
|
"illuminate/events": "^9.12",
|
||||||
"spatie/data-transfer-object": "^3.7",
|
"spatie/data-transfer-object": "^3.7",
|
||||||
"php-ds/php-ds": "^1.4"
|
"php-ds/php-ds": "^1.4"
|
||||||
},
|
},
|
||||||
|
|||||||
Generated
+568
-1322
File diff suppressed because it is too large
Load Diff
Binary file not shown.
+15
-4
@@ -81,23 +81,34 @@ a.just_link {
|
|||||||
|
|
||||||
button.with_skin {
|
button.with_skin {
|
||||||
padding: 0 4px;
|
padding: 0 4px;
|
||||||
background-color: black;
|
background-color: #191919;
|
||||||
color: white;
|
color: white;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
border-top-color: gray;
|
||||||
|
border-left-color: gray;
|
||||||
|
border-right-color: black;
|
||||||
|
border-bottom-color: black;
|
||||||
}
|
}
|
||||||
|
|
||||||
button.with_skin:disabled {
|
button.with_skin:disabled {
|
||||||
background-color: #333333;
|
background-color: #333;
|
||||||
}
|
}
|
||||||
|
|
||||||
input.with_skin {
|
input.with_skin {
|
||||||
background-color: black;
|
background-color: #191919;
|
||||||
color: white;
|
color: white;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input.with_skin[type=button], input.with_skin[type=submit]{
|
||||||
|
border-top-color: gray;
|
||||||
|
border-left-color: gray;
|
||||||
|
border-right-color: black;
|
||||||
|
border-bottom-color: black;
|
||||||
|
}
|
||||||
|
|
||||||
input.with_skin:disabled {
|
input.with_skin:disabled {
|
||||||
background-color: #333333;
|
background-color: #333;
|
||||||
}
|
}
|
||||||
|
|
||||||
.font0 {
|
.font0 {
|
||||||
|
|||||||
+2
-1
@@ -96,7 +96,8 @@ function logError(string $err, string $errstr, string $errpath, array $trace)
|
|||||||
$fdb = FileDB::db(ROOT . '/d_log/err_log.sqlite3', ROOT . '/f_install/sql/err_log.sql');
|
$fdb = FileDB::db(ROOT . '/d_log/err_log.sqlite3', ROOT . '/f_install/sql/err_log.sql');
|
||||||
$date = date("Ymd_His");
|
$date = date("Ymd_His");
|
||||||
|
|
||||||
$err =str_replace(ROOT, '{ROOT}', $errpath);
|
$err = str_replace(ROOT, '{ROOT}', $err);
|
||||||
|
$errstr = str_replace(ROOT, '{ROOT}', $errstr);
|
||||||
$errpath = str_replace(ROOT, '{ROOT}', $errpath);
|
$errpath = str_replace(ROOT, '{ROOT}', $errpath);
|
||||||
$trace = array_map(function (string $text) {
|
$trace = array_map(function (string $text) {
|
||||||
return str_replace(ROOT, '{ROOT}', $text);
|
return str_replace(ROOT, '{ROOT}', $text);
|
||||||
|
|||||||
+6
-6
@@ -50,9 +50,9 @@ switch ($btn) {
|
|||||||
$db->update('general', [
|
$db->update('general', [
|
||||||
'turntime' => $db->sqleval('DATE_SUB(turntime, INTERVAL %i MINUTE)', $minute)
|
'turntime' => $db->sqleval('DATE_SUB(turntime, INTERVAL %i MINUTE)', $minute)
|
||||||
], true);
|
], true);
|
||||||
$db->update('auction', [
|
$db->update('ng_auction', [
|
||||||
'expire' => $db->sqleval('DATE_SUB(expire, INTERVAL %i MINUTE)', $minute)
|
'close_date' => $db->sqleval('DATE_SUB(close_date, INTERVAL %i MINUTE)', $minute)
|
||||||
], true);
|
], 'finished = 0');
|
||||||
if ($locked) {
|
if ($locked) {
|
||||||
unlock();
|
unlock();
|
||||||
}
|
}
|
||||||
@@ -78,9 +78,9 @@ switch ($btn) {
|
|||||||
$db->update('general', [
|
$db->update('general', [
|
||||||
'turntime' => $db->sqleval('DATE_ADD(turntime, INTERVAL %i MINUTE)', $minute)
|
'turntime' => $db->sqleval('DATE_ADD(turntime, INTERVAL %i MINUTE)', $minute)
|
||||||
], true);
|
], true);
|
||||||
$db->update('auction', [
|
$db->update('ng_auction', [
|
||||||
'expire' => $db->sqleval('DATE_ADD(expire, INTERVAL %i MINUTE)', $minute)
|
'close_date' => $db->sqleval('DATE_ADD(close_date, INTERVAL %i MINUTE)', $minute)
|
||||||
], true);
|
], 'finished = 0');
|
||||||
if ($locked) {
|
if ($locked) {
|
||||||
unlock();
|
unlock();
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-51
@@ -48,54 +48,25 @@ $db = DB::db();
|
|||||||
<font color=red>접속제한</font><br><b style=background-color:red;>블럭회원</b>
|
<font color=red>접속제한</font><br><b style=background-color:red;>블럭회원</b>
|
||||||
</td>
|
</td>
|
||||||
<td width=105 rowspan=12>
|
<td width=105 rowspan=12>
|
||||||
<?php
|
<select name=genlist[] size=20 multiple style='color:white;background-color:black;font-size:14px'>
|
||||||
|
<?php
|
||||||
|
$generalList = $db->query('SELECT `no`, `name`, npc, `block` FROM general ORDER BY npc, binary(`name`)');
|
||||||
|
|
||||||
echo "
|
foreach ($generalList as $general) {
|
||||||
<select name=genlist[] size=20 multiple style='color:white;background-color:black;font-size:14px'>";
|
$style = "style=;";
|
||||||
$generalList = $db->query('SELECT `no`, `name`, npc, `block` FROM general ORDER BY npc, binary(`name`)');
|
if ($general['block'] > 0) {
|
||||||
|
$style .= "background-color:red;";
|
||||||
foreach ($generalList as $general) {
|
|
||||||
$style = "style=;";
|
|
||||||
if ($general['block'] > 0) {
|
|
||||||
$style .= "background-color:red;";
|
|
||||||
}
|
|
||||||
|
|
||||||
$npcColor = getNPCColor($general['npc']);
|
|
||||||
if($npcColor !== null){
|
|
||||||
$style .= "color:{$npcColor};";
|
|
||||||
}
|
|
||||||
|
|
||||||
echo "
|
|
||||||
<option value={$general['no']} $style>{$general['name']}</option>";
|
|
||||||
}
|
|
||||||
|
|
||||||
echo "
|
|
||||||
</select>
|
|
||||||
</td>
|
|
||||||
<td width=100 align=center>아이템 지급</td>
|
|
||||||
<td width=504>
|
|
||||||
<select name=weapon size=1 style='color:white;background-color:black;font-size:14px'>";
|
|
||||||
foreach (GameConst::$allItems as $itemCategories) {
|
|
||||||
foreach ($itemCategories as $item => $cnt) {
|
|
||||||
if ($cnt == 0) {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
$itemObj = buildItemClass($item);
|
|
||||||
if ($itemObj->isBuyable()) {
|
$npcColor = getNPCColor($general['npc']);
|
||||||
continue;
|
if ($npcColor !== null) {
|
||||||
|
$style .= "color:{$npcColor};";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
echo "<option value={$general['no']} $style>{$general['name']}</option>";
|
||||||
}
|
}
|
||||||
}
|
?>
|
||||||
for ($i = 0; $i < 27; $i++) {
|
|
||||||
echo "
|
|
||||||
<option value={$i}>{$i}</option>";
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
</select>
|
</select>
|
||||||
<input type=submit name=btn value='무기지급'>
|
|
||||||
<input type=submit name=btn value='책지급'>
|
|
||||||
<input type=submit name=btn value='말지급'>
|
|
||||||
<input type=submit name=btn value='도구지급'>
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -109,10 +80,6 @@ $db = DB::db();
|
|||||||
<td align=center>강제 사망</td>
|
<td align=center>강제 사망</td>
|
||||||
<td><input type=submit name=btn value='강제 사망'></td>
|
<td><input type=submit name=btn value='강제 사망'></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
|
||||||
<td align=center>이벤트</td>
|
|
||||||
<td><input type=submit name=btn value='특기 부여'><input type=submit name=btn value='공헌치1000'><input type=submit name=btn value='경험치1000'></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
<tr>
|
||||||
<td align=center>이벤트2</td>
|
<td align=center>이벤트2</td>
|
||||||
<td><input type=submit name=btn value='보숙10000'><input type=submit name=btn value='궁숙10000'><input type=submit name=btn value='기숙10000'><input type=submit name=btn value='귀숙10000'><input type=submit name=btn value='차숙10000'></td>
|
<td><input type=submit name=btn value='보숙10000'><input type=submit name=btn value='궁숙10000'><input type=submit name=btn value='기숙10000'><input type=submit name=btn value='귀숙10000'><input type=submit name=btn value='차숙10000'></td>
|
||||||
@@ -121,10 +88,6 @@ $db = DB::db();
|
|||||||
<td align=center>접속제한</td>
|
<td align=center>접속제한</td>
|
||||||
<td><input type=submit name=btn value='접속 허용'><input type=submit name=btn value='접속 제한'></td>
|
<td><input type=submit name=btn value='접속 허용'><input type=submit name=btn value='접속 제한'></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
|
||||||
<td align=center>턴 시각 설정</td>
|
|
||||||
<td><input type=submit name=btn value='00턴'><input type=submit name=btn value='랜덤턴'></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
<tr>
|
||||||
<td align=center>명령 설정</td>
|
<td align=center>명령 설정</td>
|
||||||
<td><input type=submit name=btn value='하야입력'><input type=submit name=btn value='방랑해산'></td>
|
<td><input type=submit name=btn value='하야입력'><input type=submit name=btn value='방랑해산'></td>
|
||||||
|
|||||||
@@ -107,28 +107,6 @@ switch ($btn) {
|
|||||||
'arg' => '{}',
|
'arg' => '{}',
|
||||||
'brief' => '휴식',
|
'brief' => '휴식',
|
||||||
], 'general_id IN %li AND turn_idx = 0', $genlist);
|
], 'general_id IN %li AND turn_idx = 0', $genlist);
|
||||||
break;
|
|
||||||
case "특기 부여":
|
|
||||||
[$year, $month] = $gameStor->getValuesAsArray(['year', 'month']);
|
|
||||||
$text = "특기 부여!";
|
|
||||||
|
|
||||||
foreach ($db->query("SELECT `no`,leadership,strength,intel,dex1,dex2,dex3,dex4,dex5 FROM general WHERE `no` IN %li", $genlist) as $general) {
|
|
||||||
$msg = new Message(Message::MSGTYPE_PRIVATE, $src, MessageTarget::buildQuick($general['no']), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
|
|
||||||
$msg->send(true);
|
|
||||||
|
|
||||||
$specialWar = SpecialityHelper::pickSpecialWar($general);
|
|
||||||
$db->update('general', [
|
|
||||||
'specage2' => $db->sqleval('age'),
|
|
||||||
'special2' => $specialWar
|
|
||||||
], 'no=%i', $general['no']);
|
|
||||||
$specialWarName = buildGeneralSpecialWarClass($specialWar)->getName();
|
|
||||||
$josaUl = JosaUtil::pick($specialWarName, '을');
|
|
||||||
$logger = new ActionLogger($general['no'], 0, $year, $month);
|
|
||||||
$logger->pushGeneralHistoryLog("특기 【<b><C>{$specialWarName}</></b>】{$josaUl} 습득");
|
|
||||||
$logger->pushGeneralActionLog("특기 【<b><L>{$specialWarName}</></b>】{$josaUl} 익혔습니다!",ActionLogger::PLAIN);
|
|
||||||
$logger->flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case "경험치1000":
|
case "경험치1000":
|
||||||
$text = $btn . " 지급!";
|
$text = $btn . " 지급!";
|
||||||
@@ -222,95 +200,6 @@ switch ($btn) {
|
|||||||
$msg->send(true);
|
$msg->send(true);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "무기지급":
|
|
||||||
|
|
||||||
if ($item == 'None') {
|
|
||||||
$text = "무기 회수!";
|
|
||||||
} else {
|
|
||||||
$text = getItemName($item) . " 지급!";
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($genlist as $generalID) {
|
|
||||||
$msg = new Message(Message::MSGTYPE_PRIVATE, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
|
|
||||||
$msg->send(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($item === 'None') {
|
|
||||||
$db->update('general', [
|
|
||||||
'weapon' => 'None'
|
|
||||||
], '`no` IN %li', $genlist);
|
|
||||||
} else {
|
|
||||||
$db->update('general', [
|
|
||||||
'weapon' => $item
|
|
||||||
], '`no` IN %li', $genlist, $item);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "책지급":
|
|
||||||
if ($item == 'None') {
|
|
||||||
$text = "책 회수!";
|
|
||||||
} else {
|
|
||||||
$text = getItemName($item) . " 지급!";
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($genlist as $generalID) {
|
|
||||||
$msg = new Message(Message::MSGTYPE_PRIVATE, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
|
|
||||||
$msg->send(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($item == 'None') {
|
|
||||||
$db->update('general', [
|
|
||||||
'book' => 'None'
|
|
||||||
], '`no` IN %li', $genlist);
|
|
||||||
} else {
|
|
||||||
$db->update('general', [
|
|
||||||
'book' => $item
|
|
||||||
], '`no` IN %li', $genlist);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "말지급":
|
|
||||||
if ($item == 'None') {
|
|
||||||
$text = "말 회수!";
|
|
||||||
} else {
|
|
||||||
$text = getItemName($item) . " 지급!";
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($genlist as $generalID) {
|
|
||||||
$msg = new Message(Message::MSGTYPE_PRIVATE, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
|
|
||||||
$msg->send(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($item == 'None') {
|
|
||||||
$db->update('general', [
|
|
||||||
'horse' => 'None'
|
|
||||||
], '`no` IN %li', $genlist);
|
|
||||||
} else {
|
|
||||||
$db->update('general', [
|
|
||||||
'horse' => $item
|
|
||||||
], '`no` IN %li', $genlist);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "도구지급":
|
|
||||||
if ($item == 'None') {
|
|
||||||
$text = "특수도구 회수!";
|
|
||||||
} else {
|
|
||||||
$text = getItemName($item) . " 지급!";
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($genlist as $generalID) {
|
|
||||||
$msg = new Message(Message::MSGTYPE_PRIVATE, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
|
|
||||||
$msg->send(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($item == 'None') {
|
|
||||||
$db->update('general', [
|
|
||||||
'item' => 'None'
|
|
||||||
], '`no` IN %li', $genlist);
|
|
||||||
} else {
|
|
||||||
$db->update('general', [
|
|
||||||
'item' => $item
|
|
||||||
], '`no` IN %li AND item < %i', $genlist, $item);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "하야입력":
|
case "하야입력":
|
||||||
$db->update('general_turn', [
|
$db->update('general_turn', [
|
||||||
'action' => 'che_하야',
|
'action' => 'che_하야',
|
||||||
@@ -330,26 +219,6 @@ switch ($btn) {
|
|||||||
'brief' => '해산',
|
'brief' => '해산',
|
||||||
], 'general_id IN %li AND turn_idx = 1', $genlist);
|
], 'general_id IN %li AND turn_idx = 1', $genlist);
|
||||||
break;
|
break;
|
||||||
case "00턴":
|
|
||||||
$turnterm = $gameStor->turnterm;
|
|
||||||
|
|
||||||
foreach ($genlist as $generalID) {
|
|
||||||
$turntime = getRandTurn($turnterm);
|
|
||||||
$cutTurn = cutTurn($turntime, $turnterm);
|
|
||||||
$db->update('general', [
|
|
||||||
'turntime' => $cutTurn
|
|
||||||
], '`no` IN %li', $genlist);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "랜덤턴":
|
|
||||||
$turnterm = $gameStor->turnterm;
|
|
||||||
foreach ($genlist as $generalID) {
|
|
||||||
$turntime = getRandTurn($turnterm);
|
|
||||||
$db->update('general', [
|
|
||||||
'turntime' => $turntime
|
|
||||||
], '`no` IN %li', $genlist);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
header('location:_admin2.php');
|
header('location:_admin2.php');
|
||||||
|
|||||||
@@ -2,7 +2,9 @@
|
|||||||
|
|
||||||
namespace sammo;
|
namespace sammo;
|
||||||
|
|
||||||
|
use Ds\Set;
|
||||||
use sammo\Enums\RankColumn;
|
use sammo\Enums\RankColumn;
|
||||||
|
use sammo\Enums\AuctionType;
|
||||||
|
|
||||||
include "lib.php";
|
include "lib.php";
|
||||||
include "func.php";
|
include "func.php";
|
||||||
@@ -19,6 +21,7 @@ $gameStor = KVStorage::getStorage($db, 'game_env');
|
|||||||
increaseRefresh("명장일람", 1);
|
increaseRefresh("명장일람", 1);
|
||||||
$templates = new \League\Plates\Engine(__DIR__ . '/templates');
|
$templates = new \League\Plates\Engine(__DIR__ . '/templates');
|
||||||
|
|
||||||
|
|
||||||
?>
|
?>
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
@@ -326,6 +329,32 @@ $templates = new \League\Plates\Engine(__DIR__ . '/templates');
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$dummyAuctionGeneral = [
|
||||||
|
'nation' => 0,
|
||||||
|
'no' => 0,
|
||||||
|
'ownerName' => '',
|
||||||
|
'pictureFullPath' => GetImageURL(0) . "/default.jpg",
|
||||||
|
'name' => '경매중',
|
||||||
|
'bgColor' => '#00582c',
|
||||||
|
'fgColor' => 'white',
|
||||||
|
'nationName' => '-',
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($db->queryFirstColumn(
|
||||||
|
'SELECT `target` FROM ng_auction WHERE `finished` = 0 AND `type` = %s',
|
||||||
|
AuctionType::UniqueItem->value
|
||||||
|
) as $itemClassName) {
|
||||||
|
if(key_exists($itemClassName, $itemOwners)) {
|
||||||
|
$itemOwners[$itemClassName][] = $dummyAuctionGeneral;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
$itemOwners[$itemClassName] = [$dummyAuctionGeneral];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
foreach (GameConst::$allItems as $itemType => $itemList) {
|
foreach (GameConst::$allItems as $itemType => $itemList) {
|
||||||
$itemNameType = $itemTypes[$itemType];
|
$itemNameType = $itemTypes[$itemType];
|
||||||
$itemList = array_reverse($itemList, true);
|
$itemList = array_reverse($itemList, true);
|
||||||
|
|||||||
-434
@@ -1,434 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace sammo;
|
|
||||||
|
|
||||||
include "lib.php";
|
|
||||||
include "func.php";
|
|
||||||
|
|
||||||
$session = Session::requireGameLogin()->setReadOnly();
|
|
||||||
$userID = Session::getUserID();
|
|
||||||
$db = DB::db();
|
|
||||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
|
||||||
|
|
||||||
increaseRefresh("설문조사", 1);
|
|
||||||
|
|
||||||
$isVoteAdmin = in_array('vote', $session->acl[DB::prefix()] ?? []);
|
|
||||||
$isVoteAdmin = $isVoteAdmin || $session->userGrade >= 5;
|
|
||||||
|
|
||||||
$me = $db->queryFirstRow('SELECT no,vote from general where owner=%i', $userID);
|
|
||||||
|
|
||||||
$admin = $gameStor->getValues(['develcost', 'voteopen', 'vote_title', 'vote', 'votecomment']);
|
|
||||||
$vote_title = $admin['vote_title'] ?? '-';
|
|
||||||
$vote = $admin['vote'] ?: ['-'];
|
|
||||||
|
|
||||||
?>
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<title><?= UniqueConst::$serverName ?>: 설문조사</title>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
||||||
<meta name="viewport" content="width=1024" />
|
|
||||||
<?= WebUtil::printCSS('../d_shared/common.css') ?>
|
|
||||||
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard/dist/web/static/pretendard.css" />
|
|
||||||
<style>
|
|
||||||
.little_bar {
|
|
||||||
float: left;
|
|
||||||
position: relative;
|
|
||||||
height: 17px;
|
|
||||||
line-height: 17px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<?= WebUtil::printJS('../d_shared/common_path.js') ?>
|
|
||||||
<?= WebUtil::printDist('ts', ['common']) ?>
|
|
||||||
<script type="text/javascript">
|
|
||||||
function captureKey(e) {
|
|
||||||
if (e.keyCode == 13 && e.srcElement.type == 'text') {
|
|
||||||
form1.btn.value = '댓글';
|
|
||||||
form1.btn.click();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<table align=center width=1000 class='tb_layout bg0'>
|
|
||||||
<tr>
|
|
||||||
<td>설 문 조 사<br><?= closeButton() ?></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<table align=center width=1000 class='tb_layout bg0'>
|
|
||||||
<form name=form1 action=c_vote.php method=post>
|
|
||||||
<tr>
|
|
||||||
<td colspan=3 align=center class='bg2'>
|
|
||||||
<font size=5>설 문 조 사 (<?= $admin['develcost'] * 5 ?>금과 추첨으로 유니크템 증정!)</font>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<?php
|
|
||||||
|
|
||||||
if ($isVoteAdmin) {
|
|
||||||
echo "
|
|
||||||
<tr>
|
|
||||||
<td width=48 align=center><input type=submit name=btn value='알림'></td>
|
|
||||||
<td width=98 align=center><input type=submit name=btn value='수정'></td>
|
|
||||||
<td width=848 align=left><input type=text name=title style=width:848px;></td>
|
|
||||||
</tr>
|
|
||||||
";
|
|
||||||
}
|
|
||||||
|
|
||||||
$vote_title = Tag2Code($vote_title);
|
|
||||||
echo "
|
|
||||||
<tr>
|
|
||||||
<td colspan=2 width=148 align=center class='bg1'>제 목</td>
|
|
||||||
<td width=848 align=left> {$vote_title}</td>
|
|
||||||
</tr>
|
|
||||||
";
|
|
||||||
|
|
||||||
$voteCount = $db->queryFirstField('SELECT count(no) FROM general WHERE vote>0 AND npc<2');
|
|
||||||
$allCount = $db->queryFirstField('SELECT count(no) FROM general WHERE npc<2');
|
|
||||||
|
|
||||||
$percentage = round($voteCount / $allCount * 100, 1);
|
|
||||||
|
|
||||||
$voteTypeCount = count($vote);
|
|
||||||
for ($i = 1; $i < $voteTypeCount; $i++) {
|
|
||||||
echo "
|
|
||||||
<tr>
|
|
||||||
<td width=48 align=center style=color:" . getNewColor($i) . "; bgcolor=" . getVoteColor($i) . ">{$i}.</td>
|
|
||||||
<td width=98 align=center>
|
|
||||||
";
|
|
||||||
if ($me['vote'] == 0 && $me['no'] > 0) {
|
|
||||||
echo "
|
|
||||||
<input type=radio name=sel value={$i}>
|
|
||||||
";
|
|
||||||
} elseif ($admin['voteopen'] >= 1 || $isVoteAdmin) {
|
|
||||||
$vCount = $db->queryFirstField('SELECT count(no) FROM general WHERE vote=%i', $i);
|
|
||||||
|
|
||||||
$per = @round($vCount / $voteCount * 100, 1);
|
|
||||||
echo "{$vCount} 표 ({$per}%)";
|
|
||||||
} else {
|
|
||||||
echo "추후공개";
|
|
||||||
}
|
|
||||||
$vote[$i] = Tag2Code($vote[$i]);
|
|
||||||
echo "
|
|
||||||
</td>
|
|
||||||
<td align=left> {$vote[$i]}</td>
|
|
||||||
</tr>
|
|
||||||
";
|
|
||||||
}
|
|
||||||
|
|
||||||
echo "
|
|
||||||
<tr>
|
|
||||||
";
|
|
||||||
if ($me['vote'] == 0 && $me['no'] > 0) {
|
|
||||||
echo "
|
|
||||||
<td align=center>투표</td>
|
|
||||||
<td align=center><input type=submit name=btn value='투표'></td>
|
|
||||||
";
|
|
||||||
} else {
|
|
||||||
echo "
|
|
||||||
<td colspan=2 align=center>결산</td>
|
|
||||||
";
|
|
||||||
}
|
|
||||||
echo "
|
|
||||||
<td align=left> 투표율 : {$voteCount} / {$allCount} ({$percentage} %)</td>
|
|
||||||
</tr>
|
|
||||||
";
|
|
||||||
|
|
||||||
if ($isVoteAdmin) {
|
|
||||||
echo "
|
|
||||||
<tr>
|
|
||||||
<td align=center><input type=submit name=btn value='리셋'></td>
|
|
||||||
<td align=center><input type=submit name=btn value='추가'></td>
|
|
||||||
<td align=left><input type=text name=str style=width:848px;></td>
|
|
||||||
</tr>
|
|
||||||
";
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($admin['votecomment']) {
|
|
||||||
$comment = $admin['votecomment'];
|
|
||||||
$commentCount = count($comment);
|
|
||||||
} else {
|
|
||||||
$commentCount = 0;
|
|
||||||
}
|
|
||||||
echo "
|
|
||||||
</table>
|
|
||||||
<table align=center width=1000 class='tb_layout bg0'>
|
|
||||||
<tr>
|
|
||||||
<td colspan=4 align=center class='bg1'>댓 글</td>
|
|
||||||
</tr>
|
|
||||||
";
|
|
||||||
for ($i = 0; $i < $commentCount; $i++) {
|
|
||||||
$cmt = $comment[$i];
|
|
||||||
$cmt[2] = Tag2Code($cmt[2]);
|
|
||||||
$j = $i + 1;
|
|
||||||
echo "
|
|
||||||
<tr>
|
|
||||||
<td width=28 align=center>{$j}.</td>
|
|
||||||
<td width=130 align=center>{$cmt[0]}</td>
|
|
||||||
<td width=130 align=center>{$cmt[1]}</td>
|
|
||||||
<td width=712 align=left> {$cmt[2]}</td>
|
|
||||||
</tr>
|
|
||||||
";
|
|
||||||
}
|
|
||||||
if ($me['no'] > 0) {
|
|
||||||
echo "
|
|
||||||
<tr>
|
|
||||||
<td width=158 colspan=2 align=center>-</td>
|
|
||||||
<td width=130 align=center><input type=submit name=btn value='댓글'></td>
|
|
||||||
<td align=left><input type=text name=comment maxlength=60 style=width:700px; onkeydown='return captureKey(event)'></td>
|
|
||||||
</tr>
|
|
||||||
";
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
</table>
|
|
||||||
<br>
|
|
||||||
<table align=center width=1000 class='tb_layout bg0'>
|
|
||||||
<tr>
|
|
||||||
<td colspan=3 align=center class='bg2'>
|
|
||||||
<font size=5>
|
|
||||||
전 체 통 계
|
|
||||||
<?php
|
|
||||||
if ($isVoteAdmin) {
|
|
||||||
echo "
|
|
||||||
<input type=submit name=btn value='숨김'>
|
|
||||||
<input type=submit name=btn value='전체통계만'>
|
|
||||||
<input type=submit name=btn value='전부'>";
|
|
||||||
}
|
|
||||||
echo "
|
|
||||||
</font></td></tr>";
|
|
||||||
|
|
||||||
if ($admin['voteopen'] >= 1 || $isVoteAdmin) {
|
|
||||||
echo "
|
|
||||||
<tr>
|
|
||||||
<td width=130 align=center>전 체</td>
|
|
||||||
<td width=128 align=center>{$voteCount} / {$allCount} ({$percentage} %)</td>
|
|
||||||
<td width=742>
|
|
||||||
";
|
|
||||||
|
|
||||||
$memCount = max(1, $db->queryFirstField('SELECT count(`no`) FROM general WHERE npc<2'));
|
|
||||||
|
|
||||||
$totalVote = [];
|
|
||||||
$nationVoteCount = [];
|
|
||||||
$nationVote = [];
|
|
||||||
|
|
||||||
foreach ($db->query("SELECT nation, vote, count(`no`) as cnt FROM general WHERE npc<2 GROUP BY nation, vote") as $row) {
|
|
||||||
$nation = $row['nation'];
|
|
||||||
$ownVote = $row['vote'];
|
|
||||||
$cnt = $row['cnt'];
|
|
||||||
|
|
||||||
if (!isset($totalVote[$ownVote])) {
|
|
||||||
$totalVote[$ownVote] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isset($nationVoteCount[$nation])) {
|
|
||||||
$nationVoteCount[$nation] = 0;
|
|
||||||
$nationVote[$nation] = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isset($nationVote[$nation][$ownVote])) {
|
|
||||||
$nationVote[$nation][$ownVote] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
$totalVote[$ownVote] += $cnt;
|
|
||||||
$nationVoteCount[$nation] += $cnt;
|
|
||||||
$nationVote[$nation][$ownVote] += $cnt;
|
|
||||||
}
|
|
||||||
|
|
||||||
$totalPer = 0;
|
|
||||||
for ($i = 0; $i < $voteTypeCount; $i++) {
|
|
||||||
$per = round(($totalVote[$i] ?? 0) * 100 / $memCount, 1);
|
|
||||||
if ($i == $voteTypeCount - 1) {
|
|
||||||
$per = 100 - $totalPer;
|
|
||||||
} else {
|
|
||||||
$totalPer += $per;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// if($per < 5) { $vote['cnt'] = " "; }
|
|
||||||
?>
|
|
||||||
<?php if ($per == 0) : ?>
|
|
||||||
<?php elseif ($per < 10) : ?>
|
|
||||||
<div class='little_bar' style='width:<?= $per ?>%;color:<?= getNewColor($i) ?>;background-color:<?= getVoteColor($i) ?>;'></div>
|
|
||||||
<?php else : ?>
|
|
||||||
<div class='little_bar' style='width:<?= $per ?>%;color:<?= getNewColor($i) ?>;background-color:<?= getVoteColor($i) ?>;'><?= $totalVote[$i] ?></div>
|
|
||||||
<?php endif; ?>
|
|
||||||
<?php
|
|
||||||
}
|
|
||||||
|
|
||||||
echo "
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
";
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($admin['voteopen'] >= 2 || $isVoteAdmin) {
|
|
||||||
$memCount = $db->queryFirstField('SELECT count(no) FROM general WHERE nation=0 AND npc <2');
|
|
||||||
if ($memCount == 0) {
|
|
||||||
$memCount = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isset($nationVoteCount[0])) {
|
|
||||||
$nationVoteCount[0] = 0;
|
|
||||||
}
|
|
||||||
$percentage = round($nationVoteCount[0] / $memCount * 100, 1);
|
|
||||||
|
|
||||||
echo "
|
|
||||||
<tr>
|
|
||||||
<td align=center bgcolor=black>재 야</td>
|
|
||||||
<td align=center>{$nationVoteCount[0]} / {$memCount} ({$percentage} %)</td>
|
|
||||||
<td>
|
|
||||||
";
|
|
||||||
|
|
||||||
$totalPer = 0;
|
|
||||||
for ($i = 0; $i < $voteTypeCount; $i++) {
|
|
||||||
$per = round(Util::array_get($nationVote[0][$i], 0) / $memCount * 100, 1);
|
|
||||||
if ($i == $voteTypeCount - 1) {
|
|
||||||
$per = 100 - $totalPer;
|
|
||||||
} else {
|
|
||||||
$totalPer += $per;
|
|
||||||
}
|
|
||||||
// if($per < 5) { $vote['cnt'] = " "; }
|
|
||||||
?>
|
|
||||||
<?php if ($per == 0) : ?>
|
|
||||||
<?php elseif ($per < 10) : ?>
|
|
||||||
<div class='little_bar' style='width:<?= $per ?>%;color:<?= getNewColor($i) ?>;background-color:<?= getVoteColor($i) ?>;'></div>
|
|
||||||
<?php else : ?>
|
|
||||||
<div class='little_bar' style='width:<?= $per ?>%;color:<?= getNewColor($i) ?>;background-color:<?= getVoteColor($i) ?>;'><?= $nationVote[0][$i] ?></div>
|
|
||||||
<?php endif; ?>
|
|
||||||
<?php
|
|
||||||
}
|
|
||||||
|
|
||||||
echo "
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
";
|
|
||||||
|
|
||||||
foreach ($db->query('SELECT nation,color,name,gennum from nation order by gennum desc') as $i => $nation) {
|
|
||||||
$memCount = $db->queryFirstField('SELECT count(no) FROM general WHERE nation=%i AND npc<2', $nation['nation']);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
$voteCount = $nationVoteCount[$nation['nation']] ?? 0;
|
|
||||||
if ($memCount == 0) {
|
|
||||||
$percentage = 100;
|
|
||||||
} else {
|
|
||||||
$percentage = round($voteCount / $memCount * 100, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
echo "
|
|
||||||
<tr>
|
|
||||||
<td align=center style=color:" . newColor($nation['color']) . "; bgcolor={$nation['color']}>{$nation['name']}</td>
|
|
||||||
<td align=center>{$voteCount} / {$memCount} ({$percentage} %)</td>
|
|
||||||
<td align=center>
|
|
||||||
";
|
|
||||||
|
|
||||||
$totalPer = 0;
|
|
||||||
for ($k = 0; $k < $voteTypeCount; $k++) {
|
|
||||||
if ($memCount == 0) {
|
|
||||||
$per = 0;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$per = round(($nationVote[$nation['nation']][$k] ?? 0) / $memCount * 100, 1);
|
|
||||||
|
|
||||||
if ($i == $voteTypeCount - 1) {
|
|
||||||
$per = 100 - $totalPer;
|
|
||||||
} else {
|
|
||||||
$totalPer += $per;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if($per < 5) { $vote['cnt'] = " "; }
|
|
||||||
?>
|
|
||||||
<?php if ($per == 0) : ?>
|
|
||||||
<?php elseif ($per < 10) : ?>
|
|
||||||
<div class='little_bar' style='width:<?= $per ?>%;color:<?= getNewColor($k) ?>;background-color:<?= getVoteColor($k) ?>;'></div>
|
|
||||||
<?php else : ?>
|
|
||||||
<div class='little_bar' style='width:<?= $per ?>%;color:<?= getNewColor($k) ?>;background-color:<?= getVoteColor($k) ?>;'><?= $nationVote[$nation['nation']][$k] ?? 0 ?></div>
|
|
||||||
<?php endif; ?>
|
|
||||||
<?php
|
|
||||||
}
|
|
||||||
|
|
||||||
echo "
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
</form>
|
|
||||||
</table>
|
|
||||||
<table align=center width=1000 class='tb_layout bg0'>
|
|
||||||
<tr>
|
|
||||||
<td><?= closeButton() ?></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><?= banner() ?> </td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
|
|
||||||
<?php
|
|
||||||
function getVoteColor($type)
|
|
||||||
{
|
|
||||||
if ($type > 0) {
|
|
||||||
$type = (($type - 1) % 7) + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch ($type) {
|
|
||||||
default:
|
|
||||||
case 0:
|
|
||||||
$color = "black";
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
$color = "red";
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
$color = "orange";
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
$color = "yellow";
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
$color = "green";
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
$color = "blue";
|
|
||||||
break;
|
|
||||||
case 6:
|
|
||||||
$color = "navy";
|
|
||||||
break;
|
|
||||||
case 7:
|
|
||||||
$color = "purple";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $color;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getNewColor($type)
|
|
||||||
{
|
|
||||||
if ($type > 0) {
|
|
||||||
$type = (($type - 1) % 7) + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch ($type) {
|
|
||||||
case 2:
|
|
||||||
$color = "black";
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
$color = "black";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
$color = "white";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $color;
|
|
||||||
}
|
|
||||||
@@ -1,306 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace sammo;
|
|
||||||
|
|
||||||
include "lib.php";
|
|
||||||
include "func.php";
|
|
||||||
|
|
||||||
$msg = Util::getReq('msg');
|
|
||||||
$msg2 = Util::getReq('msg2');
|
|
||||||
|
|
||||||
//로그인 검사
|
|
||||||
$session = Session::requireGameLogin()->setReadOnly();
|
|
||||||
$userID = Session::getUserID();
|
|
||||||
|
|
||||||
$db = DB::db();
|
|
||||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
|
||||||
|
|
||||||
increaseRefresh("거래장", 2);
|
|
||||||
|
|
||||||
$me = $db->queryFirstRow('SELECT no,special,con,turntime from general where owner=%i', $userID);
|
|
||||||
|
|
||||||
$con = checkLimit($me['con']);
|
|
||||||
if ($con >= 2) {
|
|
||||||
printLimitMsg($me['turntime']);
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
$tradeCount = $db->queryFirstField('SELECT count(no) FROM auction WHERE no1=%i', $me['no']);
|
|
||||||
$bidCount = $db->queryFirstField('SELECT count(no) FROM auction where no2=%i', $me['no']);
|
|
||||||
|
|
||||||
$btCount = $tradeCount + $bidCount;
|
|
||||||
|
|
||||||
if ($session->userGrade >= 5 || $btCount < 1) {
|
|
||||||
$btn = "submit";
|
|
||||||
} else {
|
|
||||||
$btn = "hidden";
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($msg == "") {
|
|
||||||
$msg = "-";
|
|
||||||
}
|
|
||||||
if ($msg2 == "") {
|
|
||||||
$msg2 = "-";
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<title><?= UniqueConst::$serverName ?>: 거래장</title>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
||||||
<meta name="viewport" content="width=1024" />
|
|
||||||
<?= WebUtil::printJS('../d_shared/common_path.js') ?>
|
|
||||||
<?= WebUtil::printCSS('../d_shared/common.css') ?>
|
|
||||||
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard/dist/web/static/pretendard.css" />
|
|
||||||
<?= WebUtil::printDist('ts', ['common']) ?>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<table align=center width=1000 class='tb_layout bg0'>
|
|
||||||
<tr>
|
|
||||||
<td>거 래 장<br><?= closeButton() ?></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align=center class='bg2'>
|
|
||||||
<font color=orange size=6><b>거 래 장</b></font><input type=button value='갱신' onclick="location.replace('b_auction.php')">
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<table align=center width=1000 class='tb_layout bg0'>
|
|
||||||
<form method=post action=c_auction.php>
|
|
||||||
<tr>
|
|
||||||
<td colspan=11 align=center bgcolor=orange>
|
|
||||||
<font size=5>팝 니 다</font>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr align=center class='bg1'>
|
|
||||||
<td width=68>거래번호</td>
|
|
||||||
<td width=48>선택</td>
|
|
||||||
<td width=98>판매자</td>
|
|
||||||
<td width=118>물품</td>
|
|
||||||
<td width=88>수량</td>
|
|
||||||
<td width=88>시작판매가</td>
|
|
||||||
<td width=88>현재판매가</td>
|
|
||||||
<td width=88>즉시판매가</td>
|
|
||||||
<td width=48>단가</td>
|
|
||||||
<td width=98>구매 예정자</td>
|
|
||||||
<td width=148>거래종료</td>
|
|
||||||
</tr>
|
|
||||||
<?php
|
|
||||||
$chk = 0;
|
|
||||||
foreach ($db->query('SELECT * from auction where type=0 order by expire') as $auction) {
|
|
||||||
$radio = "";
|
|
||||||
$alert = "";
|
|
||||||
$alert2 = "";
|
|
||||||
if ($auction['no1'] == $me['no']) {
|
|
||||||
$radio = " disabled";
|
|
||||||
} elseif ($auction['no2'] > 0 && $auction['amount'] * 2 <= $auction['value']) {
|
|
||||||
$radio = " disabled";
|
|
||||||
$alert = "<font color=red>";
|
|
||||||
$alert2 = "</font>";
|
|
||||||
} elseif ($auction['no2'] > 0 && $auction['topv'] <= $auction['value']) {
|
|
||||||
$radio = " disabled";
|
|
||||||
$alert = "<font color=red>";
|
|
||||||
$alert2 = "</font>";
|
|
||||||
} elseif ($chk == 0) {
|
|
||||||
$radio = " checked";
|
|
||||||
$chk = 1;
|
|
||||||
}
|
|
||||||
$pv = round($auction['value'] * 100 / $auction['amount']) / 100 + 0.001;
|
|
||||||
$pv = substr((string)$pv, 0, 4);
|
|
||||||
|
|
||||||
echo "
|
|
||||||
<tr align=center>
|
|
||||||
<td>{$auction['no']}</td>
|
|
||||||
<td><input type=radio name=sel value={$auction['no']}{$radio}></td>
|
|
||||||
<td>{$auction['name1']}</td>
|
|
||||||
<td>쌀</td>
|
|
||||||
<td>{$auction['amount']}</td>
|
|
||||||
<td>금 {$auction['cost']}</td>
|
|
||||||
<td>{$alert}금 {$auction['value']}{$alert2}</td>
|
|
||||||
<td>{$alert}금 {$auction['topv']}{$alert2}</td>
|
|
||||||
<td>{$alert}{$pv}{$alert2}</td>
|
|
||||||
<td>{$alert}{$auction['name2']}{$alert2}</td>
|
|
||||||
<td>{$auction['expire']}</td>
|
|
||||||
</tr>
|
|
||||||
";
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
<tr height=25>
|
|
||||||
<td align=center class='bg1'>등록결과</td>
|
|
||||||
<td colspan=10><?= ConvertLog($msg) ?></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align=center class='bg1'>입찰등록</td>
|
|
||||||
<td colspan=10>
|
|
||||||
지불할 금액: <input type=text style=color:white;background-color:black; size=6 maxlength=6 name=value>
|
|
||||||
<input type=<?= $btn ?> name=btn value='구매시도' onclick='return confirm("정말 입찰하시겠습니까?");'>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align=center class='bg1'>거래등록</td>
|
|
||||||
<td colspan=10>
|
|
||||||
종료: <input type=text style=color:white;background-color:black; size=2 maxlength=2 name=term value=12>턴 후
|
|
||||||
물품: 쌀
|
|
||||||
판매량: <input type=text style=color:white;background-color:black; size=5 maxlength=5 name=amount value=1000>
|
|
||||||
시작가: <input type=text style=color:white;background-color:black; size=5 maxlength=5 name=cost value=500>
|
|
||||||
즉구가: <input type=text style=color:white;background-color:black; size=5 maxlength=5 name=topv value=2000>
|
|
||||||
<input type=<?= $btn ?> name=btn value='판매' onclick='return confirm("정말 판매하시겠습니까?");'>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td colspan=11>
|
|
||||||
ㆍ<font color=cyan>Hint</font>) 거래자가 판매(물품 판매, 금 수령), 입찰자가 구매(물품 구입, 금 지불).<br>
|
|
||||||
ㆍ<font color=cyan>Hint</font>) 단가가 1.00보다 높을수록 판매자 유리.<br>
|
|
||||||
ㆍ<font color=cyan>Hint</font>) 단가가 1.00보다 낮을수록 입찰자 유리.<br>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</form>
|
|
||||||
</table>
|
|
||||||
<br>
|
|
||||||
<table align=center width=1000 class='tb_layout bg0'>
|
|
||||||
<form method=post action=c_auction.php>
|
|
||||||
<tr>
|
|
||||||
<td colspan=11 align=center bgcolor=skyblue>
|
|
||||||
<font size=5>삽 니 다</font>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr align=center class='bg1'>
|
|
||||||
<td width=68>거래번호</td>
|
|
||||||
<td width=48>선택</td>
|
|
||||||
<td width=98>구매자</td>
|
|
||||||
<td width=118>물품</td>
|
|
||||||
<td width=88>수량</td>
|
|
||||||
<td width=88>시작구매가</td>
|
|
||||||
<td width=88>현재구매가</td>
|
|
||||||
<td width=88>즉시구매가</td>
|
|
||||||
<td width=48>단가</td>
|
|
||||||
<td width=98>판매 예정자</td>
|
|
||||||
<td width=148>거래종료</td>
|
|
||||||
</tr>
|
|
||||||
<?php
|
|
||||||
$chk = 0;
|
|
||||||
foreach ($db->query('SELECT * from auction where type=1 order by expire') as $auction) {
|
|
||||||
$radio = "";
|
|
||||||
$alert = "";
|
|
||||||
$alert2 = "";
|
|
||||||
if ($auction['no1'] == $me['no']) {
|
|
||||||
$radio = " disabled";
|
|
||||||
} elseif ($auction['no2'] > 0 && $auction['amount'] >= $auction['value'] * 2) {
|
|
||||||
$radio = " disabled";
|
|
||||||
$alert = "<font color=red>";
|
|
||||||
$alert2 = "</font>";
|
|
||||||
} elseif ($auction['no2'] > 0 && $auction['topv'] >= $auction['value']) {
|
|
||||||
$radio = " disabled";
|
|
||||||
$alert = "<font color=red>";
|
|
||||||
$alert2 = "</font>";
|
|
||||||
} elseif ($chk == 0) {
|
|
||||||
$radio = " checked";
|
|
||||||
$chk = 1;
|
|
||||||
}
|
|
||||||
$pv = round($auction['value'] * 100 / $auction['amount']) / 100 + 0.001;
|
|
||||||
$pv = substr((string)$pv, 0, 4);
|
|
||||||
echo "
|
|
||||||
<tr align=center>
|
|
||||||
<td>{$auction['no']}</td>
|
|
||||||
<td><input type=radio name=sel value={$auction['no']}{$radio}></td>
|
|
||||||
<td>{$auction['name1']}</td>
|
|
||||||
<td>쌀</td>
|
|
||||||
<td>{$auction['amount']}</td>
|
|
||||||
<td>금 {$auction['cost']}</td>
|
|
||||||
<td>{$alert}금 {$auction['value']}{$alert2}</td>
|
|
||||||
<td>{$alert}금 {$auction['topv']}{$alert2}</td>
|
|
||||||
<td>{$alert}{$pv}{$alert2}</td>
|
|
||||||
<td>{$alert}{$auction['name2']}{$alert2}</td>
|
|
||||||
<td>{$auction['expire']}</td>
|
|
||||||
</tr>
|
|
||||||
";
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
<tr height=25>
|
|
||||||
<td align=center class='bg1'>등록결과</td>
|
|
||||||
<td colspan=10><?= ConvertLog($msg2) ?></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align=center class='bg1'>입찰등록</td>
|
|
||||||
<td colspan=10>
|
|
||||||
수령할 금액: <input type=text style=color:white;background-color:black; size=6 maxlength=6 name=value>
|
|
||||||
<input type=<?= $btn ?> name=btn value='판매시도' onclick='return confirm("정말 입찰하시겠습니까?");'>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align=center class='bg1'>거래등록</td>
|
|
||||||
<td colspan=10>
|
|
||||||
종료: <input type=text style=color:white;background-color:black; size=2 maxlength=2 name=term value=12>턴 후
|
|
||||||
물품: 쌀
|
|
||||||
구입량: <input type=text style=color:white;background-color:black; size=5 maxlength=5 name=amount value=1000>
|
|
||||||
시작가: <input type=text style=color:white;background-color:black; size=5 maxlength=5 name=cost value=2000>
|
|
||||||
즉구가: <input type=text style=color:white;background-color:black; size=5 maxlength=5 name=topv value=500>
|
|
||||||
<input type=<?= $btn ?> name=btn value='구매' onclick='return confirm("정말 구매하시겠습니까?");'>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td colspan=11>
|
|
||||||
ㆍ<font color=cyan>Hint</font>) 거래자가 구매(물품 구매, 금 지불), 입찰자가 판매(물품 판매, 금 수령).<br>
|
|
||||||
ㆍ<font color=cyan>Hint</font>) 단가가 1.00보다 낮을수록 구매자 유리.<br>
|
|
||||||
ㆍ<font color=cyan>Hint</font>) 단가가 1.00보다 높을수록 입찰자 유리.<br>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</form>
|
|
||||||
</table>
|
|
||||||
<br>
|
|
||||||
<table align=center width=1000 class='tb_layout bg0'>
|
|
||||||
<tr>
|
|
||||||
<td align=center class='bg2'>
|
|
||||||
<font size=5>최 근 기 록</font>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<?= getAuctionLogRecent(20) ?>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align=center class='bg2'>
|
|
||||||
<font size=5>도 움 말</font>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<font color=white size=2>
|
|
||||||
ㆍ판매거래는 거래자가 판매할 물품을 거래하면, 구입을 희망하는 사람이 현재가보다 높게 입찰하여 구입하는 방식입니다.<br>
|
|
||||||
ㆍ<font color=cyan>Hint</font>) 쌀이 귀한 경우는 입찰자가 많아서 자연스레 단가가 오르게 됩니다. (해당 물품을 사려는 가격이 오름)<br>
|
|
||||||
ㆍ<font color=cyan>Hint</font>) 쌀이 흔한 경우는 초기 가격을 낮게 책정해야 판매가 가능할 겁니다.<br>
|
|
||||||
ㆍ구매거래는 거래자가 구입할 물품을 거래하면, 판매를 희망하는 사람이 현재가보다 낮게 입찰하여 판매하는 방식입니다.<br>
|
|
||||||
ㆍ<font color=cyan>Hint</font>) 쌀이 흔한 경우는 입찰자가 많아서 자연스레 단가가 내리게 됩니다. (해당 물품을 팔려는 가격이 내림)<br>
|
|
||||||
ㆍ<font color=cyan>Hint</font>) 쌀이 귀한 경우는 초기 가격을 높게 책정해야 구입이 가능할 겁니다.<br>
|
|
||||||
ㆍ마감임박때 입찰하는 경우 입찰후 1턴 후로 종료시간이 연장됩니다.<br>
|
|
||||||
ㆍ즉시구매가로 입찰하는 경우 입찰후 1턴 후로 종료시간이 결정됩니다.<br>
|
|
||||||
ㆍ악용 방지를 위해 50% ~ 200%의 가격에서 거래시작이 가능합니다.<br>
|
|
||||||
ㆍ악용 방지를 위해 즉시판매가는 110% 이상, 즉시구매가는 90% 이하의 시세로 가능합니다.<br>
|
|
||||||
ㆍ악용 방지를 위해 즉시판매가는 시작판매가의 110% 이상, 즉시구매가는 시작구매가의 90% 이하로 가능합니다.<br>
|
|
||||||
ㆍ1인당 도합 1건의 거래와 입찰이 가능합니다.<br>
|
|
||||||
ㆍ기본금쌀 1000은 거래에 사용되지 못합니다.<br>
|
|
||||||
ㆍ유찰될 때는 거래 과실자에게 거래금의 1%가 벌금으로 부과됩니다.<br>
|
|
||||||
ㆍ<font color=magenta>10단위로 거래가 가능합니다. 1자리는 반올림 처리 됩니다.</font><br>
|
|
||||||
ㆍ<font color=red>★ 최고가 거래 ★</font> 혹은 <font color=red>★ 최저가 거래 ★</font> 는 암거래 및 악용의 가능성이니 감시 부탁드립니다.<br>
|
|
||||||
ㆍ거래와 입찰은 취소가 불가능하니 주의하세요!<br>
|
|
||||||
ㆍ<font color=cyan>Hint</font>) 단가는 금/쌀로 쌀1을 거래하기 위한 금의 양입니다.<br>
|
|
||||||
ㆍ<font color=cyan>Hint</font>) 단가가 높으면(>1.00) 쌀이 비싸므로 판매가 이득입니다.<br>
|
|
||||||
ㆍ<font color=cyan>Hint</font>) 단가가 낮으면(<1.00) 금이 비싸므로 구매가 이득입니다.<br>
|
|
||||||
ㆍ즐거운 거래!
|
|
||||||
</font>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><?= closeButton() ?></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><?= banner() ?> </td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
@@ -197,7 +197,7 @@ $showGeneral = General::createGeneralObjFromDB($gen);
|
|||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
<div class="row gx-0">
|
<div class="row gx-0">
|
||||||
<div class="col "><?= backButton() ?></div>
|
<div class="col "><?= closeButton() ?></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row bg0 gx-0">
|
<div class="row bg0 gx-0">
|
||||||
<div class="col bg0"><?= banner() ?></div>
|
<div class="col bg0"><?= banner() ?></div>
|
||||||
|
|||||||
+47
-48
@@ -25,6 +25,17 @@ if ($meLevel == 0) {
|
|||||||
|
|
||||||
$nation = $db->queryFirstRow('SELECT nation,name,level,color,chief_set from nation where nation=%i', $nationID); //국가정보
|
$nation = $db->queryFirstRow('SELECT nation,name,level,color,chief_set from nation where nation=%i', $nationID); //국가정보
|
||||||
|
|
||||||
|
if ($meLevel >= 5) {
|
||||||
|
$candidateStrength = $db->query('SELECT no,name,officer_level,city,npc from general where nation=%i and officer_level!=12 and strength>=%i order by npc,binary(name)', $nationID, GameConst::$chiefStatMin);
|
||||||
|
$candidateIntel = $db->query('SELECT no,name,officer_level,city,npc from general where nation=%i and officer_level!=12 and intel>=%i order by npc,binary(name)', $nationID, GameConst::$chiefStatMin);
|
||||||
|
$candidateAny = $db->query('SELECT no,name,officer_level,city,npc,leadership,strength,intel,killturn from general where nation=%i and officer_level!=12 order by npc,binary(name)', $nationID); //추방 때문에 조금 더 김
|
||||||
|
} else {
|
||||||
|
$candidateStrength = [];
|
||||||
|
$candidateIntel = [];
|
||||||
|
$candidateAny = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
?>
|
?>
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
@@ -180,61 +191,21 @@ $nation = $db->queryFirstRow('SELECT nation,name,level,color,chief_set from nati
|
|||||||
<td colspan=5><?= $eaglestr ?></td>
|
<td colspan=5><?= $eaglestr ?></td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<table align=center width=1000 class='tb_layout bg0'>
|
<table align=center width=1000 class='tb_layout bg0'>
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan=6 height=5></td>
|
<td colspan=4 height=5></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan=2 align=center bgcolor=red>추 방</td>
|
<td colspan=4 align=center bgcolor=blue>수 뇌 부 임 명</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td width=498 align=right class='bg1'>대상 장수</td>
|
<?php $officerLevelText = getOfficerLevelText(11, $nation['level']); ?>
|
||||||
<td width=498>
|
<td width=98 align=right class='bg1'><?= getOfficerLevelText(12, $nation['level']) ?></td>
|
||||||
|
<td width=398><?= $level[12]['name'] ?> 【<?= CityConst::byID($level[12]['city'])->name ?>】</td>
|
||||||
|
<td width=98 align=right class='bg1'><?= $officerLevelText ?></td>
|
||||||
|
<td width=398>
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
if ($meLevel >= 5) {
|
|
||||||
$candidateStrength = $db->query('SELECT no,name,officer_level,city,npc from general where nation=%i and officer_level!=12 and strength>=%i order by npc,binary(name)', $nationID, GameConst::$chiefStatMin);
|
|
||||||
$candidateIntel = $db->query('SELECT no,name,officer_level,city,npc from general where nation=%i and officer_level!=12 and intel>=%i order by npc,binary(name)', $nationID, GameConst::$chiefStatMin);
|
|
||||||
$candidateAny = $db->query('SELECT no,name,officer_level,city,npc,leadership,strength,intel,killturn from general where nation=%i and officer_level!=12 order by npc,binary(name)', $nationID); //추방 때문에 조금 더 김
|
|
||||||
} else {
|
|
||||||
$candidateStrength = [];
|
|
||||||
$candidateIntel = [];
|
|
||||||
$candidateAny = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if ($meLevel >= 5 && !isOfficerSet($nation['chief_set'], $meLevel)) {
|
|
||||||
echo "
|
|
||||||
<select id='genlist_kick' size=1 style=color:white;background-color:black;>";
|
|
||||||
|
|
||||||
foreach ($candidateAny as $general) {
|
|
||||||
if ($general['no'] === $me['no']) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
echo "
|
|
||||||
<option data-officer_level='{$general['officer_level']}' data-name='{$general['name']}' value={$general['no']}>{$general['name']} <small>({$general['leadership']}/{$general['strength']}/{$general['intel']}, {$general['killturn']}턴)</small></option>";
|
|
||||||
}
|
|
||||||
|
|
||||||
echo "
|
|
||||||
</select>
|
|
||||||
<input type=$btn id='btn_kick' value=추방>";
|
|
||||||
}
|
|
||||||
|
|
||||||
$officerLevelText = getOfficerLevelText(11, $nation['level']);
|
|
||||||
echo "
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<table align=center width=1000 class='tb_layout bg0'>
|
|
||||||
<tr><td colspan=4 height=5></td></tr>
|
|
||||||
<tr><td colspan=4 align=center bgcolor=blue>수 뇌 부 임 명</td></tr>
|
|
||||||
<tr>
|
|
||||||
<td width=98 align=right class='bg1'>" . getOfficerLevelText(12, $nation['level']) . "</td>
|
|
||||||
<td width=398>{$level[12]['name']} 【" . CityConst::byID($level[12]['city'])->name . "】</td>
|
|
||||||
<td width=98 align=right class='bg1'>{$officerLevelText}</td>
|
|
||||||
<td width=398>
|
|
||||||
";
|
|
||||||
|
|
||||||
if ($meLevel >= 5 && !isOfficerSet($nation['chief_set'], 11)) {
|
if ($meLevel >= 5 && !isOfficerSet($nation['chief_set'], 11)) {
|
||||||
echo "
|
echo "
|
||||||
<select id='genlist_11' size=1 maxlength=15 style=color:white;background-color:black;>
|
<select id='genlist_11' size=1 maxlength=15 style=color:white;background-color:black;>
|
||||||
@@ -553,6 +524,34 @@ $nation = $db->queryFirstRow('SELECT nation,name,level,color,chief_set from nati
|
|||||||
<td colspan=5>※ <font color=orange>노란색</font>은 변경 불가능, 하얀색은 변경 가능 관직입니다.</td>
|
<td colspan=5>※ <font color=orange>노란색</font>은 변경 불가능, 하얀색은 변경 가능 관직입니다.</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
<table align=center width=1000 class='tb_layout bg0'>
|
||||||
|
<tr>
|
||||||
|
<td colspan=6 height=5></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan=2 align=center bgcolor=red>추 방</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width=498 align=right class='bg1'>대상 장수</td>
|
||||||
|
<td width=498>
|
||||||
|
<?php
|
||||||
|
if ($meLevel >= 5 && !isOfficerSet($nation['chief_set'], $meLevel)) : ?>
|
||||||
|
|
||||||
|
<select id='genlist_kick' size=1 style=color:white;background-color:black;>";
|
||||||
|
|
||||||
|
<?php foreach ($candidateAny as $general) : ?>
|
||||||
|
<?php if ($general['no'] === $me['no']) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<option data-officer_level='<?= $general['officer_level'] ?>' data-name='<?= $general['name'] ?>' value='<?= $general['no'] ?>'><?= $general['name'] ?> <small>(<?= $general['leadership'] ?>/<?= $general['strength'] ?>/<?= $general['intel'] ?>, <?= $general['killturn'] ?>턴)</small></option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
|
<input type=<?= $btn ?> id='btn_kick' value=추방>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
<br>
|
<br>
|
||||||
<table align=center width=1000 class='tb_layout bg0'>
|
<table align=center width=1000 class='tb_layout bg0'>
|
||||||
<tr>
|
<tr>
|
||||||
|
|||||||
@@ -1,247 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace sammo;
|
|
||||||
|
|
||||||
include "lib.php";
|
|
||||||
include "func.php";
|
|
||||||
|
|
||||||
$v = new Validator($_POST + $_GET);
|
|
||||||
$v->rule('integer', [
|
|
||||||
'amount',
|
|
||||||
'cost',
|
|
||||||
'topv',
|
|
||||||
'value',
|
|
||||||
'term',
|
|
||||||
'sel'
|
|
||||||
]);
|
|
||||||
|
|
||||||
$btn = Util::getPost('btn');
|
|
||||||
$amount = Util::getPost('amount', 'int');
|
|
||||||
$cost = Util::getPost('cost', 'int');
|
|
||||||
$topv = Util::getPost('topv', 'int');
|
|
||||||
$value = Util::getPost('value', 'int');
|
|
||||||
$term = Util::getPost('term', 'int');
|
|
||||||
$sel = Util::getPost('sel', 'int');
|
|
||||||
|
|
||||||
$msg = '';
|
|
||||||
$msg2 = '';
|
|
||||||
|
|
||||||
|
|
||||||
//로그인 검사
|
|
||||||
$session = Session::requireGameLogin()->setReadOnly();
|
|
||||||
$userID = Session::getUserID();
|
|
||||||
|
|
||||||
$db = DB::db();
|
|
||||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
|
||||||
|
|
||||||
increaseRefresh("입찰", 1);
|
|
||||||
|
|
||||||
$turnterm = $gameStor->turnterm;
|
|
||||||
|
|
||||||
$me = $db->queryFirstRow('SELECT no,name,gold,rice,special from general where owner=%i', $userID);
|
|
||||||
|
|
||||||
$tradeCount = $db->queryFirstField('SELECT count(no) FROM auction WHERE no1=%i', $me['no']);
|
|
||||||
$bidCount = $db->queryFirstField('SELECT count(no) FROM auction WHERE no2=%i', $me['no']);
|
|
||||||
|
|
||||||
$btCount = $tradeCount + $bidCount;
|
|
||||||
|
|
||||||
$unit = $turnterm * 60;
|
|
||||||
|
|
||||||
$amount = Util::round($amount, -1);
|
|
||||||
$cost = Util::round($cost, -1);
|
|
||||||
$topv = Util::round($topv, -1);
|
|
||||||
$value = Util::round($value, -1);
|
|
||||||
if ($term > 24) {
|
|
||||||
$term = 24;
|
|
||||||
}
|
|
||||||
|
|
||||||
$valid = 1;
|
|
||||||
if ($session->userGrade >= 5 || $btCount < 1) {
|
|
||||||
} else {
|
|
||||||
$msg = "ㆍ<span class='ev_warning'>더이상 등록할 수 없습니다.</span>";
|
|
||||||
$msg2 = "ㆍ<span class='ev_warning'>더이상 등록할 수 없습니다.</span>";
|
|
||||||
$valid = 0;
|
|
||||||
$btn = "hidden";
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($btn == "판매") {
|
|
||||||
if ($term < 0 || $term > 24) {
|
|
||||||
$msg = "ㆍ<span class='ev_warning'>종료기한은 1 ~ 24 턴 이어야 합니다.</span>";
|
|
||||||
$valid = 0;
|
|
||||||
}
|
|
||||||
if ($amount < 100 || $amount > 10000) {
|
|
||||||
$msg = "ㆍ<span class='ev_warning'>거래량은 100 ~ 10000 이어야 합니다.</span>";
|
|
||||||
$valid = 0;
|
|
||||||
}
|
|
||||||
if ($cost > $amount * 2 || $cost * 2 < $amount) {
|
|
||||||
$msg = "ㆍ<span class='ev_warning'>시작판매가는 50% ~ 200% 이어야 합니다.</span>";
|
|
||||||
$valid = 0;
|
|
||||||
}
|
|
||||||
if ($topv * 10 < $amount * 11 || $topv > $amount * 2) {
|
|
||||||
$msg = "ㆍ<span class='ev_warning'>즉시판매가는 110% ~ 200% 이어야 합니다.</span>";
|
|
||||||
$valid = 0;
|
|
||||||
}
|
|
||||||
if ($topv * 10 < $cost * 11) {
|
|
||||||
$msg = "ㆍ<span class='ev_warning'>즉시판매가는 시작판매가의 110% 이상이어야 합니다.</span>";
|
|
||||||
$valid = 0;
|
|
||||||
}
|
|
||||||
if ($amount > $me['rice'] - GameConst::$defaultRice) {
|
|
||||||
$msg = "ㆍ<span class='ev_warning'>기본 군량 ".GameConst::$defaultRice."은 거래할 수 없습니다.</span>";
|
|
||||||
$valid = 0;
|
|
||||||
}
|
|
||||||
if ($valid == 1) {
|
|
||||||
$msg = "ㆍ<span class='ev_success'>등록 성공.</span>";
|
|
||||||
$date = date("Y-m-d H:i:s", strtotime(date("Y-m-d H:i:s")) + $unit * $term);
|
|
||||||
$db->insert('auction', [
|
|
||||||
'type'=>0,
|
|
||||||
'no1'=>$me['no'],
|
|
||||||
'name1'=>$me['name'],
|
|
||||||
'amount'=>$amount,
|
|
||||||
'cost'=>$cost,
|
|
||||||
'value'=>$cost,
|
|
||||||
'topv'=>$topv,
|
|
||||||
'expire'=>$date
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
} elseif ($btn == "구매시도") {
|
|
||||||
$auction = $db->queryFirstRow('SELECT no2,value,topv,expire,amount FROM auction WHERE no=%i LIMIT 1', $sel);
|
|
||||||
|
|
||||||
if ($value == $auction['topv']) {
|
|
||||||
$valid = 2;
|
|
||||||
}
|
|
||||||
if (!$auction) {
|
|
||||||
$msg = "ㆍ<span class='ev_warning'>종료된 거래입니다.</span>";
|
|
||||||
$valid = 0;
|
|
||||||
}
|
|
||||||
if ($auction['no2'] > 0 && $value <= $auction['value']) {
|
|
||||||
$msg = "ㆍ<span class='ev_warning'>현재판매가보다 높게 입찰해야 합니다.</span>";
|
|
||||||
$valid = 0;
|
|
||||||
}
|
|
||||||
if ($value < $auction['value']) {
|
|
||||||
$msg = "ㆍ<span class='ev_warning'>현재판매가보다 높게 입찰해야 합니다.</span>";
|
|
||||||
$valid = 0;
|
|
||||||
}
|
|
||||||
if ($value > $auction['topv']) {
|
|
||||||
$msg = "ㆍ<span class='ev_warning'>즉시판매가보다 높을 수 없습니다.</span>";
|
|
||||||
$valid = 0;
|
|
||||||
}
|
|
||||||
if ($value > $me['gold'] - GameConst::$defaultGold) {
|
|
||||||
$msg = "ㆍ<span class='ev_warning'>기본 자금 ".GameConst::$defaultGold."은 거래할 수 없습니다.</span>";
|
|
||||||
$valid = 0;
|
|
||||||
}
|
|
||||||
if ($valid == 1) {
|
|
||||||
$msg = "ㆍ<span class='ev_success'>입찰 성공.</span> 거래완료는 빨라도 현재로부터 1턴 뒤입니다.";
|
|
||||||
$date = date("Y-m-d H:i:s", strtotime(date("Y-m-d H:i:s")) + $unit);
|
|
||||||
if ($auction['expire'] > $date) {
|
|
||||||
$date = $auction['expire'];
|
|
||||||
}
|
|
||||||
|
|
||||||
$db->update('auction', [
|
|
||||||
'value'=>$value,
|
|
||||||
'no2'=>$me['no'],
|
|
||||||
'name2'=>$me['name'],
|
|
||||||
'expire'=>$date,
|
|
||||||
], 'no=%i', $sel);
|
|
||||||
} elseif ($valid == 2) {
|
|
||||||
$msg = "ㆍ<span class='ev_success'>즉시판매 성공.</span> 거래완료는 빨라도 현재로부터 1턴 뒤입니다.";
|
|
||||||
$date = date("Y-m-d H:i:s", strtotime(date("Y-m-d H:i:s")) + $unit);
|
|
||||||
|
|
||||||
$db->update('auction', [
|
|
||||||
'value'=>$value,
|
|
||||||
'no2'=>$me['no'],
|
|
||||||
'name2'=>$me['name'],
|
|
||||||
'expire'=>$date,
|
|
||||||
], 'no=%i', $sel);
|
|
||||||
}
|
|
||||||
} elseif ($btn == "구매") {
|
|
||||||
if ($term < 0 || $term > 24) {
|
|
||||||
$msg2 = "ㆍ<span class='ev_warning'>종료기한은 1 ~ 24 턴 이어야 합니다.</span>";
|
|
||||||
$valid = 0;
|
|
||||||
}
|
|
||||||
if ($amount < 100 || $amount > 10000) {
|
|
||||||
$msg2 = "ㆍ<span class='ev_warning'>거래량은 100 ~ 10000 이어야 합니다.</span>";
|
|
||||||
$valid = 0;
|
|
||||||
}
|
|
||||||
if ($cost > $amount * 2 || $cost * 2 < $amount) {
|
|
||||||
$msg2 = "ㆍ<span class='ev_warning'>시작구매가는 50% ~ 200% 이어야 합니다.</span>";
|
|
||||||
$valid = 0;
|
|
||||||
}
|
|
||||||
if ($topv < $amount * 0.5 || $topv > $amount * 0.9) {
|
|
||||||
$msg2 = "ㆍ<span class='ev_warning'>즉시구매가는 50% ~ 90% 이어야 합니다.</span>";
|
|
||||||
$valid = 0;
|
|
||||||
}
|
|
||||||
if ($topv > $cost * 0.9) {
|
|
||||||
$msg2 = "ㆍ<span class='ev_warning'>즉시구매가는 시작구매가의 90% 이하이어야 합니다.</span>";
|
|
||||||
$valid = 0;
|
|
||||||
}
|
|
||||||
if ($cost > $me['gold'] - GameConst::$defaultGold) {
|
|
||||||
$msg2 = "ㆍ<span class='ev_warning'>기본 자금 ".GameConst::$defaultGold."은 거래할 수 없습니다.</span>";
|
|
||||||
$valid = 0;
|
|
||||||
}
|
|
||||||
if ($valid == 1) {
|
|
||||||
$msg2 = "ㆍ<span class='ev_success'>등록 성공.</span>";
|
|
||||||
$date = date("Y-m-d H:i:s", strtotime(date("Y-m-d H:i:s")) + $unit * $term);
|
|
||||||
|
|
||||||
$db->insert('auction', [
|
|
||||||
'type'=>1,
|
|
||||||
'no1'=>$me['no'],
|
|
||||||
'name1'=>$me['name'],
|
|
||||||
'amount'=>$amount,
|
|
||||||
'cost'=>$cost,
|
|
||||||
'value'=>$cost,
|
|
||||||
'topv'=>$topv,
|
|
||||||
'expire'=>$date
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
} elseif ($btn == "판매시도") {
|
|
||||||
$auction = $db->queryFirstRow('SELECT no2,value,topv,expire,amount FROM auction WHERE no=%i LIMIT 1', $sel);
|
|
||||||
|
|
||||||
if ($value == $auction['topv']) {
|
|
||||||
$valid = 2;
|
|
||||||
}
|
|
||||||
if (!$auction) {
|
|
||||||
$msg2 = "ㆍ<span class='ev_warning'>종료된 거래입니다.</span>";
|
|
||||||
$valid = 0;
|
|
||||||
}
|
|
||||||
if ($auction['no2'] > 0 && $value >= $auction['value']) {
|
|
||||||
$msg2 = "ㆍ<span class='ev_warning'>현재구매가보다 낮게 입찰해야 합니다.</span>";
|
|
||||||
$valid = 0;
|
|
||||||
}
|
|
||||||
if ($value > $auction['value']) {
|
|
||||||
$msg2 = "ㆍ<span class='ev_warning'>현재구매가보다 낮게 입찰해야 합니다.</span>";
|
|
||||||
$valid = 0;
|
|
||||||
}
|
|
||||||
if ($value < $auction['topv']) {
|
|
||||||
$msg2 = "ㆍ<span class='ev_warning'>즉시구매가보다 낮을 수 없습니다.</span>";
|
|
||||||
$valid = 0;
|
|
||||||
}
|
|
||||||
if ($value > $me['rice'] - GameConst::$defaultRice) {
|
|
||||||
$msg2 = "ㆍ<span class='ev_warning'>기본 군량 ".GameConst::$defaultRice."은 거래할 수 없습니다.</span>";
|
|
||||||
$valid = 0;
|
|
||||||
}
|
|
||||||
if ($valid == 1) {
|
|
||||||
$msg2 = "ㆍ<span class='ev_success'>입찰 성공.</span> 거래완료는 빨라도 현재로부터 1턴 뒤입니다.";
|
|
||||||
$date = date("Y-m-d H:i:s", strtotime(date("Y-m-d H:i:s")) + $unit);
|
|
||||||
if ($auction['expire'] > $date) {
|
|
||||||
$date = $auction['expire'];
|
|
||||||
}
|
|
||||||
|
|
||||||
$db->update('auction', [
|
|
||||||
'value'=>$value,
|
|
||||||
'no2'=>$me['no'],
|
|
||||||
'name2'=>$me['name'],
|
|
||||||
'expire'=>$date,
|
|
||||||
], 'no=%i', $sel);
|
|
||||||
} elseif ($valid == 2) {
|
|
||||||
$msg2 = "ㆍ<span class='ev_success'>즉시구매 성공.</span> 거래완료는 빨라도 현재로부터 1턴 뒤입니다.";
|
|
||||||
$date = date("Y-m-d H:i:s", strtotime(date("Y-m-d H:i:s")) + $unit);
|
|
||||||
|
|
||||||
$db->update('auction', [
|
|
||||||
'value'=>$value,
|
|
||||||
'no2'=>$me['no'],
|
|
||||||
'name2'=>$me['name'],
|
|
||||||
'expire'=>$date,
|
|
||||||
], 'no=%i', $sel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Submit("b_auction.php", $msg, $msg2);
|
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace sammo;
|
|
||||||
|
|
||||||
include "lib.php";
|
|
||||||
include "func.php";
|
|
||||||
|
|
||||||
$btn = Util::getPost('btn');
|
|
||||||
$sel = Util::getPost('sel', 'int');
|
|
||||||
$comment = Util::getPost('comment');
|
|
||||||
$title = Util::getPost('title');
|
|
||||||
$str = Util::getPost('str');
|
|
||||||
|
|
||||||
//로그인 검사
|
|
||||||
$session = Session::requireGameLogin()->setReadOnly();
|
|
||||||
$userID = Session::getUserID();
|
|
||||||
|
|
||||||
$isVoteAdmin = in_array('vote', $session->acl[DB::prefix()]??[]);
|
|
||||||
$isVoteAdmin = $isVoteAdmin || $session->userGrade >= 5;
|
|
||||||
|
|
||||||
$db = DB::db();
|
|
||||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
|
||||||
|
|
||||||
$admin = $gameStor->getValues(['develcost', 'cost', 'vote_title', 'vote', 'votecomment']);
|
|
||||||
|
|
||||||
$generalID = Session::getGeneralID();
|
|
||||||
|
|
||||||
$general = General::createGeneralObjFromDB($generalID, ['vote','horse','weapon','book','item','npc','imgsvr','picture','aux'], 2);
|
|
||||||
|
|
||||||
if($btn == "투표" && $general->getVar('vote') == 0 && $sel > 0) {
|
|
||||||
$develcost = $admin['develcost'] * 5;
|
|
||||||
$db->update('general', [
|
|
||||||
'gold'=>$db->sqleval('gold + %i', $develcost),
|
|
||||||
'vote'=>$sel
|
|
||||||
], 'owner=%i', $userID);
|
|
||||||
|
|
||||||
if(tryUniqueItemLottery($general, '설문조사')){
|
|
||||||
$general->applyDB($db);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if($btn == "댓글" && trim($comment) != "") {
|
|
||||||
$comment = StringUtil::neutralize($comment);
|
|
||||||
|
|
||||||
$nation = $general->getStaticNation();
|
|
||||||
|
|
||||||
if(!$admin['votecomment']){
|
|
||||||
$admin['votecomment'] = [];
|
|
||||||
}
|
|
||||||
$admin['votecomment'][] = [$nation['name'],$general->getName(),$comment];
|
|
||||||
$gameStor->votecomment = $admin['votecomment'];
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!$isVoteAdmin){
|
|
||||||
header('location:a_vote.php', true, 303);
|
|
||||||
die();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if($btn == "수정") {
|
|
||||||
if($title != "") {
|
|
||||||
$gameStor->vote_title = WebUtil::htmlPurify($title);
|
|
||||||
}
|
|
||||||
} elseif($btn == "추가") {
|
|
||||||
if($str != "") {
|
|
||||||
if(!$admin['vote']){
|
|
||||||
$admin['vote'] = [];
|
|
||||||
}
|
|
||||||
$admin['vote'][] = WebUtil::htmlPurify($str);
|
|
||||||
$gameStor->vote=$admin['vote'];
|
|
||||||
}
|
|
||||||
} elseif($btn == "리셋") {
|
|
||||||
$gameStor->voteopen=1;
|
|
||||||
$gameStor->vote=['-'];
|
|
||||||
$gameStor->vote_title = '-';
|
|
||||||
$gameStor->votecomment=[];
|
|
||||||
|
|
||||||
$db->update('general', [
|
|
||||||
'vote'=>0
|
|
||||||
], true);
|
|
||||||
} elseif($btn == "알림") {
|
|
||||||
$db->update('general', [
|
|
||||||
'newvote'=>1
|
|
||||||
], 'vote=0');
|
|
||||||
} elseif($btn == "숨김") {
|
|
||||||
$gameStor->voteopen = 0;
|
|
||||||
} elseif($btn == "전체통계만") {
|
|
||||||
$gameStor->voteopen = 1;
|
|
||||||
} elseif($btn == "전부") {
|
|
||||||
$gameStor->voteopen = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
header('location:a_vote.php', true, 303);
|
|
||||||
@@ -5,6 +5,7 @@ class UniqueConst{
|
|||||||
public static $serverID = '_tK_serverID_';
|
public static $serverID = '_tK_serverID_';
|
||||||
public static $serverName = '_tK_serverName_';
|
public static $serverName = '_tK_serverName_';
|
||||||
public static $seasonIdx = '_tK_seasonIdx_';
|
public static $seasonIdx = '_tK_seasonIdx_';
|
||||||
|
public static $hiddenSeed = '_tK_hiddenSeed_';
|
||||||
|
|
||||||
private function __construct(){}
|
private function __construct(){}
|
||||||
|
|
||||||
|
|||||||
+61
-242
@@ -3,6 +3,8 @@
|
|||||||
namespace sammo;
|
namespace sammo;
|
||||||
|
|
||||||
use DateTime;
|
use DateTime;
|
||||||
|
use Ds\Set;
|
||||||
|
use sammo\Enums\AuctionType;
|
||||||
use sammo\Enums\InheritanceKey;
|
use sammo\Enums\InheritanceKey;
|
||||||
use sammo\Enums\RankColumn;
|
use sammo\Enums\RankColumn;
|
||||||
use sammo\Event\Action;
|
use sammo\Event\Action;
|
||||||
@@ -135,11 +137,11 @@ function getBlockLevel()
|
|||||||
return DB::db()->queryFirstField('select block from general where no = %i', Session::getInstance()->generalID);
|
return DB::db()->queryFirstField('select block from general where no = %i', Session::getInstance()->generalID);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRandGenName()
|
function getRandGenName(RandUtil $rng)
|
||||||
{
|
{
|
||||||
$firstname = Util::choiceRandom(GameConst::$randGenFirstName);
|
$firstname = $rng->choice(GameConst::$randGenFirstName);
|
||||||
$middlename = Util::choiceRandom(GameConst::$randGenMiddleName);
|
$middlename = $rng->choice(GameConst::$randGenMiddleName);
|
||||||
$lastname = Util::choiceRandom(GameConst::$randGenLastName);
|
$lastname = $rng->choice(GameConst::$randGenLastName);
|
||||||
|
|
||||||
return "{$firstname}{$middlename}{$lastname}";
|
return "{$firstname}{$middlename}{$lastname}";
|
||||||
}
|
}
|
||||||
@@ -1204,9 +1206,9 @@ function checkDelay()
|
|||||||
$db->update('general', [
|
$db->update('general', [
|
||||||
'turntime' => $db->sqleval('DATE_ADD(turntime, INTERVAL %i MINUTE)', $minute)
|
'turntime' => $db->sqleval('DATE_ADD(turntime, INTERVAL %i MINUTE)', $minute)
|
||||||
], 'turntime<=DATE_ADD(turntime, INTERVAL %i MINUTE)', $term);
|
], 'turntime<=DATE_ADD(turntime, INTERVAL %i MINUTE)', $term);
|
||||||
$db->update('auction', [
|
$db->update('ng_auction', [
|
||||||
'expire' => $db->sqleval('DATE_ADD(expire, INTERVAL %i MINUTE)', $minute)
|
'close_date' => $db->sqleval('DATE_ADD(close_date, INTERVAL %i MINUTE)', $minute)
|
||||||
], true);
|
], 'finished = 0');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1247,7 +1249,7 @@ function updateOnline()
|
|||||||
$gameStor->online_nation = join(', ', $onlineNation);
|
$gameStor->online_nation = join(', ', $onlineNation);
|
||||||
}
|
}
|
||||||
|
|
||||||
function addAge()
|
function addAge(RandUtil $rng)
|
||||||
{
|
{
|
||||||
$db = DB::db();
|
$db = DB::db();
|
||||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||||
@@ -1268,6 +1270,7 @@ function addAge()
|
|||||||
foreach ($db->query('SELECT no,name,nation,leadership,strength,intel,aux from general where specage<=age and special=%s', GameConst::$defaultSpecialDomestic) as $general) {
|
foreach ($db->query('SELECT no,name,nation,leadership,strength,intel,aux from general where specage<=age and special=%s', GameConst::$defaultSpecialDomestic) as $general) {
|
||||||
$generalID = $general['no'];
|
$generalID = $general['no'];
|
||||||
$special = SpecialityHelper::pickSpecialDomestic(
|
$special = SpecialityHelper::pickSpecialDomestic(
|
||||||
|
$rng,
|
||||||
$general,
|
$general,
|
||||||
(Json::decode($general['aux'])['prev_types_special']) ?? []
|
(Json::decode($general['aux'])['prev_types_special']) ?? []
|
||||||
);
|
);
|
||||||
@@ -1295,6 +1298,7 @@ function addAge()
|
|||||||
$updateVars['aux'] = Json::encode($generalAux);
|
$updateVars['aux'] = Json::encode($generalAux);
|
||||||
} else {
|
} else {
|
||||||
$special2 = SpecialityHelper::pickSpecialWar(
|
$special2 = SpecialityHelper::pickSpecialWar(
|
||||||
|
$rng,
|
||||||
$general,
|
$general,
|
||||||
($generalAux['prev_types_special2']) ?? []
|
($generalAux['prev_types_special2']) ?? []
|
||||||
);
|
);
|
||||||
@@ -1343,7 +1347,7 @@ function turnDate($curtime)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function triggerTournament()
|
function triggerTournament(RandUtil $rng)
|
||||||
{
|
{
|
||||||
$db = DB::db();
|
$db = DB::db();
|
||||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||||
@@ -1357,7 +1361,7 @@ function triggerTournament()
|
|||||||
if ($tnmt_trig == 0) {
|
if ($tnmt_trig == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!Util::randBool(0.4)) {
|
if (!$rng->nextBool(0.4)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1552,9 +1556,10 @@ function CheckHall($no)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function giveRandomUniqueItem(General $general, string $acquireType): bool
|
function giveRandomUniqueItem(RandUtil $rng, General $general, string $acquireType): bool
|
||||||
{
|
{
|
||||||
$db = DB::db();
|
$db = DB::db();
|
||||||
|
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||||
//아이템 습득 상황
|
//아이템 습득 상황
|
||||||
$availableUnique = [];
|
$availableUnique = [];
|
||||||
|
|
||||||
@@ -1586,6 +1591,18 @@ function giveRandomUniqueItem(General $general, string $acquireType): bool
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$auctionItems = $db->queryFirstColumn(
|
||||||
|
'SELECT `target` FROM `ng_auction` WHERE `type` = %s AND `finished` = 0',
|
||||||
|
AuctionType::UniqueItem->value
|
||||||
|
);
|
||||||
|
foreach ($auctionItems as $itemCode) {
|
||||||
|
if (key_exists($itemCode, $occupiedUnique)) {
|
||||||
|
$occupiedUnique[$itemCode]++;
|
||||||
|
} else {
|
||||||
|
$occupiedUnique[$itemCode] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
foreach ($db->queryAllLists('SELECT namespace, count(*) as cnt FROM `storage` WHERE namespace LIKE "ut_%" GROUP BY namespace') as [$uniqueNS, $cnt]) {
|
foreach ($db->queryAllLists('SELECT namespace, count(*) as cnt FROM `storage` WHERE namespace LIKE "ut_%" GROUP BY namespace') as [$uniqueNS, $cnt]) {
|
||||||
$itemCode = substr($uniqueNS, 3);
|
$itemCode = substr($uniqueNS, 3);
|
||||||
$itemClass = buildItemClass($itemCode);
|
$itemClass = buildItemClass($itemCode);
|
||||||
@@ -1629,10 +1646,7 @@ function giveRandomUniqueItem(General $general, string $acquireType): bool
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if ($general->getAuxVar('inheritRandomUnique')) {
|
if ($general->getAuxVar('inheritRandomUnique')) {
|
||||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
|
||||||
[$year, $month, $initYear, $initMonth] = $gameStor->getValuesAsArray(['year', 'month', 'init_year', 'init_month']);
|
[$year, $month, $initYear, $initMonth] = $gameStor->getValuesAsArray(['year', 'month', 'init_year', 'init_month']);
|
||||||
|
|
||||||
$relMonthByInit = Util::joinYearMonth($year, $month) - Util::joinYearMonth($initYear, $initMonth);
|
$relMonthByInit = Util::joinYearMonth($year, $month) - Util::joinYearMonth($initYear, $initMonth);
|
||||||
@@ -1643,7 +1657,7 @@ function giveRandomUniqueItem(General $general, string $acquireType): bool
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[$itemType, $itemCode] = Util::choiceRandomUsingWeightPair($availableUnique);
|
[$itemType, $itemCode] = $rng->choiceUsingWeightPair($availableUnique);
|
||||||
|
|
||||||
$nationName = $general->getStaticNation()['name'];
|
$nationName = $general->getStaticNation()['name'];
|
||||||
$generalName = $general->getName();
|
$generalName = $general->getName();
|
||||||
@@ -1666,211 +1680,7 @@ function giveRandomUniqueItem(General $general, string $acquireType): bool
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function rollbackInheritUniqueTrial(General $general, string $itemKey, string $reason)
|
function tryUniqueItemLottery(RandUtil $rng, General $general, string $acquireType = '아이템'): bool
|
||||||
{
|
|
||||||
|
|
||||||
$ownerID = $general->getVar('owner');
|
|
||||||
|
|
||||||
$db = DB::db();
|
|
||||||
|
|
||||||
$itemTrials = $general->getAuxVar('inheritUniqueTrial');
|
|
||||||
LogText("선택유니크 롤백:{$ownerID}", [$itemKey, $itemTrials]);
|
|
||||||
unset($itemTrials[$itemKey]);
|
|
||||||
if (count($itemTrials) == 0) {
|
|
||||||
$itemTrials = null;
|
|
||||||
}
|
|
||||||
$general->setAuxVar('inheritUniqueTrial', $itemTrials);
|
|
||||||
|
|
||||||
|
|
||||||
$trialStor = KVStorage::getStorage($db, "ut_{$itemKey}");
|
|
||||||
$ownTrial = $trialStor->getValue("u{$ownerID}");
|
|
||||||
|
|
||||||
$itemObj = buildItemClass($itemKey);
|
|
||||||
$itemName = $itemObj->getName();
|
|
||||||
|
|
||||||
if ($ownTrial) {
|
|
||||||
//두 값이 general, KVStorage 둘다 있고, 이중에선 KVStorage 값을 기준으로 하자 따르자
|
|
||||||
[,, $amount] = $ownTrial;
|
|
||||||
$trialStor->deleteValue("u{$ownerID}");
|
|
||||||
$general->increaseInheritancePoint(InheritanceKey::previous, $amount);
|
|
||||||
$general->increaseRankVar(RankColumn::inherit_point_spent_dynamic, -$amount);
|
|
||||||
LogText("선택유니크 롤백포인트:{$ownerID}", $amount);
|
|
||||||
|
|
||||||
$userLogger = new UserLogger($ownerID);
|
|
||||||
$userLogger->push("{$itemName} 입찰에 사용한 {$amount} 포인트 반환", "inheritPoint");
|
|
||||||
}
|
|
||||||
|
|
||||||
//메시지
|
|
||||||
|
|
||||||
$staticNation = $general->getStaticNation();
|
|
||||||
|
|
||||||
$unlimited = new \DateTime('9999-12-31');
|
|
||||||
$src = new MessageTarget(0, '', 0, 'System', '#000000');
|
|
||||||
$dest = new MessageTarget($general->getID(), $general->getName(), $general->getNationID(), $staticNation['name'], $staticNation['color'], GetImageURL($general->getVar('imgsvr'), $general->getVar('picture')));
|
|
||||||
$josaUl = JosaUtil::pick($itemName, '을');
|
|
||||||
$msg = new Message(
|
|
||||||
Message::MSGTYPE_PRIVATE,
|
|
||||||
$src,
|
|
||||||
$dest,
|
|
||||||
"{$itemName}{$josaUl} 얻지 못했습니다. {$reason}",
|
|
||||||
new DateTime(),
|
|
||||||
$unlimited,
|
|
||||||
[]
|
|
||||||
);
|
|
||||||
|
|
||||||
$general->applyDB($db);
|
|
||||||
$msg->send(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
function tryRollbackInheritUniqueItem(General $general): void
|
|
||||||
{
|
|
||||||
tryInheritUniqueItem($general, 'Rollback', true);
|
|
||||||
}
|
|
||||||
|
|
||||||
function tryInheritUniqueItem(General $general, string $acquireType = '아이템', bool $justRollback = false): bool
|
|
||||||
{
|
|
||||||
$ownerID = $general->getVar('owner');
|
|
||||||
if (!$ownerID) {
|
|
||||||
LogText("선택유니크 실패???: {$ownerID}", $general->getName());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$itemTrials = $general->getAuxVar('inheritUniqueTrial') ?? [];
|
|
||||||
arsort($itemTrials);
|
|
||||||
LogText("선택유니크항목: {$ownerID}", $itemTrials);
|
|
||||||
|
|
||||||
$db = DB::db();
|
|
||||||
|
|
||||||
$ownTarget = null;
|
|
||||||
$ownType = null;
|
|
||||||
|
|
||||||
foreach ($itemTrials as $itemKey => $amount) {
|
|
||||||
$availableItemTypes = [];
|
|
||||||
$reasons = [];
|
|
||||||
foreach (GameConst::$allItems as $itemType => $itemList) {
|
|
||||||
//아직은 그런 경우는 없지만 동일 유니크를 여러 부위에 장착할 수 있을지도 모름
|
|
||||||
if (!key_exists($itemKey, $itemList)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$ownItem = $general->getItem($itemType);
|
|
||||||
if ($ownItem->getRawClassName() == $itemKey) {
|
|
||||||
$reasons[] = '이미 그 유니크를 가지고 있습니다.';
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$ownItem->isBuyable()) {
|
|
||||||
$reasons[] = '이미 다른 유니크를 가지고 있습니다.';
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$availableCnt = $itemList[$itemKey];
|
|
||||||
$occupiedCnt = $db->queryFirstField('SELECT count(*) FROM general WHERE %b = %s', $itemType, $itemKey);
|
|
||||||
if ($occupiedCnt >= $availableCnt) {
|
|
||||||
$reasons[] = '그 유니크는 모두 점유되었습니다.';
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$availableItemTypes[] = $itemType;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$availableItemTypes) {
|
|
||||||
rollbackInheritUniqueTrial($general, $itemKey, join(' ', $reasons));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$reasons = [];
|
|
||||||
|
|
||||||
$itemType = Util::choiceRandom($availableItemTypes);
|
|
||||||
|
|
||||||
$trialStor = KVStorage::getStorage($db, "ut_{$itemKey}"); //혹시 itemKey의 크기가 37이 넘을 수 있을까?
|
|
||||||
$anyTrials = $trialStor->getAll();
|
|
||||||
if (!$anyTrials) {
|
|
||||||
//순서가 꼬였던 모양, 실제 값은 storage를 우선시하자
|
|
||||||
rollbackInheritUniqueTrial($general, $itemKey, '절차상의 오류입니다.');
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
//XXX: 정렬할 필요 없지 않나?
|
|
||||||
usort($anyTrials, function ($lhsTrial, $rhsTrial) {
|
|
||||||
[,, $lhsAmount] = $lhsTrial;
|
|
||||||
[,, $rhsAmount] = $rhsTrial;
|
|
||||||
return $rhsAmount <=> $lhsAmount; //큰 값이 앞에 오도록
|
|
||||||
});
|
|
||||||
|
|
||||||
LogText("선택유니크상태 {$ownerID} {$itemKey}", $anyTrials);
|
|
||||||
|
|
||||||
//공동 1등인데 본인이 있을 수도 있다.
|
|
||||||
[,, $topAmount] = $anyTrials[0];
|
|
||||||
if ($amount < $topAmount) {
|
|
||||||
$compAmount = $topAmount / $amount;
|
|
||||||
if ($compAmount > 2.0) {
|
|
||||||
$compText = '엄청난 차이로 ';
|
|
||||||
} else if ($compAmount > 1.2) {
|
|
||||||
$compText = '큰 차이로 ';
|
|
||||||
} else if ($compAmount > 1.05) {
|
|
||||||
$compText = '';
|
|
||||||
} else {
|
|
||||||
$compText = '아슬아슬한 차이로 ';
|
|
||||||
}
|
|
||||||
rollbackInheritUniqueTrial($general, $itemKey, "{$compText}상위 입찰한 장수가 있습니다.");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
//내가 1위다
|
|
||||||
if ($ownTarget !== null) {
|
|
||||||
//이미 다른 아이템을 얻기로 되어있다.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$ownTarget = $itemKey;
|
|
||||||
$ownType = $itemType;
|
|
||||||
}
|
|
||||||
unset($itemKey);
|
|
||||||
unset($itemType);
|
|
||||||
|
|
||||||
if ($ownTarget === null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if ($justRollback) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
LogText("선택유니크획득{$ownerID}", $ownTarget);
|
|
||||||
|
|
||||||
$trialStor = KVStorage::getStorage($db, "ut_{$ownTarget}");
|
|
||||||
$trialStor->deleteValue("u{$ownerID}");
|
|
||||||
|
|
||||||
//rollbackInheritUniqueTrial 과정 때문에 새로 받아와야함
|
|
||||||
$itemTrials = $general->getAuxVar('inheritUniqueTrial');
|
|
||||||
unset($itemTrials[$ownTarget]);
|
|
||||||
$general->setAuxVar('inheritUniqueTrial', $itemTrials);
|
|
||||||
|
|
||||||
$nationName = $general->getStaticNation()['name'];
|
|
||||||
$generalName = $general->getName();
|
|
||||||
$josaYi = JosaUtil::pick($generalName, '이');
|
|
||||||
$itemObj = buildItemClass($ownTarget);
|
|
||||||
$itemName = $itemObj->getName();
|
|
||||||
$itemRawName = $itemObj->getRawName();
|
|
||||||
$josaUl = JosaUtil::pick($itemRawName, '을');
|
|
||||||
|
|
||||||
|
|
||||||
$general->setVar($ownType, $ownTarget);
|
|
||||||
|
|
||||||
|
|
||||||
$logger = $general->getLogger();
|
|
||||||
|
|
||||||
$logger->pushGeneralActionLog("<C>{$itemName}</>{$josaUl} 습득했습니다!");
|
|
||||||
$logger->pushGeneralHistoryLog("<C>{$itemName}</>{$josaUl} 습득");
|
|
||||||
$logger->pushGlobalActionLog("<Y>{$generalName}</>{$josaYi} <C>{$itemName}</>{$josaUl} 습득했습니다!");
|
|
||||||
$logger->pushGlobalHistoryLog("<C><b>【{$acquireType}】</b></><D><b>{$nationName}</b></>의 <Y>{$generalName}</>{$josaYi} <C>{$itemName}</>{$josaUl} 습득했습니다!");
|
|
||||||
|
|
||||||
$general->applyDB($db);
|
|
||||||
|
|
||||||
//같은 종류의 유니크를 입찰했을 수 있으니 한번 더 검사한다.
|
|
||||||
tryRollbackInheritUniqueItem($general);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function tryUniqueItemLottery(General $general, string $acquireType = '아이템'): bool
|
|
||||||
{
|
{
|
||||||
$db = DB::db();
|
$db = DB::db();
|
||||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||||
@@ -1915,18 +1725,9 @@ function tryUniqueItemLottery(General $general, string $acquireType = '아이템
|
|||||||
$userLogger = new UserLogger($general->getVar('owner'));
|
$userLogger = new UserLogger($general->getVar('owner'));
|
||||||
$userLogger->push(sprintf("유니크를 얻을 공간이 없어 %d 포인트 반환", GameConst::$inheritItemRandomPoint), "inheritPoint");
|
$userLogger->push(sprintf("유니크를 얻을 공간이 없어 %d 포인트 반환", GameConst::$inheritItemRandomPoint), "inheritPoint");
|
||||||
}
|
}
|
||||||
tryRollbackInheritUniqueItem($general);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$inheritUnique = $general->getAuxVar('inheritUniqueTrial');
|
|
||||||
if ($acquireType != '설문조사' && $inheritUnique && count($inheritUnique) && $availableBuyUnique) {
|
|
||||||
$trialResult = tryInheritUniqueItem($general, $acquireType);
|
|
||||||
if ($trialResult) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$scenario = $gameStor->scenario;
|
$scenario = $gameStor->scenario;
|
||||||
$genCount = $db->queryFirstField('SELECT count(*) FROM general WHERE npc<2');
|
$genCount = $db->queryFirstField('SELECT count(*) FROM general WHERE npc<2');
|
||||||
|
|
||||||
@@ -1956,7 +1757,7 @@ function tryUniqueItemLottery(General $general, string $acquireType = '아이템
|
|||||||
}
|
}
|
||||||
|
|
||||||
foreach (Util::range($maxCnt) as $_idx) {
|
foreach (Util::range($maxCnt) as $_idx) {
|
||||||
if (Util::randBool($prob)) {
|
if ($rng->nextBool($prob)) {
|
||||||
$result = true;
|
$result = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1968,7 +1769,7 @@ function tryUniqueItemLottery(General $general, string $acquireType = '아이템
|
|||||||
}
|
}
|
||||||
LogText("{$general->getName()}, {$general->getID()} 유니크 성공 {$maxCnt}", $prob);
|
LogText("{$general->getName()}, {$general->getID()} 유니크 성공 {$maxCnt}", $prob);
|
||||||
|
|
||||||
return giveRandomUniqueItem($general, $acquireType);
|
return giveRandomUniqueItem($rng, $general, $acquireType);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAdmin()
|
function getAdmin()
|
||||||
@@ -2085,13 +1886,31 @@ function nextRuler(General $general)
|
|||||||
|
|
||||||
//npc or npc유저인 경우 후계 찾기
|
//npc or npc유저인 경우 후계 찾기
|
||||||
if (!$fiction && $general->getNPCType() > 0) {
|
if (!$fiction && $general->getNPCType() > 0) {
|
||||||
$candidate = $db->queryFirstRow(
|
$rng = new RandUtil(new LiteHashDRBG(Util::simpleSerialize(
|
||||||
'SELECT no,name,officer_level,IF(ABS(affinity-%i)>75,150-ABS(affinity-%i),ABS(affinity-%i)) as npcmatch2 from general where nation=%i and officer_level!=12 and 1 <= npc and npc<=3 order by npcmatch2,rand() LIMIT 1',
|
UniqueConst::$hiddenSeed,
|
||||||
|
'NextNPCRuler',
|
||||||
|
$year,
|
||||||
|
$month,
|
||||||
|
$general->getID(),
|
||||||
|
)));
|
||||||
|
$rawCandidates = $db->query(
|
||||||
|
'SELECT no,name,officer_level,IF(ABS(affinity-%i)>75,150-ABS(affinity-%i),ABS(affinity-%i)) as npcmatch2 from general where nation=%i and officer_level!=12 and 1 <= npc and npc<=3 order by npcmatch2 asc',
|
||||||
$general->getVar('affinity'),
|
$general->getVar('affinity'),
|
||||||
$general->getVar('affinity'),
|
$general->getVar('affinity'),
|
||||||
$general->getVar('affinity'),
|
$general->getVar('affinity'),
|
||||||
$nationID
|
$nationID
|
||||||
);
|
);
|
||||||
|
if ($rawCandidates) {
|
||||||
|
$candidates = [];
|
||||||
|
$minNPCMatch = $rawCandidates[0]['npcmatch2'];
|
||||||
|
foreach ($rawCandidates as $candidate) {
|
||||||
|
if (!$candidate['npcmatch2'] == $minNPCMatch) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$candidates[] = $candidate;
|
||||||
|
}
|
||||||
|
$candidate = $rng->choice($candidates);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!$candidate) {
|
if (!$candidate) {
|
||||||
$candidate = $db->queryFirstRow(
|
$candidate = $db->queryFirstRow(
|
||||||
@@ -2415,7 +2234,7 @@ function isNeighbor(int $nation1, int $nation2, bool $includeNoSupply = true)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function SabotageInjury(array $cityGeneralList, string $reason): int
|
function SabotageInjury(RandUtil $rng, array $cityGeneralList, string $reason): int
|
||||||
{
|
{
|
||||||
$injuryCount = 0;
|
$injuryCount = 0;
|
||||||
$josaRo = JosaUtil::pick($reason, '로');
|
$josaRo = JosaUtil::pick($reason, '로');
|
||||||
@@ -2427,12 +2246,12 @@ function SabotageInjury(array $cityGeneralList, string $reason): int
|
|||||||
/** @var General $general */
|
/** @var General $general */
|
||||||
$injuryProb = 0.3;
|
$injuryProb = 0.3;
|
||||||
$injuryProb = $general->onCalcStat($general, 'injuryProb', $injuryProb);
|
$injuryProb = $general->onCalcStat($general, 'injuryProb', $injuryProb);
|
||||||
if (!Util::randBool($injuryProb)) {
|
if (!$rng->nextBool($injuryProb)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$general->getLogger()->pushGeneralActionLog($text);
|
$general->getLogger()->pushGeneralActionLog($text);
|
||||||
|
|
||||||
$general->increaseVarWithLimit('injury', Util::randRangeInt(1, 16), 0, 80);
|
$general->increaseVarWithLimit('injury', $rng->nextRangeInt(1, 16), 0, 80);
|
||||||
$general->multiplyVar('crew', 0.98);
|
$general->multiplyVar('crew', 0.98);
|
||||||
$general->multiplyVar('atmos', 0.98);
|
$general->multiplyVar('atmos', 0.98);
|
||||||
$general->multiplyVar('train', 0.98);
|
$general->multiplyVar('train', 0.98);
|
||||||
@@ -2445,7 +2264,7 @@ function SabotageInjury(array $cityGeneralList, string $reason): int
|
|||||||
return $injuryCount;
|
return $injuryCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRandTurn($term, ?\DateTimeInterface $baseDateTime = null)
|
function getRandTurn(RandUtil $rng, $term, ?\DateTimeInterface $baseDateTime = null)
|
||||||
{
|
{
|
||||||
if ($baseDateTime === null) {
|
if ($baseDateTime === null) {
|
||||||
$baseDateTime = new \DateTimeImmutable();
|
$baseDateTime = new \DateTimeImmutable();
|
||||||
@@ -2457,13 +2276,13 @@ function getRandTurn($term, ?\DateTimeInterface $baseDateTime = null)
|
|||||||
throw new MustNotBeReachedException();
|
throw new MustNotBeReachedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
$randSecond = Util::randRangeInt(0, 60 * $term - 1);
|
$randSecond = $rng->nextRangeInt(0, 60 * $term - 1);
|
||||||
$randFraction = Util::randRangeInt(0, 999999) / 1000000; //6자리 소수
|
$randFraction = $rng->nextRangeInt(0, 999999) / 1000000; //6자리 소수
|
||||||
|
|
||||||
return TimeUtil::format($baseDateTime->add(TimeUtil::secondsToDateInterval($randSecond + $randFraction)), true);
|
return TimeUtil::format($baseDateTime->add(TimeUtil::secondsToDateInterval($randSecond + $randFraction)), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRandTurn2($term, ?\DateTimeInterface $baseDateTime = null)
|
function getRandTurn2(RandUtil $rng, $term, ?\DateTimeInterface $baseDateTime = null)
|
||||||
{
|
{
|
||||||
if ($baseDateTime === null) {
|
if ($baseDateTime === null) {
|
||||||
$baseDateTime = new \DateTimeImmutable();
|
$baseDateTime = new \DateTimeImmutable();
|
||||||
@@ -2472,8 +2291,8 @@ function getRandTurn2($term, ?\DateTimeInterface $baseDateTime = null)
|
|||||||
} else {
|
} else {
|
||||||
throw new MustNotBeReachedException();
|
throw new MustNotBeReachedException();
|
||||||
}
|
}
|
||||||
$randSecond = Util::randRangeInt(0, 60 * $term - 1);
|
$randSecond = $rng->nextRangeInt(0, 60 * $term - 1);
|
||||||
$randFraction = Util::randRangeInt(0, 999999) / 1000000; //6자리 소수
|
$randFraction = $rng->nextRangeInt(0, 999999) / 1000000; //6자리 소수
|
||||||
|
|
||||||
return $baseDateTime->sub(TimeUtil::secondsToDateInterval($randSecond + $randFraction))->format('Y-m-d H:i:s.u');
|
return $baseDateTime->sub(TimeUtil::secondsToDateInterval($randSecond + $randFraction))->format('Y-m-d H:i:s.u');
|
||||||
}
|
}
|
||||||
|
|||||||
+55
-212
@@ -1,247 +1,90 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace sammo;
|
namespace sammo;
|
||||||
|
|
||||||
function registerAuction() {
|
use sammo\Enums\AuctionType;
|
||||||
|
|
||||||
|
function registerAuction(RandUtil $rng)
|
||||||
|
{
|
||||||
$db = DB::db();
|
$db = DB::db();
|
||||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
|
||||||
|
|
||||||
$admin = $gameStor->getValues(['startyear', 'year', 'month', 'turnterm']);
|
|
||||||
|
|
||||||
$unit = 60 * $admin['turnterm'];
|
|
||||||
|
|
||||||
// 장수들 평금,평쌀
|
// 장수들 평금,평쌀
|
||||||
$general = $db->queryFirstRow('SELECT avg(gold) as gold, avg(rice) as rice,max(gold) as maxgold from general where npc<2');
|
[$avgGold, $avgRice] = $db->queryFirstList('SELECT avg(gold), avg(rice) from general where npc<2');
|
||||||
|
$avgGold = Util::valueFit($avgGold, 1000, 20000);
|
||||||
|
$avgRice = Util::valueFit($avgRice, 1000, 20000);
|
||||||
|
|
||||||
if($general['gold'] < 1000) { $general['gold'] = 1000; }
|
$neutralAuctionCnt = Util::convertPairArrayToDict($db->queryAllLists(
|
||||||
if($general['gold'] > 20000) { $general['gold'] = 20000; }
|
'SELECT `type`, count(*) FROM ng_auction WHERE `type` IN %ls AND `host_general_id`=0 GROUP BY `type`',
|
||||||
if($general['rice'] < 1000) { $general['rice'] = 1000; }
|
[AuctionType::BuyRice->value, AuctionType::SellRice->value],
|
||||||
if($general['rice'] > 20000) { $general['rice'] = 20000; }
|
));
|
||||||
|
|
||||||
|
$neutralbuyRiceCnt = $neutralAuctionCnt[AuctionType::BuyRice->value];
|
||||||
|
|
||||||
$count = $db->queryFirstField('SELECT count(*) FROM auction WHERE type=0 AND no1=0');
|
|
||||||
$count += 5;
|
|
||||||
// 판매건 등록
|
// 판매건 등록
|
||||||
if(Util::randBool(1/$count)) {
|
if ($rng->nextBool(1 / ($neutralbuyRiceCnt + 5))) {
|
||||||
//평균 쌀의 5% ~ 25%
|
//평균 쌀의 5% ~ 25%
|
||||||
$mul = rand() % 5 + 1;
|
$mul = $rng->nextRangeInt(1, 5);
|
||||||
$amount = $general['rice'] / 20 * $mul;
|
$amount = $avgRice / 20 * $mul;
|
||||||
$cost = $general['gold'] / 20 * 0.9 * $mul;
|
$cost = $avgGold / 20 * 0.9 * $mul;
|
||||||
$topv = $amount * 2;
|
$topv = $amount * 2;
|
||||||
if($cost <= $amount*0.8) { $cost = $amount*0.8; }
|
$cost = Util::valueFit($cost, $amount * 0.8, $amount * 1.2);
|
||||||
if($cost >= $amount*1.2) { $cost = $amount*1.2; }
|
|
||||||
|
|
||||||
$amount = Util::round($amount, -1);
|
$amount = Util::round($amount, -1);
|
||||||
$cost = Util::round($cost, -1);
|
$cost = Util::round($cost, -1);
|
||||||
$topv = Util::round($topv, -1);
|
$topv = Util::round($topv, -1);
|
||||||
|
|
||||||
$term = 3 + rand() % 10;
|
$term = $rng->nextRangeInt(3, 12);
|
||||||
$date = date("Y-m-d H:i:s", strtotime(date("Y-m-d H:i:s")) + $unit * $term);
|
$dummyGeneral = AuctionBasicResource::genDummy();
|
||||||
$db->insert('auction', [
|
AuctionBuyRice::openResourceAuction($dummyGeneral, $amount, $term, $cost, $topv);
|
||||||
'type'=>0,
|
|
||||||
'no1'=>0,
|
|
||||||
'name1'=>'ⓝ상인',
|
|
||||||
'amount'=>$amount,
|
|
||||||
'cost'=>$cost,
|
|
||||||
'value'=>$cost,
|
|
||||||
'topv'=>$topv,
|
|
||||||
'expire'=>$date
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$count = $db->queryFirstField('SELECT count(*) FROM auction WHERE type=1 AND no1=0');
|
$neutralSellRiceCnt = $neutralAuctionCnt[AuctionType::SellRice->value];
|
||||||
$count += 5;
|
|
||||||
// 구매건 등록
|
// 구매건 등록
|
||||||
if(Util::randBool(1/$count)) {
|
if ($rng->nextBool(1 / ($neutralSellRiceCnt + 5))) {
|
||||||
//평균 쌀의 5% ~ 25%
|
//평균 쌀의 5% ~ 25%
|
||||||
$mul = Util::randRangeInt(1, 5);
|
$mul = $rng->nextRangeInt(1, 5);
|
||||||
$amount = $general['rice'] / 20 * $mul;
|
$amount = $avgGold / 20 * $mul;
|
||||||
$cost = $general['gold'] / 20 * 1.1 * $mul;
|
$cost = $avgRice / 20 * 1.1 * $mul;
|
||||||
$topv = $amount * 0.5;
|
$topv = $amount * 2;
|
||||||
if($cost <= $amount*0.8) { $cost = $amount*0.8; }
|
$cost = Util::valueFit($cost, $amount * 0.8, $amount * 1.2);
|
||||||
if($cost >= $amount*1.2) { $cost = $amount*1.2; }
|
|
||||||
|
|
||||||
$amount = Util::round($amount, -1);
|
$amount = Util::round($amount, -1);
|
||||||
$cost = Util::round($cost, -1);
|
$cost = Util::round($cost, -1);
|
||||||
$topv = Util::round($topv, -1);
|
$topv = Util::round($topv, -1);
|
||||||
|
|
||||||
$term = Util::randRangeInt(3, 12);
|
$term = $rng->nextRangeInt(3, 12);
|
||||||
$date = date("Y-m-d H:i:s", strtotime(date("Y-m-d H:i:s")) + $unit * $term);
|
$dummyGeneral = AuctionBasicResource::genDummy();
|
||||||
$db->insert('auction', [
|
AuctionSellRice::openResourceAuction($dummyGeneral, $amount, $term, $cost, $topv);
|
||||||
'type'=>1,
|
|
||||||
'no1'=>0,
|
|
||||||
'name1'=>'ⓝ상인',
|
|
||||||
'amount'=>$amount,
|
|
||||||
'cost'=>$cost,
|
|
||||||
'value'=>$cost,
|
|
||||||
'topv'=>$topv,
|
|
||||||
'expire'=>$date
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function processAuction() {
|
function processAuction()
|
||||||
|
{
|
||||||
$db = DB::db();
|
$db = DB::db();
|
||||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
|
||||||
|
|
||||||
$date = TimeUtil::now();
|
$now = TimeUtil::now();
|
||||||
[$year, $month] = $gameStor->getValuesAsArray(['year', 'month']);
|
|
||||||
|
|
||||||
$admin = $gameStor->getValues(['year', 'month']);
|
$auctionList = $db->queryAllLists(
|
||||||
|
'SELECT id, `type` FROM ng_auction WHERE `close_date` <= %s AND finished = 0',
|
||||||
|
$now
|
||||||
|
);
|
||||||
|
|
||||||
foreach($db->query('SELECT * from auction where expire<=%s', $date) as $auction){
|
if (!$auctionList) {
|
||||||
$josaYi1 = JosaUtil::pick($auction['name1'], '이');
|
return;
|
||||||
$josaYi2 = JosaUtil::pick($auction['name2'], '이');
|
|
||||||
|
|
||||||
// 쌀 처리
|
|
||||||
if($auction['no2'] == 0) {
|
|
||||||
// 상인건수가 아닌것만 출력
|
|
||||||
if($auction['no1'] != 0) {
|
|
||||||
$traderID = $db->queryFirstField('SELECT no FROM general WHERE no=%i', $auction['no1']);
|
|
||||||
$logger = new ActionLogger($traderID, 0, $year, $month);
|
|
||||||
$logger->pushGeneralActionLog("입찰자 부재로 {$auction['no']}번 거래 <M>유찰</>!", ActionLogger::EVENT_PLAIN);
|
|
||||||
$logger->flush();
|
|
||||||
|
|
||||||
$auctionLog = [];
|
|
||||||
if($auction['type'] == 0) {
|
|
||||||
$josaUlRice = JosaUtil::pick($auction['amount'], '을');
|
|
||||||
$auctionLog[] = "<S>◆</>{$admin['year']}년 {$admin['month']}월, {$auction['no']}번 <span class='sell'>판매</span> <M>유찰</> : <Y>{$auction['name1']}</>{$josaYi1} 쌀 <C>{$auction['amount']}</>{$josaUlRice} 판매, 그러나 입찰자 부재";
|
|
||||||
} else {
|
|
||||||
$josaUlRice = JosaUtil::pick($auction['amount'], '을');
|
|
||||||
$auctionLog[] = "<S>◆</>{$admin['year']}년 {$admin['month']}월, {$auction['no']}번 <S>구매</> <M>유찰</> : <Y>{$auction['name1']}</>{$josaYi1} 쌀 <C>{$auction['amount']}</>{$josaUlRice} 구매, 그러나 입찰자 부재";
|
|
||||||
}
|
|
||||||
|
|
||||||
pushAuctionLog($auctionLog);
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if($auction['no1'] == 0) {
|
|
||||||
$trader = [
|
|
||||||
'no'=>0,
|
|
||||||
'name'=>'ⓝ상인',
|
|
||||||
'gold'=>99999,
|
|
||||||
'rice'=>99999
|
|
||||||
];
|
|
||||||
} else {
|
|
||||||
$trader = $db->queryFirstRow('SELECT no,name,gold,rice from general where no=%i', $auction['no1']);
|
|
||||||
}
|
|
||||||
|
|
||||||
$bidder = $db->queryFirstRow('SELECT no,name,gold,rice from general where no=%i', $auction['no2']);
|
|
||||||
|
|
||||||
$traderLogger = new ActionLogger($trader['no'], 0, $year, $month, false);
|
|
||||||
$bidderLogger = new ActionLogger($bidder['no'], 0, $year, $month, false);
|
|
||||||
|
|
||||||
$auctionLog = [];
|
|
||||||
|
|
||||||
|
|
||||||
//판매거래
|
|
||||||
if($auction['type'] == 0) {
|
|
||||||
if($auction['amount'] > $trader['rice'] - 1000) {
|
|
||||||
$gold = Util::round($auction['value'] * 0.01);
|
|
||||||
$db->update('general', [
|
|
||||||
'gold'=>Util::valueFit($trader['gold'] - $gold, 0)
|
|
||||||
], 'no=%i', $trader['no']);
|
|
||||||
|
|
||||||
$josaUlRice = JosaUtil::pick($auction['amount'], '을');
|
|
||||||
$josaRo = JosaUtil::pick($auction['value'], '로');
|
|
||||||
$traderLogger->pushGeneralActionLog("판매자의 군량 부족으로 {$auction['no']}번 거래 <M>유찰</>! 벌금 <C>{$gold}</>", ActionLogger::EVENT_PLAIN);
|
|
||||||
$bidderLogger->pushGeneralActionLog("판매자의 군량 부족으로 {$auction['no']}번 거래 <M>유찰</>!", ActionLogger::EVENT_PLAIN);
|
|
||||||
$auctionLog[0] = "<S>◆</>{$admin['year']}년 {$admin['month']}월, {$auction['no']}번 <span class='sell'>판매</span> <M>유찰</> : <Y>{$auction['name1']}</>{$josaYi1} 쌀 <C>{$auction['amount']}</>{$josaUlRice} 판매, <Y>{$auction['name2']}</>{$josaYi2} 금 <C>{$auction['value']}</>{$josaRo} 입찰, 그러나 판매자 군량부족, 벌금 <C>{$gold}</>";
|
|
||||||
} elseif($auction['value'] > $bidder['gold'] - 1000) {
|
|
||||||
$gold = Util::round($auction['value'] * 0.01);
|
|
||||||
$db->update('general', [
|
|
||||||
'gold'=>Util::valueFit($bidder['gold'] - $gold, 0)
|
|
||||||
], 'no=%i', $bidder['no']);
|
|
||||||
|
|
||||||
$josaUlRice = JosaUtil::pick($auction['amount'], '을');
|
|
||||||
$josaRo = JosaUtil::pick($auction['value'], '로');
|
|
||||||
$traderLogger->pushGeneralActionLog("입찰자의 자금 부족으로 {$auction['no']}번 거래 <M>유찰</>!", ActionLogger::EVENT_PLAIN);
|
|
||||||
$bidderLogger->pushGeneralActionLog("입찰자의 자금 부족으로 {$auction['no']}번 거래 <M>유찰</>! 벌금 <C>{$gold}</>", ActionLogger::EVENT_PLAIN);
|
|
||||||
$auctionLog[0] = "<S>◆</>{$admin['year']}년 {$admin['month']}월, {$auction['no']}번 <span class='sell'>판매</span> <M>유찰</> : <Y>{$auction['name1']}</>{$josaYi1} 쌀 <C>{$auction['amount']}</>{$josaUlRice} 판매, <Y>{$auction['name2']}</>{$josaYi2} 금 <C>{$auction['value']}</>{$josaRo} 입찰, 그러나 입찰자 자금부족, 벌금 <C>{$gold}</>";
|
|
||||||
} else {
|
|
||||||
$josaUlGold = JosaUtil::pick($auction['value'], '을');
|
|
||||||
$josaUlRice = JosaUtil::pick($auction['amount'], '을');
|
|
||||||
$josaRo = JosaUtil::pick($auction['value'], '로');
|
|
||||||
$traderLogger->pushGeneralActionLog("{$auction['no']}번 거래 <C>성사</>로 쌀 <C>{$auction['amount']}</>{$josaUlRice} 판매, 금 <C>{$auction['value']}</>{$josaUlGold} 획득!", ActionLogger::EVENT_PLAIN);
|
|
||||||
$bidderLogger->pushGeneralActionLog("{$auction['no']}번 거래 <C>성사</>로 금 <C>{$auction['value']}</>{$josaUlGold} 지불, 쌀 <C>{$auction['amount']}</>{$josaUlRice} 구입!", ActionLogger::EVENT_PLAIN);
|
|
||||||
$auctionLog[0] = "<S>◆</>{$admin['year']}년 {$admin['month']}월, {$auction['no']}번 <span class='sell'>판매</span> <C>성사</> : <Y>{$auction['name1']}</>{$josaYi1} 쌀 <C>{$auction['amount']}</>{$josaUlRice} 판매, <Y>{$auction['name2']}</>{$josaYi2} 금 <C>{$auction['value']}</>{$josaRo} 구매";
|
|
||||||
if($auction['value'] >= $auction['amount'] * 2) {
|
|
||||||
$auctionLog[0] .= " <R>★ 최고가 거래 ★</>";
|
|
||||||
} elseif($auction['value'] >= $auction['topv']) {
|
|
||||||
$auctionLog[0] .= " <M>★ 즉시구매가 거래 ★</>";
|
|
||||||
} elseif($auction['value'] * 2 <= $auction['amount']) {
|
|
||||||
$auctionLog[0] .= " <R>★ 최저가 거래 ★</>";
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
$db->update('general', [
|
|
||||||
'gold'=>$db->sqleval('gold + %i', $auction['value']),
|
|
||||||
'rice'=>$db->sqleval('rice - %i', $auction['amount']),
|
|
||||||
], 'no=%i', $auction['no1']);
|
|
||||||
$db->update('general', [
|
|
||||||
'gold'=>$db->sqleval('gold - %i', $auction['value']),
|
|
||||||
'rice'=>$db->sqleval('rice + %i', $auction['amount']),
|
|
||||||
], 'no=%i', $auction['no2']);
|
|
||||||
}
|
|
||||||
pushAuctionLog($auctionLog);
|
|
||||||
//구매거래
|
|
||||||
} else {
|
|
||||||
if($auction['amount'] > $bidder['rice'] - 1000) {
|
|
||||||
$gold = Util::round($auction['value'] * 0.01);
|
|
||||||
$db->update('general', [
|
|
||||||
'gold'=>Util::valueFit($bidder['gold'] - $gold, 0)
|
|
||||||
], 'no=%i', $bidder['no']);
|
|
||||||
|
|
||||||
$josaUlRice = JosaUtil::pick($auction['amount'], '을');
|
|
||||||
$josaRo = JosaUtil::pick($auction['value'], '로');
|
|
||||||
$traderLogger->pushGeneralActionLog("입찰자의 군량 부족으로 {$auction['no']}번 거래 <M>유찰</>!", ActionLogger::EVENT_PLAIN);
|
|
||||||
$bidderLogger->pushGeneralActionLog("입찰자의 군량 부족으로 {$auction['no']}번 거래 <M>유찰</>! 벌금 <C>{$gold}</>", ActionLogger::EVENT_PLAIN);
|
|
||||||
$auctionLog[0] = "<S>◆</>{$admin['year']}년 {$admin['month']}월, {$auction['no']}번 <S>구매</> <M>유찰</> : <Y>{$auction['name1']}</>{$josaYi1} 쌀 <C>{$auction['amount']}</>{$josaUlRice} 구매, <Y>{$auction['name2']}</>{$josaYi2} 금 <C>{$auction['value']}</>{$josaRo} 입찰, 그러나 입찰자 군량부족, 벌금 <C>{$gold}</>";
|
|
||||||
} elseif($auction['value'] > $trader['gold'] - 1000) {
|
|
||||||
$gold = Util::round($auction['value'] * 0.01);
|
|
||||||
$db->update('general', [
|
|
||||||
'gold'=>Util::valueFit($trader['gold'] - $gold, 0)
|
|
||||||
], 'no=%i', $trader['no']);
|
|
||||||
|
|
||||||
$josaUlRice = JosaUtil::pick($auction['amount'], '을');
|
|
||||||
$josaRo = JosaUtil::pick($auction['value'], '로');
|
|
||||||
$traderLogger->pushGeneralActionLog("구매자의 자금 부족으로 {$auction['no']}번 거래 <M>유찰</>! 벌금 <C>{$gold}</>", ActionLogger::EVENT_PLAIN);
|
|
||||||
$bidderLogger->pushGeneralActionLog("구매자의 자금 부족으로 {$auction['no']}번 거래 <M>유찰</>!", ActionLogger::EVENT_PLAIN);
|
|
||||||
$auctionLog[0] = "<S>◆</>{$admin['year']}년 {$admin['month']}월, {$auction['no']}번 <S>구매</> <M>유찰</> : <Y>{$auction['name1']}</>{$josaYi1} 쌀 <C>{$auction['amount']}</>{$josaUlRice} 구매, <Y>{$auction['name2']}</>{$josaYi2} 금 <C>{$auction['value']}</>{$josaRo} 입찰, 그러나 구매자 자금부족, 벌금 <C>{$gold}</>";
|
|
||||||
} else {
|
|
||||||
$josaUlGold = JosaUtil::pick($auction['value'], '을');
|
|
||||||
$josaUlRice = JosaUtil::pick($auction['amount'], '을');
|
|
||||||
$josaRo = JosaUtil::pick($auction['value'], '로');
|
|
||||||
$traderLogger->pushGeneralActionLog(
|
|
||||||
"{$auction['no']}번 거래 <C>성사</>로 금 <C>{$auction['value']}</>{$josaUlGold} 지불, 쌀 <C>{$auction['amount']}</>{$josaUlRice} 구입!", ActionLogger::EVENT_PLAIN
|
|
||||||
);
|
|
||||||
$bidderLogger->pushGeneralActionLog("{$auction['no']}번 거래 <C>성사</>로 쌀 <C>{$auction['amount']}</>{$josaUlRice} 판매, 금 <C>{$auction['value']}</>{$josaUlGold} 획득!", ActionLogger::EVENT_PLAIN);
|
|
||||||
$auctionLog[0] = "<S>◆</>{$admin['year']}년 {$admin['month']}월, {$auction['no']}번 <S>구매</> <C>성사</> : <Y>{$auction['name1']}</>{$josaYi1} 쌀 <C>{$auction['amount']}</>{$josaUlRice} 구매, <Y>{$auction['name2']}</>{$josaYi2} 금 <C>{$auction['value']}</>{$josaRo} 판매";
|
|
||||||
if($auction['value'] >= $auction['amount'] * 2) {
|
|
||||||
$auctionLog[0] .= " <R>★ 최고가 거래 ★</>";
|
|
||||||
} elseif($auction['value'] * 2 <= $auction['amount']) {
|
|
||||||
$auctionLog[0] .= " <R>★ 최저가 거래 ★</>";
|
|
||||||
} elseif($auction['value'] <= $auction['topv']) {
|
|
||||||
$auctionLog[0] .= " <M>★ 즉시구매가 거래 ★</>";
|
|
||||||
}
|
|
||||||
|
|
||||||
$db->update('general', [
|
|
||||||
'gold'=>$db->sqleval('gold - %i', $auction['value']),
|
|
||||||
'rice'=>$db->sqleval('rice + %i', $auction['amount']),
|
|
||||||
], 'no=%i', $auction['no1']);
|
|
||||||
$db->update('general', [
|
|
||||||
'gold'=>$db->sqleval('gold + %i', $auction['value']),
|
|
||||||
'rice'=>$db->sqleval('rice - %i', $auction['amount']),
|
|
||||||
], 'no=%i', $auction['no2']);
|
|
||||||
}
|
|
||||||
$traderLogger->flush();
|
|
||||||
$bidderLogger->flush();
|
|
||||||
pushAuctionLog($auctionLog);
|
|
||||||
}
|
|
||||||
|
|
||||||
$traderLogger->flush();
|
|
||||||
$bidderLogger->flush();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$db->delete('auction', 'expire <= %s', $date);
|
$dummyGeneral = AuctionBasicResource::genDummy();
|
||||||
|
foreach ($auctionList as [$auctionID, $rawAuctionType]) {
|
||||||
|
$auctionType = AuctionType::from($rawAuctionType);
|
||||||
|
if ($auctionType === AuctionType::BuyRice) {
|
||||||
|
$auction = new AuctionBuyRice($auctionID, $dummyGeneral);
|
||||||
|
} else if ($auctionType === AuctionType::SellRice) {
|
||||||
|
$auction = new AuctionSellRice($auctionID, $dummyGeneral);
|
||||||
|
} else if ($auctionType === AuctionType::UniqueItem) {
|
||||||
|
$auction = new AuctionUniqueItem($auctionID, $dummyGeneral);
|
||||||
|
} else {
|
||||||
|
throw new \Exception('Unknown auction type');
|
||||||
|
}
|
||||||
|
$auction->tryFinish();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -266,7 +266,7 @@ function checkCommandArg(?array $arg):?string{
|
|||||||
/*'string'=>[
|
/*'string'=>[
|
||||||
'nationName', 'optionText', 'itemType', 'nationType', 'commandType',
|
'nationName', 'optionText', 'itemType', 'nationType', 'commandType',
|
||||||
],*/
|
],*/
|
||||||
'integer'=>[
|
'int'=>[
|
||||||
'crewType', 'destGeneralID', 'destCityID', 'destNationID',
|
'crewType', 'destGeneralID', 'destCityID', 'destNationID',
|
||||||
'amount', 'colorType',
|
'amount', 'colorType',
|
||||||
'srcArmType', 'destArmType', //숙련전환 전용
|
'srcArmType', 'destArmType', //숙련전환 전용
|
||||||
|
|||||||
@@ -405,10 +405,10 @@ function getGeneralPoolClass(string $type){
|
|||||||
* @param null|string $prefix
|
* @param null|string $prefix
|
||||||
* @return AbsGeneralPool[]
|
* @return AbsGeneralPool[]
|
||||||
*/
|
*/
|
||||||
function pickGeneralFromPool(\MeekroDB $db, int $owner, int $pickCnt, ?string $prefix=null):array{
|
function pickGeneralFromPool(\MeekroDB $db, RandUtil $rng, int $owner, int $pickCnt, ?string $prefix=null):array{
|
||||||
/** @var AbsGeneralPool */
|
/** @var AbsGeneralPool */
|
||||||
$class = getGeneralPoolClass(GameConst::$targetGeneralPool);
|
$class = getGeneralPoolClass(GameConst::$targetGeneralPool);
|
||||||
return $class::pickGeneralFromPool($db, $owner, $pickCnt, $prefix);
|
return $class::pickGeneralFromPool($db, $rng, $owner, $pickCnt, $prefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
function countPureGeneralFromRawList(?array $rawGeneralList=null):int{
|
function countPureGeneralFromRawList(?array $rawGeneralList=null):int{
|
||||||
|
|||||||
+78
-25
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
namespace sammo;
|
namespace sammo;
|
||||||
|
|
||||||
use Monolog\Logger;
|
|
||||||
use sammo\Enums\InheritanceKey;
|
use sammo\Enums\InheritanceKey;
|
||||||
use sammo\Enums\RankColumn;
|
use sammo\Enums\RankColumn;
|
||||||
|
|
||||||
@@ -334,7 +333,7 @@ EOD),
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 외교 로그처리, 외교 상태 처리
|
// 외교 로그처리, 외교 상태 처리
|
||||||
function postUpdateMonthly()
|
function postUpdateMonthly(RandUtil $rng)
|
||||||
{
|
{
|
||||||
$db = DB::db();
|
$db = DB::db();
|
||||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||||
@@ -397,7 +396,7 @@ function postUpdateMonthly()
|
|||||||
|
|
||||||
//약간의 랜덤치 부여 (95% ~ 105%)
|
//약간의 랜덤치 부여 (95% ~ 105%)
|
||||||
|
|
||||||
$nation['power'] = Util::round($nation['power'] * (rand() % 101 + 950) / 1000);
|
$nation['power'] = Util::round($nation['power'] * $rng->nextRange(0.95, 1.05));
|
||||||
$powerValues['maxPower'] = max($powerValues['maxPower'] ?? 0, $nation['power']);
|
$powerValues['maxPower'] = max($powerValues['maxPower'] ?? 0, $nation['power']);
|
||||||
$powerValues['maxCrew'] = max($powerValues['maxCrew'] ?? 0, Util::toInt($nation['totalCrew']));
|
$powerValues['maxCrew'] = max($powerValues['maxCrew'] ?? 0, Util::toInt($nation['totalCrew']));
|
||||||
|
|
||||||
@@ -486,12 +485,12 @@ function postUpdateMonthly()
|
|||||||
$availableWarSettingCnt = KVStorage::getValuesFromInterNamespace($db, 'nation_env', 'available_war_setting_cnt');
|
$availableWarSettingCnt = KVStorage::getValuesFromInterNamespace($db, 'nation_env', 'available_war_setting_cnt');
|
||||||
foreach ($nations as $nation) {
|
foreach ($nations as $nation) {
|
||||||
$nationID = $nation['nation'];
|
$nationID = $nation['nation'];
|
||||||
if(!key_exists($nationID, $availableWarSettingCnt)){
|
if (!key_exists($nationID, $availableWarSettingCnt)) {
|
||||||
$availableWarSettingCnt[$nationID] = 0;
|
$availableWarSettingCnt[$nationID] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach($availableWarSettingCnt as $nationID=>$cnt){
|
foreach ($availableWarSettingCnt as $nationID => $cnt) {
|
||||||
if($cnt >= GameConst::$maxAvailableWarSettingCnt){
|
if ($cnt >= GameConst::$maxAvailableWarSettingCnt) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$cnt = Util::valueFit($cnt + GameConst::$incAvailableWarSettingCnt, 0, GameConst::$maxAvailableWarSettingCnt);
|
$cnt = Util::valueFit($cnt + GameConst::$incAvailableWarSettingCnt, 0, GameConst::$maxAvailableWarSettingCnt);
|
||||||
@@ -500,7 +499,7 @@ function postUpdateMonthly()
|
|||||||
|
|
||||||
//초반이후 방랑군 자동 해체
|
//초반이후 방랑군 자동 해체
|
||||||
if ($admin['year'] >= $admin['startyear'] + 2) {
|
if ($admin['year'] >= $admin['startyear'] + 2) {
|
||||||
checkWander();
|
checkWander($rng);
|
||||||
}
|
}
|
||||||
// 작위 업데이트
|
// 작위 업데이트
|
||||||
updateNationState();
|
updateNationState();
|
||||||
@@ -509,9 +508,9 @@ function postUpdateMonthly()
|
|||||||
// 천통여부 검사
|
// 천통여부 검사
|
||||||
checkEmperior();
|
checkEmperior();
|
||||||
//토너먼트 개시
|
//토너먼트 개시
|
||||||
triggerTournament();
|
triggerTournament($rng);
|
||||||
// 시스템 거래건 등록
|
// 시스템 거래건 등록
|
||||||
registerAuction();
|
registerAuction($rng);
|
||||||
//전방설정
|
//전방설정
|
||||||
foreach (getAllNationStaticInfo() as $nation) {
|
foreach (getAllNationStaticInfo() as $nation) {
|
||||||
if ($nation['level'] <= 0) {
|
if ($nation['level'] <= 0) {
|
||||||
@@ -522,7 +521,7 @@ function postUpdateMonthly()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function checkWander()
|
function checkWander(RandUtil $rng)
|
||||||
{
|
{
|
||||||
$db = DB::db();
|
$db = DB::db();
|
||||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||||
@@ -536,7 +535,7 @@ function checkWander()
|
|||||||
if ($wanderCmd->hasFullConditionMet()) {
|
if ($wanderCmd->hasFullConditionMet()) {
|
||||||
$logger = $wanderer->getLogger();
|
$logger = $wanderer->getLogger();
|
||||||
$logger->pushGeneralActionLog('초반 제한후 방랑군은 자동 해산됩니다.', ActionLogger::PLAIN);
|
$logger->pushGeneralActionLog('초반 제한후 방랑군은 자동 해산됩니다.', ActionLogger::PLAIN);
|
||||||
$wanderCmd->run();
|
$wanderCmd->run($rng);
|
||||||
$wanderCmd->setNextAvailable();
|
$wanderCmd->setNextAvailable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -553,6 +552,9 @@ function updateNationState()
|
|||||||
|
|
||||||
$history = array();
|
$history = array();
|
||||||
$admin = $gameStor->getValues(['killturn', 'year', 'month', 'fiction', 'startyear', 'show_img_level', 'turnterm', 'turntime']);
|
$admin = $gameStor->getValues(['killturn', 'year', 'month', 'fiction', 'startyear', 'show_img_level', 'turnterm', 'turntime']);
|
||||||
|
$year = $admin['year'];
|
||||||
|
$month = $admin['month'];
|
||||||
|
$startYear = $admin['startyear'];
|
||||||
|
|
||||||
$assemblerCnts = [];
|
$assemblerCnts = [];
|
||||||
foreach ($db->queryAllLists('SELECT nation,count(no) FROM general WHERE npc = 5 GROUP BY nation') as [$nationID, $assemblerCnt]) {
|
foreach ($db->queryAllLists('SELECT nation,count(no) FROM general WHERE npc = 5 GROUP BY nation') as [$nationID, $assemblerCnt]) {
|
||||||
@@ -561,7 +563,9 @@ function updateNationState()
|
|||||||
|
|
||||||
foreach ($db->query('SELECT nation,name,level,tech,aux FROM nation') as $nation) {
|
foreach ($db->query('SELECT nation,name,level,tech,aux FROM nation') as $nation) {
|
||||||
//TODO: level이 진관수이소중대특 체계를 벗어날 수 있음
|
//TODO: level이 진관수이소중대특 체계를 벗어날 수 있음
|
||||||
$citycount = $db->queryFirstField('SELECT count(*) FROM city WHERE nation=%i AND level>=4', $nation['nation']);
|
$nationID = $nation['nation'];
|
||||||
|
$citycount = $db->queryFirstField('SELECT count(*) FROM city WHERE nation=%i AND level>=4', $nationID);
|
||||||
|
|
||||||
|
|
||||||
if ($citycount == 0) {
|
if ($citycount == 0) {
|
||||||
$nationlevel = 0; // 방랑군
|
$nationlevel = 0; // 방랑군
|
||||||
@@ -595,26 +599,26 @@ function updateNationState()
|
|||||||
switch ($nationlevel) {
|
switch ($nationlevel) {
|
||||||
case 7:
|
case 7:
|
||||||
$josaUl = JosaUtil::pick(getNationLevel($nationlevel), '을');
|
$josaUl = JosaUtil::pick(getNationLevel($nationlevel), '을');
|
||||||
$history[] = "<C>●</>{$admin['year']}년 {$admin['month']}월:<Y><b>【작위】</b></><D><b>{$nation['name']}</b></>의 군주가 <Y>" . getNationLevel($nationlevel) . "</>{$josaUl} 자칭하였습니다.";
|
$history[] = "<C>●</>{$year}년 {$month}월:<Y><b>【작위】</b></><D><b>{$nation['name']}</b></>의 군주가 <Y>" . getNationLevel($nationlevel) . "</>{$josaUl} 자칭하였습니다.";
|
||||||
pushNationHistoryLog($nation['nation'], ["<C>●</>{$admin['year']}년 {$admin['month']}월:<D><b>{$nation['name']}</b></>의 군주가 <Y>" . getNationLevel($nationlevel) . "</>{$josaUl} 자칭"]);
|
pushNationHistoryLog($nation['nation'], ["<C>●</>{$year}년 {$month}월:<D><b>{$nation['name']}</b></>의 군주가 <Y>" . getNationLevel($nationlevel) . "</>{$josaUl} 자칭"]);
|
||||||
$auxVal = Json::decode($nation['aux']);
|
$auxVal = Json::decode($nation['aux']);
|
||||||
$auxVal['can_국기변경'] = 1;
|
$auxVal['can_국기변경'] = 1;
|
||||||
$auxVal['can_국호변경'] = 1;
|
$auxVal['can_국호변경'] = 1;
|
||||||
$updateVals['aux'] = Json::encode($auxVal);
|
$updateVals['aux'] = Json::encode($auxVal);
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
$history[] = "<C>●</>{$admin['year']}년 {$admin['month']}월:<Y><b>【작위】</b></><D><b>{$nation['name']}</b></>의 군주가 <Y>" . getNationLevel($nationlevel) . "</>에 등극하였습니다.";
|
$history[] = "<C>●</>{$year}년 {$month}월:<Y><b>【작위】</b></><D><b>{$nation['name']}</b></>의 군주가 <Y>" . getNationLevel($nationlevel) . "</>에 등극하였습니다.";
|
||||||
pushNationHistoryLog($nation['nation'], ["<C>●</>{$admin['year']}년 {$admin['month']}월:<D><b>{$nation['name']}</b></>의 군주가 <Y>" . getNationLevel($nationlevel) . "</>에 등극"]);
|
pushNationHistoryLog($nation['nation'], ["<C>●</>{$year}년 {$month}월:<D><b>{$nation['name']}</b></>의 군주가 <Y>" . getNationLevel($nationlevel) . "</>에 등극"]);
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
case 4:
|
case 4:
|
||||||
case 3:
|
case 3:
|
||||||
$history[] = "<C>●</>{$admin['year']}년 {$admin['month']}월:<Y><b>【작위】</b></><D><b>{$nation['name']}</b></>의 군주가 <Y>" . getNationLevel($nationlevel) . "</>에 임명되었습니다.";
|
$history[] = "<C>●</>{$year}년 {$month}월:<Y><b>【작위】</b></><D><b>{$nation['name']}</b></>의 군주가 <Y>" . getNationLevel($nationlevel) . "</>에 임명되었습니다.";
|
||||||
pushNationHistoryLog($nation['nation'], ["<C>●</>{$admin['year']}년 {$admin['month']}월:<D><b>{$nation['name']}</b></>의 군주가 <Y>" . getNationLevel($nationlevel) . "</>에 임명됨"]);
|
pushNationHistoryLog($nation['nation'], ["<C>●</>{$year}년 {$month}월:<D><b>{$nation['name']}</b></>의 군주가 <Y>" . getNationLevel($nationlevel) . "</>에 임명됨"]);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
$history[] = "<C>●</>{$admin['year']}년 {$admin['month']}월:<Y><b>【작위】</b></><D><b>{$nation['name']}</b></>의 군주가 독립하여 <Y>" . getNationLevel($nationlevel) . "</>로 나섰습니다.";
|
$history[] = "<C>●</>{$year}년 {$month}월:<Y><b>【작위】</b></><D><b>{$nation['name']}</b></>의 군주가 독립하여 <Y>" . getNationLevel($nationlevel) . "</>로 나섰습니다.";
|
||||||
pushNationHistoryLog($nation['nation'], ["<C>●</>{$admin['year']}년 {$admin['month']}월:<D><b>{$nation['name']}</b></>의 군주가 <Y>" . getNationLevel($nationlevel) . "</>로 나서다"]);
|
pushNationHistoryLog($nation['nation'], ["<C>●</>{$year}년 {$month}월:<D><b>{$nation['name']}</b></>의 군주가 <Y>" . getNationLevel($nationlevel) . "</>로 나서다"]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -649,7 +653,6 @@ function updateNationState()
|
|||||||
|
|
||||||
$uniqueLotteryWeightList = [];
|
$uniqueLotteryWeightList = [];
|
||||||
|
|
||||||
[$startYear, $year] = $gameStor->getValuesAsArray(['startyear', 'year']);
|
|
||||||
$relYear = $year - $startYear;
|
$relYear = $year - $startYear;
|
||||||
$maxTrialCountByYear = 1;
|
$maxTrialCountByYear = 1;
|
||||||
foreach (GameConst::$maxUniqueItemLimit as $tmpVals) {
|
foreach (GameConst::$maxUniqueItemLimit as $tmpVals) {
|
||||||
@@ -685,20 +688,37 @@ function updateNationState()
|
|||||||
$score += 15;
|
$score += 15;
|
||||||
}
|
}
|
||||||
|
|
||||||
$score *= 2**$trialCnt;
|
$score *= 2 ** $trialCnt;
|
||||||
|
|
||||||
$uniqueLotteryWeightList[$nationGen->getID()] = [$nationGen, $score];
|
$uniqueLotteryWeightList[$nationGen->getID()] = [$nationGen, $score];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$nationLevelUpRNG = new RandUtil(new LiteHashDRBG(Util::simpleSerialize(
|
||||||
|
UniqueConst::$hiddenSeed,
|
||||||
|
'nationLevelUp',
|
||||||
|
$year,
|
||||||
|
$month,
|
||||||
|
$nationID
|
||||||
|
)));
|
||||||
|
|
||||||
foreach (Util::range($levelDiff) as $idx) {
|
foreach (Util::range($levelDiff) as $idx) {
|
||||||
if (!$uniqueLotteryWeightList) {
|
if (!$uniqueLotteryWeightList) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @var General */
|
/** @var General */
|
||||||
$winnerObj = Util::choiceRandomUsingWeightPair($uniqueLotteryWeightList);
|
$winnerObj = $nationLevelUpRNG->choiceUsingWeightPair($uniqueLotteryWeightList);
|
||||||
unset($uniqueLotteryWeightList[$winnerObj->getID()]);
|
unset($uniqueLotteryWeightList[$winnerObj->getID()]);
|
||||||
giveRandomUniqueItem($winnerObj, '작위보상');
|
|
||||||
|
$givenUniqueRNG = new RandUtil(new LiteHashDRBG(Util::simpleSerialize(
|
||||||
|
UniqueConst::$hiddenSeed,
|
||||||
|
'givenUnique',
|
||||||
|
$year,
|
||||||
|
$month,
|
||||||
|
$nationID,
|
||||||
|
$winnerObj->getID(),
|
||||||
|
)));
|
||||||
|
giveRandomUniqueItem($givenUniqueRNG, $winnerObj, '작위보상');
|
||||||
$winnerObj->applyDB($db);
|
$winnerObj->applyDB($db);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -724,9 +744,18 @@ function updateNationState()
|
|||||||
if ($assemblerCnt < $maxAssemblerCnt) {
|
if ($assemblerCnt < $maxAssemblerCnt) {
|
||||||
$lastAssemblerID = $gameStor->assembler_id ?? 0;
|
$lastAssemblerID = $gameStor->assembler_id ?? 0;
|
||||||
|
|
||||||
|
$troopLeaderRng = new RandUtil(new LiteHashDRBG(Util::simpleSerialize(
|
||||||
|
UniqueConst::$hiddenSeed,
|
||||||
|
'troopLeader',
|
||||||
|
$year,
|
||||||
|
$month,
|
||||||
|
$nationID
|
||||||
|
)));
|
||||||
|
|
||||||
while ($assemblerCnt < $maxAssemblerCnt) {
|
while ($assemblerCnt < $maxAssemblerCnt) {
|
||||||
$lastAssemblerID += 1;
|
$lastAssemblerID += 1;
|
||||||
$npcObj = new Scenario\GeneralBuilder(
|
$npcObj = new Scenario\GeneralBuilder(
|
||||||
|
$troopLeaderRng,
|
||||||
sprintf('부대장%4d', $lastAssemblerID),
|
sprintf('부대장%4d', $lastAssemblerID),
|
||||||
false,
|
false,
|
||||||
null,
|
null,
|
||||||
@@ -1184,7 +1213,8 @@ function checkEmperior()
|
|||||||
'aux' => $statGeneral['aux']
|
'aux' => $statGeneral['aux']
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$history = ["<C>●</>{$admin['year']}년 {$admin['month']}월:<Y><b>【통일】</b></><D><b>{$nation['name']}</b></>{$josaYi} 전토를 통일하였습니다."];
|
$hiddenSeed = UniqueConst::$hiddenSeed;
|
||||||
|
$history = ["<C>●</>{$admin['year']}년 {$admin['month']}월:<Y><b>【통일】</b></><D><b>{$nation['name']}</b></>{$josaYi} 전토를 통일하였습니다. <span class='hidden_but_copyable'>(서버시드: $hiddenSeed})</span>"];
|
||||||
pushGlobalHistoryLog($history, $admin['year'], $admin['month']);
|
pushGlobalHistoryLog($history, $admin['year'], $admin['month']);
|
||||||
|
|
||||||
//연감 월결산
|
//연감 월결산
|
||||||
@@ -1202,3 +1232,26 @@ function updateMaxDomesticCritical(General $general, $score)
|
|||||||
$general->setInheritancePoint(InheritanceKey::max_domestic_critical, $maxDomesticCritical);
|
$general->setInheritancePoint(InheritanceKey::max_domestic_critical, $maxDomesticCritical);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function genGenericUniqueRNG(int $year, int $month, int $generalID): RandUtil
|
||||||
|
{
|
||||||
|
return new RandUtil(new LiteHashDRBG(Util::simpleSerialize(
|
||||||
|
UniqueConst::$hiddenSeed,
|
||||||
|
'unique',
|
||||||
|
$year,
|
||||||
|
$month,
|
||||||
|
$generalID
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
function genGenericUniqueRNGFromGeneral(General $general): RandUtil
|
||||||
|
{
|
||||||
|
$logger = $general->getLogger();
|
||||||
|
if (!$logger) {
|
||||||
|
throw new \Exception('정식 초기화된 객체가 아닙니다.');
|
||||||
|
}
|
||||||
|
$year = $logger->getYear();
|
||||||
|
$month = $logger->getMonth();
|
||||||
|
$generalID = $general->getID();
|
||||||
|
return genGenericUniqueRNG($year, $month, $generalID);
|
||||||
|
}
|
||||||
|
|||||||
@@ -90,8 +90,8 @@ function pushAuctionLog($log) {
|
|||||||
pushRawFileLog(__DIR__."/logs/".UniqueConst::$serverID."/_auctionlog.txt", $log);
|
pushRawFileLog(__DIR__."/logs/".UniqueConst::$serverID."/_auctionlog.txt", $log);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAuctionLogRecent(int $count) {
|
function getAuctionLogRecent(int $count): array {
|
||||||
return join('<br>', array_reverse(getFormattedFileLogRecent(__DIR__."/logs/".UniqueConst::$serverID."/_auctionlog.txt", $count, 300)));
|
return array_reverse(getRawFileLogRecent(__DIR__."/logs/".UniqueConst::$serverID."/_auctionlog.txt", $count, 300));
|
||||||
}
|
}
|
||||||
|
|
||||||
//DB-based
|
//DB-based
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ namespace sammo;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 내정 커맨드 사용시 성공 확률 계산
|
* 내정 커맨드 사용시 성공 확률 계산
|
||||||
*
|
*
|
||||||
* @param General $general 장수 정보
|
* @param General $general 장수 정보
|
||||||
* @param string $type 내정 커맨드 타입, 'leadership' = 통솔 기반, 'strength' = 무력 기반, 'intel' = 지력 기반
|
* @param string $type 내정 커맨드 타입, 'leadership' = 통솔 기반, 'strength' = 무력 기반, 'intel' = 지력 기반
|
||||||
*
|
*
|
||||||
* @return array 계산된 실패, 성공 확률 ('success' => 성공 확률, 'fail' => 실패 확률)
|
* @return array 계산된 실패, 성공 확률 ('success' => 성공 확률, 'fail' => 실패 확률)
|
||||||
*/
|
*/
|
||||||
function CriticalRatioDomestic(General $general, string $type) {
|
function CriticalRatioDomestic(General $general, string $type) {
|
||||||
@@ -24,7 +24,7 @@ function CriticalRatioDomestic(General $general, string $type) {
|
|||||||
506040(33%/30%), 505050(43%/40%), 504060(50%/50%)
|
506040(33%/30%), 505050(43%/40%), 504060(50%/50%)
|
||||||
|
|
||||||
* 통솔 내정 기준
|
* 통솔 내정 기준
|
||||||
756510(25%/22%), 707010(31%/28%), 657510(38%,35%),
|
756510(25%/22%), 707010(31%/28%), 657510(38%,35%),
|
||||||
505050(50%,50%), 107070(50%,50%)
|
505050(50%,50%), 107070(50%,50%)
|
||||||
*/
|
*/
|
||||||
switch($type) {
|
switch($type) {
|
||||||
@@ -60,13 +60,12 @@ function calcLeadershipBonus($officerLevel, $nationLevel):int{
|
|||||||
return $lbonus;
|
return $lbonus;
|
||||||
}
|
}
|
||||||
|
|
||||||
function CriticalScoreEx(string $type):float {
|
function CriticalScoreEx(RandUtil $rng, string $type):float {
|
||||||
if ($type == 'success') {
|
if ($type == 'success') {
|
||||||
return Util::randRange(2.2, 3.0);
|
return $rng->nextRange(2.2, 3.0);
|
||||||
}
|
}
|
||||||
if ($type == 'fail') {
|
if ($type == 'fail') {
|
||||||
return Util::randRange(0.2, 0.4);
|
return $rng->nextRange(0.2, 0.4);
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+11
-10
@@ -60,7 +60,8 @@ function chiefTurnTable()
|
|||||||
";
|
";
|
||||||
}
|
}
|
||||||
|
|
||||||
function templateLimitMsg(string $turntime): string{
|
function templateLimitMsg(string $turntime): string
|
||||||
|
{
|
||||||
return "이미 너무 많은 접속을 하셨습니다. 다음 턴에 다시 시도해주세요. (턴시간: {$turntime})";
|
return "이미 너무 많은 접속을 하셨습니다. 다음 턴에 다시 시도해주세요. (턴시간: {$turntime})";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,7 +130,7 @@ function allButton(bool $seizeNPCMode, array $opts = [])
|
|||||||
$site = "a_npcList.php";
|
$site = "a_npcList.php";
|
||||||
$call = "빙의일람";
|
$call = "빙의일람";
|
||||||
} else {
|
} else {
|
||||||
$site = "a_vote.php";
|
$site = "v_vote.php";
|
||||||
$call = "설문조사";
|
$call = "설문조사";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,7 +166,7 @@ function commandButton(array $opts = [])
|
|||||||
'color' => '#000000'
|
'color' => '#000000'
|
||||||
];
|
];
|
||||||
|
|
||||||
$bgColor = Util::array_get($nation['color']) ?: '#000000';
|
$bgColor = $nation['color'] ?? '#000000';
|
||||||
$fgColor = newColor($bgColor);
|
$fgColor = newColor($bgColor);
|
||||||
|
|
||||||
$templates = new \League\Plates\Engine(__DIR__ . '/templates');
|
$templates = new \League\Plates\Engine(__DIR__ . '/templates');
|
||||||
@@ -173,16 +174,16 @@ function commandButton(array $opts = [])
|
|||||||
$permission = checkSecretPermission($me);
|
$permission = checkSecretPermission($me);
|
||||||
$btnClassForTournament = $opts['btnClass'];
|
$btnClassForTournament = $opts['btnClass'];
|
||||||
if ($opts['isTournamentApplicationOpen']) {
|
if ($opts['isTournamentApplicationOpen']) {
|
||||||
if ($btnClassForTournament != 'dropdown-item') {
|
if ($btnClassForTournament != 'dropdown-item') {
|
||||||
$btnClassForTournament = 'toolbarButton2';
|
$btnClassForTournament = 'toolbarButton2';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$btnClassForBetting = $opts['btnClass'];
|
$btnClassForBetting = $opts['btnClass'];
|
||||||
if ($opts['isBettingActive']) {
|
if ($opts['isBettingActive']) {
|
||||||
if ($btnClassForTournament != 'dropdown-item') {
|
if ($btnClassForTournament != 'dropdown-item') {
|
||||||
$btnClassForBetting = 'toolbarButton2';
|
$btnClassForBetting = 'toolbarButton2';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($permission >= 1) {
|
if ($permission >= 1) {
|
||||||
@@ -246,7 +247,7 @@ function getMapHtml(?string $mapName = null)
|
|||||||
{
|
{
|
||||||
$templates = new \League\Plates\Engine(__DIR__ . '/templates');
|
$templates = new \League\Plates\Engine(__DIR__ . '/templates');
|
||||||
|
|
||||||
if($mapName === null){
|
if ($mapName === null) {
|
||||||
$mapName = GameConst::$mapName;
|
$mapName = GameConst::$mapName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -513,7 +513,7 @@ function getOutcome(float $billRate, array $generalList) {
|
|||||||
return $outcome;
|
return $outcome;
|
||||||
}
|
}
|
||||||
|
|
||||||
function tradeRate() {
|
function tradeRate(RandUtil $rng) {
|
||||||
$db = DB::db();
|
$db = DB::db();
|
||||||
|
|
||||||
foreach($db->query('SELECT city,level FROM city') as $city){
|
foreach($db->query('SELECT city,level FROM city') as $city){
|
||||||
@@ -528,8 +528,8 @@ function tradeRate() {
|
|||||||
7=>0.8,
|
7=>0.8,
|
||||||
8=>1
|
8=>1
|
||||||
][$city['level']];
|
][$city['level']];
|
||||||
if($prob > 0 && Util::randBool($prob)) {
|
if($prob > 0 && $rng->nextBool($prob)) {
|
||||||
$trade = Util::randRangeInt(95, 105);
|
$trade = $rng->nextRangeInt(95, 105);
|
||||||
} else {
|
} else {
|
||||||
$trade = null;
|
$trade = null;
|
||||||
}
|
}
|
||||||
@@ -539,7 +539,7 @@ function tradeRate() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function disaster() {
|
function disaster(RandUtil $rng) {
|
||||||
$db = DB::db();
|
$db = DB::db();
|
||||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||||
|
|
||||||
@@ -560,7 +560,7 @@ function disaster() {
|
|||||||
10=>0
|
10=>0
|
||||||
];
|
];
|
||||||
|
|
||||||
$isGood = Util::randBool($boomingRate[$month]);
|
$isGood = $rng->nextBool($boomingRate[$month]);
|
||||||
|
|
||||||
|
|
||||||
$targetCityList = [];
|
$targetCityList = [];
|
||||||
@@ -575,7 +575,7 @@ function disaster() {
|
|||||||
$raiseProp = 0.06 - ($city['secu'] / $city['secu_max']) * 0.05; // 1 ~ 6%
|
$raiseProp = 0.06 - ($city['secu'] / $city['secu_max']) * 0.05; // 1 ~ 6%
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Util::randBool($raiseProp)) {
|
if($rng->nextBool($raiseProp)) {
|
||||||
$targetCityList[] = $city;
|
$targetCityList[] = $city;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -621,7 +621,7 @@ function disaster() {
|
|||||||
10 => null
|
10 => null
|
||||||
];
|
];
|
||||||
|
|
||||||
[$logTitle, $stateCode, $logBody] = Util::choiceRandom(($isGood?$boomingTextList:$disasterTextList)[$month]);
|
[$logTitle, $stateCode, $logBody] = $rng->choice(($isGood?$boomingTextList:$disasterTextList)[$month]);
|
||||||
|
|
||||||
$logger = new ActionLogger(0, 0, $year, $month, false);
|
$logger = new ActionLogger(0, 0, $year, $month, false);
|
||||||
|
|
||||||
@@ -653,7 +653,7 @@ function disaster() {
|
|||||||
$generalListByCity[$city['city']]??[]
|
$generalListByCity[$city['city']]??[]
|
||||||
);
|
);
|
||||||
|
|
||||||
SabotageInjury($generalList, '재난');
|
SabotageInjury($rng, $generalList, '재난');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
|
|||||||
+13
-2
@@ -383,10 +383,12 @@ function getDummyBettingInfo(string $tnmt_type): BettingInfo
|
|||||||
name: $tnmt_type,
|
name: $tnmt_type,
|
||||||
finished: true,
|
finished: true,
|
||||||
selectCnt: 1,
|
selectCnt: 1,
|
||||||
|
isExclusive: null,
|
||||||
reqInheritancePoint: false,
|
reqInheritancePoint: false,
|
||||||
openYearMonth: 0,
|
openYearMonth: 0,
|
||||||
closeYearMonth: 0,
|
closeYearMonth: 0,
|
||||||
candidates: []
|
candidates: [],
|
||||||
|
winner: null,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -425,6 +427,7 @@ function startBetting($type, $unit)
|
|||||||
$candidates[$general['no']] = new \sammo\DTO\SelectItem(
|
$candidates[$general['no']] = new \sammo\DTO\SelectItem(
|
||||||
title: $general['name'],
|
title: $general['name'],
|
||||||
info: "{$statName}: {$general[$statKey]}",
|
info: "{$statName}: {$general[$statKey]}",
|
||||||
|
isHtml: null,
|
||||||
aux: $general
|
aux: $general
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -436,10 +439,12 @@ function startBetting($type, $unit)
|
|||||||
name: $typeText,
|
name: $typeText,
|
||||||
finished: false,
|
finished: false,
|
||||||
selectCnt: 1,
|
selectCnt: 1,
|
||||||
|
isExclusive: null,
|
||||||
reqInheritancePoint: false,
|
reqInheritancePoint: false,
|
||||||
openYearMonth: $openYearMonth,
|
openYearMonth: $openYearMonth,
|
||||||
closeYearMonth: $closeYearMonth,
|
closeYearMonth: $closeYearMonth,
|
||||||
candidates: $candidates,
|
candidates: $candidates,
|
||||||
|
winner: null,
|
||||||
));
|
));
|
||||||
|
|
||||||
$betting = new Betting($bettingID);
|
$betting = new Betting($bettingID);
|
||||||
@@ -448,12 +453,18 @@ function startBetting($type, $unit)
|
|||||||
|
|
||||||
$betGold = Util::valueFit(floor((3 + $year - $startyear) * 0.334) * 10, 10);
|
$betGold = Util::valueFit(floor((3 + $year - $startyear) * 0.334) * 10, 10);
|
||||||
|
|
||||||
|
$rng = new RandUtil(new LiteHashDRBG(Util::simpleSerialize(
|
||||||
|
UniqueConst::$hiddenSeed,
|
||||||
|
'OpenBettingTournament',
|
||||||
|
$bettingID,
|
||||||
|
)));
|
||||||
|
|
||||||
$npcList = $db->queryFirstColumn('SELECT no FROM general WHERE npc >= 2 AND gold >= (500 + %i)', $betGold);
|
$npcList = $db->queryFirstColumn('SELECT no FROM general WHERE npc >= 2 AND gold >= (500 + %i)', $betGold);
|
||||||
$npcBet = [];
|
$npcBet = [];
|
||||||
|
|
||||||
$targetList = array_keys($candidates);
|
$targetList = array_keys($candidates);
|
||||||
foreach ($npcList as $npcID) {
|
foreach ($npcList as $npcID) {
|
||||||
$target = Util::choiceRandom($targetList);
|
$target = $rng->choice($targetList);
|
||||||
$npcBet[] = [$npcID, $target];
|
$npcBet[] = [$npcID, $target];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+42
-7
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
namespace sammo;
|
namespace sammo;
|
||||||
|
|
||||||
|
use sammo\DTO\VoteInfo;
|
||||||
|
|
||||||
include "lib.php";
|
include "lib.php";
|
||||||
include "func.php";
|
include "func.php";
|
||||||
|
|
||||||
@@ -86,7 +88,7 @@ $color = "cyan";
|
|||||||
$serverName = UniqueConst::$serverName;
|
$serverName = UniqueConst::$serverName;
|
||||||
$serverCnt = $gameStor->server_cnt;
|
$serverCnt = $gameStor->server_cnt;
|
||||||
|
|
||||||
$auctionCount = $db->queryFirstField('SELECT count(`no`) FROM auction');
|
$auctionCount = $db->queryFirstField('SELECT count(*) FROM ng_auction WHERE finished = 0');
|
||||||
$isTournamentActive = $gameStor->tournament > 0;
|
$isTournamentActive = $gameStor->tournament > 0;
|
||||||
$isTournamentApplicationOpen = $gameStor->tournament == 1;
|
$isTournamentApplicationOpen = $gameStor->tournament == 1;
|
||||||
$isBettingActive = $gameStor->tournament == 6;
|
$isBettingActive = $gameStor->tournament == 6;
|
||||||
@@ -109,6 +111,16 @@ if (!$otherTextInfo) {
|
|||||||
} else {
|
} else {
|
||||||
$otherTextInfo = join(', ', $otherTextInfo);
|
$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>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
@@ -207,13 +219,11 @@ if (!$otherTextInfo) {
|
|||||||
</div>
|
</div>
|
||||||
<div class="s-border-t py-2 col col-6 col-md-4 vote-cell">
|
<div class="s-border-t py-2 col col-6 col-md-4 vote-cell">
|
||||||
<?php
|
<?php
|
||||||
$vote = $gameStor->vote ?: [''];
|
|
||||||
$vote_title = Tag2Code($gameStor->vote_title ?? '-');
|
|
||||||
?>
|
?>
|
||||||
<?php if ($vote[0] == "") : ?>
|
<?php if ($lastVote === null) : ?>
|
||||||
<span style='color:magenta'>진행중 설문 없음</span>
|
<span style='color:magenta'>진행중 설문 없음</span>
|
||||||
<?php else : ?>
|
<?php else : ?>
|
||||||
<span style='color:cyan'>설문 진행중</span> : <span><?= $vote_title ?></span>
|
<span style='color:cyan'>설문 진행중</span> : <span><?= $lastVote->title ?></span>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -272,7 +282,21 @@ if (!$otherTextInfo) {
|
|||||||
<div id="nation-position"><?php myNationInfo($generalObj); ?></div>
|
<div id="nation-position"><?php myNationInfo($generalObj); ?></div>
|
||||||
<div id="general-position"><?php generalInfo($generalObj); ?></div>
|
<div id="general-position"><?php generalInfo($generalObj); ?></div>
|
||||||
<div id="generalCommandButton" class="row gx-0">
|
<div id="generalCommandButton" class="row gx-0">
|
||||||
<div class="buttonPlate bg2"><?= commandButton(['btnClass' => 'btn btn-sammo-nation', 'isTournamentApplicationOpen' => $isTournamentApplicationOpen, 'isBettingActive' => $isBettingActive]) ?></div>
|
<div class="buttonPlate bg2">
|
||||||
|
<?= commandButton([
|
||||||
|
'splitBtnBegin' => '<div class="btn-group">',
|
||||||
|
'splitBtnEnd' => '</div>',
|
||||||
|
'splitZoneSign' => '<button type="button" class="btn btn-sammo-nation dropdown-toggle dropdown-toggle-split" data-bs-toggle="dropdown" aria-expanded="false"><span class="visually-hidden">Toggle Dropdown</span></button>',
|
||||||
|
'splitZoneBegin' => '<ul class="dropdown-menu dropdown-menu-end">',
|
||||||
|
'splitZoneEnd' => '</ul>',
|
||||||
|
'splitSubBtnBegin' => '<li>',
|
||||||
|
'splitSubBtnEnd' => '</li>',
|
||||||
|
'btnClass' => 'btn btn-sammo-nation',
|
||||||
|
'btnSplitClass' => 'dropdown-item',
|
||||||
|
'isTournamentApplicationOpen' => $isTournamentApplicationOpen,
|
||||||
|
'isBettingActive' => $isBettingActive
|
||||||
|
])
|
||||||
|
?></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -372,7 +396,18 @@ if (!$otherTextInfo) {
|
|||||||
국가 메뉴
|
국가 메뉴
|
||||||
</div>
|
</div>
|
||||||
<ul class="dropdown-menu" aria-labelledby="navbarNation" id="navbarNationItems">
|
<ul class="dropdown-menu" aria-labelledby="navbarNation" id="navbarNationItems">
|
||||||
<?= commandButton(['btnBegin' => '<li>', 'btnEnd' => '</li>', 'btnClass' => 'dropdown-item', 'isTournamentApplicationOpen' => $isTournamentApplicationOpen, 'isBettingActive' => $isBettingActive]) ?>
|
<?= commandButton([
|
||||||
|
'btnBegin' => '<li>',
|
||||||
|
'btnEnd' => '</li>',
|
||||||
|
'splitMainBegin' => '<div class="d-none">',
|
||||||
|
'splitMainEnd' => '</div>',
|
||||||
|
'splitSubBtnBegin' => '<li>',
|
||||||
|
'splitSubBtnEnd' => '</li>',
|
||||||
|
'btnClass' => 'dropdown-item',
|
||||||
|
'btnSplitClass' => 'dropdown-item',
|
||||||
|
'isTournamentApplicationOpen' => $isTournamentApplicationOpen,
|
||||||
|
'isBettingActive' => $isBettingActive
|
||||||
|
]) ?>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item dropup">
|
<li class="nav-item dropup">
|
||||||
|
|||||||
@@ -110,16 +110,23 @@ foreach($db->queryFirstColumn('SELECT pick_result FROM select_npc_token WHERE `o
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$rng = new RandUtil(new LiteHashDRBG(Util::simpleSerialize(
|
||||||
|
UniqueConst::$hiddenSeed,
|
||||||
|
'SelectNPCToken',
|
||||||
|
$userID,
|
||||||
|
$now,
|
||||||
|
)));
|
||||||
|
|
||||||
$pickLimit = min(count($candidates), 5);
|
$pickLimit = min(count($candidates), 5);
|
||||||
|
|
||||||
while(count($pickResult) < $pickLimit){
|
while(count($pickResult) < $pickLimit){
|
||||||
$generalID = Util::choiceRandomUsingWeight($weight);
|
$generalID = $rng->choiceUsingWeight($weight);
|
||||||
if(!key_exists($generalID, $pickResult)){
|
if(!key_exists($generalID, $pickResult)){
|
||||||
$pickResult[$generalID] = $candidates[$generalID];
|
$pickResult[$generalID] = $candidates[$generalID];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$newNonce = mt_rand(0, 0xfffffff);
|
$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));
|
||||||
|
|||||||
@@ -74,9 +74,13 @@ if($tokens){
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$rng = new RandUtil(new LiteHashDRBG(Util::simpleSerialize(
|
||||||
|
UniqueConst::$hiddenSeed, 'selectPool', $userID, $now
|
||||||
|
)));
|
||||||
|
|
||||||
$pick = [];
|
$pick = [];
|
||||||
$valid_until = null;
|
$valid_until = null;
|
||||||
foreach(pickGeneralFromPool($db, $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);
|
putInfoText($info);
|
||||||
|
|||||||
+6
-6
@@ -4,8 +4,6 @@ namespace sammo;
|
|||||||
include "lib.php";
|
include "lib.php";
|
||||||
include "func.php";
|
include "func.php";
|
||||||
|
|
||||||
WebUtil::requireAJAX();
|
|
||||||
|
|
||||||
$session = Session::requireLogin([])->setReadOnly();
|
$session = Session::requireLogin([])->setReadOnly();
|
||||||
|
|
||||||
if(!class_exists('\\sammo\\DB')){
|
if(!class_exists('\\sammo\\DB')){
|
||||||
@@ -144,7 +142,7 @@ $autorun_user = $autorun_user_minutes?[
|
|||||||
if($reserve_open){
|
if($reserve_open){
|
||||||
$reserve_open = new \DateTime($reserve_open);
|
$reserve_open = new \DateTime($reserve_open);
|
||||||
$db = DB::db();
|
$db = DB::db();
|
||||||
|
|
||||||
if (!$db->queryFirstField("SHOW TABLES LIKE 'storage'")) {
|
if (!$db->queryFirstField("SHOW TABLES LIKE 'storage'")) {
|
||||||
$clearResult = ResetHelper::clearDB();
|
$clearResult = ResetHelper::clearDB();
|
||||||
if(!$clearResult['result']){
|
if(!$clearResult['result']){
|
||||||
@@ -159,7 +157,9 @@ if($reserve_open){
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$scenarioObj = new Scenario($scenario, true);
|
$rng = new RandUtil(new LiteHashDRBG(random_bytes(16)));
|
||||||
|
|
||||||
|
$scenarioObj = new Scenario($rng, $scenario, true);
|
||||||
$open_date = $reserve_open->format('Y-m-d H:i:s');
|
$open_date = $reserve_open->format('Y-m-d H:i:s');
|
||||||
|
|
||||||
$reserveInfo = [
|
$reserveInfo = [
|
||||||
@@ -179,14 +179,14 @@ if($reserve_open){
|
|||||||
'autorun_user'=>$autorun_user
|
'autorun_user'=>$autorun_user
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
if($pre_reserve_open){
|
if($pre_reserve_open){
|
||||||
$pre_reserve_open = new \DateTime($pre_reserve_open);
|
$pre_reserve_open = new \DateTime($pre_reserve_open);
|
||||||
$open_date = $pre_reserve_open->format('Y-m-d H:i:s');
|
$open_date = $pre_reserve_open->format('Y-m-d H:i:s');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
$db->delete('reserved_open', true);
|
$db->delete('reserved_open', true);
|
||||||
$db->insert('reserved_open', [
|
$db->insert('reserved_open', [
|
||||||
'options'=>Json::encode($reserveInfo),
|
'options'=>Json::encode($reserveInfo),
|
||||||
|
|||||||
+35
-26
@@ -241,34 +241,43 @@ function do추방(General $general, int $myOfficerLevel):?string{
|
|||||||
}
|
}
|
||||||
$general->setVar('troop', 0);
|
$general->setVar('troop', 0);
|
||||||
|
|
||||||
if($general->getNPCType() >= 2 && Util::randBool(GameConst::$npcBanMessageProb)) {
|
if($general->getNPCType() >= 2){
|
||||||
|
$rng = new RandUtil(new LiteHashDRBG(Util::simpleSerialize(
|
||||||
|
UniqueConst::$hiddenSeed,
|
||||||
|
'BanNPC',
|
||||||
|
$env['year'],
|
||||||
|
$env['month'],
|
||||||
|
$general->getID(),
|
||||||
|
)));
|
||||||
|
if ($rng->nextBool(GameConst::$npcBanMessageProb)) {
|
||||||
|
|
||||||
$str = Util::choiceRandom([
|
$str = $rng->choice([
|
||||||
'날 버리다니... 곧 전장에서 복수해주겠다...',
|
'날 버리다니... 곧 전장에서 복수해주겠다...',
|
||||||
'추방이라... 내가 무얼 잘못했단 말인가...',
|
'추방이라... 내가 무얼 잘못했단 말인가...',
|
||||||
'어디 추방해가면서 잘되나 보자... 꼭 복수하겠다...',
|
'어디 추방해가면서 잘되나 보자... 꼭 복수하겠다...',
|
||||||
'인덕이 제일이거늘... 추방이 웬말인가... 저주한다!',
|
'인덕이 제일이거늘... 추방이 웬말인가... 저주한다!',
|
||||||
'날 추방했으니 그 복수로 적국에 정보를 팔아 넘겨야겠군요. 그럼 이만.'
|
'날 추방했으니 그 복수로 적국에 정보를 팔아 넘겨야겠군요. 그럼 이만.'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$src = new MessageTarget(
|
$src = new MessageTarget(
|
||||||
$generalID,
|
$generalID,
|
||||||
$generalName,
|
$generalName,
|
||||||
$nationID,
|
$nationID,
|
||||||
$nation['name'],
|
$nation['name'],
|
||||||
$nation['color'],
|
$nation['color'],
|
||||||
GetImageURL($general->getVar('imgsvr'), $general->getVar('picture'))
|
GetImageURL($general->getVar('imgsvr'), $general->getVar('picture'))
|
||||||
);
|
);
|
||||||
$msg = new Message(
|
$msg = new Message(
|
||||||
Message::MSGTYPE_PUBLIC,
|
Message::MSGTYPE_PUBLIC,
|
||||||
$src,
|
$src,
|
||||||
$src,
|
$src,
|
||||||
$str,
|
$str,
|
||||||
new \DateTime(),
|
new \DateTime(),
|
||||||
new \DateTime('9999-12-31'),
|
new \DateTime('9999-12-31'),
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
$msg->send();
|
$msg->send();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if($env['year'] < $env['startyear']+3) {
|
if($env['year'] < $env['startyear']+3) {
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ foreach(GameConst::$generalPoolAllowOption as $allowOption){
|
|||||||
}
|
}
|
||||||
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);
|
||||||
}
|
}
|
||||||
if(!array_search($personal, GameConst::$availablePersonality)){
|
if(!array_search($personal, GameConst::$availablePersonality)){
|
||||||
Json::die([
|
Json::die([
|
||||||
|
|||||||
@@ -300,12 +300,17 @@ function simulateBattle(
|
|||||||
$rawDefenderList, $rawDefenderCity, $rawDefenderNation,
|
$rawDefenderList, $rawDefenderCity, $rawDefenderNation,
|
||||||
$startYear, $year, $month, $cityRate
|
$startYear, $year, $month, $cityRate
|
||||||
){
|
){
|
||||||
|
|
||||||
|
$warSeed = bin2hex(random_bytes(16));
|
||||||
|
$warRng = new RandUtil(new LiteHashDRBG($warSeed));
|
||||||
|
|
||||||
$attacker = new WarUnitGeneral(
|
$attacker = new WarUnitGeneral(
|
||||||
|
$warRng,
|
||||||
new General($rawAttacker, extractRankVar($rawAttacker), $rawAttackerCity, $rawAttackerNation, $year, $month),
|
new General($rawAttacker, extractRankVar($rawAttacker), $rawAttackerCity, $rawAttackerNation, $year, $month),
|
||||||
$rawAttackerNation,
|
$rawAttackerNation,
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
$city = new WarUnitCity($rawDefenderCity, $rawDefenderNation, $year, $month, $cityRate);
|
$city = new WarUnitCity($warRng, $rawDefenderCity, $rawDefenderNation, $year, $month, $cityRate);
|
||||||
|
|
||||||
$iterDefender = new \ArrayIterator($rawDefenderList);
|
$iterDefender = new \ArrayIterator($rawDefenderList);
|
||||||
$iterDefender->rewind();
|
$iterDefender->rewind();
|
||||||
@@ -316,7 +321,7 @@ function simulateBattle(
|
|||||||
$defenderRice = 0;
|
$defenderRice = 0;
|
||||||
|
|
||||||
$getNextDefender = function(?WarUnit $prevDefender, bool $reqNext)
|
$getNextDefender = function(?WarUnit $prevDefender, bool $reqNext)
|
||||||
use ($iterDefender, $rawDefenderCity, $rawDefenderNation, $year, $month, &$battleResult, &$defenderRice) {
|
use ($warRng, $iterDefender, $rawDefenderCity, $rawDefenderNation, $year, $month, &$battleResult, &$defenderRice) {
|
||||||
if($prevDefender !== null){
|
if($prevDefender !== null){
|
||||||
$prevDefender->getLogger()->rollback();
|
$prevDefender->getLogger()->rollback();
|
||||||
$battleResult[] = $prevDefender;
|
$battleResult[] = $prevDefender;
|
||||||
@@ -341,6 +346,7 @@ function simulateBattle(
|
|||||||
$defenderRice += $defenderObj->getVar('rice');
|
$defenderRice += $defenderObj->getVar('rice');
|
||||||
|
|
||||||
$retVal = new WarUnitGeneral(
|
$retVal = new WarUnitGeneral(
|
||||||
|
$warRng,
|
||||||
$defenderObj,
|
$defenderObj,
|
||||||
$rawDefenderNation,
|
$rawDefenderNation,
|
||||||
false
|
false
|
||||||
@@ -349,7 +355,7 @@ function simulateBattle(
|
|||||||
return $retVal;
|
return $retVal;
|
||||||
};
|
};
|
||||||
|
|
||||||
$conquerCity = processWar_NG($attacker, $getNextDefender, $city, $year - $startYear);
|
$conquerCity = processWar_NG($warSeed, $attacker, $getNextDefender, $city, $year - $startYear);
|
||||||
|
|
||||||
$rawDefenderCity = $city->getRaw();
|
$rawDefenderCity = $city->getRaw();
|
||||||
$updateAttackerNation = [];
|
$updateAttackerNation = [];
|
||||||
|
|||||||
+27
-14
@@ -3,9 +3,10 @@
|
|||||||
namespace sammo;
|
namespace sammo;
|
||||||
|
|
||||||
|
|
||||||
function processWar(General $attackerGeneral, array $rawAttackerNation, array $rawDefenderCity)
|
function processWar(string $warSeed, General $attackerGeneral, array $rawAttackerNation, array $rawDefenderCity)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
$rng = new RandUtil(new LiteHashDRBG($warSeed));
|
||||||
$db = DB::db();
|
$db = DB::db();
|
||||||
|
|
||||||
$attackerNationID = $attackerGeneral->getNationID();
|
$attackerNationID = $attackerGeneral->getNationID();
|
||||||
@@ -30,9 +31,9 @@ function processWar(General $attackerGeneral, array $rawAttackerNation, array $r
|
|||||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||||
[$startYear, $year, $month, $cityRate, $joinMode] = $gameStor->getValuesAsArray(['startyear', 'year', 'month', 'city_rate', 'join_mode']);
|
[$startYear, $year, $month, $cityRate, $joinMode] = $gameStor->getValuesAsArray(['startyear', 'year', 'month', 'city_rate', 'join_mode']);
|
||||||
|
|
||||||
$attacker = new WarUnitGeneral($attackerGeneral, $rawAttackerNation, true);
|
$attacker = new WarUnitGeneral($rng, $attackerGeneral,$rawAttackerNation, true);
|
||||||
|
|
||||||
$city = new WarUnitCity($rawDefenderCity, $rawDefenderNation, $year, $month, $cityRate);
|
$city = new WarUnitCity($rng, $rawDefenderCity, $rawDefenderNation, $year, $month, $cityRate);
|
||||||
|
|
||||||
$defenderIDList = $db->queryFirstColumn('SELECT no FROM general WHERE nation=%i AND city=%i AND nation!=0 and crew > 0 and rice>(crew/100) and train>=defence_train and atmos>=defence_train', $city->getVar('nation'), $city->getVar('city'));
|
$defenderIDList = $db->queryFirstColumn('SELECT no FROM general WHERE nation=%i AND city=%i AND nation!=0 and crew > 0 and rice>(crew/100) and train>=defence_train and atmos>=defence_train', $city->getVar('nation'), $city->getVar('city'));
|
||||||
$defenderList = General::createGeneralObjListFromDB($defenderIDList, null, 2);
|
$defenderList = General::createGeneralObjListFromDB($defenderIDList, null, 2);
|
||||||
@@ -44,7 +45,7 @@ function processWar(General $attackerGeneral, array $rawAttackerNation, array $r
|
|||||||
$iterDefender = new \ArrayIterator($defenderList);
|
$iterDefender = new \ArrayIterator($defenderList);
|
||||||
$iterDefender->rewind();
|
$iterDefender->rewind();
|
||||||
|
|
||||||
$getNextDefender = function (?WarUnit $prevDefender, bool $reqNext) use ($iterDefender, $rawDefenderNation, $rawDefenderCity, $db) {
|
$getNextDefender = function (?WarUnit $prevDefender, bool $reqNext) use ($rng, $iterDefender, $rawDefenderNation, $rawDefenderCity, $db) {
|
||||||
if ($prevDefender !== null) {
|
if ($prevDefender !== null) {
|
||||||
$prevDefender->applyDB($db);
|
$prevDefender->applyDB($db);
|
||||||
}
|
}
|
||||||
@@ -65,6 +66,7 @@ function processWar(General $attackerGeneral, array $rawAttackerNation, array $r
|
|||||||
|
|
||||||
|
|
||||||
$retVal = new WarUnitGeneral(
|
$retVal = new WarUnitGeneral(
|
||||||
|
$rng,
|
||||||
$nextDefender,
|
$nextDefender,
|
||||||
$rawDefenderNation,
|
$rawDefenderNation,
|
||||||
false
|
false
|
||||||
@@ -73,7 +75,7 @@ function processWar(General $attackerGeneral, array $rawAttackerNation, array $r
|
|||||||
return $retVal;
|
return $retVal;
|
||||||
};
|
};
|
||||||
|
|
||||||
$conquerCity = processWar_NG($attacker, $getNextDefender, $city, $year - $startYear);
|
$conquerCity = processWar_NG($warSeed, $attacker, $getNextDefender, $city, $year - $startYear);
|
||||||
|
|
||||||
$attacker->applyDB($db);
|
$attacker->applyDB($db);
|
||||||
|
|
||||||
@@ -206,6 +208,7 @@ function extractBattleOrder(General $general)
|
|||||||
}
|
}
|
||||||
|
|
||||||
function processWar_NG(
|
function processWar_NG(
|
||||||
|
string $warSeed,
|
||||||
WarUnitGeneral $attacker,
|
WarUnitGeneral $attacker,
|
||||||
callable $getNextDefender,
|
callable $getNextDefender,
|
||||||
WarUnitCity $city,
|
WarUnitCity $city,
|
||||||
@@ -228,8 +231,8 @@ function processWar_NG(
|
|||||||
$josaRo = JosaUtil::pick($city->getName(), '로');
|
$josaRo = JosaUtil::pick($city->getName(), '로');
|
||||||
$josaYi = JosaUtil::pick($attacker->getName(), '이');
|
$josaYi = JosaUtil::pick($attacker->getName(), '이');
|
||||||
|
|
||||||
$logger->pushGlobalActionLog("<D><b>{$attacker->getNationVar('name')}</b></>의 <Y>{$attacker->getName()}</>{$josaYi} <G><b>{$city->getName()}</b></>{$josaRo} 진격합니다.");
|
$logger->pushGlobalActionLog("<D><b>{$attacker->getNationVar('name')}</b></>의 <Y>{$attacker->getName()}</>{$josaYi} <G><b>{$city->getName()}</b></>{$josaRo} 진격합니다.<span class='hidden_but_copyable'>(전투시드: {$warSeed})</span>");
|
||||||
$logger->pushGeneralActionLog("<G><b>{$city->getName()}</b></>{$josaRo} <M>진격</>합니다. <1>$date</>");
|
$logger->pushGeneralActionLog("<G><b>{$city->getName()}</b></>{$josaRo} <M>진격</>합니다.<span class='hidden_but_copyable'>(전투시드: {$warSeed})</span> <1>$date</>");
|
||||||
|
|
||||||
$logWritten = false;
|
$logWritten = false;
|
||||||
|
|
||||||
@@ -309,7 +312,7 @@ function processWar_NG(
|
|||||||
$initCaller = $attacker->getGeneral()->getBattleInitSkillTriggerList($attacker);
|
$initCaller = $attacker->getGeneral()->getBattleInitSkillTriggerList($attacker);
|
||||||
$initCaller->merge($defender->getGeneral()->getBattleInitSkillTriggerList($defender));
|
$initCaller->merge($defender->getGeneral()->getBattleInitSkillTriggerList($defender));
|
||||||
|
|
||||||
$initCaller->fire([], [$attacker, $defender]);
|
$initCaller->fire($attacker->rng, [], [$attacker, $defender]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$attacker->beginPhase();
|
$attacker->beginPhase();
|
||||||
@@ -318,7 +321,7 @@ function processWar_NG(
|
|||||||
$battleCaller = $attacker->getGeneral()->getBattlePhaseSkillTriggerList($attacker);
|
$battleCaller = $attacker->getGeneral()->getBattlePhaseSkillTriggerList($attacker);
|
||||||
$battleCaller->merge($defender->getGeneral()->getBattlePhaseSkillTriggerList($defender));
|
$battleCaller->merge($defender->getGeneral()->getBattlePhaseSkillTriggerList($defender));
|
||||||
|
|
||||||
$battleCaller->fire([], [$attacker, $defender]);
|
$battleCaller->fire($attacker->rng, [], [$attacker, $defender]);
|
||||||
|
|
||||||
$deadDefender = $attacker->calcDamage();
|
$deadDefender = $attacker->calcDamage();
|
||||||
$deadAttacker = $defender->calcDamage();
|
$deadAttacker = $defender->calcDamage();
|
||||||
@@ -510,6 +513,16 @@ function ConquerCity(array $admin, General $general, array $city)
|
|||||||
$cityID = $city['city'];
|
$cityID = $city['city'];
|
||||||
$cityName = $city['name'];
|
$cityName = $city['name'];
|
||||||
|
|
||||||
|
$rng = new RandUtil(new LiteHashDRBG(Util::simpleSerialize(
|
||||||
|
UniqueConst::$hiddenSeed,
|
||||||
|
'ConquerCity',
|
||||||
|
$year,
|
||||||
|
$month,
|
||||||
|
$attackerNationID,
|
||||||
|
$attackerID,
|
||||||
|
$cityID
|
||||||
|
)));
|
||||||
|
|
||||||
$defenderNationID = $city['nation'];
|
$defenderNationID = $city['nation'];
|
||||||
$defenderStaticNation = getNationStaticInfo($defenderNationID);
|
$defenderStaticNation = getNationStaticInfo($defenderNationID);
|
||||||
$defenderNationName = $defenderStaticNation['name'];
|
$defenderNationName = $defenderStaticNation['name'];
|
||||||
@@ -577,8 +590,8 @@ function ConquerCity(array $admin, General $general, array $city)
|
|||||||
$loseGeneralGold = 0;
|
$loseGeneralGold = 0;
|
||||||
$loseGeneralRice = 0;
|
$loseGeneralRice = 0;
|
||||||
foreach ($oldNationGenerals as $oldGeneral) {
|
foreach ($oldNationGenerals as $oldGeneral) {
|
||||||
$loseGold = intdiv($oldGeneral->getVar('gold') * (rand() % 30 + 20), 100);
|
$loseGold = Util::toInt($oldGeneral->getVar('gold') * $rng->nextRange(0.2, 0.5));
|
||||||
$loseRice = intdiv($oldGeneral->getVar('rice') * (rand() % 30 + 20), 100);
|
$loseRice = Util::toInt($oldGeneral->getVar('rice') * $rng->nextRange(0.2, 0.5));
|
||||||
$oldGeneral->getLogger()->pushGeneralActionLog(
|
$oldGeneral->getLogger()->pushGeneralActionLog(
|
||||||
"도주하며 금<C>$loseGold</> 쌀<C>$loseRice</>을 분실했습니다.",
|
"도주하며 금<C>$loseGold</> 쌀<C>$loseRice</>을 분실했습니다.",
|
||||||
ActionLogger::PLAIN
|
ActionLogger::PLAIN
|
||||||
@@ -594,7 +607,7 @@ function ConquerCity(array $admin, General $general, array $city)
|
|||||||
$oldGeneral->applyDB($db);
|
$oldGeneral->applyDB($db);
|
||||||
|
|
||||||
//모두 등용장 발부
|
//모두 등용장 발부
|
||||||
if ($admin['join_mode'] != 'onlyRandom' && Util::randBool(0.5)) {
|
if ($admin['join_mode'] != 'onlyRandom' && $rng->nextBool(0.5)) {
|
||||||
$msg = ScoutMessage::buildScoutMessage($attackerID, $oldGeneral->getID());
|
$msg = ScoutMessage::buildScoutMessage($attackerID, $oldGeneral->getID());
|
||||||
if ($msg) {
|
if ($msg) {
|
||||||
$msg->send(true);
|
$msg->send(true);
|
||||||
@@ -603,11 +616,11 @@ function ConquerCity(array $admin, General $general, array $city)
|
|||||||
|
|
||||||
//NPC인 경우 일정 확률로 임관(엔장, 인재, 의병)
|
//NPC인 경우 일정 확률로 임관(엔장, 인재, 의병)
|
||||||
$npcType = $oldGeneral->getNPCType();
|
$npcType = $oldGeneral->getNPCType();
|
||||||
if ($admin['join_mode'] != 'onlyRandom' && 2 <= $npcType && $npcType <= 8 && $npcType != 5 && Util::randBool(GameConst::$joinRuinedNPCProp)) {
|
if ($admin['join_mode'] != 'onlyRandom' && 2 <= $npcType && $npcType <= 8 && $npcType != 5 && $rng->nextBool(GameConst::$joinRuinedNPCProp)) {
|
||||||
$cmd = buildGeneralCommandClass('che_임관', $oldGeneral, $admin, [
|
$cmd = buildGeneralCommandClass('che_임관', $oldGeneral, $admin, [
|
||||||
'destNationID' => $attackerNationID
|
'destNationID' => $attackerNationID
|
||||||
]);
|
]);
|
||||||
$joinTurn = Util::randRangeInt(0, 12);
|
$joinTurn = $rng->nextRangeInt(0, 12);
|
||||||
if ($joinTurn) {
|
if ($joinTurn) {
|
||||||
_setGeneralCommand(buildGeneralCommandClass('che_견문', $oldGeneral, $admin), iterator_to_array(Util::range($joinTurn)));
|
_setGeneralCommand(buildGeneralCommandClass('che_견문', $oldGeneral, $admin), iterator_to_array(Util::range($joinTurn)));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace sammo\API\Auction;
|
||||||
|
|
||||||
|
use sammo\Session;
|
||||||
|
use DateTimeInterface;
|
||||||
|
use sammo\AuctionBuyRice;
|
||||||
|
use sammo\AuctionUniqueItem;
|
||||||
|
use sammo\Validator;
|
||||||
|
use sammo\General;
|
||||||
|
|
||||||
|
class BidBuyRiceAuction extends \sammo\BaseAPI
|
||||||
|
{
|
||||||
|
public function validateArgs(): ?string
|
||||||
|
{
|
||||||
|
$v = new Validator($this->args);
|
||||||
|
$v->rule('required', [
|
||||||
|
'auctionID',
|
||||||
|
'amount',
|
||||||
|
])
|
||||||
|
->rule('int', 'amount')
|
||||||
|
->rule('int', 'auctionID');
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
$auctionID = $this->args['auctionID'];
|
||||||
|
$amount = $this->args['amount'];
|
||||||
|
|
||||||
|
$generalID = $session->generalID;
|
||||||
|
$general = General::createGeneralObjFromDB($generalID);
|
||||||
|
$auction = new AuctionBuyRice($auctionID, $general);
|
||||||
|
$result = $auction->bid($amount, true);
|
||||||
|
|
||||||
|
if (is_string($result)) {
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace sammo\API\Auction;
|
||||||
|
|
||||||
|
use sammo\Session;
|
||||||
|
use DateTimeInterface;
|
||||||
|
use sammo\AuctionSellRice;
|
||||||
|
use sammo\Validator;
|
||||||
|
use sammo\General;
|
||||||
|
|
||||||
|
class BidSellRiceAuction extends \sammo\BaseAPI
|
||||||
|
{
|
||||||
|
public function validateArgs(): ?string
|
||||||
|
{
|
||||||
|
$v = new Validator($this->args);
|
||||||
|
$v->rule('required', [
|
||||||
|
'auctionID',
|
||||||
|
'amount',
|
||||||
|
])
|
||||||
|
->rule('int', 'amount')
|
||||||
|
->rule('int', 'auctionID');
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
$auctionID = $this->args['auctionID'];
|
||||||
|
$amount = $this->args['amount'];
|
||||||
|
|
||||||
|
$generalID = $session->generalID;
|
||||||
|
$general = General::createGeneralObjFromDB($generalID);
|
||||||
|
$auction = new AuctionSellRice($auctionID, $general);
|
||||||
|
$result = $auction->bid($amount, true);
|
||||||
|
|
||||||
|
if (is_string($result)) {
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace sammo\API\Auction;
|
||||||
|
|
||||||
|
use sammo\Session;
|
||||||
|
use DateTimeInterface;
|
||||||
|
use sammo\AuctionUniqueItem;
|
||||||
|
use sammo\Validator;
|
||||||
|
use sammo\GameConst;
|
||||||
|
use sammo\General;
|
||||||
|
|
||||||
|
class BidUniqueAuction extends \sammo\BaseAPI
|
||||||
|
{
|
||||||
|
public function validateArgs(): ?string
|
||||||
|
{
|
||||||
|
$v = new Validator($this->args);
|
||||||
|
$v->rule('required', [
|
||||||
|
'auctionID',
|
||||||
|
'amount',
|
||||||
|
])
|
||||||
|
->rule('int', 'amount')
|
||||||
|
->rule('int', 'auctionID')
|
||||||
|
->rule('boolean', 'extendCloseDate');
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
$auctionID = $this->args['auctionID'];
|
||||||
|
$amount = $this->args['amount'];
|
||||||
|
$tryExtendCloseDate = $this->arg['extendCloseDate'] ?? false;
|
||||||
|
|
||||||
|
$generalID = $session->generalID;
|
||||||
|
$general = General::createGeneralObjFromDB($generalID);
|
||||||
|
$auction = new AuctionUniqueItem($auctionID, $general);
|
||||||
|
$result = $auction->bid($amount, $tryExtendCloseDate);
|
||||||
|
|
||||||
|
if (is_string($result)) {
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,123 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace sammo\API\Auction;
|
||||||
|
|
||||||
|
use sammo\Session;
|
||||||
|
use DateTimeInterface;
|
||||||
|
use sammo\AuctionSellRice;
|
||||||
|
use sammo\DB;
|
||||||
|
use sammo\DTO\AuctionBidItem;
|
||||||
|
use sammo\DTO\AuctionInfo;
|
||||||
|
use sammo\Enums\AuctionType;
|
||||||
|
use sammo\Validator;
|
||||||
|
use sammo\General;
|
||||||
|
use sammo\Json;
|
||||||
|
use sammo\TimeUtil;
|
||||||
|
use sammo\Util;
|
||||||
|
|
||||||
|
use function sammo\getAuctionLogRecent;
|
||||||
|
|
||||||
|
class GetActiveResourceAuctionList extends \sammo\BaseAPI
|
||||||
|
{
|
||||||
|
public function validateArgs(): ?string
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRequiredSessionMode(): int
|
||||||
|
{
|
||||||
|
return static::REQ_GAME_LOGIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag)
|
||||||
|
{
|
||||||
|
$db = DB::db();
|
||||||
|
|
||||||
|
$buyRiceList = [];
|
||||||
|
$sellRiceList = [];
|
||||||
|
/** @var AuctionInfo[] */
|
||||||
|
$auctions = array_map(fn ($raw) => AuctionInfo::fromArray($raw), $db->query(
|
||||||
|
'SELECT * FROM `ng_auction` WHERE `type` IN %ls AND `finished` = 0 ORDER BY `close_date` ASC',
|
||||||
|
[
|
||||||
|
AuctionType::BuyRice->value,
|
||||||
|
AuctionType::SellRice->value,
|
||||||
|
]
|
||||||
|
));
|
||||||
|
|
||||||
|
$recentLogs = getAuctionLogRecent(20);
|
||||||
|
|
||||||
|
|
||||||
|
if (!$auctions) {
|
||||||
|
return [
|
||||||
|
'result' => true,
|
||||||
|
'buyRice' => $buyRiceList,
|
||||||
|
'sellRice' => $sellRiceList,
|
||||||
|
'recentLogs' => $recentLogs,
|
||||||
|
'generalID' => $session->generalID,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$auctionIDList = [];
|
||||||
|
foreach ($auctions as $auction) {
|
||||||
|
$auctionIDList[] = $auction->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$rawHighestBids = Util::convertArrayToDict($db->query(
|
||||||
|
'SELECT bid.* FROM `ng_auction_bid` bid INNER JOIN (
|
||||||
|
SELECT `auction_id`, MAX(`amount`) as `max_amount`
|
||||||
|
FROM `ng_auction_bid`
|
||||||
|
WHERE `auction_id` IN %li
|
||||||
|
GROUP BY `auction_id`
|
||||||
|
ORDER BY `amount`
|
||||||
|
) AS max_bid
|
||||||
|
ON bid.`auction_id` = max_bid.`auction_id` AND bid.`amount` = max_bid.`max_amount`',
|
||||||
|
$auctionIDList,
|
||||||
|
) ?? [], 'auction_id');
|
||||||
|
/** @var array<int,AuctionBidItem> */
|
||||||
|
$highestBids = Util::mapWithKey(
|
||||||
|
fn ($auctionID, $bid) => AuctionBidItem::fromArray($bid),
|
||||||
|
$rawHighestBids
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($auctions as $auction) {
|
||||||
|
$rawAuction = [
|
||||||
|
'id' => $auction->id,
|
||||||
|
'type' => $auction->type->value,
|
||||||
|
'hostGeneralID' => $auction->hostGeneralID,
|
||||||
|
'hostName' => $auction->detail->hostName,
|
||||||
|
'openDate' => TimeUtil::format($auction->openDate, false),
|
||||||
|
'closeDate' => TimeUtil::format($auction->closeDate, false),
|
||||||
|
'amount' => $auction->detail->amount,
|
||||||
|
'startBidAmount' => $auction->detail->startBidAmount,
|
||||||
|
'finishBidAmount' => $auction->detail->finishBidAmount,
|
||||||
|
];
|
||||||
|
|
||||||
|
$highestBid = $highestBids[$rawAuction['id']] ?? null;
|
||||||
|
if ($highestBid === null) {
|
||||||
|
$rawAuction['highestBid'] = null;
|
||||||
|
} else {
|
||||||
|
$rawAuction['highestBid'] = [
|
||||||
|
'amount' => $highestBid->amount,
|
||||||
|
'date' => TimeUtil::format($highestBid->date, false),
|
||||||
|
'generalID' => $highestBid->generalID,
|
||||||
|
'generalName' => $highestBid->aux->generalName,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($rawAuction['type'] == AuctionType::BuyRice->value) {
|
||||||
|
$buyRiceList[] = $rawAuction;
|
||||||
|
} else {
|
||||||
|
$sellRiceList[] = $rawAuction;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'result' => true,
|
||||||
|
'buyRice' => $buyRiceList,
|
||||||
|
'sellRice' => $sellRiceList,
|
||||||
|
'recentLogs' => $recentLogs,
|
||||||
|
'generalID' => $session->generalID,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace sammo\API\Auction;
|
||||||
|
|
||||||
|
use sammo\Session;
|
||||||
|
use DateTimeInterface;
|
||||||
|
use sammo\AuctionUniqueItem;
|
||||||
|
use sammo\DB;
|
||||||
|
use sammo\DTO\AuctionBidItem;
|
||||||
|
use sammo\DTO\AuctionInfo;
|
||||||
|
use sammo\Enums\AuctionType;
|
||||||
|
use sammo\Enums\InheritanceKey;
|
||||||
|
use sammo\InheritancePointManager;
|
||||||
|
use sammo\TimeUtil;
|
||||||
|
use sammo\Validator;
|
||||||
|
use sammo\General;
|
||||||
|
|
||||||
|
class GetUniqueItemAuctionDetail extends \sammo\BaseAPI
|
||||||
|
{
|
||||||
|
public function validateArgs(): ?string
|
||||||
|
{
|
||||||
|
$v = new Validator($this->args);
|
||||||
|
$v->rule('required', [
|
||||||
|
'auctionID',
|
||||||
|
])
|
||||||
|
->rule('integer', 'auctionID');
|
||||||
|
|
||||||
|
if (!$v->validate()) {
|
||||||
|
return $v->errorStr();
|
||||||
|
}
|
||||||
|
$this->args['auctionID'] = (int)$this->args['auctionID'];
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRequiredSessionMode(): int
|
||||||
|
{
|
||||||
|
return static::REQ_GAME_LOGIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag)
|
||||||
|
{
|
||||||
|
$db = DB::db();
|
||||||
|
|
||||||
|
$generalID = $session->generalID;
|
||||||
|
$auctionID = $this->args['auctionID'];
|
||||||
|
|
||||||
|
$rawAuction = $db->queryFirstRow(
|
||||||
|
'SELECT * FROM `ng_auction` WHERE `type` = %s AND `id` = %i',
|
||||||
|
AuctionType::UniqueItem->value,
|
||||||
|
$auctionID
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!$rawAuction) {
|
||||||
|
return '선택한 경매가 없습니다.';
|
||||||
|
}
|
||||||
|
|
||||||
|
$auction = AuctionInfo::fromArray($rawAuction);
|
||||||
|
|
||||||
|
/** @var AuctionBidItem[] */
|
||||||
|
$bidList = array_map(fn ($raw) => AuctionBidItem::fromArray($raw), $db->query(
|
||||||
|
'SELECT * FROM `ng_auction_bid` WHERE `auction_id` = %s ORDER BY `amount` DESC',
|
||||||
|
$auctionID
|
||||||
|
) ?? []);
|
||||||
|
|
||||||
|
$responseBid = [];
|
||||||
|
foreach ($bidList as $bid) {
|
||||||
|
$responseBid[] = [
|
||||||
|
'generalName' => $bid->aux->generalName,
|
||||||
|
'amount' => $bid->amount,
|
||||||
|
'isCallerHighestBidder' => $bid->generalID === $generalID,
|
||||||
|
'date' => TimeUtil::format($bid->date, false),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$inheritMgr = InheritancePointManager::getInstance();
|
||||||
|
//preveious라서 column을 최대한 비울 수 있다.
|
||||||
|
$remainPoint = $inheritMgr->getInheritancePoint(
|
||||||
|
General::createGeneralObjFromDB($generalID, ['owner'], 0),
|
||||||
|
InheritanceKey::previous
|
||||||
|
);
|
||||||
|
|
||||||
|
$obfuscatedName = AuctionUniqueItem::genObfuscatedName($generalID);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'result' => true,
|
||||||
|
'auction' => [
|
||||||
|
'id' => $auction->id,
|
||||||
|
'finished' => $auction->finished,
|
||||||
|
'title' => $auction->detail->title,
|
||||||
|
'target' => $auction->target,
|
||||||
|
'isCallerHost' => $auction->hostGeneralID === $generalID,
|
||||||
|
'hostName' => $auction->detail->hostName,
|
||||||
|
'closeDate' => TimeUtil::format($auction->closeDate, false),
|
||||||
|
'remainCloseDateExtensionCnt' => $auction->detail->remainCloseDateExtensionCnt,
|
||||||
|
'availableLatestBidCloseDate' => TimeUtil::format($auction->detail->availableLatestBidCloseDate, false),
|
||||||
|
],
|
||||||
|
'bidList' => $responseBid,
|
||||||
|
'obfuscatedName' => $obfuscatedName,
|
||||||
|
'remainPoint' => $remainPoint,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace sammo\API\Auction;
|
||||||
|
|
||||||
|
use sammo\Session;
|
||||||
|
use DateTimeInterface;
|
||||||
|
use sammo\AuctionUniqueItem;
|
||||||
|
use sammo\DB;
|
||||||
|
use sammo\DTO\AuctionBidItem;
|
||||||
|
use sammo\DTO\AuctionInfo;
|
||||||
|
use sammo\Enums\AuctionType;
|
||||||
|
use sammo\TimeUtil;
|
||||||
|
use sammo\Util;
|
||||||
|
|
||||||
|
class GetUniqueItemAuctionList extends \sammo\BaseAPI
|
||||||
|
{
|
||||||
|
public function validateArgs(): ?string
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRequiredSessionMode(): int
|
||||||
|
{
|
||||||
|
return static::REQ_GAME_LOGIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag)
|
||||||
|
{
|
||||||
|
$db = DB::db();
|
||||||
|
|
||||||
|
$generalID = $session->generalID;
|
||||||
|
|
||||||
|
/** @var AuctionInfo[] */
|
||||||
|
$auctions = array_map(fn($raw)=>AuctionInfo::fromArray($raw), $db->query(
|
||||||
|
'SELECT * FROM `ng_auction` WHERE `type` = %s ORDER BY `close_date` ASC',
|
||||||
|
AuctionType::UniqueItem->value
|
||||||
|
) ?? []);
|
||||||
|
|
||||||
|
$obfuscatedName = AuctionUniqueItem::genObfuscatedName($generalID);
|
||||||
|
|
||||||
|
if(!$auctions){
|
||||||
|
return [
|
||||||
|
'result' => true,
|
||||||
|
'list' => [],
|
||||||
|
'obfuscatedName' => $obfuscatedName,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$auctionIDList = [];
|
||||||
|
foreach ($auctions as $auction) {
|
||||||
|
$auctionIDList[] = $auction->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
$rawHighestBids = Util::convertArrayToDict($db->query(
|
||||||
|
'SELECT bid.* FROM `ng_auction_bid` bid INNER JOIN (
|
||||||
|
SELECT `auction_id`, MAX(`amount`) as `max_amount`
|
||||||
|
FROM `ng_auction_bid`
|
||||||
|
WHERE `auction_id` IN %li
|
||||||
|
GROUP BY `auction_id`
|
||||||
|
ORDER BY `amount`
|
||||||
|
) AS max_bid
|
||||||
|
ON bid.`auction_id` = max_bid.`auction_id` AND bid.`amount` = max_bid.`max_amount`',
|
||||||
|
$auctionIDList,
|
||||||
|
) ?? [], 'auction_id');
|
||||||
|
/** @var array<int,AuctionBidItem> */
|
||||||
|
$highestBids = Util::mapWithKey(
|
||||||
|
fn ($auctionID, $bid) => AuctionBidItem::fromArray($bid),
|
||||||
|
$rawHighestBids
|
||||||
|
);
|
||||||
|
|
||||||
|
$response = [];
|
||||||
|
foreach ($auctions as $auction) {
|
||||||
|
$auctionID = $auction->id;
|
||||||
|
$highestBid = $highestBids[$auctionID] ?? null;
|
||||||
|
if($highestBid === null){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$response[] = [
|
||||||
|
'id' => $auctionID,
|
||||||
|
'finished' => $auction->finished,
|
||||||
|
'title' => $auction->detail->title,
|
||||||
|
'target' => $auction->target,
|
||||||
|
'isCallerHost' => $auction->hostGeneralID === $generalID,
|
||||||
|
'hostName' => $auction->detail->hostName,
|
||||||
|
'closeDate' => TimeUtil::format($auction->closeDate, false),
|
||||||
|
'remainCloseDateExtensionCnt' => $auction->detail->remainCloseDateExtensionCnt,
|
||||||
|
'availableLatestBidCloseDate' => TimeUtil::format($auction->detail->availableLatestBidCloseDate, false),
|
||||||
|
'highestBid' => [
|
||||||
|
'generalName' => $highestBid->aux->generalName,
|
||||||
|
'amount' => $highestBid->amount,
|
||||||
|
'isCallerHighestBidder' => $highestBid->generalID === $generalID,
|
||||||
|
'date' => $highestBid->date,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'result' => true,
|
||||||
|
'list' => $response,
|
||||||
|
'obfuscatedName' => $obfuscatedName,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace sammo\API\Auction;
|
||||||
|
|
||||||
|
use sammo\Session;
|
||||||
|
use DateTimeInterface;
|
||||||
|
use sammo\AuctionBuyRice;
|
||||||
|
use sammo\DB;
|
||||||
|
use sammo\Validator;
|
||||||
|
use sammo\GameConst;
|
||||||
|
use sammo\General;
|
||||||
|
use sammo\KVStorage;
|
||||||
|
use sammo\Util;
|
||||||
|
|
||||||
|
class OpenBuyRiceAuction extends \sammo\BaseAPI
|
||||||
|
{
|
||||||
|
public function validateArgs(): ?string
|
||||||
|
{
|
||||||
|
$availableItems = [];
|
||||||
|
foreach (GameConst::$allItems as $items) {
|
||||||
|
foreach ($items as $itemKey => $amount) {
|
||||||
|
if ($amount == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$availableItems[$itemKey] = $amount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$v = new Validator($this->args);
|
||||||
|
$v->rule('required', [
|
||||||
|
'amount',
|
||||||
|
'closeTurnCnt',
|
||||||
|
'startBidAmount',
|
||||||
|
'finishBidAmount',
|
||||||
|
])
|
||||||
|
->rule('int', 'amount')
|
||||||
|
->rule('int', 'closeTurnCnt')
|
||||||
|
->rule('min', 'amount', 100)
|
||||||
|
->rule('max', 'amount', 10000)
|
||||||
|
->rule('int', 'startBidAmount')
|
||||||
|
->rule('int', 'finishBidAmount');
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
/** @var int */
|
||||||
|
$amount = $this->args['amount'];
|
||||||
|
/** @var int */
|
||||||
|
$closeTurnCnt = $this->args['closeTurnCnt'];
|
||||||
|
|
||||||
|
/** @var int */
|
||||||
|
$startBidAmount = $this->args['startBidAmount'];
|
||||||
|
/** @var int */
|
||||||
|
$finishBidAmount = $this->args['finishBidAmount'];
|
||||||
|
$generalID = $session->generalID;
|
||||||
|
|
||||||
|
$general = General::createGeneralObjFromDB($generalID);
|
||||||
|
|
||||||
|
$db = DB::db();
|
||||||
|
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||||
|
[$initYear, $initMonth, $year, $month] = $gameStor->getValuesAsArray(['init_year', 'init_month', 'year', 'month']);
|
||||||
|
$initYearMonth = Util::joinYearMonth($initYear, $initMonth);
|
||||||
|
$yearMonth = Util::joinYearMonth($year, $month);
|
||||||
|
|
||||||
|
if($yearMonth < $initYearMonth + 3){
|
||||||
|
return '시작 후 3개월이 지나야 경매를 열 수 있습니다.';
|
||||||
|
}
|
||||||
|
|
||||||
|
$auctionResult = AuctionBuyRice::openResourceAuction(
|
||||||
|
$general,
|
||||||
|
$amount,
|
||||||
|
$closeTurnCnt,
|
||||||
|
$startBidAmount,
|
||||||
|
$finishBidAmount
|
||||||
|
);
|
||||||
|
|
||||||
|
if (is_string($auctionResult)) {
|
||||||
|
return $auctionResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'result' => true,
|
||||||
|
'auctionID' => $auctionResult->getInfo()->id,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace sammo\API\Auction;
|
||||||
|
|
||||||
|
use sammo\Session;
|
||||||
|
use DateTimeInterface;
|
||||||
|
use sammo\AuctionSellRice;
|
||||||
|
use sammo\DB;
|
||||||
|
use sammo\Validator;
|
||||||
|
use sammo\GameConst;
|
||||||
|
use sammo\General;
|
||||||
|
use sammo\KVStorage;
|
||||||
|
use sammo\Util;
|
||||||
|
|
||||||
|
class OpenSellRiceAuction extends \sammo\BaseAPI
|
||||||
|
{
|
||||||
|
public function validateArgs(): ?string
|
||||||
|
{
|
||||||
|
$availableItems = [];
|
||||||
|
foreach (GameConst::$allItems as $items) {
|
||||||
|
foreach ($items as $itemKey => $amount) {
|
||||||
|
if ($amount == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$availableItems[$itemKey] = $amount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$v = new Validator($this->args);
|
||||||
|
$v->rule('required', [
|
||||||
|
'amount',
|
||||||
|
'closeTurnCnt',
|
||||||
|
'startBidAmount',
|
||||||
|
'finishBidAmount',
|
||||||
|
])
|
||||||
|
->rule('int', 'amount')
|
||||||
|
->rule('int', 'closeTurnCnt')
|
||||||
|
->rule('min', 'amount', 100)
|
||||||
|
->rule('max', 'amount', 10000)
|
||||||
|
->rule('int', 'startBidAmount')
|
||||||
|
->rule('int', 'finishBidAmount');
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
/** @var int */
|
||||||
|
$amount = $this->args['amount'];
|
||||||
|
/** @var int */
|
||||||
|
$closeTurnCnt = $this->args['closeTurnCnt'];
|
||||||
|
|
||||||
|
/** @var int */
|
||||||
|
$startBidAmount = $this->args['startBidAmount'];
|
||||||
|
/** @var int */
|
||||||
|
$finishBidAmount = $this->args['finishBidAmount'];
|
||||||
|
$generalID = $session->generalID;
|
||||||
|
|
||||||
|
$general = General::createGeneralObjFromDB($generalID);
|
||||||
|
|
||||||
|
$db = DB::db();
|
||||||
|
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||||
|
[$initYear, $initMonth, $year, $month] = $gameStor->getValuesAsArray(['init_year', 'init_month', 'year', 'month']);
|
||||||
|
$initYearMonth = Util::joinYearMonth($initYear, $initMonth);
|
||||||
|
$yearMonth = Util::joinYearMonth($year, $month);
|
||||||
|
|
||||||
|
if($yearMonth < $initYearMonth + 3){
|
||||||
|
return '시작 후 3개월이 지나야 경매를 열 수 있습니다.';
|
||||||
|
}
|
||||||
|
|
||||||
|
$auctionResult = AuctionSellRice::openResourceAuction(
|
||||||
|
$general,
|
||||||
|
$amount,
|
||||||
|
$closeTurnCnt,
|
||||||
|
$startBidAmount,
|
||||||
|
$finishBidAmount
|
||||||
|
);
|
||||||
|
|
||||||
|
if (is_string($auctionResult)) {
|
||||||
|
return $auctionResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'result' => true,
|
||||||
|
'auctionID' => $auctionResult->getInfo()->id,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace sammo\API\Auction;
|
||||||
|
|
||||||
|
use sammo\Session;
|
||||||
|
use DateTimeInterface;
|
||||||
|
use sammo\AuctionUniqueItem;
|
||||||
|
use sammo\DB;
|
||||||
|
use sammo\Validator;
|
||||||
|
use sammo\GameConst;
|
||||||
|
use sammo\General;
|
||||||
|
use sammo\KVStorage;
|
||||||
|
use sammo\Util;
|
||||||
|
|
||||||
|
use function sammo\buildItemClass;
|
||||||
|
|
||||||
|
class OpenUniqueAuction extends \sammo\BaseAPI
|
||||||
|
{
|
||||||
|
public function validateArgs(): ?string
|
||||||
|
{
|
||||||
|
$availableItems = [];
|
||||||
|
foreach (GameConst::$allItems as $items) {
|
||||||
|
foreach ($items as $itemKey => $amount) {
|
||||||
|
if ($amount == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$availableItems[$itemKey] = $amount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$v = new Validator($this->args);
|
||||||
|
$v->rule('required', [
|
||||||
|
'itemID',
|
||||||
|
'amount'
|
||||||
|
])
|
||||||
|
->rule('int', 'amount')
|
||||||
|
->rule('min', 'amount', GameConst::$inheritItemUniqueMinPoint)
|
||||||
|
->rule('keyExists', 'itemID', $availableItems);
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
$itemID = $this->args['itemID'];
|
||||||
|
$amount = $this->args['amount'];
|
||||||
|
$generalID = $session->generalID;
|
||||||
|
|
||||||
|
$itemObj = buildItemClass($itemID);
|
||||||
|
$general = General::createGeneralObjFromDB($generalID);
|
||||||
|
|
||||||
|
$db = DB::db();
|
||||||
|
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||||
|
[$initYear, $initMonth, $year, $month] = $gameStor->getValuesAsArray(['init_year', 'init_month', 'year', 'month']);
|
||||||
|
$initYearMonth = Util::joinYearMonth($initYear, $initMonth);
|
||||||
|
$yearMonth = Util::joinYearMonth($year, $month);
|
||||||
|
|
||||||
|
if($yearMonth < $initYearMonth + 3){
|
||||||
|
return '시작 후 3개월이 지나야 경매를 열 수 있습니다.';
|
||||||
|
}
|
||||||
|
|
||||||
|
$auctionResult = AuctionUniqueItem::openItemAuction($itemObj, $general, $amount);
|
||||||
|
|
||||||
|
if(is_string($auctionResult)) {
|
||||||
|
return $auctionResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'result' => true,
|
||||||
|
'auctionID' => $auctionResult->getInfo()->id,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,9 +23,9 @@ class Bet extends \sammo\BaseAPI
|
|||||||
'bettingType',
|
'bettingType',
|
||||||
'amount'
|
'amount'
|
||||||
])
|
])
|
||||||
->rule('integer', 'bettingID')
|
->rule('int', 'bettingID')
|
||||||
->rule('integerArray', 'bettingType')
|
->rule('integerArray', 'bettingType')
|
||||||
->rule('integer', 'amount')
|
->rule('int', 'amount')
|
||||||
->rule('min', 'amount', 1);
|
->rule('min', 'amount', 1);
|
||||||
|
|
||||||
if (!$v->validate()) {
|
if (!$v->validate()) {
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ class GetBettingDetail extends \sammo\BaseAPI
|
|||||||
if (!$v->validate()) {
|
if (!$v->validate()) {
|
||||||
return $v->errorStr();
|
return $v->errorStr();
|
||||||
}
|
}
|
||||||
|
$this->args['betting_id'] = (int)$this->args['betting_id'];
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,7 +47,7 @@ class GetBettingDetail extends \sammo\BaseAPI
|
|||||||
}
|
}
|
||||||
|
|
||||||
try{
|
try{
|
||||||
$bettingInfo = new BettingInfo($rawBettingInfo);
|
$bettingInfo = BettingInfo::fromArray($rawBettingInfo);
|
||||||
}
|
}
|
||||||
catch(\Error $e){
|
catch(\Error $e){
|
||||||
return $e->getMessage();
|
return $e->getMessage();
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ class GetBettingList extends \sammo\BaseAPI
|
|||||||
|
|
||||||
$bettingList = [];
|
$bettingList = [];
|
||||||
foreach ($bettingStor->getAll() as $_key => $rawItem) {
|
foreach ($bettingStor->getAll() as $_key => $rawItem) {
|
||||||
$item = new BettingInfo($rawItem);
|
$item = BettingInfo::fromArray($rawItem);
|
||||||
if ($reqType !== null && $item->type != $reqType) {
|
if ($reqType !== null && $item->type != $reqType) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ class PushCommand extends \sammo\BaseAPI
|
|||||||
$v->rule('required', [
|
$v->rule('required', [
|
||||||
'amount',
|
'amount',
|
||||||
])
|
])
|
||||||
->rule('integer', 'amount')
|
->rule('int', 'amount')
|
||||||
->rule('min', 'amount', -12)
|
->rule('min', 'amount', -12)
|
||||||
->rule('max', 'amount', 12);
|
->rule('max', 'amount', 12);
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ class RepeatCommand extends \sammo\BaseAPI
|
|||||||
$v->rule('required', [
|
$v->rule('required', [
|
||||||
'amount',
|
'amount',
|
||||||
])
|
])
|
||||||
->rule('integer', 'amount')
|
->rule('int', 'amount')
|
||||||
->rule('min', 'amount', 1)
|
->rule('min', 'amount', 1)
|
||||||
->rule('max', 'amount', 12);
|
->rule('max', 'amount', 12);
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace sammo\API\General;
|
namespace sammo\API\General;
|
||||||
|
|
||||||
|
use Ds\Set;
|
||||||
use sammo\DB;
|
use sammo\DB;
|
||||||
use sammo\Validator;
|
use sammo\Validator;
|
||||||
|
|
||||||
@@ -9,6 +10,7 @@ use sammo\Session;
|
|||||||
use sammo\GameConst;
|
use sammo\GameConst;
|
||||||
use sammo\General;
|
use sammo\General;
|
||||||
use sammo\JosaUtil;
|
use sammo\JosaUtil;
|
||||||
|
use sammo\KVStorage;
|
||||||
|
|
||||||
class DropItem extends \sammo\BaseAPI
|
class DropItem extends \sammo\BaseAPI
|
||||||
{
|
{
|
||||||
@@ -56,12 +58,13 @@ class DropItem extends \sammo\BaseAPI
|
|||||||
$logger->pushGeneralActionLog("<C>{$itemName}</>{$josaUl} 버렸습니다.");
|
$logger->pushGeneralActionLog("<C>{$itemName}</>{$josaUl} 버렸습니다.");
|
||||||
|
|
||||||
$nationName = $me->getStaticNation()['name'];
|
$nationName = $me->getStaticNation()['name'];
|
||||||
|
$db = DB::db();
|
||||||
if (!$item->isBuyable()) {
|
if (!$item->isBuyable()) {
|
||||||
$logger->pushGlobalActionLog("<Y>{$generalName}</>{$josaYi} <C>{$itemName}</>{$josaUl} 잃었습니다!");
|
$logger->pushGlobalActionLog("<Y>{$generalName}</>{$josaYi} <C>{$itemName}</>{$josaUl} 잃었습니다!");
|
||||||
$logger->pushGlobalHistoryLog("<R><b>【망실】</b></><D><b>{$nationName}</b></>의 <Y>{$generalName}</>{$josaYi} <C>{$itemName}</>{$josaUl} 잃었습니다!");
|
$logger->pushGlobalHistoryLog("<R><b>【망실】</b></><D><b>{$nationName}</b></>의 <Y>{$generalName}</>{$josaYi} <C>{$itemName}</>{$josaUl} 잃었습니다!");
|
||||||
}
|
}
|
||||||
|
|
||||||
$me->applyDB(DB::db());
|
$me->applyDB($db);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ class GetGeneralLog extends GetNationGeneralLog
|
|||||||
->rule('required', [
|
->rule('required', [
|
||||||
'type',
|
'type',
|
||||||
])
|
])
|
||||||
->rule('integer', [
|
->rule('int', [
|
||||||
'reqTo',
|
'reqTo',
|
||||||
])
|
])
|
||||||
->rule('in', 'type', [
|
->rule('in', 'type', [
|
||||||
|
|||||||
@@ -13,11 +13,14 @@ use sammo\InheritancePointManager;
|
|||||||
use sammo\JosaUtil;
|
use sammo\JosaUtil;
|
||||||
use sammo\Json;
|
use sammo\Json;
|
||||||
use sammo\KVStorage;
|
use sammo\KVStorage;
|
||||||
|
use sammo\LiteHashDRBG;
|
||||||
|
use sammo\RandUtil;
|
||||||
use sammo\RootDB;
|
use sammo\RootDB;
|
||||||
use sammo\Session;
|
use sammo\Session;
|
||||||
use sammo\SpecialityHelper;
|
use sammo\SpecialityHelper;
|
||||||
use sammo\StringUtil;
|
use sammo\StringUtil;
|
||||||
use sammo\TimeUtil;
|
use sammo\TimeUtil;
|
||||||
|
use sammo\UniqueConst;
|
||||||
use sammo\UserLogger;
|
use sammo\UserLogger;
|
||||||
use sammo\Util;
|
use sammo\Util;
|
||||||
use sammo\Validator;
|
use sammo\Validator;
|
||||||
@@ -43,7 +46,7 @@ class Join extends \sammo\BaseAPI
|
|||||||
'pic',
|
'pic',
|
||||||
'character',
|
'character',
|
||||||
])
|
])
|
||||||
->rule('integer', [
|
->rule('int', [
|
||||||
'leadership',
|
'leadership',
|
||||||
'strength',
|
'strength',
|
||||||
'intel',
|
'intel',
|
||||||
@@ -162,6 +165,14 @@ class Join extends \sammo\BaseAPI
|
|||||||
|
|
||||||
$userLogger = new UserLogger($userID, $admin['year'], $admin['month'], false);
|
$userLogger = new UserLogger($userID, $admin['year'], $admin['month'], false);
|
||||||
|
|
||||||
|
$now = TimeUtil::now(false);
|
||||||
|
$rng = new RandUtil(new LiteHashDRBG(Util::simpleSerialize(
|
||||||
|
UniqueConst::$hiddenSeed,
|
||||||
|
'MakeGeneral',
|
||||||
|
$userID,
|
||||||
|
$now
|
||||||
|
)));
|
||||||
|
|
||||||
if ($inheritCity !== null) {
|
if ($inheritCity !== null) {
|
||||||
$inheritRequiredPoint += GameConst::$inheritBornCityPoint;
|
$inheritRequiredPoint += GameConst::$inheritBornCityPoint;
|
||||||
}
|
}
|
||||||
@@ -193,7 +204,7 @@ class Join extends \sammo\BaseAPI
|
|||||||
$genius = true;
|
$genius = true;
|
||||||
} else {
|
} else {
|
||||||
// 현재 1%
|
// 현재 1%
|
||||||
$genius = Util::randBool(0.01);
|
$genius = $rng->nextBool(0.01);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($genius && $gameStor->genius > 0) {
|
if ($genius && $gameStor->genius > 0) {
|
||||||
@@ -208,10 +219,11 @@ class Join extends \sammo\BaseAPI
|
|||||||
$city = $inheritCity;
|
$city = $inheritCity;
|
||||||
} else {
|
} else {
|
||||||
// 공백지에서만 태어나게
|
// 공백지에서만 태어나게
|
||||||
$city = $db->queryFirstField("select city from city where level>=5 and level<=6 and nation=0 order by rand() limit 0,1");
|
$cities = $db->queryFirstColumn('SELECT city FROM city where `level`>=5 and `level`<=6 and nation=0');
|
||||||
if (!$city) {
|
if (!$cities) {
|
||||||
$city = $db->queryFirstField("select city from city where level>=5 and level<=6 order by rand() limit 0,1");
|
$cities = $db->queryFirstColumn('SELECT city FROM city where `level`>=5 and `level`<=6');
|
||||||
}
|
}
|
||||||
|
$city = $rng->choice($cities);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($inheritBonusStat) {
|
if ($inheritBonusStat) {
|
||||||
@@ -221,8 +233,8 @@ class Join extends \sammo\BaseAPI
|
|||||||
$pleadership = 0;
|
$pleadership = 0;
|
||||||
$pstrength = 0;
|
$pstrength = 0;
|
||||||
$pintel = 0;
|
$pintel = 0;
|
||||||
foreach (Util::range(Util::randRangeInt(3, 5)) as $statIdx) {
|
foreach (Util::range($rng->nextRangeInt(3, 5)) as $statIdx) {
|
||||||
switch (Util::choiceRandomUsingWeight([$leadership, $strength, $intel])) {
|
switch ($rng->choiceUsingWeight([$leadership, $strength, $intel])) {
|
||||||
case 0:
|
case 0:
|
||||||
$pleadership++;
|
$pleadership++;
|
||||||
break;
|
break;
|
||||||
@@ -242,14 +254,14 @@ class Join extends \sammo\BaseAPI
|
|||||||
|
|
||||||
$relYear = Util::valueFit($admin['year'] - $admin['startyear'], 0);
|
$relYear = Util::valueFit($admin['year'] - $admin['startyear'], 0);
|
||||||
|
|
||||||
$age = 20 + ($pleadership + $pstrength + $pintel) * 2 - (mt_rand(0, 1));
|
$age = 20 + ($pleadership + $pstrength + $pintel) * 2 - $rng->nextRangeInt(0, 1);
|
||||||
// 아직 남았고 천재등록상태이면 특기 부여
|
// 아직 남았고 천재등록상태이면 특기 부여
|
||||||
if ($genius) {
|
if ($genius) {
|
||||||
$specage2 = $age;
|
$specage2 = $age;
|
||||||
if ($inheritSpecial) {
|
if ($inheritSpecial) {
|
||||||
$special2 = $inheritSpecial;
|
$special2 = $inheritSpecial;
|
||||||
} else {
|
} else {
|
||||||
$special2 = SpecialityHelper::pickSpecialWar([
|
$special2 = SpecialityHelper::pickSpecialWar($rng, [
|
||||||
'leadership' => $leadership,
|
'leadership' => $leadership,
|
||||||
'strength' => $strength,
|
'strength' => $strength,
|
||||||
'intel' => $intel,
|
'intel' => $intel,
|
||||||
@@ -290,12 +302,12 @@ 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");
|
||||||
|
|
||||||
$inheritTurntime += Util::randRangeInt(0, 999999) / 1000000;
|
$inheritTurntime += $rng->nextRangeInt(0, 999999) / 1000000;
|
||||||
$turntime = new \DateTimeImmutable(cutTurn($admin['turntime'], $admin['turnterm']));
|
$turntime = new \DateTimeImmutable(cutTurn($admin['turntime'], $admin['turnterm']));
|
||||||
$turntime = $turntime->add(TimeUtil::secondsToDateInterval($inheritTurntime));
|
$turntime = $turntime->add(TimeUtil::secondsToDateInterval($inheritTurntime));
|
||||||
$turntime = TimeUtil::format($turntime, true);
|
$turntime = TimeUtil::format($turntime, true);
|
||||||
} else {
|
} else {
|
||||||
$turntime = getRandTurn($admin['turnterm'], new \DateTimeImmutable($admin['turntime']));
|
$turntime = getRandTurn($rng, $admin['turnterm'], new \DateTimeImmutable($admin['turntime']));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -315,10 +327,10 @@ class Join extends \sammo\BaseAPI
|
|||||||
|
|
||||||
//성격 랜덤시
|
//성격 랜덤시
|
||||||
if (!in_array($character, GameConst::$availablePersonality)) {
|
if (!in_array($character, GameConst::$availablePersonality)) {
|
||||||
$character = Util::choiceRandom(GameConst::$availablePersonality);
|
$character = $rng->choice(GameConst::$availablePersonality);
|
||||||
}
|
}
|
||||||
//상성 랜덤
|
//상성 랜덤
|
||||||
$affinity = rand() % 150 + 1;
|
$affinity = $rng->nextRangeInt(1, 150);
|
||||||
|
|
||||||
########## 회원정보 테이블에 입력값을 등록한다. ##########
|
########## 회원정보 테이블에 입력값을 등록한다. ##########
|
||||||
$db->insert('general', [
|
$db->insert('general', [
|
||||||
|
|||||||
@@ -33,6 +33,8 @@ class GetHistory extends \sammo\BaseAPI
|
|||||||
if (!$this->args['serverID']) {
|
if (!$this->args['serverID']) {
|
||||||
$this->args['serverID'] = UniqueConst::$serverID;
|
$this->args['serverID'] = UniqueConst::$serverID;
|
||||||
}
|
}
|
||||||
|
$this->args['year'] = (int)$this->args['year'];
|
||||||
|
$this->args['month'] = (int)$this->args['month'];
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ class BuyHiddenBuff extends \sammo\BaseAPI
|
|||||||
'type',
|
'type',
|
||||||
'level',
|
'level',
|
||||||
])
|
])
|
||||||
->rule('integer', 'level')
|
->rule('int', 'level')
|
||||||
->rule('min', 'level', 1)
|
->rule('min', 'level', 1)
|
||||||
->rule('max', 'level', TriggerInheritBuff::MAX_STEP)
|
->rule('max', 'level', TriggerInheritBuff::MAX_STEP)
|
||||||
->rule('keyExists', 'type', TriggerInheritBuff::BUFF_KEY_TEXT);
|
->rule('keyExists', 'type', TriggerInheritBuff::BUFF_KEY_TEXT);
|
||||||
|
|||||||
@@ -1,104 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace sammo\API\InheritAction;
|
|
||||||
|
|
||||||
use sammo\Session;
|
|
||||||
use DateTimeInterface;
|
|
||||||
use sammo\DB;
|
|
||||||
use sammo\Enums\RankColumn;
|
|
||||||
use sammo\GameConst;
|
|
||||||
use sammo\General;
|
|
||||||
use sammo\KVStorage;
|
|
||||||
use sammo\UserLogger;
|
|
||||||
use sammo\Validator;
|
|
||||||
|
|
||||||
use function sammo\buildItemClass;
|
|
||||||
|
|
||||||
class BuySpecificUnique extends \sammo\BaseAPI
|
|
||||||
{
|
|
||||||
public function validateArgs(): ?string
|
|
||||||
{
|
|
||||||
$availableItems = [];
|
|
||||||
foreach (GameConst::$allItems as $items) {
|
|
||||||
foreach ($items as $itemKey => $amount) {
|
|
||||||
if ($amount == 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$availableItems[$itemKey] = $amount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$v = new Validator($this->args);
|
|
||||||
$v->rule('required', [
|
|
||||||
'item',
|
|
||||||
'amount',
|
|
||||||
])
|
|
||||||
->rule('integer', 'amount')
|
|
||||||
->rule('min', 'amount', GameConst::$inheritItemUniqueMinPoint)
|
|
||||||
->rule('keyExists', 'item', $availableItems);
|
|
||||||
|
|
||||||
if (!$v->validate()) {
|
|
||||||
return $v->errorStr();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getRequiredSessionMode(): int
|
|
||||||
{
|
|
||||||
//KVStrorage, General.aux 모두 쓰므로 lock;
|
|
||||||
return static::REQ_GAME_LOGIN;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag)
|
|
||||||
{
|
|
||||||
$itemKey = $this->args['item'];
|
|
||||||
$amount = $this->args['amount'];
|
|
||||||
|
|
||||||
$userID = $session->userID;
|
|
||||||
$generalID = $session->generalID;
|
|
||||||
|
|
||||||
$general = General::createGeneralObjFromDB($generalID);
|
|
||||||
if ($userID != $general->getVar('owner')) {
|
|
||||||
return '로그인 상태가 이상합니다. 다시 로그인해 주세요.';
|
|
||||||
}
|
|
||||||
|
|
||||||
$itemTrials = $general->getAuxVar('inheritUniqueTrial') ?? [];
|
|
||||||
if (key_exists($itemKey, $itemTrials)) {
|
|
||||||
return '이미 입찰한 아이템입니다. 다음 턴에 시도해 주세요.';
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach(GameConst::$allItems as $itemType => $items){
|
|
||||||
if(!key_exists($itemKey, $items)){
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$prevItem = $general->getItem($itemType);
|
|
||||||
if(!$prevItem->isBuyable()){
|
|
||||||
return '이미 같은 자리에 유니크를 보유하고 있습니다.';
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
$db = DB::db();
|
|
||||||
$inheritStor = KVStorage::getStorage($db, "inheritance_{$userID}");
|
|
||||||
$trialStor = KVStorage::getStorage($db, "ut_{$itemKey}");
|
|
||||||
$previousPoint = ($inheritStor->getValue('previous') ?? [0, 0])[0];
|
|
||||||
if ($previousPoint < $amount) {
|
|
||||||
return '충분한 유산 포인트를 가지고 있지 않습니다.';
|
|
||||||
}
|
|
||||||
|
|
||||||
$itemObj = buildItemClass($itemKey);
|
|
||||||
$userLogger = new UserLogger($userID);
|
|
||||||
$userLogger->push("{$amount} 포인트로 유니크 {$itemObj->getName()} 구입 시도", "inheritPoint");
|
|
||||||
$userLogger->flush();
|
|
||||||
|
|
||||||
$itemTrials[$itemKey] = $amount;
|
|
||||||
$general->setAuxVar('inheritUniqueTrial', $itemTrials);
|
|
||||||
$inheritStor->setValue('previous', [$previousPoint - $amount, null]);
|
|
||||||
$general->increaseRankVar(RankColumn::inherit_point_spent_dynamic, $amount);
|
|
||||||
$trialStor->setValue("u{$userID}", [$userID, $generalID, $amount]);
|
|
||||||
$general->applyDB($db);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -10,7 +10,10 @@ use sammo\Enums\RankColumn;
|
|||||||
use sammo\GameConst;
|
use sammo\GameConst;
|
||||||
use sammo\General;
|
use sammo\General;
|
||||||
use sammo\KVStorage;
|
use sammo\KVStorage;
|
||||||
|
use sammo\LiteHashDRBG;
|
||||||
|
use sammo\RandUtil;
|
||||||
use sammo\TimeUtil;
|
use sammo\TimeUtil;
|
||||||
|
use sammo\UniqueConst;
|
||||||
use sammo\UserLogger;
|
use sammo\UserLogger;
|
||||||
use sammo\Util;
|
use sammo\Util;
|
||||||
|
|
||||||
@@ -59,7 +62,14 @@ class ResetTurnTime extends \sammo\BaseAPI
|
|||||||
$currTurnTime = new DateTimeImmutable($general->getTurnTime());
|
$currTurnTime = new DateTimeImmutable($general->getTurnTime());
|
||||||
$serverTurnTimeObj = new DateTimeImmutable($serverTurnTime);
|
$serverTurnTimeObj = new DateTimeImmutable($serverTurnTime);
|
||||||
|
|
||||||
$afterTurn = Util::randRange($turnTerm * -60 / 2, $turnTerm * 60 / 2);
|
$rng = new RandUtil(new LiteHashDRBG(Util::simpleSerialize(
|
||||||
|
UniqueConst::$hiddenSeed,
|
||||||
|
'ResetTurnTime',
|
||||||
|
$userID,
|
||||||
|
$general->getTurnTime()
|
||||||
|
)));
|
||||||
|
|
||||||
|
$afterTurn = $rng->nextRange($turnTerm * -60 / 2, $turnTerm * 60 / 2);
|
||||||
|
|
||||||
$userLogger = new UserLogger($userID);
|
$userLogger = new UserLogger($userID);
|
||||||
if($afterTurn >= 0){
|
if($afterTurn >= 0){
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class SetBill extends \sammo\BaseAPI
|
|||||||
$v->rule('required', [
|
$v->rule('required', [
|
||||||
'amount',
|
'amount',
|
||||||
])
|
])
|
||||||
->rule('integer', 'amount')
|
->rule('int', 'amount')
|
||||||
->rule('min', 'amount', 20)
|
->rule('min', 'amount', 20)
|
||||||
->rule('max', 'amount', 200);
|
->rule('max', 'amount', 200);
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class SetRate extends \sammo\BaseAPI
|
|||||||
$v->rule('required', [
|
$v->rule('required', [
|
||||||
'amount',
|
'amount',
|
||||||
])
|
])
|
||||||
->rule('integer', 'amount')
|
->rule('int', 'amount')
|
||||||
->rule('min', 'amount', 5)
|
->rule('min', 'amount', 5)
|
||||||
->rule('max', 'amount', 30);
|
->rule('max', 'amount', 30);
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class SetSecretLimit extends \sammo\BaseAPI
|
|||||||
$v->rule('required', [
|
$v->rule('required', [
|
||||||
'amount',
|
'amount',
|
||||||
])
|
])
|
||||||
->rule('integer', 'amount')
|
->rule('int', 'amount')
|
||||||
->rule('min', 'amount', 1)
|
->rule('min', 'amount', 1)
|
||||||
->rule('max', 'amount', 99);
|
->rule('max', 'amount', 99);
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ class PushCommand extends \sammo\BaseAPI
|
|||||||
$v->rule('required', [
|
$v->rule('required', [
|
||||||
'amount',
|
'amount',
|
||||||
])
|
])
|
||||||
->rule('integer', 'amount')
|
->rule('int', 'amount')
|
||||||
->rule('min', 'amount', -12)
|
->rule('min', 'amount', -12)
|
||||||
->rule('max', 'amount', 12);
|
->rule('max', 'amount', 12);
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ class RepeatCommand extends \sammo\BaseAPI
|
|||||||
$v->rule('required', [
|
$v->rule('required', [
|
||||||
'amount',
|
'amount',
|
||||||
])
|
])
|
||||||
->rule('integer', 'amount')
|
->rule('int', 'amount')
|
||||||
->rule('min', 'amount', 1)
|
->rule('min', 'amount', 1)
|
||||||
->rule('max', 'amount', 12);
|
->rule('max', 'amount', 12);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace sammo\API\Vote;
|
||||||
|
|
||||||
|
use DateTimeInterface;
|
||||||
|
use sammo\DB;
|
||||||
|
use sammo\DTO\VoteComment;
|
||||||
|
use sammo\General;
|
||||||
|
use sammo\Session;
|
||||||
|
use sammo\TimeUtil;
|
||||||
|
use sammo\Validator;
|
||||||
|
|
||||||
|
class AddComment extends \sammo\BaseAPI
|
||||||
|
{
|
||||||
|
function getRequiredSessionMode(): int
|
||||||
|
{
|
||||||
|
return static::REQ_GAME_LOGIN | static::REQ_READ_ONLY;
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateArgs(): ?string
|
||||||
|
{
|
||||||
|
$v = new Validator($this->args);
|
||||||
|
$v->rule('required', [
|
||||||
|
'voteID',
|
||||||
|
'text',
|
||||||
|
])->rule('lengthMin', 'text', 1)
|
||||||
|
->rule('int', 'voteID');
|
||||||
|
|
||||||
|
if (!$v->validate()) {
|
||||||
|
return $v->errorStr();
|
||||||
|
}
|
||||||
|
$this->args['voteID'] = (int)$this->args['voteID'];
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag)
|
||||||
|
{
|
||||||
|
$voteID = $this->args['voteID'];
|
||||||
|
$text = mb_substr($this->args['text'], 0, 200);
|
||||||
|
|
||||||
|
$generalID = $session->generalID;
|
||||||
|
$general = General::createGeneralObjFromDB($generalID, [], 0);
|
||||||
|
$generalName = $general->getName();
|
||||||
|
$nationID = $general->getNationID();
|
||||||
|
$nationName = $general->getStaticNation()['name'];
|
||||||
|
$date = TimeUtil::now();
|
||||||
|
|
||||||
|
|
||||||
|
$comment = new VoteComment(
|
||||||
|
id: null,
|
||||||
|
voteID: $voteID,
|
||||||
|
generalID: $generalID,
|
||||||
|
nationID: $nationID,
|
||||||
|
nationName: $nationName,
|
||||||
|
generalName: $generalName,
|
||||||
|
text: $text,
|
||||||
|
date: $date
|
||||||
|
);
|
||||||
|
|
||||||
|
$db = DB::db();
|
||||||
|
$db->insert('vote_comment', $comment->toArray());
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace sammo\API\Vote;
|
||||||
|
|
||||||
|
use sammo\Session;
|
||||||
|
use DateTimeInterface;
|
||||||
|
use sammo\DB;
|
||||||
|
use sammo\DTO\VoteComment;
|
||||||
|
use sammo\DTO\VoteInfo;
|
||||||
|
use sammo\Json;
|
||||||
|
use sammo\KVStorage;
|
||||||
|
use sammo\Validator;
|
||||||
|
|
||||||
|
class GetVoteDetail extends \sammo\BaseAPI
|
||||||
|
{
|
||||||
|
public function validateArgs(): ?string
|
||||||
|
{
|
||||||
|
$v = new Validator($this->args);
|
||||||
|
$v->rule('required', 'voteID')
|
||||||
|
->rule('integer', 'voteID');
|
||||||
|
if (!$v->validate()) {
|
||||||
|
return $v->errorStr();
|
||||||
|
}
|
||||||
|
$this->args['voteID'] = (int)$this->args['voteID'];
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRequiredSessionMode(): int
|
||||||
|
{
|
||||||
|
return static::REQ_LOGIN | static::REQ_READ_ONLY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag)
|
||||||
|
{
|
||||||
|
$voteID = $this->args['voteID'];
|
||||||
|
$db = DB::db();
|
||||||
|
|
||||||
|
$voteStor = KVStorage::getStorage($db, 'vote');
|
||||||
|
$rawVote = $voteStor->getValue("vote_{$voteID}");
|
||||||
|
if (!$rawVote) {
|
||||||
|
return '설문조사가 없습니다.';
|
||||||
|
}
|
||||||
|
$voteInfo = VoteInfo::fromArray($rawVote);
|
||||||
|
|
||||||
|
|
||||||
|
$votes = array_map(fn ($arr) => [Json::decode($arr[0]), $arr[1]], $db->queryAllLists(
|
||||||
|
'SELECT selection, count(*) AS cnt FROM vote WHERE vote_id = %i GROUP BY selection',
|
||||||
|
$voteID
|
||||||
|
));
|
||||||
|
|
||||||
|
$comments = array_map(fn ($arr) => VoteComment::fromArray($arr), $db->query('SELECT * FROM vote_comment WHERE vote_id = %i ORDER BY `id` ASC', $voteID));
|
||||||
|
|
||||||
|
$myVote = null;
|
||||||
|
if ($session->isGameLoggedIn()) {
|
||||||
|
$generalID = $session->generalID;
|
||||||
|
$rawMyVote = $db->queryFirstField('SELECT selection FROM vote WHERE vote_id = %i AND general_id = %i', $voteID, $generalID);
|
||||||
|
if ($rawMyVote) {
|
||||||
|
$myVote = Json::decode($rawMyVote);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$userCnt = $db->queryFirstField('SELECT count(*) FROM general WHERE npc < 2');
|
||||||
|
|
||||||
|
|
||||||
|
return [
|
||||||
|
'result' => true,
|
||||||
|
'voteInfo' => $voteInfo,
|
||||||
|
'votes' => $votes,
|
||||||
|
'comments' => $comments,
|
||||||
|
'myVote' => $myVote,
|
||||||
|
'userCnt' => $userCnt,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace sammo\API\Vote;
|
||||||
|
|
||||||
|
use DateTimeInterface;
|
||||||
|
use sammo\DB;
|
||||||
|
use sammo\DTO\VoteInfo;
|
||||||
|
use sammo\KVStorage;
|
||||||
|
use sammo\Session;
|
||||||
|
|
||||||
|
class GetVoteList extends \sammo\BaseAPI
|
||||||
|
{
|
||||||
|
|
||||||
|
public function validateArgs(): ?string
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRequiredSessionMode(): int
|
||||||
|
{
|
||||||
|
return static::REQ_LOGIN | static::REQ_READ_ONLY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag)
|
||||||
|
{
|
||||||
|
$db = DB::db();
|
||||||
|
|
||||||
|
$voteStor = KVStorage::getStorage($db, 'vote');
|
||||||
|
|
||||||
|
$votes = [];
|
||||||
|
foreach($voteStor->getAll() as $voteKey => $rawVote){
|
||||||
|
if(!str_starts_with($voteKey, 'vote_')){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$voteID = (int)substr($voteKey, 5);
|
||||||
|
$votes[$voteID] = VoteInfo::fromArray($rawVote);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'result'=>true,
|
||||||
|
'votes'=>$votes
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,130 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace sammo\API\Vote;
|
||||||
|
|
||||||
|
use DateTimeInterface;
|
||||||
|
use sammo\DB;
|
||||||
|
use sammo\DTO\VoteInfo;
|
||||||
|
use sammo\KVStorage;
|
||||||
|
use sammo\Session;
|
||||||
|
use sammo\TimeUtil;
|
||||||
|
use sammo\Util;
|
||||||
|
use sammo\Validator;
|
||||||
|
|
||||||
|
class NewVote extends \sammo\BaseAPI
|
||||||
|
{
|
||||||
|
function getRequiredSessionMode(): int
|
||||||
|
{
|
||||||
|
return static::REQ_GAME_LOGIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateArgs(): ?string
|
||||||
|
{
|
||||||
|
$v = new Validator($this->args);
|
||||||
|
$v->rule('required', [
|
||||||
|
'title',
|
||||||
|
])->rule('lengthMin', 'title', 1)
|
||||||
|
->rule('int', 'multipleOptions')
|
||||||
|
->rule('date', 'endDate')
|
||||||
|
->rule('stringArray', 'options')
|
||||||
|
->rule('boolean', 'keepOldVote');
|
||||||
|
|
||||||
|
if (!$v->validate()) {
|
||||||
|
return $v->errorStr();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeOldVote(int $voteID, KVStorage $voteStor)
|
||||||
|
{
|
||||||
|
$db = DB::db();
|
||||||
|
$voteStor = KVStorage::getStorage($db, 'vote');
|
||||||
|
$rawLastVoteInfo = $voteStor->getValue("vote_{$voteID}");
|
||||||
|
if (!$rawLastVoteInfo) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$lastVoteInfo = VoteInfo::fromArray($rawLastVoteInfo);
|
||||||
|
if ($lastVoteInfo->endDate) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$lastVoteInfo->endDate = TimeUtil::now();
|
||||||
|
$voteStor->setValue("vote_{$voteID}", $lastVoteInfo->toArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag)
|
||||||
|
{
|
||||||
|
$isVoteAdmin = in_array('vote', $session->acl[DB::prefix()] ?? []);
|
||||||
|
$isVoteAdmin = $isVoteAdmin || $session->userGrade >= 5;
|
||||||
|
|
||||||
|
if (!$isVoteAdmin) {
|
||||||
|
return "권한이 부족합니다.";
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
$title = $this->args['title'];
|
||||||
|
/** @var int */
|
||||||
|
$multipleOptions = $this->args['multipleOptions'] ?? 1;
|
||||||
|
if ($multipleOptions < 0) {
|
||||||
|
$multipleOptions = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
$now = TimeUtil::now();
|
||||||
|
/** @var ?string */
|
||||||
|
$endDate = $this->args['endDate'] ?? null;
|
||||||
|
/** @var string[] */
|
||||||
|
$options = $this->args['options'] ?? [];
|
||||||
|
|
||||||
|
if(!$options){
|
||||||
|
return '항목이 없습니다.';
|
||||||
|
}
|
||||||
|
|
||||||
|
if($endDate !== null){
|
||||||
|
try{
|
||||||
|
$oNow = new \DateTimeImmutable($now);
|
||||||
|
$oEndDate = new \DateTimeImmutable($endDate);
|
||||||
|
if($oEndDate < $oNow){
|
||||||
|
return '종료일이 이미 지났습니다.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(\Throwable $e){
|
||||||
|
return '종료일이 잘못되었습니다.'.$e->getMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$db = DB::db();
|
||||||
|
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||||
|
|
||||||
|
|
||||||
|
$lastVote = $gameStor->getValue('lastVote') ?? 0;
|
||||||
|
$voteID = $lastVote + 1;
|
||||||
|
|
||||||
|
$voteStor = KVStorage::getStorage($db, 'vote');
|
||||||
|
|
||||||
|
if (!($this->args['keepOldVote'] ?? false)) {
|
||||||
|
$this->closeOldVote($lastVote, $voteStor);
|
||||||
|
}
|
||||||
|
|
||||||
|
$multipleOptions = Util::valueFit($multipleOptions, 0, count($options));
|
||||||
|
|
||||||
|
$voteInfo = new VoteInfo(
|
||||||
|
id: $voteID,
|
||||||
|
title: $title,
|
||||||
|
multipleOptions: $multipleOptions,
|
||||||
|
startDate: $now,
|
||||||
|
endDate: $endDate,
|
||||||
|
options: $options,
|
||||||
|
);
|
||||||
|
|
||||||
|
$voteStor->setValue("vote_{$voteID}", $voteInfo->toArray());
|
||||||
|
$gameStor->setValue('lastVote', $voteID);
|
||||||
|
|
||||||
|
$db->update('general', [
|
||||||
|
'newvote' => 1
|
||||||
|
], true);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'result' => true
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,124 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace sammo\API\Vote;
|
||||||
|
|
||||||
|
use DateTimeInterface;
|
||||||
|
use sammo\DB;
|
||||||
|
use sammo\DTO\VoteInfo;
|
||||||
|
use sammo\General;
|
||||||
|
use sammo\Json;
|
||||||
|
use sammo\KVStorage;
|
||||||
|
use sammo\LiteHashDRBG;
|
||||||
|
use sammo\RandUtil;
|
||||||
|
use sammo\Session;
|
||||||
|
use sammo\UniqueConst;
|
||||||
|
use sammo\Util;
|
||||||
|
use sammo\Validator;
|
||||||
|
use Symfony\Component\Lock\LockFactory;
|
||||||
|
use Symfony\Component\Lock\Store\SemaphoreStore;
|
||||||
|
|
||||||
|
use function sammo\tryUniqueItemLottery;
|
||||||
|
|
||||||
|
class Vote extends \sammo\BaseAPI
|
||||||
|
{
|
||||||
|
function getRequiredSessionMode(): int
|
||||||
|
{
|
||||||
|
return static::REQ_GAME_LOGIN | static::REQ_READ_ONLY;
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateArgs(): ?string
|
||||||
|
{
|
||||||
|
$v = new Validator($this->args);
|
||||||
|
$v->rule('required', [
|
||||||
|
'voteID',
|
||||||
|
'selection'
|
||||||
|
])->rule('lengthMin', 'title', 1)
|
||||||
|
->rule('int', 'voteID')
|
||||||
|
->rule('integerArray', 'seletion');
|
||||||
|
|
||||||
|
if (!$v->validate()) {
|
||||||
|
return $v->errorStr();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag)
|
||||||
|
{
|
||||||
|
|
||||||
|
$voteID = $this->args['voteID'];
|
||||||
|
/** @var int[] */
|
||||||
|
$selection = $this->args['selection'];
|
||||||
|
if (!$selection) {
|
||||||
|
return '선택한 항목이 없습니다.';
|
||||||
|
}
|
||||||
|
$db = DB::db();
|
||||||
|
$voteStor = KVStorage::getStorage($db, 'vote');
|
||||||
|
|
||||||
|
$rawVoteInfo = $voteStor->getValue("vote_{$voteID}");
|
||||||
|
if (!$rawVoteInfo) {
|
||||||
|
return '설문조사가 없습니다.';
|
||||||
|
}
|
||||||
|
$voteInfo = VoteInfo::fromArray($rawVoteInfo);
|
||||||
|
|
||||||
|
if ($voteInfo->endDate && $voteInfo->endDate < new \DateTimeImmutable()) {
|
||||||
|
return '설문조사가 종료되었습니다.';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($voteInfo->multipleOptions >= 1 && count($selection) > $voteInfo->multipleOptions) {
|
||||||
|
return '선택한 항목이 너무 많습니다.';
|
||||||
|
}
|
||||||
|
|
||||||
|
$optionsCnt = count($voteInfo->options);
|
||||||
|
foreach ($selection as $sel) {
|
||||||
|
if ($sel >= $optionsCnt) {
|
||||||
|
return '선택한 항목이 없습니다.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sort($selection, SORT_NUMERIC);
|
||||||
|
|
||||||
|
$userID = $session->userID;
|
||||||
|
$generalID = $session->generalID;
|
||||||
|
|
||||||
|
$serverPrefix = DB::prefix();
|
||||||
|
$lockFactory = new LockFactory(new SemaphoreStore());
|
||||||
|
|
||||||
|
$nationID = $db->query('SELECT nation FROM general WHERE no = %i', $generalID);
|
||||||
|
|
||||||
|
|
||||||
|
$lock = $lockFactory->createLock("api_{$serverPrefix}_{$userID}");
|
||||||
|
$lock->acquire(true);
|
||||||
|
|
||||||
|
|
||||||
|
$db->insertIgnore('vote', [
|
||||||
|
'vote_id' => $voteID,
|
||||||
|
'general_id' => $generalID,
|
||||||
|
'nation_id' => $nationID,
|
||||||
|
'selection' => Json::encode($selection),
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($db->affectedRows() == 0) {
|
||||||
|
return '이미 설문조사를 완료하였습니다.';
|
||||||
|
}
|
||||||
|
|
||||||
|
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||||
|
$voteReward = $gameStor->getValue('develcost') * 5;
|
||||||
|
|
||||||
|
$general = General::createGeneralObjFromDB($generalID, ['gold', 'horse', 'weapon', 'book', 'item', 'npc', 'imgsvr', 'picture', 'aux'], 2);
|
||||||
|
$general->increaseVar('gold', $voteReward);
|
||||||
|
$uniqueRng = new RandUtil(new LiteHashDRBG(Util::simpleSerialize(
|
||||||
|
UniqueConst::$hiddenSeed,
|
||||||
|
'voteUnique',
|
||||||
|
$voteID,
|
||||||
|
$generalID
|
||||||
|
)));
|
||||||
|
$wonLottery = tryUniqueItemLottery($uniqueRng, $general, '설문조사');
|
||||||
|
|
||||||
|
$general->applyDB($db);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'result' => true,
|
||||||
|
'wonLottery' => $wonLottery,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,7 +24,7 @@ abstract class AbsFromUserPool extends AbsGeneralPool{
|
|||||||
return $db->affectedRows()!=0;
|
return $db->affectedRows()!=0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static public function pickGeneralFromPool(\MeekroDB $db, int $owner, int $pickCnt, ?string $prefix=null):array{
|
static public function pickGeneralFromPool(\MeekroDB $db, RandUtil $rng, int $owner, int $pickCnt, ?string $prefix=null):array{
|
||||||
$oNow = new \DateTimeImmutable();
|
$oNow = new \DateTimeImmutable();
|
||||||
$now = $oNow->format('Y-m-d H:i:s');
|
$now = $oNow->format('Y-m-d H:i:s');
|
||||||
|
|
||||||
@@ -48,7 +48,7 @@ abstract class AbsFromUserPool extends AbsGeneralPool{
|
|||||||
$result = [];
|
$result = [];
|
||||||
$validUntil = TimeUtil::nowAddMinutes(2 * $gameStor->turnterm);
|
$validUntil = TimeUtil::nowAddMinutes(2 * $gameStor->turnterm);
|
||||||
while(count($result) < $pickCnt){
|
while(count($result) < $pickCnt){
|
||||||
$cand = Util::choiceRandomUsingWeightPair($pool);
|
$cand = $rng->choiceUsingWeightPair($pool);
|
||||||
$poolID = $cand['id'];
|
$poolID = $cand['id'];
|
||||||
if(key_exists($poolID, $result)){
|
if(key_exists($poolID, $result)){
|
||||||
continue;
|
continue;
|
||||||
@@ -64,7 +64,7 @@ abstract class AbsFromUserPool extends AbsGeneralPool{
|
|||||||
if($db->affectedRows()==0){
|
if($db->affectedRows()==0){
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$result[$poolID] = new static($db, $candInfo, $validUntil);
|
$result[$poolID] = new static($db, $rng, $candInfo, $validUntil);
|
||||||
}
|
}
|
||||||
|
|
||||||
return array_values($result);
|
return array_values($result);
|
||||||
|
|||||||
@@ -20,27 +20,28 @@ abstract class AbsGeneralPool{
|
|||||||
* generalName
|
* generalName
|
||||||
* imgsvr
|
* imgsvr
|
||||||
* picture
|
* picture
|
||||||
*
|
*
|
||||||
* leadership
|
* leadership
|
||||||
* strength
|
* strength
|
||||||
* intel
|
* intel
|
||||||
*
|
*
|
||||||
* experience
|
* experience
|
||||||
* dedication
|
* dedication
|
||||||
*
|
*
|
||||||
* dex[5]
|
* dex[5]
|
||||||
*
|
*
|
||||||
* specialDomestic
|
* specialDomestic
|
||||||
* specialWar
|
* specialWar
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public function __construct(\MeekroDB $db, array $info, string $validUntil)
|
public function __construct(\MeekroDB $db, RandUtil $rng, array $info, string $validUntil)
|
||||||
{
|
{
|
||||||
$this->db = $db;
|
$this->db = $db;
|
||||||
$this->info = $info;
|
$this->info = $info;
|
||||||
$this->uniqueName = $info['uniqueName'];
|
$this->uniqueName = $info['uniqueName'];
|
||||||
$this->generalName = $info['generalName'];
|
$this->generalName = $info['generalName'];
|
||||||
$this->builder = new GeneralBuilder(
|
$this->builder = new GeneralBuilder(
|
||||||
|
$rng,
|
||||||
$info['generalName'],
|
$info['generalName'],
|
||||||
$info['imgsvr'],
|
$info['imgsvr'],
|
||||||
$info['picture'],
|
$info['picture'],
|
||||||
@@ -97,14 +98,14 @@ abstract class AbsGeneralPool{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param \MeekroDB $db
|
* @param \MeekroDB $db
|
||||||
* @param int $owner
|
* @param int $owner
|
||||||
* @param int $pickCnt
|
* @param int $pickCnt
|
||||||
* @param null|string $prefix
|
* @param null|string $prefix
|
||||||
* @return AbsGeneralPool[]
|
* @return AbsGeneralPool[]
|
||||||
*/
|
*/
|
||||||
static abstract public function pickGeneralFromPool(\MeekroDB $db, int $owner, int $pickCnt, ?string $prefix=null):array;
|
static abstract public function pickGeneralFromPool(\MeekroDB $db, RandUtil $rng, int $owner, int $pickCnt, ?string $prefix=null):array;
|
||||||
abstract public function occupyGeneralName():bool;
|
abstract public function occupyGeneralName():bool;
|
||||||
|
|
||||||
|
|
||||||
abstract public static function getPoolName():string;
|
abstract public static function getPoolName():string;
|
||||||
abstract public static function initPool(\MeekroDB $db);
|
abstract public static function initPool(\MeekroDB $db);
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ use sammo\DB;
|
|||||||
use \sammo\iAction;
|
use \sammo\iAction;
|
||||||
use \sammo\General;
|
use \sammo\General;
|
||||||
use sammo\KVStorage;
|
use sammo\KVStorage;
|
||||||
|
use sammo\RandUtil;
|
||||||
use sammo\Util;
|
use sammo\Util;
|
||||||
|
|
||||||
class che_보물_도기 extends \sammo\BaseItem
|
class che_보물_도기 extends \sammo\BaseItem
|
||||||
@@ -13,11 +14,11 @@ class che_보물_도기 extends \sammo\BaseItem
|
|||||||
|
|
||||||
protected $rawName = '도기';
|
protected $rawName = '도기';
|
||||||
protected $name = '도기(보물)';
|
protected $name = '도기(보물)';
|
||||||
protected $info = '[개인] 판매 시 장수 소지금과 국고에 금, 쌀 중 하나를 추가 (총 +10,000, 5년마다 +10,000)';
|
protected $info = '[개인] 판매 시 장수 소지금과 국고에 금, 쌀 중 하나를 추가 (총 +10,000, 2년마다 +5,000)';
|
||||||
protected $cost = 200;
|
protected $cost = 200;
|
||||||
protected $consumable = false;
|
protected $consumable = false;
|
||||||
|
|
||||||
public function onArbitraryAction(General $general, string $actionType, ?string $phase = null, $aux = null): ?array
|
public function onArbitraryAction(General $general, RandUtil $rng, string $actionType, ?string $phase = null, $aux = null): ?array
|
||||||
{
|
{
|
||||||
if ($aux === null){
|
if ($aux === null){
|
||||||
return $aux;
|
return $aux;
|
||||||
@@ -37,9 +38,9 @@ class che_보물_도기 extends \sammo\BaseItem
|
|||||||
[$year, $startYear] = $gameStor->getValuesAsArray(['year', 'startyear']);
|
[$year, $startYear] = $gameStor->getValuesAsArray(['year', 'startyear']);
|
||||||
$relYear = $year - $startYear;
|
$relYear = $year - $startYear;
|
||||||
|
|
||||||
$score = 10000 * (1 + Util::valueFit(intdiv($relYear, 5), 0));
|
$score = 10000 + 5000 * Util::valueFit(intdiv($relYear, 2), 0);
|
||||||
|
|
||||||
[$resName, $resKey] = Util::choiceRandom([
|
[$resName, $resKey] = $rng->choice([
|
||||||
['금', 'gold'],
|
['금', 'gold'],
|
||||||
['쌀', 'rice']
|
['쌀', 'rice']
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ class che_저지_삼황내문 extends \sammo\BaseItem{
|
|||||||
if($unit->getPhase() >= 2){
|
if($unit->getPhase() >= 2){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if($unit->getPhase() == 1 && Util::randBool(0.5)){
|
if($unit->getPhase() == 1 && $unit->rng->nextBool(0.5)){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ use \sammo\iAction;
|
|||||||
use \sammo\General;
|
use \sammo\General;
|
||||||
use \sammo\GeneralTrigger;
|
use \sammo\GeneralTrigger;
|
||||||
use \sammo\GeneralTriggerCaller;
|
use \sammo\GeneralTriggerCaller;
|
||||||
|
use sammo\RandUtil;
|
||||||
|
|
||||||
class che_치료_환약 extends \sammo\BaseItem{
|
class che_치료_환약 extends \sammo\BaseItem{
|
||||||
|
|
||||||
@@ -23,7 +24,7 @@ class che_치료_환약 extends \sammo\BaseItem{
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onArbitraryAction(General $general, string $actionType, ?string $phase = null, $aux = null): ?array
|
function onArbitraryAction(General $general, RandUtil $rng, string $actionType, ?string $phase = null, $aux = null): ?array
|
||||||
{
|
{
|
||||||
if($actionType != '장비매매'){
|
if($actionType != '장비매매'){
|
||||||
return $aux;
|
return $aux;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ class event_전투특기_필살 extends \sammo\BaseItem{
|
|||||||
|
|
||||||
protected $rawName = '비급';
|
protected $rawName = '비급';
|
||||||
protected $name = '비급(필살)';
|
protected $name = '비급(필살)';
|
||||||
protected $info = '[전투] 필살 확률 +30%p, 필살 발동시 대상 회피 불가';
|
protected $info = '[전투] 필살 확률 +30%p, 필살 발동시 대상 회피 불가, 필살 계수 항상 최대';
|
||||||
protected $cost = 100;
|
protected $cost = 100;
|
||||||
protected $buyable = true;
|
protected $buyable = true;
|
||||||
protected $consumable = false;
|
protected $consumable = false;
|
||||||
@@ -21,6 +21,11 @@ class event_전투특기_필살 extends \sammo\BaseItem{
|
|||||||
if($statName === 'warCriticalRatio'){
|
if($statName === 'warCriticalRatio'){
|
||||||
return $value + 0.3;
|
return $value + 0.3;
|
||||||
}
|
}
|
||||||
|
if($statName === 'criticalDamageRange'){
|
||||||
|
[, $rangeMax] = $value;
|
||||||
|
return [$rangeMax, $rangeMax];
|
||||||
|
}
|
||||||
|
|
||||||
return $value;
|
return $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ class che_event_필살 extends \sammo\BaseSpecial{
|
|||||||
|
|
||||||
protected $id = 71;
|
protected $id = 71;
|
||||||
protected $name = '필살';
|
protected $name = '필살';
|
||||||
protected $info = '[전투] 필살 확률 +30%p, 필살 발동시 대상 회피 불가';
|
protected $info = '[전투] 필살 확률 +30%p, 필살 발동시 대상 회피 불가, 필살 계수 항상 최대';
|
||||||
|
|
||||||
static $selectWeightType = SpecialityHelper::WEIGHT_NORM;
|
static $selectWeightType = SpecialityHelper::WEIGHT_NORM;
|
||||||
static $selectWeight = 1;
|
static $selectWeight = 1;
|
||||||
@@ -25,6 +25,11 @@ class che_event_필살 extends \sammo\BaseSpecial{
|
|||||||
if($statName === 'warCriticalRatio'){
|
if($statName === 'warCriticalRatio'){
|
||||||
return $value + 0.30;
|
return $value + 0.30;
|
||||||
}
|
}
|
||||||
|
if($statName === 'criticalDamageRange'){
|
||||||
|
[, $rangeMax] = $value;
|
||||||
|
return [$rangeMax, $rangeMax];
|
||||||
|
}
|
||||||
|
|
||||||
return $value;
|
return $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,524 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace sammo;
|
||||||
|
|
||||||
|
use DateTime;
|
||||||
|
use DateTimeImmutable;
|
||||||
|
use DateTimeInterface;
|
||||||
|
use sammo\DTO\AuctionBidItem;
|
||||||
|
use sammo\DTO\AuctionBidItemData;
|
||||||
|
use sammo\DTO\AuctionInfo;
|
||||||
|
use sammo\Enums\AuctionType;
|
||||||
|
use sammo\Enums\InheritanceKey;
|
||||||
|
use sammo\Enums\RankColumn;
|
||||||
|
use sammo\Enums\ResourceType;
|
||||||
|
|
||||||
|
abstract class Auction
|
||||||
|
{
|
||||||
|
|
||||||
|
protected AuctionInfo $info;
|
||||||
|
|
||||||
|
static AuctionType $auctionType;
|
||||||
|
|
||||||
|
public const COEFF_AUCTION_CLOSE_MINUTES = 24;
|
||||||
|
public const COEFF_EXTENSION_MINUTES_PER_BID = (1 / 6);
|
||||||
|
public const COEFF_EXTENSION_MINUTES_LIMIT_BY_BID = 1;
|
||||||
|
public const COEFF_EXTENSION_MINUTES_BY_EXTENSION_QUERY = 1;
|
||||||
|
public const MIN_AUCTION_CLOSE_MINUTES = 30;
|
||||||
|
public const MIN_EXTENSION_MINUTES_PER_BID = 1;
|
||||||
|
public const MIN_EXTENSION_MINUTES_LIMIT_BY_BID = 5;
|
||||||
|
public const MIN_EXTENSION_MINUTES_BY_EXTENSION_QUERY = 5;
|
||||||
|
|
||||||
|
protected AuctionBidItem|null|false $_highestBid = false;
|
||||||
|
|
||||||
|
static public function genObfuscatedName(int $id): string
|
||||||
|
{
|
||||||
|
$db = DB::db();
|
||||||
|
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||||
|
|
||||||
|
$namePool = $gameStor->getValue('obfuscatedNamePool');
|
||||||
|
if ($namePool === null) {
|
||||||
|
$rng = new RandUtil(new LiteHashDRBG(Util::simpleSerialize(
|
||||||
|
UniqueConst::$hiddenSeed,
|
||||||
|
)));
|
||||||
|
$namePool = [];
|
||||||
|
foreach (GameConst::$randGenFirstName as $ch0) {
|
||||||
|
foreach (GameConst::$randGenMiddleName as $ch1) {
|
||||||
|
foreach (GameConst::$randGenLastName as $ch2) {
|
||||||
|
$namePool[] = "{$ch0}{$ch1}{$ch2}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$namePool = $rng->shuffle($namePool);
|
||||||
|
$gameStor->setValue('obfuscatedNamePool', $namePool);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$dupIdx = intdiv($id, count($namePool));
|
||||||
|
$subIdx = $id % count($namePool);
|
||||||
|
if ($dupIdx == 0) {
|
||||||
|
return $namePool[$subIdx];
|
||||||
|
}
|
||||||
|
return "{$namePool[$subIdx]}{$dupIdx}";
|
||||||
|
}
|
||||||
|
|
||||||
|
static protected function openAuction(AuctionInfo $info, General $general): int|string
|
||||||
|
{
|
||||||
|
$db = DB::db();
|
||||||
|
if ($info->id !== null) {
|
||||||
|
return 'id가 지정되어 있습니다.';
|
||||||
|
}
|
||||||
|
|
||||||
|
$db->insert('ng_auction', $info->toArray());
|
||||||
|
return $db->insertId();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getHighestBid(): ?AuctionBidItem
|
||||||
|
{
|
||||||
|
$db = DB::db();
|
||||||
|
|
||||||
|
if ($this->_highestBid !== false) {
|
||||||
|
return $this->_highestBid;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->info->detail->isReverse) {
|
||||||
|
$rawHighestBid = $db->queryFirstRow(
|
||||||
|
'SELECT * FROM ng_auction_bid WHERE auction_id = %i ORDER BY `amount` DESC LIMIT 1',
|
||||||
|
$this->info->id
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$rawHighestBid = $db->queryFirstRow(
|
||||||
|
'SELECT * FROM ng_auction_bid WHERE auction_id = %i ORDER BY `amount` ASC LIMIT 1',
|
||||||
|
$this->info->id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$rawHighestBid) {
|
||||||
|
$this->_highestBid = null;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$highestBid = AuctionBidItem::fromArray($rawHighestBid);
|
||||||
|
$this->_highestBid = $highestBid;
|
||||||
|
return $highestBid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMyPrevBid(): ?AuctionBidItem
|
||||||
|
{
|
||||||
|
$db = DB::db();
|
||||||
|
if (!$this->info->detail->isReverse) {
|
||||||
|
$rawMyPrevBid = $db->queryFirstRow(
|
||||||
|
'SELECT * FROM ng_auction_bid WHERE general_id = %i AND auction_id = %i ORDER BY `amount` DESC LIMIT 1',
|
||||||
|
$this->general->getID(),
|
||||||
|
$this->info->id
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$rawMyPrevBid = $db->queryFirstRow(
|
||||||
|
'SELECT * FROM ng_auction_bid WHERE general_id = %i AND auction_id = %i ORDER BY `amount` ASC LIMIT 1',
|
||||||
|
$this->general->getID(),
|
||||||
|
$this->info->id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (!$rawMyPrevBid) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return AuctionBidItem::fromArray($rawMyPrevBid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __construct(protected readonly int $auctionID, protected General $general)
|
||||||
|
{
|
||||||
|
$db = DB::db();
|
||||||
|
$rawAuctionInfo = $db->queryFirstRow('SELECT * FROM `ng_auction` WHERE id = %i', $auctionID);
|
||||||
|
if (!$rawAuctionInfo) {
|
||||||
|
throw new \RuntimeException("해당 경매가 없습니다: {$auctionID}");
|
||||||
|
}
|
||||||
|
$this->info = AuctionInfo::fromArray($rawAuctionInfo);
|
||||||
|
$thisAuctionType = static::$auctionType;
|
||||||
|
if ($this->info->type !== $thisAuctionType) {
|
||||||
|
throw new \RuntimeException("잘못된 경매 타입입니다: {$this->info->type->value} != {$thisAuctionType->value}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getInfo(): AuctionInfo
|
||||||
|
{
|
||||||
|
return $this->info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function shrinkCloseDate(?DateTimeInterface $date): ?string
|
||||||
|
{
|
||||||
|
if ($date === null) {
|
||||||
|
$date = new DateTimeImmutable();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->info->closeDate = $date;
|
||||||
|
$db = DB::db();
|
||||||
|
$db->update('ng_auction', $this->info->toArray('id'), 'id = %i', $this->info->id);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function extendLatestBidCloseDate(?DateTimeInterface $date): ?string
|
||||||
|
{
|
||||||
|
if ($date === null) {
|
||||||
|
$db = DB::db();
|
||||||
|
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||||
|
$turnTerm = $gameStor->getValue('turnterm');
|
||||||
|
$date = $this->info->closeDate->add(TimeUtil::secondsToDateInterval(
|
||||||
|
max(static::MIN_EXTENSION_MINUTES_PER_BID, $turnTerm * static::COEFF_EXTENSION_MINUTES_PER_BID) * 60
|
||||||
|
));
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
$date = DateTimeImmutable::createFromInterface($date);
|
||||||
|
}
|
||||||
|
if ($this->info->detail->availableLatestBidCloseDate !== null && $date < $this->info->detail->availableLatestBidCloseDate) {
|
||||||
|
return '기간보다 짧습니다.';
|
||||||
|
}
|
||||||
|
$this->info->detail->availableLatestBidCloseDate = $date;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function extendCloseDate(DateTimeInterface $date, bool $force = false): ?string
|
||||||
|
{
|
||||||
|
if (!$force) {
|
||||||
|
if ($this->info->detail->remainCloseDateExtensionCnt === null) {
|
||||||
|
return '연장할 수 없는 경매입니다.';
|
||||||
|
}
|
||||||
|
if ($this->info->detail->remainCloseDateExtensionCnt === 0) {
|
||||||
|
return '더 이상 연장할 수 없습니다';
|
||||||
|
}
|
||||||
|
if ($this->info->detail->remainCloseDateExtensionCnt > 0) {
|
||||||
|
$this->info->detail->remainCloseDateExtensionCnt--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($date < $this->info->closeDate) {
|
||||||
|
return '종료 기간보다 짧습니다.';
|
||||||
|
}
|
||||||
|
|
||||||
|
$closeDate = DateTimeImmutable::createFromInterface($date);
|
||||||
|
$this->info->closeDate = $closeDate;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function applyDB(): void
|
||||||
|
{
|
||||||
|
$db = DB::db();
|
||||||
|
$db->update('ng_auction', $this->info->toArray('id'), 'id = %i', $this->info->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function refundBid(AuctionBidItem $bidItem, string $reason): void
|
||||||
|
{
|
||||||
|
if ($bidItem->auctionID !== $this->info->id) {
|
||||||
|
throw new \RuntimeException('잘못된 경매입니다.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$db = DB::db();
|
||||||
|
if ($bidItem->generalID === $this->general->getID()) {
|
||||||
|
$oldBidder = $this->general;
|
||||||
|
} else {
|
||||||
|
$oldBidder = General::createGeneralObjFromDB($bidItem->generalID);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->info->reqResource === ResourceType::inheritancePoint) {
|
||||||
|
$oldBidder->increaseInheritancePoint(InheritanceKey::previous, $bidItem->amount);
|
||||||
|
$oldBidder->increaseRankVar(RankColumn::inherit_point_spent_dynamic, -$bidItem->amount);
|
||||||
|
} else {
|
||||||
|
$oldBidder->increaseVar($this->info->reqResource->value, $bidItem->amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($oldBidder instanceof DummyGeneral) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$staticNation = $oldBidder->getStaticNation();
|
||||||
|
$src = new MessageTarget(0, '', 0, 'System', '#000000');
|
||||||
|
$dest = new MessageTarget(
|
||||||
|
$oldBidder->getID(),
|
||||||
|
$oldBidder->getName(),
|
||||||
|
$oldBidder->getNationID(),
|
||||||
|
$staticNation['name'],
|
||||||
|
$staticNation['color'],
|
||||||
|
GetImageURL($oldBidder->getVar('imgsvr'), $oldBidder->getVar('picture'))
|
||||||
|
);
|
||||||
|
|
||||||
|
//TODO: 전역 알림이 나타나야한다. 일반 메시지보다는 중요하고, 메시지보단 약하게..
|
||||||
|
//TODO: 바로가기를 제공하는 편이 좋을 것 같다.
|
||||||
|
$msg = new Message(
|
||||||
|
Message::MSGTYPE_PRIVATE,
|
||||||
|
$src,
|
||||||
|
$dest,
|
||||||
|
$reason,
|
||||||
|
new DateTime(),
|
||||||
|
new DateTime('9999-12-31'),
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
$oldBidder->applyDB($db);
|
||||||
|
$msg->send(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function closeAuction(bool $isRollback = false): void
|
||||||
|
{
|
||||||
|
$db = DB::db();
|
||||||
|
|
||||||
|
$this->info->finished = true;
|
||||||
|
|
||||||
|
if ($isRollback) {
|
||||||
|
$highestBid = $this->getHighestBid();
|
||||||
|
if ($highestBid !== null) {
|
||||||
|
$this->refundBid($highestBid, "{$this->info->id}번 {$this->info->detail->title} 경매가 취소되었습니다.");
|
||||||
|
}
|
||||||
|
$this->rollbackAuction();
|
||||||
|
}
|
||||||
|
|
||||||
|
$db->update('ng_auction', $this->info->toArray('id'), 'id = %i', $this->info->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function bidInheritPoint(int $amount, \DateTimeImmutable $now, bool $tryExtendCloseDate): ?string
|
||||||
|
{
|
||||||
|
$db = DB::db();
|
||||||
|
|
||||||
|
$auctionInfo = $this->info;
|
||||||
|
$general = $this->general;
|
||||||
|
|
||||||
|
$highestBid = $this->getHighestBid();
|
||||||
|
if ($highestBid !== null && $amount < $highestBid->amount + 10) {
|
||||||
|
return '현재입찰가보다 10 포인트 높게 입찰해야 합니다.';
|
||||||
|
}
|
||||||
|
|
||||||
|
$myPrevBid = $this->getMyPrevBid();
|
||||||
|
if ($myPrevBid !== null && $highestBid->no !== $myPrevBid->no) {
|
||||||
|
//이미 환불 받았으니 무효.
|
||||||
|
$myPrevBid = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$morePoint = $amount - ($myPrevBid ? $myPrevBid->amount : 0);
|
||||||
|
$currPoint = $general->getInheritancePoint(InheritanceKey::previous);
|
||||||
|
if ($currPoint === null || $currPoint < $morePoint) {
|
||||||
|
return '유산포인트가 부족합니다.';
|
||||||
|
}
|
||||||
|
|
||||||
|
$obfuscatedName = static::genObfuscatedName($general->getID());
|
||||||
|
//여기서부터 입찰 성공
|
||||||
|
|
||||||
|
$newBid = new AuctionBidItem(
|
||||||
|
null,
|
||||||
|
$auctionInfo->id,
|
||||||
|
$general->getVar('owner'),
|
||||||
|
$general->getID(),
|
||||||
|
$amount,
|
||||||
|
$now,
|
||||||
|
new AuctionBidItemData(
|
||||||
|
$general->getVar('owner_name'),
|
||||||
|
$obfuscatedName,
|
||||||
|
$tryExtendCloseDate,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$db->insert('ng_auction_bid', $newBid->toArray());
|
||||||
|
if ($db->affectedRows() == 0) {
|
||||||
|
return '입찰에 실패했습니다: DB 오류';
|
||||||
|
}
|
||||||
|
|
||||||
|
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||||
|
$turnTerm = $gameStor->getValue('turnterm');
|
||||||
|
|
||||||
|
if ($this->info->detail->availableLatestBidCloseDate !== null) {
|
||||||
|
$extendedCloseDate = $now->add(TimeUtil::secondsToDateInterval(
|
||||||
|
max(static::MIN_EXTENSION_MINUTES_PER_BID, $turnTerm * static::COEFF_EXTENSION_MINUTES_PER_BID) * 60
|
||||||
|
));
|
||||||
|
|
||||||
|
if ($extendedCloseDate > $this->info->closeDate && $this->info->closeDate < $this->info->detail->availableLatestBidCloseDate) {
|
||||||
|
$this->extendCloseDate(min($extendedCloseDate, $this->info->detail->availableLatestBidCloseDate), true);
|
||||||
|
$this->applyDB();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$general->increaseInheritancePoint(InheritanceKey::previous, -$morePoint);
|
||||||
|
$general->increaseRankVar(RankColumn::inherit_point_spent_dynamic, $morePoint);
|
||||||
|
|
||||||
|
if ($highestBid !== null && $myPrevBid === null) {
|
||||||
|
$this->refundBid($highestBid, "{$auctionInfo->id}번 {$auctionInfo->detail->title}에 상회입찰자가 나타났습니다.");
|
||||||
|
}
|
||||||
|
$general->applyDB($db);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function _bid(int $amount, bool $tryExtendCloseDate = false): ?string
|
||||||
|
{
|
||||||
|
$auctionInfo = $this->info;
|
||||||
|
$general = $this->general;
|
||||||
|
|
||||||
|
if ($auctionInfo->finished) {
|
||||||
|
return '경매가 이미 끝났습니다.';
|
||||||
|
}
|
||||||
|
|
||||||
|
$now = new \DateTimeImmutable();
|
||||||
|
|
||||||
|
if ($auctionInfo->closeDate < $now) {
|
||||||
|
return '경매가 이미 끝났습니다.';
|
||||||
|
}
|
||||||
|
if ($auctionInfo->openDate > $now) {
|
||||||
|
return '경매가 아직 시작되지 않았습니다.';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$auctionInfo->detail->isReverse) {
|
||||||
|
if ($auctionInfo->detail->finishBidAmount !== null && $auctionInfo->detail->finishBidAmount < $amount) {
|
||||||
|
return '즉시판매가보다 높을 수 없습니다.';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ($auctionInfo->detail->finishBidAmount !== null && $auctionInfo->detail->finishBidAmount > $amount) {
|
||||||
|
return '즉시판매가보다 낮을 수 없습니다.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if ($auctionInfo->reqResource === ResourceType::inheritancePoint) {
|
||||||
|
return $this->bidInheritPoint($amount, $now, $tryExtendCloseDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
//reqResource는 말 그대로 '구매자가 내야하는 자원'이다.
|
||||||
|
|
||||||
|
$db = DB::db();
|
||||||
|
|
||||||
|
$highestBid = $this->getHighestBid();
|
||||||
|
if (!$auctionInfo->detail->isReverse) {
|
||||||
|
if ($highestBid !== null && $amount <= $highestBid->amount) {
|
||||||
|
return '현재입찰가보다 높게 입찰해야 합니다.';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ($highestBid !== null && $amount >= $highestBid->amount) {
|
||||||
|
return '현재입찰가보다 낮게 입찰해야 합니다.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$myPrevBid = $this->getMyPrevBid();
|
||||||
|
if ($myPrevBid !== null && $highestBid->no !== $myPrevBid->no) {
|
||||||
|
//이미 환불 받았으니 무효.
|
||||||
|
$myPrevBid = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$morePoint = $amount - ($myPrevBid ? $myPrevBid->amount : 0);
|
||||||
|
$resType = $auctionInfo->reqResource;
|
||||||
|
$minReqRes = match ($resType) {
|
||||||
|
ResourceType::gold => GameConst::$defaultGold,
|
||||||
|
ResourceType::rice => GameConst::$defaultRice,
|
||||||
|
};
|
||||||
|
|
||||||
|
if ($general->getVar($resType->value) < $morePoint + $minReqRes) {
|
||||||
|
return $resType->getName() . '이 부족합니다.';
|
||||||
|
}
|
||||||
|
|
||||||
|
//여기서부터 입찰 성공
|
||||||
|
|
||||||
|
$newBid = new AuctionBidItem(
|
||||||
|
null,
|
||||||
|
$auctionInfo->id,
|
||||||
|
$general->getVar('owner'),
|
||||||
|
$general->getID(),
|
||||||
|
$amount,
|
||||||
|
$now,
|
||||||
|
new AuctionBidItemData(
|
||||||
|
$general->getVar('owner_name'),
|
||||||
|
$general->getName(),
|
||||||
|
$tryExtendCloseDate,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$db->insert('ng_auction_bid', $newBid->toArray());
|
||||||
|
if ($db->affectedRows() == 0) {
|
||||||
|
return '입찰에 실패했습니다: DB 오류';
|
||||||
|
}
|
||||||
|
|
||||||
|
$general->increaseVar($resType->value, -$morePoint);
|
||||||
|
|
||||||
|
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||||
|
$turnTerm = $gameStor->getValue('turnterm');
|
||||||
|
$extendedCloseDate = $now->add(TimeUtil::secondsToDateInterval(
|
||||||
|
max(static::MIN_EXTENSION_MINUTES_PER_BID, $turnTerm * static::COEFF_EXTENSION_MINUTES_PER_BID) * 60
|
||||||
|
));
|
||||||
|
|
||||||
|
if ($extendedCloseDate > $this->info->closeDate) {
|
||||||
|
$this->extendCloseDate($extendedCloseDate, true);
|
||||||
|
$this->applyDB();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($highestBid !== null && $myPrevBid === null) {
|
||||||
|
$this->refundBid($highestBid, "{$auctionInfo->id}번 {$auctionInfo->detail->title}에 상회입찰자가 나타났습니다.");
|
||||||
|
}
|
||||||
|
$general->applyDB($db);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function tryFinish(): ?bool
|
||||||
|
{
|
||||||
|
$now = new DateTimeImmutable();
|
||||||
|
if ($now < $this->info->closeDate) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
//경매를 닫아야한다.
|
||||||
|
$highestBid = $this->getHighestBid();
|
||||||
|
if ($highestBid === null) {
|
||||||
|
$this->closeAuction(true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($highestBid->aux->tryExtendCloseDate) {
|
||||||
|
$db = DB::db();
|
||||||
|
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||||
|
$turnTerm = $gameStor->getValue('turnterm');
|
||||||
|
|
||||||
|
//연장 요청이 있었다.
|
||||||
|
$extendedCloseDate = $this->info->closeDate->add(TimeUtil::secondsToDateInterval(
|
||||||
|
max(static::MIN_EXTENSION_MINUTES_BY_EXTENSION_QUERY, $turnTerm * static::COEFF_EXTENSION_MINUTES_BY_EXTENSION_QUERY) * 60
|
||||||
|
));
|
||||||
|
|
||||||
|
if ($this->extendCloseDate($extendedCloseDate) === null) {
|
||||||
|
$this->extendLatestBidCloseDate(null);
|
||||||
|
$this->applyDB();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$bidder = General::createGeneralObjFromDB($highestBid->generalID);
|
||||||
|
$failReason = $this->finishAuction($highestBid, $bidder);
|
||||||
|
if ($failReason === null) {
|
||||||
|
$this->closeAuction();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($bidder instanceof DummyGeneral) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$staticNation = $bidder->getStaticNation();
|
||||||
|
$src = new MessageTarget(0, '', 0, 'System', '#000000');
|
||||||
|
$dest = new MessageTarget(
|
||||||
|
$bidder->getID(),
|
||||||
|
$bidder->getName(),
|
||||||
|
$bidder->getNationID(),
|
||||||
|
$staticNation['name'],
|
||||||
|
$staticNation['color'],
|
||||||
|
GetImageURL($bidder->getVar('imgsvr'), $bidder->getVar('picture'))
|
||||||
|
);
|
||||||
|
|
||||||
|
//TODO: 전역 알림이 나타나야한다. 일반 메시지보다는 중요하고, 메시지보단 약하게..
|
||||||
|
//TODO: 바로가기를 제공하는 편이 좋을 것 같다.
|
||||||
|
$msg = new Message(
|
||||||
|
Message::MSGTYPE_PRIVATE,
|
||||||
|
$src,
|
||||||
|
$dest,
|
||||||
|
$failReason,
|
||||||
|
new \DateTime(),
|
||||||
|
new \DateTime('9999-12-31'),
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
$msg->send(true);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract public function bid(int $amount, bool $tryExtendCloseDate): ?string;
|
||||||
|
|
||||||
|
abstract protected function rollbackAuction(): void;
|
||||||
|
abstract protected function finishAuction(AuctionBidItem $highestBid, General $bidder): ?string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,254 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace sammo;
|
||||||
|
|
||||||
|
use DateTimeImmutable;
|
||||||
|
use sammo\DTO\AuctionBidItem;
|
||||||
|
use sammo\DTO\AuctionInfo;
|
||||||
|
use sammo\DTO\AuctionInfoDetail;
|
||||||
|
use sammo\Enums\AuctionType;
|
||||||
|
use sammo\Enums\ResourceType;
|
||||||
|
|
||||||
|
abstract class AuctionBasicResource extends Auction
|
||||||
|
{
|
||||||
|
const MIN_AUCTION_AMOUNT = 100;
|
||||||
|
const MAX_AUCTION_AMOUNT = 10000;
|
||||||
|
static ResourceType $hostRes;
|
||||||
|
static ResourceType $bidderRes;
|
||||||
|
|
||||||
|
static public function openResourceAuction(General $general, int $amount, int $closeTurnCnt, int $startBidAmount, int $finishBidAmount): self|string
|
||||||
|
{
|
||||||
|
if ($closeTurnCnt < 1 || $closeTurnCnt > 24) {
|
||||||
|
return '종료기한은 1 ~ 24 턴 이어야 합니다.';
|
||||||
|
}
|
||||||
|
if ($amount < self::MIN_AUCTION_AMOUNT || $amount > self::MAX_AUCTION_AMOUNT) {
|
||||||
|
return '거래량은 ' . self::MIN_AUCTION_AMOUNT . ' ~ ' . self::MAX_AUCTION_AMOUNT . ' 이어야 합니다.';
|
||||||
|
}
|
||||||
|
if ($startBidAmount < $amount * 0.5 || $amount * 2 < $startBidAmount) {
|
||||||
|
return '시작거래가는 50% ~ 200% 이어야 합니다.';
|
||||||
|
}
|
||||||
|
if ($finishBidAmount < $amount * 1.1 || $amount * 2 < $finishBidAmount) {
|
||||||
|
return '즉시거래가는 110% ~ 200% 이어야 합니다.';
|
||||||
|
}
|
||||||
|
if ($finishBidAmount < $startBidAmount * 1.1) {
|
||||||
|
return '즉시거래가는 시작판매가의 110% 이상이어야 합니다.';
|
||||||
|
}
|
||||||
|
|
||||||
|
$hostRes = static::$hostRes;
|
||||||
|
$hostResName = $hostRes->getName();
|
||||||
|
$bidderRes = static::$bidderRes;
|
||||||
|
$minimumRes = static::$hostRes === ResourceType::rice ? GameConst::$generalMinimumRice : GameConst::$generalMinimumGold;
|
||||||
|
if ($general->getVar($hostRes->value) < $amount + $minimumRes) {
|
||||||
|
return "기본 {$hostRes->getName()} {$minimumRes}은 거래할 수 없습니다.";
|
||||||
|
}
|
||||||
|
|
||||||
|
$db = DB::db();
|
||||||
|
if (!($general instanceof DummyGeneral)) {
|
||||||
|
$prevAuctionID = $db->queryFirstField(
|
||||||
|
'SELECT id FROM ng_auction WHERE host_general_id = %i AND finished = 0 AND `type` IN %ls',
|
||||||
|
$general->getID(),
|
||||||
|
[AuctionType::BuyRice->value, AuctionType::SellRice->value],
|
||||||
|
);
|
||||||
|
if ($prevAuctionID !== null) {
|
||||||
|
return '아직 경매가 끝나지 않았습니다.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$now = new \DateTimeImmutable();
|
||||||
|
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||||
|
$turnTerm = $gameStor->getValue('turnterm');
|
||||||
|
$closeDate = $now->add(TimeUtil::secondsToDateInterval($closeTurnCnt * $turnTerm * 60));
|
||||||
|
|
||||||
|
$openResult = static::openAuction(new AuctionInfo(
|
||||||
|
null,
|
||||||
|
static::$auctionType,
|
||||||
|
false,
|
||||||
|
"$amount",
|
||||||
|
$general->getId(),
|
||||||
|
$bidderRes,
|
||||||
|
$now,
|
||||||
|
$closeDate,
|
||||||
|
new AuctionInfoDetail(
|
||||||
|
"{$hostResName} {$amount} 경매",
|
||||||
|
$general->getName(),
|
||||||
|
$amount,
|
||||||
|
false,
|
||||||
|
$startBidAmount,
|
||||||
|
$finishBidAmount,
|
||||||
|
null,
|
||||||
|
null
|
||||||
|
)
|
||||||
|
), $general);
|
||||||
|
|
||||||
|
if (is_string($openResult)) {
|
||||||
|
return $openResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
$general->increaseVarWithLimit($hostRes->value, -$amount, 0);
|
||||||
|
$general->applyDB($db);
|
||||||
|
|
||||||
|
return new static($openResult, $general);
|
||||||
|
}
|
||||||
|
|
||||||
|
static public function genDummy(bool $initFullLogger = true): DummyGeneral
|
||||||
|
{
|
||||||
|
$dummyGeneral = new DummyGeneral(false);
|
||||||
|
$dummyGeneral->setVar('name', '상인');
|
||||||
|
$dummyGeneral->setVar('gold', static::MAX_AUCTION_AMOUNT * 10);
|
||||||
|
$dummyGeneral->setVar('rice', static::MAX_AUCTION_AMOUNT * 10);
|
||||||
|
|
||||||
|
if($initFullLogger){
|
||||||
|
$db = DB::db();
|
||||||
|
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||||
|
[$year, $month] = $gameStor->getValuesAsArray(['year', 'month']);
|
||||||
|
$dummyGeneral->initLogger($year, $month);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $dummyGeneral;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function rollbackAuction(): void
|
||||||
|
{
|
||||||
|
if ($this->general->getID() === $this->info->hostGeneralID) {
|
||||||
|
$auctionHost = $this->general;
|
||||||
|
} else if ($this->info->hostGeneralID == 0) {
|
||||||
|
$auctionHost = $this->genDummy();
|
||||||
|
} else {
|
||||||
|
$auctionHost = General::createGeneralObjFromDB($this->info->hostGeneralID);
|
||||||
|
}
|
||||||
|
|
||||||
|
$hostRes = static::$hostRes;
|
||||||
|
$hostResName = $hostRes->getName();
|
||||||
|
|
||||||
|
$auctionHost->increaseVar($hostRes->value, $this->info->detail->amount);
|
||||||
|
$auctionHost->applyDB(DB::db());
|
||||||
|
|
||||||
|
if($this->info->hostGeneralID != 0){
|
||||||
|
$josaYiHost = JosaUtil::pick($auctionHost->getName(), '이');
|
||||||
|
$auctionAmount = $this->info->detail->amount;
|
||||||
|
$auctionLog = "{$this->auctionID}번 {$hostResName} 경매 <M>유찰</> : <Y>{$auctionHost->getName()}</>{$josaYiHost} {$hostResName} <C>{$auctionAmount}</> 판매, 그러나 입찰자 부재";
|
||||||
|
pushAuctionLog($auctionHost->getLogger()->formatText($auctionLog, ActionLogger::EVENT_PLAIN));
|
||||||
|
}
|
||||||
|
|
||||||
|
$staticNation = $auctionHost->getStaticNation();
|
||||||
|
$src = new MessageTarget(0, '', 0, 'System', '#000000');
|
||||||
|
$dest = new MessageTarget(
|
||||||
|
$auctionHost->getID(),
|
||||||
|
$auctionHost->getName(),
|
||||||
|
$auctionHost->getNationID(),
|
||||||
|
$staticNation['name'],
|
||||||
|
$staticNation['color'],
|
||||||
|
GetImageURL($auctionHost->getVar('imgsvr'), $auctionHost->getVar('picture'))
|
||||||
|
);
|
||||||
|
|
||||||
|
//TODO: 전역 알림이 나타나야한다. 일반 메시지보다는 중요하고, 메시지보단 약하게..
|
||||||
|
//TODO: 바로가기를 제공하는 편이 좋을 것 같다.
|
||||||
|
$msg = new Message(
|
||||||
|
Message::MSGTYPE_PRIVATE,
|
||||||
|
$src,
|
||||||
|
$dest,
|
||||||
|
"{$this->auctionID}번 {$hostResName} 경매에 입찰이 없어 취소되었습니다.",
|
||||||
|
new \DateTime(),
|
||||||
|
new \DateTime('9999-12-31'),
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
$msg->send(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function finishAuction(AuctionBidItem $highestBid, General $bidder): ?string
|
||||||
|
{
|
||||||
|
if ($this->general->getID() === $this->info->hostGeneralID) {
|
||||||
|
$auctionHost = $this->general;
|
||||||
|
} else if ($this->info->hostGeneralID == 0) {
|
||||||
|
$auctionHost = $this->genDummy();
|
||||||
|
} else {
|
||||||
|
$auctionHost = General::createGeneralObjFromDB($this->info->hostGeneralID);
|
||||||
|
}
|
||||||
|
|
||||||
|
$highestBid = $this->getHighestBid();
|
||||||
|
if ($highestBid === null) {
|
||||||
|
throw new \Exception('입찰자가 없습니다.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->general->getID() === $highestBid->generalID) {
|
||||||
|
$bidder = $this->general;
|
||||||
|
} else {
|
||||||
|
$bidder = General::createGeneralObjFromDB($highestBid->generalID);
|
||||||
|
}
|
||||||
|
|
||||||
|
$hostRes = static::$hostRes;
|
||||||
|
$hostResName = $hostRes->getName();
|
||||||
|
$bidderRes = static::$bidderRes;
|
||||||
|
$bidderResName = $bidderRes->getName();
|
||||||
|
|
||||||
|
$bidAmount = $highestBid->amount;
|
||||||
|
$auctionAmount = $this->info->detail->amount;
|
||||||
|
|
||||||
|
//거래 종료이므로 서로 반대
|
||||||
|
$josaUlBidder = JosaUtil::pick($bidAmount, '을');
|
||||||
|
$josaUlHost = JosaUtil::pick($auctionAmount, '을');
|
||||||
|
$auctionHost->increaseVar($bidderRes->value, $bidAmount);
|
||||||
|
$bidder->increaseVar($hostRes->value, $auctionAmount);
|
||||||
|
|
||||||
|
$auctionID = $this->info->id;
|
||||||
|
|
||||||
|
$auctionHost->getLogger()->pushGeneralActionLog(
|
||||||
|
"{$auctionID}번 거래 <C>성사</>로 {$hostResName} <C>{$auctionAmount}</>{$josaUlHost} 판매, {$bidderResName} <C>{$bidAmount}</>{$josaUlBidder} 획득!",
|
||||||
|
ActionLogger::EVENT_PLAIN
|
||||||
|
);
|
||||||
|
$bidder->getLogger()->pushGeneralActionLog(
|
||||||
|
"{$auctionID}번 거래 <C>성사</>로 {$bidderResName} <C>{$bidAmount}</>{$josaUlBidder} 지불, {$hostResName} <C>{$auctionAmount}</>{$josaUlHost} 획득!",
|
||||||
|
ActionLogger::EVENT_PLAIN
|
||||||
|
);
|
||||||
|
|
||||||
|
$josaYiHost = JosaUtil::pick($auctionHost->getName(), '이');
|
||||||
|
$josaYiBidder = JosaUtil::pick($bidder->getName(), '이');
|
||||||
|
|
||||||
|
$auctionLog = [];
|
||||||
|
$josaRoBidder = JosaUtil::pick($bidAmount, '로');
|
||||||
|
$auctionLog[] = "{$auctionID}번 {$hostResName} 경매 <C>성사</> : <Y>{$auctionHost->getName()}</>{$josaYiHost} {$hostResName} <C>{$auctionAmount}</> 판매, <Y>{$bidder->getName()}</>{$josaYiBidder} {$bidderResName} <C>{$bidAmount}</>{$josaRoBidder} 구매";
|
||||||
|
|
||||||
|
|
||||||
|
if ($highestBid->amount === $this->info->detail->finishBidAmount) {
|
||||||
|
$auctionLog[0] .= ' <M>★ 마감가 거래 ★</>';
|
||||||
|
} else if ($highestBid->amount === $this->info->detail->startBidAmount) {
|
||||||
|
$auctionLog[0] .= " <R>★ 최저가 거래 ★</>";
|
||||||
|
}
|
||||||
|
|
||||||
|
pushAuctionLog(array_map(
|
||||||
|
fn ($log) =>
|
||||||
|
$bidder->getLogger()->formatText($log, ActionLogger::EVENT_PLAIN),
|
||||||
|
$auctionLog
|
||||||
|
));
|
||||||
|
|
||||||
|
$db = DB::db();
|
||||||
|
$bidder->applyDB($db);
|
||||||
|
$auctionHost->applyDB($db);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function bid(int $amount, bool $tryExtendCloseDate = false): ?string
|
||||||
|
{
|
||||||
|
if ($this->info->hostGeneralID === $this->general->getID()) {
|
||||||
|
return '자신이 연 경매에 입찰할 수 없습니다.';
|
||||||
|
}
|
||||||
|
$result = $this->_bid($amount, $tryExtendCloseDate);
|
||||||
|
|
||||||
|
if (is_string($result)) {
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($amount === $this->info->detail->finishBidAmount) {
|
||||||
|
//즉구, 1턴 후 지급
|
||||||
|
$db = DB::db();
|
||||||
|
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||||
|
$turnTerm = $gameStor->getValue('turnterm');
|
||||||
|
$date = (new DateTimeImmutable())->add(TimeUtil::secondsToDateInterval($turnTerm * 60));
|
||||||
|
$this->shrinkCloseDate($date);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace sammo;
|
||||||
|
|
||||||
|
use sammo\Enums\AuctionType;
|
||||||
|
use sammo\Enums\ResourceType;
|
||||||
|
|
||||||
|
/** 경매에 쌀을 매물로 등록, 입찰자가 금으로 구매 */
|
||||||
|
class AuctionBuyRice extends AuctionBasicResource
|
||||||
|
{
|
||||||
|
static AuctionType $auctionType = AuctionType::BuyRice;
|
||||||
|
static ResourceType $hostRes = ResourceType::rice;
|
||||||
|
static ResourceType $bidderRes = ResourceType::gold;
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace sammo;
|
||||||
|
|
||||||
|
use sammo\Enums\AuctionType;
|
||||||
|
use sammo\Enums\ResourceType;
|
||||||
|
|
||||||
|
/** 경매에 금을 매물로 등록, 입찰자가 쌀로 판매 */
|
||||||
|
class AuctionSellRice extends AuctionBasicResource
|
||||||
|
{
|
||||||
|
static AuctionType $auctionType = AuctionType::SellRice;
|
||||||
|
static ResourceType $hostRes = ResourceType::gold;
|
||||||
|
static ResourceType $bidderRes = ResourceType::rice;
|
||||||
|
}
|
||||||
@@ -0,0 +1,328 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace sammo;
|
||||||
|
|
||||||
|
use DateTimeImmutable;
|
||||||
|
use Ds\Set;
|
||||||
|
use sammo\DTO\AuctionBidItem;
|
||||||
|
use sammo\DTO\AuctionInfo;
|
||||||
|
use sammo\DTO\AuctionInfoDetail;
|
||||||
|
use sammo\Enums\AuctionType;
|
||||||
|
use sammo\Enums\InheritanceKey;
|
||||||
|
use sammo\Enums\ResourceType;
|
||||||
|
use sammo\RandUtil;
|
||||||
|
|
||||||
|
class AuctionUniqueItem extends Auction
|
||||||
|
{
|
||||||
|
const COEFF_EXTENSION_MINUTES_LIMIT_UNIQUE_CNT = 24;
|
||||||
|
|
||||||
|
static AuctionType $auctionType = AuctionType::UniqueItem;
|
||||||
|
|
||||||
|
static public function openItemAuction(BaseItem $item, General $general, int $startAmount): self|string
|
||||||
|
{
|
||||||
|
if ($startAmount < GameConst::$inheritItemUniqueMinPoint) {
|
||||||
|
return '최소 경매 금액은 ' . GameConst::$inheritItemUniqueMinPoint . '입니다.';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($general->getInheritancePoint(InheritanceKey::previous) < $startAmount) {
|
||||||
|
return '경매를 시작할 포인트가 부족합니다.';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($item->isBuyable()) {
|
||||||
|
return '구매할 수 있는 아이템입니다.';
|
||||||
|
}
|
||||||
|
|
||||||
|
$itemKey = $item->getRawClassName();
|
||||||
|
$db = DB::db();
|
||||||
|
$auctionIDonProgress = $db->queryFirstField(
|
||||||
|
'SELECT `id` FROM ng_auction WHERE `finished` = 0 AND `type` = %s AND `target` = %s',
|
||||||
|
AuctionType::UniqueItem->value,
|
||||||
|
$itemKey
|
||||||
|
);
|
||||||
|
if ($auctionIDonProgress !== null) {
|
||||||
|
return '이미 경매가 진행중입니다.';
|
||||||
|
}
|
||||||
|
|
||||||
|
$prevAuctionID = $db->queryFirstField(
|
||||||
|
'SELECT id FROM ng_auction WHERE host_general_id = %i AND finished = 0 AND `type` = %s',
|
||||||
|
$general->getID(),
|
||||||
|
AuctionType::UniqueItem->value,
|
||||||
|
);
|
||||||
|
if ($prevAuctionID !== null) {
|
||||||
|
return '아직 경매가 끝나지 않았습니다.';
|
||||||
|
}
|
||||||
|
|
||||||
|
$availableCnt = 0;
|
||||||
|
foreach(GameConst::$allItems as $itemType => $itemList){
|
||||||
|
$availableCnt += $itemList[$itemKey] ?? 0;
|
||||||
|
$availableCnt -= $db->queryFirstField('SELECT count(*) FROM `general` WHERE %b = %s', $itemType, $itemKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
if($availableCnt <= 0){
|
||||||
|
return '그 유니크를 더 얻을 수 없습니다.';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||||
|
|
||||||
|
$now = new DateTimeImmutable();
|
||||||
|
|
||||||
|
[$turnTerm, $year, $month] = $gameStor->getValuesAsArray(['turnterm', 'year', 'month']);
|
||||||
|
|
||||||
|
$closeDate = $now->add(TimeUtil::secondsToDateInterval(
|
||||||
|
max(static::MIN_AUCTION_CLOSE_MINUTES, $turnTerm * static::COEFF_AUCTION_CLOSE_MINUTES) * 60
|
||||||
|
));
|
||||||
|
$availableLatestBidCloseDate = $closeDate->add(TimeUtil::secondsToDateInterval(
|
||||||
|
max(static::MIN_EXTENSION_MINUTES_LIMIT_BY_BID, $turnTerm * static::COEFF_EXTENSION_MINUTES_LIMIT_BY_BID) * 60
|
||||||
|
));
|
||||||
|
|
||||||
|
$info = new AuctionInfo(
|
||||||
|
null,
|
||||||
|
AuctionType::UniqueItem,
|
||||||
|
false,
|
||||||
|
$itemKey,
|
||||||
|
$general->getID(),
|
||||||
|
ResourceType::inheritancePoint,
|
||||||
|
$now,
|
||||||
|
$closeDate,
|
||||||
|
new AuctionInfoDetail(
|
||||||
|
"{$item->getName()} 경매",
|
||||||
|
static::genObfuscatedName($general->getID()),
|
||||||
|
1,
|
||||||
|
false,
|
||||||
|
$startAmount,
|
||||||
|
null,
|
||||||
|
1,
|
||||||
|
$availableLatestBidCloseDate,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$auctionID = static::openAuction($info, $general);
|
||||||
|
if (!is_int($auctionID)) {
|
||||||
|
return $auctionID;
|
||||||
|
}
|
||||||
|
$auction = new static($auctionID, $general);
|
||||||
|
try {
|
||||||
|
$auction->bid($startAmount, false);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
//실패해선 안된다.
|
||||||
|
$msg = $e->getMessage();
|
||||||
|
$auction->closeAuction();
|
||||||
|
return "경매를 시작했지만, 첫 입찰에 실패했습니다: {$msg}";
|
||||||
|
}
|
||||||
|
|
||||||
|
$itemName = $item->getName();
|
||||||
|
$josaRa = JosaUtil::pick($item->getRawName(), '라');
|
||||||
|
|
||||||
|
$logger = new ActionLogger(0, 0, $year, $month);
|
||||||
|
$logger->pushGlobalHistoryLog("<C><b>【보물수배】</b></>누군가가 <C>{$itemName}</>{$josaRa}는 보물을 구한다는 소문이 들려옵니다.");
|
||||||
|
$logger->flush();
|
||||||
|
|
||||||
|
return $auction;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function rollbackAuction(): void
|
||||||
|
{
|
||||||
|
// 유니크 옥션의 개최자는 운영자이므로 할 일이 없다.
|
||||||
|
}
|
||||||
|
|
||||||
|
public function bid(int $amount, bool $tryExtendCloseDate): ?string
|
||||||
|
{
|
||||||
|
|
||||||
|
if($this->info->finished){
|
||||||
|
return '경매가 종료되었습니다.';
|
||||||
|
}
|
||||||
|
|
||||||
|
$db = DB::db();
|
||||||
|
/** @var AuctionInfo[] */
|
||||||
|
$openUniqueAuctions = array_map(fn ($raw) => AuctionInfo::fromArray($raw), $db->query(
|
||||||
|
'SELECT * FROM `ng_auction` WHERE `finished` = 0 AND `type`= %s',
|
||||||
|
AuctionType::UniqueItem->value
|
||||||
|
) ?? []);
|
||||||
|
|
||||||
|
$auctionIDList = [];
|
||||||
|
foreach ($openUniqueAuctions as $auction) {
|
||||||
|
$auctionIDList[] = $auction->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
$db = DB::db();
|
||||||
|
if($auctionIDList){
|
||||||
|
$rawHighestBids = Util::convertArrayToDict($db->query(
|
||||||
|
'SELECT bid.* FROM `ng_auction_bid` bid INNER JOIN (
|
||||||
|
SELECT `auction_id`, MAX(`amount`) as `max_amount`
|
||||||
|
FROM `ng_auction_bid`
|
||||||
|
WHERE `auction_id` IN %li
|
||||||
|
GROUP BY `auction_id`
|
||||||
|
ORDER BY `amount`
|
||||||
|
) AS max_bid
|
||||||
|
ON bid.`auction_id` = max_bid.`auction_id` AND bid.`amount` = max_bid.`max_amount`',
|
||||||
|
$auctionIDList,
|
||||||
|
) ?? [], 'auction_id');
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
$rawHighestBids = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var array<int,AuctionBidItem> */
|
||||||
|
$highestBids = Util::mapWithKey(
|
||||||
|
fn ($auctionID, $bid) => AuctionBidItem::fromArray($bid),
|
||||||
|
$rawHighestBids
|
||||||
|
);
|
||||||
|
|
||||||
|
$itemCode = $this->info->target;
|
||||||
|
|
||||||
|
if ($itemCode === null) {
|
||||||
|
throw new \Exception('아이템 코드가 없습니다.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$bidItemTypes = new Set();
|
||||||
|
foreach (GameConst::$allItems as $itemType => $itemList) {
|
||||||
|
if (($itemList[$itemCode] ?? 0) <= 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$bidItemTypes->add($itemType);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($openUniqueAuctions as $auction) {
|
||||||
|
$auctionID = $auction->id;
|
||||||
|
if (!isset($highestBids[$auctionID])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ($auctionID === $this->auctionID) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$bid = $highestBids[$auctionID];
|
||||||
|
if ($bid->generalID !== $this->general->getID()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$itemCodeComp = $auction->target;
|
||||||
|
|
||||||
|
foreach (GameConst::$allItems as $itemType => $itemList) {
|
||||||
|
if (($itemList[$itemCodeComp] ?? 0) <= 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ($bidItemTypes->contains($itemType)) {
|
||||||
|
return '1순위 입찰자인 경매중에 같은 부위가 있습니다.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->_bid($amount, $tryExtendCloseDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function finishAuction(AuctionBidItem $highestBid, General $bidder): ?string
|
||||||
|
{
|
||||||
|
$itemKey = $this->info->target;
|
||||||
|
if ($itemKey === null) {
|
||||||
|
throw new \Exception('아이템 키가 없습니다.');
|
||||||
|
}
|
||||||
|
$itemObj = buildItemClass($itemKey);
|
||||||
|
$general = $bidder;
|
||||||
|
$availableItemTypes = [];
|
||||||
|
$reasons = [];
|
||||||
|
$db = DB::db();
|
||||||
|
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||||
|
[$startYear, $year] = $gameStor->getValuesAsArray(['startyear', 'year']);
|
||||||
|
$relYear = $year - $startYear;
|
||||||
|
$availableEquipUniqueCnt = 1;
|
||||||
|
foreach (GameConst::$maxUniqueItemLimit as $tmpVals) {
|
||||||
|
[$targetYear, $targetTrialCnt] = $tmpVals;
|
||||||
|
if ($relYear < $targetYear) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$availableEquipUniqueCnt = $targetTrialCnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
$availableEquipUniqueCnt = Util::valueFit($availableEquipUniqueCnt, null, count(GameConst::$allItems));
|
||||||
|
|
||||||
|
foreach ($general->getItems() as $item) {
|
||||||
|
if (!$item->isBuyable()) {
|
||||||
|
$availableEquipUniqueCnt -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($availableEquipUniqueCnt <= 0) {
|
||||||
|
$turnTerm = $gameStor->getValue('turnterm');
|
||||||
|
//제한에 걸렸다면 자동 연장
|
||||||
|
$extendedCloseDate = $this->info->closeDate->add(TimeUtil::secondsToDateInterval(
|
||||||
|
max(static::MIN_EXTENSION_MINUTES_BY_EXTENSION_QUERY, $turnTerm * static::COEFF_EXTENSION_MINUTES_LIMIT_UNIQUE_CNT) * 60
|
||||||
|
));
|
||||||
|
|
||||||
|
$this->extendCloseDate($extendedCloseDate, true);
|
||||||
|
$this->extendLatestBidCloseDate(null);
|
||||||
|
$this->applyDB();
|
||||||
|
return '유니크 아이템 소유 제한 상태입니다. 종료 시간이 연장됩니다.';
|
||||||
|
}
|
||||||
|
|
||||||
|
$isExtendCloseDateRequired = false;
|
||||||
|
foreach (GameConst::$allItems as $itemType => $itemList) {
|
||||||
|
//아직은 그런 경우는 없지만 동일 유니크를 여러 부위에 장착할 수 있을지도 모름
|
||||||
|
if (!key_exists($itemKey, $itemList)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$ownItem = $general->getItem($itemType);
|
||||||
|
if ($ownItem->getRawClassName() == $itemKey) {
|
||||||
|
//FIXME: 이 경우에는 환불이 되던가 해야함.
|
||||||
|
$isExtendCloseDateRequired = true;
|
||||||
|
$reasons[] = '이미 그 유니크를 가지고 있습니다.';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$ownItem->isBuyable()) {
|
||||||
|
$isExtendCloseDateRequired = true;
|
||||||
|
$reasons[] = '이미 다른 유니크를 가지고 있습니다.';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$availableCnt = $itemList[$itemKey];
|
||||||
|
$occupiedCnt = $db->queryFirstField('SELECT count(*) FROM general WHERE %b = %s', $itemType, $itemKey);
|
||||||
|
if ($occupiedCnt >= $availableCnt) {
|
||||||
|
//FIXME: 이 경우에는 환불이 되던가 해야함.
|
||||||
|
$reasons[] = '그 유니크는 모두 점유되었습니다.';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$availableItemTypes[] = $itemType;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$availableItemTypes) {
|
||||||
|
if ($isExtendCloseDateRequired) {
|
||||||
|
$turnTerm = $gameStor->getValue('turnterm');
|
||||||
|
//동일 부위 제한에 걸렸다면 자동 연장
|
||||||
|
$extendedCloseDate = $this->info->closeDate->add(TimeUtil::secondsToDateInterval(
|
||||||
|
max(static::MIN_EXTENSION_MINUTES_LIMIT_BY_BID, $turnTerm * static::COEFF_EXTENSION_MINUTES_LIMIT_BY_BID) * 60
|
||||||
|
));
|
||||||
|
|
||||||
|
$this->extendCloseDate($extendedCloseDate, true);
|
||||||
|
$this->extendLatestBidCloseDate(null);
|
||||||
|
}
|
||||||
|
return join(' ', $reasons);
|
||||||
|
}
|
||||||
|
|
||||||
|
$itemType = $availableItemTypes[0];
|
||||||
|
|
||||||
|
$general->setVar($itemType, $itemKey);
|
||||||
|
|
||||||
|
$logger = $general->getLogger();
|
||||||
|
$nationName = $general->getStaticNation()['name'];
|
||||||
|
$generalName = $general->getName();
|
||||||
|
$josaYi = JosaUtil::pick($generalName, '이');
|
||||||
|
$itemName = $itemObj->getName();
|
||||||
|
$itemRawName = $itemObj->getRawName();
|
||||||
|
$josaUl = JosaUtil::pick($itemRawName, '을');
|
||||||
|
|
||||||
|
$logger->pushGeneralActionLog("<C>{$itemName}</>{$josaUl} 습득했습니다!");
|
||||||
|
$logger->pushGeneralHistoryLog("<C>{$itemName}</>{$josaUl} 습득");
|
||||||
|
$logger->pushGlobalActionLog("<Y>{$generalName}</>{$josaYi} <C>{$itemName}</>{$josaUl} 습득했습니다!");
|
||||||
|
$logger->pushGlobalHistoryLog("<C><b>【보물수배】</b></><D><b>{$nationName}</b></>의 <Y>{$generalName}</>{$josaYi} <C>{$itemName}</>{$josaUl} 습득했습니다!");
|
||||||
|
|
||||||
|
$userLogger = new UserLogger($general->getVar('owner'));
|
||||||
|
$userLogger->push(sprintf("유니크 %s 경매로 %d 포인트 사용", $itemName, $highestBid->amount), "inheritPoint");
|
||||||
|
|
||||||
|
$general->applyDB($db);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -28,7 +28,7 @@ abstract class BaseWarUnitTrigger extends ObjectTrigger{
|
|||||||
return "{$priority}_{$fqn}_{$objID}_{$this->raiseType}";
|
return "{$priority}_{$fqn}_{$objID}_{$this->raiseType}";
|
||||||
}
|
}
|
||||||
|
|
||||||
public function action(?array $env=null, $arg=null):?array{
|
public function action(\sammo\RandUtil $rng, ?array $env=null, $arg=null):?array{
|
||||||
if($env === null){
|
if($env === null){
|
||||||
$env = [];
|
$env = [];
|
||||||
}
|
}
|
||||||
@@ -46,7 +46,7 @@ abstract class BaseWarUnitTrigger extends ObjectTrigger{
|
|||||||
/** @var WarUnitGeneral $attacker */
|
/** @var WarUnitGeneral $attacker */
|
||||||
/** @var WarUnit $defender */
|
/** @var WarUnit $defender */
|
||||||
[$attacker, $defender] = $arg;
|
[$attacker, $defender] = $arg;
|
||||||
|
|
||||||
/** @var WarUnit $self */
|
/** @var WarUnit $self */
|
||||||
$self = $this->object;
|
$self = $this->object;
|
||||||
$isAttacker = $self->isAttacker();
|
$isAttacker = $self->isAttacker();
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ class Betting
|
|||||||
if ($rawBettingInfo === null) {
|
if ($rawBettingInfo === null) {
|
||||||
throw new \RuntimeException("해당 베팅이 없습니다: {$bettingID}");
|
throw new \RuntimeException("해당 베팅이 없습니다: {$bettingID}");
|
||||||
}
|
}
|
||||||
$this->info = new BettingInfo($rawBettingInfo);
|
$this->info = BettingInfo::fromArray($rawBettingInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function _convertBettingKey(array $bettingType): string
|
private function _convertBettingKey(array $bettingType): string
|
||||||
@@ -148,13 +148,14 @@ class Betting
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$bettingItem = new BettingItem([
|
$bettingItem = new BettingItem(
|
||||||
'betting_id' => $this->bettingID,
|
rowID: null,
|
||||||
'general_id' => $generalID,
|
bettingID: $this->bettingID,
|
||||||
'user_id' => $userID,
|
generalID: $generalID,
|
||||||
'betting_type' => $bettingTypeKey,
|
userID: $userID,
|
||||||
'amount' => $amount
|
bettingType: $bettingTypeKey,
|
||||||
]);
|
amount: $amount
|
||||||
|
);
|
||||||
|
|
||||||
$db->insertUpdate(
|
$db->insertUpdate(
|
||||||
'ng_betting',
|
'ng_betting',
|
||||||
|
|||||||
@@ -6,7 +6,8 @@ use \sammo\{
|
|||||||
General, GameConst,
|
General, GameConst,
|
||||||
ActionLogger,
|
ActionLogger,
|
||||||
LastTurn,
|
LastTurn,
|
||||||
NotInheritedMethodException
|
NotInheritedMethodException,
|
||||||
|
RandUtil
|
||||||
};
|
};
|
||||||
|
|
||||||
use function \sammo\getNationStaticInfo;
|
use function \sammo\getNationStaticInfo;
|
||||||
@@ -473,7 +474,7 @@ abstract class BaseCommand{
|
|||||||
abstract public function getPreReqTurn():int;
|
abstract public function getPreReqTurn():int;
|
||||||
abstract public function getPostReqTurn():int;
|
abstract public function getPostReqTurn():int;
|
||||||
|
|
||||||
abstract public function run():bool;
|
abstract public function run(RandUtil $rng):bool;
|
||||||
|
|
||||||
public function exportJSVars():array {
|
public function exportJSVars():array {
|
||||||
return [];
|
return [];
|
||||||
|
|||||||
@@ -13,8 +13,6 @@ use \sammo\{
|
|||||||
use \sammo\Constraint\Constraint;
|
use \sammo\Constraint\Constraint;
|
||||||
use \sammo\Constraint\ConstraintHelper;
|
use \sammo\Constraint\ConstraintHelper;
|
||||||
|
|
||||||
use function sammo\tryRollbackInheritUniqueItem;
|
|
||||||
|
|
||||||
class che_NPC능동 extends Command\GeneralCommand{
|
class che_NPC능동 extends Command\GeneralCommand{
|
||||||
static protected $actionName = 'NPC능동';
|
static protected $actionName = 'NPC능동';
|
||||||
|
|
||||||
@@ -75,7 +73,7 @@ class che_NPC능동 extends Command\GeneralCommand{
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function run():bool{
|
public function run(\Sammo\RandUtil $rng):bool{
|
||||||
if(!$this->hasFullConditionMet()){
|
if(!$this->hasFullConditionMet()){
|
||||||
throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도');
|
throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도');
|
||||||
}
|
}
|
||||||
@@ -98,7 +96,6 @@ class che_NPC능동 extends Command\GeneralCommand{
|
|||||||
|
|
||||||
$this->setResultTurn(new LastTurn(static::getName(), $this->arg));
|
$this->setResultTurn(new LastTurn(static::getName(), $this->arg));
|
||||||
}
|
}
|
||||||
tryRollbackInheritUniqueItem($general);
|
|
||||||
$general->applyDB($db);
|
$general->applyDB($db);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ class che_강행 extends Command\GeneralCommand
|
|||||||
return "{$failReason} <G><b>{$destCityName}</b></>{$josaRo} {$commandName} 실패.";
|
return "{$failReason} <G><b>{$destCityName}</b></>{$josaRo} {$commandName} 실패.";
|
||||||
}
|
}
|
||||||
|
|
||||||
public function run(): bool
|
public function run(\Sammo\RandUtil $rng): bool
|
||||||
{
|
{
|
||||||
if (!$this->hasFullConditionMet()) {
|
if (!$this->hasFullConditionMet()) {
|
||||||
throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도');
|
throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도');
|
||||||
@@ -156,7 +156,7 @@ class che_강행 extends Command\GeneralCommand
|
|||||||
$general->increaseVar('leadership_exp', 1);
|
$general->increaseVar('leadership_exp', 1);
|
||||||
$this->setResultTurn(new LastTurn(static::getName(), $this->arg));
|
$this->setResultTurn(new LastTurn(static::getName(), $this->arg));
|
||||||
$general->checkStatChange();
|
$general->checkStatChange();
|
||||||
tryUniqueItemLottery($general);
|
tryUniqueItemLottery(\sammo\genGenericUniqueRNGFromGeneral($general), $general);
|
||||||
|
|
||||||
$general->applyDB($db);
|
$general->applyDB($db);
|
||||||
|
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ class che_거병 extends Command\GeneralCommand{
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function run():bool{
|
public function run(\Sammo\RandUtil $rng):bool{
|
||||||
if(!$this->hasFullConditionMet()){
|
if(!$this->hasFullConditionMet()){
|
||||||
throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도');
|
throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도');
|
||||||
}
|
}
|
||||||
@@ -174,7 +174,7 @@ class che_거병 extends Command\GeneralCommand{
|
|||||||
|
|
||||||
$this->setResultTurn(new LastTurn(static::getName(), $this->arg));
|
$this->setResultTurn(new LastTurn(static::getName(), $this->arg));
|
||||||
$general->checkStatChange();
|
$general->checkStatChange();
|
||||||
tryUniqueItemLottery($general);
|
tryUniqueItemLottery(\sammo\genGenericUniqueRNGFromGeneral($general), $general);
|
||||||
|
|
||||||
$general->applyDB($db);
|
$general->applyDB($db);
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ use \sammo\Constraint\ConstraintHelper;
|
|||||||
use sammo\Enums\InheritanceKey;
|
use sammo\Enums\InheritanceKey;
|
||||||
|
|
||||||
use function sammo\buildNationTypeClass;
|
use function sammo\buildNationTypeClass;
|
||||||
|
use function sammo\genGenericUniqueRNGFromGeneral;
|
||||||
use function sammo\refreshNationStaticInfo;
|
use function sammo\refreshNationStaticInfo;
|
||||||
use function sammo\GetNationColors;
|
use function sammo\GetNationColors;
|
||||||
|
|
||||||
@@ -126,7 +127,7 @@ class che_건국 extends Command\GeneralCommand
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function run(): bool
|
public function run(\Sammo\RandUtil $rng): bool
|
||||||
{
|
{
|
||||||
if (!$this->hasFullConditionMet()) {
|
if (!$this->hasFullConditionMet()) {
|
||||||
throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도');
|
throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도');
|
||||||
@@ -190,7 +191,7 @@ class che_건국 extends Command\GeneralCommand
|
|||||||
$general->increaseInheritancePoint(InheritanceKey::active_action, 1);
|
$general->increaseInheritancePoint(InheritanceKey::active_action, 1);
|
||||||
$this->setResultTurn(new LastTurn(static::getName(), $this->arg));
|
$this->setResultTurn(new LastTurn(static::getName(), $this->arg));
|
||||||
$general->checkStatChange();
|
$general->checkStatChange();
|
||||||
tryUniqueItemLottery($general, '건국');
|
tryUniqueItemLottery(genGenericUniqueRNGFromGeneral($general), $general, '건국');
|
||||||
$general->applyDB($db);
|
$general->applyDB($db);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ class che_견문 extends Command\GeneralCommand{
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function run():bool{
|
public function run(\Sammo\RandUtil $rng):bool{
|
||||||
if(!$this->hasFullConditionMet()){
|
if(!$this->hasFullConditionMet()){
|
||||||
throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도');
|
throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도');
|
||||||
}
|
}
|
||||||
@@ -99,10 +99,10 @@ class che_견문 extends Command\GeneralCommand{
|
|||||||
$text = str_replace(':riceAmount:', '200', $text);
|
$text = str_replace(':riceAmount:', '200', $text);
|
||||||
}
|
}
|
||||||
if($type & SightseeingMessage::Wounded){
|
if($type & SightseeingMessage::Wounded){
|
||||||
$general->increaseVarWithLimit('injury', Util::randRangeInt(10, 20), null, 80);
|
$general->increaseVarWithLimit('injury', $rng->nextRangeInt(10, 20), null, 80);
|
||||||
}
|
}
|
||||||
if($type & SightseeingMessage::HeavyWounded){
|
if($type & SightseeingMessage::HeavyWounded){
|
||||||
$general->increaseVarWithLimit('injury', Util::randRangeInt(20, 50), null, 80);
|
$general->increaseVarWithLimit('injury', $rng->nextRangeInt(20, 50), null, 80);
|
||||||
}
|
}
|
||||||
|
|
||||||
$logger = $general->getLogger();
|
$logger = $general->getLogger();
|
||||||
@@ -112,7 +112,7 @@ class che_견문 extends Command\GeneralCommand{
|
|||||||
$general->addExperience($exp);
|
$general->addExperience($exp);
|
||||||
$this->setResultTurn(new LastTurn(static::getName(), $this->arg));
|
$this->setResultTurn(new LastTurn(static::getName(), $this->arg));
|
||||||
$general->checkStatChange();
|
$general->checkStatChange();
|
||||||
tryUniqueItemLottery($general);
|
tryUniqueItemLottery(\sammo\genGenericUniqueRNGFromGeneral($general), $general);
|
||||||
|
|
||||||
$general->applyDB($db);
|
$general->applyDB($db);
|
||||||
|
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ class che_군량매매 extends Command\GeneralCommand{
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function run():bool{
|
public function run(\Sammo\RandUtil $rng):bool{
|
||||||
if(!$this->hasFullConditionMet()){
|
if(!$this->hasFullConditionMet()){
|
||||||
throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도');
|
throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도');
|
||||||
}
|
}
|
||||||
@@ -166,7 +166,7 @@ class che_군량매매 extends Command\GeneralCommand{
|
|||||||
$exp = 30;
|
$exp = 30;
|
||||||
$ded = 50;
|
$ded = 50;
|
||||||
|
|
||||||
$incStat = Util::choiceRandomUsingWeight([
|
$incStat = $rng->choiceUsingWeight([
|
||||||
'leadership_exp'=>$general->getLeadership(false, false, false, false),
|
'leadership_exp'=>$general->getLeadership(false, false, false, false),
|
||||||
'strength_exp'=>$general->getStrength(false, false, false, false),
|
'strength_exp'=>$general->getStrength(false, false, false, false),
|
||||||
'intel_exp'=>$general->getIntel(false, false, false, false)
|
'intel_exp'=>$general->getIntel(false, false, false, false)
|
||||||
@@ -178,7 +178,7 @@ class che_군량매매 extends Command\GeneralCommand{
|
|||||||
|
|
||||||
$this->setResultTurn(new LastTurn(static::getName(), $this->arg));
|
$this->setResultTurn(new LastTurn(static::getName(), $this->arg));
|
||||||
$general->checkStatChange();
|
$general->checkStatChange();
|
||||||
tryUniqueItemLottery($general);
|
tryUniqueItemLottery(\sammo\genGenericUniqueRNGFromGeneral($general), $general);
|
||||||
|
|
||||||
$general->applyDB($db);
|
$general->applyDB($db);
|
||||||
|
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ class che_귀환 extends Command\GeneralCommand{
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function run():bool{
|
public function run(\Sammo\RandUtil $rng):bool{
|
||||||
if(!$this->hasFullConditionMet()){
|
if(!$this->hasFullConditionMet()){
|
||||||
throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도');
|
throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도');
|
||||||
}
|
}
|
||||||
@@ -95,7 +95,7 @@ class che_귀환 extends Command\GeneralCommand{
|
|||||||
$general->increaseVar('leadership_exp', 1);
|
$general->increaseVar('leadership_exp', 1);
|
||||||
$this->setResultTurn(new LastTurn(static::getName(), $this->arg));
|
$this->setResultTurn(new LastTurn(static::getName(), $this->arg));
|
||||||
$general->checkStatChange();
|
$general->checkStatChange();
|
||||||
tryUniqueItemLottery($general);
|
tryUniqueItemLottery(\sammo\genGenericUniqueRNGFromGeneral($general), $general);
|
||||||
|
|
||||||
$general->applyDB($db);
|
$general->applyDB($db);
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ namespace sammo\Command\General;
|
|||||||
|
|
||||||
use \sammo\{
|
use \sammo\{
|
||||||
DB, Util, JosaUtil,
|
DB, Util, JosaUtil,
|
||||||
General,
|
General,
|
||||||
ActionLogger,
|
ActionLogger,
|
||||||
LastTurn,
|
LastTurn,
|
||||||
Command, GameConst
|
Command, GameConst
|
||||||
@@ -11,7 +11,7 @@ use \sammo\{
|
|||||||
|
|
||||||
use function sammo\{
|
use function sammo\{
|
||||||
TechLimit,
|
TechLimit,
|
||||||
CriticalRatioDomestic,
|
CriticalRatioDomestic,
|
||||||
CriticalScoreEx,
|
CriticalScoreEx,
|
||||||
tryUniqueItemLottery,
|
tryUniqueItemLottery,
|
||||||
updateMaxDomesticCritical
|
updateMaxDomesticCritical
|
||||||
@@ -38,11 +38,11 @@ class che_기술연구 extends che_상업투자{
|
|||||||
|
|
||||||
$this->setCity();
|
$this->setCity();
|
||||||
$this->setNation(['tech']);
|
$this->setNation(['tech']);
|
||||||
|
|
||||||
[$reqGold, $reqRice] = $this->getCost();
|
[$reqGold, $reqRice] = $this->getCost();
|
||||||
|
|
||||||
$this->fullConditionConstraints=[
|
$this->fullConditionConstraints=[
|
||||||
ConstraintHelper::NotBeNeutral(),
|
ConstraintHelper::NotBeNeutral(),
|
||||||
ConstraintHelper::NotWanderingNation(),
|
ConstraintHelper::NotWanderingNation(),
|
||||||
ConstraintHelper::OccupiedCity(),
|
ConstraintHelper::OccupiedCity(),
|
||||||
ConstraintHelper::SuppliedCity(),
|
ConstraintHelper::SuppliedCity(),
|
||||||
@@ -53,7 +53,7 @@ class che_기술연구 extends che_상업투자{
|
|||||||
$this->reqGold = $reqGold;
|
$this->reqGold = $reqGold;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function run():bool{
|
public function run(\Sammo\RandUtil $rng):bool{
|
||||||
if(!$this->hasFullConditionMet()){
|
if(!$this->hasFullConditionMet()){
|
||||||
throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도');
|
throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도');
|
||||||
}
|
}
|
||||||
@@ -64,7 +64,7 @@ class che_기술연구 extends che_상업투자{
|
|||||||
|
|
||||||
$trust = Util::valueFit($this->city['trust'], 50);
|
$trust = Util::valueFit($this->city['trust'], 50);
|
||||||
|
|
||||||
$score = Util::valueFit($this->calcBaseScore(), 1);
|
$score = Util::valueFit($this->calcBaseScore($rng), 1);
|
||||||
|
|
||||||
['success'=>$successRatio, 'fail'=>$failRatio] = CriticalRatioDomestic($general, static::$statKey);
|
['success'=>$successRatio, 'fail'=>$failRatio] = CriticalRatioDomestic($general, static::$statKey);
|
||||||
if($trust < 80){
|
if($trust < 80){
|
||||||
@@ -77,9 +77,9 @@ class che_기술연구 extends che_상업투자{
|
|||||||
$failRatio = Util::valueFit($failRatio, 0, 1 - $successRatio);
|
$failRatio = Util::valueFit($failRatio, 0, 1 - $successRatio);
|
||||||
$normalRatio = 1 - $failRatio - $successRatio;
|
$normalRatio = 1 - $failRatio - $successRatio;
|
||||||
|
|
||||||
$pick = Util::choiceRandomUsingWeight([
|
$pick = $rng->choiceUsingWeight([
|
||||||
'fail'=>$failRatio,
|
'fail'=>$failRatio,
|
||||||
'success'=>$successRatio,
|
'success'=>$successRatio,
|
||||||
'normal'=>$normalRatio
|
'normal'=>$normalRatio
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -87,14 +87,14 @@ class che_기술연구 extends che_상업투자{
|
|||||||
|
|
||||||
$date = $general->getTurnTime($general::TURNTIME_HM);
|
$date = $general->getTurnTime($general::TURNTIME_HM);
|
||||||
|
|
||||||
$score *= CriticalScoreEx($pick);
|
$score *= CriticalScoreEx($rng, $pick);
|
||||||
$score = Util::round($score);
|
$score = Util::round($score);
|
||||||
|
|
||||||
$exp = $score * 0.7;
|
$exp = $score * 0.7;
|
||||||
$ded = $score * 1.0;
|
$ded = $score * 1.0;
|
||||||
|
|
||||||
if($pick == 'success'){
|
if($pick == 'success'){
|
||||||
updateMaxDomesticCritical($general, $score);
|
updateMaxDomesticCritical($general, $score);
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
$general->setAuxVar('max_domestic_critical', 0);
|
$general->setAuxVar('max_domestic_critical', 0);
|
||||||
@@ -134,11 +134,11 @@ class che_기술연구 extends che_상업투자{
|
|||||||
|
|
||||||
$this->setResultTurn(new LastTurn(static::getName(), $this->arg));
|
$this->setResultTurn(new LastTurn(static::getName(), $this->arg));
|
||||||
$general->checkStatChange();
|
$general->checkStatChange();
|
||||||
tryUniqueItemLottery($general);
|
tryUniqueItemLottery(\sammo\genGenericUniqueRNGFromGeneral($general), $general);
|
||||||
$general->applyDB($db);
|
$general->applyDB($db);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -3,7 +3,7 @@ namespace sammo\Command\General;
|
|||||||
|
|
||||||
use \sammo\{
|
use \sammo\{
|
||||||
DB, Util, JosaUtil,
|
DB, Util, JosaUtil,
|
||||||
General,
|
General,
|
||||||
ActionLogger,
|
ActionLogger,
|
||||||
GameConst, GameUnitConst,
|
GameConst, GameUnitConst,
|
||||||
LastTurn,
|
LastTurn,
|
||||||
@@ -35,9 +35,9 @@ class che_단련 extends Command\GeneralCommand{
|
|||||||
$this->setNation();
|
$this->setNation();
|
||||||
|
|
||||||
[$reqGold, $reqRice] = $this->getCost();
|
[$reqGold, $reqRice] = $this->getCost();
|
||||||
|
|
||||||
$this->fullConditionConstraints=[
|
$this->fullConditionConstraints=[
|
||||||
ConstraintHelper::NotBeNeutral(),
|
ConstraintHelper::NotBeNeutral(),
|
||||||
ConstraintHelper::ReqGeneralCrew(),
|
ConstraintHelper::ReqGeneralCrew(),
|
||||||
ConstraintHelper::ReqGeneralValue('train', '훈련', '>=', GameConst::$defaultTrainLow),
|
ConstraintHelper::ReqGeneralValue('train', '훈련', '>=', GameConst::$defaultTrainLow),
|
||||||
ConstraintHelper::ReqGeneralValue('atmos', '사기', '>=', GameConst::$defaultAtmosLow),
|
ConstraintHelper::ReqGeneralValue('atmos', '사기', '>=', GameConst::$defaultAtmosLow),
|
||||||
@@ -66,7 +66,7 @@ class che_단련 extends Command\GeneralCommand{
|
|||||||
$env = $this->env;
|
$env = $this->env;
|
||||||
return [$env['develcost'], $env['develcost']];
|
return [$env['develcost'], $env['develcost']];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPreReqTurn():int{
|
public function getPreReqTurn():int{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -75,7 +75,7 @@ class che_단련 extends Command\GeneralCommand{
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function run():bool{
|
public function run(\Sammo\RandUtil $rng):bool{
|
||||||
if(!$this->hasFullConditionMet()){
|
if(!$this->hasFullConditionMet()){
|
||||||
throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도');
|
throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도');
|
||||||
}
|
}
|
||||||
@@ -85,7 +85,7 @@ class che_단련 extends Command\GeneralCommand{
|
|||||||
$general = $this->generalObj;
|
$general = $this->generalObj;
|
||||||
$date = $general->getTurnTime($general::TURNTIME_HM);
|
$date = $general->getTurnTime($general::TURNTIME_HM);
|
||||||
|
|
||||||
[$pick, $multiplier] = Util::choiceRandomUsingWeightPair([
|
[$pick, $multiplier] = $rng->choiceUsingWeightPair([
|
||||||
[['success', 3], 0.34],
|
[['success', 3], 0.34],
|
||||||
[['normal', 2], 0.33],
|
[['normal', 2], 0.33],
|
||||||
[['fail', 1], 0.33]
|
[['fail', 1], 0.33]
|
||||||
@@ -113,7 +113,7 @@ class che_단련 extends Command\GeneralCommand{
|
|||||||
|
|
||||||
$general->addDex($general->getCrewTypeObj(), $score, false);
|
$general->addDex($general->getCrewTypeObj(), $score, false);
|
||||||
|
|
||||||
$incStat = Util::choiceRandomUsingWeight([
|
$incStat = $rng->choiceUsingWeight([
|
||||||
'leadership_exp'=>$general->getLeadership(false, false, false, false),
|
'leadership_exp'=>$general->getLeadership(false, false, false, false),
|
||||||
'strength_exp'=>$general->getStrength(false, false, false, false),
|
'strength_exp'=>$general->getStrength(false, false, false, false),
|
||||||
'intel_exp'=>$general->getIntel(false, false, false, false)
|
'intel_exp'=>$general->getIntel(false, false, false, false)
|
||||||
@@ -126,11 +126,11 @@ class che_단련 extends Command\GeneralCommand{
|
|||||||
$general->increaseVar($incStat, 1);
|
$general->increaseVar($incStat, 1);
|
||||||
$this->setResultTurn(new LastTurn(static::getName(), $this->arg));
|
$this->setResultTurn(new LastTurn(static::getName(), $this->arg));
|
||||||
$general->checkStatChange();
|
$general->checkStatChange();
|
||||||
tryUniqueItemLottery($general);
|
tryUniqueItemLottery(\sammo\genGenericUniqueRNGFromGeneral($general), $general);
|
||||||
$general->applyDB($db);
|
$general->applyDB($db);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -136,7 +136,7 @@ class che_등용 extends Command\GeneralCommand
|
|||||||
return "【{$destGeneralName}】{$josaUl} {$name}";
|
return "【{$destGeneralName}】{$josaUl} {$name}";
|
||||||
}
|
}
|
||||||
|
|
||||||
public function run(): bool
|
public function run(\Sammo\RandUtil $rng): bool
|
||||||
{
|
{
|
||||||
if (!$this->hasFullConditionMet()) {
|
if (!$this->hasFullConditionMet()) {
|
||||||
throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도');
|
throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도');
|
||||||
@@ -173,7 +173,7 @@ class che_등용 extends Command\GeneralCommand
|
|||||||
|
|
||||||
$this->setResultTurn(new LastTurn(static::getName(), $this->arg));
|
$this->setResultTurn(new LastTurn(static::getName(), $this->arg));
|
||||||
$general->checkStatChange();
|
$general->checkStatChange();
|
||||||
tryUniqueItemLottery($general);
|
tryUniqueItemLottery(\sammo\genGenericUniqueRNGFromGeneral($general), $general);
|
||||||
|
|
||||||
$general->applyDB($db);
|
$general->applyDB($db);
|
||||||
|
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ class che_등용수락 extends Command\GeneralCommand{
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function run():bool{
|
public function run(\Sammo\RandUtil $rng):bool{
|
||||||
if(!$this->hasFullConditionMet()){
|
if(!$this->hasFullConditionMet()){
|
||||||
throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도');
|
throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도');
|
||||||
}
|
}
|
||||||
@@ -118,13 +118,6 @@ class che_등용수락 extends Command\GeneralCommand{
|
|||||||
$destNationID = $this->destNation['nation'];
|
$destNationID = $this->destNation['nation'];
|
||||||
$destNationName = $this->destNation['name'];
|
$destNationName = $this->destNation['name'];
|
||||||
|
|
||||||
$relYear = $env['year'] - $env['startyear'];
|
|
||||||
if($general->getNPCType() == 1 || $relYear >= 3){
|
|
||||||
$joinedNations = $general->getAuxVar('joinedNations')??[];
|
|
||||||
$joinedNations[] = $destNationID;
|
|
||||||
$general->setAuxVar('joinedNations', $joinedNations);
|
|
||||||
}
|
|
||||||
|
|
||||||
$isTroopLeader = ($generalID == $general->getVar('troop'));
|
$isTroopLeader = ($generalID == $general->getVar('troop'));
|
||||||
|
|
||||||
$destGeneral->addExperience(100);
|
$destGeneral->addExperience(100);
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ use \sammo\GameUnitConst;
|
|||||||
use \sammo\LastTurn;
|
use \sammo\LastTurn;
|
||||||
use \sammo\Command;
|
use \sammo\Command;
|
||||||
|
|
||||||
|
use function sammo\genGenericUniqueRNGFromGeneral;
|
||||||
use function \sammo\tryUniqueItemLottery;
|
use function \sammo\tryUniqueItemLottery;
|
||||||
|
|
||||||
use \sammo\Constraint\Constraint;
|
use \sammo\Constraint\Constraint;
|
||||||
@@ -110,7 +111,7 @@ class che_랜덤임관 extends Command\GeneralCommand
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function run(): bool
|
public function run(\Sammo\RandUtil $rng): bool
|
||||||
{
|
{
|
||||||
if (!$this->hasFullConditionMet()) {
|
if (!$this->hasFullConditionMet()) {
|
||||||
throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도');
|
throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도');
|
||||||
@@ -127,7 +128,7 @@ class che_랜덤임관 extends Command\GeneralCommand
|
|||||||
$relYear = $env['year'] - $env['startyear'];
|
$relYear = $env['year'] - $env['startyear'];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
$notIn = array_merge($general->getAuxVar('joinedNations')??[], $this->arg['destNationIDList']);
|
$notIn = $this->arg['destNationIDList']);
|
||||||
*/
|
*/
|
||||||
$notIn = null;
|
$notIn = null;
|
||||||
|
|
||||||
@@ -162,7 +163,7 @@ class che_랜덤임관 extends Command\GeneralCommand
|
|||||||
$score = log($affinity + 1, 2); //0~
|
$score = log($affinity + 1, 2); //0~
|
||||||
|
|
||||||
//쉐킷쉐킷
|
//쉐킷쉐킷
|
||||||
$score += Util::randF();
|
$score += $rng->nextFloat1();
|
||||||
|
|
||||||
$score += sqrt($testNation['gennum'] / $allGen);
|
$score += sqrt($testNation['gennum'] / $allGen);
|
||||||
|
|
||||||
@@ -219,7 +220,7 @@ class che_랜덤임관 extends Command\GeneralCommand
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($generalsCnt) {
|
if ($generalsCnt) {
|
||||||
$destNation = Util::choiceRandomUsingWeightPair($generalsCnt);
|
$destNation = $rng->choiceUsingWeightPair($generalsCnt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -251,7 +252,7 @@ class che_랜덤임관 extends Command\GeneralCommand
|
|||||||
'천하의 균형을 맞추기 위해',
|
'천하의 균형을 맞추기 위해',
|
||||||
'오랜 은거를 마치고',
|
'오랜 은거를 마치고',
|
||||||
];
|
];
|
||||||
$randomTalk = Util::choiceRandom($talkList);
|
$randomTalk = $rng->choice($talkList);
|
||||||
|
|
||||||
$logger->pushGeneralActionLog("<D>{$destNationName}</>에 랜덤 임관했습니다. <1>$date</>");
|
$logger->pushGeneralActionLog("<D>{$destNationName}</>에 랜덤 임관했습니다. <1>$date</>");
|
||||||
$logger->pushGeneralHistoryLog("<D><b>{$destNationName}</b></>에 랜덤 임관");
|
$logger->pushGeneralHistoryLog("<D><b>{$destNationName}</b></>에 랜덤 임관");
|
||||||
@@ -279,18 +280,11 @@ class che_랜덤임관 extends Command\GeneralCommand
|
|||||||
'gennum' => $db->sqleval('gennum + 1')
|
'gennum' => $db->sqleval('gennum + 1')
|
||||||
], 'nation=%i', $destNationID);
|
], 'nation=%i', $destNationID);
|
||||||
|
|
||||||
$relYear = $env['year'] - $env['startyear'];
|
|
||||||
if ($general->getNPCType() == 1 || $relYear >= 3) {
|
|
||||||
$joinedNations = $general->getAuxVar('joinedNations') ?? [];
|
|
||||||
$joinedNations[] = $destNationID;
|
|
||||||
$general->setAuxVar('joinedNations', $joinedNations);
|
|
||||||
}
|
|
||||||
|
|
||||||
$general->increaseInheritancePoint(InheritanceKey::active_action, 1);
|
$general->increaseInheritancePoint(InheritanceKey::active_action, 1);
|
||||||
$general->addExperience($exp);
|
$general->addExperience($exp);
|
||||||
$this->setResultTurn(new LastTurn(static::getName(), $this->arg));
|
$this->setResultTurn(new LastTurn(static::getName(), $this->arg));
|
||||||
$general->checkStatChange();
|
$general->checkStatChange();
|
||||||
tryUniqueItemLottery($general, '랜덤 임관');
|
tryUniqueItemLottery(genGenericUniqueRNGFromGeneral($general), $general, '랜덤 임관');
|
||||||
$general->applyDB($db);
|
$general->applyDB($db);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -15,8 +15,6 @@ use \sammo\Constraint\Constraint;
|
|||||||
use \sammo\Constraint\ConstraintHelper;
|
use \sammo\Constraint\ConstraintHelper;
|
||||||
use sammo\Enums\InheritanceKey;
|
use sammo\Enums\InheritanceKey;
|
||||||
|
|
||||||
use function sammo\tryRollbackInheritUniqueItem;
|
|
||||||
|
|
||||||
class che_모반시도 extends Command\GeneralCommand{
|
class che_모반시도 extends Command\GeneralCommand{
|
||||||
static protected $actionName = '모반시도';
|
static protected $actionName = '모반시도';
|
||||||
|
|
||||||
@@ -55,7 +53,7 @@ class che_모반시도 extends Command\GeneralCommand{
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function run():bool{
|
public function run(\Sammo\RandUtil $rng):bool{
|
||||||
if(!$this->hasFullConditionMet()){
|
if(!$this->hasFullConditionMet()){
|
||||||
throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도');
|
throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도');
|
||||||
}
|
}
|
||||||
@@ -99,7 +97,6 @@ class che_모반시도 extends Command\GeneralCommand{
|
|||||||
$this->setResultTurn(new LastTurn(static::getName(), $this->arg));
|
$this->setResultTurn(new LastTurn(static::getName(), $this->arg));
|
||||||
$general->increaseInheritancePoint(InheritanceKey::active_action, 1);
|
$general->increaseInheritancePoint(InheritanceKey::active_action, 1);
|
||||||
$general->checkStatChange();
|
$general->checkStatChange();
|
||||||
tryRollbackInheritUniqueItem($general);
|
|
||||||
$general->applyDB($db);
|
$general->applyDB($db);
|
||||||
$lordGeneral->applyDB($db);
|
$lordGeneral->applyDB($db);
|
||||||
|
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ class che_물자조달 extends Command\GeneralCommand{
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function run():bool{
|
public function run(\Sammo\RandUtil $rng):bool{
|
||||||
if(!$this->hasFullConditionMet()){
|
if(!$this->hasFullConditionMet()){
|
||||||
throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도');
|
throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도');
|
||||||
}
|
}
|
||||||
@@ -70,14 +70,14 @@ class che_물자조달 extends Command\GeneralCommand{
|
|||||||
$general = $this->generalObj;
|
$general = $this->generalObj;
|
||||||
$date = $general->getTurnTime($general::TURNTIME_HM);
|
$date = $general->getTurnTime($general::TURNTIME_HM);
|
||||||
|
|
||||||
[$resName, $resKey] = Util::choiceRandom([
|
[$resName, $resKey] = $rng->choice([
|
||||||
['금', 'gold'],
|
['금', 'gold'],
|
||||||
['쌀', 'rice']
|
['쌀', 'rice']
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$score = $general->getLeadership() + $general->getStrength() + $general->getIntel();
|
$score = $general->getLeadership() + $general->getStrength() + $general->getIntel();
|
||||||
$score *= getDomesticExpLevelBonus($general->getVar('explevel'));
|
$score *= getDomesticExpLevelBonus($general->getVar('explevel'));
|
||||||
$score *= Util::randRange(0.8, 1.2);
|
$score *= $rng->nextRange(0.8, 1.2);
|
||||||
|
|
||||||
$successRatio = 0.1;
|
$successRatio = 0.1;
|
||||||
$failRatio = 0.3;
|
$failRatio = 0.3;
|
||||||
@@ -86,12 +86,12 @@ class che_물자조달 extends Command\GeneralCommand{
|
|||||||
$failRatio = $general->onCalcDomestic('조달', 'fail', $failRatio);
|
$failRatio = $general->onCalcDomestic('조달', 'fail', $failRatio);
|
||||||
$normalRatio = 1 - $failRatio - $successRatio;
|
$normalRatio = 1 - $failRatio - $successRatio;
|
||||||
|
|
||||||
$pick = Util::choiceRandomUsingWeight([
|
$pick = $rng->choiceUsingWeight([
|
||||||
'fail'=>$failRatio,
|
'fail'=>$failRatio,
|
||||||
'success'=>$successRatio,
|
'success'=>$successRatio,
|
||||||
'normal'=>$normalRatio
|
'normal'=>$normalRatio
|
||||||
]);
|
]);
|
||||||
$score *= CriticalScoreEx($pick);
|
$score *= CriticalScoreEx($rng, $pick);
|
||||||
$score = $general->onCalcDomestic('조달', 'score', $score);
|
$score = $general->onCalcDomestic('조달', 'score', $score);
|
||||||
|
|
||||||
$score = Util::round($score);
|
$score = Util::round($score);
|
||||||
@@ -112,7 +112,7 @@ class che_물자조달 extends Command\GeneralCommand{
|
|||||||
$exp = $score * 0.7 / 3;
|
$exp = $score * 0.7 / 3;
|
||||||
$ded = $score * 1.0 / 3;
|
$ded = $score * 1.0 / 3;
|
||||||
|
|
||||||
$incStat = Util::choiceRandomUsingWeight([
|
$incStat = $rng->choiceUsingWeight([
|
||||||
'leadership_exp'=>$general->getLeadership(false, false, false, false),
|
'leadership_exp'=>$general->getLeadership(false, false, false, false),
|
||||||
'strength_exp'=>$general->getStrength(false, false, false, false),
|
'strength_exp'=>$general->getStrength(false, false, false, false),
|
||||||
'intel_exp'=>$general->getIntel(false, false, false, false)
|
'intel_exp'=>$general->getIntel(false, false, false, false)
|
||||||
@@ -128,7 +128,7 @@ class che_물자조달 extends Command\GeneralCommand{
|
|||||||
|
|
||||||
$this->setResultTurn(new LastTurn(static::getName(), $this->arg));
|
$this->setResultTurn(new LastTurn(static::getName(), $this->arg));
|
||||||
$general->checkStatChange();
|
$general->checkStatChange();
|
||||||
tryUniqueItemLottery($general);
|
tryUniqueItemLottery(\sammo\genGenericUniqueRNGFromGeneral($general), $general);
|
||||||
|
|
||||||
$general->applyDB($db);
|
$general->applyDB($db);
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ use sammo\Enums\InheritanceKey;
|
|||||||
|
|
||||||
use function sammo\DeleteConflict;
|
use function sammo\DeleteConflict;
|
||||||
use function sammo\refreshNationStaticInfo;
|
use function sammo\refreshNationStaticInfo;
|
||||||
use function sammo\tryRollbackInheritUniqueItem;
|
|
||||||
|
|
||||||
class che_방랑 extends Command\GeneralCommand{
|
class che_방랑 extends Command\GeneralCommand{
|
||||||
static protected $actionName = '방랑';
|
static protected $actionName = '방랑';
|
||||||
@@ -59,7 +58,7 @@ class che_방랑 extends Command\GeneralCommand{
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function run():bool{
|
public function run(\Sammo\RandUtil $rng):bool{
|
||||||
if(!$this->hasFullConditionMet()){
|
if(!$this->hasFullConditionMet()){
|
||||||
throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도');
|
throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도');
|
||||||
}
|
}
|
||||||
@@ -125,7 +124,6 @@ class che_방랑 extends Command\GeneralCommand{
|
|||||||
refreshNationStaticInfo();
|
refreshNationStaticInfo();
|
||||||
$general->increaseInheritancePoint(InheritanceKey::active_action, 1);
|
$general->increaseInheritancePoint(InheritanceKey::active_action, 1);
|
||||||
$this->setResultTurn(new LastTurn(static::getName(), $this->arg));
|
$this->setResultTurn(new LastTurn(static::getName(), $this->arg));
|
||||||
tryRollbackInheritUniqueItem($general);
|
|
||||||
$general->applyDB($db);
|
$general->applyDB($db);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ namespace sammo\Command\General;
|
|||||||
|
|
||||||
use \sammo\{
|
use \sammo\{
|
||||||
DB, Util, JosaUtil,
|
DB, Util, JosaUtil,
|
||||||
General,
|
General,
|
||||||
ActionLogger,
|
ActionLogger,
|
||||||
GameConst, GameUnitConst,
|
GameConst, GameUnitConst,
|
||||||
LastTurn,
|
LastTurn,
|
||||||
@@ -34,13 +34,13 @@ class che_사기진작 extends Command\GeneralCommand{
|
|||||||
[$reqGold, $reqRice] = $this->getCost();
|
[$reqGold, $reqRice] = $this->getCost();
|
||||||
|
|
||||||
$this->minConditionConstraints=[
|
$this->minConditionConstraints=[
|
||||||
ConstraintHelper::NotBeNeutral(),
|
ConstraintHelper::NotBeNeutral(),
|
||||||
ConstraintHelper::NotWanderingNation(),
|
ConstraintHelper::NotWanderingNation(),
|
||||||
ConstraintHelper::OccupiedCity(),
|
ConstraintHelper::OccupiedCity(),
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->fullConditionConstraints=[
|
$this->fullConditionConstraints=[
|
||||||
ConstraintHelper::NotBeNeutral(),
|
ConstraintHelper::NotBeNeutral(),
|
||||||
ConstraintHelper::NotWanderingNation(),
|
ConstraintHelper::NotWanderingNation(),
|
||||||
ConstraintHelper::OccupiedCity(),
|
ConstraintHelper::OccupiedCity(),
|
||||||
ConstraintHelper::ReqGeneralCrew(),
|
ConstraintHelper::ReqGeneralCrew(),
|
||||||
@@ -62,7 +62,7 @@ class che_사기진작 extends Command\GeneralCommand{
|
|||||||
$general = $this->generalObj;
|
$general = $this->generalObj;
|
||||||
return [Util::round($general->getVar('crew')/100), 0];
|
return [Util::round($general->getVar('crew')/100), 0];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPreReqTurn():int{
|
public function getPreReqTurn():int{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -71,7 +71,7 @@ class che_사기진작 extends Command\GeneralCommand{
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function run():bool{
|
public function run(\Sammo\RandUtil $rng):bool{
|
||||||
if(!$this->hasFullConditionMet()){
|
if(!$this->hasFullConditionMet()){
|
||||||
throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도');
|
throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도');
|
||||||
}
|
}
|
||||||
@@ -98,16 +98,19 @@ class che_사기진작 extends Command\GeneralCommand{
|
|||||||
|
|
||||||
$general->addDex($general->getCrewTypeObj(), $score, false);
|
$general->addDex($general->getCrewTypeObj(), $score, false);
|
||||||
|
|
||||||
|
[$reqGold,] = $this->getCost();
|
||||||
|
$general->increaseVarWithLimit('gold', -$reqGold, 0);
|
||||||
|
|
||||||
$general->addExperience($exp);
|
$general->addExperience($exp);
|
||||||
$general->addDedication($ded);
|
$general->addDedication($ded);
|
||||||
$general->increaseVar('leadership_exp', 1);
|
$general->increaseVar('leadership_exp', 1);
|
||||||
$this->setResultTurn(new LastTurn(static::getName(), $this->arg));
|
$this->setResultTurn(new LastTurn(static::getName(), $this->arg));
|
||||||
$general->checkStatChange();
|
$general->checkStatChange();
|
||||||
tryUniqueItemLottery($general);
|
tryUniqueItemLottery(\sammo\genGenericUniqueRNGFromGeneral($general), $general);
|
||||||
$general->applyDB($db);
|
$general->applyDB($db);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -3,12 +3,13 @@ namespace sammo\Command\General;
|
|||||||
|
|
||||||
use \sammo\{
|
use \sammo\{
|
||||||
DB, Util, JosaUtil,
|
DB, Util, JosaUtil,
|
||||||
General,
|
General,
|
||||||
ActionLogger,
|
ActionLogger,
|
||||||
GameConst,
|
GameConst,
|
||||||
LastTurn,
|
LastTurn,
|
||||||
GameUnitConst,
|
GameUnitConst,
|
||||||
Command
|
Command,
|
||||||
|
RandUtil
|
||||||
};
|
};
|
||||||
|
|
||||||
use function \sammo\getDomesticExpLevelBonus;
|
use function \sammo\getDomesticExpLevelBonus;
|
||||||
@@ -41,11 +42,11 @@ class che_상업투자 extends Command\GeneralCommand{
|
|||||||
|
|
||||||
$this->setCity();
|
$this->setCity();
|
||||||
$this->setNation();
|
$this->setNation();
|
||||||
|
|
||||||
[$reqGold, $reqRice] = $this->getCost();
|
[$reqGold, $reqRice] = $this->getCost();
|
||||||
|
|
||||||
$this->fullConditionConstraints=[
|
$this->fullConditionConstraints=[
|
||||||
ConstraintHelper::NotBeNeutral(),
|
ConstraintHelper::NotBeNeutral(),
|
||||||
ConstraintHelper::NotWanderingNation(),
|
ConstraintHelper::NotWanderingNation(),
|
||||||
ConstraintHelper::OccupiedCity(),
|
ConstraintHelper::OccupiedCity(),
|
||||||
ConstraintHelper::SuppliedCity(),
|
ConstraintHelper::SuppliedCity(),
|
||||||
@@ -82,15 +83,15 @@ class che_상업투자 extends Command\GeneralCommand{
|
|||||||
$develCost = $this->env['develcost'];
|
$develCost = $this->env['develcost'];
|
||||||
$reqGold = Util::round($this->generalObj->onCalcDomestic(static::$actionKey, 'cost', $develCost));
|
$reqGold = Util::round($this->generalObj->onCalcDomestic(static::$actionKey, 'cost', $develCost));
|
||||||
$reqRice = 0;
|
$reqRice = 0;
|
||||||
|
|
||||||
return [$reqGold, $reqRice];
|
return [$reqGold, $reqRice];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function getCompensationStyle():?int{
|
public function getCompensationStyle():?int{
|
||||||
return $this->generalObj->onCalcDomestic(static::$actionKey, 'score', 100)<=>100;
|
return $this->generalObj->onCalcDomestic(static::$actionKey, 'score', 100)<=>100;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPreReqTurn():int{
|
public function getPreReqTurn():int{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -99,7 +100,7 @@ class che_상업투자 extends Command\GeneralCommand{
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function calcBaseScore():float{
|
protected function calcBaseScore(RandUtil $rng):float{
|
||||||
$trust = Util::valueFit($this->city['trust'], 50);
|
$trust = Util::valueFit($this->city['trust'], 50);
|
||||||
$general = $this->generalObj;
|
$general = $this->generalObj;
|
||||||
|
|
||||||
@@ -115,16 +116,16 @@ class che_상업투자 extends Command\GeneralCommand{
|
|||||||
else{
|
else{
|
||||||
throw new \sammo\MustNotBeReachedException();
|
throw new \sammo\MustNotBeReachedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
$score *= $trust / 100;
|
$score *= $trust / 100;
|
||||||
$score *= getDomesticExpLevelBonus($general->getVar('explevel'));
|
$score *= getDomesticExpLevelBonus($general->getVar('explevel'));
|
||||||
$score *= Util::randRange(0.8, 1.2);
|
$score *= $rng->nextRange(0.8, 1.2);
|
||||||
$score = $general->onCalcDomestic(static::$actionKey, 'score', $score);
|
$score = $general->onCalcDomestic(static::$actionKey, 'score', $score);
|
||||||
|
|
||||||
return $score;
|
return $score;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function run():bool{
|
public function run(\Sammo\RandUtil $rng):bool{
|
||||||
if(!$this->hasFullConditionMet()){
|
if(!$this->hasFullConditionMet()){
|
||||||
throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도');
|
throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도');
|
||||||
}
|
}
|
||||||
@@ -135,7 +136,7 @@ class che_상업투자 extends Command\GeneralCommand{
|
|||||||
|
|
||||||
$trust = Util::valueFit($this->city['trust'], 50);
|
$trust = Util::valueFit($this->city['trust'], 50);
|
||||||
|
|
||||||
$score = Util::valueFit($this->calcBaseScore(), 1);
|
$score = Util::valueFit($this->calcBaseScore($rng), 1);
|
||||||
|
|
||||||
['success'=>$successRatio, 'fail'=>$failRatio] = CriticalRatioDomestic($general, static::$statKey);
|
['success'=>$successRatio, 'fail'=>$failRatio] = CriticalRatioDomestic($general, static::$statKey);
|
||||||
if($trust < 80){
|
if($trust < 80){
|
||||||
@@ -148,9 +149,9 @@ class che_상업투자 extends Command\GeneralCommand{
|
|||||||
$failRatio = Util::valueFit($failRatio, 0, 1 - $successRatio);
|
$failRatio = Util::valueFit($failRatio, 0, 1 - $successRatio);
|
||||||
$normalRatio = 1 - $failRatio - $successRatio;
|
$normalRatio = 1 - $failRatio - $successRatio;
|
||||||
|
|
||||||
$pick = Util::choiceRandomUsingWeight([
|
$pick = $rng->choiceUsingWeight([
|
||||||
'fail'=>$failRatio,
|
'fail'=>$failRatio,
|
||||||
'success'=>$successRatio,
|
'success'=>$successRatio,
|
||||||
'normal'=>$normalRatio
|
'normal'=>$normalRatio
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -158,14 +159,14 @@ class che_상업투자 extends Command\GeneralCommand{
|
|||||||
|
|
||||||
$date = $general->getTurnTime($general::TURNTIME_HM);
|
$date = $general->getTurnTime($general::TURNTIME_HM);
|
||||||
|
|
||||||
$score *= CriticalScoreEx($pick);
|
$score *= CriticalScoreEx($rng, $pick);
|
||||||
$score = Util::round($score);
|
$score = Util::round($score);
|
||||||
|
|
||||||
$exp = $score * 0.7;
|
$exp = $score * 0.7;
|
||||||
$ded = $score * 1.0;
|
$ded = $score * 1.0;
|
||||||
|
|
||||||
if($pick == 'success'){
|
if($pick == 'success'){
|
||||||
updateMaxDomesticCritical($general, $score);
|
updateMaxDomesticCritical($general, $score);
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
$general->setAuxVar('max_domestic_critical', 0);
|
$general->setAuxVar('max_domestic_critical', 0);
|
||||||
@@ -204,7 +205,7 @@ class che_상업투자 extends Command\GeneralCommand{
|
|||||||
$general->increaseVar(static::$statKey.'_exp', 1);
|
$general->increaseVar(static::$statKey.'_exp', 1);
|
||||||
$this->setResultTurn(new LastTurn(static::getName(), $this->arg));
|
$this->setResultTurn(new LastTurn(static::getName(), $this->arg));
|
||||||
$general->checkStatChange();
|
$general->checkStatChange();
|
||||||
tryUniqueItemLottery($general);
|
tryUniqueItemLottery(\sammo\genGenericUniqueRNGFromGeneral($general), $general);
|
||||||
$general->applyDB($db);
|
$general->applyDB($db);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ use \sammo\ActionLogger;
|
|||||||
use \sammo\GameConst;
|
use \sammo\GameConst;
|
||||||
use \sammo\GameUnitConst;
|
use \sammo\GameUnitConst;
|
||||||
use \sammo\Command;
|
use \sammo\Command;
|
||||||
|
use sammo\RandUtil;
|
||||||
|
|
||||||
class che_선동 extends che_화계{
|
class che_선동 extends che_화계{
|
||||||
static protected $actionName = '선동';
|
static protected $actionName = '선동';
|
||||||
@@ -16,7 +17,7 @@ class che_선동 extends che_화계{
|
|||||||
static protected $statType = 'leadership';
|
static protected $statType = 'leadership';
|
||||||
static protected $injuryGeneral = true;
|
static protected $injuryGeneral = true;
|
||||||
|
|
||||||
protected function affectDestCity(int $injuryCount){
|
protected function affectDestCity(RandUtil $rng, int $injuryCount){
|
||||||
$general = $this->generalObj;
|
$general = $this->generalObj;
|
||||||
$date = $general->getTurnTime($general::TURNTIME_HM);
|
$date = $general->getTurnTime($general::TURNTIME_HM);
|
||||||
|
|
||||||
@@ -30,15 +31,15 @@ class che_선동 extends che_화계{
|
|||||||
$commandName = $this->getName();
|
$commandName = $this->getName();
|
||||||
|
|
||||||
// 선동 최대 10
|
// 선동 최대 10
|
||||||
$secuAmount = Util::valueFit(Util::randRangeInt(GameConst::$sabotageDamageMin, GameConst::$sabotageDamageMax), null, $destCity['secu']);
|
$secuAmount = Util::valueFit($rng->nextRangeInt(GameConst::$sabotageDamageMin, GameConst::$sabotageDamageMax), null, $destCity['secu']);
|
||||||
$trustAmount = Util::valueFit(
|
$trustAmount = Util::valueFit(
|
||||||
Util::randRange(GameConst::$sabotageDamageMin, GameConst::$sabotageDamageMax) / 50,
|
$rng->nextRange(GameConst::$sabotageDamageMin, GameConst::$sabotageDamageMax) / 50,
|
||||||
null,
|
null,
|
||||||
$destCity['trust']
|
$destCity['trust']
|
||||||
);
|
);
|
||||||
$destCity['secu'] -= $secuAmount;
|
$destCity['secu'] -= $secuAmount;
|
||||||
$destCity['trust'] -= $trustAmount;
|
$destCity['trust'] -= $trustAmount;
|
||||||
|
|
||||||
DB::db()->update('city', [
|
DB::db()->update('city', [
|
||||||
'state'=>32,
|
'state'=>32,
|
||||||
'secu'=>$destCity['secu'],
|
'secu'=>$destCity['secu'],
|
||||||
@@ -57,5 +58,5 @@ class che_선동 extends che_화계{
|
|||||||
ActionLogger::PLAIN
|
ActionLogger::PLAIN
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user