fix gles1 issues (read: android port now works again).

update csaddon code.
qclib now understands 'objects'. engine+qcc does not use them yet.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4987 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2015-09-14 10:36:42 +00:00
parent a38a933fdd
commit da316ce374
31 changed files with 2146 additions and 811 deletions

View File

@ -382,6 +382,7 @@ typedef struct csqcedict_s
qboolean isfree;
float freetime; // sv.time when the object was freed
int entnum;
unsigned int fieldsize;
qboolean readonly; //world
#ifdef VM_Q1
csqcentvars_t *v;
@ -4384,7 +4385,7 @@ qboolean CSQC_DeltaPlayer(int playernum, player_state_t *state)
ent = csqcdelta_playerents[playernum];
if (!ent)
{
ent = (csqcedict_t *)ED_Alloc(csqcprogs);
ent = (csqcedict_t *)ED_Alloc(csqcprogs, false, 0);
ent->xv->drawmask = MASK_DELTA;
}
@ -4460,7 +4461,7 @@ qboolean CSQC_DeltaUpdate(entity_state_t *src)
ent = oldent;
else
{
ent = (csqcedict_t *)ED_Alloc(csqcprogs);
ent = (csqcedict_t *)ED_Alloc(csqcprogs, false, 0);
ent->xv->drawmask = MASK_DELTA;
}
@ -7300,7 +7301,7 @@ void CSQC_ParseEntities(void)
ent = csqcent[entnum];
if (!ent)
{
ent = (csqcedict_t*)ED_Alloc(csqcprogs);
ent = (csqcedict_t*)ED_Alloc(csqcprogs, false, 0);
csqcent[entnum] = ent;
ent->xv->entnum = entnum;
G_FLOAT(OFS_PARM0) = true;

View File

@ -1057,6 +1057,7 @@ typedef struct menuedict_s
qboolean isfree;
float freetime; // sv.time when the object was freed
int entnum;
unsigned int fieldsize;
qboolean readonly; //world
void *fields;
} menuedict_t;

View File

@ -2480,7 +2480,7 @@ static const char *If_Token_Term(const char *func, const char **end)
else if (!strcmp(com_token, "eval"))
{
//read the stuff to the right
func = If_Token(s, end, IFPUNCT);
func = If_Token(s, end, IF_PRI_MAX);
//and evaluate it
s2 = If_Token(func, &func, IF_PRI_MAX);
}

View File

