]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - pr_cmds.c
whitespace
[xonotic/darkplaces.git] / pr_cmds.c
index 39060d594163d86307e102d5955402a19821361e..7cf39ca5786d8f7aef93eca4d8bcb4989f292223 100644 (file)
--- a/pr_cmds.c
+++ b/pr_cmds.c
@@ -37,59 +37,62 @@ cvar_t      sv_aim = {CVAR_SAVE, "sv_aim", "2"}; //"0.93"}; // LordHavoc: disabled au
 char *PF_VarString (int        first)
 {
        int             i;
-       static char out[256];
+       static char out[4096]; // FIXME: buffer overflow potential
 
        out[0] = 0;
-       for (i=first ; i<pr_argc ; i++)
-       {
+       for (i = first;i < pr_argc;i++)
                strcat (out, G_STRING((OFS_PARM0+i*3)));
-       }
        return out;
 }
 
-char *ENGINE_EXTENSIONS = "\
-DP_ENT_ALPHA \
-DP_ENT_COLORMOD \
-DP_ENT_DELTACOMPRESS \
-DP_ENT_GLOW \
-DP_ENT_SCALE \
-DP_ENT_VIEWMODEL \
-DP_GFX_FOG \
-DP_HALFLIFE_MAP \
-DP_INPUTBUTTONS \
-DP_MONSTERWALK \
-DP_MOVETYPEFOLLOW \
-DP_QC_CHANGEPITCH \
-DP_QC_COPYENTITY \
-DP_QC_ETOS \
-DP_QC_FINDCHAIN \
-DP_QC_FINDCHAINFLOAT \
-DP_QC_FINDFLOAT \
-DP_QC_GETLIGHT \
-DP_QC_MINMAXBOUND \
-DP_QC_RANDOMVEC \
-DP_QC_SINCOSSQRTPOW \
-DP_QC_TRACEBOX \
-DP_QC_TRACETOSS \
-DP_QUAKE2_MODEL \
-DP_REGISTERCVAR \
-DP_SOLIDCORPSE \
-DP_SPRITE32 \
-DP_SV_DRAWONLYTOCLIENT \
-DP_SV_EFFECT \
-DP_SV_EXTERIORMODELTOCLIENT \
-DP_SV_NODRAWTOCLIENT \
-DP_SV_SETCOLOR \
-DP_TE_BLOOD \
-DP_TE_BLOODSHOWER \
-DP_TE_EXPLOSIONRGB \
-DP_TE_PARTICLECUBE \
-DP_TE_PARTICLERAIN \
-DP_TE_PARTICLESNOW \
-DP_TE_SPARK \
-NEH_CMD_PLAY2 \
-TW_SV_STEPCONTROL \
-";
+char *ENGINE_EXTENSIONS =
+"DP_ENT_ALPHA "
+"DP_ENT_CUSTOMCOLORMAP "
+"DP_ENT_EXTERIORMODELTOCLIENT "
+"DP_ENT_LOWPRECISION "
+"DP_ENT_GLOW "
+"DP_ENT_SCALE "
+"DP_ENT_VIEWMODEL "
+"DP_GFX_FOG "
+"DP_HALFLIFE_MAP "
+"DP_INPUTBUTTONS "
+"DP_MONSTERWALK "
+"DP_MOVETYPEFOLLOW "
+"DP_QC_CHANGEPITCH "
+"DP_QC_COPYENTITY "
+"DP_QC_ETOS "
+"DP_QC_FINDCHAIN "
+"DP_QC_FINDCHAINFLOAT "
+"DP_QC_FINDFLOAT "
+"DP_QC_GETLIGHT "
+"DP_QC_MINMAXBOUND "
+"DP_QC_RANDOMVEC "
+"DP_QC_SINCOSSQRTPOW "
+"DP_QC_TRACEBOX "
+"DP_QC_TRACETOSS "
+"DP_QC_VECTORVECTORS "
+"DP_QUAKE2_MODEL "
+"DP_REGISTERCVAR "
+"DP_SOLIDCORPSE "
+"DP_SPRITE32 "
+"DP_SV_DRAWONLYTOCLIENT "
+"DP_SV_EFFECT "
+"DP_SV_EXTERIORMODELTOCLIENT "
+"DP_SV_NODRAWTOCLIENT "
+"DP_SV_PLAYERPHYSICS "
+"DP_SV_SETCOLOR "
+"DP_SV_SLOWMO "
+"DP_TE_BLOOD "
+"DP_TE_BLOODSHOWER "
+"DP_TE_EXPLOSIONRGB "
+"DP_TE_PARTICLECUBE "
+"DP_TE_PARTICLERAIN "
+"DP_TE_PARTICLESNOW "
+"DP_TE_SPARK "
+"NEH_CMD_PLAY2 "
+"NEH_RESTOREGAME "
+"TW_SV_STEPCONTROL "
+;
 
 qboolean checkextension(char *name)
 {
@@ -140,7 +143,7 @@ void PF_error (void)
 {
        char    *s;
        edict_t *ed;
-       
+
        s = PF_VarString(0);
        Con_Printf ("======SERVER ERROR in %s:\n%s\n", pr_strings + pr_xfunction->s_name, s);
        ed = PROG_TO_EDICT(pr_global_struct->self);
@@ -163,7 +166,7 @@ void PF_objerror (void)
 {
        char    *s;
        edict_t *ed;
-       
+
        s = PF_VarString(0);
        Con_Printf ("======OBJECT ERROR in %s:\n%s\n", pr_strings + pr_xfunction->s_name, s);
        ed = PROG_TO_EDICT(pr_global_struct->self);
@@ -226,7 +229,7 @@ void SetMinMaxSize (edict_t *e, float *min, float *max, qboolean rotate)
        
        for (i=0 ; i<3 ; i++)
                if (min[i] > max[i])
-                       PR_RunError ("backwards mins/maxs");
+                       Host_Error ("backwards mins/maxs");
 
 // set derived values
        VectorCopy (min, e->v.mins);
@@ -281,7 +284,7 @@ void PF_setmodel (void)
                        break;
 
        if (!*check)
-               PR_RunError ("no precache: %s\n", m);
+               Host_Error ("no precache: %s\n", m);
 
 
        e->v.model = m - pr_strings;
@@ -643,7 +646,7 @@ break()
 */
 void PF_break (void)
 {
-       PR_RunError ("break statement");
+       Host_Error ("break statement");
 }
 
 /*
@@ -846,15 +849,15 @@ void PF_checkclient (void)
        mleaf_t *leaf;
        int             l;
        vec3_t  view;
-       
-// find a new check if on a new frame
+
+       // find a new check if on a new frame
        if (sv.time - sv.lastchecktime >= 0.1)
        {
                sv.lastcheck = PF_newcheckclient (sv.lastcheck);
                sv.lastchecktime = sv.time;
        }
 
-// return check if it might be visible 
+       // return check if it might be visible
        ent = EDICT_NUM(sv.lastcheck);
        if (ent->free || ent->v.health <= 0)
        {
@@ -862,20 +865,23 @@ void PF_checkclient (void)
                return;
        }
 
-// if current entity can't possibly see the check entity, return 0
+       // if current entity can't possibly see the check entity, return 0
        self = PROG_TO_EDICT(pr_global_struct->self);
        VectorAdd (self->v.origin, self->v.view_ofs, view);
        leaf = Mod_PointInLeaf (view, sv.worldmodel);
-       l = (leaf - sv.worldmodel->leafs) - 1;
-       if ( (l<0) || !(checkpvs[l>>3] & (1<<(l&7)) ) )
+       if (leaf)
        {
-c_notvis++;
-               RETURN_EDICT(sv.edicts);
-               return;
+               l = (leaf - sv.worldmodel->leafs) - 1;
+               if ( (l<0) || !(checkpvs[l>>3] & (1<<(l&7)) ) )
+               {
+                       c_notvis++;
+                       RETURN_EDICT(sv.edicts);
+                       return;
+               }
        }
 
-// might be able to see it
-c_invis++;
+       // might be able to see it
+       c_invis++;
        RETURN_EDICT(ent);
 }
 
@@ -899,9 +905,9 @@ void PF_stuffcmd (void)
        
        entnum = G_EDICTNUM(OFS_PARM0);
        if (entnum < 1 || entnum > svs.maxclients)
-               PR_RunError ("Parm 0 not a client");
+               Host_Error ("Parm 0 not a client");
        str = G_STRING(OFS_PARM1);      
-       
+
        old = host_client;
        host_client = &svs.clients[entnum-1];
        Host_ClientCommands ("%s", str);
@@ -937,7 +943,7 @@ void PF_cvar (void)
        char    *str;
        
        str = G_STRING(OFS_PARM0);
-       
+
        G_FLOAT(OFS_RETURN) = Cvar_VariableValue (str);
 }
 
@@ -1078,9 +1084,9 @@ void PF_Remove (void)
 
        ed = G_EDICT(OFS_PARM0);
        if (ed == sv.edicts)
-               PR_RunError("remove: tried to remove world\n");
+               Host_Error("remove: tried to remove world\n");
        if (NUM_FOR_EDICT(ed) <= svs.maxclients)
-               PR_RunError("remove: tried to remove a client\n");
+               Host_Error("remove: tried to remove a client\n");
        ED_Free (ed);
 }
 
@@ -1216,7 +1222,7 @@ void PF_findchainfloat (void)
 void PR_CheckEmptyString (char *s)
 {
        if (s[0] <= ' ')
-               PR_RunError ("Bad string");
+               Host_Error ("Bad string");
 }
 
 void PF_precache_file (void)
@@ -1230,7 +1236,7 @@ void PF_precache_sound (void)
        int             i;
 
        if (sv.state != ss_loading)
-               PR_RunError ("PF_Precache_*: Precache can only be done in spawn functions");
+               Host_Error ("PF_Precache_*: Precache can only be done in spawn functions");
 
        s = G_STRING(OFS_PARM0);
        G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
@@ -1246,7 +1252,7 @@ void PF_precache_sound (void)
                if (!strcmp(sv.sound_precache[i], s))
                        return;
        }
-       PR_RunError ("PF_precache_sound: overflow");
+       Host_Error ("PF_precache_sound: overflow");
 }
 
 void PF_precache_model (void)
@@ -1255,7 +1261,7 @@ void PF_precache_model (void)
        int             i;
        
        if (sv.state != ss_loading)
-               PR_RunError ("PF_Precache_*: Precache can only be done in spawn functions");
+               Host_Error ("PF_Precache_*: Precache can only be done in spawn functions");
 
        s = G_STRING(OFS_PARM0);
        if (sv.worldmodel->ishlbsp && ((!s) || (!s[0])))
@@ -1274,7 +1280,7 @@ void PF_precache_model (void)
                if (!strcmp(sv.model_precache[i], s))
                        return;
        }
-       PR_RunError ("PF_precache_model: overflow");
+       Host_Error ("PF_precache_model: overflow");
 }
 
 
@@ -1444,7 +1450,7 @@ PF_pointcontents
 */
 void PF_pointcontents (void)
 {
-       G_FLOAT(OFS_RETURN) = Mod_PointInLeaf(G_VECTOR(OFS_PARM0), sv.worldmodel)->contents;
+       G_FLOAT(OFS_RETURN) = Mod_PointContents(G_VECTOR(OFS_PARM0), sv.worldmodel);
 }
 
 /*
@@ -1618,14 +1624,14 @@ void PF_changepitch (void)
                ideal = val->_float;
        else
        {
-               PR_RunError ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
+               Host_Error ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
                return;
        }
        if ((val = GETEDICTFIELDVALUE(ent, eval_pitch_speed)))
                speed = val->_float;
        else
        {
-               PR_RunError ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
+               Host_Error ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
                return;
        }
 
@@ -1685,7 +1691,7 @@ sizebuf_t *WriteDest (void)
                ent = PROG_TO_EDICT(pr_global_struct->msg_entity);
                entnum = NUM_FOR_EDICT(ent);
                if (entnum < 1 || entnum > svs.maxclients)
-                       PR_RunError ("WriteDest: not a client");
+                       Host_Error ("WriteDest: not a client");
                return &svs.clients[entnum-1].message;
 
        case MSG_ALL:
@@ -1695,7 +1701,7 @@ sizebuf_t *WriteDest (void)
                return &sv.signon;
 
        default:
-               PR_RunError ("WriteDest: bad destination");
+               Host_Error ("WriteDest: bad destination");
                break;
        }
 
@@ -1745,12 +1751,10 @@ void PF_WriteEntity (void)
 
 //=============================================================================
 
-int SV_ModelIndex (char *name);
-
 void PF_makestatic (void)
 {
-       edict_t *ent;
-       int             i, large;
+       edict_t *ent;
+       int i, large;
 
        ent = G_EDICT(OFS_PARM0);
 
@@ -1799,7 +1803,7 @@ void PF_setspawnparms (void)
        ent = G_EDICT(OFS_PARM0);
        i = NUM_FOR_EDICT(ent);
        if (i < 1 || i > svs.maxclients)
-               PR_RunError ("Entity is not a client");
+               Host_Error ("Entity is not a client");
 
        // copy spawn parms out of the client_t
        client = svs.clients + (i-1);
@@ -1891,8 +1895,8 @@ int currentqc_cvar;
 
 void PF_registercvar (void)
 {
-       char    *name, *value;
-       cvar_t  *variable;
+       char *name, *value;
+       cvar_t *variable;
        name = G_STRING(OFS_PARM0);
        value = G_STRING(OFS_PARM1);
        G_FLOAT(OFS_RETURN) = 0;
@@ -1908,7 +1912,7 @@ void PF_registercvar (void)
        }
 
        if (currentqc_cvar >= MAX_QC_CVARS)
-               PR_RunError ("PF_registercvar: ran out of cvar slots (%i)\n", MAX_QC_CVARS);
+               Host_Error ("PF_registercvar: ran out of cvar slots (%i)\n", MAX_QC_CVARS);
 
 // copy the name and value
        variable = &qc_cvar[currentqc_cvar++];
@@ -1918,9 +1922,7 @@ void PF_registercvar (void)
        strcpy (variable->string, value);
        variable->value = atof (value);
 
-// link the variable in
-       variable->next = cvar_vars;
-       cvar_vars = variable;
+       Cvar_RegisterVariable(variable);
        G_FLOAT(OFS_RETURN) = 1; // success
 }
 
@@ -1948,7 +1950,7 @@ void PF_min (void)
                G_FLOAT(OFS_RETURN) = f;
        }
        else
-               PR_RunError("min: must supply at least 2 floats\n");
+               Host_Error("min: must supply at least 2 floats\n");
 }
 
 /*
@@ -1975,7 +1977,7 @@ void PF_max (void)
                G_FLOAT(OFS_RETURN) = f;
        }
        else
-               PR_RunError("max: must supply at least 2 floats\n");
+               Host_Error("max: must supply at least 2 floats\n");
 }
 
 /*
@@ -2067,7 +2069,7 @@ void PF_effect (void)
        char *s;
        s = G_STRING(OFS_PARM1);
        if (!s || !s[0])
-               PR_RunError("effect: no model specified\n");
+               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));
 }
@@ -2463,9 +2465,170 @@ void PF_te_plasmaburn (void)
        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) = surf->texinfo->texture->name - pr_strings;
+}
+//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));
+}
+
 void PF_Fixme (void)
 {
-       PR_RunError ("unimplemented builtin"); // LordHavoc: was misspelled (bulitin)
+       Host_Error ("unimplemented QC builtin"); // LordHavoc: was misspelled (bulitin)
 }
 
 
@@ -2621,6 +2784,12 @@ PF_te_lightning3,                // #430
 PF_te_beam,                            // #431
 PF_vectorvectors,              // #432
 PF_te_plasmaburn,              // #433
+PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
+PF_getsurfacepoint,     // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
+PF_getsurfacenormal,    // #436 vector(entity e, float s) getsurfacenormal = #436;
+PF_getsurfacetexture,   // #437 string(entity e, float s) getsurfacetexture = #437;
+PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
+PF_getsurfaceclippedpoint,// #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
 };
 
 builtin_t *pr_builtins = pr_builtin;