[Release] [PAID][ESX] Interactive Airport

This interactive airport is meant to enhance the roleplay experience by making it more immersive and is part of a project series I’m creating making public transport a pleasure to use.

Features
  1. Fully animated.
  2. Simple yet sleek UI design.
  3. NPC Stewardesses at key locations that can be fully customized and can even look like regular players and can be fully animated.
  4. Transported through cutscene. Not just a simple teleport.
  5. Full access to the script. No IP Lock or Obfuscation.
  6. Very extensive config file. Pretty much anything you need to change can be done through the config.
  7. Support for custom notifications. Uses mythic by default but you can change that to whatever you want by changing the export. Do not forget to change the Serverside Client events if you are changing the Notifications.
  8. Support for custom progress bars. Uses Chipsahoy’s Progress Bars by default but can be changed to whatever you want by changing the export.
  9. Bt-Target is integrated and enabled by default. To use regular markers make sure to set Config.UseEyeTracker to false.
  10. Code is very commented in an attempt to guide the user what parts of the code does.
  11. Performance friendly 0.00-0.01ms on the resmon if using the eye tracker. 0.00-0.03ms if using markers.

The UI will show available destinations based on where you are located at the time. For example the UI will not show Cayo Perico as an available destination when located at Cayo Perico.

Regarding the Stewardess NPC’s:
Please note that if you use vMenu to decide the look for them, you have to go back 1 for every Drawable Texture. For example: You wish to use Shoes 51 with texture 4, make sure you note it as:

[‘shoes_1’] = 51, [‘shoes_2’] = 3,

This is because vMenu starts at texture #1 whereas Skinchanger starts at #0.

Notes

Please note that Sandy Shores does not have cutscenes (as far as I know) involving planes landing and taking off so I had to improvise this. If somebody does know a cutscene with planes leaving and entering in Sandy Shores. Please let me know and I’ll update it.

If build 2189 is used, and a player logs out on Cayo Perico, there is an extra layer of protection added to make sure players will respawn back on the island however this may fail. If it does please let me know and I’ll look into it.

To use Cayo Perico as an available destination make sure that if you are on atleast build 2189, to set Config.UseBuild2189 to true. This will ensure the island will load by using these build specific natives. If you are streaming Cayo Perico assets set Config.UseBuild2189 to false and Config.StreamingCayoPerico to true. If you are not using build 2189 and not streaming Cayo Perico assets set Config.UseBuild2189 and Config.StreamingCayoPerico to false. This will enable a popup warning that there are no flights to Cayo Perico and prevents a player from accidentally being dropped in the ocean.

Required Edits

In order to make the NPC’s work all you have to do is add a bit of code to the skinchanger script.

Copy the following code and place it somewhere within Skinchanger/Client.lua.

