diff options
author | ModoX <moardox@gmail.com> | 2025-02-02 00:42:51 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-02-02 00:42:51 +0100 |
commit | 46251b56553b610588eea89b83b4b4e8b88e47da (patch) | |
tree | 4baba8dfe266f894cf85d759eaf182882969a0cd /src | |
parent | fa75f796d5f8a5e8f51a32ea36ee11beb541eb06 (diff) |
Core/Vehicle: Added RideSpellID field to override npc_spellclick_spells (#30198)
Diffstat (limited to 'src')
-rw-r--r-- | src/server/game/Entities/Unit/Unit.cpp | 135 | ||||
-rw-r--r-- | src/server/game/Entities/Unit/Unit.h | 2 | ||||
-rw-r--r-- | src/server/game/Entities/Vehicle/Vehicle.cpp | 9 | ||||
-rw-r--r-- | src/server/game/Entities/Vehicle/Vehicle.h | 2 | ||||
-rw-r--r-- | src/server/game/Entities/Vehicle/VehicleDefines.h | 5 | ||||
-rw-r--r-- | src/server/game/Globals/ObjectMgr.cpp | 36 |
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; } |