diff --git a/FFXIVClassic Map Server/actors/chara/player/Equipment.cs b/FFXIVClassic Map Server/actors/chara/player/Equipment.cs index f25e3314..49181e09 100644 --- a/FFXIVClassic Map Server/actors/chara/player/Equipment.cs +++ b/FFXIVClassic Map Server/actors/chara/player/Equipment.cs @@ -26,11 +26,11 @@ namespace FFXIVClassic_Map_Server.actors.chara.player public const int SLOT_RIGHTFINGER = 21; public const int SLOT_LEFTFINGER = 22; - private Player owner; - private ushort inventoryCapacity; - private ushort inventoryCode; + readonly private Player owner; + readonly private ushort inventoryCapacity; + readonly private ushort inventoryCode; private InventoryItem[] list; - private ItemPackage normalInventory; + readonly private ItemPackage normalInventory; private bool writeToDB = true; @@ -43,62 +43,6 @@ namespace FFXIVClassic_Map_Server.actors.chara.player this.normalInventory = normalInventory; } - public InventoryItem GetItemAtSlot(ushort slot) - { - if (slot < list.Length) - return list[slot]; - else - return null; - } - - public void SendCheckEquipmentToPlayer(Player toPlayer) - { - List items = new List(); - for (ushort i = 0; i < list.Length; i++) - { - if (list[i] != null) - { - InventoryItem equipItem = new InventoryItem(list[i], i); - items.Add(equipItem); - } - } - - toPlayer.QueuePacket(InventorySetBeginPacket.BuildPacket(owner.actorId, 0x23, ItemPackage.EQUIPMENT_OTHERPLAYER)); - int currentIndex = 0; - - while (true) - { - if (items.Count - currentIndex >= 16) - toPlayer.QueuePacket(InventoryListX16Packet.BuildPacket(owner.actorId, items, ref currentIndex)); - else if (items.Count - currentIndex > 1) - toPlayer.QueuePacket(InventoryListX08Packet.BuildPacket(owner.actorId, items, ref currentIndex)); - else if (items.Count - currentIndex == 1) - { - toPlayer.QueuePacket(InventoryListX01Packet.BuildPacket(owner.actorId, items[currentIndex])); - currentIndex++; - } - else - break; - } - toPlayer.QueuePacket(InventorySetEndPacket.BuildPacket(owner.actorId)); - } - - public void SendFullEquipment(bool DoClear) - { - List slotsToUpdate = new List(); - for (ushort i = 0; i < list.Length; i++) - { - if (list[i] == null && DoClear) - slotsToUpdate.Add(0); - else if (list[i] != null) - slotsToUpdate.Add(i); - } - - owner.QueuePacket(InventorySetBeginPacket.BuildPacket(owner.actorId, inventoryCapacity, inventoryCode)); - SendEquipmentPackets(slotsToUpdate); - owner.QueuePacket(InventorySetEndPacket.BuildPacket(owner.actorId)); - } - public void SetEquipment(ushort[] slots, ushort[] itemSlots) { if (slots.Length != itemSlots.Length) @@ -116,7 +60,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.player } owner.QueuePacket(InventoryBeginChangePacket.BuildPacket(owner.actorId)); - SendFullEquipment(false); + SendFullEquipment(owner); owner.QueuePacket(InventoryEndChangePacket.BuildPacket(owner.actorId)); } @@ -157,7 +101,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.player normalInventory.RefreshItem(owner, item); owner.QueuePacket(InventorySetBeginPacket.BuildPacket(owner.actorId, inventoryCapacity, inventoryCode)); - SendEquipmentPackets(slot, item); + SendSingleEquipmentUpdatePacket(slot, item); owner.QueuePacket(InventorySetEndPacket.BuildPacket(owner.actorId)); owner.QueuePacket(InventoryEndChangePacket.BuildPacket(owner.actorId)); @@ -179,52 +123,23 @@ namespace FFXIVClassic_Map_Server.actors.chara.player if (writeToDB) Database.UnequipItem(owner, slot); - owner.QueuePacket(InventoryBeginChangePacket.BuildPacket(owner.actorId)); normalInventory.RefreshItem(owner, list[slot]); - owner.QueuePacket(InventorySetBeginPacket.BuildPacket(owner.actorId, inventoryCapacity, inventoryCode)); - SendEquipmentPackets(slot, null); - owner.QueuePacket(InventorySetEndPacket.BuildPacket(owner.actorId)); - + owner.QueuePacket(InventoryBeginChangePacket.BuildPacket(owner.actorId)); + SendSingleEquipmentUpdatePacket(slot, null); owner.QueuePacket(InventoryEndChangePacket.BuildPacket(owner.actorId)); list[slot] = null; owner.RecalculateStats(); } - private void SendEquipmentPackets(ushort equipSlot, InventoryItem item) + public InventoryItem GetItemAtSlot(ushort slot) { - if (item == null) - owner.QueuePacket(InventoryRemoveX01Packet.BuildPacket(owner.actorId, equipSlot)); + if (slot < list.Length) + return list[slot]; else - owner.QueuePacket(EquipmentListX01Packet.BuildPacket(owner.actorId, equipSlot, item.slot)); - } - - private void SendEquipmentPackets(List slotsToUpdate) - { - - int currentIndex = 0; - - while (true) - { - if (slotsToUpdate.Count - currentIndex >= 64) - owner.QueuePacket(EquipmentListX64Packet.BuildPacket(owner.actorId, list, slotsToUpdate, ref currentIndex)); - else if (slotsToUpdate.Count - currentIndex >= 32) - owner.QueuePacket(EquipmentListX32Packet.BuildPacket(owner.actorId, list, slotsToUpdate, ref currentIndex)); - else if (slotsToUpdate.Count - currentIndex >= 16) - owner.QueuePacket(EquipmentListX16Packet.BuildPacket(owner.actorId, list, slotsToUpdate, ref currentIndex)); - else if (slotsToUpdate.Count - currentIndex > 1) - owner.QueuePacket(EquipmentListX08Packet.BuildPacket(owner.actorId, list, slotsToUpdate, ref currentIndex)); - else if (slotsToUpdate.Count - currentIndex == 1) - { - owner.QueuePacket(EquipmentListX01Packet.BuildPacket(owner.actorId, slotsToUpdate[currentIndex], list[slotsToUpdate[currentIndex]].slot)); - currentIndex++; - } - else - break; - } - + return null; } public int GetCapacity() @@ -232,5 +147,66 @@ namespace FFXIVClassic_Map_Server.actors.chara.player return list.Length; } + #region Packet Functions + private void SendSingleEquipmentUpdatePacket(ushort equipSlot, InventoryItem item) + { + owner.QueuePacket(InventorySetBeginPacket.BuildPacket(owner.actorId, inventoryCapacity, inventoryCode)); + if (item == null) + owner.QueuePacket(InventoryRemoveX01Packet.BuildPacket(owner.actorId, equipSlot)); + else + owner.QueuePacket(EquipmentListX01Packet.BuildPacket(owner.actorId, equipSlot, item.slot)); + owner.QueuePacket(InventorySetEndPacket.BuildPacket(owner.actorId)); + } + + private void SendEquipmentPackets(List slotsToUpdate, Player targetPlayer) + { + int currentIndex = 0; + + while (true) + { + if (slotsToUpdate.Count - currentIndex >= 64) + targetPlayer.QueuePacket(EquipmentListX64Packet.BuildPacket(owner.actorId, list, slotsToUpdate, ref currentIndex)); + else if (slotsToUpdate.Count - currentIndex >= 32) + targetPlayer.QueuePacket(EquipmentListX32Packet.BuildPacket(owner.actorId, list, slotsToUpdate, ref currentIndex)); + else if (slotsToUpdate.Count - currentIndex >= 16) + targetPlayer.QueuePacket(EquipmentListX16Packet.BuildPacket(owner.actorId, list, slotsToUpdate, ref currentIndex)); + else if (slotsToUpdate.Count - currentIndex > 1) + targetPlayer.QueuePacket(EquipmentListX08Packet.BuildPacket(owner.actorId, list, slotsToUpdate, ref currentIndex)); + else if (slotsToUpdate.Count - currentIndex == 1) + { + targetPlayer.QueuePacket(EquipmentListX01Packet.BuildPacket(owner.actorId, slotsToUpdate[currentIndex], list[slotsToUpdate[currentIndex]].slot)); + currentIndex++; + } + else + break; + } + } + + public void SendFullEquipment() + { + SendFullEquipment(owner); + } + + public void SendFullEquipment(Player targetPlayer) + { + List slotsToUpdate = new List(); + + for (ushort i = 0; i < list.Length; i++) + { + if (list[i] != null) + slotsToUpdate.Add(i); + } + + if (targetPlayer.Equals(owner)) + targetPlayer.QueuePacket(InventorySetBeginPacket.BuildPacket(owner.actorId, inventoryCapacity, inventoryCode)); + else + targetPlayer.QueuePacket(InventorySetBeginPacket.BuildPacket(owner.actorId, 0x23, ItemPackage.EQUIPMENT_OTHERPLAYER)); + + SendEquipmentPackets(slotsToUpdate, targetPlayer); + + targetPlayer.QueuePacket(InventorySetEndPacket.BuildPacket(owner.actorId)); + } + + #endregion } } diff --git a/FFXIVClassic Map Server/actors/chara/player/Inventory.cs b/FFXIVClassic Map Server/actors/chara/player/Inventory.cs index e442050c..9573bb0f 100644 --- a/FFXIVClassic Map Server/actors/chara/player/Inventory.cs +++ b/FFXIVClassic Map Server/actors/chara/player/Inventory.cs @@ -121,7 +121,32 @@ namespace FFXIVClassic_Map_Server.actors.chara.player { return AddItem(itemId, quantity, 1); } - + + public bool AddItems(uint[] itemIds) + { + bool canAdd = GetFreeSlots() - itemIds.Length >= 0; + if (canAdd) + { + foreach (uint id in itemIds) + { + ItemData gItem = Server.GetItemGamedata(id); + InventoryItem.ItemModifier modifiers = null; + if (gItem.durability != 0) + { + modifiers = new InventoryItem.ItemModifier(); + modifiers.durability = (uint)gItem.durability; + } + + InventoryItem addedItem = Database.CreateItem(id, Math.Min(1, gItem.maxStack), 0, modifiers); + addedItem.RefreshPositioning(owner, itemPackageCode, (ushort)endOfListIndex); + isDirty[endOfListIndex] = true; + list[endOfListIndex++] = addedItem; + DoDatabaseAdd(addedItem); + } + } + return canAdd; + } + public INV_ERROR AddItem(InventoryItem itemRef) { //If it isn't a single item (ie: armor) just add like normal (not valid for BAZAAR) @@ -600,7 +625,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.player //If player is updating their normal inventory, we need to send //an equip update as well to resync the slots. if (player.Equals(owner) && itemPackageCode == NORMAL) - player.GetEquipment().SendFullEquipment(true); + player.GetEquipment().SendFullEquipment(); player.QueuePacket(InventoryEndChangePacket.BuildPacket(owner.actorId)); } @@ -624,7 +649,12 @@ namespace FFXIVClassic_Map_Server.actors.chara.player { return endOfListIndex >= itemPackageCapacity; } - + + public int GetFreeSlots() + { + return itemPackageCapacity - endOfListIndex; + } + public bool IsSpaceForAdd(uint itemId, int quantity, int quality) { int quantityCount = quantity; diff --git a/FFXIVClassic Map Server/actors/chara/player/Player.cs b/FFXIVClassic Map Server/actors/chara/player/Player.cs index a9e3a381..0d7f9606 100644 --- a/FFXIVClassic Map Server/actors/chara/player/Player.cs +++ b/FFXIVClassic Map Server/actors/chara/player/Player.cs @@ -537,7 +537,7 @@ namespace FFXIVClassic_Map_Server.Actors itemPackages[ItemPackage.BAZAAR].SendFullInventory(this); itemPackages[ItemPackage.MELDREQUEST].SendFullInventory(this); itemPackages[ItemPackage.LOOT].SendFullInventory(this); - equipment.SendFullEquipment(false); + equipment.SendFullEquipment(); playerSession.QueuePacket(InventoryEndChangePacket.BuildPacket(actorId)); #endregion @@ -1675,7 +1675,7 @@ namespace FFXIVClassic_Map_Server.Actors return; QueuePacket(InventoryBeginChangePacket.BuildPacket(toBeExamined.actorId)); - toBeExamined.GetEquipment().SendCheckEquipmentToPlayer(this); + toBeExamined.GetEquipment().SendFullEquipment(this); QueuePacket(InventoryEndChangePacket.BuildPacket(toBeExamined.actorId)); } diff --git a/data/scripts/base/chara/npc/populace/PopulaceRetainerManager.lua b/data/scripts/base/chara/npc/populace/PopulaceRetainerManager.lua index 50c0b727..5506a6ae 100644 --- a/data/scripts/base/chara/npc/populace/PopulaceRetainerManager.lua +++ b/data/scripts/base/chara/npc/populace/PopulaceRetainerManager.lua @@ -13,65 +13,133 @@ eventTalkStepFinalAnswer(actorClassId) - Confirm Dialog eventTalkStepError(errorCode) - Error dialog, 1: No Extra Retainers, 2: Server Busy. eventTalkStepFinish() + --]] require ("global") + function init(npc) - return false, false, 0, 0; + return false, false, 0, 0; end function onEventStarted(player, npc, triggerName) - - introChoice = callClientFunction(player, "newEventTalkStep1", false); - - if (introChoice == 1) then - - raceChoice = callClientFunction(player, "eventTalkStep2"); - - while (true) do - - if (retainerChoice == 0) then - raceChoice = callClientFunction(player, "eventTalkStep22"); - end - - if (raceChoice == 0) then - --Choose random actorId - elseif (raceChoice > 0) then - --Choose 5 random but correct actor ids - retainerChoice = callClientFunction(player, "eventTaklSelectCutSeane", "rtn0g010", 0x2DCB1A, 0x2DCB1A, 0x2DCB1A, 0x2DCB1A, 0x2DCB1A); - - if (retainerChoice == -1) then - player:EndEvent(); - return; - elseif (retainerChoice > 0) then - --Retainer chosen, choose name - retainerName = callClientFunction(player, "eventTalkStep4", 0x2DCB1A); - - if (retainerName ~= "") then - confirmChoice = callClientFunction(player, "eventTalkStepFinalAnswer", 0x2DCB1A); - - if (confirmChoice == 1) then - callClientFunction(player, "eventTalkStepFinish"); - player:EndEvent(); - return; - elseif (confirmChoice == 3) then - raceChoice = 0; - else - player:EndEvent(); - return; - end - - end - - end - else - break; - end - - end - - end - - player:EndEvent(); + + local npcActorClass = npc:GetActorClassId() + local retainerIndex = 3001100; + local cutscene = "rtn0l010" -- Defaulting to Limsa for now for testing + + if npcActorClass == 1000166 then + cutscene = "rtn0l010"; + retainerIndex = 3001101; + elseif npcActorClass == 1000865 then + cutscene = "rtn0u010"; + retainerIndex = 3002101; + elseif npcActorClass == 1001184 then + cutscene = "rtn0g010"; + retainerIndex = 3003101; + else + return; + end + + + introChoice = callClientFunction(player, "newEventTalkStep1", false); + + if (introChoice == 1) then + + -- Choose Retainer or Random + raceChoice = callClientFunction(player, "eventTalkStep2"); + + while (true) do + + + if (retainerChoice == 0) then + raceChoice = callClientFunction(player, "eventTalkStep22"); + end + + + if (raceChoice == 0) then + --Choose random actorId from a valid set for the city + + math.randomseed(os.time()); + local randomRetainer = math.random(retainerIndex, (retainerIndex+74)); + + retainerName = callClientFunction(player, "eventTalkStep4", randomRetainer); + + if (retainerName ~= "") then + confirmChoice = callClientFunction(player, "eventTalkStepFinalAnswer", randomRetainer); + + if (confirmChoice == 1) then + callClientFunction(player, "eventTalkStepFinish"); + player:EndEvent(); + return; + elseif (confirmChoice == 3) then + raceChoice = 0; + else + player:EndEvent(); + return; + end + else + callClientFunction(player, "eventTalkStepBreak"); + raceChoice = -1; + end + + + elseif (raceChoice > 0) and (raceChoice < 16) then + --Choose 5 random but correct actor ids for the city and race/tribe + + local retainerRace = ((retainerIndex) + (5*(raceChoice-1))); + local retainerRaceChoices = {retainerRace, retainerRace+1, retainerRace+2, retainerRace+3, retainerRace+4}; + + -- Randomize the appearance order of the available five + shuffle(retainerRaceChoices); + + retainerChoice = callClientFunction(player, "eventTaklSelectCutSeane", cutscene, retainerRaceChoices[1], retainerRaceChoices[2], retainerRaceChoices[3], retainerRaceChoices[4], retainerRaceChoices[5]); + + if (retainerChoice == -1) then + player:EndEvent(); + return; + elseif (retainerChoice > 0) then + --Retainer chosen, choose name + retainerName = callClientFunction(player, "eventTalkStep4", retainerRaceChoices[retainerChoice]); + + if (retainerName ~= "") then + confirmChoice = callClientFunction(player, "eventTalkStepFinalAnswer", retainerRaceChoices[retainerChoice]); + + if (confirmChoice == 1) then + callClientFunction(player, "eventTalkStepFinish"); + player:EndEvent(); + return; + elseif (confirmChoice == 3) then + retainerChoice = 0; + else + player:EndEvent(); + return; + end + else + callClientFunction(player, "eventTalkStepBreak"); + raceChoice = -1; + end + + end + else + break; + end + + + end + + end + + player:EndEvent(); +end + + + +function shuffle(tbl) + for i = #tbl, 2, -1 do + local j = math.random(i) + tbl[i], tbl[j] = tbl[j], tbl[i] + end + return tbl end \ No newline at end of file