set g_ca_warmup 10 "time players get to run around before the round starts"
set g_ca_damage2score 100 "every this amount of damage done give players 1 point"
set g_ca_round_timelimit 180 "round time limit in seconds"
+set g_ca_round_stop 0 "freeze the game after round stops" // BaI mod
+ set g_ca_round_enddelay 1 "seconds of delay for score evaluation after round could end"
set g_ca_teams_override 0
- set g_ca_team_spawns 0 "when 1, players spawn from the team spawnpoints of the map, if any"
+ set g_ca_team_spawns 1 "when 1, players spawn from the team spawnpoints of the map, if any"
set g_ca_teams 0
set g_ca_prevent_stalemate 0 "When round time ends instead of instant stalemate give round win to the team with 1: most survivors. 2: most total health. 3: most survivors or if equal then most total health"
set g_ca_weaponarena "most" "starting weapons - takes the same options as g_weaponarena"
set g_freezetag_revive_nade_health 40 "Amount of health player has if they revived from their own nade explosion"
set g_freezetag_revive_time_to_score 1.5 "every this amount of seconds give players reviving a frozen teammate 1 point"
set g_freezetag_round_timelimit 360 "round time limit in seconds"
+set g_freezetag_round_stop 0 "freeze game when round ends" // BaI mod
+set g_freezetag_round_respawn 0 // BaI mod
+ set g_freezetag_round_enddelay 1 "seconds of delay for score evaluation after round could end"
set g_freezetag_revive_auto 1 "automatically revive frozen players after some time (g_freezetag_frozen_maxtime)"
set g_freezetag_revive_auto_progress 1 "start the automatic reviving progress as soon as the player gets frozen"
set g_freezetag_revive_auto_reducible 1 "reduce auto-revival time when frozen players are hit by enemies; set to -1 to reduce it even when they are hit by teammates"
set g_freezetag_revive_spawnshield 1 "apply spawnshield for this time in seconds after the player has been revived"
set g_freezetag_frozen_maxtime 60 "frozen players will be automatically unfrozen after this time in seconds"
set g_freezetag_teams_override 0
- set g_freezetag_team_spawns 0 "when 1, players spawn from the team spawnpoints of the map, if any"
+ set g_freezetag_team_spawns 1 "when 1, players spawn from the team spawnpoints of the map, if any"
set g_freezetag_teams 0
-set g_freezetag_weaponarena "most_available" "starting weapons - takes the same options as g_weaponarena"
+// BaI mod changes this
+set g_freezetag_weaponarena "0" "starting weapons - takes the same options as g_weaponarena"
// ==========
if (autocvar_con_chat != floor(mySize.y / autocvar_con_chatsize - 0.5))
cvar_set("con_chat", ftos(floor(mySize.y / autocvar_con_chatsize - 0.5)));
+ //vector chatsize = '1 1 0' * autocvar_con_chatsize;
if(autocvar__hud_configure)
{
+ float alpha = 1; // engine can display chat only at full alpha
+ if (hud_configure_menu_open == 2 && highlightedPanel != panel)
+ alpha = hud_fade_alpha; // fade only when the settings menu of another panel is open
vector chatsize = '1 1 0' * autocvar_con_chatsize;
if (cvar_string("con_chatrect_x") != "9001")
cvar_set("con_chatrect_x", "9001"); // over 9000, we'll fake it instead for more control over alpha and such
break;
}
InfoMessage(s);
- }
+ }*/
- bool mutator_returnvalue = MUTATOR_CALLHOOK(DrawInfoMessages, pos, mySize, img_curr_group);
- pos = M_ARGV(0, vector);
- img_curr_group = M_ARGV(2, int);
+ //bool mutator_returnvalue = MUTATOR_CALLHOOK(DrawInfoMessages, pos, mySize, img_curr_group);
+ //pos = M_ARGV(0, vector);
+ //img_curr_group = M_ARGV(2, int);
- if(!mutator_returnvalue)
+ if(entcs_GetWantsJoin(current_player))
{
- int tm = Team_IndexToTeam(entcs_GetWantsJoin(current_player));
- s = sprintf(_("^2You're queued to join the %s%s^2 team"), Team_ColorCode(tm), Team_ColorName(tm));
+ int tm = entcs_GetWantsJoin(current_player);
+ if(tm > 0)
+ {
+ tm = Team_IndexToTeam(tm);
+ s = sprintf(_("^2You're queued to join the %s%s^2 team"), Team_ColorCode(tm), Team_ColorName(tm));
+ }
+ else if (tm < 0)
+ s = sprintf(_("^2You're queued to join any available team"));
+ else
+ s = sprintf(_("^1Press ^3%s^1 to join"), getcommandkey(_("jump"), "+jump"));
+ InfoMessage(s);
}
+ else
+ s = sprintf(_("^1Press ^3%s^1 to join"), getcommandkey(_("jump"), "+jump"));
+ InfoMessage(s);
}
if (time < STAT(GAMESTARTTIME))
InfoMessage(s);
}
}
+
+ // z411
+ if (motd_permanent != "")
+ InfoMessage(motd_permanent);
+
+ MUTATOR_CALLHOOK(DrawInfoMessages, pos, mySize, img_curr_group);
++
+ if(autocvar_cl_race_checkpoint_splits_hud && !spectatee_status) {
+ int lines[6];
+ int ln = 5;
+ // show up to race_nextcheckpoint (not including) or everything
+ // if you are before start (0 or 254)
+ // (except race_laptime != 0 for race, means next is
+ // start+finish so don't show previous lap finish)
+ int i;
+ if (race_checkpoint != 0 && race_checkpoint != 254)
+ { // middle of run/race
+ i = race_checkpoint;
+ }
+ else if (ISGAMETYPE(RACE) && race_nextcheckpoint == 0)
+ { // before start, but on race, so don't keep old finish visible
+ i = 253;
+ }
+ else
+ { // before start, not on race (cts), keep old run cps visible
+ i = 255;
+ }
+ for (; ln >= 0 && i >= 0; --i)
+ {
+ if (race_checkpoint_splits[i])
+ {
+ lines[ln] = i;
+ --ln;
+ }
+ }
+ for (int j = 0; j < 6; ++j)
+ InfoMessage(race_checkpoint_splits[lines[j]]);
+ }
}
else
{
PlayerScoreField sbt_field[MAX_SBT_FIELDS + 1];
float sbt_field_size[MAX_SBT_FIELDS + 1];
string sbt_field_title[MAX_SBT_FIELDS + 1];
+ float sbt_field_title_condense_factor[MAX_SBT_FIELDS + 1];
+ float sbt_field_title_width[MAX_SBT_FIELDS + 1];
int sbt_num_fields;
+ float sbt_field_title_maxwidth;
+ float sbt_field_title_maxwidth_factor;
string autocvar_hud_fontsize;
- string hud_fontsize_str;
float max_namesize;
+ float name_field_index;
+ int sb_field_sizes_init;
+vector duel_score_fontsize;
+vector duel_name_fontsize;
+vector duel_score_size;
+vector team_score_fontsize;
+vector team_name_fontsize;
+vector team_score_size;
+int total_medals;
+
+float autocvar_hud_panel_scoreboard_duel_weapon_scale = 1.25; // z411
+
float sbt_bg_alpha;
float sbt_fg_alpha;
float sbt_fg_alpha_self;
SCO_LABEL(_("SCO^bctime"), "bctime", " ", _("Total amount of time holding the ball in Keepaway"));
SCO_LABEL(_("SCO^caps"), "caps", " ", _("How often a flag (CTF) or a key (KeyHunt) was captured"));
SCO_LABEL(_("SCO^captime"), "captime", " ", _("Time of fastest capture (CTF)"));
+ SCO_LABEL(_("SCO^cn"), "cn", " ", _("Country of player"));
SCO_LABEL(_("SCO^deaths"), "deaths", " ", _("Number of deaths"));
- SCO_LABEL(_("SCO^destroyed"), "destroyed", " ", _("Number of keys destroyed by pushing them into void"));
- SCO_LABEL(_("SCO^damage"), "dmg", " ", _("The total damage done"));
- SCO_LABEL(_("SCO^dmgtaken"), "dmgtaken", " ", _("The total damage taken"));
+ SCO_LABEL(_("SCO^destructions"), "destructions", " ", _("Number of keys destroyed by pushing them into void"));
+ SCO_LABEL(_("SCO^damage dealt"), "dmg", " ", _("The total damage dealt"));
+ SCO_LABEL(_("SCO^damage taken"), "dmgtaken", " ", _("The total damage taken"));
SCO_LABEL(_("SCO^drops"), "drops", " ", _("Number of flag drops"));
SCO_LABEL(_("SCO^elo"), "elo", " ", _("Player ELO"));
SCO_LABEL(_("SCO^fastest"), "fastest", " ", _("Time of fastest lap (Race/CTS)"));
return str;
}
- void Scoreboard_initFieldSizes()
+ void Scoreboard_initFieldSizes(bool compress_more)
{
+ if (compress_more)
+ {
+ float sbt_field_title_maxwidth_factor_prev = sbt_field_title_maxwidth_factor;
+ sbt_field_title_maxwidth_factor -= 0.05;
+ if (sbt_field_title_maxwidth * sbt_field_title_maxwidth_factor < 0.01 * vid_conwidth)
+ {
+ sbt_field_title_maxwidth_factor = (0.01 * vid_conwidth) / sbt_field_title_maxwidth;
+ if (sbt_field_title_maxwidth_factor_prev == sbt_field_title_maxwidth_factor)
+ return;
+ }
+ }
+ else
+ sbt_field_title_maxwidth_factor = 1;
+
for(int i = 0; i < sbt_num_fields; ++i)
{
- sbt_field_size[i] = stringwidth(sbt_field_title[i], false, hud_fontsize);
- Scoreboard_FixColumnWidth(i, "");
+ if (sbt_field[i] == SP_NAME)
+ {
+ name_field_index = i;
+ continue;
+ }
+
+ Scoreboard_FixColumnWidth(i, "", true);
}
+
+ // update name field size in the end as it takes remaining space
+ Scoreboard_FixColumnWidth(name_field_index, "", true);
}
-vector Scoreboard_DrawHeader(vector pos, vector rgb, bool other_players)
+vector Scoreboard_DrawHeader(vector pos, vector rgb, bool other_players, int team)
{
int i;
+ string title_str;
+ vector title_rgb;
vector column_dim = eY * panel_size.y;
+
if(other_players)
column_dim.y -= 1.25 * hud_fontsize.y;
vector text_offset = eY * (1.25 - 1) / 2 * hud_fontsize.y;
if (sbt_highlight)
if (i % 2)
drawfill(pos - eX * hud_fontsize.x * 0.5, column_dim, '0 0 0', sbt_highlight_alpha, DRAWFLAG_NORMAL);
++
+ drawstring(pos + text_offset + text_offset_center, title_str, hud_fontsize, title_rgb, sbt_fg_alpha, DRAWFLAG_NORMAL);
++
+ vector prev_drawfontscale = drawfontscale;
+ if (sbt_field_title_condense_factor[i])
+ drawfontscale.x *= sbt_field_title_condense_factor[i];
+ drawstring(pos + text_offset, sbt_field_title[i], hud_fontsize, rgb * 1.5, sbt_fg_alpha, DRAWFLAG_NORMAL);
+ if (sbt_field_title_condense_factor[i])
+ {
+ drawfontscale.x *= sbt_field_title_condense_factor[i];
+ drawfontscale = prev_drawfontscale;
+ }
++
pos.x += column_dim.x;
}
+
if(sbt_field[i] == SP_SEPARATOR)
{
pos.x = panel_pos.x + panel_size.x - hud_fontsize.x * 0.5;
continue;
if(pl == ignored_pl)
continue;
+
+ string flag_name = "";
+ vector flag_size = '0 0 0';
+ Scoreboard_GetField(pl, SP_COUNTRY, autocvar_hud_panel_scoreboard_scores_per_round);
+
+ if(sbt_field_icon3 != "") {
+ sz = draw_getimagesize(sbt_field_icon3);
+ flag_name = sbt_field_icon3;
+ flag_size = vec2(hud_fontsize.x * (sz.x / sz.y), hud_fontsize.y);
+ }
+
+ if(entcs_GetWantsJoin(pl.sv_entnum))
+ {
+ vector tmcolor = Team_ColorRGB(Team_IndexToTeam(entcs_GetWantsJoin(pl.sv_entnum)));
+ tmcolor -= tmcolor * sin(2*M_PI*time);
+
+ drawstring(pos, "(Q)", hud_fontsize, tmcolor, sbt_fg_alpha, DRAWFLAG_NORMAL);
+ pos.x += stringwidth("(Q) ", true, hud_fontsize);
+ }
+ if(entcs_GetWantsJoin(pl.sv_entnum))
+ {
+ vector tmcolor = Team_ColorRGB(Team_IndexToTeam(entcs_GetWantsJoin(pl.sv_entnum)));
+ tmcolor -= tmcolor * sin(2*M_PI*time);
+
+ drawstring(pos, "(Q)", hud_fontsize, tmcolor, sbt_fg_alpha, DRAWFLAG_NORMAL);
+ pos.x += stringwidth("(Q) ", true, hud_fontsize);
+ }
+
field = "";
if(this_team == NUM_SPECTATOR)
{
pos = Scoreboard_MakeTable(pos, tm, panel_bg_color, bg_size);
}
+ pos = Scoreboard_MedalStats_Draw(pos);
+
+ // if the name column is too small, try to compress all other field titles
+ if (sbt_field_size[name_field_index] < sbt_field_title_width[name_field_index] + hud_fontsize.x)
+ sb_field_sizes_init = 2;
+
// draw scoreboard spectators before accuracy and item stats
if (autocvar_hud_panel_scoreboard_spectators_position == 0) {
pos = Scoreboard_Spectators_Draw(pos);
int overtimes = STAT(OVERTIMES);
if(warmup_stage || autocvar__hud_configure)
- subtext = _("Warmup");
+ {
+ if (STAT(WARMUP_TIMELIMIT) > 0)
+ subtext = _("Warmup");
+ else
+ {
+ Scoreboard_UpdatePlayerTeams(); // ensure numplayers is current
+ if (srv_minplayers - numplayers > 0)
+ subtext = _("Warmup: too few players!");
+ else if (teamnagger && (ts_max - ts_min) >= teamnagger)
+ subtext = _("Warmup: teams unbalanced!");
+ else
+ subtext = _("Warmup: no time limit");
+ }
+ }
else if(STAT(TIMEOUT_STATUS) == 2)
subtext = _("Timeout");
- else if (overtimes == -1)
- subtext = _("Sudden Death");
- else if(overtimes == 1)
- subtext = _("Overtime");
- else if (overtimes >= 2)
+ else if(overtimes >= 2)
subtext = sprintf(_("Overtime #%d"), overtimes);
+ else if(overtimes != 0)
+ subtext = _("Overtime");
subtext_size = vec2(mySize.x, mySize.y / 3);
timer_size = vec2(mySize.x, mySize.y - subtext_size.y);
ENTCS_PROP(FRAGS, true, frags, frags, ENTCS_SET_NORMAL,
{ WriteShort(chan, ent.frags); },
{ ent.frags = ReadShort(); })
+
+ENTCS_PROP(COUNTRYCODE, true, countrycode, countrycode, ENTCS_SET_NORMAL,
+ { WriteByte(chan, ent.countrycode); },
+ { ent.countrycode = ReadByte(); })
+
+ENTCS_PROP(RANK, true, rank, rank, ENTCS_SET_NORMAL,
+ { WriteString(chan, ent.rank); },
+ { strcpy(ent.rank, ReadString()); })
+ // index of join queue team selection, max 127 because -1 means any available team
ENTCS_PROP(WANTSJOIN, true, wants_join, wants_join, ENTCS_SET_NORMAL,
- { WriteByte(chan, ent.wants_join); },
- { ent.wants_join = ReadByte(); })
+ { WriteChar(chan, ent.wants_join); },
+ { ent.wants_join = ReadChar(); })
// use sv_solid to avoid changing solidity state of entcs entities
ENTCS_PROP(SOLID, true, sv_solid, solid, ENTCS_SET_NORMAL,
if (!winner_team)
winner_team = Team_GetWinnerAliveTeam();
if (!winner_team)
+ {
+ // Dr. Jaska:
+ // reset delay time here only for consistency
+ // CA players currently have no known ways to resurrect
+ round_handler_ResetEndDelayTime();
return 0;
+ }
+
+ // delay round ending a bit
+ if (autocvar_g_ca_round_enddelay
+ && round_handler_GetEndTime() > 0
+ && round_handler_GetEndTime() - time > 0) // don't delay past timelimit
+ {
+ if (round_handler_GetEndDelayTime() == -1)
+ {
+ round_handler_SetEndDelayTime(min(time + autocvar_g_ca_round_enddelay, round_handler_GetEndTime()));
+ return 0;
+ }
+ else if (round_handler_GetEndDelayTime() >= time)
+ {
+ return 0;
+ }
+ }
+ bool perfect = false;
if(winner_team > 0)
{
+ entity tm = Team_GetTeam(winner_team);
+ entity last_pl = ca_LastPlayer(winner_team);
+
+ if(last_pl && Team_GetNumberOfPlayers(tm) >= 3) {
+ Give_Medal(last_pl, DEFENSE);
+ }
+
Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, APP_TEAM_NUM(winner_team, CENTER_ROUND_TEAM_WIN));
Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(winner_team, INFO_ROUND_TEAM_WIN));
+ if(fragsleft > 1) Send_Notification(NOTIF_ALL, NULL, MSG_ANNCE, APP_TEAM_NUM(winner_team, ANNCE_ROUND_TEAM_WIN));
TeamScore_AddToTeam(winner_team, ST_CA_ROUNDS, +1);
+
+ if (Team_GetNumberOfPlayers(tm) >= 3 &&
+ Team_GetNumberOfAlivePlayers(tm) == Team_GetNumberOfPlayers(tm))
+ perfect = true;
}
else if(winner_team == -1)
{
void nades_Clear(entity);
void nades_GiveBonus(entity player, float score);
+entity freezetag_LastPlayer(float tm)
+{
+ entity last_pl = NULL;
+ FOREACH_CLIENT(IS_PLAYER(it) && it.team == tm, {
+ if (STAT(FROZEN, it) != FROZEN_NORMAL && GetResource(it, RES_HEALTH) >= 1)
+ {
+ if (!last_pl)
+ last_pl = it;
+ else
+ return NULL;
+ }
+ });
+ return last_pl;
+}
+
+ float autocvar_g_freezetag_round_enddelay = 1;
++
bool freezetag_CheckWinner()
{
- if(round_handler_GetEndTime() > 0 && round_handler_GetEndTime() - time <= 0)
+ if(round_handler_GetEndTime() > 0 && round_handler_GetEndTime() - time <= 0
+ && round_handler_GetEndDelayTime() == -1)
{
Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_ROUND_OVER);
Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_ROUND_OVER);
- // generated file; do not modify
+ // genmod.sh autogenerated file; do not modify
+#include <common/mutators/mutator/attackertext/_mod.inc>
#include <common/mutators/mutator/bloodloss/_mod.inc>
#include <common/mutators/mutator/breakablehook/_mod.inc>
#include <common/mutators/mutator/buffs/_mod.inc>
MSG_INFO_NOTIF(POWERUP_STRENGTH, N_CONSOLE, 1, 0, "s1", "s1", "strength", _("^BG%s^K1 picked up Strength"), "")
MSG_INFO_NOTIF(QUIT_DISCONNECT, N_CHATCON, 1, 0, "s1", "", "", _("^BG%s^F3 disconnected"), "")
+ MSG_INFO_NOTIF(QUIT_KICK, N_CHATCON, 1, 0, "s1", "", "", _("^BG%s^F3 was kicked"), "")
MSG_INFO_NOTIF(QUIT_KICK_IDLING, N_CHATCON, 1, 1, "s1 f1", "", "", _("^BG%s^F3 was kicked after idling for %s seconds"), "")
MSG_INFO_NOTIF(MOVETOSPEC_IDLING, N_CHATCON, 1, 1, "s1 f1", "", "", _("^BG%s^F3 was moved to^BG spectators^F3 after idling for %s seconds"), "")
+ MSG_INFO_NOTIF(MOVETOSPEC_IDLING_QUEUE, N_CHATCON, 1, 1, "s1 f1", "", "", _("^BG%s^F3 has left the join queue after idling for %s seconds"), "")
MSG_INFO_NOTIF(MOVETOSPEC_REMOVE, N_CHATCON, 1, 0, "s1", "", "", _("^BG%s^F3 was moved to^BG spectators^F3 for balance reasons"), "")
MSG_INFO_NOTIF(QUIT_KICK_SPECTATING, N_CONSOLE, 0, 0, "", "", "", _("^F2You were kicked from the server because you are a spectator and spectators aren't allowed at the moment."), "")
MSG_INFO_NOTIF(QUIT_KICK_TEAMKILL, N_CHATCON, 1, 0, "s1", "", "", _("^BG%s^F3 was kicked for excessive teamkilling"), "")
REPLICATE_INIT(int, cvar_cl_autoscreenshot);
REPLICATE_INIT(bool, cvar_cl_clippedspectating);
REPLICATE_INIT(bool, cvar_cl_cts_noautoswitch);
- REPLICATE_INIT(float, cvar_cl_handicap);
+ REPLICATE_INIT(vector, cvar_cl_handicap);
+ REPLICATE_INIT(float, cvar_cl_handicap_damage_given);
+ REPLICATE_INIT(float, cvar_cl_handicap_damage_taken);
REPLICATE_INIT(bool, cvar_cl_noantilag);
+REPLICATE_INIT(bool, cvar_cl_chat_sounds);
REPLICATE_INIT(string, cvar_g_xonoticversion);
REPLICATE(cvar_cl_autoswitch, bool, "cl_autoswitch");
REPLICATE(cvar_cl_autoscreenshot, int, "cl_autoscreenshot");
REPLICATE(cvar_cl_clippedspectating, bool, "cl_clippedspectating");
REPLICATE(cvar_cl_cts_noautoswitch, bool, "cl_cts_noautoswitch");
- REPLICATE(cvar_cl_handicap, float, "cl_handicap");
+ REPLICATE(cvar_cl_handicap, vector, "cl_handicap");
+ REPLICATE(cvar_cl_handicap_damage_given, float, "cl_handicap_damage_given");
+ REPLICATE(cvar_cl_handicap_damage_taken, float, "cl_handicap_damage_taken");
REPLICATE(cvar_cl_noantilag, bool, "cl_noantilag");
+REPLICATE(cvar_cl_chat_sounds, bool, "cl_chat_sounds");
REPLICATE(cvar_g_xonoticversion, string, "g_xonoticversion");
#endif
case NUM_TEAM_4: return '1 0.0625 1'; // 0xFF0FFF
}
- return '0 0 0';
+ return '1 1 1';
}
+#ifdef CSQC
+string Team_CustomName(int teamid)
+{
+ switch(teamid)
+ {
+ case NUM_TEAM_1: return ((teamname_red != "") ? teamname_red : "^1RED^7 team");
+ case NUM_TEAM_2: return ((teamname_blue != "")? teamname_blue : "^4BLUE^7 team");
+ case NUM_TEAM_3: return ((teamname_yellow != "") ? teamname_yellow : "^3YELLOW^7 team");
+ case NUM_TEAM_4: return ((teamname_pink != "") ? teamname_pink : "^6PINK^7 team");
+ }
+
+ return NAME_NEUTRAL;
+}
+#endif
+
string Team_ColorName(int teamid)
{
switch(teamid)
if(IS_PLAYER(directhitentity))
if(DIFF_TEAM(this.realowner, directhitentity))
if(!IS_DEAD(directhitentity))
- if(IsFlying(directhitentity))
- Send_Notification(NOTIF_ONE, this.realowner, MSG_ANNCE, ANNCE_ACHIEVEMENT_ELECTROBITCH);
-
+ if(IsFlying(directhitentity)) {
+ Give_Medal(this.realowner, ELECTROBITCH);
+ }
+ */
+
this.event_damage = func_null;
this.takedamage = DAMAGE_NO;
- this.velocity = this.movedir; // .velocity must be != '0 0 0' for particle fx and decal to work
+ if (!this.velocity)
+ this.velocity = this.movedir; // .velocity must be != '0 0 0' for particle fx and decal to work
if(this.move_movetype == MOVETYPE_BOUNCE || this.classname == "electro_orb") // TODO: classname is more reliable anyway?
{
*/
string namestr = "";
- if (source)
- namestr = playername(source.netname, source.team, (autocvar_g_chat_teamcolors && IS_PLAYER(source)));
+ if (source) {
+ namestr = playername(source.netname, source.team, (autocvar_g_chat_teamcolors));
+
+ if (IS_DEAD(source) || source.frags == FRAGS_PLAYER_OUT_OF_GAME)
+ namestr = strcat("(DEAD) ", namestr);
+ else if (IS_OBSERVER(source) || IS_SPEC(source))
+ namestr = strcat("(s) ", namestr);
+ }
+ if (autocvar_g_chat_show_playerid)
+ namestr = strcat(namestr, " ^9#", itos(etof(source)), "^7");
+
string colorprefix = (strdecolorize(namestr) == namestr) ? "^3" : "^7";
string msgstr = "", cmsgstr = "";
return ret;
}
+bool play_chatsound(entity source, string msgin)
+{
+ if(autocvar_sv_chat_sounds && CS_CVAR(source).cvar_cl_chat_sounds) {
+ var .float flood_sound = floodcontrol_chatsound;
+
+ if (source.(flood_sound) < time - autocvar_sv_chat_sounds_flood) {
+ string rawmsg;
+ bool found = false;
+ rawmsg = strreplace("\n", " ", msgin);
+
+ FOREACH_WORD(autocvar_sv_chat_sounds_list, it == rawmsg, { found = true; });
+ if (found) {
+ FOREACH_CLIENT(IS_REAL_CLIENT(it) && CS_CVAR(it).cvar_cl_chat_sounds, {
+ msg_entity = it;
+ WriteHeader(MSG_ONE, TE_CSQC_CHATSOUND);
+ WriteString(MSG_ONE, rawmsg);
+ });
+ source.(flood_sound) = time;
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
entity findnearest(vector point, bool checkitems, vector axismod)
{
- vector dist;
- int num_nearest = 0;
-
- IL_EACH(((checkitems) ? g_items : g_locations), ((checkitems) ? (it.target == "###item###") : (it.classname == "target_location")),
- {
- if ((it.items == IT_KEY1 || it.items == IT_KEY2) && it.target == "###item###")
- dist = it.oldorigin;
- else
- dist = it.origin;
- dist = dist - point;
- dist = dist.x * axismod.x * '1 0 0' + dist.y * axismod.y * '0 1 0' + dist.z * axismod.z * '0 0 1';
- float len = vlen2(dist);
-
- int l;
- for (l = 0; l < num_nearest; ++l)
- {
- if (len < nearest_length[l])
- break;
- }
-
- // now i tells us where to insert at
- // INSERTION SORT! YOU'VE SEEN IT! RUN!
- if (l < NUM_NEAREST_ENTITIES)
- {
- for (int j = NUM_NEAREST_ENTITIES - 1; j >= l; --j)
- {
- nearest_length[j + 1] = nearest_length[j];
- nearest_entity[j + 1] = nearest_entity[j];
- }
- nearest_length[l] = len;
- nearest_entity[l] = it;
- if (num_nearest < NUM_NEAREST_ENTITIES)
- num_nearest = num_nearest + 1;
- }
- });
-
- // now use the first one from our list that we can see
- for (int j = 0; j < num_nearest; ++j)
- {
- traceline(point, nearest_entity[j].origin, true, NULL);
- if (trace_fraction == 1)
- {
- if (j != 0)
- LOG_TRACEF("Nearest point (%s) is not visible, using a visible one.", nearest_entity[0].netname);
- return nearest_entity[j];
- }
- }
-
- if (num_nearest == 0)
- return NULL;
-
- LOG_TRACE("Not seeing any location point, using nearest as fallback.");
- /* DEBUGGING CODE:
- dprint("Candidates were: ");
- for(j = 0; j < num_nearest; ++j)
- {
- if(j != 0)
- dprint(", ");
- dprint(nearest_entity[j].netname);
- }
- dprint("\n");
- */
-
- return nearest_entity[0];
+ vector dist;
+ int num_nearest = 0;
+
+ IntrusiveList list = ((checkitems) ? g_items : g_locations);
+ IL_EACH(list, (checkitems ? (it.target == "###item###") : (it.classname == "target_location")),
+ {
+ if ((it.items == IT_KEY1 || it.items == IT_KEY2) && it.target == "###item###")
+ dist = it.oldorigin;
+ else
+ dist = it.origin;
+ dist = dist - point;
+ dist = vec3(dist.x * axismod.x, dist.y * axismod.y, dist.z * axismod.z);
+ float len = vlen2(dist);
+
+ int l;
+ for (l = 0; l < num_nearest; ++l)
+ {
+ if (len < nearest_length[l])
+ break;
+ }
+
+ // now i tells us where to insert at
+ // INSERTION SORT! YOU'VE SEEN IT! RUN!
+ if (l < NUM_NEAREST_ENTITIES)
+ {
+ for (int j = NUM_NEAREST_ENTITIES - 2; j >= l; --j)
+ {
+ nearest_length[j + 1] = nearest_length[j];
+ nearest_entity[j + 1] = nearest_entity[j];
+ }
+ nearest_length[l] = len;
+ nearest_entity[l] = it;
+ if (num_nearest < NUM_NEAREST_ENTITIES)
+ num_nearest = num_nearest + 1;
+ }
+ });
+
+ // now use the first one from our list that we can see
+ for (int j = 0; j < num_nearest; ++j)
+ {
+ traceline(point, nearest_entity[j].origin, true, NULL);
+ if (trace_fraction == 1)
+ {
+ if (j != 0)
+ {
+ LOG_TRACEF("Nearest point (%s) is not visible, using a visible one.",
+ nearest_entity[0].netname);
+ }
+ return nearest_entity[j];
+ }
+ }
+
+ if (num_nearest == 0)
+ return NULL;
+
+ LOG_TRACE("Not seeing any location point, using nearest as fallback.");
+ /* DEBUGGING CODE:
+ dprint("Candidates were: ");
+ for(j = 0; j < num_nearest; ++j)
+ {
+ if(j != 0)
+ dprint(", ");
+ dprint(nearest_entity[j].netname);
+ }
+ dprint("\n");
+ */
+
+ return nearest_entity[0];
}
string NearestLocation(vector p)
int autocvar_g_chat_nospectators;
bool autocvar_g_chat_teamcolors;
bool autocvar_g_chat_tellprivacy;
+ bool autocvar_g_chat_show_playerid;
+bool autocvar_sv_chat_sounds;
+float autocvar_sv_chat_sounds_flood;
+string autocvar_sv_chat_sounds_list;
+
const float NUM_NEAREST_ENTITIES = 4;
entity nearest_entity[NUM_NEAREST_ENTITIES];
float nearest_length[NUM_NEAREST_ENTITIES];
ClientDisconnect(this);
}
- void send_CSQC_teamnagger() {
- WriteHeader(MSG_BROADCAST, TE_CSQC_TEAMNAGGER);
- }
++/* TODO void send_CSQC_teamnagger() {
++ WriteHeader(MSG_BROADCAST, TE_CSQC_TEAMNAGGER);
++}*/
+
+void send_TeamNames(int channel, entity to) {
- msg_entity = to;
-
- WriteHeader(channel, TE_CSQC_TEAMNAMES);
- WriteString(channel, autocvar_g_teamnames_red);
- WriteString(channel, autocvar_g_teamnames_blue);
- WriteString(channel, autocvar_g_teamnames_yellow);
- WriteString(channel, autocvar_g_teamnames_pink);
++ msg_entity = to;
++
++ WriteHeader(channel, TE_CSQC_TEAMNAMES);
++ WriteString(channel, autocvar_g_teamnames_red);
++ WriteString(channel, autocvar_g_teamnames_blue);
++ WriteString(channel, autocvar_g_teamnames_yellow);
++ WriteString(channel, autocvar_g_teamnames_pink);
+}
+
int CountSpectators(entity player, entity to)
{
if(!player) { return 0; } // not sure how, but best to be safe
if (CS(this).just_joined)
CS(this).just_joined = false;
- if (this.wants_join)
- this.wants_join = 0;
+ // for RJZ
+ if (autocvar_rjz_count_shards)
+ send_TotalShards(this);
++
+ if (recount_ready)
+ ReadyCount(); // must be called after SetPlayerTeam() and TRANSMUTE(Observer
}
int player_getspecies(entity this)
setcolor(player, stof(autocvar_sv_defaultplayercolors));
}
-void GiveWarmupResources(entity this)
+void ResetPlayerResources(entity this)
{
- SetResource(this, RES_SHELLS, warmup_start_ammo_shells);
- SetResource(this, RES_BULLETS, warmup_start_ammo_nails);
- SetResource(this, RES_ROCKETS, warmup_start_ammo_rockets);
- SetResource(this, RES_CELLS, warmup_start_ammo_cells);
- SetResource(this, RES_FUEL, warmup_start_ammo_fuel);
- SetResource(this, RES_HEALTH, warmup_start_health);
- SetResource(this, RES_ARMOR, warmup_start_armorvalue);
- STAT(WEAPONS, this) = WARMUP_START_WEAPONS;
+ if (warmup_stage) {
- SetResource(this, RES_SHELLS, warmup_start_ammo_shells);
- SetResource(this, RES_BULLETS, warmup_start_ammo_nails);
- SetResource(this, RES_ROCKETS, warmup_start_ammo_rockets);
- SetResource(this, RES_CELLS, warmup_start_ammo_cells);
- SetResource(this, RES_PLASMA, warmup_start_ammo_plasma);
- SetResource(this, RES_FUEL, warmup_start_ammo_fuel);
- SetResource(this, RES_HEALTH, warmup_start_health);
- SetResource(this, RES_ARMOR, warmup_start_armorvalue);
- STAT(WEAPONS, this) = WARMUP_START_WEAPONS;
++ SetResource(this, RES_SHELLS, warmup_start_ammo_shells);
++ SetResource(this, RES_BULLETS, warmup_start_ammo_nails);
++ SetResource(this, RES_ROCKETS, warmup_start_ammo_rockets);
++ SetResource(this, RES_CELLS, warmup_start_ammo_cells);
++ SetResource(this, RES_FUEL, warmup_start_ammo_fuel);
++ SetResource(this, RES_HEALTH, warmup_start_health);
++ SetResource(this, RES_ARMOR, warmup_start_armorvalue);
++ STAT(WEAPONS, this) = WARMUP_START_WEAPONS;
+ } else {
- SetResource(this, RES_SHELLS, start_ammo_shells);
- SetResource(this, RES_BULLETS, start_ammo_nails);
- SetResource(this, RES_ROCKETS, start_ammo_rockets);
- SetResource(this, RES_CELLS, start_ammo_cells);
- SetResource(this, RES_PLASMA, start_ammo_plasma);
- SetResource(this, RES_FUEL, start_ammo_fuel);
- SetResource(this, RES_HEALTH, start_health);
- SetResource(this, RES_ARMOR, start_armorvalue);
- STAT(WEAPONS, this) = start_weapons;
- if (MUTATOR_CALLHOOK(ForbidRandomStartWeapons, this) == false)
- {
- GiveRandomWeapons(this, random_start_weapons_count,
- autocvar_g_random_start_weapons, random_start_ammo);
- }
++ SetResource(this, RES_SHELLS, start_ammo_shells);
++ SetResource(this, RES_BULLETS, start_ammo_nails);
++ SetResource(this, RES_ROCKETS, start_ammo_rockets);
++ SetResource(this, RES_CELLS, start_ammo_cells);
++ SetResource(this, RES_FUEL, start_ammo_fuel);
++ SetResource(this, RES_HEALTH, start_health);
++ SetResource(this, RES_ARMOR, start_armorvalue);
++ STAT(WEAPONS, this) = start_weapons;
++ if (MUTATOR_CALLHOOK(ForbidRandomStartWeapons, this) == false)
++ {
++ GiveRandomWeapons(this, random_start_weapons_count,
++ autocvar_g_random_start_weapons, random_start_ammo);
++ }
+ }
}
void PutPlayerInServer(entity this)
this.takedamage = DAMAGE_AIM;
this.effects = EF_TELEPORT_BIT | EF_RESTARTANIM_BIT;
- if (warmup_stage)
- GiveWarmupResources(this);
- else
- {
- SetResource(this, RES_SHELLS, start_ammo_shells);
- SetResource(this, RES_BULLETS, start_ammo_nails);
- SetResource(this, RES_ROCKETS, start_ammo_rockets);
- SetResource(this, RES_CELLS, start_ammo_cells);
- SetResource(this, RES_FUEL, start_ammo_fuel);
- SetResource(this, RES_HEALTH, start_health);
- SetResource(this, RES_ARMOR, start_armorvalue);
- STAT(WEAPONS, this) = start_weapons;
- if (MUTATOR_CALLHOOK(ForbidRandomStartWeapons, this) == false)
- {
- GiveRandomWeapons(this, random_start_weapons_count,
- autocvar_g_random_start_weapons, random_start_ammo);
- }
- }
+ ResetPlayerResources(this);
-
SetSpectatee_status(this, 0);
PS(this).dual_weapons = '0 0 0';
} else if (IS_PLAYER(this)) {
PutPlayerInServer(this);
}
+
+ // send team names
+ if(teamplay && IS_REAL_CLIENT(this))
+ send_TeamNames(MSG_ONE, this);
++
bot_relinkplayerlist();
}
WriteByte(channel, this.cnt * 255.0); // g_balance_damagepush_speedfactor
WriteByte(channel, serverflags);
WriteCoord(channel, autocvar_g_trueaim_minrange);
-
++
+ // z411 send full hostname
+ WriteString(channel, (autocvar_hostname_full != "" ? autocvar_hostname_full : autocvar_hostname));
+ WriteString(channel, autocvar_sv_motd_permanent);
-
++
+ // z411 send client countdown type
+ WriteByte(channel, autocvar_sv_timer_countdown);
}
void ClientInit_CheckUpdate(entity this)
else
CS(this).allowed_timeouts = autocvar_sv_timeout_number;
- if (autocvar_sv_eventlog)
+ if (autocvar_sv_eventlog) {
GameLogEcho(strcat(":join:", ftos(this.playerid), ":", ftos(etof(this)), ":", ((IS_REAL_CLIENT(this)) ? GameLog_ProcessIP(this.netaddress) : "bot"), ":", playername(this.netname, this.team, false)));
-
+
+ /* z411 for RJZ */
+ if(autocvar_rjz_ranks) GameLogEcho(strcat(":idfp:", ftos(etof(this)), ":", this.crypto_idfp));
+ }
+
CS(this).just_joined = true; // stop spamming the eventlog with additional lines when the client connects
this.wants_join = 0;
return false;
}
- if (timeout_status == TIMEOUT_ACTIVE) {
++ //if (timeout_status == TIMEOUT_ACTIVE) {
+ if (game_timeout) {
- // don't allow the player to turn around while game is paused
+ // don't allow the player to turn around while game is paused
// FIXME turn this into CSQC stuff
this.v_angle = this.lastV_angle;
this.angles = this.lastV_angle;
ATTRIB(Client, cvar_cl_pokenade_type, string, this.cvar_cl_pokenade_type);
ATTRIB(Client, cvar_cl_spawn_near_teammate, bool, this.cvar_cl_spawn_near_teammate);
ATTRIB(Client, cvar_cl_gunalign, int, this.cvar_cl_gunalign);
- ATTRIB(Client, cvar_cl_handicap, float, this.cvar_cl_handicap);
+ ATTRIB(Client, cvar_cl_chat_sounds, bool, this.cvar_cl_chat_sounds);
+ ATTRIB(Client, cvar_cl_handicap_damage_given, float, this.cvar_cl_handicap_damage_given);
+ ATTRIB(Client, cvar_cl_handicap_damage_taken, float, this.cvar_cl_handicap_damage_taken);
ATTRIB(Client, cvar_cl_clippedspectating, bool, this.cvar_cl_clippedspectating);
ATTRIB(Client, cvar_cl_autoscreenshot, int, this.cvar_cl_autoscreenshot);
ATTRIB(Client, cvar_cl_jetpack_jump, bool, this.cvar_cl_jetpack_jump);
#define IS_INDEPENDENT_PLAYER(e) ((e).solid == SOLID_TRIGGER)
#define MAKE_INDEPENDENT_PLAYER(e) (((e).solid = SOLID_TRIGGER), ((e).frags = FRAGS_PLAYER_OUT_OF_GAME))
+.float lastkill;
+.int countrycode;
.int killcount;
+.string rank; // RJZ
- //flood fields
- .float nickspamtime; // time of last nick change
- .float nickspamcount;
-
void SendWelcomeMessage(entity this, int msg_type);
// respawning
{
case CMD_REQUEST_COMMAND:
{
- if (!game_stopped && IS_CLIENT(caller) && !IS_PLAYER(caller))
+ if (!game_stopped && !game_timeout && IS_CLIENT(caller) && !IS_PLAYER(caller))
{
- if (joinAllowed(caller))
- Join(caller);
+ if (joinAllowed(caller, caller.wants_join))
+ Join(caller, teamplay);
else if(time < CS(caller).jointime + MIN_SPEC_TIME)
CS(caller).autojoin_checked = -1;
}
timeout_status = TIMEOUT_ACTIVE;
// set the slowmo value to the timeout default slowmo value
- cvar_set("slowmo", ftos(TIMEOUT_SLOWMO_VALUE));
+ //cvar_set("slowmo", ftos(TIMEOUT_SLOWMO_VALUE));
+ game_timeout = true;
+ timeout_last = time;
+
+ // play timeout sound
+ sound(NULL, CH_INFO, SND_TIMEOUT, VOL_BASE, ATTN_NONE);
- // reset all the flood variables
- FOREACH_CLIENT(true, {
- it.nickspamcount = it.nickspamtime = it.floodcontrol_chat =
- it.floodcontrol_chatteam = it.floodcontrol_chattell =
- it.floodcontrol_voice = it.floodcontrol_voiceteam = 0;
- });
-
// copy .v_angle to .lastV_angle for every player in order to fix their view during pause (see PlayerPreThink)
FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it), {
it.lastV_angle = it.v_angle;
{
warmup_stage = autocvar_g_warmup; // CAN change it AFTER calling Nagger_ReadyCounted() this frame
game_starttime = time;
- Send_Notification(NOTIF_ALL, NULL, MSG_MULTI, COUNTDOWN_STOP, minplayers);
+ if (total_players < minplayers)
+ Send_Notification(NOTIF_ALL, NULL, MSG_MULTI, COUNTDOWN_STOP_MINPLAYERS, minplayers);
+ else
+ Send_Notification(NOTIF_ALL, NULL, MSG_MULTI, COUNTDOWN_STOP_BADTEAMS);
if (!sv_ready_restart_after_countdown) // if we ran reset_map() at start of countdown
- FOREACH_CLIENT(IS_PLAYER(it), { GiveWarmupResources(it); });
+ FOREACH_CLIENT(IS_PLAYER(it), { ResetPlayerResources(it); });
}
- if (warmup_limit > 0)
- warmup_limit = -1;
- return; // don't ReadyRestart if players are ready but too few
+ warmup_limit = -1;
+ return; // don't ReadyRestart if players are ready but too few or teams are bad
}
- else if (minplayers && warmup_limit <= 0)
+ else if (warmup_limit <= 0
+ && game_starttime <= time) // No countdown in progress, check prevents early countdown end if only player leaves
{
- // there's enough players now but we're still in infinite warmup
+ // there's enough players now and teams are ok
+ // but we're still in infinite warmup and may need to switch to timed warmup
warmup_limit = cvar("g_warmup_limit");
if (warmup_limit == 0)
warmup_limit = autocvar_timelimit * 60;
pickedup |= Item_GiveAmmoTo(item, player, RES_BULLETS, g_pickup_nails_max);
pickedup |= Item_GiveAmmoTo(item, player, RES_ROCKETS, g_pickup_rockets_max);
pickedup |= Item_GiveAmmoTo(item, player, RES_CELLS, g_pickup_cells_max);
- pickedup |= Item_GiveAmmoTo(item, player, RES_PLASMA, g_pickup_plasma_max);
pickedup |= Item_GiveAmmoTo(item, player, RES_FUEL, g_pickup_fuel_max);
+
+ // for RJZ
+ if (autocvar_rjz_count_shards && !warmup_stage && item.itemdef == ITEM_ArmorSmall) {
+ total_shards++;
+ send_TotalShardsAll();
+ }
+
if (item.itemdef.instanceOfWeaponPickup)
{
WepSet w, wp;
if (this.canRoundEnd())
{
// schedule a new round
+ round_delaytime = time;
this.wait = true;
this.nextthink = time + this.delay;
+ round_handler_ResetEndDelayTime();
}
else
{
this.canRoundEnd = canRoundEnd_func;
this.roundStart = roundStart_func;
this.wait = false;
+ round_handler_ResetEndDelayTime();
round_handler_Init(5, 5, 180);
- this.nextthink = time;
ScoreInfo_SetLabel_PlayerScore(SP_ROUNDS_PL, "rounds_pl", 0);
}
BADPREFIX("sv_timeout_");
BADPREFIX("sv_vote_");
BADPREFIX("timelimit_");
+ BADPREFIX("sv_chat_");
+ BADPREFIX("sv_jingle_");
BADPRESUFFIX("g_", "_round_timelimit");
+ BADPRESUFFIX("g_", "_round_enddelay");
// allowed changes to server admins (please sync this to server.cfg)
// vi commands:
void readlevelcvars();
.vector dropped_origin;
- void droptofloor(entity this);
+ void DropToFloor_QC_DelayedInit(entity this);
+/* z411 for RJZ */
+bool autocvar_rjz_count_shards = false;
+bool autocvar_rjz_ranks = false;
+int total_shards = 0;
+void send_TotalShards(entity to);
+void send_TotalShardsAll();
+
IntrusiveList g_moveables;
STATIC_INIT(g_moveables) { g_moveables = IL_NEW(); }