657 lines
24 KiB
XML
Executable File
657 lines
24 KiB
XML
Executable File
//Header for controlling various gadgets available when driving the JB700 car.
|
|
|
|
USING "rage_builtins.sch"
|
|
USING "globals.sch"
|
|
|
|
USING "commands_audio.sch"
|
|
USING "commands_camera.sch"
|
|
USING "commands_debug.sch"
|
|
USING "commands_fire.sch"
|
|
USING "commands_graphics.sch"
|
|
USING "commands_hud.sch"
|
|
USING "commands_misc.sch"
|
|
USING "commands_object.sch"
|
|
USING "commands_pad.sch"
|
|
USING "commands_ped.sch"
|
|
USING "commands_physics.sch"
|
|
USING "commands_player.sch"
|
|
USING "commands_script.sch"
|
|
USING "commands_streaming.sch"
|
|
USING "commands_task.sch"
|
|
USING "commands_vehicle.sch"
|
|
|
|
USING "model_enums.sch"
|
|
USING "script_player.sch"
|
|
USING "script_misc.sch"
|
|
USING "vehicle_public.sch"
|
|
USING "cellphone_public.sch"
|
|
|
|
STRUCT SPIKE_DATA
|
|
OBJECT_INDEX ObjectIndex
|
|
VEHICLE_INDEX VehicleIndex
|
|
INT iForceTimer
|
|
INT iCutsceneTimer
|
|
VECTOR vPosition
|
|
BOOL bPtfxPlayed
|
|
ENDSTRUCT
|
|
|
|
STRUCT JB700_GADGET_DATA
|
|
//guns
|
|
INT iGunTimer
|
|
INT iGunOffsetModifier
|
|
INT iGunSoundID
|
|
INT iGunOffSoundID
|
|
BOOL bGunsFired
|
|
CONTROL_ACTION caGunInput // Input for firing guns - we use INPUT_VEH_ATTACK on PC instead of INPUT_VEH_AIM as that maps to left mouse.
|
|
|
|
//spikes
|
|
SPIKE_DATA SpikesData[3]
|
|
INT iSpikesTimer
|
|
INT iTimesSpikesDropped
|
|
BOOL bCutsceneTriggered
|
|
BOOL bSpikesDropped
|
|
BOOL bSpikesHit
|
|
INT iSpikeHit
|
|
INT iSpikesHits
|
|
|
|
|
|
|
|
ENDSTRUCT
|
|
|
|
PROC RESET_JB700_GADGET_DATA(JB700_GADGET_DATA &sGadgetData)
|
|
sGadgetData.iGunTimer = 0
|
|
sGadgetData.iGunSoundID = -1
|
|
sGadgetData.iGunOffSoundID = -1
|
|
sGadgetData.iGunOffsetModifier = 1
|
|
sGadgetData.bGunsFired = FALSE
|
|
sGadgetData.caGunInput = INPUT_VEH_AIM
|
|
sGadgetData.iSpikeHit = 0
|
|
sGadgetData.iSpikesHits = 0
|
|
sGadgetData.iSpikesTimer = 0
|
|
sGadgetData.iTimesSpikesDropped = 0
|
|
sGadgetData.bCutsceneTriggered = FALSE
|
|
sGadgetData.bSpikesDropped = FALSE
|
|
sGadgetData.bSpikesHit = FALSE
|
|
ENDPROC
|
|
|
|
PROC RESET_JB700_SPIKES_CUTSCENE_TIMERS(JB700_GADGET_DATA &sGadgetData)
|
|
sGadgetData.SpikesData[0].iCutsceneTimer = 0
|
|
sGadgetData.SpikesData[1].iCutsceneTimer = 0
|
|
sGadgetData.SpikesData[2].iCutsceneTimer = 0
|
|
ENDPROC
|
|
|
|
PROC CLEANUP_JB700_SPIKES(JB700_GADGET_DATA &sGadgetData, BOOL bDelete)
|
|
|
|
INT i
|
|
|
|
REPEAT COUNT_OF(sGadgetData.SpikesData) i
|
|
IF DOES_ENTITY_EXIST(sGadgetData.SpikesData[i].ObjectIndex)
|
|
IF ( bDelete = TRUE )
|
|
DELETE_OBJECT(sGadgetData.SpikesData[i].ObjectIndex)
|
|
ELSE
|
|
SET_OBJECT_AS_NO_LONGER_NEEDED(sGadgetData.SpikesData[i].ObjectIndex)
|
|
ENDIF
|
|
ENDIF
|
|
ENDREPEAT
|
|
|
|
ENDPROC
|
|
|
|
PROC CLEANUP_JB700_GUNS(JB700_GADGET_DATA &sGadgetData)
|
|
REMOVE_PTFX_ASSET()
|
|
|
|
IF sGadgetData.iGunSoundID != -1
|
|
IF NOT HAS_SOUND_FINISHED(sGadgetData.iGunSoundID)
|
|
STOP_SOUND(sGadgetData.iGunSoundID)
|
|
ENDIF
|
|
|
|
RELEASE_SOUND_ID(sGadgetData.iGunSoundID)
|
|
sGadgetData.iGunSoundID = -1
|
|
ENDIF
|
|
|
|
IF sGadgetData.iGunOffSoundID != -1
|
|
IF NOT HAS_SOUND_FINISHED(sGadgetData.iGunOffSoundID)
|
|
STOP_SOUND(sGadgetData.iGunOffSoundID)
|
|
ENDIF
|
|
|
|
RELEASE_SOUND_ID(sGadgetData.iGunOffSoundID)
|
|
sGadgetData.iGunOffSoundID = -1
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
PROC UPDATE_JB700_GUNS(VEHICLE_INDEX veh, JB700_GADGET_DATA &sGadgetData)
|
|
REQUEST_PTFX_ASSET()
|
|
|
|
IF IS_USING_KEYBOARD_AND_MOUSE(PLAYER_CONTROL)
|
|
sGadgetData.caGunInput = INPUT_VEH_ATTACK
|
|
ELSE
|
|
sGadgetData.caGunInput = INPUT_VEH_AIM
|
|
ENDIF
|
|
|
|
IF sGadgetData.iGunSoundID = -1
|
|
sGadgetData.iGunSoundID = GET_SOUND_ID()
|
|
ENDIF
|
|
|
|
IF sGadgetData.iGunOffSoundID = -1
|
|
sGadgetData.iGunOffSoundID = GET_SOUND_ID()
|
|
ENDIF
|
|
|
|
IF IS_VEHICLE_DRIVEABLE(veh)
|
|
AND IS_PED_SITTING_IN_VEHICLE(PLAYER_PED_ID(), veh)
|
|
AND HAS_PTFX_ASSET_LOADED()
|
|
|
|
//DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_VEH_ATTACK)
|
|
//DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_VEH_ATTACK2)
|
|
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_VEH_AIM)
|
|
IF IS_USING_KEYBOARD_AND_MOUSE(PLAYER_CONTROL)
|
|
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_VEH_ATTACK)
|
|
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_AIM) // This is a kludge because PC is using this for vehicle aim.
|
|
ENDIF
|
|
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_VEH_SELECT_NEXT_WEAPON)
|
|
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_VEH_SELECT_PREV_WEAPON)
|
|
|
|
//IF IS_DISABLED_CONTROL_PRESSED(PLAYER_CONTROL, INPUT_VEH_ATTACK)
|
|
IF IS_DISABLED_CONTROL_PRESSED(PLAYER_CONTROL, sGadgetData.caGunInput)
|
|
IF GET_GAME_TIMER() - sGadgetData.iGunTimer > 225
|
|
IF sGadgetData.iGunOffsetModifier = 0
|
|
sGadgetData.iGunOffsetModifier = 1
|
|
ENDIF
|
|
|
|
VECTOR vStartOffset = <<0.6826 * sGadgetData.iGunOffsetModifier, 1.6707, 0.3711>>
|
|
VECTOR vEndOffset = <<vStartOffset.x, vStartOffset.y + 10.0, vStartOffset.z - 0.1>>
|
|
VECTOR vStartPos = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(veh, vStartOffset)
|
|
VECTOR vEndPos = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(veh, vEndOffset)
|
|
|
|
SHOOT_SINGLE_BULLET_BETWEEN_COORDS(vStartPos, vEndPos, 15, TRUE, WEAPONTYPE_ASSAULTSHOTGUN, PLAYER_PED_ID())
|
|
SHOOT_SINGLE_BULLET_BETWEEN_COORDS(vStartPos + <<0.0, 0.0, 0.2>>, vEndPos + <<0.0, 0.0, 0.2>>, 15, TRUE, WEAPONTYPE_ASSAULTSHOTGUN, PLAYER_PED_ID())
|
|
|
|
START_PARTICLE_FX_NON_LOOPED_ON_ENTITY("scr_carsteal5_car_muzzle_flash", veh, vStartOffset + <<0.0, -0.15, 0.0>>, <<0.0, 0.0, 90.0>>)
|
|
|
|
IF IS_PLAYER_PLAYING(PLAYER_ID())
|
|
IF IS_SPECIAL_ABILITY_ACTIVE(PLAYER_ID())
|
|
PLAY_SOUND_FROM_COORD(-1, "FRANKLIN_GUN_MASTER", vStartPos) //play this during special ability mode, see B*1490847
|
|
ELSE
|
|
PLAY_SOUND_FROM_COORD(-1, "JB700_GUN_PLAYER_MASTER", vStartPos) //play this when special ability mode is off
|
|
ENDIF
|
|
ENDIF
|
|
|
|
sGadgetData.bGunsFired = TRUE
|
|
|
|
sGadgetData.iGunOffsetModifier *= -1
|
|
sGadgetData.iGunTimer = GET_GAME_TIMER()
|
|
ENDIF
|
|
|
|
/*IF HAS_SOUND_FINISHED(sGadgetData.iGunSoundID)
|
|
PLAY_SOUND_FROM_ENTITY(sGadgetData.iGunSoundID, "JB700_GUN_PLAYER_MASTER", veh)
|
|
ENDIF
|
|
|
|
IF NOT HAS_SOUND_FINISHED(sGadgetData.iGunOffSoundID)
|
|
STOP_SOUND(sGadgetData.iGunOffSoundID)
|
|
ENDIF*/
|
|
ELSE
|
|
/*IF NOT HAS_SOUND_FINISHED(sGadgetData.iGunSoundID)
|
|
STOP_SOUND(sGadgetData.iGunSoundID)
|
|
ENDIF
|
|
|
|
IF HAS_SOUND_FINISHED(sGadgetData.iGunOffSoundID)
|
|
PLAY_SOUND_FROM_ENTITY(sGadgetData.iGunOffSoundID, "JB700_GUN_PLAYER_RPRT_MASTER", veh)
|
|
ENDIF*/
|
|
ENDIF
|
|
ELSE
|
|
IF NOT HAS_SOUND_FINISHED(sGadgetData.iGunSoundID)
|
|
STOP_SOUND(sGadgetData.iGunSoundID)
|
|
ENDIF
|
|
|
|
IF NOT HAS_SOUND_FINISHED(sGadgetData.iGunOffSoundID)
|
|
STOP_SOUND(sGadgetData.iGunOffSoundID)
|
|
ENDIF
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
FUNC BOOL HAS_ENTITY_BEEN_DAMAGED_BY_JB700_GUNS(ENTITY_INDEX entity, VEHICLE_INDEX vehJB700)
|
|
IF NOT IS_ENTITY_DEAD(entity)
|
|
AND NOT IS_ENTITY_DEAD(vehJB700)
|
|
IF HAS_ENTITY_BEEN_DAMAGED_BY_WEAPON(entity, WEAPONTYPE_PUMPSHOTGUN)
|
|
AND IS_PED_SITTING_IN_VEHICLE(PLAYER_PED_ID(), vehJB700)
|
|
RETURN TRUE
|
|
ENDIF
|
|
ENDIF
|
|
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
FUNC INT FIND_FREE_SPIKE_SLOT_NEW(JB700_GADGET_DATA sGadgetData)
|
|
|
|
INT i = 0
|
|
|
|
REPEAT COUNT_OF(sGadgetData.SpikesData) i
|
|
IF sGadgetData.SpikesData[i].vPosition.x = 0.0
|
|
RETURN i
|
|
ENDIF
|
|
ENDREPEAT
|
|
|
|
RETURN -1
|
|
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Converts a rotation vector into a normalised direction vector (basically the direction an entity would move if it moved forward at the current rotation).
|
|
/// For example: a rotation of <<0.0, 0.0, 45.0>> gives a direction vector of <<-0.707107, 0.707107, 0.0>>
|
|
/// PARAMS:
|
|
/// vRot - The rotation vector
|
|
/// RETURNS:
|
|
/// The direction vector
|
|
FUNC VECTOR CONVERT_ROTATION_TO_DIRECTION_VECTOR_NEW(VECTOR vRot)
|
|
RETURN <<-SIN(vRot.z) * COS(vRot.x), COS(vRot.z) * COS(vRot.x), SIN(vRot.x)>>
|
|
ENDFUNC
|
|
|
|
PROC UPDATE_JB700_SPIKES_DROPPING(VEHICLE_INDEX VehicleIndex, JB700_GADGET_DATA &sGadgetData)
|
|
|
|
ALLOW_ALTERNATIVE_SCRIPT_CONTROLS_LAYOUT(PLAYER_CONTROL)
|
|
|
|
IF DOES_ENTITY_EXIST(VehicleIndex)
|
|
IF NOT IS_ENTITY_DEAD(VehicleIndex)
|
|
|
|
INT i
|
|
|
|
IF IS_PED_SITTING_IN_VEHICLE(PLAYER_PED_ID(), VehicleIndex)
|
|
|
|
IF NOT IS_CINEMATIC_SHOT_ACTIVE(SHOTTYPE_CAMERA_MAN)
|
|
AND NOT IS_STUNT_JUMP_IN_PROGRESS()
|
|
|
|
REQUEST_PTFX_ASSET()
|
|
REQUEST_AMBIENT_AUDIO_BANK("CAR_THEFT_MOVIE_LOT")
|
|
|
|
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_VEH_HORN)
|
|
|
|
IF IS_CONTROL_JUST_PRESSED(PLAYER_CONTROL, INPUT_SCRIPT_LS)
|
|
AND IS_ENTITY_UPRIGHT(VehicleIndex)
|
|
|
|
IF GET_GAME_TIMER() - sGadgetData.iSpikesTimer > 1600
|
|
|
|
BOOL bNewSpikesAllowed = TRUE
|
|
|
|
IF DOES_ENTITY_EXIST(sGadgetData.SpikesData[0].ObjectIndex)
|
|
IF VDIST2(GET_ENTITY_COORDS(VehicleIndex), GET_ENTITY_COORDS(sGadgetData.SpikesData[0].ObjectIndex)) < 9.0
|
|
bNewSpikesAllowed = FALSE
|
|
ENDIF
|
|
ENDIF
|
|
|
|
IF ( bNewSpikesAllowed = TRUE )
|
|
|
|
INT iSlot = FIND_FREE_SPIKE_SLOT_NEW(sGadgetData)
|
|
|
|
//For the moment just go back to the start of the array once all the slots are full.
|
|
//This could be improved to find the furthest away spike and overwrite that one.
|
|
IF iSlot = -1
|
|
iSlot = 0
|
|
ENDIF
|
|
|
|
sGadgetData.SpikesData[iSlot].vPosition = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(VehicleIndex, <<0.0, -2.0, 0.0>>)
|
|
sGadgetData.SpikesData[iSlot].iForceTimer = 0
|
|
sGadgetData.SpikesData[iSlot].iCutsceneTimer = 0
|
|
sGadgetData.SpikesData[iSlot].VehicleIndex = NULL
|
|
|
|
sGadgetData.iSpikeHit = 0
|
|
sGadgetData.bSpikesHit = FALSE
|
|
|
|
REPEAT COUNT_OF(sGadgetData.SpikesData) i
|
|
IF DOES_ENTITY_EXIST(sGadgetData.SpikesData[i].ObjectIndex)
|
|
IF NOT IS_ENTITY_ON_SCREEN(sGadgetData.SpikesData[i].ObjectIndex)
|
|
DELETE_OBJECT(sGadgetData.SpikesData[i].ObjectIndex)
|
|
ELSE
|
|
SET_OBJECT_AS_NO_LONGER_NEEDED(sGadgetData.SpikesData[i].ObjectIndex)
|
|
ENDIF
|
|
ENDIF
|
|
ENDREPEAT
|
|
|
|
sGadgetData.iSpikesTimer = GET_GAME_TIMER()
|
|
|
|
ENDIF
|
|
|
|
ENDIF
|
|
|
|
ENDIF
|
|
|
|
IF ( sGadgetData.iSpikesTimer != 0 ) //create new spikes
|
|
|
|
IF GET_GAME_TIMER() - sGadgetData.iSpikesTimer > 100
|
|
IF NOT DOES_ENTITY_EXIST(sGadgetData.SpikesData[0].ObjectIndex)
|
|
sGadgetData.SpikesData[0].ObjectIndex = CREATE_OBJECT(PROP_TYRE_SPIKE_01, GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(VehicleIndex, << 0.0, -1.2, -0.4 >>))
|
|
SET_ENTITY_NO_COLLISION_ENTITY(sGadgetData.SpikesData[0].ObjectIndex, VehicleIndex, TRUE)
|
|
PLAY_SOUND_FROM_ENTITY(-1, "CAR_THEFT_MOVIE_LOT_DROP_SPIKES" , VehicleIndex)
|
|
ENDIF
|
|
ENDIF
|
|
|
|
IF GET_GAME_TIMER() - sGadgetData.iSpikesTimer > 200
|
|
IF NOT DOES_ENTITY_EXIST(sGadgetData.SpikesData[1].ObjectIndex)
|
|
sGadgetData.SpikesData[1].ObjectIndex = CREATE_OBJECT(PROP_TYRE_SPIKE_01, GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(VehicleIndex, << 0.1, -1.1, -0.4 >>))
|
|
SET_ENTITY_NO_COLLISION_ENTITY(sGadgetData.SpikesData[1].ObjectIndex, VehicleIndex, TRUE)
|
|
|
|
ENDIF
|
|
ENDIF
|
|
|
|
IF GET_GAME_TIMER() - sGadgetData.iSpikesTimer > 300
|
|
IF NOT DOES_ENTITY_EXIST(sGadgetData.SpikesData[2].ObjectIndex)
|
|
sGadgetData.SpikesData[2].ObjectIndex = CREATE_OBJECT(PROP_TYRE_SPIKE_01, GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(VehicleIndex, << -0.1, -1.0, -0.34 >>))
|
|
SET_ENTITY_NO_COLLISION_ENTITY(sGadgetData.SpikesData[2].ObjectIndex, VehicleIndex, TRUE)
|
|
sGadgetData.iSpikesTimer = 0
|
|
|
|
ENDIF
|
|
|
|
sGadgetData.iTimesSpikesDropped++
|
|
|
|
#IF IS_DEBUG_BUILD
|
|
PRINTLN(GET_THIS_SCRIPT_NAME(), ": Number of JB700 spike drops: ", sGadgetData.iTimesSpikesDropped, ".")
|
|
#ENDIF
|
|
|
|
sGadgetData.bSpikesDropped = TRUE
|
|
|
|
sGadgetData.iSpikeHit = 0
|
|
sGadgetData.bSpikesHit = FALSE
|
|
|
|
sGadgetData.SpikesData[0].bPtfxPlayed = FALSE
|
|
sGadgetData.SpikesData[1].bPtfxPlayed = FALSE
|
|
sGadgetData.SpikesData[2].bPtfxPlayed = FALSE
|
|
|
|
ENDIF
|
|
|
|
ENDIF
|
|
|
|
//play spikes sparks effect
|
|
IF HAS_PTFX_ASSET_LOADED()
|
|
IF ( sGadgetData.SpikesData[0].bPtfxPlayed = FALSE )
|
|
IF DOES_ENTITY_EXIST(sGadgetData.SpikesData[0].ObjectIndex)
|
|
IF NOT IS_ENTITY_IN_AIR(sGadgetData.SpikesData[0].ObjectIndex)
|
|
START_PARTICLE_FX_NON_LOOPED_ON_ENTITY("scr_carsteal3_tyre_spikes", sGadgetData.SpikesData[0].ObjectIndex, << 0.0, 0.0, -0.025 >>, << 0.0, 0.0, 0.0 >>)
|
|
sGadgetData.SpikesData[0].bPtfxPlayed = TRUE
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
IF ( sGadgetData.SpikesData[1].bPtfxPlayed = FALSE )
|
|
IF DOES_ENTITY_EXIST(sGadgetData.SpikesData[1].ObjectIndex)
|
|
IF NOT IS_ENTITY_IN_AIR(sGadgetData.SpikesData[1].ObjectIndex)
|
|
START_PARTICLE_FX_NON_LOOPED_ON_ENTITY("scr_carsteal3_tyre_spikes", sGadgetData.SpikesData[1].ObjectIndex, << 0.0, 0.0, -0.025 >>, << 0.0, 0.0, 0.0 >>)
|
|
sGadgetData.SpikesData[1].bPtfxPlayed = TRUE
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
IF ( sGadgetData.SpikesData[2].bPtfxPlayed = FALSE )
|
|
IF DOES_ENTITY_EXIST(sGadgetData.SpikesData[2].ObjectIndex)
|
|
IF NOT IS_ENTITY_IN_AIR(sGadgetData.SpikesData[2].ObjectIndex)
|
|
START_PARTICLE_FX_NON_LOOPED_ON_ENTITY("scr_carsteal3_tyre_spikes", sGadgetData.SpikesData[2].ObjectIndex, << 0.0, 0.0, -0.025 >>, << 0.0, 0.0, 0.0 >>)
|
|
sGadgetData.SpikesData[2].bPtfxPlayed = TRUE
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
ENDIF
|
|
ENDIF
|
|
|
|
REPEAT COUNT_OF(sGadgetData.SpikesData) i //activate physiscs on the spikes
|
|
|
|
IF DOES_ENTITY_EXIST(sGadgetData.SpikesData[i].ObjectIndex)
|
|
IF NOT IS_ENTITY_DEAD(sGadgetData.SpikesData[i].ObjectIndex)
|
|
IF DOES_ENTITY_HAVE_PHYSICS(sGadgetData.SpikesData[i].ObjectIndex)
|
|
ACTIVATE_PHYSICS(sGadgetData.SpikesData[i].ObjectIndex)
|
|
SET_ENTITY_DYNAMIC(sGadgetData.SpikesData[i].ObjectIndex, TRUE)
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
ENDREPEAT
|
|
|
|
ENDIF
|
|
ENDIF
|
|
|
|
ENDPROC
|
|
|
|
PROC UPDATE_JB700_SPIKES_CUTSCENE(VEHICLE_INDEX VehicleIndex, JB700_GADGET_DATA &sGadgetData, STRING AudioSceneName = NULL)
|
|
|
|
IF DOES_ENTITY_EXIST(VehicleIndex)
|
|
IF NOT IS_ENTITY_DEAD(VehicleIndex)
|
|
|
|
IF ( sGadgetData.bSpikesHit = TRUE )
|
|
|
|
IF ( sGadgetData.SpikesData[sGadgetData.iSpikeHit].iCutsceneTimer != 0 )
|
|
|
|
IF ( sGadgetData.bCutsceneTriggered = FALSE )
|
|
AND NOT IS_CINEMATIC_SHOT_ACTIVE(SHOTTYPE_CAMERA_MAN)
|
|
|
|
IF IS_PED_IN_VEHICLE(PLAYER_PED_ID(), VehicleIndex)
|
|
AND NOT IS_STUNT_JUMP_IN_PROGRESS()
|
|
|
|
IF IS_VEHICLE_DRIVEABLE(sGadgetData.SpikesData[sGadgetData.iSpikeHit].VehicleIndex)
|
|
|
|
CLEAR_HELP()
|
|
DISPLAY_HUD(FALSE)
|
|
DISPLAY_RADAR(FALSE)
|
|
|
|
DISABLE_CELLPHONE(TRUE)
|
|
HANG_UP_AND_PUT_AWAY_PHONE(TRUE)
|
|
|
|
SPECIAL_ABILITY_DEACTIVATE(PLAYER_ID())
|
|
ENABLE_SPECIAL_ABILITY(PLAYER_ID(), FALSE)
|
|
|
|
CREATE_CINEMATIC_SHOT(SHOTTYPE_CAMERA_MAN, 2000, NULL, sGadgetData.SpikesData[sGadgetData.iSpikeHit].VehicleIndex)
|
|
|
|
IF NOT IS_STRING_NULL_OR_EMPTY(AudioSceneName)
|
|
START_AUDIO_SCENE(AudioSceneName)
|
|
ENDIF
|
|
|
|
sGadgetData.bCutsceneTriggered = TRUE
|
|
|
|
#IF IS_DEBUG_BUILD
|
|
PRINTLN(GET_THIS_SCRIPT_NAME(), ": Starting cinematic shot spikes cutscene.")
|
|
#ENDIF
|
|
|
|
ENDIF
|
|
|
|
ELSE
|
|
|
|
RESET_JB700_SPIKES_CUTSCENE_TIMERS(sGadgetData)
|
|
|
|
ENDIF
|
|
|
|
ELSE
|
|
|
|
IF ( GET_GAME_TIMER() - sGadgetData.SpikesData[sGadgetData.iSpikeHit].iCutsceneTimer > 1500 )
|
|
OR NOT IS_VEHICLE_DRIVEABLE(sGadgetData.SpikesData[sGadgetData.iSpikeHit].VehicleIndex)
|
|
|
|
STOP_CINEMATIC_SHOT(SHOTTYPE_CAMERA_MAN)
|
|
|
|
REMOVE_PTFX_ASSET()
|
|
|
|
DISPLAY_HUD(TRUE)
|
|
DISPLAY_RADAR(TRUE)
|
|
|
|
DISABLE_CELLPHONE(FALSE)
|
|
|
|
IF NOT IS_STRING_NULL_OR_EMPTY(AudioSceneName)
|
|
STOP_AUDIO_SCENE(AudioSceneName)
|
|
ENDIF
|
|
|
|
ENABLE_SPECIAL_ABILITY(PLAYER_ID(), TRUE)
|
|
|
|
sGadgetData.SpikesData[sGadgetData.iSpikeHit].vPosition = << 0.0, 0.0, 0.0 >>
|
|
|
|
RESET_JB700_SPIKES_CUTSCENE_TIMERS(sGadgetData)
|
|
|
|
#IF IS_DEBUG_BUILD
|
|
PRINTLN(GET_THIS_SCRIPT_NAME(), ": Ending cinematic shot spikes cutscene.")
|
|
#ENDIF
|
|
|
|
ENDIF
|
|
|
|
ENDIF
|
|
|
|
ENDIF
|
|
|
|
ENDIF
|
|
|
|
ENDIF
|
|
ENDIF
|
|
|
|
ENDPROC
|
|
|
|
PROC UPDATE_JB700_SPIKES_COLLISIONS(VEHICLE_INDEX VehicleIndex, JB700_GADGET_DATA &sGadgetData, BOOL bGiveWantedLevel = TRUE)
|
|
|
|
IF DOES_ENTITY_EXIST(VehicleIndex)
|
|
IF NOT IS_ENTITY_DEAD(VehicleIndex)
|
|
|
|
INT i
|
|
VECTOR vSpikeOffsets[3]
|
|
FLOAT fSpikeGroundZ[3]
|
|
|
|
REPEAT COUNT_OF(sGadgetData.SpikesData) i
|
|
|
|
IF ( sGadgetData.SpikesData[i].vPosition.x != 0.0 )
|
|
|
|
IF ( sGadgetData.bSpikesHit = FALSE )
|
|
|
|
IF ( VDIST2(sGadgetData.SpikesData[i].vPosition, GET_ENTITY_COORDS(VehicleIndex)) > 2500.0 )
|
|
|
|
sGadgetData.SpikesData[i].vPosition = << 0.0, 0.0, 0.0 >>
|
|
|
|
ELSE
|
|
|
|
sGadgetData.SpikesData[i].VehicleIndex = GET_CLOSEST_VEHICLE(sGadgetData.SpikesData[i].vPosition, 20.0,
|
|
DUMMY_MODEL_FOR_SCRIPT,
|
|
VEHICLE_SEARCH_FLAG_ALLOW_VEHICLE_OCCUPANTS_TO_BE_PERFORMING_A_NON_DEFAULT_TASK |
|
|
VEHICLE_SEARCH_FLAG_ALLOW_VEHICLE_OCCUPANTS_TO_BE_PERFORMING_A_SCRIPTED_TASK |
|
|
VEHICLE_SEARCH_FLAG_ALLOW_LAW_ENFORCER_VEHICLES_WITH_WANTED_LEVEL |
|
|
VEHICLE_SEARCH_FLAG_RETURN_LAW_ENFORCER_VEHICLES |
|
|
VEHICLE_SEARCH_FLAG_RETURN_MISSION_VEHICLES |
|
|
VEHICLE_SEARCH_FLAG_RETURN_RANDOM_VEHICLES)
|
|
|
|
IF DOES_ENTITY_EXIST(sGadgetData.SpikesData[i].VehicleIndex) //if clostest vehicle is found
|
|
AND sGadgetData.SpikesData[i].VehicleIndex != VehicleIndex //and it's not vehicle that dropped spikes
|
|
|
|
REQUEST_PTFX_ASSET()
|
|
|
|
IF IS_VEHICLE_DRIVEABLE(sGadgetData.SpikesData[i].VehicleIndex)
|
|
AND NOT IS_THIS_MODEL_A_BIKE(GET_ENTITY_MODEL(sGadgetData.SpikesData[i].VehicleIndex))
|
|
|
|
VECTOR vVehiclePosition = GET_ENTITY_COORDS(sGadgetData.SpikesData[i].VehicleIndex)
|
|
|
|
#IF IS_DEBUG_BUILD
|
|
DRAW_DEBUG_LINE(sGadgetData.SpikesData[i].vPosition, vVehiclePosition, 255, 255, 255)
|
|
DRAW_DEBUG_TEXT(GET_STRING_FROM_INT(i),vVehiclePosition, 255, 255, 255)
|
|
#ENDIF
|
|
|
|
IF ( VDIST2(vVehiclePosition, sGadgetData.SpikesData[i].vPosition) < 100.0 ) //check distance from vehicle to spike
|
|
AND ( ABSF(vVehiclePosition.z - sGadgetData.SpikesData[i].vPosition.z) < 1.25 ) //check Z difference from vehicle to spike
|
|
AND ( GET_ENTITY_SPEED(sGadgetData.SpikesData[i].VehicleIndex) > 10.0 ) //check vehicle speed
|
|
AND IS_ENTITY_UPRIGHT(sGadgetData.SpikesData[i].VehicleIndex) //check if vehicle is not flipped
|
|
AND IS_VEHICLE_ON_ALL_WHEELS(sGadgetData.SpikesData[i].VehicleIndex) //check if vehicle is not off the ground
|
|
AND DOES_ENTITY_EXIST(sGadgetData.SpikesData[0].ObjectIndex)
|
|
AND DOES_ENTITY_EXIST(sGadgetData.SpikesData[1].ObjectIndex)
|
|
AND DOES_ENTITY_EXIST(sGadgetData.SpikesData[2].ObjectIndex)
|
|
|
|
VECTOR vVehicleDirection = CONVERT_ROTATION_TO_DIRECTION_VECTOR_NEW(<<0.0, 0.0, GET_ENTITY_HEADING(sGadgetData.SpikesData[i].VehicleIndex)>>)
|
|
|
|
VECTOR vDirectionToSpike = sGadgetData.SpikesData[i].vPosition - vVehiclePosition
|
|
|
|
vDirectionToSpike = vDirectionToSpike / VMAG(vDirectionToSpike)
|
|
|
|
IF DOT_PRODUCT(vVehicleDirection, vDirectionToSpike) > 0.0
|
|
|
|
sGadgetData.iSpikesHits++
|
|
sGadgetData.bSpikesHit = TRUE
|
|
sGadgetData.iSpikeHit = i
|
|
sGadgetData.bCutsceneTriggered = FALSE
|
|
sGadgetData.SpikesData[i].iCutsceneTimer = GET_GAME_TIMER()
|
|
|
|
#IF IS_DEBUG_BUILD
|
|
PRINTLN(GET_THIS_SCRIPT_NAME(), ": Number of JB700 spike hits: ", sGadgetData.iSpikesHits, ".")
|
|
#ENDIF
|
|
|
|
//Reposition the spikes so they always hit if the cutscene triggers
|
|
vSpikeOffsets[0] = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(sGadgetData.SpikesData[i].VehicleIndex, <<0.8, 6.0, 0.0>>)
|
|
vSpikeOffsets[1] = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(sGadgetData.SpikesData[i].VehicleIndex, <<0.5, 7.0, 0.0>>)
|
|
vSpikeOffsets[2] = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(sGadgetData.SpikesData[i].VehicleIndex, <<0.9, 8.0, 0.0>>)
|
|
GET_GROUND_Z_FOR_3D_COORD(vSpikeOffsets[0], fSpikeGroundZ[0])
|
|
GET_GROUND_Z_FOR_3D_COORD(vSpikeOffsets[1], fSpikeGroundZ[1])
|
|
GET_GROUND_Z_FOR_3D_COORD(vSpikeOffsets[2], fSpikeGroundZ[2])
|
|
SET_ENTITY_COORDS(sGadgetData.SpikesData[0].ObjectIndex, <<vSpikeOffsets[0].x, vSpikeOffsets[0].y, fSpikeGroundZ[0] + 0.05>>)
|
|
SET_ENTITY_COORDS(sGadgetData.SpikesData[1].ObjectIndex, <<vSpikeOffsets[1].x, vSpikeOffsets[1].y, fSpikeGroundZ[1] + 0.05>>)
|
|
SET_ENTITY_COORDS(sGadgetData.SpikesData[2].ObjectIndex, <<vSpikeOffsets[2].x, vSpikeOffsets[2].y, fSpikeGroundZ[2] + 0.05>>)
|
|
sGadgetData.SpikesData[i].vPosition = vSpikeOffsets[1]
|
|
|
|
ENDIF
|
|
|
|
ENDIF
|
|
ENDIF
|
|
|
|
ENDIF
|
|
|
|
ENDIF
|
|
|
|
ELSE //once the vehicle hits the spike, make it spin and burst tyres
|
|
|
|
IF IS_VEHICLE_DRIVEABLE(sGadgetData.SpikesData[i].VehicleIndex)
|
|
|
|
VECTOR vVehiclePosition = GET_ENTITY_COORDS(sGadgetData.SpikesData[i].VehicleIndex, FALSE)
|
|
|
|
IF ( sGadgetData.SpikesData[i].iForceTimer = 0 )
|
|
|
|
REQUEST_PTFX_ASSET()
|
|
|
|
IF ( VDIST2(vVehiclePosition, sGadgetData.SpikesData[i].vPosition) < 9.0 )
|
|
|
|
FLOAT fMaxSpeed = GET_VEHICLE_ESTIMATED_MAX_SPEED(sGadgetData.SpikesData[i].VehicleIndex)
|
|
FLOAT fCurrentSpeed = GET_ENTITY_SPEED(sGadgetData.SpikesData[i].VehicleIndex)
|
|
FLOAT fSpeedRatio = fCurrentSpeed / (fMaxSpeed - 20.0)
|
|
|
|
IF fSpeedRatio > 1.0
|
|
fSpeedRatio = 1.0
|
|
ELIF fSpeedRatio < 0.3
|
|
fSpeedRatio = 0.3
|
|
ENDIF
|
|
|
|
sGadgetData.SpikesData[i].iForceTimer = GET_GAME_TIMER() - ROUND((1.0 - fSpeedRatio) * 1000.0)
|
|
|
|
SET_VEHICLE_TYRE_BURST(sGadgetData.SpikesData[i].VehicleIndex, SC_WHEEL_CAR_FRONT_LEFT, TRUE)
|
|
SET_VEHICLE_TYRE_BURST(sGadgetData.SpikesData[i].VehicleIndex, SC_WHEEL_CAR_FRONT_RIGHT, TRUE)
|
|
|
|
PLAY_SOUND_FROM_ENTITY(-1, "CAR_STEAL_3_AGENT_TYRE_BURST", sGadgetData.SpikesData[i].VehicleIndex, "CAR_STEAL_3_AGENT")
|
|
|
|
IF HAS_PTFX_ASSET_LOADED()
|
|
START_PARTICLE_FX_NON_LOOPED_ON_ENTITY("scr_carsteal4_tyre_spiked", sGadgetData.SpikesData[i].VehicleIndex, << 1.2, 2.0, -0.3 >>, << 0.0, 0.0, 0.0 >>)
|
|
START_PARTICLE_FX_NON_LOOPED_ON_ENTITY("scr_carsteal4_tyre_spiked", sGadgetData.SpikesData[i].VehicleIndex, << -1.2, 2.0, -0.3 >>, << 0.0, 0.0, 0.0 >>)
|
|
ENDIF
|
|
|
|
IF ( bGiveWantedLevel = TRUE )
|
|
IF IS_PLAYER_PLAYING(PLAYER_ID())
|
|
IF NOT IS_PLAYER_WANTED_LEVEL_GREATER(PLAYER_ID(), 0)
|
|
IF IS_MODEL_POLICE_VEHICLE(GET_ENTITY_MODEL(sGadgetData.SpikesData[i].VehicleIndex))
|
|
SET_PLAYER_WANTED_LEVEL(PLAYER_ID(), 1)
|
|
SET_PLAYER_WANTED_LEVEL_NOW(PLAYER_ID())
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
ENDIF
|
|
|
|
ELSE
|
|
|
|
IF GET_GAME_TIMER() - sGadgetData.SpikesData[i].iForceTimer < 1000
|
|
APPLY_FORCE_TO_ENTITY(sGadgetData.SpikesData[i].VehicleIndex, APPLY_TYPE_FORCE, << -25.0, 0.0, 0.0 >>, << 0.0, -2.0, 0.0 >>, 0, TRUE, TRUE, TRUE)
|
|
ENDIF
|
|
|
|
ENDIF
|
|
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
ENDREPEAT
|
|
|
|
ENDIF
|
|
ENDIF
|
|
|
|
ENDPROC
|