EXP and levels now get saved and loaded from database, changed battlecommand id dictionary to hold lists to account for archer and DoH/DoLs getting multiple abilities at certain levels. Level 1 abilities are now added to the hotbar on character creation.

This commit is contained in:
yogurt 2017-09-30 07:28:08 -05:00
parent ab98f3662f
commit 5dfbc0f249
5 changed files with 254 additions and 34 deletions

View File

@ -231,15 +231,51 @@ namespace FFXIVClassic_Lobby_Server
catch (MySqlException e)
{
Program.Log.Error(e.ToString());
conn.Dispose();
return;
}
//Create Hotbar
try
{
MySqlCommand cmd = new MySqlCommand();
cmd.Connection = conn;
cmd.CommandText = "SELECT id FROM server_battle_commands WHERE classJob = @classjob AND lvl = 1 ORDER BY id DESC";
cmd.Prepare();
cmd.Parameters.AddWithValue("@classJob", charaInfo.currentClass);
List<uint> defaultActions = new List<uint>();
using (var reader = cmd.ExecuteReader())
{
while(reader.Read())
{
defaultActions.Add(reader.GetUInt32("id"));
}
}
MySqlCommand cmd2 = new MySqlCommand();
cmd2.Connection = conn;
cmd2.CommandText = "INSERT INTO characters_hotbar (characterId, classId, hotbarSlot, commandId, recastTime) VALUES (@characterId, @classId, @hotbarSlot, @commandId, 0)";
cmd2.Prepare();
cmd2.Parameters.AddWithValue("@characterId", cid);
cmd2.Parameters.AddWithValue("@classId", charaInfo.currentClass);
cmd2.Parameters.Add("@hotbarSlot", MySqlDbType.Int16);
cmd2.Parameters.Add("@commandId", MySqlDbType.Int16);
for(int i = 0; i < defaultActions.Count; i++)
{
cmd2.Parameters["@hotbarSlot"].Value = i;
cmd2.Parameters["@commandId"].Value = defaultActions[i];
cmd2.ExecuteNonQuery();
}
}
catch(MySqlException e)
{
Program.Log.Error(e.ToString());
}
finally
{
conn.Dispose();
}
}
Program.Log.Debug("[SQL] CID={0} state updated to active(2).", cid);

View File

