Fix Excruciate removign status from enemy rather than caster
This commit is contained in:
Yogurt
2019-06-05 19:28:02 -07:00
272 changed files with 8223 additions and 2425 deletions

View File

@@ -1,236 +0,0 @@
using FFXIVClassic_Map_Server.Actors;
using FFXIVClassic_Map_Server.dataobjects;
using FFXIVClassic_Map_Server.packets.send.actor.inventory;
using System.Collections.Generic;
namespace FFXIVClassic_Map_Server.actors.chara.player
{
class Equipment
{
public const int SLOT_MAINHAND = 0;
public const int SLOT_OFFHAND = 1;
public const int SLOT_THROWINGWEAPON = 4;
public const int SLOT_PACK = 5;
public const int SLOT_POUCH = 6;
public const int SLOT_HEAD = 8;
public const int SLOT_UNDERSHIRT = 9;
public const int SLOT_BODY = 10;
public const int SLOT_UNDERGARMENT = 11;
public const int SLOT_LEGS = 12;
public const int SLOT_HANDS = 13;
public const int SLOT_BOOTS = 14;
public const int SLOT_WAIST = 15;
public const int SLOT_NECK = 16;
public const int SLOT_EARS = 17;
public const int SLOT_WRISTS = 19;
public const int SLOT_RIGHTFINGER = 21;
public const int SLOT_LEFTFINGER = 22;
private Player owner;
private ushort inventoryCapacity;
private ushort inventoryCode;
private InventoryItem[] list;
private Inventory normalInventory;
private bool writeToDB = true;
public Equipment(Player ownerPlayer, Inventory normalInventory, ushort capacity, ushort code)
{
owner = ownerPlayer;
inventoryCapacity = capacity;
inventoryCode = code;
list = new InventoryItem[inventoryCapacity];
this.normalInventory = normalInventory;
}
public InventoryItem GetItemAtSlot(ushort slot)
{
if (slot < list.Length)
return list[slot];
else
return null;
}
public void SendCheckEquipmentToPlayer(Player toPlayer)
{
List<InventoryItem> items = new List<InventoryItem>();
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, Inventory.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<ushort> slotsToUpdate = new List<ushort>();
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)
return;
for (int i = 0; i < slots.Length; i++)
{
InventoryItem item = normalInventory.GetItemAtSlot(itemSlots[i]);
if (item == null)
continue;
Database.EquipItem(owner, slots[i], item.uniqueId);
list[slots[i]] = normalInventory.GetItemAtSlot(itemSlots[i]);
}
owner.QueuePacket(InventoryBeginChangePacket.BuildPacket(owner.actorId));
SendFullEquipment(false);
owner.QueuePacket(InventoryEndChangePacket.BuildPacket(owner.actorId));
}
public void SetEquipment(InventoryItem[] toEquip)
{
List<ushort> slotsToUpdate = new List<ushort>();
for (ushort i = 0; i < toEquip.Length; i++)
{
if (toEquip[i] != null)
slotsToUpdate.Add(i);
}
list = toEquip;
}
public void Equip(ushort slot, ushort invSlot)
{
InventoryItem item = normalInventory.GetItemAtSlot(invSlot);
if (item == null)
return;
Equip(slot, item);
}
public void Equip(ushort slot, InventoryItem item)
{
if (slot >= list.Length)
return;
if (writeToDB)
Database.EquipItem(owner, slot, item.uniqueId);
owner.QueuePacket(InventoryBeginChangePacket.BuildPacket(owner.actorId));
if (list[slot] != null)
normalInventory.RefreshItem(owner, list[slot], item);
else
normalInventory.RefreshItem(owner, item);
owner.QueuePacket(InventorySetBeginPacket.BuildPacket(owner.actorId, inventoryCapacity, inventoryCode));
SendEquipmentPackets(slot, item);
owner.QueuePacket(InventorySetEndPacket.BuildPacket(owner.actorId));
owner.QueuePacket(InventoryEndChangePacket.BuildPacket(owner.actorId));
list[slot] = item;
owner.CalculateBaseStats();// RecalculateStats();
}
public void ToggleDBWrite(bool flag)
{
writeToDB = flag;
}
public void Unequip(ushort slot)
{
if (slot >= list.Length)
return;
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(InventoryEndChangePacket.BuildPacket(owner.actorId));
list[slot] = null;
owner.RecalculateStats();
}
private void SendEquipmentPackets(ushort equipSlot, InventoryItem item)
{
if (item == null)
owner.QueuePacket(InventoryRemoveX01Packet.BuildPacket(owner.actorId, equipSlot));
else
owner.QueuePacket(EquipmentListX01Packet.BuildPacket(owner.actorId, equipSlot, item.slot));
}
private void SendEquipmentPackets(List<ushort> 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;
}
}
public int GetCapacity()
{
return list.Length;
}
}
}

View File

