// ***************************************************************************************** // ***************************************************************************************** // ***************************************************************************************** // // SCRIPT NAME : TRI_Racer.sch // AUTHOR : Nicholas Zippmann // DESCRIPTION : Single Player Races - Racer procs/functions file // // ***************************************************************************************** // ***************************************************************************************** // ***************************************************************************************** USING "TRI_Head.sch" USING "TRI_Helpers.sch" USING "TRI_Gate.sch" USING "chase_hint_cam.sch" USING "stunt_plane_public.sch" // ----------------------------------- // SETUP PROCS/FUNCTIONS // ----------------------------------- // bits for dialogue // tracks how many consecutive gates weve hit 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(TRI_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 TRI_Racer_Init(TRI_RACER_STRUCT& Racer) //DEBUG_MESSAGE("TRI_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 = TRI_RACER_RESET_WAIT Racer.vStartPos = TRI_Master.vDefRcrPos Racer.fStartHead = TRI_Master.fDefRcrHead Racer.eDriverType = TRI_Master.eDefDrvType Racer.eDriverModel = TRI_Master.eDefDrvModel Racer.eVehicleModel = TRI_Master.eDefVehModel ENDPROC PROC TRI_Racer_Setup_Misc(TRI_RACER_STRUCT& Racer) //DEBUG_MESSAGE("TRI_Racer_Setup_Misc") Racer.Blip = NULL Racer.iGateCur = -1 Racer.iRank = 0 Racer.fClockTime = 0.0 Racer.eReset = TRI_RACER_RESET_WAIT ENDPROC PROC TRI_Racer_Setup_Name(TRI_RACER_STRUCT& Racer, STRING sName) //DEBUG_MESSAGE("TRI_Racer_Setup_Name") Racer.szName = sName ENDPROC PROC TRI_Racer_Setup_Entities(TRI_RACER_STRUCT& Racer, PED_INDEX Driver, VEHICLE_INDEX Vehicle) //DEBUG_MESSAGE("TRI_Racer_Setup_Entities") Racer.Driver = Driver Racer.Vehicle = Vehicle ENDPROC PROC TRI_Racer_Setup_Start(TRI_RACER_STRUCT& Racer, VECTOR vStartPos, FLOAT fStartHead) //DEBUG_MESSAGE("TRI_Racer_Setup_Start") Racer.vStartPos = vStartPos Racer.fStartHead = fStartHead ENDPROC PROC TRI_Racer_Setup_Types(TRI_RACER_STRUCT& Racer, PED_TYPE eDriverType, MODEL_NAMES eDriverModel, MODEL_NAMES eVehicleModel) //DEBUG_MESSAGE("TRI_Racer_Setup_Types") Racer.eDriverType = eDriverType Racer.eDriverModel = eDriverModel Racer.eVehicleModel = eVehicleModel ENDPROC // ----------------------------------- // DRIVER CREATION PROCS/FUNCTIONS // ----------------------------------- PROC TRI_Racer_Driver_Request(TRI_RACER_STRUCT& Racer) //DEBUG_MESSAGE("TRI_Racer_Driver_Request") IF (Racer.eDriverModel = DUMMY_MODEL_FOR_SCRIPT) SCRIPT_ASSERT("TRI_Racer_Driver_Request: Model invalid!") EXIT ENDIF REQUEST_MODEL(Racer.eDriverModel) ENDPROC FUNC BOOL TRI_Racer_Driver_Stream(TRI_RACER_STRUCT& Racer) //DEBUG_MESSAGE("TRI_Racer_Driver_Stream") IF (Racer.eDriverModel = DUMMY_MODEL_FOR_SCRIPT) SCRIPT_ASSERT("TRI_Racer_Driver_Stream: Model invalid!") RETURN FALSE ENDIF RETURN HAS_MODEL_LOADED(Racer.eDriverModel) ENDFUNC PROC TRI_Racer_Driver_Evict(TRI_RACER_STRUCT& Racer) //DEBUG_MESSAGE("TRI_Racer_Driver_Evict") IF (Racer.eDriverModel = DUMMY_MODEL_FOR_SCRIPT) SCRIPT_ASSERT("TRI_Racer_Driver_Evict: Model invalid!") EXIT ENDIF SET_MODEL_AS_NO_LONGER_NEEDED(Racer.eDriverModel) ENDPROC FUNC BOOL TRI_Racer_Driver_Create(TRI_RACER_STRUCT& Racer) DEBUG_MESSAGE("TRI_Racer_Driver_Create") // Check if driver model is valid before continuing. IF (Racer.eDriverModel = DUMMY_MODEL_FOR_SCRIPT) SCRIPT_ASSERT("TRI_Racer_Driver_Create: Model invalid!") RETURN FALSE ENDIF // Check if driver already exists. IF NOT IS_ENTITY_DEAD(Racer.Driver) // Set driver health to max. SET_ENTITY_HEALTH(Racer.Driver, 1000) // If vehicle also exists, put driver in it, if needed. IF NOT IS_ENTITY_DEAD(Racer.Vehicle) //DEBUG_MESSAGE("TRI_Racer_Driver_Create: Tele Veh") IF NOT IS_PED_SITTING_IN_VEHICLE(Racer.Driver, Racer.Vehicle) SET_PED_INTO_VEHICLE(Racer.Driver, Racer.Vehicle) ENDIF // Otherwise, vehicle doesn't exist, teleport driver to start. ELSE //DEBUG_MESSAGE("TRI_Racer_Driver_Create: Teleport") SET_ENTITY_COORDS(Racer.Driver, Racer.vStartPos) SET_ENTITY_HEADING(Racer.Driver, Racer.fStartHead) ENDIF // Otherwise, if vehicle exists, create driver inside it and check for validity. ELIF NOT IS_ENTITY_DEAD(Racer.Vehicle) //DEBUG_MESSAGE("TRI_Racer_Driver_Create: Create In Vehicle") Racer.Driver = CREATE_PED_INSIDE_VEHICLE(Racer.Vehicle, Racer.eDriverType, Racer.eDriverModel) IF IS_ENTITY_DEAD(Racer.Driver) DEBUG_MESSAGE("TRI_Racer_Driver_Create: Failed to create driver in vehicle!") RETURN FALSE ENDIF // Otherwise, vehicle doesn't exist, just create driver normally and check for validity. ELSE //DEBUG_MESSAGE("TRI_Racer_Driver_Create: Create On Foot") Racer.Driver = CREATE_PED(Racer.eDriverType, Racer.eDriverModel, Racer.vStartPos, Racer.fStartHead) IF IS_ENTITY_DEAD(Racer.Driver) DEBUG_MESSAGE("TRI_Racer_Driver_Create: Failed to create driver on foot!") RETURN FALSE ENDIF SET_PED_LEG_IK_MODE(Racer.Driver, LEG_IK_PARTIAL) SET_PED_STEERS_AROUND_OBJECTS(Racer.Driver, FALSE) CPRINTLN(DEBUG_TRIATHLON, "SET_PED_LEG_IK_MODE(Racer.Driver, LEG_IK_PARTIAL) called") ENDIF // Check if driver type is player. IF (Racer.eDriverType <= PEDTYPE_PLAYER_UNUSED) // TODO: Put player driver logic here... // Otherwise, driver type isn't player. ELSE // 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 IF NOT IS_ENTITY_DEAD(Racer.Driver) IF ORR_DOES_RACE_REQUIRE_MOTORCYCLE() SET_PED_HELMET(Racer.Driver, TRUE) GIVE_PED_HELMET(Racer.Driver, TRUE) ENDIF ENDIF // Racer driver successfully created. RETURN TRUE ENDFUNC /// PURPOSE: /// In Triathlon, reset the player's health. PROC TRI_Racer_TriRacer_Create(TRI_RACER_STRUCT& Racer) CPRINTLN(DEBUG_TRIATHLON, "[TRI_Racer.sch->TRI_Racer_TriRacer_Create] Procedure started.") // Check if driver already exists. IF NOT IS_ENTITY_DEAD(Racer.Driver) CPRINTLN(DEBUG_TRIATHLON, "[TRI_Racer.sch->TRI_Racer_TriRacer_Create] Setting driver to full health.") SET_ENTITY_HEALTH(Racer.Driver, 1000) ENDIF ENDPROC /// PURPOSE: /// In Triathlon, place the recreated player after resetting. PROC TRI_Racer_TriRacer_Place(TRI_RACE_STRUCT& Race, TRI_RACER_STRUCT& Racer) VECTOR vFwd // Check if the current gate is the first one. IF Racer.iGateCur > 0 VECTOR vProbeStartPosition //10m above the gate so we can probe VECTOR vProbeEndPosition //10m below the gate so we can probe VECTOR vNewPlayerPosition //the pos we'll be setting the player to // If not, warp the bike to the start of the checkpoint previous to the current. PRINTLN("Gate position is... ", Race.sGate[Racer.iGateCur - 1].vPos) //Setup our test vectors, and the player coords vProbeStartPosition = Race.sGate[Racer.iGateCur - 1].vPos vProbeEndPosition = Race.sGate[Racer.iGateCur - 1].vPos vNewPlayerPosition = Race.sGate[Racer.iGateCur - 1].vPos vProbeStartPosition.z += 10 vProbeEndPosition.z -= 10 PRINTLN("Adding 10 to the z for the start probe... ", vProbeStartPosition) PRINTLN("Subtracting 10 to the z for the end probe... ", vProbeEndPosition) PRINTLN("Probing for water... ") IF TEST_PROBE_AGAINST_WATER(vProbeStartPosition, vProbeEndPosition, vNewPlayerPosition) PRINTLN("Found a water intersection! Setting new player position... ", vNewPlayerPosition) vNewPlayerPosition.z += TRI_WATER_RESET_OFFSET SET_ENTITY_COORDS(Racer.Driver, vNewPlayerPosition) ELSE PRINTLN("No water detected. Probing ground...") IF GET_GROUND_Z_FOR_3D_COORD(vProbeStartPosition, vNewPlayerPosition.z) PRINTLN("Found a ground z so setting the player here...", vNewPlayerPosition) SET_ENTITY_COORDS(Racer.Driver, vNewPlayerPosition) ELSE PRINTLN("No ground coord so setting player here...", vNewPlayerPosition) SET_ENTITY_COORDS(Racer.Driver, vNewPlayerPosition) ENDIF ENDIF // Get the vector between the previous and current checkpoint, to use as the driver's heading. vFwd = Race.sGate[Racer.iGateCur].vPos - Race.sGate[Racer.iGateCur - 1].vPos ELSE // Warp the player to the start position. SET_ENTITY_COORDS(Racer.Driver, Racer.vStartPos) // Get the vector between the starting position, and the current checkpoint, to use as the driver's heading. vFwd = Race.sGate[Racer.iGateCur].vPos - Racer.vStartPos ENDIF // Set its heading towards the current checkpoint. IF NOT IS_ENTITY_DEAD(Racer.Driver) FLOAT fPlayerHeading fPlayerHeading = GET_HEADING_FROM_VECTOR_2D(vFwd.x, vFwd.y) SET_ENTITY_HEADING(Racer.Driver, fPlayerHeading) ENDIF ENDPROC PROC TRI_Racer_Driver_Freeze(TRI_RACER_STRUCT& Racer) //DEBUG_MESSAGE("TRI_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 TRI_Racer_Driver_UnFreeze(TRI_RACER_STRUCT& Racer) //DEBUG_MESSAGE("TRI_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 TRI_Racer_Driver_Release(TRI_RACER_STRUCT& Racer) //DEBUG_MESSAGE("TRI_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 TRI_Racer_Driver_Destroy(TRI_RACER_STRUCT& Racer) //DEBUG_MESSAGE("TRI_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 TRI_Racer_Vehicle_Request(TRI_RACER_STRUCT& Racer) //DEBUG_MESSAGE("TRI_Racer_Vehicle_Request") IF (Racer.eVehicleModel = DUMMY_MODEL_FOR_SCRIPT) DEBUG_MESSAGE("TRI_Racer_Vehicle_Request: Model invalid!") EXIT ENDIF REQUEST_MODEL(Racer.eVehicleModel) ENDPROC FUNC BOOL TRI_Racer_Vehicle_Stream(TRI_RACER_STRUCT& Racer) //DEBUG_MESSAGE("TRI_Racer_Vehicle_Stream") IF (Racer.eVehicleModel = DUMMY_MODEL_FOR_SCRIPT) DEBUG_MESSAGE("TRI_Racer_Vehicle_Stream: Model invalid!") RETURN TRUE ENDIF RETURN HAS_MODEL_LOADED(Racer.eVehicleModel) ENDFUNC PROC TRI_Racer_Vehicle_Evict(TRI_RACER_STRUCT& Racer) //DEBUG_MESSAGE("TRI_Racer_Vehicle_Evict") IF (Racer.eVehicleModel = DUMMY_MODEL_FOR_SCRIPT) DEBUG_MESSAGE("TRI_Racer_Vehicle_Evict: Model invalid!") EXIT ENDIF SET_MODEL_AS_NO_LONGER_NEEDED(Racer.eVehicleModel) ENDPROC FUNC BOOL TRI_Racer_Vehicle_Create(TRI_RACER_STRUCT& Racer, BOOL bForceCreate) DEBUG_MESSAGE("TRI_Racer_Vehicle_Create called.") // If forcing a create and vehicle already exists, destroy it. IF bForceCreate DEBUG_MESSAGE("Inside force create vehicle") IF TRI_Master.eRaceType = TRI_RACE_TYPE_PLANE IF DOES_ENTITY_EXIST(Racer.Vehicle) IF NOT IS_ENTITY_DEAD(Racer.Vehicle) OR NOT IS_VEHICLE_DRIVEABLE(Racer.Vehicle) IF IS_PED_IN_VEHICLE(Racer.Driver, Racer.Vehicle) CLEAR_PED_TASKS_IMMEDIATELY(Racer.Driver) DELETE_VEHICLE(Racer.Vehicle) DEBUG_MESSAGE("TRI_Racer_Vehicle_Create: Force deleted Stunt plane") ENDIF ELSE IF IS_PED_IN_VEHICLE(Racer.Driver, Racer.Vehicle) SET_ENTITY_COORDS(Racer.Driver, Racer.vStartPos) ENDIF IF IS_PED_IN_VEHICLE(Racer.Driver, Racer.Vehicle) DEBUG_MESSAGE("TRI_Racer_Vehicle_Create: Driver still in Vehicle, not deleting vehicle") ELSE DELETE_VEHICLE(Racer.Vehicle) ENDIF ENDIF ENDIF ELSE IF DOES_ENTITY_EXIST(Racer.Vehicle) IF NOT IS_ENTITY_DEAD(Racer.Driver) AND NOT IS_ENTITY_DEAD(Racer.Vehicle) IF IS_PED_IN_VEHICLE(Racer.Driver, Racer.Vehicle) CLEAR_PED_TASKS_IMMEDIATELY(Racer.Driver) ENDIF ENDIF IF IS_PED_IN_ANY_VEHICLE(Racer.Driver) VEHICLE_INDEX iVehicle = GET_VEHICLE_PED_IS_IN(Racer.Driver) IF IS_ENTITY_A_MISSION_ENTITY(iVehicle) DELETE_VEHICLE(iVehicle) DEBUG_MESSAGE("Deleted the Racer.Vehicle inside force create vehicle") ENDIF ENDIF ENDIF ENDIF ENDIF // If vehicle already exists, set health to max and teleport it. IF NOT IS_ENTITY_DEAD(Racer.Vehicle) //IF (TRI_Master.eRaceType = TRI_RACE_TYPE_PLANE) - removing for 162891 DEBUG_MESSAGE("TRI_Racer_Vehicle_Create: Teleport") SET_ENTITY_HEALTH(Racer.Vehicle, 1000) SET_VEHICLE_FIXED(Racer.Vehicle) SET_VEHICLE_ENGINE_HEALTH(Racer.Vehicle, 1000.0) SET_ENTITY_COORDS(Racer.Vehicle, Racer.vStartPos) //Racer.vStartPos) SET_ENTITY_HEADING(Racer.Vehicle, Racer.fStartHead) IF (TRI_Master.eRaceType = TRI_RACE_TYPE_PLANE) SET_VEHICLE_ENGINE_ON(Racer.Vehicle, TRUE, TRUE) SET_HELI_BLADES_FULL_SPEED(Racer.Vehicle) ENDIF //ENDIF // Otherwise, vehicle doesn't exist, create it and check for validity. ELSE DEBUG_MESSAGE("TRI_Racer_Vehicle_Create: Create New Vehicle") IF (Racer.eVehicleModel = DUMMY_MODEL_FOR_SCRIPT) DEBUG_MESSAGE("TRI_Racer_Create: No vehicle to create!") RETURN TRUE ENDIF IF IS_ENTITY_DEAD(Racer.Vehicle) DEBUG_MESSAGE("TRI_Racer_Create: Failed to create vehicle!") RETURN FALSE ENDIF ENDIF IF (TRI_Master.eRaceType <> TRI_RACE_TYPE_PLANE) IF (GET_ENTITY_HEIGHT_ABOVE_GROUND(Racer.Vehicle) <= TRI_ON_GROUND_DIST) SET_VEHICLE_ON_GROUND_PROPERLY(Racer.Vehicle) IF (GET_ENTITY_HEIGHT_ABOVE_GROUND(Racer.Vehicle) > 1.5) VECTOR vEntityCoords = GET_ENTITY_COORDS(Racer.Vehicle) vEntityCoords.z -= GET_ENTITY_HEIGHT_ABOVE_GROUND(Racer.Vehicle) + 1.5 SET_ENTITY_COORDS(Racer.Vehicle, vEntityCoords, TRUE) ENDIF ENDIF ENDIF SET_VEHICLE_ENGINE_ON(Racer.Vehicle, TRUE, TRUE) IF TRI_Master.eRaceType = TRI_RACE_TYPE_PLANE SET_HELI_BLADES_FULL_SPEED(Racer.Vehicle) ENDIF // 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) SET_PED_INTO_VEHICLE(Racer.Driver, Racer.Vehicle) ENDIF ENDIF // Set vehicle as mission entity. IF NOT IS_ENTITY_A_MISSION_ENTITY(Racer.Vehicle) 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) // Store player vehicle in master struct. TRI_Master.PlayerVeh = Racer.Vehicle // Allow player to maintain speed during autopilot. SET_VEHICLE_LIMIT_SPEED_WHEN_PLAYER_INACTIVE(Racer.Vehicle, FALSE) // Otherwise, driver type isn't player. ELSE // TODO: Put ai driver logic here... ENDIF // Racer vehicle successfully created. RETURN TRUE ENDFUNC /// PURPOSE: /// In Triathlon, recreate the player's bike after being reset. PROC TRI_Racer_Tribike_Create(TRI_RACER_STRUCT& Racer) CPRINTLN(DEBUG_TRIATHLON, "[TRI_Racer.sch->TRI_Racer_Tribike_Create] Procedure started.") IF DOES_ENTITY_EXIST(Racer.Vehicle) IF NOT IS_ENTITY_DEAD(Racer.Vehicle) CPRINTLN(DEBUG_TRIATHLON, "[TRI_Racer.sch->TRI_Racer_Tribike_Create] Player bike is NOT DEAD. Fixing bike.") // Fix up the bike. SET_ENTITY_HEALTH(Racer.Vehicle, 1000) SET_VEHICLE_ENGINE_HEALTH(Racer.Vehicle, 1000.0) ELSE CPRINTLN(DEBUG_TRIATHLON, "[TRI_Racer.sch->TRI_Racer_Tribike_Create] Player bike IS DEAD. Creating new bike.") IF NOT IS_ENTITY_DEAD(Racer.Driver) // If bike is dead, create a new one away from the water. VECTOR vCreateBikeHere = GET_ENTITY_COORDS(Racer.Driver) vCreateBikeHere.Z += 3.0 Racer.Vehicle = CREATE_VEHICLE(TRIBIKE, vCreateBikeHere, GET_ENTITY_HEADING(Racer.Driver)) ENDIF ENDIF IF NOT IS_ENTITY_DEAD(Racer.Driver) // Heal the player, just in case. SET_ENTITY_HEALTH(Racer.Driver, 1000) ENDIF // Teleport the player to be on the bike. IF NOT IS_PED_IN_ANY_VEHICLE(Racer.Driver) IF NOT IS_ENTITY_DEAD(Racer.Driver) IF NOT IS_ENTITY_DEAD(Racer.Vehicle) CPRINTLN(DEBUG_TRIATHLON, "[TRI_Racer.sch->TRI_Racer_Tribike_Create] Player is NOT ON BIKE. Setting player on bike.") SET_PED_INTO_VEHICLE(Racer.Driver, Racer.Vehicle) ENDIF ENDIF ENDIF IF NOT IS_PED_IN_ANY_VEHICLE(Racer.Driver) CPRINTLN(DEBUG_TRIATHLON, "[TRI_Racer.sch->TRI_Racer_Tribike_Create] Player STILL NOT ON BIKE!") ELSE CPRINTLN(DEBUG_TRIATHLON, "[TRI_Racer.sch->TRI_Racer_Tribike_Create] Player successfully put ON BIKE!") ENDIF ELSE CPRINTLN(DEBUG_TRIATHLON, "[TRI_Racer.sch->TRI_Racer_Tribike_Create] Player bike DOES NOT EXIST!") ENDIF ENDPROC /// PURPOSE: /// In Triathlon, place the recreated player's bike in the correct position. PROC TRI_Racer_Tribike_Place(TRI_RACE_STRUCT& Race, TRI_RACER_STRUCT& Racer) VECTOR vForwardPreviousToCurrentGate // Check if the current gate is the first one. IF Racer.iGateCur > 0 IF NOT IS_PED_IN_ANY_VEHICLE(Racer.Driver) IF NOT IS_ENTITY_DEAD(Racer.Driver) IF NOT IS_ENTITY_DEAD(Racer.Vehicle) CPRINTLN(DEBUG_TRIATHLON, "[TRI_Racer.sch->TRI_Racer_Tribike_Place] Player is NOT IN BIKE. Setting player in bike.") SET_PED_INTO_VEHICLE(Racer.Driver, Racer.Vehicle) ENDIF ENDIF ELSE CPRINTLN(DEBUG_TRIATHLON, "[TRI_Racer.sch->TRI_Racer_Tribike_Place] Player ALREADY ON BIKE..") ENDIF // If not, warp the bike to the start of the checkpoint previous to the current. //SET_ENTITY_COORDS(Racer.Vehicle, Race.sGate[Racer.iGateCur - 1].vPos) // Teleport the player and his bike to the last gate cleared. CPRINTLN(DEBUG_TRIATHLON, "[TRI_Racer.sch->TRI_Racer_Tribike_Place] Teleporting player with bike.") SET_PED_COORDS_KEEP_VEHICLE(Racer.Driver, Race.sGate[Racer.iGateCur - 1].vPos) // Get the vector between the previous and current checkpoint, to use as the bike's heading. vForwardPreviousToCurrentGate = Race.sGate[Racer.iGateCur].vPos - Race.sGate[Racer.iGateCur - 1].vPos // We should never get here, but just in case. ELSE CPRINTLN(DEBUG_TRIATHLON, "[TRI_Racer.sch->TRI_Racer_Tribike_Place] ERROR: This should not be called if gate is 0! The first gate is always a water gate!") ENDIF // Set its heading towards the current checkpoint. IF NOT IS_ENTITY_DEAD(Racer.Vehicle) FLOAT fBikeHeading fBikeHeading = GET_HEADING_FROM_VECTOR_2D(vForwardPreviousToCurrentGate.x, vForwardPreviousToCurrentGate.y) SET_ENTITY_HEADING(Racer.Vehicle, fBikeHeading) ENDIF ENDPROC PROC TRI_Racer_Vehicle_Freeze(TRI_RACER_STRUCT& Racer) //DEBUG_MESSAGE("TRI_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 TRI_Racer_Vehicle_UnFreeze(TRI_RACER_STRUCT& Racer) //DEBUG_MESSAGE("TRI_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 TRI_Racer_Vehicle_Release(TRI_RACER_STRUCT& Racer) //DEBUG_MESSAGE("TRI_Racer_Vehicle_Release") IF DOES_ENTITY_EXIST(Racer.Vehicle) // TODO: Decide if this player check is even needed... IF (Racer.Vehicle <> TRI_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 TRI_Racer_Vehicle_Destroy(TRI_RACER_STRUCT& Racer) //DEBUG_MESSAGE("TRI_Racer_Vehicle_Destroy") IF DOES_ENTITY_EXIST(Racer.Vehicle) // TODO: Decide if this player check is even needed... IF (Racer.Vehicle <> TRI_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 TRI_Racer_Request(TRI_RACER_STRUCT& Racer) //DEBUG_MESSAGE("TRI_Racer_Request") TRI_Racer_Driver_Request(Racer) TRI_Racer_Vehicle_Request(Racer) ENDPROC FUNC BOOL TRI_Racer_Stream(TRI_RACER_STRUCT& Racer) //DEBUG_MESSAGE("TRI_Racer_Stream") IF NOT TRI_Racer_Driver_Stream(Racer) OR NOT TRI_Racer_Vehicle_Stream(Racer) RETURN FALSE ENDIF RETURN TRUE ENDFUNC PROC TRI_Racer_Evict(TRI_RACER_STRUCT& Racer) //DEBUG_MESSAGE("TRI_Racer_Evict") TRI_Racer_Driver_Evict(Racer) TRI_Racer_Vehicle_Evict(Racer) ENDPROC FUNC BOOL TRI_Racer_Blip_Create(TRI_RACER_STRUCT& Racer, FLOAT fScale = 1.0) IF (Racer.Driver <> PLAYER_PED_ID()) IF NOT TRI_Blip_Entity_Create(Racer.Blip, Racer.Driver, fScale) DEBUG_MESSAGE("TRI_Racer_Blip_Create: Failed to create racer driver blip!") RETURN FALSE ENDIF ENDIF RETURN TRUE ENDFUNC PROC TRI_Racer_Blip_Destroy(TRI_RACER_STRUCT& Racer) //DEBUG_MESSAGE("TRI_Racer_Blip_Destroy") TRI_Blip_Destroy(Racer.Blip) ENDPROC FUNC BOOL TRI_Racer_Create(TRI_RACER_STRUCT& Racer, BOOL bForceCreate) DEBUG_MESSAGE("TRI_Racer_Create") IF NOT TRI_Racer_Vehicle_Create(Racer, bForceCreate) OR NOT TRI_Racer_Driver_Create(Racer) RETURN FALSE ENDIF // TODO: Should this be done in every case? // BUG : 86339 - they don't want racers blipped any more. //TRI_Racer_Blip_Create(Racer) RETURN TRUE ENDFUNC PROC TRI_Racer_Freeze(TRI_RACER_STRUCT& Racer) //DEBUG_MESSAGE("TRI_Racer_Freeze") TRI_Racer_Driver_Freeze(Racer) TRI_Racer_Vehicle_Freeze(Racer) ENDPROC PROC TRI_Racer_UnFreeze(TRI_RACER_STRUCT& Racer) //DEBUG_MESSAGE("TRI_Racer_UnFreeze") TRI_Racer_Driver_UnFreeze(Racer) TRI_Racer_Vehicle_UnFreeze(Racer) ENDPROC PROC TRI_Racer_Release(TRI_RACER_STRUCT& Racer) //DEBUG_MESSAGE("TRI_Racer_Release") TRI_Racer_Blip_Destroy(Racer) TRI_Racer_Driver_Release(Racer) TRI_Racer_Vehicle_Release(Racer) ENDPROC PROC TRI_Racer_Destroy(TRI_RACER_STRUCT& Racer) //DEBUG_MESSAGE("TRI_Racer_Destroy") TRI_Racer_Blip_Destroy(Racer) TRI_Racer_Driver_Destroy(Racer) TRI_Racer_Vehicle_Destroy(Racer) ENDPROC // ----------------------------------- // HELPER PROCS/FUNCTIONS // ----------------------------------- PROC TRI_Racer_Teleport(TRI_RACER_STRUCT& Racer, VECTOR vPos, FLOAT fHeading, FLOAT fSpeed) //DEBUG_MESSAGE("TRI_Racer_Teleport") CPRINTLN(DEBUG_TRIATHLON, "TRI_Racer_Teleport, Racer=", Racer.szName) IF IS_ENTITY_DEAD(Racer.Vehicle) OR NOT IS_PED_IN_VEHICLE(Racer.Driver, Racer.Vehicle) SET_ENTITY_COORDS(Racer.Driver, vPos) SET_ENTITY_HEADING(Racer.Driver, fHeading) ELSE SET_ENTITY_COORDS(Racer.Vehicle, vPos) SET_ENTITY_HEADING(Racer.Vehicle, fHeading) SET_VEHICLE_FORWARD_SPEED(Racer.Vehicle, fSpeed) // In Tri, this code causes the player's bike to sometimes teleport below the ground. IF (TRI_Master.eRaceType <> TRI_RACE_TYPE_PLANE) AND (TRI_Master.eRaceType <> TRI_RACE_TYPE_TRIATHLON) SET_VEHICLE_ON_GROUND_PROPERLY(Racer.Vehicle) WAIT(0) IF NOT IS_ENTITY_DEAD(Racer.Vehicle) IF (GET_ENTITY_HEIGHT_ABOVE_GROUND(Racer.Vehicle) > 1.5) VECTOR vEntityCoords = GET_ENTITY_COORDS(Racer.Vehicle) vEntityCoords.z -= GET_ENTITY_HEIGHT_ABOVE_GROUND(Racer.Vehicle) + 1.5 SET_ENTITY_COORDS(Racer.Vehicle, vEntityCoords, TRUE) ENDIF ENDIF ENDIF ENDIF ENDPROC PROC TRI_Racer_Start(TRI_RACER_STRUCT& Racer) //DEBUG_MESSAGE("TRI_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, TRI_VEH_STUCK_MIN_MOVE, TRI_VEH_STUCK_CHK_TIME) //ENDIF ENDIF ENDPROC PROC TRI_Racer_Finish(TRI_RACER_STRUCT& Racer) //DEBUG_MESSAGE("TRI_Racer_Finish") // Check if racer vehicle is alive. IF NOT IS_ENTITY_DEAD(Racer.Vehicle) IF TRI_Master.eRaceType <> TRI_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 TRI_Racer_Crash_Check(TRI_RACER_STRUCT& Racer) //DEBUG_MESSAGE("TRI_Racer_Crash_Check") IF (Racer.eVehicleModel <> DUMMY_MODEL_FOR_SCRIPT) IF Racer.Driver = PLAYER_PED_ID() //special cases for player in off-road, as player can get out of vehicle...spaghetti-o'd - SiM AND TRI_Master.eRaceType = TRI_RACE_TYPE_OFFROAD IF IS_PED_IN_VEHICLE(Racer.Driver, Racer.Vehicle) IF IS_ENTITY_DEAD(Racer.Vehicle) DEBUG_MESSAGE("TRI_Racer_Crash_Check: Vehicle dead!") RETURN TRUE ENDIF IF NOT IS_VEHICLE_DRIVEABLE(Racer.Vehicle) DEBUG_MESSAGE("TRI_Racer_Crash_Check: Vehicle undrivable!") RETURN TRUE ENDIF ENDIF ELSE IF IS_ENTITY_DEAD(Racer.Vehicle) DEBUG_MESSAGE("TRI_Racer_Crash_Check: Vehicle dead!") RETURN TRUE ENDIF IF NOT IS_VEHICLE_DRIVEABLE(Racer.Vehicle) DEBUG_MESSAGE("TRI_Racer_Crash_Check: Vehicle undrivable!") RETURN TRUE ENDIF ENDIF // 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, TRI_VEH_STUCK_PLANE_ROOF_TIME) DEBUG_MESSAGE("TRI_Racer_Crash_Check: Vehicle stuck (roof)!") RETURN TRUE ENDIF IF IS_VEHICLE_STUCK_TIMER_UP(Racer.Vehicle, VEH_STUCK_ON_SIDE, TRI_VEH_STUCK_PLANE_SIDE_TIME) DEBUG_MESSAGE("TRI_Racer_Crash_Check: Vehicle stuck (side)!") RETURN TRUE ENDIF IF IS_VEHICLE_STUCK_TIMER_UP(Racer.Vehicle, VEH_STUCK_HUNG_UP, TRI_VEH_STUCK_PLANE_HUNG_TIME) DEBUG_MESSAGE("TRI_Racer_Crash_Check: Vehicle stuck (hung)!") RETURN TRUE ENDIF IF IS_VEHICLE_STUCK_TIMER_UP(Racer.Vehicle, VEH_STUCK_JAMMED, TRI_VEH_STUCK_PLANE_JAM_TIME) DEBUG_MESSAGE("TRI_Racer_Crash_Check: Vehicle stuck (jam)!") RETURN TRUE ENDIF ENDIF ELSE IF IS_VEHICLE_STUCK_TIMER_UP(Racer.Vehicle, VEH_STUCK_ON_ROOF, TRI_VEH_STUCK_BIKE_ROOF_TIME) DEBUG_MESSAGE("TRI_Racer_Crash_Check: Vehicle stuck (roof)!") RETURN TRUE ENDIF IF IS_VEHICLE_STUCK_TIMER_UP(Racer.Vehicle, VEH_STUCK_ON_SIDE, TRI_VEH_STUCK_BIKE_SIDE_TIME) DEBUG_MESSAGE("TRI_Racer_Crash_Check: Vehicle stuck (side)!") RETURN TRUE ENDIF IF IS_VEHICLE_STUCK_TIMER_UP(Racer.Vehicle, VEH_STUCK_HUNG_UP, TRI_VEH_STUCK_BIKE_HUNG_TIME) DEBUG_MESSAGE("TRI_Racer_Crash_Check: Vehicle stuck (hung)!") RETURN TRUE ENDIF IF IS_VEHICLE_STUCK_TIMER_UP(Racer.Vehicle, VEH_STUCK_JAMMED, TRI_VEH_STUCK_BIKE_JAM_TIME) DEBUG_MESSAGE("TRI_Racer_Crash_Check: Vehicle stuck (jam)!") RETURN TRUE ENDIF ENDIF ENDIF ENDIF ENDIF //ENDIF ENDIF RETURN FALSE ENDFUNC // END OF FILE! DO NOT ADD ANYTHING BELOW THIS LINE!