Files
gtav-src/script/dev_ng/singleplayer/scripts/Ambient/EpsilonTract/epsilonTract.sc
T
2025-09-29 00:52:08 +02:00

485 lines
18 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.
// Includes
USING "rage_builtins.sch"
USING "globals.sch"
USING "commands_camera.sch"
USING "commands_pad.sch"
USING "commands_script.sch"
USING "flow_public_core_override.sch"
USING "common_packages.sch"
USING "scrap_common.sch"
// *****************************************************************************************
// *****************************************************************************************
// *****************************************************************************************
//
// MISSION NAME : epsilonTract.sc
// AUTHOR : Joanna Wright
// DESCRIPTION : Collect all the time capsules in order. Clues are iven for each one.
//
// *****************************************************************************************
// *****************************************************************************************
// *****************************************************************************************
CONST_INT TIME_DELAY_FOR_TEXT_STOLE_CASH 300000
CONST_INT TIME_DELAY_FOR_TEXT_GOOD_EPSILONIST 16000
MISSION_STAGE eStage = STAGE_INITIALISE
MODEL_NAMES eTractModel = PROP_TIME_CAPSULE_01
INT iCurrentLocToFind = 0
INT iTimer_DelayForPhoneText = 0
INT iphoneTextDelay = 0
INT iMessageStage = 0
SCALEFORM_INDEX siMessage
BOOL bDisplayMessage = FALSE
BOOL bMessageOnDisplay = FALSE
INT iMessageTimer = 0
SCRAP_PICKUP_DATA tractPickup[MAX_TRACT_PICKUPS]
STRING helpText[MAX_TRACT_PICKUPS]
// ===========================================================================================================
// Debug
// ===========================================================================================================
#IF IS_DEBUG_BUILD
USING "shared_debug.sch"
BOOL bDebug_PrintToTTY = TRUE
VECTOR warpCoords[MAX_TRACT_PICKUPS]
WIDGET_GROUP_ID widgetGroup
BOOL bWarpToScrap[MAX_TRACT_PICKUPS]
BOOL bMapAlltractPickup
BOOL bCollectAlltractPickup
BOOL bResetAllTractPickups
BOOL bSimulateProgress[MAX_TRACT_PICKUPS]
/// PURPOSE: Returns clue for the specified pickup
/// PARAMS:
/// iIndex - the index of the specified pickup
FUNC STRING GET_TRACT_CLUE(INT iIndex)
SWITCH iIndex
CASE 0 RETURN "WE WORSHIP KRAM WHERE THE EARTH REACHES UP TO KRAFF." BREAK
CASE 1 RETURN "Where the first of the fleet succumbed to the waves, there the message is seeded." BREAK
CASE 2 RETURN "When they sail from the North, they will find this offering." BREAK
CASE 3 RETURN "In the core of the mountain, where the blast is not felt, there you shall find it." BREAK
CASE 4 RETURN "In the rubble of the old religion, will be the basis for the new." BREAK
CASE 5 RETURN "Where the first fleet sailed, the new fleet will find its map." BREAK
CASE 6 RETURN "What dwelling is worthy of Kram? He is humble, yet we exult him." BREAK
CASE 7 RETURN "We are not dinosaurs, or plants, but a tree in the jet stream may hold Kram's true word." BREAK
CASE 8 RETURN "The tallest obelisk of glass and steel holds no comparison to the word of Kram." BREAK
CASE 9 RETURN "Where they discard their earthly prisons, there you may find the germ of a higher civilisation." BREAK
ENDSWITCH
RETURN "Invalid Pickup Index"
ENDFUNC
/// PURPOSE: Creates widgets to teleport Player to the locations, blip locations etc
PROC SETUP_TRACT_WIDGETS()
TEXT_LABEL_63 tlTemp
INT iIndex = 0
widgetGroup = START_WIDGET_GROUP("Tract Locations")
ADD_WIDGET_BOOL("Show all tract locations on map", bMapAlltractPickup)
ADD_WIDGET_BOOL("Visit all tract locations", bCollectAlltractPickup)
ADD_WIDGET_BOOL("Reset all tract locations", bResetAllTractPickups)
START_WIDGET_GROUP("Positions")
REPEAT MAX_TRACT_PICKUPS iIndex
tlTemp = "Tract["
tlTemp += iIndex
tlTemp += "]"
START_WIDGET_GROUP(tlTemp)
ADD_WIDGET_STRING(GET_TRACT_CLUE(iIndex))
ADD_WIDGET_BOOL("Simulate progress", bSimulateProgress[iIndex])
ADD_WIDGET_BOOL("bWarp", bWarpToScrap[iIndex])
STOP_WIDGET_GROUP()
ENDREPEAT
STOP_WIDGET_GROUP()
STOP_WIDGET_GROUP()
iIndex = 0
REPEAT MAX_TRACT_PICKUPS iIndex
bSimulateProgress[iIndex] = FALSE
ENDREPEAT
ENDPROC
/// PURPOSE: collects the correct amount of scraps in order to warp the Player to the specified scrap
/// PARAMS:
/// index - the index of the scrap you wish to collect next (the one you will warp to)
PROC SORT_DEBUG_SCRAP_COUNTING(INT index)
INT i = 0
IF DOES_PICKUP_EXIST(tractPickup[iCurrentLocToFind].pickup)
AND NOT (iCurrentLocToFind = index)
REMOVE_PICKUP(tractPickup[iCurrentLocToFind].pickup)
ENDIF
iCurrentLocToFind = index
//set previous scraps to collected if not already
REPEAT MAX_TRACT_PICKUPS i
IF (i < iCurrentLocToFind)
#IF IS_DEBUG_BUILD
IF bDebug_PrintToTTY
CPRINTLN(DEBUG_MISSION,"if not packed stat: ", i)
ENDIF
#ENDIF
IF NOT GET_PACKED_STAT_BOOL(INT_TO_ENUM(STATS_PACKED, (PACKSTAT_TRACT_START + i)))
SET_PACKED_STAT_BOOL(INT_TO_ENUM(STATS_PACKED, (PACKSTAT_TRACT_START + i)), TRUE)
STAT_INCREMENT(NUM_HIDDEN_PACKAGES_2, 1.0)
ENDIF
ELSE
#IF IS_DEBUG_BUILD
IF bDebug_PrintToTTY
CPRINTLN(DEBUG_AMBIENT,"if packed stat: ", i)
ENDIF
#ENDIF
IF GET_PACKED_STAT_BOOL(INT_TO_ENUM(STATS_PACKED, (PACKSTAT_TRACT_START + i)))
SET_PACKED_STAT_BOOL(INT_TO_ENUM(STATS_PACKED, (PACKSTAT_TRACT_START + i)), FALSE)
STAT_DECREMENT(NUM_HIDDEN_PACKAGES_2, 1.0)
ENDIF
ENDIF
ENDREPEAT
ENDPROC
/// PURPOSE: Sorts out the correct functionality depending on if any widgets are selected
PROC MAINTAIN_TRACT_WIDGETS()
IF NOT IS_CURRENTLY_ON_MISSION_OF_TYPE(MISSION_TYPE_DIRECTOR)
INT iIndex
INT ipackNum
REPEAT MAX_TRACT_PICKUPS iIndex
IF IS_ENTITY_ALIVE(PLAYER_PED_ID())
IF bSimulateProgress[iIndex]
SORT_DEBUG_SCRAP_COUNTING(iIndex)
bSimulateProgress[iIndex] = FALSE
ENDIF
IF bWarpToScrap[iIndex]
DO_PLAYER_MAP_WARP_WITH_LOAD(warpCoords[iIndex])
INTERIOR_INSTANCE_INDEX intIndex = GET_INTERIOR_AT_COORDS(warpCoords[iIndex])
IF bDebug_PrintToTTY
CPRINTLN(DEBUG_MISSION, "Eps Tract: Need an interior...")
ENDIF
IF IS_VALID_INTERIOR(intIndex)
IF bDebug_PrintToTTY
CPRINTLN(DEBUG_MISSION, "Eps Tract: Loading interior")
ENDIF
PIN_INTERIOR_IN_MEMORY(intIndex)
WHILE NOT IS_INTERIOR_READY(intIndex)
WAIT(0)
ENDWHILE
WAIT(0)
UNPIN_INTERIOR(intIndex)
ENDIF
IF IS_ENTITY_ALIVE(PLAYER_PED_ID())
IF IS_PED_SWIMMING_UNDER_WATER(PLAYER_PED_ID()) //so player doesn't automatically collect it
FORCE_PED_MOTION_STATE(PLAYER_PED_ID(), MS_DIVING_IDLE)
ENDIF
SET_ENTITY_FACING(PLAYER_PED_ID(), tractPickup[iIndex].vCoords)
ENDIF
bWarpToScrap[iIndex] = FALSE
ENDIF
ENDIF
MAP_SCRAP_CHECK(bMapAlltractPickup, tractPickup[iIndex].blip, iIndex, MAX_TRACT_PICKUPS, SCRAP_TRACT, tractPickup[iIndex].vCoords)
IF bCollectAllTractPickup
ipackNum = PACKSTAT_TRACT_START + iIndex
SET_PACKED_STAT_BOOL(INT_TO_ENUM(STATS_PACKED, ipackNum), TRUE)
STAT_INCREMENT(NUM_HIDDEN_PACKAGES_2, 1.0)
iCurrentLocToFind = MAX_TRACT_PICKUPS
ENDIF
IF bResetAllTractPickups
ipackNum = PACKSTAT_TRACT_START + iIndex
IF GET_PACKED_STAT_BOOL(INT_TO_ENUM(STATS_PACKED, ipackNum))
SET_PACKED_STAT_BOOL(INT_TO_ENUM(STATS_PACKED, ipackNum), FALSE)
STAT_DECREMENT(NUM_HIDDEN_PACKAGES_2, 1.0)
ENDIF
IF NOT (iIndex = 0)
SAFE_REMOVE_PICKUP(tractPickup[iIndex].pickup)
ENDIF
iCurrentLocToFind = 0
ENDIF
ENDREPEAT
bCollectAlltractPickup = FALSE
bResetAllTractPickups = FALSE
ENDIF
ENDPROC
#ENDIF
// ===========================================================================================================
// Script Cleanup
// ===========================================================================================================
PROC SCRIPT_CLEANUP()
INT iIndex = 0
#IF IS_DEBUG_BUILD
IF bDebug_PrintToTTY
CPRINTLN(DEBUG_MISSION, "STAGE_CLEANUP")
ENDIF
IF DOES_WIDGET_GROUP_EXIST(widgetGroup)
DELETE_WIDGET_GROUP(widgetGroup)
ENDIF
#ENDIF
REPEAT MAX_TRACT_PICKUPS iIndex
SAFE_REMOVE_PICKUP(tractPickup[iIndex].pickup)
ENDREPEAT
TERMINATE_THIS_THREAD()
ENDPROC
PROC SCRIPT_PASSED()
Set_Mission_Flow_Flag_State(FLOWFLAG_EPSILON_UNLOCKED_TRACT, TRUE)
//Krant be praised, the Tract is complete! No material possessions can match the feeling of enlightened satisfaction that you must now be feeling.
//Instead, expand your knowledge at our secret ~b~<u>www.epsilonprogram.com</u>~s~ page, yet remember if you know nothing, then you know everything. Kifflom!
FIRE_EMAIL_INTO_DYNAMIC_THREAD(DYNAMIC_THREAD_EPSILON_TRACT, TRACT_DONE, FALSE)
Remove_Script_From_Relaunch_List(LAUNCH_BIT_RC_AMB_EPSILON_TRACT)
eStage = STAGE_CLEANUP
ENDPROC
PROC DO_INITIALISE()
INT iScrap = 0
INT ipackNum
#IF IS_DEBUG_BUILD
IF bDebug_PrintToTTY
CPRINTLN(DEBUG_MISSION, "TRACT_STAGE_INITIALISE")
ENDIF
warpCoords[0] = << 505.1541, 5602.3984, 796.9146 >>
warpCoords[1] = <<2722.8655, -1255.5728, -27.9673>>
warpCoords[2] = <<22.9464, 7641.9365, 17.2828>>
warpCoords[3] = << -256.9334, 4733.3311, 135.8996 >>
warpCoords[4] = <<-772.4346, -681.6366, 28.8548>>
warpCoords[5] = << -1606.3145, 5260.2427, 1.1005 >>
warpCoords[6] = <<-1803.4014, 401.5742, 111.8039>>
warpCoords[7] = <<486.3900, 5615.3789, 788.0875>>
warpCoords[8] = << -75.0000, -816.0000, 325.3656 >>
warpCoords[9] = <<-1720.9717, -188.5656, 57.2576>>
#ENDIF
//text sent depends on if Player stole the money in a previous mission
IF g_savedGlobals.sRandomChars.g_bStoleEpsilonCash
//Kifflom. Your past sin was great but Kram is not without mercy. To redeem yourself you must write the tract...WE WORSHIP KRAM WHERE THE EARTH REACHES UP TO KRAFF.
helpText[0] = "TRACT_HINT1B"
iphoneTextDelay = TIME_DELAY_FOR_TEXT_STOLE_CASH
ELSE
//Kifflom brother, you now truly one of us and are ready to write the tract...WE WORSHIP KRAM WHERE THE EARTH REACHES UP TO KRAFF.
helpText[0] = "TRACT_HINT1"
iphoneTextDelay = TIME_DELAY_FOR_TEXT_GOOD_EPSILONIST
ENDIF
tractPickup[0].vCoords = << 501.9415, 5604.4292, 796.9146 >>
tractPickup[1].vCoords = <<2658.18, -1361.14, -21.63>> helpText[1] = "TRACT_HINT2"
tractPickup[2].vCoords = <<24.7139, 7644.3340, 18.0792>> helpText[2] = "TRACT_HINT3"
tractPickup[3].vCoords = << -263.55, 4729.60, 137.37 >> helpText[3] = "TRACT_HINT4"
tractPickup[4].vCoords = <<-771.98, -685.22, 28.86>> helpText[4] = "TRACT_HINT5"
tractPickup[5].vCoords = << -1605.03, 5256.55, 1.08 >> helpText[5] = "TRACT_HINT6"
tractPickup[6].vCoords = <<-1804.5464, 403.9298, 112.1966>> helpText[6] = "TRACT_HINT7"
tractPickup[7].vCoords = <<484.2701, 5617.1748, 787.4708>> helpText[7] = "TRACT_HINT8"
tractPickup[8].vCoords = << -75.1004, -819.0673, 325.3656 >> helpText[8] = "TRACT_HINT9"
tractPickup[9].vCoords = <<-1725.34, -189.95, 57.52>> helpText[9] = "TRACT_HINT10"
iTimer_DelayForPhoneText = GET_GAME_TIMER()
//set up which pickup the Player is looking for
REPEAT MAX_TRACT_PICKUPS iScrap
ipackNum = PACKSTAT_TRACT_START + iScrap
IF GET_PACKED_STAT_BOOL(INT_TO_ENUM(STATS_PACKED, ipackNum))
iCurrentLocToFind++
ENDIF
ENDREPEAT
eStage = STAGE_PROCESS
ENDPROC
/// PURPOSE: sort looking at scrap if close
PROC SORT_HEADTRACKING_FOR_TRACT(VECTOR coord)
IF IS_ENTITY_IN_RANGE_COORDS(PLAYER_PED_ID(), coord, 7.0)
TASK_LOOK_AT_COORD(PLAYER_PED_ID(), coord, 100, SLF_WHILE_NOT_IN_FOV, SLF_LOOKAT_LOW)
ENDIF
ENDPROC
/// PURPOSE: Checks if Player has reached current location. If they have, print hint for next
/// After a short time, sends the first clue via text.
PROC DO_PROCESS()
IF IS_ENTITY_ALIVE(PLAYER_PED_ID())
AND NOT IS_CURRENTLY_ON_MISSION_OF_TYPE(MISSION_TYPE_DIRECTOR) // Fix for B*2204893 and B*2204914
// If you walk towards a tract piece and start Director Mode *just* as you're about to touch it, when you come back from DM you collect
// the pickup immediately as the screen fades in. The onscreen message then said "0/10 collected" - I think this was because the stat system
// hadn't reset itself when you picked it up, so SET_PACKED_STAT_BOOL (which the message relies on) seemed to fail.
// If we wait for the screen to be faded in, this appears to work though? -IG
AND NOT IS_SCREEN_FADED_OUT()
IF iCurrentLocToFind < MAX_TRACT_PICKUPS
//send first text with delay if not sent already
IF (iCurrentLocToFind = 0)
IF NOT HAS_ONE_TIME_HELP_DISPLAYED(FHM_FIRST_TRACT_CLUE)
AND (GET_GAME_TIMER() - iTimer_DelayForPhoneText > iphoneTextDelay)
SEND_TEXT_MESSAGE_TO_CHARACTER_BUFFER(CHAR_MICHAEL, CHAR_MARNIE, helpText[0], TXTMSG_UNLOCKED)
SET_ONE_TIME_HELP_MESSAGE_DISPLAYED(FHM_FIRST_TRACT_CLUE)
iTimer_DelayForPhoneText = -1 //halt message sending, it's been sent
#IF IS_DEBUG_BUILD
IF bDebug_PrintToTTY
CPRINTLN(DEBUG_MISSION, "Epsilon Tract: Send text message for tract 0")
ENDIF
#ENDIF
ENDIF
ELIF iCurrentLocToFind < MAX_TRACT_PICKUPS
IF NOT (iTimer_DelayForPhoneText = -1)
IF (GET_GAME_TIMER() - iTimer_DelayForPhoneText > 15000)
SEND_TEXT_MESSAGE_TO_CHARACTER_BUFFER(CHAR_MICHAEL, CHAR_MARNIE, helpText[iCurrentLocToFind], TXTMSG_UNLOCKED)
iTimer_DelayForPhoneText = -1 //halt message sending, it's been sent
#IF IS_DEBUG_BUILD
IF bDebug_PrintToTTY
CPRINTLN(DEBUG_MISSION, "Epsilon Tract: Send text message for tract ", iCurrentLocToFind)
ENDIF
#ENDIF
ENDIF
ENDIF
ENDIF
IF tractPickup[iCurrentLocToFind].bActive
// If the tract pickup has been collected
IF HAS_PICKUP_BEEN_COLLECTED(tractPickup[iCurrentLocToFind].pickup)
OR HAS_PLAYER_COLLECTED_PICKUP_IN_WATER_VEHICLE(tractPickup[iCurrentLocToFind].pickup)
IF DOES_ENTITY_EXIST(PLAYER_PED_ID())
TASK_CLEAR_LOOK_AT(PLAYER_PED_ID())
ENDIF
SAFE_REMOVE_PICKUP(tractPickup[iCurrentLocToFind].pickup)
tractPickup[iCurrentLocToFind].bActive = FALSE
SET_CONTROL_SHAKE(PLAYER_CONTROL, PICKUP_RUMBLE_DURATION, PICKUP_RUMBLE_FREQ)
#IF IS_DEBUG_BUILD
IF bDebug_PrintToTTY
CPRINTLN(DEBUG_MISSION, "Epsilon Tract: Picked up tract #", iCurrentLocToFind)
ENDIF
#ENDIF
INT ipackNum = PACKSTAT_TRACT_START + iCurrentLocToFind
SET_PACKED_STAT_BOOL(INT_TO_ENUM(STATS_PACKED, ipackNum), TRUE)
STAT_INCREMENT(NUM_HIDDEN_PACKAGES_2, 1.0)
#IF IS_DEBUG_BUILD
IF bDebug_PrintToTTY
PRINT_SCRAP_NUMBER(iCurrentLocToFind)
ENDIF
#ENDIF
bDisplayMessage = TRUE
IF iCurrentLocToFind < MAX_TRACT_PICKUPS
iCurrentLocToFind++
iTimer_DelayForPhoneText = GET_GAME_TIMER() //reset timer for message sending
SET_AUTOSAVE_IGNORES_ON_MISSION_FLAG(TRUE)
MAKE_AUTOSAVE_REQUEST()
#IF IS_DEBUG_BUILD
IF bDebug_PrintToTTY
CPRINTLN(DEBUG_MISSION, "Epsilon Tract: Incremented tract to #", iCurrentLocToFind)
ENDIF
#ENDIF
ENDIF
// The tract pickup hasn't been collected
ELIF DOES_PICKUP_EXIST(tractPickup[iCurrentLocToFind].pickup)
SORT_HEADTRACKING_FOR_TRACT(tractPickup[iCurrentLocToFind].vCoords)
REMOVE_SCRAP_WHEN_OUT_OF_RANGE(tractPickup[iCurrentLocToFind].pickup, tractPickup[iCurrentLocToFind].bActive)
ENDIF
ELSE
INT iScrap
WHILE HAS_PLAYER_PICKED_UP_SCRAP(SCRAP_TRACT, iScrap)
AND iScrap < MAX_TRACT_PICKUPS
iScrap++
ENDWHILE
// We need to create the tract pickup
IF iScrap = iCurrentLocToFind
CREATE_SCRAP_WHEN_IN_RANGE(tractPickup[iCurrentLocToFind], eTractModel)
ENDIF
ENDIF
ELSE
IF NOT bMessageOnDisplay
AND NOT bDisplayMessage
#IF IS_DEBUG_BUILD
IF bDebug_PrintToTTY
CPRINTLN(DEBUG_MISSION, "Tract pickups all collected. Mission pass")
ENDIF
#ENDIF
SCRIPT_PASSED()
ENDIF
ENDIF
UPDATE_DISPLAY_MESSAGE(bDisplayMessage, bMessageOnDisplay, iMessageTimer, SCRAP_TRACT, iMessageStage, siMessage, "TRACT_TITLE", "TRACT_COLLECT")
ENDIF
ENDPROC
// ===========================================================================================================
// Script Loop
// ===========================================================================================================
SCRIPT
// Setup death/arrest callbacks
IF HAS_FORCE_CLEANUP_OCCURRED(FORCE_CLEANUP_FLAG_DEBUG_MENU|FORCE_CLEANUP_FLAG_SP_TO_MP|FORCE_CLEANUP_FLAG_REPEAT_PLAY | FORCE_CLEANUP_FLAG_DIRECTOR)
SCRIPT_CLEANUP()
ENDIF
// Stop multiple instances of the same script from running
IF GET_NUMBER_OF_THREADS_RUNNING_THE_SCRIPT_WITH_THIS_HASH (HASH("epsilonTract")) > 1
CPRINTLN(DEBUG_MISSION, "Epsilon Tract is attempting to launch with an instance already active.")
TERMINATE_THIS_THREAD()
ENDIF
// Register the script so that it can be relaunched when loading from a savegame.
Register_Script_To_Relaunch_List(LAUNCH_BIT_RC_AMB_EPSILON_TRACT)
// Setup debug widgets
#IF IS_DEBUG_BUILD
SETUP_TRACT_WIDGETS()
#ENDIF
// Main loop
WHILE (TRUE)
// The wait must go here otherwise SPCID_RESET_EPSILON_TRACT won't reset flags in time...
WAIT(0)
SWITCH eStage
CASE STAGE_INITIALISE
DO_INITIALISE()
BREAK
CASE STAGE_PROCESS
DO_PROCESS()
BREAK
CASE STAGE_CLEANUP
SCRIPT_CLEANUP()
BREAK
ENDSWITCH
#IF IS_DEBUG_BUILD
MAINTAIN_TRACT_WIDGETS()
#ENDIF
ENDWHILE
// Script should never reach here. Always terminate with cleanup function.
ENDSCRIPT