Skip to content

Instantly share code, notes, and snippets.

@Randolio
Created December 18, 2025 23:05
Show Gist options
  • Select an option

  • Save Randolio/eab960a581221eedd681c6a25989c995 to your computer and use it in GitHub Desktop.

Select an option

Save Randolio/eab960a581221eedd681c6a25989c995 to your computer and use it in GitHub Desktop.
GTA:O Taxi Research - Randolio
local taxiScaleform, TAX_CAM, driver, meter, vehicle
local pricePerMeter = 0.05
local zeroCoords = vec3(0.000000, 0.000000, 0.000000)
local pickingWaypoint = false
local function normalizeVec(vec)
local mag = #(vec)
if mag ~= 0.0 then
local inv = 1.0 / mag
return vec3(vec.x * inv, vec.y * inv, vec.z * inv)
end
return vec3(0.0, 0.0, 0.0)
end
local function getPitchAndYaw(param0, bool)
local yaw
local pitch
if param0.y ~= 0.0 then
yaw = math.deg(math.atan2(param0.x, param0.y))
elseif param0.x < 0.0 then
yaw = -90.0
else
yaw = 90.0
end
if bool then
yaw = -yaw
if yaw < 0.0 then
yaw = yaw + 360.0
end
end
local horizMag = math.sqrt((param0.x * param0.x) + (param0.y * param0.y))
if horizMag ~= 0.0 then
pitch = math.deg(math.atan2(param0.z, horizMag))
elseif param0.z < 0.0 then
pitch = -90.0
else
pitch = 90.0
end
return pitch, yaw
end
local function createTaxiCam(vehicle)
if DoesCamExist(TAX_CAM) then return end
local offset1 = vec3(0.0, -0.25, 0.55)
local offset2 = vec3(-0.3, 1.0, 0.35)
TAX_CAM = CreateCam('DEFAULT_SCRIPTED_CAMERA', true)
-- CAM::ATTACH_CAM_TO_ENTITY(iLocal_2719, NETWORK::NET_TO_VEH(Local_67.f_2[iParam0 /*26*/]), Local_2729, true);
AttachCamToEntity(TAX_CAM, vehicle, offset1, true)
SetCamControlsMiniMapHeading(TAX_CAM, true)
local var0 = GetEntityRotation(vehicle, 2)
local fVar5 = var0.y
local offsetA = GetOffsetFromEntityInWorldCoords(vehicle, offset2)
local offsetB = GetOffsetFromEntityInWorldCoords(vehicle, offset1)
local diff = offsetA - offsetB
local var6 = normalizeVec(diff)
local fVar3, fVar4 = getPitchAndYaw(var6, true)
SetCamRot(TAX_CAM, fVar3, fVar5, fVar4, 2)
SetCamFov(TAX_CAM, 60.0) -- 50.0 felt too close idk.
SetCamNearClip(TAX_CAM, 0.01)
SetCamControlsMiniMapHeading(TAX_CAM, true)
SetCamActive(TAX_CAM, true)
RenderScriptCams(true, false, 3000, true, false)
SetParticleFxCamInsideVehicle(true)
end
local function destroyTaxiCam()
if DoesCamExist(TAX_CAM) then
SetCamActive(TAX_CAM, false)
DestroyCam(TAX_CAM, false)
RenderScriptCams(false, false, 3000, true, false)
TAX_CAM = nil
end
end
local function updateScaleformDest(location, street, zone)
PushScaleformMovieFunction(taxiScaleform, 'ADD_TAXI_DESTINATION')
PushScaleformMovieFunctionParameterInt(0)
PushScaleformMovieFunctionParameterInt(8)
local r, g, b = GetHudColour(142) -- waypoint color
PushScaleformMovieFunctionParameterInt(r)
PushScaleformMovieFunctionParameterInt(g)
PushScaleformMovieFunctionParameterInt(b)
PushScaleformMovieFunctionParameterString(location)
PushScaleformMovieFunctionParameterString(street)
PushScaleformMovieFunctionParameterString(zone)
EndScaleformMovieMethod()
end
local function updateScaleformPrice(num)
PushScaleformMovieFunction(taxiScaleform, 'SET_TAXI_PRICE')
PushScaleformMovieFunctionParameterInt(num)
EndScaleformMovieMethod()
end
local function scaleformHighlightDest(bool)
PushScaleformMovieFunction(taxiScaleform, 'HIGHLIGHT_DESTINATION')
PushScaleformMovieFunctionParameterBool(bool)
EndScaleformMovieMethod()
end
local function showDestination()
PushScaleformMovieFunction(taxiScaleform, 'SHOW_TAXI_DESTINATION')
EndScaleformMovieMethod()
end
local function createRenderId(name, model)
local handle = 0
if not IsNamedRendertargetRegistered(name) then
RegisterNamedRendertarget(name, 0)
end
if not IsNamedRendertargetLinked(model) then
LinkNamedRendertarget(model)
end
if IsNamedRendertargetRegistered(name) then
handle = GetNamedRendertargetRenderId(name)
end
return handle
end
local function runTaxiScaleform(vehicle)
local coords = GetEntityCoords(vehicle)
local model = `prop_taxi_meter_2`
lib.requestModel(model, 10000)
meter = CreateObject(model, coords.x, coords.y, coords.z, false, false)
-- cam offsets Local_2723 = { -0.01f, 0.6f, 0.24f }; Local_2726 = { -5f, 0f, 0f };
AttachEntityToEntity(meter, vehicle, GetEntityBoneIndexByName(vehicle, 'Chassis'), -0.01, 0.6, 0.24, -5.0, 0.0, 0.0, false, false, false, false, 2, true)
SetEntityAsMissionEntity(meter, true, true)
SetModelAsNoLongerNeeded(model)
taxiScaleform = lib.requestScaleformMovie('taxi_display', 15000)
local handle = createRenderId('taxi', model)
local zoneName = GetNameOfZone(coords)
local streetName = GetStreetNameAtCoord(coords.x, coords.y, coords.z)
updateScaleformDest('Location', GetStreetNameFromHashKey(streetName), GetLabelText(zoneName))
updateScaleformPrice(0)
scaleformHighlightDest(0)
showDestination()
Wait(100)
CreateThread(function()
while cache.vehicle do
SetTextRenderId(handle)
SetScriptGfxDrawOrder(4)
SetScriptGfxDrawBehindPausemenu(1)
DrawScaleformMovie(taxiScaleform, 0.201, 0.351, 0.4, 0.6, 0, 0, 0, 255, 0)
-- fLocal_1834 = 1f; fLocal_1835 = (0.4f * fLocal_1834); fLocal_1836 = (0.6f * fLocal_1834);
Wait(0)
end
destroyTaxiCam()
DeleteEntity(meter)
SetScaleformMovieAsNoLongerNeeded(taxiScaleform)
taxiScaleform = nil
end)
end
local function createTaxi(coords)
local taxiModel = `taxi`
lib.requestModel(taxiModel, 25000)
local vehicle = CreateVehicle(taxiModel, coords.x, coords.y, coords.z, coords.w, true, true)
SetVehicleOnGroundProperly(vehicle)
SetVehicleEngineOn(vehicle, true, true, false)
SetVehicleHasBeenOwnedByPlayer(vehicle, true)
SetVehicleAutomaticallyAttaches(vehicle, false, 0)
SetModelAsNoLongerNeeded(taxiModel)
return vehicle
end
local function createTaxiDriver(vehicle)
local driverModel = `a_m_m_eastsa_02`
lib.requestModel(driverModel, 25000)
local driver = CreatePedInsideVehicle(vehicle, 25, driverModel, -1, true, true, true)
SetPedKeepTask(driver, true)
SetDriverAbility(driver, 1.0)
SetDriverAggressiveness(driver, 0.0)
SetPedCanBeDraggedOut(driver, false)
SetPedConfigFlag(driver, 29, true)
SetPedConfigFlag(driver, 251, true)
SetPedCombatAbility(driver, 5, false)
SetPedCombatAttributes(driver, 5, false)
SetPedCombatAttributes(driver, 17, true)
SetPedFleeAttributes(driver, 512, false)
SetBlockingOfNonTemporaryEvents(driver, true)
SetModelAsNoLongerNeeded(driverModel)
return driver
end
RegisterCommand('taxi', function()
local pos = GetEntityCoords(cache.ped)
local angle = math.random() * 2 * math.pi
local distance = math.random(50, 100)
local x = pos.x + math.cos(angle) * distance
local y = pos.y + math.sin(angle) * distance
local found, spawnPos, spawnHeading = GetClosestVehicleNodeWithHeading(x, y, pos.z, 1, 3.0, 0)
-- I searched ages tryna find some 'decent' spawn logic, this is okay-ish.
if not found then
return print('couldnt find a spawn')
end
local coords = vec4(spawnPos.x, spawnPos.y, spawnPos.z, spawnHeading)
vehicle = createTaxi(coords)
if not vehicle then return end
driver = createTaxiDriver(vehicle)
if not driver then return end
local blippy = AddBlipForEntity(driver)
SetBlipSprite(blippy, 198)
SetBlipColour(blippy, 5)
SetBlipFlashes(blippy, true)
BeginTextCommandSetBlipName('STRING')
AddTextComponentString('Taxi')
EndTextCommandSetBlipName(blippy)
TaskVehicleDriveToCoordLongrange(driver, vehicle, pos.x, pos.y, pos.z, 15.0, 1076367531, 7.0)
while GetScriptTaskStatus(driver, "SCRIPT_TASK_VEHICLE_DRIVE_TO_COORD_LONGRANGE") ~= 7 do
if not DoesEntityExist(vehicle) then
print('cancelled?')
RemoveBlip(blippy)
driver = nil
vehicle = nil
return
end
print('Waiting for this cunt to run me over..')
Wait(500)
end
TaskVehicleTempAction(driver, vehicle, 1, 1000000)
ClearPedTasks(cache.ped)
TaskEnterVehicle(cache.ped, vehicle, -1, 1, 2.0, 8388608, 0)
SetPedKeepTask(cache.ped, true)
SetPlayerControl(cache.playerId, false)
local startTime = GetGameTimer()
local timeout = 5000
while cache.vehicle ~= vehicle do
if GetGameTimer() - startTime > timeout then break end
Wait(0)
end
SetPlayerControl(cache.playerId, true)
if not cache.vehicle and DoesEntityExist(vehicle) then
TaskWarpPedIntoVehicle(cache.ped, vehicle, 1)
end
lib.showTextUI('**ENTER** - Confirm Waypoint', {position = "left-center"})
runTaxiScaleform(vehicle)
Wait(1000)
createTaxiCam(vehicle)
lib.requestAnimDict('oddjobs@taxi@driver')
local animTaskSequence = OpenSequenceTask()
TaskPlayAnim(0, 'oddjobs@taxi@driver', 'leanover_enter', 4.0, -8.0, -1, 0, 0.0, false, false, false)
TaskPlayAnim(0, 'oddjobs@taxi@driver', 'leanover_idle', 4.0, -8.0, -1, 1, 0.0, false, false, false)
CloseSequenceTask(animTaskSequence)
TaskPerformSequence(driver, animTaskSequence)
ClearSequenceTask(animTaskSequence)
SetAmbientVoiceName(driver, 'A_M_M_EASTSA_02_LATINO_FULL_01')
PlayPedAmbientSpeechNative(driver, 'TAXID_WHERE_TO', 'SPEECH_PARAMS_FORCE_NORMAL_CLEAR', 1)
pickingWaypoint = true
local dest
while pickingWaypoint do
if IsControlJustReleased(0, 201) then -- enter
if GetBlipInfoIdCoord(GetFirstBlipInfoId(8)) ~= zeroCoords then
dest = GetBlipInfoIdCoord(GetFirstBlipInfoId(8))
pickingWaypoint = false
else
print('no waypoint set')
end
elseif IsControlJustReleased(0, 23) then -- F
pickingWaypoint = false
end
Wait(0)
end
lib.hideTextUI()
if not dest then
RemoveBlip(blippy)
destroyTaxiCam()
ClearPedTasks(driver)
TaskLeaveVehicle(cache.ped, cache.vehicle, 16)
Wait(1000)
DeleteEntity(meter)
SetScaleformMovieAsNoLongerNeeded(taxiScaleform)
taxiScaleform = nil
TaskVehicleDriveWander(driver, vehicle, 25.0, 790699)
SetEntityAsNoLongerNeeded(driver)
SetEntityAsNoLongerNeeded(vehicle)
driver = nil
vehicle = nil
return
end
local zoneName = GetNameOfZone(dest)
local streetName = GetStreetNameAtCoord(dest.x, dest.y, dest.z)
updateScaleformDest('Destination', GetStreetNameFromHashKey(streetName), GetLabelText(zoneName))
local distance = #(pos - dest)
local fare = math.ceil(distance * pricePerMeter)
updateScaleformPrice(fare)
scaleformHighlightDest(0)
showDestination()
lib.playAnim(driver, 'oddjobs@taxi@driver', 'leanover_exit', 4.0, 4.0, 1000, 49, 0, false, false, false)
Wait(1000)
destroyTaxiCam()
PlayPedAmbientSpeechNative(driver, 'TAXID_BEGIN_JOURNEY', 'SPEECH_PARAMS_FORCE_NORMAL_CLEAR', 1)
local sequence = OpenSequenceTask()
SetBlockingOfNonTemporaryEvents(0, true)
TaskVehicleDriveToCoordLongrange(0, vehicle, dest.x, dest.y, dest.z, 45.0, 1076367531, 30.0)
-- there was a vehicle park native here but it was braindead af.
CloseSequenceTask(sequence)
TaskPerformSequence(driver, sequence)
ClearSequenceTask(sequence)
while #(GetEntityCoords(cache.ped) - dest) > 35.0 do -- Using the range from the task is really dookie so i gotta run this.
if not cache.vehicle then
RemoveBlip(blippy)
ClearPedTasks(driver)
TaskLeaveVehicle(cache.ped, cache.vehicle, 16)
DeleteEntity(meter)
SetScaleformMovieAsNoLongerNeeded(taxiScaleform)
taxiScaleform = nil
TaskVehicleDriveWander(driver, vehicle, 25.0, 790699)
SetEntityAsNoLongerNeeded(driver)
SetEntityAsNoLongerNeeded(vehicle)
driver = nil
vehicle = nil
print('cancelled?')
return
end
Wait(500)
end
ClearPedTasks(driver)
BringVehicleToHalt(vehicle, 5.0, 1, false) -- Seems to be the smoother way of getting the vehicle to stop close to destination.
while not IsVehicleStopped(vehicle) do Wait(100) end
TaskVehicleTempAction(driver, vehicle, 1, 1000000)
PlayPedAmbientSpeechNative(driver, 'TAXID_ARRIVE_AT_DEST', 'SPEECH_PARAMS_FORCE_NORMAL_CLEAR', 1)
RemoveBlip(blippy)
ClearPedTasks(driver)
TaskLeaveVehicle(cache.ped, cache.vehicle, 0)
Wait(2000)
print(driver, vehicle)
TaskVehicleDriveWander(driver, vehicle, 25.0, 790699)
SetEntityAsNoLongerNeeded(driver)
SetEntityAsNoLongerNeeded(vehicle)
DeleteEntity(meter)
driver = nil
vehicle = nil
SetScaleformMovieAsNoLongerNeeded(taxiScaleform)
taxiScaleform = nil
end)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment