diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..0a0b726 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,6 @@ +## 1.0 + +- Added support for NativeUILua. +- Added support for EssentialMode. +- Added blips for **Los Santos International Airport** and **Sandy Shores Airfield.** +- Players can travel from **Los Santos International Airport** to **Sandy Shores Airfield.**. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..beba45d --- /dev/null +++ b/README.md @@ -0,0 +1,19 @@ +# FiveM Airports +[![GitHub release](https://img.shields.io/github/release/Fivem-Scripts/airports.svg)](https://github.com/FiveM-Scripts/airports/releases/latest) +[![GitHub license](https://img.shields.io/github/license/FiveM-Scripts/airports.svg)](https://github.com/FiveM-Scripts/airports/blob/master/LICENSE) +Discord Status + +With this resource players can fly from **Los Santos International Airport** to **Sandy Shores Airfield** and back. + +## Requirements +- [NativeUILua](https://github.com/FrazzIe/NativeUILua) +- [Essentialmode](https://forum.fivem.net/t/release-essentialmode-base/3665) (optional) + +## Installation +1. Download the latest [release](https://github.com/FiveM-Scripts/airports/releases) +2. Extract the files to `resources/airports` +3. Add `start airports` to your **server.cfg** +4. (re)start your server. + +## Changelog +You can find the changelog [here](https://github.com/FiveM-Scripts/airports/CHANGELOG.md). \ No newline at end of file diff --git a/__resource.lua b/__resource.lua new file mode 100644 index 0000000..790af48 --- /dev/null +++ b/__resource.lua @@ -0,0 +1,19 @@ +resource_manifest_version '05cfa83c-a124-4cfa-a768-c24a5811d8f9' +resource_version '1.0' + +dependency 'NativeUI' + +client_script '@NativeUI/NativeUI.lua' + +client_scripts { + 'config.lua', + 'client/spawn.lua', + 'client/menu.lua', + 'client/airports.lua', + 'client/client.lua' +} + +server_script { + 'config.lua', + 'server/server.lua' +} \ No newline at end of file diff --git a/client/airports.lua b/client/airports.lua new file mode 100644 index 0000000..4016f39 --- /dev/null +++ b/client/airports.lua @@ -0,0 +1,61 @@ +--[[ + FiveM Airports + Copyright (C) 2018 FiveM-Scripts + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. +You should have received a copy of the GNU Affero General Public License +along with this resource in the file "LICENSE". If not, see . +]] + +StarPoints = { + {x= -1030.8077, y= -2493.35766, z=20.16929, desc="Los Santos International"}, + {x= 1752.15, y= 3290.56, z= 41.1109, desc="Sandy shores"} +} + +local function CreateAirportBlips() + for k,v in pairs(StarPoints) do + blip = AddBlipForCoord(v.x, v.y, v.z-1) + SetBlipSprite(blip, 90) + SetBlipAsShortRange(blip, true) + + BeginTextCommandSetBlipName("STRING") + AddTextComponentString("Airport") + EndTextCommandSetBlipName(blip) + end +end + +function IsPlayerNearAirport() + for k,v in pairs(StarPoints) do + if GetDistanceBetweenCoords(GetEntityCoords(PlayerPedId(), true), v.x, v.y, v.z, true) < 80.0 then + if not IsPedInAnyPlane(PlayerPedId()) then + if not _menuPool:IsAnyMenuOpen() then + DrawMarker(1, v.x, v.y, v.z-1.0001, 0, 0, 0, 0, 0, 0, 2.0, 2.0, 2.0, 255, 219, 77, 155, 0, 0, 2, 0, 0, 0, 0) + end + end + end + + if GetDistanceBetweenCoords(GetEntityCoords(PlayerPedId(), true), v.x, v.y, v.z, true) < 2.0 then + if not _menuPool:IsAnyMenuOpen() then + if not IsHelpMessageBeingDisplayed() then + BeginTextCommandDisplayHelp("STRING") + AddTextComponentSubstringPlayerName("Press ~INPUT_CONTEXT~ to travel.") + EndTextCommandDisplayHelp(0, 0, 1, -1) + end + else + ClearAllHelpMessages() + end + return true + end + end +end + +Citizen.CreateThread(function() + CreateAirportBlips() +end) \ No newline at end of file diff --git a/client/client.lua b/client/client.lua new file mode 100644 index 0000000..eccfb1d --- /dev/null +++ b/client/client.lua @@ -0,0 +1,96 @@ +--[[ + FiveM Airports + Copyright (C) 2018 FiveM-Scripts + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. +You should have received a copy of the GNU Affero General Public License +along with this resource in the file "LICENSE". If not, see . +]] + +Citizen.CreateThread(function() + while true do + Citizen.Wait(0) + if IsPlayerNearAirport() then + if IsControlJustPressed(0, 38) then + if not IsPlayerWantedLevelGreater(PlayerId(), 0) then + mainMenu:Visible(not mainMenu:Visible()) + else + if IsHelpMessageBeingDisplayed() then + ClearAllHelpMessages() + end + + BeginTextCommandDisplayHelp("STRING") + AddTextComponentSubstringPlayerName("Lose the Cops") + EndTextCommandDisplayHelp(0, 0, 1, -1) + end + end + else + if _menuPool:IsAnyMenuOpen() then + mainMenu:Visible(not mainMenu:Visible()) + end + end + + if not landing then + if IsEntityInAir(AirPlane) then + SetVehicleLandingGear(AirPlane, 1) + end + + if startZone == "AIRP" and planeDest == "DESRT" then + if IsEntityInZone(AirPlane, "DESRT") or IsEntityInZone(PlayerPedId(), "GREATC") then + TaskPlaneLand(pilot, AirPlane, 881.4462, 3060.4829, 41.1682+10.0001, 1657.07, 3238.21, 40.5669+1.0001) + SetPedKeepTask(pilot, true) + landing = true + end + elseif startZone == "DESRT" and planeDest == "AIRP" then + if IsEntityInZone(AirPlane, "RICHM") or IsEntityInZone(AirPlane, "OCEANA") then + TaskPlaneLand(pilot, AirPlane, -1792.00122, -2882.29980, 13.9440+1.0001, -998.5266, -3341.3579, 13.9444+1.0001) + SetPedKeepTask(pilot, true) + landing = true + end + end + end + + if not IsEntityInZone(PlayerPedId(), startZone) then + if not IsEntityInAir(AirPlane) and IsPedInAnyPlane(PlayerPedId()) then + TaskVehicleTempAction(pilot, Airplane, 27, -1) + SetVehicleHandbrake(AirPlane, true) + + if GetEntitySpeed(AirPlaine) == 0.0 then + if IsEntityInZone(PlayerPedId(), "AIRP") then + DoScreenFadeOut(200) + while not IsScreenFadedOut() do + Citizen.Wait(0) + end + + SetEntityCoords(PlayerPedId(), -1042.0395, -2740.7780, 20.1692) + SetEntityHeading(PlayerPedId(), 340.2285) + Citizen.Wait(500) + DoScreenFadeIn(500) + else + TaskLeaveVehicle(PlayerPedId(), AirPlane, 0) + end + end + end + + if not IsPedInVehicle(PlayerPedId(), AirPlane, false) and landing == true then + SetVehicleHandbrake(AirPlane, false) + SetBlockingOfNonTemporaryEvents(pilot, false) + + SetEntityAsNoLongerNeeded(pilot) + SetEntityAsNoLongerNeeded(AirPlane) + + startZone = nil + planeDest = nil + landing = false + end + end + + end +end) \ No newline at end of file diff --git a/client/menu.lua b/client/menu.lua new file mode 100644 index 0000000..9c67f53 --- /dev/null +++ b/client/menu.lua @@ -0,0 +1,78 @@ +--[[ + FiveM Airports + Copyright (C) 2018 FiveM-Scripts + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. +You should have received a copy of the GNU Affero General Public License +along with this resource in the file "LICENSE". If not, see . +]] + +_menuPool = NativeUI.CreatePool() +mainMenu = NativeUI.CreateMenu("", "~s~DESTINATION", "", "", "shopui_title_exec_vechupgrade", "shopui_title_exec_vechupgrade") +_menuPool:Add(mainMenu) + +_menuPool:ControlDisablingEnabled(false) +_menuPool:MouseControlsEnabled(false) + +function ShowNotification(text) + SetNotificationTextEntry("STRING") + AddTextComponentSubstringPlayerName(text) + DrawNotification(false, false) +end + +function AddAirPortMenu(menu) + if config.use_essentialmode then + SantonsButton = NativeUI.CreateItem("Los Santos International Airport", "Buy a ticket for "..config.moneyCurrency .." " ..config.ticketPrice) + DesrtButton = NativeUI.CreateItem("Sandy Shores Airfield", "Buy a ticket for "..config.moneyCurrency .." " ..config.ticketPrice) + else + SantonsButton = NativeUI.CreateItem("Los Santos International Airport", "") + DesrtButton = NativeUI.CreateItem("Sandy Shores Airfield", "") + end + + menu:AddItem(SantonsButton) + menu:AddItem(DesrtButton) + menu.OnItemSelect = function(sender, item, index) + if item == DesrtButton then + if not IsEntityInZone(PlayerPedId(), "DESRT") then + startZone = "AIRP" + planeDest = "DESRT" + if config.use_essentialmode then + TriggerServerEvent('airports:payTicket', -1675.2446, -2798.8835, 14.5409, 327.8560, planeDest, config.ticketPrice) + else + CreatePlane(-1675.2446, -2798.8835, 14.5409, 327.8560, planeDest) + end + else + ShowNotification("No plane is ~y~scheduled~w~ to that location right now.") + end + elseif item == SantonsButton then + if not IsEntityInZone(PlayerPedId(), "AIRP") then + startZone = "DESRT" + planeDest = "AIRP" + if config.use_essentialmode then + TriggerServerEvent('airports:payTicket', 1599.02453, 3231.2016, 40.4115, 105.7817, planeDest, config.ticketPrice) + else + CreatePlane(1599.02453, 3231.2016, 40.4115, 105.7817, planeDest) + end + else + ShowNotification("No plane is ~y~scheduled~w~ to that location right now.") + end + end + end +end + +AddAirPortMenu(mainMenu) +_menuPool:RefreshIndex() + +Citizen.CreateThread(function() + while true do + Citizen.Wait(1) + _menuPool:ProcessMenus() + end +end) \ No newline at end of file diff --git a/client/spawn.lua b/client/spawn.lua new file mode 100644 index 0000000..491d84b --- /dev/null +++ b/client/spawn.lua @@ -0,0 +1,81 @@ +--[[ + FiveM Airports + Copyright (C) 2018 FiveM-Scripts + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. +You should have received a copy of the GNU Affero General Public License +along with this resource in the file "LICENSE". If not, see . +]] + +function CreatePlane(x, y, z, heading, destination) + mainMenu:Visible(not mainMenu:Visible()) + + modelHash = GetHashKey(config.plane_model) + pilotModel = GetHashKey("s_m_m_pilot_01") + + RequestModel(modelHash) + while not HasModelLoaded(modelHash) do + Citizen.Wait(0) + end + + RequestModel(pilotModel) + while not HasModelLoaded(pilotModel) do + Citizen.Wait(0) + end + + if HasModelLoaded(modelHash) and HasModelLoaded(pilotModel) then + ClearAreaOfEverything(x, y, z, 1500, false, false, false, false, false) + + AirPlane = CreateVehicle(modelHash, x, y, z-1.0, heading, true, false) + SetVehicleOnGroundProperly(AirPlane) + SetVehicleEngineOn(AirPlane, true, true, true) + SetEntityProofs(PlayerPedId(), true, true, true, true, true, true, true, false) + SetVehicleHasBeenOwnedByPlayer(AirPlane, true) + + pilot = CreatePedInsideVehicle(AirPlane, 6, pilotModel, -1, true, false) + + SetBlockingOfNonTemporaryEvents(pilot, true) + + local netVehid = NetworkGetNetworkIdFromEntity(AirPlane) + SetNetworkIdCanMigrate(netVehid, true) + NetworkRegisterEntityAsNetworked(VehToNet(AirPlane)) + + local netPedid = NetworkGetNetworkIdFromEntity(pilot) + SetNetworkIdCanMigrate(netPedid, true) + NetworkRegisterEntityAsNetworked(pilot) + + totalSeats = GetVehicleModelNumberOfSeats(modelHash) + TaskWarpPedIntoVehicle(PlayerPedId(), AirPlane, 2) + + SetModelAsNoLongerNeeded(modelHash) + SetModelAsNoLongerNeeded(pilotModel) + end + + if destination == "DESRT" then + TaskPlaneMission(pilot, AirPlane, 0, 0, -107.2212, 2717.5534, 61.9673, 4, GetVehicleModelMaxSpeed(modelHash), 1.0, 0.0, 10.0, 40.0) + elseif destination == "AIRP" then + TaskVehicleDriveToCoordLongrange(pilot, AirPlane, 1403.0020751953, 2995.9179, 40.5507, GetVehicleModelMaxSpeed(modelHash), 16777216, 0.0) + Wait(5000) + TaskPlaneMission(pilot, AirPlane, 0, 0, -1571.5589, -556.7288, 114.4482, 4, GetVehicleModelMaxSpeed(modelHash), 1.0, 0.0, 5.0, 40.0) + end +end + +RegisterNetEvent("airports:departure") +AddEventHandler("airports:departure", function(x, y, z, heading, planeDest) + CreatePlane(x, y, z, heading, planeDest) +end) + +RegisterNetEvent("airports:moneyInvalid") +AddEventHandler("airports:moneyInvalid", function() + SetNotificationTextEntry("STRING") + AddTextComponentSubstringPlayerName("You don't have enough money to buy a ticket.\n") + SetNotificationMessage("CHAR_BLOCKED", "CHAR_BLOCKED", true, 4, "FiveM Airports", "", "You don't have enough money to buy a ticket.\n") + DrawNotification(false, true) +end) diff --git a/config.lua b/config.lua new file mode 100644 index 0000000..a2d7e41 --- /dev/null +++ b/config.lua @@ -0,0 +1,6 @@ +config = { + plane_model = "nimbus", + use_essentialmode = true, + moneyCurrency = "$", + ticketPrice = 80, +} diff --git a/server/server.lua b/server/server.lua new file mode 100644 index 0000000..fdc7cb4 --- /dev/null +++ b/server/server.lua @@ -0,0 +1,57 @@ +--[[ + FiveM Airports + Copyright (C) 2018 FiveM-Scripts + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. +You should have received a copy of the GNU Affero General Public License +along with this resource in the file "LICENSE". If not, see . +]] + +if GetCurrentResourceName() == 'airports' then + version = GetResourceMetadata(GetCurrentResourceName(), 'resource_version', 0) + PerformHttpRequest("https://updates.fivem-scripts.org/verify/airports", function(err, rData, headers) + if err == 404 then + RconPrint("\n----------------------------------------------------") + RconPrint("\nUPDATE ERROR: your version from FiveM Airports could not be verified.\n") + RconPrint("If you keep receiving this error then please contact FiveM-Scripts.") + RconPrint("\n----------------------------------------------------") + else + local vData = json.decode(rData) + if vData then + stableV = vData.version + if vData.version < version or vData.version > version then + RconPrint("\n----------------------------------------------------\n") + RconPrint("You are running a outdated version of FiveM Airports.\nPlease update to the most recent version: " .. vData.version) + RconPrint("\n----------------------------------------------------\n") + end + else + RconPrint("\n----------------------------------------------------------------------") + RconPrint("\nUPDATE ERROR: your version from FiveM Airports could not be verified.\n") + RconPrint("If you keep receiving this error then please contact FiveM-Scripts.") + RconPrint("\n----------------------------------------------------------------------\n") + end + end + end) +end + +RegisterServerEvent("airports:payTicket") +AddEventHandler("airports:payTicket", function(x, y, z, heading, destination, price) + TriggerEvent("es:getPlayerFromId", tonumber(source), function(user) + if user.getMoney() >= tonumber(price) then + user.removeMoney(tonumber(price)) + TriggerClientEvent("airports:departure", tonumber(source), x, y, z, heading, destination) + elseif user.getBank() >= tonumber(price) then + user.removeBank(tonumber(price)) + TriggerClientEvent("airports:departure", tonumber(source), x, y, z, heading, destination) + else + TriggerClientEvent("airports:moneyInvalid", tonumber(source)) + end + end) +end) \ No newline at end of file