Compare commits
26 commits
Author | SHA1 | Date | |
---|---|---|---|
99ab5b239d | |||
84397a847e | |||
28864ff1e4 | |||
3c2397cdbd | |||
356fc5278e | |||
50f694add0 | |||
f99165e452 | |||
8d1211750b | |||
285fc0b6fa | |||
55b7ed3beb | |||
220fbc42f0 | |||
7d7bd76ae8 | |||
26fe9551d4 | |||
970dde020a | |||
2ccdf84dd0 | |||
fc121c7cba | |||
cbe169fe1a | |||
c710716fa1 | |||
d196ef861a | |||
d3cd213d27 | |||
a7da14c109 | |||
99123a15ef | |||
69634fda64 | |||
370f141f88 | |||
4b86d62d3f | |||
9af61cd33f |
123 changed files with 453997 additions and 888 deletions
|
@ -13,6 +13,8 @@ tokio-util = { version = "0.7.10", features = ["io"] }
|
|||
# Serialization
|
||||
serde = { version = "1.0.197", features = ["derive"] }
|
||||
serde_json = "1.0.114"
|
||||
jsonc-parser = { version = "0.23.0", features = ["serde"] }
|
||||
chrono = { version = "0.4.38", features = ["serde"] }
|
||||
toml = "0.8.4"
|
||||
rbase64 = "2.0.3"
|
||||
prost = "0.12.3"
|
||||
|
@ -61,6 +63,7 @@ atomic_enum = "0.3.0"
|
|||
num_enum = "0.7.2"
|
||||
dashmap = "6.0.1"
|
||||
regex = "1.10.5"
|
||||
rustyline-async = "0.4.2"
|
||||
ansi_term = "0.12.1"
|
||||
|
||||
# Internal
|
||||
|
|
|
@ -6,9 +6,13 @@
|
|||
### Current features
|
||||
- Logging in
|
||||
- Fully playable prologue
|
||||
- HollowDeepDive with Combat and Rally commissions
|
||||
- Archive (playable cutscenes and battles)
|
||||
- Open world
|
||||
- World exploration with any character (can be changed with a command)
|
||||
- Player progress saving with PostgreSQL
|
||||
- Unlock all characters
|
||||
- Training battle
|
||||
- Player management command system
|
||||
- Training
|
||||
|
||||
### Requirements
|
||||
- [Rust](https://www.rust-lang.org/tools/install)
|
||||
|
|
215
assets/EventConfig/Interacts.json
Normal file
215
assets/EventConfig/Interacts.json
Normal file
|
@ -0,0 +1,215 @@
|
|||
[
|
||||
{
|
||||
"event_id": 10000001,
|
||||
"actions": [
|
||||
{
|
||||
"$type": "SwitchSection",
|
||||
"section_id": 2,
|
||||
"camera_x": 1,
|
||||
"camera_y": 6000,
|
||||
"transform": "Workshop_PlayerPos_FromStreet"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"event_id": 10000002,
|
||||
"actions": [
|
||||
{
|
||||
"$type": "SwitchSection",
|
||||
"section_id": 3,
|
||||
"camera_x": 1,
|
||||
"camera_y": 6000,
|
||||
"transform": "Garage_PlayerPos_FromStreet"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"event_id": 10000003,
|
||||
"actions": [
|
||||
{
|
||||
"$type": "SwitchSection",
|
||||
"section_id": 1,
|
||||
"camera_x": 1,
|
||||
"camera_y": 6000,
|
||||
"transform": "Street_PlayerPos_FromWorkshop"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"event_id": 10000004,
|
||||
"actions": [
|
||||
{
|
||||
"$type": "SwitchSection",
|
||||
"section_id": 3,
|
||||
"camera_x": 1,
|
||||
"camera_y": 6000,
|
||||
"transform": "Garage_PlayerPos_FromWorkshop"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"event_id": 10000005,
|
||||
"actions": [
|
||||
{
|
||||
"$type": "SwitchSection",
|
||||
"section_id": 1,
|
||||
"camera_x": 1,
|
||||
"camera_y": 6000,
|
||||
"transform": "Street_PlayerPos_FromGarage"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"event_id": 10000006,
|
||||
"actions": [
|
||||
{
|
||||
"$type": "SwitchSection",
|
||||
"section_id": 2,
|
||||
"camera_x": 1,
|
||||
"camera_y": 6000,
|
||||
"transform": "Workshop_PlayerPos_FromGarage"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"event_id": 10000016,
|
||||
"actions": [
|
||||
{
|
||||
"$type": "SwitchSection",
|
||||
"section_id": 3,
|
||||
"camera_x": 1,
|
||||
"camera_y": 6000,
|
||||
"transform": "Garage_PlayerPos_FromStreet2"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"event_id": 10000017,
|
||||
"actions": [
|
||||
{
|
||||
"$type": "SwitchSection",
|
||||
"section_id": 1,
|
||||
"camera_x": 1,
|
||||
"camera_y": 6000,
|
||||
"transform": "Street_PlayerPos_FromGarage2"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"event_id": 15001601,
|
||||
"actions": [
|
||||
{
|
||||
"$type": "SwitchSection",
|
||||
"section_id": 153,
|
||||
"camera_x": 1,
|
||||
"camera_y": 6000,
|
||||
"transform": "Subway_PlayerPos_FromStreet"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"event_id": 15001102,
|
||||
"actions": [
|
||||
{
|
||||
"$type": "SwitchSection",
|
||||
"section_id": 1,
|
||||
"camera_x": 1,
|
||||
"camera_y": 6000,
|
||||
"transform": "Street_PlayerPos_FromZero"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"event_id": 15001302,
|
||||
"actions": [
|
||||
{
|
||||
"$type": "SwitchSection",
|
||||
"section_id": 101,
|
||||
"camera_x": 1,
|
||||
"camera_y": 6000,
|
||||
"transform": "Square_PlayerPos_FromFortuneHIA"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"event_id": 15001303,
|
||||
"actions": [
|
||||
{
|
||||
"$type": "SwitchSection",
|
||||
"section_id": 101,
|
||||
"camera_x": 1,
|
||||
"camera_y": 6000,
|
||||
"transform": "Square_PlayerPos_FromFortuneHIA"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"event_id": 15001701,
|
||||
"actions": [
|
||||
{
|
||||
"$type": "SwitchSection",
|
||||
"section_id": 153,
|
||||
"camera_x": 1,
|
||||
"camera_y": 6000,
|
||||
"transform": "Subway_PlayerPos_FromFortuneSquare01"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"event_id": 15001702,
|
||||
"actions": [
|
||||
{
|
||||
"$type": "SwitchSection",
|
||||
"section_id": 103,
|
||||
"camera_x": 1,
|
||||
"camera_y": 6000,
|
||||
"transform": "HIA_PlayerPos_FromFortuneSquare01"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"event_id": 15001701,
|
||||
"actions": [
|
||||
{
|
||||
"$type": "SwitchSection",
|
||||
"section_id": 153,
|
||||
"camera_x": 1,
|
||||
"camera_y": 6000,
|
||||
"transform": "Subway_PlayerPos_FromFortuneSquare02"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"event_id": 10000009,
|
||||
"actions": [
|
||||
{
|
||||
"$type": "OpenUi",
|
||||
"ui": "UIYorozuyaPage",
|
||||
"args": 0,
|
||||
"store_template_id": 1161
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"event_id": 10000010,
|
||||
"actions": [
|
||||
{
|
||||
"$type": "OpenUi",
|
||||
"ui": "UIMainStoryPage",
|
||||
"args": 0,
|
||||
"store_template_id": 1191
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"event_id": 15000301,
|
||||
"actions": [
|
||||
{
|
||||
"$type": "OpenUi",
|
||||
"ui": "UINewsStandPageController",
|
||||
"args": 0,
|
||||
"store_template_id": 1061
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
342
assets/FileCfg/ArchiveBattleQuestTemplateTb.json
Normal file
342
assets/FileCfg/ArchiveBattleQuestTemplateTb.json
Normal file
|
@ -0,0 +1,342 @@
|
|||
[
|
||||
{
|
||||
"ID": 107010011,
|
||||
"QuestName": "QuestName_107010011",
|
||||
"QuestDesc": "QuestDesc_107010011",
|
||||
"Target": "QuestTarget_107010011",
|
||||
"QuestType": 1,
|
||||
"Chapter": 1,
|
||||
"Difficulty": 1,
|
||||
"MonsterLevel": 1,
|
||||
"RecommendedLevel": 1,
|
||||
"EBCDABBGHMF": 3,
|
||||
"MLLPFMLKIKF": 0,
|
||||
"HollowID": 19900014,
|
||||
"FirstBattleEventID": 19900014,
|
||||
"BattleEventID": 19900019,
|
||||
"GGAEGKMMGLN": 999,
|
||||
"BattleRank": "1|101|208",
|
||||
"Slot1Avatar": 101000101,
|
||||
"Slot2Avatar": -1,
|
||||
"Slot3Avatar": -1,
|
||||
"Buddy": 0,
|
||||
"HGJGIMKPHLH": false,
|
||||
"LHNGFLLKHED": 0,
|
||||
"JGKFLKJNNHI": false,
|
||||
"KIFDIIKMIBJ": "Chapter0",
|
||||
"EDECGDLJIEB": "UI/Sprite/A1DynamicLoad/Hollow/ImgMission/UnPacker/ImgMission01.png",
|
||||
"JGBDOPDIDHA": "",
|
||||
"DGLENAGIGBO": false,
|
||||
"NPEBHOLENNI": 205,
|
||||
"NEIIOOLBAPD": false,
|
||||
"NABBCKLEDME": 0,
|
||||
"FBDEJOEECMJ": "",
|
||||
"CPJIMNGMCDO": 0
|
||||
},
|
||||
{
|
||||
"ID": 107010021,
|
||||
"QuestName": "QuestName_107010021",
|
||||
"QuestDesc": "QuestDesc_107010021",
|
||||
"Target": "QuestTarget_107010021",
|
||||
"QuestType": 1,
|
||||
"Chapter": 1,
|
||||
"Difficulty": 1,
|
||||
"MonsterLevel": 1,
|
||||
"RecommendedLevel": 1,
|
||||
"EBCDABBGHMF": 3,
|
||||
"MLLPFMLKIKF": 0,
|
||||
"HollowID": 19900015,
|
||||
"FirstBattleEventID": 19900015,
|
||||
"BattleEventID": 19900015,
|
||||
"GGAEGKMMGLN": 999,
|
||||
"BattleRank": "1|101|208",
|
||||
"Slot1Avatar": 101000201,
|
||||
"Slot2Avatar": 101000202,
|
||||
"Slot3Avatar": -1,
|
||||
"Buddy": 0,
|
||||
"HGJGIMKPHLH": false,
|
||||
"LHNGFLLKHED": 0,
|
||||
"JGKFLKJNNHI": false,
|
||||
"KIFDIIKMIBJ": "Chapter0",
|
||||
"EDECGDLJIEB": "UI/Sprite/A1DynamicLoad/Hollow/ImgMission/UnPacker/ImgMission01.png",
|
||||
"JGBDOPDIDHA": "",
|
||||
"DGLENAGIGBO": false,
|
||||
"NPEBHOLENNI": 205,
|
||||
"NEIIOOLBAPD": false,
|
||||
"NABBCKLEDME": 0,
|
||||
"FBDEJOEECMJ": "",
|
||||
"CPJIMNGMCDO": 0
|
||||
},
|
||||
{
|
||||
"ID": 107010031,
|
||||
"QuestName": "QuestName_107010031",
|
||||
"QuestDesc": "QuestDesc_107010031",
|
||||
"Target": "QuestTarget_107010031",
|
||||
"QuestType": 1,
|
||||
"Chapter": 1,
|
||||
"Difficulty": 1,
|
||||
"MonsterLevel": 1,
|
||||
"RecommendedLevel": 1,
|
||||
"EBCDABBGHMF": 3,
|
||||
"MLLPFMLKIKF": 0,
|
||||
"HollowID": 19900016,
|
||||
"FirstBattleEventID": 19900016,
|
||||
"BattleEventID": 19900016,
|
||||
"GGAEGKMMGLN": 999,
|
||||
"BattleRank": "1|101|208",
|
||||
"Slot1Avatar": 101000302,
|
||||
"Slot2Avatar": 101000301,
|
||||
"Slot3Avatar": -1,
|
||||
"Buddy": 0,
|
||||
"HGJGIMKPHLH": false,
|
||||
"LHNGFLLKHED": 0,
|
||||
"JGKFLKJNNHI": false,
|
||||
"KIFDIIKMIBJ": "Chapter0",
|
||||
"EDECGDLJIEB": "UI/Sprite/A1DynamicLoad/Hollow/ImgMission/UnPacker/ImgMission01.png",
|
||||
"JGBDOPDIDHA": "",
|
||||
"DGLENAGIGBO": false,
|
||||
"NPEBHOLENNI": 205,
|
||||
"NEIIOOLBAPD": false,
|
||||
"NABBCKLEDME": 0,
|
||||
"FBDEJOEECMJ": "",
|
||||
"CPJIMNGMCDO": 0
|
||||
},
|
||||
{
|
||||
"ID": 107010051,
|
||||
"QuestName": "QuestName_107010051",
|
||||
"QuestDesc": "QuestDesc_107010051",
|
||||
"Target": "QuestTarget_107010051",
|
||||
"QuestType": 1,
|
||||
"Chapter": 1,
|
||||
"Difficulty": 1,
|
||||
"MonsterLevel": 6,
|
||||
"RecommendedLevel": 6,
|
||||
"EBCDABBGHMF": 3,
|
||||
"MLLPFMLKIKF": 0,
|
||||
"HollowID": 19900017,
|
||||
"FirstBattleEventID": 19900017,
|
||||
"BattleEventID": 19900017,
|
||||
"GGAEGKMMGLN": 999,
|
||||
"BattleRank": "1|101|208",
|
||||
"Slot1Avatar": 101000501,
|
||||
"Slot2Avatar": 101000502,
|
||||
"Slot3Avatar": 101000503,
|
||||
"Buddy": 101000504,
|
||||
"HGJGIMKPHLH": true,
|
||||
"LHNGFLLKHED": 2,
|
||||
"JGKFLKJNNHI": true,
|
||||
"KIFDIIKMIBJ": "Chapter0",
|
||||
"EDECGDLJIEB": "UI/Sprite/A1DynamicLoad/Hollow/ImgMission/UnPacker/ImgMission01.png",
|
||||
"JGBDOPDIDHA": "",
|
||||
"DGLENAGIGBO": false,
|
||||
"NPEBHOLENNI": 205,
|
||||
"NEIIOOLBAPD": false,
|
||||
"NABBCKLEDME": 0,
|
||||
"FBDEJOEECMJ": "",
|
||||
"CPJIMNGMCDO": 0
|
||||
},
|
||||
{
|
||||
"ID": 107020021,
|
||||
"QuestName": "QuestName_107020021",
|
||||
"QuestDesc": "QuestDesc_107020021",
|
||||
"Target": "QuestTarget_107020021",
|
||||
"QuestType": 1,
|
||||
"Chapter": 2,
|
||||
"Difficulty": 1,
|
||||
"MonsterLevel": 9,
|
||||
"RecommendedLevel": 9,
|
||||
"EBCDABBGHMF": 3,
|
||||
"MLLPFMLKIKF": 0,
|
||||
"HollowID": 10202101,
|
||||
"FirstBattleEventID": 10202101,
|
||||
"BattleEventID": 10202101,
|
||||
"GGAEGKMMGLN": 999,
|
||||
"BattleRank": "1|101|208",
|
||||
"Slot1Avatar": 1000010101,
|
||||
"Slot2Avatar": 1000010102,
|
||||
"Slot3Avatar": 1000010103,
|
||||
"Buddy": 1000010104,
|
||||
"HGJGIMKPHLH": true,
|
||||
"LHNGFLLKHED": 2,
|
||||
"JGKFLKJNNHI": false,
|
||||
"KIFDIIKMIBJ": "Chapter0",
|
||||
"EDECGDLJIEB": "UI/Sprite/A1DynamicLoad/Hollow/ImgMission/UnPacker/ImgMission01.png",
|
||||
"JGBDOPDIDHA": "",
|
||||
"DGLENAGIGBO": false,
|
||||
"NPEBHOLENNI": 205,
|
||||
"NEIIOOLBAPD": false,
|
||||
"NABBCKLEDME": 0,
|
||||
"FBDEJOEECMJ": "",
|
||||
"CPJIMNGMCDO": 0
|
||||
},
|
||||
{
|
||||
"ID": 107020031,
|
||||
"QuestName": "QuestName_107020031",
|
||||
"QuestDesc": "QuestDesc_107020031",
|
||||
"Target": "QuestTarget_107020031",
|
||||
"QuestType": 1,
|
||||
"Chapter": 2,
|
||||
"Difficulty": 1,
|
||||
"MonsterLevel": 9,
|
||||
"RecommendedLevel": 9,
|
||||
"EBCDABBGHMF": 3,
|
||||
"MLLPFMLKIKF": 0,
|
||||
"HollowID": 10202102,
|
||||
"FirstBattleEventID": 10202102,
|
||||
"BattleEventID": 10202102,
|
||||
"GGAEGKMMGLN": 999,
|
||||
"BattleRank": "1|101|208",
|
||||
"Slot1Avatar": 1000010201,
|
||||
"Slot2Avatar": 1000010202,
|
||||
"Slot3Avatar": 1000010203,
|
||||
"Buddy": 1000010204,
|
||||
"HGJGIMKPHLH": true,
|
||||
"LHNGFLLKHED": 2,
|
||||
"JGKFLKJNNHI": false,
|
||||
"KIFDIIKMIBJ": "Chapter0",
|
||||
"EDECGDLJIEB": "UI/Sprite/A1DynamicLoad/Hollow/ImgMission/UnPacker/ImgMission01.png",
|
||||
"JGBDOPDIDHA": "",
|
||||
"DGLENAGIGBO": false,
|
||||
"NPEBHOLENNI": 205,
|
||||
"NEIIOOLBAPD": false,
|
||||
"NABBCKLEDME": 0,
|
||||
"FBDEJOEECMJ": "",
|
||||
"CPJIMNGMCDO": 0
|
||||
},
|
||||
{
|
||||
"ID": 107020041,
|
||||
"QuestName": "QuestName_107020041",
|
||||
"QuestDesc": "QuestDesc_107020041",
|
||||
"Target": "QuestTarget_107020041",
|
||||
"QuestType": 1,
|
||||
"Chapter": 2,
|
||||
"Difficulty": 1,
|
||||
"MonsterLevel": 9,
|
||||
"RecommendedLevel": 9,
|
||||
"EBCDABBGHMF": 3,
|
||||
"MLLPFMLKIKF": 0,
|
||||
"HollowID": 10202103,
|
||||
"FirstBattleEventID": 10202103,
|
||||
"BattleEventID": 10202103,
|
||||
"GGAEGKMMGLN": 999,
|
||||
"BattleRank": "1|101|208",
|
||||
"Slot1Avatar": 1000010301,
|
||||
"Slot2Avatar": 1000010302,
|
||||
"Slot3Avatar": 1000010303,
|
||||
"Buddy": 1000010304,
|
||||
"HGJGIMKPHLH": true,
|
||||
"LHNGFLLKHED": 2,
|
||||
"JGKFLKJNNHI": false,
|
||||
"KIFDIIKMIBJ": "Chapter0",
|
||||
"EDECGDLJIEB": "UI/Sprite/A1DynamicLoad/Hollow/ImgMission/UnPacker/ImgMission01.png",
|
||||
"JGBDOPDIDHA": "",
|
||||
"DGLENAGIGBO": false,
|
||||
"NPEBHOLENNI": 205,
|
||||
"NEIIOOLBAPD": false,
|
||||
"NABBCKLEDME": 0,
|
||||
"FBDEJOEECMJ": "",
|
||||
"CPJIMNGMCDO": 0
|
||||
},
|
||||
{
|
||||
"ID": 107030021,
|
||||
"QuestName": "QuestName_107030021",
|
||||
"QuestDesc": "QuestDesc_107030021",
|
||||
"Target": "QuestTarget_107030021",
|
||||
"QuestType": 1,
|
||||
"Chapter": 3,
|
||||
"Difficulty": 1,
|
||||
"MonsterLevel": 11,
|
||||
"RecommendedLevel": 11,
|
||||
"EBCDABBGHMF": 4,
|
||||
"MLLPFMLKIKF": 0,
|
||||
"HollowID": 10202104,
|
||||
"FirstBattleEventID": 10202104,
|
||||
"BattleEventID": 10202104,
|
||||
"GGAEGKMMGLN": 999,
|
||||
"BattleRank": "1|101|208",
|
||||
"Slot1Avatar": 1000010601,
|
||||
"Slot2Avatar": 1000010602,
|
||||
"Slot3Avatar": 1000010603,
|
||||
"Buddy": 1000010604,
|
||||
"HGJGIMKPHLH": true,
|
||||
"LHNGFLLKHED": 2,
|
||||
"JGKFLKJNNHI": false,
|
||||
"KIFDIIKMIBJ": "Chapter0",
|
||||
"EDECGDLJIEB": "UI/Sprite/A1DynamicLoad/Hollow/ImgMission/UnPacker/ImgMission01.png",
|
||||
"JGBDOPDIDHA": "",
|
||||
"DGLENAGIGBO": false,
|
||||
"NPEBHOLENNI": 205,
|
||||
"NEIIOOLBAPD": false,
|
||||
"NABBCKLEDME": 0,
|
||||
"FBDEJOEECMJ": "",
|
||||
"CPJIMNGMCDO": 0
|
||||
},
|
||||
{
|
||||
"ID": 107030031,
|
||||
"QuestName": "QuestName_107030031",
|
||||
"QuestDesc": "QuestDesc_107030031",
|
||||
"Target": "QuestTarget_107030031",
|
||||
"QuestType": 1,
|
||||
"Chapter": 3,
|
||||
"Difficulty": 1,
|
||||
"MonsterLevel": 12,
|
||||
"RecommendedLevel": 12,
|
||||
"EBCDABBGHMF": 4,
|
||||
"MLLPFMLKIKF": 0,
|
||||
"HollowID": 10202106,
|
||||
"FirstBattleEventID": 10202106,
|
||||
"BattleEventID": 10202106,
|
||||
"GGAEGKMMGLN": 999,
|
||||
"BattleRank": "1|101|208",
|
||||
"Slot1Avatar": 1000010701,
|
||||
"Slot2Avatar": 1000010702,
|
||||
"Slot3Avatar": 1000010703,
|
||||
"Buddy": 1000010704,
|
||||
"HGJGIMKPHLH": true,
|
||||
"LHNGFLLKHED": 2,
|
||||
"JGKFLKJNNHI": false,
|
||||
"KIFDIIKMIBJ": "Chapter0",
|
||||
"EDECGDLJIEB": "UI/Sprite/A1DynamicLoad/Hollow/ImgMission/UnPacker/ImgMission01.png",
|
||||
"JGBDOPDIDHA": "",
|
||||
"DGLENAGIGBO": false,
|
||||
"NPEBHOLENNI": 205,
|
||||
"NEIIOOLBAPD": false,
|
||||
"NABBCKLEDME": 0,
|
||||
"FBDEJOEECMJ": "",
|
||||
"CPJIMNGMCDO": 0
|
||||
},
|
||||
{
|
||||
"ID": 107030041,
|
||||
"QuestName": "QuestName_107030041",
|
||||
"QuestDesc": "QuestDesc_107030041",
|
||||
"Target": "QuestTarget_107030041",
|
||||
"QuestType": 1,
|
||||
"Chapter": 3,
|
||||
"Difficulty": 1,
|
||||
"MonsterLevel": 13,
|
||||
"RecommendedLevel": 13,
|
||||
"EBCDABBGHMF": 4,
|
||||
"MLLPFMLKIKF": 0,
|
||||
"HollowID": 10202108,
|
||||
"FirstBattleEventID": 10202108,
|
||||
"BattleEventID": 10202108,
|
||||
"GGAEGKMMGLN": 999,
|
||||
"BattleRank": "1|101|208",
|
||||
"Slot1Avatar": 1000010801,
|
||||
"Slot2Avatar": 1000010802,
|
||||
"Slot3Avatar": 1000010803,
|
||||
"Buddy": 1000010804,
|
||||
"HGJGIMKPHLH": true,
|
||||
"LHNGFLLKHED": 2,
|
||||
"JGKFLKJNNHI": false,
|
||||
"KIFDIIKMIBJ": "Chapter0",
|
||||
"EDECGDLJIEB": "UI/Sprite/A1DynamicLoad/Hollow/ImgMission/UnPacker/ImgMission01.png",
|
||||
"JGBDOPDIDHA": "",
|
||||
"DGLENAGIGBO": false,
|
||||
"NPEBHOLENNI": 205,
|
||||
"NEIIOOLBAPD": false,
|
||||
"NABBCKLEDME": 0,
|
||||
"FBDEJOEECMJ": "",
|
||||
"CPJIMNGMCDO": 0
|
||||
}
|
||||
]
|
1229
assets/FileCfg/ArchiveFileQuestTemplateTb.json
Normal file
1229
assets/FileCfg/ArchiveFileQuestTemplateTb.json
Normal file
File diff suppressed because it is too large
Load diff
31203
assets/FileCfg/BattleEventConfigTemplateTb.json
Normal file
31203
assets/FileCfg/BattleEventConfigTemplateTb.json
Normal file
File diff suppressed because it is too large
Load diff
1262
assets/FileCfg/BattleGroupConfigTemplateTb.json
Normal file
1262
assets/FileCfg/BattleGroupConfigTemplateTb.json
Normal file
File diff suppressed because it is too large
Load diff
266
assets/FileCfg/BuddyBaseTemplateTb.json
Normal file
266
assets/FileCfg/BuddyBaseTemplateTb.json
Normal file
|
@ -0,0 +1,266 @@
|
|||
[
|
||||
{
|
||||
"ID": 50001,
|
||||
"BuddyType": 1,
|
||||
"ECHNDHDIIAC": 0,
|
||||
"OHLKAFPBJHD": 0,
|
||||
"GDDJBFHBJNK": 1,
|
||||
"LAFKHMCKNIO": "Bangboo_Name_en_50001",
|
||||
"DIIDBBGLDOL": "Bangboo_Name_50001",
|
||||
"PCNEIBEDMCO": "BK_Eous",
|
||||
"HIMPMHKGGIC": "",
|
||||
"ANDDIMCDBME": 9831098947874880184
|
||||
},
|
||||
{
|
||||
"ID": 53001,
|
||||
"BuddyType": 2,
|
||||
"ECHNDHDIIAC": 0,
|
||||
"OHLKAFPBJHD": 0,
|
||||
"GDDJBFHBJNK": 1,
|
||||
"LAFKHMCKNIO": "Bangboo_Name_en_53001",
|
||||
"DIIDBBGLDOL": "Bangboo_Name_53001",
|
||||
"PCNEIBEDMCO": "BK_Eous",
|
||||
"HIMPMHKGGIC": "",
|
||||
"ANDDIMCDBME": 8017298617212498953
|
||||
},
|
||||
{
|
||||
"ID": 53002,
|
||||
"BuddyType": 2,
|
||||
"ECHNDHDIIAC": 0,
|
||||
"OHLKAFPBJHD": 0,
|
||||
"GDDJBFHBJNK": 1,
|
||||
"LAFKHMCKNIO": "Bangboo_Name_en_53002",
|
||||
"DIIDBBGLDOL": "Bangboo_Name_53002",
|
||||
"PCNEIBEDMCO": "BK_Eous",
|
||||
"HIMPMHKGGIC": "",
|
||||
"ANDDIMCDBME": 15759244567804428825
|
||||
},
|
||||
{
|
||||
"ID": 53003,
|
||||
"BuddyType": 2,
|
||||
"ECHNDHDIIAC": 0,
|
||||
"OHLKAFPBJHD": 0,
|
||||
"GDDJBFHBJNK": 1,
|
||||
"LAFKHMCKNIO": "Bangboo_Name_en_53003",
|
||||
"DIIDBBGLDOL": "Bangboo_Name_53003",
|
||||
"PCNEIBEDMCO": "BK_Eous",
|
||||
"HIMPMHKGGIC": "",
|
||||
"ANDDIMCDBME": 793541769103470830
|
||||
},
|
||||
{
|
||||
"ID": 53004,
|
||||
"BuddyType": 2,
|
||||
"ECHNDHDIIAC": 0,
|
||||
"OHLKAFPBJHD": 0,
|
||||
"GDDJBFHBJNK": 1,
|
||||
"LAFKHMCKNIO": "Bangboo_Name_en_53004",
|
||||
"DIIDBBGLDOL": "Bangboo_Name_53004",
|
||||
"PCNEIBEDMCO": "BK_Eous",
|
||||
"HIMPMHKGGIC": "",
|
||||
"ANDDIMCDBME": 15333283710424173893
|
||||
},
|
||||
{
|
||||
"ID": 53005,
|
||||
"BuddyType": 2,
|
||||
"ECHNDHDIIAC": 0,
|
||||
"OHLKAFPBJHD": 0,
|
||||
"GDDJBFHBJNK": 1,
|
||||
"LAFKHMCKNIO": "Bangboo_Name_en_53005",
|
||||
"DIIDBBGLDOL": "Bangboo_Name_53005",
|
||||
"PCNEIBEDMCO": "BK_Eous",
|
||||
"HIMPMHKGGIC": "",
|
||||
"ANDDIMCDBME": 6625485447473768309
|
||||
},
|
||||
{
|
||||
"ID": 53006,
|
||||
"BuddyType": 2,
|
||||
"ECHNDHDIIAC": 0,
|
||||
"OHLKAFPBJHD": 0,
|
||||
"GDDJBFHBJNK": 1,
|
||||
"LAFKHMCKNIO": "Bangboo_Name_en_53006",
|
||||
"DIIDBBGLDOL": "Bangboo_Name_53006",
|
||||
"PCNEIBEDMCO": "BK_Eous",
|
||||
"HIMPMHKGGIC": "",
|
||||
"ANDDIMCDBME": 12516213533679239810
|
||||
},
|
||||
{
|
||||
"ID": 53007,
|
||||
"BuddyType": 2,
|
||||
"ECHNDHDIIAC": 0,
|
||||
"OHLKAFPBJHD": 0,
|
||||
"GDDJBFHBJNK": 1,
|
||||
"LAFKHMCKNIO": "Bangboo_Name_en_53007",
|
||||
"DIIDBBGLDOL": "Bangboo_Name_53007",
|
||||
"PCNEIBEDMCO": "BK_Eous",
|
||||
"HIMPMHKGGIC": "",
|
||||
"ANDDIMCDBME": 1205030983673817181
|
||||
},
|
||||
{
|
||||
"ID": 53008,
|
||||
"BuddyType": 2,
|
||||
"ECHNDHDIIAC": 0,
|
||||
"OHLKAFPBJHD": 0,
|
||||
"GDDJBFHBJNK": 1,
|
||||
"LAFKHMCKNIO": "Bangboo_Name_en_53008",
|
||||
"DIIDBBGLDOL": "Bangboo_Name_53008",
|
||||
"PCNEIBEDMCO": "BK_Eous",
|
||||
"HIMPMHKGGIC": "",
|
||||
"ANDDIMCDBME": 825481331324073038
|
||||
},
|
||||
{
|
||||
"ID": 53009,
|
||||
"BuddyType": 2,
|
||||
"ECHNDHDIIAC": 0,
|
||||
"OHLKAFPBJHD": 0,
|
||||
"GDDJBFHBJNK": 1,
|
||||
"LAFKHMCKNIO": "Bangboo_Name_en_53009",
|
||||
"DIIDBBGLDOL": "Bangboo_Name_53009",
|
||||
"PCNEIBEDMCO": "BK_Eous",
|
||||
"HIMPMHKGGIC": "",
|
||||
"ANDDIMCDBME": 1109142289374885163
|
||||
},
|
||||
{
|
||||
"ID": 53010,
|
||||
"BuddyType": 2,
|
||||
"ECHNDHDIIAC": 0,
|
||||
"OHLKAFPBJHD": 0,
|
||||
"GDDJBFHBJNK": 1,
|
||||
"LAFKHMCKNIO": "Bangboo_Name_en_53010",
|
||||
"DIIDBBGLDOL": "Bangboo_Name_53010",
|
||||
"PCNEIBEDMCO": "BK_Eous",
|
||||
"HIMPMHKGGIC": "",
|
||||
"ANDDIMCDBME": 7654740197435466664
|
||||
},
|
||||
{
|
||||
"ID": 53011,
|
||||
"BuddyType": 2,
|
||||
"ECHNDHDIIAC": 0,
|
||||
"OHLKAFPBJHD": 0,
|
||||
"GDDJBFHBJNK": 1,
|
||||
"LAFKHMCKNIO": "Bangboo_Name_en_53011",
|
||||
"DIIDBBGLDOL": "Bangboo_Name_53011",
|
||||
"PCNEIBEDMCO": "BK_Eous",
|
||||
"HIMPMHKGGIC": "",
|
||||
"ANDDIMCDBME": 13043263780191768021
|
||||
},
|
||||
{
|
||||
"ID": 53012,
|
||||
"BuddyType": 2,
|
||||
"ECHNDHDIIAC": 0,
|
||||
"OHLKAFPBJHD": 0,
|
||||
"GDDJBFHBJNK": 1,
|
||||
"LAFKHMCKNIO": "Bangboo_Name_en_53012",
|
||||
"DIIDBBGLDOL": "Bangboo_Name_53012",
|
||||
"PCNEIBEDMCO": "BK_Eous",
|
||||
"HIMPMHKGGIC": "",
|
||||
"ANDDIMCDBME": 2166541009547495725
|
||||
},
|
||||
{
|
||||
"ID": 54001,
|
||||
"BuddyType": 2,
|
||||
"ECHNDHDIIAC": 0,
|
||||
"OHLKAFPBJHD": 0,
|
||||
"GDDJBFHBJNK": 1,
|
||||
"LAFKHMCKNIO": "Bangboo_Name_en_54001",
|
||||
"DIIDBBGLDOL": "Bangboo_Name_54001",
|
||||
"PCNEIBEDMCO": "BK_Eous",
|
||||
"HIMPMHKGGIC": "",
|
||||
"ANDDIMCDBME": 12126171553945369848
|
||||
},
|
||||
{
|
||||
"ID": 54002,
|
||||
"BuddyType": 2,
|
||||
"ECHNDHDIIAC": 3,
|
||||
"OHLKAFPBJHD": 0,
|
||||
"GDDJBFHBJNK": 1,
|
||||
"LAFKHMCKNIO": "Bangboo_Name_en_54002",
|
||||
"DIIDBBGLDOL": "Bangboo_Name_54002",
|
||||
"PCNEIBEDMCO": "BK_Eous",
|
||||
"HIMPMHKGGIC": "",
|
||||
"ANDDIMCDBME": 13558320022686804846
|
||||
},
|
||||
{
|
||||
"ID": 54003,
|
||||
"BuddyType": 2,
|
||||
"ECHNDHDIIAC": 0,
|
||||
"OHLKAFPBJHD": 0,
|
||||
"GDDJBFHBJNK": 1,
|
||||
"LAFKHMCKNIO": "Bangboo_Name_en_54003",
|
||||
"DIIDBBGLDOL": "Bangboo_Name_54003",
|
||||
"PCNEIBEDMCO": "BK_Eous",
|
||||
"HIMPMHKGGIC": "",
|
||||
"ANDDIMCDBME": 9057893760084610210
|
||||
},
|
||||
{
|
||||
"ID": 54004,
|
||||
"BuddyType": 2,
|
||||
"ECHNDHDIIAC": 2,
|
||||
"OHLKAFPBJHD": 0,
|
||||
"GDDJBFHBJNK": 1,
|
||||
"LAFKHMCKNIO": "Bangboo_Name_en_54004",
|
||||
"DIIDBBGLDOL": "Bangboo_Name_54004",
|
||||
"PCNEIBEDMCO": "BK_Eous",
|
||||
"HIMPMHKGGIC": "",
|
||||
"ANDDIMCDBME": 7098007717545413607
|
||||
},
|
||||
{
|
||||
"ID": 54005,
|
||||
"BuddyType": 2,
|
||||
"ECHNDHDIIAC": 1,
|
||||
"OHLKAFPBJHD": 0,
|
||||
"GDDJBFHBJNK": 1,
|
||||
"LAFKHMCKNIO": "Bangboo_Name_en_54005",
|
||||
"DIIDBBGLDOL": "Bangboo_Name_54005",
|
||||
"PCNEIBEDMCO": "BK_Eous",
|
||||
"HIMPMHKGGIC": "",
|
||||
"ANDDIMCDBME": 7896901026978333696
|
||||
},
|
||||
{
|
||||
"ID": 54006,
|
||||
"BuddyType": 2,
|
||||
"ECHNDHDIIAC": 0,
|
||||
"OHLKAFPBJHD": 0,
|
||||
"GDDJBFHBJNK": 1,
|
||||
"LAFKHMCKNIO": "Bangboo_Name_en_54006",
|
||||
"DIIDBBGLDOL": "Bangboo_Name_54006",
|
||||
"PCNEIBEDMCO": "BK_Eous",
|
||||
"HIMPMHKGGIC": "",
|
||||
"ANDDIMCDBME": 15413390933002967244
|
||||
},
|
||||
{
|
||||
"ID": 54008,
|
||||
"BuddyType": 2,
|
||||
"ECHNDHDIIAC": 0,
|
||||
"OHLKAFPBJHD": 0,
|
||||
"GDDJBFHBJNK": 1,
|
||||
"LAFKHMCKNIO": "Bangboo_Name_en_54008",
|
||||
"DIIDBBGLDOL": "Bangboo_Name_54008",
|
||||
"PCNEIBEDMCO": "BK_Eous",
|
||||
"HIMPMHKGGIC": "",
|
||||
"ANDDIMCDBME": 13745481736816990381
|
||||
},
|
||||
{
|
||||
"ID": 54009,
|
||||
"BuddyType": 2,
|
||||
"ECHNDHDIIAC": 0,
|
||||
"OHLKAFPBJHD": 0,
|
||||
"GDDJBFHBJNK": 1,
|
||||
"LAFKHMCKNIO": "Bangboo_Name_en_54009",
|
||||
"DIIDBBGLDOL": "Bangboo_Name_54009",
|
||||
"PCNEIBEDMCO": "BK_Eous",
|
||||
"HIMPMHKGGIC": "",
|
||||
"ANDDIMCDBME": 4565374391606395253
|
||||
},
|
||||
{
|
||||
"ID": 54013,
|
||||
"BuddyType": 2,
|
||||
"ECHNDHDIIAC": 0,
|
||||
"OHLKAFPBJHD": 0,
|
||||
"GDDJBFHBJNK": 1,
|
||||
"LAFKHMCKNIO": "Bangboo_Name_en_54013",
|
||||
"DIIDBBGLDOL": "Bangboo_Name_54013",
|
||||
"PCNEIBEDMCO": "BK_Eous",
|
||||
"HIMPMHKGGIC": "",
|
||||
"ANDDIMCDBME": 4076165347655962714
|
||||
}
|
||||
]
|
212
assets/FileCfg/HollowConfigTemplateTb.json
Normal file
212
assets/FileCfg/HollowConfigTemplateTb.json
Normal file
|
@ -0,0 +1,212 @@
|
|||
[
|
||||
{
|
||||
"ID": 100001,
|
||||
"FOPDNLNNHDJ": 1000,
|
||||
"DIIDBBGLDOL": "HollowGroupNameText_Arcade",
|
||||
"EFPBDDJIJBO": "1040140114",
|
||||
"OCBLGHECPLH": "Hollow_LockedHint_01",
|
||||
"BEIEFNLAJCH": "UI/Sprite/A1DynamicLoad/YorozuyaPage/UnPacker/Icon_RallyQuest.png",
|
||||
"CCFBKFKFJGM": "UI/3D/Yorozuya/Yorozuya_Hollow_Sphere_L.prefab",
|
||||
"LDKNDDHOHND": "FF0019FF",
|
||||
"EEBAIANJMEC": "006EFFFF|FF001900",
|
||||
"EKMLECIKMID": false,
|
||||
"FNIGJDFMHBA": "",
|
||||
"BECFHCOGPKG": ""
|
||||
},
|
||||
{
|
||||
"ID": 100101,
|
||||
"FOPDNLNNHDJ": 1001,
|
||||
"DIIDBBGLDOL": "HollowGroupNameText_Story",
|
||||
"EFPBDDJIJBO": "",
|
||||
"OCBLGHECPLH": "Hollow_LockedHint_01",
|
||||
"BEIEFNLAJCH": "UI/Sprite/A1DynamicLoad/YorozuyaPage/UnPacker/Icon_Story.png",
|
||||
"CCFBKFKFJGM": "UI/3D/Yorozuya/Yorozuya_Hollow_Sphere_M.prefab",
|
||||
"LDKNDDHOHND": "FF9500FF",
|
||||
"EEBAIANJMEC": "FF9500FF|FFDE0000",
|
||||
"EKMLECIKMID": false,
|
||||
"FNIGJDFMHBA": "UI/Menus/Widget/Yorozuya/Icon_MapTips.prefab",
|
||||
"BECFHCOGPKG": "YorozuyaMapTipsUnLockChange_01"
|
||||
},
|
||||
{
|
||||
"ID": 100102,
|
||||
"FOPDNLNNHDJ": 1001,
|
||||
"DIIDBBGLDOL": "HollowGroupNameText_exploration",
|
||||
"EFPBDDJIJBO": "",
|
||||
"OCBLGHECPLH": "Hollow_LockedHint_01",
|
||||
"BEIEFNLAJCH": "UI/Sprite/A1DynamicLoad/YorozuyaPage/UnPacker/Icon_Explore.png",
|
||||
"CCFBKFKFJGM": "UI/3D/Yorozuya/Yorozuya_Hollow_Sphere_M02.prefab",
|
||||
"LDKNDDHOHND": "00A1FFFF",
|
||||
"EEBAIANJMEC": "00A1FFFF|00FFD300",
|
||||
"EKMLECIKMID": true,
|
||||
"FNIGJDFMHBA": "UI/Menus/Widget/Yorozuya/Icon_MapTips03.prefab",
|
||||
"BECFHCOGPKG": "YorozuyaMapTipsUnLockChange_03"
|
||||
},
|
||||
{
|
||||
"ID": 100103,
|
||||
"FOPDNLNNHDJ": 1001,
|
||||
"DIIDBBGLDOL": "HollowGroupNameText_combat",
|
||||
"EFPBDDJIJBO": "",
|
||||
"OCBLGHECPLH": "Hollow_LockedHint_01",
|
||||
"BEIEFNLAJCH": "UI/Sprite/A1DynamicLoad/YorozuyaPage/UnPacker/Icon_Combat.png",
|
||||
"CCFBKFKFJGM": "UI/3D/Yorozuya/Yorozuya_Hollow_Sphere_S.prefab",
|
||||
"LDKNDDHOHND": "00A1FFFF",
|
||||
"EEBAIANJMEC": "00A1FFFF|00FFD300",
|
||||
"EKMLECIKMID": true,
|
||||
"FNIGJDFMHBA": "UI/Menus/Widget/Yorozuya/Icon_MapTips02.prefab",
|
||||
"BECFHCOGPKG": "YorozuyaMapTipsUnLockChange_02"
|
||||
},
|
||||
{
|
||||
"ID": 100201,
|
||||
"FOPDNLNNHDJ": 1002,
|
||||
"DIIDBBGLDOL": "HollowGroupNameText_Story",
|
||||
"EFPBDDJIJBO": "",
|
||||
"OCBLGHECPLH": "Hollow_LockedHint_01",
|
||||
"BEIEFNLAJCH": "UI/Sprite/A1DynamicLoad/YorozuyaPage/UnPacker/Icon_Story.png",
|
||||
"CCFBKFKFJGM": "UI/3D/Yorozuya/Yorozuya_Hollow_Sphere_M.prefab",
|
||||
"LDKNDDHOHND": "FF9500FF",
|
||||
"EEBAIANJMEC": "FF9500FF|FFDE0000",
|
||||
"EKMLECIKMID": true,
|
||||
"FNIGJDFMHBA": "UI/Menus/Widget/Yorozuya/Icon_MapTips.prefab",
|
||||
"BECFHCOGPKG": "YorozuyaMapTipsUnLockChange_01"
|
||||
},
|
||||
{
|
||||
"ID": 100202,
|
||||
"FOPDNLNNHDJ": 1002,
|
||||
"DIIDBBGLDOL": "HollowGroupNameText_exploration",
|
||||
"EFPBDDJIJBO": "",
|
||||
"OCBLGHECPLH": "Hollow_LockedHint_01",
|
||||
"BEIEFNLAJCH": "UI/Sprite/A1DynamicLoad/YorozuyaPage/UnPacker/Icon_Explore.png",
|
||||
"CCFBKFKFJGM": "UI/3D/Yorozuya/Yorozuya_Hollow_Sphere_M02.prefab",
|
||||
"LDKNDDHOHND": "00A1FFFF",
|
||||
"EEBAIANJMEC": "00A1FFFF|00FFD300",
|
||||
"EKMLECIKMID": true,
|
||||
"FNIGJDFMHBA": "UI/Menus/Widget/Yorozuya/Icon_MapTips03.prefab",
|
||||
"BECFHCOGPKG": "YorozuyaMapTipsUnLockChange_03"
|
||||
},
|
||||
{
|
||||
"ID": 100203,
|
||||
"FOPDNLNNHDJ": 1002,
|
||||
"DIIDBBGLDOL": "HollowGroupNameText_combat",
|
||||
"EFPBDDJIJBO": "",
|
||||
"OCBLGHECPLH": "Hollow_LockedHint_01",
|
||||
"BEIEFNLAJCH": "UI/Sprite/A1DynamicLoad/YorozuyaPage/UnPacker/Icon_Combat.png",
|
||||
"CCFBKFKFJGM": "UI/3D/Yorozuya/Yorozuya_Hollow_Sphere_S.prefab",
|
||||
"LDKNDDHOHND": "00A1FFFF",
|
||||
"EEBAIANJMEC": "00A1FFFF|00FFD300",
|
||||
"EKMLECIKMID": true,
|
||||
"FNIGJDFMHBA": "UI/Menus/Widget/Yorozuya/Icon_MapTips02.prefab",
|
||||
"BECFHCOGPKG": "YorozuyaMapTipsUnLockChange_02"
|
||||
},
|
||||
{
|
||||
"ID": 100301,
|
||||
"FOPDNLNNHDJ": 1003,
|
||||
"DIIDBBGLDOL": "HollowGroupNameText_Story",
|
||||
"EFPBDDJIJBO": "",
|
||||
"OCBLGHECPLH": "Hollow_LockedHint_01",
|
||||
"BEIEFNLAJCH": "UI/Sprite/A1DynamicLoad/YorozuyaPage/UnPacker/Icon_Story.png",
|
||||
"CCFBKFKFJGM": "UI/3D/Yorozuya/Yorozuya_Hollow_Sphere_M.prefab",
|
||||
"LDKNDDHOHND": "FF9500FF",
|
||||
"EEBAIANJMEC": "FF9500FF|FFDE0000",
|
||||
"EKMLECIKMID": true,
|
||||
"FNIGJDFMHBA": "UI/Menus/Widget/Yorozuya/Icon_MapTips.prefab",
|
||||
"BECFHCOGPKG": "YorozuyaMapTipsUnLockChange_01"
|
||||
},
|
||||
{
|
||||
"ID": 100302,
|
||||
"FOPDNLNNHDJ": 1003,
|
||||
"DIIDBBGLDOL": "HollowGroupNameText_exploration",
|
||||
"EFPBDDJIJBO": "",
|
||||
"OCBLGHECPLH": "Hollow_LockedHint_01",
|
||||
"BEIEFNLAJCH": "UI/Sprite/A1DynamicLoad/YorozuyaPage/UnPacker/Icon_Explore.png",
|
||||
"CCFBKFKFJGM": "UI/3D/Yorozuya/Yorozuya_Hollow_Sphere_M02.prefab",
|
||||
"LDKNDDHOHND": "00A1FFFF",
|
||||
"EEBAIANJMEC": "00A1FFFF|00FFD300",
|
||||
"EKMLECIKMID": true,
|
||||
"FNIGJDFMHBA": "UI/Menus/Widget/Yorozuya/Icon_MapTips03.prefab",
|
||||
"BECFHCOGPKG": "YorozuyaMapTipsUnLockChange_03"
|
||||
},
|
||||
{
|
||||
"ID": 100303,
|
||||
"FOPDNLNNHDJ": 1003,
|
||||
"DIIDBBGLDOL": "HollowGroupNameText_combat",
|
||||
"EFPBDDJIJBO": "",
|
||||
"OCBLGHECPLH": "Hollow_LockedHint_01",
|
||||
"BEIEFNLAJCH": "UI/Sprite/A1DynamicLoad/YorozuyaPage/UnPacker/Icon_Combat.png",
|
||||
"CCFBKFKFJGM": "UI/3D/Yorozuya/Yorozuya_Hollow_Sphere_S.prefab",
|
||||
"LDKNDDHOHND": "00A1FFFF",
|
||||
"EEBAIANJMEC": "00A1FFFF|00FFD300",
|
||||
"EKMLECIKMID": true,
|
||||
"FNIGJDFMHBA": "UI/Menus/Widget/Yorozuya/Icon_MapTips02.prefab",
|
||||
"BECFHCOGPKG": "YorozuyaMapTipsUnLockChange_02"
|
||||
},
|
||||
{
|
||||
"ID": 100401,
|
||||
"FOPDNLNNHDJ": 1004,
|
||||
"DIIDBBGLDOL": "HollowGroupNameText_BigWorld",
|
||||
"EFPBDDJIJBO": "1100140008",
|
||||
"OCBLGHECPLH": "Hollow_LockedHint_01",
|
||||
"BEIEFNLAJCH": "UI/Sprite/A1DynamicLoad/YorozuyaPage/UnPacker/Icon_HighRisk.png",
|
||||
"CCFBKFKFJGM": "UI/3D/Yorozuya/Yorozuya_Hollow_Sphere_L.prefab",
|
||||
"LDKNDDHOHND": "00A1FFFF",
|
||||
"EEBAIANJMEC": "00A1FFFF|00FFD300",
|
||||
"EKMLECIKMID": false,
|
||||
"FNIGJDFMHBA": "",
|
||||
"BECFHCOGPKG": ""
|
||||
},
|
||||
{
|
||||
"ID": 100501,
|
||||
"FOPDNLNNHDJ": 1005,
|
||||
"DIIDBBGLDOL": "HollowGroupNameText_Story",
|
||||
"EFPBDDJIJBO": "",
|
||||
"OCBLGHECPLH": "Hollow_LockedHint_01",
|
||||
"BEIEFNLAJCH": "UI/Sprite/A1DynamicLoad/YorozuyaPage/UnPacker/Icon_Story.png",
|
||||
"CCFBKFKFJGM": "UI/3D/Yorozuya/Yorozuya_Hollow_Sphere_M.prefab",
|
||||
"LDKNDDHOHND": "FF9500FF",
|
||||
"EEBAIANJMEC": "FF9500FF|FFDE0000",
|
||||
"EKMLECIKMID": true,
|
||||
"FNIGJDFMHBA": "UI/Menus/Widget/Yorozuya/Icon_MapTips.prefab",
|
||||
"BECFHCOGPKG": "YorozuyaMapTipsUnLockChange_01"
|
||||
},
|
||||
{
|
||||
"ID": 100502,
|
||||
"FOPDNLNNHDJ": 1005,
|
||||
"DIIDBBGLDOL": "HollowGroupNameText_exploration",
|
||||
"EFPBDDJIJBO": "",
|
||||
"OCBLGHECPLH": "Hollow_LockedHint_01",
|
||||
"BEIEFNLAJCH": "UI/Sprite/A1DynamicLoad/YorozuyaPage/UnPacker/Icon_Explore.png",
|
||||
"CCFBKFKFJGM": "UI/3D/Yorozuya/Yorozuya_Hollow_Sphere_M02.prefab",
|
||||
"LDKNDDHOHND": "00A1FFFF",
|
||||
"EEBAIANJMEC": "00A1FFFF|00FFD300",
|
||||
"EKMLECIKMID": true,
|
||||
"FNIGJDFMHBA": "UI/Menus/Widget/Yorozuya/Icon_MapTips03.prefab",
|
||||
"BECFHCOGPKG": "YorozuyaMapTipsUnLockChange_03"
|
||||
},
|
||||
{
|
||||
"ID": 100503,
|
||||
"FOPDNLNNHDJ": 1005,
|
||||
"DIIDBBGLDOL": "HollowGroupNameText_combat",
|
||||
"EFPBDDJIJBO": "",
|
||||
"OCBLGHECPLH": "Hollow_LockedHint_01",
|
||||
"BEIEFNLAJCH": "UI/Sprite/A1DynamicLoad/YorozuyaPage/UnPacker/Icon_Combat.png",
|
||||
"CCFBKFKFJGM": "UI/3D/Yorozuya/Yorozuya_Hollow_Sphere_S.prefab",
|
||||
"LDKNDDHOHND": "00A1FFFF",
|
||||
"EEBAIANJMEC": "00A1FFFF|00FFD300",
|
||||
"EKMLECIKMID": true,
|
||||
"FNIGJDFMHBA": "UI/Menus/Widget/Yorozuya/Icon_MapTips02.prefab",
|
||||
"BECFHCOGPKG": "YorozuyaMapTipsUnLockChange_02"
|
||||
},
|
||||
{
|
||||
"ID": 109901,
|
||||
"FOPDNLNNHDJ": 1099,
|
||||
"DIIDBBGLDOL": "HollowGroupNameText_Story",
|
||||
"EFPBDDJIJBO": "",
|
||||
"OCBLGHECPLH": "Hollow_LockedHint_01",
|
||||
"BEIEFNLAJCH": "UI/Sprite/A1DynamicLoad/YorozuyaPage/UnPacker/Icon_Story.png",
|
||||
"CCFBKFKFJGM": "UI/3D/Yorozuya/Yorozuya_Hollow_Sphere_M.prefab",
|
||||
"LDKNDDHOHND": "FF9500FF",
|
||||
"EEBAIANJMEC": "FF9500FF|FFDE0000",
|
||||
"EKMLECIKMID": false,
|
||||
"FNIGJDFMHBA": "UI/Menus/Widget/Yorozuya/Icon_MapTips.prefab",
|
||||
"BECFHCOGPKG": "YorozuyaMapTipsUnLockChange_01"
|
||||
}
|
||||
]
|
11622
assets/FileCfg/HollowQuestTemplateTb.json
Normal file
11622
assets/FileCfg/HollowQuestTemplateTb.json
Normal file
File diff suppressed because it is too large
Load diff
62086
assets/FileCfg/ItemTemplateTb.json
Normal file
62086
assets/FileCfg/ItemTemplateTb.json
Normal file
File diff suppressed because it is too large
Load diff
32
assets/FileCfg/MainCityBgmConfigTemplateTb.json
Normal file
32
assets/FileCfg/MainCityBgmConfigTemplateTb.json
Normal file
|
@ -0,0 +1,32 @@
|
|||
[
|
||||
{
|
||||
"ID": 0,
|
||||
"PlayEventName": "Play_BGM_Maincity",
|
||||
"StateName": "Normal"
|
||||
},
|
||||
{
|
||||
"ID": 1001,
|
||||
"PlayEventName": "Play_BGM_Maincity",
|
||||
"StateName": "Hack_Maincity"
|
||||
},
|
||||
{
|
||||
"ID": 1002,
|
||||
"PlayEventName": "Play_BGM_Maincity",
|
||||
"StateName": "WorkShop_OnMission"
|
||||
},
|
||||
{
|
||||
"ID": 1003,
|
||||
"PlayEventName": "Play_BGM_Maincity",
|
||||
"StateName": "SummerActivity_Ready"
|
||||
},
|
||||
{
|
||||
"ID": 1004,
|
||||
"PlayEventName": "Play_BGM_Maincity",
|
||||
"StateName": "SummerActivity_Start"
|
||||
},
|
||||
{
|
||||
"ID": 1005,
|
||||
"PlayEventName": "Play_BGM_Maincity",
|
||||
"StateName": "Mission_Accomplish"
|
||||
}
|
||||
]
|
800
assets/FileCfg/MainCityDefaultObjectTemplateTb.json
Normal file
800
assets/FileCfg/MainCityDefaultObjectTemplateTb.json
Normal file
|
@ -0,0 +1,800 @@
|
|||
[
|
||||
{
|
||||
"TagID": 1,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 2,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 3,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 4,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 5,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 6,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 7,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 8,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 9,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 10,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 1001,
|
||||
"MCHJEPCIEOC": "1040140086",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 1002,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 1003,
|
||||
"MCHJEPCIEOC": "1040140214",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 1004,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 1005,
|
||||
"MCHJEPCIEOC": "1040140077",
|
||||
"EFPBDDJIJBO": "1040140077",
|
||||
"InteractIDs": [10000014],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 1006,
|
||||
"MCHJEPCIEOC": "1040140073",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 1008,
|
||||
"MCHJEPCIEOC": "1040140070",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 1009,
|
||||
"MCHJEPCIEOC": "1040140126",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 1011,
|
||||
"MCHJEPCIEOC": "1040140091",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 1012,
|
||||
"MCHJEPCIEOC": "1040140071",
|
||||
"EFPBDDJIJBO": "1040140071",
|
||||
"InteractIDs": [10000029],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 1018,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 2016,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "1040140073",
|
||||
"InteractIDs": [10000015],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 2017,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 2018,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 2019,
|
||||
"MCHJEPCIEOC": "1040140082",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 2028,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "1040140117",
|
||||
"InteractIDs": [100700],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 2099,
|
||||
"MCHJEPCIEOC": "1040140115",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": "0:1|0:2|0:3"
|
||||
},
|
||||
{
|
||||
"TagID": 5004,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 5005,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 5007,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 5009,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 5010,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 5011,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 5012,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 5013,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 5014,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 5015,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 5016,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 5017,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 5018,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 5019,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 10022,
|
||||
"MCHJEPCIEOC": "1060140220",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 20281,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 100301,
|
||||
"MCHJEPCIEOC": "1040140072",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 100303,
|
||||
"MCHJEPCIEOC": "1040140072",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 100503,
|
||||
"MCHJEPCIEOC": "1040140126",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 100603,
|
||||
"MCHJEPCIEOC": "1040140070",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 100901,
|
||||
"MCHJEPCIEOC": "1040890044",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 100910,
|
||||
"MCHJEPCIEOC": "1040140263",
|
||||
"EFPBDDJIJBO": "1040140263",
|
||||
"InteractIDs": [15001404],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 100913,
|
||||
"MCHJEPCIEOC": "1040140264",
|
||||
"EFPBDDJIJBO": "1040140264",
|
||||
"InteractIDs": [15001405],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 100914,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 100915,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 100916,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 101016,
|
||||
"MCHJEPCIEOC": "1040140071",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 101017,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 101018,
|
||||
"MCHJEPCIEOC": "1040140071",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 101202,
|
||||
"MCHJEPCIEOC": "1040140115",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": "0:4"
|
||||
},
|
||||
{
|
||||
"TagID": 102101,
|
||||
"MCHJEPCIEOC": "1040140114",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 102102,
|
||||
"MCHJEPCIEOC": "1040140298",
|
||||
"EFPBDDJIJBO": "1040140298",
|
||||
"InteractIDs": [15001109],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 102201,
|
||||
"MCHJEPCIEOC": "1040140215",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 102202,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "1060140051",
|
||||
"InteractIDs": [15001104],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 102204,
|
||||
"MCHJEPCIEOC": "1040140298",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 102205,
|
||||
"MCHJEPCIEOC": "1040140193",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 102302,
|
||||
"MCHJEPCIEOC": "1040140193",
|
||||
"EFPBDDJIJBO": "1040140193",
|
||||
"InteractIDs": [15001108],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 102501,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 102502,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 102503,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 102504,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 102601,
|
||||
"MCHJEPCIEOC": "1060140044",
|
||||
"EFPBDDJIJBO": "1060140044",
|
||||
"InteractIDs": [15001107],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 102602,
|
||||
"MCHJEPCIEOC": "1060140044",
|
||||
"EFPBDDJIJBO": "1060140044",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 103101,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "1040140339",
|
||||
"InteractIDs": [15001201],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 103201,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 103202,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 103203,
|
||||
"MCHJEPCIEOC": "1040140339",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 103302,
|
||||
"MCHJEPCIEOC": "1040140260",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 104101,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 104102,
|
||||
"MCHJEPCIEOC": "1040140260",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 104108,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 104110,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 104111,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 104112,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 104113,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 104201,
|
||||
"MCHJEPCIEOC": "1040140302",
|
||||
"EFPBDDJIJBO": "1040140302",
|
||||
"InteractIDs": [15001801],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 104202,
|
||||
"MCHJEPCIEOC": "1030140001",
|
||||
"EFPBDDJIJBO": "1030140001",
|
||||
"InteractIDs": [15001802],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 104205,
|
||||
"MCHJEPCIEOC": "1030140002",
|
||||
"EFPBDDJIJBO": "1030140002",
|
||||
"InteractIDs": [15001803],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 104206,
|
||||
"MCHJEPCIEOC": "1030140003",
|
||||
"EFPBDDJIJBO": "1030140003",
|
||||
"InteractIDs": [15001804],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 202646,
|
||||
"MCHJEPCIEOC": "1040140279",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 500021,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": "0:4"
|
||||
},
|
||||
{
|
||||
"TagID": 500022,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": "0:3"
|
||||
},
|
||||
{
|
||||
"TagID": 500023,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": "0:2"
|
||||
},
|
||||
{
|
||||
"TagID": 500024,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": "0:1"
|
||||
},
|
||||
{
|
||||
"TagID": 500025,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": "0:2"
|
||||
},
|
||||
{
|
||||
"TagID": 500026,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": "0:1"
|
||||
},
|
||||
{
|
||||
"TagID": 504001,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 504002,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 504003,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 504004,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 504005,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 504006,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 504007,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 504008,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 504009,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 504010,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 520001,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 520002,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": "0:3"
|
||||
},
|
||||
{
|
||||
"TagID": 41120101,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 41120201,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 41120202,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 41120203,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 41120301,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 41120302,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 41120401,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": "0:1|0:2|0:3"
|
||||
},
|
||||
{
|
||||
"TagID": 41500001,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
},
|
||||
{
|
||||
"TagID": 241062001,
|
||||
"MCHJEPCIEOC": "",
|
||||
"EFPBDDJIJBO": "",
|
||||
"InteractIDs": [],
|
||||
"MOBKGMGMIDA": ""
|
||||
}
|
||||
]
|
236871
assets/FileCfg/MainCityObjectTemplateTb.json
Normal file
236871
assets/FileCfg/MainCityObjectTemplateTb.json
Normal file
File diff suppressed because it is too large
Load diff
84672
assets/FileCfg/OnceRewardTemplateTb.json
Normal file
84672
assets/FileCfg/OnceRewardTemplateTb.json
Normal file
File diff suppressed because it is too large
Load diff
29
assets/FileCfg/QuickAccessTemplateTb.json
Normal file
29
assets/FileCfg/QuickAccessTemplateTb.json
Normal file
|
@ -0,0 +1,29 @@
|
|||
[
|
||||
{
|
||||
"QuickAccessIndex": 1,
|
||||
"QuickFuncID": 1005,
|
||||
"RequiredUnlockIDs": [
|
||||
1005
|
||||
],
|
||||
"EFPBDDJIJBO": 1040140154,
|
||||
"BOKMLGNMJPB": null
|
||||
},
|
||||
{
|
||||
"QuickAccessIndex": 2,
|
||||
"QuickFuncID": 1022,
|
||||
"RequiredUnlockIDs": [
|
||||
1022
|
||||
],
|
||||
"EFPBDDJIJBO": 1040140049,
|
||||
"BOKMLGNMJPB": null
|
||||
},
|
||||
{
|
||||
"QuickAccessIndex": 3,
|
||||
"QuickFuncID": 1009,
|
||||
"RequiredUnlockIDs": [
|
||||
1009
|
||||
],
|
||||
"EFPBDDJIJBO": 1050060115,
|
||||
"BOKMLGNMJPB": null
|
||||
}
|
||||
]
|
112
assets/FileCfg/QuickFuncTemplateTb.json
Normal file
112
assets/FileCfg/QuickFuncTemplateTb.json
Normal file
|
@ -0,0 +1,112 @@
|
|||
[
|
||||
{
|
||||
"BtnID": 1001,
|
||||
"BOMNEKHOGIH": "",
|
||||
"PECPFBBOGKO": ""
|
||||
},
|
||||
{
|
||||
"BtnID": 1002,
|
||||
"BOMNEKHOGIH": "",
|
||||
"PECPFBBOGKO": ""
|
||||
},
|
||||
{
|
||||
"BtnID": 1003,
|
||||
"BOMNEKHOGIH": "",
|
||||
"PECPFBBOGKO": ""
|
||||
},
|
||||
{
|
||||
"BtnID": 1004,
|
||||
"BOMNEKHOGIH": "",
|
||||
"PECPFBBOGKO": ""
|
||||
},
|
||||
{
|
||||
"BtnID": 1005,
|
||||
"BOMNEKHOGIH": "UI/Sprite/A1DynamicLoad/MainCityMenus/Packer/BtnInterKnot.png",
|
||||
"PECPFBBOGKO": "UI/Sprite/A1DynamicLoad/MainCityMenus/Packer/BtnInterKnot.png"
|
||||
},
|
||||
{
|
||||
"BtnID": 1006,
|
||||
"BOMNEKHOGIH": "",
|
||||
"PECPFBBOGKO": ""
|
||||
},
|
||||
{
|
||||
"BtnID": 1007,
|
||||
"BOMNEKHOGIH": "",
|
||||
"PECPFBBOGKO": ""
|
||||
},
|
||||
{
|
||||
"BtnID": 1008,
|
||||
"BOMNEKHOGIH": "",
|
||||
"PECPFBBOGKO": ""
|
||||
},
|
||||
{
|
||||
"BtnID": 1009,
|
||||
"BOMNEKHOGIH": "UI/Sprite/A1DynamicLoad/MainCityMenus/Packer/BtnGuide.png",
|
||||
"PECPFBBOGKO": "UI/Sprite/A1DynamicLoad/MainCityMenus/Packer/BtnGuide.png"
|
||||
},
|
||||
{
|
||||
"BtnID": 1010,
|
||||
"BOMNEKHOGIH": "",
|
||||
"PECPFBBOGKO": ""
|
||||
},
|
||||
{
|
||||
"BtnID": 1011,
|
||||
"BOMNEKHOGIH": "",
|
||||
"PECPFBBOGKO": ""
|
||||
},
|
||||
{
|
||||
"BtnID": 1013,
|
||||
"BOMNEKHOGIH": "",
|
||||
"PECPFBBOGKO": ""
|
||||
},
|
||||
{
|
||||
"BtnID": 1014,
|
||||
"BOMNEKHOGIH": "",
|
||||
"PECPFBBOGKO": ""
|
||||
},
|
||||
{
|
||||
"BtnID": 1015,
|
||||
"BOMNEKHOGIH": "",
|
||||
"PECPFBBOGKO": ""
|
||||
},
|
||||
{
|
||||
"BtnID": 1016,
|
||||
"BOMNEKHOGIH": "",
|
||||
"PECPFBBOGKO": ""
|
||||
},
|
||||
{
|
||||
"BtnID": 1017,
|
||||
"BOMNEKHOGIH": "",
|
||||
"PECPFBBOGKO": ""
|
||||
},
|
||||
{
|
||||
"BtnID": 1018,
|
||||
"BOMNEKHOGIH": "",
|
||||
"PECPFBBOGKO": ""
|
||||
},
|
||||
{
|
||||
"BtnID": 1019,
|
||||
"BOMNEKHOGIH": "",
|
||||
"PECPFBBOGKO": ""
|
||||
},
|
||||
{
|
||||
"BtnID": 1020,
|
||||
"BOMNEKHOGIH": "",
|
||||
"PECPFBBOGKO": ""
|
||||
},
|
||||
{
|
||||
"BtnID": 1021,
|
||||
"BOMNEKHOGIH": "UI/Sprite/A1DynamicLoad/MainCityMenus/Packer/BtnCamera.png",
|
||||
"PECPFBBOGKO": "UI/Sprite/A1DynamicLoad/MainCityMenus/Packer/BtnCamera.png"
|
||||
},
|
||||
{
|
||||
"BtnID": 1022,
|
||||
"BOMNEKHOGIH": "UI/Sprite/A1DynamicLoad/MainCityMenus/Packer/BtnMessage.png",
|
||||
"PECPFBBOGKO": "UI/Sprite/A1DynamicLoad/MainCityMenus/Packer/BtnMessage.png"
|
||||
},
|
||||
{
|
||||
"BtnID": 1023,
|
||||
"BOMNEKHOGIH": "",
|
||||
"PECPFBBOGKO": ""
|
||||
}
|
||||
]
|
519
assets/FileCfg/RobotBuddyConfigTemplateTb.json
Normal file
519
assets/FileCfg/RobotBuddyConfigTemplateTb.json
Normal file
|
@ -0,0 +1,519 @@
|
|||
[
|
||||
{
|
||||
"RobotBuddyID": 19053001,
|
||||
"BuddyID": 53001,
|
||||
"CharLevel": 20,
|
||||
"CharUpgradeLevel": 2,
|
||||
"CharStar": 1,
|
||||
"GHGKBFEKDND": 0,
|
||||
"ACGEEJMKBBO": 1053001,
|
||||
"INPPGCADDPO": 0,
|
||||
"FMPOMKKHELJ": 0
|
||||
},
|
||||
{
|
||||
"RobotBuddyID": 19053002,
|
||||
"BuddyID": 53002,
|
||||
"CharLevel": 20,
|
||||
"CharUpgradeLevel": 2,
|
||||
"CharStar": 1,
|
||||
"GHGKBFEKDND": 0,
|
||||
"ACGEEJMKBBO": 1053002,
|
||||
"INPPGCADDPO": 0,
|
||||
"FMPOMKKHELJ": 0
|
||||
},
|
||||
{
|
||||
"RobotBuddyID": 19053003,
|
||||
"BuddyID": 53003,
|
||||
"CharLevel": 20,
|
||||
"CharUpgradeLevel": 2,
|
||||
"CharStar": 1,
|
||||
"GHGKBFEKDND": 0,
|
||||
"ACGEEJMKBBO": 1053003,
|
||||
"INPPGCADDPO": 0,
|
||||
"FMPOMKKHELJ": 0
|
||||
},
|
||||
{
|
||||
"RobotBuddyID": 19053004,
|
||||
"BuddyID": 53004,
|
||||
"CharLevel": 20,
|
||||
"CharUpgradeLevel": 2,
|
||||
"CharStar": 1,
|
||||
"GHGKBFEKDND": 0,
|
||||
"ACGEEJMKBBO": 1053004,
|
||||
"INPPGCADDPO": 0,
|
||||
"FMPOMKKHELJ": 0
|
||||
},
|
||||
{
|
||||
"RobotBuddyID": 19053005,
|
||||
"BuddyID": 53005,
|
||||
"CharLevel": 20,
|
||||
"CharUpgradeLevel": 2,
|
||||
"CharStar": 1,
|
||||
"GHGKBFEKDND": 0,
|
||||
"ACGEEJMKBBO": 1053005,
|
||||
"INPPGCADDPO": 0,
|
||||
"FMPOMKKHELJ": 0
|
||||
},
|
||||
{
|
||||
"RobotBuddyID": 19053006,
|
||||
"BuddyID": 53006,
|
||||
"CharLevel": 20,
|
||||
"CharUpgradeLevel": 2,
|
||||
"CharStar": 1,
|
||||
"GHGKBFEKDND": 0,
|
||||
"ACGEEJMKBBO": 1053006,
|
||||
"INPPGCADDPO": 0,
|
||||
"FMPOMKKHELJ": 0
|
||||
},
|
||||
{
|
||||
"RobotBuddyID": 19053007,
|
||||
"BuddyID": 53007,
|
||||
"CharLevel": 20,
|
||||
"CharUpgradeLevel": 2,
|
||||
"CharStar": 1,
|
||||
"GHGKBFEKDND": 0,
|
||||
"ACGEEJMKBBO": 1053007,
|
||||
"INPPGCADDPO": 0,
|
||||
"FMPOMKKHELJ": 0
|
||||
},
|
||||
{
|
||||
"RobotBuddyID": 19053008,
|
||||
"BuddyID": 53008,
|
||||
"CharLevel": 20,
|
||||
"CharUpgradeLevel": 2,
|
||||
"CharStar": 1,
|
||||
"GHGKBFEKDND": 0,
|
||||
"ACGEEJMKBBO": 1053008,
|
||||
"INPPGCADDPO": 0,
|
||||
"FMPOMKKHELJ": 0
|
||||
},
|
||||
{
|
||||
"RobotBuddyID": 19053009,
|
||||
"BuddyID": 53009,
|
||||
"CharLevel": 20,
|
||||
"CharUpgradeLevel": 2,
|
||||
"CharStar": 1,
|
||||
"GHGKBFEKDND": 0,
|
||||
"ACGEEJMKBBO": 1053009,
|
||||
"INPPGCADDPO": 0,
|
||||
"FMPOMKKHELJ": 0
|
||||
},
|
||||
{
|
||||
"RobotBuddyID": 19053010,
|
||||
"BuddyID": 53010,
|
||||
"CharLevel": 20,
|
||||
"CharUpgradeLevel": 2,
|
||||
"CharStar": 1,
|
||||
"GHGKBFEKDND": 0,
|
||||
"ACGEEJMKBBO": 1053010,
|
||||
"INPPGCADDPO": 0,
|
||||
"FMPOMKKHELJ": 0
|
||||
},
|
||||
{
|
||||
"RobotBuddyID": 19053011,
|
||||
"BuddyID": 53011,
|
||||
"CharLevel": 20,
|
||||
"CharUpgradeLevel": 2,
|
||||
"CharStar": 1,
|
||||
"GHGKBFEKDND": 0,
|
||||
"ACGEEJMKBBO": 1053011,
|
||||
"INPPGCADDPO": 0,
|
||||
"FMPOMKKHELJ": 0
|
||||
},
|
||||
{
|
||||
"RobotBuddyID": 19053012,
|
||||
"BuddyID": 53012,
|
||||
"CharLevel": 20,
|
||||
"CharUpgradeLevel": 2,
|
||||
"CharStar": 1,
|
||||
"GHGKBFEKDND": 0,
|
||||
"ACGEEJMKBBO": 1053012,
|
||||
"INPPGCADDPO": 0,
|
||||
"FMPOMKKHELJ": 0
|
||||
},
|
||||
{
|
||||
"RobotBuddyID": 19054001,
|
||||
"BuddyID": 54001,
|
||||
"CharLevel": 20,
|
||||
"CharUpgradeLevel": 2,
|
||||
"CharStar": 1,
|
||||
"GHGKBFEKDND": 0,
|
||||
"ACGEEJMKBBO": 1054001,
|
||||
"INPPGCADDPO": 0,
|
||||
"FMPOMKKHELJ": 0
|
||||
},
|
||||
{
|
||||
"RobotBuddyID": 19054002,
|
||||
"BuddyID": 54002,
|
||||
"CharLevel": 20,
|
||||
"CharUpgradeLevel": 2,
|
||||
"CharStar": 1,
|
||||
"GHGKBFEKDND": 0,
|
||||
"ACGEEJMKBBO": 1054002,
|
||||
"INPPGCADDPO": 0,
|
||||
"FMPOMKKHELJ": 0
|
||||
},
|
||||
{
|
||||
"RobotBuddyID": 19054003,
|
||||
"BuddyID": 54003,
|
||||
"CharLevel": 20,
|
||||
"CharUpgradeLevel": 2,
|
||||
"CharStar": 1,
|
||||
"GHGKBFEKDND": 0,
|
||||
"ACGEEJMKBBO": 1054003,
|
||||
"INPPGCADDPO": 0,
|
||||
"FMPOMKKHELJ": 0
|
||||
},
|
||||
{
|
||||
"RobotBuddyID": 19054004,
|
||||
"BuddyID": 54004,
|
||||
"CharLevel": 20,
|
||||
"CharUpgradeLevel": 2,
|
||||
"CharStar": 1,
|
||||
"GHGKBFEKDND": 0,
|
||||
"ACGEEJMKBBO": 1054004,
|
||||
"INPPGCADDPO": 0,
|
||||
"FMPOMKKHELJ": 0
|
||||
},
|
||||
{
|
||||
"RobotBuddyID": 19054005,
|
||||
"BuddyID": 54005,
|
||||
"CharLevel": 20,
|
||||
"CharUpgradeLevel": 2,
|
||||
"CharStar": 1,
|
||||
"GHGKBFEKDND": 0,
|
||||
"ACGEEJMKBBO": 1054005,
|
||||
"INPPGCADDPO": 0,
|
||||
"FMPOMKKHELJ": 0
|
||||
},
|
||||
{
|
||||
"RobotBuddyID": 19054006,
|
||||
"BuddyID": 54006,
|
||||
"CharLevel": 20,
|
||||
"CharUpgradeLevel": 2,
|
||||
"CharStar": 1,
|
||||
"GHGKBFEKDND": 0,
|
||||
"ACGEEJMKBBO": 1054006,
|
||||
"INPPGCADDPO": 0,
|
||||
"FMPOMKKHELJ": 0
|
||||
},
|
||||
{
|
||||
"RobotBuddyID": 19054008,
|
||||
"BuddyID": 54008,
|
||||
"CharLevel": 20,
|
||||
"CharUpgradeLevel": 2,
|
||||
"CharStar": 1,
|
||||
"GHGKBFEKDND": 0,
|
||||
"ACGEEJMKBBO": 1054008,
|
||||
"INPPGCADDPO": 0,
|
||||
"FMPOMKKHELJ": 0
|
||||
},
|
||||
{
|
||||
"RobotBuddyID": 19054009,
|
||||
"BuddyID": 54009,
|
||||
"CharLevel": 20,
|
||||
"CharUpgradeLevel": 2,
|
||||
"CharStar": 1,
|
||||
"GHGKBFEKDND": 0,
|
||||
"ACGEEJMKBBO": 1054009,
|
||||
"INPPGCADDPO": 0,
|
||||
"FMPOMKKHELJ": 0
|
||||
},
|
||||
{
|
||||
"RobotBuddyID": 19054013,
|
||||
"BuddyID": 54013,
|
||||
"CharLevel": 20,
|
||||
"CharUpgradeLevel": 2,
|
||||
"CharStar": 1,
|
||||
"GHGKBFEKDND": 0,
|
||||
"ACGEEJMKBBO": 1054013,
|
||||
"INPPGCADDPO": 0,
|
||||
"FMPOMKKHELJ": 0
|
||||
},
|
||||
{
|
||||
"RobotBuddyID": 101000404,
|
||||
"BuddyID": 53006,
|
||||
"CharLevel": 1,
|
||||
"CharUpgradeLevel": 1,
|
||||
"CharStar": 1,
|
||||
"GHGKBFEKDND": 53006,
|
||||
"ACGEEJMKBBO": 0,
|
||||
"INPPGCADDPO": 0,
|
||||
"FMPOMKKHELJ": 0
|
||||
},
|
||||
{
|
||||
"RobotBuddyID": 101000504,
|
||||
"BuddyID": 54005,
|
||||
"CharLevel": 6,
|
||||
"CharUpgradeLevel": 1,
|
||||
"CharStar": 1,
|
||||
"GHGKBFEKDND": 0,
|
||||
"ACGEEJMKBBO": 0,
|
||||
"INPPGCADDPO": 0,
|
||||
"FMPOMKKHELJ": 0
|
||||
},
|
||||
{
|
||||
"RobotBuddyID": 1000010104,
|
||||
"BuddyID": 54005,
|
||||
"CharLevel": 9,
|
||||
"CharUpgradeLevel": 1,
|
||||
"CharStar": 1,
|
||||
"GHGKBFEKDND": 0,
|
||||
"ACGEEJMKBBO": 0,
|
||||
"INPPGCADDPO": 0,
|
||||
"FMPOMKKHELJ": 0
|
||||
},
|
||||
{
|
||||
"RobotBuddyID": 1000010204,
|
||||
"BuddyID": 54005,
|
||||
"CharLevel": 9,
|
||||
"CharUpgradeLevel": 1,
|
||||
"CharStar": 1,
|
||||
"GHGKBFEKDND": 0,
|
||||
"ACGEEJMKBBO": 0,
|
||||
"INPPGCADDPO": 0,
|
||||
"FMPOMKKHELJ": 0
|
||||
},
|
||||
{
|
||||
"RobotBuddyID": 1000010304,
|
||||
"BuddyID": 54005,
|
||||
"CharLevel": 9,
|
||||
"CharUpgradeLevel": 1,
|
||||
"CharStar": 1,
|
||||
"GHGKBFEKDND": 0,
|
||||
"ACGEEJMKBBO": 0,
|
||||
"INPPGCADDPO": 0,
|
||||
"FMPOMKKHELJ": 0
|
||||
},
|
||||
{
|
||||
"RobotBuddyID": 1000010604,
|
||||
"BuddyID": 54005,
|
||||
"CharLevel": 11,
|
||||
"CharUpgradeLevel": 2,
|
||||
"CharStar": 1,
|
||||
"GHGKBFEKDND": 0,
|
||||
"ACGEEJMKBBO": 0,
|
||||
"INPPGCADDPO": 0,
|
||||
"FMPOMKKHELJ": 0
|
||||
},
|
||||
{
|
||||
"RobotBuddyID": 1000010704,
|
||||
"BuddyID": 54005,
|
||||
"CharLevel": 12,
|
||||
"CharUpgradeLevel": 2,
|
||||
"CharStar": 1,
|
||||
"GHGKBFEKDND": 0,
|
||||
"ACGEEJMKBBO": 0,
|
||||
"INPPGCADDPO": 0,
|
||||
"FMPOMKKHELJ": 0
|
||||
},
|
||||
{
|
||||
"RobotBuddyID": 1000010804,
|
||||
"BuddyID": 54005,
|
||||
"CharLevel": 13,
|
||||
"CharUpgradeLevel": 2,
|
||||
"CharStar": 1,
|
||||
"GHGKBFEKDND": 0,
|
||||
"ACGEEJMKBBO": 0,
|
||||
"INPPGCADDPO": 0,
|
||||
"FMPOMKKHELJ": 0
|
||||
},
|
||||
{
|
||||
"RobotBuddyID": 1001000404,
|
||||
"BuddyID": 54005,
|
||||
"CharLevel": 8,
|
||||
"CharUpgradeLevel": 1,
|
||||
"CharStar": 1,
|
||||
"GHGKBFEKDND": 0,
|
||||
"ACGEEJMKBBO": 0,
|
||||
"INPPGCADDPO": 0,
|
||||
"FMPOMKKHELJ": 0
|
||||
},
|
||||
{
|
||||
"RobotBuddyID": 1001010104,
|
||||
"BuddyID": 54005,
|
||||
"CharLevel": 10,
|
||||
"CharUpgradeLevel": 2,
|
||||
"CharStar": 1,
|
||||
"GHGKBFEKDND": 0,
|
||||
"ACGEEJMKBBO": 0,
|
||||
"INPPGCADDPO": 0,
|
||||
"FMPOMKKHELJ": 0
|
||||
},
|
||||
{
|
||||
"RobotBuddyID": 1001010204,
|
||||
"BuddyID": 54005,
|
||||
"CharLevel": 15,
|
||||
"CharUpgradeLevel": 2,
|
||||
"CharStar": 1,
|
||||
"GHGKBFEKDND": 0,
|
||||
"ACGEEJMKBBO": 0,
|
||||
"INPPGCADDPO": 0,
|
||||
"FMPOMKKHELJ": 0
|
||||
},
|
||||
{
|
||||
"RobotBuddyID": 1001020204,
|
||||
"BuddyID": 54002,
|
||||
"CharLevel": 24,
|
||||
"CharUpgradeLevel": 3,
|
||||
"CharStar": 1,
|
||||
"GHGKBFEKDND": 0,
|
||||
"ACGEEJMKBBO": 0,
|
||||
"INPPGCADDPO": 0,
|
||||
"FMPOMKKHELJ": 0
|
||||
},
|
||||
{
|
||||
"RobotBuddyID": 1001020304,
|
||||
"BuddyID": 54002,
|
||||
"CharLevel": 24,
|
||||
"CharUpgradeLevel": 3,
|
||||
"CharStar": 1,
|
||||
"GHGKBFEKDND": 0,
|
||||
"ACGEEJMKBBO": 0,
|
||||
"INPPGCADDPO": 0,
|
||||
"FMPOMKKHELJ": 0
|
||||
},
|
||||
{
|
||||
"RobotBuddyID": 1001020404,
|
||||
"BuddyID": 54002,
|
||||
"CharLevel": 26,
|
||||
"CharUpgradeLevel": 3,
|
||||
"CharStar": 1,
|
||||
"GHGKBFEKDND": 0,
|
||||
"ACGEEJMKBBO": 0,
|
||||
"INPPGCADDPO": 0,
|
||||
"FMPOMKKHELJ": 0
|
||||
},
|
||||
{
|
||||
"RobotBuddyID": 1001020904,
|
||||
"BuddyID": 54002,
|
||||
"CharLevel": 28,
|
||||
"CharUpgradeLevel": 3,
|
||||
"CharStar": 1,
|
||||
"GHGKBFEKDND": 0,
|
||||
"ACGEEJMKBBO": 0,
|
||||
"INPPGCADDPO": 0,
|
||||
"FMPOMKKHELJ": 0
|
||||
},
|
||||
{
|
||||
"RobotBuddyID": 1001021104,
|
||||
"BuddyID": 54009,
|
||||
"CharLevel": 32,
|
||||
"CharUpgradeLevel": 4,
|
||||
"CharStar": 1,
|
||||
"GHGKBFEKDND": 0,
|
||||
"ACGEEJMKBBO": 0,
|
||||
"INPPGCADDPO": 0,
|
||||
"FMPOMKKHELJ": 0
|
||||
},
|
||||
{
|
||||
"RobotBuddyID": 1001021204,
|
||||
"BuddyID": 54009,
|
||||
"CharLevel": 33,
|
||||
"CharUpgradeLevel": 4,
|
||||
"CharStar": 1,
|
||||
"GHGKBFEKDND": 0,
|
||||
"ACGEEJMKBBO": 0,
|
||||
"INPPGCADDPO": 0,
|
||||
"FMPOMKKHELJ": 0
|
||||
},
|
||||
{
|
||||
"RobotBuddyID": 1001030204,
|
||||
"BuddyID": 54005,
|
||||
"CharLevel": 34,
|
||||
"CharUpgradeLevel": 4,
|
||||
"CharStar": 1,
|
||||
"GHGKBFEKDND": 0,
|
||||
"ACGEEJMKBBO": 0,
|
||||
"INPPGCADDPO": 0,
|
||||
"FMPOMKKHELJ": 0
|
||||
},
|
||||
{
|
||||
"RobotBuddyID": 1001030304,
|
||||
"BuddyID": 54004,
|
||||
"CharLevel": 35,
|
||||
"CharUpgradeLevel": 4,
|
||||
"CharStar": 1,
|
||||
"GHGKBFEKDND": 0,
|
||||
"ACGEEJMKBBO": 0,
|
||||
"INPPGCADDPO": 0,
|
||||
"FMPOMKKHELJ": 0
|
||||
},
|
||||
{
|
||||
"RobotBuddyID": 1001030404,
|
||||
"BuddyID": 54004,
|
||||
"CharLevel": 36,
|
||||
"CharUpgradeLevel": 4,
|
||||
"CharStar": 1,
|
||||
"GHGKBFEKDND": 0,
|
||||
"ACGEEJMKBBO": 0,
|
||||
"INPPGCADDPO": 0,
|
||||
"FMPOMKKHELJ": 0
|
||||
},
|
||||
{
|
||||
"RobotBuddyID": 1001030504,
|
||||
"BuddyID": 54004,
|
||||
"CharLevel": 38,
|
||||
"CharUpgradeLevel": 4,
|
||||
"CharStar": 1,
|
||||
"GHGKBFEKDND": 0,
|
||||
"ACGEEJMKBBO": 0,
|
||||
"INPPGCADDPO": 0,
|
||||
"FMPOMKKHELJ": 0
|
||||
},
|
||||
{
|
||||
"RobotBuddyID": 1009010104,
|
||||
"BuddyID": 53006,
|
||||
"CharLevel": 25,
|
||||
"CharUpgradeLevel": 3,
|
||||
"CharStar": 1,
|
||||
"GHGKBFEKDND": 0,
|
||||
"ACGEEJMKBBO": 0,
|
||||
"INPPGCADDPO": 0,
|
||||
"FMPOMKKHELJ": 0
|
||||
},
|
||||
{
|
||||
"RobotBuddyID": 1009010204,
|
||||
"BuddyID": 53006,
|
||||
"CharLevel": 35,
|
||||
"CharUpgradeLevel": 4,
|
||||
"CharStar": 1,
|
||||
"GHGKBFEKDND": 0,
|
||||
"ACGEEJMKBBO": 0,
|
||||
"INPPGCADDPO": 0,
|
||||
"FMPOMKKHELJ": 0
|
||||
},
|
||||
{
|
||||
"RobotBuddyID": 1009010304,
|
||||
"BuddyID": 53006,
|
||||
"CharLevel": 45,
|
||||
"CharUpgradeLevel": 5,
|
||||
"CharStar": 1,
|
||||
"GHGKBFEKDND": 0,
|
||||
"ACGEEJMKBBO": 0,
|
||||
"INPPGCADDPO": 0,
|
||||
"FMPOMKKHELJ": 0
|
||||
},
|
||||
{
|
||||
"RobotBuddyID": 1009010404,
|
||||
"BuddyID": 53006,
|
||||
"CharLevel": 55,
|
||||
"CharUpgradeLevel": 6,
|
||||
"CharStar": 1,
|
||||
"GHGKBFEKDND": 0,
|
||||
"ACGEEJMKBBO": 0,
|
||||
"INPPGCADDPO": 0,
|
||||
"FMPOMKKHELJ": 0
|
||||
},
|
||||
{
|
||||
"RobotBuddyID": 1009010504,
|
||||
"BuddyID": 53006,
|
||||
"CharLevel": 60,
|
||||
"CharUpgradeLevel": 6,
|
||||
"CharStar": 1,
|
||||
"GHGKBFEKDND": 0,
|
||||
"ACGEEJMKBBO": 0,
|
||||
"INPPGCADDPO": 0,
|
||||
"FMPOMKKHELJ": 0
|
||||
}
|
||||
]
|
10072
assets/FileCfg/RobotConfigTemplateTb.json
Normal file
10072
assets/FileCfg/RobotConfigTemplateTb.json
Normal file
File diff suppressed because it is too large
Load diff
882
assets/FileCfg/SubAreaDataTemplateTb.json
Normal file
882
assets/FileCfg/SubAreaDataTemplateTb.json
Normal file
|
@ -0,0 +1,882 @@
|
|||
[
|
||||
{
|
||||
"AreaID": 500000101,
|
||||
"BattleEventID": 5000001,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5000001_1.asset",
|
||||
"MDMOGIDKCLG": "metro4_2",
|
||||
"LLPNKBBJHKL": "PlayerPos_E2",
|
||||
"TimePeriod": "Morning",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 500000102,
|
||||
"BattleEventID": 5000001,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5000001_2.asset",
|
||||
"MDMOGIDKCLG": "metro4_2",
|
||||
"LLPNKBBJHKL": "PlayerPos_E1",
|
||||
"TimePeriod": "Morning",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 500000103,
|
||||
"BattleEventID": 5000001,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5000001_3.asset",
|
||||
"MDMOGIDKCLG": "metro4_2",
|
||||
"LLPNKBBJHKL": "PlayerPos_E1",
|
||||
"TimePeriod": "Morning",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 500000201,
|
||||
"BattleEventID": 5000002,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5000002_1.asset",
|
||||
"MDMOGIDKCLG": "Construction2_3_Boss",
|
||||
"LLPNKBBJHKL": "PlayerPos_B5",
|
||||
"TimePeriod": "Night",
|
||||
"Weather": "Thunder",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 500000202,
|
||||
"BattleEventID": 5000002,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5000002_2.asset",
|
||||
"MDMOGIDKCLG": "Construction2_3_Boss",
|
||||
"LLPNKBBJHKL": "PlayerPos_A1",
|
||||
"TimePeriod": "Night",
|
||||
"Weather": "Thunder",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 500000203,
|
||||
"BattleEventID": 5000002,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5000002_3.asset",
|
||||
"MDMOGIDKCLG": "Construction2_3_Boss",
|
||||
"LLPNKBBJHKL": "PlayerPos_A1",
|
||||
"TimePeriod": "Night",
|
||||
"Weather": "Thunder",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 500000301,
|
||||
"BattleEventID": 5000003,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5000003_1.asset",
|
||||
"MDMOGIDKCLG": "Stage_SkyScraper_H_3_1",
|
||||
"LLPNKBBJHKL": "PlayerPos_A1",
|
||||
"TimePeriod": "Morning",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 500000302,
|
||||
"BattleEventID": 5000003,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5000003_2.asset",
|
||||
"MDMOGIDKCLG": "Stage_SkyScraper_H_3_1",
|
||||
"LLPNKBBJHKL": "PlayerPos_A1",
|
||||
"TimePeriod": "Morning",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 500000303,
|
||||
"BattleEventID": 5000003,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5000003_3.asset",
|
||||
"MDMOGIDKCLG": "Stage_SkyScraper_H_3_1",
|
||||
"LLPNKBBJHKL": "PlayerPos_A1",
|
||||
"TimePeriod": "Morning",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 500000401,
|
||||
"BattleEventID": 5000004,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5000004_1.asset",
|
||||
"MDMOGIDKCLG": "Stage_Zero_SpecialRoom_5",
|
||||
"LLPNKBBJHKL": "PlayerPos_E1",
|
||||
"TimePeriod": "Morning",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 500000402,
|
||||
"BattleEventID": 5000004,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5000004_2.asset",
|
||||
"MDMOGIDKCLG": "Stage_Zero_SpecialRoom_5",
|
||||
"LLPNKBBJHKL": "PlayerPos_SP",
|
||||
"TimePeriod": "Morning",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 500000403,
|
||||
"BattleEventID": 5000004,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5000004_3.asset",
|
||||
"MDMOGIDKCLG": "Stage_Zero_SpecialRoom_5",
|
||||
"LLPNKBBJHKL": "PlayerPos_SP",
|
||||
"TimePeriod": "Morning",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501010101,
|
||||
"BattleEventID": 5010101,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010101_1.asset",
|
||||
"MDMOGIDKCLG": "metro4_1_Rally",
|
||||
"LLPNKBBJHKL": "PlayerPos_CheckPoint1",
|
||||
"TimePeriod": "Night",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": true,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501010102,
|
||||
"BattleEventID": 5010101,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010101_2.asset",
|
||||
"MDMOGIDKCLG": "metro4_1_Rally",
|
||||
"LLPNKBBJHKL": "PlayerPos_CheckPoint2",
|
||||
"TimePeriod": "Night",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501010103,
|
||||
"BattleEventID": 5010101,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010101_3.asset",
|
||||
"MDMOGIDKCLG": "metro4_1_Rally",
|
||||
"LLPNKBBJHKL": "PlayerPos_CheckPoint3",
|
||||
"TimePeriod": "Night",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501010104,
|
||||
"BattleEventID": 5010101,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010101_4.asset",
|
||||
"MDMOGIDKCLG": "Stage_Zero_ComplexRoom_22",
|
||||
"LLPNKBBJHKL": "SpecialPlayerPos_1",
|
||||
"TimePeriod": "Morning",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": true,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501010105,
|
||||
"BattleEventID": 5010101,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010101_5.asset",
|
||||
"MDMOGIDKCLG": "metro4_1_Rally",
|
||||
"LLPNKBBJHKL": "PlayerPos_CheckPoint5",
|
||||
"TimePeriod": "Night",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": true,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501011101,
|
||||
"BattleEventID": 5010111,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010111_1.asset",
|
||||
"MDMOGIDKCLG": "metro4_2_Rally",
|
||||
"LLPNKBBJHKL": "PlayerPos_A1",
|
||||
"TimePeriod": "Night",
|
||||
"Weather": "Rain",
|
||||
"HAIGBCBDJPL": true,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501011102,
|
||||
"BattleEventID": 5010111,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010111_2.asset",
|
||||
"MDMOGIDKCLG": "metro4_2_Rally",
|
||||
"LLPNKBBJHKL": "RallyPlayerPos_C1",
|
||||
"TimePeriod": "Night",
|
||||
"Weather": "Rain",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501011103,
|
||||
"BattleEventID": 5010111,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010111_3.asset",
|
||||
"MDMOGIDKCLG": "metro4_2_Rally",
|
||||
"LLPNKBBJHKL": "RallyPlayerPos_A1",
|
||||
"TimePeriod": "Night",
|
||||
"Weather": "Rain",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501011104,
|
||||
"BattleEventID": 5010111,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010111_4.asset",
|
||||
"MDMOGIDKCLG": "Stage_Zero_ComplexRoom_22",
|
||||
"LLPNKBBJHKL": "SpecialPlayerPos_1",
|
||||
"TimePeriod": "Morning",
|
||||
"Weather": "Rain",
|
||||
"HAIGBCBDJPL": true,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501011105,
|
||||
"BattleEventID": 5010111,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010111_5.asset",
|
||||
"MDMOGIDKCLG": "metro4_2_Rally",
|
||||
"LLPNKBBJHKL": "PlayerPos_F2",
|
||||
"TimePeriod": "Night",
|
||||
"Weather": "Rain",
|
||||
"HAIGBCBDJPL": true,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501012101,
|
||||
"BattleEventID": 5010121,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010121_1.asset",
|
||||
"MDMOGIDKCLG": "metro4_1_Rally",
|
||||
"LLPNKBBJHKL": "PlayerPos_CheckPoint6",
|
||||
"TimePeriod": "Night",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": true,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501012102,
|
||||
"BattleEventID": 5010121,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010121_2.asset",
|
||||
"MDMOGIDKCLG": "metro4_1_Rally",
|
||||
"LLPNKBBJHKL": "PlayerPos_CheckPoint7",
|
||||
"TimePeriod": "Night",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501012103,
|
||||
"BattleEventID": 5010121,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010121_3.asset",
|
||||
"MDMOGIDKCLG": "metro4_2_Rally",
|
||||
"LLPNKBBJHKL": "PlayerPos_A1",
|
||||
"TimePeriod": "Night",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": true,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501012104,
|
||||
"BattleEventID": 5010121,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010121_4.asset",
|
||||
"MDMOGIDKCLG": "metro4_2_Rally",
|
||||
"LLPNKBBJHKL": "PlayerPos_E2",
|
||||
"TimePeriod": "Night",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501020200,
|
||||
"BattleEventID": 5010201,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010201_0.asset",
|
||||
"MDMOGIDKCLG": "Stage_VR_TrainingRoom_30R",
|
||||
"LLPNKBBJHKL": "PlayerPos_A1",
|
||||
"TimePeriod": "Evening",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501020201,
|
||||
"BattleEventID": 5010201,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010201_1.asset",
|
||||
"MDMOGIDKCLG": "Construction3_4_SuccessiveLevel",
|
||||
"LLPNKBBJHKL": "PlayerPos_CheckPoint1",
|
||||
"TimePeriod": "Evening",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501020202,
|
||||
"BattleEventID": 5010201,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010201_2.asset",
|
||||
"MDMOGIDKCLG": "Construction3_4_SuccessiveLevel",
|
||||
"LLPNKBBJHKL": "PlayerPos_CheckPoint2",
|
||||
"TimePeriod": "Evening",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501020203,
|
||||
"BattleEventID": 5010201,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010201_3.asset",
|
||||
"MDMOGIDKCLG": "Construction3_4_SuccessiveLevel",
|
||||
"LLPNKBBJHKL": "PlayerPos_CheckPoint3",
|
||||
"TimePeriod": "Evening",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501020204,
|
||||
"BattleEventID": 5010201,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010201_4.asset",
|
||||
"MDMOGIDKCLG": "Construction3_4_SuccessiveLevel",
|
||||
"LLPNKBBJHKL": "PlayerPos_CheckPoint4",
|
||||
"TimePeriod": "Evening",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501020205,
|
||||
"BattleEventID": 5010201,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010201_5.asset",
|
||||
"MDMOGIDKCLG": "Construction3_4_SuccessiveLevel",
|
||||
"LLPNKBBJHKL": "PlayerPos_CheckPoint5",
|
||||
"TimePeriod": "Evening",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501020206,
|
||||
"BattleEventID": 5010201,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010201_6.asset",
|
||||
"MDMOGIDKCLG": "Stage_Zero_ComplexRoom_25_SuccessiveLevel",
|
||||
"LLPNKBBJHKL": "PlayerPos_CheckPoint6",
|
||||
"TimePeriod": "Morning",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": true,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501020207,
|
||||
"BattleEventID": 5010201,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010201_7.asset",
|
||||
"MDMOGIDKCLG": "Construction3_4_SuccessiveLevel",
|
||||
"LLPNKBBJHKL": "PlayerPos_CheckPoint7",
|
||||
"TimePeriod": "Evening",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": true,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501020208,
|
||||
"BattleEventID": 5010201,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010201_6.asset",
|
||||
"MDMOGIDKCLG": "Stage_Zero_ComplexRoom_25_SuccessiveLevel",
|
||||
"LLPNKBBJHKL": "PlayerPos_CheckPoint6",
|
||||
"TimePeriod": "Morning",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501020209,
|
||||
"BattleEventID": 5010201,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010201_9.asset",
|
||||
"MDMOGIDKCLG": "Construction2_3_Boss",
|
||||
"LLPNKBBJHKL": "PlayerPos_A1",
|
||||
"TimePeriod": "Night",
|
||||
"Weather": "Thunder",
|
||||
"HAIGBCBDJPL": true,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501021101,
|
||||
"BattleEventID": 5010211,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010211_1.asset",
|
||||
"MDMOGIDKCLG": "Construction2_5_Rally",
|
||||
"LLPNKBBJHKL": "PlayerPos_CheckPoint1",
|
||||
"TimePeriod": "Evening",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501021102,
|
||||
"BattleEventID": 5010211,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010211_2.asset",
|
||||
"MDMOGIDKCLG": "Construction2_5_Rally",
|
||||
"LLPNKBBJHKL": "PlayerPos_CheckPoint2",
|
||||
"TimePeriod": "Evening",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501021103,
|
||||
"BattleEventID": 5010211,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010211_3.asset",
|
||||
"MDMOGIDKCLG": "Construction2_5_Rally",
|
||||
"LLPNKBBJHKL": "PlayerPos_CheckPoint3",
|
||||
"TimePeriod": "Evening",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501021104,
|
||||
"BattleEventID": 5010211,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010211_4.asset",
|
||||
"MDMOGIDKCLG": "Stage_Zero_ComplexRoom_12_Rally",
|
||||
"LLPNKBBJHKL": "PlayerPos_CheckPoint4",
|
||||
"TimePeriod": "Morning",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": true,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501021105,
|
||||
"BattleEventID": 5010211,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010211_5.asset",
|
||||
"MDMOGIDKCLG": "Construction2_5_Rally",
|
||||
"LLPNKBBJHKL": "PlayerPos_CheckPoint5",
|
||||
"TimePeriod": "Evening",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501021106,
|
||||
"BattleEventID": 5010211,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010211_6.asset",
|
||||
"MDMOGIDKCLG": "Construction2_5_Rally",
|
||||
"LLPNKBBJHKL": "PlayerPos_CheckPoint6",
|
||||
"TimePeriod": "Evening",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": true,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501021107,
|
||||
"BattleEventID": 5010211,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010211_7.asset",
|
||||
"MDMOGIDKCLG": "Construction2_5_Rally",
|
||||
"LLPNKBBJHKL": "PlayerPos_CheckPoint3",
|
||||
"TimePeriod": "Evening",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501021301,
|
||||
"BattleEventID": 5010213,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010213_1.asset",
|
||||
"MDMOGIDKCLG": "Construction2_3_Boss",
|
||||
"LLPNKBBJHKL": "PlayerPos_B5",
|
||||
"TimePeriod": "Night",
|
||||
"Weather": "Thunder",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501021302,
|
||||
"BattleEventID": 5010213,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010213_2.asset",
|
||||
"MDMOGIDKCLG": "Construction2_3_Boss",
|
||||
"LLPNKBBJHKL": "PlayerPos_A1",
|
||||
"TimePeriod": "Night",
|
||||
"Weather": "Thunder",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501021303,
|
||||
"BattleEventID": 5010213,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010213_3.asset",
|
||||
"MDMOGIDKCLG": "Construction2_3_Boss",
|
||||
"LLPNKBBJHKL": "PlayerPos_A1",
|
||||
"TimePeriod": "Night",
|
||||
"Weather": "Thunder",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501021304,
|
||||
"BattleEventID": 5010213,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010213_4.asset",
|
||||
"MDMOGIDKCLG": "Construction2_3_Boss",
|
||||
"LLPNKBBJHKL": "PlayerPos_A1",
|
||||
"TimePeriod": "Night",
|
||||
"Weather": "Thunder",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501022101,
|
||||
"BattleEventID": 5010221,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010221_1.asset",
|
||||
"MDMOGIDKCLG": "Construction3_4_SuccessiveLevel",
|
||||
"LLPNKBBJHKL": "PlayerPos_CheckPoint9",
|
||||
"TimePeriod": "Evening",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501022102,
|
||||
"BattleEventID": 5010221,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010221_2.asset",
|
||||
"MDMOGIDKCLG": "Construction3_4_SuccessiveLevel",
|
||||
"LLPNKBBJHKL": "PlayerPos_C2",
|
||||
"TimePeriod": "Evening",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501022103,
|
||||
"BattleEventID": 5010221,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010221_3.asset",
|
||||
"MDMOGIDKCLG": "Construction2_3_Zero",
|
||||
"LLPNKBBJHKL": "PlayerPos_E4_Rally",
|
||||
"TimePeriod": "Evening",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": true,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501022104,
|
||||
"BattleEventID": 5010221,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010221_4.asset",
|
||||
"MDMOGIDKCLG": "Construction2_3_Zero",
|
||||
"LLPNKBBJHKL": "PlayerPos_D4_Rally",
|
||||
"TimePeriod": "Evening",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501030101,
|
||||
"BattleEventID": 5010301,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010301_1.asset",
|
||||
"MDMOGIDKCLG": "Stage_SkyScraper_H_2_3_Successive",
|
||||
"LLPNKBBJHKL": "SpecialPlayerPos_B1",
|
||||
"TimePeriod": "Night",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501030102,
|
||||
"BattleEventID": 5010301,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010301_2.asset",
|
||||
"MDMOGIDKCLG": "Stage_SkyScraper_L_2_1_Successive",
|
||||
"LLPNKBBJHKL": "PlayerPos_CheckPoint1",
|
||||
"TimePeriod": "Night",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": true,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501030103,
|
||||
"BattleEventID": 5010301,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010301_3.asset",
|
||||
"MDMOGIDKCLG": "Stage_SkyScraper_L_2_1_Successive",
|
||||
"LLPNKBBJHKL": "PlayerPos_CheckPoint2",
|
||||
"TimePeriod": "Night",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501030104,
|
||||
"BattleEventID": 5010301,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010301_4.asset",
|
||||
"MDMOGIDKCLG": "Stage_SkyScraper_L_2_1_Successive",
|
||||
"LLPNKBBJHKL": "PlayerPos_CheckPoint3",
|
||||
"TimePeriod": "Night",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501030105,
|
||||
"BattleEventID": 5010301,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010301_5.asset",
|
||||
"MDMOGIDKCLG": "Stage_SkyScraper_L_2_1_Successive",
|
||||
"LLPNKBBJHKL": "PlayerPos_CheckPoint4",
|
||||
"TimePeriod": "Night",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": true,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501030106,
|
||||
"BattleEventID": 5010301,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010301_6.asset",
|
||||
"MDMOGIDKCLG": "Stage_Zero_ComplexRoom_15_Rally",
|
||||
"LLPNKBBJHKL": "PlayerPos_CheckPointSideQuest1",
|
||||
"TimePeriod": "Morning",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": true,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501030107,
|
||||
"BattleEventID": 5010301,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010301_7.asset",
|
||||
"MDMOGIDKCLG": "Stage_SkyScraper_L_2_1_Successive",
|
||||
"LLPNKBBJHKL": "SpecialRallyPos_7",
|
||||
"TimePeriod": "Night",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501031101,
|
||||
"BattleEventID": 5010311,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010311_1.asset",
|
||||
"MDMOGIDKCLG": "Stage_SkyScraper_H_2_1_Rally",
|
||||
"LLPNKBBJHKL": "PlayerPos_CheckPoint1",
|
||||
"TimePeriod": "Night",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501031102,
|
||||
"BattleEventID": 5010311,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010311_2.asset",
|
||||
"MDMOGIDKCLG": "Stage_SkyScraper_H_2_1_Rally",
|
||||
"LLPNKBBJHKL": "PlayerPos_CheckPoint2",
|
||||
"TimePeriod": "Night",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501031103,
|
||||
"BattleEventID": 5010311,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010311_3.asset",
|
||||
"MDMOGIDKCLG": "Stage_SkyScraper_H_2_1_Rally",
|
||||
"LLPNKBBJHKL": "PlayerPos_CheckPoint3",
|
||||
"TimePeriod": "Night",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501031104,
|
||||
"BattleEventID": 5010311,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010311_4.asset",
|
||||
"MDMOGIDKCLG": "Stage_SkyScraper_H_2_1_Rally",
|
||||
"LLPNKBBJHKL": "PlayerPos_CheckPoint4",
|
||||
"TimePeriod": "Night",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501031105,
|
||||
"BattleEventID": 5010311,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010311_5.asset",
|
||||
"MDMOGIDKCLG": "Stage_SkyScraper_H_2_1_Rally",
|
||||
"LLPNKBBJHKL": "PlayerPos_CheckPoint5",
|
||||
"TimePeriod": "Night",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501031106,
|
||||
"BattleEventID": 5010311,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010311_6.asset",
|
||||
"MDMOGIDKCLG": "Stage_SkyScraper_H_2_1_Rally",
|
||||
"LLPNKBBJHKL": "PlayerPos_CheckPoint6",
|
||||
"TimePeriod": "Night",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501031107,
|
||||
"BattleEventID": 5010311,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010311_7.asset",
|
||||
"MDMOGIDKCLG": "Stage_SkyScraper_L_1_1_Rally",
|
||||
"LLPNKBBJHKL": "PlayerPos_CheckPoint7",
|
||||
"TimePeriod": "Night",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": true,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501031108,
|
||||
"BattleEventID": 5010311,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010311_8.asset",
|
||||
"MDMOGIDKCLG": "Stage_Zero_ComplexRoom_15_Rally",
|
||||
"LLPNKBBJHKL": "PlayerPos_CheckPoint8",
|
||||
"TimePeriod": "Morning",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": true,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501031109,
|
||||
"BattleEventID": 5010311,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010311_9.asset",
|
||||
"MDMOGIDKCLG": "Stage_SkyScraper_H_2_1_Rally",
|
||||
"LLPNKBBJHKL": "PlayerPos_CheckPoint9",
|
||||
"TimePeriod": "Night",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501031110,
|
||||
"BattleEventID": 5010311,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010311_10.asset",
|
||||
"MDMOGIDKCLG": "Stage_SkyScraper_H_1_1_Rally",
|
||||
"LLPNKBBJHKL": "PlayerPos_CheckPoint10",
|
||||
"TimePeriod": "Night",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": true,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501031111,
|
||||
"BattleEventID": 5010311,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010311_11.asset",
|
||||
"MDMOGIDKCLG": "Stage_SkyScraper_H_2_1_Rally",
|
||||
"LLPNKBBJHKL": "PlayerPos_CheckPoint11",
|
||||
"TimePeriod": "Night",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": true,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501031112,
|
||||
"BattleEventID": 5010311,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010311_12.asset",
|
||||
"MDMOGIDKCLG": "Stage_SkyScraper_L_1_1_Rally",
|
||||
"LLPNKBBJHKL": "PlayerPos_CheckPoint12",
|
||||
"TimePeriod": "Night",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": true,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501032101,
|
||||
"BattleEventID": 5010321,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010321_1.asset",
|
||||
"MDMOGIDKCLG": "Stage_SkyScraper_L_1_2_Zero",
|
||||
"LLPNKBBJHKL": "PlayerPos_A5_Rally",
|
||||
"TimePeriod": "Night",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501032102,
|
||||
"BattleEventID": 5010321,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010321_2.asset",
|
||||
"MDMOGIDKCLG": "Stage_SkyScraper_L_1_2_Zero",
|
||||
"LLPNKBBJHKL": "PlayerPos_A6_Rally",
|
||||
"TimePeriod": "Night",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501032103,
|
||||
"BattleEventID": 5010321,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010321_3.asset",
|
||||
"MDMOGIDKCLG": "Stage_SkyScraper_L_1_2_Zero",
|
||||
"LLPNKBBJHKL": "PlayerPos_C5_Rally",
|
||||
"TimePeriod": "Night",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 501032104,
|
||||
"BattleEventID": 5010321,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5010321_4.asset",
|
||||
"MDMOGIDKCLG": "Stage_SkyScraper_H_1_1_Rally",
|
||||
"LLPNKBBJHKL": "PlayerPos_A1",
|
||||
"TimePeriod": "Night",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": true,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 503020101,
|
||||
"BattleEventID": 5030201,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5030201_1.asset",
|
||||
"MDMOGIDKCLG": "Stage_MetroArea_4_1_Lycaon",
|
||||
"LLPNKBBJHKL": "PlayerPos_Ly1",
|
||||
"TimePeriod": "Night",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 503020102,
|
||||
"BattleEventID": 5030201,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5030201_2.asset",
|
||||
"MDMOGIDKCLG": "Stage_MetroArea_4_1_Lycaon",
|
||||
"LLPNKBBJHKL": "PlayerPos_Ly2",
|
||||
"TimePeriod": "Night",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 503020103,
|
||||
"BattleEventID": 5030201,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5030201_3.asset",
|
||||
"MDMOGIDKCLG": "Stage_MetroArea_4_1_Lycaon",
|
||||
"LLPNKBBJHKL": "PlayerPos_Ly3",
|
||||
"TimePeriod": "Night",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 503021101,
|
||||
"BattleEventID": 5030211,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5030211_1.asset",
|
||||
"MDMOGIDKCLG": "Stage_SkyScraper_L_1_2_Lycaon",
|
||||
"LLPNKBBJHKL": "PlayerPos_Ly1",
|
||||
"TimePeriod": "Night",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 503021102,
|
||||
"BattleEventID": 5030211,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5030211_2.asset",
|
||||
"MDMOGIDKCLG": "Stage_SkyScraper_L_1_2_Lycaon",
|
||||
"LLPNKBBJHKL": "PlayerPos_Ly2",
|
||||
"TimePeriod": "Night",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
},
|
||||
{
|
||||
"AreaID": 503021103,
|
||||
"BattleEventID": 5030211,
|
||||
"NELIKCGAKEJ": "Level/FC_Main/FC_Successive/FC_5030211_3.asset",
|
||||
"MDMOGIDKCLG": "Stage_SkyScraper_L_1_2_Lycaon",
|
||||
"LLPNKBBJHKL": "PlayerPos_Ly3",
|
||||
"TimePeriod": "Night",
|
||||
"Weather": "SunShine",
|
||||
"HAIGBCBDJPL": false,
|
||||
"MBIMPLIHABC": ""
|
||||
}
|
||||
]
|
2008
assets/FileCfg/TeleportConfigTemplateTb.json
Normal file
2008
assets/FileCfg/TeleportConfigTemplateTb.json
Normal file
File diff suppressed because it is too large
Load diff
604
assets/FileCfg/VariableDataTemplateTb.json
Normal file
604
assets/FileCfg/VariableDataTemplateTb.json
Normal file
|
@ -0,0 +1,604 @@
|
|||
[
|
||||
{
|
||||
"ID": 500000101,
|
||||
"BattleEventID": 5000001,
|
||||
"VariableName": "IsArea1Finish",
|
||||
"ValueType": "bool",
|
||||
"InitialValue": "false"
|
||||
},
|
||||
{
|
||||
"ID": 500000102,
|
||||
"BattleEventID": 5000001,
|
||||
"VariableName": "IsArea2Finish",
|
||||
"ValueType": "bool",
|
||||
"InitialValue": "false"
|
||||
},
|
||||
{
|
||||
"ID": 500000103,
|
||||
"BattleEventID": 5000001,
|
||||
"VariableName": "IsArea3Finish",
|
||||
"ValueType": "bool",
|
||||
"InitialValue": "false"
|
||||
},
|
||||
{
|
||||
"ID": 500000104,
|
||||
"BattleEventID": 5000001,
|
||||
"VariableName": "IsArea4Finish",
|
||||
"ValueType": "bool",
|
||||
"InitialValue": "false"
|
||||
},
|
||||
{
|
||||
"ID": 500000105,
|
||||
"BattleEventID": 5000001,
|
||||
"VariableName": "IsArea5Finish",
|
||||
"ValueType": "bool",
|
||||
"InitialValue": "false"
|
||||
},
|
||||
{
|
||||
"ID": 500000106,
|
||||
"BattleEventID": 5000001,
|
||||
"VariableName": "IsArea6Finish",
|
||||
"ValueType": "bool",
|
||||
"InitialValue": "false"
|
||||
},
|
||||
{
|
||||
"ID": 500000107,
|
||||
"BattleEventID": 5000001,
|
||||
"VariableName": "SideQuest",
|
||||
"ValueType": "bool",
|
||||
"InitialValue": "false"
|
||||
},
|
||||
{
|
||||
"ID": 500000108,
|
||||
"BattleEventID": 5000001,
|
||||
"VariableName": "SecondSideQuest",
|
||||
"ValueType": "bool",
|
||||
"InitialValue": "false"
|
||||
},
|
||||
{
|
||||
"ID": 500000109,
|
||||
"BattleEventID": 5000001,
|
||||
"VariableName": "AreaSelect",
|
||||
"ValueType": "int",
|
||||
"InitialValue": "1"
|
||||
},
|
||||
{
|
||||
"ID": 500000201,
|
||||
"BattleEventID": 5000002,
|
||||
"VariableName": "whichAreaIn",
|
||||
"ValueType": "int",
|
||||
"InitialValue": "1"
|
||||
},
|
||||
{
|
||||
"ID": 500000202,
|
||||
"BattleEventID": 5000002,
|
||||
"VariableName": "IsArea2Finish",
|
||||
"ValueType": "bool",
|
||||
"InitialValue": "false"
|
||||
},
|
||||
{
|
||||
"ID": 500000203,
|
||||
"BattleEventID": 5000002,
|
||||
"VariableName": "IsArea3Finish",
|
||||
"ValueType": "bool",
|
||||
"InitialValue": "false"
|
||||
},
|
||||
{
|
||||
"ID": 500000204,
|
||||
"BattleEventID": 5000002,
|
||||
"VariableName": "IsArea4Finish",
|
||||
"ValueType": "bool",
|
||||
"InitialValue": "false"
|
||||
},
|
||||
{
|
||||
"ID": 500000205,
|
||||
"BattleEventID": 5000002,
|
||||
"VariableName": "IsArea5Finish",
|
||||
"ValueType": "bool",
|
||||
"InitialValue": "false"
|
||||
},
|
||||
{
|
||||
"ID": 500000206,
|
||||
"BattleEventID": 5000002,
|
||||
"VariableName": "SecretMission",
|
||||
"ValueType": "int",
|
||||
"InitialValue": "0"
|
||||
},
|
||||
{
|
||||
"ID": 500000207,
|
||||
"BattleEventID": 5000002,
|
||||
"VariableName": "AreaSelect",
|
||||
"ValueType": "int",
|
||||
"InitialValue": "1"
|
||||
},
|
||||
{
|
||||
"ID": 500000301,
|
||||
"BattleEventID": 5000003,
|
||||
"VariableName": "AreaSelect",
|
||||
"ValueType": "int",
|
||||
"InitialValue": "1"
|
||||
},
|
||||
{
|
||||
"ID": 500000401,
|
||||
"BattleEventID": 5000004,
|
||||
"VariableName": "AreaSelect",
|
||||
"ValueType": "int",
|
||||
"InitialValue": "1"
|
||||
},
|
||||
{
|
||||
"ID": 501010100,
|
||||
"BattleEventID": 5010101,
|
||||
"VariableName": "AreaSelect",
|
||||
"ValueType": "int",
|
||||
"InitialValue": "1"
|
||||
},
|
||||
{
|
||||
"ID": 501010101,
|
||||
"BattleEventID": 5010101,
|
||||
"VariableName": "SideQuest",
|
||||
"ValueType": "bool",
|
||||
"InitialValue": "false"
|
||||
},
|
||||
{
|
||||
"ID": 501010102,
|
||||
"BattleEventID": 5010101,
|
||||
"VariableName": "IsSideQuestFinsih",
|
||||
"ValueType": "bool",
|
||||
"InitialValue": "false"
|
||||
},
|
||||
{
|
||||
"ID": 501010103,
|
||||
"BattleEventID": 5010101,
|
||||
"VariableName": "RevivedTime",
|
||||
"ValueType": "int",
|
||||
"InitialValue": "0"
|
||||
},
|
||||
{
|
||||
"ID": 501010104,
|
||||
"BattleEventID": 5010101,
|
||||
"VariableName": "IsSideQuestRestart",
|
||||
"ValueType": "bool",
|
||||
"InitialValue": "false"
|
||||
},
|
||||
{
|
||||
"ID": 501011101,
|
||||
"BattleEventID": 5010111,
|
||||
"VariableName": "AreaSelect",
|
||||
"ValueType": "int",
|
||||
"InitialValue": "1"
|
||||
},
|
||||
{
|
||||
"ID": 501011102,
|
||||
"BattleEventID": 5010111,
|
||||
"VariableName": "SideQuest",
|
||||
"ValueType": "bool",
|
||||
"InitialValue": "false"
|
||||
},
|
||||
{
|
||||
"ID": 501011103,
|
||||
"BattleEventID": 5010111,
|
||||
"VariableName": "IsSideQuestFinsih",
|
||||
"ValueType": "bool",
|
||||
"InitialValue": "false"
|
||||
},
|
||||
{
|
||||
"ID": 501011104,
|
||||
"BattleEventID": 5010111,
|
||||
"VariableName": "RevivedTime",
|
||||
"ValueType": "int",
|
||||
"InitialValue": "0"
|
||||
},
|
||||
{
|
||||
"ID": 501011105,
|
||||
"BattleEventID": 5010111,
|
||||
"VariableName": "GroundSideQuest",
|
||||
"ValueType": "bool",
|
||||
"InitialValue": "false"
|
||||
},
|
||||
{
|
||||
"ID": 501011106,
|
||||
"BattleEventID": 5010111,
|
||||
"VariableName": "IsSideQuestRestart",
|
||||
"ValueType": "bool",
|
||||
"InitialValue": "FALSE"
|
||||
},
|
||||
{
|
||||
"ID": 501012101,
|
||||
"BattleEventID": 5010121,
|
||||
"VariableName": "AreaSelect",
|
||||
"ValueType": "int",
|
||||
"InitialValue": "4"
|
||||
},
|
||||
{
|
||||
"ID": 501012102,
|
||||
"BattleEventID": 5010121,
|
||||
"VariableName": "RevivedTime",
|
||||
"ValueType": "int",
|
||||
"InitialValue": "0"
|
||||
},
|
||||
{
|
||||
"ID": 501020200,
|
||||
"BattleEventID": 5010201,
|
||||
"VariableName": "IsEnterTeachLevel",
|
||||
"ValueType": "bool",
|
||||
"InitialValue": "false"
|
||||
},
|
||||
{
|
||||
"ID": 501020201,
|
||||
"BattleEventID": 5010201,
|
||||
"VariableName": "IsArea1Finish",
|
||||
"ValueType": "bool",
|
||||
"InitialValue": "false"
|
||||
},
|
||||
{
|
||||
"ID": 501020202,
|
||||
"BattleEventID": 5010201,
|
||||
"VariableName": "IsArea2Finish",
|
||||
"ValueType": "bool",
|
||||
"InitialValue": "false"
|
||||
},
|
||||
{
|
||||
"ID": 501020203,
|
||||
"BattleEventID": 5010201,
|
||||
"VariableName": "IsArea3Finish",
|
||||
"ValueType": "bool",
|
||||
"InitialValue": "false"
|
||||
},
|
||||
{
|
||||
"ID": 501020204,
|
||||
"BattleEventID": 5010201,
|
||||
"VariableName": "IsArea4Finish",
|
||||
"ValueType": "bool",
|
||||
"InitialValue": "false"
|
||||
},
|
||||
{
|
||||
"ID": 501020205,
|
||||
"BattleEventID": 5010201,
|
||||
"VariableName": "IsArea5Finish",
|
||||
"ValueType": "bool",
|
||||
"InitialValue": "false"
|
||||
},
|
||||
{
|
||||
"ID": 501020206,
|
||||
"BattleEventID": 5010201,
|
||||
"VariableName": "IsArea6Finish",
|
||||
"ValueType": "bool",
|
||||
"InitialValue": "false"
|
||||
},
|
||||
{
|
||||
"ID": 501020207,
|
||||
"BattleEventID": 5010201,
|
||||
"VariableName": "IsArea7Finish",
|
||||
"ValueType": "bool",
|
||||
"InitialValue": "false"
|
||||
},
|
||||
{
|
||||
"ID": 501020208,
|
||||
"BattleEventID": 5010201,
|
||||
"VariableName": "SideQuest",
|
||||
"ValueType": "bool",
|
||||
"InitialValue": "false"
|
||||
},
|
||||
{
|
||||
"ID": 501020209,
|
||||
"BattleEventID": 5010201,
|
||||
"VariableName": "IsArea8Finish",
|
||||
"ValueType": "bool",
|
||||
"InitialValue": "false"
|
||||
},
|
||||
{
|
||||
"ID": 501020210,
|
||||
"BattleEventID": 5010201,
|
||||
"VariableName": "SecondSideQuest",
|
||||
"ValueType": "bool",
|
||||
"InitialValue": "false"
|
||||
},
|
||||
{
|
||||
"ID": 501020211,
|
||||
"BattleEventID": 5010201,
|
||||
"VariableName": "StartSecondPhase",
|
||||
"ValueType": "bool",
|
||||
"InitialValue": "false"
|
||||
},
|
||||
{
|
||||
"ID": 501020212,
|
||||
"BattleEventID": 5010201,
|
||||
"VariableName": "AreaSelect",
|
||||
"ValueType": "int",
|
||||
"InitialValue": "1"
|
||||
},
|
||||
{
|
||||
"ID": 501020213,
|
||||
"BattleEventID": 5010201,
|
||||
"VariableName": "IsSideQuestRestart",
|
||||
"ValueType": "bool",
|
||||
"InitialValue": "false"
|
||||
},
|
||||
{
|
||||
"ID": 501020214,
|
||||
"BattleEventID": 5010201,
|
||||
"VariableName": "IsSideQuestFinsih",
|
||||
"ValueType": "bool",
|
||||
"InitialValue": "false"
|
||||
},
|
||||
{
|
||||
"ID": 501020215,
|
||||
"BattleEventID": 5010201,
|
||||
"VariableName": "RevivedTime",
|
||||
"ValueType": "int",
|
||||
"InitialValue": "0"
|
||||
},
|
||||
{
|
||||
"ID": 501020216,
|
||||
"BattleEventID": 5010201,
|
||||
"VariableName": "LifeCoinGet",
|
||||
"ValueType": "bool",
|
||||
"InitialValue": "FALSE"
|
||||
},
|
||||
{
|
||||
"ID": 501021101,
|
||||
"BattleEventID": 5010211,
|
||||
"VariableName": "AreaSelect",
|
||||
"ValueType": "int",
|
||||
"InitialValue": "1"
|
||||
},
|
||||
{
|
||||
"ID": 501021102,
|
||||
"BattleEventID": 5010211,
|
||||
"VariableName": "IsSideQuestRestart",
|
||||
"ValueType": "bool",
|
||||
"InitialValue": "false"
|
||||
},
|
||||
{
|
||||
"ID": 501021103,
|
||||
"BattleEventID": 5010211,
|
||||
"VariableName": "IsSideQuestFinsih",
|
||||
"ValueType": "bool",
|
||||
"InitialValue": "false"
|
||||
},
|
||||
{
|
||||
"ID": 501021104,
|
||||
"BattleEventID": 5010211,
|
||||
"VariableName": "RevivedTime",
|
||||
"ValueType": "int",
|
||||
"InitialValue": "0"
|
||||
},
|
||||
{
|
||||
"ID": 501021105,
|
||||
"BattleEventID": 5010211,
|
||||
"VariableName": "BossHealth",
|
||||
"ValueType": "float",
|
||||
"InitialValue": "1"
|
||||
},
|
||||
{
|
||||
"ID": 501021106,
|
||||
"BattleEventID": 5010211,
|
||||
"VariableName": "CargoCartStopped",
|
||||
"ValueType": "bool",
|
||||
"InitialValue": "FALSE"
|
||||
},
|
||||
{
|
||||
"ID": 501021107,
|
||||
"BattleEventID": 5010211,
|
||||
"VariableName": "IsLastAreaFinish",
|
||||
"ValueType": "bool",
|
||||
"InitialValue": "false"
|
||||
},
|
||||
{
|
||||
"ID": 501021301,
|
||||
"BattleEventID": 5010213,
|
||||
"VariableName": "whichAreaIn",
|
||||
"ValueType": "int",
|
||||
"InitialValue": "1"
|
||||
},
|
||||
{
|
||||
"ID": 501022101,
|
||||
"BattleEventID": 5010221,
|
||||
"VariableName": "AreaSelect",
|
||||
"ValueType": "int",
|
||||
"InitialValue": "4"
|
||||
},
|
||||
{
|
||||
"ID": 501022102,
|
||||
"BattleEventID": 5010221,
|
||||
"VariableName": "RevivedTime",
|
||||
"ValueType": "int",
|
||||
"InitialValue": "0"
|
||||
},
|
||||
{
|
||||
"ID": 501030101,
|
||||
"BattleEventID": 5010301,
|
||||
"VariableName": "AreaSelect",
|
||||
"ValueType": "int",
|
||||
"InitialValue": "1"
|
||||
},
|
||||
{
|
||||
"ID": 501030102,
|
||||
"BattleEventID": 5010301,
|
||||
"VariableName": "IsSideQuestFinsih",
|
||||
"ValueType": "bool",
|
||||
"InitialValue": "false"
|
||||
},
|
||||
{
|
||||
"ID": 501030103,
|
||||
"BattleEventID": 5010301,
|
||||
"VariableName": "RevivedTime",
|
||||
"ValueType": "int",
|
||||
"InitialValue": "0"
|
||||
},
|
||||
{
|
||||
"ID": 501030104,
|
||||
"BattleEventID": 5010301,
|
||||
"VariableName": "DoorStatus1",
|
||||
"ValueType": "int",
|
||||
"InitialValue": "0"
|
||||
},
|
||||
{
|
||||
"ID": 501030105,
|
||||
"BattleEventID": 5010301,
|
||||
"VariableName": "DoorStatus2",
|
||||
"ValueType": "int",
|
||||
"InitialValue": "0"
|
||||
},
|
||||
{
|
||||
"ID": 501030106,
|
||||
"BattleEventID": 5010301,
|
||||
"VariableName": "DoorStatus3",
|
||||
"ValueType": "int",
|
||||
"InitialValue": "0"
|
||||
},
|
||||
{
|
||||
"ID": 501030107,
|
||||
"BattleEventID": 5010301,
|
||||
"VariableName": "DoorStatus4",
|
||||
"ValueType": "int",
|
||||
"InitialValue": "0"
|
||||
},
|
||||
{
|
||||
"ID": 501030108,
|
||||
"BattleEventID": 5010301,
|
||||
"VariableName": "DoorStatus5",
|
||||
"ValueType": "int",
|
||||
"InitialValue": "0"
|
||||
},
|
||||
{
|
||||
"ID": 501030109,
|
||||
"BattleEventID": 5010301,
|
||||
"VariableName": "IsSideQuestRestart",
|
||||
"ValueType": "bool",
|
||||
"InitialValue": "FALSE"
|
||||
},
|
||||
{
|
||||
"ID": 501030110,
|
||||
"BattleEventID": 5010301,
|
||||
"VariableName": "IsTrickFinish",
|
||||
"ValueType": "int",
|
||||
"InitialValue": "0"
|
||||
},
|
||||
{
|
||||
"ID": 501031101,
|
||||
"BattleEventID": 5010311,
|
||||
"VariableName": "AreaSelect",
|
||||
"ValueType": "int",
|
||||
"InitialValue": "1"
|
||||
},
|
||||
{
|
||||
"ID": 501031102,
|
||||
"BattleEventID": 5010311,
|
||||
"VariableName": "IsSideQuestFinsih",
|
||||
"ValueType": "bool",
|
||||
"InitialValue": "false"
|
||||
},
|
||||
{
|
||||
"ID": 501031103,
|
||||
"BattleEventID": 5010311,
|
||||
"VariableName": "RevivedTime",
|
||||
"ValueType": "int",
|
||||
"InitialValue": "0"
|
||||
},
|
||||
{
|
||||
"ID": 501031104,
|
||||
"BattleEventID": 5010311,
|
||||
"VariableName": "IsAllyRescued",
|
||||
"ValueType": "bool",
|
||||
"InitialValue": "FALSE"
|
||||
},
|
||||
{
|
||||
"ID": 501031105,
|
||||
"BattleEventID": 5010311,
|
||||
"VariableName": "IsShortcutOpened",
|
||||
"ValueType": "bool",
|
||||
"InitialValue": "FALSE"
|
||||
},
|
||||
{
|
||||
"ID": 501031106,
|
||||
"BattleEventID": 5010311,
|
||||
"VariableName": "IsGuardDefeated",
|
||||
"ValueType": "bool",
|
||||
"InitialValue": "FALSE"
|
||||
},
|
||||
{
|
||||
"ID": 501031107,
|
||||
"BattleEventID": 5010311,
|
||||
"VariableName": "DoorStatus1",
|
||||
"ValueType": "int",
|
||||
"InitialValue": "0"
|
||||
},
|
||||
{
|
||||
"ID": 501031108,
|
||||
"BattleEventID": 5010311,
|
||||
"VariableName": "DoorStatus2",
|
||||
"ValueType": "int",
|
||||
"InitialValue": "0"
|
||||
},
|
||||
{
|
||||
"ID": 501031109,
|
||||
"BattleEventID": 5010311,
|
||||
"VariableName": "DoorStatus3",
|
||||
"ValueType": "int",
|
||||
"InitialValue": "0"
|
||||
},
|
||||
{
|
||||
"ID": 501031110,
|
||||
"BattleEventID": 5010311,
|
||||
"VariableName": "DoorStatus4",
|
||||
"ValueType": "int",
|
||||
"InitialValue": "0"
|
||||
},
|
||||
{
|
||||
"ID": 501031111,
|
||||
"BattleEventID": 5010311,
|
||||
"VariableName": "DoorStatus5",
|
||||
"ValueType": "int",
|
||||
"InitialValue": "0"
|
||||
},
|
||||
{
|
||||
"ID": 501031112,
|
||||
"BattleEventID": 5010311,
|
||||
"VariableName": "IsAllyImposterCatched",
|
||||
"ValueType": "bool",
|
||||
"InitialValue": "FALSE"
|
||||
},
|
||||
{
|
||||
"ID": 501031113,
|
||||
"BattleEventID": 5010311,
|
||||
"VariableName": "IsSideQuestRestart",
|
||||
"ValueType": "bool",
|
||||
"InitialValue": "FALSE"
|
||||
},
|
||||
{
|
||||
"ID": 501031114,
|
||||
"BattleEventID": 5010311,
|
||||
"VariableName": "LifeCoinGet",
|
||||
"ValueType": "bool",
|
||||
"InitialValue": "FALSE"
|
||||
},
|
||||
{
|
||||
"ID": 501032101,
|
||||
"BattleEventID": 5010321,
|
||||
"VariableName": "AreaSelect",
|
||||
"ValueType": "int",
|
||||
"InitialValue": "4"
|
||||
},
|
||||
{
|
||||
"ID": 501032102,
|
||||
"BattleEventID": 5010321,
|
||||
"VariableName": "RevivedTime",
|
||||
"ValueType": "int",
|
||||
"InitialValue": "0"
|
||||
},
|
||||
{
|
||||
"ID": 503020101,
|
||||
"BattleEventID": 5030201,
|
||||
"VariableName": "AreaSelect",
|
||||
"ValueType": "int",
|
||||
"InitialValue": "1"
|
||||
},
|
||||
{
|
||||
"ID": 503021101,
|
||||
"BattleEventID": 5030211,
|
||||
"VariableName": "AreaSelect",
|
||||
"ValueType": "int",
|
||||
"InitialValue": "1"
|
||||
}
|
||||
]
|
1815
assets/FileCfg/WeaponTemplateTb.json
Normal file
1815
assets/FileCfg/WeaponTemplateTb.json
Normal file
File diff suppressed because it is too large
Load diff
1486
assets/GachaConfig/gacha.jsonc
Normal file
1486
assets/GachaConfig/gacha.jsonc
Normal file
File diff suppressed because it is too large
Load diff
|
@ -16,8 +16,7 @@ rand_mt.workspace = true
|
|||
|
||||
# Database
|
||||
sqlx.workspace = true
|
||||
|
||||
# Util
|
||||
rustyline-async.workspace = true
|
||||
thiserror.workspace = true
|
||||
rand.workspace = true
|
||||
byteorder.workspace = true
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
pub const SERVER_VERSION: &str = "0.1.0";
|
||||
pub const SERVER_VERSION: &str = "0.2.0";
|
||||
pub const CLIENT_VERSION: &str = "CNBeta1.1.1";
|
||||
|
|
|
@ -1,6 +1,18 @@
|
|||
pub fn init_tracing() {
|
||||
use env_logger::Target;
|
||||
use rustyline_async::SharedWriter;
|
||||
use tracing_log::log::LevelFilter;
|
||||
|
||||
pub fn init_tracing(out: Option<SharedWriter>) {
|
||||
#[cfg(target_os = "windows")]
|
||||
ansi_term::enable_ansi_support().unwrap();
|
||||
|
||||
env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
|
||||
let target = match out {
|
||||
Some(out) => Target::Pipe(Box::new(out)),
|
||||
None => Target::Stdout,
|
||||
};
|
||||
|
||||
env_logger::builder()
|
||||
.target(target)
|
||||
.filter(None, LevelFilter::Info)
|
||||
.init();
|
||||
}
|
||||
|
|
|
@ -7,6 +7,9 @@ version.workspace = true
|
|||
# Serialization
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
jsonc-parser.workspace = true
|
||||
chrono.workspace = true
|
||||
prost.workspace = true
|
||||
|
||||
# Util
|
||||
paste.workspace = true
|
||||
|
@ -14,3 +17,6 @@ thiserror.workspace = true
|
|||
|
||||
# Tracing
|
||||
tracing.workspace = true
|
||||
|
||||
# Internal
|
||||
proto.workspace = true
|
||||
|
|
42
nap_data/src/action/mod.rs
Normal file
42
nap_data/src/action/mod.rs
Normal file
|
@ -0,0 +1,42 @@
|
|||
use paste::paste;
|
||||
use serde::Deserialize;
|
||||
|
||||
macro_rules! actions {
|
||||
($($name:ident;)*) => {
|
||||
paste! {
|
||||
$(
|
||||
mod [<$name:snake>];
|
||||
pub use [<$name:snake>]::[<Config $name>];
|
||||
)*
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(tag = "$type")]
|
||||
pub enum ActionConfig {
|
||||
$(
|
||||
$name([<Config $name>]),
|
||||
)*
|
||||
}
|
||||
|
||||
impl ActionConfig {
|
||||
pub fn to_protocol(&self) -> ::proto::ActionInfo {
|
||||
use ::prost::Message;
|
||||
|
||||
match self {
|
||||
$(
|
||||
Self::$name(config) => ::proto::ActionInfo {
|
||||
body: config.to_protocol().encode_to_vec(),
|
||||
action_type: ::proto::ActionType::$name.into(),
|
||||
..Default::default()
|
||||
},
|
||||
)*
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
actions! {
|
||||
SwitchSection;
|
||||
OpenUi;
|
||||
}
|
19
nap_data/src/action/open_ui.rs
Normal file
19
nap_data/src/action/open_ui.rs
Normal file
|
@ -0,0 +1,19 @@
|
|||
use serde::Deserialize;
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct ConfigOpenUi {
|
||||
pub ui: String,
|
||||
pub args: i32,
|
||||
pub store_template_id: i32,
|
||||
}
|
||||
|
||||
impl ConfigOpenUi {
|
||||
pub fn to_protocol(&self) -> ::proto::ActionOpenUi {
|
||||
::proto::ActionOpenUi {
|
||||
ui: self.ui.clone(),
|
||||
args: self.args,
|
||||
store_template_id: self.store_template_id,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
21
nap_data/src/action/switch_section.rs
Normal file
21
nap_data/src/action/switch_section.rs
Normal file
|
@ -0,0 +1,21 @@
|
|||
use serde::Deserialize;
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct ConfigSwitchSection {
|
||||
pub section_id: u32,
|
||||
pub transform: String,
|
||||
pub camera_x: u32,
|
||||
pub camera_y: u32,
|
||||
}
|
||||
|
||||
impl ConfigSwitchSection {
|
||||
pub fn to_protocol(&self) -> ::proto::ActionSwitchSection {
|
||||
::proto::ActionSwitchSection {
|
||||
section: self.section_id,
|
||||
transform: self.transform.clone(),
|
||||
camera_x: self.camera_x,
|
||||
camera_y: self.camera_y,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
29
nap_data/src/event/mod.rs
Normal file
29
nap_data/src/event/mod.rs
Normal file
|
@ -0,0 +1,29 @@
|
|||
use std::sync::OnceLock;
|
||||
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::{action::ActionConfig, DataLoadError};
|
||||
|
||||
const INTERACT_CONFIG_JSON: &str = "Interacts.json";
|
||||
static EVENT_GRAPHS: OnceLock<Vec<EventGraphConfig>> = OnceLock::new();
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct EventGraphConfig {
|
||||
pub event_id: u32,
|
||||
pub actions: Vec<ActionConfig>,
|
||||
}
|
||||
|
||||
pub(crate) fn load_event_graphs(path: &str) -> Result<(), DataLoadError> {
|
||||
let data = std::fs::read_to_string(format!("{path}/{INTERACT_CONFIG_JSON}"))
|
||||
.map_err(|err| DataLoadError::IoError(err))?;
|
||||
|
||||
let event_graphs = serde_json::from_str::<Vec<EventGraphConfig>>(&data)
|
||||
.map_err(|err| DataLoadError::FromJsonError(String::from("EventGraphCollection"), err))?;
|
||||
|
||||
EVENT_GRAPHS.set(event_graphs).unwrap();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn interacts() -> std::slice::Iter<'static, EventGraphConfig> {
|
||||
EVENT_GRAPHS.get().unwrap().iter()
|
||||
}
|
305
nap_data/src/gacha/gacha_config.rs
Normal file
305
nap_data/src/gacha/gacha_config.rs
Normal file
|
@ -0,0 +1,305 @@
|
|||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
use chrono::{prelude::Local, DateTime};
|
||||
use serde::{Deserialize, Deserializer};
|
||||
use tracing;
|
||||
|
||||
#[derive(Debug, Default, Deserialize)]
|
||||
pub struct ExtraItemsPolicy {
|
||||
pub id: u32,
|
||||
pub count: u32,
|
||||
#[serde(default)]
|
||||
pub apply_on_owned_count: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Deserialize)]
|
||||
pub struct ProbabilityPoint {
|
||||
pub start_pity: u32,
|
||||
pub start_chance_percent: f64,
|
||||
#[serde(default)]
|
||||
pub increment_percent: f64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Deserialize)]
|
||||
pub struct ProbabilityModel {
|
||||
#[serde(default)]
|
||||
pub clear_status_on_higher_rarity_pulled: bool,
|
||||
pub points: Vec<ProbabilityPoint>,
|
||||
// This value is for display only, so it's set when
|
||||
// the maximum guarantee is not equal to the
|
||||
// automatically calculated value (commonly, less than).
|
||||
#[serde(default)]
|
||||
pub maximum_guarantee_pity: u32,
|
||||
|
||||
#[serde(skip_deserializing)]
|
||||
probability_percents: Vec<f64>,
|
||||
}
|
||||
|
||||
impl ProbabilityModel {
|
||||
fn get_maximum_guarantee(&self) -> u32 {
|
||||
self.probability_percents.len() as u32 - 1
|
||||
}
|
||||
|
||||
pub fn post_configure(&mut self, tag: &String) {
|
||||
self.points.sort_by_key(|point| point.start_pity);
|
||||
|
||||
let mut probability_percents: Vec<f64> = vec![0.0];
|
||||
for (i, point) in self.points.iter().enumerate() {
|
||||
if i > 0 {
|
||||
let last_point = &self.points[i - 1];
|
||||
let last_stop_percent = last_point.start_chance_percent
|
||||
+ last_point.increment_percent
|
||||
* (point.start_pity - last_point.start_pity) as f64;
|
||||
if last_stop_percent > point.start_chance_percent {
|
||||
tracing::warn!("Gacha - ProbabilityModel '{tag}': The start chance of '{point:?}' is less than the value inherited from the previous point.");
|
||||
}
|
||||
}
|
||||
|
||||
let mut max_pity = 2000;
|
||||
if i < self.points.len() - 1 {
|
||||
let next_point = &self.points[i + 1];
|
||||
max_pity = next_point.start_pity - 1;
|
||||
let max_probability = point.start_chance_percent
|
||||
+ point.increment_percent
|
||||
* (next_point.start_pity - 1 - point.start_pity) as f64;
|
||||
assert!(max_probability < 100.0, "Gacha - ProbabilityModel '{tag}': Probability already reached 100% in '{point:?}' (though points with higher pity left)");
|
||||
}
|
||||
|
||||
let mut pity = point.start_pity;
|
||||
let mut percent = point.start_chance_percent;
|
||||
while pity <= max_pity {
|
||||
if max_pity >= 2000 && percent >= 100.0 {
|
||||
probability_percents.push(100.0);
|
||||
break;
|
||||
}
|
||||
probability_percents.push(percent);
|
||||
percent += point.increment_percent;
|
||||
pity += 1;
|
||||
}
|
||||
assert!(pity <= 2000, "Gacha - ProbabilityModel '{tag}' (point {i}): Haven't reached 100% guarantee probability at Pity 2001. The current probability is {percent}%. Crazy.");
|
||||
}
|
||||
|
||||
self.probability_percents = probability_percents;
|
||||
if self.maximum_guarantee_pity <= 0 {
|
||||
self.maximum_guarantee_pity = self.get_maximum_guarantee();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_chance_percent(&self, pity: &u32) -> f64 {
|
||||
// The vec length is 1 bigger than the maximum pity (1-based)
|
||||
let guarantee_pity = self.probability_percents.len() - 1;
|
||||
let idx = *pity as usize;
|
||||
if idx > guarantee_pity {
|
||||
return self.probability_percents[guarantee_pity];
|
||||
}
|
||||
self.probability_percents[idx]
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Default, Deserialize)]
|
||||
pub struct CategoryGuaranteePolicy {
|
||||
pub included_category_tags: HashSet<String>,
|
||||
pub trigger_on_failure_times: u32,
|
||||
pub clear_status_on_target_changed: bool,
|
||||
pub chooseable: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Deserialize)]
|
||||
pub struct TenPullDiscount {
|
||||
pub use_limit: u32,
|
||||
pub discounted_prize: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Deserialize)]
|
||||
pub struct AdvancedGuarantee {
|
||||
pub use_limit: u32,
|
||||
pub rarity: u32,
|
||||
pub guarantee_pity: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Deserialize)]
|
||||
pub struct MustGainItem {
|
||||
pub use_limit: u32,
|
||||
pub rarity: u32,
|
||||
pub category_tag: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Deserialize)]
|
||||
pub struct FreeSelectItem {
|
||||
pub milestones: Vec<u32>,
|
||||
pub rarity: u32,
|
||||
pub category_tags: Vec<String>,
|
||||
pub free_select_progress_record_tag: String,
|
||||
pub free_select_usage_record_tag: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Deserialize)]
|
||||
pub struct DiscountPolicyCollection {
|
||||
pub ten_pull_discount_map: HashMap<String, TenPullDiscount>,
|
||||
pub must_gain_item_map: HashMap<String, MustGainItem>,
|
||||
pub advanced_guarantee_map: HashMap<String, AdvancedGuarantee>,
|
||||
pub free_select_map: HashMap<String, FreeSelectItem>,
|
||||
}
|
||||
|
||||
impl DiscountPolicyCollection {
|
||||
pub fn post_configure(&mut self) {
|
||||
for (tag, ten_pull_discount) in self.ten_pull_discount_map.iter() {
|
||||
let discounted_prize = ten_pull_discount.discounted_prize;
|
||||
assert!(discounted_prize < 10, "Gacha - DiscountPolicy '{tag}': ten_pull_discount's value should be smaller than 10 (read {discounted_prize}).");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum GachaAddedItemType {
|
||||
#[default]
|
||||
None = 0,
|
||||
Weapon = 1,
|
||||
Character = 2,
|
||||
Bangboo = 3,
|
||||
}
|
||||
|
||||
impl GachaAddedItemType {
|
||||
pub fn as_str_name(&self) -> &'static str {
|
||||
match self {
|
||||
GachaAddedItemType::None => "GACHA_ADDED_ITEM_TYPE_NONE",
|
||||
GachaAddedItemType::Weapon => "GACHA_ADDED_ITEM_TYPE_WEAPON",
|
||||
GachaAddedItemType::Character => "GACHA_ADDED_ITEM_TYPE_CHARACTER",
|
||||
GachaAddedItemType::Bangboo => "GACHA_ADDED_ITEM_TYPE_BANGBOO",
|
||||
}
|
||||
}
|
||||
pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
|
||||
match value {
|
||||
"GACHA_ADDED_ITEM_TYPE_NONE" => Some(Self::None),
|
||||
"GACHA_ADDED_ITEM_TYPE_WEAPON" => Some(Self::Weapon),
|
||||
"GACHA_ADDED_ITEM_TYPE_CHARACTER" => Some(Self::Character),
|
||||
"GACHA_ADDED_ITEM_TYPE_BANGBOO" => Some(Self::Bangboo),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i32> for GachaAddedItemType {
|
||||
fn from(value: i32) -> Self {
|
||||
match value {
|
||||
1 => Self::Weapon,
|
||||
2 => Self::Character,
|
||||
3 => Self::Bangboo,
|
||||
_ => Self::None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<i32> for GachaAddedItemType {
|
||||
fn into(self) -> i32 {
|
||||
match self {
|
||||
Self::Weapon => 1,
|
||||
Self::Character => 2,
|
||||
Self::Bangboo => 3,
|
||||
Self::None => 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Deserialize)]
|
||||
pub struct GachaCategoryInfo {
|
||||
#[serde(default)]
|
||||
pub is_promotional_items: bool,
|
||||
pub item_ids: Vec<u32>,
|
||||
pub category_weight: u32,
|
||||
#[serde(deserialize_with = "from_str")]
|
||||
pub item_type: GachaAddedItemType,
|
||||
}
|
||||
|
||||
pub fn from_str<'de, D>(deserializer: D) -> Result<GachaAddedItemType, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let s: String = Deserialize::deserialize(deserializer)?;
|
||||
|
||||
let result = GachaAddedItemType::from_str_name(&s);
|
||||
match result {
|
||||
Some(val) => Ok(val),
|
||||
None => Ok(GachaAddedItemType::None)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Deserialize)]
|
||||
pub struct GachaAvailableItemsInfo {
|
||||
pub rarity: u32,
|
||||
#[serde(default)]
|
||||
pub extra_items_policy_tags: Vec<String>,
|
||||
pub categories: HashMap<String, GachaCategoryInfo>,
|
||||
pub probability_model_tag: String,
|
||||
#[serde(default)]
|
||||
pub category_guarantee_policy_tags: Vec<String>,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Default, Deserialize)]
|
||||
pub struct CharacterGachaPool {
|
||||
pub gacha_schedule_id: u32,
|
||||
pub gacha_parent_schedule_id: u32,
|
||||
pub comment: String,
|
||||
pub gacha_type: u32,
|
||||
pub cost_item_id: u32,
|
||||
pub start_time: DateTime<Local>,
|
||||
pub end_time: DateTime<Local>,
|
||||
#[serde(default)]
|
||||
pub discount_policy_tags: Vec<String>,
|
||||
pub sharing_guarantee_info_category: String,
|
||||
pub gacha_items: Vec<GachaAvailableItemsInfo>,
|
||||
}
|
||||
|
||||
impl CharacterGachaPool {
|
||||
pub fn is_still_open(&self, now: &DateTime<Local>) -> bool {
|
||||
self.start_time <= *now && *now <= self.end_time
|
||||
}
|
||||
|
||||
pub fn post_configure(&mut self, probability_model_map: &HashMap<String, ProbabilityModel>) {
|
||||
self.gacha_items
|
||||
.sort_by_key(|item_list| u32::MAX - item_list.rarity);
|
||||
for items_info in self.gacha_items.iter_mut() {
|
||||
assert!(probability_model_map.contains_key(&items_info.probability_model_tag), "Gacha - CharacterGachaPool '{}': Specified ProbabilityModel tag '{}' that does not exist.", self.gacha_schedule_id, items_info.probability_model_tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Deserialize)]
|
||||
pub struct GachaCommonProperties {
|
||||
pub up_item_category_tag: String,
|
||||
pub s_item_rarity: u32,
|
||||
pub a_item_rarity: u32,
|
||||
// TODO: PostConfigure check
|
||||
pub ten_pull_discount_tag: String,
|
||||
pub newcomer_advanced_s_tag: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Deserialize)]
|
||||
pub struct GachaConfiguration {
|
||||
pub character_gacha_pool_list: Vec<CharacterGachaPool>,
|
||||
pub probability_model_map: HashMap<String, ProbabilityModel>,
|
||||
pub category_guarantee_policy_map: HashMap<String, CategoryGuaranteePolicy>,
|
||||
pub extra_items_policy_map: HashMap<String, ExtraItemsPolicy>,
|
||||
pub discount_policies: DiscountPolicyCollection,
|
||||
pub common_properties: GachaCommonProperties,
|
||||
}
|
||||
|
||||
impl GachaConfiguration {
|
||||
pub fn post_configure(&mut self) {
|
||||
assert!(
|
||||
self.category_guarantee_policy_map
|
||||
.contains_key(&self.common_properties.up_item_category_tag),
|
||||
"The UP category should be valid in policy map."
|
||||
);
|
||||
|
||||
for (tag, policy) in self.probability_model_map.iter_mut() {
|
||||
policy.post_configure(&tag);
|
||||
}
|
||||
self.discount_policies.post_configure();
|
||||
for character_pool in self.character_gacha_pool_list.iter_mut() {
|
||||
character_pool.post_configure(&self.probability_model_map);
|
||||
}
|
||||
}
|
||||
}
|
45
nap_data/src/gacha/mod.rs
Normal file
45
nap_data/src/gacha/mod.rs
Normal file
|
@ -0,0 +1,45 @@
|
|||
use std::sync::OnceLock;
|
||||
|
||||
use gacha_config::GachaConfiguration;
|
||||
use jsonc_parser::{parse_to_serde_value, ParseOptions};
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::{action::ActionConfig, DataLoadError};
|
||||
|
||||
pub mod gacha_config;
|
||||
|
||||
const GACHA_CONFIG_NAME: &str = "gacha.jsonc";
|
||||
static GACHACONF: OnceLock<GachaConfiguration> = OnceLock::new();
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct EventGraphConfig {
|
||||
pub event_id: u32,
|
||||
pub actions: Vec<ActionConfig>,
|
||||
}
|
||||
|
||||
pub(crate) fn load_gacha_config(path: &str) -> Result<(), DataLoadError> {
|
||||
let jsonc_data = std::fs::read_to_string(format!("{path}/{GACHA_CONFIG_NAME}"))
|
||||
.map_err(|err| DataLoadError::IoError(err))?;
|
||||
|
||||
let json_value = parse_to_serde_value(
|
||||
&jsonc_data,
|
||||
&ParseOptions {
|
||||
allow_comments: true,
|
||||
allow_loose_object_property_names: false,
|
||||
allow_trailing_commas: true,
|
||||
},
|
||||
)
|
||||
.map_err(|err| DataLoadError::JsoncParseError(err))?
|
||||
.unwrap();
|
||||
|
||||
let mut result = serde_json::from_value::<GachaConfiguration>(json_value)
|
||||
.map_err(|err| DataLoadError::FromJsonError(String::from("GachaConfiguration"), err))?;
|
||||
result.post_configure();
|
||||
|
||||
GACHACONF.set(result).unwrap();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn global_gacha_config() -> &'static GachaConfiguration {
|
||||
GACHACONF.get().unwrap()
|
||||
}
|
|
@ -1,14 +1,20 @@
|
|||
pub mod action;
|
||||
pub mod event;
|
||||
pub mod gacha;
|
||||
pub mod tables;
|
||||
|
||||
use std::{collections::HashMap, sync::OnceLock};
|
||||
|
||||
use jsonc_parser::errors::ParseError;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct AssetsConfig {
|
||||
pub filecfg_path: String,
|
||||
pub event_config_path: String,
|
||||
pub usm_keys_path: String,
|
||||
pub gacha_config_path: String,
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
|
@ -17,16 +23,20 @@ pub enum DataLoadError {
|
|||
IoError(#[from] std::io::Error),
|
||||
#[error("from_json failed for type {0}, error: {1}")]
|
||||
FromJsonError(String, serde_json::Error),
|
||||
#[error("jsonc_parser parse as json error: {0}")]
|
||||
JsoncParseError(#[from] ParseError),
|
||||
}
|
||||
|
||||
static USM_KEY_MAP: OnceLock<HashMap<u32, u64>> = OnceLock::new();
|
||||
|
||||
pub fn init_data(config: &AssetsConfig) -> Result<(), DataLoadError> {
|
||||
tables::load_tables(&config.filecfg_path)?;
|
||||
event::load_event_graphs(&config.event_config_path)?;
|
||||
if let Err(err) = load_usm_keys(&config.usm_keys_path) {
|
||||
tracing::warn!("failed to load USM keys, in-game cutscenes will not work! Reason: {err}");
|
||||
USM_KEY_MAP.set(HashMap::new()).unwrap();
|
||||
}
|
||||
gacha::load_gacha_config(&config.gacha_config_path)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
30
nap_data/src/tables/archive_battle_quest_template.rs
Normal file
30
nap_data/src/tables/archive_battle_quest_template.rs
Normal file
|
@ -0,0 +1,30 @@
|
|||
use serde::Deserialize;
|
||||
|
||||
use super::BattleEventConfigID;
|
||||
|
||||
template_id!(ArchiveBattleQuest id);
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct ArchiveBattleQuestTemplate {
|
||||
#[serde(rename = "ID")]
|
||||
pub id: ArchiveBattleQuestID,
|
||||
pub quest_name: String,
|
||||
pub quest_desc: String,
|
||||
pub target: String,
|
||||
pub quest_type: u32,
|
||||
pub chapter: u32,
|
||||
pub difficulty: u32,
|
||||
pub monster_level: u32,
|
||||
#[serde(rename = "HollowID")]
|
||||
pub hollow_id: u32,
|
||||
#[serde(rename = "FirstBattleEventID")]
|
||||
pub first_battle_event_id: u32,
|
||||
#[serde(rename = "BattleEventID")]
|
||||
pub battle_event_id: BattleEventConfigID,
|
||||
pub battle_rank: String,
|
||||
pub slot1_avatar: i32,
|
||||
pub slot2_avatar: i32,
|
||||
pub slot3_avatar: i32,
|
||||
pub buddy: i32,
|
||||
}
|
20
nap_data/src/tables/archive_file_quest_template.rs
Normal file
20
nap_data/src/tables/archive_file_quest_template.rs
Normal file
|
@ -0,0 +1,20 @@
|
|||
use serde::Deserialize;
|
||||
|
||||
template_id!(ArchiveFileQuest id);
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct ArchiveFileQuestTemplate {
|
||||
#[serde(rename = "ID")]
|
||||
pub id: ArchiveFileQuestID,
|
||||
#[serde(rename = "ArchiveID")]
|
||||
pub archive_id: u32,
|
||||
pub difficulty_lv: u32,
|
||||
pub show_type: u32,
|
||||
pub recommended_hit_types: Vec<u32>,
|
||||
pub video: String,
|
||||
pub archive_file_name: String,
|
||||
pub archive_file_num: String,
|
||||
pub archive_file_ni_ds: Vec<u32>,
|
||||
pub auto_distribution: bool,
|
||||
}
|
|
@ -1,10 +1,12 @@
|
|||
use serde::Deserialize;
|
||||
|
||||
template_id!(AvatarBase id);
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct AvatarBaseTemplate {
|
||||
#[serde(rename = "ID")]
|
||||
pub id: u32,
|
||||
pub id: AvatarBaseID,
|
||||
pub code_name: String,
|
||||
pub name: String,
|
||||
pub full_name: String,
|
||||
|
|
16
nap_data/src/tables/battle_event_config_template.rs
Normal file
16
nap_data/src/tables/battle_event_config_template.rs
Normal file
|
@ -0,0 +1,16 @@
|
|||
use serde::Deserialize;
|
||||
|
||||
use super::OnceRewardID;
|
||||
|
||||
template_id!(BattleEventConfig id);
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct BattleEventConfigTemplate {
|
||||
#[serde(rename = "ID")]
|
||||
pub id: BattleEventConfigID,
|
||||
#[serde(rename = "LevelDesignID")]
|
||||
pub level_design_id: u32,
|
||||
pub normal_drop: String,
|
||||
pub special_drop: Vec<OnceRewardID>,
|
||||
}
|
16
nap_data/src/tables/battle_group_config_template.rs
Normal file
16
nap_data/src/tables/battle_group_config_template.rs
Normal file
|
@ -0,0 +1,16 @@
|
|||
use serde::Deserialize;
|
||||
|
||||
use super::BattleEventConfigID;
|
||||
|
||||
template_id!(BattleGroupConfig id);
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct BattleGroupConfigTemplate {
|
||||
#[serde(rename = "ID")]
|
||||
pub id: BattleGroupConfigID,
|
||||
#[serde(rename = "QuestID")]
|
||||
pub quest_id: u32,
|
||||
#[serde(rename = "BattleEventID")]
|
||||
pub battle_event_id: BattleEventConfigID,
|
||||
}
|
11
nap_data/src/tables/buddy_base_template.rs
Normal file
11
nap_data/src/tables/buddy_base_template.rs
Normal file
|
@ -0,0 +1,11 @@
|
|||
use serde::Deserialize;
|
||||
|
||||
template_id!(BuddyBase id);
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct BuddyBaseTemplate {
|
||||
#[serde(rename = "ID")]
|
||||
pub id: BuddyBaseID,
|
||||
pub buddy_type: u32,
|
||||
}
|
10
nap_data/src/tables/hollow_config_template.rs
Normal file
10
nap_data/src/tables/hollow_config_template.rs
Normal file
|
@ -0,0 +1,10 @@
|
|||
use serde::Deserialize;
|
||||
|
||||
template_id!(HollowConfig id);
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct HollowConfigTemplate {
|
||||
#[serde(rename = "ID")]
|
||||
pub id: HollowConfigID,
|
||||
}
|
13
nap_data/src/tables/hollow_quest_template.rs
Normal file
13
nap_data/src/tables/hollow_quest_template.rs
Normal file
|
@ -0,0 +1,13 @@
|
|||
use serde::Deserialize;
|
||||
|
||||
template_id!(HollowQuest id);
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct HollowQuestTemplate {
|
||||
#[serde(rename = "ID")]
|
||||
pub id: HollowQuestID,
|
||||
#[serde(rename = "ChessBoardID")]
|
||||
pub chess_board_id: u32,
|
||||
pub hollow_quest_type: u32,
|
||||
}
|
10
nap_data/src/tables/item_template.rs
Normal file
10
nap_data/src/tables/item_template.rs
Normal file
|
@ -0,0 +1,10 @@
|
|||
use serde::Deserialize;
|
||||
|
||||
template_id!(Item id);
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct ItemTemplate {
|
||||
#[serde(rename = "ID")]
|
||||
pub id: ItemID,
|
||||
}
|
12
nap_data/src/tables/main_city_bgm_config_template.rs
Normal file
12
nap_data/src/tables/main_city_bgm_config_template.rs
Normal file
|
@ -0,0 +1,12 @@
|
|||
use serde::Deserialize;
|
||||
|
||||
template_id!(MainCityBgmConfig id);
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct MainCityBgmConfigTemplate {
|
||||
#[serde(rename = "ID")]
|
||||
pub id: MainCityBgmConfigID,
|
||||
pub play_event_name: String,
|
||||
pub state_name: String,
|
||||
}
|
12
nap_data/src/tables/main_city_default_object_template.rs
Normal file
12
nap_data/src/tables/main_city_default_object_template.rs
Normal file
|
@ -0,0 +1,12 @@
|
|||
use serde::Deserialize;
|
||||
|
||||
template_id!(MainCityDefaultObject tag_id);
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct MainCityDefaultObjectTemplate {
|
||||
#[serde(rename = "TagID")]
|
||||
pub tag_id: MainCityDefaultObjectID,
|
||||
#[serde(rename = "InteractIDs")]
|
||||
pub interact_ids: Vec<u32>,
|
||||
}
|
28
nap_data/src/tables/main_city_object_template.rs
Normal file
28
nap_data/src/tables/main_city_object_template.rs
Normal file
|
@ -0,0 +1,28 @@
|
|||
use serde::Deserialize;
|
||||
|
||||
template_id!(MainCityObject tag_id);
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct MainCityObjectTemplate {
|
||||
#[serde(rename = "TagID")]
|
||||
pub tag_id: MainCityObjectID,
|
||||
#[serde(rename = "NPCID")]
|
||||
pub npc_id: u32,
|
||||
pub create_position: String,
|
||||
pub create_type: u32,
|
||||
#[serde(rename = "DefaultInteractIDs")]
|
||||
pub default_interact_ids: Vec<u32>,
|
||||
pub interact_name: String,
|
||||
pub interact_shape: u32,
|
||||
pub interact_scale: String,
|
||||
pub focus_interact_scale: f32,
|
||||
pub camera_story_key: String,
|
||||
}
|
||||
|
||||
impl MainCityObjectTemplate {
|
||||
pub fn get_section_name(&self) -> String {
|
||||
let section_name = self.create_position.split('_').next().unwrap();
|
||||
format!("SectionName_{section_name}")
|
||||
}
|
||||
}
|
|
@ -1,13 +1,53 @@
|
|||
use paste::paste;
|
||||
use std::sync::OnceLock;
|
||||
use thiserror::Error;
|
||||
|
||||
use super::DataLoadError;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
#[error("template with id {0} not found")]
|
||||
pub struct TemplateNotFoundError(pub u32);
|
||||
|
||||
macro_rules! template_id {
|
||||
($type_name:ident $id_field:ident) => {
|
||||
::paste::paste! {
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, ::serde::Deserialize, ::serde::Serialize)]
|
||||
pub struct [<$type_name ID>](u32);
|
||||
|
||||
impl [<$type_name ID>] {
|
||||
pub fn new(id: u32) -> Result<Self, super::TemplateNotFoundError> {
|
||||
crate::tables::[<$type_name:snake _template_tb>]::iter()
|
||||
.any(|tmpl| tmpl.$id_field.value() == id)
|
||||
.then_some(Self(id)).ok_or(super::TemplateNotFoundError(id))
|
||||
}
|
||||
|
||||
pub const fn new_unchecked(id: u32) -> Self {
|
||||
Self(id)
|
||||
}
|
||||
|
||||
pub fn value(&self) -> u32 {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub fn template(&self) -> &[<$type_name Template>] {
|
||||
crate::tables::[<$type_name:snake _template_tb>]::iter().find(|tmpl| tmpl.$id_field == *self).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::fmt::Display for [<$type_name ID>] {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||
f.write_fmt(format_args!("{}", self.0))
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! template_tables {
|
||||
($($template_type:ident;)*) => {
|
||||
$(paste! {
|
||||
mod [<$template_type:snake>];
|
||||
pub use [<$template_type:snake>]::$template_type;
|
||||
pub use [<$template_type:snake>]::*;
|
||||
})*
|
||||
|
||||
$(paste! {
|
||||
|
@ -38,9 +78,29 @@ macro_rules! template_tables {
|
|||
|
||||
template_tables! {
|
||||
AvatarBaseTemplate;
|
||||
BuddyBaseTemplate;
|
||||
UnlockConfigTemplate;
|
||||
SectionConfigTemplate;
|
||||
ProcedureConfigTemplate;
|
||||
PostGirlConfigTemplate;
|
||||
TrainingQuestTemplate;
|
||||
WeaponTemplate;
|
||||
MainCityObjectTemplate;
|
||||
MainCityDefaultObjectTemplate;
|
||||
MainCityBgmConfigTemplate;
|
||||
ArchiveFileQuestTemplate;
|
||||
ArchiveBattleQuestTemplate;
|
||||
HollowQuestTemplate;
|
||||
HollowConfigTemplate;
|
||||
BattleEventConfigTemplate;
|
||||
BattleGroupConfigTemplate;
|
||||
SubAreaDataTemplate;
|
||||
VariableDataTemplate;
|
||||
OnceRewardTemplate;
|
||||
QuickAccessTemplate;
|
||||
QuickFuncTemplate;
|
||||
TeleportConfigTemplate;
|
||||
ItemTemplate;
|
||||
RobotConfigTemplate;
|
||||
RobotBuddyConfigTemplate;
|
||||
}
|
||||
|
|
19
nap_data/src/tables/once_reward_template.rs
Normal file
19
nap_data/src/tables/once_reward_template.rs
Normal file
|
@ -0,0 +1,19 @@
|
|||
use serde::Deserialize;
|
||||
|
||||
template_id!(OnceReward reward_id);
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct OnceRewardTemplate {
|
||||
#[serde(rename = "RewardID")]
|
||||
pub reward_id: OnceRewardID,
|
||||
pub reward_list: Vec<RewardItem>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct RewardItem {
|
||||
#[serde(rename = "RewardItemID")]
|
||||
pub reward_item_id: u32,
|
||||
pub reward_amount: u32,
|
||||
}
|
|
@ -1,9 +1,11 @@
|
|||
use serde::Deserialize;
|
||||
|
||||
template_id!(PostGirlConfig id);
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct PostGirlConfigTemplate {
|
||||
#[serde(rename = "ID")]
|
||||
pub id: u32,
|
||||
pub id: PostGirlConfigID,
|
||||
pub name: String,
|
||||
}
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
use serde::Deserialize;
|
||||
|
||||
template_id!(ProcedureConfig procedure_id);
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct ProcedureConfigTemplate {
|
||||
#[serde(rename = "ProcedureID")]
|
||||
pub procedure_id: i32,
|
||||
pub procedure_id: ProcedureConfigID,
|
||||
pub procedure_type: u32,
|
||||
#[serde(rename = "ContentID")]
|
||||
pub content_id: String,
|
||||
pub jump_tos: Vec<i32>,
|
||||
pub jump_tos: Vec<u32>,
|
||||
pub procedure_banks: Vec<String>,
|
||||
pub procedure_event: String,
|
||||
}
|
||||
|
|
11
nap_data/src/tables/quick_access_template.rs
Normal file
11
nap_data/src/tables/quick_access_template.rs
Normal file
|
@ -0,0 +1,11 @@
|
|||
use serde::Deserialize;
|
||||
|
||||
template_id!(QuickAccess quick_func_id);
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct QuickAccessTemplate {
|
||||
pub quick_access_index: u32,
|
||||
#[serde(rename = "QuickFuncID")]
|
||||
pub quick_func_id: QuickAccessID,
|
||||
}
|
10
nap_data/src/tables/quick_func_template.rs
Normal file
10
nap_data/src/tables/quick_func_template.rs
Normal file
|
@ -0,0 +1,10 @@
|
|||
use serde::Deserialize;
|
||||
|
||||
template_id!(QuickFunc btn_id);
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct QuickFuncTemplate {
|
||||
#[serde(rename = "BtnID")]
|
||||
pub btn_id: QuickFuncID,
|
||||
}
|
17
nap_data/src/tables/robot_buddy_config_template.rs
Normal file
17
nap_data/src/tables/robot_buddy_config_template.rs
Normal file
|
@ -0,0 +1,17 @@
|
|||
use serde::Deserialize;
|
||||
|
||||
use super::BuddyBaseID;
|
||||
|
||||
template_id!(RobotBuddyConfig robot_id);
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct RobotBuddyConfigTemplate {
|
||||
#[serde(rename = "RobotBuddyID")]
|
||||
pub robot_id: RobotBuddyConfigID,
|
||||
#[serde(rename = "BuddyID")]
|
||||
pub buddy_id: BuddyBaseID,
|
||||
pub char_level: u32,
|
||||
pub char_upgrade_level: u32,
|
||||
pub char_star: u32,
|
||||
}
|
24
nap_data/src/tables/robot_config_template.rs
Normal file
24
nap_data/src/tables/robot_config_template.rs
Normal file
|
@ -0,0 +1,24 @@
|
|||
use serde::Deserialize;
|
||||
|
||||
use super::{AvatarBaseID, WeaponID};
|
||||
|
||||
template_id!(RobotConfig robot_id);
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct RobotConfigTemplate {
|
||||
#[serde(rename = "RobotID")]
|
||||
pub robot_id: RobotConfigID,
|
||||
#[serde(rename = "CharacterID")]
|
||||
pub character_id: AvatarBaseID,
|
||||
pub char_level: u32,
|
||||
pub char_upgrade_level: u32,
|
||||
pub char_star: u32,
|
||||
pub skill_levels: Vec<u32>,
|
||||
pub talent_level: u32,
|
||||
#[serde(rename = "WeaponID")]
|
||||
pub weapon_id: WeaponID,
|
||||
pub weapon_level: u32,
|
||||
pub weapon_upgrade_level: u32,
|
||||
pub weapon_refine_level: u32,
|
||||
}
|
|
@ -1,9 +1,11 @@
|
|||
use serde::Deserialize;
|
||||
|
||||
template_id!(SectionConfig section_id);
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct SectionConfigTemplate {
|
||||
pub section_id: u32,
|
||||
pub section_id: SectionConfigID,
|
||||
pub photo_name: String,
|
||||
pub name: String,
|
||||
pub primary_entry_name: String,
|
||||
|
|
16
nap_data/src/tables/sub_area_data_template.rs
Normal file
16
nap_data/src/tables/sub_area_data_template.rs
Normal file
|
@ -0,0 +1,16 @@
|
|||
use std::u32;
|
||||
|
||||
use serde::Deserialize;
|
||||
|
||||
template_id!(SubAreaData area_id);
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct SubAreaDataTemplate {
|
||||
#[serde(rename = "AreaID")]
|
||||
pub area_id: SubAreaDataID,
|
||||
#[serde(rename = "BattleEventID")]
|
||||
pub battle_event_id: u32,
|
||||
pub time_period: String,
|
||||
pub weather: String,
|
||||
}
|
11
nap_data/src/tables/teleport_config_template.rs
Normal file
11
nap_data/src/tables/teleport_config_template.rs
Normal file
|
@ -0,0 +1,11 @@
|
|||
use serde::Deserialize;
|
||||
|
||||
template_id!(TeleportConfig teleport_id);
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct TeleportConfigTemplate {
|
||||
#[serde(rename = "TeleportID")]
|
||||
pub teleport_id: TeleportConfigID,
|
||||
pub client_visible: u32,
|
||||
}
|
|
@ -1,9 +1,13 @@
|
|||
use serde::Deserialize;
|
||||
|
||||
use super::BattleEventConfigID;
|
||||
|
||||
template_id!(TrainingQuest id);
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct TrainingQuestTemplate {
|
||||
pub id: u32,
|
||||
pub id: TrainingQuestID,
|
||||
pub training_type: u32,
|
||||
pub battle_event_id: u32,
|
||||
pub battle_event_id: BattleEventConfigID,
|
||||
}
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
use serde::Deserialize;
|
||||
|
||||
template_id!(UnlockConfig id);
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct UnlockConfigTemplate {
|
||||
#[serde(rename = "ID")]
|
||||
pub id: i32,
|
||||
pub id: UnlockConfigID,
|
||||
pub name: String,
|
||||
}
|
||||
|
|
25
nap_data/src/tables/variable_data_template.rs
Normal file
25
nap_data/src/tables/variable_data_template.rs
Normal file
|
@ -0,0 +1,25 @@
|
|||
use std::u32;
|
||||
|
||||
use serde::Deserialize;
|
||||
|
||||
template_id!(VariableData id);
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct VariableDataTemplate {
|
||||
#[serde(rename = "ID")]
|
||||
pub id: VariableDataID,
|
||||
#[serde(rename = "BattleEventID")]
|
||||
pub battle_event_id: u32,
|
||||
pub variable_name: String,
|
||||
pub value_type: VariableValueType,
|
||||
pub initial_value: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum VariableValueType {
|
||||
Int,
|
||||
Bool,
|
||||
Float,
|
||||
}
|
36
nap_data/src/tables/weapon_template.rs
Normal file
36
nap_data/src/tables/weapon_template.rs
Normal file
|
@ -0,0 +1,36 @@
|
|||
use serde::Deserialize;
|
||||
|
||||
template_id!(Weapon item_id);
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct WeaponTemplate {
|
||||
#[serde(rename = "ItemID")]
|
||||
pub item_id: WeaponID,
|
||||
pub code_name: String,
|
||||
#[serde(rename = "Type")]
|
||||
pub weapon_type: u32,
|
||||
pub base_property: IntPropertyIntValue,
|
||||
pub rand_property: IntPropertyIntValue,
|
||||
pub star_limit: u32,
|
||||
pub exp_recycle: u32,
|
||||
pub refine_costs: Vec<IntItemIDIntNumber>,
|
||||
pub refine_initial: u32,
|
||||
pub refine_limit: u32,
|
||||
}
|
||||
|
||||
// nice names, mihoyo
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct IntPropertyIntValue {
|
||||
pub property: u32,
|
||||
pub value: i32,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct IntItemIDIntNumber {
|
||||
#[serde(rename = "ItemID")]
|
||||
pub item_id: u32,
|
||||
pub number: u32,
|
||||
}
|
|
@ -15,6 +15,7 @@ rbase64.workspace = true
|
|||
toml.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
chrono.workspace = true
|
||||
|
||||
# Database
|
||||
sqlx.workspace = true
|
||||
|
@ -28,6 +29,7 @@ rand.workspace = true
|
|||
atomic_enum.workspace = true
|
||||
num_enum.workspace = true
|
||||
dashmap.workspace = true
|
||||
rustyline-async.workspace = true
|
||||
|
||||
# Tracing
|
||||
tracing.workspace = true
|
||||
|
|
116
nap_gameserver/src/commands/avatar.rs
Normal file
116
nap_gameserver/src/commands/avatar.rs
Normal file
|
@ -0,0 +1,116 @@
|
|||
use data::tables::{self, AvatarBaseID};
|
||||
use proto::{AddAvatarPerformType, AddAvatarScNotify, PlayerSyncScNotify};
|
||||
|
||||
use crate::ServerState;
|
||||
|
||||
use super::ArgSlice;
|
||||
|
||||
pub async fn add(
|
||||
args: ArgSlice<'_>,
|
||||
state: &ServerState,
|
||||
) -> Result<String, Box<dyn std::error::Error>> {
|
||||
const USAGE: &str = "Usage: avatar add [player_uid] [avatar_id]";
|
||||
|
||||
if args.len() != 2 {
|
||||
return Ok(USAGE.to_string());
|
||||
}
|
||||
|
||||
let uid = args[0].parse::<u32>()?;
|
||||
let avatar_id = args[1].parse::<u32>()?;
|
||||
let Ok(avatar_id) = AvatarBaseID::new(avatar_id) else {
|
||||
return Ok(format!("avatar with id {avatar_id} doesn't exist"));
|
||||
};
|
||||
|
||||
let Some(player_lock) = state.player_mgr.get_player(uid).await else {
|
||||
return Ok(String::from("player not found"));
|
||||
};
|
||||
|
||||
let (session_id, avatar_sync) = {
|
||||
let mut player = player_lock.lock().await;
|
||||
|
||||
player.role_model.add_avatar(avatar_id);
|
||||
(player.current_session_id(), player.role_model.avatar_sync())
|
||||
};
|
||||
|
||||
if let Some(session) = session_id.map(|id| state.session_mgr.get(id)).flatten() {
|
||||
session
|
||||
.notify(AddAvatarScNotify {
|
||||
avatar_id: avatar_id.value(),
|
||||
perform_type: AddAvatarPerformType::Gacha.into(),
|
||||
..Default::default()
|
||||
})
|
||||
.await?;
|
||||
|
||||
session
|
||||
.notify(PlayerSyncScNotify {
|
||||
avatar: Some(avatar_sync),
|
||||
..Default::default()
|
||||
})
|
||||
.await?;
|
||||
} else {
|
||||
state.player_mgr.save_and_remove(uid).await;
|
||||
}
|
||||
|
||||
Ok(format!(
|
||||
"successfully added avatar {avatar_id} to player {uid}"
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn add_all(
|
||||
args: ArgSlice<'_>,
|
||||
state: &ServerState,
|
||||
) -> Result<String, Box<dyn std::error::Error>> {
|
||||
const USAGE: &str = "Usage: avatar add_all [player_uid]";
|
||||
|
||||
if args.len() != 1 {
|
||||
return Ok(USAGE.to_string());
|
||||
}
|
||||
|
||||
let uid = args[0].parse::<u32>()?;
|
||||
|
||||
let Some(player_lock) = state.player_mgr.get_player(uid).await else {
|
||||
return Ok(String::from("player not found"));
|
||||
};
|
||||
|
||||
let (session_id, avatar_sync, avatar_id_list) = {
|
||||
let mut player = player_lock.lock().await;
|
||||
|
||||
let avatar_id_list = tables::avatar_base_template_tb::iter()
|
||||
.filter(|tmpl| tmpl.id.value() < 2000 && !player.role_model.has_avatar(tmpl.id))
|
||||
.map(|tmpl| tmpl.id)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
avatar_id_list
|
||||
.iter()
|
||||
.for_each(|id| player.role_model.add_avatar(*id));
|
||||
|
||||
(
|
||||
player.current_session_id(),
|
||||
player.role_model.avatar_sync(),
|
||||
avatar_id_list,
|
||||
)
|
||||
};
|
||||
|
||||
if let Some(session) = session_id.map(|id| state.session_mgr.get(id)).flatten() {
|
||||
for id in avatar_id_list {
|
||||
session
|
||||
.notify(AddAvatarScNotify {
|
||||
avatar_id: id.value(),
|
||||
perform_type: AddAvatarPerformType::ShowPopup.into(),
|
||||
..Default::default()
|
||||
})
|
||||
.await?;
|
||||
}
|
||||
|
||||
session
|
||||
.notify(PlayerSyncScNotify {
|
||||
avatar: Some(avatar_sync),
|
||||
..Default::default()
|
||||
})
|
||||
.await?;
|
||||
} else {
|
||||
state.player_mgr.save_and_remove(uid).await;
|
||||
}
|
||||
|
||||
Ok(format!("successfully added all avatars to player {uid}"))
|
||||
}
|
125
nap_gameserver/src/commands/gacha.rs
Normal file
125
nap_gameserver/src/commands/gacha.rs
Normal file
|
@ -0,0 +1,125 @@
|
|||
use data::{gacha::global_gacha_config, tables::ItemID};
|
||||
|
||||
use crate::ServerState;
|
||||
|
||||
use super::ArgSlice;
|
||||
|
||||
pub async fn up(
|
||||
args: ArgSlice<'_>,
|
||||
state: &ServerState,
|
||||
) -> Result<String, Box<dyn std::error::Error>> {
|
||||
const USAGE: &str = "Usage: gacha up [player_uid] (start a gacha UP setting guide (available for Bangboo pool))";
|
||||
|
||||
if args.len() == 0 {
|
||||
return Ok(USAGE.to_string());
|
||||
}
|
||||
|
||||
let uid = args[0].parse::<u32>()?;
|
||||
|
||||
let Some(player_lock) = state.player_mgr.get_player(uid).await else {
|
||||
return Ok(String::from("player not found"));
|
||||
};
|
||||
|
||||
let gachaconf = global_gacha_config();
|
||||
let pool_list: Vec<(u32, &String)> = gachaconf
|
||||
.character_gacha_pool_list
|
||||
.iter()
|
||||
.filter(|pool| {
|
||||
pool.gacha_items.iter().any(|rarity_items| {
|
||||
rarity_items
|
||||
.category_guarantee_policy_tags
|
||||
.iter()
|
||||
.map(|tag| gachaconf.category_guarantee_policy_map.get(tag).unwrap())
|
||||
.any(|policy| policy.chooseable)
|
||||
})
|
||||
})
|
||||
.map(|pool| (pool.gacha_schedule_id, &pool.comment))
|
||||
.collect::<Vec<_>>();
|
||||
if args.len() == 1 {
|
||||
return Ok(format!(
|
||||
"{}\n{}\n{}",
|
||||
"Choose a target gacha pool first:",
|
||||
pool_list
|
||||
.iter()
|
||||
.map(|(id, comment)| format!("- gacha_schedule_id: {id} ({comment})"))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n"),
|
||||
"Use 'gacha up [player_uid] [gacha_schedule_id]' to continue."
|
||||
));
|
||||
}
|
||||
|
||||
let target_pool_id = args[1].parse::<u32>()?;
|
||||
let accepted_pool_id_list = pool_list.into_iter().map(|(id, _)| id).collect::<Vec<_>>();
|
||||
if !accepted_pool_id_list.contains(&target_pool_id) {
|
||||
return Ok(String::from("Gacha Pool not found or not allowed to set UP. Use gacha up [player_uid] to view available pool ids."));
|
||||
}
|
||||
let target_pool = gachaconf
|
||||
.character_gacha_pool_list
|
||||
.iter()
|
||||
.filter(|pool| pool.gacha_schedule_id == target_pool_id)
|
||||
.last()
|
||||
.unwrap();
|
||||
|
||||
let chooseable_items: Vec<(ItemID, &String)> = target_pool
|
||||
.gacha_items
|
||||
.iter()
|
||||
.filter(|rarity_items| {
|
||||
rarity_items
|
||||
.category_guarantee_policy_tags
|
||||
.iter()
|
||||
.map(|tag| gachaconf.category_guarantee_policy_map.get(tag).unwrap())
|
||||
.any(|policy| policy.chooseable)
|
||||
})
|
||||
.map(|items| {
|
||||
items
|
||||
.categories
|
||||
.iter()
|
||||
.map(|(category_tag, category)| {
|
||||
category
|
||||
.item_ids
|
||||
.iter()
|
||||
.map(|id| (ItemID::new_unchecked(id.clone()), category_tag))
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.concat()
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.concat();
|
||||
if args.len() == 2 {
|
||||
return Ok(format!(
|
||||
"{}\n{}\nUse 'gacha up [player_uid] {target_pool_id} [item_id]' to set your UP.",
|
||||
"Choose the UP item you want:",
|
||||
chooseable_items
|
||||
.iter()
|
||||
.map(|(item_id, category_tag)| format!("- ID {item_id} (category: {category_tag})"))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n")
|
||||
));
|
||||
}
|
||||
|
||||
let accepted_ids = chooseable_items
|
||||
.iter()
|
||||
.map(|(item_id, _)| item_id.value())
|
||||
.collect::<Vec<_>>();
|
||||
let item_id = args[2].parse::<u32>()?;
|
||||
if !accepted_ids.contains(&item_id) {
|
||||
return Ok(format!("Item ID not found or not included in UP list. Use gacha up [player_uid] {target_pool_id} to view available item ids."));
|
||||
}
|
||||
|
||||
let mut player = player_lock.lock().await;
|
||||
if player
|
||||
.gacha_model
|
||||
.choose_gacha_up(target_pool, &ItemID::new_unchecked(item_id))
|
||||
{
|
||||
Ok(format!(
|
||||
"successfully set your gacha pool: {} (comment: {}) 100% UP to {item_id}. Close & Open Gacha Page to see result.",
|
||||
target_pool.gacha_schedule_id, target_pool.comment
|
||||
))
|
||||
} else {
|
||||
Ok(format!(
|
||||
"failed to set your gacha pool: {} (comment: {}) 100% UP to {item_id} (unexpected maybe bug)",
|
||||
target_pool.gacha_schedule_id, target_pool.comment
|
||||
))
|
||||
}
|
||||
}
|
51
nap_gameserver/src/commands/item.rs
Normal file
51
nap_gameserver/src/commands/item.rs
Normal file
|
@ -0,0 +1,51 @@
|
|||
use data::tables::WeaponID;
|
||||
use proto::PlayerSyncScNotify;
|
||||
|
||||
use crate::ServerState;
|
||||
|
||||
use super::ArgSlice;
|
||||
|
||||
pub async fn add_weapon(
|
||||
args: ArgSlice<'_>,
|
||||
state: &ServerState,
|
||||
) -> Result<String, Box<dyn std::error::Error>> {
|
||||
const USAGE: &str = "Usage: item add_weapon [player_uid] [weapon_id]";
|
||||
|
||||
if args.len() != 2 {
|
||||
return Ok(USAGE.to_string());
|
||||
}
|
||||
|
||||
let uid = args[0].parse::<u32>()?;
|
||||
let weapon_id = args[1].parse::<u32>()?;
|
||||
let Ok(weapon_id) = WeaponID::new(weapon_id) else {
|
||||
return Ok(format!("weapon with id {weapon_id} doesn't exist"));
|
||||
};
|
||||
|
||||
let Some(player_lock) = state.player_mgr.get_player(uid).await else {
|
||||
return Ok(String::from("player not found"));
|
||||
};
|
||||
|
||||
let (session_id, weapon_uid, item_sync) = {
|
||||
let mut player = player_lock.lock().await;
|
||||
let uid = player.item_model.add_weapon(weapon_id);
|
||||
|
||||
(
|
||||
player.current_session_id(),
|
||||
uid.value(),
|
||||
player.item_model.item_sync(),
|
||||
)
|
||||
};
|
||||
|
||||
if let Some(session) = session_id.map(|id| state.session_mgr.get(id)).flatten() {
|
||||
session
|
||||
.notify(PlayerSyncScNotify {
|
||||
item_sync: Some(item_sync),
|
||||
..Default::default()
|
||||
})
|
||||
.await?;
|
||||
} else {
|
||||
state.player_mgr.save_and_remove(uid).await;
|
||||
}
|
||||
|
||||
Ok(format!("successfully added weapon, item uid: {weapon_uid}"))
|
||||
}
|
95
nap_gameserver/src/commands/mod.rs
Normal file
95
nap_gameserver/src/commands/mod.rs
Normal file
|
@ -0,0 +1,95 @@
|
|||
use std::io::Write;
|
||||
use std::sync::Arc;
|
||||
|
||||
use rustyline_async::{Readline, ReadlineEvent, SharedWriter};
|
||||
|
||||
use crate::ServerState;
|
||||
|
||||
mod avatar;
|
||||
mod gacha;
|
||||
mod item;
|
||||
mod player;
|
||||
|
||||
type ArgSlice<'a> = &'a [&'a str];
|
||||
|
||||
pub struct CommandManager {
|
||||
state: Arc<ServerState>,
|
||||
}
|
||||
|
||||
macro_rules! commands {
|
||||
($($category:ident::$action:ident $usage:tt $desc:tt;)*) => {
|
||||
async fn exec(state: &ServerState, cmd: &str) -> String {
|
||||
let input = cmd.split(" ").collect::<Vec<&str>>();
|
||||
|
||||
if input.len() == 1 && *input.get(0).unwrap() == "help" {
|
||||
return Self::help_message();
|
||||
}
|
||||
|
||||
let (Some(category), Some(action)) = (input.get(0), input.get(1)) else {
|
||||
return String::new();
|
||||
};
|
||||
|
||||
let args = &input[2..];
|
||||
match match (*category, *action) {
|
||||
$(
|
||||
(stringify!($category), stringify!($action)) => {
|
||||
$category::$action(args, state).await
|
||||
}
|
||||
)*,
|
||||
_ => {
|
||||
::tracing::info!("unknown command");
|
||||
return Self::help_message();
|
||||
}
|
||||
} {
|
||||
Ok(s) => s,
|
||||
Err(err) => format!("failed to execute command: {err}"),
|
||||
}
|
||||
}
|
||||
|
||||
fn help_message() -> String {
|
||||
concat!("available commands:\n",
|
||||
$(stringify!($category), " ", stringify!($action), " ", $usage, " - ", $desc, "\n",)*
|
||||
"help - shows this message"
|
||||
).to_string()
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl CommandManager {
|
||||
pub fn new(state: Arc<ServerState>) -> Self {
|
||||
Self { state }
|
||||
}
|
||||
|
||||
pub async fn run(&self, mut rl: Readline, mut out: SharedWriter) {
|
||||
loop {
|
||||
match rl.readline().await {
|
||||
Ok(ReadlineEvent::Line(line)) => {
|
||||
let str = Self::exec(&self.state, &line).await;
|
||||
writeln!(&mut out, "{str}").unwrap();
|
||||
|
||||
rl.add_history_entry(line);
|
||||
}
|
||||
Ok(ReadlineEvent::Eof) | Ok(ReadlineEvent::Interrupted) => {
|
||||
rl.flush().unwrap();
|
||||
drop(rl);
|
||||
|
||||
// TODO: maybe disconnect and save all players
|
||||
|
||||
std::process::exit(0);
|
||||
}
|
||||
_ => continue,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
commands! {
|
||||
player::avatar "[player_uid] [avatar_id]" "changes player avatar for main city";
|
||||
player::nickname "[player_uid] [nickname]" "changes player nickname";
|
||||
player::procedure "[player_uid] [procedure_id]" "changes current beginner procedure id, parameter -1 can be used for skipping it";
|
||||
player::kick "[player_uid] [reason]" "kick the specified player (reason is optional)";
|
||||
avatar::add "[player_uid] [avatar_id]" "gives avatar with specified id to player";
|
||||
avatar::add_all "[player_uid]" "gives all avatars to player";
|
||||
item::add_weapon "[player_uid] [weapon_id]" "gives weapon with specified id to player";
|
||||
gacha::up "[player_uid]" "start a gacha UP setting guide (available for Bangboo pool)";
|
||||
}
|
||||
}
|
170
nap_gameserver/src/commands/player.rs
Normal file
170
nap_gameserver/src/commands/player.rs
Normal file
|
@ -0,0 +1,170 @@
|
|||
use data::tables::{AvatarBaseID, ProcedureConfigID};
|
||||
use proto::{DisconnectReason, DisconnectScNotify, PlayerSyncScNotify};
|
||||
|
||||
use crate::ServerState;
|
||||
|
||||
use super::ArgSlice;
|
||||
|
||||
pub async fn avatar(
|
||||
args: ArgSlice<'_>,
|
||||
state: &ServerState,
|
||||
) -> Result<String, Box<dyn std::error::Error>> {
|
||||
const USAGE: &str = "Usage: player avatar [player_uid] [avatar_id]";
|
||||
|
||||
if args.len() != 2 {
|
||||
return Ok(USAGE.to_string());
|
||||
}
|
||||
|
||||
let uid = args[0].parse::<u32>()?;
|
||||
let avatar_id = args[1].parse::<u32>()?;
|
||||
let Ok(avatar_id) = AvatarBaseID::new(avatar_id) else {
|
||||
return Ok(format!("avatar with id {avatar_id} doesn't exist"));
|
||||
};
|
||||
|
||||
let Some(player_lock) = state.player_mgr.get_player(uid).await else {
|
||||
return Ok(String::from("player not found"));
|
||||
};
|
||||
|
||||
let should_save = {
|
||||
let mut player = player_lock.lock().await;
|
||||
player.basic_data_model.frontend_avatar_id = Some(avatar_id);
|
||||
player.current_session_id().is_none()
|
||||
};
|
||||
|
||||
if should_save {
|
||||
state.player_mgr.save_and_remove(uid).await;
|
||||
}
|
||||
|
||||
Ok(format!(
|
||||
"changed frontend_avatar_id, you have to re-enter main city now"
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn nickname(
|
||||
args: ArgSlice<'_>,
|
||||
state: &ServerState,
|
||||
) -> Result<String, Box<dyn std::error::Error>> {
|
||||
const USAGE: &str = "Usage: player nickname [uid] [nickname]";
|
||||
|
||||
if args.len() != 2 {
|
||||
return Ok(USAGE.to_string());
|
||||
}
|
||||
|
||||
let uid = args[0].parse::<u32>()?;
|
||||
let nickname = args[1].trim();
|
||||
|
||||
if !matches!(nickname.len(), (4..=15)) {
|
||||
return Ok(String::from(
|
||||
"nickname should contain at least 4 and not more than 15 characters",
|
||||
));
|
||||
}
|
||||
|
||||
let Some(player_lock) = state.player_mgr.get_player(uid).await else {
|
||||
return Ok(String::from("player not found"));
|
||||
};
|
||||
|
||||
let (session_id, basic_info) = {
|
||||
let mut player = player_lock.lock().await;
|
||||
player.basic_data_model.nick_name = Some(nickname.to_string());
|
||||
|
||||
(
|
||||
player.current_session_id(),
|
||||
player.basic_data_model.player_basic_info(),
|
||||
)
|
||||
};
|
||||
|
||||
if let Some(session) = session_id.map(|id| state.session_mgr.get(id)).flatten() {
|
||||
session
|
||||
.notify(PlayerSyncScNotify {
|
||||
basic_info: Some(basic_info),
|
||||
..Default::default()
|
||||
})
|
||||
.await?;
|
||||
} else {
|
||||
state.player_mgr.save_and_remove(uid).await;
|
||||
}
|
||||
|
||||
Ok(format!(
|
||||
"successfully changed player {uid} nickname to {nickname}"
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn procedure(
|
||||
args: ArgSlice<'_>,
|
||||
state: &ServerState,
|
||||
) -> Result<String, Box<dyn std::error::Error>> {
|
||||
const USAGE: &str = "Usage: player procedure [uid] [procedure_id]";
|
||||
|
||||
if args.len() != 2 {
|
||||
return Ok(USAGE.to_string());
|
||||
}
|
||||
|
||||
let uid = args[0].parse::<u32>()?;
|
||||
let procedure_id = args[1].parse::<i32>()?;
|
||||
|
||||
let procedure_id = match procedure_id {
|
||||
1.. => ProcedureConfigID::new(procedure_id as u32).ok(),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let Some(player_lock) = state.player_mgr.get_player(uid).await else {
|
||||
return Ok(String::from("player not found"));
|
||||
};
|
||||
|
||||
let session_id = {
|
||||
let mut player = player_lock.lock().await;
|
||||
player.basic_data_model.beginner_procedure_id = procedure_id;
|
||||
|
||||
player.current_session_id()
|
||||
};
|
||||
|
||||
if session_id.is_none() {
|
||||
state.player_mgr.save_and_remove(uid).await;
|
||||
}
|
||||
|
||||
Ok(format!(
|
||||
"successfully changed procedure_id to {procedure_id:?}"
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn kick(
|
||||
args: ArgSlice<'_>,
|
||||
state: &ServerState,
|
||||
) -> Result<String, Box<dyn std::error::Error>> {
|
||||
const USAGE: &str = "Usage: player kick [player_uid]";
|
||||
|
||||
if args.len() > 2 {
|
||||
return Ok(USAGE.to_string());
|
||||
}
|
||||
|
||||
let uid = args[0].parse::<u32>()?;
|
||||
let default_reason = DisconnectReason::ServerKick.into();
|
||||
let reason = match args.get(1) {
|
||||
Some(arg) => match arg.parse::<i32>() {
|
||||
Ok(val) => val,
|
||||
Err(_err) => default_reason,
|
||||
},
|
||||
None => default_reason,
|
||||
};
|
||||
let reason_str = match DisconnectReason::try_from(reason) {
|
||||
Ok(converted_enum) => converted_enum.as_str_name().to_owned(),
|
||||
Err(_err) => reason.to_string(),
|
||||
};
|
||||
|
||||
let Some(player_lock) = state.player_mgr.get_player(uid).await else {
|
||||
return Ok(String::from("player not found"));
|
||||
};
|
||||
|
||||
let session_id = player_lock.lock().await.current_session_id();
|
||||
|
||||
if let Some(session) = session_id.map(|id| state.session_mgr.get(id)).flatten() {
|
||||
session
|
||||
.notify(DisconnectScNotify { reason: reason })
|
||||
.await?;
|
||||
tokio::time::sleep(tokio::time::Duration::from_millis(50)).await;
|
||||
session.shutdown().await?;
|
||||
Ok(format!("kicked player, uid: {uid}, reason: {reason_str}"))
|
||||
} else {
|
||||
Ok(format!("player uid: {uid} is not online yet."))
|
||||
}
|
||||
}
|
|
@ -19,7 +19,9 @@ impl Default for NapGSConfig {
|
|||
database_credentials: DatabaseCredentials::default(),
|
||||
assets: AssetsConfig {
|
||||
filecfg_path: String::from("assets/FileCfg"),
|
||||
event_config_path: String::from("assets/EventConfig"),
|
||||
usm_keys_path: String::from("assets/VideoUSMEncKeys.json"),
|
||||
gacha_config_path: String::from("assets/GachaConfig"),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use crate::logic::{EOperator, ESystem};
|
||||
use crate::logic::{game::LogicError, EOperator, ESystem};
|
||||
|
||||
use super::*;
|
||||
|
||||
use data::tables;
|
||||
use data::tables::{self, PostGirlConfigID, QuickFuncID};
|
||||
|
||||
pub async fn on_get_tips_info(
|
||||
_session: &NetSession,
|
||||
|
@ -12,7 +12,7 @@ pub async fn on_get_tips_info(
|
|||
Ok(GetTipsInfoScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
tips_info: Some(TipsInfo::default()),
|
||||
ofolagfmcmo: req.ofolagfmcmo, // tips group type
|
||||
r#type: req.r#type, // tips group type
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -21,23 +21,34 @@ pub async fn on_get_client_systems_info(
|
|||
player: &mut Player,
|
||||
_req: GetClientSystemsInfoCsReq,
|
||||
) -> NetResult<GetClientSystemsInfoScRsp> {
|
||||
let mut post_girl_data = PostGirlData {
|
||||
post_girl_list: tables::post_girl_config_template_tb::iter()
|
||||
.map(|template| PostGirlItem {
|
||||
template_id: template.id.value(),
|
||||
unlock_time: 1720052644,
|
||||
})
|
||||
.collect(),
|
||||
..Default::default()
|
||||
};
|
||||
if let Some(post_girl_id) = player.basic_data_model.selected_post_girl_id {
|
||||
post_girl_data
|
||||
.selected_post_girl_id_list
|
||||
.push(post_girl_id.value());
|
||||
}
|
||||
|
||||
Ok(GetClientSystemsInfoScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
info: Some(ClientSystemsInfo {
|
||||
post_girl_data: Some(PostGirlData {
|
||||
selected_post_girl_id_list: tables::post_girl_config_template_tb::iter()
|
||||
.map(|template| template.id)
|
||||
.collect(),
|
||||
post_girl_list: tables::post_girl_config_template_tb::iter()
|
||||
.map(|template| PostGirlItem {
|
||||
template_id: template.id,
|
||||
unlock_time: 1000,
|
||||
})
|
||||
post_girl_data: Some(post_girl_data),
|
||||
unlock_data: Some(player.lock_model.to_client()),
|
||||
calling_card_data: Some(CallingCardData::default()),
|
||||
teleport_data: Some(TeleportData {
|
||||
unlock_id_list: tables::teleport_config_template_tb::iter()
|
||||
.filter(|template| template.client_visible > 0)
|
||||
.map(|template| template.teleport_id.value() as i32)
|
||||
.collect(),
|
||||
..Default::default()
|
||||
}),
|
||||
unlock_data: Some(player.lock_model.to_client()),
|
||||
hbhfjgbahgf: Some(Aboegnnepmi::default()),
|
||||
..Default::default()
|
||||
}),
|
||||
})
|
||||
|
@ -54,6 +65,16 @@ pub async fn on_get_news_stand_data(
|
|||
})
|
||||
}
|
||||
|
||||
pub async fn on_news_stand_seen(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
_req: NewsStandSeenCsReq,
|
||||
) -> NetResult<NewsStandSeenScRsp> {
|
||||
Ok(NewsStandSeenScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_get_trashbin_hermit_data(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
|
@ -124,6 +145,22 @@ pub async fn on_player_operation(
|
|||
})
|
||||
}
|
||||
|
||||
pub async fn on_player_system_parameter_change(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
req: PlayerSystemParameterChangeCsReq,
|
||||
) -> NetResult<PlayerSystemParameterChangeScRsp> {
|
||||
tracing::info!(
|
||||
"PlayerSystemParameterChange(type={}, param={})",
|
||||
req.r#type,
|
||||
req.params,
|
||||
);
|
||||
|
||||
Ok(PlayerSystemParameterChangeScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_pop_up_window_seen(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
|
@ -157,3 +194,62 @@ pub async fn on_interact_with_scene_object(
|
|||
retcode: Retcode::RetSucc.into(),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_mod_quick_menu(
|
||||
session: &NetSession,
|
||||
player: &mut Player,
|
||||
req: ModQuickMenuCsReq,
|
||||
) -> NetResult<ModQuickMenuScRsp> {
|
||||
req.quick_access_data_list.iter().for_each(|data| {
|
||||
player
|
||||
.lock_model
|
||||
.mod_quick_access(data.quick_access_index, QuickFuncID::new(data.btn_id).ok())
|
||||
});
|
||||
|
||||
session
|
||||
.notify(PlayerSyncScNotify {
|
||||
client_systems_sync: Some(ClientSystemsSync {
|
||||
quick_access_data_list: player.lock_model.quick_access_to_client(),
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
})
|
||||
.await?;
|
||||
|
||||
Ok(ModQuickMenuScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_change_post_girl(
|
||||
session: &NetSession,
|
||||
player: &mut Player,
|
||||
req: ChangePostGirlCsReq,
|
||||
) -> NetResult<ChangePostGirlScRsp> {
|
||||
let post_girl_id = *req
|
||||
.new_selected_post_girl_id_list
|
||||
.get(0)
|
||||
.ok_or(Retcode::RetFail)?;
|
||||
|
||||
let post_girl_id = PostGirlConfigID::new(post_girl_id).map_err(LogicError::from)?;
|
||||
|
||||
player.basic_data_model.selected_post_girl_id = Some(post_girl_id);
|
||||
session
|
||||
.notify(PlayerSyncScNotify {
|
||||
client_systems_sync: Some(ClientSystemsSync {
|
||||
post_girl_data: Some(PostGirlSync {
|
||||
selected_post_girl_id_list: vec![post_girl_id.value()],
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
})
|
||||
.await?;
|
||||
|
||||
Ok(ChangePostGirlScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
|
|
25
nap_gameserver/src/handlers/event_graph.rs
Normal file
25
nap_gameserver/src/handlers/event_graph.rs
Normal file
|
@ -0,0 +1,25 @@
|
|||
use crate::logic::ENPCInteraction;
|
||||
|
||||
use super::*;
|
||||
|
||||
pub async fn on_run_event_graph(
|
||||
session: &NetSession,
|
||||
_player: &mut Player,
|
||||
req: RunEventGraphCsReq,
|
||||
) -> NetResult<RunEventGraphScRsp> {
|
||||
session
|
||||
.notify(UpdateEventGraphScNotify {
|
||||
owner_type: req.owner_type,
|
||||
tag: req.tag,
|
||||
ddiamibnibg: req.ddiamibnibg,
|
||||
npc_interaction: ENPCInteraction::OnInteract.to_string(),
|
||||
ppabhkhbalm: true,
|
||||
gainclnemhc: req.owner_id,
|
||||
..Default::default()
|
||||
})
|
||||
.await?;
|
||||
|
||||
Ok(RunEventGraphScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
})
|
||||
}
|
|
@ -1,13 +1,235 @@
|
|||
use data::{
|
||||
gacha::{
|
||||
gacha_config::{CharacterGachaPool, GachaAddedItemType},
|
||||
global_gacha_config,
|
||||
},
|
||||
tables::{AvatarBaseID, ItemID, WeaponID},
|
||||
};
|
||||
use proto::{GainItemInfo, GetGachaDataScRsp};
|
||||
|
||||
use super::*;
|
||||
use crate::{
|
||||
handlers::core::NetError,
|
||||
logic::{item::ItemModel, role::RoleModel},
|
||||
};
|
||||
use chrono::{DateTime, Local};
|
||||
|
||||
pub async fn on_get_gacha_data(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
req: GetGachaDataCsReq,
|
||||
) -> NetResult<GetGachaDataScRsp> {
|
||||
Ok(GetGachaDataScRsp {
|
||||
if req.gacha_type != 3 {
|
||||
// tracing::info!("non-supported gacha type {}", body.gacha_type);
|
||||
Ok(GetGachaDataScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
gacha_type: req.gacha_type,
|
||||
gacha_data: Some(GachaData::default()),
|
||||
})
|
||||
} else {
|
||||
// tracing::info!("construct gacha info");
|
||||
Ok(GetGachaDataScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
gacha_type: req.gacha_type,
|
||||
gacha_data: Some(_player.gacha_model.to_client(&Local::now())),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn on_do_gacha(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
req: DoGachaCsReq,
|
||||
) -> NetResult<DoGachaScRsp> {
|
||||
let gachaconf = global_gacha_config();
|
||||
let gacha_model = &mut _player.gacha_model;
|
||||
let item_model = &mut _player.item_model;
|
||||
let role_model = &mut _player.role_model;
|
||||
let pull_time = Local::now();
|
||||
let target_pool = get_gacha_pool(
|
||||
&gachaconf.character_gacha_pool_list,
|
||||
&req.gacha_parent_schedule_id,
|
||||
&pull_time,
|
||||
)?;
|
||||
|
||||
// tracing::info!("cost_item_count: {}", req.cost_item_count);
|
||||
let pull_count = if req.cost_item_count > 1 { 10 } else { 1 };
|
||||
let mut cost_count = gacha_model.get_actual_cost_count(target_pool, &pull_count);
|
||||
if pull_count != req.cost_item_count {
|
||||
tracing::info!(
|
||||
"refuse gacha because: expected cost item {cost_count}, found {}",
|
||||
req.cost_item_count
|
||||
);
|
||||
return Err(NetError::from(Retcode::RetFail));
|
||||
} else {
|
||||
// TODO: cost resource
|
||||
}
|
||||
|
||||
let mut gain_item_list: Vec<GainItemInfo> = vec![];
|
||||
while cost_count > 0 {
|
||||
let pull_result = gacha_model.perform_pull_pool(&pull_time, target_pool);
|
||||
|
||||
let uid = add_item(
|
||||
role_model,
|
||||
item_model,
|
||||
&pull_result.obtained_item_id,
|
||||
&pull_result.item_type,
|
||||
)?;
|
||||
let (mut extra_item_id, mut extra_item_count) = (0, 0);
|
||||
if let Some(extra_resources) = &pull_result.extra_resources {
|
||||
(extra_item_id, extra_item_count) = (
|
||||
extra_resources.extra_item_id.value(),
|
||||
extra_resources.extra_item_count.clone(),
|
||||
);
|
||||
item_model.add_resource(extra_item_id, extra_item_count);
|
||||
}
|
||||
gain_item_list.push(GainItemInfo {
|
||||
item_id: pull_result.obtained_item_id.value(),
|
||||
extra_item_id,
|
||||
extra_item_count,
|
||||
uid,
|
||||
num: 1,
|
||||
..GainItemInfo::default()
|
||||
});
|
||||
cost_count -= 1;
|
||||
gacha_model.gacha_records.push(pull_result);
|
||||
}
|
||||
|
||||
_session
|
||||
.notify(construct_sync(role_model, item_model))
|
||||
.await?;
|
||||
Ok(DoGachaScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
gacha_type: req.gacha_type,
|
||||
gacha_data: Some(GachaData::default()),
|
||||
gain_item_list,
|
||||
gacha_data: Some(gacha_model.to_client(&pull_time)),
|
||||
cost_item_count: req.cost_item_count,
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_gacha_free_agent(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
req: GachaFreeAgentCsReq,
|
||||
) -> NetResult<GachaFreeAgentScRsp> {
|
||||
let gachaconf = global_gacha_config();
|
||||
let gacha_model = &mut _player.gacha_model;
|
||||
let role_model = &mut _player.role_model;
|
||||
let item_model = &mut _player.item_model;
|
||||
let pull_time = Local::now();
|
||||
let target_pool = get_gacha_pool(
|
||||
&gachaconf.character_gacha_pool_list,
|
||||
&req.gacha_parent_schedule_id,
|
||||
&pull_time,
|
||||
)?;
|
||||
|
||||
let item_id = ItemID::new(req.avatar_id);
|
||||
if item_id.is_err() {
|
||||
return Err(NetError::from(Retcode::RetFail));
|
||||
}
|
||||
let item_id = item_id.unwrap();
|
||||
|
||||
let item_type = gacha_model.request_free_agent(target_pool, &item_id);
|
||||
if item_type == GachaAddedItemType::None {
|
||||
return Err(NetError::from(Retcode::RetFail));
|
||||
}
|
||||
let _ = add_item(role_model, item_model, &item_id, &item_type);
|
||||
|
||||
_session
|
||||
.notify(construct_sync(role_model, item_model))
|
||||
.await?;
|
||||
Ok(GachaFreeAgentScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_choose_gacha_up(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
req: ChooseGachaUpCsReq,
|
||||
) -> NetResult<ChooseGachaUpScRsp> {
|
||||
let gachaconf = global_gacha_config();
|
||||
let gacha_model = &mut _player.gacha_model;
|
||||
let pull_time = Local::now();
|
||||
let target_pool = get_gacha_pool(
|
||||
&gachaconf.character_gacha_pool_list,
|
||||
&req.gacha_parent_schedule_id,
|
||||
&pull_time,
|
||||
)?;
|
||||
|
||||
let item_id = ItemID::new(req.item_id);
|
||||
if item_id.is_err() {
|
||||
return Err(NetError::from(Retcode::RetFail));
|
||||
}
|
||||
let item_id = item_id.unwrap();
|
||||
|
||||
Ok(ChooseGachaUpScRsp {
|
||||
retcode: if gacha_model.choose_gacha_up(target_pool, &item_id) {
|
||||
Retcode::RetSucc.into()
|
||||
} else {
|
||||
Retcode::RetFail.into()
|
||||
},
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
|
||||
fn get_gacha_pool<'conf>(
|
||||
character_gacha_pool_list: &'conf Vec<CharacterGachaPool>,
|
||||
gacha_parent_schedule_id: &u32,
|
||||
pull_time: &DateTime<Local>,
|
||||
) -> NetResult<&'conf CharacterGachaPool> {
|
||||
for target_pool in character_gacha_pool_list.iter() {
|
||||
if &target_pool.gacha_parent_schedule_id == gacha_parent_schedule_id
|
||||
&& target_pool.is_still_open(pull_time)
|
||||
{
|
||||
return Ok(target_pool);
|
||||
}
|
||||
}
|
||||
tracing::info!(
|
||||
"refuse gacha op because: pool of parent_schedule_id {} not found or isn't in open time",
|
||||
gacha_parent_schedule_id
|
||||
);
|
||||
Err(NetError::from(Retcode::RetFail))
|
||||
}
|
||||
|
||||
/// Return is item UID (weapon specific)
|
||||
fn add_item(
|
||||
role_model: &mut RoleModel,
|
||||
item_model: &mut ItemModel,
|
||||
item_id: &ItemID,
|
||||
item_type: &GachaAddedItemType,
|
||||
) -> NetResult<u32> {
|
||||
match item_type {
|
||||
GachaAddedItemType::Character => match AvatarBaseID::new(item_id.value()) {
|
||||
Ok(avatar_id) => {
|
||||
role_model.add_avatar(avatar_id);
|
||||
Ok(0)
|
||||
}
|
||||
Err(_) => {
|
||||
tracing::info!("add item failed for avatar id {item_id}");
|
||||
Err(NetError::from(Retcode::RetFail))
|
||||
}
|
||||
},
|
||||
GachaAddedItemType::Weapon => match WeaponID::new(item_id.value()) {
|
||||
Ok(weapon_id) => Ok(item_model.add_weapon(weapon_id).value()),
|
||||
Err(_) => {
|
||||
tracing::info!("add item failed for weapon id {item_id}");
|
||||
Err(NetError::from(Retcode::RetFail))
|
||||
}
|
||||
},
|
||||
GachaAddedItemType::Bangboo => Ok(0),
|
||||
_ => {
|
||||
tracing::info!(
|
||||
"add item failed due to undefined item type (from {item_id}) in configuration"
|
||||
);
|
||||
Err(NetError::from(Retcode::RetFail))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn construct_sync(role_model: &RoleModel, item_model: &ItemModel) -> PlayerSyncScNotify {
|
||||
PlayerSyncScNotify {
|
||||
avatar: Some(role_model.avatar_sync()),
|
||||
item_sync: Some(item_model.item_sync()),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
use data::tables::AvatarBaseID;
|
||||
|
||||
use crate::logic::game::LogicError;
|
||||
|
||||
use super::*;
|
||||
|
||||
pub async fn on_get_item_data(
|
||||
|
@ -10,6 +14,57 @@ pub async fn on_get_item_data(
|
|||
Ok(GetItemDataScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
resource_list: item_model.resources.iter().map(|i| i.to_client()).collect(),
|
||||
weapon_list: item_model.weapons.iter().map(|w| w.to_client()).collect(),
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_weapon_dress(
|
||||
session: &NetSession,
|
||||
player: &mut Player,
|
||||
req: WeaponDressCsReq,
|
||||
) -> NetResult<WeaponDressScRsp> {
|
||||
player.dress_weapon(
|
||||
AvatarBaseID::new(req.avatar_id).map_err(LogicError::from)?,
|
||||
req.weapon_uid.into(),
|
||||
)?;
|
||||
|
||||
session
|
||||
.notify(PlayerSyncScNotify {
|
||||
avatar: Some(player.role_model.avatar_sync()),
|
||||
item_sync: Some(player.item_model.item_sync()),
|
||||
..Default::default()
|
||||
})
|
||||
.await?;
|
||||
|
||||
Ok(WeaponDressScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_weapon_un_dress(
|
||||
session: &NetSession,
|
||||
player: &mut Player,
|
||||
req: WeaponUnDressCsReq,
|
||||
) -> NetResult<WeaponUnDressScRsp> {
|
||||
let avatar_id = AvatarBaseID::new(req.avatar_id).map_err(LogicError::from)?;
|
||||
let avatar = player
|
||||
.role_model
|
||||
.avatar_list
|
||||
.iter_mut()
|
||||
.find(|a| a.template_id == avatar_id)
|
||||
.ok_or(Retcode::RetFail)?;
|
||||
|
||||
avatar.weapon_uid = None;
|
||||
|
||||
session
|
||||
.notify(PlayerSyncScNotify {
|
||||
avatar: Some(player.role_model.avatar_sync()),
|
||||
..Default::default()
|
||||
})
|
||||
.await?;
|
||||
|
||||
Ok(WeaponUnDressScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
})
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ mod client_systems;
|
|||
mod collect;
|
||||
mod daily_challenge;
|
||||
mod embattles;
|
||||
mod event_graph;
|
||||
mod fairy;
|
||||
mod friend;
|
||||
mod gacha;
|
||||
|
@ -85,7 +86,7 @@ req_handlers! {
|
|||
character_quest::GetPhotoWallData;
|
||||
month_card::GetMonthCardDayReward;
|
||||
world::EnterWorld;
|
||||
world::EnterSection;
|
||||
world::SyncHallEvent;
|
||||
world::SavePosInMainCity;
|
||||
world::WorldInitFinish;
|
||||
world::AdvanceBeginnerProcedure;
|
||||
|
@ -95,6 +96,12 @@ req_handlers! {
|
|||
world::StartTrialFightingMission;
|
||||
world::EndBattle;
|
||||
world::LeaveCurDungeon;
|
||||
world::InteractWithUnit;
|
||||
world::EnterSection;
|
||||
world::JumpPageSystem;
|
||||
world::StartHollowQuest;
|
||||
world::FinishHollowBattleEvent;
|
||||
world::LongFightProgressUpdate;
|
||||
client_systems::ReportUiLayoutPlatform;
|
||||
client_systems::PlayerOperation;
|
||||
client_systems::UnlockNewbieGroup;
|
||||
|
@ -102,6 +109,8 @@ req_handlers! {
|
|||
client_systems::PopUpWindowSeen;
|
||||
client_systems::ReportSystemSettingsChange;
|
||||
client_systems::InteractWithSceneObject;
|
||||
client_systems::PlayerSystemParameterChange;
|
||||
client_systems::NewsStandSeen;
|
||||
perform::PerformTrigger;
|
||||
perform::PerformEnd;
|
||||
perform::PerformJump;
|
||||
|
@ -109,6 +118,17 @@ req_handlers! {
|
|||
misc::GetServerTimestamp;
|
||||
misc::GetCutSceneKeyInfo;
|
||||
embattles::ReportBattleTeam;
|
||||
item::WeaponDress;
|
||||
item::WeaponUnDress;
|
||||
event_graph::RunEventGraph;
|
||||
quest::BeginArchiveBattleQuest;
|
||||
quest::FinishArchiveQuest;
|
||||
gacha::DoGacha;
|
||||
gacha::ChooseGachaUp;
|
||||
gacha::GachaFreeAgent;
|
||||
player::ModNickname;
|
||||
client_systems::ModQuickMenu;
|
||||
client_systems::ChangePostGirl;
|
||||
}
|
||||
|
||||
notify_handlers! {
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
use super::core::NetError;
|
||||
|
||||
use crate::logic::{
|
||||
game::{GameInstance, LogicError},
|
||||
procedure::ProcedureAction,
|
||||
|
@ -12,14 +10,12 @@ pub async fn on_perform_trigger(
|
|||
player: &mut Player,
|
||||
req: PerformTriggerCsReq,
|
||||
) -> NetResult<PerformTriggerScRsp> {
|
||||
let GameInstance::Fresh(fresh_game) = &mut player.game_instance else {
|
||||
return Err(NetError::from(Retcode::RetFail));
|
||||
};
|
||||
|
||||
fresh_game
|
||||
.procedure_mgr
|
||||
.on_action(ProcedureAction::PerformTrigger)
|
||||
.map_err(LogicError::from)?;
|
||||
if let GameInstance::Fresh(fresh_game) = &mut player.game_instance {
|
||||
fresh_game
|
||||
.procedure_mgr
|
||||
.on_action(ProcedureAction::PerformTrigger)
|
||||
.map_err(LogicError::from)?;
|
||||
}
|
||||
|
||||
Ok(PerformTriggerScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
|
@ -32,14 +28,12 @@ pub async fn on_perform_end(
|
|||
player: &mut Player,
|
||||
_req: PerformEndCsReq,
|
||||
) -> NetResult<PerformEndScRsp> {
|
||||
let GameInstance::Fresh(fresh_game) = &mut player.game_instance else {
|
||||
return Err(NetError::from(Retcode::RetFail));
|
||||
};
|
||||
|
||||
fresh_game
|
||||
.procedure_mgr
|
||||
.on_action(ProcedureAction::PerformEnd)
|
||||
.map_err(LogicError::from)?;
|
||||
if let GameInstance::Fresh(fresh_game) = &mut player.game_instance {
|
||||
fresh_game
|
||||
.procedure_mgr
|
||||
.on_action(ProcedureAction::PerformEnd)
|
||||
.map_err(LogicError::from)?;
|
||||
}
|
||||
|
||||
Ok(PerformEndScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use data::tables::AvatarBaseID;
|
||||
|
||||
use crate::logic::game::{GameInstance, LogicError};
|
||||
use crate::logic::procedure::ProcedureAction;
|
||||
|
||||
|
@ -20,6 +22,8 @@ pub async fn on_create_role(
|
|||
player: &mut Player,
|
||||
req: CreateRoleCsReq,
|
||||
) -> NetResult<CreateRoleScRsp> {
|
||||
let avatar_id = AvatarBaseID::new(req.avatar_id).map_err(LogicError::from)?;
|
||||
|
||||
let GameInstance::Fresh(fresh_game) = &mut player.game_instance else {
|
||||
return Err(NetError::from(Retcode::RetFail));
|
||||
};
|
||||
|
@ -29,7 +33,7 @@ pub async fn on_create_role(
|
|||
.on_action(ProcedureAction::SelectRole)
|
||||
.map_err(LogicError::from)?;
|
||||
|
||||
player.set_frontend_avatar(req.avatar_id as i32)?;
|
||||
player.set_frontend_avatar(avatar_id)?;
|
||||
|
||||
session
|
||||
.notify(PlayerSyncScNotify {
|
||||
|
@ -54,6 +58,25 @@ pub async fn on_get_player_transaction(
|
|||
})
|
||||
}
|
||||
|
||||
pub async fn on_mod_nickname(
|
||||
session: &NetSession,
|
||||
_player: &mut Player,
|
||||
_req: ModNicknameCsReq,
|
||||
) -> NetResult<ModNicknameScRsp> {
|
||||
_player.basic_data_model.nick_name = Some(_req.nick_name.to_string());
|
||||
session
|
||||
.notify(PlayerSyncScNotify {
|
||||
basic_info: Some(_player.basic_data_model.player_basic_info()),
|
||||
..Default::default()
|
||||
})
|
||||
.await?;
|
||||
|
||||
Ok(ModNicknameScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_keep_alive(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
use data::tables::{self, ArchiveBattleQuestID};
|
||||
|
||||
use crate::logic::{
|
||||
game::{GameInstance, HollowGame, LogicError},
|
||||
ELocalPlayType, EQuestType,
|
||||
};
|
||||
|
||||
use super::*;
|
||||
|
||||
pub async fn on_get_quest_data(
|
||||
|
@ -8,7 +15,24 @@ pub async fn on_get_quest_data(
|
|||
Ok(GetQuestDataScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
quest_type: req.quest_type,
|
||||
quest_data: Some(QuestData::default()),
|
||||
quest_data: Some(QuestData {
|
||||
quest_collection_list: vec![
|
||||
QuestCollection {
|
||||
quest_type: EQuestType::ArchiveFile as u32,
|
||||
quest_id_list: tables::archive_file_quest_template_tb::iter()
|
||||
.map(|tmpl| tmpl.id.value())
|
||||
.collect(),
|
||||
..Default::default()
|
||||
},
|
||||
QuestCollection {
|
||||
quest_type: EQuestType::Hollow as u32,
|
||||
quest_id_list: tables::hollow_quest_template_tb::iter()
|
||||
.map(|tmpl| tmpl.id.value())
|
||||
.collect(),
|
||||
..Default::default()
|
||||
},
|
||||
],
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -19,7 +43,22 @@ pub async fn on_get_yorozuya_info(
|
|||
) -> NetResult<GetYorozuyaInfoScRsp> {
|
||||
Ok(GetYorozuyaInfoScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
yorozuya_info: Some(YorozuyaInfo::default()),
|
||||
yorozuya_info: Some(YorozuyaInfo {
|
||||
odohdljfdlf: vec![1000, 1001, 1002, 1003, 1004],
|
||||
apmojjlcooa: vec![1000, 1001, 1002, 1003, 1004],
|
||||
akiddbalfoa: vec![10010001, 10010002, 10010004],
|
||||
npgjhahijkb: tables::hollow_config_template_tb::iter()
|
||||
.map(|tmpl| tmpl.id.value())
|
||||
.collect(),
|
||||
eoljpdnjgeg: tables::hollow_quest_template_tb::iter()
|
||||
.map(|tmpl| Ofhlkjeakif {
|
||||
nnkcanmllod: tmpl.id.value(),
|
||||
kkjlnkehddj: Some(Cgpajijemlj::default()),
|
||||
..Default::default()
|
||||
})
|
||||
.collect(),
|
||||
..Default::default()
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -30,6 +69,54 @@ pub async fn on_get_archive_info(
|
|||
) -> NetResult<GetArchiveInfoScRsp> {
|
||||
Ok(GetArchiveInfoScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
archive_info: Some(ArchiveInfo::default()),
|
||||
archive_info: Some(ArchiveInfo {
|
||||
hollow_archive_id_list: (1..99999).collect(),
|
||||
videotaps_info: tables::archive_file_quest_template_tb::iter()
|
||||
.map(|tmpl| VideotapeInfo {
|
||||
archive_file_id: tmpl.id.value(),
|
||||
finished: true,
|
||||
..Default::default()
|
||||
})
|
||||
.collect(),
|
||||
..Default::default()
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_begin_archive_battle_quest(
|
||||
session: &NetSession,
|
||||
player: &mut Player,
|
||||
req: BeginArchiveBattleQuestCsReq,
|
||||
) -> NetResult<BeginArchiveBattleQuestScRsp> {
|
||||
let quest_id = ArchiveBattleQuestID::new(req.quest_id).map_err(LogicError::from)?;
|
||||
|
||||
player.game_instance = GameInstance::Hollow(
|
||||
HollowGame::create_archive_battle(
|
||||
quest_id,
|
||||
ELocalPlayType::ArchiveBattle,
|
||||
&req.avatars,
|
||||
req.buddy_id,
|
||||
)
|
||||
.map_err(LogicError::from)?,
|
||||
);
|
||||
|
||||
let world_init_notify = player.game_instance.create_world_init_notify()?;
|
||||
session.notify(world_init_notify).await?;
|
||||
|
||||
Ok(BeginArchiveBattleQuestScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
quest_id: req.quest_id,
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_finish_archive_quest(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
req: FinishArchiveQuestCsReq,
|
||||
) -> NetResult<FinishArchiveQuestScRsp> {
|
||||
Ok(FinishArchiveQuestScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
quest_id: req.quest_id,
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,7 +1,14 @@
|
|||
use data::{
|
||||
event,
|
||||
tables::{HollowQuestID, ProcedureConfigID, SectionConfigID, TrainingQuestID},
|
||||
};
|
||||
|
||||
use super::core::NetError;
|
||||
|
||||
use crate::{
|
||||
logic::{game::*, procedure::ProcedureAction, ELocalPlayType},
|
||||
logic::{
|
||||
game::*, procedure::ProcedureAction, EHollowQuestType, ELocalPlayType, ENPCInteraction,
|
||||
},
|
||||
net::NetSessionState,
|
||||
};
|
||||
|
||||
|
@ -14,10 +21,8 @@ pub async fn on_enter_world(
|
|||
) -> NetResult<EnterWorldScRsp> {
|
||||
session.set_state(NetSessionState::EndBasicsReq);
|
||||
|
||||
if player.basic_data_model.beginner_procedure_id != -1 {
|
||||
player.game_instance = GameInstance::Fresh(FreshGame::new(
|
||||
player.basic_data_model.beginner_procedure_id,
|
||||
))
|
||||
if let Some(procedure_id) = player.basic_data_model.beginner_procedure_id {
|
||||
player.game_instance = GameInstance::Fresh(FreshGame::new(procedure_id))
|
||||
} else {
|
||||
player.init_frontend_game()?;
|
||||
}
|
||||
|
@ -41,9 +46,12 @@ pub async fn on_advance_beginner_procedure(
|
|||
return Err(NetError::from(Retcode::RetFail));
|
||||
};
|
||||
|
||||
let procedure_id =
|
||||
ProcedureConfigID::new(req.procedure_id as u32).map_err(LogicError::from)?;
|
||||
|
||||
fresh_game
|
||||
.procedure_mgr
|
||||
.try_complete_procedure(req.procedure_id)
|
||||
.try_complete_procedure(procedure_id)
|
||||
.map_err(LogicError::from)?;
|
||||
|
||||
player.basic_data_model.beginner_procedure_id = fresh_game.procedure_mgr.procedure_id();
|
||||
|
@ -119,12 +127,12 @@ pub async fn on_beginner_battle_rebegin(
|
|||
})
|
||||
}
|
||||
|
||||
pub async fn on_enter_section(
|
||||
pub async fn on_sync_hall_event(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
_req: EnterSectionCsReq,
|
||||
) -> NetResult<EnterSectionScRsp> {
|
||||
Ok(EnterSectionScRsp {
|
||||
_req: SyncHallEventCsReq,
|
||||
) -> NetResult<SyncHallEventScRsp> {
|
||||
Ok(SyncHallEventScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
})
|
||||
}
|
||||
|
@ -160,8 +168,10 @@ pub async fn on_start_trial_fighting_mission(
|
|||
player: &mut Player,
|
||||
req: StartTrialFightingMissionCsReq,
|
||||
) -> NetResult<StartTrialFightingMissionScRsp> {
|
||||
let quest_id = TrainingQuestID::new(req.quest_id).map_err(LogicError::from)?;
|
||||
|
||||
player.game_instance = GameInstance::Hollow(
|
||||
HollowGame::create_training_game(req.quest_id, ELocalPlayType::TrainingRoomFight)
|
||||
HollowGame::create_training_game(quest_id, ELocalPlayType::TrainingRoomFight, &req.avatars)
|
||||
.map_err(LogicError::from)?,
|
||||
);
|
||||
|
||||
|
@ -174,10 +184,42 @@ pub async fn on_start_trial_fighting_mission(
|
|||
}
|
||||
|
||||
pub async fn on_end_battle(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
_req: EndBattleCsReq,
|
||||
session: &NetSession,
|
||||
player: &mut Player,
|
||||
req: EndBattleCsReq,
|
||||
) -> NetResult<EndBattleScRsp> {
|
||||
match &mut player.game_instance {
|
||||
GameInstance::Hollow(hollow) if hollow.quest_manager.has_active_quests() => {
|
||||
hollow
|
||||
.quest_manager
|
||||
.finish_quest(hollow.battle_event_id.value())
|
||||
.map_err(LogicError::from)?;
|
||||
|
||||
session
|
||||
.notify(DungeonQuestFinishedScNotify {
|
||||
result: req.battle_result.unwrap().result as u32,
|
||||
quest_id: hollow.quest_id,
|
||||
..Default::default()
|
||||
})
|
||||
.await?;
|
||||
}
|
||||
GameInstance::LongFight(fight) => {
|
||||
fight
|
||||
.quest_manager
|
||||
.finish_quest(fight.battle_event_id.value())
|
||||
.map_err(LogicError::from)?;
|
||||
|
||||
session
|
||||
.notify(DungeonQuestFinishedScNotify {
|
||||
result: req.battle_result.unwrap().result as u32,
|
||||
quest_id: fight.quest_id,
|
||||
..Default::default()
|
||||
})
|
||||
.await?;
|
||||
}
|
||||
_ => (),
|
||||
};
|
||||
|
||||
Ok(EndBattleScRsp {
|
||||
battle_reward: Some(BattleRewardInfo::default()),
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
|
@ -198,3 +240,132 @@ pub async fn on_leave_cur_dungeon(
|
|||
retcode: Retcode::RetSucc.into(),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_interact_with_unit(
|
||||
session: &NetSession,
|
||||
_player: &mut Player,
|
||||
req: InteractWithUnitCsReq,
|
||||
) -> NetResult<InteractWithUnitScRsp> {
|
||||
tracing::info!("interact: {req:?}");
|
||||
|
||||
if let Some(graph) = event::interacts().find(|e| e.event_id == req.interaction as u32) {
|
||||
session
|
||||
.notify(SyncEventInfoScNotify {
|
||||
owner_id: req.interaction as u32,
|
||||
npc_interaction: ENPCInteraction::OnInteract.to_string(),
|
||||
tag: req.unit_tag as u32,
|
||||
owner_type: EventGraphOwnerType::SceneUnit.into(),
|
||||
action_list: graph.actions.iter().map(|a| a.to_protocol()).collect(),
|
||||
..Default::default()
|
||||
})
|
||||
.await?;
|
||||
} else {
|
||||
tracing::warn!("no event graph for interaction: {}", req.interaction);
|
||||
}
|
||||
|
||||
Ok(InteractWithUnitScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_enter_section(
|
||||
session: &NetSession,
|
||||
player: &mut Player,
|
||||
req: EnterSectionCsReq,
|
||||
) -> NetResult<EnterSectionScRsp> {
|
||||
let section_id = SectionConfigID::new(req.section_id).map_err(LogicError::from)?;
|
||||
|
||||
player.main_city_model.switch_section(section_id);
|
||||
player.init_frontend_game()?;
|
||||
|
||||
let GameInstance::Frontend(frontend_game) = &mut player.game_instance else {
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
frontend_game.set_entry_transform(req.transform);
|
||||
|
||||
session
|
||||
.notify(player.game_instance.create_world_init_notify()?)
|
||||
.await?;
|
||||
|
||||
Ok(EnterSectionScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_jump_page_system(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
_req: JumpPageSystemCsReq,
|
||||
) -> NetResult<JumpPageSystemScRsp> {
|
||||
Ok(JumpPageSystemScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_start_hollow_quest(
|
||||
session: &NetSession,
|
||||
player: &mut Player,
|
||||
req: StartHollowQuestCsReq,
|
||||
) -> NetResult<StartHollowQuestScRsp> {
|
||||
use crate::logic::{TimePeriodType, WeatherType};
|
||||
|
||||
let quest_id = HollowQuestID::new(req.quest_id).map_err(LogicError::from)?;
|
||||
let quest_type = EHollowQuestType::from(quest_id.template().hollow_quest_type);
|
||||
|
||||
match quest_type {
|
||||
EHollowQuestType::RallyBattle => {
|
||||
player.game_instance = GameInstance::LongFight(
|
||||
LongFightGame::create_rally_game(
|
||||
quest_id,
|
||||
&req.avatars,
|
||||
req.buddy_id,
|
||||
TimePeriodType::from_str(&req.quest_time_period),
|
||||
WeatherType::from_str(&req.quest_weather),
|
||||
)
|
||||
.map_err(LogicError::from)?,
|
||||
)
|
||||
}
|
||||
_ => {
|
||||
player.game_instance = GameInstance::Hollow(
|
||||
HollowGame::create_pure_hollow_battle(
|
||||
quest_id,
|
||||
&req.avatars,
|
||||
req.buddy_id,
|
||||
TimePeriodType::from_str(&req.quest_time_period),
|
||||
WeatherType::from_str(&req.quest_weather),
|
||||
)
|
||||
.map_err(LogicError::from)?,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
let world_init_notify = player.game_instance.create_world_init_notify()?;
|
||||
session.notify(world_init_notify).await?;
|
||||
|
||||
Ok(StartHollowQuestScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
quest_id: 0,
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_finish_hollow_battle_event(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
_req: FinishHollowBattleEventCsReq,
|
||||
) -> NetResult<FinishHollowBattleEventScRsp> {
|
||||
Ok(FinishHollowBattleEventScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn on_long_fight_progress_update(
|
||||
_session: &NetSession,
|
||||
_player: &mut Player,
|
||||
_req: LongFightProgressUpdateCsReq,
|
||||
) -> NetResult<LongFightProgressUpdateScRsp> {
|
||||
Ok(LongFightProgressUpdateScRsp {
|
||||
retcode: Retcode::RetSucc.into(),
|
||||
})
|
||||
}
|
||||
|
|
67
nap_gameserver/src/logic/battle/drop/fight_drop.rs
Normal file
67
nap_gameserver/src/logic/battle/drop/fight_drop.rs
Normal file
|
@ -0,0 +1,67 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use data::tables::{BattleEventConfigID, OnceRewardID};
|
||||
use proto::{FightDropInfo, FightReward, RewardItems};
|
||||
|
||||
pub struct FightDropPool {
|
||||
special_drop: Vec<SpecialReward>,
|
||||
}
|
||||
|
||||
pub struct SpecialReward {
|
||||
pub reward_id: OnceRewardID,
|
||||
pub item_count_map: HashMap<u32, u32>,
|
||||
}
|
||||
|
||||
impl FightDropPool {
|
||||
pub fn new(battle_event_id: BattleEventConfigID) -> Self {
|
||||
let template = battle_event_id.template();
|
||||
|
||||
Self {
|
||||
special_drop: template
|
||||
.special_drop
|
||||
.iter()
|
||||
.map(|id| SpecialReward::new(*id))
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_client(&self) -> FightDropInfo {
|
||||
FightDropInfo {
|
||||
normal_drop_list: Vec::new(),
|
||||
special_drop_list: self
|
||||
.special_drop
|
||||
.iter()
|
||||
.map(SpecialReward::to_client)
|
||||
.collect(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SpecialReward {
|
||||
pub fn new(template_id: OnceRewardID) -> Self {
|
||||
let template = template_id.template();
|
||||
|
||||
Self {
|
||||
reward_id: template_id,
|
||||
item_count_map: template
|
||||
.reward_list
|
||||
.iter()
|
||||
.map(|r| (r.reward_item_id, r.reward_amount))
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_client(&self) -> FightReward {
|
||||
FightReward {
|
||||
reward_id: self.reward_id.value(),
|
||||
fight_reward_map: HashMap::from([(
|
||||
0,
|
||||
RewardItems {
|
||||
reward_item_map: self.item_count_map.clone(),
|
||||
},
|
||||
)]),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
2
nap_gameserver/src/logic/battle/drop/mod.rs
Normal file
2
nap_gameserver/src/logic/battle/drop/mod.rs
Normal file
|
@ -0,0 +1,2 @@
|
|||
mod fight_drop;
|
||||
pub use fight_drop::FightDropPool;
|
9
nap_gameserver/src/logic/battle/mod.rs
Normal file
9
nap_gameserver/src/logic/battle/mod.rs
Normal file
|
@ -0,0 +1,9 @@
|
|||
pub mod drop;
|
||||
mod quest;
|
||||
mod team;
|
||||
pub mod unit;
|
||||
mod variable;
|
||||
|
||||
pub use quest::{DungeonQuestError, DungeonQuestManager};
|
||||
pub use team::{BuddyParam, TeamDataItem};
|
||||
pub use variable::LogicVariableTable;
|
44
nap_gameserver/src/logic/battle/quest.rs
Normal file
44
nap_gameserver/src/logic/battle/quest.rs
Normal file
|
@ -0,0 +1,44 @@
|
|||
use data::tables::BattleGroupConfigID;
|
||||
use proto::DungeonQuestInfo;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct DungeonQuestManager {
|
||||
inner_quests: Vec<u32>,
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum DungeonQuestError {
|
||||
#[error("dungeon inner quest with id {0} is not active")]
|
||||
QuestNotActive(u32),
|
||||
}
|
||||
|
||||
impl DungeonQuestManager {
|
||||
pub fn new_for_battle_group(battle_group_id: BattleGroupConfigID) -> Self {
|
||||
Self {
|
||||
inner_quests: vec![battle_group_id.template().battle_event_id.value()],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn finish_quest(&mut self, quest_id: u32) -> Result<(), DungeonQuestError> {
|
||||
let idx = self
|
||||
.inner_quests
|
||||
.iter()
|
||||
.position(|id| *id == quest_id)
|
||||
.ok_or(DungeonQuestError::QuestNotActive(quest_id))?;
|
||||
|
||||
self.inner_quests.remove(idx);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn has_active_quests(&self) -> bool {
|
||||
!self.inner_quests.is_empty()
|
||||
}
|
||||
|
||||
pub fn to_client(&self) -> DungeonQuestInfo {
|
||||
DungeonQuestInfo {
|
||||
inner_quest_id_list: self.inner_quests.clone(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
34
nap_gameserver/src/logic/battle/team.rs
Normal file
34
nap_gameserver/src/logic/battle/team.rs
Normal file
|
@ -0,0 +1,34 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use crate::logic::BuddyTeamType;
|
||||
|
||||
use super::unit::{AvatarUnit, AvatarUnitID, BuddyUnit, BuddyUnitID};
|
||||
|
||||
pub struct TeamDataItem {
|
||||
pub avatar_member_list: Vec<AvatarUnit>,
|
||||
pub equipped_buddy_list: Vec<BuddyUnit>,
|
||||
}
|
||||
|
||||
pub struct BuddyParam(pub BuddyUnitID, pub BuddyTeamType);
|
||||
|
||||
impl TeamDataItem {
|
||||
pub fn new(avatars: &[AvatarUnitID], buddy_params: &[BuddyParam]) -> Self {
|
||||
Self {
|
||||
avatar_member_list: avatars
|
||||
.iter()
|
||||
.map(|id| AvatarUnit {
|
||||
avatar_id: *id,
|
||||
mp_property_override: HashMap::new(),
|
||||
})
|
||||
.collect(),
|
||||
equipped_buddy_list: buddy_params
|
||||
.iter()
|
||||
.map(|param| BuddyUnit {
|
||||
buddy_id: param.0,
|
||||
buddy_team: param.1,
|
||||
override_property_map: HashMap::new(),
|
||||
})
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
42
nap_gameserver/src/logic/battle/unit/avatar.rs
Normal file
42
nap_gameserver/src/logic/battle/unit/avatar.rs
Normal file
|
@ -0,0 +1,42 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use crate::logic::BaseProperty;
|
||||
use data::tables::{AvatarBaseID, RobotConfigID};
|
||||
use proto::AvatarUnitInfo;
|
||||
|
||||
pub struct AvatarUnit {
|
||||
pub avatar_id: AvatarUnitID,
|
||||
pub mp_property_override: HashMap<BaseProperty, i32>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum AvatarUnitID {
|
||||
Base(AvatarBaseID),
|
||||
Robot(RobotConfigID),
|
||||
}
|
||||
|
||||
impl AvatarUnitID {
|
||||
pub fn base_id(&self) -> AvatarBaseID {
|
||||
match *self {
|
||||
Self::Base(id) => id,
|
||||
Self::Robot(id) => id.template().character_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AvatarUnit {
|
||||
pub fn to_client(&self) -> AvatarUnitInfo {
|
||||
AvatarUnitInfo {
|
||||
avatar_id: match self.avatar_id {
|
||||
AvatarUnitID::Base(id) => id.value(),
|
||||
AvatarUnitID::Robot(id) => id.value(),
|
||||
},
|
||||
mp_property_override_map: self
|
||||
.mp_property_override
|
||||
.iter()
|
||||
.map(|(prop, value)| (*prop as u32, *value))
|
||||
.collect(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
44
nap_gameserver/src/logic/battle/unit/buddy.rs
Normal file
44
nap_gameserver/src/logic/battle/unit/buddy.rs
Normal file
|
@ -0,0 +1,44 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use data::tables::{BuddyBaseID, RobotBuddyConfigID};
|
||||
use proto::BuddyUnitInfo;
|
||||
|
||||
use crate::logic::{BaseProperty, BuddyTeamType};
|
||||
|
||||
pub struct BuddyUnit {
|
||||
pub buddy_id: BuddyUnitID,
|
||||
pub buddy_team: BuddyTeamType,
|
||||
pub override_property_map: HashMap<BaseProperty, i32>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum BuddyUnitID {
|
||||
Base(BuddyBaseID),
|
||||
Robot(RobotBuddyConfigID),
|
||||
}
|
||||
|
||||
impl BuddyUnitID {
|
||||
pub fn base_id(&self) -> BuddyBaseID {
|
||||
match *self {
|
||||
Self::Base(id) => id,
|
||||
Self::Robot(id) => id.template().buddy_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BuddyUnit {
|
||||
pub fn to_client(&self) -> BuddyUnitInfo {
|
||||
BuddyUnitInfo {
|
||||
buddy_id: match self.buddy_id {
|
||||
BuddyUnitID::Base(id) => id.value(),
|
||||
BuddyUnitID::Robot(id) => id.value(),
|
||||
},
|
||||
r#type: self.buddy_team.to_protocol().into(),
|
||||
mp_property_override_map: self
|
||||
.override_property_map
|
||||
.iter()
|
||||
.map(|(prop, value)| (*prop as u32, *value))
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
5
nap_gameserver/src/logic/battle/unit/mod.rs
Normal file
5
nap_gameserver/src/logic/battle/unit/mod.rs
Normal file
|
@ -0,0 +1,5 @@
|
|||
mod avatar;
|
||||
mod buddy;
|
||||
|
||||
pub use avatar::{AvatarUnit, AvatarUnitID};
|
||||
pub use buddy::{BuddyUnit, BuddyUnitID};
|
74
nap_gameserver/src/logic/battle/variable.rs
Normal file
74
nap_gameserver/src/logic/battle/variable.rs
Normal file
|
@ -0,0 +1,74 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use data::tables::{self, BattleEventConfigID, VariableDataID, VariableValueType};
|
||||
use proto::FightVariable;
|
||||
|
||||
pub struct LogicVariableTable {
|
||||
variable_map: HashMap<String, LogicVariable>,
|
||||
}
|
||||
|
||||
impl LogicVariableTable {
|
||||
pub fn new(battle_event_id: BattleEventConfigID) -> Self {
|
||||
let event_id = battle_event_id.value();
|
||||
|
||||
Self {
|
||||
variable_map: tables::variable_data_template_tb::iter()
|
||||
.filter(|tmpl| tmpl.battle_event_id == event_id)
|
||||
.map(|tmpl| (tmpl.variable_name.clone(), LogicVariable::new(tmpl.id)))
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_client(&self) -> HashMap<String, FightVariable> {
|
||||
self.variable_map
|
||||
.iter()
|
||||
.map(|(name, var)| (name.clone(), var.to_client()))
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
pub enum LogicVariable {
|
||||
Int(i64),
|
||||
Float(f64),
|
||||
Bool(bool),
|
||||
}
|
||||
|
||||
impl LogicVariable {
|
||||
pub fn new(id: VariableDataID) -> Self {
|
||||
let template = id.template();
|
||||
|
||||
match template.value_type {
|
||||
VariableValueType::Int => Self::Int(template.initial_value.parse().unwrap_or_default()),
|
||||
VariableValueType::Bool => Self::Bool(
|
||||
template
|
||||
.initial_value
|
||||
.to_lowercase()
|
||||
.parse()
|
||||
.unwrap_or_default(),
|
||||
),
|
||||
VariableValueType::Float => {
|
||||
Self::Float(template.initial_value.parse().unwrap_or_default())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_client(&self) -> FightVariable {
|
||||
match self {
|
||||
Self::Int(val) => FightVariable {
|
||||
r#type: 1,
|
||||
int_value: *val,
|
||||
..Default::default()
|
||||
},
|
||||
Self::Bool(val) => FightVariable {
|
||||
r#type: 4,
|
||||
int_value: *val as i64,
|
||||
..Default::default()
|
||||
},
|
||||
Self::Float(val) => FightVariable {
|
||||
r#type: 2,
|
||||
float_value: *val,
|
||||
..Default::default()
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,6 +12,43 @@ pub enum ESceneType {
|
|||
Fight = 3,
|
||||
Fresh = 4,
|
||||
MultiFight = 5,
|
||||
LongFight = 7,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
#[repr(u32)]
|
||||
pub enum EQuestType {
|
||||
ArchiveFile = 1,
|
||||
DungeonInner = 2,
|
||||
Hollow = 3,
|
||||
Manual = 4,
|
||||
MainCity = 5,
|
||||
HollowChallenge = 6,
|
||||
ArchiveBattle = 7,
|
||||
Knowledge = 8,
|
||||
Daily = 9,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy, FromPrimitive)]
|
||||
#[repr(u32)]
|
||||
pub enum EHollowQuestType {
|
||||
ChallengeChaos = 6,
|
||||
BossRushBattle = 14,
|
||||
World = 8,
|
||||
MainQuest = 1,
|
||||
SideQuest = 2,
|
||||
#[default]
|
||||
Common = 0,
|
||||
Challenge = 5,
|
||||
PromoteBattle = 11,
|
||||
DifficutyBattle = 12,
|
||||
AvatarSide = 7,
|
||||
RallyBattle = 13,
|
||||
Urgent = 3,
|
||||
UrgentSupplement = 4,
|
||||
NormalBattle = 10,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, PartialEq, Eq, Clone, Copy, FromPrimitive)]
|
||||
|
@ -88,6 +125,17 @@ pub enum TimePeriodType {
|
|||
Night = 2,
|
||||
}
|
||||
|
||||
impl TimePeriodType {
|
||||
pub fn from_str(s: &str) -> Self {
|
||||
match s {
|
||||
"Morning" => Self::Morning,
|
||||
"Evening" => Self::Evening,
|
||||
"Night" => Self::Night,
|
||||
_ => Self::Morning,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for TimePeriodType {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
std::fmt::Debug::fmt(self, f)
|
||||
|
@ -108,12 +156,44 @@ pub enum WeatherType {
|
|||
None = 0xFFFFFFFF,
|
||||
}
|
||||
|
||||
impl WeatherType {
|
||||
pub fn from_str(s: &str) -> Self {
|
||||
match s {
|
||||
"SunShine" => Self::SunShine,
|
||||
"Fog" => Self::Fog,
|
||||
"Cloudy" => Self::Cloudy,
|
||||
"Rain" => Self::Rain,
|
||||
"Thunder" => Self::Thunder,
|
||||
"ThickFog" => Self::ThickFog,
|
||||
"ThickCloudy" => Self::ThickCloudy,
|
||||
_ => Self::SunShine,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for WeatherType {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
std::fmt::Debug::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[repr(u32)]
|
||||
pub enum ENPCInteraction {
|
||||
OnStart = 0,
|
||||
OnEnd = 1,
|
||||
OnInteract = 2,
|
||||
OnAddInteract = 3,
|
||||
OnRemoveInteract = 4,
|
||||
}
|
||||
|
||||
impl Display for ENPCInteraction {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
std::fmt::Debug::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, Copy)]
|
||||
pub enum ELocalPlayType {
|
||||
TrainingRoom = 290,
|
||||
|
@ -142,3 +222,108 @@ pub enum ELocalPlayType {
|
|||
#[default]
|
||||
Unknown = 0,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
#[repr(u32)]
|
||||
pub enum BaseProperty {
|
||||
CurHP = 0,
|
||||
MaxHpFinal = 36,
|
||||
AddedDamageRatioFire = 52,
|
||||
AddedDamageRatioElecBattle = 583,
|
||||
FeverGetRatio = 45,
|
||||
AtkBattle = 560,
|
||||
MaxArmor = 18,
|
||||
ElementMysteryBattle = 577,
|
||||
DamageTakeRatio = 42,
|
||||
Defence = 3,
|
||||
CritRes = 23,
|
||||
MaxShield = 20,
|
||||
CritDmgBattle = 565,
|
||||
DamageTakeRatioBattle = 573,
|
||||
BreakStunBattle = 561,
|
||||
AddedElementAccumulationRatio = 48,
|
||||
CurSP = 7,
|
||||
DefBattle = 562,
|
||||
CritResBattle = 564,
|
||||
CritDmg = 6,
|
||||
ElementMystery = 46,
|
||||
AddedDamageRatioEtherBattle = 584,
|
||||
EnduranceBattle = 569,
|
||||
CritBattle = 563,
|
||||
CurBuddyBattery = 56,
|
||||
MaxHP = 1,
|
||||
CurBreakPoint = 27,
|
||||
Unknown = 4294967295,
|
||||
SPRecover = 31,
|
||||
PenRatio = 21,
|
||||
ResistBreakLevel = 35,
|
||||
CritDmgRes = 24,
|
||||
AddedDamageRatioPhysics = 51,
|
||||
AddedDamageRatioFireBattle = 581,
|
||||
AddedDamageRatioBattle = 572,
|
||||
PenDelta = 22,
|
||||
AutoRecoverStunRate = 37,
|
||||
AddedDamageRatioIce = 53,
|
||||
SpGetRatio = 44,
|
||||
MaxBuddyBattery = 57,
|
||||
AddedDamageRatioEther = 55,
|
||||
HpHealRatioBattle = 571,
|
||||
AddedDamageRatioIceBattle = 582,
|
||||
Level = 49,
|
||||
ElementAbnormalPower = 50,
|
||||
StunMaxBase = 551,
|
||||
Attack = 2,
|
||||
MaxSP = 8,
|
||||
CurMaxHpHealPercent = 32,
|
||||
MaxStunRuntime = 33,
|
||||
AllDamageResistBattle = 574,
|
||||
AddedDamageRatio = 41,
|
||||
AddedElementAccumulationRatioBattle = 578,
|
||||
Custom = 10,
|
||||
Crit = 4,
|
||||
SpGetRatioBattle = 575,
|
||||
ResistBreakPoint = 28,
|
||||
AddedDamageRatioElec = 54,
|
||||
MaxStun = 12,
|
||||
HpMaxBase = 550,
|
||||
CurStun = 11,
|
||||
CurrentArmor = 17,
|
||||
HpRecoverRate = 47,
|
||||
ElementAbnormalPowerBattle = 579,
|
||||
FeverGetRatioBattle = 576,
|
||||
CritDmgResBattle = 566,
|
||||
SpRecoverBattle = 570,
|
||||
CurEndurance = 25,
|
||||
PenDeltaBattle = 568,
|
||||
AccumulationValue = 58,
|
||||
MaxEndurance = 26,
|
||||
DestroyRecoverStunRate = 38,
|
||||
HpHealRatio = 40,
|
||||
SpMaxBase = 552,
|
||||
PenRatioBattle = 567,
|
||||
AddedDamageRatioPhysicsBattle = 580,
|
||||
BreakStun = 13,
|
||||
CurrentShield = 19,
|
||||
Luck = 5,
|
||||
AllDamageResist = 43,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[repr(i32)]
|
||||
pub enum BuddyTeamType {
|
||||
RallyGuidance = 0,
|
||||
Fighting = 1,
|
||||
Assisting = 2,
|
||||
}
|
||||
|
||||
impl BuddyTeamType {
|
||||
pub fn to_protocol(&self) -> ::proto::BuddyTeamType {
|
||||
match *self {
|
||||
Self::RallyGuidance => ::proto::BuddyTeamType::RallyGuidance,
|
||||
Self::Fighting => ::proto::BuddyTeamType::Fighting,
|
||||
Self::Assisting => ::proto::BuddyTeamType::Assisting,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
440
nap_gameserver/src/logic/gacha/client_op.rs
Normal file
440
nap_gameserver/src/logic/gacha/client_op.rs
Normal file
|
@ -0,0 +1,440 @@
|
|||
use data::gacha::gacha_config::*;
|
||||
use data::gacha::global_gacha_config;
|
||||
use data::tables::ItemID;
|
||||
|
||||
use chrono::{DateTime, Local};
|
||||
use proto::{Gacha, GachaData, GachaPool, NeedItemInfo};
|
||||
use std::{
|
||||
cmp::min,
|
||||
collections::{
|
||||
hash_map::Entry::{Occupied, Vacant},
|
||||
HashSet,
|
||||
},
|
||||
};
|
||||
|
||||
use super::GachaModel;
|
||||
|
||||
impl GachaModel {
|
||||
pub fn to_client(&self, now: &DateTime<Local>) -> GachaData {
|
||||
let gachaconf = global_gacha_config();
|
||||
let mut gacha_list: Vec<Gacha> = vec![];
|
||||
for target_pool in gachaconf.character_gacha_pool_list.iter() {
|
||||
if target_pool.is_still_open(now) {
|
||||
gacha_list.push(
|
||||
self.generate_gacha_info_from_pool(target_pool, &gachaconf.common_properties),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// tracing::info!("gacha_list: {:?}", gacha_list);
|
||||
GachaData {
|
||||
random_number: 6167,
|
||||
gacha_pool: Some(GachaPool { gacha_list }),
|
||||
..GachaData::default()
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_gacha_info_from_pool(
|
||||
&self,
|
||||
target_pool: &CharacterGachaPool,
|
||||
common_properties: &GachaCommonProperties,
|
||||
) -> Gacha {
|
||||
let gachaconf = data::gacha::global_gacha_config();
|
||||
let sharing_guarantee_category_tag = &target_pool.sharing_guarantee_info_category;
|
||||
let status_bin = self
|
||||
.gacha_status_map
|
||||
.get(sharing_guarantee_category_tag)
|
||||
.unwrap();
|
||||
let pity_s = status_bin
|
||||
.rarity_status_map
|
||||
.get(&common_properties.s_item_rarity)
|
||||
.unwrap()
|
||||
.pity;
|
||||
let pity_a = status_bin
|
||||
.rarity_status_map
|
||||
.get(&common_properties.a_item_rarity)
|
||||
.unwrap()
|
||||
.pity;
|
||||
|
||||
let mut discount_ten_roll_prize: u32 = 0;
|
||||
let mut discount_avaliable_num: u32 = 0;
|
||||
let mut advanced_s_guarantee: u32 = 0;
|
||||
let mut free_select_progress: u32 = 0;
|
||||
let mut free_select_required_pull: u32 = 0;
|
||||
let mut free_select_policy: Option<&FreeSelectItem> = None;
|
||||
for discount_policy_tag in target_pool.discount_policy_tags.iter() {
|
||||
if common_properties.newcomer_advanced_s_tag == *discount_policy_tag {
|
||||
let policy = gachaconf
|
||||
.discount_policies
|
||||
.advanced_guarantee_map
|
||||
.get(discount_policy_tag)
|
||||
.unwrap();
|
||||
if status_bin
|
||||
.discount_usage_map
|
||||
.get(discount_policy_tag)
|
||||
.unwrap()
|
||||
< &policy.use_limit
|
||||
{
|
||||
advanced_s_guarantee = policy.guarantee_pity - pity_s + 1;
|
||||
}
|
||||
} else if common_properties.ten_pull_discount_tag == *discount_policy_tag {
|
||||
let policy = gachaconf
|
||||
.discount_policies
|
||||
.ten_pull_discount_map
|
||||
.get(discount_policy_tag)
|
||||
.unwrap();
|
||||
let discount_usage = status_bin
|
||||
.discount_usage_map
|
||||
.get(discount_policy_tag)
|
||||
.unwrap();
|
||||
if discount_usage < &policy.use_limit {
|
||||
discount_ten_roll_prize = policy.discounted_prize;
|
||||
discount_avaliable_num = policy.use_limit - discount_usage;
|
||||
}
|
||||
} else if gachaconf
|
||||
.discount_policies
|
||||
.free_select_map
|
||||
.contains_key(discount_policy_tag)
|
||||
{
|
||||
let policy = gachaconf
|
||||
.discount_policies
|
||||
.free_select_map
|
||||
.get(discount_policy_tag)
|
||||
.unwrap();
|
||||
let free_select_demand_idx = usize::try_from(
|
||||
*(status_bin
|
||||
.discount_usage_map
|
||||
.get(&policy.free_select_usage_record_tag)
|
||||
.unwrap()),
|
||||
)
|
||||
.unwrap();
|
||||
if policy.milestones.len() <= free_select_demand_idx {
|
||||
continue;
|
||||
}
|
||||
|
||||
let free_select_actual_progress = status_bin
|
||||
.discount_usage_map
|
||||
.get(&policy.free_select_progress_record_tag)
|
||||
.unwrap();
|
||||
free_select_policy = Some(policy);
|
||||
free_select_required_pull = policy
|
||||
.milestones
|
||||
.get(free_select_demand_idx)
|
||||
.unwrap()
|
||||
.to_owned();
|
||||
free_select_progress = min(free_select_required_pull, *free_select_actual_progress);
|
||||
}
|
||||
}
|
||||
|
||||
let mut up_s_item_list: Vec<u32> = vec![];
|
||||
let mut up_a_item_list: Vec<u32> = vec![];
|
||||
let mut free_select_item_list: Vec<u32> = vec![];
|
||||
let mut chooseable_up_list: Vec<u32> = vec![];
|
||||
let mut chosen_up_item: u32 = 0;
|
||||
let mut s_guarantee: u32 = 0;
|
||||
let mut a_guarantee: u32 = 0;
|
||||
for rarity_items in target_pool.gacha_items.iter() {
|
||||
let mut chooseable_up_included_category_tags: Option<&HashSet<String>> = None;
|
||||
let mut chooseable_policy_tag: Option<&String> = None;
|
||||
for guarantee_policy_tag in rarity_items.category_guarantee_policy_tags.iter() {
|
||||
let category_guarantee_policy = gachaconf
|
||||
.category_guarantee_policy_map
|
||||
.get(guarantee_policy_tag)
|
||||
.unwrap();
|
||||
if !category_guarantee_policy.chooseable {
|
||||
continue;
|
||||
}
|
||||
chooseable_policy_tag = Some(guarantee_policy_tag);
|
||||
chooseable_up_included_category_tags =
|
||||
Some(&category_guarantee_policy.included_category_tags);
|
||||
if let Some(item) = status_bin
|
||||
.rarity_status_map
|
||||
.get(&rarity_items.rarity)
|
||||
.unwrap()
|
||||
.categories_chosen_guarantee_item_map
|
||||
.get(guarantee_policy_tag)
|
||||
{
|
||||
chosen_up_item = item.clone();
|
||||
}
|
||||
}
|
||||
|
||||
for (category_tag, category) in rarity_items.categories.iter() {
|
||||
let probability_model = gachaconf
|
||||
.probability_model_map
|
||||
.get(&rarity_items.probability_model_tag)
|
||||
.unwrap();
|
||||
let maximum_pity = &probability_model.maximum_guarantee_pity;
|
||||
if rarity_items.rarity == common_properties.s_item_rarity {
|
||||
if category.is_promotional_items {
|
||||
up_s_item_list = category.item_ids.clone();
|
||||
}
|
||||
// tracing::info!("pity_s: {pity_s}");
|
||||
// thread 'tokio-runtime-worker' panicked at nap_gameserver\src\handlers\gacha.rs:369:31:
|
||||
// attempt to subtract with overflow
|
||||
s_guarantee = maximum_pity - min(pity_s, maximum_pity.clone()) + 1;
|
||||
}
|
||||
if rarity_items.rarity == common_properties.a_item_rarity {
|
||||
if category.is_promotional_items {
|
||||
up_a_item_list = category.item_ids.clone();
|
||||
}
|
||||
// tracing::info!("pity_a: {pity_a}");
|
||||
a_guarantee = maximum_pity - min(pity_a, maximum_pity.clone()) + 1;
|
||||
}
|
||||
|
||||
if let Some(val) = free_select_policy {
|
||||
if val.rarity == rarity_items.rarity && val.category_tags.contains(category_tag)
|
||||
{
|
||||
free_select_item_list.append(&mut category.item_ids.clone());
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(tags) = chooseable_up_included_category_tags {
|
||||
if tags.contains(category_tag) {
|
||||
chooseable_up_list.append(&mut category.item_ids.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(_priority_policy_tag) = chooseable_policy_tag {
|
||||
// if let Some(item) = status_bin
|
||||
// .rarity_status_map
|
||||
// .get(&rarity_items.rarity)
|
||||
// .unwrap()
|
||||
// .categories_chosen_guarantee_item_map
|
||||
// .get(priority_policy_tag)
|
||||
// {
|
||||
if rarity_items.rarity == gachaconf.common_properties.s_item_rarity {
|
||||
up_s_item_list = chooseable_up_list.clone();
|
||||
} else if rarity_items.rarity == gachaconf.common_properties.a_item_rarity {
|
||||
up_a_item_list = vec![];
|
||||
}
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
let need_item_info_list: Vec<NeedItemInfo> = vec![NeedItemInfo {
|
||||
need_item_id: target_pool.cost_item_id,
|
||||
need_item_count: 1,
|
||||
}];
|
||||
|
||||
let mut result = Gacha {
|
||||
gacha_schedule_id: target_pool.gacha_schedule_id,
|
||||
gacha_parent_schedule_id: target_pool.gacha_parent_schedule_id,
|
||||
gacha_type: target_pool.gacha_type,
|
||||
start_timestamp: target_pool.start_time.timestamp(),
|
||||
end_timestamp: target_pool.end_time.timestamp(),
|
||||
discount_avaliable_num,
|
||||
discount_ten_roll_prize,
|
||||
advanced_s_guarantee,
|
||||
s_guarantee,
|
||||
a_guarantee,
|
||||
need_item_info_list,
|
||||
free_select_progress,
|
||||
free_select_required_pull,
|
||||
free_select_item_list,
|
||||
chosen_up_item,
|
||||
// nammdglepbk: 563,
|
||||
// hgmcofcjmbg: 101,
|
||||
// akggbhgkifd: chooseable_up_list.clone(),
|
||||
chooseable_up_list,
|
||||
..Gacha::default()
|
||||
};
|
||||
if up_s_item_list.len() > 0 {
|
||||
result.up_s_item_list = up_s_item_list;
|
||||
}
|
||||
if up_a_item_list.len() > 0 {
|
||||
result.up_a_item_list = up_a_item_list;
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
/// Get the actual item cost count (counting discount).
|
||||
pub fn get_actual_cost_count<'bin, 'conf>(
|
||||
&'bin mut self,
|
||||
target_pool: &'conf CharacterGachaPool,
|
||||
pull_count: &u32,
|
||||
) -> u32 {
|
||||
let gachaconf = global_gacha_config();
|
||||
|
||||
if *pull_count == 10 {
|
||||
let discount_tag = &gachaconf.common_properties.ten_pull_discount_tag;
|
||||
if target_pool.discount_policy_tags.contains(&discount_tag) {
|
||||
let status_bin = self
|
||||
.gacha_status_map
|
||||
.get_mut(&target_pool.sharing_guarantee_info_category)
|
||||
.unwrap();
|
||||
let discount_policy = gachaconf
|
||||
.discount_policies
|
||||
.ten_pull_discount_map
|
||||
.get(discount_tag)
|
||||
.unwrap();
|
||||
let usage = status_bin.discount_usage_map.get_mut(discount_tag).unwrap();
|
||||
if *usage < discount_policy.use_limit {
|
||||
*usage += 1;
|
||||
return discount_policy.discounted_prize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pull_count.clone()
|
||||
}
|
||||
|
||||
pub fn request_free_agent<'bin, 'conf>(
|
||||
&'bin mut self,
|
||||
target_pool: &'conf CharacterGachaPool,
|
||||
item_id: &ItemID,
|
||||
) -> GachaAddedItemType {
|
||||
let gachaconf = global_gacha_config();
|
||||
let sharing_guarantee_category_tag = &target_pool.sharing_guarantee_info_category;
|
||||
let status_bin = self
|
||||
.gacha_status_map
|
||||
.get_mut(sharing_guarantee_category_tag)
|
||||
.unwrap();
|
||||
let item_id = item_id.value();
|
||||
|
||||
let mut free_select_policy: Option<&FreeSelectItem> = None;
|
||||
let mut free_select_progress: u32 = 0;
|
||||
let mut free_select_required_pull: u32 = 0;
|
||||
for discount_policy_tag in target_pool.discount_policy_tags.iter() {
|
||||
if gachaconf
|
||||
.discount_policies
|
||||
.free_select_map
|
||||
.contains_key(discount_policy_tag)
|
||||
{
|
||||
let policy = gachaconf
|
||||
.discount_policies
|
||||
.free_select_map
|
||||
.get(discount_policy_tag)
|
||||
.unwrap();
|
||||
let free_select_demand_idx = usize::try_from(
|
||||
*(status_bin
|
||||
.discount_usage_map
|
||||
.get(&policy.free_select_usage_record_tag)
|
||||
.unwrap()),
|
||||
)
|
||||
.unwrap();
|
||||
if policy.milestones.len() <= free_select_demand_idx {
|
||||
continue;
|
||||
}
|
||||
|
||||
let free_select_actual_progress = status_bin
|
||||
.discount_usage_map
|
||||
.get(&policy.free_select_progress_record_tag)
|
||||
.unwrap();
|
||||
free_select_policy = Some(policy);
|
||||
free_select_required_pull = policy
|
||||
.milestones
|
||||
.get(free_select_demand_idx)
|
||||
.unwrap()
|
||||
.to_owned();
|
||||
free_select_progress = min(free_select_required_pull, *free_select_actual_progress);
|
||||
}
|
||||
}
|
||||
|
||||
if let None = free_select_policy {
|
||||
tracing::info!(
|
||||
"refuse free agent because: pool of parent_schedule_id {} hasn't defined free agent discount yet (or used up chance)",
|
||||
target_pool.gacha_parent_schedule_id
|
||||
);
|
||||
return GachaAddedItemType::None;
|
||||
} else if free_select_progress < free_select_required_pull {
|
||||
tracing::info!(
|
||||
"refuse free agent because: use pulled {free_select_progress} (after last free agent) in parent_schedule_id {}, required {free_select_required_pull}",
|
||||
target_pool.gacha_parent_schedule_id
|
||||
);
|
||||
return GachaAddedItemType::None;
|
||||
}
|
||||
|
||||
let free_select_policy = free_select_policy.unwrap();
|
||||
let mut item_type: GachaAddedItemType = GachaAddedItemType::None;
|
||||
for rarity_items in target_pool.gacha_items.iter() {
|
||||
if rarity_items.rarity != free_select_policy.rarity {
|
||||
continue;
|
||||
}
|
||||
for (category_tag, category) in rarity_items.categories.iter() {
|
||||
if !free_select_policy.category_tags.contains(category_tag) {
|
||||
continue;
|
||||
}
|
||||
if category.item_ids.contains(&item_id) {
|
||||
item_type = category.item_type.clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if item_type != GachaAddedItemType::None {
|
||||
(*status_bin
|
||||
.discount_usage_map
|
||||
.get_mut(&free_select_policy.free_select_usage_record_tag)
|
||||
.unwrap()) += 1;
|
||||
(*status_bin
|
||||
.discount_usage_map
|
||||
.get_mut(&free_select_policy.free_select_progress_record_tag)
|
||||
.unwrap()) -= free_select_required_pull;
|
||||
}
|
||||
item_type
|
||||
}
|
||||
|
||||
pub fn choose_gacha_up<'bin, 'conf>(
|
||||
&'bin mut self,
|
||||
target_pool: &'conf CharacterGachaPool,
|
||||
item_id: &ItemID,
|
||||
) -> bool {
|
||||
let gachaconf = global_gacha_config();
|
||||
let item_id = item_id.value();
|
||||
for rarity_items in target_pool.gacha_items.iter() {
|
||||
for guarantee_policy_tag in rarity_items.category_guarantee_policy_tags.iter() {
|
||||
let category_guarantee_policy = gachaconf
|
||||
.category_guarantee_policy_map
|
||||
.get(guarantee_policy_tag)
|
||||
.unwrap();
|
||||
if !category_guarantee_policy.chooseable {
|
||||
continue;
|
||||
}
|
||||
let mut up_category: Option<&String> = None;
|
||||
for (category_tag, category) in rarity_items.categories.iter() {
|
||||
if category.item_ids.contains(&item_id) {
|
||||
up_category = Some(category_tag);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if let None = up_category {
|
||||
continue;
|
||||
};
|
||||
let up_category = up_category.unwrap();
|
||||
|
||||
let progress_bin = self
|
||||
.gacha_status_map
|
||||
.get_mut(&target_pool.sharing_guarantee_info_category)
|
||||
.unwrap()
|
||||
.rarity_status_map
|
||||
.get_mut(&rarity_items.rarity)
|
||||
.unwrap();
|
||||
match progress_bin
|
||||
.categories_chosen_guarantee_item_map
|
||||
.entry(guarantee_policy_tag.clone())
|
||||
{
|
||||
Occupied(mut occupied_entry) => {
|
||||
occupied_entry.insert(item_id);
|
||||
}
|
||||
Vacant(vacant_entry) => {
|
||||
vacant_entry.insert(item_id);
|
||||
}
|
||||
};
|
||||
match progress_bin
|
||||
.categories_chosen_guarantee_category_map
|
||||
.entry(up_category.clone())
|
||||
{
|
||||
Occupied(mut occupied_entry) => {
|
||||
occupied_entry.insert(up_category.clone());
|
||||
}
|
||||
Vacant(vacant_entry) => {
|
||||
vacant_entry.insert(up_category.clone());
|
||||
}
|
||||
};
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
}
|
531
nap_gameserver/src/logic/gacha/gacha_model.rs
Normal file
531
nap_gameserver/src/logic/gacha/gacha_model.rs
Normal file
|
@ -0,0 +1,531 @@
|
|||
use super::record::*;
|
||||
use super::stat::*;
|
||||
use data::gacha;
|
||||
use data::gacha::gacha_config::*;
|
||||
use data::tables::ItemID;
|
||||
|
||||
use chrono::{DateTime, Local};
|
||||
use proto::GachaModelBin;
|
||||
use rand::{thread_rng, Rng};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::hash::{BuildHasher, Hash};
|
||||
|
||||
pub struct GachaModel {
|
||||
pub gacha_status_map: HashMap<String, GachaStatus>,
|
||||
pub gacha_records: Vec<GachaRecord>,
|
||||
}
|
||||
|
||||
impl Default for GachaModel {
|
||||
fn default() -> GachaModel {
|
||||
let result = GachaModel {
|
||||
gacha_status_map: HashMap::new(),
|
||||
gacha_records: vec![],
|
||||
};
|
||||
result.post_deserialize()
|
||||
}
|
||||
}
|
||||
|
||||
impl GachaModel {
|
||||
pub fn from_bin(gacha_bin: GachaModelBin) -> Self {
|
||||
let result = Self {
|
||||
gacha_status_map: gacha_bin
|
||||
.gacha_status_map
|
||||
.into_iter()
|
||||
.map(|(k, v)| (k, GachaStatus::from_bin(v)))
|
||||
.collect(),
|
||||
gacha_records: gacha_bin
|
||||
.gacha_records
|
||||
.into_iter()
|
||||
.map(|x| GachaRecord::from_bin(x))
|
||||
.collect(),
|
||||
};
|
||||
result.post_deserialize()
|
||||
}
|
||||
|
||||
pub fn to_bin(&self) -> GachaModelBin {
|
||||
GachaModelBin {
|
||||
gacha_status_map: self
|
||||
.gacha_status_map
|
||||
.iter()
|
||||
.map(|(k, v)| (k.clone(), v.to_bin()))
|
||||
.collect(),
|
||||
gacha_records: self.gacha_records.iter().map(|x| x.to_bin()).collect(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn post_deserialize(mut self) -> GachaModel {
|
||||
let gachaconf = gacha::global_gacha_config();
|
||||
for gacha_pool in gachaconf.character_gacha_pool_list.iter() {
|
||||
let mut gacha_status_map = &mut self.gacha_status_map;
|
||||
let status_bin = get_or_add(
|
||||
&mut gacha_status_map,
|
||||
&gacha_pool.sharing_guarantee_info_category,
|
||||
);
|
||||
for rarity_items in gacha_pool.gacha_items.iter() {
|
||||
let progress_bin =
|
||||
get_or_add(&mut status_bin.rarity_status_map, &rarity_items.rarity);
|
||||
if progress_bin.pity <= 0 {
|
||||
progress_bin.pity = 1;
|
||||
}
|
||||
for category_guarantee_policy_tag in
|
||||
rarity_items.category_guarantee_policy_tags.iter()
|
||||
{
|
||||
get_or_add(
|
||||
&mut progress_bin.categories_progress_map,
|
||||
&category_guarantee_policy_tag,
|
||||
);
|
||||
|
||||
let guarantee_policy = gachaconf
|
||||
.category_guarantee_policy_map
|
||||
.get(category_guarantee_policy_tag)
|
||||
.unwrap();
|
||||
if !guarantee_policy.chooseable {
|
||||
continue;
|
||||
}
|
||||
get_or_add(
|
||||
&mut progress_bin.categories_chosen_guarantee_progress_map,
|
||||
&category_guarantee_policy_tag,
|
||||
);
|
||||
}
|
||||
}
|
||||
for discount_policy_tag in gacha_pool.discount_policy_tags.iter() {
|
||||
if gachaconf
|
||||
.discount_policies
|
||||
.free_select_map
|
||||
.contains_key(discount_policy_tag)
|
||||
{
|
||||
let policy = gachaconf
|
||||
.discount_policies
|
||||
.free_select_map
|
||||
.get(discount_policy_tag)
|
||||
.unwrap();
|
||||
get_or_add(
|
||||
&mut status_bin.discount_usage_map,
|
||||
&policy.free_select_progress_record_tag,
|
||||
);
|
||||
get_or_add(
|
||||
&mut status_bin.discount_usage_map,
|
||||
&policy.free_select_usage_record_tag,
|
||||
);
|
||||
} else {
|
||||
get_or_add(&mut status_bin.discount_usage_map, &discount_policy_tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
pub fn perform_pull_pool<'bin, 'conf>(
|
||||
&'bin mut self,
|
||||
pull_time: &DateTime<Local>,
|
||||
target_pool: &'conf CharacterGachaPool,
|
||||
) -> GachaRecord {
|
||||
let (rarity_items, progress_bin, status_bin, probability_model) =
|
||||
self.determine_rarity(target_pool);
|
||||
let (category_tag, category) =
|
||||
self.determine_category(rarity_items, progress_bin, target_pool);
|
||||
let result = determine_gacha_result(
|
||||
pull_time,
|
||||
category,
|
||||
target_pool,
|
||||
status_bin,
|
||||
progress_bin,
|
||||
rarity_items,
|
||||
);
|
||||
self.update_pity(rarity_items, probability_model, target_pool);
|
||||
self.update_category_guarantee_info(rarity_items, &category_tag, target_pool);
|
||||
self.update_discount(target_pool, &category_tag, rarity_items);
|
||||
result
|
||||
}
|
||||
|
||||
fn rand_rarity<'bin, 'conf>(
|
||||
&'bin self,
|
||||
target_pool: &'conf CharacterGachaPool,
|
||||
status_bin: &'bin GachaStatus,
|
||||
) -> (
|
||||
&'conf GachaAvailableItemsInfo,
|
||||
&'bin GachaProgress,
|
||||
&'conf ProbabilityModel,
|
||||
) {
|
||||
let gachaconf = gacha::global_gacha_config();
|
||||
let mut rng = thread_rng();
|
||||
let rarity_status_map = &status_bin.rarity_status_map;
|
||||
// gacha_items is already sorted by rarity descendingly in its post_configure.
|
||||
for rarity_items in target_pool.gacha_items.iter() {
|
||||
// Surely any judgement should be made on the current pity.
|
||||
let progress_bin = rarity_status_map.get(&rarity_items.rarity).unwrap();
|
||||
let pity = progress_bin.pity;
|
||||
let probability_model = gachaconf
|
||||
.probability_model_map
|
||||
.get(&rarity_items.probability_model_tag)
|
||||
.unwrap();
|
||||
if rng.gen_range(0.0..100.0) <= probability_model.get_chance_percent(&pity) {
|
||||
return (rarity_items, progress_bin, probability_model);
|
||||
}
|
||||
}
|
||||
panic!("The user failed to get any items.");
|
||||
}
|
||||
|
||||
fn determine_rarity<'bin, 'conf>(
|
||||
&'bin self,
|
||||
target_pool: &'conf CharacterGachaPool,
|
||||
) -> (
|
||||
&'conf GachaAvailableItemsInfo,
|
||||
&'bin GachaProgress,
|
||||
&'bin GachaStatus,
|
||||
&'conf ProbabilityModel,
|
||||
) {
|
||||
let gachaconf = gacha::global_gacha_config();
|
||||
let status_bin = self
|
||||
.gacha_status_map
|
||||
.get(&target_pool.sharing_guarantee_info_category)
|
||||
.expect(&format!(
|
||||
"post_deserialize forgot StatusBin/sharing_guarantee_info_category: {}",
|
||||
target_pool.sharing_guarantee_info_category
|
||||
));
|
||||
let (mut rarity_items, mut progress_bin, mut probability_model) =
|
||||
self.rand_rarity(target_pool, &status_bin);
|
||||
|
||||
// We should take AdvancedGuarantee discount into consideration.
|
||||
for discount_tag in target_pool.discount_policy_tags.iter() {
|
||||
if let Some(discount) = gachaconf
|
||||
.discount_policies
|
||||
.advanced_guarantee_map
|
||||
.get(discount_tag)
|
||||
{
|
||||
if discount.rarity <= rarity_items.rarity {
|
||||
continue;
|
||||
}
|
||||
if status_bin
|
||||
.discount_usage_map
|
||||
.get(discount_tag)
|
||||
.expect(&format!(
|
||||
"post_deserialize forgot StatusBin/discount_usage_map: {}",
|
||||
discount_tag
|
||||
))
|
||||
>= &discount.use_limit
|
||||
{
|
||||
continue;
|
||||
}
|
||||
let higher_progress_bin = status_bin
|
||||
.rarity_status_map
|
||||
.get(&discount.rarity)
|
||||
.expect(&format!(
|
||||
"post_deserialize forgot StatusBin/rarity_status_map: {}",
|
||||
&discount.rarity
|
||||
));
|
||||
if higher_progress_bin.pity >= discount.guarantee_pity {
|
||||
let mut found_rarity_items = false;
|
||||
for gacha_items in target_pool.gacha_items.iter() {
|
||||
if gacha_items.rarity == discount.rarity {
|
||||
rarity_items = gacha_items;
|
||||
probability_model = gachaconf
|
||||
.probability_model_map
|
||||
.get(&gacha_items.probability_model_tag)
|
||||
.unwrap();
|
||||
found_rarity_items = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert!(found_rarity_items, "Handle AdvancedGuarantee Discount ({discount_tag}) error: The target rarity does not exist in this pool.");
|
||||
progress_bin = higher_progress_bin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(rarity_items, progress_bin, status_bin, probability_model)
|
||||
}
|
||||
|
||||
fn determine_category<'bin, 'conf>(
|
||||
&'bin self,
|
||||
rarity_items: &'conf GachaAvailableItemsInfo,
|
||||
progress_bin: &'bin GachaProgress,
|
||||
target_pool: &'conf CharacterGachaPool,
|
||||
) -> (String, &'conf GachaCategoryInfo) {
|
||||
let gachaconf = gacha::global_gacha_config();
|
||||
let mut category_tag_inited = false;
|
||||
let mut category_tag_result: HashSet<String> = HashSet::new();
|
||||
// First of all, if there's a chooseable category and
|
||||
// it is SELECTED then we MUST give that category's item.
|
||||
for guarantee_policy_tag in rarity_items.category_guarantee_policy_tags.iter() {
|
||||
let category_guarantee_policy = gachaconf
|
||||
.category_guarantee_policy_map
|
||||
.get(guarantee_policy_tag)
|
||||
.unwrap();
|
||||
if !category_guarantee_policy.chooseable {
|
||||
continue;
|
||||
}
|
||||
// As we found a policy defined chooseable, we
|
||||
// should head to look whether the user chose
|
||||
// the category he want.
|
||||
if let Some(category_tag) = progress_bin
|
||||
.categories_chosen_guarantee_category_map
|
||||
.get(guarantee_policy_tag)
|
||||
{
|
||||
// User chose a category; our work are done here.
|
||||
category_tag_result.insert(category_tag.clone());
|
||||
category_tag_inited = true;
|
||||
}
|
||||
}
|
||||
// Then we should take a look at MustGainItem.
|
||||
if !category_tag_inited {
|
||||
for discount_policy_tag in target_pool.discount_policy_tags.iter() {
|
||||
if let Some(discount) = gachaconf
|
||||
.discount_policies
|
||||
.must_gain_item_map
|
||||
.get(discount_policy_tag)
|
||||
{
|
||||
if discount.rarity != rarity_items.rarity {
|
||||
continue;
|
||||
}
|
||||
category_tag_result.insert(discount.category_tag.clone());
|
||||
category_tag_inited = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Otherwise, just select as normal.
|
||||
if !category_tag_inited {
|
||||
for tag in rarity_items.categories.keys() {
|
||||
category_tag_result.insert(tag.clone());
|
||||
}
|
||||
for guarantee_policy_tag in rarity_items.category_guarantee_policy_tags.iter() {
|
||||
let category_guarantee_policy = gachaconf
|
||||
.category_guarantee_policy_map
|
||||
.get(guarantee_policy_tag)
|
||||
.unwrap();
|
||||
let failure_times = progress_bin.categories_progress_map
|
||||
.get(guarantee_policy_tag)
|
||||
.expect(&format!("post_deserialize forgot StatusBin/rarity_status_map[{}]/categories_progress_map: {}", &rarity_items.rarity, guarantee_policy_tag));
|
||||
if failure_times >= &category_guarantee_policy.trigger_on_failure_times {
|
||||
category_tag_result = category_tag_result
|
||||
.intersection(&category_guarantee_policy.included_category_tags)
|
||||
.cloned()
|
||||
.collect();
|
||||
}
|
||||
}
|
||||
// category_tag_inited = true;
|
||||
}
|
||||
|
||||
let mut categories: Vec<(String, &GachaCategoryInfo)> = vec![];
|
||||
let mut weight_sum = 0;
|
||||
for result_tag in category_tag_result {
|
||||
let category = rarity_items.categories.get(&result_tag).unwrap();
|
||||
categories.push((result_tag, category));
|
||||
weight_sum += category.category_weight;
|
||||
}
|
||||
|
||||
let randomnum = rand::thread_rng().gen_range(0..weight_sum);
|
||||
let mut enumerated_ranges_end = 0;
|
||||
for category in categories.into_iter() {
|
||||
if randomnum <= enumerated_ranges_end + category.1.category_weight {
|
||||
return (category.0, category.1);
|
||||
}
|
||||
enumerated_ranges_end += category.1.category_weight;
|
||||
}
|
||||
panic!("No category is chosen.");
|
||||
}
|
||||
|
||||
fn update_pity<'bin, 'conf>(
|
||||
&'bin mut self,
|
||||
rarity_items: &'conf GachaAvailableItemsInfo,
|
||||
probability_model: &'conf ProbabilityModel,
|
||||
target_pool: &'conf CharacterGachaPool,
|
||||
) {
|
||||
let status_bin = self
|
||||
.gacha_status_map
|
||||
.get_mut(&target_pool.sharing_guarantee_info_category)
|
||||
.unwrap();
|
||||
for (rarity, rarity_status) in status_bin.rarity_status_map.iter_mut() {
|
||||
if (rarity == &rarity_items.rarity)
|
||||
|| (probability_model.clear_status_on_higher_rarity_pulled
|
||||
&& rarity < &rarity_items.rarity)
|
||||
{
|
||||
rarity_status.pity = 1;
|
||||
} else {
|
||||
rarity_status.pity += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn update_category_guarantee_info<'bin, 'conf>(
|
||||
&'bin mut self,
|
||||
rarity_items: &'conf GachaAvailableItemsInfo,
|
||||
category_tag: &String,
|
||||
target_pool: &'conf CharacterGachaPool,
|
||||
) {
|
||||
let gachaconf = gacha::global_gacha_config();
|
||||
let status_bin = self
|
||||
.gacha_status_map
|
||||
.get_mut(&target_pool.sharing_guarantee_info_category)
|
||||
.unwrap();
|
||||
let progress_bin = status_bin
|
||||
.rarity_status_map
|
||||
.get_mut(&rarity_items.rarity)
|
||||
.unwrap();
|
||||
for policy_tag in rarity_items.category_guarantee_policy_tags.iter() {
|
||||
let policy = gachaconf
|
||||
.category_guarantee_policy_map
|
||||
.get(policy_tag)
|
||||
.unwrap();
|
||||
// TODO: Chooseable guarantee not implemented
|
||||
let prev_failure = progress_bin
|
||||
.categories_progress_map
|
||||
.get_mut(policy_tag)
|
||||
.expect(&format!(
|
||||
"post_deserialize forgot StatusBin/rarity_status_map[{}]/categories_progress_map: {}",
|
||||
rarity_items.rarity, policy_tag
|
||||
));
|
||||
if policy.included_category_tags.contains(category_tag) {
|
||||
*prev_failure = 0;
|
||||
} else {
|
||||
*prev_failure += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn update_discount<'bin, 'conf>(
|
||||
&'bin mut self,
|
||||
target_pool: &'conf CharacterGachaPool,
|
||||
category_tag: &String,
|
||||
rarity_items: &GachaAvailableItemsInfo,
|
||||
) {
|
||||
let gachaconf = gacha::global_gacha_config();
|
||||
for (policy_tag, policy) in gachaconf.discount_policies.must_gain_item_map.iter() {
|
||||
if *category_tag != policy.category_tag {
|
||||
continue;
|
||||
}
|
||||
if !target_pool.discount_policy_tags.contains(policy_tag) {
|
||||
continue;
|
||||
}
|
||||
let status_bin = self
|
||||
.gacha_status_map
|
||||
.get_mut(&target_pool.sharing_guarantee_info_category)
|
||||
.unwrap();
|
||||
let usage = status_bin.discount_usage_map.get_mut(policy_tag).unwrap();
|
||||
if *usage < policy.use_limit {
|
||||
*usage += 1;
|
||||
}
|
||||
}
|
||||
for (policy_tag, policy) in gachaconf.discount_policies.advanced_guarantee_map.iter() {
|
||||
if rarity_items.rarity != policy.rarity {
|
||||
continue;
|
||||
}
|
||||
if !target_pool.discount_policy_tags.contains(policy_tag) {
|
||||
continue;
|
||||
}
|
||||
let status_bin = self
|
||||
.gacha_status_map
|
||||
.get_mut(&target_pool.sharing_guarantee_info_category)
|
||||
.unwrap();
|
||||
let usage = status_bin.discount_usage_map.get_mut(policy_tag).unwrap();
|
||||
if *usage < policy.use_limit {
|
||||
*usage += 1;
|
||||
}
|
||||
}
|
||||
for (policy_tag, policy) in gachaconf.discount_policies.free_select_map.iter() {
|
||||
if !target_pool.discount_policy_tags.contains(policy_tag) {
|
||||
continue;
|
||||
}
|
||||
let status_bin = self
|
||||
.gacha_status_map
|
||||
.get_mut(&target_pool.sharing_guarantee_info_category)
|
||||
.unwrap();
|
||||
let progress = status_bin
|
||||
.discount_usage_map
|
||||
.get_mut(&policy.free_select_progress_record_tag)
|
||||
.unwrap();
|
||||
*progress += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_or_add<'a, K: Eq + PartialEq + Hash + Clone, V: Default, S: BuildHasher>(
|
||||
map: &'a mut HashMap<K, V, S>,
|
||||
key: &K,
|
||||
) -> &'a mut V {
|
||||
if !map.contains_key(key) {
|
||||
map.insert(key.clone(), V::default());
|
||||
}
|
||||
map.get_mut(key).unwrap()
|
||||
}
|
||||
|
||||
fn determine_gacha_result<'bin, 'conf>(
|
||||
pull_time: &DateTime<Local>,
|
||||
category: &'conf GachaCategoryInfo,
|
||||
target_pool: &'conf CharacterGachaPool,
|
||||
status_bin: &'bin GachaStatus,
|
||||
progress_bin: &'bin GachaProgress,
|
||||
rarity_items: &'conf GachaAvailableItemsInfo,
|
||||
) -> GachaRecord {
|
||||
let gachaconf = gacha::global_gacha_config();
|
||||
let item_pool_len = category.item_ids.len() as u32;
|
||||
let mut item_id: Option<&u32> = None;
|
||||
// We should see whether user's search priority exists.
|
||||
for guarantee_policy_tag in rarity_items.category_guarantee_policy_tags.iter() {
|
||||
let category_guarantee_policy = gachaconf
|
||||
.category_guarantee_policy_map
|
||||
.get(guarantee_policy_tag)
|
||||
.unwrap();
|
||||
if !category_guarantee_policy.chooseable {
|
||||
continue;
|
||||
}
|
||||
// Firstly, judge whether the user failed enough times.
|
||||
// The user is limited to get only this category's item,
|
||||
// so we should record the user's failure to get his
|
||||
// selected item elsewhere.
|
||||
if progress_bin
|
||||
.categories_chosen_guarantee_progress_map
|
||||
.get(guarantee_policy_tag)
|
||||
.unwrap()
|
||||
< &category_guarantee_policy.trigger_on_failure_times
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// We directly look whether user chose an UP item.
|
||||
if let Some(item) = progress_bin
|
||||
.categories_chosen_guarantee_item_map
|
||||
.get(guarantee_policy_tag)
|
||||
{
|
||||
item_id = Some(item);
|
||||
}
|
||||
}
|
||||
|
||||
let item_id = match item_id {
|
||||
Some(val) => val,
|
||||
None => category
|
||||
.item_ids
|
||||
.get(rand::thread_rng().gen_range(0..item_pool_len) as usize)
|
||||
.unwrap(),
|
||||
};
|
||||
let mut extra_item_id: Option<ItemID> = None;
|
||||
let mut extra_item_count: u32 = 0;
|
||||
|
||||
for extra_items_policy_tag in rarity_items.extra_items_policy_tags.iter() {
|
||||
let extra_items_policy = gachaconf
|
||||
.extra_items_policy_map
|
||||
.get(extra_items_policy_tag)
|
||||
.unwrap();
|
||||
// TODO: apply_on_owned_count in a context with bag
|
||||
// TODO: That's what RoleModel should do, not me.
|
||||
if extra_items_policy.apply_on_owned_count == 0 {
|
||||
extra_item_id = ItemID::new(extra_items_policy.id).ok();
|
||||
extra_item_count = extra_items_policy.count;
|
||||
}
|
||||
}
|
||||
let extra_resources = match extra_item_id {
|
||||
Some(item_id) => Some(GachaExtraResources {
|
||||
extra_item_id: item_id,
|
||||
extra_item_count,
|
||||
}),
|
||||
None => None,
|
||||
};
|
||||
GachaRecord {
|
||||
pull_timestamp: pull_time.timestamp(),
|
||||
obtained_item_id: ItemID::new_unchecked(item_id.clone()),
|
||||
gacha_id: target_pool.gacha_schedule_id.clone(),
|
||||
progress_map: status_bin.rarity_status_map.clone(),
|
||||
extra_resources,
|
||||
item_type: category.item_type.clone(),
|
||||
}
|
||||
}
|
6
nap_gameserver/src/logic/gacha/mod.rs
Normal file
6
nap_gameserver/src/logic/gacha/mod.rs
Normal file
|
@ -0,0 +1,6 @@
|
|||
mod client_op;
|
||||
mod gacha_model;
|
||||
mod record;
|
||||
mod stat;
|
||||
|
||||
pub use gacha_model::GachaModel;
|
85
nap_gameserver/src/logic/gacha/record.rs
Normal file
85
nap_gameserver/src/logic/gacha/record.rs
Normal file
|
@ -0,0 +1,85 @@
|
|||
use data::gacha::gacha_config::*;
|
||||
use data::tables::ItemID;
|
||||
|
||||
use proto::{GachaExtraItemBin, GachaRecordBin};
|
||||
use std::collections::HashMap;
|
||||
|
||||
use super::stat::*;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct GachaExtraResources {
|
||||
pub extra_item_id: ItemID,
|
||||
pub extra_item_count: u32,
|
||||
}
|
||||
|
||||
impl GachaExtraResources {
|
||||
pub fn from_bin_opt(bin_opt: Option<GachaExtraItemBin>) -> Option<Self> {
|
||||
match bin_opt {
|
||||
None => None,
|
||||
Some(bin) => {
|
||||
let item_id_opt = ItemID::new(bin.extra_item_id);
|
||||
match item_id_opt {
|
||||
Err(_) => None,
|
||||
Ok(extra_item_id) => Some(Self {
|
||||
extra_item_id,
|
||||
extra_item_count: bin.extra_item_count,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_bin_opt(opt: &Option<Self>) -> Option<GachaExtraItemBin> {
|
||||
match opt {
|
||||
None => None,
|
||||
Some(this) => Some(GachaExtraItemBin {
|
||||
extra_item_id: this.extra_item_id.value(),
|
||||
extra_item_count: this.extra_item_count.clone(),
|
||||
..Default::default()
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct GachaRecord {
|
||||
pub pull_timestamp: i64,
|
||||
pub obtained_item_id: ItemID,
|
||||
pub gacha_id: u32,
|
||||
/// The progress BEFORE this gacha is performed. key is rarity.
|
||||
pub progress_map: HashMap<u32, GachaProgress>,
|
||||
pub extra_resources: Option<GachaExtraResources>,
|
||||
pub item_type: GachaAddedItemType,
|
||||
}
|
||||
|
||||
impl GachaRecord {
|
||||
pub fn from_bin(bin: GachaRecordBin) -> Self {
|
||||
Self {
|
||||
pull_timestamp: bin.pull_timestamp,
|
||||
obtained_item_id: ItemID::new_unchecked(bin.obtained_item_id),
|
||||
gacha_id: bin.gacha_id,
|
||||
progress_map: bin
|
||||
.progress_map
|
||||
.into_iter()
|
||||
.map(|(k, v)| (k, GachaProgress::from_bin(v)))
|
||||
.collect(),
|
||||
extra_resources: GachaExtraResources::from_bin_opt(bin.extra_item_bin),
|
||||
item_type: GachaAddedItemType::from(bin.item_type),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_bin(&self) -> GachaRecordBin {
|
||||
GachaRecordBin {
|
||||
pull_timestamp: self.pull_timestamp.clone(),
|
||||
obtained_item_id: self.obtained_item_id.value(),
|
||||
gacha_id: self.gacha_id.clone(),
|
||||
progress_map: self
|
||||
.progress_map
|
||||
.iter()
|
||||
.map(|(k, v)| (k.clone(), v.to_bin()))
|
||||
.collect(),
|
||||
extra_item_bin: GachaExtraResources::to_bin_opt(&self.extra_resources),
|
||||
item_type: self.item_type.clone().into(),
|
||||
}
|
||||
}
|
||||
}
|
73
nap_gameserver/src/logic/gacha/stat.rs
Normal file
73
nap_gameserver/src/logic/gacha/stat.rs
Normal file
|
@ -0,0 +1,73 @@
|
|||
use proto::*;
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct GachaProgress {
|
||||
/// The pity (counting how many pulls) of this pull (in previous record) or the next pull (in status).
|
||||
pub pity: u32,
|
||||
/// The failure times of this category.
|
||||
pub categories_progress_map: HashMap<String, u32>,
|
||||
/// The selected priority (category) for a Chooseable category.
|
||||
pub categories_chosen_guarantee_category_map: HashMap<String, String>,
|
||||
/// The selectedpriority (a specified item) for a Chooseable category.
|
||||
pub categories_chosen_guarantee_item_map: HashMap<String, u32>,
|
||||
/// The failure times for selected priority (a specified item).
|
||||
pub categories_chosen_guarantee_progress_map: HashMap<String, u32>,
|
||||
}
|
||||
|
||||
impl GachaProgress {
|
||||
pub fn from_bin(bin: GachaProgressBin) -> Self {
|
||||
Self {
|
||||
pity: bin.pity,
|
||||
categories_progress_map: bin.categories_progress_map,
|
||||
categories_chosen_guarantee_category_map: bin.categories_chosen_guarantee_category_map,
|
||||
categories_chosen_guarantee_item_map: bin.categories_chosen_guarantee_item_map,
|
||||
categories_chosen_guarantee_progress_map: bin.categories_chosen_guarantee_progress_map,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_bin(&self) -> GachaProgressBin {
|
||||
GachaProgressBin {
|
||||
pity: self.pity,
|
||||
categories_progress_map: self.categories_progress_map.clone(),
|
||||
categories_chosen_guarantee_category_map: self
|
||||
.categories_chosen_guarantee_category_map
|
||||
.clone(),
|
||||
categories_chosen_guarantee_item_map: self.categories_chosen_guarantee_item_map.clone(),
|
||||
categories_chosen_guarantee_progress_map: self
|
||||
.categories_chosen_guarantee_progress_map
|
||||
.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct GachaStatus {
|
||||
pub rarity_status_map: HashMap<u32, GachaProgress>,
|
||||
pub discount_usage_map: HashMap<String, u32>,
|
||||
}
|
||||
|
||||
impl GachaStatus {
|
||||
pub fn from_bin(bin: GachaStatusBin) -> Self {
|
||||
Self {
|
||||
rarity_status_map: bin
|
||||
.rarity_status_map
|
||||
.into_iter()
|
||||
.map(|(k, v)| (k, GachaProgress::from_bin(v)))
|
||||
.collect(),
|
||||
discount_usage_map: bin.discount_usage_map,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_bin(&self) -> GachaStatusBin {
|
||||
GachaStatusBin {
|
||||
rarity_status_map: self
|
||||
.rarity_status_map
|
||||
.iter()
|
||||
.map(|(k, v)| (k.clone(), v.to_bin()))
|
||||
.collect(),
|
||||
discount_usage_map: self.discount_usage_map.clone(),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
use data::tables::ProcedureConfigID;
|
||||
use proto::{DungeonInfo, FreshSceneInfo, SceneInfo};
|
||||
|
||||
use crate::logic::{procedure::ProcedureManager, ESceneType};
|
||||
|
@ -9,7 +10,7 @@ pub struct FreshGame {
|
|||
}
|
||||
|
||||
impl FreshGame {
|
||||
pub fn new(start_procedure_id: i32) -> Self {
|
||||
pub fn new(start_procedure_id: ProcedureConfigID) -> Self {
|
||||
Self {
|
||||
procedure_mgr: ProcedureManager::new(start_procedure_id),
|
||||
}
|
||||
|
@ -25,7 +26,11 @@ impl NapGameMode for FreshGame {
|
|||
Some(SceneInfo {
|
||||
scene_type: self.scene_type() as u32,
|
||||
fresh_scene_info: Some(FreshSceneInfo {
|
||||
beginner_procedure_id: (self.procedure_mgr.procedure_id() - 1) as u32,
|
||||
beginner_procedure_id: self
|
||||
.procedure_mgr
|
||||
.procedure_id()
|
||||
.map(|i| i.value() - 1)
|
||||
.unwrap_or(0),
|
||||
}),
|
||||
..Default::default()
|
||||
})
|
||||
|
|
|
@ -1,17 +1,24 @@
|
|||
use data::tables;
|
||||
use data::tables::{AvatarBaseID, MainCityBgmConfigID, SectionConfigID};
|
||||
use proto::*;
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::logic::{math::Vector3f, time::MainCityTime, ESceneType};
|
||||
use crate::logic::{
|
||||
math::Vector3f,
|
||||
scene::{SceneUnit, SceneUnitManager},
|
||||
time::MainCityTime,
|
||||
ESceneType,
|
||||
};
|
||||
|
||||
use super::NapGameMode;
|
||||
|
||||
pub struct FrontendGame {
|
||||
section_id: u32,
|
||||
frontend_avatar_id: i32,
|
||||
section_id: SectionConfigID,
|
||||
frontend_avatar_id: AvatarBaseID,
|
||||
main_city_bgm: MainCityBgmConfigID,
|
||||
scene_unit_mgr: SceneUnitManager,
|
||||
camera_x: u32,
|
||||
camera_y: u32,
|
||||
born_pos: String,
|
||||
entry_transform: String,
|
||||
main_city_time: MainCityTime,
|
||||
avatar_pos: Vector3f,
|
||||
avatar_rot: Vector3f,
|
||||
|
@ -19,14 +26,16 @@ pub struct FrontendGame {
|
|||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum FrontendGameError {
|
||||
#[error("section id is invalid ({0})")]
|
||||
InvalidSection(u32),
|
||||
#[error("player's frontend avatar is None")]
|
||||
NoFrontendAvatar,
|
||||
}
|
||||
|
||||
impl FrontendGame {
|
||||
const DEFAULT_BGM_ID: u32 = 1005;
|
||||
|
||||
pub fn new(
|
||||
section_id: u32,
|
||||
avatar_id: i32,
|
||||
section_id: SectionConfigID,
|
||||
avatar_id: AvatarBaseID,
|
||||
main_city_time: MainCityTime,
|
||||
avatar_pos: Vector3f,
|
||||
avatar_rot: Vector3f,
|
||||
|
@ -34,11 +43,12 @@ impl FrontendGame {
|
|||
let instance = Self {
|
||||
section_id,
|
||||
main_city_time,
|
||||
main_city_bgm: MainCityBgmConfigID::new_unchecked(Self::DEFAULT_BGM_ID),
|
||||
scene_unit_mgr: SceneUnitManager::new(section_id),
|
||||
frontend_avatar_id: avatar_id,
|
||||
camera_x: 0xFFFFFFFF,
|
||||
camera_y: 0xFFFFFFFF,
|
||||
born_pos: Self::get_default_stage_entry_name(section_id)
|
||||
.ok_or(FrontendGameError::InvalidSection(section_id))?,
|
||||
entry_transform: section_id.template().primary_entry_name.clone(),
|
||||
avatar_pos,
|
||||
avatar_rot,
|
||||
};
|
||||
|
@ -47,10 +57,8 @@ impl FrontendGame {
|
|||
Ok(instance)
|
||||
}
|
||||
|
||||
fn get_default_stage_entry_name(section_id: u32) -> Option<String> {
|
||||
tables::section_config_template_tb::iter()
|
||||
.find(|tmpl| tmpl.section_id == section_id)
|
||||
.map(|tmpl| tmpl.primary_entry_name.clone())
|
||||
pub fn set_entry_transform(&mut self, transform_name: String) {
|
||||
self.entry_transform = transform_name;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -59,14 +67,15 @@ impl NapGameMode for FrontendGame {
|
|||
Some(SceneInfo {
|
||||
scene_type: self.scene_type() as u32,
|
||||
hall_scene_info: Some(HallSceneInfo {
|
||||
section_id: self.section_id,
|
||||
frontend_avatar_id: self.frontend_avatar_id as u32,
|
||||
section_id: self.section_id.value(),
|
||||
frontend_avatar_id: self.frontend_avatar_id.value(),
|
||||
main_city_bgm_id: self.main_city_bgm.value(),
|
||||
camera_x: self.camera_x,
|
||||
camera_y: self.camera_y,
|
||||
born_pos: self
|
||||
transform: self
|
||||
.avatar_pos
|
||||
.is_zero()
|
||||
.then_some(self.born_pos.clone())
|
||||
.then_some(self.entry_transform.clone())
|
||||
.unwrap_or_default(),
|
||||
day_of_week: self.main_city_time.day_of_week.value(),
|
||||
time_of_day: self.main_city_time.time_of_day.value(),
|
||||
|
@ -74,6 +83,12 @@ impl NapGameMode for FrontendGame {
|
|||
position: self.avatar_pos.to_vec(),
|
||||
rotation: self.avatar_rot.to_vec(),
|
||||
}),
|
||||
scene_unit_list: self
|
||||
.scene_unit_mgr
|
||||
.unit_vec
|
||||
.iter()
|
||||
.map(SceneUnit::protocol_info)
|
||||
.collect(),
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
|
|
|
@ -1,45 +1,169 @@
|
|||
use common::util;
|
||||
use data::tables;
|
||||
use data::tables::{
|
||||
self, ArchiveBattleQuestID, AvatarBaseID, BattleEventConfigID, BuddyBaseID, HollowQuestID,
|
||||
RobotBuddyConfigID, RobotConfigID, TrainingQuestID,
|
||||
};
|
||||
use proto::{DungeonInfo, DungeonItemData, FightSceneInfo, SceneInfo, WeatherPoolInfo};
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::logic::{ELocalPlayType, ESceneType, TimePeriodType, WeatherType};
|
||||
use crate::logic::{
|
||||
battle::{
|
||||
drop::FightDropPool,
|
||||
unit::{AvatarUnit, AvatarUnitID, BuddyUnit, BuddyUnitID},
|
||||
BuddyParam, DungeonQuestManager, TeamDataItem,
|
||||
},
|
||||
BuddyTeamType, EHollowQuestType, ELocalPlayType, ESceneType, TimePeriodType, WeatherType,
|
||||
};
|
||||
|
||||
use super::NapGameMode;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum HollowGameError {
|
||||
#[error("quest id is invalid: {0}")]
|
||||
InvalidQuestId(u32),
|
||||
#[error("Quest ({0}) type is not supported: {1:?}")]
|
||||
QuestTypeNotSupported(u32, EHollowQuestType),
|
||||
#[error("Battle group not found, quest id: {0}")]
|
||||
BattleGroupNotFound(u32),
|
||||
#[error("Invalid avatar id: {0}")]
|
||||
InvalidAvatarID(u32),
|
||||
#[error("Invalid robot id: {0}")]
|
||||
InvalidRobotID(u32),
|
||||
}
|
||||
|
||||
pub struct HollowGame {
|
||||
pub quest_id: u32,
|
||||
pub battle_event_id: u32,
|
||||
pub battle_event_id: BattleEventConfigID,
|
||||
pub time_period: TimePeriodType,
|
||||
pub weather: WeatherType,
|
||||
pub play_type: ELocalPlayType,
|
||||
pub start_timestamp: i64,
|
||||
pub team_data: TeamDataItem,
|
||||
pub fight_drop_pool: FightDropPool,
|
||||
pub quest_manager: DungeonQuestManager,
|
||||
}
|
||||
|
||||
impl HollowGame {
|
||||
pub fn create_training_game(
|
||||
training_quest_id: u32,
|
||||
training_quest_id: TrainingQuestID,
|
||||
play_type: ELocalPlayType,
|
||||
avatars: &[u32],
|
||||
) -> Result<Self, HollowGameError> {
|
||||
let template = tables::training_quest_template_tb::iter()
|
||||
.find(|tmpl| tmpl.id == training_quest_id)
|
||||
.ok_or(HollowGameError::InvalidQuestId(training_quest_id))?;
|
||||
let template = training_quest_id.template();
|
||||
|
||||
let avatars = match avatars
|
||||
.iter()
|
||||
.map(|id| AvatarBaseID::new(*id).map(|id| AvatarUnitID::Base(id)))
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
{
|
||||
Ok(avatars) => avatars,
|
||||
Err(err) => return Err(HollowGameError::InvalidAvatarID(err.0)),
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
quest_id: template.id,
|
||||
quest_id: template.id.value(),
|
||||
battle_event_id: template.battle_event_id,
|
||||
time_period: TimePeriodType::Morning,
|
||||
weather: WeatherType::SunShine,
|
||||
start_timestamp: util::cur_timestamp() as i64,
|
||||
play_type,
|
||||
team_data: TeamDataItem::new(&avatars, &[]),
|
||||
fight_drop_pool: FightDropPool::new(template.battle_event_id),
|
||||
quest_manager: DungeonQuestManager::default(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn create_archive_battle(
|
||||
archive_battle_quest_id: ArchiveBattleQuestID,
|
||||
play_type: ELocalPlayType,
|
||||
avatars: &[u32],
|
||||
buddy_id: u32,
|
||||
) -> Result<Self, HollowGameError> {
|
||||
let template = archive_battle_quest_id.template();
|
||||
|
||||
let avatars = match avatars
|
||||
.iter()
|
||||
.map(|id| RobotConfigID::new(*id).map(|id| AvatarUnitID::Robot(id)))
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
{
|
||||
Ok(avatars) => avatars,
|
||||
Err(err) => return Err(HollowGameError::InvalidAvatarID(err.0)),
|
||||
};
|
||||
|
||||
let buddy_params = match RobotBuddyConfigID::new(buddy_id) {
|
||||
Ok(id) => vec![BuddyParam(BuddyUnitID::Robot(id), BuddyTeamType::Fighting)],
|
||||
Err(_) => Vec::with_capacity(0),
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
quest_id: template.id.value(),
|
||||
battle_event_id: template.battle_event_id,
|
||||
time_period: TimePeriodType::Morning,
|
||||
weather: WeatherType::SunShine,
|
||||
start_timestamp: util::cur_timestamp() as i64,
|
||||
play_type,
|
||||
team_data: TeamDataItem::new(&avatars, &buddy_params),
|
||||
fight_drop_pool: FightDropPool::new(template.battle_event_id),
|
||||
quest_manager: DungeonQuestManager::default(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn create_pure_hollow_battle(
|
||||
quest_id: HollowQuestID,
|
||||
avatars: &[u32],
|
||||
buddy_id: u32,
|
||||
time_period: TimePeriodType,
|
||||
weather: WeatherType,
|
||||
) -> Result<Self, HollowGameError> {
|
||||
let template = quest_id.template();
|
||||
if template.chess_board_id != 0 {
|
||||
return Err(HollowGameError::QuestTypeNotSupported(
|
||||
template.id.value(),
|
||||
EHollowQuestType::from(template.hollow_quest_type),
|
||||
));
|
||||
}
|
||||
|
||||
let Some(battle_group) = tables::battle_group_config_template_tb::iter()
|
||||
.find(|tmpl| tmpl.quest_id == template.id.value())
|
||||
else {
|
||||
return Err(HollowGameError::BattleGroupNotFound(template.id.value()));
|
||||
};
|
||||
|
||||
let avatars = match avatars
|
||||
.iter()
|
||||
.map(|id| AvatarBaseID::new(*id).map(|id| AvatarUnitID::Base(id)))
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
{
|
||||
Ok(avatars) => avatars,
|
||||
Err(err) => return Err(HollowGameError::InvalidAvatarID(err.0)),
|
||||
};
|
||||
|
||||
let buddy_params = match BuddyBaseID::new(buddy_id) {
|
||||
Ok(id) => vec![BuddyParam(BuddyUnitID::Base(id), BuddyTeamType::Fighting)],
|
||||
Err(_) => Vec::with_capacity(0),
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
quest_id: template.id.value(),
|
||||
battle_event_id: battle_group.battle_event_id,
|
||||
time_period,
|
||||
weather,
|
||||
start_timestamp: util::cur_timestamp() as i64,
|
||||
play_type: Self::get_play_type_by_quest_type(EHollowQuestType::from(
|
||||
template.hollow_quest_type,
|
||||
)),
|
||||
team_data: TeamDataItem::new(&avatars, &buddy_params),
|
||||
fight_drop_pool: FightDropPool::new(battle_group.battle_event_id),
|
||||
quest_manager: DungeonQuestManager::new_for_battle_group(battle_group.id),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_play_type_by_quest_type(quest_type: EHollowQuestType) -> ELocalPlayType {
|
||||
match quest_type {
|
||||
EHollowQuestType::NormalBattle => ELocalPlayType::PureHollowBattle,
|
||||
EHollowQuestType::BossRushBattle => ELocalPlayType::BossRushBattle,
|
||||
EHollowQuestType::DifficutyBattle => ELocalPlayType::PureHollowBattleHardmode,
|
||||
_ => ELocalPlayType::PureHollowBattle,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl NapGameMode for HollowGame {
|
||||
|
@ -50,14 +174,16 @@ impl NapGameMode for HollowGame {
|
|||
fn scene_info(&self) -> Option<SceneInfo> {
|
||||
Some(SceneInfo {
|
||||
scene_type: self.scene_type() as u32,
|
||||
battle_event_id: self.battle_event_id,
|
||||
battle_event_id: self.battle_event_id.value(),
|
||||
play_type: self.play_type as u32,
|
||||
fight_scene_info: Some(FightSceneInfo {
|
||||
nmhdkmcabjg: true,
|
||||
weather_pool: Some(WeatherPoolInfo {
|
||||
time_period: self.time_period.to_string(),
|
||||
weather: self.weather.to_string(),
|
||||
..Default::default()
|
||||
}),
|
||||
fight_drop_info: Some(self.fight_drop_pool.to_client()),
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
|
@ -69,6 +195,19 @@ impl NapGameMode for HollowGame {
|
|||
quest_id: self.quest_id,
|
||||
start_timestamp: self.start_timestamp,
|
||||
dungeon_item_data: Some(DungeonItemData::default()),
|
||||
avatar_list: self
|
||||
.team_data
|
||||
.avatar_member_list
|
||||
.iter()
|
||||
.map(AvatarUnit::to_client)
|
||||
.collect(),
|
||||
buddy_list: self
|
||||
.team_data
|
||||
.equipped_buddy_list
|
||||
.iter()
|
||||
.map(BuddyUnit::to_client)
|
||||
.collect(),
|
||||
dungeon_quest_info: Some(self.quest_manager.to_client()),
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
|
|
155
nap_gameserver/src/logic/game/long_fight.rs
Normal file
155
nap_gameserver/src/logic/game/long_fight.rs
Normal file
|
@ -0,0 +1,155 @@
|
|||
use common::util;
|
||||
use data::tables::{self, AvatarBaseID, BattleEventConfigID, BuddyBaseID, HollowQuestID};
|
||||
use proto::{
|
||||
DungeonInfo, DungeonItemData, FightQuestInfo, LongFightInfo, LongFightSceneInfo, SceneInfo,
|
||||
WeatherPoolInfo,
|
||||
};
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::logic::{
|
||||
battle::{
|
||||
drop::FightDropPool,
|
||||
unit::{AvatarUnit, AvatarUnitID, BuddyUnit, BuddyUnitID},
|
||||
BuddyParam, DungeonQuestManager, LogicVariableTable, TeamDataItem,
|
||||
},
|
||||
BuddyTeamType, EHollowQuestType, ELocalPlayType, ESceneType, TimePeriodType, WeatherType,
|
||||
};
|
||||
|
||||
use super::NapGameMode;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum LongFightGameError {
|
||||
#[error("Tried to run quest of type {0:?} using LongFight logic")]
|
||||
InvalidQuestType(EHollowQuestType),
|
||||
#[error("Battle group not found, quest id: {0}")]
|
||||
BattleGroupNotFound(u32),
|
||||
#[error("Invalid avatar id: {0}")]
|
||||
InvalidAvatarID(u32),
|
||||
}
|
||||
|
||||
pub struct LongFightGame {
|
||||
pub quest_id: u32,
|
||||
pub battle_event_id: BattleEventConfigID,
|
||||
pub play_type: ELocalPlayType,
|
||||
pub time_period: TimePeriodType,
|
||||
pub weather: WeatherType,
|
||||
pub start_timestamp: i64,
|
||||
pub team_data: TeamDataItem,
|
||||
pub variable_table: LogicVariableTable,
|
||||
pub fight_drop_pool: FightDropPool,
|
||||
pub quest_manager: DungeonQuestManager,
|
||||
}
|
||||
|
||||
impl LongFightGame {
|
||||
const RALLY_GUIDANCE_BUDDY: BuddyBaseID = BuddyBaseID::new_unchecked(50001);
|
||||
|
||||
pub fn create_rally_game(
|
||||
quest_id: HollowQuestID,
|
||||
avatars: &[u32],
|
||||
buddy_id: u32,
|
||||
time_period: TimePeriodType,
|
||||
weather: WeatherType,
|
||||
) -> Result<Self, LongFightGameError> {
|
||||
let template = quest_id.template();
|
||||
let quest_type = EHollowQuestType::from(template.hollow_quest_type);
|
||||
|
||||
if quest_type != EHollowQuestType::RallyBattle {
|
||||
return Err(LongFightGameError::InvalidQuestType(quest_type));
|
||||
}
|
||||
|
||||
let Some(battle_group) = tables::battle_group_config_template_tb::iter()
|
||||
.find(|tmpl| tmpl.quest_id == template.id.value())
|
||||
else {
|
||||
return Err(LongFightGameError::BattleGroupNotFound(template.id.value()));
|
||||
};
|
||||
|
||||
let avatars = match avatars
|
||||
.iter()
|
||||
.map(|id| AvatarBaseID::new(*id).map(|id| AvatarUnitID::Base(id)))
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
{
|
||||
Ok(avatars) => avatars,
|
||||
Err(err) => return Err(LongFightGameError::InvalidAvatarID(err.0)),
|
||||
};
|
||||
|
||||
let mut buddy_params = vec![BuddyParam(
|
||||
BuddyUnitID::Base(Self::RALLY_GUIDANCE_BUDDY),
|
||||
BuddyTeamType::RallyGuidance,
|
||||
)];
|
||||
|
||||
if let Ok(buddy_id) = BuddyBaseID::new(buddy_id) {
|
||||
buddy_params.push(BuddyParam(
|
||||
BuddyUnitID::Base(buddy_id),
|
||||
BuddyTeamType::Fighting,
|
||||
));
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
quest_id: template.id.value(),
|
||||
battle_event_id: battle_group.battle_event_id,
|
||||
play_type: ELocalPlayType::RallyLongFight,
|
||||
time_period,
|
||||
weather,
|
||||
start_timestamp: util::cur_timestamp() as i64,
|
||||
team_data: TeamDataItem::new(&avatars, &buddy_params),
|
||||
variable_table: LogicVariableTable::new(battle_group.battle_event_id),
|
||||
fight_drop_pool: FightDropPool::new(battle_group.battle_event_id),
|
||||
quest_manager: DungeonQuestManager::new_for_battle_group(battle_group.id),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl NapGameMode for LongFightGame {
|
||||
fn scene_type(&self) -> ESceneType {
|
||||
ESceneType::LongFight
|
||||
}
|
||||
|
||||
fn scene_info(&self) -> Option<SceneInfo> {
|
||||
Some(SceneInfo {
|
||||
scene_type: self.scene_type() as u32,
|
||||
battle_event_id: self.battle_event_id.value(),
|
||||
play_type: self.play_type as u32,
|
||||
long_fight_scene_info: Some(LongFightSceneInfo {
|
||||
fight_data: Some(LongFightInfo {
|
||||
fight_quest_info: Some(FightQuestInfo {
|
||||
fight_variable_map: self.variable_table.to_client(),
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
}),
|
||||
fight_drop_info: Some(self.fight_drop_pool.to_client()),
|
||||
weather_pool: Some(WeatherPoolInfo {
|
||||
time_period: self.time_period.to_string(),
|
||||
weather: self.weather.to_string(),
|
||||
febgjinpcbp: true,
|
||||
bejeblcfcha: true,
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
|
||||
fn dungeon_info(&self) -> Option<DungeonInfo> {
|
||||
Some(DungeonInfo {
|
||||
quest_id: self.quest_id,
|
||||
start_timestamp: self.start_timestamp,
|
||||
dungeon_item_data: Some(DungeonItemData::default()),
|
||||
avatar_list: self
|
||||
.team_data
|
||||
.avatar_member_list
|
||||
.iter()
|
||||
.map(AvatarUnit::to_client)
|
||||
.collect(),
|
||||
buddy_list: self
|
||||
.team_data
|
||||
.equipped_buddy_list
|
||||
.iter()
|
||||
.map(BuddyUnit::to_client)
|
||||
.collect(),
|
||||
dungeon_quest_info: Some(self.quest_manager.to_client()),
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,20 +1,24 @@
|
|||
mod fresh;
|
||||
mod frontend;
|
||||
mod hollow;
|
||||
mod long_fight;
|
||||
use data::tables::TemplateNotFoundError;
|
||||
pub use fresh::*;
|
||||
pub use frontend::*;
|
||||
pub use hollow::*;
|
||||
pub use long_fight::*;
|
||||
|
||||
use proto::{DungeonInfo, SceneInfo, WorldInitScNotify};
|
||||
use thiserror::Error;
|
||||
|
||||
use super::{procedure::ProcedureError, ESceneType};
|
||||
use super::{battle::DungeonQuestError, procedure::ProcedureError, ESceneType};
|
||||
|
||||
#[derive(Default)]
|
||||
pub enum GameInstance {
|
||||
Frontend(FrontendGame),
|
||||
Fresh(FreshGame),
|
||||
Hollow(HollowGame),
|
||||
LongFight(LongFightGame),
|
||||
#[default]
|
||||
Null,
|
||||
}
|
||||
|
@ -29,6 +33,12 @@ pub enum LogicError {
|
|||
Procedure(#[from] ProcedureError),
|
||||
#[error("hollow error: {0}")]
|
||||
Hollow(#[from] HollowGameError),
|
||||
#[error("longfight error: {0}")]
|
||||
LongFight(#[from] LongFightGameError),
|
||||
#[error("dungeon quest error: {0}")]
|
||||
DungeonQuest(#[from] DungeonQuestError),
|
||||
#[error("{0}")]
|
||||
TemplateNotFound(#[from] TemplateNotFoundError),
|
||||
}
|
||||
|
||||
impl GameInstance {
|
||||
|
@ -41,6 +51,7 @@ impl GameInstance {
|
|||
Self::Frontend(game) => game,
|
||||
Self::Fresh(game) => game,
|
||||
Self::Hollow(game) => game,
|
||||
Self::LongFight(game) => game,
|
||||
Self::Null => return Err(LogicError::GameIsNull),
|
||||
}))
|
||||
}
|
||||
|
|
|
@ -1,24 +1,31 @@
|
|||
use super::ResourceItem;
|
||||
use proto::ItemModelBin;
|
||||
use super::{ItemUID, ResourceItem, Weapon};
|
||||
use data::tables::WeaponID;
|
||||
use proto::{ItemModelBin, ItemSync};
|
||||
|
||||
pub struct ItemModel {
|
||||
uid_counter: u32,
|
||||
pub resources: Vec<ResourceItem>,
|
||||
pub weapons: Vec<Weapon>,
|
||||
}
|
||||
|
||||
impl ItemModel {
|
||||
pub fn from_bin(bin: ItemModelBin) -> Self {
|
||||
Self {
|
||||
uid_counter: bin.item_uid_counter,
|
||||
resources: bin
|
||||
.resource_list
|
||||
.into_iter()
|
||||
.map(ResourceItem::from_bin)
|
||||
.collect(),
|
||||
weapons: bin.weapon_list.into_iter().map(Weapon::from_bin).collect(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_bin(&self) -> ItemModelBin {
|
||||
ItemModelBin {
|
||||
item_uid_counter: self.uid_counter,
|
||||
resource_list: self.resources.iter().map(ResourceItem::to_bin).collect(),
|
||||
weapon_list: self.weapons.iter().map(Weapon::to_bin).collect(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -36,12 +43,34 @@ impl ItemModel {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_weapon(&mut self, template_id: WeaponID) -> ItemUID {
|
||||
let uid = self.next_uid();
|
||||
self.weapons.push(Weapon::new(template_id, uid));
|
||||
|
||||
uid
|
||||
}
|
||||
|
||||
pub fn item_sync(&self) -> ItemSync {
|
||||
ItemSync {
|
||||
resource_list: self.resources.iter().map(|i| i.to_client()).collect(),
|
||||
weapon_list: self.weapons.iter().map(|w| w.to_client()).collect(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
fn next_uid(&mut self) -> ItemUID {
|
||||
self.uid_counter += 1;
|
||||
self.uid_counter.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ItemModel {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
uid_counter: 0,
|
||||
resources: Vec::new(),
|
||||
weapons: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,22 @@
|
|||
mod item_model;
|
||||
mod resource;
|
||||
mod weapon;
|
||||
|
||||
pub use item_model::ItemModel;
|
||||
pub use resource::ResourceItem;
|
||||
pub use weapon::Weapon;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub struct ItemUID(u32);
|
||||
|
||||
impl ItemUID {
|
||||
pub fn value(&self) -> u32 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u32> for ItemUID {
|
||||
fn from(value: u32) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue