mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-27 06:34:11 +00:00
575 lines
9.9 KiB
C
575 lines
9.9 KiB
C
/*
|
|
sv_pr_qwe.c
|
|
|
|
qwe extentions needed by the KTPro mod
|
|
|
|
Copyright (C) 2003 Bill Currie
|
|
|
|
Author: Bill Currie <bill@taniwha.org>
|
|
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__ ((used))
|
|
const char rcsid[] = "$Id$";
|
|
|
|
#ifdef HAVE_STRING_H
|
|
# include <string.h>
|
|
#endif
|
|
#ifdef HAVE_STRINGS_H
|
|
# include <strings.h>
|
|
#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 "server.h"
|
|
#include "sv_pr_qwe.h"
|
|
#include "sv_progs.h"
|
|
#include "sv_recorder.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
|
|
|
|
tokenize 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 - 1] = 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 byte *str = (byte *) P_GSTRING (pr, 0);
|
|
|
|
R_FLOAT (pr) = (short) ((str[1] << 8) | str[0]);
|
|
}
|
|
|
|
|
|
/*
|
|
PF_newstr
|
|
|
|
string newstr (string str [, float size])
|
|
The new string will be at least as big as size, if given.
|
|
*/
|
|
static void
|
|
PF_newstr (progs_t *pr)
|
|
{
|
|
const char *s;
|
|
dstring_t *dstr;
|
|
int i;
|
|
|
|
s = P_GSTRING (pr, 0);
|
|
|
|
i = PR_NewMutableString (pr);
|
|
dstr = PR_GetMutableString (pr, i);
|
|
|
|
dstring_copystr (dstr, s);
|
|
|
|
if (pr->pr_argc > 1 && P_FLOAT (pr, 1) > dstr->size) {
|
|
int s = dstr->size;
|
|
dstr->size = P_FLOAT (pr, 1) + 1;
|
|
dstring_adjust (dstr);
|
|
memset (dstr->str + s, dstr->size - s, 0);
|
|
}
|
|
|
|
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 = PR_FindFunction (pr, "timeofday")) != NULL) {
|
|
|
|
Sys_TimeOfDay (&date);
|
|
|
|
PR_PushFrame (&sv_pr_state);
|
|
PR_RESET_PARAMS (pr);
|
|
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)
|
|
{
|
|
SVR_ForceFrame ();
|
|
if (P_FLOAT (pr, 0) == 1)
|
|
SVR_SendMessages ();
|
|
}
|
|
|
|
|
|
/*
|
|
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 (char *text)
|
|
{
|
|
while (*text) {
|
|
*text = sys_char_map[(byte) *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)
|
|
{
|
|
Sys_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},
|
|
{0}
|
|
};
|
|
|
|
static struct {
|
|
const char *name;
|
|
func_t *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)
|
|
{
|
|
size_t i;
|
|
|
|
for (i = 0; i < sizeof (qwe_func_list) / sizeof (qwe_func_list[0]); i++) {
|
|
dfunction_t *f = PR_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);
|
|
}
|
|
|
|
sv_cbuf->unknown_command = qwe_console_cmd;
|
|
ucmd_unknown = qwe_user_cmd;
|
|
return 1;
|
|
}
|
|
|
|
void
|
|
SV_PR_QWE_Init (progs_t *pr)
|
|
{
|
|
PR_RegisterBuiltins (pr, builtins);
|
|
PR_AddLoadFunc (pr, qwe_load);
|
|
}
|