[10641] Fixed use item dynamic/item proto flags.

* List its independelty. Each from this 2 fields have own flags. Cleanup lists.
* Not copy proto flags to item flags update field. This fix heroic item versions
  show in client in result mixed use ITEM_DYNFLAG_WRAPPED (0x8) with ITEM_FLAG_HEROIC (0x8)
* Update uses to proto case use for some cases where before wrongly has been used item dyn.flags
* For ITEM_DYNFLAG_UNLOCKED (0x4) set for item at unlock and check for prevent re-unlocking.
  This mostly for future case when will be implemented partly loting items support.
* For ITEM_FLAG_LOOTABLE (0x4) check loot absent or conflicting setting with containers/casted at use items.
  Report wrong cases art loading.
* Better check related loot tables content using ITEM_FLAG_PROSPECTABLE and ITEM_FLAG_MILLABLE
This commit is contained in:
VladimirMangos 2010-10-24 20:31:50 +04:00
parent d53fe93e9d
commit 46d740bbf4
17 changed files with 208 additions and 103 deletions

View file

@ -254,7 +254,7 @@ void WorldSession::HandleAuctionSellItem( WorldPacket & recv_data )
return;
}
if (it->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_CONJURED) || it->GetUInt32Value(ITEM_FIELD_DURATION))
if ((it->GetProto()->Flags & ITEM_FLAG_CONJURED) || it->GetUInt32Value(ITEM_FIELD_DURATION))
{
SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_INTERNAL_ERROR);
return;

View file

@ -74,7 +74,6 @@ bool Bag::Create(uint32 guidlow, uint32 itemid, Player const* owner)
SetUInt32Value(ITEM_FIELD_MAXDURABILITY, itemProto->MaxDurability);
SetUInt32Value(ITEM_FIELD_DURABILITY, itemProto->MaxDurability);
SetUInt32Value(ITEM_FIELD_FLAGS, itemProto->Flags);
SetUInt32Value(ITEM_FIELD_STACK_COUNT, 1);
// Setting the number of Slots the Container has

View file

@ -52,7 +52,7 @@ void Roll::CalculateCommonVoteMask(uint32 max_enchanting_skill)
ItemPrototype const* itemProto = ObjectMgr::GetItemPrototype(itemid);
if (itemProto->Flags2 & ITEM_FLAGS2_NEED_ROLL_DISABLED)
if (itemProto->Flags2 & ITEM_FLAG2_NEED_ROLL_DISABLED)
m_commonVoteMask = RollVoteMask(m_commonVoteMask & ~ROLL_VOTE_MASK_NEED);
if (!itemProto->DisenchantID || uint32(itemProto->RequiredDisenchantSkill) > max_enchanting_skill)

View file

