aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp135
-rw-r--r--src/server/game/Entities/Unit/Unit.h2
-rw-r--r--src/server/game/Entities/Vehicle/Vehicle.cpp9
-rw-r--r--src/server/game/Entities/Vehicle/Vehicle.h2
-rw-r--r--src/server/game/Entities/Vehicle/VehicleDefines.h5
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp36
6 files changed, 120 insertions, 69 deletions
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index a084e76096c..960b402d05b 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -12413,79 +12413,100 @@ void Unit::HandleSpellClick(Unit* clicker, int8 seatId /*= -1*/)
if (!sConditionMgr->IsObjectMeetingSpellClickConditions(spellClickEntry, clickPair.second.spellId, clicker, this))
continue;
- Unit* caster = (clickPair.second.castFlags & NPC_CLICK_CAST_CASTER_CLICKER) ? clicker : this;
- Unit* target = (clickPair.second.castFlags & NPC_CLICK_CAST_TARGET_CLICKER) ? clicker : this;
- ObjectGuid origCasterGUID = (clickPair.second.castFlags & NPC_CLICK_CAST_ORIG_CASTER_OWNER) ? GetOwnerGUID() : clicker->GetGUID();
+ spellClickHandled = HandleSpellClick(clicker, seatId, clickPair.second.spellId, flags, &clickPair.second);
- SpellInfo const* spellEntry = sSpellMgr->AssertSpellInfo(clickPair.second.spellId, caster->GetMap()->GetDifficultyID());
// if (!spellEntry) should be checked at npc_spellclick load
+ }
- SpellCastResult castResult = SPELL_FAILED_SUCCESS;
- if (seatId > -1)
- {
- uint8 i = 0;
- bool valid = false;
- for (SpellEffectInfo const& spellEffectInfo : spellEntry->GetEffects())
- {
- if (spellEffectInfo.ApplyAuraName == SPELL_AURA_CONTROL_VEHICLE)
- {
- valid = true;
- break;
- }
- ++i;
- }
+ Creature* creature = ToCreature();
+ if (creature && creature->IsAIEnabled())
+ creature->AI()->OnSpellClick(clicker, spellClickHandled);
+}
- if (!valid)
- {
- TC_LOG_ERROR("sql.sql", "Spell {} specified in npc_spellclick_spells is not a valid vehicle enter aura!", clickPair.second.spellId);
- continue;
- }
+bool Unit::HandleSpellClick(Unit* clicker, int8 seatId, uint32 spellId, TriggerCastFlags flags /*= TRIGGERED_NONE*/, SpellClickInfo const* spellClickInfo /*= nullptr*/)
+{
+ Unit* caster = clicker;
+ Unit* target = this;
+ ObjectGuid origCasterGUID = caster->GetGUID();
+ SpellCastResult castResult = SPELL_FAILED_SUCCESS;
- if (IsInMap(caster))
- {
- CastSpellExtraArgs args(flags);
- args.OriginalCaster = origCasterGUID;
- args.AddSpellMod(SpellValueMod(SPELLVALUE_BASE_POINT0 + i), seatId + 1);
- castResult = caster->CastSpell(target, clickPair.second.spellId, args);
- }
- else // This can happen during Player::_LoadAuras
- {
- int32 bp[MAX_SPELL_EFFECTS] = { };
- for (SpellEffectInfo const& spellEffectInfo : spellEntry->GetEffects())
- bp[spellEffectInfo.EffectIndex] = int32(spellEffectInfo.BasePoints);
+ if (spellClickInfo)
+ {
+ caster = (spellClickInfo->castFlags & NPC_CLICK_CAST_CASTER_CLICKER) ? clicker : this;
+ target = (spellClickInfo->castFlags & NPC_CLICK_CAST_TARGET_CLICKER) ? clicker : this;
+ origCasterGUID = (spellClickInfo->castFlags & NPC_CLICK_CAST_ORIG_CASTER_OWNER) ? GetOwnerGUID() : clicker->GetGUID();
+ }
- bp[i] = seatId;
+ if (!spellId)
+ {
+ TC_LOG_ERROR("sql.sql", "No valid spell specified for clickee {} and clicker {}!", target->GetGUID(), caster->GetGUID());
+ return false;
+ }
- AuraCreateInfo createInfo(ObjectGuid::Create<HighGuid::Cast>(SPELL_CAST_SOURCE_NORMAL, GetMapId(), spellEntry->Id, GetMap()->GenerateLowGuid<HighGuid::Cast>()), spellEntry, GetMap()->GetDifficultyID(), MAX_EFFECT_MASK, this);
- createInfo
- .SetCaster(clicker)
- .SetBaseAmount(bp)
- .SetCasterGUID(origCasterGUID);
+ SpellInfo const* spellEntry = sSpellMgr->AssertSpellInfo(spellId, caster->GetMap()->GetDifficultyID());
- Aura::TryRefreshStackOrCreate(createInfo);
- }
+ uint8 effectIndex = 0;
+ bool hasControlVehicleAura = false;
+ for (SpellEffectInfo const& spellEffectInfo : spellEntry->GetEffects())
+ {
+ if (spellEffectInfo.ApplyAuraName == SPELL_AURA_CONTROL_VEHICLE)
+ {
+ hasControlVehicleAura = true;
+ break;
}
- else
+ ++effectIndex;
+ }
+
+ if (seatId > -1)
+ {
+ if (!hasControlVehicleAura)
{
- if (IsInMap(caster))
- castResult = caster->CastSpell(target, spellEntry->Id, CastSpellExtraArgs().SetOriginalCaster(origCasterGUID));
+ if (!spellClickInfo)
+ TC_LOG_ERROR("sql.sql", "RideSpell {} specified in vehicle_accessory or vehicle_template_accessory is not a valid vehicle enter aura!", spellId);
else
- {
- AuraCreateInfo createInfo(ObjectGuid::Create<HighGuid::Cast>(SPELL_CAST_SOURCE_NORMAL, GetMapId(), spellEntry->Id, GetMap()->GenerateLowGuid<HighGuid::Cast>()), spellEntry, GetMap()->GetDifficultyID(), MAX_EFFECT_MASK, this);
- createInfo
- .SetCaster(clicker)
- .SetCasterGUID(origCasterGUID);
+ TC_LOG_ERROR("sql.sql", "Spell {} specified in npc_spellclick_spells is not a valid vehicle enter aura!", spellId);
+ return false;
+ }
- Aura::TryRefreshStackOrCreate(createInfo);
- }
+ if (IsInMap(caster))
+ {
+ CastSpellExtraArgs args(flags);
+ args.OriginalCaster = origCasterGUID;
+ args.AddSpellMod(SpellValueMod(SPELLVALUE_BASE_POINT0 + effectIndex), seatId + 1);
+ castResult = caster->CastSpell(target, spellId, args);
}
+ else // This can happen during Player::_LoadAuras
+ {
+ int32 bp[MAX_SPELL_EFFECTS] = { };
+ for (SpellEffectInfo const& spellEffectInfo : spellEntry->GetEffects())
+ bp[spellEffectInfo.EffectIndex] = int32(spellEffectInfo.BasePoints);
- spellClickHandled = castResult == SPELL_FAILED_SUCCESS;
+ bp[effectIndex] = seatId;
+
+ AuraCreateInfo createInfo(ObjectGuid::Create<HighGuid::Cast>(SPELL_CAST_SOURCE_NORMAL, GetMapId(), spellEntry->Id, GetMap()->GenerateLowGuid<HighGuid::Cast>()), spellEntry, GetMap()->GetDifficultyID(), MAX_EFFECT_MASK, this);
+ createInfo
+ .SetCaster(clicker)
+ .SetBaseAmount(bp)
+ .SetCasterGUID(origCasterGUID);
+
+ Aura::TryRefreshStackOrCreate(createInfo);
+ }
}
+ else
+ {
+ if (IsInMap(caster))
+ castResult = caster->CastSpell(target, spellEntry->Id, CastSpellExtraArgs().SetOriginalCaster(origCasterGUID));
+ else
+ {
+ AuraCreateInfo createInfo(ObjectGuid::Create<HighGuid::Cast>(SPELL_CAST_SOURCE_NORMAL, GetMapId(), spellEntry->Id, GetMap()->GenerateLowGuid<HighGuid::Cast>()), spellEntry, GetMap()->GetDifficultyID(), MAX_EFFECT_MASK, this);
+ createInfo
+ .SetCaster(clicker)
+ .SetCasterGUID(origCasterGUID);
- Creature* creature = ToCreature();
- if (creature && creature->IsAIEnabled())
- creature->AI()->OnSpellClick(clicker, spellClickHandled);
+ Aura::TryRefreshStackOrCreate(createInfo);
+ }
+ }
+ return castResult == SPELL_FAILED_SUCCESS;
}
void Unit::EnterVehicle(Unit* base, int8 seatId /*= -1*/)
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index 892ad6666a5..8feedd56904 100644
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -70,6 +70,7 @@ struct FactionTemplateEntry;
struct LiquidData;
struct LiquidTypeEntry;
struct MountCapabilityEntry;
+struct SpellClickInfo;
struct SpellValue;
struct TeleportLocation;
@@ -1751,6 +1752,7 @@ class TC_GAME_API Unit : public WorldObject
TransportBase* GetDirectTransport() const;
void HandleSpellClick(Unit* clicker, int8 seatId = -1);
+ bool HandleSpellClick(Unit* clicker, int8 seatId, uint32 spellId, TriggerCastFlags flags = TRIGGERED_NONE, SpellClickInfo const* spellClickInfo = nullptr);
void EnterVehicle(Unit* base, int8 seatId = -1);
virtual void ExitVehicle(Position const* exitPosition = nullptr);
void ChangeSeat(int8 seatId, bool next = true);
diff --git a/src/server/game/Entities/Vehicle/Vehicle.cpp b/src/server/game/Entities/Vehicle/Vehicle.cpp
index 0b8b3b20af5..25b4931d24a 100644
--- a/src/server/game/Entities/Vehicle/Vehicle.cpp
+++ b/src/server/game/Entities/Vehicle/Vehicle.cpp
@@ -93,7 +93,7 @@ void Vehicle::InstallAllAccessories(bool evading)
for (VehicleAccessoryList::const_iterator itr = accessories->begin(); itr != accessories->end(); ++itr)
if (!evading || itr->IsMinion) // only install minions on evade mode
- InstallAccessory(itr->AccessoryEntry, itr->SeatId, itr->IsMinion, itr->SummonedType, itr->SummonTime);
+ InstallAccessory(itr->AccessoryEntry, itr->SeatId, itr->IsMinion, itr->SummonedType, itr->SummonTime, itr->RideSpellID);
}
/**
@@ -378,7 +378,7 @@ VehicleSeatAddon const* Vehicle::GetSeatAddonForSeatOfPassenger(Unit const* pass
* @param summonTime Time after which the minion is despawned in case of a timed despawn @type specified.
*/
-void Vehicle::InstallAccessory(uint32 entry, int8 seatId, bool minion, uint8 type, uint32 summonTime)
+void Vehicle::InstallAccessory(uint32 entry, int8 seatId, bool minion, uint8 type, uint32 summonTime, Optional<uint32> rideSpellId /*= {}*/)
{
/// @Prevent adding accessories when vehicle is uninstalling. (Bad script in OnUninstall/OnRemovePassenger/PassengerBoarded hook.)
if (_status == STATUS_UNINSTALLING)
@@ -398,7 +398,10 @@ void Vehicle::InstallAccessory(uint32 entry, int8 seatId, bool minion, uint8 typ
if (minion)
accessory->AddUnitTypeMask(UNIT_MASK_ACCESSORY);
- _me->HandleSpellClick(accessory, seatId);
+ if (rideSpellId)
+ _me->HandleSpellClick(accessory, seatId, *rideSpellId);
+ else
+ _me->HandleSpellClick(accessory, seatId);
/// If for some reason adding accessory to vehicle fails it will unsummon in
/// @VehicleJoinEvent::Abort
diff --git a/src/server/game/Entities/Vehicle/Vehicle.h b/src/server/game/Entities/Vehicle/Vehicle.h
index e0ca5e9d632..b46e6f47c13 100644
--- a/src/server/game/Entities/Vehicle/Vehicle.h
+++ b/src/server/game/Entities/Vehicle/Vehicle.h
@@ -44,7 +44,7 @@ class TC_GAME_API Vehicle final : public TransportBase
void Reset(bool evading = false);
void InstallAllAccessories(bool evading);
void ApplyAllImmunities();
- void InstallAccessory(uint32 entry, int8 seatId, bool minion, uint8 type, uint32 summonTime); // May be called from scripts
+ void InstallAccessory(uint32 entry, int8 seatId, bool minion, uint8 type, uint32 summonTime, Optional<uint32> rideSpellId = {}); // May be called from scripts
Unit* GetBase() const { return _me; }
VehicleEntry const* GetVehicleInfo() const { return _vehicleInfo; }
diff --git a/src/server/game/Entities/Vehicle/VehicleDefines.h b/src/server/game/Entities/Vehicle/VehicleDefines.h
index 82261db0f0c..9155f23d1c9 100644
--- a/src/server/game/Entities/Vehicle/VehicleDefines.h
+++ b/src/server/game/Entities/Vehicle/VehicleDefines.h
@@ -131,13 +131,14 @@ struct VehicleSeat
struct VehicleAccessory
{
- VehicleAccessory(uint32 entry, int8 seatId, bool isMinion, uint8 summonType, uint32 summonTime) :
- AccessoryEntry(entry), IsMinion(isMinion), SummonTime(summonTime), SeatId(seatId), SummonedType(summonType) { }
+ VehicleAccessory(uint32 entry, int8 seatId, bool isMinion, uint8 summonType, uint32 summonTime, Optional<uint32> rideSpellID) :
+ AccessoryEntry(entry), IsMinion(isMinion), SummonTime(summonTime), SeatId(seatId), SummonedType(summonType), RideSpellID(rideSpellID) { }
uint32 AccessoryEntry;
bool IsMinion;
uint32 SummonTime;
int8 SeatId;
uint8 SummonedType;
+ Optional<uint32> RideSpellID;
};
struct VehicleTemplate
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index ea45fd3fbb5..1e65ba93062 100644
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -3462,8 +3462,8 @@ void ObjectMgr::LoadVehicleTemplateAccessories()
uint32 count = 0;
- // 0 1 2 3 4 5
- QueryResult result = WorldDatabase.Query("SELECT `entry`, `accessory_entry`, `seat_id`, `minion`, `summontype`, `summontimer` FROM `vehicle_template_accessory`");
+ // 0 1 2 3 4 5 6
+ QueryResult result = WorldDatabase.Query("SELECT `entry`, `accessory_entry`, `seat_id`, `minion`, `summontype`, `summontimer`, `RideSpellID` FROM `vehicle_template_accessory`");
if (!result)
{
@@ -3482,6 +3482,18 @@ void ObjectMgr::LoadVehicleTemplateAccessories()
uint8 summonType = fields[4].GetUInt8();
uint32 summonTimer = fields[5].GetUInt32();
+ Optional<uint32> rideSpellId;
+ if (!fields[6].IsNull())
+ {
+ rideSpellId = fields[6].GetUInt32();
+
+ if (!sSpellMgr->GetSpellInfo(*rideSpellId, DIFFICULTY_NONE))
+ {
+ TC_LOG_ERROR("sql.sql", "Table `vehicle_template_accessory`: rideSpellId {} does not exist for entry {}.", *rideSpellId, entry);
+ continue;
+ }
+ }
+
if (!GetCreatureTemplate(entry))
{
TC_LOG_ERROR("sql.sql", "Table `vehicle_template_accessory`: creature template entry {} does not exist.", entry);
@@ -3500,7 +3512,7 @@ void ObjectMgr::LoadVehicleTemplateAccessories()
continue;
}
- _vehicleTemplateAccessoryStore[entry].push_back(VehicleAccessory(accessory, seatId, isMinion, summonType, summonTimer));
+ _vehicleTemplateAccessoryStore[entry].push_back(VehicleAccessory(accessory, seatId, isMinion, summonType, summonTimer, rideSpellId));
++count;
}
@@ -3552,8 +3564,8 @@ void ObjectMgr::LoadVehicleAccessories()
uint32 count = 0;
- // 0 1 2 3 4 5
- QueryResult result = WorldDatabase.Query("SELECT `guid`, `accessory_entry`, `seat_id`, `minion`, `summontype`, `summontimer` FROM `vehicle_accessory`");
+ // 0 1 2 3 4 5 6
+ QueryResult result = WorldDatabase.Query("SELECT `guid`, `accessory_entry`, `seat_id`, `minion`, `summontype`, `summontimer`, `RideSpellID` FROM `vehicle_accessory`");
if (!result)
{
@@ -3572,13 +3584,25 @@ void ObjectMgr::LoadVehicleAccessories()
uint8 uiSummonType = fields[4].GetUInt8();
uint32 uiSummonTimer= fields[5].GetUInt32();
+ Optional<uint32> rideSpellId;
+ if (!fields[6].IsNull())
+ {
+ rideSpellId = fields[6].GetUInt32();
+
+ if (!sSpellMgr->GetSpellInfo(*rideSpellId, DIFFICULTY_NONE))
+ {
+ TC_LOG_ERROR("sql.sql", "Table `vehicle_accessory`: rideSpellId {} does not exist for guid {}.", *rideSpellId, uiGUID);
+ continue;
+ }
+ }
+
if (!GetCreatureTemplate(uiAccessory))
{
TC_LOG_ERROR("sql.sql", "Table `vehicle_accessory`: Accessory {} does not exist.", uiAccessory);
continue;
}
- _vehicleAccessoryStore[uiGUID].push_back(VehicleAccessory(uiAccessory, uiSeat, bMinion, uiSummonType, uiSummonTimer));
+ _vehicleAccessoryStore[uiGUID].push_back(VehicleAccessory(uiAccessory, uiSeat, bMinion, uiSummonType, uiSummonTimer, rideSpellId));
++count;
}