+/*
+=================
+PF_copyentity
+
+copies data from one entity to another
+
+copyentity(src, dst)
+=================
+*/
+void PF_copyentity (void)
+{
+ edict_t *in, *out;
+ in = G_EDICT(OFS_PARM0);
+ if (in == sv.edicts)
+ PF_WARNING("copyentity: can not read world entity\n");
+ if (in->e->free)
+ PF_WARNING("copyentity: can not read free entity\n");
+ out = G_EDICT(OFS_PARM1);
+ if (out == sv.edicts)
+ PF_WARNING("copyentity: can not modify world entity\n");
+ if (out->e->free)
+ PF_WARNING("copyentity: can not modify free entity\n");
+ memcpy(out->v, in->v, progs->entityfields * 4);
+}
+
+/*
+=================
+PF_setcolor
+
+sets the color of a client and broadcasts the update to all connected clients
+
+setcolor(clientent, value)
+=================
+*/
+void PF_setcolor (void)
+{
+ client_t *client;
+ int entnum, i;
+ eval_t *val;
+
+ entnum = G_EDICTNUM(OFS_PARM0);
+ i = G_FLOAT(OFS_PARM1);
+
+ if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
+ {
+ Con_Print("tried to setcolor a non-client\n");
+ return;
+ }
+
+ client = svs.clients + entnum-1;
+ if ((val = GETEDICTFIELDVALUE(client->edict, eval_clientcolors)))
+ val->_float = i;
+ client->colors = i;
+ client->old_colors = i;
+ client->edict->v->team = (i & 15) + 1;
+
+ MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
+ MSG_WriteByte (&sv.reliable_datagram, entnum - 1);
+ MSG_WriteByte (&sv.reliable_datagram, i);
+}
+
+/*
+=================
+PF_effect
+
+effect(origin, modelname, startframe, framecount, framerate)
+=================
+*/
+void PF_effect (void)
+{
+ char *s;
+ s = G_STRING(OFS_PARM1);
+ if (!s || !s[0])
+ PF_WARNING("effect: no model specified\n");
+
+ SV_StartEffect(G_VECTOR(OFS_PARM0), SV_ModelIndex(s), G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), G_FLOAT(OFS_PARM4));
+}
+
+void PF_te_blood (void)
+{
+ if (G_FLOAT(OFS_PARM2) < 1)
+ return;
+ MSG_WriteByte(&sv.datagram, svc_temp_entity);
+ MSG_WriteByte(&sv.datagram, TE_BLOOD);
+ // origin
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+ // velocity
+ MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
+ MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
+ MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
+ // count
+ MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
+}
+
+void PF_te_bloodshower (void)
+{
+ if (G_FLOAT(OFS_PARM3) < 1)
+ return;
+ MSG_WriteByte(&sv.datagram, svc_temp_entity);
+ MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
+ // min
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+ // max
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
+ // speed
+ MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM2));
+ // count
+ MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
+}
+
+void PF_te_explosionrgb (void)
+{
+ MSG_WriteByte(&sv.datagram, svc_temp_entity);
+ MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
+ // origin
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+ // color
+ MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[0] * 255), 255));
+ MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[1] * 255), 255));
+ MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[2] * 255), 255));
+}
+
+void PF_te_particlecube (void)
+{
+ if (G_FLOAT(OFS_PARM3) < 1)
+ return;
+ MSG_WriteByte(&sv.datagram, svc_temp_entity);
+ MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
+ // min
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+ // max
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
+ // velocity
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
+ // count
+ MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
+ // color
+ MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
+ // gravity true/false
+ MSG_WriteByte(&sv.datagram, ((int) G_FLOAT(OFS_PARM5)) != 0);
+ // randomvel
+ MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM6));
+}
+
+void PF_te_particlerain (void)
+{
+ if (G_FLOAT(OFS_PARM3) < 1)
+ return;
+ MSG_WriteByte(&sv.datagram, svc_temp_entity);
+ MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
+ // min
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+ // max
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
+ // velocity
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
+ // count
+ MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
+ // color
+ MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
+}
+
+void PF_te_particlesnow (void)
+{
+ if (G_FLOAT(OFS_PARM3) < 1)
+ return;
+ MSG_WriteByte(&sv.datagram, svc_temp_entity);
+ MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
+ // min
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+ // max
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
+ // velocity
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
+ // count
+ MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
+ // color
+ MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM4));
+}
+
+void PF_te_spark (void)
+{
+ if (G_FLOAT(OFS_PARM2) < 1)
+ return;
+ MSG_WriteByte(&sv.datagram, svc_temp_entity);
+ MSG_WriteByte(&sv.datagram, TE_SPARK);
+ // origin
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+ // velocity
+ MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
+ MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
+ MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[2], 127));
+ // count
+ MSG_WriteByte(&sv.datagram, bound(0, (int) G_FLOAT(OFS_PARM2), 255));
+}
+
+void PF_te_gunshotquad (void)
+{
+ MSG_WriteByte(&sv.datagram, svc_temp_entity);
+ MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
+ // origin
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+}
+
+void PF_te_spikequad (void)
+{
+ MSG_WriteByte(&sv.datagram, svc_temp_entity);
+ MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
+ // origin
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+}
+
+void PF_te_superspikequad (void)
+{
+ MSG_WriteByte(&sv.datagram, svc_temp_entity);
+ MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
+ // origin
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+}
+
+void PF_te_explosionquad (void)
+{
+ MSG_WriteByte(&sv.datagram, svc_temp_entity);
+ MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
+ // origin
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+}
+
+void PF_te_smallflash (void)
+{
+ MSG_WriteByte(&sv.datagram, svc_temp_entity);
+ MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
+ // origin
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+}
+
+void PF_te_customflash (void)
+{
+ if (G_FLOAT(OFS_PARM1) < 8 || G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
+ return;
+ MSG_WriteByte(&sv.datagram, svc_temp_entity);
+ MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
+ // origin
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+ // radius
+ MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM1) / 8 - 1, 255));
+ // lifetime
+ MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM2) / 256 - 1, 255));
+ // color
+ MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[0] * 255, 255));
+ MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[1] * 255, 255));
+ MSG_WriteByte(&sv.datagram, bound(0, G_VECTOR(OFS_PARM3)[2] * 255, 255));
+}
+
+void PF_te_gunshot (void)
+{
+ MSG_WriteByte(&sv.datagram, svc_temp_entity);
+ MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
+ // origin
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+}
+
+void PF_te_spike (void)
+{
+ MSG_WriteByte(&sv.datagram, svc_temp_entity);
+ MSG_WriteByte(&sv.datagram, TE_SPIKE);
+ // origin
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+}
+
+void PF_te_superspike (void)
+{
+ MSG_WriteByte(&sv.datagram, svc_temp_entity);
+ MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
+ // origin
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+}
+
+void PF_te_explosion (void)
+{
+ MSG_WriteByte(&sv.datagram, svc_temp_entity);
+ MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
+ // origin
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+}
+
+void PF_te_tarexplosion (void)
+{
+ MSG_WriteByte(&sv.datagram, svc_temp_entity);
+ MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
+ // origin
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+}
+
+void PF_te_wizspike (void)
+{
+ MSG_WriteByte(&sv.datagram, svc_temp_entity);
+ MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
+ // origin
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+}
+
+void PF_te_knightspike (void)
+{
+ MSG_WriteByte(&sv.datagram, svc_temp_entity);
+ MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
+ // origin
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+}
+
+void PF_te_lavasplash (void)
+{
+ MSG_WriteByte(&sv.datagram, svc_temp_entity);
+ MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
+ // origin
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+}
+
+void PF_te_teleport (void)
+{
+ MSG_WriteByte(&sv.datagram, svc_temp_entity);
+ MSG_WriteByte(&sv.datagram, TE_TELEPORT);
+ // origin
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+}
+
+void PF_te_explosion2 (void)
+{
+ MSG_WriteByte(&sv.datagram, svc_temp_entity);
+ MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
+ // origin
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+ // color
+ MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM1));
+ MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM2));
+}
+
+void PF_te_lightning1 (void)
+{
+ MSG_WriteByte(&sv.datagram, svc_temp_entity);
+ MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
+ // owner entity
+ MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
+ // start
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
+ // end
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
+}
+
+void PF_te_lightning2 (void)
+{
+ MSG_WriteByte(&sv.datagram, svc_temp_entity);
+ MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
+ // owner entity
+ MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
+ // start
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
+ // end
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
+}
+
+void PF_te_lightning3 (void)
+{
+ MSG_WriteByte(&sv.datagram, svc_temp_entity);
+ MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
+ // owner entity
+ MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
+ // start
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
+ // end
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
+}
+
+void PF_te_beam (void)
+{
+ MSG_WriteByte(&sv.datagram, svc_temp_entity);
+ MSG_WriteByte(&sv.datagram, TE_BEAM);
+ // owner entity
+ MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
+ // start
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
+ // end
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
+}
+
+void PF_te_plasmaburn (void)
+{
+ MSG_WriteByte(&sv.datagram, svc_temp_entity);
+ MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
+ MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+}
+
+static void clippointtosurface(msurface_t *surf, vec3_t p, vec3_t out)
+{
+ int i, j;
+ vec3_t v1, clipplanenormal, normal;
+ vec_t clipplanedist, clipdist;
+ VectorCopy(p, out);
+ if (surf->flags & SURF_PLANEBACK)
+ VectorNegate(surf->plane->normal, normal);
+ else
+ VectorCopy(surf->plane->normal, normal);
+ for (i = 0, j = surf->poly_numverts - 1;i < surf->poly_numverts;j = i, i++)
+ {
+ VectorSubtract(&surf->poly_verts[j * 3], &surf->poly_verts[i * 3], v1);
+ VectorNormalizeFast(v1);
+ CrossProduct(v1, normal, clipplanenormal);
+ clipplanedist = DotProduct(&surf->poly_verts[i * 3], clipplanenormal);
+ clipdist = DotProduct(out, clipplanenormal) - clipplanedist;
+ if (clipdist > 0)
+ {
+ clipdist = -clipdist;
+ VectorMA(out, clipdist, clipplanenormal, out);
+ }
+ }
+}
+
+static msurface_t *getsurface(edict_t *ed, int surfnum)
+{
+ int modelindex;
+ model_t *model;
+ if (!ed || ed->e->free)
+ return NULL;
+ modelindex = ed->v->modelindex;
+ if (modelindex < 1 || modelindex >= MAX_MODELS)
+ return NULL;
+ model = sv.models[modelindex];
+ if (surfnum < 0 || surfnum >= model->nummodelsurfaces)
+ return NULL;
+ return model->brushq1.surfaces + surfnum + model->firstmodelsurface;
+}
+
+
+//PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
+void PF_getsurfacenumpoints(void)
+{
+ msurface_t *surf;
+ // return 0 if no such surface
+ if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
+ {
+ G_FLOAT(OFS_RETURN) = 0;
+ return;
+ }
+
+ G_FLOAT(OFS_RETURN) = surf->poly_numverts;
+}
+//PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
+void PF_getsurfacepoint(void)
+{
+ edict_t *ed;
+ msurface_t *surf;
+ int pointnum;
+ VectorClear(G_VECTOR(OFS_RETURN));
+ ed = G_EDICT(OFS_PARM0);
+ if (!ed || ed->e->free)
+ return;
+ if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
+ return;
+ pointnum = G_FLOAT(OFS_PARM2);
+ if (pointnum < 0 || pointnum >= surf->poly_numverts)
+ return;
+ // FIXME: implement rotation/scaling
+ VectorAdd(&surf->poly_verts[pointnum * 3], ed->v->origin, G_VECTOR(OFS_RETURN));
+}
+//PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal = #436;
+void PF_getsurfacenormal(void)
+{
+ msurface_t *surf;
+ VectorClear(G_VECTOR(OFS_RETURN));
+ if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
+ return;
+ // FIXME: implement rotation/scaling
+ if (surf->flags & SURF_PLANEBACK)
+ VectorNegate(surf->plane->normal, G_VECTOR(OFS_RETURN));
+ else
+ VectorCopy(surf->plane->normal, G_VECTOR(OFS_RETURN));
+}
+//PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture = #437;
+void PF_getsurfacetexture(void)
+{
+ msurface_t *surf;
+ G_INT(OFS_RETURN) = 0;
+ if (!(surf = getsurface(G_EDICT(OFS_PARM0), G_FLOAT(OFS_PARM1))))
+ return;
+ G_INT(OFS_RETURN) = PR_SetString(surf->texinfo->texture->name);
+}
+//PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
+void PF_getsurfacenearpoint(void)
+{
+ int surfnum, best, modelindex;
+ vec3_t clipped, p;
+ vec_t dist, bestdist;
+ edict_t *ed;
+ model_t *model;
+ msurface_t *surf;
+ vec_t *point;
+ G_FLOAT(OFS_RETURN) = -1;
+ ed = G_EDICT(OFS_PARM0);
+ point = G_VECTOR(OFS_PARM1);
+
+ if (!ed || ed->e->free)
+ return;
+ modelindex = ed->v->modelindex;
+ if (modelindex < 1 || modelindex >= MAX_MODELS)
+ return;
+ model = sv.models[modelindex];
+ if (!model->brushq1.numsurfaces)
+ return;
+
+ // FIXME: implement rotation/scaling
+ VectorSubtract(point, ed->v->origin, p);
+ best = -1;
+ bestdist = 1000000000;
+ for (surfnum = 0;surfnum < model->nummodelsurfaces;surfnum++)
+ {
+ surf = model->brushq1.surfaces + surfnum + model->firstmodelsurface;
+ dist = PlaneDiff(p, surf->plane);
+ dist = dist * dist;
+ if (dist < bestdist)
+ {
+ clippointtosurface(surf, p, clipped);
+ VectorSubtract(clipped, p, clipped);
+ dist += DotProduct(clipped, clipped);
+ if (dist < bestdist)
+ {
+ best = surfnum;
+ bestdist = dist;
+ }
+ }
+ }
+ G_FLOAT(OFS_RETURN) = best;
+}
+//PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
+void PF_getsurfaceclippedpoint(void)
+{
+ edict_t *ed;
+ msurface_t *surf;
+ vec3_t p, out;
+ VectorClear(G_VECTOR(OFS_RETURN));
+ ed = G_EDICT(OFS_PARM0);
+ if (!ed || ed->e->free)
+ return;
+ if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1))))
+ return;
+ // FIXME: implement rotation/scaling
+ VectorSubtract(G_VECTOR(OFS_PARM2), ed->v->origin, p);
+ clippointtosurface(surf, p, out);
+ // FIXME: implement rotation/scaling
+ VectorAdd(out, ed->v->origin, G_VECTOR(OFS_RETURN));
+}
+
+#define MAX_PRFILES 256
+
+qfile_t *pr_files[MAX_PRFILES];
+
+void PR_Files_Init(void)
+{
+ memset(pr_files, 0, sizeof(pr_files));
+}
+
+void PR_Files_CloseAll(void)
+{
+ int i;
+ for (i = 0;i < MAX_PRFILES;i++)
+ {
+ if (pr_files[i])
+ FS_Close(pr_files[i]);
+ pr_files[i] = NULL;
+ }
+}
+
+//float(string s) stof = #81; // get numerical value from a string
+void PF_stof(void)
+{
+ char string[STRINGTEMP_LENGTH];
+ PF_VarString(0, string, sizeof(string));
+ G_FLOAT(OFS_RETURN) = atof(string);
+}
+
+//float(string filename, float mode) fopen = #110; // opens a file inside quake/gamedir/data/ (mode is FILE_READ, FILE_APPEND, or FILE_WRITE), returns fhandle >= 0 if successful, or fhandle < 0 if unable to open file for any reason
+void PF_fopen(void)
+{
+ int filenum, mode, i;
+ char *modestring, *filename;
+ for (filenum = 0;filenum < MAX_PRFILES;filenum++)
+ if (pr_files[filenum] == NULL)
+ break;
+ if (filenum >= MAX_PRFILES)
+ {
+ Con_Printf("PF_fopen: ran out of file handles (%i)\n", MAX_PRFILES);
+ G_FLOAT(OFS_RETURN) = -2;
+ return;
+ }
+ mode = G_FLOAT(OFS_PARM1);
+ switch(mode)
+ {
+ case 0: // FILE_READ
+ modestring = "rb";
+ break;
+ case 1: // FILE_APPEND
+ modestring = "ab";
+ break;
+ case 2: // FILE_WRITE
+ modestring = "wb";
+ break;
+ default:
+ Con_Printf("PF_fopen: no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", mode);
+ G_FLOAT(OFS_RETURN) = -3;
+ return;
+ }
+ filename = G_STRING(OFS_PARM0);
+ // control characters do not cause issues with any platforms I know of, but they are usually annoying to deal with
+ // ../ is parent directory on many platforms
+ // // is parent directory on Amiga
+ // / at the beginning of a path is root on unix, and parent directory on Amiga
+ // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea)
+ // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
+ for (i = 0;filename[i];i++)
+ {
+ if (filename[i] < ' ' || (filename[i] == '/' && filename[i+1] == '/') || (filename[i] == '.' && filename[i+1] == '.') || filename[i] == ':' || filename[i] == '\\' || filename[0] == '/')
+ {
+ Con_Printf("PF_fopen: dangerous/confusing/annoying/non-portable filename \"%s\" not allowed. (contains control characters or // or .. or : or \\ or begins with /)\n", filename);
+ G_FLOAT(OFS_RETURN) = -4;
+ return;
+ }
+ }
+ pr_files[filenum] = FS_Open(va("data/%s", filename), modestring, false);
+
+ if (pr_files[filenum] == NULL && modestring == "rb")
+ pr_files[filenum] = FS_Open(filename, modestring, false);
+
+ if (pr_files[filenum] == NULL)
+ G_FLOAT(OFS_RETURN) = -1;
+ else
+ G_FLOAT(OFS_RETURN) = filenum;
+}
+
+//void(float fhandle) fclose = #111; // closes a file
+void PF_fclose(void)
+{
+ int filenum = G_FLOAT(OFS_PARM0);
+ if (filenum < 0 || filenum >= MAX_PRFILES)
+ {
+ Con_Printf("PF_fclose: invalid file handle %i\n", filenum);
+ return;
+ }
+ if (pr_files[filenum] == NULL)
+ {
+ Con_Printf("PF_fclose: no such file handle %i (or file has been closed)\n", filenum);
+ return;
+ }
+ FS_Close(pr_files[filenum]);
+ pr_files[filenum] = NULL;
+}
+
+//string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
+void PF_fgets(void)
+{
+ int c, end;
+ static char string[STRINGTEMP_LENGTH];
+ int filenum = G_FLOAT(OFS_PARM0);
+ if (filenum < 0 || filenum >= MAX_PRFILES)
+ {
+ Con_Printf("PF_fgets: invalid file handle %i\n", filenum);
+ return;
+ }
+ if (pr_files[filenum] == NULL)
+ {
+ Con_Printf("PF_fgets: no such file handle %i (or file has been closed)\n", filenum);
+ return;
+ }
+ end = 0;
+ for (;;)
+ {
+ c = FS_Getc(pr_files[filenum]);
+ if (c == '\r' || c == '\n' || c < 0)
+ break;
+ if (end < STRINGTEMP_LENGTH - 1)
+ string[end++] = c;
+ }
+ string[end] = 0;
+ // remove \n following \r
+ if (c == '\r')
+ c = FS_Getc(pr_files[filenum]);
+ if (developer.integer)
+ Con_Printf("fgets: %s\n", string);
+ if (c >= 0)
+ G_INT(OFS_RETURN) = PR_SetString(string);
+ else
+ G_INT(OFS_RETURN) = 0;
+}
+
+//void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
+void PF_fputs(void)
+{
+ int stringlength;
+ char string[STRINGTEMP_LENGTH];
+ int filenum = G_FLOAT(OFS_PARM0);
+ if (filenum < 0 || filenum >= MAX_PRFILES)
+ {
+ Con_Printf("PF_fputs: invalid file handle %i\n", filenum);
+ return;
+ }
+ if (pr_files[filenum] == NULL)
+ {
+ Con_Printf("PF_fputs: no such file handle %i (or file has been closed)\n", filenum);
+ return;
+ }
+ PF_VarString(1, string, sizeof(string));
+ if ((stringlength = strlen(string)))
+ FS_Write(pr_files[filenum], string, stringlength);
+ if (developer.integer)
+ Con_Printf("fputs: %s\n", string);
+}
+
+//float(string s) strlen = #114; // returns how many characters are in a string
+void PF_strlen(void)
+{
+ char *s;
+ s = G_STRING(OFS_PARM0);
+ if (s)
+ G_FLOAT(OFS_RETURN) = strlen(s);
+ else
+ G_FLOAT(OFS_RETURN) = 0;
+}
+
+//string(string s1, string s2) strcat = #115; // concatenates two strings (for example "abc", "def" would return "abcdef") and returns as a tempstring
+void PF_strcat(void)