@ -266,7 +266,6 @@ bool Item::Create( uint32 guidlow, uint32 itemid, Player const* owner)
for(int i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
SetSpellCharges(i,itemProto->Spells[i].SpellCharges);
SetUInt32Value(ITEM_FIELD_FLAGS, itemProto->Flags);
SetUInt32Value(ITEM_FIELD_DURATION, itemProto->Duration);
return true;
@ -319,13 +318,13 @@ void Item::SaveToDB()
CharacterDatabase.Execute( ss.str().c_str() );
if(HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPED))
if (HasFlag(ITEM_FIELD_FLAGS, ITEM_DYNFLAG_WRAPPED))
CharacterDatabase.PExecute("UPDATE character_gifts SET guid = '%u' WHERE item_guid = '%u'", GUID_LOPART(GetOwnerGUID()),GetGUIDLow());
} break;
case ITEM_REMOVED:
{
CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid = '%u'", guid);
if(HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPED))
if (HasFlag(ITEM_FIELD_FLAGS, ITEM_DYNFLAG_WRAPPED))
CharacterDatabase.PExecute("DELETE FROM character_gifts WHERE item_guid = '%u'", GetGUIDLow());
delete this;
return;
@ -401,7 +400,7 @@ bool Item::LoadFromDB(uint32 guidLow, uint64 owner_guid, QueryResult *result)
// Remove bind flag for items vs NO_BIND set
if (IsSoulBound() && proto->Bonding == NO_BIND)
{
ApplyModFlag(ITEM_FIELD_FLAGS,ITEM_FLAGS_BINDED, false);
ApplyModFlag(ITEM_FIELD_FLAGS, ITEM_DYNFLAG_BINDED, false);
need_save = true;
}
@ -419,6 +418,20 @@ bool Item::LoadFromDB(uint32 guidLow, uint64 owner_guid, QueryResult *result)
need_save = true;
}
// set correct wrapped state
if (HasFlag(ITEM_FIELD_FLAGS, ITEM_DYNFLAG_WRAPPED))
{
// wrapped item must be wrapper (used version that not stackable)
if (!(proto->Flags & ITEM_FLAG_WRAPPER) || GetMaxStackCount() > 1)
{
RemoveFlag(ITEM_FIELD_FLAGS, ITEM_DYNFLAG_WRAPPED);
need_save = true;
// also cleanup for sure gift table
CharacterDatabase.PExecute("DELETE FROM character_gifts WHERE item_guid = '%u'", GetGUIDLow());
}
}
if (need_save) // normal item changed state set not work at loading
{
std::ostringstream ss;

View file

@ -202,6 +202,44 @@ enum ItemUpdateState
ITEM_REMOVED = 3
};
// masks for ITEM_FIELD_FLAGS field
enum ItemDynFlags
{
ITEM_DYNFLAG_BINDED = 0x00000001, // set in game at binding
ITEM_DYNFLAG_UNK1 = 0x00000002,
ITEM_DYNFLAG_UNLOCKED = 0x00000004, // have meaning only for item with proto->LockId, if not set show as "Locked, req. lockpicking N"
ITEM_DYNFLAG_WRAPPED = 0x00000008, // mark item as wrapped into wrapper container
ITEM_DYNFLAG_UNK4 = 0x00000010, // can't repeat old note: appears red icon (like when item durability==0)
ITEM_DYNFLAG_UNK5 = 0x00000020,
ITEM_DYNFLAG_UNK6 = 0x00000040, // ? old note: usable
ITEM_DYNFLAG_UNK7 = 0x00000080,
ITEM_DYNFLAG_UNK8 = 0x00000100,
ITEM_DYNFLAG_READBLE = 0x00000200, // can be open for read, it or item proto pagetText make show "Right click to read"
ITEM_DYNFLAG_UNK10 = 0x00000400,
ITEM_DYNFLAG_UNK11 = 0x00000800,
ITEM_DYNFLAG_UNK12 = 0x00001000,
ITEM_DYNFLAG_UNK13 = 0x00002000,
ITEM_DYNFLAG_UNK14 = 0x00004000,
ITEM_DYNFLAG_UNK15 = 0x00008000,
ITEM_DYNFLAG_UNK16 = 0x00010000,
ITEM_DYNFLAG_UNK17 = 0x00020000,
ITEM_DYNFLAG_UNK18 = 0x00040000,
ITEM_DYNFLAG_UNK19 = 0x00080000,
ITEM_DYNFLAG_UNK20 = 0x00100000,
ITEM_DYNFLAG_UNK21 = 0x00200000,
ITEM_DYNFLAG_UNK22 = 0x00400000,
ITEM_DYNFLAG_UNK23 = 0x00800000,
ITEM_DYNFLAG_UNK24 = 0x01000000,
ITEM_DYNFLAG_UNK25 = 0x02000000,
ITEM_DYNFLAG_UNK26 = 0x04000000,
ITEM_DYNFLAG_UNK27 = 0x08000000,
ITEM_DYNFLAG_UNK28 = 0x10000000,
ITEM_DYNFLAG_UNK29 = 0x20000000,
ITEM_DYNFLAG_UNK30 = 0x40000000,
ITEM_DYNFLAG_UNK31 = 0x80000000
};
enum ItemRequiredTargetType
{
ITEM_TARGET_TYPE_CREATURE = 1,
@ -238,9 +276,9 @@ class MANGOS_DLL_SPEC Item : public Object
void SetOwnerGUID(uint64 guid) { SetUInt64Value(ITEM_FIELD_OWNER, guid); }
Player* GetOwner()const;
void SetBinding(bool val) { ApplyModFlag(ITEM_FIELD_FLAGS,ITEM_FLAGS_BINDED,val); }
bool IsSoulBound() const { return HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_BINDED); }
bool IsBoundAccountWide() const { return HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_BOA); }
void SetBinding(bool val) { ApplyModFlag(ITEM_FIELD_FLAGS, ITEM_DYNFLAG_BINDED,val); }
bool IsSoulBound() const { return HasFlag(ITEM_FIELD_FLAGS, ITEM_DYNFLAG_BINDED); }
bool IsBoundAccountWide() const { return GetProto()->Flags & ITEM_FLAG_BOA; }
bool IsBindedNotWith(Player const* player) const;
bool IsBoundByEnchant() const;
virtual void SaveToDB();

View file

