diff --git a/FFXIVClassic Map Server/Database.cs b/FFXIVClassic Map Server/Database.cs index a9683de6..14b958c4 100644 --- a/FFXIVClassic Map Server/Database.cs +++ b/FFXIVClassic Map Server/Database.cs @@ -1113,7 +1113,7 @@ namespace FFXIVClassic_Map_Server player.GetItemPackage(ItemPackage.NORMAL).InitList(GetItemPackage(player, 0, ItemPackage.NORMAL)); player.GetItemPackage(ItemPackage.KEYITEMS).InitList(GetItemPackage(player, 0, ItemPackage.KEYITEMS)); player.GetItemPackage(ItemPackage.CURRENCY_CRYSTALS).InitList(GetItemPackage(player, 0, ItemPackage.CURRENCY_CRYSTALS)); - player.GetItemPackage(ItemPackage.BAZAAR).InitList(GetBazaar(player)); + player.GetItemPackage(ItemPackage.BAZAAR).InitList(GetItemPackage(player, 0, ItemPackage.BAZAAR)); player.GetItemPackage(ItemPackage.MELDREQUEST).InitList(GetItemPackage(player, 0, ItemPackage.MELDREQUEST)); player.GetItemPackage(ItemPackage.LOOT).InitList(GetItemPackage(player, 0, ItemPackage.LOOT)); @@ -1435,7 +1435,7 @@ namespace FFXIVClassic_Map_Server return slot; } - public static List GetItemPackage(Player player, uint slotOffset, uint type) + public static List GetItemPackage(Character owner, uint slotOffset, uint type) { List items = new List(); @@ -1453,6 +1453,14 @@ namespace FFXIVClassic_Map_Server quantity, quality, + dealingValue, + dealingMode, + dealingAttached1, + dealingAttached2, + dealingAttached3, + dealingTag, + bazaarMode, + durability, mainQuality, subQuality1, @@ -1471,348 +1479,20 @@ namespace FFXIVClassic_Map_Server FROM characters_inventory INNER JOIN server_items ON serverItemId = server_items.id LEFT JOIN server_items_modifiers ON server_items.id = server_items_modifiers.id - WHERE characterId = @charId AND itemPackage = @type"; - - MySqlCommand cmd = new MySqlCommand(query, conn); - cmd.Parameters.AddWithValue("@charId", player.actorId); - cmd.Parameters.AddWithValue("@type", type); - - ushort slot = 0; - using (MySqlDataReader reader = cmd.ExecuteReader()) - { - while (reader.Read()) - { - uint uniqueId = reader.GetUInt32("serverItemId"); - uint itemId = reader.GetUInt32("itemId"); - int quantity = reader.GetInt32("quantity"); - - byte qualityNumber = reader.GetByte("quality"); - - bool hasModifier = !reader.IsDBNull(reader.GetOrdinal("modifierId")); - InventoryItem.ItemModifier modifier = null; - - if (hasModifier) - modifier = new InventoryItem.ItemModifier(reader); - - InventoryItem item = new InventoryItem(uniqueId, Server.GetItemGamedata(itemId), quantity, qualityNumber, modifier); - items.Add(item); - } - } - } - catch (MySqlException e) - { - Program.Log.Error(e.ToString()); - } - finally - { - conn.Dispose(); - } - } - - return items; - } - - public static bool CreateBazaarEntry(Player owner, InventoryItem reward, InventoryItem seek, int rewardAmount, int seekAmount, byte bazaarMode, int sellPrice = 0) - { - 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(); - - string query = @" - INSERT INTO characters_inventory_bazaar - (characterId, rewardId, seekId, rewardAmount, seekAmount, bazaarMode, sellPrice) - VALUES - (@characterId, @rewardId, @seekId, @rewardAmount, @seekAmount, @bazaarMode, @sellPrice); - "; - - MySqlCommand cmd = new MySqlCommand(query, conn); - cmd.Parameters.AddWithValue("@characterId", owner.actorId); - cmd.Parameters.AddWithValue("@rewardId", reward.uniqueId); - cmd.Parameters.AddWithValue("@seekId", seek.uniqueId); - cmd.Parameters.AddWithValue("@rewardAmount", rewardAmount); - cmd.Parameters.AddWithValue("@seekAmount", seekAmount); - cmd.Parameters.AddWithValue("@bazaarMode", bazaarMode); - cmd.Parameters.AddWithValue("@sellPrice", sellPrice); - cmd.ExecuteNonQuery(); - } - catch (MySqlException e) - { - Program.Log.Error(e.ToString()); - return false; - } - finally - { - conn.Dispose(); - } - } - - return true; - } - - public static void ClearBazaarEntry(Player owner, InventoryItem reward) - { - using (MySqlConnection conn = new MySqlConnection(String.Format("Server={0}; Port={1}; Database={2}; UID={3}; Password={4}; Allow User Variables=True", ConfigConstants.DATABASE_HOST, ConfigConstants.DATABASE_PORT, ConfigConstants.DATABASE_NAME, ConfigConstants.DATABASE_USERNAME, ConfigConstants.DATABASE_PASSWORD))) - { - try - { - conn.Open(); - - string query = @" - DELETE FROM characters_inventory_bazaar - WHERE characterId = @charId and rewardId = @rewardId; - "; + LEFT JOIN server_items_dealing ON server_items.id = server_items_dealing.id + WHERE characterId = @charId AND itemPackage = @type + ORDER BY slot ASC"; MySqlCommand cmd = new MySqlCommand(query, conn); cmd.Parameters.AddWithValue("@charId", owner.actorId); - cmd.Parameters.AddWithValue("@rewardId", reward.uniqueId); - cmd.ExecuteNonQuery(); - - } - catch (MySqlException e) - { - Program.Log.Error(e.ToString()); - } - finally - { - conn.Dispose(); - } - } - } - - public static List GetBazaar(Player player) - { - List rewardItems = new List(); - Dictionary seekItems = new Dictionary(); - - 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(); - - string query = @" - SELECT - rewardId, - seekId, - rewardAmount, - bazaarMode, - sellPrice, - itemId, - server_items_modifiers.id AS modifierId, - quantity, - quality, - - durability, - mainQuality, - subQuality1, - subQuality2, - subQuality3, - param1, - param2, - param3, - spiritbind, - materia1, - materia2, - materia3, - materia4, - materia5 - - FROM characters_inventory_bazaar - INNER JOIN server_items ON rewardId = server_items.id - LEFT JOIN server_items_modifiers ON server_items.id = server_items_modifiers.id - WHERE characterId = @charaId"; - - MySqlCommand cmd = new MySqlCommand(query, conn); - cmd.Parameters.AddWithValue("@charaId", player.actorId); - - using (MySqlDataReader reader = cmd.ExecuteReader()) - { - while (reader.Read()) - { - uint uniqueId = reader.GetUInt32("rewardId"); - uint itemId = reader.GetUInt32("itemId"); - int quantity = reader.GetInt32("quantity"); - - byte qualityNumber = reader.GetByte("quality"); - - bool hasModifier = !reader.IsDBNull(reader.GetOrdinal("modifierId")); - InventoryItem.ItemModifier modifier = null; - - if (hasModifier) - modifier = new InventoryItem.ItemModifier(reader); - - InventoryItem item = new InventoryItem(uniqueId, Server.GetItemGamedata(itemId), quantity, qualityNumber, modifier); - - byte bazaarMode = reader.GetByte("bazaarMode"); - - if (bazaarMode == InventoryItem.TYPE_SINGLE || bazaarMode == InventoryItem.TYPE_MULTI || bazaarMode == InventoryItem.TYPE_STACK) - { - uint price = (uint)reader.GetInt32("sellPrice"); - item.SetDealing(bazaarMode, (int)price); - } - else - { - uint seekId = reader.GetUInt32("seekId"); - item.SetDealingAttached(bazaarMode, seekId); - } - - rewardItems.Add(item); - } - } - - string query2 = @" - SELECT - seekId, - seekAmount, - sellPrice, - itemId, - server_items_modifiers.id AS modifierId, - quantity, - quality, - - durability, - mainQuality, - subQuality1, - subQuality2, - subQuality3, - param1, - param2, - param3, - spiritbind, - materia1, - materia2, - materia3, - materia4, - materia5 - - FROM characters_inventory_bazaar - INNER JOIN server_items ON seekId = server_items.id - LEFT JOIN server_items_modifiers ON server_items.id = server_items_modifiers.id - WHERE characterId = @charaId and bazaarMode != 11 and bazaarMode != 12 and bazaarMode != 13"; - - MySqlCommand cmd2 = new MySqlCommand(query2, conn); - cmd2.Parameters.AddWithValue("@charaId", player.actorId); - - using (MySqlDataReader reader = cmd2.ExecuteReader()) - { - while (reader.Read()) - { - uint uniqueId = reader.GetUInt32("seekId"); - uint itemId = reader.GetUInt32("itemId"); - int quantity = reader.GetInt32("quantity"); - - byte qualityNumber = reader.GetByte("quality"); - - bool hasModifier = !reader.IsDBNull(reader.GetOrdinal("modifierId")); - InventoryItem.ItemModifier modifier = null; - - if (hasModifier) - modifier = new InventoryItem.ItemModifier(reader); - - InventoryItem item = new InventoryItem(uniqueId, Server.GetItemGamedata(itemId), quantity, qualityNumber, modifier); - item.SetHasAttached(true); - seekItems.Add(uniqueId, item); - } - } - } - catch (MySqlException e) - { - Program.Log.Error(e.ToString()); - } - finally - { - conn.Dispose(); - } - } - - List items = new List(); - ushort slot = 0; - foreach (InventoryItem reward in rewardItems) - { - if (reward.dealingMode == InventoryItem.DEALINGMODE_PRICED) - { - reward.slot = slot++; - items.Add(reward); - } - else - { - if (seekItems.ContainsKey(reward.GetAttached())) - { - reward.slot = slot++; - items.Add(reward); - InventoryItem seek = seekItems[reward.GetAttached()]; - seek.slot = slot++; - items.Add(seek); - reward.SetAttachedIndex(7, seek.slot); - } - } - } - - return items; - } - - public static List GetInventory(Retainer retainer, uint type) - { - List items = new List(); - - 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(); - - string query = @" - SELECT - serverItemId, - itemId, - server_items_modifiers.id AS modifierId, - quantity, - quality, - - durability, - mainQuality, - subQuality1, - subQuality2, - subQuality3, - param1, - param2, - param3, - spiritbind, - materia1, - materia2, - materia3, - materia4, - materia5 - - FROM retainers_inventory - INNER JOIN server_items ON serverItemId = server_items.id - LEFT JOIN server_items_modifiers ON server_items.id = server_items_modifiers.id - WHERE retainerId = @retainerId AND itemPackage = @type"; - - MySqlCommand cmd = new MySqlCommand(query, conn); - cmd.Parameters.AddWithValue("@retainerId", retainer.GetRetainerId()); cmd.Parameters.AddWithValue("@type", type); ushort slot = 0; using (MySqlDataReader reader = cmd.ExecuteReader()) { while (reader.Read()) - { - uint uniqueId = reader.GetUInt32("serverItemId"); - uint itemId = reader.GetUInt32("itemId"); - int quantity = reader.GetInt32("quantity"); - - byte qualityNumber = reader.GetByte("quality"); - - bool hasModifier = !reader.IsDBNull(reader.GetOrdinal("modifierId")); - InventoryItem.ItemModifier modifier = null; - - if (hasModifier) - modifier = new InventoryItem.ItemModifier(reader); - - InventoryItem item = new InventoryItem(uniqueId, Server.GetItemGamedata(itemId), quantity, qualityNumber, modifier); + { + InventoryItem item = new InventoryItem(reader); items.Add(item); } } @@ -1828,6 +1508,11 @@ namespace FFXIVClassic_Map_Server } return items; + } + + public static InventoryItem CreateItem(InventoryItem item, uint quantity) + { + return CreateItem(item.itemId, (int) quantity, item.quality, item.modifiers); } public static InventoryItem CreateItem(uint itemId, int quantity, byte quality, InventoryItem.ItemModifier modifiers = null) @@ -1862,7 +1547,7 @@ namespace FFXIVClassic_Map_Server cmd.Parameters.AddWithValue("@quality", quality); cmd.ExecuteNonQuery(); - insertedItem = new InventoryItem((uint)cmd.LastInsertedId, Server.GetItemGamedata(itemId), quantity, quality, modifiers); + insertedItem = new InventoryItem((uint)cmd.LastInsertedId, itemId, quantity, quality, modifiers); if (modifiers != null) { @@ -1885,7 +1570,7 @@ namespace FFXIVClassic_Map_Server return insertedItem; } - public static void AddItem(Player player, InventoryItem addedItem, uint type) + public static void AddItem(Character owner, InventoryItem addedItem, ushort itemPackage, ushort slot) { 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))) { @@ -1895,16 +1580,17 @@ namespace FFXIVClassic_Map_Server string query = @" INSERT INTO characters_inventory - (characterId, itemPackage, serverItemId) + (characterId, itemPackage, serverItemId, slot) VALUES - (@charId, @itemPackage, @serverItemId) + (@charId, @itemPackage, @serverItemId, @slot) "; MySqlCommand cmd = new MySqlCommand(query, conn); cmd.Parameters.AddWithValue("@serverItemId", addedItem.uniqueId); - cmd.Parameters.AddWithValue("@charId", player.actorId); - cmd.Parameters.AddWithValue("@itemPackage", type); + cmd.Parameters.AddWithValue("@charId", owner.actorId); + cmd.Parameters.AddWithValue("@itemPackage", itemPackage); + cmd.Parameters.AddWithValue("@slot", slot); cmd.ExecuteNonQuery(); } @@ -1919,7 +1605,35 @@ namespace FFXIVClassic_Map_Server } } + public static void RemoveItem(Character owner, ulong serverItemId) + { + using (MySqlConnection conn = new MySqlConnection(String.Format("Server={0}; Port={1}; Database={2}; UID={3}; Password={4}; Allow User Variables=True", ConfigConstants.DATABASE_HOST, ConfigConstants.DATABASE_PORT, ConfigConstants.DATABASE_NAME, ConfigConstants.DATABASE_USERNAME, ConfigConstants.DATABASE_PASSWORD))) + { + try + { + conn.Open(); + string query = @" + DELETE FROM characters_inventory + WHERE characterId = @charId and serverItemId = @serverItemId; + "; + + MySqlCommand cmd = new MySqlCommand(query, conn); + cmd.Parameters.AddWithValue("@charId", owner.actorId); + cmd.Parameters.AddWithValue("@serverItemId", serverItemId); + cmd.ExecuteNonQuery(); + + } + catch (MySqlException e) + { + Program.Log.Error(e.ToString()); + } + finally + { + conn.Dispose(); + } + } + } public static void SetQuantity(ulong serverItemId, int quantity) { @@ -1953,37 +1667,7 @@ namespace FFXIVClassic_Map_Server } - public static void RemoveItem(Player player, ulong serverItemId) - { - using (MySqlConnection conn = new MySqlConnection(String.Format("Server={0}; Port={1}; Database={2}; UID={3}; Password={4}; Allow User Variables=True", ConfigConstants.DATABASE_HOST, ConfigConstants.DATABASE_PORT, ConfigConstants.DATABASE_NAME, ConfigConstants.DATABASE_USERNAME, ConfigConstants.DATABASE_PASSWORD))) - { - try - { - conn.Open(); - - string query = @" - DELETE FROM characters_inventory - WHERE characterId = @charId and serverItemId = @serverItemId; - "; - - MySqlCommand cmd = new MySqlCommand(query, conn); - cmd.Parameters.AddWithValue("@charId", player.actorId); - cmd.Parameters.AddWithValue("@serverItemId", serverItemId); - cmd.ExecuteNonQuery(); - - } - catch (MySqlException e) - { - Program.Log.Error(e.ToString()); - } - finally - { - conn.Dispose(); - } - } - } - - public static void AddItem(Retainer retainer, InventoryItem addedItem, uint type) + public static void SetDealingInfo(InventoryItem item) { 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))) { @@ -1992,18 +1676,13 @@ namespace FFXIVClassic_Map_Server conn.Open(); string query = @" - INSERT INTO retainers_inventory - (retainerId, itemPackage, serverItemId) - VALUES - (@retainerId, @itemPackage, @serverItemId) + REPLACE INTO server_items_dealing + (id, dealingValue, dealingMode, dealingAttached1, dealingAttached2, dealingAttached3, dealingTag, bazaarMode) + VALUES + (@serverItemId, @dealingValue, @dealingMode, @dealingAttached1, @dealingAttached2, @dealingAttached3, @dealingTag, @bazaarMode); "; - MySqlCommand cmd = new MySqlCommand(query, conn); - - cmd.Parameters.AddWithValue("@serverItemId", addedItem.uniqueId); - cmd.Parameters.AddWithValue("@retainerId", retainer.GetRetainerId()); - cmd.Parameters.AddWithValue("@itemPackage", type); - + item.SaveDealingInfo(cmd); cmd.ExecuteNonQuery(); } catch (MySqlException e) @@ -2017,24 +1696,23 @@ namespace FFXIVClassic_Map_Server } } - public static void RemoveItem(Retainer retainer, ulong serverItemId) + public static void ClearDealingInfo(InventoryItem item) { - using (MySqlConnection conn = new MySqlConnection(String.Format("Server={0}; Port={1}; Database={2}; UID={3}; Password={4}; Allow User Variables=True", ConfigConstants.DATABASE_HOST, ConfigConstants.DATABASE_PORT, ConfigConstants.DATABASE_NAME, ConfigConstants.DATABASE_USERNAME, ConfigConstants.DATABASE_PASSWORD))) + 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(); string query = @" - DELETE FROM retainers_inventory - WHERE retainerId = @retainerId and serverItemId = @serverItemId; + DELETE FROM + server_items_dealing + WHERE + id = @serverItemId; "; - MySqlCommand cmd = new MySqlCommand(query, conn); - cmd.Parameters.AddWithValue("@retainerId", retainer.GetRetainerId()); - cmd.Parameters.AddWithValue("@serverItemId", serverItemId); + cmd.Parameters.AddWithValue("@serverItemId", item.uniqueId); cmd.ExecuteNonQuery(); - } catch (MySqlException e) { @@ -2045,9 +1723,8 @@ namespace FFXIVClassic_Map_Server conn.Dispose(); } } - } - + public static SubPacket GetLatestAchievements(Player player) { uint[] latestAchievements = new uint[5]; diff --git a/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj b/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj index 5105d83c..fc0432bd 100644 --- a/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj +++ b/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj @@ -197,6 +197,7 @@ + diff --git a/FFXIVClassic Map Server/WorldManager.cs b/FFXIVClassic Map Server/WorldManager.cs index cea08c80..0468357a 100644 --- a/FFXIVClassic Map Server/WorldManager.cs +++ b/FFXIVClassic Map Server/WorldManager.cs @@ -18,6 +18,7 @@ using FFXIVClassic_Map_Server.actors.director; using FFXIVClassic_Map_Server.actors.chara.ai; using FFXIVClassic_Map_Server.actors.chara; using FFXIVClassic_Map_Server.actors.chara.player; +using FFXIVClassic_Map_Server.packets.send.actor.inventory; namespace FFXIVClassic_Map_Server { @@ -1502,7 +1503,7 @@ namespace FFXIVClassic_Map_Server return 2; } //Check if gil is max - else if (item.itemId == 100001 && item.dealingAttached3 + itemReceiver.GetCurrentGil() > item.GetItemData().maxStack) + else if (item.itemId == 100001 && item.GetTradeQuantity() + itemReceiver.GetCurrentGil() > item.GetItemData().maxStack) { return 3; } @@ -1515,147 +1516,153 @@ namespace FFXIVClassic_Map_Server return Database.CreateItem(itemId, amount, quality, modifiers); } - public bool BazaarBuyOperation(Player bazaar, Player buyer, InventoryItem itemToBuy, int quantity, int cost) - { - if (bazaar == null || buyer == null || itemToBuy == null) - return false; - - if (quantity <= 0) - return false; - - if (cost < 0) - return false; - - if (itemToBuy.GetBazaarMode() == InventoryItem.TYPE_SINGLE || itemToBuy.GetBazaarMode() == InventoryItem.TYPE_MULTI || itemToBuy.GetBazaarMode() == InventoryItem.TYPE_STACK) + public int AddToBazaar(Player player, InventoryItem reward, InventoryItem seek, int rewardAmount, int seekAmount, byte bazaarMode) + { + //Selling Items + if (bazaarMode == InventoryItem.MODE_SELL_SINGLE) { - itemToBuy.ChangeQuantity(-quantity); - buyer.AddItem(itemToBuy.itemId, quantity, itemToBuy.quality); - buyer.GetItemPackage(ItemPackage.CURRENCY_CRYSTALS).RemoveItem(1000001, cost); + reward.SetSelling(bazaarMode, seekAmount); + ItemPackage originalPackage = player.GetItemPackage(reward.itemPackage); + ItemPackage bazaarPackage = player.GetItemPackage(ItemPackage.BAZAAR); + originalPackage.MoveItem(reward, bazaarPackage); } - - if (itemToBuy.quantity == 0) - Database.ClearBazaarEntry(bazaar, itemToBuy); - - bazaar.CheckBazaarFlags(); - - return true; - } - - public bool BazaarSellOperation(Player bazaar, Player buyer, InventoryItem reward, int rewardQuantity, InventoryItem seek, int seekQuantity) - { - if (bazaar == null || buyer == null || reward == null || seek == null) - return false; - - if (rewardQuantity <= 0 || seekQuantity <= 0) - return false; - - if (reward.GetBazaarMode() == InventoryItem.TYPE_SEEK_ITEM) + else if (bazaarMode == InventoryItem.MODE_SELL_PSTACK) { - InventoryItem seekBazaar = bazaar.GetItemPackage(ItemPackage.BAZAAR).GetItemAttachedTo(reward); - bazaar.RemoveItem(reward, rewardQuantity); - bazaar.RemoveItem(seekBazaar, seekQuantity); - bazaar.AddItem(seekBazaar); - bazaar.AddItem(seek.itemId, seekQuantity, seek.quality); + if (rewardAmount <= reward.quantity) + { + ItemPackage originalPackage = player.GetItemPackage(reward.itemPackage); + ItemPackage bazaarPackage = player.GetItemPackage(ItemPackage.BAZAAR); - buyer.RemoveItem(seek, seekQuantity); - buyer.AddItem(reward); + InventoryItem splitItem = Database.CreateItem(reward, (uint) rewardAmount); + + if (splitItem != null) + { + reward.ChangeQuantity(-rewardAmount); + splitItem.SetSelling(bazaarMode, seekAmount); + bazaarPackage.AddItem(splitItem); + } + + //TODO: Refactor so that it's not a mess like V + player.QueuePacket(InventoryBeginChangePacket.BuildPacket(player.actorId)); + originalPackage.SendUpdate(); + player.QueuePacket(InventoryEndChangePacket.BuildPacket(player.actorId)); + } + } + else if (bazaarMode == InventoryItem.MODE_SELL_FSTACK) + { + reward.SetSelling(bazaarMode, seekAmount); + ItemPackage originalPackage = player.GetItemPackage(reward.itemPackage); + ItemPackage bazaarPackage = player.GetItemPackage(ItemPackage.BAZAAR); + originalPackage.MoveItem(reward, bazaarPackage); } - Database.ClearBazaarEntry(bazaar, reward); + //Seeking Items + else if (bazaarMode == InventoryItem.MODE_SEEK_ITEM || bazaarMode == InventoryItem.MODE_SEEK_REPAIR) + { + ItemPackage originalRewardPackage = player.GetItemPackage(reward.itemPackage); + ItemPackage originalSeekPackage = player.GetItemPackage(seek.itemPackage); + ItemPackage bazaarPackage = player.GetItemPackage(ItemPackage.BAZAAR); - bazaar.CheckBazaarFlags(); + InventoryItem finalReward, finalSeek; - return true; - } - - public void AddToBazaar(Player player, InventoryItem reward, InventoryItem seek, int rewardAmount, int seekAmount, byte bazaarMode) - { - bool succ = false; - - if (bazaarMode == InventoryItem.TYPE_SINGLE || bazaarMode == InventoryItem.TYPE_MULTI || bazaarMode == InventoryItem.TYPE_STACK) - succ = Database.CreateBazaarEntry(player, reward, seek, rewardAmount, 0, bazaarMode, seekAmount); - else - succ = Database.CreateBazaarEntry(player, reward, seek, rewardAmount, seekAmount, bazaarMode); - - if (succ) - { - if (bazaarMode != InventoryItem.TYPE_SINGLE && bazaarMode != InventoryItem.TYPE_MULTI && bazaarMode != InventoryItem.TYPE_STACK) - { - reward.SetDealingAttached(bazaarMode, seek.uniqueId); - seek.SetHasAttached(true); - player.GetItemPackage(ItemPackage.BAZAAR).StartSendUpdate(); - player.GetItemPackage(ItemPackage.BAZAAR).AddItem(reward); - player.GetItemPackage(ItemPackage.BAZAAR).AddItem(seek); - reward.SetAttachedIndex(ItemPackage.BAZAAR, seek.slot); - player.GetItemPackage(ItemPackage.BAZAAR).DoneSendUpdate(); - } - else - { - reward.SetDealing(bazaarMode, seekAmount); - player.GetItemPackage(ItemPackage.BAZAAR).StartSendUpdate(); - player.GetItemPackage(ItemPackage.BAZAAR).AddItem(reward); - player.GetItemPackage(ItemPackage.BAZAAR).DoneSendUpdate(); - } + /////REWARD///// - } + //No Split, just move + if (rewardAmount == reward.itemData.maxStack) + { + finalReward = reward; + originalRewardPackage.RemoveItem(reward); + } + else //Splitting (ughh) + { + InventoryItem splitItem = Database.CreateItem(reward, (uint)rewardAmount); + + if (splitItem != null) + { + reward.ChangeQuantity(-rewardAmount); + finalReward = splitItem; + + player.QueuePacket(InventoryBeginChangePacket.BuildPacket(player.actorId)); + originalRewardPackage.SendUpdate(); + player.QueuePacket(InventoryEndChangePacket.BuildPacket(player.actorId)); + } + else + return ItemPackage.ERROR_SYSTEM; + } + + /////SEEK///// + + //No Split, just move + if (seekAmount == seek.itemData.maxStack) + { + finalSeek = seek; + originalSeekPackage.RemoveItem(seek); + } + else //Splitting (ughh) + { + InventoryItem splitItem = Database.CreateItem(seek, (uint)seekAmount); + + if (splitItem != null) + { + seek.ChangeQuantity(-seekAmount); + finalSeek = splitItem; + + player.QueuePacket(InventoryBeginChangePacket.BuildPacket(player.actorId)); + originalSeekPackage.SendUpdate(); + player.QueuePacket(InventoryEndChangePacket.BuildPacket(player.actorId)); + } + else + return ItemPackage.ERROR_SYSTEM; + } + + /////FINAL///// + + bazaarPackage.AddItem(finalReward); + bazaarPackage.AddItem(finalSeek); + finalReward.SetAsOfferTo(bazaarMode, finalSeek); + + player.QueuePacket(InventoryBeginChangePacket.BuildPacket(player.actorId)); + bazaarPackage.SendUpdate(); + player.QueuePacket(InventoryEndChangePacket.BuildPacket(player.actorId)); + } player.CheckBazaarFlags(); + return ItemPackage.ERROR_SUCCESS; } - - public void RemoveFromBazaar(Player player, InventoryItem rewardRef) + public int RemoveFromBazaar(Player player, InventoryItem reward) { - ushort attachedItemPackage = (ushort)((rewardRef.dealingAttached1 >> 16) & 0xFF); - ushort attachedSlot = (ushort) (rewardRef.dealingAttached1 & 0xFF); + InventoryItem seek = reward.GetOfferedTo(); + ItemPackage bazaarPackage = player.GetItemPackage(ItemPackage.BAZAAR); - InventoryItem seekRef = rewardRef.IsSelling() ? null : player.GetItemPackage(attachedItemPackage).GetItemAtSlot(attachedSlot); - - Database.ClearBazaarEntry(player, rewardRef); - - player.GetItemPackage(ItemPackage.BAZAAR).RemoveItem(rewardRef); - - bool isSelling = rewardRef.IsSelling(); - rewardRef.SetNormal(); - - if (seekRef != null) - player.GetItemPackage(ItemPackage.BAZAAR).RemoveItem(seekRef); - - player.AddItem(rewardRef); - - if (!isSelling) + bazaarPackage.RemoveItem(reward); + reward.SetNormal(); + player.AddItem(reward); + Database.ClearDealingInfo(reward); + + if (seek != null) { - seekRef.SetNormal(); - player.AddItem(seekRef); + bazaarPackage.RemoveItem(seek); + seek.SetNormal(); + player.AddItem(seek); + Database.ClearDealingInfo(seek); } - + player.CheckBazaarFlags(); + return ItemPackage.ERROR_SUCCESS; } - /* - public void TransactionBazaar(Player owner, Player other, InventoryItem reward, InventoryItem seek, int rewardAmount, int seekAmount) + + public int BazaarBuyOperation(Player bazaar, Player buyer, InventoryItem itemToBuy, int quantity, int cost) { - Database.ClearBazaarEntry(owner, reward, seek); + //TODO: Implement + return ItemPackage.ERROR_SYSTEM; + } - //Remove Bazaar Items from owner - owner.GetInventory(Inventory.BAZAAR).RemoveItem(reward); - owner.GetInventory(Inventory.BAZAAR).RemoveItem(seek); - - //Remove Seek item from other - if (seek.GetItemData().IsMoney()) - other.GetInventory(Inventory.CURRENCY_CRYSTALS).RemoveItem(seek.itemId, seekAmount); - else - other.GetInventory(Inventory.NORMAL).RemoveItem(seek.itemId, seekAmount); - - //Add reward to other, seek to owner - if (reward.GetItemData().IsMoney()) - other.GetInventory(Inventory.CURRENCY_CRYSTALS).AddItem(reward.itemId, rewardAmount); - else - other.GetInventory(Inventory.NORMAL).AddItem(reward); - - if (seek.GetItemData().IsMoney()) - owner.GetInventory(Inventory.CURRENCY_CRYSTALS).AddItem(seek.itemId, seekAmount); - else - other.GetInventory(Inventory.NORMAL).AddItem(seek); - }*/ + public int BazaarSellOperation(Player bazaar, Player buyer, InventoryItem reward, int rewardQuantity, InventoryItem seek, int seekQuantity) + { + //TODO: Implement + return ItemPackage.ERROR_SYSTEM; + } public bool SendGroupInit(Session session, ulong groupId) { diff --git a/FFXIVClassic Map Server/actors/Actor.cs b/FFXIVClassic Map Server/actors/Actor.cs index 747cf9d3..07cc9f26 100644 --- a/FFXIVClassic Map Server/actors/Actor.cs +++ b/FFXIVClassic Map Server/actors/Actor.cs @@ -743,7 +743,18 @@ namespace FFXIVClassic_Map_Server.Actors return FindRandomPoint(positionX, positionY, positionZ, minRadius, maxRadius); } #endregion - + + public override string ToString() + { + if (className != null) + { + return string.Format("{0} [0x{1:X}]", className, actorId); + } + else + { + return string.Format("Unknown [0x{0:X}]", actorId); + } + } } } diff --git a/FFXIVClassic Map Server/actors/chara/Character.cs b/FFXIVClassic Map Server/actors/chara/Character.cs index 3246848a..c505b0c5 100644 --- a/FFXIVClassic Map Server/actors/chara/Character.cs +++ b/FFXIVClassic Map Server/actors/chara/Character.cs @@ -1147,7 +1147,7 @@ namespace FFXIVClassic_Map_Server.Actors return; player.QueuePacket(InventoryBeginChangePacket.BuildPacket(actorId, true)); - itemPackages[(ushort)id].SendUpdate(player); + itemPackages[(ushort)id].SendFullPackage(player); player.QueuePacket(InventoryEndChangePacket.BuildPacket(actorId)); } @@ -1179,23 +1179,14 @@ namespace FFXIVClassic_Map_Server.Actors } } - public void SetItem(InventoryItem item, ushort itemPackage, ushort slot) - { - if (itemPackages.ContainsKey(itemPackage)) - { - itemPackages[itemPackage].SetItem(slot, item); - } - } - public void MoveItem(InventoryItem item, ushort destinationPackage) { ushort sourcePackage = item.itemPackage; if (!itemPackages.ContainsKey(sourcePackage) && !itemPackages.ContainsKey(destinationPackage)) return; - - itemPackages[sourcePackage].RemoveItem(item); - itemPackages[destinationPackage].AddItem(item); + + itemPackages[sourcePackage].MoveItem(item, itemPackages[destinationPackage]); } public void RemoveItem(uint catalogID) @@ -1227,15 +1218,7 @@ namespace FFXIVClassic_Map_Server.Actors public void RemoveItem(InventoryItem item) { - RemoveItem(item, 1); - } - - public void RemoveItem(InventoryItem item, int quantity) - { - if (itemPackages.ContainsKey(item.itemPackage)) - { - itemPackages[item.itemPackage].RemoveItem(item, quantity); - } + itemPackages[item.itemPackage].RemoveItem(item); } public bool HasItem(uint catalogID) @@ -1270,7 +1253,6 @@ namespace FFXIVClassic_Map_Server.Actors return false; } - public InventoryItem GetItem(LuaUtils.ItemRefParam reference) { if (reference.actorId != actorId) diff --git a/FFXIVClassic Map Server/actors/chara/ItemPackage.cs b/FFXIVClassic Map Server/actors/chara/ItemPackage.cs index 1309ea64..5df79535 100644 --- a/FFXIVClassic Map Server/actors/chara/ItemPackage.cs +++ b/FFXIVClassic Map Server/actors/chara/ItemPackage.cs @@ -63,7 +63,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.player int i = 0; foreach (InventoryItem item in itemsFromDB) { - item.RefreshPositioning(owner, itemPackageCode, (ushort) i); + item.SetOwner(owner, itemPackageCode, (ushort) i); list[i++] = item; } endOfListIndex = i; @@ -104,20 +104,6 @@ namespace FFXIVClassic_Map_Server.actors.chara.player } return null; } - - public InventoryItem GetItemAttachedTo(InventoryItem attachedTo) - { - for (int i = 0; i < endOfListIndex; i++) - { - InventoryItem item = list[i]; - - Debug.Assert(item != null, "Item slot was null!!!"); - - if (attachedTo.GetAttached() == item.uniqueId) - return item; - } - return null; - } public int AddItem(uint itemId) { @@ -128,7 +114,75 @@ namespace FFXIVClassic_Map_Server.actors.chara.player { return AddItem(itemId, quantity, 1); } - + + public int AddItem(uint itemId, int quantity, byte quality) + { + if (!IsSpaceForAdd(itemId, quantity, quality)) + return ERROR_FULL; + + ItemData gItem = Server.GetItemGamedata(itemId); + + //If it's unique, abort + if (HasItem(itemId) && gItem.isExclusive) + return ERROR_HAS_UNIQUE; + + if (gItem == null) + { + Program.Log.Error("Inventory.AddItem: unable to find item %u", itemId); + return ERROR_SYSTEM; + } + + //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; + } + } + + //New item that spilled over + while (quantityCount > 0) + { + InventoryItem.ItemModifier modifiers = null; + if (gItem.durability != 0) + { + modifiers = new InventoryItem.ItemModifier(); + modifiers.durability = (uint)gItem.durability; + } + + InventoryItem addedItem = Database.CreateItem(itemId, Math.Min(quantityCount, gItem.maxStack), quality, modifiers); + addedItem.SetOwner(owner, itemPackageCode, (ushort)endOfListIndex); + isDirty[endOfListIndex] = true; + list[endOfListIndex++] = addedItem; + quantityCount -= gItem.maxStack; + + DoDatabaseAdd(addedItem); + } + + if (owner is Player) + { + (owner as Player).QueuePacket(InventoryBeginChangePacket.BuildPacket(owner.actorId)); + SendUpdate(); + (owner as Player).QueuePacket(InventoryEndChangePacket.BuildPacket(owner.actorId)); + } + + return ERROR_SUCCESS; + } + public int AddItems(uint[] itemIds, uint[] quantity = null, byte[] quality = null) { //Check if has space @@ -187,7 +241,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.player byte setQuality = quality != null ? quality[i] : (byte)1; InventoryItem addedItem = Database.CreateItem(itemIds[i], Math.Min(quantityCount, gItem.maxStack), setQuality, modifiers); - addedItem.RefreshPositioning(owner, itemPackageCode, (ushort)endOfListIndex); + addedItem.SetOwner(owner, itemPackageCode, (ushort)endOfListIndex); isDirty[endOfListIndex] = true; list[endOfListIndex++] = addedItem; quantityCount -= gItem.maxStack; @@ -205,45 +259,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.player return ERROR_SUCCESS; } - - public bool CanAdd(uint[] itemIds, uint[] quantity, byte[] quality) - { - int tempInvSize = GetCount(); - - for (int i = 0; i < itemIds.Length; i++) - { - ItemData gItem = Server.GetItemGamedata(itemIds[i]); - //Check if item id exists and fill up til maxstack - int quantityCount = (int) (quantity != null ? quantity[i] : 1); - for (int j = 0; j < endOfListIndex; j++) - { - InventoryItem item = list[j]; - - Debug.Assert(item != null, "Item slot was null!!!"); - - if (item.itemId == itemIds[i] && item.quality == (quality != null ? quality[i] : 1) && item.quantity < gItem.maxStack) - { - quantityCount -= (gItem.maxStack - item.quantity); - if (quantityCount <= 0) - break; - } - } - - //New items that spilled over creating new stacks - while (quantityCount > 0) - { - quantityCount -= gItem.maxStack; - tempInvSize++; - } - - //If the new stacks push us over capacity, can't add these items - if (tempInvSize > itemPackageCapacity) - return false; - } - - return true; - } - + public int AddItem(InventoryItem itemRef) { //If it isn't a single item (ie: armor) just add like normal (not valid for BAZAAR) @@ -261,7 +277,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.player return ERROR_SYSTEM; } - itemRef.RefreshPositioning(owner, itemPackageCode, (ushort)endOfListIndex); + itemRef.SetOwner(owner, itemPackageCode, (ushort)endOfListIndex); isDirty[endOfListIndex] = true; list[endOfListIndex++] = itemRef; @@ -277,84 +293,31 @@ namespace FFXIVClassic_Map_Server.actors.chara.player return ERROR_SUCCESS; } - public int AddItem(uint itemId, int quantity, byte quality) - { - if (!IsSpaceForAdd(itemId, quantity, quality)) - return ERROR_FULL; + public int MoveItem(ushort position, ItemPackage destinationPackage) + { + InventoryItem item = GetItemAtSlot(position); - ItemData gItem = Server.GetItemGamedata(itemId); - - //If it's unique, abort - if (HasItem(itemId) && gItem.isExclusive) - return ERROR_HAS_UNIQUE; - - if (gItem == null) + if (destinationPackage.CanAdd(item)) { - Program.Log.Error("Inventory.AddItem: unable to find item %u", itemId); - return ERROR_SYSTEM; + RemoveItemAtSlot(position); + destinationPackage.AddItem(item); + return ERROR_SUCCESS; } - - //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; - } - } - - //New item that spilled over - while (quantityCount > 0) - { - InventoryItem.ItemModifier modifiers = null; - if (gItem.durability != 0) - { - modifiers = new InventoryItem.ItemModifier(); - modifiers.durability = (uint)gItem.durability; - } - - InventoryItem addedItem = Database.CreateItem(itemId, Math.Min(quantityCount, gItem.maxStack), quality, modifiers); - addedItem.RefreshPositioning(owner, itemPackageCode, (ushort)endOfListIndex); - isDirty[endOfListIndex] = true; - list[endOfListIndex++] = addedItem; - quantityCount -= gItem.maxStack; - - DoDatabaseAdd(addedItem); - } - - if (owner is Player) - { - (owner as Player).QueuePacket(InventoryBeginChangePacket.BuildPacket(owner.actorId)); - SendUpdate(); - (owner as Player).QueuePacket(InventoryEndChangePacket.BuildPacket(owner.actorId)); - } - - return ERROR_SUCCESS; + return ERROR_FULL; } - public void SetItem(ushort slot, InventoryItem item) + public int MoveItem(InventoryItem item, ItemPackage destinationPackage) { - list[slot] = item; - if (owner is Player) + if (destinationPackage == null || item == null) + return ERROR_SYSTEM; + + if (destinationPackage.CanAdd(item)) { - (owner as Player).QueuePacket(InventoryBeginChangePacket.BuildPacket(owner.actorId)); - SendUpdate(); - (owner as Player).QueuePacket(InventoryEndChangePacket.BuildPacket(owner.actorId)); + RemoveItem(item); + destinationPackage.AddItem(item); + return ERROR_SUCCESS; } - item.RefreshPositioning(owner, itemPackageCode, slot); + return ERROR_FULL; } public void RemoveItem(uint itemId) @@ -423,14 +386,10 @@ namespace FFXIVClassic_Map_Server.actors.chara.player public void RemoveItem(InventoryItem item) { - RemoveItemByUniqueId(item.uniqueId, item.quantity); + if (itemPackageCode == item.itemPackage) + RemoveItemAtSlot(item.slot); } - - public void RemoveItem(InventoryItem item, int quantity) - { - RemoveItemByUniqueId(item.uniqueId, quantity); - } - + public void RemoveItemByUniqueId(ulong itemDBId, int quantity) { ushort slot = 0; @@ -455,7 +414,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.player if (quantity >= toDelete.quantity) { DoDatabaseRemove(toDelete.uniqueId); - list[slot].RefreshPositioning(null, 0xFFFF, 0xFFFF); + list[slot].ClearOwner(); list[slot] = null; } else @@ -483,7 +442,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.player DoDatabaseRemove(list[slot].uniqueId); - list[slot].RefreshPositioning(null, 0xFFFF, 0xFFFF); + list[slot].ClearOwner(); list[slot] = null; isDirty[slot] = true; @@ -510,7 +469,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.player { DoDatabaseRemove(list[slot].uniqueId); - list[slot].RefreshPositioning(null, 0xFFFF, 0xFFFF); + list[slot].ClearOwner(); list[slot] = null; DoRealign(); } @@ -532,7 +491,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.player { for (int i = 0; i < endOfListIndex; i++) { - list[i].RefreshPositioning(null, 0xFFFF, 0xFFFF); + list[i].ClearOwner(); list[i] = null; isDirty[i] = true; } @@ -546,6 +505,49 @@ namespace FFXIVClassic_Map_Server.actors.chara.player } } + public bool CanAdd(InventoryItem item) + { + return itemPackageCapacity - GetCount() > 0; + } + + public bool CanAdd(uint[] itemIds, uint[] quantity, byte[] quality) + { + int tempInvSize = GetCount(); + + for (int i = 0; i < itemIds.Length; i++) + { + ItemData gItem = Server.GetItemGamedata(itemIds[i]); + //Check if item id exists and fill up til maxstack + int quantityCount = (int)(quantity != null ? quantity[i] : 1); + for (int j = 0; j < endOfListIndex; j++) + { + InventoryItem item = list[j]; + + Debug.Assert(item != null, "Item slot was null!!!"); + + if (item.itemId == itemIds[i] && item.quality == (quality != null ? quality[i] : 1) && item.quantity < gItem.maxStack) + { + quantityCount -= (gItem.maxStack - item.quantity); + if (quantityCount <= 0) + break; + } + } + + //New items that spilled over creating new stacks + while (quantityCount > 0) + { + quantityCount -= gItem.maxStack; + tempInvSize++; + } + + //If the new stacks push us over capacity, can't add these items + if (tempInvSize > itemPackageCapacity) + return false; + } + + return true; + } + public void MarkDirty(InventoryItem item) { if (item.itemPackage != itemPackageCode || list[item.slot] == null) @@ -724,24 +726,14 @@ namespace FFXIVClassic_Map_Server.actors.chara.player if (isTemporary) return; - if (itemPackageCode == BAZAAR) - return; - - if (owner is Player) - Database.AddItem((Player)owner, addedItem, itemPackageCode); - else if (owner is Retainer) - Database.AddItem((Retainer)owner, addedItem, itemPackageCode); + Database.AddItem(owner, addedItem, itemPackageCode, addedItem.slot); } private void DoDatabaseQuantity(ulong itemDBId, int quantity) { if (isTemporary) return; - - - if (itemPackageCode == BAZAAR) - return; - + Database.SetQuantity(itemDBId, quantity); } @@ -749,14 +741,8 @@ namespace FFXIVClassic_Map_Server.actors.chara.player { if (isTemporary) return; - - if (itemPackageCode == BAZAAR) - return; - - if (owner is Player) - Database.RemoveItem((Player)owner, itemDBId); - else if (owner is Retainer) - Database.RemoveItem((Retainer)owner, itemDBId); + + Database.RemoveItem(owner, itemDBId); } public void StartSendUpdate() @@ -870,5 +856,45 @@ namespace FFXIVClassic_Map_Server.actors.chara.player { return endOfListIndex; } + + public override string ToString() + { + string packageName; + switch (itemPackageCode) + { + case NORMAL: + packageName = "Inventory"; + break; + case LOOT: + packageName = "Loot"; + break; + case MELDREQUEST: + packageName = "Meld Request"; + break; + case BAZAAR: + packageName = "Bazaar"; + break; + case CURRENCY_CRYSTALS: + packageName = "Currency"; + break; + case KEYITEMS: + packageName = "KeyItems"; + break; + case EQUIPMENT: + packageName = "Equipment"; + break; + case TRADE: + packageName = "Trade"; + break; + case EQUIPMENT_OTHERPLAYER: + packageName = "CheckEquip"; + break; + default: + packageName = "Unknown"; + break; + } + + return string.Format("{0} Package", packageName); + } } } diff --git a/FFXIVClassic Map Server/actors/chara/npc/Retainer.cs b/FFXIVClassic Map Server/actors/chara/npc/Retainer.cs index 2e6e2531..f1b26fae 100644 --- a/FFXIVClassic Map Server/actors/chara/npc/Retainer.cs +++ b/FFXIVClassic Map Server/actors/chara/npc/Retainer.cs @@ -24,9 +24,9 @@ namespace FFXIVClassic_Map_Server.actors.chara.npc itemPackages[ItemPackage.CURRENCY_CRYSTALS] = new ItemPackage(this, MAXSIZE_INVENTORY_CURRANCY, ItemPackage.CURRENCY_CRYSTALS); itemPackages[ItemPackage.BAZAAR] = new ItemPackage(this, MAXSIZE_INVENTORY_BAZAAR, ItemPackage.BAZAAR); - itemPackages[ItemPackage.NORMAL].InitList(Database.GetInventory(this, ItemPackage.NORMAL)); - itemPackages[ItemPackage.CURRENCY_CRYSTALS].InitList(Database.GetInventory(this, ItemPackage.CURRENCY_CRYSTALS)); - itemPackages[ItemPackage.BAZAAR].InitList(Database.GetInventory(this, ItemPackage.BAZAAR)); + itemPackages[ItemPackage.NORMAL].InitList(Database.GetItemPackage(this, 0, ItemPackage.NORMAL)); + itemPackages[ItemPackage.CURRENCY_CRYSTALS].InitList(Database.GetItemPackage(this, 0, ItemPackage.CURRENCY_CRYSTALS)); + itemPackages[ItemPackage.BAZAAR].InitList(Database.GetItemPackage(this, 0, ItemPackage.BAZAAR)); } public uint GetRetainerId() diff --git a/FFXIVClassic Map Server/actors/chara/player/Player.cs b/FFXIVClassic Map Server/actors/chara/player/Player.cs index eaa2f2c7..280a3bbb 100644 --- a/FFXIVClassic Map Server/actors/chara/player/Player.cs +++ b/FFXIVClassic Map Server/actors/chara/player/Player.cs @@ -1131,11 +1131,11 @@ namespace FFXIVClassic_Map_Server.Actors if (item == null) break; - if (item.GetBazaarMode() == InventoryItem.TYPE_SINGLE || item.GetBazaarMode() == InventoryItem.TYPE_MULTI || item.GetBazaarMode() == InventoryItem.TYPE_STACK) + if (item.GetBazaarMode() == InventoryItem.MODE_SELL_SINGLE || item.GetBazaarMode() == InventoryItem.MODE_SELL_PSTACK || item.GetBazaarMode() == InventoryItem.MODE_SELL_FSTACK) isDealing = true; - if (item.GetBazaarMode() == InventoryItem.TYPE_SEEK_REPAIR) + if (item.GetBazaarMode() == InventoryItem.MODE_SEEK_REPAIR) isRepairing = true; - if (item.GetBazaarMode() == InventoryItem.TYPE_SEEK_ITEM) + if (item.GetBazaarMode() == InventoryItem.MODE_SEEK_ITEM) isDealing = true; if (isDealing && isRepairing && seekingItem) diff --git a/FFXIVClassic Map Server/dataobjects/InventoryItem.cs b/FFXIVClassic Map Server/dataobjects/InventoryItem.cs index c6c87382..6fdd1ed9 100644 --- a/FFXIVClassic Map Server/dataobjects/InventoryItem.cs +++ b/FFXIVClassic Map Server/dataobjects/InventoryItem.cs @@ -1,4 +1,6 @@ -using FFXIVClassic_Map_Server.Actors; +using FFXIVClassic_Map_Server.actors.chara.player; +using FFXIVClassic_Map_Server.Actors; +using MySql.Data.MySqlClient; using System; using System.IO; @@ -14,29 +16,28 @@ namespace FFXIVClassic_Map_Server.dataobjects public const byte TAG_DEALING = 0xC9; public const byte TAG_ATTACHED = 0xCA; - public const byte TYPE_SINGLE = 11; - public const byte TYPE_MULTI = 12; - public const byte TYPE_STACK = 13; - public const byte TYPE_SEEK_ITEM = 20; - public const byte TYPE_SEEK_REPAIR = 30; + public const byte MODE_SELL_SINGLE = 11; //0xB + public const byte MODE_SELL_PSTACK = 12; //0xC + public const byte MODE_SELL_FSTACK = 13; //0xD + public const byte MODE_SEEK_ITEM = 20; //0x14 + public const byte MODE_SEEK_REPAIR = 30; //0x1E + public const byte MODE_SEEK_MELD = 40; //0x28 public ulong uniqueId; public uint itemId; public int quantity = 1; - public byte dealingVal = 0; - public byte dealingMode = DEALINGMODE_NONE; - public int dealingAttached1 = 0; - public int dealingAttached2 = 0; - public int dealingAttached3 = 0; + private byte dealingVal = 0; + private byte dealingMode = DEALINGMODE_NONE; + private int dealingAttached1 = 0; + private int dealingAttached2 = 0; + private int dealingAttached3 = 0; - public byte[] tags = new byte[4]; - public byte[] tagValues = new byte[4]; + private byte[] tags = new byte[4]; + private byte[] tagValues = new byte[4]; public byte quality = 1; - - private ulong attachedTo = 0; - + public ItemModifier modifiers; public readonly ItemData itemData; @@ -122,23 +123,41 @@ namespace FFXIVClassic_Map_Server.dataobjects binWriter.Write((Byte) materiaGrade[4]); } } - - //Bare Minimum - public InventoryItem(uint id, ItemData data) + + //For loading already existing items + public InventoryItem(MySqlDataReader reader) { - this.uniqueId = id; - this.itemId = data.catalogID; - this.itemData = data; - this.quantity = 1; + uniqueId = reader.GetUInt32("serverItemId"); + itemId = reader.GetUInt32("itemId"); + itemData = Server.GetItemGamedata(itemId); + quantity = reader.GetInt32("quantity"); + quality = reader.GetByte("quality"); + + bool hasDealing = !reader.IsDBNull(reader.GetOrdinal("bazaarMode")); + if (hasDealing) + { + dealingVal = reader.GetByte("dealingValue"); + dealingMode = reader.GetByte("dealingMode"); + dealingAttached1 = reader.GetInt32("dealingAttached1"); + dealingAttached2 = reader.GetInt32("dealingAttached2"); + dealingAttached3 = reader.GetInt32("dealingAttached3"); + tags[0] = reader.GetByte("dealingTag"); + tagValues[0] = reader.GetByte("bazaarMode"); + } + + bool hasModifiers = !reader.IsDBNull(reader.GetOrdinal("modifierId")); + if (hasModifiers) + modifiers = new InventoryItem.ItemModifier(reader); tags[1] = itemData.isExclusive ? TAG_EXCLUSIVE : (byte)0; } - - public InventoryItem(uint uniqueId, ItemData itemData, int quantity, byte qualityNumber, ItemModifier modifiers = null) + + //For creating new items (only should be called by the DB) + public InventoryItem(uint uniqueId, uint itemId, int quantity, byte qualityNumber, ItemModifier modifiers = null) { this.uniqueId = uniqueId; - this.itemId = itemData.catalogID; - this.itemData = itemData; + this.itemId = itemId; + this.itemData = Server.GetItemGamedata(itemId); this.quantity = quantity; this.quality = qualityNumber; this.modifiers = modifiers; @@ -146,6 +165,18 @@ namespace FFXIVClassic_Map_Server.dataobjects tags[1] = itemData.isExclusive ? TAG_EXCLUSIVE : (byte)0; } + public void SaveDealingInfo(MySqlCommand cmd) + { + cmd.Parameters.AddWithValue("@serverItemId", uniqueId); + cmd.Parameters.AddWithValue("@dealingValue", dealingVal); + cmd.Parameters.AddWithValue("@dealingMode", dealingMode); + cmd.Parameters.AddWithValue("@dealingAttached1", dealingAttached1); + cmd.Parameters.AddWithValue("@dealingAttached2", dealingAttached2); + cmd.Parameters.AddWithValue("@dealingAttached3", dealingAttached3); + cmd.Parameters.AddWithValue("@dealingTag", tags[0]); + cmd.Parameters.AddWithValue("@bazaarMode", tagValues[0]); + } + public byte[] ToPacketBytes() { byte[] data = new byte[0x70]; @@ -220,27 +251,28 @@ namespace FFXIVClassic_Map_Server.dataobjects Database.SetQuantity(uniqueId, this.quantity); if (owner != null) - owner.GetItemPackage(itemPackage).MarkDirty(this); + owner.GetItemPackage(itemPackage).MarkDirty(this); } } - public void RefreshPositioning(Character owner, ushort itemPackage, ushort slot) + public void SetOwner(Character owner, ushort itemPackage, ushort slot) { this.owner = owner; this.itemPackage = itemPackage; this.slot = slot; - } + } - public void SetHasAttached(bool isAttached) + public void ClearOwner() { - tags[0] = isAttached ? TAG_ATTACHED : (byte)0; + owner = null; + itemPackage = 0xFFFF; + slot = 0xFFFF; } - + public void SetNormal() { tags[0] = 0; tagValues[0] = 0; - attachedTo = 0; dealingVal = 0; dealingMode = 0; dealingAttached1 = 0; @@ -249,55 +281,70 @@ namespace FFXIVClassic_Map_Server.dataobjects if (owner != null) owner.GetItemPackage(itemPackage).MarkDirty(this); - } + } - public void SetDealing(byte mode, int price) - { - tags[0] = TAG_DEALING; - tagValues[0] = mode; - - if (mode == TYPE_SINGLE || mode == TYPE_MULTI || mode == TYPE_STACK) - { - dealingVal = 1; - dealingMode = DEALINGMODE_PRICED; - dealingAttached1 = 1; - dealingAttached2 = price; - dealingAttached3 = 0; - } - - if (owner != null) - owner.GetItemPackage(itemPackage).MarkDirty(this); - } - - public void SetDealingAttached(byte mode, ulong attached) + public void SetSelling(byte mode, int price) { tags[0] = TAG_DEALING; tagValues[0] = mode; - attachedTo = attached; - + + dealingVal = 0; + dealingMode = DEALINGMODE_PRICED; + dealingAttached1 = 0; + dealingAttached2 = price; + dealingAttached3 = 0; + if (owner != null) owner.GetItemPackage(itemPackage).MarkDirty(this); + + Database.SetDealingInfo(this); } - public ulong GetAttached() + public void SetAsOfferTo(byte mode, InventoryItem seeked) { - return attachedTo; - } + tags[0] = TAG_DEALING; + tagValues[0] = mode; - public void SetAttachedIndex(ushort package, ushort index) - { - dealingVal = 1; + dealingVal = 0; dealingMode = DEALINGMODE_REFERENCED; - dealingAttached1 = ((package << 16) | index); + dealingAttached1 = ((seeked.itemPackage << 16) | seeked.slot); + dealingAttached2 = 0; + dealingAttached3 = 0; + + seeked.SetSeeking(); + + if (owner != null) + owner.GetItemPackage(itemPackage).MarkDirty(this); + + Database.SetDealingInfo(this); + } + + protected void SetSeeking() + { + tags[0] = TAG_ATTACHED; + tagValues[0] = 0; + + dealingVal = 0; + dealingMode = DEALINGMODE_NONE; + dealingAttached1 = 0; dealingAttached2 = 0; dealingAttached3 = 0; if (owner != null) owner.GetItemPackage(itemPackage).MarkDirty(this); + + Database.SetDealingInfo(this); } public void SetTradeQuantity(int quantity) { + tags[0] = 0; + tagValues[0] = 0; + + dealingVal = 0; + dealingMode = DEALINGMODE_NONE; + dealingAttached1 = 0; + dealingAttached2 = 0; dealingAttached3 = quantity; if (owner != null) @@ -309,9 +356,19 @@ namespace FFXIVClassic_Map_Server.dataobjects return dealingAttached3; } - public ItemData GetItemData() + public InventoryItem GetOfferedTo() { - return itemData; + if (dealingMode != DEALINGMODE_REFERENCED) + return null; + + ushort attachedItemPackage = (ushort)((dealingAttached1 >> 16) & 0xFF); + ushort attachedSlot = (ushort)(dealingAttached1 & 0xFF); + return owner.GetItemPackage(attachedItemPackage).GetItemAtSlot(attachedSlot); + } + + public bool IsSelling() + { + return GetBazaarMode() == MODE_SELL_SINGLE || GetBazaarMode() == MODE_SELL_PSTACK || GetBazaarMode() == MODE_SELL_FSTACK; } public byte GetBazaarMode() @@ -321,9 +378,22 @@ namespace FFXIVClassic_Map_Server.dataobjects return 0; } - public bool IsSelling() + public ItemData GetItemData() { - return GetBazaarMode() == TYPE_SINGLE || GetBazaarMode() == TYPE_MULTI || GetBazaarMode() == TYPE_STACK; + return itemData; + } + + public override string ToString() + { + if (itemData != null) + { + if (quantity <= 1) + return string.Format("{0}+{1} ({2}/{3})", itemData.name, quality-1, quantity, itemData.maxStack); + else + return string.Format("{0} ({1}/{2})", itemData.name, quantity, itemData.maxStack); + } + else + return "Invalid Item"; } } diff --git a/FFXIVClassic Map Server/lua/LuaUtils.cs b/FFXIVClassic Map Server/lua/LuaUtils.cs index 7c324a3a..b591094e 100644 --- a/FFXIVClassic Map Server/lua/LuaUtils.cs +++ b/FFXIVClassic Map Server/lua/LuaUtils.cs @@ -32,16 +32,20 @@ namespace FFXIVClassic_Map_Server { public uint actorId; public ushort offerSlot; - public ushort unknown1; + public byte offerPackageId; + public byte unknown1; public ushort seekSlot; - public ushort unknown2; + public byte seekPackageId; + public byte unknown2; - public ItemOfferParam(uint actorId, ushort unknown1, ushort offerSlot, ushort seekSlot, ushort unknown2) + public ItemOfferParam(uint actorId, ushort offerSlot, byte offerPackageId, byte unknown1, ushort seekSlot, byte seekPackageId, byte unknown2) { this.actorId = actorId; - this.unknown1 = unknown1; this.offerSlot = offerSlot; + this.offerPackageId = offerPackageId; + this.unknown1 = unknown1; this.seekSlot = seekSlot; + this.seekPackageId = seekPackageId; this.unknown2 = unknown2; } } @@ -111,11 +115,13 @@ namespace FFXIVClassic_Map_Server case 0x8: //Used for offering { uint actorId = Utils.SwapEndian(reader.ReadUInt32()); - ushort unk1 = Utils.SwapEndian(reader.ReadUInt16()); - ushort offerSlot = Utils.SwapEndian(reader.ReadUInt16()); + ushort rewardSlot = Utils.SwapEndian(reader.ReadUInt16()); + byte rewardPackageId = reader.ReadByte(); + byte unk1 = reader.ReadByte(); //Always 0x2? ushort seekSlot = Utils.SwapEndian(reader.ReadUInt16()); - ushort unk2 = Utils.SwapEndian(reader.ReadUInt16()); - value = new ItemOfferParam(actorId, unk1, offerSlot, seekSlot, unk2); + byte seekPackageId = reader.ReadByte(); + byte unk2 = reader.ReadByte(); //Always 0xD? + value = new ItemOfferParam(actorId, rewardSlot, rewardPackageId, unk1, seekSlot, seekPackageId, unk2); } break; case 0x9: //Two Longs (only storing first one) @@ -130,6 +136,8 @@ namespace FFXIVClassic_Map_Server case 0xF: //End isDone = true; continue; + default: + throw new ArgumentException("Unknown lua param..."); } if (isDone) @@ -139,7 +147,7 @@ namespace FFXIVClassic_Map_Server if (value != null && value is ItemOfferParam) { luaParams.Add(new LuaParam(code, value)); - luaParams.Add(new LuaParam(5, null)); + luaParams.Add(new LuaParam(0x5, null)); //This is to clean up the seek script as it fucks with the args. } else if (value != null) luaParams.Add(new LuaParam(code, value)); @@ -150,6 +158,103 @@ namespace FFXIVClassic_Map_Server return luaParams; } + public static List ReadLuaParams(byte[] bytesIn) + { + List luaParams = new List(); + + using (MemoryStream memStream = new MemoryStream(bytesIn)) + { + using (BinaryReader reader = new BinaryReader(memStream)) + { + bool isDone = false; + while (true) + { + byte code = reader.ReadByte(); + object value = null; + bool wasNil = false; + + switch (code) + { + case 0x0: //Int32 + value = Utils.SwapEndian(reader.ReadInt32()); + break; + case 0x1: //Int32 + value = Utils.SwapEndian(reader.ReadUInt32()); + break; + case 0x2: //Null Termed String + List list = new List(); + while (true) + { + byte readByte = reader.ReadByte(); + if (readByte == 0) + break; + list.Add(readByte); + } + value = Encoding.ASCII.GetString(list.ToArray()); + break; + case 0x3: //Boolean True + value = true; + break; + case 0x4: //Boolean False + value = false; + break; + case 0x5: //Nil + wasNil = true; + break; + case 0x6: //Actor (By Id) + value = Utils.SwapEndian(reader.ReadUInt32()); + break; + case 0x7: //Weird one used for inventory + uint type7ActorId = Utils.SwapEndian(reader.ReadUInt32()); + byte type7Unknown = reader.ReadByte(); + byte type7Slot = reader.ReadByte(); + byte type7InventoryType = reader.ReadByte(); + value = new ItemRefParam(type7ActorId, type7Unknown, type7Slot, type7InventoryType); + break; + case 0x8: + uint actorId = Utils.SwapEndian(reader.ReadUInt32()); + ushort rewardSlot = Utils.SwapEndian(reader.ReadUInt16()); + byte rewardPackageId = reader.ReadByte(); + byte unk1 = reader.ReadByte(); //Always 0x2? + ushort seekSlot = Utils.SwapEndian(reader.ReadUInt16()); + byte seekPackageId = reader.ReadByte(); + byte unk2 = reader.ReadByte(); //Always 0xD? + value = new ItemOfferParam(actorId, rewardSlot, rewardPackageId, unk1, seekSlot, seekPackageId, unk2); + break; + case 0x9: //Two Longs (only storing first one) + value = new Type9Param(Utils.SwapEndian(reader.ReadUInt64()), Utils.SwapEndian(reader.ReadUInt64())); + break; + case 0xC: //Byte + value = reader.ReadByte(); + break; + case 0x1B: //Short? + value = reader.ReadUInt16(); + break; + case 0xF: //End + isDone = true; + continue; + default: + throw new ArgumentException("Unknown lua param..."); + } + + if (isDone) + break; + + if (value != null && value is ItemOfferParam) + { + luaParams.Add(new LuaParam(code, value)); + luaParams.Add(new LuaParam(0x5, null)); //This is to clean up the seek script as it fucks with the args. + } + else if (value != null) + luaParams.Add(new LuaParam(code, value)); + else if (wasNil) + luaParams.Add(new LuaParam(code, value)); + } + } + } + return luaParams; + } + public static void WriteLuaParams(BinaryWriter writer, List luaParams) { if (luaParams == null) @@ -211,86 +316,6 @@ namespace FFXIVClassic_Map_Server writer.Write((Byte)0xF); } - public static List ReadLuaParams(byte[] bytesIn) - { - List luaParams = new List(); - - using (MemoryStream memStream = new MemoryStream(bytesIn)) - { - using (BinaryReader reader = new BinaryReader(memStream)) - { - bool isDone = false; - while (true) - { - byte code = reader.ReadByte(); - object value = null; - bool wasNil = false; - - switch (code) - { - case 0x0: //Int32 - value = Utils.SwapEndian(reader.ReadInt32()); - break; - case 0x1: //Int32 - value = Utils.SwapEndian(reader.ReadUInt32()); - break; - case 0x2: //Null Termed String - List list = new List(); - while (true) - { - byte readByte = reader.ReadByte(); - if (readByte == 0) - break; - list.Add(readByte); - } - value = Encoding.ASCII.GetString(list.ToArray()); - break; - case 0x3: //Boolean True - value = true; - break; - case 0x4: //Boolean False - value = false; - break; - case 0x5: //Nil - wasNil = true; - break; - case 0x6: //Actor (By Id) - value = Utils.SwapEndian(reader.ReadUInt32()); - break; - case 0x7: //Weird one used for inventory - uint type7ActorId = Utils.SwapEndian(reader.ReadUInt32()); - byte type7Unknown = reader.ReadByte(); - byte type7Slot = reader.ReadByte(); - byte type7InventoryType = reader.ReadByte(); - value = new ItemRefParam(type7ActorId, type7Unknown, type7Slot, type7InventoryType); - break; - case 0x9: //Two Longs (only storing first one) - value = new Type9Param(Utils.SwapEndian(reader.ReadUInt64()), Utils.SwapEndian(reader.ReadUInt64())); - break; - case 0xC: //Byte - value = reader.ReadByte(); - break; - case 0x1B: //Short? - value = reader.ReadUInt16(); - break; - case 0xF: //End - isDone = true; - continue; - } - - if (isDone) - break; - - if (value != null) - luaParams.Add(new LuaParam(code, value)); - else if (wasNil) - luaParams.Add(new LuaParam(code, value)); - } - } - } - return luaParams; - } - public static List CreateLuaParamList(DynValue fromScript) { List luaParams = new List(); @@ -461,7 +486,7 @@ namespace FFXIVClassic_Map_Server break; case 0x8: //Weird one used for inventory ItemOfferParam itemOfferParam = ((ItemOfferParam)lParams[i].value); - dumpString += String.Format("Type8 Param: (0x{0:X}, 0x{1:X}, 0x{2:X}, 0x{3:X}, 0x{4:X})", itemOfferParam.actorId, itemOfferParam.unknown1, itemOfferParam.offerSlot, itemOfferParam.seekSlot, itemOfferParam.unknown2); + dumpString += String.Format("Type8 Param: (0x{0:X}, 0x{1:X}, 0x{2:X}, 0x{3:X}, 0x{4:X}, 0x{5:X}, 0x{6:X})", itemOfferParam.actorId, itemOfferParam.offerSlot, itemOfferParam.offerPackageId, itemOfferParam.unknown1, itemOfferParam.seekSlot, itemOfferParam.seekPackageId, itemOfferParam.unknown2); break; case 0x9: //Long (+ 8 bytes ignored) Type9Param type9Param = ((Type9Param)lParams[i].value);