diff --git a/FFXIVClassic Map Server/Database.cs b/FFXIVClassic Map Server/Database.cs index 576ef116..6677faa1 100644 --- a/FFXIVClassic Map Server/Database.cs +++ b/FFXIVClassic Map Server/Database.cs @@ -949,27 +949,9 @@ namespace FFXIVClassic_Map_Server player.timers[i] = reader.GetUInt32(i); } } - - //Load Hotbar - query = @" - SELECT - hotbarSlot, - commandId, - recastTime - FROM characters_hotbar WHERE characterId = @charId AND classId = @classId"; - cmd = new MySqlCommand(query, conn); - cmd.Parameters.AddWithValue("@charId", player.actorId); - cmd.Parameters.AddWithValue("@classId", player.charaWork.parameterSave.state_mainSkill[0]); - using (MySqlDataReader reader = cmd.ExecuteReader()) - { - while (reader.Read()) - { - int index = reader.GetUInt16(0); - player.charaWork.command[index+32] = reader.GetUInt32(1); - player.charaWork.parameterSave.commandSlot_recastTime[index] = reader.GetUInt32(2); - } - } + //Load Hotbar + LoadHotbar(player); //Load Scenario Quests query = @" @@ -1208,6 +1190,143 @@ namespace FFXIVClassic_Map_Server } } + public static void EquipAbility(Player player, ushort hotbarSlot, uint commandId, uint recastTime) + { + //2700083201 is where abilities start. 2700083200 is for unequipping abilities. Trying to put this in the hotbar will crash the game, need to put 0 instead + if (commandId > 2700083200) + { + 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(); + MySqlCommand cmd; + string query = @" + INSERT INTO characters_hotbar + (characterId, classId, hotbarSlot, commandId, recastTime) + VALUES + (@charId, @classId, @hotbarSlot, @commandId, @recastTime) + ON DUPLICATE KEY UPDATE commandId=@commandId, recastTime=@recastTime; + "; + + cmd = new MySqlCommand(query, conn); + cmd.Parameters.AddWithValue("@charId", player.actorId); + cmd.Parameters.AddWithValue("@classId", player.charaWork.parameterSave.state_mainSkill[0]); + cmd.Parameters.AddWithValue("@commandId", commandId); + cmd.Parameters.AddWithValue("@hotbarSlot", hotbarSlot); + cmd.Parameters.AddWithValue("@recastTime", recastTime); + cmd.ExecuteNonQuery(); + } + catch (MySqlException e) + { + Program.Log.Error(e.ToString()); + } + finally + { + conn.Dispose(); + } + } + } + } + + //Unequipping is done by sending an equip packet with 2700083200 as the ability and the hotbar slot of the action being unequipped + public static void UnequipAbility(Player player, ushort hotbarSlot) + { + 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(); + MySqlCommand cmd; + string query = ""; + + //Drop + List> hotbarList = new List>(); + query = @" + DELETE FROM characters_hotbar + WHERE characterId = @charId AND classId = @classId AND hotbarSlot = @hotbarSlot + "; + cmd = new MySqlCommand(query, conn); + cmd.Parameters.AddWithValue("@charId", player.actorId); + cmd.Parameters.AddWithValue("@classId", player.charaWork.parameterSave.state_mainSkill[0]); + cmd.Parameters.AddWithValue("@hotbarSlot", hotbarSlot - 1); + cmd.ExecuteNonQuery(); + } + catch (MySqlException e) + { + Program.Log.Error(e.ToString()); + } + finally + { + conn.Dispose(); + } + } + + } + + public static void LoadHotbar(Player player) + { + string query; + MySqlCommand cmd; + + 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(); + //Load Hotbar + query = @" + SELECT + hotbarSlot, + commandId, + recastTime + FROM characters_hotbar WHERE characterId = @charId AND classId = @classId + ORDER BY hotbarSlot"; + + cmd = new MySqlCommand(query, conn); + cmd.Parameters.AddWithValue("@charId", player.actorId); + cmd.Parameters.AddWithValue("@classId", player.charaWork.parameterSave.state_mainSkill[0]); + player.charaWork.commandBorder = 32; + for (int i = player.charaWork.commandBorder; i < player.charaWork.commandCategory.Length; i++) + { + player.charaWork.command[i] = 0; + player.charaWork.commandCategory[i] = 0; + player.charaWork.parameterSave.commandSlot_recastTime[i - player.charaWork.commandBorder] = 0; + } + + using (MySqlDataReader reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + int index = reader.GetUInt16(0); + player.charaWork.command[index] = reader.GetUInt32(1); + player.charaWork.commandCategory[index] = 1; + player.charaWork.parameterSave.commandSlot_recastTime[index - player.charaWork.commandBorder] = reader.GetUInt32(2); + } + } + } + catch (MySqlException e) + { + Program.Log.Error(e.ToString()); + } + finally + { + conn.Dispose(); + } + } + } public static List GetInventory(Player player, uint slotOffset, uint type) { diff --git a/FFXIVClassic Map Server/actors/Actor.cs b/FFXIVClassic Map Server/actors/Actor.cs index 283884cf..9f09d162 100644 --- a/FFXIVClassic Map Server/actors/Actor.cs +++ b/FFXIVClassic Map Server/actors/Actor.cs @@ -82,7 +82,7 @@ namespace FFXIVClassic_Map_Server.Actors } } } - + public void ResetMoveSpeedsToDefault() { this.moveSpeeds[0] = SetActorSpeedPacket.DEFAULT_STOP; @@ -94,11 +94,12 @@ namespace FFXIVClassic_Map_Server.Actors this.moveState = this.oldMoveState; hasMoved = true; } - - public SubPacket CreateAddActorPacket(byte val) { + + public SubPacket CreateAddActorPacket(byte val) + { return AddActorPacket.BuildPacket(actorId, val); } - + public SubPacket CreateNamePacket() { return SetActorNamePacket.BuildPacket(actorId, displayNameId, displayNameId == 0xFFFFFFFF | displayNameId == 0x0 ? customDisplayName : ""); @@ -160,7 +161,7 @@ namespace FFXIVClassic_Map_Server.Actors updateMs = 150; } - if (forceUpdate || (hasMoved && ((this is Player ) || diffTime.Milliseconds >= updateMs))) + if (forceUpdate || (hasMoved && ((this is Player) || diffTime.Milliseconds >= updateMs))) { hasMoved = (this.positionUpdates != null && this.positionUpdates.Count > 0); if (hasMoved) @@ -169,7 +170,7 @@ namespace FFXIVClassic_Map_Server.Actors if (this is Character) ((Character)this).OnPath(pos); - + positionX = pos.X; positionY = pos.Y; positionZ = pos.Z; @@ -284,7 +285,7 @@ namespace FFXIVClassic_Map_Server.Actors public SubPacket CreateIsZoneingPacket() { - return SetActorIsZoningPacket.BuildPacket(actorId, false); + return SetActorIsZoningPacket.BuildPacket(actorId, false); } public virtual SubPacket CreateScriptBindPacket(Player player) @@ -292,13 +293,13 @@ namespace FFXIVClassic_Map_Server.Actors return ActorInstantiatePacket.BuildPacket(actorId, actorName, className, classParams); } - public virtual SubPacket CreateScriptBindPacket() + public virtual SubPacket CreateScriptBindPacket() { return ActorInstantiatePacket.BuildPacket(actorId, actorName, className, classParams); } - + public virtual List GetSpawnPackets(Player player, ushort spawnType) - { + { List subpackets = new List(); subpackets.Add(CreateAddActorPacket(8)); subpackets.AddRange(GetEventConditionPackets()); diff --git a/FFXIVClassic Map Server/actors/area/Area.cs b/FFXIVClassic Map Server/actors/area/Area.cs index b223072e..c21cc087 100644 --- a/FFXIVClassic Map Server/actors/area/Area.cs +++ b/FFXIVClassic Map Server/actors/area/Area.cs @@ -376,23 +376,23 @@ namespace FFXIVClassic_Map_Server.Actors } } - // todo: for zones override this to seach contentareas (assuming flag is passed) + // todo: for zones override this to seach contentareas (assuming flag is passed) public virtual List GetAllActors() where T : Actor { lock (mActorList) { List actorList = new List(mActorList.Count); - actorList.AddRange(mActorList.Values.OfType()); + actorList.AddRange(mActorList.Values.OfType()); return actorList; } } - + public virtual List GetAllActors() { return GetAllActors(); } - + public void BroadcastPacketsAroundActor(Actor actor, List packets) { foreach (SubPacket packet in packets) diff --git a/FFXIVClassic Map Server/actors/chara/player/Inventory.cs b/FFXIVClassic Map Server/actors/chara/player/Inventory.cs index 2066ad72..6d6042b8 100644 --- a/FFXIVClassic Map Server/actors/chara/player/Inventory.cs +++ b/FFXIVClassic Map Server/actors/chara/player/Inventory.cs @@ -1,5 +1,5 @@ - -using FFXIVClassic.Common; + +using FFXIVClassic.Common; using FFXIVClassic_Map_Server.Actors; using FFXIVClassic_Map_Server.dataobjects; using FFXIVClassic_Map_Server.packets.send.actor.inventory; @@ -95,11 +95,11 @@ namespace FFXIVClassic_Map_Server.actors.chara.player ItemData gItem = Server.GetItemGamedata(itemId); List slotsToUpdate = new List(); List addItemPackets = new List(); - + if (gItem == null) { Program.Log.Error("Inventory.AddItem: unable to find item %u", itemId); - return false; + return false; } //Check if item id exists diff --git a/FFXIVClassic Map Server/actors/chara/player/Player.cs b/FFXIVClassic Map Server/actors/chara/player/Player.cs index 1799273d..42715695 100644 --- a/FFXIVClassic Map Server/actors/chara/player/Player.cs +++ b/FFXIVClassic Map Server/actors/chara/player/Player.cs @@ -211,11 +211,7 @@ namespace FFXIVClassic_Map_Server.Actors charaWork.command[12] = 0xA0F00000 | 22012; charaWork.command[13] = 0xA0F00000 | 22013; charaWork.command[14] = 0xA0F00000 | 29497; - charaWork.command[15] = 0xA0F00000 | 22015; - - charaWork.command[32] = 0xA0F00000 | 27191; - charaWork.command[33] = 0xA0F00000 | 22302; - charaWork.command[34] = 0xA0F00000 | 28466; + charaWork.command[15] = 0xA0F00000 | 22015; charaWork.commandAcquired[27150 - 26000] = true; @@ -235,13 +231,9 @@ namespace FFXIVClassic_Map_Server.Actors charaWork.commandCategory[0] = 1; charaWork.commandCategory[1] = 1; - charaWork.commandCategory[32] = 1; - charaWork.commandCategory[33] = 1; - charaWork.commandCategory[34] = 1; charaWork.parameterSave.commandSlot_compatibility[0] = true; charaWork.parameterSave.commandSlot_compatibility[1] = true; - charaWork.parameterSave.commandSlot_compatibility[32] = true; charaWork.commandBorder = 0x20; @@ -276,13 +268,13 @@ namespace FFXIVClassic_Map_Server.Actors * Unknown - Bool * Unknown - Number * Unknown - Bool - * Timer Array - 20 Number + * Timer Array - 20 Number */ public override SubPacket CreateScriptBindPacket(Player requestPlayer) { List lParams; - if (IsMyPlayer(requestPlayer.actorId)) + if (IsMyPlayer(requestPlayer.actorId)) { if (loginInitDirector != null) lParams = LuaUtils.CreateLuaParamList("/Chara/Player/Player_work", false, false, true, loginInitDirector, true, 0, false, timers, true); @@ -294,31 +286,32 @@ namespace FFXIVClassic_Map_Server.Actors ActorInstantiatePacket.BuildPacket(actorId, actorName, className, lParams).DebugPrintSubPacket(); + return ActorInstantiatePacket.BuildPacket(actorId, actorName, className, lParams); } - public override List GetSpawnPackets(Player requestPlayer, ushort spawnType) + public override List GetSpawnPackets(Player requestPlayer, ushort spawnType) { List subpackets = new List(); subpackets.Add(CreateAddActorPacket(8)); if (IsMyPlayer(requestPlayer.actorId)) subpackets.AddRange(Create0x132Packets()); - subpackets.Add(CreateSpeedPacket()); - subpackets.Add(CreateSpawnPositonPacket(this, spawnType)); + subpackets.Add(CreateSpeedPacket()); + subpackets.Add(CreateSpawnPositonPacket(this, spawnType)); subpackets.Add(CreateAppearancePacket()); subpackets.Add(CreateNamePacket()); subpackets.Add(_0xFPacket.BuildPacket(actorId)); subpackets.Add(CreateStatePacket()); subpackets.Add(CreateIdleAnimationPacket()); - subpackets.Add(CreateInitStatusPacket()); + subpackets.Add(CreateInitStatusPacket()); subpackets.Add(CreateSetActorIconPacket()); - subpackets.Add(CreateIsZoneingPacket()); + subpackets.Add(CreateIsZoneingPacket()); subpackets.AddRange(CreatePlayerRelatedPackets(requestPlayer.actorId)); subpackets.Add(CreateScriptBindPacket(requestPlayer)); return subpackets; } - - public List CreatePlayerRelatedPackets(uint requestingPlayerActorId) + + public List CreatePlayerRelatedPackets(uint requestingPlayerActorId) { List subpackets = new List(); @@ -328,10 +321,10 @@ namespace FFXIVClassic_Map_Server.Actors if (currentTitle != 0) subpackets.Add(SetPlayerTitlePacket.BuildPacket(actorId, currentTitle)); - if (currentJob != 0) + if (currentJob != 0) subpackets.Add(SetCurrentJobPacket.BuildPacket(actorId, currentJob)); - if (IsMyPlayer(requestingPlayerActorId)) + if (IsMyPlayer(requestingPlayerActorId)) { subpackets.Add(SetSpecialEventWorkPacket.BuildPacket(actorId)); @@ -355,9 +348,9 @@ namespace FFXIVClassic_Map_Server.Actors subpackets.Add(SetCurrentMountGoobbuePacket.BuildPacket(actorId, 1)); return subpackets; - } - - public override List GetInitPackets() + } + + public override List GetInitPackets() { ActorPropertyPacketUtil propPacketUtil = new ActorPropertyPacketUtil("/_init", this); @@ -519,10 +512,10 @@ namespace FFXIVClassic_Map_Server.Actors QueuePacket(_0x10Packet.BuildPacket(actorId, 0xFF)); QueuePacket(SetMusicPacket.BuildPacket(actorId, zone.bgmDay, 0x01)); QueuePacket(SetWeatherPacket.BuildPacket(actorId, SetWeatherPacket.WEATHER_CLEAR, 1)); - - QueuePacket(SetMapPacket.BuildPacket(actorId, zone.regionId, zone.actorId)); - QueuePackets(GetSpawnPackets(this, spawnType)); + QueuePacket(SetMapPacket.BuildPacket(actorId, zone.regionId, zone.actorId)); + + QueuePackets(GetSpawnPackets(this, spawnType)); //GetSpawnPackets(actorId, spawnType).DebugPrintPacket(); #region Inventory & Equipment @@ -532,7 +525,7 @@ namespace FFXIVClassic_Map_Server.Actors inventories[Inventory.KEYITEMS].SendFullInventory(); inventories[Inventory.BAZAAR].SendFullInventory(); inventories[Inventory.MELDREQUEST].SendFullInventory(); - inventories[Inventory.LOOT].SendFullInventory(); + inventories[Inventory.LOOT].SendFullInventory(); equipment.SendFullEquipment(false); playerSession.QueuePacket(InventoryEndChangePacket.BuildPacket(actorId)); #endregion @@ -542,9 +535,9 @@ namespace FFXIVClassic_Map_Server.Actors List areaMasterSpawn = zone.GetSpawnPackets(); List debugSpawn = world.GetDebugActor().GetSpawnPackets(); List worldMasterSpawn = world.GetActor().GetSpawnPackets(); - + playerSession.QueuePacket(areaMasterSpawn); - playerSession.QueuePacket(debugSpawn); + playerSession.QueuePacket(debugSpawn); playerSession.QueuePacket(worldMasterSpawn); //Inn Packets (Dream, Cutscenes, Armoire) @@ -560,16 +553,16 @@ namespace FFXIVClassic_Map_Server.Actors QueuePacket(SetPlayerItemStoragePacket.BuildPacket(actorId)); } - if (zone.GetWeatherDirector() != null) + if (zone.GetWeatherDirector() != null) { - playerSession.QueuePacket(zone.GetWeatherDirector().GetSpawnPackets()); + playerSession.QueuePacket(zone.GetWeatherDirector().GetSpawnPackets()); } - + foreach (Director director in ownedDirectors) { - QueuePackets(director.GetSpawnPackets()); - QueuePackets(director.GetInitPackets()); + QueuePackets(director.GetSpawnPackets()); + QueuePackets(director.GetInitPackets()); } if (currentContentGroup != null) @@ -601,17 +594,17 @@ namespace FFXIVClassic_Map_Server.Actors public bool IsMyPlayer(uint otherActorId) { - return actorId == otherActorId; + return actorId == otherActorId; } - + public void QueuePacket(SubPacket packet) { playerSession.QueuePacket(packet); } - public void QueuePackets(List packets) - { - playerSession.QueuePacket(packets); + public void QueuePackets(List packets) + { + playerSession.QueuePacket(packets); } public void SendPacket(string path) @@ -967,7 +960,7 @@ namespace FFXIVClassic_Map_Server.Actors charaWork.parameterSave.state_mainSkill[0] = classId; charaWork.parameterSave.state_mainSkillLevel = charaWork.battleSave.skillLevel[classId-1]; - + Database.LoadHotbar(this); playerWork.restBonusExpRate = 0.0f; ActorPropertyPacketUtil propertyBuilder = new ActorPropertyPacketUtil("charaWork/stateForAll", this); @@ -977,6 +970,8 @@ namespace FFXIVClassic_Map_Server.Actors propertyBuilder.NewTarget("playerWork/expBonus"); propertyBuilder.AddProperty("playerWork.restBonusExpRate"); + QueuePackets(GetUpdateHotbarPacket(actorId).Done()); + List packets = propertyBuilder.Done(); foreach (SubPacket packet in packets) @@ -1161,17 +1156,17 @@ namespace FFXIVClassic_Map_Server.Actors } public void MarkGuildleve(uint id, bool abandoned, bool completed) - { + { if (HasGuildleve(id)) - { + { for (int i = 0; i < work.guildleveId.Length; i++) { if (work.guildleveId[i] == id) { work.guildleveChecked[i] = completed; - work.guildleveDone[i] = abandoned; + work.guildleveDone[i] = abandoned; Database.MarkGuildleve(this, id, abandoned, completed); - SendGuildleveMarkClientUpdate(i); + SendGuildleveMarkClientUpdate(i); } } } @@ -1437,8 +1432,8 @@ namespace FFXIVClassic_Map_Server.Actors QueuePackets(propPacketUtil.Done()); } - private void SendGuildleveClientUpdate(int slot) - { + private void SendGuildleveClientUpdate(int slot) + { ActorPropertyPacketUtil propPacketUtil = new ActorPropertyPacketUtil("work/guildleve", this); propPacketUtil.AddProperty(String.Format("work.guildleveId[{0}]", slot)); QueuePackets(propPacketUtil.Done()); @@ -1466,29 +1461,29 @@ namespace FFXIVClassic_Map_Server.Actors director.AddMember(this); } } - - public void SendDirectorPackets(Director director) + + public void SendDirectorPackets(Director director) { QueuePackets(director.GetSpawnPackets()); - QueuePackets(director.GetInitPackets()); + QueuePackets(director.GetInitPackets()); } public void RemoveDirector(Director director) - { + { if (ownedDirectors.Contains(director)) { - QueuePacket(RemoveActorPacket.BuildPacket(director.actorId)); + QueuePacket(RemoveActorPacket.BuildPacket(director.actorId)); ownedDirectors.Remove(director); director.RemoveMember(this); } } - - public GuildleveDirector GetGuildleveDirector() + + public GuildleveDirector GetGuildleveDirector() { foreach (Director d in ownedDirectors) { - if (d is GuildleveDirector) - return (GuildleveDirector)d; + if (d is GuildleveDirector) + return (GuildleveDirector)d; } return null; @@ -1681,12 +1676,161 @@ namespace FFXIVClassic_Map_Server.Actors currentParty = null; } - - public void Update(double delta) { LuaEngine.GetInstance().CallLuaFunction(this, this, "OnUpdate", true, delta); } + //Update all the hotbar slots past the commandborder. Commands before the commandborder only need to be sent on init since they never change + public ActorPropertyPacketUtil GetUpdateHotbarPacket(uint playerActorId) + { + List slotsToUpdate = new List(); + for (ushort i = charaWork.commandBorder; i < charaWork.commandBorder + 30; i++) + { + slotsToUpdate.Add(i); + } + + return GetUpdateHotbarPacket(playerActorId, slotsToUpdate); + } + + //Update select hotbar slots. + public ActorPropertyPacketUtil GetUpdateHotbarPacket(uint playerActorId, List slotsToUpdate) + { + ActorPropertyPacketUtil propPacketUtil = new ActorPropertyPacketUtil("charawork/command", this); + + propPacketUtil.AddProperty("charaWork.commandBorder"); + + foreach (ushort slot in slotsToUpdate) + { + propPacketUtil.AddProperty(String.Format("charaWork.command[{0}]", slot)); + propPacketUtil.AddProperty(String.Format("charaWork.commandCategory[{0}]", slot)); + } + + for (int i = 0; i < charaWork.parameterSave.commandSlot_compatibility.Length; i++) + { + //charaWork.parameterSave.commandSlot_compatibility[i] = true; + // propPacketUtil.AddProperty(String.Format("charaWork.parameterSave.commandSlot_compatibility[{0}]", i)); + } + + charaWork.parameterTemp.otherClassAbilityCount[0] = 3; + charaWork.parameterTemp.otherClassAbilityCount[1] = 5; + // charaWork.parameterTemp.giftCount[1] = 5; + propPacketUtil.AddProperty("charaWork.parameterTemp.otherClassAbilityCount[0]"); + propPacketUtil.AddProperty("charaWork.parameterTemp.otherClassAbilityCount[1]"); + propPacketUtil.AddProperty("charaWork.parameterTemp.giftCount[1]"); + + ActorPropertyPacketUtil recastPacketUtil = new ActorPropertyPacketUtil("charaWork/commandDetailForSelf", this); + for(int i = 0; i < charaWork.parameterSave.commandSlot_recastTime.Length; i++) + { + propPacketUtil.AddProperty(String.Format("charawork.parameterSave.commandSlot_recastTime[{0}]", i)); + propPacketUtil.AddProperty(String.Format("charawork.parameterTemp.maxCommandRecastTime[{0}]", i)); + } + + QueuePackets(recastPacketUtil.Done()); + + return propPacketUtil; + } + + + public void EquipAbility(ushort hotbarSlot, uint commandId, uint recastTime) + { + //if (charaWork.commandAcquired[commandId]) + { + uint trueCommandId = 0xA0F00000 | commandId; + ushort trueHotbarSlot = (ushort)(hotbarSlot + charaWork.commandBorder - 1); + ushort endOfHotbar = (ushort)(charaWork.commandBorder + 30); + List slotsToUpdate = new List(); + if (trueCommandId != 2700083200) + { + bool canEquip = true; + bool isAlreadyEquipped = false; + + //If hotbar slot is 0, look for the first open slot + if (hotbarSlot == 0) + { + trueHotbarSlot = findFirstCommandSlotById(0); + int equippedSlot = findFirstCommandSlotById(trueCommandId); + //We can only equip a command if there is an open hotbar slot and if the command was not found in the hotbar. + canEquip = trueHotbarSlot < endOfHotbar && equippedSlot >= endOfHotbar; + //If the command was found in the hotbar, mark it as already equipped + isAlreadyEquipped = equippedSlot < endOfHotbar; + } + //If the slot the command is being moved to is occupied, move that command to the slot currently occupied by the command being placed. + else if (charaWork.command[trueHotbarSlot] != trueCommandId) + { + ushort oldSlot = findFirstCommandSlotById(trueCommandId); + //If the command was found, update the old slot, otherwise it will just be overwritten + if (oldSlot < endOfHotbar) + { + Database.EquipAbility(this, oldSlot, charaWork.command[trueHotbarSlot], recastTime); + charaWork.command[oldSlot] = charaWork.command[trueHotbarSlot]; + slotsToUpdate.Add(oldSlot); + } + } + + if (canEquip) + { + Actor a = Server.GetStaticActors(trueCommandId); + Database.EquipAbility(this, trueHotbarSlot, trueCommandId, recastTime); + charaWork.command[trueHotbarSlot] = trueCommandId; + charaWork.commandCategory[trueHotbarSlot] = 1; + slotsToUpdate.Add(trueHotbarSlot); + + //"[Command] set." + SendGameMessage(Server.GetWorldManager().GetActor(), 30603, 0x20, 0, commandId); + } + else if (isAlreadyEquipped) + { + //"That action is already set to an action slot." + SendGameMessage(Server.GetWorldManager().GetActor(), 30719, 0x20, 0); + } + else + { + //"You cannot set any more actions." + SendGameMessage(Server.GetWorldManager().GetActor(), 30720, 0x20, 0); + } + } + //Unequip command + else if (trueCommandId == 2700083200) + { + //Need to get the commandId this way because when unequipping an ability the commandId is 0. + commandId = charaWork.command[trueHotbarSlot] ^ 2700083200; + SendGameMessage(Server.GetWorldManager().GetActor(), 30604, 0x20, 0, charaWork.command[trueHotbarSlot] ^ 2700083200); + Database.UnequipAbility(this, trueHotbarSlot); + charaWork.command[trueHotbarSlot] = 0; + slotsToUpdate.Add(trueHotbarSlot); + //"[Command] removed." + SendGameMessage(Server.GetWorldManager().GetActor(), 30747, 0x20, 0); + + } + ActorPropertyPacketUtil packet = GetUpdateHotbarPacket(actorId, slotsToUpdate); + QueuePackets(packet.Done()); + } + //action not acquired + // else + { + //"You have not yet acquired that action." + //SendGameMessage(Server.GetWorldManager().GetActor(), 30742, 0x20, 0, 0); + } + } + + //Finds the first hotbar slot with a given commandId. + //If the returned value is outside the hotbar, it indicates it wasn't found. + private ushort findFirstCommandSlotById(uint commandId) + { + ushort firstSlot = (ushort)(charaWork.commandBorder + 30); + + for (ushort i = charaWork.commandBorder; i < charaWork.commandBorder + 30; i++) + { + if (charaWork.command[i] == commandId) + { + firstSlot = i; + break; + } + } + + return firstSlot; + } + } } diff --git a/data/scripts/commands/EquipAbilityCommand.lua b/data/scripts/commands/EquipAbilityCommand.lua new file mode 100644 index 00000000..946c5a2a --- /dev/null +++ b/data/scripts/commands/EquipAbilityCommand.lua @@ -0,0 +1,14 @@ +require ("global") +--player: Player that called this command +--equipAbilityWidget: Widget that calls this command +--triggername: Event Starter ? +--slot: Which slot the ability will go into +--ability: Ability being equipped + + +function onEventStarted(player, equipAbilityWidget, triggername, slot, ability, unkown, arg1, arg2, arg3, arg4, arg5, arg6) + if ability then + player:EquipAbility(slot, ability, 1); + end + player:endEvent(); +end \ No newline at end of file diff --git a/data/scripts/player.lua b/data/scripts/player.lua index 19930b93..817ab4cb 100644 --- a/data/scripts/player.lua +++ b/data/scripts/player.lua @@ -1,7 +1,6 @@ local initClassItems, initRaceItems; -function onBeginLogin(player) - +function onBeginLogin(player) --New character, set the initial quest if (player:GetPlayTime(false) == 0) then initialTown = player:GetInitialTown(); @@ -60,7 +59,6 @@ function onBeginLogin(player) player:GetQuest(110009):ClearQuestData(); player:GetQuest(110009):ClearQuestFlags(); end - end function onLogin(player)