This commit is contained in:
Mikhail Tyukin
2025-09-27 20:49:34 -04:00
parent 17e843ecdb
commit 50d4d23e00
16 changed files with 655 additions and 593 deletions

View File

@@ -44,7 +44,7 @@ namespace EpinelPS.Data
public readonly Dictionary<int, CampaignStageRecord> StageDataRecords = [];
[LoadRecord("RewardTable.json", "id")]
public readonly Dictionary<int, RewardTableRecord> RewardDataRecords = [];
public readonly Dictionary<int, RewardRecord> RewardDataRecords = [];
[LoadRecord("UserExpTable.json", "level")]
public readonly Dictionary<int, UserExpRecord> UserExpDataRecords = [];
@@ -518,7 +518,7 @@ namespace EpinelPS.Data
{
return StageDataRecords[stage];
}
public RewardTableRecord? GetRewardTableEntry(int rewardId)
public RewardRecord? GetRewardTableEntry(int rewardId)
{
return RewardDataRecords[rewardId];
}

View File

@@ -134,14 +134,56 @@ namespace EpinelPS.Data
public int characterLevel;
}
[MemoryPackable]
public partial class RewardTableRecord
public partial class RewardRecord
{
public int id;
public int user_exp;
public int character_exp;
public RewardEntry[]? rewards;
public List<RewardEntry> rewards = [];
}
public enum PercentDisplayType
{
None,
Percent,
Random
}
public enum RewardType
{
None = 0,
User_exp = 1,
Char_exp = 2,
Currency = 3,
Character = 4,
Item = 5,
Frame = 6,
AttractivePoint = 7,
Bgm = 8,
Point = 9,
LiveWallpaper = 10,
Memorial = 11,
CharacterCostume = 12,
ItemRandom = 13,
InfraCoreExp = 14,
ItemRandomBox = 15,
Equipment_None = 16,
Equipment_MISSILIS = 17,
Equipment_ELYSION = 18,
Equipment_TETRA = 19,
Equipment_PILGRIM = 20,
Equipment_Random_01 = 21,
Equipment_Random_02 = 22,
Equipment_Random_03 = 23,
PassPoint = 41,
Equipment_ABNORMAL = 42,
FavoriteItem = 43,
ProfileCardObject = 44,
ProfileRandomBox = 45,
UserTitle = 46,
LobbyDecoBackground = 47
}
[MemoryPackable]
public partial class RewardEntry
{
@@ -149,8 +191,8 @@ namespace EpinelPS.Data
/// example: 1000000
/// </summary>
public int reward_percent;
public string percent_display_type = "";
public string reward_type = "";
public PercentDisplayType percent_display_type;
public RewardType reward_type;
public int reward_id;
public int reward_value;
}
@@ -202,12 +244,33 @@ namespace EpinelPS.Data
public string lesson_type = "";
public TacticAcademyLessonReward[]? lesson_reward;
}
public enum OpenType
{
Open,
NonUpdate
}
public enum ChapterGuideType
{
None,
Tutorial,
Common
}
[MemoryPackable]
public partial class CampaignChapterRecord
{
public int id;
public string name_localized = "";
public string description_localized = "";
public int world;
public int chapter;
public OpenType openType;
public DateTime openTime;
public ChapterGuideType chapter_guide;
public string chapter_image = "";
public string hard_chapter_image = "";
public string field_id = "";
public string hard_field_id = "";
}
@@ -878,7 +941,7 @@ namespace EpinelPS.Data
{
public int id;
public int group_id;
public string reward_type = "";
public RewardType reward_type;
public int reward_id;
public int reward_value_min;
public int reward_value_max;

View File

@@ -38,7 +38,7 @@ namespace EpinelPS.LobbyServer.Campaign
ItemSpawner position = map.ItemSpawner.Where(x => x.positionId == req.FieldObject.PositionId).FirstOrDefault() ?? throw new Exception("bad position id");
FieldItemRecord positionReward = GameData.Instance.FieldItems[position.itemId];
RewardTableRecord reward = GameData.Instance.GetRewardTableEntry(positionReward.type_value) ?? throw new Exception("failed to get reward");
RewardRecord reward = GameData.Instance.GetRewardTableEntry(positionReward.type_value) ?? throw new Exception("failed to get reward");
response.Reward = RewardUtils.RegisterRewardsForUser(user, reward);
// Hide it from the field

View File

@@ -24,7 +24,7 @@ namespace EpinelPS.LobbyServer.Character
{
item.ObtainedRewardLevels.Add(levelUpRecord.Value.id);
RewardTableRecord reward = GameData.Instance.GetRewardTableEntry(levelUpRecord.Value.reward_id) ?? throw new Exception("failed to get reward");
RewardRecord reward = GameData.Instance.GetRewardTableEntry(levelUpRecord.Value.reward_id) ?? throw new Exception("failed to get reward");
response.Reward = RewardUtils.RegisterRewardsForUser(user, reward);
JsonDb.Save();

View File

@@ -39,8 +39,8 @@ namespace EpinelPS.LobbyServer.FavoriteItem
characterCsn = character.Csn;
}
RewardTableRecord ? reward = GameData.Instance.GetRewardTableEntry(questData.reward_id);
if (reward?.rewards == null || reward.rewards.Length == 0 || reward.rewards[0].reward_type != "FavoriteItem")
RewardRecord ? reward = GameData.Instance.GetRewardTableEntry(questData.reward_id);
if (reward?.rewards == null || reward.rewards.Count == 0 || reward.rewards[0].reward_type != RewardType.FavoriteItem)
{
if (questData.reward_id > 0 && reward != null)
{

View File

@@ -17,7 +17,7 @@ namespace EpinelPS.LobbyServer.Messenger
KeyValuePair<int, SubquestRecord> opener = GameData.Instance.Subquests.Where(x => x.Key == req.SubQuestId).First();
KeyValuePair<string, MessengerDialogRecord> conversation = GameData.Instance.Messages.Where(x => x.Value.id == req.MessageId).First();
RewardTableRecord rewardRecord = GameData.Instance.GetRewardTableEntry(conversation.Value.reward_id) ?? throw new Exception("unable to lookup reward");
RewardRecord rewardRecord = GameData.Instance.GetRewardTableEntry(conversation.Value.reward_id) ?? throw new Exception("unable to lookup reward");
user.SetSubQuest(req.SubQuestId, true);

View File

@@ -20,7 +20,7 @@ namespace EpinelPS.LobbyServer.Minigame.InTheMirror
{
foreach (var rewardEntry in GameData.Instance.RewardDataRecords[quest.reward_id].rewards ??= [])
{
if (!string.IsNullOrEmpty(rewardEntry.reward_type))
if (rewardEntry.reward_type != RewardType.None)
{
switch (rewardEntry.reward_id)
{

View File

@@ -24,7 +24,7 @@ namespace EpinelPS.LobbyServer.Mission
if (!GameData.Instance.TriggerTable.TryGetValue(item, out TriggerRecord? key)) throw new Exception("unknown TID");
RewardTableRecord rewardRecord = GameData.Instance.GetRewardTableEntry(key.reward_id) ?? throw new Exception("unable to lookup reward");
RewardRecord rewardRecord = GameData.Instance.GetRewardTableEntry(key.reward_id) ?? throw new Exception("unable to lookup reward");
NetRewardData reward = RewardUtils.RegisterRewardsForUser(user, rewardRecord);
rewards.Add(reward);

View File

@@ -33,7 +33,7 @@ namespace EpinelPS.LobbyServer.Mission
if (key.reward_id != 0)
{
// Actual reward
RewardTableRecord rewardRecord = GameData.Instance.GetRewardTableEntry(key.reward_id) ?? throw new Exception("unable to lookup reward");
RewardRecord rewardRecord = GameData.Instance.GetRewardTableEntry(key.reward_id) ?? throw new Exception("unable to lookup reward");
rewards.Add(RewardUtils.RegisterRewardsForUser(user, rewardRecord));
}
else

View File

@@ -29,7 +29,7 @@ namespace EpinelPS.LobbyServer.Mission
if (key.reward_id != 0)
{
// Actual reward
RewardTableRecord rewardRecord = GameData.Instance.GetRewardTableEntry(key.reward_id) ?? throw new Exception("unable to lookup reward");
RewardRecord rewardRecord = GameData.Instance.GetRewardTableEntry(key.reward_id) ?? throw new Exception("unable to lookup reward");
rewards.Add(RewardUtils.RegisterRewardsForUser(user, rewardRecord));
}
else

View File

@@ -21,7 +21,7 @@ namespace EpinelPS.LobbyServer.Sidestory
if (GameData.Instance.SidestoryRewardTable.TryGetValue(req.SideStoryStageId, out SideStoryStageRecord? value))
{
RewardTableRecord? rewardData = GameData.Instance.GetRewardTableEntry(value.first_clear_reward);
RewardRecord? rewardData = GameData.Instance.GetRewardTableEntry(value.first_clear_reward);
if (rewardData != null)
response.Reward = RewardUtils.RegisterRewardsForUser(user, rewardData);

View File

@@ -42,7 +42,7 @@ namespace EpinelPS.LobbyServer.Stage
}
DoQuestSpecificUserOperations(user, StageId);
RewardTableRecord? rewardData = GameData.Instance.GetRewardTableEntry(clearedStage.reward_id);
RewardRecord? rewardData = GameData.Instance.GetRewardTableEntry(clearedStage.reward_id);
if (forceCompleteScenarios)
{

View File

@@ -63,7 +63,7 @@ namespace EpinelPS.LobbyServer.Tower
user.AddTrigger(TriggerType.TowerBasicClear, TowerId);
}
RewardTableRecord reward = GameData.Instance.GetRewardTableEntry(record.reward_id) ?? throw new Exception("failed to get reward");
RewardRecord reward = GameData.Instance.GetRewardTableEntry(record.reward_id) ?? throw new Exception("failed to get reward");
response.Reward = RewardUtils.RegisterRewardsForUser(user, reward);

View File

@@ -29,7 +29,7 @@ namespace EpinelPS.LobbyServer.Trigger
user.MainQuestData[item.Key] = true;
MainQuestCompletionRecord? questInfo = GameData.Instance.GetMainQuestByTableId(item.Key) ?? throw new Exception("failed to lookup quest id " + item.Key);
RewardTableRecord? reward = GameData.Instance.GetRewardTableEntry(questInfo.reward_id) ?? throw new Exception("failed to lookup reward id " + questInfo.reward_id);
RewardRecord? reward = GameData.Instance.GetRewardTableEntry(questInfo.reward_id) ?? throw new Exception("failed to lookup reward id " + questInfo.reward_id);
rewards.Add(RewardUtils.RegisterRewardsForUser(user, reward));
}
}

View File

@@ -414,7 +414,7 @@ namespace EpinelPS.Utils
Logging.WriteLine("TODO: reward_value_max", LogType.Warning);
}
if (winningRecord.reward_type == "Currency")
if (winningRecord.reward_type == RewardType.Currency)
RewardUtils.AddSingleCurrencyObject(user, ref ret, (CurrencyType)winningRecord.reward_id, winningRecord.reward_value_min);
else
RewardUtils.AddSingleObject(user, ref ret, winningRecord.reward_id, winningRecord.reward_type, winningRecord.reward_value_min);

View File

@@ -9,10 +9,10 @@ namespace EpinelPS.Utils
{
public static NetRewardData RegisterRewardsForUser(User user, int rewardId)
{
RewardTableRecord rewardData = GameData.Instance.GetRewardTableEntry(rewardId) ?? throw new Exception($"unknown reward id {rewardId}");
RewardRecord rewardData = GameData.Instance.GetRewardTableEntry(rewardId) ?? throw new Exception($"unknown reward id {rewardId}");
return RegisterRewardsForUser(user, rewardData);
}
public static NetRewardData RegisterRewardsForUser(User user, RewardTableRecord rewardData)
public static NetRewardData RegisterRewardsForUser(User user, RewardRecord rewardData)
{
NetRewardData ret = new()
{
@@ -70,7 +70,7 @@ namespace EpinelPS.Utils
foreach (RewardEntry item in rewardData.rewards)
{
if (!string.IsNullOrEmpty(item.reward_type))
if (item.reward_type != RewardType.None)
{
if (item.reward_percent != 1000000)
{
@@ -111,175 +111,174 @@ namespace EpinelPS.Utils
/// <param name="rewardType"></param>
/// <param name="rewardCount"></param>
/// <exception cref="Exception"></exception>
public static void AddSingleObject(User user, ref NetRewardData ret, int rewardId, string rewardType, int rewardCount)
public static void AddSingleObject(User user, ref NetRewardData ret, int rewardId, RewardType rewardType, int rewardCount)
{
if (rewardId != 0 || !string.IsNullOrEmpty(rewardType))
if (rewardId == 0 || rewardType == RewardType.None) return;
if (rewardType == RewardType.Currency)
{
if (string.IsNullOrEmpty(rewardType) || string.IsNullOrWhiteSpace(rewardType)) { }
else if (rewardType == "Currency")
AddSingleCurrencyObject(user, ref ret, (CurrencyType)rewardId, rewardCount);
}
else if (rewardType == RewardType.Item ||
rewardType.ToString().StartsWith("Equipment_"))
{
// Check if user already has said item. If it is level 1, increase item count.
// If user does not have item, generate a new item ID
if (user.Items.Where(x => x.ItemType == rewardId && x.Level == 1).Any())
{
AddSingleCurrencyObject(user, ref ret, (CurrencyType)rewardId, rewardCount);
}
else if (rewardType == "Item" || rewardType.StartsWith("Equipment_"))
{
// Check if user already has said item. If it is level 1, increase item count.
// If user does not have item, generate a new item ID
if (user.Items.Where(x => x.ItemType == rewardId && x.Level == 1).Any())
ItemData? newItem = user.Items.Where(x => x.ItemType == rewardId && x.Level == 1).FirstOrDefault();
if (newItem != null)
{
ItemData? newItem = user.Items.Where(x => x.ItemType == rewardId && x.Level == 1).FirstOrDefault();
if (newItem != null)
{
newItem.Count += rewardCount;
newItem.Count += rewardCount;
// Tell the client the reward and its amount
ret.Item.Add(new NetItemData()
{
Count = rewardCount,
Tid = rewardId,
//Isn = newItem.Isn
});
// Tell the client the new amount of this item
ret.UserItems.Add(new NetUserItemData()
{
Isn = newItem.Isn,
Tid = newItem.ItemType,
Count = newItem.Count
});
}
else
{
throw new Exception("should not occur");
}
}
else
{
int id = user.GenerateUniqueItemId();
user.Items.Add(new ItemData() { ItemType = rewardId, Isn = id, Level = 1, Exp = 0, Count = rewardCount });
// Tell the client the reward and its amount
ret.Item.Add(new NetItemData()
{
Count = rewardCount,
Tid = rewardId,
//Isn = id
//Isn = newItem.Isn
});
// Tell the client the new amount of this item (which is the same as user did not have item previously)
// Tell the client the new amount of this item
ret.UserItems.Add(new NetUserItemData()
{
Isn = id,
Tid = rewardId,
Count = rewardCount
Isn = newItem.Isn,
Tid = newItem.ItemType,
Count = newItem.Count
});
}
}
else if (rewardType == "Memorial")
{
if (!user.Memorial.Contains(rewardId))
{
ret.Memorial.Add(rewardId);
user.Memorial.Add(rewardId);
}
}
else if (rewardType == "Bgm")
{
if (!user.JukeboxBgm.Contains(rewardId))
{
ret.JukeboxBgm.Add(rewardId);
user.JukeboxBgm.Add(rewardId);
}
}
else if (rewardType == "InfraCoreExp")
{
int beforeLv = user.InfraCoreLvl;
int beforeExp = user.InfraCoreExp;
user.InfraCoreExp += rewardCount;
// Check for level ups
Dictionary<int, InfracoreRecord> gradeTable = GameData.Instance.InfracoreTable;
int newLevel = user.InfraCoreLvl;
foreach (InfracoreRecord grade in gradeTable.Values.OrderBy(g => g.grade))
{
if (user.InfraCoreExp >= grade.infra_core_exp)
{
newLevel = grade.grade + 1;
}
else
{
break;
}
}
if (newLevel > user.InfraCoreLvl)
{
user.InfraCoreLvl = newLevel;
}
ret.InfraCoreExp = new NetIncreaseExpData()
{
BeforeLv = beforeLv,
BeforeExp = beforeExp,
CurrentLv = user.InfraCoreLvl,
CurrentExp = user.InfraCoreExp,
GainExp = rewardCount
};
}
else if (rewardType == "ItemRandomBox")
{
ItemConsumeRecord? cItem = GameData.Instance.ConsumableItems.Where(x => x.Value.id == rewardId).FirstOrDefault().Value;
if (cItem.item_sub_type == ItemSubType.ItemRandomBoxList)
{
NetRewardData reward = NetUtils.UseLootBox(user, rewardId, rewardCount);
ret = NetUtils.MergeRewards([ret, reward], user);
}
else
{
NetItemData itm = new()
{
Count = rewardCount,
Tid = cItem.id,
Isn = user.GenerateUniqueItemId()
};
ret.Item.Add(itm);
user.Items.Add(new ItemData() { Count = rewardCount, Isn = itm.Isn, ItemType = itm.Tid });
throw new Exception("should not occur");
}
}
else if (rewardType == "FavoriteItem")
{
NetUserFavoriteItemData newFavoriteItem = new NetUserFavoriteItemData
{
FavoriteItemId = user.GenerateUniqueItemId(),
Tid = rewardId,
Csn = 0,
Lv = 0,
Exp = 0
};
user.FavoriteItems.Add(newFavoriteItem);
ret.UserFavoriteItems.Add(newFavoriteItem);
NetFavoriteItemData favoriteItemData = new NetFavoriteItemData
{
FavoriteItemId = newFavoriteItem.FavoriteItemId,
Tid = newFavoriteItem.Tid,
Csn = newFavoriteItem.Csn,
Lv = newFavoriteItem.Lv,
Exp = newFavoriteItem.Exp
};
ret.FavoriteItems.Add(favoriteItemData);
}
else
{
Logging.WriteLine("TODO: Reward type " + rewardType, LogType.Warning);
int id = user.GenerateUniqueItemId();
user.Items.Add(new ItemData() { ItemType = rewardId, Isn = id, Level = 1, Exp = 0, Count = rewardCount });
ret.Item.Add(new NetItemData()
{
Count = rewardCount,
Tid = rewardId,
//Isn = id
});
// Tell the client the new amount of this item (which is the same as user did not have item previously)
ret.UserItems.Add(new NetUserItemData()
{
Isn = id,
Tid = rewardId,
Count = rewardCount
});
}
}
else if (rewardType == RewardType.Memorial)
{
if (!user.Memorial.Contains(rewardId))
{
ret.Memorial.Add(rewardId);
user.Memorial.Add(rewardId);
}
}
else if (rewardType == RewardType.Bgm)
{
if (!user.JukeboxBgm.Contains(rewardId))
{
ret.JukeboxBgm.Add(rewardId);
user.JukeboxBgm.Add(rewardId);
}
}
else if (rewardType == RewardType.InfraCoreExp)
{
int beforeLv = user.InfraCoreLvl;
int beforeExp = user.InfraCoreExp;
user.InfraCoreExp += rewardCount;
// Check for level ups
Dictionary<int, InfracoreRecord> gradeTable = GameData.Instance.InfracoreTable;
int newLevel = user.InfraCoreLvl;
foreach (InfracoreRecord grade in gradeTable.Values.OrderBy(g => g.grade))
{
if (user.InfraCoreExp >= grade.infra_core_exp)
{
newLevel = grade.grade + 1;
}
else
{
break;
}
}
if (newLevel > user.InfraCoreLvl)
{
user.InfraCoreLvl = newLevel;
}
ret.InfraCoreExp = new NetIncreaseExpData()
{
BeforeLv = beforeLv,
BeforeExp = beforeExp,
CurrentLv = user.InfraCoreLvl,
CurrentExp = user.InfraCoreExp,
GainExp = rewardCount
};
}
else if (rewardType == RewardType.ItemRandomBox)
{
ItemConsumeRecord? cItem = GameData.Instance.ConsumableItems.Where(x => x.Value.id == rewardId).FirstOrDefault().Value;
if (cItem.item_sub_type == ItemSubType.ItemRandomBoxList)
{
NetRewardData reward = NetUtils.UseLootBox(user, rewardId, rewardCount);
ret = NetUtils.MergeRewards([ret, reward], user);
}
else
{
NetItemData itm = new()
{
Count = rewardCount,
Tid = cItem.id,
Isn = user.GenerateUniqueItemId()
};
ret.Item.Add(itm);
user.Items.Add(new ItemData() { Count = rewardCount, Isn = itm.Isn, ItemType = itm.Tid });
}
}
else if (rewardType == RewardType.FavoriteItem)
{
NetUserFavoriteItemData newFavoriteItem = new NetUserFavoriteItemData
{
FavoriteItemId = user.GenerateUniqueItemId(),
Tid = rewardId,
Csn = 0,
Lv = 0,
Exp = 0
};
user.FavoriteItems.Add(newFavoriteItem);
ret.UserFavoriteItems.Add(newFavoriteItem);
NetFavoriteItemData favoriteItemData = new NetFavoriteItemData
{
FavoriteItemId = newFavoriteItem.FavoriteItemId,
Tid = newFavoriteItem.Tid,
Csn = newFavoriteItem.Csn,
Lv = newFavoriteItem.Lv,
Exp = newFavoriteItem.Exp
};
ret.FavoriteItems.Add(favoriteItemData);
}
else
{
Logging.WriteLine("TODO: Reward type " + rewardType, LogType.Warning);
}
}
}
}