mirror of
https://github.com/nzp-team/fteqw.git
synced 2024-11-23 04:11:53 +00:00
4c2066601a
Fixed up the -netquake / -spasm / -fitz args slightly, should actually be usable now. sv_mintic 0 is now treated as 0.013 when using nqplayerphysics, to try to make it smoother for nq clients. Preparing for astc's volume formats. Mostly for completeness, I was bored. Disabled for now because nothing supports them anyway. Fix broken mousewheel in SDL2 builds. Fix configs not getting loaded following initial downloads in the web port/etc. Make the near-cloud layer of q1 scrolling sky fully opaque by default (like vanilla). Sky fog now ignores depth, treating it as an infinite distance. Fix turbs not responding to fog. r_fullbright no longer needs vid_reload to take effect (and more efficient now). Tweaked the audio code to use an format enum instead of byte width, just with the same values still, primarily to clean up loaders that deal with S32 vs F32, or U8 vs S8. Added a cvar to control whether to use threads for the qcgc. Still disabled by default but no longer requires engine recompiles to enable! git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5683 fc73d0e0-1445-4013-8a0c-d673dee63da5
3340 lines
95 KiB
C
3340 lines
95 KiB
C
#include "quakedef.h"
|
|
|
|
#include "pr_common.h"
|
|
#include "shader.h"
|
|
|
|
#ifdef GLQUAKE
|
|
#include "glquake.h"
|
|
#endif
|
|
|
|
#if defined(MENU_DAT) || defined(CSQC_DAT)
|
|
#include "cl_master.h"
|
|
|
|
//MP_MouseMove(mx, my, mouse->qdeviceid)
|
|
|
|
static qbyte mpkeysdown[K_MAX/8];
|
|
extern qboolean csqc_dp_lastwas3d;
|
|
|
|
void M_Init_Internal (void);
|
|
void M_DeInit_Internal (void);
|
|
|
|
extern unsigned int r2d_be_flags;
|
|
#define DRAWFLAG_NORMAL 0
|
|
#define DRAWFLAG_ADD 1
|
|
#define DRAWFLAG_MODULATE 2
|
|
#define DRAWFLAG_MODULATE2 3
|
|
#define DRAWFLAG_2D (1u<<2)
|
|
#define DRAWFLAG_TWOSIDED 0x400
|
|
#define DRAWFLAG_LINES 0x800
|
|
static unsigned int PF_SelectDPDrawFlag(pubprogfuncs_t *prinst, int flag)
|
|
{
|
|
if (r_refdef.warndraw)
|
|
{
|
|
if (!*r_refdef.rt_destcolour[0].texname)
|
|
{
|
|
r_refdef.warndraw = false; //don't spam too much
|
|
PR_RunWarning(prinst, "Detected attempt to draw to framebuffer where framebuffer is not valid\n");
|
|
}
|
|
}
|
|
#ifdef CSQC_DAT
|
|
csqc_dp_lastwas3d = false; //for compat with dp's stupid beginpolygon
|
|
#endif
|
|
|
|
//flags:
|
|
//0 = blend
|
|
//1 = add
|
|
//2 = modulate
|
|
//3 = modulate*2
|
|
flag &= 3;
|
|
if (flag == DRAWFLAG_ADD)
|
|
return BEF_FORCEADDITIVE;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
//float drawfill(vector position, vector size, vector rgb, float alpha, float flag) = #457;
|
|
void QCBUILTIN PF_CL_drawfill (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
float *pos = G_VECTOR(OFS_PARM0);
|
|
float *size = G_VECTOR(OFS_PARM1);
|
|
float *rgb = G_VECTOR(OFS_PARM2);
|
|
float alpha = G_FLOAT(OFS_PARM3);
|
|
int flag = prinst->callargc >= 5?G_FLOAT(OFS_PARM4):0;
|
|
|
|
r2d_be_flags = PF_SelectDPDrawFlag(prinst, flag);
|
|
R2D_ImageColours(rgb[0], rgb[1], rgb[2], alpha);
|
|
R2D_FillBlock(pos[0], pos[1], size[0], size[1]);
|
|
r2d_be_flags = 0;
|
|
|
|
G_FLOAT(OFS_RETURN) = 1;
|
|
}
|
|
//void drawsetcliparea(float x, float y, float width, float height) = #458;
|
|
void QCBUILTIN PF_CL_drawsetcliparea (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
srect_t srect;
|
|
if (R2D_Flush)
|
|
R2D_Flush();
|
|
|
|
#ifdef CSQC_DAT
|
|
csqc_dp_lastwas3d = false;
|
|
#endif
|
|
|
|
srect.x = G_FLOAT(OFS_PARM0) / (float)vid.fbvwidth;
|
|
srect.y = G_FLOAT(OFS_PARM1) / (float)vid.fbvheight;
|
|
srect.width = G_FLOAT(OFS_PARM2) / (float)vid.fbvwidth;
|
|
srect.height = G_FLOAT(OFS_PARM3) / (float)vid.fbvheight;
|
|
srect.dmin = -99999;
|
|
srect.dmax = 99999;
|
|
srect.y = (1-srect.y) - srect.height;
|
|
BE_Scissor(&srect);
|
|
|
|
G_FLOAT(OFS_RETURN) = 1;
|
|
}
|
|
//void drawresetcliparea(void) = #459;
|
|
void QCBUILTIN PF_CL_drawresetcliparea (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
if (R2D_Flush)
|
|
R2D_Flush();
|
|
|
|
#ifdef CSQC_DAT
|
|
csqc_dp_lastwas3d = false;
|
|
#endif
|
|
|
|
BE_Scissor(NULL);
|
|
G_FLOAT(OFS_RETURN) = 1;
|
|
}
|
|
|
|
#define FONT_SLOTS 32
|
|
#define FONT_SIZES 16
|
|
struct {
|
|
unsigned int owner; //kdm_foo. whoever has an interest in this font. font is purged when this becomes 0.
|
|
char slotname[16];
|
|
char facename[MAX_OSPATH];
|
|
float scale; //poop
|
|
int outline; //argh
|
|
int sizes;
|
|
int size[FONT_SIZES];
|
|
struct font_s *font[FONT_SIZES];
|
|
} fontslot[FONT_SLOTS];
|
|
|
|
static struct font_s *PR_CL_ChooseFont(float *fontsel, int szx, int szy)
|
|
{
|
|
int fontidx = 0; //default by default...
|
|
struct font_s *font = font_default;
|
|
|
|
if (fontsel)
|
|
{
|
|
fontidx = *fontsel;
|
|
}
|
|
|
|
if (fontidx >= 0 && fontidx < FONT_SLOTS)
|
|
{
|
|
int i, j;
|
|
int fontdiff = 10000;
|
|
for (i = 0; i < fontslot[fontidx].sizes; i++)
|
|
{
|
|
j = abs(szy - fontslot[fontidx].size[i]);
|
|
if (j < fontdiff && fontslot[fontidx].font[i])
|
|
{
|
|
fontdiff = j;
|
|
font = fontslot[fontidx].font[i];
|
|
}
|
|
}
|
|
}
|
|
return font;
|
|
}
|
|
void PR_CL_BeginString(pubprogfuncs_t *prinst, float vx, float vy, float szx, float szy, float *px, float *py)
|
|
{
|
|
world_t *world = prinst->parms->user;
|
|
struct font_s *font;
|
|
if (world->g.drawfontscale && (world->g.drawfontscale[0] || world->g.drawfontscale[1]))
|
|
{
|
|
szx *= world->g.drawfontscale[0];
|
|
szy *= world->g.drawfontscale[1];
|
|
}
|
|
font = PR_CL_ChooseFont(world->g.drawfont, szx, szy);
|
|
Font_BeginScaledString(font, vx, vy, szx, szy, px, py);
|
|
}
|
|
int PR_findnamedfont(const char *name, qboolean isslotname)
|
|
{
|
|
int i;
|
|
if (isslotname)
|
|
{
|
|
for (i = 0; i < FONT_SLOTS; i++)
|
|
{
|
|
if (!stricmp(fontslot[i].slotname, name))
|
|
return i;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < FONT_SLOTS; i++)
|
|
{
|
|
if (!stricmp(fontslot[i].facename, name))
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
int PR_findunusedfont(void)
|
|
{
|
|
int i;
|
|
//don't find slot 0.
|
|
for (i = FONT_SLOTS; i-- > 1; )
|
|
{
|
|
if (!*fontslot[i].slotname && !*fontslot[i].facename)
|
|
return i;
|
|
}
|
|
return -1;
|
|
}
|
|
//purgeowner is the bitmask of owners that are getting freed.
|
|
//if purgeowner is 0, fonts will get purged
|
|
void PR_ReleaseFonts(unsigned int purgeowner)
|
|
{
|
|
int i, j;
|
|
|
|
for (i = 0; i < FONT_SLOTS; i++)
|
|
{
|
|
if (fontslot[i].owner)
|
|
continue; //already free
|
|
fontslot[i].owner &= ~purgeowner;
|
|
if (fontslot[i].owner)
|
|
continue; //still owned by someone
|
|
|
|
for (j = 0; j < fontslot[i].sizes; j++)
|
|
{
|
|
if (fontslot[i].font[j])
|
|
Font_Free(fontslot[i].font[j]);
|
|
fontslot[i].font[j] = NULL;
|
|
}
|
|
|
|
fontslot[i].sizes = 0;
|
|
fontslot[i].slotname[0] = '\0';
|
|
fontslot[i].facename[0] = '\0';
|
|
fontslot[i].scale = 1;
|
|
fontslot[i].outline = 0;
|
|
}
|
|
}
|
|
void PR_ReloadFonts(qboolean reload)
|
|
{
|
|
int i, j;
|
|
|
|
if (qrenderer == QR_NONE)
|
|
reload = false;
|
|
|
|
for (i = 0; i < FONT_SLOTS; i++)
|
|
{
|
|
//already not loaded
|
|
if (!fontslot[i].owner)
|
|
continue;
|
|
|
|
//flush it (if loaded)
|
|
for (j = 0; j < fontslot[i].sizes; j++)
|
|
{
|
|
if (fontslot[i].font[j])
|
|
Font_Free(fontslot[i].font[j]);
|
|
fontslot[i].font[j] = NULL;
|
|
}
|
|
//and reload if needed
|
|
if (reload)
|
|
{ //otherwise load it.
|
|
for (j = 0; j < fontslot[i].sizes; j++)
|
|
{
|
|
fontslot[i].font[j] = Font_LoadFont(fontslot[i].facename, fontslot[i].size[j], fontslot[i].scale, fontslot[i].outline);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
void QCBUILTIN PF_CL_findfont (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
const char *slotname = PR_GetStringOfs(prinst, OFS_PARM0);
|
|
G_FLOAT(OFS_RETURN) = PR_findnamedfont(slotname, true) + 1; //return default on failure.
|
|
}
|
|
void QCBUILTIN PF_CL_loadfont (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
extern cvar_t r_font_postprocess_outline;
|
|
const char *slotname = PR_GetStringOfs(prinst, OFS_PARM0);
|
|
const char *facename = PR_GetStringOfs(prinst, OFS_PARM1);
|
|
const char *sizestr = PR_GetStringOfs(prinst, OFS_PARM2);
|
|
int slotnum = (prinst->callargc>3)?G_FLOAT(OFS_PARM3):-1;
|
|
//float fix_scale = (prinst->callargc>4)?G_FLOAT(OFS_PARM4):0;
|
|
//float fix_voffset = (prinst->callargc>5)G_FLOAT(OFS_PARM5):0;
|
|
int i, sz;
|
|
world_t *world = prinst->parms->user;
|
|
|
|
G_FLOAT(OFS_RETURN) = 0; //return default on failure.
|
|
|
|
if (slotnum < 0 && *slotname)
|
|
slotnum = PR_findnamedfont(slotname, true);
|
|
else if (slotnum < 0)
|
|
slotnum = PR_findnamedfont(facename, false);
|
|
if (slotnum < 0)
|
|
slotnum = PR_findunusedfont();
|
|
if (slotnum < 0)
|
|
return; //eep.
|
|
|
|
if ((unsigned)slotnum >= FONT_SLOTS)
|
|
return;
|
|
|
|
//if its changed, purge it.
|
|
if (stricmp(fontslot[slotnum].slotname, slotname) || stricmp(fontslot[slotnum].facename, facename) || !fontslot[slotnum].sizes)
|
|
{
|
|
Q_strncpyz(fontslot[slotnum].slotname, slotname, sizeof(fontslot[slotnum].slotname));
|
|
Q_strncpyz(fontslot[slotnum].facename, facename, sizeof(fontslot[slotnum].facename));
|
|
for (i = 0; i < fontslot[slotnum].sizes; i++)
|
|
{
|
|
if (fontslot[slotnum].font[i])
|
|
Font_Free(fontslot[slotnum].font[i]);
|
|
fontslot[slotnum].font[i] = NULL;
|
|
}
|
|
fontslot[slotnum].sizes = 0;
|
|
fontslot[slotnum].owner = 0;
|
|
fontslot[slotnum].scale = 1;
|
|
fontslot[slotnum].outline = r_font_postprocess_outline.ival;
|
|
}
|
|
fontslot[slotnum].owner |= world->keydestmask;
|
|
|
|
while(*sizestr)
|
|
{
|
|
sizestr = COM_Parse(sizestr);
|
|
if (!strncmp(com_token, "scale=", 6))
|
|
{
|
|
fontslot[slotnum].scale = atof(com_token+6);
|
|
continue;
|
|
}
|
|
if (!strncmp(com_token, "outline=", 8))
|
|
{
|
|
fontslot[slotnum].outline = atoi(com_token+8);
|
|
continue;
|
|
}
|
|
if (!strncmp(com_token, "blur=", 5))
|
|
{
|
|
//fontslot[slotnum].blur = atoi(com_token+5);
|
|
continue;
|
|
}
|
|
if (!strncmp(com_token, "voffset=", 8))
|
|
{
|
|
//com_token+8 unused.
|
|
continue;
|
|
}
|
|
|
|
sz = atoi(com_token);
|
|
if (!sz)
|
|
continue; //o.O
|
|
|
|
for (i = 0; i < fontslot[slotnum].sizes; i++)
|
|
{
|
|
if (fontslot[slotnum].size[i] == sz)
|
|
break;
|
|
}
|
|
if (i == fontslot[slotnum].sizes)
|
|
{
|
|
if (i >= FONT_SIZES)
|
|
break;
|
|
fontslot[slotnum].size[i] = sz;
|
|
fontslot[slotnum].font[i] = NULL;
|
|
fontslot[slotnum].sizes++;
|
|
}
|
|
}
|
|
|
|
if (qrenderer > QR_NONE)
|
|
{
|
|
for (i = 0; i < fontslot[slotnum].sizes; i++)
|
|
fontslot[slotnum].font[i] = Font_LoadFont(facename, fontslot[slotnum].size[i], fontslot[slotnum].scale, fontslot[slotnum].outline);
|
|
}
|
|
|
|
G_FLOAT(OFS_RETURN) = slotnum;
|
|
}
|
|
|
|
#ifdef HAVE_LEGACY
|
|
void CL_LoadFont_f(void)
|
|
{
|
|
extern cvar_t r_font_postprocess_outline;
|
|
//console command for compat with dp/debug.
|
|
if (Cmd_Argc() == 1)
|
|
{
|
|
int i, j;
|
|
int th;
|
|
for (i = 0; i < FONT_SLOTS; i++)
|
|
{
|
|
if (fontslot[i].sizes)
|
|
{
|
|
Con_Printf("%s[%i]: %s (", fontslot[i].slotname, i, fontslot[i].facename);
|
|
for (j = 0; j < fontslot[i].sizes; j++)
|
|
{
|
|
if (j)
|
|
Con_Printf(", ");
|
|
Con_Printf("%i", fontslot[i].size[j]);
|
|
if (fontslot[i].font[j])
|
|
{
|
|
th = Font_GetTrueHeight(fontslot[i].font[j]);
|
|
if (th != Font_CharPHeight(fontslot[i].font[j]))
|
|
Con_Printf("[%g]", ((float)th*vid.height)/vid.pixelheight);
|
|
}
|
|
}
|
|
Con_Printf(")\n");
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int i;
|
|
int slotnum = 0;
|
|
char *slotname = Cmd_Argv(1);
|
|
char *facename = Cmd_Argv(2);
|
|
int sizenum = 3;
|
|
extern cvar_t dpcompat_console, gl_font, con_textfont;
|
|
|
|
//loadfont slot face size1 size2...
|
|
|
|
slotnum = PR_findnamedfont(slotname, true);
|
|
if (slotnum < 0)
|
|
{
|
|
char *dpnames[] = {"default", "console", "sbar", "notify", "chat", "centerprint", "infobar", "menu", "user0", "user1", "user2", "user3", "user4", "user5", "user6", "user7", NULL};
|
|
for (i = 0; dpnames[i]; i++)
|
|
{
|
|
if (!strcmp(dpnames[i], slotname))
|
|
{
|
|
//assign it to this slot only if this slot does not already have a face. avoids corrupting already-loaded fonts.
|
|
if (!*fontslot[i].facename)
|
|
slotnum = i;
|
|
break;
|
|
}
|
|
}
|
|
if (slotnum < 0)
|
|
slotnum = PR_findnamedfont("", true); //whatever is still free
|
|
}
|
|
if (slotnum < 0)
|
|
{
|
|
Con_Printf("out of font slots\n");
|
|
return;
|
|
}
|
|
|
|
//if there's a new font in this slot, purge the old and change the name+face strings
|
|
if (stricmp(fontslot[slotnum].slotname, slotname) || stricmp(fontslot[slotnum].facename, facename))
|
|
{
|
|
Q_strncpyz(fontslot[slotnum].slotname, slotname, sizeof(fontslot[slotnum].slotname));
|
|
Q_strncpyz(fontslot[slotnum].facename, facename, sizeof(fontslot[slotnum].facename));
|
|
for (i = 0; i < fontslot[slotnum].sizes; i++)
|
|
{
|
|
if (fontslot[slotnum].font[i])
|
|
Font_Free(fontslot[slotnum].font[i]);
|
|
fontslot[slotnum].font[i] = NULL;
|
|
}
|
|
fontslot[slotnum].owner = 0;
|
|
fontslot[slotnum].scale = 1;
|
|
fontslot[slotnum].sizes = 0;
|
|
fontslot[slotnum].outline = r_font_postprocess_outline.ival; //locked in at definition, so different fonts can have different settings even with vid_reload going on.
|
|
}
|
|
if (!*facename)
|
|
return;
|
|
fontslot[slotnum].owner |= kdm_console; //fonts owned by the console are never forgotten.
|
|
|
|
while(sizenum < Cmd_Argc())
|
|
{
|
|
const char *a = Cmd_Argv(sizenum++);
|
|
int sz;
|
|
if (!strcmp(a, "scale"))
|
|
{
|
|
fontslot[slotnum].scale = atof(Cmd_Argv(sizenum++));
|
|
continue;
|
|
}
|
|
if (!strcmp(a, "outline"))
|
|
{
|
|
fontslot[slotnum].outline = atoi(Cmd_Argv(sizenum++));
|
|
continue;
|
|
}
|
|
if (!strcmp(a, "blur"))
|
|
{
|
|
//fontslot[slotnum].blur = atoi(Cmd_Argv(sizenum++));
|
|
sizenum++;
|
|
continue;
|
|
}
|
|
if (!strcmp(a, "voffset"))
|
|
{
|
|
// fontslot[slotnum].voffset = atof(Cmd_Argv(sizenum++));
|
|
sizenum++;
|
|
continue;
|
|
}
|
|
sz = atoi(a);
|
|
if (sz <= 0)
|
|
sz = 8;
|
|
|
|
for (i = 0; i < fontslot[slotnum].sizes; i++)
|
|
{
|
|
if (fontslot[slotnum].size[i] == sz)
|
|
break;
|
|
}
|
|
if (i == fontslot[slotnum].sizes)
|
|
{
|
|
if (i >= FONT_SIZES)
|
|
break;
|
|
fontslot[slotnum].size[i] = sz;
|
|
fontslot[slotnum].font[i] = NULL;
|
|
fontslot[slotnum].sizes++;
|
|
}
|
|
}
|
|
|
|
if (qrenderer > QR_NONE)
|
|
{
|
|
for (i = 0; i < fontslot[slotnum].sizes; i++)
|
|
fontslot[slotnum].font[i] = Font_LoadFont(facename, fontslot[slotnum].size[i], fontslot[slotnum].scale, fontslot[slotnum].outline);
|
|
}
|
|
|
|
//FIXME: slotnum0==default is problematic.
|
|
if (dpcompat_console.ival && slotnum == 1)
|
|
Cvar_Set(&con_textfont, facename);
|
|
if (dpcompat_console.ival && slotnum == 0)
|
|
Cvar_Set(&gl_font, facename);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//scrolling could be done with scissoring.
|
|
//selection could be done with some substrings
|
|
void QCBUILTIN PF_CL_DrawTextField (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
float *pos = G_VECTOR(OFS_PARM0);
|
|
float *size = G_VECTOR(OFS_PARM1);
|
|
unsigned int flags = G_FLOAT(OFS_PARM2);
|
|
const char *text = PR_GetStringOfs(prinst, OFS_PARM3);
|
|
|
|
world_t *world = prinst->parms->user;
|
|
vec2_t scale = {8, 8};
|
|
struct font_s *font;
|
|
if (world->g.drawfontscale && (world->g.drawfontscale[0] || world->g.drawfontscale[1]))
|
|
{
|
|
scale[0] *= world->g.drawfontscale[0];
|
|
scale[1] *= world->g.drawfontscale[1];
|
|
}
|
|
font = PR_CL_ChooseFont(world->g.drawfont, scale[0], scale[1]);
|
|
|
|
// Oversight ~eukara
|
|
R2D_ImageColours(1.0f, 1.0f, 1.0f, 1.0f);
|
|
|
|
G_FLOAT(OFS_RETURN) = R_DrawTextField(pos[0], pos[1], size[0], size[1], text, CON_WHITEMASK, flags, font, scale);
|
|
}
|
|
|
|
//float drawstring(vector position, string text, vector scale, float alpha, float flag) = #455;
|
|
void QCBUILTIN PF_CL_drawcolouredstring (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
float *pos = G_VECTOR(OFS_PARM0);
|
|
const char *text = PR_GetStringOfs(prinst, OFS_PARM1);
|
|
float *size = G_VECTOR(OFS_PARM2);
|
|
float alpha = 0;
|
|
float flag = 0;
|
|
float r, g, b;
|
|
float px, py, ipx;
|
|
unsigned int codeflags, codepoint;
|
|
|
|
conchar_t buffer[2048], *str;
|
|
|
|
if (prinst->callargc >= 6)
|
|
{
|
|
r = G_FLOAT(OFS_PARM3 + 0);
|
|
g = G_FLOAT(OFS_PARM3 + 1);
|
|
b = G_FLOAT(OFS_PARM3 + 2);
|
|
alpha = G_FLOAT(OFS_PARM4);
|
|
flag = G_FLOAT(OFS_PARM5); //flag is mandatory to distinguish it.
|
|
}
|
|
else
|
|
{
|
|
r = 1;
|
|
g = 1;
|
|
b = 1;
|
|
alpha = G_FLOAT(OFS_PARM3);
|
|
flag = prinst->callargc >= 5?G_FLOAT(OFS_PARM4):0;
|
|
}
|
|
|
|
if (!text)
|
|
{
|
|
G_FLOAT(OFS_RETURN) = -1; //was null..
|
|
return;
|
|
}
|
|
|
|
COM_ParseFunString(CON_WHITEMASK, text, buffer, sizeof(buffer), false);
|
|
str = buffer;
|
|
|
|
r2d_be_flags = PF_SelectDPDrawFlag(prinst, flag);
|
|
PR_CL_BeginString(prinst, pos[0], pos[1], size[0], size[1], &px, &py);
|
|
ipx = px;
|
|
R2D_ImageColours(r, g, b, alpha);
|
|
while(*str)
|
|
{
|
|
str = Font_Decode(str, &codeflags, &codepoint);
|
|
if (codeflags & CON_HIDDEN)
|
|
continue;
|
|
if (codepoint == '\n')
|
|
py += Font_CharHeight();
|
|
else if (codepoint == '\r')
|
|
px = ipx;
|
|
else
|
|
px = Font_DrawScaleChar(px, py, codeflags, codepoint);
|
|
}
|
|
R2D_ImageColours(1,1,1,1);
|
|
Font_EndString(NULL);
|
|
r2d_be_flags = 0;
|
|
}
|
|
|
|
void QCBUILTIN PF_CL_stringwidth(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
conchar_t buffer[2048], *end;
|
|
float px, py;
|
|
const char *text = PR_GetStringOfs(prinst, OFS_PARM0);
|
|
int usecolours = G_FLOAT(OFS_PARM1);
|
|
float *size = (prinst->callargc > 2)?G_VECTOR(OFS_PARM2):NULL;
|
|
|
|
if (!qrenderer)
|
|
{
|
|
G_FLOAT(OFS_RETURN) = 0;
|
|
return;
|
|
}
|
|
|
|
end = COM_ParseFunString(CON_WHITEMASK, text, buffer, sizeof(buffer), !usecolours);
|
|
|
|
PR_CL_BeginString(prinst, 0, 0, size?size[0]:8, size?size[1]:8, &px, &py);
|
|
px = Font_LineScaleWidth(buffer, end);
|
|
Font_EndString(NULL);
|
|
|
|
if (!size) //for compat with dp, divide by 8 after... because weird.
|
|
px /= 8;
|
|
|
|
G_FLOAT(OFS_RETURN) = (px * vid.width) / vid.rotpixelwidth;
|
|
}
|
|
|
|
//float drawpic(vector position, string pic, vector size, vector rgb, float alpha, float flag) = #456;
|
|
void QCBUILTIN PF_CL_drawpic (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
float *pos = G_VECTOR(OFS_PARM0);
|
|
const char *picname = PR_GetStringOfs(prinst, OFS_PARM1);
|
|
float *size = G_VECTOR(OFS_PARM2);
|
|
float *rgb = G_VECTOR(OFS_PARM3);
|
|
float alpha = G_FLOAT(OFS_PARM4);
|
|
int flag = prinst->callargc >= 6?(int)G_FLOAT(OFS_PARM5):0;
|
|
|
|
mpic_t *p;
|
|
|
|
p = R2D_SafeCachePic(picname);
|
|
if (!p || !R_GetShaderSizes(p, NULL, NULL, false))
|
|
p = R2D_SafePicFromWad(picname);
|
|
|
|
if (!p)
|
|
{
|
|
if (!CL_IsDownloading(picname))
|
|
p = R2D_SafeCachePic("no_texture");
|
|
G_FLOAT(OFS_RETURN) = 0;
|
|
}
|
|
else
|
|
G_FLOAT(OFS_RETURN) = 1;
|
|
|
|
r2d_be_flags = PF_SelectDPDrawFlag(prinst, flag);
|
|
R2D_ImageColours(rgb[0], rgb[1], rgb[2], alpha);
|
|
if ((size[0] < 0) ^ (size[1] < 0))
|
|
R2D_Image(pos[0]+size[0], pos[1]+size[1], -size[0], -size[1], 1, 1, 0, 0, p);
|
|
else
|
|
R2D_Image(pos[0], pos[1], size[0], size[1], 0, 0, 1, 1, p);
|
|
r2d_be_flags = 0;
|
|
}
|
|
|
|
void QCBUILTIN PF_CL_drawrotpic (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
float *pivot = G_VECTOR(OFS_PARM0);
|
|
float *mins = G_VECTOR(OFS_PARM1);
|
|
float *maxs = G_VECTOR(OFS_PARM2);
|
|
const char *picname = PR_GetStringOfs(prinst, OFS_PARM3);
|
|
float *rgb = G_VECTOR(OFS_PARM4);
|
|
float alpha = G_FLOAT(OFS_PARM5);
|
|
float angle = (G_FLOAT(OFS_PARM6) * M_PI)/180;
|
|
int flag = prinst->callargc >= 8?(int) G_FLOAT(OFS_PARM7):0;
|
|
|
|
vec2_t points[4];
|
|
vec2_t tcoords[4];
|
|
vec2_t saxis;
|
|
vec2_t taxis;
|
|
|
|
mpic_t *p;
|
|
|
|
p = R2D_SafeCachePic(picname);
|
|
if (!p)
|
|
p = R2D_SafePicFromWad(picname);
|
|
|
|
saxis[0] = cos(angle);
|
|
saxis[1] = sin(angle);
|
|
taxis[0] = -sin(angle);
|
|
taxis[1] = cos(angle);
|
|
|
|
Vector2MA(pivot, mins[0], saxis, points[0]); Vector2MA(points[0], mins[1], taxis, points[0]);
|
|
Vector2MA(pivot, maxs[0], saxis, points[1]); Vector2MA(points[1], mins[1], taxis, points[1]);
|
|
Vector2MA(pivot, maxs[0], saxis, points[2]); Vector2MA(points[2], maxs[1], taxis, points[2]);
|
|
Vector2MA(pivot, mins[0], saxis, points[3]); Vector2MA(points[3], maxs[1], taxis, points[3]);
|
|
|
|
Vector2Set(tcoords[0], 0, 0);
|
|
Vector2Set(tcoords[1], 1, 0);
|
|
Vector2Set(tcoords[2], 1, 1);
|
|
Vector2Set(tcoords[3], 0, 1);
|
|
|
|
r2d_be_flags = PF_SelectDPDrawFlag(prinst, flag);
|
|
R2D_ImageColours(rgb[0], rgb[1], rgb[2], alpha);
|
|
R2D_Image2dQuad((const vec2_t*)points, (const vec2_t*)tcoords, NULL, p);
|
|
r2d_be_flags = 0;
|
|
|
|
G_FLOAT(OFS_RETURN) = 1;
|
|
}
|
|
|
|
void QCBUILTIN PF_CL_drawsubpic (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
float *pos = G_VECTOR(OFS_PARM0);
|
|
float *size = G_VECTOR(OFS_PARM1);
|
|
const char *picname = PR_GetStringOfs(prinst, OFS_PARM2);
|
|
float *srcPos = G_VECTOR(OFS_PARM3);
|
|
float *srcSize = G_VECTOR(OFS_PARM4);
|
|
float *rgb = G_VECTOR(OFS_PARM5);
|
|
float alpha = G_FLOAT(OFS_PARM6);
|
|
int flag = prinst->callargc >= 8?(int) G_FLOAT(OFS_PARM7):0;
|
|
|
|
mpic_t *p;
|
|
|
|
p = R2D_SafeCachePic(picname);
|
|
if (!p || !R_GetShaderSizes(p, NULL, NULL, false))
|
|
p = R2D_SafePicFromWad(picname);
|
|
|
|
r2d_be_flags = PF_SelectDPDrawFlag(prinst, flag);
|
|
R2D_ImageColours(rgb[0], rgb[1], rgb[2], alpha);
|
|
if ((size[0] < 0) ^ (size[1] < 0))
|
|
R2D_Image(pos[0]+size[0], pos[1]+size[1], -size[0], -size[1], srcPos[0]+srcSize[0], srcPos[1]+srcSize[1], srcPos[0], srcPos[1], p);
|
|
else
|
|
R2D_Image(pos[0], pos[1], size[0], size[1], srcPos[0], srcPos[1], srcPos[0]+srcSize[0], srcPos[1]+srcSize[1], p);
|
|
r2d_be_flags = 0;
|
|
|
|
G_FLOAT(OFS_RETURN) = 1;
|
|
}
|
|
void QCBUILTIN PF_CL_drawrotsubpic (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
float *pivot = G_VECTOR(OFS_PARM0);
|
|
float *mins = G_VECTOR(OFS_PARM1);
|
|
float *maxs = G_VECTOR(OFS_PARM2);
|
|
const char *picname = PR_GetStringOfs(prinst, OFS_PARM3);
|
|
float *srcPos = G_VECTOR(OFS_PARM4);
|
|
float *srcSize = G_VECTOR(OFS_PARM5);
|
|
float *rgb = G_VECTOR(OFS_PARM6);
|
|
float alpha = G_FLOAT(OFS_PARM7+0);
|
|
float angle = (G_FLOAT(OFS_PARM7+1) * M_PI) / 180;
|
|
int flag = prinst->callargc >= 8?(int) G_FLOAT(OFS_PARM7+2):0;
|
|
vec2_t points[4], tcoords[4];
|
|
vec2_t saxis;
|
|
vec2_t taxis;
|
|
|
|
mpic_t *p;
|
|
|
|
saxis[0] = cos(angle);
|
|
saxis[1] = sin(angle);
|
|
taxis[0] = -sin(angle);
|
|
taxis[1] = cos(angle);
|
|
|
|
p = R2D_SafeCachePic(picname);
|
|
if (!p)
|
|
p = R2D_SafePicFromWad(picname);
|
|
|
|
Vector2MA(pivot, mins[0], saxis, points[0]); Vector2MA(points[0], mins[1], taxis, points[0]);
|
|
Vector2MA(pivot, maxs[0], saxis, points[1]); Vector2MA(points[1], mins[1], taxis, points[1]);
|
|
Vector2MA(pivot, maxs[0], saxis, points[2]); Vector2MA(points[2], maxs[1], taxis, points[2]);
|
|
Vector2MA(pivot, mins[0], saxis, points[3]); Vector2MA(points[3], maxs[1], taxis, points[3]);
|
|
|
|
Vector2Set(tcoords[0], srcPos[0] , srcPos[1] );
|
|
Vector2Set(tcoords[1], srcPos[0]+srcSize[0] , srcPos[1] );
|
|
Vector2Set(tcoords[2], srcPos[0]+srcSize[0] , srcPos[1]+srcSize[1] );
|
|
Vector2Set(tcoords[3], srcPos[0] , srcPos[1]+srcSize[1] );
|
|
|
|
r2d_be_flags = PF_SelectDPDrawFlag(prinst, flag);
|
|
R2D_ImageColours(rgb[0], rgb[1], rgb[2], alpha);
|
|
R2D_Image2dQuad((const vec2_t*)points, (const vec2_t*)tcoords, NULL, p);
|
|
r2d_be_flags = 0;
|
|
|
|
G_FLOAT(OFS_RETURN) = 1;
|
|
}
|
|
|
|
#ifdef HAVE_LEGACY
|
|
/*fuck sake, why does no one give a shit about existing extension?!? seriously this stuff is pissing me off*/
|
|
void QCBUILTIN PF_CL_drawrotpic_dp (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
float *pivot = G_VECTOR(OFS_PARM0);
|
|
const char *picname = PR_GetStringOfs(prinst, OFS_PARM1);
|
|
float *size = G_VECTOR(OFS_PARM2);
|
|
float *mins = G_VECTOR(OFS_PARM3);
|
|
float angle = (G_FLOAT(OFS_PARM4) * M_PI)/180;
|
|
float *rgb = G_VECTOR(OFS_PARM5);
|
|
float alpha = G_FLOAT(OFS_PARM6);
|
|
int flag = prinst->callargc >= 8?(int) G_FLOAT(OFS_PARM7):0;
|
|
|
|
vec3_t maxs;
|
|
|
|
vec2_t points[4];
|
|
vec2_t tcoords[4];
|
|
vec2_t saxis;
|
|
vec2_t taxis;
|
|
|
|
mpic_t *p;
|
|
|
|
VectorSubtract(size, mins, maxs);
|
|
|
|
p = R2D_SafeCachePic(picname);
|
|
if (!p)
|
|
p = R2D_SafePicFromWad(picname);
|
|
|
|
saxis[0] = cos(angle);
|
|
saxis[1] = sin(angle);
|
|
taxis[0] = -sin(angle);
|
|
taxis[1] = cos(angle);
|
|
|
|
Vector2MA(pivot, mins[0], saxis, points[0]); Vector2MA(points[0], mins[1], taxis, points[0]);
|
|
Vector2MA(pivot, maxs[0], saxis, points[1]); Vector2MA(points[1], mins[1], taxis, points[1]);
|
|
Vector2MA(pivot, maxs[0], saxis, points[2]); Vector2MA(points[2], maxs[1], taxis, points[2]);
|
|
Vector2MA(pivot, mins[0], saxis, points[3]); Vector2MA(points[3], maxs[1], taxis, points[3]);
|
|
|
|
Vector2Set(tcoords[0], 0, 0);
|
|
Vector2Set(tcoords[1], 1, 0);
|
|
Vector2Set(tcoords[2], 1, 1);
|
|
Vector2Set(tcoords[3], 0, 1);
|
|
|
|
r2d_be_flags = PF_SelectDPDrawFlag(prinst, flag);
|
|
R2D_ImageColours(rgb[0], rgb[1], rgb[2], alpha);
|
|
R2D_Image2dQuad((const vec2_t*)points, (const vec2_t*)tcoords, NULL, p);
|
|
r2d_be_flags = 0;
|
|
|
|
G_FLOAT(OFS_RETURN) = 1;
|
|
}
|
|
#endif
|
|
|
|
|
|
void QCBUILTIN PF_CL_is_cached_pic (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
const char *str;
|
|
str = PR_GetStringOfs(prinst, OFS_PARM0);
|
|
G_FLOAT(OFS_RETURN) = !!R_RegisterCustom(str, SUF_2D, NULL, NULL);
|
|
}
|
|
|
|
void QCBUILTIN PF_CL_precache_pic (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
const char *str;
|
|
mpic_t *pic;
|
|
float fromwad;
|
|
|
|
str = PR_GetStringOfs(prinst, OFS_PARM0);
|
|
if (prinst->callargc > 1)
|
|
fromwad = G_FLOAT(OFS_PARM1);
|
|
else
|
|
fromwad = false;
|
|
|
|
if (fromwad)
|
|
pic = R2D_SafePicFromWad(str);
|
|
else
|
|
{
|
|
pic = R2D_SafeCachePic(str);
|
|
|
|
if ((!pic || !R_GetShaderSizes(pic, NULL, NULL, true)) && cls.state
|
|
#ifndef CLIENTONLY
|
|
&& !sv.active
|
|
#endif
|
|
&& strchr(str, '.')) //only try to download it if it looks as though it contains a path.
|
|
CL_CheckOrEnqueDownloadFile(str, str, 0);
|
|
}
|
|
|
|
if (pic && R_GetShaderSizes(pic, NULL, NULL, true))
|
|
G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
|
|
else
|
|
G_INT(OFS_RETURN) = 0;
|
|
}
|
|
|
|
#ifdef CSQC_DAT
|
|
//warning: not threaded.
|
|
void QCBUILTIN PF_CL_uploadimage (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
const char *imagename = PR_GetStringOfs(prinst, OFS_PARM0);
|
|
int width = G_INT(OFS_PARM1);
|
|
int height = G_INT(OFS_PARM2);
|
|
int src = G_INT(OFS_PARM3); //ptr
|
|
int size = (prinst->callargc > 4)?G_INT(OFS_PARM4):(width * height * 4);
|
|
uploadfmt_t format = (prinst->callargc > 5)?PR_TranslateTextureFormat(G_INT(OFS_PARM5)):TF_RGBA32;
|
|
void *imgptr;
|
|
texid_t tid;
|
|
|
|
G_INT(OFS_RETURN) = 0; //assume the worst
|
|
|
|
if (width < 0 || height < 0 || width > 16384 || height > 16384)
|
|
{ //this is actually kinda likely when everyone assumes everything is a float.
|
|
PR_BIError(prinst, "PF_CL_uploadimage: dimensions are out of range\n");
|
|
return;
|
|
}
|
|
//FIXME: this should use a proper qclib function to validate more reliably / reusably
|
|
if (src <= 0 || src+size >= prinst->stringtablesize)
|
|
{
|
|
PR_BIError(prinst, "PF_CL_uploadimage: invalid source\n");
|
|
return;
|
|
}
|
|
imgptr = prinst->stringtable + src;
|
|
|
|
|
|
tid = Image_FindTexture(imagename, NULL, RT_IMAGEFLAGS);
|
|
if (!TEXVALID(tid))
|
|
tid = Image_CreateTexture(imagename, NULL, RT_IMAGEFLAGS);
|
|
|
|
if (!format)
|
|
{
|
|
void *data = BZ_Malloc(size);
|
|
memcpy(data, imgptr, size);
|
|
G_INT(OFS_RETURN) = Image_LoadTextureFromMemory(tid, tid->flags, tid->ident, imagename, data, size);
|
|
}
|
|
else
|
|
{
|
|
unsigned int blockbytes, blockwidth, blockheight, blockdepth;
|
|
//get format info
|
|
Image_BlockSizeForEncoding(format, &blockbytes, &blockwidth, &blockheight, &blockdepth);
|
|
//round up as appropriate
|
|
blockwidth = ((width+blockwidth-1)/blockwidth)*blockwidth;
|
|
blockheight = ((height+blockheight-1)/blockheight)*blockheight;
|
|
if (size != blockwidth*blockheight*blockbytes)
|
|
G_INT(OFS_RETURN) = 0; //size isn't right. which means the pointer might be invalid too.
|
|
else
|
|
{
|
|
Image_Upload(tid, format, imgptr, NULL, width, height, RT_IMAGEFLAGS);
|
|
tid->width = width;
|
|
tid->height = height;
|
|
G_INT(OFS_RETURN) = 1;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//warning: not threadable. hopefully noone abuses it.
|
|
void QCBUILTIN PF_CL_readimage (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
size_t filesize;
|
|
const char *filename = PR_GetStringOfs(prinst, OFS_PARM0);
|
|
|
|
int imagewidth, imageheight;
|
|
uploadfmt_t format;
|
|
void *filedata;
|
|
|
|
G_INT(OFS_RETURN) = 0; //assume the worst
|
|
G_INT(OFS_PARM1) = 0; //out width
|
|
G_INT(OFS_PARM2) = 0; //out height
|
|
|
|
filedata = FS_LoadMallocFile(filename, &filesize);
|
|
|
|
if (filedata)
|
|
{
|
|
qbyte *imagedata = ReadRawImageFile(filedata, filesize, &imagewidth, &imageheight, &format, true, filename);
|
|
Z_Free(filedata);
|
|
|
|
if (imagedata)
|
|
{
|
|
void *ptr = prinst->AddressableAlloc(prinst, imagewidth*imageheight*4);
|
|
if (ptr)
|
|
{
|
|
memcpy(ptr, imagedata, imagewidth*imageheight*4);
|
|
G_INT(OFS_RETURN) = (char*)ptr - prinst->stringtable;
|
|
G_INT(OFS_PARM1) = imagewidth; //out width
|
|
G_INT(OFS_PARM2) = imageheight; //out height
|
|
}
|
|
BZ_Free(imagedata);
|
|
}
|
|
}
|
|
}
|
|
|
|
void QCBUILTIN PF_CL_free_pic (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
//we don't support this, as the shader could be used elsewhere also, and we have pointers to things.
|
|
/*
|
|
char *str;
|
|
str = PR_GetStringOfs(prinst, OFS_PARM0);
|
|
R_UnloadShader(R_RegisterCustom(str, NULL, NULL));
|
|
*/
|
|
}
|
|
|
|
//float drawcharacter(vector position, float character, vector scale, vector rgb, float alpha, float flag) = #454;
|
|
void QCBUILTIN PF_CL_drawcharacter (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
float *pos = G_VECTOR(OFS_PARM0);
|
|
int chara = G_FLOAT(OFS_PARM1);
|
|
float *size = G_VECTOR(OFS_PARM2);
|
|
float *rgb = G_VECTOR(OFS_PARM3);
|
|
float alpha = G_FLOAT(OFS_PARM4);
|
|
int flag = prinst->callargc >= 6?G_FLOAT(OFS_PARM5):0;
|
|
|
|
float x, y;
|
|
|
|
if (!chara)
|
|
{
|
|
G_FLOAT(OFS_RETURN) = -1; //was null..
|
|
return;
|
|
}
|
|
|
|
//no control chars. use quake ones if so
|
|
if (!(flag & 4) && !com_parseutf8.ival)
|
|
{
|
|
//ugly quake chars...
|
|
if (chara >= 32 && chara < 128)
|
|
; //ascii-comptaible range
|
|
else
|
|
chara |= 0xe000; //use quake glyphs (including for red text, unfortunately)
|
|
}
|
|
|
|
r2d_be_flags = PF_SelectDPDrawFlag(prinst, flag);
|
|
PR_CL_BeginString(prinst, pos[0], pos[1], size[0], size[1], &x, &y);
|
|
R2D_ImageColours(rgb[0], rgb[1], rgb[2], alpha);
|
|
Font_DrawScaleChar(x, y, CON_WHITEMASK, chara);
|
|
R2D_ImageColours(1,1,1,1);
|
|
Font_EndString(NULL);
|
|
r2d_be_flags = 0;
|
|
|
|
G_FLOAT(OFS_RETURN) = 1;
|
|
}
|
|
|
|
//float drawrawstring(vector position, string text, vector scale, vector rgb, float alpha, float flag) = #455;
|
|
void QCBUILTIN PF_CL_drawrawstring (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
float *pos = G_VECTOR(OFS_PARM0);
|
|
const char *text = PR_GetStringOfs(prinst, OFS_PARM1);
|
|
float *size = G_VECTOR(OFS_PARM2);
|
|
float *rgb = G_VECTOR(OFS_PARM3);
|
|
float alpha = G_FLOAT(OFS_PARM4);
|
|
int flag = prinst->callargc >= 6?G_FLOAT(OFS_PARM5):0;
|
|
float x, y;
|
|
unsigned int c;
|
|
int error;
|
|
|
|
if (!text)
|
|
{
|
|
G_FLOAT(OFS_RETURN) = -1; //was null..
|
|
return;
|
|
}
|
|
|
|
r2d_be_flags = PF_SelectDPDrawFlag(prinst, flag);
|
|
PR_CL_BeginString(prinst, pos[0], pos[1], size[0], size[1], &x, &y);
|
|
R2D_ImageColours(rgb[0], rgb[1], rgb[2], alpha);
|
|
|
|
while(*text)
|
|
{
|
|
if (1)//VMUTF8)
|
|
c = unicode_decode(&error, text, &text, false);
|
|
else
|
|
{
|
|
//FIXME: which charset is this meant to be using?
|
|
//quakes? 8859-1? utf8? some weird hacky mixture?
|
|
c = *text++&0xff;
|
|
if ((c&0x7f) < 32)
|
|
c |= 0xe000; //if its a control char, just use the quake range instead.
|
|
else if (c & 0x80)
|
|
c |= 0xe000; //if its a high char, just use the quake range instead. we could colour it, but why bother
|
|
}
|
|
x = Font_DrawScaleChar(x, y, CON_WHITEMASK, c);
|
|
}
|
|
R2D_ImageColours(1,1,1,1);
|
|
Font_EndString(NULL);
|
|
r2d_be_flags = 0;
|
|
}
|
|
|
|
//void (float width, vector pos1, vector pos2, vector rgb, float alpha, optional float flags) drawline;
|
|
void QCBUILTIN PF_CL_drawline (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
//float width = G_FLOAT(OFS_PARM0);
|
|
float *point1 = G_VECTOR(OFS_PARM1);
|
|
float *point2 = G_VECTOR(OFS_PARM2);
|
|
float *rgb = G_VECTOR(OFS_PARM3);
|
|
float alpha = G_FLOAT(OFS_PARM4);
|
|
int flags = prinst->callargc >= 6?G_FLOAT(OFS_PARM5):0;
|
|
shader_t *shader_draw_line;
|
|
|
|
//this shader lookup might get pricy.
|
|
shader_draw_line = R_RegisterShader("shader_draw_line", SUF_NONE,
|
|
"{\n"
|
|
"program defaultfill\n"
|
|
"{\n"
|
|
"map $whiteimage\n"
|
|
"rgbgen exactvertex\n"
|
|
"alphagen vertex\n"
|
|
"blendfunc blend\n"
|
|
"}\n"
|
|
"}\n");
|
|
|
|
r2d_be_flags = PF_SelectDPDrawFlag(prinst, flags);
|
|
R2D_ImageColours(rgb[0], rgb[1], rgb[2], alpha);
|
|
R2D_Line(point1[0], point1[1], point2[0], point2[1], shader_draw_line);
|
|
R2D_ImageColours(1,1,1,1);
|
|
r2d_be_flags = 0;
|
|
}
|
|
|
|
//vector drawgetimagesize(string pic) = #460;
|
|
void QCBUILTIN PF_CL_drawgetimagesize (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
const char *picname = PR_GetStringOfs(prinst, OFS_PARM0);
|
|
mpic_t *p = R2D_SafeCachePic(picname);
|
|
|
|
float *ret = G_VECTOR(OFS_RETURN);
|
|
int iw, ih;
|
|
|
|
if (R_GetShaderSizes(p, &iw, &ih, true) > 0)
|
|
{
|
|
ret[0] = iw;
|
|
ret[1] = ih;
|
|
ret[2] = 0;
|
|
}
|
|
else
|
|
{
|
|
ret[0] = 0;
|
|
ret[1] = 0;
|
|
ret[2] = 0;
|
|
}
|
|
}
|
|
|
|
//vector getmousepos(void) = #66;
|
|
void QCBUILTIN PF_cl_getmousepos (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
float *ret = G_VECTOR(OFS_RETURN);
|
|
world_t *world = prinst->parms->user;
|
|
unsigned int target = world->keydestmask;
|
|
|
|
if (key_dest_absolutemouse & target)
|
|
{
|
|
ret[0] = mousecursor_x;
|
|
ret[1] = mousecursor_y;
|
|
}
|
|
else
|
|
{
|
|
ret[0] = mousemove_x;
|
|
ret[1] = mousemove_y;
|
|
}
|
|
|
|
mousemove_x=0;
|
|
mousemove_y=0;
|
|
|
|
// extern int mousecursor_x, mousecursor_y;
|
|
// ret[0] = mousecursor_x;
|
|
// ret[1] = mousecursor_y;
|
|
ret[2] = 0;
|
|
}
|
|
|
|
|
|
void QCBUILTIN PF_SubConGetSet (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
const char *conname = PR_GetStringOfs(prinst, OFS_PARM0);
|
|
const char *field = PR_GetStringOfs(prinst, OFS_PARM1);
|
|
const char *value = (prinst->callargc>2)?PR_GetStringOfs(prinst, OFS_PARM2):NULL;
|
|
console_t *con = Con_FindConsole(conname);
|
|
G_INT(OFS_RETURN) = 0;
|
|
if (!con)
|
|
{
|
|
//null if it doesn't exist
|
|
return;
|
|
}
|
|
if (!strcmp(field, "title"))
|
|
{
|
|
RETURN_TSTRING(con->title);
|
|
if (value)
|
|
Q_strncpyz(con->title, value, sizeof(con->title));
|
|
}
|
|
else if (!strcmp(field, "name"))
|
|
{
|
|
RETURN_TSTRING(con->name);
|
|
if (value && *value && *con->name)
|
|
Q_strncpyz(con->name, value, sizeof(con->name));
|
|
}
|
|
else if (!strcmp(field, "next"))
|
|
{
|
|
con = con->next;
|
|
if (con)
|
|
RETURN_TSTRING(con->name);
|
|
}
|
|
else if (!strcmp(field, "unseen"))
|
|
{
|
|
RETURN_TSTRING(va("%i", con->unseentext));
|
|
if (value)
|
|
con->unseentext = atoi(value);
|
|
}
|
|
else if (!strcmp(field, "markup"))
|
|
{
|
|
int cur;
|
|
if (con->parseflags & PFS_NOMARKUP)
|
|
cur = 0;
|
|
else if (con->parseflags & PFS_KEEPMARKUP)
|
|
cur = 2;
|
|
else
|
|
cur = 1;
|
|
RETURN_TSTRING(va("%i", cur));
|
|
if (value)
|
|
{
|
|
cur = atoi(value);
|
|
con->parseflags &= ~(PFS_NOMARKUP|PFS_KEEPMARKUP);
|
|
if (cur == 0)
|
|
con->parseflags |= PFS_NOMARKUP;
|
|
else if (cur == 2)
|
|
con->parseflags |= PFS_KEEPMARKUP;
|
|
}
|
|
}
|
|
else if (!strcmp(field, "forceutf8"))
|
|
{
|
|
RETURN_TSTRING((con->parseflags&PFS_FORCEUTF8)?"1":"0");
|
|
if (value)
|
|
{
|
|
con->parseflags &= ~PFS_FORCEUTF8;
|
|
if (atoi(value))
|
|
con->parseflags |= PFS_FORCEUTF8;
|
|
}
|
|
}
|
|
else if (!strcmp(field, "close"))
|
|
{
|
|
RETURN_TSTRING("0"); //meant to return the old state...
|
|
if (value && atoi(value))
|
|
{
|
|
if (con->close && atoi(value) != 2 && !con->close(con, true))
|
|
return;
|
|
Con_Destroy(con);
|
|
}
|
|
}
|
|
else if (!strcmp(field, "clear"))
|
|
{
|
|
RETURN_TSTRING(con->linecount?"0":"1");
|
|
if (value && atoi(value))
|
|
Con_ClearCon(con);
|
|
}
|
|
else if (!strcmp(field, "hidden"))
|
|
{
|
|
RETURN_TSTRING((con->flags & CONF_HIDDEN)?"1":"0");
|
|
if (value)
|
|
con->flags = (con->flags & ~CONF_HIDDEN) | (atoi(value)?CONF_HIDDEN:0);
|
|
}
|
|
else if (!strcmp(field, "linecount"))
|
|
{
|
|
RETURN_TSTRING(va("%i", con->linecount));
|
|
if (value)
|
|
con->unseentext = atoi(value);
|
|
}
|
|
else if (!strcmp(field, "backimage"))
|
|
{
|
|
RETURN_TSTRING(con->backshader?con->backshader->name:con->backimage);
|
|
if (value)
|
|
{
|
|
Q_strncpyz(con->backimage, value, sizeof(con->backimage));
|
|
if (con->backshader)
|
|
R_UnloadShader(con->backshader);
|
|
}
|
|
}
|
|
else if (!strcmp(field, "backvideomap"))
|
|
{
|
|
RETURN_TSTRING(con->backshader?con->backshader->name:con->backimage);
|
|
if (value)
|
|
{
|
|
Q_strncpyz(con->backimage, "", sizeof(con->backimage));
|
|
if (con->backshader)
|
|
R_UnloadShader(con->backshader);
|
|
con->backshader = R_RegisterCustom(va("consolevid_%s", con->name), SUF_NONE, Shader_DefaultCinematic, value);
|
|
}
|
|
}
|
|
}
|
|
void QCBUILTIN PF_SubConPrintf (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
char outbuf[4096];
|
|
const char *conname = PR_GetStringOfs(prinst, OFS_PARM0);
|
|
const char *fmt = PR_GetStringOfs(prinst, OFS_PARM1);
|
|
console_t *con = Con_FindConsole(conname);
|
|
if (!con)
|
|
{
|
|
con = Con_Create(conname, 0);
|
|
if (!con)
|
|
return;
|
|
}
|
|
PF_sprintf_internal(prinst, pr_globals, fmt, 2, outbuf, sizeof(outbuf));
|
|
Con_PrintCon(con, outbuf, con->parseflags);
|
|
}
|
|
void QCBUILTIN PF_SubConDraw (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
const char *conname = PR_GetStringOfs(prinst, OFS_PARM0);
|
|
float *pos = G_VECTOR(OFS_PARM1);
|
|
float *size = G_VECTOR(OFS_PARM2);
|
|
float fontsize = G_FLOAT(OFS_PARM3);
|
|
console_t *con = Con_FindConsole(conname);
|
|
world_t *world = prinst->parms->user;
|
|
if (!con)
|
|
return;
|
|
|
|
if (world->g.drawfontscale)
|
|
{
|
|
// szx *= world->g.drawfontscale[0];
|
|
fontsize *= world->g.drawfontscale[1];
|
|
}
|
|
|
|
Con_DrawOneConsole(con, con->flags & CONF_KEYFOCUSED, PR_CL_ChooseFont(world->g.drawfont, fontsize, fontsize), pos[0], pos[1], size[0], size[1], 0);
|
|
}
|
|
void QCBUILTIN PF_SubConInput (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
const char *conname = PR_GetStringOfs(prinst, OFS_PARM0);
|
|
int ie = G_FLOAT(OFS_PARM1);
|
|
float pa = G_FLOAT(OFS_PARM2);
|
|
float pb = G_FLOAT(OFS_PARM3);
|
|
// float pc = G_FLOAT(OFS_PARM4);
|
|
console_t *con = Con_FindConsole(conname);
|
|
G_FLOAT(OFS_RETURN) = 0;
|
|
if (!con)
|
|
return;
|
|
switch(ie)
|
|
{
|
|
case CSIE_KEYDOWN:
|
|
//scan, char
|
|
if ((pa && qcinput_scan != pa) || (pb && pb != qcinput_unicode))
|
|
G_FLOAT(OFS_RETURN) = 0;
|
|
else
|
|
G_FLOAT(OFS_RETURN) = Key_Console(con, MP_TranslateQCtoFTECodes(pa), pb);
|
|
break;
|
|
case CSIE_KEYUP:
|
|
//scan, char
|
|
Key_ConsoleRelease(con, MP_TranslateQCtoFTECodes(pa), pb);
|
|
G_FLOAT(OFS_RETURN) = 0; //does not inhibit
|
|
break;
|
|
case CSIE_MOUSEABS:
|
|
//x, y
|
|
if (con == con_current && (key_dest_mask & kdm_console))
|
|
break; //no interfering with the main console!
|
|
con->mousecursor[0] = pa;
|
|
con->mousecursor[1] = pb;
|
|
G_FLOAT(OFS_RETURN) = true;
|
|
break;
|
|
case CSIE_FOCUS:
|
|
//mouse, key
|
|
if (pb >= 0)
|
|
{
|
|
con->flags = (con->flags & ~CONF_KEYFOCUSED) | (pb?CONF_KEYFOCUSED:0);
|
|
G_FLOAT(OFS_RETURN) = true;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef MENU_DAT
|
|
|
|
typedef struct menuedict_s
|
|
{
|
|
enum ereftype_e ereftype;
|
|
float freetime; // sv.time when the object was freed
|
|
int entnum;
|
|
unsigned int fieldsize;
|
|
pbool readonly; //world
|
|
|
|
void *fields;
|
|
} menuedict_t;
|
|
|
|
|
|
|
|
static struct
|
|
{
|
|
evalc_t chain;
|
|
evalc_t model;
|
|
evalc_t mins;
|
|
evalc_t maxs;
|
|
evalc_t origin;
|
|
evalc_t angles;
|
|
evalc_t skin;
|
|
evalc_t colormap;
|
|
evalc_t frame1;
|
|
evalc_t frame2;
|
|
evalc_t lerpfrac;
|
|
evalc_t frame1time;
|
|
evalc_t frame2time;
|
|
evalc_t renderflags;
|
|
evalc_t skinobject;
|
|
} menuc_eval;
|
|
static playerview_t menuview;
|
|
|
|
|
|
static menu_t menuqc; //this is how the client forwards events etc.
|
|
static int inmenuprogs;
|
|
static progparms_t menuprogparms;
|
|
static menuedict_t *menu_edicts;
|
|
static int num_menu_edicts;
|
|
world_t menu_world;
|
|
static int menuentsize;
|
|
double menutime;
|
|
static struct
|
|
{
|
|
func_t init;
|
|
func_t shutdown;
|
|
func_t draw; qboolean fuckeddrawsizes;
|
|
func_t drawloading;
|
|
func_t keydown;
|
|
func_t keyup;
|
|
func_t inputevent;
|
|
func_t toggle;
|
|
func_t consolecommand;
|
|
func_t gethostcachecategory;
|
|
func_t rendererrestarted;
|
|
} mpfuncs;
|
|
jmp_buf mp_abort;
|
|
|
|
|
|
// cvars
|
|
#define MENUPROGSGROUP "Menu progs control"
|
|
cvar_t forceqmenu = CVAR("forceqmenu", "0");
|
|
cvar_t pr_menu_coreonerror = CVAR("pr_menu_coreonerror", "1");
|
|
cvar_t pr_menu_memsize = CVAR("pr_menu_memsize", "64m");
|
|
|
|
|
|
//new generic functions.
|
|
|
|
const char *RemapCvarNameFromDPToFTE(const char *name)
|
|
{
|
|
if (!stricmp(name, "vid_bitsperpixel"))
|
|
return "vid_bpp";
|
|
if (!stricmp(name, "_cl_playermodel"))
|
|
return "model";
|
|
if (!stricmp(name, "_cl_playerskin"))
|
|
return "skin";
|
|
if (!stricmp(name, "_cl_color"))
|
|
return "topcolor";
|
|
if (!stricmp(name, "_cl_name"))
|
|
return "name";
|
|
|
|
if (!stricmp(name, "v_contrast"))
|
|
return "v_contrast";
|
|
if (!stricmp(name, "v_hwgamma"))
|
|
return "vid_hardwaregamma";
|
|
if (!stricmp(name, "showfps"))
|
|
return "show_fps";
|
|
if (!stricmp(name, "sv_progs"))
|
|
return "progs";
|
|
|
|
return name;
|
|
}
|
|
|
|
static void QCBUILTIN PF_menu_cvar (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
cvar_t *var;
|
|
const char *str;
|
|
|
|
str = PR_GetStringOfs(prinst, OFS_PARM0);
|
|
|
|
if (!strcmp(str, "vid_conwidth"))
|
|
G_FLOAT(OFS_RETURN) = vid.width;
|
|
else if (!strcmp(str, "vid_conheight"))
|
|
G_FLOAT(OFS_RETURN) = vid.height;
|
|
else if (!strcmp(str, "vid_pixwidth"))
|
|
G_FLOAT(OFS_RETURN) = vid.pixelwidth;
|
|
else if (!strcmp(str, "vid_pixheight"))
|
|
G_FLOAT(OFS_RETURN) = vid.pixelheight;
|
|
else
|
|
{
|
|
str = RemapCvarNameFromDPToFTE(str);
|
|
var = PF_Cvar_FindOrGet(str);
|
|
if (var && !(var->flags & CVAR_NOUNSAFEEXPAND))
|
|
{
|
|
//menuqc sees desired settings, not latched settings.
|
|
if (var->latched_string)
|
|
G_FLOAT(OFS_RETURN) = atof(var->latched_string);
|
|
else
|
|
G_FLOAT(OFS_RETURN) = var->value;
|
|
}
|
|
else
|
|
G_FLOAT(OFS_RETURN) = 0;
|
|
}
|
|
}
|
|
static void QCBUILTIN PF_menu_cvar_set (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
const char *var_name, *val;
|
|
cvar_t *var;
|
|
|
|
var_name = PR_GetStringOfs(prinst, OFS_PARM0);
|
|
var_name = RemapCvarNameFromDPToFTE(var_name);
|
|
val = PR_GetStringOfs(prinst, OFS_PARM1);
|
|
|
|
var = PF_Cvar_FindOrGet(var_name);
|
|
if (var && var->flags & CVAR_NOTFROMSERVER)
|
|
{
|
|
//fixme: menuqc needs some way to display a prompt to allow it anyway.
|
|
return;
|
|
}
|
|
Cvar_Set (var, val);
|
|
}
|
|
static void QCBUILTIN PF_menu_cvar_string (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
const char *str = PR_GetStringOfs(prinst, OFS_PARM0);
|
|
cvar_t *cv = PF_Cvar_FindOrGet(RemapCvarNameFromDPToFTE(str));
|
|
if (!cv)
|
|
G_INT(OFS_RETURN) = 0;
|
|
else if (cv->flags & CVAR_NOUNSAFEEXPAND)
|
|
G_INT(OFS_RETURN) = 0;
|
|
else if (cv->latched_string)
|
|
G_INT(OFS_RETURN) = (int)PR_TempString(prinst, cv->latched_string);
|
|
else
|
|
G_INT(OFS_RETURN) = (int)PR_TempString(prinst, cv->string);
|
|
}
|
|
|
|
|
|
|
|
|
|
void QCBUILTIN PF_nonfatalobjerror (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
const char *s;
|
|
struct edict_s *ed;
|
|
eval_t *selfp;
|
|
|
|
s = PF_VarString(prinst, 0, pr_globals);
|
|
|
|
PR_StackTrace(prinst, true);
|
|
|
|
selfp = PR_FindGlobal(prinst, "self", PR_CURRENT, NULL);
|
|
if (selfp && selfp->_int)
|
|
{
|
|
ed = PROG_TO_EDICT(prinst, selfp->_int);
|
|
|
|
PR_PrintEdict(prinst, ed);
|
|
|
|
|
|
if (developer.value)
|
|
{ //enable tracing.
|
|
PR_RunWarning(prinst, "======OBJECT ERROR======\n%s\n", s);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
ED_Free (prinst, ed);
|
|
}
|
|
}
|
|
|
|
Con_Printf ("======OBJECT ERROR======\n%s\n", s);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//float isserver(void) = #60;
|
|
void QCBUILTIN PF_isserver (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
#ifdef CLIENTONLY
|
|
G_FLOAT(OFS_RETURN) = false;
|
|
#else
|
|
G_FLOAT(OFS_RETURN) = sv.state != ss_dead;
|
|
#endif
|
|
}
|
|
void QCBUILTIN PF_isdemo (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
G_FLOAT(OFS_RETURN) = !!cls.demoplayback;
|
|
}
|
|
|
|
//float clientstate(void) = #62;
|
|
void QCBUILTIN PF_clientstate (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
//menuqc was originally implemented in DP, so these return values follow NQ norms.
|
|
if (isDedicated) //unreachable
|
|
G_FLOAT(OFS_RETURN) = 0/*nq ca_dedicated*/;
|
|
else if ( cls.state >= ca_connected //we're on a server
|
|
|| CL_TryingToConnect() //or we're trying to connect (avoids bugs with certain menuqc mods)
|
|
#ifndef CLIENTONLY
|
|
|| sv.state>=ss_loading
|
|
#endif
|
|
) //or we're going to connect to ourselves once we get our act together
|
|
G_FLOAT(OFS_RETURN) = 2/*nq ca_connected*/;
|
|
else
|
|
G_FLOAT(OFS_RETURN) = 1/*nq ca_disconnected*/;
|
|
}
|
|
|
|
//too specific to the prinst's builtins.
|
|
static void QCBUILTIN PF_Fixme (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
int binum;
|
|
char fname[MAX_QPATH];
|
|
if (!prinst->GetBuiltinCallInfo(prinst, &binum, fname, sizeof(fname)))
|
|
{
|
|
binum = 0;
|
|
strcpy(fname, "?unknown?");
|
|
}
|
|
|
|
Con_Printf("\n");
|
|
prinst->RunError(prinst, "\nBuiltin %i:%s not implemented.\nMenu is not compatible.", binum, fname);
|
|
PR_BIError (prinst, "bulitin not implemented");
|
|
}
|
|
static void QCBUILTIN PF_checkbuiltin (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
func_t funcref = G_INT(OFS_PARM0);
|
|
char *funcname = NULL;
|
|
int args;
|
|
int builtinno;
|
|
if (prinst->GetFunctionInfo(prinst, funcref, &args, NULL, &builtinno, funcname, sizeof(funcname)))
|
|
{ //qc defines the function at least. nothing weird there...
|
|
if (builtinno > 0 && builtinno < prinst->parms->numglobalbuiltins)
|
|
{
|
|
if (!prinst->parms->globalbuiltins[builtinno] || prinst->parms->globalbuiltins[builtinno] == PF_Fixme)
|
|
G_FLOAT(OFS_RETURN) = false; //the builtin with that number isn't defined.
|
|
else
|
|
{
|
|
G_FLOAT(OFS_RETURN) = true; //its defined, within the sane range, mapped, everything. all looks good.
|
|
//we should probably go through the available builtins and validate that the qc's name matches what would be expected
|
|
//this is really intended more for builtins defined as #0 though, in such cases, mismatched assumptions are impossible.
|
|
}
|
|
}
|
|
else
|
|
G_FLOAT(OFS_RETURN) = false; //not a valid builtin (#0 builtins get remapped according to the function name)
|
|
}
|
|
else
|
|
{ //not valid somehow.
|
|
G_FLOAT(OFS_RETURN) = false;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void QCBUILTIN PF_CL_precache_sound (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
const char *str;
|
|
|
|
str = PR_GetStringOfs(prinst, OFS_PARM0);
|
|
|
|
if (S_PrecacheSound(str))
|
|
G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
|
|
else
|
|
G_INT(OFS_RETURN) = 0;
|
|
}
|
|
|
|
//void setkeydest(float dest) = #601;
|
|
void QCBUILTIN PF_cl_setkeydest (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
//these arguments are stupid
|
|
switch((int)G_FLOAT(OFS_PARM0))
|
|
{
|
|
case 0:
|
|
// key_game
|
|
if (Key_Dest_Has(kdm_menu))
|
|
{
|
|
Menu_Unlink(&menuqc);
|
|
Key_Dest_Remove(kdm_menu);
|
|
// Key_Dest_Remove(kdm_message);
|
|
// if (cls.state == ca_disconnected)
|
|
// Key_Dest_Add(kdm_console);
|
|
}
|
|
break;
|
|
case 2:
|
|
// key_menu
|
|
Key_Dest_Remove(kdm_message);
|
|
if (!Key_Dest_Has(kdm_menu))
|
|
Key_Dest_Remove(kdm_console);
|
|
Menu_Push(&menuqc, false);
|
|
break;
|
|
case 1:
|
|
// key_message
|
|
//Key_Dest_Remove(kdm_menu);
|
|
//Key_Dest_Add(kdm_message);
|
|
// break;
|
|
default:
|
|
PR_BIError (prinst, "PF_setkeydest: wrong destination %i !\n",(int)G_FLOAT(OFS_PARM0));
|
|
}
|
|
}
|
|
//float getkeydest(void) = #602;
|
|
void QCBUILTIN PF_cl_getkeydest (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
if (Key_Dest_Has(kdm_menu))
|
|
G_FLOAT(OFS_RETURN) = 2;
|
|
// else if (Key_Dest_Has(kdm_message))
|
|
// G_FLOAT(OFS_RETURN) = 1;
|
|
else
|
|
G_FLOAT(OFS_RETURN) = 0;
|
|
}
|
|
|
|
static void QCBUILTIN PF_Remove_ (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
menuedict_t *ed;
|
|
|
|
ed = (void*)G_EDICT(prinst, OFS_PARM0);
|
|
|
|
if (ed->ereftype == ER_FREE)
|
|
{
|
|
Con_DPrintf("Tried removing free entity\n");
|
|
PR_StackTrace(prinst, false);
|
|
return;
|
|
}
|
|
|
|
ED_Free (prinst, (void*)ed);
|
|
}
|
|
static void QCBUILTIN PF_RemoveInstant (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
menuedict_t *ed;
|
|
|
|
ed = (void*)G_EDICT(prinst, OFS_PARM0);
|
|
|
|
if (ed->ereftype == ER_FREE)
|
|
{
|
|
Con_DPrintf("Tried removing free entity\n");
|
|
PR_StackTrace(prinst, false);
|
|
return;
|
|
}
|
|
|
|
prinst->EntFree(prinst, (void*)ed, true);
|
|
}
|
|
|
|
static void QCBUILTIN PF_CopyEntity (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
menuedict_t *in, *out;
|
|
|
|
in = (menuedict_t*)G_EDICT(prinst, OFS_PARM0);
|
|
out = (menuedict_t*)G_EDICT(prinst, OFS_PARM1);
|
|
|
|
memcpy(out->fields, in->fields, menuentsize);
|
|
}
|
|
|
|
void QCBUILTIN PF_menu_checkextension (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
const char *extname = PR_GetStringOfs(prinst, OFS_PARM0);
|
|
int i;
|
|
G_FLOAT(OFS_RETURN) = 0;
|
|
|
|
for (i = 0; i < QSG_Extensions_count; i++)
|
|
{
|
|
if (!QSG_Extensions[i].name)
|
|
continue;
|
|
if (!stricmp(extname, QSG_Extensions[i].name))
|
|
{
|
|
G_FLOAT(OFS_RETURN) = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void QCBUILTIN PF_CL_precache_file (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
|
|
}
|
|
|
|
//entity findchainstring(.string _field, string match) = #26;
|
|
void QCBUILTIN PF_menu_findchain (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
int i, f;
|
|
const char *s;
|
|
string_t t;
|
|
menuedict_t *ent, *chain; //note, all edicts share the common header, but don't use it's fields!
|
|
eval_t *val;
|
|
|
|
chain = (menuedict_t *) *prinst->parms->edicts;
|
|
|
|
f = G_INT(OFS_PARM0)+prinst->fieldadjust;
|
|
s = PR_GetStringOfs(prinst, OFS_PARM1);
|
|
|
|
for (i = 1; i < *prinst->parms->num_edicts; i++)
|
|
{
|
|
ent = (menuedict_t *)EDICT_NUM_PB(prinst, i);
|
|
if (ent->ereftype == ER_FREE)
|
|
continue;
|
|
t = *(string_t *)&((float*)ent->fields)[f];
|
|
if (!t)
|
|
continue;
|
|
if (strcmp(PR_GetString(prinst, t), s))
|
|
continue;
|
|
|
|
val = prinst->GetEdictFieldValue(prinst, (void*)ent, "chain", ev_entity, &menuc_eval.chain);
|
|
if (val)
|
|
val->edict = EDICT_TO_PROG(prinst, (void*)chain);
|
|
chain = ent;
|
|
}
|
|
|
|
RETURN_EDICT(prinst, (void*)chain);
|
|
}
|
|
//entity findchainfloat(.float _field, float match) = #27;
|
|
void QCBUILTIN PF_menu_findchainfloat (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
int i, f;
|
|
float s;
|
|
menuedict_t *ent, *chain; //note, all edicts share the common header, but don't use it's fields!
|
|
eval_t *val;
|
|
|
|
chain = (menuedict_t *) *prinst->parms->edicts;
|
|
|
|
f = G_INT(OFS_PARM0)+prinst->fieldadjust;
|
|
s = G_FLOAT(OFS_PARM1);
|
|
|
|
for (i = 1; i < *prinst->parms->num_edicts; i++)
|
|
{
|
|
ent = (menuedict_t*)EDICT_NUM_PB(prinst, i);
|
|
if (ent->ereftype == ER_FREE)
|
|
continue;
|
|
if (((float *)ent->fields)[f] != s)
|
|
continue;
|
|
|
|
val = prinst->GetEdictFieldValue(prinst, (void*)ent, "chain", ev_entity, &menuc_eval.chain);
|
|
if (val)
|
|
val->edict = EDICT_TO_PROG(prinst, (void*)chain);
|
|
chain = ent;
|
|
}
|
|
|
|
RETURN_EDICT(prinst, (void*)chain);
|
|
}
|
|
//entity findchainflags(.float _field, float match);
|
|
void QCBUILTIN PF_menu_findchainflags (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
int i, f;
|
|
int s;
|
|
menuedict_t *ent, *chain; //note, all edicts share the common header, but don't use it's fields!
|
|
eval_t *val;
|
|
|
|
chain = (menuedict_t *) *prinst->parms->edicts;
|
|
|
|
f = G_INT(OFS_PARM0)+prinst->fieldadjust;
|
|
s = G_FLOAT(OFS_PARM1);
|
|
|
|
for (i = 1; i < *prinst->parms->num_edicts; i++)
|
|
{
|
|
ent = (menuedict_t*)EDICT_NUM_PB(prinst, i);
|
|
if (ent->ereftype == ER_FREE)
|
|
continue;
|
|
if ((int)((float *)ent->fields)[f] & s)
|
|
continue;
|
|
|
|
val = prinst->GetEdictFieldValue(prinst, (void*)ent, "chain", ev_entity, &menuc_eval.chain);
|
|
if (val)
|
|
val->edict = EDICT_TO_PROG(prinst, (void*)chain);
|
|
chain = ent;
|
|
}
|
|
|
|
RETURN_EDICT(prinst, (void*)chain);
|
|
}
|
|
|
|
void QCBUILTIN PF_etof(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
G_FLOAT(OFS_RETURN) = G_EDICTNUM(prinst, OFS_PARM0);
|
|
}
|
|
void QCBUILTIN PF_ftoe(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
int entnum = G_FLOAT(OFS_PARM0);
|
|
|
|
RETURN_EDICT(prinst, EDICT_NUM_UB(prinst, entnum));
|
|
}
|
|
|
|
void QCBUILTIN PF_IsNotNull(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
int str = G_INT(OFS_PARM0);
|
|
G_FLOAT(OFS_RETURN) = !!str;
|
|
}
|
|
|
|
//float altstr_count(string str) = #82;
|
|
//returns number of single quoted strings in the string.
|
|
void QCBUILTIN PF_altstr_count(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
const char *s;
|
|
int count = 0;
|
|
s = PR_GetStringOfs(prinst, OFS_PARM0);
|
|
for (;*s;s++)
|
|
{
|
|
if (*s == '\\')
|
|
{
|
|
if (!*++s)
|
|
break;
|
|
}
|
|
else if (*s == '\'')
|
|
count++;
|
|
}
|
|
G_FLOAT(OFS_RETURN) = count/2;
|
|
}
|
|
//string altstr_prepare(string str) = #83;
|
|
void QCBUILTIN PF_altstr_prepare(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
char outstr[8192], *out;
|
|
const char *instr, *in;
|
|
int size;
|
|
|
|
// VM_SAFEPARMCOUNT( 1, VM_altstr_prepare );
|
|
|
|
instr = PR_GetStringOfs(prinst, OFS_PARM0 );
|
|
//VM_CheckEmptyString( instr );
|
|
|
|
for( out = outstr, in = instr, size = sizeof(outstr) - 1 ; size && *in ; size--, in++, out++ )
|
|
{
|
|
if( *in == '\'' )
|
|
{
|
|
*out++ = '\\';
|
|
*out = '\'';
|
|
size--;
|
|
}
|
|
else
|
|
*out = *in;
|
|
}
|
|
*out = 0;
|
|
|
|
G_INT( OFS_RETURN ) = (int)PR_TempString( prinst, outstr );
|
|
}
|
|
//string altstr_get(string str, float num) = #84;
|
|
void QCBUILTIN PF_altstr_get(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
const char *altstr, *pos;
|
|
char outstr[8192], *out;
|
|
int count, size;
|
|
|
|
// VM_SAFEPARMCOUNT( 2, VM_altstr_get );
|
|
|
|
altstr = PR_GetStringOfs(prinst, OFS_PARM0 );
|
|
//VM_CheckEmptyString( altstr );
|
|
|
|
count = G_FLOAT( OFS_PARM1 );
|
|
count = count * 2 + 1;
|
|
|
|
for( pos = altstr ; *pos && count ; pos++ )
|
|
{
|
|
if( *pos == '\\' && !*++pos )
|
|
break;
|
|
else if( *pos == '\'' )
|
|
count--;
|
|
}
|
|
|
|
if( !*pos )
|
|
{
|
|
G_INT( OFS_RETURN ) = (int)PR_SetString( prinst, "" );
|
|
return;
|
|
}
|
|
|
|
for( out = outstr, size = sizeof(outstr) - 1 ; size && *pos ; size--, pos++, out++ )
|
|
{
|
|
if( *pos == '\\' )
|
|
{
|
|
if( !*++pos )
|
|
break;
|
|
*out = *pos;
|
|
size--;
|
|
}
|
|
else if( *pos == '\'' )
|
|
break;
|
|
else
|
|
*out = *pos;
|
|
}
|
|
|
|
*out = 0;
|
|
G_INT( OFS_RETURN ) = (int)PR_TempString( prinst, outstr );
|
|
}
|
|
//string altstr_set(string str, float num, string set) = #85
|
|
void QCBUILTIN PF_altstr_set(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
int num;
|
|
const char *altstr, *str;
|
|
const char *in;
|
|
char outstr[8192], *out;
|
|
|
|
// VM_SAFEPARMCOUNT( 3, VM_altstr_set );
|
|
|
|
altstr = PR_GetStringOfs(prinst, OFS_PARM0 );
|
|
//VM_CheckEmptyString( altstr );
|
|
|
|
num = G_FLOAT( OFS_PARM1 );
|
|
|
|
str = PR_GetStringOfs(prinst, OFS_PARM2 );
|
|
//VM_CheckEmptyString( str );
|
|
|
|
out = outstr;
|
|
for( num = num * 2 + 1, in = altstr; *in && num; *out++ = *in++ )
|
|
{
|
|
if( *in == '\\' && !*++in )
|
|
break;
|
|
else if( *in == '\'' )
|
|
num--;
|
|
}
|
|
|
|
if( !in )
|
|
{
|
|
G_INT( OFS_RETURN ) = (int)PR_SetString( prinst, "" );
|
|
return;
|
|
}
|
|
// copy set in
|
|
for( ; *str; *out++ = *str++ )
|
|
;
|
|
// now jump over the old contents
|
|
for( ; *in ; in++ )
|
|
{
|
|
if( *in == '\'' || (*in == '\\' && !*++in) )
|
|
break;
|
|
}
|
|
|
|
if( !in ) {
|
|
G_INT( OFS_RETURN ) = (int)PR_SetString( prinst, "" );
|
|
return;
|
|
}
|
|
|
|
strcpy( out, in );
|
|
G_INT( OFS_RETURN ) = (int)PR_TempString( prinst, outstr );
|
|
|
|
}
|
|
|
|
//string(string serveraddress) crypto_getkeyfp
|
|
void QCBUILTIN PF_crypto_getkeyfp(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
//not supported.
|
|
G_INT(OFS_RETURN) = 0;
|
|
}
|
|
//string(string serveraddress) crypto_getidfp
|
|
void QCBUILTIN PF_crypto_getidfp(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
//not supported.
|
|
G_INT(OFS_RETURN) = 0;
|
|
}
|
|
//float(string serveraddress) crypto_getidstatus
|
|
void QCBUILTIN PF_crypto_getidstatus(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
//not supported.
|
|
G_INT(OFS_RETURN) = 0;
|
|
}
|
|
//string(string serveraddress) crypto_getencryptlevel
|
|
void QCBUILTIN PF_crypto_getencryptlevel(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
//not supported.
|
|
G_INT(OFS_RETURN) = 0;
|
|
}
|
|
//string(float i) crypto_getmykeyfp
|
|
void QCBUILTIN PF_crypto_getmykeyfp(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
//not supported.
|
|
G_INT(OFS_RETURN) = 0;
|
|
}
|
|
//string(float i) crypto_getmyidfp
|
|
void QCBUILTIN PF_crypto_getmyidfp(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
//not supported.
|
|
G_INT(OFS_RETURN) = 0;
|
|
}
|
|
//float(float i) PF_crypto_getmyidstatus
|
|
void QCBUILTIN PF_crypto_getmyidstatus(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
//not supported.
|
|
G_INT(OFS_RETURN) = 0;
|
|
}
|
|
|
|
static void QCBUILTIN PF_m_precache_model(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
const char *modelname = PR_GetStringOfs(prinst, OFS_PARM0);
|
|
Mod_ForName(modelname, MLV_WARN);
|
|
}
|
|
static void QCBUILTIN PF_m_setmodel(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
menuedict_t *ent = (void*)G_EDICT(prinst, OFS_PARM0);
|
|
const char *modelname = PR_GetStringOfs(prinst, OFS_PARM1);
|
|
eval_t *modelval = prinst->GetEdictFieldValue(prinst, (void*)ent, "model", ev_string, &menuc_eval.model);
|
|
eval_t *minsval = prinst->GetEdictFieldValue(prinst, (void*)ent, "mins", ev_vector, &menuc_eval.mins);
|
|
eval_t *maxsval = prinst->GetEdictFieldValue(prinst, (void*)ent, "maxs", ev_vector, &menuc_eval.maxs);
|
|
model_t *mod = Mod_ForName(modelname, MLV_WARN);
|
|
if (modelval)
|
|
modelval->string = G_INT(OFS_PARM1); //lets hope garbage collection is enough.
|
|
else
|
|
Con_Printf("PF_m_setmodel: no model field!\n");
|
|
|
|
if (mod)
|
|
while(mod->loadstate == MLS_LOADING)
|
|
COM_WorkerPartialSync(mod, &mod->loadstate, MLS_LOADING);
|
|
|
|
if (mod && minsval)
|
|
VectorCopy(mod->mins, minsval->_vector);
|
|
if (mod && maxsval)
|
|
VectorCopy(mod->maxs, maxsval->_vector);
|
|
}
|
|
static void QCBUILTIN PF_m_setcustomskin(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
menuedict_t *ent = (void*)G_EDICT(prinst, OFS_PARM0);
|
|
const char *fname = PR_GetStringOfs(prinst, OFS_PARM1);
|
|
const char *skindata = PF_VarString(prinst, 2, pr_globals);
|
|
eval_t *val = prinst->GetEdictFieldValue(prinst, (void*)ent, "skinobject", ev_string, &menuc_eval.skinobject);
|
|
if (!val)
|
|
{
|
|
Con_Printf("PF_m_setcustomskin: no skinobject field!\n");
|
|
return;
|
|
}
|
|
|
|
if (val->_float > 0)
|
|
{
|
|
Mod_WipeSkin(val->_float, false);
|
|
val->_float = 0;
|
|
}
|
|
|
|
if (*fname || *skindata)
|
|
{
|
|
if (*skindata)
|
|
val->_float = Mod_ReadSkinFile(fname, skindata);
|
|
else
|
|
val->_float = -(int)Mod_RegisterSkinFile(fname);
|
|
}
|
|
}
|
|
//trivially basic
|
|
static void QCBUILTIN PF_m_setorigin(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
menuedict_t *ent = (void*)G_EDICT(prinst, OFS_PARM0);
|
|
float *org = G_VECTOR(OFS_PARM1);
|
|
eval_t *val = prinst->GetEdictFieldValue(prinst, (void*)ent, "origin", ev_vector, &menuc_eval.origin);
|
|
if (val)
|
|
VectorCopy(org, val->_vector);
|
|
else
|
|
Con_Printf("PF_m_setorigin: no origin field!\n");
|
|
}
|
|
static void QCBUILTIN PF_m_clearscene(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
// CL_DecayLights ();
|
|
|
|
#if defined(SKELETALOBJECTS) || defined(RAGDOLLS)
|
|
world_t *world = prinst->parms->user;
|
|
if (world)
|
|
skel_dodelete(world);
|
|
#endif
|
|
CL_ClearEntityLists();
|
|
|
|
V_ClearRefdef(&menuview);
|
|
r_refdef.drawsbar = false;
|
|
r_refdef.drawcrosshair = false;
|
|
V_CalcRefdef(&menuview); //set up the defaults
|
|
r_refdef.flags |= RDF_NOWORLDMODEL;
|
|
}
|
|
static qboolean CopyMenuEdictToEntity(pubprogfuncs_t *prinst, menuedict_t *in, entity_t *out)
|
|
{
|
|
eval_t *modelval = prinst->GetEdictFieldValue(prinst, (void*)in, "model", ev_string, &menuc_eval.model);
|
|
eval_t *originval = prinst->GetEdictFieldValue(prinst, (void*)in, "origin", ev_vector, &menuc_eval.origin);
|
|
eval_t *anglesval = prinst->GetEdictFieldValue(prinst, (void*)in, "angles", ev_vector, &menuc_eval.angles);
|
|
eval_t *skinval = prinst->GetEdictFieldValue(prinst, (void*)in, "skin", ev_float, &menuc_eval.skin);
|
|
eval_t *frame1val = prinst->GetEdictFieldValue(prinst, (void*)in, "frame", ev_float, &menuc_eval.frame1);
|
|
eval_t *frame2val = prinst->GetEdictFieldValue(prinst, (void*)in, "frame2", ev_float, &menuc_eval.frame2);
|
|
eval_t *lerpfracval = prinst->GetEdictFieldValue(prinst, (void*)in, "lerpfrac", ev_float, &menuc_eval.lerpfrac);
|
|
eval_t *frame1timeval = prinst->GetEdictFieldValue(prinst, (void*)in, "frame1time", ev_float, &menuc_eval.frame1time);
|
|
eval_t *frame2timeval = prinst->GetEdictFieldValue(prinst, (void*)in, "frame2time", ev_float, &menuc_eval.frame2time);
|
|
eval_t *colormapval = prinst->GetEdictFieldValue(prinst, (void*)in, "colormap", ev_float, &menuc_eval.colormap);
|
|
eval_t *renderflagsval = prinst->GetEdictFieldValue(prinst, (void*)in, "renderflags", ev_float, &menuc_eval.renderflags);
|
|
eval_t *skinobjectval = prinst->GetEdictFieldValue(prinst, (void*)in, "skinobject", ev_float, &menuc_eval.skinobject);
|
|
int ival;
|
|
int rflags;
|
|
|
|
rflags = renderflagsval?renderflagsval->_float:0;
|
|
|
|
memset(out, 0, sizeof(*out));
|
|
if (modelval)
|
|
out->model = Mod_ForName(prinst->StringToNative(prinst, modelval->_int), MLV_WARN);
|
|
if (originval)
|
|
VectorCopy(originval->_vector, out->origin);
|
|
if (!anglesval)anglesval = (eval_t*)vec3_origin;
|
|
AngleVectors(anglesval->_vector, out->axis[0], out->axis[1], out->axis[2]);
|
|
VectorInverse(out->axis[1]);
|
|
|
|
out->scale = 1;
|
|
out->skinnum = skinval?skinval->_float:0;
|
|
out->framestate.g[FS_REG].frame[0] = frame1val?frame1val->_float:0;
|
|
out->framestate.g[FS_REG].frame[1] = frame2val?frame2val->_float:0;
|
|
out->framestate.g[FS_REG].lerpweight[1] = lerpfracval?lerpfracval->_float:0;
|
|
out->framestate.g[FS_REG].lerpweight[0] = 1-out->framestate.g[FS_REG].lerpweight[1];
|
|
out->framestate.g[FS_REG].frametime[0] = frame1timeval?frame1timeval->_float:0;
|
|
out->framestate.g[FS_REG].frametime[1] = frame2timeval?frame2timeval->_float:0;
|
|
|
|
out->customskin = skinobjectval?skinobjectval->_float:0;
|
|
|
|
//FIXME: colourmap
|
|
ival = colormapval?colormapval->_float:0;
|
|
out->playerindex = -1;
|
|
if (ival >= 1024)
|
|
{
|
|
//DP COLORMAP extension
|
|
out->topcolour = (ival>>4) & 0x0f;
|
|
out->bottomcolour = ival & 0xf;
|
|
}
|
|
/* else if (ival > 0 && ival <= MAX_CLIENTS)
|
|
{ //FIXME: tie to the current skin/topcolor/bottomcolor cvars somehow?
|
|
out->playerindex = ival - 1;
|
|
out->topcolour = cl.players[ival-1].ttopcolor;
|
|
out->bottomcolour = cl.players[ival-1].tbottomcolor;
|
|
}*/
|
|
else
|
|
{
|
|
out->topcolour = TOP_DEFAULT;
|
|
out->bottomcolour = BOTTOM_DEFAULT;
|
|
}
|
|
|
|
if (rflags & CSQCRF_ADDITIVE)
|
|
out->flags |= RF_ADDITIVE;
|
|
if (rflags & CSQCRF_DEPTHHACK)
|
|
out->flags |= RF_DEPTHHACK;
|
|
|
|
if (out->model)
|
|
return true;
|
|
return false;
|
|
}
|
|
static void QCBUILTIN PF_m_addentity(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
menuedict_t *in = (void*)G_EDICT(prinst, OFS_PARM0);
|
|
entity_t ent;
|
|
if (in->ereftype == ER_FREE || in->entnum == 0)
|
|
{
|
|
Con_Printf("Tried drawing a free/removed/world entity\n");
|
|
return;
|
|
}
|
|
|
|
if (CopyMenuEdictToEntity(prinst, in, &ent))
|
|
V_AddAxisEntity(&ent);
|
|
}
|
|
static void QCBUILTIN PF_m_renderscene(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
V_ApplyRefdef();
|
|
R_RenderView();
|
|
}
|
|
void QCBUILTIN PF_R_SetViewFlag(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
|
void QCBUILTIN PF_R_GetViewFlag(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
|
|
|
|
|
static void QCBUILTIN PF_menu_cprint (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
const char *str = PF_VarString(prinst, 0, pr_globals);
|
|
SCR_CenterPrint(0, str, true);
|
|
}
|
|
static void QCBUILTIN PF_cl_changelevel (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
#ifndef CLIENTONLY
|
|
const char *nextmap = PR_GetStringOfs(prinst, OFS_PARM0);
|
|
if (sv.active || !cls.state)
|
|
{
|
|
char buf[1024];
|
|
Cbuf_AddText(va("changelevel %s\n", COM_QuotedString(nextmap, buf, sizeof(buf), false)), RESTRICT_INSECURE);
|
|
}
|
|
#endif
|
|
}
|
|
static void QCBUILTIN PF_crash (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
int binum;
|
|
char fname[MAX_QPATH];
|
|
//allow people to rename it or whatever
|
|
if (!prinst->GetBuiltinCallInfo(prinst, &binum, fname, sizeof(fname)))
|
|
{
|
|
binum = 0;
|
|
strcpy(fname, "?unknown?");
|
|
}
|
|
|
|
prinst->RunError(prinst, "\n%s called", fname);
|
|
}
|
|
static void QCBUILTIN PF_stackdump (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
prinst->StackTrace(prinst, true);
|
|
}
|
|
#define PF_cl_clientcommand PF_Fixme
|
|
#define PF_altstr_ins PF_Fixme //insert after, apparently
|
|
|
|
static void MP_ConsoleCommand_f(void)
|
|
{
|
|
char cmd[2048];
|
|
Q_snprintfz(cmd, sizeof(cmd), "%s %s", Cmd_Argv(0), Cmd_Args());
|
|
MP_ConsoleCommand(cmd);
|
|
}
|
|
static void QCBUILTIN PF_menu_registercommand (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|
{
|
|
const char *str = PF_VarString(prinst, 0, pr_globals);
|
|
if (!Cmd_Exists(str))
|
|
Cmd_AddCommand(str, MP_ConsoleCommand_f);
|
|
}
|
|
|
|
|
|
static struct {
|
|
char *name;
|
|
builtin_t bifunc;
|
|
int ebfsnum;
|
|
} BuiltinList[] = {
|
|
{"checkextension", PF_menu_checkextension, 1},
|
|
{"checkbuiltin", PF_checkbuiltin, 0},
|
|
{"error", PF_error, 2},
|
|
{"objerror", PF_nonfatalobjerror, 3},
|
|
{"print", PF_print, 4},
|
|
{"bprint", PF_cl_bprint, 5},
|
|
{"msprint", PF_cl_sprint, 6},
|
|
{"cprint", PF_menu_cprint, 7},
|
|
{"normalize", PF_normalize, 8},
|
|
{"vlen", PF_vlen, 9},
|
|
{"vectoyaw", PF_vectoyaw, 10},
|
|
{"vectoangles", PF_vectoangles, 11},
|
|
{"crossproduct", PF_crossproduct, 0},
|
|
{"random", PF_random, 12},
|
|
{"localcmd", PF_localcmd, 13},
|
|
{"cvar", PF_menu_cvar, 14},
|
|
{"cvar_set", PF_menu_cvar_set, 15},
|
|
{"dprint", PF_dprint, 16},
|
|
{"ftos", PF_ftos, 17},
|
|
{"fabs", PF_fabs, 18},
|
|
{"vtos", PF_vtos, 19},
|
|
{"etos", PF_etos, 20},
|
|
{"stof", PF_stof, 21},
|
|
|
|
{"stoi", PF_stoi, 0},
|
|
{"itos", PF_itos, 0},
|
|
{"stoh", PF_stoh, 0},
|
|
{"htos", PF_htos, 0},
|
|
{"ftoi", PF_ftoi, 0},
|
|
{"itof", PF_itof, 0},
|
|
|
|
{"spawn", PF_Spawn, 22},
|
|
{"remove", PF_Remove_, 23},
|
|
{"removeinstant", PF_RemoveInstant, 0},
|
|
{"find", PF_FindString, 24},
|
|
{"findfloat", PF_FindFloat, 25},
|
|
{"findentity", PF_FindFloat, 25},
|
|
{"findchain", PF_menu_findchain, 26},
|
|
{"findchainfloat", PF_menu_findchainfloat, 27},
|
|
{"precache_file", PF_CL_precache_file, 28},
|
|
{"precache_sound", PF_CL_precache_sound, 29},
|
|
{"coredump", PF_coredump, 30},
|
|
{"traceon", PF_traceon, 31},
|
|
{"traceoff", PF_traceoff, 32},
|
|
{"eprint", PF_eprint, 33},
|
|
{"rint", PF_rint, 34},
|
|
{"floor", PF_floor, 35},
|
|
{"ceil", PF_ceil, 36},
|
|
{"nextent", PF_nextent, 37},
|
|
{"sin", PF_Sin, 38},
|
|
{"cos", PF_Cos, 39},
|
|
{"sqrt", PF_Sqrt, 40},
|
|
{"randomvector", PF_randomvector, 41},
|
|
{"registercvar", PF_registercvar, 42},
|
|
{"min", PF_min, 43},
|
|
{"max", PF_max, 44},
|
|
{"bound", PF_bound, 45},
|
|
{"pow", PF_pow, 46},
|
|
{"logarithm", PF_Logarithm, 0},
|
|
{"entityprotection", PF_entityprotection, 0},
|
|
{"copyentity", PF_CopyEntity, 47},
|
|
{"fopen", PF_fopen, 48},
|
|
{"fclose", PF_fclose, 49},
|
|
{"fgets", PF_fgets, 50},
|
|
{"fputs", PF_fputs, 51},
|
|
{"fread", PF_fread, 0},
|
|
{"fwrite", PF_fwrite, 0},
|
|
{"fseek", PF_fseek, 0},
|
|
{"fsize", PF_fsize, 0},
|
|
{"strlen", PF_strlen, 52},
|
|
{"strcat", PF_strcat, 53},
|
|
{"substring", PF_substring, 54},
|
|
{"stov", PF_stov, 55},
|
|
{"strzone", PF_strzone, 56},
|
|
{"strunzone", PF_strunzone, 57},
|
|
{"tokenize", PF_Tokenize, 58},
|
|
{"argv", PF_ArgV, 59},
|
|
{"isserver", PF_isserver, 60},
|
|
{"clientcount", PF_cl_clientcount, 61}, //float clientcount(void) = #61;
|
|
{"clientstate", PF_clientstate, 62},
|
|
{"clientcommand", PF_cl_clientcommand, 63}, //void clientcommand(float client, string s) = #63;
|
|
{"changelevel", PF_cl_changelevel, 64}, //void changelevel(string map) = #64;
|
|
{"localsound", PF_cl_localsound, 65},
|
|
{"getmousepos", PF_cl_getmousepos, 66},
|
|
{"gettime", PF_gettime, 67},
|
|
{"loadfromdata", PF_loadfromdata, 68},
|
|
{"loadfromfile", PF_loadfromfile, 69},
|
|
{"mod", PF_mod, 70},
|
|
{"cvar_string", PF_menu_cvar_string, 71},
|
|
{"crash", PF_crash, 72}, //void crash(void) = #72;
|
|
{"stackdump", PF_stackdump, 73}, //void stackdump(void) = #73;
|
|
{"search_begin", PF_search_begin, 74},
|
|
{"search_end", PF_search_end, 75},
|
|
{"search_getsize", PF_search_getsize, 76},
|
|
{"search_getfilename", PF_search_getfilename, 77},
|
|
{"search_getfilesize", PF_search_getfilesize, 0},
|
|
{"search_getfilemtime", PF_search_getfilemtime, 0},
|
|
{"chr2str", PF_chr2str, 78},
|
|
{"etof", PF_etof, 79},
|
|
{"ftoe", PF_ftoe, 80},
|
|
{"validstring", PF_IsNotNull, 81},
|
|
{"altstr_count", PF_altstr_count, 82},
|
|
{"altstr_prepare", PF_altstr_prepare, 83},
|
|
{"altstr_get", PF_altstr_get, 84},
|
|
{"altstr_set", PF_altstr_set, 85},
|
|
{"altstr_ins", PF_altstr_ins, 86},
|
|
{"findflags", PF_FindFlags, 87},
|
|
{"findchainflags", PF_menu_findchainflags, 88},
|
|
{"cvar_defstring", PF_cvar_defstring, 89},
|
|
{"setmodel", PF_m_setmodel, 90},
|
|
{"precache_model", PF_m_precache_model, 91},
|
|
{"setorigin", PF_m_setorigin, 92},
|
|
//gap
|
|
{"abort", PF_Abort, 211},
|
|
//gap
|
|
{"strstrofs", PF_strstrofs, 221},
|
|
{"str2chr", PF_str2chr, 222},
|
|
{"chr2str", PF_chr2str, 223},
|
|
{"strconv", PF_strconv, 224},
|
|
{"strpad", PF_strpad, 225},
|
|
{"infoadd", PF_infoadd, 226},
|
|
{"infoget", PF_infoget, 227},
|
|
{"strcmp", PF_strncmp, 228},
|
|
{"strncmp", PF_strncmp, 228},
|
|
{"strcasecmp", PF_strncasecmp, 229},
|
|
{"strncasecmp", PF_strncasecmp, 230},
|
|
{"strtrim", PF_strtrim, 0},
|
|
//gap
|
|
{"shaderforname", PF_shaderforname, 238},
|
|
{"sendpacket", PF_cl_SendPacket, 242},
|
|
//gap
|
|
{"hash_createtab", PF_hash_createtab, 287},
|
|
{"hash_destroytab", PF_hash_destroytab, 288},
|
|
{"hash_add", PF_hash_add, 289},
|
|
{"hash_get", PF_hash_get, 290},
|
|
{"hash_delete", PF_hash_delete, 291},
|
|
{"hash_getkey", PF_hash_getkey, 292},
|
|
{"hash_getcb", PF_hash_getcb, 293},
|
|
{"checkcommand", PF_checkcommand, 294},
|
|
{"argescape", PF_argescape, 295},
|
|
//gap
|
|
{"clearscene", PF_m_clearscene, 300},
|
|
// {"addentities", PF_Fixme, 301},
|
|
{"addentity", PF_m_addentity, 302},//FIXME: needs setmodel, origin, angles, colormap(eep), frame etc, skin,
|
|
#ifdef CSQC_DAT
|
|
{"setproperty", PF_R_SetViewFlag, 303},//should be okay to share
|
|
#endif
|
|
{"renderscene", PF_m_renderscene, 304},//too module-specific
|
|
// {"dynamiclight_add", PF_R_DynamicLight_Add, 305},//should be okay to share
|
|
{"R_BeginPolygon", PF_R_PolygonBegin, 306},//useful for 2d stuff
|
|
{"R_PolygonVertex", PF_R_PolygonVertex, 307},
|
|
{"R_EndPolygon", PF_R_PolygonEnd, 308},
|
|
#ifdef CSQC_DAT
|
|
{"getproperty", PF_R_GetViewFlag, 309},//should be okay to share
|
|
#endif
|
|
//unproject 310
|
|
//project 311
|
|
|
|
#ifdef CSQC_DAT
|
|
{"r_uploadimage", PF_CL_uploadimage, 0},
|
|
#endif
|
|
{"r_readimage", PF_CL_readimage, 0},
|
|
|
|
|
|
{"print_csqc", PF_print, 339},
|
|
{"keynumtostring_csqc", PF_cl_keynumtostring, 340},
|
|
{"stringtokeynum_csqc", PF_cl_stringtokeynum, 341},
|
|
{"getkeybind", PF_cl_getkeybind, 342},
|
|
{"setcursormode", PF_cl_setcursormode, 343},
|
|
{"getcursormode", PF_cl_getcursormode, 0},
|
|
{"setmousepos", PF_cl_setmousepos, 0},
|
|
// {NULL, PF_Fixme, 344},
|
|
// {NULL, PF_Fixme, 345},
|
|
// {NULL, PF_Fixme, 346},
|
|
// {NULL, PF_Fixme, 347},
|
|
// {NULL, PF_Fixme, 348},
|
|
{"isdemo", PF_isdemo, 349},
|
|
// {NULL, PF_Fixme, 350},
|
|
// {NULL, PF_Fixme, 351},
|
|
{"registercommand", PF_menu_registercommand, 352},
|
|
{"wasfreed", PF_WasFreed, 353},
|
|
// {NULL, PF_Fixme, 354},
|
|
#ifdef HAVE_MEDIA_DECODER
|
|
{"videoplaying", PF_cs_media_getstate, 355},
|
|
#endif
|
|
{"findfont", PF_CL_findfont, 356},
|
|
{"loadfont", PF_CL_loadfont, 357},
|
|
//gap
|
|
// {"dynamiclight_get", PF_R_DynamicLight_Get, 372},
|
|
// {"dynamiclight_set", PF_R_DynamicLight_Set, 373},
|
|
// {NULL, PF_Fixme, 374},
|
|
// {NULL, PF_Fixme, 375},
|
|
{"setcustomskin", PF_m_setcustomskin, 376},
|
|
//gap
|
|
{"memalloc", PF_memalloc, 384},
|
|
{"memfree", PF_memfree, 385},
|
|
{"memcpy", PF_memcpy, 386},
|
|
{"memfill8", PF_memfill8, 387},
|
|
{"memgetval", PF_memgetval, 388},
|
|
{"memsetval", PF_memsetval, 389},
|
|
{"memptradd", PF_memptradd, 390},
|
|
{"memstrsize", PF_memstrsize, 0},
|
|
{"con_getset", PF_SubConGetSet, 391},
|
|
{"con_printf", PF_SubConPrintf, 392},
|
|
{"con_draw", PF_SubConDraw, 393},
|
|
{"con_input", PF_SubConInput, 394},
|
|
{"setwindowcaption", PF_cl_setwindowcaption, 0},
|
|
{"cvars_haveunsaved", PF_cvars_haveunsaved, 0},
|
|
//gap
|
|
// {"writebyte, PF_Fixme, 401},
|
|
// {"writechar, PF_Fixme, 402},
|
|
// {"writeshort, PF_Fixme, 403},
|
|
// {"writelong, PF_Fixme, 404},
|
|
// {"writeangle, PF_Fixme, 405},
|
|
// {"writecoord, PF_Fixme, 406},
|
|
// {"writestring, PF_Fixme, 407},
|
|
// {"writeentity, PF_Fixme, 408},
|
|
//gap
|
|
{"buf_create", PF_buf_create, 440},
|
|
{"buf_del", PF_buf_del, 441},
|
|
{"buf_getsize", PF_buf_getsize, 442},
|
|
{"buf_copy", PF_buf_copy, 443},
|
|
{"buf_sort", PF_buf_sort, 444},
|
|
{"buf_implode", PF_buf_implode, 445},
|
|
{"bufstr_get", PF_bufstr_get, 446},
|
|
{"bufstr_set", PF_bufstr_set, 447},
|
|
{"bufstr_add", PF_bufstr_add, 448},
|
|
{"bufstr_free", PF_bufstr_free, 449},
|
|
// {NULL, PF_Fixme, 450},
|
|
{"iscachedpic", PF_CL_is_cached_pic, 451},
|
|
{"precache_pic", PF_CL_precache_pic, 452},
|
|
{"free_pic", PF_CL_free_pic, 453},
|
|
{"drawcharacter", PF_CL_drawcharacter, 454},
|
|
{"drawrawstring", PF_CL_drawrawstring, 455},
|
|
{"drawpic", PF_CL_drawpic, 456},
|
|
{"drawrotpic", PF_CL_drawrotpic, 0},
|
|
{"drawfill", PF_CL_drawfill, 457},
|
|
{"drawsetcliparea", PF_CL_drawsetcliparea, 458},
|
|
{"drawresetcliparea", PF_CL_drawresetcliparea, 459},
|
|
{"drawgetimagesize", PF_CL_drawgetimagesize, 460},
|
|
#ifdef HAVE_MEDIA_DECODER
|
|
{"cin_open", PF_cs_media_create, 461},
|
|
{"cin_close", PF_cs_media_destroy, 462},
|
|
{"cin_setstate", PF_cs_media_setstate, 463},
|
|
{"cin_getstate", PF_cs_media_getstate, 464},
|
|
{"cin_restart", PF_cs_media_restart, 465},
|
|
#endif
|
|
{"drawline", PF_CL_drawline, 466},
|
|
{"drawstring", PF_CL_drawcolouredstring, 467},
|
|
{"stringwidth", PF_CL_stringwidth, 468},
|
|
{"drawsubpic", PF_CL_drawsubpic, 469},
|
|
{"drawrotsubpic", PF_CL_drawrotsubpic, 0},
|
|
{"drawtextfield", PF_CL_DrawTextField, 0},
|
|
|
|
#ifdef HAVE_LEGACY
|
|
{"drawrotpic_dp", PF_CL_drawrotpic_dp, 470},
|
|
#endif
|
|
//MERGES WITH CLIENT+SERVER BUILTIN MAPPINGS BELOW
|
|
{"asin", PF_asin, 471},
|
|
{"acos", PF_acos, 472},
|
|
{"atan", PF_atan, 473},
|
|
{"atan2", PF_atan2, 474},
|
|
{"tan", PF_tan, 475},
|
|
{"strlennocol", PF_strlennocol, 476},
|
|
{"strdecolorize", PF_strdecolorize, 477},
|
|
{"strftime", PF_strftime, 478},
|
|
{"tokenizebyseparator", PF_tokenizebyseparator, 479},
|
|
{"strtolower", PF_strtolower, 480},
|
|
{"strtoupper", PF_strtoupper, 481},
|
|
{"csqc_cvar_defstring", PF_cvar_defstring, 482},
|
|
// {NULL, PF_Fixme, 483},
|
|
{"strreplace", PF_strreplace, 484},
|
|
{"strireplace", PF_strireplace, 485},
|
|
// {NULL, PF_Fixme, 486},
|
|
#ifdef HAVE_MEDIA_DECODER
|
|
{"gecko_create", PF_cs_media_create, 487},
|
|
{"gecko_destroy", PF_cs_media_destroy, 488},
|
|
{"gecko_navigate", PF_cs_media_command, 489},
|
|
{"gecko_keyevent", PF_cs_media_keyevent, 490},
|
|
{"gecko_mousemove", PF_cs_media_mousemove, 491},
|
|
{"gecko_resize", PF_cs_media_resize, 492},
|
|
{"gecko_get_texture_extent",PF_cs_media_get_texture_extent,493},
|
|
{"gecko_getproperty", PF_cs_media_getproperty, 0},
|
|
#endif
|
|
{"crc16", PF_crc16, 494},
|
|
{"cvar_type", PF_cvar_type, 495},
|
|
{"numentityfields", PF_numentityfields, 496},
|
|
{"findentityfield", PF_findentityfield, 0},
|
|
{"entityfieldref", PF_entityfieldref, 0},
|
|
{"entityfieldname", PF_entityfieldname, 497},
|
|
{"entityfieldtype", PF_entityfieldtype, 498},
|
|
{"getentityfieldstring", PF_getentityfieldstring, 499},
|
|
{"putentityfieldstring", PF_putentityfieldstring, 500},
|
|
// {NULL, PF_Fixme, 501},
|
|
// {NULL, PF_Fixme, 502},
|
|
{"whichpack", PF_whichpack, 503},
|
|
//gap
|
|
{"uri_escape", PF_uri_escape, 510},
|
|
{"uri_unescape", PF_uri_unescape, 511},
|
|
{"num_for_edict", PF_etof, 512},
|
|
{"uri_get", PF_uri_get, 513},
|
|
{"uri_post", PF_uri_get, 513},
|
|
{"tokenize_console", PF_tokenize_console, 514},
|
|
{"argv_start_index", PF_argv_start_index, 515},
|
|
{"argv_end_index", PF_argv_end_index, 516},
|
|
{"buf_cvarlist", PF_buf_cvarlist, 517},
|
|
{"cvar_description", PF_cvar_description, 518},
|
|
//gap
|
|
{"log", PF_Logarithm, 532},
|
|
// {"getsoundtime", PF_Fixme, 533},
|
|
{"soundlength", PF_soundlength, 534},
|
|
{"buf_loadfile", PF_buf_loadfile, 535},
|
|
{"buf_writefile", PF_buf_writefile, 536},
|
|
// {"bufstr_find", PF_Fixme, 537},
|
|
// {"matchpattern", PF_Fixme, 538},
|
|
//gap
|
|
{"setkeydest", PF_cl_setkeydest, 601},
|
|
{"getkeydest", PF_cl_getkeydest, 602},
|
|
{"setmousetarget", PF_cl_setmousetarget, 603},
|
|
{"getmousetarget", PF_cl_getmousetarget, 604},
|
|
{"callfunction", PF_callfunction, 605},
|
|
{"writetofile", PF_writetofile, 606},
|
|
{"isfunction", PF_isfunction, 607},
|
|
{"getresolution", PF_cl_getresolution, 608},
|
|
{"keynumtostring", PF_cl_keynumtostring, 609},
|
|
{"findkeysforcommand", PF_cl_findkeysforcommand, 610},
|
|
{"gethostcachevalue", PF_cl_gethostcachevalue, 611},
|
|
{"gethostcachestring", PF_cl_gethostcachestring, 612},
|
|
{"parseentitydata", PF_parseentitydata, 613},
|
|
{"generateentitydata", PF_generateentitydata, 0},
|
|
|
|
{"stringtokeynum", PF_cl_stringtokeynum, 614},
|
|
|
|
{"resethostcachemasks", PF_cl_resethostcachemasks, 615},
|
|
{"sethostcachemaskstring", PF_cl_sethostcachemaskstring,616},
|
|
{"sethostcachemasknumber", PF_cl_sethostcachemasknumber,617},
|
|
{"resorthostcache", PF_cl_resorthostcache, 618},
|
|
{"sethostcachesort", PF_cl_sethostcachesort, 619},
|
|
{"refreshhostcache", PF_cl_refreshhostcache, 620},
|
|
{"gethostcachenumber", PF_cl_gethostcachenumber, 621},
|
|
{"gethostcacheindexforkey", PF_cl_gethostcacheindexforkey,622},
|
|
{"addwantedhostcachekey", PF_cl_addwantedhostcachekey,623},
|
|
#ifdef CL_MASTER
|
|
{"getextresponse", PF_cl_getextresponse, 624},
|
|
#endif
|
|
{"netaddress_resolve", PF_netaddress_resolve, 625},
|
|
{"getgamedirinfo", PF_cl_getgamedirinfo, 626},
|
|
#ifdef PACKAGEMANAGER
|
|
{"getpackagemanagerinfo", PF_cl_getpackagemanagerinfo,0},
|
|
#endif
|
|
{"sprintf", PF_sprintf, 627},
|
|
// {NULL, PF_Fixme, 628},
|
|
// {NULL, PF_Fixme, 629},
|
|
{"setkeybind", PF_cl_setkeybind, 630},
|
|
{"getbindmaps", PF_cl_GetBindMap, 631},
|
|
{"setbindmaps", PF_cl_SetBindMap, 632},
|
|
{"crypto_getkeyfp", PF_crypto_getkeyfp, 633},
|
|
{"crypto_getidfp", PF_crypto_getidfp, 634},
|
|
{"crypto_getencryptlevel", PF_crypto_getencryptlevel, 635},
|
|
{"crypto_getmykeyfp", PF_crypto_getmykeyfp, 636},
|
|
{"crypto_getmyidfp", PF_crypto_getmyidfp, 637},
|
|
// {NULL, PF_Fixme, 638},
|
|
{"digest_hex", PF_digest_hex, 639},
|
|
{"digest_ptr", PF_digest_ptr, 0},
|
|
// {NULL, PF_Fixme, 640},
|
|
{"crypto_getmyidstatus", PF_crypto_getmyidstatus, 641},
|
|
// {"coverage", PF_Fixme, 642},
|
|
{"crypto_getidstatus", PF_crypto_getidstatus, 643},
|
|
// {NULL, PF_Fixme, 644},
|
|
// {NULL, PF_Fixme, 645},
|
|
// {NULL, PF_Fixme, 646},
|
|
// {NULL, PF_Fixme, 647},
|
|
// {NULL, PF_Fixme, 648},
|
|
// {NULL, PF_Fixme, 649},
|
|
{"fcopy", PF_fcopy, 650},
|
|
{"frename", PF_frename, 651},
|
|
{"fremove", PF_fremove, 652},
|
|
{"fexists", PF_fexists, 653},
|
|
{"rmtree", PF_rmtree, 654},
|
|
|
|
|
|
{"setlocaluserinfo", PF_cl_setlocaluserinfo, 0},
|
|
{"getlocaluserinfo", PF_cl_getlocaluserinfostring, 0},
|
|
{"setlocaluserinfoblob", PF_cl_setlocaluserinfo, 0},
|
|
{"getlocaluserinfoblob", PF_cl_getlocaluserinfoblob, 0},
|
|
|
|
{NULL}
|
|
};
|
|
static builtin_t menu_builtins[1024];
|
|
|
|
|
|
int MP_BuiltinValid(const char *name, int num)
|
|
{
|
|
int i;
|
|
for (i = 0; BuiltinList[i].name; i++)
|
|
{
|
|
if (BuiltinList[i].ebfsnum == num)
|
|
{
|
|
if (!strcmp(BuiltinList[i].name, name))
|
|
{
|
|
if (/*BuiltinList[i].bifunc == PF_NoMenu ||*/ BuiltinList[i].bifunc == PF_Fixme)
|
|
return false;
|
|
else
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static void MP_SetupBuiltins(void)
|
|
{
|
|
int i;
|
|
for (i = 0; i < sizeof(menu_builtins)/sizeof(menu_builtins[0]); i++)
|
|
menu_builtins[i] = PF_Fixme;
|
|
for (i = 0; BuiltinList[i].bifunc; i++)
|
|
{
|
|
if (BuiltinList[i].ebfsnum)
|
|
menu_builtins[BuiltinList[i].ebfsnum] = BuiltinList[i].bifunc;
|
|
}
|
|
}
|
|
|
|
static int PDECL PR_Menu_MapNamedBuiltin(pubprogfuncs_t *progfuncs, int headercrc, const char *builtinname)
|
|
{
|
|
int i, binum;
|
|
for (i = 0;BuiltinList[i].name;i++)
|
|
{
|
|
if (!strcmp(BuiltinList[i].name, builtinname) && BuiltinList[i].bifunc != PF_Fixme)
|
|
{
|
|
for (binum = sizeof(menu_builtins)/sizeof(menu_builtins[0]); --binum; )
|
|
{
|
|
if (menu_builtins[binum] && menu_builtins[binum] != PF_Fixme && BuiltinList[i].bifunc)
|
|
continue;
|
|
menu_builtins[binum] = BuiltinList[i].bifunc;
|
|
return binum;
|
|
}
|
|
Con_Printf("No more builtin slots to allocate for %s\n", builtinname);
|
|
break;
|
|
}
|
|
}
|
|
Con_DPrintf("Unknown menu builtin: %s\n", builtinname);
|
|
return 0;
|
|
}
|
|
|
|
|
|
static qboolean MP_MouseMove(menu_t *menu, qboolean isabs, unsigned int devid, float xdelta, float ydelta)
|
|
{
|
|
void *pr_globals;
|
|
|
|
if (!menu_world.progs || !mpfuncs.inputevent)
|
|
return false;
|
|
|
|
if (setjmp(mp_abort))
|
|
return false;
|
|
inmenuprogs++;
|
|
pr_globals = PR_globals(menu_world.progs, PR_CURRENT);
|
|
G_FLOAT(OFS_PARM0) = isabs?CSIE_MOUSEABS:CSIE_MOUSEDELTA;
|
|
G_FLOAT(OFS_PARM1) = (xdelta * vid.width) / vid.pixelwidth;
|
|
G_FLOAT(OFS_PARM2) = (ydelta * vid.height) / vid.pixelheight;
|
|
G_FLOAT(OFS_PARM3) = devid;
|
|
PR_ExecuteProgram (menu_world.progs, mpfuncs.inputevent);
|
|
if (R2D_Flush)
|
|
R2D_Flush();
|
|
inmenuprogs--;
|
|
return G_FLOAT(OFS_RETURN);
|
|
}
|
|
|
|
static qboolean MP_JoystickAxis(menu_t *menu, unsigned int devid, int axis, float value)
|
|
{
|
|
void *pr_globals;
|
|
if (!menu_world.progs || !mpfuncs.inputevent)
|
|
return false;
|
|
if (setjmp(mp_abort))
|
|
return false;
|
|
inmenuprogs++;
|
|
pr_globals = PR_globals(menu_world.progs, PR_CURRENT);
|
|
G_FLOAT(OFS_PARM0) = CSIE_JOYAXIS;
|
|
G_FLOAT(OFS_PARM1) = axis;
|
|
G_FLOAT(OFS_PARM2) = value;
|
|
G_FLOAT(OFS_PARM3) = devid;
|
|
PR_ExecuteProgram (menu_world.progs, mpfuncs.inputevent);
|
|
if (R2D_Flush)
|
|
R2D_Flush();
|
|
inmenuprogs--;
|
|
return G_FLOAT(OFS_RETURN);
|
|
}
|
|
static qboolean MP_KeyEvent(menu_t *menu, qboolean isdown, unsigned int devid, int key, int unicode)
|
|
{
|
|
qboolean result;
|
|
|
|
#ifdef TEXTEDITOR
|
|
if (editormodal)
|
|
return false;
|
|
#endif
|
|
|
|
if (setjmp(mp_abort))
|
|
return true;
|
|
|
|
if (isdown)
|
|
{
|
|
#ifndef NOBUILTINMENUS
|
|
if (key == 'c')
|
|
{
|
|
extern qboolean keydown[K_MAX];
|
|
if (keydown[K_LCTRL] || keydown[K_RCTRL])
|
|
{
|
|
MP_Shutdown();
|
|
M_Init_Internal();
|
|
return true;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
mpkeysdown[key>>3] |= (1<<(key&7));
|
|
}
|
|
else
|
|
{ //don't fire up events if it was not actually pressed.
|
|
if (key && !(mpkeysdown[key>>3] & (1<<(key&7))))
|
|
return false;
|
|
mpkeysdown[key>>3] &= ~(1<<(key&7));
|
|
}
|
|
|
|
menutime = Sys_DoubleTime();
|
|
if (menu_world.g.time)
|
|
*menu_world.g.time = menutime;
|
|
|
|
inmenuprogs++;
|
|
if (mpfuncs.inputevent)
|
|
{
|
|
void *pr_globals = PR_globals(menu_world.progs, PR_CURRENT);
|
|
G_FLOAT(OFS_PARM0) = isdown?CSIE_KEYDOWN:CSIE_KEYUP;
|
|
G_FLOAT(OFS_PARM1) = MP_TranslateFTEtoQCCodes(key);
|
|
G_FLOAT(OFS_PARM2) = unicode;
|
|
G_FLOAT(OFS_PARM3) = devid;
|
|
if (isdown)
|
|
{
|
|
qcinput_scan = G_FLOAT(OFS_PARM1);
|
|
qcinput_unicode = G_FLOAT(OFS_PARM2);
|
|
}
|
|
PR_ExecuteProgram(menu_world.progs, mpfuncs.inputevent);
|
|
result = G_FLOAT(OFS_RETURN);
|
|
qcinput_scan = 0;
|
|
qcinput_unicode = 0;
|
|
}
|
|
else if (isdown && mpfuncs.keydown)
|
|
{
|
|
void *pr_globals = PR_globals(menu_world.progs, PR_CURRENT);
|
|
G_FLOAT(OFS_PARM0) = MP_TranslateFTEtoQCCodes(key);
|
|
G_FLOAT(OFS_PARM1) = unicode;
|
|
PR_ExecuteProgram(menu_world.progs, mpfuncs.keydown);
|
|
result = true; //doesn't have a return value, so if the menu is set up for key events, all events are considered eaten.
|
|
}
|
|
else if (!isdown && mpfuncs.keyup)
|
|
{
|
|
void *pr_globals = PR_globals(menu_world.progs, PR_CURRENT);
|
|
G_FLOAT(OFS_PARM0) = MP_TranslateFTEtoQCCodes(key);
|
|
G_FLOAT(OFS_PARM1) = unicode;
|
|
PR_ExecuteProgram(menu_world.progs, mpfuncs.keyup);
|
|
result = false; // doesn't have a return value, so don't block it
|
|
}
|
|
else
|
|
result = false;
|
|
inmenuprogs--;
|
|
|
|
if (R2D_Flush) //shouldn't be needed, but in case the mod is buggy.
|
|
R2D_Flush();
|
|
return result;
|
|
}
|
|
static void MP_TryRelease(menu_t *m)
|
|
{
|
|
if (inmenuprogs)
|
|
return; //if the qc asked for it, the qc probably already knows about it. don't recurse.
|
|
MP_Toggle(0);
|
|
}
|
|
|
|
void MP_Shutdown (void)
|
|
{
|
|
func_t temp;
|
|
if (!menu_world.progs)
|
|
return;
|
|
|
|
menuqc.release = NULL; //don't notify
|
|
Menu_Unlink(&menuqc);
|
|
/*
|
|
{
|
|
char *buffer;
|
|
int size = 1024*1024*8;
|
|
buffer = Z_Malloc(size);
|
|
menuprogs->save_ents(menuprogs, buffer, &size, 1);
|
|
COM_WriteFile("menucore.txt", buffer, size);
|
|
Z_Free(buffer);
|
|
}
|
|
*/
|
|
temp = mpfuncs.shutdown;
|
|
mpfuncs.shutdown = 0;
|
|
if (temp && !inmenuprogs)
|
|
PR_ExecuteProgram(menu_world.progs, temp);
|
|
|
|
PR_Common_Shutdown(menu_world.progs, false);
|
|
menu_world.progs->Shutdown(menu_world.progs);
|
|
memset(&menu_world, 0, sizeof(menu_world));
|
|
PR_ReleaseFonts(kdm_menu);
|
|
|
|
#ifdef CL_MASTER
|
|
Master_ClearMasks();
|
|
#endif
|
|
|
|
Cmd_RemoveCommands(MP_ConsoleCommand_f);
|
|
|
|
Key_Dest_Remove(kdm_menu);
|
|
key_dest_absolutemouse &= ~kdm_menu;
|
|
}
|
|
|
|
void *VARGS PR_CB_Malloc(int size); //these functions should be tracked by the library reliably, so there should be no need to track them ourselves.
|
|
void VARGS PR_CB_Free(void *mem);
|
|
|
|
//Any menu builtin error or anything like that will come here.
|
|
void VARGS Menu_Abort (char *format, ...)
|
|
{
|
|
va_list argptr;
|
|
char string[1024];
|
|
|
|
va_start (argptr, format);
|
|
vsnprintf (string,sizeof(string)-1, format,argptr);
|
|
va_end (argptr);
|
|
|
|
Con_Printf("Menu_Abort: %s\nShutting down menu.dat\n", string);
|
|
|
|
if (pr_menu_coreonerror.value)
|
|
{
|
|
char *buffer;
|
|
size_t size = 1024*1024*8;
|
|
buffer = Z_Malloc(size);
|
|
menu_world.progs->save_ents(menu_world.progs, buffer, &size, size, 3);
|
|
COM_WriteFile("menucore.txt", FS_GAMEONLY, buffer, size);
|
|
Z_Free(buffer);
|
|
}
|
|
|
|
MP_Shutdown();
|
|
M_Init_Internal();
|
|
|
|
if (inmenuprogs) //something in the menu caused the problem, so...
|
|
{
|
|
inmenuprogs = 0;
|
|
longjmp(mp_abort, 1);
|
|
}
|
|
}
|
|
|
|
void MP_CvarChanged(cvar_t *var)
|
|
{
|
|
if (menu_world.progs)
|
|
{
|
|
PR_AutoCvar(menu_world.progs, var);
|
|
}
|
|
}
|
|
|
|
pbool PDECL Menu_CheckHeaderCrc(pubprogfuncs_t *inst, progsnum_t idx, int crc, const char *filename)
|
|
{
|
|
if (crc == 10020)
|
|
return true; //its okay
|
|
Con_Printf("progs crc is invalid for %s\n", filename);
|
|
if (crc == 12776)
|
|
{ //whoever wrote wrath fucked up.
|
|
Con_Printf("(please correct .src include orders)\n");
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static void *PDECL MP_PRReadFile (const char *path, qbyte *(PDECL *buf_get)(void *buf_ctx, size_t size), void *buf_ctx, size_t *size, pbool issource)
|
|
{
|
|
flocation_t loc;
|
|
if (FS_FLocateFile(path, FSLF_IFFOUND|FSLF_SECUREONLY, &loc))
|
|
{
|
|
qbyte *buffer = NULL;
|
|
vfsfile_t *file = FS_OpenReadLocation(&loc);
|
|
if (file)
|
|
{
|
|
*size = loc.len;
|
|
buffer = buf_get(buf_ctx, *size);
|
|
if (buffer)
|
|
VFS_READ(file, buffer, *size);
|
|
VFS_CLOSE(file);
|
|
}
|
|
return buffer;
|
|
}
|
|
else
|
|
{
|
|
if (FS_FLocateFile(path, FSLF_IFFOUND, &loc))
|
|
Con_Printf("Not loading %s because it comes from an untrusted source\n", path);
|
|
return NULL;
|
|
}
|
|
}
|
|
static int PDECL MP_PRFileSize (const char *path)
|
|
{
|
|
flocation_t loc;
|
|
if (FS_FLocateFile(path, FSLF_IFFOUND|FSLF_SECUREONLY, &loc))
|
|
return loc.len;
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
qboolean MP_Init (void)
|
|
{
|
|
struct key_cursor_s *m = &key_customcursor[kc_menuqc];
|
|
|
|
if (qrenderer == QR_NONE)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (forceqmenu.value)
|
|
{
|
|
Con_DPrintf("menu.dat disabled\n");
|
|
return false;
|
|
}
|
|
|
|
MP_SetupBuiltins();
|
|
|
|
memset(&menuc_eval, 0, sizeof(menuc_eval));
|
|
|
|
|
|
menuprogparms.progsversion = PROGSTRUCT_VERSION;
|
|
menuprogparms.ReadFile = MP_PRReadFile;//char *(*ReadFile) (char *fname, void *buffer, int *len);
|
|
menuprogparms.FileSize = MP_PRFileSize;//int (*FileSize) (char *fname); //-1 if file does not exist
|
|
menuprogparms.WriteFile = QC_WriteFile;//bool (*WriteFile) (char *name, void *data, int len);
|
|
menuprogparms.Printf = PR_Printf;//Con_Printf;//void (*printf) (char *, ...);
|
|
menuprogparms.DPrintf = PR_DPrintf;//Con_DPrintf;//void (*dprintf) (char *, ...);
|
|
menuprogparms.Sys_Error = Sys_Error;
|
|
menuprogparms.Abort = Menu_Abort;
|
|
menuprogparms.CheckHeaderCrc = Menu_CheckHeaderCrc;
|
|
menuprogparms.edictsize = sizeof(menuedict_t);
|
|
|
|
menuprogparms.entspawn = NULL;//void (*entspawn) (struct edict_s *ent); //ent has been spawned, but may not have all the extra variables (that may need to be set) set
|
|
menuprogparms.entcanfree = NULL;//bool (*entcanfree) (struct edict_s *ent); //return true to stop ent from being freed
|
|
menuprogparms.stateop = NULL;//StateOp;//void (*stateop) (float var, func_t func);
|
|
menuprogparms.cstateop = NULL;//CStateOp;
|
|
menuprogparms.cwstateop = NULL;//CWStateOp;
|
|
menuprogparms.thinktimeop = NULL;//ThinkTimeOp;
|
|
menuprogparms.MapNamedBuiltin = PR_Menu_MapNamedBuiltin;
|
|
menuprogparms.loadcompleate = NULL;//void (*loadcompleate) (int edictsize); //notification to reset any pointers.
|
|
|
|
menuprogparms.memalloc = PR_CB_Malloc;//void *(*memalloc) (int size); //small string allocation malloced and freed randomly
|
|
menuprogparms.memfree = PR_CB_Free;//void (*memfree) (void * mem);
|
|
|
|
|
|
menuprogparms.globalbuiltins = menu_builtins;//builtin_t *globalbuiltins; //these are available to all progs
|
|
menuprogparms.numglobalbuiltins = sizeof(menu_builtins) / sizeof(menu_builtins[0]);
|
|
|
|
menuprogparms.autocompile = PR_COMPILEIGNORE;//PR_COMPILEEXISTANDCHANGED;//enum {PR_NOCOMPILE, PR_COMPILENEXIST, PR_COMPILECHANGED, PR_COMPILEALWAYS} autocompile;
|
|
|
|
menuprogparms.gametime = &menutime;
|
|
#ifdef MULTITHREAD
|
|
menuprogparms.usethreadedgc = pr_gc_threaded.ival;
|
|
#endif
|
|
|
|
menuprogparms.edicts = (struct edict_s **)&menu_edicts;
|
|
menuprogparms.num_edicts = &num_menu_edicts;
|
|
|
|
menuprogparms.useeditor = QCEditor;//void (*useeditor) (char *filename, int line, int nump, char **parms);
|
|
menuprogparms.user = &menu_world;
|
|
menu_world.keydestmask = kdm_menu;
|
|
|
|
//default to free mouse+hidden cursor, to match dp's default setting, and because its generally the right thing for a menu.
|
|
Q_strncpyz(m->name, "none", sizeof(m->name));
|
|
m->hotspot[0] = 0;
|
|
m->hotspot[1] = 0;
|
|
m->scale = 1;
|
|
m->dirty = true;
|
|
|
|
menuqc.cursor = &key_customcursor[kc_menuqc];
|
|
menuqc.drawmenu = NULL; //menuqc sucks!
|
|
menuqc.mousemove = MP_MouseMove;
|
|
menuqc.keyevent = MP_KeyEvent;
|
|
menuqc.joyaxis = MP_JoystickAxis;
|
|
menuqc.release = MP_TryRelease;
|
|
|
|
menutime = Sys_DoubleTime();
|
|
if (!menu_world.progs)
|
|
{
|
|
int mprogs;
|
|
Con_DPrintf("Initializing menu.dat\n");
|
|
menu_world.progs = InitProgs(&menuprogparms);
|
|
PR_Configure(menu_world.progs, PR_ReadBytesString(pr_menu_memsize.string), 1, pr_enable_profiling.ival);
|
|
mprogs = PR_LoadProgs(menu_world.progs, "menu.dat");
|
|
if (mprogs < 0) //no per-progs builtins.
|
|
{
|
|
//failed to load or something
|
|
// CloseProgs(menu_world.progs);
|
|
// menuprogs = NULL;
|
|
return false;
|
|
}
|
|
if (setjmp(mp_abort))
|
|
{
|
|
Con_DPrintf("Failed to initialize menu.dat\n");
|
|
inmenuprogs = false;
|
|
return false;
|
|
}
|
|
inmenuprogs++;
|
|
|
|
M_DeInit_Internal();
|
|
|
|
PF_InitTempStrings(menu_world.progs);
|
|
|
|
menu_world.g.self = (int*)PR_FindGlobal(menu_world.progs, "self", 0, NULL);
|
|
menu_world.g.time = (float*)PR_FindGlobal(menu_world.progs, "time", 0, NULL);
|
|
if (menu_world.g.time)
|
|
*menu_world.g.time = Sys_DoubleTime();
|
|
menu_world.g.frametime = (float*)PR_FindGlobal(menu_world.progs, "frametime", 0, NULL);
|
|
|
|
menu_world.g.drawfont = (float*)PR_FindGlobal(menu_world.progs, "drawfont", 0, NULL);
|
|
menu_world.g.drawfontscale = (float*)PR_FindGlobal(menu_world.progs, "drawfontscale", 0, NULL);
|
|
|
|
PR_ProgsAdded(menu_world.progs, mprogs, "menu.dat");
|
|
|
|
//ensure that there's space for these fields in.
|
|
//other fields will always be referenced/defined by the qc, or 0.
|
|
PR_RegisterFieldVar(menu_world.progs, ev_string, "model", -1, -1);
|
|
PR_RegisterFieldVar(menu_world.progs, ev_vector, "origin", -1, -1);
|
|
PR_RegisterFieldVar(menu_world.progs, ev_float, "skinobject", -1, -1);
|
|
|
|
menuentsize = PR_InitEnts(menu_world.progs, 8192);
|
|
|
|
|
|
//'world' edict
|
|
// EDICT_NUM_PB(menu_world.progs, 0)->readonly = true;
|
|
EDICT_NUM_PB(menu_world.progs, 0)->ereftype = ER_ENTITY;
|
|
|
|
|
|
mpfuncs.init = PR_FindFunction(menu_world.progs, "m_init", PR_ANY);
|
|
mpfuncs.shutdown = PR_FindFunction(menu_world.progs, "m_shutdown", PR_ANY);
|
|
{
|
|
int args = 0;
|
|
qbyte *argsizes = NULL;
|
|
mpfuncs.draw = PR_FindFunction(menu_world.progs, "m_draw", PR_ANY);
|
|
menu_world.progs->GetFunctionInfo(menu_world.progs, mpfuncs.draw, &args, &argsizes, NULL, NULL, 0);
|
|
mpfuncs.fuckeddrawsizes = (args == 2 && argsizes[0] == 1 && argsizes[1] == 1);
|
|
}
|
|
mpfuncs.drawloading = PR_FindFunction(menu_world.progs, "m_drawloading", PR_ANY);
|
|
mpfuncs.inputevent = PR_FindFunction(menu_world.progs, "Menu_InputEvent", PR_ANY);
|
|
mpfuncs.keydown = PR_FindFunction(menu_world.progs, "m_keydown", PR_ANY);
|
|
mpfuncs.keyup = PR_FindFunction(menu_world.progs, "m_keyup", PR_ANY);
|
|
mpfuncs.toggle = PR_FindFunction(menu_world.progs, "m_toggle", PR_ANY);
|
|
mpfuncs.consolecommand = PR_FindFunction(menu_world.progs, "m_consolecommand", PR_ANY);
|
|
mpfuncs.gethostcachecategory = PR_FindFunction(menu_world.progs, "m_gethostcachecategory", PR_ANY);
|
|
mpfuncs.rendererrestarted = PR_FindFunction(menu_world.progs, "Menu_RendererRestarted", PR_ANY);
|
|
if (mpfuncs.init)
|
|
PR_ExecuteProgram(menu_world.progs, mpfuncs.init);
|
|
inmenuprogs--;
|
|
|
|
EDICT_NUM_PB(menu_world.progs, 0)->readonly = true;
|
|
|
|
Con_DPrintf("Initialized menu.dat\n");
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static void MP_GameCommand_f(void)
|
|
{
|
|
void *pr_globals;
|
|
func_t gamecommand;
|
|
if (!menu_world.progs)
|
|
return;
|
|
gamecommand = PR_FindFunction(menu_world.progs, "GameCommand", PR_ANY);
|
|
if (!gamecommand)
|
|
return;
|
|
|
|
if (setjmp(mp_abort))
|
|
return;
|
|
inmenuprogs++;
|
|
pr_globals = PR_globals(menu_world.progs, PR_CURRENT);
|
|
(((string_t *)pr_globals)[OFS_PARM0] = PR_TempString(menu_world.progs, Cmd_Args()));
|
|
PR_ExecuteProgram (menu_world.progs, gamecommand);
|
|
inmenuprogs--;
|
|
}
|
|
|
|
qboolean MP_ConsoleCommand(const char *cmdtext)
|
|
{
|
|
void *pr_globals;
|
|
if (!menu_world.progs)
|
|
return false;
|
|
if (!mpfuncs.consolecommand)
|
|
return false;
|
|
|
|
if (setjmp(mp_abort))
|
|
return true;
|
|
inmenuprogs++;
|
|
pr_globals = PR_globals(menu_world.progs, PR_CURRENT);
|
|
(((string_t *)pr_globals)[OFS_PARM0] = PR_TempString(menu_world.progs, cmdtext));
|
|
PR_ExecuteProgram (menu_world.progs, mpfuncs.consolecommand);
|
|
inmenuprogs--;
|
|
return G_FLOAT(OFS_RETURN);
|
|
}
|
|
|
|
void MP_CoreDump_f(void)
|
|
{
|
|
if (!menu_world.progs)
|
|
{
|
|
Con_Printf("Can't core dump, you need to be running the CSQC progs first.");
|
|
return;
|
|
}
|
|
|
|
{
|
|
size_t size = 1024*1024*8;
|
|
char *buffer = BZ_Malloc(size);
|
|
menu_world.progs->save_ents(menu_world.progs, buffer, &size, size, 3);
|
|
COM_WriteFile("menucore.txt", FS_GAMEONLY, buffer, size);
|
|
BZ_Free(buffer);
|
|
}
|
|
}
|
|
|
|
static void MP_Poke_f(void)
|
|
{
|
|
/*if (!SV_MayCheat())
|
|
Con_TPrintf ("Please set sv_cheats 1 and restart the map first.\n");
|
|
else */if (menu_world.progs && menu_world.progs->EvaluateDebugString)
|
|
Con_TPrintf("Result: %s\n", menu_world.progs->EvaluateDebugString(menu_world.progs, Cmd_Args()));
|
|
else
|
|
Con_TPrintf ("not supported.\n");
|
|
}
|
|
|
|
void MP_Breakpoint_f(void)
|
|
{
|
|
int wasset;
|
|
int isset;
|
|
char *filename = Cmd_Argv(1);
|
|
int line = atoi(Cmd_Argv(2));
|
|
|
|
if (!menu_world.progs)
|
|
{
|
|
Con_Printf("Menu not running\n");
|
|
return;
|
|
}
|
|
wasset = menu_world.progs->ToggleBreak(menu_world.progs, filename, line, 3);
|
|
isset = menu_world.progs->ToggleBreak(menu_world.progs, filename, line, 2);
|
|
|
|
if (wasset == isset)
|
|
Con_Printf("Breakpoint was not valid\n");
|
|
else if (isset)
|
|
Con_Printf("Breakpoint has been set\n");
|
|
else
|
|
Con_Printf("Breakpoint has been cleared\n");
|
|
|
|
Cvar_Set(Cvar_FindVar("pr_debugger"), "1");
|
|
}
|
|
|
|
void MP_RegisterCvarsAndCmds(void)
|
|
{
|
|
Cmd_AddCommand("coredump_menuqc", MP_CoreDump_f);
|
|
Cmd_AddCommand("menu_cmd", MP_GameCommand_f);
|
|
Cmd_AddCommand("breakpoint_menu", MP_Breakpoint_f);
|
|
#ifdef HAVE_LEGACY
|
|
Cmd_AddCommand("loadfont", CL_LoadFont_f);
|
|
#endif
|
|
|
|
Cmd_AddCommand("poke_menuqc", MP_Poke_f);
|
|
|
|
|
|
Cvar_Register(&forceqmenu, MENUPROGSGROUP);
|
|
Cvar_Register(&pr_menu_coreonerror, MENUPROGSGROUP);
|
|
Cvar_Register(&pr_menu_memsize, MENUPROGSGROUP);
|
|
|
|
if (COM_CheckParm("-qmenu"))
|
|
Cvar_Set(&forceqmenu, "1");
|
|
}
|
|
|
|
qboolean MP_UsingGamecodeLoadingScreen(void)
|
|
{
|
|
return menu_world.progs && mpfuncs.drawloading;
|
|
}
|
|
|
|
int MP_GetServerCategory(int index)
|
|
{
|
|
int category = 0;
|
|
if (menu_world.progs && mpfuncs.gethostcachecategory)
|
|
{
|
|
void *pr_globals = PR_globals(menu_world.progs, PR_CURRENT);
|
|
if (!setjmp(mp_abort))
|
|
{
|
|
inmenuprogs++;
|
|
G_FLOAT(OFS_PARM0) = index;
|
|
PR_ExecuteProgram(menu_world.progs, mpfuncs.gethostcachecategory);
|
|
category = G_FLOAT(OFS_RETURN);
|
|
inmenuprogs--;
|
|
}
|
|
}
|
|
return category;
|
|
}
|
|
|
|
void MP_RendererRestarted(void)
|
|
{
|
|
int i;
|
|
if (!menu_world.progs)
|
|
return;
|
|
|
|
menu_world.worldmodel = cl.worldmodel;
|
|
|
|
for (i = 0; i < MAX_CSMODELS; i++)
|
|
{
|
|
cl.model_csqcprecache[i] = NULL;
|
|
}
|
|
|
|
//FIXME: registered shaders
|
|
|
|
//let the csqc know that its rendertargets got purged
|
|
if (mpfuncs.rendererrestarted)
|
|
{
|
|
void *pr_globals = PR_globals(menu_world.progs, PR_CURRENT);
|
|
(((string_t *)pr_globals)[OFS_PARM0] = PR_TempString(menu_world.progs, rf->description));
|
|
PR_ExecuteProgram(menu_world.progs, mpfuncs.rendererrestarted);
|
|
}
|
|
//in case it drew to any render targets.
|
|
if (R2D_Flush)
|
|
R2D_Flush();
|
|
if (*r_refdef.rt_destcolour[0].texname)
|
|
{
|
|
Q_strncpyz(r_refdef.rt_destcolour[0].texname, "", sizeof(r_refdef.rt_destcolour[0].texname));
|
|
BE_RenderToTextureUpdate2d(true);
|
|
}
|
|
}
|
|
|
|
void MP_Draw(void)
|
|
{
|
|
extern qboolean scr_drawloading;
|
|
globalvars_t *pr_globals;
|
|
if (!menu_world.progs)
|
|
return;
|
|
if (setjmp(mp_abort))
|
|
return;
|
|
|
|
menutime = Sys_DoubleTime();
|
|
if (menu_world.g.time)
|
|
*menu_world.g.time = menutime;
|
|
if (menu_world.g.frametime)
|
|
*menu_world.g.frametime = host_frametime;
|
|
|
|
inmenuprogs++;
|
|
pr_globals = PR_globals(menu_world.progs, PR_CURRENT);
|
|
|
|
if (scr_drawloading||scr_disabled_for_loading)
|
|
{ //don't draw the menu if we're meant to be drawing a loading screen
|
|
//the menu should provide a special function if it wants to draw custom loading screens. this is for compat with old/dp/lazy/crappy menus.
|
|
if (mpfuncs.drawloading)
|
|
{
|
|
((float *)pr_globals)[OFS_PARM0+0] = vid.width;
|
|
((float *)pr_globals)[OFS_PARM0+1] = vid.height;
|
|
((float *)pr_globals)[OFS_PARM0+2] = 0;
|
|
|
|
((float *)pr_globals)[OFS_PARM1] = scr_disabled_for_loading;
|
|
PR_ExecuteProgram(menu_world.progs, mpfuncs.drawloading);
|
|
}
|
|
}
|
|
else if (mpfuncs.draw)
|
|
{
|
|
if (mpfuncs.fuckeddrawsizes)
|
|
{ //pass useless sizes in two args if its a dp menu
|
|
((float *)pr_globals)[OFS_PARM0] = vid.pixelwidth;
|
|
((float *)pr_globals)[OFS_PARM1] = vid.pixelheight;
|
|
}
|
|
else
|
|
{ //pass useful sizes in a 1-arg vector if its an fte menu.
|
|
((float *)pr_globals)[OFS_PARM0+0] = vid.width;
|
|
((float *)pr_globals)[OFS_PARM0+1] = vid.height;
|
|
((float *)pr_globals)[OFS_PARM0+2] = 0;
|
|
}
|
|
|
|
PR_ExecuteProgram(menu_world.progs, mpfuncs.draw);
|
|
}
|
|
inmenuprogs--;
|
|
}
|
|
|
|
qboolean MP_Toggle(int mode)
|
|
{
|
|
if (!menu_world.progs)
|
|
return false;
|
|
#ifdef TEXTEDITOR
|
|
if (editormodal)
|
|
return false;
|
|
#endif
|
|
|
|
if (!mode && !Key_Dest_Has(kdm_menu))
|
|
return false;
|
|
|
|
if (setjmp(mp_abort))
|
|
return false;
|
|
|
|
menutime = Sys_DoubleTime();
|
|
if (menu_world.g.time)
|
|
*menu_world.g.time = menutime;
|
|
|
|
inmenuprogs++;
|
|
if (mpfuncs.toggle)
|
|
{
|
|
void *pr_globals = PR_globals(menu_world.progs, PR_CURRENT);
|
|
G_FLOAT(OFS_PARM0) = mode;
|
|
PR_ExecuteProgram(menu_world.progs, mpfuncs.toggle);
|
|
}
|
|
if (R2D_Flush)
|
|
R2D_Flush();
|
|
inmenuprogs--;
|
|
|
|
return true;
|
|
}
|
|
#endif
|