X-Git-Url: https://de.git.xonotic.org/?a=blobdiff_plain;f=pr_cmds.c;h=a7468f0a39368aff17728db196df3077e7b04638;hb=53018de29bf2a7cc2e9d4eb753adb4153ffeeca7;hp=0da857a852ed0c6196311235bcb7737e9e1d7441;hpb=3b559840aaf1e5a218052d893881c1dd8c1b0780;p=xonotic%2Fdarkplaces.git diff --git a/pr_cmds.c b/pr_cmds.c index 0da857a8..a7468f0a 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,30 +51,24 @@ char pr_varstring_temp[MAX_VARSTRING]; */ -char *PF_VarString (int first) +void PF_VarString(int first, char *out, int outlength) { - int i, j, end; - char *s; + int i; + const char *s; + char *outend; - end = 0; - for (i = first;i < pr_argc;i++) + outend = out + outlength - 1; + for (i = first;i < pr_argc && out < outend;i++) { - // LordHavoc: FIXME: this is just a strlcat inlined s = G_STRING((OFS_PARM0+i*3)); - j = strlen(s); - if (j > MAX_VARSTRING - 1 - end) - j = MAX_VARSTRING - 1 - end; - if (j > 0) - { - memcpy(pr_varstring_temp + end, s, j); - end += j; - } + while (out < outend && *s) + *out++ = *s++; } - pr_varstring_temp[end] = 0; - return pr_varstring_temp; + *out++ = 0; } char *ENGINE_EXTENSIONS = +"DP_CL_LOADSKY " "DP_EF_NODRAW " "DP_EF_ADDITIVE " "DP_EF_BLUE " @@ -79,8 +83,13 @@ char *ENGINE_EXTENSIONS = "DP_ENT_GLOW " "DP_ENT_SCALE " "DP_ENT_VIEWMODEL " +"DP_GFX_EXTERNALTEXTURES " "DP_GFX_FOG " +"DP_GFX_QUAKE3MODELTAGS " +"DP_GFX_SKINFILES " +"DP_GFX_SKYBOX " "DP_HALFLIFE_MAP " +"DP_HALFLIFE_MAP_CVAR " "DP_INPUTBUTTONS " "DP_MONSTERWALK " "DP_MOVETYPEBOUNCEMISSILE " @@ -98,6 +107,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_VECTORVECTORS " "DP_QUAKE2_MODEL " "DP_QUAKE3_MODEL " @@ -126,6 +137,7 @@ char *ENGINE_EXTENSIONS = "DP_TE_STANDARDEFFECTBUILTINS " "DP_VIEWZOOM " "FRIK_FILE " +"KRIMZON_SV_PARSECLIENTCOMMAND " "NEH_CMD_PLAY2 " "NEH_RESTOREGAME " "TW_SV_STEPCONTROL " @@ -178,11 +190,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); @@ -201,11 +213,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); @@ -346,10 +358,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); } /* @@ -363,23 +374,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 > svs.maxclients) + if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active) { Con_Printf ("tried to sprint to a non-client\n"); return; } - client = &svs.clients[entnum-1]; - - MSG_WriteChar (&client->message,svc_print); - MSG_WriteString (&client->message, s ); + 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, string); } @@ -394,23 +406,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 > svs.maxclients) + if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active) { Con_Printf ("tried to sprint to a non-client\n"); return; } - client = &svs.clients[entnum-1]; - - MSG_WriteChar (&client->message,svc_centerprint); - MSG_WriteString (&client->message, s ); + 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, string); } @@ -711,7 +724,7 @@ void PF_traceline (void) nomonsters = G_FLOAT(OFS_PARM2); ent = G_EDICT(OFS_PARM3); - trace = SV_Move (v1, vec3_origin, vec3_origin, v2, nomonsters ? MOVE_NOMONSTERS : MOVE_NORMAL, ent); + trace = SV_Move (v1, vec3_origin, vec3_origin, v2, nomonsters, ent); pr_global_struct->trace_allsolid = trace.allsolid; pr_global_struct->trace_startsolid = trace.startsolid; @@ -818,23 +831,18 @@ void PF_checkpos (void) //============================================================================ +int checkpvsbytes; qbyte checkpvs[MAX_MAP_LEAFS/8]; int PF_newcheckclient (int check) { int i; - qbyte *pvs; edict_t *ent; - mleaf_t *leaf; vec3_t org; // cycle to the next one - if (check < 1) - check = 1; - if (check > svs.maxclients) - check = svs.maxclients; - + check = bound(1, check, svs.maxclients); if (check == svs.maxclients) i = 1; else @@ -842,31 +850,25 @@ int PF_newcheckclient (int check) for ( ; ; i++) { + // count the cost pr_xfunction->builtinsprofile++; + // wrap around if (i == svs.maxclients+1) i = 1; - + // look up the client's edict ent = EDICT_NUM(i); - - if (i == check) - break; // didn't find anything else - - if (ent->free) + // check if it is to be ignored, but never ignore the one we started on (prevent infinite loop) + if (i != check && (ent->e->free || ent->v->health <= 0 || ((int)ent->v->flags & FL_NOTARGET))) continue; - if (ent->v->health <= 0) - continue; - if ((int)ent->v->flags & FL_NOTARGET) - continue; - - // anything that is a client, or has a client as an enemy + // found a valid client (possibly the same one again) break; } // get the PVS for the entity - VectorAdd (ent->v->origin, ent->v->view_ofs, org); - leaf = Mod_PointInLeaf (org, sv.worldmodel); - pvs = Mod_LeafPVS (leaf, sv.worldmodel); - memcpy (checkpvs, pvs, (sv.worldmodel->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; } @@ -890,8 +892,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 @@ -903,7 +903,7 @@ void PF_checkclient (void) // return check if it might be visible ent = EDICT_NUM(sv.lastcheck); - if (ent->free || ent->v->health <= 0) + if (ent->e->free || ent->v->health <= 0) { RETURN_EDICT(sv.edicts); return; @@ -911,17 +911,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 = Mod_PointInLeaf (view, sv.worldmodel); - 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->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 @@ -948,13 +943,16 @@ void PF_stuffcmd (void) client_t *old; entnum = G_EDICTNUM(OFS_PARM0); - if (entnum < 1 || entnum > svs.maxclients) - 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; - host_client = &svs.clients[entnum-1]; - Host_ClientCommands ("%s", str); + if ((host_client = svs.clients + entnum-1) && host_client->netconnection) + Host_ClientCommands ("%s", str); host_client = old; } @@ -969,10 +967,7 @@ localcmd (string) */ void PF_localcmd (void) { - char *str; - - str = G_STRING(OFS_PARM0); - Cbuf_AddText (str); + Cbuf_AddText(G_STRING(OFS_PARM0)); } /* @@ -984,11 +979,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)); } /* @@ -1000,12 +991,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)); } /* @@ -1036,7 +1022,7 @@ void PF_findradius (void) for (i=1 ; ibuiltinsprofile++; - if (ent->free) + if (ent->e->free) continue; if (ent->v->solid == SOLID_NOT) continue; @@ -1064,21 +1050,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) @@ -1088,8 +1065,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); } @@ -1159,7 +1138,7 @@ void PF_Find (void) { pr_xfunction->builtinsprofile++; ed = EDICT_NUM(e); - if (ed->free) + if (ed->e->free) continue; t = E_STRING(ed,f); if (!t) @@ -1190,7 +1169,7 @@ void PF_FindFloat (void) { pr_xfunction->builtinsprofile++; ed = EDICT_NUM(e); - if (ed->free) + if (ed->e->free) continue; if (E_FLOAT(ed,f) == s) { @@ -1225,7 +1204,7 @@ void PF_findchain (void) for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent)) { pr_xfunction->builtinsprofile++; - if (ent->free) + if (ent->e->free) continue; t = E_STRING(ent,f); if (!t) @@ -1258,7 +1237,7 @@ void PF_findchainfloat (void) for (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent)) { pr_xfunction->builtinsprofile++; - if (ent->free) + if (ent->e->free) continue; if (E_FLOAT(ent,f) != s) continue; @@ -1315,7 +1294,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->ishlbsp && ((!s) || (!s[0]))) + if (sv.worldmodel->brush.ishlbsp && ((!s) || (!s[0]))) return; G_INT(OFS_RETURN) = G_INT(OFS_PARM0); PR_CheckEmptyString (s); @@ -1428,7 +1407,7 @@ void PF_droptofloor (void) ent->v->groundentity = EDICT_TO_PROG(trace.ent); G_FLOAT(OFS_RETURN) = 1; // if support is destroyed, keep suspended (gross hack for floating items in various maps) - ent->suspendedinairflag = true; + ent->e->suspendedinairflag = true; } } @@ -1456,13 +1435,15 @@ void PF_lightstyle (void) if (sv.state != ss_active) return; - for (j=0, client = svs.clients ; jactive || client->spawned) + for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++) + { + if (client->netconnection) { MSG_WriteChar (&client->message, svc_lightstyle); MSG_WriteChar (&client->message,style); MSG_WriteString (&client->message, val); } + } } void PF_rint (void) @@ -1501,7 +1482,7 @@ PF_pointcontents */ void PF_pointcontents (void) { - G_FLOAT(OFS_RETURN) = Mod_PointContents(G_VECTOR(OFS_PARM0), sv.worldmodel); + G_FLOAT(OFS_RETURN) = SV_PointQ1Contents(G_VECTOR(OFS_PARM0)); } /* @@ -1527,7 +1508,7 @@ void PF_nextent (void) return; } ent = EDICT_NUM(i); - if (!ent->free) + if (!ent->e->free) { RETURN_EDICT(ent); return; @@ -1743,8 +1724,8 @@ 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 > svs.maxclients) - Host_Error ("WriteDest: not a client"); + if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active) + Con_Printf("WriteDest: tried to write to non-client\n"); return &svs.clients[entnum-1].message; case MSG_ALL: @@ -1855,12 +1836,14 @@ void PF_setspawnparms (void) ent = G_EDICT(OFS_PARM0); i = NUM_FOR_EDICT(ent); - if (i < 1 || i > svs.maxclients) - 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); - + client = svs.clients + i-1; for (i=0 ; i< NUM_SPAWN_PARMS ; i++) (&pr_global_struct->parm1)[i] = client->spawn_parms[i]; } @@ -1920,7 +1903,6 @@ void PF_randomvec (void) VectorCopy (temp, G_VECTOR(OFS_RETURN)); } -void SV_LightPoint (vec3_t color, vec3_t p); /* ================= PF_GetLight @@ -1935,11 +1917,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 @@ -2089,21 +2075,25 @@ setcolor(clientent, value) */ void PF_setcolor (void) { - client_t *client; - int entnum, i; + client_t *client; + int entnum, i; + eval_t *val; entnum = G_EDICTNUM(OFS_PARM0); i = G_FLOAT(OFS_PARM1); - if (entnum < 1 || entnum > svs.maxclients) + 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]; + client = svs.clients + entnum-1; + if ((val = GETEDICTFIELDVALUE(client->edict, eval_clientcolors))) + val->_float = i; client->colors = i; - EDICT_NUM(client->edictnumber)->v->team = (i & 15) + 1; + client->old_colors = i; + client->edict->v->team = (i & 15) + 1; MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors); MSG_WriteByte (&sv.reliable_datagram, entnum - 1); @@ -2547,17 +2537,15 @@ static msurface_t *getsurface(edict_t *ed, int surfnum) { int modelindex; model_t *model; - if (!ed || ed->free) + if (!ed || ed->e->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) + if (surfnum < 0 || surfnum >= model->brushq1.nummodelsurfaces) return NULL; - return model->surfaces + surfnum + model->firstmodelsurface; + return model->brushq1.surfaces + surfnum + model->brushq1.firstmodelsurface; } @@ -2582,7 +2570,7 @@ void PF_getsurfacepoint(void) int pointnum; VectorClear(G_VECTOR(OFS_RETURN)); ed = G_EDICT(OFS_PARM0); - if (!ed || ed->free) + if (!ed || ed->e->free) return; if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1)))) return; @@ -2628,22 +2616,22 @@ void PF_getsurfacenearpoint(void) ed = G_EDICT(OFS_PARM0); point = G_VECTOR(OFS_PARM1); - if (!ed || ed->free) + if (!ed || ed->e->free) return; modelindex = ed->v->modelindex; 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 VectorSubtract(point, ed->v->origin, p); best = -1; bestdist = 1000000000; - for (surfnum = 0;surfnum < model->nummodelsurfaces;surfnum++) + for (surfnum = 0;surfnum < model->brushq1.nummodelsurfaces;surfnum++) { - surf = model->surfaces + surfnum + model->firstmodelsurface; + surf = model->brushq1.surfaces + surfnum + model->brushq1.firstmodelsurface; dist = PlaneDiff(p, surf->plane); dist = dist * dist; if (dist < bestdist) @@ -2668,7 +2656,7 @@ void PF_getsurfaceclippedpoint(void) vec3_t p, out; VectorClear(G_VECTOR(OFS_RETURN)); ed = G_EDICT(OFS_PARM0); - if (!ed || ed->free) + if (!ed || ed->e->free) return; if (!(surf = getsurface(ed, G_FLOAT(OFS_PARM1)))) return; @@ -2702,8 +2690,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 @@ -2777,7 +2766,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) { @@ -2795,7 +2784,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; @@ -2814,7 +2803,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) { @@ -2826,10 +2815,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 @@ -2846,43 +2836,34 @@ 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); } //string(string s, float start, float length) substring = #116; // returns a section of a string as a tempstring void PF_substring(void) { - int end, start, length, slen; - char *s; - char string[MAX_VARSTRING]; + int i, start, length; + char *s, *string = PR_GetTempString(); s = G_STRING(OFS_PARM0); start = G_FLOAT(OFS_PARM1); length = G_FLOAT(OFS_PARM2); - if (s) - slen = strlen(s); - else - slen = 0; - if (start < 0) - start = 0; - if (length > slen - start) - length = slen - start; - if (length > MAX_VARSTRING - 1) - length = MAX_VARSTRING - 1; - end = 0; - if (length > 0) - { - memcpy(string, s + start, length); - end = length; - } - string[end] = 0; + if (!s) + s = ""; + for (i = 0;i < start && *s;i++, s++); + for (i = 0;i < STRINGTEMP_LENGTH - 1 && *s && i < length;i++, s++) + string[i] = *s; + string[i] = 0; G_INT(OFS_RETURN) = PR_SetString(string); } //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) @@ -2901,6 +2882,112 @@ void PF_strunzone(void) Mem_Free(G_STRING(OFS_PARM0)); } +//void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client +//this function originally written by KrimZon, made shorter by LordHavoc +void PF_clientcommand (void) +{ + client_t *temp_client; + int i; + + //find client for this entity + i = (NUM_FOR_EDICT(G_EDICT(OFS_PARM0)) - 1); + 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.clients + i; + Cmd_ExecuteString (G_STRING(OFS_PARM1), src_client); + host_client = temp_client; +} + +//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; +void PF_tokenize (void) +{ + const char *p; + char *str; + str = G_STRING(OFS_PARM0); + + if (tokens != NULL) + { + int i; + for (i=0;i= 0 && token_num < num_tokens) + G_INT(OFS_RETURN) = PR_SetString(tokens[token_num]); + else + G_INT(OFS_RETURN) = PR_SetString(""); +} + +//void(entity e, entity tagentity, string tagname) setattachment = #443; // attachs e to a tag on tagentity (note: use "" to attach to entity origin/angles instead of a tag) +void PF_setattachment (void) +{ + edict_t *e = G_EDICT(OFS_PARM0); + edict_t *tagentity = G_EDICT(OFS_PARM1); + char *tagname = G_STRING(OFS_PARM2); + eval_t *v; + int i, modelindex; + model_t *model; + + if (tagentity == NULL) + tagentity = sv.edicts; + + v = GETEDICTFIELDVALUE(e, eval_tag_entity); + if (v) + v->edict = EDICT_TO_PROG(tagentity); + + v = GETEDICTFIELDVALUE(e, eval_tag_index); + if (v) + v->_float = 0; + if (tagentity != NULL && tagentity != sv.edicts && tagname && tagname[0]) + { + modelindex = (int)tagentity->v->modelindex; + if (modelindex >= 0 && modelindex < MAX_MODELS) + { + 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)) + v->_float = i + 1; + if (v->_float == 0 && model->alias.aliasnum_tags) + for (i = 0;i < model->alias.aliasnum_tags;i++) + if (!strcmp(tagname, model->alias.aliasdata_tags[i].name)) + v->_float = i + 1; + if (v->_float == 0) + Con_DPrintf("setattachment(edict %i, edict %i, string \"%s\"): tried to find tag named \"%s\" on entity %i (model \"%s\") but could not find it\n", NUM_FOR_EDICT(e), NUM_FOR_EDICT(tagentity), tagname, tagname, NUM_FOR_EDICT(tagentity), model->name); + } + else + Con_DPrintf("setattachment(edict %i, edict %i, string \"%s\"): tried to find tag named \"%s\" on entity %i but it has no model\n", NUM_FOR_EDICT(e), NUM_FOR_EDICT(tagentity), tagname, tagname, NUM_FOR_EDICT(tagentity)); + } +} + + builtin_t pr_builtin[] = { NULL, // #0 @@ -3067,7 +3154,17 @@ PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_ PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE) PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE) PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE) -a a a a a a // #440-499 (LordHavoc) +PF_clientcommand, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND) +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 +NULL, // #449 +a a a a a // #450-499 (LordHavoc) }; builtin_t *pr_builtins = pr_builtin;