@ -262,7 +262,7 @@ void WorldSession::HandleDestroyItemOpcode( WorldPacket & recv_data )
}
// checked at client side and not have server side appropriate error output
if (pItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_INDESTRUCTIBLE))
if (pItem->GetProto()->Flags & ITEM_FLAG_INDESTRUCTIBLE)
{
_player->SendEquipError( EQUIP_ERR_CANT_DROP_SOULBOUND, NULL, NULL );
return;
@ -777,10 +777,10 @@ void WorldSession::SendListInventory(ObjectGuid vendorguid)
continue;
// race wrong item skip always
if ((pProto->Flags2 & ITEM_FLAGS2_HORDE_ONLY) && _player->GetTeam() != HORDE)
if ((pProto->Flags2 & ITEM_FLAG2_HORDE_ONLY) && _player->GetTeam() != HORDE)
continue;
if ((pProto->Flags2 & ITEM_FLAGS2_ALLIANCE_ONLY) && _player->GetTeam() != ALLIANCE)
if ((pProto->Flags2 & ITEM_FLAG2_ALLIANCE_ONLY) && _player->GetTeam() != ALLIANCE)
continue;
if ((pProto->AllowableRace & _player->getRaceMask()) == 0)
@ -790,7 +790,7 @@ void WorldSession::SendListInventory(ObjectGuid vendorguid)
++count;
// reputation discount
uint32 price = (crItem->ExtendedCost == 0 || pProto->Flags2 & ITEM_FLAGS2_EXT_COST_REQUIRES_GOLD) ? uint32(floor(pProto->BuyPrice * discountMod)) : 0;
uint32 price = (crItem->ExtendedCost == 0 || pProto->Flags2 & ITEM_FLAG2_EXT_COST_REQUIRES_GOLD) ? uint32(floor(pProto->BuyPrice * discountMod)) : 0;
data << uint32(vendorslot +1); // client size expected counting from 1
data << uint32(crItem->item);
@ -1111,7 +1111,8 @@ void WorldSession::HandleWrapItemOpcode(WorldPacket& recv_data)
return;
}
if (!gift->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPER))// cheating: non-wrapper wrapper
// cheating: non-wrapper wrapper (all empty wrappers is stackable)
if (!(gift->GetProto()->Flags & ITEM_FLAG_WRAPPER) || gift->GetMaxStackCount() == 1)
{
_player->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, gift, NULL );
return;
@ -1137,7 +1138,7 @@ void WorldSession::HandleWrapItemOpcode(WorldPacket& recv_data)
return;
}
if (!item->GetGuidValue(ITEM_FIELD_GIFTCREATOR).IsEmpty())// HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPED);
if (!item->GetGuidValue(ITEM_FIELD_GIFTCREATOR).IsEmpty())// HasFlag(ITEM_FIELD_FLAGS, ITEM_DYNFLAG_WRAPPED);
{
_player->SendEquipError( EQUIP_ERR_WRAPPED_CANT_BE_WRAPPED, item, NULL );
return;
@ -1182,7 +1183,7 @@ void WorldSession::HandleWrapItemOpcode(WorldPacket& recv_data)
case 21830: item->SetEntry(21831); break;
}
item->SetGuidValue(ITEM_FIELD_GIFTCREATOR, _player->GetObjectGuid());
item->SetUInt32Value(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPED);
item->SetUInt32Value(ITEM_FIELD_FLAGS, ITEM_DYNFLAG_WRAPPED);
item->SetState(ITEM_CHANGED, _player);
if(item->GetState() == ITEM_NEW) // save new item, to have alway for `character_gifts` record in `item_instance`
@ -1281,7 +1282,7 @@ void WorldSession::HandleSocketOpcode(WorldPacket& recv_data)
ItemPrototype const* iGemProto = Gems[i]->GetProto();
// unique item (for new and already placed bit removed enchantments
if (iGemProto->Flags & ITEM_FLAGS_UNIQUE_EQUIPPED)
if (iGemProto->Flags & ITEM_FLAG_UNIQUE_EQUIPPED)
{
for (int j = 0; j < MAX_GEM_SOCKETS; ++j)
{
@ -1438,7 +1439,7 @@ void WorldSession::HandleItemRefundInfoRequest(WorldPacket& recv_data)
return;
}
if(!item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_REFUNDABLE))
if(!(item->GetProto()->Flags & ITEM_FLAG_REFUNDABLE))
{
DEBUG_LOG("Item refund: item not refundable!");
return;

View file

@ -101,43 +101,54 @@ enum ItemBondingType
#define MAX_BIND_TYPE 6
// masks for ITEM_FIELD_FLAGS field
enum ItemFlags
// Mask for ItemPrototype.Flags field
enum ItemPrototypeFlags
{
ITEM_FLAGS_BINDED = 0x00000001, // set in game at binding, not set in template
ITEM_FLAGS_CONJURED = 0x00000002,
ITEM_FLAGS_OPENABLE = 0x00000004,
ITEM_FLAGS_WRAPPED = 0x00000008, // conflicts with heroic flag
ITEM_FLAGS_HEROIC = 0x00000008, // weird...
ITEM_FLAGS_BROKEN = 0x00000010, // appears red icon (like when item durability==0)
ITEM_FLAGS_INDESTRUCTIBLE = 0x00000020, // used for totem. Item can not be destroyed, except by using spell (item can be reagent for spell and then allowed)
ITEM_FLAGS_USABLE = 0x00000040, // ?
ITEM_FLAGS_NO_EQUIP_COOLDOWN = 0x00000080, // ?
ITEM_FLAGS_UNK3 = 0x00000100, // saw this on item 47115, 49295...
ITEM_FLAGS_WRAPPER = 0x00000200, // used or not used wrapper
ITEM_FLAGS_IGNORE_BAG_SPACE = 0x00000400, // ignore bag space at new item creation?
ITEM_FLAGS_PARTY_LOOT = 0x00000800, // determines if item is party loot or not
ITEM_FLAGS_REFUNDABLE = 0x00001000, // item cost can be refunded within 2 hours after purchase
ITEM_FLAGS_CHARTER = 0x00002000, // arena/guild charter
ITEM_FLAGS_UNK4 = 0x00008000, // a lot of items have this
ITEM_FLAGS_UNK1 = 0x00010000, // a lot of items have this
ITEM_FLAGS_PROSPECTABLE = 0x00040000,
ITEM_FLAGS_UNIQUE_EQUIPPED = 0x00080000,
ITEM_FLAGS_USEABLE_IN_ARENA = 0x00200000,
ITEM_FLAGS_THROWABLE = 0x00400000, // not used in game for check trow possibility, only for item in game tooltip
ITEM_FLAGS_SPECIALUSE = 0x00800000, // last used flag in 2.3.0
ITEM_FLAGS_BOA = 0x08000000, // bind on account (set in template for items that can binded in like way)
ITEM_FLAGS_ENCHANT_SCROLL = 0x10000000, // for enchant scrolls
ITEM_FLAGS_MILLABLE = 0x20000000,
ITEM_FLAGS_BOP_TRADEABLE = 0x80000000
ITEM_FLAG_UNK0 = 0x00000001, // not used
ITEM_FLAG_CONJURED = 0x00000002,
ITEM_FLAG_LOOTABLE = 0x00000004, // affect only non container items that can be "open" for loot. It or lockid set enable for client show "Right click to open". See also ITEM_DYNFLAG_UNLOCKED
ITEM_FLAG_HEROIC = 0x00000008, // heroic item version
ITEM_FLAG_UNK4 = 0x00000010, // can't repeat old note: appears red icon (like when item durability==0)
ITEM_FLAG_INDESTRUCTIBLE = 0x00000020, // used for totem. Item can not be destroyed, except by using spell (item can be reagent for spell and then allowed)
ITEM_FLAG_UNK6 = 0x00000040, // ? old note: usable
ITEM_FLAG_NO_EQUIP_COOLDOWN = 0x00000080,
ITEM_FLAG_UNK8 = 0x00000100, // saw this on item 47115, 49295...
ITEM_FLAG_WRAPPER = 0x00000200, // used or not used wrapper
ITEM_FLAG_IGNORE_BAG_SPACE = 0x00000400, // ignore bag space at new item creation?
ITEM_FLAG_PARTY_LOOT = 0x00000800, // determines if item is party loot or not
ITEM_FLAG_REFUNDABLE = 0x00001000, // item cost can be refunded within 2 hours after purchase
ITEM_FLAG_CHARTER = 0x00002000, // arena/guild charter
ITEM_FLAG_UNK14 = 0x00004000,
ITEM_FLAG_UNK15 = 0x00008000, // a lot of items have this
ITEM_FLAG_UNK16 = 0x00010000, // a lot of items have this
ITEM_FLAG_UNK17 = 0x00020000,
ITEM_FLAG_PROSPECTABLE = 0x00040000, // item can have prospecting loot (in fact some items expected have empty loot)
ITEM_FLAG_UNIQUE_EQUIPPED = 0x00080000,
ITEM_FLAG_UNK20 = 0x00100000,
ITEM_FLAG_USEABLE_IN_ARENA = 0x00200000,
ITEM_FLAG_THROWABLE = 0x00400000, // Only items of ITEM_SUBCLASS_WEAPON_THROWN have it but not all, so can't be used as in game check
ITEM_FLAG_SPECIALUSE = 0x00800000, // last used flag in 2.3.0
ITEM_FLAG_UNK24 = 0x01000000,
ITEM_FLAG_UNK25 = 0x02000000,
ITEM_FLAG_UNK26 = 0x04000000,
ITEM_FLAG_BOA = 0x08000000, // bind on account (set in template for items that can binded in like way)
ITEM_FLAG_ENCHANT_SCROLL = 0x10000000, // for enchant scrolls
ITEM_FLAG_MILLABLE = 0x20000000, // item can have milling loot
ITEM_FLAG_UNK30 = 0x04000000,
ITEM_FLAG_BOP_TRADEABLE = 0x80000000, // bound item that can be traded
};
enum ItemFlags2
enum ItemPrototypeFlags2
{
ITEM_FLAGS2_HORDE_ONLY = 0x00000001, // drop in loot, sell by vendor and equipping only for horde
ITEM_FLAGS2_ALLIANCE_ONLY = 0x00000002, // drop in loot, sell by vendor and equipping only for alliance
ITEM_FLAGS2_EXT_COST_REQUIRES_GOLD = 0x00000004, // item cost include gold part in case extended cost use also
ITEM_FLAGS2_NEED_ROLL_DISABLED = 0x00000100, // need roll during looting is not allowed for this item
ITEM_FLAG2_HORDE_ONLY = 0x00000001, // drop in loot, sell by vendor and equipping only for horde
ITEM_FLAG2_ALLIANCE_ONLY = 0x00000002, // drop in loot, sell by vendor and equipping only for alliance
ITEM_FLAG2_EXT_COST_REQUIRES_GOLD = 0x00000004, // item cost include gold part in case extended cost use also
ITEM_FLAG2_UNK4 = 0x00000008,
ITEM_FLAG2_UNK5 = 0x00000010,
ITEM_FLAG2_UNK6 = 0x00000020,
ITEM_FLAG2_UNK7 = 0x00000040,
ITEM_FLAG2_UNK8 = 0x00000080,
ITEM_FLAG2_NEED_ROLL_DISABLED = 0x00000100, // need roll during looting is not allowed for this item
};
enum BagFamilyMask
@ -653,7 +664,7 @@ struct ItemPrototype
}
bool IsPotion() const { return Class==ITEM_CLASS_CONSUMABLE && SubClass==ITEM_SUBCLASS_POTION; }
bool IsConjuredConsumable() const { return Class == ITEM_CLASS_CONSUMABLE && (Flags & ITEM_FLAGS_CONJURED); }
bool IsConjuredConsumable() const { return Class == ITEM_CLASS_CONSUMABLE && (Flags & ITEM_FLAG_CONJURED); }
};
// GCC have alternative #pragma pack() syntax and old gcc version not support pack(pop), also any gcc version not support it at some platform

