diff --git a/hwe/a_status.php b/hwe/a_status.php
index 4e5f3b35..a7178e4d 100644
--- a/hwe/a_status.php
+++ b/hwe/a_status.php
@@ -12,7 +12,7 @@ $gameStor = KVStorage::getStorage($db, 'game_env');
$connect=$db->get();
increaseRefresh("세력도", 2);
-checkTurn();
+TurnExecutionHelper::executeAllCommand();
$mapTheme = $gameStor->map_theme??'che';
diff --git a/hwe/b_battleCenter.php b/hwe/b_battleCenter.php
index 99be6501..149980d3 100644
--- a/hwe/b_battleCenter.php
+++ b/hwe/b_battleCenter.php
@@ -28,7 +28,7 @@ $connect=$db->get();
increaseRefresh("감찰부", 2);
//전투 추진을 위해 갱신
-checkTurn();
+TurnExecutionHelper::executeAllCommand();
$gameStor->resetCache();
$query = "select nation from general where no='$gen'";
diff --git a/hwe/b_betting.php b/hwe/b_betting.php
index f89ad6f5..13b40dff 100644
--- a/hwe/b_betting.php
+++ b/hwe/b_betting.php
@@ -12,7 +12,7 @@ $gameStor = KVStorage::getStorage($db, 'game_env');
$connect=$db->get();
increaseRefresh("베팅장", 1);
-checkTurn();
+TurnExecutionHelper::executeAllCommand();
$query = "select no,tournament,con,turntime,bet0+bet1+bet2+bet3+bet4+bet5+bet6+bet7+bet8+bet9+bet10+bet11+bet12+bet13+bet14+bet15 as bet from general where owner='{$userID}'";
$result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect), "");
diff --git a/hwe/b_myBossInfo.php b/hwe/b_myBossInfo.php
index da998868..2847a2bb 100644
--- a/hwe/b_myBossInfo.php
+++ b/hwe/b_myBossInfo.php
@@ -12,7 +12,7 @@ $connect=$db->get();
increaseRefresh("인사부", 1);
//훼섭 추방을 위해 갱신
-checkTurn();
+TurnExecutionHelper::executeAllCommand();
$query = "select no,nation,level from general where owner='{$userID}'";
$result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
diff --git a/hwe/b_tournament.php b/hwe/b_tournament.php
index 013c615f..1bad6b0f 100644
--- a/hwe/b_tournament.php
+++ b/hwe/b_tournament.php
@@ -12,7 +12,7 @@ $gameStor = KVStorage::getStorage($db, 'game_env');
$connect=$db->get();
increaseRefresh("토너먼트", 1);
-checkTurn();
+TurnExecutionHelper::executeAllCommand();
$query = "select no,tournament,con,turntime from general where owner='{$userID}'";
$result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect), "");
diff --git a/hwe/func.old.php b/hwe/func.old.php
new file mode 100644
index 00000000..7bffa121
--- /dev/null
+++ b/hwe/func.old.php
@@ -0,0 +1,2984 @@
+0,
+ 'name'=>'재야',
+ 'color'=>'#000000',
+ 'type'=>GameConst::$neutralNationType,
+ 'level'=>0,
+ 'capital'=>0
+ ];
+ }
+
+ if($nationList === null){
+ $nationAll = DB::db()->query("select nation, name, color, type, level, capital from nation");
+ $nationList = Util::convertArrayToDict($nationAll, "nation");
+ $nationList[-1] = $nationAll;
+ }
+
+ if(isset($nationList[$nationID])){
+ return $nationList[$nationID];
+ }
+ return null;
+}
+
+/**
+ * getNationStaticInfo() 함수의 국가 캐시를 초기화
+ */
+function refreshNationStaticInfo(){
+ getNationStaticInfo(null, true);
+}
+
+/**
+ * getNationStaticInfo(-1) 의 단축형
+ */
+function getAllNationStaticInfo(){
+ return getNationStaticInfo(-1);
+}
+
+function GetImageURL($imgsvr, $filepath='') {
+ if($imgsvr == 0) {
+ return ServConfig::getSharedIconPath($filepath);
+ } else {
+ return AppConf::getUserIconPathWeb($filepath);
+ }
+}
+
+/**
+ * @param null|int $con 장수의 벌점
+ * @param null|int $conlimit 최대 벌점
+ */
+function checkLimit($con = null) {
+ $session = Session::getInstance();
+ if($session->userGrade>=4){
+ return 0;
+ }
+
+ $db = DB::db();
+ $gameStor = KVStorage::getStorage($db, 'game_env');
+
+ if($con === null){
+ $con = $db->queryFirstField('SELECT con FROM general WHERE `owner`=%i', Session::getUserID());
+ }
+ $conlimit = $gameStor->conlimit;
+
+ if($con > $conlimit) {
+ return 2;
+ //접속제한 90%이면 경고문구
+ } elseif($con > $conlimit * 0.9) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+function getBlockLevel() {
+ return DB::db()->queryFirstField('select block from general where no = %i', Session::getInstance()->generalID);
+}
+
+function getRandGenName() {
+ $first = array('가', '간', '감', '강', '고', '공', '공손', '곽', '관', '괴', '교', '금', '노', '뇌', '능', '도', '동', '두',
+ '등', '마', '맹', '문', '미', '반', '방', '부', '비', '사', '사마', '서', '설', '성', '소', '손', '송', '순', '신', '심',
+ '악', '안', '양', '엄', '여', '염', '오', '왕', '요', '우', '원', '위', '유', '육', '윤', '이', '장', '저', '전', '정',
+ '제갈', '조', '종', '주', '진', '채', '태사', '하', '하후', '학', '한', '향', '허', '호', '화', '황',
+ '공손', '손', '왕', '유', '장', '조');
+ $last = array('가', '간', '강', '거', '건', '검', '견', '경', '공', '광', '권', '규', '녕', '단', '대', '도', '등', '람',
+ '량', '례', '로', '료', '모', '민', '박', '범', '보', '비', '사', '상', '색', '서', '소', '속', '송', '수', '순', '습',
+ '승', '양', '연', '영', '온', '옹', '완', '우', '웅', '월', '위', '유', '윤', '융', '이', '익', '임', '정', '제', '조',
+ '주', '준', '지', '찬', '책', '충', '탁', '택', '통', '패', '평', '포', '합', '해', '혁', '현', '화', '환', '회', '횡',
+ '후', '훈', '휴', '흠', '흥');
+
+ $firstname = $first[rand()%count($first)];
+ $lastname = $last[rand()%count($last)];
+
+ $fullname = "{$firstname}{$lastname}";
+ return $fullname;
+}
+
+
+
+function cityInfo() {
+ $db = DB::db();
+ $connect=$db->get();
+ $userID = Session::getUserID();
+
+ $query = "select no,city from general where owner='{$userID}'";
+ $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
+ $me = MYDB_fetch_array($result);
+
+ // 도시 정보
+ $city = getCity($me['city']);
+
+ $nation = getNationStaticInfo($city['nation']);
+
+ $pop = $city['pop'] / $city['pop2'] * 100;
+ $trust = $city['trust'];
+ $agri = $city['agri'] / $city['agri2'] * 100;
+ $comm = $city['comm'] / $city['comm2'] * 100;
+ $secu = $city['secu'] / $city['secu2'] * 100;
+ $def = $city['def'] / $city['def2'] * 100;
+ $wall = $city['wall'] / $city['wall2'] * 100;
+ if($city['trade'] == 0) {
+ $trade = 0;
+ $tradeStr = "상인없음";
+ } else {
+ $trade = ($city['trade']-95) * 10;
+ $tradeStr = $city['trade'] . "%";
+ }
+
+ if(!$nation){
+ $nation = getNationStaticInfo(0);
+ }
+
+ if($nation['color'] == "" ) { $nation['color'] = "#000000"; }
+ echo "
+ 【 ".CityConst::$regionMap[$city['region']]." | ".CityConst::$levelMap[$city['level']]." 】 {$city['name']}
+ ";
+
+ if($city['nation'] == 0) {
+ echo "공 백 지";
+ } else {
+ echo "지배 국가 【 {$nation['name']} 】";
+ }
+
+ if($city['gen1'] > 0) {
+ $query = "select name from general where no='{$city['gen1']}'";
+ $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
+ $gen1 = MYDB_fetch_array($result);
+ } else {
+ $gen1 = ['name'=>'-'];
+ }
+
+ if($city['gen2'] > 0) {
+ $query = "select name from general where no='{$city['gen2']}'";
+ $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
+ $gen2 = MYDB_fetch_array($result);
+ } else {
+ $gen2 = ['name'=>'-'];
+ }
+
+ if($city['gen3'] > 0) {
+ $query = "select name from general where no='{$city['gen3']}'";
+ $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
+ $gen3 = MYDB_fetch_array($result);
+ } else {
+ $gen3 = ['name'=>'-'];
+ }
+
+ echo "
+
+
+
+ 주민
+ ".bar($pop)."
+ 민심
+ ".bar($trust)."
+ 태수
+ {$gen1['name']}
+
+
+ {$city['pop']}/{$city['pop2']}
+ ".round($city['trust'], 1)."
+
+
+ 농업
+ ".bar($agri)."
+ 상업
+ ".bar($comm)."
+ 치안
+ ".bar($secu)."
+ 군사
+ {$gen2['name']}
+
+
+ {$city['agri']}/{$city['agri2']}
+ {$city['comm']}/{$city['comm2']}
+ {$city['secu']}/{$city['secu2']}
+
+
+ 수비
+ ".bar($def)."
+ 성벽
+ ".bar($wall)."
+ 시세
+ ".bar($trade)."
+ 시중
+ {$gen3['name']}
+
+
+ {$city['def']}/{$city['def2']}
+ {$city['wall']}/{$city['wall2']}
+ {$tradeStr}
+
+
+";
+}
+
+function myNationInfo() {
+ $db = DB::db();
+ $gameStor = KVStorage::getStorage($db, 'game_env');
+ $connect=$db->get();
+ $userID = Session::getUserID();
+
+ $admin = $gameStor->getValues(['startyear','year']);
+
+ $query = "select no,nation from general where owner='{$userID}'";
+ $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
+ $me = MYDB_fetch_array($result);
+
+ $query = "select nation,name,color,power,msg,gold,rice,bill,rate,scout,war,sabotagelimit,surlimit,tech,level,type from nation where nation='{$me['nation']}'";
+ $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
+ $nation = MYDB_fetch_array($result);
+
+ $query = "select COUNT(*) as cnt, SUM(pop) as totpop, SUM(pop2) as maxpop from city where nation='{$nation['nation']}'"; // 도시 이름 목록
+ $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
+ $city = MYDB_fetch_array($result);
+
+ $query = "select COUNT(*) as cnt, SUM(crew) as totcrew,SUM(leader)*100 as maxcrew from general where nation='{$nation['nation']}'"; // 장수 목록
+ $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
+ $general = MYDB_fetch_array($result);
+
+ $query = "select name from general where nation='{$nation['nation']}' and level='12'";
+ $genresult = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
+ $level12 = MYDB_fetch_array($genresult);
+
+ $query = "select name from general where nation='{$nation['nation']}' and level='11'";
+ $genresult = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
+ $level11 = MYDB_fetch_array($genresult);
+
+ echo "
+
+ 【재 야】"; }
+ else { echo "style='color:".newColor($nation['color']).";background-color:{$nation['color']};font-weight:bold;font-size:13px;text-align:center'>국가【 {$nation['name']} 】"; }
+
+ echo "
+
+
+
+ 성 향
+ ".getNationType($nation['type'])." (".getNationType2($nation['type']).")
+
+
+
+ ".getLevel(12, $nation['level'])."
+ ";echo $level12?$level12['name']:"-"; echo "
+ ".getLevel(11, $nation['level'])."
+ ";echo $level11?$level11['name']:"-"; echo "
+
+
+ 총주민
+ ";echo $me['nation']==0?"해당 없음":"{$city['totpop']}/{$city['maxpop']}";echo "
+ 총병사
+ ";echo $me['nation']==0?"해당 없음":"{$general['totcrew']}/{$general['maxcrew']}"; echo "
+
+
+
+ 국 고
+ ";echo $me['nation']==0?"해당 없음":"{$nation['gold']}";echo "
+ 병 량
+ ";echo $me['nation']==0?"해당 없음":"{$nation['rice']}";echo "
+
+
+ 지급율
+ ";
+ if($me['nation'] == 0) {
+ echo "해당 없음";
+ } else {
+ echo $nation['bill']==0?"0 %":"{$nation['bill']} %";
+ }
+ echo "
+
+ 세 율
+ ";
+ if($me['nation'] == 0) {
+ echo "해당 없음";
+ } else {
+ echo $nation['rate']==0?"0 %":"{$nation['rate']} %";
+ }
+
+ $techCall = getTechCall($nation['tech']);
+
+ if(TechLimit($admin['startyear'], $admin['year'], $nation['tech'])) { $nation['tech'] = "".floor($nation['tech'])." "; }
+ else { $nation['tech'] = "".floor($nation['tech'])." "; }
+
+ $nation['tech'] = "$techCall / {$nation['tech']}";
+
+ if($me['nation']==0){
+ $nation['sabotagelimit'] = "해당 없음 ";
+ $nation['surlimit'] = "해당 없음 ";
+ $nation['scout'] = "해당 없음 ";
+ $nation['war'] = "해당 없음 ";
+ $nation['power'] = "해당 없음 ";
+ } else {
+ if($nation['sabotagelimit'] != 0) { $nation['sabotagelimit'] = "{$nation['sabotagelimit']}턴 "; }
+ else { $nation['sabotagelimit'] = "가 능 "; }
+
+ if($nation['surlimit'] != 0) { $nation['surlimit'] = "{$nation['surlimit']}턴 "; }
+ else { $nation['surlimit'] = "가 능 "; }
+
+ if($nation['scout'] != 0) { $nation['scout'] = "금 지 "; }
+ else { $nation['scout'] = "허 가 "; }
+
+ if($nation['war'] != 0) { $nation['war'] = "금 지 "; }
+ else { $nation['war'] = "허 가 "; }
+
+
+ }
+
+ echo "
+
+
+
+ 속 령
+ ";echo $me['nation']==0?"-":"{$city['cnt']}"; echo "
+ 장 수
+ ";echo $me['nation']==0?"-":"{$general['cnt']}"; echo "
+
+
+ 국 력
+ {$nation['power']}
+ 기술력
+ ";echo $me['nation']==0?"-":"{$nation['tech']}"; echo "
+
+
+ 전 략
+ {$nation['sabotagelimit']}
+ 외 교
+ {$nation['surlimit']}
+
+
+ 임 관
+ {$nation['scout']}
+ 전 쟁
+ {$nation['war']}
+
+
+";
+}
+
+function addCommand($typename, $value, $valid = 1, $color=0) {
+ if($valid == 1) {
+ switch($color) {
+ case 0:
+ echo "
+ {$typename} ";
+ break;
+ case 1:
+ echo "
+ {$typename} ";
+ break;
+ case 2:
+ echo "
+ {$typename} ";
+ break;
+ }
+ } else {
+ echo "
+ {$typename}(불가) ";
+ }
+}
+
+function commandGroup($typename, $type=0) {
+ if($type == 0) {
+ echo "
+ ";
+ } else {
+ echo "
+ ";
+ }
+}
+
+function commandTable() {
+ $db = DB::db();
+ $gameStor = KVStorage::getStorage($db, 'game_env');
+ $connect=$db->get();
+ $userID = Session::getUserID();
+
+ $admin = $gameStor->getValues(['startyear', 'year', 'month', 'develcost', 'scenario']);
+
+ $query = "select no,npc,troop,city,nation,level,crew,makelimit,special from general where owner='{$userID}'";
+ $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
+ $me = MYDB_fetch_array($result);
+
+ $troop = getTroop($me['troop']);
+ $city = getCity($me['city']);
+
+ $nationcount = count(getAllNationStaticInfo());
+
+ $query = "select city from city where nation='{$me['nation']}'";
+ $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
+ $citycount = MYDB_num_rows($result);
+
+ $query = "select no from general where nation='{$me['nation']}'";
+ $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
+ $gencount = MYDB_num_rows($result);
+
+ $nation = getNationStaticInfo($me['nation']);
+
+ $develcost = $admin['develcost'];
+ $develcostA = $admin['develcost']; $colorA = 0;
+ $develcostB = $admin['develcost']; $colorB = 0;
+ $develcostC = $admin['develcost']; $colorC = 0;
+ $develcostD = $admin['develcost']; $colorD = 0;
+ $develcostE = $admin['develcost']*2; $colorE = 0;
+ $develcost3 = $admin['develcost']*3;
+ $develcost5 = $admin['develcost']*5;
+
+ // 농상 국가보정
+ if($nation['type'] == 2 || $nation['type'] == 12) { $develcostA *= 0.8; $colorA = 1; }
+ if($nation['type'] == 8 || $nation['type'] == 11) { $develcostA *= 1.2; $colorA = 2; }
+ // 기술 국가보정
+ if($nation['type'] == 3 || $nation['type'] == 13) { $develcostB *= 0.8; $colorB = 1; }
+ if($nation['type'] == 5 || $nation['type'] == 6 || $nation['type'] == 7 || $nation['type'] == 8 || $nation['type'] == 12) { $develcostB *= 1.2; $colorB = 2; }
+ // 수성 국가보정
+ if($nation['type'] == 3 || $nation['type'] == 5 || $nation['type'] == 10 || $nation['type'] == 11) { $develcostC *= 0.8; $colorC = 1; }
+ if($nation['type'] == 4 || $nation['type'] == 7 || $nation['type'] == 8 || $nation['type'] == 13) { $develcostC *= 1.2; $colorC = 2; }
+ // 치안 국가보정
+ if($nation['type'] == 1 || $nation['type'] == 4) { $develcostD *= 0.8; $colorD = 1; }
+ if($nation['type'] == 6 || $nation['type'] == 9) { $develcostD *= 1.2; $colorD = 2; }
+ // 민심,정착장려 국가보정
+ if($nation['type'] == 2 || $nation['type'] == 4 || $nation['type'] == 7 || $nation['type'] == 10) { $develcostE *= 0.8; $colorE = 1; }
+ if($nation['type'] == 1 || $nation['type'] == 3 || $nation['type'] == 9) { $develcostE *= 1.2; $colorE = 2; }
+
+ $develcostA = Util::round($develcostA);
+ $develcostB = Util::round($develcostB);
+ $develcostC = Util::round($develcostC);
+ $develcostD = Util::round($develcostD);
+ $develcostE = Util::round($develcostE);
+
+ echo "
+";
+ addCommand("휴 식", 0);
+ addCommand("요 양", 50);
+ commandGroup("========= 내 정 ==========");
+ if($me['level'] >= 1 && ($citycount != 0 || $admin['year'] >= $admin['startyear']+3) && $city['supply'] != 0) {
+ addCommand("농지개간(지력경험, 자금$develcostA)", 1, 1, $colorA);
+ addCommand("상업투자(지력경험, 자금$develcostA)", 2, 1, $colorA);
+ addCommand("기술연구(지력경험, 자금$develcostB)", 3, 1, $colorB);
+ addCommand("수비강화(무력경험, 자금$develcostC)", 5, 1, $colorC);
+ addCommand("성벽보수(무력경험, 자금$develcostC)", 6, 1, $colorC);
+ addCommand("치안강화(무력경험, 자금$develcostD)", 8, 1, $colorD);
+ addCommand("정착장려(통솔경험, 군량$develcostE)", 7, 1, $colorE);
+ addCommand("주민선정(통솔경험, 군량$develcostE)", 4, 1, $colorE);
+ } else {
+ addCommand("농지개간(지력경험, 자금$develcostA)", 1, 0);
+ addCommand("상업투자(지력경험, 자금$develcostA)", 2, 0);
+ addCommand("기술연구(지력경험, 자금$develcostB)", 3, 0);
+ addCommand("수비강화(무력경험, 자금$develcostC)", 5, 0);
+ addCommand("성벽보수(무력경험, 자금$develcostC)", 6, 0);
+ addCommand("치안강화(무력경험, 자금$develcostD)", 8, 0);
+ addCommand("정착장려(통솔경험, 군량$develcostE)", 7, 0);
+ addCommand("주민선정(통솔경험, 군량$develcostE)", 4, 0);
+ }
+ if($me['level'] >= 1 && (($nation['level'] > 0 && $city['nation'] == $me['nation'] && $city['supply'] != 0) || $nation['level'] == 0)) {
+ addCommand("물자조달(랜덤경험)", 9, 1);
+ } else {
+ addCommand("물자조달(랜덤경험)", 9, 0);
+ }
+ commandGroup("", 1);
+ commandGroup("========= 군 사 ==========");
+ if($me['level'] >= 1 && $citycount > 0) {
+ addCommand("첩보(통솔경험, 자금$develcost3, 군량$develcost3)", 31);
+ addCommand("징병(통솔경험)", 11);
+ addCommand("모병(통솔경험, 자금x2)", 12);
+ addCommand("훈련(통솔경험)", 13);
+ addCommand("사기진작(통솔경험, 자금↓)", 14);
+ //addCommand("전투태세/3턴(통솔경험, 자금↓)", 15);
+ addCommand("출병", 16);
+ } else {
+ addCommand("첩보(통솔경험, 자금$develcost3, 군량$develcost3)", 31, 0);
+ addCommand("징병(통솔경험)", 11, 0);
+ addCommand("모병(통솔경험, 자금x2)", 12, 0);
+ addCommand("훈련(통솔경험)", 13, 0);
+ addCommand("사기진작(통솔경험, 자금↓)", 14, 0);
+ //addCommand("전투태세/3턴(통솔경험, 자금↓)", 15, 0);
+ addCommand("출병", 16, 0);
+ }
+ if($me['crew'] > 0) {
+ addCommand("소집해제(병사↓, 주민↑)", 17);
+ } else {
+ addCommand("소집해제(병사↓, 주민↑)", 17, 0);
+ }
+
+ commandGroup("", 1);
+ commandGroup("========= 인 사 ==========");
+ addCommand("이동(통솔경험, 자금$develcost, 사기↓)", 21);
+ addCommand("강행(통솔경험, 자금$develcost5, 병력/사기/훈련↓)", 30);
+
+ if($nation['level'] > 0 && $me['level'] >= 1) {
+ addCommand("인재탐색(랜덤경험, 자금$develcost)", 29);
+ } else {
+ addCommand("인재탐색(랜덤경험, 자금$develcost)", 29, 0);
+ }
+
+ if($me['level'] >= 1 && $city['supply'] != 0) {
+ addCommand("등용(자금{$develcost5}+장수가치)", 22);
+ } else {
+ addCommand("등용(자금{$develcost5}+장수가치)", 22, 0);
+ }
+
+ if($me['no'] == $troop['no'] && $citycount > 0 && $city['supply'] != 0 && $city['nation'] == $me['nation']) {
+ addCommand("집합(통솔경험)", 26);
+ } else {
+ addCommand("집합(통솔경험)", 26, 0);
+ }
+ if($me['level'] >= 1 && $me['level'] <= 12 && $nation['level'] > 0) {
+ addCommand("귀환(통솔경험)", 28);
+ } else {
+ addCommand("귀환(통솔경험)", 28, 0);
+ }
+ if($me['level'] == 0 && $nationcount != 0 && $me['makelimit'] == 0) {
+ addCommand("임관", 25);
+ } else {
+ addCommand("임관", 25, 0);
+ }
+ commandGroup("", 1);
+ commandGroup("========= 계 략 ==========");
+ if($me['level'] >= 1 && (($nation['level'] > 0 && $city['nation'] == $me['nation'] && $city['supply'] != 0) || $nation['level'] == 0)) {
+ addCommand("화계(지력경험, 자금$develcost5, 군량$develcost5)", 32);
+ addCommand("탈취(무력경험, 자금$develcost5, 군량$develcost5)", 33);
+ addCommand("파괴(무력경험, 자금$develcost5, 군량$develcost5)", 34);
+ addCommand("선동(통솔경험, 자금$develcost5, 군량$develcost5)", 35);
+ } else {
+ addCommand("화계(지력경험, 자금$develcost5, 군량$develcost5)", 32, 0);
+ addCommand("탈취(무력경험, 자금$develcost5, 군량$develcost5)", 33, 0);
+ addCommand("파괴(무력경험, 자금$develcost5, 군량$develcost5)", 34, 0);
+ addCommand("선동(통솔경험, 자금$develcost5, 군량$develcost5)", 35, 0);
+ }
+ commandGroup("", 1);
+ commandGroup("========= 개 인 ==========");
+ if($me['level'] >= 1) {
+ addCommand("단련(자금$develcost, 군량$develcost)", 41);
+ } else {
+ addCommand("단련(자금$develcost, 군량$develcost)", 41, 0);
+ }
+ addCommand("견문(자금?, 군량?, 경험치?)", 42);
+ if($city['trade'] > 0) {
+ addCommand("장비매매", 48);
+ addCommand("군량매매", 49);
+ } else {
+ addCommand("장비매매", 48, 0);
+ addCommand("군량매매", 49, 0);
+ }
+ if($city['supply'] != 0 && $city['nation'] == $me['nation']) {
+ addCommand("증여(통솔경험)", 43);
+ } else {
+ addCommand("증여(통솔경험)", 43, 0);
+ }
+
+ if($me['level'] >= 1 && $city['supply'] != 0 && $city['nation'] == $me['nation']) {
+ addCommand("헌납(통솔경험)", 44);
+ } else {
+ addCommand("헌납(통솔경험)", 44, 0);
+ }
+ if($me['npc'] == 0) {
+ if($me['level'] >= 1 && $me['level'] < 12) {
+ addCommand("하야", 45);
+ } else {
+ addCommand("하야", 45, 0);
+ }
+ }
+ if($me['level'] == 0) {
+ addCommand("거병", 55);
+ } else {
+ addCommand("거병", 55, 0);
+ }
+ if($me['level'] == 12 &&
+ ($city['level'] == 5 || $city['level'] == 6) &&
+ $city['nation'] == 0 &&
+ $me['makelimit'] == 0 &&
+ $gencount >= 2 &&
+ $citycount == 0 &&
+ $admin['year'] < $admin['startyear']+2
+ ) {
+ addCommand("건국", 46);
+ } else {
+ addCommand("건국", 46, 0);
+ }
+ if($me['level'] == 12) {
+ addCommand("선양", 54);
+ if($citycount != 0) {
+ if ($admin['year'] + 3 < $admin['startyear']) {
+ addCommand("방랑", 47, 0);
+ }
+ else{
+ addCommand("방랑", 47);
+ }
+
+ addCommand("해산", 56, 0);
+ } else {
+ addCommand("방랑", 47, 0);
+ addCommand("해산", 56);
+ }
+ } else {
+ addCommand("선양", 54, 0);
+ addCommand("방랑", 47, 0);
+ addCommand("해산", 56, 0);
+ }
+ if($me['level'] > 1 && $me['level'] < 12) {
+ addCommand("모반시도", 57);
+ } else {
+ addCommand("모반시도", 57, 0);
+ }
+ commandGroup("", 1);
+
+ echo "
+
+";
+}
+
+function CoreCommandTable() {
+ $db = DB::db();
+ $gameStor = KVStorage::getStorage($db, 'game_env');
+ $connect=$db->get();
+ $userID = Session::getUserID();
+
+ $develcost = $gameStor->develcost;
+
+ $query = "select no,nation,city,level from general where owner='{$userID}'";
+ $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
+ $me = MYDB_fetch_array($result);
+
+ $query = "select level,can_change_flag from nation where nation='{$me['nation']}'";
+ $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
+ $nation = MYDB_fetch_array($result);
+
+ $query = "select no from general where nation='{$me['nation']}'";
+ $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
+ $genCount = MYDB_num_rows($result);
+
+ $query = "select supply from city where city='{$me['city']}'";
+ $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
+ $city = MYDB_fetch_array($result);
+
+ if($nation['level'] > 0) { $valid = 1; }
+ else { $valid = 0; }
+ if($city['supply'] == 0) { $valid = 0; }
+
+ echo "
+";
+ commandGroup("====== 휴 식 ======");
+ addCommand("휴 식", 99);
+ commandGroup("", 1);
+ commandGroup("====== 인 사 ======");
+ addCommand("발령", 27, $valid);
+ addCommand("포상", 23, $valid);
+ addCommand("몰수", 24, $valid);
+ commandGroup("", 1);
+ commandGroup("====== 외 교 ======");
+ addCommand("통합 제의", 53, $valid);
+
+ addCommand("항복 권고", 51, $valid);
+ if($nation['level'] >= 2) {
+ addCommand("물자 원조", 52, $valid);
+ } else {
+ addCommand("물자 원조", 52, 0);
+ }
+ addCommand("불가침 제의", 61, $valid);
+ addCommand("선전 포고", 62, $valid);
+ addCommand("종전 제의", 63, $valid);
+ addCommand("파기 제의", 64, $valid);
+ commandGroup("", 1);
+ commandGroup("====== 특 수 ======");
+ addCommand("초토화", 65, $valid);
+ addCommand("천도/3턴(금쌀{$develcost}0)", 66, $valid);
+ $cost = $develcost * 500 + 60000; // 7만~13만
+ addCommand("증축/6턴(금쌀{$cost})", 67, $valid);
+ addCommand("감축/6턴", 68, $valid);
+ commandGroup("", 1);
+ commandGroup("====== 전 략 ======");
+ $term = Util::round(sqrt($genCount*8)*10);
+ addCommand("필사즉생/3턴(전략{$term})", 71, $valid);
+ $term = Util::round(sqrt($genCount*4)*10);
+ addCommand("백성동원/1턴(전략{$term})", 72, $valid);
+ $term = Util::round(sqrt($genCount*4)*10);
+ addCommand("수몰/3턴(전략{$term})", 73, $valid);
+ $term = Util::round(sqrt($genCount*4)*10);
+ addCommand("허보/2턴(전략{$term})", 74, $valid);
+ $term = Util::round(sqrt($genCount*2)*10);
+ if($term < 72) { $term = 72; }
+ addCommand("피장파장/3턴(전략{$term})", 75, $valid);
+ $term = Util::round(sqrt($genCount*10)*10);
+ addCommand("의병모집/3턴(전략{$term})", 76, $valid);
+ $term = Util::round(sqrt($genCount*16)*10);
+ addCommand("이호경식/1턴(전략{$term})", 77, $valid);
+ $term = Util::round(sqrt($genCount*16)*10);
+ addCommand("급습/1턴(전략{$term})", 78, $valid);
+ commandGroup("", 1);
+ commandGroup("====== 기 타 ======");
+ if($nation['can_change_flag'] > 0) {
+ addCommand("국기 변경", 81, 1);
+ } else {
+ addCommand("국기 변경", 81, 0);
+ }
+ commandGroup("", 1);
+ echo "
+
+";
+}
+
+function myInfo() {
+ $db = DB::db();
+ $connect=$db->get();
+ $userID = Session::getUserID();
+
+ $query = "select no from general where owner='{$userID}'";
+ $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
+ $me = MYDB_fetch_array($result);
+
+ generalInfo($me['no']);
+}
+
+function generalInfo($no) {
+ $db = DB::db();
+ $gameStor = KVStorage::getStorage($db, 'game_env');
+ $connect=$db->get();
+
+ $show_img_level = $gameStor->show_img_level;
+
+ $query = "select block,no,name,picture,imgsvr,injury,nation,city,troop,leader,leader2,power,power2,intel,intel2,explevel,experience,level,gold,rice,crew,crewtype,train,atmos,weap,book,horse,item,turntime,killturn,age,personal,special,specage,special2,specage2,mode,con,connect from general where no='$no'";
+ $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
+ $general = MYDB_fetch_array($result);
+
+ $nation = getNationStaticInfo($general['nation']);
+
+ if($general['level'] == 12) {
+ $lbonus = $nation['level'] * 2;
+ } elseif($general['level'] >= 5) {
+ $lbonus = $nation['level'];
+ } else {
+ $lbonus = 0;
+ }
+ if($lbonus > 0) {
+ $lbonus = "+{$lbonus} ";
+ } else {
+ $lbonus = "";
+ }
+
+ $troop = getTroop($general['troop']);
+
+ $level = getLevel($general['level'], $nation['level']);
+ if($general['level'] == 2) {
+ $query = "select name from city where gen3='{$general['no']}'";
+ $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
+ $city = MYDB_fetch_array($result);
+ $level = $city['name']." ".$level;
+ } elseif($general['level'] == 3) {
+ $query = "select name from city where gen2='{$general['no']}'";
+ $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
+ $city = MYDB_fetch_array($result);
+ $level = $city['name']." ".$level;
+ } elseif($general['level'] == 4) {
+ $query = "select name from city where gen1='{$general['no']}'";
+ $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
+ $city = MYDB_fetch_array($result);
+ $level = $city['name']." ".$level;
+ }
+ $call = getCall($general['leader'], $general['power'], $general['intel']);
+ $typename = GameUnitConst::byId($general['crewtype'])->name;
+ $weapname = getWeapName($general['weap']);
+ $bookname = getBookName($general['book']);
+ $horsename = getHorseName($general['horse']);
+ $itemname = displayItemInfo($general['item']);
+ if($general['injury'] > 0) {
+ $leader = intdiv($general['leader'] * (100 - $general['injury']), 100);
+ $power = intdiv($general['power'] * (100 - $general['injury']), 100);
+ $intel = intdiv($general['intel'] * (100 - $general['injury']), 100);
+ } else {
+ $leader = $general['leader'];
+ $power = $general['power'];
+ $intel = $general['intel'];
+ }
+ if($general['injury'] > 60) { $color = ""; $injury = "위독"; }
+ elseif($general['injury'] > 40) { $color = ""; $injury = "심각"; }
+ elseif($general['injury'] > 20) { $color = ""; $injury = "중상"; }
+ elseif($general['injury'] > 0) { $color = ""; $injury = "경상"; }
+ else { $color = ""; $injury = "건강"; }
+
+ $remaining = substr($general['turntime'], 14, 2) - date('i');
+ if($remaining < 0) { $remaining = 60 + $remaining; }
+
+ if($nation['color'] == "") { $nation['color'] = "#000000"; }
+
+ if($general['age'] < 60) { $general['age'] = "{$general['age']} 세 "; }
+ elseif($general['age'] < 80) { $general['age'] = "{$general['age']} 세 "; }
+ else { $general['age'] = "{$general['age']} 세 "; }
+
+ $general['connect'] = Util::round($general['connect'] / 10) * 10;
+ $special = $general['special'] == GameConst::$defaultSpecial ? "{$general['specage']}세" : "".displaySpecialDomesticInfo($general['special'])." ";
+ $special2 = $general['special2'] == 0 ? "{$general['specage2']}세" : "".displaySpecialWarInfo($general['special2'])." ";
+
+ switch($general['personal']) {
+ case 2: case 4:
+ $atmos = "{$general['atmos']} (+5) "; break;
+ case 0: case 9: case 10:
+ $atmos = "{$general['atmos']} (-5) "; break;
+ default:
+ $atmos = "{$general['atmos']}"; break;
+ }
+ switch($general['personal']) {
+ case 3: case 5:
+ $train = "{$general['train']} (+5) "; break;
+ case 1: case 8: case 10:
+ $train = "{$general['train']} (-5) "; break;
+ default:
+ $train = "{$general['train']}"; break;
+ }
+ if($general['troop'] == 0) { $troop['name'] = "-"; }
+ if($general['mode'] == 2) { $general['mode'] = "수비 함(훈사80) "; }
+ elseif($general['mode'] == 1) { $general['mode'] = "수비 함(훈사60) "; }
+ else { $general['mode'] = "수비 안함 "; }
+
+ $weapImage = ServConfig::$gameImagePath."/weap{$general['crewtype']}.png";
+ if($show_img_level < 2) { $weapImage = ServConfig::$sharedIconPath."/default.jpg"; };
+ $imageTemp = GetImageURL($general['imgsvr']);
+ echo "
+
+
+ {$general['name']} 【 {$level} | {$call} | {$color}{$injury} 】 ".substr($general['turntime'], 11)."
+
+
+ 통솔
+ {$color}{$leader}{$lbonus}
+ ".bar(expStatus($general['leader2']), 20)."
+ 무력
+ {$color}{$power}
+ ".bar(expStatus($general['power2']), 20)."
+ 지력
+ {$color}{$intel}
+ ".bar(expStatus($general['intel2']), 20)."
+
+
+ 명마
+ $horsename
+ 무기
+ $weapname
+ 서적
+ $bookname
+
+
+
+ 자금
+ {$general['gold']}
+ 군량
+ {$general['rice']}
+ 도구
+ $itemname
+
+
+ 병종
+ $typename
+ 병사
+ {$general['crew']}
+ 성격
+ ".displayCharInfo($general['personal'])."
+
+
+ 훈련
+ $train
+ 사기
+ $atmos
+ 특기
+ $special / $special2
+
+
+ Lv
+ {$general['explevel']}
+ ".bar(getLevelPer($general['experience'], $general['explevel']), 20)."
+ 연령
+ {$general['age']}
+
+
+ 수비
+ {$general['mode']}
+ 삭턴
+ {$general['killturn']} 턴
+ 실행
+ $remaining 분 남음
+
+
+ 부대
+ {$troop['name']}
+ 벌점
+ ".getConnect($general['connect'])." {$general['connect']}({$general['con']})
+
+
";
+}
+
+function myInfo2() {
+ $db = DB::db();
+ $connect=$db->get();
+ $userID = Session::getUserID();
+
+ $query = "select no from general where owner='{$userID}'";
+ $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
+ $me = MYDB_fetch_array($result);
+
+ generalInfo2($me['no']);
+}
+
+function generalInfo2($no) {
+ $db = DB::db();
+ $connect=$db->get();
+
+ $query = "select personal,experience,dedication,firenum,warnum,killnum,deathnum,killcrew,deathcrew,belong,killnum*100/warnum as winrate,killcrew/deathcrew*100 as killrate,dex0,dex10,dex20,dex30,dex40 from general where no='$no'";
+ $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
+ $general = MYDB_fetch_array($result);
+
+ $general['winrate'] = round($general['winrate'], 2);
+ $general['killrate'] = round($general['killrate'], 2);
+
+ switch($general['personal']) {
+ case 0: case 1; case 6:
+ $experience = "".getHonor($general['experience'])." ({$general['experience']}) "; break;
+ case 4: case 5: case 7: case 10:
+ $experience = "".getHonor($general['experience'])." ({$general['experience']}) "; break;
+ default:
+ $experience = getHonor($general['experience'])." ({$general['experience']})"; break;
+ }
+ switch($general['personal']) {
+ case 10:
+ $dedication = "".getDed($general['dedication'])." ({$general['dedication']}) "; break;
+ default:
+ $dedication = getDed($general['dedication'])." ({$general['dedication']})"; break;
+ }
+
+ $dex0 = $general['dex0'] / GameConst::$dexLimit * 100;
+ $dex10 = $general['dex10'] / GameConst::$dexLimit * 100;
+ $dex20 = $general['dex20'] / GameConst::$dexLimit * 100;
+ $dex30 = $general['dex30'] / GameConst::$dexLimit * 100;
+ $dex40 = $general['dex40'] / GameConst::$dexLimit * 100;
+
+ if($dex0 > 100) { $dex0 = 100; }
+ if($dex10 > 100) { $dex10 = 100; }
+ if($dex20 > 100) { $dex20 = 100; }
+ if($dex30 > 100) { $dex30 = 100; }
+ if($dex40 > 100) { $dex40 = 100; }
+
+ $general['dex0_text'] = getDexCall($general['dex0']);
+ $general['dex10_text'] = getDexCall($general['dex10']);
+ $general['dex20_text'] = getDexCall($general['dex20']);
+ $general['dex30_text'] = getDexCall($general['dex30']);
+ $general['dex40_text'] = getDexCall($general['dex40']);
+
+ $general['dex0_short'] = sprintf('%.1fK', $general['dex0']/1000);
+ $general['dex10_short'] = sprintf('%.1fK', $general['dex10']/1000);
+ $general['dex20_short'] = sprintf('%.1fK', $general['dex20']/1000);
+ $general['dex30_short'] = sprintf('%.1fK', $general['dex30']/1000);
+ $general['dex40_short'] = sprintf('%.1fK', $general['dex40']/1000);
+
+ echo "
+ 추 가 정 보
+
+ 명성
+ $experience
+ 계급
+ $dedication
+
+
+ 전투
+ {$general['warnum']}
+ 계략
+ {$general['firenum']}
+ 사관
+ {$general['belong']}년
+
+
+ 승률
+ {$general['winrate']} %
+ 승리
+ {$general['killnum']}
+ 패배
+ {$general['deathnum']}
+
+
+ 살상률
+ {$general['killrate']} %
+ 사살
+ {$general['killcrew']}
+ 피살
+ {$general['deathcrew']}
+
+
+
+ 숙 련 도
+
+ 보병
+ {$general['dex0_text']}
+ {$general['dex0_short']}
+ ".bar($dex0, 16)."
+
+
+ 궁병
+ {$general['dex10_text']}
+ {$general['dex10_short']}
+ ".bar($dex10, 16)."
+
+
+ 기병
+ {$general['dex20_text']}
+ {$general['dex20_short']}
+ ".bar($dex20, 16)."
+
+
+ 귀병
+ {$general['dex30_text']}
+ {$general['dex30_short']}
+ ".bar($dex30, 16)."
+
+
+ 차병
+ {$general['dex40_text']}
+ {$general['dex40_short']}
+ ".bar($dex40, 16)."
+
+
";
+}
+
+function adminMsg() {
+ $db = DB::db();
+ $gameStor = KVStorage::getStorage($db, 'game_env');
+ $msg = $gameStor->msg;
+
+ return "운영자 메세지 : $msg ";
+}
+
+function getOnlineNum() {
+ return KVStorage::getStorage(DB::db(), 'game_env')->online;
+}
+
+function onlinegen() {
+ $db = DB::db();
+ $gameStor = KVStorage::getStorage($db, 'game_env');
+
+ $onlinegen = "";
+ $generalID = Session::getInstance()->generalID;
+ $nationID = DB::db()->queryFirstField('select `nation` from `general` where `no` = %i', $generalID);
+ if($nationID === null || Util::toInt($nationID) === 0) {
+ $onlinegen = $gameStor->onlinegen;
+ } else {
+ $onlinegen = DB::db()->queryFirstField('select onlinegen from nation where nation=%i',$nationID);
+ }
+ return $onlinegen;
+}
+
+function onlineNation() {
+ $db = DB::db();
+ $gameStor = KVStorage::getStorage($db, 'game_env');
+
+ return $gameStor->onlinenation;
+}
+
+function nationMsg() {
+ $db = DB::db();
+ $connect=$db->get();
+ $userID = Session::getUserID();
+
+ $msg = $db->queryFirstField(
+ 'SELECT msg FROM nation WHERE nation = (SELECT nation FROM general WHERE `owner` = %i)',
+ $userID
+ );
+
+ return $msg?:'';
+}
+
+function msgprint($msg, $name, $picture, $imgsvr, $when, $num, $type) {
+ $db = DB::db();
+ $connect=$db->get();
+
+ $message = explode('|', $msg);
+ $count = (count($message) - 2)/2;
+ $message[0] = Tag2Code($message[0]);
+ $message[1] = Tag2Code($message[1]);
+// $message[0] = str_replace("\n", " ", $message[0]);
+// $message[1] = str_replace("\n", " ", $message[1]);
+
+ if($type == 0) { $board = "c_nationboard.php"; }
+ else { $board = "c_chiefboard.php"; }
+
+ $imageTemp = GetImageURL($imgsvr);
+ echo "
+
+
+ $name
+ $message[0]
+ $when
+
+
+
+ $message[1]
+ ";
+ for($i=0; $i < $count; $i++) {
+ $who = Tag2Code($message[2+$i*2]);
+ $reply = Tag2Code($message[3+$i*2]);
+ $query = "select name from general where no='$who'";
+ $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
+ $regen = MYDB_fetch_array($result);
+ echo "
+
+ {$regen['name']}
+ $reply
+ ";
+ }
+ echo "
+
+
+
+
+ ";
+}
+
+function banner() {
+
+ return sprintf(
+ '%s %s / %s ',
+ GameConst::$title,
+ VersionGit::$version,
+ GameConst::$banner);
+}
+
+function addTurn($date, int $turnterm, int $turn=1, bool $withFraction=true) {
+ $date = new \DateTime($date);
+ $target = $turnterm*$turn;
+ $date->add(new \DateInterval("PT{$target}M"));
+ if($withFraction){
+ return $date->format('Y-m-d H:i:s.u');
+ }
+ return $date->format('Y-m-d H:i:s');
+}
+
+function subTurn($date, int $turnterm, int $turn=1, bool $withFraction=true) {
+ $date = new \DateTime($date);
+ $target = $turnterm*$turn;
+ $date->sub(new \DateInterval("PT{$target}M"));
+ if($withFraction){
+ return $date->format('Y-m-d H:i:s.u');
+ }
+ return $date->format('Y-m-d H:i:s');
+}
+
+function cutTurn($date, int $turnterm, bool $withFraction=true) {
+ $date = new \DateTime($date);
+
+ $baseDate = new \DateTime($date->format('Y-m-d'));
+ $baseDate->sub(new \DateInterval("P1D"));
+ $baseDate->add(new \DateInterval("PT1H"));
+
+ $diffMin = intdiv($date->getTimeStamp() - $baseDate->getTimeStamp(), 60);
+ $diffMin -= $diffMin % $turnterm;
+
+ $baseDate->add(new \DateInterval("PT{$diffMin}M"));
+ if($withFraction){
+ return $baseDate->format('Y-m-d H:i:s.u');
+ }
+ return $baseDate->format('Y-m-d H:i:s');
+
+}
+
+function cutDay($date, int $turnterm, bool $withFraction=true) {
+ $date = new \DateTime($date);
+
+ $baseDate = new \DateTime($date->format('Y-m-d'));
+ $baseDate->sub(new \DateInterval("P1D"));
+ $baseDate->add(new \DateInterval("PT1H"));
+
+ $baseGap = 12 * $turnterm;
+
+ $diffMin = intdiv($date->getTimeStamp() - $baseDate->getTimeStamp(), 60);
+
+ $timeAdjust = $diffMin % $baseGap;
+ $newMonth = intdiv($timeAdjust, $turnterm) + 1;
+
+ $yearPulled = false;
+ if($newMonth > 3){//3월 이후일때는
+ $yearPulled = true;
+ $diffMin += $baseGap;
+ }
+ $diffMin -= $timeAdjust;
+
+ $baseDate->add(new \DateInterval("PT{$diffMin}M"));
+ if($withFraction){
+ $dateTimeString = $baseDate->format('Y-m-d H:i:s.u');
+ }
+ else{
+ $dateTimeString = $baseDate->format('Y-m-d H:i:s');
+ }
+
+ return [$dateTimeString, $yearPulled, $newMonth];
+}
+
+function increaseRefresh($type="", $cnt=1) {
+ //FIXME: 로그인, 비로그인 시 처리가 명확하지 않음
+ $session = Session::getInstance();
+ $userID = $session->userID;
+ $generalID = $session->generalID;
+ $userGrade = $session->userGrade;
+
+ $date = TimeUtil::now();
+
+ $db = DB::db();
+ $gameStor = KVStorage::getStorage($db, 'game_env');
+ $gameStor->refresh = $gameStor->refresh+$cnt; //TODO: +로 증가하는 값은 별도로 분리
+
+ if($generalID && $userGrade < 6) {
+ $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);
+ $online = getOnlineNum();
+ file_put_contents(
+ __dir__."/logs/".UniqueConst::$serverID."/_{$date2}_refresh.txt",
+ sprintf(
+ "%s, %s, %s, %s, %s, %d\n",
+ $date,
+ $session->userName,
+ $session->generalName,
+ $session->ip,
+ $type,
+ $online
+ ),
+ 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() {
+ $online = getOnlineNum();
+ $db = DB::db();
+ $gameStor = KVStorage::getStorage($db, 'game_env');
+ $admin = $gameStor->getValues(['year','month','refresh','maxonline','maxrefresh']);
+
+ //최다갱신자
+ $user = $db->queryFirstRow('select name,refresh from general order by refresh desc limit 1');
+
+ if($admin['maxrefresh'] < $admin['refresh']) {
+ $admin['maxrefresh'] = $admin['refresh'];
+ }
+ if($admin['maxonline'] < $online) {
+ $admin['maxonline'] = $online;
+ }
+ $gameStor->refresh = 0;
+ $gameStor->maxrefresh = $admin['maxrefresh'];
+ $gameStor->maxonline = $admin['maxonline'];
+
+ $db->update('general', ['refresh'=>0], true);
+
+ $date = TimeUtil::now();
+ //일시|년|월|총갱신|접속자|최다갱신자
+ file_put_contents(__dir__."/logs/".UniqueConst::$serverID."/_traffic.txt",
+ Json::encode([
+ $date,
+ $admin['year'],
+ $admin['month'],
+ $admin['refresh'],
+ $online,
+ $user['name']."(".$user['refresh'].")"
+ ])."\n"
+ , FILE_APPEND);
+}
+
+function CheckOverhead() {
+ //서버정보
+ $db = DB::db();
+ $gameStor = KVStorage::getStorage($db, 'game_env');
+ list($turnterm, $conlimit) = $gameStor->getValuesAsArray(['turnterm', 'conlimit']);
+
+ $con = Util::round(pow($turnterm, 0.6) * 3) * 10;
+
+
+ if($con != $conlimit){
+ $gameStor->conlimit = $con;
+ }
+}
+
+function isLock() {
+ return DB::db()->queryFirstField("SELECT plock from plock limit 1") != 0;
+}
+
+function tryLock():bool{
+ //NOTE: 게임 로직과 관련한 모든 insert, update 함수들은 lock을 거칠것을 권장함.
+ $db = DB::db();
+
+ // 잠금
+ $db->update('plock', [
+ 'plock'=>1,
+ 'locktime'=>TimeUtil::now(true)
+ ], 'plock=1');
+
+ return $db->affectedRows() > 0;
+}
+
+function unlock():bool{
+ // 풀림
+ $db = DB::db();
+ $db->update('plock', [
+ 'plock'=>0
+ ], true);
+
+ return $db->affectedRows() > 0;
+}
+
+function timeover():bool {
+ $db = DB::db();
+ $gameStor = KVStorage::getStorage($db, 'game_env');
+
+ list($turnterm, $turntime) = $gameStor->getValuesAsArray(['turnterm', 'turntime']);
+ $diff = (new \DateTime())->getTimestamp() - (new \DateTime($turntime))->getTimestamp();
+
+ $t = min($turnterm, 5);
+
+ $term = $diff;
+ if($term >= $t || $term < 0) { return true; }
+ else { return false; }
+}
+
+function checkDelay() {
+ $db = DB::db();
+ $gameStor = KVStorage::getStorage($db, 'game_env');
+
+ //서버정보
+ $now = new \DateTimeImmutable();
+ $turntime = new \DateTimeImmutable($gameStor->turntime);
+ $timeMinDiff = intdiv($now->getTimestamp() - $turntime->getTimestamp(), 60);
+
+ // 1턴이상 갱신 없었으면 서버 지연
+ $term = $gameStor->turnterm;
+ if($term >= 20){
+ $threshold = 1;
+ }
+ else if($term >= 10){
+ $threshold = 2;
+ }
+ else{
+ $threshold = 3;
+ }
+ //지연 해야할 밀린 턴 횟수
+ $iter = intdiv($timeMinDiff, $term);
+ if($iter > $threshold) {
+ $minute = ($iter - $threshold) * $term;
+ $newTurntime = $turntime->add(new \DateInterval("PT{$minute}M"));
+ $newNextTurntime = $turntime->add(new \DateInterval("PT{$term}M"));
+ $gameStor->turntime = $newTurntime->format('Y-m-d H:i:s');
+ $gameStor->starttime = (new \DateTimeImmutable($gameStor->starttime))
+ ->add(new \DateInterval("PT{$minute}M"))
+ ->format('Y-m-d H:i:s');
+ $db->update('general', [
+ 'turntime'=> $db->sqleval('DATE_ADD(turntime, INTERVAL %i MINUTE)', $minute)
+ ], true);
+ $db->update('auction', [
+ 'expire'=> $db->sqleval('DATE_ADD(expire, INTERVAL %i MINUTE)', $minute)
+ ], true);
+ }
+}
+
+function updateOnline() {
+ $db = DB::db();
+ $gameStor = KVStorage::getStorage($db, 'game_env');
+ $connect=$db->get();
+ $nationname = ["재야"];
+
+ //국가별 이름 매핑
+ foreach(getAllNationStaticInfo() as $nation) {
+ $nationname[$nation['nation']] = $nation['name'];
+ }
+
+
+ //동접수
+ $query = "select no,name,nation from general where lastrefresh > DATE_SUB(NOW(), INTERVAL 5 MINUTE)";
+ $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
+ $onlinenum = MYDB_num_rows($result);
+
+ $onnation = array();
+ $onnationstr = "";
+
+ //국가별 접속중인 장수
+ for($i=0; $i < $onlinenum; $i++) {
+ $general = MYDB_fetch_array($result);
+ if(isset($onnation[$general['nation']])){
+ $onnation[$general['nation']] .= $general['name'].', ';
+ }else {
+ $onnation[$general['nation']] = $general['name'].', ';
+ }
+ }
+
+ //$onnation이 empty라면 굳이 foreach를 수행 할 이유가 없음.
+ if(!empty($onnation)){
+ foreach($onnation as $key => $val) {
+ $onnationstr .= "【{$nationname[$key]}】, ";
+
+ if($key == 0) {
+ $gameStor->onlinegen = $onnation[0];
+ } else {
+ $query = "update nation set onlinegen='$onnation[$key]' where nation='$key'";
+ MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
+ }
+ }
+ }
+
+ //접속중인 국가
+ $gameStor->online = $onlinenum;
+ $gameStor->onlinenation = $onnationstr;
+}
+
+function checkTurn() {
+ $db = DB::db();
+ $gameStor = KVStorage::getStorage($db, 'game_env');
+ $connect=$db->get();
+
+ $alllog = [];
+
+ // 잦은 갱신 금지 현재 5초당 1회
+ if(!timeover()) { return; }
+ // 현재 처리중이면 접근 불가
+
+ // 파일락 획득
+ //FIXME:이미 DB 테이블로 lock을 시도하는데 이게 따로 필요한가?
+ $fp = fopen(__dir__.'/lock.txt', 'r');
+ if(!flock($fp, LOCK_EX)) {
+ return;
+ }
+
+ if(!tryLock()){
+ return;
+ }
+
+ $session = Session::getInstance();
+
+ pushLockLog(["- checkTurn() : ".TimeUtil::now()." : ".$session->userName]);
+
+ // 파일락 해제
+ if(!flock($fp, LOCK_UN)) { return; }
+ // 세마포어 해제
+ //if(!@sem_release($sema)) { echo "치명적 에러! Hide_D에게 문의하세요!"; exit(1); }
+
+ pushLockLog(["- checkTurn() 입 : ".TimeUtil::now()." : ".$session->userName]);
+
+ //if(STEP_LOG) delStepLog();
+ //if(STEP_LOG) pushStepLog(TimeUtil::now().', 진입');
+
+
+ if($gameStor->isunited == 2) {
+ $db->update('plock', ['plock'=>1], true);
+ return;
+ }
+ $gameStor->cacheAll();
+ // 1턴이상 갱신 없었으면 서버 지연
+ //if(STEP_LOG) pushStepLog(TimeUtil::now().', checkDelay');
+ checkDelay();
+ // 접속자수, 접속국가, 국가별 접속장수 갱신
+ //if(STEP_LOG) pushStepLog(TimeUtil::now().', checkDelay');
+ updateOnline();
+ //접속자 수 따라서 갱신제한 변경
+ //if(STEP_LOG) pushStepLog(TimeUtil::now().', CheckOverhead');
+ CheckOverhead();
+ //서버정보
+
+ $date = TimeUtil::now();
+ // 최종 처리 월턴의 다음 월턴시간 구함
+ $prevTurn = cutTurn($gameStor->turntime, $gameStor->turnterm);
+ $nextTurn = addTurn($prevTurn, $gameStor->turnterm);
+ // 현재 턴 이전 월턴까지 모두처리.
+ //최종 처리 이후 다음 월턴이 현재 시간보다 전이라면
+ while($nextTurn <= $date) {
+ // 월턴이전 장수 모두 처리
+ $query = "select no,name,turntime,turn0,npc from general where turntime < '$nextTurn' order by turntime";
+ $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
+ $gencount = MYDB_num_rows($result);
+ for($i=0; $i < $gencount; $i++) {
+ $general = MYDB_fetch_array($result);
+
+ //if(PROCESS_LOG) $processlog[0] = "[{$date}] 월턴 이전 갱신: name({$general['name']}), no({$general['no']}), turntime({$general['turntime']}), turn0({$general['turn0']})";
+ //if(PROCESS_LOG) pushProcessLog($processlog);
+
+ //if(STEP_LOG) pushStepLog(TimeUtil::now().', processAI');
+ if($general['npc'] >= 2) { processAI($general['no']); } // npc AI 처리
+ //if(STEP_LOG) pushStepLog(TimeUtil::now().', PreprocessCommand');
+ PreprocessCommand($general['no']);
+ //if(STEP_LOG) pushStepLog(TimeUtil::now().', processCommand');
+ processCommand($general['no']);
+ //if(STEP_LOG) pushStepLog(TimeUtil::now().', updateCommand');
+ updateCommand($general['no']);
+ //if(STEP_LOG) pushStepLog(TimeUtil::now().', updateTurntime');
+ updateTurntime($general['no']);
+
+ }
+
+ // 트래픽 업데이트
+ //if(STEP_LOG) pushStepLog(TimeUtil::now().', updateTraffic');
+ updateTraffic();
+ // 1달마다 처리하는 것들, 벌점 감소 및 건국,전턴,합병 -1, 군량 소모
+ //if(STEP_LOG) pushStepLog(TimeUtil::now().', preUpdateMonthly');
+ $result = preUpdateMonthly();
+ if($result == false) {
+ pushLockLog(["-- checkTurn() 오류출 : ".TimeUtil::now()." : ".$session->userName]);
+
+ // 잡금 해제
+ //if(STEP_LOG) pushStepLog(TimeUtil::now().', unlock');
+ $gameStor->resetCache(true);
+ unlock();
+ return false;
+ }
+
+ // 그 시각 년도,월 저장
+ list($gameStor->year, $gameStor->month) = turnDate($nextTurn);
+
+ pushLockLog(["-- checkTurn() ".$gameStor->month."월 : ".TimeUtil::now()." : ".$session->userName]);
+
+ // 이벤트 핸들러 동작
+ foreach (DB::db()->query('SELECT * from event') as $rawEvent) {
+ $eventID = $rawEvent['id'];
+ $cond = Json::decode($rawEvent['condition']);
+ $action = Json::decode($rawEvent['action']);
+ $event = new Event\EventHandler($cond, $action);
+
+ $event->tryRunEvent(['currentEventID'=>$eventID] + $gameStor->getAll(true));
+ }
+
+ // 분기계산. 장수들 턴보다 먼저 있다면 먼저처리
+ if($gameStor->month == 1) {
+ // NPC 등장
+ //if(STEP_LOG) pushStepLog(TimeUtil::now().', processGoldIncome');
+ processGoldIncome();
+ //if(STEP_LOG) pushStepLog(TimeUtil::now().', processSpring');
+ processSpring();
+ //if(STEP_LOG) pushStepLog(TimeUtil::now().', updateYearly');
+ updateYearly();
+ //if(STEP_LOG) pushStepLog(TimeUtil::now().', updateQuaterly');
+ updateQuaterly();
+ //if(STEP_LOG) pushStepLog(TimeUtil::now().', disaster');
+ disaster();
+ //if(STEP_LOG) pushStepLog(TimeUtil::now().', tradeRate');
+ tradeRate();
+ //if(STEP_LOG) pushStepLog(TimeUtil::now().', addAge');
+ addAge();
+ // 새해 알림
+ $alllog[] = "◆>{$gameStor->month}월:{$gameStor->year}>년이 되었습니다.";
+ pushGeneralPublicRecord($alllog, $gameStor->year, $gameStor->month);
+ } elseif($gameStor->month == 4) {
+ //if(STEP_LOG) pushStepLog(TimeUtil::now().', updateQuaterly');
+ updateQuaterly();
+ //if(STEP_LOG) pushStepLog(TimeUtil::now().', disaster');
+ disaster();
+ } elseif($gameStor->month == 7) {
+ //if(STEP_LOG) pushStepLog(TimeUtil::now().', processRiceIncome');
+ processRiceIncome();
+ //if(STEP_LOG) pushStepLog(TimeUtil::now().', processFall');
+ processFall();
+ //if(STEP_LOG) pushStepLog(TimeUtil::now().', updateQuaterly');
+ updateQuaterly();
+ //if(STEP_LOG) pushStepLog(TimeUtil::now().', disaster');
+ disaster();
+ //if(STEP_LOG) pushStepLog(TimeUtil::now().', tradeRate');
+ tradeRate();
+ } elseif($gameStor->month == 10) {
+ //if(STEP_LOG) pushStepLog(TimeUtil::now().', updateQuaterly');
+ updateQuaterly();
+ //if(STEP_LOG) pushStepLog(TimeUtil::now().', disaster');
+ disaster();
+ }
+ //if(STEP_LOG) pushStepLog(TimeUtil::now().', postUpdateMonthly');
+ postUpdateMonthly();
+
+ // 다음달로 넘김
+ $prevTurn = $nextTurn;
+ $nextTurn = addTurn($prevTurn, $gameStor->turnterm);
+ }
+
+ //if(STEP_LOG) pushStepLog(TimeUtil::now().', '.__LINE__);
+
+ // 이시각 정각 시까지 업데이트 완료했음
+ $gameStor->turntime = $prevTurn;
+
+ // 그 시각 년도,월 저장
+ list($gameStor->year, $gameStor->month) = turnDate($prevTurn);
+ // 현재시간의 월턴시간 이후 분단위 장수 처리
+ do {
+ $query = "select no,name,turntime,turn0,npc from general where turntime<='$date' order by turntime";
+ $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
+ $gencount = MYDB_num_rows($result);
+
+ for($i=0; $i < $gencount; $i++) {
+ $general = MYDB_fetch_array($result);
+
+ //if(PROCESS_LOG) $processlog[0] = "[{$date}] 월턴 이후 갱신: name({$general['name']}), no({$general['no']}), turntime({$general['turntime']}), turn0({$general['turn0']})";
+ //if(PROCESS_LOG) pushProcessLog($processlog);
+
+ //if(STEP_LOG) pushStepLog(TimeUtil::now().', processAI');
+ if($general['npc'] >= 2) { processAI($general['no']); } // npc AI 처리
+ //if(STEP_LOG) pushStepLog(TimeUtil::now().', PreprocessCommand');
+ PreprocessCommand($general['no']);
+ //if(STEP_LOG) pushStepLog(TimeUtil::now().', processCommand');
+ processCommand($general['no']);
+ //if(STEP_LOG) pushStepLog(TimeUtil::now().', updateCommand');
+ updateCommand($general['no']);
+ //if(STEP_LOG) pushStepLog(TimeUtil::now().', updateTurntime');
+ updateTurntime($general['no']);
+ }
+ } while($gencount > 0);
+
+ //if(STEP_LOG) pushStepLog(TimeUtil::now().', '.__LINE__);
+
+ $gameStor->turntime = $date;
+
+ // 부상 과도 제한
+ $query = "update general set injury='80' where injury>'80'";
+ MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
+ //토너먼트 처리
+ //if(STEP_LOG) pushStepLog(TimeUtil::now().', processTournament');
+ processTournament();
+ //거래 처리
+ //if(STEP_LOG) pushStepLog(TimeUtil::now().', processAuction');
+ processAuction();
+ // 잡금 해제
+ //if(STEP_LOG) pushStepLog(TimeUtil::now().', unlock');
+ $gameStor->resetCache(true);
+ unlock();
+
+ pushLockLog(["- checkTurn() 출 : ".TimeUtil::now()." : ".$session->userName]);
+
+ //if(STEP_LOG) pushStepLog(TimeUtil::now().', finish');
+
+ return true;
+}
+
+function addAge() {
+ $db = DB::db();
+ $gameStor = KVStorage::getStorage($db, 'game_env');
+ $connect=$db->get();
+
+ //나이와 호봉 증가
+ $query = "update general set age=age+1,belong=belong+1";
+ MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
+
+ $admin = $gameStor->getValues(['startyear', 'year', 'month']);
+
+ if($admin['year'] >= $admin['startyear']+3) {
+ foreach($db->query('SELECT no,name,nation,leader,power,intel from general where specage<=age and special=%s', GameConst::$defaultSpecial) as $general){
+ $special = getSpecial($general['leader'], $general['power'], $general['intel']);
+ $specialClass = getGeneralSpecialDomesticClass($special);
+ $specialText = $specialClass::$name;
+ $db->update('general', [
+ 'special'=>$special
+ ], 'no=%i',$general['no']);
+
+ $josaUl = JosaUtil::pick($specialText, '을');
+ pushGeneralHistory($general, "●>{$admin['year']}년 {$admin['month']}월:특기 【{$specialText}> 】{$josaUl} 습득");
+ pushGenLog($general, "●>특기 【{$specialText}> 】{$josaUl} 익혔습니다!");
+ }
+
+ $query = "select no,name,nation,leader,power,intel,npc,dex0,dex10,dex20,dex30,dex40 from general where specage2<=age and special2='0'";
+ $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
+ $gencount = MYDB_num_rows($result);
+
+ for($i=0; $i < $gencount; $i++) {
+ $general = MYDB_fetch_array($result);
+ $special2 = getSpecial2($general['leader'], $general['power'], $general['intel'], 0, $general['dex0'], $general['dex10'], $general['dex20'], $general['dex30'], $general['dex40']);
+
+ $query = "update general set special2='$special2' where no='{$general['no']}'";
+ MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
+
+ $josaUl = JosaUtil::pick($special2, '을');
+ pushGeneralHistory($general, "●>{$admin['year']}년 {$admin['month']}월:특기 【".getGenSpecial($special2)."> 】{$josaUl} 습득");
+ pushGenLog($general, "●>특기 【".getGenSpecial($special2)."> 】{$josaUl} 익혔습니다!");
+ }
+ }
+}
+
+function turnDate($curtime) {
+ $db = DB::db();
+ $gameStor = KVStorage::getStorage($db, 'game_env');
+ $admin = $gameStor->getValues(['startyear', 'starttime', 'turnterm', 'year', 'month']);
+
+ $turn = $admin['starttime'];
+ $curturn = cutTurn($curtime, $admin['turnterm']);
+ $term = $admin['turnterm'];
+
+ $num = intdiv((strtotime($curturn) - strtotime($turn)), $term*60);
+
+ $date = $admin['startyear'] * 12;
+ $date += $num;
+
+ $year = intdiv($date, 12);
+ $month = 1 + $date % 12;
+
+ // 바뀐 경우만 업데이트
+ if($admin['month'] != $month || $admin['year'] != $year) {
+ $gameStor->year = $year;
+ $gameStor->month = $month;
+ }
+
+ return [$year, $month];
+}
+
+
+function triggerTournament() {
+ $db = DB::db();
+ $gameStor = KVStorage::getStorage($db, 'game_env');
+
+ $admin = $gameStor->getValues(['tournament', 'tnmt_trig']);
+
+ //현재 토너먼트 없고, 자동개시 걸려있을때, 40%확률
+ if($admin['tournament'] == 0 && $admin['tnmt_trig'] > 0 && rand() % 100 < 40) {
+ $type = rand() % 5; // 0 : 전력전, 1 : 통솔전, 2 : 일기토, 3 : 설전
+ //전력전 40%, 통, 일, 설 각 20%
+ if($type > 3) { $type = 0; }
+ startTournament($admin['tnmt_trig'], $type);
+ }
+}
+
+function PreprocessCommand($no) {
+ $db = DB::db();
+ $connect=$db->get();
+ $log = [];
+
+ $query = "select no,name,city,injury,special2,item,turn0,rice,crew from general where no='$no'";
+ $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
+ $general = MYDB_fetch_array($result);
+
+ if($general['special2'] == 73 || $general['item'] == 23 || $general['item'] == 24) {
+ //특기보정 : 의술
+ //의서 사용
+ if($general['injury'] > 0) {
+ $general['injury'] = 0;
+ $query = "update general set injury=0 where no='$no'";
+ MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
+
+ pushGenLog($general, "●>의술>을 펼쳐 스스로 치료합니다!");
+ }
+
+ $query = "select no,name,injury from general where city='{$general['city']}' and injury>10 order by rand()";
+ $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
+ $patientCount = MYDB_num_rows($result);
+
+ if($patientCount > 0) {
+ // 50% 확률로 치료
+ $patientCount = Util::round($patientCount * 0.5);
+
+ $patientName = "";
+ for($i=0; $i < $patientCount; $i++) {
+ $patient = MYDB_fetch_array($result);
+
+ //부상 치료
+ $query = "update general set injury=0 where no='{$patient['no']}'";
+ MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
+
+ $josaYi = JosaUtil::pick($general['name'], '이');
+ pushGenLog($patient, "●>{$general['name']}>{$josaYi} 의술>로써 치료해줍니다!");
+
+ if($patientName == "") {
+ $patientName = $patient['name'];
+ }
+ }
+
+ if($patientCount == 1) {
+ $josaUl = JosaUtil::pick($patientName, '을');
+ pushGenLog($general, "●>의술>을 펼쳐 도시의 장수 {$patientName}>{$josaUl} 치료합니다!");
+ } else {
+ $patientCount -= 1;
+ pushGenLog($general, "●>의술>을 펼쳐 도시의 장수들 {$patientName}> 외 {$patientCount}>명을 치료합니다!");
+ }
+ }
+ }
+
+ if($general['injury'] > 0) {
+ if($general['item'] >=7 && $general['item'] <= 11) {
+ //영구약 사용
+ $query = "update general set injury=0 where no='$no'";
+ MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
+
+ $josaUl = JosaUtil::pick($general['item'], '을');
+ $log[0] = "●>".getItemName($general['item']).">{$josaUl} 사용하여 치료합니다!";
+ pushGenLog($general, $log);
+ } elseif($general['injury'] > 10 && $general['item'] == 1 && DecodeCommand($general['turn0'])[0] != 50) {
+ //환약 사용
+ $query = "update general set injury=0,item=0 where no='$no'";
+ MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
+
+ $log[0] = "●>환약>을 사용하여 치료합니다!";
+ pushGenLog($general, $log);
+ } elseif($general['injury'] > 10) {
+ //부상 감소
+ $query = "update general set injury=injury-10 where no='$no'";
+ MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
+ } else {
+ //부상 감소
+ $query = "update general set injury=0 where no='$no'";
+ MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
+ }
+ }
+
+
+ if($general['crew'] >= 100){
+ $newRice = $general['rice'] - $general['crew'] / 100;
+ if($newRice >= 0){
+ $db->update('general', [
+ 'rice'=>Util::round($newRice)
+ ], 'no=%i',$general['no']);
+ }
+ else{
+ $db->update('city', [
+ 'pop'=>$db->sqleval('pop + %i', $general['crew'])
+ ], 'city=%i', $general['city']);
+ $db->update('general', [
+ 'crew'=>0,
+ 'rice'=>0
+ ], 'no=%i',$general['no']);
+ pushGenLog($general, ["●>군량이 모자라 병사들이 소집해제>되었습니다!"]);
+ }
+ }
+
+}
+
+
+function updateTurntime($no) {
+ $db = DB::db();
+ $gameStor = KVStorage::getStorage($db, 'game_env');
+ $connect=$db->get();
+ $alllog = [];
+ $log = [];
+
+ $admin = $gameStor->getValues(['year', 'month', 'isunited', 'turnterm']);
+
+ $query = "select no,name,name2,nation,troop,age,turntime,killturn,level,deadyear,npc,npc_org,affinity,npcid from general where no='$no'";
+ $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
+ $general = MYDB_fetch_array($result);
+
+ // 삭턴장수 삭제처리
+ if($general['killturn'] <= 0) {
+ // npc유저 삭턴시 npc로 전환
+ if($general['npc'] == 1 && $general['deadyear'] > $admin['year']) {
+ $general['killturn'] = ($general['deadyear'] - $admin['year']) * 12;
+ $general['npc'] = $general['npc_org'];
+
+ $db->update('general', [
+ 'owner'=>-1,
+ 'npc'=>$general['npc_org'],
+ 'killturn'=>$general['killturn'],
+ 'mode'=>2,
+ 'name2'=>null
+ ], 'no=%i',$no);
+
+ $josaYi = JosaUtil::pick($general['name2'], '이');
+ $alllog[0] = "●>{$admin['month']}월:{$general['name2']}>{$josaYi} {$general['name']}>의 육체에서 유체이탈>합니다!";
+ pushGeneralPublicRecord($alllog, $admin['year'], $admin['month']);
+ } else {
+
+ storeOldGeneral($general['no'], $admin['year'], $admin['month']);
+
+ // 군주였으면 유지 이음
+ if($general['level'] == 12) {
+ nextRuler($general);
+ }
+
+ //도시의 태수, 군사, 시중직도 초기화
+ $query = "update city set gen1='0' where gen1='{$general['no']}'";
+ MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
+ $query = "update city set gen2='0' where gen2='{$general['no']}'";
+ MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
+ $query = "update city set gen3='0' where gen3='{$general['no']}'";
+ MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
+
+ // 부대 처리
+ $query = "select no from troop where troop='{$general['troop']}'";
+ $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
+ $troop = MYDB_fetch_array($result);
+
+ //부대장일 경우
+ if($troop['no'] == $general['no']) {
+ // 모두 탈퇴
+ $query = "update general set troop='0' where troop='{$general['troop']}'";
+ MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
+ // 부대 삭제
+ $query = "delete from troop where troop='{$general['troop']}'";
+ MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
+ } else {
+ $query = "update general set troop='0' where no='{$general['no']}'";
+ MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
+ }
+ // 장수 삭제
+ $query = "delete from general where no='{$general['no']}'";
+ MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
+
+ $db->update('nation', [
+ 'gennum'=>$db->sqleval('gennum - 1')
+ ], 'nation=%i', $general['nation']);
+
+ // 병, 요절, 객사, 번개, 사채, 일확천금, 호랑이, 곰, 수영, 처형, 발견
+ $josaYi = JosaUtil::pick($general['name'], '이');
+ switch(rand()%42) {
+ case 0: $alllog[0] = "●>{$admin['month']}월:{$general['name']}>{$josaYi} 역병에 걸려 죽고> 말았습니다."; break;
+ case 1: $alllog[0] = "●>{$admin['month']}월:{$general['name']}>{$josaYi} 요절>하고 말았습니다."; break;
+ case 2: $alllog[0] = "●>{$admin['month']}월:{$general['name']}>{$josaYi} 거리에서 갑자기 객사>하고 말았습니다."; break;
+ case 3: $alllog[0] = "●>{$admin['month']}월:{$general['name']}>{$josaYi} 안타깝게도 번개에 맞아 죽고> 말았습니다."; break;
+ case 4: $alllog[0] = "●>{$admin['month']}월:{$general['name']}>{$josaYi} 고리대금에 시달리다가 자살>하고 말았습니다."; break;
+ case 5: $alllog[0] = "●>{$admin['month']}월:{$general['name']}>{$josaYi} 일확천금에 놀라 심장마비로 죽고> 말았습니다."; break;
+ case 6: $alllog[0] = "●>{$admin['month']}월:{$general['name']}>{$josaYi} 산속에서 호랑이에게 물려 죽고> 말았습니다."; break;
+ case 7: $alllog[0] = "●>{$admin['month']}월:{$general['name']}>{$josaYi} 산책중 곰에게 할퀴어 죽고> 말았습니다."; break;
+ case 8: $alllog[0] = "●>{$admin['month']}월:{$general['name']}>{$josaYi} 수영을 하다 익사>하고 말았습니다."; break;
+ case 9: $alllog[0] = "●>{$admin['month']}월:{$general['name']}>{$josaYi} 황제를 모독하다가 처형>당하고 말았습니다."; break;
+ case 10: $alllog[0] = "●>{$admin['month']}월:{$general['name']}>{$josaYi} 이튿날 침실에서 죽은채로>발견되었습니다."; break;
+ case 11: $alllog[0] = "●>{$admin['month']}월:{$general['name']}>{$josaYi} 색에 빠져 기력이 쇠진해 죽고>말았습니다."; break;
+ case 12: $alllog[0] = "●>{$admin['month']}월:{$general['name']}>{$josaYi} 미녀를 보고 심장마비로 죽고>말았습니다."; break;
+ case 13: $alllog[0] = "●>{$admin['month']}월:{$general['name']}>{$josaYi} 우울증에 걸려 자살>하고 말았습니다."; break;
+ case 14: $alllog[0] = "●>{$admin['month']}월:{$general['name']}>{$josaYi} 천하 정세를 비관하며 분신>하고 말았습니다."; break;
+ case 15: $alllog[0] = "●>{$admin['month']}월:{$general['name']}>{$josaYi} 어떤 관심도 못받고 쓸쓸히 죽고>말았습니다."; break;
+ case 16: $alllog[0] = "●>{$admin['month']}월:{$general['name']}>{$josaYi} 유산 상속 문제로 다투다가 살해>당했습니다."; break;
+ case 17: $alllog[0] = "●>{$admin['month']}월:{$general['name']}>{$josaYi} 누군가의 사주로 자객에게 암살>당했습니다."; break;
+ case 18: $alllog[0] = "●>{$admin['month']}월:{$general['name']}>{$josaYi} 바람난 배우자에게 독살>당하고 말았습니다."; break;
+ case 19: $alllog[0] = "●>{$admin['month']}월:{$general['name']}>{$josaYi} 농약을 술인줄 알고 마셔 죽고>말았습니다."; break;
+ case 20: $alllog[0] = "●>{$admin['month']}월:{$general['name']}>{$josaYi} 아무 이유 없이 죽고>말았습니다."; break;
+ case 21: $alllog[0] = "●>{$admin['month']}월:{$general['name']}>{$josaYi} 전재산을 잃고 화병으로 죽고>말았습니다."; break;
+ case 22: $alllog[0] = "●>{$admin['month']}월:{$general['name']}>{$josaYi} 단식운동을 하다가 굶어 죽고>말았습니다."; break;
+ case 23: $alllog[0] = "●>{$admin['month']}월:{$general['name']}>{$josaYi} 귀신에게 홀려 시름 앓다가 죽고>말았습니다."; break;
+ case 24: $alllog[0] = "●>{$admin['month']}월:{$general['name']}>{$josaYi} 사람들에게 집단으로 맞아서 죽고>말았습니다."; break;
+ case 25: $alllog[0] = "●>{$admin['month']}월:{$general['name']}>{$josaYi} 갑자기 성벽에서 뛰어내려 죽고>말았습니다."; break;
+ case 26: $alllog[0] = "●>{$admin['month']}월:{$general['name']}>{$josaYi} 농사중 호미에 머리를 맞아 죽고>말았습니다."; break;
+ case 27: $alllog[0] = "●>{$admin['month']}월:{$general['name']}>{$josaYi} 저세상이 궁금하다며 자살>하고 말았습니다."; break;
+ case 28: $alllog[0] = "●>{$admin['month']}월:운좋기로 소문난 {$general['name']}>{$josaYi} 불운하게도 죽고>말았습니다."; break;
+ case 29: $alllog[0] = "●>{$admin['month']}월:{$general['name']}>{$josaYi} 무리하게 단련을 하다가 죽고>말았습니다."; break;
+ case 30: $alllog[0] = "●>{$admin['month']}월:{$general['name']}>{$josaYi} 생활고를 비관하며 자살>하고 말았습니다."; break;
+ case 31: $alllog[0] = "●>{$admin['month']}월:{$general['name']}>{$josaYi} 평생 결혼도 못해보고 죽고> 말았습니다."; break;
+ case 32: $alllog[0] = "●>{$admin['month']}월:{$general['name']}>{$josaYi} 과식하다 배가 터져 죽고> 말았습니다."; break;
+ case 33: $alllog[0] = "●>{$admin['month']}월:{$general['name']}>{$josaYi} 웃다가 숨이 넘어가 죽고> 말았습니다."; break;
+ case 34: $alllog[0] = "●>{$admin['month']}월:{$general['name']}>{$josaYi} 추녀를 보고 놀라서 죽고> 말았습니다."; break;
+ case 35: $alllog[0] = "●>{$admin['month']}월:{$general['name']}>{$josaYi} 물에 빠진 사람을 구하려다 같이 죽고> 말았습니다."; break;
+ case 36: $alllog[0] = "●>{$admin['month']}월:{$general['name']}>{$josaYi} 독살을 준비하다 독에 걸려 죽고> 말았습니다."; break;
+ case 37: $alllog[0] = "●>{$admin['month']}월:{$general['name']}>{$josaYi} 뒷간에서 너무 힘을 주다가 죽고> 말았습니다."; break;
+ case 38: $alllog[0] = "●>{$admin['month']}월:{$general['name']}>{$josaYi} 돌팔이 의사에게 치료받다가 죽고> 말았습니다."; break;
+ case 39: $alllog[0] = "●>{$admin['month']}월:{$general['name']}>{$josaYi} 남의 보약을 훔쳐먹다 부작용으로 죽고> 말았습니다."; break;
+ case 40: $alllog[0] = "●>{$admin['month']}월:희대의 사기꾼 {$general['name']}>{$josaYi} 사망>했습니다."; break;
+ case 41: $alllog[0] = "●>{$admin['month']}월:희대의 호색한 {$general['name']}>{$josaYi} 사망>했습니다."; break;
+ default: $alllog[0] = "●>{$admin['month']}월:{$general['name']}>{$josaYi} 사망>했습니다."; break;
+ }
+ // 엔피씨,엠피씨,의병 사망로그
+ if($general['npc'] == 2 || $general['npc'] == 6) {
+ $alllog[0] = "●>{$admin['month']}월:{$general['name']}>{$josaYi} 사망>했습니다.";
+ } elseif($general['npc'] >= 3) {
+ switch(rand()%10) {
+ case 0: $alllog[0] = "●>{$admin['month']}월:{$general['name']}>{$josaYi} 푸대접에 실망하여 떠났습니다."; break;
+ case 1: $alllog[0] = "●>{$admin['month']}월:{$general['name']}>{$josaYi} 갑자기 화를 내며 떠났습니다."; break;
+ case 2: $alllog[0] = "●>{$admin['month']}월:{$general['name']}>{$josaYi} 의견차이를 좁히지 못하고 떠났습니다."; break;
+ case 3: $alllog[0] = "●>{$admin['month']}월:{$general['name']}>{$josaYi} 판단 착오였다며 떠났습니다."; break;
+ case 4: $alllog[0] = "●>{$admin['month']}월:{$general['name']}>{$josaYi} 생활고가 나아지지 않는다며 떠났습니다."; break;
+ case 5: $alllog[0] = "●>{$admin['month']}월:{$general['name']}>{$josaYi} 기대가 너무 컸다며 떠났습니다."; break;
+ case 6: $alllog[0] = "●>{$admin['month']}월:{$general['name']}>{$josaYi} 아무 이유 없이 떠났습니다."; break;
+ case 7: $alllog[0] = "●>{$admin['month']}월:{$general['name']}>{$josaYi} 자기 목적은 달성했다며 떠났습니다."; break;
+ case 8: $alllog[0] = "●>{$admin['month']}월:{$general['name']}>{$josaYi} 자기가 없어도 될것 같다며 떠났습니다."; break;
+ case 9: $alllog[0] = "●>{$admin['month']}월:{$general['name']}>{$josaYi} 처자식이 그립다며 떠났습니다."; break;
+ }
+ }
+
+ pushGeneralPublicRecord($alllog, $admin['year'], $admin['month']);
+
+ return;
+ }
+ }
+
+ if($general['age'] >= 80 && $general['npc'] == 0) {
+ if($admin['isunited'] == 0) {
+ CheckHall($no);
+ }
+
+ $query = "update general set leader=leader*0.85,power=power*0.85,intel=intel*0.85,injury=0,experience=experience*0.5,dedication=dedication*0.5,firenum=0,warnum=0,killnum=0,deathnum=0,killcrew=0,deathcrew=0,age=20,specage=0,specage2=0,crew=crew*0.85,dex0=dex0*0.5,dex10=dex10*0.5,dex20=dex20*0.5,dex30=dex30*0.5,dex40=dex40*0.5 where no='$no'";
+ MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
+
+ $josaYi = JosaUtil::pick($general['name'], '이');
+ $alllog[0] = "●>{$admin['month']}월:{$general['name']}>{$josaYi} 은퇴>하고 그 자손이 유지를 이어받았습니다.";
+ pushGeneralPublicRecord($alllog, $admin['year'], $admin['month']);
+
+ $log[0] = "●>나이가 들어 은퇴>하고 자손에게 자리를 물려줍니다.";
+ pushGenLog($general, $log);
+ pushGeneralHistory($general, "●>{$admin['year']}년 {$admin['month']}월:나이가 들어 은퇴하고, 자손에게 관직을 물려줌");
+ }
+
+ $turntime = addTurn($general['turntime'], $admin['turnterm']);
+
+ $query = "update general set turntime='$turntime' where no='$no'";
+ MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
+}
+
+function CheckHall($no) {
+ $db = DB::db();
+ $gameStor = KVStorage::getStorage($db, 'game_env');
+
+ $types = array(
+ "experience",
+ "dedication",
+ "firenum",
+ "warnum",
+ "killnum",
+ "winrate",
+ "killcrew",
+ "killrate",
+ "dex0",
+ "dex10",
+ "dex20",
+ "dex30",
+ "dex40",
+ "ttrate",
+ "tlrate",
+ "tprate",
+ "tirate",
+ "betgold",
+ "betwin",
+ "betwingold",
+ "betrate"
+ );
+
+ $general = $db->queryFirstRow('SELECT name,name2,owner,nation,picture,imgsvr,
+ experience,dedication,warnum,firenum,killnum,
+ killnum/warnum as winrate,killcrew,killcrew/deathcrew as killrate,
+ dex0,dex10,dex20,dex30,dex40,
+ ttw/(ttw+ttd+ttl) as ttrate, ttw+ttd+ttl as tt,
+ tlw/(tlw+tld+tll) as tlrate, tlw+tld+tll as tl,
+ tpw/(tpw+tpd+tpl) as tprate, tpw+tpd+tpl as tp,
+ tiw/(tiw+tid+til) as tirate, tiw+tid+til as ti,
+ betgold, betwin, betwingold, betwingold/betgold as betrate
+ from general where no=%i', $no);
+
+ if(!$general){
+ return;
+ }
+
+ $unitedDate = TimeUtil::now();
+ $nation = getNationStaticInfo($general['nation']);
+
+ $serverCnt = $db->queryFirstField('SELECT count(*) FROM ng_games');
+
+ [$scenarioIdx, $scenarioName, $startTime] = $gameStor->getValuesAsArray(['scenario', 'scenario_text', 'starttime']);
+
+ foreach($types as $idx=>$typeName) {
+
+
+ //승률,살상률인데 10회 미만 전투시 스킵
+ if(($typeName === 'winrate' || $typeName === 'killrate') && $general['warnum']<10) { continue; }
+ //토너승률인데 50회 미만시 스킵
+ if($typeName === 'ttrate' && $general['tt'] < 50) { continue; }
+ //토너승률인데 50회 미만시 스킵
+ if($typeName === 'tlrate' && $general['tl'] < 50) { continue; }
+ //토너승률인데 50회 미만시 스킵
+ if($typeName === 'tprate' && $general['tp'] < 50) { continue; }
+ //토너승률인데 50회 미만시 스킵
+ if($typeName === 'tirate' && $general['ti'] < 50) { continue; }
+ //수익률인데 1000미만시 스킵
+ if($typeName === 'betrate' && $general['betgold'] < 1000) { continue; }
+
+ if($general[$typeName]<=0){
+ continue;
+ }
+
+ $aux = [
+ 'name'=>$general['name'],
+ 'nationName'=>$nation['name'],
+ 'bgColor'=>$nation['color'],
+ 'fgColor'=>newColor($nation['color']),
+ 'picture'=>$general['picture'],
+ 'imgsvr'=>$general['imgsvr'],
+ 'startTime'=>$startTime,
+ 'unitedTime'=>$unitedDate,
+ 'owner_name'=>$general['name2'],
+ 'serverID'=>UniqueConst::$serverID,
+ 'serverIdx'=>$serverCnt,
+ 'serverName'=>UniqueConst::$serverName,
+ 'scenarioName'=>$scenarioName,
+ ];
+ $jsonAux = Json::encode($aux);
+
+ $db->insertUpdate('ng_hall', [
+ 'server_id'=>UniqueConst::$serverID,
+ 'scenario'=>$scenarioIdx,
+ 'general_no'=>$no,
+ 'type'=>$idx,
+ 'value'=>$general[$typeName]??0,
+ 'owner'=>$general['owner']??null,
+ 'aux'=>$jsonAux
+ ],[
+ 'value'=>$general[$typeName]??0,
+ 'aux'=>$jsonAux
+ ]);
+ }
+}
+
+function uniqueItemEx(int $generalID, ActionLogger $logger, string $acquireType='아이템'):bool {
+ //TODO: 이름 바꾸기
+ $db = DB::db();
+ $gameStor = KVStorage::getStorage($db, 'game_env');
+
+ $general = $db->queryFirstRow('SELECT no,name,nation,npc,weap,book,horse,item FROM general WHERE no=%i', $generalID);
+ if(!$general){
+ return false;
+ }
+
+ if($general['npc'] >= 2) {
+ return false;
+ }
+ if($general['horse'] > 6 || $general['weap'] > 6 || $general['book'] > 6 || $general['item'] > 6){
+ return false;
+ }
+
+ $scenario = $gameStor->scenario;
+
+ $genCount = $db->queryFirstField('SELECT count(*) FROM general WHERE npc<2');
+
+ if ($scenario < 100) {
+ $prob = 1 / ($genCount * 5); // 5~6개월에 하나씩 등장
+ }
+ else {
+ $prob = 1 / $genCount; // 1~2개월에 하나씩 등장
+ }
+
+ if($acquireType == '투표'){
+ $prob = 1 / ($genCount * 0.7 / 3); // 투표율 70%, 투표 한번에 2~3개 등장
+ }
+ else if($acquireType == '랜덤 임관'){
+ $prob = 1 / ($genCount / 10/ 2); // 랜임시 2개(10%) 등장(200명중 20명 랜임시도?)
+ }
+ else if($acquireType == '건국'){
+ $prob = 1 / ($genCount / 10/ 4); // 건국시 4개(20%) 등장(200명시 20국 정도 됨)
+ }
+
+ $prob = Util::valueFit($prob, 1/3, 1);
+
+ if(!Util::randBool($prob)){
+ return false;
+ }
+
+ //아이템 습득 상황
+ $availableUnique = [];
+ $itemTypes = [
+ 'horse'=>'getHorseName',
+ 'weap'=>'getWeapName',
+ 'book'=>'getBookName',
+ 'item'=>'getItemName'
+ ];
+ $itemCodeList = range(7, 26); // [7, 26] 20개
+
+ foreach($itemTypes as $itemType=>$itemNameFunc){
+ foreach($itemCodeList as $itemCode){
+ $availableUnique["{$itemType}_{$itemCode}"] = [$itemType, $itemCode];
+ }
+ }
+
+ //TODO: 너무 바보 같다. 장기적으로는 유니크 아이템 테이블 같은게 필요하지 않을까?
+ foreach ($itemTypes as $itemType=>$itemNameFunc) {
+ foreach($db->queryFirstColumn('SELECT %b FROM general WHERE %b > 6', $itemType, $itemType) as $itemCode){
+ unset($availableUnique["{$itemType}_{$itemCode}"]);
+ }
+ }
+
+ if(!$availableUnique){
+ return false;
+ }
+
+ [$itemType, $itemCode] = Util::choiceRandom($availableUnique);
+
+ $nationName = getNationStaticInfo($general['nation'])['name'];
+ $generalName = $general['name'];
+ $josaYi = JosaUtil::pick($generalName, '이');
+ $itemName = ($itemTypes[$itemType])($itemCode);
+ $josaUl = JosaUtil::pick($itemName, '을');
+
+
+ $db->update('general', [
+ $itemType=>$itemCode
+ ], 'no=%i', $generalID);
+
+ $logger->pushGeneralActionLog("{$itemName}>{$josaUl} 습득했습니다!");
+ $logger->pushGlobalActionLog("{$generalName}>{$josaYi} {$itemName}>{$josaUl} 습득했습니다!");
+ $logger->pushGlobalHistoryLog("【{$acquireType}】 >{$nationName} >의 {$generalName}>{$josaYi} {$itemName}>{$josaUl} 습득했습니다!");
+
+ return true;
+}
+
+function uniqueItem($general, $log, $vote=0) {
+ //TODO: uniqueItem 을 쓰는 경우를 모두 제거.
+ $db = DB::db();
+ $gameStor = KVStorage::getStorage($db, 'game_env');
+ $connect=$db->get();
+ $alllog = [];
+ $history = [];
+ $occupied = [];
+ $item = [];
+
+ if($general['npc'] >= 2) { return $log; }
+ if($general['weap'] > 6 || $general['book'] > 6 || $general['horse'] > 6 || $general['item'] > 6) { return $log; }
+
+ $admin = $gameStor->getValues(['year', 'month', 'scenario']);
+
+ $query = "select count(*) as cnt from general where npc<2";
+ $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
+ $gen = MYDB_fetch_array($result);
+
+ if($admin['scenario'] < 100) { $prob = $gen['cnt'] * 5; } // 5~6개월에 하나씩 등장
+ else { $prob = $gen['cnt']; } // 1~2개월에 하나씩 등장
+
+ if($vote == 1) { $prob = Util::round($gen['cnt'] * 0.7 / 3); } // 투표율 70%, 투표 한번에 2~3개 등장
+ elseif($vote == 2) { $prob = Util::round($gen['cnt'] / 10 / 2); } // 랜임시 2개(10%) 등장(200명중 20명 랜임시도?)
+ elseif($vote == 3) { $prob = Util::round($gen['cnt'] / 10 / 4); } // 건국시 4개(20%) 등장(200명시 20국 정도 됨)
+
+ if($prob < 3) { $prob = 3; }
+ //아이템 습득 상황
+ if(rand() % $prob == 0) {
+ //셋중 선택
+ $sel = rand() % 4;
+ switch($sel) {
+ case 0: $type = "weap"; break;
+ case 1: $type = "book"; break;
+ case 2: $type = "horse"; break;
+ case 3: $type = "item"; break;
+ }
+ $query = "select no,{$type} from general where {$type}>6";
+ $result = MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
+ $count = MYDB_num_rows($result);
+ if($count < 20) {
+ for($i=0; $i < $count; $i++) {
+ $gen = MYDB_fetch_array($result);
+ $occupied[$gen[$type]] = 1;
+ }
+ for($i=7; $i <= 26; $i++) {
+ if(!Util::array_get($occupied[$i])) {
+ $item[] = $i;
+ }
+ }
+ $it = $item[rand() % count($item)]??0;
+
+ $query = "update general set {$type}='$it' where no='{$general['no']}'";
+ MYDB_query($query, $connect) or Error(__LINE__.MYDB_error($connect),"");
+
+ $nation = getNationStaticInfo($general['nation']);
+
+ switch($sel) {
+ case 0:
+ $josaUl = JosaUtil::pick(getWeapName($it), '을');
+ $josaYi = JosaUtil::pick($general['name'], '이');
+ $log[] = "●>".getWeapName($it).">{$josaUl} 습득했습니다!";
+ $alllog[0] = "●>{$admin['month']}월:{$general['name']}>{$josaYi} ".getWeapName($it).">{$josaUl} 습득했습니다!";
+ pushGeneralHistory($general, "●>{$admin['year']}년 {$admin['month']}월:".getWeapName($it).">{$josaUl} 습득");
+ if($vote == 0) {
+ $history[] = "●>{$admin['year']}년 {$admin['month']}월:【아이템】 >{$nation['name']} >의 {$general['name']}>{$josaYi} ".getWeapName($it).">{$josaUl} 습득했습니다!";
+ } elseif($vote == 1) {
+ $history[] = "●>{$admin['year']}년 {$admin['month']}월:【설문상품】 >{$nation['name']} >의 {$general['name']}>{$josaYi} ".getWeapName($it).">{$josaUl} 습득했습니다!";
+ } elseif($vote == 2) {
+ $history[] = "●>{$admin['year']}년 {$admin['month']}월:【랜덤임관상품】 >{$nation['name']} >의 {$general['name']}>{$josaYi} ".getWeapName($it).">{$josaUl} 습득했습니다!";
+ } elseif($vote == 3) {
+ $history[] = "●>{$admin['year']}년 {$admin['month']}월:【건국상품】 >{$nation['name']} >의 {$general['name']}>{$josaYi} ".getWeapName($it).">{$josaUl} 습득했습니다!";
+ }
+ break;
+ case 1:
+ $josaUl = JosaUtil::pick(getBookName($it), '을');
+ $josaYi = JosaUtil::pick($general['name'], '이');
+ $log[] = "●>".getBookName($it).">{$josaUl} 습득했습니다!";
+ $alllog[0] = "●>{$admin['month']}월:{$general['name']}>{$josaYi} ".getBookName($it).">{$josaUl} 습득했습니다!";
+ pushGeneralHistory($general, "●>{$admin['year']}년 {$admin['month']}월:".getBookName($it).">{$josaUl} 습득");
+ if($vote == 0) {
+ $history[] = "●>{$admin['year']}년 {$admin['month']}월:【아이템】 >{$nation['name']} >의 {$general['name']}>{$josaYi} ".getBookName($it).">{$josaUl} 습득했습니다!";
+ } elseif($vote == 1) {
+ $history[] = "●>{$admin['year']}년 {$admin['month']}월:【설문상품】 >{$nation['name']} >의 {$general['name']}>{$josaYi} ".getBookName($it).">{$josaUl} 습득했습니다!";
+ } elseif($vote == 2) {
+ $history[] = "●>{$admin['year']}년 {$admin['month']}월:【랜덤임관상품】 >{$nation['name']} >의 {$general['name']}>{$josaYi} ".getBookName($it).">{$josaUl} 습득했습니다!";
+ } elseif($vote == 3) {
+ $history[] = "●>{$admin['year']}년 {$admin['month']}월:【건국상품】 >{$nation['name']} >의 {$general['name']}>{$josaYi} ".getBookName($it).">{$josaUl} 습득했습니다!";
+ }
+ break;
+ case 2:
+ $josaUl = JosaUtil::pick(getHorseName($it), '을');
+ $josaYi = JosaUtil::pick($general['name'], '이');
+ $log[] = "●>