diff options
Diffstat (limited to 'src/game')
-rw-r--r-- | src/game/Chat.cpp | 1 | ||||
-rw-r--r-- | src/game/Chat.h | 1 | ||||
-rw-r--r-- | src/game/Debugcmds.cpp | 7 | ||||
-rw-r--r-- | src/game/Item.cpp | 30 | ||||
-rw-r--r-- | src/game/Item.h | 21 | ||||
-rw-r--r-- | src/game/Level3.cpp | 9 | ||||
-rw-r--r-- | src/game/ObjectMgr.cpp | 100 | ||||
-rw-r--r-- | src/game/ObjectMgr.h | 11 | ||||
-rw-r--r-- | src/game/PetHandler.cpp | 14 | ||||
-rw-r--r-- | src/game/Spell.cpp | 40 | ||||
-rw-r--r-- | src/game/Spell.h | 1 | ||||
-rw-r--r-- | src/game/SpellHandler.cpp | 22 | ||||
-rw-r--r-- | src/game/World.cpp | 3 |
13 files changed, 226 insertions, 34 deletions
diff --git a/src/game/Chat.cpp b/src/game/Chat.cpp index 1722fd9602c..527406a76d1 100644 --- a/src/game/Chat.cpp +++ b/src/game/Chat.cpp @@ -447,6 +447,7 @@ ChatCommand * ChatHandler::getCommandTable() { "gameobject_scripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadGameObjectScriptsCommand, "", NULL }, { "item_enchantment_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadItemEnchantementsCommand, "", NULL }, { "item_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesItemCommand, "", NULL }, + { "item_required_target", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadItemRequiredTragetCommand, "", NULL }, { "locales_achievement_reward", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesAchievementRewardCommand,"", NULL }, { "locales_creature", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesCreatureCommand, "", NULL }, { "locales_gameobject", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesGameobjectCommand, "", NULL }, diff --git a/src/game/Chat.h b/src/game/Chat.h index 0b8b076969b..6fbc9b30d34 100644 --- a/src/game/Chat.h +++ b/src/game/Chat.h @@ -359,6 +359,7 @@ class ChatHandler bool HandleReloadGOQuestRelationsCommand(const char* args); bool HandleReloadGOQuestInvRelationsCommand(const char* args); bool HandleReloadItemEnchantementsCommand(const char* args); + bool HandleReloadItemRequiredTragetCommand(const char* args); bool HandleReloadLocalesAchievementRewardCommand(const char* args); bool HandleReloadLocalesCreatureCommand(const char* args); bool HandleReloadLocalesGameobjectCommand(const char* args); diff --git a/src/game/Debugcmds.cpp b/src/game/Debugcmds.cpp index 196816fff02..2e432ab1c0f 100644 --- a/src/game/Debugcmds.cpp +++ b/src/game/Debugcmds.cpp @@ -43,7 +43,7 @@ bool ChatHandler::HandleDebugSendSpellFailCommand(const char* args) return false; char* px = strtok((char*)args, " "); - if(!px) + if (!px) return false; uint8 failnum = (uint8)atoi(px); @@ -56,14 +56,13 @@ bool ChatHandler::HandleDebugSendSpellFailCommand(const char* args) char* p2 = strtok(NULL, " "); uint8 failarg2 = p2 ? (uint8)atoi(p2) : 0; - WorldPacket data(SMSG_CAST_FAILED, 5); data << uint8(0); data << uint32(133); data << uint8(failnum); - if(p1 || p2) + if (p1 || p2) data << uint32(failarg1); - if(p2) + if (p2) data << uint32(failarg2); m_session->SendPacket(&data); diff --git a/src/game/Item.cpp b/src/game/Item.cpp index 36ddcd16828..06268f2fef7 100644 --- a/src/game/Item.cpp +++ b/src/game/Item.cpp @@ -776,6 +776,23 @@ bool Item::IsFitToSpellRequirements(SpellEntry const* spellInfo) const return true; } +bool Item::IsTargetValidForItemUse(Unit* pUnitTarget) +{ + ItemRequiredTargetMapBounds bounds = objmgr.GetItemRequiredTargetMapBounds(GetProto()->ItemId); + + if (bounds.first == bounds.second) + return true; + + if (!pUnitTarget) + return false; + + for(ItemRequiredTargetMap::const_iterator itr = bounds.first; itr != bounds.second; ++itr) + if(itr->second.IsFitToRequirements(pUnitTarget)) + return true; + + return false; +} + void Item::SetEnchantment(EnchantmentSlot slot, uint32 id, uint32 duration, uint32 charges) { // Better lost small time at check in comparison lost time at item save to DB. @@ -982,3 +999,16 @@ bool Item::IsBindedNotWith( Player const* player ) const return objmgr.GetPlayerAccountIdByGUID(GetOwnerGUID()) != player->GetSession()->GetAccountId(); } } + +bool ItemRequiredTarget::IsFitToRequirements( Unit* pUnitTarget ) const +{ + switch(m_uiType) + { + case ITEM_TARGET_TYPE_CREATURE: + return pUnitTarget->isAlive(); + case ITEM_TARGET_TYPE_DEAD: + return !pUnitTarget->isAlive(); + default: + return false; + } +} diff --git a/src/game/Item.h b/src/game/Item.h index 30cf1a595cb..9cae8f67105 100644 --- a/src/game/Item.h +++ b/src/game/Item.h @@ -29,6 +29,7 @@ struct SpellEntry; class Bag; class QueryResult; +class Unit; struct ItemSetEffect { @@ -197,6 +198,24 @@ enum ItemUpdateState ITEM_REMOVED = 3 }; +enum ItemRequiredTargetType +{ + ITEM_TARGET_TYPE_CREATURE = 1, + ITEM_TARGET_TYPE_DEAD = 2 +}; + +#define MAX_ITEM_REQ_TARGET_TYPE 2 + +struct ItemRequiredTarget +{ + ItemRequiredTarget(ItemRequiredTargetType uiType, uint32 uiTargetEntry) : m_uiType(uiType), m_uiTargetEntry(uiTargetEntry) {} + ItemRequiredTargetType m_uiType; + uint32 m_uiTargetEntry; + + // helpers + bool IsFitToRequirements(Unit* pUnitTarget) const; +}; + bool ItemCanGoIntoBag(ItemPrototype const *proto, ItemPrototype const *pBagProto); class TRINITY_DLL_SPEC Item : public Object @@ -232,6 +251,7 @@ class TRINITY_DLL_SPEC Item : public Object bool IsInTrade() const { return mb_in_trade; } bool IsFitToSpellRequirements(SpellEntry const* spellInfo) const; + bool IsTargetValidForItemUse(Unit* pUnitTarget); bool IsLimitedToAnotherMapOrZone( uint32 cur_mapId, uint32 cur_zoneId) const; bool GemsFitSockets() const; @@ -296,6 +316,7 @@ class TRINITY_DLL_SPEC Item : public Object bool IsWeaponVellum() const { return GetProto()->IsWeaponVellum(); } bool IsArmorVellum() const { return GetProto()->IsArmorVellum(); } bool IsConjuredConsumable() const { return GetProto()->IsConjuredConsumable(); } + private: uint8 m_slot; Bag *m_container; diff --git a/src/game/Level3.cpp b/src/game/Level3.cpp index fe8cca2da4b..77c81144d48 100644 --- a/src/game/Level3.cpp +++ b/src/game/Level3.cpp @@ -668,6 +668,7 @@ bool ChatHandler::HandleReloadAllItemCommand(const char*) { HandleReloadPageTextsCommand("a"); HandleReloadItemEnchantementsCommand("a"); + HandleReloadItemRequiredTragetCommand("a"); return true; } @@ -1107,6 +1108,14 @@ bool ChatHandler::HandleReloadItemEnchantementsCommand(const char*) return true; } +bool ChatHandler::HandleReloadItemRequiredTragetCommand(const char*) +{ + sLog.outString( "Re-Loading Item Required Targets Table..." ); + objmgr.LoadItemRequiredTarget(); + SendGlobalSysMessage("DB table `item_required_target` reloaded."); + return true; +} + bool ChatHandler::HandleReloadGameObjectScriptsCommand(const char* arg) { if(sWorld.IsScriptScheduled()) diff --git a/src/game/ObjectMgr.cpp b/src/game/ObjectMgr.cpp index 8c0e5d6e1bd..350bf5d3a15 100644 --- a/src/game/ObjectMgr.cpp +++ b/src/game/ObjectMgr.cpp @@ -2117,6 +2117,106 @@ void ObjectMgr::LoadItemPrototypes() } } +void ObjectMgr::LoadItemRequiredTarget() +{ + m_ItemRequiredTarget.clear(); // needed for reload case + + uint32 count = 0; + + QueryResult *result = WorldDatabase.Query("SELECT entry,type,targetEntry FROM item_required_target"); + + if (!result) + { + barGoLink bar(1); + + bar.step(); + + sLog.outString(); + sLog.outErrorDb(">> Loaded 0 ItemRequiredTarget. DB table `item_required_target` is empty."); + return; + } + + barGoLink bar(result->GetRowCount()); + + do + { + Field *fields = result->Fetch(); + bar.step(); + + uint32 uiItemId = fields[0].GetUInt32(); + uint32 uiType = fields[1].GetUInt32(); + uint32 uiTargetEntry = fields[2].GetUInt32(); + + ItemPrototype const* pItemProto = sItemStorage.LookupEntry<ItemPrototype>(uiItemId); + + if (!pItemProto) + { + sLog.outErrorDb("Table `item_required_target`: Entry %u listed for TargetEntry %u does not exist in `item_template`.",uiItemId,uiTargetEntry); + continue; + } + + bool bIsItemSpellValid = false; + + for(int i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i) + { + if (SpellEntry const* pSpellInfo = sSpellStore.LookupEntry(pItemProto->Spells[i].SpellId)) + { + if (pItemProto->Spells[i].SpellTrigger == ITEM_SPELLTRIGGER_ON_USE || + pItemProto->Spells[i].SpellTrigger == ITEM_SPELLTRIGGER_ON_NO_DELAY_USE) + { + SpellScriptTarget::const_iterator lower = spellmgr.GetBeginSpellScriptTarget(pSpellInfo->Id); + SpellScriptTarget::const_iterator upper = spellmgr.GetEndSpellScriptTarget(pSpellInfo->Id); + + if (lower != upper) + break; + + if (pSpellInfo->EffectImplicitTargetA[i] == TARGET_UNIT_TARGET_ENEMY || + pSpellInfo->EffectImplicitTargetB[i] == TARGET_UNIT_TARGET_ENEMY || + pSpellInfo->EffectImplicitTargetA[i] == TARGET_UNIT_TARGET_ANY || + pSpellInfo->EffectImplicitTargetB[i] == TARGET_UNIT_TARGET_ANY) + { + bIsItemSpellValid = true; + break; + } + } + } + } + + if (!bIsItemSpellValid) + { + sLog.outErrorDb("Table `item_required_target`: Spell used by item %u does not have implicit target TARGET_CHAIN_DAMAGE(6), TARGET_DUELVSPLAYER(25), already listed in `spell_script_target` or doesn't have item spelltrigger.",uiItemId); + continue; + } + + if (!uiType || uiType > MAX_ITEM_REQ_TARGET_TYPE) + { + sLog.outErrorDb("Table `item_required_target`: Type %u for TargetEntry %u is incorrect.",uiType,uiTargetEntry); + continue; + } + + if (!uiTargetEntry) + { + sLog.outErrorDb("Table `item_required_target`: TargetEntry == 0 for Type (%u).",uiType); + continue; + } + + if (!sCreatureStorage.LookupEntry<CreatureInfo>(uiTargetEntry)) + { + sLog.outErrorDb("Table `item_required_target`: creature template entry %u does not exist.",uiTargetEntry); + continue; + } + + m_ItemRequiredTarget.insert(ItemRequiredTargetMap::value_type(uiItemId,ItemRequiredTarget(ItemRequiredTargetType(uiType),uiTargetEntry))); + + ++count; + } while (result->NextRow()); + + delete result; + + sLog.outString(); + sLog.outString(">> Loaded %u Item required targets", count); +} + void ObjectMgr::LoadPetLevelInfo() { // Loading levels data diff --git a/src/game/ObjectMgr.h b/src/game/ObjectMgr.h index ae1222cccfb..b8d282569f1 100644 --- a/src/game/ObjectMgr.h +++ b/src/game/ObjectMgr.h @@ -160,6 +160,8 @@ typedef UNORDERED_MAP<uint32,NpcOptionLocale> NpcOptionLocaleMap; typedef UNORDERED_MAP<uint32,PointOfInterestLocale> PointOfInterestLocaleMap; typedef std::multimap<uint32,uint32> QuestRelations; +typedef std::multimap<uint32,ItemRequiredTarget> ItemRequiredTargetMap; +typedef std::pair<ItemRequiredTargetMap::const_iterator, ItemRequiredTargetMap::const_iterator> ItemRequiredTargetMapBounds; struct PetLevelInfo { @@ -534,6 +536,7 @@ class ObjectMgr void LoadGameobjects(); void LoadGameobjectRespawnTimes(); void LoadItemPrototypes(); + void LoadItemRequiredTarget(); void LoadItemLocales(); void LoadQuestLocales(); void LoadNpcTextLocales(); @@ -805,6 +808,12 @@ class ObjectMgr uint32 GetScriptId(const char *name); int GetOrNewIndexForLocale(LocaleConstant loc); + + ItemRequiredTargetMapBounds GetItemRequiredTargetMapBounds(uint32 uiItemEntry) const + { + return ItemRequiredTargetMapBounds(m_ItemRequiredTarget.lower_bound(uiItemEntry),m_ItemRequiredTarget.upper_bound(uiItemEntry)); + } + protected: // first free id for selected id type @@ -867,6 +876,8 @@ class ObjectMgr ScriptNameMap m_scriptNames; + ItemRequiredTargetMap m_ItemRequiredTarget; + typedef std::vector<LocaleConstant> LocalForIndex; LocalForIndex m_LocalForIndex; diff --git a/src/game/PetHandler.cpp b/src/game/PetHandler.cpp index 87c667f1e77..7547d125d9c 100644 --- a/src/game/PetHandler.cpp +++ b/src/game/PetHandler.cpp @@ -286,19 +286,7 @@ void WorldSession::HandlePetActionHelper(Unit *pet, uint64 guid1, uint16 spellid else { if(pet->isPossessed()) - { - WorldPacket data(SMSG_CAST_FAILED, (4+1+1)); - data << uint8(0) << uint32(spellid) << uint8(result); - switch (result) - { - case SPELL_FAILED_REQUIRES_SPELL_FOCUS: - data << uint32(spellInfo->RequiresSpellFocus); - break; - default: - break; - } - SendPacket(&data); - } + Spell::SendCastResult(GetPlayer(),spellInfo,0,result); else pet->SendPetCastFail(spellid, result); diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp index ebb3a355a95..8d9cf6e5265 100644 --- a/src/game/Spell.cpp +++ b/src/game/Spell.cpp @@ -3125,18 +3125,26 @@ void Spell::SendCastResult(SpellCastResult result) if(((Player*)m_caster)->GetSession()->PlayerLoading()) // don't send cast results at loading time return; + SendCastResult((Player*)m_caster,m_spellInfo,m_cast_count,result); +} + +void Spell::SendCastResult(Player* caster, SpellEntry const* spellInfo, uint8 cast_count, SpellCastResult result) +{ + if(result == SPELL_CAST_OK) + return; + WorldPacket data(SMSG_CAST_FAILED, (4+1+1)); - data << uint8(m_cast_count); // single cast or multi 2.3 (0/1) - data << uint32(m_spellInfo->Id); + data << uint8(cast_count); // single cast or multi 2.3 (0/1) + data << uint32(spellInfo->Id); data << uint8(result); // problem switch (result) { case SPELL_FAILED_REQUIRES_SPELL_FOCUS: - data << uint32(m_spellInfo->RequiresSpellFocus); + data << uint32(spellInfo->RequiresSpellFocus); break; case SPELL_FAILED_REQUIRES_AREA: // hardcode areas limitation case - switch(m_spellInfo->Id) + switch(spellInfo->Id) { case 41617: // Cenarion Mana Salve case 41619: // Cenarion Healing Salve @@ -3155,26 +3163,26 @@ void Spell::SendCastResult(SpellCastResult result) } break; case SPELL_FAILED_TOTEMS: - if(m_spellInfo->Totem[0]) - data << uint32(m_spellInfo->Totem[0]); - if(m_spellInfo->Totem[1]) - data << uint32(m_spellInfo->Totem[1]); + if(spellInfo->Totem[0]) + data << uint32(spellInfo->Totem[0]); + if(spellInfo->Totem[1]) + data << uint32(spellInfo->Totem[1]); break; case SPELL_FAILED_TOTEM_CATEGORY: - if(m_spellInfo->TotemCategory[0]) - data << uint32(m_spellInfo->TotemCategory[0]); - if(m_spellInfo->TotemCategory[1]) - data << uint32(m_spellInfo->TotemCategory[1]); + if(spellInfo->TotemCategory[0]) + data << uint32(spellInfo->TotemCategory[0]); + if(spellInfo->TotemCategory[1]) + data << uint32(spellInfo->TotemCategory[1]); break; case SPELL_FAILED_EQUIPPED_ITEM_CLASS: - data << uint32(m_spellInfo->EquippedItemClass); - data << uint32(m_spellInfo->EquippedItemSubClassMask); - //data << uint32(m_spellInfo->EquippedItemInventoryTypeMask); + data << uint32(spellInfo->EquippedItemClass); + data << uint32(spellInfo->EquippedItemSubClassMask); + //data << uint32(spellInfo->EquippedItemInventoryTypeMask); break; default: break; } - ((Player*)m_caster)->GetSession()->SendPacket(&data); + caster->GetSession()->SendPacket(&data); } void Spell::SendSpellStart() diff --git a/src/game/Spell.h b/src/game/Spell.h index 9d16a85ebcf..4bf032bbbd7 100644 --- a/src/game/Spell.h +++ b/src/game/Spell.h @@ -423,6 +423,7 @@ class Spell void CheckSrc() { if(!m_targets.HasSrc()) m_targets.setSrc(m_caster); } void CheckDst() { if(!m_targets.HasDst()) m_targets.setDestination(m_caster); } + static void SendCastResult(Player* caster, SpellEntry const* spellInfo, uint8 cast_count, SpellCastResult result); void SendCastResult(SpellCastResult result); void SendSpellStart(); void SendSpellGo(); diff --git a/src/game/SpellHandler.cpp b/src/game/SpellHandler.cpp index 7e72fd4e749..62056a6806f 100644 --- a/src/game/SpellHandler.cpp +++ b/src/game/SpellHandler.cpp @@ -123,9 +123,29 @@ void WorldSession::HandleUseItemOpcode(WorldPacket& recvPacket) } SpellCastTargets targets; - if(!targets.read(&recvPacket, pUser)) + if (!targets.read(&recvPacket, pUser)) return; + targets.Update(pUser); + + if (!pItem->IsTargetValidForItemUse(targets.getUnitTarget())) + { + // free greay item aftre use faul + pUser->SendEquipError(EQUIP_ERR_NONE, pItem, NULL); + + // send spell error + if (SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellid)) + { + // for implicit area/coord target spells + if(!targets.getUnitTarget()) + 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(!Script->ItemUse(pUser,pItem,targets)) { diff --git a/src/game/World.cpp b/src/game/World.cpp index 7412a7a282c..5ab3c46a036 100644 --- a/src/game/World.cpp +++ b/src/game/World.cpp @@ -1252,6 +1252,9 @@ void World::SetInitialWorldSettings() sLog.outString( "Loading SpellsScriptTarget..."); spellmgr.LoadSpellScriptTarget(); // must be after LoadCreatureTemplates and LoadGameobjectInfo + sLog.outString( "Loading ItemRequiredTarget..."); + objmgr.LoadItemRequiredTarget(); + sLog.outString( "Loading Creature Reputation OnKill Data..." ); objmgr.LoadReputationOnKill(); |