Core/Vehicle: Added RideSpellID field to override npc_spellclick_spells (#30198)
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE `vehicle_template_accessory` ADD COLUMN `RideSpellID` int NULL AFTER `summontimer`;
|
||||
ALTER TABLE `vehicle_accessory` ADD COLUMN `RideSpellID` int NULL AFTER `summontimer`;
|
||||
@@ -12413,74 +12413,9 @@ 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;
|
||||
}
|
||||
|
||||
if (!valid)
|
||||
{
|
||||
TC_LOG_ERROR("sql.sql", "Spell {} specified in npc_spellclick_spells is not a valid vehicle enter aura!", clickPair.second.spellId);
|
||||
continue;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
bp[i] = 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);
|
||||
|
||||
Aura::TryRefreshStackOrCreate(createInfo);
|
||||
}
|
||||
}
|
||||
|
||||
spellClickHandled = castResult == SPELL_FAILED_SUCCESS;
|
||||
}
|
||||
|
||||
Creature* creature = ToCreature();
|
||||
@@ -12488,6 +12423,92 @@ void Unit::HandleSpellClick(Unit* clicker, int8 seatId /*= -1*/)
|
||||
creature->AI()->OnSpellClick(clicker, spellClickHandled);
|
||||
}
|
||||
|
||||
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 (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();
|
||||
}
|
||||
|
||||
if (!spellId)
|
||||
{
|
||||
TC_LOG_ERROR("sql.sql", "No valid spell specified for clickee {} and clicker {}!", target->GetGUID(), caster->GetGUID());
|
||||
return false;
|
||||
}
|
||||
|
||||
SpellInfo const* spellEntry = sSpellMgr->AssertSpellInfo(spellId, caster->GetMap()->GetDifficultyID());
|
||||
|
||||
uint8 effectIndex = 0;
|
||||
bool hasControlVehicleAura = false;
|
||||
for (SpellEffectInfo const& spellEffectInfo : spellEntry->GetEffects())
|
||||
{
|
||||
if (spellEffectInfo.ApplyAuraName == SPELL_AURA_CONTROL_VEHICLE)
|
||||
{
|
||||
hasControlVehicleAura = true;
|
||||
break;
|
||||
}
|
||||
++effectIndex;
|
||||
}
|
||||
|
||||
if (seatId > -1)
|
||||
{
|
||||
if (!hasControlVehicleAura)
|
||||
{
|
||||
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
|
||||
TC_LOG_ERROR("sql.sql", "Spell {} specified in npc_spellclick_spells is not a valid vehicle enter aura!", spellId);
|
||||
return false;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
Aura::TryRefreshStackOrCreate(createInfo);
|
||||
}
|
||||
}
|
||||
return castResult == SPELL_FAILED_SUCCESS;
|
||||
}
|
||||
|
||||
void Unit::EnterVehicle(Unit* base, int8 seatId /*= -1*/)
|
||||
{
|
||||
CastSpellExtraArgs args(TRIGGERED_IGNORE_CASTER_MOUNTED_OR_ON_VEHICLE);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user