mirror of
https://github.com/EpinelPS/EpinelPS.git
synced 2025-12-12 23:14:34 +01:00
Skill upgrade, more commands, fixes (#21)
* add BuyWallpaper * added partial stage clear info handling, no longer fails get check the creation of the clear info still has imperfections, so I've left it disabled for now. no point in letting it clutter the DB until the info is at least accurate in the UI. * unfinished CP calculation stuff still need to impl other tables (equipment), need a better way to capture outputs and compare them to retail, not really worth the excess work currently since CP calc isn't used anywhere critical right now * AddItem command * AddCharacter command * finishalltutorials command * addallmaterials command also load the material items table * skill upgrade impl * update README * potential fix for bodies not being removed properly on limit breaks and core upgrades the client seems to be smart enough to deal with zero count item entries, so there's no real reason to remove zero count item entries from the DB * check to make sure we have the character before adding a body * use CreateWholeUserDataFromDbUser instead of doing a manual copy
This commit is contained in:
@@ -183,6 +183,7 @@ namespace EpinelPS.Database
|
||||
public NetWallpaperJukeboxFavorite[] WallpaperFavoriteList = [];
|
||||
public NetWallpaperPlaylist[] WallpaperPlaylistList = [];
|
||||
public NetWallpaperJukebox[] WallpaperJukeboxList = [];
|
||||
public List<int> LobbyDecoBackgroundList = [];
|
||||
|
||||
|
||||
public Dictionary<int, NetUserTeamData> UserTeams = new Dictionary<int, NetUserTeamData>();
|
||||
@@ -208,6 +209,8 @@ namespace EpinelPS.Database
|
||||
public OutpostBuffs OutpostBuffs = new();
|
||||
public Dictionary<int, UnlockData> ContentsOpenUnlocked = new();
|
||||
|
||||
public List<NetStageClearInfo> StageClearHistorys = [];
|
||||
|
||||
// Event data
|
||||
public Dictionary<int, EventData> EventInfo = new();
|
||||
public MogMinigameInfo MogInfo = new();
|
||||
@@ -381,25 +384,13 @@ namespace EpinelPS.Database
|
||||
break;
|
||||
|
||||
if (item.Isn == isn)
|
||||
{
|
||||
if (item.Count == 1)
|
||||
{
|
||||
Items.Remove(item);
|
||||
count--;
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO test this
|
||||
if (item.Count >= count)
|
||||
{
|
||||
removed++;
|
||||
item.Count -= count;
|
||||
}
|
||||
else
|
||||
|
||||
if (item.Count < 0)
|
||||
{
|
||||
removed += item.Count;
|
||||
Items.Remove(item);
|
||||
}
|
||||
item.Count = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,8 +32,9 @@ namespace EpinelPS.StaticInfo
|
||||
private Dictionary<int, CampaignChapterRecord> chapterCampaignData;
|
||||
private JArray characterCostumeTable;
|
||||
public Dictionary<int, CharacterRecord> characterTable;
|
||||
private Dictionary<int, ClearedTutorialData> tutorialTable;
|
||||
private Dictionary<int, ItemEquipRecord> itemEquipTable;
|
||||
public Dictionary<int, ClearedTutorialData> tutorialTable;
|
||||
public Dictionary<int, ItemEquipRecord> itemEquipTable;
|
||||
public Dictionary<int, ItemMaterialRecord> itemMaterialTable;
|
||||
private Dictionary<string, JArray> FieldMapData = new Dictionary<string, JArray>(); // Fixed initialization
|
||||
private Dictionary<int, CharacterLevelData> LevelData = new Dictionary<int, CharacterLevelData>(); // Fixed initialization
|
||||
private Dictionary<int, TacticAcademyLessonRecord> TacticAcademyLessons = new Dictionary<int, TacticAcademyLessonRecord>(); // Fixed initialization
|
||||
@@ -54,6 +55,9 @@ namespace EpinelPS.StaticInfo
|
||||
public Dictionary<int, ArchiveEventDungeonStageRecord> archiveEventDungeonStageRecords = new Dictionary<int, ArchiveEventDungeonStageRecord>();
|
||||
public Dictionary<int, UserTitleRecord> userTitleRecords = new Dictionary<int, UserTitleRecord>();
|
||||
public Dictionary<int, ArchiveMessengerConditionRecord> archiveMessengerConditionRecords;
|
||||
public Dictionary<int, CharacterStatRecord> characterStatTable;
|
||||
public Dictionary<int, SkillInfoRecord> skillInfoTable;
|
||||
public Dictionary<int, CostRecord> costTable;
|
||||
|
||||
|
||||
|
||||
@@ -90,6 +94,10 @@ namespace EpinelPS.StaticInfo
|
||||
ZipStream = new();
|
||||
tutorialTable = new();
|
||||
itemEquipTable = new();
|
||||
itemMaterialTable = new();
|
||||
characterStatTable = new();
|
||||
skillInfoTable = new();
|
||||
costTable = new();
|
||||
|
||||
// Initialize Jukebox data dictionaries
|
||||
jukeboxListDataRecords = new Dictionary<int, JukeboxListRecord>();
|
||||
@@ -320,6 +328,12 @@ namespace EpinelPS.StaticInfo
|
||||
this.itemEquipTable.Add(obj.id, obj);
|
||||
}
|
||||
|
||||
var itemMaterialTable = await LoadZip<ItemMaterialTable>("ItemMaterialTable.json", progress);
|
||||
foreach (var obj in itemMaterialTable.records)
|
||||
{
|
||||
this.itemMaterialTable.Add(obj.id, obj);
|
||||
}
|
||||
|
||||
var characterLevelTable = await LoadZip("CharacterLevelTable.json", progress);
|
||||
|
||||
foreach (JToken item in characterLevelTable)
|
||||
@@ -460,6 +474,24 @@ namespace EpinelPS.StaticInfo
|
||||
// Load Jukebox data
|
||||
await LoadJukeboxListData(progress);
|
||||
await LoadJukeboxThemeData(progress);
|
||||
|
||||
var characterStatTable = await LoadZip<CharacterStatTable>("CharacterStatTable.json", progress);
|
||||
foreach (var obj in characterStatTable.records)
|
||||
{
|
||||
this.characterStatTable.Add(obj.id, obj);
|
||||
}
|
||||
|
||||
var skillinfoTable = await LoadZip<SkillInfoTable>("SkillInfoTable.json", progress);
|
||||
foreach (var obj in skillinfoTable.records)
|
||||
{
|
||||
this.skillInfoTable.Add(obj.id, obj);
|
||||
}
|
||||
|
||||
var costTable = await LoadZip<CostTable>("CostTable.json", progress);
|
||||
foreach (var obj in costTable.records)
|
||||
{
|
||||
this.costTable.Add(obj.id, obj);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task LoadJukeboxListData(ProgressBar bar)
|
||||
|
||||
@@ -136,6 +136,33 @@
|
||||
public int grade_core_id;
|
||||
public int name_code;
|
||||
public int grow_grade;
|
||||
public int stat_enhance_id;
|
||||
public string character_class;
|
||||
public List<int> element_id;
|
||||
public int critical_ratio;
|
||||
public int critical_damage;
|
||||
public int shot_id;
|
||||
public int bonusrange_min;
|
||||
public int bonusrange_max;
|
||||
public string use_burst_skill;
|
||||
public string change_burst_step;
|
||||
public int burst_apply_delay;
|
||||
public int burst_duration;
|
||||
public int ulti_skill_id;
|
||||
public int skill1_id;
|
||||
public string skill1_table;
|
||||
public int skill2_id;
|
||||
public string skill2_table;
|
||||
public string eff_category_type;
|
||||
public int eff_category_value;
|
||||
public string category_type_1;
|
||||
public string category_type_2;
|
||||
public string category_type_3;
|
||||
public string cv_localkey;
|
||||
public string squad;
|
||||
public bool is_visible;
|
||||
public bool prism_is_active;
|
||||
public bool is_detail_close;
|
||||
}
|
||||
public class CharacterTable
|
||||
{
|
||||
@@ -427,4 +454,82 @@
|
||||
public List<ArchiveMessengerConditionRecord> records;
|
||||
}
|
||||
|
||||
public class CharacterStatRecord
|
||||
{
|
||||
public int id;
|
||||
public int group;
|
||||
public int level;
|
||||
public int level_hp;
|
||||
public int level_attack;
|
||||
public int level_defence;
|
||||
public int level_energy_resist;
|
||||
public int level_bio_resist;
|
||||
}
|
||||
|
||||
public class CharacterStatTable
|
||||
{
|
||||
public List<CharacterStatRecord> records;
|
||||
}
|
||||
|
||||
public class ItemMaterialRecord
|
||||
{
|
||||
public int id;
|
||||
public string name_localkey;
|
||||
public string description_localkey;
|
||||
public string resource_id;
|
||||
public string item_type;
|
||||
public string item_sub_type;
|
||||
public string item_rare;
|
||||
public int item_value;
|
||||
public string material_type;
|
||||
public int material_value;
|
||||
public int stack_max;
|
||||
}
|
||||
|
||||
public class ItemMaterialTable
|
||||
{
|
||||
public List<ItemMaterialRecord> records;
|
||||
}
|
||||
|
||||
public class SkillInfoRecord
|
||||
{
|
||||
public int id;
|
||||
public int group_id;
|
||||
public int skill_level;
|
||||
public int next_level_id;
|
||||
public int level_up_cost_id;
|
||||
public string icon;
|
||||
public string name_localkey;
|
||||
public string description_localkey;
|
||||
public string info_description_localkey;
|
||||
public List<DescriptionValue> description_value_list;
|
||||
}
|
||||
|
||||
public class DescriptionValue
|
||||
{
|
||||
public string description_value;
|
||||
}
|
||||
|
||||
public class SkillInfoTable
|
||||
{
|
||||
public List<SkillInfoRecord> records;
|
||||
}
|
||||
|
||||
public class CostRecord
|
||||
{
|
||||
public int id;
|
||||
public List<CostData> costs;
|
||||
}
|
||||
|
||||
public class CostData
|
||||
{
|
||||
public string item_type;
|
||||
public int item_id;
|
||||
public int item_value;
|
||||
}
|
||||
|
||||
public class CostTable
|
||||
{
|
||||
public List<CostRecord> records;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,12 +55,9 @@ namespace EpinelPS.LobbyServer.Msgs.Character
|
||||
};
|
||||
|
||||
// remove spare body item
|
||||
var bodyItem = user.Items.FirstOrDefault(i => i.Isn == req.Isn);
|
||||
user.RemoveItemBySerialNumber(req.Isn, 1);
|
||||
|
||||
foreach (var item in user.Items)
|
||||
{
|
||||
response.Items.Add(NetUtils.ToNet(item));
|
||||
}
|
||||
response.Items.Add(NetUtils.ToNet(bodyItem));
|
||||
|
||||
// replace any reference to the old character to the new TID
|
||||
// Check if RepresentationTeamData exists and has slots
|
||||
|
||||
87
EpinelPS/LobbyServer/Msgs/Character/SkillLevelUp.cs
Normal file
87
EpinelPS/LobbyServer/Msgs/Character/SkillLevelUp.cs
Normal file
@@ -0,0 +1,87 @@
|
||||
using EpinelPS.Database;
|
||||
using EpinelPS.StaticInfo;
|
||||
using EpinelPS.Utils;
|
||||
|
||||
namespace EpinelPS.LobbyServer.Msgs.Character
|
||||
{
|
||||
[PacketPath("/character/skill/levelup")]
|
||||
public class SkillLevelUp : LobbyMsgHandler
|
||||
{
|
||||
protected override async Task HandleAsync()
|
||||
{
|
||||
var req = await ReadData<ReqCharacterSkillLevelUp>();
|
||||
var user = GetUser();
|
||||
var response = new ResCharacterSkillLevelUp();
|
||||
var character = user.Characters.FirstOrDefault(c => c.Csn == req.Csn);
|
||||
var charRecord = GameData.Instance.characterTable.Values.FirstOrDefault(c => c.id == character.Tid);
|
||||
var skillIdMap = new Dictionary<int, int>
|
||||
{
|
||||
{ 1, charRecord.ulti_skill_id },
|
||||
{ 2, charRecord.skill1_id },
|
||||
{ 3, charRecord.skill2_id }
|
||||
};
|
||||
var skillLevelMap = new Dictionary<int, int>
|
||||
{
|
||||
{ 1, character.UltimateLevel },
|
||||
{ 2, character.Skill1Lvl },
|
||||
{ 3, character.Skill2Lvl }
|
||||
};
|
||||
var skillRecord = GameData.Instance.skillInfoTable.Values.FirstOrDefault(s => s.id == skillIdMap[req.Category] + (skillLevelMap[req.Category] - 1));
|
||||
var costRecord = GameData.Instance.costTable.Values.FirstOrDefault(c => c.id == skillRecord.level_up_cost_id);
|
||||
|
||||
foreach (var cost in costRecord.costs.Where(i => i.item_type != "None"))
|
||||
{
|
||||
var item = user.Items.FirstOrDefault(i => i.ItemType == cost.item_id);
|
||||
|
||||
item.Count -= cost.item_value;
|
||||
|
||||
response.Items.Add(new NetUserItemData
|
||||
{
|
||||
Isn = item.Isn,
|
||||
Tid = cost.item_id,
|
||||
Count = item.Count,
|
||||
Csn = item.Csn,
|
||||
Corporation = item.Corp,
|
||||
Level = item.Level,
|
||||
Exp = item.Exp,
|
||||
Position = item.Position
|
||||
});
|
||||
}
|
||||
|
||||
var newChar = new NetUserCharacterDefaultData
|
||||
{
|
||||
CostumeId = character.CostumeId,
|
||||
Csn = character.Csn,
|
||||
Level = character.Level,
|
||||
Grade = character.Grade,
|
||||
Tid = character.Tid,
|
||||
DispatchTid = character.Tid,
|
||||
Skill1Lv = character.Skill1Lvl,
|
||||
Skill2Lv = character.Skill2Lvl,
|
||||
UltiSkillLv = character.UltimateLevel,
|
||||
};
|
||||
|
||||
if (req.Category == 1)
|
||||
{
|
||||
character.UltimateLevel++;
|
||||
newChar.UltiSkillLv++;
|
||||
}
|
||||
else if (req.Category == 2)
|
||||
{
|
||||
character.Skill1Lvl++;
|
||||
newChar.Skill1Lv++;
|
||||
}
|
||||
else if (req.Category == 3)
|
||||
{
|
||||
character.Skill2Lvl++;
|
||||
newChar.Skill2Lv++;
|
||||
}
|
||||
|
||||
response.Character = newChar;
|
||||
|
||||
JsonDb.Save();
|
||||
|
||||
await WriteDataAsync(response);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -56,12 +56,9 @@ namespace EpinelPS.LobbyServer.Msgs.Character
|
||||
};
|
||||
|
||||
// remove spare body item
|
||||
var bodyItem = user.Items.FirstOrDefault(i => i.Isn == req.Isn);
|
||||
user.RemoveItemBySerialNumber(req.Isn, 1);
|
||||
|
||||
foreach (var item in user.Items)
|
||||
{
|
||||
response.Items.Add(NetUtils.ToNet(item));
|
||||
}
|
||||
response.Items.Add(NetUtils.ToNet(bodyItem));
|
||||
|
||||
// replace any reference to the old character to the new TID
|
||||
// Check if RepresentationTeamData exists and has slots
|
||||
|
||||
@@ -64,6 +64,8 @@ namespace EpinelPS.LobbyServer.Msgs.Gacha
|
||||
// Add each character's item to user.Items if the character exists in user.Characters
|
||||
foreach (var characterData in selectedCharacters)
|
||||
{
|
||||
if (user.HasCharacter(characterData.id))
|
||||
{
|
||||
// Check if the item for this character already exists in user.Items based on ItemType
|
||||
var existingItem = user.Items.FirstOrDefault(item => item.ItemType == characterData.piece_id);
|
||||
|
||||
@@ -113,6 +115,7 @@ namespace EpinelPS.LobbyServer.Msgs.Gacha
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Populate the 2D array with characterId and pieceId for each selected character
|
||||
foreach (var characterData in selectedCharacters)
|
||||
|
||||
@@ -104,6 +104,8 @@ namespace EpinelPS.LobbyServer.Msgs.Stage
|
||||
}
|
||||
}
|
||||
|
||||
// CreateClearInfo(user);
|
||||
|
||||
var key = (clearedStage.chapter_id - 1) + "_" + clearedStage.chapter_mod;
|
||||
if (!user.FieldInfoNew.ContainsKey(key))
|
||||
user.FieldInfoNew.Add(key, new FieldInfoNew());
|
||||
@@ -309,5 +311,29 @@ namespace EpinelPS.LobbyServer.Msgs.Stage
|
||||
}
|
||||
// TODO: add neon
|
||||
}
|
||||
|
||||
private static void CreateClearInfo(Database.User user)
|
||||
{
|
||||
NetStageClearInfo clearInfo = new NetStageClearInfo
|
||||
{
|
||||
User = LobbyHandler.CreateWholeUserDataFromDbUser(user),
|
||||
TeamCombat = user.RepresentationTeamData.TeamCombat,
|
||||
ClearedAt = DateTimeOffset.UtcNow.Ticks
|
||||
};
|
||||
|
||||
foreach (var character in user.RepresentationTeamData.Slots)
|
||||
{
|
||||
clearInfo.Slots.Add(new NetStageClearInfoTeam()
|
||||
{
|
||||
Slot = character.Slot,
|
||||
Tid = character.Tid,
|
||||
Level = character.Level,
|
||||
Combat = FormulaUtils.CalculateCP(user, character.Csn),
|
||||
CharacterType = StageClearInfoTeamCharacterType.StageClearInfoTeamCharacterTypeOwnedCharacter // TODO: how do we get this?
|
||||
});
|
||||
}
|
||||
|
||||
user.StageClearHistorys.Add(clearInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
19
EpinelPS/LobbyServer/Msgs/Stage/GetStageClearInfo.cs
Normal file
19
EpinelPS/LobbyServer/Msgs/Stage/GetStageClearInfo.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using EpinelPS.Utils;
|
||||
|
||||
namespace EpinelPS.LobbyServer.Msgs.Stage
|
||||
{
|
||||
[PacketPath("/stageclearinfo/get")]
|
||||
public class GetStageClearInfo : LobbyMsgHandler
|
||||
{
|
||||
protected override async Task HandleAsync()
|
||||
{
|
||||
var req = await ReadData<ReqGetStageClearInfo>();
|
||||
var response = new ResGetStageClearInfo();
|
||||
var user = GetUser();
|
||||
|
||||
response.Historys.AddRange(user.StageClearHistorys);
|
||||
|
||||
await WriteDataAsync(response);
|
||||
}
|
||||
}
|
||||
}
|
||||
24
EpinelPS/LobbyServer/Msgs/User/BuyWallpaper.cs
Normal file
24
EpinelPS/LobbyServer/Msgs/User/BuyWallpaper.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using EpinelPS.Database;
|
||||
using EpinelPS.Utils;
|
||||
|
||||
namespace EpinelPS.LobbyServer.Msgs.User
|
||||
{
|
||||
[PacketPath("/user/wallpaper/buy")]
|
||||
public class BuyWallpaper : LobbyMsgHandler
|
||||
{
|
||||
protected override async Task HandleAsync()
|
||||
{
|
||||
var req = await ReadData<ReqBuyLobbyDecoBackground>();
|
||||
var response = new ResBuyLobbyDecoBackground();
|
||||
var user = GetUser();
|
||||
|
||||
user.LobbyDecoBackgroundList.Add(req.LobbyDecoBackgroundId);
|
||||
|
||||
response.OwnedLobbyDecoBackgroundIdList.Add(user.LobbyDecoBackgroundList);
|
||||
|
||||
JsonDb.Save();
|
||||
|
||||
await WriteDataAsync(response);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -85,6 +85,8 @@ namespace EpinelPS.LobbyServer.Msgs.User
|
||||
response.LastClearedNormalMainStageId = user.LastNormalStageCleared;
|
||||
response.TimeRewardBuffs.AddRange(NetUtils.GetOutpostTimeReward(user));
|
||||
|
||||
response.OwnedLobbyDecoBackgroundIdList.AddRange(user.LobbyDecoBackgroundList);
|
||||
|
||||
await WriteDataAsync(response);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ namespace EpinelPS.LobbyServer.Msgs.User
|
||||
response.WallpaperJukeboxList.AddRange(user.WallpaperJukeboxList);
|
||||
response.WallpaperBackgroundList.AddRange(user.WallpaperBackground);
|
||||
response.WallpaperFavoriteList.AddRange(user.WallpaperFavoriteList);
|
||||
response.OwnedLobbyDecoBackgroundIdList.AddRange(user.LobbyDecoBackgroundList);
|
||||
|
||||
// TODO: JukeboxIdList
|
||||
|
||||
|
||||
@@ -221,8 +221,11 @@ namespace EpinelPS
|
||||
Console.WriteLine(" SetLevel (level) - Set all characters' level (between 1 and 999 takes effect on game and server restart)");
|
||||
Console.WriteLine(" SetSkillLevel (level) - Set all characters' skill levels between 1 and 10 (takes effect on game and server restart)");
|
||||
Console.WriteLine(" addallcharacters - Add all missing characters to the selected user with default levels and skills (takes effect on game and server restart)");
|
||||
Console.WriteLine(" addallmaterials (amount) - Add all materials to the selected user with default levels and skills (takes effect on game and server restart)");
|
||||
Console.WriteLine(" finishalltutorials - finish all tutorials for the selected user (takes effect on game and server restart)");
|
||||
Console.WriteLine(" SetCoreLevel (core level / 0-3 sets stars) - Set all characters' grades based on the input (from 0 to 11)");
|
||||
|
||||
Console.WriteLine(" AddItem (id) (amount) - Adds an item to the selected user (takes effect on game and server restart)");
|
||||
Console.WriteLine(" AddCharacter (id) - Adds a character to the selected user (takes effect on game and server restart)");
|
||||
}
|
||||
else if (input == "ls /users")
|
||||
{
|
||||
@@ -309,6 +312,85 @@ namespace EpinelPS
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (input == "addallmaterials")
|
||||
{
|
||||
if (selectedUser == 0)
|
||||
{
|
||||
Console.WriteLine("No user selected");
|
||||
}
|
||||
else
|
||||
{
|
||||
var user = JsonDb.Instance.Users.FirstOrDefault(x => x.ID == selectedUser);
|
||||
if (user == null)
|
||||
{
|
||||
Console.WriteLine("Selected user does not exist");
|
||||
selectedUser = 0;
|
||||
prompt = "# ";
|
||||
}
|
||||
else
|
||||
{
|
||||
int amount = 1000000;
|
||||
if (args.Length >= 2)
|
||||
{
|
||||
int.TryParse(args[1], out amount);
|
||||
}
|
||||
|
||||
foreach (var tableItem in GameData.Instance.itemMaterialTable.Values)
|
||||
{
|
||||
ItemData? item = user.Items.FirstOrDefault(i => i.ItemType == tableItem.id);
|
||||
|
||||
if (item == null)
|
||||
{
|
||||
user.Items.Add(new ItemData
|
||||
{
|
||||
Isn = user.GenerateUniqueItemId(),
|
||||
ItemType = tableItem.id,
|
||||
Level = 1,
|
||||
Exp = 1,
|
||||
Count = amount
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
item.Count += amount;
|
||||
}
|
||||
}
|
||||
|
||||
Console.WriteLine($"Added {amount} of all materials to user " + user.Username);
|
||||
JsonDb.Save();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (input == "finishalltutorials")
|
||||
{
|
||||
if (selectedUser == 0)
|
||||
{
|
||||
Console.WriteLine("No user selected");
|
||||
}
|
||||
else
|
||||
{
|
||||
var user = JsonDb.Instance.Users.FirstOrDefault(x => x.ID == selectedUser);
|
||||
if (user == null)
|
||||
{
|
||||
Console.WriteLine("Selected user does not exist");
|
||||
selectedUser = 0;
|
||||
prompt = "# ";
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var tutorial in GameData.Instance.tutorialTable.Values)
|
||||
{
|
||||
if (!user.ClearedTutorialData.ContainsKey(tutorial.id))
|
||||
{
|
||||
user.ClearedTutorialData.Add(tutorial.id, tutorial);
|
||||
}
|
||||
}
|
||||
|
||||
Console.WriteLine("Finished all tutorials for user " + user.Username);
|
||||
JsonDb.Save();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (input.StartsWith("SetCoreLevel"))
|
||||
{
|
||||
if (selectedUser == 0)
|
||||
@@ -689,10 +771,120 @@ namespace EpinelPS
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (input.StartsWith("AddItem"))
|
||||
{
|
||||
if (selectedUser == 0)
|
||||
{
|
||||
Console.WriteLine("No user selected");
|
||||
}
|
||||
else
|
||||
{
|
||||
var user = JsonDb.Instance.Users.FirstOrDefault(x => x.ID == selectedUser);
|
||||
if (user == null)
|
||||
{
|
||||
Console.WriteLine("Selected user does not exist");
|
||||
selectedUser = 0;
|
||||
prompt = "# ";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (args.Length == 3)
|
||||
{
|
||||
if (int.TryParse(args[1], out int itemId) && int.TryParse(args[2], out int amount))
|
||||
{
|
||||
ItemData? item = user.Items.FirstOrDefault(i => i.ItemType == itemId);
|
||||
|
||||
if (item == null)
|
||||
{
|
||||
user.Items.Add(new ItemData
|
||||
{
|
||||
Isn = user.GenerateUniqueItemId(),
|
||||
ItemType = itemId,
|
||||
Level = 1,
|
||||
Exp = 1,
|
||||
Count = amount
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
item.Count += amount;
|
||||
|
||||
if (item.Count < 0)
|
||||
{
|
||||
item.Count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
Console.WriteLine($"Added {amount} of item {itemId} to user {user.Username}");
|
||||
JsonDb.Save();
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Invalid item ID or amount");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Invalid argument length, must be 2");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (input.StartsWith("AddCharacter"))
|
||||
{
|
||||
if (selectedUser == 0)
|
||||
{
|
||||
Console.WriteLine("No user selected");
|
||||
}
|
||||
else
|
||||
{
|
||||
var user = JsonDb.Instance.Users.FirstOrDefault(x => x.ID == selectedUser);
|
||||
if (user == null)
|
||||
{
|
||||
Console.WriteLine("Selected user does not exist");
|
||||
selectedUser = 0;
|
||||
prompt = "# ";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (args.Length == 2)
|
||||
{
|
||||
if (int.TryParse(args[1], out int characterId))
|
||||
{
|
||||
if (!user.HasCharacter(characterId))
|
||||
{
|
||||
user.Characters.Add(new Database.Character()
|
||||
{
|
||||
CostumeId = 0,
|
||||
Csn = user.GenerateUniqueCharacterId(),
|
||||
Grade = 0,
|
||||
Level = 1,
|
||||
Skill1Lvl = 1,
|
||||
Skill2Lvl = 1,
|
||||
Tid = characterId,
|
||||
UltimateLevel = 1
|
||||
});
|
||||
|
||||
Console.WriteLine($"Added character {characterId} to user {user.Username}");
|
||||
JsonDb.Save();
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"User {user.Username} already has character {characterId}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Invalid character ID");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Invalid argument length, must be 1");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (input == "exit")
|
||||
{
|
||||
Environment.Exit(0);
|
||||
|
||||
32
EpinelPS/Utils/FormulaUtils.cs
Normal file
32
EpinelPS/Utils/FormulaUtils.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using EpinelPS.StaticInfo;
|
||||
|
||||
namespace EpinelPS.Utils
|
||||
{
|
||||
public class FormulaUtils
|
||||
{
|
||||
public static int CalculateCP(Database.User user, long csn)
|
||||
{
|
||||
var character = user.Characters.FirstOrDefault(c => c.Csn == csn);
|
||||
var charRecord = GameData.Instance.characterTable.Values.FirstOrDefault(c => c.id == character.Tid);
|
||||
var statRecord = GameData.Instance.characterStatTable.Values.FirstOrDefault(s => charRecord.stat_enhance_id == s.group + (character.Level - 1));
|
||||
float coreMult = 1f + character.Grade * 0.02f;
|
||||
float hp = statRecord.level_hp * coreMult;
|
||||
float atk = statRecord.level_attack * coreMult;
|
||||
float def = statRecord.level_defence * coreMult;
|
||||
float critRate = charRecord.critical_ratio;
|
||||
float critDamage = charRecord.critical_damage;
|
||||
float skill1Level = character.Skill1Lvl;
|
||||
float skill2Level = character.Skill2Lvl;
|
||||
float ultSkillLevel = character.UltimateLevel;
|
||||
float critResult = 1 + ((critRate / 10000f) * (critDamage / 10000f - 1));
|
||||
float effHealthResult = (def * 100) + hp;
|
||||
float skillResult = (skill1Level * 0.01f) + (skill2Level * 0.01f) + (ultSkillLevel * 0.02f);
|
||||
float bondResult = 0f; // TODO
|
||||
float equipResult = 0f; // TOD
|
||||
float overloadResult = 0; // TODO
|
||||
float finalResult = (((critResult * atk * 18) + (effHealthResult * 0.7f)) * (1.3f + skillResult) + bondResult + equipResult + overloadResult) / 100f;
|
||||
|
||||
return (int)Math.Round(finalResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -45,7 +45,7 @@ To skip stages, a basic command line interface is implemented.
|
||||
- [X] Outpost Rewards
|
||||
- [ ] Admin Panel
|
||||
- [ ] Simulation Room
|
||||
- [ ] Skill level up
|
||||
- [X] Skill level up
|
||||
- [ ] Outpost jukebox
|
||||
- [ ] Event system
|
||||
- [ ] Download all game assets ahead of time
|
||||
@@ -57,7 +57,6 @@ To skip stages, a basic command line interface is implemented.
|
||||
|
||||
## What is not working:
|
||||
- Events
|
||||
- Skill upgrade
|
||||
- Mission reward, daily/weekly missions
|
||||
- Side quests
|
||||
- Lots of things in the outpost
|
||||
|
||||
Reference in New Issue
Block a user