diff --git a/Source/Framework/Constants/VehicleConst.cs b/Source/Framework/Constants/VehicleConst.cs index aac5d0cb2..e000fcb07 100644 --- a/Source/Framework/Constants/VehicleConst.cs +++ b/Source/Framework/Constants/VehicleConst.cs @@ -61,4 +61,12 @@ namespace Framework.Constants AdjustAimPower = 0x800, // LuaIsvehicleaimpoweradjustable FixedPosition = 0x200000 // Used for cannons, when they should be rooted } + + public enum VehicleExitParameters + { + VehicleExitParamNone = 0, // provided parameters will be ignored + VehicleExitParamOffset = 1, // provided parameters will be used as offset values + VehicleExitParamDest = 2, // provided parameters will be used as absolute destination + VehicleExitParamMax + } } diff --git a/Source/Game/Entities/Unit/Unit.cs b/Source/Game/Entities/Unit/Unit.cs index ad3fdab02..61eb2fc24 100644 --- a/Source/Game/Entities/Unit/Unit.cs +++ b/Source/Game/Entities/Unit/Unit.cs @@ -1025,6 +1025,7 @@ namespace Game.Entities return; // This should be done before dismiss, because there may be some aura removal + VehicleSeatAddon seatAddon = m_vehicle.GetSeatAddonForSeatOfPassenger(this); Vehicle vehicle = m_vehicle.RemovePassenger(this); Player player = ToPlayer(); @@ -1049,7 +1050,18 @@ namespace Game.Entities // Set exit position to vehicle position and use the current orientation pos = vehicle.GetBase().GetPosition(); pos.SetOrientation(GetOrientation()); + + // To-do: snap this hook out of existance Global.ScriptMgr.ModifyVehiclePassengerExitPos(this, vehicle, pos); + + // Change exit position based on seat entry addon data + if (seatAddon != null) + { + if (seatAddon.ExitParameter == VehicleExitParameters.VehicleExitParamOffset) + pos.RelocateOffset(new Position(seatAddon.ExitParameterX, seatAddon.ExitParameterY, seatAddon.ExitParameterZ, seatAddon.ExitParameterO)); + else if (seatAddon.ExitParameter == VehicleExitParameters.VehicleExitParamDest) + pos.Relocate(new Position(seatAddon.ExitParameterX, seatAddon.ExitParameterY, seatAddon.ExitParameterZ, seatAddon.ExitParameterO)); + } } float height = pos.GetPositionZ() + vehicle.GetBase().GetCollisionHeight(); diff --git a/Source/Game/Entities/Vehicle.cs b/Source/Game/Entities/Vehicle.cs index c7115ab61..b02e009c6 100644 --- a/Source/Game/Entities/Vehicle.cs +++ b/Source/Game/Entities/Vehicle.cs @@ -45,7 +45,8 @@ namespace Game.Entities VehicleSeatRecord veSeat = CliDB.VehicleSeatStorage.LookupByKey(seatId); if (veSeat != null) { - Seats.Add((sbyte)i, new VehicleSeat(veSeat)); + VehicleSeatAddon addon = Global.ObjectMgr.GetVehicleSeatAddon(seatId); + Seats.Add((sbyte)i, new VehicleSeat(veSeat, addon)); if (veSeat.CanEnterOrExit()) ++UsableSeatNum; } @@ -253,6 +254,20 @@ namespace Game.Entities return seat; } + /// + /// Gets the vehicle seat addon data for the seat of a passenger + /// + /// Identifier for the current seat user + /// The seat addon data for the currently used seat of a passenger + public VehicleSeatAddon GetSeatAddonForSeatOfPassenger(Unit passenger) + { + foreach (var pair in Seats) + if (!pair.Value.IsEmpty() && pair.Value.Passenger.Guid == passenger.GetGUID()) + return pair.Value.SeatAddon; + + return null; + } + void InstallAccessory(uint entry, sbyte seatId, bool minion, byte type, uint summonTime) { // @Prevent adding accessories when vehicle is uninstalling. (Bad script in OnUninstall/OnRemovePassenger/PassengerBoarded hook.) @@ -625,6 +640,7 @@ namespace Game.Entities Passenger.RemoveAurasByType(AuraType.Mounted); VehicleSeatRecord veSeat = Seat.Value.SeatInfo; + VehicleSeatAddon veSeatAddon = Seat.Value.SeatAddon; Player player = Passenger.ToPlayer(); if (player != null) @@ -644,10 +660,12 @@ namespace Game.Entities if (veSeat.HasFlag(VehicleSeatFlags.DisableGravity)) Passenger.SetDisableGravity(true); - if (Seat.Value.SeatInfo.HasFlag(VehicleSeatFlags.PassengerNotSelectable)) - Passenger.AddUnitFlag(UnitFlags.NotSelectable); + float o = veSeatAddon != null ? veSeatAddon.SeatOrientationOffset : 0.0f; + float x = veSeat.AttachmentOffset.X; + float y = veSeat.AttachmentOffset.Y; + float z = veSeat.AttachmentOffset.Z; - Passenger.m_movementInfo.transport.pos.Relocate(veSeat.AttachmentOffset.X, veSeat.AttachmentOffset.Y, veSeat.AttachmentOffset.Z); + Passenger.m_movementInfo.transport.pos.Relocate(x, y, z, o); Passenger.m_movementInfo.transport.time = 0; Passenger.m_movementInfo.transport.seat = Seat.Key; Passenger.m_movementInfo.transport.guid = Target.GetBase().GetGUID(); @@ -669,8 +687,8 @@ namespace Game.Entities MoveSplineInit init = new(Passenger); init.DisableTransportPathTransformations(); - init.MoveTo(veSeat.AttachmentOffset.X, veSeat.AttachmentOffset.Y, veSeat.AttachmentOffset.Z, false, true); - init.SetFacing(0.0f); + init.MoveTo(x, y, z, false, true); + init.SetFacing(o); init.SetTransportEnter(); Passenger.GetMotionMaster().LaunchMoveSpline(init, EventId.VehicleBoard, MovementGeneratorPriority.Highest); @@ -736,15 +754,17 @@ namespace Game.Entities public class VehicleSeat { - public VehicleSeat(VehicleSeatRecord seatInfo) + public VehicleSeat(VehicleSeatRecord seatInfo, VehicleSeatAddon seatAddon) { SeatInfo = seatInfo; + SeatAddon = seatAddon; Passenger.Reset(); } public bool IsEmpty() { return Passenger.Guid.IsEmpty(); } public VehicleSeatRecord SeatInfo; + public VehicleSeatAddon SeatAddon; public PassengerInfo Passenger; } @@ -769,4 +789,24 @@ namespace Game.Entities { public TimeSpan DespawnDelay; } + + public class VehicleSeatAddon + { + public float SeatOrientationOffset; + public float ExitParameterX; + public float ExitParameterY; + public float ExitParameterZ; + public float ExitParameterO; + public VehicleExitParameters ExitParameter; + + public VehicleSeatAddon(float orientatonOffset, float exitX, float exitY, float exitZ, float exitO, byte param) + { + SeatOrientationOffset = orientatonOffset; + ExitParameterX = exitX; + ExitParameterY = exitY; + ExitParameterZ = exitZ; + ExitParameterO = exitO; + ExitParameter = (VehicleExitParameters)param; + } + } } diff --git a/Source/Game/Globals/ObjectManager.cs b/Source/Game/Globals/ObjectManager.cs index 61f743df0..81b291f00 100644 --- a/Source/Game/Globals/ObjectManager.cs +++ b/Source/Game/Globals/ObjectManager.cs @@ -10505,7 +10505,6 @@ namespace Game Log.outInfo(LogFilter.ServerLoading, "Loaded {0} Vehicle Template Accessories in {1} ms", count, Time.GetMSTimeDiffToNow(oldMSTime)); } - public void LoadVehicleAccessories() { uint oldMSTime = Time.GetMSTime(); @@ -10546,6 +10545,57 @@ namespace Game Log.outInfo(LogFilter.ServerLoading, "Loaded {0} Vehicle Accessories in {1} ms", count, Time.GetMSTimeDiffToNow(oldMSTime)); } + public void LoadVehicleSeatAddon() + { + uint oldMSTime = Time.GetMSTime(); + + _vehicleSeatAddonStore.Clear(); // needed for reload case + + // 0 1 2 3 4 5 6 + SQLResult result = DB.World.Query("SELECT `SeatEntry`, `SeatOrientation`, `ExitParamX`, `ExitParamY`, `ExitParamZ`, `ExitParamO`, `ExitParamValue` FROM `vehicle_seat_addon`"); + if (result.IsEmpty()) + { + Log.outError(LogFilter.ServerLoading, "Loaded 0 vehicle seat addons. DB table `vehicle_seat_addon` is empty."); + return; + } + + uint count = 0; + do + { + uint seatID = result.Read(0); + float orientation = result.Read(1); + float exitX = result.Read(2); + float exitY = result.Read(3); + float exitZ = result.Read(4); + float exitO = result.Read(5); + byte exitParam = result.Read(6); + + if (!CliDB.VehicleSeatStorage.ContainsKey(seatID)) + { + Log.outError(LogFilter.Sql, $"Table `vehicle_seat_addon`: SeatID: {seatID} does not exist in VehicleSeat.dbc. Skipping entry."); + continue; + } + + // Sanitizing values + if (orientation > MathF.PI * 2) + { + Log.outError(LogFilter.Sql, $"Table `vehicle_seat_addon`: SeatID: {seatID} is using invalid angle offset value ({orientation}). Set Value to 0."); + orientation = 0.0f; + } + + if (exitParam >= (byte)VehicleExitParameters.VehicleExitParamMax) + { + Log.outError(LogFilter.Sql, $"Table `vehicle_seat_addon`: SeatID: {seatID} is using invalid exit parameter value ({exitParam}). Setting to 0 (none)."); + continue; + } + + _vehicleSeatAddonStore[seatID] = new VehicleSeatAddon(orientation, exitX, exitY, exitZ, exitO, exitParam); + + ++count; + } while (result.NextRow()); + + Log.outInfo(LogFilter.ServerLoading, $"Loaded {count} Vehicle Seat Addon entries in {Time.GetMSTimeDiffToNow(oldMSTime)} ms"); + } public VehicleTemplate GetVehicleTemplate(Vehicle veh) { @@ -10565,7 +10615,11 @@ namespace Game // Otherwise return entry-based return _vehicleTemplateAccessoryStore.LookupByKey(veh.GetCreatureEntry()); } - + public VehicleSeatAddon GetVehicleSeatAddon(uint seatId) + { + return _vehicleSeatAddonStore.LookupByKey(seatId); + } + #region Fields //General Dictionary CypherStringStorage = new(); @@ -10684,6 +10738,7 @@ namespace Game Dictionary _vehicleTemplateStore = new(); MultiMap _vehicleTemplateAccessoryStore = new(); MultiMap _vehicleAccessoryStore = new(); + Dictionary _vehicleSeatAddonStore = new(); //Locales Dictionary _creatureLocaleStorage = new(); diff --git a/Source/Game/Server/WorldManager.cs b/Source/Game/Server/WorldManager.cs index f01f42f9a..240d4cf6e 100644 --- a/Source/Game/Server/WorldManager.cs +++ b/Source/Game/Server/WorldManager.cs @@ -706,6 +706,9 @@ namespace Game Log.outInfo(LogFilter.ServerLoading, "Loading Vehicle Accessories..."); Global.ObjectMgr.LoadVehicleAccessories(); // must be after LoadCreatureTemplates() and LoadNPCSpellClickSpells() + Log.outInfo(LogFilter.ServerLoading, "Loading Vehicle Seat Addon Data..."); + Global.ObjectMgr.LoadVehicleSeatAddon(); // must be after loading DBC + Log.outInfo(LogFilter.ServerLoading, "Loading SpellArea Data..."); // must be after quest load Global.SpellMgr.LoadSpellAreas(); diff --git a/Source/Scripts/World/NpcSpecial.cs b/Source/Scripts/World/NpcSpecial.cs index 3d4a59bc1..960031721 100644 --- a/Source/Scripts/World/NpcSpecial.cs +++ b/Source/Scripts/World/NpcSpecial.cs @@ -2350,32 +2350,6 @@ namespace Scripts.World.NpcSpecial creature.SetDisplayFromModel(0); } } - - [Script] - class npc_traveler_tundra_mammoth_exit_pos : UnitScript - { - public npc_traveler_tundra_mammoth_exit_pos() : base("npc_traveler_tundra_mammoth_exit_pos") { } - - public override void ModifyVehiclePassengerExitPos(Unit passenger, Vehicle vehicle, Position pos) - { - if (passenger.IsCreature()) - { - switch (passenger.GetEntry()) - { - // Right side - case CreatureIds.DrixBlackwrench: - case CreatureIds.Gnimo: - pos.RelocateOffset(new Position(-2.0f, -2.0f, 0.0f, 0.0f)); - break; - // Left side - case CreatureIds.Mojodishu: - case CreatureIds.HakmudOfArgus: - pos.RelocateOffset(new Position(-2.0f, 2.0f, 0.0f, 0.0f)); - break; - } - } - } - } class CastFoodSpell : BasicEvent { diff --git a/sql/updates/world/master/2021_12_21_00_world_2020_02_08_01_world.sql b/sql/updates/world/master/2021_12_21_00_world_2020_02_08_01_world.sql new file mode 100644 index 000000000..00bf33bb8 --- /dev/null +++ b/sql/updates/world/master/2021_12_21_00_world_2020_02_08_01_world.sql @@ -0,0 +1,18 @@ +-- +DROP TABLE IF EXISTS `vehicle_seat_addon`; +CREATE TABLE `vehicle_seat_addon` ( + `SeatEntry` INT(4) UNSIGNED NOT NULL COMMENT 'VehicleSeatEntry.dbc identifier', + `SeatOrientation` FLOAT(6) DEFAULT 0 COMMENT 'Seat Orientation override value', + `ExitParamX` FLOAT(10) DEFAULT 0, + `ExitParamY` FLOAT(10) DEFAULT 0, + `ExitParamZ` FLOAT(10) DEFAULT 0, + `ExitParamO` FLOAT(10) DEFAULT 0, + `ExitParamValue` TINYINT(1) DEFAULT 0, + PRIMARY KEY (`SeatEntry`) +); + +INSERT INTO `vehicle_seat_addon` (`SeatEntry`, `SeatOrientation`, `ExitParamX`, `ExitParamY`, `ExitParamZ`, `ExitParamO`, `ExitParamValue`) VALUES +(2764, 0, -2, 2, 0, 0, 1), -- Traveler's Tundra Mammoth Seat 2 +(2765, 0, -2, -2, 0, 0, 1), -- Traveler's Tundra Mammoth Seat 3 +(2767, 0, -2, 2, 0, 0, 1), -- Traveler's Tundra Mammoth Seat 2 +(2768, 0, -2, -2, 0, 0, 1); -- Traveler's Tundra Mammoth Seat 3