Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions include/g_local.h
Original file line number Diff line number Diff line change
Expand Up @@ -861,6 +861,7 @@ void vote_check_all(void);
#define OV_HOOKCRHOOK (VOTE_FOFS ( hookcrhook ) )
#define OV_ANTILAG ( VOTE_FOFS ( antilag ) )
#define OV_PRIVATE ( VOTE_FOFS ( privategame ) )
#define OV_NOSPRAY ( VOTE_FOFS ( nospray ) )
//#define OV_KICKUNAUTHED ( VOTE_FOFS (kick_unauthed) )
#define OV_SWAPALL ( VOTE_FOFS ( swapall ) )
#define MAX_RPICKUP_RECUSION 3
Expand Down Expand Up @@ -896,6 +897,7 @@ void ra_out_que(gedict_t *p);
qbool ra_isin_que(gedict_t *p);
int ra_pos_que(gedict_t *p);
qbool isRA(void); // not game mode, but just modificator of duel
qbool RA_CanSpray(void);
qbool isWinner(gedict_t *p);
qbool isLoser(gedict_t *p);
gedict_t* getWinner(void);
Expand Down
1 change: 1 addition & 0 deletions include/progs.h
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@ typedef struct vote_s
int hookcrhook;
int antilag;
int privategame;
int nospray;
//int kick_unauthed;
int swapall;

Expand Down
7 changes: 7 additions & 0 deletions src/arena.c
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,13 @@ qbool isRA(void)
return (isDuel() && cvar("k_rocketarena"));
}

qbool RA_CanSpray(void)
{
// Queued RA players are waiting for the next fight and should not affect
// the current arena with sprays.
return !ra_isin_que(self);
}

qbool isWinner(gedict_t *p)
{
return (p->ra_pt == raWinner);
Expand Down
9 changes: 4 additions & 5 deletions src/clan_arena.c
Original file line number Diff line number Diff line change
Expand Up @@ -295,8 +295,6 @@ void SM_PrepareCA(void)
WO_InitializeSpawns(); // init wipeout spawns
}

KTX_SpraysClearAll();

team1_score = team2_score = 0;
round_num = 1;

Expand Down Expand Up @@ -340,9 +338,10 @@ qbool isCA(void)

qbool CA_CanSpray(void)
{
// Allow sprays during prewar
if (!match_in_progress) {
return true;
// Players must be in play (not dead or unready)
if (!self->ca_ready || !self->in_play)
{
return false;
}

// During match, sprays are only allowed between rounds
Expand Down
24 changes: 24 additions & 0 deletions src/commands.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ void VoteCaptain(void);
void VoteCoach(void);
void SuggestColorVote(void);
void nospecs(void);
void nospray(void);
void teamoverlay(void);
void votecoop(void);
void RandomPickup(void);
Expand Down Expand Up @@ -658,6 +659,7 @@ const char CD_NODESC[] = "no desc";
// }

#define CD_NOSPECS "allow/disallow spectators"
#define CD_NOSPRAY "allow/disallow sprays during match"
#define CD_NOITEMS "allow/disallow items in game"
#define CD_TEAMOVERLAY "allow/disallow teamoverlay"

Expand Down Expand Up @@ -1038,6 +1040,7 @@ cmd_t cmds[] =
{ "race_hide_players", race_hide_players_toggle, 0, CF_PLAYER, CD_RHIDEPLAYERS },
// }
{ "nospecs", nospecs, 0, CF_PLAYER | CF_SPC_ADMIN, CD_NOSPECS },
{ "nospray", nospray, 0, CF_PLAYER | CF_SPC_ADMIN, CD_NOSPRAY },
{ "noitems", noitems, 0, CF_PLAYER | CF_SPC_ADMIN, CD_NOITEMS },
{ "teamoverlay", teamoverlay, 0, CF_PLAYER | CF_SPC_ADMIN, CD_TEAMOVERLAY },
{ "spawn666time", Spawn666Time, 0, CF_PLAYER | CF_SPC_ADMIN | CF_PARAMS, CD_SPAWN666TIME },
Expand Down Expand Up @@ -2242,6 +2245,25 @@ void ModStatusVote(void)
}
}