View file

@ -406,8 +406,7 @@ void WorldSession::DoLootRelease(ObjectGuid lguid)
ItemPrototype const* proto = pItem->GetProto();
// destroy only 5 items from stack in case prospecting and milling
if( (proto->BagFamily & (BAG_FAMILY_MASK_MINING_SUPP|BAG_FAMILY_MASK_HERBS)) &&
proto->Class == ITEM_CLASS_TRADE_GOODS)
if ((proto->Flags & (ITEM_FLAG_PROSPECTABLE | ITEM_FLAG_MILLABLE)))
{
pItem->m_lootGenerated = false;
pItem->loot.clear();

View file

@ -38,8 +38,8 @@ static eConfigFloatValues const qualityToRate[MAX_ITEM_QUALITY] = {
LootStore LootTemplates_Creature( "creature_loot_template", "creature entry", true);
LootStore LootTemplates_Disenchant( "disenchant_loot_template", "item disenchant id", true);
LootStore LootTemplates_Fishing( "fishing_loot_template", "area id", true);
LootStore LootTemplates_Gameobject( "gameobject_loot_template", "gameobject entry", true);
LootStore LootTemplates_Item( "item_loot_template", "item entry", true);
LootStore LootTemplates_Gameobject( "gameobject_loot_template", "gameobject lootid", true);
LootStore LootTemplates_Item( "item_loot_template", "item entry with ITEM_FLAG_LOOTABLE", true);
LootStore LootTemplates_Mail( "mail_loot_template", "mail template id", false);
LootStore LootTemplates_Milling( "milling_loot_template", "item entry (herb)", true);
LootStore LootTemplates_Pickpocketing("pickpocketing_loot_template","creature pickpocket lootid", true);
@ -320,7 +320,7 @@ LootItem::LootItem(LootStoreItem const& li)
conditionId = li.conditionId;
ItemPrototype const* proto = ObjectMgr::GetItemPrototype(itemid);
freeforall = proto && (proto->Flags & ITEM_FLAGS_PARTY_LOOT);
freeforall = proto && (proto->Flags & ITEM_FLAG_PARTY_LOOT);
needs_quest = li.needs_quest;
@ -345,10 +345,10 @@ bool LootItem::AllowedForPlayer(Player const * player) const
return false;
// not show loot for not own team
if ((pProto->Flags2 & ITEM_FLAGS2_HORDE_ONLY) && player->GetTeam() != HORDE)
if ((pProto->Flags2 & ITEM_FLAG2_HORDE_ONLY) && player->GetTeam() != HORDE)
return false;
if ((pProto->Flags2 & ITEM_FLAGS2_ALLIANCE_ONLY) && player->GetTeam() != ALLIANCE)
if ((pProto->Flags2 & ITEM_FLAG2_ALLIANCE_ONLY) && player->GetTeam() != ALLIANCE)
return false;
if ( needs_quest )
@ -386,10 +386,10 @@ void Loot::AddItem(LootStoreItem const & item)
// non-conditional one-player only items are counted here,
// free for all items are counted in FillFFALoot(),
// non-ffa conditionals are counted in FillNonQuestNonFFAConditionalLoot()
if( !item.conditionId )
if (!item.conditionId)
{
ItemPrototype const* proto = ObjectMgr::GetItemPrototype(item.itemid);
if( !proto || (proto->Flags & ITEM_FLAGS_PARTY_LOOT)==0 )
if (!proto || !(proto->Flags & ITEM_FLAG_PARTY_LOOT))
++unlootedCount;
}
}
@ -1189,9 +1189,19 @@ void LoadLootTemplates_Item()
// remove real entries and check existence loot
for(uint32 i = 1; i < sItemStorage.MaxEntry; ++i )
{
if(ItemPrototype const* proto = sItemStorage.LookupEntry<ItemPrototype>(i))
if (ids_set.find(proto->ItemId) != ids_set.end())
{
if (!(proto->Flags & ITEM_FLAG_LOOTABLE))
continue;
if (ids_set.find(proto->ItemId) != ids_set.end() || proto->MaxMoneyLoot > 0)
ids_set.erase(proto->ItemId);
// wdb have wrong data cases, so skip by default
else if ((sLog.getLogFilter() & LOG_FILTER_DB_STRICTED_CHECK) == 0)
LootTemplates_Item.ReportNotExistedId(proto->ItemId);
}
}
// output error for any still listed (not referenced from appropriate table) ids
LootTemplates_Item.ReportUnusedIds(ids_set);
@ -1209,11 +1219,13 @@ void LoadLootTemplates_Milling()
if(!proto)
continue;
if((proto->BagFamily & BAG_FAMILY_MASK_HERBS)==0)
if (!(proto->Flags & ITEM_FLAG_MILLABLE))
continue;
if (ids_set.find(proto->ItemId) != ids_set.end())
ids_set.erase(proto->ItemId);
else
LootTemplates_Milling.ReportNotExistedId(proto->ItemId);
}
// output error for any still listed (not referenced from appropriate table) ids
@ -1255,14 +1267,16 @@ void LoadLootTemplates_Prospecting()
for(uint32 i = 1; i < sItemStorage.MaxEntry; ++i )
{
ItemPrototype const* proto = sItemStorage.LookupEntry<ItemPrototype>(i);
if(!proto)
if (!proto)
continue;
if((proto->BagFamily & BAG_FAMILY_MASK_MINING_SUPP)==0)
if (!(proto->Flags & ITEM_FLAG_PROSPECTABLE))
continue;
if (ids_set.find(proto->ItemId) != ids_set.end())
ids_set.erase(proto->ItemId);
//else -- exist some cases that possible can be prospected but not expected have any result loot
// LootTemplates_Prospecting.ReportNotExistedId(proto->ItemId);
}
// output error for any still listed (not referenced from appropriate table) ids