function CreateNPCSkin(skin, clothes, ped)
	local playerPed = ped

	for k,v in pairs(skin) do
		Character[k] = v
	end

	if clothes ~= nil then
		for k,v in pairs(clothes) do
			if
				k ~= 'sex'				and
				k ~= 'face'				and
				k ~= 'skin'				and
				k ~= 'age_1'			and
				k ~= 'age_2'			and
				k ~= 'eye_color'		and
				k ~= 'beard_1'			and
				k ~= 'beard_2'			and
				k ~= 'beard_3'			and
				k ~= 'beard_4'			and
				k ~= 'hair_1'			and
				k ~= 'hair_2'			and
				k ~= 'hair_color_1'		and
				k ~= 'hair_color_2'		and
				k ~= 'eyebrows_1'		and
				k ~= 'eyebrows_2'		and
				k ~= 'eyebrows_3'		and
				k ~= 'eyebrows_4'		and
				k ~= 'makeup_1'			and
				k ~= 'makeup_2'			and
				k ~= 'makeup_3'			and
				k ~= 'makeup_4'			and
				k ~= 'lipstick_1'		and
				k ~= 'lipstick_2'		and
				k ~= 'lipstick_3'		and
				k ~= 'lipstick_4'		and
				k ~= 'blemishes_1'		and
				k ~= 'blemishes_2'		and
				k ~= 'blush_1'			and
				k ~= 'blush_2'			and
				k ~= 'blush_3'			and
				k ~= 'complexion_1'		and
				k ~= 'complexion_2'		and
				k ~= 'sun_1'			and
				k ~= 'sun_2'			and
				k ~= 'moles_1'			and
				k ~= 'moles_2'			and
				k ~= 'chest_1'			and
				k ~= 'chest_2'			and
				k ~= 'chest_3'			and
				k ~= 'bodyb_1'			and
				k ~= 'bodyb_2'
			then
				Character[k] = v
			end
		end
	end

	SetPedHeadBlendData			(playerPed, Character['face'], Character['face'], Character['face'], Character['skin'], Character['skin'], Character['skin'], 1.0, 1.0, 1.0, true)

	SetPedHairColor				(playerPed,			Character['hair_color_1'],		Character['hair_color_2'])					-- Hair Color
	SetPedHeadOverlay			(playerPed, 3,		Character['age_1'],				(Character['age_2'] / 10) + 0.0)			-- Age + opacity
	SetPedHeadOverlay			(playerPed, 1,		Character['beard_1'],			(Character['beard_2'] / 10) + 0.0)			-- Beard + opacity
	SetPedEyeColor				(playerPed,			Character['eye_color'], 0, 1)												-- Eyes color
	SetPedHeadOverlay			(playerPed, 2,		Character['eyebrows_1'],		(Character['eyebrows_2'] / 10) + 0.0)		-- Eyebrows + opacity
	SetPedHeadOverlay			(playerPed, 4,		Character['makeup_1'],			(Character['makeup_2'] / 10) + 0.0)			-- Makeup + opacity
	SetPedHeadOverlay			(playerPed, 8,		Character['lipstick_1'],		(Character['lipstick_2'] / 10) + 0.0)		-- Lipstick + opacity
	SetPedComponentVariation	(playerPed, 2,		Character['hair_1'],			Character['hair_2'], 2)						-- Hair
	SetPedHeadOverlayColor		(playerPed, 1, 1,	Character['beard_3'],			Character['beard_4'])						-- Beard Color
	SetPedHeadOverlayColor		(playerPed, 2, 1,	Character['eyebrows_3'],		Character['eyebrows_4'])					-- Eyebrows Color
	SetPedHeadOverlayColor		(playerPed, 4, 1,	Character['makeup_3'],			Character['makeup_4'])						-- Makeup Color
	SetPedHeadOverlayColor		(playerPed, 8, 1,	Character['lipstick_3'],		Character['lipstick_4'])					-- Lipstick Color
	SetPedHeadOverlay			(playerPed, 5,		Character['blush_1'],			(Character['blush_2'] / 10) + 0.0)			-- Blush + opacity
	SetPedHeadOverlayColor		(playerPed, 5, 2,	Character['blush_3'])														-- Blush Color
	SetPedHeadOverlay			(playerPed, 6,		Character['complexion_1'],		(Character['complexion_2'] / 10) + 0.0)		-- Complexion + opacity
	SetPedHeadOverlay			(playerPed, 7,		Character['sun_1'],				(Character['sun_2'] / 10) + 0.0)			-- Sun Damage + opacity
	SetPedHeadOverlay			(playerPed, 9,		Character['moles_1'],			(Character['moles_2'] / 10) + 0.0)			-- Moles/Freckles + opacity
	SetPedHeadOverlay			(playerPed, 10,		Character['chest_1'],			(Character['chest_2'] / 10) + 0.0)			-- Chest Hair + opacity
	SetPedHeadOverlayColor		(playerPed, 10, 1,	Character['chest_3'])														-- Torso Color
	SetPedHeadOverlay			(playerPed, 11,		Character['bodyb_1'],			(Character['bodyb_2'] / 10) + 0.0)			-- Body Blemishes + opacity

	if Character['ears_1'] == -1 then
		ClearPedProp(playerPed, 2)
	else
		SetPedPropIndex			(playerPed, 2,		Character['ears_1'],			Character['ears_2'], 2)						-- Ears Accessories
	end

	SetPedComponentVariation	(playerPed, 8,		Character['tshirt_1'],			Character['tshirt_2'], 2)					-- Tshirt
	SetPedComponentVariation	(playerPed, 11,		Character['torso_1'],			Character['torso_2'], 2)					-- torso parts
	SetPedComponentVariation	(playerPed, 3,		Character['arms'],				Character['arms_2'], 2)						-- Amrs
	SetPedComponentVariation	(playerPed, 10,		Character['decals_1'],			Character['decals_2'], 2)					-- decals
	SetPedComponentVariation	(playerPed, 4,		Character['pants_1'],			Character['pants_2'], 2)					-- pants
	SetPedComponentVariation	(playerPed, 6,		Character['shoes_1'],			Character['shoes_2'], 2)					-- shoes
	SetPedComponentVariation	(playerPed, 1,		Character['mask_1'],			Character['mask_2'], 2)						-- mask
	SetPedComponentVariation	(playerPed, 9,		Character['bproof_1'],			Character['bproof_2'], 2)					-- bulletproof
	SetPedComponentVariation	(playerPed, 7,		Character['chain_1'],			Character['chain_2'], 2)					-- chain
	SetPedComponentVariation	(playerPed, 5,		Character['bags_1'],			Character['bags_2'], 2)						-- Bag

	if Character['helmet_1'] == -1 then
		ClearPedProp(playerPed, 0)
	else
		SetPedPropIndex			(playerPed, 0,		Character['helmet_1'],			Character['helmet_2'], 2)					-- Helmet
	end

	if Character['glasses_1'] == -1 then
		ClearPedProp(playerPed, 1)
	else
		SetPedPropIndex			(playerPed, 1,		Character['glasses_1'],			Character['glasses_2'], 2)					-- Glasses
	end

	if Character['watches_1'] == -1 then
		ClearPedProp(playerPed, 6)
	else
		SetPedPropIndex			(playerPed, 6,		Character['watches_1'],			Character['watches_2'], 2)					-- Watches
	end

	if Character['bracelets_1'] == -1 then
		ClearPedProp(playerPed,	7)
	else
		SetPedPropIndex			(playerPed, 7,		Character['bracelets_1'],		Character['bracelets_2'], 2)				-- Bracelets
	end