@ -785,6 +785,62 @@ namespace FFXIVClassic_Map_Server
}
}
//Get class experience
query = @"
SELECT
pug,
gla,
mrd,
arc,
lnc,
thm,
cnj,
crp,
bsm,
arm,
gsm,
ltw,
wvr,
alc,
cul,
min,
btn,
fsh
FROM characters_class_exp WHERE characterId = @charId";
cmd = new MySqlCommand(query, conn);
cmd.Parameters.AddWithValue("@charId", player.actorId);
using (MySqlDataReader reader = cmd.ExecuteReader())
{
if (reader.Read())
{
player.charaWork.battleSave.skillPoint[Player.CLASSID_PUG - 1] = reader.GetInt16("pug");
player.charaWork.battleSave.skillPoint[Player.CLASSID_GLA - 1] = reader.GetInt16("gla");
player.charaWork.battleSave.skillPoint[Player.CLASSID_MRD - 1] = reader.GetInt16("mrd");
player.charaWork.battleSave.skillPoint[Player.CLASSID_ARC - 1] = reader.GetInt16("arc");
player.charaWork.battleSave.skillPoint[Player.CLASSID_LNC - 1] = reader.GetInt16("lnc");
player.charaWork.battleSave.skillPoint[Player.CLASSID_THM - 1] = reader.GetInt16("thm");
player.charaWork.battleSave.skillPoint[Player.CLASSID_CNJ - 1] = reader.GetInt16("cnj");
player.charaWork.battleSave.skillPoint[Player.CLASSID_CRP - 1] = reader.GetInt16("crp");
player.charaWork.battleSave.skillPoint[Player.CLASSID_BSM - 1] = reader.GetInt16("bsm");
player.charaWork.battleSave.skillPoint[Player.CLASSID_ARM - 1] = reader.GetInt16("arm");
player.charaWork.battleSave.skillPoint[Player.CLASSID_GSM - 1] = reader.GetInt16("gsm");
player.charaWork.battleSave.skillPoint[Player.CLASSID_LTW - 1] = reader.GetInt16("ltw");
player.charaWork.battleSave.skillPoint[Player.CLASSID_WVR - 1] = reader.GetInt16("wvr");
player.charaWork.battleSave.skillPoint[Player.CLASSID_ALC - 1] = reader.GetInt16("alc");
player.charaWork.battleSave.skillPoint[Player.CLASSID_CUL - 1] = reader.GetInt16("cul");
player.charaWork.battleSave.skillPoint[Player.CLASSID_MIN - 1] = reader.GetInt16("min");
player.charaWork.battleSave.skillPoint[Player.CLASSID_BTN - 1] = reader.GetInt16("btn");
player.charaWork.battleSave.skillPoint[Player.CLASSID_FSH - 1] = reader.GetInt16("fsh");
}
}
//Load Saved Parameters
query = @"
SELECT
@ -1327,7 +1383,7 @@ namespace FFXIVClassic_Map_Server
cmd = new MySqlCommand(query, conn);
cmd.Parameters.AddWithValue("@charId", player.actorId);
cmd.Parameters.AddWithValue("@classId", player.charaWork.parameterSave.state_mainSkill[0]);
cmd.Parameters.AddWithValue("@classId", player.GetCurrentClassOrJob());
player.charaWork.commandBorder = 32;
@ -2197,10 +2253,8 @@ namespace FFXIVClassic_Map_Server
}
}
public static void LoadGlobalBattleCommandList(Dictionary<ushort, BattleCommand> battleCommandDict, Dictionary<Tuple<byte, short>, uint> battleCommandIdByLevel)
public static void LoadGlobalBattleCommandList(Dictionary<ushort, BattleCommand> battleCommandDict, Dictionary<Tuple<byte, short>, List<uint>> battleCommandIdByLevel)
{
//var battleCommands = new Dictionary<ushort, BattleCommand>();
using (MySqlConnection conn = new MySqlConnection(String.Format("Server={0}; Port={1}; Database={2}; UID={3}; Password={4}", ConfigConstants.DATABASE_HOST, ConfigConstants.DATABASE_PORT, ConfigConstants.DATABASE_NAME, ConfigConstants.DATABASE_USERNAME, ConfigConstants.DATABASE_PASSWORD)))
{
try
@ -2248,9 +2302,16 @@ namespace FFXIVClassic_Map_Server
battleCommandDict.Add(id, battleCommand);
//Handle level 1 abilities separately because of FUCKING ARCHER REEE, just add those to the hotbar when the job is unlocked or on char creation, ez
if(battleCommand.level > 1)
battleCommandIdByLevel.Add(Tuple.Create<byte, short>(battleCommand.job, battleCommand.level), id | 0xA0F00000);
Tuple<byte, short> tuple = Tuple.Create<byte, short>(battleCommand.job, battleCommand.level);
if (battleCommandIdByLevel.ContainsKey(tuple))
{
battleCommandIdByLevel[tuple].Add(id | 0xA0F00000);
}
else
{
List<uint> list = new List<uint>() { id | 0xA0F00000 };
battleCommandIdByLevel.Add(tuple, list);
}
}
}
}
@ -2264,6 +2325,72 @@ namespace FFXIVClassic_Map_Server
}
}
}
public static void SetExp(Player player, byte classId, int exp)
{
using (MySqlConnection conn = new MySqlConnection(String.Format("Server={0}; Port={1}; Database={2}; UID={3}; Password={4}", ConfigConstants.DATABASE_HOST, ConfigConstants.DATABASE_PORT, ConfigConstants.DATABASE_NAME, ConfigConstants.DATABASE_USERNAME, ConfigConstants.DATABASE_PASSWORD)))
{
try
{
conn.Open();
var query = String.Format(@"
UPDATE characters_class_exp
SET
{0} = @exp
WHERE
characterId = @characterId", CharacterUtils.GetClassNameForId(classId));
MySqlCommand cmd = new MySqlCommand(query, conn);
cmd.Prepare();
cmd = new MySqlCommand(query, conn);
cmd.Parameters.AddWithValue("@characterId", player.actorId);
cmd.Parameters.AddWithValue("@exp", exp);
cmd.ExecuteNonQuery();
}
catch (MySqlException e)
{
Program.Log.Error(e.ToString());
}
finally
{
conn.Dispose();
}
}
}
public static void SetLevel(Player player, byte classId, short level)
{
using (MySqlConnection conn = new MySqlConnection(String.Format("Server={0}; Port={1}; Database={2}; UID={3}; Password={4}", ConfigConstants.DATABASE_HOST, ConfigConstants.DATABASE_PORT, ConfigConstants.DATABASE_NAME, ConfigConstants.DATABASE_USERNAME, ConfigConstants.DATABASE_PASSWORD)))
{
try
{
conn.Open();
var query = String.Format(@"
UPDATE characters_class_levels
SET
{0} = @lvl
WHERE
characterId = @characterId", CharacterUtils.GetClassNameForId(classId));
MySqlCommand cmd = new MySqlCommand(query, conn);
cmd.Prepare();
cmd = new MySqlCommand(query, conn);
cmd.Parameters.AddWithValue("@characterId", player.actorId);
cmd.Parameters.AddWithValue("@lvl", level);
cmd.ExecuteNonQuery();
}
catch (MySqlException e)
{
Program.Log.Error(e.ToString());
}
finally
{
conn.Dispose();
}
}
}
}
}

