From: Rudolf Polzer Date: Tue, 4 Feb 2014 16:17:34 +0000 (+0100) Subject: Refactor respawn delay logic in preparation for implementing vote #215. X-Git-Tag: xonotic-v0.8.0~226^2~17 X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=e9070cc793a0c832bd7316f57b4338d4c481bbb8;p=xonotic%2Fxonotic-data.pk3dir.git Refactor respawn delay logic in preparation for implementing vote #215. --- diff --git a/defaultXonotic.cfg b/defaultXonotic.cfg index 6a99a1f88..747e0c419 100644 --- a/defaultXonotic.cfg +++ b/defaultXonotic.cfg @@ -470,7 +470,10 @@ set g_spawn_alloweffects 1 "allow clients to enable spawn point and event effect set g_spawn_furthest 1 "this amount of the spawns shall be far away from any players" set g_spawn_useallspawns 0 "use all spawns, e.g. also team spawns in non-teamplay, and all spawns, even enemy spawns, in teamplay" // respawn delay -set g_respawn_delay 2 "number of seconds you have to wait before you can respawn again" +set g_respawn_delay_small 2 "small game number of seconds you have to wait before you can respawn again" +set g_respawn_delay_small_count 0 "Player count per team for g_respawn_delay_small. <=0 values mean the minimum amount of players to have gameplay (typically 2 in FFA, 1 in teamplay)." +set g_respawn_delay_large 2 "large game number of seconds you have to wait before you can respawn again" +set g_respawn_delay_large_count 8 "Player count per team for g_respawn_delay_large. <=0 values mean the minimum amount of players to have gameplay (typically 2 in FFA, 1 in teamplay)." set g_respawn_delay_max 0 "number of seconds you can wait before you're forced to respawn (only effective with g_forced_respawn 1)" set g_respawn_waves 0 "respawn in waves (every n seconds), intended to decrease overwhelming base attacks" diff --git a/gamemodes.cfg b/gamemodes.cfg index a44b83ad5..9addcbc7d 100644 --- a/gamemodes.cfg +++ b/gamemodes.cfg @@ -86,52 +86,112 @@ seta g_invasion_round_limit -1 "Invasion round limit overriding the mapinfo spec // ================================= // respawn delay/waves/weapon_stay // ================================= -// when variables are set to anything other than 0, they take over the global setting... +// when variables are set to anything other than 0, they take over the global setting. Negative values force an output value of zero. // to force disable delay or waves, set them to 0.125 -set g_ctf_respawn_delay 5 +set g_ctf_respawn_delay_small 5 +set g_ctf_respawn_delay_small_count 0 +set g_ctf_respawn_delay_large 5 +set g_ctf_respawn_delay_large_count 0 +set g_ctf_respawn_delay_max 0 set g_ctf_respawn_waves 0 set g_ctf_weapon_stay 0 -set g_dm_respawn_delay 0 +set g_dm_respawn_delay_small 0 +set g_dm_respawn_delay_small_count 0 +set g_dm_respawn_delay_large 0 +set g_dm_respawn_delay_large_count 0 +set g_dm_respawn_delay_max 0 set g_dm_respawn_waves 0 set g_dm_weapon_stay 0 -set g_dom_respawn_delay 0 +set g_dom_respawn_delay_small 0 +set g_dom_respawn_delay_small_count 0 +set g_dom_respawn_delay_large 0 +set g_dom_respawn_delay_large_count 0 +set g_dom_respawn_delay_max 0 set g_dom_respawn_waves 0 set g_dom_weapon_stay 0 -set g_lms_respawn_delay 0 +set g_lms_respawn_delay_small 0 +set g_lms_respawn_delay_small_count 0 +set g_lms_respawn_delay_large 0 +set g_lms_respawn_delay_large_count 0 +set g_lms_respawn_delay_max 0 set g_lms_respawn_waves 0 set g_lms_weapon_stay 0 -set g_tdm_respawn_delay 0 +set g_tdm_respawn_delay_small 0 +set g_tdm_respawn_delay_small_count 0 +set g_tdm_respawn_delay_large 0 +set g_tdm_respawn_delay_large_count 0 +set g_tdm_respawn_delay_max 0 set g_tdm_respawn_waves 0 set g_tdm_weapon_stay 0 -set g_ka_respawn_delay 0 +set g_ka_respawn_delay_small 0 +set g_ka_respawn_delay_small_count 0 +set g_ka_respawn_delay_large 0 +set g_ka_respawn_delay_large_count 0 +set g_ka_respawn_delay_max 0 set g_ka_respawn_waves 0 set g_ka_weapon_stay 0 -set g_kh_respawn_delay 0 +set g_kh_respawn_delay_small 0 +set g_kh_respawn_delay_small_count 0 +set g_kh_respawn_delay_large 0 +set g_kh_respawn_delay_large_count 0 +set g_kh_respawn_delay_max 0 set g_kh_respawn_waves 0 set g_kh_weapon_stay 0 -set g_ca_respawn_delay 0 +set g_ca_respawn_delay_small 0 +set g_ca_respawn_delay_small_count 0 +set g_ca_respawn_delay_large 0 +set g_ca_respawn_delay_large_count 0 +set g_ca_respawn_delay_max 0 set g_ca_respawn_waves 0 set g_ca_weapon_stay 0 -set g_nb_respawn_delay 0 +set g_nb_respawn_delay_small 0 +set g_nb_respawn_delay_small_count 0 +set g_nb_respawn_delay_large 0 +set g_nb_respawn_delay_large_count 0 +set g_nb_respawn_delay_max 0 set g_nb_respawn_waves 0 set g_nb_weapon_stay 0 -set g_as_respawn_delay 0 +set g_as_respawn_delay_small 0 +set g_as_respawn_delay_small_count 0 +set g_as_respawn_delay_large 0 +set g_as_respawn_delay_large_count 0 +set g_as_respawn_delay_max 0 set g_as_respawn_waves 0 set g_as_weapon_stay 0 -set g_ons_respawn_delay 0 +set g_ons_respawn_delay_small 0 +set g_ons_respawn_delay_small_count 0 +set g_ons_respawn_delay_large 0 +set g_ons_respawn_delay_large_count 0 +set g_ons_respawn_delay_max 0 set g_ons_respawn_waves 0 set g_ons_weapon_stay 0 +set g_rc_respawn_delay_small 0 +set g_rc_respawn_delay_small_count 0 +set g_rc_respawn_delay_large 0 +set g_rc_respawn_delay_large_count 0 +set g_rc_respawn_delay_max 0 set g_rc_respawn_waves 0 -set g_rc_respawn_delay 0 set g_rc_weapon_stay 0 +set g_cts_respawn_delay_small -1 // CTS shall have instant respawn. +set g_cts_respawn_delay_small_count 0 +set g_cts_respawn_delay_large -1 // CTS shall have instant respawn. +set g_cts_respawn_delay_large_count 0 +set g_cts_respawn_delay_max 0 set g_cts_respawn_waves 0 -set g_cts_respawn_delay 0 set g_cts_weapon_stay 2 +set g_ft_respawn_delay_small 0 +set g_ft_respawn_delay_small_count 0 +set g_ft_respawn_delay_large 0 +set g_ft_respawn_delay_large_count 0 +set g_ft_respawn_delay_max 0 set g_ft_respawn_waves 0 -set g_ft_respawn_delay 0 set g_ft_weapon_stay 0 +set g_inv_respawn_delay_small 0 +set g_inv_respawn_delay_small_count 0 +set g_inv_respawn_delay_large 0 +set g_inv_respawn_delay_large_count 0 +set g_inv_respawn_delay_max 0 set g_inv_respawn_waves 0 -set g_inv_respawn_delay 0 set g_inv_weapon_stay 0 diff --git a/qcsrc/server/autocvars.qh b/qcsrc/server/autocvars.qh index fc9181d56..69d66cc04 100644 --- a/qcsrc/server/autocvars.qh +++ b/qcsrc/server/autocvars.qh @@ -795,7 +795,6 @@ float autocvar_g_domination_point_leadlimit; float autocvar_g_domination_point_rate; float autocvar_g_domination_teams_override; float autocvar_g_forced_respawn; -float autocvar_g_respawn_delay_max; string autocvar_g_forced_team_blue; string autocvar_g_forced_team_otherwise; string autocvar_g_forced_team_pink; @@ -944,7 +943,11 @@ float autocvar_g_projectiles_spread_style; float autocvar_g_race_qualifying_timelimit; float autocvar_g_race_qualifying_timelimit_override; float autocvar_g_race_teams; -float autocvar_g_respawn_delay; +float autocvar_g_respawn_delay_small; +float autocvar_g_respawn_delay_small_count; +float autocvar_g_respawn_delay_large; +float autocvar_g_respawn_delay_large_count; +float autocvar_g_respawn_delay_max; float autocvar_g_respawn_ghosts; float autocvar_g_respawn_ghosts_maxtime; float autocvar_g_respawn_ghosts_speed; diff --git a/qcsrc/server/cl_player.qc b/qcsrc/server/cl_player.qc index 0229d3ed5..67738c4c6 100644 --- a/qcsrc/server/cl_player.qc +++ b/qcsrc/server/cl_player.qc @@ -322,11 +322,107 @@ void PlayerCorpseDamage (entity inflictor, entity attacker, float damage, float } } +// g__str: +// If 0, default is used. +// If <0, 0 is used. +// Otherwise, g_str (default value) is used. +// For consistency, negative values there are mapped to zero too. +#define GAMETYPE_DEFAULTED_SETTING(str) \ + ((gametype_setting_tmp = cvar(strcat("g_", GetGametype(), "_" #str))), \ + (gametype_setting_tmp < 0) ? 0 : \ + (gametype_setting_tmp == 0) ? max(0, autocvar_g_##str) : \ + gametype_setting_tmp) + + +void calculate_player_respawn_time() +{ + float gametype_setting_tmp; + float sdelay_max = GAMETYPE_DEFAULTED_SETTING(respawn_delay_max); + float sdelay_small = GAMETYPE_DEFAULTED_SETTING(respawn_delay_small); + float sdelay_large = GAMETYPE_DEFAULTED_SETTING(respawn_delay_large); + float sdelay_small_count = GAMETYPE_DEFAULTED_SETTING(respawn_delay_small_count); + float sdelay_large_count = GAMETYPE_DEFAULTED_SETTING(respawn_delay_large_count); + float waves = GAMETYPE_DEFAULTED_SETTING(respawn_waves); + + float pcount = 1; // Include myself whether or not team is already set right and I'm a "player". + entity pl; + if (teamplay) + { + FOR_EACH_PLAYER(pl) + if (pl != self) + if (pl.team == self.team) + ++pcount; + if (sdelay_small_count == 0) + sdelay_small_count = 1; + if (sdelay_large_count == 0) + sdelay_large_count = 1; + } + else + { + FOR_EACH_PLAYER(pl) + if (pl != self) + ++pcount; + if (sdelay_small_count == 0) + { + if (g_cts) + { + // Players play independently. No point in requiring enemies. + sdelay_small_count = 1; + } + else + { + // Players play AGAINST each other. Enemies required. + sdelay_small_count = 2; + } + } + if (sdelay_large_count == 0) + { + if (g_cts) + { + // Players play independently. No point in requiring enemies. + sdelay_large_count = 1; + } + else + { + // Players play AGAINST each other. Enemies required. + sdelay_large_count = 2; + } + } + } + + float sdelay; + + if (pcount <= sdelay_small_count) + sdelay = sdelay_small; + else if (pcount >= sdelay_large_count) + sdelay = sdelay_large; + else // NOTE: this case implies sdelay_large_count > sdelay_small_count. + sdelay = sdelay_small + (sdelay_large - sdelay_small) * (pcount - sdelay_small_count) / (sdelay_large_count - sdelay_small_count); + + if(waves) + self.respawn_time = ceil((time + sdelay) / waves) * waves; + else + self.respawn_time = time + sdelay; + + if(sdelay < sdelay_max) + self.respawn_time_max = time + sdelay_max; + else + self.respawn_time_max = self.respawn_time; + + if((sdelay + waves >= 5.0) && (self.respawn_time - time > 1.75)) + self.respawn_countdown = 10; // first number to count down from is 10 + else + self.respawn_countdown = -1; // do not count down + + if(g_cts || autocvar_g_forced_respawn) + self.respawn_flags = self.respawn_flags | RESPAWN_FORCE; +} + void ClientKill_Now_TeamChange(); void PlayerDamage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force) { - float take, save, waves, sdelay, dh, da, j; + float take, save, dh, da, j; vector v; float valid_damage_for_weaponstats; float excess; @@ -621,34 +717,7 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, float deatht // dying animation self.deadflag = DEAD_DYING; // when to allow respawn - sdelay = 0; - waves = 0; - sdelay = cvar(strcat("g_", GetGametype(), "_respawn_delay")); - if(!sdelay) - { - if(g_cts) - sdelay = 0; // no respawn delay in CTS - else - sdelay = autocvar_g_respawn_delay; - } - waves = cvar(strcat("g_", GetGametype(), "_respawn_waves")); - if(!waves) - waves = autocvar_g_respawn_waves; - if(waves) - self.respawn_time = ceil((time + sdelay) / waves) * waves; - else - self.respawn_time = time + sdelay; - if(autocvar_g_respawn_delay_max > sdelay) - self.respawn_time_max = time + autocvar_g_respawn_delay_max; - else - self.respawn_time_max = self.respawn_time; - if((sdelay + waves >= 5.0) && (self.respawn_time - time > 1.75)) - self.respawn_countdown = 10; // first number to count down from is 10 - else - self.respawn_countdown = -1; // do not count down - - if(g_cts || autocvar_g_forced_respawn) - self.respawn_flags = self.respawn_flags | RESPAWN_FORCE; + calculate_player_respawn_time(); self.death_time = time; if (random() < 0.5)