mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-17 16:10:49 +01:00
Core/Spells: Allow free casting of player's own spells on vehicle seats with flag VEHICLE_SEAT_FLAG_CAN_ATTACK
This commit is contained in:
@@ -575,6 +575,26 @@ void Vehicle::Dismiss()
|
||||
GetBase()->ToCreature()->DespawnOrUnsummon();
|
||||
}
|
||||
|
||||
/**
|
||||
* @fn bool Vehicle::IsVehicleInUse() const
|
||||
*
|
||||
* @brief Returns information whether the vehicle is currently used by any unit
|
||||
*
|
||||
* @author Shauren
|
||||
* @date 26-2-2013
|
||||
*
|
||||
* @return true if any passenger is boarded on vehicle, false otherwise.
|
||||
*/
|
||||
|
||||
bool Vehicle::IsVehicleInUse() const
|
||||
{
|
||||
for (SeatMap::const_iterator itr = Seats.begin(); itr != Seats.end(); ++itr)
|
||||
if (itr->second.Passenger)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @fn void Vehicle::InitMovementInfoForBase()
|
||||
*
|
||||
@@ -613,7 +633,7 @@ void Vehicle::InitMovementInfoForBase()
|
||||
* @return null if passenger not found on vehicle, else the DBC record for the seat.
|
||||
*/
|
||||
|
||||
VehicleSeatEntry const* Vehicle::GetSeatForPassenger(Unit* passenger)
|
||||
VehicleSeatEntry const* Vehicle::GetSeatForPassenger(Unit const* passenger)
|
||||
{
|
||||
SeatMap::iterator itr;
|
||||
for (itr = Seats.begin(); itr != Seats.end(); ++itr)
|
||||
|
||||
@@ -63,14 +63,14 @@ class Vehicle : public TransportBase
|
||||
void RelocatePassengers();
|
||||
void RemoveAllPassengers();
|
||||
void Dismiss();
|
||||
bool IsVehicleInUse() { return Seats.begin() != Seats.end(); }
|
||||
bool IsVehicleInUse() const;
|
||||
|
||||
void SetLastShootPos(Position const& pos) { _lastShootPos.Relocate(pos); }
|
||||
Position GetLastShootPos() { return _lastShootPos; }
|
||||
Position const& GetLastShootPos() const { return _lastShootPos; }
|
||||
|
||||
SeatMap Seats; ///< The collection of all seats on the vehicle. Including vacant ones.
|
||||
|
||||
VehicleSeatEntry const* GetSeatForPassenger(Unit* passenger);
|
||||
VehicleSeatEntry const* GetSeatForPassenger(Unit const* passenger);
|
||||
|
||||
protected:
|
||||
friend class VehicleJoinEvent;
|
||||
|
||||
@@ -320,7 +320,6 @@ void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket)
|
||||
}
|
||||
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
|
||||
|
||||
if (!spellInfo)
|
||||
{
|
||||
sLog->outError(LOG_FILTER_NETWORKIO, "WORLD: unknown spell id %u", spellId);
|
||||
@@ -328,31 +327,37 @@ void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket)
|
||||
return;
|
||||
}
|
||||
|
||||
if (mover->GetTypeId() == TYPEID_PLAYER)
|
||||
if (spellInfo->IsPassive())
|
||||
{
|
||||
// not have spell in spellbook or spell passive and not casted by client
|
||||
if (!mover->ToPlayer()->HasActiveSpell (spellId) || spellInfo->IsPassive())
|
||||
{
|
||||
//cheater? kick? ban?
|
||||
recvPacket.rfinish(); // prevent spam at ignore packet
|
||||
return;
|
||||
}
|
||||
recvPacket.rfinish(); // prevent spam at ignore packet
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
||||
Unit* caster = mover;
|
||||
if (caster->GetTypeId() == TYPEID_UNIT && !caster->ToCreature()->HasSpell(spellId))
|
||||
{
|
||||
// not have spell in spellbook or spell passive and not casted by client
|
||||
if ((mover->GetTypeId() == TYPEID_UNIT && !mover->ToCreature()->HasSpell(spellId)) || spellInfo->IsPassive())
|
||||
// If the vehicle creature does not have the spell but it allows the passenger to cast own spells
|
||||
// change caster to player and let him cast
|
||||
if (!_player->IsOnVehicle(caster) || spellInfo->CheckVehicle(_player) != SPELL_CAST_OK)
|
||||
{
|
||||
//cheater? kick? ban?
|
||||
recvPacket.rfinish(); // prevent spam at ignore packet
|
||||
return;
|
||||
}
|
||||
|
||||
caster = _player;
|
||||
}
|
||||
|
||||
if (caster->GetTypeId() == TYPEID_PLAYER && !caster->ToPlayer()->HasActiveSpell(spellId))
|
||||
{
|
||||
// not have spell in spellbook
|
||||
recvPacket.rfinish(); // prevent spam at ignore packet
|
||||
return;
|
||||
}
|
||||
|
||||
// Client is resending autoshot cast opcode when other spell is casted during shoot rotation
|
||||
// Skip it to prevent "interrupt" message
|
||||
if (spellInfo->IsAutoRepeatRangedSpell() && _player->GetCurrentSpell(CURRENT_AUTOREPEAT_SPELL)
|
||||
&& _player->GetCurrentSpell(CURRENT_AUTOREPEAT_SPELL)->m_spellInfo == spellInfo)
|
||||
if (spellInfo->IsAutoRepeatRangedSpell() && caster->GetCurrentSpell(CURRENT_AUTOREPEAT_SPELL)
|
||||
&& caster->GetCurrentSpell(CURRENT_AUTOREPEAT_SPELL)->m_spellInfo == spellInfo)
|
||||
{
|
||||
recvPacket.rfinish();
|
||||
return;
|
||||
@@ -367,7 +372,7 @@ void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket)
|
||||
|
||||
// client provided targets
|
||||
SpellCastTargets targets;
|
||||
targets.Read(recvPacket, mover);
|
||||
targets.Read(recvPacket, caster);
|
||||
HandleClientCastFlags(recvPacket, castFlags, targets);
|
||||
|
||||
// auto-selection buff level base at target level (in spellInfo)
|
||||
@@ -380,7 +385,7 @@ void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket)
|
||||
spellInfo = actualSpellInfo;
|
||||
}
|
||||
|
||||
Spell* spell = new Spell(mover, spellInfo, TRIGGERED_NONE, 0, false);
|
||||
Spell* spell = new Spell(caster, spellInfo, TRIGGERED_NONE, 0, false);
|
||||
spell->m_cast_count = castCount; // set count of casts
|
||||
spell->prepare(&targets);
|
||||
}
|
||||
|
||||
@@ -4832,34 +4832,12 @@ SpellCastResult Spell::CheckCast(bool strict)
|
||||
return SPELL_FAILED_MOVING;
|
||||
}
|
||||
|
||||
|
||||
Vehicle* vehicle = m_caster->GetVehicle();
|
||||
if (vehicle && !(_triggeredCastFlags & TRIGGERED_IGNORE_CASTER_MOUNTED_OR_ON_VEHICLE))
|
||||
// Check vehicle flags
|
||||
if (!(_triggeredCastFlags & TRIGGERED_IGNORE_CASTER_MOUNTED_OR_ON_VEHICLE))
|
||||
{
|
||||
uint16 checkMask = 0;
|
||||
for (uint8 effIndex = EFFECT_0; effIndex < MAX_SPELL_EFFECTS; ++effIndex)
|
||||
{
|
||||
SpellEffectInfo const* effInfo = &m_spellInfo->Effects[effIndex];
|
||||
if (effInfo->ApplyAuraName == SPELL_AURA_MOD_SHAPESHIFT)
|
||||
{
|
||||
SpellShapeshiftEntry const* shapeShiftEntry = sSpellShapeshiftStore.LookupEntry(effInfo->MiscValue);
|
||||
if (shapeShiftEntry && (shapeShiftEntry->flags1 & 1) == 0) // unk flag
|
||||
checkMask |= VEHICLE_SEAT_FLAG_UNCONTROLLED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_spellInfo->HasAura(SPELL_AURA_MOUNTED))
|
||||
checkMask |= VEHICLE_SEAT_FLAG_CAN_CAST_MOUNT_SPELL;
|
||||
|
||||
if (!checkMask)
|
||||
checkMask = VEHICLE_SEAT_FLAG_CAN_ATTACK;
|
||||
|
||||
// All creatures should be able to cast as passengers freely, restriction and attribute are only for players
|
||||
VehicleSeatEntry const* vehicleSeat = vehicle->GetSeatForPassenger(m_caster);
|
||||
if (!(m_spellInfo->AttributesEx6 & SPELL_ATTR6_CASTABLE_WHILE_ON_VEHICLE) && !(m_spellInfo->Attributes & SPELL_ATTR0_CASTABLE_WHILE_MOUNTED)
|
||||
&& (vehicleSeat->m_flags & checkMask) != checkMask && m_caster->GetTypeId() == TYPEID_PLAYER)
|
||||
return SPELL_FAILED_DONT_REPORT;
|
||||
SpellCastResult vehicleCheck = m_spellInfo->CheckVehicle(m_caster);
|
||||
if (vehicleCheck != SPELL_CAST_OK)
|
||||
return vehicleCheck;
|
||||
}
|
||||
|
||||
// check spell cast conditions from database
|
||||
@@ -7167,7 +7145,7 @@ bool Spell::CheckScriptEffectImplicitTargets(uint32 effIndex, uint32 effIndexToC
|
||||
if (((*targetSelectHookItr).IsEffectAffected(m_spellInfo, effIndex) && !(*targetSelectHookItr).IsEffectAffected(m_spellInfo, effIndexToCheck)) ||
|
||||
(!(*targetSelectHookItr).IsEffectAffected(m_spellInfo, effIndex) && (*targetSelectHookItr).IsEffectAffected(m_spellInfo, effIndexToCheck)))
|
||||
return false;
|
||||
|
||||
|
||||
std::list<SpellScript::ObjectAreaTargetSelectHandler>::iterator areaTargetSelectHookEnd = (*itr)->OnObjectAreaTargetSelect.end(), areaTargetSelectHookItr = (*itr)->OnObjectAreaTargetSelect.begin();
|
||||
for (; areaTargetSelectHookItr != areaTargetSelectHookEnd; ++areaTargetSelectHookItr)
|
||||
if (((*areaTargetSelectHookItr).IsEffectAffected(m_spellInfo, effIndex) && !(*areaTargetSelectHookItr).IsEffectAffected(m_spellInfo, effIndexToCheck)) ||
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "ConditionMgr.h"
|
||||
#include "Player.h"
|
||||
#include "Battleground.h"
|
||||
#include "Vehicle.h"
|
||||
|
||||
uint32 GetTargetFlagMask(SpellTargetObjectTypes objType)
|
||||
{
|
||||
@@ -1614,6 +1615,56 @@ SpellCastResult SpellInfo::CheckExplicitTarget(Unit const* caster, WorldObject c
|
||||
return SPELL_CAST_OK;
|
||||
}
|
||||
|
||||
SpellCastResult SpellInfo::CheckVehicle(Unit const* caster) const
|
||||
{
|
||||
// All creatures should be able to cast as passengers freely, restriction and attribute are only for players
|
||||
if (caster->GetTypeId() != TYPEID_PLAYER)
|
||||
return SPELL_CAST_OK;
|
||||
|
||||
Vehicle* vehicle = caster->GetVehicle();
|
||||
if (vehicle)
|
||||
{
|
||||
uint16 checkMask = 0;
|
||||
for (uint8 effIndex = EFFECT_0; effIndex < MAX_SPELL_EFFECTS; ++effIndex)
|
||||
{
|
||||
if (Effects[effIndex].ApplyAuraName == SPELL_AURA_MOD_SHAPESHIFT)
|
||||
{
|
||||
SpellShapeshiftEntry const* shapeShiftEntry = sSpellShapeshiftStore.LookupEntry(Effects[effIndex].MiscValue);
|
||||
if (shapeShiftEntry && (shapeShiftEntry->flags1 & 1) == 0) // unk flag
|
||||
checkMask |= VEHICLE_SEAT_FLAG_UNCONTROLLED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (HasAura(SPELL_AURA_MOUNTED))
|
||||
checkMask |= VEHICLE_SEAT_FLAG_CAN_CAST_MOUNT_SPELL;
|
||||
|
||||
if (!checkMask)
|
||||
checkMask = VEHICLE_SEAT_FLAG_CAN_ATTACK;
|
||||
|
||||
VehicleSeatEntry const* vehicleSeat = vehicle->GetSeatForPassenger(caster);
|
||||
if (!(AttributesEx6 & SPELL_ATTR6_CASTABLE_WHILE_ON_VEHICLE) && !(Attributes & SPELL_ATTR0_CASTABLE_WHILE_MOUNTED)
|
||||
&& (vehicleSeat->m_flags & checkMask) != checkMask)
|
||||
return SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW;
|
||||
|
||||
// Can only summon uncontrolled minions/guardians when on controlled vehicle
|
||||
if (vehicleSeat->m_flags & (VEHICLE_SEAT_FLAG_CAN_CONTROL | VEHICLE_SEAT_FLAG_UNK2))
|
||||
{
|
||||
for (uint32 i = EFFECT_0; i < MAX_SPELL_EFFECTS; ++i)
|
||||
{
|
||||
if (Effects[i].Effect != SPELL_EFFECT_SUMMON)
|
||||
continue;
|
||||
|
||||
SummonPropertiesEntry const* props = sSummonPropertiesStore.LookupEntry(Effects[i].MiscValueB);
|
||||
if (props && props->Category != SUMMON_CATEGORY_WILD)
|
||||
return SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return SPELL_CAST_OK;
|
||||
}
|
||||
|
||||
bool SpellInfo::CheckTargetCreatureType(Unit const* target) const
|
||||
{
|
||||
// Curse of Doom & Exorcism: not find another way to fix spell target check :/
|
||||
|
||||
@@ -420,6 +420,7 @@ public:
|
||||
SpellCastResult CheckLocation(uint32 map_id, uint32 zone_id, uint32 area_id, Player const* player = NULL) const;
|
||||
SpellCastResult CheckTarget(Unit const* caster, WorldObject const* target, bool implicit = true) const;
|
||||
SpellCastResult CheckExplicitTarget(Unit const* caster, WorldObject const* target, Item const* itemTarget = NULL) const;
|
||||
SpellCastResult CheckVehicle(Unit const* caster) const;
|
||||
bool CheckTargetCreatureType(Unit const* target) const;
|
||||
|
||||
SpellSchoolMask GetSchoolMask() const;
|
||||
|
||||
Reference in New Issue
Block a user