// ***************************************************************************************** // ***************************************************************************************** // ***************************************************************************************** // // SCRIPT NAME : SPTT_Racer.sch // AUTHOR : Nicholas Zippmann // DESCRIPTION : Single Player Races - Racer procs/functions file // // ***************************************************************************************** // ***************************************************************************************** // ***************************************************************************************** USING "SPTT_Head.sch" USING "SPTT_Helpers.sch" USING "SPTT_Gate.sch" USING "chase_hint_cam.sch" USING "stunt_plane_public.sch" // ----------------------------------- // SETUP PROCS/FUNCTIONS // ----------------------------------- // bits for dialogue INT iMissedGateBits // missed gates INT iClearedGateBits // cleared gates INT iPerfectGateBits // perfect gates INT iInvertedGateBits // inverted gates INT iKnifeGateBits // knife gates INT iPerfInvGateBits // perfect inverted gates INT iPerfKniGateBits // perfect knife gates // tracks how many consecutive gates weve hit INT iStuntGateHit ENUM GateStuntBits Missed_Once = BIT0, Missed_Twice = BIT1, Missed_Third = BIT2, Hit_Once = BIT3, Hit_Twice = BIT4, Hit_Third = BIT5, Knife_Once = BIT6, Knife_Twice = BIT7, Knife_Third = BIT8, Inverted_Once = BIT9, Inverted_Twice = BIT10, Inverted_Third = BIT11, Perfect_Once = BIT12, Perfect_Twice = BIT13, Perfect_Third = BIT14, P_Inverted_Once = BIT15, P_Inverted_Twice = BIT16, P_Inverted_Third = BIT17, P_Knife_Once = BIT18, P_Knife_Twice = BIT19, P_Knife_Third = BIT20 ENDENUM #IF NOT DEFINED(OFFROAD_RACE_VEHICLE_CHECK) FUNC INT OFFROAD_RACE_VEHICLE_CHECK(SPTT_RACER_STRUCT& Racer, INT& iMesaTop) DEBUG_MESSAGE("Printing stuff inside of empty OFFROAD_RACE_VEHICLE_CHECK") iMesaTop = -1 PRINTFLOAT(Racer.fClockTime) PRINTNL() RETURN -1 ENDFUNC #ENDIF #IF NOT DEFINED(UnfreezePlayerVehicle) PROC UnfreezePlayerVehicle() DEBUG_MESSAGE("Printing stuff inside of empty UnfreezePlayerVehicle") ENDPROC #ENDIF #IF NOT DEFINED(Play_Gate_Audio) PROC Play_Gate_Audio(STRING sLine, INT iBitmaskInt) PRINTINT(iBitmaskInt) PRINTNL() PRINTSTRING(sLine) PRINTNL() ENDPROC #ENDIF PROC SPTT_Racer_Init(SPTT_RACER_STRUCT& Racer) //DEBUG_MESSAGE("SPTT_Racer_Init") Racer.szName = "Racer" Racer.Driver = NULL Racer.Vehicle = NULL Racer.Blip = NULL Racer.iGateCur = -1 Racer.iRank = 0 Racer.fClockTime = 0.0 Racer.fPlsMnsLst = 0.0 Racer.fPlsMnsTot = 0.0 Racer.eReset = SPTT_RACER_RESET_WAIT Racer.vStartPos = SPTT_Master.vDefRcrPos Racer.fStartHead = SPTT_Master.fDefRcrHead Racer.eDriverType = SPTT_Master.eDefDrvType Racer.eDriverModel = SPTT_Master.eDefDrvModel Racer.eVehicleModel = SPTT_Master.eDefVehModel ENDPROC PROC SPTT_Racer_Setup_Misc(SPTT_RACER_STRUCT& Racer) //DEBUG_MESSAGE("SPTT_Racer_Setup_Misc") Racer.Blip = NULL Racer.iGateCur = -1 Racer.iRank = 0 Racer.fClockTime = 0.0 Racer.eReset = SPTT_RACER_RESET_WAIT ENDPROC PROC SPTT_Racer_Setup_Name(SPTT_RACER_STRUCT& Racer, STRING sName) //DEBUG_MESSAGE("SPTT_Racer_Setup_Name") Racer.szName = sName ENDPROC PROC SPTT_Racer_Setup_Entities(SPTT_RACER_STRUCT& Racer, PED_INDEX Driver, VEHICLE_INDEX Vehicle) //DEBUG_MESSAGE("SPTT_Racer_Setup_Entities") Racer.Driver = Driver Racer.Vehicle = Vehicle GET_VEHICLE_SETUP( Vehicle, SPTT_Master.vssPlaneSetup ) ENDPROC PROC SPTT_Racer_Setup_Start(SPTT_RACER_STRUCT& Racer, VECTOR vStartPos, FLOAT fStartHead) //DEBUG_MESSAGE("SPTT_Racer_Setup_Start") Racer.vStartPos = vStartPos Racer.fStartHead = fStartHead ENDPROC PROC SPTT_Racer_Setup_Types(SPTT_RACER_STRUCT& Racer, PED_TYPE eDriverType, MODEL_NAMES eDriverModel, MODEL_NAMES eVehicleModel) //DEBUG_MESSAGE("SPTT_Racer_Setup_Types") Racer.eDriverType = eDriverType Racer.eDriverModel = eDriverModel Racer.eVehicleModel = eVehicleModel ENDPROC PROC SPTT_RESET_GATE_DIALOGUE_BITS() iMissedGateBits = 0 // missed gates iClearedGateBits = 0 // cleared gates iPerfectGateBits = 0 // perfect gates iInvertedGateBits = 0 // inverted gates iKnifeGateBits = 0 // knife gates iPerfInvGateBits = 0 // perfect inverted gates iPerfKniGateBits = 0 // perfect knife gates iStuntGateHit = 0 ENDPROC // ----------------------------------- // DRIVER CREATION PROCS/FUNCTIONS // ----------------------------------- PROC SPTT_Racer_Driver_Request(SPTT_RACER_STRUCT& Racer) //DEBUG_MESSAGE("SPTT_Racer_Driver_Request") IF (Racer.eDriverModel = DUMMY_MODEL_FOR_SCRIPT) SCRIPT_ASSERT("SPTT_Racer_Driver_Request: Model invalid!") EXIT ENDIF REQUEST_MODEL(Racer.eDriverModel) ENDPROC FUNC BOOL SPTT_Racer_Driver_Stream(SPTT_RACER_STRUCT& Racer) //DEBUG_MESSAGE("SPTT_Racer_Driver_Stream") IF (Racer.eDriverModel = DUMMY_MODEL_FOR_SCRIPT) SCRIPT_ASSERT("SPTT_Racer_Driver_Stream: Model invalid!") RETURN FALSE ENDIF RETURN HAS_MODEL_LOADED(Racer.eDriverModel) ENDFUNC PROC SPTT_Racer_Driver_Evict(SPTT_RACER_STRUCT& Racer) //DEBUG_MESSAGE("SPTT_Racer_Driver_Evict") IF (Racer.eDriverModel = DUMMY_MODEL_FOR_SCRIPT) SCRIPT_ASSERT("SPTT_Racer_Driver_Evict: Model invalid!") EXIT ENDIF SET_MODEL_AS_NO_LONGER_NEEDED(Racer.eDriverModel) ENDPROC FUNC BOOL SPTT_Racer_Driver_Create(SPTT_RACER_STRUCT& Racer) PRINTLN("[SPTT_Racer_Driver_Create] Function called.") // Check if driver model is valid before continuing. IF (Racer.eDriverModel = DUMMY_MODEL_FOR_SCRIPT) SCRIPT_ASSERT("[SPTT_Racer_Driver_Create] Model invalid!") RETURN FALSE ENDIF // Check if driver already exists. IF NOT IS_ENTITY_DEAD(Racer.Driver) PRINTLN("[SPTT_Racer_Driver_Create] Player is ALIVE.") SET_ENTITY_HEALTH(Racer.Driver, 1000) // If vehicle also exists, put driver in it, if needed. IF NOT IS_ENTITY_DEAD(Racer.Vehicle) PRINTLN("[SPTT_Racer_Driver_Create] Placing player in stunt plane.") IF NOT IS_PED_SITTING_IN_VEHICLE(Racer.Driver, Racer.Vehicle) SET_PED_INTO_VEHICLE(Racer.Driver, Racer.Vehicle) ENDIF ELSE PRINTLN("[SPTT_Racer_Driver_Create] Warp the player to the start position.") SET_ENTITY_COORDS(Racer.Driver, Racer.vStartPos) SET_ENTITY_HEADING(Racer.Driver, Racer.fStartHead) ENDIF // The driver does not exist, but the vehicle is dead, so create driver inside it and check for validity. ELIF NOT IS_ENTITY_DEAD(Racer.Vehicle) PRINTLN("[SPTT_Racer_Driver_Create] Player is DEAD, but stunt plane is ALIVE. Create the player inside the vehicle.") Racer.Driver = CREATE_PED_INSIDE_VEHICLE(Racer.Vehicle, Racer.eDriverType, Racer.eDriverModel) IF IS_ENTITY_DEAD(Racer.Driver) PRINTLN("[SPTT_Racer_Driver_Create] Failed to create the player in the stunt plane.") RETURN FALSE ENDIF // The driver nor the vehicle exist. ELSE PRINTLN("[SPTT_Racer_Driver_Create] Player and stunt plane are BOTH DEAD. Create the player on foot.") Racer.Driver = CREATE_PED(Racer.eDriverType, Racer.eDriverModel, Racer.vStartPos, Racer.fStartHead) IF IS_ENTITY_DEAD(Racer.Driver) PRINTLN("[SPTT_Racer_Driver_Create] Failed to create the player on foot.") RETURN FALSE ENDIF ENDIF // Check if driver type is player. NOTE: This may not be needed. IF (Racer.eDriverType > PEDTYPE_PLAYER_UNUSED) // Set driver as mission entity. IF NOT IS_ENTITY_A_MISSION_ENTITY(Racer.Driver) SET_ENTITY_AS_MISSION_ENTITY(Racer.Driver) ENDIF // Set driver debug name. TEXT_LABEL szDebugName = Racer.szName szDebugName += "_Drv" SET_PED_NAME_DEBUG(Racer.Driver, szDebugName) ENDIF // Racer driver successfully created. PRINTLN("[SPTT_Racer_Driver_Create] Player successfully created and/or set.") RETURN TRUE ENDFUNC PROC SPTT_Racer_Driver_Freeze(SPTT_RACER_STRUCT& Racer) //DEBUG_MESSAGE("SPTT_Racer_Driver_Freeze") IF NOT IS_ENTITY_DEAD(Racer.Driver) IF NOT IS_PED_IN_ANY_VEHICLE(Racer.Driver) FREEZE_ENTITY_POSITION(Racer.Driver, TRUE) SET_ENTITY_COLLISION(Racer.Driver, FALSE) ENDIF SET_ENTITY_INVINCIBLE(Racer.Driver, TRUE) ENDIF ENDPROC PROC SPTT_Racer_Driver_UnFreeze(SPTT_RACER_STRUCT& Racer) //DEBUG_MESSAGE("SPTT_Racer_Driver_UnFreeze") IF NOT IS_ENTITY_DEAD(Racer.Driver) IF NOT IS_PED_IN_ANY_VEHICLE(Racer.Driver) FREEZE_ENTITY_POSITION(Racer.Driver, FALSE) SET_ENTITY_COLLISION(Racer.Driver, TRUE) ENDIF // SET_ENTITY_INVINCIBLE(Racer.Driver, FALSE) ENDIF ENDPROC PROC SPTT_Racer_Driver_Release(SPTT_RACER_STRUCT& Racer) //DEBUG_MESSAGE("SPTT_Racer_Driver_Release") IF DOES_ENTITY_EXIST(Racer.Driver) // TODO: Decide if this player check is even needed... IF (Racer.Driver <> PLAYER_PED_ID()) SET_PED_AS_NO_LONGER_NEEDED(Racer.Driver) ENDIF ENDIF ENDPROC PROC SPTT_Racer_Driver_Destroy(SPTT_RACER_STRUCT& Racer) //DEBUG_MESSAGE("SPTT_Racer_Driver_Destroy") IF DOES_ENTITY_EXIST(Racer.Driver) // TODO: Decide if this player check is even needed... IF (Racer.Driver <> PLAYER_PED_ID()) DELETE_PED(Racer.Driver) ENDIF ENDIF ENDPROC // ----------------------------------- // VEHICLE CREATION PROCS/FUNCTIONS // ----------------------------------- PROC SPTT_Racer_Vehicle_Request(SPTT_RACER_STRUCT& Racer) //DEBUG_MESSAGE("SPTT_Racer_Vehicle_Request") IF (Racer.eVehicleModel = DUMMY_MODEL_FOR_SCRIPT) DEBUG_MESSAGE("SPTT_Racer_Vehicle_Request: Model invalid!") EXIT ENDIF REQUEST_MODEL(Racer.eVehicleModel) ENDPROC FUNC BOOL SPTT_Racer_Vehicle_Stream(SPTT_RACER_STRUCT& Racer) //DEBUG_MESSAGE("SPTT_Racer_Vehicle_Stream") IF (Racer.eVehicleModel = DUMMY_MODEL_FOR_SCRIPT) DEBUG_MESSAGE("SPTT_Racer_Vehicle_Stream: Model invalid!") RETURN TRUE ENDIF RETURN HAS_MODEL_LOADED(Racer.eVehicleModel) ENDFUNC PROC SPTT_Racer_Vehicle_Evict(SPTT_RACER_STRUCT& Racer) //DEBUG_MESSAGE("SPTT_Racer_Vehicle_Evict") IF (Racer.eVehicleModel = DUMMY_MODEL_FOR_SCRIPT) DEBUG_MESSAGE("SPTT_Racer_Vehicle_Evict: Model invalid!") EXIT ENDIF SET_MODEL_AS_NO_LONGER_NEEDED(Racer.eVehicleModel) ENDPROC FUNC BOOL SPTT_Racer_Vehicle_Create(SPTT_RACER_STRUCT& Racer, BOOL bForceCreate) PRINTLN("[SPTT_Racer_Vehicle_Create] Function called.") // If forced to create a new stunt plane and one already exists, destroy it! IF bForceCreate PRINTLN("[SPTT_Racer_Vehicle_Create] Force-creating the stunt plane was passed as TRUE.") IF DOES_ENTITY_EXIST(Racer.Vehicle) PRINTLN("[SPTT_Racer_Vehicle_Create] The stunt plane still exists.") IF NOT IS_ENTITY_DEAD(Racer.Vehicle) OR NOT IS_VEHICLE_DRIVEABLE(Racer.Vehicle) PRINTLN("[SPTT_Racer_Vehicle_Create] The stunt plane is not dead, but it's not driveable.") IF IS_PED_IN_VEHICLE(Racer.Driver, Racer.Vehicle) PRINTLN("[SPTT_Racer_Vehicle_Create] The player is inside the stunt plane. Clear his tasks and delete the stunt plane.") CLEAR_PED_TASKS_IMMEDIATELY(Racer.Driver) SET_ENTITY_AS_MISSION_ENTITY(Racer.Vehicle, TRUE, TRUE) DELETE_VEHICLE(Racer.Vehicle) ENDIF ELSE IF IS_PED_IN_VEHICLE(Racer.Driver, Racer.Vehicle) PRINTLN("[SPTT_Racer_Vehicle_Create] Warping the player out of the stunt plane.") SET_ENTITY_COORDS(Racer.Driver, Racer.vStartPos) ENDIF IF IS_PED_IN_VEHICLE(Racer.Driver, Racer.Vehicle) PRINTLN("[SPTT_Racer_Vehicle_Create] The player is still in the stunt plane.") ELSE PRINTLN("[SPTT_Racer_Vehicle_Create] The player is no longer in the stunt plane. Delete the stunt plane.") SET_ENTITY_AS_MISSION_ENTITY(Racer.Vehicle, TRUE, TRUE) DELETE_VEHICLE(Racer.Vehicle) ENDIF ENDIF ENDIF ENDIF // If vehicle already exists, set health to max and teleport it. IF NOT IS_ENTITY_DEAD(Racer.Vehicle) PRINTLN("[SPTT_Racer_Vehicle_Create] A vehicle exists, so fix it. We should never reach here if we're forced to create a new stunt plane.") // Fix vehicle. SET_ENTITY_HEALTH(Racer.Vehicle, 1000) SET_VEHICLE_FIXED(Racer.Vehicle) SET_VEHICLE_ENGINE_HEALTH(Racer.Vehicle, 1000.0) // Position and orient the vehicle. SET_ENTITY_COORDS(Racer.Vehicle, Racer.vStartPos) SET_ENTITY_HEADING(Racer.Vehicle, Racer.fStartHead) SET_VEHICLE_ON_GROUND_PROPERLY( Racer.Vehicle ) ELSE PRINTLN("[SPTT_Racer_Vehicle_Create] A vehicle exists, so fix it.") IF (Racer.eVehicleModel = DUMMY_MODEL_FOR_SCRIPT) PRINTLN("[SPTT_Racer_Vehicle_Create] ERROR: Cannot create vehicle. No model name stored for vehicle. Returning TRUE.") RETURN TRUE ENDIF // Create the stunt plane with strong axles. Racer.Vehicle = CREATE_VEHICLE(STUNT, Racer.vStartPos, Racer.fStartHead) IF IS_ENTITY_DEAD(Racer.Vehicle) PRINTLN("[SPTT_Racer_Vehicle_Create] ERROR: Vehicle not created.") RETURN FALSE ENDIF IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) SET_VEHICLE_DOORS_LOCKED(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()), VEHICLELOCK_LOCKED_PLAYER_INSIDE) ENDIF SET_VEHICLE_HAS_STRONG_AXLES(Racer.Vehicle, TRUE) SET_VEHICLE_SETUP( Racer.Vehicle, SPTT_Master.vssPlaneSetup ) ENDIF ENABLE_STALL_WARNING_SOUNDS(Racer.Vehicle, FALSE) SET_VEHICLE_ENGINE_ON(Racer.Vehicle, TRUE, TRUE) SET_HELI_BLADES_FULL_SPEED(Racer.Vehicle) // If driver exists, put them in vehicle, if needed. IF NOT IS_ENTITY_DEAD(Racer.Driver) IF NOT IS_PED_SITTING_IN_VEHICLE(Racer.Driver, Racer.Vehicle) PRINTLN("[SPTT_Racer_Vehicle_Create] Setting the player inside the stunt plane.") SET_PED_INTO_VEHICLE(Racer.Driver, Racer.Vehicle) ENDIF ENDIF // Set vehicle as mission entity. IF NOT IS_ENTITY_A_MISSION_ENTITY(Racer.Vehicle) PRINTLN("[SPTT_Racer_Vehicle_Create] Set plane as mission entity.") SET_ENTITY_AS_MISSION_ENTITY(Racer.Vehicle) ENDIF // Set vehicle debug name. TEXT_LABEL szDebugName = Racer.szName szDebugName += "_Veh" SET_VEHICLE_NAME_DEBUG(Racer.Vehicle, szDebugName) // Check if driver type is player. IF (Racer.eDriverType <= PEDTYPE_PLAYER_UNUSED) PRINTLN("[SPTT_Racer_Vehicle_Create] Store the vehicle in the system, and set vehicle to maintain speed when in autopilot.") SET_VEHICLE_LIMIT_SPEED_WHEN_PLAYER_INACTIVE(Racer.Vehicle, FALSE) SPTT_Master.PlayerVeh = Racer.Vehicle ENDIF // Racer vehicle successfully created. PRINTLN("[SPTT_Racer_Vehicle_Create] Stunt plane has been successfully created!") RETURN TRUE ENDFUNC PROC SPTT_Racer_Vehicle_Freeze(SPTT_RACER_STRUCT& Racer) //DEBUG_MESSAGE("SPTT_Racer_Vehicle_Freeze") IF NOT IS_ENTITY_DEAD(Racer.Vehicle) FREEZE_ENTITY_POSITION(Racer.Vehicle, TRUE) SET_ENTITY_COLLISION(Racer.Vehicle, FALSE) SET_ENTITY_INVINCIBLE(Racer.Vehicle, TRUE) ENDIF ENDPROC PROC SPTT_Racer_Vehicle_UnFreeze(SPTT_RACER_STRUCT& Racer) //DEBUG_MESSAGE("SPTT_Racer_Vehicle_UnFreeze") IF NOT IS_ENTITY_DEAD(Racer.Vehicle) FREEZE_ENTITY_POSITION(Racer.Vehicle, FALSE) SET_ENTITY_COLLISION(Racer.Vehicle, TRUE) // SET_ENTITY_INVINCIBLE(Racer.Vehicle, FALSE) ENDIF ENDPROC PROC SPTT_Racer_Vehicle_Release(SPTT_RACER_STRUCT& Racer) //DEBUG_MESSAGE("SPTT_Racer_Vehicle_Release") IF DOES_ENTITY_EXIST(Racer.Vehicle) // TODO: Decide if this player check is even needed... IF (Racer.Vehicle <> SPTT_Master.PlayerVeh) IF NOT IS_ENTITY_DEAD(Racer.Driver) IF IS_PED_IN_VEHICLE(Racer.Driver, Racer.Vehicle) TASK_LEAVE_ANY_VEHICLE(Racer.Driver) ENDIF ENDIF SET_VEHICLE_AS_NO_LONGER_NEEDED(Racer.Vehicle) ENDIF ENDIF ENDPROC PROC SPTT_Racer_Vehicle_Destroy(SPTT_RACER_STRUCT& Racer) //DEBUG_MESSAGE("SPTT_Racer_Vehicle_Destroy") IF DOES_ENTITY_EXIST(Racer.Vehicle) // TODO: Decide if this player check is even needed... IF (Racer.Vehicle <> SPTT_Master.PlayerVeh) IF NOT ( IS_ENTITY_DEAD(Racer.Driver) OR IS_ENTITY_DEAD(Racer.Vehicle) ) IF IS_PED_IN_VEHICLE(Racer.Driver, Racer.Vehicle) CLEAR_PED_TASKS_IMMEDIATELY(Racer.Driver) ENDIF ENDIF DELETE_VEHICLE(Racer.Vehicle) ENDIF ENDIF ENDPROC // ----------------------------------- // MAIN CREATION PROCS/FUNCTIONS // ----------------------------------- PROC SPTT_Racer_Request(SPTT_RACER_STRUCT& Racer) //DEBUG_MESSAGE("SPTT_Racer_Request") SPTT_Racer_Driver_Request(Racer) SPTT_Racer_Vehicle_Request(Racer) ENDPROC FUNC BOOL SPTT_Racer_Stream(SPTT_RACER_STRUCT& Racer) //DEBUG_MESSAGE("SPTT_Racer_Stream") IF NOT SPTT_Racer_Driver_Stream(Racer) OR NOT SPTT_Racer_Vehicle_Stream(Racer) RETURN FALSE ENDIF RETURN TRUE ENDFUNC PROC SPTT_Racer_Evict(SPTT_RACER_STRUCT& Racer) //DEBUG_MESSAGE("SPTT_Racer_Evict") SPTT_Racer_Driver_Evict(Racer) SPTT_Racer_Vehicle_Evict(Racer) ENDPROC FUNC BOOL SPTT_Racer_Blip_Create(SPTT_RACER_STRUCT& Racer, BOOL bFriendly = TRUE, FLOAT fScale = 1.0) //DEBUG_MESSAGE("SPTT_Racer_Blip_Create") /* SAVE: Just bliping the driver now, since they will be in the vehicle that we are bliping. IF IS_ENTITY_DEAD(Racer.Vehicle) IF (Racer.Driver <> PLAYER_PED_ID()) IF NOT SPTT_Blip_Entity_Create(Racer.Blip, Racer.Driver, bFriendly, fScale, Racer.szName) DEBUG_MESSAGE("SPTT_Racer_Blip_Create: Failed to create racer driver blip!") RETURN FALSE ENDIF ENDIF ELIF (Racer.Driver <> PLAYER_PED_ID()) OR NOT IS_PED_SITTING_IN_VEHICLE(Racer.Driver, Racer.Vehicle) IF NOT SPTT_Blip_Entity_Create(Racer.Blip, Racer.Vehicle, bFriendly, fScale, Racer.szName) DEBUG_MESSAGE("SPTT_Racer_Blip_Create: Failed to create racer vehicle blip!") RETURN FALSE ENDIF ENDIF*/ IF (Racer.Driver <> PLAYER_PED_ID()) IF NOT SPTT_Blip_Entity_Create(Racer.Blip, Racer.Driver, bFriendly, fScale, Racer.szName) DEBUG_MESSAGE("SPTT_Racer_Blip_Create: Failed to create racer driver blip!") RETURN FALSE ENDIF ENDIF RETURN TRUE ENDFUNC PROC SPTT_Racer_Blip_Destroy(SPTT_RACER_STRUCT& Racer) //DEBUG_MESSAGE("SPTT_Racer_Blip_Destroy") SPTT_Blip_Destroy(Racer.Blip) ENDPROC FUNC BOOL SPTT_Racer_Create(SPTT_RACER_STRUCT& Racer, BOOL bForceCreate) PRINTLN("[SPTT_Racer_Create] Function called.") IF NOT SPTT_Racer_Vehicle_Create(Racer, bForceCreate) OR NOT SPTT_Racer_Driver_Create(Racer) PRINTLN("[SPTT_Racer_Create] Vehicle and driver both NOT yet created.") RETURN FALSE ENDIF PRINTLN("[SPTT_Racer_Create] Vehicle and driver BOTH created.") RETURN TRUE ENDFUNC PROC SPTT_Racer_Freeze(SPTT_RACER_STRUCT& Racer) //DEBUG_MESSAGE("SPTT_Racer_Freeze") SPTT_Racer_Driver_Freeze(Racer) SPTT_Racer_Vehicle_Freeze(Racer) ENDPROC PROC SPTT_Racer_UnFreeze(SPTT_RACER_STRUCT& Racer) //DEBUG_MESSAGE("SPTT_Racer_UnFreeze") SPTT_Racer_Driver_UnFreeze(Racer) SPTT_Racer_Vehicle_UnFreeze(Racer) ENDPROC PROC SPTT_Racer_Release(SPTT_RACER_STRUCT& Racer) //DEBUG_MESSAGE("SPTT_Racer_Release") SPTT_Racer_Blip_Destroy(Racer) SPTT_Racer_Driver_Release(Racer) SPTT_Racer_Vehicle_Release(Racer) ENDPROC PROC SPTT_Racer_Destroy(SPTT_RACER_STRUCT& Racer) //DEBUG_MESSAGE("SPTT_Racer_Destroy") SPTT_Racer_Blip_Destroy(Racer) SPTT_Racer_Driver_Destroy(Racer) SPTT_Racer_Vehicle_Destroy(Racer) ENDPROC // ----------------------------------- // HELPER PROCS/FUNCTIONS // ----------------------------------- FUNC BOOL SPTT_IS_PLANE_KNIFING(ENTITY_INDEX entKnifing) VECTOR vFront, vSide, vUp, vPos IF IS_ENTITY_DEAD(entKnifing) RETURN FALSE ENDIF GET_ENTITY_MATRIX(entKnifing, vFront, vSide, vUp, vPos) IF ABSF(vUp.z) > STUNT_PLANE_KNIFE_THRESHOLD RETURN FALSE ENDIF RETURN vSide.z <> 0.0 ENDFUNC FUNC BOOL SPTT_IS_PLANE_KNIFING_LEFT(ENTITY_INDEX entKnifing) VECTOR vFront, vSide, vUp, vPos IF IS_ENTITY_DEAD(entKnifing) RETURN FALSE ENDIF GET_ENTITY_MATRIX(entKnifing, vFront, vSide, vUp, vPos) IF ABSF(vUp.z) > STUNT_PLANE_KNIFE_THRESHOLD RETURN FALSE ENDIF RETURN vSide.z > 0.0 ENDFUNC FUNC BOOL SPTT_IS_PLANE_KNIFING_RIGHT(ENTITY_INDEX entKnifing) VECTOR vFront, vSide, vUp, vPos IF IS_ENTITY_DEAD(entKnifing) RETURN FALSE ENDIF GET_ENTITY_MATRIX(entKnifing, vFront, vSide, vUp, vPos) IF ABSF(vUp.z) > STUNT_PLANE_KNIFE_THRESHOLD RETURN FALSE ENDIF RETURN vSide.z < 0.0 ENDFUNC PROC SPTT_Racer_Teleport(SPTT_RACER_STRUCT& Racer, VECTOR vPos, FLOAT fHeading, FLOAT fSpeed) PRINTLN("[SPTT_Racer_Teleport] Procedure started.") SET_ENTITY_COORDS(Racer.Vehicle, vPos) SET_ENTITY_HEADING(Racer.Vehicle, fHeading) SET_VEHICLE_FORWARD_SPEED(Racer.Vehicle, fSpeed) ENDPROC PROC SPTT_Racer_Start(SPTT_RACER_STRUCT& Racer) //DEBUG_MESSAGE("SPTT_Racer_Start") IF NOT IS_ENTITY_DEAD(Racer.Vehicle) IF NOT IS_ENTITY_DEAD(Racer.Driver) IF IS_PLAYBACK_GOING_ON_FOR_VEHICLE(Racer.Vehicle) STOP_PLAYBACK_RECORDED_VEHICLE(Racer.Vehicle) ENDIF SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(Racer.Driver, TRUE) ENDIF ENDIF // Reset racer current gate. Racer.iGateCur = 0 // Check if racer vehicle is alive. IF NOT IS_ENTITY_DEAD(Racer.Vehicle) // Start racer vehicle engine, if needed. IF NOT IS_THIS_MODEL_A_BIKE(Racer.eVehicleModel) SET_VEHICLE_ENGINE_ON(Racer.Vehicle, TRUE, TRUE) ENDIF // Add stuck check for racer vehicle, if needed. // TODO: Make sure this isn't needed at all for stuck checks. //IF NOT DOES_VEHICLE_HAVE_STUCK_VEHICLE_CHECK(Racer.Vehicle) // ADD_VEHICLE_STUCK_CHECK(Racer.Vehicle, SPTT_VEH_STUCK_MIN_MOVE, SPTT_VEH_STUCK_CHK_TIME) //ENDIF ENDIF ENDPROC PROC SPTT_Racer_Finish(SPTT_RACER_STRUCT& Racer) //DEBUG_MESSAGE("SPTT_Racer_Finish") // Check if racer vehicle is alive. IF NOT IS_ENTITY_DEAD(Racer.Vehicle) IF SPTT_Master.eRaceType <> SPTT_RACE_TYPE_PLANE UnfreezePlayerVehicle() DEBUG_MESSAGE("Unfreezing Players pre-race vehicle") ENDIF // Remove stuck check for racer vehicle, if needed. // TODO: Make sure this isn't needed at all for stuck checks. //IF DOES_VEHICLE_HAVE_STUCK_VEHICLE_CHECK(Racer.Vehicle) // REMOVE_VEHICLE_STUCK_CHECK(Racer.Vehicle) //ENDIF ENDIF ENDPROC FUNC BOOL SPTT_Racer_Stuck_Check(SPTT_RACER_STRUCT& Racer) //DEBUG_MESSAGE("SPTT_Racer_Crash_Check") IF (Racer.eVehicleModel <> DUMMY_MODEL_FOR_SCRIPT) // TODO: Make sure this isn't needed at all for stuck checks. //IF DOES_VEHICLE_HAVE_STUCK_VEHICLE_CHECK(Racer.Vehicle) IF NOT IS_PLAYER_DEAD(PLAYER_ID()) IF IS_PED_IN_VEHICLE(PLAYER_PED_ID(), Racer.Vehicle) IF (GET_ENTITY_SPEED(Racer.Vehicle) <= 15.0) IF Racer.eVehicleModel = STUNT IF GET_ENTITY_HEIGHT_ABOVE_GROUND(Racer.Vehicle) < 3.0 OR HAS_ENTITY_COLLIDED_WITH_ANYTHING(Racer.Vehicle) IF IS_ENTITY_UPSIDEDOWN(Racer.Vehicle) AND GET_ENTITY_HEIGHT_ABOVE_GROUND(Racer.Vehicle) < 1.0 DEBUG_MESSAGE("we on the roof!") RETURN TRUE ENDIF IF IS_VEHICLE_STUCK_TIMER_UP(Racer.Vehicle, VEH_STUCK_ON_ROOF, SPTT_VEH_STUCK_PLANE_ROOF_TIME) DEBUG_MESSAGE("SPTT_Racer_Crash_Check: Vehicle stuck (roof)!") RETURN TRUE ENDIF IF IS_VEHICLE_STUCK_TIMER_UP(Racer.Vehicle, VEH_STUCK_ON_SIDE, SPTT_VEH_STUCK_PLANE_SIDE_TIME) DEBUG_MESSAGE("SPTT_Racer_Crash_Check: Vehicle stuck (side)!") RETURN TRUE ENDIF IF IS_VEHICLE_STUCK_TIMER_UP(Racer.Vehicle, VEH_STUCK_HUNG_UP, SPTT_VEH_STUCK_PLANE_HUNG_TIME) DEBUG_MESSAGE("SPTT_Racer_Crash_Check: Vehicle stuck (hung)!") RETURN TRUE ENDIF IF IS_VEHICLE_STUCK_TIMER_UP(Racer.Vehicle, VEH_STUCK_JAMMED, SPTT_VEH_STUCK_PLANE_JAM_TIME) DEBUG_MESSAGE("SPTT_Racer_Crash_Check: Vehicle stuck (jam)!") RETURN TRUE ENDIF ENDIF ENDIF ENDIF ENDIF ENDIF //ENDIF ENDIF RETURN FALSE ENDFUNC FUNC SPTT_RACE_GATE_STATUS SPTT_Racer_Gate_Check(SPTT_RACE_STRUCT& Race, SPTT_GATE_STRUCT& GateCur, SPTT_GATE_STRUCT& GateNxt, PED_INDEX pedDriver) VECTOR vFront, vSide, vUp, vPos #IF NOT DEFINED(bAudioPlayedLastGate) BOOL bAudioPlayedLastGate bAudioPlayedLastGate = bAudioPlayedLastGate #ENDIF IF IS_ENTITY_DEAD(Race.Racer[0].Vehicle) RETURN SPTT_RACE_GATE_STATUS_INVALID ENDIF SPTT_RACE_GATE_STATUS status = SPTT_Gate_Check_Pass(GateCur, pedDriver) IF (SPTT_Master.eRaceType = SPTT_RACE_TYPE_PLANE) IF (status <> SPTT_RACE_GATE_STATUS_INCOMPLETE) // INNER (PERFECT) RING CHECKS IF (status = SPTT_RACE_GATE_STATUS_PASS_INNER) // left roll IF SPTT_IS_PLANE_KNIFING_LEFT(Race.Racer[0].Vehicle) // Check if its a stunt gate IF GateCur.eStuntType <> SPTT_RACE_STUNT_GATE_NORMAL // check if its a KNIFE LEFT stunt gate IF GateCur.eStuntType = SPTT_RACE_STUNT_GATE_SIDE_LEFT // if left stunt gate, return successfull stunt status = SPTT_RACE_GATE_STATUS_STUNT_KL RETURN status ENDIF // check if its a KNIFE RIGHT stunt gate IF GateCur.eStuntType = SPTT_RACE_STUNT_GATE_SIDE_RIGHT // if right stunt gate, return hit status = SPTT_RACE_GATE_STATUS_STUNT_KR_HIT RETURN status ENDIF // check if its a INVERTED stunt gate IF GateCur.eStuntType = SPTT_RACE_STUNT_GATE_INVERTED // if inverted gate, return hit status = SPTT_RACE_GATE_STATUS_STUNT_INV_HIT RETURN status ENDIF ELSE // check bits status = SPTT_RACE_GATE_STATUS_KNIFE_INNER // new perfect Knife IF NOT IS_BITMASK_AS_ENUM_SET(iStuntGateHit, P_Knife_Once) // play audio Play_Gate_Audio("Gate_PK", iPerfKniGateBits) // clear then set audio tracking bit (done on all first hits to reset consecutives for all audio bits) iStuntGateHit = 0 SET_BITMASK_AS_ENUM(iStuntGateHit, P_Knife_Once) RETURN status ELSE // hit 2 perfect Knife in a row IF NOT IS_BITMASK_AS_ENUM_SET(iStuntGateHit, P_Knife_Twice) // consecutive audio Play_Gate_Audio("Con_PK", iPerfKniGateBits) SET_BITMASK_AS_ENUM(iStuntGateHit, P_Knife_Twice) RETURN status ELSE // hit 3 perfect Knife in a row IF NOT IS_BITMASK_AS_ENUM_SET(iStuntGateHit, P_Knife_Third) // consecutive audio Play_Gate_Audio("Con_PK", iPerfKniGateBits) SET_BITMASK_AS_ENUM(iStuntGateHit, P_Knife_Third) RETURN status ELSE // 4 or more perfect Knife in a row // consecutive audio Play_Gate_Audio("Con_PK", iPerfKniGateBits) RETURN status ENDIF ENDIF ENDIF ENDIF // right roll ELIF SPTT_IS_PLANE_KNIFING_RIGHT(Race.Racer[0].Vehicle) PRINTLN("SPTT_Racer_Gate_Check: plane is rolled right") // Check if its a stunt gate IF GateCur.eStuntType <> SPTT_RACE_STUNT_GATE_NORMAL // check if its a KNIFE RIGHT stunt gate IF GateCur.eStuntType = SPTT_RACE_STUNT_GATE_SIDE_RIGHT // if right stunt gate, return successfull stunt status = SPTT_RACE_GATE_STATUS_STUNT_KR RETURN status ENDIF // check if its a KNIFE LEFT stunt gate IF GateCur.eStuntType = SPTT_RACE_STUNT_GATE_SIDE_LEFT // if left stunt gate, return hit status = SPTT_RACE_GATE_STATUS_STUNT_KL_HIT RETURN status ENDIF // check if its a INVERTED stunt gate IF GateCur.eStuntType = SPTT_RACE_STUNT_GATE_INVERTED // if inverted gate, return hit status = SPTT_RACE_GATE_STATUS_STUNT_INV_HIT RETURN status ENDIF ELSE status = SPTT_RACE_GATE_STATUS_KNIFE_INNER // new perfect Knife IF NOT IS_BITMASK_AS_ENUM_SET(iStuntGateHit, P_Knife_Once) // play audio Play_Gate_Audio("Gate_PK", iPerfKniGateBits) // clear then set audio tracking bit (done on all first hits to reset consecutives for all audio bits) iStuntGateHit = 0 SET_BITMASK_AS_ENUM(iStuntGateHit, P_Knife_Once) RETURN status ELSE // hit 2 perfect Knife in a row IF NOT IS_BITMASK_AS_ENUM_SET(iStuntGateHit, P_Knife_Twice) // consecutive audio Play_Gate_Audio("Con_PK", iPerfKniGateBits) SET_BITMASK_AS_ENUM(iStuntGateHit, P_Knife_Twice) RETURN status ELSE // hit 3 perfect Knife in a row IF NOT IS_BITMASK_AS_ENUM_SET(iStuntGateHit, P_Knife_Third) // consecutive audio Play_Gate_Audio("Con_PK", iPerfKniGateBits) SET_BITMASK_AS_ENUM(iStuntGateHit, P_Knife_Third) RETURN status ELSE // 4 or more perfect Knife in a row // consecutive audio Play_Gate_Audio("Con_PK", iPerfKniGateBits) RETURN status ENDIF ENDIF ENDIF ENDIF // Inverted ELSE GET_ENTITY_MATRIX(Race.Racer[0].Vehicle, vFront, vSide, vUp, vPos) IF vUp.z <= SPTT_STUNT_INVERT_THRESHOLD // Check if its a stunt gate IF GateCur.eStuntType <> SPTT_RACE_STUNT_GATE_NORMAL // check if its a INVERTED stunt gate IF GateCur.eStuntType = SPTT_RACE_STUNT_GATE_INVERTED // if inverted stunt gate, return successfull stunt status = SPTT_RACE_GATE_STATUS_STUNT_INV RETURN status ENDIF // check if its a KNIFE LEFT stunt gate IF GateCur.eStuntType = SPTT_RACE_STUNT_GATE_SIDE_LEFT // if left stunt gate, return hit status = SPTT_RACE_GATE_STATUS_STUNT_KL_HIT RETURN status ENDIF // check if its a KNIFE RIGHT stunt gate IF GateCur.eStuntType = SPTT_RACE_STUNT_GATE_SIDE_RIGHT // if right stunt gate, return hit status = SPTT_RACE_GATE_STATUS_STUNT_KR_HIT RETURN status ENDIF ELSE // check bits status = SPTT_RACE_GATE_STATUS_INVERT_INNER // new perfect Inverted IF NOT IS_BITMASK_AS_ENUM_SET(iStuntGateHit, P_Inverted_Once) // play audio Play_Gate_Audio("Gate_PI", iPerfInvGateBits) // clear then set audio tracking bit (done on all first hits to reset consecutives for all audio bits) iStuntGateHit = 0 SET_BITMASK_AS_ENUM(iStuntGateHit, P_Inverted_Once) RETURN status ELSE // hit 2 perfect Inverted in a row IF NOT IS_BITMASK_AS_ENUM_SET(iStuntGateHit, P_Inverted_Twice) // consecutive audio Play_Gate_Audio("Con_PI", iPerfInvGateBits) SET_BITMASK_AS_ENUM(iStuntGateHit, P_Inverted_Twice) RETURN status ELSE // hit 3 perfect Inverted in a row IF NOT IS_BITMASK_AS_ENUM_SET(iStuntGateHit, P_Inverted_Third) // consecutive audio Play_Gate_Audio("Con_PI", iPerfInvGateBits) SET_BITMASK_AS_ENUM(iStuntGateHit, P_Inverted_Third) RETURN status ELSE // 4 or more perfect Inverted in a row // consecutive audio Play_Gate_Audio("Con_PI", iPerfInvGateBits) RETURN status ENDIF ENDIF ENDIF ENDIF ELSE // Flew through gate normally // if its a stunt gate IF GateCur.eStuntType <> SPTT_RACE_STUNT_GATE_NORMAL IF GateCur.eStuntType = SPTT_RACE_STUNT_GATE_SIDE_LEFT status = SPTT_RACE_GATE_STATUS_STUNT_KL_HIT RETURN status ELIF GateCur.eStuntType = SPTT_RACE_STUNT_GATE_SIDE_RIGHT status = SPTT_RACE_GATE_STATUS_STUNT_KR_HIT RETURN status ELIF GateCur.eStuntType = SPTT_RACE_STUNT_GATE_INVERTED status = SPTT_RACE_GATE_STATUS_STUNT_INV_HIT RETURN status ENDIF ELSE status = SPTT_RACE_GATE_STATUS_PASS_INNER // new perfect Knife IF NOT IS_BITMASK_AS_ENUM_SET(iStuntGateHit, Perfect_Once) // play audio Play_Gate_Audio("Get_Perf", iPerfectGateBits) // clear then set audio tracking bit (done on all first hits to reset consecutives for all audio bits) iStuntGateHit = 0 SET_BITMASK_AS_ENUM(iStuntGateHit, Perfect_Once) RETURN status ELSE // hit 2 perfect in a row IF NOT IS_BITMASK_AS_ENUM_SET(iStuntGateHit, Perfect_Twice) // consecutive audio Play_Gate_Audio("Con_Perf", iPerfectGateBits) SET_BITMASK_AS_ENUM(iStuntGateHit, Perfect_Twice) RETURN status ELSE // hit 3 perfect in a row IF NOT IS_BITMASK_AS_ENUM_SET(iStuntGateHit, Perfect_Third) // consecutive audio Play_Gate_Audio("Con_Perf", iPerfectGateBits) SET_BITMASK_AS_ENUM(iStuntGateHit, Perfect_Third) RETURN status ELSE // 4 or more perfect in a row // consecutive audio Play_Gate_Audio("Con_Perf", iPerfectGateBits) RETURN status ENDIF ENDIF ENDIF ENDIF ENDIF ENDIF ENDIF // OUTTER RING CHECKS IF (status = SPTT_RACE_GATE_STATUS_PASS_OUTTER) // knife left check IF SPTT_IS_PLANE_KNIFING_LEFT(Race.Racer[0].Vehicle) // Check if its a stunt gate IF GateCur.eStuntType <> SPTT_RACE_STUNT_GATE_NORMAL // check if its a KNIFE LEFT stunt gate IF GateCur.eStuntType = SPTT_RACE_STUNT_GATE_SIDE_LEFT // if left stunt gate, return successfull stunt status = SPTT_RACE_GATE_STATUS_STUNT_KL RETURN status ENDIF // check if its a KNIFE RIGHT stunt gate IF GateCur.eStuntType = SPTT_RACE_STUNT_GATE_SIDE_RIGHT // if right stunt gate, return hit status = SPTT_RACE_GATE_STATUS_STUNT_KR_HIT RETURN status ENDIF // check if its a INVERTED stunt gate IF GateCur.eStuntType = SPTT_RACE_STUNT_GATE_INVERTED // if inverted gate, return hit status = SPTT_RACE_GATE_STATUS_STUNT_INV_HIT RETURN status ENDIF ELSE // check bits status = SPTT_RACE_GATE_STATUS_KNIFE_OUTTER // new knife IF NOT IS_BITMASK_AS_ENUM_SET(iStuntGateHit, Knife_Once) // play audio Play_Gate_Audio("Gate_Kni", iKnifeGateBits) // clear then set audio tracking bit (done on all first hits to reset consecutives for all audio bits) iStuntGateHit = 0 SET_BITMASK_AS_ENUM(iStuntGateHit, Knife_Once) RETURN status ELSE // hit 2 Knife in a row IF NOT IS_BITMASK_AS_ENUM_SET(iStuntGateHit, Knife_Twice) // consecutive audio Play_Gate_Audio("Con_Kni", iKnifeGateBits) SET_BITMASK_AS_ENUM(iStuntGateHit, Knife_Twice) RETURN status ELSE // hit 3 Knife in a row IF NOT IS_BITMASK_AS_ENUM_SET(iStuntGateHit, Knife_Third) // consecutive audio Play_Gate_Audio("Con_Kni", iKnifeGateBits) SET_BITMASK_AS_ENUM(iStuntGateHit, Knife_Third) RETURN status ELSE // 4 or more Knife in a row // consecutive audio Play_Gate_Audio("Con_Kni", iKnifeGateBits) RETURN status ENDIF ENDIF ENDIF ENDIF ELIF SPTT_IS_PLANE_KNIFING_RIGHT(Race.Racer[0].Vehicle) // Check if its a stunt gate IF GateCur.eStuntType <> SPTT_RACE_STUNT_GATE_NORMAL // check if its a KNIFE RIGHT stunt gate IF GateCur.eStuntType = SPTT_RACE_STUNT_GATE_SIDE_RIGHT // if right stunt gate, return successfull stunt status = SPTT_RACE_GATE_STATUS_STUNT_KR RETURN status ENDIF // check if its a KNIFE LEFT stunt gate IF GateCur.eStuntType = SPTT_RACE_STUNT_GATE_SIDE_LEFT // if left stunt gate, return hit status = SPTT_RACE_GATE_STATUS_STUNT_KL_HIT RETURN status ENDIF // check if its a INVERTED stunt gate IF GateCur.eStuntType = SPTT_RACE_STUNT_GATE_INVERTED // if inverted gate, return hit status = SPTT_RACE_GATE_STATUS_STUNT_INV_HIT RETURN status ENDIF ELSE // check bits status = SPTT_RACE_GATE_STATUS_KNIFE_OUTTER // new knife IF NOT IS_BITMASK_AS_ENUM_SET(iStuntGateHit, Knife_Once) // play audio Play_Gate_Audio("Gate_Kni", iKnifeGateBits) // clear then set audio tracking bit (done on all first hits to reset consecutives for all audio bits) iStuntGateHit = 0 SET_BITMASK_AS_ENUM(iStuntGateHit, Knife_Once) RETURN status ELSE // hit 2 Knife in a row IF NOT IS_BITMASK_AS_ENUM_SET(iStuntGateHit, Knife_Twice) // consecutive audio Play_Gate_Audio("Con_Kni", iKnifeGateBits) SET_BITMASK_AS_ENUM(iStuntGateHit, Knife_Twice) RETURN status ELSE // hit 3 Knife in a row IF NOT IS_BITMASK_AS_ENUM_SET(iStuntGateHit, Knife_Third) // consecutive audio Play_Gate_Audio("Con_Kni", iKnifeGateBits) SET_BITMASK_AS_ENUM(iStuntGateHit, Knife_Third) RETURN status ELSE // 4 or more Knife in a row // consecutive audio Play_Gate_Audio("Con_Kni", iKnifeGateBits) RETURN status ENDIF ENDIF ENDIF ENDIF ELSE GET_ENTITY_MATRIX(Race.Racer[0].Vehicle, vFront, vSide, vUp, vPos) IF vUp.z <= SPTT_STUNT_INVERT_THRESHOLD // Check if its a stunt gate IF GateCur.eStuntType <> SPTT_RACE_STUNT_GATE_NORMAL // check if its a INVERTED stunt gate IF GateCur.eStuntType = SPTT_RACE_STUNT_GATE_INVERTED // if inverted gate, return successful stunt status = SPTT_RACE_GATE_STATUS_STUNT_INV RETURN status ENDIF // check if its a KNIFE LEFT stunt gate IF GateCur.eStuntType = SPTT_RACE_STUNT_GATE_SIDE_LEFT // if left stunt gate, return successfull stunt status = SPTT_RACE_GATE_STATUS_STUNT_KL RETURN status ENDIF // check if its a KNIFE RIGHT stunt gate IF GateCur.eStuntType = SPTT_RACE_STUNT_GATE_SIDE_RIGHT // if right stunt gate, return hit status = SPTT_RACE_GATE_STATUS_STUNT_KR_HIT RETURN status ENDIF ELSE // check bits status = SPTT_RACE_GATE_STATUS_INVERT_OUTTER // new Inverted IF NOT IS_BITMASK_AS_ENUM_SET(iStuntGateHit, Inverted_Once) // play audio Play_Gate_Audio("Gate_Inv", iInvertedGateBits) // clear then set audio tracking bit (done on all first hits to reset consecutives for all audio bits) iStuntGateHit = 0 SET_BITMASK_AS_ENUM(iStuntGateHit, Inverted_Once) RETURN status ELSE // hit 2 Inverted in a row IF NOT IS_BITMASK_AS_ENUM_SET(iStuntGateHit, Inverted_Twice) // consecutive audio Play_Gate_Audio("Con_Inv", iInvertedGateBits) // set audio tracking bit SET_BITMASK_AS_ENUM(iStuntGateHit, Inverted_Twice) RETURN status ELSE // Hit 3 Inverted in a row IF NOT IS_BITMASK_AS_ENUM_SET(iStuntGateHit, Inverted_Third) // consecutive audio Play_Gate_Audio("Con_Inv", iInvertedGateBits) SET_BITMASK_AS_ENUM(iStuntGateHit, Inverted_Third) RETURN status ELSE // hit 4 or more Inverted in a row // consecutive audio Play_Gate_Audio("Con_Inv", iInvertedGateBits) RETURN status ENDIF ENDIF ENDIF ENDIF ELSE // if its a stunt gate IF GateCur.eStuntType <> SPTT_RACE_STUNT_GATE_NORMAL IF GateCur.eStuntType = SPTT_RACE_STUNT_GATE_SIDE_LEFT status = SPTT_RACE_GATE_STATUS_STUNT_KL_HIT RETURN status ELIF GateCur.eStuntType = SPTT_RACE_STUNT_GATE_SIDE_RIGHT status = SPTT_RACE_GATE_STATUS_STUNT_KR_HIT RETURN status ELIF GateCur.eStuntType = SPTT_RACE_STUNT_GATE_INVERTED status = SPTT_RACE_GATE_STATUS_STUNT_INV_HIT RETURN status ENDIF ELSE // check bits status = SPTT_RACE_GATE_STATUS_PASS_OUTTER // New Gate Hit IF NOT IS_BITMASK_AS_ENUM_SET(iStuntGateHit, Hit_Once) // play audio Play_Gate_Audio("Gate_Hit", iClearedGateBits) // clear then set audio tracking bit (done on all first hits to reset consecutives for all audio bits) iStuntGateHit = 0 SET_BITMASK_AS_ENUM(iStuntGateHit, Hit_Once) RETURN status ELSE // hit 2 Gates in a row IF NOT IS_BITMASK_AS_ENUM_SET(iStuntGateHit, Hit_Twice) // consecutive audio Play_Gate_Audio("Con_Hit", iClearedGateBits) SET_BITMASK_AS_ENUM(iStuntGateHit, Hit_Twice) RETURN status ELSE // hit 3 Gates in a row IF NOT IS_BITMASK_AS_ENUM_SET(iStuntGateHit, Hit_Third) // consecutive audio Play_Gate_Audio("Con_Hit", iClearedGateBits) SET_BITMASK_AS_ENUM(iStuntGateHit, Hit_Third) RETURN status ELSE // Hit 4 or more Gates in a row // consecutive audio Play_Gate_Audio("Con_Hit", iClearedGateBits) RETURN status ENDIF ENDIF ENDIF ENDIF ENDIF ENDIF ENDIF IF SPTT_Gate_Check_Miss(GateCur, GateNxt, pedDriver) // Check if its a stunt gate IF GateCur.eStuntType <> SPTT_RACE_STUNT_GATE_NORMAL // check if its a knife left stunt gate IF GateCur.eStuntType = SPTT_RACE_STUNT_GATE_SIDE_LEFT // missed the knife left stunt gate status = SPTT_RACE_GATE_STATUS_STUNT_KL_MISS RETURN status ENDIF // check if its a knife right stunt gate IF GateCur.eStuntType = SPTT_RACE_STUNT_GATE_SIDE_RIGHT // missed the knife right stunt gate status = SPTT_RACE_GATE_STATUS_STUNT_KR_MISS RETURN status ENDIF // check if its a INVERTED stunt gate IF GateCur.eStuntType = SPTT_RACE_STUNT_GATE_INVERTED // if inverted stunt gate, return successfull stunt status = SPTT_RACE_GATE_STATUS_STUNT_INV_MISS RETURN status ENDIF ELSE status = SPTT_RACE_GATE_STATUS_MISSED_GATE // new Missed Gate IF NOT IS_BITMASK_AS_ENUM_SET(iStuntGateHit, Missed_Once) // play audio Play_Gate_Audio("Gate_Miss", iMissedGateBits) // clear then set audio tracking bit (done on all first hits to reset consecutives for all audio bits) iStuntGateHit = 0 SET_BITMASK_AS_ENUM(iStuntGateHit, Missed_Once) RETURN status ELSE // Missed 2 Gates in a row IF NOT IS_BITMASK_AS_ENUM_SET(iStuntGateHit, Missed_Twice) // consecutive audio Play_Gate_Audio("Con_Miss", iMissedGateBits) SET_BITMASK_AS_ENUM(iStuntGateHit, Missed_Twice) RETURN status ELSE // Missed 3 Gates in a row IF NOT IS_BITMASK_AS_ENUM_SET(iStuntGateHit, Missed_Third) // consecutive audio Play_Gate_Audio("Con_Miss", iMissedGateBits) SET_BITMASK_AS_ENUM(iStuntGateHit, Missed_Third) RETURN status ELSE // Missed 4 or more Gates in a row // consecutive audio Play_Gate_Audio("Con_Miss", iMissedGateBits) RETURN status ENDIF ENDIF ENDIF ENDIF ENDIF RETURN status ENDIF IF SPTT_Gate_Check_Miss(GateCur, GateNxt, pedDriver) // Check if its a stunt gate IF GateCur.eStuntType <> SPTT_RACE_STUNT_GATE_NORMAL // check if its a knife left stunt gate IF GateCur.eStuntType = SPTT_RACE_STUNT_GATE_SIDE_LEFT // missed the knife left stunt gate status = SPTT_RACE_GATE_STATUS_STUNT_KL_MISS RETURN status ENDIF // check if its a knife right stunt gate IF GateCur.eStuntType = SPTT_RACE_STUNT_GATE_SIDE_RIGHT // missed the knife right stunt gate status = SPTT_RACE_GATE_STATUS_STUNT_KR_MISS RETURN status ENDIF // check if its a INVERTED stunt gate IF GateCur.eStuntType = SPTT_RACE_STUNT_GATE_INVERTED // if inverted stunt gate, return successfull stunt status = SPTT_RACE_GATE_STATUS_STUNT_INV_MISS RETURN status ENDIF ELSE // check bits status = SPTT_RACE_GATE_STATUS_MISSED_GATE // new Missed Gate IF NOT IS_BITMASK_AS_ENUM_SET(iStuntGateHit, Missed_Once) // play audio Play_Gate_Audio("Gate_Miss", iMissedGateBits) // clear then set audio tracking bit (done on all first hits to reset consecutives for all audio bits) iStuntGateHit = 0 SET_BITMASK_AS_ENUM(iStuntGateHit, Missed_Once) RETURN status ELSE // Missed 2 Gates in a row IF NOT IS_BITMASK_AS_ENUM_SET(iStuntGateHit, Missed_Twice) // consecutive audio Play_Gate_Audio("Con_Miss", iMissedGateBits) SET_BITMASK_AS_ENUM(iStuntGateHit, Missed_Twice) RETURN status ELSE // Missed 3 Gates in a row IF NOT IS_BITMASK_AS_ENUM_SET(iStuntGateHit, Missed_Third) // consecutive audio Play_Gate_Audio("Con_Miss", iMissedGateBits) SET_BITMASK_AS_ENUM(iStuntGateHit, Missed_Third) RETURN status ELSE // Missed 4 or more Gates in a row // consecutive audio Play_Gate_Audio("Con_Miss", iMissedGateBits) RETURN status ENDIF ENDIF ENDIF ENDIF RETURN status ENDIF ELIF status != SPTT_RACE_GATE_STATUS_INCOMPLETE RETURN status ENDIF RETURN SPTT_RACE_GATE_STATUS_INVALID ENDFUNC // END OF FILE! DO NOT ADD ANYTHING BELOW THIS LINE!