X-Git-Url: https://de.git.xonotic.org/?a=blobdiff_plain;f=pr_cmds.c;h=74872ab17a909a87031617684cc99b0e1a2d5a29;hb=c218cedd2533732ee59de007261f2be25e605897;hp=956e01e9dd0fab296cb8aa32399316fb29a9de3c;hpb=a0338ffd578afdaf693aee96bc6f948afb5b1844;p=xonotic%2Fdarkplaces.git diff --git a/pr_cmds.c b/pr_cmds.c index 956e01e9..74872ab1 100644 --- a/pr_cmds.c +++ b/pr_cmds.c @@ -25,9 +25,19 @@ cvar_t pr_zone_min_strings = {0, "pr_zone_min_strings", "64"}; mempool_t *pr_strings_mempool; -#define MAX_VARSTRING 4096 +// LordHavoc: added this to semi-fix the problem of using many ftos calls in a print +#define STRINGTEMP_BUFFERS 16 +#define STRINGTEMP_LENGTH 4096 +static char pr_string_temp[STRINGTEMP_BUFFERS][STRINGTEMP_LENGTH]; +static int pr_string_tempindex = 0; -char pr_varstring_temp[MAX_VARSTRING]; +static char *PR_GetTempString(void) +{ + char *s; + s = pr_string_temp[pr_string_tempindex]; + pr_string_tempindex = (pr_string_tempindex + 1) % STRINGTEMP_BUFFERS; + return s; +} #define RETURN_EDICT(e) (((int *)pr_globals)[OFS_RETURN] = EDICT_TO_PROG(e)) @@ -41,14 +51,13 @@ char pr_varstring_temp[MAX_VARSTRING]; */ -char *PF_VarString (int first) +void PF_VarString(int first, char *out, int outlength) { int i; const char *s; - char *out, *outend; + char *outend; - out = pr_varstring_temp; - outend = pr_varstring_temp + sizeof(pr_varstring_temp) - 1; + outend = out + outlength - 1; for (i = first;i < pr_argc && out < outend;i++) { s = G_STRING((OFS_PARM0+i*3)); @@ -56,23 +65,22 @@ char *PF_VarString (int first) *out++ = *s++; } *out++ = 0; - return pr_varstring_temp; } 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 " @@ -83,15 +91,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 " @@ -99,6 +110,8 @@ char *ENGINE_EXTENSIONS = "DP_QC_SINCOSSQRTPOW " "DP_QC_TRACEBOX " "DP_QC_TRACETOSS " +"DP_QC_TRACE_MOVETYPE_HITMODEL " +"DP_QC_TRACE_MOVETYPE_WORLDONLY " "DP_QC_VECTORVECTORS " "DP_QUAKE2_MODEL " "DP_QUAKE3_MODEL " @@ -180,11 +193,11 @@ error(value) */ void PF_error (void) { - char *s; edict_t *ed; + char string[STRINGTEMP_LENGTH]; - s = PF_VarString(0); - Con_Printf ("======SERVER ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), s); + PF_VarString(0, string, sizeof(string)); + Con_Printf ("======SERVER ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), string); ed = PROG_TO_EDICT(pr_global_struct->self); ED_Print (ed); @@ -203,11 +216,11 @@ objerror(value) */ void PF_objerror (void) { - char *s; edict_t *ed; + char string[STRINGTEMP_LENGTH]; - s = PF_VarString(0); - Con_Printf ("======OBJECT ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), s); + PF_VarString(0, string, sizeof(string)); + Con_Printf ("======OBJECT ERROR in %s:\n%s\n", PR_GetString(pr_xfunction->s_name), string); ed = PROG_TO_EDICT(pr_global_struct->self); ED_Print (ed); ED_Free (ed); @@ -256,6 +269,10 @@ void PF_setorigin (void) float *org; e = G_EDICT(OFS_PARM0); + if (e == sv.edicts) + Host_Error("setorigin: can not modify world entity\n"); + if (e->e->free) + Host_Error("setorigin: can not modify free entity\n"); org = G_VECTOR(OFS_PARM1); VectorCopy (org, e->v->origin); SV_LinkEdict (e, false); @@ -294,6 +311,10 @@ void PF_setsize (void) float *min, *max; e = G_EDICT(OFS_PARM0); + if (e == sv.edicts) + Host_Error("setsize: can not modify world entity\n"); + if (e->e->free) + Host_Error("setsize: can not modify free entity\n"); min = G_VECTOR(OFS_PARM1); max = G_VECTOR(OFS_PARM2); SetMinMaxSize (e, min, max, false); @@ -315,6 +336,10 @@ void PF_setmodel (void) int i; e = G_EDICT(OFS_PARM0); + if (e == sv.edicts) + Host_Error("setmodel: can not modify world entity\n"); + if (e->e->free) + Host_Error("setmodel: can not modify free entity\n"); m = G_STRING(OFS_PARM1); // check to see if model was properly precached @@ -348,10 +373,9 @@ bprint(value) */ void PF_bprint (void) { - char *s; - - s = PF_VarString(0); - SV_BroadcastPrintf ("%s", s); + char string[STRINGTEMP_LENGTH]; + PF_VarString(0, string, sizeof(string)); + SV_BroadcastPrintf("%s", string); } /* @@ -365,22 +389,24 @@ sprint(clientent, value) */ void PF_sprint (void) { - char *s; client_t *client; int entnum; + char string[STRINGTEMP_LENGTH]; entnum = G_EDICTNUM(OFS_PARM0); - s = PF_VarString(1); - if (entnum < 1 || entnum > MAX_SCOREBOARD || !svs.connectedclients[entnum-1]) + if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active) { Con_Printf ("tried to sprint to a non-client\n"); return; } - client = svs.connectedclients[entnum-1]; + client = svs.clients + entnum-1; + if (!client->netconnection) + return; + PF_VarString(1, string, sizeof(string)); MSG_WriteChar(&client->message,svc_print); - MSG_WriteString(&client->message, s ); + MSG_WriteString(&client->message, string); } @@ -395,22 +421,24 @@ centerprint(clientent, value) */ void PF_centerprint (void) { - char *s; client_t *client; int entnum; + char string[STRINGTEMP_LENGTH]; entnum = G_EDICTNUM(OFS_PARM0); - s = PF_VarString(1); - if (entnum < 1 || entnum > MAX_SCOREBOARD || !svs.connectedclients[entnum-1]) + if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active) { Con_Printf ("tried to sprint to a non-client\n"); return; } - client = svs.connectedclients[entnum-1]; + client = svs.clients + entnum-1; + if (!client->netconnection) + return; + PF_VarString(1, string, sizeof(string)); MSG_WriteChar(&client->message,svc_centerprint); - MSG_WriteString(&client->message, s ); + MSG_WriteString(&client->message, string); } @@ -783,6 +811,8 @@ void PF_TraceToss (void) pr_xfunction->builtinsprofile += 600; ent = G_EDICT(OFS_PARM0); + if (ent == sv.edicts) + Host_Error("tracetoss: can not use world entity\n"); ignore = G_EDICT(OFS_PARM1); trace = SV_Trace_Toss (ent, ignore); @@ -818,6 +848,7 @@ void PF_checkpos (void) //============================================================================ +int checkpvsbytes; qbyte checkpvs[MAX_MAP_LEAFS/8]; int PF_newcheckclient (int check) @@ -828,8 +859,8 @@ int PF_newcheckclient (int check) // cycle to the next one - check = bound(1, check, MAX_SCOREBOARD); - if (check == MAX_SCOREBOARD) + check = bound(1, check, svs.maxclients); + if (check == svs.maxclients) i = 1; else i = check + 1; @@ -839,7 +870,7 @@ int PF_newcheckclient (int check) // count the cost pr_xfunction->builtinsprofile++; // wrap around - if (i == MAX_SCOREBOARD+1) + if (i == svs.maxclients+1) i = 1; // look up the client's edict ent = EDICT_NUM(i); @@ -851,8 +882,10 @@ int PF_newcheckclient (int check) } // get the PVS for the entity - VectorAdd (ent->v->origin, ent->v->view_ofs, org); - memcpy (checkpvs, sv.worldmodel->brushq1.LeafPVS(sv.worldmodel, sv.worldmodel->brushq1.PointInLeaf(sv.worldmodel, org)), (sv.worldmodel->brushq1.numleafs+7)>>3 ); + VectorAdd(ent->v->origin, ent->v->view_ofs, org); + checkpvsbytes = 0; + if (sv.worldmodel && sv.worldmodel->brush.FatPVS) + checkpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, org, 0, checkpvs, sizeof(checkpvs)); return i; } @@ -876,8 +909,6 @@ int c_invis, c_notvis; void PF_checkclient (void) { edict_t *ent, *self; - mleaf_t *leaf; - int l; vec3_t view; // find a new check if on a new frame @@ -897,17 +928,12 @@ void PF_checkclient (void) // 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 = sv.worldmodel->brushq1.PointInLeaf(sv.worldmodel, view); - if (leaf) + VectorAdd(self->v->origin, self->v->view_ofs, view); + if (sv.worldmodel && checkpvsbytes && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, checkpvs, view, view)) { - l = (leaf - sv.worldmodel->brushq1.leafs) - 1; - if ( (l<0) || !(checkpvs[l>>3] & (1<<(l&7)) ) ) - { - c_notvis++; - RETURN_EDICT(sv.edicts); - return; - } + c_notvis++; + RETURN_EDICT(sv.edicts); + return; } // might be able to see it @@ -934,12 +960,15 @@ void PF_stuffcmd (void) client_t *old; entnum = G_EDICTNUM(OFS_PARM0); - if (entnum < 1 || entnum > MAX_SCOREBOARD) - Host_Error ("Parm 0 not a client"); + if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active) + { + Con_Printf("Can't stuffcmd to a non-client"); + return; + } str = G_STRING(OFS_PARM1); old = host_client; - if ((host_client = svs.connectedclients[entnum-1])) + if ((host_client = svs.clients + entnum-1) && host_client->netconnection) Host_ClientCommands ("%s", str); host_client = old; } @@ -948,17 +977,14 @@ void PF_stuffcmd (void) ================= PF_localcmd -Sends text over to the client's execution buffer +Sends text to server console localcmd (string) ================= */ void PF_localcmd (void) { - char *str; - - str = G_STRING(OFS_PARM0); - Cbuf_AddText (str); + Cbuf_AddText(G_STRING(OFS_PARM0)); } /* @@ -970,11 +996,7 @@ float cvar (string) */ void PF_cvar (void) { - char *str; - - str = G_STRING(OFS_PARM0); - - G_FLOAT(OFS_RETURN) = Cvar_VariableValue (str); + G_FLOAT(OFS_RETURN) = Cvar_VariableValue(G_STRING(OFS_PARM0)); } /* @@ -986,12 +1008,7 @@ float cvar (string) */ void PF_cvar_set (void) { - char *var, *val; - - var = G_STRING(OFS_PARM0); - val = G_STRING(OFS_PARM1); - - Cvar_Set (var, val); + Cvar_Set(G_STRING(OFS_PARM0), G_STRING(OFS_PARM1)); } /* @@ -1050,21 +1067,12 @@ PF_dprint */ void PF_dprint (void) { - Con_DPrintf ("%s",PF_VarString(0)); -} - -// LordHavoc: added this to semi-fix the problem of using many ftos calls in a print -#define STRINGTEMP_BUFFERS 16 -#define STRINGTEMP_LENGTH 128 -static char pr_string_temp[STRINGTEMP_BUFFERS][STRINGTEMP_LENGTH]; -static int pr_string_tempindex = 0; - -static char *PR_GetTempString(void) -{ - char *s; - s = pr_string_temp[pr_string_tempindex]; - pr_string_tempindex = (pr_string_tempindex + 1) % STRINGTEMP_BUFFERS; - return s; + char string[STRINGTEMP_LENGTH]; + if (developer.integer) + { + PF_VarString(0, string, sizeof(string)); + Con_Printf("%s",string); + } } void PF_ftos (void) @@ -1074,8 +1082,10 @@ void PF_ftos (void) v = G_FLOAT(OFS_PARM0); s = PR_GetTempString(); - // LordHavoc: ftos improvement - sprintf (s, "%g", v); + if ((float)((int)v) == v) + sprintf(s, "%i", (int)v); + else + sprintf(s, "%f", v); G_INT(OFS_RETURN) = PR_SetString(s); } @@ -1118,8 +1128,11 @@ void PF_Remove (void) ed = G_EDICT(OFS_PARM0); if (ed == sv.edicts) Host_Error("remove: tried to remove world\n"); - if (NUM_FOR_EDICT(ed) <= MAX_SCOREBOARD) + if (NUM_FOR_EDICT(ed) <= svs.maxclients) Host_Error("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"); ED_Free (ed); } @@ -1301,7 +1314,7 @@ void PF_precache_model (void) Host_Error ("PF_Precache_*: Precache can only be done in spawn functions"); s = G_STRING(OFS_PARM0); - if (sv.worldmodel->brushq1.ishlbsp && ((!s) || (!s[0]))) + if (sv.worldmodel->brush.ishlbsp && ((!s) || (!s[0]))) return; G_INT(OFS_RETURN) = G_INT(OFS_PARM0); PR_CheckEmptyString (s); @@ -1357,6 +1370,10 @@ void PF_walkmove (void) int oldself; ent = PROG_TO_EDICT(pr_global_struct->self); + if (ent == sv.edicts) + Host_Error("walkmove: can not modify world entity\n"); + if (ent->e->free) + Host_Error("walkmove: can not modify free entity\n"); yaw = G_FLOAT(OFS_PARM0); dist = G_FLOAT(OFS_PARM1); @@ -1398,6 +1415,10 @@ void PF_droptofloor (void) trace_t trace; ent = PROG_TO_EDICT(pr_global_struct->self); + if (ent == sv.edicts) + Host_Error("droptofloor: can not modify world entity\n"); + if (ent->e->free) + Host_Error("droptofloor: can not modify free entity\n"); VectorCopy (ent->v->origin, end); end[2] -= 256; @@ -1442,9 +1463,9 @@ void PF_lightstyle (void) if (sv.state != ss_active) return; - for (j = 0;j < MAX_SCOREBOARD;j++) + for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++) { - if ((client = svs.connectedclients[j])) + if (client->netconnection) { MSG_WriteChar (&client->message, svc_lightstyle); MSG_WriteChar (&client->message,style); @@ -1489,7 +1510,7 @@ PF_pointcontents */ void PF_pointcontents (void) { - G_FLOAT(OFS_RETURN) = SV_PointContents(G_VECTOR(OFS_PARM0)); + G_FLOAT(OFS_RETURN) = SV_PointQ1Contents(G_VECTOR(OFS_PARM0)); } /* @@ -1541,6 +1562,10 @@ void PF_aim (void) float speed; ent = G_EDICT(OFS_PARM0); + if (ent == sv.edicts) + Host_Error("aim: can not use world entity\n"); + if (ent->e->free) + Host_Error("aim: can not use free entity\n"); speed = G_FLOAT(OFS_PARM1); VectorCopy (ent->v->origin, start); @@ -1617,6 +1642,10 @@ void PF_changeyaw (void) float ideal, current, move, speed; ent = PROG_TO_EDICT(pr_global_struct->self); + if (ent == sv.edicts) + Host_Error("changeyaw: can not modify world entity\n"); + if (ent->e->free) + Host_Error("changeyaw: can not modify free entity\n"); current = ANGLEMOD(ent->v->angles[1]); ideal = ent->v->ideal_yaw; speed = ent->v->yaw_speed; @@ -1660,6 +1689,10 @@ void PF_changepitch (void) eval_t *val; ent = G_EDICT(OFS_PARM0); + if (ent == sv.edicts) + Host_Error("changepitch: can not modify world entity\n"); + if (ent->e->free) + Host_Error("changepitch: can not modify free entity\n"); current = ANGLEMOD( ent->v->angles[0] ); if ((val = GETEDICTFIELDVALUE(ent, eval_idealpitch))) ideal = val->_float; @@ -1731,9 +1764,9 @@ sizebuf_t *WriteDest (void) case MSG_ONE: ent = PROG_TO_EDICT(pr_global_struct->msg_entity); entnum = NUM_FOR_EDICT(ent); - if (entnum < 1 || entnum > MAX_SCOREBOARD || svs.connectedclients[entnum-1] == NULL) - Host_Error("WriteDest: not a client"); - return &svs.connectedclients[entnum-1]->message; + if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active) + Host_Error("WriteDest: tried to write to non-client\n"); + return &svs.clients[entnum-1].message; case MSG_ALL: return &sv.reliable_datagram; @@ -1798,6 +1831,10 @@ void PF_makestatic (void) int i, large; ent = G_EDICT(OFS_PARM0); + if (ent == sv.edicts) + Host_Error("makestatic: can not modify world entity\n"); + if (ent->e->free) + Host_Error("makestatic: can not modify free entity\n"); large = false; if (ent->v->modelindex >= 256 || ent->v->frame >= 256) @@ -1843,10 +1880,14 @@ void PF_setspawnparms (void) ent = G_EDICT(OFS_PARM0); i = NUM_FOR_EDICT(ent); - if (i < 1 || i > MAX_SCOREBOARD || !(client = svs.connectedclients[i-1])) - Host_Error ("Entity is not a client"); + if (i < 1 || i > svs.maxclients || !svs.clients[i-1].active) + { + Con_Printf("tried to setspawnparms on a non-client\n"); + return; + } // copy spawn parms out of the client_t + client = svs.clients + i-1; for (i=0 ; i< NUM_SPAWN_PARMS ; i++) (&pr_global_struct->parm1)[i] = client->spawn_parms[i]; } @@ -1906,7 +1947,6 @@ void PF_randomvec (void) VectorCopy (temp, G_VECTOR(OFS_RETURN)); } -void SV_LightPoint (vec3_t color, vec3_t p); /* ================= PF_GetLight @@ -1921,11 +1961,15 @@ getlight(vector) */ void PF_GetLight (void) { - vec3_t color; - vec_t* p; + vec3_t ambientcolor, diffusecolor, diffusenormal; + vec_t *p; p = G_VECTOR(OFS_PARM0); - SV_LightPoint (color, p); - VectorCopy (color, G_VECTOR(OFS_RETURN)); + VectorClear(ambientcolor); + VectorClear(diffusecolor); + VectorClear(diffusenormal); + if (sv.worldmodel && sv.worldmodel->brush.LightPoint) + sv.worldmodel->brush.LightPoint(sv.worldmodel, p, ambientcolor, diffusecolor, diffusenormal); + VectorMA(ambientcolor, 0.5, diffusecolor, G_VECTOR(OFS_RETURN)); } #define MAX_QC_CVARS 128 @@ -2060,7 +2104,15 @@ 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"); + if (in->e->free) + Host_Error("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"); + if (out->e->free) + Host_Error("copyentity: can not modify free entity\n"); memcpy(out->v, in->v, progs->entityfields * 4); } @@ -2082,12 +2134,13 @@ void PF_setcolor (void) entnum = G_EDICTNUM(OFS_PARM0); i = G_FLOAT(OFS_PARM1); - if (entnum < 1 || entnum > MAX_SCOREBOARD || !(client = svs.connectedclients[entnum-1])) + if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active) { Con_Printf ("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; @@ -2542,8 +2595,6 @@ static msurface_t *getsurface(edict_t *ed, int surfnum) if (modelindex < 1 || modelindex >= MAX_MODELS) return NULL; model = sv.models[modelindex]; - if (model->type != mod_brush) - return NULL; if (surfnum < 0 || surfnum >= model->brushq1.nummodelsurfaces) return NULL; return model->brushq1.surfaces + surfnum + model->brushq1.firstmodelsurface; @@ -2623,7 +2674,7 @@ void PF_getsurfacenearpoint(void) if (modelindex < 1 || modelindex >= MAX_MODELS) return; model = sv.models[modelindex]; - if (model->type != mod_brush) + if (!model->brushq1.numsurfaces) return; // FIXME: implement rotation/scaling @@ -2691,8 +2742,9 @@ void PR_Files_CloseAll(void) //float(string s) stof = #81; // get numerical value from a string void PF_stof(void) { - char *s = PF_VarString(0); - G_FLOAT(OFS_RETURN) = atof(s); + 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 @@ -2766,7 +2818,7 @@ void PF_fclose(void) void PF_fgets(void) { int c, end; - static char string[MAX_VARSTRING]; + static char string[STRINGTEMP_LENGTH]; int filenum = G_FLOAT(OFS_PARM0); if (filenum < 0 || filenum >= MAX_PRFILES) { @@ -2784,7 +2836,7 @@ void PF_fgets(void) c = FS_Getc(pr_files[filenum]); if (c == '\r' || c == '\n' || c < 0) break; - if (end < MAX_VARSTRING - 1) + if (end < STRINGTEMP_LENGTH - 1) string[end++] = c; } string[end] = 0; @@ -2803,7 +2855,7 @@ void PF_fgets(void) void PF_fputs(void) { int stringlength; - char *s = PF_VarString(1); + char string[STRINGTEMP_LENGTH]; int filenum = G_FLOAT(OFS_PARM0); if (filenum < 0 || filenum >= MAX_PRFILES) { @@ -2815,10 +2867,11 @@ void PF_fputs(void) Con_Printf("PF_fputs: no such file handle %i (or file has been closed)\n", filenum); return; } - if ((stringlength = strlen(s))) - FS_Write(pr_files[filenum], s, stringlength); + 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", s); + Con_Printf("fputs: %s\n", string); } //float(string s) strlen = #114; // returns how many characters are in a string @@ -2835,7 +2888,8 @@ void PF_strlen(void) //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) { - char *s = PF_VarString(0); + char *s = PR_GetTempString(); + PF_VarString(0, s, STRINGTEMP_LENGTH); G_INT(OFS_RETURN) = PR_SetString(s); } @@ -2859,7 +2913,9 @@ void PF_substring(void) //vector(string s) stov = #117; // returns vector value from a string void PF_stov(void) { - Math_atov(PF_VarString(0), G_VECTOR(OFS_RETURN)); + char string[STRINGTEMP_LENGTH]; + PF_VarString(0, string, sizeof(string)); + Math_atov(string, G_VECTOR(OFS_RETURN)); } //string(string s) strzone = #118; // makes a copy of a string into the string zone and returns it, this is often used to keep around a tempstring for longer periods of time (tempstrings are replaced often) @@ -2887,11 +2943,14 @@ void PF_clientcommand (void) //find client for this entity i = (NUM_FOR_EDICT(G_EDICT(OFS_PARM0)) - 1); - if (i < 0 || i >= MAX_SCOREBOARD || !svs.connectedclients[i]) - Host_Error("PF_clientcommand: entity is not a client"); + if (i < 0 || i >= svs.maxclients || !svs.clients[i].active) + { + Con_Printf("PF_clientcommand: entity is not a client"); + return; + } temp_client = host_client; - host_client = svs.connectedclients[i]; + host_client = svs.clients + i; Cmd_ExecuteString (G_STRING(OFS_PARM1), src_client); host_client = temp_client; } @@ -2948,6 +3007,11 @@ void PF_setattachment (void) int i, modelindex; model_t *model; + if (e == sv.edicts) + Host_Error("setattachment: can not modify world entity\n"); + if (e->e->free) + Host_Error("setattachment: can not modify free entity\n"); + if (tagentity == NULL) tagentity = sv.edicts; @@ -2961,9 +3025,8 @@ void PF_setattachment (void) if (tagentity != NULL && tagentity != sv.edicts && tagname && tagname[0]) { modelindex = (int)tagentity->v->modelindex; - if (modelindex >= 0 && modelindex < MAX_MODELS) + if (modelindex >= 0 && modelindex < MAX_MODELS && (model = sv.models[modelindex])) { - model = sv.models[modelindex]; if (model->data_overridetagnamesforskin && (unsigned int)tagentity->v->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames) for (i = 0;i < model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames;i++) if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].data_overridetagnames[i].name)) @@ -2981,6 +3044,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 @@ -3151,11 +3383,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) }; @@ -3167,11 +3399,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(); }