[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:
VladimirMangos 2010-11-01 00:02:51 +03:00
parent 9a5accf8a9
commit f48e768a70
21 changed files with 392 additions and 132 deletions

View file

@ -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)
{