Files
2025-09-29 00:52:08 +02:00

418 lines
14 KiB
Python
Executable File

//Compile out Title Update changes to header functions.
//Must be before includes.
//CONST_INT USE_TU_CHANGES 0 // Removed by Kenneth R.
//////////////////////////////////////////////////////////////////////////////////////////
// //
// SCRIPT NAME : controller_Races.sc //
// AUTHOR : //
// DESCRIPTION : Simple script that manages the race blip state //
// //
//////////////////////////////////////////////////////////////////////////////////////////
// Includes
USING "globals.sch"
USING "commands_entity.sch"
USING "commands_script.sch"
USING "code_control_public.sch"
USING "flow_public_game.sch"
// Enums
ENUM RACE_CONTROLLER_STATE
RACE_CONTROL_INIT,
RACE_CONTROL_DAY,
RACE_CONTROL_NIGHT
ENDENUM
RACE_CONTROLLER_STATE eControlState = RACE_CONTROL_INIT
// -----------------------------------------------------------------------------------------------------------
// Script Cleanup
// -----------------------------------------------------------------------------------------------------------
/// PURPOSE:
/// Script Cleanup
PROC SCRIPT_CLEANUP()
CPRINTLN(DEBUG_AMBIENT, "Controller Races: Cleanup")
TERMINATE_THIS_THREAD()
ENDPROC
// -----------------------------------------------------------------------------------------------------------
// Script Functions
// -----------------------------------------------------------------------------------------------------------
#IF IS_DEBUG_BUILD
FUNC STRING GET_SEA_RACE_NAME_FOR_DEBUG(INT iIndex)
SWITCH iIndex
CASE 0 RETURN "SEA_RACE_EAST" BREAK
CASE 1 RETURN "SEA_RACE_NORTH" BREAK
CASE 2 RETURN "SEA_RACE_CANYON" BREAK
CASE 3 RETURN "SEA_RACE_CITY" BREAK
ENDSWITCH
RETURN "SEA_RACE_NONE"
ENDFUNC
FUNC STRING GET_STREET_RACE_NAME_FOR_DEBUG(INT iIndex)
SWITCH iIndex
CASE 0 RETURN "STREET_RACE_LOS_SANTOS" BREAK
CASE 1 RETURN "STREET_RACE_CITY_CIRCUIT" BREAK
CASE 2 RETURN "STREET_RACE_AIRPORT" BREAK
CASE 3 RETURN "STREET_RACE_FREEWAY" BREAK
CASE 4 RETURN "STREET_RACE_VESPUCCI_CANALS" BREAK
ENDSWITCH
RETURN "STREET_RACE_NONE"
ENDFUNC
#ENDIF
/// PURPOSE:
/// Gets the street race enum from the index
FUNC STATIC_BLIP_NAME_ENUM GET_SEA_RACE_BLIP_NAME(INT iIndex)
SWITCH iIndex
CASE 0 RETURN STATIC_BLIP_MINIGAME_SEA_RACE1 BREAK
CASE 1 RETURN STATIC_BLIP_MINIGAME_SEA_RACE2 BREAK
CASE 2 RETURN STATIC_BLIP_MINIGAME_SEA_RACE3 BREAK
CASE 3 RETURN STATIC_BLIP_MINIGAME_SEA_RACE4 BREAK
ENDSWITCH
SCRIPT_ASSERT("Invalid index passed to GET_SEA_RACE_BLIP_NAME()")
RETURN STATIC_BLIP_MINIGAME_SEA_RACE1
ENDFUNC
/// PURPOSE:
/// Gets the street race enum from the index
FUNC STATIC_BLIP_NAME_ENUM GET_STREET_RACE_BLIP_NAME(INT iIndex)
SWITCH iIndex
CASE 0 RETURN STATIC_BLIP_MINIGAME_STREET_RACE1 BREAK
CASE 1 RETURN STATIC_BLIP_MINIGAME_STREET_RACE2 BREAK
CASE 2 RETURN STATIC_BLIP_MINIGAME_STREET_RACE4 BREAK
CASE 3 RETURN STATIC_BLIP_MINIGAME_STREET_RACE5 BREAK
CASE 4 RETURN STATIC_BLIP_MINIGAME_STREET_RACE6 BREAK
ENDSWITCH
SCRIPT_ASSERT("Invalid index passed to GET_STREET_RACE_BLIP_NAME()")
RETURN STATIC_BLIP_MINIGAME_STREET_RACE1
ENDFUNC
/// PURPOSE:
/// Removes all street race blips from the map
PROC TURN_OFF_ALL_STREET_RACE_BLIPS()
INT iRace
FOR iRace = 0 TO (ENUM_TO_INT(NUM_STREET_RACES) - 1)
SET_STATIC_BLIP_ACTIVE_STATE(GET_STREET_RACE_BLIP_NAME(iRace), FALSE)
ENDFOR
ENDPROC
/// PURPOSE:
/// Checks the current time of day and updates mission state accordingly
PROC CHECK_TIME_OF_DAY()
SWITCH(eControlState)
CASE RACE_CONTROL_INIT
IF GET_CLOCK_HOURS() < MIN_STREET_RACE_HOUR
AND GET_CLOCK_HOURS() >= MAX_STREET_RACE_HOUR
CPRINTLN(DEBUG_AMBIENT, "Controller Races: RACE_CONTROL_INIT->RACE_CONTROL_DAY")
TURN_OFF_ALL_STREET_RACE_BLIPS()
eControlState = RACE_CONTROL_DAY
ELSE
CPRINTLN(DEBUG_AMBIENT, "Controller Races: RACE_CONTROL_INIT->RACE_CONTROL_NIGHT")
eControlState = RACE_CONTROL_NIGHT
ENDIF
BREAK
CASE RACE_CONTROL_DAY
IF GET_CLOCK_HOURS() >= MIN_STREET_RACE_HOUR
OR GET_CLOCK_HOURS() < MAX_STREET_RACE_HOUR
CPRINTLN(DEBUG_AMBIENT, "Controller Races: RACE_CONTROL_DAY->RACE_CONTROL_NIGHT")
eControlState = RACE_CONTROL_NIGHT
ENDIF
BREAK
CASE RACE_CONTROL_NIGHT
IF GET_CLOCK_HOURS() < MIN_STREET_RACE_HOUR
AND GET_CLOCK_HOURS() >= MAX_STREET_RACE_HOUR
CPRINTLN(DEBUG_AMBIENT, "Controller Races: RACE_CONTROL_NIGHT->RACE_CONTROL_DAY")
TURN_OFF_ALL_STREET_RACE_BLIPS()
eControlState = RACE_CONTROL_DAY
ENDIF
BREAK
ENDSWITCH
ENDPROC
/// PURPOSE:
/// Maintains the triggering of sea races
PROC UPDATE_SEA_RACE_BLIPS()
IF IS_MINIGAME_ACTIVE(MINIGAME_SEA_RACES)
// For all sea races...
INT iSeaRace
FOR iSeaRace = 0 TO (ENUM_TO_INT(NUM_SEA_RACES) - 1)
// Get blip name for current race
STATIC_BLIP_NAME_ENUM eBlipName = GET_SEA_RACE_BLIP_NAME(iSeaRace)
// Do we need to check for leaving the race vicinity
IF IS_BIT_SET(g_savedGlobals.sSeaRaceData.iRaceLeaveArea, ENUM_TO_INT(iSeaRace))
// Get distance from race
FLOAT fRaceDistance
fRaceDistance = VDIST2(GET_PLAYER_COORDS(PLAYER_ID()), GET_STATIC_BLIP_POSITION(eBlipName))
// Left vicinity of race
IF fRaceDistance > (209*209)
// Enable blip
IF NOT IS_STATIC_BLIP_CURRENTLY_VISIBLE(eBlipName)
IF NOT g_bSeaRaceTimeout[iSeaRace]
CPRINTLN(DEBUG_AMBIENT, "Controller Races: Reactivating blip ", GET_SEA_RACE_NAME_FOR_DEBUG(iSeaRace))
SET_STATIC_BLIP_SHORT_RANGE(eBlipName)
SET_STATIC_BLIP_ACTIVE_STATE(eBlipName, TRUE, TRUE)
CLEAR_BIT(g_savedGlobals.sSeaRaceData.iRaceLeaveArea, ENUM_TO_INT(iSeaRace))
ELSE
IF (GET_GAME_TIMER()- g_iSeaRaceCooldown[iSeaRace]) > SEA_RACE_TIMEOUT
CPRINTLN(DEBUG_AMBIENT, "Controller Races: Reactivating blip after timeout ", GET_SEA_RACE_NAME_FOR_DEBUG(iSeaRace))
g_bSeaRaceTimeout[iSeaRace] = FALSE
g_iSeaRaceCooldown[iSeaRace] = GET_GAME_TIMER()
SET_STATIC_BLIP_SHORT_RANGE(eBlipName)
SET_STATIC_BLIP_ACTIVE_STATE(eBlipName, TRUE, TRUE)
CLEAR_BIT(g_savedGlobals.sSeaRaceData.iRaceLeaveArea, ENUM_TO_INT(iSeaRace))
ENDIF
ENDIF
ENDIF
ELSE
// Remove blip
IF IS_STATIC_BLIP_CURRENTLY_VISIBLE(eBlipName)
CPRINTLN(DEBUG_AMBIENT, "Controller Races: Removing blip ", GET_SEA_RACE_NAME_FOR_DEBUG(iSeaRace))
SET_STATIC_BLIP_ACTIVE_STATE(eBlipName, FALSE, TRUE)
ENDIF
ENDIF
ELSE
// Do we need to blip the race?
IF NOT IS_STATIC_BLIP_CURRENTLY_VISIBLE(eBlipName)
IF NOT g_bSeaRaceTimeout[iSeaRace]
CPRINTLN(DEBUG_AMBIENT, "Controller Races: Activating blip ", GET_SEA_RACE_NAME_FOR_DEBUG(iSeaRace))
SET_STATIC_BLIP_SHORT_RANGE(eBlipName)
SET_STATIC_BLIP_ACTIVE_STATE(eBlipName, TRUE, TRUE)
ELSE
IF (GET_GAME_TIMER() - g_iSeaRaceCooldown[iSeaRace]) > SEA_RACE_TIMEOUT
CPRINTLN(DEBUG_AMBIENT, "Controller Races: Activating blip after timeout ", GET_SEA_RACE_NAME_FOR_DEBUG(iSeaRace))
g_bSeaRaceTimeout[iSeaRace] = FALSE
g_iSeaRaceCooldown[iSeaRace] = GET_GAME_TIMER()
SET_STATIC_BLIP_SHORT_RANGE(eBlipName)
SET_STATIC_BLIP_ACTIVE_STATE(eBlipName, TRUE, TRUE)
ENDIF
ENDIF
ELSE
// Flash the first blip instance
IF NOT g_savedGlobals.sSeaRaceData.bFirstBlip
IF eBlipName = STATIC_BLIP_MINIGAME_SEA_RACE1
SET_STATIC_BLIP_LONG_RANGE(STATIC_BLIP_MINIGAME_SEA_RACE1)
EXECUTE_CODE_ID(CID_FLASH_SEA_RACE_BLIP, 1000)
g_savedGlobals.sSeaRaceData.bFirstBlip = TRUE
CPRINTLN(DEBUG_AMBIENT, "Controller Races: Flashing blip ", GET_SEA_RACE_NAME_FOR_DEBUG(iSeaRace))
ENDIF
ENDIF
ENDIF
ENDIF
ENDFOR
ENDIF
ENDPROC
/// PURPOSE:
/// Maintains the triggering of street races
PROC UPDATE_STREET_RACE_BLIPS()
IF IS_MINIGAME_ACTIVE(MINIGAME_STREET_RACES)
// For all street races...
INT iStreetRace
FOR iStreetRace = 0 TO (ENUM_TO_INT(NUM_STREET_RACES) - 1)
// Get blip name for current race
STATIC_BLIP_NAME_ENUM eBlipName = GET_STREET_RACE_BLIP_NAME(iStreetRace)
// Race has been unlocked
IF IS_BIT_SET(g_savedGlobals.sStreetRaceData.iRaceUnlocked, ENUM_TO_INT(iStreetRace))
// Do we need to check for leaving the race vicinity
IF IS_BIT_SET(g_savedGlobals.sStreetRaceData.iRaceLeaveArea, ENUM_TO_INT(iStreetRace))
// Get distance from race
FLOAT fRaceDistance
fRaceDistance = VDIST2(GET_PLAYER_COORDS(PLAYER_ID()), GET_STATIC_BLIP_POSITION(eBlipName))
// Left vicinity of race
IF fRaceDistance > (209*209)
// Enable blip
IF NOT IS_STATIC_BLIP_CURRENTLY_VISIBLE(eBlipName)
IF NOT g_bStreetRaceTimeout[iStreetRace]
CPRINTLN(DEBUG_AMBIENT, "Controller Races: Reactivating blip ", GET_STREET_RACE_NAME_FOR_DEBUG(iStreetRace))
SET_STATIC_BLIP_SHORT_RANGE(eBlipName)
//SET_STATIC_BLIP_FLASH_ON_ACTIVE(eBlipName, FALSE)
SET_STATIC_BLIP_ACTIVE_STATE(eBlipName, TRUE, TRUE)
// Player has left the world point and race can retrigger
CLEAR_BIT(g_savedGlobals.sStreetRaceData.iRaceLeaveArea, ENUM_TO_INT(iStreetRace))
ELSE
IF (GET_GAME_TIMER()- g_iStreetRaceCooldown[iStreetRace]) > STREET_RACE_TIMEOUT
CPRINTLN(DEBUG_AMBIENT, "Controller Races: Reactivating blip after timeout ", GET_STREET_RACE_NAME_FOR_DEBUG(iStreetRace))
g_bStreetRaceTimeout[iStreetRace] = FALSE
g_iStreetRaceCooldown[iStreetRace] = GET_GAME_TIMER()
SET_STATIC_BLIP_SHORT_RANGE(eBlipName)
//SET_STATIC_BLIP_FLASH_ON_ACTIVE(eBlipName, FALSE)
SET_STATIC_BLIP_ACTIVE_STATE(eBlipName, TRUE, TRUE)
// Player has left the world point and race can retrigger
CLEAR_BIT(g_savedGlobals.sStreetRaceData.iRaceLeaveArea, ENUM_TO_INT(iStreetRace))
ENDIF
ENDIF
ELSE
CPRINTLN(DEBUG_AMBIENT, "Controller Races: Clearing leave area bit for blip ", GET_STREET_RACE_NAME_FOR_DEBUG(iStreetRace))
CLEAR_BIT(g_savedGlobals.sStreetRaceData.iRaceLeaveArea, ENUM_TO_INT(iStreetRace))
ENDIF
ELSE
// Remove blip
IF IS_STATIC_BLIP_CURRENTLY_VISIBLE(eBlipName)
CPRINTLN(DEBUG_AMBIENT, "Controller Races: Removing blip ", GET_STREET_RACE_NAME_FOR_DEBUG(iStreetRace))
SET_STATIC_BLIP_ACTIVE_STATE(eBlipName, FALSE, TRUE)
ENDIF
ENDIF
// Do we need to blip the race?
ELSE
IF NOT IS_STATIC_BLIP_CURRENTLY_VISIBLE(eBlipName)
IF NOT g_bStreetRaceTimeout[iStreetRace]
CPRINTLN(DEBUG_AMBIENT, "Controller Races: Activating blip ", GET_STREET_RACE_NAME_FOR_DEBUG(iStreetRace))
SET_STATIC_BLIP_SHORT_RANGE(eBlipName)
//SET_STATIC_BLIP_FLASH_ON_ACTIVE(eBlipName, FALSE)
SET_STATIC_BLIP_ACTIVE_STATE(eBlipName, TRUE, TRUE)
ELSE
IF (GET_GAME_TIMER()- g_iStreetRaceCooldown[iStreetRace]) > STREET_RACE_TIMEOUT
CPRINTLN(DEBUG_AMBIENT, "Controller Races: Activating blip after timeout ", GET_STREET_RACE_NAME_FOR_DEBUG(iStreetRace))
g_bStreetRaceTimeout[iStreetRace] = FALSE
g_iStreetRaceCooldown[iStreetRace] = GET_GAME_TIMER()
SET_STATIC_BLIP_SHORT_RANGE(eBlipName)
//SET_STATIC_BLIP_FLASH_ON_ACTIVE(eBlipName, FALSE)
SET_STATIC_BLIP_ACTIVE_STATE(eBlipName, TRUE, TRUE)
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDFOR
ENDIF
ENDPROC
/// PURPOSE:
/// Should the controller update or wait another second?
FUNC BOOL DO_CONTROLLER_UPDATE()
IF IS_CURRENTLY_ON_MISSION_TO_TYPE(MISSION_TYPE_MINIGAME)
RETURN FALSE
ENDIF
IF IS_PLAYER_TIMETABLE_SCENE_IN_PROGRESS()
RETURN FALSE
ENDIF
IF GET_PLAYER_WANTED_LEVEL(PLAYER_ID()) > 0
RETURN FALSE
ENDIF
IF IS_PLAYER_SWITCH_IN_PROGRESS()
RETURN FALSE
ENDIF
RETURN TRUE
ENDFUNC
/// PURPOSE:
/// Initialise timeouts for sea and street races
PROC INIT_RACE_UNSAVED_GLOBALS()
INT i
FOR i=0 TO (ENUM_TO_INT(NUM_SEA_RACES) - 1)
g_bSeaRaceTimeout[i] = FALSE
g_iSeaRaceCooldown[i] = GET_GAME_TIMER()
ENDFOR
// Street race timeouts
FOR i=0 TO (ENUM_TO_INT(NUM_STREET_RACES) - 1)
g_bStreetRaceTimeout[i] = FALSE
ENDFOR
ENDPROC
// -----------------------------------------------------------------------------------------------------------
// Main Script
// -----------------------------------------------------------------------------------------------------------
SCRIPT
IF HAS_FORCE_CLEANUP_OCCURRED(FORCE_CLEANUP_FLAG_DEBUG_MENU|FORCE_CLEANUP_FLAG_SP_TO_MP|FORCE_CLEANUP_FLAG_REPEAT_PLAY)
CPRINTLN(DEBUG_AMBIENT, "Controller Races: Cleanup: FORCE CLEANUP")
SCRIPT_CLEANUP()
ENDIF
IF GET_NUMBER_OF_THREADS_RUNNING_THE_SCRIPT_WITH_THIS_HASH (HASH("controller_Races")) > 1
CPRINTLN(DEBUG_AMBIENT, "Controller Races: Cleanup: Attempting to launch with an instance already active...")
TERMINATE_THIS_THREAD()
ENDIF
// Wait until game has loaded to ensure blips get correctly setup.
// RESTORE_MINIGAME_BLIPS_AFTER_LOAD() is called after script relaunch and clock value is incorrect to initialise blips there...
WHILE GET_NUMBER_OF_THREADS_RUNNING_THE_SCRIPT_WITH_THIS_HASH (HASH("initial")) > 0
WAIT(0)
ENDWHILE
// Setup race timeouts
INIT_RACE_UNSAVED_GLOBALS()
// Main loop
WHILE (TRUE)
IF IS_CURRENTLY_ON_MISSION_TO_TYPE(MISSION_TYPE_MINIGAME)
OR g_bPlayerLockedInToTrigger
CPRINTLN(DEBUG_RANDOM_CHAR, "Controller Races: Cleaning up as we have gone on mission...")
Script_Cleanup()
ENDIF
// Entity check
IF IS_PLAYER_PLAYING(PLAYER_ID())
// Only update when Franklin
IF DO_CONTROLLER_UPDATE()
// Check for races activation
CHECK_TIME_OF_DAY()
// Sea Races
UPDATE_SEA_RACE_BLIPS()
// Street Races
IF GET_CURRENT_PLAYER_PED_ENUM() = CHAR_FRANKLIN
// Handle TOD
SWITCH(eControlState)
CASE RACE_CONTROL_DAY
BREAK
CASE RACE_CONTROL_NIGHT
UPDATE_STREET_RACE_BLIPS()
BREAK
ENDSWITCH
ENDIF
ENDIF
ENDIF
WAIT(1000)
ENDWHILE
ENDSCRIPT