Core/Transmog: Charge money for transmogrification

This commit is contained in:
Nay
2012-08-02 01:16:45 +01:00
parent e909fd036b
commit edee3732c5
8 changed files with 250 additions and 10 deletions

View File

@@ -110,9 +110,15 @@ DBCStorage <GtRegenMPPerSptEntry> sGtRegenMPPerSptStore(GtRegenMPPerSptf
DBCStorage <HolidaysEntry> sHolidaysStore(Holidaysfmt);
DBCStorage <ImportPriceArmorEntry> sImportPriceArmorStore(ImportPriceArmorfmt);
DBCStorage <ImportPriceQualityEntry> sImportPriceQualityStore(ImportPriceQualityfmt);
DBCStorage <ImportPriceShieldEntry> sImportPriceShieldStore(ImportPriceShieldfmt);
DBCStorage <ImportPriceWeaponEntry> sImportPriceWeaponStore(ImportPriceWeaponfmt);
DBCStorage <ItemPriceBaseEntry> sItemPriceBaseStore(ItemPriceBasefmt);
DBCStorage <ItemArmorQualityEntry> sItemArmorQualityStore(ItemArmorQualityfmt);
DBCStorage <ItemArmorShieldEntry> sItemArmorShieldStore(ItemArmorShieldfmt);
DBCStorage <ItemArmorTotalEntry> sItemArmorTotalStore(ItemArmorTotalfmt);
DBCStorage <ItemClassEntry> sItemClassStore(ItemClassfmt);
DBCStorage <ItemBagFamilyEntry> sItemBagFamilyStore(ItemBagFamilyfmt);
DBCStorage <ItemDamageEntry> sItemDamageAmmoStore(ItemDamagefmt);
DBCStorage <ItemDamageEntry> sItemDamageOneHandStore(ItemDamagefmt);

View File

@@ -121,9 +121,15 @@ extern DBCStorage <GtRegenHPPerSptEntry> sGtRegenHPPerSptStore;
extern DBCStorage <gtOCTHpPerStaminaEntry> sGtOCTHpPerStaminaStore;
extern DBCStorage <GtRegenMPPerSptEntry> sGtRegenMPPerSptStore;
extern DBCStorage <HolidaysEntry> sHolidaysStore;
extern DBCStorage <ImportPriceArmorEntry> sImportPriceArmorStore;
extern DBCStorage <ImportPriceQualityEntry> sImportPriceQualityStore;
extern DBCStorage <ImportPriceShieldEntry> sImportPriceShieldStore;
extern DBCStorage <ImportPriceWeaponEntry> sImportPriceWeaponStore;
extern DBCStorage <ItemPriceBaseEntry> sItemPriceBaseStore;
extern DBCStorage <ItemArmorQualityEntry> sItemArmorQualityStore;
extern DBCStorage <ItemArmorShieldEntry> sItemArmorShieldStore;
extern DBCStorage <ItemArmorTotalEntry> sItemArmorTotalStore;
extern DBCStorage <ItemClassEntry> sItemClassStore;
extern DBCStorage <ItemBagFamilyEntry> sItemBagFamilyStore;
extern DBCStorage <ItemDamageEntry> sItemDamageAmmoStore;
extern DBCStorage <ItemDamageEntry> sItemDamageOneHandStore;

View File

@@ -1153,6 +1153,45 @@ struct HolidaysEntry
//uint32 flags; // 54 m_flags (0 = Darkmoon Faire, Fishing Contest and Wotlk Launch, rest is 1)
};
// ImportPriceArmor.dbc
struct ImportPriceArmorEntry
{
uint32 InventoryType; // 1 Id/InventoryType
float ClothFactor; // 2 Price factor cloth
float LeatherFactor; // 3 Price factor leather
float MailFactor; // 4 Price factor mail
float PlateFactor; // 5 Price factor plate
};
// ImportPriceQuality.dbc
struct ImportPriceQualityEntry
{
uint32 QualityId; // 1 Quality Id (+1?)
float Factor; // 2 Price factor
};
// ImportPriceShield.dbc
struct ImportPriceShieldEntry
{
uint32 Id; // 1 Unk id (only 1 and 2)
float Factor; // 2 Price factor
};
// ImportPriceWeapon.dbc
struct ImportPriceWeaponEntry
{
uint32 Id; // 1 Unk id (mainhand - 0, offhand - 1, weapon - 2, 2hweapon - 3, ranged/rangedright/relic - 4)
float Factor; // 2 Price factor
};
// ItemPriceBase.dbc
struct ItemPriceBaseEntry
{
uint32 ItemLevel; // 2 Item level (1 - 1000)
float ArmorFactor; // 3 Price factor for armor
float WeaponFactor; // 4 Price factor for weapons
};
// common struct for:
// ItemDamageAmmo.dbc
// ItemDamageOneHand.dbc
@@ -1190,6 +1229,16 @@ struct ItemArmorTotalEntry
float Value[4]; // 2-5 multiplier for armor types (cloth...plate)
};
// ItemClass.dbc
struct ItemClassEntry
{
uint32 Class; // 1 item class id
//uint32 Unk; // 2 unk
//uint32 IsWeapon; // 3 1 for weapon, 0 for everything else
float PriceFactor; // 4 used to calculate certain prices
//char* Name; // class name
};
struct ItemBagFamilyEntry
{
uint32 ID; // 0

View File

@@ -19,6 +19,9 @@
#ifndef TRINITY_DBCSFRM_H
#define TRINITY_DBCSFRM_H
// x - skip<uint32>, X - skip<uint8>, s - char*, f - float, i - uint32, b - uint8, d - index (not included)
// n - index (included), l - bool, p - field present in sql dbc, a - field absent in sql dbc
const char Achievementfmt[]="niixsxiixixxii";
//const std::string CustomAchievementfmt="pppaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaapapaaaaaaaaaaaaaaaaaapp";
//const std::string CustomAchievementIndex = "ID";
@@ -74,12 +77,17 @@ const char GtOCTRegenHPfmt[]="f";
//const char GtOCTRegenMPfmt[]="f";
const char GtRegenHPPerSptfmt[]="f";
const char GtRegenMPPerSptfmt[]="xf";
const char Holidaysfmt[]="niiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiixxsiix";
const char ImportPriceArmorfmt[]="nffff";
const char ImportPriceQualityfmt[]="nf";
const char ImportPriceShieldfmt[]="nf";
const char ImportPriceWeaponfmt[]="nf";
const char ItemPriceBasefmt[]="diff";
const char ItemBagFamilyfmt[]="nx";
const char ItemArmorQualityfmt[]="nfffffffi";
const char ItemArmorShieldfmt[]="nifffffff";
const char ItemArmorTotalfmt[]="niffff";
const char ItemClassfmt[]="dixxfs";
const char ItemDamagefmt[]="nfffffffi";
const char ItemDisenchantLootfmt[]="niiiiii";
//const char ItemDisplayTemplateEntryfmt[]="nxxxxxxxxxxixxxxxxxxxxx";

View File

@@ -1275,7 +1275,7 @@ bool Item::CanTransmogrifyItemWithItem(Item const* transmogrified, Item const* t
proto1->InventoryType == INVTYPE_QUIVER)
return false;
if (proto1->SubClass != proto2->SubClass && (proto1->Class != ITEM_CLASS_WEAPON || !transmogrified->IsRangedWeapon() || !transmogrifier->IsRangedWeapon()))
if (proto1->SubClass != proto2->SubClass && (proto1->Class != ITEM_CLASS_WEAPON || !proto2->IsRangedWeapon() || !proto1->IsRangedWeapon()))
return false;
if (proto1->InventoryType != proto2->InventoryType &&
@@ -1290,20 +1290,171 @@ bool Item::HasStats() const
if (GetItemRandomPropertyId() != 0)
return true;
ItemTemplate const* proto = GetTemplate();
for (uint8 i = 0; i < MAX_ITEM_PROTO_STATS; ++i)
if (GetTemplate()->ItemStat[i].ItemStatValue != 0)
if (proto->ItemStat[i].ItemStatValue != 0)
return true;
return false;
}
bool Item::IsRangedWeapon() const
// used by mail items, transmog cost, stationeryinfo and others
uint32 Item::GetSellPrice(bool& normalSellPrice) const
{
ItemTemplate const* proto = GetTemplate();
if (proto && proto->Class == ITEM_CLASS_WEAPON)
return proto->SubClass == ITEM_SUBCLASS_WEAPON_BOW ||
proto->SubClass == ITEM_SUBCLASS_WEAPON_GUN ||
proto->SubClass == ITEM_SUBCLASS_WEAPON_CROSSBOW;
normalSellPrice = true;
return false;
if (proto->Flags2 & ITEM_FLAGS_EXTRA_HAS_NORMAL_PRICE)
{
return proto->BuyPrice;
}
else
{
ImportPriceQualityEntry const* qualityPrice = sImportPriceQualityStore.LookupEntry(proto->Quality + 1);
ItemPriceBaseEntry const* basePrice = sItemPriceBaseStore.LookupEntry(proto->ItemLevel);
if (!qualityPrice || !basePrice)
return 0;
float qualityFactor = qualityPrice->Factor;
float baseFactor = 0.0f;
uint32 inventoryType = proto->InventoryType;
if (inventoryType == INVTYPE_WEAPON ||
inventoryType == INVTYPE_2HWEAPON ||
inventoryType == INVTYPE_WEAPONMAINHAND ||
inventoryType == INVTYPE_WEAPONOFFHAND ||
inventoryType == INVTYPE_RANGED ||
inventoryType == INVTYPE_THROWN ||
inventoryType == INVTYPE_RANGEDRIGHT)
baseFactor = basePrice->WeaponFactor;
else
baseFactor = basePrice->ArmorFactor;
if (inventoryType == INVTYPE_ROBE)
inventoryType = INVTYPE_CHEST;
float typeFactor = 0.0f;
uint8 wepType = -1;
switch (inventoryType)
{
case INVTYPE_HEAD:
case INVTYPE_SHOULDERS:
case INVTYPE_CHEST:
case INVTYPE_WAIST:
case INVTYPE_LEGS:
case INVTYPE_FEET:
case INVTYPE_WRISTS:
case INVTYPE_HANDS:
case INVTYPE_CLOAK:
{
ImportPriceArmorEntry const* armorPrice = sImportPriceArmorStore.LookupEntry(inventoryType);
if (!armorPrice)
return 0;
switch (proto->SubClass)
{
case ITEM_SUBCLASS_ARMOR_MISCELLANEOUS:
case ITEM_SUBCLASS_ARMOR_CLOTH:
{
typeFactor = armorPrice->ClothFactor;
break;
}
case ITEM_SUBCLASS_ARMOR_LEATHER:
{
typeFactor = armorPrice->ClothFactor;
break;
}
case ITEM_SUBCLASS_ARMOR_MAIL:
{
typeFactor = armorPrice->ClothFactor;
break;
}
case ITEM_SUBCLASS_ARMOR_PLATE:
{
typeFactor = armorPrice->ClothFactor;
break;
}
default:
{
return 0;
}
}
break;
}
case INVTYPE_SHIELD:
{
ImportPriceShieldEntry const* shieldPrice = sImportPriceShieldStore.LookupEntry(1); // it only has two rows, it's unclear which is the one used
if (!shieldPrice)
return 0;
typeFactor = shieldPrice->Factor;
break;
}
case INVTYPE_WEAPONMAINHAND:
wepType = 0; // unk enum, fall back
case INVTYPE_WEAPONOFFHAND:
wepType = 1; // unk enum, fall back
case INVTYPE_WEAPON:
wepType = 2; // unk enum, fall back
case INVTYPE_2HWEAPON:
wepType = 3; // unk enum, fall back
case INVTYPE_RANGED:
case INVTYPE_RANGEDRIGHT:
case INVTYPE_RELIC:
{
wepType = 4; // unk enum
ImportPriceWeaponEntry const* weaponPrice = sImportPriceWeaponStore.LookupEntry(wepType + 1); // it only has two rows, it's unclear which is the one used
if (!weaponPrice)
return 0;
typeFactor = weaponPrice->Factor;
break;
}
default:
return proto->BuyPrice;
}
normalSellPrice = false;
return (uint32)(qualityFactor * proto->Unk430_2 * proto->Unk430_1 * typeFactor * baseFactor);
}
}
uint32 Item::GetTransmogrifyCost() const
{
ItemTemplate const* proto = GetTemplate();
uint32 cost = 0;
if (proto->Flags2 & ITEM_FLAGS_EXTRA_HAS_NORMAL_PRICE)
cost = proto->SellPrice;
else
{
bool normalPrice;
cost = GetSellPrice(normalPrice);
if (!normalPrice)
{
if (proto->BuyCount <= 1)
{
ItemClassEntry const* classEntry = sItemClassStore.LookupEntry(proto->Class);
if (classEntry)
cost *= classEntry->PriceFactor;
else
cost = 0;
}
else
cost /= 4 * proto->BuyCount;
}
else
cost = proto->SellPrice;
}
if (cost < 10000)
cost = 10000;
return cost;
}

View File

@@ -323,7 +323,7 @@ class Item : public Object
bool IsWeaponVellum() const { return GetTemplate()->IsWeaponVellum(); }
bool IsArmorVellum() const { return GetTemplate()->IsArmorVellum(); }
bool IsConjuredConsumable() const { return GetTemplate()->IsConjuredConsumable(); }
bool IsRangedWeapon() const;
bool IsRangedWeapon() const { return GetTemplate()->IsRangedWeapon(); }
// Item Refund system
void SetNotRefundable(Player* owner, bool changestate = true, SQLTransaction* trans = NULL);
@@ -350,6 +350,7 @@ class Item : public Object
bool CanBeTransmogrified() const;
bool CanTransmogrify() const;
static bool CanTransmogrifyItemWithItem(Item const* transmogrified, Item const* transmogrifier);
uint32 GetTransmogrifyCost() const;
uint32 GetVisibleEntry() const
{
@@ -358,6 +359,8 @@ class Item : public Object
return GetEntry();
}
uint32 GetSellPrice(bool& success) const;
private:
std::string m_text;
uint8 m_slot;

View File

@@ -196,6 +196,7 @@ enum ItemFlagsExtra
ITEM_FLAGS_EXTRA_EXT_COST_REQUIRES_GOLD = 0x00000004, // when item uses extended cost, gold is also required
ITEM_FLAGS_EXTRA_NEED_ROLL_DISABLED = 0x00000100,
ITEM_FLAGS_EXTRA_CASTER_WEAPON = 0x00000200,
ITEM_FLAGS_EXTRA_HAS_NORMAL_PRICE = 0x00004000,
ITEM_FLAGS_EXTRA_BNET_ACCOUNT_BOUND = 0x00020000,
ITEM_FLAGS_EXTRA_CANNOT_BE_TRANSMOG = 0x00200000,
ITEM_FLAGS_EXTRA_CANNOT_TRANSMOG = 0x00400000,
@@ -740,6 +741,14 @@ struct ItemTemplate
bool IsWeaponVellum() const { return Class == ITEM_CLASS_TRADE_GOODS && SubClass == ITEM_SUBCLASS_WEAPON_ENCHANTMENT; }
bool IsArmorVellum() const { return Class == ITEM_CLASS_TRADE_GOODS && SubClass == ITEM_SUBCLASS_ITEM_ENCHANTMENT; }
bool IsConjuredConsumable() const { return Class == ITEM_CLASS_CONSUMABLE && (Flags & ITEM_PROTO_FLAG_CONJURED); }
bool IsRangedWeapon() const
{
return Class == ITEM_CLASS_WEAPON ||
SubClass == ITEM_SUBCLASS_WEAPON_BOW ||
SubClass == ITEM_SUBCLASS_WEAPON_GUN ||
SubClass == ITEM_SUBCLASS_WEAPON_CROSSBOW;
}
};
// Benchmarked: Faster than std::map (insert/find)

View File

@@ -1534,6 +1534,7 @@ void WorldSession::HandleTransmogrifyItems(WorldPacket& recvData)
return;
}
int32 cost = 0;
for (uint8 i = 0; i < count; ++i)
{
// slot of the transmogrified item
@@ -1615,7 +1616,14 @@ void WorldSession::HandleTransmogrifyItems(WorldPacket& recvData)
itemTransmogrifier->SetOwnerGUID(player->GetGUID());
itemTransmogrifier->SetNotRefundable(player);
itemTransmogrifier->ClearSoulboundTradeable(player);
cost += itemTransmogrified->GetTransmogrifyCost();
}
// trusting the client, if it got here it has to have enough money
// ... unless client was modified
if (cost) // 0 cost if reverting look
player->ModifyMoney(-cost);
}
delete[] itemGuids;