#include <common/util.qh>
#include <common/vehicles/all.qh>
#include <common/weapons/_all.qh>
+#include <lib/warpzone/common.qh>
#include <server/anticheat.qh>
#include <server/antilag.qh>
#include <server/bot/api.qh>
{
k = bufstr_get(h, i);
-#define BADPREFIX(p) if(substring(k, 0, strlen(p)) == p) continue
-#define BADPRESUFFIX(p,s) if(substring(k, 0, strlen(p)) == p && substring(k, -strlen(s), -1) == s) continue
+#define BADPREFIX_COND(p) (substring(k, 0, strlen(p)) == p)
+#define BADSUFFIX_COND(s) (substring(k, -strlen(s), -1) == s)
+
+#define BADPREFIX(p) if(BADPREFIX_COND(p)) continue
+#define BADPRESUFFIX(p, s) if(BADPREFIX_COND(p) && BADSUFFIX_COND(s)) continue
#define BADCVAR(p) if(k == p) continue
#define BADVALUE(p, val) if (k == p && v == val) continue
+#define BADPRESUFFIXVALUE(p, s, val) if(BADPREFIX_COND(p) && BADSUFFIX_COND(s) && v == val) continue
// general excludes and namespaces for server admin used cvars
BADPREFIX("help_"); // PN's server has this listed as changed, let's not rat him out for THAT
BADCVAR("timeformat");
BADCVAR("timestamps");
BADCVAR("g_require_stats");
+ BADCVAR("g_chatban_list");
+ BADCVAR("g_playban_list");
+ BADCVAR("g_playban_minigames");
+ BADCVAR("g_voteban_list");
BADPREFIX("developer_");
BADPREFIX("g_ban_");
BADPREFIX("g_banned_list");
// these can contain player IDs, so better hide
BADPREFIX("g_forced_team_");
- BADCVAR("sv_muteban_list");
- BADCVAR("sv_voteban_list");
BADCVAR("sv_allow_customplayermodels_idlist");
BADCVAR("sv_allow_customplayermodels_speciallist");
BADCVAR("g_keyhunt");
BADCVAR("g_keyhunt_teams");
BADCVAR("g_lms");
+ BADCVAR("g_mayhem");
BADCVAR("g_nexball");
BADCVAR("g_onslaught");
BADCVAR("g_race");
BADCVAR("g_tdm");
BADCVAR("g_tdm_on_dm_maps");
BADCVAR("g_tdm_teams");
+ BADCVAR("g_tka");
+ BADCVAR("g_tka_on_ka_maps");
+ BADCVAR("g_tka_on_tdm_maps");
+ BADCVAR("g_tka_teams");
+ BADCVAR("g_tmayhem");
+ BADCVAR("g_tmayhem_teams");
BADCVAR("g_vip");
BADCVAR("leadlimit");
BADCVAR("nextmap");
BADCVAR("g_spawn_alloweffects");
BADCVAR("g_tdm_point_leadlimit");
BADCVAR("g_tdm_point_limit");
+ BADCVAR("g_mayhem_point_limit");
+ BADCVAR("g_mayhem_point_leadlimit");
+ BADCVAR("g_tmayhem_point_limit");
+ BADCVAR("g_tmayhem_point_leadlimit");
BADCVAR("leadlimit_and_fraglimit");
BADCVAR("leadlimit_override");
BADCVAR("pausable");
BADCVAR("sv_announcer");
+ BADCVAR("sv_autopause");
BADCVAR("sv_checkforpacketsduringsleep");
BADCVAR("sv_damagetext");
BADCVAR("sv_db_saveasdump");
BADCVAR("w_prop_interval");
BADPREFIX("chat_");
BADPREFIX("crypto_");
- BADPREFIX("gameversion");
BADPREFIX("g_chat_");
BADPREFIX("g_ctf_captimerecord_");
BADPREFIX("g_hats_");
BADCVAR("g_ban_sync_uri");
BADCVAR("g_buffs");
BADCVAR("g_ca_teams_override");
+ BADCVAR("g_ca_prevent_stalemate");
BADCVAR("g_ctf_fullbrightflags");
BADCVAR("g_ctf_ignore_frags");
BADCVAR("g_ctf_leaderboard");
BADCVAR("g_keyhunt_point_limit");
BADCVAR("g_keyhunt_teams_override");
BADCVAR("g_lms_lives_override");
+ BADCVAR("g_mayhem_powerups");
BADCVAR("g_maplist");
BADCVAR("g_maxplayers");
BADCVAR("g_mirrordamage");
BADCVAR("g_start_delay");
BADCVAR("g_superspectate");
BADCVAR("g_tdm_teams_override");
+ BADCVAR("g_tmayhem_teams_override");
+ BADCVAR("g_tmayhem_powerups");
BADCVAR("g_weapon_stay"); BADPRESUFFIX("g_", "_weapon_stay");
BADCVAR("hostname");
BADCVAR("log_file");
BADPREFIX("sv_info_");
BADPREFIX("sv_ready_restart_");
+ BADPRESUFFIXVALUE("g_", "_weaponarena", "most");
+ BADPRESUFFIXVALUE("g_", "_weaponarena", "most_available");
+
// mutators that announce themselves properly to the server browser
BADCVAR("g_instagib");
BADCVAR("g_new_toys");
#undef BADPREFIX
#undef BADCVAR
#undef BADVALUE
+#undef BADPRESUFFIXVALUE
if(pureadding)
{
if (!g_duel)
MapReadSizes(mapname);
- if (autocvar_g_maxplayers < 0 && teamplay)
+ if (autocvar_g_maxplayers < 0)
{
- // automatic maxplayers should be a multiple of team count
- if (map_maxplayers == 0 || map_maxplayers > maxclients)
+ if (map_maxplayers <= 0)
map_maxplayers = maxclients; // unlimited, but may need rounding
- int d = map_maxplayers % AVAILABLE_TEAMS;
- int u = AVAILABLE_TEAMS - d;
- map_maxplayers += (u <= d && u + map_maxplayers <= maxclients) ? u : -d;
+ map_maxplayers = bound(max(2, AVAILABLE_TEAMS * 2), map_maxplayers, maxclients);
+ if (teamplay)
+ {
+ // automatic maxplayers should be a multiple of team count
+ int down = map_maxplayers % AVAILABLE_TEAMS;
+ int up = AVAILABLE_TEAMS - down;
+ map_maxplayers += (up < down && up + map_maxplayers <= maxclients) ? up : -down;
+ }
}
if (warmup_stage < 0)
if (teamplay)
{
// automatic minplayers should be a multiple of team count
- int d = map_minplayers % AVAILABLE_TEAMS;
- int u = AVAILABLE_TEAMS - d;
- map_minplayers += (u < d && u + map_minplayers <= m) ? u : -d;
+ int down = map_minplayers % AVAILABLE_TEAMS;
+ int up = AVAILABLE_TEAMS - down;
+ map_minplayers += (up < down && up + map_minplayers <= m) ? up : -down;
}
- warmup_limit = -1;
}
else
- map_minplayers = 0; // don't display a minimum if it's not used
+ map_minplayers = 0; // don't display a minimum if it's not used (g_maxplayers < 0 && g_warmup >= 0)
}
void InitGameplayMode()
{
- VoteReset();
+ VoteReset(false);
// find out good world mins/maxs bounds, either the static bounds found by looking for solid, or the mapinfo specified bounds
get_mi_min_max(1);
{
if (!server_is_dedicated)
{
- // force unloading of server pk3 files when starting a listen server
- // localcmd("\nfs_rescan\n"); // FIXME: does more harm than good, has unintended side effects. What we really want is to unload temporary pk3s only
+ // DP unloads dlcache pk3s before starting a listen server since https://gitlab.com/xonotic/darkplaces/-/merge_requests/134
// restore csqc_progname too
string expect = "csprogs.dat";
wantrestart = cvar_string("csqc_progname") != expect;
GameRules_limit_fallbacks();
- if(warmup_limit == 0)
- warmup_limit = autocvar_timelimit * 60;
-
player_count = 0;
bot_waypoints_for_items = autocvar_g_waypoints_for_items;
if(bot_waypoints_for_items == 1)
WinningConditionHelper(this); // set worldstatus
+ if (autocvar_sv_autopause && server_is_dedicated && !wantrestart)
+ // INITPRIO_LAST is too soon: bots either didn't join yet or didn't leave yet, see: bot_fixcount()
+ defer(this, 5, Pause_TryPause_Dedicated);
+
world_initialized = 1;
__spawnfunc_spawn_all();
}
//pos = FindIntermission ();
- VoteReset();
+ VoteReset(true);
DumpStats(true);
if(cvar("sv_allow_fullbright"))
serverflags |= SERVERFLAG_ALLOW_FULLBRIGHT;
- sv_ready_restart_after_countdown = cvar("sv_ready_restart_after_countdown");
+ serverflags &= ~SERVERFLAG_FORBID_PICKUPTIMER;
+ if(cvar("sv_forbid_pickuptimer"))
+ serverflags |= SERVERFLAG_FORBID_PICKUPTIMER;
- warmup_stage = cvar("g_warmup");
- warmup_limit = cvar("g_warmup_limit");
+ sv_ready_restart_after_countdown = cvar("sv_ready_restart_after_countdown");
if(cvar("g_campaign"))
warmup_stage = 0; // no warmup during campaign
+ else
+ {
+ warmup_stage = autocvar_g_warmup;
+ if (warmup_stage < 0 || warmup_stage > 1)
+ warmup_limit = -1; // don't start until there's enough players
+ else if (warmup_stage == 1)
+ {
+ // this code is duplicated in ReadyCount()
+ warmup_limit = cvar("g_warmup_limit");
+ if(warmup_limit == 0)
+ warmup_limit = autocvar_timelimit * 60;
+ }
+ }
g_pickup_respawntime_weapon = cvar("g_pickup_respawntime_weapon");
g_pickup_respawntime_superweapon = cvar("g_pickup_respawntime_superweapon");
g_pickup_respawntime_ammo = cvar("g_pickup_respawntime_ammo");
- g_pickup_respawntime_short = cvar("g_pickup_respawntime_short");
- g_pickup_respawntime_medium = cvar("g_pickup_respawntime_medium");
- g_pickup_respawntime_long = cvar("g_pickup_respawntime_long");
+ g_pickup_respawntime_armor_small = cvar("g_pickup_respawntime_armor_small");
+ g_pickup_respawntime_armor_medium = cvar("g_pickup_respawntime_armor_medium");
+ g_pickup_respawntime_armor_big = cvar("g_pickup_respawntime_armor_big");
+ g_pickup_respawntime_armor_mega = cvar("g_pickup_respawntime_armor_mega");
+ g_pickup_respawntime_health_small = cvar("g_pickup_respawntime_health_small");
+ g_pickup_respawntime_health_medium = cvar("g_pickup_respawntime_health_medium");
+ g_pickup_respawntime_health_big = cvar("g_pickup_respawntime_health_big");
+ g_pickup_respawntime_health_mega = cvar("g_pickup_respawntime_health_mega");
g_pickup_respawntime_powerup = cvar("g_pickup_respawntime_powerup");
g_pickup_respawntimejitter_weapon = cvar("g_pickup_respawntimejitter_weapon");
g_pickup_respawntimejitter_superweapon = cvar("g_pickup_respawntimejitter_superweapon");
g_pickup_respawntimejitter_ammo = cvar("g_pickup_respawntimejitter_ammo");
- g_pickup_respawntimejitter_short = cvar("g_pickup_respawntimejitter_short");
- g_pickup_respawntimejitter_medium = cvar("g_pickup_respawntimejitter_medium");
- g_pickup_respawntimejitter_long = cvar("g_pickup_respawntimejitter_long");
+ g_pickup_respawntimejitter_armor_small = cvar("g_pickup_respawntimejitter_armor_small");
+ g_pickup_respawntimejitter_armor_medium = cvar("g_pickup_respawntimejitter_armor_medium");
+ g_pickup_respawntimejitter_armor_big = cvar("g_pickup_respawntimejitter_armor_big");
+ g_pickup_respawntimejitter_armor_mega = cvar("g_pickup_respawntimejitter_armor_mega");
+ g_pickup_respawntimejitter_health_small = cvar("g_pickup_respawntimejitter_health_small");
+ g_pickup_respawntimejitter_health_medium = cvar("g_pickup_respawntimejitter_health_medium");
+ g_pickup_respawntimejitter_health_big = cvar("g_pickup_respawntimejitter_health_big");
+ g_pickup_respawntimejitter_health_mega = cvar("g_pickup_respawntimejitter_health_mega");
g_pickup_respawntimejitter_powerup = cvar("g_pickup_respawntimejitter_powerup");
g_pickup_shells = cvar("g_pickup_shells");
return;
}
- vector end = this.origin - '0 0 256';
+ vector end = this.origin;
+ if (autocvar_sv_mapformat_is_quake3)
+ end.z -= 4096;
+ else if (autocvar_sv_mapformat_is_quake2)
+ end.z -= 128;
+ else
+ end.z -= 256; // Quake, QuakeWorld
- // NOTE: NudgeOutOfSolid support is not added as Xonotic's physics do not use it!
- //if(autocvar_sv_gameplayfix_droptofloorstartsolid_nudgetocorrect)
- //SV_NudgeOutOfSolid(this);
+ // NOTE: SV_NudgeOutOfSolid is used in the engine here
+ if(autocvar_sv_gameplayfix_droptofloorstartsolid_nudgetocorrect)
+ {
+ _Movetype_UnstickEntity(this);
+ move_out_of_solid(this);
+ }
tracebox(this.origin, this.mins, this.maxs, end, MOVE_NORMAL, this);
else if(trace_fraction < 1)
{
LOG_DEBUGF("DropToFloor_Handler: %v fixed badly placed entity", this.origin);
- //if(autocvar_sv_gameplayfix_droptofloorstartsolid_nudgetocorrect)
- //SV_NudgeOutOfSolid(this);
setorigin(this, trace_endpos);
+ if(autocvar_sv_gameplayfix_droptofloorstartsolid_nudgetocorrect)
+ {
+ _Movetype_UnstickEntity(this);
+ move_out_of_solid(this);
+ }
SET_ONGROUND(this);
this.groundentity = trace_ent;
// if support is destroyed, keep suspended (gross hack for floating items in various maps)
// if support is destroyed, keep suspended (gross hack for floating items in various maps)
this.move_suspendedinair = true;
}
+ else
+ {
+ // if we can't get the entity out of solid, mark it as on ground so physics doesn't attempt to drop it
+ // hacky workaround for #2774
+ SET_ONGROUND(this);
+ }
}
this.dropped_origin = this.origin;
}