#include "libcurl.h"
#include <time.h>
+#include "cl_collision.h"
+#include "clvm_cmds.h"
#include "ft2.h"
extern cvar_t prvm_backtraceforwarnings;
void VM_GenerateFrameGroupBlend(framegroupblend_t *framegroupblend, const prvm_edict_t *ed)
{
- prvm_eval_t *val;
// self.frame is the interpolation target (new frame)
// self.frame1time is the animation base time for the interpolation target
// self.frame2 is the interpolation start (previous frame)
// self.lerpfrac4 is the interpolation strength for self.frame4
// pitch angle on a player model where the animator set up 5 sets of
// animations and the csqc simply lerps between sets)
- if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame))) framegroupblend[0].frame = (int) val->_float;
- if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame2))) framegroupblend[1].frame = (int) val->_float;
- if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame3))) framegroupblend[2].frame = (int) val->_float;
- if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame4))) framegroupblend[3].frame = (int) val->_float;
- if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame1time))) framegroupblend[0].start = val->_float;
- if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame2time))) framegroupblend[1].start = val->_float;
- if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame3time))) framegroupblend[2].start = val->_float;
- if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame4time))) framegroupblend[3].start = val->_float;
- if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.lerpfrac))) framegroupblend[1].lerp = val->_float;
- if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.lerpfrac3))) framegroupblend[2].lerp = val->_float;
- if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.lerpfrac4))) framegroupblend[3].lerp = val->_float;
+ framegroupblend[0].frame = (int) PRVM_gameedictfloat(ed, frame );
+ framegroupblend[1].frame = (int) PRVM_gameedictfloat(ed, frame2 );
+ framegroupblend[2].frame = (int) PRVM_gameedictfloat(ed, frame3 );
+ framegroupblend[3].frame = (int) PRVM_gameedictfloat(ed, frame4 );
+ framegroupblend[0].start = PRVM_gameedictfloat(ed, frame1time);
+ framegroupblend[1].start = PRVM_gameedictfloat(ed, frame2time);
+ framegroupblend[2].start = PRVM_gameedictfloat(ed, frame3time);
+ framegroupblend[3].start = PRVM_gameedictfloat(ed, frame4time);
+ framegroupblend[1].lerp = PRVM_gameedictfloat(ed, lerpfrac );
+ framegroupblend[2].lerp = PRVM_gameedictfloat(ed, lerpfrac3 );
+ framegroupblend[3].lerp = PRVM_gameedictfloat(ed, lerpfrac4 );
// assume that the (missing) lerpfrac1 is whatever remains after lerpfrac2+lerpfrac3+lerpfrac4 are summed
framegroupblend[0].lerp = 1 - framegroupblend[1].lerp - framegroupblend[2].lerp - framegroupblend[3].lerp;
}
VM_RemoveEdictSkeleton(ed);
ed->priv.server->skeleton.model = edmodel;
}
- if (!ed->priv.server->skeleton.relativetransforms && ed->priv.server->skeleton.model && ed->priv.server->skeleton.model->num_bones)
- ed->priv.server->skeleton.relativetransforms = Mem_Alloc(prog->progs_mempool, ed->priv.server->skeleton.model->num_bones * sizeof(matrix4x4_t));
- if (ed->priv.server->skeleton.relativetransforms)
+ if (!ed->priv.server->skeleton.model || !ed->priv.server->skeleton.model->num_bones)
{
- int skeletonindex = 0;
+ if(ed->priv.server->skeleton.relativetransforms)
+ Mem_Free(ed->priv.server->skeleton.relativetransforms);
+ ed->priv.server->skeleton.relativetransforms = NULL;
+ return;
+ }
+
+ {
+ int skeletonindex = -1;
skeleton_t *skeleton;
- prvm_eval_t *val;
- if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.skeletonindex))) skeletonindex = (int)val->_float;
- if (skeletonindex > 0 && skeletonindex < MAX_EDICTS && (skeleton = prog->skeletons[skeletonindex]) && skeleton->model->num_bones == ed->priv.server->skeleton.model->num_bones)
+ skeletonindex = (int)PRVM_gameedictfloat(ed, skeletonindex) - 1;
+ if (skeletonindex >= 0 && skeletonindex < MAX_EDICTS && (skeleton = prog->skeletons[skeletonindex]) && skeleton->model->num_bones == ed->priv.server->skeleton.model->num_bones)
{
// custom skeleton controlled by the game (FTE_CSQC_SKELETONOBJECTS)
+ if (!ed->priv.server->skeleton.relativetransforms)
+ ed->priv.server->skeleton.relativetransforms = (matrix4x4_t *)Mem_Alloc(prog->progs_mempool, ed->priv.server->skeleton.model->num_bones * sizeof(matrix4x4_t));
memcpy(ed->priv.server->skeleton.relativetransforms, skeleton->relativetransforms, ed->priv.server->skeleton.model->num_bones * sizeof(matrix4x4_t));
}
else
{
- // generated skeleton from frame animation
- int blendindex;
- int bonenum;
- int numbones = ed->priv.server->skeleton.model->num_bones;
- const float *poses = ed->priv.server->skeleton.model->data_poses;
- const float *framebones;
- float lerp;
- matrix4x4_t *relativetransforms = ed->priv.server->skeleton.relativetransforms;
- matrix4x4_t matrix;
- memset(relativetransforms, 0, numbones * sizeof(matrix4x4_t));
- for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++)
- {
- lerp = frameblend[blendindex].lerp;
- framebones = poses + 12 * frameblend[blendindex].subframe * numbones;
- for (bonenum = 0;bonenum < numbones;bonenum++)
- {
- Matrix4x4_FromArray12FloatD3D(&matrix, framebones + 12 * bonenum);
- Matrix4x4_Accumulate(&ed->priv.server->skeleton.relativetransforms[bonenum], &matrix, lerp);
- }
- }
+ if(ed->priv.server->skeleton.relativetransforms)
+ Mem_Free(ed->priv.server->skeleton.relativetransforms);
+ ed->priv.server->skeleton.relativetransforms = NULL;
}
}
}
static qboolean checkextension(const char *name)
{
int len;
- char *e, *start;
+ const char *e, *start;
len = (int)strlen(name);
for (e = prog->extensionstring;*e;e++)
while (*e && *e != ' ')
e++;
if ((e - start) == len && !strncasecmp(start, name, len))
+ {
+ // special sheck for ODE
+ if (!strncasecmp("DP_PHYSICS_ODE", name, 14))
+ {
+#ifdef USEODE
+ return ode_dll ? true : false;
+#else
+ return false;
+#endif
+ }
return true;
+ }
}
return false;
}
VM_VarString(0, string, sizeof(string));
Con_Printf("======%s ERROR in %s:\n%s\n", PRVM_NAME, PRVM_GetString(prog->xfunction->s_name), string);
- if (prog->globaloffsets.self >= 0)
- {
- ed = PRVM_PROG_TO_EDICT(PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict);
- PRVM_ED_Print(ed, NULL);
- }
+ ed = PRVM_PROG_TO_EDICT(PRVM_allglobaledict(self));
+ PRVM_ED_Print(ed, NULL);
PRVM_ERROR ("%s: Program error in function %s:\n%s\nTip: read above for entity information\n", PRVM_NAME, PRVM_GetString(prog->xfunction->s_name), string);
}
VM_VarString(0, string, sizeof(string));
Con_Printf("======OBJECT ERROR======\n"); // , PRVM_NAME, PRVM_GetString(prog->xfunction->s_name), string); // or include them? FIXME
- if (prog->globaloffsets.self >= 0)
- {
- ed = PRVM_PROG_TO_EDICT(PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict);
- PRVM_ED_Print(ed, NULL);
-
- PRVM_ED_Free (ed);
- }
- else
- // objerror has to display the object fields -> else call
- PRVM_ERROR ("VM_objecterror: self not defined !");
+ ed = PRVM_PROG_TO_EDICT(PRVM_allglobaledict(self));
+ PRVM_ED_Print(ed, NULL);
+ PRVM_ED_Free (ed);
Con_Printf("%s OBJECT ERROR in %s:\n%s\nTip: read above for entity information\n", PRVM_NAME, PRVM_GetString(prog->xfunction->s_name), string);
}
VM_SAFEPARMCOUNT(1, VM_ftoe);
ent = (int)PRVM_G_FLOAT(OFS_PARM0);
- if (ent < 0 || ent >= MAX_EDICTS || PRVM_PROG_TO_EDICT(ent)->priv.required->free)
+ if (ent < 0 || ent >= prog->max_edicts || PRVM_PROG_TO_EDICT(ent)->priv.required->free)
ent = 0; // return world instead of a free or invalid entity
PRVM_G_INT(OFS_RETURN) = ent;
ed = PRVM_G_EDICT(OFS_PARM0);
if( PRVM_NUM_FOR_EDICT(ed) <= prog->reserved_edicts )
{
- if (developer.integer)
+ if (developer.integer > 0)
VM_Warning( "VM_remove: tried to remove the null entity or a reserved entity!\n" );
}
else if( ed->priv.required->free )
{
- if (developer.integer)
+ if (developer.integer > 0)
VM_Warning( "VM_remove: tried to remove an already freed entity!\n" );
}
else
if (strcmp(t,s))
continue;
- PRVM_EDICTFIELDVALUE(ent,chainfield)->edict = PRVM_NUM_FOR_EDICT(chain);
+ PRVM_EDICTFIELDEDICT(ent,chainfield) = PRVM_NUM_FOR_EDICT(chain);
chain = ent;
}
if (PRVM_E_FLOAT(ent,f) != s)
continue;
- PRVM_EDICTFIELDVALUE(ent,chainfield)->edict = PRVM_EDICT_TO_PROG(chain);
+ PRVM_EDICTFIELDEDICT(ent,chainfield) = PRVM_EDICT_TO_PROG(chain);
chain = ent;
}
if (!((int)PRVM_E_FLOAT(ent,f) & s))
continue;
- PRVM_EDICTFIELDVALUE(ent,chainfield)->edict = PRVM_EDICT_TO_PROG(chain);
+ PRVM_EDICTFIELDEDICT(ent,chainfield) = PRVM_EDICT_TO_PROG(chain);
chain = ent;
}
*/
void VM_numentityfields(void)
{
- PRVM_G_FLOAT(OFS_RETURN) = prog->progs->numfielddefs;
+ PRVM_G_FLOAT(OFS_RETURN) = prog->numfielddefs;
}
// KrimZon - DP_QC_ENTITYDATA
ddef_t *d;
int i = (int)PRVM_G_FLOAT(OFS_PARM0);
- if (i < 0 || i >= prog->progs->numfielddefs)
+ if (i < 0 || i >= prog->numfielddefs)
{
VM_Warning("VM_entityfieldname: %s: field index out of bounds\n", PRVM_NAME);
PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString("");
ddef_t *d;
int i = (int)PRVM_G_FLOAT(OFS_PARM0);
- if (i < 0 || i >= prog->progs->numfielddefs)
+ if (i < 0 || i >= prog->numfielddefs)
{
VM_Warning("VM_entityfieldtype: %s: field index out of bounds\n", PRVM_NAME);
PRVM_G_FLOAT(OFS_RETURN) = -1.0;
prvm_edict_t * ent;
int i = (int)PRVM_G_FLOAT(OFS_PARM0);
- if (i < 0 || i >= prog->progs->numfielddefs)
+ if (i < 0 || i >= prog->numfielddefs)
{
VM_Warning("VM_entityfielddata: %s: field index out of bounds\n", PRVM_NAME);
PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString("");
prvm_edict_t * ent;
int i = (int)PRVM_G_FLOAT(OFS_PARM0);
- if (i < 0 || i >= prog->progs->numfielddefs)
+ if (i < 0 || i >= prog->numfielddefs)
{
VM_Warning("VM_entityfielddata: %s: field index out of bounds\n", PRVM_NAME);
PRVM_G_FLOAT(OFS_RETURN) = 0.0f;
subject_len = (int)strlen(subject);
si = 0;
- for (i = 0; i < subject_len; i++)
+ for (i = 0; i <= subject_len - search_len; i++)
{
- for (j = 0; j < search_len && i+j < subject_len; j++)
+ for (j = 0; j < search_len; j++) // thus, i+j < subject_len
if (subject[i+j] != search[j])
break;
- if (j == search_len || i+j == subject_len)
+ if (j == search_len)
{
- // found it at offset 'i'
+ // NOTE: if search_len == 0, we always hit THIS case, and never the other
+ // found it at offset 'i'
for (j = 0; j < replace_len && si < (int)sizeof(string) - 1; j++)
string[si++] = replace[j];
- i += search_len - 1;
+ if(search_len > 0)
+ {
+ i += search_len - 1;
+ }
+ else
+ {
+ // the above would subtract 1 from i... so we
+ // don't do that, but instead output the next
+ // char
+ if (si < (int)sizeof(string) - 1)
+ string[si++] = subject[i];
+ }
}
else
{
- // not found
+ // in THIS case, we know search_len > 0, thus i < subject_len
+ // not found
if (si < (int)sizeof(string) - 1)
string[si++] = subject[i];
}
}
+ // remaining chars (these cannot match)
+ for (; i < subject_len; i++)
+ if (si < (int)sizeof(string) - 1)
+ string[si++] = subject[i];
string[si] = '\0';
PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(string);
subject_len = (int)strlen(subject);
si = 0;
- for (i = 0; i < subject_len; i++)
+ for (i = 0; i <= subject_len - search_len; i++)
{
- for (j = 0; j < search_len && i+j < subject_len; j++)
+ for (j = 0; j < search_len; j++) // thus, i+j < subject_len
if (tolower(subject[i+j]) != tolower(search[j]))
break;
- if (j == search_len || i+j == subject_len)
+ if (j == search_len)
{
- // found it at offset 'i'
+ // NOTE: if search_len == 0, we always hit THIS case, and never the other
+ // found it at offset 'i'
for (j = 0; j < replace_len && si < (int)sizeof(string) - 1; j++)
string[si++] = replace[j];
- i += search_len - 1;
+ if(search_len > 0)
+ {
+ i += search_len - 1;
+ }
+ else
+ {
+ // the above would subtract 1 from i... so we
+ // don't do that, but instead output the next
+ // char
+ if (si < (int)sizeof(string) - 1)
+ string[si++] = subject[i];
+ }
}
else
{
- // not found
+ // in THIS case, we know search_len > 0, thus i < subject_len
+ // not found
if (si < (int)sizeof(string) - 1)
string[si++] = subject[i];
}
}
+ // remaining chars (these cannot match)
+ for (; i < subject_len; i++)
+ if (si < (int)sizeof(string) - 1)
+ string[si++] = subject[i];
string[si] = '\0';
PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(string);
}
}
+/*
+=========
+VM_getsoundtime
+
+float getsoundtime(void)
+=========
+*/
+
+void VM_getsoundtime (void)
+{
+ int entnum, entchannel, pnum;
+ VM_SAFEPARMCOUNT(2,VM_getsoundtime);
+
+ pnum = PRVM_GetProgNr();
+ if (pnum == PRVM_MENUPROG)
+ {
+ VM_Warning("VM_getsoundtime: %s: not supported on this progs\n", PRVM_NAME);
+ PRVM_G_FLOAT(OFS_RETURN) = -1;
+ return;
+ }
+ entnum = ((pnum == PRVM_CLIENTPROG) ? MAX_EDICTS : 0) + PRVM_NUM_FOR_EDICT(PRVM_G_EDICT(OFS_PARM0));
+ entchannel = (int)PRVM_G_FLOAT(OFS_PARM1);
+ if (entchannel <= 0 || entchannel > 8)
+ VM_Warning("VM_getsoundtime: %s: bad channel %i\n", PRVM_NAME, entchannel);
+ PRVM_G_FLOAT(OFS_RETURN) = (float)S_GetEntChannelPosition(entnum, entchannel);
+}
+
+/*
+=========
+VM_GetSoundLen
+
+string soundlength (string sample)
+=========
+*/
+void VM_soundlength (void)
+{
+ const char *s;
+
+ VM_SAFEPARMCOUNT(1, VM_soundlength);
+
+ s = PRVM_G_STRING(OFS_PARM0);
+ PRVM_G_FLOAT(OFS_RETURN) = S_SoundLength(s);
+}
+
/*
=========
VM_loadfromdata
VM_CheckEmptyString (s);
// AK Draw_CachePic is supposed to always return a valid pointer
- if( Draw_CachePic_Flags(s, CACHEPICFLAG_NOTPERSISTENT)->tex == r_texture_notexture )
+ if( Draw_CachePic_Flags(s, 0)->tex == r_texture_notexture )
PRVM_G_INT(OFS_RETURN) = OFS_NULL;
}
{
vec3_t v;
*sx = *sy = 1;
- if(prog->globaloffsets.drawfontscale >= 0)
+ VectorCopy(PRVM_drawglobalvector(drawfontscale), v);
+ if(VectorLength2(v) > 0)
{
- VectorCopy(PRVM_G_VECTOR(prog->globaloffsets.drawfontscale), v);
- if(VectorLength2(v) > 0)
- {
- *sx = v[0];
- *sy = v[1];
- }
+ *sx = v[0];
+ *sy = v[1];
}
}
dp_font_t *getdrawfont(void)
{
- if(prog->globaloffsets.drawfont >= 0)
- {
- int f = (int) PRVM_G_FLOAT(prog->globaloffsets.drawfont);
- if(f < 0 || f >= MAX_FONTS)
- return FONT_DEFAULT;
- return &dp_fonts[f];
- }
- else
+ int f = (int) PRVM_drawglobalfloat(drawfont);
+ if(f < 0 || f >= dp_fonts.maxsize)
return FONT_DEFAULT;
+ return &dp_fonts.f[f];
}
/*
VM_drawcolorcodedstring
float drawcolorcodedstring(vector position, string text, vector scale, float alpha, float flag)
+/
+float drawcolorcodedstring(vector position, string text, vector scale, vector rgb, float alpha, float flag)
=========
*/
void VM_drawcolorcodedstring(void)
{
- float *pos,*scale;
+ float *pos, *scale;
const char *string;
- int flag,color;
- float sx, sy;
- VM_SAFEPARMCOUNT(5,VM_drawstring);
+ int flag;
+ vec3_t rgb;
+ float sx, sy, alpha;
- string = PRVM_G_STRING(OFS_PARM1);
- pos = PRVM_G_VECTOR(OFS_PARM0);
- scale = PRVM_G_VECTOR(OFS_PARM2);
- flag = (int)PRVM_G_FLOAT(OFS_PARM4);
+ VM_SAFEPARMCOUNTRANGE(5,6,VM_drawcolorcodedstring);
- if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
+ if (prog->argc == 6) // full 6 parms, like normal drawstring
+ {
+ pos = PRVM_G_VECTOR(OFS_PARM0);
+ string = PRVM_G_STRING(OFS_PARM1);
+ scale = PRVM_G_VECTOR(OFS_PARM2);
+ VectorCopy(PRVM_G_VECTOR(OFS_PARM3), rgb);
+ alpha = PRVM_G_FLOAT(OFS_PARM4);
+ flag = (int)PRVM_G_FLOAT(OFS_PARM5);
+ }
+ else
+ {
+ pos = PRVM_G_VECTOR(OFS_PARM0);
+ string = PRVM_G_STRING(OFS_PARM1);
+ scale = PRVM_G_VECTOR(OFS_PARM2);
+ rgb[0] = 1.0;
+ rgb[1] = 1.0;
+ rgb[2] = 1.0;
+ alpha = PRVM_G_FLOAT(OFS_PARM3);
+ flag = (int)PRVM_G_FLOAT(OFS_PARM4);
+ }
+
+ if(flag < DRAWFLAG_NORMAL || flag >= DRAWFLAG_NUMFLAGS)
{
PRVM_G_FLOAT(OFS_RETURN) = -2;
VM_Warning("VM_drawcolorcodedstring: %s: wrong DRAWFLAG %i !\n",PRVM_NAME,flag);
if(pos[2] || scale[2])
Con_Printf("VM_drawcolorcodedstring: z value%s from %s discarded\n",(pos[2] && scale[2]) ? "s" : " ",((pos[2] && scale[2]) ? "pos and scale" : (pos[2] ? "pos" : "scale")));
- color = -1;
getdrawfontscale(&sx, &sy);
- DrawQ_String_Scale(pos[0], pos[1], string, 0, scale[0], scale[1], sx, sy, 1, 1, 1, PRVM_G_FLOAT(OFS_PARM3), flag, NULL, false, getdrawfont());
- PRVM_G_FLOAT(OFS_RETURN) = 1;
+ DrawQ_String_Scale(pos[0], pos[1], string, 0, scale[0], scale[1], sx, sy, rgb[0], rgb[1], rgb[2], alpha, flag, NULL, false, getdrawfont());
+ if (prog->argc == 6) // also return vector of last color
+ VectorCopy(DrawQ_Color, PRVM_G_VECTOR(OFS_RETURN));
+ else
+ PRVM_G_FLOAT(OFS_RETURN) = 1;
}
/*
=========
PRVM_G_FLOAT(OFS_RETURN) = DrawQ_TextWidth(string, 0, !colors, getdrawfont()) * mult; // 1x1 characters, don't actually draw
*/
+}
+/*
+=========
+VM_findfont
+
+float findfont(string s)
+=========
+*/
+
+float getdrawfontnum(const char *fontname)
+{
+ int i;
+
+ for(i = 0; i < dp_fonts.maxsize; ++i)
+ if(!strcmp(dp_fonts.f[i].title, fontname))
+ return i;
+ return -1;
}
+
+void VM_findfont(void)
+{
+ VM_SAFEPARMCOUNT(1,VM_findfont);
+ PRVM_G_FLOAT(OFS_RETURN) = getdrawfontnum(PRVM_G_STRING(OFS_PARM0));
+}
+
+/*
+=========
+VM_loadfont
+
+float loadfont(string fontname, string fontmaps, string sizes, float slot)
+=========
+*/
+
+dp_font_t *FindFont(const char *title, qboolean allocate_new);
+void LoadFont(qboolean override, const char *name, dp_font_t *fnt, float scale, float voffset);
+void VM_loadfont(void)
+{
+ const char *fontname, *filelist, *sizes, *c, *cm;
+ char mainfont[MAX_QPATH];
+ int i, numsizes;
+ float sz, scale, voffset;
+ dp_font_t *f;
+
+ VM_SAFEPARMCOUNTRANGE(3,6,VM_loadfont);
+
+ fontname = PRVM_G_STRING(OFS_PARM0);
+ if (!fontname[0])
+ fontname = "default";
+
+ filelist = PRVM_G_STRING(OFS_PARM1);
+ if (!filelist[0])
+ filelist = "gfx/conchars";
+
+ sizes = PRVM_G_STRING(OFS_PARM2);
+ if (!sizes[0])
+ sizes = "10";
+
+ // find a font
+ f = NULL;
+ if (prog->argc >= 4)
+ {
+ i = PRVM_G_FLOAT(OFS_PARM3);
+ if (i >= 0 && i < dp_fonts.maxsize)
+ {
+ f = &dp_fonts.f[i];
+ strlcpy(f->title, fontname, sizeof(f->title)); // replace name
+ }
+ }
+ if (!f)
+ f = FindFont(fontname, true);
+ if (!f)
+ {
+ PRVM_G_FLOAT(OFS_RETURN) = -1;
+ return; // something go wrong
+ }
+
+ memset(f->fallbacks, 0, sizeof(f->fallbacks));
+ memset(f->fallback_faces, 0, sizeof(f->fallback_faces));
+
+ // first font is handled "normally"
+ c = strchr(filelist, ':');
+ cm = strchr(filelist, ',');
+ if(c && (!cm || c < cm))
+ f->req_face = atoi(c+1);
+ else
+ {
+ f->req_face = 0;
+ c = cm;
+ }
+ if(!c || (c - filelist) > MAX_QPATH)
+ strlcpy(mainfont, filelist, sizeof(mainfont));
+ else
+ {
+ memcpy(mainfont, filelist, c - filelist);
+ mainfont[c - filelist] = 0;
+ }
+
+ // handle fallbacks
+ for(i = 0; i < MAX_FONT_FALLBACKS; ++i)
+ {
+ c = strchr(filelist, ',');
+ if(!c)
+ break;
+ filelist = c + 1;
+ if(!*filelist)
+ break;
+ c = strchr(filelist, ':');
+ cm = strchr(filelist, ',');
+ if(c && (!cm || c < cm))
+ f->fallback_faces[i] = atoi(c+1);
+ else
+ {
+ f->fallback_faces[i] = 0; // f->req_face; could make it stick to the default-font's face index
+ c = cm;
+ }
+ if(!c || (c-filelist) > MAX_QPATH)
+ {
+ strlcpy(f->fallbacks[i], filelist, sizeof(mainfont));
+ }
+ else
+ {
+ memcpy(f->fallbacks[i], filelist, c - filelist);
+ f->fallbacks[i][c - filelist] = 0;
+ }
+ }
+
+ // handle sizes
+ for(i = 0; i < MAX_FONT_SIZES; ++i)
+ f->req_sizes[i] = -1;
+ for (numsizes = 0,c = sizes;;)
+ {
+ if (!COM_ParseToken_VM_Tokenize(&c, 0))
+ break;
+ sz = atof(com_token);
+ // detect crap size
+ if (sz < 0.001f || sz > 1000.0f)
+ {
+ VM_Warning("VM_loadfont: crap size %s", com_token);
+ continue;
+ }
+ // check overflow
+ if (numsizes == MAX_FONT_SIZES)
+ {
+ VM_Warning("VM_loadfont: MAX_FONT_SIZES = %i exceeded", MAX_FONT_SIZES);
+ break;
+ }
+ f->req_sizes[numsizes] = sz;
+ numsizes++;
+ }
+
+ // additional scale/hoffset parms
+ scale = 1;
+ voffset = 0;
+ if (prog->argc >= 5)
+ {
+ scale = PRVM_G_FLOAT(OFS_PARM4);
+ if (scale <= 0)
+ scale = 1;
+ }
+ if (prog->argc >= 6)
+ voffset = PRVM_G_FLOAT(OFS_PARM5);
+
+ // load
+ LoadFont(true, mainfont, f, scale, voffset);
+
+ // return index of loaded font
+ PRVM_G_FLOAT(OFS_RETURN) = (f - dp_fonts.f);
+}
+
/*
=========
VM_drawpic
if(pos[2] || size[2])
Con_Printf("VM_drawpic: z value%s from %s discarded\n",(pos[2] && size[2]) ? "s" : " ",((pos[2] && size[2]) ? "pos and size" : (pos[2] ? "pos" : "size")));
- DrawQ_Pic(pos[0], pos[1], Draw_CachePic (picname), size[0], size[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM4), flag);
+ DrawQ_Pic(pos[0], pos[1], Draw_CachePic_Flags (picname, CACHEPICFLAG_NOTPERSISTENT), size[0], size[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM4), flag);
PRVM_G_FLOAT(OFS_RETURN) = 1;
}
/*
if(pos[2] || size[2] || org[2])
Con_Printf("VM_drawrotpic: z value from pos/size/org discarded\n");
- DrawQ_RotPic(pos[0], pos[1], Draw_CachePic(picname), size[0], size[1], org[0], org[1], PRVM_G_FLOAT(OFS_PARM4), rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM6), flag);
+ DrawQ_RotPic(pos[0], pos[1], Draw_CachePic_Flags(picname, CACHEPICFLAG_NOTPERSISTENT), size[0], size[1], org[0], org[1], PRVM_G_FLOAT(OFS_PARM4), rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM6), flag);
PRVM_G_FLOAT(OFS_RETURN) = 1;
}
/*
if(pos[2] || size[2])
Con_Printf("VM_drawsubpic: z value%s from %s discarded\n",(pos[2] && size[2]) ? "s" : " ",((pos[2] && size[2]) ? "pos and size" : (pos[2] ? "pos" : "size")));
- DrawQ_SuperPic(pos[0], pos[1], Draw_CachePic (picname),
+ DrawQ_SuperPic(pos[0], pos[1], Draw_CachePic_Flags (picname, CACHEPICFLAG_NOTPERSISTENT),
size[0], size[1],
srcPos[0], srcPos[1], rgb[0], rgb[1], rgb[2], alpha,
srcPos[0] + srcSize[0], srcPos[1], rgb[0], rgb[1], rgb[2], alpha,
=========
VM_findkeysforcommand
-string findkeysforcommand(string command)
+string findkeysforcommand(string command, float bindmap)
the returned string is an altstring
=========
*/
-#define NUMKEYS 5 // TODO: merge the constant in keys.c with this one somewhen
-
+#define FKFC_NUMKEYS 5
void M_FindKeysForCommand(const char *command, int *keys);
void VM_findkeysforcommand(void)
{
const char *cmd;
char ret[VM_STRINGTEMP_LENGTH];
- int keys[NUMKEYS];
+ int keys[FKFC_NUMKEYS];
int i;
+ int bindmap;
- VM_SAFEPARMCOUNT(1, VM_findkeysforcommand);
+ VM_SAFEPARMCOUNTRANGE(1, 2, VM_findkeysforcommand);
cmd = PRVM_G_STRING(OFS_PARM0);
+ if(prog->argc == 2)
+ bindmap = bound(-1, PRVM_G_FLOAT(OFS_PARM1), MAX_BINDMAPS-1);
+ else
+ bindmap = 0; // consistent to "bind"
VM_CheckEmptyString(cmd);
- M_FindKeysForCommand(cmd, keys);
+ Key_FindKeysForCommand(cmd, keys, FKFC_NUMKEYS, bindmap);
ret[0] = 0;
- for(i = 0; i < NUMKEYS; i++)
+ for(i = 0; i < FKFC_NUMKEYS; i++)
strlcat(ret, va(" \'%i\'", keys[i]), sizeof(ret));
PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(ret);
{
VM_SAFEPARMCOUNT( 1, VM_keynumtostring );
- PRVM_G_INT(OFS_RETURN) = Key_StringToKeynum(PRVM_G_STRING(OFS_PARM0));
+ PRVM_G_FLOAT(OFS_RETURN) = Key_StringToKeynum(PRVM_G_STRING(OFS_PARM0));
+}
+
+/*
+=========
+VM_getkeybind
+
+string getkeybind(float key, float bindmap)
+=========
+*/
+void VM_getkeybind (void)
+{
+ int bindmap;
+ VM_SAFEPARMCOUNTRANGE(1, 2, VM_CL_getkeybind);
+ if(prog->argc == 2)
+ bindmap = bound(-1, PRVM_G_FLOAT(OFS_PARM1), MAX_BINDMAPS-1);
+ else
+ bindmap = 0; // consistent to "bind"
+
+ PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(Key_GetBind((int)PRVM_G_FLOAT(OFS_PARM0), bindmap));
+}
+
+/*
+=========
+VM_setkeybind
+
+float setkeybind(float key, string cmd, float bindmap)
+=========
+*/
+void VM_setkeybind (void)
+{
+ int bindmap;
+ VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_setkeybind);
+ if(prog->argc == 3)
+ bindmap = bound(-1, PRVM_G_FLOAT(OFS_PARM2), MAX_BINDMAPS-1);
+ else
+ bindmap = 0; // consistent to "bind"
+
+ PRVM_G_FLOAT(OFS_RETURN) = 0;
+ if(Key_SetBinding((int)PRVM_G_FLOAT(OFS_PARM0), bindmap, PRVM_G_STRING(OFS_PARM1)))
+ PRVM_G_FLOAT(OFS_RETURN) = 1;
+}
+
+/*
+=========
+VM_getbindmap
+
+vector getbindmaps()
+=========
+*/
+void VM_getbindmaps (void)
+{
+ int fg, bg;
+ VM_SAFEPARMCOUNT(0, VM_CL_getbindmap);
+ Key_GetBindMap(&fg, &bg);
+ PRVM_G_VECTOR(OFS_RETURN)[0] = fg;
+ PRVM_G_VECTOR(OFS_RETURN)[1] = bg;
+ PRVM_G_VECTOR(OFS_RETURN)[2] = 0;
+}
+
+/*
+=========
+VM_setbindmap
+
+float setbindmaps(vector bindmap)
+=========
+*/
+void VM_setbindmaps (void)
+{
+ VM_SAFEPARMCOUNT(1, VM_CL_setbindmap);
+ PRVM_G_FLOAT(OFS_RETURN) = 0;
+ if(PRVM_G_VECTOR(OFS_PARM0)[2] == 0)
+ if(Key_SetBindMap((int)PRVM_G_VECTOR(OFS_PARM0)[0], (int)PRVM_G_VECTOR(OFS_PARM0)[1]))
+ PRVM_G_FLOAT(OFS_RETURN) = 1;
}
// CL_Video interface functions
VM_CheckEmptyString( file );
VM_CheckEmptyString( name );
- if( CL_OpenVideo( file, name, MENUOWNER ) )
+ if( CL_OpenVideo( file, name, MENUOWNER, "" ) )
PRVM_G_FLOAT( OFS_RETURN ) = 1;
else
PRVM_G_FLOAT( OFS_RETURN ) = 0;
*/
void VM_makevectors (void)
{
- prvm_eval_t *valforward, *valright, *valup;
- valforward = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.v_forward);
- valright = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.v_right);
- valup = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.v_up);
- if (!valforward || !valright || !valup)
- {
- VM_Warning("makevectors: could not find v_forward, v_right, or v_up global variables\n");
- return;
- }
VM_SAFEPARMCOUNT(1, VM_makevectors);
- AngleVectors (PRVM_G_VECTOR(OFS_PARM0), valforward->vector, valright->vector, valup->vector);
+ AngleVectors(PRVM_G_VECTOR(OFS_PARM0), PRVM_gameglobalvector(v_forward), PRVM_gameglobalvector(v_right), PRVM_gameglobalvector(v_up));
}
/*
*/
void VM_vectorvectors (void)
{
- prvm_eval_t *valforward, *valright, *valup;
- valforward = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.v_forward);
- valright = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.v_right);
- valup = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.v_up);
- if (!valforward || !valright || !valup)
- {
- VM_Warning("vectorvectors: could not find v_forward, v_right, or v_up global variables\n");
- return;
- }
VM_SAFEPARMCOUNT(1, VM_vectorvectors);
- VectorNormalize2(PRVM_G_VECTOR(OFS_PARM0), valforward->vector);
- VectorVectors(valforward->vector, valright->vector, valup->vector);
+ VectorNormalize2(PRVM_G_VECTOR(OFS_PARM0), PRVM_gameglobalvector(v_forward));
+ VectorVectors(PRVM_gameglobalvector(v_forward), PRVM_gameglobalvector(v_right), PRVM_gameglobalvector(v_up));
}
/*
void VM_altstr_ins(void)
{
int num;
- const char *setstr;
const char *set;
- const char *instr;
const char *in;
char *out;
char outstr[VM_STRINGTEMP_LENGTH];
VM_SAFEPARMCOUNT(3, VM_altstr_ins);
- in = instr = PRVM_G_STRING( OFS_PARM0 );
+ in = PRVM_G_STRING( OFS_PARM0 );
num = (int)PRVM_G_FLOAT( OFS_PARM1 );
- set = setstr = PRVM_G_STRING( OFS_PARM2 );
+ set = PRVM_G_STRING( OFS_PARM2 );
out = outstr;
for( num = num * 2 + 2 ; *in && num > 0 ; *out++ = *in++ )
const char *a, *b;
a = *((const char **) in1);
b = *((const char **) in2);
- if(!a[0]) return 1;
- if(!b[0]) return -1;
+ if(!a || !a[0]) return 1;
+ if(!b || !b[0]) return -1;
return strncmp(a, b, stringbuffers_sortlength);
}
const char *a, *b;
a = *((const char **) in1);
b = *((const char **) in2);
- if(!a[0]) return 1;
- if(!b[0]) return -1;
+ if(!a || !a[0]) return 1;
+ if(!b || !b[0]) return -1;
return strncmp(b, a, stringbuffers_sortlength);
}
VM_buf_create
creates new buffer, and returns it's index, returns -1 if failed
float buf_create(void) = #460;
+float newbuf(string format, float flags) = #460;
========================
*/
+
void VM_buf_create (void)
{
prvm_stringbuffer_t *stringbuffer;
int i;
- VM_SAFEPARMCOUNT(0, VM_buf_create);
+
+ VM_SAFEPARMCOUNTRANGE(0, 2, VM_buf_create);
+
+ // VorteX: optional parm1 (buffer format) is unfinished, to keep intact with future databuffers extension must be set to "string"
+ if(prog->argc >= 1 && strcmp(PRVM_G_STRING(OFS_PARM0), "string"))
+ {
+ PRVM_G_FLOAT(OFS_RETURN) = -1;
+ return;
+ }
stringbuffer = (prvm_stringbuffer_t *) Mem_ExpandableArray_AllocRecord(&prog->stringbuffersarray);
for (i = 0;stringbuffer != Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, i);i++);
stringbuffer->origin = PRVM_AllocationOrigin();
+ // optional flags parm
+ if (prog->argc >= 2)
+ stringbuffer->flags = (int)PRVM_G_FLOAT(OFS_PARM1) & 0xFF;
PRVM_G_FLOAT(OFS_RETURN) = i;
}
+
+
/*
========================
VM_buf_del
strindex = (int)PRVM_G_FLOAT(OFS_PARM1);
if (strindex < 0)
{
- VM_Warning("VM_bufstr_get: invalid string index %i used in %s\n", strindex, PRVM_NAME);
+ // VM_Warning("VM_bufstr_get: invalid string index %i used in %s\n", strindex, PRVM_NAME);
return;
}
if (strindex < stringbuffer->num_strings && stringbuffer->strings[strindex])
*/
void VM_bufstr_set (void)
{
+ size_t alloclen;
int strindex;
prvm_stringbuffer_t *stringbuffer;
const char *news;
Mem_Free(stringbuffer->strings[strindex]);
stringbuffer->strings[strindex] = NULL;
- news = PRVM_G_STRING(OFS_PARM2);
- if (news && news[0])
+ if(PRVM_G_INT(OFS_PARM2))
{
- size_t alloclen = strlen(news) + 1;
+ // not the NULL string!
+ news = PRVM_G_STRING(OFS_PARM2);
+ alloclen = strlen(news) + 1;
stringbuffer->strings[strindex] = (char *)Mem_Alloc(prog->progs_mempool, alloclen);
memcpy(stringbuffer->strings[strindex], news, alloclen);
}
VM_Warning("VM_bufstr_add: invalid buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), PRVM_NAME);
return;
}
- string = PRVM_G_STRING(OFS_PARM1);
- if(!string || !string[0])
+ if(!PRVM_G_INT(OFS_PARM1)) // NULL string
{
VM_Warning("VM_bufstr_add: can not add an empty string to buffer %i in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), PRVM_NAME);
return;
}
+ string = PRVM_G_STRING(OFS_PARM1);
order = (int)PRVM_G_FLOAT(OFS_PARM2);
if(order)
strindex = stringbuffer->num_strings;
// parameters because they are the parameters to SV_MoveToGoal, not this
//VM_SAFEPARMCOUNT(0, VM_changeyaw);
- ent = PRVM_PROG_TO_EDICT(PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict);
+ ent = PRVM_PROG_TO_EDICT(PRVM_gameglobaledict(self));
if (ent == prog->edicts)
{
VM_Warning("changeyaw: can not modify world entity\n");
VM_Warning("changeyaw: can not modify free entity\n");
return;
}
- if (prog->fieldoffsets.angles < 0 || prog->fieldoffsets.ideal_yaw < 0 || prog->fieldoffsets.yaw_speed < 0)
- {
- VM_Warning("changeyaw: angles, ideal_yaw, or yaw_speed field(s) not found\n");
- return;
- }
- current = ANGLEMOD(PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.angles)->vector[1]);
- ideal = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.ideal_yaw)->_float;
- speed = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.yaw_speed)->_float;
+ current = PRVM_gameedictvector(ent, angles)[1];
+ current = ANGLEMOD(current);
+ ideal = PRVM_gameedictfloat(ent, ideal_yaw);
+ speed = PRVM_gameedictfloat(ent, yaw_speed);
if (current == ideal)
return;
move = -speed;
}
- PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.angles)->vector[1] = ANGLEMOD (current + move);
+ current += move;
+ PRVM_gameedictvector(ent, angles)[1] = ANGLEMOD(current);
}
/*
VM_Warning("changepitch: can not modify free entity\n");
return;
}
- if (prog->fieldoffsets.angles < 0 || prog->fieldoffsets.idealpitch < 0 || prog->fieldoffsets.pitch_speed < 0)
- {
- VM_Warning("changepitch: angles, idealpitch, or pitch_speed field(s) not found\n");
- return;
- }
- current = ANGLEMOD(PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.angles)->vector[0]);
- ideal = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.idealpitch)->_float;
- speed = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.pitch_speed)->_float;
+ current = PRVM_gameedictvector(ent, angles)[0];
+ current = ANGLEMOD(current);
+ ideal = PRVM_gameedictfloat(ent, idealpitch);
+ speed = PRVM_gameedictfloat(ent, pitch_speed);
if (current == ideal)
return;
move = -speed;
}
- PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.angles)->vector[0] = ANGLEMOD (current + move);
+ current += move;
+ PRVM_gameedictvector(ent, angles)[0] = ANGLEMOD(current);
}
if (!match)
PRVM_G_FLOAT(OFS_RETURN) = -1;
else
- PRVM_G_FLOAT(OFS_RETURN) = match - instr;
+ PRVM_G_FLOAT(OFS_RETURN) = u8_strnlen(instr, match-instr);
}
//#222 string(string s, float index) str2chr (FTE_STRINGS)
if (utf8_enable.integer)
ch = u8_getchar_noendptr(s + index);
else
- ch = s[index];
+ ch = (unsigned char)s[index];
PRVM_G_FLOAT(OFS_RETURN) = ch;
}
else
void VM_SetTraceGlobals(const trace_t *trace)
{
- prvm_eval_t *val;
- if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_allsolid)))
- val->_float = trace->allsolid;
- if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_startsolid)))
- val->_float = trace->startsolid;
- if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_fraction)))
- val->_float = trace->fraction;
- if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_inwater)))
- val->_float = trace->inwater;
- if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_inopen)))
- val->_float = trace->inopen;
- if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_endpos)))
- VectorCopy(trace->endpos, val->vector);
- if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_plane_normal)))
- VectorCopy(trace->plane.normal, val->vector);
- if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_plane_dist)))
- val->_float = trace->plane.dist;
- if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_ent)))
- val->edict = PRVM_EDICT_TO_PROG(trace->ent ? trace->ent : prog->edicts);
- if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_dpstartcontents)))
- val->_float = trace->startsupercontents;
- if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_dphitcontents)))
- val->_float = trace->hitsupercontents;
- if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_dphitq3surfaceflags)))
- val->_float = trace->hitq3surfaceflags;
- if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_dphittexturename)))
- val->string = trace->hittexture ? PRVM_SetTempString(trace->hittexture->name) : 0;
+ PRVM_gameglobalfloat(trace_allsolid) = trace->allsolid;
+ PRVM_gameglobalfloat(trace_startsolid) = trace->startsolid;
+ PRVM_gameglobalfloat(trace_fraction) = trace->fraction;
+ PRVM_gameglobalfloat(trace_inwater) = trace->inwater;
+ PRVM_gameglobalfloat(trace_inopen) = trace->inopen;
+ VectorCopy(trace->endpos, PRVM_gameglobalvector(trace_endpos));
+ VectorCopy(trace->plane.normal, PRVM_gameglobalvector(trace_plane_normal));
+ PRVM_gameglobalfloat(trace_plane_dist) = trace->plane.dist;
+ PRVM_gameglobaledict(trace_ent) = PRVM_EDICT_TO_PROG(trace->ent ? trace->ent : prog->edicts);
+ PRVM_gameglobalfloat(trace_dpstartcontents) = trace->startsupercontents;
+ PRVM_gameglobalfloat(trace_dphitcontents) = trace->hitsupercontents;
+ PRVM_gameglobalfloat(trace_dphitq3surfaceflags) = trace->hitq3surfaceflags;
+ PRVM_gameglobalstring(trace_dphittexturename) = trace->hittexture ? PRVM_SetTempString(trace->hittexture->name) : 0;
}
void VM_ClearTraceGlobals(void)
{
// clean up all trace globals when leaving the VM (anti-triggerbot safeguard)
- prvm_eval_t *val;
- if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_allsolid)))
- val->_float = 0;
- if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_startsolid)))
- val->_float = 0;
- if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_fraction)))
- val->_float = 0;
- if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_inwater)))
- val->_float = 0;
- if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_inopen)))
- val->_float = 0;
- if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_endpos)))
- VectorClear(val->vector);
- if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_plane_normal)))
- VectorClear(val->vector);
- if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_plane_dist)))
- val->_float = 0;
- if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_ent)))
- val->edict = PRVM_EDICT_TO_PROG(prog->edicts);
- if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_dpstartcontents)))
- val->_float = 0;
- if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_dphitcontents)))
- val->_float = 0;
- if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_dphitq3surfaceflags)))
- val->_float = 0;
- if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_dphittexturename)))
- val->string = 0;
+ PRVM_gameglobalfloat(trace_allsolid) = 0;
+ PRVM_gameglobalfloat(trace_startsolid) = 0;
+ PRVM_gameglobalfloat(trace_fraction) = 0;
+ PRVM_gameglobalfloat(trace_inwater) = 0;
+ PRVM_gameglobalfloat(trace_inopen) = 0;
+ VectorClear(PRVM_gameglobalvector(trace_endpos));
+ VectorClear(PRVM_gameglobalvector(trace_plane_normal));
+ PRVM_gameglobalfloat(trace_plane_dist) = 0;
+ PRVM_gameglobaledict(trace_ent) = PRVM_EDICT_TO_PROG(prog->edicts);
+ PRVM_gameglobalfloat(trace_dpstartcontents) = 0;
+ PRVM_gameglobalfloat(trace_dphitcontents) = 0;
+ PRVM_gameglobalfloat(trace_dphitq3surfaceflags) = 0;
+ PRVM_gameglobalstring(trace_dphittexturename) = 0;
}
//=============
|| (*p >= 'a' && *p <= 'z')
|| (*p >= '0' && *p <= '9')
|| (*p == '-') || (*p == '_') || (*p == '.')
- || (*p == '!') || (*p == '~') || (*p == '*')
+ || (*p == '!') || (*p == '~')
|| (*p == '\'') || (*p == '(') || (*p == ')'))
*q++ = *p;
else
double starttime;
float id;
char buffer[MAX_INPUTLINE];
+ unsigned char *postdata; // free when uri_to_prog_t is freed
+ size_t postlen;
+ char *sigdata; // free when uri_to_prog_t is freed
+ size_t siglen;
}
uri_to_prog_t;
if(!PRVM_ProgLoaded(handle->prognr))
{
// curl reply came too late... so just drop it
+ if(handle->postdata)
+ Z_Free(handle->postdata);
+ if(handle->sigdata)
+ Z_Free(handle->sigdata);
Z_Free(handle);
return;
}
PRVM_SetProg(handle->prognr);
PRVM_Begin;
- if((prog->starttime == handle->starttime) && (prog->funcoffsets.URI_Get_Callback))
+ if((prog->starttime == handle->starttime) && (PRVM_allfunction(URI_Get_Callback)))
{
if(length_received >= sizeof(handle->buffer))
length_received = sizeof(handle->buffer) - 1;
PRVM_G_FLOAT(OFS_PARM0) = handle->id;
PRVM_G_FLOAT(OFS_PARM1) = status;
PRVM_G_INT(OFS_PARM2) = PRVM_SetTempString(handle->buffer);
- PRVM_ExecuteProgram(prog->funcoffsets.URI_Get_Callback, "QC function URI_Get_Callback is missing");
+ PRVM_ExecuteProgram(PRVM_allfunction(URI_Get_Callback), "QC function URI_Get_Callback is missing");
}
PRVM_End;
+ if(handle->postdata)
+ Z_Free(handle->postdata);
+ if(handle->sigdata)
+ Z_Free(handle->sigdata);
Z_Free(handle);
}
float id;
qboolean ret;
uri_to_prog_t *handle;
-
- if(!prog->funcoffsets.URI_Get_Callback)
+ const char *posttype = NULL;
+ const char *postseparator = NULL;
+ int poststringbuffer = -1;
+ int postkeyid = -1;
+ const char *query_string = NULL;
+ size_t lq;
+
+ if(!PRVM_allfunction(URI_Get_Callback))
PRVM_ERROR("uri_get called by %s without URI_Get_Callback defined", PRVM_NAME);
- VM_SAFEPARMCOUNT(2, VM_uri_get);
+ VM_SAFEPARMCOUNTRANGE(2, 6, VM_uri_get);
url = PRVM_G_STRING(OFS_PARM0);
id = PRVM_G_FLOAT(OFS_PARM1);
+ if(prog->argc >= 3)
+ posttype = PRVM_G_STRING(OFS_PARM2);
+ if(prog->argc >= 4)
+ postseparator = PRVM_G_STRING(OFS_PARM3);
+ if(prog->argc >= 5)
+ poststringbuffer = PRVM_G_FLOAT(OFS_PARM4);
+ if(prog->argc >= 6)
+ postkeyid = PRVM_G_FLOAT(OFS_PARM5);
handle = (uri_to_prog_t *) Z_Malloc(sizeof(*handle)); // this can't be the prog's mem pool, as curl may call the callback later!
+ query_string = strchr(url, '?');
+ if(query_string)
+ ++query_string;
+ lq = query_string ? strlen(query_string) : 0;
+
handle->prognr = PRVM_GetProgNr();
handle->starttime = prog->starttime;
handle->id = id;
- ret = Curl_Begin_ToMemory(url, (unsigned char *) handle->buffer, sizeof(handle->buffer), uri_to_string_callback, handle);
+ if(postseparator)
+ {
+ size_t l = strlen(postseparator);
+ if(poststringbuffer >= 0)
+ {
+ size_t ltotal;
+ int i;
+ // "implode"
+ prvm_stringbuffer_t *stringbuffer;
+ stringbuffer = (prvm_stringbuffer_t *)Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, poststringbuffer);
+ if(!stringbuffer)
+ {
+ VM_Warning("uri_get: invalid buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), PRVM_NAME);
+ return;
+ }
+ ltotal = 0;
+ for(i = 0;i < stringbuffer->num_strings;i++)
+ {
+ if(i > 0)
+ ltotal += l;
+ if(stringbuffer->strings[i])
+ ltotal += strlen(stringbuffer->strings[i]);
+ }
+ handle->postdata = (unsigned char *)Z_Malloc(ltotal + 1 + lq);
+ handle->postlen = ltotal;
+ ltotal = 0;
+ for(i = 0;i < stringbuffer->num_strings;i++)
+ {
+ if(i > 0)
+ {
+ memcpy(handle->postdata + ltotal, postseparator, l);
+ ltotal += l;
+ }
+ if(stringbuffer->strings[i])
+ {
+ memcpy(handle->postdata + ltotal, stringbuffer->strings[i], strlen(stringbuffer->strings[i]));
+ ltotal += strlen(stringbuffer->strings[i]);
+ }
+ }
+ if(ltotal != handle->postlen)
+ PRVM_ERROR ("%s: string buffer content size mismatch, possible overrun", PRVM_NAME);
+ }
+ else
+ {
+ handle->postdata = (unsigned char *)Z_Malloc(l + 1 + lq);
+ handle->postlen = l;
+ memcpy(handle->postdata, postseparator, l);
+ }
+ handle->postdata[handle->postlen] = 0;
+ if(query_string)
+ memcpy(handle->postdata + handle->postlen + 1, query_string, lq);
+ if(postkeyid >= 0)
+ {
+ // POST: we sign postdata \0 query string
+ size_t ll;
+ handle->sigdata = (char *)Z_Malloc(8192);
+ strlcpy(handle->sigdata, "X-D0-Blind-ID-Detached-Signature: ", 8192);
+ l = strlen(handle->sigdata);
+ handle->siglen = Crypto_SignDataDetached(handle->postdata, handle->postlen + 1 + lq, postkeyid, handle->sigdata + l, 8192 - l);
+ if(!handle->siglen)
+ {
+ Z_Free(handle->sigdata);
+ handle->sigdata = NULL;
+ goto out1;
+ }
+ ll = base64_encode((unsigned char *) (handle->sigdata + l), handle->siglen, 8192 - l - 1);
+ if(!ll)
+ {
+ Z_Free(handle->sigdata);
+ handle->sigdata = NULL;
+ goto out1;
+ }
+ handle->siglen = l + ll;
+ handle->sigdata[handle->siglen] = 0;
+ }
+out1:
+ ret = Curl_Begin_ToMemory_POST(url, handle->sigdata, 0, posttype, handle->postdata, handle->postlen, (unsigned char *) handle->buffer, sizeof(handle->buffer), uri_to_string_callback, handle);
+ }
+ else
+ {
+ if(postkeyid >= 0 && query_string)
+ {
+ // GET: we sign JUST the query string
+ size_t l, ll;
+ handle->sigdata = (char *)Z_Malloc(8192);
+ strlcpy(handle->sigdata, "X-D0-Blind-ID-Detached-Signature: ", 8192);
+ l = strlen(handle->sigdata);
+ handle->siglen = Crypto_SignDataDetached(query_string, lq, postkeyid, handle->sigdata + l, 8192 - l);
+ if(!handle->siglen)
+ {
+ Z_Free(handle->sigdata);
+ handle->sigdata = NULL;
+ goto out2;
+ }
+ ll = base64_encode((unsigned char *) (handle->sigdata + l), handle->siglen, 8192 - l - 1);
+ if(!ll)
+ {
+ Z_Free(handle->sigdata);
+ handle->sigdata = NULL;
+ goto out2;
+ }
+ handle->siglen = l + ll;
+ handle->sigdata[handle->siglen] = 0;
+ }
+out2:
+ handle->postdata = NULL;
+ handle->postlen = 0;
+ ret = Curl_Begin_ToMemory(url, 0, (unsigned char *) handle->buffer, sizeof(handle->buffer), uri_to_string_callback, handle);
+ }
if(ret)
{
PRVM_G_INT(OFS_RETURN) = 1;
}
else
{
+ if(handle->postdata)
+ Z_Free(handle->postdata);
+ if(handle->sigdata)
+ Z_Free(handle->sigdata);
Z_Free(handle);
PRVM_G_INT(OFS_RETURN) = 0;
}
int first;
--cl_net_extresponse_count;
first = (cl_net_extresponse_last + NET_EXTRESPONSE_MAX - cl_net_extresponse_count) % NET_EXTRESPONSE_MAX;
- PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(cl_net_extresponse[first]);
+ PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(cl_net_extresponse[first]);
}
}
int first;
--sv_net_extresponse_count;
first = (sv_net_extresponse_last + NET_EXTRESPONSE_MAX - sv_net_extresponse_count) % NET_EXTRESPONSE_MAX;
- PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(sv_net_extresponse[first]);
+ PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(sv_net_extresponse[first]);
}
}
+/*
+=========
+Common functions between menu.dat and clsprogs
+=========
+*/
+
+//#349 float() isdemo
+void VM_CL_isdemo (void)
+{
+ VM_SAFEPARMCOUNT(0, VM_CL_isdemo);
+ PRVM_G_FLOAT(OFS_RETURN) = cls.demoplayback;
+}
+
+//#355 float() videoplaying
+void VM_CL_videoplaying (void)
+{
+ VM_SAFEPARMCOUNT(0, VM_CL_videoplaying);
+ PRVM_G_FLOAT(OFS_RETURN) = cl_videoplaying;
+}
+
/*
=========
VM_M_callfunction
int width, precision, thisarg, flags;
char formatbuf[16];
char *f;
- qboolean isfloat;
+ int isfloat;
+ static int dummyivec[3] = {0, 0, 0};
+ static float dummyvec[3] = {0, 0, 0};
+
#define PRINTF_ALTERNATE 1
#define PRINTF_ZEROPAD 2
#define PRINTF_LEFT 4
s = PRVM_G_STRING(OFS_PARM0);
#define GETARG_FLOAT(a) (((a)>=1 && (a)<prog->argc) ? (PRVM_G_FLOAT(OFS_PARM0 + 3 * (a))) : 0)
+#define GETARG_VECTOR(a) (((a)>=1 && (a)<prog->argc) ? (PRVM_G_VECTOR(OFS_PARM0 + 3 * (a))) : dummyvec)
#define GETARG_INT(a) (((a)>=1 && (a)<prog->argc) ? (PRVM_G_INT(OFS_PARM0 + 3 * (a))) : 0)
+#define GETARG_INTVECTOR(a) (((a)>=1 && (a)<prog->argc) ? ((int*) PRVM_G_VECTOR(OFS_PARM0 + 3 * (a))) : dummyivec)
#define GETARG_STRING(a) (((a)>=1 && (a)<prog->argc) ? (PRVM_G_STRING(OFS_PARM0 + 3 * (a))) : "")
for(;;)
{
case 0:
goto finished;
- break;
case '%':
++s;
precision = -1;
thisarg = -1;
flags = 0;
+ isfloat = -1;
// is number following?
if(*s >= '0' && *s <= '9')
else
width = argpos++;
width = GETARG_FLOAT(width);
+ if(width < 0)
+ {
+ flags |= PRINTF_LEFT;
+ width = -width;
+ }
}
else if(*s >= '0' && *s <= '9')
{
goto finished;
}
s = err;
+ if(width < 0)
+ {
+ flags |= PRINTF_LEFT;
+ width = -width;
+ }
}
- if(width < 0)
- {
- flags |= PRINTF_LEFT;
- width = -width;
- }
+ // otherwise width stays -1
}
if(*s == '.')
}
}
- isfloat = true;
for(;;)
{
switch(*s)
{
- case 'h': isfloat = true; break;
- case 'l': isfloat = false; break;
- case 'L': isfloat = false; break;
+ case 'h': isfloat = 1; break;
+ case 'l': isfloat = 0; break;
+ case 'L': isfloat = 0; break;
case 'j': break;
case 'z': break;
case 't': break;
}
nolength:
+ // now s points to the final directive char and is no longer changed
+ if(isfloat < 0)
+ {
+ if(*s == 'i')
+ isfloat = 0;
+ else
+ isfloat = 1;
+ }
+
if(thisarg < 0)
thisarg = argpos++;
if(flags & PRINTF_SPACEPOSITIVE) *f++ = ' ';
if(flags & PRINTF_SIGNPOSITIVE) *f++ = '+';
*f++ = '*';
- *f++ = '.';
- *f++ = '*';
+ if(precision >= 0)
+ {
+ *f++ = '.';
+ *f++ = '*';
+ }
*f++ = *s;
*f++ = 0;
- if(width < 0)
+ if(width < 0) // not set
width = 0;
switch(*s)
{
case 'd': case 'i':
- o += dpsnprintf(o, end - o, formatbuf, width, precision, (isfloat ? (int) GETARG_FLOAT(thisarg) : (int) GETARG_INT(thisarg)));
+ if(precision < 0) // not set
+ o += dpsnprintf(o, end - o, formatbuf, width, (isfloat ? (int) GETARG_FLOAT(thisarg) : (int) GETARG_INT(thisarg)));
+ else
+ o += dpsnprintf(o, end - o, formatbuf, width, precision, (isfloat ? (int) GETARG_FLOAT(thisarg) : (int) GETARG_INT(thisarg)));
break;
case 'o': case 'u': case 'x': case 'X':
- o += dpsnprintf(o, end - o, formatbuf, width, precision, (isfloat ? (unsigned int) GETARG_FLOAT(thisarg) : (unsigned int) GETARG_INT(thisarg)));
+ if(precision < 0) // not set
+ o += dpsnprintf(o, end - o, formatbuf, width, (isfloat ? (unsigned int) GETARG_FLOAT(thisarg) : (unsigned int) GETARG_INT(thisarg)));
+ else
+ o += dpsnprintf(o, end - o, formatbuf, width, precision, (isfloat ? (unsigned int) GETARG_FLOAT(thisarg) : (unsigned int) GETARG_INT(thisarg)));
break;
case 'e': case 'E': case 'f': case 'F': case 'g': case 'G':
- if(precision < 0)
- precision = 6;
- o += dpsnprintf(o, end - o, formatbuf, width, precision, (isfloat ? (double) GETARG_FLOAT(thisarg) : (double) GETARG_INT(thisarg)));
+ if(precision < 0) // not set
+ o += dpsnprintf(o, end - o, formatbuf, width, (isfloat ? (double) GETARG_FLOAT(thisarg) : (double) GETARG_INT(thisarg)));
+ else
+ o += dpsnprintf(o, end - o, formatbuf, width, precision, (isfloat ? (double) GETARG_FLOAT(thisarg) : (double) GETARG_INT(thisarg)));
+ break;
+ case 'v': case 'V':
+ f[-2] += 'g' - 'v';
+ if(precision < 0) // not set
+ o += dpsnprintf(o, end - o, va("%s %s %s", /* NESTED SPRINTF IS NESTED */ formatbuf, formatbuf, formatbuf),
+ width, (isfloat ? (double) GETARG_VECTOR(thisarg)[0] : (double) GETARG_INTVECTOR(thisarg)[0]),
+ width, (isfloat ? (double) GETARG_VECTOR(thisarg)[1] : (double) GETARG_INTVECTOR(thisarg)[1]),
+ width, (isfloat ? (double) GETARG_VECTOR(thisarg)[2] : (double) GETARG_INTVECTOR(thisarg)[2])
+ );
+ else
+ o += dpsnprintf(o, end - o, va("%s %s %s", /* NESTED SPRINTF IS NESTED */ formatbuf, formatbuf, formatbuf),
+ width, precision, (isfloat ? (double) GETARG_VECTOR(thisarg)[0] : (double) GETARG_INTVECTOR(thisarg)[0]),
+ width, precision, (isfloat ? (double) GETARG_VECTOR(thisarg)[1] : (double) GETARG_INTVECTOR(thisarg)[1]),
+ width, precision, (isfloat ? (double) GETARG_VECTOR(thisarg)[2] : (double) GETARG_INTVECTOR(thisarg)[2])
+ );
break;
case 'c':
- if(precision < 0)
- precision = end - o - 1;
if(flags & PRINTF_ALTERNATE)
- o += dpsnprintf(o, end - o, formatbuf, width, precision, (isfloat ? (unsigned int) GETARG_FLOAT(thisarg) : (unsigned int) GETARG_INT(thisarg)));
+ {
+ if(precision < 0) // not set
+ o += dpsnprintf(o, end - o, formatbuf, width, (isfloat ? (unsigned int) GETARG_FLOAT(thisarg) : (unsigned int) GETARG_INT(thisarg)));
+ else
+ o += dpsnprintf(o, end - o, formatbuf, width, precision, (isfloat ? (unsigned int) GETARG_FLOAT(thisarg) : (unsigned int) GETARG_INT(thisarg)));
+ }
else
{
unsigned int c = (isfloat ? (unsigned int) GETARG_FLOAT(thisarg) : (unsigned int) GETARG_INT(thisarg));
const char *buf = u8_encodech(c, NULL);
if(!buf)
buf = "";
+ if(precision < 0) // not set
+ precision = end - o - 1;
o += u8_strpad(o, end - o, buf, (flags & PRINTF_LEFT) != 0, width, precision);
}
break;
case 's':
- if(precision < 0)
- precision = end - o - 1;
if(flags & PRINTF_ALTERNATE)
- o += dpsnprintf(o, end - o, formatbuf, width, precision, GETARG_STRING(thisarg));
+ {
+ if(precision < 0) // not set
+ o += dpsnprintf(o, end - o, formatbuf, width, GETARG_STRING(thisarg));
+ else
+ o += dpsnprintf(o, end - o, formatbuf, width, precision, GETARG_STRING(thisarg));
+ }
else
+ {
+ if(precision < 0) // not set
+ precision = end - o - 1;
o += u8_strpad(o, end - o, GETARG_STRING(thisarg), (flags & PRINTF_LEFT) != 0, width, precision);
+ }
break;
default:
VM_Warning("VM_sprintf: invalid directive in %s: %s\n", PRVM_NAME, s0);
*o = 0;
PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(outbuf);
}
+
+
+// surface querying
+
+static dp_model_t *getmodel(prvm_edict_t *ed)
+{
+ switch(PRVM_GetProgNr())
+ {
+ case PRVM_SERVERPROG:
+ return SV_GetModelFromEdict(ed);
+ case PRVM_CLIENTPROG:
+ return CL_GetModelFromEdict(ed);
+ default:
+ return NULL;
+ }
+}
+
+typedef struct
+{
+ unsigned int progid;
+ dp_model_t *model;
+ frameblend_t frameblend[MAX_FRAMEBLENDS];
+ skeleton_t *skeleton_p;
+ skeleton_t skeleton;
+ float *data_vertex3f;
+ float *data_svector3f;
+ float *data_tvector3f;
+ float *data_normal3f;
+ int max_vertices;
+ float *buf_vertex3f;
+ float *buf_svector3f;
+ float *buf_tvector3f;
+ float *buf_normal3f;
+}
+animatemodel_cache_t;
+static animatemodel_cache_t animatemodel_cache;
+
+void animatemodel(dp_model_t *model, prvm_edict_t *ed)
+{
+ skeleton_t *skeleton;
+ int skeletonindex = -1;
+ qboolean need = false;
+ if(!(model->surfmesh.isanimated && model->AnimateVertices))
+ {
+ animatemodel_cache.data_vertex3f = model->surfmesh.data_vertex3f;
+ animatemodel_cache.data_svector3f = model->surfmesh.data_svector3f;
+ animatemodel_cache.data_tvector3f = model->surfmesh.data_tvector3f;
+ animatemodel_cache.data_normal3f = model->surfmesh.data_normal3f;
+ return;
+ }
+ if(animatemodel_cache.progid != prog->id)
+ memset(&animatemodel_cache, 0, sizeof(animatemodel_cache));
+ need |= (animatemodel_cache.model != model);
+ VM_GenerateFrameGroupBlend(ed->priv.server->framegroupblend, ed);
+ VM_FrameBlendFromFrameGroupBlend(ed->priv.server->frameblend, ed->priv.server->framegroupblend, model);
+ need |= (memcmp(&animatemodel_cache.frameblend, &ed->priv.server->frameblend, sizeof(ed->priv.server->frameblend))) != 0;
+ skeletonindex = (int)PRVM_gameedictfloat(ed, skeletonindex) - 1;
+ if (!(skeletonindex >= 0 && skeletonindex < MAX_EDICTS && (skeleton = prog->skeletons[skeletonindex]) && skeleton->model->num_bones == ed->priv.server->skeleton.model->num_bones))
+ skeleton = NULL;
+ need |= (animatemodel_cache.skeleton_p != skeleton);
+ if(skeleton)
+ need |= (memcmp(&animatemodel_cache.skeleton, skeleton, sizeof(ed->priv.server->skeleton))) != 0;
+ if(!need)
+ return;
+ if(model->surfmesh.num_vertices > animatemodel_cache.max_vertices)
+ {
+ animatemodel_cache.max_vertices = model->surfmesh.num_vertices * 2;
+ if(animatemodel_cache.buf_vertex3f) Mem_Free(animatemodel_cache.buf_vertex3f);
+ if(animatemodel_cache.buf_svector3f) Mem_Free(animatemodel_cache.buf_svector3f);
+ if(animatemodel_cache.buf_tvector3f) Mem_Free(animatemodel_cache.buf_tvector3f);
+ if(animatemodel_cache.buf_normal3f) Mem_Free(animatemodel_cache.buf_normal3f);
+ animatemodel_cache.buf_vertex3f = (float *)Mem_Alloc(prog->progs_mempool, sizeof(float[3]) * animatemodel_cache.max_vertices);
+ animatemodel_cache.buf_svector3f = (float *)Mem_Alloc(prog->progs_mempool, sizeof(float[3]) * animatemodel_cache.max_vertices);
+ animatemodel_cache.buf_tvector3f = (float *)Mem_Alloc(prog->progs_mempool, sizeof(float[3]) * animatemodel_cache.max_vertices);
+ animatemodel_cache.buf_normal3f = (float *)Mem_Alloc(prog->progs_mempool, sizeof(float[3]) * animatemodel_cache.max_vertices);
+ }
+ animatemodel_cache.data_vertex3f = animatemodel_cache.buf_vertex3f;
+ animatemodel_cache.data_svector3f = animatemodel_cache.buf_svector3f;
+ animatemodel_cache.data_tvector3f = animatemodel_cache.buf_tvector3f;
+ animatemodel_cache.data_normal3f = animatemodel_cache.buf_normal3f;
+ VM_UpdateEdictSkeleton(ed, model, ed->priv.server->frameblend);
+ model->AnimateVertices(model, ed->priv.server->frameblend, &ed->priv.server->skeleton, animatemodel_cache.data_vertex3f, animatemodel_cache.data_normal3f, animatemodel_cache.data_svector3f, animatemodel_cache.data_tvector3f);
+ animatemodel_cache.progid = prog->id;
+ animatemodel_cache.model = model;
+ memcpy(&animatemodel_cache.frameblend, &ed->priv.server->frameblend, sizeof(ed->priv.server->frameblend));
+ animatemodel_cache.skeleton_p = skeleton;
+ if(skeleton)
+ memcpy(&animatemodel_cache.skeleton, skeleton, sizeof(ed->priv.server->skeleton));
+}
+
+static void getmatrix(prvm_edict_t *ed, matrix4x4_t *out)
+{
+ switch(PRVM_GetProgNr())
+ {
+ case PRVM_SERVERPROG:
+ SV_GetEntityMatrix(ed, out, false);
+ break;
+ case PRVM_CLIENTPROG:
+ CL_GetEntityMatrix(ed, out, false);
+ break;
+ default:
+ *out = identitymatrix;
+ break;
+ }
+}
+
+static void applytransform_forward(const vec3_t in, prvm_edict_t *ed, vec3_t out)
+{
+ matrix4x4_t m;
+ getmatrix(ed, &m);
+ Matrix4x4_Transform(&m, in, out);
+}
+
+static void applytransform_forward_direction(const vec3_t in, prvm_edict_t *ed, vec3_t out)
+{
+ matrix4x4_t m;
+ getmatrix(ed, &m);
+ Matrix4x4_Transform3x3(&m, in, out);
+}
+
+static void applytransform_inverted(const vec3_t in, prvm_edict_t *ed, vec3_t out)
+{
+ matrix4x4_t m, n;
+ getmatrix(ed, &m);
+ Matrix4x4_Invert_Full(&n, &m);
+ Matrix4x4_Transform3x3(&n, in, out);
+}
+
+static void applytransform_forward_normal(const vec3_t in, prvm_edict_t *ed, vec3_t out)
+{
+ matrix4x4_t m;
+ float p[4];
+ getmatrix(ed, &m);
+ Matrix4x4_TransformPositivePlane(&m, in[0], in[1], in[2], 0, p);
+ VectorCopy(p, out);
+}
+
+static void clippointtosurface(prvm_edict_t *ed, dp_model_t *model, msurface_t *surface, vec3_t p, vec3_t out)
+{
+ int i, j, k;
+ float *v[3], facenormal[3], edgenormal[3], sidenormal[3], temp[3], offsetdist, dist, bestdist;
+ const int *e;
+ animatemodel(model, ed);
+ bestdist = 1000000000;
+ VectorCopy(p, out);
+ for (i = 0, e = (model->surfmesh.data_element3i + 3 * surface->num_firsttriangle);i < surface->num_triangles;i++, e += 3)
+ {
+ // clip original point to each triangle of the surface and find the
+ // triangle that is closest
+ v[0] = animatemodel_cache.data_vertex3f + e[0] * 3;
+ v[1] = animatemodel_cache.data_vertex3f + e[1] * 3;
+ v[2] = animatemodel_cache.data_vertex3f + e[2] * 3;
+ TriangleNormal(v[0], v[1], v[2], facenormal);
+ VectorNormalize(facenormal);
+ offsetdist = DotProduct(v[0], facenormal) - DotProduct(p, facenormal);
+ VectorMA(p, offsetdist, facenormal, temp);
+ for (j = 0, k = 2;j < 3;k = j, j++)
+ {
+ VectorSubtract(v[k], v[j], edgenormal);
+ CrossProduct(edgenormal, facenormal, sidenormal);
+ VectorNormalize(sidenormal);
+ offsetdist = DotProduct(v[k], sidenormal) - DotProduct(temp, sidenormal);
+ if (offsetdist < 0)
+ VectorMA(temp, offsetdist, sidenormal, temp);
+ }
+ dist = VectorDistance2(temp, p);
+ if (bestdist > dist)
+ {
+ bestdist = dist;
+ VectorCopy(temp, out);
+ }
+ }
+}
+
+static msurface_t *getsurface(dp_model_t *model, int surfacenum)
+{
+ if (surfacenum < 0 || surfacenum >= model->nummodelsurfaces)
+ return NULL;
+ return model->data_surfaces + surfacenum + model->firstmodelsurface;
+}
+
+
+//PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
+void VM_getsurfacenumpoints(void)
+{
+ dp_model_t *model;
+ msurface_t *surface;
+ VM_SAFEPARMCOUNT(2, VM_getsurfacenumpoints);
+ // return 0 if no such surface
+ if (!(model = getmodel(PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
+ {
+ PRVM_G_FLOAT(OFS_RETURN) = 0;
+ return;
+ }
+
+ // note: this (incorrectly) assumes it is a simple polygon
+ PRVM_G_FLOAT(OFS_RETURN) = surface->num_vertices;
+}
+//PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
+void VM_getsurfacepoint(void)
+{
+ prvm_edict_t *ed;
+ dp_model_t *model;
+ msurface_t *surface;
+ int pointnum;
+ VM_SAFEPARMCOUNT(3, VM_getsurfacepoint);
+ VectorClear(PRVM_G_VECTOR(OFS_RETURN));
+ ed = PRVM_G_EDICT(OFS_PARM0);
+ if (!(model = getmodel(ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
+ return;
+ // note: this (incorrectly) assumes it is a simple polygon
+ pointnum = (int)PRVM_G_FLOAT(OFS_PARM2);
+ if (pointnum < 0 || pointnum >= surface->num_vertices)
+ return;
+ animatemodel(model, ed);
+ applytransform_forward(&(animatemodel_cache.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed, PRVM_G_VECTOR(OFS_RETURN));
+}
+//PF_getsurfacepointattribute, // #486 vector(entity e, float s, float n, float a) getsurfacepointattribute = #486;
+// float SPA_POSITION = 0;
+// float SPA_S_AXIS = 1;
+// float SPA_T_AXIS = 2;
+// float SPA_R_AXIS = 3; // same as SPA_NORMAL
+// float SPA_TEXCOORDS0 = 4;
+// float SPA_LIGHTMAP0_TEXCOORDS = 5;
+// float SPA_LIGHTMAP0_COLOR = 6;
+void VM_getsurfacepointattribute(void)
+{
+ prvm_edict_t *ed;
+ dp_model_t *model;
+ msurface_t *surface;
+ int pointnum;
+ int attributetype;
+
+ VM_SAFEPARMCOUNT(4, VM_getsurfacepoint);
+ VectorClear(PRVM_G_VECTOR(OFS_RETURN));
+ ed = PRVM_G_EDICT(OFS_PARM0);
+ if (!(model = getmodel(ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
+ return;
+ pointnum = (int)PRVM_G_FLOAT(OFS_PARM2);
+ if (pointnum < 0 || pointnum >= surface->num_vertices)
+ return;
+ attributetype = (int) PRVM_G_FLOAT(OFS_PARM3);
+
+ animatemodel(model, ed);
+
+ switch( attributetype ) {
+ // float SPA_POSITION = 0;
+ case 0:
+ applytransform_forward(&(animatemodel_cache.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed, PRVM_G_VECTOR(OFS_RETURN));
+ break;
+ // float SPA_S_AXIS = 1;
+ case 1:
+ applytransform_forward_direction(&(animatemodel_cache.data_svector3f + 3 * surface->num_firstvertex)[pointnum * 3], ed, PRVM_G_VECTOR(OFS_RETURN));
+ break;
+ // float SPA_T_AXIS = 2;
+ case 2:
+ applytransform_forward_direction(&(animatemodel_cache.data_tvector3f + 3 * surface->num_firstvertex)[pointnum * 3], ed, PRVM_G_VECTOR(OFS_RETURN));
+ break;
+ // float SPA_R_AXIS = 3; // same as SPA_NORMAL
+ case 3:
+ applytransform_forward_direction(&(animatemodel_cache.data_normal3f + 3 * surface->num_firstvertex)[pointnum * 3], ed, PRVM_G_VECTOR(OFS_RETURN));
+ break;
+ // float SPA_TEXCOORDS0 = 4;
+ case 4: {
+ float *ret = PRVM_G_VECTOR(OFS_RETURN);
+ float *texcoord = &(model->surfmesh.data_texcoordtexture2f + 2 * surface->num_firstvertex)[pointnum * 2];
+ ret[0] = texcoord[0];
+ ret[1] = texcoord[1];
+ ret[2] = 0.0f;
+ break;
+ }
+ // float SPA_LIGHTMAP0_TEXCOORDS = 5;
+ case 5: {
+ float *ret = PRVM_G_VECTOR(OFS_RETURN);
+ float *texcoord = &(model->surfmesh.data_texcoordlightmap2f + 2 * surface->num_firstvertex)[pointnum * 2];
+ ret[0] = texcoord[0];
+ ret[1] = texcoord[1];
+ ret[2] = 0.0f;
+ break;
+ }
+ // float SPA_LIGHTMAP0_COLOR = 6;
+ case 6:
+ // ignore alpha for now..
+ VectorCopy( &(model->surfmesh.data_lightmapcolor4f + 4 * surface->num_firstvertex)[pointnum * 4], PRVM_G_VECTOR(OFS_RETURN));
+ break;
+ default:
+ VectorSet( PRVM_G_VECTOR(OFS_RETURN), 0.0f, 0.0f, 0.0f );
+ break;
+ }
+}
+//PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal = #436;
+void VM_getsurfacenormal(void)
+{
+ dp_model_t *model;
+ msurface_t *surface;
+ vec3_t normal;
+ VM_SAFEPARMCOUNT(2, VM_getsurfacenormal);
+ VectorClear(PRVM_G_VECTOR(OFS_RETURN));
+ if (!(model = getmodel(PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
+ return;
+ // note: this only returns the first triangle, so it doesn't work very
+ // well for curved surfaces or arbitrary meshes
+ animatemodel(model, PRVM_G_EDICT(OFS_PARM0));
+ TriangleNormal((animatemodel_cache.data_vertex3f + 3 * surface->num_firstvertex), (animatemodel_cache.data_vertex3f + 3 * surface->num_firstvertex) + 3, (animatemodel_cache.data_vertex3f + 3 * surface->num_firstvertex) + 6, normal);
+ applytransform_forward_normal(normal, PRVM_G_EDICT(OFS_PARM0), PRVM_G_VECTOR(OFS_RETURN));
+ VectorNormalize(PRVM_G_VECTOR(OFS_RETURN));
+}
+//PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture = #437;
+void VM_getsurfacetexture(void)
+{
+ dp_model_t *model;
+ msurface_t *surface;
+ VM_SAFEPARMCOUNT(2, VM_getsurfacetexture);
+ PRVM_G_INT(OFS_RETURN) = OFS_NULL;
+ if (!(model = getmodel(PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
+ return;
+ PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(surface->texture->name);
+}
+//PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
+void VM_getsurfacenearpoint(void)
+{
+ int surfacenum, best;
+ vec3_t clipped, p;
+ vec_t dist, bestdist;
+ prvm_edict_t *ed;
+ dp_model_t *model;
+ msurface_t *surface;
+ vec_t *point;
+ VM_SAFEPARMCOUNT(2, VM_getsurfacenearpoint);
+ PRVM_G_FLOAT(OFS_RETURN) = -1;
+ ed = PRVM_G_EDICT(OFS_PARM0);
+ point = PRVM_G_VECTOR(OFS_PARM1);
+
+ if (!ed || ed->priv.server->free)
+ return;
+ model = getmodel(ed);
+ if (!model || !model->num_surfaces)
+ return;
+
+ animatemodel(model, ed);
+
+ applytransform_inverted(point, ed, p);
+ best = -1;
+ bestdist = 1000000000;
+ for (surfacenum = 0;surfacenum < model->nummodelsurfaces;surfacenum++)
+ {
+ surface = model->data_surfaces + surfacenum + model->firstmodelsurface;
+ // first see if the nearest point on the surface's box is closer than the previous match
+ clipped[0] = bound(surface->mins[0], p[0], surface->maxs[0]) - p[0];
+ clipped[1] = bound(surface->mins[1], p[1], surface->maxs[1]) - p[1];
+ clipped[2] = bound(surface->mins[2], p[2], surface->maxs[2]) - p[2];
+ dist = VectorLength2(clipped);
+ if (dist < bestdist)
+ {
+ // it is, check the nearest point on the actual geometry
+ clippointtosurface(ed, model, surface, p, clipped);
+ VectorSubtract(clipped, p, clipped);
+ dist += VectorLength2(clipped);
+ if (dist < bestdist)
+ {
+ // that's closer too, store it as the best match
+ best = surfacenum;
+ bestdist = dist;
+ }
+ }
+ }
+ PRVM_G_FLOAT(OFS_RETURN) = best;
+}
+//PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
+void VM_getsurfaceclippedpoint(void)
+{
+ prvm_edict_t *ed;
+ dp_model_t *model;
+ msurface_t *surface;
+ vec3_t p, out;
+ VM_SAFEPARMCOUNT(3, VM_te_getsurfaceclippedpoint);
+ VectorClear(PRVM_G_VECTOR(OFS_RETURN));
+ ed = PRVM_G_EDICT(OFS_PARM0);
+ if (!(model = getmodel(ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
+ return;
+ animatemodel(model, ed);
+ applytransform_inverted(PRVM_G_VECTOR(OFS_PARM2), ed, p);
+ clippointtosurface(ed, model, surface, p, out);
+ VectorAdd(out, ed->fields.server->origin, PRVM_G_VECTOR(OFS_RETURN));
+}
+
+//PF_getsurfacenumtriangles, // #??? float(entity e, float s) getsurfacenumtriangles = #???;
+void VM_getsurfacenumtriangles(void)
+{
+ dp_model_t *model;
+ msurface_t *surface;
+ VM_SAFEPARMCOUNT(2, VM_SV_getsurfacenumtriangles);
+ // return 0 if no such surface
+ if (!(model = getmodel(PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
+ {
+ PRVM_G_FLOAT(OFS_RETURN) = 0;
+ return;
+ }
+
+ // note: this (incorrectly) assumes it is a simple polygon
+ PRVM_G_FLOAT(OFS_RETURN) = surface->num_triangles;
+}
+//PF_getsurfacetriangle, // #??? vector(entity e, float s, float n) getsurfacetriangle = #???;
+void VM_getsurfacetriangle(void)
+{
+ const vec3_t d = {-1, -1, -1};
+ prvm_edict_t *ed;
+ dp_model_t *model;
+ msurface_t *surface;
+ int trinum;
+ VM_SAFEPARMCOUNT(3, VM_SV_getsurfacetriangle);
+ VectorClear(PRVM_G_VECTOR(OFS_RETURN));
+ ed = PRVM_G_EDICT(OFS_PARM0);
+ if (!(model = getmodel(ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
+ return;
+ trinum = (int)PRVM_G_FLOAT(OFS_PARM2);
+ if (trinum < 0 || trinum >= surface->num_triangles)
+ return;
+ // FIXME: implement rotation/scaling
+ VectorMA(&(model->surfmesh.data_element3i + 3 * surface->num_firsttriangle)[trinum * 3], surface->num_firstvertex, d, PRVM_G_VECTOR(OFS_RETURN));
+}
+
+//
+// physics builtins
+//
+
+void World_Physics_ApplyCmd(prvm_edict_t *ed, edict_odefunc_t *f);
+
+#define VM_physics_ApplyCmd(ed,f) if (!ed->priv.server->ode_body) VM_physics_newstackfunction(ed, f); else World_Physics_ApplyCmd(ed, f)
+
+edict_odefunc_t *VM_physics_newstackfunction(prvm_edict_t *ed, edict_odefunc_t *f)
+{
+ edict_odefunc_t *newfunc, *func;
+
+ newfunc = (edict_odefunc_t *)Mem_Alloc(prog->progs_mempool, sizeof(edict_odefunc_t));
+ memcpy(newfunc, f, sizeof(edict_odefunc_t));
+ newfunc->next = NULL;
+ if (!ed->priv.server->ode_func)
+ ed->priv.server->ode_func = newfunc;
+ else
+ {
+ for (func = ed->priv.server->ode_func; func->next; func = func->next);
+ func->next = newfunc;
+ }
+ return newfunc;
+}
+
+// void(entity e, float physics_enabled) physics_enable = #;
+void VM_physics_enable(void)
+{
+ prvm_edict_t *ed;
+ edict_odefunc_t f;
+
+ VM_SAFEPARMCOUNT(2, VM_physics_enable);
+ ed = PRVM_G_EDICT(OFS_PARM0);
+ if (!ed)
+ {
+ if (developer.integer > 0)
+ VM_Warning("VM_physics_enable: null entity!\n");
+ return;
+ }
+ // entity should have MOVETYPE_PHYSICS already set, this can damage memory (making leaked allocation) so warn about this even if non-developer
+ if (ed->fields.server->movetype != MOVETYPE_PHYSICS)
+ {
+ VM_Warning("VM_physics_enable: entity is not MOVETYPE_PHYSICS!\n");
+ return;
+ }
+ f.type = PRVM_G_FLOAT(OFS_PARM1) == 0 ? ODEFUNC_DISABLE : ODEFUNC_ENABLE;
+ VM_physics_ApplyCmd(ed, &f);
+}
+
+// void(entity e, vector force, vector relative_ofs) physics_addforce = #;
+void VM_physics_addforce(void)
+{
+ prvm_edict_t *ed;
+ edict_odefunc_t f;
+
+ VM_SAFEPARMCOUNT(3, VM_physics_addforce);
+ ed = PRVM_G_EDICT(OFS_PARM0);
+ if (!ed)
+ {
+ if (developer.integer > 0)
+ VM_Warning("VM_physics_addforce: null entity!\n");
+ return;
+ }
+ // entity should have MOVETYPE_PHYSICS already set, this can damage memory (making leaked allocation) so warn about this even if non-developer
+ if (ed->fields.server->movetype != MOVETYPE_PHYSICS)
+ {
+ VM_Warning("VM_physics_addforce: entity is not MOVETYPE_PHYSICS!\n");
+ return;
+ }
+ f.type = ODEFUNC_RELFORCEATPOS;
+ VectorCopy(PRVM_G_VECTOR(OFS_PARM1), f.v1);
+ VectorSubtract(ed->fields.server->origin, PRVM_G_VECTOR(OFS_PARM2), f.v2);
+ VM_physics_ApplyCmd(ed, &f);
+}
+
+// void(entity e, vector torque) physics_addtorque = #;
+void VM_physics_addtorque(void)
+{
+ prvm_edict_t *ed;
+ edict_odefunc_t f;
+
+ VM_SAFEPARMCOUNT(2, VM_physics_addtorque);
+ ed = PRVM_G_EDICT(OFS_PARM0);
+ if (!ed)
+ {
+ if (developer.integer > 0)
+ VM_Warning("VM_physics_addtorque: null entity!\n");
+ return;
+ }
+ // entity should have MOVETYPE_PHYSICS already set, this can damage memory (making leaked allocation) so warn about this even if non-developer
+ if (ed->fields.server->movetype != MOVETYPE_PHYSICS)
+ {
+ VM_Warning("VM_physics_addtorque: entity is not MOVETYPE_PHYSICS!\n");
+ return;
+ }
+ f.type = ODEFUNC_RELTORQUE;
+ VectorCopy(PRVM_G_VECTOR(OFS_PARM1), f.v1);
+ VM_physics_ApplyCmd(ed, &f);
+}