[*] Improvements on both Driving and Flight School
This commit is contained in:
@@ -11,20 +11,22 @@ export default function checkpointHandle(globalData: GlobalData) {
|
|||||||
var delay;
|
var delay;
|
||||||
var delayCounter;
|
var delayCounter;
|
||||||
var markerID;
|
var markerID;
|
||||||
|
var markerSize;
|
||||||
var event;
|
var event;
|
||||||
var checkPointsDone = 0;
|
var checkPointsDone = 0;
|
||||||
var activeBlip = null;
|
var activeBlip = null;
|
||||||
|
|
||||||
mp.events.add('setCheckPoint', (position, player, checkPointID, nDelay, nMarkerID, nEvent) => {
|
mp.events.add('setCheckPoint', (position, player, checkPointID, nDelay, nMarkerID, nMarkerSize, nEvent) => {
|
||||||
inCheckpoint = false;
|
inCheckpoint = false;
|
||||||
posCp = position;
|
posCp = position;
|
||||||
Player = player;
|
Player = player;
|
||||||
delay = nDelay;
|
delay = nDelay;
|
||||||
markerID = nMarkerID;
|
markerID = nMarkerID;
|
||||||
|
markerSize = nMarkerSize;
|
||||||
delayCounter = 0;
|
delayCounter = 0;
|
||||||
checkPointsDone = checkPointID;
|
checkPointsDone = checkPointID;
|
||||||
event = nEvent;
|
event = nEvent;
|
||||||
activeCheckpoint = mp.markers.new(markerID, posCp, 10.0, {
|
activeCheckpoint = mp.markers.new(markerID, posCp, markerSize, {
|
||||||
color: [255, 0, 0, 150],
|
color: [255, 0, 0, 150],
|
||||||
visible: true,
|
visible: true,
|
||||||
dimension: 0
|
dimension: 0
|
||||||
@@ -36,7 +38,8 @@ export default function checkpointHandle(globalData: GlobalData) {
|
|||||||
alpha: 255,
|
alpha: 255,
|
||||||
shortRange: false,
|
shortRange: false,
|
||||||
});
|
});
|
||||||
|
activeBlip.setRoute(true);
|
||||||
|
activeBlip.setRouteColour(33);
|
||||||
clearInterval(myVar);
|
clearInterval(myVar);
|
||||||
//mp.events.call("SERVER:Util_setWaypoint", posCp.X, posCp.Z);
|
//mp.events.call("SERVER:Util_setWaypoint", posCp.X, posCp.Z);
|
||||||
//mp.game.ui.setNewWaypoint(posCp.x, posCp.y);
|
//mp.game.ui.setNewWaypoint(posCp.x, posCp.y);
|
||||||
@@ -56,7 +59,9 @@ export default function checkpointHandle(globalData: GlobalData) {
|
|||||||
|
|
||||||
if (!inCheckpoint) {
|
if (!inCheckpoint) {
|
||||||
if (delay != 0) {
|
if (delay != 0) {
|
||||||
mp.gui.chat.push("Warte nun " + delay / 1000 + " Sekunden");
|
massage = "Warte nun " + delay / 1000 +" Sekunden.";
|
||||||
|
render = true;
|
||||||
|
textTime = setInterval(ClearText, delay)
|
||||||
}
|
}
|
||||||
mp.game.audio.playSoundFrontend(1, "Beep_Red", "DLC_HEIST_HACKING_SNAKE_SOUNDS", true);
|
mp.game.audio.playSoundFrontend(1, "Beep_Red", "DLC_HEIST_HACKING_SNAKE_SOUNDS", true);
|
||||||
}
|
}
|
||||||
@@ -81,4 +86,40 @@ export default function checkpointHandle(globalData: GlobalData) {
|
|||||||
delayCounter = 0;
|
delayCounter = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var renderedText = null;
|
||||||
|
var textTime = null;
|
||||||
|
var render = false;
|
||||||
|
var massage;
|
||||||
|
|
||||||
|
function ClearText() {
|
||||||
|
render = false;
|
||||||
|
clearInterval(textTime);
|
||||||
|
textTime = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
mp.events.add('render', () => {
|
||||||
|
if (render) {
|
||||||
|
renderedText = mp.game.graphics.drawText(massage, [0.5, 0.85], {
|
||||||
|
font: 4,
|
||||||
|
centre: true,
|
||||||
|
color: [255, 255, 145, 185],
|
||||||
|
scale: [0.5, 0.5],
|
||||||
|
outline: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
mp.events.add('renderTextOnScreen', (msg) => {
|
||||||
|
if (textTime != null) {
|
||||||
|
clearInterval(textTime);
|
||||||
|
textTime = null;
|
||||||
|
}
|
||||||
|
massage = msg;
|
||||||
|
render = true;
|
||||||
|
textTime = setInterval(ClearText, 7000)
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -52,43 +52,11 @@ export default function planeSchoolHandle(globalData: GlobalData) {
|
|||||||
timer = setInterval(timerPlayerInVehicle1, 3000);
|
timer = setInterval(timerPlayerInVehicle1, 3000);
|
||||||
});
|
});
|
||||||
|
|
||||||
var renderedText = null;
|
|
||||||
var textTime = null;
|
|
||||||
var render = false;
|
|
||||||
var massage;
|
|
||||||
|
|
||||||
function ClearText() {
|
|
||||||
render = false;
|
|
||||||
clearInterval(textTime);
|
|
||||||
textTime = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
mp.events.add('render', () =>{
|
|
||||||
if (render) {
|
|
||||||
renderedText = mp.game.graphics.drawText(massage, [0.5, 0.85], {
|
|
||||||
font: 4,
|
|
||||||
centre: true,
|
|
||||||
color: [255, 255, 145, 185],
|
|
||||||
scale: [0.5, 0.5],
|
|
||||||
outline: true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
mp.events.add('renderTextOnScreen', (msg) => {
|
|
||||||
if (textTime != null) {
|
|
||||||
clearInterval(textTime);
|
|
||||||
textTime = null;
|
|
||||||
}
|
|
||||||
massage = msg;
|
|
||||||
render = true;
|
|
||||||
textTime = setInterval(ClearText, 7000)
|
|
||||||
});
|
|
||||||
mp.events.add('stopTimer', () => {
|
mp.events.add('stopTimer', () => {
|
||||||
timerSet = false;
|
timerSet = false;
|
||||||
clearInterval(timer);
|
clearInterval(timer);
|
||||||
});
|
});
|
||||||
|
|
||||||
function timerPlayerInVehicle1() {
|
function timerPlayerInVehicle1() {
|
||||||
if (timerSet) {
|
if (timerSet) {
|
||||||
mp.events.callRemote('timerCheckVehicle1');
|
mp.events.callRemote('timerCheckVehicle1');
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ using System.Linq;
|
|||||||
using GTANetworkAPI;
|
using GTANetworkAPI;
|
||||||
using ReallifeGamemode.Database.Entities;
|
using ReallifeGamemode.Database.Entities;
|
||||||
using ReallifeGamemode.Database.Models;
|
using ReallifeGamemode.Database.Models;
|
||||||
|
using ReallifeGamemode.Server.Managers;
|
||||||
|
|
||||||
namespace ReallifeGamemode.Server.DrivingSchool
|
namespace ReallifeGamemode.Server.DrivingSchool
|
||||||
{
|
{
|
||||||
@@ -21,43 +22,47 @@ namespace ReallifeGamemode.Server.DrivingSchool
|
|||||||
private readonly IReadOnlyCollection<Vector3> DrivingRoute = new List<Vector3>
|
private readonly IReadOnlyCollection<Vector3> DrivingRoute = new List<Vector3>
|
||||||
{
|
{
|
||||||
//BEGIN
|
//BEGIN
|
||||||
new Vector3(-745.6191, -1285.735, 4.947221),
|
new Vector3(-745.6191, -1285.735, 3.947221),
|
||||||
new Vector3(-704.5242, -1246.765, 9.885977),
|
new Vector3(-704.5242, -1246.765, 8.885977),
|
||||||
new Vector3(-673.0675, -1266.652, 10.29717),
|
new Vector3(-673.0675, -1266.652, 9.29717),
|
||||||
new Vector3(-646.1747, -1293.238, 10.28384),
|
new Vector3(-646.1747, -1293.238, 9.28384),
|
||||||
new Vector3(-510.7098, -916.9164, 25.10735),
|
new Vector3(-510.7098, -916.9164, 24.10735),
|
||||||
new Vector3(-492.6284, -860.5167, 29.89526),
|
new Vector3(-492.6284, -860.5167, 28.89526),
|
||||||
new Vector3(-450.3232, -841.7007, 30.3698),
|
new Vector3(-450.3232, -841.7007, 29.3698),
|
||||||
new Vector3(17.09636, -973.2763, 29.01929),
|
new Vector3(17.09636, -973.2763, 28.01929),
|
||||||
new Vector3(76.66012, -999.568, 28.97918),
|
new Vector3(76.66012, -999.568, 27.97918),
|
||||||
//SLALOM
|
//SLALOM
|
||||||
new Vector3(-12.64976, -1751.287, 28.91913),
|
new Vector3(-12.64976, -1751.287, 27.91913),
|
||||||
new Vector3(6.008641, -1767.067, 28.91265),
|
new Vector3(6.008641, -1767.067, 27.91265),
|
||||||
new Vector3(12.80635, -1752.094, 28.91877),
|
new Vector3(12.80635, -1752.094, 27.91877),
|
||||||
new Vector3(26.71735, -1747.96, 28.92006),
|
new Vector3(26.71735, -1747.96, 27.92006),
|
||||||
new Vector3(28.67053, -1733.492, 28.91953),
|
new Vector3(28.67053, -1733.492, 27.91953),
|
||||||
new Vector3(42.68731, -1728.767, 28.92002),
|
new Vector3(42.68731, -1728.767, 27.92002),
|
||||||
new Vector3(44.33229, -1714.426, 28.9193),
|
new Vector3(44.33229, -1714.426, 27.9193),
|
||||||
new Vector3(37.25899, -1723.924, 28.92041),
|
new Vector3(37.25899, -1723.924, 27.92041),
|
||||||
new Vector3(34.591, -1738.211, 28.92125),
|
new Vector3(34.591, -1738.211, 27.92125),
|
||||||
new Vector3(21.28996, -1742.563, 28.91987),
|
new Vector3(21.28996, -1742.563, 27.91987),
|
||||||
new Vector3(18.46534, -1756.87, 28.92011),
|
new Vector3(18.46534, -1756.87, 27.92011),
|
||||||
new Vector3(4.841759, -1761.316, 28.91519),
|
new Vector3(4.841759, -1761.316, 27.91519),
|
||||||
new Vector3(44.69115, -1805.247, 25.07369),
|
new Vector3(44.69115, -1805.247, 24.07369),
|
||||||
new Vector3(111.6519, -1822.466, 26.03703),
|
new Vector3(111.6519, -1822.466, 25.03703),
|
||||||
//AUTOBAHN-ENDE
|
//AUTOBAHN-ENDE
|
||||||
new Vector3(-270.89, -1461.01, 30.81),
|
new Vector3(-270.89, -1461.01, 29.81),
|
||||||
new Vector3(-369.08, -1415.37, 28.68),
|
new Vector3(-369.08, -1415.37, 27.68),
|
||||||
new Vector3(-114.48, -1251.43, 36.59),
|
new Vector3(-114.48, -1251.43, 35.59),
|
||||||
new Vector3(59.22, -1261.71, 28.84),
|
new Vector3(59.22, -1261.71, 27.84),
|
||||||
new Vector3(39.12, -1165.28, 28.87),
|
new Vector3(39.12, -1165.28, 27.87),
|
||||||
new Vector3(-307.52, -1200.85, 36.79),
|
new Vector3(-307.52, -1200.85, 35.79),
|
||||||
new Vector3(-441.79, -1251.67, 45.37),
|
new Vector3(-441.79, -1251.67, 44.37),
|
||||||
new Vector3(-463.77, -1405.07, 28.71),
|
new Vector3(-463.77, -1405.07, 27.71),
|
||||||
new Vector3(-617.66, -1259.34, 10.82),
|
new Vector3(-617.66, -1259.34, 9.82),
|
||||||
new Vector3(-758.35, -1285.03, 4.48),
|
}.AsReadOnly();
|
||||||
|
private readonly IReadOnlyCollection<Vector3> Stop = new List<Vector3>
|
||||||
|
{
|
||||||
|
new Vector3(-758.35, -1285.03, 3.48),
|
||||||
}.AsReadOnly();
|
}.AsReadOnly();
|
||||||
|
|
||||||
|
|
||||||
public static void Setup()
|
public static void Setup()
|
||||||
{
|
{
|
||||||
informationLabel = NAPI.TextLabel.CreateTextLabel("Fahrschule", new Vector3(-813.17, -1354.5, 5.14), 20.0f, 1.3f, 0, new Color(255, 255, 255));
|
informationLabel = NAPI.TextLabel.CreateTextLabel("Fahrschule", new Vector3(-813.17, -1354.5, 5.14), 20.0f, 1.3f, 0, new Color(255, 255, 255));
|
||||||
@@ -85,9 +90,22 @@ namespace ReallifeGamemode.Server.DrivingSchool
|
|||||||
public void StartDrivingSchool(Client client)
|
public void StartDrivingSchool(Client client)
|
||||||
{
|
{
|
||||||
User user = client.GetUser();
|
User user = client.GetUser();
|
||||||
if (user.DriverLicenseVehicle)
|
|
||||||
return;
|
|
||||||
|
|
||||||
|
if(user.Handmoney < 2500)
|
||||||
|
{
|
||||||
|
client.SendNotification("~r~Du brauchst ~g~$2500~r~ auf der Hand um die Prüfung zu starten.", true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
using (var dbContext = new DatabaseContext())
|
||||||
|
{
|
||||||
|
User payer = client.GetUser(dbContext);
|
||||||
|
payer.Handmoney -= 2500;
|
||||||
|
dbContext.SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (user.DriverLicenseVehicle || client.HasData("ActiveSchool"))
|
||||||
|
return;
|
||||||
|
client.SetData("ActiveSchool", 0);
|
||||||
client.TriggerEvent("renderTextOnScreen", "Sie haben die Führerscheinprüfung gestartet. Steigen Sie in eines der Fahrschulautos ein.");
|
client.TriggerEvent("renderTextOnScreen", "Sie haben die Führerscheinprüfung gestartet. Steigen Sie in eines der Fahrschulautos ein.");
|
||||||
client.TriggerEvent("waitPlayerEntersVehicle");
|
client.TriggerEvent("waitPlayerEntersVehicle");
|
||||||
}
|
}
|
||||||
@@ -103,13 +121,36 @@ namespace ReallifeGamemode.Server.DrivingSchool
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
user.TriggerEvent("renderTextOnScreen", "Gut nun kann die Prüfung losgehen");
|
user.TriggerEvent("renderTextOnScreen", "Gut nun kann die Prüfung losgehen.");
|
||||||
user.TriggerEvent("stopTimer");
|
user.TriggerEvent("stopTimer");
|
||||||
|
|
||||||
CheckPointHandle.StartCheckPointRoute(user, DrivingRoute, 0, 1, "drivingSchoolEvent");
|
CheckPointHandle.StartCheckPointRoute(user, DrivingRoute, 0, 1, 7, "drivingSchoolEvent");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[RemoteEvent("drivingSchoolEventEnd")]
|
||||||
|
public void DrivingSchoolEventEnd(Client user, int checkpoint)
|
||||||
|
{
|
||||||
|
user.TriggerEvent("renderTextOnScreen", "Du hast den Führerschein bestanden. Glückwunsch!");
|
||||||
|
user.ResetData("ActiveSchool");
|
||||||
|
using (var dbContext = new DatabaseContext())
|
||||||
|
{
|
||||||
|
User drivingUser = user.GetUser(dbContext);
|
||||||
|
drivingUser.DriverLicenseVehicle = true;
|
||||||
|
dbContext.SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
Vehicle veh = user.Vehicle;
|
||||||
|
user.WarpOutOfVehicle();
|
||||||
|
ServerVehicle sVeh = VehicleManager.GetServerVehicleFromVehicle(veh);
|
||||||
|
VehicleStreaming.SetEngineState(veh, false);
|
||||||
|
VehicleStreaming.SetLockStatus(veh, false);
|
||||||
|
NAPI.Entity.SetEntityVelocity(veh.Handle, new Vector3(0, 0, 0));
|
||||||
|
veh.Position = sVeh.Position;
|
||||||
|
veh.Rotation = new Vector3(0, 0, sVeh.Heading);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
[RemoteEvent("drivingSchoolEvent")]
|
[RemoteEvent("drivingSchoolEvent")]
|
||||||
public void DrivingSchoolEvent(Client user, int checkpoint)
|
public void DrivingSchoolEvent(Client user, int checkpoint)
|
||||||
{
|
{
|
||||||
@@ -117,39 +158,22 @@ namespace ReallifeGamemode.Server.DrivingSchool
|
|||||||
|
|
||||||
if (checkpoint == 7)
|
if (checkpoint == 7)
|
||||||
{
|
{
|
||||||
user.TriggerEvent("checkWait");
|
ChatService.SendMessage(user, "Schaue an der nächsten Kreuzung nach links.");
|
||||||
ChatService.SendMessage(user, "Schaue an der nächsten Kreuzung nach links");
|
}
|
||||||
}
|
|
||||||
else if (checkpoint == 9)
|
else if (checkpoint == 9)
|
||||||
{
|
{
|
||||||
user.TriggerEvent("renderTextOnScreen", "Fahre zwischen den Laternen Slalom");
|
user.TriggerEvent("renderTextOnScreen", "Fahre zwischen den Laternen Slalom.");
|
||||||
}
|
}
|
||||||
else if (checkpoint == 20)
|
else if (checkpoint == 20)
|
||||||
{
|
{
|
||||||
user.TriggerEvent("renderTextOnScreen", "Verlasse nun den Parkplatz");
|
user.TriggerEvent("renderTextOnScreen", "Verlasse nun den Parkplatz.");
|
||||||
}
|
}
|
||||||
else if (checkpoint == 32)
|
else if (checkpoint == 31)
|
||||||
{
|
{
|
||||||
user.TriggerEvent("renderTextOnScreen", "Du hast den Führerschein bestanden. Glückwunsch");
|
CheckPointHandle.StartCheckPointRoute(user, Stop, 5000, 1, 7, "drivingSchoolEventEnd");
|
||||||
User spieler = user.GetUser();
|
}
|
||||||
using (var dbContext = new DatabaseContext())
|
|
||||||
{
|
|
||||||
User drivingUser = dbContext.Users.Where(u => u.Id == spieler.Id).FirstOrDefault();
|
|
||||||
drivingUser.DriverLicenseVehicle = true;
|
|
||||||
dbContext.SaveChanges();
|
|
||||||
}
|
|
||||||
//veh & client tp
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command("ld", "~m~Benutzung: ~s~/lt")]
|
|
||||||
public void CmdAdminLt(Client player)
|
|
||||||
{
|
|
||||||
Vehicle veh = player.Vehicle;
|
|
||||||
ChatService.Broadcast("x: " + veh.Rotation.X + " | y: " + veh.Rotation.Y + " | z: " + veh.Rotation.Z);
|
|
||||||
|
|
||||||
//player.TriggerEvent("lookDirectionTesting", veh);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,9 +36,15 @@ namespace ReallifeGamemode.Server.DrivingSchool
|
|||||||
new Vector3(2134.13, 4782.7, 41.9),
|
new Vector3(2134.13, 4782.7, 41.9),
|
||||||
new Vector3(2098.9, 4792.94, 41.98),
|
new Vector3(2098.9, 4792.94, 41.98),
|
||||||
new Vector3(-869.77, -1424.05, 133),
|
new Vector3(-869.77, -1424.05, 133),
|
||||||
|
}.AsReadOnly();
|
||||||
|
|
||||||
|
|
||||||
|
private readonly IReadOnlyCollection<Vector3> planeRouteEnd = new List<Vector3>
|
||||||
|
{
|
||||||
new Vector3(-1164.29, -2351.52, 14.88),
|
new Vector3(-1164.29, -2351.52, 14.88),
|
||||||
}.AsReadOnly();
|
}.AsReadOnly();
|
||||||
|
|
||||||
|
|
||||||
public static void Setup()
|
public static void Setup()
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -65,8 +71,20 @@ namespace ReallifeGamemode.Server.DrivingSchool
|
|||||||
[RemoteEvent("startplaneSchool")]
|
[RemoteEvent("startplaneSchool")]
|
||||||
public void StartplaneSchool(Client client)
|
public void StartplaneSchool(Client client)
|
||||||
{
|
{
|
||||||
|
if (user.Handmoney < 5000)
|
||||||
|
{
|
||||||
|
client.SendNotification("~r~Du brauchst ~g~$5000~r~ auf der Hand um die Prüfung zu starten.", true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
using (var dbContext = new DatabaseContext())
|
||||||
|
{
|
||||||
|
User payer = client.GetUser(dbContext);
|
||||||
|
payer.Handmoney -= 2500;
|
||||||
|
dbContext.SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
User user = client.GetUser();
|
User user = client.GetUser();
|
||||||
if (user.FlyingLicensePlane)
|
if (user.FlyingLicensePlane || client.HasData("ActiveSchool"))
|
||||||
return;
|
return;
|
||||||
client.SetData("ActiveSchool", 1);
|
client.SetData("ActiveSchool", 1);
|
||||||
client.TriggerEvent("renderTextOnScreen", "Du hast die Flugscheinprüfung gestartet. Steige nun in eines der Flugzeuge ein.");
|
client.TriggerEvent("renderTextOnScreen", "Du hast die Flugscheinprüfung gestartet. Steige nun in eines der Flugzeuge ein.");
|
||||||
@@ -86,10 +104,32 @@ namespace ReallifeGamemode.Server.DrivingSchool
|
|||||||
{
|
{
|
||||||
user.TriggerEvent("renderTextOnScreen", "Fahren Sie langsam und sicher zur Roten Markierung.");
|
user.TriggerEvent("renderTextOnScreen", "Fahren Sie langsam und sicher zur Roten Markierung.");
|
||||||
user.TriggerEvent("stopTimer");
|
user.TriggerEvent("stopTimer");
|
||||||
CheckPointHandle.StartCheckPointRoute(user, planeRoute, 0, 6, "planeSchoolEvent");
|
CheckPointHandle.StartCheckPointRoute(user, planeRoute, 0, 6, 12, "planeSchoolEvent");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[RemoteEvent("planeSchoolEventEnd")]
|
||||||
|
public void planeSchoolEventEnd(Client user, int checkpoint)
|
||||||
|
{
|
||||||
|
Vehicle veh = user.Vehicle;
|
||||||
|
user.WarpOutOfVehicle();
|
||||||
|
ServerVehicle sVeh = VehicleManager.GetServerVehicleFromVehicle(veh);
|
||||||
|
VehicleStreaming.SetEngineState(veh, false);
|
||||||
|
VehicleStreaming.SetLockStatus(veh, false);
|
||||||
|
NAPI.Entity.SetEntityVelocity(veh.Handle, new Vector3(0, 0, 0));
|
||||||
|
veh.Position = sVeh.Position;
|
||||||
|
veh.Rotation = new Vector3(0, 0, sVeh.Heading);
|
||||||
|
|
||||||
|
user.TriggerEvent("renderTextOnScreen", "Du hast deinen Flugschein bestanden!");
|
||||||
|
using (var dbContext = new DatabaseContext())
|
||||||
|
{
|
||||||
|
User drivingUser = user.GetUser(dbContext);
|
||||||
|
drivingUser.FlyingLicensePlane = true;
|
||||||
|
dbContext.SaveChanges();
|
||||||
|
}
|
||||||
|
user.ResetData("ActiveSchool");
|
||||||
|
user.Position = new Vector3(-1083.96, -2476.96, 13.07);
|
||||||
|
}
|
||||||
[RemoteEvent("planeSchoolEvent")]
|
[RemoteEvent("planeSchoolEvent")]
|
||||||
public void planeSchoolEvent(Client user, int checkpoint)
|
public void planeSchoolEvent(Client user, int checkpoint)
|
||||||
{
|
{
|
||||||
@@ -99,12 +139,8 @@ namespace ReallifeGamemode.Server.DrivingSchool
|
|||||||
user.TriggerEvent("renderTextOnScreen", "Achten Sie darauf dass Sie mittig durch jeder Markierung fahren/fliegen.");
|
user.TriggerEvent("renderTextOnScreen", "Achten Sie darauf dass Sie mittig durch jeder Markierung fahren/fliegen.");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1:
|
|
||||||
user.TriggerEvent("renderTextOnScreen", "Für die Flugprüfung haben Sie 15min Zeit.");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
user.TriggerEvent("renderTextOnScreen", "Wenn Sie aus dem Flugzeug aussteigen sind Sie aus der Prüfung durchgefallen.");
|
user.TriggerEvent("renderTextOnScreen", "Falls Sie aus dem Flugzeug aussteigen sind Sie aus der Prüfung durchgefallen.");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
@@ -137,28 +173,10 @@ namespace ReallifeGamemode.Server.DrivingSchool
|
|||||||
|
|
||||||
case 14:
|
case 14:
|
||||||
user.TriggerEvent("renderTextOnScreen", "Setze zum landeflug an. Drücke 'G' um ihr Fahrwerk auszufahren.");
|
user.TriggerEvent("renderTextOnScreen", "Setze zum landeflug an. Drücke 'G' um ihr Fahrwerk auszufahren.");
|
||||||
|
CheckPointHandle.StartCheckPointRoute(user, planeRouteEnd, 5000, 6, 12, "planeSchoolEventEnd");
|
||||||
break;
|
break;
|
||||||
case 15:
|
|
||||||
|
|
||||||
Vehicle veh = user.Vehicle;
|
|
||||||
user.WarpOutOfVehicle();
|
|
||||||
ServerVehicle sVeh = VehicleManager.GetServerVehicleFromVehicle(veh);
|
|
||||||
VehicleStreaming.SetEngineState(veh, false);
|
|
||||||
VehicleStreaming.SetLockStatus(veh, false);
|
|
||||||
NAPI.Entity.SetEntityVelocity(veh.Handle, new Vector3(0,0,0));
|
|
||||||
veh.Position = sVeh.Position;
|
|
||||||
veh.Rotation = new Vector3(0, 0, sVeh.Heading);
|
|
||||||
|
|
||||||
user.TriggerEvent("renderTextOnScreen", "Du hast deinen Flugschein bestanden!");
|
|
||||||
using (var dbContext = new DatabaseContext())
|
|
||||||
{
|
|
||||||
User drivingUser = user.GetUser(dbContext);
|
|
||||||
drivingUser.FlyingLicensePlane = true;
|
|
||||||
dbContext.SaveChanges();
|
|
||||||
}
|
|
||||||
user.ResetData("ActiveSchool");
|
|
||||||
user.Position = new Vector3(-1083.96, -2476.96, 13.07);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ namespace ReallifeGamemode.Server.Events
|
|||||||
return;
|
return;
|
||||||
List<Vector3> dealPoint = new List<Vector3>();
|
List<Vector3> dealPoint = new List<Vector3>();
|
||||||
dealPoint.Add(vector);
|
dealPoint.Add(vector);
|
||||||
CheckPointHandle.StartCheckPointRoute(client, dealPoint, 5000, 1, "loadWeaponTransport");
|
CheckPointHandle.StartCheckPointRoute(client, dealPoint, 5000, 1, 7, "loadWeaponTransport");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using System.Text;
|
|||||||
using GTANetworkAPI;
|
using GTANetworkAPI;
|
||||||
using ReallifeGamemode.Database.Entities;
|
using ReallifeGamemode.Database.Entities;
|
||||||
using ReallifeGamemode.Server.Extensions;
|
using ReallifeGamemode.Server.Extensions;
|
||||||
|
using ReallifeGamemode.Server.Managers;
|
||||||
using ReallifeGamemode.Server.Util;
|
using ReallifeGamemode.Server.Util;
|
||||||
using ReallifeGamemode.Server.WeaponDeal;
|
using ReallifeGamemode.Server.WeaponDeal;
|
||||||
|
|
||||||
@@ -24,7 +25,21 @@ namespace ReallifeGamemode.Server.Events
|
|||||||
client.TriggerEvent("destroyCP");
|
client.TriggerEvent("destroyCP");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (vehicle.GetServerVehicle() is SchoolVehicle vehS)
|
||||||
|
{
|
||||||
|
if (client.HasData("ActiveSchool"))
|
||||||
|
{
|
||||||
|
client.SendNotification("~r~Du hast deine Prüfung unterbrochen!", true);
|
||||||
|
|
||||||
|
client.WarpOutOfVehicle();
|
||||||
|
ServerVehicle sVeh = VehicleManager.GetServerVehicleFromVehicle(vehicle);
|
||||||
|
VehicleStreaming.SetEngineState(vehicle, false);
|
||||||
|
VehicleStreaming.SetLockStatus(vehicle, false);
|
||||||
|
NAPI.Entity.SetEntityVelocity(vehicle.Handle, new Vector3(0, 0, 0));
|
||||||
|
vehicle.Position = sVeh.Position;
|
||||||
|
vehicle.Rotation = new Vector3(0, 0, sVeh.Heading);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,80 +16,80 @@ namespace ReallifeGamemode.Server.Job
|
|||||||
|
|
||||||
private readonly IReadOnlyCollection<Vector3> Route1 = new List<Vector3>
|
private readonly IReadOnlyCollection<Vector3> Route1 = new List<Vector3>
|
||||||
{
|
{
|
||||||
new Vector3(-105.5951, -1684.548, 29.23948),
|
new Vector3(-105.5951, -1684.548, 28.23948),
|
||||||
new Vector3(-1056.246, -2552.576, 13.66063),
|
new Vector3(-1056.246, -2552.576, 12.66063),
|
||||||
new Vector3(200.3088, -1978.828, 19.3329),
|
new Vector3(200.3088, -1978.828, 18.3329),
|
||||||
new Vector3(358.6138, -1785.821, 28.92113),
|
new Vector3(358.6138, -1785.821, 27.92113),
|
||||||
new Vector3(281.8594, -1462.503, 29.13148),
|
new Vector3(281.8594, -1462.503, 28.13148),
|
||||||
new Vector3(77.72239, -1212.086, 29.12294),
|
new Vector3(77.72239, -1212.086, 28.12294),
|
||||||
new Vector3(218.1398, -850.9549, 30.16619)
|
new Vector3(218.1398, -850.9549, 29.16619)
|
||||||
}.AsReadOnly();
|
}.AsReadOnly();
|
||||||
|
|
||||||
private readonly IReadOnlyCollection<Vector3> Route2 = new List<Vector3>
|
private readonly IReadOnlyCollection<Vector3> Route2 = new List<Vector3>
|
||||||
{
|
{
|
||||||
new Vector3(403.4488, -786.5514, 29.2046),
|
new Vector3(403.4488, -786.5514, 28.2046),
|
||||||
new Vector3(787.6898, -1364.566, 26.41318),
|
new Vector3(787.6898, -1364.566, 25.41318),
|
||||||
new Vector3(942.0541, -1447.974, 31.14204),
|
new Vector3(942.0541, -1447.974, 30.14204),
|
||||||
new Vector3(866.8322, -997.5225, 30.48207),
|
new Vector3(866.8322, -997.5225, 29.48207),
|
||||||
new Vector3(785.4254, -781.3905, 26.33277),
|
new Vector3(785.4254, -781.3905, 25.33277),
|
||||||
new Vector3(351.5793, -1064.582, 29.40059),
|
new Vector3(351.5793, -1064.582, 28.40059),
|
||||||
new Vector3(235.0964, -857.1152, 29.74256),
|
new Vector3(235.0964, -857.1152, 28.74256),
|
||||||
}.AsReadOnly();
|
}.AsReadOnly();
|
||||||
|
|
||||||
private readonly IReadOnlyCollection<Vector3> Route3 = new List<Vector3>
|
private readonly IReadOnlyCollection<Vector3> Route3 = new List<Vector3>
|
||||||
{
|
{
|
||||||
new Vector3(313.7626,-647.1252,28.6658),
|
new Vector3(313.7626,-647.1252,27.6658),
|
||||||
new Vector3(28.84793,-543.386,35.42649),
|
new Vector3(28.84793,-543.386,34.42649),
|
||||||
new Vector3(120.2759,-195.0664,53.98029),
|
new Vector3(120.2759,-195.0664,52.98029),
|
||||||
new Vector3(291.5339,-257.244,53.89333),
|
new Vector3(291.5339,-257.244,52.89333),
|
||||||
new Vector3(459.6921,116.3203,98.18157),
|
new Vector3(459.6921,116.3203,97.18157),
|
||||||
new Vector3(173.9451,220.1987,105.4178),
|
new Vector3(173.9451,220.1987,104.4178),
|
||||||
new Vector3(-327.3175,261.2248,85.86708),
|
new Vector3(-327.3175,261.2248,84.86708),
|
||||||
new Vector3(-764.2745,294.4415,85.00808),
|
new Vector3(-764.2745,294.4415,84.00808),
|
||||||
new Vector3(-980.486,275.0842,68.26749),
|
new Vector3(-980.486,275.0842,67.26749),
|
||||||
new Vector3(-1031.586,107.9002,52.30307),
|
new Vector3(-1031.586,107.9002,51.30307),
|
||||||
new Vector3(-489.973,-195.4356,36.59651),
|
new Vector3(-489.973,-195.4356,35.59651),
|
||||||
new Vector3(-312.2727,-367.7886,29.93641),
|
new Vector3(-312.2727,-367.7886,28.93641),
|
||||||
new Vector3(-224.4042,-528.0254,34.08064),
|
new Vector3(-224.4042,-528.0254,33.08064),
|
||||||
new Vector3(-245.7707,-714.5482,32.90899),
|
new Vector3(-245.7707,-714.5482,31.90899),
|
||||||
new Vector3(-248.9475,-883.7717,30.00919),
|
new Vector3(-248.9475,-883.7717,29.00919),
|
||||||
}.AsReadOnly();
|
}.AsReadOnly();
|
||||||
|
|
||||||
private readonly IReadOnlyCollection<Vector3> RouteLong = new List<Vector3>
|
private readonly IReadOnlyCollection<Vector3> RouteLong = new List<Vector3>
|
||||||
{
|
{
|
||||||
|
|
||||||
new Vector3(403.8605,-597.0284,28.1788),
|
new Vector3(403.8605,-597.0284,27.1788),
|
||||||
new Vector3(953.7955,140.8976,80.34214),
|
new Vector3(953.7955,140.8976,79.34214),
|
||||||
new Vector3(1531.374,832.1884,76.94727),
|
new Vector3(1531.374,832.1884,75.94727),
|
||||||
new Vector3(1972.424,2643.501,45.62299),
|
new Vector3(1972.424,2643.501,44.62299),
|
||||||
new Vector3(1812.351,3318.685,41.64569),
|
new Vector3(1812.351,3318.685,40.64569),
|
||||||
new Vector3(1820.982,3700.176,33.31515),
|
new Vector3(1820.982,3700.176,32.31515),
|
||||||
new Vector3(2599.954,4264.15,41.87192),
|
new Vector3(2599.954,4264.15,40.87192),
|
||||||
new Vector3(2705.722,3308.447,55.2841),
|
new Vector3(2705.722,3308.447,54.2841),
|
||||||
new Vector3(355.8403,-634.835,28.56906),
|
new Vector3(355.8403,-634.835,27.56906),
|
||||||
|
|
||||||
}.AsReadOnly();
|
}.AsReadOnly();
|
||||||
|
|
||||||
private readonly IReadOnlyCollection<Vector3> RouteVeryLong = new List<Vector3>
|
private readonly IReadOnlyCollection<Vector3> RouteVeryLong = new List<Vector3>
|
||||||
{
|
{
|
||||||
|
|
||||||
new Vector3(-562.68, -2203.85, 6.72),
|
new Vector3(-562.68, -2203.85, 5.72),
|
||||||
new Vector3(-889.0892, -2190.34, 8.100273),
|
new Vector3(-889.0892, -2190.34, 7.100273),
|
||||||
new Vector3(-695.8978, -1197.1, 10.07723),
|
new Vector3(-695.8978, -1197.1, 9.07723),
|
||||||
new Vector3(-1025.791, -788.746, 16.95118),
|
new Vector3(-1025.791, -788.746, 15.95118),
|
||||||
new Vector3(-1411.543, -569.5651, 29.83663),
|
new Vector3(-1411.543, -569.5651, 28.83663),
|
||||||
new Vector3(-1863.717, -355.0997, 48.79111),
|
new Vector3(-1863.717, -355.0997, 47.79111),
|
||||||
new Vector3(-2171.938, -299.1247, 12.24473),
|
new Vector3(-2171.938, -299.1247, 11.24473),
|
||||||
new Vector3(-2973.008, 506.4566, 14.99877),
|
new Vector3(-2973.008, 506.4566, 13.99877),
|
||||||
new Vector3(-2738.997, 2239.153, 21.54851),
|
new Vector3(-2738.997, 2239.153, 20.54851),
|
||||||
new Vector3(-2448.411, 3736.997, 16.20646),
|
new Vector3(-2448.411, 3736.997, 15.20646),
|
||||||
new Vector3(-2206.853, 4257.991, 47.13944),
|
new Vector3(-2206.853, 4257.991, 46.13944),
|
||||||
new Vector3(-1545.054, 4934.076, 61.29264),
|
new Vector3(-1545.054, 4934.076, 60.29264),
|
||||||
new Vector3(-152.66, 6209.62, 32.03),
|
new Vector3(-152.66, 6209.62, 31.03),
|
||||||
new Vector3(2707.136, 3309.894, 55.37453),
|
new Vector3(2707.136, 3309.894, 54.37453),
|
||||||
new Vector3(2554.981, 292.5191, 108.036),
|
new Vector3(2554.981, 292.5191, 107.036),
|
||||||
new Vector3(-740.3124, -1645.125, 26.10983),
|
new Vector3(-740.3124, -1645.125, 25.10983),
|
||||||
new Vector3(-756.3812, -2295.088, 12.43381),
|
new Vector3(-756.3812, -2295.088, 11.43381),
|
||||||
}.AsReadOnly();
|
}.AsReadOnly();
|
||||||
|
|
||||||
public BusDriverJob()
|
public BusDriverJob()
|
||||||
@@ -131,23 +131,23 @@ namespace ReallifeGamemode.Server.Job
|
|||||||
{
|
{
|
||||||
if (type == "Kurz 1")
|
if (type == "Kurz 1")
|
||||||
{
|
{
|
||||||
CheckPointHandle.StartCheckPointRoute(player, Route1, 3000, 1, "");
|
CheckPointHandle.StartCheckPointRoute(player, Route1, 3000, 1, 7, "");
|
||||||
}
|
}
|
||||||
else if (type == "Kurz 2")
|
else if (type == "Kurz 2")
|
||||||
{
|
{
|
||||||
CheckPointHandle.StartCheckPointRoute(player, Route2, 3000, 1, "");
|
CheckPointHandle.StartCheckPointRoute(player, Route2, 3000, 1, 7, "");
|
||||||
}
|
}
|
||||||
else if (type == "Mittel 1")
|
else if (type == "Mittel 1")
|
||||||
{
|
{
|
||||||
CheckPointHandle.StartCheckPointRoute(player, Route3, 3000, 1, "");
|
CheckPointHandle.StartCheckPointRoute(player, Route3, 3000, 1, 7, "");
|
||||||
}
|
}
|
||||||
else if (type == "Lang 1")
|
else if (type == "Lang 1")
|
||||||
{
|
{
|
||||||
CheckPointHandle.StartCheckPointRoute(player, RouteLong, 3000, 1, "");
|
CheckPointHandle.StartCheckPointRoute(player, RouteLong, 3000, 1, 7, "");
|
||||||
}
|
}
|
||||||
else if (type == "Lang 2")
|
else if (type == "Lang 2")
|
||||||
{
|
{
|
||||||
CheckPointHandle.StartCheckPointRoute(player, RouteVeryLong, 3000, 1, "");
|
CheckPointHandle.StartCheckPointRoute(player, RouteVeryLong, 3000, 1, 7, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -139,27 +139,27 @@ namespace ReallifeGamemode.Server.Job
|
|||||||
{
|
{
|
||||||
if (type == "Route 1")
|
if (type == "Route 1")
|
||||||
{
|
{
|
||||||
CheckPointHandle.StartCheckPointRoute(player, Route1, 0, 6, "");
|
CheckPointHandle.StartCheckPointRoute(player, Route1, 0, 6, 12, "");
|
||||||
}
|
}
|
||||||
else if (type == "Route 2")
|
else if (type == "Route 2")
|
||||||
{
|
{
|
||||||
CheckPointHandle.StartCheckPointRoute(player, Route2, 0, 6, "");
|
CheckPointHandle.StartCheckPointRoute(player, Route2, 0, 6, 12, "");
|
||||||
}
|
}
|
||||||
else if (type == "Route 3")
|
else if (type == "Route 3")
|
||||||
{
|
{
|
||||||
CheckPointHandle.StartCheckPointRoute(player, Route3, 0, 6, "");
|
CheckPointHandle.StartCheckPointRoute(player, Route3, 0, 6, 12, "");
|
||||||
}
|
}
|
||||||
else if (type == "Route 4")
|
else if (type == "Route 4")
|
||||||
{
|
{
|
||||||
CheckPointHandle.StartCheckPointRoute(player, Route4, 0, 6, "");
|
CheckPointHandle.StartCheckPointRoute(player, Route4, 0, 6, 12, "");
|
||||||
}
|
}
|
||||||
else if (type == "Route 5")
|
else if (type == "Route 5")
|
||||||
{
|
{
|
||||||
CheckPointHandle.StartCheckPointRoute(player, Route5, 0, 6, "");
|
CheckPointHandle.StartCheckPointRoute(player, Route5, 0, 6, 12, "");
|
||||||
}
|
}
|
||||||
else if (type == "Route 6")
|
else if (type == "Route 6")
|
||||||
{
|
{
|
||||||
CheckPointHandle.StartCheckPointRoute(player, Route6, 0, 6, "");
|
CheckPointHandle.StartCheckPointRoute(player, Route6, 0, 6,12, "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,10 +7,10 @@ namespace ReallifeGamemode.Server.Util
|
|||||||
public class CheckPointHandle : Script
|
public class CheckPointHandle : Script
|
||||||
{
|
{
|
||||||
public static List<CheckPointListForPlayer> listHandle = new List<CheckPointListForPlayer>();
|
public static List<CheckPointListForPlayer> listHandle = new List<CheckPointListForPlayer>();
|
||||||
public static void StartCheckPointRoute(Client player, IEnumerable<Vector3> nListCps, int delay, int markerID, string nEvent)
|
public static void StartCheckPointRoute(Client player, IEnumerable<Vector3> nListCps, int delay, int markerID, int markerSize, string nEvent)
|
||||||
{
|
{
|
||||||
RemovePlayerHandlerFromList(player);
|
RemovePlayerHandlerFromList(player);
|
||||||
CheckPointListForPlayer playerHandle = new CheckPointListForPlayer(player, nListCps, delay, markerID, nEvent);
|
CheckPointListForPlayer playerHandle = new CheckPointListForPlayer(player, nListCps, delay, markerID, markerSize, nEvent);
|
||||||
listHandle.Add(playerHandle);
|
listHandle.Add(playerHandle);
|
||||||
|
|
||||||
playerHandle.StartRoute();
|
playerHandle.StartRoute();
|
||||||
@@ -50,23 +50,25 @@ namespace ReallifeGamemode.Server.Util
|
|||||||
public Client player;
|
public Client player;
|
||||||
public int delay = 0;
|
public int delay = 0;
|
||||||
public int markerID;
|
public int markerID;
|
||||||
|
public int markerSize;
|
||||||
public string eventInCheckpoint = "";
|
public string eventInCheckpoint = "";
|
||||||
|
|
||||||
int checkPointsDone = 0;
|
int checkPointsDone = 0;
|
||||||
|
|
||||||
public CheckPointListForPlayer(Client nPlayer, IEnumerable<Vector3> nList, int nDelay, int nMarkerID, string nEvent)
|
public CheckPointListForPlayer(Client nPlayer, IEnumerable<Vector3> nList, int nDelay, int nMarkerID, int nMarkerSize, string nEvent)
|
||||||
{
|
{
|
||||||
this.player = nPlayer;
|
this.player = nPlayer;
|
||||||
this.list = nList;
|
this.list = nList;
|
||||||
this.delay = nDelay;
|
this.delay = nDelay;
|
||||||
this.markerID = nMarkerID;
|
this.markerID = nMarkerID;
|
||||||
|
this.markerSize = nMarkerSize;
|
||||||
this.eventInCheckpoint = nEvent;
|
this.eventInCheckpoint = nEvent;
|
||||||
this.checkPointsDone = 0;
|
this.checkPointsDone = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StartRoute()
|
public void StartRoute()
|
||||||
{
|
{
|
||||||
player.TriggerEvent("setCheckPoint", this.list.ElementAt(0), player, 0, this.delay, this.markerID, this.eventInCheckpoint);
|
player.TriggerEvent("setCheckPoint", this.list.ElementAt(0), player, 0, this.delay, this.markerID, this.markerSize, this.eventInCheckpoint);
|
||||||
}
|
}
|
||||||
public void NextCheckpoint()
|
public void NextCheckpoint()
|
||||||
{
|
{
|
||||||
@@ -74,12 +76,10 @@ namespace ReallifeGamemode.Server.Util
|
|||||||
if (this.list.Count() > checkPointsDone)
|
if (this.list.Count() > checkPointsDone)
|
||||||
{
|
{
|
||||||
Vector3 nextCp = list.ElementAt(checkPointsDone);
|
Vector3 nextCp = list.ElementAt(checkPointsDone);
|
||||||
this.player.TriggerEvent("setCheckPoint", nextCp, player, this.checkPointsDone, delay, this.markerID, this.eventInCheckpoint);
|
this.player.TriggerEvent("setCheckPoint", nextCp, player, this.checkPointsDone, delay, this.markerID, this.markerSize, this.eventInCheckpoint);
|
||||||
}
|
}
|
||||||
if (this.list.Count() == checkPointsDone)
|
if (this.list.Count() == checkPointsDone)
|
||||||
{
|
{
|
||||||
ChatService.SendMessage(this.player, "Du hast alle Checkpoints abgefahren!");
|
|
||||||
|
|
||||||
CheckPointHandle.RemovePlayerHandlerFromList(this.player);
|
CheckPointHandle.RemovePlayerHandlerFromList(this.player);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user