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

1635 lines
64 KiB
Python
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//////////////////////////////////////////////////////////////////////////////////////////
// //
// SCRIPT NAME : Range_Modern.sc //
// AUTHOR : Ryan Paradis //
// DESCRIPTION : Our shooting range! The modern range involves more //
// game like shooting //
// //
//////////////////////////////////////////////////////////////////////////////////////////
//Compile out Title Update changes to header functions.
//Must be before includes.
//CONST_INT USE_TU_CHANGES 0 // Removed by Kenneth R.
#IF IS_DEBUG_BUILD
CONST_INT COMPILE_WIDGET_OUTPUT 0
BOOL PRINT_RANGE_MEDAL_VALUES = FALSE
#ENDIF
USING "socialclub_leaderboard.sch"
USING "Range_Public.sch"
USING "selector_public.sch"
USING "script_oddjob_funcs.sch"
USING "minigame_UIInputs.sch"
USING "cellphone_public.sch"
USING "shop_public.sch"
USING "savegame_public.sch"
USING "mission_titles_private.sch"
USING "cheat_controller_public.sch"
// My four globals:
PED_INDEX rangePlayerPed
enumCharacterList ePlayerChar
VECTOR EARMUFFS_OFFSET = <<0.111, 0, 0>>
VECTOR EARMUFFS_ROT = <<0, 90, 0>>
USING "range_header.sch"
USING "Range_Core_lib.sch"
USING "Range_UI.sch"
USING "Range_Tutorial_lib.sch"
USING "Range_Round_lib.sch"
USING "Range_Menu_lib.sch"
USING "range_round_library.sch"
#IF IS_DEBUG_BUILD
USING "range_debug.sch"
USING "Range_Widget_Support_lib.sch"
#ENDIF
PROC Initialize(Range_RangeData & sRangeData, Range_RoundInfo & sRndInfo, Range_WeaponRounds & sWeapRnds[], Range_SPTData & sSPTInfo, SHOOTING_RANGE_LAUNCH_DATA & launchData, Range_TutorialData & sTutorialInfo)
// No player control for now
IF IS_PLAYER_PLAYING(PLAYER_ID())
SET_PLAYER_CONTROL(PLAYER_ID(), FALSE)
ENDIF
DISABLE_CELLPHONE(TRUE)
DISPLAY_RADAR(FALSE)
SET_PLAYER_NOISE_MULTIPLIER(PLAYER_ID(), 0.0)
// Initialize all of our weapons
INIT_WEAPON_ROUNDS(sWeapRnds)
// Check our unlocks
INIT_ROUND_UNLOCKS(sWeapRnds)
// Create our HUD items
SETUP_SPT_QUEUE(sSPTInfo.sSPTQueue)
// Store where we are.
sRangeData.eLocation = launchData.eLocation
// Allow me to draw debug info
// SET_DEBUG_LINES_AND_SPHERES_DRAWING_ACTIVE(TRUE)
// Range Corners -- 0: Back Left, 1: Back Right, 2: Front Right, 3: Front Left
IF (sRangeData.eLocation = RANGELOC_PILLBOX_HILL)
sRangeData.vDoorPos = <<6.8179, -1098.2095, 29.9469>>
sRangeData.vRangeCorners[RANGE_FRONT_LEFT] = << 12.617, -1092.350, 31.580 >>
sRangeData.vRangeCorners[RANGE_BACK_LEFT] = << 16.475, -1081.5134, 31.580 >>
sRangeData.vRangeCorners[RANGE_BACK_RIGHT] = << 20.1332, -1081.7876, 31.580 >>
sRangeData.vRangeCorners[RANGE_FRONT_RIGHT] = << 17.325, -1094.090, 31.580 >>
// Here are the far coords
sRangeData.vRangeCorners[RANGE_FRONT_LEFT_FAR] = << 16.995, -1080.040, 31.580 >>
sRangeData.vRangeCorners[RANGE_BACK_LEFT_FAR] = << 19.475, -1073.203, 31.580 >>
sRangeData.vRangeCorners[RANGE_FRONT_RIGHT_FAR] = << 21.945, -1081.930, 31.580 >>
sRangeData.vPlayerRootPos = <<13.4784, -1097.4746, 28.8347>>
sRangeData.fPlayerRootHead = 345.1710 // 339.6250
sRangeData.vAngledAreaChk1 = <<11.1371, -1097.8242, 23.8347>>
sRangeData.vAngledAreaChk2 = <<14.8423, -1099.4520, 33.8348>>
sRangeData.vRedressPos = <<7.6658, -1097.2264, 28.7970>>
sRangeData.fRedressHead = 166.8465
sRangeData.vRedressGoto = <<7.4450, -1100.0970, 28.7970>>
sRangeData.vRedressCamStart = <<8.7466, -1103.6846, 30.1295>>
sRangeData.vRedressCamStartOrient = <<-0.8304, -0.0000, 19.3158>>
sRangeData.vRedressCamInterp = <<8.6633, -1103.4474, 30.1259>>
sRangeData.vRedressCamInterpOrient = <<-0.8304, -0.0000, 19.3158>>
sRangeData.vRedressCamEnd = <<6.4526, -1098.5763, 30.4486>>
sRangeData.vRedressCamEndOrient = <<-7.9441, -0.0000, -150.3985>>
sRangeData.vQuitCamPos = <<14.6062, -1096.6014, 30.3995>>
sRangeData.vQuitCamOrient = <<-6.4007, 0.0000, 128.1684>>
sRangeData.vRemoveGlassesFacing = <<12.65248, -1100.08313, 29.74706>>
sRangeData.vRedressLeaveRangeGoto = <<7.7033, -1097.8596, 28.7970>>
sTutorialInfo.vSceneRootPos = << 6.818, -1098.210, 29.946 >>
sTutorialInfo.vSceneRootOrient = << 0.000, 0.000, 160.000 >>
sTutorialInfo.vScoreTargetPos = <<14.4990, -1093.4354, 31.32>>
sTutorialInfo.vNonTutorialCamPos = <<13.9958, -1097.8820, 30.3701>>
sTutorialInfo.vNonTutorialCamOrient = <<-6.0067, -0.0000, -19.5923>>
sTutorialInfo.vNonTutorialCamEndPos = <<13.4248, -1099.6191, 30.4893>>
sTutorialInfo.vNonTutorialCamEndOrient = <<-6.1681, -0.0000, -12.1775>>
sRangeData.fTargetEndZRot = 160.0
ELSE
sRangeData.vDoorPos = <<827.5342, -2160.4927, 29.7688>>
sRangeData.vRangeCorners[RANGE_FRONT_LEFT] = <<824.1354, -2167.8152, 31.4334>>
sRangeData.vRangeCorners[RANGE_BACK_LEFT] = <<824.0692, -2179.0039, 31.3222>>
sRangeData.vRangeCorners[RANGE_BACK_RIGHT] = <<820.6007, -2180.3564, 31.3625>>
sRangeData.vRangeCorners[RANGE_FRONT_RIGHT] = <<819.0558, -2167.5212, 31.4334>>
// Here are the far coords
sRangeData.vRangeCorners[RANGE_FRONT_LEFT_FAR] = <<823.9216, -2180.9316, 31.2504>>
sRangeData.vRangeCorners[RANGE_BACK_LEFT_FAR] = <<823.9360, -2188.2485, 31.1813>>
sRangeData.vRangeCorners[RANGE_FRONT_RIGHT_FAR] = <<818.8218, -2180.8616, 31.3736>>
sRangeData.vPlayerRootPos = <<821.5508, -2163.7073, 28.6567>>
sRangeData.fPlayerRootHead = 184.3922
sRangeData.vAngledAreaChk1 = <<823.5616, -2162.2393, 24.4409>>
sRangeData.vAngledAreaChk2 = <<819.3583, -2163.4966, 34.5824>>
sRangeData.vRedressPos = <<826.8076, -2162.1846, 28.6190>>
sRangeData.fRedressHead = 346.2118
sRangeData.vRedressGoto = <<824.8320, -2158.3601, 28.6190>>
sRangeData.vRedressCamStart = <<823.9988, -2156.3330, 29.8591>>
sRangeData.vRedressCamStartOrient = <<-1.9082, 0.0000, -142.3420>>
sRangeData.vRedressCamInterp = <<824.2747, -2156.6902, 29.8441>>
sRangeData.vRedressCamInterpOrient = <<-1.9082, 0.0000, -142.3420>>
sRangeData.vRedressCamEnd = <<827.7817, -2160.1260, 30.2877>>
sRangeData.vRedressCamEndOrient = <<-8.0026, 0.0000, 55.1241>>
sRangeData.vQuitCamPos = <<820.7900, -2164.8320, 30.1899>>
sRangeData.vQuitCamOrient = <<-2.2613, -0.0000, -30.6783>>
sRangeData.vRemoveGlassesFacing = <<821.5570, -2160.8552, 30.3338>>
sRangeData.vRedressLeaveRangeGoto = <<826.6258, -2161.7048, 28.6190>>//<<822.3644, -2163.3521, 30.9273>>
sTutorialInfo.vSceneRootPos = <<827.5342, -2160.4927, 29.7688>>
sTutorialInfo.vSceneRootOrient = << 0,0,0 >>
sTutorialInfo.vScoreTargetPos = <<821.9563, -2167.0859, 31.0>>
sTutorialInfo.vNonTutorialCamPos = <<820.9255, -2163.0254, 30.1917>>
sTutorialInfo.vNonTutorialCamOrient = <<-4.2298, 0.0000, -179.5710>>
sTutorialInfo.vNonTutorialCamEndPos = <<820.8491, -2161.1663, 30.3292>>
sTutorialInfo.vNonTutorialCamEndOrient = <<-4.2298, -0.0000, -173.1768>>
sRangeData.fTargetEndZRot = 359.0
ENDIF
// Int our range
INIT_RANGE_GRID(sRangeData, sRndInfo)
// Just temp spot for these now
sRndInfo.iMaxActions = 0
sRndInfo.fCurrentRoundLength = 45.0
sTutorialInfo.eSceneState = eRangeSyncScene_Init
// Now law
ENABLE_DISPATCH_SERVICE(DT_POLICE_AUTOMOBILE,FALSE)
ENABLE_DISPATCH_SERVICE(DT_POLICE_HELICOPTER,FALSE)
SET_WANTED_LEVEL_MULTIPLIER(0.0)
SET_MAX_WANTED_LEVEL(0)
SET_EVERYONE_IGNORE_PLAYER(GET_PLAYER_INDEX(), TRUE)
CLEAR_RANK_REDICTION_DETAILS()
RANGE_SP_CLEANUP_SOCIAL_CLUB_LEADERBOARD()
ENDPROC
// Cleanup the script on termination must not include any WAITs
PROC Script_Cleanup(Range_RangeData & sRangeInfo, Range_Targets & sTargData, Range_CoreData & sCoreInfo, Range_MenuData & sMenuInfo, VEHICLE_SAVE_ARGS &vehPlayerCar, BOOL bForceCleanup=FALSE)
CDEBUG2LN(DEBUG_SHOOTRANGE, "Shooting Range: Script_Cleanup()")
SET_STATE_OF_CLOSEST_DOOR_OF_TYPE(V_ILEV_GC_DOOR01, sRangeInfo.vDoorPos, FALSE, 0.0) //unlock the door now that we've ended.
// We may need to make an emergency write.
IF sCoreInfo.ProcessPrediction AND NOT scLB_rank_predict.bFinishedWrite
WRITE_TO_RANGE_SP_HIGH_SCORE_LEADERBOARD(sCoreInfo.lbdWrite)
ENDIF
CLEAR_RANK_REDICTION_DETAILS()
RANGE_SP_CLEANUP_SOCIAL_CLUB_LEADERBOARD()
MISSION_FLOW_CLEAR_DISPLAY_MISSION_TITLE()
DISABLE_COMPOSITE_SHOTGUN_DECALS(FALSE)
ODDJOB_RESTORE_SAVED_VEHICLE(vehPlayerCar)
IF IS_SHOOTING_RANGE_UNSAVED_BITFLAG_SET(SRB_RangeInSession)
CLEAR_SHOOTING_RANGE_UNSAVED_BITFLAG(SRB_RangeInSession)
ENDIF
// Resetting last known info to be consistent with missions, B*909265
ResetLastKnownPedInfo(g_savedGlobals.sPlayerData.sInfo, SP_MISSION_NONE)
IF g_bResultScreenDisplaying
SET_RESULT_SCREEN_DISPLAYING_STATE(FALSE)
ENDIF
ENABLE_SELECTOR()
SET_PLAYER_NOISE_MULTIPLIER(PLAYER_ID(), 1.0)
SET_GAME_PAUSED(FALSE)
// Destroy all targets
INT iTer
REPEAT iMAX_ENTITIES iTer
DESTROY_TARGET(sTargData.sTargetEntities[iTer].target)
ENDREPEAT
IF NOT sCoreInfo.bRestoredWeapons
RANGE_RESTORE_PLAYER_WEAPONS(sCoreInfo.sWeapons)
ENDIF
IF DOES_ENTITY_EXIST(sCoreInfo.oEarMuffs)
SET_OBJECT_AS_NO_LONGER_NEEDED(sCoreInfo.oEarMuffs)
ENDIF
REMOVE_ANIM_DICT("mini@ears_defenders")
IF NOT IS_TRANSITION_ACTIVE()
AND GET_CAM_VIEW_MODE_FOR_CONTEXT(CAM_VIEW_MODE_CONTEXT_ON_FOOT) <> CAM_VIEW_MODE_FIRST_PERSON
AND NOT RANGE_GET_HAS_PLAYER_KICKED_OFF_IN_RANGE( sCoreInfo )
CDEBUG2LN(DEBUG_SHOOTRANGE, "STOP_RENDERING_SCRIPT_CAMS_USING_CATCH_UP(FALSE)")
STOP_RENDERING_SCRIPT_CAMS_USING_CATCH_UP(FALSE)
ENDIF
// Player can switch weapons again
SET_PED_CAN_SWITCH_WEAPON(rangePlayerPed, TRUE)
// Turn off our Radar
DISPLAY_RADAR(TRUE)
// Give control back
SET_PLAYER_CONTROL(PLAYER_ID(), TRUE)
// don't need to keep the interior loaded.
IF (sCoreInfo.RangeInterior <> NULL)
UNPIN_INTERIOR(sCoreInfo.RangeInterior)
sCoreInfo.RangeInterior = NULL
ENDIF
// Clear floaty help.
CLEAR_FLOATING_HELP(FLOATING_HELP_TEXT_ID_2)
CLEAR_ALL_FLOATING_HELP()
// Turn law in this shop back on
SET_PLAYER_IS_ALLOWED_TO_SHOOT_IN_SHOP(GUN_SHOP_01_DT, FALSE)
ENABLE_DISPATCH_SERVICE(DT_POLICE_AUTOMOBILE, TRUE)
ENABLE_DISPATCH_SERVICE(DT_POLICE_HELICOPTER, TRUE)
SET_WANTED_LEVEL_MULTIPLIER(1.0)
SET_MAX_WANTED_LEVEL(6)
SET_EVERYONE_IGNORE_PLAYER(GET_PLAYER_INDEX(), FALSE)
RELEASE_SCRIPT_AUDIO_BANK()
CLEAR_ADDITIONAL_TEXT(MINIGAME_TEXT_SLOT, FALSE)
DISABLE_CELLPHONE(FALSE)
//B* 2138704: Remove railgun if before Exile1
IF DOES_PLAYER_HAVE_WEAPON(WEAPONTYPE_DLC_RAILGUN)
IF NOT GET_MISSION_COMPLETE_STATE(SP_MISSION_EXILE_1)
OR NOT IS_PLAYER_PED_WEAPON_PURCHASED(GET_PLAYER_PED_ENUM(PLAYER_PED_ID()),WEAPONTYPE_DLC_RAILGUN)
CPRINTLN(DEBUG_SHOOTRANGE,"Player has the Railgun before completing Exile1 or without purchasing it, removing from inventory")
REMOVE_WEAPON_FROM_PED(PLAYER_PED_ID(), WEAPONTYPE_DLC_RAILGUN)
ENDIF
ENDIF
CLEANUP_SIMPLE_USE_CONTEXT(sMenuInfo.menuContext)
RANGE_CLEAN_UI(sMenuInfo)
RELEASE_MINIGAME_COUNTDOWN_UI(sMenuInfo.uiCountdown)
#IF IS_DEBUG_BUILD
CLEANUP_RANGE_WIDGETS()
#ENDIF
IF sCoreInfo.bDelayShutdown
CDEBUG2LN(DEBUG_SHOOTRANGE, "Range Core has been ordered to delay shutdown. Delaying 10 seconds...")
WAIT(10000)
ENDIF
IF IS_SCREEN_FADED_OUT()
DO_SCREEN_FADE_IN(500)
ENDIF
SET_AUTOSAVE_IGNORES_ON_MISSION_FLAG(FALSE)
// ENABLE CHEATS!
DISABLE_CHEAT(CHEAT_TYPE_ALL, FALSE)
DISABLE_CHEAT(CHEAT_TYPE_GIVE_WEAPONS, FALSE)
IF bForceCleanup
IF DOES_ENTITY_EXIST(sCoreInfo.oEarMuffs)
DELETE_OBJECT(sCoreInfo.oEarMuffs)
ENDIF
CLEAR_PED_PROP(rangePlayerPed, ANCHOR_HEAD)
CLEAR_PED_PROP(rangePlayerPed, ANCHOR_EYES)
ENDIF
SET_SHOP_IGNORES_KICKING_OFF_CHECKS(GUN_SHOP_01_DT, FALSE)
SET_SHOP_IGNORES_KICKING_OFF_CHECKS(GUN_SHOP_11_ID1, FALSE)
CPRINTLN(DEBUG_SHOOTRANGE, "Michael's Discounts")
CPRINTLN(DEBUG_SHOOTRANGE, "Gold Discount: ", PICK_STRING( IS_BITMASK_AS_ENUM_SET(g_savedGlobals.sRangeData[0].iBools, SRB_ShownFloatingHelp_ShopDiscountGold), "unlocked", "locked" ) )
CPRINTLN(DEBUG_SHOOTRANGE, "Silver Discount: ", PICK_STRING( IS_BITMASK_AS_ENUM_SET(g_savedGlobals.sRangeData[0].iBools, SRB_ShownFloatingHelp_ShopDiscountSilver), "unlocked", "locked" ) )
CPRINTLN(DEBUG_SHOOTRANGE, "Bronze Discount: ", PICK_STRING( IS_BITMASK_AS_ENUM_SET(g_savedGlobals.sRangeData[0].iBools, SRB_ShownFloatingHelp_ShopDiscountBronze), "unlocked", "locked" ) )
CPRINTLN(DEBUG_SHOOTRANGE, "Franklin's Discounts")
CPRINTLN(DEBUG_SHOOTRANGE, "Gold Discount: ", PICK_STRING( IS_BITMASK_AS_ENUM_SET(g_savedGlobals.sRangeData[1].iBools, SRB_ShownFloatingHelp_ShopDiscountGold), "unlocked", "locked" ) )
CPRINTLN(DEBUG_SHOOTRANGE, "Silver Discount: ", PICK_STRING( IS_BITMASK_AS_ENUM_SET(g_savedGlobals.sRangeData[1].iBools, SRB_ShownFloatingHelp_ShopDiscountSilver), "unlocked", "locked" ) )
CPRINTLN(DEBUG_SHOOTRANGE, "Bronze Discount: ", PICK_STRING( IS_BITMASK_AS_ENUM_SET(g_savedGlobals.sRangeData[1].iBools, SRB_ShownFloatingHelp_ShopDiscountBronze), "unlocked", "locked" ) )
CPRINTLN(DEBUG_SHOOTRANGE, "Trevor's Discounts")
CPRINTLN(DEBUG_SHOOTRANGE, "Gold Discount: ", PICK_STRING( IS_BITMASK_AS_ENUM_SET(g_savedGlobals.sRangeData[2].iBools, SRB_ShownFloatingHelp_ShopDiscountGold), "unlocked", "locked" ) )
CPRINTLN(DEBUG_SHOOTRANGE, "Silver Discount: ", PICK_STRING( IS_BITMASK_AS_ENUM_SET(g_savedGlobals.sRangeData[2].iBools, SRB_ShownFloatingHelp_ShopDiscountSilver), "unlocked", "locked" ) )
CPRINTLN(DEBUG_SHOOTRANGE, "Bronze Discount: ", PICK_STRING( IS_BITMASK_AS_ENUM_SET(g_savedGlobals.sRangeData[2].iBools, SRB_ShownFloatingHelp_ShopDiscountBronze), "unlocked", "locked" ) )
CDEBUG2LN(DEBUG_SHOOTRANGE, "******************* TERMINATING THE SHOOTING RANGE *******************")
TERMINATE_THIS_THREAD()
ENDPROC
/// PURPOSE:
/// Removes the player's glasses and ear defenders with or without animations involved.
/// PARAMS:
/// sCoreInfo -
/// sTutorialInfo -
/// sRangeInfo -
/// RETURNS:
/// TRUE when finished removing stuff. FALSE otherwise.
FUNC BOOL RANGE_REMOVE_CRANIAL_ACCESSORIES(Range_CoreData & sCoreInfo, Range_TutorialData & sTutorialInfo, Range_RangeData & sRangeInfo)
IF GET_CAM_VIEW_MODE_FOR_CONTEXT(CAM_VIEW_MODE_CONTEXT_ON_FOOT) = CAM_VIEW_MODE_FIRST_PERSON
CDEBUG2LN(DEBUG_SHOOTRANGE, "Deleting glasses, in first person")
CLEAR_PED_PROP(rangePlayerPed, ANCHOR_EYES)
IF DOES_ENTITY_EXIST(sCoreInfo.oEarmuffs)
CDEBUG2LN(DEBUG_SHOOTRANGE, "Deleting ear muffs, in first person")
DELETE_OBJECT(sCoreInfo.oEarmuffs)
ENDIF
CLEAR_PED_PROP(rangePlayerPed, ANCHOR_HEAD)
RETURN TRUE
ENDIF
IF (GET_SCRIPT_TASK_STATUS(rangePlayerPed, SCRIPT_TASK_PERFORM_SEQUENCE) != PERFORMING_TASK)
// This handles all cases of quitting.
// If we've been tasked to sequentially play an anim, once it's started, the sequence is done.
// Alternatively, if we walk out or something, we never started the sequence.
IF (sCoreInfo.iEarsRemoveStart = 0)
IF NOT sCoreInfo.bFailed
IF NOT DOES_CAM_EXIST(sTutorialInfo.sceneCamera)
sTutorialInfo.sceneCamera = CREATE_CAM("DEFAULT_SCRIPTED_CAMERA")
ENDIF
SET_CAM_COORD(sTutorialInfo.sceneCamera, sRangeInfo.vQuitCamPos)
SET_CAM_ROT(sTutorialInfo.sceneCamera, sRangeInfo.vQuitCamOrient)
SET_CAM_FOV(sTutorialInfo.sceneCamera, 50.0)
SET_CAM_ACTIVE(sTutorialInfo.sceneCamera, TRUE)
RENDER_SCRIPT_CAMS(TRUE, FALSE)
SET_GAMEPLAY_CAM_RELATIVE_PITCH(0.0)
SET_GAMEPLAY_CAM_RELATIVE_HEADING(0.0)
ENDIF
sCoreInfo.iAnimStartTime = GET_GAME_TIMER()
sCoreInfo.iEarsRemoveStart = 315 + GET_GAME_TIMER()
sCoreInfo.iEarsRemoveEnd = 920 + GET_GAME_TIMER()
ENDIF
ENDIF
IF (sCoreInfo.iEarsRemoveStart != 0)
// Remove glasses.
IF GET_GAME_TIMER() >= sCoreInfo.iEarsRemoveStart
CDEBUG2LN(DEBUG_SHOOTRANGE, "Deleting glasses")
CLEAR_PED_PROP(rangePlayerPed, ANCHOR_EYES)
IF DOES_ENTITY_EXIST(sCoreInfo.oEarmuffs)
IF NOT IS_ENTITY_VISIBLE(sCoreInfo.oEarmuffs)
CDEBUG2LN(DEBUG_SHOOTRANGE, "showing object earmuffs")
SET_ENTITY_VISIBLE(sCoreInfo.oEarmuffs, TRUE)
ENDIF
ENDIF
IF NOT IS_PED_INJURED(PLAYER_PED_ID())
CDEBUG2LN(DEBUG_SHOOTRANGE, "clearing head ped prop")
CLEAR_PED_PROP(PLAYER_PED_ID(), ANCHOR_HEAD)
ENDIF
ENDIF
IF GET_GAME_TIMER() >= sCoreInfo.iEarsRemoveStart AND GET_GAME_TIMER() < sCoreInfo.iEarsRemoveEnd // time to attach earmuffs to the ped's hand
CDEBUG2LN(DEBUG_SHOOTRANGE, "Attaching earmuffs to hand")
ATTACH_ENTITY_TO_ENTITY(sCoreInfo.oEarmuffs, PLAYER_PED_ID(), GET_PED_BONE_INDEX(PLAYER_PED_ID(), BONETAG_PH_L_HAND),
(<<0,0,0>>), (<<0,0,0>>), TRUE, TRUE, TRUE)
ELIF GET_GAME_TIMER() >= sCoreInfo.iEarsRemoveEnd
CDEBUG2LN(DEBUG_SHOOTRANGE, "Detaching earmuffs from hand")
DETACH_ENTITY(sCoreInfo.oEarmuffs)
RETURN TRUE
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// PRocesses the player's final state, where he'll remove glasses, etc.
PROC RANGE_MONITOR_END_CUTSCENE(Range_CoreData & sCoreInfo, Range_RoundInfo & sRndInfo, Range_TutorialData & sTutorialInfo, Range_Targets & sTargInfo, Range_MenuData & sMenuInfo, VEHICLE_SAVE_ARGS &vehPlayerCar, Range_RangeData & sRangeInfo)
IF NOT sCoreInfo.bTriggeredOutro
IF IS_ROUND_FLAG_SET(sRndInfo, ROUND_FAIL_TARGET_CLEANUP)
BOOL bAnimFinished = RANGE_REMOVE_CRANIAL_ACCESSORIES(sCoreInfo, sTutorialInfo, sRangeInfo)
IF NOT ARE_ANY_TARGET_ENTITIES_MOVING(sRndInfo, sTargInfo.sTargetEntities) AND bAnimFinished
CLEAR_ROUND_FLAG(sRndInfo, ROUND_FAIL_TARGET_CLEANUP)
// If the palyer had something on his head, we need to have an exit cut to show him taking it off..
IF (sCoreInfo.iStartHeadPropIdx != -1 OR sCoreInfo.iStartFacePropIdx != -1)
AND NOT sCoreInfo.bFailed
SETTIMERA(0)
TASK_FOLLOW_NAV_MESH_TO_COORD(rangePlayerPed, sRangeInfo.vRedressLeaveRangeGoto, PEDMOVEBLENDRATIO_WALK)
sCoreInfo.eRangeState = SRM_TRIGGER_EXIT_REDRESS
sCoreInfo.bTriggeredOutro = TRUE
ELSE
Script_Cleanup(sRangeInfo, sTargInfo, sCoreInfo, sMenuInfo, vehPlayerCar)
ENDIF
ENDIF
ELIF CHECK_RANGE_PLAYER_FAIL_CONDITIONS(sCoreInfo, sRangeInfo)
sCoreInfo.bFailed = TRUE
EXIT_ALL_TARGETS(sTargInfo.sTargetEntities)
SET_ROUND_FLAG(sRndInfo, ROUND_FAIL_TARGET_CLEANUP)
sCoreInfo.bRestoredWeapons = TRUE
RANGE_RESTORE_PLAYER_WEAPONS(sCoreInfo.sWeapons)
IF GET_CAM_VIEW_MODE_FOR_CONTEXT(CAM_VIEW_MODE_CONTEXT_ON_FOOT) = CAM_VIEW_MODE_FIRST_PERSON
EXIT
ENDIF
WAIT(1000)
ANIM_DATA none
ANIM_DATA animDataBlend
INT iAnimFlags = 0
animDataBlend.type = APT_SINGLE_ANIM
animDataBlend.anim0 = "takeoff_earsdefenders_idle"
animDataBlend.dictionary0 = "mini@ears_defenders"
animDataBlend.phase0 = 0.0
animDataBlend.rate0 = 1.0
animDataBlend.filter = GET_HASH_KEY("BONEMASK_HEAD_NECK_AND_L_ARM")
iAnimFlags += ENUM_TO_INT(AF_SECONDARY)
iAnimFlags += ENUM_TO_INT(AF_EXIT_AFTER_INTERRUPTED)
animDataBlend.flags = INT_TO_ENUM(ANIMATION_FLAGS, iAnimFlags)
TASK_SCRIPTED_ANIMATION(rangePlayerPed, animDataBlend, none, none, SLOW_BLEND_DURATION, SLOW_BLEND_DURATION)
CPRINTLN(DEBUG_SHOOTRANGE, "TASKING TO PLAY REMOVAL ANIM!!!!")
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// Sets the player's initial state in the range, clears the area, pins interior.
PROC RANGE_SET_INITAL_STATE(Range_CoreData & sCoreInfo, Range_RangeData & sRangeInfo)
SET_ROOM_FOR_GAME_VIEWPORT_BY_NAME("V_7_ShootRm")
// Clear the area of vehicles and projectiles
CLEAR_AREA_OF_VEHICLES(sRangeInfo.vPlayerRootPos, 20)
RANGE_STORE_PLAYER_WEAPONS(sCoreInfo.sWeapons)
SET_PED_STEALTH_MOVEMENT(rangePlayerPed, FALSE)
// We need to stream that interior.
IF (sCoreInfo.RangeInterior = NULL)
sCoreInfo.RangeInterior = GET_INTERIOR_AT_COORDS(sRangeInfo.vPlayerRootPos)
PIN_INTERIOR_IN_MEMORY(sCoreInfo.RangeInterior)
ENDIF
ENDPROC
/// PURPOSE:
/// The main update loop for the shooting range
PROC UPDATE_MAIN(Range_CoreData & sCoreInfo, Range_RoundInfo & sRndInfo, Range_TutorialData & sTutorialInfo, Range_Targets & sTargInfo, Range_WeaponRounds & sWeaponRndInfo[],
Range_RangeData & sRangeInfo, Range_SPTData & sSPTInfo, Range_MenuData & sMenuInfo, VEHICLE_SAVE_ARGS &vehPlayerCar,
SHOOTING_RANGE_LAUNCH_DATA & launchData)
IF NOT IS_CELLPHONE_DISABLED()
DISABLE_CELLPHONE(TRUE)
ENDIF
INT iTer
// This handles player leaving states.
RANGE_MONITOR_END_CUTSCENE(sCoreInfo, sRndInfo, sTutorialInfo, sTargInfo, sMenuInfo, vehPlayerCar, sRangeInfo)
// Don't allow the player to aim at anyone.
SET_PLAYER_LOCKON_RANGE_OVERRIDE(PLAYER_ID(), 0.05)
// Block crimes.
SUPPRESS_CRIME_THIS_FRAME(PLAYER_ID(), CRIME_DISTURBANCE)
SUPPRESS_CRIME_THIS_FRAME(PLAYER_ID(), CRIME_DAMAGE_TO_PROPERTY)
SUPPRESS_CRIME_THIS_FRAME(PLAYER_ID(), CRIME_FIREARM_DISCHARGE)
SET_SHOP_IGNORES_KICKING_OFF_CHECKS(GUN_SHOP_01_DT, TRUE)
SET_SHOP_IGNORES_KICKING_OFF_CHECKS(GUN_SHOP_11_ID1, TRUE)
#IF IS_DEBUG_BUILD
DRAW_DEBUG_TEXT_2D( GET_STRING_FROM_RANGE_STATE(sCoreInfo.eRangeState), (<< 0.9, 0.2, 0.0 >>) )
#ENDIF
SWITCH (sCoreInfo.eRangeState)
CASE SRM_INIT
CDEBUG2LN(DEBUG_SHOOTRANGE, "SRM_INIT")
// Our string table
REQUEST_ADDITIONAL_TEXT("S_RANGE", MINIGAME_TEXT_SLOT)
// Initialize everything
Initialize(sRangeInfo, sRndInfo, sWeaponRndInfo, sSPTInfo, launchData, sTutorialInfo)
enumCharacterList eChar
eChar = GET_CURRENT_PLAYER_PED_ENUM()
IF (eChar = CHAR_MICHAEL)
DO_BANK_ACCOUNT_ACTION(BANK_ACCOUNT_MICHAEL, BAA_DEBIT, BAAC_SHOOTING_RANGE, PRICE_OF_RANGE, TRUE)
ELIF (eChar = CHAR_TREVOR)
DO_BANK_ACCOUNT_ACTION(BANK_ACCOUNT_TREVOR, BAA_DEBIT, BAAC_SHOOTING_RANGE, PRICE_OF_RANGE, TRUE)
ELIF (eChar = CHAR_FRANKLIN)
DO_BANK_ACCOUNT_ACTION(BANK_ACCOUNT_FRANKLIN, BAA_DEBIT, BAAC_SHOOTING_RANGE, PRICE_OF_RANGE, TRUE)
ENDIF
CDEBUG2LN(DEBUG_SHOOTRANGE, "SRM_INIT -> SRM_LOAD_AREA_INTRO")
sCoreInfo.eRangeState = SRM_LOAD_AREA_INTRO
BREAK
// Do our Intro cutscene
CASE SRM_LOAD_AREA_INTRO
SET_PLAYER_CONTROL(PLAYER_ID(), FALSE)
// Instead of loading, just set the assets.
RANGE_REQUEST_FIRST_STAGE_ASSETS()
IF RANGE_HAVE_FIRST_STAGE_ASSETS_LOADED()
RANGE_SET_INITAL_STATE(sCoreInfo, sRangeInfo)
// Wait for the streaming
RESTART_TIMER_AT(sRndInfo.sGenTimer, 0.0)
// Okay, first stage done loading, request all.
RANGE_STREAM_ALL_ASSETS(sCoreInfo.iAudioStreamTimeout, sMenuInfo)
DEBUG_MESSAGE("UpdateMain -- SRM_INIT_DONE (after intro scene)")
sCoreInfo.eRangeState = SRM_INIT_DONE
ENDIF
BREAK
// Wait till everything is loaded
CASE SRM_INIT_DONE
SET_ROOM_FOR_GAME_VIEWPORT_BY_NAME("V_7_ShootRm")
IF GET_TIMER_IN_SECONDS(sRndInfo.sGenTimer) > 1.0
IF IS_SCREEN_FADED_OUT()
DO_SCREEN_FADE_IN(250)
ENDIF
FREEZE_ENTITY_POSITION(rangePlayerPed, FALSE)
// If the tutorial peds don't exist, don't run the tutorial...
BOOL bCanTutorialRun
bCanTutorialRun = TRUE
IF NOT DOES_ENTITY_EXIST(sTutorialInfo.pedGuy1)
OR NOT DOES_ENTITY_EXIST(sTutorialInfo.pedGuy2)
OR NOT DOES_ENTITY_EXIST(sTutorialInfo.pedGuy3)
bCanTutorialRun = FALSE
ENDIF
// Do we do our tutorial first?
IF NOT g_savedGlobals.sRangeData[0].m_bSeenTutorial AND bCanTutorialRun
sTutorialInfo.iTutorialState = 0
SETUP_PLAYER_WEAPONS(WEAPONTYPE_PISTOL, sRndInfo)
TASK_SWAP_WEAPON(rangePlayerPed, TRUE)
RESTART_TIMER_AT(sRndInfo.sGenTimer, 0.0)
g_savedGlobals.sRangeData[0].m_bSeenTutorial = TRUE
DEBUG_MESSAGE("UpdateMain -- SRM_TUTORIAL")
sCoreInfo.eRangeState = SRM_TUTORIAL
ELSE
sTutorialInfo.iTutorialState = 0
DEBUG_MESSAGE("UpdateMain -- SRM_NON_TUTORIAL_INTRO")
sCoreInfo.eRangeState = SRM_NON_TUTORIAL_INTRO
ENDIF
ENDIF
BREAK
CASE SRM_NON_TUTORIAL_INTRO
IF RANGE_RUN_NON_TUTORIAL_INTRO(sTutorialInfo, sRndInfo, sCoreInfo, sRangeInfo)
AND RANGE_HAVE_ALL_ASSETS_STREAMED(sCoreInfo.iAudioStreamTimeout, sMenuInfo)
DEBUG_MESSAGE("UpdateMain -- SRM_PICK_WEAPON")
SET_MISSION_FLOW_FLAG_STATE(FLOWFLAG_GUNRANGE_TUTORIAL_COMPLETED, TRUE)
CANCEL_COMMUNICATION(TEXT_SRANGE_UNLOCK)
SET_STATE_OF_CLOSEST_DOOR_OF_TYPE(V_ILEV_GC_DOOR01, sRangeInfo.vDoorPos, TRUE, 0.0) // lock the door now that we've started
sCoreInfo.eRangeState = SRM_PICK_WEAPON
ENDIF
BREAK
// Weapon pick menu
CASE SRM_PICK_WEAPON
IF IS_PC_VERSION()
DISABLE_CONTROL_ACTION(FRONTEND_CONTROL, INPUT_FRONTEND_PAUSE)
ENDIF
DISABLE_CONTROL_ACTION(FRONTEND_CONTROL, INPUT_FRONTEND_PAUSE_ALTERNATE) // B*2239651 - Disabling pause_alternate during end screens (to avoid clash when exiting leaderboards)
// Make sure the transition is active.
RANGE_UI_TRIGGER_TRANSITION(sMenuInfo, TRUE)
IF NOT IS_TIMER_STARTED(sMenuInfo.tQuitDelay)
RESTART_TIMER_NOW(sMenuInfo.tQuitDelay)
EXIT
ELIF GET_TIMER_IN_SECONDS(sMenuInfo.tQuitDelay) < 0.5
EXIT
ENDIF
// Check if they want to unlock all rounds
#IF IS_DEBUG_BUILD
IF IS_DEBUG_KEY_JUST_PRESSED(KEY_W, KEYBOARD_MODIFIER_NONE, "Unlock all rounds.")
IF NOT CHEAT_ARE_ALL_ROUNDS_UNLOCKED(sCoreInfo)
CHEAT_UNLOCK_ALL_WEAPONS(sCoreInfo)
DEBUG_MESSAGE("ReadWepMenuInput -- Cheat entered, all rounds unlocked.")
// Mess with our menu selections.
sMenuInfo.curMenu = RANGE_MENU_WEAPCAT
sMenuInfo.catMenu.iCurElement = 0
sMenuInfo.weapMenu.iCurElement = -1
sMenuInfo.chalMenu.iCurElement = -1
sMenuInfo.weapMenu.iNumElements = 0
SETUP_RANGE_MENU_CONTROLS(sMenuInfo.menuContext, TRUE, DEFAULT, TRUE)
// Go through all rounds and set them to active.
INT index
FOR index = 0 TO (ENUM_TO_INT(NUM_WEAPON_CATS) - 1)
sMenuInfo.catMenu.menuElement[index].bActive = TRUE
ENDFOR
FOR index = 0 TO MAX_WEAPONS_PER_CAT - 1
sMenuInfo.weapMenu.menuElement[index].bActive = TRUE
ENDFOR
FOR index = 0 TO (ENUM_TO_INT(NUM_WEAPON_CHALLS) - 1)
sMenuInfo.chalMenu.menuElement[index].bActive = TRUE
ENDFOR
ENDIF
ENDIF
#ENDIF
//Put categories and guns that qualify for round 4 here.
IF INT_TO_ENUM(RANGE_WEAPON_CATEGORY, sMenuInfo.catMenu.iCurElement) = WEAPCAT_RAILGUN
AND sCoreInfo.bCGtoNG
sMenuInfo.chalMenu.menuElement[WEAPCHAL_4].bActive = IS_ROUND_CHALLENGE_REQ_MET(sWeaponRndInfo[INT_TO_ENUM(RANGE_WEAPON_CATEGORY, sMenuInfo.catMenu.iCurElement)].sChallenges[WEAPCHAL_4].eUnlockReq) OR CHEAT_ARE_ALL_ROUNDS_UNLOCKED(sCoreInfo)
sMenuInfo.chalMenu.iNumElements = 4
ELSE
sMenuInfo.chalMenu.menuElement[WEAPCHAL_4].bActive = FALSE
sMenuInfo.chalMenu.iNumElements = 3
ENDIF
// Having an issue keeping the room streamed in.
SET_ROOM_FOR_GAME_VIEWPORT_BY_NAME("V_7_ShootRm")
IF NOT (sMenuInfo.bInitMenu)
sMenuInfo.bInitMenu = TRUE
INIT_MAIN_MENU(sCoreInfo, sMenuInfo, sWeaponRndInfo)
ENDIF
// Update our menus. They are compartmentalized.
THREE_STATE_RETVAL tempRet
tempRet = UPDATE_MAIN_MENU(sCoreInfo, sRndInfo, sWeaponRndInfo, sMenuInfo)
IF (tempRet = RETVAL_TRUE)
// We've just been given a complete round description in rndStarting. Set this up as our current playing.
RANGE_SetupRound(sCoreInfo, sRndInfo, sTargInfo, sRangeInfo)
IF (sCoreInfo.eRangeLoc = RANGELOC_PILLBOX_HILL)
SET_STATIC_EMITTER_ENABLED("LOS_SANTOS_AMMUNATION_GUN_RANGE", FALSE)
ELSE
SET_STATIC_EMITTER_ENABLED("SE_AMMUNATION_CYPRESS_FLATS_GUN_RANGE", FALSE)
ENDIF
CANCEL_TIMER(sMenuInfo.tQuitDelay)
// Turn off transition effect.
RANGE_UI_TRIGGER_TRANSITION(sMenuInfo, FALSE)
// Set our next state (to begin countdown)
sCoreInfo.eRangeState = SRM_COUNT_DWN_INIT
ELIF (tempRet = RETVAL_FALSE)
// We've backed out of the first menu. Need to display Are you sure you want to quit screen?
INIT_SIMPLE_USE_CONTEXT(sMenuInfo.menuContext, FALSE, FALSE, TRUE, TRUE)
ADD_SIMPLE_USE_CONTEXT_INPUT(sMenuInfo.menuContext, "FE_HLP29", FRONTEND_CONTROL, INPUT_FRONTEND_ACCEPT)
ADD_SIMPLE_USE_CONTEXT_INPUT(sMenuInfo.menuContext, "FE_HLP31", FRONTEND_CONTROL, INPUT_FRONTEND_CANCEL)
SET_SIMPLE_USE_CONTEXT_FULLSCREEN(sMenuInfo.menuContext, TRUE)
CANCEL_TIMER(sMenuInfo.tQuitDelay)
sCoreInfo.eRangeState = SRM_EXIT_CONF
ENDIF
BREAK
CASE SRM_EXIT_CONF
UPDATE_UI_EXIT(TRUE)
IF IS_CONTROL_JUST_RELEASED(FRONTEND_CONTROL, INPUT_FRONTEND_ACCEPT) // GET_CONTROL_INSTRUCTIONAL_BUTTONS_STRING(FRONTEND_CONTROL, INPUT_FRONTEND_ACCEPT)
// Turn off transition effect.
RANGE_UI_TRIGGER_TRANSITION(sMenuInfo, FALSE)
sCoreInfo.eRangeState = SRM_START_EXIT_CUTSCENE
ENDIF
IF IS_CONTROL_JUST_RELEASED(FRONTEND_CONTROL, INPUT_FRONTEND_CANCEL) //GET_CONTROL_INSTRUCTIONAL_BUTTONS_STRING(FRONTEND_CONTROL, INPUT_FRONTEND_CANCEL)
// Set us to have a previous button depending on our destination...
IF (sMenuInfo.curMenu != RANGE_MENU_WEAPCAT)
SETUP_RANGE_MENU_CONTROLS(sMenuInfo.menuContext, FALSE, DEFAULT, TRUE)
sCoreInfo.eRangeState = SRM_PICK_WEAPON
ELSE
SETUP_RANGE_MENU_CONTROLS(sMenuInfo.menuContext, TRUE, sMenuInfo.catMenu.menuElement[sMenuInfo.catMenu.iCurElement].bActive, TRUE)
sCoreInfo.eRangeState = SRM_PICK_WEAPON
ENDIF
SET_SIMPLE_USE_CONTEXT_MINIGAME_ATTACHED(sMenuInfo.menuContext)
ENDIF
BREAK
CASE SRM_START_EXIT_CUTSCENE
CDEBUG2LN(DEBUG_SHOOTRANGE, "SRM_START_EXIT_CUTSCENE started, script exiting")
IF NOT IS_ROUND_FLAG_SET(sRndInfo, ROUND_FAIL_TARGET_CLEANUP)
SET_ROUND_FLAG(sRndInfo, ROUND_FAIL_TARGET_CLEANUP)
// Turn off transition effect.
RANGE_UI_TRIGGER_TRANSITION(sMenuInfo, FALSE)
IF GET_CAM_VIEW_MODE_FOR_CONTEXT(CAM_VIEW_MODE_CONTEXT_ON_FOOT) <> CAM_VIEW_MODE_FIRST_PERSON
SEQUENCE_INDEX leaveSeq
OPEN_SEQUENCE_TASK(leaveSeq)
TASK_TURN_PED_TO_FACE_COORD(NULL, sRangeInfo.vRemoveGlassesFacing)
ANIM_DATA none
ANIM_DATA animDataBlend
INT iAnimFlags
iAnimFlags = 0
animDataBlend.type = APT_SINGLE_ANIM
animDataBlend.anim0 = "takeoff_earsdefenders_idle"
animDataBlend.dictionary0 = "mini@ears_defenders"
animDataBlend.phase0 = 0.0
animDataBlend.rate0 = 1.0
animDataBlend.filter = GET_HASH_KEY("BONEMASK_HEAD_NECK_AND_L_ARM")
iAnimFlags += ENUM_TO_INT(AF_SECONDARY)
iAnimFlags += ENUM_TO_INT(AF_EXIT_AFTER_INTERRUPTED)
animDataBlend.flags = INT_TO_ENUM(ANIMATION_FLAGS, iAnimFlags)
TASK_SCRIPTED_ANIMATION(NULL, animDataBlend, none, none, SLOW_BLEND_DURATION, SLOW_BLEND_DURATION)
CLOSE_SEQUENCE_TASK(leaveSeq)
TASK_PERFORM_SEQUENCE(rangePlayerPed, leaveSeq)
CLEAR_SEQUENCE_TASK(leaveSeq)
ENDIF
ENDIF
BREAK
// Tutorial if we have too
CASE SRM_TUTORIAL
IF UPDATE_TUTORIAL(sTutorialInfo, sCoreInfo, sTargInfo.sTargetEntities, sRndInfo, sRangeInfo.sRangeGrid, sSPTInfo, sRangeInfo)
AND RANGE_HAVE_ALL_ASSETS_STREAMED(sCoreInfo.iAudioStreamTimeout, sMenuInfo)
ROUND_CLEANUP(sRangeInfo.sRangeGrid, sRndInfo, sTargInfo, sSPTInfo.sSptQueue, sWeaponRndInfo, sMenuInfo, TRUE)
SET_WIDESCREEN_BORDERS(FALSE, 0)
// Clear floaty help.
CLEAR_FLOATING_HELP(FLOATING_HELP_TEXT_ID_2)
SET_MISSION_FLOW_FLAG_STATE(FLOWFLAG_GUNRANGE_TUTORIAL_COMPLETED, TRUE)
CANCEL_COMMUNICATION(TEXT_SRANGE_UNLOCK)
SET_STATE_OF_CLOSEST_DOOR_OF_TYPE(V_ILEV_GC_DOOR01, sRangeInfo.vDoorPos, TRUE, 0.0) // lock the door now that we've started
// Return to the menu
DEBUG_MESSAGE("UpdateMain -- SRM_PICK_WEAPON")
sCoreInfo.eRangeState = SRM_PICK_WEAPON
EXIT
ENDIF
BREAK
// Countdown.
CASE SRM_COUNT_DWN_INIT
// Set the player looking toward the range, do it only once.
IF NOT IS_BITMASK_AS_ENUM_SET(sRndInfo.iRoundFlags, ROUND_WIPE_CAM)
SET_BITMASK_AS_ENUM(sRndInfo.iRoundFlags, ROUND_WIPE_CAM)
IF NOT IS_POINT_IN_ANGLED_AREA(GET_ENTITY_COORDS(PLAYER_PED_ID()), sRangeInfo.vAngledAreaChk1, sRangeInfo.vAngledAreaChk2, 4)
SET_ENTITY_COORDS(PLAYER_PED_ID(), sRangeInfo.vPlayerRootPos)
SET_ENTITY_HEADING(PLAYER_PED_ID(), sRangeInfo.fPlayerRootHead)
CDEBUG2LN(DEBUG_SHOOTRANGE, "SRM_COUNT_DWN_INIT Setting coords and heading because we're at a crap view")
ENDIF
RANGE_SET_PLAYER_CAM_DOWNRANGE(sRangeInfo)
ENDIF
// Short wait here...
IF GET_TIMER_IN_SECONDS(sRndInfo.sGenTimer) >= 0.35
// Give player control back
SET_PLAYER_CONTROL(PLAYER_ID(), TRUE)
CLEAR_ROUND_FLAG(sRndInfo, ROUND_CAN_DISPLAY_TARGET_HELP)
CLEAR_PRINTS()
RESTART_TIMER_AT(sRndInfo.sGenTimer, 0.0)
IF NOT IS_PLAYER_DEAD(PLAYER_ID())
SET_PED_USING_ACTION_MODE(PLAYER_PED_ID(), TRUE)
CDEBUG2LN(DEBUG_SHOOTRANGE, "Setting ped into action mode for shooting range")
ENDIF
CLEAR_RANK_REDICTION_DETAILS()
RANGE_SP_CLEANUP_SOCIAL_CLUB_LEADERBOARD()
sCoreInfo.ePredictedRnd = RT_INVALID
//Print Multiplier help
IF sRndInfo.eWeaponCat = WEAPCAT_PISTOL
PRINT_HELP("SH_MULT_HG")
ELIF sRndInfo.eWeaponCat = WEAPCAT_SMG OR sRndInfo.eWeaponCat = WEAPCAT_AR OR sRndInfo.eWeaponCat = WEAPCAT_LIGHT_MG
PRINT_HELP("SH_MULT_AUTO")
ELIF sRndInfo.eWeaponCat = WEAPCAT_MINIGUN
PRINT_HELP("SH_MULT_HEAVY")
ENDIF
CLEAR_AREA(GET_ENTITY_COORDS(PLAYER_PED_ID()), 100, TRUE)
sCoreInfo.eRangeState = SRM_COUNT_DWN
ENDIF
BREAK
CASE SRM_COUNT_DWN
IF GET_TIMER_IN_SECONDS(sRndInfo.sGenTimer) > 2.25
SET_PLAYER_CONTROL(PLAYER_ID(), TRUE)
RENDER_SCRIPT_CAMS(FALSE, TRUE)
ENDIF
HIDE_HUD_COMPONENT_THIS_FRAME(NEW_HUD_RETICLE)
RANGE_DISABLE_SHOOTING()
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_NEXT_CAMERA)
// When the cd ui is done, move us on!
IF UPDATE_MINIGAME_COUNTDOWN_UI(sMenuInfo.uiCountdown, TRUE, FALSE, TRUE, 3, FALSE, TRUE)
RESET_MULTIPLIER(sRndInfo.sMPData)
CLEAR_ROUND_FLAG(sRndInfo, ROUND_TARGET_HIT) // 2144283 - clear target hit
CLEAR_ROUND_FLAG(sRndInfo, ROUND_SHOT_FIRED) // 2144283 - clear shot fired
sRndInfo.iTargetsHitThisExplosion = 0 // 2144283 - clear hits this explosion
sCoreInfo.eRangeState = SRM_SHOOT
ENDIF
BREAK
//// MAIN STATE RIGHT HERE
CASE SRM_SHOOT
// Draw our hud
DRAW_RANGE_HUD(sRndInfo, sWeaponRndInfo, sSPTInfo)
IF IS_BITMASK_AS_ENUM_SET(sRndInfo.iRoundFlags, ROUND_WIPE_CAM)
CLEAR_BITMASK_AS_ENUM(sRndInfo.iRoundFlags, ROUND_WIPE_CAM)
ENDIF
// Always draw the movie.
DRAW_SCALEFORM_MOVIE(sMenuInfo.uiCountdown.uiCountdown, 0.5, 0.5, 1.0, 1.0, 255, 255, 255, 100)
// If we're more than 1 second into the round, we're now able to display floating help.
IF IS_TIMER_STARTED(sRndInfo.sTimeLeft)
IF GET_TIMER_IN_SECONDS(sRndInfo.sTimeLeft) > 1.0
SET_ROUND_FLAG(sRndInfo, ROUND_CAN_DISPLAY_TARGET_HELP)
// Also, draw the reticle here.
SHOW_HUD_COMPONENT_THIS_FRAME(NEW_HUD_RETICLE)
ENDIF
ENDIF
// Check if times up.
IF IS_ROUND_OVER(sRndInfo, sTargInfo.sTargetEntities)
// Going to force a reload here, just for good looks.
CLEAR_HELP()
STOP_FIRE_IN_RANGE(GET_ENTITY_COORDS(PLAYER_PED_ID()), 100)
// Target slide sounds may persist to here. Shut them down.
STOP_TARGET_SOUNDS(sTargInfo.sTargetEntities, sRndInfo.iMaxTargets)
sCoreInfo.bSkipPressed = TRUE
RESTART_TIMER_AT(sRndInfo.sGenTimer, 0.0)
// Calculate our time bonus, if any.
ROUND_CALCULATE_TIME_BONUS(sRndInfo)
// What's our reason for the round ending?
// And did we pass the minimum score?
INT iScore, iScoreReq
BOOL bPassed
iScore = sRndInfo.sScoreData.iP1Score
iScoreReq = GET_MEDAL_SCORE_REQUIREMENT(sWeaponRndInfo[sRndInfo.eWeaponCat].sChallenges[sRndInfo.eChallengeType], RRM_BRONZE)
IF NOT IS_ROUND_FLAG_SET(sRndInfo, ROUND_NO_TIME_BONUS)
iScore += sRndInfo.sScoreData.iTimeBonus
ENDIF
CDEBUG2LN(DEBUG_SHOOTRANGE, "IF IS_ROUND_OVER checking scores for messaging, iScore=", iScore, ", iScoreReq=", iScoreReq)
bPassed = iScore >= iScoreReq
SET_ROUND_OVER_MESSAGE(sRndInfo, sMenuInfo, bPassed)
IF NOT IS_PLAYER_DEAD(PLAYER_ID())
SET_PED_USING_ACTION_MODE(PLAYER_PED_ID(), FALSE)
IF IS_PED_IN_COVER(PLAYER_PED_ID())
CLEAR_PED_TASKS(PLAYER_PED_ID())
ENDIF
ENDIF
SET_PLAYER_CONTROL(PLAYER_ID(), FALSE)
IF NOT bPassed
PLAY_SOUND_FRONTEND(-1, "LOSER", "HUD_AWARDS")
ELSE
PLAY_SOUND_FRONTEND(-1, "SHOOTING_RANGE_ROUND_OVER", "HUD_AWARDS")
ENDIF
DEBUG_MESSAGE("UpdateMain -- SRM_COMPLETE_MSG")
sCoreInfo.eRangeState = SRM_COMPLETE_MSG
EXIT
ENDIF
// We can hit the back button to leave if we're not cleaning up. Update us pressing back
IF NOT IS_ROUND_FLAG_SET(sRndInfo, ROUND_FAIL_TARGET_CLEANUP)
// Don't display help if we're drawing another important help.
IF NOT IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("SHR_EXIT_HELP")
AND NOT IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("SHR_DEST_LOWHIT")
AND NOT IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("SH_MULT_HG")
AND NOT IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("SH_MULT_AUTO")
AND NOT IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("SH_MULT_HEAVY")
AND NOT IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("SHR_H_LEAVE")
PRINT_HELP_FOREVER("SHR_EXIT_HELP")
ENDIF
IF IS_CONTROL_JUST_PRESSED(FRONTEND_CONTROL, INPUT_CONTEXT)
OR IS_DISABLED_CONTROL_JUST_PRESSED(FRONTEND_CONTROL, INPUT_CONTEXT)
PLAY_RANGE_SOUND("QUIT", TRUE)
sCoreInfo.ePrevState = SRM_SHOOT
PAUSE_RANGE_ROUND(sCoreInfo, sRndInfo, sMenuInfo)
ENDIF
ENDIF
// Update Time Remaining
UPDATE_ROUND_TIME_LEFT(sRndInfo)
// Check what targets need to be created
PROCESS_TARGET_CREATION(sRndInfo, sTargInfo.sTargetEntities, sRangeInfo)
// Check what needs to be done this frame!
PROCESS_TARGET_ACTIONS(sRndInfo, sTargInfo, sRangeInfo)
// Process general round needs
PROCESS_ROUND_GENERAL(sRndInfo)
IF sRndInfo.eWeaponCat <> WEAPCAT_RAILGUN
// Go through all of our targets
INT iTargetsHitThisIter
iTargetsHitThisIter = sRndInfo.iTargetHitsCached // Set equal to the cached hits
BOOL bCheckShotgunHits
bCheckShotgunHits = FALSE // We're not checking shotgun hits unless the buffer has expired
INT iGameTimer
iGameTimer = GET_GAME_TIMER()
// Check that the buffer has expired
IF iGameTimer > sRndInfo.iTargetHitsBuffer
sRndInfo.iTargetHitsCached = 0
bCheckShotgunHits = TRUE
ENDIF
REPEAT sRndInfo.iMaxTargets iTer
// Only update this target if it is occupied
IF CHECK_TARGET_STATUS(sTargInfo.sTargetEntities[iTer], TS_CREATED) AND NOT CHECK_TARGET_STATUS(sTargInfo.sTargetEntities[iTer], TS_DESTROYED)
IF UPDATE_TARGET_ENTITY(sTargInfo.sTargetEntities[iTer], sRangeInfo.sRangeGrid, sRndInfo, sSPTInfo, sRangeInfo)
iTargetsHitThisIter += 1
sRndInfo.iTargetHitsBuffer = iGameTimer + k_RANGE_TARGET_HIT_BUFFER
bCheckShotgunHits = FALSE
CDEBUG2LN(DEBUG_SHOOTRANGE, "SRM_SHOOT We hit another target, increased iTargetsHitThisIter to ", iTargetsHitThisIter)
CDEBUG2LN(DEBUG_SHOOTRANGE, "sRndInfo.iTargetHitsCached = ", sRndInfo.iTargetHitsCached)
CDEBUG2LN(DEBUG_SHOOTRANGE, "bCheckShotgunHits = ", bCheckShotgunHits)
CDEBUG2LN(DEBUG_SHOOTRANGE, "iGameTimer = ", iGameTimer)
CDEBUG2LN(DEBUG_SHOOTRANGE, "sRndInfo.iTargetHitsBuffer = ", sRndInfo.iTargetHitsBuffer)
ENDIF
ENDIF
ENDREPEAT
IF NOT bCheckShotgunHits // We're not submitting results for points, cache off the new number of targets hit.
sRndInfo.iTargetHitsCached = iTargetsHitThisIter
ENDIF
CLEAR_PED_LAST_WEAPON_DAMAGE(rangePlayerPed)
// If we're in the shotgun challenge, and we've destroyed targets this loop, count all and SPT draw.
IF (sRndInfo.sScoreData.eScoreStyle = ROUNDSCORE_DESTRUCTION)
IF (iTargetsHitThisIter <> 0)
ADD_SCORE_TO_SPT(iTargetsHitThisIter, HUD_COLOUR_GREEN, sSPTInfo)
ENDIF
ELIF (sRndInfo.sScoreData.eScoreStyle = ROUNDSCORE_DESTRUCTION_W_BONUS)
// If we're minigun 3, and we've hit some back rows, go ahead and add to SPT.
INT iMult
BOOL bIsMinigunChallenge
bIsMinigunChallenge = (sRndInfo.eRoundType = RT_MINIGUN_CHAL_1 OR sRndInfo.eRoundType = RT_MINIGUN_CHAL_2 OR sRndInfo.eRoundType = RT_MINIGUN_CHAL_3)
IF NOT bIsMinigunChallenge AND NOT bCheckShotgunHits
EXIT
ENDIF
IF bIsMinigunChallenge
iMult = 100
ELSE
iMult = 1
ENDIF
// Handles hitting up to 6 simultaneous targets... impossible? to get more than that.
IF (iTargetsHitThisIter = 1)
ADD_SCORE_TO_SPT(1 * iMult, HUD_COLOUR_GREY, sSPTInfo)
sRndInfo.sScoreData.iP1Score += 1 * iMult
RANGE_INCREMENT_ZONE_HITS(sRndInfo, 4)
ELIF (iTargetsHitThisIter = 2)
ADD_SCORE_TO_SPT(CONST_SHOTTY_2TARGS * iMult, HUD_COLOUR_GREEN, sSPTInfo)
sRndInfo.sScoreData.iP1Score += CONST_SHOTTY_2TARGS * iMult
RANGE_INCREMENT_ZONE_HITS(sRndInfo, 3)
ELIF (iTargetsHitThisIter = 3)
ADD_SCORE_TO_SPT(CONST_SHOTTY_3TARGS * iMult, HUD_COLOUR_BLUE, sSPTInfo)
sRndInfo.sScoreData.iP1Score += CONST_SHOTTY_3TARGS * iMult
RANGE_INCREMENT_ZONE_HITS(sRndInfo, 2)
ELIF (iTargetsHitThisIter = 4)
ADD_SCORE_TO_SPT(CONST_SHOTTY_4TARGS * iMult, HUD_COLOUR_RED, sSPTInfo)
sRndInfo.sScoreData.iP1Score += CONST_SHOTTY_4TARGS * iMult
RANGE_INCREMENT_ZONE_HITS(sRndInfo, 1)
ELIF (iTargetsHitThisIter = 5)
ADD_SCORE_TO_SPT(CONST_SHOTTY_5TARGS * iMult, HUD_COLOUR_YELLOW, sSPTInfo)
sRndInfo.sScoreData.iP1Score += CONST_SHOTTY_5TARGS * iMult
RANGE_INCREMENT_ZONE_HITS(sRndInfo, 1)
ELIF (iTargetsHitThisIter = 6)
ADD_SCORE_TO_SPT(CONST_SHOTTY_6TARGS * iMult, HUD_COLOUR_WHITE, sSPTInfo)
sRndInfo.sScoreData.iP1Score += CONST_SHOTTY_6TARGS * iMult
RANGE_INCREMENT_ZONE_HITS(sRndInfo, 1)
ENDIF
// ENDIF
ELIF (sRndInfo.sScoreData.eScoreStyle = ROUNDSCORE_MINIGUN)
// If we are to increment the multiplier
IF sRndInfo.sMPData.bIncrementMP
// Set the timer back to MAX_MINIGUN_COMBO_FRAMES
RESET_RANGE_MINIGUN_COMBO_TIMER(sRndInfo.sMPData)
IF GET_RANGE_MINIGUN_BLOCK_TIMER(sRndInfo.sMPData) > 0
sRndInfo.sMPData.bIncrementMP = FALSE
sRndInfo.iTotalShots++
ENDIF
ENDIF
UPDATE_RANGE_MINIGUN_COMBO_TIMERS(sRndInfo.sMPData)
ENDIF
// We can check for another hit now.
CLEAR_ROUND_FLAG(sRndInfo, ROUND_TARGET_HIT)
// Shotguns don't get multipliers.
IF (sRndInfo.eWeaponCat = WEAPCAT_SHOTGUN)
sRndInfo.sMPData.bIncrementMP = FALSE
ENDIF
// After checking all the entities, do we need to increase our mp?
IF (sRndInfo.sMPData.bIncrementMP)
// Increment our multiplier
INCREMENT_MULTIPLIER(sRndInfo.sMPData)
sRndInfo.sMPData.bIncrementMP = FALSE
RESET_RANGE_MINIGUN_BLOCK_TIMER(sRndInfo.sMPData)
CDEBUG2LN(DEBUG_SHOOTRANGE, "Incrementing iTotalShots because (sRndInfo.sMPData.bIncrementMP) :: ", sRndInfo.iTotalShots)
ELIF IS_ROUND_FLAG_SET(sRndInfo, ROUND_SHOT_FIRED) AND sRndInfo.sScoreData.eScoreStyle <> ROUNDSCORE_MINIGUN
// Reset the multiplier, unless we're an auto weapon and haven't consumed the grace period.
IF NEED_RESET_MULTIPLIER(sRndInfo)
RESET_MULTIPLIER(sRndInfo.sMPData)
ENDIF
CDEBUG2LN(DEBUG_SHOOTRANGE, "Incrementing iTotalShots because IS_ROUND_FLAG_SET(sRndInfo, ROUND_SHOT_FIRED) :: ", sRndInfo.iTotalShots)
ELIF GET_RANGE_MINIGUN_COMBO_TIMER(sRndInfo.sMPData) <= 0 AND sRndInfo.sScoreData.eScoreStyle = ROUNDSCORE_MINIGUN
RESET_MULTIPLIER(sRndInfo.sMPData)
ENDIF
IF IS_ROUND_FLAG_SET(sRndInfo, ROUND_SHOT_FIRED)
sRndInfo.iTotalShots++
ENDIF
// Gotta clamp accuracy for shotguns...
RANGE_ACCURACY_CLAMP(sRndInfo)
CLEAR_ROUND_FLAG(sRndInfo, ROUND_SHOT_FIRED)
ELSE
REPEAT sRndInfo.iMaxTargets iTer
// Only update this target if it is occupied
IF CHECK_TARGET_STATUS(sTargInfo.sTargetEntities[iTer], TS_CREATED) AND NOT CHECK_TARGET_STATUS(sTargInfo.sTargetEntities[iTer], TS_DESTROYED)
IF UPDATE_TARGET_ENTITY(sTargInfo.sTargetEntities[iTer], sRangeInfo.sRangeGrid, sRndInfo, sSPTInfo, sRangeInfo)
sRndInfo.iTargetsHitThisExplosion += 1
ENDIF
ENDIF
ENDREPEAT
CLEAR_PED_LAST_WEAPON_DAMAGE(rangePlayerPed)
// We can check for another hit now.
CLEAR_ROUND_FLAG(sRndInfo, ROUND_TARGET_HIT)
IF IS_EXPLOSION_IN_SPHERE(EXP_TAG_DONTCARE, GET_ENTITY_COORDS(PLAYER_PED_ID()), 50)
AND NOT IS_ROUND_FLAG_SET(sRndInfo, ROUND_SHOT_FIRED)
sRndInfo.iTotalShots++
SET_ROUND_FLAG(sRndInfo, ROUND_SHOT_FIRED)
ELSE
IF NOT IS_EXPLOSION_IN_SPHERE(EXP_TAG_DONTCARE, GET_ENTITY_COORDS(PLAYER_PED_ID()), 50)
AND IS_ROUND_FLAG_SET(sRndInfo, ROUND_SHOT_FIRED)
IF (sRndInfo.iTargetsHitThisExplosion = 1)
ADD_SCORE_TO_SPT(1, HUD_COLOUR_GREY, sSPTInfo)
sRndInfo.sScoreData.iP1Score += 1
RANGE_INCREMENT_ZONE_HITS(sRndInfo, 4)
ELIF (sRndInfo.iTargetsHitThisExplosion = 2)
ADD_SCORE_TO_SPT(CONST_SHOTTY_2TARGS, HUD_COLOUR_GREEN, sSPTInfo)
sRndInfo.sScoreData.iP1Score += CONST_SHOTTY_2TARGS
RANGE_INCREMENT_ZONE_HITS(sRndInfo, 3)
ELIF (sRndInfo.iTargetsHitThisExplosion = 3)
ADD_SCORE_TO_SPT(CONST_SHOTTY_3TARGS, HUD_COLOUR_BLUE, sSPTInfo)
sRndInfo.sScoreData.iP1Score += CONST_SHOTTY_3TARGS
RANGE_INCREMENT_ZONE_HITS(sRndInfo, 2)
ELIF (sRndInfo.iTargetsHitThisExplosion = 4)
ADD_SCORE_TO_SPT(CONST_SHOTTY_4TARGS, HUD_COLOUR_RED, sSPTInfo)
sRndInfo.sScoreData.iP1Score += CONST_SHOTTY_4TARGS
RANGE_INCREMENT_ZONE_HITS(sRndInfo, 1)
ELIF (sRndInfo.iTargetsHitThisExplosion = 5)
ADD_SCORE_TO_SPT(CONST_SHOTTY_5TARGS, HUD_COLOUR_YELLOW, sSPTInfo)
sRndInfo.sScoreData.iP1Score += CONST_SHOTTY_5TARGS
RANGE_INCREMENT_ZONE_HITS(sRndInfo, 1)
ELIF (sRndInfo.iTargetsHitThisExplosion = 6)
ADD_SCORE_TO_SPT(CONST_SHOTTY_6TARGS, HUD_COLOUR_WHITE, sSPTInfo)
sRndInfo.sScoreData.iP1Score += CONST_SHOTTY_6TARGS
RANGE_INCREMENT_ZONE_HITS(sRndInfo, 1)
ENDIF
CLEAR_ROUND_FLAG(sRndInfo, ROUND_SHOT_FIRED)
sRndInfo.iTargetsHitThisExplosion = 0
ENDIF
ENDIF
RANGE_ACCURACY_CLAMP(sRndInfo)
ENDIF
BREAK
CASE SRM_COMPLETE_MSG
STOP_FIRE_IN_RANGE(GET_ENTITY_COORDS(PLAYER_PED_ID()), 100)
CLEAR_AREA(GET_ENTITY_COORDS(PLAYER_PED_ID()), 100, TRUE)
// Draw the hud for a bit longer.
DRAW_RANGE_HUD(sRndInfo, sWeaponRndInfo, sSPTInfo, TRUE)
// Remove the weapon from the player
IF NOT IS_PED_INJURED(rangePlayerPed)
SET_CURRENT_PED_WEAPON(rangePlayerPed, WEAPONTYPE_UNARMED)
ENDIF
// Okay, need to add the medal feed a little after the message comes up.
IF IS_TIMER_STARTED(sMenuInfo.uiSplashText.movieTimer)
IF GET_TIMER_IN_SECONDS(sMenuInfo.uiSplashText.movieTimer) > 1.0
IF NOT IS_RANGE_MENU_FLAG_SET(sMenuInfo, RMF_SHOWED_MEDAL_SPLASH)
RANGE_ROUND_MEDAL eMedalToGive
eMedalToGive = GET_MEDAL_AWARD(sRndInfo.sScoreData.iP1Score + sRndInfo.sScoreData.iTimeBonus, sWeaponRndInfo[sRndInfo.eWeaponCat].sChallenges[sRndInfo.eChallengeType])
sMenuInfo.iMedalFeed = UPDATE_RANGE_MEDAL_TOAST(eMedalToGive, sRndInfo)
SET_RANGE_MENU_FLAG(sMenuInfo, RMF_SHOWED_MEDAL_SPLASH)
ENDIF
ENDIF
ENDIF
IF UPDATE_RANGE_SPLASH(sMenuInfo)
// Turn on the radio!
IF (sCoreInfo.eRangeLoc = RANGELOC_PILLBOX_HILL)
SET_STATIC_EMITTER_ENABLED("LOS_SANTOS_AMMUNATION_GUN_RANGE", TRUE)
ELSE
SET_STATIC_EMITTER_ENABLED("SE_AMMUNATION_CYPRESS_FLATS_GUN_RANGE", TRUE)
ENDIF
IF (sRndInfo.sScoreData.eScoreStyle = ROUNDSCORE_BULLSEYE)
CDEBUG2LN(DEBUG_SHOOTRANGE, "UpdateMain -- Applying time bonus...")
// Actually add the bonus.
ROUND_GIVE_TIME_BONUS(sRndInfo)
ENDIF
// If we cleared the round, with a better score than our last,
// as Michael or Trevor, add some special ability power. -- #411002
enumCharacterList tempChar
tempChar = GET_CURRENT_PLAYER_PED_ENUM()
IF (tempChar = CHAR_TREVOR) OR (tempChar = CHAR_MICHAEL)
IF IS_ROUND_CLEARED(sRndInfo, sWeaponRndInfo[sRndInfo.eWeaponCat].sChallenges[sRndInfo.eChallengeType])
IF (sRndInfo.sScoreData.iP1Score > GET_RANGE_SP_HIGH_SCORE(ePlayerChar, sRndInfo.eRoundType))
SPECIAL_ABILITY_CHARGE_NORMALIZED(GET_PLAYER_INDEX(), 0.1, TRUE)
ELSE
SPECIAL_ABILITY_CHARGE_NORMALIZED(GET_PLAYER_INDEX(), 0.05, TRUE)
ENDIF
ENDIF
ENDIF
// Do something with numbers!
SET_ROUND_ZONE_HITS(sRndInfo.eRoundType, sRndInfo.sScoreData.iP1Score, sRndInfo.iZ1Hits, sRndInfo.iZ2Hits, sRndInfo.iZ3Hits, sRndInfo.iZ4Hits)
// Check if we beat the high schore
IF SAVE_PLAYER_MEDAL(sWeaponRndInfo[sRndInfo.eWeaponCat].sChallenges[sRndInfo.eChallengeType], sRndInfo)
// Move on.
CDEBUG2LN(DEBUG_SHOOTRANGE, "UpdateMain -- SRM_MEDAL_TOAST")
sCoreInfo.eRangeState = SRM_MEDAL_TOAST //SRM_PICK_WEAPON
ELSE
// Move on.
CDEBUG2LN(DEBUG_SHOOTRANGE, "UpdateMain -- SRM_PICK_WEAPON")
sCoreInfo.eRangeState = SRM_PICK_WEAPON
ENDIF
CHECK_OUR_SCORE_AGAINST_HIGH_SCORE(sRndInfo.sScoreData, sRndInfo)
// Are we setting the next round to unlocked?
CHECK_UNLOCK_NEXT_ROUND(sRndInfo, sWeaponRndInfo[sRndInfo.eWeaponCat].sChallenges[sRndInfo.eChallengeType])
// Start our predictions...
IF IS_PLAYER_ONLINE()
RANGE_SP_PRE_READ_LBD(sCoreInfo.lbdWrite, sRndInfo, sWeaponRndInfo[sRndInfo.eWeaponCat].sChallenges[sRndInfo.eChallengeType])
sCoreInfo.ProcessPrediction = TRUE
sCoreInfo.bOnlineForPrediction = TRUE
sCoreInfo.ePredictedRnd = sRndInfo.eRoundType
ELSE
// Track this, we may need to make an emergency predition...
sCoreInfo.bOnlineForPrediction = FALSE
sCoreInfo.ProcessPrediction = FALSE
sCoreInfo.ePredictedRnd = sRndInfo.eRoundType
ENDIF
// Return to the menu
CLEAR_RANGE_MENU_FLAG(sMenuInfo, RMF_SHOWED_MEDAL_SPLASH)
IF (sMenuInfo.iMedalFeed != -1)
THEFEED_REMOVE_ITEM(sMenuInfo.iMedalFeed)
sMenuInfo.iMedalFeed = -1
ENDIF
ROUND_CLEANUP(sRangeInfo.sRangeGrid, sRndInfo, sTargInfo, sSPTInfo.sSptQueue, sWeaponRndInfo, sMenuInfo)
INIT_CATEGORY_MENU(sCoreInfo, sMenuInfo)
INIT_WEAPONS_MENU(sCoreInfo, sRndInfo.eWeaponCat, sMenuInfo)
INIT_CHALLENGES_MENU(sWeaponRndInfo, sCoreInfo, sRndInfo.eWeaponCat, sMenuInfo)
INIT_RANGE_MENU(sMenuInfo.uiPlacement)
sCoreInfo.bSkipPressed = TRUE
SET_PLAYER_CONTROL(PLAYER_ID(), FALSE)
RESTART_TIMER_AT(sRndInfo.sGenTimer, 0.0)
// Trigger a save, need to restore weapons first...
RANGE_RESTORE_PLAYER_WEAPONS(sCoreInfo.sWeapons)
SET_AUTOSAVE_IGNORES_ON_MISSION_FLAG(TRUE)
MAKE_AUTOSAVE_REQUEST()
HANDLE_RANGE_SCORE_AWARDS()
ENDIF
BREAK
CASE SRM_MEDAL_TOAST
// Can use this as an update state if need be.
CDEBUG2LN(DEBUG_SHOOTRANGE, "UpdateMain -- SRM_PICK_WEAPON")
sCoreInfo.eRangeState = SRM_PICK_WEAPON //SRM_PICK_WEAPON
BREAK
CASE SRM_EXIT
UPDATE_UI_EXIT()
IF IS_CONTROL_JUST_RELEASED(FRONTEND_CONTROL, INPUT_FRONTEND_ACCEPT) //CASE GET_CONTROL_INSTRUCTIONAL_BUTTONS_STRING(FRONTEND_CONTROL, INPUT_FRONTEND_ACCEPT)
// Make sure he's at the range. This is so cutscenes line up.
SET_ENTITY_COORDS(PLAYER_PED_ID(), sRangeInfo.vPlayerRootPos)
SET_ENTITY_HEADING(PLAYER_PED_ID(), sRangeInfo.fPlayerRootHead)
SET_GAME_PAUSED(FALSE)
IF NOT IS_PLAYER_DEAD(PLAYER_ID())
SET_PED_USING_ACTION_MODE(PLAYER_PED_ID(), FALSE)
ENDIF
// Remove the weapon from the player
IF NOT IS_PED_INJURED(rangePlayerPed)
SET_CURRENT_PED_WEAPON(rangePlayerPed, WEAPONTYPE_UNARMED)
ENDIF
// Trigger a save, need to restore weapons first...
RANGE_RESTORE_PLAYER_WEAPONS(sCoreInfo.sWeapons)
// Return to the menu
STOP_TARGET_SOUNDS(sTargInfo.sTargetEntities, sRndInfo.iMaxTargets)
ROUND_CLEANUP(sRangeInfo.sRangeGrid, sRndInfo, sTargInfo, sSPTInfo.sSptQueue, sWeaponRndInfo, sMenuInfo, DEFAULT, TRUE)
INIT_CATEGORY_MENU(sCoreInfo, sMenuInfo)
INIT_WEAPONS_MENU(sCoreInfo, sRndInfo.eWeaponCat, sMenuInfo)
INIT_CHALLENGES_MENU(sWeaponRndInfo, sCoreInfo, sRndInfo.eWeaponCat, sMenuInfo)
INIT_RANGE_MENU(sMenuInfo.uiPlacement)
sCoreInfo.bSkipPressed = TRUE
IF (sRndInfo.iSFX_Warning != -1)
STOP_SOUND(sRndInfo.iSFX_Warning)
RELEASE_SOUND_ID(sRndInfo.iSFX_Warning)
sRndInfo.iSFX_Warning = -1
ENDIF
// Need to tell the leaderboard system not to write anything here, because we quit mid round.
// We do this by faking being online...
sCoreInfo.bOnlineForPrediction = TRUE
sCoreInfo.ProcessPrediction = FALSE
sCoreInfo.ePredictedRnd = RT_INVALID
sCoreInfo.lbdWrite.eRoundType = RT_INVALID
// Re-add radio.
IF (sCoreInfo.eRangeLoc = RANGELOC_PILLBOX_HILL)
SET_STATIC_EMITTER_ENABLED("LOS_SANTOS_AMMUNATION_GUN_RANGE", TRUE)
ELSE
SET_STATIC_EMITTER_ENABLED("SE_AMMUNATION_CYPRESS_FLATS_GUN_RANGE", TRUE)
ENDIF
CDEBUG2LN(DEBUG_SHOOTRANGE, "UpdateMain -- SRM_PICK_WEAPON")
sCoreInfo.eRangeState = SRM_PICK_WEAPON
EXIT
ENDIF
IF IS_CONTROL_JUST_RELEASED(FRONTEND_CONTROL, INPUT_FRONTEND_CANCEL) //CASE GET_CONTROL_INSTRUCTIONAL_BUTTONS_STRING(FRONTEND_CONTROL, INPUT_FRONTEND_CANCEL)
PAUSE_RANGE_ROUND(sCoreInfo, sRndInfo, sMenuInfo, FALSE)
ENDIF
BREAK
CASE SRM_TRIGGER_EXIT_REDRESS
// Okay, we need to have the player exit the range.
IF (TIMERA() > 1000)
// Warp the player.
SET_ENTITY_COORDS(rangePlayerPed, sRangeInfo.vRedressPos, FALSE)
SET_ENTITY_HEADING(rangePlayerPed, sRangeInfo.fRedressHead)
SET_STATE_OF_CLOSEST_DOOR_OF_TYPE(V_ILEV_GC_DOOR01, sRangeInfo.vDoorPos, FALSE, 0.0)
// Set the camera.
IF NOT DOES_CAM_EXIST(sTutorialInfo.sceneCamera)
sTutorialInfo.sceneCamera = CREATE_CAM("DEFAULT_SCRIPTED_CAMERA")
ENDIF
SET_CAM_COORD(sTutorialInfo.sceneCamera, sRangeInfo.vRedressCamStart)
SET_CAM_ROT(sTutorialInfo.sceneCamera, sRangeInfo.vRedressCamStartOrient)
SET_CAM_FOV(sTutorialInfo.sceneCamera, 42.3427)
SET_CAM_ACTIVE(sTutorialInfo.sceneCamera, TRUE)
RENDER_SCRIPT_CAMS(TRUE, FALSE)
SET_CAM_PARAMS(sTutorialInfo.sceneCamera, sRangeInfo.vRedressCamInterp, sRangeInfo.vRedressCamInterpOrient, 42.3427, 2500)
CLEAR_PED_PROP(rangePlayerPed, ANCHOR_HEAD)
CLEAR_PED_PROP(rangePlayerPed, ANCHOR_EYES)
// Restore the player's props.
RESTORE_PLAYER_PED_VARIATIONS(rangePlayerPed)
// Now set the player to walk out.
IF (sCoreInfo.eRangeLoc = RANGELOC_CYPRESS_FLATS)
SEQUENCE_INDEX siExit
OPEN_SEQUENCE_TASK(siExit)
TASK_GO_STRAIGHT_TO_COORD(NULL, <<826.8521, -2160.5791, 28.6190>>, PEDMOVEBLENDRATIO_WALK)
TASK_GO_STRAIGHT_TO_COORD(NULL, <<826.0770, -2158.7080, 28.6190>>, PEDMOVEBLENDRATIO_WALK)
CLOSE_SEQUENCE_TASK(siExit)
TASK_PERFORM_SEQUENCE(rangePlayerPed, siExit)
CLEAR_SEQUENCE_TASK(siExit)
ELSE
TASK_FOLLOW_NAV_MESH_TO_COORD(rangePlayerPed, sRangeInfo.vRedressGoto, PEDMOVEBLENDRATIO_WALK)
ENDIF
SET_PED_CONFIG_FLAG(rangePlayerPed, PCF_OpenDoorArmIK, TRUE)
SET_PED_RESET_FLAG(rangePlayerPed, PRF_SearchForClosestDoor, TRUE)
SETTIMERA(0)
sCoreInfo.eRangeState = SRM_REDRESS_STAGE_2
ENDIF
BREAK
CASE SRM_REDRESS_STAGE_2
SET_PED_RESET_FLAG(rangePlayerPed, PRF_SearchForClosestDoor, TRUE)
IF TIMERA() > 2500
// Shut the door in the corner
SET_STATE_OF_CLOSEST_DOOR_OF_TYPE(V_ILEV_GC_DOOR01, sRangeInfo.vDoorPos, TRUE, 0.0)
SET_CAM_COORD(sTutorialInfo.sceneCamera, sRangeInfo.vRedressCamEnd)
SET_CAM_ROT(sTutorialInfo.sceneCamera, sRangeInfo.vRedressCamEndOrient)
SET_CAM_ACTIVE(sTutorialInfo.sceneCamera, TRUE)
RENDER_SCRIPT_CAMS(TRUE, FALSE)
sCoreInfo.eRangeState = SRM_REDRESS_EXIT
ENDIF
BREAK
CASE SRM_REDRESS_EXIT
SET_STATE_OF_CLOSEST_DOOR_OF_TYPE(V_ILEV_GC_DOOR01, sRangeInfo.vDoorPos, FALSE, 0.0)
IF NOT IS_TRANSITION_ACTIVE()
CDEBUG2LN(DEBUG_SHOOTRANGE, "STOP_RENDERING_SCRIPT_CAMS_USING_CATCH_UP(FALSE, 20.0)")
STOP_RENDERING_SCRIPT_CAMS_USING_CATCH_UP(FALSE, 20.0)
ENDIF
Script_Cleanup(sRangeInfo, sTargInfo, sCoreInfo, sMenuInfo, vehPlayerCar)
BREAK
ENDSWITCH
ENDPROC
/// PURPOSE:
/// Saves the player vehicle to a position based on the range location we started near.
/// PARAMS:
/// sCoreRangeInfo -
/// vehPlayerCar -
PROC RANGE_SAVE_VEHICLE( Range_CoreData & sCoreRangeInfo, VEHICLE_SAVE_ARGS & vehPlayerCar )
VECTOR vSavePosition
FLOAT fSaveHeading
BOOL bNeedLargeSpace
IF DOES_ENTITY_EXIST( vehPlayerCar.playerVehicle )
bNeedLargeSpace = MINIGAME_DOES_VEHICLE_NEED_LARGE_RESPAWN_SPACE( vehPlayerCar.playerVehicle )
ENDIF
IF sCoreRangeInfo.eRangeLoc = RANGELOC_PILLBOX_HILL
vSavePosition = (<< 15.4041, -1125.9149, 27.7096 >>)
fSaveHeading = 90.5811
ELIF sCoreRangeInfo.eRangeLoc = RANGELOC_CYPRESS_FLATS
vSavePosition = PICK_VECTOR(bNeedLargeSpace, (<< 810.0622, -2137.9922, 28.2980 >>), (<< 782.8192, -2120.5012, 28.3352 >>) )
fSaveHeading = PICK_FLOAT(bNeedLargeSpace, 0.0589, 355.0583)
ELSE
CERRORLN( DEBUG_SHOOTRANGE, "RANGE_SAVE_VEHICLE :: RangeLocation is wrong, sCoreRangeInfo.eRangeLoc=", sCoreRangeInfo.eRangeLoc )
ENDIF
IF ODDJOB_SAVE_VEHICLE_AND_WARP( vehPlayerCar, vSavePosition, TRUE, fSaveHeading )
CDEBUG2LN(DEBUG_SHOOTRANGE, "RANGE_SAVE_VEHICLE :: vehPlayerCar Saved :)")
ELSE
CDEBUG2LN(DEBUG_SHOOTRANGE, "RANGE_SAVE_VEHICLE :: vehPlayerCar Not Saved :(")
ENDIF
ENDPROC
// Initialisation and the script loop
SCRIPT (SHOOTING_RANGE_LAUNCH_DATA launchData)
CDEBUG2LN(DEBUG_SHOOTRANGE, "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Range SP First Post %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%")
// Variables we'll need:
Range_CoreData sCoreRangeInfo // The info about the shooting range as a whole
Range_RoundInfo sRoundInfo // Info per round
Range_SPTData sSPTData // Our SPT scroll, probably going to flash.
Range_RangeData sRangeData // The range is constant, this should become constant one day.
Range_Targets sTargets // Target information.
Range_WeaponRounds sRoundUnlocks[NUM_WEAPON_CATS] // Our unlock info for weapons and challenges
Range_TutorialData sTutorialInfo // Information about the tutorial.
Range_MenuData sMenuInfo
VEHICLE_SAVE_ARGS vehPlayerCar
sCoreRangeInfo.eRangeLoc = launchData.eLocation
ePlayerChar = GET_CURRENT_PLAYER_PED_ENUM()
RANGE_CHECK_DLC(sCoreRangeInfo)
SET_SHOOTING_RANGE_UNSAVED_BITFLAG(SRB_RangeInSession)
STORE_PLAYER_PED_VARIATIONS(PLAYER_PED_ID(), TRUE)
// DISABLE CHEATS!
DISABLE_CHEAT(CHEAT_TYPE_ALL, TRUE)
DISABLE_CHEAT(CHEAT_TYPE_GIVE_WEAPONS, TRUE)
DISABLE_COMPOSITE_SHOTGUN_DECALS(TRUE)
// TRACE_NATIVE_COMMAND("SET_EXCLUSIVE_INPUT")
TEXT_LABEL_23 mMocapName = "NONE"
MINIGAME_DISPLAY_MISSION_TITLE(ENUM_TO_INT(MINIGAME_SHOOTING_RANGE))
RANGE_SAVE_VEHICLE( sCoreRangeInfo, vehPlayerCar )
// Handles the player being busted or arrested, or if the player
// jumps into Multiplayer from Singleplayer ensures the script
// gets cleaned up properly under the correct circumstances
IF (HAS_FORCE_CLEANUP_OCCURRED(DEFAULT_FORCE_CLEANUP_FLAGS | FORCE_CLEANUP_FLAG_SP_TO_MP | FORCE_CLEANUP_FLAG_REPEAT_PLAY))
Script_Cleanup(sRangeData, sTargets, sCoreRangeInfo, sMenuInfo, vehPlayerCar, TRUE)
ENDIF
IF NOT IS_PED_INJURED(PLAYER_PED_ID())
SET_PLAYER_WANTED_LEVEL(PLAYER_ID(), 0)
SET_PLAYER_WANTED_LEVEL_NOW(PLAYER_ID())
ENDIF
// Store some tutorial data.
RANGE_STORE_TUTORIAL_INFO(launchData, sTutorialInfo)
// Any initialisation (generally, only mission scripts should set
// the mission flag to TRUE)
SET_MISSION_FLAG(TRUE)
// Disable the character selector
DISABLE_SELECTOR()
CLEAR_HELP()
CLEAR_PRINTS()
#IF IS_DEBUG_BUILD
enumCharacterList ePlayer = GET_CURRENT_PLAYER_PED_ENUM()
CDEBUG2LN(DEBUG_SHOOTRANGE, "Player Character is ", PICK_STRING(ePlayer = CHAR_MICHAEL, "CHAR_MICHAEL", PICK_STRING(ePlayer = CHAR_FRANKLIN, "CHAR_FRANKLIN", PICK_STRING(ePlayer = CHAR_TREVOR, "CHAR_TREVOR", "Unknown playabled ped"))))
#ENDIF
// The script loop
WHILE (TRUE)
rangePlayerPed = PLAYER_PED_ID()
HIDE_UI_DURING_RANGE(sCoreRangeInfo.eRangeState)
// Don't this if we're on or past the menu.
IF (sCoreRangeInfo.eRangeState < SRM_PICK_WEAPON)
UPDATE_MISSION_NAME_DISPLAYING(mMocapName, default, default, default, TRUE)
ELSE
g_eMissionTitleState = MTS_DONE
ENDIF
IF NOT IS_SELECTOR_DISABLED()
DISABLE_SELECTOR()
ENDIF
#IF IS_DEBUG_BUILD
// Explanation: If UPDATE_RANGE_WIDGETS returns true, that means we're debugging a target or something.
// Anything going on in the general shooting range will just get in the way.
IF NOT UPDATE_RANGE_WIDGETS(sMenuInfo, sCoreRangeInfo.eRangeState)
#ENDIF
// Make sure Law is not going to hurt us
SET_PLAYER_IS_ALLOWED_TO_SHOOT_IN_SHOP(GUN_SHOP_01_DT, TRUE)
// Handle ped flags and whatnot on the player. Every frame.
RANGE_UPDATE_PED_ABILITIES()
// Maintain the script perform per-frame functionality
UPDATE_MAIN(sCoreRangeInfo, sRoundInfo, sTutorialInfo, sTargets, sRoundUnlocks, sRangeData, sSPTData, sMenuInfo, vehPlayerCar, launchData)
#IF IS_DEBUG_BUILD
// Debug Key: Check for Pass (not for Minigmes)
IF (IS_KEYBOARD_KEY_JUST_PRESSED(KEY_S))
RANGE_UI_TRIGGER_TRANSITION(sMenuInfo, FALSE)
DELETE_OBJECT(sCoreRangeInfo.oEarmuffs)
CLEAR_PED_PROP(rangePlayerPed, ANCHOR_HEAD)
CLEAR_PED_PROP(rangePlayerPed, ANCHOR_EYES)
Script_Cleanup(sRangeData, sTargets, sCoreRangeInfo, sMenuInfo, vehPlayerCar)
ENDIF
// Debug Key: Check for Fail (not for Minigames)
IF (IS_KEYBOARD_KEY_JUST_PRESSED(KEY_F))
RANGE_UI_TRIGGER_TRANSITION(sMenuInfo, FALSE)
DELETE_OBJECT(sCoreRangeInfo.oEarmuffs)
CLEAR_PED_PROP(rangePlayerPed, ANCHOR_HEAD)
CLEAR_PED_PROP(rangePlayerPed, ANCHOR_EYES)
g_savedGlobals.sRangeData[0].m_bSeenTutorial = FALSE
Script_Cleanup(sRangeData, sTargets, sCoreRangeInfo, sMenuInfo, vehPlayerCar)
ENDIF
//Debug Key: Toggle CGtoNG
IF (IS_KEYBOARD_KEY_JUST_PRESSED(KEY_NUMPAD1))
IF sCoreRangeInfo.bCGtoNG = TRUE
sCoreRangeInfo.bCGtoNG = FALSE
sMenuInfo.catMenu.iNumElements -= 1
sMenuInfo.curMenu = RANGE_MENU_WEAPCAT
sMenuInfo.catMenu.iCurElement = 0
sMenuInfo.weapMenu.iNumElements = 0
ELSE
sCoreRangeInfo.bCGtoNG = TRUE
sMenuInfo.catMenu.iNumElements += 1
ENDIF
sRoundInfo.eWeaponCat = INT_TO_ENUM(RANGE_WEAPON_CATEGORY, sMenuInfo.catMenu.iCurElement)
INIT_CHALLENGES_MENU(sRoundUnlocks, sCoreRangeInfo, sRoundInfo.eWeaponCat, sMenuInfo)
ENDIF
#ENDIF
#IF IS_DEBUG_BUILD
ENDIF
#ENDIF
WAIT(0)
ENDWHILE
ENDSCRIPT