Created
December 18, 2025 23:05
-
-
Save Randolio/eab960a581221eedd681c6a25989c995 to your computer and use it in GitHub Desktop.
GTA:O Taxi Research - Randolio
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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