void WorldSession::HandleAutostoreLootItemOpcode(WorldPacket& recv_data) { DEBUG_LOG("WORLD: CMSG_AUTOSTORE_LOOT_ITEM"); Player* player = GetPlayer(); ObjectGuid lguid = player->GetLootGuid(); Loot* loot; uint8 lootSlot; Item* pItem = NULL; recv_data >> lootSlot; switch (lguid.GetHigh()) { case HIGHGUID_GAMEOBJECT: { GameObject* go = player->GetMap()->GetGameObject(lguid); // not check distance for GO in case owned GO (fishing bobber case, for example) or Fishing hole GO if (!go || ((go->GetOwnerGuid() != _player->GetObjectGuid() && go->GetGoType() != GAMEOBJECT_TYPE_FISHINGHOLE) && !go->IsWithinDistInMap(_player, INTERACTION_DISTANCE))) { player->SendLootRelease(lguid); return; } loot = &go->loot; break; } case HIGHGUID_ITEM: { pItem = player->GetItemByGuid(lguid); if (!pItem || !pItem->HasGeneratedLoot()) { player->SendLootRelease(lguid); return; } loot = &pItem->loot; break; } case HIGHGUID_CORPSE: { Corpse* bones = player->GetMap()->GetCorpse(lguid); if (!bones) { player->SendLootRelease(lguid); return; } loot = &bones->loot; break; } case HIGHGUID_UNIT: case HIGHGUID_VEHICLE: { Creature* pCreature = GetPlayer()->GetMap()->GetCreature(lguid); bool ok_loot = pCreature && pCreature->isAlive() == (player->getClass() == CLASS_ROGUE && pCreature->lootForPickPocketed); if (!ok_loot || !pCreature->IsWithinDistInMap(_player, INTERACTION_DISTANCE)) { player->SendLootRelease(lguid); return; } loot = &pCreature->loot; break; } default: { sLog.outError("%s is unsupported for looting.", lguid.GetString().c_str()); return; } } QuestItem* qitem = NULL; QuestItem* ffaitem = NULL; QuestItem* conditem = NULL; LootItem* item = loot->LootItemInSlot(lootSlot, player, &qitem, &ffaitem, &conditem); if (!item) { player->SendEquipError(EQUIP_ERR_ALREADY_LOOTED, NULL, NULL); return; } // questitems use the blocked field for other purposes if (!qitem && item->is_blocked) { player->SendLootRelease(lguid); return; } if (pItem) pItem->SetLootState(ITEM_LOOT_CHANGED); ItemPosCountVec dest; InventoryResult msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, item->itemid, item->count); if (msg == EQUIP_ERR_OK) { Item* newitem = player->StoreNewItem(dest, item->itemid, true, item->randomPropertyId, item->GetAllowedLooters()); if (qitem) { qitem->is_looted = true; // freeforall is 1 if everyone's supposed to get the quest item. if (item->freeforall || loot->GetPlayerQuestItems().size() == 1) player->SendNotifyLootItemRemoved(lootSlot); else loot->NotifyQuestItemRemoved(qitem->index); } else { if (ffaitem) { // freeforall case, notify only one player of the removal ffaitem->is_looted = true; player->SendNotifyLootItemRemoved(lootSlot); } else { // not freeforall, notify everyone if (conditem) conditem->is_looted = true; loot->NotifyItemRemoved(lootSlot); } } // if only one person is supposed to loot the item, then set it to looted if (!item->freeforall) item->is_looted = true; --loot->unlootedCount; player->SendNewItem(newitem, uint32(item->count), false, false, true); player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM, item->itemid, item->count); player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE, loot->loot_type, item->count); player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM, item->itemid, item->count); } else player->SendEquipError(msg, NULL, NULL, item->itemid); }
void WorldSession::HandleLootMasterGiveOpcode(WorldPacket& recv_data) { uint8 slotid; ObjectGuid lootguid; ObjectGuid target_playerguid; recv_data >> lootguid >> slotid >> target_playerguid; if (!_player->GetGroup() || _player->GetGroup()->GetLooterGuid() != _player->GetObjectGuid()) { _player->SendLootRelease(GetPlayer()->GetLootGuid()); return; } Player* target = ObjectAccessor::FindPlayer(target_playerguid); if (!target) return; DEBUG_LOG("WorldSession::HandleLootMasterGiveOpcode (CMSG_LOOT_MASTER_GIVE, 0x02A3) Target = %s.", target->GetGuidStr().c_str()); if (_player->GetLootGuid() != lootguid) return; if (!_player->IsInSameRaidWith(target) || !_player->IsInMap(target)) { sLog.outString("WorldSession::HandleLootMasterGiveOpcode: %s tried to give an item to ineligible %s!", _player->GetGuidStr().c_str(), target->GetGuidStr().c_str()); return; } Loot* pLoot = NULL; if (lootguid.IsCreatureOrVehicle()) { Creature* pCreature = GetPlayer()->GetMap()->GetCreature(lootguid); if (!pCreature) return; pLoot = &pCreature->loot; } else if (lootguid.IsGameObject()) { GameObject* pGO = GetPlayer()->GetMap()->GetGameObject(lootguid); if (!pGO) return; pLoot = &pGO->loot; } else return; if (slotid > pLoot->items.size()) { DEBUG_LOG("AutoLootItem: %s might be using a hack! (slot %d, size " SIZEFMTD ")", GetPlayer()->GetGuidStr().c_str(), slotid, pLoot->items.size()); return; } LootItem& item = pLoot->items[slotid]; ItemPosCountVec dest; InventoryResult msg = target->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, item.itemid, item.count); if (msg != EQUIP_ERR_OK) { target->SendEquipError(msg, NULL, NULL, item.itemid); // send duplicate of error massage to master looter _player->SendEquipError(msg, NULL, NULL, item.itemid); return; } // now move item from loot to target inventory Item* newitem = target->StoreNewItem(dest, item.itemid, true, item.randomPropertyId, item.GetAllowedLooters()); target->SendNewItem(newitem, uint32(item.count), false, false, true); target->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM, item.itemid, item.count); target->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE, pLoot->loot_type, item.count); target->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM, item.itemid, item.count); // mark as looted item.count = 0; item.is_looted = true; pLoot->NotifyItemRemoved(slotid); --pLoot->unlootedCount; }
void WorldSession::HandleOpenItemOpcode(WorldPacket& recvPacket) { DETAIL_LOG("WORLD: CMSG_OPEN_ITEM packet, data length = %i", (uint32)recvPacket.size()); uint8 bagIndex, slot; recvPacket >> bagIndex >> slot; DETAIL_LOG("bagIndex: %u, slot: %u", bagIndex, slot); Player* pUser = _player; // ignore for remote control state if (!pUser->IsSelfMover()) return; Item* pItem = pUser->GetItemByPos(bagIndex, slot); if (!pItem) { pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL); return; } ItemPrototype const* proto = pItem->GetProto(); if (!proto) { pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, pItem, NULL); return; } // locked item uint32 lockId = proto->LockID; if (lockId && !pItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_DYNFLAG_UNLOCKED)) { LockEntry const* lockInfo = sLockStore.LookupEntry(lockId); if (!lockInfo) { pUser->SendEquipError(EQUIP_ERR_ITEM_LOCKED, pItem, NULL); sLog.outError("WORLD::OpenItem: item [guid = %u] has an unknown lockId: %u!", pItem->GetGUIDLow() , lockId); return; } // required picklocking if (lockInfo->Skill[1] || lockInfo->Skill[0]) { pUser->SendEquipError(EQUIP_ERR_ITEM_LOCKED, pItem, NULL); return; } } if (pItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_DYNFLAG_WRAPPED))// wrapped? { QueryResult* result = CharacterDatabase.PQuery("SELECT entry, flags FROM character_gifts WHERE item_guid = '%u'", pItem->GetGUIDLow()); if (result) { Field* fields = result->Fetch(); uint32 entry = fields[0].GetUInt32(); uint32 flags = fields[1].GetUInt32(); pItem->SetGuidValue(ITEM_FIELD_GIFTCREATOR, ObjectGuid()); pItem->SetEntry(entry); pItem->SetUInt32Value(ITEM_FIELD_FLAGS, flags); pItem->SetState(ITEM_CHANGED, pUser); delete result; } else { sLog.outError("Wrapped item %u don't have record in character_gifts table and will deleted", pItem->GetGUIDLow()); pUser->DestroyItem(pItem->GetBagSlot(), pItem->GetSlot(), true); return; } static SqlStatementID delGifts ; SqlStatement stmt = CharacterDatabase.CreateStatement(delGifts, "DELETE FROM character_gifts WHERE item_guid = ?"); stmt.PExecute(pItem->GetGUIDLow()); } else pUser->SendLoot(pItem->GetObjectGuid(), LOOT_CORPSE); }
void WorldSession::HandleUseItemOpcode(WorldPacket& recvPacket) { uint8 bagIndex, slot; uint8 spell_count; // number of spells at item, not used uint8 cast_count; // next cast if exists (single or not) ObjectGuid itemGuid; recvPacket >> bagIndex >> slot >> spell_count >> cast_count >> itemGuid; // TODO: add targets.read() check Player* pUser = _player; // ignore for remote control state if (!pUser->IsSelfMover()) { recvPacket.rpos(recvPacket.wpos()); // prevent spam at not read packet tail return; } Item* pItem = pUser->GetItemByPos(bagIndex, slot); if (!pItem) { recvPacket.rpos(recvPacket.wpos()); // prevent spam at not read packet tail pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL); return; } if (pItem->GetObjectGuid() != itemGuid) { recvPacket.rpos(recvPacket.wpos()); // prevent spam at not read packet tail pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL); return; } DETAIL_LOG("WORLD: CMSG_USE_ITEM packet, bagIndex: %u, slot: %u, spell_count: %u , cast_count: %u, Item: %u, data length = %i", bagIndex, slot, spell_count, cast_count, pItem->GetEntry(), (uint32)recvPacket.size()); ItemPrototype const* proto = pItem->GetProto(); if (!proto) { recvPacket.rpos(recvPacket.wpos()); // prevent spam at not read packet tail pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, pItem, NULL); return; } // some item classes can be used only in equipped state if (proto->InventoryType != INVTYPE_NON_EQUIP && !pItem->IsEquipped()) { recvPacket.rpos(recvPacket.wpos()); // prevent spam at not read packet tail pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, pItem, NULL); return; } InventoryResult msg = pUser->CanUseItem(pItem); if (msg != EQUIP_ERR_OK) { recvPacket.rpos(recvPacket.wpos()); // prevent spam at not read packet tail pUser->SendEquipError(msg, pItem, NULL); return; } // not allow use item from trade (cheat way only) if (pItem->IsInTrade()) { recvPacket.rpos(recvPacket.wpos()); // prevent spam at not read packet tail pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, pItem, NULL); return; } // only allow conjured consumable, bandage, poisons (all should have the 2^21 item flag set in DB) if (proto->Class == ITEM_CLASS_CONSUMABLE && !(proto->Flags & ITEM_FLAG_USEABLE_IN_ARENA) && pUser->InArena()) { recvPacket.rpos(recvPacket.wpos()); // prevent spam at not read packet tail pUser->SendEquipError(EQUIP_ERR_NOT_DURING_ARENA_MATCH, pItem, NULL); return; } if (pUser->isInCombat()) { for (int i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i) { if (SpellEntry const* spellInfo = sSpellStore.LookupEntry(proto->Spells[i].SpellId)) { if (IsNonCombatSpell(spellInfo)) { recvPacket.rpos(recvPacket.wpos()); // prevent spam at not read packet tail pUser->SendEquipError(EQUIP_ERR_NOT_IN_COMBAT, pItem, NULL); return; } } } } // check also BIND_WHEN_PICKED_UP and BIND_QUEST_ITEM for .additem or .additemset case by GM (not binded at adding to inventory) if (pItem->GetProto()->Bonding == BIND_WHEN_USE || pItem->GetProto()->Bonding == BIND_WHEN_PICKED_UP || pItem->GetProto()->Bonding == BIND_QUEST_ITEM) { if (!pItem->IsSoulBound()) { pItem->SetState(ITEM_CHANGED, pUser); pItem->SetBinding(true); } } SpellCastTargets targets; recvPacket >> targets.ReadForCaster(pUser); targets.Update(pUser); if (!pItem->IsTargetValidForItemUse(targets.getUnitTarget())) { // free gray item after use fail pUser->SendEquipError(EQUIP_ERR_NONE, pItem, NULL); // search spell for spell error uint32 spellid = 0; for (int i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i) { if (proto->Spells[i].SpellTrigger == ITEM_SPELLTRIGGER_ON_USE) { spellid = proto->Spells[i].SpellId; break; } } // send spell error if (SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellid)) Spell::SendCastResult(_player, spellInfo, cast_count, SPELL_FAILED_BAD_TARGETS); return; } //Note: If script stop casting it must send appropriate data to client to prevent stuck item in gray state. if (!sScriptMgr.OnItemUse(pUser, pItem, targets)) { // no script or script not process request by self pUser->CastItemUseSpell(pItem, targets, cast_count); } }
void WorldSession::HandleUseItemOpcode(WorldPacket& recvPacket) { uint8 bagIndex, slot; uint8 unk_flags; // flags (if 0x02 - some additional data are received) uint8 cast_count; // next cast if exists (single or not) uint64 item_guid; uint32 glyphIndex; // something to do with glyphs? uint32 spellid; // casted spell id recvPacket >> bagIndex >> slot >> cast_count >> spellid >> item_guid >> glyphIndex >> unk_flags; // TODO: add targets.read() check Player* pUser = _player; // ignore for remote control state if (!pUser->IsSelfMover()) { recvPacket.rpos(recvPacket.wpos()); // prevent spam at not read packet tail return; } // reject fake data if (glyphIndex >= MAX_GLYPH_SLOT_INDEX) { recvPacket.rpos(recvPacket.wpos()); // prevent spam at not read packet tail pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL ); return; } Item *pItem = pUser->GetItemByPos(bagIndex, slot); if (!pItem) { recvPacket.rpos(recvPacket.wpos()); // prevent spam at not read packet tail pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL ); return; } if (pItem->GetGUID() != item_guid) { recvPacket.rpos(recvPacket.wpos()); // prevent spam at not read packet tail pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL ); return; } DETAIL_LOG("WORLD: CMSG_USE_ITEM packet, bagIndex: %u, slot: %u, cast_count: %u, spellid: %u, Item: %u, glyphIndex: %u, unk_flags: %u, data length = %i", bagIndex, slot, cast_count, spellid, pItem->GetEntry(), glyphIndex, unk_flags, (uint32)recvPacket.size()); ItemPrototype const *proto = pItem->GetProto(); if (!proto) { recvPacket.rpos(recvPacket.wpos()); // prevent spam at not read packet tail pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, pItem, NULL ); return; } // some item classes can be used only in equipped state if (proto->InventoryType != INVTYPE_NON_EQUIP && !pItem->IsEquipped()) { recvPacket.rpos(recvPacket.wpos()); // prevent spam at not read packet tail pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, pItem, NULL ); return; } uint8 msg = pUser->CanUseItem(pItem); if (msg != EQUIP_ERR_OK) { recvPacket.rpos(recvPacket.wpos()); // prevent spam at not read packet tail pUser->SendEquipError( msg, pItem, NULL ); return; } // not allow use item from trade (cheat way only) if (pItem->IsInTrade()) { recvPacket.rpos(recvPacket.wpos()); // prevent spam at not read packet tail pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, pItem, NULL ); return; } // only allow conjured consumable, bandage, poisons (all should have the 2^21 item flag set in DB) if (proto->Class == ITEM_CLASS_CONSUMABLE && !(proto->Flags & ITEM_FLAG_USEABLE_IN_ARENA) && pUser->InArena()) { recvPacket.rpos(recvPacket.wpos()); // prevent spam at not read packet tail pUser->SendEquipError(EQUIP_ERR_NOT_DURING_ARENA_MATCH,pItem,NULL); return; } if (pUser->isInCombat()) { for(int i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i) { if (SpellEntry const *spellInfo = sSpellStore.LookupEntry(proto->Spells[i].SpellId)) { if (IsNonCombatSpell(spellInfo)) { recvPacket.rpos(recvPacket.wpos()); // prevent spam at not read packet tail pUser->SendEquipError(EQUIP_ERR_NOT_IN_COMBAT,pItem,NULL); return; } } } // Prevent potion drink if another potion in processing (client have potions disabled in like case) if (pItem->IsPotion() && pUser->GetLastPotionId()) { recvPacket.rpos(recvPacket.wpos()); // prevent spam at not read packet tail pUser->SendEquipError(EQUIP_ERR_OBJECT_IS_BUSY,pItem,NULL); return; } } // check also BIND_WHEN_PICKED_UP and BIND_QUEST_ITEM for .additem or .additemset case by GM (not binded at adding to inventory) if( pItem->GetProto()->Bonding == BIND_WHEN_USE || pItem->GetProto()->Bonding == BIND_WHEN_PICKED_UP || pItem->GetProto()->Bonding == BIND_QUEST_ITEM ) { if (!pItem->IsSoulBound()) { pItem->SetState(ITEM_CHANGED, pUser); pItem->SetBinding( true ); } } SpellCastTargets targets; recvPacket >> targets.ReadForCaster(pUser); targets.Update(pUser); if (!pItem->IsTargetValidForItemUse(targets.getUnitTarget())) { // free gray item after use fail pUser->SendEquipError(EQUIP_ERR_NONE, pItem, NULL); // send spell error if (SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellid)) { SpellEffectEntry const* spellEffect = spellInfo->GetSpellEffect(EFFECT_INDEX_0); // for implicit area/coord target spells if (spellEffect && (IsPointEffectTarget(Targets(spellEffect->EffectImplicitTargetA)) || IsAreaEffectTarget(Targets(spellEffect->EffectImplicitTargetA)))) Spell::SendCastResult(_player,spellInfo,cast_count,SPELL_FAILED_NO_VALID_TARGETS); // for explicit target spells else Spell::SendCastResult(_player,spellInfo,cast_count,SPELL_FAILED_BAD_TARGETS); } return; } //Note: If script stop casting it must send appropriate data to client to prevent stuck item in gray state. if (!sScriptMgr.OnItemUse(pUser, pItem, targets)) { // no script or script not process request by self pUser->CastItemUseSpell(pItem,targets,cast_count,glyphIndex); } }
void WorldSession::HandleLootMasterGiveOpcode(WorldPacket & recv_data) { uint8 slotid; uint64 lootguid, target_playerguid; recv_data >> lootguid >> slotid >> target_playerguid; if (!_player->GetGroup() || _player->GetGroup()->GetLooterGuid() != _player->GetGUID()) { _player->SendLootRelease(GetPlayer()->GetLootGUID()); return; } Player* target = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(target_playerguid, 0, HIGHGUID_PLAYER)); if (!target) return; sLog->outDebug(LOG_FILTER_NETWORKIO, "WorldSession::HandleLootMasterGiveOpcode (CMSG_LOOT_MASTER_GIVE, 0x02A3) Target = [%s].", target->GetName()); if (_player->GetLootGUID() != lootguid) return; Loot* loot = NULL; if (IS_CRE_OR_VEH_GUID(GetPlayer()->GetLootGUID())) { Creature* creature = GetPlayer()->GetMap()->GetCreature(lootguid); if (!creature) return; loot = &creature->loot; } else if (IS_GAMEOBJECT_GUID(GetPlayer()->GetLootGUID())) { GameObject* pGO = GetPlayer()->GetMap()->GetGameObject(lootguid); if (!pGO) return; loot = &pGO->loot; } if (!loot) return; if (slotid > loot->items.size()) { sLog->outDebug(LOG_FILTER_LOOT, "MasterLootItem: Player %s might be using a hack! (slot %d, size %lu)", GetPlayer()->GetName(), slotid, (unsigned long)loot->items.size()); return; } LootItem& item = loot->items[slotid]; ItemPosCountVec dest; InventoryResult msg = target->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, item.itemid, item.count); if (msg != EQUIP_ERR_OK) { target->SendEquipError(msg, NULL, NULL, item.itemid); // send duplicate of error massage to master looter _player->SendEquipError(msg, NULL, NULL, item.itemid); return; } // list of players allowed to receive this item in trade AllowedLooterSet looters = item.GetAllowedLooters(); // not move item from loot to target inventory Item* newitem = target->StoreNewItem(dest, item.itemid, true, item.randomPropertyId, looters); target->SendNewItem(newitem, uint32(item.count), false, false, true); target->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM, item.itemid, item.count); target->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE, loot->loot_type, item.count); target->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM, item.itemid, item.count); // mark as looted item.count=0; item.is_looted=true; loot->NotifyItemRemoved(slotid); --loot->unlootedCount; }
void WorldSession::HandleLootMasterGiveOpcode( WorldPacket & recv_data ) { uint8 slotid; ObjectGuid lootguid; ObjectGuid target_playerguid; recv_data >> lootguid >> slotid >> target_playerguid; if (!_player->GetGroup() || _player->GetGroup()->GetLooterGuid() != _player->GetObjectGuid()) { _player->SendLootRelease(GetPlayer()->GetLootGUID()); return; } Player *target = ObjectAccessor::FindPlayer(target_playerguid); if (!target) return; DEBUG_LOG("WorldSession::HandleLootMasterGiveOpcode (CMSG_LOOT_MASTER_GIVE, 0x02A3) Target = %s [%s].", target_playerguid.GetString().c_str(), target->GetName()); if (_player->GetLootGUID() != lootguid.GetRawValue()) return; Loot *pLoot = NULL; if(lootguid.IsCreature()) { Creature *pCreature = GetPlayer()->GetMap()->GetCreature(lootguid); if(!pCreature) return; pLoot = &pCreature->loot; } else if(lootguid.IsGameobject()) { GameObject *pGO = GetPlayer()->GetMap()->GetGameObject(lootguid); if(!pGO) return; pLoot = &pGO->loot; } else return; if (slotid > pLoot->items.size()) { DEBUG_LOG("AutoLootItem: Player %s might be using a hack! (slot %d, size %lu)",GetPlayer()->GetName(), slotid, (unsigned long)pLoot->items.size()); return; } LootItem& item = pLoot->items[slotid]; ItemPosCountVec dest; uint8 msg = target->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, item.itemid, item.count ); if ( msg != EQUIP_ERR_OK ) { target->SendEquipError( msg, NULL, NULL ); _player->SendEquipError( msg, NULL, NULL ); // send duplicate of error massage to master looter return; } // now move item from loot to target inventory Item * newitem = target->StoreNewItem( dest, item.itemid, true, item.randomPropertyId ); target->SendNewItem(newitem, uint32(item.count), false, false, true ); // mark as looted item.count=0; item.is_looted=true; pLoot->NotifyItemRemoved(slotid); --pLoot->unlootedCount; }
void WorldSession::HandleLootMasterGiveOpcode(WorldPacket& recvData) { uint8 slotid; ObjectGuid lootguid, target_playerguid; recvData >> lootguid >> slotid >> target_playerguid; if (!_player->GetGroup() || _player->GetGroup()->GetMasterLooterGuid() != _player->GetGUID() || _player->GetGroup()->GetLootMethod() != MASTER_LOOT) { _player->SendLootError(lootguid, LOOT_ERROR_DIDNT_KILL); return; } Player* target = ObjectAccessor::FindPlayer(target_playerguid); if (!target) { _player->SendLootError(lootguid, LOOT_ERROR_PLAYER_NOT_FOUND); return; } TC_LOG_DEBUG("network", "WorldSession::HandleLootMasterGiveOpcode (CMSG_LOOT_MASTER_GIVE, 0x02A3) Target = [%s].", target->GetName().c_str()); if (_player->GetLootGUID() != lootguid) { _player->SendLootError(lootguid, LOOT_ERROR_DIDNT_KILL); return; } if (!_player->IsInRaidWith(target) || !_player->IsInMap(target)) { _player->SendLootError(lootguid, LOOT_ERROR_MASTER_OTHER); TC_LOG_INFO("loot", "MasterLootItem: Player %s tried to give an item to ineligible player %s !", GetPlayer()->GetName().c_str(), target->GetName().c_str()); return; } Loot* loot = NULL; if (GetPlayer()->GetLootGUID().IsCreatureOrVehicle()) { Creature* creature = GetPlayer()->GetMap()->GetCreature(lootguid); if (!creature) return; loot = &creature->loot; } else if (GetPlayer()->GetLootGUID().IsGameObject()) { GameObject* pGO = GetPlayer()->GetMap()->GetGameObject(lootguid); if (!pGO) return; loot = &pGO->loot; } if (!loot) return; if (slotid >= loot->items.size() + loot->quest_items.size()) { TC_LOG_DEBUG("loot", "MasterLootItem: Player %s might be using a hack! (slot %d, size %lu)", GetPlayer()->GetName().c_str(), slotid, (unsigned long)loot->items.size()); return; } LootItem& item = slotid >= loot->items.size() ? loot->quest_items[slotid - loot->items.size()] : loot->items[slotid]; ItemPosCountVec dest; InventoryResult msg = target->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, item.itemid, item.count); if (item.follow_loot_rules && !item.AllowedForPlayer(target)) msg = EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM; if (msg != EQUIP_ERR_OK) { if (msg == EQUIP_ERR_CANT_CARRY_MORE_OF_THIS) _player->SendLootError(lootguid, LOOT_ERROR_MASTER_UNIQUE_ITEM); else if (msg == EQUIP_ERR_INVENTORY_FULL) _player->SendLootError(lootguid, LOOT_ERROR_MASTER_INV_FULL); else _player->SendLootError(lootguid, LOOT_ERROR_MASTER_OTHER); target->SendEquipError(msg, NULL, NULL, item.itemid); return; } // list of players allowed to receive this item in trade AllowedLooterSet looters = item.GetAllowedLooters(); // now move item from loot to target inventory Item* newitem = target->StoreNewItem(dest, item.itemid, true, item.randomPropertyId, looters); target->SendNewItem(newitem, uint32(item.count), false, false, true); target->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM, item.itemid, item.count); target->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE, loot->loot_type, item.count); target->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM, item.itemid, item.count); // mark as looted item.count = 0; item.is_looted = true; loot->NotifyItemRemoved(slotid); --loot->unlootedCount; }
void WorldSession::HandleAcceptTradeOpcode(WorldPacket& /*recvPacket*/) { TradeData* my_trade = _player->m_trade; if (!my_trade) return; Player* trader = my_trade->GetTrader(); TradeData* his_trade = trader->m_trade; if (!his_trade) return; Item* myItems[TRADE_SLOT_TRADED_COUNT] = { NULL, NULL, NULL, NULL, NULL, NULL }; Item* hisItems[TRADE_SLOT_TRADED_COUNT] = { NULL, NULL, NULL, NULL, NULL, NULL }; bool myCanCompleteTrade = true, hisCanCompleteTrade = true; // set before checks for propertly undo at problems (it already set in to client) my_trade->SetAccepted(true); if (!_player->IsWithinDistInMap(trader, TRADE_DISTANCE, false)) { SendTradeStatus(TRADE_STATUS_TARGET_TO_FAR); my_trade->SetAccepted(false); return; } // not accept case incorrect money amount if (!_player->HasEnoughMoney(my_trade->GetMoney())) { SendNotification(LANG_NOT_ENOUGH_GOLD); my_trade->SetAccepted(false, true); return; } // not accept case incorrect money amount if (!trader->HasEnoughMoney(his_trade->GetMoney())) { trader->GetSession()->SendNotification(LANG_NOT_ENOUGH_GOLD); his_trade->SetAccepted(false, true); return; } if (_player->GetMoney() >= uint64(MAX_MONEY_AMOUNT) - his_trade->GetMoney()) { _player->SendEquipError(EQUIP_ERR_TOO_MUCH_GOLD, NULL, NULL); my_trade->SetAccepted(false, true); return; } if (trader->GetMoney() >= uint64(MAX_MONEY_AMOUNT) - my_trade->GetMoney()) { trader->SendEquipError(EQUIP_ERR_TOO_MUCH_GOLD, NULL, NULL); his_trade->SetAccepted(false, true); return; } // not accept if some items now can't be trade (cheating) for (uint8 i = 0; i < TRADE_SLOT_TRADED_COUNT; ++i) { if (Item* item = my_trade->GetItem(TradeSlots(i))) { if (!item->CanBeTraded(false, true)) { SendTradeStatus(TRADE_STATUS_TRADE_CANCELED); return; } if (item->IsBindedNotWith(trader)) { SendTradeStatus(TRADE_STATUS_NOT_ELIGIBLE); SendTradeStatus(TRADE_STATUS_CLOSE_WINDOW/*TRADE_STATUS_TRADE_CANCELED*/); return; } } if (Item* item = his_trade->GetItem(TradeSlots(i))) { if (!item->CanBeTraded(false, true)) { SendTradeStatus(TRADE_STATUS_TRADE_CANCELED); return; } //if (item->IsBindedNotWith(_player)) // dont mark as invalid when his item isnt good (not exploitable because if item is invalid trade will fail anyway later on the same check) //{ // SendTradeStatus(TRADE_STATUS_NOT_ELIGIBLE); // his_trade->SetAccepted(false, true); // return; //} } } if (his_trade->IsAccepted()) { setAcceptTradeMode(my_trade, his_trade, myItems, hisItems); Spell* my_spell = NULL; SpellCastTargets my_targets; Spell* his_spell = NULL; SpellCastTargets his_targets; // not accept if spell can't be cast now (cheating) if (uint32 my_spell_id = my_trade->GetSpell()) { SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(my_spell_id); Item* castItem = my_trade->GetSpellCastItem(); if (!spellEntry || !his_trade->GetItem(TRADE_SLOT_NONTRADED) || (my_trade->HasSpellCastItem() && !castItem)) { clearAcceptTradeMode(my_trade, his_trade); clearAcceptTradeMode(myItems, hisItems); my_trade->SetSpell(0); return; } my_spell = new Spell(_player, spellEntry, TRIGGERED_FULL_MASK); my_spell->m_CastItem = castItem; my_targets.SetTradeItemTarget(_player); my_spell->m_targets = my_targets; SpellCastResult res = my_spell->CheckCast(true); if (res != SPELL_CAST_OK) { my_spell->SendCastResult(res); clearAcceptTradeMode(my_trade, his_trade); clearAcceptTradeMode(myItems, hisItems); delete my_spell; my_trade->SetSpell(0); return; } } // not accept if spell can't be cast now (cheating) if (uint32 his_spell_id = his_trade->GetSpell()) { SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(his_spell_id); Item* castItem = his_trade->GetSpellCastItem(); if (!spellEntry || !my_trade->GetItem(TRADE_SLOT_NONTRADED) || (his_trade->HasSpellCastItem() && !castItem)) { delete my_spell; his_trade->SetSpell(0); clearAcceptTradeMode(my_trade, his_trade); clearAcceptTradeMode(myItems, hisItems); return; } his_spell = new Spell(trader, spellEntry, TRIGGERED_FULL_MASK); his_spell->m_CastItem = castItem; his_targets.SetTradeItemTarget(trader); his_spell->m_targets = his_targets; SpellCastResult res = his_spell->CheckCast(true); if (res != SPELL_CAST_OK) { his_spell->SendCastResult(res); clearAcceptTradeMode(my_trade, his_trade); clearAcceptTradeMode(myItems, hisItems); delete my_spell; delete his_spell; his_trade->SetSpell(0); return; } } // inform partner client trader->GetSession()->SendTradeStatus(TRADE_STATUS_TRADE_ACCEPT); // test if item will fit in each inventory hisCanCompleteTrade = (trader->CanStoreItems(myItems, TRADE_SLOT_TRADED_COUNT) == EQUIP_ERR_OK); myCanCompleteTrade = (_player->CanStoreItems(hisItems, TRADE_SLOT_TRADED_COUNT) == EQUIP_ERR_OK); clearAcceptTradeMode(myItems, hisItems); // in case of missing space report error if (!myCanCompleteTrade) { clearAcceptTradeMode(my_trade, his_trade); SendNotification(LANG_NOT_FREE_TRADE_SLOTS); trader->GetSession()->SendNotification(LANG_NOT_PARTNER_FREE_TRADE_SLOTS); my_trade->SetAccepted(false); his_trade->SetAccepted(false); return; } else if (!hisCanCompleteTrade) { clearAcceptTradeMode(my_trade, his_trade); SendNotification(LANG_NOT_PARTNER_FREE_TRADE_SLOTS); trader->GetSession()->SendNotification(LANG_NOT_FREE_TRADE_SLOTS); my_trade->SetAccepted(false); his_trade->SetAccepted(false); return; } // execute trade: 1. remove for (uint8 i = 0; i < TRADE_SLOT_TRADED_COUNT; ++i) { if (myItems[i]) { myItems[i]->SetUInt64Value(ITEM_FIELD_GIFTCREATOR, _player->GetGUID()); _player->MoveItemFromInventory(myItems[i]->GetBagSlot(), myItems[i]->GetSlot(), true); } if (hisItems[i]) { hisItems[i]->SetUInt64Value(ITEM_FIELD_GIFTCREATOR, trader->GetGUID()); trader->MoveItemFromInventory(hisItems[i]->GetBagSlot(), hisItems[i]->GetSlot(), true); } } // execute trade: 2. store moveItems(myItems, hisItems); // logging money if (HasPermission(rbac::RBAC_PERM_LOG_GM_TRADE)) { if (my_trade->GetMoney() > 0) { sLog->outCommand(_player->GetSession()->GetAccountId(), "GM %s (Account: %u) give money (Amount: " UI64FMTD ") to player: %s (Account: %u)", _player->GetName().c_str(), _player->GetSession()->GetAccountId(), my_trade->GetMoney(), trader->GetName().c_str(), trader->GetSession()->GetAccountId()); } if (his_trade->GetMoney() > 0) { sLog->outCommand(trader->GetSession()->GetAccountId(), "GM %s (Account: %u) give money (Amount: " UI64FMTD ") to player: %s (Account: %u)", trader->GetName().c_str(), trader->GetSession()->GetAccountId(), his_trade->GetMoney(), _player->GetName().c_str(), _player->GetSession()->GetAccountId()); } } // update money _player->ModifyMoney(-int64(my_trade->GetMoney())); _player->ModifyMoney(his_trade->GetMoney()); trader->ModifyMoney(-int64(his_trade->GetMoney())); trader->ModifyMoney(my_trade->GetMoney()); if (my_spell) my_spell->prepare(&my_targets); if (his_spell) his_spell->prepare(&his_targets); // cleanup clearAcceptTradeMode(my_trade, his_trade); delete _player->m_trade; _player->m_trade = NULL; delete trader->m_trade; trader->m_trade = NULL; // desynchronized with the other saves here (SaveInventoryAndGoldToDB() not have own transaction guards) SQLTransaction trans = CharacterDatabase.BeginTransaction(); _player->SaveInventoryAndGoldToDB(trans); trader->SaveInventoryAndGoldToDB(trans); CharacterDatabase.CommitTransaction(trans); trader->GetSession()->SendTradeStatus(TRADE_STATUS_TRADE_COMPLETE); SendTradeStatus(TRADE_STATUS_TRADE_COMPLETE); } else { trader->GetSession()->SendTradeStatus(TRADE_STATUS_TRADE_ACCEPT); } }
void WorldSession::HandleLootMasterGiveOpcode( WorldPacket & recv_data ) { CHECK_PACKET_SIZE(recv_data,8+1+8); uint8 slotid; uint64 lootguid, target_playerguid; recv_data >> lootguid >> slotid >> target_playerguid; if(!_player->GetGroup() || _player->GetGroup()->GetLooterGuid() != _player->GetGUID()) { _player->SendLootRelease(GetPlayer()->GetLootGUID()); return; } Player *target = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(target_playerguid, 0, HIGHGUID_PLAYER)); if(!target) return; sLog.outDebug("WorldSession::HandleLootMasterGiveOpcode (CMSG_LOOT_MASTER_GIVE, 0x02A3) Target = [%s].", target->GetName()); if(_player->GetLootGUID() != lootguid) return; Loot *pLoot = NULL; if(IS_CREATURE_GUID(GetPlayer()->GetLootGUID())) { Creature *pCreature = ObjectAccessor::GetCreature(*GetPlayer(), lootguid); if(!pCreature) return; pLoot = &pCreature->loot; } else if(IS_GAMEOBJECT_GUID(GetPlayer()->GetLootGUID())) { GameObject *pGO = ObjectAccessor::GetGameObject(*GetPlayer(), lootguid); if(!pGO) return; pLoot = &pGO->loot; } if(!pLoot) return; if (slotid > pLoot->items.size()) { sLog.outDebug("AutoLootItem: Player %s might be using a hack! (slot %d, size %d)",GetPlayer()->GetName(), slotid, pLoot->items.size()); return; } LootItem& item = pLoot->items[slotid]; ItemPosCountVec dest; uint8 msg = target->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, item.itemid, item.count ); if ( msg != EQUIP_ERR_OK ) { target->SendEquipError( msg, NULL, NULL ); _player->SendEquipError( msg, NULL, NULL ); // send duplicate of error massage to master looter return; } // not move item from loot to target inventory Item * newitem = target->StoreNewItem( dest, item.itemid, true, item.randomPropertyId ); target->SendNewItem(newitem, uint32(item.count), false, false, true ); // mark as looted item.count=0; item.is_looted=true; pLoot->NotifyItemRemoved(slotid); --pLoot->unlootedCount; }
void WorldSession::HandleAutostoreLootItemOpcode( WorldPacket & recv_data ) { CHECK_PACKET_SIZE(recv_data,1); sLog.outDebug("WORLD: CMSG_AUTOSTORE_LOOT_ITEM"); Player *player = GetPlayer(); uint64 lguid = player->GetLootGUID(); Loot *loot; uint8 lootSlot; recv_data >> lootSlot; if (IS_GAMEOBJECT_GUID(lguid)) { GameObject *go = ObjectAccessor::GetGameObject(*player, lguid); // not check distance for GO in case owned GO (fishing bobber case, for example) or Fishing hole GO if (!go || (go->GetOwnerGUID() != _player->GetGUID() && go->GetGoType() != GAMEOBJECT_TYPE_FISHINGHOLE) && !go->IsWithinDistInMap(_player,INTERACTION_DISTANCE)) { player->SendLootRelease(lguid); return; } loot = &go->loot; } else if (IS_ITEM_GUID(lguid)) { Item *pItem = player->GetItemByGuid( lguid ); if (!pItem) { player->SendLootRelease(lguid); return; } loot = &pItem->loot; } else { Creature* pCreature = ObjectAccessor::GetCreature(*player, lguid); bool ok_loot = pCreature && pCreature->isAlive() == (player->getClass()==CLASS_ROGUE && pCreature->lootForPickPocketed); if( !ok_loot || !pCreature->IsWithinDistInMap(_player,INTERACTION_DISTANCE) ) { player->SendLootRelease(lguid); return; } loot = &pCreature->loot; } QuestItem *qitem = NULL; QuestItem *ffaitem = NULL; QuestItem *conditem = NULL; LootItem *item = loot->LootItemInSlot(lootSlot,player,&qitem,&ffaitem,&conditem); if(!item) { player->SendEquipError( EQUIP_ERR_ALREADY_LOOTED, NULL, NULL ); return; } // questitems use the blocked field for other purposes if (!qitem && item->is_blocked) { player->SendLootRelease(lguid); return; } ItemPosCountVec dest; uint8 msg = player->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, item->itemid, item->count ); if ( msg == EQUIP_ERR_OK ) { Item * newitem = player->StoreNewItem( dest, item->itemid, true, item->randomPropertyId); if (qitem) { qitem->is_looted = true; //freeforall is 1 if everyone's supposed to get the quest item. if (item->freeforall || loot->GetPlayerQuestItems().size() == 1) player->SendNotifyLootItemRemoved(lootSlot); else loot->NotifyQuestItemRemoved(qitem->index); } else { if (ffaitem) { //freeforall case, notify only one player of the removal ffaitem->is_looted=true; player->SendNotifyLootItemRemoved(lootSlot); } else { //not freeforall, notify everyone if(conditem) conditem->is_looted=true; loot->NotifyItemRemoved(lootSlot); } } //if only one person is supposed to loot the item, then set it to looted if (!item->freeforall) item->is_looted = true; --loot->unlootedCount; player->SendNewItem(newitem, uint32(item->count), false, false, true); } else player->SendEquipError( msg, NULL, NULL ); }