@ -1535,14 +1535,14 @@ static void Alias_DrawSkeletalBones(galiasbone_t *bones, float *bonepose, int bo
#else
PPL_RevertToKnownState();
BE_SelectEntity(currententity);
qglColor3f(1, 0, 0);
qglColor4f(1, 0, 0, 1);
{
int i;
int p;
// vec3_t org, dest;
qglBegin(GL_LINES);
qglColor3f(0, 0, 1);
qglColor4f(0, 0, 1, 1);
for (i = 0; i < basebone; i++)
{
p = bones[i].parent;
@ -1551,7 +1551,7 @@ static void Alias_DrawSkeletalBones(galiasbone_t *bones, float *bonepose, int bo
qglVertex3f(bonepose[i*12+3], bonepose[i*12+7], bonepose[i*12+11]);
qglVertex3f(bonepose[p*12+3], bonepose[p*12+7], bonepose[p*12+11]);
}
qglColor3f(1, 0, 0);
qglColor4f(1, 0, 0, 1);
for (; i < bonecount; i++)
{
p = bones[i].parent;
@ -1561,7 +1561,7 @@ static void Alias_DrawSkeletalBones(galiasbone_t *bones, float *bonepose, int bo
qglVertex3f(bonepose[p*12+3], bonepose[p*12+7], bonepose[p*12+11]);
}
qglEnd();
qglColor3f(1, 1, 1);
qglColor4f(1, 1, 1, 1);
/* qglBegin(GL_LINES);
for (i = 0; i < bonecount; i++)
{

View File

@ -2619,7 +2619,17 @@ void QCBUILTIN PF_nextent (pubprogfuncs_t *prinst, struct globalvars_s *pr_globa
void QCBUILTIN PF_Spawn (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
struct edict_s *ed;
ed = ED_Alloc(prinst);
ed = ED_Alloc(prinst, false, 0);
pr_globals = PR_globals(prinst, PR_CURRENT);
RETURN_EDICT(prinst, ed);
}
void QCBUILTIN PF_spawn_object (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
int obj = G_INT(OFS_PARM0);
int size = G_INT(OFS_PARM1);
struct edict_s *ed;
ed = ED_Alloc(prinst, obj, size);
pr_globals = PR_globals(prinst, PR_CURRENT);
RETURN_EDICT(prinst, ed);
}
@ -2635,16 +2645,20 @@ void QCBUILTIN PF_copyentity (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl
in = G_WEDICT(prinst, OFS_PARM0);
if (prinst->callargc <= 1)
out = (wedict_t*)ED_Alloc(prinst);
out = (wedict_t*)ED_Alloc(prinst, false, 0);
else
out = G_WEDICT(prinst, OFS_PARM1);
if (in->isfree)
PR_BIError(prinst, "PF_copyentity: source is free");
if (!out || out->isfree)
PR_BIError(prinst, "PF_copyentity: destination is free");
if (out->readonly)
PR_BIError(prinst, "PF_copyentity: destination is read-only");
if (out->fieldsize != in->fieldsize)
PR_BIError(prinst, "PF_copyentity: different object types");
memcpy(out->v, in->v, w->edict_size);
memcpy(out->v, in->v, out->fieldsize);
World_LinkEdict(w, out, false);
RETURN_EDICT(prinst, out);

View File

@ -10,6 +10,7 @@ typedef struct edict_s {
float freetime; // realtime when the object was freed
unsigned int entnum;
unsigned int fieldsize;
pbool readonly; //causes error when QC tries writing to it. (quake's world entity)
void *v;
} edict_t;
@ -20,6 +21,7 @@ struct wedict_s
qboolean isfree;
float freetime; // sv.time when the object was freed
int entnum;
unsigned int fieldsize;
qboolean readonly; //world
#ifdef VM_Q1
comentvars_t *v;

View File

@ -1015,7 +1015,7 @@ int Fragment_ClipPolyToPlane(float *inverts, float *outverts, int incount, float
int outcount = 0;
int clippedcount = 0;
float d, *p1, *p2, *out;
#define FRAG_EPSILON 0.5
#define FRAG_EPSILON (1.0/32) //0.5
for (i = 0; i < incount; i++)
{

View File

@ -1018,7 +1018,7 @@ static void RevertToKnownState(void)
if (!gl_config_nofixedfunc)
{
BE_SetPassBlendMode(0, PBM_REPLACE);
qglColor3f(1,1,1);
qglColor4f(1,1,1,1);
GL_DeSelectProgram();
}

View File

@ -3723,7 +3723,6 @@ static void Heightmap_Trace_Square(hmtrace_t *tr, int tx, int ty)
vec3_t d[2];
vec3_t p[4];
vec4_t n[6];
int t;
int i;
#ifndef STRICTEDGES
@ -5074,7 +5073,7 @@ void Terr_ParseEntityLump(char *data, heightmap_t *heightmap)
heightmap->sectionsize = 1024;
heightmap->mode = HMM_TERRAIN;
heightmap->culldistance = 4096;
heightmap->culldistance = 4096*4096;
heightmap->defaultgroundheight = 0;
heightmap->defaultwaterheight = 0;
@ -5113,7 +5112,10 @@ void Terr_ParseEntityLump(char *data, heightmap_t *heightmap)
else if (!strcmp("defaultwatertexture", key))
Q_strncpyz(heightmap->defaultwatershader, value, sizeof(heightmap->defaultwatershader));
else if (!strcmp("culldistance", key))
{
heightmap->culldistance = atof(value);
heightmap->culldistance *= heightmap->culldistance;
}
else if (!strcmp("skybox", key))
Q_strncpyz(heightmap->skyname, value, sizeof(heightmap->skyname));
else if (!strcmp("tiles", key))
@ -5247,7 +5249,7 @@ void Terr_FinishTerrain(model_t *mod)
int Fragment_ClipPolyToPlane(float *inverts, float *outverts, int incount, float *plane, float planedist);
static size_t Terr_GenerateBrushFace(vecV_t *points, size_t maxpoints, vec4_t *planes, size_t numplanes, vec4_t face)
{
int p;
int p, a;
vec4_t verts[128];
vec4_t verts2[128];
vec4_t *cverts;
@ -5314,7 +5316,14 @@ static size_t Terr_GenerateBrushFace(vecV_t *points, size_t maxpoints, vec4_t *p
cverts = verts;
for (p = 0; p < numverts; p++)
{
VectorCopy(cverts[p], points[p]);
for (a = 0; a < 3; a++)
{
//if its within 1/1000th of a qu, just call it okay.
if ((int)points[p][a] * 1000 == (int)(points[p][a]*1000))
points[p][a] = floor(cverts[p][a] + 0.5);
else
points[p][a] = cverts[p][a];
}
}
return numverts;
@ -5353,7 +5362,7 @@ void Terr_Brush_Draw(heightmap_t *hm, batch_t **batches, entity_t *e)
//allocate lightmap space for all surfaces, and then rebuild all textures.
//if a surface is modified, clear its lightmap to -1 and when its batches are rebuilt, it'll unlight naturally.
if (hm->recalculatebrushlighting)
if (hm->recalculatebrushlighting && !r_fullbright.ival)
{
unsigned int lmcount;
unsigned int lmblocksize = 512;//LMBLOCK_SIZE_MAX
@ -5439,7 +5448,7 @@ void Terr_Brush_Draw(heightmap_t *hm, batch_t **batches, entity_t *e)
}
}
if (hm->relightcontext)
if (hm->relightcontext && !r_fullbright.ival)
for (i = 0, br = hm->wbrushes; i < hm->numbrushes; i++, br++)
{
for (j = 0; j < br->numplanes; j++)
@ -5486,17 +5495,69 @@ void Terr_Brush_Draw(heightmap_t *hm, batch_t **batches, entity_t *e)
in = br->faces[j].lightdata;
out = lm->lightmaps + (br->faces[j].lmbase[1] * lm->width + br->faces[j].lmbase[0]) * lightmap_bytes;
for (t = 0; t < br->faces[j].lmextents[1]; t++)
if (lightmap_bytes == 4)
{
for (s = 0; s < br->faces[j].lmextents[0]; s++)
if (lightmap_bgra)
{
*out++ = in[2];
*out++ = in[1];
*out++ = in[0];
*out++ = 0xff;
in+=3;
for (t = 0; t < br->faces[j].lmextents[1]; t++)
{
for (s = 0; s < br->faces[j].lmextents[0]; s++)
{
*out++ = in[2];
*out++ = in[1];
*out++ = in[0];
*out++ = 0xff;
in+=3;
}
out += (lm->width - br->faces[j].lmextents[0]) * 4;
}
}
else
{
for (t = 0; t < br->faces[j].lmextents[1]; t++)
{
for (s = 0; s < br->faces[j].lmextents[0]; s++)
{
*out++ = in[0];
*out++ = in[1];
*out++ = in[2];
*out++ = 0xff;
in+=3;
}
out += (lm->width - br->faces[j].lmextents[0]) * 4;
}
}
}
else if (lightmap_bytes == 3)
{
if (lightmap_bgra)
{
for (t = 0; t < br->faces[j].lmextents[1]; t++)
{
for (s = 0; s < br->faces[j].lmextents[0]; s++)
{
*out++ = in[2];
*out++ = in[1];
*out++ = in[0];
in+=3;
}
out += (lm->width - br->faces[j].lmextents[0]) * 3;
}
}
else
{
for (t = 0; t < br->faces[j].lmextents[1]; t++)
{
for (s = 0; s < br->faces[j].lmextents[0]; s++)
{
*out++ = in[0];
*out++ = in[1];
*out++ = in[2];
in+=3;
}
out += (lm->width - br->faces[j].lmextents[0]) * 3;
}
}
out += (lm->width - br->faces[j].lmextents[0]) * lightmap_bytes;
}
}
}
@ -5507,25 +5568,33 @@ void Terr_Brush_Draw(heightmap_t *hm, batch_t **batches, entity_t *e)
{
if (!bt->shader)
{
miptex_t *tx = W_GetMipTex(bt->shadername);
if (!Q_strcasecmp(bt->shadername, "clip"))
bt->shader = R_RegisterShader(bt->shadername, SUF_LIGHTMAP, "{\nsurfaceparm nodraw\n}");
else
bt->shader = R_RegisterCustom (bt->shadername, SUF_LIGHTMAP, Shader_DefaultBSPQ1, NULL);
// bt->shader = R_RegisterShader_Lightmap(bt->shadername);
if (!Q_strncasecmp(bt->shadername, "sky", 3))
if (!Q_strncasecmp(bt->shadername, "sky", 3) && tx)
R_InitSky (bt->shader, bt->shadername, (qbyte*)tx + tx->offsets[0], tx->width, tx->height);
else if (tx)
{
miptex_t *tx = W_GetMipTex(bt->shadername);
if (tx)
{
R_InitSky (bt->shader, bt->shadername, (qbyte*)tx + tx->offsets[0], tx->width, tx->height);
BZ_Free(tx);
}
else
R_BuildDefaultTexnums(NULL, bt->shader);
qbyte *mips[4] = {(qbyte*)tx + tx->offsets[0], (qbyte*)tx + tx->offsets[1], (qbyte*)tx + tx->offsets[2], (qbyte*)tx + tx->offsets[3]};
unsigned int mapflags = SHADER_HASPALETTED | SHADER_HASDIFFUSE | SHADER_HASFULLBRIGHT | SHADER_HASNORMALMAP | SHADER_HASGLOSS;
R_BuildLegacyTexnums(bt->shader, tx->name, NULL, mapflags, TF_BGRA32, tx->width, tx->height, mips, NULL);
}
else
R_BuildDefaultTexnums(NULL, bt->shader);
if (tx)
{
if (!bt->shader->width)
bt->shader->width = tx->width;
if (!bt->shader->height)
bt->shader->height = tx->height;
BZ_Free(tx);
}
}
if (bt->rebuild)
@ -5565,7 +5634,7 @@ void Terr_Brush_Draw(heightmap_t *hm, batch_t **batches, entity_t *e)
for (j = 0; j < br->numplanes; j++)
{
if (br->faces[j].tex == bt /*&& !br->selected*/ && br->faces[j].lightmap == lmnum)
if (br->faces[j].tex == bt && !br->selected && br->faces[j].lightmap == lmnum)
{
size_t k, o;
float s,t;
@ -5640,7 +5709,7 @@ void Terr_Brush_Draw(heightmap_t *hm, batch_t **batches, entity_t *e)
{
j = 0;
if (bb->lightmap >= 0)
b->lightmap[j++] = hm->brushlmremaps[bb->lightmap];
b->lightmap[j++] = r_fullbright.ival?-1:hm->brushlmremaps[bb->lightmap];
for (; j < MAXRLIGHTMAPS; j++)
b->lightmap[j] = -1;
b->ent = e;
@ -6035,7 +6104,7 @@ typedef struct
float tbias;
} qcbrushface_t;
static void *validateqcpointer(pubprogfuncs_t *prinst, size_t qcptr, size_t elementsize, size_t elementcount)
static void *validateqcpointer(pubprogfuncs_t *prinst, size_t qcptr, size_t elementsize, size_t elementcount, qboolean allownull)
{
//make sure that the sizes can't overflow
if (elementcount > 0x10000)
@ -6048,6 +6117,12 @@ static void *validateqcpointer(pubprogfuncs_t *prinst, size_t qcptr, size_t elem
PR_BIError(prinst, "brush: invalid qc pointer\n");
return NULL;
}
if (!qcptr)
{
if (!allownull)
PR_BIError(prinst, "brush: null qc pointer\n");
return NULL;
}
return prinst->stringtable + qcptr;
}
// {"brush_get", PF_brush_get, 0, 0, 0, 0, D(qcbrushface "int(float modelidx, int brushid, brushface_t *out_faces, int maxfaces, int *out_contents)", "Queries a brush's information. You must pre-allocate the face array for the builtin to write to. Return value is the number of faces retrieved, 0 on error.")},
@ -6058,14 +6133,14 @@ void QCBUILTIN PF_brush_get(pubprogfuncs_t *prinst, struct globalvars_s *pr_glob
heightmap_t *hm = mod?mod->terrain:NULL;
unsigned int brushid = G_INT(OFS_PARM1);
unsigned int maxfaces = G_INT(OFS_PARM3);
qcbrushface_t *out_faces = validateqcpointer(prinst, G_INT(OFS_PARM2), sizeof(*out_faces), maxfaces);
unsigned int *out_contents = validateqcpointer(prinst, G_INT(OFS_PARM4), sizeof(*out_contents), 1);
qcbrushface_t *out_faces = validateqcpointer(prinst, G_INT(OFS_PARM2), sizeof(*out_faces), maxfaces, true);
unsigned int *out_contents = validateqcpointer(prinst, G_INT(OFS_PARM4), sizeof(*out_contents), 1, true);
unsigned int fa, i;
brushes_t *br;
//assume the worst.
G_INT(OFS_RETURN) = 0;
if (G_INT(OFS_PARM4))
if (out_contents)
*out_contents = 0;
if (!hm)
@ -6076,9 +6151,9 @@ void QCBUILTIN PF_brush_get(pubprogfuncs_t *prinst, struct globalvars_s *pr_glob
br = &hm->wbrushes[i];
if (br->id == brushid)
{
if (G_INT(OFS_PARM4))
if (out_contents)
*out_contents = br->contents;
if (!G_INT(OFS_PARM2))
if (!out_faces)
G_INT(OFS_RETURN) = br->numplanes;
else
{
@ -6110,7 +6185,7 @@ void QCBUILTIN PF_brush_create(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
model_t *mod = vmw->Get_CModel(vmw, G_FLOAT(OFS_PARM0));
heightmap_t *hm = mod?mod->terrain:NULL;
unsigned int numfaces = G_INT(OFS_PARM2);
qcbrushface_t *in_faces = validateqcpointer(prinst, G_INT(OFS_PARM1), sizeof(*in_faces), numfaces);
qcbrushface_t *in_faces = validateqcpointer(prinst, G_INT(OFS_PARM1), sizeof(*in_faces), numfaces, false);
unsigned int contents = G_INT(OFS_PARM3);
unsigned int i;
@ -6269,9 +6344,9 @@ void QCBUILTIN PF_brush_calcfacepoints(pubprogfuncs_t *prinst, struct globalvars
{
unsigned int faceid = G_INT(OFS_PARM0);
unsigned int numfaces = G_INT(OFS_PARM2);
qcbrushface_t *in_faces = validateqcpointer(prinst, G_INT(OFS_PARM1), sizeof(*in_faces), numfaces);
qcbrushface_t *in_faces = validateqcpointer(prinst, G_INT(OFS_PARM1), sizeof(*in_faces), numfaces, false);
unsigned int maxpoints = G_INT(OFS_PARM4);
vec3_t *out_verts = validateqcpointer(prinst, G_INT(OFS_PARM3), sizeof(*out_verts), maxpoints);
vec3_t *out_verts = validateqcpointer(prinst, G_INT(OFS_PARM3), sizeof(*out_verts), maxpoints, false);
vecV_t facepoints[256];
vec4_t planes[256];
unsigned int j, numpoints;
@ -6325,7 +6400,7 @@ void QCBUILTIN PF_brush_getfacepoints(pubprogfuncs_t *prinst, struct globalvars_
unsigned int brushid = G_INT(OFS_PARM1);
unsigned int faceid = G_INT(OFS_PARM2);
unsigned int maxpoints = G_INT(OFS_PARM4), p;
vec3_t *out_verts = validateqcpointer(prinst, G_INT(OFS_PARM3), sizeof(*out_verts), maxpoints);
vec3_t *out_verts = validateqcpointer(prinst, G_INT(OFS_PARM3), sizeof(*out_verts), maxpoints, false);
size_t i;
brushes_t *br;
@ -6374,11 +6449,11 @@ void QCBUILTIN PF_brush_findinvolume(pubprogfuncs_t *prinst, struct globalvars_s
model_t *mod = vmw->Get_CModel(vmw, G_FLOAT(OFS_PARM0));
heightmap_t *hm = mod?mod->terrain:NULL;
int in_numplanes = G_INT(OFS_PARM3);
vec3_t *in_normals = validateqcpointer(prinst, G_INT(OFS_PARM1), sizeof(*in_normals), in_numplanes);
float *in_distances = validateqcpointer(prinst, G_INT(OFS_PARM2), sizeof(*in_distances), in_numplanes);
vec3_t *in_normals = validateqcpointer(prinst, G_INT(OFS_PARM1), sizeof(*in_normals), in_numplanes, false);
float *in_distances = validateqcpointer(prinst, G_INT(OFS_PARM2), sizeof(*in_distances), in_numplanes, false);
unsigned int maxresults = G_INT(OFS_PARM6);
unsigned int *out_brushids = validateqcpointer(prinst, G_INT(OFS_PARM4), sizeof(*out_brushids), maxresults);
unsigned int *out_faceids = G_INT(OFS_PARM5)?validateqcpointer(prinst, G_INT(OFS_PARM5), sizeof(*out_faceids), maxresults):NULL;
unsigned int *out_brushids = validateqcpointer(prinst, G_INT(OFS_PARM4), sizeof(*out_brushids), maxresults, false);
unsigned int *out_faceids = G_INT(OFS_PARM5)?validateqcpointer(prinst, G_INT(OFS_PARM5), sizeof(*out_faceids), maxresults, false):NULL;
unsigned int i, j, k, r = 0;
brushes_t *br;
vec3_t best;
@ -6569,12 +6644,6 @@ void Mod_Terrain_Save_f(void)
}
else
{
if (mod->type != mod_brush)
{
Con_Printf("that model isn't a suitable worldmodel\n");
return;
}
FS_CreatePath(fname, FS_GAMEONLY);
file = FS_OpenVFS(fname, "wb", FS_GAMEONLY);
if (!file)
@ -6721,9 +6790,9 @@ qboolean Terr_ReformEntitiesLump(model_t *mod, heightmap_t *hm, char *entities)
else if (inbrush)
{
//parse a plane
//( -0 -0 16 ) ( -0 -0 32 ) ( 64 -0 16 ) texname 0 -32 rotation sscale tscale
//( -0 -0 16 ) ( -0 -0 32 ) ( 64 -0 16 ) texname [x y z d] [x y z d] rotation sscale tscale
//( 0 0 1 16 ) texname [x y z d] [x y z d] rotation sscale tscale
//Quake: ( -0 -0 16 ) ( -0 -0 32 ) ( 64 -0 16 ) texname 0 -32 rotation sscale tscale
//Valve: ( -0 -0 16 ) ( -0 -0 32 ) ( 64 -0 16 ) texname [x y z d] [x y z d] rotation sscale tscale
//fte : ( px py pz pd ) texname [sx sy sz sd] [tx ty tz td] 0 1 1
brushtex_t *bt;
vec3_t d1,d2;
vec3_t points[3];

View File

@ -2790,9 +2790,13 @@ static void Sh_DrawStencilLightShadows(dlight_t *dl, qbyte *lvis, qbyte *vvis, q
if (qrenderer == QR_DIRECT3D11)
return;
if (qrenderer != QR_OPENGL)
return; //FIXME: uses glBegin specifics.
#ifdef GLQUAKE
if (gl_config.nofixedfunc)
if (gl_config_nofixedfunc)
return; /*hackzone*/
if (gl_config_gles)
return; //FIXME: uses glBegin
#endif
// draw sprites seperately, because of alpha blending
@ -2943,7 +2947,7 @@ static qboolean Sh_DrawStencilLight(dlight_t *dl, vec3_t colour, vec3_t axis[3],
// if (r_shadows.value == 666) //testing (visible shadow volumes)
{
qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
qglColor3f(dl->color[0], dl->color[1], dl->color[2]);
qglColor4f(dl->color[0], dl->color[1], dl->color[2], 1);
qglDisable(GL_STENCIL_TEST);
// qglEnable(GL_POLYGON_OFFSET_FILL);
// qglPolygonOffset(-1, -1);

View File

@ -105,12 +105,12 @@ void (APIENTRY *qglBegin) (GLenum mode);
void (APIENTRY *qglCallList) (GLuint list);
void (APIENTRY *qglClearDepth) (GLclampd depth);
void (APIENTRY *qglClipPlane) (GLenum plane, const GLdouble *equation);
void (APIENTRY *qglColor3f) (GLfloat red, GLfloat green, GLfloat blue);
void (APIENTRY *qglColor3ub) (GLubyte red, GLubyte green, GLubyte blue);
//void (APIENTRY *qglColor3f) (GLfloat red, GLfloat green, GLfloat blue);
//void (APIENTRY *qglColor3ub) (GLubyte red, GLubyte green, GLubyte blue);
void (APIENTRY *qglColor4f) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
void (APIENTRY *qglColor4fv) (const GLfloat *v);
void (APIENTRY *qglColor4ub) (GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha);
void (APIENTRY *qglColor4ubv) (const GLubyte *v);
//void (APIENTRY *qglColor4ub) (GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha);
//void (APIENTRY *qglColor4ubv) (const GLubyte *v);
void (APIENTRY *qglDepthRange) (GLclampd zNear, GLclampd zFar);
void (APIENTRY *qglDrawBuffer) (GLenum mode);
void (APIENTRY *qglDrawPixels) (GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
@ -394,6 +394,12 @@ void APIENTRY GL_DrawRangeElementsEmul(GLenum mode, GLuint start, GLuint end, GL
{
qglDrawElements(mode, count, type, indices);
}
void APIENTRY GL_Color4fv_Emul(const GLfloat *v)
{
qglColor4f(v[0], v[1], v[2], v[3]);
}
void APIENTRY GL_BindBufferARBStub(GLenum target, GLuint id)
{
}
@ -448,6 +454,15 @@ void GL_CheckExtensions (void *(*getglfunction) (char *name))
s++;
gl_minor_version = atoi(s);
}
#ifdef _DEBUG
{ extern cvar_t vid_gl_context_es;
if (vid_gl_context_es.ival == 3)
{
gl_config.gles = true;
gl_major_version = 1;
gl_minor_version = 0;
} }
#endif
if (webgl) //webgl version 1 equates to gles 2.
{
if (gl_major_version < 1)
@ -494,6 +509,14 @@ void GL_CheckExtensions (void *(*getglfunction) (char *name))
Sys_Error("no extensions\n");
}
#ifdef _DEBUG
{ extern cvar_t vid_gl_context_es;
if (vid_gl_context_es.ival == 3)
{
gl_extensions = "";
} }
#endif
if (gl_config.gles)
gl_config.nofixedfunc = gl_config.glversion >= 2;
else
@ -2482,12 +2505,14 @@ void GL_Init(void *(*getglfunction) (char *name))
qglBegin = (void *)getglcore("glBegin");
qglClearDepth = (void *)getglcore("glClearDepth");
qglClipPlane = (void *)getglcore("glClipPlane");
qglColor3f = (void *)getglcore("glColor3f");
qglColor3ub = (void *)getglcore("glColor3ub");
// qglColor3f = (void *)getglcore("glColor3f");
// qglColor3ub = (void *)getglcore("glColor3ub");
qglColor4f = (void *)getglcore("glColor4f");
qglColor4fv = (void *)getglcore("glColor4fv");
qglColor4ub = (void *)getglcore("glColor4ub");
qglColor4ubv = (void *)getglcore("glColor4ubv");
qglColor4fv = (void *)getglext("glColor4fv");
if (!qglColor4fv)
qglColor4fv = GL_Color4fv_Emul; //can be missing in gles1
// qglColor4ub = (void *)getglcore("glColor4ub");
// qglColor4ubv = (void *)getglcore("glColor4ubv");
qglDepthRange = (void *)getglcore("glDepthRange");
qglDrawBuffer = (void *)getglcore("glDrawBuffer");
qglDrawPixels = (void *)getglcore("glDrawPixels");

View File

@ -345,6 +345,166 @@ static char *gles2funcs[] =
f(wglCreateContextAttribsARB)
NULL
};
//this is a list of the functions that exist in opengles2, as well as wglCreateContextAttribsARB.
//functions not in this list *should* be stubs that just return errors, but we can't always depend on drivers for that... they shouldn't get called.
//this list is just to make it easier to test+debug android gles2 stuff using windows.
static char *gles1funcs[] =
{
#define f(n) #n,
/* Available only in Common profile */
f(glAlphaFunc)
f(glClearColor)
f(glClearDepthf)
f(glClipPlanef)
f(glColor4f)
f(glDepthRangef)
f(glFogf)
f(glFogfv)
f(glFrustumf)
f(glGetClipPlanef)
f(glGetFloatv)
f(glGetLightfv)
f(glGetMaterialfv)
f(glGetTexEnvfv)
f(glGetTexParameterfv)
f(glLightModelf)
f(glLightModelfv)
f(glLightf)
f(glLightfv)
f(glLineWidth)
f(glLoadMatrixf)
f(glMaterialf)
f(glMaterialfv)
f(glMultMatrixf)
f(glMultiTexCoord4f)
f(glNormal3f)
f(glOrthof)
f(glPointParameterf)
f(glPointParameterfv)
f(glPointSize)
f(glPolygonOffset)
f(glRotatef)
f(glScalef)
f(glTexEnvf)
f(glTexEnvfv)
f(glTexParameterf)
f(glTexParameterfv)
f(glTranslatef)
/* Available in both Common and Common-Lite profiles */
f(glActiveTexture)
f(glAlphaFuncx)
f(glBindBuffer)
f(glBindTexture)
f(glBlendFunc)
f(glBufferData)
f(glBufferSubData)
f(glClear)
f(glClearColorx)
f(glClearDepthx)
f(glClearStencil)
f(glClientActiveTexture)
f(glClipPlanex)
f(glColor4ub)
f(glColor4x)
f(glColorMask)
f(glColorPointer)
f(glCompressedTexImage2D)
f(glCompressedTexSubImage2D)
f(glCopyTexImage2D)
f(glCopyTexSubImage2D)
f(glCullFace)
f(glDeleteBuffers)
f(glDeleteTextures)
f(glDepthFunc)
f(glDepthMask)
f(glDepthRangex)
f(glDisable)
f(glDisableClientState)
f(glDrawArrays)
f(glDrawElements)
f(glEnable)
f(glEnableClientState)
f(glFinish)
f(glFlush)
f(glFogx)
f(glFogxv)
f(glFrontFace)
f(glFrustumx)
f(glGetBooleanv)
f(glGetBufferParameteriv)
f(glGetClipPlanex)
f(glGenBuffers)
f(glGenTextures)
f(glGetError)
f(glGetFixedv)
f(glGetIntegerv)
f(glGetLightxv)
f(glGetMaterialxv)
f(glGetPointerv)
f(glGetString)
f(glGetTexEnviv)
f(glGetTexEnvxv)
f(glGetTexParameteriv)
f(glGetTexParameterxv)
f(glHint)
f(glIsBuffer)
f(glIsEnabled)
f(glIsTexture)
f(glLightModelx)
f(glLightModelxv)
f(glLightx)
f(glLightxv)
f(glLineWidthx)
f(glLoadIdentity)
f(glLoadMatrixx)
f(glLogicOp)
f(glMaterialx)
f(glMaterialxv)
f(glMatrixMode)
f(glMultMatrixx)
f(glMultiTexCoord4x)
f(glNormal3x)
f(glNormalPointer)
f(glOrthox)
f(glPixelStorei)
f(glPointParameterx)
f(glPointParameterxv)
f(glPointSizex)
f(glPolygonOffsetx)
f(glPopMatrix)
f(glPushMatrix)
f(glReadPixels)
f(glRotatex)
f(glSampleCoverage)
f(glSampleCoveragex)
f(glScalex)
f(glScissor)
f(glShadeModel)
f(glStencilFunc)
f(glStencilMask)
f(glStencilOp)
f(glTexCoordPointer)
f(glTexEnvi)
f(glTexEnvx)
f(glTexEnviv)
f(glTexEnvxv)
f(glTexImage2D)
f(glTexParameteri)
f(glTexParameterx)
f(glTexParameteriv)
f(glTexParameterxv)
f(glTexSubImage2D)
f(glTranslatex)
f(glVertexPointer)
f(glViewport)
/*required to switch stuff around*/
f(wglCreateContextAttribsARB)
NULL
};
#endif
//just GetProcAddress with a safty net.
@ -363,6 +523,16 @@ void *getglfunc(char *name)
}
#ifdef _DEBUG
if (vid_gl_context_es.ival == 3)
{
int i;
for (i = 0; gles1funcs[i]; i++)
{
if (!strcmp(name, gles1funcs[i]))
return proc;
}
return NULL;
}
if (vid_gl_context_es.ival == 2)
{
int i;

View File

@ -26,7 +26,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include <ctype.h>
static void R_CalcSkyChainBounds (batch_t *s);
static void GL_DrawSkyGrid (texture_t *tex);
static void GL_DrawSkyGrid (texnums_t *tex);
static void GL_DrawSkySphere (batch_t *fa, shader_t *shader);
static void GL_SkyForceDepth(batch_t *fa);
static void GL_DrawSkyBox (texid_t *texnums, batch_t *s);
@ -90,12 +90,12 @@ void R_DrawSkyChain (batch_t *batch)
if (skyshader->numpasses)
{
#if defined(GLQUAKE) && !defined(ANDROID)
if (*r_fastsky.string && qrenderer == QR_OPENGL && TEXVALID(batch->shader->defaulttextures->base) && TEXVALID(batch->shader->defaulttextures->fullbright))
if (*r_fastsky.string && qrenderer == QR_OPENGL && !gl_config_gles && !gl_config_nofixedfunc && TEXVALID(batch->shader->defaulttextures->base) && TEXVALID(batch->shader->defaulttextures->fullbright))
{
R_CalcSkyChainBounds(batch);
R_IBrokeTheArrays();
GL_DrawSkyGrid(batch->texture);
GL_DrawSkyGrid(skyshader->defaulttextures);
R_IBrokeTheArrays();
}
else
@ -638,12 +638,12 @@ static void GL_DrawSkyGridFace (int axis)
qglEnd ();
}
static void GL_DrawSkyGrid (texture_t *tex)
static void GL_DrawSkyGrid (texnums_t *tex)
{
int i;
float time = cl.gametime+realtime-cl.gametimemark;
GL_LazyBind(0, GL_TEXTURE_2D, tex->shader->defaulttextures->base);
GL_LazyBind(0, GL_TEXTURE_2D, tex->base);
speedscale = time*8;
speedscale -= (int)speedscale & ~127;
@ -655,19 +655,22 @@ static void GL_DrawSkyGrid (texture_t *tex)
GL_DrawSkyGridFace (i);
}
qglEnable (GL_BLEND);
GL_LazyBind(0, GL_TEXTURE_2D, tex->shader->defaulttextures->fullbright);
speedscale = time*16;
speedscale -= (int)speedscale & ~127;
for (i = 0; i < 6; i++)
if (tex->fullbright)
{
if ((skymins[0][i] >= skymaxs[0][i] || skymins[1][i] >= skymaxs[1][i]))
continue;
GL_DrawSkyGridFace (i);
qglEnable (GL_BLEND);
GL_LazyBind(0, GL_TEXTURE_2D, tex->fullbright);
speedscale = time*16;
speedscale -= (int)speedscale & ~127;
for (i = 0; i < 6; i++)
{
if ((skymins[0][i] >= skymaxs[0][i] || skymins[1][i] >= skymaxs[1][i]))
continue;
GL_DrawSkyGridFace (i);
}
qglDisable (GL_BLEND);
}
qglDisable (GL_BLEND);
}
#endif

View File

@ -834,12 +834,14 @@ reeval:
break;
case OP_LOADP_V:
i = OPA->_int + OPB->_int*4; //NOTE: inconsistant!
i = OPA->_int + OPB->_int*4; //NOTE: inconsistant, but a bit more practical for the qcc when structs etc are involved
errorif ((unsigned int)i > prinst.addressableused-sizeof(vec3_t))
{
if (i == -1)
{
OPC->_int = 0;
OPC->_vector[0] = 0;
OPC->_vector[1] = 0;
OPC->_vector[2] = 0;
break;
}
pr_xstatement = st-pr_statements;

View File

@ -449,10 +449,10 @@ int PDECL PR_InitEnts(pubprogfuncs_t *ppf, int max_ents)
prinst.max_fields_size = prinst.fields_size;
progfuncs->funcs.edicttable = prinst.edicttable = PRHunkAlloc(progfuncs, prinst.maxedicts*sizeof(struct edicts_s *), "edicttable");
prinst.edicttable = (struct edictrun_s**)(progfuncs->funcs.edicttable = PRHunkAlloc(progfuncs, prinst.maxedicts*sizeof(struct edicts_s *), "edicttable"));
sv_edicts = PRHunkAlloc(progfuncs, externs->edictsize, "edict0");
prinst.edicttable[0] = sv_edicts;
((edictrun_t*)prinst.edicttable[0])->fields = PRAddressableExtend(progfuncs, NULL, prinst.fields_size, prinst.max_fields_size-prinst.fields_size);
progfuncs->funcs.edicttable[0] = sv_edicts;
prinst.edicttable[0]->fields = PRAddressableExtend(progfuncs, NULL, prinst.fields_size, prinst.max_fields_size-prinst.fields_size);
QC_ClearEdict(&progfuncs->funcs, sv_edicts);
sv_num_edicts = 1;
@ -515,12 +515,12 @@ static void PDECL PR_Configure (pubprogfuncs_t *ppf, size_t addressable_size, in
prinst.profiling = profiling;
prinst.maxedicts = 1;
progfuncs->funcs.edicttable = prinst.edicttable = &sv_edicts;
prinst.edicttable = (edictrun_t**)(progfuncs->funcs.edicttable = &sv_edicts);
sv_num_edicts = 1; //set up a safty buffer so things won't go horribly wrong too often
sv_edicts=(struct edict_s *)&tempedict;
tempedict.readonly = true;
tempedict.fields = tempedictfields;
tempedict.isfree = false;
tempedict.ereftype = ER_ENTITY;
}
@ -543,7 +543,7 @@ struct globalvars_s *PDECL PR_globals (pubprogfuncs_t *ppf, progsnum_t pnum)
struct entvars_s *PDECL PR_entvars (pubprogfuncs_t *ppf, struct edict_s *ed)
{
// progfuncs_t *progfuncs = (progfuncs_t*)ppf;
if (((edictrun_t *)ed)->isfree)
if (((edictrun_t *)ed)->ereftype != ER_ENTITY)
return NULL;
return (struct entvars_s *)edvars(ed);

View File

@ -24,21 +24,35 @@ void PDECL QC_ClearEdict (pubprogfuncs_t *ppf, struct edict_s *ed)
progfuncs_t *progfuncs = (progfuncs_t*)ppf;
edictrun_t *e = (edictrun_t *)ed;
int num = e->entnum;
memset (e->fields, 0, prinst.fields_size);
e->isfree = false;
memset (e->fields, 0, e->fieldsize);
e->ereftype = ER_ENTITY;
e->entnum = num;
}
edictrun_t *ED_AllocIntoTable (progfuncs_t *progfuncs, int num)
edictrun_t *ED_AllocIntoTable (progfuncs_t *progfuncs, int num, pbool object, unsigned int fields_size)
{
edictrun_t *e;
prinst.edicttable[num] = *(struct edict_s **)&e = (void*)externs->memalloc(externs->edictsize);
memset(e, 0, externs->edictsize);
e->fields = PRAddressableExtend(progfuncs, NULL, prinst.fields_size, 0);
e->entnum = num;
QC_ClearEdict(&progfuncs->funcs, (struct edict_s*)e);
e = prinst.edicttable[num];
if (!e)
{
e = (void*)externs->memalloc(externs->edictsize);
prinst.edicttable[num] = e;
memset(e, 0, externs->edictsize);
}
if (e->fieldsize != fields_size)
{
if (e->fields)
progfuncs->funcs.AddressableFree(&progfuncs->funcs, e->fields);
e->fields = progfuncs->funcs.AddressableAlloc(&progfuncs->funcs, fields_size);
e->fieldsize = fields_size;
// e->fields = PRAddressableExtend(progfuncs, NULL, fields_size, 0);
}
e->entnum = num;
memset (e->fields, 0, e->fieldsize);
e->ereftype = object?ER_OBJECT:ER_ENTITY;
return e;
}
@ -53,11 +67,35 @@ instead of being removed and recreated, which can cause interpolated
angles and bad trails.
=================
*/
struct edict_s *PDECL ED_Alloc (pubprogfuncs_t *ppf)
struct edict_s *PDECL ED_Alloc (pubprogfuncs_t *ppf, pbool object, size_t extrasize)
{
progfuncs_t *progfuncs = (progfuncs_t*)ppf;
unsigned int i;
edictrun_t *e;
unsigned int fields_size;
fields_size = object?0:prinst.fields_size;
fields_size += extrasize;
if (object)
{
//objects are allocated at the end.
for ( i=prinst.maxedicts-1 ; i>0 ; i--)
{
e = (edictrun_t*)EDICT_NUM(progfuncs, i);
// the first couple seconds of server time can involve a lot of
// freeing and allocating, so relax the replacement policy
if (!e || (e->ereftype==ER_FREE && ( e->freetime < 2 || *externs->gametime - e->freetime > 0.5 ) ))
{
e = ED_AllocIntoTable(progfuncs, i, object, fields_size);
if (externs->entspawn)
externs->entspawn((struct edict_s *) e, false);
return (struct edict_s *)e;
}
}
Sys_Error ("ED_Alloc: no free edicts (max is %i)", prinst.maxedicts);
}
//define this to wastefully allocate extra ents, to test network capabilities.
#define STEP 1//((i <= 32)?1:8)
@ -67,12 +105,9 @@ struct edict_s *PDECL ED_Alloc (pubprogfuncs_t *ppf)
e = (edictrun_t*)EDICT_NUM(progfuncs, i);
// the first couple seconds of server time can involve a lot of
// freeing and allocating, so relax the replacement policy
if (!e || (e->isfree && ( e->freetime < 2 || *externs->gametime - e->freetime > 0.5 ) ))
if (!e || (e->ereftype==ER_FREE && ( e->freetime < 2 || *externs->gametime - e->freetime > 0.5 ) ))
{
if (!e)
e = ED_AllocIntoTable(progfuncs, i);
else
QC_ClearEdict (&progfuncs->funcs, (struct edict_s*)e);
e = ED_AllocIntoTable(progfuncs, i, object, fields_size);
if (externs->entspawn)
externs->entspawn((struct edict_s *) e, false);
@ -87,12 +122,9 @@ struct edict_s *PDECL ED_Alloc (pubprogfuncs_t *ppf)
e = (edictrun_t*)EDICT_NUM(progfuncs, i);
// the first couple seconds of server time can involve a lot of
// freeing and allocating, so relax the replacement policy
if (!e || (e->isfree))
if (!e || (e->ereftype==ER_FREE))
{
if (!e)
e = ED_AllocIntoTable(progfuncs, i);
else
QC_ClearEdict (&progfuncs->funcs, (struct edict_s*)e);
e = ED_AllocIntoTable(progfuncs, i, object, fields_size);
if (externs->entspawn)
externs->entspawn((struct edict_s *) e, false);
@ -119,21 +151,16 @@ struct edict_s *PDECL ED_Alloc (pubprogfuncs_t *ppf)
e = (edictrun_t*)EDICT_NUM(progfuncs, sv_num_edicts);
if (!e)
{
e = ED_AllocIntoTable(progfuncs, sv_num_edicts);
e = ED_AllocIntoTable(progfuncs, sv_num_edicts, object, fields_size);
if (externs->entspawn)
externs->entspawn((struct edict_s *) e, false);
e->isfree = true;
e->ereftype=ER_FREE;
}
sv_num_edicts++;
}
sv_num_edicts++;
e = (edictrun_t*)EDICT_NUM(progfuncs, i);
if (!e)
e = ED_AllocIntoTable(progfuncs, i);
else
QC_ClearEdict (&progfuncs->funcs, (struct edict_s*)e);
e = ED_AllocIntoTable(progfuncs, i, object, fields_size);
if (externs->entspawn)
externs->entspawn((struct edict_s *) e, false);
@ -154,7 +181,7 @@ void PDECL ED_Free (pubprogfuncs_t *ppf, struct edict_s *ed)
edictrun_t *e = (edictrun_t *)ed;
// SV_UnlinkEdict (ed); // unlink from world bsp
if (e->isfree) //this happens on start.bsp where an onlyregistered trigger killtargets itself (when all of this sort die after 1 trigger anyway).
if (e->ereftype == ER_FREE) //this happens on start.bsp where an onlyregistered trigger killtargets itself (when all of this sort die after 1 trigger anyway).
{
if (pr_depth)
printf("Tried to free free entity within %s\n", pr_xfunction->s_name+progfuncs->funcs.stringtable);
@ -169,7 +196,7 @@ void PDECL ED_Free (pubprogfuncs_t *ppf, struct edict_s *ed)
if (!externs->entcanfree(ed)) //can stop an ent from being freed.
return;
e->isfree = true;
e->ereftype = ER_FREE;
e->freetime = (float)*externs->gametime;
/*
@ -966,7 +993,7 @@ void PDECL ED_Print (pubprogfuncs_t *ppf, struct edict_s *ed)
char *name;
int type;
if (((edictrun_t *)ed)->isfree)
if (((edictrun_t *)ed)->ereftype == ER_FREE)
{
printf ("FREE\n");
return;
@ -1403,7 +1430,7 @@ cont:
}
if (!init)
ent->isfree = true;
ent->ereftype = ER_FREE;
return data;
}
@ -1757,7 +1784,7 @@ char *PDECL PR_SaveEnts(pubprogfuncs_t *ppf, char *buf, int *bufofs, int bufmax,
AddS ("{\n");
if (!ed->isfree) //free entities write a {} with no data. the loader detects this specifically.
if (ed->ereftype == ER_ENTITY) //free entities write a {} with no data. the loader detects this specifically.
ED_WriteEdict(progfuncs, ed, buf, bufofs, bufmax, true);
AddS ("}\n");
@ -1817,7 +1844,7 @@ char *PDECL PR_SaveEnts(pubprogfuncs_t *ppf, char *buf, int *bufofs, int bufmax,
{
edictrun_t *ed = (edictrun_t *)EDICT_NUM(progfuncs, a);
if (!ed || ed->isfree)
if (!ed || ed->ereftype != ER_ENTITY)
continue;
AddS (qcva("entity %i{\n", a));
@ -1901,8 +1928,8 @@ int PDECL PR_LoadEnts(pubprogfuncs_t *ppf, const char *file, float killonspawnfl
if (!ed)
{
ed = ED_AllocIntoTable(progfuncs, num);
ed->isfree = true;
ed = ED_AllocIntoTable(progfuncs, num, false, prinst.fields_size);
ed->ereftype = ER_FREE;
if (externs->entspawn)
externs->entspawn((struct edict_s *) ed, true);
}
@ -1915,7 +1942,7 @@ int PDECL PR_LoadEnts(pubprogfuncs_t *ppf, const char *file, float killonspawnfl
if (qcc_token[0] != '{')
Sys_Error("Progs loading found %s, not '{'", qcc_token);
if (!resethunk)
ed = (edictrun_t *)ED_Alloc(&progfuncs->funcs);
ed = (edictrun_t *)ED_Alloc(&progfuncs->funcs, false, 0);
else
{
ed = (edictrun_t *)EDICT_NUM(progfuncs, num);
@ -1923,10 +1950,10 @@ int PDECL PR_LoadEnts(pubprogfuncs_t *ppf, const char *file, float killonspawnfl
if (!ed)
{
Sys_Error("Edict was not allocated\n");
ed = ED_AllocIntoTable(progfuncs, num);
ed = ED_AllocIntoTable(progfuncs, num, false, prinst.fields_size);
}
}
ed->isfree = false;
ed->ereftype = ER_ENTITY;
if (externs->entspawn)
externs->entspawn((struct edict_s *) ed, true);
file = ED_ParseEdict(progfuncs, file, ed);
@ -1938,7 +1965,7 @@ int PDECL PR_LoadEnts(pubprogfuncs_t *ppf, const char *file, float killonspawnfl
{
if ((int)var->_float & (int)killonspawnflags)
{
ed->isfree = true;
ed->ereftype = ER_FREE;
continue;
}
}
@ -2015,8 +2042,8 @@ int PDECL PR_LoadEnts(pubprogfuncs_t *ppf, const char *file, float killonspawnfl
if (!ed)
{
ed = ED_AllocIntoTable(progfuncs, num);
ed->isfree = true;
ed = ED_AllocIntoTable(progfuncs, num, false, prinst.fields_size);
ed->ereftype = ER_FREE;
}
if (externs->entspawn)
@ -2134,7 +2161,7 @@ int PDECL PR_LoadEnts(pubprogfuncs_t *ppf, const char *file, float killonspawnfl
sv_num_edicts = 1; //set up a safty buffer so things won't go horribly wrong too often
sv_edicts=(struct edict_s *)&tempedict;
progfuncs->funcs.edicttable = prinst.edicttable = &sv_edicts;
prinst.edicttable = (struct edictrun_s**)(progfuncs->funcs.edicttable = &sv_edicts);
sv_num_edicts = numents; //should be fine
@ -2192,12 +2219,12 @@ int PDECL PR_LoadEnts(pubprogfuncs_t *ppf, const char *file, float killonspawnfl
{
ed = (edictrun_t *)EDICT_NUM(progfuncs, numents);
if (!ed)
ed = ED_AllocIntoTable(progfuncs, numents);
ed = ED_AllocIntoTable(progfuncs, numents, false, prinst.fields_size);
if (externs->entspawn)
externs->entspawn((struct edict_s *) ed, true);
ed->isfree = false;
ed->ereftype = ER_ENTITY;
file = ED_ParseEdict (progfuncs, file, ed);
}
sv_num_edicts = ++numents;
@ -2215,8 +2242,8 @@ int PDECL PR_LoadEnts(pubprogfuncs_t *ppf, const char *file, float killonspawnfl
if (!ed)
{
ed = ED_AllocIntoTable(progfuncs, num);
ed->isfree = true;
ed = ED_AllocIntoTable(progfuncs, num, false, prinst.fields_size);
ed->ereftype = ER_FREE;
}
}
}
@ -2224,8 +2251,8 @@ int PDECL PR_LoadEnts(pubprogfuncs_t *ppf, const char *file, float killonspawnfl
if (!ed) //first entity
ed = (edictrun_t *)EDICT_NUM(progfuncs, 0);
else
ed = (edictrun_t *)ED_Alloc(&progfuncs->funcs);
ed->isfree = false;
ed = (edictrun_t *)ED_Alloc(&progfuncs->funcs, false, 0);
ed->ereftype = ER_ENTITY;
if (externs->entspawn)
externs->entspawn((struct edict_s *) ed, true);
file = ED_ParseEdict(progfuncs, file, ed);
@ -2237,7 +2264,7 @@ int PDECL PR_LoadEnts(pubprogfuncs_t *ppf, const char *file, float killonspawnfl
{
if ((int)var->_float & (int)killonspawnflags)
{
ed->isfree = true;
ed->ereftype = ER_FREE;
ed->freetime = 0;
continue;
}
@ -2447,11 +2474,11 @@ struct edict_s *PDECL PR_RestoreEnt (pubprogfuncs_t *ppf, const char *buf, int *
Sys_Error("Restore Ent with no opening brace");
if (!ed)
ent = (edictrun_t *)ED_Alloc(&progfuncs->funcs);
ent = (edictrun_t *)ED_Alloc(&progfuncs->funcs, false, 0);
else
ent = (edictrun_t *)ed;
if (ent->isfree && externs->entspawn)
if (ent->ereftype == ER_FREE && externs->entspawn)
externs->entspawn((struct edict_s *) ent, false);
buf = ED_ParseEdict(progfuncs, buf, ent);
@ -3445,7 +3472,7 @@ struct edict_s *PDECL QC_EDICT_NUM(pubprogfuncs_t *ppf, unsigned int n)
if (n >= prinst.maxedicts)
Sys_Error ("QCLIB: EDICT_NUM: bad number %i", n);
return prinst.edicttable[n];
return (struct edict_s*)prinst.edicttable[n];
}
unsigned int PDECL QC_NUM_FOR_EDICT(pubprogfuncs_t *ppf, struct edict_s *e)

View File

@ -148,7 +148,7 @@ typedef struct prinst_s
size_t addressableused;
size_t addressablesize;
struct edict_s **edicttable;
struct edictrun_s **edicttable;
} prinst_t;
typedef struct progfuncs_s
@ -254,13 +254,19 @@ typedef union eval_s
} eval_t;
#endif
*/
enum ereftype_e
{
ER_ENTITY,
ER_FREE,
ER_OBJECT //custom sized, no vm/engine fields.
};
typedef struct edictrun_s
{
pbool isfree;
pbool ereftype;
float freetime; // realtime when the object was freed
unsigned int entnum;
unsigned int fieldsize;
pbool readonly; //causes error when QC tries writing to it. (quake's world entity)
void *fields;
@ -364,7 +370,7 @@ void *PRHunkAlloc(progfuncs_t *progfuncs, int ammount, char *name);
void PR_Profile_f (void);
struct edict_s *PDECL ED_Alloc (pubprogfuncs_t *progfuncs);
struct edict_s *PDECL ED_Alloc (pubprogfuncs_t *progfuncs, pbool object, size_t extrasize);
void PDECL ED_Free (pubprogfuncs_t *progfuncs, struct edict_s *ed);
pbool PR_RunGC (progfuncs_t *progfuncs);

View File

@ -89,7 +89,7 @@ struct pubprogfuncs_s
void (VARGS *RunError) (pubprogfuncs_t *prinst, char *msg, ...) LIKEPRINTF(2); //builtins call this to say there was a problem
void (PDECL *PrintEdict) (pubprogfuncs_t *prinst, struct edict_s *ed); //get a listing of all vars on an edict (sent back via 'print')
struct edict_s *(PDECL *EntAlloc) (pubprogfuncs_t *prinst);
struct edict_s *(PDECL *EntAlloc) (pubprogfuncs_t *prinst, pbool object, size_t extrasize);
void (PDECL *EntFree) (pubprogfuncs_t *prinst, struct edict_s *ed);
struct edict_s *(PDECL *EDICT_NUM) (pubprogfuncs_t *prinst, unsigned int n); //get the nth edict
@ -261,7 +261,7 @@ typedef union eval_s
#define PR_RegisterFieldVar(pf,type,name,reqofs,qcofs) (*pf->RegisterFieldVar) (pf,type,name,reqofs,qcofs)
#define ED_Alloc(pf) (*pf->EntAlloc) (pf)
#define ED_Alloc(pf,isobj,extsize) (*pf->EntAlloc) (pf, isobj, extsize)
#define ED_Free(pf, ed) (*pf->EntFree) (pf, ed)
#define ED_Clear(pf, ed) (*pf->EntClear) (pf, ed)

View File

@ -4923,6 +4923,15 @@ QCC_sref_t QCC_PR_ParseFunctionCall (QCC_ref_t *funcref) //warning, the func cou
return QCC_MakeIntConst(sz);
}
}
if (!strcmp(funcname, "alloca"))
{ //FIXME: half of these functions with regular expression arguments should be handled later or something
QCC_sref_t sz;
sz = QCC_PR_Expression(TOP_PRIORITY, 0);
QCC_PR_Expect(")");
sz = QCC_SupplyConversion(sz, ev_integer, true);
sz = QCC_PR_Statement(&pr_opcodes[OP_PUSH], sz, nullsref, NULL);
return sz;
}
if (!strcmp(funcname, "_"))
{
if (!func.sym->initialized)

View File

@ -3687,7 +3687,7 @@ static void QCBUILTIN PF_h2dprintv (pubprogfuncs_t *prinst, struct globalvars_s
static void QCBUILTIN PF_h2spawn_temp (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
edict_t *ed;
ed = ED_Alloc(prinst);
ed = ED_Alloc(prinst, false, 0);
RETURN_EDICT(prinst, ed);
}
#endif

View File

@ -67,6 +67,7 @@ typedef struct edict_s
qboolean isfree;
float freetime; // sv.time when the object was freed
int entnum;
unsigned int fieldsize;
qboolean readonly; //world
#ifdef VM_Q1
stdentvars_t *v;

View File

@ -1266,7 +1266,7 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us
{
svs.clients[i].viewent = 0;
ent = ED_Alloc(svprogfuncs);//EDICT_NUM(i+1);
ent = ED_Alloc(svprogfuncs, false, 0);//EDICT_NUM(i+1);
svs.clients[i].edict = ent;
ent->isfree = false;
//ZOID - make sure we update frags right

View File

@ -1,4 +1,3 @@
float autocvar_ca_show;
var float autocvar_ca_editormode = MODE_LIGHTEDIT;
string autocvar_ca_colourtint;
@ -13,6 +12,8 @@ float ctrldown;
vector mousenear;
vector mousefar;
float releasedmouse;
string pointedshadername;
vector pointedsurfacenormal;
entity pointedent;
@ -20,12 +21,39 @@ float pointedsurface;
float editorrsd[editornames.length];
float(float key, float unic, vector mouse) editor_options_key =
{
if (key == K_MOUSE1)
if (mouse_y >= 16 && mouse_y < 16+8)
{
cvar_set("ca_show", "0");
return TRUE;
}
return FALSE;
};
void(vector mouse) editor_options_overlay =
{
if (mouse_y >= 16 && mouse_y < 16+8)
drawstring('0 16', "Close", '8 8', '0 0 1', 1, 0);
else
drawstring('0 16', "Close", '8 8', '1 1 1', 1, 0);
};
/*the renderscene builtin in the parent progs is redirected to here*/
void() wrap_renderscene =
{
float x;
vector col;
local float i;
if (ca_checksave)
{
if (ca_checksave(autocvar_ca_show?autocvar_ca_editormode:0))
{
ca_checksave = __NULL__;
localcmd("changelevel . .\n");
}
}
//don't do anything if this is a subview. this avoids getting confused.
if (!(float)getproperty(VF_DRAWWORLD))
@ -101,8 +129,32 @@ void() wrap_renderscene =
);
drawpic(getproperty(VF_MIN), shdrname, getproperty(VF_SIZE), '1 1 1', 1);
}
if (releasedmouse)
{ //remove the cursor if we activated it
releasedmouse = FALSE;
setcursormode(FALSE);
}
mousedown = 0;
return;
}
if (mousedown == 2)
{ //RMB re-enables mlook
if (releasedmouse)
{
releasedmouse = FALSE;
setcursormode(FALSE);
}
}
else
{
if (FALSE == getcursormode(FALSE))
{ //only release it again if it should be released.
setcursormode(TRUE);
releasedmouse = TRUE;
}
}
/*hide hud and crosshair*/
setproperty(VF_DRAWENGINESBAR, 0);
@ -149,7 +201,9 @@ void() wrap_renderscene =
editorrsd[i] = x;
}
if (autocvar_ca_editormode == MODE_LIGHTEDIT)
if (autocvar_ca_editormode == MODE_OPTIONS)
editor_options_overlay(curmousepos);
else if (autocvar_ca_editormode == MODE_LIGHTEDIT)
editor_lights_overlay(curmousepos);
#ifdef CAMQUAKE
else if (autocvar_ca_editormode == MODE_SPLINEEDIT)
@ -180,6 +234,8 @@ float (float event, float parama, float paramb) wrap_InputEvent =
shiftdown = (event == IE_KEYDOWN);
if (parama == K_RCTRL || parama == K_LCTRL)
ctrldown = (event == IE_KEYDOWN);
if (parama == K_RALT || parama == K_LALT)
altdown = (event == IE_KEYDOWN);
}
if (autocvar_ca_show)
{
@ -198,7 +254,12 @@ float (float event, float parama, float paramb) wrap_InputEvent =
cvar_set("ca_editormode", ftos(nm));
return TRUE;
}
if (autocvar_ca_editormode == MODE_LIGHTEDIT)
if (autocvar_ca_editormode == MODE_OPTIONS)
{
if (editor_options_key(parama, paramb, curmousepos))
return TRUE;
}
else if (autocvar_ca_editormode == MODE_LIGHTEDIT)
{
if (editor_lights_key(parama, paramb, curmousepos))
return TRUE;
@ -315,9 +376,6 @@ void(float mask) wrap_addentities =
var float autocvar_fov = 90;
static void(float seat, vector mn, vector sz) renderscene_helper =
{
#ifndef VF_ACTIVESEAT
#define VF_ACTIVESEAT VF_LPLAYER
#endif
if (seat)
{
setproperty(VF_ACTIVESEAT, seat, TRUE); //updates globals, true means resets view properties too (but not ents)
@ -379,6 +437,9 @@ void(float width, float height, float do2d) CSQC_UpdateView =
void() CSQC_Input_Frame =
{
vector t, o;
if (autocvar_ca_show) //when we're using the UI, don't send any attack or jump stuff. these are generally annoying modifiers or so
input_buttons = 0;
if ((input_buttons & 1) && pointedshadername == "")
{
t = mousefar;
@ -491,6 +552,12 @@ float(string txt, string info) CSQC_ConsoleLink =
};
*/
float(string cmd) CSQC_ConsoleCommand =
{
tokenize(cmd);
return editor_brushes_command();
};
/*this is a fallback function, in case the main progs does not have one*/
float (float event, float parama, float paramb, float devid) CSQC_InputEvent =
{
@ -521,6 +588,9 @@ void(float prevprogs) init =
localcmd(sprintf("alias terrain_editor \"set ca_show 1; set ca_editormode %g\"\n", MODE_TERRAINEDIT));
localcmd(sprintf("alias r_part_editor \"set ca_show 1; set ca_editormode %g\"\n", MODE_PARTICLEEDIT));
localcmd(sprintf("alias entities_editor \"set ca_show 1; set ca_editormode %g\"\n", MODE_ENTSEDIT));
//brush editor needs some commands for easier binds.
editor_brushes_registercommands();
};
void() CSQC_Shutdown =

View File

@ -13,6 +13,9 @@ vector *ptr_trace_endpos;
vector *ptr_trace_plane_normal;
#define trace_plane_normal (*ptr_trace_plane_normal)
entity *ptr_trace_ent;
#define trace_ent (*ptr_trace_ent)
entity *ptr_self;
#define self (*ptr_self)
@ -20,6 +23,7 @@ void() csfixups =
{
ptr_trace_endpos = (vector*)externvalue(0, "&trace_endpos");
ptr_trace_plane_normal = (vector*)externvalue(0, "&trace_plane_normal");
ptr_trace_ent = (entity*)externvalue(0, "&trace_ent");
ptr_self = (entity*)externvalue(0, "&self");
};
@ -27,19 +31,26 @@ void() csfixups =
vector mousenear;
vector mousefar;
float mousedown;
float shiftdown;
float ctrldown;
float altdown;
enum
{
MODE_INITIAL=0,
MODE_OPTIONS,
MODE_LIGHTEDIT=1,
MODE_SPLINEEDIT=2,
MODE_TERRAINEDIT=3,
MODE_BRUSHEDIT=4,
MODE_PARTICLEEDIT=5,
MODE_ENTSEDIT=6,
MODE_LIGHTEDIT,
MODE_SPLINEEDIT,
MODE_TERRAINEDIT,
MODE_BRUSHEDIT,
MODE_PARTICLEEDIT,
MODE_ENTSEDIT,
MODE_COUNT
};
var string editornames[] = {"","LIGHTS","SPLINES", "TERRAIN", "BRUSHES", "PARTICLES", "ENTITIES"};
var string editornames[MODE_COUNT] = {"OPTIONS","LIGHTS","SPLINES", "TERRAIN", "BRUSHES", "PARTICLES", "ENTITIES"};
var float(float vismode) ca_checksave;

View File

@ -13,6 +13,7 @@ Available options:
-O - write to a different qc file
*/
#pragma noref 1
//#pragma flag enable logicops
#pragma warning error Q101 /*too many parms*/
#pragma warning error Q105 /*too few parms*/
#pragma warning error Q208 /*system crc unknown*/
@ -142,7 +143,7 @@ Available options:
#define DP_TE_EXPLOSIONRGB
#define DP_TE_PARTICLECUBE
#define DP_TE_SMALLFLASH
#define DP_TE_SPARK
#define DP_TE_SPARK
#define DP_TE_STANDARDEFFECTBUILTINS
#define DP_VIEWZOOM
#define EXT_BITSHIFT
@ -173,6 +174,7 @@ Available options:
#define FTE_NPCCHAT
#define FTE_QC_CHECKCOMMAND
#define FTE_QC_CHECKPVS
#define FTE_QC_HARDWARECURSORS /* setcursormode exists in both csqc+menuqc, and accepts additional arguments to specify a cursor image to use when this module has focus. If the image exceeds hardware limits, it will be emulated using regular draws - this at least still avoids conflicting cursors. */
#define FTE_QC_HASHTABLES
#define FTE_QC_INTCONV
#define FTE_QC_MATCHCLIENTNAME
@ -271,6 +273,8 @@ vector input_cursor_screen;
vector input_cursor_trace_start;
vector input_cursor_trace_endpos;
float input_cursor_trace_entnum;
int trace_brush_id;
int trace_brush_faceid;
.vector punchangle;
.float gravity;
.float hull; /* Overrides the hull used by the entity for walkmove/movetogoal and not traceline/tracebox. */
@ -288,7 +292,7 @@ float input_cursor_trace_entnum;
.entity tag_entity;
.float tag_index;
.float skeletonindex; /* This object serves as a container for the skeletal bone states used to override the animation data. */
.vector colormod;
.vector colormod; /* Provides a colour tint for the entity. */
.vector glowmod;
.vector gravitydir; /* Specifies the direction in which gravity acts. Must be normalised. '0 0 0' also means down. Use '0 0 1' if you want the player to be able to run on ceilings. */
.vector(vector org, vector ang) camera_transform; /* Provides portal transform information for portal surfaces attached to this entity. Also used to open up pvs in ssqc. */
@ -319,32 +323,33 @@ float input_cursor_trace_entnum;
.float bonecontrol5; /* Halflife model format bone controller. This typically affects the mouth. */
.float subblendfrac; /* Weird animation value specific to halflife models. On player models, this typically affects the spine's pitch. */
.float basesubblendfrac; /* See basebone */
noref void(float reqid, float responsecode, string resourcebody) URI_Get_Callback; /* Called as an eventual result of the uri_get builtin. */
noref void(float apilevel, string enginename, float engineversion) CSQC_Init; /* Called at startup. enginename and engineversion are arbitary hints and can take any form. enginename should be consistant between revisions, but this cannot truely be relied upon. */
noref void() CSQC_WorldLoaded; /* Called after model+sound precaches have been executed. Gives a chance for the qc to read the entity lump from the bsp. */
noref void() CSQC_Shutdown; /* Specifies that the csqc is going down. Save your persistant settings here. */
noref void(float vwidth, float vheight, float notmenu) CSQC_UpdateView; /* Called every single video frame. The CSQC is responsible for rendering the entire screen. */
noref void(float vwidth, float vheight, float notmenu) CSQC_UpdateViewLoading; /* Alternative to CSQC_UpdateView, called when the engine thinks there should be a loading screen. If present, will inhibit the engine's normal loading screen, deferring to qc to draw it. */
noref void(string msg) CSQC_Parse_StuffCmd; /* Gives the CSQC a chance to intercept stuffcmds. Use the tokenize builtin to parse the message. Unrecognised commands would normally be localcmded, but its probably better to drop unrecognised stuffcmds completely. */
noref float(string msg) CSQC_Parse_CenterPrint; /* Gives the CSQC a chance to intercept centerprints. Return true if you wish the engine to otherwise ignore the centerprint. */
noref float(float save, float take, vector inflictororg) CSQC_Parse_Damage; /* Called as a result of player.dmg_save or player.dmg_take being set on the server.
void(float reqid, float responsecode, string resourcebody) URI_Get_Callback; /* Called as an eventual result of the uri_get builtin. */
void(float apilevel, string enginename, float engineversion) CSQC_Init; /* Called at startup. enginename and engineversion are arbitary hints and can take any form. enginename should be consistant between revisions, but this cannot truely be relied upon. */
void() CSQC_WorldLoaded; /* Called after model+sound precaches have been executed. Gives a chance for the qc to read the entity lump from the bsp. */
void() CSQC_Shutdown; /* Specifies that the csqc is going down. Save your persistant settings here. */
void(float vwidth, float vheight, float notmenu) CSQC_UpdateView; /* Called every single video frame. The CSQC is responsible for rendering the entire screen. */
void(float vwidth, float vheight, float notmenu) CSQC_UpdateViewLoading; /* Alternative to CSQC_UpdateView, called when the engine thinks there should be a loading screen. If present, will inhibit the engine's normal loading screen, deferring to qc to draw it. */
void(string msg) CSQC_Parse_StuffCmd; /* Gives the CSQC a chance to intercept stuffcmds. Use the tokenize builtin to parse the message. Unrecognised commands would normally be localcmded, but its probably better to drop unrecognised stuffcmds completely. */
float(string msg) CSQC_Parse_CenterPrint; /* Gives the CSQC a chance to intercept centerprints. Return true if you wish the engine to otherwise ignore the centerprint. */
float(float save, float take, vector inflictororg) CSQC_Parse_Damage; /* Called as a result of player.dmg_save or player.dmg_take being set on the server.
Return true to completely inhibit the engine's colour shift and damage rolls, allowing you to do your own thing.
You can use punch_roll += (normalize(inflictororg-player.origin)*v_right)*(take+save)*autocvar_v_kickroll; as a modifier for the roll angle should the player be hit from the side, and slowly fade it away over time. */
noref void(string printmsg, float printlvl) CSQC_Parse_Print; /* Gives the CSQC a chance to intercept sprint/bprint builtin calls. CSQC should filter by the client's current msg setting and then pass the message on to the print command, or handle them itself. */
noref void() CSQC_Parse_Event; /* Called when the client receives an SVC_CGAMEPACKET. The csqc should read the data or call the error builtin if it does not recognise the message. */
noref float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent; /* Called whenever a key is pressed, the mouse is moved, etc. evtype will be one of the IE_* constants. The other arguments vary depending on the evtype. Key presses are not guarenteed to have both scan and unichar values set at the same time. */
noref void() CSQC_Input_Frame; /* Called just before each time clientcommandframe is updated. You can edit the input_* globals in order to apply your own player inputs within csqc, which may allow you a convienient way to pass certain info to ssqc. */
noref float(string cmd) CSQC_ConsoleCommand; /* Called if the user uses any console command registed via registercommand. */
noref float(string text, string info) CSQC_ConsoleLink; /* Called if the user clicks a ^[text\infokey\infovalue^] link. Use infoget to read/check each supported key. Return true if you wish the engine to not attempt to handle the link itself. */
noref void(float isnew) CSQC_Ent_Update;
noref void() CSQC_Ent_Remove;
noref float(float entnum, float channel, string soundname, float vol, float attenuation, vector pos, float pitchmod) CSQC_Event_Sound;
noref float(string resname, string restype) CSQC_LoadResource; /* Called each time some resource is being loaded. CSQC can invoke various draw calls to provide a loading screen, until WorldLoaded is called. */
noref float() CSQC_Parse_TempEntity; /* Please don't use this. Use CSQC_Parse_Event and multicasts instead. */
noref void(string cmdtext) GameCommand;
noref void(float prevprogs) init; /* Part of FTE_MULTIPROGS. Called as soon as a progs is loaded, called at a time when entities are not valid. This is the only time when it is safe to call addprogs without field assignment. As it is also called as part of addprogs, this also gives you a chance to hook functions in modules that are already loaded (via externget+externget). */
noref void() initents; /* Part of FTE_MULTIPROGS. Called after fields have been finalized. This is the first point at which it is safe to call spawn(), and is called before any entity fields have been parsed. You can use this entrypoint to send notifications to other modules. */
var float physics_mode = 2; /* 0: original csqc - physics are not run
void(string printmsg, float printlvl) CSQC_Parse_Print; /* Gives the CSQC a chance to intercept sprint/bprint builtin calls. CSQC should filter by the client's current msg setting and then pass the message on to the print command, or handle them itself. */
void() CSQC_Parse_Event; /* Called when the client receives an SVC_CGAMEPACKET. The csqc should read the data or call the error builtin if it does not recognise the message. */
float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent; /* Called whenever a key is pressed, the mouse is moved, etc. evtype will be one of the IE_* constants. The other arguments vary depending on the evtype. Key presses are not guarenteed to have both scan and unichar values set at the same time. */
__used void() CSQC_Input_Frame; /* Called just before each time clientcommandframe is updated. You can edit the input_* globals in order to apply your own player inputs within csqc, which may allow you a convienient way to pass certain info to ssqc. */
void(void) CSQC_RendererRestarted; /* Called by the engine after the video was restarted. This serves to notify the CSQC that any render targets that it may have cached were purged, and will need to be regenerated. */
float(string cmd) CSQC_ConsoleCommand; /* Called if the user uses any console command registed via registercommand. */
float(string text, string info) CSQC_ConsoleLink; /* Called if the user clicks a ^[text\infokey\infovalue^] link. Use infoget to read/check each supported key. Return true if you wish the engine to not attempt to handle the link itself. */
void(float isnew) CSQC_Ent_Update;
void() CSQC_Ent_Remove;
float(float entnum, float channel, string soundname, float vol, float attenuation, vector pos, float pitchmod, float flags) CSQC_Event_Sound;
float(string resname, string restype) CSQC_LoadResource; /* Called each time some resource is being loaded. CSQC can invoke various draw calls to provide a loading screen, until WorldLoaded is called. */
float() CSQC_Parse_TempEntity; /* Please don't use this. Use CSQC_Parse_Event and multicasts instead. */
void(string cmdtext) GameCommand;
void(float prevprogs) init; /* Part of FTE_MULTIPROGS. Called as soon as a progs is loaded, called at a time when entities are not valid. This is the only time when it is safe to call addprogs without field assignment. As it is also called as part of addprogs, this also gives you a chance to hook functions in modules that are already loaded (via externget+externget). */
void() initents; /* Part of FTE_MULTIPROGS. Called after fields have been finalized. This is the first point at which it is safe to call spawn(), and is called before any entity fields have been parsed. You can use this entrypoint to send notifications to other modules. */
__used var float physics_mode = 2; /* 0: original csqc - physics are not run
1: DP-compat. Thinks occur, but not true movetypes.
2: movetypes occur just as they do in ssqc. */
float gamespeed; /* Set by the engine, this is the value of the sv_gamespeed cvar */
@ -428,6 +433,9 @@ float drawfont; /* Allows you to choose exactly which font is to be used to draw
#define CHAN_VOICE 2
#define CHAN_ITEM 3
#define CHAN_BODY 4
#define SOUNDFLAG_ABSVOLUME 16
#define SOUNDFLAG_FORCELOOP 2
#define SOUNDFLAG_NOSPACIALISE 4
#define ATTN_NONE 0 /* Sounds with this attenuation can be heard throughout the map */
#define ATTN_NORM 1 /* Standard attenuation */
#define ATTN_IDLE 2 /* Extra attenuation so that sounds don't travel too far. */
@ -448,15 +456,16 @@ float drawfont; /* Allows you to choose exactly which font is to be used to draw
#define SERVERKEY_IP "ip" /* The address of the server we connected to. */
#define SERVERKEY_SERVERNAME "servername" /* The hostname that was last passed to the connect command. */
#define SERVERKEY_CONSTATE "constate" /* The current connection state. Will be set to one of: disconnected (menu-only mode), active (gamestate received and loaded), connecting(connecting, downloading, or precaching content, aka: loading screen). */
#define SERVERKEY_TRANSFERRING "transferring" /* Set to the hostname of the server that we are attempting to connect or transfer to. */
#define SERVERKEY_TRANSFERRING "transferring" /* Set to the hostname of the server that we are attempting to connect or transfer to. */
#define SERVERKEY_LOADSTATE "loadstate" /* loadstage, loading image name, current step, max steps
Stages are: 1=connecting, 2=serverside, 3=clientside
Key will be empty if we are not loading. */
#define SERVERKEY_PAUSESTATE "pausestate" /* 1 if the server claimed to be paused. 0 otherwise */
#define SERVERKEY_DLSTATE "dlstate" /* The progress of any current downloads. Empty string if no download is active, otherwise a tokenizable string containing this info:
files-remaining, total-size, unknown-sizes-flag, file-localname, file-remotename, file-percent, file-rate, file-received-bytes, file-total-bytes
If the current file info is omitted, then we are waiting for a download to start. */
If the current file info is omitted, then we are waiting for a download to start. */
#define SERVERKEY_PROTOCOL "protocol" /* The protocol we are connected to the server with. */
#define SERVERKEY_MAXPLAYERS "maxplayers" /* The protocol we are connected to the server with. */
#define FL_FLY 1
#define FL_SWIM 2
#define FL_CLIENT 8
@ -493,6 +502,7 @@ If the current file info is omitted, then we are waiting for a download to start
#define EF_ADDITIVE 32
#define EF_BLUE 64
#define EF_RED 128
#define EF_GREEN 262144
#define EF_FULLBRIGHT 512
#define EF_NODEPTHTEST 8192
#define MF_ROCKET 1
@ -516,6 +526,7 @@ If the current file info is omitted, then we are waiting for a download to start
#define EV_VARIANT 9
hashtable gamestate; /* Special hash table index for hash_add and hash_get. Entries in this table will persist over map changes (and doesn't need to be created/deleted). */
#define HASH_REPLACE 256 /* Used with hash_add. Attempts to remove the old value instead of adding two values for a single key. */
#define HASH_ADD 512 /* Used with hash_add. The new entry will be inserted in addition to the existing entry. */
#define STAT_HEALTH 0 /* Player's health. */
#define STAT_WEAPONMODELI 2 /* This is the modelindex of the current viewmodel (renamed from the original name 'STAT_WEAPON' due to confusions). */
#define STAT_AMMO 3 /* player.currentammo */
@ -561,7 +572,8 @@ hashtable gamestate; /* Special hash table index for hash_add and hash_get. Entr
#define VF_CL_VIEWANGLES_Y 35
#define VF_CL_VIEWANGLES_Z 36
#define VF_PERSPECTIVE 200 /* 1: regular rendering. Fov specifies the angle. 0: isometric-style. Fov specifies the number of Quake Units each side of the viewport. */
#define VF_LPLAYER 202 /* The 'seat' number, used when running splitscreen. */
#define VF_LPLAYER VF_ACTIVESEAT
const float VF_ACTIVESEAT = 202; /* The 'seat' number, used when running splitscreen. */
#define VF_AFOV 203 /* Aproximate fov. Matches the 'fov' cvar. The engine handles the aspect ratio for you. */
#define VF_SCREENVSIZE 204 /* Provides a reliable way to retrieve the current virtual screen size (even if the screen is automatically scaled to retain aspect). */
#define VF_SCREENPSIZE 205 /* Provides a reliable way to retrieve the current physical screen size (cvars need vid_restart for them to take effect). */
@ -636,13 +648,17 @@ Note that any rendertarget textures may be destroyed on video mode changes or so
#define TEREDIT_TEX_UNIFY 11
#define TEREDIT_TEX_NOISE 12
#define TEREDIT_TEX_BLUR 13
#define TEREDIT_TEX_REPLACE 19
#define TEREDIT_TEX_SETMASK 25
#define TEREDIT_WATER_SET 14
#define TEREDIT_MESH_ADD 15
#define TEREDIT_MESH_KILL 16
#define TEREDIT_TINT 17
#define TEREDIT_TEX_REPLACE 19
#define TEREDIT_RESET_SECT 20
#define TEREDIT_RELOAD_SECT 21
#define TEREDIT_ENTS_WIPE 22
#define TEREDIT_ENTS_CONCAT 23
#define TEREDIT_ENTS_GET 24
#define SLIST_HOSTCACHEVIEWCOUNT 0
#define SLIST_HOSTCACHETOTALCOUNT 1
#define SLIST_MASTERQUERYCOUNT 2
@ -676,12 +692,13 @@ void(entity e, vector min, vector max) setsize = #4; /*
float() random = #7; /*
Returns a random value between 0 and 1. Be warned, this builtin can return 1 in most engines, which can break arrays. */
void(entity e, float chan, string samp, float vol, float atten, optional float speedpct, optional float flags) sound = #8; /*
void(entity e, float chan, string samp, float vol, float atten, optional float speedpct, optional float flags, optional float timeofs) sound = #8; /*
Starts a sound centered upon the given entity.
chan is the entity sound channel to use, channel 0 will allow you to mix many samples at once, others will replace the old sample
'samp' must have been precached first
if specified, 'speedpct' should normally be around 100 (or =0), 200 for double speed or 50 for half speed.
flags&1 means the sound should be sent reliably. */
If flags is specified, the reliable flag in the channels argument is used for additional channels. Flags should be made from SOUNDFLAG_* constants
timeofs should be negative in order to provide a delay before the sound actually starts. */
vector(vector v) normalize = #9; /*
Shorten or lengthen a direction vector such that it is only one quake unit long. */
@ -758,7 +775,7 @@ float(float yaw, float dist, optional float settraceglobals) walkmove = #32; /*
This function will trigger touch events. */
float() droptofloor = #34; /*
Instantly moves the entity downwards until it hits the ground. If the entity would need to drop more than 'pr_droptofloorunits' quake units, its position will be considered invalid and the builtin will abort. */
Instantly moves the entity downwards until it hits the ground. If the entity is in solid or would need to drop more than 'pr_droptofloorunits' quake units, its position will be considered invalid and the builtin will abort, returning FALSE, otherwise TRUE. */
void(float lightstyle, string stylestring, optional vector rgb) lightstyle = #35; /*
Specifies an auto-animating string that specifies the light intensity for entities using that lightstyle.
@ -797,18 +814,22 @@ void(vector pos, vector dir, float colour, float count) particle = #48; /*
#define ChangeYaw changeyaw
void() changeyaw = #49; /*
Changes the self.angles_y field towards self.ideal_yaw by up to self.yawspeed. */
Changes the self.angles_y field towards self.ideal_yaw by up to self.yaw_speed. */
vector(vector fwd, optional vector up) vectoangles = #51; /*
Returns the angles (+x=UP) required to orient an entity to look in the given direction. The 'up' argument is required if you wish to set a roll angle, otherwise it will be limited to just monster-style turning. */
float(float angle) sin = #60; /* Part of DP_QC_SINCOSSQRTPOW*/
float(float angle) sin = #60; /* Part of DP_QC_SINCOSSQRTPOW
Forgive me father, for I have trigonometry homework. */
float(float angle) cos = #61; /* Part of DP_QC_SINCOSSQRTPOW*/
float(float value) sqrt = #62; /* Part of DP_QC_SINCOSSQRTPOW*/
void(entity ent) changepitch = #63; /* Part of DP_QC_CHANGEPITCH*/
void(entity ent, entity ignore) tracetoss = #64;
string(entity ent) etos = #65; /* Part of DP_QC_ETOS*/
void(float step) movetogoal = #67;
void(float step) movetogoal = #67; /*
Runs lots and lots of fancy logic in order to try to step the entity the specified distance towards its goalentity. */
string(string s) precache_file = #68; /*
This builtin does nothing. It was used only as a hint for pak generation. */
@ -845,10 +866,17 @@ float(float minimum, float val, float maximum) bound = #96; /* Part of DP_QC_MIN
Returns val, unless minimum is higher, or maximum is less. */
float(float value, float exp) pow = #97; /* Part of DP_QC_SINCOSSQRTPOW*/
float(float v, optional float base) logarithm = #0/*:logarithm*/; /*
Determines the logarithm of the input value according to the specified base. This can be used to calculate how much something was shifted by. */
entity(entity start, .float fld, float match) findfloat = #98; /* Part of DP_QC_FINDFLOAT
Equivelent to the find builtin, but instead of comparing strings, this builtin compares floats. This builtin requires multiple calls in order to scan all entities - set start to the previous call's return value.
world is returned when there are no more entities. */
entity(entity start, .entity fld, entity match) findentity = #98; /*
Equivelent to the find builtin, but instead of comparing strings, this builtin compares entities. This builtin requires multiple calls in order to scan all entities - set start to the previous call's return value.
world is returned when there are no more entities. */
float(string extname) checkextension = #99; /*
Checks for an extension by its name (eg: checkextension("FRIK_FILE") says that its okay to go ahead and use strcat).
Use cvar("pr_checkextension") to see if this builtin exists. */
@ -859,7 +887,7 @@ void(filestream fhandle) fclose = #111; /* Part of FRIK_FILE*/
string(filestream fhandle) fgets = #112; /* Part of FRIK_FILE*/
void(filestream fhandle, string s, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6, optional string s7) fputs = #113; /* Part of FRIK_FILE*/
float(string s) strlen = #114; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/
string(string s1, optional string s2, ...) strcat = #115; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/
string(string s1, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6, optional string s7, optional string s8) strcat = #115; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/
string(string s, float start, float length) substring = #116; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/
vector(string s) stov = #117; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS*/
string(string s, ...) strzone = #118; /* Part of FRIK_FILE, FTE_STRINGS, ZQ_QC_STRINGS
@ -952,6 +980,9 @@ float(string s1, string s2, float len, optional float s1ofs, optional float s2of
Compares up to 'len' chars in the two strings without case sensitivity. s1ofs allows you to treat s2 as a substring to compare against, or should be 0.
Returns 0 if they are equal. The sign of the return value may be significant, but should not be depended upon. */
string(string s) strtrim = #0/*:strtrim*/; /*
Trims the whitespace from the start+end of the string. */
void() calltimeofday = #231; /* Part of FTE_CALLTIMEOFDAY
Asks the engine to instantly call the qc's 'timeofday' function, before returning. For compatibility with mvdsv.
timeofday should have the prototype: void(float secs, float mins, float hour, float day, float mon, float year, string strvalue)
@ -969,10 +1000,10 @@ void(vector org, optional float count) te_bloodqw = #239; /* Part of FTE_TE_STAN
float(vector viewpos, entity entity) checkpvs = #240; /* Part of FTE_QC_CHECKPVS*/
vector(entity ent, float tagnum) rotatevectorsbytag = #244;
int(string) stoi = #259; /* Part of FTE_QC_INTCONV
Converts the given string into an integer. Base 8, 10, or 16 is determined based upon the format of the string. */
Converts the given string into a true integer. Base 8, 10, or 16 is determined based upon the format of the string. */
string(int) itos = #260; /* Part of FTE_QC_INTCONV
Converts the passed integer into a base10 string. */
Converts the passed true integer into a base10 string. */
int(string) stoh = #261; /* Part of FTE_QC_INTCONV
Reads a base-16 string (with or without 0x prefix) as an integer. Bugs out if given a base 8 or base 10 string. :P */
@ -980,6 +1011,12 @@ int(string) stoh = #261; /* Part of FTE_QC_INTCONV
string(int) htos = #262; /* Part of FTE_QC_INTCONV
Formats an integer as a base16 string, with leading 0s and no prefix. Always returns 8 characters. */
int(float) ftoi = #0/*:ftoi*/; /*
Converts the given float into a true integer without depending on extended qcvm instructions. */
float(int) itof = #0/*:itof*/; /*
Converts the given true integer into a float without depending on extended qcvm instructions. */
float(float modlindex, optional float useabstransforms) skel_create = #263; /* Part of FTE_CSQC_SKELETONOBJECTS
Allocates a new uninitiaised skeletal object, with enough bone info to animate the given model.
eg: self.skeletonobject = skel_create(self.modelindex); */
@ -1056,6 +1093,9 @@ float(float modelid, int brushid, int faceid, float selectedstate) brush_selecte
int(float modelid, int brushid, int faceid, vector *points, int maxpoints) brush_getfacepoints = #0/*:brush_getfacepoints*/; /*
Returns the list of verticies surrounding the given face. If face is 0, returns the center of the brush (if space for 1 point) or the mins+maxs (if space for 2 points). */
int(int faceid, brushface_t *in_faces, int numfaces, vector *points, int maxpoints) brush_calcfacepoints = #0/*:brush_calcfacepoints*/; /*
Determines the points of the specified face, if the specified brush were to actually be created. */
int(float modelid, vector *planes, float *dists, int numplanes, int *out_brushes, int *out_faces, int maxresults) brush_findinvolume = #0/*:brush_findinvolume*/; /*
Allows you to easily obtain a list of brushes+faces within the given bounding region. If out_faces is not null, the same brush might be listed twice. */
@ -1136,9 +1176,9 @@ void() renderscene = #304; /*
float(vector org, float radius, vector lightcolours, optional float style, optional string cubemapname, optional float pflags) dynamiclight_add = #305; /*
Adds a temporary dlight, ready to be drawn via addscene. Cubemap orientation will be read from v_forward/v_right/v_up. */
void(string texturename, optional float flags) R_BeginPolygon = #306; /*
void(string texturename, optional float flags, optional float is2d) R_BeginPolygon = #306; /*
Specifies the shader to use for the following polygons, along with optional flags.
If flags&4, the polygon will be drawn as soon as the EndPolygon call is made, rather than waiting for renderscene. This allows complex 2d effects. */
If is2d, the polygon will be drawn as soon as the EndPolygon call is made, rather than waiting for renderscene. This allows complex 2d effects. */
void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex = #307; /*
Specifies a polygon vertex with its various properties. */
@ -1259,11 +1299,14 @@ float(string keyname) stringtokeynum = #341; /*
Looks up the key name in the same way that the bind command would, returning the keycode for that key. */
string(float keynum) getkeybind = #342; /*
Finds the current binding for the given key (ignores modifiers like shift/alt/ctrl). */
Returns the current binding for the given key (returning only the command executed when no modifiers are pressed). */
void(float usecursor, optional string cursorimage, optional vector hotspot, optional float scale) setcursormode = #343; /*
Pass TRUE if you want the engine to release the mouse cursor (absolute input events + touchscreen mode). Pass FALSE if you want the engine to grab the cursor (relative input events + standard looking). If the image name is specified, the engine will use that image for a cursor (use an empty string to clear it again), in a way that will not conflict with the console. Images specified this way will be hardware accelerated, if supported by the platform/port. */
float(float effective) getcursormode = #0/*:getcursormode*/; /*
Reports the cursor mode this module previously attempted to use. If 'effective' is true, reports the cursor mode currently active (if was overriden by a different module which has precidence, for instance, or if there is only a touchscreen and no mouse). */
vector() getmousepos = #344; /*
Nasty convoluted DP extension. Typically returns deltas instead of positions. Use CSQC_InputEvent for such things in csqc mods. */
@ -1374,6 +1417,9 @@ void(__variant *dst, float ofs, __variant val) memsetval = #389; /*
__variant*(__variant *base, float ofs) memptradd = #390; /*
Perform some pointer maths. Woo. */
float(string s) memstrsize = #0/*:memstrsize*/; /*
strlen, except ignores utf-8 */
string(string conname, string field, optional string newvalue) con_getset = #391; /* Part of FTE_CSQC_ALTCONSOLES_WIP
Reads or sets a property from a console object. The old value is returned. Iterrate through consoles with the 'next' field. Valid properties: title, name, next, unseen, markup, forceutf8, close, clear, hidden, linecount */
@ -1386,6 +1432,9 @@ void(string conname, vector pos, vector size, float fontsize) con_draw = #393; /
float(string conname, float inevtype, float parama, float paramb, float paramc) con_input = #394; /* Part of FTE_CSQC_ALTCONSOLES_WIP
Forwards input events to the named console. Mouse updates should be absolute only. */
float() cvars_haveunsaved = #0/*:cvars_haveunsaved*/; /*
Returns true if any archived cvar has an unsaved value. */
void(entity from, entity to) copyentity = #400; /* Part of DP_QC_COPYENTITY*/
entity(.string field, string match) findchain = #402; /* Part of DP_QC_FINDCHAIN*/
entity(.float fld, float match) findchainfloat = #403; /* Part of DP_QC_FINDCHAINFLOAT*/
@ -1468,9 +1517,15 @@ float(float s) asin = #471; /* Part of DP_QC_ASINACOSATANATAN2TAN*/
float(float c) acos = #472; /* Part of DP_QC_ASINACOSATANATAN2TAN*/
float(float t) atan = #473; /* Part of DP_QC_ASINACOSATANATAN2TAN*/
float(float c, float s) atan2 = #474; /* Part of DP_QC_ASINACOSATANATAN2TAN*/
float(float a) tan = #475; /* Part of DP_QC_ASINACOSATANATAN2TAN*/
float(string s) strlennocol = #476; /* Part of DP_QC_STRINGCOLORFUNCTIONS*/
string(string s) strdecolorize = #477; /* Part of DP_QC_STRINGCOLORFUNCTIONS*/
float(float a) tan = #475; /* Part of DP_QC_ASINACOSATANATAN2TAN
Forgive me father, for I have a sunbed and I'm not afraid to use it. */
float(string s) strlennocol = #476; /* Part of DP_QC_STRINGCOLORFUNCTIONS
Returns the number of characters in the string after any colour codes or other markup has been parsed. */
string(string s) strdecolorize = #477; /* Part of DP_QC_STRINGCOLORFUNCTIONS
Flattens any markup/colours, removing them from the string. */
string(float uselocaltime, string format, ...) strftime = #478; /* Part of DP_QC_STRFTIME*/
float(string s, string separator1, ...) tokenizebyseparator = #479; /* Part of DP_QC_TOKENIZEBYSEPARATOR*/
string(string s) strtolower = #480; /* Part of DP_QC_STRING_CASE_FUNCTIONS*/
@ -1531,28 +1586,56 @@ __variant(float entnum, float fieldnum) getentity = #504; /*
string(string in) uri_escape = #510; /* Part of DP_QC_URI_ESCAPE*/
string(string in) uri_unescape = #511; /* Part of DP_QC_URI_ESCAPE*/
float(entity ent) num_for_edict = #512;
#define uri_post uri_get
float(string uril, float id, optional string postmimetype, optional string postdata) uri_get = #513; /* Part of DP_QC_URI_GET, DP_QC_URI_POST
uri_get() gets content from an URL and calls a callback "uri_get_callback" with it set as string; an unique ID of the transfer is returned
returns 1 on success, and then calls the callback with the ID, 0 or the HTTP status code, and the received data in a string */
returns 1 on success, and then calls the callback with the ID, 0 or the HTTP status code, and the received data in a string
For a POST request, you will typically want the postmimetype set to application/x-www-form-urlencoded.
For a GET request, omit the mime+data entirely.
Consult your webserver/php/etc documentation for best-practise. */
float(string str) tokenize_console = #514; /*
Tokenize a string exactly as the console's tokenizer would do so. The regular tokenize builtin became bastardized for convienient string parsing, which resulted in a large disparity that can be exploited to bypass checks implemented in a naive SV_ParseClientCommand function, therefore you can use this builtin to make sure it exactly matches. */
float(float idx) argv_start_index = #515; /*
Returns the character index that the tokenized arg started at. */
float(float idx) argv_end_index = #516; /*
Returns the character index that the tokenized arg stopped at. */
float(string str) tokenize_console = #514;
float(float idx) argv_start_index = #515;
float(float idx) argv_end_index = #516;
void(strbuf strbuf, string pattern, string antipattern) buf_cvarlist = #517;
string(string cvarname) cvar_description = #518;
string(string cvarname) cvar_description = #518; /*
Retrieves the description of a cvar, which might be useful for tooltips or help files. This may still not be useful. */
float(optional float timetype) gettime = #519;
string(float keynum) keynumtostring_omgwtf = #520;
string(string command, optional float bindmap) findkeysforcommand = #521;
string(string command, optional float bindmap) findkeysforcommand = #521; /*
Returns a list of keycodes that perform the given console command in a format that can only be parsed via tokenize (NOT tokenize_console). This only and always returns two values - if only one key is actually bound, -1 will be returned. The bindmap argument is listed for compatibility with dp-specific defs, but is ignored in FTE. */
string(string command, optional float bindmap) findkeysforcommandex = #0/*:findkeysforcommandex*/; /*
Returns a list of key bindings in keyname format instead of keynums. Use tokenize to parse. This list may contain modifiers. May return large numbers of keys. */
void(string s) loadfromdata = #529; /*
Reads a set of entities from the given string. This string should have the same format as a .ent file or a saved game. Entities will be spawned as required. If you need to see the entities that were created, you should use parseentitydata instead. */
void(string s) loadfromfile = #530; /*
Reads a set of entities from the named file. This file should have the same format as a .ent file or a saved game. Entities will be spawned as required. If you need to see the entities that were created, you should use parseentitydata instead. */
float(entity e, float channel) getsoundtime = #533;
float(string sample) soundlength = #534;
float(string filename, strbuf bufhandle) buf_loadfile = #535;
float(filestream filehandle, strbuf bufhandle, optional float startpos, optional float numstrings) buf_writefile = #536;
float(entity e, float channel, string newsample, float volume, float attenuation, float pitchpct, float flags, float timeoffset) soundupdate = #0/*:soundupdate*/; /*
Changes the properties of the current sound being played on the given entity channel. newsample may be empty, and will be ignored in this case. timeoffset is relative to the current position (subtract the result of getsoundtime for absolute positions). Negative volume can be used to stop the sound. Return value is a fractional value based upon the number of audio devices that could be updated - test against TRUE rather than non-zero. */
float(entity e, float channel) getsoundtime = #533; /*
Returns the current playback time of the sample on the given entity's channel. Beware CHAN_AUTO (in csqc, channels are not limited by network protocol). */
float(string sample) soundlength = #534; /*
Provides a way to query the duration of a sound sample, allowing you to set up a timer to chain samples. */
float(string filename, strbuf bufhandle) buf_loadfile = #535; /*
Appends the named file into a string buffer (which must have been created in advance). The return value merely says whether the file was readable. */
float(filestream filehandle, strbuf bufhandle, optional float startpos, optional float numstrings) buf_writefile = #536; /*
Writes the contents of a string buffer onto the end of the supplied filehandle (you must have already used fopen). Additional optional arguments permit you to constrain the writes to a subsection of the stringbuffer. */
void(entity e, float physics_enabled) physics_enable = #540; /*
Enable or disable the physics attached to a MOVETYPE_PHYSICS entity. Entities which have been disabled in this way will stop taking so much cpu time. */
@ -1570,10 +1653,13 @@ void(.../*, string funcname*/) callfunction = #605; /*
void(filestream fh, entity e) writetofile = #606; /*
Writes an entity's fields to the named frik_file file handle. */
float(string s) isfunction = #607;
vector(float vidmode, optional float forfullscreen) getresolution = #608;
float(string s) isfunction = #607; /*
Returns true if the named function exists and can be called with the callfunction builtin. */
vector(float vidmode, optional float forfullscreen) getresolution = #608; /*
Supposed to query the driver for supported video modes. FTE does not query drivers in this way, nor would it trust drivers anyway. */
string(float keynum) keynumtostring_menu = #609;
string(string command, optional float bindmap) findkeysforcommand_dp = #610;
float(float type) gethostcachevalue = #611; /* Part of FTE_CSQC_SERVERBROWSER*/
string(float type, float hostnr) gethostcachestring = #612; /* Part of FTE_CSQC_SERVERBROWSER*/
void(entity e, string s) parseentitydata = #613; /*
@ -1594,6 +1680,8 @@ string(string dnsname, optional float defport) netaddress_resolve = #625;
string(string fmt, ...) sprintf = #627;
float(entity e, float s) getsurfacenumtriangles = #628;
vector(entity e, float s, float n) getsurfacetriangle = #629;
vector() getbindmaps = #631;
float(vector bm) setbindmaps = #632;
string(string digest, string data, ...) digest_hex = #639;
#if defined(CSQC) || defined(MENU)
#define K_TAB 9
@ -1707,28 +1795,11 @@ string(string digest, string data, ...) digest_hex = #639;
#define K_CAPSLOCK 155
#define K_SCROLLLOCK 156
#define K_SEMICOLON 59
#define K_PLUS 43
#define K_TILDE 126
#define K_BACKQUOTE 96
#define K_BACKSLASH 92
#endif
#pragma target fte
inline float(float a) retarg = {return a;};
var float glob = 9;
inline float(vector a, vector b, float c) inlinedfunc =
{
// float c = 4;
return a*b*c*glob * (retarg(c)*retarg(a_z));
};
float() itest =
{
return 5*glob*inlinedfunc('0 1 2', '1 2 0', 4);
};
#pragma target fte
#endif
accessor strbuf : float
{
inline get float asfloat[float idx] = {return stof(bufstr_get(this, idx));};
@ -1764,6 +1835,3 @@ accessor filestream : float
inline set string = {fputs(this,value);};
};
#pragma noref 0

File diff suppressed because it is too large Load Diff

View File

@ -1,17 +1,7 @@
//#define ENTS_NYI
#ifdef ENTS_NYI
void() editor_ents_add =
{
};
void(vector mousepos) editor_ents_overlay =
{
drawrawstring('0 32 0', "Not Yet Implemented", '8 8 0', '1 1 1', 1);
};
#else
static int selectedent;
static entity tempent;
static string editkey;
static int editfieldtype; //0 = not editing. 1 = editing the fieldname. 2 = editing the value
typedef struct
{
@ -44,123 +34,123 @@ struct
float spawnflags_mask;
} entclasses[] =
{
{"info_player_start", "progs/player.mdl", '0 1 0', '-16 -16 -24', '16 16 32'},
{"info_player_start", "progs/player.mdl", '1 0 0', '-16 -16 -24', '16 16 32'},
{"info_player_start2", "progs/player.mdl", '1 0 0', '-16 -16 -24', '16 16 32'},
{"info_player_deathmatch", "progs/player.mdl", '1 0 1', '-16 -16 -24', '16 16 32'},
{"info_player_coop", "progs/player.mdl", '1 0 1', '-16 -16 -24', '16 16 32'},
{"info_player_start", "progs/player.mdl", '0 1 0', '-16 -16 -24', '16 16 32'},
{"info_player_start", "progs/player.mdl", '1 0 0', '-16 -16 -24', '16 16 32'},
{"info_player_start2", "progs/player.mdl", '1 0 0', '-16 -16 -24', '16 16 32'},
{"info_player_deathmatch", "progs/player.mdl", '1 0 1', '-16 -16 -24', '16 16 32'},
{"info_player_coop", "progs/player.mdl", '1 0 1', '-16 -16 -24', '16 16 32'},
{"item_armor1", "progs/armor.mdl", '0 0.5 0.8', '-16 -16 0', '16 16 56'},
{"item_armor2", "progs/armor.mdl", '0 0.5 0.8', '-16 -16 0', '16 16 56'},
{"item_armorInv", "progs/armor.mdl", '0 0.5 0.8', '-16 -16 0', '16 16 56'},
{"item_armor1", "progs/armor.mdl", '0 0.5 0.8', '-16 -16 0', '16 16 56'},
{"item_armor2", "progs/armor.mdl", '0 0.5 0.8', '-16 -16 0', '16 16 56'},
{"item_armorInv", "progs/armor.mdl", '0 0.5 0.8', '-16 -16 0', '16 16 56'},
{"weapon_supershotgun", "progs/g_shot.mdl", '0 0.5 0.8', '-16 -16 0', '16 16 56'},
{"weapon_nailgun", "progs/g_nail.mdl", '0 0.5 0.8', '-16 -16 0', '16 16 56'},
{"weapon_supernailgun", "progs/g_nail2.mdl", '0 0.5 0.8', '-16 -16 0', '16 16 56'},
{"weapon_grenadelauncher", "progs/g_rock.mdl", '0 0.5 0.8', '-16 -16 0', '16 16 56'},
{"weapon_rocketlauncher", "progs/g_rock2.mdl", '0 0.5 0.8', '-16 -16 0', '16 16 56'},
{"weapon_lightning", "progs/g_light.mdl", '0 0.5 0.8', '-16 -16 0', '16 16 56'},
{"weapon_supershotgun", "progs/g_shot.mdl", '0 0.5 0.8', '-16 -16 0', '16 16 56'},
{"weapon_nailgun", "progs/g_nail.mdl", '0 0.5 0.8', '-16 -16 0', '16 16 56'},
{"weapon_supernailgun", "progs/g_nail2.mdl", '0 0.5 0.8', '-16 -16 0', '16 16 56'},
{"weapon_grenadelauncher", "progs/g_rock.mdl", '0 0.5 0.8', '-16 -16 0', '16 16 56'},
{"weapon_rocketlauncher", "progs/g_rock2.mdl", '0 0.5 0.8', '-16 -16 0', '16 16 56'},
{"weapon_lightning", "progs/g_light.mdl", '0 0.5 0.8', '-16 -16 0', '16 16 56'},
{"item_key1", "progs/w_s_key.mdl", '0 0.5 0.8', '-16 -16 -24', '16 16 32'},
{"item_key2", "progs/w_g_key.mdl", '0 0.5 0.8', '-16 -16 -24', '16 16 32'},
{"item_sigil", "progs/end1.mdl", '0 0.5 0.8', '-16 -16 -24', '16 16 32'},
{"item_key1", "progs/w_s_key.mdl", '0 0.5 0.8', '-16 -16 -24', '16 16 32'},
{"item_key2", "progs/w_g_key.mdl", '0 0.5 0.8', '-16 -16 -24', '16 16 32'},
{"item_sigil", "progs/end1.mdl", '0 0.5 0.8', '-16 -16 -24', '16 16 32'},
{"item_artifact_invulnerability", "progs/invulner.mdl", '0 0.5 0.8', '-16 -16 -24', '16 16 32'},
{"item_artifact_envirosuit", "progs/suit.mdl", '0 0.5 0.8', '-16 -16 -24', '16 16 32'},
{"item_artifact_invisibility", "progs/invisibl.mdl", '0 0.5 0.8', '-16 -16 -24', '16 16 32'},
{"item_artifact_invulnerability", "progs/invulner.mdl", '0 0.5 0.8', '-16 -16 -24', '16 16 32'},
{"item_artifact_envirosuit", "progs/suit.mdl", '0 0.5 0.8', '-16 -16 -24', '16 16 32'},
{"item_artifact_invisibility", "progs/invisibl.mdl", '0 0.5 0.8', '-16 -16 -24', '16 16 32'},
{"item_artifact_super_damage", "progs/quaddama.mdl", '0 0.5 0.8', '-16 -16 -24', '16 16 32'},
// {"func_button", 0, '0 .5 .8', ?
// {"trigger_changelevel", 0, '0.5 0.5 0.5' ? //NO_INTERMISSION
// {"func_door", 0, '0 .5 .8,' ? //START_OPEN x DOOR_DONT_LINK GOLD_KEY SILVER_KEY TOGGLE
// {"func_door_secret", 0, '0 .5 .8', ? //open_once 1st_left 1st_down no_shoot always_shoot
// {"trigger_portaldespawn", 0, '.5 .5 .5', ?
// {"func_wall", 0, '0 .5 .8', ?
// {"func_illusionary", 0, '0 .5 .8', ?
// {"func_episodegate", 0, '0 .5 .8', ? //E1 E2 E3 E4
// {"func_bossgate", 0, '0 .5 .8', ?
// {"func_plat", 0, '0 .5 .8' ? PLAT_LOW_TRIGGER
// {"func_train", 0, '0 .5 .8' ?
// {"trigger_multiple", 0, '.5 .5 .5' ? notouch
// {"trigger_once", 0, '.5 .5 .5' ? notouch
// {"trigger_secret", 0, '.5 .5 .5' ?
// {"trigger_counter", 0, '.5 .5 .5' ? nomessage
// {"trigger_teleport", 0, '.5 .5 .5' ? PLAYER_ONLY SILENT
// {"trigger_setskill", 0, '.5 .5 .5' ?
// {"trigger_onlyregistered", 0, '.5 .5 .5' ?
// {"trigger_hurt", 0, '.5 .5 .5' ?
// {"trigger_push", 0, '.5 .5 .5' ? PUSH_ONCE
// {"trigger_monsterjump", 0, '.5 .5 .5', ?
// {"trigger_motionsickness", 0, '.5 .5 .5', ?
// {"worldspawn", 0, '0 0 0) ?
// {"func_button", "*", '0 .5 .8', ?
// {"trigger_changelevel", "*", '0.5 0.5 0.5' ? //NO_INTERMISSION
// {"func_door", "*", '0 .5 .8,' ? //START_OPEN x DOOR_DONT_LINK GOLD_KEY SILVER_KEY TOGGLE
// {"func_door_secret", "*", '0 .5 .8', ? //open_once 1st_left 1st_down no_shoot always_shoot
// {"trigger_portaldespawn", "*", '.5 .5 .5', ?
// {"func_wall", "*", '0 .5 .8', ?
// {"func_illusionary", "*", '0 .5 .8', ?
// {"func_episodegate", "*", '0 .5 .8', ? //E1 E2 E3 E4
// {"func_bossgate", "*", '0 .5 .8', ?
// {"func_plat", "*", '0 .5 .8' ? PLAT_LOW_TRIGGER
// {"func_train", "*", '0 .5 .8' ?
// {"trigger_multiple", "*", '.5 .5 .5' ? notouch
// {"trigger_once", "*", '.5 .5 .5' ? notouch
// {"trigger_secret", "*", '.5 .5 .5' ?
// {"trigger_counter", "*", '.5 .5 .5' ? nomessage
// {"trigger_teleport", "*", '.5 .5 .5' ? PLAYER_ONLY SILENT
// {"trigger_setskill", "*", '.5 .5 .5' ?
// {"trigger_onlyregistered", "*", '.5 .5 .5' ?
// {"trigger_hurt", "*", '.5 .5 .5' ?
// {"trigger_push", "*", '.5 .5 .5' ? PUSH_ONCE
// {"trigger_monsterjump", "*", '.5 .5 .5', ?
// {"trigger_motionsickness", "*", '.5 .5 .5', ?
// {"worldspawn", "*", '0 0 0) ?
{"path_corner", 0, '0.5 0.3 0', '-8 -8 -8', '8 8 8'},
{"event_lightning", 0, '0 1 1', '-16 -16 -16', '16 16 16'},
{"info_intermission", 0, '1 0.5 0.5', '-16 -16 -16', '16 16 16'},
{"misc_portalspawn", 0, '.5 .5 .5', '-8 -8 -8', '8 8 8'},
{"noclass", 0, '0 0 0', '-8 -8 -8', '8 8 8'},
{"item_health", "maps/b_bh25.bsp", '.3 .3 1', '0 0 0', '32 32 32'}, //rotten megahealth
{"item_shells", "maps/b_shell0.bsp", '0 .5 .8', '0 0 0', '32 32 32'}, //big
{"item_spikes", "maps/b_nail0.bsp", '0 .5 .8', '0 0 0', '32 32 32'}, //big
{"item_rockets", "maps/b_rock0.bsp", '0 .5 .8', '0 0 0', '32 32 32'}, //big
{"item_cells", "maps/b_batt0.bsp", '0 .5 .8', '0 0 0', '32 32 32'}, //big
{"item_weapon", 0, '0 .5 .8', '0 0 0', '32 32 32'}, //shotgun rocket spikes big
{"info_null", 0, '0 0.5 0', '-4 -4 -4', '4 4 4'},
{"info_notnull", 0, '0 0.5 0', '-4 -4 -4', '4 4 4'},
{"light", 0, '0 1 0', '-8 -8 -8', '8 8 8'}, //START_OFF
{"light_fluoro", 0, '0 1 0', '-8 -8 -8', '8 8 8'},//START_OFF
{"light_fluorospark", 0, '0 1 0', '-8 -8 -8', '8 8 8'},
{"light_globe", 0, '0 1 0', '-8 -8 -8', '8 8 8'},
{"light_torch_small_walltorch", 0, '0 .5 0', '-10 -10 -20', '10 10 20'},
{"light_flame_large_yellow", 0, '0 1 0', '-10 -10 -12', '12 12 18'},
{"light_flame_small_yellow", 0, '0 1 0', '-8 -8 -8', '8 8 8'}, //START_OFF
{"light_flame_small_white", 0, '0 1 0', '-10 -10 -40', '10 10 40'}, //START_OFF
{"misc_fireball", 0, '0 .5 .8', '-8 -8 -8', '8 8 8'},
{"misc_explobox", 0, '0 .5 .8', '0 0 0', '32 32 64'},
{"misc_explobox2", 0, '0 .5 .8', '0 0 0', '32 32 64'},
{"trap_spikeshooter", 0, '0 .5 .8', '-8 -8 -8', '8 8 8'}, //superspike laser
{"trap_shooter", 0, '0 .5 .8', '-8 -8 -8', '8 8 8'}, //superspike laser
{"air_bubbles", 0, '0 .5 .8', '-8 -8 -8', '8 8 8'},
{"viewthing", 0, '0 .5 .8', '-8 -8 -8', '8 8 8'},
{"ambient_suck_wind", 0, '0.3 0.1 0.6', '-10 -10 -8', '10 10 8'},
{"ambient_drone", 0, '0.3 0.1 0.6', '-10 -10 -8', '10 10 8'},
{"ambient_flouro_buzz", 0, '0.3 0.1 0.6', '-10 -10 -8', '10 10 8'},
{"ambient_drip", 0, '0.3 0.1 0.6', '-10 -10 -8', '10 10 8'},
{"ambient_comp_hum", 0, '0.3 0.1 0.6', '-10 -10 -8', '10 10 8'},
{"ambient_thunder", 0, '0.3 0.1 0.6', '-10 -10 -8', '10 10 8'},
{"ambient_light_buzz", 0, '0.3 0.1 0.6', '-10 -10 -8', '10 10 8'},
{"ambient_swamp1", 0, '0.3 0.1 0.6', '-10 -10 -8', '10 10 8'},
{"ambient_swamp2", 0, '0.3 0.1 0.6', '-10 -10 -8', '10 10 8'},
{"misc_noisemaker", 0, '1 0.5 0', '-10 -10 -10', '10 10 10'},
{"misc_teleporttrain", 0, '0 .5 .8', '-8 -8 -8', '8 8 8'},
{"trigger_relay", 0, '.5 .5 .5', '-8 -8 -8', '8 8 8'},
{"info_teleport_destination", 0, '.5 .5 .5', '-8 -8 -8', '8 8 32'},
{"path_corner", 0, '0.5 0.3 0', '-8 -8 -8', '8 8 8'},
{"event_lightning", 0, '0 1 1', '-16 -16 -16', '16 16 16'},
{"info_intermission", 0, '1 0.5 0.5', '-16 -16 -16', '16 16 16'},
{"misc_portalspawn", 0, '.5 .5 .5', '-8 -8 -8', '8 8 8'},
{"noclass", 0, '0 0 0', '-8 -8 -8', '8 8 8'},
{"item_health", "maps/b_bh25.bsp", '.3 .3 1', '0 0 0', '32 32 32'}, //rotten megahealth
{"item_shells", "maps/b_shell0.bsp", '0 .5 .8', '0 0 0', '32 32 32'}, //big
{"item_spikes", "maps/b_nail0.bsp", '0 .5 .8', '0 0 0', '32 32 32'}, //big
{"item_rockets", "maps/b_rock0.bsp", '0 .5 .8', '0 0 0', '32 32 32'}, //big
{"item_cells", "maps/b_batt0.bsp", '0 .5 .8', '0 0 0', '32 32 32'}, //big
{"item_weapon", 0, '0 .5 .8', '0 0 0', '32 32 32'}, //shotgun rocket spikes big
{"info_null", 0, '0 0.5 0', '-4 -4 -4', '4 4 4'},
{"info_notnull", 0, '0 0.5 0', '-4 -4 -4', '4 4 4'},
{"light", 0, '0 1 0', '-8 -8 -8', '8 8 8'}, //START_OFF
{"light_fluoro", 0, '0 1 0', '-8 -8 -8', '8 8 8'},//START_OFF
{"light_fluorospark", 0, '0 1 0', '-8 -8 -8', '8 8 8'},
{"light_globe", 0, '0 1 0', '-8 -8 -8', '8 8 8'},
{"light_torch_small_walltorch", 0, '0 .5 0', '-10 -10 -20', '10 10 20'},
{"light_flame_large_yellow", 0, '0 1 0', '-10 -10 -12', '12 12 18'},
{"light_flame_small_yellow", 0, '0 1 0', '-8 -8 -8', '8 8 8'}, //START_OFF
{"light_flame_small_white", 0, '0 1 0', '-10 -10 -40', '10 10 40'}, //START_OFF
{"misc_fireball", 0, '0 .5 .8', '-8 -8 -8', '8 8 8'},
{"misc_explobox", 0, '0 .5 .8', '0 0 0', '32 32 64'},
{"misc_explobox2", 0, '0 .5 .8', '0 0 0', '32 32 64'},
{"trap_spikeshooter", 0, '0 .5 .8', '-8 -8 -8', '8 8 8'}, //superspike laser
{"trap_shooter", 0, '0 .5 .8', '-8 -8 -8', '8 8 8'}, //superspike laser
{"air_bubbles", 0, '0 .5 .8', '-8 -8 -8', '8 8 8'},
{"viewthing", 0, '0 .5 .8', '-8 -8 -8', '8 8 8'},
{"ambient_suck_wind", 0, '0.3 0.1 0.6', '-10 -10 -8', '10 10 8'},
{"ambient_drone", 0, '0.3 0.1 0.6', '-10 -10 -8', '10 10 8'},
{"ambient_flouro_buzz", 0, '0.3 0.1 0.6', '-10 -10 -8', '10 10 8'},
{"ambient_drip", 0, '0.3 0.1 0.6', '-10 -10 -8', '10 10 8'},
{"ambient_comp_hum", 0, '0.3 0.1 0.6', '-10 -10 -8', '10 10 8'},
{"ambient_thunder", 0, '0.3 0.1 0.6', '-10 -10 -8', '10 10 8'},
{"ambient_light_buzz", 0, '0.3 0.1 0.6', '-10 -10 -8', '10 10 8'},
{"ambient_swamp1", 0, '0.3 0.1 0.6', '-10 -10 -8', '10 10 8'},
{"ambient_swamp2", 0, '0.3 0.1 0.6', '-10 -10 -8', '10 10 8'},
{"misc_noisemaker", 0, '1 0.5 0', '-10 -10 -10', '10 10 10'},
{"misc_teleporttrain", 0, '0 .5 .8', '-8 -8 -8', '8 8 8'},
{"trigger_relay", 0, '.5 .5 .5', '-8 -8 -8', '8 8 8'},
{"info_teleport_destination", 0, '.5 .5 .5', '-8 -8 -8', '8 8 32'},
{"monster_boss", "progs/boss.mdl", '1 0 0', '-128 -128 -24','128 128 256'},
{"monster_hell_knight", "progs/hknight.mdl", '1 0 0', '-16 -16 -24', '16 16 40'}, //Ambush
{"monster_demon1", "progs/demon.mdl", '1 0 0', '-32 -32 -24', '32 32 64'}, //Ambush
{"monster_dog", "progs/dog.mdl", '1 0 0', '-32 -32 -24', '32 32 40'}, //Ambush
{"monster_enforcer", "progs/enforcer.mdl", '1 0 0', '-16 -16 -24', '16 16 40'}, //Ambush
{"monster_fish", "progs/fish.mdl", '1 0 0', '-16 -16 -24', '16 16 24'}, //Ambush
{"monster_ogre", "progs/ogre.mdl", '1 0 0', '-32 -32 -24', '32 32 64'}, //Ambush
{"monster_oldone", "progs/oldone.mdl", '1 0 0', '-16 -16 -24', '16 16 32'},
{"monster_knight", "progs/knight.mdl", '1 0 0', '-16 -16 -24', '16 16 40'}, //Ambush
{"monster_shalrath", "progs/shalrath.mdl", '1 0 0', '-32 -32 -24', '32 32 48'}, //Ambush
{"monster_shambler", "progs/shambler.mdl",'1 0 0', '-32 -32 -24', '32 32 64'}, //Ambush
{"monster_army", "progs/soldier.mdl", '1 0 0', '-16 -16 -24', '16 16 40'}, //Ambush
{"monster_tarbaby", "progs/tarbaby.mdl", '1 0 0', '-16 -16 -24', '16 16 24'}, //Ambush
{"monster_wizard", "progs/wizard.mdl", '1 0 0', '-16 -16 -24', '16 16 40'}, // Ambush
{"monster_zombie", "progs/zombie.mdl", '1 0 0', '-16 -16 -24', '16 16 32'} //Crucified ambush
{"monster_boss", "progs/boss.mdl", '1 0 0', '-128 -128 -24','128 128 256'},
{"monster_hell_knight", "progs/hknight.mdl", '1 0 0', '-16 -16 -24', '16 16 40'}, //Ambush
{"monster_demon1", "progs/demon.mdl", '1 0 0', '-32 -32 -24', '32 32 64'}, //Ambush
{"monster_dog", "progs/dog.mdl", '1 0 0', '-32 -32 -24', '32 32 40'}, //Ambush
{"monster_enforcer", "progs/enforcer.mdl", '1 0 0', '-16 -16 -24', '16 16 40'}, //Ambush
{"monster_fish", "progs/fish.mdl", '1 0 0', '-16 -16 -24', '16 16 24'}, //Ambush
{"monster_ogre", "progs/ogre.mdl", '1 0 0', '-32 -32 -24', '32 32 64'}, //Ambush
{"monster_oldone", "progs/oldone.mdl", '1 0 0', '-16 -16 -24', '16 16 32'},
{"monster_knight", "progs/knight.mdl", '1 0 0', '-16 -16 -24', '16 16 40'}, //Ambush
{"monster_shalrath", "progs/shalrath.mdl", '1 0 0', '-32 -32 -24', '32 32 48'}, //Ambush
{"monster_shambler", "progs/shambler.mdl", '1 0 0', '-32 -32 -24', '32 32 64'}, //Ambush
{"monster_army", "progs/soldier.mdl", '1 0 0', '-16 -16 -24', '16 16 40'}, //Ambush
{"monster_tarbaby", "progs/tarbaby.mdl", '1 0 0', '-16 -16 -24', '16 16 24'}, //Ambush
{"monster_wizard", "progs/wizard.mdl", '1 0 0', '-16 -16 -24', '16 16 40'}, // Ambush
{"monster_zombie", "progs/zombie.mdl", '1 0 0', '-16 -16 -24', '16 16 32'} //Crucified ambush
};
entedit_t*() editor_ents_new =
{
local float nent;
local int nent;
local entedit_t *newents;
nent = numents;
numents += 1;
numents += 1i;
//extend the list
newents = memalloc(sizeof(entedit_t)*numents);
@ -175,13 +165,62 @@ entedit_t*() editor_ents_new =
void(float num) editor_ents_delete =
{
if (num >= 0 && num < numents)
{
hash_destroytab(editents[num].fields);
numents--;
memcpy(&editents[num], &editents[num+1], sizeof(entedit_t) * (numents-num));
}
};
float(float mode) editor_ents_poll =
{
if (mode != MODE_ENTSEDIT)
{
int i, e;
self = world;
terrain_edit(TEREDIT_ENTS_WIPE);
for (e = 0; e < numents; e++)
{
local entedit_t *ent = &editents[e];
string n;
n = "{\n";
for (i = 0; ; i++)
{
string key, value;
key = hash_getkey(ent->fields, i);
if not (key)
break;
value = ent->fields[key];
//inject markup into the value so that it doesn't get too corrupted
value = strreplace("\\", "\\\\", value);
value = strreplace("\"", "\\\"", value);
value = strreplace("\n", "\\n", value);
//these are more optional
value = strreplace("\t", "\\t", value);
value = strreplace("\r", "\\r", value);
n = strcat(n, key, " \"", value, "\"\n");
}
n = strcat(n, "}\n");
terrain_edit(TEREDIT_ENTS_CONCAT, n);
}
localcmd("mod_terrain_save\n"); //saves a .ent if its a bsp, a .map if it has brushes, and a .hmp if otherwise. or something.
ca_checksave = __NULL__;
return TRUE;
}
return FALSE;
}
void() editor_ents_edited =
{
ca_checksave = editor_ents_poll;
}
inline float(string model) modelindexforname =
{
print("precaching \"");
print(model);
print("\"\n");
// print("precaching \"");
// print(model);
// print("\"\n");
precache_model(model);
setmodel(tempent, model);
return tempent.modelindex;
@ -193,10 +232,11 @@ void(entedit_t *nent) editor_ents_updated =
nent->alpha = stof(nent->fields["alpha"]);
nent->scale = stof(nent->fields["scale"]);
nent->modelindex = modelindexforname(nent->fields["model"]);
nent->mins = tempent.mins;
nent->maxs = tempent.maxs;
nent->mins = '-8 -8 -8';
nent->maxs = '8 8 8';
nent->org = stov(nent->fields["origin"]);
nent->isbsp = FALSE;
nent->colourmod = '1 1 1';
ang = stof(nent->fields["angle"]);
if (ang == -1)
@ -231,6 +271,27 @@ void(entedit_t *nent) editor_ents_updated =
nent->ang = '0 0 0'; //bsp entities should not be displayed rotated, because that just messes everything up.
};
entedit_t*(entedit_t *o) editor_ents_clone =
{
int i;
entedit_t *n = editor_ents_new();
for (i = 0; ; i++)
{
string key, value;
key = hash_getkey(o->fields, i);
if not (key)
break;
value = o->fields[key];
n->fields[key] = value;
}
editor_ents_updated(n);
return n;
};
void() editor_ents_reload =
{
local string field, value;
@ -263,7 +324,7 @@ void() editor_ents_reload =
value = getentitytoken();
nent.fields[field] = value;
print(sprintf("%s: %s\n", field, value));
// print(sprintf("%s: %s\n", field, value));
}
editor_ents_updated(nent);
@ -300,7 +361,7 @@ void(string shadername, vector min, vector max, vector col) editor_ents_drawbbox
void() editor_ents_add =
{
float e;
int e;
if (!tempent)
{
tempent = spawn();
@ -336,14 +397,14 @@ void() editor_ents_add =
{
if (e == selectedent)
{
if (gettime(0)*5f & 1)
if ((gettime(0)*5f) & 1)
continue;
tempent.effects |= 8192f;
tempent.effects |= EF_NODEPTHTEST;
editor_ents_drawbbox("entboxsel", editents[e].org+editents[e].mins, editents[e].org+editents[e].maxs, editents[e].colourmod);
}
else
{
tempent.effects &~= 8192f;
tempent.effects &= ~EF_NODEPTHTEST;
editor_ents_drawbbox("entbox", editents[e].org+editents[e].mins, editents[e].org+editents[e].maxs, editents[e].colourmod);
}
@ -363,62 +424,203 @@ void() editor_ents_add =
float(float key, float unic, vector mousepos) editor_ents_key =
{
if (key != K_MOUSE1)
return FALSE;
float bestfrac = 1;
int bestent = selectedent, e;
vector t = mousefar;
vector o = mousenear;
if (vlen(o - t) > 8192)
t = o + normalize(t)*8192;
entedit_t *ent;
for (e = 1; e < numents; e++)
if (key == K_MOUSE1)
{
if (editents[e].isbsp)
tempent.solid = SOLID_BSP;
else
tempent.solid = SOLID_BBOX;
tempent.modelindex = editents[e].modelindex;
tempent.alpha = editents[e].alpha;
tempent.scale = editents[e].scale;
tempent.angles = editents[e].ang;
tempent.colormod = editents[e].colourmod;
tempent.mins = editents[e].mins;
tempent.maxs = editents[e].maxs;
setorigin(tempent, editents[e].org);
traceline(o, t, 256, tempent);
if (bestfrac > trace_fraction)
float bestfrac = 1;
int bestent = selectedent, e;
if (mousepos_x < 128)
{
bestfrac = trace_fraction;
bestent = e;
editfieldtype = editkey?2:1;
return TRUE;
}
editfieldtype = 0;
if (vlen(o - t) > 8192)
t = o + normalize(t)*8192;
for (e = 1; e < numents; e++)
{
if (editents[e].isbsp)
tempent.solid = SOLID_BSP;
else
tempent.solid = SOLID_BBOX;
tempent.modelindex = editents[e].modelindex;
tempent.alpha = editents[e].alpha;
tempent.scale = editents[e].scale;
tempent.angles = editents[e].ang;
tempent.colormod = editents[e].colourmod;
tempent.mins = editents[e].mins;
tempent.maxs = editents[e].maxs;
setorigin(tempent, editents[e].org);
traceline(o, t, 256, tempent);
if (bestfrac > trace_fraction)
{
bestfrac = trace_fraction;
bestent = e;
}
}
tempent.modelindex = SOLID_NOT;
selectedent = bestent;
}
else if (editfieldtype == 1)
{
if (selectedent >= numents)
return FALSE;
if (key == K_ESCAPE)
{
editkey = "";
editfieldtype = 0;
}
else if (key == K_BACKSPACE || key == K_DEL)
{
if (!editkey)
editfieldtype = 0;
else
editkey = substring(editkey, 0, -2);
}
else if (key == K_ENTER && !shiftdown)
{
if (editkey != "")
{
editents[selectedent].fields[editkey] = "";
editfieldtype = 2;
}
}
else if (unic)
editkey = strcat(editkey, chr2str(unic));
else
return FALSE;
}
else if (editfieldtype == 2)
{
if (selectedent >= numents)
return FALSE;
string value = editents[selectedent].fields[editkey];
if (key == K_ESCAPE)
{
editkey = "";
editfieldtype = 0;
}
else if (key == K_BACKSPACE || key == K_DEL)
{
if (!value)
{
hash_delete(editents[selectedent].fields, editkey);
editfieldtype = 0;
}
else
value = substring(value, 0, -2);
}
else if (key == K_ENTER && !shiftdown)
editfieldtype = 0;
else if (key == K_ENTER)
value = strcat(value, chr2str('\n'));
else if (unic)
value = strcat(value, chr2str(unic));
else
return FALSE;
if (editfieldtype)
{
editents[selectedent].fields[editkey] = value;
editor_ents_updated(&editents[selectedent]);
}
}
tempent.modelindex = SOLID_NOT;
else if (key == K_ESCAPE && selectedent)
selectedent = 0;
else if (key == K_BACKSPACE || key == K_DEL)
editor_ents_delete(selectedent);
else if (unic == 'm' || unic == 'M' || unic == 'i' || unic == 'I')
{
traceline(o, t, TRUE, world);
ent = &editents[selectedent];
if (unic == 'i' || unic == 'I')
ent = editor_ents_clone(ent);
selectedent = bestent;
//figure out how far along the plane normal to push the entity in order to ensure that its mins/maxs is on the floor/slope/ceiling/wall/etc
//yay dotproducts
float ext = [
(trace_plane_normal[0] < 0)?ent->mins[0]:ent->maxs[0],
(trace_plane_normal[1] < 0)?ent->mins[1]:ent->maxs[1],
(trace_plane_normal[2] < 0)?ent->mins[2]:ent->maxs[2]
] * trace_plane_normal;
//update the all important origin
string str = sprintf("%v", trace_endpos + trace_plane_normal * ext);
ent->fields["origin"] = str;
//and fix up the quick-access stuff
ent->org = stov(ent->fields["origin"]);
editor_ents_edited();
}
else
return FALSE;
return TRUE;
};
void(vector mousepos) editor_ents_overlay =
{
int i;
vector pos = '0 32 0';
vector pos;
vector col;
float foundedit = FALSE;
float pickedit;
if (selectedent >= numents)
return;
entedit_t *ent = &editents[selectedent];
pos = '128 0 0';
pos_y = vidsize_y - 32;
drawfill('0 16 0', pos, '0 0 0', 0.3);
pos = '0 32 0';
pickedit = !editfieldtype && mousepos_x < 128;
if (pickedit)
editkey = 0;
for (i = 0; ; i++)
{
string key, value;
key = hash_getkey(ent->fields, i);
if not (key)
return;
break;
value = ent->fields[key];
drawrawstring(pos, sprintf("%s: %s", key, value), '8 8 0', '1 1 1', 1);
col = '1 1 1';
if (pickedit && mousepos_y >= pos_y && mousepos_y < pos_y + 8)
{
col_y = 0;
editkey = key;
}
if (key == editkey && editfieldtype)
{
col = '0 0 1';
foundedit = TRUE;
}
//provide some markup so that its actually readable.
value = strreplace("^", "^^", value);
value = strreplace("\\", "^5\\\\^7", value);
value = strreplace("\"", "^5\\\"^7", value);
value = strreplace("\n", "^5\\n^7", value);
value = strreplace("\t", "^5\\t^7", value);
value = strreplace("\r", "^5\\r^7", value);
drawstring(pos, sprintf("%s: %s", key, value), '8 8 0', col, 1, 0);
pos_y += 8;
}
if (editfieldtype && !foundedit)
{
drawrawstring(pos, sprintf("%s: <UNDEFINED>", editkey==""?"<UNMNAMED>":editkey), '8 8 0', '0 0 1', 1);
pos_y += 8;
}
};
#endif

View File

@ -75,9 +75,9 @@ static string(int fld, float foredit) readfield =
return ftos(selectedlight);
return strcat(ftos(selectedlight), " / ", ftos(dynamiclight_get(-1f, -1f)));
case 2:
return sprintf("%v", dynamiclight_get(selectedlight, LFIELD_ORIGIN));
return sprintf("%v", (vector)dynamiclight_get(selectedlight, LFIELD_ORIGIN));
case 3:
return sprintf("%v", dynamiclight_get(selectedlight, LFIELD_COLOUR));
return sprintf("%v", (vector)dynamiclight_get(selectedlight, LFIELD_COLOUR));
case 4:
return ftos(dynamiclight_get(selectedlight, LFIELD_RADIUS));
case 5:
@ -94,7 +94,7 @@ static string(int fld, float foredit) readfield =
case 6:
return ftos(dynamiclight_get(selectedlight, LFIELD_STYLE));
case 7:
return sprintf("%v", dynamiclight_get(selectedlight, LFIELD_ANGLES));
return sprintf("%v", (vector)dynamiclight_get(selectedlight, LFIELD_ANGLES));
case 8:
return ftos(dynamiclight_get(selectedlight, LFIELD_FOV));
case 9:
@ -110,7 +110,7 @@ static string(int fld, float foredit) readfield =
case 14:
return ftos(dynamiclight_get(selectedlight, LFIELD_SPECULARSCALE));
case 15:
return sprintf("%v", dynamiclight_get(selectedlight, LFIELD_ROTATION));
return sprintf("%v", (vector)dynamiclight_get(selectedlight, LFIELD_ROTATION));
default:
return "";
}
@ -430,19 +430,16 @@ float(float keyc, float unic, vector m) editor_lights_key =
}
else if (unic == '[')
{
o = (vector)getproperty(11);
traceline(o, t, TRUE, world);
dynamiclight_set(selectedlight, LFIELD_ORIGIN, dynamiclight_get(selectedlight, LFIELD_ORIGIN) - trace_plane_normal);
dynamiclight_set(selectedlight, LFIELD_ORIGIN, (vector)dynamiclight_get(selectedlight, LFIELD_ORIGIN) - trace_plane_normal);
}
else if (unic == ']')
{
o = (vector)getproperty(11);
traceline(o, t, TRUE, world);
dynamiclight_set(selectedlight, LFIELD_ORIGIN, dynamiclight_get(selectedlight, LFIELD_ORIGIN) + trace_plane_normal);
dynamiclight_set(selectedlight, LFIELD_ORIGIN, (vector)dynamiclight_get(selectedlight, LFIELD_ORIGIN) + trace_plane_normal);
}
else if (unic == '\'' || unic == '@')
{
o = (vector)getproperty(11);
traceline(o, t, TRUE, world);
dynamiclight_set(selectedlight, LFIELD_RADIUS, 1.5*vlen(trace_endpos - (vector)dynamiclight_get(selectedlight, LFIELD_ORIGIN)));
}

View File

@ -200,7 +200,7 @@ static void() updateloadedparticles =
}
ls = le+1;
}
cureffect = -1;
selecteffect(ce);
};
@ -213,6 +213,7 @@ static void(string descname) loadparticles =
if (particlesfile)
strunzone(particlesfile);
particlesfile = (string)0;
cureffect = 0;
/*load new string*/
if (descname != "")
@ -240,7 +241,7 @@ static void(string descname) saveparticle =
/*only do this if there's something to save*/
if (cureffect < 0)
return;
newfile = textfield_strcat(&tf_particle);
newfile = strcat(substring(particlesfile, 0, pdesc[cureffect].start), newfile, substring(particlesfile, pdesc[cureffect].end, -1));
@ -377,6 +378,8 @@ void(vector mousepos) editor_particles_overlay =
pointparticles(particleeffectnum(pdesc[cureffect].efname), trace_endpos, '0 0 -1', 1);
}
//fixme: should ONLY be done if we started dragging.
trailparticles(particleeffectnum(pdesc[cureffect].efname), ptrailent, ptrailent.origin, trace_endpos);
ptrailent.origin = trace_endpos;
}

View File

@ -52,7 +52,7 @@ static var string tint[8] = {"1 1 1", "1.2 0.9 0.9", "0 1 0"};
static string meshname;
static var float curtool = ter_blank;
static var float lasttool = ter_blank;
static float painttex;
static int painttex;
static float mautorepeattime;
static entity tempent;
static var float texturesearch = -1;
@ -148,6 +148,12 @@ void(vector m, float repeated) editor_do =
else
terrain_edit(TEREDIT_HEIGHT_SPREAD, trace_endpos, eradius, epercent/100.0);
break;
case ter_height_flatten:
if (autocvar_mod_terrain_networked && !isserver())
sendevent("teredit", "fvff", TEREDIT_HEIGHT_FLATTEN, trace_endpos, eradius, epercent/100.0);
else
terrain_edit(TEREDIT_HEIGHT_FLATTEN, trace_endpos, eradius, epercent/100.0);
break;
case ter_water_set:
if (autocvar_mod_terrain_networked && !isserver())
sendevent("teredit", "fvff", TEREDIT_WATER_SET, trace_endpos, eradius, equant);
@ -441,6 +447,10 @@ void(vector mousepos) editor_terrain_add =
float r;
vector tx, p, col;
float a;
if (curtool == ter_tex_paint || curtool == ter_tex_paint_single || curtool == ter_tex)
terrain_edit(22, tex[painttex]);
if (mousepos_x < 128)
return;
@ -503,6 +513,9 @@ void(vector mousepos) editor_terrain_overlay =
float i;
vector pos;
vector colour;
// if (curtool == ter_tex_paint || curtool == ter_tex_paint_single || curtool == ter_tex)
terrain_edit(22, 0);
float ctime = gettime(5);
if (mautorepeattime)

View File

@ -290,7 +290,7 @@ void(string fieldname, vector pos, vector *mousepos_in, float *value, float key)
void(menu_t *menu, string fieldname, vector pos, int *value) checkboxi_widgit =
{
local vector rpos, epos, spos, col;
local vector epos, spos, col;
local int render_only = 0;
local vector mousepos = *menu->mousepos;
local vector mousediff = menu->mousediff;
@ -338,7 +338,7 @@ void(menu_t *menu, string fieldname, vector pos, int *value) checkboxi_widgit =
int (menu_t *menu, string fieldname, vector pos) button_widget =
{
local vector rpos, epos, spos, col;
local vector epos, spos, col;
local int render_only = 0;
local vector mousepos = *menu->mousepos;
local vector mousediff = menu->mousediff;