end

RegisterNetEvent('skinchanger:loadPedSkin')
AddEventHandler('skinchanger:loadPedSkin', function(ped, skin)
	CreateNPCSkin(skin, nil, ped)
end)

Save skinchanger and that’s it!

It should work perfectly, and it should not interfere with the regular working of skinchanger and esx_skin. I myself don’t use ESX Legacy, so while during testing worked perfectly, I’m still not 100% sure about the overall result. Please let me know :slight_smile:

Installation Instructions
  1. Place ‘avanae_airports’ in your resource folder.
  2. Place ‘ensure avanae_airports’ in your config.
  3. Follow the instructions in Required Edits
  4. This script should support every version of ESX. However due to the amount of different versions of the item table in the database based on so many different inventories (weight or limit based) , a SQL has not been provided. To ensure everything working correctly you need to go to your database, go to “ITEMS” and insert ‘planeticket_lsia’, ‘planeticket_ssa’ and ‘planeticket_cpa’ as items and you should be good to go.
  5. Start your server and profit.
Config

The config is quite extensive and almost anything you want to adjust can be done through the config.

A quick run down of what every option does:

  1. Config.TicketPrice - Self explanatory. Set the price of a ticket globally.

  2. Config.UseCustomNotifications - Set this to true to use custom notifications or false to use ESX Notifications. By default this uses Mythic Notify, but if you use your own, you can find the client and server events to change to your own notification system.

  3. Config.UseProgressBars - Use progress bars during animations and interactions. This uses Chipsahoy’s Progress Bars by default but the export can be changed to whichever system you use.

  4. Config.UseEyeTracker - Bt-Target is already set-up and integrated into the script and ready to use. If you don’t use the eyetracker, set this to false to use markers.

  5. Config.UseBuild2189 - If you don’t stream Cayo Perico assets, but are on Build2189, set this to true. This will allow the island to load, and enables Cayo Perico as a destination.

  6. Config.StreamingCayoPerico - If you are not on Build 2189, but you are streaming Cayo Perico assets then set this to true. This makes sure that Cayo Perico is an available destination.

  7. Config.TicketMachineModel - Sets the model for the spawned ticket machines. You can change this but it’s recommended that you don’t.

  8. Config.AirportPeds - Allows you to completely change the look of your Stewardess peds and even make them look like actual players, and you can let them play animations too. I have already set them up but they can be changed as you wish.