View file

@ -207,13 +207,13 @@ void WorldSession::HandleSendMail(WorldPacket & recv_data )
return;
}
if (item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_CONJURED) || item->GetUInt32Value(ITEM_FIELD_DURATION))
if ((item->GetProto()->Flags & ITEM_FLAG_CONJURED) || item->GetUInt32Value(ITEM_FIELD_DURATION))
{
pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_MAIL_BOUND_ITEM);
return;
}
if (COD && item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPED))
if (COD && item->HasFlag(ITEM_FIELD_FLAGS, ITEM_DYNFLAG_WRAPPED))
{
pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_CANT_SEND_WRAPPED_COD);
return;
@ -716,7 +716,7 @@ void WorldSession::HandleMailCreateTextItem(WorldPacket & recv_data )
bodyItem->SetText(m->body);
bodyItem->SetGuidValue(ITEM_FIELD_CREATOR, ObjectGuid(HIGHGUID_PLAYER, m->sender));
bodyItem->SetFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPER | ITEM_FLAGS_UNK4 | ITEM_FLAGS_UNK1);
bodyItem->SetFlag(ITEM_FIELD_FLAGS, ITEM_DYNFLAG_READBLE | ITEM_DYNFLAG_UNK15 | ITEM_DYNFLAG_UNK16);
DETAIL_LOG("HandleMailCreateTextItem mailid=%u", mailId);

View file

