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
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ set(SRC_COMMON
"${DIR_SRC}/route_lookup.c"
"${DIR_SRC}/runes.c"
"${DIR_SRC}/server.c"
"${DIR_SRC}/sprays.c"
"${DIR_SRC}/sp_ai.c"
"${DIR_SRC}/sp_boss.c"
"${DIR_SRC}/sp_client.c"
Expand Down
8 changes: 8 additions & 0 deletions include/g_local.h
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,8 @@ enum
G_SETEXTFIELDPTR,
G_GETEXTFIELDPTR,
G_SETSENDNEEDED,
G_SPRAYCLEAR = G_EXTENSIONS_FIRST + 14,
G_SPRAYCLEARALL,
G_EXTENSIONS_LAST
};
extern qbool haveextensiontab[G_EXTENSIONS_LAST-G_EXTENSIONS_FIRST];
Expand All @@ -245,6 +247,11 @@ float g_random(void);
float crandom(void);
int i_rnd(int from, int to);
float dist_random(float minValue, float maxValue, float spreadFactor);
void KTX_SpraysClearAll(void);
void KTX_SpraysClearPlayer(gedict_t *player);
void KTX_SpraysForgetPlayer(gedict_t *player);
qbool KTX_CanSpray(void);
void KTX_SprayPlaced(int spray_id);
float next_frame(void);
gedict_t* spawn(void);
void ent_remove(gedict_t *t);
Expand Down Expand Up @@ -911,6 +918,7 @@ void ra_break(void);
// clan_arena.c

qbool isCA(void);
qbool CA_CanSpray(void);
qbool CA_CheckAlive(gedict_t *p);
int CA_wins_required(void);
int CA_count_ready_players(void);
Expand Down
2 changes: 2 additions & 0 deletions include/g_public.h
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,8 @@ typedef enum
GAME_CLIENT_SAY, // ( int isTeamSay );
GAME_PAUSED_TIC, // ( int duration_msec ); // duration is in msecs
GAME_CLEAR_EDICT, // (self)
GAME_CAN_SPRAY, // self
GAME_SPRAY_PLACED, // self, spray_id

GAME_EDICT_CSQCSEND = 200, //entrypoint, called when using SendEntity
} gameExport_t;
Expand Down
2 changes: 2 additions & 0 deletions include/g_syscalls.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ intptr_t trap_SetBotCMD(intptr_t edn, intptr_t msec, float angles_x, float angle
intptr_t impulse);

void trap_setpause(intptr_t pause);
intptr_t trap_SprayClear(intptr_t id);
intptr_t trap_SprayClearAll(void);

intptr_t QVMstrftime(char *valbuff, intptr_t sizebuff, const char *fmt, intptr_t offset);

Expand Down
13 changes: 13 additions & 0 deletions src/clan_arena.c
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,8 @@ void SM_PrepareCA(void)
WO_InitializeSpawns(); // init wipeout spawns
}

KTX_SpraysClearAll();

team1_score = team2_score = 0;
round_num = 1;

Expand Down Expand Up @@ -336,6 +338,17 @@ qbool isCA(void)
return (isTeam() && cvar("k_clan_arena"));
}

qbool CA_CanSpray(void)
{
// Allow sprays during prewar
if (!match_in_progress) {
return true;
}

// During match, sprays are only allowed between rounds
return ca_round_pause != 0;
}

