//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 = <> 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, <>) SET_ENTITY_COORDS(sGadgetData.SpikesData[1].ObjectIndex, <>) SET_ENTITY_COORDS(sGadgetData.SpikesData[2].ObjectIndex, <>) 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