if (!match_in_progress)
{
if ((votes = get_votes(OV_NOSPRAY)))
{
voted = true;

G_sprint(self, 2, "\220%d/%d\221 vote%s for a %s mode change:\n", votes,
get_votes_req(OV_NOSPRAY, false), count_s(votes), redtext("nospray"));

for (p = world; (p = find_client(p));)
{
if (p->v.nospray)
{
G_sprint(self, 2, " %s\n", p->netname);
}
}
}
}

if (!match_in_progress)
{
if ((votes = get_votes(OV_TEAMOVERLAY)))
Expand Down Expand Up @@ -4487,6 +4509,7 @@ const char wipeout_um_init[] =
"k_clan_arena 2\n" // enable wipeout
"k_clan_arena_rounds 9\n" // number of rounds in a series
"k_clan_arena_max_respawns 4\n" // number of respawns per round
"k_player_spray_limit 5\n" // per-player visible spray limit
"coop 0\n" // no coop
"dp 0\n" // don't drop packs
"teamplay 4\n"
Expand All @@ -4512,6 +4535,7 @@ const char carena_um_init[] =
"k_clan_arena 1\n" // enable clan arena
"k_clan_arena_rounds 9\n" // number of rounds in a series
"k_clan_arena_max_respawns 0\n" // number of respawns per round
"k_player_spray_limit 5\n" // per-player visible spray limit
"dp 0\n" // don't drop packs
"teamplay 4\n"
"deathmatch 5\n"
Expand Down
7 changes: 7 additions & 0 deletions src/match.c
Original file line number Diff line number Diff line change
Expand Up @@ -1702,6 +1702,11 @@ void PrintCountdown(int seconds)
strlcat(text, va("%s %5s\n", "NoItems", redtext("on")), sizeof(text));
}

if (cvar("k_nospray"))
{
strlcat(text, va("%s %5s\n", "NoSpray", redtext("on")), sizeof(text));
}

