diff options
Diffstat (limited to 'src')
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(); |