X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fserver%2Fmutators%2Fmutator%2Fgamemode_race.qc;h=d1fa685f7ae5cc2a8402bc8883f4d4878af76430;hb=75f32635eb47f324db31c8f257c935018dedbc23;hp=cc250dfc73e75f870ee649071ac9e2d6c3655b41;hpb=ae8867e3301e6cdda736e245858932f8f36d71f1;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/server/mutators/mutator/gamemode_race.qc b/qcsrc/server/mutators/mutator/gamemode_race.qc index cc250dfc7..d1fa685f7 100644 --- a/qcsrc/server/mutators/mutator/gamemode_race.qc +++ b/qcsrc/server/mutators/mutator/gamemode_race.qc @@ -1,3 +1,5 @@ +#include "gamemode_race.qh" + #ifndef GAMEMODE_RACE_H #define GAMEMODE_RACE_H @@ -6,12 +8,12 @@ void race_Initialize(); REGISTER_MUTATOR(rc, false) { - rc_SetLimits(); - MUTATOR_ONADD { if (time > 1) // game loads at time 1 error("This is a game type and it cannot be added at runtime."); + + rc_SetLimits(); race_Initialize(); } @@ -31,18 +33,11 @@ REGISTER_MUTATOR(rc, false) return 0; } -float race_teams; - -// scores -const float ST_RACE_LAPS = 1; -const float SP_RACE_LAPS = 4; -const float SP_RACE_TIME = 5; -const float SP_RACE_FASTEST = 6; #endif #ifdef IMPLEMENTATION -#include "../../race.qh" +#include #define autocvar_g_race_laps_limit cvar("g_race_laps_limit") float autocvar_g_race_qualifying_timelimit; @@ -51,30 +46,30 @@ int autocvar_g_race_teams; // legacy bot roles .float race_checkpoint; -void havocbot_role_race() -{SELFPARAM(); - if(self.deadflag != DEAD_NO) +void havocbot_role_race(entity this) +{ + if(IS_DEAD(this)) return; entity e; - if (self.bot_strategytime < time) + if (this.bot_strategytime < time) { - self.bot_strategytime = time + autocvar_bot_ai_strategyinterval; - navigation_goalrating_start(); + this.bot_strategytime = time + autocvar_bot_ai_strategyinterval; + navigation_goalrating_start(this); for(e = world; (e = find(e, classname, "trigger_race_checkpoint")) != world; ) { - if(e.cnt == self.race_checkpoint) + if(e.cnt == this.race_checkpoint) { - navigation_routerating(e, 1000000, 5000); + navigation_routerating(this, e, 1000000, 5000); } - else if(self.race_checkpoint == -1) + else if(this.race_checkpoint == -1) { - navigation_routerating(e, 1000000, 5000); + navigation_routerating(this, e, 1000000, 5000); } } - navigation_goalrating_end(); + navigation_goalrating_end(this); } } @@ -107,25 +102,65 @@ void race_EventLog(string mode, entity actor) // use an alias for easy changing GameLogEcho(strcat(":race:", mode, ":", ((actor != world) ? (strcat(":", ftos(actor.playerid))) : ""))); } +float WinningCondition_Race(float fraglimit) +{ + float wc; + float n, c; + + n = 0; + c = 0; + FOREACH_CLIENT(IS_PLAYER(it), LAMBDA( + ++n; + if(it.race_completed) + ++c; + )); + if(n && (n == c)) + return WINNING_YES; + wc = WinningCondition_Scores(fraglimit, 0); + + // ALWAYS initiate overtime, unless EVERYONE has finished the race! + if(wc == WINNING_YES || wc == WINNING_STARTSUDDENDEATHOVERTIME) + // do NOT support equality when the laps are all raced! + return WINNING_STARTSUDDENDEATHOVERTIME; + else + return WINNING_NEVER; +} + +float WinningCondition_QualifyingThenRace(float limit) +{ + float wc; + wc = WinningCondition_Scores(limit, 0); + + // NEVER initiate overtime + if(wc == WINNING_YES || wc == WINNING_STARTSUDDENDEATHOVERTIME) + { + return WINNING_YES; + } + + return wc; +} + MUTATOR_HOOKFUNCTION(rc, PlayerPhysics) -{SELFPARAM(); - self.race_movetime_frac += PHYS_INPUT_TIMELENGTH; - float f = floor(self.race_movetime_frac); - self.race_movetime_frac -= f; - self.race_movetime_count += f; - self.race_movetime = self.race_movetime_frac + self.race_movetime_count; +{ + entity player = M_ARGV(0, entity); + + player.race_movetime_frac += PHYS_INPUT_TIMELENGTH; + float f = floor(player.race_movetime_frac); + player.race_movetime_frac -= f; + player.race_movetime_count += f; + player.race_movetime = player.race_movetime_frac + player.race_movetime_count; #ifdef SVQC - if(IS_PLAYER(self)) + if(IS_PLAYER(player)) { - if (self.race_penalty) - if (time > self.race_penalty) - self.race_penalty = 0; - if(self.race_penalty) + if (player.race_penalty) + if (time > player.race_penalty) + player.race_penalty = 0; + if(player.race_penalty) { - self.velocity = '0 0 0'; - self.movetype = MOVETYPE_NONE; - self.disableclientprediction = 2; + player.velocity = '0 0 0'; + player.movetype = MOVETYPE_NONE; + player.disableclientprediction = 2; } } #endif @@ -138,8 +173,8 @@ MUTATOR_HOOKFUNCTION(rc, PlayerPhysics) // ensure nothing EVIL is being done (i.e. div0_evade) // this hinders joystick users though // but it still gives SOME analog control - wishvel.x = fabs(self.movement.x); - wishvel.y = fabs(self.movement.y); + wishvel.x = fabs(player.movement.x); + wishvel.y = fabs(player.movement.y); if(wishvel.x != 0 && wishvel.y != 0 && wishvel.x != wishvel.y) { wishvel.z = 0; @@ -147,36 +182,34 @@ MUTATOR_HOOKFUNCTION(rc, PlayerPhysics) if(wishvel.x >= 2 * wishvel.y) { // pure X motion - if(self.movement.x > 0) - self.movement_x = wishspeed; + if(player.movement.x > 0) + player.movement_x = wishspeed; else - self.movement_x = -wishspeed; - self.movement_y = 0; + player.movement_x = -wishspeed; + player.movement_y = 0; } else if(wishvel.y >= 2 * wishvel.x) { // pure Y motion - self.movement_x = 0; - if(self.movement.y > 0) - self.movement_y = wishspeed; + player.movement_x = 0; + if(player.movement.y > 0) + player.movement_y = wishspeed; else - self.movement_y = -wishspeed; + player.movement_y = -wishspeed; } else { // diagonal - if(self.movement.x > 0) - self.movement_x = M_SQRT1_2 * wishspeed; + if(player.movement.x > 0) + player.movement_x = M_SQRT1_2 * wishspeed; else - self.movement_x = -M_SQRT1_2 * wishspeed; - if(self.movement.y > 0) - self.movement_y = M_SQRT1_2 * wishspeed; + player.movement_x = -M_SQRT1_2 * wishspeed; + if(player.movement.y > 0) + player.movement_y = M_SQRT1_2 * wishspeed; else - self.movement_y = -M_SQRT1_2 * wishspeed; + player.movement_y = -M_SQRT1_2 * wishspeed; } } - - return false; } MUTATOR_HOOKFUNCTION(rc, reset_map_global) @@ -188,17 +221,15 @@ MUTATOR_HOOKFUNCTION(rc, reset_map_global) race_ClearRecords(); PlayerScore_Sort(race_place, 0, 1, 0); - entity e; - FOR_EACH_CLIENT(e) - { - if(e.race_place) + FOREACH_CLIENT(true, LAMBDA( + if(it.race_place) { - s = PlayerScore_Add(e, SP_RACE_FASTEST, 0); + s = PlayerScore_Add(it, SP_RACE_FASTEST, 0); if(!s) - e.race_place = 0; + it.race_place = 0; } - race_EventLog(ftos(e.race_place), e); - } + race_EventLog(ftos(it.race_place), it); + )); if(g_race_qualifying == 2) { @@ -209,30 +240,20 @@ MUTATOR_HOOKFUNCTION(rc, reset_map_global) cvar_set("timelimit", ftos(race_timelimit)); race_ScoreRules(); } - - return false; -} - -MUTATOR_HOOKFUNCTION(rc, PlayerPreThink) -{SELFPARAM(); - if(IS_SPEC(self) || IS_OBSERVER(self)) - if(g_race_qualifying) - if(msg_entity.enemy.race_laptime) - race_SendNextCheckpoint(msg_entity.enemy, 1); - - return false; } MUTATOR_HOOKFUNCTION(rc, ClientConnect) -{SELFPARAM(); - race_PreparePlayer(); - self.race_checkpoint = -1; +{ + entity player = M_ARGV(0, entity); + + race_PreparePlayer(player); + player.race_checkpoint = -1; string rr = RACE_RECORD; - if(IS_REAL_CLIENT(self)) + if(IS_REAL_CLIENT(player)) { - msg_entity = self; + msg_entity = player; race_send_recordtime(MSG_ONE); race_send_speedaward(MSG_ONE); @@ -246,88 +267,93 @@ MUTATOR_HOOKFUNCTION(rc, ClientConnect) race_SendRankings(i, 0, 0, MSG_ONE); } } - - return false; } MUTATOR_HOOKFUNCTION(rc, MakePlayerObserver) -{SELFPARAM(); +{ + entity player = M_ARGV(0, entity); + if(g_race_qualifying) - if(PlayerScore_Add(self, SP_RACE_FASTEST, 0)) - self.frags = FRAGS_LMS_LOSER; + if(PlayerScore_Add(player, SP_RACE_FASTEST, 0)) + player.frags = FRAGS_LMS_LOSER; else - self.frags = FRAGS_SPECTATOR; + player.frags = FRAGS_SPECTATOR; - race_PreparePlayer(); - self.race_checkpoint = -1; - - return false; + race_PreparePlayer(player); + player.race_checkpoint = -1; } MUTATOR_HOOKFUNCTION(rc, PlayerSpawn) -{SELFPARAM(); +{ + entity player = M_ARGV(0, entity); + entity spawn_spot = M_ARGV(1, entity); + if(spawn_spot.target == "") // Emergency: this wasn't a real spawnpoint. Can this ever happen? - race_PreparePlayer(); + race_PreparePlayer(player); // if we need to respawn, do it right - self.race_respawn_checkpoint = self.race_checkpoint; - self.race_respawn_spotref = spawn_spot; + player.race_respawn_checkpoint = player.race_checkpoint; + player.race_respawn_spotref = spawn_spot; - self.race_place = 0; - - return false; + player.race_place = 0; } MUTATOR_HOOKFUNCTION(rc, PutClientInServer) -{SELFPARAM(); - if(IS_PLAYER(self)) +{ + entity player = M_ARGV(0, entity); + + if(IS_PLAYER(player)) if(!gameover) { - if(self.killcount == -666 /* initial spawn */ || g_race_qualifying) // spawn - race_PreparePlayer(); + if(player.killcount == FRAGS_SPECTATOR /* initial spawn */ || g_race_qualifying) // spawn + race_PreparePlayer(player); else // respawn - race_RetractPlayer(); + race_RetractPlayer(player); - race_AbandonRaceCheck(self); + race_AbandonRaceCheck(player); } - return false; } MUTATOR_HOOKFUNCTION(rc, PlayerDies) -{SELFPARAM(); - self.respawn_flags |= RESPAWN_FORCE; - race_AbandonRaceCheck(self); - return false; +{ + entity frag_target = M_ARGV(2, entity); + + frag_target.respawn_flags |= RESPAWN_FORCE; + race_AbandonRaceCheck(frag_target); } MUTATOR_HOOKFUNCTION(rc, HavocBot_ChooseRole) -{SELFPARAM(); - self.havocbot_role = havocbot_role_race; +{ + entity bot = M_ARGV(0, entity); + + bot.havocbot_role = havocbot_role_race; return true; } MUTATOR_HOOKFUNCTION(rc, GetPressedKeys) -{SELFPARAM(); - if(self.cvar_cl_allow_uidtracking == 1 && self.cvar_cl_allow_uid2name == 1) +{ + entity player = M_ARGV(0, entity); + + if(player.cvar_cl_allow_uidtracking == 1 && player.cvar_cl_allow_uid2name == 1) { - if (!self.stored_netname) - self.stored_netname = strzone(uid2name(self.crypto_idfp)); - if(self.stored_netname != self.netname) + if (!player.stored_netname) + player.stored_netname = strzone(uid2name(player.crypto_idfp)); + if(player.stored_netname != player.netname) { - db_put(ServerProgsDB, strcat("/uid2name/", self.crypto_idfp), self.netname); - strunzone(self.stored_netname); - self.stored_netname = strzone(self.netname); + db_put(ServerProgsDB, strcat("/uid2name/", player.crypto_idfp), player.netname); + strunzone(player.stored_netname); + player.stored_netname = strzone(player.netname); } } - if (!IS_OBSERVER(self)) + if (!IS_OBSERVER(player)) { - if (vlen(self.velocity - self.velocity_z * '0 0 1') > speedaward_speed) + if(vdist(player.velocity - player.velocity_z * '0 0 1', >, speedaward_speed)) { - speedaward_speed = vlen(self.velocity - self.velocity_z * '0 0 1'); - speedaward_holder = self.netname; - speedaward_uid = self.crypto_idfp; + speedaward_speed = vlen(player.velocity - player.velocity_z * '0 0 1'); + speedaward_holder = player.netname; + speedaward_uid = player.crypto_idfp; speedaward_lastupdate = time; } if (speedaward_speed > speedaward_lastsent && time - speedaward_lastupdate > 1) @@ -346,21 +372,17 @@ MUTATOR_HOOKFUNCTION(rc, GetPressedKeys) } } } - return false; } MUTATOR_HOOKFUNCTION(rc, ForbidPlayerScore_Clear) { if(g_race_qualifying) return true; // in qualifying, you don't lose score by observing - - return false; } MUTATOR_HOOKFUNCTION(rc, GetTeamCount, CBC_ORDER_EXCLUSIVE) { - ret_float = race_teams; - return false; + M_ARGV(0, float) = race_teams; } MUTATOR_HOOKFUNCTION(rc, Scores_CountFragsRemaining) @@ -368,12 +390,13 @@ MUTATOR_HOOKFUNCTION(rc, Scores_CountFragsRemaining) // announce remaining frags if not in qualifying mode if(!g_race_qualifying) return true; - - return false; } MUTATOR_HOOKFUNCTION(rc, GetRecords) { + int record_page = M_ARGV(0, int); + string ret_string = M_ARGV(1, string); + for(int i = record_page * 200; i < MapInfo_count && i < record_page * 200 + 200; ++i) { if(MapInfo_Get_ByID(i)) @@ -388,31 +411,40 @@ MUTATOR_HOOKFUNCTION(rc, GetRecords) } } - return false; + M_ARGV(1, string) = ret_string; } MUTATOR_HOOKFUNCTION(rc, FixClientCvars) { - stuffcmd(fix_client, "cl_cmd settemp cl_movecliptokeyboard 2\n"); - return false; + entity player = M_ARGV(0, entity); + + stuffcmd(player, "cl_cmd settemp cl_movecliptokeyboard 2\n"); } MUTATOR_HOOKFUNCTION(rc, CheckRules_World) { - if(g_race_qualifying == 2 && checkrules_timelimit >= 0) + float checkrules_timelimit = M_ARGV(1, float); + float checkrules_fraglimit = M_ARGV(2, float); + + if(checkrules_timelimit >= 0) { - ret_float = WinningCondition_QualifyingThenRace(checkrules_fraglimit); - return true; + if(!g_race_qualifying) + { + M_ARGV(0, float) = WinningCondition_Race(checkrules_fraglimit); + return true; + } + else if(g_race_qualifying == 2) + { + M_ARGV(0, float) = WinningCondition_QualifyingThenRace(checkrules_fraglimit); + return true; + } } - - return false; } MUTATOR_HOOKFUNCTION(rc, ReadLevelCvars) { if(g_race_qualifying == 2) warmup_stage = 0; - return false; } void race_Initialize() @@ -439,9 +471,8 @@ void rc_SetLimits() qualifying_override = autocvar_g_race_qualifying_timelimit_override; fraglimit_override = autocvar_g_race_laps_limit; leadlimit_override = 0; // currently not supported by race - timelimit_override = -1; // use default if we don't set it below + timelimit_override = autocvar_timelimit_override; - // we need to find out the correct value for g_race_qualifying float want_qualifying = ((qualifying_override >= 0) ? qualifying_override : autocvar_g_race_qualifying_timelimit) > 0; if(autocvar_g_campaign) @@ -449,20 +480,20 @@ void rc_SetLimits() g_race_qualifying = 1; independent_players = 1; } - else if(!autocvar_g_campaign && want_qualifying) + else if(want_qualifying) { g_race_qualifying = 2; independent_players = 1; - race_fraglimit = (race_fraglimit >= 0) ? fraglimit_override : autocvar_fraglimit; - race_leadlimit = (race_leadlimit >= 0) ? leadlimit_override : autocvar_leadlimit; - race_timelimit = (race_timelimit >= 0) ? timelimit_override : autocvar_timelimit; + race_fraglimit = (fraglimit_override >= 0) ? fraglimit_override : autocvar_fraglimit; + race_leadlimit = (leadlimit_override >= 0) ? leadlimit_override : autocvar_leadlimit; + race_timelimit = (timelimit_override >= 0) ? timelimit_override : autocvar_timelimit; + qualifying_override = (qualifying_override >= 0) ? qualifying_override : autocvar_g_race_qualifying_timelimit; fraglimit_override = 0; leadlimit_override = 0; - timelimit_override = autocvar_g_race_qualifying_timelimit; + timelimit_override = qualifying_override; } else g_race_qualifying = 0; - SetLimits(fraglimit_override, leadlimit_override, timelimit_override, qualifying_override); }