]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - pr_cmds.c
upgraded network protocol to DP5, now sends precise entity angles (except for EF_LOWP...
[xonotic/darkplaces.git] / pr_cmds.c
index 1fa832fd190ea64119bd67ee034c73a16fe89aad..d2b39692b9ffe9ab25963654a9a91229b8df409e 100644 (file)
--- a/pr_cmds.c
+++ b/pr_cmds.c
@@ -39,7 +39,9 @@ static char *PR_GetTempString(void)
        return s;
 }
 
-#define        RETURN_EDICT(e) (((int *)pr_globals)[OFS_RETURN] = EDICT_TO_PROG(e))
+#define        RETURN_EDICT(e) (G_INT(OFS_RETURN) = EDICT_TO_PROG(e))
+#define PF_WARNING(s) do{Con_Printf(s);PR_PrintState();return;}while(0)
+#define PF_ERROR(s) do{Host_Error(s);return;}while(0)
 
 
 /*
@@ -69,18 +71,18 @@ void PF_VarString(int first, char *out, int outlength)
 
 char *ENGINE_EXTENSIONS =
 "DP_CL_LOADSKY "
-"DP_EF_NODRAW "
 "DP_EF_ADDITIVE "
 "DP_EF_BLUE "
-"DP_EF_RED "
-"DP_EF_FULLBRIGHT "
 "DP_EF_FLAME "
+"DP_EF_FULLBRIGHT "
+"DP_EF_NODRAW "
+"DP_EF_RED "
 "DP_EF_STARDUST "
 "DP_ENT_ALPHA "
 "DP_ENT_CUSTOMCOLORMAP "
 "DP_ENT_EXTERIORMODELTOCLIENT "
-"DP_ENT_LOWPRECISION "
 "DP_ENT_GLOW "
+"DP_ENT_LOWPRECISION "
 "DP_ENT_SCALE "
 "DP_ENT_VIEWMODEL "
 "DP_GFX_EXTERNALTEXTURES "
@@ -91,15 +93,18 @@ char *ENGINE_EXTENSIONS =
 "DP_HALFLIFE_MAP "
 "DP_HALFLIFE_MAP_CVAR "
 "DP_INPUTBUTTONS "
+"DP_LITSUPPORT "
 "DP_MONSTERWALK "
 "DP_MOVETYPEBOUNCEMISSILE "
 "DP_MOVETYPEFOLLOW "
 "DP_QC_CHANGEPITCH "
 "DP_QC_COPYENTITY "
+"DP_QC_CVAR_STRING "
 "DP_QC_ETOS "
 "DP_QC_FINDCHAIN "
 "DP_QC_FINDCHAINFLOAT "
 "DP_QC_FINDFLOAT "
+"DP_QC_FS_SEARCH " // Black: same as in the menu qc
 "DP_QC_GETLIGHT "
 "DP_QC_GETSURFACE "
 "DP_QC_MINMAXBOUND "
@@ -107,8 +112,8 @@ char *ENGINE_EXTENSIONS =
 "DP_QC_SINCOSSQRTPOW "
 "DP_QC_TRACEBOX "
 "DP_QC_TRACETOSS "
-"DP_QC_TRACE_MOVETYPE_WORLDONLY "
 "DP_QC_TRACE_MOVETYPE_HITMODEL "
+"DP_QC_TRACE_MOVETYPE_WORLDONLY "
 "DP_QC_VECTORVECTORS "
 "DP_QUAKE2_MODEL "
 "DP_QUAKE3_MODEL "
@@ -140,6 +145,7 @@ char *ENGINE_EXTENSIONS =
 "KRIMZON_SV_PARSECLIENTCOMMAND "
 "NEH_CMD_PLAY2 "
 "NEH_RESTOREGAME "
+"TENEBRAE_GFX_DLIGHTS "
 "TW_SV_STEPCONTROL "
 ;
 
@@ -198,7 +204,7 @@ void PF_error (void)
        ed = PROG_TO_EDICT(pr_global_struct->self);
        ED_Print (ed);
 
-       Host_Error ("Program error");
+       PF_ERROR("Program error");
 }
 
 /*
@@ -267,9 +273,9 @@ void PF_setorigin (void)
 
        e = G_EDICT(OFS_PARM0);
        if (e == sv.edicts)
-               Host_Error("setorigin: can not modify world entity\n");
+               PF_WARNING("setorigin: can not modify world entity\n");
        if (e->e->free)
-               Host_Error("setorigin: can not modify free entity\n");
+               PF_WARNING("setorigin: can not modify free entity\n");
        org = G_VECTOR(OFS_PARM1);
        VectorCopy (org, e->v->origin);
        SV_LinkEdict (e, false);
@@ -282,7 +288,7 @@ void SetMinMaxSize (edict_t *e, float *min, float *max, qboolean rotate)
 
        for (i=0 ; i<3 ; i++)
                if (min[i] > max[i])
-                       Host_Error ("backwards mins/maxs");
+                       PF_ERROR("SetMinMaxSize: backwards mins/maxs\n");
 
 // set derived values
        VectorCopy (min, e->v->mins);
@@ -309,9 +315,9 @@ void PF_setsize (void)
 
        e = G_EDICT(OFS_PARM0);
        if (e == sv.edicts)
-               Host_Error("setsize: can not modify world entity\n");
+               PF_WARNING("setsize: can not modify world entity\n");
        if (e->e->free)
-               Host_Error("setsize: can not modify free entity\n");
+               PF_WARNING("setsize: can not modify free entity\n");
        min = G_VECTOR(OFS_PARM1);
        max = G_VECTOR(OFS_PARM2);
        SetMinMaxSize (e, min, max, false);
@@ -334,9 +340,9 @@ void PF_setmodel (void)
 
        e = G_EDICT(OFS_PARM0);
        if (e == sv.edicts)
-               Host_Error("setmodel: can not modify world entity\n");
+               PF_WARNING("setmodel: can not modify world entity\n");
        if (e->e->free)
-               Host_Error("setmodel: can not modify free entity\n");
+               PF_WARNING("setmodel: can not modify free entity\n");
        m = G_STRING(OFS_PARM1);
 
 // check to see if model was properly precached
@@ -345,7 +351,7 @@ void PF_setmodel (void)
                        break;
 
        if (!*check)
-               Host_Error ("no precache: %s\n", m);
+               PF_WARNING("setmodel: no precache\n");
 
 
        e->v->model = PR_SetString(*check);
@@ -688,13 +694,13 @@ void PF_sound (void)
        attenuation = G_FLOAT(OFS_PARM4);
 
        if (volume < 0 || volume > 255)
-               Host_Error ("SV_StartSound: volume = %i", volume);
+               PF_WARNING("SV_StartSound: volume must be in range 0-1\n");
 
        if (attenuation < 0 || attenuation > 4)
-               Host_Error ("SV_StartSound: attenuation = %f", attenuation);
+               PF_WARNING("SV_StartSound: attenuation must be in range 0-4\n");
 
        if (channel < 0 || channel > 7)
-               Host_Error ("SV_StartSound: channel = %i", channel);
+               PF_WARNING("SV_StartSound: channel must be in range 0-7\n");
 
        SV_StartSound (entity, channel, sample, volume, attenuation);
 }
@@ -708,7 +714,7 @@ break()
 */
 void PF_break (void)
 {
-       Host_Error ("break statement");
+       PF_ERROR("break: break statement\n");
 }
 
 /*
@@ -726,17 +732,17 @@ void PF_traceline (void)
 {
        float   *v1, *v2;
        trace_t trace;
-       int             nomonsters;
+       int             move;
        edict_t *ent;
 
        pr_xfunction->builtinsprofile += 30;
 
        v1 = G_VECTOR(OFS_PARM0);
        v2 = G_VECTOR(OFS_PARM1);
-       nomonsters = G_FLOAT(OFS_PARM2);
+       move = G_FLOAT(OFS_PARM2);
        ent = G_EDICT(OFS_PARM3);
 
-       trace = SV_Move (v1, vec3_origin, vec3_origin, v2, nomonsters, ent);
+       trace = SV_Move (v1, vec3_origin, vec3_origin, v2, move, ent);
 
        pr_global_struct->trace_allsolid = trace.allsolid;
        pr_global_struct->trace_startsolid = trace.startsolid;
@@ -770,7 +776,7 @@ void PF_tracebox (void)
 {
        float   *v1, *v2, *m1, *m2;
        trace_t trace;
-       int             nomonsters;
+       int             move;
        edict_t *ent;
 
        pr_xfunction->builtinsprofile += 30;
@@ -779,10 +785,10 @@ void PF_tracebox (void)
        m1 = G_VECTOR(OFS_PARM1);
        m2 = G_VECTOR(OFS_PARM2);
        v2 = G_VECTOR(OFS_PARM3);
-       nomonsters = G_FLOAT(OFS_PARM4);
+       move = G_FLOAT(OFS_PARM4);
        ent = G_EDICT(OFS_PARM5);
 
-       trace = SV_Move (v1, m1, m2, v2, nomonsters ? MOVE_NOMONSTERS : MOVE_NORMAL, ent);
+       trace = SV_Move (v1, m1, m2, v2, move, ent);
 
        pr_global_struct->trace_allsolid = trace.allsolid;
        pr_global_struct->trace_startsolid = trace.startsolid;
@@ -809,7 +815,7 @@ void PF_TraceToss (void)
 
        ent = G_EDICT(OFS_PARM0);
        if (ent == sv.edicts)
-               Host_Error("tracetoss: can not use world entity\n");
+               PF_WARNING("tracetoss: can not use world entity\n");
        ignore = G_EDICT(OFS_PARM1);
 
        trace = SV_Trace_Toss (ent, ignore);
@@ -1124,12 +1130,12 @@ void PF_Remove (void)
 
        ed = G_EDICT(OFS_PARM0);
        if (ed == sv.edicts)
-               Host_Error("remove: tried to remove world\n");
+               PF_WARNING("remove: tried to remove world\n");
        if (NUM_FOR_EDICT(ed) <= svs.maxclients)
-               Host_Error("remove: tried to remove a client\n");
+               PF_WARNING("remove: tried to remove a client\n");
        // LordHavoc: not an error because id1 progs did this in some cases (killtarget removes entities, even if they are already removed in some cases...)
        if (ed->e->free && developer.integer)
-               Con_Printf("remove: tried to remove an entity that was already removed\n");
+               PF_WARNING("remove: tried to remove an entity that was already removed\n");
        ED_Free (ed);
 }
 
@@ -1269,7 +1275,7 @@ void PF_findchainfloat (void)
 void PR_CheckEmptyString (char *s)
 {
        if (s[0] <= ' ')
-               Host_Error ("Bad string");
+               PF_ERROR("Bad string");
 }
 
 void PF_precache_file (void)
@@ -1283,7 +1289,7 @@ void PF_precache_sound (void)
        int             i;
 
        if (sv.state != ss_loading)
-               Host_Error ("PF_Precache_*: Precache can only be done in spawn functions");
+               PF_ERROR("PF_Precache_*: Precache can only be done in spawn functions");
 
        s = G_STRING(OFS_PARM0);
        G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
@@ -1299,7 +1305,7 @@ void PF_precache_sound (void)
                if (!strcmp(sv.sound_precache[i], s))
                        return;
        }
-       Host_Error ("PF_precache_sound: overflow");
+       PF_ERROR("PF_precache_sound: overflow");
 }
 
 void PF_precache_model (void)
@@ -1308,7 +1314,7 @@ void PF_precache_model (void)
        int             i;
 
        if (sv.state != ss_loading)
-               Host_Error ("PF_Precache_*: Precache can only be done in spawn functions");
+               PF_ERROR("PF_Precache_*: Precache can only be done in spawn functions");
 
        s = G_STRING(OFS_PARM0);
        if (sv.worldmodel->brush.ishlbsp && ((!s) || (!s[0])))
@@ -1327,7 +1333,7 @@ void PF_precache_model (void)
                if (!strcmp(sv.model_precache[i], s))
                        return;
        }
-       Host_Error ("PF_precache_model: overflow");
+       PF_ERROR("PF_precache_model: overflow");
 }
 
 
@@ -1366,19 +1372,19 @@ void PF_walkmove (void)
        mfunction_t     *oldf;
        int     oldself;
 
+       // assume failure if it returns early
+       G_FLOAT(OFS_RETURN) = 0;
+       
        ent = PROG_TO_EDICT(pr_global_struct->self);
        if (ent == sv.edicts)
-               Host_Error("walkmove: can not modify world entity\n");
+               PF_WARNING("walkmove: can not modify world entity\n");
        if (ent->e->free)
-               Host_Error("walkmove: can not modify free entity\n");
+               PF_WARNING("walkmove: can not modify free entity\n");
        yaw = G_FLOAT(OFS_PARM0);
        dist = G_FLOAT(OFS_PARM1);
 
        if ( !( (int)ent->v->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
-       {
-               G_FLOAT(OFS_RETURN) = 0;
                return;
-       }
 
        yaw = yaw*M_PI*2 / 360;
 
@@ -1411,20 +1417,21 @@ void PF_droptofloor (void)
        vec3_t          end;
        trace_t         trace;
 
+       // assume failure if it returns early
+       G_FLOAT(OFS_RETURN) = 0;
+
        ent = PROG_TO_EDICT(pr_global_struct->self);
        if (ent == sv.edicts)
-               Host_Error("droptofloor: can not modify world entity\n");
+               PF_WARNING("droptofloor: can not modify world entity\n");
        if (ent->e->free)
-               Host_Error("droptofloor: can not modify free entity\n");
+               PF_WARNING("droptofloor: can not modify free entity\n");
 
        VectorCopy (ent->v->origin, end);
        end[2] -= 256;
 
        trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
 
-       if (trace.fraction == 1)
-               G_FLOAT(OFS_RETURN) = 0;
-       else
+       if (trace.fraction != 1)
        {
                VectorCopy (trace.endpos, ent->v->origin);
                SV_LinkEdict (ent, false);
@@ -1558,11 +1565,14 @@ void PF_aim (void)
        float   dist, bestdist;
        float   speed;
 
+       // assume failure if it returns early
+       VectorClear(G_VECTOR(OFS_RETURN));
+
        ent = G_EDICT(OFS_PARM0);
        if (ent == sv.edicts)
-               Host_Error("aim: can not use world entity\n");
+               PF_WARNING("aim: can not use world entity\n");
        if (ent->e->free)
-               Host_Error("aim: can not use free entity\n");
+               PF_WARNING("aim: can not use free entity\n");
        speed = G_FLOAT(OFS_PARM1);
 
        VectorCopy (ent->v->origin, start);
@@ -1640,9 +1650,9 @@ void PF_changeyaw (void)
 
        ent = PROG_TO_EDICT(pr_global_struct->self);
        if (ent == sv.edicts)
-               Host_Error("changeyaw: can not modify world entity\n");
+               PF_WARNING("changeyaw: can not modify world entity\n");
        if (ent->e->free)
-               Host_Error("changeyaw: can not modify free entity\n");
+               PF_WARNING("changeyaw: can not modify free entity\n");
        current = ANGLEMOD(ent->v->angles[1]);
        ideal = ent->v->ideal_yaw;
        speed = ent->v->yaw_speed;
@@ -1687,22 +1697,22 @@ void PF_changepitch (void)
 
        ent = G_EDICT(OFS_PARM0);
        if (ent == sv.edicts)
-               Host_Error("changepitch: can not modify world entity\n");
+               PF_WARNING("changepitch: can not modify world entity\n");
        if (ent->e->free)
-               Host_Error("changepitch: can not modify free entity\n");
+               PF_WARNING("changepitch: can not modify free entity\n");
        current = ANGLEMOD( ent->v->angles[0] );
        if ((val = GETEDICTFIELDVALUE(ent, eval_idealpitch)))
                ideal = val->_float;
        else
        {
-               Host_Error ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
+               PF_WARNING("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch\n");
                return;
        }
        if ((val = GETEDICTFIELDVALUE(ent, eval_pitch_speed)))
                speed = val->_float;
        else
        {
-               Host_Error ("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch");
+               PF_WARNING("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch\n");
                return;
        }
 
@@ -1772,7 +1782,7 @@ sizebuf_t *WriteDest (void)
                return &sv.signon;
 
        default:
-               Host_Error ("WriteDest: bad destination");
+               Host_Error("WriteDest: bad destination");
                break;
        }
 
@@ -1829,9 +1839,9 @@ void PF_makestatic (void)
 
        ent = G_EDICT(OFS_PARM0);
        if (ent == sv.edicts)
-               Host_Error("makestatic: can not modify world entity\n");
+               PF_WARNING("makestatic: can not modify world entity\n");
        if (ent->e->free)
-               Host_Error("makestatic: can not modify free entity\n");
+               PF_WARNING("makestatic: can not modify free entity\n");
 
        large = false;
        if (ent->v->modelindex >= 256 || ent->v->frame >= 256)
@@ -1992,7 +2002,7 @@ void PF_registercvar (void)
        }
 
        if (currentqc_cvar >= MAX_QC_CVARS)
-               Host_Error ("PF_registercvar: ran out of cvar slots (%i)\n", MAX_QC_CVARS);
+               PF_ERROR("PF_registercvar: ran out of cvar slots\n");
 
 // copy the name and value
        variable = &qc_cvar[currentqc_cvar++];
@@ -2030,7 +2040,10 @@ void PF_min (void)
                G_FLOAT(OFS_RETURN) = f;
        }
        else
-               Host_Error("min: must supply at least 2 floats\n");
+       {
+               G_FLOAT(OFS_RETURN) = 0;
+               PF_WARNING("min: must supply at least 2 floats\n");
+       }
 }
 
 /*
@@ -2057,7 +2070,10 @@ void PF_max (void)
                G_FLOAT(OFS_RETURN) = f;
        }
        else
-               Host_Error("max: must supply at least 2 floats\n");
+       {
+               G_FLOAT(OFS_RETURN) = 0;
+               PF_WARNING("max: must supply at least 2 floats\n");
+       }
 }
 
 /*
@@ -2102,14 +2118,14 @@ void PF_copyentity (void)
        edict_t *in, *out;
        in = G_EDICT(OFS_PARM0);
        if (in == sv.edicts)
-               Host_Error("copyentity: can not read world entity\n");
+               PF_WARNING("copyentity: can not read world entity\n");
        if (in->e->free)
-               Host_Error("copyentity: can not read free entity\n");
+               PF_WARNING("copyentity: can not read free entity\n");
        out = G_EDICT(OFS_PARM1);
        if (out == sv.edicts)
-               Host_Error("copyentity: can not modify world entity\n");
+               PF_WARNING("copyentity: can not modify world entity\n");
        if (out->e->free)
-               Host_Error("copyentity: can not modify free entity\n");
+               PF_WARNING("copyentity: can not modify free entity\n");
        memcpy(out->v, in->v, progs->entityfields * 4);
 }
 
@@ -2161,7 +2177,7 @@ void PF_effect (void)
        char *s;
        s = G_STRING(OFS_PARM1);
        if (!s || !s[0])
-               Host_Error("effect: no model specified\n");
+               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));
 }
@@ -2954,30 +2970,26 @@ void PF_clientcommand (void)
 
 //float(string s) tokenize = #441; // takes apart a string into individal words (access them with argv), returns how many
 //this function originally written by KrimZon, made shorter by LordHavoc
-char **tokens = NULL;
-int    max_tokens, num_tokens = 0;
+//20040203: rewritten by LordHavoc (no longer uses allocations)
+int num_tokens = 0;
+char *tokens[256], tokenbuf[4096];
 void PF_tokenize (void)
 {
+       int pos;
        const char *p;
-       char *str;
-       str = G_STRING(OFS_PARM0);
-
-       if (tokens != NULL)
-       {
-               int i;
-               for (i=0;i<num_tokens;i++)
-                       Z_Free(tokens[i]);
-               Z_Free(tokens);
-               num_tokens = 0;
-       }
+       p = G_STRING(OFS_PARM0);
 
-       tokens = Z_Malloc(strlen(str) * sizeof(char *));
-       max_tokens = strlen(str);
-
-       for (p = str;COM_ParseToken(&p, false) && num_tokens < max_tokens;num_tokens++)
+       num_tokens = 0;
+       pos = 0;
+       while(COM_ParseToken(&p, false))
        {
-               tokens[num_tokens] = Z_Malloc(strlen(com_token) + 1);
-               strcpy(tokens[num_tokens], com_token);
+               if (num_tokens >= (int)(sizeof(tokens)/sizeof(tokens[0])))
+                       break;
+               if (pos + strlen(com_token) + 1 > sizeof(tokenbuf))
+                       break;
+               tokens[num_tokens++] = tokenbuf + pos;
+               strcpy(tokenbuf + pos, com_token);
+               pos += strlen(com_token) + 1;
        }
 
        G_FLOAT(OFS_RETURN) = num_tokens;
@@ -3005,9 +3017,9 @@ void PF_setattachment (void)
        model_t *model;
 
        if (e == sv.edicts)
-               Host_Error("setattachment: can not modify world entity\n");
+               PF_WARNING("setattachment: can not modify world entity\n");
        if (e->e->free)
-               Host_Error("setattachment: can not modify free entity\n");
+               PF_WARNING("setattachment: can not modify free entity\n");
 
        if (tagentity == NULL)
                tagentity = sv.edicts;
@@ -3041,6 +3053,175 @@ void PF_setattachment (void)
 }
 
 
+/////////////////////////////////////////
+// DP_QC_FS_SEARCH extension
+
+// qc fs search handling
+#define MAX_SEARCHES 128
+
+fssearch_t *pr_fssearchlist[MAX_SEARCHES];
+
+void PR_Search_Init(void)
+{
+       memset(pr_fssearchlist,0,sizeof(pr_fssearchlist));
+}
+
+void PR_Search_Reset(void)
+{
+       int i;
+       // reset the fssearch list
+       for(i = 0; i < MAX_SEARCHES; i++)
+               if(pr_fssearchlist[i])
+                       FS_FreeSearch(pr_fssearchlist[i]);
+       memset(pr_fssearchlist,0,sizeof(pr_fssearchlist));
+}
+
+/*
+=========
+PF_search_begin
+
+float search_begin(string pattern, float caseinsensitive, float quiet)
+=========
+*/
+void PF_search_begin(void)
+{
+       int handle;
+       char *pattern;
+       int caseinsens, quiet;
+
+       pattern = G_STRING(OFS_PARM0);
+
+       PR_CheckEmptyString(pattern);
+
+       caseinsens = G_FLOAT(OFS_PARM1);
+       quiet = G_FLOAT(OFS_PARM2);
+       
+       for(handle = 0; handle < MAX_SEARCHES; handle++)
+               if(!pr_fssearchlist[handle])
+                       break;
+
+       if(handle >= MAX_SEARCHES)
+       {
+               Con_Printf("PR_search_begin: ran out of search handles (%i)\n", MAX_SEARCHES);
+               G_FLOAT(OFS_RETURN) = -2;
+               return;
+       }
+
+       if(!(pr_fssearchlist[handle] = FS_Search(pattern,caseinsens, quiet)))
+               G_FLOAT(OFS_RETURN) = -1;
+       else
+               G_FLOAT(OFS_RETURN) = handle;
+}
+
+/*
+=========
+VM_search_end
+
+void   search_end(float handle)
+=========
+*/
+void PF_search_end(void)
+{
+       int handle;
+
+       handle = G_FLOAT(OFS_PARM0);
+       
+       if(handle < 0 || handle >= MAX_SEARCHES)
+       {
+               Con_Printf("PF_search_end: invalid handle %i\n", handle);
+               return;
+       }
+       if(pr_fssearchlist[handle] == NULL)
+       {
+               Con_Printf("PF_search_end: no such handle %i\n", handle);
+               return;
+       }
+
+       FS_FreeSearch(pr_fssearchlist[handle]);
+       pr_fssearchlist[handle] = NULL;
+}
+
+/*
+=========
+VM_search_getsize
+
+float  search_getsize(float handle)
+=========
+*/
+void PF_search_getsize(void)
+{
+       int handle;
+
+       handle = G_FLOAT(OFS_PARM0);
+
+       if(handle < 0 || handle >= MAX_SEARCHES)
+       {
+               Con_Printf("PF_search_getsize: invalid handle %i\n", handle);
+               return;
+       }
+       if(pr_fssearchlist[handle] == NULL)
+       {
+               Con_Printf("PF_search_getsize: no such handle %i\n", handle);
+               return;
+       }
+       
+       G_FLOAT(OFS_RETURN) = pr_fssearchlist[handle]->numfilenames;
+}
+
+/*
+=========
+VM_search_getfilename
+
+string search_getfilename(float handle, float num)
+=========
+*/
+void PF_search_getfilename(void)
+{
+       int handle, filenum;
+       char *tmp;
+
+       handle = G_FLOAT(OFS_PARM0);
+       filenum = G_FLOAT(OFS_PARM1);
+
+       if(handle < 0 || handle >= MAX_SEARCHES)
+       {
+               Con_Printf("PF_search_getfilename: invalid handle %i\n", handle);
+               return;
+       }
+       if(pr_fssearchlist[handle] == NULL)
+       {
+               Con_Printf("PF_search_getfilename: no such handle %i\n", handle);
+               return;
+       }
+       if(filenum < 0 || filenum >= pr_fssearchlist[handle]->numfilenames)
+       {
+               Con_Printf("PF_search_getfilename: invalid filenum %i\n", filenum);
+               return;
+       }
+       
+       tmp = PR_GetTempString();
+       strcpy(tmp, pr_fssearchlist[handle]->filenames[filenum]);
+
+       G_INT(OFS_RETURN) = PR_SetString(tmp);
+}
+
+void PF_cvar_string (void)
+{
+       char *str;
+       cvar_t *var;
+       char *tmp;
+
+       str = G_STRING(OFS_PARM0);
+       var = Cvar_FindVar (str);
+
+       tmp = PR_GetTempString();
+       strcpy(tmp, var->string);
+
+       G_INT(OFS_RETURN) = PR_SetString(tmp);
+}
+
+
+
 builtin_t pr_builtin[] =
 {
 NULL,                                          // #0
@@ -3211,11 +3392,11 @@ PF_clientcommand,                       // #440 void(entity e, string s) clientcommand (KRIMZON_SV_P
 PF_tokenize,                           // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
 PF_argv,                                       // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
 PF_setattachment,                      // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
-NULL,                                          // #444
-NULL,                                          // #445
-NULL,                                          // #446
-NULL,                                          // #447
-NULL,                                          // #448
+PF_search_begin,                       // #444
+PF_search_end,                         // #445
+PF_search_getsize,                     // #446
+PF_search_getfilename,         // #447
+PF_cvar_string,                                // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
 NULL,                                          // #449
 a a a a a                                      // #450-499 (LordHavoc)
 };
@@ -3227,11 +3408,13 @@ void PR_Cmd_Init(void)
 {
        pr_strings_mempool = Mem_AllocPool("pr_stringszone");
        PR_Files_Init();
+       PR_Search_Init();
 }
 
 void PR_Cmd_Reset(void)
 {
        Mem_EmptyPool(pr_strings_mempool);
+       PR_Search_Reset();
        PR_Files_CloseAll();
 }