2020-06-21 23:26:35 +08:00
|
|
|
|
import os
|
|
|
|
|
|
import re
|
|
|
|
|
|
|
|
|
|
|
|
from dev_tools.slpp import slpp
|
2021-10-21 21:15:01 +08:00
|
|
|
|
from dev_tools.utils import LuaLoader
|
2022-04-15 03:37:54 +08:00
|
|
|
|
from module.base.utils import location2node
|
2021-10-21 21:15:01 +08:00
|
|
|
|
from module.logger import logger
|
2022-04-15 03:37:54 +08:00
|
|
|
|
from module.map.utils import *
|
2020-06-21 23:26:35 +08:00
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
This an auto-tool to extract map files used in Alas.
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
2020-08-20 18:54:09 +08:00
|
|
|
|
DIC_SIREN_NAME_CHI_TO_ENG = {
|
2020-11-15 02:06:10 +08:00
|
|
|
|
# Siren Winter's Crown, Fallen Wings
|
|
|
|
|
|
'sairenquzhu': 'DD',
|
|
|
|
|
|
'sairenqingxun': 'CL',
|
|
|
|
|
|
'sairenzhongxun': 'CA',
|
|
|
|
|
|
'sairenzhanlie': 'BB',
|
|
|
|
|
|
'sairenhangmu': 'CV',
|
|
|
|
|
|
'sairenqianting': 'SS',
|
|
|
|
|
|
|
2020-08-20 18:54:09 +08:00
|
|
|
|
# Siren cyan
|
|
|
|
|
|
'sairenquzhu_i': 'DD',
|
|
|
|
|
|
'sairenqingxun_i': 'CL',
|
|
|
|
|
|
'sairenzhongxun_i': 'CA',
|
|
|
|
|
|
'sairenzhanlie_i': 'BB',
|
|
|
|
|
|
'sairenhangmu_i': 'CV',
|
2020-09-18 18:45:20 +08:00
|
|
|
|
'sairenqianting_i': 'SS',
|
2020-08-20 18:54:09 +08:00
|
|
|
|
|
2020-09-19 15:57:05 +08:00
|
|
|
|
# Siren red
|
|
|
|
|
|
'sairenquzhu_M': 'DD',
|
|
|
|
|
|
'sairenqingxun_M': 'CL',
|
|
|
|
|
|
'sairenzhongxun_M': 'CAred',
|
2021-02-26 20:28:11 +08:00
|
|
|
|
'sairenzhanlie_M': 'BBred',
|
2020-09-19 15:57:05 +08:00
|
|
|
|
'sairenhangmu_M': 'CV',
|
|
|
|
|
|
'sairenqianting_M': 'SS',
|
|
|
|
|
|
|
2020-08-20 18:54:09 +08:00
|
|
|
|
# Scherzo of Iron and Blood
|
|
|
|
|
|
'aruituosha': 'Arethusa',
|
|
|
|
|
|
'xiefeierde': 'Sheffield',
|
|
|
|
|
|
'duosaitejun': 'Dorsetshire',
|
|
|
|
|
|
'shengwang': 'Renown',
|
2020-10-29 22:42:10 +08:00
|
|
|
|
'weiershiqinwang': 'PrinceOfWales',
|
|
|
|
|
|
|
|
|
|
|
|
# Universe in Unison
|
|
|
|
|
|
'edu_idol': 'LeMalinIdol',
|
|
|
|
|
|
'daiduo_idol': 'DidoIdol',
|
|
|
|
|
|
'daqinghuayu_idol': 'AlbacoreIdol',
|
|
|
|
|
|
'baerdimo_idol': 'BaltimoreIdol',
|
|
|
|
|
|
'kelifulan_idol': 'ClevelandIdol',
|
|
|
|
|
|
'xipeier_idol': 'HipperIdol',
|
|
|
|
|
|
'sipeibojue_5': 'SpeeIdol',
|
|
|
|
|
|
'luoen_idol': 'RoonIdol',
|
|
|
|
|
|
'guanghui_idol': 'IllustriousIdol',
|
2020-11-26 21:21:51 +08:00
|
|
|
|
|
|
|
|
|
|
# Vacation Lane
|
|
|
|
|
|
'maliluosi_doa': 'MarieRoseDOA',
|
|
|
|
|
|
'haixiao_doa': 'MisakiDOA',
|
|
|
|
|
|
'xia_doa': 'KasumiDOA',
|
|
|
|
|
|
'zhixiao_doa': 'NagisaDOA',
|
2020-12-11 20:52:23 +08:00
|
|
|
|
|
|
|
|
|
|
# The Enigma and the Shark
|
|
|
|
|
|
'nvjiang': 'Amazon',
|
2020-12-29 20:03:07 +08:00
|
|
|
|
|
|
|
|
|
|
# Inverted Orthant
|
|
|
|
|
|
'luodeni': 'Rodney',
|
|
|
|
|
|
'huangjiafangzhou': 'ArkRoyal',
|
|
|
|
|
|
'jingang': 'Kongo',
|
|
|
|
|
|
'shancheng': 'Yamashiro',
|
|
|
|
|
|
'z24': 'Z24',
|
|
|
|
|
|
'niulunbao': 'Nuremberg',
|
|
|
|
|
|
'longqibing': 'Carabiniere',
|
2022-02-10 22:32:47 +08:00
|
|
|
|
# siren_ii has purple lightning around
|
|
|
|
|
|
# Detect area of DD and CL are not effected
|
2021-08-19 23:12:06 +08:00
|
|
|
|
'sairenquzhu_ii': 'DD',
|
|
|
|
|
|
'sairenqingxun_ii': 'CL',
|
2022-02-10 22:32:47 +08:00
|
|
|
|
'sairenzhongxun_ii': 'CAlightning',
|
|
|
|
|
|
'sairenzhanlie_ii': 'BBlightning',
|
|
|
|
|
|
'sairenhangmu_ii': 'CVlightning',
|
2020-12-29 20:03:07 +08:00
|
|
|
|
'qinraozhe': 'Intruder',
|
|
|
|
|
|
'xianghe': 'Shokaku',
|
|
|
|
|
|
'ruihe': 'Zuikaku',
|
|
|
|
|
|
'shitelasai': 'PeterStrasser',
|
2021-01-21 14:46:29 +08:00
|
|
|
|
|
|
|
|
|
|
# Empyreal Tragicomedy
|
|
|
|
|
|
'teluntuo': 'Trento',
|
|
|
|
|
|
'lituoliao': 'Littorio',
|
2021-01-21 15:33:44 +08:00
|
|
|
|
'jianyu': 'Swordfish', # Not siren but movable enemy
|
2021-03-26 17:27:22 +08:00
|
|
|
|
|
|
|
|
|
|
# Ashen Simulacrum
|
|
|
|
|
|
'shengdiyage': 'SanDiego',
|
|
|
|
|
|
'weiqita': 'Wichita',
|
|
|
|
|
|
'yalisangna': 'Arizona',
|
|
|
|
|
|
'liekexingdun': 'Lexington',
|
|
|
|
|
|
'tiaoyu': 'Dace',
|
2021-04-22 17:05:19 +08:00
|
|
|
|
|
|
|
|
|
|
# Daedalian Hymn
|
|
|
|
|
|
'geluosite': 'Gloucester',
|
|
|
|
|
|
'yueke': 'York',
|
|
|
|
|
|
'yanzhan': 'Warspite',
|
|
|
|
|
|
'naerxun': 'Nelson',
|
|
|
|
|
|
'kewei': 'Formidable',
|
|
|
|
|
|
'guanghui': 'Illustrious',
|
2021-05-27 18:04:16 +08:00
|
|
|
|
|
|
|
|
|
|
# Mirror Involution
|
|
|
|
|
|
# Note: In this event, sirens are covered by fog
|
|
|
|
|
|
'duwei': 'Dewey',
|
|
|
|
|
|
'haman': 'Hammann',
|
|
|
|
|
|
'yatelanda': 'Atlanta',
|
|
|
|
|
|
'beianpudun': 'Northampton',
|
2021-06-24 22:06:57 +08:00
|
|
|
|
|
|
|
|
|
|
# Swirling Cherry Blossoms
|
|
|
|
|
|
'xia': 'Kasumi',
|
|
|
|
|
|
'xiang': 'Hibiki',
|
|
|
|
|
|
'guinu': 'Kinu',
|
|
|
|
|
|
'moye': 'Maya',
|
|
|
|
|
|
'yishi': 'Ise',
|
|
|
|
|
|
'sunying': 'Junyo',
|
2020-08-20 15:58:29 +08:00
|
|
|
|
|
2021-10-28 17:43:51 +08:00
|
|
|
|
# Skybound Oratorio
|
|
|
|
|
|
'aerjiliya': 'Algerie',
|
|
|
|
|
|
'jialisuoniye': 'LaGalissonniere',
|
|
|
|
|
|
'wokelan': 'Vauquelin',
|
2021-11-18 22:59:54 +08:00
|
|
|
|
|
|
|
|
|
|
# Crimson Echoes
|
|
|
|
|
|
'xili': 'Yuudachi',
|
|
|
|
|
|
'shentong': 'Jintsuu',
|
|
|
|
|
|
'niaohai': 'Choukai',
|
|
|
|
|
|
'wudao': 'Kirishima',
|
2021-12-29 20:36:45 +08:00
|
|
|
|
'canglong': 'Souryuu',
|
|
|
|
|
|
|
|
|
|
|
|
# Tower of Transcendence
|
|
|
|
|
|
'sairenquzhu_6': 'DD',
|
|
|
|
|
|
'sairenqingxun_6': 'CL',
|
|
|
|
|
|
'sairenzhongxun_6': 'CA',
|
|
|
|
|
|
'sairenzhanlie_6': 'BB',
|
|
|
|
|
|
'sairenhangmu_6': 'CV',
|
2022-02-10 17:49:14 +08:00
|
|
|
|
|
|
|
|
|
|
# Northern Overture Rerun
|
|
|
|
|
|
'ganraozhe': 'Intruder',
|
2022-02-24 18:11:01 +08:00
|
|
|
|
|
|
|
|
|
|
# Abyssal Refrain
|
|
|
|
|
|
'lingmin': 'Soobrazitelny',
|
|
|
|
|
|
'jifu': 'Kiev',
|
|
|
|
|
|
'fuerjia': 'Volga',
|
2022-04-14 19:31:49 +08:00
|
|
|
|
|
|
|
|
|
|
# Aurora Noctis
|
|
|
|
|
|
'U81': 'U81',
|
|
|
|
|
|
'U101': 'U101',
|
|
|
|
|
|
'U522': 'U522',
|
|
|
|
|
|
'deyizhi': 'Deutschland',
|
|
|
|
|
|
'tierbici': 'Tirpitz',
|
|
|
|
|
|
'genaisennao': 'Gneisenau',
|
|
|
|
|
|
'shaenhuosite': 'Scharnhorst',
|
|
|
|
|
|
'sipeibojue': 'Spee',
|
|
|
|
|
|
'U73': 'U73',
|
2022-04-28 12:45:07 +08:00
|
|
|
|
|
|
|
|
|
|
# Rondo at Rainbow's End
|
|
|
|
|
|
'z2': 'Z2',
|
|
|
|
|
|
'laibixi': 'Leipzig',
|
|
|
|
|
|
'ougen': 'PrinzEugen',
|
2022-04-29 19:34:54 +08:00
|
|
|
|
'sairenqianting_ii': 'SS',
|
|
|
|
|
|
'sairenboss11': 'Compiler',
|
2022-05-26 18:56:46 +08:00
|
|
|
|
|
|
|
|
|
|
# Pledge of the Radiant Court
|
|
|
|
|
|
'sizhannvshen': 'Bellona',
|
|
|
|
|
|
'fuchou': 'Revenge',
|
2022-07-28 21:25:16 +08:00
|
|
|
|
|
|
|
|
|
|
# Aquilifer's Ballade
|
|
|
|
|
|
'tianhou_ghost': 'Juno_ghost',
|
|
|
|
|
|
'haiwangxing_ghost': 'Neptune_ghost',
|
|
|
|
|
|
'lemaer_ghost': 'LeMars_ghost',
|
|
|
|
|
|
'jingjishen_ghost': 'Hermes_ghost',
|
|
|
|
|
|
'qiubite_ghost': 'Jupiter_ghost',
|
2022-08-18 23:47:57 +08:00
|
|
|
|
|
|
|
|
|
|
# Aquilifer's Ballade
|
|
|
|
|
|
'z46': 'Z46',
|
|
|
|
|
|
'haiyinlixi': 'PrinzHeinrich',
|
|
|
|
|
|
'qibolin': 'GrafZeppelin',
|
|
|
|
|
|
'magedebao': 'Magdeburg',
|
|
|
|
|
|
'adaerbote': 'PrinzAdalbert',
|
|
|
|
|
|
'weixi': 'Weser',
|
|
|
|
|
|
'wuerlixi': 'UlrichVonHutten',
|
2022-09-15 21:53:51 +08:00
|
|
|
|
|
|
|
|
|
|
# Violet Tempest Blooming Lycoris
|
|
|
|
|
|
'ruoyue': 'Wakaba',
|
|
|
|
|
|
'liangyue': 'Suzutsuki',
|
|
|
|
|
|
'shenxue': 'Miyuki',
|
|
|
|
|
|
'qifeng': 'Hatakaze',
|
|
|
|
|
|
'yuhei': 'Haguro',
|
|
|
|
|
|
'birui': 'Hiei',
|
|
|
|
|
|
'zhenming': 'Haruna',
|
|
|
|
|
|
'chicheng': 'Akagi',
|
|
|
|
|
|
'jiahe': 'Kaga',
|
|
|
|
|
|
'sanli': 'Mikasa',
|
|
|
|
|
|
'changmen': 'Nagato',
|
|
|
|
|
|
'jiuyun': 'Sakawa',
|
|
|
|
|
|
'qiansui': 'Chitose',
|
|
|
|
|
|
'qiandaitian': 'Chiyoda',
|
|
|
|
|
|
'longfeng': 'Ryuuhou',
|
2022-09-16 20:49:51 +08:00
|
|
|
|
'chunyue': 'Harutsuki',
|
|
|
|
|
|
'jiangfeng': 'Kawakaze',
|
2022-12-23 16:06:21 +08:00
|
|
|
|
|
|
|
|
|
|
# The Alchemist and the Archipelago of Secrets
|
|
|
|
|
|
'lianjin_sairenquzhu': 'DDalchemist',
|
|
|
|
|
|
'lianjin_sairenqingxun': 'CLalchemist',
|
|
|
|
|
|
'lianjin_sairenzhongxun': 'CAalchemist',
|
|
|
|
|
|
'lianjin_sairenzhanlie': 'BBalchemist',
|
|
|
|
|
|
'lianjin_sairenhangmu': 'CValchemist',
|
|
|
|
|
|
|
|
|
|
|
|
# Parallel Superimposition
|
|
|
|
|
|
'sairenboss15': 'SirenBoss15',
|
|
|
|
|
|
'sairenboss16': 'SirenBoss16',
|
2023-02-23 21:01:30 +08:00
|
|
|
|
|
|
|
|
|
|
# Revelations of Dust
|
|
|
|
|
|
'xiafei': 'Joffre',
|
|
|
|
|
|
'lemaer': 'LeMars',
|
2023-08-17 13:27:15 +08:00
|
|
|
|
|
2023-08-18 12:10:46 +08:00
|
|
|
|
# Confluence of Nothingness
|
|
|
|
|
|
'shenyuanboss4': 'AbyssalBoss4',
|
|
|
|
|
|
'shenyuanboss4_alter': 'AbyssalBoss4',
|
|
|
|
|
|
'shenyuanboss5': 'AbyssalBoss5',
|
|
|
|
|
|
'shenyuanboss5_alter': 'AbyssalBoss5',
|
|
|
|
|
|
'sairenquzhu_m': 'DD',
|
|
|
|
|
|
'sairenqingxun_m': 'CL',
|
|
|
|
|
|
'sairenzhongxun_m': 'CAred',
|
|
|
|
|
|
'sairenzhanlie_m': 'BBred',
|
|
|
|
|
|
'sairenhangmu_m': 'CV',
|
|
|
|
|
|
'sairenqianting_m': 'SS',
|
|
|
|
|
|
|
2023-08-17 13:27:15 +08:00
|
|
|
|
# The Fool's Scales
|
|
|
|
|
|
'sairenboss18': 'SirenBoss18',
|
|
|
|
|
|
'sairenboss19': 'SirenBoss19',
|
|
|
|
|
|
'srjiaohuangjijia': 'Dilloy',
|
2023-09-15 02:43:24 +08:00
|
|
|
|
|
|
|
|
|
|
# Effulgence Before Eclipse
|
|
|
|
|
|
'chuyue': 'Hatsuzuki',
|
|
|
|
|
|
'zhaozhi': 'Asanagi',
|
2023-12-23 00:11:34 +08:00
|
|
|
|
'ruifeng': 'Zuiho',
|
|
|
|
|
|
|
|
|
|
|
|
'shanluan_sairenquzhu': 'SK_DD',
|
|
|
|
|
|
'shanluan_sairenqingxun': 'SK_CL',
|
|
|
|
|
|
'shanluan_sairenzhongxun': 'SK_CA',
|
|
|
|
|
|
'shanluan_sairenzhanlie': 'SK_BB',
|
|
|
|
|
|
'shanluan_sairenhangmu': 'SK_CV',
|
|
|
|
|
|
|
|
|
|
|
|
# Light-Chasing Sea of Stars
|
|
|
|
|
|
'sairenboss10': 'Sirenboss10',
|
|
|
|
|
|
'UDFsairen_baolei_2': 'UDFFortress2',
|
2024-04-26 03:55:49 +08:00
|
|
|
|
|
|
|
|
|
|
# Heart-Linking Harmony
|
|
|
|
|
|
'lafei_6': 'Laffey6',
|
|
|
|
|
|
'tashigan_idol': 'TashkentIdol',
|
|
|
|
|
|
'xiefeierde_idol': 'SheffieldIdol',
|
|
|
|
|
|
'yilishabai_3': 'Elizabeth3',
|
|
|
|
|
|
'jiasikenie_idol': 'GascogneIdol',
|
|
|
|
|
|
'dafeng_idol': 'TaihouIdol',
|
2024-07-26 00:40:16 +08:00
|
|
|
|
|
|
|
|
|
|
# Interlude of Illusions
|
|
|
|
|
|
'tianlangxing': 'Sirius',
|
|
|
|
|
|
'daiduo': 'Dido',
|
|
|
|
|
|
'z23_g': 'Z23_g',
|
|
|
|
|
|
'laibixi_g': 'Leipzig_g',
|
|
|
|
|
|
'pangpeimagenuo': 'PompeoMagno',
|
|
|
|
|
|
'aerfuleiduo': 'AlfredoOriani',
|
|
|
|
|
|
'guogan': 'LAudacieux',
|
|
|
|
|
|
'dipulaikesi': 'Dupleix',
|
2024-08-17 00:30:49 +08:00
|
|
|
|
|
|
|
|
|
|
# Windborne Steel Wings
|
|
|
|
|
|
'qinraozhe_IV': 'Intruder',
|
2024-08-30 22:49:07 +08:00
|
|
|
|
'tiancheng_m_quzhu': 'AmagiMasked',
|
2024-08-17 00:30:49 +08:00
|
|
|
|
'tiancheng_m_qingxun': 'AmagiMasked',
|
|
|
|
|
|
'tiancheng_m_zhongxun': 'AmagiMasked',
|
2024-08-30 22:49:07 +08:00
|
|
|
|
'tiancheng_m_zhanlie': 'AmagiMasked',
|
|
|
|
|
|
'tiancheng_m_hangmu': 'AmagiMasked',
|
2024-11-22 21:25:41 +08:00
|
|
|
|
|
|
|
|
|
|
# Tempesta and the Sleeping Sea
|
|
|
|
|
|
'hemuhao': 'Amity',
|
|
|
|
|
|
'pucimaosi': 'Portsmouth',
|
|
|
|
|
|
'mali': 'MaryCeleste',
|
|
|
|
|
|
'fengfan_haigu03': 'fengfanhaigu03',
|
|
|
|
|
|
|
|
|
|
|
|
# Dangerous Inventions Incoming
|
|
|
|
|
|
'tolove_renxing01': 'ToLoveNana01',
|
|
|
|
|
|
'tolove_renxing02': 'ToLoveYui02',
|
|
|
|
|
|
'tolove_renxing03': 'ToLoveNana03',
|
|
|
|
|
|
'tolove_renxing04': 'ToLoveHaruna04',
|
|
|
|
|
|
'tolove_renxing05': 'ToLoveGoldenDarkness05',
|
2025-02-27 23:31:00 +08:00
|
|
|
|
|
|
|
|
|
|
# Paradiso of Shackled Light
|
|
|
|
|
|
'boerzhanuo_alter': 'BolzanoAlter',
|
|
|
|
|
|
'kaisa_alter': 'CesareAlter',
|
|
|
|
|
|
'teluntuo_alter': 'TrentoAlter',
|
|
|
|
|
|
'sairenboss26': 'SirenBoss26',
|
|
|
|
|
|
'sairenboss25': 'SirenBoss25',
|
2025-05-21 11:45:03 +08:00
|
|
|
|
|
|
|
|
|
|
# A Rose on the High Tower
|
|
|
|
|
|
'shengli': 'Victorious',
|
|
|
|
|
|
'huangjiaxiangshu': 'RoyalOak',
|
2025-07-24 23:28:53 +08:00
|
|
|
|
|
|
|
|
|
|
# The Alchemist and the Tower of Horizons
|
|
|
|
|
|
'lianjin_II_sairenquzhu': 'DDalchemist2',
|
|
|
|
|
|
'lianjin_II_sairenqingxun': 'CLalchemist2',
|
|
|
|
|
|
'lianjin_II_sairenzhongxun': 'CAalchemist2',
|
|
|
|
|
|
'lianjin_II_sairenzhanlie': 'BBalchemist2',
|
|
|
|
|
|
'lianjin_II_sairenhangmu': 'CValchemist2',
|
2025-08-15 23:42:52 +08:00
|
|
|
|
|
|
|
|
|
|
# Secrets of the Abyss
|
|
|
|
|
|
'jiulaimu_ruanniguai': 'Jiulaimu_Mud',
|
|
|
|
|
|
'jiulaimu_shixianggui': 'Jiulaimu_Statue',
|
|
|
|
|
|
'jiulaimu_emo': 'Jiulaimu_Demon',
|
|
|
|
|
|
'youlin_ylsb': 'Jiulaimu_Ghost',
|
2025-12-19 02:50:13 +08:00
|
|
|
|
|
|
|
|
|
|
# A Note Through the Firmament
|
|
|
|
|
|
'unknownV_boss_star': 'Vboss_Star',
|
|
|
|
|
|
'unknownV_boss_hermit': 'Vboss_Hermit',
|
|
|
|
|
|
'unknownV_boss_lovers': 'Vboss_Lovers',
|
|
|
|
|
|
'unknownV_boss_chariot': 'Vboss_Chariot',
|
2021-10-28 17:43:51 +08:00
|
|
|
|
}
|
2020-12-29 16:44:11 +08:00
|
|
|
|
|
|
|
|
|
|
|
2020-06-21 23:26:35 +08:00
|
|
|
|
class MapData:
|
|
|
|
|
|
dic_grid_info = {
|
|
|
|
|
|
0: '--',
|
|
|
|
|
|
1: 'SP',
|
2020-06-22 21:07:50 +08:00
|
|
|
|
2: 'MM',
|
2020-06-21 23:26:35 +08:00
|
|
|
|
3: 'MA',
|
2020-06-22 01:02:10 +08:00
|
|
|
|
4: 'Me', # This grid 100% spawn enemy?
|
2020-06-21 23:26:35 +08:00
|
|
|
|
6: 'ME',
|
|
|
|
|
|
8: 'MB',
|
|
|
|
|
|
12: 'MS',
|
2021-01-21 15:33:44 +08:00
|
|
|
|
16: '__',
|
|
|
|
|
|
100: '++', # Dock in Empyreal Tragicomedy
|
2020-06-21 23:26:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2020-09-19 15:57:05 +08:00
|
|
|
|
def __init__(self, data, data_loop):
|
2020-06-21 23:26:35 +08:00
|
|
|
|
self.data = data
|
2020-09-19 15:57:05 +08:00
|
|
|
|
self.data_loop = data_loop
|
2020-06-21 23:26:35 +08:00
|
|
|
|
self.chapter_name = data['chapter_name'].replace('–', '-')
|
|
|
|
|
|
self.name = data['name']
|
|
|
|
|
|
self.profiles = data['profiles']
|
|
|
|
|
|
self.map_id = data['id']
|
2021-01-01 22:18:06 +08:00
|
|
|
|
|
2020-09-18 18:45:20 +08:00
|
|
|
|
try:
|
2021-01-01 22:18:06 +08:00
|
|
|
|
self.spawn_data = self.parse_spawn_data(data)
|
|
|
|
|
|
if data_loop is not None:
|
|
|
|
|
|
self.spawn_data_loop = self.parse_spawn_data(data_loop)
|
|
|
|
|
|
if len(self.spawn_data) == len(self.spawn_data_loop) \
|
|
|
|
|
|
and all([s1 == s2 for s1, s2 in zip(self.spawn_data, self.spawn_data_loop)]):
|
|
|
|
|
|
self.spawn_data_loop = None
|
|
|
|
|
|
else:
|
|
|
|
|
|
self.spawn_data_loop = None
|
2020-06-21 23:26:35 +08:00
|
|
|
|
|
|
|
|
|
|
# map_data
|
|
|
|
|
|
# {0: {0: 6, 1: 8, 2: False, 3: 0}, ...}
|
2020-09-19 15:57:05 +08:00
|
|
|
|
self.map_data = self.parse_map_data(data['grids'])
|
2020-06-21 23:26:35 +08:00
|
|
|
|
self.shape = tuple(np.max(list(self.map_data.keys()), axis=0))
|
2020-09-19 15:57:05 +08:00
|
|
|
|
if self.data_loop is not None:
|
|
|
|
|
|
self.map_data_loop = self.parse_map_data(data_loop['grids'])
|
|
|
|
|
|
if all([d1 == d2 for d1, d2 in zip(self.map_data.values(), self.map_data_loop.values())]):
|
|
|
|
|
|
self.map_data_loop = None
|
|
|
|
|
|
else:
|
|
|
|
|
|
self.map_data_loop = None
|
|
|
|
|
|
|
|
|
|
|
|
# portal
|
|
|
|
|
|
self.portal = []
|
2024-07-26 00:40:16 +08:00
|
|
|
|
# if self.map_id in MAP_EVENT_LIST:
|
|
|
|
|
|
# for event_id in MAP_EVENT_LIST[self.map_id]['event_list'].values():
|
|
|
|
|
|
# event = MAP_EVENT_TEMPLATE[event_id]
|
|
|
|
|
|
# for effect in event['effect'].values():
|
|
|
|
|
|
# if effect[0] == 'jump':
|
|
|
|
|
|
# address = event['address']
|
|
|
|
|
|
# address = location2node((address[1], address[0]))
|
|
|
|
|
|
# target = location2node((effect[2], effect[1]))
|
|
|
|
|
|
# self.portal.append((address, target))
|
2020-08-20 15:58:29 +08:00
|
|
|
|
|
2020-11-13 22:20:31 +08:00
|
|
|
|
# land_based
|
|
|
|
|
|
# land_based = {{6, 7, 1}, ...}
|
|
|
|
|
|
# Format: {y, x, rotation}
|
|
|
|
|
|
land_based_rotation_dict = {1: 'up', 2: 'down', 3: 'left', 4: 'right'}
|
|
|
|
|
|
self.land_based = []
|
2020-12-15 15:40:35 +08:00
|
|
|
|
if isinstance(data['land_based'], dict):
|
|
|
|
|
|
for lb in data['land_based'].values():
|
|
|
|
|
|
y, x, r = lb.values()
|
2020-12-29 16:44:11 +08:00
|
|
|
|
if r not in land_based_rotation_dict:
|
|
|
|
|
|
continue
|
2020-12-15 15:40:35 +08:00
|
|
|
|
self.land_based.append([location2node((x, y)), land_based_rotation_dict[r]])
|
2020-11-13 22:20:31 +08:00
|
|
|
|
|
2020-08-20 15:58:29 +08:00
|
|
|
|
# config
|
2020-08-20 18:54:09 +08:00
|
|
|
|
self.MAP_SIREN_TEMPLATE = []
|
|
|
|
|
|
self.MOVABLE_ENEMY_TURN = set()
|
2022-07-28 21:25:16 +08:00
|
|
|
|
# Aquilifers Ballade (event_20220728_cn) has different sirens in clear mode
|
|
|
|
|
|
sirens = list(data['ai_expedition_list'].values())
|
|
|
|
|
|
if data_loop is not None and data_loop['ai_expedition_list'] is not None:
|
|
|
|
|
|
sirens += list(data_loop['ai_expedition_list'].values())
|
|
|
|
|
|
for siren_id in sirens:
|
2020-08-20 15:58:29 +08:00
|
|
|
|
if siren_id == 1:
|
|
|
|
|
|
continue
|
2021-09-16 14:59:45 +08:00
|
|
|
|
exped_data = EXPECTATION_DATA.get(siren_id, {})
|
|
|
|
|
|
name = exped_data.get('icon', str(siren_id))
|
2020-08-20 18:54:09 +08:00
|
|
|
|
name = DIC_SIREN_NAME_CHI_TO_ENG.get(name, name)
|
2020-11-15 02:06:10 +08:00
|
|
|
|
if name not in self.MAP_SIREN_TEMPLATE:
|
|
|
|
|
|
self.MAP_SIREN_TEMPLATE.append(name)
|
2021-09-16 14:59:45 +08:00
|
|
|
|
self.MOVABLE_ENEMY_TURN.add(int(exped_data.get('ai_mov', 2)))
|
2020-09-19 15:57:05 +08:00
|
|
|
|
self.MAP_HAS_MOVABLE_ENEMY = bool(len(self.MOVABLE_ENEMY_TURN))
|
2020-08-20 18:54:09 +08:00
|
|
|
|
self.MAP_HAS_MAP_STORY = len(data['story_refresh_boss']) > 0
|
|
|
|
|
|
self.MAP_HAS_FLEET_STEP = bool(data['is_limit_move'])
|
2020-09-19 15:57:05 +08:00
|
|
|
|
self.MAP_HAS_AMBUSH = bool(data['is_ambush']) or bool(data['is_air_attack'])
|
2021-09-16 18:10:52 +08:00
|
|
|
|
self.MAP_HAS_MYSTERY = sum([b.get('mystery', 0) for b in self.spawn_data]) > 0
|
2020-09-19 15:57:05 +08:00
|
|
|
|
self.MAP_HAS_PORTAL = bool(len(self.portal))
|
2020-11-13 22:20:31 +08:00
|
|
|
|
self.MAP_HAS_LAND_BASED = bool(len(self.land_based))
|
2020-09-18 18:45:20 +08:00
|
|
|
|
for n in range(1, 4):
|
|
|
|
|
|
self.__setattr__(f'STAR_REQUIRE_{n}', data[f'star_require_{n}'])
|
2020-06-21 23:26:35 +08:00
|
|
|
|
except Exception as e:
|
|
|
|
|
|
for k, v in data.items():
|
|
|
|
|
|
print(f'{k} = {v}')
|
|
|
|
|
|
raise e
|
|
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
|
return f'{self.map_id} {self.chapter_name} {self.name}'
|
|
|
|
|
|
|
|
|
|
|
|
__repr__ = __str__
|
|
|
|
|
|
|
2020-09-19 15:57:05 +08:00
|
|
|
|
def parse_map_data(self, grids):
|
|
|
|
|
|
map_data = {}
|
|
|
|
|
|
offset_y = min([grid[0] for grid in grids.values()])
|
|
|
|
|
|
offset_x = min([grid[1] for grid in grids.values()])
|
|
|
|
|
|
for grid in grids.values():
|
|
|
|
|
|
loca = (grid[1] - offset_x, grid[0] - offset_y)
|
|
|
|
|
|
if not grid[2]:
|
|
|
|
|
|
info = '++'
|
|
|
|
|
|
else:
|
|
|
|
|
|
info = self.dic_grid_info.get(grid[3], '??')
|
|
|
|
|
|
if info == '??':
|
|
|
|
|
|
print(f'Unknown grid info. grid={location2node(loca)}, info={grid[3]}')
|
|
|
|
|
|
map_data[loca] = info
|
|
|
|
|
|
|
|
|
|
|
|
return map_data
|
|
|
|
|
|
|
2021-01-01 22:18:06 +08:00
|
|
|
|
@staticmethod
|
|
|
|
|
|
def parse_spawn_data(data):
|
|
|
|
|
|
try:
|
|
|
|
|
|
battle_count = max(data['boss_refresh'], max(data['enemy_refresh'].keys()))
|
|
|
|
|
|
except ValueError:
|
|
|
|
|
|
battle_count = 0
|
|
|
|
|
|
spawn_data = [{'battle': index} for index in range(battle_count + 1)]
|
|
|
|
|
|
|
|
|
|
|
|
for index, count in data['enemy_refresh'].items():
|
|
|
|
|
|
if count:
|
|
|
|
|
|
spawn = spawn_data[index]
|
|
|
|
|
|
spawn['enemy'] = spawn.get('enemy', 0) + count
|
|
|
|
|
|
if ''.join([str(item) for item in data['elite_refresh'].values()]) != '100': # Some data is incorrect
|
|
|
|
|
|
for index, count in data['elite_refresh'].items():
|
|
|
|
|
|
if count:
|
|
|
|
|
|
spawn = spawn_data[index]
|
|
|
|
|
|
spawn['enemy'] = spawn.get('enemy', 0) + count
|
|
|
|
|
|
for index, count in data['ai_refresh'].items():
|
|
|
|
|
|
if count:
|
|
|
|
|
|
spawn = spawn_data[index]
|
|
|
|
|
|
spawn['siren'] = spawn.get('siren', 0) + count
|
|
|
|
|
|
for index, count in data['box_refresh'].items():
|
|
|
|
|
|
if count:
|
|
|
|
|
|
spawn = spawn_data[index]
|
|
|
|
|
|
spawn['mystery'] = spawn.get('mystery', 0) + count
|
|
|
|
|
|
try:
|
|
|
|
|
|
spawn_data[data['boss_refresh']]['boss'] = 1
|
|
|
|
|
|
except IndexError:
|
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
return spawn_data
|
|
|
|
|
|
|
2020-06-21 23:26:35 +08:00
|
|
|
|
def map_file_name(self):
|
|
|
|
|
|
name = self.chapter_name.replace('-', '_').lower()
|
|
|
|
|
|
if name[0].isdigit():
|
|
|
|
|
|
name = f'campaign_{name}'
|
|
|
|
|
|
return name + '.py'
|
|
|
|
|
|
|
2021-01-21 15:33:44 +08:00
|
|
|
|
def get_file_lines(self, has_modified_campaign_base):
|
2020-06-21 23:26:35 +08:00
|
|
|
|
"""
|
2021-01-21 15:33:44 +08:00
|
|
|
|
Args:
|
|
|
|
|
|
has_modified_campaign_base (bool): If target folder has modified campaign_base.py
|
|
|
|
|
|
|
2020-06-21 23:26:35 +08:00
|
|
|
|
Returns:
|
|
|
|
|
|
list(str): Python code in map file.
|
|
|
|
|
|
"""
|
2020-11-15 02:06:10 +08:00
|
|
|
|
if IS_WAR_ARCHIVES:
|
|
|
|
|
|
base_import = 'from ..campaign_war_archives.campaign_base import CampaignBase'
|
2021-01-21 15:33:44 +08:00
|
|
|
|
elif has_modified_campaign_base:
|
|
|
|
|
|
base_import = 'from .campaign_base import CampaignBase'
|
2020-11-15 02:06:10 +08:00
|
|
|
|
else:
|
|
|
|
|
|
base_import = 'from module.campaign.campaign_base import CampaignBase'
|
|
|
|
|
|
|
|
|
|
|
|
header = f"""
|
|
|
|
|
|
{base_import}
|
2020-06-21 23:26:35 +08:00
|
|
|
|
from module.map.map_base import CampaignMap
|
|
|
|
|
|
from module.map.map_grids import SelectedGrids, RoadGrids
|
|
|
|
|
|
from module.logger import logger
|
|
|
|
|
|
"""
|
|
|
|
|
|
lines = []
|
|
|
|
|
|
|
|
|
|
|
|
# Import
|
|
|
|
|
|
for head in header.strip().split('\n'):
|
|
|
|
|
|
lines.append(head.strip())
|
2020-08-20 15:20:52 +08:00
|
|
|
|
if self.chapter_name[-1].isdigit():
|
|
|
|
|
|
chap, stage = self.chapter_name[:-1], self.chapter_name[-1]
|
|
|
|
|
|
if stage != '1':
|
|
|
|
|
|
lines.append(f'from .{chap.lower()}1 import Config as ConfigBase')
|
2020-06-21 23:26:35 +08:00
|
|
|
|
lines.append('')
|
|
|
|
|
|
|
|
|
|
|
|
# Map
|
|
|
|
|
|
lines.append(f'MAP = CampaignMap(\'{self.chapter_name}\')')
|
|
|
|
|
|
lines.append(f'MAP.shape = \'{location2node(self.shape)}\'')
|
2021-02-25 17:07:59 +08:00
|
|
|
|
camera_data = camera_2d(get_map_active_area(self.map_data), sight=(-3, -1, 3, 2))
|
2020-06-21 23:26:35 +08:00
|
|
|
|
lines.append(
|
2020-09-18 19:35:30 +08:00
|
|
|
|
f'MAP.camera_data = {[location2node(loca) for loca in camera_data]}')
|
|
|
|
|
|
camera_sp = camera_spawn_point(camera_data, sp_list=[k for k, v in self.map_data.items() if v == 'SP'])
|
|
|
|
|
|
lines.append(f'MAP.camera_data_spawn_point = {[location2node(loca) for loca in camera_sp]}')
|
2020-11-13 22:20:31 +08:00
|
|
|
|
if self.MAP_HAS_PORTAL:
|
2020-09-19 15:57:05 +08:00
|
|
|
|
lines.append(f'MAP.portal_data = {self.portal}')
|
2020-06-21 23:26:35 +08:00
|
|
|
|
lines.append('MAP.map_data = \"\"\"')
|
|
|
|
|
|
for y in range(self.shape[1] + 1):
|
2024-08-17 00:30:49 +08:00
|
|
|
|
lines.append(' ' + ' '.join([self.map_data.get((x, y), '??') for x in range(self.shape[0] + 1)]))
|
2020-06-21 23:26:35 +08:00
|
|
|
|
lines.append('\"\"\"')
|
2020-09-19 15:57:05 +08:00
|
|
|
|
if self.map_data_loop is not None:
|
|
|
|
|
|
lines.append('MAP.map_data_loop = \"\"\"')
|
|
|
|
|
|
for y in range(self.shape[1] + 1):
|
|
|
|
|
|
lines.append(' ' + ' '.join([self.map_data_loop[(x, y)] for x in range(self.shape[0] + 1)]))
|
|
|
|
|
|
lines.append('\"\"\"')
|
2020-06-21 23:26:35 +08:00
|
|
|
|
lines.append('MAP.weight_data = \"\"\"')
|
|
|
|
|
|
for y in range(self.shape[1] + 1):
|
2020-09-04 15:16:51 +08:00
|
|
|
|
lines.append(' ' + ' '.join(['50'] * (self.shape[0] + 1)))
|
2020-06-21 23:26:35 +08:00
|
|
|
|
lines.append('\"\"\"')
|
2020-11-16 19:27:09 +08:00
|
|
|
|
if self.MAP_HAS_LAND_BASED:
|
|
|
|
|
|
lines.append(f'MAP.land_based_data = {self.land_based}')
|
2020-06-21 23:43:22 +08:00
|
|
|
|
lines.append('MAP.spawn_data = [')
|
|
|
|
|
|
for battle in self.spawn_data:
|
|
|
|
|
|
lines.append(' ' + str(battle) + ',')
|
|
|
|
|
|
lines.append(']')
|
2021-01-01 22:18:06 +08:00
|
|
|
|
if self.spawn_data_loop is not None:
|
|
|
|
|
|
lines.append('MAP.spawn_data_loop = [')
|
|
|
|
|
|
for battle in self.spawn_data_loop:
|
|
|
|
|
|
lines.append(' ' + str(battle) + ',')
|
|
|
|
|
|
lines.append(']')
|
2020-06-21 23:26:35 +08:00
|
|
|
|
for y in range(self.shape[1] + 1):
|
|
|
|
|
|
lines.append(', '.join([location2node((x, y)) for x in range(self.shape[0] + 1)]) + ', \\')
|
|
|
|
|
|
lines.append(' = MAP.flatten()')
|
|
|
|
|
|
lines.append('')
|
|
|
|
|
|
lines.append('')
|
|
|
|
|
|
|
|
|
|
|
|
# Config
|
2020-08-20 15:20:52 +08:00
|
|
|
|
if self.chapter_name[-1].isdigit():
|
|
|
|
|
|
chap, stage = self.chapter_name[:-1], self.chapter_name[-1]
|
|
|
|
|
|
if stage != '1':
|
|
|
|
|
|
lines.append('class Config(ConfigBase):')
|
|
|
|
|
|
else:
|
|
|
|
|
|
lines.append('class Config:')
|
2020-08-20 15:58:29 +08:00
|
|
|
|
else:
|
|
|
|
|
|
lines.append('class Config:')
|
2020-09-18 18:45:20 +08:00
|
|
|
|
lines.append(' # ===== Start of generated config =====')
|
2020-08-20 18:54:09 +08:00
|
|
|
|
if len(self.MAP_SIREN_TEMPLATE):
|
|
|
|
|
|
lines.append(f' MAP_SIREN_TEMPLATE = {self.MAP_SIREN_TEMPLATE}')
|
|
|
|
|
|
lines.append(f' MOVABLE_ENEMY_TURN = {tuple(self.MOVABLE_ENEMY_TURN)}')
|
|
|
|
|
|
lines.append(f' MAP_HAS_SIREN = True')
|
2020-09-19 15:57:05 +08:00
|
|
|
|
lines.append(f' MAP_HAS_MOVABLE_ENEMY = {self.MAP_HAS_MOVABLE_ENEMY}')
|
2020-08-20 18:54:09 +08:00
|
|
|
|
lines.append(f' MAP_HAS_MAP_STORY = {self.MAP_HAS_MAP_STORY}')
|
|
|
|
|
|
lines.append(f' MAP_HAS_FLEET_STEP = {self.MAP_HAS_FLEET_STEP}')
|
2020-09-19 15:57:05 +08:00
|
|
|
|
lines.append(f' MAP_HAS_AMBUSH = {self.MAP_HAS_AMBUSH}')
|
2021-09-16 18:10:52 +08:00
|
|
|
|
lines.append(f' MAP_HAS_MYSTERY = {self.MAP_HAS_MYSTERY}')
|
2026-02-26 23:48:08 +08:00
|
|
|
|
lines.append(f' MAP_CHAPTER_SWITCH_20241219 = True')
|
|
|
|
|
|
lines.append(f" STAGE_ENTRANCE = ['half', '20240725']")
|
|
|
|
|
|
lines.append(f' MAP_HAS_MODE_SWITCH = True')
|
|
|
|
|
|
lines.append(f' STAGE_INCREASE_AB = True')
|
|
|
|
|
|
lines.append(f' MAP_WALK_USE_CURRENT_FLEET = True')
|
2020-09-19 15:57:05 +08:00
|
|
|
|
if self.MAP_HAS_PORTAL:
|
|
|
|
|
|
lines.append(f' MAP_HAS_PORTAL = {self.MAP_HAS_PORTAL}')
|
2020-11-13 22:20:31 +08:00
|
|
|
|
if self.MAP_HAS_LAND_BASED:
|
|
|
|
|
|
lines.append(f' MAP_HAS_LAND_BASED = {self.MAP_HAS_LAND_BASED}')
|
2020-09-18 18:45:20 +08:00
|
|
|
|
for n in range(1, 4):
|
2021-03-25 19:44:43 +08:00
|
|
|
|
if self.__getattribute__(f'STAR_REQUIRE_{n}') != n:
|
2020-09-18 18:45:20 +08:00
|
|
|
|
lines.append(f' STAR_REQUIRE_{n} = 0')
|
|
|
|
|
|
lines.append(' # ===== End of generated config =====')
|
2020-06-21 23:26:35 +08:00
|
|
|
|
lines.append('')
|
|
|
|
|
|
lines.append('')
|
|
|
|
|
|
|
|
|
|
|
|
# Campaign
|
2021-10-28 17:43:51 +08:00
|
|
|
|
battle = self.data["boss_refresh"]
|
2020-06-21 23:26:35 +08:00
|
|
|
|
lines.append('class Campaign(CampaignBase):')
|
|
|
|
|
|
lines.append(' MAP = MAP')
|
2021-10-28 17:43:51 +08:00
|
|
|
|
lines.append(f' ENEMY_FILTER = \'{ENEMY_FILTER}\'')
|
2020-06-21 23:26:35 +08:00
|
|
|
|
lines.append('')
|
|
|
|
|
|
lines.append(' def battle_0(self):')
|
2020-08-20 18:54:09 +08:00
|
|
|
|
if len(self.MAP_SIREN_TEMPLATE):
|
|
|
|
|
|
lines.append(' if self.clear_siren():')
|
|
|
|
|
|
lines.append(' return True')
|
2021-10-28 17:43:51 +08:00
|
|
|
|
preserve = self.data["boss_refresh"] - 5 if battle >= 5 else 0
|
|
|
|
|
|
lines.append(f' if self.clear_filter_enemy(self.ENEMY_FILTER, preserve={preserve}):')
|
|
|
|
|
|
lines.append(' return True')
|
|
|
|
|
|
lines.append('')
|
2020-06-21 23:26:35 +08:00
|
|
|
|
lines.append(' return self.battle_default()')
|
|
|
|
|
|
lines.append('')
|
2021-10-28 17:43:51 +08:00
|
|
|
|
if battle >= 6:
|
|
|
|
|
|
lines.append(' def battle_5(self):')
|
|
|
|
|
|
if len(self.MAP_SIREN_TEMPLATE):
|
|
|
|
|
|
lines.append(' if self.clear_siren():')
|
|
|
|
|
|
lines.append(' return True')
|
|
|
|
|
|
preserve = 0
|
|
|
|
|
|
lines.append(f' if self.clear_filter_enemy(self.ENEMY_FILTER, preserve={preserve}):')
|
|
|
|
|
|
lines.append(' return True')
|
|
|
|
|
|
lines.append('')
|
|
|
|
|
|
lines.append(' return self.battle_default()')
|
|
|
|
|
|
lines.append('')
|
2020-06-21 23:26:35 +08:00
|
|
|
|
lines.append(f' def battle_{self.data["boss_refresh"]}(self):')
|
2021-10-28 17:43:51 +08:00
|
|
|
|
if battle >= 5:
|
2020-09-04 15:16:51 +08:00
|
|
|
|
lines.append(' return self.fleet_boss.clear_boss()')
|
|
|
|
|
|
else:
|
|
|
|
|
|
lines.append(' return self.clear_boss()')
|
2020-06-21 23:26:35 +08:00
|
|
|
|
|
|
|
|
|
|
return lines
|
|
|
|
|
|
|
|
|
|
|
|
def write(self, path):
|
|
|
|
|
|
file = os.path.join(path, self.map_file_name())
|
2021-01-21 15:33:44 +08:00
|
|
|
|
has_modified_campaign_base = os.path.exists(os.path.join(path, 'campaign_base.py'))
|
|
|
|
|
|
if has_modified_campaign_base:
|
|
|
|
|
|
print('Using existing campaign_base.py')
|
2020-06-21 23:26:35 +08:00
|
|
|
|
if os.path.exists(file):
|
2020-09-18 18:45:20 +08:00
|
|
|
|
if OVERWRITE:
|
|
|
|
|
|
print(f'Delete file: {file}')
|
|
|
|
|
|
os.remove(file)
|
|
|
|
|
|
else:
|
|
|
|
|
|
print(f'File exists: {file}')
|
|
|
|
|
|
return False
|
2020-06-21 23:26:35 +08:00
|
|
|
|
print(f'Extract: {file}')
|
|
|
|
|
|
with open(file, 'w') as f:
|
2021-01-21 15:33:44 +08:00
|
|
|
|
for text in self.get_file_lines(has_modified_campaign_base=has_modified_campaign_base):
|
2020-06-21 23:26:35 +08:00
|
|
|
|
f.write(text + '\n')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ChapterTemplate:
|
2020-09-19 15:57:05 +08:00
|
|
|
|
def __init__(self):
|
|
|
|
|
|
pass
|
2020-06-21 23:26:35 +08:00
|
|
|
|
|
|
|
|
|
|
def get_chapter_by_name(self, name, select=False):
|
|
|
|
|
|
"""
|
|
|
|
|
|
11004 (map id) --> 10-4 Hard
|
|
|
|
|
|
↑-- ↑
|
|
|
|
|
|
| | +-- stage index
|
|
|
|
|
|
| +---- chapter index
|
|
|
|
|
|
+------ 1 for hard, 0 for normal
|
|
|
|
|
|
|
|
|
|
|
|
1140017 (map id) --> Iris of Light and Dark D2
|
|
|
|
|
|
--- ↑↑
|
|
|
|
|
|
↑ |+-- stage index
|
|
|
|
|
|
| +--- chapter index
|
|
|
|
|
|
+------- event index, >=210 for war achieve
|
|
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
|
name (str, int): A keyword from chapter name, such as '短兵相接', '正义的怒吼'
|
|
|
|
|
|
Or map_id such as 702, 1140017
|
|
|
|
|
|
select (bool): False means only extract this map, True means all maps from this event
|
|
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
list(MapData):
|
|
|
|
|
|
"""
|
2024-07-26 00:40:16 +08:00
|
|
|
|
def is_extra(name):
|
|
|
|
|
|
name = name.lower().replace('.', '')
|
|
|
|
|
|
return name in ['extra', 'ex']
|
|
|
|
|
|
|
2020-06-21 23:26:35 +08:00
|
|
|
|
print('<<< SEARCH MAP >>>')
|
2020-07-13 15:10:44 +08:00
|
|
|
|
name = name.strip()
|
|
|
|
|
|
name = int(name) if name.isdigit() else name
|
2020-06-21 23:26:35 +08:00
|
|
|
|
print(f'Searching: {name}')
|
|
|
|
|
|
if isinstance(name, str):
|
|
|
|
|
|
maps = []
|
2020-09-19 15:57:05 +08:00
|
|
|
|
for map_id, data in DATA.items():
|
2025-08-15 20:30:57 +08:00
|
|
|
|
if not isinstance(map_id, int) or not isinstance(data, dict) or is_extra(data['chapter_name']):
|
2020-06-21 23:26:35 +08:00
|
|
|
|
continue
|
|
|
|
|
|
if not re.search(name, data['name']):
|
|
|
|
|
|
continue
|
2020-09-19 15:57:05 +08:00
|
|
|
|
data = MapData(data, DATA_LOOP.get(map_id, None))
|
2020-06-21 23:26:35 +08:00
|
|
|
|
print(f'Found map: {data}')
|
|
|
|
|
|
maps.append(data)
|
|
|
|
|
|
else:
|
2020-09-19 15:57:05 +08:00
|
|
|
|
data = MapData(DATA[name], DATA_LOOP.get(name, None))
|
2020-06-21 23:26:35 +08:00
|
|
|
|
print(f'Found map: {data}')
|
|
|
|
|
|
maps = [data]
|
|
|
|
|
|
|
|
|
|
|
|
if not len(maps):
|
|
|
|
|
|
print('No maps found')
|
|
|
|
|
|
return []
|
|
|
|
|
|
print('')
|
|
|
|
|
|
|
|
|
|
|
|
print('<<< SELECT MAP >>>')
|
2020-07-17 06:05:55 +08:00
|
|
|
|
|
|
|
|
|
|
def get_event_id(map_id):
|
|
|
|
|
|
return (map_id - 2100000) // 20 + 21000 if map_id // 10000 == 210 else map_id // 10000
|
|
|
|
|
|
|
2020-06-21 23:26:35 +08:00
|
|
|
|
if select:
|
2020-07-17 06:05:55 +08:00
|
|
|
|
event_id = get_event_id(maps[0].map_id)
|
2020-06-21 23:26:35 +08:00
|
|
|
|
new = []
|
2020-09-19 15:57:05 +08:00
|
|
|
|
for map_id, data in DATA.items():
|
2025-08-15 20:30:57 +08:00
|
|
|
|
if not isinstance(map_id, int) or not isinstance(data, dict) or is_extra(data['chapter_name']):
|
2020-06-21 23:26:35 +08:00
|
|
|
|
continue
|
2020-07-17 06:05:55 +08:00
|
|
|
|
if get_event_id(data['id']) == event_id:
|
2020-09-19 15:57:05 +08:00
|
|
|
|
data = MapData(data, DATA_LOOP.get(map_id, None))
|
2020-06-21 23:26:35 +08:00
|
|
|
|
print(f'Selected: {data}')
|
|
|
|
|
|
new.append(data)
|
|
|
|
|
|
maps = new
|
|
|
|
|
|
else:
|
|
|
|
|
|
maps = maps[:1]
|
|
|
|
|
|
print(f'Selected: {maps[0]}')
|
|
|
|
|
|
|
|
|
|
|
|
print('')
|
|
|
|
|
|
return maps
|
|
|
|
|
|
|
|
|
|
|
|
def extract(self, maps, folder):
|
|
|
|
|
|
"""
|
|
|
|
|
|
Args:
|
|
|
|
|
|
maps (list[MapData]):
|
|
|
|
|
|
folder (str):
|
|
|
|
|
|
"""
|
|
|
|
|
|
print('<<< CONFIRM >>>')
|
2020-09-18 18:45:20 +08:00
|
|
|
|
print('Please confirm selected the correct maps before extracting.\n'
|
2020-07-13 15:10:44 +08:00
|
|
|
|
'Input any key and press ENTER to continue')
|
2020-06-21 23:26:35 +08:00
|
|
|
|
input()
|
|
|
|
|
|
|
|
|
|
|
|
if not os.path.exists(folder):
|
|
|
|
|
|
os.mkdir(folder)
|
|
|
|
|
|
for data in maps:
|
|
|
|
|
|
data.write(folder)
|
|
|
|
|
|
|
2020-08-20 15:20:52 +08:00
|
|
|
|
|
2020-06-21 23:26:35 +08:00
|
|
|
|
"""
|
|
|
|
|
|
This an auto-tool to extract map files used in Alas.
|
|
|
|
|
|
|
2021-10-21 21:15:01 +08:00
|
|
|
|
Git clone https://github.com/AzurLaneTools/AzurLaneLuaScripts, to get the decrypted scripts.
|
2020-06-21 23:26:35 +08:00
|
|
|
|
Arguments:
|
2021-10-21 21:15:01 +08:00
|
|
|
|
FILE: Path to your AzurLaneLuaScripts directory
|
2020-11-15 02:06:10 +08:00
|
|
|
|
FOLDER: Folder to save, './campaign/test'
|
|
|
|
|
|
KEYWORD: A keyword in map name, such as '短兵相接' (7-2, zh-CN), 'Counterattack!' (3-4, en-US)
|
|
|
|
|
|
Or map id, such as 702 (7-2), 1140017 (Iris of Light and Dark D2)
|
|
|
|
|
|
SELECT: True if select all maps in the same event
|
|
|
|
|
|
False if extract this map only
|
|
|
|
|
|
OVERWRITE: If overwrite existing files
|
|
|
|
|
|
IS_WAR_ARCHIVES: True if retrieved map is to be
|
|
|
|
|
|
adapted for war_archives usage
|
2020-06-21 23:26:35 +08:00
|
|
|
|
"""
|
2024-02-29 23:17:57 +08:00
|
|
|
|
FILE = '../AzurLaneLuaScripts'
|
2024-06-28 03:19:37 +08:00
|
|
|
|
FOLDER = './campaign/test'
|
|
|
|
|
|
KEYWORD = ''
|
2023-12-23 00:11:34 +08:00
|
|
|
|
SELECT = True
|
2020-09-18 18:45:20 +08:00
|
|
|
|
OVERWRITE = True
|
2020-11-15 02:06:10 +08:00
|
|
|
|
IS_WAR_ARCHIVES = False
|
2021-10-28 17:43:51 +08:00
|
|
|
|
ENEMY_FILTER = '1L > 1M > 1E > 1C > 2L > 2M > 2E > 2C > 3L > 3M > 3E > 3C'
|
2020-06-21 23:26:35 +08:00
|
|
|
|
|
2021-10-21 21:15:01 +08:00
|
|
|
|
LOADER = LuaLoader(FILE, server='CN')
|
2022-05-26 18:56:46 +08:00
|
|
|
|
DATA = LOADER.load('./sharecfgdata/chapter_template.lua')
|
|
|
|
|
|
DATA_LOOP = LOADER.load('./sharecfgdata/chapter_template_loop.lua')
|
2024-07-26 00:40:16 +08:00
|
|
|
|
# MAP_EVENT_LIST = LOADER.load('./sharecfg/map_event_list.lua')
|
|
|
|
|
|
# MAP_EVENT_TEMPLATE = LOADER.load('./sharecfg/map_event_template.lua')
|
2021-11-11 18:25:34 +08:00
|
|
|
|
EXPECTATION_DATA = LOADER.load('./sharecfgdata/expedition_data_template.lua')
|
2020-09-19 15:57:05 +08:00
|
|
|
|
|
|
|
|
|
|
ct = ChapterTemplate()
|
2020-06-21 23:26:35 +08:00
|
|
|
|
ct.extract(ct.get_chapter_by_name(KEYWORD, select=SELECT), folder=FOLDER)
|