diff --git a/include/QF/progs.h b/include/QF/progs.h index af326dfed..66009b0a7 100644 --- a/include/QF/progs.h +++ b/include/QF/progs.h @@ -178,6 +178,23 @@ qboolean PR_EdictValid (progs_t *pr, int e); #define E_GSTRING(p,e,o) (PR_GetString (p, E_STRING (e, o))) #define E_DSTRING(p,e,o) (PR_GetDString (p, E_STRING (e, o))) +/* + Builtins are arranged into groups of 65536 to allow for diffent expantion + sets. eg, stock id is 0x0000xxxx, quakeforge is 0x000fxxxx. predefined + groups go up to 0x0fffxxxx allowing 4096 different groups. Builtins + 0x10000000 to 0x7fffffff are reserved for auto-allocation. The range + 0x8000000 to 0xffffffff is unavailable due to the builtin number being + a negative statement address. +*/ +#define PR_RANGE_SHIFT 16 +#define PR_RANGE_MASK 0xffff0000 + +#define PR_RANGE_QF 0x000f + +#define PR_RANGE_AUTO 0x1000 +#define PR_RANGE_NONE 0xffff +#define PR_AUTOBUILTIN (PR_RANGE_AUTO << PR_RANGE_SHIFT) + typedef void (*builtin_proc) (progs_t *pr); typedef struct { const char *name; diff --git a/libs/gamecode/builtins/pr_cmds.c b/libs/gamecode/builtins/pr_cmds.c index 204c2bd3a..8077805db 100644 --- a/libs/gamecode/builtins/pr_cmds.c +++ b/libs/gamecode/builtins/pr_cmds.c @@ -592,6 +592,8 @@ PR_gametype (progs_t *pr) RETURN_STRING (pr, pr_gametype); } +#define QF (PR_RANGE_QF << PR_RANGE_SHIFT) | + static builtin_t builtins[] = { {"break", PF_break, 6}, {"random", PF_random, 7}, @@ -617,15 +619,15 @@ static builtin_t builtins[] = { {"stof", PF_stof, 81}, - {"strlen", PF_strlen, 100}, - {"charcount", PF_charcount, 101}, - {"sprintf", PF_sprintf, 109}, - {"ftoi", PF_ftoi, 110}, - {"itof", PF_itof, 111}, - {"itos", PF_itos, 112}, - {"stoi", PF_stoi, 113}, - {"stov", PF_stov, 114}, - {"gametype", PR_gametype, 115}, + {"strlen", PF_strlen, QF 100}, + {"charcount", PF_charcount, QF 101}, + {"sprintf", PF_sprintf, QF 109}, + {"ftoi", PF_ftoi, QF 110}, + {"itof", PF_itof, QF 111}, + {"itos", PF_itos, QF 112}, + {"stoi", PF_stoi, QF 113}, + {"stov", PF_stov, QF 114}, + {"gametype", PR_gametype, QF 115}, {0} }; diff --git a/libs/gamecode/engine/pr_builtins.c b/libs/gamecode/engine/pr_builtins.c index fffc54232..7230f69c0 100644 --- a/libs/gamecode/engine/pr_builtins.c +++ b/libs/gamecode/engine/pr_builtins.c @@ -54,16 +54,6 @@ static __attribute__ ((unused)) const char rcsid[] = #include "compat.h" -/* - Builtins are arranged into groups of 65536 to allow for diffent expantion - sets. eg, stock id is 0x0000xxxx, quakeforge is 0x000fxxxx. predefined - groups go up to 0x0fffxxxx allowing 4096 different groups. Builtins - 0x10000000 to 0x7fffffff are reserved for auto-allocation. The range - 0x8000000 to 0xffffffff is unavailable due to the builtin number being - a negative statement address. -*/ -#define PR_AUTOBUILTIN 0x10000000 - static const char * builtin_get_key (void *_bi, void *unused) { diff --git a/nq/include/sv_progs.h b/nq/include/sv_progs.h index 4b73a1393..6dcdfe3a9 100644 --- a/nq/include/sv_progs.h +++ b/nq/include/sv_progs.h @@ -187,6 +187,9 @@ typedef struct extern sv_fields_t sv_fields; +#define PR_RANGE_ID 0x0000 +#define PR_RANGE_ID_MAX 82 + #if TYPECHECK_PROGS #define SVFIELD(e,f,t) E_var (e, PR_AccessField (&sv_pr_state, #f, ev_##t, __FILE__, __LINE__), t) #else diff --git a/nq/source/sv_pr_cmds.c b/nq/source/sv_pr_cmds.c index b1b8c1e24..fbadde278 100644 --- a/nq/source/sv_pr_cmds.c +++ b/nq/source/sv_pr_cmds.c @@ -1351,6 +1351,8 @@ PF_checkextension (progs_t *pr) R_FLOAT (pr) = 0; // FIXME: make this function actually useful } +#define QF (PR_RANGE_QF << PR_RANGE_SHIFT) | + static builtin_t builtins[] = { {"makevectors", PF_makevectors, 1}, {"setorigin", PF_setorigin, 2}, @@ -1397,12 +1399,12 @@ static builtin_t builtins[] = { {"precache_sound2", PF_precache_sound, 76}, {"precache_file2", PF_precache_file, 77}, {"setspawnparms", PF_setspawnparms, 78}, - {"hullpointcontents", PF_hullpointcontents, 93}, - {"getboxbounds", PF_getboxbounds, 94}, - {"getboxhull", PF_getboxhull, 95}, - {"freeboxhull", PF_freeboxhull, 96}, - {"rotate_bbox", PF_rotate_bbox, 97}, - {"checkextension", PF_checkextension, 99}, + {"hullpointcontents", PF_hullpointcontents, QF 93}, + {"getboxbounds", PF_getboxbounds, QF 94}, + {"getboxhull", PF_getboxhull, QF 95}, + {"freeboxhull", PF_freeboxhull, QF 96}, + {"rotate_bbox", PF_rotate_bbox, QF 97}, + {"checkextension", PF_checkextension, QF 99}, {0} }; diff --git a/nq/source/sv_progs.c b/nq/source/sv_progs.c index 7b890d20f..eef1327b9 100644 --- a/nq/source/sv_progs.c +++ b/nq/source/sv_progs.c @@ -43,6 +43,7 @@ static __attribute__ ((unused)) const char rcsid[] = #include "QF/cvar.h" #include "QF/quakefs.h" +#include "compat.h" #include "host.h" #include "server.h" #include "sv_progs.h" @@ -55,6 +56,7 @@ sv_fields_t sv_fields; cvar_t *sv_progs; cvar_t *sv_progs_zone; +cvar_t *sv_progs_ext; cvar_t *pr_checkextensions; cvar_t *nomonsters; @@ -71,6 +73,22 @@ cvar_t *saved4; func_t EndFrame; +static int sv_range; + +static unsigned +bi_map (progs_t *pr, unsigned binum) +{ + unsigned range; + + if (sv_range != PR_RANGE_NONE) { + range = (binum & PR_RANGE_MASK) >> PR_RANGE_SHIFT; + + if (!range && binum > PR_RANGE_ID_MAX) + binum |= sv_range << PR_RANGE_SHIFT; + } + return binum; +} + static int prune_edict (progs_t *pr, edict_t *ent) { @@ -143,12 +161,25 @@ SV_LoadProgs (void) ddef_t *def; dfunction_t *f; const char *progs_name = "progs.dat"; + const char *range; if (qfs_gamedir->gamecode && *qfs_gamedir->gamecode) progs_name = qfs_gamedir->gamecode; if (*sv_progs->string) progs_name = sv_progs->string; + if (strequal (sv_progs_ext->string, "qf")) { + sv_range = PR_RANGE_QF; + range = "QF"; + } else if (strequal (sv_progs_ext->string, "id")) { + sv_range = PR_RANGE_ID; + range = "ID"; + } else { + sv_range = PR_RANGE_NONE; + range = "None"; + } + Con_DPrintf ("Using %s builtin extention mapping\n", range); + PR_LoadProgs (&sv_pr_state, progs_name, sv.max_edicts, sv_progs_zone->int_val * 1024); if (!sv_pr_state.progs) @@ -342,6 +373,7 @@ SV_Progs_Init (void) sv_pr_state.unlink = SV_UnlinkEdict; sv_pr_state.parse_field = parse_field; sv_pr_state.prune_edict = prune_edict; + sv_pr_state.bi_map = bi_map; SV_PR_Cmds_Init (); @@ -362,6 +394,9 @@ SV_Progs_Init_Cvars (void) "Override the default game progs."); sv_progs_zone = Cvar_Get ("sv_progs_zone", "256", CVAR_NONE, NULL, "size of the zone for progs in kb"); + sv_progs_ext = Cvar_Get ("sv_progs_ext", "qf", CVAR_NONE, NULL, + "extention mapping to use: " + "none, id, qf"); pr_checkextensions = Cvar_Get ("pr_checkextensions", "1", CVAR_ROM, NULL, "indicate the presence of the " "checkextentions qc function"); diff --git a/qw/include/sv_pr_qwe.h b/qw/include/sv_pr_qwe.h new file mode 100644 index 000000000..37dd189c2 --- /dev/null +++ b/qw/include/sv_pr_qwe.h @@ -0,0 +1,36 @@ +/* + sv_pr_qwe.h + + server side QuakeC builtins + + Copyright (C) 1996-1997 Id Software, Inc. + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + + $Id$ +*/ + +#ifndef __sv_pr_qwe_h +#define __sv_pr_qwe_h + +struct progs_s; + +void SV_PR_QWE_Init (struct progs_s *pr); + +#endif // __sv_pr_qwe_h diff --git a/qw/include/sv_progs.h b/qw/include/sv_progs.h index 1949cc684..f6ab80453 100644 --- a/qw/include/sv_progs.h +++ b/qw/include/sv_progs.h @@ -176,6 +176,10 @@ extern sv_fields_t sv_fields; extern struct progs_s sv_pr_state; +#define PR_RANGE_ID 0x0000 +#define PR_RANGE_ID_MAX 82 +#define PR_RANGE_QWE 0x0001 + #if TYPECHECK_PROGS #define SVFIELD(e,f,t) E_var (e, PR_AccessField (&sv_pr_state, #f, ev_##t, __FILE__, __LINE__), t) #else diff --git a/qw/source/Makefile.am b/qw/source/Makefile.am index 63f010f67..f773257cb 100644 --- a/qw/source/Makefile.am +++ b/qw/source/Makefile.am @@ -70,8 +70,8 @@ EXTRA_DIST=sv_sys_win.c sv_sys_unix.c libqw_server_a_SOURCES= \ crudefile.c sv_ccmds.c sv_demo.c sv_ents.c sv_gib.c sv_init.c sv_main.c \ - sv_move.c sv_nchan.c sv_phys.c sv_pr_cmds.c sv_progs.c sv_send.c \ - sv_user.c world.c $(syssv_SRC) + sv_move.c sv_nchan.c sv_phys.c sv_pr_cmds.c sv_pr_qwe.c sv_progs.c \ + sv_send.c sv_user.c world.c $(syssv_SRC) qf_server_LIBS= \ $(SERVER_PLUGIN_STATIC_LIBS) \ diff --git a/qw/source/sv_pr_cmds.c b/qw/source/sv_pr_cmds.c index 3313154b3..64cc584ca 100644 --- a/qw/source/sv_pr_cmds.c +++ b/qw/source/sv_pr_cmds.c @@ -1912,6 +1912,8 @@ PR_SV_Spawn (progs_t *pr) SV_Spawn (cl); } +#define QF (PR_RANGE_QF << PR_RANGE_SHIFT) | + static builtin_t builtins[] = { {"makevectors", PF_makevectors, 1}, {"setorigin", PF_setorigin, 2}, @@ -1974,22 +1976,22 @@ static builtin_t builtins[] = { {"logfrag", PF_logfrag, 79}, {"infokey", PF_infokey, 80}, {"multicast", PF_multicast, 82}, - {"testentitypos", PF_testentitypos, 92}, - {"hullpointcontents", PF_hullpointcontents, 93}, - {"getboxbounds", PF_getboxbounds, 94}, - {"getboxhull", PF_getboxhull, 95}, - {"freeboxhull", PF_freeboxhull, 96}, - {"rotate_bbox", PF_rotate_bbox, 97}, + {"testentitypos", PF_testentitypos, QF 92}, + {"hullpointcontents", PF_hullpointcontents, QF 93}, + {"getboxbounds", PF_getboxbounds, QF 94}, + {"getboxhull", PF_getboxhull, QF 95}, + {"freeboxhull", PF_freeboxhull, QF 96}, + {"rotate_bbox", PF_rotate_bbox, QF 97}, - {"checkmove", PF_checkmove, 98}, - {"checkextension", PF_checkextension, 99}, - {"setinfokey", PF_setinfokey, 102}, - {"cfopen", PF_cfopen, 103}, - {"cfclose", PF_cfclose, 104}, - {"cfread", PF_cfread, 105}, - {"cfwrite", PF_cfwrite, 106}, - {"cfeof", PF_cfeof, 107}, - {"cfquota", PF_cfquota, 108}, + {"checkmove", PF_checkmove, QF 98}, + {"checkextension", PF_checkextension, QF 99}, + {"setinfokey", PF_setinfokey, QF 102}, + {"cfopen", PF_cfopen, QF 103}, + {"cfclose", PF_cfclose, QF 104}, + {"cfread", PF_cfread, QF 105}, + {"cfwrite", PF_cfwrite, QF 106}, + {"cfeof", PF_cfeof, QF 107}, + {"cfquota", PF_cfquota, QF 108}, {"SV_AllocClient", PF_SV_AllocClient, -1}, {"SV_FreeClient", PF_SV_FreeClient, -1}, diff --git a/qw/source/sv_pr_qwe.c b/qw/source/sv_pr_qwe.c new file mode 100644 index 000000000..20fe9e018 --- /dev/null +++ b/qw/source/sv_pr_qwe.c @@ -0,0 +1,566 @@ +/* + sv_pr_qwe.c + + qwe extentions needed by the KTPro mod + + Copyright (C) 2003 Bill Currie + + Author: Bill Currie + Date: 2003/11/17 + + taken from qwe (actual author currently unkown, probably + `highlander') and ported to qf + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +static __attribute__ ((unused)) +const char rcsid[] = "$Id$"; + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "QF/cbuf.h" +#include "QF/cmd.h" +#include "QF/dstring.h" +#include "QF/idparse.h" +#include "QF/progs.h" +#include "QF/quakefs.h" +#include "QF/sys.h" +#include "QF/va.h" + +#include "sv_demo.h" +#include "sv_pr_qwe.h" +#include "sv_progs.h" + +typedef struct { + func_t timeofday; + func_t ConsoleCmd; + func_t UserCmd; +} qwe_funcs_t; + +static qwe_funcs_t qwe_funcs; + +static void +PF_executecmd (progs_t * pr) +{ + int old_other, old_self; // mod_consolecmd will be executed, so + // we need to store these + + old_self = *sv_globals.self; + old_other = *sv_globals.other; + + Cbuf_Execute (sv_cbuf); + + *sv_globals.self = old_self; + *sv_globals.other = old_other; +} + +/* + PF_tokanize + + tokanize string + + void tokanize(string) +*/ + +static void +PF_tokanize (progs_t * pr) +{ + const char *str; + + str = P_GSTRING (pr, 0); + COM_TokenizeString (str, sv_args); + cmd_args = sv_args; +} + +/* + PF_argc + + returns number of tokens (must be executed after PF_Tokanize!) + + float argc(void) +*/ + +static void +PF_argc (progs_t * pr) +{ + R_FLOAT (pr) = (float) Cmd_Argc (); +} + +/* + PF_argv + + returns token requested by user (must be executed after PF_Tokanize!) + + string argc(float) +*/ + +static void +PF_argv (progs_t * pr) +{ + int num; + + num = (int) P_FLOAT (pr, 0); + + if (num < 0) + num = 0; + if (num > Cmd_Argc () - 1) + num = Cmd_Argc () - 1; + + RETURN_STRING (pr, Cmd_Argv (num)); +} + +/* + PF_teamfield + + string teamfield(.string field) +*/ + +static void +PF_teamfield (progs_t * pr) +{ + sv_fields.team_str = P_INT (pr, 0); +} + +/* + PF_substr + + string substr(string str, float start, float len) +*/ + +static void +PF_substr (progs_t * pr) +{ + const char *s; + char *tmp; + int start, len, l; + + s = P_GSTRING (pr, 0); + start = (int) P_FLOAT (pr, 1); + len = (int) P_FLOAT (pr, 2); + l = strlen (s); + + if (start >= l || !len || !*s) { + R_STRING (pr) = 0; + return; + } + + s += start; + l -= start; + + if (len > l + 1) + len = l + 1; + + tmp = Hunk_TempAlloc (len); + strncpy (tmp, s, len - 1); + tmp[len] = 0; + + RETURN_STRING (pr, tmp); +} + +/* + PF_strcat + + string strcat(string str1, string str2) +*/ + +static void +PF_strcat (progs_t * pr) +{ + RETURN_STRING (pr, PF_VarString (pr, 0)); +} + +/* + PF_strlen + + float strlen(string str) +*/ + +static void +PF_strlen (progs_t * pr) +{ + R_FLOAT (pr) = (float) strlen (P_GSTRING (pr, 0)); +} + +/* + PF_str2byte + + float str2byte (string str) +*/ + +static void +PF_str2byte (progs_t * pr) +{ + R_FLOAT (pr) = (float) *P_GSTRING (pr, 0); +} + +/* + PF_str2short + + float str2short (string str) +*/ + +static void +PF_str2short (progs_t * pr) +{ + const unsigned char *str = P_GSTRING (pr, 0); + + R_FLOAT (pr) = (short) ((str[1] << 8) | str[0]); +} + + +/* + PF_newstr + + string newstr (string str [, float size]) + + ignores size (there for compatability with qwe) +*/ +static void +PF_newstr (progs_t * pr) +{ + const char *s; + dstring_t *dstr; + int i; + + s = P_GSTRING (pr, 0); + + i = PR_NewString (pr); + dstr = PR_GetDString (pr, i); + + dstring_copystr (dstr, s); + + R_STRING (pr) = i; +} + +/* + PF_frestr + + void freestr (string str) +*/ + +static void +PF_freestr (progs_t * pr) +{ + PR_FreeString (pr, P_STRING (pr, 0)); +} + +/* + PF_readcmd + + string readmcmd (string str) +*/ + +static void +PF_readcmd (progs_t *pr) +{ + const char *s; + redirect_t old; + + s = P_GSTRING (pr, 0); + + Cbuf_Execute (sv_cbuf); + Cbuf_AddText (sv_cbuf, s); + + old = sv_redirected; + if (old != RD_NONE) + SV_EndRedirect (); + + SV_BeginRedirect (RD_MOD); + Cbuf_Execute (sv_cbuf); + RETURN_STRING (pr, outputbuf.str); + SV_EndRedirect (); + + if (old != RD_NONE) + SV_BeginRedirect (old); +} + +/* + PF_redirectcmd + + void redirectcmd (entity to, string str) +*/ + +static void +PF_redirectcmd (progs_t *pr) +{ + const char *s; + int entnum; + extern redirect_t sv_redirected; + + if (sv_redirected) + return; + + entnum = P_EDICTNUM (pr, 0); + if (entnum < 1 || entnum > MAX_CLIENTS) + PR_RunError (pr, "Parm 0 not a client"); + + s = P_GSTRING (pr, 1); + + Cbuf_AddText (sv_cbuf, s); + + SV_BeginRedirect (RD_MOD + entnum); + Cbuf_Execute (sv_cbuf); + SV_EndRedirect (); +} + +static void +PF_calltimeofday (progs_t * pr) +{ + date_t date; + dfunction_t *f; + + if ((f = ED_FindFunction (pr, "timeofday")) != NULL) { + + Sys_TimeOfDay (&date); + + PR_PushFrame (&sv_pr_state); + P_FLOAT (pr, 0) = (float) date.sec; + P_FLOAT (pr, 1) = (float) date.min; + P_FLOAT (pr, 2) = (float) date.hour; + P_FLOAT (pr, 3) = (float) date.day; + P_FLOAT (pr, 4) = (float) date.mon; + P_FLOAT (pr, 5) = (float) date.year; + P_STRING (pr, 6) = PR_SetTempString (pr, date.str); + + PR_ExecuteProgram (pr, (func_t) (f - sv_pr_state.pr_functions)); + PR_PopFrame (&sv_pr_state); + } +} + +/* + PF_forcedemoframe + + void PF_forcedemoframe(float now) + Forces demo frame + if argument 'now' is set, frame is written instantly +*/ + +static void +PF_forcedemoframe (progs_t * pr) +{ + demo.forceFrame = 1; + if (P_FLOAT (pr, 0) == 1) + SV_SendDemoMessage (); +} + + +/* + PF_strcpy + + void strcpy(string dst, string src) +*/ + +static void +PF_strcpy (progs_t * pr) +{ + dstring_copystr (P_DSTRING (pr, 0), P_GSTRING (pr, 1)); +} + +/* + PF_strncpy + + void strcpy(string dst, string src, float count) +*/ + +static void +PF_strncpy (progs_t * pr) +{ + dstring_t *dst = P_DSTRING (pr, 0); + const char *src = P_GSTRING (pr, 1); + size_t count = P_FLOAT (pr, 2); + + dst->size = count; + dstring_adjust (dst); + strncpy (dst->str, src, count); +} + + +/* + PF_strstr + + string strstr(string str, string sub) +*/ + +static void +PF_strstr (progs_t * pr) +{ + const char *str, *sub, *p; + + str = P_GSTRING (pr, 0); + sub = P_GSTRING (pr, 1); + + if ((p = strstr (str, sub)) == NULL) { + R_STRING (pr) = 0; + return; + } + + R_STRING (pr) = p - pr->pr_strings; +} + +static inline void +clean_text (unsigned char *text) +{ + while (*text) { + *text = sys_char_map[*text]; + text++; + } +} + +/* + PF_log + + void log(string name, float console, string text) +*/ + +static void +PF_log (progs_t * pr) +{ + const char *name; + char *text; + QFile *file; + + name = va ("%s/%s.log", qfs_gamedir->dir.def, P_GSTRING (pr, 0)); + file = QFS_Open (name, "a"); + + text = PF_VarString (pr, 2); + clean_text (text); + + if (P_FLOAT (pr, 1)) + Sys_Printf ("%s", text); + + if (!file) { + Sys_Printf ("coldn't open log file %s\n", name); + } else { + Qputs (file, text); + Qflush (file); + Qclose (file); + } +} + +/* + PF_conprint +*/ +static void +PF_conprint (progs_t * pr) +{ + Con_Printf ("%s", PF_VarString (pr, 0)); +} + +#define QWE (PR_RANGE_QWE << PR_RANGE_SHIFT) | + +static builtin_t builtins[] = { + {"QWE:executecmd", PF_executecmd, QWE 83}, + {"QWE:tokanize" /* sic */, PF_tokanize, QWE 84}, + {"QWE:argc", PF_argc, QWE 85}, + {"QWE:argv", PF_argv, QWE 86}, + {"QWE:teamfield", PF_teamfield, QWE 87}, + {"QWE:substr", PF_substr, QWE 88}, + {"QWE:strcat", PF_strcat, QWE 89}, + {"QWE:strlen", PF_strlen, QWE 90}, + {"QWE:str2byte", PF_str2byte, QWE 91}, + {"QWE:str2short", PF_str2short, QWE 92}, + {"QWE:newstr", PF_newstr, QWE 93}, + {"QWE:freestr", PF_freestr, QWE 94}, + {"QWE:conprint", PF_conprint, QWE 95}, + {"QWE:readcmd", PF_readcmd, QWE 96}, + {"QWE:strcpy", PF_strcpy, QWE 97}, + {"QWE:strstr", PF_strstr, QWE 98}, + {"QWE:strncpy", PF_strncpy, QWE 99}, + {"QWE:log", PF_log, QWE 100}, + {"QWE:redirectcmd", PF_redirectcmd, QWE 101}, + {"QWE:calltimeofday", PF_calltimeofday, QWE 102}, + {"QWE:forceddemoframe", PF_forcedemoframe, QWE 103}, +}; + +static struct { + const char *name; + int *field; +} qwe_func_list[] = { + {"timeofday", &qwe_funcs.timeofday}, + {"ConsoleCmd", &qwe_funcs.ConsoleCmd}, + {"UserCmd", &qwe_funcs.UserCmd}, + {"localinfoChanged", &sv_funcs.LocalinfoChanged}, + {"UserInfo_Changed", &sv_funcs.UserInfoChanged}, + {"ChatMessage", &sv_funcs.ChatMessage}, +}; + +static int +qwe_console_cmd (void) +{ + if (qwe_funcs.ConsoleCmd) { + if (sv_redirected != RD_MOD) { + *sv_globals.time = sv.time; + *sv_globals.self = 0; + } + PR_ExecuteProgram (&sv_pr_state, qwe_funcs.ConsoleCmd); + return (int) R_FLOAT (&sv_pr_state); + } + + return false; +} + +static int +qwe_user_cmd (void) +{ + if (qwe_funcs.UserCmd) { + if (sv_redirected != RD_MOD) { + *sv_globals.time = sv.time; + *sv_globals.self = EDICT_TO_PROG(&sv_pr_state, sv_player); + } + PR_ExecuteProgram (&sv_pr_state, qwe_funcs.UserCmd); + return (int) R_FLOAT (&sv_pr_state); + } + + return false; +} + +static int +qwe_load (progs_t * pr) +{ + int i; + + for (i = 0; i < sizeof (qwe_func_list) / sizeof (qwe_func_list[0]); i++) { + dfunction_t *f = ED_FindFunction (pr, qwe_func_list[i].name); + + *qwe_func_list[i].field = 0; + if (f) + *qwe_func_list[i].field = (func_t) (f - pr->pr_functions); + } + return 1; +} + +void +SV_PR_QWE_Init (progs_t *pr) +{ + PR_RegisterBuiltins (pr, builtins); + PR_AddLoadFunc (pr, qwe_load); + + sv_cbuf->unknown_command = qwe_console_cmd; + ucmd_unknown = qwe_user_cmd; +} diff --git a/qw/source/sv_progs.c b/qw/source/sv_progs.c index 0cd39d0cb..ef7f50431 100644 --- a/qw/source/sv_progs.c +++ b/qw/source/sv_progs.c @@ -43,6 +43,7 @@ #include "compat.h" #include "server.h" #include "sv_progs.h" +#include "sv_pr_qwe.h" #include "world.h" sv_globals_t sv_globals; @@ -53,12 +54,29 @@ progs_t sv_pr_state; cvar_t *r_skyname; cvar_t *sv_progs; cvar_t *sv_progs_zone; +cvar_t *sv_progs_ext; cvar_t *pr_checkextensions; cvar_t *sv_old_entity_free; cvar_t *sv_hide_version_info; static int reserved_edicts = MAX_CLIENTS; +static int sv_range; + +static unsigned +bi_map (progs_t *pr, unsigned binum) +{ + unsigned range; + + if (sv_range != PR_RANGE_NONE) { + range = (binum & PR_RANGE_MASK) >> PR_RANGE_SHIFT; + + if (!range && binum > PR_RANGE_ID_MAX) + binum |= sv_range << PR_RANGE_SHIFT; + } + return binum; +} + static void free_edict (progs_t *pr, edict_t *ent) { @@ -162,9 +180,26 @@ SV_LoadProgs (void) ddef_t *def; dfunction_t *f; const char *progs_name = "qwprogs.dat"; + const char *range; memset (&sv_funcs, 0, sizeof (sv_funcs)); + if (strequal (sv_progs_ext->string, "qf")) { + sv_range = PR_RANGE_QF; + range = "QF"; + } else if (strequal (sv_progs_ext->string, "id")) { + sv_range = PR_RANGE_ID; + range = "ID"; + } else if (strequal (sv_progs_ext->string, "qwe") + || strequal (sv_progs_ext->string, "ktpro")) { + sv_range = PR_RANGE_QWE; + range = "QWE/KTPro"; + } else { + sv_range = PR_RANGE_NONE; + range = "None"; + } + Con_DPrintf ("Using %s builtin extention mapping\n", range); + if (qfs_gamedir->gamecode && *qfs_gamedir->gamecode) progs_name = qfs_gamedir->gamecode; if (*sv_progs->string) @@ -351,9 +386,11 @@ SV_Progs_Init (void) sv_pr_state.parse_field = parse_field; sv_pr_state.prune_edict = prune_edict; sv_pr_state.free_edict = free_edict; // eww, I hate the need for this :( + sv_pr_state.bi_map = bi_map; PR_Resources_Init (&sv_pr_state); SV_PR_Cmds_Init (); + SV_PR_QWE_Init (&sv_pr_state); Cmd_Progs_Init (&sv_pr_state); Hash_Progs_Init (&sv_pr_state); @@ -376,6 +413,9 @@ SV_Progs_Init_Cvars (void) "Override the default game progs."); sv_progs_zone = Cvar_Get ("sv_progs_zone", "256", CVAR_NONE, NULL, "size of the zone for progs in kb"); + sv_progs_ext = Cvar_Get ("sv_progs_ext", "qf", CVAR_NONE, NULL, + "extention mapping to use: " + "none, id, qf, qwe, ktpro"); pr_checkextensions = Cvar_Get ("pr_checkextensions", "1", CVAR_ROM, NULL, "indicate the presence of the " "checkextentions qc function");