From 6f5d7ff84bf79b747ec12e58e33962e980ae7969 Mon Sep 17 00:00:00 2001 From: Hide_D Date: Thu, 9 Mar 2023 02:25:31 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20Vue3=EB=A1=9C=20=EC=83=88=EB=A1=AD?= =?UTF-8?q?=EA=B2=8C=20=EC=9E=91=EC=84=B1=ED=95=9C=20=EB=A9=94=EC=9D=B8=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=20(#229)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - v_front.php - API 추가 - General/GetFrontInfo - Global/GetGlobalMenu - DTO 추가 - MenuItem, MenuMulti, MenuSplit - 글로벌 메뉴 출력 방식 변경 - d_setting/GlobalMenu.php Reviewed-on: https://storage.hided.net/gitea/devsam/core/pulls/229 --- hwe/d_setting/GlobalMenu.orig.php | 53 ++ hwe/sammo/API/General/GetFrontInfo.php | 574 ++++++++++++++++ hwe/sammo/API/Global/GetGlobalMenu.php | 47 ++ hwe/sammo/API/Global/GetRecentRecord.php | 70 +- hwe/sammo/API/Message/SendMessage.php | 4 + hwe/sammo/API/Nation/GetNationInfo.php | 9 +- hwe/sammo/DTO/MenuItem.php | 26 + hwe/sammo/DTO/MenuMulti.php | 20 + hwe/sammo/DTO/MenuSplit.php | 20 + hwe/sammo/General.php | 2 +- hwe/sammo/GlobalMenu.php | 53 ++ hwe/scss/gameEvent.scss | 28 + hwe/scss/map.scss | 2 + hwe/ts/PageFront.vue | 621 ++++++++++++++++++ hwe/ts/SammoAPI.ts | 16 +- hwe/ts/build_exports.json | 3 +- hwe/ts/components/AutorunInfo.vue | 63 ++ hwe/ts/components/CityBasicCard.vue | 228 +++++++ hwe/ts/components/GameBottomBar.vue | 192 ++++++ hwe/ts/components/GameInfo.vue | 155 +++++ hwe/ts/components/GlobalMenu.vue | 154 +++++ hwe/ts/components/GlobalMenuDropdown.vue | 116 ++++ hwe/ts/components/MainControlBar.vue | 116 ++++ hwe/ts/components/MainControlDropdown.vue | 69 ++ hwe/ts/components/MessagePanel.vue | 755 ++++++++++++++++++++++ hwe/ts/components/MessagePlate.vue | 360 +++++++++++ hwe/ts/components/NationBasicCard.vue | 198 ++++++ hwe/ts/defs/API/Global.ts | 310 ++++++--- hwe/ts/defs/API/Nation.ts | 21 +- hwe/ts/util/Entries.ts | 3 + hwe/ts/utilGame/formatTournament.ts | 35 + hwe/ts/utilGame/index.ts | 3 +- hwe/ts/utilGame/tournament.ts | 4 + hwe/ts/v_front.ts | 13 + hwe/v_front.php | 44 ++ 35 files changed, 4260 insertions(+), 127 deletions(-) create mode 100644 hwe/d_setting/GlobalMenu.orig.php create mode 100644 hwe/sammo/API/General/GetFrontInfo.php create mode 100644 hwe/sammo/API/Global/GetGlobalMenu.php create mode 100644 hwe/sammo/DTO/MenuItem.php create mode 100644 hwe/sammo/DTO/MenuMulti.php create mode 100644 hwe/sammo/DTO/MenuSplit.php create mode 100644 hwe/sammo/GlobalMenu.php create mode 100644 hwe/scss/gameEvent.scss create mode 100644 hwe/ts/PageFront.vue create mode 100644 hwe/ts/components/AutorunInfo.vue create mode 100644 hwe/ts/components/CityBasicCard.vue create mode 100644 hwe/ts/components/GameBottomBar.vue create mode 100644 hwe/ts/components/GameInfo.vue create mode 100644 hwe/ts/components/GlobalMenu.vue create mode 100644 hwe/ts/components/GlobalMenuDropdown.vue create mode 100644 hwe/ts/components/MainControlBar.vue create mode 100644 hwe/ts/components/MainControlDropdown.vue create mode 100644 hwe/ts/components/MessagePanel.vue create mode 100644 hwe/ts/components/MessagePlate.vue create mode 100644 hwe/ts/components/NationBasicCard.vue create mode 100644 hwe/ts/util/Entries.ts create mode 100644 hwe/ts/utilGame/formatTournament.ts create mode 100644 hwe/ts/utilGame/tournament.ts create mode 100644 hwe/ts/v_front.ts create mode 100644 hwe/v_front.php diff --git a/hwe/d_setting/GlobalMenu.orig.php b/hwe/d_setting/GlobalMenu.orig.php new file mode 100644 index 00000000..d064a2f4 --- /dev/null +++ b/hwe/d_setting/GlobalMenu.orig.php @@ -0,0 +1,53 @@ +args); + $v->rule('lengthMin', 'lastNationNoticeDate', 19) + ->rule('integer', 'lastGeneralRecordID') + ->rule('integer', 'lastWorldHistoryID'); + if (!$v->validate()) { + return $v->errorStr(); + } + $this->args['lastGeneralRecordID'] = (int)($this->args['lastGeneralRecordID'] ?? 0); + $this->args['lastWorldHistoryID'] = (int)($this->args['lastWorldHistoryID'] ?? 0); + return null; + } + + private function getGlobalRecord(int $lastRecordID): array + { + $db = DB::db(); + + $globalRecord = $db->queryAllLists( + 'SELECT id, `text` FROM general_record WHERE `general_id` = 0 AND log_type = %s AND id >= %i ORDER BY `id` DESC LIMIT %i', + 'history', + $lastRecordID, + static::ROW_LIMIT + 1, + ); + return $globalRecord; + } + + private function getGeneralRecord(int $generalID, int $lastRecordID): array + { + $db = DB::db(); + + $generalRecord = $db->queryAllLists( + 'SELECT id, `text` FROM general_record WHERE `general_id` = %i AND log_type = %s AND id >= %i ORDER BY `id` DESC LIMIT %i', + $generalID, + 'action', + $lastRecordID, + static::ROW_LIMIT + 1, + ); + return $generalRecord; + } + + private function getHistory(int $lastHistoryID): array + { + $db = DB::db(); + + $history = $db->queryAllLists( + 'SELECT id, `text` FROM world_history WHERE nation_id = 0 AND id >= %i ORDER BY `id` DESC LIMIT %i', + $lastHistoryID, + static::ROW_LIMIT + 1, + ); + return $history; + } + + private function generateRecentRecord(int $generalID){ + $db = DB::db(); + + $gameStor = KVStorage::getStorage($db, 'game_env'); + $gameStor->cacheValues(['isunited', 'opentime', 'refresh']); + + $lastHistoryID = $this->args['lastWorldHistoryID']; + $lastRecordID = $this->args['lastGeneralRecordID']; + + $history = $this->getHistory($lastHistoryID); + $globalRecord = $this->getGlobalRecord($lastRecordID); + $generalRecord = $this->getGeneralRecord($generalID, $lastRecordID); + + $flushHistory = false; + $flushGlobalRecord = false; + $flushGeneralRecord = false; + + if (!$history) { + $flushHistory = false; + } else if (Util::array_last($history)[0] <= $lastHistoryID) { + $flushHistory = false; + array_pop($history); + } else if (count($history) > static::ROW_LIMIT) { + array_pop($history); + } + + if (!$globalRecord) { + $flushGlobalRecord = false; + } else if (Util::array_last($globalRecord)[0] == $lastRecordID) { + $flushGlobalRecord = false; + array_pop($globalRecord); + } else if (count($globalRecord) > static::ROW_LIMIT) { + array_pop($globalRecord); + } + + if (!$generalRecord) { + $flushGeneralRecord = false; + } else if (Util::array_last($generalRecord)[0] == $lastRecordID) { + $flushGeneralRecord = false; + array_pop($generalRecord); + } else if (count($generalRecord) > static::ROW_LIMIT) { + array_pop($generalRecord); + } + + return [ + 'history' => $history, + 'global' => $globalRecord, + 'general' => $generalRecord, + 'flushHistory' => $flushHistory ? 1 : 0, + 'flushGlobal' => $flushGlobalRecord ? 1 : 0, + 'flushGeneral' => $flushGeneralRecord ? 1 : 0, + ]; + } + + private function generateGlobalInfo(MeekroDB $db): array + { + $gameStor = KVStorage::getStorage($db, 'game_env'); + + [ + $scenarioText, $extendedGeneral, $isFiction, $npcMode, + $joinMode, $autorunUser, $turnterm, $lastExecuted, + $lastVoteID, $develCost, $noticeMsg, + $onlineNations, $onlineUserCnt, + $year, $month, $startYear, + $generalCntLimit, + $apiLimit, + $serverCnt, + ] = $gameStor->getValuesAsArray([ + 'scenario_text', 'extended_general', 'fiction', 'npcmode', + 'join_mode', 'autorun_user', 'turnterm', 'turntime', + 'lastVote', 'develcost', 'msg', + 'online_nation', 'online_user_cnt', + 'year', 'month', 'startyear', + 'maxgeneral', + 'conlimit', + 'server_cnt', + ]); + + $lastVote = null; + if ($lastVoteID) { + $voteStor = KVStorage::getStorage($db, 'vote'); + $lastVote = VoteInfo::fromArray($voteStor->getValue("vote_{$lastVoteID}")); + if ($lastVote->endDate && $lastVote->endDate < TimeUtil::now()) { + $lastVote = null; + } + } + + $auctionCount = $db->queryFirstField('SELECT count(*) FROM ng_auction WHERE finished = 0'); + $isTournamentActive = $gameStor->tournament > 0; + $isTournamentApplicationOpen = $gameStor->tournament == 1; + $isBettingActive = $gameStor->tournament == 6; + $tournamentType = $gameStor->tnmt_type; + $tournamentState = $gameStor->tournament; + $tournamentTime = $gameStor->tnmt_time; + $isLocked = boolval($db->queryFirstField('SELECT plock FROM plock WHERE `type`="GAME" LIMIT 1')); + + $globalGenCount = $db->queryAllLists('SELECT npc, count(no) FROM general GROUP BY npc'); + + return [ + 'scenarioText' => $scenarioText, + 'extendedGeneral' => $extendedGeneral, + 'isFiction' => $isFiction, + 'npcMode' => $npcMode, + 'joinMode' => $joinMode, + 'startyear' => $startYear, + 'year' => $year, + 'month' => $month, + 'autorunUser' => $autorunUser, + 'turnterm' => $turnterm, + 'lastExecuted' => $lastExecuted, + 'lastVoteID' => $lastVoteID, + 'develCost' => $develCost, + 'noticeMsg' => $noticeMsg, + 'onlineNations' => $onlineNations, + 'onlineUserCnt' => $onlineUserCnt, + 'apiLimit' => $apiLimit, + 'auctionCount' => $auctionCount, + 'isTournamentActive' => $isTournamentActive, + 'isTournamentApplicationOpen' => $isTournamentApplicationOpen, + 'isBettingActive' => $isBettingActive, + 'isLocked' => $isLocked, + 'tournamentType' => $tournamentType, + 'tournamentState' => $tournamentState, + 'tournamentTime' => $tournamentTime, + 'genCount' => $globalGenCount, + 'generalCntLimit' => $generalCntLimit, + 'serverCnt' => $serverCnt, + 'lastVote' => $lastVote === null ? null : $lastVote->toArray(), + ]; + } + + public function generateNationInfo(MeekroDB $db, General $general, array $rawNation): array + { + $gameStor = KVStorage::getStorage($db, 'game_env'); + $admin = $gameStor->getAll(true); + + $lastNationNoticeDate = $this->args['lastNationNoticeDate'] ?? '2022-08-19 00:00:00'; + + $nationID = $general->getNationID(); + + //XXX: 매번 더하는가? + $nationPopulation = $db->queryFirstRow( + 'SELECT COUNT(*) as cityCnt, CAST(SUM(pop) AS INTEGER) as `now`, CAST(SUM(pop_max) AS INTEGER) as `max` from city where nation=%i', + $nationID + ); + + //XXX: 매번 더하는가? + $nationCrew = $db->queryFirstRow( + 'SELECT COUNT(*) as generalCnt, CAST(SUM(crew) AS INTEGER) as `now`,CAST(SUM(leadership)*100 AS INTEGER) as `max` from general where nation=%i AND npc != 5', + $nationID + ); + + $nationStor = KVStorage::getStorage($db, $nationID, 'nation_env'); + [$nationNotice, $onlineGen] = $nationStor->getValuesAsArray(['nationNotice', 'online_genenerals']); + if (!$nationNotice || ($nationNotice['date'] ?? '') <= $lastNationNoticeDate) { + $nationNotice = null; + } + + $topChiefs = Util::convertArrayToDict($db->query( + 'SELECT officer_level, no, name, npc FROM general WHERE nation = %i AND officer_level >= 11', + $nationID + ), 'officer_level'); + + $impossibleStrategicCommandLists = []; + $strategicCommandLists = GameConst::$availableChiefCommand['전략']; + $yearMonth = Util::joinYearMonth($admin['year'], $admin['month']); + foreach ($strategicCommandLists as $command) { + $cmd = buildNationCommandClass($command, $general, $admin, new LastTurn()); + $nextAvailableTurn = $cmd->getNextAvailableTurn(); + if ($nextAvailableTurn > $yearMonth) { + $impossibleStrategicCommandLists[] = [$cmd->getName(), $nextAvailableTurn - $yearMonth]; + } + } + + $nationClass = buildNationTypeClass($rawNation['type']); + + return [ + 'id' => $nationID, + 'full' => true, + 'name' => $rawNation['name'], + 'population' => $nationPopulation, + 'crew' => $nationCrew, + 'type' => [ + 'raw' => $rawNation['type'], + 'name' => $nationClass->getName(), + 'pros' => $nationClass::$pros, + 'cons' => $nationClass::$cons, + ], + 'color' => $rawNation['color'], + 'level' => $rawNation['level'], + 'capital' => $rawNation['capital'], + 'gold' => $rawNation['gold'], + 'rice' => $rawNation['rice'], + 'tech' => $rawNation['tech'], + 'gennum' => $rawNation['gennum'], + 'power' => $rawNation['power'], + + 'bill' => $rawNation['bill'], + 'taxRate' => $rawNation['rate'], + 'onlineGen' => $onlineGen, + 'notice' => $nationNotice, + 'topChiefs' => $topChiefs, + + 'diplomaticLimit' => $rawNation['surlimit'], + 'strategicCmdLimit' => $rawNation['strategic_cmd_limit'], + 'impossibleStrategicCommand' => $impossibleStrategicCommandLists, + + 'prohibitScout' => $rawNation['scout'], + 'prohibitWar' => $rawNation['war'], + ]; + } + + public function generateDummyNationInfo(MeekroDB $db, General $general, array $rawNation): array + { + $staticInfo = getNationStaticInfo(0); + return [ + 'id' => 0, + 'full' => false, + 'name' => $staticInfo['name'], + 'population' => [ + 'cityCnt' => 0, + 'now' => 0, + 'max' => 0, + ], + 'crew' => [ + 'generalCnt' => 0, + 'now' => 0, + 'max' => 0, + ], + 'type' => [ + 'raw' => 'None', + 'name' => '-', + 'pros' => '', + 'cons' => '', + ], + 'color' => $staticInfo['color'], + 'level' => $staticInfo['level'], + 'capital' => $staticInfo['capital'], + 'gold' => $staticInfo['gold'], + 'rice' => $staticInfo['rice'], + 'tech' => $staticInfo['tech'], + 'gennum' => $staticInfo['gennum'], + 'power' => $staticInfo['power'], + 'onlineGen' => '', //TODO 접속자 + 'notice' => '', + 'topChiefs' => [], + 'impossibleStrategicCommand' => [], + ]; + } + + public function generateGeneralInfo(MeekroDB $db, General $general, array $rawNation): array + { + + $permission = checkSecretPermission($general->getRaw()); + + $result = [ + 'no' => $general->getID(), // number; + 'name' => $general->getName(), // string; + 'nation' => $general->getNationID(), // number; + 'npc' => $general->getNPCType(), // number; + 'injury' => $general->getVar(GeneralColumn::injury), // number; + 'leadership' => $general->getVar(GeneralColumn::leadership), // number; + 'strength' => $general->getVar('strength'), // number; + 'intel' => $general->getVar('intel'), // number; + 'explevel' => $general->getVar('explevel'), // number; + 'dedlevel' => $general->getVar('dedlevel'), // number; + 'gold' => $general->getVar('gold'), // number; + 'rice' => $general->getVar('rice'), // number; + 'killturn' => $general->getVar(GeneralColumn::killturn), // number; + 'picture' => $general->getVar(GeneralColumn::picture), // string; + 'imgsvr' => $general->getVar(GeneralColumn::imgsvr), // 0 | 1; + 'age' => $general->getVar(GeneralColumn::age), // number; + 'specialDomestic' => $general->getVar(GeneralColumn::special), // GameObjClassKey; + 'specialWar' => $general->getVar(GeneralColumn::special2), // GameObjClassKey; + 'personal' => $general->getVar(GeneralColumn::personal), // GameObjClassKey; + 'belong' => $general->getVar(GeneralColumn::belong), // number; + 'connect' => $general->getVar(GeneralColumn::connect), // number; + + 'officerLevel' => $general->getVar(GeneralColumn::officer_level), // number; + 'officerLevelText' => getOfficerLevelText($general->getVar(GeneralColumn::officer_level), $rawNation['level']), // string; + 'lbonus' => calcLeadershipBonus($general->getVar(GeneralColumn::officer_level), $rawNation['level']), // number; + 'ownerName' => $general->getVar(GeneralColumn::owner_name), // string | null; + 'honorText' => getHonor($general->getVar(GeneralColumn::experience)), // string; + 'dedLevelText' => getDed($general->getVar(GeneralColumn::dedication)), // string; + 'bill' => getBillByLevel($general->getVar(GeneralColumn::dedlevel)), // number; + 'reservedCommand' => null, // TurnObj[] | null; + + 'autorun_limit' => $general->getAuxVar('autorun_limit') ?? 0, // number; + + 'city' => $general->getVar(GeneralColumn::city), // number; + 'troop' => $general->getVar(GeneralColumn::troop), // number; + //P0 End + + 'con' => $general->getVar(GeneralColumn::con), // number; + 'specage' => $general->getVar(GeneralColumn::specage), // number; + 'specage2' => $general->getVar(GeneralColumn::specage2), // number; + 'leadership_exp' => $general->getVar(GeneralColumn::leadership_exp), // number; + 'strength_exp' => $general->getVar(GeneralColumn::strength_exp), // number; + 'intel_exp' => $general->getVar(GeneralColumn::intel_exp), // number; + + 'dex1' => $general->getVar(GeneralColumn::dex1), // number; + 'dex2' => $general->getVar(GeneralColumn::dex2), // number; + 'dex3' => $general->getVar(GeneralColumn::dex3), // number; + 'dex4' => $general->getVar(GeneralColumn::dex4), // number; + 'dex5' => $general->getVar(GeneralColumn::dex5), // number; + + 'experience' => $general->getVar(GeneralColumn::experience), // number; + 'dedication' => $general->getVar(GeneralColumn::dedication), // number; + 'officer_level' => $general->getVar(GeneralColumn::officer_level), // number; + 'officer_city' => $general->getVar(GeneralColumn::officer_city), // number; + 'defence_train' => $general->getVar(GeneralColumn::defence_train), // number; + 'crewtype' => $general->getVar(GeneralColumn::crewtype), // GameObjClassKey; + 'crew' => $general->getVar(GeneralColumn::crew), // number; + 'train' => $general->getVar(GeneralColumn::train), // number; + 'atmos' => $general->getVar(GeneralColumn::atmos), // number; + 'turntime' => $general->getVar(GeneralColumn::turntime), // string; + 'recent_war' => $general->getVar(GeneralColumn::recent_war), // string; + 'horse' => $general->getVar(GeneralColumn::horse), // GameObjClassKey; + 'weapon' => $general->getVar(GeneralColumn::weapon), // GameObjClassKey; + 'book' => $general->getVar(GeneralColumn::book), // GameObjClassKey; + 'item' => $general->getVar(GeneralColumn::item), // GameObjClassKey; + + 'warnum' => $general->getRankVar(RankColumn::warnum), // number; + 'killnum' => $general->getRankVar(RankColumn::killnum), // number; + 'deathnum' => $general->getRankVar(RankColumn::deathnum), // number; + 'killcrew' => $general->getRankVar(RankColumn::killcrew), // number; + 'deathcrew' => $general->getRankVar(RankColumn::deathcrew), // number; + 'firenum' => $general->getRankVar(RankColumn::firenum), // number; + //P1 End + + 'permission' => $permission, + ]; + + $nationID = $general->getNationID(); + $troopID = $general->getVar(GeneralColumn::troop); + if (!$troopID) { + return $result; + } + + $troopName = $db->queryFirstField( + 'SELECT `name` FROM troop WHERE nation = %i AND troop_leader = %i', + $nationID, + $troopID + ); + if (!$troopName) { + return $result; + } + + $troopCityID = $db->queryFirstField( + 'SELECT city FROM general WHERE nation = %i AND `no` = %i', + $nationID, + $troopID + ); + if (!$troopCityID) { + return $result; + } + + $troopReservedCommand = $db->query( + 'SELECT action, arg, brief FROM general_turn WHERE general_id = %i AND turn_idx < 5 ORDER BY turn_idx asc', + $troopID + ); + if ($troopReservedCommand) { + return $result; + } + + $result['troopInfo'] = [ + 'leader' => [ + 'city' => $troopCityID, + 'reservedCommand' => $troopReservedCommand, + ], + 'name' => $troopName, + ]; + + return $result; + } + + public function generateCityInfo(MeekroDB $db, General $general, array $rawNation): array + { + $rawCity = $general->getRawCity() ?? []; + $cityID = $rawCity[CityColumn::city->value]; + + $nationID = $rawCity[CityColumn::nation->value]; + if ($nationID == $general->getNationID()) { + $nationName = $rawNation['name']; + $nationColor = $rawNation['color']; + } else { + $staticNation = getNationStaticInfo($nationID); + $nationName = $staticNation['name']; + $nationColor = $staticNation['color']; + } + + $rawOfficerList = $db->query('SELECT officer_level, name, npc FROM general WHERE officer_city = %i AND officer_level IN (4,3,2)', $cityID); + $officerList = [4 => null, 3 => null, 2 => null]; + foreach ($rawOfficerList as $officer) { + $officerLevel = $officer['officer_level']; + $officerList[$officerLevel] = $officer; + } + + $result = [ + 'id' => $rawCity[CityColumn::city->value], + 'name' => $rawCity[CityColumn::name->value], + 'nationInfo' => [ + 'id' => $nationID, + 'name' => $nationName, + 'color' => $nationColor, + ], + 'level' => $rawCity[CityColumn::level->value], + 'trust' => $rawCity[CityColumn::trust->value], + 'pop' => [$rawCity[CityColumn::pop->value], $rawCity[CityColumn::pop_max->value]], + 'agri' => [$rawCity[CityColumn::agri->value], $rawCity[CityColumn::agri_max->value]], + 'comm' => [$rawCity[CityColumn::comm->value], $rawCity[CityColumn::comm_max->value]], + 'secu' => [$rawCity[CityColumn::secu->value], $rawCity[CityColumn::secu_max->value]], + 'def' => [$rawCity[CityColumn::def->value], $rawCity[CityColumn::def_max->value]], + 'wall' => [$rawCity[CityColumn::wall->value], $rawCity[CityColumn::wall_max->value]], + 'trade' => $rawCity[CityColumn::trade->value], + 'officerList' => $officerList, + ]; + return $result; + } + + public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag) + { + $generalID = $session->generalID; + //NOTE: 이 경우 staticNation 정보를 조회한다. + $general = General::createGeneralObjFromDB($generalID); + $nationID = $general->getNationID(); + $cityID = $general->getCityID(); + + $con = checkLimit($general->getVar('con')); + if ($con >= 2) { + return [ + 'result' => false, + 'reason' => '접속 제한중입니다.', + 'recovery' => APIRecoveryType::GameQuota, + 'recovery_arg' => $general->getVar('turntime'), + ]; + } + + $db = DB::db(); + $gameStor = KVStorage::getStorage($db, 'game_env'); + $gameStor->cacheAll(true); + + increaseRefresh("General/GetFrontInfo", 1); + + $rawCity = $db->queryFirstRow('SELECT * FROM city WHERE city = %i', $cityID); + $general->setRawCity($rawCity); + + if ($nationID == 0) { + $rawNation = getNationStaticInfo(0); + } else { + $rawNation = $db->queryFirstRow('SELECT * FROM nation WHERE nation = %i', $nationID); + } + + $globalInfo = $this->generateGlobalInfo($db); + $nationInfo = $nationID != 0 ? + $this->generateNationInfo($db, $general, $rawNation) : + $this->generateDummyNationInfo($db, $general, $rawNation); + $generalInfo = $this->generateGeneralInfo($db, $general, $rawNation); + $cityInfo = $this->generateCityInfo($db, $general, $rawNation); + + //TODO: 마지막 투표, 토너먼트, 베팅을 했는지 정보를 별도로 가져와야 함. aux? + + + return [ + 'result' => true, + 'recentRecord' => $this->generateRecentRecord($generalID), + 'global' => $globalInfo, + 'nation' => $nationInfo, + 'general' => $generalInfo, + 'city' => $cityInfo, + ]; + } +} diff --git a/hwe/sammo/API/Global/GetGlobalMenu.php b/hwe/sammo/API/Global/GetGlobalMenu.php new file mode 100644 index 00000000..bb2507b9 --- /dev/null +++ b/hwe/sammo/API/Global/GetGlobalMenu.php @@ -0,0 +1,47 @@ + true, + 'menu' => array_map(function (DTO $dto) { + return $dto->toArray(); + }, GlobalMenu::getMenu()), + ]; + } + public function tryCache(): ?APICacheResult + { + $version = GlobalMenu::version; + return new APICacheResult( + null, + "v{$version}", + 60 * 60 * 6, + true + ); + } +} diff --git a/hwe/sammo/API/Global/GetRecentRecord.php b/hwe/sammo/API/Global/GetRecentRecord.php index ecae8dd8..fdc8d865 100644 --- a/hwe/sammo/API/Global/GetRecentRecord.php +++ b/hwe/sammo/API/Global/GetRecentRecord.php @@ -5,24 +5,26 @@ namespace sammo\API\Global; use sammo\Session; use DateTimeInterface; use sammo\DB; +use sammo\KVStorage; use sammo\Util; use sammo\Validator; class GetRecentRecord extends \sammo\BaseAPI { + static bool $allowExternalAPI = false; const ROW_LIMIT = 15; public function validateArgs(): ?string { $v = new Validator($this->args); - $v->rule('int', 'lastGeneralRecordID') - ->rule('int', 'lastWorldHistoryID'); + $v->rule('integer', 'lastGeneralRecordID') + ->rule('integer', 'lastWorldHistoryID'); if (!$v->validate()) { return $v->errorStr(); } - $this->args['lastGeneralRecordID'] = (int)($this->args['lastGeneralRecordID']??0); - $this->args['lastWorldHistoryID'] = (int)($this->args['lastWorldHistoryID']??0); + $this->args['lastGeneralRecordID'] = (int)($this->args['lastGeneralRecordID'] ?? 0); + $this->args['lastWorldHistoryID'] = (int)($this->args['lastWorldHistoryID'] ?? 0); return null; } @@ -74,6 +76,9 @@ class GetRecentRecord extends \sammo\BaseAPI { $db = DB::db(); + $gameStor = KVStorage::getStorage($db, 'game_env'); + $gameStor->cacheValues(['isunited', 'opentime', 'refresh']); + $lastHistoryID = $this->args['lastWorldHistoryID']; $lastRecordID = $this->args['lastGeneralRecordID']; @@ -81,38 +86,35 @@ class GetRecentRecord extends \sammo\BaseAPI $globalRecord = $this->getGlobalRecord($lastRecordID); $generalRecord = $this->getGeneralRecord($session->generalID, $lastRecordID); - $flushHistory = true; - $flushGlobalRecord = true; - $flushGeneralRecord = true; + $flushHistory = false; + $flushGlobalRecord = false; + $flushGeneralRecord = false; - if($history){ - if(Util::array_last($history)[0] == $lastHistoryID){ - $flushHistory = false; - array_pop($history); - } - else if(count($history) > static::ROW_LIMIT){ - array_pop($history); - } + if (!$history) { + $flushHistory = false; + } else if (Util::array_last($history)[0] <= $lastHistoryID) { + $flushHistory = false; + array_pop($history); + } else if (count($history) > static::ROW_LIMIT) { + array_pop($history); } - if($globalRecord){ - if(Util::array_last($globalRecord)[0] == $lastRecordID){ - $flushGlobalRecord = false; - array_pop($globalRecord); - } - else if(count($globalRecord) > static::ROW_LIMIT){ - array_pop($globalRecord); - } + if (!$globalRecord) { + $flushGlobalRecord = false; + } else if (Util::array_last($globalRecord)[0] == $lastRecordID) { + $flushGlobalRecord = false; + array_pop($globalRecord); + } else if (count($globalRecord) > static::ROW_LIMIT) { + array_pop($globalRecord); } - if($generalRecord){ - if(Util::array_last($generalRecord)[0] == $lastRecordID){ - $flushGeneralRecord = false; - array_pop($generalRecord); - } - else if(count($generalRecord) > static::ROW_LIMIT){ - array_pop($generalRecord); - } + if (!$generalRecord) { + $flushGeneralRecord = false; + } else if (Util::array_last($generalRecord)[0] == $lastRecordID) { + $flushGeneralRecord = false; + array_pop($generalRecord); + } else if (count($generalRecord) > static::ROW_LIMIT) { + array_pop($generalRecord); } return [ @@ -120,9 +122,9 @@ class GetRecentRecord extends \sammo\BaseAPI 'history' => $history, 'global' => $globalRecord, 'general' => $generalRecord, - 'flushHistory' => $flushHistory?1:0, - 'flushGlobal' => $flushGlobalRecord?1:0, - 'flushGeneral' => $flushGeneralRecord?1:0, + 'flushHistory' => $flushHistory ? 1 : 0, + 'flushGlobal' => $flushGlobalRecord ? 1 : 0, + 'flushGeneral' => $flushGeneralRecord ? 1 : 0, ]; } } diff --git a/hwe/sammo/API/Message/SendMessage.php b/hwe/sammo/API/Message/SendMessage.php index b9564087..96452624 100644 --- a/hwe/sammo/API/Message/SendMessage.php +++ b/hwe/sammo/API/Message/SendMessage.php @@ -185,6 +185,7 @@ class SendMessage extends \sammo\BaseAPI if ($mailbox === Message::MAILBOX_PUBLIC) { $msgID = $this->genPublicMessage($src, $text)->send(); return [ + 'msgType' => 'public', 'msgID' => $msgID ]; } @@ -201,6 +202,7 @@ class SendMessage extends \sammo\BaseAPI if ($destNationID === $nationID) { $msgID = $this->genNationalMessage($src, $text)->send(); return [ + 'msgType' => 'national', 'msgID' => $msgID ]; } @@ -211,6 +213,7 @@ class SendMessage extends \sammo\BaseAPI } $msgID = $msgObjOrError->send(); return [ + 'msgType' => 'diplomacy', 'msgID' => $msgID ]; } @@ -231,6 +234,7 @@ class SendMessage extends \sammo\BaseAPI $msgID = $msgObjOrError->send(); return [ + 'msgType' => 'private', 'msgID' => $msgID ]; } diff --git a/hwe/sammo/API/Nation/GetNationInfo.php b/hwe/sammo/API/Nation/GetNationInfo.php index fe0c2fd0..f7eae16f 100644 --- a/hwe/sammo/API/Nation/GetNationInfo.php +++ b/hwe/sammo/API/Nation/GetNationInfo.php @@ -27,7 +27,7 @@ class GetNationInfo extends \sammo\BaseAPI public function validateArgs(): ?string { $v = new Validator($this->args); - $v->rule('boolean', 'full'); + $v->rule('in', 'full', ['true', 'false']); if (!$v->validate()) { return $v->errorStr(); @@ -70,7 +70,7 @@ class GetNationInfo extends \sammo\BaseAPI $gameEnv = $gameStor->getValues(['year', 'month', 'startyear']); $nation = $db->queryFirstRow( - 'SELECT nation, `name`, color, capital, gennum, gold, rice, bill, rate, secretlimit, chief_set, scout, war, strategic_cmd_limit, surlimit, tech, `power`, `level`, `type` FROM nation WHERE id = %i', + 'SELECT nation, `name`, color, capital, gennum, gold, rice, bill, rate, secretlimit, chief_set, scout, war, strategic_cmd_limit, surlimit, tech, `power`, `level`, `type` FROM nation WHERE nation = %i', $nationID ); $nationStor = \sammo\KVStorage::getStorage($db, $nationID, 'nation_env'); @@ -94,11 +94,14 @@ class GetNationInfo extends \sammo\BaseAPI $troopName[$troopID] = $tName; } - return [ + $result = [ 'result' => true, + 'isFull' => $isFull, 'nation' => $nation, 'impossibleStrategicCommandLists' => $impossibleStrategicCommandLists, 'troops' => $troopName, ]; + + return $result; } } diff --git a/hwe/sammo/DTO/MenuItem.php b/hwe/sammo/DTO/MenuItem.php new file mode 100644 index 00000000..1c3f1231 --- /dev/null +++ b/hwe/sammo/DTO/MenuItem.php @@ -0,0 +1,26 @@ +type = 'item'; + } +} \ No newline at end of file diff --git a/hwe/sammo/DTO/MenuMulti.php b/hwe/sammo/DTO/MenuMulti.php new file mode 100644 index 00000000..d3204595 --- /dev/null +++ b/hwe/sammo/DTO/MenuMulti.php @@ -0,0 +1,20 @@ +type = 'multi'; + } +} \ No newline at end of file diff --git a/hwe/sammo/DTO/MenuSplit.php b/hwe/sammo/DTO/MenuSplit.php new file mode 100644 index 00000000..a01df416 --- /dev/null +++ b/hwe/sammo/DTO/MenuSplit.php @@ -0,0 +1,20 @@ +type = 'split'; + } +} \ No newline at end of file diff --git a/hwe/sammo/General.php b/hwe/sammo/General.php index bdac693a..5f715220 100644 --- a/hwe/sammo/General.php +++ b/hwe/sammo/General.php @@ -1082,7 +1082,7 @@ class General implements iAction 'personal', 'special', 'special2', 'defence_train', 'tnmt', 'npc', 'npc_org', 'deadyear', 'npcmsg', 'dex1', 'dex2', 'dex3', 'dex4', 'dex5', 'betray', 'recent_war', 'last_turn', 'myset', - 'specage', 'specage2', 'con', 'connect', 'aux', 'lastrefresh', + 'specage', 'specage2', 'con', 'connect', 'aux', 'lastrefresh', 'permission', 'penalty', ]; if ($reqColumns === null) { diff --git a/hwe/sammo/GlobalMenu.php b/hwe/sammo/GlobalMenu.php new file mode 100644 index 00000000..33087809 --- /dev/null +++ b/hwe/sammo/GlobalMenu.php @@ -0,0 +1,53 @@ + +
+
+ + +
+
+ +
+ +
접속중인 국가: {{ globalInfo.onlineNations }}
+
【 접속자 】 {{ nationInfo?.onlineGen }}
+
+
【 국가방침 】
+ +
+
+
+ +
+ +
+
+ +
+
+
+
+
+ +
+
+ +
+
+
+
+
+ +
+
+ +
+
+ +
+ +
+ +
+
+
+
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+
+
장수 동향
+ +
+
+
개인 기록
+ +
+
+
중원 정세
+ +
+
+ +
+ +
+ +
+ +
+
+
+
서버 갱신 중입니다.
+
+ +
+ + + + diff --git a/hwe/ts/SammoAPI.ts b/hwe/ts/SammoAPI.ts index d13390e4..cfc61373 100644 --- a/hwe/ts/SammoAPI.ts +++ b/hwe/ts/SammoAPI.ts @@ -22,11 +22,13 @@ import type { SetBlockWarResponse, GeneralListResponse as NationGeneralListRespo import type { UploadImageResponse } from "./defs/API/Misc"; import type { GeneralLogType, GetGeneralLogResponse, JoinArgs } from "./defs/API/General"; import type { -ExecuteResponse, + ExecuteResponse, GetConstResponse, GetCurrentHistoryResponse, GetDiplomacyResponse, + GetFrontInfoResponse, GetHistoryResponse, + GetMenuResponse, GetRecentRecordResponse, } from "./defs/API/Global"; import type { CachedMapResult, CommandTableResponse, GeneralListResponse, ItemTypeKey, MapResult } from "./defs"; @@ -131,6 +133,11 @@ const apiRealPath = { DieOnPrestart: POST as APICallT, BuildNationCandidate: POST as APICallT, GetCommandTable: GET as APICallT, + GetFrontInfo: GET as APICallT<{ + lastNationNoticeDate?: string, + lastGeneralRecordID?: number, + lastWorldHistoryID?: number, + }, GetFrontInfoResponse>, }, Global: { GeneralList: GET as APICallT, @@ -152,10 +159,11 @@ const apiRealPath = { }, ExecuteResponse, InvalidResponse & { reqRefresh?: boolean }>, - GetRecentRecord: GET as APICallT<{ + /*GetRecentRecord: GET as APICallT<{ lastGeneralRecordID: number; lastWorldHistoryID: number; - } | undefined, GetRecentRecordResponse>, + } | undefined, GetRecentRecordResponse>,*/ + GetGlobalMenu: GET as APICallT, }, InheritAction: { BuyHiddenBuff: PUT as APICallT<{ @@ -191,7 +199,7 @@ const apiRealPath = { SendMessage: POST as APICallT<{ mailbox: number; text: string; - }, ValidResponse & {msgID: number}> + }, ValidResponse & {msgID: number, msgType: MsgType}> }, Misc: { UploadImage: POST as APICallT< diff --git a/hwe/ts/build_exports.json b/hwe/ts/build_exports.json index 555bbde0..3db70d2b 100644 --- a/hwe/ts/build_exports.json +++ b/hwe/ts/build_exports.json @@ -37,6 +37,7 @@ "v_nationGeneral": "v_nationGeneral.ts", "v_globalDiplomacy": "v_globalDiplomacy", "v_troop": "v_troop.ts", - "v_vote": "v_vote.ts" + "v_vote": "v_vote.ts", + "v_front": "v_front.ts" } } \ No newline at end of file diff --git a/hwe/ts/components/AutorunInfo.vue b/hwe/ts/components/AutorunInfo.vue new file mode 100644 index 00000000..6e3803cb --- /dev/null +++ b/hwe/ts/components/AutorunInfo.vue @@ -0,0 +1,63 @@ + + \ No newline at end of file diff --git a/hwe/ts/components/CityBasicCard.vue b/hwe/ts/components/CityBasicCard.vue new file mode 100644 index 00000000..1584e311 --- /dev/null +++ b/hwe/ts/components/CityBasicCard.vue @@ -0,0 +1,228 @@ + + + diff --git a/hwe/ts/components/GameBottomBar.vue b/hwe/ts/components/GameBottomBar.vue new file mode 100644 index 00000000..3e8f084c --- /dev/null +++ b/hwe/ts/components/GameBottomBar.vue @@ -0,0 +1,192 @@ + + + + + diff --git a/hwe/ts/components/GameInfo.vue b/hwe/ts/components/GameInfo.vue new file mode 100644 index 00000000..b9c8424d --- /dev/null +++ b/hwe/ts/components/GameInfo.vue @@ -0,0 +1,155 @@ + + + + diff --git a/hwe/ts/components/GlobalMenu.vue b/hwe/ts/components/GlobalMenu.vue new file mode 100644 index 00000000..914f6e89 --- /dev/null +++ b/hwe/ts/components/GlobalMenu.vue @@ -0,0 +1,154 @@ + + + + + diff --git a/hwe/ts/components/GlobalMenuDropdown.vue b/hwe/ts/components/GlobalMenuDropdown.vue new file mode 100644 index 00000000..47c7ea40 --- /dev/null +++ b/hwe/ts/components/GlobalMenuDropdown.vue @@ -0,0 +1,116 @@ + + + + + diff --git a/hwe/ts/components/MainControlBar.vue b/hwe/ts/components/MainControlBar.vue new file mode 100644 index 00000000..bc6abc56 --- /dev/null +++ b/hwe/ts/components/MainControlBar.vue @@ -0,0 +1,116 @@ + + + + diff --git a/hwe/ts/components/MainControlDropdown.vue b/hwe/ts/components/MainControlDropdown.vue new file mode 100644 index 00000000..e40e45ae --- /dev/null +++ b/hwe/ts/components/MainControlDropdown.vue @@ -0,0 +1,69 @@ + + + + diff --git a/hwe/ts/components/MessagePanel.vue b/hwe/ts/components/MessagePanel.vue new file mode 100644 index 00000000..bef39014 --- /dev/null +++ b/hwe/ts/components/MessagePanel.vue @@ -0,0 +1,755 @@ + + + + + + diff --git a/hwe/ts/components/MessagePlate.vue b/hwe/ts/components/MessagePlate.vue new file mode 100644 index 00000000..9fa9e16f --- /dev/null +++ b/hwe/ts/components/MessagePlate.vue @@ -0,0 +1,360 @@ + + + + + \ No newline at end of file diff --git a/hwe/ts/components/NationBasicCard.vue b/hwe/ts/components/NationBasicCard.vue new file mode 100644 index 00000000..50698522 --- /dev/null +++ b/hwe/ts/components/NationBasicCard.vue @@ -0,0 +1,198 @@ + + + diff --git a/hwe/ts/defs/API/Global.ts b/hwe/ts/defs/API/Global.ts index 7b51ea32..4353b11d 100644 --- a/hwe/ts/defs/API/Global.ts +++ b/hwe/ts/defs/API/Global.ts @@ -1,96 +1,250 @@ -import type { CityID, CrewTypeID, GameCityDefault, GameConstType, GameUnitType, GameIActionKey, GameIActionCategory, GameIActionInfo } from "@/defs/GameObj"; -import type { diplomacyState, MapResult, SimpleNationObj } from "@/defs"; +import type { + CityID, + CrewTypeID, + GameCityDefault, + GameConstType, + GameUnitType, + GameIActionKey, + GameIActionCategory, + GameIActionInfo, +} from "@/defs/GameObj"; +import type { diplomacyState, MapResult, NationLevel, SimpleNationObj } from "@/defs"; +import type { GeneralListItemP0, GeneralListItemP1, NationNotice } from "./Nation"; +import type { VoteInfo } from "./Vote"; export interface GetConstResponse { - result: true; - cacheKey: string; - data: { - gameConst: GameConstType; - gameUnitConst: Record; - cityConst: Record; - cityConstMap: { - region: Record; - level: Record; //defs.CityLevelText - }; - iActionInfo: Record< - GameIActionCategory, - Record< - GameIActionKey, - GameIActionInfo - > - >; - iActionKeyMap: { - availableNationType: "nationType"; - neutralNationType: "nationType"; - defaultSpecialDomestic: "specialDomestic"; - availableSpecialDomestic: "specialDomestic"; - optionalSpecialDomestic: "specialDomestic"; - defaultSpecialWar: "specialWar"; - availableSpecialWar: "specialWar"; - optionalSpecialWar: "specialWar"; - neutralPersonality: "personality"; - availablePersonality: "personality"; - optionalPersonality: "personality"; - allItems: "item"; - }; + result: true; + cacheKey: string; + data: { + gameConst: GameConstType; + gameUnitConst: Record; + cityConst: Record; + cityConstMap: { + region: Record; + level: Record; //defs.CityLevelText }; + iActionInfo: Record>; + iActionKeyMap: { + availableNationType: "nationType"; + neutralNationType: "nationType"; + defaultSpecialDomestic: "specialDomestic"; + availableSpecialDomestic: "specialDomestic"; + optionalSpecialDomestic: "specialDomestic"; + defaultSpecialWar: "specialWar"; + availableSpecialWar: "specialWar"; + optionalSpecialWar: "specialWar"; + neutralPersonality: "personality"; + availablePersonality: "personality"; + optionalPersonality: "personality"; + allItems: "item"; + }; + }; } export type HistoryObj = { - server_id: string, - year: number; - month: number; - map: MapResult, - global_history: string[], - global_action: string[], - nations: { - capital: number, - cities: string[], - color: string, - gennum: number, - level: number, - name: string, - nation: number, - power: number, - type: GameIActionKey - }[], -} + server_id: string; + year: number; + month: number; + map: MapResult; + global_history: string[]; + global_action: string[]; + nations: { + capital: number; + cities: string[]; + color: string; + gennum: number; + level: number; + name: string; + nation: number; + power: number; + type: GameIActionKey; + }[]; +}; export type GetHistoryResponse = { - result: true; - data: HistoryObj & { - hash: string; - //no: number, - }; -} + result: true; + data: HistoryObj & { + hash: string; + //no: number, + }; +}; export type GetCurrentHistoryResponse = { - result: true; - data: HistoryObj; -} - + result: true; + data: HistoryObj; +}; export type GetDiplomacyResponse = { - result: true; - nations: SimpleNationObj[]; - conflict: [number, Record][]; - diplomacyList: Record>; - myNationID: number; -} + result: true; + nations: SimpleNationObj[]; + conflict: [number, Record][]; + diplomacyList: Record>; + myNationID: number; +}; export type ExecuteResponse = { - result: true; - updated: boolean; - locked: boolean; - lastExecuted: string; + result: true; + updated: boolean; + locked: boolean; + lastExecuted: string; }; export type GetRecentRecordResponse = { - result: true; - history: [number, string][]; - global: [number, string][]; - general: [number, string][]; - flushHistory: 1 | 0; - flushGlobal: 1 | 0; - flushGeneral: 1 | 0; + result: true; + history: [number, string][]; + global: [number, string][]; + general: [number, string][]; + flushHistory: 1 | 0; + flushGlobal: 1 | 0; + flushGeneral: 1 | 0; +}; + +export type AutorunUserMode = "develop" | "warp" | "recruit" | "recruit_high" | "train" | "battle" | "chief"; + +export type GetFrontInfoResponse = { + result: true; + recentRecord: Omit; + global: { + scenarioText: string; + extendedGeneral: 1 | 0; + isFiction: 1 | 0; + npcMode: 2 | 1 | 0; + joinMode: "onlyRandom" | "full"; + startyear: number; + year: number; + month: number; + autorunUser: { + limit_minutes: number, + options: Record, + }; + turnterm: number; + lastExecuted: string; + lastVoteID: number; + develCost: number; + noticeMsg: number; + onlineNations: string; //TODO: string[]으로 변경 + onlineUserCnt: number; + apiLimit: number; + auctionCount: number; + isTournamentActive: boolean; + isTournamentApplicationOpen: boolean; + isBettingActive: boolean; + isLocked: boolean; + tournamentType: null | 0 | 1 | 2 | 3; + tournamentState: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10; + tournamentTime: string; + genCount: [number, number][]; + generalCntLimit: number; + serverCnt: number; + lastVote: VoteInfo | null; + }; + general: GeneralListItemP1 & { + permission: number; + troopInfo?: { + leader: { + city: number; + reservedCommand: GeneralListItemP1["reservedCommand"]; + }; + name: string; + }; + }; + nation: { + id: number; + name: string; + population: { + cityCnt: number; + now: number; + max: number; + }; + crew: { + generalCnt: number; + now: number; + max: number; + }; + type: { + raw: GameIActionKey; + name: string; + pros: string; + cons: string; + }; + color: string; + level: NationLevel + capital: number; + gold: number; + rice: number; + tech: number; + gennum: number; + power: number; + bill: number; + taxRate: number; + onlineGen: string; + notice: NationNotice; + topChiefs: Record< + 11 | 12, + { + officer_level: number; + no: number; + name: string; + npc: GeneralListItemP0["npc"]; + } + >; + diplomaticLimit: number; + strategicCmdLimit: number; + impossibleStrategicCommand: [string, number][]; + prohibitScout: 1 | 0; + prohibitWar: 1 | 0; + }; + city: { + id: number; + name: string; + nationInfo: { + id: number; + name: string; + color: string; + }; + level: number; + trust: number; + pop: [number, number]; + agri: [number, number]; + comm: [number, number]; + secu: [number, number]; + def: [number, number]; + wall: [number, number]; + trade: null | number; + officerList: Record< + 2 | 3 | 4, + { + officer_level: 2 | 3 | 4; + name: string; + npc: GeneralListItemP0["npc"]; + } | null + >; + }; +}; + +export type MenuItem = { + type: 'item'; + name: string; + url: string; + icon?: string; + newTab?: boolean; + condHightlightVar?: string; + condShowVar?: string; +} + +export type MenuSplit = { + type: 'split'; + main: MenuItem; + subMenu: MenuItem[]; +} + +export type MenuMulti = { + type: 'multi'; + name: string; + subMenu: MenuItem[]; +} + +export type GetMenuResponse = { + result: true; + menu: (MenuItem | MenuSplit | MenuMulti)[]; } \ No newline at end of file diff --git a/hwe/ts/defs/API/Nation.ts b/hwe/ts/defs/API/Nation.ts index 85b26c67..161fef06 100644 --- a/hwe/ts/defs/API/Nation.ts +++ b/hwe/ts/defs/API/Nation.ts @@ -150,12 +150,23 @@ export type LiteNationInfoResponse = ValidResponse & { nation: NationStaticItem; }; +export type NationInfoFull = ValidResponse & { + nation: NationItem; + isFull: true, + impossibleStrategicCommandLists: [string, number][]; + troops: Record; +} + +export type NationNotice = { + date: string, + msg: string, + author: string, + authorID: number, +} + export type NationInfoResponse = | (ValidResponse & { nation: NationStaticItem; + isFull?: false; }) - | (ValidResponse & { - nation: NationItem; - impossibleStrategicCommandLists: [string, number][]; - troops: Record; - }); + | NationInfoFull; diff --git a/hwe/ts/util/Entries.ts b/hwe/ts/util/Entries.ts new file mode 100644 index 00000000..9ff7a024 --- /dev/null +++ b/hwe/ts/util/Entries.ts @@ -0,0 +1,3 @@ +export type Entries = { + [K in keyof T]: [K, T[K]]; +}[keyof T][]; \ No newline at end of file diff --git a/hwe/ts/utilGame/formatTournament.ts b/hwe/ts/utilGame/formatTournament.ts new file mode 100644 index 00000000..e1660ab5 --- /dev/null +++ b/hwe/ts/utilGame/formatTournament.ts @@ -0,0 +1,35 @@ +const typeMap = ["전력전", "통솔전", "일기토", "설전"]; + +export function formatTournamentType(type: null | undefined | 0 | 1 | 2 | 3): string { + if (type === null || type === undefined) { + return "?"; + } + return typeMap[type]; +} + +export type TournamentStepType = { + availableJoin: boolean; + state: string; + nextText: string; +}; +const stepMap: TournamentStepType[] = [ + { availableJoin: false, state: "경기 없음", nextText:"" }, + { availableJoin: true, state: "참가 모집중", nextText:"개막시간" }, + { availableJoin: false, state: "예선 진행중", nextText:"다음경기" }, + { availableJoin: false, state: "본선 추첨중", nextText:"다음추첨" }, + { availableJoin: false, state: "본선 진행중", nextText:"다음경기" }, + { availableJoin: false, state: "16강 배정중", nextText:"16강배정" }, + { availableJoin: true, state: "베팅 진행중", nextText:"베팅마감" }, + { availableJoin: false, state: "16강 진행중", nextText:"다음경기" }, + { availableJoin: false, state: "8강 진행중", nextText:"다음경기" }, + { availableJoin: false, state: "4강 진행중", nextText:"다음경기" }, + { availableJoin: false, state: "결승 진행중", nextText:"다음경기" }, +]; + +export function formatTournamentStep(step: null | undefined | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10): TournamentStepType { + if (step === null || step === undefined) { + return stepMap[0]; + } + + return stepMap[step]; +} diff --git a/hwe/ts/utilGame/index.ts b/hwe/ts/utilGame/index.ts index d3b26892..cf9046a0 100644 --- a/hwe/ts/utilGame/index.ts +++ b/hwe/ts/utilGame/index.ts @@ -13,4 +13,5 @@ export { getNPCColor } from "./getNPCColor"; export { isValidObjKey } from "./isValidObjKey"; export { nextExpLevelRemain } from "./nextExpLevelRemain"; export { postFilterNationCommandGen } from "./postFilterNationCommandGen"; -export { isTechLimited, convTechLevel, getMaxRelativeTechLevel } from "./techLevel"; \ No newline at end of file +export { isTechLimited, convTechLevel, getMaxRelativeTechLevel } from "./techLevel"; +export { calcTournamentTerm } from "./tournament"; \ No newline at end of file diff --git a/hwe/ts/utilGame/tournament.ts b/hwe/ts/utilGame/tournament.ts new file mode 100644 index 00000000..3b740100 --- /dev/null +++ b/hwe/ts/utilGame/tournament.ts @@ -0,0 +1,4 @@ +import { clamp } from 'lodash-es'; +export function calcTournamentTerm(turnTerm: number): number{ + return clamp(turnTerm, 5, 120); +} \ No newline at end of file diff --git a/hwe/ts/v_front.ts b/hwe/ts/v_front.ts new file mode 100644 index 00000000..f8af9d4d --- /dev/null +++ b/hwe/ts/v_front.ts @@ -0,0 +1,13 @@ +import { createApp } from 'vue' +import { BootstrapVue3, BToastPlugin } from 'bootstrap-vue-3' +import { auto500px } from './util/auto500px'; +import { htmlReady } from './util/htmlReady'; +import { insertCustomCSS } from './util/customCSS'; +import PageFront from './PageFront.vue'; +import Multiselect from 'vue-multiselect'; +auto500px(); + +htmlReady(() => { + insertCustomCSS(); +}); +createApp(PageFront).use(BootstrapVue3).use(BToastPlugin).component('v-multiselect', Multiselect).mount('#app'); diff --git a/hwe/v_front.php b/hwe/v_front.php new file mode 100644 index 00000000..913f078b --- /dev/null +++ b/hwe/v_front.php @@ -0,0 +1,44 @@ + + + + + + + + + <?= UniqueConst::$serverName ?>: 메인 + [ + 'serverName' => UniqueConst::$serverName, + 'serverNick' => DB::prefix(), + 'serverID' => UniqueConst::$serverID, + 'mapName' => GameConst::$mapName, + 'unitSet' => GameConst::$unitSet, + + 'maxTurn' => GameConst::$maxTurn, + 'maxPushTurn' => 12, + 'serverNow' => TimeUtil::now(false), + ] + ], false) ?> + + + + + + + + +
+ + + \ No newline at end of file