diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/server/game/AI/SmartScripts/SmartScriptMgr.h | 2 | ||||
| -rwxr-xr-x | src/server/game/Entities/Item/ItemPrototype.h | 1 | ||||
| -rwxr-xr-x | src/server/game/Entities/Unit/Unit.cpp | 16 | ||||
| -rwxr-xr-x | src/server/game/Groups/Group.cpp | 118 | ||||
| -rwxr-xr-x | src/server/game/Handlers/LootHandler.cpp | 6 | ||||
| -rwxr-xr-x | src/server/game/Loot/LootMgr.cpp | 67 | ||||
| -rwxr-xr-x | src/server/game/Loot/LootMgr.h | 3 | ||||
| -rwxr-xr-x | src/server/game/Spells/Spell.cpp | 115 | ||||
| -rwxr-xr-x | src/server/game/Spells/Spell.h | 1 | ||||
| -rw-r--r-- | src/server/game/Spells/SpellInfo.cpp | 1 | ||||
| -rwxr-xr-x | src/server/game/Spells/SpellScript.cpp | 15 | ||||
| -rwxr-xr-x | src/server/game/Spells/SpellScript.h | 18 | ||||
| -rw-r--r-- | src/server/scripts/Northrend/Nexus/Oculus/oculus.cpp | 36 | ||||
| -rw-r--r-- | src/server/scripts/Spells/spell_quest.cpp | 52 |
14 files changed, 386 insertions, 65 deletions
diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h index 55e6a7fc446..cdb662edbaf 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h @@ -885,7 +885,7 @@ struct SmartAction struct { - uint8 pointId; + uint32 pointId; } MoveToPos; struct diff --git a/src/server/game/Entities/Item/ItemPrototype.h b/src/server/game/Entities/Item/ItemPrototype.h index 5dbf1cad5bb..5088a30157c 100755 --- a/src/server/game/Entities/Item/ItemPrototype.h +++ b/src/server/game/Entities/Item/ItemPrototype.h @@ -196,6 +196,7 @@ enum ItemFlagsCustom { ITEM_FLAGS_CU_DURATION_REAL_TIME = 0x0001, // Item duration will tick even if player is offline ITEM_FLAGS_CU_IGNORE_QUEST_STATUS = 0x0002, // No quest status will be checked when this item drops + ITEM_FLAGS_CU_FOLLOW_LOOT_RULES = 0x0004, // Item will always follow group/master/need before greed looting rules }; enum BAG_FAMILY_MASK diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index fc1e4398e17..92f2f30b0ff 100755 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -804,11 +804,6 @@ void Unit::CastSpell(SpellCastTargets const& targets, SpellInfo const* spellInfo return; } - // TODO: this is a workaround and needs removal - if (!originalCaster && GetTypeId() == TYPEID_UNIT && ToCreature()->isTotem() && IsControlledByPlayer()) - if (Unit* owner = GetOwner()) - originalCaster=owner->GetGUID(); - // TODO: this is a workaround - not needed anymore, but required for some scripts :( if (!originalCaster && triggeredByAura) originalCaster = triggeredByAura->GetCasterGUID(); @@ -8205,6 +8200,14 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg CastSpell(victim, 27526, true, castItem, triggeredByAura); return true; } + // Evasive Maneuvers + case 50240: + { + // Remove a Evasive Charge + Aura* charge = GetAura(50241); + if (charge->ModStackAmount(-1, AURA_REMOVE_BY_ENEMY_SPELL)) + RemoveAurasDueToSpell(50240); + } } break; case SPELLFAMILY_MAGE: @@ -11719,10 +11722,11 @@ uint32 Unit::MeleeDamageBonusTaken(Unit* attacker, uint32 pdamage, WeaponAttackT float TakenTotalCasterMod = 0.0f; // get all auras from caster that allow the spell to ignore resistance (sanctified wrath) + SpellSchoolMask attackSchoolMask = spellProto ? spellProto->GetSchoolMask() : SPELL_SCHOOL_MASK_NORMAL; AuraEffectList const& IgnoreResistAuras = attacker->GetAuraEffectsByType(SPELL_AURA_MOD_IGNORE_TARGET_RESIST); for (AuraEffectList::const_iterator i = IgnoreResistAuras.begin(); i != IgnoreResistAuras.end(); ++i) { - if ((*i)->GetMiscValue() & spellProto->GetSchoolMask()) + if ((*i)->GetMiscValue() & attackSchoolMask) TakenTotalCasterMod += (float((*i)->GetAmount())/100); } diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp index 3a6390cd83a..26faa7e6ae8 100755 --- a/src/server/game/Groups/Group.cpp +++ b/src/server/game/Groups/Group.cpp @@ -949,6 +949,64 @@ void Group::GroupLoot(Loot* loot, WorldObject* pLootedObject) else i->is_underthreshold = true; } + + for (i = loot->quest_items.begin(); i != loot->quest_items.end(); ++i, ++itemSlot) + { + if (!i->follow_loot_rules) + continue; + + item = sObjectMgr->GetItemTemplate(i->itemid); + if (!item) + { + //sLog->outDebug("Group::GroupLoot: missing item prototype for item with id: %d", i->itemid); + continue; + } + + uint64 newitemGUID = MAKE_NEW_GUID(sObjectMgr->GenerateLowGuid(HIGHGUID_ITEM), 0, HIGHGUID_ITEM); + Roll* r = new Roll(newitemGUID, *i); + + //a vector is filled with only near party members + for (GroupReference* itr = GetFirstMember(); itr != NULL; itr = itr->next()) + { + Player* member = itr->getSource(); + if (!member || !member->GetSession()) + continue; + + if (i->AllowedForPlayer(member)) + { + if (member->IsWithinDistInMap(pLootedObject, sWorld->getFloatConfig(CONFIG_GROUP_XP_DISTANCE), false)) + { + r->totalPlayersRolling++; + r->playerVote[member->GetGUID()] = NOT_EMITED_YET; + } + } + } + + if (r->totalPlayersRolling > 0) + { + r->setLoot(loot); + r->itemSlot = itemSlot; + + loot->quest_items[itemSlot - loot->items.size()].is_blocked = true; + + SendLootStartRoll(60000, pLootedObject->GetMapId(), *r); + + RollId.push_back(r); + + if (Creature* creature = pLootedObject->ToCreature()) + { + creature->m_groupLootTimer = 60000; + creature->lootingGroupLowGUID = GetLowGUID(); + } + else if (GameObject* go = pLootedObject->ToGameObject()) + { + go->m_groupLootTimer = 60000; + go->lootingGroupLowGUID = GetLowGUID(); + } + } + else + delete r; + } } void Group::NeedBeforeGreed(Loot* loot, WorldObject* lootedObject) @@ -1033,6 +1091,66 @@ void Group::NeedBeforeGreed(Loot* loot, WorldObject* lootedObject) else i->is_underthreshold = true; } + + for (std::vector<LootItem>::iterator i = loot->quest_items.begin(); i != loot->quest_items.end(); ++i, ++itemSlot) + { + if (!i->follow_loot_rules) + continue; + + item = sObjectMgr->GetItemTemplate(i->itemid); + uint64 newitemGUID = MAKE_NEW_GUID(sObjectMgr->GenerateLowGuid(HIGHGUID_ITEM), 0, HIGHGUID_ITEM); + Roll* r = new Roll(newitemGUID, *i); + + for (GroupReference* itr = GetFirstMember(); itr != NULL; itr = itr->next()) + { + Player* playerToRoll = itr->getSource(); + if (!playerToRoll || !playerToRoll->GetSession()) + continue; + + bool allowedForPlayer = i->AllowedForPlayer(playerToRoll); + if (allowedForPlayer && playerToRoll->IsWithinDistInMap(lootedObject, sWorld->getFloatConfig(CONFIG_GROUP_XP_DISTANCE), false)) + { + r->totalPlayersRolling++; + r->playerVote[playerToRoll->GetGUID()] = NOT_EMITED_YET; + } + } + + if (r->totalPlayersRolling > 0) + { + r->setLoot(loot); + r->itemSlot = itemSlot; + + loot->quest_items[itemSlot - loot->items.size()].is_blocked = true; + + //Broadcast Pass and Send Rollstart + for (Roll::PlayerVote::const_iterator itr = r->playerVote.begin(); itr != r->playerVote.end(); ++itr) + { + Player* p = ObjectAccessor::FindPlayer(itr->first); + if (!p || !p->GetSession()) + continue; + + if (itr->second == PASS) + SendLootRoll(newitemGUID, p->GetGUID(), 128, ROLL_PASS, *r); + else + SendLootStartRollToPlayer(60000, lootedObject->GetMapId(), p, p->CanRollForItemInLFG(item, lootedObject) == EQUIP_ERR_OK, *r); + } + + RollId.push_back(r); + + if (Creature* creature = lootedObject->ToCreature()) + { + creature->m_groupLootTimer = 60000; + creature->lootingGroupLowGUID = GetLowGUID(); + } + else if (GameObject* go = lootedObject->ToGameObject()) + { + go->m_groupLootTimer = 60000; + go->lootingGroupLowGUID = GetLowGUID(); + } + } + else + delete r; + } } void Group::MasterLoot(Loot* /*loot*/, WorldObject* pLootedObject) diff --git a/src/server/game/Handlers/LootHandler.cpp b/src/server/game/Handlers/LootHandler.cpp index 339c7a44d9f..72e0b63f5b6 100755 --- a/src/server/game/Handlers/LootHandler.cpp +++ b/src/server/game/Handlers/LootHandler.cpp @@ -472,16 +472,18 @@ void WorldSession::HandleLootMasterGiveOpcode(WorldPacket & recv_data) if (!loot) return; - if (slotid > loot->items.size()) + if (slotid > loot->items.size() + loot->quest_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]; + 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) { target->SendEquipError(msg, NULL, NULL, item.itemid); diff --git a/src/server/game/Loot/LootMgr.cpp b/src/server/game/Loot/LootMgr.cpp index b4433906674..8d80c145026 100755 --- a/src/server/game/Loot/LootMgr.cpp +++ b/src/server/game/Loot/LootMgr.cpp @@ -322,6 +322,7 @@ LootItem::LootItem(LootStoreItem const& li) ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemid); freeforall = proto && (proto->Flags & ITEM_PROTO_FLAG_PARTY_LOOT); + follow_loot_rules = proto && (proto->FlagsCu & ITEM_FLAGS_CU_FOLLOW_LOOT_RULES); needs_quest = li.needs_quest; @@ -358,12 +359,7 @@ bool LootItem::AllowedForPlayer(Player const* player) const // check quest requirements if (!(pProto->FlagsCu & ITEM_FLAGS_CU_IGNORE_QUEST_STATUS) && ((needs_quest || (pProto->StartQuest && player->GetQuestStatus(pProto->StartQuest) != QUEST_STATUS_NONE)) && !player->HasQuestForItem(itemid))) - if (Group const* group = player->GetGroup()) - { - if (pProto->Flags & ITEM_PROTO_FLAG_PARTY_LOOT || ((pProto->Flags & ITEM_PROTO_FLAG_PARTY_LOOT) == 0 && (group->GetLootMethod() != MASTER_LOOT || group->GetLooterGuid() != player->GetGUID()))) - return false; - } - else return false; + return false; return true; } @@ -517,18 +513,20 @@ QuestItemList* Loot::FillQuestLoot(Player* player) for (uint8 i = 0; i < quest_items.size(); ++i) { LootItem &item = quest_items[i]; - if (!item.is_looted && item.AllowedForPlayer(player)) + + if ((!item.is_looted && item.AllowedForPlayer(player)) || (item.follow_loot_rules && player->GetGroup() && player->GetGroup()->GetLootMethod() == MASTER_LOOT && player->GetGroup()->GetLooterGuid() == player->GetGUID())) { ql->push_back(QuestItem(i)); - // questitems get blocked when they first appear in a + // quest items get blocked when they first appear in a // player's quest vector // // increase once if one looter only, looter-times if free for all - if (item.freeforall || !item.is_blocked) + if (item.freeforall && !item.is_blocked) + { ++unlootedCount; - - item.is_blocked = true; + item.is_blocked = true; + } if (items.size() + ql->size() == MAX_NR_LOOT_ITEMS) break; @@ -551,7 +549,7 @@ QuestItemList* Loot::FillNonQuestNonFFAConditionalLoot(Player* player, bool pres for (uint8 i = 0; i < items.size(); ++i) { LootItem &item = items[i]; - if (!item.is_looted && !item.freeforall && item.AllowedForPlayer(player)) + if (!item.is_looted && !item.freeforall && (item.AllowedForPlayer(player)) || (item.follow_loot_rules && player->GetGroup() && player->GetGroup()->GetLootMethod() == MASTER_LOOT && player->GetGroup()->GetLooterGuid() == player->GetGUID())) { if (presentAtLooting) item.AddAllowedLooter(player); @@ -907,8 +905,24 @@ ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv) { b << uint8(l.items.size() + (qi - q_list->begin())); b << item; - if (!item.freeforall) - b << uint8(partySlotType); + if (item.follow_loot_rules) + { + switch (lv.permission) + { + case MASTER_PERMISSION: + b << uint8(LOOT_SLOT_TYPE_MASTER); + break; + case GROUP_PERMISSION: + if (!item.is_blocked) + b << uint8(LOOT_SLOT_TYPE_ALLOW_LOOT); + else + b << uint8(LOOT_SLOT_TYPE_ROLL_ONGOING); + break; + default: + b << uint8(slotType); + break; + } + } else b << uint8(slotType); ++itemsShown; @@ -928,10 +942,7 @@ ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv) { b << uint8(fi->index); b << item; - if (!item.freeforall) - b << uint8(partySlotType); - else - b << uint8(slotType); + b << uint8(slotType); ++itemsShown; } } @@ -949,8 +960,24 @@ ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv) { b << uint8(ci->index); b << item; - if (!item.freeforall) - b << uint8(partySlotType); + if (item.follow_loot_rules) + { + switch (lv.permission) + { + case MASTER_PERMISSION: + b << uint8(LOOT_SLOT_TYPE_MASTER); + break; + case GROUP_PERMISSION: + if (!item.is_blocked) + b << uint8(LOOT_SLOT_TYPE_ALLOW_LOOT); + else + b << uint8(LOOT_SLOT_TYPE_ROLL_ONGOING); + break; + default: + b << uint8(slotType); + break; + } + } else b << uint8(slotType); ++itemsShown; diff --git a/src/server/game/Loot/LootMgr.h b/src/server/game/Loot/LootMgr.h index 4a6becc7eff..1af5bd1ea62 100755 --- a/src/server/game/Loot/LootMgr.h +++ b/src/server/game/Loot/LootMgr.h @@ -140,6 +140,7 @@ struct LootItem bool is_underthreshold : 1; bool is_counted : 1; bool needs_quest : 1; // quest drop + bool follow_loot_rules : 1; // Constructor, copies most fields from LootStoreItem, generates random count and random suffixes/properties // Should be called for non-reference LootStoreItem entries only (mincountOrRef > 0) @@ -280,6 +281,7 @@ struct Loot QuestItemMap const& GetPlayerNonQuestNonFFAConditionalItems() const { return PlayerNonQuestNonFFAConditionalItems; } std::vector<LootItem> items; + std::vector<LootItem> quest_items; uint32 gold; uint8 unlootedCount; uint64 roundRobinPlayer; // GUID of the player having the Round-Robin ownership for the loot. If 0, round robin owner has released. @@ -344,7 +346,6 @@ struct Loot QuestItemList* FillQuestLoot(Player* player); QuestItemList* FillNonQuestNonFFAConditionalLoot(Player* player, bool presentAtLooting); - std::vector<LootItem> quest_items; std::set<uint64> PlayersLooting; QuestItemMap PlayerQuestItems; QuestItemMap PlayerFFAItems; diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 2c1cff0c74a..590f880a931 100755 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -914,17 +914,25 @@ void Spell::SelectImplicitChannelTargets(SpellEffIndex effIndex, SpellImplicitTa switch (targetType.GetTarget()) { case TARGET_UNIT_CHANNEL_TARGET: + { + WorldObject* target = ObjectAccessor::GetUnit(*m_caster, channeledSpell->m_targets.GetUnitTargetGUID()); + CallScriptObjectTargetSelectHandlers(target, effIndex); // unit target may be no longer avalible - teleported out of map for example - if (Unit* target = Unit::GetUnit(*m_caster, channeledSpell->m_targets.GetUnitTargetGUID())) - AddUnitTarget(target, 1 << effIndex); + if (target && target->ToUnit()) + AddUnitTarget(target->ToUnit(), 1 << effIndex); else sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "SPELL: cannot find channel spell target for spell ID %u, effect %u", m_spellInfo->Id, effIndex); break; + } case TARGET_DEST_CHANNEL_TARGET: if (channeledSpell->m_targets.HasDst()) m_targets.SetDst(channeledSpell->m_targets); else if (WorldObject* target = ObjectAccessor::GetWorldObject(*m_caster, channeledSpell->m_targets.GetObjectTargetGUID())) - m_targets.SetDst(*target); + { + CallScriptObjectTargetSelectHandlers(target, effIndex); + if (target) + m_targets.SetDst(*target); + } else sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "SPELL: cannot find channel spell destination for spell ID %u, effect %u", m_spellInfo->Id, effIndex); break; @@ -1002,6 +1010,8 @@ void Spell::SelectImplicitNearbyTargets(SpellEffIndex effIndex, SpellImplicitTar return; } + CallScriptObjectTargetSelectHandlers(target, effIndex); + switch (targetType.GetObjectType()) { case TARGET_OBJECT_TYPE_UNIT: @@ -1492,27 +1502,27 @@ void Spell::SelectImplicitDestDestTargets(SpellEffIndex effIndex, SpellImplicitT void Spell::SelectImplicitCasterObjectTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType) { + WorldObject* target = NULL; + bool checkIfValid = true; + switch (targetType.GetTarget()) { case TARGET_UNIT_CASTER: - AddUnitTarget(m_caster, 1 << effIndex, false); + target = m_caster; + checkIfValid = false; break; case TARGET_UNIT_MASTER: - if (Unit* owner = m_caster->GetCharmerOrOwner()) - AddUnitTarget(owner, 1 << effIndex); + target = m_caster->GetCharmerOrOwner(); break; case TARGET_UNIT_PET: - if (Guardian* pet = m_caster->GetGuardianPet()) - AddUnitTarget(pet, 1 << effIndex); + target = m_caster->GetGuardianPet(); break; case TARGET_UNIT_SUMMONER: if (m_caster->isSummon()) - if (Unit* unit = m_caster->ToTempSummon()->GetSummoner()) - AddUnitTarget(unit, 1 << effIndex); + target = m_caster->ToTempSummon()->GetSummoner(); break; case TARGET_UNIT_VEHICLE: - if (Unit *vehicle = m_caster->GetVehicleBase()) - AddUnitTarget(vehicle, 1 << effIndex); + target = m_caster->GetVehicleBase(); break; case TARGET_UNIT_PASSENGER_0: case TARGET_UNIT_PASSENGER_1: @@ -1523,26 +1533,38 @@ void Spell::SelectImplicitCasterObjectTargets(SpellEffIndex effIndex, SpellImpli case TARGET_UNIT_PASSENGER_6: case TARGET_UNIT_PASSENGER_7: if (m_caster->GetTypeId() == TYPEID_UNIT && m_caster->ToCreature()->IsVehicle()) - if (Unit *unit = m_caster->GetVehicleKit()->GetPassenger(targetType.GetTarget() - TARGET_UNIT_PASSENGER_0)) - AddUnitTarget(unit, 1 << effIndex); + target = m_caster->GetVehicleKit()->GetPassenger(targetType.GetTarget() - TARGET_UNIT_PASSENGER_0); break; default: break; } + + CallScriptObjectTargetSelectHandlers(target, effIndex); + + if (target && target->ToUnit()) + AddUnitTarget(target->ToUnit(), 1 << effIndex, checkIfValid); } void Spell::SelectImplicitTargetObjectTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType) { ASSERT((m_targets.GetObjectTarget() || m_targets.GetItemTarget()) && "Spell::SelectImplicitTargetObjectTargets - no explicit object or item target available!"); - if (Unit* unit = m_targets.GetUnitTarget()) - AddUnitTarget(unit, 1 << effIndex, true, false); - else if (GameObject* gobj = m_targets.GetGOTarget()) - AddGOTarget(gobj, 1 << effIndex); - else - AddItemTarget(m_targets.GetItemTarget(), 1 << effIndex); - if (WorldObject* target = m_targets.GetObjectTarget()) + WorldObject* target = m_targets.GetObjectTarget(); + + CallScriptObjectTargetSelectHandlers(target, effIndex); + + if (target) + { + if (Unit* unit = target->ToUnit()) + AddUnitTarget(unit, 1 << effIndex, true, false); + else if (GameObject* gobj = target->ToGameObject()) + AddGOTarget(gobj, 1 << effIndex); + SelectImplicitChainTargets(effIndex, targetType, target, 1 << effIndex); + } + // Script hook can remove object target and we would wrongly land here + else if (Item* item = m_targets.GetItemTarget()) + AddItemTarget(item, 1 << effIndex); } void Spell::SelectImplicitChainTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType, WorldObject* target, uint32 effMask) @@ -1734,9 +1756,12 @@ void Spell::SelectEffectTypeImplicitTargets(uint8 effIndex) case SPELL_EFFECT_SUMMON_PLAYER: if (m_caster->GetTypeId() == TYPEID_PLAYER && m_caster->ToPlayer()->GetSelection()) { - Player* target = ObjectAccessor::FindPlayer(m_caster->ToPlayer()->GetSelection()); - if (target) - AddUnitTarget(target, 1 << effIndex, false); + WorldObject* target = ObjectAccessor::FindPlayer(m_caster->ToPlayer()->GetSelection()); + + CallScriptObjectTargetSelectHandlers(target, SpellEffIndex(effIndex)); + + if (target && target->ToPlayer()) + AddUnitTarget(target->ToUnit(), 1 << effIndex, false); } return; default: @@ -1752,6 +1777,8 @@ void Spell::SelectEffectTypeImplicitTargets(uint8 effIndex) if (!targetMask) return; + WorldObject* target = NULL; + switch (m_spellInfo->Effects[effIndex].GetImplicitTargetType()) { // add explicit object target or self to the target map @@ -1760,40 +1787,46 @@ void Spell::SelectEffectTypeImplicitTargets(uint8 effIndex) if (targetMask & (TARGET_FLAG_UNIT_MASK | TARGET_FLAG_CORPSE_MASK)) { if (Unit* unitTarget = m_targets.GetUnitTarget()) - AddUnitTarget(unitTarget, 1 << effIndex, false); + target = unitTarget; else if (targetMask & TARGET_FLAG_CORPSE_MASK) { if (Corpse* corpseTarget = m_targets.GetCorpseTarget()) { // TODO: this is a workaround - corpses should be added to spell target map too, but we can't do that so we add owner instead if (Player* owner = ObjectAccessor::FindPlayer(corpseTarget->GetOwnerGUID())) - AddUnitTarget(owner, 1 << effIndex, false); + target = owner; } } else //if (targetMask & TARGET_FLAG_UNIT_MASK) - { - AddUnitTarget(m_caster, 1 << effIndex, false); - } + target = m_caster; } if (targetMask & TARGET_FLAG_ITEM_MASK) { if (Item* itemTarget = m_targets.GetItemTarget()) AddItemTarget(itemTarget, 1 << effIndex); + return; } if (targetMask & TARGET_FLAG_GAMEOBJECT_MASK) - { - if (GameObject* gObjTarget = m_targets.GetGOTarget()) - AddGOTarget(gObjTarget, 1 << effIndex); - } + target = m_targets.GetGOTarget(); break; // add self to the target map case EFFECT_IMPLICIT_TARGET_CASTER: if (targetMask & TARGET_FLAG_UNIT_MASK) - AddUnitTarget(m_caster, 1 << effIndex, false); + target = m_caster; break; default: break; } + + CallScriptObjectTargetSelectHandlers(target, SpellEffIndex(effIndex)); + + if (target) + { + if (target->ToUnit()) + AddUnitTarget(target->ToUnit(), 1 << effIndex, false); + else if (target->ToGameObject()) + AddGOTarget(target->ToGameObject(), 1 << effIndex); + } } uint32 Spell::GetSearcherTypeMask(SpellTargetObjectTypes objType, ConditionList* condList) @@ -7053,6 +7086,20 @@ void Spell::CallScriptObjectAreaTargetSelectHandlers(std::list<WorldObject*>& ta } } +void Spell::CallScriptObjectTargetSelectHandlers(WorldObject*& target, SpellEffIndex effIndex) +{ + for (std::list<SpellScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) + { + (*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_OBJECT_TARGET_SELECT); + std::list<SpellScript::ObjectTargetSelectHandler>::iterator hookItrEnd = (*scritr)->OnObjectTargetSelect.end(), hookItr = (*scritr)->OnObjectTargetSelect.begin(); + for (; hookItr != hookItrEnd; ++hookItr) + if ((*hookItr).IsEffectAffected(m_spellInfo, effIndex)) + (*hookItr).Call(*scritr, target); + + (*scritr)->_FinishScriptCall(); + } +} + bool Spell::CanExecuteTriggersOnHit(uint8 effMask, SpellInfo const* triggeredByAura) const { bool only_on_caster = (triggeredByAura && (triggeredByAura->AttributesEx4 & SPELL_ATTR4_PROC_ONLY_ON_CASTER)); diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index 98455904cf5..1376b0fbd40 100755 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -631,6 +631,7 @@ class Spell void CallScriptOnHitHandlers(); void CallScriptAfterHitHandlers(); void CallScriptObjectAreaTargetSelectHandlers(std::list<WorldObject*>& targets, SpellEffIndex effIndex); + void CallScriptObjectTargetSelectHandlers(WorldObject*& target, SpellEffIndex effIndex); std::list<SpellScript*> m_loadedScripts; struct HitTriggerSpell diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp index 7995087f2c1..16584086245 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -1736,6 +1736,7 @@ AuraStateType SpellInfo::GetAuraState() const switch (Id) { case 71465: // Divine Surge + case 50241: // Evasive Charges return AURA_STATE_UNKNOWN22; default: break; diff --git a/src/server/game/Spells/SpellScript.cpp b/src/server/game/Spells/SpellScript.cpp index a19c356b9ed..d0ae6fe3098 100755 --- a/src/server/game/Spells/SpellScript.cpp +++ b/src/server/game/Spells/SpellScript.cpp @@ -267,6 +267,17 @@ void SpellScript::ObjectAreaTargetSelectHandler::Call(SpellScript* spellScript, (spellScript->*pObjectAreaTargetSelectHandlerScript)(targets); } +SpellScript::ObjectTargetSelectHandler::ObjectTargetSelectHandler(SpellObjectTargetSelectFnType _pObjectTargetSelectHandlerScript, uint8 _effIndex, uint16 _targetType) + : TargetHook(_effIndex, _targetType, false) +{ + pObjectTargetSelectHandlerScript = _pObjectTargetSelectHandlerScript; +} + +void SpellScript::ObjectTargetSelectHandler::Call(SpellScript* spellScript, WorldObject*& target) +{ + (spellScript->*pObjectTargetSelectHandlerScript)(target); +} + bool SpellScript::_Validate(SpellInfo const* entry) { for (std::list<EffectHandler>::iterator itr = OnEffectLaunch.begin(); itr != OnEffectLaunch.end(); ++itr) @@ -289,6 +300,10 @@ bool SpellScript::_Validate(SpellInfo const* entry) if (!(*itr).GetAffectedEffectsMask(entry)) sLog->outError("TSCR: Spell `%u` Effect `%s` of script `%s` did not match dbc effect data - handler bound to hook `OnObjectAreaTargetSelect` of SpellScript won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str()); + for (std::list<ObjectTargetSelectHandler>::iterator itr = OnObjectTargetSelect.begin(); itr != OnObjectTargetSelect.end(); ++itr) + if (!(*itr).GetAffectedEffectsMask(entry)) + sLog->outError("TSCR: Spell `%u` Effect `%s` of script `%s` did not match dbc effect data - handler bound to hook `OnObjectTargetSelect` of SpellScript won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str()); + return _SpellScript::_Validate(entry); } diff --git a/src/server/game/Spells/SpellScript.h b/src/server/game/Spells/SpellScript.h index 51631bb8ffe..376e7f18edc 100755 --- a/src/server/game/Spells/SpellScript.h +++ b/src/server/game/Spells/SpellScript.h @@ -132,6 +132,7 @@ enum SpellScriptHookType SPELL_SCRIPT_HOOK_HIT, SPELL_SCRIPT_HOOK_AFTER_HIT, SPELL_SCRIPT_HOOK_OBJECT_AREA_TARGET_SELECT, + SPELL_SCRIPT_HOOK_OBJECT_TARGET_SELECT, SPELL_SCRIPT_HOOK_CHECK_CAST, SPELL_SCRIPT_HOOK_BEFORE_CAST, SPELL_SCRIPT_HOOK_ON_CAST, @@ -155,6 +156,7 @@ class SpellScript : public _SpellScript typedef void(CLASSNAME::*SpellHitFnType)(); \ typedef void(CLASSNAME::*SpellCastFnType)(); \ typedef void(CLASSNAME::*SpellObjectAreaTargetSelectFnType)(std::list<WorldObject*>&); \ + typedef void(CLASSNAME::*SpellObjectTargetSelectFnType)(WorldObject*&); SPELLSCRIPT_FUNCTION_TYPE_DEFINES(SpellScript) @@ -216,12 +218,22 @@ class SpellScript : public _SpellScript SpellObjectAreaTargetSelectFnType pObjectAreaTargetSelectHandlerScript; }; + class ObjectTargetSelectHandler : public TargetHook + { + public: + ObjectTargetSelectHandler(SpellObjectTargetSelectFnType _pObjectTargetSelectHandlerScript, uint8 _effIndex, uint16 _targetType); + void Call(SpellScript* spellScript, WorldObject*& targets); + private: + SpellObjectTargetSelectFnType pObjectTargetSelectHandlerScript; + }; + #define SPELLSCRIPT_FUNCTION_CAST_DEFINES(CLASSNAME) \ class CastHandlerFunction : public SpellScript::CastHandler { public: CastHandlerFunction(SpellCastFnType _pCastHandlerScript) : SpellScript::CastHandler((SpellScript::SpellCastFnType)_pCastHandlerScript) {} }; \ class CheckCastHandlerFunction : public SpellScript::CheckCastHandler { public: CheckCastHandlerFunction(SpellCheckCastFnType _checkCastHandlerScript) : SpellScript::CheckCastHandler((SpellScript::SpellCheckCastFnType)_checkCastHandlerScript) {} }; \ class EffectHandlerFunction : public SpellScript::EffectHandler { public: EffectHandlerFunction(SpellEffectFnType _pEffectHandlerScript, uint8 _effIndex, uint16 _effName) : SpellScript::EffectHandler((SpellScript::SpellEffectFnType)_pEffectHandlerScript, _effIndex, _effName) {} }; \ class HitHandlerFunction : public SpellScript::HitHandler { public: HitHandlerFunction(SpellHitFnType _pHitHandlerScript) : SpellScript::HitHandler((SpellScript::SpellHitFnType)_pHitHandlerScript) {} }; \ class ObjectAreaTargetSelectHandlerFunction : public SpellScript::ObjectAreaTargetSelectHandler { public: ObjectAreaTargetSelectHandlerFunction(SpellObjectAreaTargetSelectFnType _pObjectAreaTargetSelectHandlerScript, uint8 _effIndex, uint16 _targetType) : SpellScript::ObjectAreaTargetSelectHandler((SpellScript::SpellObjectAreaTargetSelectFnType)_pObjectAreaTargetSelectHandlerScript, _effIndex, _targetType) {} }; \ + class ObjectTargetSelectHandlerFunction : public SpellScript::ObjectTargetSelectHandler { public: ObjectTargetSelectHandlerFunction(SpellObjectTargetSelectFnType _pObjectTargetSelectHandlerScript, uint8 _effIndex, uint16 _targetType) : SpellScript::ObjectTargetSelectHandler((SpellScript::SpellObjectTargetSelectFnType)_pObjectTargetSelectHandlerScript, _effIndex, _targetType) {} }; #define PrepareSpellScript(CLASSNAME) SPELLSCRIPT_FUNCTION_TYPE_DEFINES(CLASSNAME) SPELLSCRIPT_FUNCTION_CAST_DEFINES(CLASSNAME) public: @@ -280,10 +292,16 @@ class SpellScript : public _SpellScript HookList<ObjectAreaTargetSelectHandler> OnObjectAreaTargetSelect; #define SpellObjectAreaTargetSelectFn(F, I, N) ObjectAreaTargetSelectHandlerFunction(&F, I, N) + // example: OnObjectTargetSelect += SpellObjectTargetSelectFn(class::function, EffectIndexSpecifier, TargetsNameSpecifier); + // where function is void function(WorldObject*& target) + HookList<ObjectTargetSelectHandler> OnObjectTargetSelect; + #define SpellObjectTargetSelectFn(F, I, N) ObjectTargetSelectHandlerFunction(&F, I, N) + // hooks are executed in following order, at specified event of spell: // 1. BeforeCast - executed when spell preparation is finished (when cast bar becomes full) before cast is handled // 2. OnCheckCast - allows to override result of CheckCast function // 3a. OnObjectAreaTargetSelect - executed just before adding selected targets to final target list (for area targets) + // 3b. OnObjectTargetSelect - executed just before adding selected target to final target list (for single unit targets) // 4. OnCast - executed just before spell is launched (creates missile) or executed // 5. AfterCast - executed after spell missile is launched and immediate spell actions are done // 6. OnEffectLaunch - executed just before specified effect handler call - when spell missile is launched diff --git a/src/server/scripts/Northrend/Nexus/Oculus/oculus.cpp b/src/server/scripts/Northrend/Nexus/Oculus/oculus.cpp index 23f55a3033b..0eafd7a7fea 100644 --- a/src/server/scripts/Northrend/Nexus/Oculus/oculus.cpp +++ b/src/server/scripts/Northrend/Nexus/Oculus/oculus.cpp @@ -47,7 +47,9 @@ enum Drakes NPC_VERDISA = 27657, NPC_BELGARISTRASZ = 27658, - NPC_ETERNOS = 27659 + NPC_ETERNOS = 27659, + + SPELL_SHOCK_CHARGE = 49836, }; enum Says @@ -210,8 +212,40 @@ public: } }; +class spell_gen_stop_time : public SpellScriptLoader +{ +public: + spell_gen_stop_time() : SpellScriptLoader("spell_gen_stop_time") { } + + class spell_gen_stop_time_AuraScript : public AuraScript + { + PrepareAuraScript(spell_gen_stop_time_AuraScript); + + void Apply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + Unit* caster = GetCaster(); + if (!caster) + return; + Unit* target = GetTarget(); + for (uint32 i = 0; i < 5; ++i) + caster->CastSpell(target, SPELL_SHOCK_CHARGE, false); + } + + void Register() + { + AfterEffectApply += AuraEffectApplyFn(spell_gen_stop_time_AuraScript::Apply, EFFECT_0, SPELL_AURA_MOD_STUN, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_gen_stop_time_AuraScript(); + } +}; + void AddSC_oculus() { new npc_oculus_drake(); new npc_image_belgaristrasz(); + new spell_gen_stop_time(); } diff --git a/src/server/scripts/Spells/spell_quest.cpp b/src/server/scripts/Spells/spell_quest.cpp index 66ff06decc3..5648c510413 100644 --- a/src/server/scripts/Spells/spell_quest.cpp +++ b/src/server/scripts/Spells/spell_quest.cpp @@ -1194,6 +1194,57 @@ public: } }; +enum ACleansingSong +{ + SPELL_SUMMON_SPIRIT_ATAH = 52954, + SPELL_SUMMON_SPIRIT_HAKHALAN = 52958, + SPELL_SUMMON_SPIRIT_KOOSU = 52959, + + AREA_BITTERTIDELAKE = 4385, + AREA_RIVERSHEART = 4290, + AREA_WINTERGRASPRIVER = 4388, +}; + +class spell_q12735_song_of_cleansing : public SpellScriptLoader +{ + public: + spell_q12735_song_of_cleansing() : SpellScriptLoader("spell_q12735_song_of_cleansing") { } + + class spell_q12735_song_of_cleansing_SpellScript : public SpellScript + { + PrepareSpellScript(spell_q12735_song_of_cleansing_SpellScript); + + void HandleScript(SpellEffIndex /*effIndex*/) + { + Unit* caster = GetCaster(); + switch (caster->GetAreaId()) + { + case AREA_BITTERTIDELAKE: + caster->CastSpell(caster, SPELL_SUMMON_SPIRIT_ATAH); + break; + case AREA_RIVERSHEART: + caster->CastSpell(caster, SPELL_SUMMON_SPIRIT_HAKHALAN); + break; + case AREA_WINTERGRASPRIVER: + caster->CastSpell(caster, SPELL_SUMMON_SPIRIT_KOOSU); + break; + default: + break; + } + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_q12735_song_of_cleansing_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_q12735_song_of_cleansing_SpellScript(); + } +}; + void AddSC_quest_spell_scripts() { new spell_q55_sacred_cleansing(); @@ -1222,4 +1273,5 @@ void AddSC_quest_spell_scripts() new spell_q12987_read_pronouncement(); new spell_q12277_wintergarde_mine_explosion(); new spell_q12066_bunny_kill_credit(); + new spell_q12735_song_of_cleansing(); } |
