aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/game/AI/SmartScripts/SmartScriptMgr.h2
-rwxr-xr-xsrc/server/game/Entities/Item/ItemPrototype.h1
-rwxr-xr-xsrc/server/game/Entities/Unit/Unit.cpp16
-rwxr-xr-xsrc/server/game/Groups/Group.cpp118
-rwxr-xr-xsrc/server/game/Handlers/LootHandler.cpp6
-rwxr-xr-xsrc/server/game/Loot/LootMgr.cpp67
-rwxr-xr-xsrc/server/game/Loot/LootMgr.h3
-rwxr-xr-xsrc/server/game/Spells/Spell.cpp115
-rwxr-xr-xsrc/server/game/Spells/Spell.h1
-rw-r--r--src/server/game/Spells/SpellInfo.cpp1
-rwxr-xr-xsrc/server/game/Spells/SpellScript.cpp15
-rwxr-xr-xsrc/server/game/Spells/SpellScript.h18
-rw-r--r--src/server/scripts/Northrend/Nexus/Oculus/oculus.cpp36
-rw-r--r--src/server/scripts/Spells/spell_quest.cpp52
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();
}