commit 92d76ed67c55fbef446333831773d5a8af8d8e1b Author: Jérémie N'gadi Date: Tue Sep 19 10:29:42 2017 +0200 chore(repo): Initial commit diff --git a/README.md b/README.md new file mode 100644 index 00000000..8000ed26 --- /dev/null +++ b/README.md @@ -0,0 +1,22 @@ +# esx_dmvschool +FXServer ESX DMV SChool + +[INSTALLATION] + +1) Using [fvm](https://github.com/qlaffont/fvm-installer) +``` +fvm install --save --folder=esx esx-org/esx_dmvschool +``` + +2) Manually + +- Download https://github.com/ESX-Org/esx_dmvschool/releases/latest +- Put it in [esx] directory + + +1) Import esx_dmvschool.sql in your database +2) Add this in your server.cfg : + +``` +start esx_dmvschool +``` diff --git a/__resource.lua b/__resource.lua new file mode 100644 index 00000000..23906bda --- /dev/null +++ b/__resource.lua @@ -0,0 +1,27 @@ +resource_manifest_version '44febabe-d386-4d18-afbe-5e627f4af937' + +description 'ESX DMV School' + +version '1.0.0' + +server_scripts { + 'server/main.lua' +} + +client_scripts { + 'config.lua', + 'client/main.lua' +} + +ui_page 'html/ui.html' + +files { + 'html/ui.html', + 'html/logo.png', + 'html/dmv.png', + 'html/cursor.png', + 'html/styles.css', + 'html/questions.js', + 'html/scripts.js', + 'html/debounce.min.js' +} \ No newline at end of file diff --git a/client/main.lua b/client/main.lua new file mode 100644 index 00000000..96b9eee0 --- /dev/null +++ b/client/main.lua @@ -0,0 +1,454 @@ +local Keys = { + ["ESC"] = 322, ["F1"] = 288, ["F2"] = 289, ["F3"] = 170, ["F5"] = 166, ["F6"] = 167, ["F7"] = 168, ["F8"] = 169, ["F9"] = 56, ["F10"] = 57, + ["~"] = 243, ["1"] = 157, ["2"] = 158, ["3"] = 160, ["4"] = 164, ["5"] = 165, ["6"] = 159, ["7"] = 161, ["8"] = 162, ["9"] = 163, ["-"] = 84, ["="] = 83, ["BACKSPACE"] = 177, + ["TAB"] = 37, ["Q"] = 44, ["W"] = 32, ["E"] = 38, ["R"] = 45, ["T"] = 245, ["Y"] = 246, ["U"] = 303, ["P"] = 199, ["["] = 39, ["]"] = 40, ["ENTER"] = 18, + ["CAPS"] = 137, ["A"] = 34, ["S"] = 8, ["D"] = 9, ["F"] = 23, ["G"] = 47, ["H"] = 74, ["K"] = 311, ["L"] = 182, + ["LEFTSHIFT"] = 21, ["Z"] = 20, ["X"] = 73, ["C"] = 26, ["V"] = 0, ["B"] = 29, ["N"] = 249, ["M"] = 244, [","] = 82, ["."] = 81, + ["LEFTCTRL"] = 36, ["LEFTALT"] = 19, ["SPACE"] = 22, ["RIGHTCTRL"] = 70, + ["HOME"] = 213, ["PAGEUP"] = 10, ["PAGEDOWN"] = 11, ["DELETE"] = 178, + ["LEFT"] = 174, ["RIGHT"] = 175, ["TOP"] = 27, ["DOWN"] = 173, + ["NENTER"] = 201, ["N4"] = 108, ["N5"] = 60, ["N6"] = 107, ["N+"] = 96, ["N-"] = 97, ["N7"] = 117, ["N8"] = 61, ["N9"] = 118 +} + +ESX = nil +local CurrentAction = nil +local CurrentActionMsg = nil +local CurrentActionData = nil +local Licenses = {} +local CurrentTest = nil +local CurrentTestType = nil +local CurrentVehicle = nil +local CurrentCheckPoint = 0 +local LastCheckPoint = -1 +local CurrentBlip = nil +local CurrentZoneType = nil +local DriveErrors = 0 +local IsAboveSpeedLimit = false +local LastVehicleHealth = nil + +Citizen.CreateThread(function() + while ESX == nil do + TriggerEvent('esx:getSharedObject', function(obj) ESX = obj end) + Citizen.Wait(0) + end +end) + +function DrawMissionText(msg, time) + ClearPrints() + SetTextEntry_2('STRING') + AddTextComponentString(msg) + DrawSubtitleTimed(time, 1) +end + +function StartTheoryTest() + + CurrentTest = 'theory' + + SendNUIMessage({ + openQuestion = true + }) + + ESX.SetTimeout(200, function() + SetNuiFocus(true, true) + end) + + TriggerServerEvent('esx_dmvschool:pay', Config.Prices['dmv']) + +end + +function StopTheoryTest(success) + + CurrentTest = nil + + SendNUIMessage({ + openQuestion = false + }) + + SetNuiFocus(false) + + if success then + TriggerServerEvent('esx_dmvschool:addLicense', 'dmv') + ESX.ShowNotification('Vous avez ~g~réussi~s~ le test') + else + ESX.ShowNotification('Vous avez ~r~raté~s~ le test') + end + +end + +function StartDriveTest(type) + + + ESX.Game.SpawnVehicle(Config.VehicleModels[type], Config.Zones.VehicleSpawnPoint.Pos, 317.0, function(vehicle) + + CurrentTest = 'drive' + CurrentTestType = type + CurrentCheckPoint = 0 + LastCheckPoint = -1 + CurrentZoneType = 'residence' + DriveErrors = 0 + IsAboveSpeedLimit = false + CurrentVehicle = vehicle + LastVehicleHealth = GetEntityHealth(vehicle) + local playerPed = GetPlayerPed(-1) + + TaskWarpPedIntoVehicle(playerPed, vehicle, -1) + end) + + TriggerServerEvent('esx_dmvschool:pay', Config.Prices[type]) + +end + +function StopDriveTest(success) + + if success then + TriggerServerEvent('esx_dmvschool:addLicense', CurrentTestType) + ESX.ShowNotification('Vous avez ~g~réussi~s~ le test') + else + ESX.ShowNotification('Vous avez ~r~raté~s~ le test') + end + + CurrentTest = nil + CurrentTestType = nil + +end + +function SetCurrentZoneType(type) + CurrentZoneType = type +end + +function OpenDMVSchoolMenu() + + local ownedLicenses = {} + + for i=1, #Licenses, 1 do + ownedLicenses[Licenses[i].type] = true + end + + local elements = {} + + if not ownedLicenses['dmv'] then + table.insert(elements, {label = 'Examen du code $' .. Config.Prices['dmv'], value = 'theory_test'}) + end + + if ownedLicenses['dmv'] then + + if not ownedLicenses['drive'] then + table.insert(elements, {label = 'Examen de conduite [voiture] $' .. Config.Prices['drive'], value = 'drive_test', type = 'drive'}) + end + + if not ownedLicenses['drive_bike'] then + table.insert(elements, {label = 'Examen de conduite [moto] $' .. Config.Prices['drive_bike'], value = 'drive_test', type = 'drive_bike'}) + end + + if not ownedLicenses['drive_truck'] then + table.insert(elements, {label = 'Examen de conduite [camion] $' .. Config.Prices['drive_truck'], value = 'drive_test', type = 'drive_truck'}) + end + + end + + ESX.UI.Menu.CloseAll() + + ESX.UI.Menu.Open( + 'default', GetCurrentResourceName(), 'dmvschool_actions', + { + title = 'Ecole de conduite', + elements = elements + }, + function(data, menu) + + if data.current.value == 'theory_test' then + menu.close() + StartTheoryTest() + end + + if data.current.value == 'drive_test' then + menu.close() + StartDriveTest(data.current.type) + end + + end, + function(data, menu) + + menu.close() + + CurrentAction = 'dmvschool_menu' + CurrentActionMsg = 'Appuyez sur ~INPUT_CONTEXT~ pour ouvrir le menu' + CurrentActionData = {} + + end + ) + +end + +RegisterNUICallback('question', function(data, cb) + + SendNUIMessage({ + openSection = 'question' + }) + + cb('OK') +end) + +RegisterNUICallback('close', function(data, cb) + StopTheoryTest(true) + cb('OK') +end) + +RegisterNUICallback('kick', function(data, cb) + StopTheoryTest(false) + cb('OK') +end) + +AddEventHandler('esx_dmvschool:hasEnteredMarker', function(zone) + + if zone == 'DMVSchool' then + + CurrentAction = 'dmvschool_menu' + CurrentActionMsg = 'Appuyez sur ~INPUT_CONTEXT~ pour ouvrir le menu' + CurrentActionData = {} + + end + +end) + +AddEventHandler('esx_dmvschool:hasExitedMarker', function(zone) + CurrentAction = nil + ESX.UI.Menu.CloseAll() +end) + +RegisterNetEvent('esx_dmvschool:loadLicenses') +AddEventHandler('esx_dmvschool:loadLicenses', function(licenses) + Licenses = licenses +end) + +-- Create Blips +Citizen.CreateThread(function() + + local blip = AddBlipForCoord(Config.Zones.DMVSchool.Pos.x, Config.Zones.DMVSchool.Pos.y, Config.Zones.DMVSchool.Pos.z) + + SetBlipSprite (blip, 408) + SetBlipDisplay(blip, 4) + SetBlipScale (blip, 1.2) + SetBlipAsShortRange(blip, true) + + BeginTextCommandSetBlipName("STRING") + AddTextComponentString("Auto-école") + EndTextCommandSetBlipName(blip) + +end) + +-- Display markers +Citizen.CreateThread(function() + while true do + + Citizen.Wait(0) + + local coords = GetEntityCoords(GetPlayerPed(-1)) + + for k,v in pairs(Config.Zones) do + if(v.Type ~= -1 and GetDistanceBetweenCoords(coords, v.Pos.x, v.Pos.y, v.Pos.z, true) < Config.DrawDistance) then + DrawMarker(v.Type, v.Pos.x, v.Pos.y, v.Pos.z, 0.0, 0.0, 0.0, 0, 0.0, 0.0, v.Size.x, v.Size.y, v.Size.z, v.Color.r, v.Color.g, v.Color.b, 100, false, true, 2, false, false, false, false) + end + end + + end +end) + +-- Enter / Exit marker events +Citizen.CreateThread(function() + while true do + + Citizen.Wait(0) + + local coords = GetEntityCoords(GetPlayerPed(-1)) + local isInMarker = false + local currentZone = nil + + for k,v in pairs(Config.Zones) do + if(GetDistanceBetweenCoords(coords, v.Pos.x, v.Pos.y, v.Pos.z, true) < v.Size.x) then + isInMarker = true + currentZone = k + end + end + + if (isInMarker and not HasAlreadyEnteredMarker) or (isInMarker and LastZone ~= currentZone) then + HasAlreadyEnteredMarker = true + LastZone = currentZone + TriggerEvent('esx_dmvschool:hasEnteredMarker', currentZone) + end + + if not isInMarker and HasAlreadyEnteredMarker then + HasAlreadyEnteredMarker = false + TriggerEvent('esx_dmvschool:hasExitedMarker', LastZone) + end + + end +end) + +-- Block UI +Citizen.CreateThread(function() + while true do + + Citizen.Wait(0) + + if CurrentTest == 'theory' then + + local playerPed = GetPlayerPed(-1) + + DisableControlAction(0, 1, true) -- LookLeftRight + DisableControlAction(0, 2, true) -- LookUpDown + DisablePlayerFiring(playerPed, true) -- Disable weapon firing + DisableControlAction(0, 142, true) -- MeleeAttackAlternate + DisableControlAction(0, 106, true) -- VehicleMouseControlOverride + + end + + end +end) + +-- Key Controls +Citizen.CreateThread(function() + while true do + + Citizen.Wait(0) + + if CurrentAction ~= nil then + + SetTextComponentFormat('STRING') + AddTextComponentString(CurrentActionMsg) + DisplayHelpTextFromStringLabel(0, 0, 1, -1) + + if IsControlJustReleased(0, Keys['E']) then + + if CurrentAction == 'dmvschool_menu' then + OpenDMVSchoolMenu() + end + + CurrentAction = nil + + end + + end + + end +end) + +-- Drive test +Citizen.CreateThread(function() + while true do + + Citizen.Wait(0) + + if CurrentTest == 'drive' then + + local playerPed = GetPlayerPed(-1) + local coords = GetEntityCoords(playerPed) + local nextCheckPoint = CurrentCheckPoint + 1 + + if Config.CheckPoints[nextCheckPoint] == nil then + + if DoesBlipExist(CurrentBlip) then + RemoveBlip(CurrentBlip) + end + + CurrentTest = nil + + ESX.ShowNotification('Test de conduite terminé') + + if DriveErrors < Config.MaxErrors then + StopDriveTest(true) + else + StopDriveTest(false) + end + + else + + if CurrentCheckPoint ~= LastCheckPoint then + + if DoesBlipExist(CurrentBlip) then + RemoveBlip(CurrentBlip) + end + + CurrentBlip = AddBlipForCoord(Config.CheckPoints[nextCheckPoint].Pos.x, Config.CheckPoints[nextCheckPoint].Pos.y, Config.CheckPoints[nextCheckPoint].Pos.z) + SetBlipRoute(CurrentBlip, 1) + + LastCheckPoint = CurrentCheckPoint + + end + + local distance = GetDistanceBetweenCoords(coords, Config.CheckPoints[nextCheckPoint].Pos.x, Config.CheckPoints[nextCheckPoint].Pos.y, Config.CheckPoints[nextCheckPoint].Pos.z, true) + + if distance <= 100.0 then + DrawMarker(1, Config.CheckPoints[nextCheckPoint].Pos.x, Config.CheckPoints[nextCheckPoint].Pos.y, Config.CheckPoints[nextCheckPoint].Pos.z, 0.0, 0.0, 0.0, 0, 0.0, 0.0, 1.5, 1.5, 1.5, 102, 204, 102, 100, false, true, 2, false, false, false, false) + end + + if distance <= 3.0 then + Config.CheckPoints[nextCheckPoint].Action(playerPed, CurrentVehicle, SetCurrentZoneType) + CurrentCheckPoint = CurrentCheckPoint + 1 + end + + end + + end + + end +end) + +-- Speed / Damage control +Citizen.CreateThread(function() + while true do + + Citizen.Wait(0) + + if CurrentTest == 'drive' then + + local playerPed = GetPlayerPed(-1) + + if IsPedInAnyVehicle(playerPed, false) then + + local vehicle = GetVehiclePedIsIn(playerPed, false) + local speed = GetEntitySpeed(vehicle) * Config.SpeedMultiplier + local tooMuchSpeed = false + + for k,v in pairs(Config.SpeedLimits) do + if CurrentZoneType == k and speed > v then + + tooMuchSpeed = true + + if not IsAboveSpeedLimit then + + DriveErrors = DriveErrors + 1 + IsAboveSpeedLimit = true + + ESX.ShowNotification('Vous roulez trop vite, vitesse limite : ~y~' .. v .. 'km/h') + ESX.ShowNotification('Erreurs : ~r~' .. DriveErrors .. '~s~/' .. Config.MaxErrors) + + end + + end + end + + if not tooMuchSpeed then + IsAboveSpeedLimit = false + end + + local health = GetEntityHealth(vehicle) + + if health < LastVehicleHealth then + + DriveErrors = DriveErrors + 1 + + ESX.ShowNotification('Vous avez endommagé votre véhicule') + ESX.ShowNotification('Erreurs : ~r~' .. DriveErrors .. '~s~/' .. Config.MaxErrors) + + LastVehicleHealth = health + + end + + end + + end + + end + +end) \ No newline at end of file diff --git a/config.lua b/config.lua new file mode 100644 index 00000000..7e864ca6 --- /dev/null +++ b/config.lua @@ -0,0 +1,187 @@ +Config = {} +Config.DrawDistance = 100.0 +Config.MaxErrors = 5 +Config.SpeedMultiplier = 3.6 + +Config.Prices = { + dmv = 200, + drive = 500, + drive_bike = 500, + drive_truck = 500 +} + +Config.VehicleModels = { + drive = 'blista', + drive_bike = 'sanchez', + drive_truck = 'mule3' +} + +Config.SpeedLimits = { + residence = 50, + town = 80, + freeway = 120 +} + +Config.Zones = { + + DMVSchool = { + Pos = {x = 239.471, y = -1380.960, z = 32.741}, + Size = {x = 1.5, y = 1.5, z = 1.0}, + Color = {r = 204, g = 204, b = 0}, + Type = 1 + }, + + VehicleSpawnPoint = { + Pos = {x = 249.409, y = -1407.230, z = 30.4094}, + Size = {x = 1.5, y = 1.5, z = 1.0}, + Color = {r = 204, g = 204, b = 0}, + Type = -1 + }, + +} + +Config.CheckPoints = { + + { + Pos = {x = 255.139, y = -1400.731, z = 29.537}, + Action = function(playerPed, vehicle, setCurrentZoneType) + DrawMissionText('Allez vers le prochain passage ! Vitesse limite : ~y~' .. Config.SpeedLimits['residence'] .. 'km/h', 5000) + end + }, + + { + Pos = {x = 271.874, y = -1370.574, z = 30.932}, + Action = function(playerPed, vehicle, setCurrentZoneType) + DrawMissionText('Allez vers le prochain passage !', 5000) + end + }, + + { + Pos = {x = 234.907, y = -1345.385, z = 29.542}, + Action = function(playerPed, vehicle, setCurrentZoneType) + Citizen.CreateThread(function() + DrawMissionText('Faite rapidement un ~r~stop~s~ pour le piéton qui ~y~traverse', 5000) + PlaySound(-1, 'RACE_PLACED', 'HUD_AWARDS', 0, 0, 1) + FreezeEntityPosition(vehicle, true) + Citizen.Wait(4000) + FreezeEntityPosition(vehicle, false) + DrawMissionText('~g~Bien!~s~ continuons!', 5000) + + end) + end + }, + + { + Pos = {x = 217.821, y = -1410.520, z = 28.292}, + Action = function(playerPed, vehicle, setCurrentZoneType) + + setCurrentZoneType('town') + + Citizen.CreateThread(function() + DrawMissionText('Marquer rapidement un ~r~stop~s~ et regardez à votre ~y~gauche~s~. Vitesse limite : ~y~' .. Config.SpeedLimits['town'] .. 'km/h', 5000) + PlaySound(-1, 'RACE_PLACED', 'HUD_AWARDS', 0, 0, 1) + FreezeEntityPosition(vehicle, true) + Citizen.Wait(6000) + FreezeEntityPosition(vehicle, false) + DrawMissionText('~g~bien!~s~ prenez à ~y~droite~s~ et suivez votre file', 5000) + end) + end + }, + + { + Pos = {x = 178.550, y = -1401.755, z = 27.725}, + Action = function(playerPed, vehicle, setCurrentZoneType) + DrawMissionText('Observez le traffic ~y~allumez vos feux~s~ !', 5000) + end + }, + + { + Pos = {x = 113.160, y = -1365.276, z = 27.725}, + Action = function(playerPed, vehicle, setCurrentZoneType) + DrawMissionText('Allez vers le prochain passage !', 5000) + end + }, + + { + Pos = {x = -73.542, y = -1364.335, z = 27.789}, + Action = function(playerPed, vehicle, setCurrentZoneType) + DrawMissionText('Marquez le stop pour laisser passer les véhicules !', 5000) + PlaySound(-1, 'RACE_PLACED', 'HUD_AWARDS', 0, 0, 1) + FreezeEntityPosition(vehicle, true) + Citizen.Wait(6000) + FreezeEntityPosition(vehicle, false) + end + }, + + { + Pos = {x = -355.143, y = -1420.282, z = 27.868}, + Action = function(playerPed, vehicle, setCurrentZoneType) + DrawMissionText('Allez vers le prochain passage !', 5000) + end + }, + + { + Pos = {x = -439.148, y = -1417.100, z = 27.704}, + Action = function(playerPed, vehicle, setCurrentZoneType) + DrawMissionText('Allez vers le prochain passage !', 5000) + end + }, + + { + Pos = {x = -453.790, y = -1444.726, z = 27.665}, + Action = function(playerPed, vehicle, setCurrentZoneType) + + setCurrentZoneType('freeway') + + DrawMissionText('Il est temps d\'aller sur la rocade ! Vitesse limite : ~y~' .. Config.SpeedLimits['freeway'] .. 'km/h', 5000) + PlaySound(-1, 'RACE_PLACED', 'HUD_AWARDS', 0, 0, 1) + end + }, + + { + Pos = {x = -463.237, y = -1592.178, z = 37.519}, + Action = function(playerPed, vehicle, setCurrentZoneType) + DrawMissionText('Allez vers le prochain passage !', 5000) + end + }, + + { + Pos = {x = -900.647, y = -1986.28, z = 26.109}, + Action = function(playerPed, vehicle, setCurrentZoneType) + DrawMissionText('Allez vers le prochain passage !', 5000) + end + }, + + { + Pos = {x = 1225.759, y = -1948.792, z = 38.718}, + Action = function(playerPed, vehicle, setCurrentZoneType) + DrawMissionText('Allez vers le prochain passage !', 5000) + end + }, + + { + Pos = {x = 1225.759, y = -1948.792, z = 38.718}, + Action = function(playerPed, vehicle, setCurrentZoneType) + + setCurrentZoneType('town') + + DrawMissionText('Entrée en ville, attention à votre vitesse ! Vitesse limite : ~y~' .. Config.SpeedLimits['town'] .. 'km/h', 5000) + end + }, + + { + Pos = {x = 1163.603, y = -1841.771, z = 35.679}, + Action = function(playerPed, vehicle, setCurrentZoneType) + DrawMissionText('Bravo, restez vigilant!', 5000) + PlaySound(-1, 'RACE_PLACED', 'HUD_AWARDS', 0, 0, 1) + end + }, + + { + Pos = {x = 235.283, y = -1398.329, z = 28.921}, + Action = function(playerPed, vehicle, setCurrentZoneType) + ESX.Game.DeleteVehicle(vehicle) + end + }, + +} \ No newline at end of file diff --git a/esx_dmvschool.sql b/esx_dmvschool.sql new file mode 100644 index 00000000..330e1ac7 --- /dev/null +++ b/esx_dmvschool.sql @@ -0,0 +1,7 @@ +USE `essentialmode`; + +INSERT INTO `licenses` (`type`, `label`) VALUES + ('drive', 'Permis de conduire'), + ('drive_bike', 'Permis moto'), + ('drive_truck', 'Permis camion') +; \ No newline at end of file diff --git a/html/badge.png b/html/badge.png new file mode 100644 index 00000000..0f365628 Binary files /dev/null and b/html/badge.png differ diff --git a/html/cursor.png b/html/cursor.png new file mode 100644 index 00000000..d36ad801 Binary files /dev/null and b/html/cursor.png differ diff --git a/html/debounce.min.js b/html/debounce.min.js new file mode 100644 index 00000000..648fe5d3 --- /dev/null +++ b/html/debounce.min.js @@ -0,0 +1,9 @@ +/* + * jQuery throttle / debounce - v1.1 - 3/7/2010 + * http://benalman.com/projects/jquery-throttle-debounce-plugin/ + * + * Copyright (c) 2010 "Cowboy" Ben Alman + * Dual licensed under the MIT and GPL licenses. + * http://benalman.com/about/license/ + */ +(function(b,c){var $=b.jQuery||b.Cowboy||(b.Cowboy={}),a;$.throttle=a=function(e,f,j,i){var h,d=0;if(typeof f!=="boolean"){i=j;j=f;f=c}function g(){var o=this,m=+new Date()-d,n=arguments;function l(){d=+new Date();j.apply(o,n)}function k(){h=c}if(i&&!h){l()}h&&clearTimeout(h);if(i===c&&m>e){l()}else{if(f!==true){h=setTimeout(i?k:l,i===c?e-m:e)}}}if($.guid){g.guid=j.guid=j.guid||$.guid++}return g};$.debounce=function(d,e,f){return f===c?a(d,e,false):a(d,f,e!==false)}})(this); diff --git a/html/dmv.png b/html/dmv.png new file mode 100644 index 00000000..b5cf951f Binary files /dev/null and b/html/dmv.png differ diff --git a/html/questions.js b/html/questions.js new file mode 100644 index 00000000..2c1ae9cb --- /dev/null +++ b/html/questions.js @@ -0,0 +1,71 @@ +var tableauQuestion = [ + { question : "Si vous conduisez à 80km/h, que vous approchez d'un lieu de résidence, cela veut dire que :", + propositionA : "Vous devez accélérer", + propositionB : "Vous pouvez garder votre vitesse, si vous ne croisez pas d'autres véhicules", + propositionC : "Vous devez ralentir", + propositionD : "Vous pouvez garder votre vitesse", + reponse : "C"}, + + { question : "Vous vous apprétez à tourner à droite au feu vert, mais vous voyez un piéton qui traverse :", + propositionA : "Vous passez avant le piéton", + propositionB : "Vous vérifiez qu'il n'y a pas d'autre véhicule et vous passez", + propositionC : "Vous attendez que le piéton est terminé", + propositionD : "Vous shoutez le piéton pour passer", + reponse : "C"}, + + { question : "Sans aucune indication : La vitesse dans une zone résidentielle est de : __ km/h", + propositionA : "50", + propositionB : "55", + propositionC : "65", + propositionD : "70", + reponse : "A"}, + + { question : "Avant chaque changement de file vous devez :", + propositionA : "Vérifiez vos rétroviseurs", + propositionB : "Vérifiez vos angles morts", + propositionC : "Signalez vos intentions", + propositionD : "Tout cela", + reponse : "D"}, + + { question : "What blood alcohol level is classified as driving while intoxicated?", + propositionA : "0.05%", + propositionB : "0.18%", + propositionC : "0.08%", + propositionD : "0.06%", + reponse : "C"}, + + { question : "A quel moment vous pouvez passer aux feux ?", + propositionA : "Quand il est vert", + propositionB : "Quand il n'y a personne sur l'intersection", + propositionC : "Vous êtes dans une zone d'école", + propositionD : "Quand il est vert et/ou rouge et que je tourne à droite", + reponse : "D"}, + + { question : "Un piéton est au feu rouge pour les piétons", + propositionA : "Vous le laissez passer", + propositionB : "Vous observez avant de continuer", + propositionC : "Vous lui faite un signe de la main", + propositionD : "Vous continuez votre chemin car votre feu est vert", + reponse : "D"}, + + { question : "Qu'est ce qui est permit quand vous dépassez un autre véhicule", + propositionA : "Le suivre de près pour le doubler plus vite", + propositionB : "Le doubler en quittant la route", + propositionC : "Conduire sur la route opposé pour le dépasser", + propositionD : "Dépasser la vitesse limite", + reponse : "C"}, + + { question : "Vous conduisez sur une rocade qui indique une vitesse maximum de 110 km/h. La plupart du traffic roule à 120 km/h, alors vous ne devriez pas conduire plus vite que :", + propositionA : "80 kmh", + propositionB : "40 kmh", + propositionC : "50 kmh", + propositionD : "110 kmh", + reponse : "D"}, + + { question : "Quand vous êtes dépassé par un autre véhicule il est important de ne PAS :", + propositionA : "Ralentir", + propositionB : "Vérifiez vos rétroviseurs", + propositionC : "Regarder les autres conducteurs", + propositionD : "Augmenter votre vitesse", + reponse : "D"}, +] diff --git a/html/scripts.js b/html/scripts.js new file mode 100644 index 00000000..6494266f --- /dev/null +++ b/html/scripts.js @@ -0,0 +1,144 @@ +// Mouse Controls +var documentWidth = document.documentElement.clientWidth; +var documentHeight = document.documentElement.clientHeight; +var cursor = $('#cursor'); +var cursorX = documentWidth / 2; +var cursorY = documentHeight / 2; + +//question variables +var questionNumber = 1; +var userAnswer = []; +var goodAnswer = []; +var questionUsed = []; +var nbQuestionToAnswer = 10; // don't forget to change the progress bar max value in html +var nbAnswerNeeded = 1; // out of nbQuestionToAnswer +var nbPossibleQuestions = 10; //number of questions in database questions.js +var lastClick = 0; +/* +var nbQuestionToAnswer = 10; // don't forget to change the progress bar max value in html +var nbAnswerNeeded = 8; // out of nbQuestionToAnswer +var nbPossibleQuestions = 15; //number of questions in database questions.js +*/ + +function getRandomQuestion() { + var continuer = true; + var random; + while (continuer){ + continuer=false; // do not continue loop + random = Math.floor(Math.random() * nbPossibleQuestions) ; // number of possible questions + if(questionNumber==1){ + return random; + } + for(i=0; i= nbAnswerNeeded) { + openResultGood(); + } + else{ + openResultBad(); + } + } + + return false; + +}); diff --git a/html/styles.css b/html/styles.css new file mode 100644 index 00000000..4b6a8e51 --- /dev/null +++ b/html/styles.css @@ -0,0 +1,191 @@ +html { + overflow: hidden; + font-family: 'Open Sans', sans-serif; +} + +#cursor { + position: absolute; + z-index: 99999999; + display: none; +} + +.full-screen { + width: 100%; + height:100%; + display: flex; + align-items: center; +} + +.question-container { + width: 70%; + height: 700px; + background-color: #fff; + border: 1px solid #222; + border-radius: 1px; + margin-left: auto; + margin-right: auto; + overflow: hidden; + z-index: 9999999; + display: none; +} + +.header { + width:100%; + height: 20%; + background-color: #eee; + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: center; +} + +.header .logo { + width: 80%; + max-height: 50%; + margin: auto; + margin-bottom: 0; +} + +.header h1 { + font-size: 2em; + text-align: center; + margin:auto; +} + +.body { + width: 100%; + height: 80%; + display: flex; + flex-direction: row; + flex-wrap: wrap; + display: none; +} + +.content { + display: flex; + flex-direction: column; + align-self: center; + width: 90%; + height: 70%; + margin: auto; + border:none; +} + +.content .logo { + width: auto; + max-height: auto; + margin: auto; + margin-bottom: 0; +} + +.content h2, p { + margin: 5px; +} + +.buttonspot { + display: flex; + flex-direction: column; + align-self: center; + width: auto; + height: 15%; + margin: auto; + border:none; +} + +.buttonspot h2, p { + margin: 5px; +} + +.button { + width: 30%; + height: 40px; + align-self: center; + text-align: center; + margin-left: 40px; + margin-right: 40px; + background: #6699ff; + background-image: linear-gradient(to bottom, #6699ff, #4d88ff); + border-radius: 4px; + color: #ffffff; + font-size: 1.5em; + text-decoration: none; +} + + +.form { + display: flex; + flex-direction: row; + justify-content: center; + flex-wrap: wrap; + width: 100%; + margin-top:5px; +} + +.form div { + margin :auto; + margin-top:5px; + margin-bottom: 5px; + width: 100%; +} + +.submit{ + align-items: center; + height: 30px; + text-align: center; + width: 30%; + background: #017ebc; + background-image: linear-gradient(to bottom, #6699ff, #4d88ff); + border-radius: 4px; + color: #fff; + font-size: 1.2em; + margin-top: 10px; +} + +.barre-progression { + width: 50%; + align-self: center; + height: 10%; + margin: auto; + margin-top: 0; + display: flex; + flex-wrap: wrap; + justify-content: center; + padding: 0; +} + +.barre-progression h2{ + width: 100%; + height: 60%; + text-align: center; + display: flex; + justify-content: center; + align-items: center; + margin:0; + color: #6699ff; +} + +.progression { + width: 80%; + border: 0 none; + background: #ddd; + border-radius: 14px; + box-shadow: inset 0px 1px 1px rgba(0,0,0,0.5), 0px 1px 0px rgba(255,255,255,0.2); +} +.progression::-moz-progress-bar { + background: #FFF; + border-radius: 14px; + box-shadow: inset 0 -2px 4px rgba(0,0,0,0.4), 0 2px 5px 0px rgba(0,0,0,0.3); +} +.progression::-webkit-progress-bar { + background: transparent; +} +.progression::-webkit-progress-value { + background-image: linear-gradient(to bottom, #6699ff, #4d88ff); + border-radius: 14px; + box-shadow: inset 0 -2px 4px rgba(0,0,0,0.4), 0 2px 5px 0px rgba(0,0,0,0.3); +} + +.bold-text{ + font-weight: bold; + font-size: 1.3em; +} \ No newline at end of file diff --git a/html/ui.html b/html/ui.html new file mode 100644 index 00000000..53446a50 --- /dev/null +++ b/html/ui.html @@ -0,0 +1,102 @@ + + + + + + +
+
+ +
+