// Used to determine value of ca_alive when PutClientInServer() is called
qbool CA_CheckAlive(gedict_t *p)
{
Expand Down
20 changes: 20 additions & 0 deletions src/g_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,11 @@ intptr_t VISIBILITY_VISIBLE vmMain(
ClearGlobals();
self = PROG_TO_EDICT(g_globalvars.self);
RemoveMOTD(); // remove MOTD entitys

// clear the bookkeeping but keep the disconnected player's sprays
// use KTX_SpraysClearPlayer() instead to clear sprays on disconnect
KTX_SpraysForgetPlayer(self);

s_lr_clear(self);
if (arg0)
{
Expand Down Expand Up @@ -437,6 +442,19 @@ intptr_t VISIBILITY_VISIBLE vmMain(

return 0;

case GAME_CAN_SPRAY:
ClearGlobals();
self = PROG_TO_EDICT(g_globalvars.self);

return KTX_CanSpray();

case GAME_SPRAY_PLACED:
ClearGlobals();
self = PROG_TO_EDICT(g_globalvars.self);
KTX_SprayPlaced(arg0);

return 0;

case GAME_EDICT_CSQCSEND:
self = PROG_TO_EDICT(g_globalvars.self);
other = PROG_TO_EDICT(g_globalvars.other);
Expand Down Expand Up @@ -671,6 +689,8 @@ static qbool G_InitExtensions(void)
{"SetExtFieldPtr", G_SETEXTFIELDPTR},
{"GetExtFieldPtr", G_GETEXTFIELDPTR},
{"setsendneeded", G_SETSENDNEEDED},
{"sprayclear", G_SPRAYCLEAR},
{"sprayclearall", G_SPRAYCLEARALL},
};
int i;
for (i = 0; i < sizeof(exttraps)/sizeof(exttraps[0]); i++)
Expand Down
2 changes: 2 additions & 0 deletions src/g_syscalls.asm
Original file line number Diff line number Diff line change
Expand Up @@ -120,3 +120,5 @@ equ trap_pointerstat -265
equ trap_MapExtFieldPtr -266
equ trap_SetExtFieldPtr -267
equ trap_GetExtFieldPtr -268
equ trap_SprayClear -270
equ trap_SprayClearAll -271
10 changes: 10 additions & 0 deletions src/g_syscalls.c
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,16 @@ void trap_setpause(intptr_t pause)
syscall(G_SETPAUSE, pause);
}

intptr_t trap_SprayClear(intptr_t id)
{
return syscall(G_SPRAYCLEAR, id);
}

intptr_t trap_SprayClearAll(void)
{
return syscall(G_SPRAYCLEARALL);
}

intptr_t QVMstrftime(char *valbuff, intptr_t sizebuff, const char *fmt, intptr_t offset)
{
return syscall(G_QVMstrftime, (intptr_t) valbuff, sizebuff, (intptr_t) fmt, offset);
Expand Down
136 changes: 136 additions & 0 deletions src/sprays.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
/*
* Server-authoritative spray policy for KTX.
*
* MVDSV owns the network protocol, pixel storage, and demo messages. KTX only
* decides when a player may spray and which previously placed spray should be
* removed when that player exceeds the current game-mode limit.
*/

#include "g_local.h"

// global limit - modes should specify a lower value
#define KTX_MAX_SPRAYS_PER_PLAYER 10

typedef struct
{
int ids[KTX_MAX_SPRAYS_PER_PLAYER];
int count;
} ktx_player_sprays_t;

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.
static int KTX_SprayLimit(void)
{
int limit = (int)cvar("k_player_spray_limit");

limit = bound(0, limit, KTX_MAX_SPRAYS_PER_PLAYER);

return limit;
}

static int KTX_SprayPlayerIndex(gedict_t *player)
{
int index;

if (!player) {
return -1;
}

index = NUM_FOR_EDICT(player) - 1;
if (index < 0 || index >= MAX_CLIENTS) {
return -1;
}

return index;
}

void KTX_SpraysClearAll(void)
{
memset(ktx_player_sprays, 0, sizeof(ktx_player_sprays));

if (HAVEEXTENSION(G_SPRAYCLEARALL)) {
trap_SprayClearAll();
}
}

// Clear every visible spray KTX has tracked for this player.
// Use this only when the sprays should be removed from the map.
void KTX_SpraysClearPlayer(gedict_t *player)
{
ktx_player_sprays_t *sprays;
int index = KTX_SprayPlayerIndex(player);
int i;

if (index < 0) {
return;
}

sprays = &ktx_player_sprays[index];
if (HAVEEXTENSION(G_SPRAYCLEAR)) {
for (i = 0; i < sprays->count; ++i) {
trap_SprayClear(sprays->ids[i]);
}
}
memset(sprays, 0, sizeof(*sprays));
}

// Drop only this client slot's spray bookkeeping.
// Use this on disconnect so visible sprays stay on the map.
void KTX_SpraysForgetPlayer(gedict_t *player)
{
int index = KTX_SprayPlayerIndex(player);

if (index < 0) {
return;
}

memset(&ktx_player_sprays[index], 0, sizeof(ktx_player_sprays[index]));
}

qbool KTX_CanSpray(void)
{
if (KTX_SprayPlayerIndex(self) < 0 || self->ct != ctPlayer) {
return false;
}

if (isCA()) {
return CA_CanSpray();
}

return false;
}

void KTX_SprayPlaced(int spray_id)
{
ktx_player_sprays_t *sprays;
int index = KTX_SprayPlayerIndex(self);
int limit = KTX_SprayLimit();
int i;

if (index < 0 || spray_id <= 0) {
return;
}

sprays = &ktx_player_sprays[index];
if (limit <= 0) {
if (HAVEEXTENSION(G_SPRAYCLEAR)) {
trap_SprayClear(spray_id);
}
return;
}

while (sprays->count >= limit) {
if (HAVEEXTENSION(G_SPRAYCLEAR)) {
trap_SprayClear(sprays->ids[0]);
}

for (i = 1; i < sprays->count; ++i) {
sprays->ids[i - 1] = sprays->ids[i];
}
--sprays->count;
}

sprays->ids[sprays->count++] = spray_id;
}
1 change: 1 addition & 0 deletions src/world.c
Original file line number Diff line number Diff line change
Expand Up @@ -988,6 +988,7 @@ 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