@@ -1,625 +0,0 @@
using FFXIVClassic.Common;
using FFXIVClassic_Map_Server.actors.chara.npc;
using FFXIVClassic_Map_Server.Actors;
using FFXIVClassic_Map_Server.dataobjects;
using FFXIVClassic_Map_Server.packets.send.actor.inventory;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace FFXIVClassic_Map_Server.actors.chara.player
{
class Inventory
{
public const ushort NORMAL = 0; //Max 0xC8
public const ushort TRADE = 1; //Max 0x96
public const ushort LOOT = 4; //Max 0xA
public const ushort MELDREQUEST = 5; //Max 0x04
public const ushort BAZAAR = 7; //Max 0x0A
public const ushort CURRENCY_CRYSTALS = 99; //Max 0x140
public const ushort KEYITEMS = 100; //Max 0x500
public const ushort EQUIPMENT = 0x00FE; //Max 0x23
public const ushort EQUIPMENT_OTHERPLAYER = 0x00F9; //Max 0x23
public enum INV_ERROR {
SUCCESS = 0,
INVENTORY_FULL,
ALREADY_HAS_UNIQUE,
SYSTEM_ERROR
};
private Character owner;
private ushort inventoryCapacity;
private ushort inventoryCode;
private bool isTemporary;
private InventoryItem[] list;
private bool[] isDirty;
private int endOfListIndex = 0;
public Inventory(Character ownerPlayer, ushort capacity, ushort code, bool temporary = false)
{
owner = ownerPlayer;
inventoryCapacity = capacity;
inventoryCode = code;
isTemporary = temporary;
list = new InventoryItem[capacity];
isDirty = new bool[capacity];
}
#region Inventory Management
public void InitList(List<InventoryItem> itemsFromDB)
{
int i = 0;
foreach (InventoryItem item in itemsFromDB)
list[i++] = item;
endOfListIndex = i;
}
public InventoryItem GetItemAtSlot(ushort slot)
{
if (slot < list.Length)
return list[slot];
else
return null;
}
public InventoryItem GetItemByUniqueId(ulong uniqueItemId)
{
for (int i = 0; i < endOfListIndex; i++)
{
InventoryItem item = list[i];
Debug.Assert(item != null, "Item slot was null!!!");
if (item.uniqueId == uniqueItemId)
return item;
}
return null;
}
public InventoryItem GetItemByCatelogId(ulong catelogId)
{
for (int i = 0; i < endOfListIndex; i++)
{
InventoryItem item = list[i];
Debug.Assert(item != null, "Item slot was null!!!");
if (item.itemId == catelogId)
return item;
}
return null;
}
public int GetItemQuantity(uint itemId)
{
return GetItemQuantity(itemId, 1);
}
public int GetItemQuantity(uint itemId, uint quality)
{
int count = 0;
for (int i = endOfListIndex - 1; i >= 0; i--)
{
InventoryItem item = list[i];
if (item.itemId == itemId && item.quality == quality)
count += item.quantity;
}
return count;
}
public int AddItem(uint itemId)
{
return AddItem(itemId, 1, 1);
}
public void AddItem(uint[] itemId)
{
for (int i = 0; i < itemId.Length; i++)
AddItem(itemId[i]);
}
public int AddItem(uint itemId, int quantity)
{
return AddItem(itemId, quantity, 1);
}
public int AddItem(uint itemId, int quantity, byte quality)
{
if (!IsSpaceForAdd(itemId, quantity, quality))
return (int)INV_ERROR.INVENTORY_FULL;
ItemData gItem = Server.GetItemGamedata(itemId);
if (gItem == null)
{
Program.Log.Error("Inventory.AddItem: unable to find item %u", itemId);
return (int)INV_ERROR.SYSTEM_ERROR;
}
//Check if item id exists
int quantityCount = quantity;
for (int i = 0; i < endOfListIndex; i++)
{
InventoryItem item = list[i];
Debug.Assert(item != null, "Item slot was null!!!");
if (item.itemId == itemId && item.quality == quality && item.quantity < gItem.maxStack)
{
int oldQuantity = item.quantity;
item.quantity = Math.Min(item.quantity + quantityCount, gItem.maxStack);
isDirty[i] = true;
quantityCount -= (gItem.maxStack - oldQuantity);
DoDatabaseQuantity(item.uniqueId, item.quantity);
if (quantityCount <= 0)
break;
}
}
//If it's unique, abort
if (HasItem(itemId) && gItem.isRare)
return (int)INV_ERROR.ALREADY_HAS_UNIQUE;
//New item that spilled over
while (quantityCount > 0)
{
InventoryItem addedItem = Database.CreateItem(itemId, Math.Min(quantityCount, gItem.maxStack), quality, gItem.isExclusive ? (byte)0x3 : (byte)0x0, gItem.durability);
addedItem.slot = (ushort)endOfListIndex;
isDirty[endOfListIndex] = true;
list[endOfListIndex++] = addedItem;
quantityCount -= gItem.maxStack;
DoDatabaseAdd(addedItem);
}
SendUpdatePackets();
return (int)INV_ERROR.SUCCESS;
}
public void RemoveItem(uint itemId)
{
RemoveItem(itemId, 1);
}
public void RemoveItem(uint itemId, int quantity)
{
RemoveItem(itemId, quantity, 1);
}
public void RemoveItem(uint itemId, int quantity, int quality)
{
if (!HasItem(itemId, quantity, quality))
return;
List<ushort> slotsToUpdate = new List<ushort>();
List<InventoryItem> itemsToRemove = new List<InventoryItem>();
List<ushort> slotsToRemove = new List<ushort>();
List<SubPacket> AddItemPackets = new List<SubPacket>();
//Remove as we go along
int quantityCount = quantity;
ushort lowestSlot = 0;
for (int i = endOfListIndex - 1; i >= 0; i--)
{
InventoryItem item = list[i];
Debug.Assert(item != null, "Item slot was null!!!");
if (item.itemId == itemId && item.quality == quality)
{
int oldQuantity = item.quantity;
//Stack nomnomed
if (item.quantity - quantityCount <= 0)
{
DoDatabaseRemove(list[i].uniqueId);
list[i] = null;
}
//Stack reduced
else
{
item.quantity -= quantityCount;
DoDatabaseQuantity(list[i].uniqueId, list[i].quantity);
}
isDirty[i] = true;
quantityCount -= oldQuantity;
lowestSlot = item.slot;
if (quantityCount <= 0)
break;
}
}
DoRealign();
SendUpdatePackets();
}
public void RemoveItemByUniqueId(ulong itemDBId)
{
ushort slot = 0;
InventoryItem toDelete = null;
for (int i = endOfListIndex - 1; i >= 0; i--)
{
InventoryItem item = list[i];
Debug.Assert(item != null, "Item slot was null!!!");
if (item.uniqueId == itemDBId)
{
toDelete = item;
break;
}
slot++;
}
if (toDelete == null)
return;
DoDatabaseRemove(toDelete.uniqueId);
list[slot] = null;
isDirty[slot] = true;
DoRealign();
SendUpdatePackets();
}
public void RemoveItemAtSlot(ushort slot)
{
if (slot >= endOfListIndex)
return;
DoDatabaseRemove(list[slot].uniqueId);
list[slot] = null;
isDirty[slot] = true;
DoRealign();
SendUpdatePackets();
}
public void RemoveItemAtSlot(ushort slot, int quantity)
{
if (slot >= endOfListIndex)
return;
if (list[slot] != null)
{
list[slot].quantity -= quantity;
if (list[slot].quantity <= 0)
{
DoDatabaseRemove(list[slot].uniqueId);
list[slot] = null;
DoRealign();
}
else
DoDatabaseQuantity(list[slot].uniqueId, list[slot].quantity);
isDirty[slot] = true;
SendUpdatePackets();
}
}
public void ChangeDurability(uint slot, uint durabilityChange)
{
isDirty[slot] = true;
}
public void ChangeSpiritBind(uint slot, uint spiritBindChange)
{
isDirty[slot] = true;
}
public void ChangeMateria(uint slot, byte materiaSlot, byte materiaId)
{
isDirty[slot] = true;
}
#endregion
#region Packet Functions
public void SendFullInventory(Player player)
{
player.QueuePacket(InventorySetBeginPacket.BuildPacket(owner.actorId, inventoryCapacity, inventoryCode));
SendInventoryPackets(player, 0);
player.QueuePacket(InventorySetEndPacket.BuildPacket(owner.actorId));
}
private void SendInventoryPackets(Player player, InventoryItem item)
{
player.QueuePacket(InventoryListX01Packet.BuildPacket(owner.actorId, item));
}
private void SendInventoryPackets(Player player, List<InventoryItem> items)
{
int currentIndex = 0;
while (true)
{
if (items.Count - currentIndex >= 64)
player.QueuePacket(InventoryListX64Packet.BuildPacket(owner.actorId, items, ref currentIndex));
else if (items.Count - currentIndex >= 32)
player.QueuePacket(InventoryListX32Packet.BuildPacket(owner.actorId, items, ref currentIndex));
else if (items.Count - currentIndex >= 16)
player.QueuePacket(InventoryListX16Packet.BuildPacket(owner.actorId, items, ref currentIndex));
else if (items.Count - currentIndex > 1)
player.QueuePacket(InventoryListX08Packet.BuildPacket(owner.actorId, items, ref currentIndex));
else if (items.Count - currentIndex == 1)
{
player.QueuePacket(InventoryListX01Packet.BuildPacket(owner.actorId, items[currentIndex]));
currentIndex++;
}
else
break;
}
}
private void SendInventoryPackets(Player player, int startOffset)
{
int currentIndex = startOffset;
List<InventoryItem> lst = new List<InventoryItem>();
for (int i = 0; i < endOfListIndex; i++)
lst.Add(list[i]);
while (true)
{
if (endOfListIndex - currentIndex >= 64)
player.QueuePacket(InventoryListX64Packet.BuildPacket(owner.actorId, lst, ref currentIndex));
else if (endOfListIndex - currentIndex >= 32)
player.QueuePacket(InventoryListX32Packet.BuildPacket(owner.actorId, lst, ref currentIndex));
else if (endOfListIndex - currentIndex >= 16)
player.QueuePacket(InventoryListX16Packet.BuildPacket(owner.actorId, lst, ref currentIndex));
else if (endOfListIndex - currentIndex > 1)
player.QueuePacket(InventoryListX08Packet.BuildPacket(owner.actorId, lst, ref currentIndex));
else if (endOfListIndex - currentIndex == 1)
{
player.QueuePacket(InventoryListX01Packet.BuildPacket(owner.actorId, list[currentIndex]));
currentIndex++;
}
else
break;
}
}
private void SendInventoryRemovePackets(Player player, ushort index)
{
player.QueuePacket(InventoryRemoveX01Packet.BuildPacket(owner.actorId, index));
}
private void SendInventoryRemovePackets(Player player, List<ushort> indexes)
{
int currentIndex = 0;
while (true)
{
if (indexes.Count - currentIndex >= 64)
player.QueuePacket(InventoryRemoveX64Packet.BuildPacket(owner.actorId, indexes, ref currentIndex));
else if (indexes.Count - currentIndex >= 32)
player.QueuePacket(InventoryRemoveX32Packet.BuildPacket(owner.actorId, indexes, ref currentIndex));
else if (indexes.Count - currentIndex >= 16)
player.QueuePacket(InventoryRemoveX16Packet.BuildPacket(owner.actorId, indexes, ref currentIndex));
else if (indexes.Count - currentIndex > 1)
player.QueuePacket(InventoryRemoveX08Packet.BuildPacket(owner.actorId, indexes, ref currentIndex));
else if (indexes.Count - currentIndex == 1)
{
player.QueuePacket(InventoryRemoveX01Packet.BuildPacket(owner.actorId, indexes[currentIndex]));
currentIndex++;
}
else
break;
}
}
public void RefreshItem(Player player, InventoryItem item)
{
player.QueuePacket(InventorySetBeginPacket.BuildPacket(owner.actorId, inventoryCapacity, inventoryCode));
SendInventoryPackets(player, item);
player.QueuePacket(InventorySetEndPacket.BuildPacket(owner.actorId));
}
public void RefreshItem(Player player, params InventoryItem[] items)
{
player.QueuePacket(InventorySetBeginPacket.BuildPacket(owner.actorId, inventoryCapacity, inventoryCode));
SendInventoryPackets(player, items.ToList());
player.QueuePacket(InventorySetEndPacket.BuildPacket(owner.actorId));
}
public void RefreshItem(Player player, List<InventoryItem> items)
{
player.QueuePacket(InventorySetBeginPacket.BuildPacket(owner.actorId, inventoryCapacity, inventoryCode));
SendInventoryPackets(player, items);
player.QueuePacket(InventorySetEndPacket.BuildPacket(owner.actorId));
}
#endregion
#region Automatic Client and DB Updating
private void DoDatabaseAdd(InventoryItem addedItem)
{
if (isTemporary)
return;
if (owner is Player)
Database.AddItem((Player)owner, addedItem, inventoryCode);
else if (owner is Retainer)
Database.AddItem((Retainer)owner, addedItem, inventoryCode);
}
private void DoDatabaseQuantity(ulong itemDBId, int quantity)
{
if (isTemporary)
return;
if (owner is Player)
Database.SetQuantity((Player)owner, itemDBId, inventoryCode);
else if (owner is Retainer)
Database.SetQuantity((Retainer)owner, itemDBId, inventoryCode);
}
private void DoDatabaseRemove(ulong itemDBId)
{
if (isTemporary)
return;
if (owner is Player)
Database.RemoveItem((Player)owner, itemDBId);
else if (owner is Retainer)
Database.RemoveItem((Retainer)owner, itemDBId);
}
private void SendUpdatePackets()
{
if (owner is Player)
{
SendUpdatePackets((Player)owner, true);
}
}
public void SendUpdatePackets(Player player, bool doneImmediate = false)
{
List<InventoryItem> items = new List<InventoryItem>();
List<ushort> slotsToRemove = new List<ushort>();
for (int i = 0; i < list.Length; i++)
{
if (i == endOfListIndex)
break;
if (isDirty[i])
items.Add(list[i]);
}
for (int i = endOfListIndex; i < list.Length; i++)
{
if (isDirty[i])
slotsToRemove.Add((ushort)i);
}
if (doneImmediate)
DoneSendUpdate();
player.QueuePacket(InventoryBeginChangePacket.BuildPacket(owner.actorId));
player.QueuePacket(InventorySetBeginPacket.BuildPacket(owner.actorId, inventoryCapacity, inventoryCode));
//Send Updated Slots
SendInventoryPackets(player, items);
//Send Remove packets for tail end
SendInventoryRemovePackets(player, slotsToRemove);
player.QueuePacket(InventorySetEndPacket.BuildPacket(owner.actorId));
player.QueuePacket(InventoryEndChangePacket.BuildPacket(owner.actorId));
}
public void DoneSendUpdate()
{
Array.Clear(isDirty, 0, isDirty.Length);
}
#endregion
#region Inventory Utils
public bool IsFull()
{
return endOfListIndex >= inventoryCapacity;
}
public bool IsSpaceForAdd(uint itemId, int quantity, int quality)
{
int quantityCount = quantity;
for (int i = 0; i < endOfListIndex; i++)
{
InventoryItem item = list[i];
ItemData gItem = Server.GetItemGamedata(item.itemId);
if (item.itemId == itemId && item.quality == quality && item.quantity < gItem.maxStack)
{
quantityCount -= (gItem.maxStack - item.quantity);
if (quantityCount <= 0)
break;
}
}
return quantityCount <= 0 || (quantityCount > 0 && !IsFull());
}
public bool HasItem(uint itemId)
{
return HasItem(itemId, 1);
}
public bool HasItem(uint itemId, int minQuantity)
{
return HasItem(itemId, minQuantity, 1);
}
public bool HasItem(uint itemId, int minQuantity, int quality)
{
int count = 0;
for (int i = endOfListIndex - 1; i >= 0; i--)
{
InventoryItem item = list[i];
Debug.Assert(item != null, "Item slot was null!!!");
if (item.itemId == itemId && item.quality == quality)
count += item.quantity;
if (count >= minQuantity)
return true;
}
return false;
}
public int GetNextEmptySlot()
{
return endOfListIndex;
}
private void DoRealign()
{
int lastNullSlot = -1;
for (int i = 0; i < endOfListIndex; i++)
{
if (list[i] == null && lastNullSlot == -1)
{
lastNullSlot = i;
continue;
}
else if (list[i] != null && lastNullSlot != -1)
{
list[lastNullSlot] = list[i];
list[lastNullSlot].slot = (ushort)lastNullSlot;
list[i] = null;
isDirty[lastNullSlot] = true;
isDirty[i] = true;
lastNullSlot++;
}
}
if (lastNullSlot != -1)
endOfListIndex = lastNullSlot;
}
#endregion
}
}