Auto-école

+
+ +
+
+ +

Bienvenu à votre Auto-école

+
Tous les citoyens de Los Santos doivent réussir leur examen de code avant de pouvoir conduire.
Prenez votre temps, répondez avec du bon sens, ne répondez pas au hasard.

+ Examen de Code
+ - L'examen de code coute 200$, cela n'est pas remboursé si vous échouez.
+ - N'ayez pas peur, l'auto-école accepte les crédits, mais faite attention à ne pas vous endetter
+ - Si vous loupez votre test une première fois, vous ne pouvez pas le repasser de suite, vous devrez le retenter un autre jour.

+ Examen de Conduite
+ - L'examen de Conduite coute 500$, comme pour l'examen de code, ce paiement ne vous sera pas remboursé si vous échoué.
+ - La chose principale pour votre permis c'est de faire attention à ce qui vous entoure et surtout éviter les accidents !

+
+
+ Démarrer +
+
+

Progrès

+ +
+
+ +
+
+

+

+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ +
+
+
+

Progrès

+ +
+
+ +
+
+

Bon travail !



Vous avez bien travaillé durant l'examen!

Vous pouvez maintenant fermer cette fenètre et passer à l'examen.
+
+
+ Fermer +
+
+

Progrès

+ +
+
+
+
+

