#include #include #include #include //http://zeex.pastebin.ca/1641138 #define MAX_RACE_RACE_CHECKPOINTS 100 #define MAX_RACE_PICKUPS 50 #define MAX_RACE_NAME 32 #define RACE_UPDATE_INTERVAL 1000 #define RACE_BOOST_EFFECT 1.5 #define RACE_BOOM_RADIUS 5.0 #define RACE_REPAIR_DAMAGE 0.8 #define RACE_DRUNK_TIME 15000 #define RACE_PICKUP_TYPE_NITRO 0 #define RACE_PICKUP_TYPE_REPAIR 3096 #define RACE_PICKUP_TYPE_BOOST 1237 //#define RACE_PICKUP_TYPE_BOOM 1254 #define RACE_PICKUP_TYPE_BEER 1484 #define cpdata(%1,%2) \ gRaceCheckpoints[%1][E_RACE_CHECKPOINT_%2] #define sqdist(%1,%2,%3,%4,%5,%6) \ ((%1 - %4)*(%1 - %4) + (%2 - %5)*(%2 - %5) + (%3 - %6)*(%3 - %6)) #define near(%1,%2) \ (%1 + (%2)*floatsin(random(cellmax))) enum E_RACE_PICKUP { E_RACE_PICKUP_ID, E_RACE_PICKUP_TYPE, Float:E_RACE_PICKUP_XPOS, Float:E_RACE_PICKUP_YPOS, Float:E_RACE_PICKUP_ZPOS, } enum E_RACE_RACE_CHECKPOINT { E_RACE_CHECKPOINT_TYPE, Float:E_RACE_CHECKPOINT_XPOS, Float:E_RACE_CHECKPOINT_YPOS, Float:E_RACE_CHECKPOINT_ZPOS, Float:E_RACE_CHECKPOINT_SIZE, } enum e_RACE_STATE { e_RACE_STATE_NONE, e_RACE_STATE_ACTIVE, e_RACE_STATE_STARTED, } enum E_RACE { E_RACE_NAME[MAX_RACE_NAME], e_RACE_STATE:E_RACE_STATE, E_RACE_CHECKPOINTS, E_RACE_PICKUPS, E_RACE_LAPS, E_RACE_PLAYERS, E_RACE_WORLD, E_RACE_UPD_TIMER, E_RACE_PSDELAY, } enum E_RACE_PLAYER { E_PLAYER_RACER, E_PLAYER_CUR_CP, E_PLAYER_CUR_LAP, E_PLAYER_CUR_POS, E_PLAYER_WORLD, Float:E_PLAYER_POS[3], Text:E_PLAYER_TEXT, } new gRaceData[E_RACE], gPlayerData[MAX_PLAYERS][E_RACE_PLAYER], gRacePickups[MAX_RACE_PICKUPS][E_RACE_PICKUP], gRaceCheckpoints[MAX_RACE_RACE_CHECKPOINTS][E_RACE_RACE_CHECKPOINT]; Itter_Create(Racer, MAX_PLAYERS); forward TogglePlayerShooting(playerid, bool:toggle); forward RaceCountdown(value); forward OnRaceMapEntryRead(block[], name[], value[]); forward UpdatePlayers(); forward RecreateRacePickup(pickup); forward ResetDrunkLevel(playerid); public OnFilterScriptInit() { for (new i; i < MAX_PLAYERS; i++) { if (IsPlayerConnected(i)) { Itter_Add(Player, i); } } return 1; } public OnFilterScriptExit() { StopRace(); return 1; } public OnPlayerEnterRaceCheckpoint(playerid) { if (gRaceData[E_RACE_STATE] == e_RACE_STATE_STARTED) { new cp = gPlayerData[playerid][E_PLAYER_CUR_CP], lap = gPlayerData[playerid][E_PLAYER_CUR_LAP], cpcount = gRaceData[E_RACE_CHECKPOINTS], lapcount = gRaceData[E_RACE_LAPS]; if (++cp >= cpcount) { if (++lap >= lapcount) { if (gPlayerData[playerid][E_PLAYER_CUR_POS] == 1) { GameTextForPlayer(playerid, "~h~~y~YOU WON!", 5000, 6); } else { GameTextForPlayer(playerid, "~h~~b~FINISH!", 3000, 6); } RemovePlayerFromRace(playerid); if (!gRaceData[E_RACE_PLAYERS]) { return StopRace(); } } cp = 0; } gPlayerData[playerid][E_PLAYER_CUR_CP] = cp; gPlayerData[playerid][E_PLAYER_CUR_LAP] = lap; SetRaceCheckpoint(playerid); } return 1; } public OnPlayerPickUpPickup(playerid, pickupid) { SendClientMessage(playerid, 0x00FFFFFF, "pickup!"); if (!gPlayerData[playerid][E_PLAYER_RACER] || gRaceData[E_RACE_STATE] != e_RACE_STATE_STARTED) return 0; for (new pickup; pickup < MAX_RACE_PICKUPS; pickup++) { if (gRacePickups[pickup][E_RACE_PICKUP_ID] == pickupid) { switch (gRacePickups[pickup][E_RACE_PICKUP_TYPE]) { case RACE_PICKUP_TYPE_BEER: { SetPlayerDrunkLevel(playerid, 10000); SetTimerEx("ResetDrunkLevel", RACE_DRUNK_TIME, false, "i", playerid); } case RACE_PICKUP_TYPE_NITRO: { AddVehicleComponent(GetPlayerVehicleID(playerid), 1009); PlayerPlaySound(playerid, 1133, 0.0, 0.0, 0.0); } case RACE_PICKUP_TYPE_REPAIR: { new Float:vhealth; GetVehicleHealth(GetPlayerVehicleID(playerid), vhealth); if (vhealth <= RACE_REPAIR_DAMAGE*1000.0) { RepairVehicle(GetPlayerVehicleID(playerid)); PlayerPlaySound(playerid, 1134, 0.0, 0.0, 0.0); } else { return RecreateRacePickup(pickup); } } case RACE_PICKUP_TYPE_BOOST: { new Float:vX, Float:vY, Float:vZ; GetVehicleVelocity(GetPlayerVehicleID(playerid), vX, vY, vZ); SetVehicleVelocity(GetPlayerVehicleID(playerid), vX*RACE_BOOST_EFFECT, vY*RACE_BOOST_EFFECT, vZ*RACE_BOOST_EFFECT); PlayerPlaySound(playerid, 1190 , 0.0, 0.0, 0.0); } /*case RACE_PICKUP_TYPE_BOOM: { new Float:x, Float:y, Float:z; GetPlayerPos(playerid, x, y, z); CreateExplosion(near(x, RACE_BOOM_RADIUS*2), near(y, RACE_BOOM_RADIUS*2), z, 5, RACE_BOOM_RADIUS); PlayerPlaySound(playerid, 1159 , 0.0, 0.0, 0.0); } */ } SetTimerEx("RecreateRacePickup", gRaceData[E_RACE_PSDELAY]*1000, false, "i", pickup); break; } } return 1; } public OnPlayerConnect(playerid) { if (gRaceData[E_RACE_STATE] == e_RACE_STATE_ACTIVE) { SetRaceCheckpoint(playerid); } return 1; } public OnPlayerDeath(playerid, killerid, reason) { RemovePlayerFromRace(playerid); return 1; } public OnPlayerDisconnect(playerid, reason) { RemovePlayerFromRace(playerid); return 1; } public OnRaceMapEntryRead(block[], name[], value[]) { //printf("block=\"%s\" | name=\"%s\" | value=\"%s\"", block, name, value); if (!strcmp(block, "GENERAL", true)) { if (!strcmp(name, "name", true)) { format(gRaceData[E_RACE_NAME], MAX_RACE_NAME, "%s", value); printf("name = %s", gRaceData[E_RACE_NAME]); } else if (!strcmp(name, "laps", true)) { gRaceData[E_RACE_LAPS] = strval(value); printf("laps = %d", gRaceData[E_RACE_LAPS]); } else if (!strcmp(name, "world", true)) { gRaceData[E_RACE_WORLD] = strval(value); printf("world = %d", gRaceData[E_RACE_WORLD]); } else if (!strcmp(name, "psdelay", true)) { gRaceData[E_RACE_PSDELAY] = strval(value); printf("psdelay = %d", gRaceData[E_RACE_PSDELAY]); } } else if (!strcmp(block, "CHECKPOINTS", true)) { new type; if (!strcmp(name, "NORMAL", true)) { type = 0; } else if (!strcmp(name, "FINISH", true)) { type = 1; } else if (!strcmp(name, "START", true)) { type = 2; } else if (!strcmp(name, "AIRNORMAL", true)) { type = 3; } else if (!strcmp(name, "AIRFINISH", true)) { type = 4; } else { return 1; } new Float:x, Float:y, Float:z, Float:size; if (!sscanf(value, "ffff", x, y, z, size)) { new count = gRaceData[E_RACE_CHECKPOINTS]; if (count >= MAX_RACE_RACE_CHECKPOINTS) return 1; gRaceCheckpoints[count][E_RACE_CHECKPOINT_TYPE] = type; gRaceCheckpoints[count][E_RACE_CHECKPOINT_XPOS] = x; gRaceCheckpoints[count][E_RACE_CHECKPOINT_YPOS] = y; gRaceCheckpoints[count][E_RACE_CHECKPOINT_ZPOS] = z; gRaceCheckpoints[count][E_RACE_CHECKPOINT_SIZE] = size; printf("checkpoint: %d %f %f %f %f", type, x, y, z, size); gRaceData[E_RACE_CHECKPOINTS]++; } } else if (!strcmp(block, "PICKUPS", true)) { new type; if (!strcmp(name, "NITRO", true)) { type = RACE_PICKUP_TYPE_NITRO; } else if (!strcmp(name, "REPAIR", true)) { type = RACE_PICKUP_TYPE_REPAIR; } /*else if (!strcmp(name, "BOOM", true)) { type = RACE_PICKUP_TYPE_BOOM; }*/ else if (!strcmp(name, "BEER", true)) { type = RACE_PICKUP_TYPE_BEER; } else if (!strcmp(name, "BOOST", true)) { type = RACE_PICKUP_TYPE_BOOST; } else { return 1; } new Float:x, Float:y, Float:z; if (!sscanf(value, "fff", x, y, z)) { new count = gRaceData[E_RACE_PICKUPS]; if (count >= MAX_RACE_PICKUPS) return 1; gRacePickups[count][E_RACE_PICKUP_ID] = CreatePickup(type, 14, x, y, z, gRaceData[E_RACE_WORLD]); gRacePickups[count][E_RACE_PICKUP_TYPE] = type; gRacePickups[count][E_RACE_PICKUP_XPOS] = x; gRacePickups[count][E_RACE_PICKUP_YPOS] = y; gRacePickups[count][E_RACE_PICKUP_ZPOS] = z; printf("pickup: %d %f %f %f ||| %d", type, x, y, z, gRacePickups[count][E_RACE_PICKUP_ID]); gRaceData[E_RACE_PICKUPS]++; } } return 1; } public RaceCountdown(value) { if (value > 0) { new text[3]; valstr(text, value); foreach (Racer, i) { SetCameraBehindPlayer(i); TogglePlayerControllable(i, false); PlayerPlaySound(i, 1056 , 0.0, 0.0, 0.0); GameTextForPlayer(i, text, 1500, 6); } SetTimerEx("RaceCountdown", 1000, false, "i", --value); } else { foreach (Racer, i) { TogglePlayerControllable(i, true); PlayerPlaySound(i, 1057 , 0.0, 0.0, 0.0); GameTextForPlayer(i, "~h~~h~~w~GO!", 3000, 6); gPlayerData[i][E_PLAYER_CUR_CP] = 1; SetRaceCheckpoint(i); } gRaceData[E_RACE_UPD_TIMER] = SetTimer("UpdatePlayers", RACE_UPDATE_INTERVAL, true); } return 1; } public UpdatePlayers() { new bool:first = true, playerLap, playerCP, otherLap, otherCP, Float:playerX, Float:playerY, Float:playerZ, Float:otherX, Float:otherY, Float:otherZ, Float:cpX, Float:cpY, Float:cpZ; foreach (Racer, i) { gPlayerData[i][E_PLAYER_CUR_POS] = 1; playerCP = gPlayerData[i][E_PLAYER_CUR_CP]; playerLap = gPlayerData[i][E_PLAYER_CUR_LAP]; cpX = gRaceCheckpoints[playerCP][E_RACE_CHECKPOINT_XPOS]; cpY = gRaceCheckpoints[playerCP][E_RACE_CHECKPOINT_YPOS]; cpZ = gRaceCheckpoints[playerCP][E_RACE_CHECKPOINT_ZPOS]; if (first) { GetPlayerPos(i, playerX, playerY, playerZ); gPlayerData[i][E_PLAYER_POS][0] = playerX; gPlayerData[i][E_PLAYER_POS][1] = playerY; gPlayerData[i][E_PLAYER_POS][2] = playerZ; } else { playerX = gPlayerData[i][E_PLAYER_POS][0]; playerY = gPlayerData[i][E_PLAYER_POS][1]; playerZ = gPlayerData[i][E_PLAYER_POS][2]; } foreach (Racer, j) { if (i == j) continue; otherCP = gPlayerData[j][E_PLAYER_CUR_CP]; otherLap = gPlayerData[j][E_PLAYER_CUR_LAP]; if (playerLap == otherLap || playerCP == otherCP) { if (first) { GetPlayerPos(j, otherX, otherY, otherZ); gPlayerData[j][E_PLAYER_POS][0] = otherX; gPlayerData[j][E_PLAYER_POS][1] = otherY; gPlayerData[j][E_PLAYER_POS][2] = otherZ; } else { otherX = gPlayerData[j][E_PLAYER_POS][0]; otherY = gPlayerData[j][E_PLAYER_POS][1]; otherZ = gPlayerData[j][E_PLAYER_POS][2]; } if (sqdist(playerX, playerY, playerZ, cpX, cpY, cpZ) < sqdist(otherX, otherY, otherZ, cpX, cpY, cpZ)) { gPlayerData[i][E_PLAYER_CUR_POS]++; } } } UpdatePlayerRaceHUD(i); } return 1; } public RecreateRacePickup(pickup) { DestroyPickup(gRacePickups[pickup][E_RACE_PICKUP_ID]); gRacePickups[pickup][E_RACE_PICKUP_ID] = CreatePickup(gRacePickups[pickup][E_RACE_PICKUP_TYPE], 14, gRacePickups[pickup][E_RACE_PICKUP_XPOS], gRacePickups[pickup][E_RACE_PICKUP_YPOS], gRacePickups[pickup][E_RACE_PICKUP_ZPOS], gRaceData[E_RACE_WORLD]); return 1; } public ResetDrunkLevel(playerid) { return SetPlayerDrunkLevel(playerid, 0); } StartRace() { if (gRaceData[E_RACE_STATE] != e_RACE_STATE_ACTIVE) return 0; new racers; foreach (Player, i) { if (IsPlayerInRaceCheckpoint(i) && GetPlayerState(i) == PLAYER_STATE_DRIVER) { AddPlayerToRace(i); racers++; } else { DisablePlayerRaceCheckpoint(i); } } if (!racers) { StopRace(); } gRaceData[E_RACE_STATE] = e_RACE_STATE_STARTED; RaceCountdown(3); return 1; } StopRace() { if (gRaceData[E_RACE_STATE] != e_RACE_STATE_STARTED) return 0; foreach (Racer, i) { RemovePlayerFromRace(i); } for (new i; i < MAX_RACE_PICKUPS; i++) { if (gRacePickups[i][E_RACE_PICKUP_TYPE]) { DestroyPickup(gRacePickups[i][E_RACE_PICKUP_ID]); gRacePickups[i][E_RACE_PICKUP_TYPE] = 0; } } gRaceData[E_RACE_STATE] = e_RACE_STATE_NONE; KillTimer(gRaceData[E_RACE_UPD_TIMER]); return 1; } LoadRace(const filename[]) { gRaceData[E_RACE_LAPS] = 1; gRaceData[E_RACE_WORLD] = 0; gRaceData[E_RACE_PICKUPS] = 0; gRaceData[E_RACE_CHECKPOINTS] = 0; format(gRaceData[E_RACE_NAME], MAX_RACE_NAME, "~UNKNOWN~"); if (Conf_ParseFile(filename, "OnRaceMapEntryRead")) { gRaceData[E_RACE_STATE] = e_RACE_STATE_ACTIVE; foreach (Player, i) { SetRaceCheckpoint(i); } return 1; } return 0; } AddPlayerToRace(playerid) { if (Itter_Add(Racer, playerid)) { gRaceData[E_RACE_PLAYERS]++; gPlayerData[playerid][E_PLAYER_CUR_CP] = 0; gPlayerData[playerid][E_PLAYER_CUR_LAP] = 0; gPlayerData[playerid][E_PLAYER_CUR_POS] = 0; gPlayerData[playerid][E_PLAYER_RACER] = true; gPlayerData[playerid][E_PLAYER_WORLD] = GetPlayerVirtualWorld(playerid); SetPlayerVirtualWorld(playerid, gRaceData[E_RACE_WORLD]); SetVehicleVirtualWorld(GetPlayerVehicleID(playerid), gRaceData[E_RACE_WORLD]); CreatePlayerRaceHUD(playerid); return 1; } return 0; } RemovePlayerFromRace(playerid) { if (Itter_Remove(Racer, playerid)) { gRaceData[E_RACE_PLAYERS]--; gPlayerData[playerid][E_PLAYER_CUR_CP] = 0; gPlayerData[playerid][E_PLAYER_CUR_LAP] = 0; gPlayerData[playerid][E_PLAYER_CUR_POS] = 0; gPlayerData[playerid][E_PLAYER_RACER] = false; SetPlayerVirtualWorld(playerid, gPlayerData[playerid][E_PLAYER_WORLD]); SetVehicleVirtualWorld(GetPlayerVehicleID(playerid), gPlayerData[playerid][E_PLAYER_WORLD]); DisablePlayerRaceCheckpoint(playerid); DestroyPlayerRaceHUD(playerid); return 1; } return 0; } CreatePlayerRaceHUD(playerid) { gPlayerData[playerid][E_PLAYER_TEXT] = TextDrawCreate(320.0, 240.0, " "); return TextDrawShowForPlayer(playerid, gPlayerData[playerid][E_PLAYER_TEXT]); } DestroyPlayerRaceHUD(playerid) { TextDrawHideForAll(gPlayerData[playerid][E_PLAYER_TEXT]); return TextDrawDestroy(gPlayerData[playerid][E_PLAYER_TEXT]); } UpdatePlayerRaceHUD(playerid) { new HUDText[50]; format(HUDText, sizeof(HUDText), "POS:%d/%d~n~LAP:%d/%d", gPlayerData[playerid][E_PLAYER_CUR_POS], gRaceData[E_RACE_PLAYERS], gPlayerData[playerid][E_PLAYER_CUR_LAP]+1, gRaceData[E_RACE_LAPS]); TextDrawSetString(gPlayerData[playerid][E_PLAYER_TEXT], HUDText); return 1; } SetRaceCheckpoint(playerid) { new cur = gPlayerData[playerid][E_PLAYER_CUR_CP]; return SetPlayerRaceCheckpoint(playerid, cpdata(cur,TYPE), cpdata(cur,XPOS), cpdata(cur,YPOS), cpdata(cur,ZPOS), cpdata(cur+1,XPOS), cpdata(cur+1,YPOS), cpdata(cur+1,ZPOS), cpdata(cur,SIZE)); } public OnPlayerCommandText(playerid, cmdtext[]) { if (!strcmp("/load", cmdtext, true)) { LoadRace("testrace.race"); SendClientMessage(playerid, 0xFFFFFFFF, "Loaded!"); return 1; } if (!strcmp("/start", cmdtext, true)) { StartRace(); SendClientMessage(playerid, 0xFFFFFFFF, "Started!"); return 1; } return 0; }