Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7a3642296a
|
||
|
|
87e57aea0e
|
||
|
|
ea256790ec
|
||
|
|
4cbd824ee0
|
||
|
|
4db1a4b32e
|
||
|
|
c060e05553
|
||
|
|
92cd195276
|
||
|
|
f9b270fef3
|
||
|
|
3f12dfd8ba
|
||
|
|
d7e57f30eb
|
||
|
|
ff822561cd
|
||
|
|
273973f4b6
|
||
|
|
c648e2df85
|
||
|
|
9b7e0ef169
|
||
|
|
6eccd248ea
|
||
|
|
eaaa1c5da8
|
||
|
|
95776cda5c
|
||
|
|
8ae0323dcc
|
||
|
|
f2d0020d92
|
||
|
|
67f3004eb0
|
||
|
|
f933c0616b | ||
|
|
a240c6f901
|
||
|
|
e2c2ae0360
|
||
|
|
bcd0117cdd
|
||
|
|
83f233cc99
|
||
|
|
4f21eab7b1
|
||
|
|
864ddf7efe
|
||
|
|
9d3636cc49
|
||
|
|
ce4f656030
|
||
|
|
a94f080cde
|
||
|
|
71ca873c7a
|
||
|
|
6e0d13e1fb
|
||
|
|
059c4d999a
|
||
|
|
f52e357e8a
|
||
|
|
761496be5c
|
||
|
|
551972d876
|
||
|
|
81c2fc4d43
|
||
|
|
3e542fcbfa
|
||
|
|
c9ab2c593d
|
||
|
|
0c9e00e90a
|
||
|
|
ea17972478
|
||
|
|
3d40df9755
|
||
|
|
b4ac348645
|
||
|
|
374611f66c
|
||
|
|
39b66fd626
|
||
|
|
75dca322b4 | ||
|
|
cfdae1ddfa
|
||
|
|
054a6c7073
|
||
|
|
e93d9e6cf5
|
||
|
|
30d99c6fc3
|
||
|
|
56c9b44c93
|
||
|
|
919ae5a863
|
||
|
|
43b8e546f6
|
||
|
|
b90aef662b
|
||
|
|
1da47863ae
|
||
|
|
81bd5c1914
|
||
|
|
b14f9a638f
|
||
|
|
8ff3a5a7a8
|
||
|
|
48c77bd6a2
|
||
|
|
35a017c1dc | ||
|
|
a3e8a10da9
|
||
|
|
142b96836e
|
||
|
|
9be0d2ec2d
|
||
|
|
fd817650e7
|
||
|
|
3c6cb96a9b
|
||
|
|
c4537454f9
|
||
|
|
82cdaa433e
|
||
|
|
32dd3ff43f
|
||
|
|
6a5840faaa
|
||
|
|
5b0a3b064d
|
||
|
|
14b8bb9790
|
||
|
|
650f4a5903 | ||
|
|
c50410a6da | ||
|
|
b2a676cd8b | ||
|
|
50a75e4543 | ||
|
|
22172ac66f | ||
|
|
392aaa343d | ||
|
|
d924f47d58 | ||
|
|
3b70cbe724 | ||
|
|
5c3233f883 | ||
|
|
b570bfa9d4 | ||
|
|
270cb25285 | ||
|
|
7d3b0db924 | ||
|
|
74d310e113 | ||
|
|
45afb1c090 | ||
|
|
40fc2f8bbf
|
||
|
|
a9de5a92e1
|
||
|
|
c592b00c3f
|
||
|
|
2c81be4d12
|
||
|
|
f10289f7b6
|
||
|
|
c1f06b4ce5 | ||
|
|
9ad3dbba90
|
||
|
|
12c62f87f7
|
||
|
|
635f1ae077
|
||
|
|
c89bd2f63f
|
||
|
|
2f94a8a2ca | ||
|
|
85b0d35af0 | ||
|
|
b25acacb1e | ||
|
|
c05a43f3b1
|
||
|
|
d99976daa9
|
||
|
|
62f53d09bf
|
@@ -10,8 +10,10 @@
|
||||
*.log
|
||||
|
||||
logs/*.txt
|
||||
api_log.db
|
||||
d_log/*.txt
|
||||
d_log/*.zip
|
||||
d_log/*.db
|
||||
sess_*
|
||||
*/logs/*.txt
|
||||
*/logs/*/*.txt
|
||||
|
||||
@@ -98,12 +98,6 @@ return [
|
||||
'hwe/j_load_scenarios.php',
|
||||
'hwe/j_map.php',
|
||||
'hwe/j_map_recent.php',
|
||||
'hwe/j_msg_contact_list.php',
|
||||
'hwe/j_msg_decide_opt.php',
|
||||
'hwe/j_msg_delete.php',
|
||||
'hwe/j_msg_get_old.php',
|
||||
'hwe/j_msg_get_recent.php',
|
||||
'hwe/j_msg_submit.php',
|
||||
'hwe/j_myBossInfo.php',
|
||||
'hwe/j_raise_event.php',
|
||||
'hwe/j_select_npc.php',
|
||||
@@ -112,7 +106,6 @@ return [
|
||||
'hwe/j_set_my_setting.php',
|
||||
'hwe/j_set_npc_control.php',
|
||||
'hwe/j_simulate_battle.php',
|
||||
'hwe/j_troop.php',
|
||||
'hwe/j_update_picked_general.php',
|
||||
'hwe/j_vacation.php',
|
||||
'hwe/lib.php',
|
||||
|
||||
+2
-2
@@ -17,7 +17,6 @@
|
||||
"league/plates": "^3.3",
|
||||
"vlucas/valitron": "^1.4",
|
||||
"php-extended/php-tail": "^2.1",
|
||||
"pguardiario/phpuri": "^1.0",
|
||||
"symfony/lock": "^6.0",
|
||||
"ezyang/htmlpurifier": "^4.10",
|
||||
"xemlock/htmlpurifier-html5": "^0.1.7",
|
||||
@@ -27,7 +26,8 @@
|
||||
"illuminate/database": "^9.12",
|
||||
"illuminate/events": "^9.12",
|
||||
"php-ds/php-ds": "^1.4",
|
||||
"hided62/ldto": "^1.0"
|
||||
"hided62/ldto": "^1.0",
|
||||
"league/uri": "^6.8"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
||||
Generated
+225
-29
@@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "fe4387d1f2df3d3162c053a1d50a733a",
|
||||
"content-hash": "d7acaa437c3c6f48c9a643c9dc4ef421",
|
||||
"packages": [
|
||||
{
|
||||
"name": "brandonwamboldt/utilphp",
|
||||
@@ -1194,6 +1194,177 @@
|
||||
},
|
||||
"time": "2020-12-25T05:00:37+00:00"
|
||||
},
|
||||
{
|
||||
"name": "league/uri",
|
||||
"version": "6.8.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thephpleague/uri.git",
|
||||
"reference": "a700b4656e4c54371b799ac61e300ab25a2d1d39"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/thephpleague/uri/zipball/a700b4656e4c54371b799ac61e300ab25a2d1d39",
|
||||
"reference": "a700b4656e4c54371b799ac61e300ab25a2d1d39",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-json": "*",
|
||||
"league/uri-interfaces": "^2.3",
|
||||
"php": "^8.1",
|
||||
"psr/http-message": "^1.0.1"
|
||||
},
|
||||
"conflict": {
|
||||
"league/uri-schemes": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"friendsofphp/php-cs-fixer": "^v3.9.5",
|
||||
"nyholm/psr7": "^1.5.1",
|
||||
"php-http/psr7-integration-tests": "^1.1.1",
|
||||
"phpbench/phpbench": "^1.2.6",
|
||||
"phpstan/phpstan": "^1.8.5",
|
||||
"phpstan/phpstan-deprecation-rules": "^1.0",
|
||||
"phpstan/phpstan-phpunit": "^1.1.1",
|
||||
"phpstan/phpstan-strict-rules": "^1.4.3",
|
||||
"phpunit/phpunit": "^9.5.24",
|
||||
"psr/http-factory": "^1.0.1"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-fileinfo": "Needed to create Data URI from a filepath",
|
||||
"ext-intl": "Needed to improve host validation",
|
||||
"league/uri-components": "Needed to easily manipulate URI objects",
|
||||
"psr/http-factory": "Needed to use the URI factory"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "6.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"League\\Uri\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Ignace Nyamagana Butera",
|
||||
"email": "nyamsprod@gmail.com",
|
||||
"homepage": "https://nyamsprod.com"
|
||||
}
|
||||
],
|
||||
"description": "URI manipulation library",
|
||||
"homepage": "https://uri.thephpleague.com",
|
||||
"keywords": [
|
||||
"data-uri",
|
||||
"file-uri",
|
||||
"ftp",
|
||||
"hostname",
|
||||
"http",
|
||||
"https",
|
||||
"middleware",
|
||||
"parse_str",
|
||||
"parse_url",
|
||||
"psr-7",
|
||||
"query-string",
|
||||
"querystring",
|
||||
"rfc3986",
|
||||
"rfc3987",
|
||||
"rfc6570",
|
||||
"uri",
|
||||
"uri-template",
|
||||
"url",
|
||||
"ws"
|
||||
],
|
||||
"support": {
|
||||
"docs": "https://uri.thephpleague.com",
|
||||
"forum": "https://thephpleague.slack.com",
|
||||
"issues": "https://github.com/thephpleague/uri/issues",
|
||||
"source": "https://github.com/thephpleague/uri/tree/6.8.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/sponsors/nyamsprod",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2022-09-13T19:58:47+00:00"
|
||||
},
|
||||
{
|
||||
"name": "league/uri-interfaces",
|
||||
"version": "2.3.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thephpleague/uri-interfaces.git",
|
||||
"reference": "00e7e2943f76d8cb50c7dfdc2f6dee356e15e383"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/00e7e2943f76d8cb50c7dfdc2f6dee356e15e383",
|
||||
"reference": "00e7e2943f76d8cb50c7dfdc2f6dee356e15e383",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-json": "*",
|
||||
"php": "^7.2 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"friendsofphp/php-cs-fixer": "^2.19",
|
||||
"phpstan/phpstan": "^0.12.90",
|
||||
"phpstan/phpstan-phpunit": "^0.12.19",
|
||||
"phpstan/phpstan-strict-rules": "^0.12.9",
|
||||
"phpunit/phpunit": "^8.5.15 || ^9.5"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-intl": "to use the IDNA feature",
|
||||
"symfony/intl": "to use the IDNA feature via Symfony Polyfill"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"League\\Uri\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Ignace Nyamagana Butera",
|
||||
"email": "nyamsprod@gmail.com",
|
||||
"homepage": "https://nyamsprod.com"
|
||||
}
|
||||
],
|
||||
"description": "Common interface for URI representation",
|
||||
"homepage": "http://github.com/thephpleague/uri-interfaces",
|
||||
"keywords": [
|
||||
"rfc3986",
|
||||
"rfc3987",
|
||||
"uri",
|
||||
"url"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/thephpleague/uri-interfaces/issues",
|
||||
"source": "https://github.com/thephpleague/uri-interfaces/tree/2.3.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/sponsors/nyamsprod",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2021-06-28T04:27:21+00:00"
|
||||
},
|
||||
{
|
||||
"name": "microsoft/tolerant-php-parser",
|
||||
"version": "v0.1.1",
|
||||
@@ -1610,34 +1781,6 @@
|
||||
},
|
||||
"time": "2022-01-24T11:29:14+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pguardiario/phpuri",
|
||||
"version": "1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/monkeysuffrage/phpuri.git",
|
||||
"reference": "ad0a5ec033fe616cfef55578b9c7f2458be8fbfc"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/monkeysuffrage/phpuri/zipball/ad0a5ec033fe616cfef55578b9c7f2458be8fbfc",
|
||||
"reference": "ad0a5ec033fe616cfef55578b9c7f2458be8fbfc",
|
||||
"shasum": ""
|
||||
},
|
||||
"type": "project",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"phpuri.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"description": "A php library for converting relative urls to absolute.",
|
||||
"support": {
|
||||
"issues": "https://github.com/monkeysuffrage/phpuri/issues",
|
||||
"source": "https://github.com/monkeysuffrage/phpuri/tree/1.0.0"
|
||||
},
|
||||
"time": "2015-05-24T09:13:17+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phan/phan",
|
||||
"version": "5.3.2",
|
||||
@@ -2077,6 +2220,59 @@
|
||||
},
|
||||
"time": "2021-11-05T16:47:00+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/http-message",
|
||||
"version": "1.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-fig/http-message.git",
|
||||
"reference": "f6561bf28d520154e4b0ec72be95418abe6d9363"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363",
|
||||
"reference": "f6561bf28d520154e4b0ec72be95418abe6d9363",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Psr\\Http\\Message\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "PHP-FIG",
|
||||
"homepage": "http://www.php-fig.org/"
|
||||
}
|
||||
],
|
||||
"description": "Common interface for HTTP messages",
|
||||
"homepage": "https://github.com/php-fig/http-message",
|
||||
"keywords": [
|
||||
"http",
|
||||
"http-message",
|
||||
"psr",
|
||||
"psr-7",
|
||||
"request",
|
||||
"response"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/php-fig/http-message/tree/master"
|
||||
},
|
||||
"time": "2016-08-06T14:39:51+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/log",
|
||||
"version": "3.0.0",
|
||||
|
||||
Binary file not shown.
@@ -90,19 +90,19 @@ if (
|
||||
|
||||
//기본 파일 생성
|
||||
if (!file_exists(AppConf::getUserIconPathFS())) {
|
||||
mkdir(AppConf::getUserIconPathFS());
|
||||
mkdir(AppConf::getUserIconPathFS(), 0775);
|
||||
}
|
||||
|
||||
if (!file_exists(ROOT . '/d_log')) {
|
||||
mkdir(ROOT . '/d_log');
|
||||
mkdir(ROOT . '/d_log', 0775);
|
||||
}
|
||||
|
||||
if (!file_exists(ROOT . '/d_setting')) {
|
||||
mkdir(ROOT . '/d_setting');
|
||||
mkdir(ROOT . '/d_setting', 0775);
|
||||
}
|
||||
|
||||
if (!file_exists(ROOT . '/d_shared')) {
|
||||
mkdir(ROOT . '/d_shared');
|
||||
mkdir(ROOT . '/d_shared', 0775);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
CREATE TABLE IF NOT EXISTS "api_log" (
|
||||
"id" INTEGER NOT NULL,
|
||||
"user_id" INTEGER NOT NULL,
|
||||
"ip" TEXT NOT NULL,
|
||||
"date" TEXT NOT NULL,
|
||||
"path" TEXT NOT NULL,
|
||||
"arg" TEXT,
|
||||
"aux" TEXT,
|
||||
PRIMARY KEY("id" AUTOINCREMENT)
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS "by_date" ON "api_log" (
|
||||
"date" DESC
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS "by_user" ON "api_log" (
|
||||
"user_id" ASC,
|
||||
"date" DESC
|
||||
);
|
||||
+10
-8
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace sammo;
|
||||
|
||||
use sammo\Enums\MessageType;
|
||||
|
||||
include "lib.php";
|
||||
include "func.php";
|
||||
|
||||
@@ -111,7 +113,7 @@ switch ($btn) {
|
||||
case "경험치1000":
|
||||
$text = $btn . " 지급!";
|
||||
foreach ($genlist as $generalID) {
|
||||
$msg = new Message(Message::MSGTYPE_PRIVATE, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
|
||||
$msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
|
||||
$msg->send(true);
|
||||
}
|
||||
$db->update('general', [
|
||||
@@ -122,7 +124,7 @@ switch ($btn) {
|
||||
case "공헌치1000":
|
||||
$text = $btn . " 지급!";
|
||||
foreach ($genlist as $generalID) {
|
||||
$msg = new Message(Message::MSGTYPE_PRIVATE, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
|
||||
$msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
|
||||
$msg->send(true);
|
||||
}
|
||||
$db->update('general', [
|
||||
@@ -133,7 +135,7 @@ switch ($btn) {
|
||||
case "보숙10000":
|
||||
$text = "보병숙련도+10000 지급!";
|
||||
foreach ($genlist as $generalID) {
|
||||
$msg = new Message(Message::MSGTYPE_PRIVATE, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
|
||||
$msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
|
||||
$msg->send(true);
|
||||
}
|
||||
$db->update('general', [
|
||||
@@ -143,7 +145,7 @@ switch ($btn) {
|
||||
case "궁숙10000":
|
||||
$text = "궁병숙련도+10000 지급!";
|
||||
foreach ($genlist as $generalID) {
|
||||
$msg = new Message(Message::MSGTYPE_PRIVATE, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
|
||||
$msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
|
||||
$msg->send(true);
|
||||
}
|
||||
$db->update('general', [
|
||||
@@ -154,7 +156,7 @@ switch ($btn) {
|
||||
$src = MessageTarget::buildQuick($session->generalID);
|
||||
$text = "기병숙련도+10000 지급!";
|
||||
foreach ($genlist as $generalID) {
|
||||
$msg = new Message(Message::MSGTYPE_PRIVATE, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
|
||||
$msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
|
||||
$msg->send(true);
|
||||
}
|
||||
$db->update('general', [
|
||||
@@ -165,7 +167,7 @@ switch ($btn) {
|
||||
$src = MessageTarget::buildQuick($session->generalID);
|
||||
$text = "귀병숙련도+10000 지급!";
|
||||
foreach ($genlist as $generalID) {
|
||||
$msg = new Message(Message::MSGTYPE_PRIVATE, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
|
||||
$msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
|
||||
$msg->send(true);
|
||||
}
|
||||
$db->update('general', [
|
||||
@@ -176,7 +178,7 @@ switch ($btn) {
|
||||
$src = MessageTarget::buildQuick($session->generalID);
|
||||
$text = "차병숙련도+10000 지급!";
|
||||
foreach ($genlist as $generalID) {
|
||||
$msg = new Message(Message::MSGTYPE_PRIVATE, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
|
||||
$msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
|
||||
$msg->send(true);
|
||||
}
|
||||
$db->update('general', [
|
||||
@@ -196,7 +198,7 @@ switch ($btn) {
|
||||
case "메세지 전달":
|
||||
$text = $msg ?? '';
|
||||
foreach ($genlist as $generalID) {
|
||||
$msg = new Message(Message::MSGTYPE_PRIVATE, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
|
||||
$msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
|
||||
$msg->send(true);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace sammo;
|
||||
|
||||
use sammo\Enums\MessageType;
|
||||
|
||||
include "lib.php";
|
||||
include "func.php";
|
||||
//로그인 검사
|
||||
@@ -18,7 +20,7 @@ $msg = Util::getPost('msg', 'string', '메시지');
|
||||
|
||||
$db = DB::db();
|
||||
|
||||
//NOTE: 왜 기능이 admin2와 admin4가 같이 있는가?
|
||||
//NOTE: 왜 기능이 admin2와 admin4가 같이 있는가?
|
||||
//NOTE: 왜 블럭 시 admin4에선 금쌀을 없애지 않는가?
|
||||
switch ($btn) {
|
||||
case "블럭 해제":
|
||||
@@ -66,7 +68,7 @@ switch ($btn) {
|
||||
$src = MessageTarget::buildQuick($session->generalID);
|
||||
foreach($genlist as $generalID){
|
||||
$msgObj = new Message(
|
||||
Message::MSGTYPE_PRIVATE,
|
||||
MessageType::private,
|
||||
$src,
|
||||
MessageTarget::buildQuick($generalID),
|
||||
$msg,
|
||||
|
||||
@@ -27,7 +27,6 @@ foreach ($db->queryFirstColumn(
|
||||
|
||||
$inheritPointManager = InheritancePointManager::getInstance();
|
||||
foreach(General::createGeneralObjListFromDB($db->queryFirstColumn('SELECT `no` FROM general WHERE npc = 0')) as $genObj){
|
||||
$inheritPointManager->mergeTotalInheritancePoint($genObj, true);
|
||||
$inheritPointManager->mergeTotalInheritancePoint($genObj);
|
||||
$inheritPointManager->applyInheritanceUser($genObj->getVar('owner'));
|
||||
$inheritPointManager->clearInheritancePoint($genObj);
|
||||
}
|
||||
+1
-1
@@ -8,7 +8,7 @@ include "func.php";
|
||||
$db = DB::db();
|
||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||
|
||||
increaseRefresh("갱신정보", 2);
|
||||
increaseRefresh("갱신정보", 1);
|
||||
|
||||
$admin = $gameStor->getValues(['year', 'month', 'refresh', 'maxrefresh', 'maxonline']);
|
||||
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@ if ($myset > 0) {
|
||||
$submit = 'hidden';
|
||||
}
|
||||
|
||||
$targetTime = addTurn($me->getVar('lastrefresh'), $gameStor->turnterm, 2);
|
||||
$targetTime = addTurn($me->getVar('lastrefresh'), $gameStor->turnterm, GameConst::$minTurnDieOnPrestart);
|
||||
if ($gameStor->turntime <= $gameStor->opentime) {
|
||||
//서버 가오픈시 할 수 있는 행동
|
||||
if ($me->getNPCType() == 0 && $me->getNationID() == 0) {
|
||||
|
||||
@@ -65,8 +65,8 @@ if ($nationID) {
|
||||
전역 설정
|
||||
</div>
|
||||
<div class="card-body dragpad_battle">
|
||||
<div class="row">
|
||||
<div class="col-sm-6">
|
||||
<div class="row gx-0">
|
||||
<div class="col-sm-4">
|
||||
<div class="input-group">
|
||||
<input type="number" class="form-control" aria-describedby="text_year" value="<?= $startYear ?>" disabled>
|
||||
<div class="input-group-text"> 년 시작 </div>
|
||||
@@ -76,9 +76,13 @@ if ($nationID) {
|
||||
<div class="input-group-text"> 월 </div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<div class="col-sm-5 px-2">
|
||||
<div class="btn-toolbar" role="toolbar">
|
||||
<div class="input-group me-2" role="group">
|
||||
<div class="input-group-text">
|
||||
시드
|
||||
</div>
|
||||
<input type="text" class="form-control" id="seed" aria-describedby="text_seed">
|
||||
<div class="input-group-text">
|
||||
반복 횟수
|
||||
</div>
|
||||
@@ -87,6 +91,10 @@ if ($nationID) {
|
||||
<option value="1000">1000회 (요약 표기)</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
<div class="btn-toolbar" role="toolbar">
|
||||
<div class="btn-group me-2" role="group">
|
||||
<button type="button" class="btn btn-danger btn-begin_battle">전투</button>
|
||||
</div>
|
||||
@@ -426,6 +434,25 @@ if ($nationID) {
|
||||
</div>
|
||||
<input type="number" class="form-control form_killcrew" value="0" step="1">
|
||||
</div>
|
||||
|
||||
<div class="input-group mb-0">
|
||||
<div class="input-group-text">자신</div>
|
||||
<div class="input-group-text">회피 확률</div>
|
||||
<input type="number" class="form-control form_war_avoid_ratio" value="0" step="1" min="0" max="5">
|
||||
<div class="input-group-text">필살 확률</div>
|
||||
<input type="number" class="form-control form_war_critical_ratio" value="0" step="1" min="0" max="5">
|
||||
<div class="input-group-text">계략 시도 확률</div>
|
||||
<input type="number" class="form-control form_war_magic_trial_prob" value="0" step="1" min="0" max="5">
|
||||
</div>
|
||||
<div class="input-group mb-1">
|
||||
<div class="input-group-text">상대</div>
|
||||
<div class="input-group-text">회피 확률</div>
|
||||
<input type="number" class="form-control form_oppose_war_avoid_ratio" value="0" step="1" min="0" max="5">
|
||||
<div class="input-group-text">필살 확률</div>
|
||||
<input type="number" class="form-control form_oppose_war_critical_ratio" value="0" step="1" min="0" max="5">
|
||||
<div class="input-group-text">계략 시도 확률</div>
|
||||
<input type="number" class="form-control form_oppose_war_magic_trial_prob" value="0" step="1" min="0" max="5">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
+38
-59
@@ -886,7 +886,7 @@ function generalInfo2(General $generalObj)
|
||||
|
||||
function getOnlineNum(): int
|
||||
{
|
||||
return KVStorage::getStorage(DB::db(), 'game_env')->getValue('online') ?? 0;
|
||||
return KVStorage::getStorage(DB::db(), 'game_env')->getValue('online_user_cnt') ?? 0;
|
||||
}
|
||||
|
||||
function onlinegen(General $general)
|
||||
@@ -1003,19 +1003,31 @@ function increaseRefresh($type = "", $cnt = 1)
|
||||
|
||||
$db = DB::db();
|
||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||
$gameStor->refresh = $gameStor->refresh + $cnt; //TODO: +로 증가하는 값은 별도로 분리
|
||||
$isunited = $gameStor->isunited;
|
||||
$opentime = $gameStor->opentime;
|
||||
|
||||
if ($isunited != 2 && $generalID && $userGrade < 6 && $opentime <= TimeUtil::now()) {
|
||||
$db->update('general', [
|
||||
'lastrefresh' => $date,
|
||||
'con' => $db->sqleval('con + %i', $cnt),
|
||||
'connect' => $db->sqleval('connect + %i', $cnt),
|
||||
'refcnt' => $db->sqleval('refcnt + %i', $cnt),
|
||||
'refresh' => $db->sqleval('refresh + %i', $cnt)
|
||||
], 'owner=%i', $userID);
|
||||
if($userGrade == 6){
|
||||
return;
|
||||
}
|
||||
if($isunited == 2){
|
||||
return;
|
||||
}
|
||||
if(!$generalID){
|
||||
return;
|
||||
}
|
||||
if($opentime > $date){
|
||||
return;
|
||||
}
|
||||
|
||||
$gameStor->refresh = $gameStor->refresh + $cnt; //TODO: +로 증가하는 값은 별도로 분리
|
||||
|
||||
$db->update('general', [
|
||||
'lastrefresh' => $date,
|
||||
'con' => $db->sqleval('con + %i', $cnt),
|
||||
'connect' => $db->sqleval('connect + %i', $cnt),
|
||||
'refcnt' => $db->sqleval('refcnt + %i', $cnt),
|
||||
'refresh' => $db->sqleval('refresh + %i', $cnt)
|
||||
], 'owner=%i', $userID);
|
||||
|
||||
$date = date('Y_m_d H:i:s');
|
||||
$date2 = substr($date, 0, 10);
|
||||
@@ -1033,42 +1045,6 @@ function increaseRefresh($type = "", $cnt = 1)
|
||||
),
|
||||
FILE_APPEND
|
||||
);
|
||||
|
||||
$proxy_headers = array(
|
||||
'HTTP_VIA',
|
||||
'HTTP_X_FORWARDED_FOR',
|
||||
'HTTP_FORWARDED_FOR',
|
||||
'HTTP_X_FORWARDED',
|
||||
'HTTP_FORWARDED',
|
||||
'HTTP_CLIENT_IP',
|
||||
'HTTP_FORWARDED_FOR_IP',
|
||||
'VIA',
|
||||
'X_FORWARDED_FOR',
|
||||
'FORWARDED_FOR',
|
||||
'X_FORWARDED',
|
||||
'FORWARDED',
|
||||
'CLIENT_IP',
|
||||
'FORWARDED_FOR_IP',
|
||||
'HTTP_PROXY_CONNECTION'
|
||||
);
|
||||
|
||||
$str = "";
|
||||
foreach ($proxy_headers as $x) {
|
||||
if (isset($_SERVER[$x])) $str .= "//{$x}:{$_SERVER[$x]}";
|
||||
}
|
||||
if ($str != "") {
|
||||
file_put_contents(
|
||||
__DIR__ . "/logs/" . UniqueConst::$serverID . "/_{$date2}_ipcheck.txt",
|
||||
sprintf(
|
||||
"%s, %s, %s%s\n",
|
||||
$session->userName,
|
||||
$session->generalName,
|
||||
$_SERVER['REMOTE_ADDR'],
|
||||
$str
|
||||
),
|
||||
FILE_APPEND
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function updateTraffic()
|
||||
@@ -1223,10 +1199,9 @@ function updateOnline()
|
||||
$nationname[$nation['nation']] = $nation['name'];
|
||||
}
|
||||
|
||||
|
||||
//동접수
|
||||
$before5Min = TimeUtil::nowAddMinutes(-5);
|
||||
$onlineUser = $db->query('SELECT no,name,nation FROM general WHERE lastrefresh > %s AND npc < 2', $before5Min);
|
||||
$startTurn = cutTurn($gameStor->turntime, $gameStor->turnterm, false);
|
||||
$onlineUser = $db->query('SELECT no,name,nation FROM general WHERE lastrefresh >= %s AND npc < 2', $startTurn);
|
||||
$onlineNum = count($onlineUser);
|
||||
$onlineNationUsers = Util::arrayGroupBy($onlineUser, 'nation');
|
||||
|
||||
@@ -1745,7 +1720,8 @@ function tryUniqueItemLottery(RandUtil $rng, General $general, string $acquireTy
|
||||
$prob = 1 / ($genCount * $itemTypeCnt / 10 / 4); // 건국시 4개(20%) 등장(200명시 20국 정도 됨)
|
||||
}
|
||||
|
||||
$prob = Util::valueFit($prob, null, 1 / 4); //최대치 감소
|
||||
$prob *= GameConst::$uniqueTrialCoef;
|
||||
$prob = Util::valueFit($prob, null, GameConst::$maxUniqueTrialProb); //최대치 감소
|
||||
$result = false;
|
||||
|
||||
$prob /= sqrt(7);
|
||||
@@ -1805,7 +1781,7 @@ function deleteNation(General $lord, bool $applyDB): array
|
||||
$nationID,
|
||||
$lordID
|
||||
),
|
||||
['npc', 'gold', 'rice', 'experience', 'explevel', 'dedication', 'dedlevel', 'belong', 'aux'],
|
||||
['npc', 'owner', 'gold', 'rice', 'experience', 'explevel', 'dedication', 'dedlevel', 'belong', 'aux'],
|
||||
1
|
||||
);
|
||||
$nationGeneralList[$lordID] = $lord;
|
||||
@@ -1814,7 +1790,7 @@ function deleteNation(General $lord, bool $applyDB): array
|
||||
$nation['aux'] = Json::decode($nation['aux']);
|
||||
$nation['msg'] = $nationStor->nationNotice['msg'] ?? '';
|
||||
$nation['scout_msg'] = $nationStor->scout_msg;
|
||||
$nation['aux'] += $nationStor->max_power;
|
||||
$nation['aux'] += $nationStor->max_power ?? [];
|
||||
$nation['history'] = getNationHistoryLogAll($nationID);
|
||||
|
||||
$josaYi = JosaUtil::pick($nationName, '이');
|
||||
@@ -1823,13 +1799,16 @@ function deleteNation(General $lord, bool $applyDB): array
|
||||
|
||||
// 전 장수 재야로
|
||||
foreach ($nationGeneralList as $general) {
|
||||
$general->setAuxVar(
|
||||
InheritanceKey::max_belong->value,
|
||||
max(
|
||||
$general->getVar('belong'),
|
||||
$general->getAuxVar(InheritanceKey::max_belong->value) ?? 0
|
||||
)
|
||||
);
|
||||
if($general->getNPCType() < 2){
|
||||
$general->setAuxVar(
|
||||
InheritanceKey::max_belong->value,
|
||||
max(
|
||||
$general->getVar('belong'),
|
||||
$general->getAuxVar(InheritanceKey::max_belong->value) ?? 0
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$general->setVar('belong', 0);
|
||||
$general->setVar('troop', 0);
|
||||
$general->setVar('officer_level', 0);
|
||||
|
||||
@@ -1092,9 +1092,8 @@ function checkEmperior()
|
||||
}
|
||||
processSumInheritPointRank();
|
||||
foreach ($allUserGenerals as $genObj) {
|
||||
$inheritPointManager->mergeTotalInheritancePoint($genObj, true);
|
||||
$inheritPointManager->mergeTotalInheritancePoint($genObj);
|
||||
$inheritPointManager->applyInheritanceUser($genObj->getVar('owner'));
|
||||
$inheritPointManager->clearInheritancePoint($genObj);
|
||||
}
|
||||
|
||||
$gameStor->isunited = 2;
|
||||
@@ -1165,7 +1164,7 @@ function checkEmperior()
|
||||
$nation['aux'] = Json::decode($nation['aux']);
|
||||
$nation['msg'] = $nationStor->nationNotice['msg'] ?? '';;
|
||||
$nation['scout_msg'] = $nationStor->scout_msg;
|
||||
$nation['aux'] += $nationStor->max_power;
|
||||
$nation['aux'] += $nationStor->max_power ?? [];
|
||||
$nation['history'] = getNationHistoryLogAll($nation['nation']);
|
||||
|
||||
storeOldGenerals(0, $admin['year'], $admin['month']);
|
||||
@@ -1242,7 +1241,7 @@ function checkEmperior()
|
||||
]);
|
||||
|
||||
$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>"];
|
||||
$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']);
|
||||
|
||||
//연감 월결산
|
||||
|
||||
+11
-10
@@ -93,8 +93,8 @@ if ($session->userGrade < 5 && !$allowReset) {
|
||||
<label for="fiction" class="col-sm-3 col-form-label">NPC 상성</label>
|
||||
<div class="col-sm-9">
|
||||
<div id="fiction" class="btn-group btn-group-toggle" data-bs-toggle="buttons">
|
||||
<input type="radio" id="fiction_0" class="btn-check" name="fiction" value="0" checked><label for="fiction_0" class="btn btn-secondary"> 연의 </label>
|
||||
<input type="radio" id="fiction_1" class="btn-check" name="fiction" value="1"><label for="fiction_1" class="btn btn-secondary"> 가상 </label>
|
||||
<input type="radio" id="fiction_0" class="btn-check" name="fiction" value="0"><label for="fiction_0" class="btn btn-secondary"> 연의 </label>
|
||||
<input type="radio" id="fiction_1" class="btn-check" name="fiction" value="1" checked><label for="fiction_1" class="btn btn-secondary"> 가상 </label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -114,6 +114,7 @@ if ($session->userGrade < 5 && !$allowReset) {
|
||||
<div class="col-sm-9">
|
||||
<div id="block_general_create" class="btn-group btn-group-toggle" data-bs-toggle="buttons">
|
||||
<input type="radio" class="btn-check" id="block_general_create_0" name="block_general_create" value="0" checked><label for="block_general_create_0" class="btn btn-secondary">가능</label>
|
||||
<input type="radio" class="btn-check" id="block_general_create_2" name="block_general_create" value="2"><label for="block_general_create_2" class="btn btn-secondary">장수명무작위</label>
|
||||
<input type="radio" class="btn-check" id="block_general_create_1" name="block_general_create" value="1"><label for="block_general_create_1" class="btn btn-secondary">불가</label>
|
||||
</div>
|
||||
</div>
|
||||
@@ -135,13 +136,13 @@ if ($session->userGrade < 5 && !$allowReset) {
|
||||
<div class="col-sm-9">
|
||||
<div class="input-group">
|
||||
<div class="btn-group btn-group-toggle" data-bs-toggle="buttons">
|
||||
<input type="checkbox" id="autorun_develop" class="autorun_user_chk btn-check" data-key="develop" name="autorun_user[]" value="develop"><label class="btn btn-secondary" for="autorun_develop">내정</label>
|
||||
<input type="checkbox" id="autorun_warp" class="autorun_user_chk btn-check" data-key="warp" name="autorun_user[]" value="warp"><label class="btn btn-secondary" for="autorun_warp">순간이동</label>
|
||||
<input type="checkbox" id="autorun_recruit" class="autorun_user_chk btn-check" data-key="recruit" name="autorun_user[]" value="recruit"><label class="btn btn-secondary" for="autorun_recruit">징병</label>
|
||||
<input type="checkbox" id="autorun_recruit_high" class="autorun_user_chk btn-check" data-key="recruit_high" name="autorun_user[]" value="recruit_high"><label class="btn btn-secondary" for="autorun_recruit_high">모병</label>
|
||||
<input type="checkbox" id="autorun_train" class="autorun_user_chk btn-check" data-key="train" name="autorun_user[]" value="train"><label class="btn btn-secondary" for="autorun_train">훈사</label>
|
||||
<input type="checkbox" id="autorun_battle" class="autorun_user_chk btn-check" data-key="battle" name="autorun_user[]" value="battle"><label class="btn btn-secondary" for="autorun_battle">출병</label>
|
||||
<input type="checkbox" id="autorun_chief" class="autorun_user_chk btn-check" data-key="chief" name="autorun_user[]" value="chief"><label class="btn btn-secondary" for="autorun_chief">기본 사령턴</label>
|
||||
<input type="checkbox" id="autorun_develop" class="autorun_user_chk btn-check" data-key="develop" name="autorun_user[]" value="develop" checked><label class="btn btn-secondary" for="autorun_develop">내정</label>
|
||||
<input type="checkbox" id="autorun_warp" class="autorun_user_chk btn-check" data-key="warp" name="autorun_user[]" value="warp" checked><label class="btn btn-secondary" for="autorun_warp">순간이동</label>
|
||||
<input type="checkbox" id="autorun_recruit" class="autorun_user_chk btn-check" data-key="recruit" name="autorun_user[]" value="recruit" checked><label class="btn btn-secondary" for="autorun_recruit">징병</label>
|
||||
<input type="checkbox" id="autorun_recruit_high" class="autorun_user_chk btn-check" data-key="recruit_high" name="autorun_user[]" value="recruit_high" checked><label class="btn btn-secondary" for="autorun_recruit_high">모병</label>
|
||||
<input type="checkbox" id="autorun_train" class="autorun_user_chk btn-check" data-key="train" name="autorun_user[]" value="train" checked><label class="btn btn-secondary" for="autorun_train">훈사</label>
|
||||
<input type="checkbox" id="autorun_battle" class="autorun_user_chk btn-check" data-key="battle" name="autorun_user[]" value="battle" checked><label class="btn btn-secondary" for="autorun_battle">출병</label>
|
||||
<input type="checkbox" id="autorun_chief" class="autorun_user_chk btn-check" data-key="chief" name="autorun_user[]" value="chief" checked><label class="btn btn-secondary" for="autorun_chief">기본 사령턴</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -163,7 +164,7 @@ if ($session->userGrade < 5 && !$allowReset) {
|
||||
<option value="480">8시간</option>
|
||||
<option value="600">10시간</option>
|
||||
<option value="720">12시간</option>
|
||||
<option value="1440">24시간</option>
|
||||
<option value="1440" selected>24시간</option>
|
||||
<option value="2160">36시간</option>
|
||||
<option value="2880">48시간</option>
|
||||
<option value="3600">60시간</option>
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<?php
|
||||
namespace sammo;
|
||||
|
||||
use sammo\Enums\MessageType;
|
||||
|
||||
include "lib.php";
|
||||
include "func.php";
|
||||
|
||||
@@ -119,7 +121,7 @@ else{
|
||||
}
|
||||
|
||||
$msg = new Message(
|
||||
Message::MSGTYPE_DIPLOMACY,
|
||||
MessageType::diplomacy,
|
||||
$src,
|
||||
$dest,
|
||||
$msgText,
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<?php
|
||||
namespace sammo;
|
||||
|
||||
use sammo\Enums\MessageType;
|
||||
|
||||
include "lib.php";
|
||||
include "func.php";
|
||||
|
||||
@@ -104,7 +106,7 @@ else{
|
||||
}
|
||||
|
||||
$msg = new Message(
|
||||
Message::MSGTYPE_DIPLOMACY,
|
||||
MessageType::diplomacy,
|
||||
$src,
|
||||
$dest,
|
||||
$msgText,
|
||||
@@ -115,7 +117,7 @@ $msg = new Message(
|
||||
$msgID = $msg->send();
|
||||
|
||||
$msg = new Message(
|
||||
Message::MSGTYPE_NATIONAL,
|
||||
MessageType::national,
|
||||
$src,
|
||||
$dest,
|
||||
$msgText,
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<?php
|
||||
namespace sammo;
|
||||
|
||||
use sammo\Enums\MessageType;
|
||||
|
||||
include "lib.php";
|
||||
include "func.php";
|
||||
|
||||
@@ -73,7 +75,7 @@ $db->update('ng_diplomacy', [
|
||||
$msgText = "외교 서신(#{$letterNo})이 회수되었습니다.";
|
||||
|
||||
$msg = new Message(
|
||||
Message::MSGTYPE_DIPLOMACY,
|
||||
MessageType::diplomacy,
|
||||
$src,
|
||||
$dest,
|
||||
$msgText,
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<?php
|
||||
namespace sammo;
|
||||
|
||||
use sammo\Enums\MessageType;
|
||||
|
||||
include "lib.php";
|
||||
include "func.php";
|
||||
|
||||
@@ -176,7 +178,7 @@ else{
|
||||
|
||||
|
||||
$msg = new Message(
|
||||
Message::MSGTYPE_DIPLOMACY,
|
||||
MessageType::diplomacy,
|
||||
$src,
|
||||
$dest,
|
||||
$msgText,
|
||||
|
||||
+1
-1
@@ -109,7 +109,7 @@ $scenario = (int)$_POST['scenario'];
|
||||
$fiction = (int)$_POST['fiction'];
|
||||
$extend = (int)$_POST['extend'];
|
||||
$npcmode = (int)$_POST['npcmode'];
|
||||
$block_general_create = (bool)$_POST['block_general_create'];
|
||||
$block_general_create = (int)$_POST['block_general_create'];
|
||||
$show_img_level = (int)$_POST['show_img_level'];
|
||||
$tournament_trig = !!(int)$_POST['tournament_trig'];
|
||||
$join_mode = $_POST['join_mode'];
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
<?php
|
||||
namespace sammo;
|
||||
|
||||
include('lib.php');
|
||||
include('func.php');
|
||||
|
||||
$session = Session::requireGameLogin([])->setReadOnly();
|
||||
|
||||
if(!Session::getInstance()->generalID){
|
||||
Json::die([
|
||||
"nation"=>[]
|
||||
]);
|
||||
}
|
||||
|
||||
//NOTE: 모든 국가, 모든 장수에 대해서 같은 결과라면 캐싱 가능하지 않을까?
|
||||
|
||||
Json::die([
|
||||
"nation"=>getMailboxList()
|
||||
]);
|
||||
@@ -1,63 +0,0 @@
|
||||
<?php
|
||||
namespace sammo;
|
||||
|
||||
include 'lib.php';
|
||||
include 'func.php';
|
||||
|
||||
WebUtil::requireAJAX();
|
||||
|
||||
//{msgID: 1206, response: true}
|
||||
$session = Session::requireGameLogin([])->setReadOnly();
|
||||
|
||||
|
||||
$generalID = Session::getInstance()->generalID;
|
||||
|
||||
if (!$generalID) {
|
||||
Json::die([
|
||||
'result'=>false,
|
||||
'reason'=>'로그인하지 않음'
|
||||
]);
|
||||
}
|
||||
|
||||
$jsonPost = Json::decode(Util::getPost('data', 'string', '{}'));
|
||||
|
||||
$msgID = Util::toInt($jsonPost['msgID']??null);
|
||||
$msgResponse = $jsonPost['response']??null;
|
||||
|
||||
if ($msgID === null || !is_bool($msgResponse)) {
|
||||
Json::die([
|
||||
'result'=>false,
|
||||
'reason'=>'올바르지 않은 인자'
|
||||
]);
|
||||
}
|
||||
|
||||
$general = DB::db()->queryFirstRow('SELECT `no`, `name`, `nation`, `officer_level`, `npc`, `gold`, `rice`, `troop`, `aux` from `general` where `no` = %i', $generalID);
|
||||
if(!$general){
|
||||
Json::die([
|
||||
'result'=>false,
|
||||
'reason'=>'존재하지 않는 장수'
|
||||
]);
|
||||
}
|
||||
|
||||
$msg = Message::getMessageByID($msgID);
|
||||
if($msg === null){
|
||||
Json::die([
|
||||
'result'=>false,
|
||||
'reason'=>'올바르지 않은 메시지'
|
||||
]);
|
||||
}
|
||||
$reason = 'success';
|
||||
$gameStor = KVStorage::getStorage(DB::db(), 'game_env');
|
||||
$gameStor->cacheAll();
|
||||
if($msgResponse){
|
||||
$result = $msg->agreeMessage($general['no'], $reason);
|
||||
}
|
||||
else{
|
||||
$result = $msg->declineMessage($general['no'], $reason);
|
||||
}
|
||||
|
||||
|
||||
Json::die([
|
||||
'result' => $result!==DiplomaticMessage::INVALID,
|
||||
'reason' => $reason
|
||||
]);
|
||||
@@ -1,74 +0,0 @@
|
||||
<?php
|
||||
namespace sammo;
|
||||
|
||||
include('lib.php');
|
||||
include('func.php');
|
||||
|
||||
WebUtil::requireAJAX();
|
||||
|
||||
$session = Session::requireGameLogin([]);
|
||||
$userID = Session::getUserID();
|
||||
|
||||
$msgID = Util::getPost('msgID', 'int');
|
||||
if($msgID === null){
|
||||
Json::die([
|
||||
'result'=>false,
|
||||
'reason'=>'올바르지 않은 범위 입니다.'
|
||||
]);
|
||||
}
|
||||
|
||||
$lastMsgGet = Json::decode($session->lastMsgGet)??[];
|
||||
$now = new \DateTime();
|
||||
$delayTime = false;
|
||||
if(count($lastMsgGet) >= 10){
|
||||
try{
|
||||
if($lastMsgGet[0] !== 'string'){
|
||||
throw new \Exception('Why not string?');
|
||||
}
|
||||
$first = new \DateTime($lastMsgGet[0]);
|
||||
$diff = $first->diff($now);
|
||||
if($diff->days == 0 && $diff->h > 0 && $diff->i == 0 && $diff->s <= 5){
|
||||
$delayTime = true;
|
||||
}
|
||||
array_shift($lastMsgGet);
|
||||
}
|
||||
catch(\Exception $e){
|
||||
$lastMsgGet = [];
|
||||
}
|
||||
}
|
||||
$lastMsgGet[] = $now;
|
||||
$session->lastMsgGet = Json::encode($lastMsgGet);
|
||||
|
||||
if($delayTime){
|
||||
sleep(1);
|
||||
}
|
||||
$session->setReadOnly();
|
||||
|
||||
list($generalID, $nationID, $generalName) = DB::db()->queryFirstList(
|
||||
'select `no`, `nation`, `name` from `general` where owner = %i',
|
||||
$userID
|
||||
);
|
||||
|
||||
if($nationID === null){
|
||||
Json::die([
|
||||
'result'=>false,
|
||||
'reason'=>'장수가 사망했습니다.'
|
||||
]);
|
||||
}
|
||||
|
||||
$reason = Message::deleteMsg($msgID, $generalID);
|
||||
if($reason === null){
|
||||
$result = [
|
||||
'result'=>true,
|
||||
'reason'=>'success'
|
||||
];
|
||||
}
|
||||
else{
|
||||
$result = [
|
||||
'result'=>false,
|
||||
'reason'=>$reason
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
Json::die($result);
|
||||
@@ -1,118 +0,0 @@
|
||||
<?php
|
||||
namespace sammo;
|
||||
|
||||
include('lib.php');
|
||||
include('func.php');
|
||||
|
||||
$session = Session::requireGameLogin([]);
|
||||
$userID = Session::getUserID();
|
||||
|
||||
$reqTo = Util::getPost('to', 'int');
|
||||
$reqType = Util::getPost('type', 'string');
|
||||
|
||||
if($reqTo === null){
|
||||
Json::die([
|
||||
'result'=>false,
|
||||
'reason'=>'올바르지 않은 범위 입니다.'
|
||||
]);
|
||||
}
|
||||
if($reqType === null || !in_array($reqType, ['private', 'public', 'national', 'diplomacy'])){
|
||||
Json::die([
|
||||
'result'=>false,
|
||||
'reason'=>'올바르지 않은 타입입니다.'
|
||||
]);
|
||||
}
|
||||
|
||||
$lastMsgGet = Json::decode($session->lastMsgGet)??[];
|
||||
$now = new \DateTime();
|
||||
$delayTime = false;
|
||||
if(count($lastMsgGet) >= 10){
|
||||
try{
|
||||
if($lastMsgGet[0] !== 'string'){
|
||||
throw new \Exception('Why not string?');
|
||||
}
|
||||
$first = new \DateTime($lastMsgGet[0]);
|
||||
$diff = $first->diff($now);
|
||||
if($diff->days == 0 && $diff->h > 0 && $diff->i == 0 && $diff->s <= 1){
|
||||
$delayTime = true;
|
||||
}
|
||||
array_shift($lastMsgGet);
|
||||
}
|
||||
catch(\Exception $e){
|
||||
$lastMsgGet = [];
|
||||
}
|
||||
}
|
||||
$lastMsgGet[] = $now;
|
||||
$session->lastMsgGet = Json::encode($lastMsgGet);
|
||||
|
||||
if($delayTime){
|
||||
sleep(1);
|
||||
}
|
||||
$session->setReadOnly();
|
||||
|
||||
$me = DB::db()->queryFirstRow('SELECT `no`,`name`,`nation`,`officer_level`,`con`,`picture`,`imgsvr`,penalty,permission FROM general WHERE `owner`=%i', $userID);
|
||||
|
||||
if($me === null){
|
||||
Json::die([
|
||||
'result'=>false,
|
||||
'reason'=>'장수가 사망했습니다.'
|
||||
]);
|
||||
}
|
||||
|
||||
[$generalID, $nationID, $generalName] = [$me['no'], $me['nation'], $me['name']];
|
||||
$permission = checkSecretPermission($me, false);
|
||||
|
||||
$result = [
|
||||
'private'=>[],
|
||||
'public'=>[],
|
||||
'national'=>[],
|
||||
'diplomacy'=>[],
|
||||
'result'=>true,
|
||||
'keepRecent'=>true,
|
||||
'sequence'=>0,
|
||||
'nationID'=>$nationID,
|
||||
'generalName'=>$generalName,
|
||||
];
|
||||
$result['result'] = true;
|
||||
|
||||
$nextSequence = $reqTo;
|
||||
|
||||
if($reqType == 'private'){
|
||||
$result['private'] = array_map(function(Message $msg) use (&$nextSequence){
|
||||
if($msg->id > $nextSequence){
|
||||
$nextSequence = $msg->id;
|
||||
}
|
||||
return $msg->toArray();
|
||||
}, Message::getMessagesFromMailBoxOld($generalID, Message::MSGTYPE_PRIVATE, $reqTo, 15));
|
||||
}
|
||||
else if($reqType == 'public'){
|
||||
$result['public'] = array_map(function(Message $msg)use (&$nextSequence){
|
||||
if($msg->id > $nextSequence){
|
||||
$nextSequence = $msg->id;
|
||||
}
|
||||
return $msg->toArray();
|
||||
}, Message::getMessagesFromMailBoxOld(Message::MAILBOX_PUBLIC, Message::MSGTYPE_PUBLIC, $reqTo, 15));
|
||||
}
|
||||
else if($reqType == 'national'){
|
||||
$result['national'] = array_map(function(Message $msg)use (&$nextSequence){
|
||||
if($msg->id > $nextSequence){
|
||||
$nextSequence = $msg->id;
|
||||
}
|
||||
return $msg->toArray();
|
||||
}, Message::getMessagesFromMailBoxOld(Message::MAILBOX_NATIONAL + $nationID, Message::MSGTYPE_NATIONAL, $reqTo, 15));
|
||||
}
|
||||
else{
|
||||
$result['diplomacy'] = array_map(function(Message $msg)use (&$nextSequence, $permission){
|
||||
if($msg->id > $nextSequence){
|
||||
$nextSequence = $msg->id;
|
||||
}
|
||||
$values = $msg->toArray();
|
||||
if($msg->dest->nationID != 0 && $permission < 3){
|
||||
$values['text'] = '(외교 메시지입니다)';//TODO: 외교서신이라 읽을 수 없음을 보여줘야함
|
||||
$values['option']['invalid'] = true;
|
||||
}
|
||||
return $values;
|
||||
}, Message::getMessagesFromMailBoxOld(Message::MAILBOX_NATIONAL + $nationID, Message::MSGTYPE_DIPLOMACY, $reqTo, 15));
|
||||
}
|
||||
|
||||
Json::die($result);
|
||||
@@ -1,120 +0,0 @@
|
||||
<?php
|
||||
namespace sammo;
|
||||
|
||||
include('lib.php');
|
||||
include('func.php');
|
||||
|
||||
$session = Session::requireGameLogin([]);
|
||||
$userID = Session::getUserID();
|
||||
|
||||
$reqSequence = Util::getPost('sequence', 'int', -1);
|
||||
|
||||
$lastMsgGet = Json::decode($session->lastMsgGet)??[];
|
||||
$now = new \DateTime();
|
||||
$delayTime = false;
|
||||
if(count($lastMsgGet) >= 10){
|
||||
try{
|
||||
if(!is_string($lastMsgGet[0])){
|
||||
throw new \Exception('Why not string?');
|
||||
}
|
||||
$first = new \DateTime($lastMsgGet[0]);
|
||||
$diff = $first->diff($now);
|
||||
if($diff->days == 0 && $diff->h > 0 && $diff->i == 0 && $diff->s <= 1){
|
||||
$delayTime = true;
|
||||
}
|
||||
array_shift($lastMsgGet);
|
||||
}
|
||||
catch(\Exception $e){
|
||||
$lastMsgGet = [];
|
||||
}
|
||||
}
|
||||
$lastMsgGet[] = TimeUtil::now();
|
||||
$session->lastMsgGet = Json::encode($lastMsgGet);
|
||||
|
||||
if($delayTime){
|
||||
usleep(200);
|
||||
}
|
||||
$session->setReadOnly();
|
||||
|
||||
|
||||
$db = DB::db();
|
||||
$me = $db->queryFirstRow('SELECT `no`,`name`,`nation`,`officer_level`,`con`,`picture`,`imgsvr`,penalty,permission FROM general WHERE `owner`=%i', $userID);
|
||||
|
||||
if($me === null){
|
||||
Json::die([
|
||||
'result'=>false,
|
||||
'reason'=>'장수가 사망했습니다.'
|
||||
]);
|
||||
}
|
||||
|
||||
[$generalID, $nationID, $generalName] = [$me['no'], $me['nation'], $me['name']];
|
||||
$permission = checkSecretPermission($me, false);
|
||||
|
||||
$result = [];
|
||||
$result['result'] = true;
|
||||
$result['keepRecent'] = false;
|
||||
$nextSequence = $reqSequence;
|
||||
$minSequence = $reqSequence;
|
||||
$lastType = null;
|
||||
|
||||
$result['private'] = array_map(function(Message $msg) use (&$nextSequence, &$minSequence, &$lastType){
|
||||
if($msg->id > $nextSequence){
|
||||
$nextSequence = $msg->id;
|
||||
}
|
||||
if($msg->id <= $minSequence){
|
||||
$minSequence = $msg->id;
|
||||
$lastType = 'private';
|
||||
}
|
||||
return $msg->toArray();
|
||||
}, Message::getMessagesFromMailBox($generalID, Message::MSGTYPE_PRIVATE, 15, $reqSequence));
|
||||
|
||||
$result['public'] = array_map(function(Message $msg)use (&$nextSequence, &$minSequence, &$lastType){
|
||||
if($msg->id > $nextSequence){
|
||||
$nextSequence = $msg->id;
|
||||
}
|
||||
if($msg->id <= $minSequence){
|
||||
$minSequence = $msg->id;
|
||||
$lastType = 'public';
|
||||
}
|
||||
return $msg->toArray();
|
||||
}, Message::getMessagesFromMailBox(Message::MAILBOX_PUBLIC, Message::MSGTYPE_PUBLIC, 15, $reqSequence));
|
||||
|
||||
$result['national'] = array_map(function(Message $msg)use (&$nextSequence, &$minSequence, &$lastType){
|
||||
if($msg->id > $nextSequence){
|
||||
$nextSequence = $msg->id;
|
||||
}
|
||||
if($msg->id <= $minSequence){
|
||||
$minSequence = $msg->id;
|
||||
$lastType = 'national';
|
||||
}
|
||||
return $msg->toArray();
|
||||
}, Message::getMessagesFromMailBox(Message::MAILBOX_NATIONAL + $nationID, Message::MSGTYPE_NATIONAL, 15, $reqSequence));
|
||||
|
||||
$result['diplomacy']= array_map(function(Message $msg)use (&$nextSequence, &$minSequence, &$lastType, $permission){
|
||||
if($msg->id > $nextSequence){
|
||||
$nextSequence = $msg->id;
|
||||
}
|
||||
if($msg->id <= $minSequence){
|
||||
$minSequence = $msg->id;
|
||||
$lastType = 'diplomacy';
|
||||
}
|
||||
$values = $msg->toArray();
|
||||
if($msg->dest->nationID != 0 && $permission < 3){
|
||||
$values['text'] = '(외교 메시지입니다)';//TODO: 외교서신이라 읽을 수 없음을 보여줘야함
|
||||
$values['option']['invalid'] = true;
|
||||
}
|
||||
return $values;
|
||||
}, Message::getMessagesFromMailBox(Message::MAILBOX_NATIONAL + $nationID, Message::MSGTYPE_DIPLOMACY, 15, $reqSequence));
|
||||
|
||||
if($lastType !== null){
|
||||
array_pop($result[$lastType]);
|
||||
$result['keepRecent'] = true;
|
||||
}
|
||||
else if($reqSequence <= 0){
|
||||
$result['keepRecent'] = true;
|
||||
}
|
||||
|
||||
$result['sequence'] = $nextSequence;
|
||||
$result['nationID'] = $nationID;
|
||||
$result['generalName'] = $generalName;
|
||||
Json::die($result);
|
||||
@@ -1,206 +0,0 @@
|
||||
<?php
|
||||
namespace sammo;
|
||||
|
||||
include 'lib.php';
|
||||
include 'func.php';
|
||||
|
||||
WebUtil::requireAJAX();
|
||||
|
||||
$post = Json::decode(Util::getPost('data', 'string', '{}'));
|
||||
'@phan-var mixed[] $post';
|
||||
|
||||
$v = new Validator($post);
|
||||
$v->rule('required', ['mailbox','text']);
|
||||
$v->rule('integer', 'mailbox');
|
||||
$v->rule('lengthMin', 'text', 1);
|
||||
|
||||
if(!$v->validate()){
|
||||
Json::die([
|
||||
'result'=>false,
|
||||
'reason'=>$v->errorStr(),
|
||||
'msgID'=>null
|
||||
]);
|
||||
}
|
||||
|
||||
$mailbox = (int)$post['mailbox'];
|
||||
$text = trim(StringUtil::cutStringForWidth($post['text'], 199, ''));
|
||||
|
||||
$session = Session::requireGameLogin([
|
||||
'msgID'=>null
|
||||
]);
|
||||
$userID = Session::getUserID();
|
||||
//NOTE: 전송 메시지 시간 계산을 위해 Session을 쓰기 가능 상태로 열어둠.
|
||||
|
||||
increaseRefresh('서신전달', 1);
|
||||
|
||||
if(getBlockLevel() == 1 || getBlockLevel() == 3) {
|
||||
Json::die([
|
||||
'result' => false,
|
||||
'reason' => '차단되었습니다.',
|
||||
'msgID'=>null
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 메시지 전송 코드.
|
||||
*
|
||||
* TODO: 장기적으로 ajax는 한곳에 모을 필요가 있을 듯.
|
||||
*/
|
||||
|
||||
$now = new \DateTime();
|
||||
$unlimited = new \DateTime('9999-12-31');
|
||||
|
||||
$db = DB::db();
|
||||
$me = $db->queryFirstRow('SELECT `no`,`name`,`nation`,`officer_level`,`con`,`picture`,`imgsvr`,penalty,permission,belong FROM general WHERE `owner`=%i', $userID);
|
||||
|
||||
if(!$me){
|
||||
$session->logoutGame();
|
||||
Json::die([
|
||||
'result' => false,
|
||||
'reason' => '로그인되지 않았습니다.',
|
||||
'msgID' => null
|
||||
]);
|
||||
}
|
||||
|
||||
$con = checkLimit($me['con']);
|
||||
if($con >= 2) {
|
||||
Json::die([
|
||||
'result' => false,
|
||||
'reason' => '접속 제한입니다.',
|
||||
'msgID' => null
|
||||
]);
|
||||
}
|
||||
|
||||
$me['icon'] = GetImageURL($me['imgsvr'], $me['picture']);
|
||||
$permission = checkSecretPermission($me);
|
||||
$srcNation = getNationStaticInfo($me['nation']);
|
||||
|
||||
$src = new MessageTarget($me['no'], $me['name'], $srcNation['nation'], $srcNation['name'], $srcNation['color'], $me['icon']);
|
||||
|
||||
// 전체 메세지
|
||||
if($mailbox == Message::MAILBOX_PUBLIC) {
|
||||
$msg = new Message(
|
||||
Message::MSGTYPE_PUBLIC,
|
||||
$src,
|
||||
$src,
|
||||
$text,
|
||||
$now,
|
||||
$unlimited,
|
||||
[]
|
||||
);
|
||||
$msgID = $msg->send();
|
||||
Json::die([
|
||||
'result' => true,
|
||||
'reason' => 'SUCCESS',
|
||||
'msgID' => $msgID
|
||||
]);
|
||||
|
||||
|
||||
}
|
||||
|
||||
// 국가 메세지
|
||||
if($mailbox >= Message::MAILBOX_NATIONAL) {
|
||||
|
||||
if($permission < 4){
|
||||
$destNationID = $me['nation'];
|
||||
}
|
||||
else{
|
||||
$destNationID = $mailbox - Message::MAILBOX_NATIONAL;
|
||||
}
|
||||
|
||||
if($destNationID == $me['nation']){
|
||||
$msgType = Message::MSGTYPE_NATIONAL;
|
||||
}
|
||||
else{
|
||||
$msgType = Message::MSGTYPE_DIPLOMACY;
|
||||
}
|
||||
|
||||
$destNation = getNationStaticInfo($destNationID);
|
||||
|
||||
$dest = new MessageTarget(0, '', $destNation['nation'], $destNation['name'], $destNation['color']);
|
||||
|
||||
$msg = new Message(
|
||||
$msgType,
|
||||
$src,
|
||||
$dest,
|
||||
$text,
|
||||
$now,
|
||||
$unlimited,
|
||||
[]
|
||||
);
|
||||
$msgID = $msg->send();
|
||||
Json::die([
|
||||
'result' => true,
|
||||
'reason' => 'SUCCESS',
|
||||
'msgID' => $msgID
|
||||
]);
|
||||
}
|
||||
|
||||
// 개인 메세지
|
||||
if($mailbox > 0) {
|
||||
$lastMsg = new \DateTime($session->lastMsg??'0000-00-00');
|
||||
|
||||
$msg_interval = $now->getTimestamp() - $lastMsg->getTimestamp();
|
||||
//NOTE: 여기서 유저 레벨을 구별할 코드가 필요할까?
|
||||
if($msg_interval < 2){
|
||||
Json::die([
|
||||
'result' => false,
|
||||
'reason' => '개인메세지는 2초당 1건만 보낼 수 있습니다!',
|
||||
'msgID' => null
|
||||
]);
|
||||
}
|
||||
|
||||
$session->lastMsg = $now->format('Y-m-d H:i:s');
|
||||
|
||||
$destUser = $db->queryFirstRow('SELECT `no`,`name`,`nation`,`officer_level`,`con`,`picture`,`imgsvr`,permission,penalty FROM general WHERE `no`=%i',$mailbox);
|
||||
|
||||
if(!$destUser){
|
||||
Json::die([
|
||||
'result' => false,
|
||||
'reason' => '존재하지 않는 유저입니다.',
|
||||
'msgID' => null
|
||||
]);
|
||||
}
|
||||
|
||||
$destPermission = checkSecretPermission($destUser, false);
|
||||
if($permission == 4 && $destPermission == 4 && $destUser['nation'] != $me['nation']){
|
||||
Json::die([
|
||||
'result' => false,
|
||||
'reason' => '외교권자끼리는 메시지를 보낼 수 없습니다.',
|
||||
'msgID' => null
|
||||
]);
|
||||
}
|
||||
|
||||
$destNation = getNationStaticInfo($destUser['nation']);
|
||||
|
||||
$dest = new MessageTarget(
|
||||
$destUser['no'],
|
||||
$destUser['name'],
|
||||
$destNation['nation'],
|
||||
$destNation['name'],
|
||||
$destNation['color'],
|
||||
GetImageURL($destUser['imgsvr'], $destUser['picture'])
|
||||
);
|
||||
|
||||
$msg = new Message(
|
||||
Message::MSGTYPE_PRIVATE,
|
||||
$src,
|
||||
$dest,
|
||||
$text,
|
||||
$now,
|
||||
$unlimited,
|
||||
[]
|
||||
);
|
||||
$msgID = $msg->send();
|
||||
Json::die([
|
||||
'result' => true,
|
||||
'reason' => 'SUCCESS',
|
||||
'msgID' => $msgID
|
||||
]);
|
||||
}
|
||||
|
||||
Json::die([
|
||||
'result' => false,
|
||||
'reason' => '알 수 없는 에러',
|
||||
'msgID' => null
|
||||
]);
|
||||
@@ -1,6 +1,8 @@
|
||||
<?php
|
||||
namespace sammo;
|
||||
|
||||
use sammo\Enums\MessageType;
|
||||
|
||||
include "lib.php";
|
||||
include "func.php";
|
||||
|
||||
@@ -226,8 +228,8 @@ function do추방(General $general, int $myOfficerLevel):?string{
|
||||
}
|
||||
else{
|
||||
$betrayCnt = $general->getVar('betray');
|
||||
$general->addExperience(-$general->getVar('experience')*0.1*$betrayCnt);
|
||||
$general->addDedication(-$general->getVar('dedication')*0.1*$betrayCnt);
|
||||
$general->addExperience(-$general->getVar('experience')*0.15*$betrayCnt);
|
||||
$general->addDedication(-$general->getVar('dedication')*0.15*$betrayCnt);
|
||||
$general->increaseVarWithLimit('betray', 1, null, GameConst::$maxBetrayCnt);
|
||||
}
|
||||
|
||||
@@ -268,7 +270,7 @@ function do추방(General $general, int $myOfficerLevel):?string{
|
||||
GetImageURL($general->getVar('imgsvr'), $general->getVar('picture'))
|
||||
);
|
||||
$msg = new Message(
|
||||
Message::MSGTYPE_PUBLIC,
|
||||
MessageType::public,
|
||||
$src,
|
||||
$src,
|
||||
$str,
|
||||
|
||||
@@ -56,7 +56,7 @@ if(file_exists(__DIR__.'/.htaccess')){
|
||||
'scenarioName'=>$options['scenarioName'],
|
||||
'turnterm'=>$options['turnterm'],
|
||||
'fictionMode'=>($options['fiction']?'가상':'사실'),
|
||||
'block_general_create'=>(!!$options['block_general_create']),
|
||||
'block_general_create'=>Util::toInt($options['block_general_create']),
|
||||
'npcMode'=>([0=>'불가',1=>'가능',2=>'선택 생성'][$options['npcmode']]),
|
||||
'openDatetime'=>$reserved['date'],
|
||||
'starttime'=>$options['starttime'],
|
||||
@@ -90,7 +90,7 @@ $admin['scenario'] = $admin['scenario_text'];
|
||||
$admin['userCnt'] = $genCnt;
|
||||
$admin['npcCnt'] = $npcCnt;
|
||||
$admin['nationCnt'] = $nationCnt;
|
||||
$admin['block_general_create'] = !!$admin['block_general_create'];
|
||||
$admin['block_general_create'] = $admin['block_general_create'];
|
||||
$admin['npcMode'] = [0=>'불가',1=>'가능',2=>'선택 생성'][$admin['npcMode']];
|
||||
$admin['fictionMode'] = $admin['fiction']?'가상':'사실';
|
||||
|
||||
|
||||
@@ -84,6 +84,7 @@ $rawDefenderList = $query['defenderGenerals'];
|
||||
$rawDefenderCity = $query['defenderCity'];
|
||||
$rawDefenderNation = $query['defenderNation'];
|
||||
|
||||
$warSeed = $query['seed'] ?? '';
|
||||
|
||||
$generalCheck = [
|
||||
'required'=>[
|
||||
@@ -132,6 +133,19 @@ $generalCheck = [
|
||||
['weapon', array_merge(array_keys(GameConst::$allItems['weapon']), ['None'])],
|
||||
['book', array_merge(array_keys(GameConst::$allItems['book']), ['None'])],
|
||||
['item', array_merge(array_keys(GameConst::$allItems['item']), ['None'])],
|
||||
],
|
||||
'array'=>['inheritBuff'],
|
||||
];
|
||||
|
||||
$inheritBuffCheck = [
|
||||
'between'=>[
|
||||
[TriggerInheritBuff::WAR_AVOID_RATIO, [0, 5]],
|
||||
[TriggerInheritBuff::WAR_CRITICAL_RATIO, [0, 5]],
|
||||
[TriggerInheritBuff::WAR_MAGIC_TRIAL_PROB, [0, 5]],
|
||||
|
||||
[TriggerInheritBuff::OPPOSE_WAR_AVOID_RATIO, [0, 5]],
|
||||
[TriggerInheritBuff::OPPOSE_WAR_CRITICAL_RATIO, [0, 5]],
|
||||
[TriggerInheritBuff::OPPOSE_WAR_MAGIC_TRIAL_PROB, [0, 5]],
|
||||
]
|
||||
];
|
||||
|
||||
@@ -143,6 +157,19 @@ if(!$v->validate()){
|
||||
'reason'=>'[출병자]'.$v->errorStr()
|
||||
]);
|
||||
}
|
||||
$rawAttacker['aux'] = [];
|
||||
if(key_exists('inheritBuff', $rawAttacker)){
|
||||
$v = new Validator($rawAttacker['inheritBuff']);
|
||||
$v->rules($inheritBuffCheck);
|
||||
if(!$v->validate()){
|
||||
Json::die([
|
||||
'result'=>false,
|
||||
'reason'=>'[출병자]'.$v->errorStr()
|
||||
]);
|
||||
}
|
||||
$rawAttacker['aux']['inheritBuff'] = $rawAttacker['inheritBuff'];
|
||||
}
|
||||
$rawAttacker['aux'] = Json::encode($rawAttacker['aux']);
|
||||
$rawAttacker['owner'] = 0;
|
||||
|
||||
$defenderList = [];
|
||||
@@ -156,6 +183,20 @@ foreach($rawDefenderList as $idx=>$rawDefenderGeneral){
|
||||
'reason'=>"[수비자{$idx}]".$v->errorStr()
|
||||
]);
|
||||
}
|
||||
$rawDefenderGeneral['aux'] = [];
|
||||
if(key_exists('inheritBuff', $rawDefenderGeneral)){
|
||||
$v = new Validator($rawDefenderGeneral['inheritBuff']);
|
||||
$v->rules($inheritBuffCheck);
|
||||
if(!$v->validate()){
|
||||
$idx+=1;
|
||||
Json::die([
|
||||
'result'=>false,
|
||||
'reason'=>"[수비자{$idx}]".$v->errorStr()
|
||||
]);
|
||||
}
|
||||
$rawDefenderGeneral['aux']['inheritBuff'] = $rawDefenderGeneral['inheritBuff'];
|
||||
}
|
||||
$rawDefenderGeneral['aux'] = Json::encode($rawDefenderGeneral['aux']);
|
||||
$rawDefenderGeneral['owner'] = 0;
|
||||
|
||||
$defenderList[] = new General($rawDefenderGeneral, extractRankVar($rawDefenderGeneral), $rawDefenderCity, $rawAttackerNation, $year, $month, true);
|
||||
@@ -297,10 +338,13 @@ function extractRankVar(array $rawVal):Map{
|
||||
function simulateBattle(
|
||||
$rawAttacker, $rawAttackerCity, $rawAttackerNation,
|
||||
$rawDefenderList, $rawDefenderCity, $rawDefenderNation,
|
||||
$startYear, $year, $month
|
||||
$startYear, $year, $month, $warSeed
|
||||
){
|
||||
|
||||
$warSeed = bin2hex(random_bytes(16));
|
||||
if(!$warSeed){
|
||||
$warSeed = bin2hex(random_bytes(16));
|
||||
}
|
||||
|
||||
$warRng = new RandUtil(new LiteHashDRBG($warSeed));
|
||||
|
||||
$attacker = new WarUnitGeneral(
|
||||
@@ -400,12 +444,16 @@ $avgWar = 0;
|
||||
$attackerActivatedSkills = [];
|
||||
$defendersActivatedSkills = [];
|
||||
|
||||
if($warSeed){
|
||||
$repeatCnt = 1;
|
||||
}
|
||||
|
||||
foreach(Util::range($repeatCnt) as $repeatIdx){
|
||||
/** @var WarUnit $attacker */
|
||||
[$attacker, $city, $battleResult, $conquerCity, $attackerRice, $defenderRice] = simulateBattle(
|
||||
$rawAttacker, $rawAttackerCity, $rawAttackerNation,
|
||||
$rawDefenderList, $rawDefenderCity, $rawDefenderNation,
|
||||
$startYear, $year, $month
|
||||
$startYear, $year, $month, $warSeed
|
||||
);
|
||||
$lastWarLog = Util::mapWithKey(function($key, $values){
|
||||
return ConvertLog(join('<br>', $values));
|
||||
|
||||
-146
@@ -1,146 +0,0 @@
|
||||
<?php
|
||||
namespace sammo;
|
||||
|
||||
include "lib.php";
|
||||
include "func.php";
|
||||
|
||||
WebUtil::requireAJAX();
|
||||
// $btn, $name, $troop
|
||||
$action = Util::getPost('action');
|
||||
$name = Util::getPost('name');
|
||||
$gen = Util::getPost('gen', 'int');
|
||||
$troop = Util::getPost('troop', 'int');
|
||||
|
||||
//로그인 검사
|
||||
$session = Session::requireGameLogin([])->setReadOnly();
|
||||
$userID = $session::getUserID();
|
||||
|
||||
increaseRefresh("부대명령", 0);
|
||||
|
||||
$db = DB::db();
|
||||
|
||||
$me = $db->queryFirstRow('SELECT `no`, name, nation, troop FROM general WHERE `owner`=%i', $userID);
|
||||
$generalID = $me['no'];
|
||||
$nationID = $me['nation'];
|
||||
|
||||
if($action == '부대창설'){
|
||||
$name = StringUtil::neutralize($name);
|
||||
if(!$name){
|
||||
Json::die([
|
||||
'result'=>false,
|
||||
'reason'=>'부대 이름이 없습니다.'
|
||||
]);
|
||||
}
|
||||
if($me['troop'] != 0){
|
||||
Json::die([
|
||||
'result'=>false,
|
||||
'reason'=>'이미 부대에 가입해있습니다.'
|
||||
]);
|
||||
}
|
||||
$db->insert('troop',[
|
||||
'troop_leader'=>$generalID,
|
||||
'name'=>$name,
|
||||
'nation'=>$nationID,
|
||||
]);
|
||||
|
||||
$db->update('general', [
|
||||
'troop'=>$generalID,
|
||||
], 'no=%i',$generalID);
|
||||
|
||||
Json::die([
|
||||
'result'=>true,
|
||||
'reason'=>'success'
|
||||
]);
|
||||
}
|
||||
|
||||
if($action == '부대추방'){
|
||||
if (!$gen){
|
||||
Json::die([
|
||||
'result'=>false,
|
||||
'reason'=>'장수를 지정해야 합니다.'
|
||||
]);
|
||||
}
|
||||
|
||||
$db->update('general', [
|
||||
'troop'=>0
|
||||
], 'no=%i AND troop = %i', $gen, $generalID);
|
||||
|
||||
if($db->affectedRows() == 0){
|
||||
Json::die([
|
||||
'result'=>false,
|
||||
'reason'=>'부대장이 아니거나, 장수를 잘못 지정했습니다.'
|
||||
]);
|
||||
}
|
||||
|
||||
Json::die([
|
||||
'result'=>true,
|
||||
'reason'=>'success'
|
||||
]);
|
||||
}
|
||||
|
||||
if ($action == '부대가입') {
|
||||
if(!$troop){
|
||||
Json::die([
|
||||
'result'=>false,
|
||||
'reason'=>'부대를 지정해야 합니다.'
|
||||
]);
|
||||
}
|
||||
|
||||
if($me['troop'] === $generalID){
|
||||
Json::die([
|
||||
'result'=>false,
|
||||
'reason'=>'부대장입니다.'
|
||||
]);
|
||||
}
|
||||
|
||||
$troopExists = $db->queryFirstField('SELECT `troop_leader` FROM `troop` WHERE `troop_leader` = %i AND `nation` = %i', $troop, $nationID);
|
||||
|
||||
if (!$troopExists) {
|
||||
Json::die([
|
||||
'result'=>false,
|
||||
'reason'=>'올바른 부대장이 아닙니다.'
|
||||
]);
|
||||
}
|
||||
|
||||
$db->update('general', [
|
||||
'troop'=>$troop
|
||||
], 'no=%i', $generalID);
|
||||
|
||||
Json::die([
|
||||
'result'=>true,
|
||||
'reason'=>'success'
|
||||
]);
|
||||
}
|
||||
|
||||
if($action == "부대탈퇴") {
|
||||
|
||||
if($me['troop'] == 0){
|
||||
Json::die([
|
||||
'result'=>false,
|
||||
'reason'=>'부대에 속해있지 않습니다.'
|
||||
]);
|
||||
}
|
||||
|
||||
//부대장일 경우
|
||||
if($me['troop'] === $generalID){
|
||||
$db->update('general', [
|
||||
'troop'=>0
|
||||
], 'troop=%i',$generalID);
|
||||
$db->delete('troop', 'troop_leader=%i', $generalID);
|
||||
}
|
||||
else{
|
||||
$db->update('general', [
|
||||
'troop'=>0
|
||||
], 'no=%i', $generalID);
|
||||
}
|
||||
|
||||
Json::die([
|
||||
'result'=>true,
|
||||
'reason'=>'success'
|
||||
]);
|
||||
}
|
||||
|
||||
Json::die([
|
||||
'result'=>false,
|
||||
'reason'=>'올바르지 않은 명령입니다.'
|
||||
]);
|
||||
+2
-2
@@ -63,8 +63,8 @@ function prepareDir(string $dirPath, bool $forceCreate=true):bool{
|
||||
if(!unlink($dirPath)){
|
||||
return false;
|
||||
}
|
||||
return mkdir($dirPath);
|
||||
return mkdir($dirPath, 0775);
|
||||
}
|
||||
|
||||
return mkdir($dirPath, 0777, true);
|
||||
return mkdir($dirPath, 0775, true);
|
||||
}
|
||||
@@ -4,7 +4,7 @@ namespace sammo\API\General;
|
||||
|
||||
use sammo\DB;
|
||||
use sammo\DummyGeneral;
|
||||
|
||||
use sammo\GameConst;
|
||||
use sammo\Session;
|
||||
use sammo\General;
|
||||
use sammo\JosaUtil;
|
||||
@@ -54,7 +54,7 @@ class DieOnPrestart extends \sammo\BaseAPI
|
||||
}
|
||||
|
||||
//서버 가오픈시 할 수 있는 행동
|
||||
$targetTime = addTurn($general['lastrefresh'], $gameStor->turnterm, 2);
|
||||
$targetTime = addTurn($general['lastrefresh'], $gameStor->turnterm, GameConst::$minTurnDieOnPrestart);
|
||||
if ($targetTime > TimeUtil::now()) {
|
||||
$targetTimeShort = substr($targetTime, 0, 19);
|
||||
return "아직 삭제할 수 없습니다. {$targetTimeShort} 부터 가능합니다.";
|
||||
@@ -67,7 +67,7 @@ class DieOnPrestart extends \sammo\BaseAPI
|
||||
|
||||
$generalName = $generalObj->getName();
|
||||
$josaYi = JosaUtil::pick($generalName, '이');
|
||||
$generalObj->kill($db, true, "<Y>{$generalName}</>{$josaYi} 이 홀연히 모습을 <R>감추었습니다</>");
|
||||
$generalObj->kill($db, true, "<Y>{$generalName}</>{$josaYi} 홀연히 모습을 <R>감추었습니다</>");
|
||||
|
||||
$session->logoutGame();
|
||||
return null;
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
|
||||
namespace sammo\API\General;
|
||||
|
||||
use Ds\Set;
|
||||
use sammo\ActionLogger;
|
||||
use sammo\Auction;
|
||||
use sammo\CityConst;
|
||||
use sammo\DB;
|
||||
use sammo\Enums\RankColumn;
|
||||
@@ -84,6 +86,40 @@ class Join extends \sammo\BaseAPI
|
||||
return static::REQ_LOGIN | static::REQ_READ_ONLY;
|
||||
}
|
||||
|
||||
public function calcRestInheritPoint(int $userID): int
|
||||
{
|
||||
$db = DB::db();
|
||||
|
||||
if (Util::toInt(UniqueConst::$seasonIdx) < 1) {
|
||||
//이벤트 시즌은 카운트하지 않음
|
||||
return 0;
|
||||
}
|
||||
|
||||
$gameID = UniqueConst::$serverID;
|
||||
$alreadyJoined = $db->queryFirstField('SELECT count(*) FROM `storage` WHERE `namespace` = %s AND `key` LIKE %s', 'inheritance_result', "{$gameID}_{$userID}_%");
|
||||
if ($alreadyJoined) {
|
||||
//이미 받았음
|
||||
return 0;
|
||||
}
|
||||
|
||||
$targetBonusPointCnt = 0;
|
||||
//정상적으로 끝난 깃수만 제공
|
||||
$oldGames = $db->queryFirstColumn('SELECT server_id FROM ng_games WHERE `winner_nation` IS NOT NULL AND `season` >= 1 AND `server_id` != %s ORDER BY `date` DESC LIMIT 8', $gameID);
|
||||
|
||||
if(!$oldGames){
|
||||
return 0;
|
||||
}
|
||||
//이전에 장수를 생성한 적이 있는지
|
||||
$oldGamesCnt = new Set($db->queryFirstColumn('SELECT `server_id` FROM ng_old_generals WHERE server_id IN %ls AND `owner` = %i GROUP BY `server_id`', $oldGames, $userID));
|
||||
foreach ($oldGames as $oldGameID) {
|
||||
if($oldGamesCnt->contains($oldGameID)) {
|
||||
break;
|
||||
}
|
||||
$targetBonusPointCnt += 1;
|
||||
}
|
||||
return $targetBonusPointCnt;
|
||||
}
|
||||
|
||||
public function launch(Session $session, ?\DateTimeInterface $modifiedSince, ?string $reqEtag)
|
||||
{
|
||||
$userID = $session->userID;
|
||||
@@ -105,7 +141,7 @@ class Join extends \sammo\BaseAPI
|
||||
$inheritCity = $this->args['inheritCity'] ?? null;
|
||||
$inheritBonusStat = $this->args['inheritBonusStat'] ?? null;
|
||||
|
||||
if($inheritTurntime !== null && $inheritCity !== null){
|
||||
if ($inheritTurntime !== null && $inheritCity !== null) {
|
||||
return '턴과 도시를 동시에 지정할 수 없습니다.';
|
||||
}
|
||||
|
||||
@@ -119,9 +155,16 @@ class Join extends \sammo\BaseAPI
|
||||
|
||||
$db = DB::db();
|
||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||
$gameStor->cacheValues(['year', 'month', 'maxgeneral', 'scenario', 'show_img_level', 'turnterm', 'turntime', 'genius', 'npcmode']);
|
||||
$gameStor->cacheValues(['year', 'month', 'maxgeneral', 'scenario', 'show_img_level', 'block_general_create', 'turnterm', 'turntime', 'genius', 'npcmode']);
|
||||
########## 동일 정보 존재여부 확인. ##########
|
||||
|
||||
$block_general_create = $gameStor->getValue('block_general_create');
|
||||
if($block_general_create & 1){
|
||||
return '장수 직접 생성이 불가능한 모드입니다.';
|
||||
}
|
||||
|
||||
$blockCustomGeneralName = $gameStor->getValue('block_general_create') & 2;
|
||||
|
||||
$gencount = $db->queryFirstField('SELECT count(`no`) FROM general WHERE npc<2');
|
||||
$oldGeneral = $db->queryFirstField('SELECT `no` FROM general WHERE `owner`=%i', $userID);
|
||||
$oldName = $db->queryFirstField('SELECT `no` FROM general WHERE `name`=%s', $name);
|
||||
@@ -305,7 +348,7 @@ class Join extends \sammo\BaseAPI
|
||||
if ($inheritTurntime !== null) {
|
||||
$inheritTurntime = $inheritTurntime % ($admin['turnterm'] * 60);
|
||||
|
||||
$userLogger->push(sprintf("턴 시간 %02d:%02d 로 지정", intdiv($inheritTurntime, 60), $inheritTurntime%60), "inheritPoint");
|
||||
$userLogger->push(sprintf("턴 시간 %02d:%02d 로 지정", intdiv($inheritTurntime, 60), $inheritTurntime % 60), "inheritPoint");
|
||||
|
||||
$inheritTurntime += $rng->nextRangeInt(0, 999999) / 1000000;
|
||||
$turntime = new \DateTimeImmutable(cutTurn($admin['turntime'], $admin['turnterm']));
|
||||
@@ -337,6 +380,15 @@ class Join extends \sammo\BaseAPI
|
||||
//상성 랜덤
|
||||
$affinity = $rng->nextRangeInt(1, 150);
|
||||
|
||||
$betray = 0;
|
||||
if ($relYear >= 4) {
|
||||
$betray += 2;
|
||||
}
|
||||
|
||||
if($blockCustomGeneralName){
|
||||
$name = bin2hex(random_bytes(5));
|
||||
}
|
||||
|
||||
########## 회원정보 테이블에 입력값을 등록한다. ##########
|
||||
$db->insert('general', [
|
||||
'owner' => $userID,
|
||||
@@ -365,6 +417,7 @@ class Join extends \sammo\BaseAPI
|
||||
'lastrefresh' => $now,
|
||||
'crewtype' => GameUnitConst::DEFAULT_CREWTYPE,
|
||||
'makelimit' => 0,
|
||||
'betray' => $betray,
|
||||
'age' => $age,
|
||||
'startage' => $age,
|
||||
'personal' => $character,
|
||||
@@ -374,6 +427,15 @@ class Join extends \sammo\BaseAPI
|
||||
'special2' => $special2
|
||||
]);
|
||||
$generalID = $db->insertId();
|
||||
|
||||
if($blockCustomGeneralName){
|
||||
//XXX: 클래스가 이게 맞나?
|
||||
$name = Auction::genObfuscatedName($generalID);
|
||||
$db->update('general', [
|
||||
'name' => $name
|
||||
], 'no=%i', $generalID);
|
||||
}
|
||||
|
||||
$turnRows = [];
|
||||
foreach (Util::range(GameConst::$maxTurn) as $turnIdx) {
|
||||
$turnRows[] = [
|
||||
@@ -402,19 +464,25 @@ class Join extends \sammo\BaseAPI
|
||||
if ($inheritRequiredPoint > 0) {
|
||||
$userLogger->push("장수 생성으로 포인트 {$inheritRequiredPoint} 소모", "inheritPoint");
|
||||
$inheritStor = KVStorage::getStorage(DB::db(), "inheritance_{$userID}");
|
||||
$inheritStor->setValue('previous', [$inheritTotalPoint - $inheritRequiredPoint, null]);
|
||||
$inheritTotalPoint -= $inheritRequiredPoint;
|
||||
$inheritStor->setValue('previous', [$inheritTotalPoint, null]);
|
||||
$userLogger->flush();
|
||||
$db->update('rank_data', [
|
||||
'value'=>$db->sqleval('value + %i', $inheritRequiredPoint)
|
||||
'value' => $db->sqleval('value + %i', $inheritRequiredPoint)
|
||||
], 'general_id = %i AND type = %s', $generalID, RankColumn::inherit_point_spent_dynamic->value);
|
||||
}
|
||||
|
||||
$me = [
|
||||
'no' => $generalID
|
||||
];
|
||||
|
||||
$log = [];
|
||||
$mylog = [];
|
||||
$restInheritPoint = $this->calcRestInheritPoint($userID) * 500;
|
||||
if($restInheritPoint > 0){
|
||||
$userLogger->push("신규/복귀 생성으로 포인트 {$restInheritPoint} 지급", "inheritPoint");
|
||||
$inheritStor = KVStorage::getStorage(DB::db(), "inheritance_{$userID}");
|
||||
$inheritTotalPoint += $restInheritPoint;
|
||||
$inheritStor->setValue('previous', [$inheritTotalPoint, null]);
|
||||
$userLogger->flush();
|
||||
}
|
||||
|
||||
|
||||
|
||||
$logger = new ActionLogger($generalID, 0, $gameStor->year, $gameStor->month);
|
||||
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace sammo\API\Message;
|
||||
|
||||
use sammo\Session;
|
||||
use DateTimeInterface;
|
||||
use sammo\DB;
|
||||
use sammo\DiplomaticMessage;
|
||||
use sammo\KVStorage;
|
||||
use sammo\Message;
|
||||
use sammo\Validator;
|
||||
|
||||
class DecideMessageResponse extends \sammo\BaseAPI
|
||||
{
|
||||
public function validateArgs(): ?string
|
||||
{
|
||||
$v = new Validator($this->args);
|
||||
$v->rule('required', ['msgID', 'response']);
|
||||
$v->rule('integer', 'msgID')
|
||||
->rule('boolean', 'response');
|
||||
if (!$v->validate()) {
|
||||
return $v->errorStr();
|
||||
}
|
||||
$this->args['msgID'] = (int)($this->args['msgID'] ?? -1);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getRequiredSessionMode(): int
|
||||
{
|
||||
return static::REQ_GAME_LOGIN;
|
||||
}
|
||||
|
||||
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag)
|
||||
{
|
||||
$msgID = $this->args['msgID'];
|
||||
$msgResponse = $this->args['response'];
|
||||
|
||||
$generalID = $session->generalID;
|
||||
|
||||
$msg = Message::getMessageByID($msgID);
|
||||
if ($msg === null) {
|
||||
return '존재하지 않는 메시지입니다.';
|
||||
}
|
||||
|
||||
$reason = 'success';
|
||||
$gameStor = KVStorage::getStorage(DB::db(), 'game_env');
|
||||
$gameStor->cacheAll();
|
||||
if ($msgResponse) {
|
||||
$result = $msg->agreeMessage($generalID, $reason);
|
||||
} else {
|
||||
$result = $msg->declineMessage($generalID, $reason);
|
||||
}
|
||||
|
||||
|
||||
return [
|
||||
'result' => $result !== DiplomaticMessage::INVALID,
|
||||
'reason' => $reason
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace sammo\API\Message;
|
||||
|
||||
use sammo\Session;
|
||||
use DateTimeInterface;
|
||||
use sammo\Message;
|
||||
use sammo\Validator;
|
||||
|
||||
class DeleteMessage extends \sammo\BaseAPI
|
||||
{
|
||||
public function validateArgs(): ?string
|
||||
{
|
||||
$v = new Validator($this->args);
|
||||
$v->rule('required', ['msgID']);
|
||||
$v->rule('integer', 'msgID');
|
||||
if (!$v->validate()) {
|
||||
return $v->errorStr();
|
||||
}
|
||||
$this->args['msgID'] = (int)($this->args['msgID'] ?? -1);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getRequiredSessionMode(): int
|
||||
{
|
||||
return static::REQ_GAME_LOGIN;
|
||||
}
|
||||
|
||||
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag)
|
||||
{
|
||||
$msgID = $this->args['msgID'];
|
||||
|
||||
$generalID = $session->generalID;
|
||||
return Message::deleteMsg($msgID, $generalID);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace sammo\API\Message;
|
||||
|
||||
use sammo\Session;
|
||||
use DateTimeInterface;
|
||||
|
||||
use function sammo\getMailboxList;
|
||||
|
||||
class GetContactList extends \sammo\BaseAPI{
|
||||
public function validateArgs(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getRequiredSessionMode(): int
|
||||
{
|
||||
return static::REQ_GAME_LOGIN | static::REQ_READ_ONLY;
|
||||
}
|
||||
|
||||
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag)
|
||||
{
|
||||
if(!$session->generalID){
|
||||
return [
|
||||
"nation"=>[]
|
||||
];
|
||||
}
|
||||
|
||||
//NOTE: 모든 국가, 모든 장수에 대해서 같은 결과라면 캐싱 가능하지 않을까?
|
||||
|
||||
return [
|
||||
"nation"=>getMailboxList()
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
<?php
|
||||
|
||||
namespace sammo\API\Message;
|
||||
|
||||
use sammo\Session;
|
||||
use DateTimeInterface;
|
||||
use sammo\DB;
|
||||
use sammo\Enums\MessageType;
|
||||
use sammo\Json;
|
||||
use sammo\Message;
|
||||
use sammo\TimeUtil;
|
||||
use sammo\Util;
|
||||
use sammo\Validator;
|
||||
|
||||
use function sammo\checkSecretPermission;
|
||||
|
||||
class GetOldMessage extends \sammo\BaseAPI
|
||||
{
|
||||
public function validateArgs(): ?string
|
||||
{
|
||||
$v = new Validator($this->args);
|
||||
$v->rule('required', [
|
||||
'to',
|
||||
'type',
|
||||
])->rule('integer', 'to')
|
||||
->rule('in', 'type', ['private', 'public', 'national', 'diplomacy']);
|
||||
if (!$v->validate()) {
|
||||
return $v->errorStr();
|
||||
}
|
||||
$this->args['to'] = (int)($this->args['to'] ?? 0);
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getRequiredSessionMode(): int
|
||||
{
|
||||
return static::REQ_GAME_LOGIN;
|
||||
}
|
||||
|
||||
private function delayFrequentCall(Session $session): void
|
||||
{
|
||||
$lastMsgGet = Json::decode($session->lastMsgGet) ?? [];
|
||||
$now = new \DateTimeImmutable();
|
||||
$delayTime = false;
|
||||
|
||||
if (count($lastMsgGet) >= 10) {
|
||||
try {
|
||||
if (!is_string($lastMsgGet[0])) {
|
||||
throw new \Exception('Why not string?');
|
||||
}
|
||||
$first = new \DateTimeImmutable($lastMsgGet[0]);
|
||||
$diffSec = TimeUtil::DateIntervalToSeconds($first->diff($now));
|
||||
if ($diffSec < 1) {
|
||||
$delayTime = true;
|
||||
}
|
||||
array_shift($lastMsgGet);
|
||||
} catch (\Exception $e) {
|
||||
$lastMsgGet = [];
|
||||
}
|
||||
}
|
||||
$lastMsgGet[] = TimeUtil::format($now, true);
|
||||
$session->lastMsgGet = Json::encode($lastMsgGet);
|
||||
|
||||
if ($delayTime) {
|
||||
usleep(200);
|
||||
}
|
||||
}
|
||||
|
||||
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag)
|
||||
{
|
||||
$this->delayFrequentCall($session);
|
||||
$session->setReadOnly();
|
||||
$userID = $session->getUserID();
|
||||
|
||||
|
||||
|
||||
$db = DB::db();
|
||||
$me = $db->queryFirstRow('SELECT `no`,`name`,`nation`,`officer_level`,`con`,`picture`,`imgsvr`,penalty,permission FROM general WHERE `owner`=%i', $userID);
|
||||
|
||||
if ($me === null) {
|
||||
return '장수가 사망했습니다.';
|
||||
}
|
||||
|
||||
[$generalID, $nationID, $generalName] = [$me['no'], $me['nation'], $me['name']];
|
||||
$permission = checkSecretPermission($me, false);
|
||||
$reqTo = $this->args['to'];
|
||||
|
||||
$result = [
|
||||
MessageType::private->value => [],
|
||||
MessageType::public->value => [],
|
||||
MessageType::national->value => [],
|
||||
MessageType::diplomacy->value => [],
|
||||
'result' => true,
|
||||
'keepRecent' => true,
|
||||
'sequence' => 0,
|
||||
'nationID' => $nationID,
|
||||
'generalName' => $generalName,
|
||||
];
|
||||
$result['result'] = true;
|
||||
|
||||
$nextSequence = $reqTo;
|
||||
$reqType = MessageType::tryFrom($this->args['type']);
|
||||
if ($reqType === null) {
|
||||
return '잘못된 요청입니다.';
|
||||
}
|
||||
|
||||
if ($reqType === MessageType::private) {
|
||||
$result[MessageType::private->value] = array_map(function (Message $msg) use (&$nextSequence) {
|
||||
if ($msg->id > $nextSequence) {
|
||||
$nextSequence = $msg->id;
|
||||
}
|
||||
return $msg->toArray();
|
||||
}, Message::getMessagesFromMailBoxOld($generalID, MessageType::private, $reqTo, 15));
|
||||
} else if ($reqType === MessageType::public) {
|
||||
$result[MessageType::public->value] = array_map(function (Message $msg) use (&$nextSequence) {
|
||||
if ($msg->id > $nextSequence) {
|
||||
$nextSequence = $msg->id;
|
||||
}
|
||||
return $msg->toArray();
|
||||
}, Message::getMessagesFromMailBoxOld(Message::MAILBOX_PUBLIC, MessageType::public, $reqTo, 15));
|
||||
} else if ($reqType === MessageType::national) {
|
||||
$result[MessageType::national->value] = array_map(function (Message $msg) use (&$nextSequence) {
|
||||
if ($msg->id > $nextSequence) {
|
||||
$nextSequence = $msg->id;
|
||||
}
|
||||
return $msg->toArray();
|
||||
}, Message::getMessagesFromMailBoxOld(Message::MAILBOX_NATIONAL + $nationID, MessageType::national, $reqTo, 15));
|
||||
} else {
|
||||
$result[MessageType::diplomacy->value] = array_map(function (Message $msg) use (&$nextSequence, $permission) {
|
||||
if ($msg->id > $nextSequence) {
|
||||
$nextSequence = $msg->id;
|
||||
}
|
||||
$values = $msg->toArray();
|
||||
if ($msg->dest->nationID != 0 && $permission < 3) {
|
||||
$values['text'] = '(외교 메시지입니다)'; //TODO: 외교서신이라 읽을 수 없음을 보여줘야함
|
||||
$values['option']['invalid'] = true;
|
||||
}
|
||||
return $values;
|
||||
}, Message::getMessagesFromMailBoxOld(Message::MAILBOX_NATIONAL + $nationID, MessageType::diplomacy, $reqTo, 15));
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
<?php
|
||||
|
||||
namespace sammo\API\Message;
|
||||
|
||||
use sammo\Session;
|
||||
use DateTimeInterface;
|
||||
use sammo\DB;
|
||||
use sammo\Enums\MessageType;
|
||||
use sammo\Json;
|
||||
use sammo\Message;
|
||||
use sammo\TimeUtil;
|
||||
use sammo\Util;
|
||||
use sammo\Validator;
|
||||
|
||||
use function sammo\checkSecretPermission;
|
||||
|
||||
class GetRecentMessage extends \sammo\BaseAPI
|
||||
{
|
||||
public function validateArgs(): ?string
|
||||
{
|
||||
$v = new Validator($this->args);
|
||||
$v->rule('integer', 'sequence');
|
||||
if (!$v->validate()) {
|
||||
return $v->errorStr();
|
||||
}
|
||||
$this->args['sequence'] = (int)($this->args['sequence'] ?? -1);
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getRequiredSessionMode(): int
|
||||
{
|
||||
return static::REQ_GAME_LOGIN;
|
||||
}
|
||||
|
||||
private function delayFrequentCall(Session $session): void
|
||||
{
|
||||
$lastMsgGet = Json::decode($session->lastMsgGet) ?? [];
|
||||
$now = new \DateTimeImmutable();
|
||||
$delayTime = false;
|
||||
|
||||
if (count($lastMsgGet) >= 10) {
|
||||
try {
|
||||
if (!is_string($lastMsgGet[0])) {
|
||||
throw new \Exception('Why not string?');
|
||||
}
|
||||
$first = new \DateTimeImmutable($lastMsgGet[0]);
|
||||
$diffSec = TimeUtil::DateIntervalToSeconds($first->diff($now));
|
||||
if ($diffSec < 1) {
|
||||
$delayTime = true;
|
||||
}
|
||||
array_shift($lastMsgGet);
|
||||
} catch (\Exception $e) {
|
||||
$lastMsgGet = [];
|
||||
}
|
||||
}
|
||||
$lastMsgGet[] = TimeUtil::format($now, true);
|
||||
$session->lastMsgGet = Json::encode($lastMsgGet);
|
||||
|
||||
if ($delayTime) {
|
||||
usleep(200);
|
||||
}
|
||||
}
|
||||
|
||||
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag)
|
||||
{
|
||||
$this->delayFrequentCall($session);
|
||||
$session->setReadOnly();
|
||||
$userID = $session->getUserID();
|
||||
|
||||
|
||||
|
||||
$db = DB::db();
|
||||
$me = $db->queryFirstRow('SELECT `no`,`name`,`nation`,`officer_level`,`con`,`picture`,`imgsvr`,penalty,permission FROM general WHERE `owner`=%i', $userID);
|
||||
|
||||
if ($me === null) {
|
||||
return '장수가 사망했습니다.';
|
||||
}
|
||||
|
||||
[$generalID, $nationID, $generalName] = [$me['no'], $me['nation'], $me['name']];
|
||||
$permission = checkSecretPermission($me, false);
|
||||
$reqSequence = $this->args['sequence'];
|
||||
|
||||
$result = [];
|
||||
$result['result'] = true;
|
||||
$result['keepRecent'] = false;
|
||||
$nextSequence = $reqSequence;
|
||||
$minSequence = $reqSequence;
|
||||
$lastType = null;
|
||||
|
||||
$result['private'] = array_map(function (Message $msg) use (&$nextSequence, &$minSequence, &$lastType) {
|
||||
if ($msg->id > $nextSequence) {
|
||||
$nextSequence = $msg->id;
|
||||
}
|
||||
if ($msg->id <= $minSequence) {
|
||||
$minSequence = $msg->id;
|
||||
$lastType = 'private';
|
||||
}
|
||||
return $msg->toArray();
|
||||
}, Message::getMessagesFromMailBox($generalID, MessageType::private, 15, $reqSequence));
|
||||
|
||||
$result['public'] = array_map(function (Message $msg) use (&$nextSequence, &$minSequence, &$lastType) {
|
||||
if ($msg->id > $nextSequence) {
|
||||
$nextSequence = $msg->id;
|
||||
}
|
||||
if ($msg->id <= $minSequence) {
|
||||
$minSequence = $msg->id;
|
||||
$lastType = 'public';
|
||||
}
|
||||
return $msg->toArray();
|
||||
}, Message::getMessagesFromMailBox(Message::MAILBOX_PUBLIC, MessageType::public, 15, $reqSequence));
|
||||
|
||||
$result['national'] = array_map(function (Message $msg) use (&$nextSequence, &$minSequence, &$lastType) {
|
||||
if ($msg->id > $nextSequence) {
|
||||
$nextSequence = $msg->id;
|
||||
}
|
||||
if ($msg->id <= $minSequence) {
|
||||
$minSequence = $msg->id;
|
||||
$lastType = 'national';
|
||||
}
|
||||
return $msg->toArray();
|
||||
}, Message::getMessagesFromMailBox(Message::MAILBOX_NATIONAL + $nationID, MessageType::national, 15, $reqSequence));
|
||||
|
||||
$result['diplomacy'] = array_map(function (Message $msg) use (&$nextSequence, &$minSequence, &$lastType, $permission) {
|
||||
if ($msg->id > $nextSequence) {
|
||||
$nextSequence = $msg->id;
|
||||
}
|
||||
if ($msg->id <= $minSequence) {
|
||||
$minSequence = $msg->id;
|
||||
$lastType = 'diplomacy';
|
||||
}
|
||||
$values = $msg->toArray();
|
||||
if ($msg->dest->nationID != 0 && $permission < 3) {
|
||||
$values['text'] = '(외교 메시지입니다)'; //TODO: 외교서신이라 읽을 수 없음을 보여줘야함
|
||||
$values['option']['invalid'] = true;
|
||||
}
|
||||
return $values;
|
||||
}, Message::getMessagesFromMailBox(Message::MAILBOX_NATIONAL + $nationID, MessageType::diplomacy, 15, $reqSequence));
|
||||
|
||||
if ($lastType !== null) {
|
||||
array_pop($result[$lastType]);
|
||||
$result['keepRecent'] = true;
|
||||
} else if ($reqSequence <= 0) {
|
||||
$result['keepRecent'] = true;
|
||||
}
|
||||
|
||||
$result['sequence'] = $nextSequence;
|
||||
$result['nationID'] = $nationID;
|
||||
$result['generalName'] = $generalName;
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,240 @@
|
||||
<?php
|
||||
|
||||
namespace sammo\API\Message;
|
||||
|
||||
use sammo\Session;
|
||||
use DateTimeInterface;
|
||||
use sammo\DB;
|
||||
use sammo\Enums\MessageType;
|
||||
use sammo\Message;
|
||||
use sammo\MessageTarget;
|
||||
use sammo\Validator;
|
||||
|
||||
use function sammo\checkLimit;
|
||||
use function sammo\checkSecretPermission;
|
||||
use function sammo\getBlockLevel;
|
||||
use function sammo\GetImageURL;
|
||||
use function sammo\getNationStaticInfo;
|
||||
use function sammo\increaseRefresh;
|
||||
|
||||
class SendMessage extends \sammo\BaseAPI
|
||||
{
|
||||
public function validateArgs(): ?string
|
||||
{
|
||||
$v = new Validator($this->args);
|
||||
$v->rule('required', ['mailbox', 'text']);
|
||||
$v->rule('integer', 'mailbox');
|
||||
$v->rule('lengthMin', 'text', 1);
|
||||
if (!$v->validate()) {
|
||||
return $v->errorStr();
|
||||
}
|
||||
$this->args['mailbox'] = (int)($this->args['mailbox'] ?? Message::MAILBOX_PUBLIC);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getRequiredSessionMode(): int
|
||||
{
|
||||
return static::REQ_GAME_LOGIN;
|
||||
}
|
||||
|
||||
private function genPublicMessage(MessageTarget $src, string $text): Message
|
||||
{
|
||||
$now = new \DateTime();
|
||||
$unlimited = new \DateTime('9999-12-31');
|
||||
|
||||
$msg = new Message(
|
||||
MessageType::public,
|
||||
$src,
|
||||
$src,
|
||||
$text,
|
||||
$now,
|
||||
$unlimited,
|
||||
[]
|
||||
);
|
||||
|
||||
return $msg;
|
||||
}
|
||||
|
||||
private function genNationalMessage(MessageTarget $src, string $text): Message
|
||||
{
|
||||
$now = new \DateTime();
|
||||
$unlimited = new \DateTime('9999-12-31');
|
||||
|
||||
$dest = new MessageTarget(0, '', $src->nationID, $src->nationName, $src->color);
|
||||
|
||||
$msg = new Message(
|
||||
MessageType::national,
|
||||
$src,
|
||||
$dest,
|
||||
$text,
|
||||
$now,
|
||||
$unlimited,
|
||||
[]
|
||||
);
|
||||
|
||||
return $msg;
|
||||
}
|
||||
|
||||
private function genDiplomacyMessage(MessageTarget $src, int $destNationID, string $text): Message|string
|
||||
{
|
||||
$now = new \DateTime();
|
||||
$unlimited = new \DateTime('9999-12-31');
|
||||
|
||||
$destNation = getNationStaticInfo($destNationID);
|
||||
|
||||
if ($destNation === null) {
|
||||
return '존재하지 않는 국가입니다.';
|
||||
}
|
||||
|
||||
$dest = new MessageTarget(0, '', $destNation['nation'], $destNation['name'], $destNation['color']);
|
||||
|
||||
$msg = new Message(
|
||||
MessageType::diplomacy,
|
||||
$src,
|
||||
$dest,
|
||||
$text,
|
||||
$now,
|
||||
$unlimited,
|
||||
[]
|
||||
);
|
||||
return $msg;
|
||||
}
|
||||
|
||||
private function genPrivateMessage(MessageTarget $src, int $destGeneralID, int $permission, string $text): Message|string
|
||||
{
|
||||
$now = new \DateTime();
|
||||
$unlimited = new \DateTime('9999-12-31');
|
||||
|
||||
$db = DB::db();
|
||||
$destUser = $db->queryFirstRow('SELECT `no`,`name`,`nation`,`officer_level`,`con`,`picture`,`imgsvr`,permission,penalty FROM general WHERE `no`=%i', $destGeneralID);
|
||||
|
||||
if (!$destUser) {
|
||||
return '존재하지 않는 유저입니다.';
|
||||
}
|
||||
|
||||
$destPermission = checkSecretPermission($destUser, false);
|
||||
if ($permission == 4 && $destPermission == 4 && $destUser['nation'] != $src->nationID) {
|
||||
return '외교권자끼리는 메시지를 보낼 수 없습니다.';
|
||||
}
|
||||
|
||||
$destNation = getNationStaticInfo($destUser['nation']);
|
||||
if ($destNation === null) {
|
||||
$destNation = getNationStaticInfo(0);
|
||||
}
|
||||
|
||||
$dest = new MessageTarget(
|
||||
$destUser['no'],
|
||||
$destUser['name'],
|
||||
$destNation['nation'],
|
||||
$destNation['name'],
|
||||
$destNation['color'],
|
||||
GetImageURL($destUser['imgsvr'], $destUser['picture'])
|
||||
);
|
||||
|
||||
$msg = new Message(
|
||||
MessageType::private,
|
||||
$src,
|
||||
$dest,
|
||||
$text,
|
||||
$now,
|
||||
$unlimited,
|
||||
[]
|
||||
);
|
||||
|
||||
return $msg;
|
||||
}
|
||||
|
||||
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag)
|
||||
{
|
||||
$userID = $session->userID;
|
||||
$mailbox = $this->args['mailbox'];
|
||||
$text = $this->args['text'];
|
||||
|
||||
increaseRefresh('서신전달', 1);
|
||||
|
||||
$blockLevel = getBlockLevel();
|
||||
if ($blockLevel == 1 || $blockLevel == 3) {
|
||||
return '차단되었습니다.';
|
||||
}
|
||||
|
||||
$db = DB::db();
|
||||
$me = $db->queryFirstRow('SELECT `no`,`name`,`nation`,`officer_level`,`con`,`picture`,`imgsvr`,penalty,permission,belong FROM general WHERE `owner`=%i', $userID);
|
||||
|
||||
if (!$me) {
|
||||
$session->logoutGame();
|
||||
return '장수가 없습니다.';
|
||||
}
|
||||
|
||||
$con = checkLimit($me['con']);
|
||||
if ($con >= 2) {
|
||||
return '접속 제한입니다.';
|
||||
}
|
||||
|
||||
$nationID = $me['nation'];
|
||||
$iconPath = GetImageURL($me['imgsvr'], $me['picture']);
|
||||
$srcNation = getNationStaticInfo($me['nation']);
|
||||
|
||||
if ($srcNation === null) {
|
||||
return '존재하지 않는 국가입니다.';
|
||||
}
|
||||
|
||||
$src = new MessageTarget($me['no'], $me['name'], $srcNation['nation'], $srcNation['name'], $srcNation['color'], $iconPath);
|
||||
|
||||
// 전체 메세지
|
||||
if ($mailbox === Message::MAILBOX_PUBLIC) {
|
||||
$msgID = $this->genPublicMessage($src, $text)->send();
|
||||
return [
|
||||
'msgID' => $msgID
|
||||
];
|
||||
}
|
||||
|
||||
$permission = checkSecretPermission($me);
|
||||
|
||||
if ($mailbox >= Message::MAILBOX_NATIONAL) {
|
||||
if ($permission < 4) {
|
||||
$destNationID = $nationID;
|
||||
} else {
|
||||
$destNationID = $mailbox - Message::MAILBOX_NATIONAL;
|
||||
}
|
||||
|
||||
if ($destNationID === $nationID) {
|
||||
$msgID = $this->genNationalMessage($src, $text)->send();
|
||||
return [
|
||||
'msgID' => $msgID
|
||||
];
|
||||
}
|
||||
|
||||
$msgObjOrError = $this->genDiplomacyMessage($src, $destNationID, $text);
|
||||
if(is_string($msgObjOrError)) {
|
||||
return $msgObjOrError;
|
||||
}
|
||||
$msgID = $msgObjOrError->send();
|
||||
return [
|
||||
'msgID' => $msgID
|
||||
];
|
||||
}
|
||||
|
||||
if ($mailbox > 0) {
|
||||
$now = new \DateTime();
|
||||
$lastMsg = new \DateTime($session->lastMsg ?? '0000-00-00');
|
||||
$msg_interval = $now->getTimestamp() - $lastMsg->getTimestamp();
|
||||
if ($msg_interval < 2) {
|
||||
return '개인메세지는 2초당 1건만 보낼 수 있습니다!';
|
||||
}
|
||||
$session->lastMsg = $now->format('Y-m-d H:i:s');
|
||||
|
||||
$msgObjOrError = $this->genPrivateMessage($src, $mailbox, $permission, $text);
|
||||
if(is_string($msgObjOrError)) {
|
||||
return $msgObjOrError;
|
||||
}
|
||||
$msgID = $msgObjOrError->send();
|
||||
|
||||
return [
|
||||
'msgID' => $msgID
|
||||
];
|
||||
}
|
||||
|
||||
return '알 수 없는 에러입니다.';
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ class che_명마_12_옥란백용구 extends \sammo\BaseStatItem{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->info .= "<br>[전투] 남은 병력이 적을수록 회피 확률 증가. 최대 +30%p";
|
||||
$this->info .= "<br>[전투] 남은 병력이 적을수록 회피 확률 증가. 최대 +50%p";
|
||||
}
|
||||
|
||||
public function onCalcStat(General $general, string $statName, $value, $aux = null)
|
||||
@@ -20,7 +20,7 @@ class che_명마_12_옥란백용구 extends \sammo\BaseStatItem{
|
||||
$leadership = $general->getLeadership(true, true, true, false);
|
||||
$crewL = $general->getVar('crew') / 100;
|
||||
|
||||
return $value + \sammo\Util::valueFit((1 - $crewL / $leadership) * 0.3, 0, 0.3);
|
||||
return $value + \sammo\Util::valueFit((1 - $crewL / $leadership) * 0.5, 0, 0.5);
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ class che_징병_낙주 extends \sammo\BaseItem{
|
||||
|
||||
protected $rawName = '낙주';
|
||||
protected $name = '낙주(징병)';
|
||||
protected $info = '[군사] 징·모병비 -30%, 통솔 순수 능력치 보정 +15%';
|
||||
protected $info = '[군사] 징·모병비 -30%<br>[기타] 통솔 순수 능력치 보정 +15%, 징병/모병/소집해제 시 인구 변동 없음';
|
||||
protected $cost = 200;
|
||||
protected $consumable = false;
|
||||
|
||||
@@ -18,6 +18,10 @@ class che_징병_낙주 extends \sammo\BaseItem{
|
||||
if($varType == 'cost') return $value * 0.7;
|
||||
}
|
||||
|
||||
if($turnType == '징집인구' && $varType == 'score'){
|
||||
return 0;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ class event_전투특기_징병 extends \sammo\BaseItem{
|
||||
|
||||
protected $rawName = '비급';
|
||||
protected $name = '비급(징병)';
|
||||
protected $info = '[군사] 징·모병비 -50%, 통솔 순수 능력치 보정 +25%';
|
||||
protected $info = '[군사] 징병/모병 시 훈사 70/84 제공<br>[기타] 통솔 순수 능력치 보정 +25%, 징병/모병/소집해제 시 인구 변동 없음';
|
||||
protected $cost = 100;
|
||||
protected $buyable = true;
|
||||
protected $consumable = false;
|
||||
@@ -17,7 +17,18 @@ class event_전투특기_징병 extends \sammo\BaseItem{
|
||||
|
||||
public function onCalcDomestic(string $turnType, string $varType, float $value, $aux=null):float{
|
||||
if(in_array($turnType, ['징병', '모병'])){
|
||||
if($varType == 'cost') return $value * 0.5;
|
||||
if($varType == 'train' || $varType == 'atmos'){
|
||||
if($turnType === '징병'){
|
||||
return 70;
|
||||
}
|
||||
else{
|
||||
return 84;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($turnType == '징집인구' && $varType == 'score'){
|
||||
return 0;
|
||||
}
|
||||
|
||||
return $value;
|
||||
|
||||
@@ -9,7 +9,7 @@ class che_event_징병 extends \sammo\BaseSpecial{
|
||||
|
||||
protected $id = 72;
|
||||
protected $name = '징병';
|
||||
protected $info = '[군사] 징·모병비 -50%, 통솔 순수 능력치 보정 +25%';
|
||||
protected $info = '[군사] 징병/모병 시 훈사 70/84 제공<br>[기타] 통솔 순수 능력치 보정 +25%, 징병/모병/소집해제 시 인구 변동 없음';
|
||||
|
||||
static $selectWeightType = SpecialityHelper::WEIGHT_NORM;
|
||||
static $selectWeight = 1;
|
||||
@@ -21,9 +21,20 @@ class che_event_징병 extends \sammo\BaseSpecial{
|
||||
|
||||
public function onCalcDomestic(string $turnType, string $varType, float $value, $aux=null):float{
|
||||
if(in_array($turnType, ['징병', '모병'])){
|
||||
if($varType == 'cost') return $value * 0.5;
|
||||
if($varType == 'train' || $varType == 'atmos'){
|
||||
if($turnType === '징병'){
|
||||
return 70;
|
||||
}
|
||||
else{
|
||||
return 84;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if($turnType == '징집인구' && $varType == 'score'){
|
||||
return 0;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ class che_징병 extends \sammo\BaseSpecial{
|
||||
|
||||
protected $id = 72;
|
||||
protected $name = '징병';
|
||||
protected $info = '[군사] 징·모병비 -50%, 통솔 순수 능력치 보정 +25%';
|
||||
protected $info = '[군사] 징병/모병 시 훈사 70/84 제공<br>[기타] 통솔 순수 능력치 보정 +25%, 징병/모병/소집해제 시 인구 변동 없음';
|
||||
|
||||
static $selectWeightType = SpecialityHelper::WEIGHT_NORM;
|
||||
static $selectWeight = 1;
|
||||
@@ -21,9 +21,20 @@ class che_징병 extends \sammo\BaseSpecial{
|
||||
|
||||
public function onCalcDomestic(string $turnType, string $varType, float $value, $aux=null):float{
|
||||
if(in_array($turnType, ['징병', '모병'])){
|
||||
if($varType == 'cost') return $value * 0.5;
|
||||
if($varType == 'train' || $varType == 'atmos'){
|
||||
if($turnType === '징병'){
|
||||
return 70;
|
||||
}
|
||||
else{
|
||||
return 84;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if($turnType == '징집인구' && $varType == 'score'){
|
||||
return 0;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ use sammo\DTO\AuctionBidItemData;
|
||||
use sammo\DTO\AuctionInfo;
|
||||
use sammo\Enums\AuctionType;
|
||||
use sammo\Enums\InheritanceKey;
|
||||
use sammo\Enums\MessageType;
|
||||
use sammo\Enums\RankColumn;
|
||||
use sammo\Enums\ResourceType;
|
||||
|
||||
@@ -245,7 +246,7 @@ abstract class Auction
|
||||
//TODO: 전역 알림이 나타나야한다. 일반 메시지보다는 중요하고, 메시지보단 약하게..
|
||||
//TODO: 바로가기를 제공하는 편이 좋을 것 같다.
|
||||
$msg = new Message(
|
||||
Message::MSGTYPE_PRIVATE,
|
||||
MessageType::private,
|
||||
$src,
|
||||
$dest,
|
||||
$reason,
|
||||
@@ -509,7 +510,7 @@ abstract class Auction
|
||||
//TODO: 전역 알림이 나타나야한다. 일반 메시지보다는 중요하고, 메시지보단 약하게..
|
||||
//TODO: 바로가기를 제공하는 편이 좋을 것 같다.
|
||||
$msg = new Message(
|
||||
Message::MSGTYPE_PRIVATE,
|
||||
MessageType::private,
|
||||
$src,
|
||||
$dest,
|
||||
$failReason,
|
||||
|
||||
@@ -7,6 +7,7 @@ use sammo\DTO\AuctionBidItem;
|
||||
use sammo\DTO\AuctionInfo;
|
||||
use sammo\DTO\AuctionInfoDetail;
|
||||
use sammo\Enums\AuctionType;
|
||||
use sammo\Enums\MessageType;
|
||||
use sammo\Enums\ResourceType;
|
||||
|
||||
abstract class AuctionBasicResource extends Auction
|
||||
@@ -145,7 +146,7 @@ abstract class AuctionBasicResource extends Auction
|
||||
//TODO: 전역 알림이 나타나야한다. 일반 메시지보다는 중요하고, 메시지보단 약하게..
|
||||
//TODO: 바로가기를 제공하는 편이 좋을 것 같다.
|
||||
$msg = new Message(
|
||||
Message::MSGTYPE_PRIVATE,
|
||||
MessageType::private,
|
||||
$src,
|
||||
$dest,
|
||||
"{$this->auctionID}번 {$hostResName} 경매에 입찰이 없어 취소되었습니다.",
|
||||
|
||||
@@ -110,7 +110,11 @@ class AuctionUniqueItem extends Auction
|
||||
}
|
||||
$auction = new static($auctionID, $general);
|
||||
try {
|
||||
$auction->bid($startAmount, false);
|
||||
$failReason = $auction->bid($startAmount, false);
|
||||
if($failReason){
|
||||
$auction->closeAuction();
|
||||
return "경매를 시작했지만, 첫 입찰에 실패했습니다: {$failReason}";
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
//실패해선 안된다.
|
||||
$msg = $e->getMessage();
|
||||
|
||||
@@ -179,6 +179,15 @@ class che_등용수락 extends Command\GeneralCommand{
|
||||
$db->update('nation', $setScoutNationValues, 'nation=%i', $destNationID);
|
||||
|
||||
$general->increaseInheritancePoint(InheritanceKey::active_action, 1);
|
||||
if($general->getNPCType() < 2){
|
||||
$general->setAuxVar(
|
||||
InheritanceKey::max_belong->value,
|
||||
max(
|
||||
$general->getVar('belong'),
|
||||
$general->getAuxVar(InheritanceKey::max_belong->value) ?? 0
|
||||
)
|
||||
);
|
||||
}
|
||||
$general->setVar('permission', 'normal');
|
||||
$general->setVar('belong', 1);
|
||||
$general->setVar('officer_level', 1);
|
||||
|
||||
@@ -0,0 +1,246 @@
|
||||
<?php
|
||||
|
||||
namespace sammo\Command\General;
|
||||
|
||||
use \sammo\DB;
|
||||
use \sammo\Util;
|
||||
use \sammo\JosaUtil;
|
||||
use \sammo\General;
|
||||
use \sammo\ActionLogger;
|
||||
use \sammo\GameConst;
|
||||
use \sammo\GameUnitConst;
|
||||
use \sammo\LastTurn;
|
||||
use \sammo\Command;
|
||||
use \sammo\Json;
|
||||
|
||||
use function \sammo\tryUniqueItemLottery;
|
||||
use function \sammo\getAllNationStaticInfo;
|
||||
|
||||
use \sammo\Constraint\ConstraintHelper;
|
||||
use sammo\Enums\InheritanceKey;
|
||||
|
||||
use function sammo\buildNationTypeClass;
|
||||
use function sammo\genGenericUniqueRNGFromGeneral;
|
||||
use function sammo\refreshNationStaticInfo;
|
||||
use function sammo\GetNationColors;
|
||||
|
||||
|
||||
class che_무작위건국 extends Command\GeneralCommand
|
||||
{
|
||||
static protected $actionName = '무작위 도시 건국';
|
||||
static public $reqArg = true;
|
||||
|
||||
protected function argTest(): bool
|
||||
{
|
||||
if ($this->arg === null) {
|
||||
return false;
|
||||
}
|
||||
$nationName = $this->arg['nationName'] ?? null;
|
||||
$nationType = $this->arg['nationType'] ?? null;
|
||||
$colorType = $this->arg['colorType'] ?? null;
|
||||
|
||||
if ($nationName === null || $nationType === null || $colorType === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!is_string($nationName) || !is_string($nationType) || !is_int($colorType)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mb_strwidth($nationName) > 18 || $nationName == '') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!key_exists($colorType, GetNationColors())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
$nationTypeClass = buildNationTypeClass($nationType);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->arg = [
|
||||
'nationName' => $nationName,
|
||||
'nationType' => $nationType,
|
||||
'colorType' => $colorType
|
||||
];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function init()
|
||||
{
|
||||
$env = $this->env;
|
||||
|
||||
$this->setNation(['gennum', 'aux']);
|
||||
|
||||
$relYear = $env['year'] - $env['startyear'];
|
||||
|
||||
$this->minConditionConstraints = [
|
||||
ConstraintHelper::BeOpeningPart($relYear + 1),
|
||||
ConstraintHelper::ReqNationValue('level', '국가규모', '==', 0, '정식 국가가 아니어야합니다.')
|
||||
];
|
||||
}
|
||||
|
||||
protected function initWithArg()
|
||||
{
|
||||
$env = $this->env;
|
||||
$relYear = $env['year'] - $env['startyear'];
|
||||
|
||||
$nationName = $this->arg['nationName'];
|
||||
$nationType = $this->arg['nationType'];
|
||||
$colorType = $this->arg['colorType'];
|
||||
|
||||
$this->fullConditionConstraints = [
|
||||
ConstraintHelper::BeLord(),
|
||||
ConstraintHelper::WanderingNation(),
|
||||
ConstraintHelper::ReqNationValue('gennum', '수하 장수', '>=', 2),
|
||||
ConstraintHelper::BeOpeningPart($relYear + 1),
|
||||
ConstraintHelper::CheckNationNameDuplicate($nationName),
|
||||
ConstraintHelper::AllowJoinAction(),
|
||||
];
|
||||
}
|
||||
|
||||
public function getBrief(): string
|
||||
{
|
||||
$nationName = $this->arg['nationName'];
|
||||
$josaUl = JosaUtil::pick($nationName, '을');
|
||||
return "【{$nationName}】{$josaUl} 무작위 도시에 건국";
|
||||
}
|
||||
|
||||
public function getCost(): array
|
||||
{
|
||||
return [0, 0];
|
||||
}
|
||||
|
||||
public function getPreReqTurn(): int
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function getPostReqTurn(): int
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function run(\Sammo\RandUtil $rng): bool
|
||||
{
|
||||
if (!$this->hasFullConditionMet()) {
|
||||
throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도');
|
||||
}
|
||||
|
||||
$db = DB::db();
|
||||
$env = $this->env;
|
||||
|
||||
$general = $this->generalObj;
|
||||
$date = $general->getTurnTime($general::TURNTIME_HM);
|
||||
$generalName = $general->getName();
|
||||
$logger = $general->getLogger();
|
||||
|
||||
$initYearMonth = Util::joinYearMonth($env['init_year'], $env['init_month']);
|
||||
$yearMonth = Util::joinYearMonth($env['year'], $env['month']);
|
||||
if($yearMonth <= $initYearMonth){
|
||||
$logger->pushGeneralActionLog("다음 턴부터 건국할 수 있습니다. <1>$date</>");
|
||||
$this->alternative = new che_인재탐색($general, $this->env, null);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
$cities = $db->queryFirstColumn('SELECT city FROM city where `level`>=5 and `level`<=6 and nation=0');
|
||||
if(!$cities){
|
||||
$logger->pushGeneralActionLog("건국할 수 있는 도시가 없습니다. <1>$date</>");
|
||||
$this->alternative = new che_해산($general, $this->env, null);
|
||||
return false;
|
||||
}
|
||||
$cityID = $rng->choice($cities);
|
||||
if($general->getCityID() == $cityID){
|
||||
$this->setCity();
|
||||
}
|
||||
else{
|
||||
$this->generalObj->setVar('city', $cityID);
|
||||
$this->setCity();
|
||||
$db->update('general', [
|
||||
'city' => $cityID
|
||||
], 'nation = %i', $general->getNationID());
|
||||
}
|
||||
|
||||
$josaYi = JosaUtil::pick($generalName, '이');
|
||||
|
||||
$nationName = $this->arg['nationName'];
|
||||
$nationType = $this->arg['nationType'];
|
||||
$colorType = GetNationColors()[$this->arg['colorType']];
|
||||
|
||||
$cityName = $this->city['name'];
|
||||
|
||||
$josaUl = JosaUtil::pick($nationName, '을');
|
||||
|
||||
$nationTypeClass = buildNationTypeClass($nationType);
|
||||
$nationTypeName = $nationTypeClass->getName();
|
||||
|
||||
$logger->pushGeneralActionLog("<D><b>{$nationName}</b></>{$josaUl} 건국하였습니다. <1>$date</>");
|
||||
$logger->pushGlobalActionLog("<Y>{$generalName}</>{$josaYi} <G><b>{$cityName}</b></>에 국가를 건설하였습니다.");
|
||||
|
||||
$josaNationYi = JosaUtil::pick($nationName, '이');
|
||||
$logger->pushGlobalHistoryLog("<Y><b>【건국】</b></>{$nationTypeName} <D><b>{$nationName}</b></>{$josaNationYi} 새로이 등장하였습니다.");
|
||||
$logger->pushGeneralHistoryLog("<D><b>{$nationName}</b></>{$josaUl} 건국");
|
||||
$logger->pushNationalHistoryLog("<Y>{$generalName}</>{$josaYi} <D><b>{$nationName}</b></>{$josaUl} 건국");
|
||||
|
||||
$exp = 1000;
|
||||
$ded = 1000;
|
||||
|
||||
$general->addExperience($exp);
|
||||
$general->addDedication($ded);
|
||||
|
||||
$aux = Json::decode($this->nation['aux']) ?? [];
|
||||
$aux['can_국기변경'] = 1;
|
||||
$aux['can_무작위수도이전'] = 1;
|
||||
|
||||
$db->update('city', [
|
||||
'nation' => $general->getNationID(),
|
||||
'conflict' => '{}'
|
||||
], 'city=%i', $general->getCityID());
|
||||
|
||||
$db->update('nation', [
|
||||
'name' => $nationName,
|
||||
'color' => $colorType,
|
||||
'level' => 1,
|
||||
'type' => $nationType,
|
||||
'capital' => $general->getCityID(),
|
||||
'aux' => Json::encode($aux)
|
||||
], 'nation=%i', $general->getNationID());
|
||||
|
||||
refreshNationStaticInfo();
|
||||
|
||||
$general->increaseInheritancePoint(InheritanceKey::active_action, 1);
|
||||
$this->setResultTurn(new LastTurn(static::getName(), $this->arg));
|
||||
$general->checkStatChange();
|
||||
tryUniqueItemLottery(genGenericUniqueRNGFromGeneral($general), $general, '건국');
|
||||
$general->applyDB($db);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function exportJSVars(): array
|
||||
{
|
||||
$nationTypes = [];
|
||||
foreach (GameConst::$availableNationType as $nationType) {
|
||||
$nationClass = buildNationTypeClass($nationType);
|
||||
$nationTypes[$nationType] = [
|
||||
'type' => $nationType,
|
||||
'name' => $nationClass->getName(),
|
||||
'pros' => $nationClass::$pros,
|
||||
'cons' => $nationClass::$cons
|
||||
];
|
||||
}
|
||||
return [
|
||||
'procRes' => [
|
||||
'available건국' => count(getAllNationStaticInfo()) < $this->env['maxnation'],
|
||||
'nationTypes' => $nationTypes,
|
||||
'colors' => GetNationColors(),
|
||||
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -62,8 +62,6 @@ class che_소집해제 extends Command\GeneralCommand{
|
||||
$general = $this->generalObj;
|
||||
$date = $general->getTurnTime($general::TURNTIME_HM);
|
||||
|
||||
$crew = $general->getVar('crew');
|
||||
|
||||
$logger = $general->getLogger();
|
||||
|
||||
$logger->pushGeneralActionLog("병사들을 <R>소집해제</>하였습니다. <1>$date</>");
|
||||
@@ -71,8 +69,10 @@ class che_소집해제 extends Command\GeneralCommand{
|
||||
$exp = 70;
|
||||
$ded = 100;
|
||||
|
||||
$crewUp = $general->onCalcDomestic('징집인구', 'score', $general->getVar('crew'));
|
||||
|
||||
$db->update('city', [
|
||||
'pop'=>$db->sqleval('pop + %i', $crew)
|
||||
'pop'=>$db->sqleval('pop + %i', $crewUp)
|
||||
], 'city=%i', $general->getCityID());
|
||||
|
||||
$general->setVar('crew', 0);
|
||||
|
||||
@@ -10,6 +10,7 @@ use \sammo\{
|
||||
use \sammo\Constraint\ConstraintHelper;
|
||||
|
||||
use function sammo\tryUniqueItemLottery;
|
||||
use function sammo\CheckHall;
|
||||
|
||||
class che_은퇴 extends Command\GeneralCommand{
|
||||
static protected $actionName = '은퇴';
|
||||
@@ -59,12 +60,17 @@ class che_은퇴 extends Command\GeneralCommand{
|
||||
}
|
||||
|
||||
$db = DB::db();
|
||||
$env = $this->env;
|
||||
|
||||
$general = $this->generalObj;
|
||||
$date = $general->getTurnTime($general::TURNTIME_HM);
|
||||
|
||||
$logger = $general->getLogger();
|
||||
|
||||
if ($env['isunited'] == 0) {
|
||||
CheckHall($general->getID());
|
||||
}
|
||||
|
||||
$general->rebirth();
|
||||
$logger->pushGeneralActionLog("은퇴하였습니다. <1>$date</>");
|
||||
|
||||
|
||||
@@ -184,10 +184,13 @@ class che_징병 extends Command\GeneralCommand
|
||||
|
||||
$logger = $general->getLogger();
|
||||
|
||||
$setTrain = $general->onCalcDomestic(static::$actionName, 'train', static::$defaultTrain);
|
||||
$setAtmos = $general->onCalcDomestic(static::$actionName, 'atmos', static::$defaultAtmos);
|
||||
|
||||
if ($reqCrewType->id == $currCrewType->id && $currCrew > 0) {
|
||||
$logger->pushGeneralActionLog("{$crewTypeName} <C>{$reqCrewText}</>명을 추가{$this->getName()}했습니다. <1>$date</>");
|
||||
$train = ($currCrew * $general->getVar('train') + $reqCrew * static::$defaultTrain) / ($currCrew + $reqCrew);
|
||||
$atmos = ($currCrew * $general->getVar('atmos') + $reqCrew * static::$defaultAtmos) / ($currCrew + $reqCrew);
|
||||
$train = ($currCrew * $general->getVar('train') + $reqCrew * $setTrain) / ($currCrew + $reqCrew);
|
||||
$atmos = ($currCrew * $general->getVar('atmos') + $reqCrew * $setAtmos) / ($currCrew + $reqCrew);
|
||||
|
||||
$general->increaseVar('crew', $reqCrew);
|
||||
$general->setVar('train', $train);
|
||||
@@ -196,15 +199,17 @@ class che_징병 extends Command\GeneralCommand
|
||||
$logger->pushGeneralActionLog("{$crewTypeName} <C>{$reqCrewText}</>명을 {$this->getName()}했습니다. <1>$date</>");
|
||||
$general->setVar('crewtype', $reqCrewType->id);
|
||||
$general->setVar('crew', $reqCrew);
|
||||
$general->setVar('train', static::$defaultTrain);
|
||||
$general->setVar('atmos', static::$defaultAtmos);
|
||||
$general->setVar('train', $setTrain);
|
||||
$general->setVar('atmos', $setAtmos);
|
||||
}
|
||||
|
||||
$newTrust = Util::valueFit($this->city['trust'] - ($reqCrew / $this->city['pop']) / static::$costOffset * 100, 0);
|
||||
$reqCrewDown = $general->onCalcDomestic('징집인구', 'score', $reqCrew);
|
||||
|
||||
$newTrust = Util::valueFit($this->city['trust'] - ($reqCrewDown / $this->city['pop']) / static::$costOffset * 100, 0);
|
||||
|
||||
$db->update('city', [
|
||||
'trust' => $newTrust,
|
||||
'pop' => $this->city['pop'] - $reqCrew
|
||||
'pop' => $this->city['pop'] - $reqCrewDown
|
||||
], 'city=%i', $general->getCityID());
|
||||
|
||||
$exp = Util::round($reqCrew / 100);
|
||||
|
||||
@@ -113,6 +113,15 @@ class che_하야 extends Command\GeneralCommand{
|
||||
$general->setVar('troop', 0);
|
||||
|
||||
$general->increaseInheritancePoint(InheritanceKey::active_action, 1);
|
||||
if($general->getNPCType() < 2){
|
||||
$general->setAuxVar(
|
||||
InheritanceKey::max_belong->value,
|
||||
max(
|
||||
$general->getVar('belong'),
|
||||
$general->getAuxVar(InheritanceKey::max_belong->value) ?? 0
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$this->setResultTurn(new LastTurn(static::getName(), $this->arg));
|
||||
$general->checkStatChange();
|
||||
|
||||
@@ -94,6 +94,7 @@ class che_화계 extends Command\GeneralCommand
|
||||
|
||||
$prob = $maxGenScore / GameConst::$sabotageProbCoefByStat;
|
||||
$prob += $probCorrection;
|
||||
$prob += (log(count($destCityGeneralList) + 1, 2) - 1.25) * GameConst::$sabotageDefenceCoefByGeneralCnt;
|
||||
|
||||
$prob += $destCity['secu'] / $destCity['secu_max'] / 5; //최대 20%p
|
||||
$prob += $destCity['supply'] ? 0.1 : 0;
|
||||
|
||||
@@ -19,6 +19,7 @@ use function \sammo\GetImageURL;
|
||||
|
||||
use \sammo\Constraint\Constraint;
|
||||
use \sammo\Constraint\ConstraintHelper;
|
||||
use sammo\Enums\MessageType;
|
||||
|
||||
class che_몰수 extends Command\NationCommand
|
||||
{
|
||||
@@ -186,7 +187,7 @@ class che_몰수 extends Command\NationCommand
|
||||
GetImageURL($destGeneral->getVar('imgsvr'), $destGeneral->getVar('picture'))
|
||||
);
|
||||
$msg = new Message(
|
||||
Message::MSGTYPE_PUBLIC,
|
||||
MessageType::public,
|
||||
$src,
|
||||
$src,
|
||||
$text,
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
<?php
|
||||
|
||||
namespace sammo\Command\Nation;
|
||||
|
||||
use \sammo\DB;
|
||||
use \sammo\Util;
|
||||
use \sammo\JosaUtil;
|
||||
use \sammo\General;
|
||||
use \sammo\DummyGeneral;
|
||||
use \sammo\ActionLogger;
|
||||
use \sammo\GameConst;
|
||||
use \sammo\LastTurn;
|
||||
use \sammo\GameUnitConst;
|
||||
use \sammo\Command;
|
||||
use \sammo\MessageTarget;
|
||||
use \sammo\Message;
|
||||
use \sammo\CityConst;
|
||||
use \sammo\Constraint\Constraint;
|
||||
use \sammo\Constraint\ConstraintHelper;
|
||||
use sammo\Enums\InheritanceKey;
|
||||
use sammo\Event\Action;
|
||||
use sammo\Json;
|
||||
|
||||
class che_무작위수도이전 extends Command\NationCommand
|
||||
{
|
||||
static protected $actionName = '무작위 수도 이전';
|
||||
|
||||
protected function argTest(): bool
|
||||
{
|
||||
$this->arg = [];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function init()
|
||||
{
|
||||
$env = $this->env;
|
||||
$relYear = $env['year'] - $env['startyear'];
|
||||
|
||||
$this->setCity();
|
||||
$this->setNation(['capital', 'aux']);
|
||||
|
||||
$this->fullConditionConstraints = [
|
||||
ConstraintHelper::OccupiedCity(),
|
||||
ConstraintHelper::BeLord(),
|
||||
ConstraintHelper::SuppliedCity(),
|
||||
ConstraintHelper::BeOpeningPart($relYear + 1),
|
||||
ConstraintHelper::ReqNationAuxValue("can_무작위수도이전", 0, '>', 0, '더이상 변경이 불가능합니다.')
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
public function getCommandDetailTitle():string{
|
||||
$name = $this->getName();
|
||||
|
||||
$reqTurn = $this->getPreReqTurn()+1;
|
||||
|
||||
return "{$name}/{$reqTurn}턴";
|
||||
}
|
||||
|
||||
|
||||
public function getCost(): array
|
||||
{
|
||||
return [0, 0];
|
||||
}
|
||||
|
||||
public function getPreReqTurn(): int
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
public function getPostReqTurn(): int
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function run(\Sammo\RandUtil $rng): bool
|
||||
{
|
||||
if (!$this->hasFullConditionMet()) {
|
||||
throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도');
|
||||
}
|
||||
|
||||
$db = DB::db();
|
||||
|
||||
$general = $this->generalObj;
|
||||
$generalID = $general->getID();
|
||||
$generalName = $general->getName();
|
||||
$date = $general->getTurnTime($general::TURNTIME_HM);
|
||||
|
||||
$year = $this->env['year'];
|
||||
$month = $this->env['month'];
|
||||
|
||||
$logger = $general->getLogger();
|
||||
|
||||
$oldCityID = $this->nation['capital'];
|
||||
|
||||
$cities = $db->queryFirstColumn('SELECT city FROM city where `level`>=5 and `level`<=6 and nation=0');
|
||||
if (!$cities) {
|
||||
$logger->pushGeneralActionLog("이동할 수 있는 도시가 없습니다. <1>$date</>");
|
||||
return false;
|
||||
}
|
||||
$destCityID = $rng->choice($cities);
|
||||
$this->setDestCity($destCityID, true);
|
||||
|
||||
|
||||
$destCity = $this->destCity;
|
||||
$destCityID = $destCity['city'];
|
||||
$destCityName = $destCity['name'];
|
||||
|
||||
$nationID = $general->getNationID();
|
||||
$nationName = $this->nation['name'];
|
||||
|
||||
$josaRo = JosaUtil::pick($destCityName, '로');
|
||||
|
||||
$general->addExperience(5 * ($this->getPreReqTurn() + 1));
|
||||
$general->addDedication(5 * ($this->getPreReqTurn() + 1));
|
||||
|
||||
$josaYi = JosaUtil::pick($generalName, '이');
|
||||
$josaYiNation = JosaUtil::pick($nationName, '이');
|
||||
|
||||
$aux = Json::decode($this->nation['aux']);
|
||||
$aux["can_무작위수도이전"] -= 1;
|
||||
|
||||
$db->update('city', [
|
||||
'nation' => $nationID,
|
||||
'conflict' => '{}'
|
||||
], 'city=%i', $destCityID);
|
||||
$db->update('nation', [
|
||||
'capital' => $destCityID,
|
||||
'aux'=>Json::encode($aux),
|
||||
], 'nation=%i', $nationID);
|
||||
$db->update('city', [
|
||||
'nation' => 0,
|
||||
'front' => 0,
|
||||
'conflict' => '{}',
|
||||
'officer_set' => 0,
|
||||
], 'city=%i', $oldCityID);
|
||||
|
||||
$general->setVar('city', $destCityID);
|
||||
$generalList = $db->queryFirstColumn('SELECT no FROM general WHERE nation=%i AND no!=%i', $general->getNationID(), $general->getID());
|
||||
if ($generalList) {
|
||||
$db->update('general', [
|
||||
'city' => $destCityID
|
||||
], 'no IN %li', $generalList);
|
||||
}
|
||||
foreach ($generalList as $targetGeneralID) {
|
||||
$targetLogger = new ActionLogger($targetGeneralID, $general->getNationID(), $year, $month);
|
||||
$targetLogger->pushGeneralActionLog("국가 수도를 <G><b>{$destCityName}</b></>{$josaRo} 옮겼습니다.", ActionLogger::PLAIN);
|
||||
$targetLogger->flush();
|
||||
}
|
||||
|
||||
\sammo\refreshNationStaticInfo();
|
||||
|
||||
$general->increaseInheritancePoint(InheritanceKey::active_action, 1);
|
||||
$logger->pushGeneralActionLog("<G><b>{$destCityName}</b></>{$josaRo} 국가를 옮겼습니다. <1>$date</>");
|
||||
$logger->pushGeneralHistoryLog("<G><b>{$destCityName}</b></>{$josaRo} <M>무작위 수도 이전</>");
|
||||
$logger->pushNationalHistoryLog("<Y>{$generalName}</>{$josaYi} <G><b>{$destCityName}</b></>{$josaRo} <M>무작위 수도 이전</>");
|
||||
$logger->pushGlobalActionLog("<Y>{$generalName}</>{$josaYi} <G><b>{$destCityName}</b></>{$josaRo} <M>수도 이전</>하였습니다.");
|
||||
$logger->pushGlobalHistoryLog("<S><b>【무작위 수도 이전】</b></><D><b>{$nationName}</b></>{$josaYiNation} <G><b>{$destCityName}</b></>{$josaRo} <M>수도 이전</>하였습니다.");
|
||||
|
||||
$this->setResultTurn(new LastTurn($this->getName(), $this->arg, 0));
|
||||
$general->applyDB($db);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -112,7 +112,7 @@ class che_불가침수락 extends Command\NationCommand
|
||||
$month = $this->arg['month'];
|
||||
|
||||
$currentMonth = $env['year'] * 12 + $env['month'] - 1;
|
||||
$reqMonth = $year * 12 + $month - 1;
|
||||
$reqMonth = $year * 12 + $month;
|
||||
|
||||
$nationID = $this->nation['nation'];
|
||||
|
||||
@@ -199,7 +199,7 @@ class che_불가침수락 extends Command\NationCommand
|
||||
$destLogger = $this->destGeneralObj->getLogger();
|
||||
|
||||
$currentMonth = $env['year'] * 12 + $env['month'] - 1;
|
||||
$reqMonth = $year * 12 + $month - 1;
|
||||
$reqMonth = $year * 12 + $month;
|
||||
|
||||
$db->update(
|
||||
'diplomacy',
|
||||
|
||||
@@ -22,6 +22,7 @@ use function \sammo\getNationStaticInfo;
|
||||
|
||||
use \sammo\Constraint\Constraint;
|
||||
use \sammo\Constraint\ConstraintHelper;
|
||||
use sammo\Enums\MessageType;
|
||||
|
||||
class che_불가침제의 extends Command\NationCommand
|
||||
{
|
||||
@@ -202,7 +203,7 @@ class che_불가침제의 extends Command\NationCommand
|
||||
$josaWa = JosaUtil::pick($nationName, '와');
|
||||
|
||||
$msg = new DiplomaticMessage(
|
||||
Message::MSGTYPE_DIPLOMACY,
|
||||
MessageType::diplomacy,
|
||||
$src,
|
||||
$dest,
|
||||
"{$nationName}{$josaWa} {$year}년 {$month}월까지 불가침 제의 서신",
|
||||
|
||||
@@ -20,6 +20,7 @@ use function \sammo\GetImageURL;
|
||||
|
||||
use \sammo\Constraint\Constraint;
|
||||
use \sammo\Constraint\ConstraintHelper;
|
||||
use sammo\Enums\MessageType;
|
||||
|
||||
class che_불가침파기제의 extends Command\NationCommand{
|
||||
static protected $actionName = '불가침 파기 제의';
|
||||
@@ -150,7 +151,7 @@ class che_불가침파기제의 extends Command\NationCommand{
|
||||
$validUntil->add(new \DateInterval("PT{$validMinutes}M"));
|
||||
|
||||
$msg = new DiplomaticMessage(
|
||||
Message::MSGTYPE_DIPLOMACY,
|
||||
MessageType::diplomacy,
|
||||
$src,
|
||||
$dest,
|
||||
"{$nationName}의 불가침 파기 제의 서신",
|
||||
|
||||
@@ -21,6 +21,7 @@ use function \sammo\GetImageURL;
|
||||
|
||||
use \sammo\Constraint\Constraint;
|
||||
use \sammo\Constraint\ConstraintHelper;
|
||||
use sammo\Enums\MessageType;
|
||||
|
||||
class che_선전포고 extends Command\NationCommand
|
||||
{
|
||||
@@ -175,7 +176,7 @@ class che_선전포고 extends Command\NationCommand
|
||||
$destNation['color']
|
||||
);
|
||||
$msg = new Message(
|
||||
Message::MSGTYPE_NATIONAL,
|
||||
MessageType::national,
|
||||
$src,
|
||||
$dest,
|
||||
$text,
|
||||
|
||||
@@ -20,6 +20,7 @@ use function \sammo\GetImageURL;
|
||||
|
||||
use \sammo\Constraint\Constraint;
|
||||
use \sammo\Constraint\ConstraintHelper;
|
||||
use sammo\Enums\MessageType;
|
||||
|
||||
class che_종전제의 extends Command\NationCommand{
|
||||
static protected $actionName = '종전 제의';
|
||||
@@ -148,7 +149,7 @@ class che_종전제의 extends Command\NationCommand{
|
||||
$validUntil->add(new \DateInterval("PT{$validMinutes}M"));
|
||||
|
||||
$msg = new DiplomaticMessage(
|
||||
Message::MSGTYPE_DIPLOMACY,
|
||||
MessageType::diplomacy,
|
||||
$src,
|
||||
$dest,
|
||||
"{$nationName}의 종전 제의 서신",
|
||||
|
||||
@@ -171,6 +171,9 @@ class che_초토화 extends Command\NationCommand{
|
||||
'pop'=>$db->sqleval('greatest(pop_max*0.1, pop*0.2)'),
|
||||
'agri'=>$db->sqleval('greatest(agri_max*0.1, agri*0.2)'),
|
||||
'comm'=>$db->sqleval('greatest(comm_max*0.1, comm*0.2)'),
|
||||
'secu'=>$db->sqleval('greatest(secu_max*0.1, secu*0.2)'),
|
||||
'def'=>$db->sqleval('greatest(def_max*0.1, def*0.2)'),
|
||||
'wall'=>$db->sqleval('greatest(wall_max*0.1, wall*0.5)'),
|
||||
'nation'=>0,
|
||||
'front'=>0,
|
||||
'conflict'=>'{}'
|
||||
|
||||
@@ -59,6 +59,9 @@ class che_피장파장 extends Command\NationCommand
|
||||
if (!in_array($commandType, GameConst::$availableChiefCommand['전략'])) {
|
||||
return false;
|
||||
}
|
||||
if($commandType == Util::getClassNameFromObj($this)){
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
$this->arg = [
|
||||
@@ -75,7 +78,7 @@ class che_피장파장 extends Command\NationCommand
|
||||
$env = $this->env;
|
||||
|
||||
$this->setCity();
|
||||
$this->setNation();
|
||||
$this->setNation(['strategic_cmd_limit']);
|
||||
|
||||
$this->minConditionConstraints = [
|
||||
ConstraintHelper::OccupiedCity(),
|
||||
@@ -113,6 +116,7 @@ class che_피장파장 extends Command\NationCommand
|
||||
[0, 1],
|
||||
'선포, 전쟁중인 상대국에게만 가능합니다.'
|
||||
),
|
||||
ConstraintHelper::AvailableStrategicCommand(),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -120,8 +124,9 @@ class che_피장파장 extends Command\NationCommand
|
||||
{
|
||||
$name = $this->getName();
|
||||
$reqTurn = $this->getPreReqTurn() + 1;
|
||||
$postReqTurn = $this->getPostReqTurn();
|
||||
|
||||
return "{$name}/{$reqTurn}턴(대상 재사용 대기 {$this->getTargetPostReqTurn()})";
|
||||
return "{$name}/{$reqTurn}턴(재사용 대기 $postReqTurn, 대상 재사용 대기 {$this->getTargetPostReqTurn()})";
|
||||
}
|
||||
|
||||
public function getCost(): array
|
||||
@@ -136,7 +141,7 @@ class che_피장파장 extends Command\NationCommand
|
||||
|
||||
public function getPostReqTurn(): int
|
||||
{
|
||||
return 0;
|
||||
return 8;
|
||||
}
|
||||
|
||||
public function getTargetPostReqTurn(): int
|
||||
@@ -251,7 +256,13 @@ class che_피장파장 extends Command\NationCommand
|
||||
|
||||
$oneAvailableCommandName = null;
|
||||
|
||||
$thisClassName = Util::getClassNameFromObj($this);
|
||||
|
||||
foreach (GameConst::$availableChiefCommand['전략'] as $commandType) {
|
||||
if($commandType == $thisClassName){
|
||||
continue;
|
||||
}
|
||||
|
||||
$cmd = buildNationCommandClass($commandType, $generalObj, $this->env, new LastTurn());
|
||||
$cmdName = $cmd->getName();
|
||||
$remainTurn = 0;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<?php
|
||||
namespace sammo;
|
||||
|
||||
use sammo\Enums\MessageType;
|
||||
|
||||
class DiplomaticMessage extends Message{
|
||||
|
||||
const ACCEPTED = 1;
|
||||
@@ -18,7 +20,7 @@ class DiplomaticMessage extends Message{
|
||||
protected $validDiplomacy = true;
|
||||
|
||||
public function __construct(
|
||||
string $msgType,
|
||||
MessageType $msgType,
|
||||
MessageTarget $src,
|
||||
MessageTarget $dest,
|
||||
string $msg,
|
||||
@@ -27,7 +29,7 @@ class DiplomaticMessage extends Message{
|
||||
array $msgOption
|
||||
)
|
||||
{
|
||||
if ($msgType !== self::MSGTYPE_DIPLOMACY){
|
||||
if ($msgType !== MessageType::diplomacy){
|
||||
throw new \InvalidArgumentException('DiplomaticMessage msgType');
|
||||
}
|
||||
|
||||
@@ -208,7 +210,7 @@ class DiplomaticMessage extends Message{
|
||||
|
||||
$josaYi = JosaUtil::pick($this->src->nationName, '이');
|
||||
$newMsg = new Message(
|
||||
self::MSGTYPE_NATIONAL,
|
||||
MessageType::national,
|
||||
$this->dest,
|
||||
$this->src,
|
||||
"【외교】{$year}년 {$month}월: {$this->src->nationName}{$josaYi} {$this->dest->nationName}에게 제안한 {$this->diplomacyDetail}",
|
||||
@@ -224,7 +226,7 @@ class DiplomaticMessage extends Message{
|
||||
$newMsg->send();
|
||||
|
||||
$newMsg = new Message(
|
||||
self::MSGTYPE_DIPLOMACY,
|
||||
MessageType::diplomacy,
|
||||
$this->dest,
|
||||
$this->src,
|
||||
"【외교】{$year}년 {$month}월: {$this->src->nationName}{$josaYi} {$this->dest->nationName}에게 제안한 {$this->diplomacyDetail}",
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace sammo\Enums;
|
||||
|
||||
enum MessageType: string
|
||||
{
|
||||
case private = 'private';
|
||||
case public = 'public';
|
||||
case national = 'national';
|
||||
case diplomacy = 'diplomacy';
|
||||
//TODO: System을 정식으로 추가해야함.
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace sammo\Event\Action;
|
||||
|
||||
use sammo\DB;
|
||||
|
||||
class AddGlobalBetray extends \sammo\Event\Action
|
||||
{
|
||||
public function __construct(private int $cnt = 1, private int $ifMax = 0)
|
||||
{
|
||||
}
|
||||
|
||||
public function run(array $env)
|
||||
{
|
||||
$db = DB::db();
|
||||
$db->update('general', [
|
||||
'betray' => $db->sqleval('betray + %i', $this->cnt),
|
||||
], 'betray <= %i', $this->ifMax);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
namespace sammo\Event\Action;
|
||||
|
||||
use sammo\ActionLogger;
|
||||
use sammo\CityConst;
|
||||
use sammo\DB;
|
||||
use sammo\KVStorage;
|
||||
use sammo\Util;
|
||||
use sammo\General;
|
||||
use sammo\JosaUtil;
|
||||
use sammo\LiteHashDRBG;
|
||||
use sammo\RandUtil;
|
||||
use sammo\UniqueConst;
|
||||
|
||||
class LostUniqueItem extends \sammo\Event\Action
|
||||
{
|
||||
public function __construct(
|
||||
private float $lostProb = 0.1,
|
||||
) {
|
||||
}
|
||||
|
||||
public function run(array $env)
|
||||
{
|
||||
$db = DB::db();
|
||||
|
||||
$generalIDList = $db->queryFirstColumn("SELECT `no` FROM general WHERE npc <= 1");
|
||||
if (!$generalIDList) {
|
||||
return;
|
||||
}
|
||||
$generals = General::createGeneralObjListFromDB($generalIDList);
|
||||
|
||||
$lostItems = [];
|
||||
$totalLostCnt = 0;
|
||||
|
||||
$year = $env['year'];
|
||||
$month = $env['month'];
|
||||
$rng = new RandUtil(new LiteHashDRBG(Util::simpleSerialize(
|
||||
UniqueConst::$hiddenSeed,
|
||||
'LostUniqueItem',
|
||||
$year,
|
||||
$month,
|
||||
)));
|
||||
|
||||
$maxLostByGenCnt = 0;
|
||||
$maxLostGenList = [];
|
||||
|
||||
foreach ($generals as $general) {
|
||||
$itemList = $general->getItems();
|
||||
$didLoseItem = false;
|
||||
$lostByGenCnt = 0;
|
||||
|
||||
foreach ($itemList as $itemType => $item) {
|
||||
if ($item->isBuyable()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
$logger = $general->getLogger();
|
||||
|
||||
if ($rng->nextBool($this->lostProb)) {
|
||||
$itemName = $item->getName();
|
||||
$itemRawName = $item->getRawName();
|
||||
$josaUl = JosaUtil::pick($itemRawName, '을');
|
||||
$lostItems[$itemName] = 1;
|
||||
$totalLostCnt++;
|
||||
$lostByGenCnt++;
|
||||
$general->setItem($itemType, 'None');
|
||||
$didLoseItem = true;
|
||||
$logger->pushGeneralActionLog("<C>{$itemName}</>{$josaUl} 잃었습니다.");
|
||||
}
|
||||
}
|
||||
|
||||
if (!$didLoseItem) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$general->applyDB($db);
|
||||
|
||||
if ($maxLostByGenCnt < $lostByGenCnt) {
|
||||
$maxLostByGenCnt = $lostByGenCnt;
|
||||
$maxLostGenList = [$general->getName()];
|
||||
} else if ($maxLostByGenCnt === $lostByGenCnt) {
|
||||
$maxLostGenList[] = $general->getName();
|
||||
}
|
||||
}
|
||||
|
||||
$logger = new ActionLogger(0, 0, $year, $month);
|
||||
if ($totalLostCnt == 0) {
|
||||
$logger->pushGlobalHistoryLog("<R><b>【망실】</b></>어떤 아이템도 잃지 않았습니다!");
|
||||
} else {
|
||||
$genCnt = count($maxLostGenList);
|
||||
if($genCnt > 4){
|
||||
$maxLostGenList = array_slice($maxLostGenList, 0, 4);
|
||||
|
||||
}
|
||||
$maxLostGenListStr = implode(', ', $maxLostGenList);
|
||||
|
||||
if($genCnt > 4){
|
||||
$maxLostGenListStr .= ' 외 ' . ($genCnt - 4) . '명';
|
||||
}
|
||||
$josaYi = JosaUtil::pick($maxLostGenListStr, '이');
|
||||
|
||||
$logger->pushGlobalHistoryLog("<R><b>【망실】</b></>불운하게도 <Y>{$maxLostGenListStr}</>{$josaYi} 한 번에 유니크 <C>{$maxLostByGenCnt}</>종을 잃었습니다! (총 <C>{$totalLostCnt}</>개)");
|
||||
}
|
||||
$logger->flush();
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ use \sammo\Util;
|
||||
use \sammo\DB;
|
||||
use sammo\DTO\BettingInfo;
|
||||
use sammo\DTO\SelectItem;
|
||||
use sammo\Enums\MessageType;
|
||||
use sammo\Json;
|
||||
use sammo\KVStorage;
|
||||
use sammo\Message;
|
||||
@@ -138,7 +139,7 @@ class OpenNationBetting extends \sammo\Event\Action
|
||||
GetImageURL($general['imgsvr'], $general['picture'])
|
||||
);
|
||||
$msg = new Message(
|
||||
Message::MSGTYPE_PRIVATE,
|
||||
MessageType::private,
|
||||
$src,
|
||||
$dest,
|
||||
$text,
|
||||
|
||||
@@ -46,6 +46,8 @@ class GameConstBase
|
||||
public static $sabotageDefaultProb = 0.35;
|
||||
/** @var int 계략시 확률 가중치(수치가 클수록 변화가 적음 : (지력차/$firing + $basefiring)*/
|
||||
public static $sabotageProbCoefByStat = 300;
|
||||
/** @var float 인원수 별 계략 방어 가중치 */
|
||||
public static $sabotageDefenceCoefByGeneralCnt = 0.04;
|
||||
/** @var int 계략시 최소 수치 감소량*/
|
||||
public static $sabotageDamageMin = 100;
|
||||
/** @var int 계략시 최대 수치 감소량*/
|
||||
@@ -202,6 +204,11 @@ class GameConstBase
|
||||
[20, 4]
|
||||
];
|
||||
|
||||
public static $minTurnDieOnPrestart = 2;
|
||||
|
||||
public static $uniqueTrialCoef = 1;
|
||||
public static $maxUniqueTrialProb = 0.25;
|
||||
|
||||
public static $maxAvailableWarSettingCnt = 10;
|
||||
public static $incAvailableWarSettingCnt = 2;
|
||||
|
||||
@@ -368,9 +375,9 @@ class GameConstBase
|
||||
'che_의병모집',
|
||||
'che_이호경식',
|
||||
'che_급습',
|
||||
'che_피장파장',
|
||||
],
|
||||
'기타' => [
|
||||
'che_피장파장',
|
||||
'che_국기변경',
|
||||
'che_국호변경',
|
||||
]
|
||||
@@ -431,5 +438,13 @@ class GameConstBase
|
||||
["NoticeToHistoryLog", "<S>출병 제한이 풀렸습니다.</>", ActionLogger::EVENT_YEAR_MONTH],
|
||||
["DeleteEvent"]
|
||||
],
|
||||
[
|
||||
"month", 2000,
|
||||
["DateRelative", "==", 4, 1],
|
||||
["NoticeToHistoryLog", "<S>이제부터 하야, 망명시 패널티가 적용됩니다.</>", ActionLogger::EVENT_YEAR_MONTH],
|
||||
["AddGlobalBetray", 1, 0],
|
||||
["AddGlobalBetray", 1, 1],
|
||||
["DeleteEvent"]
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -115,16 +115,16 @@ class GameUnitConstBase{
|
||||
[self::T_CAVALRY=>1.2, self::T_FOOTMAN=>0.8, self::T_SIEGE=>1.2],
|
||||
[self::T_CAVALRY=>0.8, self::T_FOOTMAN=>1.2, self::T_SIEGE=>0.8],
|
||||
['표준적인 궁병입니다.','궁병은 선제사격을 하는 병종입니다.'],
|
||||
null, ['che_궁병선제사격']
|
||||
null, ['che_선제사격시도', 'che_선제사격발동']
|
||||
],
|
||||
[
|
||||
1201, self::T_ARCHER, '궁기병',
|
||||
100, 100, 8, 20, 0, 11, 12,
|
||||
1000, null, ['동이'], 0,
|
||||
[self::T_CAVALRY=>1.2, self::T_FOOTMAN=>0.8, self::T_SIEGE=>1.2],
|
||||
[self::T_CAVALRY=>0.8, self::T_FOOTMAN=>1.2, self::T_SIEGE=>0.8],
|
||||
['말을 타고 잘 피합니다.'],
|
||||
null, ['che_궁병선제사격']
|
||||
[self::T_CAVALRY=>1.2, self::T_FOOTMAN=>0.9, self::T_SIEGE=>1.2],
|
||||
[self::T_CAVALRY=>0.8, self::T_FOOTMAN=>1.1, self::T_SIEGE=>0.8],
|
||||
['말을 타고 잘 피합니다. 특히 다른 궁병보다 보병에게 조금 더 강합니다.'],
|
||||
null, ['che_선제사격시도', 'che_선제사격발동']
|
||||
],
|
||||
[
|
||||
1202, self::T_ARCHER, '연노병',
|
||||
@@ -133,7 +133,7 @@ class GameUnitConstBase{
|
||||
[self::T_CAVALRY=>1.2, self::T_FOOTMAN=>0.8, self::T_SIEGE=>1.2],
|
||||
[self::T_CAVALRY=>0.8, self::T_FOOTMAN=>1.2, self::T_SIEGE=>0.8],
|
||||
['화살을 연사합니다.'],
|
||||
null, ['che_궁병선제사격']
|
||||
null, ['che_선제사격시도', 'che_선제사격발동']
|
||||
],
|
||||
[
|
||||
1203, self::T_ARCHER, '강궁병',
|
||||
@@ -142,7 +142,7 @@ class GameUnitConstBase{
|
||||
[self::T_CAVALRY=>1.2, self::T_FOOTMAN=>0.8, self::T_SIEGE=>1.2],
|
||||
[self::T_CAVALRY=>0.8, self::T_FOOTMAN=>1.2, self::T_SIEGE=>0.8],
|
||||
['강건한 궁병입니다.'],
|
||||
null, ['che_궁병선제사격']
|
||||
null, ['che_선제사격시도', 'che_선제사격발동']
|
||||
],
|
||||
[
|
||||
1204, self::T_ARCHER, '석궁병',
|
||||
@@ -151,7 +151,7 @@ class GameUnitConstBase{
|
||||
[self::T_CAVALRY=>1.2, self::T_FOOTMAN=>0.8, self::T_SIEGE=>1.2],
|
||||
[self::T_CAVALRY=>0.8, self::T_FOOTMAN=>1.2, self::T_SIEGE=>0.8],
|
||||
['강력한 화살을 쏩니다.'],
|
||||
null, ['che_궁병선제사격']
|
||||
null, ['che_선제사격시도', 'che_선제사격발동']
|
||||
],
|
||||
|
||||
[
|
||||
@@ -316,7 +316,7 @@ class GameUnitConstBase{
|
||||
[self::T_FOOTMAN=>1.25, self::T_ARCHER=>1.25, self::T_CAVALRY=>1.25, self::T_WIZARD=>1.25, self::T_CASTLE=>1.8, 1106=>1.112],
|
||||
[self::T_FOOTMAN=>1.2, self::T_ARCHER=>1.2, self::T_CAVALRY=>1.2, self::T_WIZARD=>1.2],
|
||||
['높은 구조물 위에서 공격합니다.'],
|
||||
['che_성벽부상무효'], null
|
||||
['che_성벽부상무효'], ['che_선제사격시도', 'che_선제사격발동']
|
||||
],
|
||||
[
|
||||
1501, self::T_SIEGE, '충차',
|
||||
@@ -329,19 +329,19 @@ class GameUnitConstBase{
|
||||
],
|
||||
[
|
||||
1502, self::T_SIEGE, '벽력거',
|
||||
200, 100, 6, 5, 0, 20, 5,
|
||||
150, 100, 6, 5, 0, 20, 5,
|
||||
3000, ['업'], null, 0,
|
||||
[self::T_FOOTMAN=>1.25, self::T_ARCHER=>1.25, self::T_CAVALRY=>1.25, self::T_WIZARD=>1.25, self::T_CASTLE=>1.8, 1106=>1.112],
|
||||
[self::T_FOOTMAN=>0.833, self::T_ARCHER=>0.833, self::T_CAVALRY=>0.833, self::T_WIZARD=>0.833, 1106=>0.909],
|
||||
['상대에게 돌덩이를 날립니다.'],
|
||||
['che_성벽부상무효'], null
|
||||
['che_성벽부상무효'], ['che_선제사격시도', 'che_선제사격발동']
|
||||
],
|
||||
[
|
||||
1503, self::T_SIEGE, '목우',
|
||||
50, 200, 5, 0, 0, 15, 5,
|
||||
3000, ['성도'], null, 0,
|
||||
[self::T_FOOTMAN=>1.25, self::T_ARCHER=>1.25, self::T_CAVALRY=>1.25, self::T_WIZARD=>1.25, self::T_CASTLE=>1.8, 1106=>1.112],
|
||||
[self::T_FOOTMAN=>0.833, self::T_ARCHER=>0.833, self::T_CAVALRY=>0.833, self::T_WIZARD=>0.833, 1106=>0.909],
|
||||
[self::T_FOOTMAN=>1, self::T_ARCHER=>1, self::T_CAVALRY=>1, self::T_WIZARD=>1, 1106=>1],
|
||||
['상대를 저지하는 특수병기입니다.'],
|
||||
['che_성벽부상무효'], ['che_저지시도', 'che_저지발동']
|
||||
]
|
||||
|
||||
@@ -626,7 +626,6 @@ class General implements iAction
|
||||
$inheritPointManager = InheritancePointManager::getInstance();
|
||||
$inheritPointManager->mergeTotalInheritancePoint($this);
|
||||
$inheritPointManager->applyInheritanceUser($this->getVar('owner'));
|
||||
$inheritPointManager->clearInheritancePoint($this);
|
||||
}
|
||||
|
||||
|
||||
@@ -666,6 +665,8 @@ class General implements iAction
|
||||
'reserved_until' => null,
|
||||
], 'general_id=%i', $generalID);
|
||||
|
||||
storeOldGeneral($generalID, $logger->getYear(), $logger->getMonth());
|
||||
|
||||
$db->delete('general', 'no=%i', $generalID);
|
||||
$db->delete('general_turn', 'general_id=%i', $generalID);
|
||||
$db->delete('rank_data', 'general_id=%i', $generalID);
|
||||
@@ -686,9 +687,8 @@ class General implements iAction
|
||||
|
||||
$ownerID = $this->getVar('owner');
|
||||
if ($ownerID) {
|
||||
$inheritPointManager->mergeTotalInheritancePoint($this);
|
||||
$inheritPointManager->mergeTotalInheritancePoint($this, true);
|
||||
$inheritPointManager->applyInheritanceUser($ownerID, true);
|
||||
$inheritPointManager->clearInheritancePoint($this);
|
||||
}
|
||||
|
||||
$this->multiplyVarWithLimit('leadership', 0.85, 10);
|
||||
@@ -1331,8 +1331,8 @@ class General implements iAction
|
||||
return InheritancePointManager::getInstance()->increaseInheritancePoint($this, $key, $value, $aux);
|
||||
}
|
||||
|
||||
public function mergeTotalInheritancePoint(bool $isEnd = false)
|
||||
public function mergeTotalInheritancePoint(bool $isRebirth = false)
|
||||
{
|
||||
InheritancePointManager::getInstance()->mergeTotalInheritancePoint($this, $isEnd);
|
||||
InheritancePointManager::getInstance()->mergeTotalInheritancePoint($this, $isRebirth);
|
||||
}
|
||||
}
|
||||
|
||||
+64
-35
@@ -4,6 +4,7 @@ namespace sammo;
|
||||
|
||||
use sammo\Command\GeneralCommand;
|
||||
use sammo\Command\NationCommand;
|
||||
use sammo\Enums\MessageType;
|
||||
use sammo\Enums\RankColumn;
|
||||
use sammo\Scenario\NPC;
|
||||
|
||||
@@ -11,8 +12,6 @@ class GeneralAI
|
||||
{
|
||||
protected RandUtil $rng;
|
||||
|
||||
/** @var General */
|
||||
protected $general;
|
||||
protected array $city;
|
||||
protected array $nation;
|
||||
protected int $genType;
|
||||
@@ -65,6 +64,9 @@ class GeneralAI
|
||||
/** @var General[] */
|
||||
protected $chiefGenerals;
|
||||
|
||||
/** @var bool */
|
||||
protected $reqUpdateInstance = true;
|
||||
|
||||
/** @var General[] */
|
||||
protected $lostGenerals;
|
||||
/** @var General[] 이번 턴에 '집합'하는 부대장 목록 */
|
||||
@@ -80,15 +82,16 @@ class GeneralAI
|
||||
const d직전 = 3;
|
||||
const d전쟁 = 4;
|
||||
|
||||
//수뇌용
|
||||
protected function updateInstance(): void{
|
||||
if(!$this->reqUpdateInstance){
|
||||
return;
|
||||
}
|
||||
|
||||
$this->reqUpdateInstance = false;
|
||||
|
||||
public function __construct(General $general)
|
||||
{
|
||||
$db = DB::db();
|
||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||
$this->env = $gameStor->getAll(true);
|
||||
$this->baseDevelCost = $this->env['develcost'] * 12;
|
||||
$this->general = $general;
|
||||
$general = $this->general;
|
||||
$city = $general->getRawCity();
|
||||
if ($city === null) {
|
||||
$city = $db->queryFirstRow('SELECT * FROM city WHERE city = %i', $general->getCityID());
|
||||
@@ -96,14 +99,6 @@ class GeneralAI
|
||||
}
|
||||
$this->city = $city;
|
||||
|
||||
$this->rng = new RandUtil(new LiteHashDRBG(Util::simpleSerialize(
|
||||
UniqueConst::$hiddenSeed,
|
||||
'GeneralAI',
|
||||
$this->env['year'],
|
||||
$this->env['month'],
|
||||
$general->getID(),
|
||||
)));
|
||||
|
||||
$this->nation = $db->queryFirstRow(
|
||||
'SELECT nation,name,color,capital,capset,gennum,gold,rice,bill,rate,rate_tmp,scout,war,strategic_cmd_limit,surlimit,tech,power,level,chief_set,type,aux FROM nation WHERE nation = %i',
|
||||
$general->getNationID()
|
||||
@@ -123,8 +118,8 @@ class GeneralAI
|
||||
$nationStor = KVStorage::getStorage($db, $this->nation['nation'], 'nation_env');
|
||||
$nationStor->cacheValues(['npc_nation_policy', 'npc_general_policy', 'prev_income_gold', 'prev_income_rice']);
|
||||
|
||||
$this->nationPolicy = new AutorunNationPolicy($general, $this->env['autorun_user']['options'] ?? null, $nationStor->getValue('npc_nation_policy'), $gameStor->getValue('npc_nation_policy'), $this->nation, $this->env);
|
||||
$this->generalPolicy = new AutorunGeneralPolicy($general, $this->env['autorun_user']['options'] ?? null, $nationStor->getValue('npc_general_policy'), $gameStor->getValue('npc_general_policy'), $this->nation, $this->env);
|
||||
$this->nationPolicy = new AutorunNationPolicy($general, $this->env['autorun_user']['options'] ?? null, $nationStor->getValue('npc_nation_policy'), ($this->env['npc_nation_policy']) ?? null, $this->nation, $this->env);
|
||||
$this->generalPolicy = new AutorunGeneralPolicy($general, $this->env['autorun_user']['options'] ?? null, $nationStor->getValue('npc_general_policy'), ($this->env['npc_general_policy']) ?? null, $this->nation, $this->env);
|
||||
|
||||
$prevIncomeGold = $nationStor->prev_income_gold ?? 1000;
|
||||
$prevIncomeRice = $nationStor->prev_income_rice ?? 1000;
|
||||
@@ -142,6 +137,25 @@ class GeneralAI
|
||||
|
||||
$this->nation['aux'] = Json::decode($this->nation['aux'] ?? '{}');
|
||||
|
||||
$this->calcDiplomacyState();
|
||||
|
||||
$this->genType = $this->calcGenType($general);
|
||||
}
|
||||
|
||||
public function __construct(protected General $general)
|
||||
{
|
||||
$db = DB::db();
|
||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||
$this->env = $gameStor->getAll(true);
|
||||
|
||||
$this->rng = new RandUtil(new LiteHashDRBG(Util::simpleSerialize(
|
||||
UniqueConst::$hiddenSeed,
|
||||
'GeneralAI',
|
||||
$this->env['year'],
|
||||
$this->env['month'],
|
||||
$general->getID(),
|
||||
)));
|
||||
|
||||
$this->leadership = $general->getLeadership();
|
||||
$this->strength = $general->getStrength();
|
||||
$this->intel = $general->getIntel();
|
||||
@@ -149,11 +163,6 @@ class GeneralAI
|
||||
$this->fullLeadership = $general->getLeadership(false);
|
||||
$this->fullStrength = $general->getStrength(false);
|
||||
$this->fullIntel = $general->getIntel(false);
|
||||
|
||||
|
||||
$this->genType = $this->calcGenType($general);
|
||||
|
||||
$this->calcDiplomacyState();
|
||||
}
|
||||
|
||||
public function getGeneralObj(): General
|
||||
@@ -572,6 +581,9 @@ class GeneralAI
|
||||
if ($userGeneral->getVar('crew') >= $this->nationPolicy->minWarCrew) {
|
||||
continue;
|
||||
}
|
||||
if ($userGeneral->onCalcDomestic('징집인구', 'score', 100) <= 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$generalTurnTime = $userGeneral->getTurnTime();
|
||||
$troopTurnTime = $troopLeader->getTurnTime();
|
||||
@@ -665,6 +677,9 @@ class GeneralAI
|
||||
if ($userGeneral->getVar('crew') >= $this->nationPolicy->minWarCrew) {
|
||||
continue;
|
||||
}
|
||||
if ($userGeneral->onCalcDomestic('징집인구', 'score', 100) <= 1) {
|
||||
continue;
|
||||
}
|
||||
$generalCadidates[$generalID] = $userGeneral;
|
||||
}
|
||||
|
||||
@@ -678,10 +693,8 @@ class GeneralAI
|
||||
|
||||
/** @var General */
|
||||
$pickedGeneral = $this->rng->choice($generalCadidates);
|
||||
$minRecruitPop = $this->fullLeadership * 100 + GameConst::$minAvailableRecruitPop;
|
||||
if (!$this->generalPolicy->can한계징병) {
|
||||
$minRecruitPop = max($minRecruitPop, $this->fullLeadership * 100 + $this->nationPolicy->minNPCRecruitCityPopulation);
|
||||
}
|
||||
$pickedGeneralLeadership = $pickedGeneral->getLeadership(false, true, true, true);
|
||||
$minRecruitPop = $pickedGeneralLeadership * 100 + GameConst::$minAvailableRecruitPop;
|
||||
|
||||
$recruitableCityList = [];
|
||||
|
||||
@@ -964,6 +977,9 @@ class GeneralAI
|
||||
if ($npcGeneral->getVar('crew') >= $this->nationPolicy->minWarCrew) {
|
||||
continue;
|
||||
}
|
||||
if ($npcGeneral->onCalcDomestic('징집인구', 'score', 100) <= 1) {
|
||||
continue;
|
||||
}
|
||||
$generalCadidates[$generalID] = $npcGeneral;
|
||||
}
|
||||
|
||||
@@ -977,10 +993,9 @@ class GeneralAI
|
||||
|
||||
/** @var General */
|
||||
$pickedGeneral = $this->rng->choice($generalCadidates);
|
||||
$minRecruitPop = $this->fullLeadership * 100 + GameConst::$minAvailableRecruitPop;
|
||||
if (!$this->generalPolicy->can한계징병) {
|
||||
$minRecruitPop = max($minRecruitPop, $this->fullLeadership * 100 + $this->nationPolicy->minNPCRecruitCityPopulation);
|
||||
}
|
||||
$pickedGeneralLeadership = $pickedGeneral->getLeadership(false, true, true, true);
|
||||
$minRecruitPop = $pickedGeneralLeadership * 100 + GameConst::$minAvailableRecruitPop;
|
||||
$minRecruitPop = max($minRecruitPop, $pickedGeneralLeadership * 100 + $this->nationPolicy->minNPCRecruitCityPopulation);
|
||||
|
||||
$recruitableCityList = [];
|
||||
|
||||
@@ -1289,6 +1304,7 @@ class GeneralAI
|
||||
return null;
|
||||
}
|
||||
|
||||
$this->reqUpdateInstance = true;
|
||||
return $cmd;
|
||||
}
|
||||
|
||||
@@ -1489,6 +1505,7 @@ class GeneralAI
|
||||
return null;
|
||||
}
|
||||
|
||||
$this->reqUpdateInstance = true;
|
||||
return $cmd;
|
||||
}
|
||||
|
||||
@@ -1951,6 +1968,7 @@ class GeneralAI
|
||||
return null;
|
||||
}
|
||||
|
||||
$this->reqUpdateInstance = true;
|
||||
return $cmd;
|
||||
}
|
||||
|
||||
@@ -1968,6 +1986,7 @@ class GeneralAI
|
||||
$cmd = buildNationCommandClass('che_천도', $this->general, $this->env, $lastTurn, $lastTurn->getArg());
|
||||
if ($cmd->hasFullConditionMet()) {
|
||||
$nationStor->last천도Trial = [$general->getVar('officer_level'), $general->getTurnTime()];
|
||||
$this->reqUpdateInstance = true;
|
||||
return $cmd;
|
||||
}
|
||||
}
|
||||
@@ -2090,6 +2109,7 @@ class GeneralAI
|
||||
|
||||
|
||||
$nationStor->last천도Trial = [$general->getVar('officer_level'), $general->getTurnTime()];
|
||||
$this->reqUpdateInstance = true;
|
||||
return $cmd;
|
||||
}
|
||||
|
||||
@@ -2653,7 +2673,7 @@ class GeneralAI
|
||||
return $this->rng->choiceUsingWeightPair($cmdList);
|
||||
}
|
||||
|
||||
public function do소집해제(): ?GeneralCommand
|
||||
protected function do소집해제(): ?GeneralCommand
|
||||
{
|
||||
if ($this->attackable) {
|
||||
return null;
|
||||
@@ -2972,6 +2992,9 @@ class GeneralAI
|
||||
}
|
||||
|
||||
foreach ($this->frontCities as $frontCity) {
|
||||
if(!$frontCity['supply']){
|
||||
continue;
|
||||
}
|
||||
$candidateCities[$frontCity['city']] = $frontCity['important'];
|
||||
}
|
||||
|
||||
@@ -3454,7 +3477,7 @@ class GeneralAI
|
||||
}
|
||||
if ($nationCity['front']) {
|
||||
$frontCities[$cityID] = $nationCity;
|
||||
} else {
|
||||
} else if($nationCity['supply']) {
|
||||
$backupCities[$cityID] = $nationCity;
|
||||
}
|
||||
|
||||
@@ -3532,7 +3555,7 @@ class GeneralAI
|
||||
} else if ($nationGeneral->getVar('troop') === $generalID && $nationGeneral->getReservedTurn(0, $this->env)->getName() === 'che_집합') {
|
||||
//비 NPC부대장임
|
||||
$troopLeaders[$generalID] = $nationGeneral;
|
||||
} else if ($nationGeneral->getVar('killturn') < 5) {
|
||||
} else if ($nationGeneral->getVar('killturn') <= 5) {
|
||||
//삭턴이 몇 안남은 장수는 '내정장 npc'로 처리
|
||||
$npcCivilGenerals[$generalID] = $nationGeneral;
|
||||
} else if ($npcType < 2) {
|
||||
@@ -3570,6 +3593,8 @@ class GeneralAI
|
||||
|
||||
public function chooseNationTurn(NationCommand $reservedCommand): NationCommand
|
||||
{
|
||||
$this->updateInstance();
|
||||
|
||||
//TODO: NationTurn과 InstantNationTurn 구분 필요
|
||||
$lastTurn = $reservedCommand->getLastTurn();
|
||||
$general = $this->general;
|
||||
@@ -3641,6 +3666,8 @@ class GeneralAI
|
||||
return $reservedCommand;
|
||||
}
|
||||
|
||||
$this->updateInstance();
|
||||
|
||||
foreach ($this->nationPolicy->priority as $actionName) {
|
||||
/** @var ?NationCommand */
|
||||
if (!key_exists($actionName, $this->nationPolicy::$availableInstantTurn)) {
|
||||
@@ -3663,6 +3690,8 @@ class GeneralAI
|
||||
$npcType = $general->getNPCType();
|
||||
$nationID = $general->getNationID();
|
||||
|
||||
$this->updateInstance();
|
||||
|
||||
//특별 메세지 있는 경우 출력
|
||||
$term = $this->env['turnterm'];
|
||||
if ($general->getVar('npcmsg') && $this->rng->nextBool(GameConst::$npcMessageFreqByDay * $term / (60 * 24))) {
|
||||
@@ -3675,7 +3704,7 @@ class GeneralAI
|
||||
GetImageURL($general->getVar('imgsvr'), $general->getVar('picture'))
|
||||
);
|
||||
$msg = new Message(
|
||||
Message::MSGTYPE_PUBLIC,
|
||||
MessageType::public,
|
||||
$src,
|
||||
$src,
|
||||
$general->getVar('npcmsg'),
|
||||
|
||||
@@ -23,8 +23,9 @@ class che_병력군량소모 extends BaseGeneralTrigger{
|
||||
}
|
||||
else{
|
||||
$db = DB::db();
|
||||
$crewUp = $general->onCalcDomestic('징집인구', 'score', $general->getVar('crew'));
|
||||
$db->update('city', [
|
||||
'pop'=>$db->sqleval('pop + %i', $general->getVar('crew'))
|
||||
'pop'=>$db->sqleval('pop + %i', $crewUp)
|
||||
], 'city=%i', $general->getCityID());
|
||||
|
||||
$general->setVar('crew', 0);
|
||||
|
||||
@@ -17,18 +17,18 @@ class InheritancePointManager
|
||||
private function __construct()
|
||||
{
|
||||
$inheritanceKey = new Map();
|
||||
$inheritanceKey->put(InheritanceKey::previous, new InheritancePointType(true, 1, '기존 포인트'));
|
||||
$inheritanceKey->put(InheritanceKey::lived_month, new InheritancePointType(true, 1, '생존'));
|
||||
$inheritanceKey->put(InheritanceKey::max_belong, new InheritancePointType(false, 10, '최대 임관년 수'));
|
||||
$inheritanceKey->put(InheritanceKey::max_domestic_critical, new InheritancePointType(true, 1, '최대 연속 내정 성공'));
|
||||
$inheritanceKey->put(InheritanceKey::active_action, new InheritancePointType(true, 3, '능동 행동 수'));
|
||||
$inheritanceKey->put(InheritanceKey::previous, new InheritancePointType(true, 1, '기존 포인트', 1));
|
||||
$inheritanceKey->put(InheritanceKey::lived_month, new InheritancePointType(true, 1, '생존', 1));
|
||||
$inheritanceKey->put(InheritanceKey::max_belong, new InheritancePointType(false, 10, '최대 임관년 수', null));
|
||||
$inheritanceKey->put(InheritanceKey::max_domestic_critical, new InheritancePointType(true, 1, '최대 연속 내정 성공', null));
|
||||
$inheritanceKey->put(InheritanceKey::active_action, new InheritancePointType(true, 3, '능동 행동 수', 1));
|
||||
//$inheritanceKey->put(InheritanceKey::snipe_combat, new InheritancePointType(true, 10, '병종 상성 우위 횟수'));
|
||||
$inheritanceKey->put(InheritanceKey::combat, new InheritancePointType(['rank', RankColumn::warnum], 5, '전투 횟수'));
|
||||
$inheritanceKey->put(InheritanceKey::sabotage, new InheritancePointType(['rank', RankColumn::firenum], 20, '계략 성공 횟수'));
|
||||
$inheritanceKey->put(InheritanceKey::unifier, new InheritancePointType(true, 1, '천통 기여'));
|
||||
$inheritanceKey->put(InheritanceKey::dex, new InheritancePointType(false, 0.001, '숙련도'));
|
||||
$inheritanceKey->put(InheritanceKey::tournament, new InheritancePointType(true, 1, '토너먼트'));
|
||||
$inheritanceKey->put(InheritanceKey::betting, new InheritancePointType(false, 10, '베팅 당첨'));
|
||||
$inheritanceKey->put(InheritanceKey::combat, new InheritancePointType(['rank', RankColumn::warnum], 5, '전투 횟수', 1));
|
||||
$inheritanceKey->put(InheritanceKey::sabotage, new InheritancePointType(['rank', RankColumn::firenum], 20, '계략 성공 횟수', 1));
|
||||
$inheritanceKey->put(InheritanceKey::unifier, new InheritancePointType(true, 1, '천통 기여', null));
|
||||
$inheritanceKey->put(InheritanceKey::dex, new InheritancePointType(false, 0.001, '숙련도', 0.5));
|
||||
$inheritanceKey->put(InheritanceKey::tournament, new InheritancePointType(true, 1, '토너먼트', 1));
|
||||
$inheritanceKey->put(InheritanceKey::betting, new InheritancePointType(false, 10, '베팅 당첨', 1));
|
||||
$this->inheritanceKey = $inheritanceKey;
|
||||
}
|
||||
|
||||
@@ -258,9 +258,8 @@ class InheritancePointManager
|
||||
$inheritStor->setValue($key->value, [$newValue, $aux]);
|
||||
}
|
||||
|
||||
public function clearInheritancePoint(General $general)
|
||||
public function clearInheritancePoint(?int $ownerID)
|
||||
{
|
||||
$ownerID = $general->getVar('owner');
|
||||
if (!$ownerID) {
|
||||
return;
|
||||
}
|
||||
@@ -281,7 +280,7 @@ class InheritancePointManager
|
||||
$inheritStor->setValue(InheritanceKey::previous->value, $previousPointInfo);
|
||||
}
|
||||
|
||||
public function mergeTotalInheritancePoint(General $general, bool $isEnd = false)
|
||||
public function mergeTotalInheritancePoint(General $general, bool $isRebirth = false)
|
||||
{
|
||||
$ownerID = $general->getVar('owner');
|
||||
if (!$ownerID) {
|
||||
@@ -296,7 +295,7 @@ class InheritancePointManager
|
||||
$gameStor->cacheValues(['year', 'startyear', 'month']);
|
||||
|
||||
if ($general->getVar('npc') == 1) {
|
||||
if (!$isEnd) {
|
||||
if ($isRebirth) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -331,18 +330,14 @@ class InheritancePointManager
|
||||
}
|
||||
|
||||
|
||||
function applyInheritanceUser(int $userID, bool $isRebirth = false): float
|
||||
function applyInheritanceUser(int $ownerID, bool $isRebirth = false): float
|
||||
{
|
||||
if ($userID === 0) {
|
||||
if ($ownerID === 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
//FIXME: 굳이 merge, apply, clean 3단계를 거쳐야 할 이유가 없음
|
||||
/** @var Map<InheritanceKey,float> */
|
||||
$rebirthDegraded = new Map();
|
||||
$rebirthDegraded[InheritanceKey::dex] = 0.5;
|
||||
|
||||
$inheritStor = KVStorage::getStorage(DB::db(), "inheritance_{$userID}");
|
||||
$inheritStor = KVStorage::getStorage(DB::db(), "inheritance_{$ownerID}");
|
||||
$totalPoint = 0;
|
||||
/** @var array<string,array{0:float,1:string|float}> */
|
||||
$allPoints = $inheritStor->getAll();
|
||||
@@ -355,15 +350,27 @@ class InheritancePointManager
|
||||
return $allPoints[InheritanceKey::previous->value][0];
|
||||
}
|
||||
|
||||
$userLogger = new UserLogger($userID);
|
||||
$userLogger = new UserLogger($ownerID);
|
||||
|
||||
$previousPoint = ($allPoints[InheritanceKey::previous->value] ?? [0, 0])[0];
|
||||
|
||||
foreach ($allPoints as $rKey => [$value,]) {
|
||||
$keepValues = [];
|
||||
|
||||
foreach ($allPoints as $rKey => [$value, $auxV]) {
|
||||
$key = InheritanceKey::from($rKey);
|
||||
if ($isRebirth && $rebirthDegraded->hasKey($key)) {
|
||||
$value *= $rebirthDegraded[$key];
|
||||
|
||||
/** @var InheritancePointType */
|
||||
$keyTypeObj = $this->inheritanceKey->get($key);
|
||||
|
||||
if ($isRebirth) {
|
||||
if ($keyTypeObj->rebirthStoreCoeff === null) {
|
||||
$keepValues[$rKey] = [$value, $auxV];
|
||||
continue;
|
||||
}
|
||||
|
||||
$value *= $keyTypeObj->rebirthStoreCoeff;
|
||||
}
|
||||
|
||||
$keyText = $this->getInheritancePointType($key)->info;
|
||||
$userLogger->push("{$keyText} 포인트 {$value} 증가", "inheritPoint");
|
||||
$totalPoint += $value;
|
||||
@@ -373,6 +380,10 @@ class InheritancePointManager
|
||||
$userLogger->flush();
|
||||
|
||||
$inheritStor->resetValues();
|
||||
|
||||
foreach ($keepValues as $rKey => $pointPair) {
|
||||
$inheritStor->setValue($rKey, $pointPair);
|
||||
}
|
||||
$inheritStor->setValue(InheritanceKey::previous->value, [$totalPoint, null]);
|
||||
return $totalPoint;
|
||||
}
|
||||
|
||||
+36
-82
@@ -1,16 +1,13 @@
|
||||
<?php
|
||||
namespace sammo;
|
||||
|
||||
use sammo\Enums\MessageType;
|
||||
|
||||
class Message
|
||||
{
|
||||
const MAILBOX_PUBLIC = 9999;
|
||||
const MAILBOX_NATIONAL = 9000;
|
||||
|
||||
const MSGTYPE_PUBLIC = 'public';
|
||||
const MSGTYPE_PRIVATE = 'private';
|
||||
const MSGTYPE_NATIONAL = 'national';
|
||||
const MSGTYPE_DIPLOMACY = 'diplomacy';
|
||||
|
||||
//기본 정보
|
||||
public $mailbox = null;
|
||||
public $id = null;
|
||||
@@ -18,39 +15,15 @@ class Message
|
||||
|
||||
protected $sendCnt = 0;
|
||||
|
||||
public $msgType;
|
||||
/** @var \sammo\MessageTarget */
|
||||
public $src;
|
||||
/** @var \sammo\MessageTarget */
|
||||
public $dest;
|
||||
public $msg;
|
||||
/** @var \DateTime */
|
||||
public $date;
|
||||
/** @var \DateTime */
|
||||
public $validUntil;
|
||||
|
||||
public $msgOption;
|
||||
|
||||
public function __construct(
|
||||
string $msgType,
|
||||
MessageTarget $src,
|
||||
MessageTarget $dest,
|
||||
string $msg,
|
||||
\DateTime $date,
|
||||
\DateTime $validUntil,
|
||||
array $msgOption
|
||||
public MessageType $msgType,
|
||||
public MessageTarget $src,
|
||||
public MessageTarget $dest,
|
||||
public string $msg,
|
||||
public \DateTime $date,
|
||||
public \DateTime $validUntil,
|
||||
public ?array $msgOption
|
||||
) {
|
||||
if (!static::isValidMsgType($msgType)) {
|
||||
throw new \InvalidArgumentException('올바르지 않은 msgType');
|
||||
}
|
||||
|
||||
$this->msgType = $msgType;
|
||||
$this->src = $src;
|
||||
$this->dest = $dest;
|
||||
$this->msg = $msg;
|
||||
$this->date = $date;
|
||||
$this->validUntil = $validUntil;
|
||||
$this->msgOption = $msgOption;
|
||||
}
|
||||
|
||||
public function setSentInfo(int $mailbox, int $messageID) : self
|
||||
@@ -61,19 +34,19 @@ class Message
|
||||
|
||||
do{
|
||||
if($mailbox === Message::MAILBOX_PUBLIC){
|
||||
if($this->msgType !== Message::MSGTYPE_PUBLIC){
|
||||
throw new \InvalidArgumentException('올바르지 않은 mailbox, msgType !== MSGTYPE_PUBLIC');
|
||||
if($this->msgType !== MessageType::public){
|
||||
throw new \InvalidArgumentException('올바르지 않은 mailbox, msgType !== MessageType::public');
|
||||
}
|
||||
$this->isInboxMail = true;
|
||||
break;
|
||||
}
|
||||
if($mailbox >= Message::MAILBOX_NATIONAL){
|
||||
if($this->msgType === Message::MSGTYPE_DIPLOMACY){
|
||||
if($this->msgType === MessageType::diplomacy){
|
||||
$this->isInboxMail = true;
|
||||
break;
|
||||
}
|
||||
if ($this->msgType !== Message::MSGTYPE_NATIONAL) {
|
||||
throw new \InvalidArgumentException('올바르지 않은 mailbox, msgType not in (MSGTYPE_DIPLOMACY, MSGTYPE_NATIONAL)');
|
||||
if ($this->msgType !== MessageType::national) {
|
||||
throw new \InvalidArgumentException('올바르지 않은 mailbox, msgType not in (MessageType::diplomacy, MessageType::national)');
|
||||
}
|
||||
if($this->dest->nationID + Message::MAILBOX_NATIONAL === $mailbox){
|
||||
$this->isInboxMail = true;
|
||||
@@ -85,7 +58,7 @@ class Message
|
||||
}
|
||||
throw new \InvalidArgumentException('송신, 수신국 둘 중의 어느 메일함도 아닙니다');
|
||||
}
|
||||
if($this->msgType !== Message::MSGTYPE_PRIVATE){
|
||||
if($this->msgType !== MessageType::private){
|
||||
throw new \InvalidArgumentException('올바르지 않은 mailbox, msgType !== MSGTYPE_PRIVATE');
|
||||
}
|
||||
if($this->dest->generalID === $mailbox){
|
||||
@@ -105,11 +78,11 @@ class Message
|
||||
}
|
||||
|
||||
public function toArray():array{
|
||||
if($this->msgType === Message::MSGTYPE_PUBLIC){
|
||||
if($this->msgType === MessageType::public){
|
||||
$src = $this->src->toArray();
|
||||
$dest = null;
|
||||
}
|
||||
else if($this->msgType === Message::MSGTYPE_NATIONAL || $this->msgType === Message::MSGTYPE_DIPLOMACY){
|
||||
else if($this->msgType === MessageType::national || $this->msgType === MessageType::diplomacy){
|
||||
$src = $this->src->toArray();
|
||||
$dest = $this->dest->toArray();
|
||||
}
|
||||
@@ -120,7 +93,7 @@ class Message
|
||||
|
||||
return [
|
||||
'id'=>$this->id,
|
||||
'msgType'=>$this->msgType,
|
||||
'msgType'=>$this->msgType->value,
|
||||
'src'=>$src,
|
||||
'dest'=>$dest,
|
||||
'text'=>$this->msg,
|
||||
@@ -133,7 +106,7 @@ class Message
|
||||
{
|
||||
$dbMessage = Json::decode($row['message']);
|
||||
|
||||
$msgType = $row['type'];
|
||||
$msgType = MessageType::from($row['type']);
|
||||
$src = MessageTarget::buildFromArray($dbMessage['src']);
|
||||
$dest = MessageTarget::buildFromArray($dbMessage['dest']);
|
||||
$option = Util::array_get($dbMessage['option'], []);
|
||||
@@ -149,7 +122,7 @@ class Message
|
||||
];
|
||||
|
||||
$action = Util::array_get($option['action'], null);
|
||||
if ($msgType === self::MSGTYPE_DIPLOMACY && $action !== null) {
|
||||
if ($msgType === MessageType::diplomacy && $action !== null) {
|
||||
$objMessage = new DiplomaticMessage(...$args);
|
||||
} elseif ($action === 'scout') {
|
||||
$objMessage = new ScoutMessage(...$args);
|
||||
@@ -164,7 +137,7 @@ class Message
|
||||
|
||||
protected static function isValidMailBox(int $mailbox): bool
|
||||
{
|
||||
if ($mailbox > self::MAILBOX_PUBLIC) {
|
||||
if ($mailbox > MessageType::public) {
|
||||
return false;
|
||||
}
|
||||
if ($mailbox <= 0) {
|
||||
@@ -173,17 +146,6 @@ class Message
|
||||
return true;
|
||||
}
|
||||
|
||||
protected static function isValidMsgType(string $msgType): bool
|
||||
{
|
||||
switch ($msgType) {
|
||||
case static::MSGTYPE_PUBLIC: return true;
|
||||
case static::MSGTYPE_PRIVATE: return true;
|
||||
case static::MSGTYPE_NATIONAL: return true;
|
||||
case static::MSGTYPE_DIPLOMACY: return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function getMessageByID(int $messageID) : ?Message
|
||||
{
|
||||
$db = DB::db();
|
||||
@@ -197,24 +159,20 @@ class Message
|
||||
|
||||
/**
|
||||
* @param int $mailbox 메일 사서함.
|
||||
* @param string $msgType 메일 타입. MSGTYPE 중 하나.
|
||||
* @param MessageType $msgType 메일 타입.
|
||||
* @param int $limit 가져오고자 하는 수. 0 이하의 값이면 모두.
|
||||
* @param int $fromSeq 가져오고자 하는 위치. $fromSeq보다 '큰' seq만 가져온다. 따라서 0 이하이면 모두 가져옴.
|
||||
* @return Message[]
|
||||
*/
|
||||
public static function getMessagesFromMailBox(int $mailbox, string $msgType, int $limit=30, int $fromSeq = 0)
|
||||
public static function getMessagesFromMailBox(int $mailbox, MessageType $msgType, int $limit=30, int $fromSeq = 0)
|
||||
{
|
||||
$db = DB::db();
|
||||
|
||||
if (!static::isValidMsgType($msgType)) {
|
||||
throw new \InvalidArgumentException('올바르지 않은 $msgType');
|
||||
}
|
||||
|
||||
$date = (new \DateTime())->format('Y-m-d H:i:s');
|
||||
|
||||
$where = new \WhereClause('and');
|
||||
$where->add('mailbox = %i', $mailbox);
|
||||
$where->add('type = %s', $msgType);
|
||||
$where->add('type = %s', $msgType->value);
|
||||
$where->add('valid_until > %s', $date);
|
||||
if ($fromSeq > 0) {
|
||||
$where->add('id >= %i', $fromSeq);
|
||||
@@ -233,24 +191,20 @@ class Message
|
||||
|
||||
/**
|
||||
* @param int $mailbox 메일 사서함.
|
||||
* @param string $msgType 메일 타입. MSGTYPE 중 하나.
|
||||
* @param MessageType $msgType 메일 타입.
|
||||
* @param int $toSeq 가져오고자 하는 위치. $toSeq보다 '작은' seq만 가져온다.
|
||||
* @param int $limit 가져오고자 하는 수.
|
||||
* @return Message[]
|
||||
*/
|
||||
public static function getMessagesFromMailBoxOld(int $mailbox, string $msgType, int $toSeq, int $limit = 20)
|
||||
public static function getMessagesFromMailBoxOld(int $mailbox, MessageType $msgType, int $toSeq, int $limit = 20)
|
||||
{
|
||||
$db = DB::db();
|
||||
|
||||
if (!static::isValidMsgType($msgType)) {
|
||||
throw new \InvalidArgumentException('올바르지 않은 $msgType');
|
||||
}
|
||||
|
||||
$date = (new \DateTime())->format('Y-m-d H:i:s');
|
||||
|
||||
$where = new \WhereClause('and');
|
||||
$where->add('mailbox = %i', $mailbox);
|
||||
$where->add('type = %s', $msgType);
|
||||
$where->add('type = %s', $msgType->value);
|
||||
$where->add('valid_until > %s', $date);
|
||||
$where->add('id < %i', $toSeq);
|
||||
|
||||
@@ -296,7 +250,7 @@ class Message
|
||||
'overwrite'=>[$msgObj->id]
|
||||
];
|
||||
|
||||
if($msgObj->msgType == Message::MSGTYPE_PRIVATE || $msgObj->msgType == Message::MSGTYPE_NATIONAL){
|
||||
if($msgObj->msgType === MessageType::private || $msgObj->msgType === MessageType::national){
|
||||
$receiveID = $msgObj->msgOption['receiverMessageID']??null;
|
||||
if($receiveID !== null){
|
||||
$msgObj2 = static::getMessageByID($receiveID);
|
||||
@@ -345,7 +299,7 @@ class Message
|
||||
$db = DB::db();
|
||||
$db->insert('message', [
|
||||
'mailbox' => $mailbox,
|
||||
'type' => $this->msgType,
|
||||
'type' => $this->msgType->value,
|
||||
'src' => $src_id,
|
||||
'dest' => $dest_id,
|
||||
'time' => $this->date->format('Y-m-d H:i:s'),
|
||||
@@ -364,13 +318,13 @@ class Message
|
||||
if($this->sendCnt > 1){
|
||||
throw new \RuntimeException('이미 전송한 메일입니다.');
|
||||
}
|
||||
if($this->msgType === self::MSGTYPE_PRIVATE && $this->src->generalID !== $this->dest->generalID){
|
||||
if($this->msgType === MessageType::private && $this->src->generalID !== $this->dest->generalID){
|
||||
return $this->sendRaw($this->src->generalID);
|
||||
}
|
||||
if($this->msgType === self::MSGTYPE_NATIONAL && $this->src->nationID !== $this->dest->nationID){
|
||||
if($this->msgType === MessageType::national && $this->src->nationID !== $this->dest->nationID){
|
||||
return $this->sendRaw($this->src->nationID + self::MAILBOX_NATIONAL);
|
||||
}
|
||||
if($this->msgType === self::MSGTYPE_DIPLOMACY){
|
||||
if($this->msgType === MessageType::diplomacy){
|
||||
if(key_exists('action', $this->msgOption)){
|
||||
$tmp = $this->msgOption;
|
||||
$this->msgOption = null;
|
||||
@@ -391,7 +345,7 @@ class Message
|
||||
throw new \RuntimeException('이미 전송한 메일입니다.');
|
||||
}
|
||||
|
||||
if($this->msgType === self::MSGTYPE_PRIVATE){
|
||||
if($this->msgType === MessageType::private){
|
||||
if(!($this->msgOption['silence']??false)){
|
||||
//XXX: 알림을 이런식으로 보내는게 맞는가에 대한 의문 있음
|
||||
DB::db()->update('general', [
|
||||
@@ -401,11 +355,11 @@ class Message
|
||||
return $this->sendRaw($this->dest->generalID);
|
||||
}
|
||||
|
||||
if($this->msgType === self::MSGTYPE_NATIONAL){
|
||||
if($this->msgType === MessageType::national){
|
||||
return $this->sendRaw($this->dest->nationID + self::MAILBOX_NATIONAL);
|
||||
}
|
||||
|
||||
if($this->msgType === self::MSGTYPE_DIPLOMACY){
|
||||
if($this->msgType === MessageType::diplomacy){
|
||||
if(!($this->msgOption['silence']??false)){
|
||||
//XXX: 알림을 이런식으로 보내는게 맞는가에 대한 의문 있음
|
||||
DB::db()->update('general', [
|
||||
@@ -415,7 +369,7 @@ class Message
|
||||
return $this->sendRaw($this->dest->nationID + self::MAILBOX_NATIONAL);
|
||||
}
|
||||
|
||||
if($this->msgType === self::MSGTYPE_PUBLIC){
|
||||
if($this->msgType === MessageType::public){
|
||||
return $this->sendRaw(self::MAILBOX_PUBLIC);
|
||||
}
|
||||
|
||||
|
||||
@@ -18,8 +18,8 @@ class ResetHelper{
|
||||
'reason'=>'logs, data 디렉토리를 생성할 권한이 없습니다.'
|
||||
];
|
||||
}
|
||||
mkdir($servRoot.'/logs', 0755);
|
||||
mkdir($servRoot.'/data', 0755);
|
||||
mkdir($servRoot.'/logs', 0775);
|
||||
mkdir($servRoot.'/data', 0775);
|
||||
}
|
||||
|
||||
if(!is_writable($servRoot.'/logs')){
|
||||
@@ -44,7 +44,7 @@ class ResetHelper{
|
||||
}
|
||||
|
||||
if(!file_exists($servRoot.'/logs/preserved')){
|
||||
mkdir($servRoot.'/logs/preserved', 0755);
|
||||
mkdir($servRoot.'/logs/preserved', 0775);
|
||||
}
|
||||
|
||||
if(!file_exists($servRoot.'/logs/.htaccess')){
|
||||
@@ -80,8 +80,8 @@ class ResetHelper{
|
||||
|
||||
$serverID = DB::prefix().'_'.date("ymd").'_'.Util::randomStr(4);
|
||||
|
||||
mkdir($servRoot.'/logs/'.$serverID, 0755);
|
||||
mkdir($servRoot.'/data/'.$serverID, 0755);
|
||||
mkdir($servRoot.'/logs/'.$serverID, 0775);
|
||||
mkdir($servRoot.'/data/'.$serverID, 0775);
|
||||
|
||||
$seasonIdx = 1;
|
||||
if($db->queryFirstField('SHOW TABLES LIKE %s', 'storage') !== null){
|
||||
@@ -160,7 +160,7 @@ class ResetHelper{
|
||||
int $scenario,
|
||||
int $fiction,
|
||||
int $extend,
|
||||
bool $block_general_create,
|
||||
int $block_general_create,
|
||||
int $npcmode,
|
||||
int $show_img_level,
|
||||
bool $tournament_trig,
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<?php
|
||||
namespace sammo;
|
||||
|
||||
use sammo\Enums\MessageType;
|
||||
|
||||
class ScoutMessage extends Message{
|
||||
|
||||
const ACCEPTED = 1;
|
||||
@@ -9,7 +11,7 @@ class ScoutMessage extends Message{
|
||||
protected $validScout = true;
|
||||
|
||||
public function __construct(
|
||||
string $msgType,
|
||||
MessageType $msgType,
|
||||
MessageTarget $src,
|
||||
MessageTarget $dest,
|
||||
string $msg,
|
||||
@@ -18,7 +20,7 @@ class ScoutMessage extends Message{
|
||||
array $msgOption
|
||||
)
|
||||
{
|
||||
if ($msgType !== self::MSGTYPE_PRIVATE){
|
||||
if ($msgType !== MessageType::private){
|
||||
throw new \InvalidArgumentException('DiplomaticMessage msgType');
|
||||
}
|
||||
|
||||
@@ -98,7 +100,7 @@ class ScoutMessage extends Message{
|
||||
|
||||
$josaRo = JosaUtil::pick($this->src->nationName, '로');
|
||||
$newMsg = new Message(
|
||||
self::MSGTYPE_PRIVATE,
|
||||
MessageType::private,
|
||||
$this->src,
|
||||
$this->dest,
|
||||
"{$this->src->nationName}{$josaRo} 등용 제의 수락",
|
||||
@@ -120,7 +122,7 @@ class ScoutMessage extends Message{
|
||||
|
||||
$josaRo = JosaUtil::pick($this->src->nationName, '로');
|
||||
$newMsg = new Message(
|
||||
self::MSGTYPE_PRIVATE,
|
||||
MessageType::private,
|
||||
$this->src,
|
||||
$this->dest,
|
||||
"{$this->src->nationName}{$josaRo} 등용 제의 거부",
|
||||
@@ -223,6 +225,6 @@ class ScoutMessage extends Message{
|
||||
'action'=>'scout'
|
||||
];
|
||||
|
||||
return new ScoutMessage(Message::MSGTYPE_PRIVATE, $src, $dest, $msg, $date, $validUntil, $msgOption);
|
||||
return new ScoutMessage(MessageType::private, $src, $dest, $msg, $date, $validUntil, $msgOption);
|
||||
}
|
||||
}
|
||||
@@ -195,7 +195,6 @@ class TurnExecutionHelper
|
||||
$general->setVar('owner_name', null);
|
||||
} else {
|
||||
$general->applyDB($db);
|
||||
storeOldGeneral($generalID, $gameStor->year, $gameStor->month);
|
||||
$general->kill($db);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ class InheritancePointType{
|
||||
public bool|array $storeType,
|
||||
public int|float $pointCoeff,
|
||||
public string $info,
|
||||
public ?float $rebirthStoreCoeff,
|
||||
)
|
||||
{
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ use sammo\GameUnitDetail;
|
||||
use sammo\Util;
|
||||
use sammo\ObjectTrigger;
|
||||
|
||||
/** @deprecated che_선제사격시도, che_선제사격발동 으로 이전*/
|
||||
class che_궁병선제사격 extends BaseWarUnitTrigger
|
||||
{
|
||||
protected $priority = ObjectTrigger::PRIORITY_BEGIN + 50;
|
||||
@@ -39,15 +40,15 @@ class che_궁병선제사격 extends BaseWarUnitTrigger
|
||||
if ($oppose->getCrewType()->armType == GameUnitConst::T_ARCHER) {
|
||||
$oppose->activateSkill('특수', '선제');
|
||||
|
||||
$self->multiplyWarPowerMultiply(0.5);
|
||||
$oppose->multiplyWarPowerMultiply(0.5);
|
||||
$self->multiplyWarPowerMultiply(2/3);
|
||||
$oppose->multiplyWarPowerMultiply(2/3);
|
||||
$oppose->getLogger()->pushGeneralBattleDetailLog('서로 <C>선제 사격</>을 주고 받았다!</>', ActionLogger::PLAIN);
|
||||
$self->getLogger()->pushGeneralBattleDetailLog('서로 <C>선제 사격</>을 주고 받았다!</>', ActionLogger::PLAIN);
|
||||
return true;
|
||||
}
|
||||
|
||||
$oppose->multiplyWarPowerMultiply(0);
|
||||
$self->multiplyWarPowerMultiply(0.5);
|
||||
$self->multiplyWarPowerMultiply(2/3);
|
||||
$self->activateSkill('회피불가', '필살불가', '계략불가');
|
||||
$oppose->activateSkill('회피불가', '필살불가', '격노불가', '계략불가');
|
||||
|
||||
|
||||
@@ -13,8 +13,8 @@ class che_기병병종전투 extends BaseWarUnitTrigger{
|
||||
|
||||
protected function actionWar(WarUnit $self, WarUnit $oppose, array &$selfEnv, array &$opposeEnv):bool{
|
||||
if(!$self->isAttacker()){
|
||||
$oppose->multiplyWarPowerMultiply(1/0.95);
|
||||
$self->multiplyWarPowerMultiply(0.95);
|
||||
$oppose->multiplyWarPowerMultiply(1.02);
|
||||
$self->multiplyWarPowerMultiply(0.97);
|
||||
}
|
||||
else if($oppose instanceof WarUnitCity){
|
||||
$self->multiplyWarPowerMultiply(0.9);
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace sammo\WarUnitTrigger;
|
||||
|
||||
use sammo\ActionLogger;
|
||||
use sammo\BaseWarUnitTrigger;
|
||||
use sammo\GameUnitConst;
|
||||
use sammo\WarUnitGeneral;
|
||||
use sammo\WarUnitCity;
|
||||
use sammo\WarUnit;
|
||||
use sammo\GameUnitDetail;
|
||||
use sammo\Util;
|
||||
use sammo\ObjectTrigger;
|
||||
|
||||
class che_선제사격발동 extends BaseWarUnitTrigger
|
||||
{
|
||||
protected $priority = ObjectTrigger::PRIORITY_BEGIN + 51;
|
||||
|
||||
protected function actionWar(WarUnit $self, WarUnit $oppose, array &$selfEnv, array &$opposeEnv): bool
|
||||
{
|
||||
assert($self instanceof WarUnitGeneral, 'General만 발동 가능');
|
||||
if (!$self->hasActivatedSkill('선제')) {
|
||||
return true;
|
||||
}
|
||||
if ($oppose->hasActivatedSkill('선제') && $oppose->isAttacker()){
|
||||
//맞 선제라면 공격자가 처리
|
||||
return true;
|
||||
}
|
||||
|
||||
$self->addPhase(-1);
|
||||
$oppose->addPhase(-1);
|
||||
if ($oppose->hasActivatedSkill('선제')) {
|
||||
$self->multiplyWarPowerMultiply(2/3);
|
||||
$oppose->multiplyWarPowerMultiply(2/3);
|
||||
$oppose->getLogger()->pushGeneralBattleDetailLog('서로 <C>선제 사격</>을 주고 받았다!</>', ActionLogger::PLAIN);
|
||||
$self->getLogger()->pushGeneralBattleDetailLog('서로 <C>선제 사격</>을 주고 받았다!</>', ActionLogger::PLAIN);
|
||||
return true;
|
||||
}
|
||||
|
||||
$oppose->multiplyWarPowerMultiply(0);
|
||||
$self->multiplyWarPowerMultiply(2/3);
|
||||
$self->activateSkill('회피불가', '필살불가', '계략불가');
|
||||
$oppose->activateSkill('회피불가', '필살불가', '격노불가', '계략불가');
|
||||
|
||||
$oppose->getLogger()->pushGeneralBattleDetailLog('상대에게 <R>선제 사격</>을 받았다!</>', ActionLogger::PLAIN);
|
||||
$self->getLogger()->pushGeneralBattleDetailLog('상대에게 <C>선제 사격</>을 했다!</>', ActionLogger::PLAIN);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace sammo\WarUnitTrigger;
|
||||
|
||||
use sammo\ActionLogger;
|
||||
use sammo\BaseWarUnitTrigger;
|
||||
use sammo\GameUnitConst;
|
||||
use sammo\WarUnitGeneral;
|
||||
use sammo\WarUnitCity;
|
||||
use sammo\WarUnit;
|
||||
use sammo\GameUnitDetail;
|
||||
use sammo\Util;
|
||||
use sammo\ObjectTrigger;
|
||||
|
||||
class che_선제사격시도 extends BaseWarUnitTrigger
|
||||
{
|
||||
protected $priority = ObjectTrigger::PRIORITY_BEGIN + 50;
|
||||
|
||||
protected function actionWar(WarUnit $self, WarUnit $oppose, array &$selfEnv, array &$opposeEnv): bool
|
||||
{
|
||||
assert($self instanceof WarUnitGeneral, 'General만 발동 가능');
|
||||
if ($self->getPhase() !== 0 && $oppose->getPhase() !== 0) {
|
||||
return true;
|
||||
}
|
||||
if ($self->hasActivatedSkill('선제')) {
|
||||
return true;
|
||||
}
|
||||
if ($self->hasActivatedSkillOnLog('선제')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$self->activateSkill('특수', '선제');
|
||||
return true;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,9 @@ class che_저격시도 extends BaseWarUnitTrigger{
|
||||
if($self->getPhase() !== 0 && $oppose->getPhase() !== 0){
|
||||
return true;
|
||||
}
|
||||
if($oppose->getPhase() < 0){
|
||||
return true;
|
||||
}
|
||||
if($self->hasActivatedSkill('저격')){
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -23,8 +23,8 @@
|
||||
[
|
||||
"month", 999,
|
||||
["Date", "==", 181, 1],
|
||||
["OpenNationBetting", 4, 1000],
|
||||
["OpenNationBetting", 1, 1000],
|
||||
["OpenNationBetting", 4, 5000],
|
||||
["OpenNationBetting", 1, 2000],
|
||||
["DeleteEvent"]
|
||||
],
|
||||
[
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
[
|
||||
"month", 999,
|
||||
["Date", "==", 181, 1],
|
||||
["OpenNationBetting", 4, 1000],
|
||||
["OpenNationBetting", 1, 1000],
|
||||
["OpenNationBetting", 4, 5000],
|
||||
["OpenNationBetting", 1, 2000],
|
||||
["DeleteEvent"]
|
||||
],
|
||||
[
|
||||
|
||||
@@ -30,8 +30,8 @@
|
||||
[
|
||||
"month", 999,
|
||||
["Date", "==", 181, 1],
|
||||
["OpenNationBetting", 4, 1000],
|
||||
["OpenNationBetting", 1, 1000],
|
||||
["OpenNationBetting", 4, 5000],
|
||||
["OpenNationBetting", 1, 2000],
|
||||
["DeleteEvent"]
|
||||
],
|
||||
[
|
||||
|
||||
@@ -0,0 +1,1078 @@
|
||||
{
|
||||
"title": "【가상모드27-c】 아시아 명장전(빙의전용)",
|
||||
"startYear": 180,
|
||||
"history": [
|
||||
"<C>●</>180년 1월:<L><b>【가상모드27】</b>아시아 명장전!(빙의전용)</>",
|
||||
"<C>●</>180년 1월:<L><b>【이벤트】</b></>빙의전용 시나리오. 아시아 명장 일부 스탯 유저수준 버프"
|
||||
],
|
||||
"stat": {
|
||||
"total": 310,
|
||||
"min": 40,
|
||||
"max": 140
|
||||
},
|
||||
"iconPath": ".",
|
||||
"fiction": 1,
|
||||
"nation":[],
|
||||
"diplomacy":[],
|
||||
"const": {
|
||||
"npcBanMessageProb": 0,
|
||||
"npcSeizureMessageProb": 0,
|
||||
"npcMessageFreqByDay": 8,
|
||||
"availableSpecialWar": [
|
||||
"che_귀병",
|
||||
"che_신산",
|
||||
"che_환술",
|
||||
"che_집중",
|
||||
"che_신중",
|
||||
"che_반계",
|
||||
"che_보병",
|
||||
"che_궁병",
|
||||
"che_기병",
|
||||
"che_공성",
|
||||
"che_돌격",
|
||||
"che_무쌍",
|
||||
"che_견고",
|
||||
"che_위압",
|
||||
"che_저격",
|
||||
"che_필살",
|
||||
"che_징병",
|
||||
"che_의술",
|
||||
"che_격노",
|
||||
"che_척사"
|
||||
],
|
||||
"allItems": {
|
||||
"horse": {
|
||||
"che_명마_01_노기": 0,
|
||||
"che_명마_02_조랑": 0,
|
||||
"che_명마_03_노새": 0,
|
||||
"che_명마_04_나귀": 0,
|
||||
"che_명마_05_갈색마": 0,
|
||||
"che_명마_06_흑색마": 0,
|
||||
"che_명마_07_백마": 2,
|
||||
"che_명마_07_기주마": 2,
|
||||
"che_명마_07_오환마": 2,
|
||||
"che_명마_07_백상": 2,
|
||||
"che_명마_08_양주마": 2,
|
||||
"che_명마_08_흉노마": 2,
|
||||
"che_명마_09_과하마": 2,
|
||||
"che_명마_09_의남백마": 2,
|
||||
"che_명마_10_대완마": 2,
|
||||
"che_명마_10_옥추마": 2,
|
||||
"che_명마_11_서량마": 2,
|
||||
"che_명마_11_화종마": 2,
|
||||
"che_명마_12_사륜거": 2,
|
||||
"che_명마_12_옥란백용구": 2,
|
||||
"che_명마_13_절영": 2,
|
||||
"che_명마_13_적로": 2,
|
||||
"che_명마_14_적란마": 2,
|
||||
"che_명마_14_조황비전": 2,
|
||||
"che_명마_15_한혈마": 2,
|
||||
"che_명마_15_적토마": 2
|
||||
},
|
||||
"weapon": {
|
||||
"che_무기_01_단도": 0,
|
||||
"che_무기_02_단궁": 0,
|
||||
"che_무기_03_단극": 0,
|
||||
"che_무기_04_목검": 0,
|
||||
"che_무기_05_죽창": 0,
|
||||
"che_무기_06_소부": 0,
|
||||
"che_무기_07_동추": 2,
|
||||
"che_무기_07_철편": 2,
|
||||
"che_무기_07_철쇄": 2,
|
||||
"che_무기_07_맥궁": 2,
|
||||
"che_무기_08_유성추": 2,
|
||||
"che_무기_08_철질여골": 2,
|
||||
"che_무기_09_쌍철극": 2,
|
||||
"che_무기_09_동호비궁": 2,
|
||||
"che_무기_10_삼첨도": 2,
|
||||
"che_무기_10_대부": 2,
|
||||
"che_무기_11_고정도": 2,
|
||||
"che_무기_11_이광궁": 2,
|
||||
"che_무기_12_철척사모": 2,
|
||||
"che_무기_12_칠성검": 2,
|
||||
"che_무기_13_사모": 2,
|
||||
"che_무기_13_양유기궁": 2,
|
||||
"che_무기_14_언월도": 2,
|
||||
"che_무기_14_방천화극": 2,
|
||||
"che_무기_15_청홍검": 2,
|
||||
"che_무기_15_의천검": 2
|
||||
},
|
||||
"book": {
|
||||
"che_서적_01_효경전": 0,
|
||||
"che_서적_02_회남자": 0,
|
||||
"che_서적_03_변도론": 0,
|
||||
"che_서적_04_건상역주": 0,
|
||||
"che_서적_05_여씨춘추": 0,
|
||||
"che_서적_06_사민월령": 0,
|
||||
"che_서적_07_위료자": 2,
|
||||
"che_서적_07_사마법": 2,
|
||||
"che_서적_07_한서": 2,
|
||||
"che_서적_07_논어": 2,
|
||||
"che_서적_08_전론": 2,
|
||||
"che_서적_08_사기": 2,
|
||||
"che_서적_09_장자": 2,
|
||||
"che_서적_09_역경": 2,
|
||||
"che_서적_10_시경": 2,
|
||||
"che_서적_10_구국론": 2,
|
||||
"che_서적_11_상군서": 2,
|
||||
"che_서적_11_춘추전": 2,
|
||||
"che_서적_12_산해경": 2,
|
||||
"che_서적_12_맹덕신서": 2,
|
||||
"che_서적_13_관자": 2,
|
||||
"che_서적_13_병법24편": 2,
|
||||
"che_서적_14_한비자": 2,
|
||||
"che_서적_14_오자병법": 2,
|
||||
"che_서적_15_노자": 2,
|
||||
"che_서적_15_손자병법": 2
|
||||
},
|
||||
"item": {
|
||||
"che_치료_환약": 0,
|
||||
"che_저격_수극": 0,
|
||||
"che_사기_탁주": 0,
|
||||
"che_훈련_청주": 0,
|
||||
"che_계략_이추": 0,
|
||||
"che_계략_향낭": 0,
|
||||
"event_전투특기_격노": 0,
|
||||
"event_전투특기_견고": 0,
|
||||
"event_전투특기_공성": 0,
|
||||
"event_전투특기_궁병": 0,
|
||||
"event_전투특기_귀병": 0,
|
||||
"event_전투특기_기병": 0,
|
||||
"event_전투특기_돌격": 0,
|
||||
"event_전투특기_무쌍": 0,
|
||||
"event_전투특기_반계": 0,
|
||||
"event_전투특기_보병": 0,
|
||||
"event_전투특기_신산": 0,
|
||||
"event_전투특기_신중": 0,
|
||||
"event_전투특기_위압": 0,
|
||||
"event_전투특기_의술": 0,
|
||||
"event_전투특기_저격": 0,
|
||||
"event_전투특기_집중": 0,
|
||||
"event_전투특기_징병": 0,
|
||||
"event_전투특기_척사": 0,
|
||||
"event_전투특기_필살": 0,
|
||||
"event_전투특기_환술": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
"general":[
|
||||
[0, "아회남", null, 0, null, 65, 74, 26, 0, 160, 300, null, null],
|
||||
[0, "이적", null, 0, null, 40, 24, 84, 0, 160, 300, null, null],
|
||||
[0, "윤상", null, 0, null, 51, 44, 62, 0, 160, 300, null, null],
|
||||
[0, "윤묵", null, 0, null, 26, 15, 66, 0, 160, 300, null, null],
|
||||
[0, "우금", null, 0, null, 85, 82, 75, 0, 160, 300, null, null],
|
||||
[0, "위관", null, 0, null, 69, 46, 79, 0, 160, 300, null, null],
|
||||
[0, "원윤", null, 0, null, 32, 14, 39, 0, 160, 300, null, null],
|
||||
[0, "원희", null, 0, null, 66, 51, 63, 0, 160, 300, null, null],
|
||||
[0, "염행", null, 0, null, 78, 90, 58, 0, 160, 300, null, null],
|
||||
[0, "염유", null, 0, null, 71, 57, 71, 0, 160, 300, null, null],
|
||||
[0, "원술", null, 0, null, 76, 65, 75, 0, 160, 300, null, null],
|
||||
[0, "원상", null, 0, null, 63, 75, 42, 0, 160, 300, null, null],
|
||||
[0, "원소", null, 0, null, 90, 69, 81, 0, 160, 300, null, null],
|
||||
[0, "염상", null, 0, null, 40, 27, 71, 0, 160, 300, null, null],
|
||||
[0, "원담", null, 0, null, 60, 78, 30, 0, 160, 300, null, null],
|
||||
[0, "염포", null, 0, null, 40, 25, 82, 0, 160, 300, null, null],
|
||||
[0, "왕위", null, 0, null, 60, 70, 62, 0, 160, 300, null, null],
|
||||
[0, "왕윤", null, 0, null, 26, 6, 68, 0, 160, 300, null, null],
|
||||
[0, "왕항", null, 0, null, 76, 60, 61, 0, 160, 300, null, null],
|
||||
[0, "왕찬", null, 0, null, 15, 3, 79, 0, 160, 300, null, null],
|
||||
[0, "왕수", null, 0, null, 54, 27, 77, 0, 160, 300, null, null],
|
||||
[0, "왕숙", null, 0, null, 36, 22, 76, 0, 160, 300, null, null],
|
||||
[0, "왕준", null, 0, null, 85, 73, 84, 0, 160, 300, null, null],
|
||||
[0, "왕쌍", null, 0, null, 67, 88, 19, 0, 160, 300, null, null],
|
||||
[0, "왕창", null, 0, null, 74, 64, 79, 0, 160, 300, null, null],
|
||||
[0, "왕평", null, 0, null, 88, 81, 70, 0, 160, 300, null, null],
|
||||
[0, "왕보", null, 0, null, 62, 41, 79, 0, 160, 300, null, null],
|
||||
[0, "왕문", null, 0, null, 65, 64, 31, 0, 160, 300, null, null],
|
||||
[0, "왕릉1", null, 0, null, 74, 64, 71, 0, 160, 300, null, null],
|
||||
[0, "왕루", null, 0, null, 28, 30, 79, 0, 160, 300, null, null],
|
||||
[0, "왕랑", null, 0, null, 47, 35, 79, 0, 160, 300, null, null],
|
||||
[0, "온회", null, 0, null, 62, 36, 74, 0, 160, 300, null, null],
|
||||
[0, "하안", null, 0, null, 15, 30, 72, 0, 160, 300, null, null],
|
||||
[0, "괴월", null, 0, null, 50, 38, 85, 0, 160, 300, null, null],
|
||||
[0, "괴량", null, 0, null, 68, 33, 88, 0, 160, 300, null, null],
|
||||
[0, "가화", null, 0, null, 49, 65, 41, 0, 160, 300, null, null],
|
||||
[0, "가규", null, 0, null, 78, 61, 84, 0, 160, 300, null, null],
|
||||
[0, "하의", null, 0, null, 56, 69, 36, 0, 160, 300, null, null],
|
||||
[0, "화흠", null, 0, null, 51, 33, 88, 0, 160, 300, null, null],
|
||||
[0, "가후", null, 0, null, 81, 22, 98, 0, 160, 300, null, null],
|
||||
[0, "곽가", null, 0, null, 78, 16, 99, 0, 160, 300, null, null],
|
||||
[0, "악환", null, 0, null, 65, 80, 42, 0, 160, 300, null, null],
|
||||
[0, "곽사", null, 0, null, 64, 76, 13, 0, 160, 300, null, null],
|
||||
[0, "악취", null, 0, null, 53, 66, 61, 0, 160, 300, null, null],
|
||||
[0, "곽준", null, 0, null, 73, 66, 73, 0, 160, 300, null, null],
|
||||
[0, "학소", null, 0, null, 90, 71, 88, 0, 160, 300, null, null],
|
||||
[0, "악진", null, 0, null, 80, 85, 56, 0, 160, 300, null, null],
|
||||
[0, "곽도", null, 0, null, 62, 50, 82, 0, 160, 300, null, null],
|
||||
[0, "학맹", null, 0, null, 62, 67, 42, 0, 160, 300, null, null],
|
||||
[0, "곽유지", null, 0, null, 28, 9, 69, 0, 160, 300, null, null],
|
||||
[0, "곽익", null, 0, null, 73, 69, 69, 0, 160, 300, null, null],
|
||||
[0, "곽회", null, 0, null, 90, 77, 85, 0, 160, 300, null, null],
|
||||
[0, "하후위", null, 0, null, 71, 73, 49, 0, 160, 300, null, null],
|
||||
[0, "하후연", null, 0, null, 95, 92, 74, 0, 160, 300, null, null],
|
||||
[0, "하후은", null, 0, null, 63, 72, 53, 0, 160, 300, null, null],
|
||||
[0, "하후화", null, 0, null, 48, 51, 71, 0, 160, 300, null, null],
|
||||
[0, "하후혜", null, 0, null, 50, 44, 76, 0, 160, 300, null, null],
|
||||
[0, "하후현", null, 0, null, 54, 39, 76, 0, 160, 300, null, null],
|
||||
[0, "하후상", null, 0, null, 79, 72, 75, 0, 160, 300, null, null],
|
||||
[0, "하후덕", null, 0, null, 69, 73, 32, 0, 160, 300, null, null],
|
||||
[0, "하후돈", null, 0, null, 91, 88, 68, 0, 160, 300, null, null],
|
||||
[0, "하후패", null, 0, null, 79, 85, 77, 0, 160, 300, null, null],
|
||||
[0, "하후무", null, 0, null, 20, 7, 4, 0, 160, 300, null, null],
|
||||
[0, "가충", null, 0, null, 54, 31, 89, 0, 160, 300, null, null],
|
||||
[0, "하진", null, 0, null, 68, 54, 75, 0, 160, 300, null, null],
|
||||
[0, "화웅", null, 0, null, 78, 90, 55, 0, 160, 300, null, null],
|
||||
[0, "한윤", null, 0, null, 26, 29, 65, 0, 160, 300, null, null],
|
||||
[0, "관우", null, 0, null, 96, 99, 76, 0, 160, 300, null, null],
|
||||
[0, "환계", null, 0, null, 25, 26, 68, 0, 160, 300, null, null],
|
||||
[0, "관해", null, 0, null, 70, 82, 10, 0, 160, 300, null, null],
|
||||
[0, "관구검", null, 0, null, 84, 86, 62, 0, 160, 300, null, null],
|
||||
[0, "한현", null, 0, null, 22, 33, 7, 0, 160, 300, null, null],
|
||||
[0, "한호", null, 0, null, 73, 72, 84, 0, 160, 300, null, null],
|
||||
[0, "관흥", null, 0, null, 76, 84, 67, 0, 160, 300, null, null],
|
||||
[0, "관색", null, 0, null, 74, 83, 56, 0, 160, 300, null, null],
|
||||
[0, "한수", null, 0, null, 78, 75, 79, 0, 160, 300, null, null],
|
||||
[0, "한숭", null, 0, null, 25, 15, 71, 0, 160, 300, null, null],
|
||||
[0, "관정", null, 0, null, 36, 52, 73, 0, 160, 300, null, null],
|
||||
[0, "한섬", null, 0, null, 69, 66, 36, 0, 160, 300, null, null],
|
||||
[0, "감택", null, 0, null, 51, 49, 83, 0, 160, 300, null, null],
|
||||
[0, "한충", null, 0, null, 64, 67, 18, 0, 160, 300, null, null],
|
||||
[0, "한당", null, 0, null, 76, 85, 61, 0, 160, 300, null, null],
|
||||
[0, "한덕", null, 0, null, 63, 76, 25, 0, 160, 300, null, null],
|
||||
[0, "감녕", null, 0, null, 92, 95, 76, 0, 160, 300, null, null],
|
||||
[0, "한복", null, 0, null, 28, 3, 27, 0, 160, 300, null, null],
|
||||
[0, "관평", null, 0, null, 78, 82, 72, 0, 160, 300, null, null],
|
||||
[0, "간옹", null, 0, null, 20, 32, 75, 0, 160, 300, null, null],
|
||||
[0, "안량", null, 0, null, 88, 96, 43, 0, 160, 300, null, null],
|
||||
[0, "위연", null, 0, null, 91, 90, 75, 0, 160, 300, null, null],
|
||||
[0, "국의", null, 0, null, 84, 78, 51, 0, 160, 300, null, null],
|
||||
[0, "희지재", null, 0, null, 63, 35, 91, 0, 160, 300, null, null],
|
||||
[0, "위속", null, 0, null, 67, 78, 31, 0, 160, 300, null, null],
|
||||
[0, "위유", null, 0, null, 46, 29, 74, 0, 160, 300, null, null],
|
||||
[0, "우금2", null, 0, null, 72, 79, 38, 0, 160, 300, null, null],
|
||||
[0, "우보", null, 0, null, 38, 60, 21, 0, 160, 300, null, null],
|
||||
[0, "강유", null, 0, null, 92, 80, 93, 0, 160, 300, null, null],
|
||||
[0, "공지", null, 0, null, 43, 53, 62, 0, 160, 300, null, null],
|
||||
[0, "교유", null, 0, null, 64, 69, 38, 0, 160, 300, null, null],
|
||||
[0, "공도", null, 0, null, 59, 70, 23, 0, 160, 300, null, null],
|
||||
[0, "허공", null, 0, null, 44, 66, 64, 0, 160, 300, null, null],
|
||||
[0, "허정", null, 0, null, 23, 5, 68, 0, 160, 300, null, null],
|
||||
[0, "허저", null, 0, null, 74, 97, 36, 0, 160, 300, null, null],
|
||||
[0, "허유", null, 0, null, 36, 21, 80, 0, 160, 300, null, null],
|
||||
[0, "기령", null, 0, null, 85, 84, 51, 0, 160, 300, null, null],
|
||||
[0, "김의", null, 0, null, 32, 38, 65, 0, 160, 300, null, null],
|
||||
[0, "김배삼결", null, 0, null, 64, 76, 19, 0, 160, 300, null, null],
|
||||
[0, "김선", null, 0, null, 52, 68, 13, 0, 160, 300, null, null],
|
||||
[0, "우번", null, 0, null, 46, 46, 87, 0, 160, 300, null, null],
|
||||
[0, "형도영", null, 0, null, 69, 79, 41, 0, 160, 300, null, null],
|
||||
[0, "엄안", null, 0, null, 82, 83, 72, 0, 160, 300, null, null],
|
||||
[0, "엄망", null, 0, null, 68, 71, 40, 0, 160, 300, null, null],
|
||||
[0, "엄준", null, 0, null, 41, 12, 71, 0, 160, 300, null, null],
|
||||
[0, "엄정", null, 0, null, 50, 55, 39, 0, 160, 300, null, null],
|
||||
[0, "엄백호", null, 0, null, 67, 70, 42, 0, 160, 300, null, null],
|
||||
[0, "엄여", null, 0, null, 61, 78, 44, 0, 160, 300, null, null],
|
||||
[0, "오의", null, 0, null, 79, 73, 70, 0, 160, 300, null, null],
|
||||
[0, "황개", null, 0, null, 80, 86, 70, 0, 160, 300, null, null],
|
||||
[0, "고간", null, 0, null, 74, 56, 48, 0, 160, 300, null, null],
|
||||
[0, "황권", null, 0, null, 75, 59, 88, 0, 160, 300, null, null],
|
||||
[0, "고유", null, 0, null, 57, 43, 72, 0, 160, 300, null, null],
|
||||
[0, "고순", null, 0, null, 87, 89, 60, 0, 160, 300, null, null],
|
||||
[0, "고상", null, 0, null, 68, 68, 53, 0, 160, 300, null, null],
|
||||
[0, "고승", null, 0, null, 67, 73, 41, 0, 160, 300, null, null],
|
||||
[0, "후성", null, 0, null, 74, 75, 68, 0, 160, 300, null, null],
|
||||
[0, "후선", null, 0, null, 63, 66, 34, 0, 160, 300, null, null],
|
||||
[0, "황조", null, 0, null, 81, 66, 62, 0, 160, 300, null, null],
|
||||
[0, "공손월", null, 0, null, 74, 72, 47, 0, 160, 300, null, null],
|
||||
[0, "공손연", null, 0, null, 65, 70, 60, 0, 160, 300, null, null],
|
||||
[0, "공손공", null, 0, null, 39, 17, 69, 0, 160, 300, null, null],
|
||||
[0, "공손강", null, 0, null, 72, 66, 65, 0, 160, 300, null, null],
|
||||
[0, "공손찬", null, 0, null, 86, 82, 60, 0, 160, 300, null, null],
|
||||
[0, "공손속", null, 0, null, 63, 68, 57, 0, 160, 300, null, null],
|
||||
[0, "공손도", null, 0, null, 67, 71, 66, 0, 160, 300, null, null],
|
||||
[0, "공손범", null, 0, null, 73, 69, 66, 0, 160, 300, null, null],
|
||||
[0, "황충", null, 0, null, 88, 96, 70, 0, 160, 300, null, null],
|
||||
[0, "고정", null, 0, null, 55, 63, 43, 0, 160, 300, null, null],
|
||||
[0, "고패", null, 0, null, 66, 61, 69, 0, 160, 300, null, null],
|
||||
[0, "황보숭", null, 0, null, 91, 61, 82, 0, 160, 300, null, null],
|
||||
[0, "공융", null, 0, null, 30, 5, 73, 0, 160, 300, null, null],
|
||||
[0, "고람", null, 0, null, 76, 82, 68, 0, 160, 300, null, null],
|
||||
[0, "오경", null, 0, null, 69, 66, 52, 0, 160, 300, null, null],
|
||||
[0, "호거아", null, 0, null, 70, 82, 41, 0, 160, 300, null, null],
|
||||
[0, "호진", null, 0, null, 65, 74, 12, 0, 160, 300, null, null],
|
||||
[0, "올돌골", null, 0, null, 79, 86, 11, 0, 160, 300, null, null],
|
||||
[0, "호반", null, 0, null, 55, 55, 59, 0, 160, 300, null, null],
|
||||
[0, "오반", null, 0, null, 74, 71, 59, 0, 160, 300, null, null],
|
||||
[0, "고옹", null, 0, null, 52, 18, 81, 0, 160, 300, null, null],
|
||||
[0, "오란", null, 0, null, 68, 80, 35, 0, 160, 300, null, null],
|
||||
[0, "채화", null, 0, null, 39, 50, 1, 0, 160, 300, null, null],
|
||||
[0, "채중", null, 0, null, 40, 54, 2, 0, 160, 300, null, null],
|
||||
[0, "채모", null, 0, null, 70, 70, 77, 0, 160, 300, null, null],
|
||||
[0, "착융", null, 0, null, 60, 69, 38, 0, 160, 300, null, null],
|
||||
[0, "사마의", null, 0, null, 99, 63, 98, 0, 160, 300, null, null],
|
||||
[0, "사마염", null, 0, null, 69, 59, 77, 0, 160, 300, null, null],
|
||||
[0, "사마사", null, 0, null, 84, 64, 89, 0, 160, 300, null, null],
|
||||
[0, "사마소", null, 0, null, 85, 57, 88, 0, 160, 300, null, null],
|
||||
[0, "사마부", null, 0, null, 70, 37, 77, 0, 160, 300, null, null],
|
||||
[0, "사마랑", null, 0, null, 20, 21, 72, 0, 160, 300, null, null],
|
||||
[0, "사마가", null, 0, null, 66, 84, 25, 0, 160, 300, null, null],
|
||||
[0, "주흔", null, 0, null, 65, 62, 73, 0, 160, 300, null, null],
|
||||
[0, "주앙", null, 0, null, 74, 65, 65, 0, 160, 300, null, null],
|
||||
[0, "주지", null, 0, null, 73, 85, 41, 0, 160, 300, null, null],
|
||||
[0, "주창", null, 0, null, 68, 77, 42, 0, 160, 300, null, null],
|
||||
[0, "주태", null, 0, null, 84, 90, 48, 0, 160, 300, null, null],
|
||||
[0, "주방", null, 0, null, 52, 41, 80, 0, 160, 300, null, null],
|
||||
[0, "주유", null, 0, null, 97, 71, 98, 0, 160, 300, null, null],
|
||||
[0, "주환", null, 0, null, 87, 84, 77, 0, 160, 300, null, null],
|
||||
[0, "주거", null, 0, null, 77, 57, 72, 0, 160, 300, null, null],
|
||||
[0, "축융", null, 0, null, 72, 75, 35, 0, 160, 300, null, null],
|
||||
[0, "주준", null, 0, null, 89, 65, 76, 0, 160, 300, null, null],
|
||||
[0, "주연", null, 0, null, 86, 75, 74, 0, 160, 300, null, null],
|
||||
[0, "주치", null, 0, null, 71, 56, 72, 0, 160, 300, null, null],
|
||||
[0, "주포", null, 0, null, 68, 73, 34, 0, 160, 300, null, null],
|
||||
[0, "주령", null, 0, null, 78, 73, 67, 0, 160, 300, null, null],
|
||||
[0, "순욱", null, 0, null, 78, 38, 97, 0, 160, 300, null, null],
|
||||
[0, "순우경", null, 0, null, 78, 66, 29, 0, 160, 300, null, null],
|
||||
[0, "순심", null, 0, null, 45, 25, 78, 0, 160, 300, null, null],
|
||||
[0, "순유", null, 0, null, 80, 35, 95, 0, 160, 300, null, null],
|
||||
[0, "장완", null, 0, null, 78, 34, 89, 0, 160, 300, null, null],
|
||||
[0, "종회", null, 0, null, 88, 62, 93, 0, 160, 300, null, null],
|
||||
[0, "장간", null, 0, null, 19, 6, 66, 0, 160, 300, null, null],
|
||||
[0, "장의거", null, 0, null, 71, 58, 59, 0, 160, 300, null, null],
|
||||
[0, "장흠", null, 0, null, 78, 85, 54, 0, 160, 300, null, null],
|
||||
[0, "장제3", null, 0, null, 62, 43, 85, 0, 160, 300, null, null],
|
||||
[0, "초주", null, 0, null, 16, 3, 67, 0, 160, 300, null, null],
|
||||
[0, "초촉", null, 0, null, 65, 76, 33, 0, 160, 300, null, null],
|
||||
[0, "향총", null, 0, null, 76, 61, 77, 0, 160, 300, null, null],
|
||||
[0, "종요", null, 0, null, 79, 24, 90, 0, 160, 300, null, null],
|
||||
[0, "향랑", null, 0, null, 28, 18, 74, 0, 160, 300, null, null],
|
||||
[0, "서영", null, 0, null, 92, 80, 62, 0, 160, 300, null, null],
|
||||
[0, "제갈각", null, 0, null, 72, 47, 90, 0, 160, 300, null, null],
|
||||
[0, "제갈근", null, 0, null, 75, 34, 85, 0, 160, 300, null, null],
|
||||
[0, "제갈균", null, 0, null, 29, 25, 52, 0, 160, 300, null, null],
|
||||
[0, "제갈탄", null, 0, null, 72, 72, 76, 0, 160, 300, null, null],
|
||||
[0, "제갈량", null, 0, null, 98, 43, 100, 0, 160, 300, null, null],
|
||||
[0, "서황", null, 0, null, 95, 94, 78, 0, 160, 300, null, null],
|
||||
[0, "서서", null, 0, null, 90, 64, 94, 0, 160, 300, null, null],
|
||||
[0, "서성", null, 0, null, 86, 81, 78, 0, 160, 300, null, null],
|
||||
[0, "서막", null, 0, null, 55, 32, 68, 0, 160, 300, null, null],
|
||||
[0, "신의", null, 0, null, 55, 59, 60, 0, 160, 300, null, null],
|
||||
[0, "신탐", null, 0, null, 56, 62, 54, 0, 160, 300, null, null],
|
||||
[0, "심배", null, 0, null, 80, 60, 84, 0, 160, 300, null, null],
|
||||
[0, "신비", null, 0, null, 42, 24, 79, 0, 160, 300, null, null],
|
||||
[0, "신평", null, 0, null, 69, 43, 77, 0, 160, 300, null, null],
|
||||
[0, "진복", null, 0, null, 31, 7, 73, 0, 160, 300, null, null],
|
||||
[0, "진랑", null, 0, null, 58, 70, 35, 0, 160, 300, null, null],
|
||||
[0, "휴고", null, 0, null, 63, 71, 38, 0, 160, 300, null, null],
|
||||
[0, "추단", null, 0, null, 61, 64, 34, 0, 160, 300, null, null],
|
||||
[0, "성의", null, 0, null, 74, 72, 41, 0, 160, 300, null, null],
|
||||
[0, "성공영", null, 0, null, 73, 71, 80, 0, 160, 300, null, null],
|
||||
[0, "설종", null, 0, null, 34, 16, 73, 0, 160, 300, null, null],
|
||||
[0, "단경1", null, 0, null, 71, 68, 43, 0, 160, 300, null, null],
|
||||
[0, "전종", null, 0, null, 78, 72, 75, 0, 160, 300, null, null],
|
||||
[0, "조예", null, 0, null, 72, 52, 82, 0, 160, 300, null, null],
|
||||
[0, "조휴", null, 0, null, 84, 78, 62, 0, 160, 300, null, null],
|
||||
[0, "송헌", null, 0, null, 68, 77, 38, 0, 160, 300, null, null],
|
||||
[0, "조앙", null, 0, null, 78, 67, 69, 0, 160, 300, null, null],
|
||||
[0, "조홍", null, 0, null, 80, 75, 55, 0, 160, 300, null, null],
|
||||
[0, "조순", null, 0, null, 85, 83, 63, 0, 160, 300, null, null],
|
||||
[0, "조창", null, 0, null, 86, 91, 59, 0, 160, 300, null, null],
|
||||
[0, "조식", null, 0, null, 45, 22, 86, 0, 160, 300, null, null],
|
||||
[0, "조진", null, 0, null, 88, 74, 70, 0, 160, 300, null, null],
|
||||
[0, "조인", null, 0, null, 94, 90, 72, 0, 160, 300, null, null],
|
||||
[0, "조성", null, 0, null, 54, 74, 38, 0, 160, 300, null, null],
|
||||
[0, "조조", null, 0, null, 100, 72, 96, 0, 160, 300, null, null],
|
||||
[0, "조충", null, 0, null, 43, 21, 74, 0, 160, 300, null, null],
|
||||
[0, "장패", null, 0, null, 78, 86, 53, 0, 160, 300, null, null],
|
||||
[0, "조비", null, 0, null, 75, 71, 87, 0, 160, 300, null, null],
|
||||
[0, "조표", null, 0, null, 54, 69, 32, 0, 160, 300, null, null],
|
||||
[0, "저수", null, 0, null, 86, 46, 95, 0, 160, 300, null, null],
|
||||
[0, "소비", null, 0, null, 69, 63, 66, 0, 160, 300, null, null],
|
||||
[0, "조무", null, 0, null, 70, 71, 66, 0, 160, 300, null, null],
|
||||
[0, "손환", null, 0, null, 82, 73, 76, 0, 160, 300, null, null],
|
||||
[0, "손견", null, 0, null, 94, 95, 73, 0, 160, 300, null, null],
|
||||
[0, "손건", null, 0, null, 44, 33, 79, 0, 160, 300, null, null],
|
||||
[0, "손권", null, 0, null, 86, 69, 83, 0, 160, 300, null, null],
|
||||
[0, "손교", null, 0, null, 77, 72, 67, 0, 160, 300, null, null],
|
||||
[0, "손책", null, 0, null, 93, 97, 74, 0, 160, 300, null, null],
|
||||
[0, "손소", null, 0, null, 82, 79, 76, 0, 160, 300, null, null],
|
||||
[0, "손정", null, 0, null, 66, 53, 73, 0, 160, 300, null, null],
|
||||
[0, "손중", null, 0, null, 62, 71, 36, 0, 160, 300, null, null],
|
||||
[0, "손등", null, 0, null, 62, 37, 79, 0, 160, 300, null, null],
|
||||
[0, "손유", null, 0, null, 77, 70, 68, 0, 160, 300, null, null],
|
||||
[0, "손익", null, 0, null, 67, 83, 27, 0, 160, 300, null, null],
|
||||
[0, "손례", null, 0, null, 78, 81, 67, 0, 160, 300, null, null],
|
||||
[0, "태사자", null, 0, null, 94, 94, 72, 0, 160, 300, null, null],
|
||||
[0, "대래동주", null, 0, null, 51, 53, 54, 0, 160, 300, null, null],
|
||||
[0, "대릉", null, 0, null, 70, 75, 39, 0, 160, 300, null, null],
|
||||
[0, "타사대왕", null, 0, null, 62, 59, 70, 0, 160, 300, null, null],
|
||||
[0, "담웅", null, 0, null, 58, 73, 14, 0, 160, 300, null, null],
|
||||
[0, "장윤", null, 0, null, 72, 67, 42, 0, 160, 300, null, null],
|
||||
[0, "조운", null, 0, null, 94, 96, 75, 0, 160, 300, null, null],
|
||||
[0, "장위", null, 0, null, 74, 66, 45, 0, 160, 300, null, null],
|
||||
[0, "장영", null, 0, null, 75, 74, 41, 0, 160, 300, null, null],
|
||||
[0, "장연", null, 0, null, 76, 81, 57, 0, 160, 300, null, null],
|
||||
[0, "장횡", null, 0, null, 59, 70, 23, 0, 160, 300, null, null],
|
||||
[0, "장온", null, 0, null, 32, 10, 72, 0, 160, 300, null, null],
|
||||
[0, "장개", null, 0, null, 34, 66, 8, 0, 160, 300, null, null],
|
||||
[0, "장각", null, 0, null, 87, 35, 90, 0, 160, 300, null, null],
|
||||
[0, "장기", null, 0, null, 74, 35, 76, 0, 160, 300, null, null],
|
||||
[0, "장의", null, 0, null, 79, 72, 75, 0, 160, 300, null, null],
|
||||
[0, "장훈", null, 0, null, 72, 68, 41, 0, 160, 300, null, null],
|
||||
[0, "장굉", null, 0, null, 24, 22, 86, 0, 160, 300, null, null],
|
||||
[0, "장합", null, 0, null, 92, 89, 76, 0, 160, 300, null, null],
|
||||
[0, "조홍2", null, 0, null, 66, 72, 28, 0, 160, 300, null, null],
|
||||
[0, "장제2", null, 0, null, 70, 66, 55, 0, 160, 300, null, null],
|
||||
[0, "장수", null, 0, null, 80, 73, 64, 0, 160, 300, null, null],
|
||||
[0, "장소", null, 0, null, 41, 13, 87, 0, 160, 300, null, null],
|
||||
[0, "장송", null, 0, null, 40, 6, 85, 0, 160, 300, null, null],
|
||||
[0, "장임", null, 0, null, 85, 84, 78, 0, 160, 300, null, null],
|
||||
[0, "장제", null, 0, null, 67, 43, 80, 0, 160, 300, null, null],
|
||||
[0, "장막", null, 0, null, 52, 53, 71, 0, 160, 300, null, null],
|
||||
[0, "조범", null, 0, null, 28, 21, 32, 0, 160, 300, null, null],
|
||||
[0, "장비", null, 0, null, 87, 98, 72, 0, 160, 300, null, null],
|
||||
[0, "장포", null, 0, null, 78, 84, 48, 0, 160, 300, null, null],
|
||||
[0, "장보", null, 0, null, 83, 71, 81, 0, 160, 300, null, null],
|
||||
[0, "장만성", null, 0, null, 75, 81, 45, 0, 160, 300, null, null],
|
||||
[0, "장양", null, 0, null, 72, 70, 66, 0, 160, 300, null, null],
|
||||
[0, "장익", null, 0, null, 75, 74, 76, 0, 160, 300, null, null],
|
||||
[0, "장료", null, 0, null, 96, 94, 78, 0, 160, 300, null, null],
|
||||
[0, "장량", null, 0, null, 78, 80, 74, 0, 160, 300, null, null],
|
||||
[0, "조루", null, 0, null, 70, 43, 68, 0, 160, 300, null, null],
|
||||
[0, "장로", null, 0, null, 65, 42, 81, 0, 160, 300, null, null],
|
||||
[0, "진횡", null, 0, null, 64, 63, 26, 0, 160, 300, null, null],
|
||||
[0, "진응", null, 0, null, 62, 72, 45, 0, 160, 300, null, null],
|
||||
[0, "진기", null, 0, null, 58, 65, 43, 0, 160, 300, null, null],
|
||||
[0, "진궁", null, 0, null, 84, 55, 90, 0, 160, 300, null, null],
|
||||
[0, "진교", null, 0, null, 61, 27, 77, 0, 160, 300, null, null],
|
||||
[0, "진군", null, 0, null, 32, 14, 75, 0, 160, 300, null, null],
|
||||
[0, "진규", null, 0, null, 30, 4, 82, 0, 160, 300, null, null],
|
||||
[0, "진식", null, 0, null, 70, 71, 25, 0, 160, 300, null, null],
|
||||
[0, "진진", null, 0, null, 46, 46, 69, 0, 160, 300, null, null],
|
||||
[0, "진태", null, 0, null, 86, 77, 89, 0, 160, 300, null, null],
|
||||
[0, "진등", null, 0, null, 79, 64, 81, 0, 160, 300, null, null],
|
||||
[0, "진도", null, 0, null, 82, 78, 67, 0, 160, 300, null, null],
|
||||
[0, "진무", null, 0, null, 76, 87, 43, 0, 160, 300, null, null],
|
||||
[0, "진란", null, 0, null, 66, 69, 40, 0, 160, 300, null, null],
|
||||
[0, "진림", null, 0, null, 25, 9, 75, 0, 160, 300, null, null],
|
||||
[0, "정욱", null, 0, null, 76, 49, 94, 0, 160, 300, null, null],
|
||||
[0, "정원지", null, 0, null, 69, 74, 17, 0, 160, 300, null, null],
|
||||
[0, "정은", null, 0, null, 69, 73, 40, 0, 160, 300, null, null],
|
||||
[0, "정원", null, 0, null, 70, 76, 35, 0, 160, 300, null, null],
|
||||
[0, "정보", null, 0, null, 84, 79, 79, 0, 160, 300, null, null],
|
||||
[0, "정봉", null, 0, null, 81, 92, 75, 0, 160, 300, null, null],
|
||||
[0, "전위", null, 0, null, 79, 98, 42, 0, 160, 300, null, null],
|
||||
[0, "전해", null, 0, null, 68, 65, 58, 0, 160, 300, null, null],
|
||||
[0, "전주", null, 0, null, 66, 66, 73, 0, 160, 300, null, null],
|
||||
[0, "전풍", null, 0, null, 82, 43, 96, 0, 160, 300, null, null],
|
||||
[0, "전예", null, 0, null, 93, 85, 80, 0, 160, 300, null, null],
|
||||
[0, "동윤", null, 0, null, 47, 28, 79, 0, 160, 300, null, null],
|
||||
[0, "동화", null, 0, null, 57, 34, 75, 0, 160, 300, null, null],
|
||||
[0, "등애", null, 0, null, 92, 80, 94, 0, 160, 300, null, null],
|
||||
[0, "도겸", null, 0, null, 51, 27, 64, 0, 160, 300, null, null],
|
||||
[0, "등현", null, 0, null, 61, 73, 45, 0, 160, 300, null, null],
|
||||
[0, "등지", null, 0, null, 73, 52, 81, 0, 160, 300, null, null],
|
||||
[0, "동습", null, 0, null, 72, 85, 50, 0, 160, 300, null, null],
|
||||
[0, "동승", null, 0, null, 56, 53, 65, 0, 160, 300, null, null],
|
||||
[0, "동소", null, 0, null, 34, 25, 80, 0, 160, 300, null, null],
|
||||
[0, "동탁", null, 0, null, 91, 87, 72, 0, 160, 300, null, null],
|
||||
[0, "동도나", null, 0, null, 68, 73, 31, 0, 160, 300, null, null],
|
||||
[0, "동민", null, 0, null, 49, 60, 25, 0, 160, 300, null, null],
|
||||
[0, "등무", null, 0, null, 61, 75, 29, 0, 160, 300, null, null],
|
||||
[0, "두기", null, 0, null, 74, 43, 78, 0, 160, 300, null, null],
|
||||
[0, "두예", null, 0, null, 96, 69, 95, 0, 160, 300, null, null],
|
||||
[0, "배원소", null, 0, null, 49, 65, 25, 0, 160, 300, null, null],
|
||||
[0, "마완", null, 0, null, 71, 74, 16, 0, 160, 300, null, null],
|
||||
[0, "마휴", null, 0, null, 68, 73, 48, 0, 160, 300, null, null],
|
||||
[0, "파재", null, 0, null, 74, 74, 55, 0, 160, 300, null, null],
|
||||
[0, "마준", null, 0, null, 38, 52, 31, 0, 160, 300, null, null],
|
||||
[0, "마속", null, 0, null, 61, 67, 84, 0, 160, 300, null, null],
|
||||
[0, "마대", null, 0, null, 79, 85, 62, 0, 160, 300, null, null],
|
||||
[0, "마충", null, 0, null, 78, 72, 68, 0, 160, 300, null, null],
|
||||
[0, "마초", null, 0, null, 86, 97, 44, 0, 160, 300, null, null],
|
||||
[0, "마철", null, 0, null, 70, 62, 58, 0, 160, 300, null, null],
|
||||
[0, "마등", null, 0, null, 85, 80, 52, 0, 160, 300, null, null],
|
||||
[0, "마량", null, 0, null, 53, 23, 85, 0, 160, 300, null, null],
|
||||
[0, "반준", null, 0, null, 61, 46, 82, 0, 160, 300, null, null],
|
||||
[0, "반장", null, 0, null, 76, 80, 69, 0, 160, 300, null, null],
|
||||
[0, "번조", null, 0, null, 66, 73, 31, 0, 160, 300, null, null],
|
||||
[0, "번능", null, 0, null, 69, 61, 36, 0, 160, 300, null, null],
|
||||
[0, "반봉", null, 0, null, 56, 77, 4, 0, 160, 300, null, null],
|
||||
[0, "비의", null, 0, null, 82, 56, 88, 0, 160, 300, null, null],
|
||||
[0, "비연", null, 0, null, 60, 66, 21, 0, 160, 300, null, null],
|
||||
[0, "비시", null, 0, null, 18, 28, 65, 0, 160, 300, null, null],
|
||||
[0, "미축", null, 0, null, 33, 29, 78, 0, 160, 300, null, null],
|
||||
[0, "미방", null, 0, null, 54, 61, 32, 0, 160, 300, null, null],
|
||||
[0, "비요", null, 0, null, 70, 66, 73, 0, 160, 300, null, null],
|
||||
[0, "무안국", null, 0, null, 70, 79, 34, 0, 160, 300, null, null],
|
||||
[0, "풍습", null, 0, null, 72, 71, 39, 0, 160, 300, null, null],
|
||||
[0, "부사인", null, 0, null, 46, 63, 37, 0, 160, 300, null, null],
|
||||
[0, "부첨", null, 0, null, 73, 85, 76, 0, 160, 300, null, null],
|
||||
[0, "부손", null, 0, null, 29, 13, 70, 0, 160, 300, null, null],
|
||||
[0, "문앙", null, 0, null, 76, 96, 65, 0, 160, 300, null, null],
|
||||
[0, "문흠", null, 0, null, 74, 79, 43, 0, 160, 300, null, null],
|
||||
[0, "문추", null, 0, null, 87, 95, 49, 0, 160, 300, null, null],
|
||||
[0, "문빙", null, 0, null, 88, 85, 69, 0, 160, 300, null, null],
|
||||
[0, "변희", null, 0, null, 56, 70, 62, 0, 160, 300, null, null],
|
||||
[0, "망아장", null, 0, null, 45, 79, 3, 0, 160, 300, null, null],
|
||||
[0, "봉기", null, 0, null, 56, 48, 84, 0, 160, 300, null, null],
|
||||
[0, "방희", null, 0, null, 60, 38, 69, 0, 160, 300, null, null],
|
||||
[0, "법정", null, 0, null, 82, 47, 94, 0, 160, 300, null, null],
|
||||
[0, "방통", null, 0, null, 79, 34, 97, 0, 160, 300, null, null],
|
||||
[0, "방덕", null, 0, null, 89, 94, 70, 0, 160, 300, null, null],
|
||||
[0, "포륭", null, 0, null, 58, 76, 49, 0, 160, 300, null, null],
|
||||
[0, "목순", null, 0, null, 52, 77, 11, 0, 160, 300, null, null],
|
||||
[0, "목록대왕", null, 0, null, 65, 71, 39, 0, 160, 300, null, null],
|
||||
[0, "보즐", null, 0, null, 83, 51, 81, 0, 160, 300, null, null],
|
||||
[0, "만총", null, 0, null, 88, 64, 87, 0, 160, 300, null, null],
|
||||
[0, "모개", null, 0, null, 63, 39, 60, 0, 160, 300, null, null],
|
||||
[0, "맹획", null, 0, null, 81, 88, 42, 0, 160, 300, null, null],
|
||||
[0, "맹체", null, 0, null, 75, 73, 75, 0, 160, 300, null, null],
|
||||
[0, "맹우", null, 0, null, 50, 68, 22, 0, 160, 300, null, null],
|
||||
[0, "유섭", null, 0, null, 62, 79, 24, 0, 160, 300, null, null],
|
||||
[0, "양부", null, 0, null, 62, 68, 68, 0, 160, 300, null, null],
|
||||
[0, "옹개", null, 0, null, 73, 75, 57, 0, 160, 300, null, null],
|
||||
[0, "양의", null, 0, null, 68, 40, 82, 0, 160, 300, null, null],
|
||||
[0, "양호", null, 0, null, 94, 69, 92, 0, 160, 300, null, null],
|
||||
[0, "양홍", null, 0, null, 33, 15, 77, 0, 160, 300, null, null],
|
||||
[0, "양앙", null, 0, null, 68, 72, 38, 0, 160, 300, null, null],
|
||||
[0, "양추", null, 0, null, 52, 65, 40, 0, 160, 300, null, null],
|
||||
[0, "양수", null, 0, null, 46, 23, 83, 0, 160, 300, null, null],
|
||||
[0, "양추2", null, 0, null, 67, 64, 60, 0, 160, 300, null, null],
|
||||
[0, "양송", null, 0, null, 17, 5, 28, 0, 160, 300, null, null],
|
||||
[0, "양임", null, 0, null, 70, 78, 56, 0, 160, 300, null, null],
|
||||
[0, "양조", null, 0, null, 53, 61, 36, 0, 160, 300, null, null],
|
||||
[0, "양백", null, 0, null, 44, 45, 19, 0, 160, 300, null, null],
|
||||
[0, "양부2", null, 0, null, 67, 50, 83, 0, 160, 300, null, null],
|
||||
[0, "양봉", null, 0, null, 66, 65, 31, 0, 160, 300, null, null],
|
||||
[0, "양봉2", null, 0, null, 54, 62, 53, 0, 160, 300, null, null],
|
||||
[0, "뇌동", null, 0, null, 69, 78, 51, 0, 160, 300, null, null],
|
||||
[0, "뇌박", null, 0, null, 62, 70, 36, 0, 160, 300, null, null],
|
||||
[0, "이이", null, 0, null, 63, 77, 19, 0, 160, 300, null, null],
|
||||
[0, "이회", null, 0, null, 79, 65, 79, 0, 160, 300, null, null],
|
||||
[0, "이각", null, 0, null, 69, 72, 24, 0, 160, 300, null, null],
|
||||
[0, "육항", null, 0, null, 94, 68, 93, 0, 160, 300, null, null],
|
||||
[0, "육적", null, 0, null, 20, 7, 72, 0, 160, 300, null, null],
|
||||
[0, "육손", null, 0, null, 97, 71, 96, 0, 160, 300, null, null],
|
||||
[0, "이엄", null, 0, null, 83, 84, 76, 0, 160, 300, null, null],
|
||||
[0, "이유", null, 0, null, 61, 26, 93, 0, 160, 300, null, null],
|
||||
[0, "이숙", null, 0, null, 46, 69, 61, 0, 160, 300, null, null],
|
||||
[0, "이통", null, 0, null, 73, 81, 62, 0, 160, 300, null, null],
|
||||
[0, "이전", null, 0, null, 78, 80, 79, 0, 160, 300, null, null],
|
||||
[0, "이풍", null, 0, null, 69, 74, 50, 0, 160, 300, null, null],
|
||||
[0, "유언", null, 0, null, 61, 38, 80, 0, 160, 300, null, null],
|
||||
[0, "유괴", null, 0, null, 71, 73, 67, 0, 160, 300, null, null],
|
||||
[0, "유기", null, 0, null, 52, 12, 63, 0, 160, 300, null, null],
|
||||
[0, "유우", null, 0, null, 62, 33, 75, 0, 160, 300, null, null],
|
||||
[0, "유훈", null, 0, null, 47, 63, 35, 0, 160, 300, null, null],
|
||||
[0, "유현", null, 0, null, 54, 66, 51, 0, 160, 300, null, null],
|
||||
[0, "유순", null, 0, null, 63, 46, 41, 0, 160, 300, null, null],
|
||||
[0, "유장", null, 0, null, 31, 5, 34, 0, 160, 300, null, null],
|
||||
[0, "유심", null, 0, null, 60, 62, 70, 0, 160, 300, null, null],
|
||||
[0, "유선", null, 0, null, 3, 5, 9, 0, 160, 300, null, null],
|
||||
[0, "유종", null, 0, null, 24, 22, 65, 0, 160, 300, null, null],
|
||||
[0, "유도", null, 0, null, 25, 23, 26, 0, 160, 300, null, null],
|
||||
[0, "유파", null, 0, null, 29, 22, 75, 0, 160, 300, null, null],
|
||||
[0, "유반", null, 0, null, 69, 76, 47, 0, 160, 300, null, null],
|
||||
[0, "유비", null, 0, null, 88, 78, 75, 0, 160, 300, null, null],
|
||||
[0, "유표", null, 0, null, 48, 31, 72, 0, 160, 300, null, null],
|
||||
[0, "유복", null, 0, null, 64, 49, 74, 0, 160, 300, null, null],
|
||||
[0, "유벽", null, 0, null, 70, 72, 47, 0, 160, 300, null, null],
|
||||
[0, "유봉", null, 0, null, 75, 79, 44, 0, 160, 300, null, null],
|
||||
[0, "유엽", null, 0, null, 56, 32, 92, 0, 160, 300, null, null],
|
||||
[0, "유요", null, 0, null, 62, 67, 46, 0, 160, 300, null, null],
|
||||
[0, "여위황", null, 0, null, 58, 63, 29, 0, 160, 300, null, null],
|
||||
[0, "요화", null, 0, null, 73, 76, 69, 0, 160, 300, null, null],
|
||||
[0, "양흥", null, 0, null, 61, 65, 19, 0, 160, 300, null, null],
|
||||
[0, "양습", null, 0, null, 73, 40, 74, 0, 160, 300, null, null],
|
||||
[0, "양서", null, 0, null, 56, 62, 66, 0, 160, 300, null, null],
|
||||
[0, "능조", null, 0, null, 75, 81, 42, 0, 160, 300, null, null],
|
||||
[0, "능통", null, 0, null, 83, 89, 60, 0, 160, 300, null, null],
|
||||
[0, "여개", null, 0, null, 53, 30, 67, 0, 160, 300, null, null],
|
||||
[0, "여건", null, 0, null, 57, 70, 62, 0, 160, 300, null, null],
|
||||
[0, "여광", null, 0, null, 56, 70, 13, 0, 160, 300, null, null],
|
||||
[0, "여상", null, 0, null, 54, 71, 12, 0, 160, 300, null, null],
|
||||
[0, "여대", null, 0, null, 80, 71, 70, 0, 160, 300, null, null],
|
||||
[0, "여범", null, 0, null, 73, 63, 75, 0, 160, 300, null, null],
|
||||
[0, "여포", null, 0, null, 89, 100, 42, 0, 160, 300, null, null],
|
||||
[0, "여몽", null, 0, null, 91, 81, 90, 0, 160, 300, null, null],
|
||||
[0, "윤직", null, 0, null, 46, 42, 73, 0, 160, 300, null, null],
|
||||
[0, "냉포", null, 0, null, 71, 82, 61, 0, 160, 300, null, null],
|
||||
[0, "누규", null, 0, null, 52, 13, 87, 0, 160, 300, null, null],
|
||||
[0, "노숙", null, 0, null, 89, 56, 93, 0, 160, 300, null, null],
|
||||
[0, "노식", null, 0, null, 86, 63, 82, 0, 160, 300, null, null],
|
||||
[0, "범강", null, 0, null, 49, 50, 36, 0, 160, 300, null, null],
|
||||
[0, "장달", null, 0, null, 43, 56, 34, 0, 160, 300, null, null],
|
||||
[0, "규람", null, 0, null, 55, 70, 58, 0, 160, 300, null, null],
|
||||
[0, "대원", null, 0, null, 38, 32, 68, 0, 160, 300, null, null],
|
||||
[0, "왕기", null, 0, null, 81, 72, 86, 0, 160, 300, null, null],
|
||||
[0, "왕상", null, 0, null, 23, 19, 68, 0, 160, 300, null, null],
|
||||
[0, "왕돈", null, 0, null, 60, 66, 46, 0, 160, 300, null, null],
|
||||
[0, "악침", null, 0, null, 73, 75, 43, 0, 160, 300, null, null],
|
||||
[0, "하제", null, 0, null, 83, 70, 82, 0, 160, 300, null, null],
|
||||
[0, "환범", null, 0, null, 40, 11, 78, 0, 160, 300, null, null],
|
||||
[0, "견초", null, 0, null, 72, 79, 73, 0, 160, 300, null, null],
|
||||
[0, "고당륭", null, 0, null, 35, 24, 76, 0, 160, 300, null, null],
|
||||
[0, "오찬", null, 0, null, 68, 41, 78, 0, 160, 300, null, null],
|
||||
[0, "호질", null, 0, null, 73, 46, 74, 0, 160, 300, null, null],
|
||||
[0, "오질", null, 0, null, 16, 29, 68, 0, 160, 300, null, null],
|
||||
[0, "호준", null, 0, null, 79, 76, 62, 0, 160, 300, null, null],
|
||||
[0, "고담", null, 0, null, 53, 23, 77, 0, 160, 300, null, null],
|
||||
[0, "최림", null, 0, null, 32, 22, 66, 0, 160, 300, null, null],
|
||||
[0, "사마망", null, 0, null, 78, 58, 83, 0, 160, 300, null, null],
|
||||
[0, "주이", null, 0, null, 70, 73, 61, 0, 160, 300, null, null],
|
||||
[0, "전단", null, 0, null, 67, 64, 39, 0, 160, 300, null, null],
|
||||
[0, "조우", null, 0, null, 50, 43, 37, 0, 160, 300, null, null],
|
||||
[0, "조상", null, 0, null, 39, 33, 30, 0, 160, 300, null, null],
|
||||
[0, "조방", null, 0, null, 20, 14, 27, 0, 160, 300, null, null],
|
||||
[0, "태사향", null, 0, null, 57, 66, 48, 0, 160, 300, null, null],
|
||||
[0, "장휴", null, 0, null, 63, 27, 74, 0, 160, 300, null, null],
|
||||
[0, "장호", null, 0, null, 75, 74, 51, 0, 160, 300, null, null],
|
||||
[0, "조광", null, 0, null, 67, 71, 53, 0, 160, 300, null, null],
|
||||
[0, "장집", null, 0, null, 76, 29, 80, 0, 160, 300, null, null],
|
||||
[0, "장승", null, 0, null, 77, 70, 75, 0, 160, 300, null, null],
|
||||
[0, "장소2", null, 0, null, 23, 56, 31, 0, 160, 300, null, null],
|
||||
[0, "조통", null, 0, null, 68, 67, 61, 0, 160, 300, null, null],
|
||||
[0, "진표", null, 0, null, 66, 42, 74, 0, 160, 300, null, null],
|
||||
[0, "정무", null, 0, null, 56, 35, 75, 0, 160, 300, null, null],
|
||||
[0, "정봉2", null, 0, null, 66, 66, 53, 0, 160, 300, null, null],
|
||||
[0, "전만", null, 0, null, 51, 73, 39, 0, 160, 300, null, null],
|
||||
[0, "마균", null, 0, null, 22, 17, 71, 0, 160, 300, null, null],
|
||||
[0, "방회", null, 0, null, 69, 75, 49, 0, 160, 300, null, null],
|
||||
[0, "낙통", null, 0, null, 76, 58, 75, 0, 160, 300, null, null],
|
||||
[0, "육개", null, 0, null, 65, 61, 79, 0, 160, 300, null, null],
|
||||
[0, "유찬", null, 0, null, 78, 81, 64, 0, 160, 300, null, null],
|
||||
[0, "유소", null, 0, null, 68, 53, 74, 0, 160, 300, null, null],
|
||||
[0, "요립", null, 0, null, 32, 15, 76, 0, 160, 300, null, null],
|
||||
[0, "여거", null, 0, null, 78, 69, 71, 0, 160, 300, null, null],
|
||||
[0, "제갈첨", null, 0, null, 70, 57, 76, 0, 160, 300, null, null],
|
||||
[0, "손휴", null, 0, null, 57, 42, 78, 0, 160, 300, null, null],
|
||||
[0, "극정", null, 0, null, 42, 23, 68, 0, 160, 300, null, null],
|
||||
[0, "호분", null, 0, null, 71, 76, 50, 0, 160, 300, null, null],
|
||||
[0, "손량", null, 0, null, 32, 26, 70, 0, 160, 300, null, null],
|
||||
[0, "마막", null, 0, null, 34, 12, 44, 0, 160, 300, null, null],
|
||||
[0, "손호", null, 0, null, 41, 73, 71, 0, 160, 300, null, null],
|
||||
[0, "조모", null, 0, null, 54, 61, 59, 0, 160, 300, null, null],
|
||||
[0, "조환", null, 0, null, 30, 28, 30, 0, 160, 300, null, null],
|
||||
[0, "사마유", null, 0, null, 71, 68, 75, 0, 160, 300, null, null],
|
||||
[0, "제갈상", null, 0, null, 64, 79, 62, 0, 160, 300, null, null],
|
||||
[0, "손화", null, 0, null, 31, 39, 68, 0, 160, 300, null, null],
|
||||
[0, "염우", null, 0, null, 52, 61, 51, 0, 160, 300, null, null],
|
||||
[0, "왕경", null, 0, null, 67, 63, 71, 0, 160, 300, null, null],
|
||||
[0, "왕혼", null, 0, null, 74, 71, 63, 0, 160, 300, null, null],
|
||||
[0, "곽혁", null, 0, null, 33, 29, 70, 0, 160, 300, null, null],
|
||||
[0, "가범", null, 0, null, 60, 62, 73, 0, 160, 300, null, null],
|
||||
[0, "서질", null, 0, null, 68, 83, 24, 0, 160, 300, null, null],
|
||||
[0, "손준", null, 0, null, 64, 70, 65, 0, 160, 300, null, null],
|
||||
[0, "손침", null, 0, null, 58, 55, 65, 0, 160, 300, null, null],
|
||||
[0, "우사", null, 0, null, 61, 34, 74, 0, 160, 300, null, null],
|
||||
[0, "진건", null, 0, null, 72, 71, 65, 0, 160, 300, null, null],
|
||||
[0, "동궐", null, 0, null, 65, 59, 76, 0, 160, 300, null, null],
|
||||
[0, "당자", null, 0, null, 61, 71, 50, 0, 160, 300, null, null],
|
||||
[0, "등충", null, 0, null, 76, 80, 69, 0, 160, 300, null, null],
|
||||
[0, "황숭", null, 0, null, 67, 63, 72, 0, 160, 300, null, null],
|
||||
[0, "화핵", null, 0, null, 20, 24, 71, 0, 160, 300, null, null],
|
||||
[0, "허의", null, 0, null, 51, 74, 15, 0, 160, 300, null, null],
|
||||
[0, "송겸", null, 0, null, 66, 78, 42, 0, 160, 300, null, null],
|
||||
[0, "호제", null, 0, null, 57, 39, 68, 0, 160, 300, null, null],
|
||||
[0, "나헌", null, 0, null, 86, 70, 82, 0, 160, 300, null, null],
|
||||
[0, "노숙2", null, 0, null, 73, 53, 74, 0, 160, 300, null, null],
|
||||
[0, "구성", null, 0, null, 63, 70, 38, 0, 160, 300, null, null],
|
||||
[0, "어부라", null, 0, null, 72, 68, 21, 0, 160, 300, null, null],
|
||||
[0, "아하소과", null, 0, null, 61, 76, 13, 0, 160, 300, null, null],
|
||||
[0, "가비능", null, 0, null, 77, 69, 52, 0, 160, 300, null, null],
|
||||
[0, "구력거", null, 0, null, 80, 68, 56, 0, 160, 300, null, null],
|
||||
[0, "강단", null, 0, null, 65, 83, 48, 0, 160, 300, null, null],
|
||||
[0, "황란", null, 0, null, 63, 75, 44, 0, 160, 300, null, null],
|
||||
[0, "호주천", null, 0, null, 70, 71, 40, 0, 160, 300, null, null],
|
||||
[0, "종리목", null, 0, null, 84, 72, 82, 0, 160, 300, null, null],
|
||||
[0, "제갈교", null, 0, null, 62, 27, 75, 0, 160, 300, null, null],
|
||||
[0, "답돈", null, 0, null, 84, 82, 61, 0, 160, 300, null, null],
|
||||
[0, "반임", null, 0, null, 66, 79, 38, 0, 160, 300, null, null],
|
||||
[0, "보도근", null, 0, null, 64, 73, 50, 0, 160, 300, null, null],
|
||||
[0, "미당대왕", null, 0, null, 59, 69, 21, 0, 160, 300, null, null],
|
||||
[0, "유표2", null, 0, null, 73, 74, 48, 0, 160, 300, null, null],
|
||||
[0, "루반", null, 0, null, 65, 76, 39, 0, 160, 300, null, null],
|
||||
[0, "손관", null, 0, null, 72, 78, 51, 0, 160, 300, null, null],
|
||||
[0, "곽석", null, 0, null, 59, 71, 48, 0, 160, 300, null, null],
|
||||
[0, "주조", null, 0, null, 63, 68, 26, 0, 160, 300, null, null],
|
||||
[0, "장거", null, 0, null, 79, 75, 56, 0, 160, 300, null, null],
|
||||
[0, "장순", null, 0, null, 73, 81, 60, 0, 160, 300, null, null],
|
||||
[0, "철리길", null, 0, null, 77, 70, 52, 0, 160, 300, null, null],
|
||||
[0, "주삭", null, 0, null, 54, 60, 50, 0, 160, 300, null, null],
|
||||
[0, "황월영", null, 0, null, 46, 33, 78, 0, 160, 300, null, null],
|
||||
[0, "채염", null, 0, null, 42, 26, 82, 0, 160, 300, null, null],
|
||||
[0, "소교", null, 0, null, 23, 15, 78, 0, 160, 300, null, null],
|
||||
[0, "신헌영", null, 0, null, 65, 35, 90, 0, 160, 300, null, null],
|
||||
[0, "손상향", null, 0, null, 72, 79, 55, 0, 160, 300, null, null],
|
||||
[0, "대교", null, 0, null, 22, 30, 78, 0, 160, 300, null, null],
|
||||
[0, "초선", null, 0, null, 12, 22, 71, 0, 160, 300, null, null],
|
||||
[0, "교모", null, 0, null, 54, 45, 69, 0, 160, 300, null, null],
|
||||
[0, "관구수", null, 0, null, 58, 62, 33, 0, 160, 300, null, null],
|
||||
[0, "관구전", null, 0, null, 63, 60, 69, 0, 160, 300, null, null],
|
||||
[0, "원유", null, 0, null, 56, 40, 73, 0, 160, 300, null, null],
|
||||
[0, "왕광", null, 0, null, 65, 55, 61, 0, 160, 300, null, null],
|
||||
[0, "신창", null, 0, null, 50, 26, 42, 0, 160, 300, null, null],
|
||||
[0, "사마주", null, 0, null, 61, 52, 61, 0, 160, 300, null, null],
|
||||
[0, "양제", null, 0, null, 67, 68, 71, 0, 160, 300, null, null],
|
||||
[0, "성만", null, 0, null, 61, 68, 66, 0, 160, 300, null, null],
|
||||
[0, "오연", null, 0, null, 66, 73, 42, 0, 160, 300, null, null],
|
||||
[0, "맹충", null, 0, null, 47, 28, 72, 0, 160, 300, null, null],
|
||||
[0, "잠혼", null, 0, null, 1, 1, 22, 0, 160, 300, null, null],
|
||||
[0, "사정", null, 0, null, 64, 76, 34, 0, 160, 300, null, null],
|
||||
[0, "심영", null, 0, null, 70, 77, 61, 0, 160, 300, null, null],
|
||||
[0, "도준", null, 0, null, 65, 66, 46, 0, 160, 300, null, null],
|
||||
[0, "만욱", null, 0, null, 21, 25, 71, 0, 160, 300, null, null],
|
||||
[0, "오언", null, 0, null, 76, 81, 65, 0, 160, 300, null, null],
|
||||
[0, "위막", null, 0, null, 57, 62, 59, 0, 160, 300, null, null],
|
||||
[0, "시삭", null, 0, null, 38, 65, 47, 0, 160, 300, null, null],
|
||||
[0, "전속", null, 0, null, 47, 60, 55, 0, 160, 300, null, null],
|
||||
[0, "장화", null, 0, null, 36, 27, 78, 0, 160, 300, null, null],
|
||||
[0, "오거", null, 0, null, 49, 61, 23, 0, 160, 300, null, null],
|
||||
[0, "추정", null, 0, null, 70, 64, 66, 0, 160, 300, null, null],
|
||||
[0, "장특", null, 0, null, 73, 54, 75, 0, 160, 300, null, null],
|
||||
[0, "곽마", null, 0, null, 68, 71, 47, 0, 160, 300, null, null],
|
||||
[0, "석포", null, 0, null, 69, 71, 56, 0, 160, 300, null, null],
|
||||
[0, "견홍", null, 0, null, 70, 74, 66, 0, 160, 300, null, null],
|
||||
[0, "한거자", null, 0, null, 51, 59, 51, 0, 160, 300, null, null],
|
||||
[0, "휴원진", null, 0, null, 52, 68, 45, 0, 160, 300, null, null],
|
||||
[0, "곽원", null, 0, null, 66, 73, 36, 0, 160, 300, null, null],
|
||||
[0, "계옹", null, 0, null, 63, 52, 41, 0, 160, 300, null, null],
|
||||
[0, "이부", null, 0, null, 31, 36, 74, 0, 160, 300, null, null],
|
||||
[0, "왕업", null, 0, null, 33, 6, 35, 0, 160, 300, null, null],
|
||||
[0, "좌혁", null, 0, null, 62, 66, 51, 0, 160, 300, null, null],
|
||||
[0, "화타", null, 0, null, 57, 25, 73, 0, 160, 300, null, null],
|
||||
[0, "사마휘", null, 0, null, 55, 26, 82, 0, 160, 300, null, null],
|
||||
[0, "우길", null, 0, null, 23, 15, 90, 0, 160, 300, null, null],
|
||||
[0, "헌제", null, 0, null, 22, 18, 68, 0, 160, 300, null, null],
|
||||
[0, "왕검", null, 0, null, 92, 51, 91, 0, 160, 300, null, null],
|
||||
[0, "위만", null, 0, null, 93, 90, 62, 0, 160, 300, null, null],
|
||||
[0, "부분노", null, 0, null, 97, 68, 96, 0, 160, 300, null, null],
|
||||
[0, "무휼", null, 0, null, 132, 141, 43, 0, 160, 300, null, "위압"],
|
||||
[0, "태조대왕", null, 0, null, 92, 63, 91, 0, 160, 300, null, null],
|
||||
[0, "명림답부", null, 0, null, 94, 68, 99, 0, 160, 300, null, null],
|
||||
[0, "달가", null, 0, null, 91, 60, 96, 0, 160, 300, null, null],
|
||||
[0, "고노자", null, 0, null, 93, 96, 62, 0, 160, 300, null, null],
|
||||
[0, "미천왕", null, 0, null, 91, 60, 88, 0, 160, 300, null, null],
|
||||
[0, "고무", null, 0, null, 90, 93, 63, 0, 160, 300, null, null],
|
||||
[0, "광개토대왕", null, 0, null, 145, 132, 42, 0, 160, 300, null, "필살"],
|
||||
[0, "장수왕", null, 0, null, 97, 94, 63, 0, 160, 300, null, null],
|
||||
[0, "을지문덕", null, 0, null, 138, 43, 141, 0, 160, 300, null, "환술"],
|
||||
[0, "고흘", null, 0, null, 88, 91, 63, 0, 160, 300, null, null],
|
||||
[0, "온달", null, 0, null, 90, 92, 60, 0, 160, 300, null, null],
|
||||
[0, "고건무", null, 0, null, 97, 91, 71, 0, 160, 300, null, null],
|
||||
[0, "양만춘", null, 0, null, 98, 69, 91, 0, 160, 300, null, null],
|
||||
[0, "연개소문", null, 0, null, 92, 66, 91, 0, 160, 300, null, null],
|
||||
[0, "근초고왕", null, 0, null, 93, 93, 70, 0, 160, 300, null, null],
|
||||
[0, "목라근자", null, 0, null, 89, 90, 68, 0, 160, 300, null, null],
|
||||
[0, "근구수왕", null, 0, null, 90, 63, 89, 0, 160, 300, null, null],
|
||||
[0, "사법명", null, 0, null, 91, 66, 92, 0, 160, 300, null, null],
|
||||
[0, "찬수류", null, 0, null, 87, 60, 83, 0, 160, 300, null, null],
|
||||
[0, "해례곤", null, 0, null, 86, 88, 59, 0, 160, 300, null, null],
|
||||
[0, "목간나", null, 0, null, 85, 87, 61, 0, 160, 300, null, null],
|
||||
[0, "윤충", null, 0, null, 90, 87, 59, 0, 160, 300, null, null],
|
||||
[0, "의직", null, 0, null, 85, 61, 83, 0, 160, 300, null, null],
|
||||
[0, "계백", null, 0, null, 93, 71, 94, 0, 160, 300, null, null],
|
||||
[0, "귀실복신", null, 0, null, 83, 57, 82, 0, 160, 300, null, null],
|
||||
[0, "흑치상지", null, 0, null, 90, 73, 92, 0, 160, 300, null, null],
|
||||
[0, "이사금", null, 0, null, 98, 93, 71, 0, 160, 300, null, null],
|
||||
[0, "물계자", null, 0, null, 88, 94, 43, 0, 160, 300, null, null],
|
||||
[0, "석우로", null, 0, null, 87, 91, 54, 0, 160, 300, null, null],
|
||||
[0, "이사부", null, 0, null, 90, 72, 93, 0, 160, 300, null, null],
|
||||
[0, "거칠부", null, 0, null, 92, 73, 90, 0, 160, 300, null, null],
|
||||
[0, "진흥왕", null, 0, null, 91, 66, 91, 0, 160, 300, null, null],
|
||||
[0, "사다함", null, 0, null, 86, 91, 66, 0, 160, 300, null, null],
|
||||
[0, "김세종", null, 0, null, 88, 63, 87, 0, 160, 300, null, null],
|
||||
[0, "김무력", null, 0, null, 90, 93, 63, 0, 160, 300, null, null],
|
||||
[0, "알천", null, 0, null, 93, 96, 51, 0, 160, 300, null, null],
|
||||
[0, "김유신", null, 0, null, 128, 66, 131, 0, 160, 300, null, "환술"],
|
||||
[0, "김흠돌", null, 0, null, 87, 90, 52, 0, 160, 300, null, null],
|
||||
[0, "김품일", null, 0, null, 83, 56, 82, 0, 160, 300, null, null],
|
||||
[0, "김천존", null, 0, null, 84, 60, 82, 0, 160, 300, null, null],
|
||||
[0, "죽지", null, 0, null, 83, 86, 52, 0, 160, 300, null, null],
|
||||
[0, "문무왕", null, 0, null, 92, 73, 96, 0, 160, 300, null, null],
|
||||
[0, "시득", null, 0, null, 98, 67, 90, 0, 160, 300, null, null],
|
||||
[0, "장보고", null, 0, null, 99, 72, 96, 0, 160, 300, null, null],
|
||||
[0, "김웅원", null, 0, null, 92, 91, 66, 0, 160, 300, null, null],
|
||||
[0, "대조영", null, 0, null, 96, 92, 63, 0, 160, 300, null, null],
|
||||
[0, "대무예", null, 0, null, 90, 97, 59, 0, 160, 300, null, null],
|
||||
[0, "장문휴", null, 0, null, 88, 89, 53, 0, 160, 300, null, null],
|
||||
[0, "대인수", null, 0, null, 89, 60, 85, 0, 160, 300, null, null],
|
||||
[0, "궁예", null, 0, null, 91, 90, 57, 0, 160, 300, null, null],
|
||||
[0, "왕건", null, 0, null, 141, 43, 138, 0, 160, 300, null, "집중"],
|
||||
[0, "이흔암", null, 0, null, 83, 82, 49, 0, 160, 300, null, null],
|
||||
[0, "견훤", null, 0, null, 91, 65, 90, 0, 160, 300, null, null],
|
||||
[0, "상귀", null, 0, null, 87, 88, 55, 0, 160, 300, null, null],
|
||||
[0, "상애", null, 0, null, 76, 69, 41, 0, 160, 300, null, null],
|
||||
[0, "관흔", null, 0, null, 79, 52, 83, 0, 160, 300, null, null],
|
||||
[0, "유금필", null, 0, null, 87, 94, 58, 0, 160, 300, null, null],
|
||||
[0, "배현경", null, 0, null, 86, 48, 90, 0, 160, 300, null, null],
|
||||
[0, "서희", null, 0, null, 71, 26, 99, 0, 160, 300, null, null],
|
||||
[0, "양규", null, 0, null, 95, 66, 93, 0, 160, 300, null, null],
|
||||
[0, "김숙흥", null, 0, null, 87, 90, 57, 0, 160, 300, null, null],
|
||||
[0, "지채문", null, 0, null, 86, 63, 88, 0, 160, 300, null, null],
|
||||
[0, "강감찬", null, 0, null, 94, 68, 96, 0, 160, 300, null, null],
|
||||
[0, "강민첨", null, 0, null, 92, 93, 64, 0, 160, 300, null, null],
|
||||
[0, "윤관", null, 0, null, 87, 58, 86, 0, 160, 300, null, null],
|
||||
[0, "척준경", null, 0, null, 112, 156, 51, 0, 160, 300, null, "무쌍"],
|
||||
[0, "허재", null, 0, null, 73, 48, 81, 0, 160, 300, null, null],
|
||||
[0, "김의원", null, 0, null, 80, 86, 51, 0, 160, 300, null, null],
|
||||
[0, "김부식", null, 0, null, 51, 21, 92, 0, 160, 300, null, null],
|
||||
[0, "두경승", null, 0, null, 88, 62, 86, 0, 160, 300, null, null],
|
||||
[0, "김취려", null, 0, null, 90, 88, 58, 0, 160, 300, null, null],
|
||||
[0, "박서", null, 0, null, 86, 52, 87, 0, 160, 300, null, null],
|
||||
[0, "김경손", null, 0, null, 73, 92, 58, 0, 160, 300, null, null],
|
||||
[0, "김윤후", null, 0, null, 82, 51, 83, 0, 160, 300, null, null],
|
||||
[0, "김방경", null, 0, null, 93, 56, 87, 0, 160, 300, null, null],
|
||||
[0, "정세운", null, 0, null, 86, 82, 62, 0, 160, 300, null, null],
|
||||
[0, "최영", null, 0, null, 96, 92, 71, 0, 160, 300, null, null],
|
||||
[0, "정지", null, 0, null, 88, 91, 66, 0, 160, 300, null, null],
|
||||
[0, "최무선", null, 0, null, 87, 59, 93, 0, 160, 300, null, null],
|
||||
[0, "이성계", null, 0, null, 141, 50, 133, 0, 160, 300, null, "신중"],
|
||||
[0, "김성우", null, 0, null, 87, 84, 53, 0, 160, 300, null, null],
|
||||
[0, "김종서", null, 0, null, 93, 66, 92, 0, 160, 300, null, null],
|
||||
[0, "남이", null, 0, null, 89, 90, 63, 0, 160, 300, null, null],
|
||||
[0, "권율", null, 0, null, 94, 70, 93, 0, 160, 300, null, null],
|
||||
[0, "황진", null, 0, null, 87, 96, 53, 0, 160, 300, null, null],
|
||||
[0, "곽재우", null, 0, null, 132, 144, 44, 0, 160, 300, null, "필살"],
|
||||
[0, "김시민", null, 0, null, 93, 72, 96, 0, 160, 300, null, null],
|
||||
[0, "이순신", null, 0, null, 148, 40, 142, 0, 160, 300, null, "집중"],
|
||||
[0, "정문부", null, 0, null, 87, 56, 83, 0, 160, 300, null, null],
|
||||
[0, "정충신", null, 0, null, 82, 51, 90, 0, 160, 300, null, null],
|
||||
[0, "원균", null, 0, null, 1, 1, 1, 0, 160, 300, null, null],
|
||||
[0, "관중", null, 0, null, 91, 45, 98, 0, 160, 300, null, null],
|
||||
[0, "몽무", null, 0, null, 88, 96, 53, 0, 160, 300, null, null],
|
||||
[0, "몽염", null, 0, null, 91, 83, 71, 0, 160, 300, null, null],
|
||||
[0, "몽오", null, 0, null, 90, 86, 60, 0, 160, 300, null, null],
|
||||
[0, "방난", null, 0, null, 91, 57, 93, 0, 160, 300, null, null],
|
||||
[0, "백기", null, 0, null, 100, 63, 92, 0, 160, 300, null, null],
|
||||
[0, "범려", null, 0, null, 78, 22, 96, 0, 160, 300, null, null],
|
||||
[0, "사마양저", null, 0, null, 88, 51, 92, 0, 160, 300, null, null],
|
||||
[0, "사마착", null, 0, null, 93, 91, 66, 0, 160, 300, null, null],
|
||||
[0, "손빈", null, 0, null, 80, 16, 96, 0, 160, 300, null, null],
|
||||
[0, "손무", null, 0, null, 98, 32, 100, 0, 160, 300, null, null],
|
||||
[0, "신릉군", null, 0, null, 81, 39, 90, 0, 160, 300, null, null],
|
||||
[0, "악양", null, 0, null, 83, 36, 96, 0, 160, 300, null, null],
|
||||
[0, "악의", null, 0, null, 132, 48, 141, 0, 160, 300, null, "환술"],
|
||||
[0, "염파", null, 0, null, 98, 97, 80, 0, 160, 300, null, null],
|
||||
[0, "오기", null, 0, null, 93, 39, 95, 0, 160, 300, null, null],
|
||||
[0, "오운", null, 0, null, 88, 51, 90, 0, 160, 300, null, null],
|
||||
[0, "왕분", null, 0, null, 89, 91, 68, 0, 160, 300, null, null],
|
||||
[0, "왕전", null, 0, null, 95, 66, 93, 0, 160, 300, null, null],
|
||||
[0, "왕흘", null, 0, null, 93, 92, 60, 0, 160, 300, null, null],
|
||||
[0, "이목", null, 0, null, 96, 69, 98, 0, 160, 300, null, null],
|
||||
[0, "이신", null, 0, null, 89, 90, 57, 0, 160, 300, null, null],
|
||||
[0, "전단2", null, 0, null, 94, 59, 93, 0, 160, 300, null, null],
|
||||
[0, "조사", null, 0, null, 91, 63, 91, 0, 160, 300, null, null],
|
||||
[0, "진개", null, 0, null, 88, 87, 50, 0, 160, 300, null, null],
|
||||
[0, "항연", null, 0, null, 90, 88, 60, 0, 160, 300, null, null],
|
||||
[0, "한신", null, 0, null, 100, 74, 95, 0, 160, 300, null, null],
|
||||
[0, "항적", null, 0, null, 118, 153, 47, 0, 160, 300, null, "무쌍"],
|
||||
[0, "장한", null, 0, null, 88, 66, 87, 0, 160, 300, null, null],
|
||||
[0, "유방", null, 0, null, 90, 66, 85, 0, 160, 300, null, null],
|
||||
[0, "조참", null, 0, null, 89, 53, 87, 0, 160, 300, null, null],
|
||||
[0, "팽월", null, 0, null, 92, 93, 60, 0, 160, 300, null, null],
|
||||
[0, "영포", null, 0, null, 93, 93, 58, 0, 160, 300, null, null],
|
||||
[0, "종리말", null, 0, null, 90, 83, 66, 0, 160, 300, null, null],
|
||||
[0, "주발", null, 0, null, 82, 50, 83, 0, 160, 300, null, null],
|
||||
[0, "번쾌", null, 0, null, 87, 92, 63, 0, 160, 300, null, null],
|
||||
[0, "역상", null, 0, null, 83, 52, 83, 0, 160, 300, null, null],
|
||||
[0, "관영", null, 0, null, 86, 87, 60, 0, 160, 300, null, null],
|
||||
[0, "부관", null, 0, null, 83, 58, 88, 0, 160, 300, null, null],
|
||||
[0, "근흡", null, 0, null, 86, 90, 52, 0, 160, 300, null, null],
|
||||
[0, "왕릉2", null, 0, null, 90, 87, 56, 0, 160, 300, null, null],
|
||||
[0, "계포", null, 0, null, 83, 62, 90, 0, 160, 300, null, null],
|
||||
[0, "용저", null, 0, null, 86, 92, 41, 0, 160, 300, null, null],
|
||||
[0, "곽거병", null, 0, null, 93, 92, 53, 0, 160, 300, null, null],
|
||||
[0, "마원", null, 0, null, 90, 52, 83, 0, 160, 300, null, null],
|
||||
[0, "위청", null, 0, null, 92, 91, 52, 0, 160, 300, null, null],
|
||||
[0, "주아부", null, 0, null, 86, 41, 92, 0, 160, 300, null, null],
|
||||
[0, "곽자의", null, 0, null, 92, 97, 44, 0, 160, 300, null, null],
|
||||
[0, "나오에 카네츠구", null, 0, null, 87, 91, 42, 0, 160, 300, null, null],
|
||||
[0, "다케다 신겐", null, 0, null, 91, 50, 93, 0, 160, 300, null, null],
|
||||
[0, "도요토미 히데요시", null, 0, null, 98, 70, 97, 0, 160, 300, null, null],
|
||||
[0, "고니시 유키나가", null, 0, null, 96, 68, 94, 0, 160, 300, null, null],
|
||||
[0, "가토 기요마사", null, 0, null, 92, 93, 66, 0, 160, 300, null, null],
|
||||
[0, "도요토미 히데나가", null, 0, null, 94, 70, 92, 0, 160, 300, null, null],
|
||||
[0, "도도 다카토라", null, 0, null, 90, 92, 62, 0, 160, 300, null, null],
|
||||
[0, "도쿠가와 이에야스", null, 0, null, 92, 68, 91, 0, 160, 300, null, null],
|
||||
[0, "모리 모토나리", null, 0, null, 88, 42, 96, 0, 160, 300, null, null],
|
||||
[0, "우에스기 겐신", null, 0, null, 91, 96, 78, 0, 160, 300, null, null],
|
||||
[0, "오다 노부나가", null, 0, null, 93, 73, 92, 0, 160, 300, null, null],
|
||||
[0, "이마가와 요시모토", null, 0, null, 89, 91, 71, 0, 160, 300, null, null],
|
||||
[0, "사나다 마사유키", null, 0, null, 93, 66, 90, 0, 160, 300, null, null],
|
||||
[0, "사나다 노부시게", null, 0, null, 94, 92, 70, 0, 160, 300, null, null],
|
||||
[0, "시마즈 이에히사", null, 0, null, 96, 94, 63, 0, 160, 300, null, null],
|
||||
[0, "시마즈 요시히로", null, 0, null, 93, 63, 88, 0, 160, 300, null, null],
|
||||
[0, "코바야카와타카카게", null, 0, null, 90, 61, 92, 0, 160, 300, null, null],
|
||||
[0, "타치바나 도세츠", null, 0, null, 91, 89, 71, 0, 160, 300, null, null],
|
||||
[0, "타치바나 무네시게", null, 0, null, 90, 69, 88, 0, 160, 300, null, null],
|
||||
[0, "타카하시 쇼운", null, 0, null, 92, 91, 70, 0, 160, 300, null, null],
|
||||
[0, "호조 우지야스", null, 0, null, 89, 58, 91, 0, 160, 300, null, null],
|
||||
[0, "칭기즈 칸", null, 0, null, 151, 121, 43, 0, 160, 300, null, "위압"],
|
||||
[0, "오고타이 칸", null, 0, null, 98, 93, 64, 0, 160, 300, null, null],
|
||||
[0, "자무카", null, 0, null, 97, 96, 60, 0, 160, 300, null, null],
|
||||
[0, "수부타이", null, 0, null, 94, 71, 91, 0, 160, 300, null, null],
|
||||
[0, "제베", null, 0, null, 93, 97, 68, 0, 160, 300, null, null]
|
||||
],
|
||||
"general_ex":[
|
||||
|
||||
],
|
||||
"initialEvents": [
|
||||
[
|
||||
true,
|
||||
[
|
||||
"ChangeCity",
|
||||
"all",
|
||||
{
|
||||
"trade": 100
|
||||
}
|
||||
]
|
||||
]
|
||||
],
|
||||
"events": [
|
||||
[
|
||||
"month",
|
||||
1000,
|
||||
[
|
||||
"Date",
|
||||
"==",
|
||||
180,
|
||||
1
|
||||
],
|
||||
[
|
||||
"ChangeCity",
|
||||
"all",
|
||||
{
|
||||
"trade": 100
|
||||
}
|
||||
],
|
||||
[
|
||||
"DeleteEvent"
|
||||
]
|
||||
],
|
||||
[
|
||||
"month",
|
||||
1000,
|
||||
[
|
||||
"Date",
|
||||
"==",
|
||||
180,
|
||||
7
|
||||
],
|
||||
[
|
||||
"ChangeCity",
|
||||
"all",
|
||||
{
|
||||
"trade": 100
|
||||
}
|
||||
],
|
||||
[
|
||||
"DeleteEvent"
|
||||
]
|
||||
],
|
||||
[
|
||||
"month",
|
||||
1000,
|
||||
[
|
||||
"Date",
|
||||
"==",
|
||||
181,
|
||||
1
|
||||
],
|
||||
[
|
||||
"ChangeCity",
|
||||
"all",
|
||||
{
|
||||
"trade": 100
|
||||
}
|
||||
],
|
||||
[
|
||||
"DeleteEvent"
|
||||
]
|
||||
],
|
||||
[
|
||||
"month",
|
||||
1000,
|
||||
[
|
||||
"Date",
|
||||
"==",
|
||||
181,
|
||||
7
|
||||
],
|
||||
[
|
||||
"ChangeCity",
|
||||
"all",
|
||||
{
|
||||
"trade": 100
|
||||
}
|
||||
],
|
||||
[
|
||||
"DeleteEvent"
|
||||
]
|
||||
],
|
||||
[
|
||||
"month",
|
||||
1000,
|
||||
[
|
||||
"Date",
|
||||
"==",
|
||||
182,
|
||||
1
|
||||
],
|
||||
[
|
||||
"ChangeCity",
|
||||
"all",
|
||||
{
|
||||
"trade": 100
|
||||
}
|
||||
],
|
||||
[
|
||||
"DeleteEvent"
|
||||
]
|
||||
],
|
||||
[
|
||||
"month",
|
||||
1000,
|
||||
[
|
||||
"Date",
|
||||
"==",
|
||||
182,
|
||||
7
|
||||
],
|
||||
[
|
||||
"ChangeCity",
|
||||
"all",
|
||||
{
|
||||
"trade": 100
|
||||
}
|
||||
],
|
||||
[
|
||||
"DeleteEvent"
|
||||
]
|
||||
],
|
||||
[
|
||||
"destroy_nation",
|
||||
1000,
|
||||
[
|
||||
"and",
|
||||
[
|
||||
"Date",
|
||||
">=",
|
||||
183,
|
||||
1
|
||||
],
|
||||
[
|
||||
"RemainNation",
|
||||
"==",
|
||||
1
|
||||
]
|
||||
],
|
||||
[
|
||||
"BlockScoutAction"
|
||||
],
|
||||
[
|
||||
"DeleteEvent"
|
||||
]
|
||||
]
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,283 @@
|
||||
{
|
||||
"title": "【공백지】 무작위 세계",
|
||||
"startYear": 180,
|
||||
"map": {
|
||||
"mapName": "miniche_b"
|
||||
},
|
||||
"history": [
|
||||
"<C>●</>180년 1월:<L><b>【공백지】</b></>무작위성이 넘치는 이벤트 깃수"
|
||||
],
|
||||
"const": {
|
||||
"joinRuinedNPCProp": 0,
|
||||
"npcBanMessageProb": 1,
|
||||
"inheritItemUniqueMinPoint": 75000,
|
||||
"inheritItemRandomPoint": 75000,
|
||||
"uniqueTrialCoef": 10000,
|
||||
"maxUniqueTrialProb": 0.2,
|
||||
"maxUniqueItemLimit": [
|
||||
[-1, 4]
|
||||
],
|
||||
"minTurnDieOnPrestart": 1,
|
||||
"availableGeneralCommand": {
|
||||
"개인": [
|
||||
"휴식",
|
||||
"che_요양",
|
||||
"che_단련",
|
||||
"che_숙련전환",
|
||||
"che_견문",
|
||||
"che_은퇴",
|
||||
"che_장비매매",
|
||||
"che_군량매매",
|
||||
"che_내정특기초기화",
|
||||
"che_전투특기초기화"
|
||||
],
|
||||
"내정": [
|
||||
"che_농지개간",
|
||||
"che_상업투자",
|
||||
"che_기술연구",
|
||||
"che_수비강화",
|
||||
"che_성벽보수",
|
||||
"che_치안강화",
|
||||
"che_정착장려",
|
||||
"che_주민선정",
|
||||
"che_물자조달"
|
||||
],
|
||||
"군사": [
|
||||
"che_징병",
|
||||
"che_모병",
|
||||
"che_훈련",
|
||||
"che_사기진작",
|
||||
"che_출병",
|
||||
"che_집합",
|
||||
"che_소집해제",
|
||||
"che_첩보"
|
||||
],
|
||||
"인사": [
|
||||
"che_이동",
|
||||
"che_강행",
|
||||
"che_인재탐색",
|
||||
"che_귀환",
|
||||
"che_랜덤임관"
|
||||
],
|
||||
"계략": [
|
||||
"che_선동",
|
||||
"che_탈취",
|
||||
"che_파괴",
|
||||
"che_화계"
|
||||
],
|
||||
"국가": [
|
||||
"che_증여",
|
||||
"che_헌납",
|
||||
"che_하야",
|
||||
"che_거병",
|
||||
"che_무작위건국",
|
||||
"che_선양",
|
||||
"che_해산"
|
||||
]
|
||||
},
|
||||
"availableChiefCommand": {
|
||||
"휴식": [
|
||||
"휴식"
|
||||
],
|
||||
"인사": [
|
||||
"che_발령",
|
||||
"che_포상",
|
||||
"che_몰수"
|
||||
],
|
||||
"외교": [
|
||||
"che_물자원조",
|
||||
"che_불가침제의",
|
||||
"che_선전포고",
|
||||
"che_종전제의",
|
||||
"che_불가침파기제의"
|
||||
],
|
||||
"특수": [
|
||||
"che_초토화",
|
||||
"che_천도",
|
||||
"che_증축",
|
||||
"che_감축"
|
||||
],
|
||||
"전략": [
|
||||
"che_필사즉생",
|
||||
"che_백성동원",
|
||||
"che_수몰",
|
||||
"che_허보",
|
||||
"che_의병모집",
|
||||
"che_이호경식",
|
||||
"che_급습",
|
||||
"che_피장파장"
|
||||
],
|
||||
"기타": [
|
||||
"che_국기변경",
|
||||
"che_국호변경",
|
||||
"che_무작위수도이전"
|
||||
]
|
||||
},
|
||||
"allItems": {
|
||||
"horse": {
|
||||
"che_명마_01_노기": 0, "che_명마_02_조랑": 0, "che_명마_03_노새": 0,
|
||||
"che_명마_04_나귀": 0, "che_명마_05_갈색마": 0, "che_명마_06_흑색마": 0,
|
||||
|
||||
"che_명마_07_백마": 6,
|
||||
"che_명마_07_기주마": 6,
|
||||
"che_명마_07_오환마": 4,
|
||||
"che_명마_07_백상": 8,
|
||||
"che_명마_08_양주마": 4,
|
||||
"che_명마_08_흉노마": 4,
|
||||
"che_명마_09_과하마": 4,
|
||||
"che_명마_09_의남백마": 4,
|
||||
"che_명마_10_대완마": 4,
|
||||
"che_명마_10_옥추마": 4,
|
||||
"che_명마_11_서량마": 4,
|
||||
"che_명마_11_화종마": 4,
|
||||
"che_명마_12_사륜거": 8,
|
||||
"che_명마_12_옥란백용구": 8,
|
||||
"che_명마_13_절영": 4,
|
||||
"che_명마_13_적로": 4,
|
||||
"che_명마_14_적란마": 4,
|
||||
"che_명마_14_조황비전": 4,
|
||||
"che_명마_15_한혈마": 6,
|
||||
"che_명마_15_적토마": 6
|
||||
},
|
||||
"weapon": {
|
||||
"che_무기_01_단도": 0, "che_무기_02_단궁": 0, "che_무기_03_단극": 0,
|
||||
"che_무기_04_목검": 0, "che_무기_05_죽창": 0, "che_무기_06_소부": 0,
|
||||
|
||||
"che_무기_07_동추": 4,
|
||||
"che_무기_07_철편": 4,
|
||||
"che_무기_07_철쇄": 4,
|
||||
"che_무기_07_맥궁": 8,
|
||||
"che_무기_08_유성추": 4,
|
||||
"che_무기_08_철질여골": 4,
|
||||
"che_무기_09_쌍철극": 4,
|
||||
"che_무기_09_동호비궁": 8,
|
||||
"che_무기_10_삼첨도": 4,
|
||||
"che_무기_10_대부": 4,
|
||||
"che_무기_11_고정도": 4,
|
||||
"che_무기_11_이광궁": 8,
|
||||
"che_무기_12_철척사모": 4,
|
||||
"che_무기_12_칠성검": 4,
|
||||
"che_무기_13_사모": 4,
|
||||
"che_무기_13_양유기궁": 8,
|
||||
"che_무기_14_언월도": 4,
|
||||
"che_무기_14_방천화극": 4,
|
||||
"che_무기_15_청홍검": 6,
|
||||
"che_무기_15_의천검": 6
|
||||
},
|
||||
"book": {
|
||||
"che_서적_01_효경전": 0, "che_서적_02_회남자": 0, "che_서적_03_변도론": 0,
|
||||
"che_서적_04_건상역주": 0, "che_서적_05_여씨춘추": 0, "che_서적_06_사민월령": 0,
|
||||
|
||||
"che_서적_07_위료자": 8,
|
||||
"che_서적_07_사마법": 6,
|
||||
"che_서적_07_한서": 4,
|
||||
"che_서적_07_논어": 6,
|
||||
"che_서적_08_전론": 6,
|
||||
"che_서적_08_사기": 4,
|
||||
"che_서적_09_장자": 4,
|
||||
"che_서적_09_역경": 4,
|
||||
"che_서적_10_시경": 4,
|
||||
"che_서적_10_구국론": 4,
|
||||
"che_서적_11_상군서": 4,
|
||||
"che_서적_11_춘추전": 6,
|
||||
"che_서적_12_산해경": 8,
|
||||
"che_서적_12_맹덕신서": 4,
|
||||
"che_서적_13_관자": 4,
|
||||
"che_서적_13_병법24편": 4,
|
||||
"che_서적_14_한비자": 4,
|
||||
"che_서적_14_오자병법": 4,
|
||||
"che_서적_15_노자": 6,
|
||||
"che_서적_15_손자병법": 6
|
||||
},
|
||||
"item": {
|
||||
"che_치료_환약": 0, "che_저격_수극": 0, "che_사기_탁주": 0,
|
||||
"che_훈련_청주": 0, "che_계략_이추": 0, "che_계략_향낭": 0,
|
||||
|
||||
"che_의술_정력견혈산": 3,
|
||||
"che_의술_청낭서": 3,
|
||||
"che_의술_태평청령": 3,
|
||||
"che_의술_상한잡병론": 3,
|
||||
"che_보물_도기": 2,
|
||||
"che_조달_주판": 2,
|
||||
"che_내정_납금박산로": 2,
|
||||
"che_전략_평만지장도": 2,
|
||||
"che_숙련_동작": 2,
|
||||
"che_명성_구석": 2,
|
||||
"che_척사_오악진형도": 3,
|
||||
"che_격노_구정신단경": 2,
|
||||
"che_징병_낙주": 2,
|
||||
"che_저격_매화수전": 3,
|
||||
"che_저격_비도": 3,
|
||||
"che_위압_조목삭": 2,
|
||||
"che_공성_묵자": 3,
|
||||
"che_집중_전국책": 3,
|
||||
"che_환술_논어집해": 3,
|
||||
"che_진압_박혁론": 3,
|
||||
"che_부적_태현청생부": 2,
|
||||
"che_저지_삼황내문": 2,
|
||||
"che_행동_서촉지형도": 2,
|
||||
"che_간파_노군입산부": 2,
|
||||
"che_불굴_상편": 4,
|
||||
"che_약탈_옥벽": 2,
|
||||
"che_농성_주서음부": 2,
|
||||
"che_농성_위공자병법": 2,
|
||||
"che_계략_육도": 3,
|
||||
"che_계략_삼략": 3,
|
||||
"che_상성보정_과실주": 3,
|
||||
"che_능력치_지력_이강주": 2,
|
||||
"che_능력치_무력_두강주": 2,
|
||||
"che_능력치_통솔_보령압주": 2,
|
||||
"che_훈련_철벽서": 3,
|
||||
"che_훈련_단결도": 3,
|
||||
"che_사기_춘화첩": 3,
|
||||
"che_사기_초선화": 3,
|
||||
"che_회피_태평요술": 2,
|
||||
"che_필살_둔갑천서": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
"events":[
|
||||
[
|
||||
"month", 1000,
|
||||
["or", ["Date", "==", null, 12], ["Date", "==", null, 6]],
|
||||
["CreateManyNPC", 10, 10],
|
||||
["DeleteEvent"]
|
||||
],
|
||||
[
|
||||
"month", 1000,
|
||||
["Date", "==", 181, 1],
|
||||
["RaiseNPCNation"],
|
||||
["DeleteEvent"]
|
||||
],
|
||||
[
|
||||
"month", 999,
|
||||
["Date", "==", 181, 1],
|
||||
["OpenNationBetting", 4, 5000],
|
||||
["OpenNationBetting", 1, 2000],
|
||||
["DeleteEvent"]
|
||||
],
|
||||
[
|
||||
"month", 999,
|
||||
["and",
|
||||
["Date", ">=", 183, 1],
|
||||
["RemainNation", "<=", 8]
|
||||
],
|
||||
["OpenNationBetting", 1, 1000],
|
||||
["DeleteEvent"]
|
||||
],
|
||||
[
|
||||
"destroy_nation", 1000,
|
||||
["and",
|
||||
["Date", ">=", 183, 1],
|
||||
["RemainNation", "==", 1]
|
||||
],
|
||||
["BlockScoutAction"],
|
||||
["DeleteEvent"]
|
||||
],
|
||||
[
|
||||
"month", 999,
|
||||
["Date", "==", null, 1],
|
||||
["LostUniqueItem", 0.2]
|
||||
]
|
||||
]
|
||||
}
|
||||
@@ -48,19 +48,18 @@
|
||||
</div>
|
||||
</div>
|
||||
</DragSelect>
|
||||
<BButton
|
||||
ref="btnCopy"
|
||||
<div
|
||||
class="hoverPanel d-grid"
|
||||
:style="{
|
||||
position: 'absolute',
|
||||
display: isCopyButtonShown ? 'block' : 'none',
|
||||
display: isCopyButtonShown ? 'grid !important' : 'none !important',
|
||||
top: `${btnPos * 30 + 25}px`,
|
||||
right: '10px',
|
||||
}"
|
||||
@blur="isCopyButtonShown = false"
|
||||
@click="tryCopy()"
|
||||
>
|
||||
복사하기
|
||||
</BButton>
|
||||
<BButton ref="btnCopy" variant="primary" @blur="hideCopyButton()" @click="tryCopy()"> 복사하기 </BButton>
|
||||
<BButton ref="btnCopy" @blur="hideCopyButton()" @click="tryTextCopy()"> 텍스트 복사</BButton>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
@@ -117,6 +116,12 @@ function dragStart() {
|
||||
isDragToggle.value = true;
|
||||
}
|
||||
|
||||
function hideCopyButton() {
|
||||
setTimeout(() => {
|
||||
isCopyButtonShown.value = false;
|
||||
}, 1);
|
||||
}
|
||||
|
||||
function eqSet<T>(as: Set<T>, bs: Set<T>) {
|
||||
if (as.size !== bs.size) return false;
|
||||
for (var a of as) if (!bs.has(a)) return false;
|
||||
@@ -160,6 +165,30 @@ function tryCopy() {
|
||||
storedActionsHelper.clipboard.value = [...actions];
|
||||
}
|
||||
|
||||
const removeTagRegEx = /<[^>]*>?/g;
|
||||
|
||||
function tryTextCopy() {
|
||||
const rawActions = queryActionHelper.extractQueryActions();
|
||||
isCopyButtonShown.value = false;
|
||||
|
||||
const actions = queryActionHelper.amplifyQueryActions(rawActions, queryActionHelper.getSelectedTurnList());
|
||||
if (actions.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const turnBriefs: [number, string][] = [];
|
||||
for (const action of actions) {
|
||||
const [turnIdxList, turnObj] = action;
|
||||
for (const turnIdx of turnIdxList) {
|
||||
turnBriefs.push([turnIdx, `${turnIdx + 1}턴 ${turnObj.brief.replace(removeTagRegEx, "")}`]);
|
||||
}
|
||||
}
|
||||
turnBriefs.sort((a, b) => a[0] - b[0]);
|
||||
|
||||
const text = turnBriefs.map(([, brief]) => brief).join("\n");
|
||||
void navigator.clipboard.writeText(text);
|
||||
}
|
||||
|
||||
const turnTimes = ref<string[]>([]);
|
||||
|
||||
if (!props.officer || !props.officer.turnTime) {
|
||||
|
||||
+12
-4
@@ -62,7 +62,8 @@
|
||||
<div class="row">
|
||||
<div class="col col-md-4 col-3 a-right align-self-center">장수명</div>
|
||||
<div class="col col-md-3 col-9 align-self-center">
|
||||
<input v-model="args.name" class="form-control" />
|
||||
<input v-if="!blockCustomGeneralName" v-model="args.name" class="form-control" />
|
||||
<span v-else>무작위</span>
|
||||
</div>
|
||||
<div class="col col-md-1 col-3 a-right align-self-center">전콘 사용</div>
|
||||
<div class="col col-md-4 col-9 align-self-center">
|
||||
@@ -194,7 +195,7 @@
|
||||
v-model="inheritTurnTimeMinute"
|
||||
:readonly="!inheritTurnTimeSet"
|
||||
:min="0"
|
||||
:max="1 - turnterm"
|
||||
:max="turnterm - 1"
|
||||
:right="true"
|
||||
title="분"
|
||||
/>
|
||||
@@ -267,6 +268,11 @@ declare const staticValues: {
|
||||
imgsvr: 0 | 1;
|
||||
};
|
||||
|
||||
config: {
|
||||
show_img_level: number;
|
||||
blockCustomGeneralName: boolean;
|
||||
}
|
||||
|
||||
serverID: string;
|
||||
inheritTotalPoint: number;
|
||||
};
|
||||
@@ -294,6 +300,8 @@ const { serverID, member, turnterm } = staticValues;
|
||||
const nationList = ref(shuffle(staticValues.nationList));
|
||||
const args = ref<JoinArgs>();
|
||||
|
||||
const blockCustomGeneralName = staticValues.config.blockCustomGeneralName;
|
||||
|
||||
const stats = ref({
|
||||
min: 50,
|
||||
max: 50,
|
||||
@@ -355,8 +363,8 @@ watch(gameConstStore, (gameConst) => {
|
||||
min: gameConst.gameConst.defaultStatMin,
|
||||
max: gameConst.gameConst.defaultStatMax,
|
||||
total: gameConst.gameConst.defaultStatTotal,
|
||||
bonusMin: gameConst.gameConst.defaultStatMin,
|
||||
bonusMax: gameConst.gameConst.defaultStatMax,
|
||||
bonusMin: gameConst.gameConst.bornMinStatBonus,
|
||||
bonusMax: gameConst.gameConst.bornMaxStatBonus,
|
||||
};
|
||||
|
||||
args.value = {
|
||||
|
||||
@@ -81,6 +81,8 @@
|
||||
<BDropdownItem @click="clipboardCopy"> <i class="bi bi-files" /> 복사하기 </BDropdownItem>
|
||||
<BDropdownItem @click="clipboardPaste"> <i class="bi bi-clipboard-fill" /> 붙여넣기 </BDropdownItem>
|
||||
<BDropdownDivider />
|
||||
<BDropdownItem @click="clipboardTextCopy"> <i class="bi bi-files" /> 텍스트 복사 </BDropdownItem>
|
||||
<BDropdownDivider />
|
||||
<BDropdownItem @click="setStoredActions">
|
||||
<i class="bi bi-bookmark-plus-fill" /> 보관하기
|
||||
</BDropdownItem>
|
||||
@@ -640,6 +642,36 @@ async function clipboardPaste(releaseSelect = true) {
|
||||
return result;
|
||||
}
|
||||
|
||||
const removeTagRegEx = /<[^>]*>?/g;
|
||||
|
||||
function clipboardTextCopy(releaseSelect = true) {
|
||||
const rawActions = queryActionHelper.extractQueryActions();
|
||||
if (rawActions.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const actions = queryActionHelper.amplifyQueryActions(rawActions, queryActionHelper.getSelectedTurnList());
|
||||
if (actions.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const turnBriefs: [number, string][] = [];
|
||||
for (const action of actions) {
|
||||
const [turnIdxList, turnObj] = action;
|
||||
for (const turnIdx of turnIdxList) {
|
||||
turnBriefs.push([turnIdx, `${turnIdx + 1}턴 ${turnObj.brief.replace(removeTagRegEx, "")}`]);
|
||||
}
|
||||
}
|
||||
turnBriefs.sort((a, b) => a[0] - b[0]);
|
||||
|
||||
const text = turnBriefs.map(([, brief]) => brief).join("\n");
|
||||
void navigator.clipboard.writeText(text);
|
||||
|
||||
if (releaseSelect) {
|
||||
queryActionHelper.releaseSelectedTurnList();
|
||||
}
|
||||
}
|
||||
|
||||
async function subRepeatCommand(releaseSelect = true): Promise<boolean> {
|
||||
const reqTurnList = queryActionHelper.getSelectedTurnList();
|
||||
const selectedMinTurnIdx = reqTurnList[0];
|
||||
|
||||
@@ -32,6 +32,7 @@ GetRecentRecordResponse,
|
||||
import type { CachedMapResult, GeneralListResponse, ItemTypeKey, MapResult } from "./defs";
|
||||
import type { VoteDetailResult, VoteListResult } from "./defs/API/Vote";
|
||||
import type { ActiveResourceAuctionList, OpenAuctionResponse, UniqueItemAuctionDetail, UniqueItemAuctionList } from "./defs/API/Auction";
|
||||
import type { MabilboxListResponse, MsgResponse, MsgType } from "./defs/API/Message";
|
||||
|
||||
const apiRealPath = {
|
||||
Auction: {
|
||||
@@ -170,6 +171,27 @@ const apiRealPath = {
|
||||
lastID: number
|
||||
}, InheritLogResponse>
|
||||
},
|
||||
Message: {
|
||||
DeleteMessage: PATCH as APICallT<{
|
||||
msgID: number,
|
||||
}>,
|
||||
DecideMessageResponse: POST as APICallT<{
|
||||
msgID: number,
|
||||
response: boolean,
|
||||
}>,
|
||||
GetContactList: GET as APICallT<undefined, MabilboxListResponse>,
|
||||
GetRecentMessage: GET as APICallT<{
|
||||
sequence?: number;
|
||||
}, MsgResponse>,
|
||||
GetOldMessage: GET as APICallT<{
|
||||
to: number;
|
||||
type: MsgType;
|
||||
}, MsgResponse>,
|
||||
SendMessage: POST as APICallT<{
|
||||
mailbox: number;
|
||||
text: string;
|
||||
}, ValidResponse & {msgID: number}>
|
||||
},
|
||||
Misc: {
|
||||
UploadImage: POST as APICallT<
|
||||
{
|
||||
|
||||
+1000
-960
@@ -1,1068 +1,1108 @@
|
||||
import $ from 'jquery';
|
||||
import 'bootstrap';
|
||||
import download from 'downloadjs';
|
||||
import $ from "jquery";
|
||||
import "bootstrap";
|
||||
import download from "downloadjs";
|
||||
import { unwrap } from "@util/unwrap";
|
||||
import { isInteger } from 'lodash-es';
|
||||
import { errUnknown } from '@/common_legacy';
|
||||
import { getNPCColor } from './utilGame';
|
||||
import { isInteger } from "lodash-es";
|
||||
import { errUnknown } from "@/common_legacy";
|
||||
import { getNPCColor } from "./utilGame";
|
||||
import { combineArray } from "@util/combineArray";
|
||||
import { isBrightColor } from "@util/isBrightColor";
|
||||
import { numberWithCommas } from "@util/numberWithCommas";
|
||||
import { unwrap_any } from '@util/unwrap_any';
|
||||
import type { BasicGeneralListResponse, InvalidResponse } from '@/defs';
|
||||
import { formatTime } from '@util/formatTime';
|
||||
import { Modal } from 'bootstrap';
|
||||
import { unwrap_any } from "@util/unwrap_any";
|
||||
import type { BasicGeneralListResponse, InvalidResponse } from "@/defs";
|
||||
import { formatTime } from "@util/formatTime";
|
||||
import { Modal } from "bootstrap";
|
||||
|
||||
type CityAttackerInfo = {
|
||||
level: number,
|
||||
}
|
||||
level: number;
|
||||
};
|
||||
|
||||
type CityBasicInfo = {
|
||||
nation?: number,
|
||||
level: number,
|
||||
def: number,
|
||||
wall: number,
|
||||
city?: number,
|
||||
}
|
||||
nation?: number;
|
||||
level: number;
|
||||
def: number;
|
||||
wall: number;
|
||||
city?: number;
|
||||
};
|
||||
|
||||
type NationBasicInfo = {
|
||||
level: number,
|
||||
type: string,
|
||||
tech: number,
|
||||
capital: number,
|
||||
}
|
||||
level: number;
|
||||
type: string;
|
||||
tech: number;
|
||||
capital: number;
|
||||
};
|
||||
|
||||
type InheritBuff = {
|
||||
warAvoidRatio: number;
|
||||
warCriticalRatio: number;
|
||||
warMagicTrialProb: number;
|
||||
warAvoidRatioOppose: number;
|
||||
warCriticalRatioOppose: number;
|
||||
warMagicTrialProbOppose: number;
|
||||
};
|
||||
|
||||
type GeneralInfo = {
|
||||
no: number,
|
||||
npc?: number
|
||||
name: string,
|
||||
officer_level: number,
|
||||
explevel: number,
|
||||
no: number;
|
||||
npc?: number;
|
||||
name: string;
|
||||
officer_level: number;
|
||||
explevel: number;
|
||||
|
||||
leadership: number,
|
||||
horse: string,
|
||||
strength: number,
|
||||
weapon: string,
|
||||
intel: number,
|
||||
book: string,
|
||||
item: string,
|
||||
leadership: number;
|
||||
horse: string;
|
||||
strength: number;
|
||||
weapon: string;
|
||||
intel: number;
|
||||
book: string;
|
||||
item: string;
|
||||
|
||||
injury: number,
|
||||
injury: number;
|
||||
|
||||
rice: number,
|
||||
rice: number;
|
||||
|
||||
personal: string,
|
||||
special2: string,
|
||||
personal: string;
|
||||
special2: string;
|
||||
|
||||
crew: number,
|
||||
crewtype: number,
|
||||
atmos: number,
|
||||
train: number,
|
||||
crew: number;
|
||||
crewtype: number;
|
||||
atmos: number;
|
||||
train: number;
|
||||
|
||||
dex1: number,
|
||||
dex2: number,
|
||||
dex3: number,
|
||||
dex4: number,
|
||||
dex5: number,
|
||||
dex1: number;
|
||||
dex2: number;
|
||||
dex3: number;
|
||||
dex4: number;
|
||||
dex5: number;
|
||||
|
||||
defence_train: number,
|
||||
defence_train: number;
|
||||
|
||||
warnum: number,
|
||||
killnum: number,
|
||||
killcrew: number,
|
||||
warnum: number;
|
||||
killnum: number;
|
||||
killcrew: number;
|
||||
|
||||
officer_city?: number,
|
||||
officer_city?: number;
|
||||
|
||||
inheritBuff?: InheritBuff;
|
||||
};
|
||||
|
||||
type BattleInfo = {
|
||||
attackerGeneral: GeneralInfo,
|
||||
attackerCity: CityAttackerInfo | CityBasicInfo,
|
||||
attackerNation: NationBasicInfo,
|
||||
defenderGenerals: GeneralInfo[],
|
||||
defenderCity: CityBasicInfo,
|
||||
defenderNation: NationBasicInfo,
|
||||
year: number,
|
||||
month: number,
|
||||
repeatCnt: number,
|
||||
attackerGeneral: GeneralInfo;
|
||||
attackerCity: CityAttackerInfo | CityBasicInfo;
|
||||
attackerNation: NationBasicInfo;
|
||||
defenderGenerals: GeneralInfo[];
|
||||
defenderCity: CityBasicInfo;
|
||||
defenderNation: NationBasicInfo;
|
||||
year: number;
|
||||
month: number;
|
||||
repeatCnt: number;
|
||||
seed?: string;
|
||||
};
|
||||
|
||||
type ExportedGeneralInfo = {
|
||||
objType: 'general',
|
||||
data: GeneralInfo,
|
||||
}
|
||||
objType: "general";
|
||||
data: GeneralInfo;
|
||||
};
|
||||
|
||||
type ExportedBattleInfo = {
|
||||
objType: 'battle',
|
||||
data: BattleInfo
|
||||
}
|
||||
objType: "battle";
|
||||
data: BattleInfo;
|
||||
};
|
||||
type ExportedInfo = ExportedGeneralInfo | ExportedBattleInfo;
|
||||
|
||||
type BattleResult = {
|
||||
result: true,
|
||||
datetime: string,
|
||||
lastWarLog: {
|
||||
generalBattleResultLog: string,
|
||||
generalBattleDetailLog: string,
|
||||
},
|
||||
avgWar: number,
|
||||
phase: number,
|
||||
killed: number,
|
||||
maxKilled: number,
|
||||
minKilled: number,
|
||||
dead: number,
|
||||
maxDead: number,
|
||||
minDead: number,
|
||||
attackerRice: number,
|
||||
defenderRice: number,
|
||||
attackerSkills: Record<string, number>,
|
||||
defendersSkills: Record<string, number>[],
|
||||
}
|
||||
result: true;
|
||||
datetime: string;
|
||||
lastWarLog: {
|
||||
generalBattleResultLog: string;
|
||||
generalBattleDetailLog: string;
|
||||
};
|
||||
avgWar: number;
|
||||
phase: number;
|
||||
killed: number;
|
||||
maxKilled: number;
|
||||
minKilled: number;
|
||||
dead: number;
|
||||
maxDead: number;
|
||||
minDead: number;
|
||||
attackerRice: number;
|
||||
defenderRice: number;
|
||||
attackerSkills: Record<string, number>;
|
||||
defendersSkills: Record<string, number>[];
|
||||
};
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
nation?: NationBasicInfo,
|
||||
city?: CityBasicInfo,
|
||||
defaultSpecialDomestic: string,
|
||||
}
|
||||
interface Window {
|
||||
nation?: NationBasicInfo;
|
||||
city?: CityBasicInfo;
|
||||
defaultSpecialDomestic: string;
|
||||
}
|
||||
}
|
||||
|
||||
let modalImport: Modal|undefined = undefined;
|
||||
let modalImport: Modal | undefined = undefined;
|
||||
|
||||
$(function ($) {
|
||||
const $generalForm = $(".form_sample .general_detail");
|
||||
const $defenderHeaderForm = $(".form_sample .card-header");
|
||||
const $defenderColumn = $(".defender-column");
|
||||
|
||||
const defenderNoList: Record<number, JQuery<HTMLElement>> = {};
|
||||
|
||||
const $generalForm = $('.form_sample .general_detail');
|
||||
const $defenderHeaderForm = $('.form_sample .card-header');
|
||||
const $defenderColumn = $('.defender-column');
|
||||
const $attackerCard = $(".attacker_form");
|
||||
|
||||
const defenderNoList: Record<number, JQuery<HTMLElement>> = {};
|
||||
|
||||
const $attackerCard = $('.attacker_form');
|
||||
|
||||
const initBasicEvent = function () {
|
||||
|
||||
if (window.nation && window.city) {
|
||||
$('.form_city_level').val(window.city.level);
|
||||
$('.form_def').val(window.city.def);
|
||||
$('.form_wall').val(window.city.wall);
|
||||
$('.form_nation_type').val(window.nation.type);
|
||||
$('.form_nation_level').val(window.nation.level);
|
||||
$('.form_tech').val(window.nation.tech / 1000);
|
||||
if (window.nation.capital == window.city.city) {
|
||||
$('.attacker_nation .form_is_capital:first').trigger('click');
|
||||
$('.defender_nation .form_is_capital:first').trigger('click');
|
||||
} else {
|
||||
$('.attacker_nation .form_is_capital:last').trigger('click');
|
||||
$('.defender_nation .form_is_capital:last').trigger('click');
|
||||
}
|
||||
} else {
|
||||
$('.attacker_nation .form_is_capital:last').trigger('click');
|
||||
$('.defender_nation .form_is_capital:last').trigger('click');
|
||||
}
|
||||
|
||||
$('.form_injury').on('change', function () {
|
||||
const $this = $(this) as JQuery<HTMLInputElement>;
|
||||
const $general = getGeneralDetail($this);
|
||||
const $helptext = $general.find('.injury_helptext');
|
||||
|
||||
const injury = parseInt($this.val() as string);
|
||||
//FIXME: PHP 코드와 항상 일치하도록 변경
|
||||
let text = '건강';
|
||||
let color = 'white';
|
||||
if (injury > 60) {
|
||||
text = '위독';
|
||||
color = 'red';
|
||||
} else if (injury > 40) {
|
||||
text = '심각';
|
||||
color = 'magenta';
|
||||
} else if (injury > 20) {
|
||||
text = '중상';
|
||||
color = 'orange';
|
||||
} else if (injury > 0) {
|
||||
text = '경상';
|
||||
color = 'yellow';
|
||||
}
|
||||
$helptext.html(text).css('color', color);
|
||||
});
|
||||
|
||||
$('.export_general').on('click', function () {
|
||||
const $btn = $(this);
|
||||
const $general = getGeneralDetail($btn);
|
||||
|
||||
const values = exportGeneralInfo($general);
|
||||
console.log(values);
|
||||
});
|
||||
$('.delete-defender').on('click', function () {
|
||||
const $card = getGeneralFrame($(this));
|
||||
deleteDefender($card);
|
||||
});
|
||||
$('.copy-defender').on('click', function () {
|
||||
const $card = getGeneralFrame($(this));
|
||||
copyDefender($card);
|
||||
});
|
||||
|
||||
$('.add-defender').on('click', function () {
|
||||
addDefender();
|
||||
});
|
||||
|
||||
$('.btn-general-load').on('click', function () {
|
||||
const $file = $(this).prev();
|
||||
$file[0].click();
|
||||
})
|
||||
|
||||
$<HTMLInputElement>('.form_load_general_file').on('change', function (e) {
|
||||
e.preventDefault();
|
||||
const $this = $(this);
|
||||
const $card = getGeneralFrame($this);
|
||||
|
||||
const files = unwrap(e.target.files);
|
||||
|
||||
importGeneralInfoByFile(files, $card);
|
||||
return false;
|
||||
});
|
||||
|
||||
$('.btn-general-import-server').on('click', function () {
|
||||
const $this = $(this);
|
||||
const $card = getGeneralFrame($this);
|
||||
|
||||
const $modal = $('#importModal');
|
||||
$modal.data('target', $card);
|
||||
if(!modalImport){
|
||||
modalImport = new Modal($modal[0]);
|
||||
}
|
||||
modalImport.show();
|
||||
});
|
||||
|
||||
$('.btn-general-save').on('click', function () {
|
||||
const $this = $(this);
|
||||
const $general = getGeneralDetail($this);
|
||||
const generalData = exportGeneralInfo($general);
|
||||
|
||||
const filename = `general_${generalData.name}.json`;
|
||||
const saveData = JSON.stringify({
|
||||
objType: 'general',
|
||||
data: generalData
|
||||
}, null, 4);
|
||||
|
||||
download(saveData, filename, 'application/json');
|
||||
});
|
||||
|
||||
$('.btn-battle-load').on('click', function () {
|
||||
const $file = $(this).prev();
|
||||
$file[0].click();
|
||||
})
|
||||
|
||||
$<HTMLInputElement>('.form_load_battle_file').on('change', function (e) {
|
||||
e.preventDefault();
|
||||
const files = unwrap(e.target.files);
|
||||
|
||||
importBattleInfoByFile(files);
|
||||
return false;
|
||||
});
|
||||
|
||||
$('.btn-battle-save').on('click', function () {
|
||||
const battleData = exportAllData();
|
||||
const dateText = formatTime(new Date(), 'yyyyMMdd_HHmmss');
|
||||
const filename = `battle_${dateText}.json`;
|
||||
const saveData = JSON.stringify({
|
||||
objType: 'battle',
|
||||
data: battleData
|
||||
}, null, 4);
|
||||
|
||||
download(saveData, filename, 'application/json');
|
||||
})
|
||||
|
||||
const $generals = $('.general_detail');
|
||||
$generals.on('dragover dragleave', function (e) {
|
||||
e.stopPropagation()
|
||||
e.preventDefault()
|
||||
})
|
||||
$generals.on('drop', function (e) {
|
||||
e.preventDefault();
|
||||
const $this = $(this);
|
||||
const $card = getGeneralFrame($this);
|
||||
|
||||
const files = unwrap((unwrap(e.originalEvent) as DragEvent).dataTransfer).files;
|
||||
|
||||
importGeneralInfoByFile(files, $card);
|
||||
return false;
|
||||
});
|
||||
|
||||
const $battlePad = $('.dragpad_battle');
|
||||
$battlePad.on('dragover dragleave', function (e) {
|
||||
e.stopPropagation()
|
||||
e.preventDefault()
|
||||
})
|
||||
$battlePad.on('drop', function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
const files = unwrap((unwrap(e.originalEvent) as DragEvent).dataTransfer).files;
|
||||
|
||||
importBattleInfoByFile(files);
|
||||
return false;
|
||||
});
|
||||
const initBasicEvent = function () {
|
||||
if (window.nation && window.city) {
|
||||
$(".form_city_level").val(window.city.level);
|
||||
$(".form_def").val(window.city.def);
|
||||
$(".form_wall").val(window.city.wall);
|
||||
$(".form_nation_type").val(window.nation.type);
|
||||
$(".form_nation_level").val(window.nation.level);
|
||||
$(".form_tech").val(window.nation.tech / 1000);
|
||||
if (window.nation.capital == window.city.city) {
|
||||
$(".attacker_nation .form_is_capital:first").trigger("click");
|
||||
$(".defender_nation .form_is_capital:first").trigger("click");
|
||||
} else {
|
||||
$(".attacker_nation .form_is_capital:last").trigger("click");
|
||||
$(".defender_nation .form_is_capital:last").trigger("click");
|
||||
}
|
||||
} else {
|
||||
$(".attacker_nation .form_is_capital:last").trigger("click");
|
||||
$(".defender_nation .form_is_capital:last").trigger("click");
|
||||
}
|
||||
|
||||
const importGeneralInfo = function ($general: JQuery<HTMLElement>, data: GeneralInfo) {
|
||||
const setVal = function (query: string, val: string | number) {
|
||||
$general.find(query).val(val).trigger('change');
|
||||
}
|
||||
$(".form_injury").on("change", function () {
|
||||
const $this = $(this) as JQuery<HTMLInputElement>;
|
||||
const $general = getGeneralDetail($this);
|
||||
const $helptext = $general.find(".injury_helptext");
|
||||
|
||||
setVal('.form_general_name', data.name);
|
||||
const injury = parseInt($this.val() as string);
|
||||
//FIXME: PHP 코드와 항상 일치하도록 변경
|
||||
let text = "건강";
|
||||
let color = "white";
|
||||
if (injury > 60) {
|
||||
text = "위독";
|
||||
color = "red";
|
||||
} else if (injury > 40) {
|
||||
text = "심각";
|
||||
color = "magenta";
|
||||
} else if (injury > 20) {
|
||||
text = "중상";
|
||||
color = "orange";
|
||||
} else if (injury > 0) {
|
||||
text = "경상";
|
||||
color = "yellow";
|
||||
}
|
||||
$helptext.html(text).css("color", color);
|
||||
});
|
||||
|
||||
setVal('.form_officer_level', data.officer_level);
|
||||
setVal('.form_exp_level', data.explevel);
|
||||
$(".export_general").on("click", function () {
|
||||
const $btn = $(this);
|
||||
const $general = getGeneralDetail($btn);
|
||||
|
||||
setVal('.form_leadership', data.leadership);
|
||||
setVal('.form_general_horse', data.horse);
|
||||
setVal('.form_strength', data.strength);
|
||||
setVal('.form_general_weap', data.weapon);
|
||||
setVal('.form_intel', data.intel);
|
||||
setVal('.form_general_book', data.book);
|
||||
setVal('.form_general_item', data.item);
|
||||
const values = exportGeneralInfo($general);
|
||||
console.log(values);
|
||||
});
|
||||
$(".delete-defender").on("click", function () {
|
||||
const $card = getGeneralFrame($(this));
|
||||
deleteDefender($card);
|
||||
});
|
||||
$(".copy-defender").on("click", function () {
|
||||
const $card = getGeneralFrame($(this));
|
||||
copyDefender($card);
|
||||
});
|
||||
|
||||
setVal('.form_injury', data.injury);
|
||||
$(".add-defender").on("click", function () {
|
||||
addDefender();
|
||||
});
|
||||
|
||||
setVal('.form_rice', data.rice);
|
||||
$(".btn-general-load").on("click", function () {
|
||||
const $file = $(this).prev();
|
||||
$file[0].click();
|
||||
});
|
||||
|
||||
setVal('.form_general_character', data.personal);
|
||||
setVal('.form_general_special_war', data.special2);
|
||||
$<HTMLInputElement>(".form_load_general_file").on("change", function (e) {
|
||||
e.preventDefault();
|
||||
const $this = $(this);
|
||||
const $card = getGeneralFrame($this);
|
||||
|
||||
setVal('.form_crew', data.crew);
|
||||
setVal('.form_crewtype', data.crewtype);
|
||||
setVal('.form_atmos', data.atmos);
|
||||
setVal('.form_train', data.train);
|
||||
const files = unwrap(e.target.files);
|
||||
|
||||
setVal('.form_dex1', data.dex1);
|
||||
setVal('.form_dex2', data.dex2);
|
||||
setVal('.form_dex3', data.dex3);
|
||||
setVal('.form_dex4', data.dex4);
|
||||
setVal('.form_dex5', data.dex5);
|
||||
setVal('.form_defence_train', data.defence_train);
|
||||
importGeneralInfoByFile(files, $card);
|
||||
return false;
|
||||
});
|
||||
|
||||
setVal('.form_warnum', data.warnum);
|
||||
setVal('.form_killnum', data.killnum);
|
||||
setVal('.form_killcrew', data.killcrew);
|
||||
$(".btn-general-import-server").on("click", function () {
|
||||
const $this = $(this);
|
||||
const $card = getGeneralFrame($this);
|
||||
|
||||
if (!setGeneralNo($general, data.no)) {
|
||||
setGeneralNo($general, generateNewGeneralNo());
|
||||
}
|
||||
const $modal = $("#importModal");
|
||||
$modal.data("target", $card);
|
||||
if (!modalImport) {
|
||||
modalImport = new Modal($modal[0]);
|
||||
}
|
||||
modalImport.show();
|
||||
});
|
||||
|
||||
$(".btn-general-save").on("click", function () {
|
||||
const $this = $(this);
|
||||
const $general = getGeneralDetail($this);
|
||||
const generalData = exportGeneralInfo($general);
|
||||
|
||||
const filename = `general_${generalData.name}.json`;
|
||||
const saveData = JSON.stringify(
|
||||
{
|
||||
objType: "general",
|
||||
data: generalData,
|
||||
},
|
||||
null,
|
||||
4
|
||||
);
|
||||
|
||||
download(saveData, filename, "application/json");
|
||||
});
|
||||
|
||||
$(".btn-battle-load").on("click", function () {
|
||||
const $file = $(this).prev();
|
||||
$file[0].click();
|
||||
});
|
||||
|
||||
$<HTMLInputElement>(".form_load_battle_file").on("change", function (e) {
|
||||
e.preventDefault();
|
||||
const files = unwrap(e.target.files);
|
||||
|
||||
importBattleInfoByFile(files);
|
||||
return false;
|
||||
});
|
||||
|
||||
$(".btn-battle-save").on("click", function () {
|
||||
const battleData = exportAllData();
|
||||
const dateText = formatTime(new Date(), "yyyyMMdd_HHmmss");
|
||||
const filename = `battle_${dateText}.json`;
|
||||
const saveData = JSON.stringify(
|
||||
{
|
||||
objType: "battle",
|
||||
data: battleData,
|
||||
},
|
||||
null,
|
||||
4
|
||||
);
|
||||
|
||||
download(saveData, filename, "application/json");
|
||||
});
|
||||
|
||||
const $generals = $(".general_detail");
|
||||
$generals.on("dragover dragleave", function (e) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
});
|
||||
$generals.on("drop", function (e) {
|
||||
e.preventDefault();
|
||||
const $this = $(this);
|
||||
const $card = getGeneralFrame($this);
|
||||
|
||||
const files = unwrap((unwrap(e.originalEvent) as DragEvent).dataTransfer).files;
|
||||
|
||||
importGeneralInfoByFile(files, $card);
|
||||
return false;
|
||||
});
|
||||
|
||||
const $battlePad = $(".dragpad_battle");
|
||||
$battlePad.on("dragover dragleave", function (e) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
});
|
||||
$battlePad.on("drop", function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
const files = unwrap((unwrap(e.originalEvent) as DragEvent).dataTransfer).files;
|
||||
|
||||
importBattleInfoByFile(files);
|
||||
return false;
|
||||
});
|
||||
};
|
||||
|
||||
const importGeneralInfo = function ($general: JQuery<HTMLElement>, data: GeneralInfo) {
|
||||
const setVal = function (query: string, val: string | number) {
|
||||
$general.find(query).val(val).trigger("change");
|
||||
};
|
||||
|
||||
setVal(".form_general_name", data.name);
|
||||
|
||||
setVal(".form_officer_level", data.officer_level);
|
||||
setVal(".form_exp_level", data.explevel);
|
||||
|
||||
setVal(".form_leadership", data.leadership);
|
||||
setVal(".form_general_horse", data.horse);
|
||||
setVal(".form_strength", data.strength);
|
||||
setVal(".form_general_weap", data.weapon);
|
||||
setVal(".form_intel", data.intel);
|
||||
setVal(".form_general_book", data.book);
|
||||
setVal(".form_general_item", data.item);
|
||||
|
||||
setVal(".form_injury", data.injury);
|
||||
|
||||
setVal(".form_rice", data.rice);
|
||||
|
||||
setVal(".form_general_character", data.personal);
|
||||
setVal(".form_general_special_war", data.special2);
|
||||
|
||||
setVal(".form_crew", data.crew);
|
||||
setVal(".form_crewtype", data.crewtype);
|
||||
setVal(".form_atmos", data.atmos);
|
||||
setVal(".form_train", data.train);
|
||||
|
||||
setVal(".form_dex1", data.dex1);
|
||||
setVal(".form_dex2", data.dex2);
|
||||
setVal(".form_dex3", data.dex3);
|
||||
setVal(".form_dex4", data.dex4);
|
||||
setVal(".form_dex5", data.dex5);
|
||||
setVal(".form_defence_train", data.defence_train);
|
||||
|
||||
setVal(".form_warnum", data.warnum);
|
||||
setVal(".form_killnum", data.killnum);
|
||||
setVal(".form_killcrew", data.killcrew);
|
||||
|
||||
if (data.inheritBuff) {
|
||||
setVal(".form_war_avoid_ratio", data.inheritBuff.warAvoidRatio);
|
||||
setVal(".form_war_critical_ratio", data.inheritBuff.warCriticalRatio);
|
||||
setVal(".form_war_magic_trial_prob", data.inheritBuff.warMagicTrialProb);
|
||||
setVal(".form_oppose_war_avoid_ratio", data.inheritBuff.warAvoidRatioOppose);
|
||||
setVal(".form_oppose_war_critical_ratio", data.inheritBuff.warCriticalRatioOppose);
|
||||
setVal(".form_oppose_war_magic_trial_prob", data.inheritBuff.warMagicTrialProbOppose);
|
||||
}
|
||||
|
||||
const exportGeneralInfo = function ($general: JQuery<HTMLElement>): GeneralInfo {
|
||||
const getInt = function (query: string): number {
|
||||
return parseInt(unwrap_any<string>($general.find(query).val()));
|
||||
}
|
||||
if (!setGeneralNo($general, data.no)) {
|
||||
setGeneralNo($general, generateNewGeneralNo());
|
||||
}
|
||||
};
|
||||
|
||||
const getVal = function (query: string): string {
|
||||
return unwrap_any<string>($general.find(query).val());
|
||||
}
|
||||
const exportGeneralInfo = function ($general: JQuery<HTMLElement>): GeneralInfo {
|
||||
const getInt = function (query: string): number {
|
||||
return parseInt(unwrap_any<string>($general.find(query).val()));
|
||||
};
|
||||
|
||||
return {
|
||||
no: getGeneralNo($general),
|
||||
name: getVal('.form_general_name'),
|
||||
officer_level: getInt('.form_officer_level'),
|
||||
explevel: getInt('.form_exp_level'),
|
||||
const getVal = function (query: string): string {
|
||||
return unwrap_any<string>($general.find(query).val());
|
||||
};
|
||||
|
||||
leadership: getInt('.form_leadership'),
|
||||
horse: getVal('.form_general_horse'),
|
||||
strength: getInt('.form_strength'),
|
||||
weapon: getVal('.form_general_weap'),
|
||||
intel: getInt('.form_intel'),
|
||||
book: getVal('.form_general_book'),
|
||||
item: getVal('.form_general_item'),
|
||||
return {
|
||||
no: getGeneralNo($general),
|
||||
name: getVal(".form_general_name"),
|
||||
officer_level: getInt(".form_officer_level"),
|
||||
explevel: getInt(".form_exp_level"),
|
||||
|
||||
injury: getInt('.form_injury'),
|
||||
leadership: getInt(".form_leadership"),
|
||||
horse: getVal(".form_general_horse"),
|
||||
strength: getInt(".form_strength"),
|
||||
weapon: getVal(".form_general_weap"),
|
||||
intel: getInt(".form_intel"),
|
||||
book: getVal(".form_general_book"),
|
||||
item: getVal(".form_general_item"),
|
||||
|
||||
rice: getInt('.form_rice'),
|
||||
injury: getInt(".form_injury"),
|
||||
|
||||
personal: getVal('.form_general_character'),
|
||||
special2: getVal('.form_general_special_war'),
|
||||
rice: getInt(".form_rice"),
|
||||
|
||||
crew: getInt('.form_crew'),
|
||||
crewtype: getInt('.form_crewtype'),
|
||||
atmos: getInt('.form_atmos'),
|
||||
train: getInt('.form_train'),
|
||||
personal: getVal(".form_general_character"),
|
||||
special2: getVal(".form_general_special_war"),
|
||||
|
||||
dex1: getInt('.form_dex1'),
|
||||
dex2: getInt('.form_dex2'),
|
||||
dex3: getInt('.form_dex3'),
|
||||
dex4: getInt('.form_dex4'),
|
||||
dex5: getInt('.form_dex5'),
|
||||
crew: getInt(".form_crew"),
|
||||
crewtype: getInt(".form_crewtype"),
|
||||
atmos: getInt(".form_atmos"),
|
||||
train: getInt(".form_train"),
|
||||
|
||||
defence_train: getInt('.form_defence_train'),
|
||||
dex1: getInt(".form_dex1"),
|
||||
dex2: getInt(".form_dex2"),
|
||||
dex3: getInt(".form_dex3"),
|
||||
dex4: getInt(".form_dex4"),
|
||||
dex5: getInt(".form_dex5"),
|
||||
|
||||
warnum: getInt('.form_warnum'),
|
||||
killnum: getInt('.form_killnum'),
|
||||
killcrew: getInt('.form_killcrew'),
|
||||
defence_train: getInt(".form_defence_train"),
|
||||
|
||||
};
|
||||
warnum: getInt(".form_warnum"),
|
||||
killnum: getInt(".form_killnum"),
|
||||
killcrew: getInt(".form_killcrew"),
|
||||
|
||||
inheritBuff: {
|
||||
warAvoidRatio: getInt(".form_war_avoid_ratio"),
|
||||
warCriticalRatio: getInt(".form_war_critical_ratio"),
|
||||
warMagicTrialProb: getInt(".form_war_magic_trial_prob"),
|
||||
warAvoidRatioOppose: getInt(".form_oppose_war_avoid_ratio"),
|
||||
warCriticalRatioOppose: getInt(".form_oppose_war_critical_ratio"),
|
||||
warMagicTrialProbOppose: getInt(".form_oppose_war_magic_trial_prob"),
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const importBattleInfoByFile = function (files: FileList) {
|
||||
if (files === null) {
|
||||
alert("파일 에러!");
|
||||
return false;
|
||||
}
|
||||
|
||||
const importBattleInfoByFile = function (files: FileList) {
|
||||
if (files === null) {
|
||||
alert('파일 에러!');
|
||||
return false;
|
||||
}
|
||||
if (files.length < 1) {
|
||||
alert("파일 에러!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (files.length < 1) {
|
||||
alert("파일 에러!");
|
||||
return false;
|
||||
}
|
||||
const file = files[0];
|
||||
if (file.size > 1024 * 1024) {
|
||||
alert("파일이 너무 큽니다!");
|
||||
return false;
|
||||
}
|
||||
if (file.type === "") {
|
||||
alert("폴더를 업로드할 수 없습니다!");
|
||||
return false;
|
||||
}
|
||||
|
||||
const reader = new FileReader();
|
||||
reader.onload = function () {
|
||||
let battleData: ExportedInfo;
|
||||
try {
|
||||
battleData = JSON.parse(unwrap_any<string>(reader.result));
|
||||
} catch (e) {
|
||||
alert("올바르지 않은 파일 형식입니다");
|
||||
return false;
|
||||
}
|
||||
|
||||
const file = files[0];
|
||||
if (file.size > 1024 * 1024) {
|
||||
alert('파일이 너무 큽니다!');
|
||||
return false;
|
||||
}
|
||||
if (file.type === '') {
|
||||
alert('폴더를 업로드할 수 없습니다!');
|
||||
return false;
|
||||
}
|
||||
if (!("objType" in battleData)) {
|
||||
alert("파일 형식을 확인할 수 없습니다");
|
||||
return false;
|
||||
}
|
||||
|
||||
const reader = new FileReader();
|
||||
reader.onload = function () {
|
||||
let battleData: ExportedInfo;
|
||||
try {
|
||||
battleData = JSON.parse(unwrap_any<string>(reader.result));
|
||||
} catch (e) {
|
||||
alert('올바르지 않은 파일 형식입니다');
|
||||
return false;
|
||||
}
|
||||
if (battleData.objType != "battle") {
|
||||
alert("전투 데이터가 아닙니다");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!('objType' in battleData)) {
|
||||
alert('파일 형식을 확인할 수 없습니다');
|
||||
return false;
|
||||
}
|
||||
importBattleInfo(battleData.data);
|
||||
return true;
|
||||
};
|
||||
|
||||
if (battleData.objType != 'battle') {
|
||||
alert('전투 데이터가 아닙니다');
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
reader.readAsText(file);
|
||||
} catch (e) {
|
||||
alert("파일을 읽는데 실패했습니다.");
|
||||
return false;
|
||||
}
|
||||
|
||||
importBattleInfo(battleData.data);
|
||||
return true;
|
||||
};
|
||||
return true;
|
||||
};
|
||||
|
||||
try {
|
||||
const importGeneralInfoByFile = function (files: FileList, $card: JQuery<HTMLElement>) {
|
||||
if ($card === undefined) {
|
||||
$card = addDefender();
|
||||
}
|
||||
|
||||
reader.readAsText(file);
|
||||
} catch (e) {
|
||||
alert('파일을 읽는데 실패했습니다.');
|
||||
return false;
|
||||
}
|
||||
if (files === null) {
|
||||
alert("파일 에러!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (files.length < 1) {
|
||||
alert("파일 에러!");
|
||||
return false;
|
||||
}
|
||||
|
||||
const file = files[0];
|
||||
if (file.size > 1024 * 1024) {
|
||||
alert("파일이 너무 큽니다!");
|
||||
return false;
|
||||
}
|
||||
if (file.type === "") {
|
||||
alert("폴더를 업로드할 수 없습니다!");
|
||||
return false;
|
||||
}
|
||||
|
||||
const reader = new FileReader();
|
||||
reader.onload = function () {
|
||||
let generalData: ExportedInfo;
|
||||
try {
|
||||
generalData = JSON.parse(unwrap_any<string>(reader.result));
|
||||
} catch (e) {
|
||||
alert("올바르지 않은 파일 형식입니다");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!("objType" in generalData)) {
|
||||
alert("파일 형식을 확인할 수 없습니다");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (generalData.objType == "battle") {
|
||||
importBattleInfo(generalData.data);
|
||||
return true;
|
||||
}
|
||||
if (generalData.objType != "general") {
|
||||
alert("장수 데이터가 아닙니다");
|
||||
return false;
|
||||
}
|
||||
|
||||
$card.find(".form_load_general_file").val("");
|
||||
|
||||
importGeneralInfo($card, generalData.data);
|
||||
return true;
|
||||
};
|
||||
|
||||
try {
|
||||
reader.readAsText(file);
|
||||
} catch (e) {
|
||||
alert("파일을 읽는데 실패했습니다.");
|
||||
return false;
|
||||
}
|
||||
|
||||
const importGeneralInfoByFile = function (files: FileList, $card: JQuery<HTMLElement>) {
|
||||
if ($card === undefined) {
|
||||
$card = addDefender();
|
||||
}
|
||||
|
||||
if (files === null) {
|
||||
alert('파일 에러!');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (files.length < 1) {
|
||||
alert("파일 에러!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
const file = files[0];
|
||||
if (file.size > 1024 * 1024) {
|
||||
alert('파일이 너무 큽니다!');
|
||||
return false;
|
||||
}
|
||||
if (file.type === '') {
|
||||
alert('폴더를 업로드할 수 없습니다!');
|
||||
return false;
|
||||
}
|
||||
|
||||
const reader = new FileReader();
|
||||
reader.onload = function () {
|
||||
let generalData: ExportedInfo;
|
||||
try {
|
||||
generalData = JSON.parse(unwrap_any<string>(reader.result));
|
||||
} catch (e) {
|
||||
alert('올바르지 않은 파일 형식입니다');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!('objType' in generalData)) {
|
||||
alert('파일 형식을 확인할 수 없습니다');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (generalData.objType == 'battle') {
|
||||
importBattleInfo(generalData.data);
|
||||
return true;
|
||||
}
|
||||
if (generalData.objType != 'general') {
|
||||
alert('장수 데이터가 아닙니다');
|
||||
return false;
|
||||
}
|
||||
|
||||
$card.find('.form_load_general_file').val('');
|
||||
|
||||
importGeneralInfo($card, generalData.data);
|
||||
return true;
|
||||
};
|
||||
|
||||
try {
|
||||
|
||||
reader.readAsText(file);
|
||||
} catch (e) {
|
||||
alert('파일을 읽는데 실패했습니다.');
|
||||
return false;
|
||||
return true;
|
||||
};
|
||||
|
||||
const extendGeneralInfoForDB = function (generalData: GeneralInfo) {
|
||||
const dbVal = {
|
||||
nation: generalData.no <= 1 ? 1 : 2,
|
||||
city: generalData.no <= 1 ? 1 : 3,
|
||||
turntime: "2018-08-26 12:00",
|
||||
special: window.defaultSpecialDomestic,
|
||||
leadership_exp: 0,
|
||||
strength_exp: 0,
|
||||
intel_exp: 0,
|
||||
|
||||
gold: 10000,
|
||||
|
||||
dedication: 0,
|
||||
|
||||
recent_war: "2018-08-26 12:00",
|
||||
experience: Math.pow(generalData.explevel, 2),
|
||||
};
|
||||
|
||||
return $.extend({}, generalData, dbVal);
|
||||
};
|
||||
|
||||
const getGeneralFrame = function ($btn: JQuery<HTMLElement>) {
|
||||
const $card = $btn.closest(".general_form");
|
||||
return $card;
|
||||
};
|
||||
|
||||
const getGeneralDetail = function ($btn: JQuery<HTMLElement>) {
|
||||
const $card = getGeneralFrame($btn);
|
||||
const $general = $card.find(".general_detail");
|
||||
return $general;
|
||||
};
|
||||
|
||||
const getGeneralNo = function ($btn: JQuery<HTMLElement>) {
|
||||
return parseInt(getGeneralFrame($btn).data("general_no"));
|
||||
};
|
||||
|
||||
const setGeneralNo = function ($btn: JQuery<HTMLElement>, value: number) {
|
||||
if (value == 1) {
|
||||
//1번은 무조건 공격자임
|
||||
return false;
|
||||
}
|
||||
if (value in defenderNoList) {
|
||||
return false;
|
||||
}
|
||||
const $card = getGeneralFrame($btn);
|
||||
$card.data("general_no", value);
|
||||
defenderNoList[value] = $card;
|
||||
return true;
|
||||
};
|
||||
|
||||
const generateNewGeneralNo = function () {
|
||||
for (;;) {
|
||||
const newGeneralNo = Math.floor(Math.random() * (1 << 24)) + 2;
|
||||
if (newGeneralNo in defenderNoList) {
|
||||
continue;
|
||||
}
|
||||
return newGeneralNo;
|
||||
}
|
||||
};
|
||||
|
||||
const deleteGeneralNo = function ($btn: JQuery<HTMLElement>) {
|
||||
const $card = getGeneralFrame($btn);
|
||||
$card.removeData("general_no");
|
||||
const generalNo = getGeneralNo($card);
|
||||
delete defenderNoList[generalNo];
|
||||
};
|
||||
|
||||
const addDefender = function ($cardAfter?: JQuery<HTMLElement>) {
|
||||
const $newCard = $('<div class="card mb-2 defender_form general_form"></div>');
|
||||
|
||||
if ($cardAfter === undefined) {
|
||||
$defenderColumn.append($newCard);
|
||||
} else {
|
||||
$cardAfter.after($newCard);
|
||||
}
|
||||
|
||||
$newCard.append($defenderHeaderForm.clone(true, true));
|
||||
$newCard.append($generalForm.clone(true, true));
|
||||
|
||||
//$newGeneral = getGeneralDetail($newCard);
|
||||
setGeneralNo($newCard, generateNewGeneralNo());
|
||||
|
||||
return $newCard;
|
||||
};
|
||||
|
||||
const deleteDefender = function ($card: JQuery<HTMLElement>) {
|
||||
deleteGeneralNo($card);
|
||||
$card.detach();
|
||||
};
|
||||
|
||||
const copyDefender = function ($card: JQuery<HTMLElement>) {
|
||||
const $general = getGeneralDetail($card);
|
||||
|
||||
const generalData = exportGeneralInfo($general);
|
||||
const $newObj = addDefender($card);
|
||||
importGeneralInfo(getGeneralDetail($newObj), generalData);
|
||||
};
|
||||
|
||||
const importBattleInfo = function (battleData: BattleInfo) {
|
||||
$(".form_load_battle_file").val("");
|
||||
console.log(battleData);
|
||||
|
||||
const $attackerNation = $(".attacker_nation");
|
||||
const $defenderNation = $(".defender_nation");
|
||||
|
||||
const attackerGeneral = battleData.attackerGeneral;
|
||||
const attackerCity = battleData.attackerCity;
|
||||
const attackerNation = battleData.attackerNation;
|
||||
|
||||
const defenderGenerals = battleData.defenderGenerals;
|
||||
const defenderCity = battleData.defenderCity;
|
||||
const defenderNation = battleData.defenderNation;
|
||||
|
||||
const seed = battleData.seed;
|
||||
|
||||
if (seed) {
|
||||
$("#seed").val(seed);
|
||||
}
|
||||
|
||||
$("#year").val(battleData.year);
|
||||
$("#month").val(battleData.month);
|
||||
$("#repeat_cnt").val(battleData.repeatCnt);
|
||||
|
||||
$(".delete-defender").trigger("click");
|
||||
|
||||
$attackerNation.find(".form_nation_type").val(attackerNation.type);
|
||||
$attackerNation.find(".form_tech").val(Math.floor(attackerNation.tech / 1000));
|
||||
$attackerNation.find(".form_nation_level").val(attackerNation.level);
|
||||
if (attackerNation.capital == 1) {
|
||||
$attackerNation.find(".form_is_capital:first").trigger("click");
|
||||
} else {
|
||||
$attackerNation.find(".form_is_capital:last").trigger("click");
|
||||
}
|
||||
$attackerNation.find(".form_city_level").val(attackerCity.level);
|
||||
|
||||
importGeneralInfo($(".attacker_form"), attackerGeneral);
|
||||
|
||||
$defenderNation.find(".form_nation_type").val(defenderNation.type);
|
||||
$defenderNation.find(".form_tech").val(Math.floor(defenderNation.tech / 1000));
|
||||
$defenderNation.find(".form_nation_level").val(defenderNation.level);
|
||||
if (defenderNation.capital == 1) {
|
||||
$defenderNation.find(".form_is_capital:first").trigger("click");
|
||||
} else {
|
||||
$defenderNation.find(".form_is_capital:last").trigger("click");
|
||||
}
|
||||
$defenderNation.find(".form_city_level").val(defenderCity.level);
|
||||
$("#city_def").val(defenderCity.def);
|
||||
$("#city_wall").val(defenderCity.wall);
|
||||
|
||||
$.each(defenderGenerals, function (idx, defenderGeneral) {
|
||||
const $card = addDefender();
|
||||
importGeneralInfo($card, defenderGeneral);
|
||||
});
|
||||
};
|
||||
|
||||
const exportAllData = function (): BattleInfo {
|
||||
const $attackerNation = $(".attacker_nation");
|
||||
const $defenderNation = $(".defender_nation");
|
||||
|
||||
const attackerGeneral = exportGeneralInfo($(".attacker_form"));
|
||||
|
||||
const attackerCity = {
|
||||
level: parseInt($attackerNation.find(".form_city_level").val() as string),
|
||||
};
|
||||
|
||||
const attackerNation = {
|
||||
type: unwrap_any<string>($attackerNation.find(".form_nation_type").val()),
|
||||
tech: parseInt($attackerNation.find(".form_tech").val() as string) * 1000,
|
||||
level: parseInt($attackerNation.find(".form_nation_level").val() as string),
|
||||
capital: $attackerNation.find(".form_is_capital:checked").val() == "1" ? 1 : 2,
|
||||
};
|
||||
|
||||
const defenderGenerals = $(".defender_form")
|
||||
.map(function () {
|
||||
return exportGeneralInfo($(this));
|
||||
})
|
||||
.toArray();
|
||||
|
||||
const defenderCity = {
|
||||
def: parseInt($("#city_def").val() as string),
|
||||
wall: parseInt($("#city_wall").val() as string),
|
||||
level: parseInt($defenderNation.find(".form_city_level").val() as string),
|
||||
};
|
||||
|
||||
const defenderNation = {
|
||||
type: unwrap_any<string>($defenderNation.find(".form_nation_type").val()),
|
||||
tech: parseInt(unwrap_any<string>($defenderNation.find(".form_tech").val())) * 1000,
|
||||
level: parseInt(unwrap_any<string>($defenderNation.find(".form_nation_level").val())),
|
||||
capital: $defenderNation.find(".form_is_capital:checked").val() == "1" ? 3 : 4,
|
||||
};
|
||||
|
||||
const year = parseInt(unwrap_any<string>($("#year").val()));
|
||||
const month = parseInt(unwrap_any<string>($("#month").val()));
|
||||
const repeatCnt = parseInt(unwrap_any<string>($("#repeat_cnt").val()));
|
||||
|
||||
const seed = unwrap_any<string>($("#seed").val());
|
||||
|
||||
return {
|
||||
attackerGeneral: attackerGeneral,
|
||||
attackerCity: attackerCity,
|
||||
attackerNation: attackerNation,
|
||||
|
||||
defenderGenerals: defenderGenerals,
|
||||
defenderCity: defenderCity,
|
||||
defenderNation: defenderNation,
|
||||
|
||||
year: year,
|
||||
month: month,
|
||||
repeatCnt: repeatCnt,
|
||||
|
||||
seed,
|
||||
};
|
||||
};
|
||||
|
||||
const extendAllDataForDB = function (allData: BattleInfo): BattleInfo {
|
||||
const defaultNation = {
|
||||
nation: 0,
|
||||
name: "재야",
|
||||
capital: 0,
|
||||
level: 0,
|
||||
gold: 0,
|
||||
rice: 2000,
|
||||
type: "None",
|
||||
tech: 0,
|
||||
gennum: 200,
|
||||
};
|
||||
|
||||
const defaultCity = {
|
||||
nation: 0,
|
||||
supply: 1,
|
||||
name: "도시",
|
||||
|
||||
pop: 500000,
|
||||
agri: 10000,
|
||||
comm: 10000,
|
||||
secu: 10000,
|
||||
def: 1000,
|
||||
wall: 1000,
|
||||
|
||||
trust: 100,
|
||||
|
||||
pop_max: 600000,
|
||||
agri_max: 12000,
|
||||
comm_max: 12000,
|
||||
secu_max: 10000,
|
||||
def_max: 12000,
|
||||
wall_max: 12000,
|
||||
|
||||
dead: 0,
|
||||
|
||||
state: 0,
|
||||
|
||||
conflict: "{}",
|
||||
};
|
||||
|
||||
const attackerNation = $.extend({}, defaultNation, allData.attackerNation);
|
||||
attackerNation.nation = 1;
|
||||
attackerNation.name = "출병국";
|
||||
|
||||
const attackerCity = $.extend({}, defaultCity, allData.attackerCity) as CityBasicInfo;
|
||||
attackerCity.nation = 1;
|
||||
attackerCity.city = 1;
|
||||
|
||||
const attackerGeneral = extendGeneralInfoForDB(allData.attackerGeneral);
|
||||
if (2 <= attackerGeneral.officer_level && attackerGeneral.officer_level <= 4) {
|
||||
attackerGeneral.officer_city = 1;
|
||||
} else {
|
||||
attackerGeneral.officer_city = 0;
|
||||
}
|
||||
|
||||
const defenderNation = $.extend({}, defaultNation, allData.defenderNation);
|
||||
defenderNation.nation = 2;
|
||||
defenderNation.name = "수비국";
|
||||
|
||||
const defenderCity = $.extend({}, defaultCity, allData.defenderCity);
|
||||
defenderCity.nation = 2;
|
||||
defenderCity.city = 3;
|
||||
defenderCity.wall_max = Math.floor((defenderCity.wall / 5) * 6);
|
||||
defenderCity.def_max = Math.floor((defenderCity.def / 5) * 6);
|
||||
|
||||
const defenderGenerals: GeneralInfo[] = [];
|
||||
$.each(allData.defenderGenerals, function () {
|
||||
const defenderGeneral = extendGeneralInfoForDB(this);
|
||||
if (2 <= defenderGeneral.officer_level && defenderGeneral.officer_level <= 4) {
|
||||
defenderGeneral.officer_city = 3;
|
||||
} else {
|
||||
defenderGeneral.officer_city = 0;
|
||||
}
|
||||
|
||||
defenderGenerals.push(defenderGeneral);
|
||||
});
|
||||
|
||||
return $.extend({}, allData, {
|
||||
attackerGeneral: attackerGeneral,
|
||||
attackerCity: attackerCity,
|
||||
attackerNation: attackerNation,
|
||||
|
||||
defenderGenerals: defenderGenerals,
|
||||
defenderCity: defenderCity,
|
||||
defenderNation: defenderNation,
|
||||
});
|
||||
};
|
||||
|
||||
const parseSkillCount = function (skills: Record<string, number>) {
|
||||
const result: string[] = [];
|
||||
for (const [key, value] of Object.entries(skills)) {
|
||||
result.push(`${key}(${toPretty(value)}회)`);
|
||||
}
|
||||
|
||||
if (result.length == 0) {
|
||||
return "-";
|
||||
}
|
||||
return result.join(", ");
|
||||
};
|
||||
|
||||
const toPretty = function (number: number) {
|
||||
if (isInteger(number)) {
|
||||
number = Math.floor(number);
|
||||
} else {
|
||||
number = parseFloat(number.toFixed(2));
|
||||
}
|
||||
return numberWithCommas(number);
|
||||
};
|
||||
|
||||
const showBattleResult = function (result: BattleResult) {
|
||||
$("#result_datetime").html(result.datetime);
|
||||
$("#result_warcnt").html(toPretty(result.avgWar));
|
||||
$("#result_phase").html(toPretty(result.phase));
|
||||
$("#result_killed").html(toPretty(result.killed));
|
||||
if (result.minKilled != result.maxKilled) {
|
||||
$("#result_maxKilled").html(toPretty(result.maxKilled));
|
||||
$("#result_minKilled").html(toPretty(result.minKilled));
|
||||
$("#result_varKilled").show();
|
||||
} else {
|
||||
$("#result_varKilled").hide();
|
||||
}
|
||||
$("#result_dead").html(toPretty(result.dead));
|
||||
if (result.minDead != result.maxDead) {
|
||||
$("#result_maxDead").html(toPretty(result.maxDead));
|
||||
$("#result_minDead").html(toPretty(result.minDead));
|
||||
$("#result_varDead").show();
|
||||
} else {
|
||||
$("#result_varDead").hide();
|
||||
}
|
||||
|
||||
$("#result_attackerRice").html(toPretty(result.attackerRice));
|
||||
$("#result_defenderRice").html(toPretty(result.defenderRice));
|
||||
$("#result_attackerSkills").html(parseSkillCount(result.attackerSkills));
|
||||
|
||||
$(".result_defenderSkills").detach();
|
||||
|
||||
const $summary = $("#battle_result_summary");
|
||||
|
||||
for (const [idx, defenderSkills] of Object.entries(result.defendersSkills)) {
|
||||
console.log(defenderSkills);
|
||||
const $result = $(`<tr class='result_defenderSkills'><th>수비자${parseInt(idx) + 1} 스킬</th><td></td></tr>`);
|
||||
$result.find("td").html(parseSkillCount(defenderSkills));
|
||||
$summary.append($result);
|
||||
}
|
||||
|
||||
$("#generalBattleResultLog").html(result.lastWarLog.generalBattleResultLog);
|
||||
$("#generalBattleDetailLog").html(result.lastWarLog.generalBattleDetailLog);
|
||||
};
|
||||
|
||||
const beginBattle = function () {
|
||||
const data = extendAllDataForDB(exportAllData());
|
||||
console.log(data);
|
||||
$.ajax({
|
||||
type: "post",
|
||||
url: "j_simulate_battle.php",
|
||||
dataType: "json",
|
||||
data: {
|
||||
action: "battle",
|
||||
query: JSON.stringify(data),
|
||||
},
|
||||
}).then(
|
||||
function (result) {
|
||||
console.log(result);
|
||||
if (!result.result) {
|
||||
alert(result.reason);
|
||||
return;
|
||||
}
|
||||
showBattleResult(result);
|
||||
},
|
||||
function () {
|
||||
alert("전투 개시 실패!");
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const reorderDefender = function (defenderOrder: number[]) {
|
||||
for (const generalNo of defenderOrder) {
|
||||
if (!(generalNo in defenderNoList)) {
|
||||
//음..?
|
||||
alert(`${generalNo}이 수비자 리스트에 없습니다. 버그인 듯 합니다.`);
|
||||
return true;
|
||||
}
|
||||
|
||||
const $defenderObj = defenderNoList[generalNo];
|
||||
$defenderObj.detach();
|
||||
$defenderColumn.append($defenderObj);
|
||||
}
|
||||
};
|
||||
|
||||
const extendGeneralInfoForDB = function (generalData: GeneralInfo) {
|
||||
|
||||
const dbVal = {
|
||||
nation: (generalData.no) <= 1 ? 1 : 2,
|
||||
city: (generalData.no) <= 1 ? 1 : 3,
|
||||
turntime: '2018-08-26 12:00',
|
||||
special: window.defaultSpecialDomestic,
|
||||
leadership_exp: 0,
|
||||
strength_exp: 0,
|
||||
intel_exp: 0,
|
||||
|
||||
gold: 10000,
|
||||
|
||||
dedication: 0,
|
||||
|
||||
recent_war: '2018-08-26 12:00',
|
||||
experience: Math.pow(generalData.explevel, 2),
|
||||
};
|
||||
|
||||
return $.extend({}, generalData, dbVal);
|
||||
}
|
||||
|
||||
const getGeneralFrame = function ($btn: JQuery<HTMLElement>) {
|
||||
const $card = $btn.closest('.general_form');
|
||||
return $card;
|
||||
}
|
||||
|
||||
const getGeneralDetail = function ($btn: JQuery<HTMLElement>) {
|
||||
const $card = getGeneralFrame($btn);
|
||||
const $general = $card.find('.general_detail');
|
||||
return $general;
|
||||
}
|
||||
|
||||
const getGeneralNo = function ($btn: JQuery<HTMLElement>) {
|
||||
return parseInt(getGeneralFrame($btn).data('general_no'));
|
||||
}
|
||||
|
||||
const setGeneralNo = function ($btn: JQuery<HTMLElement>, value: number) {
|
||||
if (value == 1) {
|
||||
//1번은 무조건 공격자임
|
||||
return false;
|
||||
const requestReorderDefender = function () {
|
||||
const data = extendAllDataForDB(exportAllData());
|
||||
console.log(data);
|
||||
$.ajax({
|
||||
type: "post",
|
||||
url: "j_simulate_battle.php",
|
||||
dataType: "json",
|
||||
data: {
|
||||
action: "reorder",
|
||||
query: JSON.stringify(data),
|
||||
},
|
||||
}).then(
|
||||
function (result) {
|
||||
console.log(result);
|
||||
if (!result.result) {
|
||||
alert(result.reason);
|
||||
return;
|
||||
}
|
||||
if (value in defenderNoList) {
|
||||
return false;
|
||||
}
|
||||
const $card = getGeneralFrame($btn);
|
||||
$card.data('general_no', value);
|
||||
defenderNoList[value] = $card;
|
||||
return true;
|
||||
}
|
||||
reorderDefender(result.order);
|
||||
},
|
||||
function () {
|
||||
alert("재정렬 실패!");
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const generateNewGeneralNo = function () {
|
||||
for (; ;) {
|
||||
const newGeneralNo = Math.floor(Math.random() * (1 << 24)) + 2;
|
||||
if (newGeneralNo in defenderNoList) {
|
||||
continue;
|
||||
}
|
||||
return newGeneralNo;
|
||||
}
|
||||
}
|
||||
let initGeneralList = false;
|
||||
|
||||
const deleteGeneralNo = function ($btn: JQuery<HTMLElement>) {
|
||||
const $card = getGeneralFrame($btn);
|
||||
$card.removeData('general_no');
|
||||
const generalNo = getGeneralNo($card);
|
||||
delete defenderNoList[generalNo];
|
||||
}
|
||||
$("#importFromDB").on("click", function () {
|
||||
const generalID = $("#modalSelector").val();
|
||||
console.log(generalID);
|
||||
|
||||
const addDefender = function ($cardAfter?: JQuery<HTMLElement>) {
|
||||
const $newCard = $('<div class="card mb-2 defender_form general_form"></div>');
|
||||
$.post({
|
||||
url: "j_export_simulator_object.php",
|
||||
dataType: "json",
|
||||
data: {
|
||||
destGeneralID: generalID,
|
||||
},
|
||||
}).then(function (data) {
|
||||
if (!data.result) {
|
||||
alert(data.reason);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($cardAfter === undefined) {
|
||||
$defenderColumn.append($newCard);
|
||||
} else {
|
||||
$cardAfter.after($newCard);
|
||||
}
|
||||
const $modal = $("#importModal");
|
||||
const $card = $modal.data("target");
|
||||
importGeneralInfo($card, data.general);
|
||||
|
||||
$newCard.append($defenderHeaderForm.clone(true, true));
|
||||
$newCard.append($generalForm.clone(true, true));
|
||||
if (modalImport) {
|
||||
modalImport.hide();
|
||||
}
|
||||
}, errUnknown);
|
||||
});
|
||||
|
||||
//$newGeneral = getGeneralDetail($newCard);
|
||||
setGeneralNo($newCard, generateNewGeneralNo());
|
||||
unwrap(document.querySelector("#importModal")).addEventListener("show.bs.modal", function () {
|
||||
if (!initGeneralList) {
|
||||
const $list = $("#modalSelector");
|
||||
|
||||
return $newCard;
|
||||
}
|
||||
|
||||
const deleteDefender = function ($card: JQuery<HTMLElement>) {
|
||||
deleteGeneralNo($card);
|
||||
$card.detach();
|
||||
}
|
||||
|
||||
const copyDefender = function ($card: JQuery<HTMLElement>) {
|
||||
const $general = getGeneralDetail($card);
|
||||
|
||||
const generalData = exportGeneralInfo($general);
|
||||
const $newObj = addDefender($card);
|
||||
importGeneralInfo(getGeneralDetail($newObj), generalData);
|
||||
}
|
||||
|
||||
const importBattleInfo = function (battleData: BattleInfo) {
|
||||
|
||||
$('.form_load_battle_file').val('');
|
||||
console.log(battleData);
|
||||
|
||||
const $attackerNation = $('.attacker_nation');
|
||||
const $defenderNation = $('.defender_nation');
|
||||
|
||||
const attackerGeneral = battleData.attackerGeneral;
|
||||
const attackerCity = battleData.attackerCity;
|
||||
const attackerNation = battleData.attackerNation;
|
||||
|
||||
const defenderGenerals = battleData.defenderGenerals;
|
||||
const defenderCity = battleData.defenderCity;
|
||||
const defenderNation = battleData.defenderNation;
|
||||
|
||||
$('#year').val(battleData.year);
|
||||
$('#month').val(battleData.month);
|
||||
$('#repeat_cnt').val(battleData.repeatCnt);
|
||||
|
||||
$('.delete-defender').trigger('click');
|
||||
|
||||
$attackerNation.find('.form_nation_type').val(attackerNation.type);
|
||||
$attackerNation.find('.form_tech').val(Math.floor(attackerNation.tech / 1000));
|
||||
$attackerNation.find('.form_nation_level').val(attackerNation.level);
|
||||
if (attackerNation.capital == 1) {
|
||||
$attackerNation.find('.form_is_capital:first').trigger('click');
|
||||
} else {
|
||||
$attackerNation.find('.form_is_capital:last').trigger('click');
|
||||
}
|
||||
$attackerNation.find('.form_city_level').val(attackerCity.level);
|
||||
|
||||
importGeneralInfo($('.attacker_form'), attackerGeneral);
|
||||
|
||||
$defenderNation.find('.form_nation_type').val(defenderNation.type);
|
||||
$defenderNation.find('.form_tech').val(Math.floor(defenderNation.tech / 1000));
|
||||
$defenderNation.find('.form_nation_level').val(defenderNation.level);
|
||||
if (defenderNation.capital == 1) {
|
||||
$defenderNation.find('.form_is_capital:first').trigger('click');
|
||||
} else {
|
||||
$defenderNation.find('.form_is_capital:last').trigger('click');
|
||||
}
|
||||
$defenderNation.find('.form_city_level').val(defenderCity.level);
|
||||
$('#city_def').val(defenderCity.def);
|
||||
$('#city_wall').val(defenderCity.wall);
|
||||
|
||||
$.each(defenderGenerals, function (idx, defenderGeneral) {
|
||||
const $card = addDefender();
|
||||
importGeneralInfo($card, defenderGeneral);
|
||||
const addNation = function (generalList: GeneralInfo[], nationName: string, color: string) {
|
||||
generalList.sort(function (lhs, rhs) {
|
||||
if (lhs.npc != rhs.npc) {
|
||||
return (lhs.npc ?? 0) - (rhs.npc ?? 0);
|
||||
}
|
||||
if (lhs.name < rhs.name) {
|
||||
return -1;
|
||||
}
|
||||
if (lhs.name > rhs.name) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
const $optGroup = $(`<optgroup label="${nationName}"></optgroup>`);
|
||||
$optGroup.css("background-color", color);
|
||||
$optGroup.css("color", isBrightColor(color) ? "black" : "white");
|
||||
|
||||
const exportAllData = function (): BattleInfo {
|
||||
const $attackerNation = $('.attacker_nation');
|
||||
const $defenderNation = $('.defender_nation');
|
||||
|
||||
const attackerGeneral = exportGeneralInfo($('.attacker_form'));
|
||||
|
||||
const attackerCity = {
|
||||
level: parseInt($attackerNation.find('.form_city_level').val() as string),
|
||||
};
|
||||
|
||||
const attackerNation = {
|
||||
type: unwrap_any<string>($attackerNation.find('.form_nation_type').val()),
|
||||
tech: parseInt($attackerNation.find('.form_tech').val() as string) * 1000,
|
||||
level: parseInt($attackerNation.find('.form_nation_level').val() as string),
|
||||
capital: $attackerNation.find('.form_is_capital:checked').val() == '1' ? 1 : 2,
|
||||
for (const general of generalList) {
|
||||
const $item = $(`<option value="${general.no}">${general.name}</option>`);
|
||||
if (general.npc) {
|
||||
$item.css("color", unwrap(getNPCColor(general.npc)));
|
||||
} else {
|
||||
$item.css("color", "white");
|
||||
}
|
||||
$item.css("background-color", "black");
|
||||
$optGroup.append($item);
|
||||
}
|
||||
$list.append($optGroup);
|
||||
};
|
||||
$.post({
|
||||
url: "j_get_basic_general_list.php",
|
||||
dataType: "json",
|
||||
data: {
|
||||
req: 2,
|
||||
},
|
||||
}).then(function (data: BasicGeneralListResponse | InvalidResponse) {
|
||||
if (!data.result) {
|
||||
alert(data.reason);
|
||||
if (modalImport) {
|
||||
modalImport.hide();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const defenderGenerals = $('.defender_form').map(function () {
|
||||
return exportGeneralInfo($(this));
|
||||
}).toArray();
|
||||
const nations = data.nation;
|
||||
const myNationID = data.nationID;
|
||||
|
||||
const defenderCity = {
|
||||
def: parseInt($('#city_def').val() as string),
|
||||
wall: parseInt($('#city_wall').val() as string),
|
||||
level: parseInt($defenderNation.find('.form_city_level').val() as string),
|
||||
};
|
||||
$list.empty();
|
||||
//자국 먼저
|
||||
|
||||
const defenderNation = {
|
||||
type: unwrap_any<string>($defenderNation.find('.form_nation_type').val()),
|
||||
tech: parseInt(unwrap_any<string>($defenderNation.find('.form_tech').val())) * 1000,
|
||||
level: parseInt(unwrap_any<string>($defenderNation.find('.form_nation_level').val())),
|
||||
capital: $defenderNation.find('.form_is_capital:checked').val() == '1' ? 3 : 4,
|
||||
}
|
||||
|
||||
const year = parseInt(unwrap_any<string>($('#year').val()));
|
||||
const month = parseInt(unwrap_any<string>($('#month').val()));
|
||||
const repeatCnt = parseInt(unwrap_any<string>($('#repeat_cnt').val()));
|
||||
|
||||
return {
|
||||
attackerGeneral: attackerGeneral,
|
||||
attackerCity: attackerCity,
|
||||
attackerNation: attackerNation,
|
||||
|
||||
defenderGenerals: defenderGenerals,
|
||||
defenderCity: defenderCity,
|
||||
defenderNation: defenderNation,
|
||||
|
||||
year: year,
|
||||
month: month,
|
||||
repeatCnt: repeatCnt,
|
||||
};
|
||||
}
|
||||
|
||||
const extendAllDataForDB = function (allData: BattleInfo): BattleInfo {
|
||||
const defaultNation = {
|
||||
if (0 in data.list) {
|
||||
nations[0] = {
|
||||
nation: 0,
|
||||
name: '재야',
|
||||
capital: 0,
|
||||
level: 0,
|
||||
gold: 0,
|
||||
rice: 2000,
|
||||
type: 'None',
|
||||
tech: 0,
|
||||
gennum: 200,
|
||||
};
|
||||
|
||||
const defaultCity = {
|
||||
nation: 0,
|
||||
supply: 1,
|
||||
name: '도시',
|
||||
|
||||
pop: 500000,
|
||||
agri: 10000,
|
||||
comm: 10000,
|
||||
secu: 10000,
|
||||
def: 1000,
|
||||
wall: 1000,
|
||||
|
||||
trust: 100,
|
||||
|
||||
pop_max: 600000,
|
||||
agri_max: 12000,
|
||||
comm_max: 12000,
|
||||
secu_max: 10000,
|
||||
def_max: 12000,
|
||||
wall_max: 12000,
|
||||
|
||||
dead: 0,
|
||||
|
||||
state: 0,
|
||||
|
||||
conflict: '{}',
|
||||
};
|
||||
|
||||
const attackerNation = $.extend({}, defaultNation, allData.attackerNation);
|
||||
attackerNation.nation = 1;
|
||||
attackerNation.name = '출병국';
|
||||
|
||||
const attackerCity = $.extend({}, defaultCity, allData.attackerCity) as CityBasicInfo;
|
||||
attackerCity.nation = 1;
|
||||
attackerCity.city = 1;
|
||||
|
||||
const attackerGeneral = extendGeneralInfoForDB(allData.attackerGeneral);
|
||||
if (2 <= attackerGeneral.officer_level && attackerGeneral.officer_level <= 4) {
|
||||
attackerGeneral.officer_city = 1;
|
||||
} else {
|
||||
attackerGeneral.officer_city = 0;
|
||||
name: "재야",
|
||||
color: "#000000",
|
||||
};
|
||||
}
|
||||
|
||||
const defenderNation = $.extend({}, defaultNation, allData.defenderNation);
|
||||
defenderNation.nation = 2;
|
||||
defenderNation.name = '수비국';
|
||||
addNation(
|
||||
combineArray(data.list[myNationID], data.column) as GeneralInfo[],
|
||||
nations[myNationID].name,
|
||||
nations[myNationID].color
|
||||
);
|
||||
|
||||
const defenderCity = $.extend({}, defaultCity, allData.defenderCity);
|
||||
defenderCity.nation = 2;
|
||||
defenderCity.city = 3;
|
||||
defenderCity.wall_max = Math.floor(defenderCity.wall / 5 * 6);
|
||||
defenderCity.def_max = Math.floor(defenderCity.def / 5 * 6);
|
||||
|
||||
const defenderGenerals: GeneralInfo[] = [];
|
||||
$.each(allData.defenderGenerals, function () {
|
||||
const defenderGeneral = extendGeneralInfoForDB(this);
|
||||
if (2 <= defenderGeneral.officer_level && defenderGeneral.officer_level <= 4) {
|
||||
defenderGeneral.officer_city = 3;
|
||||
} else {
|
||||
defenderGeneral.officer_city = 0;
|
||||
}
|
||||
|
||||
defenderGenerals.push(defenderGeneral);
|
||||
});
|
||||
|
||||
|
||||
return $.extend({}, allData, {
|
||||
attackerGeneral: attackerGeneral,
|
||||
attackerCity: attackerCity,
|
||||
attackerNation: attackerNation,
|
||||
|
||||
defenderGenerals: defenderGenerals,
|
||||
defenderCity: defenderCity,
|
||||
defenderNation: defenderNation,
|
||||
});
|
||||
for (const nationID of Object.keys(data.list)) {
|
||||
if (parseInt(nationID) == myNationID) {
|
||||
continue;
|
||||
}
|
||||
addNation(
|
||||
combineArray(data.list[nationID], data.column) as GeneralInfo[],
|
||||
nations[nationID].name,
|
||||
nations[nationID].color
|
||||
);
|
||||
}
|
||||
initGeneralList = true;
|
||||
}, errUnknown);
|
||||
}
|
||||
});
|
||||
|
||||
const parseSkillCount = function (skills: Record<string, number>) {
|
||||
const result: string[] = [];
|
||||
for (const [key, value] of Object.entries(skills)) {
|
||||
result.push(`${key}(${toPretty(value)}회)`);
|
||||
}
|
||||
initBasicEvent();
|
||||
$attackerCard.append($generalForm.clone(true, true));
|
||||
addDefender();
|
||||
|
||||
if (result.length == 0) {
|
||||
return '-';
|
||||
}
|
||||
return result.join(', ');
|
||||
}
|
||||
$(".btn-begin_battle").on("click", function () {
|
||||
beginBattle();
|
||||
});
|
||||
|
||||
const toPretty = function (number: number) {
|
||||
if (isInteger(number)) {
|
||||
number = Math.floor(number);
|
||||
} else {
|
||||
number = parseFloat(number.toFixed(2));
|
||||
}
|
||||
return numberWithCommas(number);
|
||||
}
|
||||
|
||||
const showBattleResult = function (result: BattleResult) {
|
||||
$('#result_datetime').html(result.datetime);
|
||||
$('#result_warcnt').html(toPretty(result.avgWar));
|
||||
$('#result_phase').html(toPretty(result.phase));
|
||||
$('#result_killed').html(toPretty(result.killed));
|
||||
if (result.minKilled != result.maxKilled) {
|
||||
$('#result_maxKilled').html(toPretty(result.maxKilled));
|
||||
$('#result_minKilled').html(toPretty(result.minKilled));
|
||||
$('#result_varKilled').show();
|
||||
} else {
|
||||
$('#result_varKilled').hide();
|
||||
}
|
||||
$('#result_dead').html(toPretty(result.dead));
|
||||
if (result.minDead != result.maxDead) {
|
||||
$('#result_maxDead').html(toPretty(result.maxDead));
|
||||
$('#result_minDead').html(toPretty(result.minDead));
|
||||
$('#result_varDead').show();
|
||||
} else {
|
||||
$('#result_varDead').hide();
|
||||
}
|
||||
|
||||
$('#result_attackerRice').html(toPretty(result.attackerRice));
|
||||
$('#result_defenderRice').html(toPretty(result.defenderRice));
|
||||
$('#result_attackerSkills').html(parseSkillCount(result.attackerSkills));
|
||||
|
||||
$('.result_defenderSkills').detach();
|
||||
|
||||
const $summary = $('#battle_result_summary');
|
||||
|
||||
for (const [idx, defenderSkills] of Object.entries(result.defendersSkills)) {
|
||||
console.log(defenderSkills);
|
||||
const $result = $(`<tr class='result_defenderSkills'><th>수비자${parseInt(idx) + 1} 스킬</th><td></td></tr>`);
|
||||
$result.find('td').html(parseSkillCount(defenderSkills));
|
||||
$summary.append($result);
|
||||
}
|
||||
|
||||
$('#generalBattleResultLog').html(result.lastWarLog.generalBattleResultLog);
|
||||
$('#generalBattleDetailLog').html(result.lastWarLog.generalBattleDetailLog);
|
||||
|
||||
}
|
||||
|
||||
const beginBattle = function () {
|
||||
const data = extendAllDataForDB(exportAllData());
|
||||
console.log(data);
|
||||
$.ajax({
|
||||
type: 'post',
|
||||
url: 'j_simulate_battle.php',
|
||||
dataType: 'json',
|
||||
data: {
|
||||
action: 'battle',
|
||||
query: JSON.stringify(data),
|
||||
}
|
||||
}).then(function (result) {
|
||||
console.log(result);
|
||||
if (!result.result) {
|
||||
alert(result.reason);
|
||||
return;
|
||||
}
|
||||
showBattleResult(result);
|
||||
|
||||
}, function () {
|
||||
alert('전투 개시 실패!');
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
const reorderDefender = function (defenderOrder: number[]) {
|
||||
for (const generalNo of defenderOrder) {
|
||||
|
||||
if (!(generalNo in defenderNoList)) {
|
||||
//음..?
|
||||
alert(`${generalNo}이 수비자 리스트에 없습니다. 버그인 듯 합니다.`);
|
||||
return true;
|
||||
}
|
||||
|
||||
const $defenderObj = defenderNoList[generalNo];
|
||||
$defenderObj.detach();
|
||||
$defenderColumn.append($defenderObj);
|
||||
}
|
||||
}
|
||||
|
||||
const requestReorderDefender = function () {
|
||||
const data = extendAllDataForDB(exportAllData());
|
||||
console.log(data);
|
||||
$.ajax({
|
||||
type: 'post',
|
||||
url: 'j_simulate_battle.php',
|
||||
dataType: 'json',
|
||||
data: {
|
||||
action: 'reorder',
|
||||
query: JSON.stringify(data),
|
||||
}
|
||||
}).then(function (result) {
|
||||
console.log(result);
|
||||
if (!result.result) {
|
||||
alert(result.reason);
|
||||
return;
|
||||
}
|
||||
reorderDefender(result.order);
|
||||
|
||||
}, function () {
|
||||
alert('재정렬 실패!');
|
||||
});
|
||||
}
|
||||
|
||||
let initGeneralList = false;
|
||||
|
||||
$('#importFromDB').on('click', function () {
|
||||
const generalID = $('#modalSelector').val();
|
||||
console.log(generalID);
|
||||
|
||||
|
||||
$.post({
|
||||
url: 'j_export_simulator_object.php',
|
||||
dataType: 'json',
|
||||
data: {
|
||||
destGeneralID: generalID
|
||||
}
|
||||
}).then(function (data) {
|
||||
|
||||
if (!data.result) {
|
||||
alert(data.reason);
|
||||
return false;
|
||||
}
|
||||
|
||||
const $modal = $('#importModal');
|
||||
const $card = $modal.data('target');
|
||||
importGeneralInfo($card, data.general);
|
||||
|
||||
if(modalImport){
|
||||
modalImport.hide();
|
||||
}
|
||||
}, errUnknown);
|
||||
|
||||
|
||||
});
|
||||
|
||||
unwrap(document.querySelector('#importModal')).addEventListener('show.bs.modal', function () {
|
||||
if (!initGeneralList) {
|
||||
const $list = $('#modalSelector');
|
||||
|
||||
const addNation = function (generalList: GeneralInfo[], nationName: string, color: string) {
|
||||
|
||||
generalList.sort(function (lhs, rhs) {
|
||||
if (lhs.npc != rhs.npc) {
|
||||
return (lhs.npc ?? 0) - (rhs.npc ?? 0);
|
||||
}
|
||||
if (lhs.name < rhs.name) {
|
||||
return -1;
|
||||
}
|
||||
if (lhs.name > rhs.name) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
})
|
||||
const $optGroup = $(`<optgroup label="${nationName}"></optgroup>`);
|
||||
$optGroup.css('background-color', color);
|
||||
$optGroup.css('color', isBrightColor(color) ? 'black' : 'white');
|
||||
|
||||
for (const general of generalList) {
|
||||
const $item = $(`<option value="${general.no}">${general.name}</option>`);
|
||||
if (general.npc) {
|
||||
$item.css('color', unwrap(getNPCColor(general.npc)));
|
||||
} else {
|
||||
$item.css('color', 'white');
|
||||
}
|
||||
$item.css('background-color', 'black');
|
||||
$optGroup.append($item);
|
||||
}
|
||||
$list.append($optGroup);
|
||||
}
|
||||
$.post({
|
||||
url: 'j_get_basic_general_list.php',
|
||||
dataType: 'json',
|
||||
data: {
|
||||
req: 2,
|
||||
}
|
||||
}).then(function (data: BasicGeneralListResponse | InvalidResponse) {
|
||||
if (!data.result) {
|
||||
alert(data.reason);
|
||||
if(modalImport){
|
||||
modalImport.hide();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const nations = data.nation;
|
||||
const myNationID = data.nationID;
|
||||
|
||||
$list.empty();
|
||||
//자국 먼저
|
||||
|
||||
if (0 in data.list) {
|
||||
nations[0] = {
|
||||
nation: 0,
|
||||
name: '재야',
|
||||
color: '#000000'
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
addNation(combineArray(data.list[myNationID], data.column) as GeneralInfo[], nations[myNationID].name, nations[myNationID].color);
|
||||
|
||||
for (const nationID of Object.keys(data.list)) {
|
||||
if (parseInt(nationID) == myNationID) {
|
||||
continue;
|
||||
}
|
||||
addNation(combineArray(data.list[nationID], data.column) as GeneralInfo[], nations[nationID].name, nations[nationID].color);
|
||||
}
|
||||
initGeneralList = true;
|
||||
}, errUnknown);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
initBasicEvent();
|
||||
$attackerCard.append($generalForm.clone(true, true));
|
||||
addDefender();
|
||||
|
||||
$('.btn-begin_battle').on('click', function () {
|
||||
beginBattle();
|
||||
});
|
||||
|
||||
$('.btn-reorder_defender').on('click', function () {
|
||||
requestReorderDefender();
|
||||
})
|
||||
});
|
||||
$(".btn-reorder_defender").on("click", function () {
|
||||
requestReorderDefender();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
{
|
||||
"ingame": {
|
||||
"troop": "troop.ts",
|
||||
"map": "map.ts",
|
||||
"install_db": "install_db.ts",
|
||||
"install": "install.ts",
|
||||
|
||||
@@ -225,6 +225,8 @@
|
||||
<i class="bi bi-clipboard-fill" /> 붙여넣기
|
||||
</BDropdownItem>
|
||||
<BDropdownDivider />
|
||||
<BDropdownItem @click="clipboardTextCopy"> <i class="bi bi-files" /> 텍스트 복사 </BDropdownItem>
|
||||
<BDropdownDivider />
|
||||
<BDropdownItem @click="setStoredActions">
|
||||
<i class="bi bi-bookmark-plus-fill" /> 보관하기
|
||||
</BDropdownItem>
|
||||
@@ -621,6 +623,37 @@ async function clipboardPaste(releaseSelect = true) {
|
||||
return result;
|
||||
}
|
||||
|
||||
const removeTagRegEx = /<[^>]*>?/g;
|
||||
|
||||
function clipboardTextCopy(releaseSelect = true) {
|
||||
const rawActions = queryActionHelper.extractQueryActions();
|
||||
if (rawActions.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const actions = queryActionHelper.amplifyQueryActions(rawActions, queryActionHelper.getSelectedTurnList());
|
||||
if (actions.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const turnBriefs: [number, string][] = [];
|
||||
for (const action of actions) {
|
||||
const [turnIdxList, turnObj] = action;
|
||||
for (const turnIdx of turnIdxList) {
|
||||
turnBriefs.push([turnIdx, `${turnIdx + 1}턴 ${turnObj.brief.replace(removeTagRegEx, "")}`]);
|
||||
}
|
||||
}
|
||||
turnBriefs.sort((a, b) => a[0] - b[0]);
|
||||
|
||||
const text = turnBriefs.map(([, brief]) => brief).join("\n");
|
||||
void navigator.clipboard.writeText(text);
|
||||
|
||||
if (releaseSelect) {
|
||||
queryActionHelper.releaseSelectedTurnList();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async function subRepeatCommand(releaseSelect = true): Promise<boolean> {
|
||||
const reqTurnList = queryActionHelper.getSelectedTurnList();
|
||||
const selectedMinTurnIdx = reqTurnList[0];
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
export type MsgType = "private" | "public" | "national" | "diplomacy";
|
||||
|
||||
export const minMsgSeq: Record<MsgType, number> = {
|
||||
private: 0x7fffffff,
|
||||
public: 0x7fffffff,
|
||||
national: 0x7fffffff,
|
||||
diplomacy: 0x7fffffff,
|
||||
};
|
||||
|
||||
export type MsgTarget = {
|
||||
id: number;
|
||||
name: string;
|
||||
nation_id: number; //XXX: 왜 이 값은 nationID가 아니고 nation_id인가?
|
||||
nation: string;
|
||||
color: string;
|
||||
icon: string;
|
||||
};
|
||||
|
||||
export type MsgItem = {
|
||||
id: number;
|
||||
msgType: MsgType;
|
||||
src: MsgTarget;
|
||||
dest?: MsgTarget;
|
||||
text: string;
|
||||
option: Record<string, string | number>;
|
||||
time: string;
|
||||
};
|
||||
|
||||
export type MsgPrintItem = MsgItem & {
|
||||
generalName: string;
|
||||
nationID: number;
|
||||
nationType: "local" | "src" | "dest";
|
||||
myGeneralID: number;
|
||||
allowButton: boolean;
|
||||
last5min: string;
|
||||
now: string;
|
||||
invalidType: "msg_invalid" | "msg_valid";
|
||||
deletable: boolean;
|
||||
src: MsgTarget & { colorType: "bright" | "dark" };
|
||||
dest: MsgTarget & { colorType: "bright" | "dark" };
|
||||
defaultIcon: string;
|
||||
};
|
||||
|
||||
export type MsgResponse = {
|
||||
[v in MsgType]: MsgItem[];
|
||||
} & {
|
||||
result: true;
|
||||
keepRecent: boolean;
|
||||
nationID: number;
|
||||
generalName: string;
|
||||
sequence: number;
|
||||
};
|
||||
|
||||
export type MailboxItem = {
|
||||
id: number,
|
||||
mailbox: number,
|
||||
color: string,
|
||||
name: string,
|
||||
nationID: number,
|
||||
//nation: string,
|
||||
general: [number, string, number][]
|
||||
}
|
||||
|
||||
export type MabilboxListResponse = {
|
||||
result: true,
|
||||
nation: MailboxItem[]
|
||||
}
|
||||
@@ -98,7 +98,7 @@ type ReservedGameInfo = {
|
||||
scenarioName: string,
|
||||
turnterm: number,
|
||||
fictionMode: '가상' | '사실',
|
||||
block_general_create: boolean,
|
||||
block_general_create: number,
|
||||
npcMode: '불가' | '가능' | '선택 생성',
|
||||
openDatetime: string,
|
||||
starttime: string,
|
||||
@@ -119,7 +119,7 @@ type GameInfo = {
|
||||
turntime: string,
|
||||
join_mode: string,
|
||||
fictionMode: '가상' | '사실',
|
||||
block_general_create: boolean,
|
||||
block_general_create: number,
|
||||
autorun_user: string,
|
||||
userCnt: number,
|
||||
npcCnt: number,
|
||||
@@ -271,7 +271,7 @@ async function Entrance_drawServerList(serverInfos: ServerResponseItem[]) {
|
||||
$serverHtml.append(
|
||||
TemplateEngine(serverCreateTemplate, {
|
||||
serverPath: serverPath,
|
||||
canCreate: !game.block_general_create,
|
||||
canCreate: !(game.block_general_create & 1),
|
||||
canSelectNPC: game.npcMode == '가능',
|
||||
canSelectPool: game.npcMode == '선택 생성'
|
||||
})
|
||||
|
||||
+68
-82
@@ -6,7 +6,7 @@ import axios from 'axios';
|
||||
import { convertFormData } from '@util/convertFormData';
|
||||
import { isBrightColor } from "@util/isBrightColor";
|
||||
import { unwrap } from '@util/unwrap';
|
||||
import _ from 'lodash-es';
|
||||
import _, { isError, isString } from 'lodash-es';
|
||||
import { addMinutes } from 'date-fns';
|
||||
import { parseTime } from '@util/parseTime';
|
||||
import { formatTime } from '@util/formatTime';
|
||||
@@ -15,6 +15,7 @@ import { isNotNull } from '@util/isNotNull';
|
||||
import { unwrap_any } from '@util/unwrap_any';
|
||||
import { setAxiosXMLHttpRequest } from '@util/setAxiosXMLHttpRequest';
|
||||
import { exportWindow } from '@util/exportWindow';
|
||||
import { SammoAPI } from './SammoAPI';
|
||||
|
||||
const messageTemplate = `<div
|
||||
class="msg_plate msg_plate_<%msgType%> msg_plate_<%nationType%>"
|
||||
@@ -164,37 +165,33 @@ type BasicInfoResponse = {
|
||||
let generalList: Record<number, BasicGeneralTarget> = {};
|
||||
|
||||
async function responseMessage(msgID: number, responseAct: boolean): Promise<void> {
|
||||
const response = await axios({
|
||||
url: 'j_msg_decide_opt.php',
|
||||
method: 'post',
|
||||
responseType: 'json',
|
||||
data: convertFormData({
|
||||
data: JSON.stringify({
|
||||
msgID: msgID,
|
||||
response: responseAct
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
const result: InvalidResponse = response.data;
|
||||
if (!result.result) {
|
||||
alert(result.reason);
|
||||
try{
|
||||
await SammoAPI.Message.DecideMessageResponse({msgID, response: responseAct});
|
||||
location.reload();
|
||||
}
|
||||
catch(e){
|
||||
if(isString(e)){
|
||||
alert(e);
|
||||
}
|
||||
if(isError(e)){
|
||||
alert(e.message);
|
||||
}
|
||||
console.error(e);
|
||||
}
|
||||
location.reload();
|
||||
}
|
||||
|
||||
async function deleteMessage(msgID: number): Promise<MsgResponse> {
|
||||
const response = await axios({
|
||||
url: 'j_msg_delete.php',
|
||||
method: 'post',
|
||||
responseType: 'json',
|
||||
data: convertFormData({
|
||||
msgID: msgID,
|
||||
})
|
||||
});
|
||||
const result: InvalidResponse | MsgResponse = response.data;
|
||||
if (!result.result) {
|
||||
throw result.reason;
|
||||
try{
|
||||
await SammoAPI.Message.DeleteMessage({msgID});
|
||||
}
|
||||
catch(e){
|
||||
if(isString(e)){
|
||||
alert(e);
|
||||
}
|
||||
if(isError(e)){
|
||||
alert(e.message);
|
||||
}
|
||||
console.error(e);
|
||||
}
|
||||
return await refreshMsg();
|
||||
}
|
||||
@@ -206,37 +203,34 @@ export async function refreshMsg(): Promise<MsgResponse> {
|
||||
exportWindow(refreshMsg, 'refreshMsg');
|
||||
|
||||
async function fetchRecentMsg(): Promise<MsgResponse> {
|
||||
const response = await axios({
|
||||
url: 'j_msg_get_recent.php',
|
||||
method: 'post',
|
||||
responseType: 'json',
|
||||
data: convertFormData({
|
||||
sequence: lastSequence ?? 0
|
||||
})
|
||||
});
|
||||
const result: InvalidResponse | MsgResponse = response.data;
|
||||
if (!result.result) {
|
||||
throw result.reason;
|
||||
try {
|
||||
console.log(lastSequence);
|
||||
return await SammoAPI.Message.GetRecentMessage({sequence: lastSequence ?? -1});
|
||||
}
|
||||
catch (e) {
|
||||
console.error(e);
|
||||
throw e;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
async function showOldMsg(msgType: MsgType): Promise<MsgResponse> {
|
||||
const response = await axios({
|
||||
url: 'j_msg_get_old.php',
|
||||
responseType: 'json',
|
||||
method: 'post',
|
||||
data: convertFormData({
|
||||
to: minMsgSeq[msgType],
|
||||
try{
|
||||
const response = await SammoAPI.Message.GetOldMessage({
|
||||
type: msgType,
|
||||
})
|
||||
});
|
||||
const result: InvalidResponse | MsgResponse = response.data;
|
||||
if (!result.result) {
|
||||
throw result.reason;
|
||||
to: minMsgSeq[msgType],
|
||||
});
|
||||
return redrawMsg(response, false);
|
||||
}
|
||||
catch(e){
|
||||
if(isString(e)){
|
||||
alert(e);
|
||||
}
|
||||
if(isError(e)){
|
||||
alert(e.message);
|
||||
}
|
||||
console.error(e);
|
||||
throw e;
|
||||
}
|
||||
|
||||
return redrawMsg(result, false);
|
||||
}
|
||||
|
||||
function redrawMsg(msgResponse: MsgResponse, addFront: boolean): MsgResponse {
|
||||
@@ -419,26 +413,26 @@ function redrawMsg(msgResponse: MsgResponse, addFront: boolean): MsgResponse {
|
||||
return null;
|
||||
}
|
||||
|
||||
$msg.find('.btn-delete-msg').click(function () {
|
||||
$msg.find('.btn-delete-msg').on('click', async function () {
|
||||
if (!confirm("삭제하시겠습니까?")) {
|
||||
return false;
|
||||
}
|
||||
void deleteMessage(msg.id);
|
||||
await deleteMessage(msg.id);
|
||||
});
|
||||
|
||||
$msg.find('button.prompt_yes').click(function () {
|
||||
$msg.find('button.prompt_yes').on('click', async function () {
|
||||
if (!confirm("수락하시겠습니까?")) {
|
||||
return false;
|
||||
}
|
||||
void responseMessage(msg.id, true);
|
||||
await responseMessage(msg.id, true);
|
||||
|
||||
});
|
||||
|
||||
$msg.find('button.prompt_no').click(function () {
|
||||
$msg.find('button.prompt_no').on('click', async function () {
|
||||
if (!confirm("거절하시겠습니까?")) {
|
||||
return false;
|
||||
}
|
||||
void responseMessage(msg.id, false);
|
||||
await responseMessage(msg.id, false);
|
||||
});
|
||||
|
||||
if ($existMsg.length) {
|
||||
@@ -641,30 +635,26 @@ function activateMessageForm() {
|
||||
}
|
||||
});
|
||||
|
||||
$msgSubmit.click(async function () {
|
||||
$msgSubmit.on('click', async function () {
|
||||
|
||||
const text = $.trim(unwrap_any<string>($msgInput.val()));
|
||||
$msgInput.val('').focus();
|
||||
const text = _.trim(unwrap_any<string>($msgInput.val()));
|
||||
$msgInput.val('').trigger('focus');
|
||||
|
||||
const targetMailbox = unwrap_any<string>($mailboxList.val());
|
||||
console.log(targetMailbox, text);
|
||||
|
||||
const response = await axios({
|
||||
url: 'j_msg_submit.php',
|
||||
method: 'post',
|
||||
responseType: 'json',
|
||||
data: convertFormData({
|
||||
data: JSON.stringify({
|
||||
mailbox: parseInt(targetMailbox),
|
||||
text: text
|
||||
})
|
||||
})
|
||||
})
|
||||
const result: InvalidResponse = response.data;
|
||||
if (!result.result) {
|
||||
alert(result.reason);
|
||||
try{
|
||||
await SammoAPI.Message.SendMessage({
|
||||
mailbox: parseInt(targetMailbox),
|
||||
text,
|
||||
});
|
||||
await refreshMsg();
|
||||
}
|
||||
catch(e){
|
||||
alert(e);
|
||||
await refreshMsg();
|
||||
return;
|
||||
}
|
||||
await refreshMsg();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -679,11 +669,7 @@ $(async function ($) {
|
||||
}).then((v) => registerGlobal(v.data));
|
||||
|
||||
//sender_list.json 은 서버측에선 캐시 가능한 데이터임.
|
||||
const senderListP = axios({
|
||||
url: 'j_msg_contact_list.php',
|
||||
method: 'post',
|
||||
responseType: 'json'
|
||||
}).then(v => v.data);
|
||||
const senderListP = SammoAPI.Message.GetContactList();
|
||||
|
||||
const messageListP = fetchRecentMsg();
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user