From f27cde756c41cdd70a823e32a5673fefaa92f5ec Mon Sep 17 00:00:00 2001 From: capyb2222 Date: Sat, 12 Sep 2026 19:37:15 -0700 Subject: [PATCH] feat(game): add warp pulls --- config/config.json | 4 +- proto/seeds.txt | 6 + resources/excel-beta/GachaBasicInfo.json | 134 + resources/excel/BattlePassReward.json | 535 ++ resources/excel/EquipmentConfig.json | 6456 ++++++++++++++++++++++ resources/excel/GachaTypeBasicInfo.json | 72 + src/core/config.cpp | 19 + src/core/config.h | 12 + src/data/excel.cpp | 112 +- src/data/excel.h | 30 + src/game/gacha.cpp | 244 + src/game/gacha.h | 75 + src/game/gacha_handlers.cpp | 143 + src/game/handlers.h | 1 + src/game/misc_handlers.cpp | 21 +- src/game/player.h | 4 + src/game/player_store.cpp | 25 + tests/test_flow.cpp | 79 + tests/test_game.cpp | 219 + 19 files changed, 8166 insertions(+), 25 deletions(-) create mode 100644 resources/excel-beta/GachaBasicInfo.json create mode 100644 resources/excel/BattlePassReward.json create mode 100644 resources/excel/EquipmentConfig.json create mode 100644 resources/excel/GachaTypeBasicInfo.json create mode 100644 src/game/gacha.cpp create mode 100644 src/game/gacha.h create mode 100644 src/game/gacha_handlers.cpp diff --git a/config/config.json b/config/config.json index 44b9868..fca946c 100644 --- a/config/config.json +++ b/config/config.json @@ -44,7 +44,9 @@ "unlock_all_challenges": true, "main_character": 8008, "march_type": 1224, - "skip_missions": [] + "skip_missions": [], + "limited_warp_pools": [], + "standard_warp_featured": 1503 }, "paths": { "srtools_file": "data/freesr-data.json", diff --git a/proto/seeds.txt b/proto/seeds.txt index 6dec7d3..ff140ee 100644 --- a/proto/seeds.txt +++ b/proto/seeds.txt @@ -297,6 +297,12 @@ GetActivityScheduleConfigCsReq GetActivityScheduleConfigScRsp DoGachaCsReq DoGachaScRsp +GetGachaCeilingCsReq +GetGachaCeilingScRsp +ExchangeGachaCeilingCsReq +ExchangeGachaCeilingScRsp +SetGachaDecideItemCsReq +SetGachaDecideItemScRsp GetMailCsReq GetMailScRsp GetPhoneDataCsReq diff --git a/resources/excel-beta/GachaBasicInfo.json b/resources/excel-beta/GachaBasicInfo.json new file mode 100644 index 0000000..4bb156c --- /dev/null +++ b/resources/excel-beta/GachaBasicInfo.json @@ -0,0 +1,134 @@ +[ + { + "GachaID": 1001, + "GachaType": "Normal", + "SortID": 99, + "StartTime": "", + "EndTime": "", + "PrefabPath": "UI/Drawcard/GachaPanel/StandardGacha_1001.prefab", + "PoolName": { + "Hash": 12642828881931173103 + }, + "PoolDesc": { + "Hash": 1121704090967857799 + }, + "PoolDescFTC": { + "Hash": 6970163302865048869 + }, + "PoolLabelIcon": "SpriteOutput/DrawCardPic/GachaTabIcon/TabIcon_Standard.png", + "PoolLabelIconSelected": "SpriteOutput/DrawCardPic/GachaTabIcon/TabIcon_Standard_Selected.png", + "TypeTitle": { + "Hash": 10012362747660649297 + } + }, + { + "GachaID": 4001, + "GachaType": "Newbie", + "SortID": 1, + "StartTime": "", + "EndTime": "", + "PrefabPath": "UI/Drawcard/GachaPanel/NoviceGacha_4001.prefab", + "PoolName": { + "Hash": 16076008841484912183 + }, + "PoolDesc": { + "Hash": 13113094041792250269 + }, + "PoolDescFTC": { + "Hash": 6682982103413155220 + }, + "PoolLabelIcon": "SpriteOutput/DrawCardPic/GachaTabIcon/TabIcon_Novice.png", + "PoolLabelIconSelected": "SpriteOutput/DrawCardPic/GachaTabIcon/TabIcon_Novice_Selected.png", + "TypeTitle": { + "Hash": 12992035607736039415 + } + }, + { + "GachaID": 2001, + "GachaType": "AvatarUp", + "SortID": 2, + "StartTime": "", + "EndTime": "", + "PrefabPath": "UI/Drawcard/GachaPanelLimited/AvatarGacha_1102.prefab", + "PoolName": { + "Hash": 10466444443325460861 + }, + "PoolDesc": { + "Hash": 12575760539773716760 + }, + "PoolDescFTC": { + "Hash": 9461473220466468630 + }, + "PoolLabelIcon": "SpriteOutput/DrawCardPic/GachaTabIconLimited/TabIcon_1102.png", + "PoolLabelIconSelected": "SpriteOutput/DrawCardPic/GachaTabIconLimited/TabIcon_1102_Selected.png", + "TypeTitle": { + "Hash": 16335421618088345187 + } + }, + { + "GachaID": 3001, + "GachaType": "WeaponUp", + "SortID": 4, + "StartTime": "", + "EndTime": "", + "PrefabPath": "UI/Drawcard/GachaPanelLimited/LightConeGacha_23001.prefab", + "PoolName": { + "Hash": 10051276577110162368 + }, + "PoolDesc": { + "Hash": 13567216986870304529 + }, + "PoolDescFTC": { + "Hash": 12441093686588219336 + }, + "PoolLabelIcon": "SpriteOutput/DrawCardPic/GachaTabIconLimited/TabIcon_LightCone_23001.png", + "PoolLabelIconSelected": "SpriteOutput/DrawCardPic/GachaTabIconLimited/TabIcon_LightCone_23001_Selected.png", + "TypeTitle": { + "Hash": 689370920993170148 + } + }, + { + "GachaID": 2002, + "GachaType": "AvatarUp", + "SortID": 3, + "StartTime": "", + "EndTime": "", + "PrefabPath": "UI/Drawcard/GachaPanelLimited/AvatarGacha_1204.prefab", + "PoolName": { + "Hash": 9253952357381402356 + }, + "PoolDesc": { + "Hash": 12575760539773716760 + }, + "PoolDescFTC": { + "Hash": 9461473220466468630 + }, + "PoolLabelIcon": "SpriteOutput/DrawCardPic/GachaTabIconLimited/TabIcon_1204.png", + "PoolLabelIconSelected": "SpriteOutput/DrawCardPic/GachaTabIconLimited/TabIcon_1204_Selected.png", + "TypeTitle": { + "Hash": 16335421618088345187 + } + }, + { + "GachaID": 3002, + "GachaType": "WeaponUp", + "SortID": 5, + "StartTime": "", + "EndTime": "", + "PrefabPath": "UI/Drawcard/GachaPanelLimited/LightConeGacha_23010.prefab", + "PoolName": { + "Hash": 3268726668422334764 + }, + "PoolDesc": { + "Hash": 13567216986870304529 + }, + "PoolDescFTC": { + "Hash": 12441093686588219336 + }, + "PoolLabelIcon": "SpriteOutput/DrawCardPic/GachaTabIconLimited/TabIcon_LightCone_23010.png", + "PoolLabelIconSelected": "SpriteOutput/DrawCardPic/GachaTabIconLimited/TabIcon_LightCone_23010_Selected.png", + "TypeTitle": { + "Hash": 689370920993170148 + } + } +] diff --git a/resources/excel/BattlePassReward.json b/resources/excel/BattlePassReward.json new file mode 100644 index 0000000..8187190 --- /dev/null +++ b/resources/excel/BattlePassReward.json @@ -0,0 +1,535 @@ +[ + { + "ID": 1, + "RewardItem": 300011, + "RewardIcon": "", + "NumShow": true + }, + { + "ID": 2, + "RewardItem": 1, + "RewardIcon": "", + "NumShow": true + }, + { + "ID": 3, + "RewardItem": 102, + "RewardIcon": "", + "NumShow": true + }, + { + "ID": 4, + "RewardItem": 300003, + "RewardIcon": "", + "NumShow": true + }, + { + "ID": 5, + "RewardItem": 300002, + "RewardIcon": "", + "NumShow": true + }, + { + "ID": 6, + "RewardItem": 200103, + "RewardIcon": "" + }, + { + "ID": 7, + "RewardItem": 200104, + "RewardIcon": "" + }, + { + "ID": 8, + "RewardItem": 1, + "RewardIcon": "", + "NumShow": true + }, + { + "ID": 9, + "RewardItem": 201, + "RewardIcon": "", + "NumShow": true + }, + { + "ID": 10, + "RewardItem": 200101, + "RewardIcon": "" + }, + { + "ID": 11, + "RewardItem": 200102, + "RewardIcon": "" + }, + { + "ID": 12, + "RewardItem": 200107, + "RewardIcon": "" + }, + { + "ID": 13, + "RewardItem": 200108, + "RewardIcon": "" + }, + { + "ID": 14, + "RewardItem": 200109, + "RewardIcon": "" + }, + { + "ID": 15, + "RewardItem": 200110, + "RewardIcon": "" + }, + { + "ID": 16, + "RewardItem": 200111, + "RewardIcon": "" + }, + { + "ID": 17, + "RewardItem": 200112, + "RewardIcon": "" + }, + { + "ID": 18, + "RewardItem": 200113, + "RewardIcon": "" + }, + { + "ID": 19, + "RewardItem": 200114, + "RewardIcon": "" + }, + { + "ID": 20, + "RewardItem": 1, + "RewardIcon": "" + }, + { + "ID": 21, + "RewardItem": 236, + "RewardIcon": "", + "NumShow": true + }, + { + "ID": 22, + "RewardItem": 102, + "RewardIcon": "" + }, + { + "ID": 23, + "RewardItem": 300011, + "RewardIcon": "" + }, + { + "ID": 24, + "RewardItem": 300003, + "RewardIcon": "" + }, + { + "ID": 25, + "RewardItem": 201, + "RewardIcon": "" + }, + { + "ID": 26, + "RewardItem": 241, + "RewardIcon": "", + "NumShow": true + }, + { + "ID": 27, + "RewardItem": 213, + "RewardIcon": "", + "NumShow": true + }, + { + "ID": 28, + "RewardItem": 223, + "RewardIcon": "", + "NumShow": true + }, + { + "ID": 29, + "RewardItem": 235, + "RewardIcon": "", + "NumShow": true + }, + { + "ID": 30, + "RewardItem": 200115, + "RewardIcon": "" + }, + { + "ID": 31, + "RewardItem": 200116, + "RewardIcon": "" + }, + { + "ID": 32, + "RewardItem": 110101, + "RewardIcon": "", + "NumShow": true + }, + { + "ID": 33, + "RewardItem": 200117, + "RewardIcon": "" + }, + { + "ID": 34, + "RewardItem": 200118, + "RewardIcon": "" + }, + { + "ID": 35, + "RewardItem": 200119, + "RewardIcon": "" + }, + { + "ID": 36, + "RewardItem": 200120, + "RewardIcon": "" + }, + { + "ID": 37, + "RewardItem": 200121, + "RewardIcon": "" + }, + { + "ID": 38, + "RewardItem": 200122, + "RewardIcon": "" + }, + { + "ID": 39, + "RewardItem": 200123, + "RewardIcon": "" + }, + { + "ID": 40, + "RewardItem": 200124, + "RewardIcon": "" + }, + { + "ID": 41, + "RewardItem": 200125, + "RewardIcon": "" + }, + { + "ID": 42, + "RewardItem": 200126, + "RewardIcon": "" + }, + { + "ID": 43, + "RewardItem": 200127, + "RewardIcon": "" + }, + { + "ID": 44, + "RewardItem": 200128, + "RewardIcon": "" + }, + { + "ID": 45, + "RewardItem": 200129, + "RewardIcon": "" + }, + { + "ID": 46, + "RewardItem": 200130, + "RewardIcon": "" + }, + { + "ID": 47, + "RewardItem": 200131, + "RewardIcon": "" + }, + { + "ID": 48, + "RewardItem": 200132, + "RewardIcon": "" + }, + { + "ID": 49, + "RewardItem": 200133, + "RewardIcon": "" + }, + { + "ID": 50, + "RewardItem": 200134, + "RewardIcon": "" + }, + { + "ID": 51, + "RewardItem": 200135, + "RewardIcon": "" + }, + { + "ID": 52, + "RewardItem": 200136, + "RewardIcon": "" + }, + { + "ID": 53, + "RewardItem": 200137, + "RewardIcon": "" + }, + { + "ID": 54, + "RewardItem": 200138, + "RewardIcon": "" + }, + { + "ID": 55, + "RewardItem": 200139, + "RewardIcon": "" + }, + { + "ID": 56, + "RewardItem": 200140, + "RewardIcon": "" + }, + { + "ID": 57, + "RewardItem": 200141, + "RewardIcon": "" + }, + { + "ID": 58, + "RewardItem": 200142, + "RewardIcon": "" + }, + { + "ID": 59, + "RewardItem": 200143, + "RewardIcon": "" + }, + { + "ID": 60, + "RewardItem": 200144, + "RewardIcon": "" + }, + { + "ID": 61, + "RewardItem": 200145, + "RewardIcon": "" + }, + { + "ID": 62, + "RewardItem": 200146, + "RewardIcon": "" + }, + { + "ID": 63, + "RewardItem": 200147, + "RewardIcon": "" + }, + { + "ID": 64, + "RewardItem": 200148, + "RewardIcon": "" + }, + { + "ID": 65, + "RewardItem": 200149, + "RewardIcon": "" + }, + { + "ID": 66, + "RewardItem": 200150, + "RewardIcon": "" + }, + { + "ID": 67, + "RewardItem": 200151, + "RewardIcon": "" + }, + { + "ID": 68, + "RewardItem": 200152, + "RewardIcon": "" + }, + { + "ID": 69, + "RewardItem": 200153, + "RewardIcon": "" + }, + { + "ID": 70, + "RewardItem": 200154, + "RewardIcon": "" + }, + { + "ID": 71, + "RewardItem": 200155, + "RewardIcon": "" + }, + { + "ID": 72, + "RewardItem": 200156, + "RewardIcon": "" + }, + { + "ID": 73, + "RewardItem": 200157, + "RewardIcon": "" + }, + { + "ID": 74, + "RewardItem": 200158, + "RewardIcon": "" + }, + { + "ID": 75, + "RewardItem": 200159, + "RewardIcon": "" + }, + { + "ID": 76, + "RewardItem": 200160, + "RewardIcon": "" + }, + { + "ID": 77, + "RewardItem": 200161, + "RewardIcon": "" + }, + { + "ID": 78, + "RewardItem": 200162, + "RewardIcon": "" + }, + { + "ID": 501, + "RewardItem": 238, + "RewardIcon": "", + "NumShow": true + }, + { + "ID": 502, + "RewardItem": 237, + "RewardIcon": "", + "NumShow": true + }, + { + "ID": 503, + "RewardItem": 300012, + "RewardIcon": "" + }, + { + "ID": 504, + "RewardItem": 283, + "RewardIcon": "", + "NumShow": true + }, + { + "ID": 505, + "RewardItem": 300014, + "RewardIcon": "" + }, + { + "ID": 1001, + "RewardItem": 21052, + "RewardIcon": "", + "NumShow": true + }, + { + "ID": 1002, + "RewardItem": 21028, + "RewardIcon": "", + "NumShow": true + }, + { + "ID": 1003, + "RewardItem": 21029, + "RewardIcon": "", + "NumShow": true + }, + { + "ID": 1004, + "RewardItem": 21030, + "RewardIcon": "", + "NumShow": true + }, + { + "ID": 1005, + "RewardItem": 21031, + "RewardIcon": "", + "NumShow": true + }, + { + "ID": 1006, + "RewardItem": 21032, + "RewardIcon": "", + "NumShow": true + }, + { + "ID": 1007, + "RewardItem": 21033, + "RewardIcon": "", + "NumShow": true + }, + { + "ID": 1008, + "RewardItem": 21034, + "RewardIcon": "", + "NumShow": true + }, + { + "ID": 1009, + "RewardItem": 21057, + "RewardIcon": "", + "NumShow": true + }, + { + "ID": 1010, + "RewardItem": 21055, + "RewardIcon": "", + "NumShow": true + }, + { + "ID": 1011, + "RewardItem": 21061, + "RewardIcon": "", + "NumShow": true + }, + { + "ID": 1012, + "RewardItem": 21053, + "RewardIcon": "", + "NumShow": true + }, + { + "ID": 1013, + "RewardItem": 21062, + "RewardIcon": "", + "NumShow": true + }, + { + "ID": 1014, + "RewardItem": 21056, + "RewardIcon": "", + "NumShow": true + }, + { + "ID": 1015, + "RewardItem": 21058, + "RewardIcon": "", + "NumShow": true + }, + { + "ID": 1016, + "RewardItem": 21060, + "RewardIcon": "", + "NumShow": true + }, + { + "ID": 1017, + "RewardItem": 21065, + "RewardIcon": "", + "NumShow": true + } +] \ No newline at end of file diff --git a/resources/excel/EquipmentConfig.json b/resources/excel/EquipmentConfig.json new file mode 100644 index 0000000..0099c1c --- /dev/null +++ b/resources/excel/EquipmentConfig.json @@ -0,0 +1,6456 @@ +[ + { + "EquipmentID": 20000, + "Release": true, + "EquipmentName": { + "Hash": 1315631816518421847 + }, + "Rarity": "CombatPowerLightconeRarity3", + "AvatarBaseType": "Rogue", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 1, + "SkillID": 20000, + "ExpProvide": 500, + "CoinCost": 250, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/20000.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/20000.png", + "ItemRightPanelOffset": [ + 0, + -64, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + -71, + 1.15 + ], + "BattleDialogOffset": [ + 12, + -6, + 0.6 + ], + "GachaResultOffset": [ + 14, + -9, + 0.545 + ] + }, + { + "EquipmentID": 20001, + "Release": true, + "EquipmentName": { + "Hash": 626150995471578115 + }, + "Rarity": "CombatPowerLightconeRarity3", + "AvatarBaseType": "Priest", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 1, + "SkillID": 20001, + "ExpProvide": 500, + "CoinCost": 250, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/20001.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/20001.png", + "ItemRightPanelOffset": [ + 0, + -52, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + -92, + 1.15 + ], + "BattleDialogOffset": [ + 55, + 16, + 0.6 + ], + "GachaResultOffset": [ + 5, + 0, + 0.545 + ] + }, + { + "EquipmentID": 20002, + "Release": true, + "EquipmentName": { + "Hash": 131015357822286277 + }, + "Rarity": "CombatPowerLightconeRarity3", + "AvatarBaseType": "Warrior", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 1, + "SkillID": 20002, + "ExpProvide": 500, + "CoinCost": 250, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/20002.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/20002.png", + "ItemRightPanelOffset": [ + 0, + -101, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + -78, + 1.15 + ], + "BattleDialogOffset": [ + 0, + 0, + 0.6 + ], + "GachaResultOffset": [ + 0, + 0, + 0.545 + ] + }, + { + "EquipmentID": 20003, + "Release": true, + "EquipmentName": { + "Hash": 1980577345993249477 + }, + "Rarity": "CombatPowerLightconeRarity3", + "AvatarBaseType": "Knight", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 1, + "SkillID": 20003, + "ExpProvide": 500, + "CoinCost": 250, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/20003.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/20003.png", + "ItemRightPanelOffset": [ + 0, + -14, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + 20, + 1.15 + ], + "BattleDialogOffset": [ + 0, + 0, + 0.6 + ], + "GachaResultOffset": [ + 0, + 0, + 0.545 + ] + }, + { + "EquipmentID": 20004, + "Release": true, + "EquipmentName": { + "Hash": 6342114722180502380 + }, + "Rarity": "CombatPowerLightconeRarity3", + "AvatarBaseType": "Warlock", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 1, + "SkillID": 20004, + "ExpProvide": 500, + "CoinCost": 250, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/20004.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/20004.png", + "ItemRightPanelOffset": [ + 0, + -114, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + -163, + 1.15 + ], + "BattleDialogOffset": [ + 20, + 0, + 0.6 + ], + "GachaResultOffset": [ + 0, + -3, + 0.545 + ] + }, + { + "EquipmentID": 20005, + "Release": true, + "EquipmentName": { + "Hash": 15002084058293597877 + }, + "Rarity": "CombatPowerLightconeRarity3", + "AvatarBaseType": "Shaman", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 1, + "SkillID": 20005, + "ExpProvide": 500, + "CoinCost": 250, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/20005.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/20005.png", + "ItemRightPanelOffset": [ + 0, + -114, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + -130, + 1.15 + ], + "BattleDialogOffset": [ + 0, + 0, + 0.6 + ], + "GachaResultOffset": [ + -4, + -3, + 0.545 + ] + }, + { + "EquipmentID": 20006, + "Release": true, + "EquipmentName": { + "Hash": 2920583894071632168 + }, + "Rarity": "CombatPowerLightconeRarity3", + "AvatarBaseType": "Mage", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 1, + "SkillID": 20006, + "ExpProvide": 500, + "CoinCost": 250, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/20006.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/20006.png", + "ItemRightPanelOffset": [ + 0, + -162, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + -186, + 1.15 + ], + "BattleDialogOffset": [ + 0, + 0, + 0.6 + ], + "GachaResultOffset": [ + -1, + -17, + 0.545 + ] + }, + { + "EquipmentID": 20007, + "Release": true, + "EquipmentName": { + "Hash": 12734437266111259030 + }, + "Rarity": "CombatPowerLightconeRarity3", + "AvatarBaseType": "Rogue", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 1, + "SkillID": 20007, + "ExpProvide": 500, + "CoinCost": 250, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/20007.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/20007.png", + "ItemRightPanelOffset": [ + 0, + 141, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + 190, + 1.15 + ], + "BattleDialogOffset": [ + 0, + 0, + 0.6 + ], + "GachaResultOffset": [ + -8, + 16, + 0.545 + ] + }, + { + "EquipmentID": 20008, + "Release": true, + "EquipmentName": { + "Hash": 10739058991811781260 + }, + "Rarity": "CombatPowerLightconeRarity3", + "AvatarBaseType": "Priest", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 1, + "SkillID": 20008, + "ExpProvide": 500, + "CoinCost": 250, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/20008.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/20008.png", + "ItemRightPanelOffset": [ + 0, + -37, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + -4, + 1.15 + ], + "BattleDialogOffset": [ + 0, + 0, + 0.6 + ], + "GachaResultOffset": [ + -4, + 10, + 0.545 + ] + }, + { + "EquipmentID": 20009, + "Release": true, + "EquipmentName": { + "Hash": 11402115896427763107 + }, + "Rarity": "CombatPowerLightconeRarity3", + "AvatarBaseType": "Warrior", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 1, + "SkillID": 20009, + "ExpProvide": 500, + "CoinCost": 250, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/20009.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/20009.png", + "ItemRightPanelOffset": [ + 0, + -62, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + -90, + 1.15 + ], + "BattleDialogOffset": [ + 22, + 24, + 0.75 + ], + "GachaResultOffset": [ + -11, + 5, + 0.545 + ] + }, + { + "EquipmentID": 20010, + "Release": true, + "EquipmentName": { + "Hash": 13332347318490615628 + }, + "Rarity": "CombatPowerLightconeRarity3", + "AvatarBaseType": "Knight", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 1, + "SkillID": 20010, + "ExpProvide": 500, + "CoinCost": 250, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/20010.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/20010.png", + "ItemRightPanelOffset": [ + 0, + 110, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + 90, + 1.15 + ], + "BattleDialogOffset": [ + -28, + 14, + 0.75 + ], + "GachaResultOffset": [ + -17, + -9, + 0.545 + ] + }, + { + "EquipmentID": 20011, + "Release": true, + "EquipmentName": { + "Hash": 17785355910974162683 + }, + "Rarity": "CombatPowerLightconeRarity3", + "AvatarBaseType": "Warlock", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 1, + "SkillID": 20011, + "ExpProvide": 500, + "CoinCost": 250, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/20011.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/20011.png", + "ItemRightPanelOffset": [ + 0, + 82, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + 105, + 1.15 + ], + "BattleDialogOffset": [ + 32, + -25, + 0.75 + ], + "GachaResultOffset": [ + 12, + -7, + 0.545 + ] + }, + { + "EquipmentID": 20012, + "Release": true, + "EquipmentName": { + "Hash": 12247399936092798494 + }, + "Rarity": "CombatPowerLightconeRarity3", + "AvatarBaseType": "Shaman", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 1, + "SkillID": 20012, + "ExpProvide": 500, + "CoinCost": 250, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/20012.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/20012.png", + "ItemRightPanelOffset": [ + 0, + 28, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + 0, + 1.15 + ], + "BattleDialogOffset": [ + -1, + -56, + 0.75 + ], + "GachaResultOffset": [ + -1, + -6, + 0.545 + ] + }, + { + "EquipmentID": 20013, + "Release": true, + "EquipmentName": { + "Hash": 17410807256696397784 + }, + "Rarity": "CombatPowerLightconeRarity3", + "AvatarBaseType": "Mage", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 1, + "SkillID": 20013, + "ExpProvide": 500, + "CoinCost": 250, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/20013.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/20013.png", + "ItemRightPanelOffset": [ + 0, + 143, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + 150, + 1.15 + ], + "BattleDialogOffset": [ + 91, + -62, + 0.75 + ], + "GachaResultOffset": [ + -1, + -6, + 0.545 + ] + }, + { + "EquipmentID": 20014, + "Release": true, + "EquipmentName": { + "Hash": 2319508155290238659 + }, + "Rarity": "CombatPowerLightconeRarity3", + "AvatarBaseType": "Rogue", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 1, + "SkillID": 20014, + "ExpProvide": 500, + "CoinCost": 250, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/20014.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/20014.png", + "ItemRightPanelOffset": [ + 0, + -51, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + -51, + 1.15 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 20015, + "Release": true, + "EquipmentName": { + "Hash": 13040055884517558711 + }, + "Rarity": "CombatPowerLightconeRarity3", + "AvatarBaseType": "Priest", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 1, + "SkillID": 20015, + "ExpProvide": 500, + "CoinCost": 250, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/20015.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/20015.png", + "ItemRightPanelOffset": [ + 0, + -24, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + -20, + 1.15 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 20016, + "Release": true, + "EquipmentName": { + "Hash": 11103093482623620642 + }, + "Rarity": "CombatPowerLightconeRarity3", + "AvatarBaseType": "Warrior", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 1, + "SkillID": 20016, + "ExpProvide": 500, + "CoinCost": 250, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/20016.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/20016.png", + "ItemRightPanelOffset": [ + 0, + 114, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + 114, + 1.15 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 20017, + "Release": true, + "EquipmentName": { + "Hash": 13879749833137113727 + }, + "Rarity": "CombatPowerLightconeRarity3", + "AvatarBaseType": "Knight", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 1, + "SkillID": 20017, + "ExpProvide": 500, + "CoinCost": 250, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/20017.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/20017.png", + "ItemRightPanelOffset": [ + 0, + 85, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + 85, + 1.15 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 20018, + "Release": true, + "EquipmentName": { + "Hash": 12247613731536879846 + }, + "Rarity": "CombatPowerLightconeRarity3", + "AvatarBaseType": "Warlock", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 1, + "SkillID": 20018, + "ExpProvide": 500, + "CoinCost": 250, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/20018.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/20018.png", + "ItemRightPanelOffset": [ + 0, + -82, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + -90, + 1.15 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 20019, + "Release": true, + "EquipmentName": { + "Hash": 15032070239134334540 + }, + "Rarity": "CombatPowerLightconeRarity3", + "AvatarBaseType": "Shaman", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 1, + "SkillID": 20019, + "ExpProvide": 500, + "CoinCost": 250, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/20019.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/20019.png", + "ItemRightPanelOffset": [ + 0, + 15, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + 20, + 1.15 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 20020, + "Release": true, + "EquipmentName": { + "Hash": 12568713156998545906 + }, + "Rarity": "CombatPowerLightconeRarity3", + "AvatarBaseType": "Mage", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 1, + "SkillID": 20020, + "ExpProvide": 500, + "CoinCost": 250, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/20020.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/20020.png", + "ItemRightPanelOffset": [ + 0, + 30, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + 30, + 1.15 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 21000, + "Release": true, + "EquipmentName": { + "Hash": 2167454448275708155 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Priest", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21000, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21000.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21000.png", + "ItemRightPanelOffset": [ + 0, + -138, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + -128, + 1.15 + ], + "BattleDialogOffset": [ + 0, + 0, + 0.55 + ], + "GachaResultOffset": [ + 8, + -11, + 0.5123 + ] + }, + { + "EquipmentID": 21001, + "Release": true, + "EquipmentName": { + "Hash": 7552929900027690675 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Warlock", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21001, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21001.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21001.png", + "ItemRightPanelOffset": [ + 0, + -15, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + 10, + 1.15 + ], + "BattleDialogOffset": [ + 0, + 0, + 0.55 + ], + "GachaResultOffset": [ + 0, + 12, + 0.545 + ] + }, + { + "EquipmentID": 21002, + "Release": true, + "EquipmentName": { + "Hash": 14499399798298365304 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Knight", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21002, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21002.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21002.png", + "ItemRightPanelOffset": [ + 0, + -148, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + -150, + 1.15 + ], + "BattleDialogOffset": [ + 0, + 0, + 0.55 + ], + "GachaResultOffset": [ + -6, + -43, + 0.6867 + ] + }, + { + "EquipmentID": 21003, + "Release": true, + "EquipmentName": { + "Hash": 12928749239135264942 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Rogue", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21003, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21003.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21003.png", + "ItemRightPanelOffset": [ + 0, + -99, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + -90, + 1.15 + ], + "BattleDialogOffset": [ + 0, + 0, + 0.55 + ], + "GachaResultOffset": [ + -8, + -6, + 0.4905 + ] + }, + { + "EquipmentID": 21004, + "Release": true, + "EquipmentName": { + "Hash": 10427242296541626113 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Shaman", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21004, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21004.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21004.png", + "ItemRightPanelOffset": [ + 0, + -45, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + -12, + 1.15 + ], + "BattleDialogOffset": [ + 0, + 0, + 0.55 + ], + "GachaResultOffset": [ + 0, + -6, + 0.4905 + ] + }, + { + "EquipmentID": 21005, + "Release": true, + "EquipmentName": { + "Hash": 10839077926966289407 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Warrior", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21005, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21005.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21005.png", + "ItemRightPanelOffset": [ + 0, + -42, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + -30, + 1.15 + ], + "BattleDialogOffset": [ + 0, + 0, + 0.55 + ], + "GachaResultOffset": [ + 1, + 7, + 0.763 + ] + }, + { + "EquipmentID": 21006, + "Release": true, + "EquipmentName": { + "Hash": 14111965920986505827 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Mage", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21006, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21006.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21006.png", + "ItemRightPanelOffset": [ + 0, + -120, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + -130, + 1.15 + ], + "BattleDialogOffset": [ + 0, + 0, + 0.55 + ], + "GachaResultOffset": [ + 0, + -10, + 0.5123 + ] + }, + { + "EquipmentID": 21008, + "Release": true, + "EquipmentName": { + "Hash": 7595585734525049293 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Warlock", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21008, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21008.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21008.png", + "ItemRightPanelOffset": [ + 0, + -130, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + -132, + 1.15 + ], + "BattleDialogOffset": [ + 0, + 0, + 0.55 + ], + "GachaResultOffset": [ + 7, + -19, + 0.5777 + ] + }, + { + "EquipmentID": 21009, + "Release": true, + "EquipmentName": { + "Hash": 1697621481831882137 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Knight", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21009, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21009.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21009.png", + "ItemRightPanelOffset": [ + 0, + -130, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + -139, + 1.15 + ], + "BattleDialogOffset": [ + -12, + -40, + 0.75 + ], + "GachaResultOffset": [ + -6, + -19, + 0.545 + ] + }, + { + "EquipmentID": 21010, + "Release": true, + "EquipmentName": { + "Hash": 12749567746103982808 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Rogue", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21010, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21010.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21010.png", + "ItemRightPanelOffset": [ + 0, + -137, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + -139, + 1.15 + ], + "BattleDialogOffset": [ + 32, + -63, + 0.75 + ], + "GachaResultOffset": [ + -9, + -24, + 0.5777 + ] + }, + { + "EquipmentID": 21011, + "Release": true, + "EquipmentName": { + "Hash": 13158293906785266925 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Shaman", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21011, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21011.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21011.png", + "ItemRightPanelOffset": [ + 0, + -155, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + -146, + 1.15 + ], + "BattleDialogOffset": [ + -14, + -40, + 0.75 + ], + "GachaResultOffset": [ + 0, + -35, + 0.6758 + ] + }, + { + "EquipmentID": 21012, + "Release": true, + "EquipmentName": { + "Hash": 7988605493025865868 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Warrior", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21012, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21012.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21012.png", + "ItemRightPanelOffset": [ + 0, + -120, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + -132, + 1.15 + ], + "BattleDialogOffset": [ + 0, + 0, + 0.55 + ], + "GachaResultOffset": [ + -3, + -38, + 0.654 + ] + }, + { + "EquipmentID": 21013, + "Release": true, + "EquipmentName": { + "Hash": 162961089588416007 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Mage", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21013, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21013.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21013.png", + "ItemRightPanelOffset": [ + 0, + -77, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + -92, + 1.15 + ], + "BattleDialogOffset": [ + 41, + 0, + 0.55 + ], + "GachaResultOffset": [ + 44, + -38, + 0.872 + ] + }, + { + "EquipmentID": 21014, + "Release": true, + "EquipmentName": { + "Hash": 13174243432611028231 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Priest", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21014, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21014.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21014.png", + "ItemRightPanelOffset": [ + -60, + -175, + 0.9 + ], + "AvatarDetailOffset": [ + -69, + -188, + 1.5 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 21015, + "Release": true, + "EquipmentName": { + "Hash": 13745399009822153287 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Warlock", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21015, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21015.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21015.png", + "ItemRightPanelOffset": [ + -11, + -179, + 0.7 + ], + "AvatarDetailOffset": [ + -22, + -163, + 1.15 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 21016, + "Release": true, + "EquipmentName": { + "Hash": 1574056865504538423 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Knight", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21016, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21016.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21016.png", + "ItemRightPanelOffset": [ + 0, + -139, + 0.85 + ], + "AvatarDetailOffset": [ + 0, + -129, + 1.2 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 21017, + "Release": true, + "EquipmentName": { + "Hash": 16799517243763151061 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Rogue", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21017, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21017.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21017.png", + "ItemRightPanelOffset": [ + 0, + -151, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + -151, + 1.15 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 21018, + "Release": true, + "EquipmentName": { + "Hash": 2617276305345465640 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Shaman", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21018, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21018.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21018.png", + "ItemRightPanelOffset": [ + 0, + -84, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + -75, + 1 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 21019, + "Release": true, + "EquipmentName": { + "Hash": 7087158918269789482 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Warrior", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21019, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21019.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21019.png", + "ItemRightPanelOffset": [ + 0, + -10, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + -10, + 1.15 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 21020, + "Release": true, + "EquipmentName": { + "Hash": 3011459729684543498 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Mage", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21020, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21020.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21020.png", + "ItemRightPanelOffset": [ + 85, + -100, + 1 + ], + "AvatarDetailOffset": [ + 79, + -94, + 1.5 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 21021, + "Release": true, + "EquipmentName": { + "Hash": 5213115940555228162 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Priest", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21021, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21021.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21021.png", + "ItemRightPanelOffset": [ + 0, + -82, + 0.66 + ], + "AvatarDetailOffset": [ + 0, + -78, + 1.01 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 21022, + "Release": true, + "EquipmentName": { + "Hash": 11556837653135001833 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Warlock", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21022, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21022.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21022.png", + "ItemRightPanelOffset": [ + 0, + 1.5, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + 3, + 1.15 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 21023, + "Release": true, + "EquipmentName": { + "Hash": 2437893704371924013 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Knight", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21023, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21023.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21023.png", + "ItemRightPanelOffset": [ + 0, + -38, + 0.66 + ], + "AvatarDetailOffset": [ + 0, + -34, + 1.01 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 21024, + "Release": true, + "EquipmentName": { + "Hash": 7199060513447123746 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Rogue", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21024, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21024.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21024.png", + "ItemRightPanelOffset": [ + 40, + -192, + 0.9 + ], + "AvatarDetailOffset": [ + 27, + -204, + 1.5 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 21026, + "Release": true, + "EquipmentName": { + "Hash": 2865330475640667594 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Warrior", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21026, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21026.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21026.png", + "ItemRightPanelOffset": [ + 0, + -122, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + -142, + 1.15 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 21027, + "Release": true, + "EquipmentName": { + "Hash": 10425213309433675372 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Mage", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21027, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21027.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21027.png", + "ItemRightPanelOffset": [ + 0, + -78, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + -78, + 1.15 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 21028, + "Release": true, + "EquipmentName": { + "Hash": 9790535670345159450 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Priest", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21028, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21028.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21028.png", + "ItemRightPanelOffset": [ + 0, + -58, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + -64, + 1.15 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 21029, + "Release": true, + "EquipmentName": { + "Hash": 16240711282141343645 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Warlock", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21029, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21029.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21029.png", + "ItemRightPanelOffset": [ + 0, + -100, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + -100, + 1.15 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 21030, + "Release": true, + "EquipmentName": { + "Hash": 12664422904687735233 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Knight", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21030, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21030.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21030.png", + "ItemRightPanelOffset": [ + 0, + -8, + 0.67 + ], + "AvatarDetailOffset": [ + 0, + -18, + 1.15 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 21031, + "Release": true, + "EquipmentName": { + "Hash": 9181486690944903166 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Rogue", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21031, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21031.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21031.png", + "ItemRightPanelOffset": [ + -10, + -92, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + -89, + 1.01 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 21032, + "Release": true, + "EquipmentName": { + "Hash": 12162768609723681896 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Shaman", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21032, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21032.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21032.png", + "ItemRightPanelOffset": [ + 0, + -58, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + -58, + 1.15 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 21033, + "Release": true, + "EquipmentName": { + "Hash": 14096160680959455656 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Warrior", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21033, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21033.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21033.png", + "ItemRightPanelOffset": [ + 0, + -133, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + -124, + 1.15 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 21034, + "Release": true, + "EquipmentName": { + "Hash": 4457157234821228851 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Mage", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21034, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21034.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21034.png", + "ItemRightPanelOffset": [ + 0, + -77, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + -77, + 1.15 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 22000, + "Release": true, + "EquipmentName": { + "Hash": 6499212577580680601 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Warlock", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 22000, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [ + 121000 + ], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/22000.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/22000.png", + "ItemRightPanelOffset": [ + -11, + -30, + 0.8 + ], + "AvatarDetailOffset": [ + -18, + -20, + 1.15 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 23000, + "Release": true, + "EquipmentName": { + "Hash": 15382217452095502614 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Mage", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23000, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23000.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23000.png", + "ItemRightPanelOffset": [ + 0, + -143, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + -158, + 1.15 + ], + "BattleDialogOffset": [ + 0, + 0, + 0.75 + ], + "GachaResultOffset": [ + -3, + -96, + 1.09 + ] + }, + { + "EquipmentID": 23001, + "Release": true, + "EquipmentName": { + "Hash": 8801957355485281282 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Rogue", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23001, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23001.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23001.png", + "ItemRightPanelOffset": [ + 0, + -118, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + -133, + 1.15 + ], + "BattleDialogOffset": [ + 44, + -0, + 0.6 + ], + "GachaResultOffset": [ + 49, + -68, + 0.981 + ] + }, + { + "EquipmentID": 23002, + "Release": true, + "EquipmentName": { + "Hash": 12383480154175459629 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Warrior", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23002, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23002.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23002.png", + "ItemRightPanelOffset": [ + 0, + -122, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + -126, + 1.15 + ], + "BattleDialogOffset": [ + -12, + -40, + 0.75 + ], + "GachaResultOffset": [ + 4, + -43, + 0.7085 + ] + }, + { + "EquipmentID": 23003, + "Release": true, + "EquipmentName": { + "Hash": 8522650187971319173 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Shaman", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23003, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23003.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23003.png", + "ItemRightPanelOffset": [ + 0, + -58, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + -50, + 1.15 + ], + "BattleDialogOffset": [ + 15, + -24, + 0.75 + ], + "GachaResultOffset": [ + 7, + 6, + 0.763 + ] + }, + { + "EquipmentID": 23004, + "Release": true, + "EquipmentName": { + "Hash": 10183975544059560062 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Warlock", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23004, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23004.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23004.png", + "ItemRightPanelOffset": [ + 0, + -137, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + -168, + 1.15 + ], + "BattleDialogOffset": [ + -22, + 0, + 0.6 + ], + "GachaResultOffset": [ + -18, + -45, + 0.6758 + ] + }, + { + "EquipmentID": 23005, + "Release": true, + "EquipmentName": { + "Hash": 7937757985821192715 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Knight", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23005, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23005.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23005.png", + "ItemRightPanelOffset": [ + 0, + -140, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + -145, + 1.15 + ], + "BattleDialogOffset": [ + -22, + 0, + 0.6 + ], + "GachaResultOffset": [ + -36, + -51, + 0.7412 + ] + }, + { + "EquipmentID": 23006, + "Release": true, + "EquipmentName": { + "Hash": 17574691798561298326 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Warlock", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23006, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23006.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23006.png", + "ItemRightPanelOffset": [ + 0, + -100, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + -76, + 1.15 + ], + "BattleDialogOffset": [ + 0, + 0, + 0.55 + ], + "GachaResultOffset": [ + 0, + -5, + 0.5777 + ] + }, + { + "EquipmentID": 23007, + "Release": true, + "EquipmentName": { + "Hash": 12681543763079713620 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Warlock", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23007, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23007.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23007.png", + "ItemRightPanelOffset": [ + 0, + -60, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + -68, + 1.15 + ], + "BattleDialogOffset": [ + 0, + -68, + 1.15 + ], + "GachaResultOffset": [ + -20, + 1, + 0.4905 + ] + }, + { + "EquipmentID": 23008, + "Release": true, + "EquipmentName": { + "Hash": 14622040109051771747 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Priest", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23008, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23008.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23008.png", + "ItemRightPanelOffset": [ + 0, + -126, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + -120, + 1.15 + ], + "BattleDialogOffset": [ + 33, + 0, + 0.55 + ], + "GachaResultOffset": [ + 35, + -25, + 0.5668 + ] + }, + { + "EquipmentID": 23009, + "Release": true, + "EquipmentName": { + "Hash": 9878785544467344708 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Warrior", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23009, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23009.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23009.png", + "ItemRightPanelOffset": [ + 0, + -172, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + -175, + 1.15 + ], + "BattleDialogOffset": [ + 32, + -63, + 0.75 + ], + "GachaResultOffset": [ + -80, + -84, + 0.872 + ] + }, + { + "EquipmentID": 23010, + "Release": true, + "EquipmentName": { + "Hash": 5016139085509664328 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Mage", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23010, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23010.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23010.png", + "ItemRightPanelOffset": [ + 0, + -106, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + -126, + 1.15 + ], + "BattleDialogOffset": [ + 33, + 0, + 0.55 + ], + "GachaResultOffset": [ + -23, + -25, + 0.5995 + ] + }, + { + "EquipmentID": 23011, + "Release": true, + "EquipmentName": { + "Hash": 4097943518132692404 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Knight", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23011, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23011.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23011.png", + "ItemRightPanelOffset": [ + 0, + -106, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + -106, + 1.15 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 23012, + "Release": true, + "EquipmentName": { + "Hash": 3988416931465964572 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Rogue", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23012, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23012.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23012.png", + "ItemRightPanelOffset": [ + 0, + 15, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + 15, + 1.15 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 23013, + "Release": true, + "EquipmentName": { + "Hash": 2939788966008364272 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Priest", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23013, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23013.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23013.png", + "ItemRightPanelOffset": [ + 0, + -115, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + -115, + 1.15 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 23014, + "Release": true, + "EquipmentName": { + "Hash": 8896320544221495485 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Warrior", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23014, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23014.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23014.png", + "ItemRightPanelOffset": [ + -38, + -284, + 1.2 + ], + "AvatarDetailOffset": [ + -37, + -260, + 1.8 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 23015, + "Release": true, + "EquipmentName": { + "Hash": 5882077875757512131 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Warrior", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23015, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23015.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23015.png", + "ItemRightPanelOffset": [ + 0, + -80, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + -75, + 1 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 23016, + "Release": true, + "EquipmentName": { + "Hash": 6338477157066304065 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Rogue", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23016, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23016.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23016.png", + "ItemRightPanelOffset": [ + 15, + -235, + 1.05 + ], + "AvatarDetailOffset": [ + 14, + -210, + 1.6 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 24000, + "Release": true, + "EquipmentName": { + "Hash": 4075116411984711274 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Warrior", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 24000, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [ + 271 + ], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/24000.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/24000.png", + "ItemRightPanelOffset": [ + 0, + -107, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + -122, + 1.15 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 24001, + "Release": true, + "EquipmentName": { + "Hash": 6397781049354459849 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Rogue", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 24001, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [ + 271 + ], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/24001.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/24001.png", + "ItemRightPanelOffset": [ + 0, + -13, + 0.7 + ], + "AvatarDetailOffset": [ + 20, + -9, + 1.15 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 24002, + "Release": true, + "EquipmentName": { + "Hash": 2383987427860701439 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Knight", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 24002, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [ + 271 + ], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/24002.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/24002.png", + "ItemRightPanelOffset": [ + 0, + -51, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + -55, + 1.15 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 21025, + "Release": true, + "EquipmentName": { + "Hash": 6669890141724855046 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Shaman", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21025, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21025.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21025.png", + "ItemRightPanelOffset": [ + 10, + -153, + 0.7 + ], + "AvatarDetailOffset": [ + 46, + -200, + 1.41 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 23017, + "Release": true, + "EquipmentName": { + "Hash": 6652371494884618152 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Priest", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23017, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23017.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23017.png", + "ItemRightPanelOffset": [ + -10, + -90, + 0.7 + ], + "AvatarDetailOffset": [ + -12, + -88, + 1.1 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 23018, + "Release": true, + "EquipmentName": { + "Hash": 7806293657413569732 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Mage", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23018, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23018.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23018.png", + "ItemRightPanelOffset": [ + -15, + -140, + 0.75 + ], + "AvatarDetailOffset": [ + -1, + -111, + 1.03 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 23019, + "Release": true, + "EquipmentName": { + "Hash": 6511942529766525790 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Shaman", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23019, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23019.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23019.png", + "ItemRightPanelOffset": [ + 0, + 5, + 0.71 + ], + "AvatarDetailOffset": [ + 0, + 18, + 1.01 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 23021, + "Release": true, + "EquipmentName": { + "Hash": 13392063733437188899 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Shaman", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23021, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23021.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23021.png", + "ItemRightPanelOffset": [ + 8, + -173, + 0.82 + ], + "AvatarDetailOffset": [ + 16, + -162, + 1.35 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 23023, + "Release": true, + "EquipmentName": { + "Hash": 16572767459975564925 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Knight", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23023, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23023.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23023.png", + "ItemRightPanelOffset": [ + 6, + -138, + 0.71 + ], + "AvatarDetailOffset": [ + 4, + -130, + 1.1 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 23020, + "Release": true, + "EquipmentName": { + "Hash": 13217917909606342578 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Rogue", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23020, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23020.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23020.png", + "ItemRightPanelOffset": [ + 0, + -70, + 0.67 + ], + "AvatarDetailOffset": [ + 0, + -62, + 1.02 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 24003, + "Release": true, + "EquipmentName": { + "Hash": 6603370301531956729 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Warlock", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 24003, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [ + 271 + ], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/24003.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/24003.png", + "ItemRightPanelOffset": [ + 0, + -50, + 0.68 + ], + "AvatarDetailOffset": [ + 0, + -47, + 1 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 21035, + "Release": true, + "EquipmentName": { + "Hash": 14618451847251881593 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Priest", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21035, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21035.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21035.png", + "ItemRightPanelOffset": [ + 4, + -4, + 0.68 + ], + "AvatarDetailOffset": [ + 0, + 11, + 1.05 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 21036, + "Release": true, + "EquipmentName": { + "Hash": 7190155227974321848 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Shaman", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21036, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21036.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21036.png", + "ItemRightPanelOffset": [ + 0, + 60, + 0.67 + ], + "AvatarDetailOffset": [ + 0, + 63, + 1.02 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 21037, + "Release": true, + "EquipmentName": { + "Hash": 11986294710949841576 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Rogue", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21037, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21037.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21037.png", + "ItemRightPanelOffset": [ + 28, + -95, + 0.78 + ], + "AvatarDetailOffset": [ + 29, + -80, + 1.2 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 21038, + "Release": true, + "EquipmentName": { + "Hash": 15061106384238445075 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Warrior", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21038, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21038.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21038.png", + "ItemRightPanelOffset": [ + -55, + -213, + 0.95 + ], + "AvatarDetailOffset": [ + -45, + -177, + 1.3 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 21039, + "Release": true, + "EquipmentName": { + "Hash": 17221523966150677749 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Knight", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21039, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21039.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21039.png", + "ItemRightPanelOffset": [ + -86, + -108, + 1 + ], + "AvatarDetailOffset": [ + -90, + -94, + 1.6 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 21040, + "Release": true, + "EquipmentName": { + "Hash": 11787985211097824188 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Mage", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21040, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21040.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21040.png", + "ItemRightPanelOffset": [ + 0, + -94, + 0.69 + ], + "AvatarDetailOffset": [ + 0, + -85, + 1.06 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 21041, + "Release": true, + "EquipmentName": { + "Hash": 9917675222835188030 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Warlock", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21041, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21041.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21041.png", + "ItemRightPanelOffset": [ + 0, + 80, + 0.72 + ], + "AvatarDetailOffset": [ + 0, + 83, + 1.1 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 23022, + "Release": true, + "EquipmentName": { + "Hash": 1760113629327884437 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Warlock", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23022, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23022.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23022.png", + "ItemRightPanelOffset": [ + 8, + -132, + 0.86 + ], + "AvatarDetailOffset": [ + 12, + -128, + 1.4 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 21007, + "Release": true, + "EquipmentName": { + "Hash": 1689191955197149654 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Priest", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21007, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21007.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21007.png", + "ItemRightPanelOffset": [ + 0, + -70, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + -62, + 1.15 + ], + "BattleDialogOffset": [ + 32, + -63, + 0.75 + ], + "GachaResultOffset": [ + -32, + -10, + 0.5123 + ] + }, + { + "EquipmentID": 24004, + "Release": true, + "EquipmentName": { + "Hash": 15435895158678403029 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Mage", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 24004, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [ + 271 + ], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/24004.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/24004.png", + "ItemRightPanelOffset": [ + 0, + -20, + 0.66 + ], + "AvatarDetailOffset": [ + 0, + -2.5, + 1.01 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 22001, + "Release": true, + "EquipmentName": { + "Hash": 5044439088801606790 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Priest", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 22001, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [ + 121001 + ], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/22001.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/22001.png", + "ItemRightPanelOffset": [ + 0, + -62, + 0.75 + ], + "AvatarDetailOffset": [ + 0, + -47, + 1.1 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 23024, + "Release": true, + "EquipmentName": { + "Hash": 2304736168270673834 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Warlock", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23024, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23024.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23024.png", + "ItemRightPanelOffset": [ + 6, + 221, + 1.05 + ], + "AvatarDetailOffset": [ + 8, + 273, + 1.9 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 23025, + "Release": true, + "EquipmentName": { + "Hash": 5533133162833624556 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Warrior", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23025, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23025.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23025.png", + "ItemRightPanelOffset": [ + 9, + -135, + 0.7 + ], + "AvatarDetailOffset": [ + 3, + -118, + 1.05 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 21042, + "Release": true, + "EquipmentName": { + "Hash": 10092969236133299188 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Warrior", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21042, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21042.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21042.png", + "ItemRightPanelOffset": [ + 0, + -70, + 0.68 + ], + "AvatarDetailOffset": [ + 0, + -54, + 1.02 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 21043, + "Release": true, + "EquipmentName": { + "Hash": 14152526364798022068 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Knight", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21043, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21043.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21043.png", + "ItemRightPanelOffset": [ + 46, + -44, + 0.85 + ], + "AvatarDetailOffset": [ + 45, + -30, + 1.3 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 23027, + "Release": true, + "EquipmentName": { + "Hash": 16562686593279533010 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Rogue", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23027, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23027.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23027.png", + "ItemRightPanelOffset": [ + 20, + -158, + 0.82 + ], + "AvatarDetailOffset": [ + 15, + -145, + 1.25 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 23028, + "Release": true, + "EquipmentName": { + "Hash": 8391488999247369590 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Mage", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23028, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23028.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23028.png", + "ItemRightPanelOffset": [ + 4, + -160, + 0.76 + ], + "AvatarDetailOffset": [ + 4, + -147, + 1.17 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 21044, + "Release": true, + "EquipmentName": { + "Hash": 10467065315466017245 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Warlock", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21044, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21044.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21044.png", + "ItemRightPanelOffset": [ + -51, + -244, + 1.12 + ], + "AvatarDetailOffset": [ + -45, + -200, + 1.6 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 21045, + "Release": true, + "EquipmentName": { + "Hash": 2017811926861740653 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Mage", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21045, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21045.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21045.png", + "ItemRightPanelOffset": [ + -84, + -193, + 1 + ], + "AvatarDetailOffset": [ + -66, + -164, + 1.44 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 21046, + "Release": true, + "EquipmentName": { + "Hash": 7852072680209603817 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Shaman", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21046, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21046.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21046.png", + "ItemRightPanelOffset": [ + 8, + -134, + 0.74 + ], + "AvatarDetailOffset": [ + 8, + -126, + 1.15 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 21047, + "Release": true, + "EquipmentName": { + "Hash": 5449558217329844746 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Rogue", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21047, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21047.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21047.png", + "ItemRightPanelOffset": [ + -34, + -161, + 0.9 + ], + "AvatarDetailOffset": [ + -28, + -147, + 1.4 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 21048, + "Release": true, + "EquipmentName": { + "Hash": 17607126303400988571 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Priest", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21048, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21048.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21048.png", + "ItemRightPanelOffset": [ + 2, + -39, + 0.68 + ], + "AvatarDetailOffset": [ + 0, + -25, + 1.05 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 22002, + "Release": true, + "EquipmentName": { + "Hash": 12477180630545967573 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Shaman", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 22002, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [ + 121002 + ], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/22002.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/22002.png", + "ItemRightPanelOffset": [ + -14, + -217, + 1.25 + ], + "AvatarDetailOffset": [ + -15, + -184, + 1.8 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 23026, + "Release": true, + "EquipmentName": { + "Hash": 7151795079392647332 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Shaman", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23026, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23026.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23026.png", + "ItemRightPanelOffset": [ + 0, + -96, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + -78, + 1 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 23030, + "Release": true, + "EquipmentName": { + "Hash": 9582006062334260573 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Warrior", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23030, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23030.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23030.png", + "ItemRightPanelOffset": [ + -57, + -165, + 1.2 + ], + "AvatarDetailOffset": [ + -62, + -149, + 1.9 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 23029, + "Release": true, + "EquipmentName": { + "Hash": 458554896646617640 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Warlock", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23029, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23029.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23029.png", + "ItemRightPanelOffset": [ + -10, + -230, + 1.1 + ], + "AvatarDetailOffset": [ + -16, + -218, + 1.7 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 23031, + "Release": true, + "EquipmentName": { + "Hash": 14143448995387386080 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Rogue", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23031, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23031.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23031.png", + "ItemRightPanelOffset": [ + 82, + -216, + 1.1 + ], + "AvatarDetailOffset": [ + 74, + -186, + 1.65 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 23032, + "Release": true, + "EquipmentName": { + "Hash": 7711419540001836555 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Priest", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23032, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23032.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23032.png", + "ItemRightPanelOffset": [ + -34, + -132, + 0.8 + ], + "AvatarDetailOffset": [ + -33, + -121, + 1.23 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 23033, + "Release": true, + "EquipmentName": { + "Hash": 166399991008704530 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Mage", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23033, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23033.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23033.png", + "ItemRightPanelOffset": [ + 7, + -167, + 0.92 + ], + "AvatarDetailOffset": [ + 7, + -158, + 1.4 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 22003, + "Release": true, + "EquipmentName": { + "Hash": 3181001684884320491 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Warrior", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 22003, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [ + 121003 + ], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/22003.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/22003.png", + "ItemRightPanelOffset": [ + 18, + -135, + 0.8 + ], + "AvatarDetailOffset": [ + 19, + -117, + 1.2 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 23035, + "Release": true, + "EquipmentName": { + "Hash": 2365588922771791772 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Warlock", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23035, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23035.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23035.png", + "ItemRightPanelOffset": [ + 7, + -218, + 1.35 + ], + "AvatarDetailOffset": [ + -5, + -189, + 1.9 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 23034, + "Release": true, + "EquipmentName": { + "Hash": 17036794612158182092 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Shaman", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23034, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23034.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23034.png", + "ItemRightPanelOffset": [ + 2, + -80, + 0.68 + ], + "AvatarDetailOffset": [ + -6, + -83, + 1.1 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 21050, + "Release": true, + "EquipmentName": { + "Hash": 3826288517981139592 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Memory", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21050, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21050.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21050.png", + "ItemRightPanelOffset": [ + -10, + -11, + 0.8 + ], + "AvatarDetailOffset": [ + -11, + -4, + 1.2 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 23037, + "Release": true, + "EquipmentName": { + "Hash": 7647972073962524348 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Mage", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23037, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23037.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23037.png", + "ItemRightPanelOffset": [ + 51, + -156, + 1 + ], + "AvatarDetailOffset": [ + 52, + -145, + 1.5 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 20021, + "Release": true, + "EquipmentName": { + "Hash": 8589021141704183905 + }, + "Rarity": "CombatPowerLightconeRarity3", + "AvatarBaseType": "Memory", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 1, + "SkillID": 20021, + "ExpProvide": 500, + "CoinCost": 250, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/20021.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/20021.png", + "ItemRightPanelOffset": [ + 13, + 118, + 0.75 + ], + "AvatarDetailOffset": [ + 12, + 115, + 1.1 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 20022, + "Release": true, + "EquipmentName": { + "Hash": 3133619668689285080 + }, + "Rarity": "CombatPowerLightconeRarity3", + "AvatarBaseType": "Memory", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 1, + "SkillID": 20022, + "ExpProvide": 500, + "CoinCost": 250, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/20022.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/20022.png", + "ItemRightPanelOffset": [ + -6, + -6, + 0.68 + ], + "AvatarDetailOffset": [ + -6, + -9, + 1.05 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 21051, + "Release": true, + "EquipmentName": { + "Hash": 6987783680196069182 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Memory", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21051, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21051.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21051.png", + "ItemRightPanelOffset": [ + -13, + -118, + 0.75 + ], + "AvatarDetailOffset": [ + -9, + -95, + 1.1 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 21052, + "Release": true, + "EquipmentName": { + "Hash": 2812952012494006470 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Memory", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21052, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21052.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21052.png", + "ItemRightPanelOffset": [ + 75, + -136, + 1 + ], + "AvatarDetailOffset": [ + 68, + -114, + 1.45 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 23036, + "Release": true, + "EquipmentName": { + "Hash": 12998084085250275171 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Memory", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23036, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23036.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23036.png", + "ItemRightPanelOffset": [ + 6, + -104, + 0.8 + ], + "AvatarDetailOffset": [ + 11, + -94, + 1.2 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 23038, + "Release": true, + "EquipmentName": { + "Hash": 5079774664946893569 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Shaman", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23038, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23038.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23038.png", + "ItemRightPanelOffset": [ + 1, + -93, + 0.84 + ], + "AvatarDetailOffset": [ + 2, + -86, + 1.3 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 24005, + "Release": true, + "EquipmentName": { + "Hash": 10592306546445443705 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Memory", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 24005, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [ + 271 + ], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/24005.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/24005.png", + "ItemRightPanelOffset": [ + 1, + -90, + 0.7 + ], + "AvatarDetailOffset": [ + 1, + -86, + 1.1 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 23039, + "Release": true, + "EquipmentName": { + "Hash": 10640455180150177057 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Warrior", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23039, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23039.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23039.png", + "ItemRightPanelOffset": [ + 41, + -160, + 0.91 + ], + "AvatarDetailOffset": [ + 38, + -148, + 1.4 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 23042, + "Release": true, + "EquipmentName": { + "Hash": 1992513852031797087 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Memory", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23042, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23042.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23042.png", + "ItemRightPanelOffset": [ + -65, + -114, + 0.95 + ], + "AvatarDetailOffset": [ + -64, + -102, + 1.45 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 23041, + "Release": true, + "EquipmentName": { + "Hash": 12290078682480906936 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Mage", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23041, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23041.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23041.png", + "ItemRightPanelOffset": [ + 0, + -95, + 0.72 + ], + "AvatarDetailOffset": [ + -3, + -79, + 1.07 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 23040, + "Release": true, + "EquipmentName": { + "Hash": 17921507779222204537 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Memory", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23040, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23040.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23040.png", + "ItemRightPanelOffset": [ + 2, + -74, + 0.67 + ], + "AvatarDetailOffset": [ + 3, + -68, + 1.03 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 22004, + "Release": true, + "EquipmentName": { + "Hash": 14528966166175872583 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Mage", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 22004, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [ + 121004 + ], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/22004.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/22004.png", + "ItemRightPanelOffset": [ + 2, + 124, + 0.7 + ], + "AvatarDetailOffset": [ + -3, + 126, + 1.05 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 21053, + "Release": true, + "EquipmentName": { + "Hash": 8374190943812153532 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Knight", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21053, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21053.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21053.png", + "ItemRightPanelOffset": [ + 1, + -62, + 0.68 + ], + "AvatarDetailOffset": [ + 2, + -57, + 1.05 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 21054, + "Release": true, + "EquipmentName": { + "Hash": 925285841184946344 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Memory", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21054, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21054.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21054.png", + "ItemRightPanelOffset": [ + 11, + -120, + 0.8 + ], + "AvatarDetailOffset": [ + 14, + -102, + 1.2 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 21055, + "Release": true, + "EquipmentName": { + "Hash": 8234482625723588709 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Priest", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21055, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21055.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21055.png", + "ItemRightPanelOffset": [ + 7, + -112, + 0.69 + ], + "AvatarDetailOffset": [ + 2, + -92, + 1.02 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 21056, + "Release": true, + "EquipmentName": { + "Hash": 13758363745381237568 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Shaman", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21056, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21056.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21056.png", + "ItemRightPanelOffset": [ + -5, + -60, + 0.68 + ], + "AvatarDetailOffset": [ + 0, + -52, + 1.02 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 21057, + "Release": true, + "EquipmentName": { + "Hash": 9049859548954827221 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Memory", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21057, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21057.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21057.png", + "ItemRightPanelOffset": [ + 21, + 14, + 0.84 + ], + "AvatarDetailOffset": [ + 21, + 27, + 1.28 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 21058, + "Release": true, + "EquipmentName": { + "Hash": 7494166407242075795 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Warrior", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21058, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21058.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21058.png", + "ItemRightPanelOffset": [ + 15, + -108, + 0.73 + ], + "AvatarDetailOffset": [ + 16, + -98, + 1.12 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 21060, + "Release": true, + "EquipmentName": { + "Hash": 2081896813700414495 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Mage", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21060, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21060.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21060.png", + "ItemRightPanelOffset": [ + 4, + -82, + 0.68 + ], + "AvatarDetailOffset": [ + 0, + -62, + 1.02 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 21061, + "Release": true, + "EquipmentName": { + "Hash": 6535201401877376706 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Warlock", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21061, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21061.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21061.png", + "ItemRightPanelOffset": [ + -22, + -111, + 0.75 + ], + "AvatarDetailOffset": [ + -18, + -96, + 1.13 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 23043, + "Release": true, + "EquipmentName": { + "Hash": 17437100551828055817 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Warlock", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23043, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23043.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23043.png", + "ItemRightPanelOffset": [ + -7, + 75, + 0.76 + ], + "AvatarDetailOffset": [ + -8, + 77, + 1.17 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 23044, + "Release": true, + "EquipmentName": { + "Hash": 1669624186204340722 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Warrior", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23044, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23044.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23044.png", + "ItemRightPanelOffset": [ + 26, + -74, + 0.76 + ], + "AvatarDetailOffset": [ + 23, + -67, + 1.15 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 23045, + "Release": true, + "EquipmentName": { + "Hash": 2655752028575549155 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Warrior", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23045, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23045.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23045.png", + "ItemRightPanelOffset": [ + 39, + -118, + 0.84 + ], + "AvatarDetailOffset": [ + 40, + -101, + 1.27 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 23046, + "Release": true, + "EquipmentName": { + "Hash": 17063264696383380947 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Rogue", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23046, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23046.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23046.png", + "ItemRightPanelOffset": [ + 25, + -134, + 1.03 + ], + "AvatarDetailOffset": [ + 26, + -120, + 1.57 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 21062, + "Release": true, + "EquipmentName": { + "Hash": 5119764409776904864 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Rogue", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21062, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21062.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21062.png", + "ItemRightPanelOffset": [ + -111, + -167, + 1.1 + ], + "AvatarDetailOffset": [ + -89, + -145, + 1.58 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 23047, + "Release": true, + "EquipmentName": { + "Hash": 16402735087408937717 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Warlock", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23047, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23047.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23047.png", + "ItemRightPanelOffset": [ + 39, + -158, + 0.86 + ], + "AvatarDetailOffset": [ + 38, + -144, + 1.33 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 23048, + "Release": true, + "EquipmentName": { + "Hash": 6685295983161490522 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Shaman", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23048, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23048.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23048.png", + "ItemRightPanelOffset": [ + -1, + -96, + 0.91 + ], + "AvatarDetailOffset": [ + -3, + -80, + 1.38 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 22005, + "Release": true, + "EquipmentName": { + "Hash": 641298228203045566 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Shaman", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 22005, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [ + 121005 + ], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/22005.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/22005.png", + "ItemRightPanelOffset": [ + -48, + -115, + 0.85 + ], + "AvatarDetailOffset": [ + -46, + -106, + 1.3 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 22006, + "Release": true, + "EquipmentName": { + "Hash": 15207548416483397866 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Memory", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 22006, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [ + 121006 + ], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/22006.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/22006.png", + "ItemRightPanelOffset": [ + 4, + -10, + 0.68 + ], + "AvatarDetailOffset": [ + 2, + 3, + 1.02 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 23049, + "Release": true, + "EquipmentName": { + "Hash": 4836366408334833891 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Memory", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23049, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23049.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23049.png", + "ItemRightPanelOffset": [ + 37, + 18, + 0.85 + ], + "AvatarDetailOffset": [ + 34.5, + 27, + 1.3 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 23050, + "Release": true, + "EquipmentName": { + "Hash": 9307349825241855113 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Warlock", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23050, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23050.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23050.png", + "ItemRightPanelOffset": [ + -41, + -128, + 0.82 + ], + "AvatarDetailOffset": [ + -27, + -108, + 1.18 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 23051, + "Release": true, + "EquipmentName": { + "Hash": 12008774210001466871 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Knight", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23051, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23051.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23051.png", + "ItemRightPanelOffset": [ + 23.5, + -132, + 0.75 + ], + "AvatarDetailOffset": [ + 16, + -117, + 1.14 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 23052, + "Release": true, + "EquipmentName": { + "Hash": 10407794298159211059 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Memory", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23052, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23052.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23052.png", + "ItemRightPanelOffset": [ + 0, + -92, + 0.68 + ], + "AvatarDetailOffset": [ + 0, + -78, + 1.02 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 20023, + "Release": true, + "EquipmentName": { + "Hash": 17981808852139106353 + }, + "Rarity": "CombatPowerLightconeRarity3", + "AvatarBaseType": "Elation", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 1, + "SkillID": 20023, + "ExpProvide": 500, + "CoinCost": 250, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/20023.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/20023.png", + "ItemRightPanelOffset": [ + -24, + 37, + 0.75 + ], + "AvatarDetailOffset": [ + 2, + 36, + 1.05 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 20024, + "Release": true, + "EquipmentName": { + "Hash": 14442278216073659952 + }, + "Rarity": "CombatPowerLightconeRarity3", + "AvatarBaseType": "Elation", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 1, + "SkillID": 20024, + "ExpProvide": 500, + "CoinCost": 250, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/20024.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/20024.png", + "ItemRightPanelOffset": [ + 20, + -198, + 0.9 + ], + "AvatarDetailOffset": [ + 5, + -146, + 1.1 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 21064, + "Release": true, + "EquipmentName": { + "Hash": 3318507436183091065 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Elation", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21064, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21064.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21064.png", + "ItemRightPanelOffset": [ + -5, + -30, + 0.73 + ], + "AvatarDetailOffset": [ + -6, + -28, + 1.1 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 21065, + "Release": true, + "EquipmentName": { + "Hash": 9454774255307972807 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Elation", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21065, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21065.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21065.png", + "ItemRightPanelOffset": [ + 26, + -30, + 0.81 + ], + "AvatarDetailOffset": [ + 22, + -6, + 1.3 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 23053, + "Release": true, + "EquipmentName": { + "Hash": 6574050664224309043 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Elation", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23053, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23053.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23053.png", + "ItemRightPanelOffset": [ + 0, + -67, + 0.75 + ], + "AvatarDetailOffset": [ + 0, + -53, + 1.1 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 23054, + "Release": true, + "EquipmentName": { + "Hash": 5484320404804108704 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Elation", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23054, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23054.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23054.png", + "ItemRightPanelOffset": [ + 0, + -49, + 0.66 + ], + "AvatarDetailOffset": [ + 0, + -30, + 1 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 23056, + "Release": true, + "EquipmentName": { + "Hash": 580008868750168993 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Rogue", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23056, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23056.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23056.png", + "ItemRightPanelOffset": [ + 11, + -34, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + -16, + 1 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 24006, + "Release": true, + "EquipmentName": { + "Hash": 13065036285849747195 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Elation", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 24006, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [ + 271 + ], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/24006.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/24006.png", + "ItemRightPanelOffset": [ + -5, + 70, + 0.75 + ], + "AvatarDetailOffset": [ + 0, + 69, + 1.05 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 23057, + "Release": true, + "EquipmentName": { + "Hash": 18067789291542392699 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Elation", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23057, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23057.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23057.png", + "ItemRightPanelOffset": [ + 7, + -132, + 1.06 + ], + "AvatarDetailOffset": [ + 10, + -115, + 1.6 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 22007, + "Release": true, + "EquipmentName": { + "Hash": 1470137069313109545 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Elation", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 22007, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [ + 121007 + ], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/22007.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/22007.png", + "ItemRightPanelOffset": [ + 0, + 7, + 0.7 + ], + "AvatarDetailOffset": [ + 0, + 13, + 1.07 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 23059, + "Release": true, + "EquipmentName": { + "Hash": 5178844806898592560 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Warlock", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23059, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23059.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23059.png", + "ItemRightPanelOffset": [ + 6, + -150, + 0.77 + ], + "AvatarDetailOffset": [ + 4, + -123, + 1.12 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 23061, + "Release": true, + "EquipmentName": { + "Hash": 12878612287235138706 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Mage", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23061, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23061.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23061.png", + "ItemRightPanelOffset": [ + -5, + -99, + 0.73 + ], + "AvatarDetailOffset": [ + 0, + -78, + 1.05 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 23062, + "Release": true, + "EquipmentName": { + "Hash": 13693150873761509240 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Warrior", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23062, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23062.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23062.png", + "ItemRightPanelOffset": [ + 18, + 73, + 0.73 + ], + "AvatarDetailOffset": [ + 3, + 74, + 1.05 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 23060, + "Release": true, + "EquipmentName": { + "Hash": 7768214880470327395 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Mage", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23060, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23060.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23060.png", + "ItemRightPanelOffset": [ + 45, + -126, + 0.83 + ], + "AvatarDetailOffset": [ + 21, + -95, + 1.15 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 23063, + "Release": true, + "EquipmentName": { + "Hash": 1179447360796025287 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Memory", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23063, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23063.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23063.png", + "ItemRightPanelOffset": [ + -22, + -140, + 0.84 + ], + "AvatarDetailOffset": [ + -16, + -119, + 1.25 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 23064, + "Release": true, + "EquipmentName": { + "Hash": 14974151069627830085 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Elation", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23064, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23064.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23064.png", + "ItemRightPanelOffset": [ + 46, + -153, + 0.92 + ], + "AvatarDetailOffset": [ + 50, + -146, + 1.43 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 23058, + "Release": true, + "EquipmentName": { + "Hash": 12250452824306430514 + }, + "Rarity": "CombatPowerLightconeRarity5", + "AvatarBaseType": "Elation", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 3, + "SkillID": 23058, + "ExpProvide": 60000, + "CoinCost": 30000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/23058.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/23058.png", + "ItemRightPanelOffset": [ + -4, + -46, + 0.78 + ], + "AvatarDetailOffset": [ + -4, + -28, + 1.17 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 21066, + "Release": true, + "EquipmentName": { + "Hash": 3394179651702416076 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Elation", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 21066, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/21066.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/21066.png", + "ItemRightPanelOffset": [ + -8, + -113, + 0.75 + ], + "AvatarDetailOffset": [ + -4, + -88, + 1.05 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + }, + { + "EquipmentID": 22008, + "Release": true, + "EquipmentName": { + "Hash": 14250856990396693091 + }, + "Rarity": "CombatPowerLightconeRarity4", + "AvatarBaseType": "Rogue", + "MaxPromotion": 6, + "MaxRank": 5, + "ExpType": 2, + "SkillID": 22008, + "ExpProvide": 12000, + "CoinCost": 6000, + "RankUpCostList": [ + 121008 + ], + "ThumbnailPath": "SpriteOutput/LightConeMediumIcon/22008.png", + "ImagePath": "SpriteOutput/LightConeMaxFigures/22008.png", + "ItemRightPanelOffset": [ + 0, + -77, + 0.72 + ], + "AvatarDetailOffset": [ + 0, + -62, + 1.07 + ], + "BattleDialogOffset": [ + 0, + 0, + 1 + ], + "GachaResultOffset": [ + 0, + 0, + 1 + ] + } +] \ No newline at end of file diff --git a/resources/excel/GachaTypeBasicInfo.json b/resources/excel/GachaTypeBasicInfo.json new file mode 100644 index 0000000..cce7036 --- /dev/null +++ b/resources/excel/GachaTypeBasicInfo.json @@ -0,0 +1,72 @@ +[ + { + "GachaTypeID": "Normal", + "ItemCosume": 101, + "ItemPrice": 160, + "DiamondID": 1, + "GachaBar": "StandardGachaPage", + "BuyPos": { + "ShopID": 1000, + "ShopGoodID": 1000001 + } + }, + { + "GachaTypeID": "Newbie", + "ItemCosume": 101, + "ItemPrice": 160, + "DiamondID": 1, + "GachaBar": "StandardGachaPage", + "BuyPos": { + "ShopID": 1000, + "ShopGoodID": 1000001 + } + }, + { + "GachaTypeID": "AvatarUp", + "UpPropability": 50, + "ItemCosume": 102, + "ItemPrice": 160, + "DiamondID": 1, + "GachaBar": "CharacterGachaPage", + "BuyPos": { + "ShopID": 1000, + "ShopGoodID": 1000002 + } + }, + { + "GachaTypeID": "WeaponUp", + "UpPropability": 75, + "ItemCosume": 102, + "ItemPrice": 160, + "DiamondID": 1, + "GachaBar": "LightconeGachaPage", + "BuyPos": { + "ShopID": 1000, + "ShopGoodID": 1000002 + } + }, + { + "GachaTypeID": "CollaborationAvatarUp", + "UpPropability": 50, + "ItemCosume": 102, + "ItemPrice": 160, + "DiamondID": 1, + "GachaBar": "CharacterGachaPage", + "BuyPos": { + "ShopID": 1000, + "ShopGoodID": 1000002 + } + }, + { + "GachaTypeID": "CollaborationWeaponUp", + "UpPropability": 75, + "ItemCosume": 102, + "ItemPrice": 160, + "DiamondID": 1, + "GachaBar": "LightconeGachaPage", + "BuyPos": { + "ShopID": 1000, + "ShopGoodID": 1000002 + } + } +] \ No newline at end of file diff --git a/src/core/config.cpp b/src/core/config.cpp index b4b764d..6ccb866 100644 --- a/src/core/config.cpp +++ b/src/core/config.cpp @@ -105,6 +105,25 @@ bool Config::load(const std::string& path) { pick(*it, "main_character", gameplay.mainCharacter); pick(*it, "march_type", gameplay.marchType); pick(*it, "skip_missions", gameplay.skipMissions); + // Each entry is a pool id, or {"id": pool, "featured": 5* id}. + if (auto pools = it->find("limited_warp_pools"); pools != it->end() && pools->is_array()) { + gameplay.limitedWarpPools.clear(); + for (const json& entry : *pools) { + WarpBanner banner; + if (entry.is_number_unsigned()) { + banner.id = entry.get(); + } else if (entry.is_object()) { + pick(entry, "id", banner.id); + pick(entry, "featured", banner.featured); + } + if (banner.id == 0) { + logging::warn("config", "a limited_warp_pools entry has no pool id"); + continue; + } + gameplay.limitedWarpPools.push_back(banner); + } + } + pick(*it, "standard_warp_featured", gameplay.standardWarpFeatured); } return true; } diff --git a/src/core/config.h b/src/core/config.h index b7646d4..e0e52c2 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -58,6 +58,11 @@ struct PathsConfig { std::string resources = "resources"; }; +struct WarpBanner { + uint32_t id = 0; + uint32_t featured = 0; // 0 keeps the pool's own +}; + struct GameplayConfig { // auto = a srtools build replaces calyx fights and nothing else; srtools = it // replaces every fight; stage = never, always use the stage the client asked for. @@ -74,6 +79,13 @@ struct GameplayConfig { // loading screen when entering at login, a fade that rolls straight back otherwise. // Main and sub mission ids both go here. std::vector skipMissions; + // Limited warp pools offered next to the standard one, each optionally featuring another + // 5*. The beta clients list 2001, 2002, 3001 and 3002 but ship no banner art for any of + // them, and one pool without art turns the whole warp page black, so leave it empty there. + std::vector limitedWarpPools; + // A 5* character Stellar Warp features, 50/50 and guarantee included, standing in for + // the current banner the beta clients have no art for. 0 keeps it the standard pool. + uint32_t standardWarpFeatured = 0; bool missionSkipped(uint32_t id) const { return std::find(skipMissions.begin(), skipMissions.end(), id) != skipMissions.end(); diff --git a/src/data/excel.cpp b/src/data/excel.cpp index 5df2983..bfa38e1 100644 --- a/src/data/excel.cpp +++ b/src/data/excel.cpp @@ -2,6 +2,7 @@ #include #include +#include #include @@ -77,6 +78,35 @@ std::vector u32List(const json& j, const char* key) { return out; } +// "CombatPowerAvatarRarityType5", "CombatPowerLightconeRarity4": the stars are the last digit. +uint32_t rarityOf(const json& row) { + auto it = row.find("Rarity"); + if (it == row.end()) return 0; + if (it->is_number()) return static_cast(numberOf(*it)); + if (!it->is_string()) return 0; + const std::string& name = it->get_ref(); + char last = name.empty() ? '\0' : name.back(); + return (last >= '1' && last <= '9') ? static_cast(last - '0') : 0; +} + +// ".../AvatarGacha_1102.prefab" -> 1102. The Sub* prefabs belong to a grouped pool and +// give 0. +uint32_t featuredFromPrefab(const std::string& path, std::string_view stem) { + size_t slash = path.find_last_of('/'); + std::string_view file(path); + if (slash != std::string::npos) file.remove_prefix(slash + 1); + constexpr std::string_view suffix = ".prefab"; + if (file.size() <= stem.size() + suffix.size() || file.substr(0, stem.size()) != stem || + file.substr(file.size() - suffix.size()) != suffix) { + return 0; + } + std::string_view digits = file.substr(stem.size(), file.size() - stem.size() - suffix.size()); + if (digits.size() > 9 || digits.find_first_not_of("0123456789") != std::string_view::npos) { + return 0; + } + return static_cast(std::strtoul(std::string(digits).c_str(), nullptr, 10)); +} + // AvatarSkillTreeConfig.AnchorType is "Point07"; the client wants the number. uint32_t anchorNumber(const std::string& anchor) { size_t i = 0; @@ -180,6 +210,23 @@ const AvatarInfo* Tables::avatar(uint32_t id) const { return it == avatars_.end() ? nullptr : &it->second; } +const LightconeInfo* Tables::lightcone(uint32_t id) const { + auto it = lightcones_.find(id); + return it == lightcones_.end() ? nullptr : &it->second; +} + +uint32_t Tables::gachaUpChance(GachaType type) const { + switch (type) { + case GachaType::AvatarUp: + return avatarUpChance_; + case GachaType::WeaponUp: + return weaponUpChance_; + case GachaType::Normal: + break; + } + return 0; +} + const StageInfo* Tables::stage(uint32_t id) const { auto it = stages_.find(id); return it == stages_.end() ? nullptr : &it->second; @@ -331,6 +378,7 @@ bool Tables::load(const std::vector& sources) { uint64_t started = util::nowMs(); size_t used = 0; bool standardGachaFound = false; + std::unordered_map upChances; for (const std::string& dir : sources) { json doc; @@ -356,6 +404,7 @@ bool Tables::load(const std::vector& sources) { info.baseType = str(*row, "AvatarBaseType"); info.maxPromotion = u32(*row, "MaxPromotion", 6); info.maxRank = u32(*row, "MaxRank", 6); + info.rarity = rarityOf(*row); // SPNeed is in whole points; SpBarInfo counts hundredths. uint32_t spNeed = u32(*row, "SPNeed"); info.spNeed = spNeed != 0 ? spNeed * 100 : 10000; @@ -503,12 +552,48 @@ bool Tables::load(const std::vector& sources) { farmStages_.insert(stageId); } - for (const json* row : table("GachaBasicInfo.json")) { - if (standardGachaFound || str(*row, "GachaType") != "Normal") continue; + for (const json* row : table("GachaTypeBasicInfo.json")) { + std::string type = str(*row, "GachaTypeID"); + if (!type.empty()) upChances.emplace(type, u32(*row, "UpPropability")); + } + // The client throws on a pool its own table lacks, and the beta table is a six-row + // stub, so here the last source with the table wins instead of the first. + const std::vector& gachaRows = table("GachaBasicInfo.json"); + if (!gachaRows.empty()) { + gachaPools_.clear(); + standardGachaFound = false; + } + for (const json* row : gachaRows) { uint32_t id = u32(*row, "GachaID"); if (id == 0) continue; - standardGacha_.gachaId = id; - standardGachaFound = true; + std::string type = str(*row, "GachaType"); + GachaPool pool; + pool.id = id; + if (type == "Normal") { + if (standardGachaFound && id != standardGacha_.gachaId) continue; + standardGacha_.gachaId = id; + standardGachaFound = true; + } else if (type == "AvatarUp") { + pool.type = GachaType::AvatarUp; + pool.featured = featuredFromPrefab(str(*row, "PrefabPath"), "AvatarGacha_"); + } else if (type == "WeaponUp") { + pool.type = GachaType::WeaponUp; + pool.featured = featuredFromPrefab(str(*row, "PrefabPath"), "LightConeGacha_"); + } else { + continue; + } + if (pool.type != GachaType::Normal && pool.featured == 0) continue; + gachaPools_.push_back(pool); + } + + for (const json* row : table("EquipmentConfig.json")) { + uint32_t id = u32(*row, "EquipmentID"); + if (id == 0 || lightcones_.count(id) != 0) continue; + lightcones_.emplace(id, LightconeInfo{id, rarityOf(*row)}); + } + for (const json* row : table("BattlePassReward.json")) { + uint32_t item = u32(*row, "RewardItem"); + if (item != 0) battlePassRewards_.insert(item); } for (const json* row : table("GachaCeiling.json")) { if (!standardGacha_.ceilingAvatars.empty() || str(*row, "GachaType") != "Normal") { @@ -744,6 +829,24 @@ bool Tables::load(const std::vector& sources) { sortById(challenges_); sortById(challengeGroups_); sortById(peakGroups_); + sortById(gachaPools_); + + // The defaults are GachaTypeBasicInfo's own numbers, for when the table is missing. + if (auto it = upChances.find("AvatarUp"); it != upChances.end()) avatarUpChance_ = it->second; + if (auto it = upChances.find("WeaponUp"); it != upChances.end()) weaponUpChance_ = it->second; + for (GachaPool& pool : gachaPools_) pool.upChance = gachaUpChance(pool.type); + // A featured 5* the tables do not have cannot be drawn. + std::erase_if(gachaPools_, [&](const GachaPool& pool) { + if (pool.type == GachaType::AvatarUp) { + const AvatarInfo* info = avatar(pool.featured); + return info == nullptr || info->rarity != 5; + } + if (pool.type == GachaType::WeaponUp) { + const LightconeInfo* info = lightcone(pool.featured); + return info == nullptr || info->rarity != 5; + } + return false; + }); // Each fight learns its season, and plants its one monster over the arena's marker. for (const PeakGroupInfo& group : peakGroups_) { @@ -779,6 +882,7 @@ bool Tables::load(const std::vector& sources) { entrances_.size(), planeEvents_.size(), used, util::nowMs() - started); logging::info("data", "{} challenge floors in {} seasons, {} of them with a third node", challenges_.size(), challengeGroups_.size(), challengeTierces_.size()); + logging::info("data", "{} lightcones, {} warp pools", lightcones_.size(), gachaPools_.size()); logging::info("data", "{} main missions, {} tutorials, {} guides, {} quests", mainMissions_.size(), tutorials_.size(), tutorialGuides_.size(), quests_.size()); diff --git a/src/data/excel.h b/src/data/excel.h index 99d546e..ff3a791 100644 --- a/src/data/excel.h +++ b/src/data/excel.h @@ -18,6 +18,7 @@ struct AvatarInfo { uint32_t spNeed = 10000; // hundredths, as the SpBarInfo wants it uint32_t maxPromotion = 6; uint32_t maxRank = 6; + uint32_t rarity = 0; uint32_t enhancedId = 0; uint32_t attackBuffId = 0; // AvatarDefaultMazeBuff; falls back to id * 100 + 1 when the row is missing. @@ -25,6 +26,21 @@ struct AvatarInfo { uint32_t techniqueSkillIndex = 2; }; +struct LightconeInfo { + uint32_t id = 0; + uint32_t rarity = 0; +}; + +enum class GachaType { Normal, AvatarUp, WeaponUp }; + +// A warp pool. A limited one is named after its featured 5* in its prefab. +struct GachaPool { + uint32_t id = 0; + GachaType type = GachaType::Normal; + uint32_t featured = 0; + uint32_t upChance = 0; // percent +}; + struct SkillTreePoint { uint32_t pointId = 0; uint32_t avatarId = 0; @@ -247,6 +263,15 @@ public: uint32_t farmElementStage(uint32_t idOrStage, uint32_t worldLevel) const; const StandardGacha& standardGacha() const { return standardGacha_; } + // The standard pool, then the limited ones in id order. + const std::vector& gachaPools() const { return gachaPools_; } + // GachaTypeBasicInfo.UpPropability, in percent; 0 for the standard pool. + uint32_t gachaUpChance(GachaType type) const; + + const LightconeInfo* lightcone(uint32_t id) const; + const std::unordered_map& lightcones() const { return lightcones_; } + // BattlePassReward: paid out by the pass, never by a warp. + bool battlePassReward(uint32_t itemId) const { return battlePassRewards_.count(itemId) != 0; } // AvatarMazeBuff rows named ADV_GlobalSkill_Maze*: Castorice and Silver Wolf. const std::vector& globalMazeBuffs() const { return globalMazeBuffs_; } @@ -300,6 +325,11 @@ private: std::unordered_map farmElements_; // id * 100 + worldLevel -> stage std::unordered_set farmStages_; StandardGacha standardGacha_; + std::vector gachaPools_; + uint32_t avatarUpChance_ = 50; + uint32_t weaponUpChance_ = 75; + std::unordered_map lightcones_; + std::unordered_set battlePassRewards_; std::vector globalMazeBuffs_; std::vector mainMissions_; std::vector tutorials_; diff --git a/src/game/gacha.cpp b/src/game/gacha.cpp new file mode 100644 index 0000000..42f4a68 --- /dev/null +++ b/src/game/gacha.cpp @@ -0,0 +1,244 @@ +#include "game/gacha.h" + +#include + +#include "core/util.h" + +namespace game { +namespace { + +// Stellar Warp's 5* light cones; no table lists them. +constexpr uint32_t kStandardLightcones[] = {23000, 23002, 23003, 23004, 23005, 23012, 23013}; + +constexpr uint32_t kUndyingEmbers = 251; +constexpr uint32_t kUndyingStarlight = 252; +constexpr uint32_t kEidolonItemOffset = 10000; +constexpr uint32_t kFourStarPity = 10; + +struct Rates { + uint32_t hardPity; + uint32_t softPity; + double base; + double step; + double fourStar; +}; + +// 0.6%, +6% a pull from 74, certain at 90. Light cones: 0.8%, +7% from 66, certain at 80. +constexpr Rates kCharacterRates{90, 74, 0.006, 0.06, 0.051}; +constexpr Rates kLightconeRates{80, 66, 0.008, 0.07, 0.066}; + +double fiveStarChance(const Rates& rates, uint32_t pullNumber) { + if (pullNumber >= rates.hardPity) return 1.0; + if (pullNumber < rates.softPity) return rates.base; + return std::min(1.0, rates.base + rates.step * (pullNumber - rates.softPity + 1)); +} + +uint32_t pick(const std::vector& ids, const GachaRoll& roll) { + size_t index = static_cast(roll() * static_cast(ids.size())); + return ids[std::min(index, ids.size() - 1)]; +} + +GachaPull pullOne(const data::GachaPool& pool, const GachaItemPools& items, GachaPity& pity, + const GachaRoll& roll) { + const Rates& rates = pool.type == data::GachaType::WeaponUp ? kLightconeRates : kCharacterRates; + ++pity.total; + GachaPull pull; + + if (roll() < fiveStarChance(rates, pity.sinceFive + 1)) { + pull.rarity = 5; + pity.sinceFive = 0; + // A 5* does not use up the 4* guarantee; it lands on the next pull instead. + ++pity.sinceFour; + if (pool.type == data::GachaType::Normal) { + pull.avatar = roll() < 0.5; + pull.itemId = pick(pull.avatar ? items.fiveStarAvatars : items.fiveStarLightcones, roll); + return pull; + } + pull.avatar = pool.type == data::GachaType::AvatarUp; + std::vector others; + for (uint32_t id : pull.avatar ? items.fiveStarAvatars : items.fiveStarLightcones) { + if (id != pool.featured) others.push_back(id); + } + pull.guaranteed = pity.guaranteed; + pull.featured = pity.guaranteed || others.empty() || roll() * 100.0 < pool.upChance; + pity.guaranteed = !pull.featured; + pull.itemId = pull.featured ? pool.featured : pick(others, roll); + return pull; + } + + ++pity.sinceFive; + if (pity.sinceFour + 1 >= kFourStarPity || roll() < rates.fourStar) { + pull.rarity = 4; + pity.sinceFour = 0; + pull.avatar = roll() < 0.5; + pull.itemId = pick(pull.avatar ? items.fourStarAvatars : items.fourStarLightcones, roll); + return pull; + } + + ++pity.sinceFour; + pull.itemId = pick(items.threeStarLightcones, roll); + return pull; +} + +} // namespace + +GachaPity& GachaProgress::forType(data::GachaType type) { + switch (type) { + case data::GachaType::AvatarUp: + return character; + case data::GachaType::WeaponUp: + return lightcone; + case data::GachaType::Normal: + break; + } + return standard; +} + +bool GachaItemPools::complete() const { + return !fiveStarAvatars.empty() && !fiveStarLightcones.empty() && !fourStarAvatars.empty() && + !fourStarLightcones.empty() && !threeStarLightcones.empty(); +} + +GachaItemPools gachaItemPools(const data::Tables& tables) { + GachaItemPools items; + items.fiveStarAvatars = tables.standardGacha().ceilingAvatars; + for (uint32_t id : kStandardLightcones) { + const data::LightconeInfo* info = tables.lightcone(id); + if (info != nullptr && info->rarity == 5) items.fiveStarLightcones.push_back(id); + } + for (const auto& [id, avatar] : tables.avatars()) { + // Playable ids, with March's second form and the Trailblazer's paths folded away. + if (avatar.rarity != 4 || id < 1000 || id >= 2000 || tables.baseAvatarId(id) != id) continue; + items.fourStarAvatars.push_back(id); + } + for (const auto& [id, lightcone] : tables.lightcones()) { + // 22xxx are event rewards. + if (id >= 22000 || tables.battlePassReward(id)) continue; + if (lightcone.rarity == 4) items.fourStarLightcones.push_back(id); + if (lightcone.rarity == 3) items.threeStarLightcones.push_back(id); + } + std::sort(items.fourStarAvatars.begin(), items.fourStarAvatars.end()); + std::sort(items.fourStarLightcones.begin(), items.fourStarLightcones.end()); + std::sort(items.threeStarLightcones.begin(), items.threeStarLightcones.end()); + return items; +} + +double gachaRoll() { return static_cast(util::randomU64() >> 11) * 0x1.0p-53; } + +namespace { + +bool featurable(const data::Tables& tables, data::GachaType type, uint32_t id) { + if (type == data::GachaType::AvatarUp) { + const data::AvatarInfo* avatar = tables.avatar(id); + return avatar != nullptr && avatar->rarity == 5; + } + if (type == data::GachaType::WeaponUp) { + const data::LightconeInfo* lightcone = tables.lightcone(id); + return lightcone != nullptr && lightcone->rarity == 5; + } + return false; +} + +} // namespace + +std::vector offeredGachaPools(const data::Tables& tables, + const std::vector& limited) { + const std::vector& pools = tables.gachaPools(); + auto find = [&pools](uint32_t id) -> const data::GachaPool* { + for (const data::GachaPool& pool : pools) { + if (pool.id == id) return &pool; + } + return nullptr; + }; + + std::vector offered; + const data::GachaPool* standard = find(tables.standardGacha().gachaId); + if (standard != nullptr && standard->type == data::GachaType::Normal) offered.push_back(*standard); + for (const core::WarpBanner& banner : limited) { + const data::GachaPool* pool = find(banner.id); + if (pool == nullptr || pool->type == data::GachaType::Normal) continue; + bool taken = std::any_of(offered.begin(), offered.end(), + [pool](const data::GachaPool& p) { return p.id == pool->id; }); + if (taken) continue; + data::GachaPool entry = *pool; + if (banner.featured != 0 && featurable(tables, entry.type, banner.featured)) { + entry.featured = banner.featured; + } + offered.push_back(std::move(entry)); + } + return offered; +} + +std::optional offeredGachaPool(const data::Tables& tables, + const std::vector& limited, + uint32_t gachaId) { + for (data::GachaPool& pool : offeredGachaPools(tables, limited)) { + if (pool.id == gachaId) return std::move(pool); + } + return std::nullopt; +} + +data::GachaPool effectiveGachaPool(const data::GachaPool& pool, const data::Tables& tables, + uint32_t standardFeatured) { + if (pool.type != data::GachaType::Normal || standardFeatured == 0) return pool; + if (!featurable(tables, data::GachaType::AvatarUp, standardFeatured)) return pool; + data::GachaPool banner = pool; + banner.type = data::GachaType::AvatarUp; + banner.featured = standardFeatured; + banner.upChance = tables.gachaUpChance(data::GachaType::AvatarUp); + return banner; +} + +std::vector pullGacha(const data::GachaPool& pool, const GachaItemPools& items, + GachaPity& pity, uint32_t count, const GachaRoll& roll) { + std::vector pulls; + pulls.reserve(count); + for (uint32_t i = 0; i < count; ++i) pulls.push_back(pullOne(pool, items, pity, roll)); + return pulls; +} + +proto::GachaItem gachaResult(const GachaPull& pull, const SrToolsData& roster) { + proto::GachaItem result; + proto::Item& item = result.gacha_item.emplace(); + item.item_id = pull.itemId; + item.num = 1; + item.level = 1; + item.rank = 1; + // Both lists go out even when empty. + proto::ItemList& transfer = result.transfer_item_list.emplace(); + proto::ItemList& tokens = result.token_item.emplace(); + auto token = [&tokens](uint32_t id, uint32_t num) { + proto::Item entry; + entry.item_id = id; + entry.num = num; + tokens.item_list.push_back(entry); + }; + + if (!pull.avatar) { + if (pull.rarity == 3) { + token(kUndyingEmbers, 20); + } else { + token(kUndyingStarlight, pull.rarity == 5 ? 40 : 8); + } + return result; + } + + auto owned = roster.avatars.find(pull.itemId); + if (owned == roster.avatars.end()) { + result.is_new = true; + return result; + } + bool fiveStar = pull.rarity == 5; + if (owned->second.rank >= 6) { + token(kUndyingStarlight, fiveStar ? 100 : 20); + return result; + } + token(kUndyingStarlight, fiveStar ? 40 : 8); + proto::Item eidolon; + eidolon.item_id = pull.itemId + kEidolonItemOffset; + eidolon.num = 1; + transfer.item_list.push_back(eidolon); + return result; +} + +} // namespace game diff --git a/src/game/gacha.h b/src/game/gacha.h new file mode 100644 index 0000000..efe674b --- /dev/null +++ b/src/game/gacha.h @@ -0,0 +1,75 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include "core/config.h" +#include "data/excel.h" +#include "game/srtools.h" +#include "proto/gen/protos.h" + +namespace game { + +struct GachaPity { + uint32_t sinceFive = 0; + uint32_t sinceFour = 0; + bool guaranteed = false; // the next 5* is the featured one + uint32_t total = 0; +}; + +// Every limited pool of one kind shares its counter. +struct GachaProgress { + GachaPity standard; + GachaPity character; + GachaPity lightcone; + + GachaPity& forType(data::GachaType type); +}; + +struct GachaItemPools { + std::vector fiveStarAvatars; + std::vector fiveStarLightcones; + std::vector fourStarAvatars; + std::vector fourStarLightcones; + std::vector threeStarLightcones; + + bool complete() const; +}; + +GachaItemPools gachaItemPools(const data::Tables& tables); + +struct GachaPull { + uint32_t itemId = 0; + uint32_t rarity = 3; + bool avatar = false; + bool featured = false; // a limited 5* that was the featured one + bool guaranteed = false; // and was owed it by an earlier lost 50/50 +}; + +// Uniform in [0, 1); injectable so the rates can be tested. +using GachaRoll = std::function; +double gachaRoll(); + +// The standard pool, then each configured limited pool the tables have, featuring what the +// config names. An override that is not a 5* of the pool's kind is ignored. +std::vector offeredGachaPools(const data::Tables& tables, + const std::vector& limited); +std::optional offeredGachaPool(const data::Tables& tables, + const std::vector& limited, + uint32_t gachaId); +// The standard pool as a character banner featuring `standardFeatured`. Anything but a 5* +// character leaves the pool as it is, and so does any limited pool. +data::GachaPool effectiveGachaPool(const data::GachaPool& pool, const data::Tables& tables, + uint32_t standardFeatured); + +// `items` must be complete(). +std::vector pullGacha(const data::GachaPool& pool, const GachaItemPools& items, + GachaPity& pity, uint32_t count, const GachaRoll& roll); + +// The result card. Nothing is granted: the srtools build stays the roster. +proto::GachaItem gachaResult(const GachaPull& pull, const SrToolsData& roster); + +} // namespace game diff --git a/src/game/gacha_handlers.cpp b/src/game/gacha_handlers.cpp new file mode 100644 index 0000000..69cbec6 --- /dev/null +++ b/src/game/gacha_handlers.cpp @@ -0,0 +1,143 @@ +#include +#include +#include +#include + +#include "core/config.h" +#include "core/logger.h" +#include "core/util.h" +#include "data/excel.h" +#include "game/gacha.h" +#include "game/handlers.h" +#include "game/player.h" +#include "net/cmd_ids.h" +#include "net/handler.h" +#include "net/session.h" +#include "proto/gen/protos.h" + +namespace game { +namespace { + +constexpr int64_t kLimitedEndTime = 4102416000; // 2100-01-01 +// Character pools carry this in item_detail_list. +constexpr uint32_t kAvatarPoolDetail = 11; + +// Always claimed: nothing is granted, so the 300-pull pick has nothing to pay out. +proto::GachaCeiling standardCeiling(const Player* player) { + const data::StandardGacha& standard = data::Tables::get().standardGacha(); + proto::GachaCeiling ceiling; + ceiling.is_claimed = true; + uint32_t pulls = player != nullptr ? player->gacha().standard.total : 0; + ceiling.ceiling_num = std::min(pulls, standard.ceilingNum); + for (uint32_t avatarId : standard.ceilingAvatars) { + proto::GachaCeilingAvatar avatar; + avatar.avatar_id = avatarId; + ceiling.avatar_list.push_back(avatar); + } + return ceiling; +} + +void onGetGachaInfo(net::Session& session, const proto::GetGachaInfoCsReq&) { + proto::GetGachaInfoScRsp rsp; + rsp.retcode = 0; + rsp.gacha_random = util::randomRange(1000, 1999); + const std::vector& limited = core::Config::get().gameplay.limitedWarpPools; + for (const data::GachaPool& pool : offeredGachaPools(data::Tables::get(), limited)) { + proto::GachaInfo& info = rsp.gacha_info_list.emplace_back(); + info.gacha_id = pool.id; + if (pool.type == data::GachaType::Normal) { + info.gacha_ceiling.emplace() = standardCeiling(session.player()); + continue; + } + info.end_time = kLimitedEndTime; + info.prize_item_list.push_back(pool.featured); + if (pool.type == data::GachaType::AvatarUp) info.item_detail_list.push_back(kAvatarPoolDetail); + } + session.send(cmd::GetGachaInfoScRsp, rsp); +} + +void onDoGacha(net::Session& session, const proto::DoGachaCsReq& req) { + proto::DoGachaScRsp rsp; + rsp.gacha_id = req.gacha_id; + rsp.gacha_num = req.gacha_num; + + Player* player = session.player(); + const data::Tables& tables = data::Tables::get(); + std::optional pool = + offeredGachaPool(tables, core::Config::get().gameplay.limitedWarpPools, req.gacha_id); + if (player == nullptr) { + rsp.retcode = fail(proto::Retcode::RET_FAIL); + } else if (!pool) { + rsp.retcode = fail(proto::Retcode::RET_GACHA_ID_NOT_EXIST); + } else if (req.gacha_num != 1 && req.gacha_num != 10) { + rsp.retcode = fail(proto::Retcode::RET_GACHA_NUM_INVALID); + } else { + GachaItemPools items = gachaItemPools(tables); + if (!items.complete()) { + logging::warn("game", "warp {} has an empty item pool, check the tables", pool->id); + rsp.retcode = fail(proto::Retcode::RET_GACHA_NOT_SUPPORT); + } else { + uint32_t featured = core::Config::get().gameplay.standardWarpFeatured; + data::GachaPool banner = effectiveGachaPool(*pool, tables, featured); + if (pool->type == data::GachaType::Normal && featured != 0 && banner.featured == 0) { + logging::warn("game", "standard_warp_featured {} is not a 5* character", featured); + } + Roster roster = player->roster(); + GachaPity& pity = player->gacha().forType(banner.type); + uint32_t fiveStars = 0; + for (const GachaPull& pull : pullGacha(banner, items, pity, req.gacha_num, gachaRoll)) { + if (pull.rarity == 5) { + ++fiveStars; + const char* how = banner.type == data::GachaType::Normal ? "standard" + : pull.guaranteed ? "guaranteed" + : pull.featured ? "won the 50/50" + : "lost the 50/50"; + logging::info("game", "warp {} 5*: {} ({})", banner.id, pull.itemId, how); + } + rsp.gacha_item_list.push_back(gachaResult(pull, roster.data())); + } + player->saveNow(); + logging::info("game", "warp {} x{}: {} 5*, {} pulls since the last", banner.id, + req.gacha_num, fiveStars, pity.sinceFive); + } + } + session.send(cmd::DoGachaScRsp, rsp); +} + +void onGetGachaCeiling(net::Session& session, const proto::GetGachaCeilingCsReq& req) { + proto::GetGachaCeilingScRsp rsp; + rsp.retcode = 0; + rsp.gacha_type = req.DDMCNOJFGON; + rsp.gacha_ceiling.emplace() = standardCeiling(session.player()); + session.send(cmd::GetGachaCeilingScRsp, rsp); +} + +void onExchangeGachaCeiling(net::Session& session, const proto::ExchangeGachaCeilingCsReq& req) { + proto::ExchangeGachaCeilingScRsp rsp; + rsp.retcode = fail(proto::Retcode::RET_GACHA_CEILING_CLOSE); + rsp.gacha_type = req.gacha_type; + rsp.avatar_id = req.avatar_id; + rsp.gacha_ceiling.emplace() = standardCeiling(session.player()); + rsp.transfer_item_list.emplace(); + session.send(cmd::ExchangeGachaCeilingScRsp, rsp); +} + +// A lost 50/50 always draws from the standard seven, so a custom pick is refused. +void onSetGachaDecideItem(net::Session& session, const proto::SetGachaDecideItemCsReq&) { + proto::SetGachaDecideItemScRsp rsp; + rsp.retcode = fail(proto::Retcode::RET_GACHA_NOT_SUPPORT); + rsp.NBLOJLDLBEB.emplace(); + session.send(cmd::SetGachaDecideItemScRsp, rsp); +} + +} // namespace + +void registerGachaHandlers() { + net::on(cmd::GetGachaInfoCsReq, onGetGachaInfo); + net::on(cmd::DoGachaCsReq, onDoGacha); + net::on(cmd::GetGachaCeilingCsReq, onGetGachaCeiling); + net::on(cmd::ExchangeGachaCeilingCsReq, onExchangeGachaCeiling); + net::on(cmd::SetGachaDecideItemCsReq, onSetGachaDecideItem); +} + +} // namespace game diff --git a/src/game/handlers.h b/src/game/handlers.h index 27d9fc9..3b72e07 100644 --- a/src/game/handlers.h +++ b/src/game/handlers.h @@ -23,6 +23,7 @@ void registerTalkHandlers(); void registerChallengeHandlers(); void registerTierceHandlers(); void registerPeakHandlers(); +void registerGachaHandlers(); void registerModuleHandlers(); void registerMiscHandlers(); diff --git a/src/game/misc_handlers.cpp b/src/game/misc_handlers.cpp index 5cdce91..0a4da90 100644 --- a/src/game/misc_handlers.cpp +++ b/src/game/misc_handlers.cpp @@ -6,7 +6,6 @@ #include "core/logger.h" #include "core/util.h" -#include "data/excel.h" #include "game/handlers.h" #include "net/cmd_ids.h" #include "net/handler.h" @@ -77,24 +76,6 @@ void onSyncClientResVersion(net::Session& session, const proto::SyncClientResVer session.send(cmd::SyncClientResVersionScRsp, rsp); } -// The warp pools. Only the standard pool is offered, and its ceiling as already -// claimed: nothing can pay a warp out yet. -void onGetGachaInfo(net::Session& session, const proto::GetGachaInfoCsReq&) { - const data::StandardGacha& standard = data::Tables::get().standardGacha(); - proto::GetGachaInfoScRsp rsp; - rsp.retcode = 0; - auto& pool = rsp.gacha_info_list.emplace_back(); - pool.gacha_id = standard.gachaId; - auto& ceiling = pool.gacha_ceiling.emplace(); - ceiling.is_claimed = true; - for (uint32_t avatarId : standard.ceilingAvatars) { - proto::GachaCeilingAvatar avatar; - avatar.avatar_id = avatarId; - ceiling.avatar_list.push_back(avatar); - } - session.send(cmd::GetGachaInfoScRsp, rsp); -} - // Activities reported as scheduled: module id, panel and window. struct ScheduledActivity { uint32_t activityId; @@ -207,7 +188,6 @@ void registerMiscHandlers() { for (uint16_t cmdId : kEmptyReplies) net::Handlers::get().addEmpty(cmdId); for (const auto& [req, rsp] : kResponseAliases) net::Handlers::get().addAlias(req, rsp); net::on(cmd::SetClientPausedCsReq, onSetClientPaused); - net::on(cmd::GetGachaInfoCsReq, onGetGachaInfo); net::on(cmd::GetActivityScheduleConfigCsReq, onGetActivityScheduleConfig); net::on(cmd::SyncClientResVersionCsReq, @@ -226,6 +206,7 @@ void registerAllHandlers() { registerChallengeHandlers(); registerTierceHandlers(); registerPeakHandlers(); + registerGachaHandlers(); registerModuleHandlers(); registerMiscHandlers(); logging::info("game", "{} packet handlers registered, {} answered empty", diff --git a/src/game/player.h b/src/game/player.h index c1a9171..1635a15 100644 --- a/src/game/player.h +++ b/src/game/player.h @@ -7,6 +7,7 @@ #include #include +#include "game/gacha.h" #include "game/lineup.h" #include "game/roster.h" #include "game/scene.h" @@ -168,6 +169,8 @@ public: const std::map& tierceHistory() const { return tierceHistory_; } PeakProgress& peakProgress() { return peakProgress_; } const PeakProgress& peakProgress() const { return peakProgress_; } + GachaProgress& gacha() { return gacha_; } + const GachaProgress& gacha() const { return gacha_; } uint32_t mainCharacter() const { return mainCharacter_; } void setMainCharacter(uint32_t value) { mainCharacter_ = value; } @@ -209,6 +212,7 @@ private: PeakProgress peakProgress_; TierceRun tierce_; std::map tierceHistory_; + GachaProgress gacha_; uint32_t mainCharacter_ = 8008; uint32_t marchType_ = 1224; diff --git a/src/game/player_store.cpp b/src/game/player_store.cpp index a4cb79e..ca49afa 100644 --- a/src/game/player_store.cpp +++ b/src/game/player_store.cpp @@ -171,6 +171,20 @@ bool loadPlayerState(Player& player) { } } } + + if (auto gacha = j.find("gacha"); gacha != j.end() && gacha->is_object()) { + auto readPity = [&gacha](const char* key, GachaPity& pity) { + auto it = gacha->find(key); + if (it == gacha->end() || !it->is_object()) return; + pity.sinceFive = u32(*it, "since_five", 0); + pity.sinceFour = u32(*it, "since_four", 0); + pity.guaranteed = boolOr(*it, "guaranteed", false); + pity.total = u32(*it, "total", 0); + }; + readPity("standard", player.gacha().standard); + readPity("character", player.gacha().character); + readPity("lightcone", player.gacha().lightcone); + } return true; } @@ -244,6 +258,17 @@ bool savePlayerState(const Player& player) { } j["tierce"] = tierce; + auto pity = [](const GachaPity& p) { + return json{{"since_five", p.sinceFive}, + {"since_four", p.sinceFour}, + {"guaranteed", p.guaranteed}, + {"total", p.total}}; + }; + const GachaProgress& gacha = player.gacha(); + j["gacha"] = {{"standard", pity(gacha.standard)}, + {"character", pity(gacha.character)}, + {"lightcone", pity(gacha.lightcone)}}; + const std::string& path = core::Config::get().paths.playerFile; if (!util::writeFile(path, j.dump(2))) { logging::warn("player", "could not write {}", path); diff --git a/tests/test_flow.cpp b/tests/test_flow.cpp index 64e57a9..2fef4b1 100644 --- a/tests/test_flow.cpp +++ b/tests/test_flow.cpp @@ -982,6 +982,85 @@ void runFlowTests() { } } + // Warp: results only, and every refusal still answers. + std::vector configuredPools = core::Config::get().gameplay.limitedWarpPools; + core::Config::get().gameplay.limitedWarpPools.clear(); + client.sendEmpty(cmd::GetGachaInfoCsReq); + check(client.await(cmd::GetGachaInfoScRsp, packet), "warp pools answered"); + proto::GetGachaInfoScRsp standardInfo; + check(parseBody(packet, standardInfo) && standardInfo.gacha_info_list.size() == 1 && + standardInfo.gacha_info_list[0].gacha_id == 1001, + "only the standard pool by default"); + + core::Config::get().gameplay.limitedWarpPools = {{2002, 0}, {3002, 0}}; + client.sendEmpty(cmd::GetGachaInfoCsReq); + check(client.await(cmd::GetGachaInfoScRsp, packet), "and again with limited pools configured"); + proto::GetGachaInfoScRsp gachaInfo; + check(parseBody(packet, gachaInfo), "the pools parse"); + check(gachaInfo.gacha_info_list.size() == 3, "the standard pool and the two configured ones"); + check(!gachaInfo.gacha_info_list.empty() && gachaInfo.gacha_info_list[0].gacha_ceiling.has() && + gachaInfo.gacha_info_list[0].gacha_ceiling->avatar_list.size() == 7, + "the standard pool carries its ceiling"); + uint32_t limitedId = 0; + if (gachaInfo.gacha_info_list.size() > 1) { + limitedId = gachaInfo.gacha_info_list[1].gacha_id; + check(gachaInfo.gacha_info_list[1].prize_item_list.size() == 1, + "a limited pool names its featured 5*"); + } + + proto::DoGachaCsReq tenPull; + tenPull.gacha_id = limitedId; + tenPull.gacha_num = 10; + tenPull.gacha_random = gachaInfo.gacha_random; + client.send(cmd::DoGachaCsReq, tenPull); + check(client.await(cmd::DoGachaScRsp, packet), "a ten pull answers"); + proto::DoGachaScRsp tenRsp; + check(parseBody(packet, tenRsp) && tenRsp.retcode == 0, "and succeeds"); + check(tenRsp.gacha_id == limitedId && tenRsp.gacha_num == 10 && + tenRsp.gacha_item_list.size() == 10, + "with ten results"); + bool cardsWhole = !tenRsp.gacha_item_list.empty(); + for (const proto::GachaItem& card : tenRsp.gacha_item_list) { + cardsWhole &= card.gacha_item.has() && card.gacha_item->item_id != 0 && + card.transfer_item_list.has() && card.token_item.has(); + } + check(cardsWhole, "every card is filled in"); + + proto::DoGachaCsReq oddPull = tenPull; + oddPull.gacha_num = 5; + client.send(cmd::DoGachaCsReq, oddPull); + proto::DoGachaScRsp oddRsp; + check(client.await(cmd::DoGachaScRsp, packet) && parseBody(packet, oddRsp) && + oddRsp.retcode == static_cast(proto::Retcode::RET_GACHA_NUM_INVALID) && + oddRsp.gacha_item_list.empty(), + "a five pull is refused"); + + proto::DoGachaCsReq oldPool; + oldPool.gacha_id = 2138; + oldPool.gacha_num = 1; + client.send(cmd::DoGachaCsReq, oldPool); + proto::DoGachaScRsp oldRsp; + check(client.await(cmd::DoGachaScRsp, packet) && parseBody(packet, oldRsp) && + oldRsp.retcode == static_cast(proto::Retcode::RET_GACHA_ID_NOT_EXIST), + "a pool that is not offered is refused"); + + proto::GetGachaCeilingCsReq ceilingReq; + ceilingReq.DDMCNOJFGON = 1; + client.send(cmd::GetGachaCeilingCsReq, ceilingReq); + proto::GetGachaCeilingScRsp ceilingRsp; + check(client.await(cmd::GetGachaCeilingScRsp, packet) && parseBody(packet, ceilingRsp) && + ceilingRsp.gacha_ceiling.has() && ceilingRsp.gacha_ceiling->is_claimed, + "the ceiling answers, claimed"); + + proto::SetGachaDecideItemCsReq decideReq; + decideReq.gacha_id = limitedId; + client.send(cmd::SetGachaDecideItemCsReq, decideReq); + proto::SetGachaDecideItemScRsp decideRsp; + check(client.await(cmd::SetGachaDecideItemScRsp, packet) && parseBody(packet, decideRsp) && + decideRsp.retcode != 0 && decideRsp.NBLOJLDLBEB.has(), + "a custom 50/50 pool is refused with a body"); + core::Config::get().gameplay.limitedWarpPools = configuredPools; + // An unimplemented request still has to complete, or the client hangs on it. This // one has no handler at all, so it exercises the name-derived fallback. client.sendEmpty(cmd::GetStarFightDataCsReq); diff --git a/tests/test_game.cpp b/tests/test_game.cpp index 92c9b52..787fce8 100644 --- a/tests/test_game.cpp +++ b/tests/test_game.cpp @@ -2,6 +2,8 @@ // present; the data-driven checks are skipped (and reported) when they are not. #include #include +#include +#include #include #include @@ -13,8 +15,10 @@ #include "data/scene_res.h" #include "game/battle.h" #include "game/challenge.h" +#include "game/gacha.h" #include "game/lineup.h" #include "game/player.h" +#include "game/player_store.h" #include "game/roster.h" #include "game/scene.h" #include "game/srtools.h" @@ -186,6 +190,220 @@ void testTables() { check(tables.plane(10000) != nullptr, "plane 10000 is loaded"); } +bool contains(const std::vector& ids, uint32_t id) { + return std::find(ids.begin(), ids.end(), id) != ids.end(); +} + +uint32_t tokenCount(const proto::GachaItem& result, uint32_t itemId) { + uint32_t total = 0; + if (!result.token_item.has()) return 0; + for (const proto::Item& item : result.token_item->item_list) { + if (item.item_id == itemId) total += item.num; + } + return total; +} + +void testGacha() { + const data::Tables& tables = data::Tables::get(); + if (!tables.loaded()) { + std::printf("SKIP gacha (no data source configured)\n"); + return; + } + + check(tables.avatar(1001) != nullptr && tables.avatar(1001)->rarity == 4, "March is a 4*"); + check(tables.avatar(1003) != nullptr && tables.avatar(1003)->rarity == 5, "Himeko is a 5*"); + check(tables.lightcone(23000) != nullptr && tables.lightcone(23000)->rarity == 5, + "light cone rarity is read"); + check(tables.lightcone(20000) != nullptr && tables.lightcone(20000)->rarity == 3, + "down to the 3* ones"); + check(tables.battlePassReward(21028) && !tables.battlePassReward(21000), + "battle pass light cones are known"); + + // The beta client's own table has six pools, and it throws on any other. + check(tables.gachaPools().size() == 5, "the client's pools, less the beginner one"); + std::vector standardOnly = game::offeredGachaPools(tables, {}); + check(standardOnly.size() == 1 && standardOnly[0].id == 1001, + "only the standard pool unless limited ones are configured"); + const std::vector limited{{2002, 0}, {3002, 0}, {2002, 0}, + {2138, 0}, {1001, 0}, {4001, 0}}; + std::vector offered = game::offeredGachaPools(tables, limited); + check(offered.size() == 3, "each configured pool once, if the table has it"); + check(!offered.empty() && offered[0].id == 1001, "standard first"); + std::optional character = game::offeredGachaPool(tables, limited, 2002); + check(character && character->type == data::GachaType::AvatarUp && + character->featured == 1204 && character->upChance == 50, + "2002 features 1204 at 50%"); + std::optional lightcone = game::offeredGachaPool(tables, limited, 3002); + check(lightcone && lightcone->type == data::GachaType::WeaponUp && + lightcone->featured == 23010 && lightcone->upChance == 75, + "3002 features 23010 at 75%"); + check(!game::offeredGachaPool(tables, limited, 2138), "a pool the client lacks is not offered"); + check(!game::offeredGachaPool(tables, limited, 4001), "nor the beginner pool"); + check(!game::offeredGachaPool(tables, {}, 2002), "nor an unconfigured one"); + + game::GachaItemPools items = game::gachaItemPools(tables); + check(items.complete(), "every rarity has something to draw"); + check(items.fiveStarAvatars.size() == 7 && items.fiveStarLightcones.size() == 7, + "seven standard 5* of each"); + check(contains(items.fourStarAvatars, 1001) && !contains(items.fourStarAvatars, 1224), + "4* characters without March's second form"); + check(!contains(items.fourStarAvatars, 1003), "and without 5*s"); + check(contains(items.fourStarLightcones, 21000) && !contains(items.fourStarLightcones, 21028) && + !contains(items.fourStarLightcones, 22000), + "4* light cones without pass or event ones"); + check(items.threeStarLightcones.size() == 25, "all 25 3* light cones"); + if (!items.complete() || !character || !lightcone || offered.empty()) return; + + auto unlucky = [] { return 0.999999; }; + auto lucky = [] { return 0.0; }; + + game::GachaPity pity; + std::vector pulls = game::pullGacha(offered[0], items, pity, 91, unlucky); + bool early = false; + for (size_t i = 0; i < 89; ++i) early |= pulls[i].rarity == 5; + check(!early && pulls[89].rarity == 5, "the 90th standard pull is a 5*"); + check(pulls[9].rarity == 4 && pulls[19].rarity == 4 && pulls[8].rarity == 3, + "every tenth pull is a 4*"); + check(pulls[90].rarity == 4, "a 5* pushes the due 4* to the next pull"); + check(pity.sinceFive == 1 && pity.sinceFour == 0 && pity.total == 91, "pity is counted"); + + game::GachaPity lcPity; + pulls = game::pullGacha(*lightcone, items, lcPity, 80, unlucky); + early = false; + for (size_t i = 0; i < 79; ++i) early |= pulls[i].rarity == 5; + check(!early && pulls[79].rarity == 5, "the 80th light cone pull is a 5*"); + + game::GachaPity charPity; + pulls = game::pullGacha(*character, items, charPity, 90, unlucky); + check(pulls[89].rarity == 5 && pulls[89].avatar && pulls[89].itemId != 1204 && + contains(items.fiveStarAvatars, pulls[89].itemId), + "losing the 50/50 gives a standard 5*"); + check(charPity.guaranteed, "and guarantees the next one"); + pulls = game::pullGacha(*character, items, charPity, 90, unlucky); + check(pulls[89].itemId == 1204 && !charPity.guaranteed, "which is the featured 5*"); + + game::GachaPity luckyPity; + pulls = game::pullGacha(*character, items, luckyPity, 10, lucky); + bool allFeatured = pulls.size() == 10; + for (const game::GachaPull& pull : pulls) allFeatured &= pull.rarity == 5 && pull.itemId == 1204; + check(allFeatured, "winning every roll gives the featured 5* every time"); + pulls = game::pullGacha(offered[0], items, luckyPity, 1, lucky); + check(pulls[0].rarity == 5 && pulls[0].itemId == items.fiveStarAvatars[0], "standard draws too"); + + game::SrToolsData roster; + game::Avatar maxed; + maxed.avatarId = 1003; + maxed.rank = 6; + roster.avatars[1003] = maxed; + game::Avatar fresh; + fresh.avatarId = 1004; + roster.avatars[1004] = fresh; + + proto::GachaItem result = game::gachaResult({20000, 3, false}, roster); + check(result.gacha_item.has() && result.gacha_item->item_id == 20000 && result.gacha_item->num == 1, + "the card names the item"); + check(result.transfer_item_list.has() && result.token_item.has(), "both lists are present"); + check(tokenCount(result, 251) == 20 && !result.is_new, "a 3* light cone is 20 embers"); + check(tokenCount(game::gachaResult({23000, 5, false}, roster), 252) == 40, "a 5* one 40 starlight"); + check(tokenCount(game::gachaResult({21000, 4, false}, roster), 252) == 8, "a 4* one 8"); + result = game::gachaResult({1003, 5, true}, roster); + check(tokenCount(result, 252) == 100 && result.transfer_item_list->item_list.empty(), + "a 5* past E6 is 100 starlight"); + result = game::gachaResult({1004, 5, true}, roster); + check(tokenCount(result, 252) == 40 && result.transfer_item_list->item_list.size() == 1 && + result.transfer_item_list->item_list[0].item_id == 11004, + "below E6 it is 40 and an eidolon"); + result = game::gachaResult({1101, 5, true}, roster); + check(result.is_new && tokenCount(result, 252) == 0, "a character not in the build is new"); + + // A configured featured 5* replaces the pool's own, if it is of the pool's kind. + std::optional pearl = game::offeredGachaPool(tables, {{2001, 1503}}, 2001); + check(pearl && pearl->type == data::GachaType::AvatarUp && pearl->featured == 1503 && + pearl->upChance == 50, + "2001 can feature Pearl at 50%"); + std::optional fourStar = game::offeredGachaPool(tables, {{2001, 1001}}, 2001); + check(fourStar && fourStar->featured == 1102, "a 4* cannot be featured"); + std::optional wrongKind = game::offeredGachaPool(tables, {{3001, 1503}}, 3001); + check(wrongKind && wrongKind->featured == 23001, "nor a character on a light cone pool"); + if (pearl) { + game::GachaPity pearlPity; + pulls = game::pullGacha(*pearl, items, pearlPity, 10, lucky); + bool allPearl = pulls.size() == 10; + for (const game::GachaPull& pull : pulls) { + allPearl &= pull.rarity == 5 && pull.avatar && pull.itemId == 1503; + } + check(allPearl, "winning the 50/50 draws her"); + pulls = game::pullGacha(*pearl, items, pearlPity, 90, unlucky); + check(pulls[89].rarity == 5 && pulls[89].avatar && pulls[89].itemId != 1503 && + contains(items.fiveStarAvatars, pulls[89].itemId) && pearlPity.guaranteed, + "losing it gives a standard 5* character and the guarantee"); + } + + // Stellar Warp standing in for Pearl's banner. + data::GachaPool standardPearl = game::effectiveGachaPool(offered[0], tables, 1503); + check(standardPearl.id == 1001 && standardPearl.type == data::GachaType::AvatarUp && + standardPearl.featured == 1503 && standardPearl.upChance == 50, + "Stellar Warp can feature Pearl at 50%"); + check(game::effectiveGachaPool(offered[0], tables, 0).type == data::GachaType::Normal, + "0 keeps it the standard pool"); + check(game::effectiveGachaPool(offered[0], tables, 1001).type == data::GachaType::Normal, + "a 4* cannot be featured on it"); + check(game::effectiveGachaPool(*character, tables, 1503).featured == 1204, + "a limited pool is left alone"); + game::GachaPity standardPearlPity; + pulls = game::pullGacha(standardPearl, items, standardPearlPity, 10, lucky); + bool allStandardPearl = pulls.size() == 10; + for (const game::GachaPull& pull : pulls) { + allStandardPearl &= pull.rarity == 5 && pull.avatar && pull.itemId == 1503; + } + check(allStandardPearl, "and it draws her on a won 50/50"); + + // The real dice, 200000 pulls: no two lost 50/50s in a row, and the losses spread evenly. + game::GachaPity simPity; + std::map lostTo; + uint32_t fiveStars = 0, owed = 0, lost = 0; + bool lostTwice = false, lastLost = false; + for (int batch = 0; batch < 20000; ++batch) { + for (const game::GachaPull& pull : + game::pullGacha(standardPearl, items, simPity, 10, game::gachaRoll)) { + if (pull.rarity != 5) continue; + ++fiveStars; + if (pull.featured) { + if (pull.guaranteed) ++owed; + lastLost = false; + continue; + } + ++lost; + ++lostTo[pull.itemId]; + lostTwice |= lastLost; + lastLost = true; + } + } + check(!lostTwice, "a lost 50/50 is never followed by another"); + check(owed == lost || owed + 1 == lost, "every loss is paid back by the next 5*"); + double rate = static_cast(fiveStars) / 200000.0; + check(rate > 0.013 && rate < 0.019, "about 1.6% of pulls are 5*"); + bool even = lostTo.size() == items.fiveStarAvatars.size(); + for (const auto& [id, count] : lostTo) even &= count > lost * 8 / 100 && count < lost * 20 / 100; + check(even, "a lost 50/50 lands evenly on the seven standard 5*s"); + std::printf(" warp simulation: %u 5* (%.2f%%), %u lost, spread:", fiveStars, rate * 100, lost); + for (const auto& [id, count] : lostTo) std::printf(" %u=%u", id, count); + std::printf("\n"); + + // Pity outlives a restart. + std::string realPath = core::Config::get().paths.playerFile; + core::Config::get().paths.playerFile = "build/test-gacha-player.json"; + game::Player saved(1); + saved.gacha().character = {12, 3, true, 345}; + check(game::savePlayerState(saved), "pity saves"); + game::Player loaded(1); + check(game::loadPlayerState(loaded), "and loads"); + const game::GachaPity& back = loaded.gacha().character; + check(back.sinceFive == 12 && back.sinceFour == 3 && back.guaranteed && back.total == 345, + "unchanged"); + core::Config::get().paths.playerFile = realPath; +} + void testChallengeHistory() { const data::Tables& tables = data::Tables::get(); if (!tables.loaded()) return; @@ -816,6 +1034,7 @@ void runGameTests() { testItemUniqueIds(); testElementBuffs(); testTables(); + testGacha(); testChallengeHistory(); testSceneRes(); testRosterProtos();