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 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 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 }