+//float(entity ent, string tagname) gettagindex;
+
+void PF_gettagindex (void)
+{
+ prvm_edict_t *ent = PRVM_G_EDICT(OFS_PARM0);
+ const char *tag_name = PRVM_G_STRING(OFS_PARM1);
+ int modelindex, tag_index;
+
+ if (ent == prog->edicts)
+ PF_WARNING("gettagindex: can't affect world entity\n");
+ if (ent->priv.server->free)
+ PF_WARNING("gettagindex: can't affect free entity\n");
+
+ modelindex = (int)ent->fields.server->modelindex;
+ tag_index = 0;
+ if (modelindex <= 0 || modelindex > MAX_MODELS)
+ Con_DPrintf("gettagindex(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(ent));
+ else
+ {
+ tag_index = SV_GetTagIndex(ent, tag_name);
+ if (tag_index == 0)
+ Con_DPrintf("gettagindex(entity #%i): tag \"%s\" not found\n", PRVM_NUM_FOR_EDICT(ent), tag_name);
+ }
+ PRVM_G_FLOAT(OFS_RETURN) = tag_index;
+};
+
+//vector(entity ent, float tagindex) gettaginfo;
+void PF_gettaginfo (void)
+{
+ prvm_edict_t *e = PRVM_G_EDICT(OFS_PARM0);
+ int tagindex = (int)PRVM_G_FLOAT(OFS_PARM1);
+ matrix4x4_t tag_matrix;
+ int returncode;
+
+ returncode = SV_GetTagMatrix(&tag_matrix, e, tagindex);
+ Matrix4x4_ToVectors(&tag_matrix, prog->globals.server->v_forward, prog->globals.server->v_right, prog->globals.server->v_up, PRVM_G_VECTOR(OFS_RETURN));
+
+ switch(returncode)
+ {
+ case 1:
+ PF_WARNING("gettagindex: can't affect world entity\n");
+ break;
+ case 2:
+ PF_WARNING("gettagindex: can't affect free entity\n");
+ break;
+ case 3:
+ Con_DPrintf("SV_GetTagMatrix(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(e));
+ break;
+ case 4:
+ Con_DPrintf("SV_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", PRVM_NUM_FOR_EDICT(e), tagindex);
+ break;
+ case 5:
+ Con_DPrintf("SV_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", PRVM_NUM_FOR_EDICT(e));
+ break;
+ }
+}
+
+
+/////////////////////////////////////////
+// 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;
+ const char *pattern;
+ int caseinsens, quiet;
+
+ pattern = PRVM_G_STRING(OFS_PARM0);
+ if (!pattern || pattern[0] <= ' ')
+ PF_ERROR("PF_search_begin: Bad string");
+
+ caseinsens = PRVM_G_FLOAT(OFS_PARM1);
+ quiet = PRVM_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);
+ PRVM_G_FLOAT(OFS_RETURN) = -2;
+ return;
+ }
+
+ if(!(pr_fssearchlist[handle] = FS_Search(pattern,caseinsens, quiet)))
+ PRVM_G_FLOAT(OFS_RETURN) = -1;
+ else
+ PRVM_G_FLOAT(OFS_RETURN) = handle;
+}
+
+/*
+=========
+VM_search_end
+
+void search_end(float handle)
+=========
+*/
+void PF_search_end(void)
+{
+ int handle;
+
+ handle = PRVM_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 = PRVM_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;
+ }
+
+ PRVM_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 = PRVM_G_FLOAT(OFS_PARM0);
+ filenum = PRVM_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]);
+
+ PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(tmp);
+}
+
+void PF_cvar_string (void)
+{
+ const char *str;
+ cvar_t *var;
+ char *tmp;
+
+ str = PRVM_G_STRING(OFS_PARM0);
+ var = Cvar_FindVar (str);
+ if (var)
+ {
+ tmp = PR_GetTempString();
+ strcpy(tmp, var->string);
+ }
+ else
+ tmp = NULL;
+ PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(tmp);
+}
+
+//void(entity clent) dropclient (DP_SV_DROPCLIENT)
+void PF_dropclient (void)
+{
+ int clientnum;
+ client_t *oldhostclient;
+ clientnum = PRVM_G_EDICTNUM(OFS_PARM0) - 1;
+ if (clientnum < 0 || clientnum >= svs.maxclients)
+ PF_WARNING("dropclient: not a client\n");
+ if (!svs.clients[clientnum].active)
+ PF_WARNING("dropclient: that client slot is not connected\n");
+ oldhostclient = host_client;
+ host_client = svs.clients + clientnum;
+ SV_DropClient(false);
+ host_client = oldhostclient;
+}
+
+//entity() spawnclient (DP_SV_BOTCLIENT)
+void PF_spawnclient (void)
+{
+ int i;
+ prvm_edict_t *ed;
+ pr_xfunction->builtinsprofile += 2;
+ ed = prog->edicts;
+ for (i = 0;i < svs.maxclients;i++)
+ {
+ if (!svs.clients[i].active)
+ {
+ pr_xfunction->builtinsprofile += 100;
+ SV_ConnectClient (i, NULL);
+ ed = PRVM_EDICT_NUM(i + 1);
+ break;
+ }
+ }
+ RETURN_EDICT(ed);
+}
+
+//float(entity clent) clienttype (DP_SV_BOTCLIENT)
+void PF_clienttype (void)
+{
+ int clientnum;
+ clientnum = PRVM_G_EDICTNUM(OFS_PARM0) - 1;
+ if (clientnum < 0 || clientnum >= svs.maxclients)
+ PRVM_G_FLOAT(OFS_RETURN) = 3;
+ else if (!svs.clients[clientnum].active)
+ PRVM_G_FLOAT(OFS_RETURN) = 0;
+ else if (svs.clients[clientnum].netconnection)
+ PRVM_G_FLOAT(OFS_RETURN) = 1;
+ else
+ PRVM_G_FLOAT(OFS_RETURN) = 2;
+}