Possible future plans

I might consider implementing AI pilots to fly you to your destination.
I am also considering making Standalone and support QBus.

Preview


When markers are configured rather than the eye tracker.

Video of script in action

You can find the script on my Tebex Store for €6,99

Should any of you have any feedback or things I can add to it, do let me know. :slight_smile:

As this is my first paid resource, please note that all updates will be free.

Updates

Update 1.0.1 Released:

  • Cleaned up left-over code that could result in duplication of NPC’s after each flight.
  • Added Config.Cutscene that allows enabling or disabling cutscenes all together.

Update 1.0.2 will include full landing, mid-air and take-off cutscenes.

Bug fix for Update 1.0.1 Released:

  • Fixed an instance where your character was stuck trying to buy a ticket with no money.
  • Hopefully fixed an instance where a player could buy a ticket with no money on a fresh server start without resource restart.
Updating ESX Version

If you’ve updated to a few of the latest ESX Legacy it will warn you about esx:getSharedObject being deprecated or it already is deprecated you need to make a couple of edits

Client Side

ESX = nil 

Citizen.CreateThread(function()
	while ESX == nil do
		TriggerEvent('esx:getSharedObject', function(obj) ESX = obj end)
		Citizen.Wait(0)
	end

	while ESX.GetPlayerData().job == nil do
		Citizen.Wait(10)
	end

	ESX.PlayerData = ESX.GetPlayerData()
end)

and change that to

ESX = exports['es_extended']:getSharedObject()

Citizen.CreateThread(function()
	while ESX.GetPlayerData().job == nil do
		Citizen.Wait(10)
	end

	ESX.PlayerData = ESX.GetPlayerData()
end)

Server Side

ESX = nil

TriggerEvent('esx:getSharedObject', function(obj) ESX = obj end)

to

ESX = exports['es_extended']:getSharedObject()

Make sure your fxmanifest includes

shared_scripts {
  '@es_extended/imports.lua',
}
5 Likes

If a lot of players use it at the same time Will the planes collide?

1 Like

Not something I came across in testing. However I can look into this just in case. :slight_smile:

1 Like

i purchased but didnt get file

It should be on your way as we speak. :slight_smile: Quite new to Tebex so still figuring things out on how to set it up properly, but you should have received it already.

Very good work!

1 Like

thanks man i got it but when i purchase ticket a get on the flight the screen just goes black and i cant do anything

Do you have console errors? Also have you inserted the ticket items in your database as a SQL was not provided?

Looks really cool :smiley:

Would adding a plane landing cutscene be possible in the future?

2 Likes

That can certainly be added. I just simply used only taking off to shorten the time to reach the destination. But I can add in a config for people wishing both Landing and Taking Off cutscenes.

2 Likes

Ah sounds good :smiley: in that case, cutscenes of the plane in the air would be cool!

I’ll see what I can do regarding that. Cutscenes that are used are from Rockstar themselves so I’ll browse through them and see if there is anything good that can be used. :slight_smile:

2 Likes

sure, you could try the mp intro cutscene? that shows the character in a plane.

yes i added the items

I was already thinking of that one.

1 Like

I’ll DM you and try to solve the issues with you there. :slight_smile:

ok thanks man

Some of us use that same cutscene to introduce new players to our servers. Would be funny to see it every time lol wouldnt make it as special. Unless you can figure out pieces of it.

besides that, this is great and Ill grab it and convert to qb for myself. TY!

You can use pieces of it IIRC. You could simply use the Player staring out the window part and skip the rest. But I will definitely consider both taking off and landing cutscenes.

1 Like

Just purchased, didn’t receive any download link or anything. Where do i go for the download?