@ -1896,23 +1896,23 @@ void ObjectMgr::LoadItemPrototypes()
const_cast<ItemPrototype*>(proto)->Quality = ITEM_QUALITY_NORMAL;
}
if (proto->Flags2 & ITEM_FLAGS2_HORDE_ONLY)
if (proto->Flags2 & ITEM_FLAG2_HORDE_ONLY)
{
if (FactionEntry const* faction = sFactionStore.LookupEntry(HORDE))
if ((proto->AllowableRace & faction->BaseRepRaceMask[0]) == 0)
sLog.outErrorDb("Item (Entry: %u) have in `AllowableRace` races (%u) only not compatible with ITEM_FLAGS2_HORDE_ONLY (%u) in Flags field, item any way will can't be equipped or use by this races.",
i, proto->AllowableRace, ITEM_FLAGS2_HORDE_ONLY);
sLog.outErrorDb("Item (Entry: %u) have in `AllowableRace` races (%u) only not compatible with ITEM_FLAG2_HORDE_ONLY (%u) in Flags field, item any way will can't be equipped or use by this races.",
i, proto->AllowableRace, ITEM_FLAG2_HORDE_ONLY);
if (proto->Flags2 & ITEM_FLAGS2_ALLIANCE_ONLY)
sLog.outErrorDb("Item (Entry: %u) have in `Flags2` flags ITEM_FLAGS2_ALLIANCE_ONLY (%u) and ITEM_FLAGS2_HORDE_ONLY (%u) in Flags field, this is wrong combination.",
i, ITEM_FLAGS2_ALLIANCE_ONLY, ITEM_FLAGS2_HORDE_ONLY);
if (proto->Flags2 & ITEM_FLAG2_ALLIANCE_ONLY)
sLog.outErrorDb("Item (Entry: %u) have in `Flags2` flags ITEM_FLAG2_ALLIANCE_ONLY (%u) and ITEM_FLAG2_HORDE_ONLY (%u) in Flags field, this is wrong combination.",
i, ITEM_FLAG2_ALLIANCE_ONLY, ITEM_FLAG2_HORDE_ONLY);
}
else if (proto->Flags2 & ITEM_FLAGS2_ALLIANCE_ONLY)
else if (proto->Flags2 & ITEM_FLAG2_ALLIANCE_ONLY)
{
if (FactionEntry const* faction = sFactionStore.LookupEntry(ALLIANCE))
if ((proto->AllowableRace & faction->BaseRepRaceMask[0]) == 0)
sLog.outErrorDb("Item (Entry: %u) have in `AllowableRace` races (%u) only not compatible with ITEM_FLAGS2_ALLIANCE_ONLY (%u) in Flags field, item any way will can't be equipped or use by this races.",
i, proto->AllowableRace, ITEM_FLAGS2_ALLIANCE_ONLY);
sLog.outErrorDb("Item (Entry: %u) have in `AllowableRace` races (%u) only not compatible with ITEM_FLAG2_ALLIANCE_ONLY (%u) in Flags field, item any way will can't be equipped or use by this races.",
i, proto->AllowableRace, ITEM_FLAG2_ALLIANCE_ONLY);
}
if(proto->BuyCount <= 0)
@ -2003,10 +2003,19 @@ void ObjectMgr::LoadItemPrototypes()
const_cast<ItemPrototype*>(proto)->Stackable = 1000;
}
if(proto->ContainerSlots > MAX_BAG_SIZE)
if (proto->ContainerSlots)
{
sLog.outErrorDb("Item (Entry: %u) has too large value in ContainerSlots (%u), replace by hardcoded limit (%u).",i,proto->ContainerSlots,MAX_BAG_SIZE);
const_cast<ItemPrototype*>(proto)->ContainerSlots = MAX_BAG_SIZE;
if(proto->ContainerSlots > MAX_BAG_SIZE)
{
sLog.outErrorDb("Item (Entry: %u) has too large value in ContainerSlots (%u), replace by hardcoded limit (%u).",i,proto->ContainerSlots,MAX_BAG_SIZE);
const_cast<ItemPrototype*>(proto)->ContainerSlots = MAX_BAG_SIZE;
}
if(proto->Flags & ITEM_FLAG_LOOTABLE)
{
sLog.outErrorDb("Item container (Entry: %u) has not allowed for containers flag ITEM_FLAG_LOOTABLE (%u), flag removed.",i,ITEM_FLAG_LOOTABLE);
const_cast<ItemPrototype*>(proto)->Flags |= ITEM_FLAG_LOOTABLE;
}
}
if(proto->StatsCount > MAX_ITEM_PROTO_STATS)
@ -2089,6 +2098,12 @@ void ObjectMgr::LoadItemPrototypes()
const_cast<ItemPrototype*>(proto)->Spells[1].SpellId = 0;
const_cast<ItemPrototype*>(proto)->Spells[1].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE;
}
// ok case for spell_1 (and other)
else if(proto->Flags & ITEM_FLAG_LOOTABLE)
{
sLog.outErrorDb("Item container (Entry: %u) has not allowed for spell learning items flag ITEM_FLAG_LOOTABLE (%u), flag removed.",i,ITEM_FLAG_LOOTABLE);
const_cast<ItemPrototype*>(proto)->Flags |= ITEM_FLAG_LOOTABLE;
}
}
// spell_3*,spell_4*,spell_5* is empty
@ -2139,6 +2154,13 @@ void ObjectMgr::LoadItemPrototypes()
sLog.outErrorDb("Item (Entry: %u) has broken spell in spellid_%d (%u)",i,j+1,proto->Spells[j].SpellId);
const_cast<ItemPrototype*>(proto)->Spells[j].SpellId = 0;
}
// ok cast at use case
else if((proto->Spells[j].SpellTrigger == ITEM_SPELLTRIGGER_ON_USE || proto->Spells[j].SpellTrigger == ITEM_SPELLTRIGGER_ON_NO_DELAY_USE) &&
proto->Flags & ITEM_FLAG_LOOTABLE)
{
sLog.outErrorDb("Item container (Entry: %u) has not allowed for spell casting at use items flag ITEM_FLAG_LOOTABLE (%u), flag removed.",i,ITEM_FLAG_LOOTABLE);
const_cast<ItemPrototype*>(proto)->Flags |= ITEM_FLAG_LOOTABLE;
}
}
}
}
@ -2146,8 +2168,11 @@ void ObjectMgr::LoadItemPrototypes()
if(proto->Bonding >= MAX_BIND_TYPE)
sLog.outErrorDb("Item (Entry: %u) has wrong Bonding value (%u)",i,proto->Bonding);
if(proto->PageText && !sPageTextStore.LookupEntry<PageText>(proto->PageText))
sLog.outErrorDb("Item (Entry: %u) has non existing first page (Id:%u)", i,proto->PageText);
if(proto->PageText)
{
if(!sPageTextStore.LookupEntry<PageText>(proto->PageText))
sLog.outErrorDb("Item (Entry: %u) has non existing first page (Id:%u)", i,proto->PageText);
}
if(proto->LockID && !sLockStore.LookupEntry(proto->LockID))
sLog.outErrorDb("Item (Entry: %u) has wrong LockID (%u)",i,proto->LockID);

