mirror of
https://github.com/mangosfour/server.git
synced 2025-12-13 13:37:05 +00:00
[10662] Implement partly item looting
* Not deleted normal item loot at first loot window close. * Save current item loot content to DB for later continue looting. * Cleanup spell effect SPELL_EFFECT_OPEN_LOCK check code * Cleanup Player::AutoStoreLoot calls
This commit is contained in:
parent
9a5accf8a9
commit
f48e768a70
21 changed files with 392 additions and 132 deletions
|
|
@ -21,7 +21,7 @@
|
||||||
|
|
||||||
DROP TABLE IF EXISTS `character_db_version`;
|
DROP TABLE IF EXISTS `character_db_version`;
|
||||||
CREATE TABLE `character_db_version` (
|
CREATE TABLE `character_db_version` (
|
||||||
`required_10655_01_characters_character_queststatus_monthly` bit(1) default NULL
|
`required_10662_01_characters_item_loot` bit(1) default NULL
|
||||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Last applied sql update to DB';
|
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Last applied sql update to DB';
|
||||||
|
|
||||||
--
|
--
|
||||||
|
|
@ -1455,6 +1455,31 @@ LOCK TABLES `item_instance` WRITE;
|
||||||
/*!40000 ALTER TABLE `item_instance` ENABLE KEYS */;
|
/*!40000 ALTER TABLE `item_instance` ENABLE KEYS */;
|
||||||
UNLOCK TABLES;
|
UNLOCK TABLES;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for table `item_loot`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `item_loot`;
|
||||||
|
CREATE TABLE `item_loot` (
|
||||||
|
`guid` int(11) unsigned NOT NULL default '0',
|
||||||
|
`owner_guid` int(11) unsigned NOT NULL default '0',
|
||||||
|
`itemid` int(11) unsigned NOT NULL default '0',
|
||||||
|
`amount` int(11) unsigned NOT NULL default '0',
|
||||||
|
`suffix` int(11) unsigned NOT NULL default '0',
|
||||||
|
`property` int(11) NOT NULL default '0',
|
||||||
|
PRIMARY KEY (`guid`,`itemid`),
|
||||||
|
KEY `idx_owner_guid` (`owner_guid`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Item System';
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Dumping data for table `item_instance`
|
||||||
|
--
|
||||||
|
|
||||||
|
LOCK TABLES `item_loot` WRITE;
|
||||||
|
/*!40000 ALTER TABLE `item_loot` DISABLE KEYS */;
|
||||||
|
/*!40000 ALTER TABLE `item_loot` ENABLE KEYS */;
|
||||||
|
UNLOCK TABLES;
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Table structure for table `mail`
|
-- Table structure for table `mail`
|
||||||
--
|
--
|
||||||
|
|
|
||||||
13
sql/updates/10662_01_characters_item_loot.sql
Normal file
13
sql/updates/10662_01_characters_item_loot.sql
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
ALTER TABLE character_db_version CHANGE COLUMN required_10655_01_characters_character_queststatus_monthly required_10662_01_characters_item_loot bit;
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `item_loot`;
|
||||||
|
CREATE TABLE `item_loot` (
|
||||||
|
`guid` int(11) unsigned NOT NULL default '0',
|
||||||
|
`owner_guid` int(11) unsigned NOT NULL default '0',
|
||||||
|
`itemid` int(11) unsigned NOT NULL default '0',
|
||||||
|
`amount` int(11) unsigned NOT NULL default '0',
|
||||||
|
`suffix` int(11) unsigned NOT NULL default '0',
|
||||||
|
`property` int(11) NOT NULL default '0',
|
||||||
|
PRIMARY KEY (`guid`,`itemid`),
|
||||||
|
KEY `idx_owner_guid` (`owner_guid`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Item System';
|
||||||
|
|
@ -112,6 +112,7 @@ pkgdata_DATA = \
|
||||||
10654_01_mangos_game_event_creature_quest.sql \
|
10654_01_mangos_game_event_creature_quest.sql \
|
||||||
10655_01_characters_character_queststatus_monthly.sql \
|
10655_01_characters_character_queststatus_monthly.sql \
|
||||||
10660_01_mangos_game_event_quest.sql \
|
10660_01_mangos_game_event_quest.sql \
|
||||||
|
10662_01_characters_item_loot.sql \
|
||||||
README
|
README
|
||||||
|
|
||||||
## Additional files to include when running 'make dist'
|
## Additional files to include when running 'make dist'
|
||||||
|
|
@ -204,4 +205,5 @@ EXTRA_DIST = \
|
||||||
10654_01_mangos_game_event_creature_quest.sql \
|
10654_01_mangos_game_event_creature_quest.sql \
|
||||||
10655_01_characters_character_queststatus_monthly.sql \
|
10655_01_characters_character_queststatus_monthly.sql \
|
||||||
10660_01_mangos_game_event_quest.sql \
|
10660_01_mangos_game_event_quest.sql \
|
||||||
|
10662_01_characters_item_loot.sql \
|
||||||
README
|
README
|
||||||
|
|
|
||||||
|
|
@ -318,7 +318,7 @@ void AuctionHouseMgr::LoadAuctionItems()
|
||||||
|
|
||||||
Item *item = NewItemOrBag(proto);
|
Item *item = NewItemOrBag(proto);
|
||||||
|
|
||||||
if(!item->LoadFromDB(item_guid,0, result))
|
if(!item->LoadFromDB(item_guid,0, fields))
|
||||||
{
|
{
|
||||||
delete item;
|
delete item;
|
||||||
continue;
|
continue;
|
||||||
|
|
|
||||||
|
|
@ -94,9 +94,9 @@ void Bag::SaveToDB()
|
||||||
Item::SaveToDB();
|
Item::SaveToDB();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Bag::LoadFromDB(uint32 guid, uint64 owner_guid, QueryResult *result)
|
bool Bag::LoadFromDB(uint32 guid, uint64 owner_guid, Field *fields)
|
||||||
{
|
{
|
||||||
if(!Item::LoadFromDB(guid, owner_guid, result))
|
if(!Item::LoadFromDB(guid, owner_guid, fields))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// cleanup bag content related item value fields (its will be filled correctly from `character_inventory`)
|
// cleanup bag content related item value fields (its will be filled correctly from `character_inventory`)
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ class Bag : public Item
|
||||||
// overwrite virtual Item::SaveToDB
|
// overwrite virtual Item::SaveToDB
|
||||||
void SaveToDB();
|
void SaveToDB();
|
||||||
// overwrite virtual Item::LoadFromDB
|
// overwrite virtual Item::LoadFromDB
|
||||||
bool LoadFromDB(uint32 guid, uint64 owner_guid, QueryResult *result);
|
bool LoadFromDB(uint32 guid, uint64 owner_guid, Field *fields);
|
||||||
// overwrite virtual Item::DeleteFromDB
|
// overwrite virtual Item::DeleteFromDB
|
||||||
void DeleteFromDB();
|
void DeleteFromDB();
|
||||||
|
|
||||||
|
|
@ -71,6 +71,10 @@ class Bag : public Item
|
||||||
|
|
||||||
inline Item* NewItemOrBag(ItemPrototype const * proto)
|
inline Item* NewItemOrBag(ItemPrototype const * proto)
|
||||||
{
|
{
|
||||||
return (proto->InventoryType == INVTYPE_BAG) ? new Bag : new Item;
|
if (proto->InventoryType == INVTYPE_BAG)
|
||||||
|
return new Bag;
|
||||||
|
|
||||||
|
return new Item;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,7 @@ bool LoginQueryHolder::Initialize()
|
||||||
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADMONTHLYQUESTSTATUS,"SELECT quest FROM character_queststatus_monthly WHERE guid = '%u'", GUID_LOPART(m_guid));
|
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADMONTHLYQUESTSTATUS,"SELECT quest FROM character_queststatus_monthly WHERE guid = '%u'", GUID_LOPART(m_guid));
|
||||||
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADREPUTATION, "SELECT faction,standing,flags FROM character_reputation WHERE guid = '%u'", GUID_LOPART(m_guid));
|
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADREPUTATION, "SELECT faction,standing,flags FROM character_reputation WHERE guid = '%u'", GUID_LOPART(m_guid));
|
||||||
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADINVENTORY, "SELECT data,text,bag,slot,item,item_template FROM character_inventory JOIN item_instance ON character_inventory.item = item_instance.guid WHERE character_inventory.guid = '%u' ORDER BY bag,slot", GUID_LOPART(m_guid));
|
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADINVENTORY, "SELECT data,text,bag,slot,item,item_template FROM character_inventory JOIN item_instance ON character_inventory.item = item_instance.guid WHERE character_inventory.guid = '%u' ORDER BY bag,slot", GUID_LOPART(m_guid));
|
||||||
|
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADITEMLOOT, "SELECT guid,itemid,amount,suffix,property FROM item_loot WHERE owner_guid = '%u'", GUID_LOPART(m_guid));
|
||||||
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADACTIONS, "SELECT spec,button,action,type FROM character_action WHERE guid = '%u' ORDER BY button", GUID_LOPART(m_guid));
|
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADACTIONS, "SELECT spec,button,action,type FROM character_action WHERE guid = '%u' ORDER BY button", GUID_LOPART(m_guid));
|
||||||
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADSOCIALLIST, "SELECT friend,flags,note FROM character_social WHERE guid = '%u' LIMIT 255", GUID_LOPART(m_guid));
|
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADSOCIALLIST, "SELECT friend,flags,note FROM character_social WHERE guid = '%u' LIMIT 255", GUID_LOPART(m_guid));
|
||||||
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADHOMEBIND, "SELECT map,zone,position_x,position_y,position_z FROM character_homebind WHERE guid = '%u'", GUID_LOPART(m_guid));
|
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADHOMEBIND, "SELECT map,zone,position_x,position_y,position_z FROM character_homebind WHERE guid = '%u'", GUID_LOPART(m_guid));
|
||||||
|
|
|
||||||
|
|
@ -1174,7 +1174,7 @@ void Guild::LoadGuildBankFromDB()
|
||||||
}
|
}
|
||||||
|
|
||||||
Item *pItem = NewItemOrBag(proto);
|
Item *pItem = NewItemOrBag(proto);
|
||||||
if (!pItem->LoadFromDB(ItemGuid, 0, result))
|
if (!pItem->LoadFromDB(ItemGuid, 0, fields))
|
||||||
{
|
{
|
||||||
CharacterDatabase.PExecute("DELETE FROM guild_bank_item WHERE guildid='%u' AND TabId='%u' AND SlotId='%u'", m_Id, uint32(TabId), uint32(SlotId));
|
CharacterDatabase.PExecute("DELETE FROM guild_bank_item WHERE guildid='%u' AND TabId='%u' AND SlotId='%u'", m_Id, uint32(TabId), uint32(SlotId));
|
||||||
sLog.outError("Item GUID %u not found in item_instance, deleting from Guild Bank!", ItemGuid);
|
sLog.outError("Item GUID %u not found in item_instance, deleting from Guild Bank!", ItemGuid);
|
||||||
|
|
|
||||||
|
|
@ -241,8 +241,8 @@ Item::Item( )
|
||||||
uState = ITEM_NEW;
|
uState = ITEM_NEW;
|
||||||
uQueuePos = -1;
|
uQueuePos = -1;
|
||||||
m_container = NULL;
|
m_container = NULL;
|
||||||
m_lootGenerated = false;
|
|
||||||
mb_in_trade = false;
|
mb_in_trade = false;
|
||||||
|
m_lootState = ITEM_LOOT_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Item::Create( uint32 guidlow, uint32 itemid, Player const* owner)
|
bool Item::Create( uint32 guidlow, uint32 itemid, Player const* owner)
|
||||||
|
|
@ -326,40 +326,66 @@ void Item::SaveToDB()
|
||||||
CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid = '%u'", guid);
|
CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid = '%u'", guid);
|
||||||
if (HasFlag(ITEM_FIELD_FLAGS, ITEM_DYNFLAG_WRAPPED))
|
if (HasFlag(ITEM_FIELD_FLAGS, ITEM_DYNFLAG_WRAPPED))
|
||||||
CharacterDatabase.PExecute("DELETE FROM character_gifts WHERE item_guid = '%u'", GetGUIDLow());
|
CharacterDatabase.PExecute("DELETE FROM character_gifts WHERE item_guid = '%u'", GetGUIDLow());
|
||||||
|
|
||||||
|
if (HasSavedLoot())
|
||||||
|
CharacterDatabase.PExecute("DELETE FROM item_loot WHERE guid = '%u'", GetGUIDLow());
|
||||||
|
|
||||||
delete this;
|
delete this;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case ITEM_UNCHANGED:
|
case ITEM_UNCHANGED:
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_lootState == ITEM_LOOT_CHANGED || m_lootState == ITEM_LOOT_REMOVED)
|
||||||
|
CharacterDatabase.PExecute("DELETE FROM item_loot WHERE guid = '%u'", GetGUIDLow());
|
||||||
|
|
||||||
|
if (m_lootState == ITEM_LOOT_NEW || m_lootState == ITEM_LOOT_CHANGED)
|
||||||
|
{
|
||||||
|
if(Player* owner = GetOwner())
|
||||||
|
{
|
||||||
|
// save money as 0 itemid data
|
||||||
|
if (loot.gold)
|
||||||
|
CharacterDatabase.PExecute("INSERT INTO item_loot (guid,owner_guid,itemid,amount,suffix,property) "
|
||||||
|
"VALUES (%u, %u, 0, %u, 0, 0)",
|
||||||
|
GetGUIDLow(), owner->GetGUIDLow(), loot.gold);
|
||||||
|
|
||||||
|
// save items and quest items (at load its all will added as normal, but this not important for item loot case)
|
||||||
|
for (size_t i = 0; i < loot.GetMaxSlotInLootFor(owner); ++i)
|
||||||
|
{
|
||||||
|
QuestItem *qitem = NULL;
|
||||||
|
|
||||||
|
LootItem *item = loot.LootItemInSlot(i,owner,&qitem);
|
||||||
|
if(!item)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// questitems use the blocked field for other purposes
|
||||||
|
if (!qitem && item->is_blocked)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
CharacterDatabase.PExecute("INSERT INTO item_loot (guid,owner_guid,itemid,amount,suffix,property) "
|
||||||
|
"VALUES (%u, %u, %u, %u, %u, %i)",
|
||||||
|
GetGUIDLow(), owner->GetGUIDLow(), item->itemid, item->count, item->randomSuffix, item->randomPropertyId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_lootState != ITEM_LOOT_NONE && m_lootState != ITEM_LOOT_TEMPORARY)
|
||||||
|
SetLootState(ITEM_LOOT_UNCHANGED);
|
||||||
|
|
||||||
SetState(ITEM_UNCHANGED);
|
SetState(ITEM_UNCHANGED);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Item::LoadFromDB(uint32 guidLow, uint64 owner_guid, QueryResult *result)
|
bool Item::LoadFromDB(uint32 guidLow, uint64 owner_guid, Field *fields)
|
||||||
{
|
{
|
||||||
// create item before any checks for store correct guid
|
// create item before any checks for store correct guid
|
||||||
// and allow use "FSetState(ITEM_REMOVED); SaveToDB();" for deleting item from DB
|
// and allow use "FSetState(ITEM_REMOVED); SaveToDB();" for deleting item from DB
|
||||||
Object::_Create(guidLow, 0, HIGHGUID_ITEM);
|
Object::_Create(guidLow, 0, HIGHGUID_ITEM);
|
||||||
|
|
||||||
bool delete_result = false;
|
|
||||||
if(!result)
|
|
||||||
{
|
|
||||||
result = CharacterDatabase.PQuery("SELECT data FROM item_instance WHERE guid = '%u'", guidLow);
|
|
||||||
delete_result = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!result)
|
|
||||||
{
|
|
||||||
sLog.outError("Item (GUID: %u owner: %u) not found in table `item_instance`, can't load. ", guidLow, GUID_LOPART(owner_guid));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Field *fields = result->Fetch();
|
|
||||||
|
|
||||||
if (!LoadValues(fields[0].GetString()))
|
if (!LoadValues(fields[0].GetString()))
|
||||||
{
|
{
|
||||||
sLog.outError("Item #%d have broken data in `data` field. Can't be loaded.", guidLow);
|
sLog.outError("Item #%d have broken data in `data` field. Can't be loaded.", guidLow);
|
||||||
if (delete_result) delete result;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -373,9 +399,6 @@ bool Item::LoadFromDB(uint32 guidLow, uint64 owner_guid, QueryResult *result)
|
||||||
need_save = true;
|
need_save = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (delete_result)
|
|
||||||
delete result;
|
|
||||||
|
|
||||||
ItemPrototype const* proto = GetProto();
|
ItemPrototype const* proto = GetProto();
|
||||||
if(!proto)
|
if(!proto)
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -446,6 +469,37 @@ bool Item::LoadFromDB(uint32 guidLow, uint64 owner_guid, QueryResult *result)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Item::LoadLootFromDB(Field *fields)
|
||||||
|
{
|
||||||
|
uint32 item_id = fields[1].GetUInt32();
|
||||||
|
uint32 item_amount = fields[2].GetUInt32();
|
||||||
|
uint32 item_suffix = fields[3].GetUInt32();
|
||||||
|
int32 item_propid = fields[4].GetInt32();
|
||||||
|
|
||||||
|
// money value special case
|
||||||
|
if (item_id == 0)
|
||||||
|
{
|
||||||
|
loot.gold = item_amount;
|
||||||
|
SetLootState(ITEM_LOOT_UNCHANGED);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// normal item case
|
||||||
|
ItemPrototype const* proto = ObjectMgr::GetItemPrototype(item_id);
|
||||||
|
|
||||||
|
if(!proto)
|
||||||
|
{
|
||||||
|
CharacterDatabase.PExecute("DELETE FROM item_loot WHERE guid = '%u' AND itemid = '%u'", GetGUIDLow(), item_id);
|
||||||
|
sLog.outError("Item::LoadLootFromDB: %s has an unknown item (id: #%u) in item_loot, deleted.", ObjectGuid(GetOwnerGUID()).GetString().c_str(), item_id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
loot.items.push_back(LootItem(item_id, item_amount, item_suffix, item_propid));
|
||||||
|
++loot.unlootedCount;
|
||||||
|
|
||||||
|
SetLootState(ITEM_LOOT_UNCHANGED);
|
||||||
|
}
|
||||||
|
|
||||||
void Item::DeleteFromDB()
|
void Item::DeleteFromDB()
|
||||||
{
|
{
|
||||||
CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid = '%u'",GetGUIDLow());
|
CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid = '%u'",GetGUIDLow());
|
||||||
|
|
@ -725,9 +779,6 @@ bool Item::IsEquipped() const
|
||||||
|
|
||||||
bool Item::CanBeTraded(bool mail) const
|
bool Item::CanBeTraded(bool mail) const
|
||||||
{
|
{
|
||||||
if (m_lootGenerated)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if ((!mail || !IsBoundAccountWide()) && IsSoulBound())
|
if ((!mail || !IsBoundAccountWide()) && IsSoulBound())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
@ -742,6 +793,9 @@ bool Item::CanBeTraded(bool mail) const
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (HasGeneratedLoot())
|
||||||
|
return false;
|
||||||
|
|
||||||
if (IsBoundByEnchant())
|
if (IsBoundByEnchant())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
@ -1003,6 +1057,10 @@ bool Item::IsBindedNotWith( Player const* player ) const
|
||||||
if(GetOwnerGUID()== player->GetGUID())
|
if(GetOwnerGUID()== player->GetGUID())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
// has loot with diff owner
|
||||||
|
if (HasGeneratedLoot())
|
||||||
|
return true;
|
||||||
|
|
||||||
// not BOA item case
|
// not BOA item case
|
||||||
if(!IsBoundAccountWide())
|
if(!IsBoundAccountWide())
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -1050,7 +1108,7 @@ uint8 Item::CanBeMergedPartlyWith( ItemPrototype const* proto ) const
|
||||||
return EQUIP_ERR_ITEM_CANT_STACK;
|
return EQUIP_ERR_ITEM_CANT_STACK;
|
||||||
|
|
||||||
// not allow merge looting currently items
|
// not allow merge looting currently items
|
||||||
if (m_lootGenerated)
|
if (HasGeneratedLoot())
|
||||||
return EQUIP_ERR_ALREADY_LOOTED;
|
return EQUIP_ERR_ALREADY_LOOTED;
|
||||||
|
|
||||||
return EQUIP_ERR_OK;
|
return EQUIP_ERR_OK;
|
||||||
|
|
@ -1099,3 +1157,47 @@ void Item::RestoreCharges()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Item::SetLootState( ItemLootUpdateState state )
|
||||||
|
{
|
||||||
|
// ITEM_LOOT_NONE -> ITEM_LOOT_TEMPORARY -> ITEM_LOOT_NONE
|
||||||
|
// ITEM_LOOT_NONE -> ITEM_LOOT_NEW -> ITEM_LOOT_NONE
|
||||||
|
// ITEM_LOOT_NONE -> ITEM_LOOT_NEW -> ITEM_LOOT_UNCHANGED [<-> ITEM_LOOT_CHANGED] -> ITEM_LOOT_REMOVED -> ITEM_LOOT_NONE
|
||||||
|
switch(state)
|
||||||
|
{
|
||||||
|
case ITEM_LOOT_NONE:
|
||||||
|
case ITEM_LOOT_NEW:
|
||||||
|
assert(false); // not used in state change calls
|
||||||
|
return;
|
||||||
|
case ITEM_LOOT_TEMPORARY:
|
||||||
|
assert(m_lootState == ITEM_LOOT_NONE); // called only for not generated yet loot case
|
||||||
|
m_lootState = ITEM_LOOT_TEMPORARY;
|
||||||
|
break;
|
||||||
|
case ITEM_LOOT_CHANGED:
|
||||||
|
// new loot must stay in new state until saved, temporary must stay until remove
|
||||||
|
if (m_lootState != ITEM_LOOT_NEW && m_lootState != ITEM_LOOT_TEMPORARY)
|
||||||
|
m_lootState = m_lootState == ITEM_LOOT_NONE ? ITEM_LOOT_NEW : state;
|
||||||
|
break;
|
||||||
|
case ITEM_LOOT_UNCHANGED:
|
||||||
|
// expected that called after DB update or load
|
||||||
|
if (m_lootState == ITEM_LOOT_REMOVED)
|
||||||
|
m_lootState = ITEM_LOOT_NONE;
|
||||||
|
// temporary must stay until remove (ignore any changes)
|
||||||
|
else if (m_lootState != ITEM_LOOT_TEMPORARY)
|
||||||
|
m_lootState = ITEM_LOOT_UNCHANGED;
|
||||||
|
break;
|
||||||
|
case ITEM_LOOT_REMOVED:
|
||||||
|
// if loot not saved then it existence in past can be just ignored
|
||||||
|
if (m_lootState == ITEM_LOOT_NEW || m_lootState == ITEM_LOOT_TEMPORARY)
|
||||||
|
{
|
||||||
|
m_lootState = ITEM_LOOT_NONE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_lootState = ITEM_LOOT_REMOVED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_lootState != ITEM_LOOT_NONE && m_lootState != ITEM_LOOT_UNCHANGED && m_lootState != ITEM_LOOT_TEMPORARY)
|
||||||
|
SetState(ITEM_CHANGED);
|
||||||
|
}
|
||||||
|
|
@ -26,6 +26,7 @@
|
||||||
|
|
||||||
struct SpellEntry;
|
struct SpellEntry;
|
||||||
class Bag;
|
class Bag;
|
||||||
|
class Field;
|
||||||
class QueryResult;
|
class QueryResult;
|
||||||
class Unit;
|
class Unit;
|
||||||
|
|
||||||
|
|
@ -202,6 +203,15 @@ enum ItemUpdateState
|
||||||
ITEM_REMOVED = 3
|
ITEM_REMOVED = 3
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum ItemLootUpdateState
|
||||||
|
{
|
||||||
|
ITEM_LOOT_NONE = 0, // loot not generated
|
||||||
|
ITEM_LOOT_TEMPORARY = 1, // generated loot is temporary (will deleted at loot window close)
|
||||||
|
ITEM_LOOT_UNCHANGED = 2,
|
||||||
|
ITEM_LOOT_CHANGED = 3,
|
||||||
|
ITEM_LOOT_NEW = 4,
|
||||||
|
ITEM_LOOT_REMOVED = 5
|
||||||
|
};
|
||||||
|
|
||||||
// masks for ITEM_FIELD_FLAGS field
|
// masks for ITEM_FIELD_FLAGS field
|
||||||
enum ItemDynFlags
|
enum ItemDynFlags
|
||||||
|
|
@ -282,9 +292,10 @@ class MANGOS_DLL_SPEC Item : public Object
|
||||||
bool IsBindedNotWith(Player const* player) const;
|
bool IsBindedNotWith(Player const* player) const;
|
||||||
bool IsBoundByEnchant() const;
|
bool IsBoundByEnchant() const;
|
||||||
virtual void SaveToDB();
|
virtual void SaveToDB();
|
||||||
virtual bool LoadFromDB(uint32 guid, uint64 owner_guid, QueryResult *result);
|
virtual bool LoadFromDB(uint32 guid, uint64 owner_guid, Field *fields);
|
||||||
virtual void DeleteFromDB();
|
virtual void DeleteFromDB();
|
||||||
void DeleteFromInventoryDB();
|
void DeleteFromInventoryDB();
|
||||||
|
void LoadLootFromDB(Field *fields);
|
||||||
|
|
||||||
bool IsBag() const { return GetProto()->InventoryType == INVTYPE_BAG; }
|
bool IsBag() const { return GetProto()->InventoryType == INVTYPE_BAG; }
|
||||||
bool IsBroken() const { return GetUInt32Value(ITEM_FIELD_MAXDURABILITY) > 0 && GetUInt32Value(ITEM_FIELD_DURABILITY) == 0; }
|
bool IsBroken() const { return GetUInt32Value(ITEM_FIELD_MAXDURABILITY) > 0 && GetUInt32Value(ITEM_FIELD_DURABILITY) == 0; }
|
||||||
|
|
@ -344,7 +355,10 @@ class MANGOS_DLL_SPEC Item : public Object
|
||||||
void RestoreCharges();
|
void RestoreCharges();
|
||||||
|
|
||||||
Loot loot;
|
Loot loot;
|
||||||
bool m_lootGenerated;
|
|
||||||
|
void SetLootState(ItemLootUpdateState state);
|
||||||
|
bool HasGeneratedLoot() const { return m_lootState != ITEM_LOOT_NONE && m_lootState != ITEM_LOOT_REMOVED; }
|
||||||
|
bool HasSavedLoot() const { return m_lootState != ITEM_LOOT_NONE && m_lootState != ITEM_LOOT_NEW && m_lootState != ITEM_LOOT_TEMPORARY; }
|
||||||
|
|
||||||
// Update States
|
// Update States
|
||||||
ItemUpdateState GetState() const { return uState; }
|
ItemUpdateState GetState() const { return uState; }
|
||||||
|
|
@ -373,5 +387,7 @@ class MANGOS_DLL_SPEC Item : public Object
|
||||||
ItemUpdateState uState;
|
ItemUpdateState uState;
|
||||||
int16 uQueuePos;
|
int16 uQueuePos;
|
||||||
bool mb_in_trade; // true if item is currently in trade-window
|
bool mb_in_trade; // true if item is currently in trade-window
|
||||||
|
ItemLootUpdateState m_lootState;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ void WorldSession::HandleAutostoreLootItemOpcode( WorldPacket & recv_data )
|
||||||
ObjectGuid lguid = player->GetLootGUID();
|
ObjectGuid lguid = player->GetLootGUID();
|
||||||
Loot *loot;
|
Loot *loot;
|
||||||
uint8 lootSlot;
|
uint8 lootSlot;
|
||||||
|
Item* pItem = NULL;
|
||||||
|
|
||||||
recv_data >> lootSlot;
|
recv_data >> lootSlot;
|
||||||
|
|
||||||
|
|
@ -59,9 +60,9 @@ void WorldSession::HandleAutostoreLootItemOpcode( WorldPacket & recv_data )
|
||||||
}
|
}
|
||||||
case HIGHGUID_ITEM:
|
case HIGHGUID_ITEM:
|
||||||
{
|
{
|
||||||
Item *pItem = player->GetItemByGuid( lguid );
|
pItem = player->GetItemByGuid( lguid );
|
||||||
|
|
||||||
if (!pItem)
|
if (!pItem || !pItem->HasGeneratedLoot())
|
||||||
{
|
{
|
||||||
player->SendLootRelease(lguid);
|
player->SendLootRelease(lguid);
|
||||||
return;
|
return;
|
||||||
|
|
@ -122,6 +123,9 @@ void WorldSession::HandleAutostoreLootItemOpcode( WorldPacket & recv_data )
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pItem)
|
||||||
|
pItem->SetLootState(ITEM_LOOT_CHANGED);
|
||||||
|
|
||||||
ItemPosCountVec dest;
|
ItemPosCountVec dest;
|
||||||
uint8 msg = player->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, item->itemid, item->count );
|
uint8 msg = player->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, item->itemid, item->count );
|
||||||
if ( msg == EQUIP_ERR_OK )
|
if ( msg == EQUIP_ERR_OK )
|
||||||
|
|
@ -179,6 +183,7 @@ void WorldSession::HandleLootMoneyOpcode( WorldPacket & /*recv_data*/ )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Loot *pLoot = NULL;
|
Loot *pLoot = NULL;
|
||||||
|
Item* pItem = NULL;
|
||||||
|
|
||||||
switch(guid.GetHigh())
|
switch(guid.GetHigh())
|
||||||
{
|
{
|
||||||
|
|
@ -203,8 +208,11 @@ void WorldSession::HandleLootMoneyOpcode( WorldPacket & /*recv_data*/ )
|
||||||
}
|
}
|
||||||
case HIGHGUID_ITEM:
|
case HIGHGUID_ITEM:
|
||||||
{
|
{
|
||||||
if(Item *item = GetPlayer()->GetItemByGuid(guid))
|
pItem = GetPlayer()->GetItemByGuid(guid);
|
||||||
pLoot = &item->loot;
|
if (!pItem || !pItem->HasGeneratedLoot())
|
||||||
|
return;
|
||||||
|
|
||||||
|
pLoot = &pItem->loot;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case HIGHGUID_UNIT:
|
case HIGHGUID_UNIT:
|
||||||
|
|
@ -255,7 +263,12 @@ void WorldSession::HandleLootMoneyOpcode( WorldPacket & /*recv_data*/ )
|
||||||
player->ModifyMoney( pLoot->gold );
|
player->ModifyMoney( pLoot->gold );
|
||||||
player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY, pLoot->gold);
|
player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY, pLoot->gold);
|
||||||
}
|
}
|
||||||
|
|
||||||
pLoot->gold = 0;
|
pLoot->gold = 0;
|
||||||
|
|
||||||
|
if (pItem)
|
||||||
|
pItem->SetLootState(ITEM_LOOT_CHANGED);
|
||||||
|
|
||||||
pLoot->NotifyMoneyRemoved();
|
pLoot->NotifyMoneyRemoved();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -400,29 +413,44 @@ void WorldSession::DoLootRelease(ObjectGuid lguid)
|
||||||
case HIGHGUID_ITEM:
|
case HIGHGUID_ITEM:
|
||||||
{
|
{
|
||||||
Item *pItem = player->GetItemByGuid(lguid );
|
Item *pItem = player->GetItemByGuid(lguid );
|
||||||
if(!pItem)
|
if (!pItem)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ItemPrototype const* proto = pItem->GetProto();
|
ItemPrototype const* proto = pItem->GetProto();
|
||||||
|
|
||||||
// destroy only 5 items from stack in case prospecting and milling
|
// destroy only 5 items from stack in case prospecting and milling
|
||||||
if ((proto->Flags & (ITEM_FLAG_PROSPECTABLE | ITEM_FLAG_MILLABLE)))
|
switch (pItem->loot.loot_type)
|
||||||
{
|
{
|
||||||
pItem->m_lootGenerated = false;
|
case LOOT_MILLING:
|
||||||
pItem->loot.clear();
|
case LOOT_PROSPECTING:
|
||||||
|
{
|
||||||
|
uint32 count = pItem->GetCount();
|
||||||
|
|
||||||
uint32 count = pItem->GetCount();
|
// >=5 checked in spell code, but will work for cheating cases also with removing from another stacks.
|
||||||
|
if(count > 5)
|
||||||
|
count = 5;
|
||||||
|
|
||||||
// >=5 checked in spell code, but will work for cheating cases also with removing from another stacks.
|
player->DestroyItemCount(pItem, count, true);
|
||||||
if(count > 5)
|
break;
|
||||||
count = 5;
|
}
|
||||||
|
case LOOT_DISENCHANTING:
|
||||||
player->DestroyItemCount(pItem, count, true);
|
{
|
||||||
|
if (!pItem->loot.isLooted())
|
||||||
|
player->AutoStoreLoot(pItem->loot); // can be lost if no space
|
||||||
|
pItem->loot.clear();
|
||||||
|
pItem->SetLootState(ITEM_LOOT_REMOVED);
|
||||||
|
player->DestroyItem( pItem->GetBagSlot(),pItem->GetSlot(), true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// must be destroyed only if no loot
|
||||||
|
if (pItem->loot.isLooted())
|
||||||
|
player->DestroyItem( pItem->GetBagSlot(),pItem->GetSlot(), true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
return; // item can be looted only single player
|
||||||
// FIXME: item don't must be deleted in case not fully looted state. But this pre-request implement loot saving in DB at item save. Or checting possible.
|
|
||||||
player->DestroyItem( pItem->GetBagSlot(),pItem->GetSlot(), true);
|
|
||||||
return; // item can be looted only single player
|
|
||||||
}
|
}
|
||||||
case HIGHGUID_UNIT:
|
case HIGHGUID_UNIT:
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -333,6 +333,25 @@ LootItem::LootItem(LootStoreItem const& li)
|
||||||
is_counted = 0;
|
is_counted = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LootItem::LootItem(uint32 itemid_, uint32 count_, uint32 randomSuffix_, int32 randomPropertyId_)
|
||||||
|
{
|
||||||
|
itemid = itemid_;
|
||||||
|
conditionId = 0;
|
||||||
|
|
||||||
|
ItemPrototype const* proto = ObjectMgr::GetItemPrototype(itemid);
|
||||||
|
freeforall = proto && (proto->Flags & ITEM_FLAG_PARTY_LOOT);
|
||||||
|
|
||||||
|
needs_quest = false;
|
||||||
|
|
||||||
|
count = count_;
|
||||||
|
randomSuffix = randomSuffix_;
|
||||||
|
randomPropertyId = randomPropertyId_;
|
||||||
|
is_looted = 0;
|
||||||
|
is_blocked = 0;
|
||||||
|
is_underthreshold = 0;
|
||||||
|
is_counted = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Basic checks for player/item compatibility - if false no chance to see the item in the loot
|
// Basic checks for player/item compatibility - if false no chance to see the item in the loot
|
||||||
bool LootItem::AllowedForPlayer(Player const * player) const
|
bool LootItem::AllowedForPlayer(Player const * player) const
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -97,6 +97,8 @@ struct LootItem
|
||||||
// Should be called for non-reference LootStoreItem entries only (mincountOrRef > 0)
|
// Should be called for non-reference LootStoreItem entries only (mincountOrRef > 0)
|
||||||
explicit LootItem(LootStoreItem const& li);
|
explicit LootItem(LootStoreItem const& li);
|
||||||
|
|
||||||
|
LootItem(uint32 itemid_, uint32 count_, uint32 randomSuffix_ = 0, int32 randomPropertyId_ = 0);
|
||||||
|
|
||||||
// Basic checks for player/item compatibility - if false no chance to see the item in the loot
|
// Basic checks for player/item compatibility - if false no chance to see the item in the loot
|
||||||
bool AllowedForPlayer(Player const * player) const;
|
bool AllowedForPlayer(Player const * player) const;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1927,6 +1927,35 @@ void ObjectMgr::LoadItemPrototypes()
|
||||||
const_cast<ItemPrototype*>(proto)->InventoryType = INVTYPE_NON_EQUIP;
|
const_cast<ItemPrototype*>(proto)->InventoryType = INVTYPE_NON_EQUIP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (proto->InventoryType != INVTYPE_NON_EQUIP)
|
||||||
|
{
|
||||||
|
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->Flags & ITEM_FLAG_MILLABLE)
|
||||||
|
{
|
||||||
|
sLog.outErrorDb("Item container (Entry: %u) has not allowed for containers flag ITEM_FLAG_MILLABLE (%u), flag removed.", i, ITEM_FLAG_MILLABLE);
|
||||||
|
const_cast<ItemPrototype*>(proto)->Flags &= ~ITEM_FLAG_MILLABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(proto->Flags & ITEM_FLAG_PROSPECTABLE)
|
||||||
|
{
|
||||||
|
sLog.outErrorDb("Item container (Entry: %u) has not allowed for containers flag ITEM_FLAG_PROSPECTABLE (%u), flag removed.", i, ITEM_FLAG_PROSPECTABLE);
|
||||||
|
const_cast<ItemPrototype*>(proto)->Flags &= ~ITEM_FLAG_PROSPECTABLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (proto->InventoryType != INVTYPE_BAG)
|
||||||
|
{
|
||||||
|
if (proto->ContainerSlots > 0)
|
||||||
|
{
|
||||||
|
sLog.outErrorDb("Non-container item (Entry: %u) has ContainerSlots (%u), set to 0.", i, proto->ContainerSlots);
|
||||||
|
const_cast<ItemPrototype*>(proto)->ContainerSlots = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(proto->RequiredSkill >= MAX_SKILL_TYPE)
|
if(proto->RequiredSkill >= MAX_SKILL_TYPE)
|
||||||
{
|
{
|
||||||
sLog.outErrorDb("Item (Entry: %u) has wrong RequiredSkill value (%u)",i,proto->RequiredSkill);
|
sLog.outErrorDb("Item (Entry: %u) has wrong RequiredSkill value (%u)",i,proto->RequiredSkill);
|
||||||
|
|
@ -2005,17 +2034,11 @@ void ObjectMgr::LoadItemPrototypes()
|
||||||
|
|
||||||
if (proto->ContainerSlots)
|
if (proto->ContainerSlots)
|
||||||
{
|
{
|
||||||
if(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);
|
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;
|
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)
|
if(proto->StatsCount > MAX_ITEM_PROTO_STATS)
|
||||||
|
|
|
||||||
|
|
@ -4254,7 +4254,7 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe
|
||||||
}
|
}
|
||||||
|
|
||||||
Item *pItem = NewItemOrBag(itemProto);
|
Item *pItem = NewItemOrBag(itemProto);
|
||||||
if (!pItem->LoadFromDB(item_guidlow, playerguid.GetRawValue(), resultItems))
|
if (!pItem->LoadFromDB(item_guidlow, playerguid.GetRawValue(), fields2))
|
||||||
{
|
{
|
||||||
pItem->FSetState(ITEM_REMOVED);
|
pItem->FSetState(ITEM_REMOVED);
|
||||||
pItem->SaveToDB(); // it also deletes item object !
|
pItem->SaveToDB(); // it also deletes item object !
|
||||||
|
|
@ -7897,25 +7897,28 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type)
|
||||||
|
|
||||||
loot = &item->loot;
|
loot = &item->loot;
|
||||||
|
|
||||||
if (!item->m_lootGenerated)
|
if (!item->HasGeneratedLoot())
|
||||||
{
|
{
|
||||||
item->m_lootGenerated = true;
|
item->loot.clear();
|
||||||
loot->clear();
|
|
||||||
|
|
||||||
switch(loot_type)
|
switch(loot_type)
|
||||||
{
|
{
|
||||||
case LOOT_DISENCHANTING:
|
case LOOT_DISENCHANTING:
|
||||||
loot->FillLoot(item->GetProto()->DisenchantID, LootTemplates_Disenchant, this,true);
|
loot->FillLoot(item->GetProto()->DisenchantID, LootTemplates_Disenchant, this,true);
|
||||||
|
item->SetLootState(ITEM_LOOT_TEMPORARY);
|
||||||
break;
|
break;
|
||||||
case LOOT_PROSPECTING:
|
case LOOT_PROSPECTING:
|
||||||
loot->FillLoot(item->GetEntry(), LootTemplates_Prospecting, this,true);
|
loot->FillLoot(item->GetEntry(), LootTemplates_Prospecting, this,true);
|
||||||
|
item->SetLootState(ITEM_LOOT_TEMPORARY);
|
||||||
break;
|
break;
|
||||||
case LOOT_MILLING:
|
case LOOT_MILLING:
|
||||||
loot->FillLoot(item->GetEntry(), LootTemplates_Milling, this,true);
|
loot->FillLoot(item->GetEntry(), LootTemplates_Milling, this,true);
|
||||||
|
item->SetLootState(ITEM_LOOT_TEMPORARY);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
loot->FillLoot(item->GetEntry(), LootTemplates_Item, this,true);
|
loot->FillLoot(item->GetEntry(), LootTemplates_Item, this,true);
|
||||||
loot->generateMoneyLoot(item->GetProto()->MinMoneyLoot,item->GetProto()->MaxMoneyLoot);
|
loot->generateMoneyLoot(item->GetProto()->MinMoneyLoot,item->GetProto()->MaxMoneyLoot);
|
||||||
|
item->SetLootState(ITEM_LOOT_CHANGED);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -9621,14 +9624,6 @@ uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint3
|
||||||
|
|
||||||
if (pItem)
|
if (pItem)
|
||||||
{
|
{
|
||||||
// item used
|
|
||||||
if(pItem->m_lootGenerated)
|
|
||||||
{
|
|
||||||
if (no_space_count)
|
|
||||||
*no_space_count = count;
|
|
||||||
return EQUIP_ERR_ALREADY_LOOTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pItem->IsBindedNotWith(this))
|
if (pItem->IsBindedNotWith(this))
|
||||||
{
|
{
|
||||||
if (no_space_count)
|
if (no_space_count)
|
||||||
|
|
@ -10116,10 +10111,6 @@ uint8 Player::CanStoreItems( Item **pItems,int count) const
|
||||||
if( !pProto )
|
if( !pProto )
|
||||||
return EQUIP_ERR_ITEM_NOT_FOUND;
|
return EQUIP_ERR_ITEM_NOT_FOUND;
|
||||||
|
|
||||||
// item used
|
|
||||||
if(pItem->m_lootGenerated)
|
|
||||||
return EQUIP_ERR_ALREADY_LOOTED;
|
|
||||||
|
|
||||||
// item it 'bind'
|
// item it 'bind'
|
||||||
if(pItem->IsBindedNotWith(this))
|
if(pItem->IsBindedNotWith(this))
|
||||||
return EQUIP_ERR_DONT_OWN_THAT_ITEM;
|
return EQUIP_ERR_DONT_OWN_THAT_ITEM;
|
||||||
|
|
@ -10323,10 +10314,6 @@ uint8 Player::CanEquipItem( uint8 slot, uint16 &dest, Item *pItem, bool swap, bo
|
||||||
ItemPrototype const *pProto = pItem->GetProto();
|
ItemPrototype const *pProto = pItem->GetProto();
|
||||||
if( pProto )
|
if( pProto )
|
||||||
{
|
{
|
||||||
// item used
|
|
||||||
if(pItem->m_lootGenerated)
|
|
||||||
return EQUIP_ERR_ALREADY_LOOTED;
|
|
||||||
|
|
||||||
if(pItem->IsBindedNotWith(this))
|
if(pItem->IsBindedNotWith(this))
|
||||||
return EQUIP_ERR_DONT_OWN_THAT_ITEM;
|
return EQUIP_ERR_DONT_OWN_THAT_ITEM;
|
||||||
|
|
||||||
|
|
@ -10455,25 +10442,21 @@ uint8 Player::CanEquipItem( uint8 slot, uint16 &dest, Item *pItem, bool swap, bo
|
||||||
uint8 Player::CanUnequipItem( uint16 pos, bool swap ) const
|
uint8 Player::CanUnequipItem( uint16 pos, bool swap ) const
|
||||||
{
|
{
|
||||||
// Applied only to equipped items and bank bags
|
// Applied only to equipped items and bank bags
|
||||||
if(!IsEquipmentPos(pos) && !IsBagPos(pos))
|
if (!IsEquipmentPos(pos) && !IsBagPos(pos))
|
||||||
return EQUIP_ERR_OK;
|
return EQUIP_ERR_OK;
|
||||||
|
|
||||||
Item* pItem = GetItemByPos(pos);
|
Item* pItem = GetItemByPos(pos);
|
||||||
|
|
||||||
// Applied only to existing equipped item
|
// Applied only to existing equipped item
|
||||||
if( !pItem )
|
if (!pItem)
|
||||||
return EQUIP_ERR_OK;
|
return EQUIP_ERR_OK;
|
||||||
|
|
||||||
DEBUG_LOG( "STORAGE: CanUnequipItem slot = %u, item = %u, count = %u", pos, pItem->GetEntry(), pItem->GetCount());
|
DEBUG_LOG( "STORAGE: CanUnequipItem slot = %u, item = %u, count = %u", pos, pItem->GetEntry(), pItem->GetCount());
|
||||||
|
|
||||||
ItemPrototype const *pProto = pItem->GetProto();
|
ItemPrototype const *pProto = pItem->GetProto();
|
||||||
if( !pProto )
|
if (!pProto)
|
||||||
return EQUIP_ERR_ITEM_NOT_FOUND;
|
return EQUIP_ERR_ITEM_NOT_FOUND;
|
||||||
|
|
||||||
// item used
|
|
||||||
if(pItem->m_lootGenerated)
|
|
||||||
return EQUIP_ERR_ALREADY_LOOTED;
|
|
||||||
|
|
||||||
// do not allow unequipping gear except weapons, offhands, projectiles, relics in
|
// do not allow unequipping gear except weapons, offhands, projectiles, relics in
|
||||||
// - combat
|
// - combat
|
||||||
// - in-progress arenas
|
// - in-progress arenas
|
||||||
|
|
@ -10505,10 +10488,6 @@ uint8 Player::CanBankItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, Item *p
|
||||||
if (!pProto)
|
if (!pProto)
|
||||||
return swap ? EQUIP_ERR_ITEMS_CANT_BE_SWAPPED : EQUIP_ERR_ITEM_NOT_FOUND;
|
return swap ? EQUIP_ERR_ITEMS_CANT_BE_SWAPPED : EQUIP_ERR_ITEM_NOT_FOUND;
|
||||||
|
|
||||||
// item used
|
|
||||||
if(pItem->m_lootGenerated)
|
|
||||||
return EQUIP_ERR_ALREADY_LOOTED;
|
|
||||||
|
|
||||||
if (pItem->IsBindedNotWith(this))
|
if (pItem->IsBindedNotWith(this))
|
||||||
return EQUIP_ERR_DONT_OWN_THAT_ITEM;
|
return EQUIP_ERR_DONT_OWN_THAT_ITEM;
|
||||||
|
|
||||||
|
|
@ -11593,13 +11572,13 @@ void Player::SplitItem( uint16 src, uint16 dst, uint32 count )
|
||||||
uint8 dstslot = dst & 255;
|
uint8 dstslot = dst & 255;
|
||||||
|
|
||||||
Item *pSrcItem = GetItemByPos( srcbag, srcslot );
|
Item *pSrcItem = GetItemByPos( srcbag, srcslot );
|
||||||
if( !pSrcItem )
|
if (!pSrcItem)
|
||||||
{
|
{
|
||||||
SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, pSrcItem, NULL );
|
SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, pSrcItem, NULL );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(pSrcItem->m_lootGenerated) // prevent split looting item (item
|
if (pSrcItem->HasGeneratedLoot()) // prevent split looting item (stackable items can has only temporary loot and this meaning that loot window open)
|
||||||
{
|
{
|
||||||
//best error message found for attempting to split while looting
|
//best error message found for attempting to split while looting
|
||||||
SendEquipError( EQUIP_ERR_COULDNT_SPLIT_ITEMS, pSrcItem, NULL );
|
SendEquipError( EQUIP_ERR_COULDNT_SPLIT_ITEMS, pSrcItem, NULL );
|
||||||
|
|
@ -11607,14 +11586,14 @@ void Player::SplitItem( uint16 src, uint16 dst, uint32 count )
|
||||||
}
|
}
|
||||||
|
|
||||||
// not let split all items (can be only at cheating)
|
// not let split all items (can be only at cheating)
|
||||||
if(pSrcItem->GetCount() == count)
|
if (pSrcItem->GetCount() == count)
|
||||||
{
|
{
|
||||||
SendEquipError( EQUIP_ERR_COULDNT_SPLIT_ITEMS, pSrcItem, NULL );
|
SendEquipError( EQUIP_ERR_COULDNT_SPLIT_ITEMS, pSrcItem, NULL );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// not let split more existing items (can be only at cheating)
|
// not let split more existing items (can be only at cheating)
|
||||||
if(pSrcItem->GetCount() < count)
|
if (pSrcItem->GetCount() < count)
|
||||||
{
|
{
|
||||||
SendEquipError( EQUIP_ERR_TRIED_TO_SPLIT_MORE_THAN_COUNT, pSrcItem, NULL );
|
SendEquipError( EQUIP_ERR_TRIED_TO_SPLIT_MORE_THAN_COUNT, pSrcItem, NULL );
|
||||||
return;
|
return;
|
||||||
|
|
@ -11622,20 +11601,20 @@ void Player::SplitItem( uint16 src, uint16 dst, uint32 count )
|
||||||
|
|
||||||
DEBUG_LOG( "STORAGE: SplitItem bag = %u, slot = %u, item = %u, count = %u", dstbag, dstslot, pSrcItem->GetEntry(), count);
|
DEBUG_LOG( "STORAGE: SplitItem bag = %u, slot = %u, item = %u, count = %u", dstbag, dstslot, pSrcItem->GetEntry(), count);
|
||||||
Item *pNewItem = pSrcItem->CloneItem( count, this );
|
Item *pNewItem = pSrcItem->CloneItem( count, this );
|
||||||
if( !pNewItem )
|
if (!pNewItem)
|
||||||
{
|
{
|
||||||
SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, pSrcItem, NULL );
|
SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, pSrcItem, NULL );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( IsInventoryPos( dst ) )
|
if (IsInventoryPos(dst))
|
||||||
{
|
{
|
||||||
// change item amount before check (for unique max count check)
|
// change item amount before check (for unique max count check)
|
||||||
pSrcItem->SetCount( pSrcItem->GetCount() - count );
|
pSrcItem->SetCount( pSrcItem->GetCount() - count );
|
||||||
|
|
||||||
ItemPosCountVec dest;
|
ItemPosCountVec dest;
|
||||||
uint8 msg = CanStoreItem( dstbag, dstslot, dest, pNewItem, false );
|
uint8 msg = CanStoreItem( dstbag, dstslot, dest, pNewItem, false );
|
||||||
if( msg != EQUIP_ERR_OK )
|
if (msg != EQUIP_ERR_OK)
|
||||||
{
|
{
|
||||||
delete pNewItem;
|
delete pNewItem;
|
||||||
pSrcItem->SetCount( pSrcItem->GetCount() + count );
|
pSrcItem->SetCount( pSrcItem->GetCount() + count );
|
||||||
|
|
@ -11643,12 +11622,12 @@ void Player::SplitItem( uint16 src, uint16 dst, uint32 count )
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( IsInWorld() )
|
if (IsInWorld())
|
||||||
pSrcItem->SendCreateUpdateToPlayer( this );
|
pSrcItem->SendCreateUpdateToPlayer( this );
|
||||||
pSrcItem->SetState(ITEM_CHANGED, this);
|
pSrcItem->SetState(ITEM_CHANGED, this);
|
||||||
StoreItem( dest, pNewItem, true);
|
StoreItem( dest, pNewItem, true);
|
||||||
}
|
}
|
||||||
else if( IsBankPos ( dst ) )
|
else if (IsBankPos (dst))
|
||||||
{
|
{
|
||||||
// change item amount before check (for unique max count check)
|
// change item amount before check (for unique max count check)
|
||||||
pSrcItem->SetCount( pSrcItem->GetCount() - count );
|
pSrcItem->SetCount( pSrcItem->GetCount() - count );
|
||||||
|
|
@ -11663,19 +11642,19 @@ void Player::SplitItem( uint16 src, uint16 dst, uint32 count )
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( IsInWorld() )
|
if (IsInWorld())
|
||||||
pSrcItem->SendCreateUpdateToPlayer( this );
|
pSrcItem->SendCreateUpdateToPlayer( this );
|
||||||
pSrcItem->SetState(ITEM_CHANGED, this);
|
pSrcItem->SetState(ITEM_CHANGED, this);
|
||||||
BankItem( dest, pNewItem, true);
|
BankItem( dest, pNewItem, true);
|
||||||
}
|
}
|
||||||
else if( IsEquipmentPos ( dst ) )
|
else if (IsEquipmentPos (dst))
|
||||||
{
|
{
|
||||||
// change item amount before check (for unique max count check), provide space for splitted items
|
// change item amount before check (for unique max count check), provide space for splitted items
|
||||||
pSrcItem->SetCount( pSrcItem->GetCount() - count );
|
pSrcItem->SetCount( pSrcItem->GetCount() - count );
|
||||||
|
|
||||||
uint16 dest;
|
uint16 dest;
|
||||||
uint8 msg = CanEquipItem( dstslot, dest, pNewItem, false );
|
uint8 msg = CanEquipItem( dstslot, dest, pNewItem, false );
|
||||||
if( msg != EQUIP_ERR_OK )
|
if (msg != EQUIP_ERR_OK)
|
||||||
{
|
{
|
||||||
delete pNewItem;
|
delete pNewItem;
|
||||||
pSrcItem->SetCount( pSrcItem->GetCount() + count );
|
pSrcItem->SetCount( pSrcItem->GetCount() + count );
|
||||||
|
|
@ -11683,7 +11662,7 @@ void Player::SplitItem( uint16 src, uint16 dst, uint32 count )
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( IsInWorld() )
|
if (IsInWorld())
|
||||||
pSrcItem->SendCreateUpdateToPlayer( this );
|
pSrcItem->SendCreateUpdateToPlayer( this );
|
||||||
pSrcItem->SetState(ITEM_CHANGED, this);
|
pSrcItem->SetState(ITEM_CHANGED, this);
|
||||||
EquipItem( dest, pNewItem, true);
|
EquipItem( dest, pNewItem, true);
|
||||||
|
|
@ -15492,6 +15471,7 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
|
||||||
m_reputationMgr.LoadFromDB(holder->GetResult(PLAYER_LOGIN_QUERY_LOADREPUTATION));
|
m_reputationMgr.LoadFromDB(holder->GetResult(PLAYER_LOGIN_QUERY_LOADREPUTATION));
|
||||||
|
|
||||||
_LoadInventory(holder->GetResult(PLAYER_LOGIN_QUERY_LOADINVENTORY), time_diff);
|
_LoadInventory(holder->GetResult(PLAYER_LOGIN_QUERY_LOADINVENTORY), time_diff);
|
||||||
|
_LoadItemLoot(holder->GetResult(PLAYER_LOGIN_QUERY_LOADITEMLOOT));
|
||||||
|
|
||||||
// update items with duration and realtime
|
// update items with duration and realtime
|
||||||
UpdateItemDuration(time_diff, true);
|
UpdateItemDuration(time_diff, true);
|
||||||
|
|
@ -15903,7 +15883,7 @@ void Player::_LoadInventory(QueryResult *result, uint32 timediff)
|
||||||
|
|
||||||
Item *item = NewItemOrBag(proto);
|
Item *item = NewItemOrBag(proto);
|
||||||
|
|
||||||
if(!item->LoadFromDB(item_guid, GetGUID(), result))
|
if(!item->LoadFromDB(item_guid, GetGUID(), fields))
|
||||||
{
|
{
|
||||||
sLog.outError( "Player::_LoadInventory: Player %s has broken item (id: #%u) in inventory, deleted.", GetName(),item_id );
|
sLog.outError( "Player::_LoadInventory: Player %s has broken item (id: #%u) in inventory, deleted.", GetName(),item_id );
|
||||||
CharacterDatabase.PExecute("DELETE FROM character_inventory WHERE item = '%u'", item_guid);
|
CharacterDatabase.PExecute("DELETE FROM character_inventory WHERE item = '%u'", item_guid);
|
||||||
|
|
@ -16027,10 +16007,39 @@ void Player::_LoadInventory(QueryResult *result, uint32 timediff)
|
||||||
draft.SendMailTo(this, MailSender(this, MAIL_STATIONERY_GM), MAIL_CHECK_MASK_COPIED);
|
draft.SendMailTo(this, MailSender(this, MAIL_STATIONERY_GM), MAIL_CHECK_MASK_COPIED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//if(isAlive())
|
//if(isAlive())
|
||||||
_ApplyAllItemMods();
|
_ApplyAllItemMods();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Player::_LoadItemLoot(QueryResult *result)
|
||||||
|
{
|
||||||
|
//QueryResult *result = CharacterDatabase.PQuery("SELECT guid,itemid,amount,suffix,property FROM item_loot WHERE guid = '%u'", GetGUIDLow());
|
||||||
|
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
Field *fields = result->Fetch();
|
||||||
|
uint32 item_guid = fields[0].GetUInt32();
|
||||||
|
|
||||||
|
Item* item = GetItemByGuid(ObjectGuid(HIGHGUID_ITEM, item_guid));
|
||||||
|
|
||||||
|
if (!item)
|
||||||
|
{
|
||||||
|
CharacterDatabase.PExecute("DELETE FROM item_loot WHERE guid = '%u'", item_guid);
|
||||||
|
sLog.outError("Player::_LoadItemLoot: Player %s has loot for not existed item (GUID: %u) in `item_loot`, deleted.", GetName(), item_guid );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
item->LoadLootFromDB(fields);
|
||||||
|
|
||||||
|
} while (result->NextRow());
|
||||||
|
|
||||||
|
delete result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// load mailed item which should receive current player
|
// load mailed item which should receive current player
|
||||||
void Player::_LoadMailedItems(QueryResult *result)
|
void Player::_LoadMailedItems(QueryResult *result)
|
||||||
{
|
{
|
||||||
|
|
@ -16064,7 +16073,7 @@ void Player::_LoadMailedItems(QueryResult *result)
|
||||||
|
|
||||||
Item *item = NewItemOrBag(proto);
|
Item *item = NewItemOrBag(proto);
|
||||||
|
|
||||||
if(!item->LoadFromDB(item_guid_low, 0, result))
|
if(!item->LoadFromDB(item_guid_low, 0, fields))
|
||||||
{
|
{
|
||||||
sLog.outError( "Player::_LoadMailedItems - Item in mail (%u) doesn't exist !!!! - item guid: %u, deleted from mail", mail->messageID, item_guid_low);
|
sLog.outError( "Player::_LoadMailedItems - Item in mail (%u) doesn't exist !!!! - item guid: %u, deleted from mail", mail->messageID, item_guid_low);
|
||||||
CharacterDatabase.PExecute("DELETE FROM mail_items WHERE item_guid = '%u'", item_guid_low);
|
CharacterDatabase.PExecute("DELETE FROM mail_items WHERE item_guid = '%u'", item_guid_low);
|
||||||
|
|
@ -21175,11 +21184,16 @@ bool Player::IsBaseRuneSlotsOnCooldown( RuneType runeType ) const
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::AutoStoreLoot(uint8 bag, uint8 slot, uint32 loot_id, LootStore const& store, bool broadcast)
|
void Player::AutoStoreLoot(uint32 loot_id, LootStore const& store, bool broadcast, uint8 bag, uint8 slot)
|
||||||
{
|
{
|
||||||
Loot loot;
|
Loot loot;
|
||||||
loot.FillLoot (loot_id,store,this,true);
|
loot.FillLoot (loot_id, store, this, true);
|
||||||
|
|
||||||
|
AutoStoreLoot(loot, broadcast, bag, slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Player::AutoStoreLoot(Loot& loot, bool broadcast, uint8 bag, uint8 slot)
|
||||||
|
{
|
||||||
uint32 max_slot = loot.GetMaxSlotInLootFor(this);
|
uint32 max_slot = loot.GetMaxSlotInLootFor(this);
|
||||||
for(uint32 i = 0; i < max_slot; ++i)
|
for(uint32 i = 0; i < max_slot; ++i)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -896,6 +896,7 @@ enum PlayerLoginQueryIndex
|
||||||
PLAYER_LOGIN_QUERY_LOADDAILYQUESTSTATUS,
|
PLAYER_LOGIN_QUERY_LOADDAILYQUESTSTATUS,
|
||||||
PLAYER_LOGIN_QUERY_LOADREPUTATION,
|
PLAYER_LOGIN_QUERY_LOADREPUTATION,
|
||||||
PLAYER_LOGIN_QUERY_LOADINVENTORY,
|
PLAYER_LOGIN_QUERY_LOADINVENTORY,
|
||||||
|
PLAYER_LOGIN_QUERY_LOADITEMLOOT,
|
||||||
PLAYER_LOGIN_QUERY_LOADACTIONS,
|
PLAYER_LOGIN_QUERY_LOADACTIONS,
|
||||||
PLAYER_LOGIN_QUERY_LOADSOCIALLIST,
|
PLAYER_LOGIN_QUERY_LOADSOCIALLIST,
|
||||||
PLAYER_LOGIN_QUERY_LOADHOMEBIND,
|
PLAYER_LOGIN_QUERY_LOADHOMEBIND,
|
||||||
|
|
@ -1299,8 +1300,8 @@ class MANGOS_DLL_SPEC Player : public Unit
|
||||||
bool StoreNewItemInBestSlots(uint32 item_id, uint32 item_count);
|
bool StoreNewItemInBestSlots(uint32 item_id, uint32 item_count);
|
||||||
Item* StoreNewItemInInventorySlot(uint32 itemEntry, uint32 amount);
|
Item* StoreNewItemInInventorySlot(uint32 itemEntry, uint32 amount);
|
||||||
|
|
||||||
void AutoStoreLoot(uint8 bag, uint8 slot, uint32 loot_id, LootStore const& store, bool broadcast = false);
|
void AutoStoreLoot(uint32 loot_id, LootStore const& store, bool broadcast = false, uint8 bag = NULL_BAG, uint8 slot = NULL_SLOT);
|
||||||
void AutoStoreLoot(uint32 loot_id, LootStore const& store, bool broadcast = false) { AutoStoreLoot(NULL_BAG,NULL_SLOT,loot_id,store,broadcast); }
|
void AutoStoreLoot(Loot& loot, bool broadcast = false, uint8 bag = NULL_BAG, uint8 slot = NULL_SLOT);
|
||||||
|
|
||||||
uint8 _CanTakeMoreSimilarItems(uint32 entry, uint32 count, Item* pItem, uint32* no_space_count = NULL) const;
|
uint8 _CanTakeMoreSimilarItems(uint32 entry, uint32 count, Item* pItem, uint32* no_space_count = NULL) const;
|
||||||
uint8 _CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec& dest, uint32 entry, uint32 count, Item *pItem = NULL, bool swap = false, uint32* no_space_count = NULL ) const;
|
uint8 _CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec& dest, uint32 entry, uint32 count, Item *pItem = NULL, bool swap = false, uint32* no_space_count = NULL ) const;
|
||||||
|
|
@ -2442,6 +2443,7 @@ class MANGOS_DLL_SPEC Player : public Unit
|
||||||
void _LoadAuras(QueryResult *result, uint32 timediff);
|
void _LoadAuras(QueryResult *result, uint32 timediff);
|
||||||
void _LoadBoundInstances(QueryResult *result);
|
void _LoadBoundInstances(QueryResult *result);
|
||||||
void _LoadInventory(QueryResult *result, uint32 timediff);
|
void _LoadInventory(QueryResult *result, uint32 timediff);
|
||||||
|
void _LoadItemLoot(QueryResult *result);
|
||||||
void _LoadMails(QueryResult *result);
|
void _LoadMails(QueryResult *result);
|
||||||
void _LoadMailedItems(QueryResult *result);
|
void _LoadMailedItems(QueryResult *result);
|
||||||
void _LoadQuestStatus(QueryResult *result);
|
void _LoadQuestStatus(QueryResult *result);
|
||||||
|
|
|
||||||
|
|
@ -4989,34 +4989,43 @@ SpellCastResult Spell::CheckCast(bool strict)
|
||||||
}
|
}
|
||||||
case SPELL_EFFECT_OPEN_LOCK:
|
case SPELL_EFFECT_OPEN_LOCK:
|
||||||
{
|
{
|
||||||
if( m_spellInfo->EffectImplicitTargetA[i] != TARGET_GAMEOBJECT &&
|
if (m_caster->GetTypeId() != TYPEID_PLAYER) // only players can open locks, gather etc.
|
||||||
m_spellInfo->EffectImplicitTargetA[i] != TARGET_GAMEOBJECT_ITEM )
|
|
||||||
break;
|
|
||||||
|
|
||||||
if( m_caster->GetTypeId() != TYPEID_PLAYER // only players can open locks, gather etc.
|
|
||||||
// we need a go target in case of TARGET_GAMEOBJECT
|
|
||||||
|| 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()->GetOwner() != m_caster ||
|
|
||||||
!m_targets.getItemTarget()->GetProto()->LockID || m_targets.getItemTarget()->HasFlag(ITEM_FIELD_FLAGS, ITEM_DYNFLAG_UNLOCKED)))
|
|
||||||
return SPELL_FAILED_BAD_TARGETS;
|
return SPELL_FAILED_BAD_TARGETS;
|
||||||
|
|
||||||
// In BattleGround players can use only flags and banners
|
// we need a go target in case of TARGET_GAMEOBJECT (for other targets acceptable GO and items)
|
||||||
if( ((Player*)m_caster)->InBattleGround() &&
|
if (m_spellInfo->EffectImplicitTargetA[i] == TARGET_GAMEOBJECT)
|
||||||
!((Player*)m_caster)->CanUseBattleGroundObject() )
|
{
|
||||||
return SPELL_FAILED_TRY_AGAIN;
|
if (!m_targets.getGOTarget())
|
||||||
|
return SPELL_FAILED_BAD_TARGETS;
|
||||||
|
}
|
||||||
|
|
||||||
// get the lock entry
|
// get the lock entry
|
||||||
uint32 lockId = 0;
|
uint32 lockId = 0;
|
||||||
if (GameObject* go = m_targets.getGOTarget())
|
if (GameObject* go = m_targets.getGOTarget())
|
||||||
{
|
{
|
||||||
|
// In BattleGround players can use only flags and banners
|
||||||
|
if( ((Player*)m_caster)->InBattleGround() &&
|
||||||
|
!((Player*)m_caster)->CanUseBattleGroundObject() )
|
||||||
|
return SPELL_FAILED_TRY_AGAIN;
|
||||||
|
|
||||||
lockId = go->GetGOInfo()->GetLockId();
|
lockId = go->GetGOInfo()->GetLockId();
|
||||||
if (!lockId)
|
if (!lockId)
|
||||||
return SPELL_FAILED_BAD_TARGETS;
|
return SPELL_FAILED_ALREADY_OPEN;
|
||||||
}
|
}
|
||||||
else if(Item* itm = m_targets.getItemTarget())
|
else if(Item* item = m_targets.getItemTarget())
|
||||||
lockId = itm->GetProto()->LockID;
|
{
|
||||||
|
// not own (trade?)
|
||||||
|
if (item->GetOwner() != m_caster)
|
||||||
|
return SPELL_FAILED_ITEM_GONE;
|
||||||
|
|
||||||
|
lockId = item->GetProto()->LockID;
|
||||||
|
|
||||||
|
// if already unlocked
|
||||||
|
if (!lockId || item->HasFlag(ITEM_FIELD_FLAGS, ITEM_DYNFLAG_UNLOCKED))
|
||||||
|
return SPELL_FAILED_ALREADY_OPEN;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return SPELL_FAILED_BAD_TARGETS;
|
||||||
|
|
||||||
SkillType skillId = SKILL_NONE;
|
SkillType skillId = SKILL_NONE;
|
||||||
int32 reqSkillValue = 0;
|
int32 reqSkillValue = 0;
|
||||||
|
|
|
||||||
|
|
@ -1302,7 +1302,7 @@ void Aura::TriggerSpell()
|
||||||
if (!creature->GetCreatureInfo()->SkinLootId)
|
if (!creature->GetCreatureInfo()->SkinLootId)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
player->AutoStoreLoot(creature->GetCreatureInfo()->SkinLootId,LootTemplates_Skinning,true);
|
player->AutoStoreLoot(creature->GetCreatureInfo()->SkinLootId, LootTemplates_Skinning, true);
|
||||||
|
|
||||||
creature->ForcedDespawn();
|
creature->ForcedDespawn();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -222,7 +222,7 @@ void WorldSession::HandleOpenItemOpcode(WorldPacket& recvPacket)
|
||||||
|
|
||||||
// locked item
|
// locked item
|
||||||
uint32 lockId = proto->LockID;
|
uint32 lockId = proto->LockID;
|
||||||
if(lockId)
|
if(lockId && !pItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_DYNFLAG_UNLOCKED))
|
||||||
{
|
{
|
||||||
LockEntry const *lockInfo = sLockStore.LookupEntry(lockId);
|
LockEntry const *lockInfo = sLockStore.LookupEntry(lockId);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
#ifndef __REVISION_NR_H__
|
#ifndef __REVISION_NR_H__
|
||||||
#define __REVISION_NR_H__
|
#define __REVISION_NR_H__
|
||||||
#define REVISION_NR "10661"
|
#define REVISION_NR "10662"
|
||||||
#endif // __REVISION_NR_H__
|
#endif // __REVISION_NR_H__
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#ifndef __REVISION_SQL_H__
|
#ifndef __REVISION_SQL_H__
|
||||||
#define __REVISION_SQL_H__
|
#define __REVISION_SQL_H__
|
||||||
#define REVISION_DB_CHARACTERS "required_10655_01_characters_character_queststatus_monthly"
|
#define REVISION_DB_CHARACTERS "required_10662_01_characters_item_loot"
|
||||||
#define REVISION_DB_MANGOS "required_10660_01_mangos_game_event_quest"
|
#define REVISION_DB_MANGOS "required_10660_01_mangos_game_event_quest"
|
||||||
#define REVISION_DB_REALMD "required_10008_01_realmd_realmd_db_version"
|
#define REVISION_DB_REALMD "required_10008_01_realmd_realmd_db_version"
|
||||||
#endif // __REVISION_SQL_H__
|
#endif // __REVISION_SQL_H__
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue