Ported .Net Core commits:
hondacrx: - Initial commit: Switch to .Net Core 2.0 - Fix build and removed not needed files Fabi: - Updated solution platforms. - Changed folder structure. - Change library target framework to netstandard2.0. - Updated solution platforms again... - Removed windows specific kernel32 function usage (Ctrl-C handler).
This commit is contained in:
@@ -0,0 +1,261 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.Database;
|
||||
|
||||
namespace Game.Entities
|
||||
{
|
||||
public class Bag : Item
|
||||
{
|
||||
public Bag()
|
||||
{
|
||||
objectTypeMask |= TypeMask.Container;
|
||||
objectTypeId = TypeId.Container;
|
||||
|
||||
valuesCount = (int)ContainerFields.End;
|
||||
_dynamicValuesCount = (int)ItemDynamicFields.End;
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
for (byte i = 0; i < ItemConst.MaxBagSize; ++i)
|
||||
{
|
||||
Item item = m_bagslot[i];
|
||||
if (item)
|
||||
{
|
||||
if (item.IsInWorld)
|
||||
{
|
||||
Log.outFatal(LogFilter.PlayerItems, "Item {0} (slot {1}, bag slot {2}) in bag {3} (slot {4}, bag slot {5}, m_bagslot {6}) is to be deleted but is still in world.",
|
||||
item.GetEntry(), item.GetSlot(), item.GetBagSlot(),
|
||||
GetEntry(), GetSlot(), GetBagSlot(), i);
|
||||
item.RemoveFromWorld();
|
||||
}
|
||||
m_bagslot[i].Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
base.Dispose();
|
||||
}
|
||||
|
||||
public override void AddToWorld()
|
||||
{
|
||||
base.AddToWorld();
|
||||
|
||||
for (uint i = 0; i < GetBagSize(); ++i)
|
||||
if (m_bagslot[i] != null)
|
||||
m_bagslot[i].AddToWorld();
|
||||
}
|
||||
|
||||
public override void RemoveFromWorld()
|
||||
{
|
||||
for (uint i = 0; i < GetBagSize(); ++i)
|
||||
if (m_bagslot[i] != null)
|
||||
m_bagslot[i].RemoveFromWorld();
|
||||
|
||||
base.RemoveFromWorld();
|
||||
}
|
||||
|
||||
public override bool Create(ulong guidlow, uint itemid, Player owner)
|
||||
{
|
||||
var itemProto = Global.ObjectMgr.GetItemTemplate(itemid);
|
||||
|
||||
if (itemProto == null || itemProto.GetContainerSlots() > ItemConst.MaxBagSize)
|
||||
return false;
|
||||
|
||||
_Create(ObjectGuid.Create(HighGuid.Item, guidlow));
|
||||
|
||||
_bonusData = new BonusData(itemProto);
|
||||
|
||||
SetEntry(itemid);
|
||||
SetObjectScale(1.0f);
|
||||
|
||||
if (owner)
|
||||
{
|
||||
SetGuidValue(ItemFields.Owner, owner.GetGUID());
|
||||
SetGuidValue(ItemFields.Contained, owner.GetGUID());
|
||||
}
|
||||
|
||||
SetUInt32Value(ItemFields.MaxDurability, itemProto.MaxDurability);
|
||||
SetUInt32Value(ItemFields.Durability, itemProto.MaxDurability);
|
||||
SetUInt32Value(ItemFields.StackCount, 1);
|
||||
|
||||
// Setting the number of Slots the Container has
|
||||
SetUInt32Value(ContainerFields.NumSlots, itemProto.GetContainerSlots());
|
||||
|
||||
// Cleaning 20 slots
|
||||
for (byte i = 0; i < ItemConst.MaxBagSize; ++i)
|
||||
SetGuidValue(ContainerFields.Slot1 + (i * 4), ObjectGuid.Empty);
|
||||
|
||||
m_bagslot = new Item[ItemConst.MaxBagSize];
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void SaveToDB(SQLTransaction trans)
|
||||
{
|
||||
base.SaveToDB(trans);
|
||||
|
||||
}
|
||||
|
||||
public override bool LoadFromDB(ulong guid, ObjectGuid owner_guid, SQLFields fields, uint entry)
|
||||
{
|
||||
if (!base.LoadFromDB(guid, owner_guid, fields, entry))
|
||||
return false;
|
||||
|
||||
ItemTemplate itemProto = GetTemplate(); // checked in Item.LoadFromDB
|
||||
SetUInt32Value(ContainerFields.NumSlots, itemProto.GetContainerSlots());
|
||||
// cleanup bag content related item value fields (its will be filled correctly from `character_inventory`)
|
||||
for (byte i = 0; i < ItemConst.MaxBagSize; ++i)
|
||||
{
|
||||
SetGuidValue(ContainerFields.Slot1 + (i * 4), ObjectGuid.Empty);
|
||||
m_bagslot[i] = null;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void DeleteFromDB(SQLTransaction trans)
|
||||
{
|
||||
for (byte i = 0; i < ItemConst.MaxBagSize; ++i)
|
||||
if (m_bagslot[i] != null)
|
||||
m_bagslot[i].DeleteFromDB(trans);
|
||||
|
||||
base.DeleteFromDB(trans);
|
||||
}
|
||||
|
||||
public uint GetFreeSlots()
|
||||
{
|
||||
uint slots = 0;
|
||||
for (uint i = 0; i < GetBagSize(); ++i)
|
||||
if (m_bagslot[i] == null)
|
||||
++slots;
|
||||
|
||||
return slots;
|
||||
}
|
||||
|
||||
public void RemoveItem(byte slot, bool update)
|
||||
{
|
||||
if (m_bagslot[slot] != null)
|
||||
m_bagslot[slot].SetContainer(null);
|
||||
|
||||
m_bagslot[slot] = null;
|
||||
SetGuidValue(ContainerFields.Slot1 + (slot * 4), ObjectGuid.Empty);
|
||||
}
|
||||
|
||||
public void StoreItem(byte slot, Item pItem, bool update)
|
||||
{
|
||||
if (pItem != null && pItem.GetGUID() != GetGUID())
|
||||
{
|
||||
m_bagslot[slot] = pItem;
|
||||
SetGuidValue(ContainerFields.Slot1 + (slot * 4), pItem.GetGUID());
|
||||
pItem.SetGuidValue(ItemFields.Contained, GetGUID());
|
||||
pItem.SetGuidValue(ItemFields.Owner, GetOwnerGUID());
|
||||
pItem.SetContainer(this);
|
||||
pItem.SetSlot(slot);
|
||||
}
|
||||
}
|
||||
|
||||
public override void BuildCreateUpdateBlockForPlayer(UpdateData data, Player target)
|
||||
{
|
||||
base.BuildCreateUpdateBlockForPlayer(data, target);
|
||||
|
||||
for (int i = 0; i < GetBagSize(); ++i)
|
||||
if (m_bagslot[i] != null)
|
||||
m_bagslot[i].BuildCreateUpdateBlockForPlayer(data, target);
|
||||
}
|
||||
|
||||
public bool IsEmpty()
|
||||
{
|
||||
for (var i = 0; i < GetBagSize(); ++i)
|
||||
if (m_bagslot[i] != null)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public uint GetItemCount(uint item, Item eItem)
|
||||
{
|
||||
Item pItem;
|
||||
uint count = 0;
|
||||
for (var i = 0; i < GetBagSize(); ++i)
|
||||
{
|
||||
pItem = m_bagslot[i];
|
||||
if (pItem != null && pItem != eItem && pItem.GetEntry() == item)
|
||||
count += pItem.GetCount();
|
||||
}
|
||||
|
||||
if (eItem != null && eItem.GetTemplate().GetGemProperties() != 0)
|
||||
{
|
||||
for (var i = 0; i < GetBagSize(); ++i)
|
||||
{
|
||||
pItem = m_bagslot[i];
|
||||
if (pItem != null && pItem != eItem && pItem.GetSocketColor(0) != 0)
|
||||
count += pItem.GetGemCountWithID(item);
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
public uint GetItemCountWithLimitCategory(uint limitCategory, Item skipItem)
|
||||
{
|
||||
uint count = 0;
|
||||
for (uint i = 0; i < GetBagSize(); ++i)
|
||||
{
|
||||
Item pItem = m_bagslot[i];
|
||||
if (pItem != null)
|
||||
{
|
||||
if (pItem != skipItem)
|
||||
{
|
||||
ItemTemplate pProto = pItem.GetTemplate();
|
||||
if (pProto != null)
|
||||
if (pProto.GetItemLimitCategory() == limitCategory)
|
||||
count += m_bagslot[i].GetCount();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
byte GetSlotByItemGUID(ObjectGuid guid)
|
||||
{
|
||||
for (byte i = 0; i < GetBagSize(); ++i)
|
||||
if (m_bagslot[i] != null)
|
||||
if (m_bagslot[i].GetGUID() == guid)
|
||||
return i;
|
||||
|
||||
return ItemConst.NullSlot;
|
||||
}
|
||||
|
||||
public Item GetItemByPos(byte slot)
|
||||
{
|
||||
if (slot < GetBagSize())
|
||||
return m_bagslot[slot];
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public uint GetBagSize() { return GetUInt32Value(ContainerFields.NumSlots); }
|
||||
|
||||
public static Item NewItemOrBag(ItemTemplate proto)
|
||||
{
|
||||
return (proto.GetInventoryType() == InventoryType.Bag) ? new Bag() : new Item();
|
||||
}
|
||||
|
||||
Item[] m_bagslot = new Item[36];
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,293 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.Database;
|
||||
using Game.DataStorage;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Game.Entities
|
||||
{
|
||||
public class ItemEnchantment
|
||||
{
|
||||
static ItemEnchantment()
|
||||
{
|
||||
RandomItemEnch = new EnchantmentStore();
|
||||
}
|
||||
|
||||
public static void LoadRandomEnchantmentsTable()
|
||||
{
|
||||
// for reload case
|
||||
RandomItemEnch[ItemRandomEnchantmentType.Property].Clear();
|
||||
RandomItemEnch[ItemRandomEnchantmentType.Suffix].Clear();
|
||||
|
||||
// 0 1 2 3
|
||||
SQLResult result = DB.World.Query("SELECT entry, type, ench, chance FROM item_enchantment_template");
|
||||
|
||||
if (result.IsEmpty())
|
||||
{
|
||||
Log.outError(LogFilter.Player, "Loaded 0 Item Enchantment definitions. DB table `item_enchantment_template` is empty.");
|
||||
}
|
||||
uint count = 0;
|
||||
|
||||
do
|
||||
{
|
||||
uint entry = result.Read<uint>(0);
|
||||
ItemRandomEnchantmentType type = (ItemRandomEnchantmentType)result.Read<byte>(1);
|
||||
uint ench = result.Read<uint>(2);
|
||||
float chance = result.Read<float>(3);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case ItemRandomEnchantmentType.Property:
|
||||
if (!CliDB.ItemRandomPropertiesStorage.ContainsKey(ench))
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "Property {0} used in `item_enchantment_template` by entry {1} doesn't have exist in ItemRandomProperties.db2", ench, entry);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case ItemRandomEnchantmentType.Suffix:
|
||||
if (!CliDB.ItemRandomSuffixStorage.ContainsKey(ench))
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "Suffix {0} used in `item_enchantment_template` by entry {1} doesn't have exist in ItemRandomSuffix.db2", ench, entry);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case ItemRandomEnchantmentType.BonusList:
|
||||
if (Global.DB2Mgr.GetItemBonusList(ench) == null)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "Bonus list {0} used in `item_enchantment_template` by entry {1} doesn't have exist in ItemBonus.db2", ench, entry);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Log.outError(LogFilter.Sql, "Invalid random enchantment type specified in `item_enchantment_template` table for `entry` {0} `ench` {1}", entry, ench);
|
||||
break;
|
||||
}
|
||||
|
||||
if (chance < 0.000001f || chance > 100.0f)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "Random item enchantment for entry {0} type {1} ench {2} has invalid chance {3}", entry, type, ench, chance);
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case ItemRandomEnchantmentType.Property:
|
||||
RandomItemEnch[ItemRandomEnchantmentType.Property].Add(entry, new EnchStoreItem(type, ench, chance));
|
||||
break;
|
||||
case ItemRandomEnchantmentType.Suffix:
|
||||
case ItemRandomEnchantmentType.BonusList: // random bonus lists use RandomSuffix field in Item-sparse.db2
|
||||
RandomItemEnch[ItemRandomEnchantmentType.Suffix].Add(entry, new EnchStoreItem(type, ench, chance));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
++count;
|
||||
} while (result.NextRow());
|
||||
|
||||
Log.outInfo(LogFilter.Player, "Loaded {0} Item Enchantment definitions", count);
|
||||
}
|
||||
|
||||
public static ItemRandomEnchantmentId GetItemEnchantMod(int entry, ItemRandomEnchantmentType type)
|
||||
{
|
||||
if (entry == 0)
|
||||
return ItemRandomEnchantmentId.Empty;
|
||||
|
||||
if (entry == -1)
|
||||
return ItemRandomEnchantmentId.Empty;
|
||||
|
||||
var tab = RandomItemEnch[type].LookupByKey(entry);
|
||||
if (tab == null)
|
||||
{
|
||||
Log.outError(LogFilter.Player, "Item RandomProperty / RandomSuffix id #{0} used in `item_template` but it does not have records in `item_enchantment_template` table.", entry);
|
||||
return ItemRandomEnchantmentId.Empty;
|
||||
}
|
||||
|
||||
var selectedItem = tab.SelectRandomElementByWeight(enchant => enchant.chance);
|
||||
|
||||
return new ItemRandomEnchantmentId(selectedItem.type, selectedItem.ench);
|
||||
}
|
||||
|
||||
public static ItemRandomEnchantmentId GenerateItemRandomPropertyId(uint item_id)
|
||||
{
|
||||
ItemTemplate itemProto = Global.ObjectMgr.GetItemTemplate(item_id);
|
||||
if (itemProto == null)
|
||||
return ItemRandomEnchantmentId.Empty;
|
||||
|
||||
// item must have one from this field values not null if it can have random enchantments
|
||||
if (itemProto.GetRandomProperty() == 0 && itemProto.GetRandomSuffix() == 0)
|
||||
return ItemRandomEnchantmentId.Empty;
|
||||
|
||||
// item can have not null only one from field values
|
||||
if (itemProto.GetRandomProperty() != 0 && itemProto.GetRandomSuffix() != 0)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "Item template {0} have RandomProperty == {1} and RandomSuffix == {2}, but must have one from field =0", itemProto.GetId(), itemProto.GetRandomProperty(), itemProto.GetRandomSuffix());
|
||||
return ItemRandomEnchantmentId.Empty;
|
||||
}
|
||||
|
||||
// RandomProperty case
|
||||
if (itemProto.GetRandomProperty() != 0)
|
||||
return GetItemEnchantMod((int)itemProto.GetRandomProperty(), ItemRandomEnchantmentType.Property);
|
||||
// RandomSuffix case
|
||||
else
|
||||
return GetItemEnchantMod((int)itemProto.GetRandomSuffix(), ItemRandomEnchantmentType.Suffix);
|
||||
}
|
||||
|
||||
public static uint GenerateEnchSuffixFactor(uint item_id)
|
||||
{
|
||||
ItemTemplate itemProto = Global.ObjectMgr.GetItemTemplate(item_id);
|
||||
|
||||
if (itemProto == null)
|
||||
return 0;
|
||||
if (itemProto.GetRandomSuffix() == 0)
|
||||
return 0;
|
||||
|
||||
return GetRandomPropertyPoints(itemProto.GetBaseItemLevel(), itemProto.GetQuality(), itemProto.GetInventoryType(), itemProto.GetSubClass());
|
||||
}
|
||||
|
||||
public static uint GetRandomPropertyPoints(uint itemLevel, ItemQuality quality, InventoryType inventoryType, uint subClass)
|
||||
{
|
||||
uint propIndex;
|
||||
switch (inventoryType)
|
||||
{
|
||||
case InventoryType.Head:
|
||||
case InventoryType.Body:
|
||||
case InventoryType.Chest:
|
||||
case InventoryType.Legs:
|
||||
case InventoryType.Ranged:
|
||||
case InventoryType.Weapon2Hand:
|
||||
case InventoryType.Robe:
|
||||
case InventoryType.Thrown:
|
||||
propIndex = 0;
|
||||
break;
|
||||
case InventoryType.RangedRight:
|
||||
if ((ItemSubClassWeapon)subClass == ItemSubClassWeapon.Wand)
|
||||
propIndex = 3;
|
||||
else
|
||||
propIndex = 0;
|
||||
break;
|
||||
case InventoryType.Weapon:
|
||||
case InventoryType.WeaponMainhand:
|
||||
case InventoryType.WeaponOffhand:
|
||||
propIndex = 3;
|
||||
break;
|
||||
case InventoryType.Shoulders:
|
||||
case InventoryType.Waist:
|
||||
case InventoryType.Feet:
|
||||
case InventoryType.Hands:
|
||||
case InventoryType.Trinket:
|
||||
propIndex = 1;
|
||||
break;
|
||||
case InventoryType.Neck:
|
||||
case InventoryType.Wrists:
|
||||
case InventoryType.Finger:
|
||||
case InventoryType.Shield:
|
||||
case InventoryType.Cloak:
|
||||
case InventoryType.Holdable:
|
||||
propIndex = 2;
|
||||
break;
|
||||
case InventoryType.Relic:
|
||||
propIndex = 4;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
RandPropPointsRecord randPropPointsEntry = CliDB.RandPropPointsStorage.LookupByKey(itemLevel);
|
||||
if (randPropPointsEntry == null)
|
||||
return 0;
|
||||
|
||||
// Select rare/epic modifier
|
||||
switch (quality)
|
||||
{
|
||||
case ItemQuality.Uncommon:
|
||||
return randPropPointsEntry.UncommonPropertiesPoints[propIndex];
|
||||
case ItemQuality.Rare:
|
||||
case ItemQuality.Heirloom:
|
||||
return randPropPointsEntry.RarePropertiesPoints[propIndex];
|
||||
case ItemQuality.Epic:
|
||||
case ItemQuality.Legendary:
|
||||
case ItemQuality.Artifact:
|
||||
return randPropPointsEntry.EpicPropertiesPoints[propIndex];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static EnchantmentStore RandomItemEnch;
|
||||
|
||||
public class EnchStoreItem
|
||||
{
|
||||
public EnchStoreItem()
|
||||
{
|
||||
ench = 0;
|
||||
chance = 0;
|
||||
}
|
||||
public EnchStoreItem(ItemRandomEnchantmentType _type, uint _ench, float _chance)
|
||||
{
|
||||
type = _type;
|
||||
ench = _ench;
|
||||
chance = _chance;
|
||||
}
|
||||
|
||||
public ItemRandomEnchantmentType type;
|
||||
public uint ench;
|
||||
public float chance;
|
||||
}
|
||||
|
||||
class EnchantmentStore
|
||||
{
|
||||
public EnchantmentStore()
|
||||
{
|
||||
_data[(byte)ItemRandomEnchantmentType.Property] = new MultiMap<uint, EnchStoreItem>();
|
||||
_data[(byte)ItemRandomEnchantmentType.Suffix] = new MultiMap<uint, EnchStoreItem>();
|
||||
}
|
||||
|
||||
public MultiMap<uint, EnchStoreItem> this[ItemRandomEnchantmentType type]
|
||||
{
|
||||
get
|
||||
{
|
||||
//(type != ItemRandomEnchantmentType.BonusList, "Random bonus lists do not have their own storage, use Suffix for them");
|
||||
return _data[(byte)type];
|
||||
}
|
||||
}
|
||||
|
||||
MultiMap<uint, EnchStoreItem>[] _data = new MultiMap<uint, EnchStoreItem>[2];
|
||||
}
|
||||
}
|
||||
|
||||
public struct ItemRandomEnchantmentId
|
||||
{
|
||||
public static ItemRandomEnchantmentId Empty = default(ItemRandomEnchantmentId);
|
||||
|
||||
public ItemRandomEnchantmentId(ItemRandomEnchantmentType type, uint id)
|
||||
{
|
||||
Type = type;
|
||||
Id = id;
|
||||
}
|
||||
|
||||
public ItemRandomEnchantmentType Type;
|
||||
public uint Id;
|
||||
}
|
||||
|
||||
public enum ItemRandomEnchantmentType
|
||||
{
|
||||
Property = 0,
|
||||
Suffix = 1,
|
||||
BonusList = 2
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,336 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.DataStorage;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.Contracts;
|
||||
|
||||
namespace Game.Entities
|
||||
{
|
||||
public class ItemTemplate
|
||||
{
|
||||
public ItemTemplate(ItemRecord item, ItemSparseRecord sparse)
|
||||
{
|
||||
BasicData = item;
|
||||
ExtendedData = sparse;
|
||||
|
||||
Specializations[0] = new BitArray((int)Class.Max * PlayerConst.MaxSpecializations);
|
||||
Specializations[1] = new BitArray((int)Class.Max * PlayerConst.MaxSpecializations);
|
||||
Specializations[2] = new BitArray((int)Class.Max * PlayerConst.MaxSpecializations);
|
||||
}
|
||||
|
||||
public string GetName(LocaleConstant locale = SharedConst.DefaultLocale)
|
||||
{
|
||||
return ExtendedData.Name[locale];
|
||||
}
|
||||
|
||||
public bool CanChangeEquipStateInCombat()
|
||||
{
|
||||
switch (GetInventoryType())
|
||||
{
|
||||
case InventoryType.Relic:
|
||||
case InventoryType.Shield:
|
||||
case InventoryType.Holdable:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (GetClass())
|
||||
{
|
||||
case ItemClass.Weapon:
|
||||
case ItemClass.Projectile:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public SkillType GetSkill()
|
||||
{
|
||||
SkillType[] item_weapon_skills =
|
||||
{
|
||||
SkillType.Axes, SkillType.TwoHandedAxes, SkillType.Bows, SkillType.Guns, SkillType.Maces,
|
||||
SkillType.TwoHandedMaces, SkillType.Polearms, SkillType.Swords, SkillType.TwoHandedSwords, SkillType.Warglaives,
|
||||
SkillType.Staves, 0, 0, SkillType.FistWeapons, 0,
|
||||
SkillType.Daggers, 0, 0, SkillType.Crossbows, SkillType.Wands,
|
||||
SkillType.Fishing
|
||||
};
|
||||
|
||||
SkillType[] item_armor_skills =
|
||||
{
|
||||
0, SkillType.Cloth, SkillType.Leather, SkillType.Mail, SkillType.PlateMail, 0, SkillType.Shield, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
|
||||
switch (GetClass())
|
||||
{
|
||||
case ItemClass.Weapon:
|
||||
if (GetSubClass() >= (int)ItemSubClassWeapon.Max)
|
||||
return 0;
|
||||
else
|
||||
return item_weapon_skills[GetSubClass()];
|
||||
|
||||
case ItemClass.Armor:
|
||||
if (GetSubClass() >= (int)ItemSubClassArmor.Max)
|
||||
return 0;
|
||||
else
|
||||
return item_armor_skills[GetSubClass()];
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public uint GetArmor(uint itemLevel)
|
||||
{
|
||||
ItemQuality quality = GetQuality() != ItemQuality.Heirloom ? GetQuality() : ItemQuality.Rare;
|
||||
if (quality > ItemQuality.Artifact)
|
||||
return 0;
|
||||
|
||||
// all items but shields
|
||||
if (GetClass() != ItemClass.Armor || GetSubClass() != (uint)ItemSubClassArmor.Shield)
|
||||
{
|
||||
ItemArmorQualityRecord armorQuality = CliDB.ItemArmorQualityStorage.LookupByKey(itemLevel);
|
||||
ItemArmorTotalRecord armorTotal = CliDB.ItemArmorTotalStorage.LookupByKey(itemLevel);
|
||||
if (armorQuality == null || armorTotal == null)
|
||||
return 0;
|
||||
|
||||
InventoryType inventoryType = GetInventoryType();
|
||||
if (inventoryType == InventoryType.Robe)
|
||||
inventoryType = InventoryType.Chest;
|
||||
|
||||
ArmorLocationRecord location = CliDB.ArmorLocationStorage.LookupByKey(inventoryType);
|
||||
if (location == null)
|
||||
return 0;
|
||||
|
||||
if (GetSubClass() < (uint)ItemSubClassArmor.Cloth || GetSubClass() > (uint)ItemSubClassArmor.Plate)
|
||||
return 0;
|
||||
|
||||
return (uint)(armorQuality.QualityMod[(int)quality] * armorTotal.Value[GetSubClass() - 1] * location.Modifier[GetSubClass() - 1] + 0.5f);
|
||||
}
|
||||
|
||||
// shields
|
||||
ItemArmorShieldRecord shield = CliDB.ItemArmorShieldStorage.LookupByKey(itemLevel);
|
||||
if (shield == null)
|
||||
return 0;
|
||||
|
||||
return (uint)(shield.Quality[(int)quality] + 0.5f);
|
||||
}
|
||||
|
||||
public void GetDamage(uint itemLevel, out float minDamage, out float maxDamage)
|
||||
{
|
||||
minDamage = maxDamage = 0.0f;
|
||||
ItemQuality quality = GetQuality() != ItemQuality.Heirloom ? GetQuality() : ItemQuality.Rare;
|
||||
if (GetClass() != ItemClass.Weapon || quality > ItemQuality.Artifact)
|
||||
return;
|
||||
|
||||
// get the right store here
|
||||
if (GetInventoryType() > InventoryType.RangedRight)
|
||||
return;
|
||||
|
||||
float dps = 0.0f;
|
||||
switch (GetInventoryType())
|
||||
{
|
||||
case InventoryType.Ammo:
|
||||
dps = CliDB.ItemDamageAmmoStorage.LookupByKey(itemLevel).DPS[(int)quality];
|
||||
break;
|
||||
case InventoryType.Weapon2Hand:
|
||||
if (GetFlags2().HasAnyFlag(ItemFlags2.CasterWeapon))
|
||||
dps = CliDB.ItemDamageTwoHandCasterStorage.LookupByKey(itemLevel).DPS[(int)quality];
|
||||
else
|
||||
dps = CliDB.ItemDamageTwoHandStorage.LookupByKey(itemLevel).DPS[(int)quality];
|
||||
break;
|
||||
case InventoryType.Ranged:
|
||||
case InventoryType.Thrown:
|
||||
case InventoryType.RangedRight:
|
||||
switch ((ItemSubClassWeapon)GetSubClass())
|
||||
{
|
||||
case ItemSubClassWeapon.Wand:
|
||||
dps = CliDB.ItemDamageOneHandCasterStorage.LookupByKey(itemLevel).DPS[(int)quality];
|
||||
break;
|
||||
case ItemSubClassWeapon.Bow:
|
||||
case ItemSubClassWeapon.Gun:
|
||||
case ItemSubClassWeapon.Crossbow:
|
||||
if (GetFlags2().HasAnyFlag(ItemFlags2.CasterWeapon))
|
||||
dps = CliDB.ItemDamageTwoHandCasterStorage.LookupByKey(itemLevel).DPS[(int)quality];
|
||||
else
|
||||
dps = CliDB.ItemDamageTwoHandStorage.LookupByKey(itemLevel).DPS[(int)quality];
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case InventoryType.Weapon:
|
||||
case InventoryType.WeaponMainhand:
|
||||
case InventoryType.WeaponOffhand:
|
||||
if (GetFlags2().HasAnyFlag(ItemFlags2.CasterWeapon))
|
||||
dps = CliDB.ItemDamageOneHandCasterStorage.LookupByKey(itemLevel).DPS[(int)quality];
|
||||
else
|
||||
dps = CliDB.ItemDamageOneHandStorage.LookupByKey(itemLevel).DPS[(int)quality];
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
float avgDamage = dps * GetDelay() * 0.001f;
|
||||
minDamage = (GetStatScalingFactor() * -0.5f + 1.0f) * avgDamage;
|
||||
maxDamage = (float)Math.Floor(avgDamage * (GetStatScalingFactor() * 0.5f + 1.0f) + 0.5f);
|
||||
}
|
||||
|
||||
public bool IsUsableByLootSpecialization(Player player, bool alwaysAllowBoundToAccount)
|
||||
{
|
||||
if (GetFlags().HasAnyFlag(ItemFlags.IsBoundToAccount) && alwaysAllowBoundToAccount)
|
||||
return true;
|
||||
|
||||
uint spec = player.GetUInt32Value(PlayerFields.LootSpecId);
|
||||
if (spec == 0)
|
||||
spec = player.GetUInt32Value(PlayerFields.CurrentSpecId);
|
||||
if (spec == 0)
|
||||
spec = player.GetDefaultSpecId();
|
||||
|
||||
ChrSpecializationRecord chrSpecialization = CliDB.ChrSpecializationStorage.LookupByKey(spec);
|
||||
if (chrSpecialization == null)
|
||||
return false;
|
||||
|
||||
int levelIndex = 0;
|
||||
if (player.getLevel() >= 110)
|
||||
levelIndex = 2;
|
||||
else if (player.getLevel() > 40)
|
||||
levelIndex = 1;
|
||||
|
||||
return Specializations[levelIndex].Get(CalculateItemSpecBit(chrSpecialization));
|
||||
}
|
||||
|
||||
public static int CalculateItemSpecBit(ChrSpecializationRecord spec)
|
||||
{
|
||||
return (int)((spec.ClassID - 1) * PlayerConst.MaxSpecializations + spec.OrderIndex);
|
||||
}
|
||||
|
||||
public uint GetId() { return BasicData.Id; }
|
||||
public ItemClass GetClass() { return (ItemClass)BasicData.Class; }
|
||||
public uint GetSubClass() { return BasicData.SubClass; }
|
||||
public ItemQuality GetQuality() { return (ItemQuality)ExtendedData.Quality; }
|
||||
public ItemFlags GetFlags() { return (ItemFlags)ExtendedData.Flags[0]; }
|
||||
public ItemFlags2 GetFlags2() { return (ItemFlags2)ExtendedData.Flags[1]; }
|
||||
public ItemFlags3 GetFlags3() { return (ItemFlags3)ExtendedData.Flags[2]; }
|
||||
public float GetUnk1() { return ExtendedData.Unk1; }
|
||||
public float GetUnk2() { return ExtendedData.Unk2; }
|
||||
public uint GetBuyCount() { return Math.Max(ExtendedData.BuyCount, 1u); }
|
||||
public uint GetBuyPrice() { return ExtendedData.BuyPrice; }
|
||||
public uint GetSellPrice() { return ExtendedData.SellPrice; }
|
||||
public InventoryType GetInventoryType() { return (InventoryType)ExtendedData.inventoryType; }
|
||||
public int GetAllowableClass() { return ExtendedData.AllowableClass; }
|
||||
public int GetAllowableRace() { return ExtendedData.AllowableRace; }
|
||||
public uint GetBaseItemLevel() { return ExtendedData.ItemLevel; }
|
||||
public int GetBaseRequiredLevel() { return ExtendedData.RequiredLevel; }
|
||||
public uint GetRequiredSkill() { return ExtendedData.RequiredSkill; }
|
||||
public uint GetRequiredSkillRank() { return ExtendedData.RequiredSkillRank; }
|
||||
public uint GetRequiredSpell() { return ExtendedData.RequiredSpell; }
|
||||
public uint GetRequiredReputationFaction() { return ExtendedData.RequiredReputationFaction; }
|
||||
public uint GetRequiredReputationRank() { return ExtendedData.RequiredReputationRank; }
|
||||
public uint GetMaxCount() { return ExtendedData.MaxCount; }
|
||||
public uint GetContainerSlots() { return ExtendedData.ContainerSlots; }
|
||||
public int GetItemStatType(uint index)
|
||||
{
|
||||
Contract.Assert(index < ItemConst.MaxStats);
|
||||
return ExtendedData.ItemStatType[index];
|
||||
}
|
||||
public int GetItemStatValue(uint index)
|
||||
{
|
||||
Contract.Assert(index < ItemConst.MaxStats);
|
||||
return ExtendedData.ItemStatValue[index];
|
||||
}
|
||||
public int GetItemStatAllocation(uint index)
|
||||
{
|
||||
Contract.Assert(index < ItemConst.MaxStats);
|
||||
return ExtendedData.ItemStatAllocation[index];
|
||||
}
|
||||
public float GetItemStatSocketCostMultiplier(uint index)
|
||||
{
|
||||
Contract.Assert(index < ItemConst.MaxStats);
|
||||
return ExtendedData.ItemStatSocketCostMultiplier[index];
|
||||
}
|
||||
public uint GetScalingStatDistribution() { return ExtendedData.ScalingStatDistribution; }
|
||||
public uint GetDamageType() { return ExtendedData.DamageType; }
|
||||
public uint GetDelay() { return ExtendedData.Delay; }
|
||||
public float GetRangedModRange() { return ExtendedData.RangedModRange; }
|
||||
public ItemBondingType GetBonding() { return (ItemBondingType)ExtendedData.Bonding; }
|
||||
public uint GetPageText() { return ExtendedData.PageText; }
|
||||
public uint GetStartQuest() { return ExtendedData.StartQuest; }
|
||||
public uint GetLockID() { return ExtendedData.LockID; }
|
||||
public uint GetRandomProperty() { return ExtendedData.RandomProperty; }
|
||||
public uint GetRandomSuffix() { return ExtendedData.RandomSuffix; }
|
||||
public uint GetItemSet() { return ExtendedData.ItemSet; }
|
||||
public uint GetArea() { return ExtendedData.Area; }
|
||||
public uint GetMap() { return ExtendedData.Map; }
|
||||
public BagFamilyMask GetBagFamily() { return (BagFamilyMask)ExtendedData.BagFamily; }
|
||||
public uint GetTotemCategory() { return ExtendedData.TotemCategory; }
|
||||
public SocketColor GetSocketColor(uint index)
|
||||
{
|
||||
Contract.Assert(index < ItemConst.MaxGemSockets);
|
||||
return (SocketColor)ExtendedData.SocketColor[index];
|
||||
}
|
||||
public uint GetSocketBonus() { return ExtendedData.SocketBonus; }
|
||||
public uint GetGemProperties() { return ExtendedData.GemProperties; }
|
||||
public float GetArmorDamageModifier() { return ExtendedData.ArmorDamageModifier; }
|
||||
public uint GetDuration() { return ExtendedData.Duration; }
|
||||
public uint GetItemLimitCategory() { return ExtendedData.ItemLimitCategory; }
|
||||
public HolidayIds GetHolidayID() { return (HolidayIds)ExtendedData.HolidayID; }
|
||||
public float GetStatScalingFactor() { return ExtendedData.StatScalingFactor; }
|
||||
public byte GetArtifactID() { return ExtendedData.ArtifactID; }
|
||||
|
||||
public bool IsCurrencyToken() { return (GetBagFamily() & BagFamilyMask.CurrencyTokens) != 0; }
|
||||
|
||||
public uint GetMaxStackSize()
|
||||
{
|
||||
return (ExtendedData.Stackable == 2147483647 || ExtendedData.Stackable <= 0) ? (0x7FFFFFFF - 1) : ExtendedData.Stackable;
|
||||
}
|
||||
|
||||
public bool IsPotion() { return GetClass() == ItemClass.Consumable && GetSubClass() == (uint)ItemSubClassConsumable.Potion; }
|
||||
public bool IsVellum() { return GetClass() == ItemClass.TradeGoods && GetSubClass() == (uint)ItemSubClassTradeGoods.Enchantment; }
|
||||
public bool IsConjuredConsumable() { return GetClass() == ItemClass.Consumable && GetFlags().HasAnyFlag(ItemFlags.Conjured); }
|
||||
public bool IsCraftingReagent() { return GetFlags2().HasAnyFlag(ItemFlags2.UsedInATradeskill); }
|
||||
|
||||
public bool IsRangedWeapon()
|
||||
{
|
||||
return GetClass() == ItemClass.Weapon || GetSubClass() == (uint)ItemSubClassWeapon.Bow ||
|
||||
GetSubClass() == (uint)ItemSubClassWeapon.Gun || GetSubClass() == (uint)ItemSubClassWeapon.Crossbow;
|
||||
}
|
||||
|
||||
public uint MaxDurability;
|
||||
public List<ItemEffectRecord> Effects = new List<ItemEffectRecord>();
|
||||
|
||||
// extra fields, not part of db2 files
|
||||
public uint ScriptId;
|
||||
public uint DisenchantID;
|
||||
public uint RequiredDisenchantSkill;
|
||||
public uint FoodType;
|
||||
public uint MinMoneyLoot;
|
||||
public uint MaxMoneyLoot;
|
||||
public ItemFlagsCustom FlagsCu;
|
||||
public float SpellPPMRate;
|
||||
public BitArray[] Specializations = new BitArray[3];
|
||||
public uint ItemSpecClassMask;
|
||||
|
||||
protected ItemRecord BasicData;
|
||||
protected ItemSparseRecord ExtendedData;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user