if (cvar("k_midair"))
{
strlcat(text, va("%s %6s\n", "Midair", redtext("on")), sizeof(text));
Expand Down Expand Up @@ -2567,6 +2572,8 @@ void StartTimer(void)

localcmd("serverinfo status Countdown\n");

KTX_SpraysClearAll();

StartDemoRecord(); // if allowed

SM_on_CountdownStart();
Expand Down
64 changes: 59 additions & 5 deletions src/sprays.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,22 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*
* $Id$
*/

/*
* Server-authoritative spray policy for KTX.
*
Expand All @@ -8,7 +27,8 @@

#include "g_local.h"

// global limit - modes should specify a lower value
// Hard storage cap for the per-player visible spray queue. Prewar uses this
// cap directly; active matches use k_player_spray_limit clamped to this size.
#define KTX_MAX_SPRAYS_PER_PLAYER 10

typedef struct
Expand All @@ -19,11 +39,18 @@ typedef struct

static ktx_player_sprays_t ktx_player_sprays[MAX_CLIENTS];

// k_player_spray_limit is a per-player policy value; clamp it to the fixed size of
// each player's tracked spray-id queue.
// k_player_spray_limit is the per-player visible spray limit while a match is
// active. Prewar uses the hard queue cap to prevent spam from exhausting the
// server's global spray storage.
static int KTX_SprayLimit(void)
{
int limit = (int)cvar("k_player_spray_limit");
int limit;

if (!match_in_progress) {
return KTX_MAX_SPRAYS_PER_PLAYER;
}

limit = (int)cvar("k_player_spray_limit");

limit = bound(0, limit, KTX_MAX_SPRAYS_PER_PLAYER);

Expand Down Expand Up @@ -91,15 +118,42 @@ void KTX_SpraysForgetPlayer(gedict_t *player)

qbool KTX_CanSpray(void)
{
// Reject invalid entities and spectators.
if (KTX_SprayPlayerIndex(self) < 0 || self->ct != ctPlayer) {
return false;
}

// No sprays during intermission or end-of-match.
if (intermission_running || match_over) {
return false;
}

// No sprays while the server is paused.
if (cvar("sv_paused")) {
return false;
}

// No sprays during countdown.
if (match_in_progress == 1) {
return false;
}

// No sprays if nospray mode is enabled.
if (match_in_progress && cvar("k_nospray")) {
return false;
}

// CA/Wipeout decides its own in-match spray policy.
if (isCA()) {
return CA_CanSpray();
}

return false;
// RA decides its own in-match spray policy.
if (isRA()) {
return RA_CanSpray();
}

return true;
}

void KTX_SprayPlaced(int spray_id)
Expand Down
75 changes: 75 additions & 0 deletions src/vote.c
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,10 @@ int get_votes_req(int fofs, qbool diff)
{
vt_req = max(2, vt_req); // at least 2 votes in this case
}
else if (fofs == OV_NOSPRAY)
{
vt_req = max(2, vt_req); // at least 2 votes in this case
}
else if (fofs == OV_COOP)
{
vt_req = max(1, vt_req); // at least 1 votes in this case
Expand Down Expand Up @@ -1120,6 +1124,76 @@ void teamoverlay(void)
vote_check_teamoverlay();
}

void vote_check_nospray(void)
{
int veto;

if (match_in_progress || intermission_running || match_over)
{
return;
}

if (!get_votes(OV_NOSPRAY))
{
return;
}

veto = is_admins_vote(OV_NOSPRAY);

if (veto || !get_votes_req(OV_NOSPRAY, true))
{
vote_clear(OV_NOSPRAY);

cvar_fset("k_nospray", !cvar("k_nospray"));

if (veto)
{
G_bprint(2, "%s\n",
redtext(va("NoSpray mode %s by admin veto", OnOff(cvar("k_nospray")))));
}
else
{
G_bprint(2, "%s\n",
redtext(va("NoSpray mode %s by majority vote", OnOff(cvar("k_nospray")))));
}
}
}

void nospray(void)
{
int votes;

if (match_in_progress)
{
G_sprint(self, 2, "%s mode %s\n", redtext("NoSpray"), OnOff(cvar("k_nospray")));

return;
}

if (!is_adm(self))
{
if ((CountPlayers() < 2) && !cvar("k_nospray"))
{
G_sprint(self, 2, "You need at least 2 players to do this.\n");

return;
}
}

self->v.nospray = !self->v.nospray;

G_bprint(
2,
"%s %s!%s\n",
self->netname,
(self->v.nospray ?
redtext(va("votes for nospray %s", OnOff(!cvar("k_nospray")))) :
redtext(va("withdraws %s nospray vote", g_his(self)))),
((votes = get_votes_req(OV_NOSPRAY, true)) ? va(" (%d)", votes) : ""));

vote_check_nospray();
}

qbool force_map_reset = false;

// { votecoop
Expand Down Expand Up @@ -1691,6 +1765,7 @@ void vote_check_all(void)
vote_check_rpickup(MAX_RPICKUP_RECUSION);
vote_check_nospecs();
vote_check_teamoverlay();
vote_check_nospray();
vote_check_coop();
vote_check_antilag();
vote_check_privategame();
Expand Down
3 changes: 2 additions & 1 deletion src/world.c
Original file line number Diff line number Diff line change
Expand Up @@ -785,6 +785,7 @@ void FirstFrame(void)
RegisterCvar("_k_nospecs"); // internal usage, will reject spectators connection

RegisterCvar("k_noitems");
RegisterCvarEx("k_nospray", "0");
RegisterCvarEx("k_pause_without_matchtag", "0");

RegisterCvar("k_random_maplist"); // select random map from k_ml_XXX variables.
Expand Down Expand Up @@ -938,6 +939,7 @@ void FirstFrame(void)
RegisterCvar("demo_skip_ktffa_record");
RegisterCvar("k_demoname_date"); // add date to demo name, value is argument for strftime() function
RegisterCvarEx("k_count", "10");
RegisterCvarEx("k_player_spray_limit", "2");
RegisterCvar("k_exclusive"); // stores whether players can join when a game is already in progress
RegisterCvarEx("k_countdown_message_head", "");
RegisterCvarEx("k_countdown_message_body", "");
Expand Down Expand Up @@ -988,7 +990,6 @@ void FirstFrame(void)
RegisterCvarEx("k_clan_arena", "0");
RegisterCvarEx("k_clan_arena_rounds", "9");
RegisterCvarEx("k_clan_arena_max_respawns", "0");
RegisterCvarEx("k_player_spray_limit", "5");
// }
// { upplayers/upspecs
RegisterCvar("k_allowcountchange");
Expand Down
Loading