View File

@ -40,7 +40,7 @@ namespace FFXIVClassic_Map_Server
private Dictionary<ulong, Party> currentPlayerParties = new Dictionary<ulong, Party>(); //GroupId, Party object
private Dictionary<uint, StatusEffect> statusEffectList = new Dictionary<uint, StatusEffect>();
private Dictionary<ushort, BattleCommand> battleCommandList = new Dictionary<ushort, BattleCommand>();
private Dictionary<Tuple<byte, short>, uint> battleCommandIdByLevel = new Dictionary<Tuple<byte, short>, uint>();//Holds battle command ids keyed by class id and level (in that order)
private Dictionary<Tuple<byte, short>, List<uint>> battleCommandIdByLevel = new Dictionary<Tuple<byte, short>, List<uint>>();//Holds battle command ids keyed by class id and level (in that order)
private Dictionary<uint, ModifierList> battleNpcGenusMods = new Dictionary<uint, ModifierList>();
private Dictionary<uint, ModifierList> battleNpcPoolMods = new Dictionary<uint, ModifierList>();
private Dictionary<uint, ModifierList> battleNpcSpawnMods = new Dictionary<uint, ModifierList>();
@ -1432,10 +1432,10 @@ namespace FFXIVClassic_Map_Server
return battleCommandList.TryGetValue((ushort)id, out battleCommand) ? battleCommand.Clone() : null;
}
public uint GetBattleCommandIdByLevel(byte classId, short level)
public List<uint> GetBattleCommandIdByLevel(byte classId, short level)
{
uint id = 0;
return battleCommandIdByLevel.TryGetValue(Tuple.Create(classId, level), out id) ? id : 0;
List<uint> ids;
return battleCommandIdByLevel.TryGetValue(Tuple.Create(classId, level), out ids) ? ids : new List<uint>();
}
}
}

View File

