aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/server/game/Entities/Unit/Unit.h2
-rwxr-xr-xsrc/server/game/Entities/Vehicle/Vehicle.cpp178
-rw-r--r--src/server/game/Entities/Vehicle/Vehicle.h27
3 files changed, 139 insertions, 68 deletions
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..b6e47f239db 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(), (int32)seat->first);
+ VehicleJoinEvent* e = new VehicleJoinEvent(this, unit, seat);
+ 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,13 +351,19 @@ bool Vehicle::AddPassenger(Unit* unit, int8 seatId)
break;
if (seat == Seats.end()) // no available seat
+ {
+ CancelJoinEvent(e);
return false;
+ }
}
else
{
seat = Seats.find(seatId);
if (seat == Seats.end())
+ {
+ CancelJoinEvent(e);
return false;
+ }
if (seat->second.Passenger)
{
@@ -344,65 +376,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 +392,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 +522,78 @@ 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);
+
+ 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)
+{
+ Passenger->m_vehicle = NULL;
+}
diff --git a/src/server/game/Entities/Vehicle/Vehicle.h b/src/server/game/Entities/Vehicle/Vehicle.h
index 823fb72b8a8..f8fa7f9b64a 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, SeatMap::iterator& itr) : Target(v), Passenger(u), Seat(itr) {}
+ bool Execute(uint64, uint32);
+ void Abort(uint64);
+
+ Vehicle* Target;
+ Unit* Passenger;
+ SeatMap::iterator& Seat;
};
#endif