aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/game/AI/SmartScripts/SmartScript.cpp39
-rw-r--r--src/server/game/AI/SmartScripts/SmartScriptMgr.cpp3
-rw-r--r--src/server/game/AI/SmartScripts/SmartScriptMgr.h12
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp54
-rw-r--r--src/server/game/Entities/Unit/Unit.h2
-rwxr-xr-xsrc/server/game/Entities/Vehicle/Vehicle.cpp184
-rw-r--r--src/server/game/Entities/Vehicle/Vehicle.h27
-rw-r--r--src/server/game/Handlers/CharacterHandler.cpp2
-rw-r--r--src/server/game/Spells/Auras/SpellAuras.cpp162
-rw-r--r--src/server/game/Spells/SpellInfo.cpp6
-rw-r--r--src/server/game/Spells/SpellInfo.h1
-rw-r--r--src/server/game/Spells/SpellMgr.cpp13
-rw-r--r--src/server/game/Weather/Weather.cpp3
-rw-r--r--src/server/game/Weather/Weather.h1
-rw-r--r--src/server/game/World/World.h2
-rw-r--r--src/server/scripts/EasternKingdoms/BlackwingLair/boss_broodlord_lashlayer.cpp90
-rw-r--r--src/server/scripts/Kalimdor/zone_desolace.cpp2
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_blood_queen_lana_thel.cpp53
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp92
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h1
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp2
-rw-r--r--src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp4
-rw-r--r--src/server/scripts/Northrend/zone_storm_peaks.cpp114
-rw-r--r--src/server/scripts/Spells/spell_item.cpp61
24 files changed, 521 insertions, 409 deletions
diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp
index e37b9e777d8..80388ce0be9 100644
--- a/src/server/game/AI/SmartScripts/SmartScript.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScript.cpp
@@ -2028,6 +2028,45 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
delete targets;
break;
}
+ case SMART_ACTION_SET_GO_FLAG:
+ {
+ ObjectList* targets = GetTargets(e, unit);
+ if (!targets)
+ break;
+
+ for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
+ if (IsGameObject(*itr))
+ (*itr)->ToGameObject()->SetUInt32Value(GAMEOBJECT_FLAGS, e.action.goFlag.flag);
+
+ delete targets;
+ break;
+ }
+ case SMART_ACTION_ADD_GO_FLAG:
+ {
+ ObjectList* targets = GetTargets(e, unit);
+ if (!targets)
+ break;
+
+ for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
+ if (IsGameObject(*itr))
+ (*itr)->ToGameObject()->SetFlag(GAMEOBJECT_FLAGS, e.action.goFlag.flag);
+
+ delete targets;
+ break;
+ }
+ case SMART_ACTION_REMOVE_GO_FLAG:
+ {
+ ObjectList* targets = GetTargets(e, unit);
+ if (!targets)
+ break;
+
+ for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
+ if (IsGameObject(*itr))
+ (*itr)->ToGameObject()->RemoveFlag(GAMEOBJECT_FLAGS, e.action.goFlag.flag);
+
+ delete targets;
+ break;
+ }
default:
sLog->outError(LOG_FILTER_SQL, "SmartScript::ProcessAction: Entry %d SourceType %u, Event %u, Unhandled Action type %u", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
break;
diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
index 90534de327a..f140afe1295 100644
--- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
@@ -907,6 +907,9 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
case SMART_ACTION_SET_HOME_POS:
case SMART_ACTION_SET_HEALTH_REGEN:
case SMART_ACTION_SET_ROOT:
+ case SMART_ACTION_SET_GO_FLAG:
+ case SMART_ACTION_ADD_GO_FLAG:
+ case SMART_ACTION_REMOVE_GO_FLAG:
break;
default:
sLog->outError(LOG_FILTER_SQL, "SmartAIMgr: Not handled action_type(%u), event_type(%u), Entry %d SourceType %u Event %u, skipped.", e.GetActionType(), e.GetEventType(), e.entryOrGuid, e.GetScriptType(), e.event_id);
diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h
index 88f9ce4f6f4..133c227f825 100644
--- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h
+++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h
@@ -426,7 +426,6 @@ enum SMART_ACTION
SMART_ACTION_SET_INVINCIBILITY_HP_LEVEL = 42, // MinHpValue(+pct, -flat)
SMART_ACTION_MOUNT_TO_ENTRY_OR_MODEL = 43, // Creature_template entry(param1) OR ModelId (param2) (or 0 for both to dismount)
SMART_ACTION_SET_INGAME_PHASE_MASK = 44, // mask
-
SMART_ACTION_SET_DATA = 45, // Field, Data (only creature TODO)
SMART_ACTION_MOVE_FORWARD = 46, // distance
SMART_ACTION_SET_VISIBILITY = 47, // on/off
@@ -449,7 +448,6 @@ enum SMART_ACTION
SMART_ACTION_STORE_TARGET_LIST = 64, // varID,
SMART_ACTION_WP_RESUME = 65, // none
SMART_ACTION_SET_ORIENTATION = 66, //
-
SMART_ACTION_CREATE_TIMED_EVENT = 67, // id, InitialMin, InitialMax, RepeatMin(only if it repeats), RepeatMax(only if it repeats), chance
SMART_ACTION_PLAYMOVIE = 68, // entry
SMART_ACTION_MOVE_TO_POS = 69, // PointId, xyz
@@ -487,8 +485,11 @@ enum SMART_ACTION
SMART_ACTION_SET_HOME_POS = 101, // none
SMART_ACTION_SET_HEALTH_REGEN = 102, // 0/1
SMART_ACTION_SET_ROOT = 103, // off/on
+ SMART_ACTION_SET_GO_FLAG = 104, // Flags
+ SMART_ACTION_ADD_GO_FLAG = 105, // Flags
+ SMART_ACTION_REMOVE_GO_FLAG = 106, // Flags
- SMART_ACTION_END = 104
+ SMART_ACTION_END = 107
};
struct SmartAction
@@ -925,6 +926,11 @@ struct SmartAction
uint32 root;
} setRoot;
+ struct
+ {
+ uint32 flag;
+ } goFlag;
+
//! Note for any new future actions
//! All parameters must have type uint32
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index e3a2430f63a..29b3fe0383a 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -3147,7 +3147,9 @@ void Unit::DeMorph()
Aura* Unit::_TryStackingOrRefreshingExistingAura(SpellInfo const* newAura, uint8 effMask, Unit* caster, int32* baseAmount /*= NULL*/, Item* castItem /*= NULL*/, uint64 casterGUID /*= 0*/)
{
ASSERT(casterGUID || caster);
- if (!casterGUID)
+
+ // Check if these can stack anyway
+ if (!casterGUID && !newAura->IsStackableOnOneSlotWithDifferentCasters())
casterGUID = caster->GetGUID();
// passive and Incanter's Absorption and auras with different type can stack with themselves any number of times
@@ -8462,48 +8464,6 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg
return false;
break;
}
- // Shadow's Fate (Shadowmourne questline)
- case 71169:
- {
- // Victim needs more checks so bugs, rats or summons can not be affected by the proc.
- if (GetTypeId() != TYPEID_PLAYER || !victim || victim->GetTypeId() != TYPEID_UNIT || victim->GetCreatureType() == CREATURE_TYPE_CRITTER)
- return false;
-
- Player* player = ToPlayer();
- if (player->GetQuestStatus(24547) == QUEST_STATUS_INCOMPLETE)
- {
- break;
- }
- else if (player->GetDifficulty(true) == RAID_DIFFICULTY_25MAN_NORMAL || player->GetDifficulty(true) == RAID_DIFFICULTY_25MAN_HEROIC)
- {
- uint32 spellId = 0;
- uint32 questId = 0;
- switch (victim->GetEntry())
- {
- case 36678: // NPC: Professor Putricide
- questId = 24749; // Quest: Unholy Infusion
- spellId = 71516; // Spell: Shadow Infusion
- break;
- case 37955: // NPC: Blood-Queen Lana'thel
- questId = 24756; // Quest: Blood Infusion
- spellId = 72154; // Spell: Thirst Quenched
- break;
- case 36853: // NPC: Sindragosa
- questId = 24757; // Quest: Frost Infusion
- spellId = 72290; // Spell: Frost-Imbued Blade
- break;
- default:
- return false;
- }
-
- if (player->GetQuestStatus(questId) != QUEST_STATUS_INCOMPLETE || !player->HasAura(spellId))
- return false;
-
- break;
- }
- else
- return false;
- }
}
if (cooldown && GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(trigger_spell_id))
@@ -16639,13 +16599,9 @@ void Unit::_EnterVehicle(Vehicle* vehicle, int8 seatId, AuraApplication const* a
}
ASSERT(!m_vehicle);
- m_vehicle = vehicle;
- if (!m_vehicle->AddPassenger(this, seatId))
- {
- m_vehicle = NULL;
- return;
- }
+
+ (void)vehicle->AddPassenger(this, seatId);
}
void Unit::ChangeSeat(int8 seatId, bool next)
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index 1a41c25d97c..62facf6a69e 100644
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -332,6 +332,7 @@ class UnitAI;
class Totem;
class Transport;
class Vehicle;
+class VehicleJoinEvent;
class TransportBase;
class SpellCastTargets;
@@ -2183,6 +2184,7 @@ class Unit : public WorldObject
uint32 GetRedirectThreatPercent() { return _redirectThreadInfo.GetThreatPct(); }
Unit* GetRedirectThreatTarget() { return _redirectThreadInfo.GetTargetGUID() ? GetUnit(*this, _redirectThreadInfo.GetTargetGUID()) : NULL; }
+ friend class VehicleJoinEvent;
bool IsAIEnabled, NeedChangeAI;
bool CreateVehicleKit(uint32 id, uint32 creatureEntry);
void RemoveVehicleKit();
diff --git a/src/server/game/Entities/Vehicle/Vehicle.cpp b/src/server/game/Entities/Vehicle/Vehicle.cpp
index 96f2b6d73dd..58cf6773c59 100755
--- a/src/server/game/Entities/Vehicle/Vehicle.cpp
+++ b/src/server/game/Entities/Vehicle/Vehicle.cpp
@@ -30,9 +30,10 @@
#include "SpellInfo.h"
#include "MoveSplineInit.h"
#include "TemporarySummon.h"
+#include "EventProcessor.h"
Vehicle::Vehicle(Unit* unit, VehicleEntry const* vehInfo, uint32 creatureEntry) :
-_me(unit), _vehicleInfo(vehInfo), _usableSeatNum(0), _creatureEntry(creatureEntry), _status(STATUS_NONE)
+_me(unit), _vehicleInfo(vehInfo), UsableSeatNum(0), _creatureEntry(creatureEntry), _status(STATUS_NONE)
{
for (uint32 i = 0; i < MAX_VEHICLE_SEATS; ++i)
{
@@ -41,7 +42,7 @@ _me(unit), _vehicleInfo(vehInfo), _usableSeatNum(0), _creatureEntry(creatureEntr
{
Seats.insert(std::make_pair(i, VehicleSeat(veSeat)));
if (veSeat->CanEnterOrExit())
- ++_usableSeatNum;
+ ++UsableSeatNum;
}
}
@@ -123,10 +124,12 @@ void Vehicle::Uninstall()
"Check Uninstall/PassengerBoarded script hooks for errors.", _me->GetGUIDLow(), _me->GetEntry());
return;
}
+
_status = STATUS_UNINSTALLING;
sLog->outDebug(LOG_FILTER_VEHICLES, "Vehicle::Uninstall Entry: %u, GuidLow: %u", _creatureEntry, _me->GetGUIDLow());
RemoveAllPassengers();
+
if (GetBase()->GetTypeId() == TYPEID_UNIT)
sScriptMgr->OnUninstall(this);
}
@@ -136,14 +139,14 @@ void Vehicle::Reset(bool evading /*= false*/)
sLog->outDebug(LOG_FILTER_VEHICLES, "Vehicle::Reset Entry: %u, GuidLow: %u", _creatureEntry, _me->GetGUIDLow());
if (_me->GetTypeId() == TYPEID_PLAYER)
{
- if (_usableSeatNum)
+ if (UsableSeatNum)
_me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_PLAYER_VEHICLE);
}
else
{
ApplyAllImmunities();
InstallAllAccessories(evading);
- if (_usableSeatNum)
+ if (UsableSeatNum)
_me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK);
}
@@ -215,6 +218,19 @@ void Vehicle::RemoveAllPassengers()
// ASSERT(!itr->second.passenger);
}
+void Vehicle::RemovePendingPassengers()
+{
+ sLog->outDebug(LOG_FILTER_VEHICLES, "Vehicle::RemovePendingPassengers. Entry: %u, GuidLow: %u", _creatureEntry, _me->GetGUIDLow());
+
+ /// Setting to_Abort to true will cause @VehicleJoinEvent::Abort to be executed on next @Unit::UpdateEvents call
+ /// This will properly "reset" the pending join process for the passenger.
+ while (VehicleJoinEvent* e = _pendingJoinEvents.front())
+ {
+ e->to_Abort = true;
+ _pendingJoinEvents.pop_front();
+ }
+}
+
bool Vehicle::HasEmptySeat(int8 seatId) const
{
SeatMap::const_iterator seat = Seats.find(seatId);
@@ -317,7 +333,17 @@ bool Vehicle::AddPassenger(Unit* unit, int8 seatId)
if (unit->GetVehicle() != this)
return false;
+ // The seat selection code may kick other passengers off the vehicle.
+ // While the validity of the following may be arguable, it is possible that when such a passenger
+ // exits the vehicle will dismiss. That's why the actual adding the passenger to the vehicle is scheduled
+ // asynchronously, so it can be cancelled easily in case the vehicle is uninstalled meanwhile.
SeatMap::iterator seat;
+ sLog->outDebug(LOG_FILTER_VEHICLES, "Unit %s scheduling enter vehicle entry %u id %u dbguid %u seat %d",
+ unit->GetName().c_str(), _me->GetEntry(), _vehicleInfo->m_ID, _me->GetGUIDLow(), seatId);
+ VehicleJoinEvent* e = new VehicleJoinEvent(this, unit);
+ unit->m_Events.AddEvent(e, unit->m_Events.CalculateTime(0));
+ _pendingJoinEvents.push_back(e);
+
if (seatId < 0) // no specific seat requirement
{
for (seat = Seats.begin(); seat != Seats.end(); ++seat)
@@ -325,14 +351,23 @@ bool Vehicle::AddPassenger(Unit* unit, int8 seatId)
break;
if (seat == Seats.end()) // no available seat
+ {
+ CancelJoinEvent(e);
return false;
+ }
+
+ e->Seat = seat;
}
else
{
seat = Seats.find(seatId);
if (seat == Seats.end())
+ {
+ CancelJoinEvent(e);
return false;
+ }
+ e->Seat = seat;
if (seat->second.Passenger)
{
if (Unit* passenger = ObjectAccessor::GetUnit(*GetBase(), seat->second.Passenger))
@@ -344,65 +379,6 @@ bool Vehicle::AddPassenger(Unit* unit, int8 seatId)
ASSERT(!seat->second.Passenger);
}
- sLog->outDebug(LOG_FILTER_VEHICLES, "Unit %s enter vehicle entry %u id %u dbguid %u seat %d", unit->GetName().c_str(), _me->GetEntry(), _vehicleInfo->m_ID, _me->GetGUIDLow(), (int32)seat->first);
-
- seat->second.Passenger = unit->GetGUID();
- if (seat->second.SeatInfo->CanEnterOrExit())
- {
- ASSERT(_usableSeatNum);
- --_usableSeatNum;
- if (!_usableSeatNum)
- {
- if (_me->GetTypeId() == TYPEID_PLAYER)
- _me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_PLAYER_VEHICLE);
- else
- _me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK);
- }
- }
-
- if (seat->second.SeatInfo->m_flags && !(seat->second.SeatInfo->m_flags & VEHICLE_SEAT_FLAG_ALLOW_TURNING))
- unit->AddUnitState(UNIT_STATE_ONVEHICLE);
-
- unit->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
- VehicleSeatEntry const* veSeat = seat->second.SeatInfo;
- unit->m_movementInfo.t_pos.m_positionX = veSeat->m_attachmentOffsetX;
- unit->m_movementInfo.t_pos.m_positionY = veSeat->m_attachmentOffsetY;
- unit->m_movementInfo.t_pos.m_positionZ = veSeat->m_attachmentOffsetZ;
- unit->m_movementInfo.t_pos.SetOrientation(0);
- unit->m_movementInfo.t_time = 0; // 1 for player
- unit->m_movementInfo.t_seat = seat->first;
- unit->m_movementInfo.t_guid = _me->GetGUID();
-
- if (_me->GetTypeId() == TYPEID_UNIT && unit->GetTypeId() == TYPEID_PLAYER &&
- seat->second.SeatInfo->m_flags & VEHICLE_SEAT_FLAG_CAN_CONTROL)
- ASSERT(_me->SetCharmedBy(unit, CHARM_TYPE_VEHICLE))
-
- if (_me->IsInWorld())
- {
- unit->SendClearTarget(); // SMSG_BREAK_TARGET
- unit->SetControlled(true, UNIT_STATE_ROOT); // SMSG_FORCE_ROOT - In some cases we send SMSG_SPLINE_MOVE_ROOT here (for creatures)
- // also adds MOVEMENTFLAG_ROOT
- Movement::MoveSplineInit init(unit);
- init.DisableTransportPathTransformations();
- init.MoveTo(veSeat->m_attachmentOffsetX, veSeat->m_attachmentOffsetY, veSeat->m_attachmentOffsetZ);
- init.SetFacing(0.0f);
- init.SetTransportEnter();
- init.Launch();
-
- if (_me->GetTypeId() == TYPEID_UNIT)
- {
- if (_me->ToCreature()->IsAIEnabled)
- _me->ToCreature()->AI()->PassengerBoarded(unit, seat->first, true);
-
- // update all passenger's positions
- //Passenger's spline OR vehicle movement will update positions
- //RelocatePassengers(_me->GetPositionX(), _me->GetPositionY(), _me->GetPositionZ(), _me->GetOrientation());
- }
- }
-
- if (GetBase()->GetTypeId() == TYPEID_UNIT)
- sScriptMgr->OnAddPassenger(this, unit, seatId);
-
return true;
}
@@ -419,14 +395,14 @@ void Vehicle::RemovePassenger(Unit* unit)
seat->second.Passenger = 0;
if (seat->second.SeatInfo->CanEnterOrExit())
{
- if (!_usableSeatNum)
+ if (!UsableSeatNum)
{
if (_me->GetTypeId() == TYPEID_PLAYER)
_me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_PLAYER_VEHICLE);
else
_me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK);
}
- ++_usableSeatNum;
+ ++UsableSeatNum;
}
unit->ClearUnitState(UNIT_STATE_ONVEHICLE);
@@ -549,3 +525,81 @@ void Vehicle::CalculatePassengerOffset(float& x, float& y, float& z, float& o)
y = (iny - inx * tan(GetBase()->GetOrientation())) / (cos(GetBase()->GetOrientation()) + std::sin(GetBase()->GetOrientation()) * tan(GetBase()->GetOrientation()));
x = (inx + iny * tan(GetBase()->GetOrientation())) / (cos(GetBase()->GetOrientation()) + std::sin(GetBase()->GetOrientation()) * tan(GetBase()->GetOrientation()));
}
+
+void Vehicle::CancelJoinEvent(VehicleJoinEvent* e)
+{
+ e->to_Abort = true;
+ _pendingJoinEvents.pop_back();
+}
+
+bool VehicleJoinEvent::Execute(uint64, uint32)
+{
+ ASSERT(Passenger->GetVehicle() == Target);
+ Passenger->m_vehicle = Target;
+
+ Seat->second.Passenger = Passenger->GetGUID();
+ if (Seat->second.SeatInfo->CanEnterOrExit())
+ {
+ ASSERT(Target->UsableSeatNum);
+ --(Target->UsableSeatNum);
+ if (!Target->UsableSeatNum)
+ {
+ if (Target->GetBase()->GetTypeId() == TYPEID_PLAYER)
+ Target->GetBase()->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_PLAYER_VEHICLE);
+ else
+ Target->GetBase()->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK);
+ }
+ }
+
+ if (Seat->second.SeatInfo->m_flags && !(Seat->second.SeatInfo->m_flags & VEHICLE_SEAT_FLAG_ALLOW_TURNING))
+ Passenger->AddUnitState(UNIT_STATE_ONVEHICLE);
+
+ Passenger->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
+ VehicleSeatEntry const* veSeat = Seat->second.SeatInfo;
+ Passenger->m_movementInfo.t_pos.m_positionX = veSeat->m_attachmentOffsetX;
+ Passenger->m_movementInfo.t_pos.m_positionY = veSeat->m_attachmentOffsetY;
+ Passenger->m_movementInfo.t_pos.m_positionZ = veSeat->m_attachmentOffsetZ;
+ Passenger->m_movementInfo.t_pos.SetOrientation(0.0f);
+ Passenger->m_movementInfo.t_time = 0; // 1 for player
+ Passenger->m_movementInfo.t_seat = Seat->first;
+ Passenger->m_movementInfo.t_guid = Target->GetBase()->GetGUID();
+
+ if (Target->GetBase()->GetTypeId() == TYPEID_UNIT && Passenger->GetTypeId() == TYPEID_PLAYER &&
+ Seat->second.SeatInfo->m_flags & VEHICLE_SEAT_FLAG_CAN_CONTROL)
+ ASSERT(Target->GetBase()->SetCharmedBy(Passenger, CHARM_TYPE_VEHICLE))
+
+ if (Target->GetBase()->IsInWorld())
+ {
+ Passenger->SendClearTarget(); // SMSG_BREAK_TARGET
+ Passenger->SetControlled(true, UNIT_STATE_ROOT); // SMSG_FORCE_ROOT - In some cases we send SMSG_SPLINE_MOVE_ROOT here (for creatures)
+ // also adds MOVEMENTFLAG_ROOT
+ Movement::MoveSplineInit init(Passenger);
+ init.DisableTransportPathTransformations();
+ init.MoveTo(veSeat->m_attachmentOffsetX, veSeat->m_attachmentOffsetY, veSeat->m_attachmentOffsetZ);
+ init.SetFacing(0.0f);
+ init.SetTransportEnter();
+ init.Launch();
+
+ if (Target->GetBase()->GetTypeId() == TYPEID_UNIT)
+ {
+ if (Target->GetBase()->ToCreature()->IsAIEnabled)
+ Target->GetBase()->ToCreature()->AI()->PassengerBoarded(Passenger, Seat->first, true);
+
+ // update all passenger's positions
+ //Passenger's spline OR vehicle movement will update positions
+ //RelocatePassengers(_me->GetPositionX(), _me->GetPositionY(), _me->GetPositionZ(), _me->GetOrientation());
+ }
+ }
+
+ if (Target->GetBase()->GetTypeId() == TYPEID_UNIT)
+ sScriptMgr->OnAddPassenger(Target, Passenger, Seat->first);
+
+ return true;
+}
+
+void VehicleJoinEvent::Abort(uint64)
+{
+ sLog->outDebug(LOG_FILTER_VEHICLES, "Passenger GuidLow: %u, Entry: %u, board on vehicle GuidLow: %u, Entry: %u SeatId: %i cancelled",
+ Passenger->GetGUIDLow(), Passenger->GetEntry(), Target->GetBase()->GetGUIDLow(), Target->GetBase()->GetEntry(), (int32)Seat->first);
+ // Passenger->m_vehicle = NULL;
+}
diff --git a/src/server/game/Entities/Vehicle/Vehicle.h b/src/server/game/Entities/Vehicle/Vehicle.h
index 823fb72b8a8..dbdd021a384 100644
--- a/src/server/game/Entities/Vehicle/Vehicle.h
+++ b/src/server/game/Entities/Vehicle/Vehicle.h
@@ -23,12 +23,12 @@
#include "Object.h"
#include "VehicleDefines.h"
#include "Unit.h"
+#include <deque>
struct VehicleEntry;
-
class Unit;
-
typedef std::set<uint64> GuidSet;
+class VehicleJoinEvent;
class Vehicle : public TransportBase
{
@@ -54,6 +54,7 @@ class Vehicle : public TransportBase
void RemovePassenger(Unit* passenger);
void RelocatePassengers();
void RemoveAllPassengers();
+ void RemovePendingPassengers();
void Dismiss();
void TeleportVehicle(float x, float y, float z, float ang);
bool IsVehicleInUse() { return Seats.begin() != Seats.end(); }
@@ -66,6 +67,10 @@ class Vehicle : public TransportBase
VehicleSeatEntry const* GetSeatForPassenger(Unit* passenger);
protected:
+ friend class VehicleJoinEvent;
+ uint32 UsableSeatNum; // Number of seats that match VehicleSeatEntry::UsableByPlayer, used for proper display flags
+
+ protected:
friend bool Unit::CreateVehicleKit(uint32 id, uint32 creatureEntry);
Vehicle(Unit* unit, VehicleEntry const* vehInfo, uint32 creatureEntry);
friend void Unit::RemoveVehicleKit();
@@ -91,9 +96,25 @@ class Vehicle : public TransportBase
Unit* _me;
VehicleEntry const* _vehicleInfo;
GuidSet vehiclePlayers;
- uint32 _usableSeatNum; // Number of seats that match VehicleSeatEntry::UsableByPlayer, used for proper display flags
+
uint32 _creatureEntry; // Can be different than me->GetBase()->GetEntry() in case of players
Status _status;
Position m_lastShootPos;
+
+ std::deque<VehicleJoinEvent*> _pendingJoinEvents;
+ void CancelJoinEvent(VehicleJoinEvent* e);
+};
+
+class VehicleJoinEvent : public BasicEvent
+{
+ friend class Vehicle;
+ protected:
+ VehicleJoinEvent(Vehicle* v, Unit* u) : Target(v), Passenger(u), Seat(Target->Seats.end()) {}
+ bool Execute(uint64, uint32);
+ void Abort(uint64);
+
+ Vehicle* Target;
+ Unit* Passenger;
+ SeatMap::iterator Seat;
};
#endif
diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp
index 817a7682678..b12893ff65f 100644
--- a/src/server/game/Handlers/CharacterHandler.cpp
+++ b/src/server/game/Handlers/CharacterHandler.cpp
@@ -727,7 +727,7 @@ void WorldSession::HandleCharDeleteOpcode(WorldPacket& recvData)
std::string IP_str = GetRemoteAddress();
sLog->outInfo(LOG_FILTER_CHARACTER, "Account: %d, IP: %s deleted character: %s, GUID: %u, Level: %u", accountId, IP_str.c_str(), name.c_str(), GUID_LOPART(guid), level);
sScriptMgr->OnPlayerDelete(guid);
- sWorld->DeleteCharaceterNameData(GUID_LOPART(guid));
+ sWorld->DeleteCharacterNameData(GUID_LOPART(guid));
if (sLog->ShouldLog(LOG_FILTER_PLAYER_DUMP, LOG_LEVEL_INFO)) // optimize GetPlayerDump call
{
diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp
index 4500152133e..375f9ef067c 100644
--- a/src/server/game/Spells/Auras/SpellAuras.cpp
+++ b/src/server/game/Spells/Auras/SpellAuras.cpp
@@ -908,6 +908,10 @@ bool Aura::CanBeSaved() const
if (HasEffectType(SPELL_AURA_OPEN_STABLE))
return false;
+ // Can't save vehicle auras, it requires both caster & target to be in world
+ if (HasEffectType(SPELL_AURA_CONTROL_VEHICLE))
+ return false;
+
// Incanter's Absorbtion - considering the minimal duration and problems with aura stacking
// we skip saving this aura
// Also for some reason other auras put as MultiSlot crash core on keeping them after restart,
@@ -2092,16 +2096,17 @@ void Aura::LoadScripts()
bool Aura::CallScriptCheckAreaTargetHandlers(Unit* target)
{
+ bool result = true;
for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
{
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_CHECK_AREA_TARGET);
std::list<AuraScript::CheckAreaTargetHandler>::iterator hookItrEnd = (*scritr)->DoCheckAreaTarget.end(), hookItr = (*scritr)->DoCheckAreaTarget.begin();
for (; hookItr != hookItrEnd; ++hookItr)
- if (!(*hookItr).Call(*scritr, target))
- return false;
+ result &= hookItr->Call(*scritr, target);
+
(*scritr)->_FinishScriptCall();
}
- return true;
+ return result;
}
void Aura::CallScriptDispel(DispelInfo* dispelInfo)
@@ -2111,7 +2116,8 @@ void Aura::CallScriptDispel(DispelInfo* dispelInfo)
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_DISPEL);
std::list<AuraScript::AuraDispelHandler>::iterator hookItrEnd = (*scritr)->OnDispel.end(), hookItr = (*scritr)->OnDispel.begin();
for (; hookItr != hookItrEnd; ++hookItr)
- (*hookItr).Call(*scritr, dispelInfo);
+ hookItr->Call(*scritr, dispelInfo);
+
(*scritr)->_FinishScriptCall();
}
}
@@ -2123,7 +2129,8 @@ void Aura::CallScriptAfterDispel(DispelInfo* dispelInfo)
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_AFTER_DISPEL);
std::list<AuraScript::AuraDispelHandler>::iterator hookItrEnd = (*scritr)->AfterDispel.end(), hookItr = (*scritr)->AfterDispel.begin();
for (; hookItr != hookItrEnd; ++hookItr)
- (*hookItr).Call(*scritr, dispelInfo);
+ hookItr->Call(*scritr, dispelInfo);
+
(*scritr)->_FinishScriptCall();
}
}
@@ -2136,14 +2143,15 @@ bool Aura::CallScriptEffectApplyHandlers(AuraEffect const* aurEff, AuraApplicati
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_APPLY, aurApp);
std::list<AuraScript::EffectApplyHandler>::iterator effEndItr = (*scritr)->OnEffectApply.end(), effItr = (*scritr)->OnEffectApply.begin();
for (; effItr != effEndItr; ++effItr)
- {
- if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
- (*effItr).Call(*scritr, aurEff, mode);
- }
+ if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
+ effItr->Call(*scritr, aurEff, mode);
+
if (!preventDefault)
preventDefault = (*scritr)->_IsDefaultActionPrevented();
+
(*scritr)->_FinishScriptCall();
}
+
return preventDefault;
}
@@ -2155,12 +2163,12 @@ bool Aura::CallScriptEffectRemoveHandlers(AuraEffect const* aurEff, AuraApplicat
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_REMOVE, aurApp);
std::list<AuraScript::EffectApplyHandler>::iterator effEndItr = (*scritr)->OnEffectRemove.end(), effItr = (*scritr)->OnEffectRemove.begin();
for (; effItr != effEndItr; ++effItr)
- {
- if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
- (*effItr).Call(*scritr, aurEff, mode);
- }
+ if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
+ effItr->Call(*scritr, aurEff, mode);
+
if (!preventDefault)
preventDefault = (*scritr)->_IsDefaultActionPrevented();
+
(*scritr)->_FinishScriptCall();
}
return preventDefault;
@@ -2173,10 +2181,9 @@ void Aura::CallScriptAfterEffectApplyHandlers(AuraEffect const* aurEff, AuraAppl
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_AFTER_APPLY, aurApp);
std::list<AuraScript::EffectApplyHandler>::iterator effEndItr = (*scritr)->AfterEffectApply.end(), effItr = (*scritr)->AfterEffectApply.begin();
for (; effItr != effEndItr; ++effItr)
- {
- if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
- (*effItr).Call(*scritr, aurEff, mode);
- }
+ if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
+ effItr->Call(*scritr, aurEff, mode);
+
(*scritr)->_FinishScriptCall();
}
}
@@ -2188,10 +2195,9 @@ void Aura::CallScriptAfterEffectRemoveHandlers(AuraEffect const* aurEff, AuraApp
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_AFTER_REMOVE, aurApp);
std::list<AuraScript::EffectApplyHandler>::iterator effEndItr = (*scritr)->AfterEffectRemove.end(), effItr = (*scritr)->AfterEffectRemove.begin();
for (; effItr != effEndItr; ++effItr)
- {
- if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
- (*effItr).Call(*scritr, aurEff, mode);
- }
+ if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
+ effItr->Call(*scritr, aurEff, mode);
+
(*scritr)->_FinishScriptCall();
}
}
@@ -2204,14 +2210,15 @@ bool Aura::CallScriptEffectPeriodicHandlers(AuraEffect const* aurEff, AuraApplic
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_PERIODIC, aurApp);
std::list<AuraScript::EffectPeriodicHandler>::iterator effEndItr = (*scritr)->OnEffectPeriodic.end(), effItr = (*scritr)->OnEffectPeriodic.begin();
for (; effItr != effEndItr; ++effItr)
- {
- if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
- (*effItr).Call(*scritr, aurEff);
- }
+ if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
+ effItr->Call(*scritr, aurEff);
+
if (!preventDefault)
preventDefault = (*scritr)->_IsDefaultActionPrevented();
+
(*scritr)->_FinishScriptCall();
}
+
return preventDefault;
}
@@ -2222,10 +2229,9 @@ void Aura::CallScriptEffectUpdatePeriodicHandlers(AuraEffect* aurEff)
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_UPDATE_PERIODIC);
std::list<AuraScript::EffectUpdatePeriodicHandler>::iterator effEndItr = (*scritr)->OnEffectUpdatePeriodic.end(), effItr = (*scritr)->OnEffectUpdatePeriodic.begin();
for (; effItr != effEndItr; ++effItr)
- {
- if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
- (*effItr).Call(*scritr, aurEff);
- }
+ if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
+ effItr->Call(*scritr, aurEff);
+
(*scritr)->_FinishScriptCall();
}
}
@@ -2237,10 +2243,9 @@ void Aura::CallScriptEffectCalcAmountHandlers(AuraEffect const* aurEff, int32 &
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_CALC_AMOUNT);
std::list<AuraScript::EffectCalcAmountHandler>::iterator effEndItr = (*scritr)->DoEffectCalcAmount.end(), effItr = (*scritr)->DoEffectCalcAmount.begin();
for (; effItr != effEndItr; ++effItr)
- {
- if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
- (*effItr).Call(*scritr, aurEff, amount, canBeRecalculated);
- }
+ if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
+ effItr->Call(*scritr, aurEff, amount, canBeRecalculated);
+
(*scritr)->_FinishScriptCall();
}
}
@@ -2252,10 +2257,9 @@ void Aura::CallScriptEffectCalcPeriodicHandlers(AuraEffect const* aurEff, bool &
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_CALC_PERIODIC);
std::list<AuraScript::EffectCalcPeriodicHandler>::iterator effEndItr = (*scritr)->DoEffectCalcPeriodic.end(), effItr = (*scritr)->DoEffectCalcPeriodic.begin();
for (; effItr != effEndItr; ++effItr)
- {
- if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
- (*effItr).Call(*scritr, aurEff, isPeriodic, amplitude);
- }
+ if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
+ effItr->Call(*scritr, aurEff, isPeriodic, amplitude);
+
(*scritr)->_FinishScriptCall();
}
}
@@ -2267,10 +2271,9 @@ void Aura::CallScriptEffectCalcSpellModHandlers(AuraEffect const* aurEff, SpellM
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_CALC_SPELLMOD);
std::list<AuraScript::EffectCalcSpellModHandler>::iterator effEndItr = (*scritr)->DoEffectCalcSpellMod.end(), effItr = (*scritr)->DoEffectCalcSpellMod.begin();
for (; effItr != effEndItr; ++effItr)
- {
- if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
- (*effItr).Call(*scritr, aurEff, spellMod);
- }
+ if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
+ effItr->Call(*scritr, aurEff, spellMod);
+
(*scritr)->_FinishScriptCall();
}
}
@@ -2282,11 +2285,13 @@ void Aura::CallScriptEffectAbsorbHandlers(AuraEffect* aurEff, AuraApplication co
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_ABSORB, aurApp);
std::list<AuraScript::EffectAbsorbHandler>::iterator effEndItr = (*scritr)->OnEffectAbsorb.end(), effItr = (*scritr)->OnEffectAbsorb.begin();
for (; effItr != effEndItr; ++effItr)
- {
- if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
- (*effItr).Call(*scritr, aurEff, dmgInfo, absorbAmount);
- }
- defaultPrevented = (*scritr)->_IsDefaultActionPrevented();
+
+ if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
+ effItr->Call(*scritr, aurEff, dmgInfo, absorbAmount);
+
+ if (!defaultPrevented)
+ defaultPrevented = (*scritr)->_IsDefaultActionPrevented();
+
(*scritr)->_FinishScriptCall();
}
}
@@ -2298,10 +2303,9 @@ void Aura::CallScriptEffectAfterAbsorbHandlers(AuraEffect* aurEff, AuraApplicati
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_AFTER_ABSORB, aurApp);
std::list<AuraScript::EffectAbsorbHandler>::iterator effEndItr = (*scritr)->AfterEffectAbsorb.end(), effItr = (*scritr)->AfterEffectAbsorb.begin();
for (; effItr != effEndItr; ++effItr)
- {
- if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
- (*effItr).Call(*scritr, aurEff, dmgInfo, absorbAmount);
- }
+ if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
+ effItr->Call(*scritr, aurEff, dmgInfo, absorbAmount);
+
(*scritr)->_FinishScriptCall();
}
}
@@ -2313,10 +2317,9 @@ void Aura::CallScriptEffectManaShieldHandlers(AuraEffect* aurEff, AuraApplicatio
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_MANASHIELD, aurApp);
std::list<AuraScript::EffectManaShieldHandler>::iterator effEndItr = (*scritr)->OnEffectManaShield.end(), effItr = (*scritr)->OnEffectManaShield.begin();
for (; effItr != effEndItr; ++effItr)
- {
- if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
- (*effItr).Call(*scritr, aurEff, dmgInfo, absorbAmount);
- }
+ if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
+ effItr->Call(*scritr, aurEff, dmgInfo, absorbAmount);
+
(*scritr)->_FinishScriptCall();
}
}
@@ -2328,10 +2331,9 @@ void Aura::CallScriptEffectAfterManaShieldHandlers(AuraEffect* aurEff, AuraAppli
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_AFTER_MANASHIELD, aurApp);
std::list<AuraScript::EffectManaShieldHandler>::iterator effEndItr = (*scritr)->AfterEffectManaShield.end(), effItr = (*scritr)->AfterEffectManaShield.begin();
for (; effItr != effEndItr; ++effItr)
- {
- if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
- (*effItr).Call(*scritr, aurEff, dmgInfo, absorbAmount);
- }
+ if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
+ effItr->Call(*scritr, aurEff, dmgInfo, absorbAmount);
+
(*scritr)->_FinishScriptCall();
}
}
@@ -2343,26 +2345,27 @@ void Aura::CallScriptEffectSplitHandlers(AuraEffect* aurEff, AuraApplication con
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_SPLIT, aurApp);
std::list<AuraScript::EffectSplitHandler>::iterator effEndItr = (*scritr)->OnEffectSplit.end(), effItr = (*scritr)->OnEffectSplit.begin();
for (; effItr != effEndItr; ++effItr)
- {
- if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
- (*effItr).Call(*scritr, aurEff, dmgInfo, splitAmount);
- }
+ if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
+ effItr->Call(*scritr, aurEff, dmgInfo, splitAmount);
+
(*scritr)->_FinishScriptCall();
}
}
bool Aura::CallScriptCheckProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo)
{
+ bool result = true;
for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
{
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_CHECK_PROC, aurApp);
std::list<AuraScript::CheckProcHandler>::iterator hookItrEnd = (*scritr)->DoCheckProc.end(), hookItr = (*scritr)->DoCheckProc.begin();
for (; hookItr != hookItrEnd; ++hookItr)
- if (!(*hookItr).Call(*scritr, eventInfo))
- return false;
+ result &= hookItr->Call(*scritr, eventInfo);
+
(*scritr)->_FinishScriptCall();
}
- return true;
+
+ return result;
}
bool Aura::CallScriptPrepareProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo)
@@ -2373,12 +2376,14 @@ bool Aura::CallScriptPrepareProcHandlers(AuraApplication const* aurApp, ProcEven
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_PREPARE_PROC, aurApp);
std::list<AuraScript::AuraProcHandler>::iterator effEndItr = (*scritr)->DoPrepareProc.end(), effItr = (*scritr)->DoPrepareProc.begin();
for (; effItr != effEndItr; ++effItr)
- (*effItr).Call(*scritr, eventInfo);
+ effItr->Call(*scritr, eventInfo);
+
+ if (prepare)
+ prepare = !(*scritr)->_IsDefaultActionPrevented();
- if (prepare && (*scritr)->_IsDefaultActionPrevented())
- prepare = false;
(*scritr)->_FinishScriptCall();
}
+
return prepare;
}
@@ -2389,7 +2394,8 @@ void Aura::CallScriptProcHandlers(AuraApplication const* aurApp, ProcEventInfo&
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_PROC, aurApp);
std::list<AuraScript::AuraProcHandler>::iterator hookItrEnd = (*scritr)->OnProc.end(), hookItr = (*scritr)->OnProc.begin();
for (; hookItr != hookItrEnd; ++hookItr)
- (*hookItr).Call(*scritr, eventInfo);
+ hookItr->Call(*scritr, eventInfo);
+
(*scritr)->_FinishScriptCall();
}
}
@@ -2401,7 +2407,8 @@ void Aura::CallScriptAfterProcHandlers(AuraApplication const* aurApp, ProcEventI
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_AFTER_PROC, aurApp);
std::list<AuraScript::AuraProcHandler>::iterator hookItrEnd = (*scritr)->AfterProc.end(), hookItr = (*scritr)->AfterProc.begin();
for (; hookItr != hookItrEnd; ++hookItr)
- (*hookItr).Call(*scritr, eventInfo);
+ hookItr->Call(*scritr, eventInfo);
+
(*scritr)->_FinishScriptCall();
}
}
@@ -2414,12 +2421,12 @@ bool Aura::CallScriptEffectProcHandlers(AuraEffect const* aurEff, AuraApplicatio
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_PROC, aurApp);
std::list<AuraScript::EffectProcHandler>::iterator effEndItr = (*scritr)->OnEffectProc.end(), effItr = (*scritr)->OnEffectProc.begin();
for (; effItr != effEndItr; ++effItr)
- {
- if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
- (*effItr).Call(*scritr, aurEff, eventInfo);
- }
+ if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
+ effItr->Call(*scritr, aurEff, eventInfo);
+
if (!preventDefault)
preventDefault = (*scritr)->_IsDefaultActionPrevented();
+
(*scritr)->_FinishScriptCall();
}
return preventDefault;
@@ -2432,10 +2439,9 @@ void Aura::CallScriptAfterEffectProcHandlers(AuraEffect const* aurEff, AuraAppli
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_AFTER_PROC, aurApp);
std::list<AuraScript::EffectProcHandler>::iterator effEndItr = (*scritr)->AfterEffectProc.end(), effItr = (*scritr)->AfterEffectProc.begin();
for (; effItr != effEndItr; ++effItr)
- {
- if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
- (*effItr).Call(*scritr, aurEff, eventInfo);
- }
+ if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
+ effItr->Call(*scritr, aurEff, eventInfo);
+
(*scritr)->_FinishScriptCall();
}
}
diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp
index 91bff331160..9a9369bad28 100644
--- a/src/server/game/Spells/SpellInfo.cpp
+++ b/src/server/game/Spells/SpellInfo.cpp
@@ -1030,6 +1030,12 @@ bool SpellInfo::IsMultiSlotAura() const
return IsPassive() || Id == 55849 || Id == 40075 || Id == 44413; // Power Spark, Fel Flak Fire, Incanter's Absorption
}
+bool SpellInfo::IsStackableOnOneSlotWithDifferentCasters() const
+{
+ /// TODO: Re-verify meaning of SPELL_ATTR3_STACK_FOR_DIFF_CASTERS and update conditions here
+ return StackAmount > 1 && !IsChanneled() && !(AttributesEx3 & SPELL_ATTR3_STACK_FOR_DIFF_CASTERS);
+}
+
bool SpellInfo::IsDeathPersistent() const
{
return AttributesEx3 & SPELL_ATTR3_DEATH_PERSISTENT;
diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h
index 23682c3d48f..bbc5b61e282 100644
--- a/src/server/game/Spells/SpellInfo.h
+++ b/src/server/game/Spells/SpellInfo.h
@@ -392,6 +392,7 @@ public:
bool IsStackableWithRanks() const;
bool IsPassiveStackableWithRanks() const;
bool IsMultiSlotAura() const;
+ bool IsStackableOnOneSlotWithDifferentCasters() const;
bool IsDeathPersistent() const;
bool IsRequiringDeadTarget() const;
bool IsAllowingDeadTarget() const;
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp
index dbd4e3904ea..312189ffad8 100644
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -3371,6 +3371,17 @@ void SpellMgr::LoadDbcDataCorrections()
case 64596: // Cosmic Smash (Algalon the Observer)
spellInfo->rangeIndex = 6; // 100yd
break;
+ case 64014: // Expedition Base Camp Teleport
+ case 64024: // Conservatory Teleport
+ case 64025: // Halls of Invention Teleport
+ case 64028: // Colossal Forge Teleport
+ case 64029: // Shattered Walkway Teleport
+ case 64030: // Antechamber Teleport
+ case 64031: // Scrapyard Teleport
+ case 64032: // Formation Grounds Teleport
+ case 65042: // Prison of Yogg-Saron Teleport
+ spellInfo->EffectImplicitTargetA[0] = TARGET_DEST_DB;
+ break;
// ENDOF ULDUAR SPELLS
//
// TRIAL OF THE CRUSADER SPELLS
@@ -3464,7 +3475,7 @@ void SpellMgr::LoadDbcDataCorrections()
case 71518: // Unholy Infusion Quest Credit (Professor Putricide)
case 72934: // Blood Infusion Quest Credit (Blood-Queen Lana'thel)
case 72289: // Frost Infusion Quest Credit (Sindragosa)
- spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_50000_YARDS; // another missing radius
+ spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_200_YARDS; // another missing radius
break;
case 71708: // Empowered Flare (Blood Prince Council)
case 72785: // Empowered Flare (Blood Prince Council)
diff --git a/src/server/game/Weather/Weather.cpp b/src/server/game/Weather/Weather.cpp
index cd148712b55..64ee188a0d2 100644
--- a/src/server/game/Weather/Weather.cpp
+++ b/src/server/game/Weather/Weather.cpp
@@ -221,6 +221,9 @@ bool Weather::UpdateWeather()
char const* wthstr;
switch (state)
{
+ case WEATHER_STATE_FOG:
+ wthstr = "fog";
+ break;
case WEATHER_STATE_LIGHT_RAIN:
wthstr = "light rain";
break;
diff --git a/src/server/game/Weather/Weather.h b/src/server/game/Weather/Weather.h
index 1fcd822d580..2645d3f2067 100644
--- a/src/server/game/Weather/Weather.h
+++ b/src/server/game/Weather/Weather.h
@@ -46,6 +46,7 @@ struct WeatherData
enum WeatherState
{
WEATHER_STATE_FINE = 0,
+ WEATHER_STATE_FOG = 1,
WEATHER_STATE_LIGHT_RAIN = 3,
WEATHER_STATE_MEDIUM_RAIN = 4,
WEATHER_STATE_HEAVY_RAIN = 5,
diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h
index 30021338c4e..b955af7d863 100644
--- a/src/server/game/World/World.h
+++ b/src/server/game/World/World.h
@@ -733,7 +733,7 @@ class World
void AddCharacterNameData(uint32 guid, std::string const& name, uint8 gender, uint8 race, uint8 playerClass, uint8 level);
void UpdateCharacterNameData(uint32 guid, std::string const& name, uint8 gender = GENDER_NONE, uint8 race = RACE_NONE);
void UpdateCharacterNameDataLevel(uint32 guid, uint8 level);
- void DeleteCharaceterNameData(uint32 guid) { _characterNameDataMap.erase(guid); }
+ void DeleteCharacterNameData(uint32 guid) { _characterNameDataMap.erase(guid); }
bool HasCharacterNameData(uint32 guid) { return _characterNameDataMap.find(guid) != _characterNameDataMap.end(); }
uint32 GetCleaningFlags() const { return m_CleaningFlags; }
diff --git a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_broodlord_lashlayer.cpp b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_broodlord_lashlayer.cpp
index fa1ab5528ca..1303f5c4f58 100644
--- a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_broodlord_lashlayer.cpp
+++ b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_broodlord_lashlayer.cpp
@@ -32,12 +32,20 @@ enum Say
SAY_LEASH = 1,
};
+enum Events
+{
+ EVENT_CLEAVE = 1,
+ EVENT_MORTAL_STRIKE = 2,
+ EVENT_BLAST_WAVE = 3,
+ EVENT_KNOCK_BACK = 4,
+};
+
enum Spells
{
SPELL_CLEAVE = 26350,
- SPELL_BLASTWAVE = 23331,
- SPELL_MORTALSTRIKE = 24573,
- SPELL_KNOCKBACK = 25778
+ SPELL_BLAST_WAVE = 23331,
+ SPELL_MORTAL_STRIKE = 24573,
+ SPELL_KNOCK_BACK = 25778
};
class boss_broodlord : public CreatureScript
@@ -54,17 +62,13 @@ public:
{
boss_broodlordAI(Creature* creature) : ScriptedAI(creature) {}
- uint32 Cleave_Timer;
- uint32 BlastWave_Timer;
- uint32 MortalStrike_Timer;
- uint32 KnockBack_Timer;
-
void Reset()
{
- Cleave_Timer = 8000; // These times are probably wrong
- BlastWave_Timer = 12000;
- MortalStrike_Timer = 20000;
- KnockBack_Timer = 30000;
+ // These timers are probably wrong
+ events.ScheduleEvent(EVENT_CLEAVE, 8000);
+ events.ScheduleEvent(EVENT_BLAST_WAVE, 12000);
+ events.ScheduleEvent(EVENT_MORTAL_STRIKE, 20000);
+ events.ScheduleEvent(EVENT_KNOCK_BACK, 30000);
}
void EnterCombat(Unit* /*who*/)
@@ -78,45 +82,51 @@ public:
if (!UpdateVictim())
return;
- //Cleave_Timer
- if (Cleave_Timer <= diff)
- {
- DoCast(me->getVictim(), SPELL_CLEAVE);
- Cleave_Timer = 7000;
- } else Cleave_Timer -= diff;
-
- // BlastWave
- if (BlastWave_Timer <= diff)
- {
- DoCast(me->getVictim(), SPELL_BLASTWAVE);
- BlastWave_Timer = urand(8000, 16000);
- } else BlastWave_Timer -= diff;
+ if (EnterEvadeIfOutOfCombatArea(diff))
+ Talk(SAY_LEASH);
- //MortalStrike_Timer
- if (MortalStrike_Timer <= diff)
- {
- DoCast(me->getVictim(), SPELL_MORTALSTRIKE);
- MortalStrike_Timer = urand(25000, 35000);
- } else MortalStrike_Timer -= diff;
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
- if (KnockBack_Timer <= diff)
+ while (uint32 eventId = events.ExecuteEvent())
{
- if (Unit* target = me->getVictim())
+ switch (eventId)
{
- DoCast(target, SPELL_KNOCKBACK);
- // Drop 50% aggro
- if (DoGetThreat(target))
- DoModifyThreatPercent(target, -50);
+ case EVENT_CLEAVE:
+ DoCastVictim(SPELL_CLEAVE);
+ events.ScheduleEvent(EVENT_CLEAVE, 8000);
+ break;
+ case EVENT_MORTAL_STRIKE:
+ DoCastVictim(SPELL_MORTAL_STRIKE);
+ events.ScheduleEvent(EVENT_MORTAL_STRIKE, 20000);
+ break;
+ case EVENT_BLAST_WAVE:
+ DoCastVictim(SPELL_BLAST_WAVE);
+ events.ScheduleEvent(EVENT_BLAST_WAVE, 12000);
+ break;
+ case EVENT_KNOCK_BACK:
+ if (Unit* target = me->getVictim())
+ {
+ DoCast(target, SPELL_BLAST_WAVE);
+ // Drop 50% of threat
+ if (DoGetThreat(target))
+ DoModifyThreatPercent(target, -50);
+ }
+ events.ScheduleEvent(EVENT_KNOCK_BACK, 30000);
+ break;
+ default:
+ break;
}
-
- KnockBack_Timer = urand(15000, 30000);
- } else KnockBack_Timer -= diff;
+ }
if (EnterEvadeIfOutOfCombatArea(diff))
Talk(SAY_LEASH);
DoMeleeAttackIfReady();
}
+
+ private:
+ EventMap events; /// @todo: change BWL to instance script and bosses to BossAI
};
};
diff --git a/src/server/scripts/Kalimdor/zone_desolace.cpp b/src/server/scripts/Kalimdor/zone_desolace.cpp
index 8dbeb989140..0c0de93b096 100644
--- a/src/server/scripts/Kalimdor/zone_desolace.cpp
+++ b/src/server/scripts/Kalimdor/zone_desolace.cpp
@@ -109,7 +109,7 @@ public:
}
}
};
-
+
CreatureAI* GetAI(Creature* creature) const
{
return new npc_aged_dying_ancient_kodoAI(creature);
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_queen_lana_thel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_queen_lana_thel.cpp
index ab0c44aa6d0..4b1ccabe682 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_queen_lana_thel.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_queen_lana_thel.cpp
@@ -45,11 +45,13 @@ enum Spells
SPELL_SHROUD_OF_SORROW = 70986,
SPELL_FRENZIED_BLOODTHIRST_VISUAL = 71949,
SPELL_VAMPIRIC_BITE = 71726,
+ SPELL_VAMPIRIC_BITE_DUMMY = 71837,
SPELL_ESSENCE_OF_THE_BLOOD_QUEEN_PLR = 70879,
SPELL_ESSENCE_OF_THE_BLOOD_QUEEN_HEAL = 70872,
SPELL_FRENZIED_BLOODTHIRST = 70877,
SPELL_UNCONTROLLABLE_FRENZY = 70923,
- SPELL_PRESENCE_OF_THE_DARKFALLEN = 71952,
+ SPELL_PRESENCE_OF_THE_DARKFALLEN = 70994,
+ SPELL_PRESENCE_OF_THE_DARKFALLEN_2 = 71952,
SPELL_BLOOD_MIRROR_DAMAGE = 70821,
SPELL_BLOOD_MIRROR_VISUAL = 71510,
SPELL_BLOOD_MIRROR_DUMMY = 70838,
@@ -88,6 +90,7 @@ uint32 const vampireAuras[3][MAX_DIFFICULTY] =
#define ESSENCE_OF_BLOOD_QUEEN_PLR RAID_MODE<uint32>(70879, 71525, 71530, 71531)
#define FRENZIED_BLOODTHIRST RAID_MODE<uint32>(70877, 71474, 70877, 71474)
#define DELIRIOUS_SLASH RAID_MODE<uint32>(71623, 71624, 71625, 71626)
+#define PRESENCE_OF_THE_DARKFALLEN RAID_MODE<uint32>(70994, 71962, 71963, 71964)
enum Events
{
@@ -220,6 +223,7 @@ class boss_blood_queen_lana_thel : public CreatureScript
instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_BLOOD_MIRROR_DUMMY);
instance->DoRemoveAurasDueToSpellOnPlayers(DELIRIOUS_SLASH);
instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_PACT_OF_THE_DARKFALLEN);
+ instance->DoRemoveAurasDueToSpellOnPlayers(PRESENCE_OF_THE_DARKFALLEN);
}
void DoAction(int32 const action)
@@ -357,8 +361,11 @@ class boss_blood_queen_lana_thel : public CreatureScript
{
Unit* target = targets.front();
DoCast(target, SPELL_VAMPIRIC_BITE);
+ DoCastAOE(SPELL_VAMPIRIC_BITE_DUMMY, true);
Talk(SAY_VAMPIRIC_BITE);
_vampires.insert(target->GetGUID());
+ target->CastSpell(target, SPELL_PRESENCE_OF_THE_DARKFALLEN, TRIGGERED_FULL_MASK);
+ target->CastSpell(target, SPELL_PRESENCE_OF_THE_DARKFALLEN_2, TRIGGERED_FULL_MASK);
}
break;
}
@@ -377,9 +384,10 @@ class boss_blood_queen_lana_thel : public CreatureScript
_offtank->CastSpell(me->getVictim(), SPELL_BLOOD_MIRROR_DAMAGE, true);
me->getVictim()->CastSpell(_offtank, SPELL_BLOOD_MIRROR_DUMMY, true);
DoCastVictim(SPELL_BLOOD_MIRROR_VISUAL);
- if (Item* shadowsEdge = _offtank->GetWeaponForAttack(BASE_ATTACK, true))
- if (!_offtank->HasAura(SPELL_THIRST_QUENCHED) && shadowsEdge->GetEntry() == ITEM_SHADOW_S_EDGE && !_offtank->HasAura(SPELL_GUSHING_WOUND))
- _offtank->CastSpell(_offtank, SPELL_GUSHING_WOUND, true);
+ if (Is25ManRaid() && _offtank->GetQuestStatus(QUEST_BLOOD_INFUSION) == QUEST_STATUS_INCOMPLETE &&
+ _offtank->HasAura(SPELL_UNSATED_CRAVING) && !_offtank->HasAura(SPELL_THIRST_QUENCHED) &&
+ !_offtank->HasAura(SPELL_GUSHING_WOUND))
+ _offtank->CastSpell(_offtank, SPELL_GUSHING_WOUND, TRIGGERED_FULL_MASK);
}
}
@@ -396,13 +404,7 @@ class boss_blood_queen_lana_thel : public CreatureScript
{
std::list<Player*> targets;
SelectRandomTarget(false, &targets);
- uint32 targetCount = 2;
- // do not combine these checks! we want it incremented TWICE when both conditions are met
- if (IsHeroic())
- ++targetCount;
- if (Is25ManRaid())
- ++targetCount;
- Trinity::Containers::RandomResizeList<Player*>(targets, targetCount);
+ Trinity::Containers::RandomResizeList(targets, Is25ManRaid() ? 3 : 2);
if (targets.size() > 1)
{
Talk(SAY_PACT_OF_THE_DARKFALLEN);
@@ -554,33 +556,36 @@ class spell_blood_queen_vampiric_bite : public SpellScriptLoader
uint32 spellId = sSpellMgr->GetSpellIdForDifficulty(SPELL_FRENZIED_BLOODTHIRST, GetCaster());
GetCaster()->RemoveAura(spellId, 0, 0, AURA_REMOVE_BY_ENEMY_SPELL);
- GetCaster()->CastSpell(GetCaster(), SPELL_ESSENCE_OF_THE_BLOOD_QUEEN_PLR, true);
- // Presence of the Darkfallen buff on Blood-Queen
- if (GetCaster()->GetMap()->IsHeroic())
- GetCaster()->CastSpell(GetCaster(), SPELL_PRESENCE_OF_THE_DARKFALLEN, true);
+ GetCaster()->CastSpell(GetCaster(), SPELL_ESSENCE_OF_THE_BLOOD_QUEEN_PLR, TRIGGERED_FULL_MASK);
+
// Shadowmourne questline
- if (GetCaster()->ToPlayer()->GetQuestStatus(QUEST_BLOOD_INFUSION) == QUEST_STATUS_INCOMPLETE)
+ if (Aura* aura = GetCaster()->GetAura(SPELL_GUSHING_WOUND))
{
- if (Aura* aura = GetCaster()->GetAura(SPELL_GUSHING_WOUND))
+ if (aura->GetStackAmount() == 3)
{
- if (aura->GetStackAmount() == 3)
- {
- GetCaster()->CastSpell(GetCaster(), SPELL_THIRST_QUENCHED, true);
- GetCaster()->RemoveAura(aura);
- }
- else
- GetCaster()->CastSpell(GetCaster(), SPELL_GUSHING_WOUND, true);
+ GetCaster()->CastSpell(GetCaster(), SPELL_THIRST_QUENCHED, TRIGGERED_FULL_MASK);
+ GetCaster()->RemoveAura(aura);
}
+ else
+ GetCaster()->CastSpell(GetCaster(), SPELL_GUSHING_WOUND, TRIGGERED_FULL_MASK);
}
+
if (InstanceScript* instance = GetCaster()->GetInstanceScript())
if (Creature* bloodQueen = ObjectAccessor::GetCreature(*GetCaster(), instance->GetData64(DATA_BLOOD_QUEEN_LANA_THEL)))
bloodQueen->AI()->SetGUID(GetHitUnit()->GetGUID(), GUID_VAMPIRE);
}
+ void HandlePresence(SpellEffIndex /*effIndex*/)
+ {
+ GetHitUnit()->CastSpell(GetHitUnit(), SPELL_PRESENCE_OF_THE_DARKFALLEN, TRIGGERED_FULL_MASK);
+ GetHitUnit()->CastSpell(GetHitUnit(), SPELL_PRESENCE_OF_THE_DARKFALLEN_2, TRIGGERED_FULL_MASK);
+ }
+
void Register()
{
OnCheckCast += SpellCheckCastFn(spell_blood_queen_vampiric_bite_SpellScript::CheckTarget);
BeforeHit += SpellHitFn(spell_blood_queen_vampiric_bite_SpellScript::OnCast);
+ OnEffectHitTarget += SpellEffectFn(spell_blood_queen_vampiric_bite_SpellScript::HandlePresence, EFFECT_1, SPELL_EFFECT_TRIGGER_SPELL);
}
};
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp
index 1c6ed848158..5c7f575413a 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp
@@ -84,7 +84,9 @@ enum Spells
SPELL_CONCUSSIVE_SHOCK = 71337,
// Frost Infusion
- SPELL_FROST_INFUSION_CREDIT = 72289
+ SPELL_FROST_INFUSION_CREDIT = 72289,
+ SPELL_FROST_IMBUED_BLADE = 72290,
+ SPELL_FROST_INFUSION = 72292,
};
enum Events
@@ -147,11 +149,7 @@ enum MovementPoints
enum Shadowmourne
{
- QUEST_FROST_INFUSION = 24757,
- ITEM_SHADOW_S_EDGE = 49888,
-
- SPELL_FROST_INFUSION = 72292,
- SPELL_FROST_IMBUED_BLADE = 72290,
+ QUEST_FROST_INFUSION = 24757
};
Position const RimefangFlyPos = {4413.309f, 2456.421f, 233.3795f, 2.890186f};
@@ -390,47 +388,10 @@ class boss_sindragosa : public CreatureScript
void SpellHitTarget(Unit* target, SpellInfo const* spell)
{
if (uint32 spellId = sSpellMgr->GetSpellIdForDifficulty(70127, me))
- {
if (spellId == spell->Id)
- {
if (Aura const* mysticBuffet = target->GetAura(spell->Id))
_mysticBuffetStack = std::max<uint8>(_mysticBuffetStack, mysticBuffet->GetStackAmount());
- return;
- }
- }
-
- // Frost Infusion
- if (Player* player = target->ToPlayer())
- {
- if (uint32 spellId = sSpellMgr->GetSpellIdForDifficulty(_isThirdPhase ? SPELL_FROST_BREATH_P2 : SPELL_FROST_BREATH_P1, me))
- {
- if (spellId == spell->Id)
- {
- Item* shadowsEdge = player->GetWeaponForAttack(BASE_ATTACK, true);
- if (player->GetQuestStatus(QUEST_FROST_INFUSION) == QUEST_STATUS_INCOMPLETE && shadowsEdge)
- {
- if (!player->HasAura(SPELL_FROST_IMBUED_BLADE) && shadowsEdge->GetEntry() == ITEM_SHADOW_S_EDGE)
- {
- if (Aura* infusion = player->GetAura(SPELL_FROST_INFUSION))
- {
- if (infusion->GetStackAmount() == 3)
- {
- player->CastSpell(player, SPELL_FROST_IMBUED_BLADE, true);
- player->RemoveAura(infusion);
- }
- else
- player->CastSpell(player, SPELL_FROST_INFUSION, true);
- }
- else
- player->CastSpell(player, SPELL_FROST_INFUSION, true);
- }
- }
-
- return;
- }
- }
- }
}
void UpdateAI(uint32 const diff)
@@ -1155,6 +1116,50 @@ class spell_sindragosa_unchained_magic : public SpellScriptLoader
}
};
+class spell_sindragosa_frost_breath : public SpellScriptLoader
+{
+ public:
+ spell_sindragosa_frost_breath() : SpellScriptLoader("spell_sindragosa_frost_breath") { }
+
+ class spell_sindragosa_frost_breath_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_sindragosa_frost_breath_SpellScript);
+
+ void HandleInfusion()
+ {
+ Player* target = GetHitPlayer();
+ if (!target)
+ return;
+
+ if (target->GetQuestStatus(QUEST_FROST_INFUSION) != QUEST_STATUS_INCOMPLETE)
+ return;
+
+ // Check if player has Shadow's Edge equipped and not ready for infusion
+ if (!target->HasAura(SPELL_UNSATED_CRAVING) || target->HasAura(SPELL_FROST_IMBUED_BLADE))
+ return;
+
+ Aura* infusion = target->GetAura(SPELL_FROST_INFUSION, target->GetGUID());
+ if (infusion && infusion->GetStackAmount() >= 3)
+ {
+ target->RemoveAura(infusion);
+ target->CastSpell(target, SPELL_FROST_IMBUED_BLADE, TRIGGERED_FULL_MASK);
+ }
+ else
+ target->CastSpell(target, SPELL_FROST_INFUSION, TRIGGERED_FULL_MASK);
+ }
+
+ void Register()
+ {
+ AfterHit += SpellHitFn(spell_sindragosa_frost_breath_SpellScript::HandleInfusion);
+ }
+ };
+
+ SpellScript* GetSpellScript() const
+ {
+ return new spell_sindragosa_frost_breath_SpellScript();
+ }
+};
+
class spell_sindragosa_instability : public SpellScriptLoader
{
public:
@@ -1577,6 +1582,7 @@ void AddSC_boss_sindragosa()
new npc_sindragosa_trash();
new spell_sindragosa_s_fury();
new spell_sindragosa_unchained_magic();
+ new spell_sindragosa_frost_breath();
new spell_sindragosa_instability();
new spell_sindragosa_frost_beacon();
new spell_sindragosa_ice_tomb();
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h
index 1407568686f..887a31baf9a 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h
+++ b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h
@@ -56,6 +56,7 @@ enum SharedSpells
SPELL_FROSTMOURNE_TELEPORT_VISUAL = 73078,
// Shadowmourne questline
+ SPELL_UNSATED_CRAVING = 71168,
SPELL_SHADOWS_FATE = 71169
};
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp
index 462708360e3..593d9586156 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp
@@ -435,7 +435,7 @@ class instance_icecrown_citadel : public InstanceMapScript
// these 2 gates are functional only on 25man modes
case GO_DOODAD_ICECROWN_ROOSTPORTCULLIS_01:
case GO_DOODAD_ICECROWN_ROOSTPORTCULLIS_04:
- if (instance->GetSpawnMode() & 1)
+ if (instance->Is25ManRaid())
AddDoor(go, true);
break;
case GO_LADY_DEATHWHISPER_ELEVATOR:
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp
index d3c174841ee..125f66497bf 100644
--- a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp
@@ -565,10 +565,6 @@ class instance_ulduar : public InstanceMapScript
}
HandleGameObject(KologarnBridgeGUID, false);
}
- if (state == IN_PROGRESS)
- HandleGameObject(KologarnDoorGUID, false);
- else
- HandleGameObject(KologarnDoorGUID, true);
break;
case BOSS_HODIR:
if (state == DONE)
diff --git a/src/server/scripts/Northrend/zone_storm_peaks.cpp b/src/server/scripts/Northrend/zone_storm_peaks.cpp
index dae2ffd36f6..d9528446bcf 100644
--- a/src/server/scripts/Northrend/zone_storm_peaks.cpp
+++ b/src/server/scripts/Northrend/zone_storm_peaks.cpp
@@ -356,34 +356,20 @@ public:
enum FreedProtoDrake
{
+ NPC_DRAKE = 29709,
+
AREA_VALLEY_OF_ANCIENT_WINTERS = 4437,
+
TEXT_EMOTE = 0,
+
SPELL_KILL_CREDIT_PRISONER = 55144,
SPELL_SUMMON_LIBERATED = 55073,
- SPELL_KILL_CREDIT_DRAKE = 55143
-};
+ SPELL_KILL_CREDIT_DRAKE = 55143,
-const Position FreedDrakeWaypoints[16] =
-{
- {7294.96f, -2418.733f, 823.869f, 0.0f},
- {7315.984f, -2331.46f, 826.3972f, 0.0f},
- {7271.826f, -2271.479f, 833.5917f, 0.0f},
- {7186.253f, -2218.475f, 847.5632f, 0.0f},
- {7113.195f, -2164.288f, 850.2301f, 0.0f},
- {7078.018f, -2063.106f, 854.7581f, 0.0f},
- {7073.221f, -1983.382f, 861.9246f, 0.0f},
- {7061.455f, -1885.899f, 865.119f, 0.0f},
- {7033.32f, -1826.775f, 876.2578f, 0.0f},
- {6999.902f, -1784.012f, 897.4521f, 0.0f},
- {6954.913f, -1747.043f, 897.4521f, 0.0f},
- {6933.856f, -1720.698f, 882.2022f, 0.0f},
- {6932.729f, -1687.306f, 866.1189f, 0.0f},
- {6952.458f, -1663.802f, 849.8133f, 0.0f},
- {7002.819f, -1651.681f, 831.397f, 0.0f},
- {7026.531f, -1649.239f, 828.8406f, 0.0f}
+ EVENT_CHECK_AREA = 1,
+ EVENT_REACHED_HOME = 2,
};
-
class npc_freed_protodrake : public CreatureScript
{
public:
@@ -393,74 +379,60 @@ public:
{
npc_freed_protodrakeAI(Creature* creature) : VehicleAI(creature) {}
- bool autoMove;
- bool wpReached;
- uint16 CheckTimer;
- uint16 countWP;
+ EventMap events;
void Reset()
{
- autoMove = false;
- wpReached = false;
- CheckTimer = 5000;
- countWP = 0;
+ events.ScheduleEvent(EVENT_CHECK_AREA, 5000);
}
void MovementInform(uint32 type, uint32 id)
{
- if (type != POINT_MOTION_TYPE)
+ if (type != WAYPOINT_MOTION_TYPE)
return;
- if (id < 15)
- {
- ++countWP;
- wpReached = true;
- }
- else
+ if (id == 15)
// drake reached village
- {
- // get player that rides drake (from seat 0)
- Unit* player = me->GetVehicleKit()->GetPassenger(0);
- if (player && player->GetTypeId() == TYPEID_PLAYER)
- {
- // for each prisoner on drake, give credit
- for (uint8 i = 1; i < 4; ++i)
- if (Unit* prisoner = me->GetVehicleKit()->GetPassenger(i))
- {
- if (prisoner->GetTypeId() != TYPEID_UNIT)
- return;
- prisoner->CastSpell(player, SPELL_KILL_CREDIT_PRISONER, true);
- prisoner->CastSpell(prisoner, SPELL_SUMMON_LIBERATED, true);
- prisoner->ExitVehicle();
- }
- me->CastSpell(me, SPELL_KILL_CREDIT_DRAKE, true);
- player->ExitVehicle();
- }
- }
+ events.ScheduleEvent(EVENT_REACHED_HOME, 2000);
}
void UpdateAI(const uint32 diff)
{
- if (!autoMove)
+ events.Update(diff);
+
+ switch (events.ExecuteEvent())
{
- if (CheckTimer < diff)
- {
- CheckTimer = 5000;
+ case EVENT_CHECK_AREA:
if (me->GetAreaId() == AREA_VALLEY_OF_ANCIENT_WINTERS)
{
- Talk(TEXT_EMOTE, me->GetVehicleKit()->GetPassenger(0)->GetGUID());
- autoMove = true;
- wpReached = true;
+ if (Vehicle* vehicle = me->GetVehicleKit())
+ if (Unit* passenger = vehicle->GetPassenger(0))
+ {
+ Talk(TEXT_EMOTE, passenger->GetGUID());
+ me->GetMotionMaster()->MovePath(NPC_DRAKE, false);
+ }
}
- }
- else
- CheckTimer -= diff;
- }
-
- if (wpReached && autoMove)
- {
- wpReached = false;
- me->GetMotionMaster()->MovePoint(countWP, FreedDrakeWaypoints[countWP]);
+ else
+ events.ScheduleEvent(EVENT_CHECK_AREA, 5000);
+ break;
+ case EVENT_REACHED_HOME:
+ Unit* player = me->GetVehicleKit()->GetPassenger(0);
+ if (player && player->GetTypeId() == TYPEID_PLAYER)
+ {
+ // for each prisoner on drake, give credit
+ for (uint8 i = 1; i < 4; ++i)
+ if (Unit* prisoner = me->GetVehicleKit()->GetPassenger(i))
+ {
+ if (prisoner->GetTypeId() != TYPEID_UNIT)
+ return;
+ prisoner->CastSpell(player, SPELL_KILL_CREDIT_PRISONER, true);
+ prisoner->CastSpell(prisoner, SPELL_SUMMON_LIBERATED, true);
+ prisoner->ExitVehicle();
+ }
+ me->CastSpell(me, SPELL_KILL_CREDIT_DRAKE, true);
+ player->ExitVehicle();
+ }
+ break;
}
}
};
diff --git a/src/server/scripts/Spells/spell_item.cpp b/src/server/scripts/Spells/spell_item.cpp
index d57ed6e126b..c9c75cdb134 100644
--- a/src/server/scripts/Spells/spell_item.cpp
+++ b/src/server/scripts/Spells/spell_item.cpp
@@ -813,53 +813,65 @@ class spell_item_scroll_of_recall : public SpellScriptLoader
enum ShadowsFate
{
SPELL_SOUL_FEAST = 71203,
- QUEST_A_FEAST_OF_SOULS = 24547
};
-class spell_item_shadows_fate : public SpellScriptLoader
+class spell_item_unsated_craving : public SpellScriptLoader
{
public:
- spell_item_shadows_fate() : SpellScriptLoader("spell_item_shadows_fate") { }
+ spell_item_unsated_craving() : SpellScriptLoader("spell_item_unsated_craving") { }
- class spell_item_shadows_fate_AuraScript : public AuraScript
+ class spell_item_unsated_craving_AuraScript : public AuraScript
{
- PrepareAuraScript(spell_item_shadows_fate_AuraScript);
+ PrepareAuraScript(spell_item_unsated_craving_AuraScript);
- bool Validate(SpellInfo const* /*spellInfo*/)
+ bool CheckProc(ProcEventInfo& procInfo)
{
- if (!sSpellMgr->GetSpellInfo(SPELL_SOUL_FEAST))
+ Unit* caster = procInfo.GetActor();
+ if (!caster || caster->GetTypeId() != TYPEID_PLAYER)
return false;
- if (!sObjectMgr->GetQuestTemplate(QUEST_A_FEAST_OF_SOULS))
+
+ Unit* target = procInfo.GetActionTarget();
+ if (!target || target->GetTypeId() != TYPEID_UNIT || target->GetCreatureType() == CREATURE_TYPE_CRITTER || target->isSummon())
return false;
- return true;
- }
- bool Load()
- {
- _procTarget = NULL;
return true;
}
- bool CheckProc(ProcEventInfo& /*eventInfo*/)
+ void Register()
{
- _procTarget = GetCaster();
- return _procTarget && _procTarget->GetTypeId() == TYPEID_PLAYER && _procTarget->ToPlayer()->GetQuestStatus(QUEST_A_FEAST_OF_SOULS) == QUEST_STATUS_INCOMPLETE;
+ DoCheckProc += AuraCheckProcFn(spell_item_unsated_craving_AuraScript::CheckProc);
}
+ };
- void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& /*eventInfo*/)
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_item_unsated_craving_AuraScript();
+ }
+};
+
+class spell_item_shadows_fate : public SpellScriptLoader
+{
+ public:
+ spell_item_shadows_fate() : SpellScriptLoader("spell_item_shadows_fate") { }
+
+ class spell_item_shadows_fate_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_item_shadows_fate_AuraScript);
+
+ void HandleProc(ProcEventInfo& procInfo)
{
- PreventDefaultAction();
- GetTarget()->CastSpell(_procTarget, SPELL_SOUL_FEAST, true);
+ Unit* caster = procInfo.GetActor();
+ Unit* target = GetCaster();
+ if (!caster || !target)
+ return;
+
+ caster->CastSpell(target, SPELL_SOUL_FEAST, TRIGGERED_FULL_MASK);
}
void Register()
{
- DoCheckProc += AuraCheckProcFn(spell_item_shadows_fate_AuraScript::CheckProc);
- OnEffectProc += AuraEffectProcFn(spell_item_shadows_fate_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ OnProc += AuraProcFn(spell_item_shadows_fate_AuraScript::HandleProc);
}
-
- private:
- Unit* _procTarget;
};
AuraScript* GetAuraScript() const
@@ -2481,6 +2493,7 @@ void AddSC_item_spell_scripts()
new spell_item_piccolo_of_the_flaming_fire();
new spell_item_savory_deviate_delight();
new spell_item_scroll_of_recall();
+ new spell_item_unsated_craving();
new spell_item_shadows_fate();
new spell_item_shadowmourne();
new spell_item_shadowmourne_soul_fragment();