X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fserver%2Fmutators%2Fmutator%2Fgamemode_race.qc;h=756d975b156ad197febcbe333455f85d9eaf246f;hb=868c953a2bff5ddb11700a7d160e66014d9704de;hp=cc250dfc73e75f870ee649071ac9e2d6c3655b41;hpb=5bbfb59ff40eca7824c231d687c2bf587a01749d;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..756d975b1 100644 --- a/qcsrc/server/mutators/mutator/gamemode_race.qc +++ b/qcsrc/server/mutators/mutator/gamemode_race.qc @@ -1,48 +1,6 @@ -#ifndef GAMEMODE_RACE_H -#define GAMEMODE_RACE_H +#include "gamemode_race.qh" -void rc_SetLimits(); -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."); - race_Initialize(); - } - - MUTATOR_ONROLLBACK_OR_REMOVE - { - // we actually cannot roll back race_Initialize here - // BUT: we don't need to! If this gets called, adding always - // succeeds. - } - - MUTATOR_ONREMOVE - { - LOG_INFO("This is a game type and it cannot be removed at runtime."); - return -1; - } - - 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 +9,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; ) + for(e = NULL; (e = find(e, classname, "trigger_race_checkpoint")) != NULL; ) { - 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); } } @@ -83,7 +41,7 @@ void race_ScoreRules() ScoreRules_basics(race_teams, 0, 0, false); if(race_teams) { - ScoreInfo_SetLabel_TeamScore( ST_RACE_LAPS, "laps", SFL_SORT_PRIO_PRIMARY); + ScoreInfo_SetLabel_TeamScore( ST_RACE_LAPS, "laps", SFL_SORT_PRIO_PRIMARY); ScoreInfo_SetLabel_PlayerScore(SP_RACE_LAPS, "laps", SFL_SORT_PRIO_PRIMARY); ScoreInfo_SetLabel_PlayerScore(SP_RACE_TIME, "time", SFL_SORT_PRIO_SECONDARY | SFL_LOWER_IS_BETTER | SFL_TIME); ScoreInfo_SetLabel_PlayerScore(SP_RACE_FASTEST, "fastest", SFL_LOWER_IS_BETTER | SFL_TIME); @@ -104,28 +62,69 @@ void race_ScoreRules() void race_EventLog(string mode, entity actor) // use an alias for easy changing and quick editing later { if(autocvar_sv_eventlog) - GameLogEcho(strcat(":race:", mode, ":", ((actor != world) ? (strcat(":", ftos(actor.playerid))) : ""))); + GameLogEcho(strcat(":race:", mode, ":", ((actor != NULL) ? (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); + float dt = M_ARGV(1, float); + + player.race_movetime_frac += dt; + 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'; + set_movetype(player, MOVETYPE_NONE); + player.disableclientprediction = 2; } } #endif @@ -138,8 +137,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,58 +146,54 @@ 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) { float s; - Score_NicePrint(world); + Score_NicePrint(NULL); 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 +204,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 +231,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; - - race_PreparePlayer(); - self.race_checkpoint = -1; + player.frags = FRAGS_SPECTATOR; - 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; - - self.race_place = 0; + player.race_respawn_checkpoint = player.race_checkpoint; + player.race_respawn_spotref = spawn_spot; - 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 +336,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 +354,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 +375,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() @@ -431,6 +427,14 @@ void rc_SetLimits() { ActivateTeamplay(); race_teams = bound(2, autocvar_g_race_teams, 4); + int teams = 0; + if(race_teams >= 1) teams |= BIT(0); + if(race_teams >= 2) teams |= BIT(1); + if(race_teams >= 3) teams |= BIT(2); + if(race_teams >= 4) teams |= BIT(3); + + race_teams = teams; // now set it? + have_team_spawns = -1; // request team spawns } else @@ -439,9 +443,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,21 +452,19 @@ 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); } - -#endif