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`;
|
||||
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';
|
||||
|
||||
--
|
||||
|
|
@ -1455,6 +1455,31 @@ LOCK TABLES `item_instance` WRITE;
|
|||
/*!40000 ALTER TABLE `item_instance` ENABLE KEYS */;
|
||||
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`
|
||||
--
|
||||
|
|
|
|||
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 \
|
||||
10655_01_characters_character_queststatus_monthly.sql \
|
||||
10660_01_mangos_game_event_quest.sql \
|
||||
10662_01_characters_item_loot.sql \
|
||||
README
|
||||
|
||||
## Additional files to include when running 'make dist'
|
||||
|
|
@ -204,4 +205,5 @@ EXTRA_DIST = \
|
|||
10654_01_mangos_game_event_creature_quest.sql \
|
||||
10655_01_characters_character_queststatus_monthly.sql \
|
||||
10660_01_mangos_game_event_quest.sql \
|
||||
10662_01_characters_item_loot.sql \
|
||||
README
|
||||
|
|
|
|||
|
|
@ -318,7 +318,7 @@ void AuctionHouseMgr::LoadAuctionItems()
|
|||
|
||||
Item *item = NewItemOrBag(proto);
|
||||
|
||||
if(!item->LoadFromDB(item_guid,0, result))
|
||||
if(!item->LoadFromDB(item_guid,0, fields))
|
||||
{
|
||||
delete item;
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -94,9 +94,9 @@ void Bag::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;
|
||||
|
||||
// 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
|
||||
void SaveToDB();
|
||||
// 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
|
||||
void DeleteFromDB();
|
||||
|
||||
|
|
@ -71,6 +71,10 @@ class Bag : public Item
|
|||
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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_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_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_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));
|
||||
|
|
|
|||
|
|
@ -1174,7 +1174,7 @@ void Guild::LoadGuildBankFromDB()
|
|||
}
|
||||
|
||||
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));
|
||||
sLog.outError("Item GUID %u not found in item_instance, deleting from Guild Bank!", ItemGuid);
|
||||
|
|
|
|||
|
|
@ -241,8 +241,8 @@ Item::Item( )
|
|||
uState = ITEM_NEW;
|
||||
uQueuePos = -1;
|
||||
m_container = NULL;
|
||||
m_lootGenerated = false;
|
||||
mb_in_trade = false;
|
||||
m_lootState = ITEM_LOOT_NONE;
|
||||
}
|
||||
|
||||
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);
|
||||
if (HasFlag(ITEM_FIELD_FLAGS, ITEM_DYNFLAG_WRAPPED))
|
||||
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;
|
||||
return;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
// and allow use "FSetState(ITEM_REMOVED); SaveToDB();" for deleting item from DB
|
||||
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()))
|
||||
{
|
||||
sLog.outError("Item #%d have broken data in `data` field. Can't be loaded.", guidLow);
|
||||
if (delete_result) delete result;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -373,9 +399,6 @@ bool Item::LoadFromDB(uint32 guidLow, uint64 owner_guid, QueryResult *result)
|
|||
need_save = true;
|
||||
}
|
||||
|
||||
if (delete_result)
|
||||
delete result;
|
||||
|
||||
ItemPrototype const* proto = GetProto();
|
||||
if(!proto)
|
||||
return false;
|
||||
|
|
@ -446,6 +469,37 @@ bool Item::LoadFromDB(uint32 guidLow, uint64 owner_guid, QueryResult *result)
|
|||
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()
|
||||
{
|
||||
CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid = '%u'",GetGUIDLow());
|
||||
|
|
@ -725,9 +779,6 @@ bool Item::IsEquipped() const
|
|||
|
||||
bool Item::CanBeTraded(bool mail) const
|
||||
{
|
||||
if (m_lootGenerated)
|
||||
return false;
|
||||
|
||||
if ((!mail || !IsBoundAccountWide()) && IsSoulBound())
|
||||
return false;
|
||||
|
||||
|
|
@ -742,6 +793,9 @@ bool Item::CanBeTraded(bool mail) const
|
|||
return false;
|
||||
}
|
||||
|
||||
if (HasGeneratedLoot())
|
||||
return false;
|
||||
|
||||
if (IsBoundByEnchant())
|
||||
return false;
|
||||
|
||||
|
|
@ -1003,6 +1057,10 @@ bool Item::IsBindedNotWith( Player const* player ) const
|
|||
if(GetOwnerGUID()== player->GetGUID())
|
||||
return false;
|
||||
|
||||
// has loot with diff owner
|
||||
if (HasGeneratedLoot())
|
||||
return true;
|
||||
|
||||
// not BOA item case
|
||||
if(!IsBoundAccountWide())
|
||||
return true;
|
||||
|
|
@ -1050,7 +1108,7 @@ uint8 Item::CanBeMergedPartlyWith( ItemPrototype const* proto ) const
|
|||
return EQUIP_ERR_ITEM_CANT_STACK;
|
||||
|
||||
// not allow merge looting currently items
|
||||
if (m_lootGenerated)
|
||||
if (HasGeneratedLoot())
|
||||
return EQUIP_ERR_ALREADY_LOOTED;
|
||||
|
||||
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;
|
||||
class Bag;
|
||||
class Field;
|
||||
class QueryResult;
|
||||
class Unit;
|
||||
|
||||
|
|
@ -202,6 +203,15 @@ enum ItemUpdateState
|
|||
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
|
||||
enum ItemDynFlags
|
||||
|
|
@ -282,9 +292,10 @@ class MANGOS_DLL_SPEC Item : public Object
|
|||
bool IsBindedNotWith(Player const* player) const;
|
||||
bool IsBoundByEnchant() const;
|
||||
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();
|
||||
void DeleteFromInventoryDB();
|
||||
void LoadLootFromDB(Field *fields);
|
||||
|
||||
bool IsBag() const { return GetProto()->InventoryType == INVTYPE_BAG; }
|
||||
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();
|
||||
|
||||
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
|
||||
ItemUpdateState GetState() const { return uState; }
|
||||
|
|
@ -373,5 +387,7 @@ class MANGOS_DLL_SPEC Item : public Object
|
|||
ItemUpdateState uState;
|
||||
int16 uQueuePos;
|
||||
bool mb_in_trade; // true if item is currently in trade-window
|
||||
ItemLootUpdateState m_lootState;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ void WorldSession::HandleAutostoreLootItemOpcode( WorldPacket & recv_data )
|
|||
ObjectGuid lguid = player->GetLootGUID();
|
||||
Loot *loot;
|
||||
uint8 lootSlot;
|
||||
Item* pItem = NULL;
|
||||
|
||||
recv_data >> lootSlot;
|
||||
|
||||
|
|
@ -59,9 +60,9 @@ void WorldSession::HandleAutostoreLootItemOpcode( WorldPacket & recv_data )
|
|||
}
|
||||
case HIGHGUID_ITEM:
|
||||
{
|
||||
Item *pItem = player->GetItemByGuid( lguid );
|
||||
pItem = player->GetItemByGuid( lguid );
|
||||
|
||||
if (!pItem)
|
||||
if (!pItem || !pItem->HasGeneratedLoot())
|
||||
{
|
||||
player->SendLootRelease(lguid);
|
||||
return;
|
||||
|
|
@ -122,6 +123,9 @@ void WorldSession::HandleAutostoreLootItemOpcode( WorldPacket & recv_data )
|
|||
return;
|
||||
}
|
||||
|
||||
if (pItem)
|
||||
pItem->SetLootState(ITEM_LOOT_CHANGED);
|
||||
|
||||
ItemPosCountVec dest;
|
||||
uint8 msg = player->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, item->itemid, item->count );
|
||||
if ( msg == EQUIP_ERR_OK )
|
||||
|
|
@ -179,6 +183,7 @@ void WorldSession::HandleLootMoneyOpcode( WorldPacket & /*recv_data*/ )
|
|||
return;
|
||||
|
||||
Loot *pLoot = NULL;
|
||||
Item* pItem = NULL;
|
||||
|
||||
switch(guid.GetHigh())
|
||||
{
|
||||
|
|
@ -203,8 +208,11 @@ void WorldSession::HandleLootMoneyOpcode( WorldPacket & /*recv_data*/ )
|
|||
}
|
||||
case HIGHGUID_ITEM:
|
||||
{
|
||||
if(Item *item = GetPlayer()->GetItemByGuid(guid))
|
||||
pLoot = &item->loot;
|
||||
pItem = GetPlayer()->GetItemByGuid(guid);
|
||||
if (!pItem || !pItem->HasGeneratedLoot())
|
||||
return;
|
||||
|
||||
pLoot = &pItem->loot;
|
||||
break;
|
||||
}
|
||||
case HIGHGUID_UNIT:
|
||||
|
|
@ -255,7 +263,12 @@ void WorldSession::HandleLootMoneyOpcode( WorldPacket & /*recv_data*/ )
|
|||
player->ModifyMoney( pLoot->gold );
|
||||
player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY, pLoot->gold);
|
||||
}
|
||||
|
||||
pLoot->gold = 0;
|
||||
|
||||
if (pItem)
|
||||
pItem->SetLootState(ITEM_LOOT_CHANGED);
|
||||
|
||||
pLoot->NotifyMoneyRemoved();
|
||||
}
|
||||
}
|
||||
|
|
@ -400,17 +413,17 @@ void WorldSession::DoLootRelease(ObjectGuid lguid)
|
|||
case HIGHGUID_ITEM:
|
||||
{
|
||||
Item *pItem = player->GetItemByGuid(lguid );
|
||||
if(!pItem)
|
||||
if (!pItem)
|
||||
return;
|
||||
|
||||
ItemPrototype const* proto = pItem->GetProto();
|
||||
|
||||
// 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)
|
||||
{
|
||||
case LOOT_MILLING:
|
||||
case LOOT_PROSPECTING:
|
||||
{
|
||||
pItem->m_lootGenerated = false;
|
||||
pItem->loot.clear();
|
||||
|
||||
uint32 count = pItem->GetCount();
|
||||
|
||||
// >=5 checked in spell code, but will work for cheating cases also with removing from another stacks.
|
||||
|
|
@ -418,10 +431,25 @@ void WorldSession::DoLootRelease(ObjectGuid lguid)
|
|||
count = 5;
|
||||
|
||||
player->DestroyItemCount(pItem, count, true);
|
||||
break;
|
||||
}
|
||||
else
|
||||
// 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.
|
||||
case LOOT_DISENCHANTING:
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
return; // item can be looted only single player
|
||||
}
|
||||
case HIGHGUID_UNIT:
|
||||
|
|
|
|||
|
|
@ -333,6 +333,25 @@ LootItem::LootItem(LootStoreItem const& li)
|
|||
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
|
||||
bool LootItem::AllowedForPlayer(Player const * player) const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -97,6 +97,8 @@ struct LootItem
|
|||
// Should be called for non-reference LootStoreItem entries only (mincountOrRef > 0)
|
||||
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
|
||||
bool AllowedForPlayer(Player const * player) const;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1927,6 +1927,35 @@ void ObjectMgr::LoadItemPrototypes()
|
|||
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)
|
||||
{
|
||||
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 > 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)
|
||||
|
|
|
|||
|
|
@ -4254,7 +4254,7 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe
|
|||
}
|
||||
|
||||
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->SaveToDB(); // it also deletes item object !
|
||||
|
|
@ -7897,25 +7897,28 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type)
|
|||
|
||||
loot = &item->loot;
|
||||
|
||||
if (!item->m_lootGenerated)
|
||||
if (!item->HasGeneratedLoot())
|
||||
{
|
||||
item->m_lootGenerated = true;
|
||||
loot->clear();
|
||||
item->loot.clear();
|
||||
|
||||
switch(loot_type)
|
||||
{
|
||||
case LOOT_DISENCHANTING:
|
||||
loot->FillLoot(item->GetProto()->DisenchantID, LootTemplates_Disenchant, this,true);
|
||||
item->SetLootState(ITEM_LOOT_TEMPORARY);
|
||||
break;
|
||||
case LOOT_PROSPECTING:
|
||||
loot->FillLoot(item->GetEntry(), LootTemplates_Prospecting, this,true);
|
||||
item->SetLootState(ITEM_LOOT_TEMPORARY);
|
||||
break;
|
||||
case LOOT_MILLING:
|
||||
loot->FillLoot(item->GetEntry(), LootTemplates_Milling, this,true);
|
||||
item->SetLootState(ITEM_LOOT_TEMPORARY);
|
||||
break;
|
||||
default:
|
||||
loot->FillLoot(item->GetEntry(), LootTemplates_Item, this,true);
|
||||
loot->generateMoneyLoot(item->GetProto()->MinMoneyLoot,item->GetProto()->MaxMoneyLoot);
|
||||
item->SetLootState(ITEM_LOOT_CHANGED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -9621,14 +9624,6 @@ uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint3
|
|||
|
||||
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 (no_space_count)
|
||||
|
|
@ -10116,10 +10111,6 @@ uint8 Player::CanStoreItems( Item **pItems,int count) const
|
|||
if( !pProto )
|
||||
return EQUIP_ERR_ITEM_NOT_FOUND;
|
||||
|
||||
// item used
|
||||
if(pItem->m_lootGenerated)
|
||||
return EQUIP_ERR_ALREADY_LOOTED;
|
||||
|
||||
// item it 'bind'
|
||||
if(pItem->IsBindedNotWith(this))
|
||||
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();
|
||||
if( pProto )
|
||||
{
|
||||
// item used
|
||||
if(pItem->m_lootGenerated)
|
||||
return EQUIP_ERR_ALREADY_LOOTED;
|
||||
|
||||
if(pItem->IsBindedNotWith(this))
|
||||
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
|
||||
{
|
||||
// Applied only to equipped items and bank bags
|
||||
if(!IsEquipmentPos(pos) && !IsBagPos(pos))
|
||||
if (!IsEquipmentPos(pos) && !IsBagPos(pos))
|
||||
return EQUIP_ERR_OK;
|
||||
|
||||
Item* pItem = GetItemByPos(pos);
|
||||
|
||||
// Applied only to existing equipped item
|
||||
if( !pItem )
|
||||
if (!pItem)
|
||||
return EQUIP_ERR_OK;
|
||||
|
||||
DEBUG_LOG( "STORAGE: CanUnequipItem slot = %u, item = %u, count = %u", pos, pItem->GetEntry(), pItem->GetCount());
|
||||
|
||||
ItemPrototype const *pProto = pItem->GetProto();
|
||||
if( !pProto )
|
||||
if (!pProto)
|
||||
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
|
||||
// - combat
|
||||
// - in-progress arenas
|
||||
|
|
@ -10505,10 +10488,6 @@ uint8 Player::CanBankItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, Item *p
|
|||
if (!pProto)
|
||||
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))
|
||||
return EQUIP_ERR_DONT_OWN_THAT_ITEM;
|
||||
|
||||
|
|
@ -11593,13 +11572,13 @@ void Player::SplitItem( uint16 src, uint16 dst, uint32 count )
|
|||
uint8 dstslot = dst & 255;
|
||||
|
||||
Item *pSrcItem = GetItemByPos( srcbag, srcslot );
|
||||
if( !pSrcItem )
|
||||
if (!pSrcItem)
|
||||
{
|
||||
SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, pSrcItem, NULL );
|
||||
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
|
||||
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)
|
||||
if(pSrcItem->GetCount() == count)
|
||||
if (pSrcItem->GetCount() == count)
|
||||
{
|
||||
SendEquipError( EQUIP_ERR_COULDNT_SPLIT_ITEMS, pSrcItem, NULL );
|
||||
return;
|
||||
}
|
||||
|
||||
// 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 );
|
||||
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);
|
||||
Item *pNewItem = pSrcItem->CloneItem( count, this );
|
||||
if( !pNewItem )
|
||||
if (!pNewItem)
|
||||
{
|
||||
SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, pSrcItem, NULL );
|
||||
return;
|
||||
}
|
||||
|
||||
if( IsInventoryPos( dst ) )
|
||||
if (IsInventoryPos(dst))
|
||||
{
|
||||
// change item amount before check (for unique max count check)
|
||||
pSrcItem->SetCount( pSrcItem->GetCount() - count );
|
||||
|
||||
ItemPosCountVec dest;
|
||||
uint8 msg = CanStoreItem( dstbag, dstslot, dest, pNewItem, false );
|
||||
if( msg != EQUIP_ERR_OK )
|
||||
if (msg != EQUIP_ERR_OK)
|
||||
{
|
||||
delete pNewItem;
|
||||
pSrcItem->SetCount( pSrcItem->GetCount() + count );
|
||||
|
|
@ -11643,12 +11622,12 @@ void Player::SplitItem( uint16 src, uint16 dst, uint32 count )
|
|||
return;
|
||||
}
|
||||
|
||||
if( IsInWorld() )
|
||||
if (IsInWorld())
|
||||
pSrcItem->SendCreateUpdateToPlayer( this );
|
||||
pSrcItem->SetState(ITEM_CHANGED, this);
|
||||
StoreItem( dest, pNewItem, true);
|
||||
}
|
||||
else if( IsBankPos ( dst ) )
|
||||
else if (IsBankPos (dst))
|
||||
{
|
||||
// change item amount before check (for unique max count check)
|
||||
pSrcItem->SetCount( pSrcItem->GetCount() - count );
|
||||
|
|
@ -11663,19 +11642,19 @@ void Player::SplitItem( uint16 src, uint16 dst, uint32 count )
|
|||
return;
|
||||
}
|
||||
|
||||
if( IsInWorld() )
|
||||
if (IsInWorld())
|
||||
pSrcItem->SendCreateUpdateToPlayer( this );
|
||||
pSrcItem->SetState(ITEM_CHANGED, this);
|
||||
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
|
||||
pSrcItem->SetCount( pSrcItem->GetCount() - count );
|
||||
|
||||
uint16 dest;
|
||||
uint8 msg = CanEquipItem( dstslot, dest, pNewItem, false );
|
||||
if( msg != EQUIP_ERR_OK )
|
||||
if (msg != EQUIP_ERR_OK)
|
||||
{
|
||||
delete pNewItem;
|
||||
pSrcItem->SetCount( pSrcItem->GetCount() + count );
|
||||
|
|
@ -11683,7 +11662,7 @@ void Player::SplitItem( uint16 src, uint16 dst, uint32 count )
|
|||
return;
|
||||
}
|
||||
|
||||
if( IsInWorld() )
|
||||
if (IsInWorld())
|
||||
pSrcItem->SendCreateUpdateToPlayer( this );
|
||||
pSrcItem->SetState(ITEM_CHANGED, this);
|
||||
EquipItem( dest, pNewItem, true);
|
||||
|
|
@ -15492,6 +15471,7 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
|
|||
m_reputationMgr.LoadFromDB(holder->GetResult(PLAYER_LOGIN_QUERY_LOADREPUTATION));
|
||||
|
||||
_LoadInventory(holder->GetResult(PLAYER_LOGIN_QUERY_LOADINVENTORY), time_diff);
|
||||
_LoadItemLoot(holder->GetResult(PLAYER_LOGIN_QUERY_LOADITEMLOOT));
|
||||
|
||||
// update items with duration and realtime
|
||||
UpdateItemDuration(time_diff, true);
|
||||
|
|
@ -15903,7 +15883,7 @@ void Player::_LoadInventory(QueryResult *result, uint32 timediff)
|
|||
|
||||
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 );
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
//if(isAlive())
|
||||
_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
|
||||
void Player::_LoadMailedItems(QueryResult *result)
|
||||
{
|
||||
|
|
@ -16064,7 +16073,7 @@ void Player::_LoadMailedItems(QueryResult *result)
|
|||
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
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.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);
|
||||
for(uint32 i = 0; i < max_slot; ++i)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -896,6 +896,7 @@ enum PlayerLoginQueryIndex
|
|||
PLAYER_LOGIN_QUERY_LOADDAILYQUESTSTATUS,
|
||||
PLAYER_LOGIN_QUERY_LOADREPUTATION,
|
||||
PLAYER_LOGIN_QUERY_LOADINVENTORY,
|
||||
PLAYER_LOGIN_QUERY_LOADITEMLOOT,
|
||||
PLAYER_LOGIN_QUERY_LOADACTIONS,
|
||||
PLAYER_LOGIN_QUERY_LOADSOCIALLIST,
|
||||
PLAYER_LOGIN_QUERY_LOADHOMEBIND,
|
||||
|
|
@ -1299,8 +1300,8 @@ class MANGOS_DLL_SPEC Player : public Unit
|
|||
bool StoreNewItemInBestSlots(uint32 item_id, uint32 item_count);
|
||||
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) { AutoStoreLoot(NULL_BAG,NULL_SLOT,loot_id,store,broadcast); }
|
||||
void AutoStoreLoot(uint32 loot_id, LootStore const& store, bool broadcast = false, uint8 bag = NULL_BAG, uint8 slot = NULL_SLOT);
|
||||
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 _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 _LoadBoundInstances(QueryResult *result);
|
||||
void _LoadInventory(QueryResult *result, uint32 timediff);
|
||||
void _LoadItemLoot(QueryResult *result);
|
||||
void _LoadMails(QueryResult *result);
|
||||
void _LoadMailedItems(QueryResult *result);
|
||||
void _LoadQuestStatus(QueryResult *result);
|
||||
|
|
|
|||
|
|
@ -4989,34 +4989,43 @@ SpellCastResult Spell::CheckCast(bool strict)
|
|||
}
|
||||
case SPELL_EFFECT_OPEN_LOCK:
|
||||
{
|
||||
if( m_spellInfo->EffectImplicitTargetA[i] != TARGET_GAMEOBJECT &&
|
||||
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)))
|
||||
if (m_caster->GetTypeId() != TYPEID_PLAYER) // only players can open locks, gather etc.
|
||||
return SPELL_FAILED_BAD_TARGETS;
|
||||
|
||||
// In BattleGround players can use only flags and banners
|
||||
if( ((Player*)m_caster)->InBattleGround() &&
|
||||
!((Player*)m_caster)->CanUseBattleGroundObject() )
|
||||
return SPELL_FAILED_TRY_AGAIN;
|
||||
// we need a go target in case of TARGET_GAMEOBJECT (for other targets acceptable GO and items)
|
||||
if (m_spellInfo->EffectImplicitTargetA[i] == TARGET_GAMEOBJECT)
|
||||
{
|
||||
if (!m_targets.getGOTarget())
|
||||
return SPELL_FAILED_BAD_TARGETS;
|
||||
}
|
||||
|
||||
// get the lock entry
|
||||
uint32 lockId = 0;
|
||||
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();
|
||||
if (!lockId)
|
||||
return SPELL_FAILED_BAD_TARGETS;
|
||||
return SPELL_FAILED_ALREADY_OPEN;
|
||||
}
|
||||
else if(Item* itm = m_targets.getItemTarget())
|
||||
lockId = itm->GetProto()->LockID;
|
||||
else if(Item* item = m_targets.getItemTarget())
|
||||
{
|
||||
// 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;
|
||||
int32 reqSkillValue = 0;
|
||||
|
|
|
|||
|
|
@ -1302,7 +1302,7 @@ void Aura::TriggerSpell()
|
|||
if (!creature->GetCreatureInfo()->SkinLootId)
|
||||
return;
|
||||
|
||||
player->AutoStoreLoot(creature->GetCreatureInfo()->SkinLootId,LootTemplates_Skinning,true);
|
||||
player->AutoStoreLoot(creature->GetCreatureInfo()->SkinLootId, LootTemplates_Skinning, true);
|
||||
|
||||
creature->ForcedDespawn();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -222,7 +222,7 @@ void WorldSession::HandleOpenItemOpcode(WorldPacket& recvPacket)
|
|||
|
||||
// locked item
|
||||
uint32 lockId = proto->LockID;
|
||||
if(lockId)
|
||||
if(lockId && !pItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_DYNFLAG_UNLOCKED))
|
||||
{
|
||||
LockEntry const *lockInfo = sLockStore.LookupEntry(lockId);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#ifndef __REVISION_NR_H__
|
||||
#define __REVISION_NR_H__
|
||||
#define REVISION_NR "10661"
|
||||
#define REVISION_NR "10662"
|
||||
#endif // __REVISION_NR_H__
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#ifndef __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_REALMD "required_10008_01_realmd_realmd_db_version"
|
||||
#endif // __REVISION_SQL_H__
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue