From 31d99e2e0c362f40802fc9d9cb7b05d3bf115563 Mon Sep 17 00:00:00 2001 From: Rudolf Polzer Date: Sat, 3 Dec 2011 19:24:15 +0100 Subject: [PATCH] spawnpoint selection: restructure to be WAY more mutator friendly and simpler; move game mode specific logic to game mode --- qcsrc/common/constants.qh | 4 + qcsrc/server/assault.qc | 8 ++ qcsrc/server/autocvars.qh | 1 - qcsrc/server/cl_client.qc | 171 ++++++++++---------------------------- qcsrc/server/defs.qh | 3 + qcsrc/server/race.qc | 33 ++++++++ qcsrc/server/sv_main.qc | 9 -- 7 files changed, 90 insertions(+), 139 deletions(-) diff --git a/qcsrc/common/constants.qh b/qcsrc/common/constants.qh index d838f09e2..e42afed4e 100644 --- a/qcsrc/common/constants.qh +++ b/qcsrc/common/constants.qh @@ -574,3 +574,7 @@ float HUD_MENU_ENABLE = 0; #define SERVERFLAG_ALLOW_FULLBRIGHT 1 #define SERVERFLAG_TEAMPLAY 2 #define SERVERFLAG_PLAYERSTATS 4 + +// spawnpoint prios +#define SPAWN_PRIO_GOOD_DISTANCE 100 +#define SPAWN_PRIO_RACE_PREVIOUS_SPAWN 50 diff --git a/qcsrc/server/assault.qc b/qcsrc/server/assault.qc index 45fa5c77d..1e91619f7 100644 --- a/qcsrc/server/assault.qc +++ b/qcsrc/server/assault.qc @@ -47,6 +47,13 @@ void assault_objective_use() { self = oldself; } +vector target_objective_spawn_evalfunc(entity player, entity spot, float teamcheck, vector current) +{ + if(self.health < 0 || self.health >= ASSAULT_VALUE_INACTIVE) + return '-1 0 0'; + return current; +} + void spawnfunc_target_objective() { if(!g_assault) { @@ -57,6 +64,7 @@ void spawnfunc_target_objective() { self.use = assault_objective_use; assault_objective_reset(); self.reset = assault_objective_reset; + self.spawn_evalfunc = target_objective_spawn_evalfunc; } diff --git a/qcsrc/server/autocvars.qh b/qcsrc/server/autocvars.qh index 609516634..f1bd5b024 100644 --- a/qcsrc/server/autocvars.qh +++ b/qcsrc/server/autocvars.qh @@ -1065,7 +1065,6 @@ float autocvar_skill_auto; #define autocvar_slowmo cvar("slowmo") float autocvar_snd_soundradius; float autocvar_spawn_debug; -float autocvar_spawn_debugview; float autocvar_speedmeter; float autocvar_sv_accelerate; var float autocvar_sv_accuracy_data_share = 1; diff --git a/qcsrc/server/cl_client.qc b/qcsrc/server/cl_client.qc index 3953b31ed..97e44c3ca 100644 --- a/qcsrc/server/cl_client.qc +++ b/qcsrc/server/cl_client.qc @@ -123,7 +123,7 @@ void spawnpoint_use() // Returns: // _x: prio (-1 if unusable) // _y: weight -vector Spawn_Score(entity spot, float teamcheck) +vector Spawn_Score(entity spot, float mindist, float teamcheck) { float shortest, thisdist; float prio; @@ -151,52 +151,36 @@ vector Spawn_Score(entity spot, float teamcheck) return '-1 0 0'; } + shortest = vlen(world.maxs - world.mins); + FOR_EACH_PLAYER(player) if (player != self) + { + thisdist = vlen(player.origin - spot.origin); + if (thisdist < shortest) + shortest = thisdist; + } + if(shortest < mindist) + prio += SPAWN_PRIO_GOOD_DISTANCE; + + spawn_score = prio * '1 0 0' + shortest * '0 1 0'; + // filter out spots for assault if(spot.target != "") { entity ent; - float good, found; + float found; found = 0; - good = 0; for(ent = world; (ent = find(ent, targetname, spot.target)); ) { ++found; - if(ent.classname == "target_objective") + if(ent.spawn_evalfunc) { - if(ent.health < 0 || ent.health >= ASSAULT_VALUE_INACTIVE) - continue; + entity oldself = self; + self = ent; + spawn_score = ent.spawn_evalfunc(oldself, spot, teamcheck, spawn_score); + self = oldself; + if(spawn_score_x < 0) + return spawn_score; } - else if(ent.classname == "trigger_race_checkpoint") - { - if(g_race_qualifying) - { - // spawn at first - if(ent.race_checkpoint != 0) - continue; - if(spot.race_place != race_lowest_place_spawn) - continue; - } - else - { - if(ent.race_checkpoint != self.race_respawn_checkpoint) - continue; - // 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; - pl = self.race_place; - if(pl > race_highest_place_spawn) - pl = 0; - if(pl == 0 && !self.race_started) - pl = race_highest_place_spawn; // use last place if he has not even touched finish yet - if(spot.race_place != pl) - continue; - } - } - } - ++good; } if(!found) @@ -204,96 +188,42 @@ vector Spawn_Score(entity spot, float teamcheck) dprint("WARNING: spawnpoint at ", vtos(spot.origin), " could not find its target ", spot.target, "\n"); return '-1 0 0'; } - - if(good < found) // at least one was bad - return '-1 0 0'; - } - - shortest = vlen(world.maxs - world.mins); - FOR_EACH_PLAYER(player) if (player != self) - { - thisdist = vlen(player.origin - spot.origin); - if (thisdist < shortest) - shortest = thisdist; } - spawn_score = prio * '1 0 0' + shortest * '0 1 0'; MUTATOR_CALLHOOK(Spawn_Score); return spawn_score; } -float spawn_allbad; -float spawn_allgood; +void Spawn_ScoreAll(entity firstspot, float mindist, float teamcheck) +{ + entity spot; + for(spot = firstspot; spot; spot = spot.chain) + spot.spawnpoint_score = Spawn_Score(spot, mindist, teamcheck); +} + entity Spawn_FilterOutBadSpots(entity firstspot, float mindist, float teamcheck) { entity spot, spotlist, spotlistend; - spawn_allgood = TRUE; - spawn_allbad = TRUE; spotlist = world; spotlistend = world; + Spawn_ScoreAll(firstspot, mindist, teamcheck); + for(spot = firstspot; spot; spot = spot.chain) { - spot.spawnpoint_score = Spawn_Score(spot, teamcheck); - - if(autocvar_spawn_debugview) - { - setmodel(spot, "models/runematch/rune.mdl"); - if(spot.spawnpoint_score_y < mindist) - { - spot.colormod = '1 0 0'; - spot.scale = 1; - } - else - { - spot.colormod = '0 1 0'; - spot.scale = spot.spawnpoint_score_y / mindist; - } - } - if(spot.spawnpoint_score_x >= 0) // spawning allowed here { - if(spot.spawnpoint_score_y < mindist) - { - // too short distance - spawn_allgood = FALSE; - } - else - { - // perfect - spawn_allbad = FALSE; - - if(spotlistend) - spotlistend.chain = spot; - spotlistend = spot; - if(!spotlist) - spotlist = spot; - - /* - if(teamcheck >= 0) - if(spot.team != teamcheck) - error("invalid spawn added"); - - print("added ", etos(spot), "\n"); - */ - } + if(spotlistend) + spotlistend.chain = spot; + spotlistend = spot; + if(!spotlist) + spotlist = spot; } } if(spotlistend) spotlistend.chain = world; - /* - entity e; - if(teamcheck >= 0) - for(e = spotlist; e; e = e.chain) - { - print("seen ", etos(e), "\n"); - if(e.team != teamcheck) - error("invalid spawn found"); - } - */ - return spotlist; } @@ -320,7 +250,6 @@ Finds a point to respawn entity SelectSpawnPoint (float anypoint) { float teamcheck; - entity firstspot_new; entity spot, firstspot; spot = find (world, classname, "testplayerstart"); @@ -362,38 +291,22 @@ entity SelectSpawnPoint (float anypoint) } else { - firstspot_new = Spawn_FilterOutBadSpots(firstspot, 100, teamcheck); - if(!firstspot_new) - firstspot_new = Spawn_FilterOutBadSpots(firstspot, -1, teamcheck); - firstspot = firstspot_new; + float mindist; + if (arena_roundbased && !g_ca) + mindist = 800; + else + mindist = 100; + firstspot = Spawn_FilterOutBadSpots(firstspot, mindist, teamcheck); // there is 50/50 chance of choosing a random spot or the furthest spot // (this means that roughly every other spawn will be furthest, so you // usually won't get fragged at spawn twice in a row) - if (arena_roundbased && !g_ca) - { - firstspot_new = Spawn_FilterOutBadSpots(firstspot, 800, teamcheck); - if(firstspot_new) - firstspot = firstspot_new; - spot = Spawn_WeightedPoint(firstspot, 1, 1, 1); - } - else if (random() > autocvar_g_spawn_furthest) + if (random() > autocvar_g_spawn_furthest) spot = Spawn_WeightedPoint(firstspot, 1, 1, 1); else spot = Spawn_WeightedPoint(firstspot, 1, 5000, 5); // chooses a far far away spawnpoint } - if(autocvar_spawn_debugview) - { - print("spot mindistance: ", vtos(spot.spawnpoint_score), "\n"); - - entity e; - if(teamcheck >= 0) - for(e = firstspot; e; e = e.chain) - if(e.team != teamcheck) - error("invalid spawn found"); - } - if (!spot) { if(autocvar_spawn_debug) diff --git a/qcsrc/server/defs.qh b/qcsrc/server/defs.qh index 21d6db440..065814018 100644 --- a/qcsrc/server/defs.qh +++ b/qcsrc/server/defs.qh @@ -669,3 +669,6 @@ float serverflags; .float misc_bulletcounter; // replaces uzi & hlac bullet counter. void PlayerUseKey(); + +typedef vector(entity player, entity spot, float teamcheck, vector current) spawn_evalfunc_t; +.spawn_evalfunc_t spawn_evalfunc; diff --git a/qcsrc/server/race.qc b/qcsrc/server/race.qc index 3d86f28a2..f145306d4 100644 --- a/qcsrc/server/race.qc +++ b/qcsrc/server/race.qc @@ -764,6 +764,38 @@ void trigger_race_checkpoint_verify() self = oldself; } +vector trigger_race_checkpoint_spawn_evalfunc(entity player, entity spot, float teamcheck, vector current) +{ + if(g_race_qualifying) + { + // spawn at first + if(self.race_checkpoint != 0) + return '-1 0 0'; + if(spot.race_place != race_lowest_place_spawn) + return '-1 0 0'; + } + else + { + if(self.race_checkpoint != player.race_respawn_checkpoint) + return '-1 0 0'; + // try reusing the previous spawn + if(self == player.race_respawn_spotref || spot == player.race_respawn_spotref) + current_x += SPAWN_PRIO_RACE_PREVIOUS_SPAWN; + if(self.race_checkpoint == 0) + { + float pl; + pl = player.race_place; + if(pl > race_highest_place_spawn) + pl = 0; + if(pl == 0 && !player.race_started) + pl = race_highest_place_spawn; // use last place if he has not even touched finish yet + if(spot.race_place != pl) + return '-1 0 0'; + } + } + return current; +} + void spawnfunc_trigger_race_checkpoint() { vector o; @@ -811,6 +843,7 @@ void spawnfunc_trigger_race_checkpoint() } self.sprite.waypointsprite_visible_for_player = race_waypointsprite_visible_for_player; + self.spawn_evalfunc = trigger_race_checkpoint_spawn_evalfunc; InitializeEntity(self, trigger_race_checkpoint_verify, INITPRIO_FINDTARGET); } diff --git a/qcsrc/server/sv_main.qc b/qcsrc/server/sv_main.qc index 6e4b0ccb7..c4cc090c3 100644 --- a/qcsrc/server/sv_main.qc +++ b/qcsrc/server/sv_main.qc @@ -231,15 +231,6 @@ void StartFrame (void) RuneMatchGivePoints(); bot_serverframe(); - if(autocvar_spawn_debugview) - { - RandomSelection_Init(); - for(self = world; (self = find(self, classname, "player")); ) - RandomSelection_Add(self, 0, string_null, 1, 0); - self = RandomSelection_chosen_ent; - SelectSpawnPoint(0); - } - FOR_EACH_PLAYER(self) self.porto_forbidden = max(0, self.porto_forbidden - 1); } -- 2.39.2