From fa3b87545c85dfb69c3a7d82bdce1c3ee4a1c353 Mon Sep 17 00:00:00 2001 From: div0 Date: Sat, 19 Dec 2009 16:27:51 +0000 Subject: [PATCH] race: improved respawn handling: 1. when respawning after touching a CP, always spawn at a spawn connected to EXACTLY THAT CP (if available). 2. when respawning without touching a CP, always spawn at the same spawn again git-svn-id: svn://svn.icculus.org/nexuiz/trunk@8417 f962a42d-fe04-0410-a3ab-8c8b0445ebaa --- data/qcsrc/server/cl_client.qc | 54 ++++++++++++++++-------------- data/qcsrc/server/miscfunctions.qc | 10 +++--- data/qcsrc/server/race.qc | 47 +++++++++++++------------- data/qcsrc/server/race.qh | 3 ++ 4 files changed, 60 insertions(+), 54 deletions(-) diff --git a/data/qcsrc/server/cl_client.qc b/data/qcsrc/server/cl_client.qc index f4882d273..2ccb2fd42 100644 --- a/data/qcsrc/server/cl_client.qc +++ b/data/qcsrc/server/cl_client.qc @@ -74,8 +74,7 @@ void ClientData_Touch(entity e) } -#define SPAWNPOINT_SCORE frags - +.vector spawnpoint_score; .string netname_previous; void spawnfunc_info_player_survivor (void) @@ -105,31 +104,34 @@ void spawnpoint_use() }; // Returns: -// -1 if a spawn can't be used -// otherwise, a weight of the spawnpoint -float Spawn_Score(entity spot, entity playerlist, float teamcheck, float anypoint) +// _x: prio (-1 if unusable) +// _y: weight +vector Spawn_Score(entity spot, entity playerlist, float teamcheck, float anypoint) { float shortest, thisdist; + float prio; entity player; + prio = 0; + // filter out spots for the wrong team if(teamcheck) if(spot.team != teamcheck) - return -1; + return '-1 0 0'; if(race_spawns) if(spot.target == "") - return -1; + return '-1 0 0'; if(clienttype(self) == CLIENTTYPE_REAL) { if(spot.restriction == 1) - return -1; + return '-1 0 0'; } else { if(spot.restriction == 2) - return -1; + return '-1 0 0'; } // filter out spots for assault @@ -143,7 +145,7 @@ float Spawn_Score(entity spot, entity playerlist, float teamcheck, float anypoin { found = 1; if(ent.health < 0 || ent.health >= ASSAULT_VALUE_INACTIVE) - return -1; + return '-1 0 0'; good = 1; } else if(ent.classname == "trigger_race_checkpoint") @@ -156,14 +158,17 @@ float Spawn_Score(entity spot, entity playerlist, float teamcheck, float anypoin { // spawn at first if(ent.race_checkpoint != 0) - return -1; + return '-1 0 0'; if(spot.race_place != race_lowest_place_spawn) - return -1; + return '-1 0 0'; } else { - if(ent.race_checkpoint != race_PreviousCheckpoint(self.race_checkpoint)) - return -1; + if(ent.race_checkpoint != max(0, self.race_respawn_checkpoint)) + return '-1 0 0'; + // try reusing the previous spawn + if(ent == self.race_respawn_spotref || spot == self.race_respawn_spotref) + prio += 1; if(ent.race_checkpoint == 0) { float pl; @@ -172,9 +177,8 @@ float Spawn_Score(entity spot, entity playerlist, float teamcheck, float anypoin pl = 0; if(pl == 0 && !self.race_started) pl = race_highest_place_spawn; // use last place if he has not even touched finish yet - //print("race started? ", ftos(self.race_started), "\n"); if(spot.race_place != pl) - return -1; + return '-1 0 0'; } } } @@ -184,7 +188,7 @@ float Spawn_Score(entity spot, entity playerlist, float teamcheck, float anypoin } if(found && !good) - return -1; + return '-1 0 0'; } player = playerlist; @@ -196,7 +200,7 @@ float Spawn_Score(entity spot, entity playerlist, float teamcheck, float anypoin if (thisdist < shortest) shortest = thisdist; } - return shortest; + return prio * '1 0 0' + shortest * '0 1 0'; } float spawn_allbad; @@ -212,12 +216,12 @@ entity Spawn_FilterOutBadSpots(entity firstspot, entity playerlist, float mindis for(spot = firstspot; spot; spot = spot.chain) { - spot.SPAWNPOINT_SCORE = Spawn_Score(spot, playerlist, teamcheck, anypoint); + spot.spawnpoint_score = Spawn_Score(spot, playerlist, teamcheck, anypoint); if(cvar("spawn_debugview")) { setmodel(spot, "models/runematch/rune.mdl"); - if(spot.SPAWNPOINT_SCORE < mindist) + if(spot.spawnpoint_score_y < mindist) { spot.colormod = '1 0 0'; spot.scale = 1; @@ -225,13 +229,13 @@ entity Spawn_FilterOutBadSpots(entity firstspot, entity playerlist, float mindis else { spot.colormod = '0 1 0'; - spot.scale = spot.SPAWNPOINT_SCORE / mindist; + spot.scale = spot.spawnpoint_score_y / mindist; } } - if(spot.SPAWNPOINT_SCORE >= 0) // spawning allowed here + if(spot.spawnpoint_score_x >= 0) // spawning allowed here { - if(spot.SPAWNPOINT_SCORE < mindist) + if(spot.spawnpoint_score_y < mindist) { // too short distance spawn_allgood = FALSE; @@ -282,7 +286,7 @@ entity Spawn_WeightedPoint(entity firstspot, float lower, float upper, float exp RandomSelection_Init(); for(spot = firstspot; spot; spot = spot.chain) - RandomSelection_Add(spot, 0, string_null, pow(bound(lower, spot.SPAWNPOINT_SCORE, upper), exponent) * spot.cnt, spot.SPAWNPOINT_SCORE >= lower); + RandomSelection_Add(spot, 0, string_null, pow(bound(lower, spot.spawnpoint_score_y, upper), exponent) * spot.cnt, (spot.spawnpoint_score_y >= lower) * 0.5 + spot.spawnpoint_score_x); return RandomSelection_chosen_ent; } @@ -344,7 +348,7 @@ entity SelectSpawnPoint (float anypoint) if(cvar("spawn_debugview")) { - print("spot mindistance: ", ftos(spot.SPAWNPOINT_SCORE), "\n"); + print("spot mindistance: ", vtos(spot.spawnpoint_score), "\n"); entity e; if(teamcheck) diff --git a/data/qcsrc/server/miscfunctions.qc b/data/qcsrc/server/miscfunctions.qc index f13d01893..5524b7e91 100644 --- a/data/qcsrc/server/miscfunctions.qc +++ b/data/qcsrc/server/miscfunctions.qc @@ -685,12 +685,12 @@ void backtrace(string msg) war = cvar("prvm_backtraceforwarnings"); cvar_set("developer", "1"); cvar_set("prvm_backtraceforwarnings", "1"); - dprint("\n"); - dprint("--- CUT HERE ---\nWARNING: "); - dprint(msg); - dprint("\n"); + print("\n"); + print("--- CUT HERE ---\nWARNING: "); + print(msg); + print("\n"); remove(world); // isn't there any better way to cause a backtrace? - dprint("\n--- CUT UNTIL HERE ---\n"); + print("\n--- CUT UNTIL HERE ---\n"); cvar_set("developer", ftos(dev)); cvar_set("prvm_backtraceforwarnings", ftos(war)); } diff --git a/data/qcsrc/server/race.qc b/data/qcsrc/server/race.qc index e7f917359..21e2cd8ea 100644 --- a/data/qcsrc/server/race.qc +++ b/data/qcsrc/server/race.qc @@ -436,6 +436,8 @@ void checkpoint_passed() self.message = oldmsg; } + other.race_respawn_checkpoint = self.race_checkpoint; + other.race_respawn_spotref = self; // this is not a spot but a CP, but spawnpoint selection will deal with that other.race_checkpoint = race_NextCheckpoint(self.race_checkpoint); race_SendTime(other, self.race_checkpoint, other.race_movetime, !!other.race_laptime); @@ -761,18 +763,17 @@ void race_PreparePlayer() race_ClearTime(self); self.race_place = 0; self.race_started = 0; + self.race_respawn_checkpoint = -1; + self.race_respawn_spotref = world; } void race_RetractPlayer() { if(!g_race && !g_cts) return; - if(self.race_started) - self.race_checkpoint = race_PreviousCheckpoint(self.race_checkpoint); - else - self.race_checkpoint = 0; - if(self.race_checkpoint == 0) + if(self.race_respawn_checkpoint == 0 || self.race_respawn_checkpoint == -1 || self.race_respawn_checkpoint == race_timed_checkpoint) race_ClearTime(self); + self.race_checkpoint = self.race_respawn_checkpoint; } void race_PreDie() @@ -787,8 +788,10 @@ void race_PreSpawn() { if(!g_race && !g_cts) return; - if(self.killcount == -666 || g_race_qualifying) + if(self.killcount == -666 /* initial spawn */ || g_race_qualifying) // spawn race_PreparePlayer(); + else // respawn + race_RetractPlayer(); race_AbandonRaceCheck(self); } @@ -797,22 +800,14 @@ void race_PostSpawn(entity spot) { if(!g_race && !g_cts) return; - if(self.killcount != -666 /* REspawning, not spawning */ && !g_race_qualifying) - { - if(spot.target == "") - // let the player run without timing, if he did not spawn at a targetting spawnpoint - race_PreparePlayer(); - else - race_RetractPlayer(); - } - if(spot.target != "" && self.race_checkpoint == -1 && self.race_started) - // if we have cleared the time, but were already in the race, set the - // current CP to 0, not -1, so when dying again we properly retract... - // however, note that race_laptime is still 0, so this won't count as - // completing another lap (as we already HAD seen that finish line before, - // or we wouldn't be at -1 and race_started) - self.race_checkpoint = 0; + if(spot.target == "") + // Emergency: this wasn't a real spawnpoint. Can this ever happen? + race_PreparePlayer(); + + // if we need to respawn, do it right + self.race_respawn_checkpoint = self.race_checkpoint; + self.race_respawn_spotref = spot; self.race_place = 0; } @@ -853,11 +848,15 @@ void race_ClearRecords() race_checkpoint_recordholders[i] = string_null; } - FOR_EACH_CLIENT(e) + e = self; + FOR_EACH_CLIENT(self) { - race_ClearTime(e); - e.race_started = 0; + float p; + p = self.race_place; + race_PreparePlayer(); + self.race_place = p; } + self = e; } void race_ReadyRestart() diff --git a/data/qcsrc/server/race.qh b/data/qcsrc/server/race.qh index 38d272cb1..71684a5b3 100644 --- a/data/qcsrc/server/race.qh +++ b/data/qcsrc/server/race.qh @@ -24,3 +24,6 @@ void race_StartCompleting(); .float race_movetime; // for reading .float race_movetime_frac; // fractional accumulator for higher accuracy (helper for writing) .float race_movetime_count; // integer accumulator + +.float race_respawn_checkpoint; +.entity race_respawn_spotref; // try THIS spawn in case you respawn -- 2.39.2