View file

@ -10748,10 +10748,10 @@ uint8 Player::CanUseItem( ItemPrototype const *pProto ) const
if( pProto )
{
if ((pProto->Flags2 & ITEM_FLAGS2_HORDE_ONLY) && GetTeam() != HORDE)
if ((pProto->Flags2 & ITEM_FLAG2_HORDE_ONLY) && GetTeam() != HORDE)
return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM;
if ((pProto->Flags2 & ITEM_FLAGS2_ALLIANCE_ONLY) && GetTeam() != ALLIANCE)
if ((pProto->Flags2 & ITEM_FLAG2_ALLIANCE_ONLY) && GetTeam() != ALLIANCE)
return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM;
if ((pProto->AllowableClass & getClassMask()) == 0 || (pProto->AllowableRace & getRaceMask()) == 0)
@ -11306,7 +11306,7 @@ void Player::DestroyItem( uint8 bag, uint8 slot, bool update )
DestroyItem(slot, i, update);
}
if(pItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPED))
if (pItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_DYNFLAG_WRAPPED))
CharacterDatabase.PExecute("DELETE FROM character_gifts WHERE item_guid = '%u'", pItem->GetGUIDLow());
RemoveEnchantmentDurations(pItem);
@ -15897,7 +15897,7 @@ void Player::_LoadInventory(QueryResult *result, uint32 timediff)
}
// "Conjured items disappear if you are logged out for more than 15 minutes"
if (timediff > 15*MINUTE && item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_CONJURED))
if (timediff > 15*MINUTE && (item->GetProto()->Flags & ITEM_FLAG_CONJURED))
{
CharacterDatabase.PExecute("DELETE FROM character_inventory WHERE item = '%u'", item_guid);
item->FSetState(ITEM_REMOVED);
@ -18682,7 +18682,7 @@ bool Player::BuyItemFromVendorSlot(uint64 vendorguid, uint32 vendorslot, uint32
}
}
uint32 price = (crItem->ExtendedCost == 0 || pProto->Flags2 & ITEM_FLAGS2_EXT_COST_REQUIRES_GOLD) ? pProto->BuyPrice * count : 0;
uint32 price = (crItem->ExtendedCost == 0 || pProto->Flags2 & ITEM_FLAG2_EXT_COST_REQUIRES_GOLD) ? pProto->BuyPrice * count : 0;
// reputation discount
if (price)
@ -19677,7 +19677,7 @@ void Player::SendInstanceResetWarning( uint32 mapid, Difficulty difficulty, uint
void Player::ApplyEquipCooldown( Item * pItem )
{
if (pItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_NO_EQUIP_COOLDOWN))
if (pItem->GetProto()->Flags & ITEM_FLAG_NO_EQUIP_COOLDOWN)
return;
for(int i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
@ -21310,7 +21310,7 @@ uint8 Player::CanEquipUniqueItem(Item* pItem, uint8 eslot, uint32 limit_count) c
uint8 Player::CanEquipUniqueItem( ItemPrototype const* itemProto, uint8 except_slot, uint32 limit_count) const
{
// check unique-equipped on item
if (itemProto->Flags & ITEM_FLAGS_UNIQUE_EQUIPPED)
if (itemProto->Flags & ITEM_FLAG_UNIQUE_EQUIPPED)
{
// there is an equip limit on this item
if(HasItemOrGemWithIdEquipped(itemProto->ItemId,1,except_slot))

View file

@ -4998,7 +4998,8 @@ SpellCastResult Spell::CheckCast(bool strict)
|| m_spellInfo->EffectImplicitTargetA[i] == TARGET_GAMEOBJECT && !m_targets.getGOTarget()
// we need a go target, or an openable item target in case of TARGET_GAMEOBJECT_ITEM
|| m_spellInfo->EffectImplicitTargetA[i] == TARGET_GAMEOBJECT_ITEM && !m_targets.getGOTarget() &&
(!m_targets.getItemTarget() || !m_targets.getItemTarget()->GetProto()->LockID || m_targets.getItemTarget()->GetOwner() != m_caster ) )
(!m_targets.getItemTarget() || m_targets.getItemTarget()->GetOwner() != m_caster ||
!m_targets.getItemTarget()->GetProto()->LockID || m_targets.getItemTarget()->HasFlag(ITEM_FIELD_FLAGS, ITEM_DYNFLAG_UNLOCKED)))
return SPELL_FAILED_BAD_TARGETS;
// In BattleGround players can use only flags and banners
@ -5721,7 +5722,7 @@ SpellCastResult Spell::CheckPower()
bool Spell::IgnoreItemRequirements() const
{
/// Check if it's an enchant scroll. These have no required reagents even though their spell does.
if (m_CastItem && m_CastItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_ENCHANT_SCROLL))
if (m_CastItem && (m_CastItem->GetProto()->Flags & ITEM_FLAG_ENCHANT_SCROLL))
return true;
if (m_IsTriggeredSpell)
@ -6038,7 +6039,7 @@ SpellCastResult Spell::CheckItems()
if(!m_targets.getItemTarget())
return SPELL_FAILED_CANT_BE_PROSPECTED;
// ensure item is a prospectable ore
if(!(m_targets.getItemTarget()->GetProto()->BagFamily & BAG_FAMILY_MASK_MINING_SUPP) || m_targets.getItemTarget()->GetProto()->Class != ITEM_CLASS_TRADE_GOODS)
if (!(m_targets.getItemTarget()->GetProto()->Flags & ITEM_FLAG_PROSPECTABLE))
return SPELL_FAILED_CANT_BE_PROSPECTED;
// prevent prospecting in trade slot
if( m_targets.getItemTarget()->GetOwnerGUID() != m_caster->GetGUID() )
@ -6061,7 +6062,7 @@ SpellCastResult Spell::CheckItems()
if(!m_targets.getItemTarget())
return SPELL_FAILED_CANT_BE_MILLED;
// ensure item is a millable herb
if(!(m_targets.getItemTarget()->GetProto()->BagFamily & BAG_FAMILY_MASK_HERBS) || m_targets.getItemTarget()->GetProto()->Class != ITEM_CLASS_TRADE_GOODS)
if (!(m_targets.getItemTarget()->GetProto()->Flags & ITEM_FLAG_MILLABLE))
return SPELL_FAILED_CANT_BE_MILLED;
// prevent milling in trade slot
if( m_targets.getItemTarget()->GetOwnerGUID() != m_caster->GetGUID() )

View file

@ -3824,6 +3824,10 @@ void Spell::EffectOpenLock(SpellEffectIndex eff_idx)
return;
}
// mark item as unlocked
if (itemTarget)
itemTarget->SetFlag(ITEM_FIELD_FLAGS, ITEM_DYNFLAG_UNLOCKED);
SendLoot(guid, LOOT_SKINNING);
// not allow use skill grow at item base open
@ -7851,17 +7855,17 @@ void Spell::EffectTransmitted(SpellEffectIndex eff_idx)
void Spell::EffectProspecting(SpellEffectIndex /*eff_idx*/)
{
if(m_caster->GetTypeId() != TYPEID_PLAYER)
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
Player* p_caster = (Player*)m_caster;
if(!itemTarget || !(itemTarget->GetProto()->BagFamily & BAG_FAMILY_MASK_MINING_SUPP))
if (!itemTarget || !(itemTarget->GetProto()->Flags & ITEM_FLAG_PROSPECTABLE))
return;
if(itemTarget->GetCount() < 5)
if (itemTarget->GetCount() < 5)
return;
if( sWorld.getConfig(CONFIG_BOOL_SKILL_PROSPECTING))
if (sWorld.getConfig(CONFIG_BOOL_SKILL_PROSPECTING))
{
uint32 SkillValue = p_caster->GetPureSkillValue(SKILL_JEWELCRAFTING);
uint32 reqSkillValue = itemTarget->GetProto()->RequiredSkillRank;
@ -7877,7 +7881,7 @@ void Spell::EffectMilling(SpellEffectIndex /*eff_idx*/)
return;
Player* p_caster = (Player*)m_caster;
if(!itemTarget || !(itemTarget->GetProto()->BagFamily & BAG_FAMILY_MASK_HERBS))
if (!itemTarget || !(itemTarget->GetProto()->Flags & ITEM_FLAG_MILLABLE))
return;
if(itemTarget->GetCount() < 5)

View file

@ -109,7 +109,7 @@ void WorldSession::HandleUseItemOpcode(WorldPacket& recvPacket)
// only allow conjured consumable, bandage, poisons (all should have the 2^21 item flag set in DB)
if (proto->Class == ITEM_CLASS_CONSUMABLE &&
!(proto->Flags & ITEM_FLAGS_USEABLE_IN_ARENA) &&
!(proto->Flags & ITEM_FLAG_USEABLE_IN_ARENA) &&
pUser->InArena())
{
recvPacket.rpos(recvPacket.wpos()); // prevent spam at not read packet tail
@ -241,7 +241,7 @@ void WorldSession::HandleOpenItemOpcode(WorldPacket& recvPacket)
}
}
if(pItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPED))// wrapped?
if (pItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_DYNFLAG_WRAPPED))// wrapped?
{
QueryResult *result = CharacterDatabase.PQuery("SELECT entry, flags FROM character_gifts WHERE item_guid = '%u'", pItem->GetGUIDLow());
if (result)

View file

@ -100,7 +100,7 @@ void WorldSession::SendUpdateTrade(bool trader_state /*= true*/)
data << uint32(item->GetProto()->DisplayInfoID);// display id
data << uint32(item->GetCount()); // stack count
// wrapped: hide stats but show giftcreator name
data << uint32(item->HasFlag(ITEM_FIELD_FLAGS,ITEM_FLAGS_WRAPPED) ? 1 : 0);
data << uint32(item->HasFlag(ITEM_FIELD_FLAGS, ITEM_DYNFLAG_WRAPPED) ? 1 : 0);
data << item->GetGuidValue(ITEM_FIELD_GIFTCREATOR);
data << uint32(item->GetEnchantmentId(PERM_ENCHANTMENT_SLOT));

View file

@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__
#define __REVISION_NR_H__
#define REVISION_NR "10640"
#define REVISION_NR "10641"
#endif // __REVISION_NR_H__