@ -389,11 +389,28 @@ namespace FFXIVClassic_Map_Server.Actors
propPacketUtil.AddProperty("charaWork.battleTemp.castGauge_speed[1]");
//Battle Save Skillpoint
propPacketUtil.AddProperty($"charaWork.battleSave.skillPoint[{CLASSID_ALC - 1}]");
propPacketUtil.AddProperty($"charaWork.battleSave.skillPoint[{CLASSID_ARC - 1}]");
propPacketUtil.AddProperty($"charaWork.battleSave.skillPoint[{CLASSID_ARM - 1}]");
propPacketUtil.AddProperty($"charaWork.battleSave.skillPoint[{CLASSID_BSM - 1}]");
propPacketUtil.AddProperty($"charaWork.battleSave.skillPoint[{CLASSID_BTN - 1}]");
propPacketUtil.AddProperty($"charaWork.battleSave.skillPoint[{CLASSID_CNJ - 1}]");
propPacketUtil.AddProperty($"charaWork.battleSave.skillPoint[{CLASSID_CRP - 1}]");
propPacketUtil.AddProperty($"charaWork.battleSave.skillPoint[{CLASSID_CUL - 1}]");
propPacketUtil.AddProperty($"charaWork.battleSave.skillPoint[{CLASSID_FSH - 1}]");
propPacketUtil.AddProperty($"charaWork.battleSave.skillPoint[{CLASSID_GLA - 1}]");
propPacketUtil.AddProperty($"charaWork.battleSave.skillPoint[{CLASSID_GSM - 1}]");
propPacketUtil.AddProperty($"charaWork.battleSave.skillPoint[{CLASSID_LNC - 1}]");
propPacketUtil.AddProperty($"charaWork.battleSave.skillPoint[{CLASSID_LTW - 1}]");
propPacketUtil.AddProperty($"charaWork.battleSave.skillPoint[{CLASSID_MIN - 1}]");
propPacketUtil.AddProperty($"charaWork.battleSave.skillPoint[{CLASSID_MRD - 1}]");
propPacketUtil.AddProperty($"charaWork.battleSave.skillPoint[{CLASSID_PUG - 1}]");
propPacketUtil.AddProperty($"charaWork.battleSave.skillPoint[{CLASSID_THM - 1}]");
propPacketUtil.AddProperty($"charaWork.battleSave.skillPoint[{CLASSID_WVR - 1}]");
//Commands
propPacketUtil.AddProperty("charaWork.commandBorder");
for (int i = 0; i < charaWork.command.Length; i++)
{
if (charaWork.command[i] != 0)
@ -408,7 +425,6 @@ namespace FFXIVClassic_Map_Server.Actors
}
}
for (int i = 0; i < charaWork.commandCategory.Length; i++)
{
charaWork.commandCategory[i] = 1;
@ -422,7 +438,6 @@ namespace FFXIVClassic_Map_Server.Actors
propPacketUtil.AddProperty(String.Format("charaWork.commandAcquired[{0}]", i));
}
for (int i = 0; i < charaWork.additionalCommandAcquired.Length; i++)
{
if (charaWork.additionalCommandAcquired[i] != false)
@ -436,13 +451,11 @@ namespace FFXIVClassic_Map_Server.Actors
propPacketUtil.AddProperty(String.Format("charaWork.parameterSave.commandSlot_compatibility[{0}]", i));
}
/*
for (int i = 0; i < charaWork.parameterSave.commandSlot_recastTime.Length; i++)
{
if (charaWork.parameterSave.commandSlot_recastTime[i] != 0)
propPacketUtil.AddProperty(String.Format("charaWork.parameterSave.commandSlot_recastTime[{0}]", i));
}
*/
for (int i = 0; i < charaWork.parameterSave.commandSlot_recastTime.Length; i++)
{
if (charaWork.parameterSave.commandSlot_recastTime[i] != 0)
propPacketUtil.AddProperty(String.Format("charaWork.parameterSave.commandSlot_recastTime[{0}]", i));
}
//System
propPacketUtil.AddProperty("charaWork.parameterTemp.forceControl_float_forClientSelf[0]");
@ -2219,7 +2232,7 @@ namespace FFXIVClassic_Map_Server.Actors
bool leveled = false;
int diff = MAXEXP[GetLevel() - 1] - charaWork.battleSave.skillPoint[classId - 1];
//While there is enough experience to level up, keep leveling up and unlocking skills and removing experience
//While there is enough experience to level up, keep leveling up, unlocking skills and removing experience from exp until we don't have enough to level up
while (exp >= diff && GetLevel() < charaWork.battleSave.skillLevelCap[classId])
{
//Level up
@ -2243,14 +2256,17 @@ namespace FFXIVClassic_Map_Server.Actors
QueuePackets(expPropertyPacket3.Done());
//play levelup animation (do this outside LevelUp so that it only plays once if multiple levels are earned
//also i dunno how to do this
Database.SetLevel(this, classId, GetLevel());
}
//Cap experience for level 50
charaWork.battleSave.skillPoint[classId - 1] = Math.Min(charaWork.battleSave.skillPoint[classId - 1] + exp, MAXEXP[GetLevel() - 1]);
ActorPropertyPacketUtil expPropertyPacket = new ActorPropertyPacketUtil("charaWork/battleStateForSelf", this);
expPropertyPacket.AddProperty($"charaWork.battleSave.skillPoint[{classId - 1}]");
//Cap experience for level 50
QueuePackets(expPropertyPacket.Done());
Database.SetExp(this, classId, charaWork.battleSave.skillPoint[classId - 1]);
}
public void LevelUp(byte classId)
@ -2263,12 +2279,12 @@ namespace FFXIVClassic_Map_Server.Actors
SendGameMessage(this, Server.GetWorldManager().GetActor(), 33909, 0x44, this, 0, 0, 0, 0, 0, 0, 0, 0, 0, (int) GetLevel());
//If there's an ability that unlocks at this level, equip it.
uint commandId = Server.GetWorldManager().GetBattleCommandIdByLevel(classId, GetLevel());
if (commandId > 0)
List<uint> commandIds = Server.GetWorldManager().GetBattleCommandIdByLevel(classId, GetLevel());
foreach(uint commandId in commandIds)
{
EquipAbilityInFirstOpenSlot(classId, commandId, false);
byte jobId = ConvertClassIdToJobId(classId);
if (jobId != classId)
if (jobId != classId)
EquipAbilityInFirstOpenSlot(jobId, commandId, false);
}
}
@ -2287,7 +2303,7 @@ namespace FFXIVClassic_Map_Server.Actors
break;
case CLASSID_ARC:
case CLASSID_LNC:
jobId += 10;
jobId += 11;
break;
case CLASSID_THM:
case CLASSID_CNJ:
@ -2297,5 +2313,20 @@ namespace FFXIVClassic_Map_Server.Actors
return jobId;
}
public void SetCurrentJob(byte jobId)
{
currentJob = jobId;
BroadcastPacket(SetCurrentJobPacket.BuildPacket(actorId, jobId), true);
Database.LoadHotbar(this);
}
public byte GetCurrentClassOrJob()
{
if (currentJob != 0)
return (byte) currentJob;
return charaWork.parameterSave.state_mainSkill[0];
}
}
}

View File

@ -96,5 +96,31 @@ namespace FFXIVClassic_Map_Server.utils
}
}
public static string GetClassNameForId(short id)
{
switch (id)
{
case 2: return "pug";
case 3: return "gla";
case 4: return "mrd";
case 7: return "arc";
case 8: return "lnc";
case 22: return "thm";
case 23: return "cnj";
case 29: return "crp";
case 30: return "bsm";
case 31: return "arm";
case 32: return "gsm";
case 33: return "ltw";
case 34: return "wvr";
case 35: return "alc";
case 36: return "cul";
case 39: return "min";
case 40: return "btn";
case 41: return "fsh";
default: return "undefined";
}
}
}
}