+/*
+=================
+PF_effect
+
+effect(origin, modelname, startframe, framecount, framerate)
+=================
+*/
+void PF_effect (void)
+{
+ char *s;
+ s = G_STRING(OFS_PARM1);
+ if (!s || !s[0])
+ Host_Error("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));
+}
+
+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->free)
+ return NULL;
+ modelindex = ed->v->modelindex;
+ if (modelindex < 1 || modelindex >= MAX_MODELS)
+ return NULL;
+ model = sv.models[modelindex];
+ if (model->type != mod_brush)
+ return NULL;
+ if (surfnum < 0 || surfnum >= model->nummodelsurfaces)
+ return NULL;
+ return model->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->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->free)
+ return;
+ modelindex = ed->v->modelindex;
+ if (modelindex < 1 || modelindex >= MAX_MODELS)
+ return;
+ model = sv.models[modelindex];
+ if (model->type != mod_brush)
+ return;
+
+ // FIXME: implement rotation/scaling
+ VectorSubtract(point, ed->v->origin, p);
+ best = -1;
+ bestdist = 1000000000;
+ for (surfnum = 0;surfnum < model->nummodelsurfaces;surfnum++)
+ {
+ surf = model->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->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));
+}
+