Vous avez échoué



Vous n'êtes pas prêt pour ce test, essayez une nouvelle fois, plus tard...

+
+
+ Fermer +
+
+

Progrès

+ +
+
+
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/server/main.lua b/server/main.lua new file mode 100644 index 00000000..d81d4daa --- /dev/null +++ b/server/main.lua @@ -0,0 +1,34 @@ +ESX = nil + +TriggerEvent('esx:getSharedObject', function(obj) ESX = obj end) + +AddEventHandler('esx:playerLoaded', function(source) + TriggerEvent('esx_license:getLicenses', source, function(licenses) + TriggerClientEvent('esx_dmvschool:loadLicenses', source, licenses) + end) +end) + +RegisterNetEvent('esx_dmvschool:addLicense') +AddEventHandler('esx_dmvschool:addLicense', function(type) + + local _source = source + + TriggerEvent('esx_license:addLicense', _source, type, function() + TriggerEvent('esx_license:getLicenses', _source, function(licenses) + TriggerClientEvent('esx_dmvschool:loadLicenses', _source, licenses) + end) + end) + +end) + +RegisterNetEvent('esx_dmvschool:pay') +AddEventHandler('esx_dmvschool:pay', function(price) + + local _source = source + local xPlayer = ESX.GetPlayerFromId(_source) + + xPlayer.removeMoney(price) + + TriggerClientEvent('esx:showNotification', _source, 'Vous avez payé ~g~$' .. price) + +end)