diff --git a/EpinelPS/Database/JsonDb.cs b/EpinelPS/Database/JsonDb.cs index f70aa08..7a944b1 100644 --- a/EpinelPS/Database/JsonDb.cs +++ b/EpinelPS/Database/JsonDb.cs @@ -113,9 +113,12 @@ namespace EpinelPS.Database public List CompletedTacticAcademyLessons = []; public List CompletedSideStoryStages = new(); + public List Memorial = new(); + public List JukeboxBgm = new(); + // Event data public Dictionary EventInfo = new(); - + public void SetQuest(int tid, bool recievedReward) { if (MainQuestData.ContainsKey(tid)) diff --git a/EpinelPS/GameData/GameData.cs b/EpinelPS/GameData/GameData.cs index c90e369..a097a84 100644 --- a/EpinelPS/GameData/GameData.cs +++ b/EpinelPS/GameData/GameData.cs @@ -39,6 +39,8 @@ namespace EpinelPS.StaticInfo private Dictionary LevelData = []; private Dictionary TacticAcademyLessons = []; public Dictionary SidestoryRewardTable = []; + public Dictionary PositionReward = new Dictionary(); + public Dictionary FieldItems = []; public byte[] Sha256Hash; public int Size; @@ -241,8 +243,9 @@ namespace EpinelPS.StaticInfo return records; } - int totalFiles = 12; + int totalFiles = 14; int currentFile = 0; + public async Task Parse() { using var progress = new ProgressBar(); @@ -342,6 +345,32 @@ namespace EpinelPS.StaticInfo SidestoryRewardTable.Add(id2, reward); } } + + + foreach (ZipEntry item in MainZip) + { + if (item.Name.StartsWith("CampaignMap/")) + { + var x = await LoadZip(item.Name, progress); + + var items = x[0]["ItemSpawner"]; + foreach (var item2 in items) + { + var id = item2["positionId"].ToObject(); + var reward = item2["itemId"].ToObject(); + + if (!PositionReward.ContainsKey(id)) + PositionReward.Add(id, reward); + } + } + } + + + var fieldItems = await LoadZip("FieldItemTable.json", progress); + foreach (var obj in fieldItems.records) + { + FieldItems.Add(obj.id, obj); + } } public MainQuestCompletionRecord? GetMainQuestForStageClearCondition(int stage) diff --git a/EpinelPS/GameData/JsonStaticData.cs b/EpinelPS/GameData/JsonStaticData.cs index 977351e..0adcac2 100644 --- a/EpinelPS/GameData/JsonStaticData.cs +++ b/EpinelPS/GameData/JsonStaticData.cs @@ -134,4 +134,17 @@ { public List records; } + + public class FieldItemRecord + { + public int id; + public string item_type; + public int type_value; + public bool is_final_reward; + public string difficulty; + } + public class FieldItemTable + { + public List records; + } } diff --git a/EpinelPS/LobbyServer/Msgs/Campaign/ObtainItem.cs b/EpinelPS/LobbyServer/Msgs/Campaign/ObtainItem.cs index d8d6c96..779c424 100644 --- a/EpinelPS/LobbyServer/Msgs/Campaign/ObtainItem.cs +++ b/EpinelPS/LobbyServer/Msgs/Campaign/ObtainItem.cs @@ -1,5 +1,7 @@ -using EpinelPS.StaticInfo; +using EpinelPS.LobbyServer.Msgs.Stage; +using EpinelPS.StaticInfo; using EpinelPS.Utils; +using Swan.Logging; namespace EpinelPS.LobbyServer.Msgs.Campaign { @@ -18,10 +20,27 @@ namespace EpinelPS.LobbyServer.Msgs.Campaign var key = chapter + "_" + mod; var field = user.FieldInfoNew[key]; - // TODO - response.Reward = new(); + foreach (var item in field.CompletedObjects) + { + if (item.PositionId == req.FieldObject.PositionId) + { + Logger.Warn("attempted to collect campaign field object twice!"); + return; + } + } + // Register and return reward + + if (!GameData.Instance.PositionReward.ContainsKey(req.FieldObject.PositionId)) throw new Exception("bad position id"); + var fieldReward = GameData.Instance.PositionReward[req.FieldObject.PositionId]; + var positionReward = GameData.Instance.FieldItems[fieldReward]; + var reward = GameData.Instance.GetRewardTableEntry(positionReward.type_value); + if (reward == null) throw new Exception("failed to get reward"); + response.Reward = ClearStage.RegisterRewardsForUser(user, reward); + + // Hide it from the field + field.CompletedObjects.Add(new NetFieldObject() { PositionId = req.FieldObject.PositionId, Type = req.FieldObject.Type}); await WriteDataAsync(response); } diff --git a/EpinelPS/LobbyServer/Msgs/Outpost/MemorialGetMemoryList.cs b/EpinelPS/LobbyServer/Msgs/Outpost/MemorialGetMemoryList.cs index 0933c55..52c7dfd 100644 --- a/EpinelPS/LobbyServer/Msgs/Outpost/MemorialGetMemoryList.cs +++ b/EpinelPS/LobbyServer/Msgs/Outpost/MemorialGetMemoryList.cs @@ -8,9 +8,14 @@ namespace EpinelPS.LobbyServer.Msgs.Outpost protected override async Task HandleAsync() { var req = await ReadData(); + var user = GetUser(); var response = new ResGetMemoryList(); - // TODO + + response.MemoryList.AddRange(user.Memorial); + + // TODO rewards + await WriteDataAsync(response); } } diff --git a/EpinelPS/LobbyServer/Msgs/Stage/ClearStage.cs b/EpinelPS/LobbyServer/Msgs/Stage/ClearStage.cs index 41b2213..e10b833 100644 --- a/EpinelPS/LobbyServer/Msgs/Stage/ClearStage.cs +++ b/EpinelPS/LobbyServer/Msgs/Stage/ClearStage.cs @@ -2,6 +2,7 @@ using EpinelPS.StaticInfo; using EpinelPS.Utils; using Swan.Logging; +using System.Linq; namespace EpinelPS.LobbyServer.Msgs.Stage { @@ -213,6 +214,22 @@ namespace EpinelPS.LobbyServer.Msgs.Stage Isn = id }); } + else if (item.reward_type == "Memorial") + { + if (!user.Memorial.Contains(item.reward_id)) + { + ret.Memorial.Add(item.reward_id); + user.Memorial.Add(item.reward_id); + } + } + else if (item.reward_type == "Bgm") + { + if (!user.JukeboxBgm.Contains(item.reward_id)) + { + ret.JukeboxBgm.Add(item.reward_id); + user.JukeboxBgm.Add(item.reward_id); + } + } else { Logger.Warn("TODO: Reward type " + item.reward_type); diff --git a/README.md b/README.md index c96d95b..b8bc838 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ To skip stages, a basic command line interface is implemented. ## TODO: - - [X] Normal campaign + - [X] Campaign (Normal, Hard, Lost items, Rewards) - [X] Lobby - [X] Save team info - [X] Profile UI @@ -41,8 +41,7 @@ To skip stages, a basic command line interface is implemented. - [X] Side story - [X] Archives - [ ] Skill level up - - [ ] Outpost jukebox / relics saving - - [ ] Field obtain object + - [ ] Outpost jukebox - [ ] Admin panel - [ ] Test hard stage support - [ ] Event system