#include <a_samp> //I'm pretty sure we all know what this line does. It adds the sa-mp natives :).
#include <zcmd> //Could be y_cmd or something else. It's not hard to adapt the code but most people currently use ZCMD.
#define MAX_RACES 25 //Maximum races will be 50, the lower the better due to array sizes - Change this higher if you need to
#define MAX_CHECKPOINTS 150 //Maximum checkpoints will be 100, the lower the better due to array sizes - Change this higher if you need to
#define WAIT_RACE 15 //The time in seconds between the opening of the race to the time that it starts
enum rInfo
{
//This enum is for anything related to the races themselves.
racetimeout,
//The above varible is the timeout in seconds before a race stops. We
//use this so the lovely people that decide to just sit in a race don't
//cause it to run forever.
Float:checkpointx[MAX_CHECKPOINTS],
Float:checkpointy[MAX_CHECKPOINTS],
Float:checkpointz[MAX_CHECKPOINTS],
//These will be the float positions of the checkpoints in a race.
//All checkpoint positions will load into these arrays on start-up.
racename[100 char],
//We use char to lower the array size to make the script more efficient
//and use less memory that the sa-mp server could use for doing other things
//We can use chars on strings because their values do not exceed 255.
//For more information on char visit:
//For example if racename[0] = 'a' then racename[0] would actually
//be racename[0] = 97. This will reduce our array size by 4x. If you are
//going to have race names over 100 characters then you should change
//the 100 to a higher value.
cpnum,
//We need to know how many slots are currently being used in
//the checkpoints array. We could use a loop everytime we
//wanted to add more checkpoints to the array but this would
//be very time wasting and pointless. the cpnum variable
//gives us the amount of checkpoints in a race and the next
//free cell in the checkpoints variable
racevehicle,
//The racevehicle variable isn't really needed but we will add it anyway.
//This variable allows us to specify a specific vehicle for the race
//such as an NRG or a specific boat if you're in a boat race. Later on
//we will make it so that if the variable is 0 then there is no specific
//vehicle needed.
bool:racerunning,
//The above is just a boolean that is true if the race is currently
//running and false if it's not. We set it to true on race start and
//false when the race is stopped.
bool:racejoinable,
//This variable is different to the one above because this is used if the
//race is open but hasn't started yet. If the race hasn't started, this would
//be true and racerunning would be false but if the race had started it would
//be the oppisite.
racetimer,
//This is the timer id for the timeout for the race. This will be dynamic
//and will change whenever the race is given a timer and set to start.
//We need this variable so that we can cancel the timer if there is no
//players before the timeout of the race.
racecount,
//This variable is to show the amount of players that are currently
//in the race so when it hits 0 we can end the race if it hasn't
//already timed out.
originalcount,
//This variable is static from the start to the end of the race because
//it gives us the amount of people in the race when it started. This is used
//for positioning in the race combined with the race count. It wouldn't be a
//race if we didn't have the race positions at the end :).
racetime
//This variable is just used to determine how long the race has been running
//for and it will allow us to use the timeout timer as a double for the
//time people have spent in the race. The race timer will run at 100ms and
//give us our race time accurate to .1 of a second. When the race timer reaches
//the timeout (if it does) then it will exit. It will be easier to understand
//the code when you see it :P.
};
new RaceInfo[MAX_RACES][rInfo];
//The lovely variable that holds all race information required
//For operating the races.
new currentraceslot;
//The above variable tells us how many races we have loaded and the
//next available slot that we can use in the array. This is very useful
//so we don't have to create a loop to find this information.
new VehicleNames[212][] =
{
"Landstalker", "Bravura", "Buffalo", "Linerunner", "Perennial", "Sentinel",
"Dumper", "Firetruck" , "Trashmaster" , "Stretch", "Manana", "Infernus",
"Voodoo", "Pony", "Mule", "Cheetah", "Ambulance", "Leviathan", "Moonbeam",
"Esperanto", "Taxi", "Washington", "Bobcat", "Mr Whoopee", "BF Injection",
"Hunter", "Premier", "Enforcer", "Securicar", "Banshee", "Predator", "Bus",
"Rhino", "Barracks", "Hotknife", "Trailer", "Previon", "Coach", "Cabbie",
"Stallion", "Rumpo", "RC Bandit", "Romero", "Packer", "Monster", "Admiral",
"Squalo", "Seasparrow", "Pizzaboy", "Tram", "Trailer", "Turismo", "Speeder",
"Reefer", "Tropic", "Flatbed","Yankee", "Caddy", "Solair","Berkley's RC Van",
"Skimmer", "PCJ-600", "Faggio", "Freeway", "RC Baron","RC Raider","Glendale",
"Oceanic", "Sanchez", "Sparrow", "Patriot", "Quad", "Coastguard", "Dinghy",
"Hermes", "Sabre", "Rustler", "ZR-350", "Walton", "Regina", "Comet", "BMX",
"Burrito", "Camper", "Marquis", "Baggage", "Dozer","Maverick","News Chopper",
"Rancher", "FBI Rancher", "Virgo", "Greenwood","Jetmax","Hotring","Sandking",
"Blista Compact", "Police Maverick", "Boxville", "Benson","Mesa","RC Goblin",
"Hotring Racer", "Hotring Racer", "Bloodring Banger", "Rancher", "Super GT",
"Elegant", "Journey", "Bike", "Mountain Bike", "Beagle", "Cropdust", "Stunt",
"Tanker", "RoadTrain", "Nebula", "Majestic", "Buccaneer", "Shamal", "Hydra",
"FCR-900","NRG-500","HPV1000","Cement Truck","Tow Truck","Fortune","Cadrona",
"FBI Truck", "Willard", "Forklift","Tractor","Combine","Feltzer","Remington",
"Slamvan", "Blade", "Freight", "Streak","Vortex","Vincent","Bullet","Clover",
"Sadler", "Firetruck", "Hustler", "Intruder", "Primo", "Cargobob", "Tampa",
"Sunrise", "Merit", "Utility Truck", "Nevada", "Yosemite", "Windsor", "Monster",
"Monster","Uranus","Jester","Sultan","Stratum","Elegy","Raindance","RCTiger",
"Flash","Tahoma","Savanna", "Bandito", "Freight", "Trailer", "Kart", "Mower",
"Dune", "Sweeper", "Broadway", "Tornado", "AT-400", "DFT-30", "Huntley",
"Stafford", "BF-400", "Newsvan","Tug","Trailer","Emperor","Wayfarer","Euros",
"Hotdog", "Club", "Trailer", "Trailer","Andromada","Dodo","RC Cam", "Launch",
"Police Car LSPD", "Police Car SFPD","Police Car LVPD","Police Ranger",
"Picador", "S.W.A.T. Van", "Alpha", "Phoenix", "Glendale", "Sadler",
"Luggage Trailer","Luggage Trailer","Stair Trailer", "Boxville", "Farm Plow",
"Utility Trailer"
};
//A lovely array of all vehicle names by ?. This allows us to tell a person what
//vehicle a race requires if it requires one.
new RaceCheckpoint[MAX_PLAYERS];
//This variable tells us what race checkpoint that the player is currently
//in so that we can send him to the next checkpoint in the array.
new InRace[MAX_PLAYERS];
//The above will be either "true" or "false" whether the player is
//currently racing or not. This variable is useful also because you
//can integrate it into your script in other ways.
stock CreateRace(RaceName[], RaceTimeout, RaceVehicle = -1)
{
//This is the function that we will use to load our race information
//into the variables themselves. We know that our variable currentraceslot
//will give us the next slot that we can use freely. So lets load the
//information that we have used in the function into our variables
//I have put RaceVehicle = -1 so it's the default value which means that
//we don't even need to specify it when creating a race, it's like an extra
//thing like the draw distance of an object. You could just do the following
//CreateRace("DEATH RACE :)", 300) to create a race with a timeout of 5 minutes
//with any vehicle or CreateRace("DEATH RACE :)", 300, 411) for a race with
//a specified vehicle. This will be shown more later on.
format(RaceInfo[currentraceslot][racename], 100, "%s", RaceName);
//We are inserting the function information of RaceName into our array
//RaceInfo with the next avalible race slot. format just transfers one
//string to another with ease. I was having issues with strcat for
//some reason with char.
RaceInfo[currentraceslot][racetimeout] = RaceTimeout;
//The above is pretty much the same as I explained for the name.
//We put the function information into the array. In this case
//it's the timeout information into the timeout variable in the array
RaceInfo[currentraceslot][racevehicle] = RaceVehicle;
//Same as above. Loading the vehicle information into the array.
RaceInfo[currentraceslot][racerunning] = false;
//Sets the race running variable to false
RaceInfo[currentraceslot][racejoinable] = false;
//Sets the race joinable variable to false
return currentraceslot, currentraceslot ++;
//We return the array ID so we can use it to add checkpoints later.
//It's the exact same thing you do with a pickup, you assign a variable
//to the ID of the pickup so that you can identify it later. For example
//new deathrace = CreateRace("DEATH RACE :)", 300); and we will be able to
//add checkpoints using the variable deathrace. currentraceslot++ is just
//adding 1 to the variable because we have used that slot.
}
stock AddCheckpointToRace(RaceID, Float:CheckPointX, Float:CheckPointY, Float:CheckPointZ)
{
//This function adds information into the designated array using the race
//id that was returned from the CreateRace function. We just add information
//to the arrays using this function rather than doing it manually because it's far
//easier this way. An example how this would look would be
//new deathrace = CreateRace("Death Race", 300);
//AddCheckpointToRace(deathrace, 1432.13, 312.311, 12.1);
//Pretty straight forward and easy to understand.
new nextcheckpointfree = RaceInfo[RaceID][cpnum];
//The above variable just makes it look cleaner because it gets
//the next free checkpoint slot in the array.
RaceInfo[RaceID][checkpointx][nextcheckpointfree] = CheckPointX;
RaceInfo[RaceID][checkpointy][nextcheckpointfree] = CheckPointY;
RaceInfo[RaceID][checkpointz][nextcheckpointfree] = CheckPointZ;
//Just putting the checkpoint locations from the function
//into the correct race array and into the correct checkpoint array.
//The variables go into the race ID defined and the next free checkpoint
//id in that specific race. It's like inception but less confusing :).
RaceInfo[RaceID][cpnum] ++;
//We add one so that the script knows that we have used that checkpoint
//slot up and to use the next one avalible.
return 1;
//We don't need to return a specific value unless you plan on editing
//the checkpoints location later so we just return 1 :).
}
public OnPlayerSpawn(playerid)
{
//This code just resets our player variables (InRace and RaceCheckpoint)
InRace[playerid] = -1;
//InRace is -1 if the player is not in any race or it will be a value > -1
//if the player is actually in a race. This is also quite useful because
//We could return the name of the race a player is in as well by using
//RaceInfo[InRace[playerid]][racename] in a string :).
RaceCheckpoint[playerid] = -1;
//We use RaceCheckpoint = -1 to show no checkpoint at all. We cannot
//have it at zero because in the array the first checkpoint is at 0 on
//the start. When the player is actually in the starting checkpoint
//and heading to the first checkpoint then this can be set to 0. The starting
//checkpoint is #0 and the second one is #1. It will be easier to understand
//when you see the code.
return 1;
}
stock OpenRace(raceid)
{
new RaceStr[128];
//We create this string to format the string that will be sent to all
//players when the race is joinable.
if(RaceInfo[raceid][racevehicle] == -1) format(RaceStr, sizeof(RaceStr), "[RACE] The Race '%s' will start in %d seconds. Type /joinrace %d to join!", RaceInfo[raceid][racename], WAIT_RACE, raceid);
if(RaceInfo[raceid][racevehicle] > 0) format(RaceStr, sizeof(RaceStr), "[RACE] The Race '%s' will start in %d seconds. Type /joinrace %d to join! A %s is required for this race.", RaceInfo[raceid][racename], WAIT_RACE, raceid, VehicleNames[RaceInfo[raceid][racevehicle]-400]);
if(RaceInfo[raceid][racevehicle] == 0) format(RaceStr, sizeof(RaceStr), "[RACE] The Race '%s' will start in %d seconds. Type /joinrace %d to join! This is a onfoot race only.", RaceInfo[raceid][racename], WAIT_RACE, raceid);
//We all probably know what format is and the above formats the message to
//send a message that the race can be joined by typing /joinrace [raceid]
//an example message would be something like the following:
//[RACE]The Race 'Death Race' will start in 60 seconds. Type /joinrace 1 to join
//Or if it requires a specific vehicle then it will add that on the end too.
SendClientMessageToAll(0xFF00AA, RaceStr);
//Sends the formatted message in yellow. You can easily change that colour =].
RaceInfo[raceid][racejoinable] = true;
//The above allows players to join the race. This will be set to false
//when the race starts.
SetTimerEx("StartRace", WAIT_RACE*1000, false, "d", raceid);
//The above sets the timer for the start race function. There will be 60 seconds
//before this function is actually called. StartRace is the function name,
//we have WAIT_RACE*1000 because WAIT_RACE is in seconds and the timers work
//in milliseconds (1 second = 1000 milliseconds).
//We also pass the raceid to the function 60 seconds later.
return 1;
}
stock Float:AngleToPoint(Float:x2, Float:y2, Float:X, Float:Y)
{
//This function by ? is used so that we can face the vehicle in the correct angle
//when we teleport the player to a race. This isn't a real biggie but it looks more
//awesome. Explaining this will be a bit tricky but I'll try to a basic overview.
//If you have ever done basic trig in class you will know that with two lengths
//we can find out an angle of a triangle
// /|
// H / | A (Lets pretend that's a triangle)
// ----
// O
//
//using tan ( O / A) we can find the angle that we are meant to be facing at
//The rest of the function just calculates the angles because we are not just
//in a triangle, we have a circle around us. If you don't understand then it
//is really no big issue. We use this function below.
new Float:DX, Float:DY;
new Float:angle;
DX = floatabs(floatsub(x2,X));
//Get the positive value of x2 - x (finding the length we need for the
//'O' side or the oppisite side to the angle
DY = floatabs(floatsub(y2,Y));
//Get the positive value of y2 - y (finding the length we need for the
//'A' side or the adjasent side to the angle
if (DY == 0.0 || DX == 0.0)
//If for some reason one length is zero then we do not need trig to complete
//the function and we can just find the angle by determining what value is
//the non-zero value. Pretty self explanitory.
{
if(DY == 0 && DX > 0) angle = 0.0;
else if(DY == 0 && DX < 0) angle = 180.0;
else if(DY > 0 && DX == 0) angle = 90.0;
else if(DY < 0 && DX == 0) angle = 270.0;
else if(DY == 0 && DX == 0) angle = 0.0;
}
else
{
angle = atan(DX/DY);
//If we have both values (no zeros) then we have to use the TOA
//tan(oppisite / adjacent) to find the angle required. We also have
//to add to it to find the actual angle as if we where in a circle.
//Sadly I cant fully explain it because it's hard to create a circle
//but think of it as a triangle in a circle and we need to find the
//full angle rather than just the angle of a specific segment.
if(X > x2 && Y <= y2) angle += 90.0;
else if(X <= x2 && Y < y2) angle = floatsub(90.0, angle);
else if(X < x2 && Y >= y2) angle -= 90.0;
else if(X >= x2 && Y > y2) angle = floatsub(270.0, angle);
}
return floatadd(angle, 90.0);
}
stock JoinRace(playerid, raceid)
{
if(RaceInfo[raceid][racejoinable] == false) return SendClientMessage(playerid, 0xAA3333AA, "Race is currently not joinable!");
//If the race isn't joinable then we send a message to the player that the
//race cannot be joined right now and we stop them there.
if(InRace[playerid] != -1) return SendClientMessage(playerid, 0xAA3333AA, "You are currently in a race! /leaverace before joining a new one!");
//If the player is already in a race and trying to join another one it's
//also a bit silly. The player has to first leave his current race before
//going into another one. As you see, /leaverace will be our command
//to leave the race :)
if(GetVehicleModel(GetPlayerVehicleID(playerid)) != RaceInfo[raceid][racevehicle] && RaceInfo[raceid][racevehicle] != -1)
{
if(RaceInfo[raceid][racevehicle] == 0) return SendClientMessage(playerid, 0xAA3333AA, "You are not allowed vehicles in a foot race!");
//If it's a foot race then it will send the player an error and stop here
new RaceStr[75];
//creates the string array
format(RaceStr, sizeof(RaceStr), "You need to be in a %s to join this race!", VehicleNames[RaceInfo[raceid][racevehicle]-400]);
//formats the string
return SendClientMessage(playerid, 0xAA3333AA, RaceStr);
//Or here you could always get rid of the return 1; and give the player
//that specific vehicle that is required or for a running race, take
//the players vehicle away from him/her. It's really up to you on
//what you want to do here. What I have done is just denied enterance
//to the race if the player is not in the required vehicle.
}
if(RaceInfo[raceid][racevehicle] == 0 && IsPlayerInAnyVehicle(playerid)) return SendClientMessage(playerid, 0xAA3333AA, "You are not allowed vehicles in this race!");
//I just made this clause for running races or swimming races, whatever
//floats your boat. Handy little addition and it's easy to add on. Just
//CreateRace("Runnin' Race", 300, 0) to make a running race :).
RaceCheckpoint[playerid] = 0;
//Checkpoint set to 0 - First checkpoint
InRace[playerid] = raceid;
//Players race is set to the race he/she chose to join.
if(IsPlayerInAnyVehicle(playerid))
//We are going to check if the player is in any vehicle so that we can
//then teleport that vehicle to the correct location + world. We do not
//use world 0 as the race world as people would just ram people for the fun
//of it.
{
new vehicleid = GetPlayerVehicleID(playerid);
//We fetch the players vehicle ID
SetVehicleVirtualWorld(vehicleid, 1050005 + raceid);
//We set the vehicle to a virtual world with 1050005 + the raceid like
//we are going to do with the player too. I used 1050005 so it doesn't
//overlap any worlds used by your script (hopefully). E.g. Race 20 would
//be in world ID 10050025 etc...
SetPlayerVirtualWorld(playerid, 1050005 + raceid);
//Sets the player to the same virtual world as above
PutPlayerInVehicle(playerid, vehicleid, 0);
//We put the player in the vehicle just in case
SetVehiclePos(vehicleid, RaceInfo[raceid][checkpointx][0], RaceInfo[raceid][checkpointy][0], RaceInfo[raceid][checkpointz][0]);
//We set the vehicles position in the first checkpoint waiting for the race to start
SetVehicleZAngle(vehicleid, AngleToPoint(RaceInfo[raceid][checkpointx][0], RaceInfo[raceid][checkpointy][0], RaceInfo[raceid][checkpointx][1], RaceInfo[raceid][checkpointy][1]));
//The code above sets the angle of the vehicle towards the second checkpoint.
}
else
{
SetPlayerVirtualWorld(playerid, 1050005 + raceid);
SetPlayerFacingAngle(playerid, AngleToPoint(RaceInfo[raceid][checkpointx][0], RaceInfo[raceid][checkpointy][0], RaceInfo[raceid][checkpointx][1], RaceInfo[raceid][checkpointy][1]));
SetPlayerPos(playerid, RaceInfo[raceid][checkpointx][0], RaceInfo[raceid][checkpointy][0], RaceInfo[raceid][checkpointz][0]);
//Same as above with the cars. The angle of the player is set to the next
//checkpoint so that they are not facing backwards when the race starts.
//Actually, that would be pretty funny :P.
}
new RaceInfoString[75];
format(RaceInfoString, sizeof(RaceInfoString), "~y~Joined the race! ~b~Please wait %d seconds for the race to start!", WAIT_RACE);
//We have to format the amount of seconds before the race starts because it's
//most likely going to change from 60 seconds that have been set.
GameTextForPlayer(playerid, RaceInfoString, 3000, 3);
//We send the player a nice on screen message telling them
//that they have joined the race :).
SetPlayerRaceCheckpoint(playerid, 0, RaceInfo[raceid][checkpointx][0], RaceInfo[raceid][checkpointy][0], RaceInfo[raceid][checkpointz][0], RaceInfo[raceid][checkpointx][1], RaceInfo[raceid][checkpointy][1], RaceInfo[raceid][checkpointz][1], 6);
//This sets the starting checkpoint and it points to the direction that the
//next checkpoint will be in. The player has to be in this checkpoint when
//the race starts or they won't racing :P. Remember that our array ids start
//at 0 rather than one.
return 1;
}
forward StartRace(raceid);
public StartRace(raceid)
{
RaceInfo[raceid][racejoinable] = false;
//We now make it so the race is no longer joinable by anyone else.
for(new i; i<MAX_PLAYERS; i++)
//if you have foreach then foreach (new i : Player) or make your own
//illiterator for players in races. Just loops through everyone currently
//that has tried to join the race
{
if(InRace[i] != raceid) continue;
//skips anyone that isn't in the race that we are looking into.
//continue just skips a certain id. For example if ID 5 wasn't in
//our race so InRace[playerid] = -1 it would skip his ID and not check
//any further.
if(IsPlayerInRaceCheckpoint(i) && (GetVehicleModel(GetPlayerVehicleID(i)) == RaceInfo[raceid][racevehicle] || RaceInfo[raceid][racevehicle] == -1 ))
//If the player is in the race we are looking at + the player is in
//the checkpoint + the vehicle model is correct if there is one.
{
SetPlayerRaceCheckpoint(i, 0, RaceInfo[raceid][checkpointx][1], RaceInfo[raceid][checkpointy][1], RaceInfo[raceid][checkpointz][1], RaceInfo[raceid][checkpointx][2], RaceInfo[raceid][checkpointy][2], RaceInfo[raceid][checkpointz][2], 6);
//The above line sets the players checkpoint from the start point
//to the second checkpoint in the race. It also points to the direction
//Of the third checkpoint RaceInfo[raceid][checkpoint[x][y][z]][2].
//Remember that the first and starting checkpoint was used in the
//Joinrace function with the index of 0. 0 is the first number in
//our array rather than 1.
RaceCheckpoint[i] = 2;
//The players race checkpoint is set to checkpoint #1. As we see
//above the race checkpoint is being set in the array as 1.
RaceInfo[raceid][originalcount] ++;
//We add to the originalcount so that we get the players in the race
//This count does not change throughout the race and will be reset
//at the end of the race on StopRace
RaceInfo[raceid][racecount] ++;
//This racecount variable will change whenever someone leaves the
//race or finishes it. It helps us determine when to stop the race
//and what position someone finishes in a certain race. This variable
//will be changed over the course of the race.
GameTextForPlayer(i, "~r~GO!!!!", 3000, 3);
//We send the player a nice on screen text that tells them that
//the race has started and they better get going :).
}
else
//The above code is if we find that the player isn't even in the checkpoint
//when the race has started or the vehicle ID specified isn't the one that
//the race allows.
{
RaceCheckpoint[i] = -1;
//Race checkpoint reset
InRace[i] = -1;
//Player is put out of the race
DisablePlayerRaceCheckpoint(i);
//Players checkpoint is disabled.
if(IsPlayerInAnyVehicle(i))
//If the player was in a car
{
new vehicleid = GetPlayerVehicleID(i);
//We fetch the players vehicle ID
SetVehicleVirtualWorld(vehicleid, 0);
//We reset the vehicles virtual world to 0
SetPlayerVirtualWorld(i, 0);
//Sets the player to virtual world 0 too
PutPlayerInVehicle(i, vehicleid, 0);
//We put the player in the vehicle just in case
}
else
{
SetPlayerVirtualWorld(i, 0);
//If the player was on foot we just put him back to virtual
//world 0.
}
}
}
if(RaceInfo[raceid][originalcount] == 0) return 1;
//The above code is executed if it's time for the race to start but we seem
//to have nobody in the race checkpoint with the specified rules. This will
//just stop the function and the race will not be started and that will be
//the end of it.
RaceInfo[raceid][racetimer] = SetTimerEx("RaceTime", 100, true, "d", raceid);
//We set the 100ms timer that acts as our timeout timer and gives us the
//amount of time that the race has gone on for. Some people would use the
//function GetTickCount although if you're server has a long uptime then
//the script would just break itself. The timer is set at 100ms and the raceid
//is carried onto the RaceTime function.
RaceInfo[raceid][racerunning] = true;
//We set the variable of racerunning to true to show that the race is actually
//running so it cant be started.
return 1;
}
forward RaceTime(raceid);
public RaceTime(raceid)
{
RaceInfo[raceid][racetime] ++;
//The racetime variable holds the current race time in 100ms increments
//This allows us to give accurate race times to players at the end of the
//race to .1 of a second.
if(floatround((RaceInfo[raceid][racetime] / 10), floatround_floor) >= RaceInfo[raceid][racetimeout]) StopRace(raceid);
//The above code does seem slightly confusing but it isn't. The racetimeout
//time is in seconds and the racetime is in 0.1 of a second. We just divide
//the race time by 10 so that we get the total race time in seconds and we
//use the function Floatround to round downwards so we have no chance to get
//errors when we try compare a float like this.
return 1;
}
stock StopRace(raceid)
{
KillTimer(RaceInfo[raceid][racetimer]);
//We kill that timer that is going at 100ms/s acting as our timeout timer
//and the race time timer
RaceInfo[raceid][racetime] = 0;
//Race time is reset to 0 for the race.
RaceInfo[raceid][racerunning] = false;
//Race running is set to false for the race
RaceInfo[raceid][originalcount] = 0;
//The originalcount is set to 0 for the race.
if(RaceInfo[raceid][racecount] != 0)
{
//The only case that this would happen is a race timeout. This is if we
//try to stop a race when there is players still in it.
for(new i; i<MAX_PLAYERS; i++)
//if you have foreach then foreach (new i : Player) or make your own
//illiterator for players in races.
{
if(InRace[i] != raceid) continue;
//skips anyone that isn't in the race that we are looking into.
//continue just skips a certain id. For example if ID 5 wasn't in
//our race so InRace[playerid] = -1 it would skip his ID and not check
//any further.
GameTextForPlayer(i, "~r~You have run out of time for this race!", 3000, 3);
//Send the player a message telling them they have ran out of time for
//the race.
LeaveRace(i, raceid);
//Calls LeaveRace for any player that is still in the race.
}
RaceInfo[raceid][racecount] = 0;
//The racecount can now be reset as all the players have been kicked
//from the race if they didn't make it.
}
return 1;
}
stock LeaveRace(playerid, raceid)
{
RaceCheckpoint[playerid] = -1;
//Race checkpoint reset
InRace[playerid] = -1;
//Player is put out of the race
DisablePlayerRaceCheckpoint(playerid);
//Players checkpoint is disabled.
if(IsPlayerInAnyVehicle(playerid))
//If the player was in a car
{
new vehicleid = GetPlayerVehicleID(playerid);
//We fetch the players vehicle ID
SetVehicleVirtualWorld(vehicleid, 0);
//We reset the vehicles virtual world to 0
SetPlayerVirtualWorld(playerid, 0);
//Sets the player to virtual world 0 too
PutPlayerInVehicle(playerid, vehicleid, 0);
//We put the player in the vehicle just in case
}
else
{
SetPlayerVirtualWorld(playerid, 0);
//If the player was on foot we just put him back to virtual
//world 0.
}
if(RaceInfo[raceid][racerunning] == true)
//If the race has actually started rather than just a player waiting for the
//race to start leaving the race.
{
RaceInfo[raceid][racecount] --;
//removes a player from the racecount.
if(RaceInfo[raceid][racecount] == 0) StopRace(raceid);
//If there is nobody in the race after this person leaves then we have to
//stop the race from running.
}
return 1;
}
public OnPlayerEnterRaceCheckpoint(playerid)
{
if(InRace[playerid] != -1)
//This just makes sure the player is actually in a race. You may be using
//race checkpoints for something else as well as this race system.
{
if(RaceCheckpoint[playerid] > 0)
//RaceCheckpoint[playerid] = 0 is if the player is in a race but at
//the starting checkpoint rather than actually racing. We check if the
//player is at a checkpoint further than CP 1.
{
new raceid = InRace[playerid], checkpoint = RaceCheckpoint[playerid];
//Above variables just makes it easier for us to use and understand
//the code. We put the raceid that the player is in into the raceid
//variable... YAY :). We also put the checkpoint id into the
//checkpoint variable ;).
if(checkpoint == RaceInfo[raceid][cpnum])
//If we have the same checkpoint value as the race checkpoints before
//we add one to our race checkpoint variable then we have gone through
//the finishing checkpoint which means we should initiate the finish
//race code and stop it there with a return 1;
{
//Player leaves the race.
new str[128], playername[24];
//creates the variables for the string we will format and the
//variable to hold the players name.
format(str, sizeof(str), "~w~Finished the race~n~~g~Position %d/%d - ~b~Time: %s", (RaceInfo[raceid][originalcount] - (RaceInfo[raceid][racecount] - 1)), RaceInfo[raceid][originalcount], ReturnTime(RaceInfo[raceid][racetime]));
//Formats the string that will be sent to the player in a gametext.
//(RaceInfo[raceid][originalcount] - (RaceInfo[raceid][racecount] - 1))
//Starts at the original count minus the players in the race
//minus the player himself (-1).
GameTextForPlayer(playerid, str, 3000, 3);
//Sends the player an on screen text of that formatted text above
GetPlayerName(playerid, playername, sizeof(playername));
//Gets the players name for the message that will be sent to everyone
format(str, sizeof(str), "[RACE RESULTS] %s(%d) finished race %s(ID:%d) in %s in the position %d/%d", playername, playerid, RaceInfo[raceid][racename], raceid, ReturnTime(RaceInfo[raceid][racetime]), (RaceInfo[raceid][originalcount] - (RaceInfo[raceid][racecount]-1)), RaceInfo[raceid][originalcount]);
//Formats a message for everyone with the players race results
//which include his name, id, race name, raceid, time, and
//position.
SendClientMessageToAll(0xFF00AA, str);
//sends everyone the formatted string.
LeaveRace(playerid, InRace[playerid]);
return 1;
}
RaceCheckpoint[playerid] ++;
//Adds one to the players current race checkpoint.
if(checkpoint != RaceInfo[raceid][cpnum]) SetPlayerRaceCheckpoint(playerid, 0, RaceInfo[raceid][checkpointx][checkpoint], RaceInfo[raceid][checkpointy][checkpoint], RaceInfo[raceid][checkpointz][checkpoint], RaceInfo[raceid][checkpointx][checkpoint+1], RaceInfo[raceid][checkpointy][checkpoint+1], RaceInfo[raceid][checkpointz][checkpoint+1], 6);
//Sets the players race checkpoint and the arrow to the next
//race checkpoint. RaceInfo[raceid][checkpointx][checkpoint+1] is the
//next x position of the next checkpoint which is what the current
//checkpoint will point at. if(checkpoint != RaceInfo[raceid][cpnum]
//means that we are not at the last checkpoint yet. The cpnum variable
//was used to show us the last array used for our checkpoints back
//when we were adding checkpoints and it will tell us the last checkpoint.
if(checkpoint+1 == RaceInfo[raceid][cpnum]) SetPlayerRaceCheckpoint(playerid, 1, RaceInfo[raceid][checkpointx][checkpoint], RaceInfo[raceid][checkpointy][checkpoint], RaceInfo[raceid][checkpointz][checkpoint], 0.0, 0.0, 0.0, 6);
//The above is different from the last time we used
//if(checkpoint == RaceInfo[raceid][cpnum]) because this time it's
//after we added 1 to the race checkpoint variable. This now means
//that we are setting the last checkpoint and the call above will
//be called when we enter that checkpoint that we are just setting now.
new RaceInfoString[80];
format(RaceInfoString, sizeof(RaceInfoString), "~b~%d/%d ~n~~g~%s", RaceCheckpoint[playerid]-2, RaceInfo[raceid][cpnum] - 1, ReturnTime(RaceInfo[raceid][racetime]));
//This returns a formatted string with the checkpoint number and the
//current time that they have taken on this course. I have created
//the function ReturnTime because I used the exact same code when
//the player had finished the race as well. We have the cpnum minus
//one because we don't count the starting checkpoint as an actual
//checkpoint that the player goes through. RaceCheckpint[playerid]-2
//is there because of the reason above (we don't count the first
//checkpoint and it shows one before what we actually have so
//that the second to last checkpoint shows 12/13 rather than 13/13
GameTextForPlayer(playerid, RaceInfoString, 3000, 3);
//Sends the gametext that tells the player their checkpoint number
//and the current time it has taken them. You could always add a
//loop here comparing with the checkpoint number to find the players
//position in the race. You could also make a Textdraw that tells
//the player their time and checkpoint rather than having it show
//as a gametext.
}
}
return 1;
}
stock ReturnTime(timevariable)
//Used in the OnPlayerEnterRaceCheckpoint code.
{
new milliseconds = timevariable, seconds, minutes, string[20];
while(milliseconds > 9)
//While we still have 10 or more 100x milliseconds left
{
seconds ++;
//Add to the seconds variable
milliseconds = milliseconds - 10;
//Take away 10 from the ms variable
}
while(seconds > 59)
//while we have 60 or more seconds on the timer
{
minutes ++;
//We add to the minutes variable
seconds = seconds - 60;
//And take the 60 seconds from the seconds variable.
}
format(string, sizeof(string), "%d:%02d.%03d
", minutes, seconds, milliseconds);
//format the return string the 0 before the first %d makes it so the
//seconds are correct and the zeros after the last %d make it so the
//milliseconds show correctly.
}
return string;
//return the end result.
}
CMD:joinrace(playerid, params[])
//The joinrace command using ZCMD
{
if(!strlen(params)) return SendClientMessage(playerid, 0xFF0000, "Please enter a race id to join or type /races");
new raceid = strval(params);
if(raceid > currentraceslot-1) return SendClientMessage(playerid, 0xFF0000, "The race ID you have entered is invalid");
//Just basic tests to see if there is a race in the array / the number is
//not too big for the array.
if(RaceInfo[raceid][racejoinable] == false && RaceInfo[raceid][racerunning] == false && InRace[playerid] == -1) OpenRace(raceid);
//If the race is not running or is joinable it is opened and the player
//isn't in a race then it will start the race. If you don't want players
//to be able to start races like this then remove the line and add an admin
//command or a timer that choses a random race every x amount of seconds.
JoinRace(playerid, raceid);
//The above line will just join the player to the race.
return 1;
}
CMD:leaverace(playerid, params[])
//The leaverace command using zcmd
{
if(InRace[playerid] == -1) return SendClientMessage(playerid, 0xFF0000, "You are not in a race");
//Checks if a player is in a race or not and errors him if he isn't and
//the code stops there with a return.
LeaveRace(playerid, InRace[playerid]);
//player leaves the race.
GameTextForPlayer(playerid, "~b~You have left the race", 3000, 3);
//On screen text telling them they have left the race
return 1;
}
public OnPlayerDeath(playerid, killerid, reason)
{
if(InRace[playerid] != -1) LeaveRace(playerid, InRace[playerid]);
//Checks if the player is in a race and removes him / her from it on death
return 1;
}
public OnPlayerDisconnect(playerid, reason)
{
if(InRace[playerid] != -1) LeaveRace(playerid, InRace[playerid]);
//Checks if the player is in a race and removes him from it on disconnect if
//(s)he is in a race.
return 1;
}
CMD:races(playerid, params[])
{
new RaceInfoString[600];
//Creates the large string for formatting all of this information. If you
//are going to have like 30+ races then you may need to make the string
//slightly larger.
for(new x; x<currentraceslot; x++)
//We are looping through all races up to the last slot used (currentraceslot)
{
if(RaceInfo[x][racejoinable] == true) format(RaceInfoString, sizeof(RaceInfoString), "%s%s(ID:%d) {00FF00}[RACE JOINABLE]{FFFFFF}\n", RaceInfoString, RaceInfo[x][racename], x);
//If the race is currently joinable (still not started) then it will add
//a line to that string that shows the race information with the tag
//[RACE JOINABLE] on the end.
else if(RaceInfo[x][racerunning] == true) format(RaceInfoString, sizeof(RaceInfoString), "%s%s(ID:%d) {FF0000}[RACE RUNNING]{FFFFFF}\n", RaceInfoString, RaceInfo[x][racename], x);
//If the race is not currently joinable it will show the race name + id
//with [RACE RUNNING] tag on it.
else format(RaceInfoString, sizeof(RaceInfoString), "%s%s(ID:%d) \n", RaceInfoString, RaceInfo[x][racename], x);
//If the race is not running or being started at all then it will just
//be added with the race name and id.
}
ShowPlayerDialog(playerid, 13337, DIALOG_STYLE_LIST, "Races", RaceInfoString, "Join", "Cancel");
//Sends the player a dialog which allows them to join races straight off
//that list if they are avalible. The list also shows all races that have
//currently been started and are currently running.
return 1;
}
public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[])
{
if(dialogid == 13337 && response != 0)
//If our dialog is chosen and the player has pressed the join button
//we initiate further code.
{
if(currentraceslot < listitem) return SendClientMessage(playerid, 0xFF0000, "Race ID is not valid");
//Just to prevent the server crashing due to array out of bounds
//if someone manages to manipulate the dialog we just make it so that
//the listitem has a higher value than the array.
if(!strlen(RaceInfo[listitem][racename])) return SendClientMessage(playerid, 0xFF0000, "Race ID is not valid");
//Same as above but it just prevents players from attempting to join
//races that are not being used by checking if they have a name or not.
//Remember the return stops the code there.
if(RaceInfo[listitem][racejoinable] == false && RaceInfo[listitem][racerunning] == false && InRace[playerid] == -1) OpenRace(listitem);
//Same as in the /joinrace command. Starts the race if possible. If you
//don't want players to have this kind of permission then just take it
//off.
JoinRace(playerid, listitem);
//We join the race to the listitem specified. The listitem will be the
//number on the list chosen which will also match up with our RaceInfo
//array.
}
return 0;
}
public OnFilterScriptInit()
{
new myfirstrace = CreateRace("Drag race", 300);
AddCheckpointToRace(myfirstrace, 2378.034423, -1256.948120, 23.392478); //This will be the starting checkpoint
AddCheckpointToRace(myfirstrace, 2424.435058, -1256.951904, 23.392736);
AddCheckpointToRace(myfirstrace, 2483.459228, -1256.290039, 29.515676);
AddCheckpointToRace(myfirstrace, 2544.722656, -1255.574829, 40.808807);
AddCheckpointToRace(myfirstrace, 2623.192871, -1256.035888, 48.688129);
AddCheckpointToRace(myfirstrace, 2640.677734, -1299.083984, 43.465404);
AddCheckpointToRace(myfirstrace, 2641.805908, -1384.888916, 29.915727);
AddCheckpointToRace(myfirstrace, 2642.633056, -1510.337402, 28.740942);
AddCheckpointToRace(myfirstrace, 2642.414306, -1609.575195, 10.076794);
AddCheckpointToRace(myfirstrace, 2642.405029, -1748.507324, 10.287642);
AddCheckpointToRace(myfirstrace, 2642.405029, -1812.125122, 10.375592); //This will be the finishing checkpoint
return 1;
}
public OnFilterScriptInit()
{
new myfirstrace = CreateRace("Drag race", 300);
AddCheckpointToRace(myfirstrace, 2378.034423, -1256.948120, 23.392478);
AddCheckpointToRace(myfirstrace, 2424.435058, -1256.951904, 23.392736);
AddCheckpointToRace(myfirstrace, 2483.459228, -1256.290039, 29.515676);
AddCheckpointToRace(myfirstrace, 2544.722656, -1255.574829, 40.808807);
AddCheckpointToRace(myfirstrace, 2623.192871, -1256.035888, 48.688129);
AddCheckpointToRace(myfirstrace, 2640.677734, -1299.083984, 43.465404);
AddCheckpointToRace(myfirstrace, 2641.805908, -1384.888916, 29.915727);
AddCheckpointToRace(myfirstrace, 2642.633056, -1510.337402, 28.740942);
AddCheckpointToRace(myfirstrace, 2642.414306, -1609.575195, 10.076794);
AddCheckpointToRace(myfirstrace, 2642.405029, -1748.507324, 10.287642);
AddCheckpointToRace(myfirstrace, 2642.405029, -1812.125122, 10.375592);
new race1 = CreateRace("DRAG LOL", 180);
AddCheckpointToRace(race1, 2829.936523, -1794.952880, 10.647988);
AddCheckpointToRace(race1, 2844.200927, -1714.927368, 10.654101);
AddCheckpointToRace(race1, 2882.619628, -1575.671142, 10.650041);
AddCheckpointToRace(race1, 2903.586425, -1443.250488, 10.646242);
AddCheckpointToRace(race1, 2889.312988, -1309.945068, 10.654065);
AddCheckpointToRace(race1, 2871.154785, -1043.372802, 10.646505);
AddCheckpointToRace(race1, 2874.849609, -857.698730, 10.646862);
AddCheckpointToRace(race1, 2884.896484, -675.723999, 10.607203);
AddCheckpointToRace(race1, 2898.247802, -742.455566, 10.612231);
AddCheckpointToRace(race1, 2892.632080, -896.031188, 10.646240);
AddCheckpointToRace(race1, 2889.872314, -1064.333740, 10.646269);
AddCheckpointToRace(race1, 2897.653076, -1222.954711, 10.646265);
AddCheckpointToRace(race1, 2916.691650, -1346.928466, 10.646243);
AddCheckpointToRace(race1, 2916.200683, -1513.697265, 10.649989);
AddCheckpointToRace(race1, 2874.615478, -1659.650390, 10.646264);
new race2 = CreateRace("lolrace", 50, 0);
AddCheckpointToRace(race2, 2915.456787, -1622.428466, 12.435916);
AddCheckpointToRace(race2, 2910.672363, -1637.185913, 12.395952);
AddCheckpointToRace(race2, 2903.093994, -1660.151611, 12.430374);
AddCheckpointToRace(race2, 2898.300048, -1675.741333, 12.457112);
AddCheckpointToRace(race2, 2890.918457, -1702.602905, 12.493884);
new race3 = CreateRace("circles", 300, 422);
AddCheckpointToRace(race3, 2743.795654, -1824.129760, 37.350173);
AddCheckpointToRace(race3, 2785.624511, -1798.400634, 38.007194);
AddCheckpointToRace(race3, 2789.515625, -1730.653320, 38.372951);
AddCheckpointToRace(race3, 2738.261718, -1703.567260, 39.003555);
AddCheckpointToRace(race3, 2684.301513, -1735.715698, 38.545482);
AddCheckpointToRace(race3, 2696.835693, -1801.783691, 38.632278);
AddCheckpointToRace(race3, 2760.039550, -1815.870971, 38.270313);
AddCheckpointToRace(race3, 2798.526611, -1765.682006, 38.073280);
AddCheckpointToRace(race3, 2788.305908, -1731.470947, 38.702461);
AddCheckpointToRace(race3, 2751.104736, -1710.066772, 40.082180);
AddCheckpointToRace(race3, 2685.113037, -1726.660766, 37.719898);
AddCheckpointToRace(race3, 2681.699951, -1785.690185, 37.916439);
AddCheckpointToRace(race3, 2732.258544, -1823.472167, 37.502525);
AddCheckpointToRace(race3, 2787.974121, -1795.875976, 37.903495);
AddCheckpointToRace(race3, 2789.651855, -1734.030151, 38.703849);
AddCheckpointToRace(race3, 2699.944824, -1717.708496, 38.976169);
AddCheckpointToRace(race3, 2682.354736, -1756.922851, 39.295875);
new race4 = CreateRace("DatLongRace", 300);
AddCheckpointToRace(race4, 2633.364990, -1734.128051, 10.525354);
AddCheckpointToRace(race4, 2545.920654, -1733.396240, 13.154250);
AddCheckpointToRace(race4, 2442.343750, -1733.484252, 13.355755);
AddCheckpointToRace(race4, 2431.615478, -1675.185058, 23.190317);
AddCheckpointToRace(race4, 2432.491699, -1583.581542, 24.303165);
AddCheckpointToRace(race4, 2426.228027, -1528.688842, 23.610731);
AddCheckpointToRace(race4, 2358.857177, -1524.946044, 23.599382);
AddCheckpointToRace(race4, 2343.114013, -1438.596801, 23.599653);
AddCheckpointToRace(race4, 2332.898925, -1387.123657, 23.665111);
AddCheckpointToRace(race4, 2267.898437, -1374.233398, 23.599349);
AddCheckpointToRace(race4, 2266.498535, -1303.596435, 23.602481);
AddCheckpointToRace(race4, 2143.897705, -1302.048583, 23.591621);
AddCheckpointToRace(race4, 2076.627197, -1295.328979, 23.590627);
AddCheckpointToRace(race4, 2054.959472, -1258.147949, 23.591150);
AddCheckpointToRace(race4, 1923.316406, -1260.406738, 16.012174);
AddCheckpointToRace(race4, 1817.992553, -1264.200195, 13.243765);
AddCheckpointToRace(race4, 1714.354370, -1297.821655, 13.160857);
AddCheckpointToRace(race4, 1607.921142, -1299.956787, 17.046354);
AddCheckpointToRace(race4, 1467.686523, -1303.289916, 13.193289);
AddCheckpointToRace(race4, 1453.888427, -1381.708862, 13.154219);
AddCheckpointToRace(race4, 1449.449584, -1436.579956, 13.154660);
AddCheckpointToRace(race4, 1405.544921, -1420.086425, 13.945821);
AddCheckpointToRace(race4, 1315.515258, -1405.038818, 13.063317);
AddCheckpointToRace(race4, 1205.709960, -1404.587158, 13.066181);
AddCheckpointToRace(race4, 1041.687133, -1403.934204, 13.045770);
AddCheckpointToRace(race4, 946.428405, -1401.756591, 13.036564);
AddCheckpointToRace(race4, 918.143981, -1382.413818, 13.005650);
AddCheckpointToRace(race4, 916.576599, -1334.884765, 13.273034);
AddCheckpointToRace(race4, 822.389953, -1334.648559, 13.323395);
AddCheckpointToRace(race4, 837.015991, -1343.594848, 7.064631);
AddCheckpointToRace(race4, 830.920715, -1355.182861, 1.802645);
AddCheckpointToRace(race4, 824.963378, -1381.297363, -1.784867);
AddCheckpointToRace(race4, 897.291625, -1450.401733, -1.967725);
AddCheckpointToRace(race4, 968.884155, -1525.094238, -2.687804);
AddCheckpointToRace(race4, 1118.831665, -1692.697875, -4.506172);
AddCheckpointToRace(race4, 1205.780883, -1793.990234, -4.416773);
AddCheckpointToRace(race4, 1327.433471, -1920.372924, 1.110849);
AddCheckpointToRace(race4, 1425.327758, -1953.886962, 12.610272);
AddCheckpointToRace(race4, 1560.160888, -1956.531127, 13.320227);
AddCheckpointToRace(race4, 1714.534423, -1957.219116, 13.322772);
AddCheckpointToRace(race4, 1827.264770, -1956.456542, 13.326131);
AddCheckpointToRace(race4, 1935.426879, -1966.828613, 14.527605);
AddCheckpointToRace(race4, 1984.612304, -1963.229858, 17.639959);
AddCheckpointToRace(race4, 2116.238037, -1956.358520, 13.328435);
AddCheckpointToRace(race4, 2198.640625, -1911.479736, 13.332157);
AddCheckpointToRace(race4, 2218.488037, -1849.738159, 13.029332);
AddCheckpointToRace(race4, 2223.098632, -1751.567504, 13.153687);
AddCheckpointToRace(race4, 2324.993896, -1749.899047, 13.151140);
AddCheckpointToRace(race4, 2405.868164, -1753.348999, 13.153372);
AddCheckpointToRace(race4, 2412.497558, -1804.233764, 13.154181);
AddCheckpointToRace(race4, 2412.224609, -1882.934814, 13.154174);
AddCheckpointToRace(race4, 2412.380615, -1999.624389, 13.132261);
AddCheckpointToRace(race4, 2412.784912, -2109.244384, 13.141799);
AddCheckpointToRace(race4, 2413.450195, -2160.048828, 13.220868);
AddCheckpointToRace(race4, 2324.239990, -2235.036132, 13.146298);
AddCheckpointToRace(race4, 2287.443115, -2302.291992, 13.150836);
AddCheckpointToRace(race4, 2359.932861, -2374.427246, 13.151649);
AddCheckpointToRace(race4, 2429.166992, -2442.671386, 13.238473);
AddCheckpointToRace(race4, 2520.102294, -2380.220703, 13.224400);
AddCheckpointToRace(race4, 2628.054931, -2402.248291, 13.233164);
AddCheckpointToRace(race4, 2736.581298, -2409.763183, 13.258348);
AddCheckpointToRace(race4, 2797.283447, -2416.207763, 13.402585);
new lsrace = CreateRace("LsRace", 300);
AddCheckpointToRace(lsrace, 1706.426391, -611.859863, 38.901790);
AddCheckpointToRace(lsrace, 1692.569946, -723.126037, 48.900508);
AddCheckpointToRace(lsrace, 1652.880004, -817.668334, 57.524845);
AddCheckpointToRace(lsrace, 1605.353881, -881.411804, 53.732391);
AddCheckpointToRace(lsrace, 1539.825439, -922.278015, 43.056083);
AddCheckpointToRace(lsrace, 1461.724975, -940.698120, 35.791889);
AddCheckpointToRace(lsrace, 1403.331054, -941.417907, 34.747589);
AddCheckpointToRace(lsrace, 1392.661621, -882.348999, 39.213245);
AddCheckpointToRace(lsrace, 1465.932739, -865.940429, 55.070766);
AddCheckpointToRace(lsrace, 1512.892944, -797.726623, 73.608940);
AddCheckpointToRace(lsrace, 1476.592773, -764.863769, 91.092216);
AddCheckpointToRace(lsrace, 1457.034545, -720.671813, 91.886367);
AddCheckpointToRace(lsrace, 1338.306518, -698.574401, 91.680290);
AddCheckpointToRace(lsrace, 1155.694335, -762.598022, 107.170852);
AddCheckpointToRace(lsrace, 1037.425781, -782.354858, 103.803581);
AddCheckpointToRace(lsrace, 944.082031, -823.647094, 95.165565);
AddCheckpointToRace(lsrace, 838.899108, -870.125427, 68.854980);
AddCheckpointToRace(lsrace, 782.362426, -907.054016, 56.233585);
AddCheckpointToRace(lsrace, 676.304748, -1057.787963, 49.234329);
AddCheckpointToRace(lsrace, 546.687988, -1158.329833, 54.421894);
AddCheckpointToRace(lsrace, 442.335571, -1189.781250, 67.419334);
AddCheckpointToRace(lsrace, 399.630310, -1174.796752, 78.225868);
AddCheckpointToRace(lsrace, 287.595764, -1227.318481, 74.894096);
AddCheckpointToRace(lsrace, 230.168182, -1276.778564, 64.179939);
AddCheckpointToRace(lsrace, 243.446228, -1327.960083, 52.253746);
AddCheckpointToRace(lsrace, 212.957321, -1365.910888, 49.981910);
AddCheckpointToRace(lsrace, 156.897445, -1428.196655, 39.155746);
AddCheckpointToRace(lsrace, 112.251525, -1485.543457, 14.808308);
AddCheckpointToRace(lsrace, 167.971176, -1530.873657, 11.934063);
AddCheckpointToRace(lsrace, 230.456497, -1443.309692, 12.917514);
AddCheckpointToRace(lsrace, 338.681091, -1381.437988, 13.922136);
AddCheckpointToRace(lsrace, 471.116241, -1298.085449, 15.019657);
AddCheckpointToRace(lsrace, 539.320739, -1241.989990, 16.362131);
AddCheckpointToRace(lsrace, 634.960266, -1259.193481, 16.687885);
AddCheckpointToRace(lsrace, 635.698059, -1334.740722, 13.114221);
AddCheckpointToRace(lsrace, 633.734802, -1491.675170, 14.342875);
AddCheckpointToRace(lsrace, 635.601684, -1616.577270, 15.354584);
AddCheckpointToRace(lsrace, 632.403259, -1718.967895, 13.681066);
AddCheckpointToRace(lsrace, 759.028747, -1766.696166, 12.587768);
AddCheckpointToRace(lsrace, 881.049072, -1770.948730, 13.109845);
AddCheckpointToRace(lsrace, 1008.124572, -1795.744262, 13.775837);
AddCheckpointToRace(lsrace, 1156.595825, -1852.637329, 13.121710);
AddCheckpointToRace(lsrace, 1312.552978, -1831.018432, 13.109981);
AddCheckpointToRace(lsrace, 1311.227416, -1670.582519, 13.109985);
AddCheckpointToRace(lsrace, 1337.795532, -1493.360961, 13.108355);
AddCheckpointToRace(lsrace, 1356.297363, -1256.863037, 13.106974);
AddCheckpointToRace(lsrace, 1363.745239, -1076.934936, 24.951122);
AddCheckpointToRace(lsrace, 1473.232055, -1031.099243, 23.383405);
AddCheckpointToRace(lsrace, 1658.844116, -1026.858276, 23.625595);
AddCheckpointToRace(lsrace, 1894.228637, -1044.847290, 23.408243);
AddCheckpointToRace(lsrace, 2039.885620, -1074.727416, 24.357799);
AddCheckpointToRace(lsrace, 2176.282226, -1143.813720, 24.630598);
AddCheckpointToRace(lsrace, 2168.373535, -1290.851318, 23.547401);
AddCheckpointToRace(lsrace, 2271.814941, -1299.705200, 23.553785);
AddCheckpointToRace(lsrace, 2331.828125, -1299.506225, 23.808448);
AddCheckpointToRace(lsrace, 2371.086181, -1352.059692, 23.562322);
AddCheckpointToRace(lsrace, 2343.587890, -1409.425415, 23.545507);
AddCheckpointToRace(lsrace, 2342.461669, -1513.188110, 23.564939);
AddCheckpointToRace(lsrace, 2300.728759, -1565.118164, 14.730288);
AddCheckpointToRace(lsrace, 2164.391357, -1532.709472, 2.032401);
AddCheckpointToRace(lsrace, 2042.412719, -1503.038574, 3.047770);
AddCheckpointToRace(lsrace, 1948.191284, -1518.647460, 3.063310);
AddCheckpointToRace(lsrace, 1851.070434, -1551.060546, 12.822020);
AddCheckpointToRace(lsrace, 1818.930175, -1665.781372, 13.110196);
AddCheckpointToRace(lsrace, 1907.059204, -1754.055419, 13.109704);
AddCheckpointToRace(lsrace, 2023.382446, -1753.830566, 13.109979);
AddCheckpointToRace(lsrace, 2189.188476, -1699.546752, 13.243209);
AddCheckpointToRace(lsrace, 2245.878662, -1653.323486, 15.011875);
AddCheckpointToRace(lsrace, 2381.359863, -1660.972656, 13.109755);
return 1;
}
CMD:addcheckpoint(playerid, params[])
{
new string[128];
new Float:X, Float:Z, Float:Y;
GetPlayerPos(playerid, X, Y, Z);
new File:pos=fopen("race.txt", io_append);
format(string, 128, "AddCheckpointToRace(%s, %f, %f, %f);\n", params, X, Y, Z);
fwrite(pos, string);
fclose(pos);
return 1;
}
pawn Код:
It is based on [HiC]TheKiller's exporting method and uses sscanf2. Lorenc.txt Код:
AddCheckpointToRace(race2, 2915.456787, -1622.428466, 12.435916); AddCheckpointToRace(race2, 2910.672363, -1637.185913, 12.395952); AddCheckpointToRace(race2, 2903.093994, -1660.151611, 12.430374); AddCheckpointToRace(race2, 2898.300048, -1675.741333, 12.457112); AddCheckpointToRace(race2, 2890.918457, -1702.602905, 12.493884); |
"THANKS LORENC FOR HELPING ME TEST" would be awesome, todaywasagoodday.jpg
|
estimated max. usage: unknown, due to recursion
%d:%02d.%03d
%d:0%d:%d00
I've been waiting for a race tutorial like this for a long time. Very nice effort and very good explained.
EDIT: I can see what you were talking about. pawn Код:
pawn Код:
pawn Код:
|
stock LoadRaceFromFile( const szFileName[ ], const szFileFormat[ ] = ".txt" )
{
if( !fexist( szFileName ) )
return 0;
new
File: fHandle = fopen( szFileName, io_read ),
szName[ 24 ],
szLine[ 128 ],
Float: X, Float: Y, Float: Z,
iCheckpoints = 0
;
strmid( szName, szFileName, 0, cellmax );
strdel( szName, strfind( szName, szFileFormat), cellmax );
new id = CreateRace( szName, 300 );
while( fread( fHandle, szLine ) )
{
if( isnull( szLine ) ) continue;
unformat( szLine, "'AddCheckpointToRace('p<,>s[24]fff');'", szLine, X, Y, Z );
AddCheckpointToRace( id, X, Y, Z );
iCheckpoints++;
}
printf( "Race %s has been loaded with %d checkpoints!", szName, iCheckpoints );
fclose( fHandle );
return 1;
}
AddCheckpointToRace(race2, 2915.456787, -1622.428466, 12.435916); AddCheckpointToRace(race2, 2910.672363, -1637.185913, 12.395952); AddCheckpointToRace(race2, 2903.093994, -1660.151611, 12.430374); AddCheckpointToRace(race2, 2898.300048, -1675.741333, 12.457112); AddCheckpointToRace(race2, 2890.918457, -1702.602905, 12.493884);