View File

@@ -23,19 +23,12 @@ using FFXIVClassic_Map_Server.packets.send.actor.inventory;
using FFXIVClassic_Map_Server.packets.send.player;
using FFXIVClassic_Map_Server.packets.send.actor.battle;
using FFXIVClassic_Map_Server.packets.receive.events;
using static FFXIVClassic_Map_Server.LuaUtils;
namespace FFXIVClassic_Map_Server.Actors
{
class Player : Character
{
public const int MAXSIZE_INVENTORY_NORMAL = 200;
public const int MAXSIZE_INVENTORY_CURRANCY = 320;
public const int MAXSIZE_INVENTORY_KEYITEMS = 500;
public const int MAXSIZE_INVENTORY_LOOT = 10;
public const int MAXSIZE_INVENTORY_MELDREQUEST = 4;
public const int MAXSIZE_INVENTORY_BAZAAR = 10;
public const int MAXSIZE_INVENTORY_EQUIPMENT = 35;
public const int TIMER_TOTORAK = 0;
public const int TIMER_DZEMAEL = 1;
public const int TIMER_BOWL_OF_EMBERS_HARD = 2;
@@ -62,6 +55,25 @@ namespace FFXIVClassic_Map_Server.Actors
public const int NPCLS_ACTIVE = 2;
public const int NPCLS_ALERT = 3;
public const int SLOT_MAINHAND = 0;
public const int SLOT_OFFHAND = 1;
public const int SLOT_THROWINGWEAPON = 4;
public const int SLOT_PACK = 5;
public const int SLOT_POUCH = 6;
public const int SLOT_HEAD = 8;
public const int SLOT_UNDERSHIRT = 9;
public const int SLOT_BODY = 10;
public const int SLOT_UNDERGARMENT = 11;
public const int SLOT_LEGS = 12;
public const int SLOT_HANDS = 13;
public const int SLOT_BOOTS = 14;
public const int SLOT_WAIST = 15;
public const int SLOT_NECK = 16;
public const int SLOT_EARS = 17;
public const int SLOT_WRISTS = 19;
public const int SLOT_RIGHTFINGER = 21;
public const int SLOT_LEFTFINGER = 22;
public static int[] MAXEXP = {570, 700, 880, 1100, 1500, 1800, 2300, 3200, 4300, 5000, //Level <= 10
5900, 6800, 7700, 8700, 9700, 11000, 12000, 13000, 15000, 16000, //Level <= 20
20000, 22000, 23000, 25000, 27000, 29000, 31000, 33000, 35000, 38000, //Level <= 30
@@ -71,7 +83,6 @@ namespace FFXIVClassic_Map_Server.Actors
//Event Related
public uint currentEventOwner = 0;
public string currentEventName = "";
public Coroutine currentEventRunning;
//Player Info
@@ -84,9 +95,10 @@ namespace FFXIVClassic_Map_Server.Actors
public bool isGM = false;
public bool isZoneChanging = true;
//Inventory
private Dictionary<ushort, Inventory> inventories = new Dictionary<ushort, Inventory>();
private Equipment equipment;
//Trading
private Player otherTrader = null;
private ReferencedItemPackage myOfferings;
private bool isTradeAccepted = false;
//GC Related
public byte gcCurrent;
@@ -115,6 +127,10 @@ namespace FFXIVClassic_Map_Server.Actors
public uint homepoint = 0;
public byte homepointInn = 0;
//Nameplate Stuff
public uint currentLSPlate = 0;
public byte repairType = 0;
//Retainer
RetainerMeetingRelationGroup retainerMeetingGroup = null;
public Retainer currentSpawnedRetainer = null;
@@ -140,14 +156,13 @@ namespace FFXIVClassic_Map_Server.Actors
moveSpeeds[2] = SetActorSpeedPacket.DEFAULT_RUN;
moveSpeeds[3] = SetActorSpeedPacket.DEFAULT_ACTIVE;
inventories[Inventory.NORMAL] = new Inventory(this, MAXSIZE_INVENTORY_NORMAL, Inventory.NORMAL);
inventories[Inventory.KEYITEMS] = new Inventory(this, MAXSIZE_INVENTORY_KEYITEMS, Inventory.KEYITEMS);
inventories[Inventory.CURRENCY_CRYSTALS] = new Inventory(this, MAXSIZE_INVENTORY_CURRANCY, Inventory.CURRENCY_CRYSTALS);
inventories[Inventory.MELDREQUEST] = new Inventory(this, MAXSIZE_INVENTORY_MELDREQUEST, Inventory.MELDREQUEST);
inventories[Inventory.BAZAAR] = new Inventory(this, MAXSIZE_INVENTORY_BAZAAR, Inventory.BAZAAR);
inventories[Inventory.LOOT] = new Inventory(this, MAXSIZE_INVENTORY_LOOT, Inventory.LOOT);
equipment = new Equipment(this, inventories[Inventory.NORMAL], MAXSIZE_INVENTORY_EQUIPMENT, Inventory.EQUIPMENT);
itemPackages[ItemPackage.NORMAL] = new ItemPackage(this, ItemPackage.MAXSIZE_NORMAL, ItemPackage.NORMAL);
itemPackages[ItemPackage.KEYITEMS] = new ItemPackage(this, ItemPackage.MAXSIZE_KEYITEMS, ItemPackage.KEYITEMS);
itemPackages[ItemPackage.CURRENCY_CRYSTALS] = new ItemPackage(this, ItemPackage.MAXSIZE_CURRANCY, ItemPackage.CURRENCY_CRYSTALS);
itemPackages[ItemPackage.MELDREQUEST] = new ItemPackage(this, ItemPackage.MAXSIZE_MELDREQUEST, ItemPackage.MELDREQUEST);
itemPackages[ItemPackage.BAZAAR] = new ItemPackage(this, ItemPackage.MAXSIZE_BAZAAR, ItemPackage.BAZAAR);
itemPackages[ItemPackage.LOOT] = new ItemPackage(this, ItemPackage.MAXSIZE_LOOT, ItemPackage.LOOT);
equipment = new ReferencedItemPackage(this, ItemPackage.MAXSIZE_EQUIPMENT, ItemPackage.EQUIPMENT);
//Set the Skill level caps of all FFXIV (classes)skills to 50
for (int i = 0; i < charaWork.battleSave.skillLevelCap.Length; i++)
@@ -230,7 +245,7 @@ namespace FFXIVClassic_Map_Server.Actors
Database.LoadPlayerCharacter(this);
lastPlayTimeUpdate = Utils.UnixTimeStampUTC();
this.aiContainer = new AIContainer(this, new PlayerController(this), null, new TargetFind(this));
allegiance = CharacterTargetingAllegiance.Player;
CalculateBaseStats();
@@ -476,7 +491,18 @@ namespace FFXIVClassic_Map_Server.Actors
propPacketUtil.AddProperty(String.Format("work.guildleveChecked[{0}]", i));
}
//NPC Linkshell
//Bazaar
CheckBazaarFlags(true);
if (charaWork.eventSave.repairType != 0)
propPacketUtil.AddProperty("charaWork.eventSave.repairType");
if (charaWork.eventTemp.bazaarRetail)
propPacketUtil.AddProperty("charaWork.eventTemp.bazaarRetail");
if (charaWork.eventTemp.bazaarRepair)
propPacketUtil.AddProperty("charaWork.eventTemp.bazaarRepair");
if (charaWork.eventTemp.bazaarMateria)
propPacketUtil.AddProperty("charaWork.eventTemp.bazaarMateria");
//NPC Linkshell
for (int i = 0; i < playerWork.npcLinkshellChatCalling.Length; i++)
{
if (playerWork.npcLinkshellChatCalling[i] != false)
@@ -516,14 +542,14 @@ namespace FFXIVClassic_Map_Server.Actors
//GetSpawnPackets(actorId, spawnType).DebugPrintPacket();
#region Inventory & Equipment
QueuePacket(InventoryBeginChangePacket.BuildPacket(actorId));
inventories[Inventory.NORMAL].SendFullInventory(this);
inventories[Inventory.CURRENCY_CRYSTALS].SendFullInventory(this);
inventories[Inventory.KEYITEMS].SendFullInventory(this);
inventories[Inventory.BAZAAR].SendFullInventory(this);
inventories[Inventory.MELDREQUEST].SendFullInventory(this);
inventories[Inventory.LOOT].SendFullInventory(this);
equipment.SendFullEquipment(false);
QueuePacket(InventoryBeginChangePacket.BuildPacket(actorId, true));
itemPackages[ItemPackage.NORMAL].SendFullPackage(this);
itemPackages[ItemPackage.CURRENCY_CRYSTALS].SendFullPackage(this);
itemPackages[ItemPackage.KEYITEMS].SendFullPackage(this);
itemPackages[ItemPackage.BAZAAR].SendFullPackage(this);
itemPackages[ItemPackage.MELDREQUEST].SendFullPackage(this);
itemPackages[ItemPackage.LOOT].SendFullPackage(this);
equipment.SendUpdate(this);
playerSession.QueuePacket(InventoryEndChangePacket.BuildPacket(actorId));
#endregion
@@ -625,6 +651,33 @@ namespace FFXIVClassic_Map_Server.Actors
}
}
public void BroadcastPackets(List<SubPacket> packets, bool sendToSelf)
{
foreach (SubPacket packet in packets)
{
if (sendToSelf)
{
SubPacket clonedPacket = new SubPacket(packet, actorId);
QueuePacket(clonedPacket);
}
foreach (Actor a in playerSession.actorInstanceList)
{
if (a is Player)
{
Player p = (Player)a;
if (p.Equals(this))
continue;
SubPacket clonedPacket = new SubPacket(packet, a.actorId);
p.QueuePacket(clonedPacket);
}
}
}
}
public void BroadcastPacket(SubPacket packet, bool sendToSelf)
{
if (sendToSelf)
@@ -940,6 +993,8 @@ namespace FFXIVClassic_Map_Server.Actors
public void PrepareClassChange(byte classId)
{
//If new class, init abilties and level
if (charaWork.battleSave.skillLevel[classId - 1] <= 0)
UpdateClassLevel(classId, 1);
SendCharaExpInfo();
}
@@ -1012,6 +1067,16 @@ namespace FFXIVClassic_Map_Server.Actors
RecalculateStats();
}
public void UpdateClassLevel(byte classId, short level)
{
Database.PlayerCharacterUpdateClassLevel(this, classId, level);
charaWork.battleSave.skillLevel[classId - 1] = level;
ActorPropertyPacketUtil propertyBuilder = new ActorPropertyPacketUtil("charaWork/exp", this);
propertyBuilder.AddProperty(String.Format("charaWork.battleSave.skillLevel[{0}]", classId-1));
List<SubPacket> packets = propertyBuilder.Done();
QueuePackets(packets);
}
public void GraphicChange(int slot, InventoryItem invItem)
{
if (invItem == null)
@@ -1057,18 +1122,68 @@ namespace FFXIVClassic_Map_Server.Actors
BroadcastPacket(CreateAppearancePacket(), true);
}
public Inventory GetInventory(ushort type)
public void SetRepairRequest(byte type)
{
if (inventories.ContainsKey(type))
return inventories[type];
else
return null;
charaWork.eventSave.repairType = type;
ActorPropertyPacketUtil propPacketUtil = new ActorPropertyPacketUtil("charaWork/bazaar", this);
propPacketUtil.AddProperty("charaWork.eventSave.repairType");
QueuePackets(propPacketUtil.Done());
}
public void CheckBazaarFlags(bool noUpdate = false)
{
bool isDealing = false, isRepairing = false, seekingItem = false;
lock (GetItemPackage(ItemPackage.BAZAAR))
{
foreach (InventoryItem item in GetItemPackage(ItemPackage.BAZAAR).GetRawList())
{
if (item == null)
break;
if (item.GetBazaarMode() == InventoryItem.TYPE_SINGLE || item.GetBazaarMode() == InventoryItem.TYPE_MULTI || item.GetBazaarMode() == InventoryItem.TYPE_STACK)
isDealing = true;
if (item.GetBazaarMode() == InventoryItem.TYPE_SEEK_REPAIR)
isRepairing = true;
if (item.GetBazaarMode() == InventoryItem.TYPE_SEEK_ITEM)
isDealing = true;
if (isDealing && isRepairing && seekingItem)
break;
}
}
bool doUpdate = false;
ActorPropertyPacketUtil propPacketUtil = new ActorPropertyPacketUtil("charaWork/bazaar", this);
if (charaWork.eventTemp.bazaarRetail != isDealing)
{
charaWork.eventTemp.bazaarRetail = isDealing;
propPacketUtil.AddProperty("charaWork.eventTemp.bazaarRetail");
doUpdate = true;
}
if (charaWork.eventTemp.bazaarRepair != isRepairing)
{
charaWork.eventTemp.bazaarRepair = isRepairing;
propPacketUtil.AddProperty("charaWork.eventTemp.bazaarRepair");
doUpdate = true;
}
if (charaWork.eventTemp.bazaarMateria != (GetItemPackage(ItemPackage.MELDREQUEST).GetCount() != 0))
{
charaWork.eventTemp.bazaarMateria = GetItemPackage(ItemPackage.MELDREQUEST).GetCount() != 0;
propPacketUtil.AddProperty("charaWork.eventTemp.bazaarMateria");
doUpdate = true;
}
if (!noUpdate && doUpdate)
BroadcastPackets(propPacketUtil.Done(), true);
}
public int GetCurrentGil()
{
if (GetInventory(Inventory.CURRENCY_CRYSTALS).HasItem(1000001))
return GetInventory(Inventory.CURRENCY_CRYSTALS).GetItemByCatelogId(1000001).quantity;
if (HasItem(1000001))
return GetItemPackage(ItemPackage.CURRENCY_CRYSTALS).GetItemByCatelogId(1000001).quantity;
else
return 0;
}
@@ -1094,7 +1209,7 @@ namespace FFXIVClassic_Map_Server.Actors
return isZoneChanging;
}
public Equipment GetEquipment()
public ReferencedItemPackage GetEquipment()
{
return equipment;
}
@@ -1578,16 +1693,10 @@ namespace FFXIVClassic_Map_Server.Actors
else
return;
QueuePacket(InventoryBeginChangePacket.BuildPacket(toBeExamined.actorId));
toBeExamined.GetEquipment().SendCheckEquipmentToPlayer(this);
QueuePacket(InventoryBeginChangePacket.BuildPacket(toBeExamined.actorId, true));
toBeExamined.GetEquipment().SendUpdateAsItemPackage(this, ItemPackage.MAXSIZE_EQUIPMENT_OTHERPLAYER, ItemPackage.EQUIPMENT_OTHERPLAYER);
QueuePacket(InventoryEndChangePacket.BuildPacket(toBeExamined.actorId));
}
public void SendMyTradeToPlayer(Player player)
{
Inventory tradeInventory = new Inventory(this, 4, Inventory.TRADE);
tradeInventory.SendFullInventory(player);
}
}
public void SendDataPacket(params object[] parameters)
{
@@ -1599,13 +1708,15 @@ namespace FFXIVClassic_Map_Server.Actors
public void StartEvent(Actor owner, EventStartPacket start)
{
currentEventOwner = start.scriptOwnerActorID;
currentEventName = start.triggerName;
LuaEngine.GetInstance().EventStarted(this, owner, start);
}
public void UpdateEvent(EventUpdatePacket update)
{
LuaEngine.GetInstance().OnEventUpdate(this, update.luaParams);
}
LuaEngine.GetInstance().OnEventUpdate(this, update.luaParams);
}
public void KickEvent(Actor actor, string conditionName, params object[] parameters)
{
@@ -1613,7 +1724,18 @@ namespace FFXIVClassic_Map_Server.Actors
return;
List<LuaParam> lParams = LuaUtils.CreateLuaParamList(parameters);
SubPacket spacket = KickEventPacket.BuildPacket(actorId, actor.actorId, conditionName, lParams);
SubPacket spacket = KickEventPacket.BuildPacket(actorId, actor.actorId, 0x75dc1705, conditionName, lParams);
spacket.DebugPrintSubPacket();
QueuePacket(spacket);
}
public void KickEventSpecial(Actor actor, uint unknown, string conditionName, params object[] parameters)
{
if (actor == null)
return;
List<LuaParam> lParams = LuaUtils.CreateLuaParamList(parameters);
SubPacket spacket = KickEventPacket.BuildPacket(actorId, actor.actorId, unknown, conditionName, lParams);
spacket.DebugPrintSubPacket();
QueuePacket(spacket);
}
@@ -1621,7 +1743,7 @@ namespace FFXIVClassic_Map_Server.Actors
public void SetEventStatus(Actor actor, string conditionName, bool enabled, byte unknown)
{
QueuePacket(packets.send.actor.events.SetEventStatus.BuildPacket(actor.actorId, enabled, unknown, conditionName));
}
}
public void RunEventFunction(string functionName, params object[] parameters)
{
@@ -2475,7 +2597,7 @@ namespace FFXIVClassic_Map_Server.Actors
base.CalculateBaseStats();
//Add weapon property mod
var equip = GetEquipment();
var mainHandItem = equip.GetItemAtSlot(Equipment.SLOT_MAINHAND);
var mainHandItem = equip.GetItemAtSlot(SLOT_MAINHAND);
var damageAttribute = 0;
var attackDelay = 3000;
var hitCount = 1;
@@ -2549,5 +2671,120 @@ namespace FFXIVClassic_Map_Server.Actors
return equippedItem != null && equippedItem.itemId == itemId;
}
public Retainer GetSpawnedRetainer()
{
return currentSpawnedRetainer;
}
public void StartTradeTransaction(Player otherPlayer)
{
myOfferings = new ReferencedItemPackage(this, ItemPackage.MAXSIZE_TRADE, ItemPackage.TRADE);
otherTrader = otherPlayer;
isTradeAccepted = false;
}
public Player GetOtherTrader()
{
return otherTrader;
}
public ReferencedItemPackage GetTradeOfferings()
{
return myOfferings;
}
public bool IsTrading()
{
return otherTrader != null;
}
public bool IsTradeAccepted()
{
return isTradeAccepted;
}
public void AddTradeItem(ushort slot, ItemRefParam chosenItem, int tradeQuantity)
{
if (!IsTrading())
return;
//Get chosen item
InventoryItem offeredItem = itemPackages[chosenItem.itemPackage].GetItemAtSlot(chosenItem.slot);
offeredItem.SetTradeQuantity(tradeQuantity);
myOfferings.Set(slot, offeredItem);
SendTradePackets();
}
public void RemoveTradeItem(ushort slot)
{
if (!IsTrading())
return;
InventoryItem offeredItem = myOfferings.GetItemAtSlot(slot);
offeredItem.SetNormal();
myOfferings.Clear(slot);
SendTradePackets();
}
public void ClearTradeItems()
{
if (!IsTrading())
return;
for (ushort i = 0; i < myOfferings.GetCapacity(); i++)
{
InventoryItem offeredItem = myOfferings.GetItemAtSlot(i);
if (offeredItem != null)
offeredItem.SetNormal();
}
myOfferings.ClearAll();
SendTradePackets();
}
private void SendTradePackets()
{
//Send to self
QueuePacket(InventoryBeginChangePacket.BuildPacket(actorId, true));
myOfferings.SendUpdate(this);
QueuePacket(InventoryEndChangePacket.BuildPacket(actorId));
//Send to other trader
otherTrader.QueuePacket(InventoryBeginChangePacket.BuildPacket(actorId, true));
myOfferings.SendUpdateAsItemPackage(otherTrader);
otherTrader.QueuePacket(InventoryEndChangePacket.BuildPacket(actorId));
}
public void AcceptTrade(bool accepted)
{
if (!IsTrading())
return;
isTradeAccepted = accepted;
}
public void FinishTradeTransaction()
{
if (myOfferings != null)
{
myOfferings.ClearAll();
for (ushort i = 0; i < myOfferings.GetCapacity(); i++)
{
InventoryItem offeredItem = myOfferings.GetItemAtSlot(i);
if (offeredItem != null)
offeredItem.SetNormal();
}
QueuePacket(InventoryBeginChangePacket.BuildPacket(actorId, true));
myOfferings.SendUpdate(this);
QueuePacket(InventoryEndChangePacket.BuildPacket(actorId));
}
isTradeAccepted = false;
myOfferings = null;
otherTrader = null;
}
}
}