#include <server/damage.qh>
#include <server/gamelog.qh>
#include <server/hook.qh>
-#include <server/intermission.qh>
#include <server/ipban.qh>
#include <server/items/items.qh>
#include <server/main.qh>
#include <server/scores_rules.qh>
#include <server/spawnpoints.qh>
#include <server/teamplay.qh>
-#include <server/weapons/common.qh>
#include <server/weapons/weaponstats.qh>
const float LATENCY_THINKRATE = 10;
{
WriteHeader(MSG_BROADCAST, TE_CSQC_PINGPLREPORT);
WriteByte(MSG_BROADCAST, this.cnt);
- WriteShort(MSG_BROADCAST, bound(1, CS(e).ping, 32767));
+ WriteShort(MSG_BROADCAST, bound(1, rint(CS(e).ping), 32767));
WriteByte(MSG_BROADCAST, min(ceil(CS(e).ping_packetloss * 255), 255));
WriteByte(MSG_BROADCAST, min(ceil(CS(e).ping_movementloss * 255), 255));
BADCVAR("g_duel_not_dm_maps");
BADCVAR("g_freezetag");
BADCVAR("g_freezetag_teams");
- BADCVAR("g_invasion_teams");
BADCVAR("g_invasion_type");
BADCVAR("g_jailbreak");
BADCVAR("g_jailbreak_teams");
BADCVAR("g_maplist");
BADCVAR("g_maplist_mostrecent");
BADCVAR("sv_motd");
+ BADCVAR("sv_termsofservice_url");
v = cvar_string(k);
d = cvar_defstring(k);
// does nothing gameplay relevant
BADCVAR("captureleadlimit_override");
BADCVAR("condump_stripcolors");
- BADCVAR("gameversion");
BADCVAR("fs_gamedir");
BADCVAR("g_allow_oldvortexbeam");
BADCVAR("g_balance_kill_delay");
BADCVAR("g_ctf_flag_glowtrails");
BADCVAR("g_ctf_dynamiclights");
BADCVAR("g_ctf_flag_pickup_verbosename");
+ BADCVAR("g_ctf_flagcarrier_auto_helpme_damage");
BADPRESUFFIX("g_ctf_flag_", "_model");
BADPRESUFFIX("g_ctf_flag_", "_skin");
BADCVAR("g_domination_point_leadlimit");
BADCVAR("sv_minigames");
BADCVAR("sv_namechangetimer");
BADCVAR("sv_precacheplayermodels");
+ BADCVAR("sv_qcphysics");
BADCVAR("sv_radio");
BADCVAR("sv_stepheight");
BADCVAR("sv_timeout");
BADCVAR("w_prop_interval");
BADPREFIX("chat_");
BADPREFIX("crypto_");
- BADPREFIX("gameversion_");
+ BADPREFIX("gameversion");
BADPREFIX("g_chat_");
BADPREFIX("g_ctf_captimerecord_");
BADPREFIX("g_hats_");
BADPREFIX("sv_timeout_");
BADPREFIX("sv_vote_");
BADPREFIX("timelimit_");
+ BADPRESUFFIX("g_", "_round_timelimit");
// allowed changes to server admins (please sync this to server.cfg)
// vi commands:
BADCVAR("g_physics_clientselect");
BADCVAR("g_pinata");
BADCVAR("g_powerups");
+ BADCVAR("g_powerups_drop_ondeath");
BADCVAR("g_player_brightness");
BADCVAR("g_rocket_flying");
BADCVAR("g_rocket_flying_disabledelays");
BADCVAR("sv_maxrate");
BADCVAR("sv_motd");
BADCVAR("sv_public");
- BADCVAR("sv_ready_restart");
BADCVAR("sv_showfps");
+ BADCVAR("sv_showspectators");
BADCVAR("sv_status_privacy");
BADCVAR("sv_taunt");
BADCVAR("sv_vote_call");
BADCVAR("g_grappling_hook");
BADCVAR("g_jetpack");
- // temporary for testing
- // TODO remove before 0.8.3 release
- BADCVAR("g_ca_weaponarena");
- BADCVAR("g_freezetag_weaponarena");
- BADCVAR("g_lms_weaponarena");
- BADCVAR("g_ctf_stalemate_time");
-
#undef BADPRESUFFIX
#undef BADPREFIX
#undef BADCVAR
{
server_is_dedicated = boolean(stof(cvar_defstring("is_dedicated")));
+ if (autocvar_sv_termsofservice_url && autocvar_sv_termsofservice_url != "")
+ {
+ strcpy(sv_termsofservice_url_escaped, strreplace(":", "|", autocvar_sv_termsofservice_url));
+ }
+ else
+ {
+ strcpy(sv_termsofservice_url_escaped, "INVALID");
+ }
+
bool wantrestart = false;
{
if (!server_is_dedicated)
if(autocvar_g_campaign)
CampaignPreInit();
+ else
+ PlayerStats_GameReport_Init(); // we need this to be initiated before InitGameplayMode
Map_MarkAsRecent(mapname);
- PlayerStats_GameReport_Init(); // we need this to be initiated before InitGameplayMode
-
InitGameplayMode();
static_init_late();
static_init_precache();
WaypointSprite_Init();
- GameLogInit(); // prepare everything
// NOTE for matchid:
// changing the logic generating it is okay. But:
// it HAS to stay <= 64 chars
// character set: ASCII 33-126 without the following characters: : ; ' " \ $
- if(autocvar_sv_eventlog)
- {
- string num = strftime_s(); // strftime(false, "%s") isn't reliable, see strftime_s description
- string s = sprintf("%s.%s.%06d", itos(autocvar_sv_eventlog_files_counter), num, floor(random() * 1000000));
- matchid = strzone(s);
-
- GameLogEcho(strcat(":gamestart:", GetGametype(), "_", GetMapname(), ":", s));
- s = ":gameinfo:mutators:LIST";
-
- MUTATOR_CALLHOOK(BuildMutatorsString, s);
- s = M_ARGV(0, string);
+ // strftime(false, "%s") isn't reliable, see strftime_s description
+ matchid = strzone(sprintf("%d.%s.%06d", autocvar_sv_eventlog_files_counter, strftime_s(), random() * 1000000));
- // initialiation stuff, not good in the mutator system
- if(!autocvar_g_use_ammunition)
- s = strcat(s, ":no_use_ammunition");
-
- // initialiation stuff, not good in the mutator system
- if(autocvar_g_pickup_items == 0)
- s = strcat(s, ":no_pickup_items");
- if(autocvar_g_pickup_items > 0)
- s = strcat(s, ":pickup_items");
-
- // initialiation stuff, not good in the mutator system
- if(autocvar_g_weaponarena != "0")
- s = strcat(s, ":", autocvar_g_weaponarena, " arena");
-
- // TODO to mutator system
- if(autocvar_g_norecoil)
- s = strcat(s, ":norecoil");
-
- // TODO to mutator system
- if(autocvar_g_powerups == 0)
- s = strcat(s, ":no_powerups");
- if(autocvar_g_powerups > 0)
- s = strcat(s, ":powerups");
-
- GameLogEcho(s);
- GameLogEcho(":gameinfo:end");
- }
- else
- matchid = strzone(ftos(random()));
+ if(autocvar_sv_eventlog)
+ GameLogInit(); // requires matchid to be set
cvar_set("nextmap", "");
MapInfo_Enumerate();
MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 1);
- if(fexists(strcat("scripts/", mapname, ".arena")))
- cvar_settemp("sv_q3acompat_machineshotgunswap", "1");
-
- if(fexists(strcat("scripts/", mapname, ".defi")))
- cvar_settemp("sv_q3defragcompat", "1");
+ q3compat = BITSET(q3compat, Q3COMPAT_ARENA, fexists(strcat("scripts/", mapname, ".arena")));
+ q3compat = BITSET(q3compat, Q3COMPAT_DEFI, fexists(strcat("scripts/", mapname, ".defi")));
if(whichpack(strcat("maps/", mapname, ".cfg")) != "")
{
delete(this);
}
-bool MoveToRandomLocationWithinBounds(entity e, vector boundmin, vector boundmax, float goodcontents, float badcontents, float badsurfaceflags, int attempts, float maxaboveground, float minviewdistance)
+bool MoveToRandomLocationWithinBounds(entity e, vector boundmin, vector boundmax, float goodcontents, float badcontents, float badsurfaceflags, int attempts, float maxaboveground, float minviewdistance, bool frompos)
{
float m = e.dphitcontentsmask;
e.dphitcontentsmask = goodcontents | badcontents;
continue;
// rule 4: we must "see" some spawnpoint or item
- entity sp = NULL;
- IL_EACH(g_spawnpoints, checkpvs(mstart, it),
- {
- if((traceline(mstart, it.origin, MOVE_NORMAL, e), trace_fraction) >= 1)
- {
- sp = it;
- break;
- }
- });
+ entity sp = NULL;
+ if(frompos)
+ {
+ if((traceline(mstart, e.origin, MOVE_NORMAL, e), trace_fraction) >= 1)
+ sp = e;
+ }
+ if(!sp)
+ {
+ IL_EACH(g_spawnpoints, checkpvs(mstart, it),
+ {
+ if((traceline(mstart, it.origin, MOVE_NORMAL, e), trace_fraction) >= 1)
+ {
+ sp = it;
+ break;
+ }
+ });
+ }
if(!sp)
{
int items_checked = 0;
float MoveToRandomMapLocation(entity e, float goodcontents, float badcontents, float badsurfaceflags, float attempts, float maxaboveground, float minviewdistance)
{
- return MoveToRandomLocationWithinBounds(e, world.mins, world.maxs, goodcontents, badcontents, badsurfaceflags, attempts, maxaboveground, minviewdistance);
+ return MoveToRandomLocationWithinBounds(e, world.mins, world.maxs, goodcontents, badcontents, badsurfaceflags, attempts, maxaboveground, minviewdistance, false);
}
/*
FOREACH_CLIENT(IS_REAL_CLIENT(it) || (IS_BOT_CLIENT(it) && autocvar_sv_logscores_bots), {
s = strcat(":player:see-labels:", GetPlayerScoreString(it, 0), ":");
s = strcat(s, ftos(rint(time - CS(it).jointime)), ":");
- if(IS_PLAYER(it) || MUTATOR_CALLHOOK(GetPlayerStatus, it))
+ if(IS_PLAYER(it) || INGAME_JOINED(it))
s = strcat(s, ftos(it.team), ":");
else
s = strcat(s, "spectator:");
*/
void NextLevel()
{
+ cvar_set("_endmatch", "0");
game_stopped = true;
intermission_running = true; // game over
GameLogClose();
- FOREACH_CLIENT(IS_PLAYER(it), {
+ int winner_team = 0;
+ FOREACH_CLIENT(IS_PLAYER(it) || INGAME(it), {
FixIntermissionClient(it);
if(it.winning)
- bprint(playername(it.netname, it.team, false), " ^7wins.\n");
+ {
+ if (teamplay && !winner_team)
+ {
+ winner_team = it.team;
+ bprint(Team_ColorCode(winner_team), Team_ColorName_Upper(winner_team), "^7 team wins the match\n");
+ }
+ bprint(playername(it.netname, it.team, false), " ^7wins\n");
+ }
});
target_music_kill();
}
-float InitiateSuddenDeath()
+int InitiateSuddenDeath()
{
// Check first whether normal overtimes could be added before initiating suddendeath mode
// - for this timelimit_overtime needs to be >0 of course
if(!checkrules_suddendeathend)
{
if(autocvar_g_campaign)
+ {
checkrules_suddendeathend = time; // no suddendeath in campaign
+ }
else
+ {
checkrules_suddendeathend = time + 60 * autocvar_timelimit_suddendeath;
+ overtimes = -1;
+ }
if(g_race && !g_race_qualifying)
race_StartCompleting();
}
void InitiateOvertime() // ONLY call this if InitiateSuddenDeath returned true
{
++checkrules_overtimesadded;
+ overtimes = checkrules_overtimesadded;
//add one more overtime by simply extending the timelimit
cvar_set("timelimit", ftos(autocvar_timelimit + autocvar_timelimit_overtime));
Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_OVERTIME_TIME, autocvar_timelimit_overtime * 60);
// set the .winning flag for exactly those players with a given field value
void SetWinners(.float field, float value)
{
- FOREACH_CLIENT(IS_PLAYER(it), { it.winning = (it.(field) == value); });
+ FOREACH_CLIENT(IS_PLAYER(it) || INGAME(it), { it.winning = (it.(field) == value); });
}
// set the .winning flag for those players with a given field value
void AddWinners(.float field, float value)
{
- FOREACH_CLIENT(IS_PLAYER(it), {
+ FOREACH_CLIENT(IS_PLAYER(it) || INGAME(it), {
if(it.(field) == value)
it.winning = 1;
});
// clear the .winning flags
void ClearWinners()
{
- FOREACH_CLIENT(IS_PLAYER(it), { it.winning = 0; });
+ FOREACH_CLIENT(IS_PLAYER(it) || INGAME(it), { it.winning = 0; });
}
int fragsleft_last;
leadlimit = 0; // no leadlimit for now
}
- if(timelimit > 0)
- {
- timelimit += game_starttime;
- }
- else if (timelimit < 0)
+ if (autocvar__endmatch || timelimit < 0)
{
// endmatch
NextLevel();
return;
}
- float wantovertime;
- wantovertime = 0;
+ if(timelimit > 0)
+ timelimit += game_starttime;
+
+ int overtimes_prev = overtimes;
+ int wantovertime = 0;
if(checkrules_suddendeathend)
{
if(readyplayers || playerswithlaps >= 2)
{
checkrules_suddendeathend = 0;
- ReadyRestart(); // go to race
+ ReadyRestart(true); // go to race
return;
}
else
if(checkrules_status == WINNING_YES)
{
+ if (overtimes == -1 && overtimes != overtimes_prev)
+ {
+ // if suddendeathend overtime has just begun, revert it
+ checkrules_suddendeathend = 0;
+ overtimes = overtimes_prev;
+ }
//print("WINNING\n");
NextLevel();
}
else if (s == "all" || s == "1")
{
g_weaponarena = 1;
- g_weaponarena_list = "All Weapons";
+ g_weaponarena_list = "All Weapons Arena";
g_weaponarena_weapons = weapons_all();
}
else if (s == "devall")
{
g_weaponarena = 1;
- g_weaponarena_list = "Dev All Weapons";
+ g_weaponarena_list = "Dev All Weapons Arena";
g_weaponarena_weapons = weapons_devall();
}
else if (s == "most")
{
g_weaponarena = 1;
- g_weaponarena_list = "Most Weapons";
+ g_weaponarena_list = "Most Weapons Arena";
g_weaponarena_weapons = weapons_most();
}
else if (s == "all_available")
{
g_weaponarena = 1;
- g_weaponarena_list = "All Available Weapons";
+ g_weaponarena_list = "All Available Weapons Arena";
// this needs to run after weaponsInMapAll is initialized
InitializeEntity(NULL, weaponarena_available_all_update, INITPRIO_FINDTARGET);
else if (s == "devall_available")
{
g_weaponarena = 1;
- g_weaponarena_list = "Dev All Available Weapons";
+ g_weaponarena_list = "Dev All Available Weapons Arena";
// this needs to run after weaponsInMapAll is initialized
InitializeEntity(NULL, weaponarena_available_devall_update, INITPRIO_FINDTARGET);
else if (s == "most_available")
{
g_weaponarena = 1;
- g_weaponarena_list = "Most Available Weapons";
+ g_weaponarena_list = "Most Available Weapons Arena";
// this needs to run after weaponsInMapAll is initialized
InitializeEntity(NULL, weaponarena_available_most_update, INITPRIO_FINDTARGET);
else if (s == "none")
{
g_weaponarena = 1;
- g_weaponarena_list = "No Weapons";
+ g_weaponarena_list = "No Weapons Arena";
}
else
{
if(wep != WEP_Null)
{
g_weaponarena_weapons |= (wep.m_wepset);
- g_weaponarena_list = strcat(g_weaponarena_list, wep.m_name, " & ");
+ g_weaponarena_list = strcat(g_weaponarena_list, wep.netname, " & ");
}
}
- g_weaponarena_list = strzone(substring(g_weaponarena_list, 0, strlen(g_weaponarena_list) - 3));
+ if (g_weaponarena_list != "") // remove trailing " & "
+ g_weaponarena_list = substring(g_weaponarena_list, 0, strlen(g_weaponarena_list) - 3);
+ else // no valid weapon found
+ g_weaponarena_list = "No Weapons Arena";
}
if (g_weaponarena)
g_weapon_stay = 0; // incompatible
start_weapons = g_weaponarena_weapons;
start_items |= IT_UNLIMITED_AMMO | IT_UNLIMITED_SUPERWEAPONS;
+ g_weaponarena_list = strzone(g_weaponarena_list);
}
else
{
MUTATOR_CALLHOOK(ReadLevelCvars);
- if (!warmup_stage)
+ if (!warmup_stage && !autocvar_g_campaign)
game_starttime = time + cvar("g_start_delay");
FOREACH(Weapons, it != WEP_Null, { it.wr_init(it); });
}
bool autocvar_sv_gameplayfix_multiplethinksperframe = true;
-void RunThink(entity this)
+void RunThink(entity this, float dt)
{
// don't let things stay in the past.
// it is possible to start that way by a trigger with a local time.
- if(this.nextthink <= 0 || this.nextthink > time + frametime)
+ if(this.nextthink <= 0 || this.nextthink > time + dt)
return;
float oldtime = time; // do we need to save this?
// we don't want to loop in that case, so exit if the new nextthink is
// <= the time the qc was told, also exit if it is past the end of the
// frame
- if(this.nextthink <= time || this.nextthink > oldtime + frametime || !autocvar_sv_gameplayfix_multiplethinksperframe)
+ if(this.nextthink <= time || this.nextthink > oldtime + dt || !autocvar_sv_gameplayfix_multiplethinksperframe)
break;
}
if(it.move_movetype == MOVETYPE_PUSH || it.move_movetype == MOVETYPE_FAKEPUSH)
continue; // these movetypes have no regular think function
// handle thinking here
- if (getthink(it) && it.nextthink > 0 && it.nextthink <= time + frametime)
- RunThink(it);
+ if (getthink(it) && it.nextthink > 0 && it.nextthink <= time + PHYS_INPUT_TIMELENGTH)
+ RunThink(it, PHYS_INPUT_TIMELENGTH);
}
});
STAT(TYPEHIT_TIME, it) = time;
} else if (e.killsound) {
STAT(KILL_TIME, it) = time;
- } else if (e.damage_dealt) {
+ } else if (e.hitsound_damage_dealt) {
STAT(HIT_TIME, it) = time;
- STAT(DAMAGE_DEALT_TOTAL, it) += ceil(e.damage_dealt);
+ // NOTE: this is not accurate as client code doesn't need so much accuracy for its purposes
+ STAT(HITSOUND_DAMAGE_DEALT_TOTAL, it) += ceil(e.hitsound_damage_dealt);
}
});
// add 1 frametime because after this, engine SV_Physics
float altime = time + frametime * (1 + autocvar_g_antilag_nudge);
FOREACH_CLIENT(true, {
it.typehitsound = false;
- it.damage_dealt = 0;
+ it.hitsound_damage_dealt = 0;
it.killsound = false;
antilag_record(it, CS(it), altime);
});
WeaponStats_Shutdown();
MapInfo_Shutdown();
+
+ strfree(sv_termsofservice_url_escaped);
}
else if(world_initialized == 0)
{