diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/bindings/scripts/scripts/zone/eastern_plaguelands/the_scarlet_enclave.cpp | 3 | ||||
-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/Level1.cpp | 2 | ||||
-rw-r--r-- | src/game/Level3.cpp | 9 | ||||
-rw-r--r-- | src/game/ObjectMgr.cpp | 103 | ||||
-rw-r--r-- | src/game/ObjectMgr.h | 11 | ||||
-rw-r--r-- | src/game/Pet.cpp | 4 | ||||
-rw-r--r-- | src/game/PetHandler.cpp | 14 | ||||
-rw-r--r-- | src/game/Player.cpp | 4 | ||||
-rw-r--r-- | src/game/Spell.cpp | 42 | ||||
-rw-r--r-- | src/game/Spell.h | 1 | ||||
-rw-r--r-- | src/game/SpellAuras.cpp | 13 | ||||
-rw-r--r-- | src/game/SpellEffects.cpp | 13 | ||||
-rw-r--r-- | src/game/SpellHandler.cpp | 28 | ||||
-rw-r--r-- | src/game/Unit.cpp | 19 | ||||
-rw-r--r-- | src/game/Unit.h | 2 | ||||
-rw-r--r-- | src/game/Vehicle.cpp | 10 | ||||
-rw-r--r-- | src/game/World.cpp | 3 |
22 files changed, 280 insertions, 61 deletions
diff --git a/src/bindings/scripts/scripts/zone/eastern_plaguelands/the_scarlet_enclave.cpp b/src/bindings/scripts/scripts/zone/eastern_plaguelands/the_scarlet_enclave.cpp index 560d9196d95..4790bf1f97d 100644 --- a/src/bindings/scripts/scripts/zone/eastern_plaguelands/the_scarlet_enclave.cpp +++ b/src/bindings/scripts/scripts/zone/eastern_plaguelands/the_scarlet_enclave.cpp @@ -598,6 +598,7 @@ CreatureAI* GetAI_npc_ros_dark_rider(Creature *_Creature) return new npc_ros_dark_riderAI(_Creature); } +// correct way: 52312 52314 52555 ... struct TRINITY_DLL_DECL npc_dkc1_gothikAI : public ScriptedAI { npc_dkc1_gothikAI(Creature *c) : ScriptedAI(c) {} @@ -628,6 +629,8 @@ CreatureAI* GetAI_npc_dkc1_gothik(Creature *_Creature) return new npc_dkc1_gothikAI(_Creature); } +// npc 28912 quest 17217 boss 29001 go 191092 + void AddSC_the_scarlet_enclave() { Script *newscript; 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/Level1.cpp b/src/game/Level1.cpp index 86a689e7383..f8acec049c2 100644 --- a/src/game/Level1.cpp +++ b/src/game/Level1.cpp @@ -1524,7 +1524,7 @@ bool ChatHandler::HandleModifyASpeedCommand(const char* args) float ASpeed = (float)atof((char*)args); - if (ASpeed > 10 || ASpeed < 0.1) + if (ASpeed > 50 || ASpeed < 0) { SendSysMessage(LANG_BAD_VALUE); SetSentErrorMessage(true); 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..38ba9c33a6c 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 @@ -6367,6 +6467,9 @@ void ObjectMgr::LoadNPCSpellClickSpells() continue; } + if(!(cInfo->npcflag & UNIT_NPC_FLAG_SPELLCLICK)) + const_cast<CreatureInfo*>(cInfo)->npcflag |= UNIT_NPC_FLAG_SPELLCLICK; + uint32 spellid = fields[1].GetUInt32(); SpellEntry const *spellinfo = sSpellStore.LookupEntry(spellid); if (!spellinfo) 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/Pet.cpp b/src/game/Pet.cpp index 51570e0750a..18b2de26c70 100644 --- a/src/game/Pet.cpp +++ b/src/game/Pet.cpp @@ -459,12 +459,12 @@ void Pet::setDeathState(DeathState s) // overwrite virtual if(!mapEntry || (mapEntry->map_type != MAP_ARENA && mapEntry->map_type != MAP_BATTLEGROUND)) ModifyPower(POWER_HAPPINESS, -HAPPINESS_LEVEL_SIZE); - SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED); + //SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED); } } else if(getDeathState()==ALIVE) { - RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED); + //RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED); CastPetAuras(true); } } 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/Player.cpp b/src/game/Player.cpp index d647768d3e0..7099b7e3945 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -17437,6 +17437,10 @@ bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc // stop combat at start taxi flight if any CombatStop(); + StopCastingCharm(); + StopCastingBindSight(); + ExitVehicle(); + // stop trade (client cancel trade at taxi map open but cheating tools can be used for reopen it) TradeCancel(true); diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp index ebb3a355a95..7f84e3a1cac 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() @@ -4821,7 +4829,7 @@ SpellCastResult Spell::CheckCast(bool strict) SpellCastResult Spell::CheckPetCast(Unit* target) { - if(!m_caster->isAlive()) + if(!m_caster->isAlive() && !(m_spellInfo->Attributes & SPELL_ATTR_CASTABLE_WHILE_DEAD)) return SPELL_FAILED_CASTER_DEAD; if(m_caster->hasUnitState(UNIT_STAT_CASTING) && !m_IsTriggeredSpell) //prevent spellcast interruption by another spellcast 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/SpellAuras.cpp b/src/game/SpellAuras.cpp index 3e6c1e3ff41..43f004d7701 100644 --- a/src/game/SpellAuras.cpp +++ b/src/game/SpellAuras.cpp @@ -3879,10 +3879,9 @@ void AuraEffect::HandleAuraModDisarm(bool apply, bool Real, bool /*changeAmount* AuraType type = AuraType(GetAuraName()); //Prevent handling aura twice - if(apply && m_target->GetAurasByType(type).size()>1) - return; - if(!apply && m_target->HasAuraType(type)) + if(apply ? m_target->GetAurasByType(type).size() > 1 : m_target->HasAuraType(type)) return; + uint32 field, flag, slot; WeaponAttackType attType; switch (type) @@ -3905,6 +3904,8 @@ void AuraEffect::HandleAuraModDisarm(bool apply, bool Real, bool /*changeAmount* slot=EQUIPMENT_SLOT_RANGED; attType=RANGED_ATTACK; break; + default: + return; } if(apply) m_target->SetFlag(field, flag); @@ -3913,10 +3914,8 @@ void AuraEffect::HandleAuraModDisarm(bool apply, bool Real, bool /*changeAmount* if (m_target->GetTypeId() == TYPEID_PLAYER) { - Item *pItem = ((Player*)m_target)->GetItemByPos( INVENTORY_SLOT_BAG_0, slot ); - if(!pItem ) - return; - ((Player*)m_target)->_ApplyItemMods(pItem, slot, !apply); + if(Item *pItem = ((Player*)m_target)->GetItemByPos( INVENTORY_SLOT_BAG_0, slot )) + ((Player*)m_target)->_ApplyItemMods(pItem, slot, !apply); } else if (((Creature*)m_target)->GetCurrentEquipmentId()) m_target->UpdateDamagePhysical(attType); diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp index 0c8a4eee292..ae84b6c4ff9 100644 --- a/src/game/SpellEffects.cpp +++ b/src/game/SpellEffects.cpp @@ -3393,10 +3393,8 @@ void Spell::EffectSummonType(uint32 i) vehicle->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id); if(damage) - { m_caster->CastSpell(vehicle, damage, true); - m_caster->EnterVehicle(vehicle); - } + m_caster->EnterVehicle(vehicle); break; } } @@ -5135,6 +5133,15 @@ void Spell::EffectScriptEffect(uint32 effIndex) { switch(m_spellInfo->Id) { + // Heart of the Pheonix + case 55709: + { + int pct = 100; + if (unitTarget->GetTypeId()==TYPEID_UNIT && ((Creature*)unitTarget)->isPet()) + if (Unit* owner = ((Creature*)unitTarget)->GetOwner()) + owner->CastCustomSpell(unitTarget, 54114, &pct, NULL, NULL, true); + break; + } // Chimera Shot case 53209: { diff --git a/src/game/SpellHandler.cpp b/src/game/SpellHandler.cpp index 7e72fd4e749..b3655448a1a 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)) { @@ -313,6 +333,12 @@ void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket) } } + // Client is resending autoshot cast opcode when other spell is casted during shoot rotation + // Skip it to prevent "interrupt" message + if (IsAutoRepeatRangedSpell(spellInfo) && _player->m_currentSpells[CURRENT_AUTOREPEAT_SPELL] + && _player->m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo == spellInfo) + return; + // can't use our own spells when we're in possession of another unit, if(_player->isPossessing()) return; diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index bc2f6b0b540..79e31ce6dce 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -2341,7 +2341,7 @@ void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffe } } if (found) - pVictim->CastCustomSpell(pVictim, 44413, &spell_dmg, NULL, NULL, false); + pVictim->CastCustomSpell(pVictim, 44413, &spell_dmg, NULL, NULL, true); } } @@ -3383,7 +3383,7 @@ void Unit::_UpdateSpells( uint32 time ) void Unit::_UpdateAutoRepeatSpell() { //check "realtime" interrupts - if ( (GetTypeId() == TYPEID_PLAYER && ((Player*)this)->isMoving()) || IsNonMeleeSpellCasted(false,false,true) ) + if ( (GetTypeId() == TYPEID_PLAYER && ((Player*)this)->isMoving()) || IsNonMeleeSpellCasted(false,false,true,m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Id == SPELL_ID_AUTOSHOT) ) { // cancel wand shoot if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Id != SPELL_ID_AUTOSHOT) @@ -3515,7 +3515,7 @@ void Unit::InterruptSpell(uint32 spellType, bool withDelayed, bool withInstant) } } -bool Unit::IsNonMeleeSpellCasted(bool withDelayed, bool skipChanneled, bool skipAutorepeat) const +bool Unit::IsNonMeleeSpellCasted(bool withDelayed, bool skipChanneled, bool skipAutorepeat, bool isAutoshoot) const { // We don't do loop here to explicitly show that melee spell is excluded. // Maybe later some special spells will be excluded too. @@ -3524,12 +3524,14 @@ bool Unit::IsNonMeleeSpellCasted(bool withDelayed, bool skipChanneled, bool skip if ( m_currentSpells[CURRENT_GENERIC_SPELL] && (m_currentSpells[CURRENT_GENERIC_SPELL]->getState() != SPELL_STATE_FINISHED) && (withDelayed || m_currentSpells[CURRENT_GENERIC_SPELL]->getState() != SPELL_STATE_DELAYED) ) - return(true); + if (!isAutoshoot || !(m_currentSpells[CURRENT_GENERIC_SPELL]->m_spellInfo->AttributesEx2 & SPELL_ATTR_EX2_NOT_RESET_AUTOSHOT)) + return(true); // channeled spells may be delayed, but they are still considered casted else if ( !skipChanneled && m_currentSpells[CURRENT_CHANNELED_SPELL] && (m_currentSpells[CURRENT_CHANNELED_SPELL]->getState() != SPELL_STATE_FINISHED) ) - return(true); + if (!isAutoshoot || !(m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->AttributesEx2 & SPELL_ATTR_EX2_NOT_RESET_AUTOSHOT)) + return(true); // autorepeat spells may be finished or delayed, but they are still considered casted else if ( !skipAutorepeat && m_currentSpells[CURRENT_AUTOREPEAT_SPELL] ) @@ -11000,7 +11002,11 @@ int32 Unit::CalculateSpellDamage(SpellEntry const* spellProto, uint8 effect_inde if(!basePointsPerLevel && (spellProto->Attributes & SPELL_ATTR_LEVEL_DAMAGE_CALCULATION && spellProto->spellLevel) && spellProto->Effect[effect_index] != SPELL_EFFECT_WEAPON_PERCENT_DAMAGE && - spellProto->Effect[effect_index] != SPELL_EFFECT_KNOCK_BACK) + spellProto->Effect[effect_index] != SPELL_EFFECT_KNOCK_BACK && + spellProto->EffectApplyAuraName[effect_index] != SPELL_AURA_MOD_SPEED_ALWAYS && + spellProto->EffectApplyAuraName[effect_index] != SPELL_AURA_MOD_SPEED_NOT_STACK && + spellProto->EffectApplyAuraName[effect_index] != SPELL_AURA_MOD_INCREASE_SPEED && + spellProto->EffectApplyAuraName[effect_index] != SPELL_AURA_MOD_DECREASE_SPEED) //there are many more: slow speed, -healing pct //value = int32(value*0.25f*exp(getLevel()*(70-spellProto->spellLevel)/1000.0f)); value = int32(value * (int32)getLevel() / (int32)(spellProto->spellLevel ? spellProto->spellLevel : 1)); @@ -13618,7 +13624,6 @@ void Unit::SetCharmedBy(Unit* charmer, CharmType type) if(GetTypeId() == TYPEID_UNIT) { ((Creature*)this)->AI()->OnCharmed(true); - GetMotionMaster()->Clear(false); GetMotionMaster()->MoveIdle(); } else diff --git a/src/game/Unit.h b/src/game/Unit.h index 11b3a6307c2..65621ca02b7 100644 --- a/src/game/Unit.h +++ b/src/game/Unit.h @@ -1441,7 +1441,7 @@ class TRINITY_DLL_SPEC Unit : public WorldObject // set withDelayed to true to account delayed spells as casted // delayed+channeled spells are always accounted as casted // we can skip channeled or delayed checks using flags - bool IsNonMeleeSpellCasted(bool withDelayed, bool skipChanneled = false, bool skipAutorepeat = false) const; + bool IsNonMeleeSpellCasted(bool withDelayed, bool skipChanneled = false, bool skipAutorepeat = false, bool isAutoshoot = false) const; // set withDelayed to true to interrupt delayed spells too // delayed+channeled spells are always interrupted diff --git a/src/game/Vehicle.cpp b/src/game/Vehicle.cpp index 3efe735a5b5..5197e799104 100644 --- a/src/game/Vehicle.cpp +++ b/src/game/Vehicle.cpp @@ -24,7 +24,6 @@ #include "Util.h" #include "WorldPacket.h" -#include "Chat.h" #include "CreatureAI.h" #include "ZoneScript.h" @@ -85,6 +84,11 @@ void Vehicle::setDeathState(DeathState s) // overwrite vir } RemoveAllPassengers(); } + else if(s == JUST_ALIVED) + { + if(m_usableSeatNum) + SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK); + } Creature::setDeathState(s); } @@ -244,13 +248,9 @@ bool Vehicle::AddPassenger(Unit *unit, int8 seatId) GetPositionZ() + unit->m_movementInfo.t_z, GetOrientation()); - unit->GetMotionMaster()->MoveIdle(MOTION_SLOT_IDLE); - WorldPacket data; if(unit->GetTypeId() == TYPEID_PLAYER) { - //ChatHandler(player).PSendSysMessage("Enter seat %u %u", veSeat->m_ID, seat->first); - if(seat->first == 0 && seat->second.seatInfo->IsUsable()) // not right SetCharmedBy(unit, CHARM_TYPE_VEHICLE); 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(); |