From 2459df603f9e48fa4abc7742e367c9fed86214e6 Mon Sep 17 00:00:00 2001 From: div0 Date: Sun, 15 Apr 2007 20:07:21 +0000 Subject: [PATCH] now using DP_SV_CMD/DP_QC_CMD; removed cvar abuse by g_maplist_add etc. and changed them to real commands; fixed a fteqcc warning git-svn-id: svn://svn.icculus.org/nexuiz/trunk@2317 f962a42d-fe04-0410-a3ab-8c8b0445ebaa --- data/default.cfg | 17 +- data/qcsrc/common/gamecommand.qc | 253 +++++++++++++++++++++++++++++ data/qcsrc/common/util.qh | 4 + data/qcsrc/menu/gamecommand.qc | 23 +++ data/qcsrc/menu/mbuiltin.qc | 3 +- data/qcsrc/menu/menu.qc | 5 +- data/qcsrc/menu/msys.qc | 2 +- data/qcsrc/menu/progs.src | 4 + data/qcsrc/server/cl_weapons.qc | 2 +- data/qcsrc/server/defs.qh | 3 +- data/qcsrc/server/g_world.qc | 190 ++++------------------ data/qcsrc/server/gamecommand.qc | 54 ++++++ data/qcsrc/server/miscfunctions.qc | 1 + data/qcsrc/server/progs.src | 3 + data/qcsrc/server/t_items.qc | 21 +-- 15 files changed, 407 insertions(+), 178 deletions(-) create mode 100644 data/qcsrc/common/gamecommand.qc create mode 100644 data/qcsrc/menu/gamecommand.qc create mode 100644 data/qcsrc/server/gamecommand.qc diff --git a/data/default.cfg b/data/default.cfg index a3454e9d9..26e90f769 100644 --- a/data/default.cfg +++ b/data/default.cfg @@ -213,10 +213,6 @@ seta g_maplist $g_maplist_defaultlist seta g_maplist_index 0 // this is used internally for saving position in maplist cycle seta g_maplist_selectrandom 0 // if 1, a random map will be chosen as next map - DEPRECATED in favor of g_maplist_shuffle seta g_maplist_shuffle 0 // new randomization method: like selectrandom, but avoid playing the same maps in short succession. This works by taking out the first element and inserting it into g_maplist with a bias to the end of the list. -alias g_maplist_shufflenow "set _g_maplist_shufflenow 1" -alias g_maplist_add "set _g_maplist_add $1" -alias g_maplist_remove "set _g_maplist_remove $1" -alias g_maplist_putfirst "set _g_maplist_putfirst $1" // timeout for kill credit when your damage knocks someone into a death trap set g_maxpushtime 8.0 @@ -599,7 +595,6 @@ set g_balance_nixnex_ammoincr_rockets 2 set g_balance_nixnex_ammoincr_cells 2 // score log -alias printstats "set _printstats 1" // print status on demand set sv_logscores_console 0 // print scores to server console set sv_logscores_file 0 // print scores to file set sv_logscores_filename scores.log // filename @@ -648,8 +643,6 @@ set sv_motd "" seta cl_shownames 1 // show player names pointed to (0: never, 1: teamplay only, 2: always) set sv_allow_shownames 1 -alias teamstatus "set _scoreboard 1" - con_chatwidth 0.6 con_chat 5 con_chatpos -7 @@ -707,3 +700,13 @@ alias "g_waypointsprite_clear" "impulse 48" alias "g_waypointsprite_toggle" "impulse 49" // key for that? seta cl_hidewaypoints 0 + +// command extensions +alias qc_cmd sv_cmd +alias adminmsg "sv_cmd adminmsg $*" +alias teamstatus "sv_cmd teamstatus" +alias printstats "sv_cmd printstats" // print status on demand +alias g_maplist_add "qc_cmd rpn /maps/$1.mapcfg fexists_assert /g_maplist g_maplist /$1 union def" +alias g_maplist_remove "qc_cmd rpn /g_maplist g_maplist /$1 difference def" +alias g_maplist_putfirst "qc_cmd rpn /maps/$1.mapcfg fexists_assert /g_maplist /$1 g_maplist union def" +alias g_maplist_shufflenow "qc_cmd rpn /g_maplist g_maplist shuffle def" diff --git a/data/qcsrc/common/gamecommand.qc b/data/qcsrc/common/gamecommand.qc new file mode 100644 index 000000000..a25f79bd3 --- /dev/null +++ b/data/qcsrc/common/gamecommand.qc @@ -0,0 +1,253 @@ +#define MAX_RPN_STACK 8 +float rpn_error; +float rpn_sp; +string rpn_stack[MAX_RPN_STACK]; +string rpn_pop() { + if(rpn_sp > 0) { + --rpn_sp; + return rpn_stack[rpn_sp]; + } else { + print("rpn: stack underflow\n"); + rpn_error = TRUE; + return ""; + } +} +void rpn_push(string s) { + if(rpn_sp < MAX_RPN_STACK) { + rpn_stack[rpn_sp] = s; + ++rpn_sp; + } else { + print("rpn: stack overflow\n"); + rpn_error = TRUE; + } +} +string rpn_get() { + if(rpn_sp > 0) { + return rpn_stack[rpn_sp - 1]; + } else { + print("rpn: empty stack\n"); + rpn_error = TRUE; + return ""; + } +} +void rpn_set(string s) { + if(rpn_sp > 0) { + rpn_stack[rpn_sp - 1] = s; + } else { + print("rpn: empty stack\n"); + rpn_error = TRUE; + } +} +float rpn_getf() { return stof(rpn_get()); } +float rpn_popf() { return stof(rpn_pop()); } +void rpn_pushf(float f) { return rpn_push(ftos(f)); } +void rpn_setf(float f) { return rpn_set(ftos(f)); } + +float GameCommand_Generic(string command) +{ + float argc; + argc = tokenize(command); + if(argv(0) == "help") + { + print(" rpn EXPRESSION... - a RPN calculator.\n"); + print(" Operator description (x: string, s: set, f: float):\n"); + print(" x pop -----------------------------> : removes the top\n"); + print(" x dup -----------------------------> x x : duplicates the top\n"); + print(" x x exch --------------------------> x x : swap the top two\n"); + print(" /cvarname load --------------------> x : loads a cvar\n"); + print(" /cvarname x def -------------------> : writes to a cvar\n"); + print(" f f add|sub|mul|div|mod -----------> f : adds/... two numbers\n"); + print(" f neg|abs|sgn|rand ----------------> f : negates/... a number\n"); + print(" s s union|intersection|difference -> s : set operations\n"); + print(" s shuffle -------------------------> s : randomly arrange elements\n"); + print(" Set operations operate on 'such''strings' like g_maplist.\n"); + print(" Unknown tokens insert their cvar value.\n"); + return TRUE; + } + + if(argv(0) == "rpn") + { + if(argc >= 2) + { + float rpnpos; + string rpncmd; + string s, s2; + float f, f2; + float i, j; + rpn_sp = 0; + rpn_error = FALSE; + for(rpnpos = 1; rpnpos < argc; ++rpnpos) + { + rpncmd = argv(rpnpos); + f = strlen(rpncmd); + if(rpncmd == "") { + } else if(stof(substring(rpncmd, 0, 1)) > 0) { + rpn_push(rpncmd); + } else if(substring(rpncmd, 0, 1) == "0") { + rpn_push(rpncmd); + } else if(f >= 2 && substring(rpncmd, 0, 1) == "+") { + rpn_push(rpncmd); + } else if(f >= 2 && substring(rpncmd, 0, 1) == "-") { + rpn_push(rpncmd); + } else if(f >= 2 && substring(rpncmd, 0, 1) == "/") { + rpn_push(substring(rpncmd, 1, strlen(rpncmd) - 1)); + } else if(rpncmd == "def" || rpncmd == "=") { + s = rpn_pop(); + s2 = rpn_pop(); +#ifdef MENUQC + registercvar(s2, "", 0); +#else + registercvar(s2, ""); +#endif + if(!rpn_error) // don't change cvars if a stack error had happened! + cvar_set(s2, s); + } else if(rpncmd == "load") { + rpn_set(cvar_string(rpn_get())); + } else if(rpncmd == "exch") { + s = rpn_pop(); + s2 = rpn_get(); + rpn_set(s); + rpn_push(s2); + } else if(rpncmd == "dup") { + rpn_push(rpn_get()); + } else if(rpncmd == "pop") { + rpn_pop(); + } else if(rpncmd == "add" || rpncmd == "+") { + f = rpn_popf(); + rpn_setf(rpn_getf() + f); + } else if(rpncmd == "sub" || rpncmd == "-") { + f = rpn_popf(); + rpn_setf(rpn_getf() - f); + } else if(rpncmd == "mul" || rpncmd == "*") { + f = rpn_popf(); + rpn_setf(rpn_getf() * f); + } else if(rpncmd == "div" || rpncmd == "/") { + f = rpn_popf(); + rpn_setf(rpn_getf() / f); + } else if(rpncmd == "mod" || rpncmd == "%") { + f = rpn_popf(); + f2 = rpn_getf(); + rpn_setf(f2 - f * floor(f2 / f)); + } else if(rpncmd == "abs") { + rpn_setf(fabs(rpn_getf())); + } else if(rpncmd == "sgn") { + f = rpn_getf(); + if(f < 0) + rpn_set("-1"); + else if(f > 0) + rpn_set("1"); + else + rpn_set("0"); + } else if(rpncmd == "neg" || rpncmd == "~") { + rpn_setf(-rpn_getf()); + } else if(rpncmd == "rand") { + rpn_setf(ceil(random() * rpn_getf()) - 1); + } else if(rpncmd == "union") { + // s s2 union + s2 = rpn_pop(); + s = rpn_get(); + f = tokenize(s); + f2 = tokenize(strcat(s, s2)); + // tokens 0..(f-1) represent s + // tokens f..f2 represent s2 + // UNION: add all tokens to s that are in s2 but not in s + s = ""; + for(i = 0; i < f; ++i) + s = strcat(s, "'", argv(i), "'"); + for(i = f; i < f2; ++i) { + for(j = 0; j < f; ++j) + if(argv(i) == argv(j)) + goto skip_union; + s = strcat(s, "'", argv(i), "'"); +:skip_union + } + rpn_set(s); + tokenize(command); + } else if(rpncmd == "intersection") { + // s s2 intersection + s2 = rpn_pop(); + s = rpn_get(); + f = tokenize(s); + f2 = tokenize(strcat(s, s2)); + // tokens 0..(f-1) represent s + // tokens f..f2 represent s2 + // INTERSECTION: keep only the tokens from s that are also in s2 + s = ""; + for(i = 0; i < f; ++i) { + for(j = f; j < f2; ++j) + if(argv(i) == argv(j)) + { + s = strcat(s, "'", argv(i), "'"); + break; + } + } + rpn_set(s); + tokenize(command); + } else if(rpncmd == "difference") { + // s s2 difference + s2 = rpn_pop(); + s = rpn_get(); + f = tokenize(s); + f2 = tokenize(strcat(s, s2)); + // tokens 0..(f-1) represent s + // tokens f..f2 represent s2 + // DIFFERENCE: keep only the tokens from s that are not in s2 + s = ""; + for(i = 0; i < f; ++i) { + for(j = f; j < f2; ++j) + if(argv(i) == argv(j)) + goto skip_difference; + s = strcat(s, "'", argv(i), "'"); +:skip_difference + } + rpn_set(s); + tokenize(command); + } else if(rpncmd == "shuffle") { + // s shuffle + s = rpn_get(); + f = tokenize(s); + + for(i = 0; i < f - 1; ++i) { + // move a random item from i..f-1 to position i + s = ""; + f2 = ceil(random() * (f - i) + i) - 1; + for(j = 0; j < i; ++j) + s = strcat(s, "'", argv(j), "'"); + s = strcat(s, "'", argv(f2), "'"); + for(j = i; j < f; ++j) + if(j != f2) + s = strcat(s, "'", argv(j), "'"); + f = tokenize(s); + } + + rpn_set(s); + tokenize(command); + } else if(rpncmd == "fexists_assert") { + s = rpn_pop(); + if(!rpn_error) + { + f = fopen(s, FILE_READ); + if(f != -1) + fclose(f); + else { + print("rpn: ERROR: ", s, " does not exist!\n"); + rpn_error = TRUE; + } + } + } else { + rpn_push(cvar_string(rpncmd)); + } + if(rpn_error) + break; + } + while(rpn_sp > 0) + { + s = rpn_pop(); + print("rpn: still on stack: ", s, "\n"); + } + return TRUE; + } + } + + return FALSE; +} diff --git a/data/qcsrc/common/util.qh b/data/qcsrc/common/util.qh index 14c237ded..bf3d53a5b 100644 --- a/data/qcsrc/common/util.qh +++ b/data/qcsrc/common/util.qh @@ -6,3 +6,7 @@ string wordwrap(string s, float l); void wordwrap_sprint(string s, float l); #endif void wordwrap_cb(string s, float l, void(string) callback) + +float GameCommand_Generic(string cmd); +// returns TRUE if handled, FALSE otherwise +// uses tokenize on its argument! diff --git a/data/qcsrc/menu/gamecommand.qc b/data/qcsrc/menu/gamecommand.qc new file mode 100644 index 000000000..d397e4e83 --- /dev/null +++ b/data/qcsrc/menu/gamecommand.qc @@ -0,0 +1,23 @@ +void GameCommand_Init() +{ + // make gg call menu QC commands + localcmd("alias qc_cmd \"menu_cmd $*\"\n"); +} + +void GameCommand(string command) +{ + float argc; + argc = tokenize(command); + + if(argv(0) == "help" || argc == 0) + { + print("Usage: menu_cmd COMMAND..., where possible commands are:\n"); + GameCommand_Generic("help"); + return; + } + + if(GameCommand_Generic(command)) + return; + + print("Invalid command. For a list of supported commands, try menu_cmd help.\n"); +} diff --git a/data/qcsrc/menu/mbuiltin.qc b/data/qcsrc/menu/mbuiltin.qc index bed9a8c4b..1d71949c8 100644 --- a/data/qcsrc/menu/mbuiltin.qc +++ b/data/qcsrc/menu/mbuiltin.qc @@ -122,7 +122,8 @@ string strzone(string s) = #56; void strunzone(string s) = #57; #endif -float tokenize(string s) = #58 +float tokenize(string s) = #58; +float(string s, string separator1, ...) tokenizebyseparator = #479; string argv(float n) = #59; float isserver(void) = #60; diff --git a/data/qcsrc/menu/menu.qc b/data/qcsrc/menu/menu.qc index 619203b6c..596d05ac2 100644 --- a/data/qcsrc/menu/menu.qc +++ b/data/qcsrc/menu/menu.qc @@ -31,6 +31,9 @@ void() m_init = // init menu Menu_Init(); + + // menu QC is running; make the aliases use its GameCommand() + GameCommand_Init(); }; // required menu functions @@ -148,4 +151,4 @@ void() m_shutdown = // make sure everything is reset setkeydest( KEY_GAME ); setmousetarget( MT_CLIENT ); -}; \ No newline at end of file +}; diff --git a/data/qcsrc/menu/msys.qc b/data/qcsrc/menu/msys.qc index 92c706307..4e93acc48 100644 --- a/data/qcsrc/menu/msys.qc +++ b/data/qcsrc/menu/msys.qc @@ -267,7 +267,7 @@ float ERR_BADFILENAME = -4; // fopen float ERR_NULLSTRING = -1; float ERR_BADDRAWFLAG = -2; float ERR_BADSCALE = -3; -float ERR_BADSIZE = ERR_BADSCALE; +//float ERR_BADSIZE = ERR_BADSCALE; float ERR_NOTCACHED = -4; /* not supported at the moment diff --git a/data/qcsrc/menu/progs.src b/data/qcsrc/menu/progs.src index f108d2f28..25936707e 100644 --- a/data/qcsrc/menu/progs.src +++ b/data/qcsrc/menu/progs.src @@ -185,4 +185,8 @@ custom/campaign.qc ../common/campaign_setup.qc ../common/campaign_file.qc +// GameCommand() extension +../common/gamecommand.qc +gamecommand.qc + menu.qc diff --git a/data/qcsrc/server/cl_weapons.qc b/data/qcsrc/server/cl_weapons.qc index 838886313..ace4e881f 100644 --- a/data/qcsrc/server/cl_weapons.qc +++ b/data/qcsrc/server/cl_weapons.qc @@ -110,7 +110,7 @@ void(vector velo, vector delta, float doreduce) W_ThrowWeapon remove(wep); goto leave; } - (Item_SpawnFunc(w))(); + Item_SpawnByItemCode(w); if(startitem_failed) goto leave; if(doreduce) diff --git a/data/qcsrc/server/defs.qh b/data/qcsrc/server/defs.qh index fa6d9ca99..8f8522448 100644 --- a/data/qcsrc/server/defs.qh +++ b/data/qcsrc/server/defs.qh @@ -286,10 +286,9 @@ void DropAllRunes(entity pl); typedef .float floatfield; -typedef void(void) spawnfunc; floatfield Item_CounterField(float it); float Item_WeaponCode(float it); -spawnfunc Item_SpawnFunc(float it); +void Item_SpawnByItemCode(float it); float W_AmmoItemCode(float wpn); float W_ItemCode(float wpn); diff --git a/data/qcsrc/server/g_world.qc b/data/qcsrc/server/g_world.qc index fe568a92c..a23eead61 100644 --- a/data/qcsrc/server/g_world.qc +++ b/data/qcsrc/server/g_world.qc @@ -2,7 +2,7 @@ float SPAWNFLAG_NO_WAYPOINTS_FOR_ITEMS = 1; string GetMapname(); void GotoNextMap(); -void HandleMaplistShuffleCommands(); +void ShuffleMaplist() float() DoNextMapOverride; void SetDefaultAlpha() @@ -57,7 +57,8 @@ void GotoFirstMap() if(cvar("_sv_init")) { cvar_set("_sv_init", "0"); - HandleMaplistShuffleCommands(); + if(cvar("g_maplist_shuffle")) + ShuffleMaplist(); tokenize(cvar_string("g_maplist")); if(argv(0) != GetMapname()) { @@ -343,12 +344,6 @@ void worldspawn (void) // 63 testing lightstyle(63, "a"); - registercvar("_g_maplist_shufflenow", "0"); - registercvar("_g_maplist_have_shuffled", "0"); - registercvar("_g_maplist_add", ""); - registercvar("_g_maplist_remove", ""); - registercvar("_g_maplist_putfirst", ""); - player_count = 0; lms_lowest_lives = 0; lms_next_place = 0; @@ -892,31 +887,41 @@ RULES =============================================================================== */ -void() DumpStats = +void(float final) DumpStats = { local float file; local string s; + local float to_console; + local float to_eventlog; + local float to_file; - if(cvar("_printstats")) - cvar_set("_printstats", "0"); - else if(!gameover) - return; + to_console = cvar("sv_logscores_console"); + to_eventlog = cvar("sv_eventlog"); + to_file = cvar("sv_logscores_file"); + + if(!final) + { + to_console = TRUE; // always print printstats replies + to_eventlog = FALSE; // but never print them to the event log + } - if(gameover) + if(final) s = ":scores:"; else s = ":status:"; - s = strcat(s, GetMapname(), ":", ftos(rint(time))); - if(cvar("sv_eventlog") && gameover) - GameLogEcho(s, FALSE); - else if(cvar("sv_logscores_console")) + if(to_console) ServerConsoleEcho(s, FALSE); - if(cvar("sv_logscores_file")) + if(to_eventlog) + GameLogEcho(s, FALSE); + if(to_file) { file = fopen(cvar_string("sv_logscores_filename"), FILE_APPEND); - fputs(file, strcat(s, "\n")); + if(file == -1) + to_file = FALSE; + else + fputs(file, strcat(s, "\n")); } FOR_EACH_CLIENT(other) @@ -928,20 +933,20 @@ void() DumpStats = s = strcat(s, ftos(rint(time - other.jointime)), ":"); s = strcat(s, ftos(other.team), ":"); - if(cvar("sv_logscores_file")) - fputs(file, strcat(s, other.netname, "\n")); - if(cvar("sv_eventlog") && gameover) - GameLogEcho(strcat(s, ftos(other.playerid), ":", other.netname), TRUE); - else if(cvar("sv_logscores_console")) + if(to_console) ServerConsoleEcho(strcat(s, other.netname), TRUE); + if(to_eventlog) + GameLogEcho(strcat(s, ftos(other.playerid), ":", other.netname), TRUE); + if(to_file) + fputs(file, strcat(s, other.netname, "\n")); } } - if(cvar("sv_eventlog") && gameover) - GameLogEcho(":end", FALSE); - else if(cvar("sv_logscores_console")) + if(to_console) ServerConsoleEcho(":end", FALSE); - if(cvar("sv_logscores_file")) + if(to_eventlog) + GameLogEcho(":end", FALSE); + if(to_file) { fputs(file, ":end\n"); fclose(file); @@ -1006,7 +1011,7 @@ void() NextLevel = VoteReset(); - DumpStats(); + DumpStats(TRUE); if(cvar("sv_eventlog")) GameLogEcho(":gameover", FALSE); @@ -1441,91 +1446,6 @@ void PrintScoreboard(entity e) print_to(e, "."); } -void RemoveFromMaplist(string m) -{ - string result; - float litems; - float i; - float found; - - litems = tokenize(cvar_string("g_maplist")); - found = 0; - result = ""; - for(i = 0; i < litems; ++i) - { - m = strcat1(m); - result = strcat1(result); - if(argv(i) == m) - found += 1; - else - result = strcat(result, "'", argv(i), "'"); - } - if(found) - cvar_set("g_maplist", result); - ServerConsoleEcho(strcat("Removed ", ftos(found), " items."), FALSE); -} - -void AddToMaplist(string m) -{ - string result; - float found; - float litems; - float i; - float ipos; - float inserted; - - if(!TryFile(strcat("maps/", m, ".mapcfg"))) - { - ServerConsoleEcho("Map not found.", FALSE); - return; - } - - litems = tokenize(cvar_string("g_maplist")); - if(cvar("g_maplist_shuffle")) - ipos = ceil(random() * (litems + 1)) - 1; - else - ipos = litems; - found = 0; - inserted = 0; - for(i = 0; i < litems; ++i) - { - m = strcat1(m); - if(i == ipos) - { - result = strcat(result, "'", m, "'"); - inserted = 1; - } - result = strcat(result, "'", argv(i), "'"); - if(argv(i) == m) - found += 1; - } - if(!inserted) - result = strcat(result, "'", m, "'"); - if(!found) - { - cvar_set("g_maplist", result); - ServerConsoleEcho("Map added.", FALSE); - } - else - ServerConsoleEcho("Map already in list.", FALSE); -} - -void MakeFirstInMaplist(string m) -{ - if(!TryFile(strcat("maps/", m, ".mapcfg"))) - { - ServerConsoleEcho("Map not found.", FALSE); - return; - } - - m = strzone(m); - RemoveFromMaplist(m); - cvar_set("g_maplist", strcat("'", m, "'", cvar_string("g_maplist"))); - strunzone(m); - - ServerConsoleEcho("Map added as first one.", FALSE); -} - void ShuffleMaplist() { string result; @@ -1560,36 +1480,6 @@ void ShuffleMaplist() cvar_set("g_maplist", result); } -void() HandleMaplistShuffleCommands = -{ - // automatically shuffle when setting g_maplist_shuffle - if(cvar_string("_g_maplist_add") != "") - { - AddToMaplist(cvar_string("_g_maplist_add")); - cvar_set("_g_maplist_add", ""); - } - if(cvar_string("_g_maplist_remove") != "") - { - RemoveFromMaplist(cvar_string("_g_maplist_remove")); - cvar_set("_g_maplist_remove", ""); - } - if(cvar_string("_g_maplist_putfirst") != "") - { - MakeFirstInMaplist(cvar_string("_g_maplist_putfirst")); - cvar_set("_g_maplist_putfirst", ""); - } - if(cvar("_g_maplist_shufflenow") || (cvar("g_maplist_shuffle") && !cvar("_g_maplist_have_shuffled"))) - { - ShuffleMaplist(); - cvar_set("_g_maplist_shufflenow", "0"); - cvar_set("_g_maplist_have_shuffled", "1"); - ServerConsoleEcho("Shuffled map list.", FALSE); - } - if(cvar("_g_maplist_have_shuffled")) - if(!cvar("g_maplist_shuffle")) - cvar_set("_g_maplist_have_shuffled", "0"); -} - /* ============ CheckRules_World @@ -1618,16 +1508,6 @@ void() CheckRules_World = if (gameover) // someone else quit the game already return; - DumpStats(); - - if(cvar("_scoreboard")) - { - cvar_set("_scoreboard", "0"); - PrintScoreboard(world); - } - - HandleMaplistShuffleCommands(); - timelimit = cvar("timelimit") * 60; fraglimit = cvar("fraglimit"); diff --git a/data/qcsrc/server/gamecommand.qc b/data/qcsrc/server/gamecommand.qc new file mode 100644 index 000000000..0c46bfd5d --- /dev/null +++ b/data/qcsrc/server/gamecommand.qc @@ -0,0 +1,54 @@ +void GameCommand(string command) +{ + float argc; + argc = tokenize(command); + + if(argv(0) == "help" || argc == 0) + { + print("Usage: sv_cmd COMMAND..., where possible commands are:\n"); + print(" adminmsg clientnumber \"message\"\n"); + print(" teamstatus\n"); + print(" printstats\n"); + GameCommand_Generic("help"); + return; + } + + if(GameCommand_Generic(command)) + return; + + if(argv(0) == "teamstatus") + { + PrintScoreboard(world); + return; + } + + if(argv(0) == "printstats") + { + DumpStats(FALSE); + return; + } + + if(argv(0) == "adminmsg") + { + if(argc == 3) + { + entity client; + float entno; + entno = stof(argv(1)); + for(client = world; entno > 0; --entno, client = nextent(client)) + ; + if(client.flags & FL_CLIENT) + { + centerprint_atprio(client, CENTERPRIO_ADMIN, strcat("^3SERVER ADMIN:\n\n^7", argv(2))); + sprint(client, strcat("\{1}\{13}^3SERVER ADMIN^7: ", argv(2), "\n")); + print("Message sent to ", client.netname, "\n"); + } + else + print("Client not found\n"); + return; + } + } + + print("Invalid command. For a list of supported commands, try sv_cmd help.\n"); +} + diff --git a/data/qcsrc/server/miscfunctions.qc b/data/qcsrc/server/miscfunctions.qc index 8d9553f7d..1d60ca665 100644 --- a/data/qcsrc/server/miscfunctions.qc +++ b/data/qcsrc/server/miscfunctions.qc @@ -513,6 +513,7 @@ string decolorize(string s) #define CENTERPRIO_VOTE 4 #define CENTERPRIO_NORMAL 5 #define CENTERPRIO_MAPVOTE 9 +#define CENTERPRIO_ADMIN 99 .float centerprint_priority; .float centerprint_expires; void centerprint_atprio(entity e, float prio, string s) diff --git a/data/qcsrc/server/progs.src b/data/qcsrc/server/progs.src index 9258d5bae..77e729026 100644 --- a/data/qcsrc/server/progs.src +++ b/data/qcsrc/server/progs.src @@ -81,3 +81,6 @@ clientcommands.qc campaign.qc ../common/campaign_file.qc ../common/campaign_setup.qc + +../common/gamecommand.qc +gamecommand.qc diff --git a/data/qcsrc/server/t_items.qc b/data/qcsrc/server/t_items.qc index 494f10641..752d81675 100644 --- a/data/qcsrc/server/t_items.qc +++ b/data/qcsrc/server/t_items.qc @@ -687,19 +687,20 @@ float Item_WeaponCode(float it) } } -spawnfunc Item_SpawnFunc(float it) +void Item_SpawnByItemCode(float it) { switch(it) { - case IT_SHOTGUN: return weapon_shotgun; - case IT_UZI: return weapon_uzi; - case IT_GRENADE_LAUNCHER: return weapon_grenadelauncher; - case IT_ELECTRO: return weapon_electro; - case IT_CRYLINK: return weapon_crylink; - case IT_NEX: return weapon_nex; - case IT_HAGAR: return weapon_hagar; - case IT_ROCKET_LAUNCHER: return weapon_rocketlauncher; + case IT_SHOTGUN: weapon_shotgun(); break; + case IT_UZI: weapon_uzi(); break; + case IT_GRENADE_LAUNCHER: weapon_grenadelauncher(); break; + case IT_ELECTRO: weapon_electro(); break; + case IT_CRYLINK: weapon_crylink(); break; + case IT_NEX: weapon_nex(); break; + case IT_HAGAR: weapon_hagar(); break; + case IT_ROCKET_LAUNCHER: weapon_rocketlauncher(); break; // add all other item spawn functions here - default: error("requested item can't be spawned"); + default: + error("requested item can't be spawned"); } } -- 2.39.2