void LootMgr::AddLoot(Loot* loot, uint32 itemid, uint32 mincount, uint32 maxcount) { uint32 i; uint32 count; ItemPrototype* itemproto = ItemPrototypeStorage.LookupEntry(itemid); if(itemproto) // this check is needed until loot DB is fixed { if(mincount == maxcount) count = maxcount; else count = RandomUInt(maxcount - mincount) + mincount; for(i = 0; i < loot->items.size(); ++i) { //itemid rand match a already placed item, if item is stackable and unique(stack), increment it, otherwise skips if((loot->items[i].item.itemproto == itemproto) && itemproto->MaxCount && ((loot->items[i].iItemsCount + count) < itemproto->MaxCount)) { if(itemproto->Unique && ((loot->items[i].iItemsCount + count) < itemproto->Unique)) { loot->items[i].iItemsCount += count; break; } else if(!itemproto->Unique) { loot->items[i].iItemsCount += count; break; } } } if(i != loot->items.size()) return; _LootItem item; item.itemproto = itemproto; item.displayid = itemproto->DisplayInfoID; __LootItem itm; itm.item = item; itm.iItemsCount = count; itm.roll = NULL; itm.passed = false; if( itemproto->HasFlag( ITEM_FLAG_FREE_FOR_ALL ) ) itm.ffa_loot = 1; else itm.ffa_loot = 0; itm.has_looted.clear(); if(itemproto->Quality > 1 && itemproto->ContainerSlots == 0) { itm.iRandomProperty = GetRandomProperties(itemproto); itm.iRandomSuffix = GetRandomSuffix(itemproto); } else { // save some calls :P itm.iRandomProperty = NULL; itm.iRandomSuffix = NULL; } loot->items.push_back(itm); } if(loot->items.size() > 16) { std::vector<__LootItem>::iterator item_to_remove; std::vector<__LootItem>::iterator itr; uint32 item_quality; bool quest_item; while(loot->items.size() > 16) { item_to_remove = loot->items.begin(); item_quality = 0; quest_item = false; for(itr = loot->items.begin(); itr != loot->items.end(); ++itr) { item_quality = (*itr).item.itemproto->Quality; quest_item = (*itr).item.itemproto->Class == ITEM_CLASS_QUEST; if((*item_to_remove).item.itemproto->Quality > item_quality && !quest_item) { item_to_remove = itr; } } loot->items.erase(item_to_remove); } } }
void LootMgr::LoadLootTables(const char* szTableName, LootStore* LootTable) { vector< pair< uint32, vector< tempy > > > db_cache; vector< pair< uint32, vector< tempy > > >::iterator itr; db_cache.reserve(10000); LootStore::iterator tab; QueryResult* result = WorldDatabase.Query("SELECT * FROM %s ORDER BY entryid ASC", szTableName); if(!result) { sLog.Error("LootMgr", "Loading loot from table %s failed.", szTableName); return; } uint32 entry_id = 0; uint32 last_entry = 0; uint32 total = (uint32) result->GetRowCount(); int pos = 0; vector< tempy > ttab; tempy t; do { Field* fields = result->Fetch(); entry_id = fields[ 0 ].GetUInt32(); if(entry_id < last_entry) { sLog.Error("LootMgr", "WARNING: Out of order loot table being loaded."); return; } if(entry_id != last_entry) { if(last_entry != 0) db_cache.push_back(make_pair(last_entry, ttab)); ttab.clear(); } t.itemid = fields[ 1 ].GetUInt32(); t.chance = fields[ 2 ].GetFloat(); t.chance_2 = fields[ 3 ].GetFloat(); t.chance3 = fields[ 4 ].GetFloat(); t.chance4 = fields[ 5 ].GetFloat(); t.mincount = fields[ 6 ].GetUInt32(); t.maxcount = fields[ 7 ].GetUInt32(); ttab.push_back(t); last_entry = entry_id; } while(result->NextRow()); //last list was not pushed in if(last_entry != 0 && ttab.size()) db_cache.push_back(make_pair(last_entry, ttab)); pos = 0; total = (uint32)db_cache.size(); ItemPrototype* proto; uint32 itemid; for(itr = db_cache.begin(); itr != db_cache.end(); ++itr) { entry_id = (*itr).first; if(LootTable->end() == LootTable->find(entry_id)) { StoreLootList list; list.count = static_cast< uint32 >(itr->second.size()); list.items = new StoreLootItem[list.count]; uint32 ind = 0; for(vector< tempy >::iterator itr2 = itr->second.begin(); itr2 != itr->second.end(); ++itr2) { //Omit items that are not in db to prevent future bugs itemid = itr2->itemid; proto = ItemPrototypeStorage.LookupEntry(itemid); if(!proto) { list.items[ind].item.itemproto = NULL; Log.Error("LootMgr", "Loot for %u contains non-existant item %u . (%s)", entry_id, itemid, szTableName); } else { list.items[ind].item.itemproto = proto; list.items[ind].item.displayid = proto->DisplayInfoID; list.items[ind].chance = itr2->chance; list.items[ind].chance2 = itr2->chance_2; list.items[ind].chance3 = itr2->chance3; list.items[ind].chance4 = itr2->chance4; list.items[ind].mincount = itr2->mincount; list.items[ind].maxcount = itr2->maxcount; if( proto->HasFlag( ITEM_FLAG_FREE_FOR_ALL ) ) list.items[ ind ].ffa_loot = 1; else list.items[ ind ].ffa_loot = 0; if(LootTable == &GOLoot) { if(proto->Class == ITEM_CLASS_QUEST) { sQuestMgr.SetGameObjectLootQuest(itr->first, itemid); quest_loot_go[entry_id].insert(proto->ItemId); } } } ind++; } (*LootTable)[entry_id] = list; } } //sLog.outString(" %d loot templates loaded from %s", db_cache.size(), szTableName); delete result; }
void WorldSession::HandleUseItemOpcode(WorldPacket & recvPacket) { CHECK_INWORLD_RETURN typedef std::list<Aura*> AuraList; Player* p_User = GetPlayer(); LOG_DETAIL("WORLD: got use Item packet, data length = %i", recvPacket.size()); int8 tmp1, slot; uint8 unk; //Alice : added in 3.0.2 uint64 item_guid; uint8 cn; uint32 spellId = 0; uint32 glyphIndex; bool found = false; recvPacket >> tmp1; recvPacket >> slot; recvPacket >> cn; recvPacket >> spellId; recvPacket >> item_guid; recvPacket >> glyphIndex; recvPacket >> unk; Item* tmpItem = NULL; tmpItem = p_User->GetItemInterface()->GetInventoryItem(tmp1, slot); if(!tmpItem) tmpItem = p_User->GetItemInterface()->GetInventoryItem(slot); if(!tmpItem) return; ItemPrototype* itemProto = tmpItem->GetProto(); // only some consumable items can be used in arenas if( ( itemProto->Class == ITEM_CLASS_CONSUMABLE ) && !itemProto->HasFlag( ITEM_FLAG_USEABLE_IN_ARENA ) && ( GetPlayer()->m_bg != NULL ) && IS_ARENA( GetPlayer()->m_bg->GetType() ) ) { GetPlayer()->GetItemInterface()->BuildInventoryChangeError(tmpItem, NULL, INV_ERR_NOT_DURING_ARENA_MATCH); return; } if(tmpItem->IsSoulbound()) // SouldBind item will be used after SouldBind() { if(sScriptMgr.CallScriptedItem(tmpItem, _player)) return; } if(_player->getDeathState() == CORPSE) return; if(itemProto->Bonding == ITEM_BIND_ON_USE) tmpItem->SoulBind(); if(sScriptMgr.CallScriptedItem(tmpItem, _player)) return; if(itemProto->InventoryType != 0 && !_player->GetItemInterface()->IsEquipped(itemProto->ItemId)) //Equipable items cannot be used before they're equipped. Prevents exploits return;//Prevents exploits such as keeping an on-use trinket in your bag and using WPE to use it from your bag in mid-combat. if(itemProto->QuestId) { // Item Starter Quest* qst = QuestStorage.LookupEntry(itemProto->QuestId); if(!qst) return; WorldPacket data; sQuestMgr.BuildQuestDetails(&data, qst, tmpItem, 0, language, _player); SendPacket(&data); } // Let's check if the item even has that spell for(int i = 0; i < 5; ++i) { if(itemProto->Spells[i].Trigger == USE && itemProto->Spells[i].Id == spellId) { found = true; break;//found 1 already } } // Let's see if it is an onuse spellid if(tmpItem->HasOnUseSpellID(spellId)) found = true; // We didn't find the spell, so the player is probably trying to cheat // with an edited itemcache.wdb // // Altough this could also happen after a DB update // if he/she didn't delete his/her cache. if(found == false) { this->Disconnect(); Anticheat_Log->writefromsession(this, "Player tried to use an item with a spell that didn't match the spell in the database."); Anticheat_Log->writefromsession(this, "Possibly corrupted or intentionally altered itemcache.wdb"); Anticheat_Log->writefromsession(this, "Itemid: %lu", itemProto->ItemId); Anticheat_Log->writefromsession(this, "Spellid: %lu", spellId); Anticheat_Log->writefromsession(this, "Player was disconnected"); return; } SpellCastTargets targets(recvPacket, _player->GetGUID()); SpellEntry* spellInfo = dbcSpell.LookupEntryForced(spellId); if(spellInfo == NULL) { LOG_DETAIL("ERROR: WORLD: unknown spell id %i", spellId); return; } if(spellInfo->AuraInterruptFlags & AURA_INTERRUPT_ON_STAND_UP) { if(p_User->CombatStatus.IsInCombat() || p_User->IsMounted()) { _player->GetItemInterface()->BuildInventoryChangeError(tmpItem, NULL, INV_ERR_CANT_DO_IN_COMBAT); return; } if(p_User->GetStandState() != 1) p_User->SetStandState(STANDSTATE_SIT); // loop through the auras and removing existing eating spells } else // cebernic: why not stand up { if(!p_User->CombatStatus.IsInCombat() && !p_User->IsMounted()) { if(p_User->GetStandState()) { p_User->SetStandState(STANDSTATE_STAND); } } } // cebernic: remove stealth on using item if(!(spellInfo->AuraInterruptFlags & ATTRIBUTESEX_NOT_BREAK_STEALTH)) { if(p_User->IsStealth()) p_User->RemoveAllAuraType(SPELL_AURA_MOD_STEALTH); } if(itemProto->RequiredLevel) { if(_player->getLevel() < itemProto->RequiredLevel) { _player->GetItemInterface()->BuildInventoryChangeError(tmpItem, NULL, INV_ERR_ITEM_RANK_NOT_ENOUGH); return; } } if(itemProto->RequiredSkill) { if(!_player->_HasSkillLine(itemProto->RequiredSkill)) { _player->GetItemInterface()->BuildInventoryChangeError(tmpItem, NULL, INV_ERR_ITEM_RANK_NOT_ENOUGH); return; } if(itemProto->RequiredSkillRank) { if(_player->_GetSkillLineCurrent(itemProto->RequiredSkill, false) < itemProto->RequiredSkillRank) { _player->GetItemInterface()->BuildInventoryChangeError(tmpItem, NULL, INV_ERR_ITEM_RANK_NOT_ENOUGH); return; } } } if((itemProto->AllowableClass && !(_player->getClassMask() & itemProto->AllowableClass)) || (itemProto->AllowableRace && !(_player->getRaceMask() & itemProto->AllowableRace))) { _player->GetItemInterface()->BuildInventoryChangeError(tmpItem, NULL, INV_ERR_YOU_CAN_NEVER_USE_THAT_ITEM); return; } if(!_player->Cooldown_CanCast(spellInfo)) { _player->SendCastResult(spellInfo->Id, SPELL_FAILED_NOT_READY, cn, 0); return; } if(_player->m_currentSpell) { _player->SendCastResult(spellInfo->Id, SPELL_FAILED_SPELL_IN_PROGRESS, cn, 0); return; } if(itemProto->ForcedPetId >= 0) { if(itemProto->ForcedPetId == 0) { if(_player->GetGUID() != targets.m_unitTarget) { _player->SendCastResult(spellInfo->Id, SPELL_FAILED_BAD_TARGETS, cn, 0); return; } } else { if(!_player->GetSummon() || _player->GetSummon()->GetEntry() != (uint32)itemProto->ForcedPetId) { _player->SendCastResult(spellInfo->Id, SPELL_FAILED_SPELL_IN_PROGRESS, cn, 0); return; } } } Spell* spell = sSpellFactoryMgr.NewSpell(_player, spellInfo, false, NULL); spell->extra_cast_number = cn; spell->i_caster = tmpItem; spell->m_glyphslot = glyphIndex; //GetPlayer()->setCurrentSpell(spell); spell->prepare(&targets); #ifdef ENABLE_ACHIEVEMENTS _player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM, itemProto->ItemId, 0, 0); #endif }
/*Loot type MUST be 1-corpse, go 2-skinning/herbalism/minning 3-Fishing */ void Player::SendLoot(uint64 guid, uint8 loot_type, uint32 mapid) { Group* m_Group = m_playerInfo->m_Group; if(!IsInWorld()) return; Loot* pLoot = NULL; uint32 guidtype = GET_TYPE_FROM_GUID(guid); int8 loot_method; if(m_Group != NULL) loot_method = m_Group->GetMethod(); else loot_method = PARTY_LOOT_FFA; if(guidtype == HIGHGUID_TYPE_UNIT) { Creature* pCreature = GetMapMgr()->GetCreature(GET_LOWGUID_PART(guid)); if(!pCreature)return; pLoot = &pCreature->loot; m_currentLoot = pCreature->GetGUID(); } else if(guidtype == HIGHGUID_TYPE_GAMEOBJECT) { GameObject* pGO = GetMapMgr()->GetGameObject(GET_LOWGUID_PART(guid)); if(!pGO)return; pGO->SetByte(GAMEOBJECT_BYTES_1, 0, 0); pLoot = &pGO->loot; m_currentLoot = pGO->GetGUID(); } else if((guidtype == HIGHGUID_TYPE_PLAYER)) { Player* p = GetMapMgr()->GetPlayer((uint32)guid); if(!p)return; pLoot = &p->loot; m_currentLoot = p->GetGUID(); } else if((guidtype == HIGHGUID_TYPE_CORPSE)) { Corpse* pCorpse = objmgr.GetCorpse((uint32)guid); if(!pCorpse)return; pLoot = &pCorpse->loot; m_currentLoot = pCorpse->GetGUID(); } else if((guidtype == HIGHGUID_TYPE_ITEM)) { Item* pItem = GetItemInterface()->GetItemByGUID(guid); if(!pItem) return; pLoot = pItem->loot; m_currentLoot = pItem->GetGUID(); } if(!pLoot) { // something whack happened.. damn cheaters.. return; } // add to looter set pLoot->looters.insert(GetLowGUID()); WorldPacket data, data2(32); data.SetOpcode(SMSG_LOOT_RESPONSE); m_lootGuid = guid; data << uint64(guid); data << uint8(loot_type); //loot_type; data << uint32(pLoot->gold); data << uint8(0); //loot size reserve std::vector<__LootItem>::iterator iter = pLoot->items.begin(); uint32 count = 0; uint8 slottype = 0; for(uint32 x = 0; iter != pLoot->items.end(); iter++, x++) { if(iter->iItemsCount == 0) continue; LooterSet::iterator itr = iter->has_looted.find(GetLowGUID()); if(iter->has_looted.end() != itr) continue; ItemPrototype* itemProto = iter->item.itemproto; if(!itemProto) continue; // check if it's on ML if so only quest items and ffa loot should be shown based on mob if(loot_method == PARTY_LOOT_MASTER && m_Group && m_Group->GetLooter() != m_playerInfo) // pass on all ffa_loot and the grey / white items if(!iter->ffa_loot && !(itemProto->Quality < m_Group->GetThreshold())) continue; // team check if( itemProto->HasFlag2(ITEM_FLAG2_HORDE_ONLY) && IsTeamAlliance() ) continue; if( itemProto->HasFlag2(ITEM_FLAG2_ALLIANCE_ONLY) && IsTeamHorde() ) continue; //quest items check. type 4/5 //quest items that don't start quests. if((itemProto->Bonding == ITEM_BIND_QUEST) && !(itemProto->QuestId) && !HasQuestForItem(itemProto->ItemId)) continue; if((itemProto->Bonding == ITEM_BIND_QUEST2) && !(itemProto->QuestId) && !HasQuestForItem(itemProto->ItemId)) continue; //quest items that start quests need special check to avoid drops all the time. if((itemProto->Bonding == ITEM_BIND_QUEST) && (itemProto->QuestId) && GetQuestLogForEntry(itemProto->QuestId)) continue; if((itemProto->Bonding == ITEM_BIND_QUEST2) && (itemProto->QuestId) && GetQuestLogForEntry(itemProto->QuestId)) continue; if((itemProto->Bonding == ITEM_BIND_QUEST) && (itemProto->QuestId) && HasFinishedQuest(itemProto->QuestId)) continue; if((itemProto->Bonding == ITEM_BIND_QUEST2) && (itemProto->QuestId) && HasFinishedQuest(itemProto->QuestId)) continue; //check for starting item quests that need questlines. if((itemProto->QuestId && itemProto->Bonding != ITEM_BIND_QUEST && itemProto->Bonding != ITEM_BIND_QUEST2)) { Quest* pQuest = QuestStorage.LookupEntry(itemProto->QuestId); if(pQuest) { uint32 finishedCount = 0; //check if its a questline. for(uint32 i = 0; i < pQuest->count_requiredquests; i++) { if(pQuest->required_quests[i]) { if(!HasFinishedQuest(pQuest->required_quests[i]) || GetQuestLogForEntry(pQuest->required_quests[i])) { } else { finishedCount++; } } } } } slottype = 0; if(m_Group != NULL && loot_type < 2) { switch(loot_method) { case PARTY_LOOT_MASTER: slottype = 2; break; case PARTY_LOOT_GROUP: case PARTY_LOOT_RR: case PARTY_LOOT_NBG: slottype = 1; break; default: slottype = 0; break; } // only quality items are distributed if(itemProto->Quality < m_Group->GetThreshold()) { slottype = 0; } // if all people passed anyone can loot it? :P if(iter->passed) slottype = 0; // All players passed on the loot //if it is ffa loot and not an masterlooter if(iter->ffa_loot) slottype = 0; } data << uint8(x); data << uint32(itemProto->ItemId); data << uint32(iter->iItemsCount); //nr of items of this type data << uint32(iter->item.displayid); if(iter->iRandomSuffix) { data << uint32(Item::GenerateRandomSuffixFactor(itemProto)); data << uint32(-int32(iter->iRandomSuffix->id)); } else if(iter->iRandomProperty) { data << uint32(0); data << uint32(iter->iRandomProperty->ID); } else { data << uint32(0); data << uint32(0); } data << slottype; // "still being rolled for" flag if(slottype == 1) { if(iter->roll == NULL && !iter->passed) { int32 ipid = 0; uint32 factor = 0; if(iter->iRandomProperty) ipid = iter->iRandomProperty->ID; else if(iter->iRandomSuffix) { ipid = -int32(iter->iRandomSuffix->id); factor = Item::GenerateRandomSuffixFactor(iter->item.itemproto); } if(iter->item.itemproto) { iter->roll = new LootRoll(60000, (m_Group != NULL ? m_Group->MemberCount() : 1), guid, x, itemProto->ItemId, factor, uint32(ipid), GetMapMgr()); data2.Initialize(SMSG_LOOT_START_ROLL); data2 << guid; data2 << uint32(mapid); data2 << uint32(x); data2 << uint32(itemProto->ItemId); data2 << uint32(factor); if(iter->iRandomProperty) data2 << uint32(iter->iRandomProperty->ID); else if(iter->iRandomSuffix) data2 << uint32(ipid); else data2 << uint32(0); data2 << uint32(iter->iItemsCount); data2 << uint32(60000); // countdown data2 << uint8(7); // some sort of flags that require research } Group* pGroup = m_playerInfo->m_Group; if(pGroup) { pGroup->Lock(); for(uint32 i = 0; i < pGroup->GetSubGroupCount(); ++i) { for(GroupMembersSet::iterator itr2 = pGroup->GetSubGroup(i)->GetGroupMembersBegin(); itr2 != pGroup->GetSubGroup(i)->GetGroupMembersEnd(); ++itr2) { PlayerInfo* pinfo = *itr2; if(pinfo->m_loggedInPlayer && pinfo->m_loggedInPlayer->GetItemInterface()->CanReceiveItem(itemProto, iter->iItemsCount) == 0) { if(pinfo->m_loggedInPlayer->m_passOnLoot) iter->roll->PlayerRolled(pinfo->m_loggedInPlayer, 3); // passed else pinfo->m_loggedInPlayer->SendPacket(&data2); } else iter->roll->OfflineRoll(pinfo->guid); } } pGroup->Unlock(); } else { m_session->SendPacket(&data2); } } } count++; } data.wpos(13); data << uint8(count); m_session->SendPacket(&data); SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_LOOTING); }
bool ChatHandler::HandleAddInvItemCommand(const char *args, WorldSession *m_session) { uint32 itemid, count=1; int32 randomprop=0; if(strlen(args) < 1) { return false; } if(sscanf(args, "%u %u %d", &itemid, &count, &randomprop) < 1) return false; Player *chr = getSelectedChar(m_session); if (chr == NULL) return true; ItemPrototype* it = ItemPrototypeStorage.LookupEntry(itemid); if(it) { sGMLog.writefromsession(m_session, "used add item command, item id %u [%s] to %s", it->ItemId, it->Name1, chr->GetName()); Item *item; item = objmgr.CreateItem( itemid, chr); item->SetUInt32Value(ITEM_FIELD_STACK_COUNT, ((count > it->MaxCount) ? it->MaxCount : count)); if(it->Bonding==ITEM_BIND_ON_PICKUP) item->SoulBind(); uint32 pr = 0; uint32 sf = 0; if(randomprop!=0) { if(randomprop<0) { sf = abs(int(randomprop)); item->SetRandomSuffix(abs(int(randomprop))); } else { pr = randomprop; item->SetRandomProperty(randomprop); } item->ApplyRandomProperties(false); } if(!chr->GetItemInterface()->AddItemToFreeSlot(item)) { m_session->SendNotification("No free slots were found in your inventory!"); delete item; return true; } char messagetext[500]; string itemlink = it->ConstructItemLink(pr, sf, item->GetUInt32Value(ITEM_FIELD_STACK_COUNT)); snprintf(messagetext, 500, "Adding item %d %s to %s's inventory.",(unsigned int)it->ItemId,itemlink.c_str(), chr->GetName()); SystemMessage(m_session, messagetext); snprintf(messagetext, 500, "%s added item %d %s to your inventory.", m_session->GetPlayer()->GetName(), (unsigned int)itemid, itemlink.c_str()); SystemMessageToPlr(chr, messagetext); SlotResult *lr = chr->GetItemInterface()->LastSearchResult(); chr->GetSession()->SendItemPushResult(item,false,true,false,true,lr->ContainerSlot,lr->Slot,item->GetUInt32Value(ITEM_FIELD_STACK_COUNT)); return true; } else { RedSystemMessage(m_session, "Item %d is not a valid item!",itemid); return true; } }