X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=blobdiff_plain;f=prvm_cmds.c;h=c1be177c09848e343e02748396319cbabc23541b;hp=20d2dd03ea6988be8461b5026a92d325e02f2cc2;hb=cf22ff4047c6cac2ee44bb3ecf554ca0f9eed819;hpb=140d5617344ca77bb7ab76802d3f18b898e58715 diff --git a/prvm_cmds.c b/prvm_cmds.c index 20d2dd03..c1be177c 100644 --- a/prvm_cmds.c +++ b/prvm_cmds.c @@ -4,45 +4,48 @@ // cause large (I think they will) parts are from pr_cmds the same copyright like in pr_cmds // also applies here +#include "quakedef.h" + #include "prvm_cmds.h" +#include "libcurl.h" +#include + +extern cvar_t prvm_backtraceforwarnings; // LordHavoc: changed this to NOT use a return statement, so that it can be used in functions that must return a value void VM_Warning(const char *fmt, ...) { va_list argptr; char msg[MAX_INPUTLINE]; + static double recursive = -1; va_start(argptr,fmt); dpvsnprintf(msg,sizeof(msg),fmt,argptr); va_end(argptr); Con_Print(msg); + // TODO: either add a cvar/cmd to control the state dumping or replace some of the calls with Con_Printf [9/13/2006 Black] - //PRVM_PrintState(); + if(prvm_backtraceforwarnings.integer && recursive != realtime) // NOTE: this compares to the time, just in case if PRVM_PrintState causes a Host_Error and keeps recursive set + { + recursive = realtime; + PRVM_PrintState(); + recursive = -1; + } } //============================================================================ // Common -// temp string handling -// LordHavoc: added this to semi-fix the problem of using many ftos calls in a print -static char vm_string_temp[VM_STRINGTEMP_BUFFERS][VM_STRINGTEMP_LENGTH]; -static int vm_string_tempindex = 0; - -// TODO: (move vm_files and vm_fssearchlist to prvm_prog_t struct) +// TODO DONE: move vm_files and vm_fssearchlist to prvm_prog_t struct // TODO: move vm_files and vm_fssearchlist back [9/13/2006 Black] -char *VM_GetTempString(void) -{ - char *s; - s = vm_string_temp[vm_string_tempindex]; - vm_string_tempindex = (vm_string_tempindex + 1) % VM_STRINGTEMP_BUFFERS; - return s; -} +// TODO: (move vm_files and vm_fssearchlist to prvm_prog_t struct again) [2007-01-23 LordHavoc] +// TODO: will this war ever end? [2007-01-23 LordHavoc] void VM_CheckEmptyString (const char *s) { - if (s[0] <= ' ') + if (ISWHITESPACE(s[0])) PRVM_ERROR ("%s: Bad string", PRVM_NAME); } @@ -121,10 +124,10 @@ void VM_error (void) VM_VarString(0, string, sizeof(string)); Con_Printf("======%s ERROR in %s:\n%s\n", PRVM_NAME, PRVM_GetString(prog->xfunction->s_name), string); - if(prog->self) + if (prog->globaloffsets.self >= 0) { - ed = PRVM_G_EDICT(prog->self->ofs); - PRVM_ED_Print(ed); + ed = PRVM_PROG_TO_EDICT(PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict); + PRVM_ED_Print(ed, NULL); } PRVM_ERROR ("%s: Program error in function %s:\n%s\nTip: read above for entity information\n", PRVM_NAME, PRVM_GetString(prog->xfunction->s_name), string); @@ -146,11 +149,11 @@ void VM_objerror (void) char string[VM_STRINGTEMP_LENGTH]; VM_VarString(0, string, sizeof(string)); - Con_Printf("======OBJECT ERROR======\n", PRVM_NAME, PRVM_GetString(prog->xfunction->s_name), string); - if(prog->self) + Con_Printf("======OBJECT ERROR======\n"); // , PRVM_NAME, PRVM_GetString(prog->xfunction->s_name), string); // or include them? FIXME + if (prog->globaloffsets.self >= 0) { - ed = PRVM_G_EDICT (prog->self->ofs); - PRVM_ED_Print(ed); + ed = PRVM_PROG_TO_EDICT(PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict); + PRVM_ED_Print(ed, NULL); PRVM_ED_Free (ed); } @@ -162,11 +165,11 @@ void VM_objerror (void) /* ================= -VM_print (actually used only by client and menu) +VM_print print to console -print(string) +print(...[string]) ================= */ void VM_print (void) @@ -215,6 +218,8 @@ void VM_sprint (void) int clientnum; char string[VM_STRINGTEMP_LENGTH]; + VM_SAFEPARMCOUNTRANGE(1, 8, VM_sprint); + //find client for this entity clientnum = (int)PRVM_G_FLOAT(OFS_PARM0); if (!sv.active || clientnum < 0 || clientnum >= svs.maxclients || !svs.clients[clientnum].active) @@ -238,13 +243,14 @@ VM_centerprint single print to the screen -centerprint(clientent, value) +centerprint(value) ================= */ void VM_centerprint (void) { char string[VM_STRINGTEMP_LENGTH]; + VM_SAFEPARMCOUNTRANGE(1, 8, VM_centerprint); VM_VarString(0, string, sizeof(string)); SCR_CenterPrint(string); } @@ -324,50 +330,14 @@ void VM_vectoyaw (void) ================= VM_vectoangles -vector vectoangles(vector) +vector vectoangles(vector[, vector]) ================= */ void VM_vectoangles (void) { - float *value1; - float forward; - float yaw, pitch; - - VM_SAFEPARMCOUNT(1,VM_vectoangles); - - value1 = PRVM_G_VECTOR(OFS_PARM0); - - if (value1[1] == 0 && value1[0] == 0) - { - yaw = 0; - if (value1[2] > 0) - pitch = 90; - else - pitch = 270; - } - else - { - // LordHavoc: optimized a bit - if (value1[0]) - { - yaw = (atan2(value1[1], value1[0]) * 180 / M_PI); - if (yaw < 0) - yaw += 360; - } - else if (value1[1] > 0) - yaw = 90; - else - yaw = 270; + VM_SAFEPARMCOUNTRANGE(1, 2,VM_vectoangles); - forward = sqrt(value1[0]*value1[0] + value1[1]*value1[1]); - pitch = (atan2(value1[2], forward) * 180 / M_PI); - if (pitch < 0) - pitch += 360; - } - - PRVM_G_FLOAT(OFS_RETURN+0) = pitch; - PRVM_G_FLOAT(OFS_RETURN+1) = yaw; - PRVM_G_FLOAT(OFS_RETURN+2) = 0; + AnglesFromVectors(PRVM_G_VECTOR(OFS_RETURN), PRVM_G_VECTOR(OFS_PARM0), prog->argc >= 2 ? PRVM_G_VECTOR(OFS_PARM1) : NULL, true); } /* @@ -386,49 +356,6 @@ void VM_random (void) PRVM_G_FLOAT(OFS_RETURN) = lhrandom(0, 1); } -/* -================= -PF_sound - -Each entity can have eight independant sound sources, like voice, -weapon, feet, etc. - -Channel 0 is an auto-allocate channel, the others override anything -already running on that entity/channel pair. - -An attenuation of 0 will play full volume everywhere in the level. -Larger attenuations will drop off. - -================= -*/ -/* -void PF_sound (void) -{ - char *sample; - int channel; - prvm_edict_t *entity; - int volume; - float attenuation; - - entity = PRVM_G_EDICT(OFS_PARM0); - channel = PRVM_G_FLOAT(OFS_PARM1); - sample = PRVM_G_STRING(OFS_PARM2); - volume = PRVM_G_FLOAT(OFS_PARM3) * 255; - attenuation = PRVM_G_FLOAT(OFS_PARM4); - - if (volume < 0 || volume > 255) - Host_Error ("SV_StartSound: volume = %i", volume); - - if (attenuation < 0 || attenuation > 4) - Host_Error ("SV_StartSound: attenuation = %f", attenuation); - - if (channel < 0 || channel > 7) - Host_Error ("SV_StartSound: channel = %i", channel); - - SV_StartSound (entity, channel, sample, volume, attenuation); -} -*/ - /* ========= VM_localsound @@ -481,10 +408,18 @@ cmd (string, ...) void VM_localcmd (void) { char string[VM_STRINGTEMP_LENGTH]; + VM_SAFEPARMCOUNTRANGE(1, 8, VM_localcmd); VM_VarString(0, string, sizeof(string)); Cbuf_AddText(string); } +static qboolean PRVM_Cvar_ReadOk(const char *string) +{ + cvar_t *cvar; + cvar = Cvar_FindVar(string); + return ((cvar) && ((cvar->flags & CVAR_PRIVATE) == 0)); +} + /* ================= VM_cvar @@ -494,39 +429,73 @@ float cvar (string) */ void VM_cvar (void) { - VM_SAFEPARMCOUNT(1,VM_cvar); - - PRVM_G_FLOAT(OFS_RETURN) = Cvar_VariableValue(PRVM_G_STRING(OFS_PARM0)); + char string[VM_STRINGTEMP_LENGTH]; + VM_SAFEPARMCOUNTRANGE(1,8,VM_cvar); + VM_VarString(0, string, sizeof(string)); + VM_CheckEmptyString(string); + PRVM_G_FLOAT(OFS_RETURN) = PRVM_Cvar_ReadOk(string) ? Cvar_VariableValue(string) : 0; } /* ================= -VM_cvar_string +VM_cvar -const string VM_cvar_string (string) +float cvar_type (string) +float CVAR_TYPEFLAG_EXISTS = 1; +float CVAR_TYPEFLAG_SAVED = 2; +float CVAR_TYPEFLAG_PRIVATE = 4; +float CVAR_TYPEFLAG_ENGINE = 8; +float CVAR_TYPEFLAG_HASDESCRIPTION = 16; +float CVAR_TYPEFLAG_READONLY = 32; ================= */ -void VM_cvar_string(void) +void VM_cvar_type (void) { - char *out; - const char *name; - const char *cvar_string; - VM_SAFEPARMCOUNT(1,VM_cvar_string); - - name = PRVM_G_STRING(OFS_PARM0); + char string[VM_STRINGTEMP_LENGTH]; + cvar_t *cvar; + int ret; - if(!name) - PRVM_ERROR("VM_cvar_string: %s: null string", PRVM_NAME); + VM_SAFEPARMCOUNTRANGE(1,8,VM_cvar); + VM_VarString(0, string, sizeof(string)); + VM_CheckEmptyString(string); + cvar = Cvar_FindVar(string); - VM_CheckEmptyString(name); - out = VM_GetTempString(); + if(!cvar) + { + PRVM_G_FLOAT(OFS_RETURN) = 0; + return; // CVAR_TYPE_NONE + } - cvar_string = Cvar_VariableString(name); + ret = 1; // CVAR_EXISTS + if(cvar->flags & CVAR_SAVE) + ret |= 2; // CVAR_TYPE_SAVED + if(cvar->flags & CVAR_PRIVATE) + ret |= 4; // CVAR_TYPE_PRIVATE + if(!(cvar->flags & CVAR_ALLOCATED)) + ret |= 8; // CVAR_TYPE_ENGINE + if(cvar->description != cvar_dummy_description) + ret |= 16; // CVAR_TYPE_HASDESCRIPTION + if(cvar->flags & CVAR_READONLY) + ret |= 32; // CVAR_TYPE_READONLY + + PRVM_G_FLOAT(OFS_RETURN) = ret; +} - strlcpy(out, cvar_string, VM_STRINGTEMP_LENGTH); +/* +================= +VM_cvar_string - PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(out); +const string VM_cvar_string (string, ...) +================= +*/ +void VM_cvar_string(void) +{ + char string[VM_STRINGTEMP_LENGTH]; + VM_SAFEPARMCOUNTRANGE(1,8,VM_cvar_string); + VM_VarString(0, string, sizeof(string)); + VM_CheckEmptyString(string); + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(PRVM_Cvar_ReadOk(string) ? Cvar_VariableString(string) : ""); } @@ -534,43 +503,49 @@ void VM_cvar_string(void) ======================== VM_cvar_defstring -const string VM_cvar_defstring (string) +const string VM_cvar_defstring (string, ...) ======================== */ void VM_cvar_defstring (void) { - char *out; - const char *name; - const char *cvar_string; - VM_SAFEPARMCOUNT(1,VM_cvar_string); - - name = PRVM_G_STRING(OFS_PARM0); - - if(!name) - PRVM_ERROR("VM_cvar_defstring: %s: null string", PRVM_NAME); - - VM_CheckEmptyString(name); - - out = VM_GetTempString(); - - cvar_string = Cvar_VariableDefString(name); + char string[VM_STRINGTEMP_LENGTH]; + VM_SAFEPARMCOUNTRANGE(1,8,VM_cvar_defstring); + VM_VarString(0, string, sizeof(string)); + VM_CheckEmptyString(string); + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(Cvar_VariableDefString(string)); +} - strlcpy(out, cvar_string, VM_STRINGTEMP_LENGTH); +/* +======================== +VM_cvar_defstring - PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(out); +const string VM_cvar_description (string, ...) +======================== +*/ +void VM_cvar_description (void) +{ + char string[VM_STRINGTEMP_LENGTH]; + VM_SAFEPARMCOUNTRANGE(1,8,VM_cvar_description); + VM_VarString(0, string, sizeof(string)); + VM_CheckEmptyString(string); + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(Cvar_VariableDescription(string)); } /* ================= VM_cvar_set -void cvar_set (string,string) +void cvar_set (string,string, ...) ================= */ void VM_cvar_set (void) { - VM_SAFEPARMCOUNT(2,VM_cvar_set); - - Cvar_Set(PRVM_G_STRING(OFS_PARM0), PRVM_G_STRING(OFS_PARM1)); + const char *name; + char string[VM_STRINGTEMP_LENGTH]; + VM_SAFEPARMCOUNTRANGE(2,8,VM_cvar_set); + VM_VarString(1, string, sizeof(string)); + name = PRVM_G_STRING(OFS_PARM0); + VM_CheckEmptyString(name); + Cvar_Set(name, string); } /* @@ -583,6 +558,7 @@ dprint(...[string]) void VM_dprint (void) { char string[VM_STRINGTEMP_LENGTH]; + VM_SAFEPARMCOUNTRANGE(1, 8, VM_dprint); if (developer.integer) { VM_VarString(0, string, sizeof(string)); @@ -605,18 +581,17 @@ string ftos(float) void VM_ftos (void) { float v; - char *s; + char s[128]; VM_SAFEPARMCOUNT(1, VM_ftos); v = PRVM_G_FLOAT(OFS_PARM0); - s = VM_GetTempString(); if ((float)((int)v) == v) - sprintf(s, "%i", (int)v); + dpsnprintf(s, sizeof(s), "%i", (int)v); else - sprintf(s, "%f", v); - PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(s); + dpsnprintf(s, sizeof(s), "%f", v); + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(s); } /* @@ -647,13 +622,12 @@ string vtos(vector) void VM_vtos (void) { - char *s; + char s[512]; VM_SAFEPARMCOUNT(1,VM_vtos); - s = VM_GetTempString(); - sprintf (s, "'%5.1f %5.1f %5.1f'", PRVM_G_VECTOR(OFS_PARM0)[0], PRVM_G_VECTOR(OFS_PARM0)[1], PRVM_G_VECTOR(OFS_PARM0)[2]); - PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(s); + dpsnprintf (s, sizeof(s), "'%5.1f %5.1f %5.1f'", PRVM_G_VECTOR(OFS_PARM0)[0], PRVM_G_VECTOR(OFS_PARM0)[1], PRVM_G_VECTOR(OFS_PARM0)[2]); + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(s); } /* @@ -666,13 +640,12 @@ string etos(entity) void VM_etos (void) { - char *s; + char s[128]; VM_SAFEPARMCOUNT(1, VM_etos); - s = VM_GetTempString(); - sprintf (s, "entity %i", PRVM_G_EDICTNUM(OFS_PARM0)); - PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(s); + dpsnprintf (s, sizeof(s), "entity %i", PRVM_G_EDICTNUM(OFS_PARM0)); + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(s); } /* @@ -685,6 +658,7 @@ float stof(...[string]) void VM_stof(void) { char string[VM_STRINGTEMP_LENGTH]; + VM_SAFEPARMCOUNTRANGE(1, 8, VM_stof); VM_VarString(0, string, sizeof(string)); PRVM_G_FLOAT(OFS_RETURN) = atof(string); } @@ -721,6 +695,65 @@ void VM_ftoe(void) PRVM_G_INT(OFS_RETURN) = ent; } +/* +======================== +VM_etof + +float etof(entity ent) +======================== +*/ +void VM_etof(void) +{ + VM_SAFEPARMCOUNT(1, VM_etof); + PRVM_G_FLOAT(OFS_RETURN) = PRVM_G_EDICTNUM(OFS_PARM0); +} + +/* +========= +VM_strftime + +string strftime(float uselocaltime, string[, string ...]) +========= +*/ +void VM_strftime(void) +{ + time_t t; +#if _MSC_VER >= 1400 + struct tm tm; + int tmresult; +#else + struct tm *tm; +#endif + char fmt[VM_STRINGTEMP_LENGTH]; + char result[VM_STRINGTEMP_LENGTH]; + VM_SAFEPARMCOUNTRANGE(2, 8, VM_strftime); + VM_VarString(1, fmt, sizeof(fmt)); + t = time(NULL); +#if _MSC_VER >= 1400 + if (PRVM_G_FLOAT(OFS_PARM0)) + tmresult = localtime_s(&tm, &t); + else + tmresult = gmtime_s(&tm, &t); + if (!tmresult) +#else + if (PRVM_G_FLOAT(OFS_PARM0)) + tm = localtime(&t); + else + tm = gmtime(&t); + if (!tm) +#endif + { + PRVM_G_INT(OFS_RETURN) = 0; + return; + } +#if _MSC_VER >= 1400 + strftime(result, sizeof(result), fmt, &tm); +#else + strftime(result, sizeof(result), fmt, tm); +#endif + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(result); +} + /* ========= VM_spawn @@ -732,6 +765,7 @@ entity spawn() void VM_spawn (void) { prvm_edict_t *ed; + VM_SAFEPARMCOUNT(0, VM_spawn); prog->xfunction->builtinsprofile += 20; ed = PRVM_ED_Alloc(); VM_RETURN_EDICT(ed); @@ -765,10 +799,6 @@ void VM_remove (void) } else PRVM_ED_Free (ed); -// if (ed == prog->edicts) -// PRVM_ERROR ("remove: tried to remove world"); -// if (PRVM_NUM_FOR_EDICT(ed) <= sv.maxclients) -// Host_Error("remove: tried to remove a client"); } /* @@ -795,8 +825,6 @@ void VM_find (void) // LordHavoc: apparently BloodMage does a find(world, weaponmodel, "") and // expects it to find all the monsters, so we must be careful to support // searching for "" - if (!s) - s = ""; for (e++ ; e < prog->num_edicts ; e++) { @@ -868,17 +896,18 @@ void VM_findchain (void) { int i; int f; - int chain_of; const char *s, *t; prvm_edict_t *ent, *chain; + int chainfield; - VM_SAFEPARMCOUNT(2,VM_findchain); - - // is the same like !(prog->flag & PRVM_FE_CHAIN) - even if the operator precedence is another - if(!prog->flag & PRVM_FE_CHAIN) - PRVM_ERROR("VM_findchain: %s doesnt have a chain field !", PRVM_NAME); + VM_SAFEPARMCOUNTRANGE(2,3,VM_findchain); - chain_of = PRVM_ED_FindField("chain")->ofs; + if(prog->argc == 3) + chainfield = PRVM_G_INT(OFS_PARM2); + else + chainfield = prog->fieldoffsets.chain; + if (chainfield < 0) + PRVM_ERROR("VM_findchain: %s doesnt have the specified chain field !", PRVM_NAME); chain = prog->edicts; @@ -888,8 +917,6 @@ void VM_findchain (void) // LordHavoc: apparently BloodMage does a find(world, weaponmodel, "") and // expects it to find all the monsters, so we must be careful to support // searching for "" - if (!s) - s = ""; ent = PRVM_NEXT_EDICT(prog->edicts); for (i = 1;i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent)) @@ -903,7 +930,7 @@ void VM_findchain (void) if (strcmp(t,s)) continue; - PRVM_E_INT(ent,chain_of) = PRVM_NUM_FOR_EDICT(chain); + PRVM_EDICTFIELDVALUE(ent,chainfield)->edict = PRVM_NUM_FOR_EDICT(chain); chain = ent; } @@ -924,16 +951,18 @@ void VM_findchainfloat (void) { int i; int f; - int chain_of; float s; prvm_edict_t *ent, *chain; + int chainfield; - VM_SAFEPARMCOUNT(2, VM_findchainfloat); - - if(!prog->flag & PRVM_FE_CHAIN) - PRVM_ERROR("VM_findchainfloat: %s doesnt have a chain field !", PRVM_NAME); + VM_SAFEPARMCOUNTRANGE(2, 3, VM_findchainfloat); - chain_of = PRVM_ED_FindField("chain")->ofs; + if(prog->argc == 3) + chainfield = PRVM_G_INT(OFS_PARM2); + else + chainfield = prog->fieldoffsets.chain; + if (chainfield < 0) + PRVM_ERROR("VM_findchain: %s doesnt have the specified chain field !", PRVM_NAME); chain = (prvm_edict_t *)prog->edicts; @@ -949,7 +978,7 @@ void VM_findchainfloat (void) if (PRVM_E_FLOAT(ent,f) != s) continue; - PRVM_E_INT(ent,chain_of) = PRVM_EDICT_TO_PROG(chain); + PRVM_EDICTFIELDVALUE(ent,chainfield)->edict = PRVM_EDICT_TO_PROG(chain); chain = ent; } @@ -1009,15 +1038,17 @@ void VM_findchainflags (void) int i; int f; int s; - int chain_of; prvm_edict_t *ent, *chain; + int chainfield; - VM_SAFEPARMCOUNT(2, VM_findchainflags); - - if(!prog->flag & PRVM_FE_CHAIN) - PRVM_ERROR("VM_findchainflags: %s doesnt have a chain field !", PRVM_NAME); + VM_SAFEPARMCOUNTRANGE(2, 3, VM_findchainflags); - chain_of = PRVM_ED_FindField("chain")->ofs; + if(prog->argc == 3) + chainfield = PRVM_G_INT(OFS_PARM2); + else + chainfield = prog->fieldoffsets.chain; + if (chainfield < 0) + PRVM_ERROR("VM_findchain: %s doesnt have the specified chain field !", PRVM_NAME); chain = (prvm_edict_t *)prog->edicts; @@ -1035,13 +1066,53 @@ void VM_findchainflags (void) if (!((int)PRVM_E_FLOAT(ent,f) & s)) continue; - PRVM_E_INT(ent,chain_of) = PRVM_EDICT_TO_PROG(chain); + PRVM_EDICTFIELDVALUE(ent,chainfield)->edict = PRVM_EDICT_TO_PROG(chain); chain = ent; } VM_RETURN_EDICT(chain); } +/* +========= +VM_precache_sound + +string precache_sound (string sample) +========= +*/ +void VM_precache_sound (void) +{ + const char *s; + + VM_SAFEPARMCOUNT(1, VM_precache_sound); + + s = PRVM_G_STRING(OFS_PARM0); + PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0); + VM_CheckEmptyString(s); + + if(snd_initialized.integer && !S_PrecacheSound(s, true, true)) + { + VM_Warning("VM_precache_sound: Failed to load %s for %s\n", s, PRVM_NAME); + return; + } +} + +/* +================= +VM_precache_file + +returns the same string as output + +does nothing, only used by qcc to build .pak archives +================= +*/ +void VM_precache_file (void) +{ + VM_SAFEPARMCOUNT(1,VM_precache_file); + // precache_file is only used to copy files with qcc, it does nothing + PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0); +} + /* ========= VM_coredump @@ -1127,7 +1198,7 @@ void VM_eprint (void) { VM_SAFEPARMCOUNT(1,VM_eprint); - PRVM_ED_PrintNum (PRVM_G_EDICTNUM(OFS_PARM0)); + PRVM_ED_PrintNum (PRVM_G_EDICTNUM(OFS_PARM0), NULL); } /* @@ -1190,6 +1261,8 @@ void VM_nextent (void) int i; prvm_edict_t *ent; + VM_SAFEPARMCOUNT(1, VM_nextent); + i = PRVM_G_EDICTNUM(OFS_PARM0); while (1) { @@ -1221,8 +1294,6 @@ changelevel(string map) */ void VM_changelevel (void) { - const char *s; - VM_SAFEPARMCOUNT(1, VM_changelevel); if(!sv.active) @@ -1236,8 +1307,7 @@ void VM_changelevel (void) return; svs.changelevel_issued = true; - s = PRVM_G_STRING(OFS_PARM0); - Cbuf_AddText (va("changelevel %s\n",s)); + Cbuf_AddText (va("changelevel %s\n",PRVM_G_STRING(OFS_PARM0))); } /* @@ -1381,7 +1451,7 @@ void VM_randomvec (void) ========= VM_registercvar -float registercvar (string name, string value, float flags) +float registercvar (string name, string value[, float flags]) ========= */ void VM_registercvar (void) @@ -1389,11 +1459,11 @@ void VM_registercvar (void) const char *name, *value; int flags; - VM_SAFEPARMCOUNT(3,VM_registercvar); + VM_SAFEPARMCOUNTRANGE(2, 3, VM_registercvar); name = PRVM_G_STRING(OFS_PARM0); value = PRVM_G_STRING(OFS_PARM1); - flags = (int)PRVM_G_FLOAT(OFS_PARM2); + flags = prog->argc >= 3 ? (int)PRVM_G_FLOAT(OFS_PARM2) : 0; PRVM_G_FLOAT(OFS_RETURN) = 0; if(flags > CVAR_MAXFLAGSVAL) @@ -1410,11 +1480,12 @@ void VM_registercvar (void) return; } - Cvar_Get(name, value, flags); + Cvar_Get(name, value, flags, NULL); PRVM_G_FLOAT(OFS_RETURN) = 1; // success } + /* ================= VM_min @@ -1426,20 +1497,19 @@ float min(float a, float b, ...[float]) */ void VM_min (void) { + VM_SAFEPARMCOUNTRANGE(2, 8, VM_min); // LordHavoc: 3+ argument enhancement suggested by FrikaC - if (prog->argc == 2) - PRVM_G_FLOAT(OFS_RETURN) = min(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1)); - else if (prog->argc >= 3) + if (prog->argc >= 3) { int i; float f = PRVM_G_FLOAT(OFS_PARM0); for (i = 1;i < prog->argc;i++) - if (PRVM_G_FLOAT((OFS_PARM0+i*3)) < f) + if (f > PRVM_G_FLOAT((OFS_PARM0+i*3))) f = PRVM_G_FLOAT((OFS_PARM0+i*3)); PRVM_G_FLOAT(OFS_RETURN) = f; } else - PRVM_ERROR("VM_min: %s must supply at least 2 floats", PRVM_NAME); + PRVM_G_FLOAT(OFS_RETURN) = min(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1)); } /* @@ -1453,20 +1523,19 @@ float max(float a, float b, ...[float]) */ void VM_max (void) { + VM_SAFEPARMCOUNTRANGE(2, 8, VM_max); // LordHavoc: 3+ argument enhancement suggested by FrikaC - if (prog->argc == 2) - PRVM_G_FLOAT(OFS_RETURN) = max(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1)); - else if (prog->argc >= 3) + if (prog->argc >= 3) { int i; float f = PRVM_G_FLOAT(OFS_PARM0); for (i = 1;i < prog->argc;i++) - if (PRVM_G_FLOAT((OFS_PARM0+i*3)) > f) + if (f < PRVM_G_FLOAT((OFS_PARM0+i*3))) f = PRVM_G_FLOAT((OFS_PARM0+i*3)); PRVM_G_FLOAT(OFS_RETURN) = f; } else - PRVM_ERROR("VM_max: %s must supply at least 2 floats", PRVM_NAME); + PRVM_G_FLOAT(OFS_RETURN) = max(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1)); } /* @@ -1499,60 +1568,6 @@ void VM_pow (void) PRVM_G_FLOAT(OFS_RETURN) = pow(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1)); } -/* -================= -VM_copyentity - -copies data from one entity to another - -copyentity(entity src, entity dst) -================= -*/ -void VM_copyentity (void) -{ - prvm_edict_t *in, *out; - VM_SAFEPARMCOUNT(2,VM_copyentity); - in = PRVM_G_EDICT(OFS_PARM0); - out = PRVM_G_EDICT(OFS_PARM1); - memcpy(out->fields.vp, in->fields.vp, prog->progs->entityfields * 4); -} - -/* -================= -VM_setcolor - -sets the color of a client and broadcasts the update to all connected clients - -setcolor(clientent, value) -================= -*/ -/*void PF_setcolor (void) -{ - client_t *client; - int entnum, i; - prvm_eval_t *val; - - entnum = PRVM_G_EDICTNUM(OFS_PARM0); - i = PRVM_G_FLOAT(OFS_PARM1); - - if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active) - { - Con_Print("tried to setcolor a non-client\n"); - return; - } - - client = svs.clients + entnum-1; - if ((val = PRVM_GETEDICTFIELDVALUE(client->edict, eval_clientcolors))) - val->_float = i; - client->colors = i; - client->old_colors = i; - client->edict->fields.server->team = (i & 15) + 1; - - MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors); - MSG_WriteByte (&sv.reliable_datagram, entnum - 1); - MSG_WriteByte (&sv.reliable_datagram, i); -}*/ - void VM_Files_Init(void) { int i; @@ -1571,7 +1586,7 @@ void VM_Files_CloseAll(void) } } -qfile_t *VM_GetFileHandle( int index ) +static qfile_t *VM_GetFileHandle( int index ) { if (index < 0 || index >= PRVM_MAX_OPENFILES) { @@ -1612,28 +1627,29 @@ void VM_fopen(void) VM_Warning("VM_fopen: %s ran out of file handles (%i)\n", PRVM_NAME, PRVM_MAX_OPENFILES); return; } + filename = PRVM_G_STRING(OFS_PARM0); mode = (int)PRVM_G_FLOAT(OFS_PARM1); switch(mode) { case 0: // FILE_READ modestring = "rb"; + prog->openfiles[filenum] = FS_OpenVirtualFile(va("data/%s", filename), false); + if (prog->openfiles[filenum] == NULL) + prog->openfiles[filenum] = FS_OpenVirtualFile(va("%s", filename), false); break; case 1: // FILE_APPEND - modestring = "ab"; + modestring = "a"; + prog->openfiles[filenum] = FS_OpenRealFile(va("data/%s", filename), modestring, false); break; case 2: // FILE_WRITE - modestring = "wb"; + modestring = "w"; + prog->openfiles[filenum] = FS_OpenRealFile(va("data/%s", filename), modestring, false); break; default: PRVM_G_FLOAT(OFS_RETURN) = -3; VM_Warning("VM_fopen: %s: no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", PRVM_NAME, mode); return; } - filename = PRVM_G_STRING(OFS_PARM0); - - prog->openfiles[filenum] = FS_Open(va("data/%s", filename), modestring, false, false); - if (prog->openfiles[filenum] == NULL && mode == 0) - prog->openfiles[filenum] = FS_Open(va("%s", filename), modestring, false, false); if (prog->openfiles[filenum] == NULL) { @@ -1646,6 +1662,7 @@ void VM_fopen(void) PRVM_G_FLOAT(OFS_RETURN) = filenum; if (developer.integer >= 100) Con_Printf("VM_fopen: %s: %s mode %s opened as #%i\n", PRVM_NAME, filename, modestring, filenum); + prog->openfiles_origin[filenum] = PRVM_AllocationOrigin(); } } @@ -1676,6 +1693,8 @@ void VM_fclose(void) } FS_Close(prog->openfiles[filenum]); prog->openfiles[filenum] = NULL; + if(prog->openfiles_origin[filenum]) + PRVM_Free((char *)prog->openfiles_origin[filenum]); if (developer.integer >= 100) Con_Printf("VM_fclose: %s: #%i closed\n", PRVM_NAME, filenum); } @@ -1691,11 +1710,14 @@ string fgets(float fhandle) void VM_fgets(void) { int c, end; - static char string[VM_STRINGTEMP_LENGTH]; + char string[VM_STRINGTEMP_LENGTH]; int filenum; VM_SAFEPARMCOUNT(1,VM_fgets); + // set the return value regardless of any possible errors + PRVM_G_INT(OFS_RETURN) = OFS_NULL; + filenum = (int)PRVM_G_FLOAT(OFS_PARM0); if (filenum < 0 || filenum >= PRVM_MAX_OPENFILES) { @@ -1727,9 +1749,7 @@ void VM_fgets(void) if (developer.integer >= 100) Con_Printf("fgets: %s: %s\n", PRVM_NAME, string); if (c >= 0 || end) - PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(string); - else - PRVM_G_INT(OFS_RETURN) = 0; + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(string); } /* @@ -1768,155 +1788,287 @@ void VM_fputs(void) /* ========= -VM_strlen +VM_writetofile -float strlen(string s) + writetofile(float fhandle, entity ent) ========= */ -//float(string s) strlen = #114; // returns how many characters are in a string -void VM_strlen(void) +void VM_writetofile(void) { - const char *s; + prvm_edict_t * ent; + qfile_t *file; - VM_SAFEPARMCOUNT(1,VM_strlen); + VM_SAFEPARMCOUNT(2, VM_writetofile); - s = PRVM_G_STRING(OFS_PARM0); - if (s) - PRVM_G_FLOAT(OFS_RETURN) = strlen(s); - else - PRVM_G_FLOAT(OFS_RETURN) = 0; + file = VM_GetFileHandle( (int)PRVM_G_FLOAT(OFS_PARM0) ); + if( !file ) + { + VM_Warning("VM_writetofile: invalid or closed file handle\n"); + return; + } + + ent = PRVM_G_EDICT(OFS_PARM1); + if(ent->priv.required->free) + { + VM_Warning("VM_writetofile: %s: entity %i is free !\n", PRVM_NAME, PRVM_NUM_FOR_EDICT(ent)); + return; + } + + PRVM_ED_Write (file, ent); } -// DRESK - Decolorized String +// KrimZon - DP_QC_ENTITYDATA /* ========= -VM_strdecolorize +VM_numentityfields -string strdecolorize(string s) +float() numentityfields +Return the number of entity fields - NOT offsets ========= */ -// string (string s) strdecolorize = #472; // returns the passed in string with color codes stripped -void VM_strdecolorize(void) +void VM_numentityfields(void) { - char *szNewString; - const char *szString; - size_t nCnt; - int nPos; - int nFillPos; - int bFinished; - nPos = 0; - nFillPos = 0; - nCnt = 0; - bFinished = 0; + PRVM_G_FLOAT(OFS_RETURN) = prog->progs->numfielddefs; +} - // Prepare Strings - VM_SAFEPARMCOUNT(1,VM_strdecolorize); - szString = PRVM_G_STRING(OFS_PARM0); - szNewString = VM_GetTempString(); - - while(!bFinished) - { // Traverse through String - if( szString[nPos] == '\n' || szString[nPos] == '\r' || szString[nPos] <= 0) - { // String End Found - szNewString[nFillPos++] = szString[nPos]; - bFinished = 1; - } - else - if( szString[nPos] == STRING_COLOR_TAG) - { // Color Code Located - if( szString[nPos + 1] == STRING_COLOR_TAG) - { // Valid Characters to Include - szNewString[nFillPos++] = szString[nPos]; - nPos = nPos + 1; - szNewString[nFillPos++] = szString[nPos]; - } - else - if( szString[nPos + 1] >= '0' && szString[nPos + 1] <= '9' ) - { // Color Code Found; Increment Position - nPos = nPos + 1; - } - else - { // Unknown Color Code; Include - szNewString[nFillPos++] = szString[nPos]; - nPos = nPos + 1; - } - } - else - // Include Character - szNewString[nFillPos++] = szString[nPos]; +// KrimZon - DP_QC_ENTITYDATA +/* +========= +VM_entityfieldname - // Increment Position - nPos = nPos + 1; +string(float fieldnum) entityfieldname +Return name of the specified field as a string, or empty if the field is invalid (warning) +========= +*/ +void VM_entityfieldname(void) +{ + ddef_t *d; + int i = (int)PRVM_G_FLOAT(OFS_PARM0); + + if (i < 0 || i >= prog->progs->numfielddefs) + { + VM_Warning("VM_entityfieldname: %s: field index out of bounds\n", PRVM_NAME); + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(""); + return; } - - PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(szNewString); + + d = &prog->fielddefs[i]; + PRVM_G_INT(OFS_RETURN) = d->s_name; // presuming that s_name points to a string already } -// DRESK - String Length (not counting color codes) +// KrimZon - DP_QC_ENTITYDATA /* ========= -VM_strlennocol +VM_entityfieldtype -float strlennocol(string s) +float(float fieldnum) entityfieldtype ========= */ -// float(string s) strlennocol = #471; // returns how many characters are in a string not including color codes -// For example, ^2Dresk returns a length of 5 -void VM_strlennocol(void) +void VM_entityfieldtype(void) { - const char *szString; - size_t nCnt; - int nPos; - int bFinished; - nPos = 0; - nCnt = 0; - bFinished = 0; - - VM_SAFEPARMCOUNT(1,VM_strlennocol); - - szString = PRVM_G_STRING(OFS_PARM0); - if(szString) - { // Valid String - while(!bFinished) - { // Count Characters - // SV_BroadcastPrintf("Position '%d'; Character '%c'; Length '%d'\n", nPos, szString[nPos], nCnt); - - if( szString[nPos] == '\n' || szString[nPos] == '\r' || szString[nPos] <= 0) - { // String End Found - // SV_BroadcastPrintf("Found End of String at '%d'\n", nPos); - bFinished = 1; - } - else - if( szString[nPos] == STRING_COLOR_TAG) - { // Color Code Located - if( szString[nPos + 1] == STRING_COLOR_TAG) - { // Increment Length; Skip Color Code - nCnt = nCnt + 1; - nPos = nPos + 1; - } - else - if( szString[nPos + 1] >= '0' && szString[nPos + 1] <= '9' ) - { // Color Code Found; Increment Position - // SV_BroadcastPrintf("Found Color Codes at '%d'\n", nPos); - nPos = nPos + 1; - } - else - { // Unknown Color Code; Increment Length! - nPos = nPos + 1; - nCnt = nCnt + 1; - } - } - else - // Increment String Length - nCnt = nCnt + 1; + ddef_t *d; + int i = (int)PRVM_G_FLOAT(OFS_PARM0); + + if (i < 0 || i >= prog->progs->numfielddefs) + { + VM_Warning("VM_entityfieldtype: %s: field index out of bounds\n", PRVM_NAME); + PRVM_G_FLOAT(OFS_RETURN) = -1.0; + return; + } + + d = &prog->fielddefs[i]; + PRVM_G_FLOAT(OFS_RETURN) = (float)d->type; +} - // Increment Position - nPos = nPos + 1; - } - PRVM_G_FLOAT(OFS_RETURN) = nCnt; +// KrimZon - DP_QC_ENTITYDATA +/* +========= +VM_getentityfieldstring + +string(float fieldnum, entity ent) getentityfieldstring +========= +*/ +void VM_getentityfieldstring(void) +{ + // put the data into a string + ddef_t *d; + int type, j; + int *v; + prvm_edict_t * ent; + int i = (int)PRVM_G_FLOAT(OFS_PARM0); + + if (i < 0 || i >= prog->progs->numfielddefs) + { + VM_Warning("VM_entityfielddata: %s: field index out of bounds\n", PRVM_NAME); + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(""); + return; } - else - PRVM_G_FLOAT(OFS_RETURN) = 0; + + d = &prog->fielddefs[i]; + + // get the entity + ent = PRVM_G_EDICT(OFS_PARM1); + if(ent->priv.required->free) + { + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(""); + VM_Warning("VM_entityfielddata: %s: entity %i is free !\n", PRVM_NAME, PRVM_NUM_FOR_EDICT(ent)); + return; + } + v = (int *)((char *)ent->fields.vp + d->ofs*4); + + // if it's 0 or blank, return an empty string + type = d->type & ~DEF_SAVEGLOBAL; + for (j=0 ; jtype, (prvm_eval_t *)v)); +} + +// KrimZon - DP_QC_ENTITYDATA +/* +========= +VM_putentityfieldstring + +float(float fieldnum, entity ent, string s) putentityfieldstring +========= +*/ +void VM_putentityfieldstring(void) +{ + ddef_t *d; + prvm_edict_t * ent; + int i = (int)PRVM_G_FLOAT(OFS_PARM0); + + if (i < 0 || i >= prog->progs->numfielddefs) + { + VM_Warning("VM_entityfielddata: %s: field index out of bounds\n", PRVM_NAME); + PRVM_G_FLOAT(OFS_RETURN) = 0.0f; + return; + } + + d = &prog->fielddefs[i]; + + // get the entity + ent = PRVM_G_EDICT(OFS_PARM1); + if(ent->priv.required->free) + { + VM_Warning("VM_entityfielddata: %s: entity %i is free !\n", PRVM_NAME, PRVM_NUM_FOR_EDICT(ent)); + PRVM_G_FLOAT(OFS_RETURN) = 0.0f; + return; + } + + // parse the string into the value + PRVM_G_FLOAT(OFS_RETURN) = ( PRVM_ED_ParseEpair(ent, d, PRVM_G_STRING(OFS_PARM2), false) ) ? 1.0f : 0.0f; +} + +/* +========= +VM_strlen + +float strlen(string s) +========= +*/ +//float(string s) strlen = #114; // returns how many characters are in a string +void VM_strlen(void) +{ + VM_SAFEPARMCOUNT(1,VM_strlen); + + PRVM_G_FLOAT(OFS_RETURN) = strlen(PRVM_G_STRING(OFS_PARM0)); +} + +// DRESK - Decolorized String +/* +========= +VM_strdecolorize + +string strdecolorize(string s) +========= +*/ +// string (string s) strdecolorize = #472; // returns the passed in string with color codes stripped +void VM_strdecolorize(void) +{ + char szNewString[VM_STRINGTEMP_LENGTH]; + const char *szString; + + // Prepare Strings + VM_SAFEPARMCOUNT(1,VM_strdecolorize); + szString = PRVM_G_STRING(OFS_PARM0); + COM_StringDecolorize(szString, 0, szNewString, sizeof(szNewString), TRUE); + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(szNewString); +} + +// DRESK - String Length (not counting color codes) +/* +========= +VM_strlennocol + +float strlennocol(string s) +========= +*/ +// float(string s) strlennocol = #471; // returns how many characters are in a string not including color codes +// For example, ^2Dresk returns a length of 5 +void VM_strlennocol(void) +{ + const char *szString; + int nCnt; + + VM_SAFEPARMCOUNT(1,VM_strlennocol); + + szString = PRVM_G_STRING(OFS_PARM0); + + nCnt = COM_StringLengthNoColors(szString, 0, NULL); + + PRVM_G_FLOAT(OFS_RETURN) = nCnt; +} + +// DRESK - String to Uppercase and Lowercase +/* +========= +VM_strtolower + +string strtolower(string s) +========= +*/ +// string (string s) strtolower = #480; // returns passed in string in lowercase form +void VM_strtolower(void) +{ + char szNewString[VM_STRINGTEMP_LENGTH]; + const char *szString; + + // Prepare Strings + VM_SAFEPARMCOUNT(1,VM_strtolower); + szString = PRVM_G_STRING(OFS_PARM0); + + COM_ToLowerString(szString, szNewString, sizeof(szNewString) ); + + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(szNewString); +} + +/* +========= +VM_strtoupper + +string strtoupper(string s) +========= +*/ +// string (string s) strtoupper = #481; // returns passed in string in uppercase form +void VM_strtoupper(void) +{ + char szNewString[VM_STRINGTEMP_LENGTH]; + const char *szString; + + // Prepare Strings + VM_SAFEPARMCOUNT(1,VM_strtoupper); + szString = PRVM_G_STRING(OFS_PARM0); + + COM_ToUpperString(szString, szNewString, sizeof(szNewString) ); + + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(szNewString); } /* @@ -1931,14 +2083,11 @@ string strcat(string,string,...[string]) // and returns as a tempstring void VM_strcat(void) { - char *s; + char s[VM_STRINGTEMP_LENGTH]; + VM_SAFEPARMCOUNTRANGE(1, 8, VM_strcat); - if(prog->argc < 1) - PRVM_ERROR("VM_strcat wrong parameter count (min. 1 expected ) !"); - - s = VM_GetTempString(); - VM_VarString(0, s, VM_STRINGTEMP_LENGTH); - PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(s); + VM_VarString(0, s, sizeof(s)); + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(s); } /* @@ -1952,23 +2101,129 @@ string substring(string s, float start, float length) // returns a section of a string as a tempstring void VM_substring(void) { - int i, start, length; + int start, length, slength, maxlen; const char *s; - char *string; + char string[VM_STRINGTEMP_LENGTH]; VM_SAFEPARMCOUNT(3,VM_substring); - string = VM_GetTempString(); s = PRVM_G_STRING(OFS_PARM0); start = (int)PRVM_G_FLOAT(OFS_PARM1); length = (int)PRVM_G_FLOAT(OFS_PARM2); - if (!s) - s = ""; - for (i = 0;i < start && *s;i++, s++); - for (i = 0;i < VM_STRINGTEMP_LENGTH - 1 && *s && i < length;i++, s++) - string[i] = *s; - string[i] = 0; - PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(string); + slength = strlen(s); + + if (start < 0) // FTE_STRINGS feature + start += slength; + start = bound(0, start, slength); + + if (length < 0) // FTE_STRINGS feature + length += slength - start + 1; + maxlen = min((int)sizeof(string) - 1, slength - start); + length = bound(0, length, maxlen); + + memcpy(string, s + start, length); + string[length] = 0; + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(string); +} + +/* +========= +VM_strreplace + +string(string search, string replace, string subject) strreplace = #484; +========= +*/ +// replaces all occurrences of search with replace in the string subject, and returns the result +void VM_strreplace(void) +{ + int i, j, si; + const char *search, *replace, *subject; + char string[VM_STRINGTEMP_LENGTH]; + int search_len, replace_len, subject_len; + + VM_SAFEPARMCOUNT(3,VM_strreplace); + + search = PRVM_G_STRING(OFS_PARM0); + replace = PRVM_G_STRING(OFS_PARM1); + subject = PRVM_G_STRING(OFS_PARM2); + + search_len = (int)strlen(search); + replace_len = (int)strlen(replace); + subject_len = (int)strlen(subject); + + si = 0; + for (i = 0; i < subject_len; i++) + { + for (j = 0; j < search_len && i+j < subject_len; j++) + if (subject[i+j] != search[j]) + break; + if (j == search_len || i+j == subject_len) + { + // found it at offset 'i' + for (j = 0; j < replace_len && si < (int)sizeof(string) - 1; j++) + string[si++] = replace[j]; + i += search_len - 1; + } + else + { + // not found + if (si < (int)sizeof(string) - 1) + string[si++] = subject[i]; + } + } + string[si] = '\0'; + + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(string); +} + +/* +========= +VM_strireplace + +string(string search, string replace, string subject) strireplace = #485; +========= +*/ +// case-insensitive version of strreplace +void VM_strireplace(void) +{ + int i, j, si; + const char *search, *replace, *subject; + char string[VM_STRINGTEMP_LENGTH]; + int search_len, replace_len, subject_len; + + VM_SAFEPARMCOUNT(3,VM_strreplace); + + search = PRVM_G_STRING(OFS_PARM0); + replace = PRVM_G_STRING(OFS_PARM1); + subject = PRVM_G_STRING(OFS_PARM2); + + search_len = (int)strlen(search); + replace_len = (int)strlen(replace); + subject_len = (int)strlen(subject); + + si = 0; + for (i = 0; i < subject_len; i++) + { + for (j = 0; j < search_len && i+j < subject_len; j++) + if (tolower(subject[i+j]) != tolower(search[j])) + break; + if (j == search_len || i+j == subject_len) + { + // found it at offset 'i' + for (j = 0; j < replace_len && si < (int)sizeof(string) - 1; j++) + string[si++] = replace[j]; + i += search_len - 1; + } + else + { + // not found + if (si < (int)sizeof(string) - 1) + string[si++] = subject[i]; + } + } + string[si] = '\0'; + + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(string); } /* @@ -2065,30 +2320,145 @@ float tokenize(string s) //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 //20040203: rewritten by LordHavoc (no longer uses allocations) -int num_tokens = 0; -char *tokens[256], tokenbuf[MAX_INPUTLINE]; +static int num_tokens = 0; +static int tokens[VM_STRINGTEMP_LENGTH / 2]; +static int tokens_startpos[VM_STRINGTEMP_LENGTH / 2]; +static int tokens_endpos[VM_STRINGTEMP_LENGTH / 2]; +static char tokenize_string[VM_STRINGTEMP_LENGTH]; void VM_tokenize (void) { - size_t pos; const char *p; VM_SAFEPARMCOUNT(1,VM_tokenize); - p = PRVM_G_STRING(OFS_PARM0); + strlcpy(tokenize_string, PRVM_G_STRING(OFS_PARM0), sizeof(tokenize_string)); + p = tokenize_string; + + num_tokens = 0; + for(;;) + { + if (num_tokens >= (int)(sizeof(tokens)/sizeof(tokens[0]))) + break; + + // skip whitespace here to find token start pos + while(*p && ISWHITESPACE(*p)) + ++p; + + tokens_startpos[num_tokens] = p - tokenize_string; + if(!COM_ParseToken_VM_Tokenize(&p, false)) + break; + tokens_endpos[num_tokens] = p - tokenize_string; + tokens[num_tokens] = PRVM_SetTempString(com_token); + ++num_tokens; + } + + PRVM_G_FLOAT(OFS_RETURN) = num_tokens; +} + +//float(string s) tokenize = #514; // takes apart a string into individal words (access them with argv), returns how many +void VM_tokenize_console (void) +{ + const char *p; + + VM_SAFEPARMCOUNT(1,VM_tokenize); + + strlcpy(tokenize_string, PRVM_G_STRING(OFS_PARM0), sizeof(tokenize_string)); + p = tokenize_string; num_tokens = 0; - pos = 0; - while(COM_ParseToken(&p, false)) + for(;;) { - size_t tokenlen; if (num_tokens >= (int)(sizeof(tokens)/sizeof(tokens[0]))) break; - tokenlen = strlen(com_token) + 1; - if (pos + tokenlen > sizeof(tokenbuf)) + + // skip whitespace here to find token start pos + while(*p && ISWHITESPACE(*p)) + ++p; + + tokens_startpos[num_tokens] = p - tokenize_string; + if(!COM_ParseToken_Console(&p)) + break; + tokens_endpos[num_tokens] = p - tokenize_string; + tokens[num_tokens] = PRVM_SetTempString(com_token); + ++num_tokens; + } + + PRVM_G_FLOAT(OFS_RETURN) = num_tokens; +} + +/* +========= +VM_tokenizebyseparator + +float tokenizebyseparator(string s, string separator1, ...) +========= +*/ +//float(string s, string separator1, ...) tokenizebyseparator = #479; // takes apart a string into individal words (access them with argv), returns how many +//this function returns the token preceding each instance of a separator (of +//which there can be multiple), and the text following the last separator +//useful for parsing certain kinds of data like IP addresses +//example: +//numnumbers = tokenizebyseparator("10.1.2.3", "."); +//returns 4 and the tokens "10" "1" "2" "3". +void VM_tokenizebyseparator (void) +{ + int j, k; + int numseparators; + int separatorlen[7]; + const char *separators[7]; + const char *p, *p0; + const char *token; + char tokentext[MAX_INPUTLINE]; + + VM_SAFEPARMCOUNTRANGE(2, 8,VM_tokenizebyseparator); + + strlcpy(tokenize_string, PRVM_G_STRING(OFS_PARM0), sizeof(tokenize_string)); + p = tokenize_string; + + numseparators = 0; + for (j = 1;j < prog->argc;j++) + { + // skip any blank separator strings + const char *s = PRVM_G_STRING(OFS_PARM0+j*3); + if (!s[0]) + continue; + separators[numseparators] = s; + separatorlen[numseparators] = strlen(s); + numseparators++; + } + + num_tokens = 0; + j = 0; + + while (num_tokens < (int)(sizeof(tokens)/sizeof(tokens[0]))) + { + token = tokentext + j; + tokens_startpos[num_tokens] = p - tokenize_string; + p0 = p; + while (*p) + { + for (k = 0;k < numseparators;k++) + { + if (!strncmp(p, separators[k], separatorlen[k])) + { + p += separatorlen[k]; + break; + } + } + if (k < numseparators) + break; + if (j < (int)sizeof(tokentext)-1) + tokentext[j++] = *p; + p++; + p0 = p; + } + tokens_endpos[num_tokens] = p0 - tokenize_string; + if (j >= (int)sizeof(tokentext)) + break; + tokentext[j++] = 0; + tokens[num_tokens++] = PRVM_SetTempString(token); + if (!*p) break; - tokens[num_tokens++] = tokenbuf + pos; - memcpy(tokenbuf + pos, com_token, tokenlen); - pos += tokenlen; } PRVM_G_FLOAT(OFS_RETURN) = num_tokens; @@ -2104,55 +2474,50 @@ void VM_argv (void) token_num = (int)PRVM_G_FLOAT(OFS_PARM0); + if(token_num < 0) + token_num += num_tokens; + if (token_num >= 0 && token_num < num_tokens) - PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(tokens[token_num]); + PRVM_G_INT(OFS_RETURN) = tokens[token_num]; else - PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(NULL); + PRVM_G_INT(OFS_RETURN) = OFS_NULL; } -/* -//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) +//float(float n) argv_start_index = #515; // returns the start index of a token +void VM_argv_start_index (void) { - prvm_edict_t *e = PRVM_G_EDICT(OFS_PARM0); - prvm_edict_t *tagentity = PRVM_G_EDICT(OFS_PARM1); - char *tagname = PRVM_G_STRING(OFS_PARM2); - prvm_eval_t *v; - int i, modelindex; - model_t *model; + int token_num; - if (tagentity == NULL) - tagentity = prog->edicts; + VM_SAFEPARMCOUNT(1,VM_argv); - v = PRVM_GETEDICTFIELDVALUE(e, eval_tag_entity); - if (v) - fields.server->edict = PRVM_EDICT_TO_PROG(tagentity); + token_num = (int)PRVM_G_FLOAT(OFS_PARM0); - v = PRVM_GETEDICTFIELDVALUE(e, eval_tag_index); - if (v) - fields.server->_float = 0; - if (tagentity != NULL && tagentity != prog->edicts && tagname && tagname[0]) - { - modelindex = (int)tagentity->fields.server->modelindex; - if (modelindex >= 0 && modelindex < MAX_MODELS) - { - model = sv.models[modelindex]; - if (model->data_overridetagnamesforskin && (unsigned int)tagentity->fields.server->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)tagentity->fields.server->skin].num_overridetagnames) - for (i = 0;i < model->data_overridetagnamesforskin[(unsigned int)tagentity->fields.server->skin].num_overridetagnames;i++) - if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)tagentity->fields.server->skin].data_overridetagnames[i].name)) - fields.server->_float = i + 1; - // FIXME: use a model function to get tag info (need to handle skeletal) - if (fields.server->_float == 0 && model->num_tags) - for (i = 0;i < model->num_tags;i++) - if (!strcmp(tagname, model->data_tags[i].name)) - fields.server->_float = i + 1; - if (fields.server->_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", PRVM_NUM_FOR_EDICT(e), PRVM_NUM_FOR_EDICT(tagentity), tagname, tagname, PRVM_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", PRVM_NUM_FOR_EDICT(e), PRVM_NUM_FOR_EDICT(tagentity), tagname, tagname, PRVM_NUM_FOR_EDICT(tagentity)); - } -}*/ + if(token_num < 0) + token_num += num_tokens; + + if (token_num >= 0 && token_num < num_tokens) + PRVM_G_FLOAT(OFS_RETURN) = tokens_startpos[token_num]; + else + PRVM_G_FLOAT(OFS_RETURN) = -1; +} + +//float(float n) argv_end_index = #516; // returns the end index of a token +void VM_argv_end_index (void) +{ + int token_num; + + VM_SAFEPARMCOUNT(1,VM_argv); + + token_num = (int)PRVM_G_FLOAT(OFS_PARM0); + + if(token_num < 0) + token_num += num_tokens; + + if (token_num >= 0 && token_num < num_tokens) + PRVM_G_FLOAT(OFS_RETURN) = tokens_endpos[token_num]; + else + PRVM_G_FLOAT(OFS_RETURN) = -1; +} /* ========= @@ -2165,7 +2530,7 @@ void VM_isserver(void) { VM_SAFEPARMCOUNT(0,VM_serverstate); - PRVM_G_FLOAT(OFS_RETURN) = sv.active; + PRVM_G_FLOAT(OFS_RETURN) = sv.active && (svs.maxclients > 1 || cls.state == ca_dedicated); } /* @@ -2193,11 +2558,26 @@ void VM_clientstate(void) { VM_SAFEPARMCOUNT(0,VM_clientstate); - PRVM_G_FLOAT(OFS_RETURN) = cls.state; -} -/* -========= + switch( cls.state ) { + case ca_uninitialized: + case ca_dedicated: + PRVM_G_FLOAT(OFS_RETURN) = 0; + break; + case ca_disconnected: + PRVM_G_FLOAT(OFS_RETURN) = 1; + break; + case ca_connected: + PRVM_G_FLOAT(OFS_RETURN) = 2; + break; + default: + // should never be reached! + break; + } +} + +/* +========= VM_getostype float getostype(void) @@ -2222,23 +2602,6 @@ void VM_getostype(void) #endif } -/* -========= -VM_getmousepos - -vector getmousepos() -========= -*/ -void VM_getmousepos(void) -{ - - VM_SAFEPARMCOUNT(0,VM_getmousepos); - - PRVM_G_VECTOR(OFS_RETURN)[0] = in_mouse_x * vid_conwidth.integer / vid.width; - PRVM_G_VECTOR(OFS_RETURN)[1] = in_mouse_y * vid_conheight.integer / vid.height; - PRVM_G_VECTOR(OFS_RETURN)[2] = 0; -} - /* ========= VM_gettime @@ -2246,11 +2609,44 @@ VM_gettime float gettime(void) ========= */ +extern double host_starttime; +float CDAudio_GetPosition(void); void VM_gettime(void) { - VM_SAFEPARMCOUNT(0,VM_gettime); + int timer_index; - PRVM_G_FLOAT(OFS_RETURN) = (float) *prog->time; + VM_SAFEPARMCOUNTRANGE(0,1,VM_gettime); + + if(prog->argc == 0) + { + PRVM_G_FLOAT(OFS_RETURN) = (float) realtime; + } + else + { + timer_index = (int) PRVM_G_FLOAT(OFS_PARM0); + switch(timer_index) + { + case 0: // GETTIME_FRAMESTART + PRVM_G_FLOAT(OFS_RETURN) = (float) realtime; + break; + case 1: // GETTIME_REALTIME + PRVM_G_FLOAT(OFS_RETURN) = (float) Sys_DoubleTime(); + break; + case 2: // GETTIME_HIRES + PRVM_G_FLOAT(OFS_RETURN) = (float) (Sys_DoubleTime() - realtime); + break; + case 3: // GETTIME_UPTIME + PRVM_G_FLOAT(OFS_RETURN) = (float) (Sys_DoubleTime() - host_starttime); + break; + case 4: // GETTIME_CDTRACK + PRVM_G_FLOAT(OFS_RETURN) = (float) CDAudio_GetPosition(); + break; + default: + VM_Warning("VM_gettime: %s: unsupported timer specified, returning realtime\n", PRVM_NAME); + PRVM_G_FLOAT(OFS_RETURN) = (float) realtime; + break; + } + } } /* @@ -2281,15 +2677,15 @@ void VM_parseentitydata(void) VM_SAFEPARMCOUNT(2, VM_parseentitydata); - // get edict and test it + // get edict and test it ent = PRVM_G_EDICT(OFS_PARM0); if (ent->priv.required->free) PRVM_ERROR ("VM_parseentitydata: %s: Can only set already spawned entities (entity %i is free)!", PRVM_NAME, PRVM_NUM_FOR_EDICT(ent)); data = PRVM_G_STRING(OFS_PARM1); - // parse the opening brace - if (!COM_ParseTokenConsole(&data) || com_token[0] != '{' ) + // parse the opening brace + if (!COM_ParseToken_Simple(&data, false, false) || com_token[0] != '{' ) PRVM_ERROR ("VM_parseentitydata: %s: Couldn't parse entity data:\n%s", PRVM_NAME, data ); PRVM_ED_ParseEdict (data, ent); @@ -2310,11 +2706,7 @@ void VM_loadfromfile(void) VM_SAFEPARMCOUNT(1,VM_loadfromfile); filename = PRVM_G_STRING(OFS_PARM0); - // .. is parent directory on many platforms - // / is parent directory on Amiga - // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea) - // \ is a windows-ism (so it's naughty to use it, / works on all platforms) - if ((filename[0] == '.' && filename[1] == '.') || filename[0] == '/' || strrchr(filename, ':') || strrchr(filename, '\\')) + if (FS_CheckNastyPath(filename, false)) { PRVM_G_FLOAT(OFS_RETURN) = -4; VM_Warning("VM_loadfromfile: %s dangerous or non-portable filename \"%s\" not allowed. (contains : or \\ or begins with .. or /)\n", PRVM_NAME, filename); @@ -2406,7 +2798,10 @@ void VM_search_begin(void) if(!(prog->opensearches[handle] = FS_Search(pattern,caseinsens, quiet))) PRVM_G_FLOAT(OFS_RETURN) = -1; else + { + prog->opensearches_origin[handle] = PRVM_AllocationOrigin(); PRVM_G_FLOAT(OFS_RETURN) = handle; + } } /* @@ -2436,6 +2831,8 @@ void VM_search_end(void) FS_FreeSearch(prog->opensearches[handle]); prog->opensearches[handle] = NULL; + if(prog->opensearches_origin[handle]) + PRVM_Free((char *)prog->opensearches_origin[handle]); } /* @@ -2476,7 +2873,6 @@ string search_getfilename(float handle, float num) void VM_search_getfilename(void) { int handle, filenum; - char *tmp; VM_SAFEPARMCOUNT(2, VM_search_getfilename); handle = (int)PRVM_G_FLOAT(OFS_PARM0); @@ -2498,10 +2894,7 @@ void VM_search_getfilename(void) return; } - tmp = VM_GetTempString(); - strlcpy(tmp, prog->opensearches[handle]->filenames[filenum], VM_STRINGTEMP_LENGTH); - - PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(tmp); + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog->opensearches[handle]->filenames[filenum]); } /* @@ -2513,14 +2906,13 @@ string chr(float ascii) */ void VM_chr(void) { - char *tmp; + char tmp[2]; VM_SAFEPARMCOUNT(1, VM_chr); - tmp = VM_GetTempString(); tmp[0] = (unsigned char) PRVM_G_FLOAT(OFS_PARM0); tmp[1] = 0; - PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(tmp); + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(tmp); } //============================================================================= @@ -2556,15 +2948,11 @@ void VM_precache_pic(void) s = PRVM_G_STRING(OFS_PARM0); PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0); - - if(!s) - PRVM_ERROR ("VM_precache_pic: %s: NULL", PRVM_NAME); - VM_CheckEmptyString (s); // AK Draw_CachePic is supposed to always return a valid pointer - if( Draw_CachePic(s, false)->tex == r_texture_notexture ) - PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(NULL); + if( Draw_CachePic_Flags(s, CACHEPICFLAG_NOTPERSISTENT)->tex == r_texture_notexture ) + PRVM_G_INT(OFS_RETURN) = OFS_NULL; } /* @@ -2581,15 +2969,24 @@ void VM_freepic(void) VM_SAFEPARMCOUNT(1,VM_freepic); s = PRVM_G_STRING(OFS_PARM0); - - if(!s) - PRVM_ERROR ("VM_freepic: %s: NULL"); - VM_CheckEmptyString (s); Draw_FreePic(s); } +dp_font_t *getdrawfont() +{ + if(prog->globaloffsets.drawfont >= 0) + { + int f = (int) PRVM_G_FLOAT(prog->globaloffsets.drawfont); + if(f < 0 || f >= MAX_FONTS) + return FONT_DEFAULT; + return &dp_fonts[f]; + } + else + return FONT_DEFAULT; +} + /* ========= VM_drawcharacter @@ -2634,7 +3031,7 @@ void VM_drawcharacter(void) return; } - DrawQ_String (pos[0], pos[1], &character, 1, scale[0], scale[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM4), flag); + DrawQ_String_Font(pos[0], pos[1], &character, 1, scale[0], scale[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM4), flag, NULL, true, getdrawfont()); PRVM_G_FLOAT(OFS_RETURN) = 1; } @@ -2653,15 +3050,6 @@ void VM_drawstring(void) VM_SAFEPARMCOUNT(6,VM_drawstring); string = PRVM_G_STRING(OFS_PARM1); - if(!string) - { - PRVM_G_FLOAT(OFS_RETURN) = -1; - VM_Warning("VM_drawstring: %s passed null string !\n",PRVM_NAME); - return; - } - - //VM_CheckEmptyString(string); Why should it be checked - perhaps the menu wants to support the precolored letters, too? - pos = PRVM_G_VECTOR(OFS_PARM0); scale = PRVM_G_VECTOR(OFS_PARM2); rgb = PRVM_G_VECTOR(OFS_PARM3); @@ -2684,11 +3072,70 @@ void VM_drawstring(void) if(pos[2] || scale[2]) Con_Printf("VM_drawstring: z value%s from %s discarded\n",(pos[2] && scale[2]) ? "s" : " ",((pos[2] && scale[2]) ? "pos and scale" : (pos[2] ? "pos" : "scale"))); - DrawQ_String (pos[0], pos[1], string, 0, scale[0], scale[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM4), flag); + DrawQ_String_Font(pos[0], pos[1], string, 0, scale[0], scale[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM4), flag, NULL, true, getdrawfont()); + PRVM_G_FLOAT(OFS_RETURN) = 1; +} + +/* +========= +VM_drawcolorcodedstring + +float drawcolorcodedstring(vector position, string text, vector scale, float alpha, float flag) +========= +*/ +void VM_drawcolorcodedstring(void) +{ + float *pos,*scale; + const char *string; + int flag,color; + VM_SAFEPARMCOUNT(5,VM_drawstring); + + string = PRVM_G_STRING(OFS_PARM1); + pos = PRVM_G_VECTOR(OFS_PARM0); + scale = PRVM_G_VECTOR(OFS_PARM2); + flag = (int)PRVM_G_FLOAT(OFS_PARM4); + + if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS) + { + PRVM_G_FLOAT(OFS_RETURN) = -2; + VM_Warning("VM_drawcolorcodedstring: %s: wrong DRAWFLAG %i !\n",PRVM_NAME,flag); + return; + } + + if(!scale[0] || !scale[1]) + { + PRVM_G_FLOAT(OFS_RETURN) = -3; + VM_Warning("VM_drawcolorcodedstring: scale %s is null !\n", (scale[0] == 0) ? ((scale[1] == 0) ? "x and y" : "x") : "y"); + return; + } + + if(pos[2] || scale[2]) + Con_Printf("VM_drawcolorcodedstring: z value%s from %s discarded\n",(pos[2] && scale[2]) ? "s" : " ",((pos[2] && scale[2]) ? "pos and scale" : (pos[2] ? "pos" : "scale"))); + + color = -1; + DrawQ_String_Font(pos[0], pos[1], string, 0, scale[0], scale[1], 1, 1, 1, PRVM_G_FLOAT(OFS_PARM3), flag, NULL, false, getdrawfont()); PRVM_G_FLOAT(OFS_RETURN) = 1; } /* ========= +VM_stringwidth + +float stringwidth(string text, float allowColorCodes) +========= +*/ +void VM_stringwidth(void) +{ + const char *string; + int colors; + VM_SAFEPARMCOUNT(2,VM_drawstring); + + string = PRVM_G_STRING(OFS_PARM0); + colors = (int)PRVM_G_FLOAT(OFS_PARM1); + + PRVM_G_FLOAT(OFS_RETURN) = DrawQ_TextWidth_Font(string, 0, !colors, getdrawfont()); // 1x1 characters, don't actually draw +} +/* +========= VM_drawpic float drawpic(vector position, string pic, vector size, vector rgb, float alpha, float flag) @@ -2703,14 +3150,6 @@ void VM_drawpic(void) VM_SAFEPARMCOUNT(6,VM_drawpic); picname = PRVM_G_STRING(OFS_PARM1); - - if(!picname) - { - PRVM_G_FLOAT(OFS_RETURN) = -1; - VM_Warning("VM_drawpic: %s passed null picture name !\n", PRVM_NAME); - return; - } - VM_CheckEmptyString (picname); // is pic cached ? no function yet for that @@ -2736,7 +3175,106 @@ void VM_drawpic(void) if(pos[2] || size[2]) Con_Printf("VM_drawpic: z value%s from %s discarded\n",(pos[2] && size[2]) ? "s" : " ",((pos[2] && size[2]) ? "pos and size" : (pos[2] ? "pos" : "size"))); - DrawQ_Pic(pos[0], pos[1], Draw_CachePic(picname, true), size[0], size[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM4), flag); + DrawQ_Pic(pos[0], pos[1], Draw_CachePic (picname), size[0], size[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM4), flag); + PRVM_G_FLOAT(OFS_RETURN) = 1; +} +/* +========= +VM_drawrotpic + +float drawrotpic(vector position, string pic, vector size, vector org, float angle, vector rgb, float alpha, float flag) +========= +*/ +void VM_drawrotpic(void) +{ + const char *picname; + float *size, *pos, *org, *rgb; + int flag; + + VM_SAFEPARMCOUNT(8,VM_drawrotpic); + + picname = PRVM_G_STRING(OFS_PARM1); + VM_CheckEmptyString (picname); + + // is pic cached ? no function yet for that + if(!1) + { + PRVM_G_FLOAT(OFS_RETURN) = -4; + VM_Warning("VM_drawrotpic: %s: %s not cached !\n", PRVM_NAME, picname); + return; + } + + pos = PRVM_G_VECTOR(OFS_PARM0); + size = PRVM_G_VECTOR(OFS_PARM2); + org = PRVM_G_VECTOR(OFS_PARM3); + rgb = PRVM_G_VECTOR(OFS_PARM5); + flag = (int) PRVM_G_FLOAT(OFS_PARM7); + + if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS) + { + PRVM_G_FLOAT(OFS_RETURN) = -2; + VM_Warning("VM_drawrotpic: %s: wrong DRAWFLAG %i !\n",PRVM_NAME,flag); + return; + } + + if(pos[2] || size[2] || org[2]) + Con_Printf("VM_drawrotpic: z value from pos/size/org discarded\n"); + + DrawQ_RotPic(pos[0], pos[1], Draw_CachePic(picname), size[0], size[1], org[0], org[1], PRVM_G_FLOAT(OFS_PARM4), rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM6), flag); + PRVM_G_FLOAT(OFS_RETURN) = 1; +} +/* +========= +VM_drawsubpic + +float drawsubpic(vector position, vector size, string pic, vector srcPos, vector srcSize, vector rgb, float alpha, float flag) + +========= +*/ +void VM_drawsubpic(void) +{ + const char *picname; + float *size, *pos, *rgb, *srcPos, *srcSize, alpha; + int flag; + + VM_SAFEPARMCOUNT(8,VM_drawsubpic); + + picname = PRVM_G_STRING(OFS_PARM2); + VM_CheckEmptyString (picname); + + // is pic cached ? no function yet for that + if(!1) + { + PRVM_G_FLOAT(OFS_RETURN) = -4; + VM_Warning("VM_drawsubpic: %s: %s not cached !\n", PRVM_NAME, picname); + return; + } + + pos = PRVM_G_VECTOR(OFS_PARM0); + size = PRVM_G_VECTOR(OFS_PARM1); + srcPos = PRVM_G_VECTOR(OFS_PARM3); + srcSize = PRVM_G_VECTOR(OFS_PARM4); + rgb = PRVM_G_VECTOR(OFS_PARM5); + alpha = PRVM_G_FLOAT(OFS_PARM6); + flag = (int) PRVM_G_FLOAT(OFS_PARM7); + + if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS) + { + PRVM_G_FLOAT(OFS_RETURN) = -2; + VM_Warning("VM_drawsubpic: %s: wrong DRAWFLAG %i !\n",PRVM_NAME,flag); + return; + } + + if(pos[2] || size[2]) + Con_Printf("VM_drawsubpic: z value%s from %s discarded\n",(pos[2] && size[2]) ? "s" : " ",((pos[2] && size[2]) ? "pos and size" : (pos[2] ? "pos" : "size"))); + + DrawQ_SuperPic(pos[0], pos[1], Draw_CachePic (picname), + size[0], size[1], + srcPos[0], srcPos[1], rgb[0], rgb[1], rgb[2], alpha, + srcPos[0] + srcSize[0], srcPos[1], rgb[0], rgb[1], rgb[2], alpha, + srcPos[0], srcPos[1] + srcSize[1], rgb[0], rgb[1], rgb[2], alpha, + srcPos[0] + srcSize[0], srcPos[1] + srcSize[1], rgb[0], rgb[1], rgb[2], alpha, + flag); PRVM_G_FLOAT(OFS_RETURN) = 1; } @@ -2770,7 +3308,7 @@ void VM_drawfill(void) if(pos[2] || size[2]) Con_Printf("VM_drawfill: z value%s from %s discarded\n",(pos[2] && size[2]) ? "s" : " ",((pos[2] && size[2]) ? "pos and size" : (pos[2] ? "pos" : "size"))); - DrawQ_Pic(pos[0], pos[1], NULL, size[0], size[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM3), flag); + DrawQ_Fill(pos[0], pos[1], size[0], size[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM3), flag); PRVM_G_FLOAT(OFS_RETURN) = 1; } @@ -2823,13 +3361,9 @@ void VM_getimagesize(void) VM_SAFEPARMCOUNT(1,VM_getimagesize); p = PRVM_G_STRING(OFS_PARM0); - - if(!p) - PRVM_ERROR("VM_getimagepos: %s passed null picture name !", PRVM_NAME); - VM_CheckEmptyString (p); - pic = Draw_CachePic (p, false); + pic = Draw_CachePic_Flags (p, CACHEPICFLAG_NOTPERSISTENT); PRVM_G_VECTOR(OFS_RETURN)[0] = pic->width; PRVM_G_VECTOR(OFS_RETURN)[1] = pic->height; @@ -2845,17 +3379,43 @@ string keynumtostring(float keynum) */ void VM_keynumtostring (void) { - int keynum; - char *tmp; VM_SAFEPARMCOUNT(1, VM_keynumtostring); - keynum = (int)PRVM_G_FLOAT(OFS_PARM0); + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(Key_KeynumToString((int)PRVM_G_FLOAT(OFS_PARM0))); +} + +/* +========= +VM_findkeysforcommand + +string findkeysforcommand(string command) + +the returned string is an altstring +========= +*/ +#define NUMKEYS 5 // TODO: merge the constant in keys.c with this one somewhen + +void M_FindKeysForCommand(const char *command, int *keys); +void VM_findkeysforcommand(void) +{ + const char *cmd; + char ret[VM_STRINGTEMP_LENGTH]; + int keys[NUMKEYS]; + int i; + + VM_SAFEPARMCOUNT(1, VM_findkeysforcommand); + + cmd = PRVM_G_STRING(OFS_PARM0); + + VM_CheckEmptyString(cmd); - tmp = VM_GetTempString(); + M_FindKeysForCommand(cmd, keys); - strlcpy(tmp, Key_KeynumToString(keynum), VM_STRINGTEMP_LENGTH); + ret[0] = 0; + for(i = 0; i < NUMKEYS; i++) + strlcat(ret, va(" \'%i\'", keys[i]), sizeof(ret)); - PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(tmp); + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(ret); } /* @@ -2867,12 +3427,9 @@ float stringtokeynum(string key) */ void VM_stringtokeynum (void) { - const char *str; VM_SAFEPARMCOUNT( 1, VM_keynumtostring ); - str = PRVM_G_STRING( OFS_PARM0 ); - - PRVM_G_INT(OFS_RETURN) = Key_StringToKeynum( str ); + PRVM_G_INT(OFS_RETURN) = Key_StringToKeynum(PRVM_G_STRING(OFS_PARM0)); } // CL_Video interface functions @@ -2993,303 +3550,315 @@ void VM_cin_restart( void ) } /* -============== -VM_vectorvectors - -Writes new values for v_forward, v_up, and v_right based on the given forward vector -vectorvectors(vector, vector) -============== +======================== +VM_Gecko_Init +======================== */ -void VM_vectorvectors (void) -{ - VectorNormalize2(PRVM_G_VECTOR(OFS_PARM0), prog->globals.server->v_forward); - VectorVectors(prog->globals.server->v_forward, prog->globals.server->v_right, prog->globals.server->v_up); +void VM_Gecko_Init( void ) { + // the prog struct is memset to 0 by Initprog? [12/6/2007 Black] + // FIXME: remove the other _Init functions then, too? [12/6/2007 Black] } /* ======================== -VM_drawline - -void drawline(float width, vector pos1, vector pos2, vector rgb, float alpha, float flags) +VM_Gecko_Destroy ======================== */ -void VM_drawline (void) -{ - float *c1, *c2, *rgb; - float alpha, width; - unsigned char flags; - - VM_SAFEPARMCOUNT(6, VM_drawline); - width = PRVM_G_FLOAT(OFS_PARM0); - c1 = PRVM_G_VECTOR(OFS_PARM1); - c2 = PRVM_G_VECTOR(OFS_PARM2); - rgb = PRVM_G_VECTOR(OFS_PARM3); - alpha = PRVM_G_FLOAT(OFS_PARM4); - flags = (int)PRVM_G_FLOAT(OFS_PARM5); - DrawQ_Line(width, c1[0], c1[1], c2[0], c2[1], rgb[0], rgb[1], rgb[2], alpha, flags); +void VM_Gecko_Destroy( void ) { + int i; + for( i = 0 ; i < PRVM_MAX_GECKOINSTANCES ; i++ ) { + clgecko_t **instance = &prog->opengeckoinstances[ i ]; + if( *instance ) { + CL_Gecko_DestroyBrowser( *instance ); + } + *instance = NULL; + } } -//==================== -//QC POLYGON functions -//==================== - -typedef struct -{ - rtexture_t *tex; - float data[36]; //[515]: enough for polygons - unsigned char flags; //[515]: + VM_POLYGON_2D and VM_POLYGON_FL4V flags -}vm_polygon_t; - -//static float vm_polygon_linewidth = 1; -static mempool_t *vm_polygons_pool = NULL; -static unsigned char vm_current_vertices = 0; -static qboolean vm_polygons_initialized = false; -static vm_polygon_t *vm_polygons = NULL; -static unsigned long vm_polygons_num = 0, vm_drawpolygons_num = 0; //[515]: ok long on 64bit ? -static qboolean vm_polygonbegin = false; //[515]: for "no-crap-on-the-screen" check -#define VM_DEFPOLYNUM 64 //[515]: enough for default ? - -#define VM_POLYGON_FL3V 16 //more than 2 vertices (used only for lines) -#define VM_POLYGON_FLLINES 32 -#define VM_POLYGON_FL2D 64 -#define VM_POLYGON_FL4V 128 //4 vertices - -void VM_InitPolygons (void) -{ - vm_polygons_pool = Mem_AllocPool("VMPOLY", 0, NULL); - vm_polygons = (vm_polygon_t *)Mem_Alloc(vm_polygons_pool, VM_DEFPOLYNUM*sizeof(vm_polygon_t)); - memset(vm_polygons, 0, VM_DEFPOLYNUM*sizeof(vm_polygon_t)); - vm_polygons_num = VM_DEFPOLYNUM; - vm_drawpolygons_num = 0; - vm_polygonbegin = false; - vm_polygons_initialized = true; -} - -void VM_DrawPolygonCallback (const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist) -{ - int surfacelistindex; - // LordHavoc: FIXME: this is stupid code - for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++) - { - const vm_polygon_t *p = &vm_polygons[surfacelist[surfacelistindex]]; - int flags = p->flags & 0x0f; - - if(flags == DRAWFLAG_ADDITIVE) - GL_BlendFunc(GL_SRC_ALPHA, GL_ONE); - else if(flags == DRAWFLAG_MODULATE) - GL_BlendFunc(GL_DST_COLOR, GL_ZERO); - else if(flags == DRAWFLAG_2XMODULATE) - GL_BlendFunc(GL_DST_COLOR,GL_SRC_COLOR); - else - GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - R_Mesh_TexBind(0, R_GetTexture(p->tex)); +/* +======================== +VM_gecko_create - CHECKGLERROR - //[515]: is speed is max ? - if(p->flags & VM_POLYGON_FLLINES) //[515]: lines - { - qglLineWidth(p->data[13]);CHECKGLERROR - qglBegin(GL_LINE_LOOP); - qglTexCoord1f (p->data[12]); - qglColor4f (p->data[20], p->data[21], p->data[22], p->data[23]); - qglVertex3f (p->data[0] , p->data[1], p->data[2]); +float[bool] gecko_create( string name ) +======================== +*/ +void VM_gecko_create( void ) { + const char *name; + int i; + clgecko_t *instance; + + VM_SAFEPARMCOUNT( 1, VM_gecko_create ); - qglTexCoord1f (p->data[14]); - qglColor4f (p->data[24], p->data[25], p->data[26], p->data[27]); - qglVertex3f (p->data[3] , p->data[4], p->data[5]); + name = PRVM_G_STRING( OFS_PARM0 ); + VM_CheckEmptyString( name ); - if(p->flags & VM_POLYGON_FL3V) - { - qglTexCoord1f (p->data[16]); - qglColor4f (p->data[28], p->data[29], p->data[30], p->data[31]); - qglVertex3f (p->data[6] , p->data[7], p->data[8]); - - if(p->flags & VM_POLYGON_FL4V) - { - qglTexCoord1f (p->data[18]); - qglColor4f (p->data[32], p->data[33], p->data[34], p->data[35]); - qglVertex3f (p->data[9] , p->data[10], p->data[11]); - } - } - qglEnd(); - CHECKGLERROR + // find an empty slot for this gecko browser.. + for( i = 0 ; i < PRVM_MAX_GECKOINSTANCES ; i++ ) { + if( prog->opengeckoinstances[ i ] == NULL ) { + break; } - else - { - qglBegin(GL_POLYGON); - qglTexCoord2f (p->data[12], p->data[13]); - qglColor4f (p->data[20], p->data[21], p->data[22], p->data[23]); - qglVertex3f (p->data[0] , p->data[1], p->data[2]); - - qglTexCoord2f (p->data[14], p->data[15]); - qglColor4f (p->data[24], p->data[25], p->data[26], p->data[27]); - qglVertex3f (p->data[3] , p->data[4], p->data[5]); - - qglTexCoord2f (p->data[16], p->data[17]); - qglColor4f (p->data[28], p->data[29], p->data[30], p->data[31]); - qglVertex3f (p->data[6] , p->data[7], p->data[8]); + } + if( i == PRVM_MAX_GECKOINSTANCES ) { + VM_Warning("VM_gecko_create: %s ran out of gecko handles (%i)\n", PRVM_NAME, PRVM_MAX_GECKOINSTANCES); + PRVM_G_FLOAT( OFS_RETURN ) = 0; + return; + } - if(p->flags & VM_POLYGON_FL4V) - { - qglTexCoord2f (p->data[18], p->data[19]); - qglColor4f (p->data[32], p->data[33], p->data[34], p->data[35]); - qglVertex3f (p->data[9] , p->data[10], p->data[11]); - } - qglEnd(); - CHECKGLERROR - } + instance = prog->opengeckoinstances[ i ] = CL_Gecko_CreateBrowser( name, PRVM_GetProgNr() ); + if( !instance ) { + // TODO: error handling [12/3/2007 Black] + PRVM_G_FLOAT( OFS_RETURN ) = 0; + return; } + PRVM_G_FLOAT( OFS_RETURN ) = 1; } -void VM_AddPolygonTo2DScene (vm_polygon_t *p) -{ - drawqueuemesh_t mesh; - static int picelements[6] = {0, 1, 2, 0, 2, 3}; +/* +======================== +VM_gecko_destroy - mesh.texture = p->tex; - mesh.data_element3i = picelements; - mesh.data_vertex3f = p->data; - mesh.data_texcoord2f = p->data + 12; - mesh.data_color4f = p->data + 20; - if(p->flags & VM_POLYGON_FL4V) - { - mesh.num_vertices = 4; - mesh.num_triangles = 2; - } - else - { - mesh.num_vertices = 3; - mesh.num_triangles = 1; - } - if(p->flags & VM_POLYGON_FLLINES) //[515]: lines - DrawQ_LineLoop (&mesh, (p->flags&0x0f)); - else - DrawQ_Mesh (&mesh, (p->flags&0x0f)); -} +void gecko_destroy( string name ) +======================== +*/ +void VM_gecko_destroy( void ) { + const char *name; + clgecko_t *instance; -//void(string texturename, float flag, float 2d, float lines) R_BeginPolygon -void VM_R_PolygonBegin (void) -{ - vm_polygon_t *p; - const char *picname; - if(prog->argc < 2) - VM_SAFEPARMCOUNT(2, VM_R_PolygonBegin); + VM_SAFEPARMCOUNT( 1, VM_gecko_destroy ); - if(!vm_polygons_initialized) - VM_InitPolygons(); - if(vm_polygonbegin) - { - VM_Warning("VM_R_PolygonBegin: called twice without VM_R_PolygonEnd after first\n"); + name = PRVM_G_STRING( OFS_PARM0 ); + VM_CheckEmptyString( name ); + instance = CL_Gecko_FindBrowser( name ); + if( !instance ) { return; } - if(vm_drawpolygons_num >= vm_polygons_num) - { - p = (vm_polygon_t *)Mem_Alloc(vm_polygons_pool, 2 * vm_polygons_num * sizeof(vm_polygon_t)); - memset(p, 0, 2 * vm_polygons_num * sizeof(vm_polygon_t)); - memcpy(p, vm_polygons, vm_polygons_num * sizeof(vm_polygon_t)); - Mem_Free(vm_polygons); - vm_polygons = p; - vm_polygons_num *= 2; - } - p = &vm_polygons[vm_drawpolygons_num]; - picname = PRVM_G_STRING(OFS_PARM0); - if(picname[0]) - p->tex = Draw_CachePic(picname, true)->tex; - else - p->tex = r_texture_white; - p->flags = (unsigned char)PRVM_G_FLOAT(OFS_PARM1); - vm_current_vertices = 0; - vm_polygonbegin = true; - if(prog->argc >= 3) - { - if(PRVM_G_FLOAT(OFS_PARM2)) - p->flags |= VM_POLYGON_FL2D; - if(prog->argc >= 4 && PRVM_G_FLOAT(OFS_PARM3)) - { - p->data[13] = PRVM_G_FLOAT(OFS_PARM3); //[515]: linewidth - p->flags |= VM_POLYGON_FLLINES; - } - } + CL_Gecko_DestroyBrowser( instance ); } -//void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex -void VM_R_PolygonVertex (void) -{ - float *coords, *tx, *rgb, alpha; - vm_polygon_t *p; - VM_SAFEPARMCOUNT(4, VM_R_PolygonVertex); - - if(!vm_polygonbegin) - { - VM_Warning("VM_R_PolygonVertex: VM_R_PolygonBegin wasn't called\n"); +/* +======================== +VM_gecko_navigate + +void gecko_navigate( string name, string URI ) +======================== +*/ +void VM_gecko_navigate( void ) { + const char *name; + const char *URI; + clgecko_t *instance; + + VM_SAFEPARMCOUNT( 2, VM_gecko_navigate ); + + name = PRVM_G_STRING( OFS_PARM0 ); + URI = PRVM_G_STRING( OFS_PARM1 ); + VM_CheckEmptyString( name ); + VM_CheckEmptyString( URI ); + + instance = CL_Gecko_FindBrowser( name ); + if( !instance ) { return; } - coords = PRVM_G_VECTOR(OFS_PARM0); - tx = PRVM_G_VECTOR(OFS_PARM1); - rgb = PRVM_G_VECTOR(OFS_PARM2); - alpha = PRVM_G_FLOAT(OFS_PARM3); + CL_Gecko_NavigateToURI( instance, URI ); +} - p = &vm_polygons[vm_drawpolygons_num]; - if(vm_current_vertices > 4) - { - VM_Warning("VM_R_PolygonVertex: may have 4 vertices max\n"); +/* +======================== +VM_gecko_keyevent + +float[bool] gecko_keyevent( string name, float key, float eventtype ) +======================== +*/ +void VM_gecko_keyevent( void ) { + const char *name; + unsigned int key; + clgecko_buttoneventtype_t eventtype; + clgecko_t *instance; + + VM_SAFEPARMCOUNT( 3, VM_gecko_keyevent ); + + name = PRVM_G_STRING( OFS_PARM0 ); + VM_CheckEmptyString( name ); + key = (unsigned int) PRVM_G_FLOAT( OFS_PARM1 ); + switch( (unsigned int) PRVM_G_FLOAT( OFS_PARM2 ) ) { + case 0: + eventtype = CLG_BET_DOWN; + break; + case 1: + eventtype = CLG_BET_UP; + break; + case 2: + eventtype = CLG_BET_PRESS; + break; + case 3: + eventtype = CLG_BET_DOUBLECLICK; + break; + default: + // TODO: console printf? [12/3/2007 Black] + PRVM_G_FLOAT( OFS_RETURN ) = 0; return; } - p->data[vm_current_vertices*3] = coords[0]; - p->data[1+vm_current_vertices*3] = coords[1]; - p->data[2+vm_current_vertices*3] = coords[2]; + instance = CL_Gecko_FindBrowser( name ); + if( !instance ) { + PRVM_G_FLOAT( OFS_RETURN ) = 0; + return; + } - p->data[12+vm_current_vertices*2] = tx[0]; - if(!(p->flags & VM_POLYGON_FLLINES)) - p->data[13+vm_current_vertices*2] = tx[1]; + PRVM_G_FLOAT( OFS_RETURN ) = (CL_Gecko_Event_Key( instance, (keynum_t) key, eventtype ) == true); +} - p->data[20+vm_current_vertices*4] = rgb[0]; - p->data[21+vm_current_vertices*4] = rgb[1]; - p->data[22+vm_current_vertices*4] = rgb[2]; - p->data[23+vm_current_vertices*4] = alpha; +/* +======================== +VM_gecko_movemouse - vm_current_vertices++; - if(vm_current_vertices == 4) - p->flags |= VM_POLYGON_FL4V; - else - if(vm_current_vertices == 3) - p->flags |= VM_POLYGON_FL3V; +void gecko_mousemove( string name, float x, float y ) +======================== +*/ +void VM_gecko_movemouse( void ) { + const char *name; + float x, y; + clgecko_t *instance; + + VM_SAFEPARMCOUNT( 3, VM_gecko_movemouse ); + + name = PRVM_G_STRING( OFS_PARM0 ); + VM_CheckEmptyString( name ); + x = PRVM_G_FLOAT( OFS_PARM1 ); + y = PRVM_G_FLOAT( OFS_PARM2 ); + + instance = CL_Gecko_FindBrowser( name ); + if( !instance ) { + return; + } + CL_Gecko_Event_CursorMove( instance, x, y ); } -//void() R_EndPolygon -void VM_R_PolygonEnd (void) -{ - if(!vm_polygonbegin) - { - VM_Warning("VM_R_PolygonEnd: VM_R_PolygonBegin wasn't called\n"); + +/* +======================== +VM_gecko_resize + +void gecko_resize( string name, float w, float h ) +======================== +*/ +void VM_gecko_resize( void ) { + const char *name; + float w, h; + clgecko_t *instance; + + VM_SAFEPARMCOUNT( 3, VM_gecko_movemouse ); + + name = PRVM_G_STRING( OFS_PARM0 ); + VM_CheckEmptyString( name ); + w = PRVM_G_FLOAT( OFS_PARM1 ); + h = PRVM_G_FLOAT( OFS_PARM2 ); + + instance = CL_Gecko_FindBrowser( name ); + if( !instance ) { + return; + } + CL_Gecko_Resize( instance, (int) w, (int) h ); +} + + +/* +======================== +VM_gecko_get_texture_extent + +vector gecko_get_texture_extent( string name ) +======================== +*/ +void VM_gecko_get_texture_extent( void ) { + const char *name; + clgecko_t *instance; + + VM_SAFEPARMCOUNT( 1, VM_gecko_movemouse ); + + name = PRVM_G_STRING( OFS_PARM0 ); + VM_CheckEmptyString( name ); + + PRVM_G_VECTOR(OFS_RETURN)[2] = 0; + instance = CL_Gecko_FindBrowser( name ); + if( !instance ) { + PRVM_G_VECTOR(OFS_RETURN)[0] = 0; + PRVM_G_VECTOR(OFS_RETURN)[1] = 0; return; } - vm_polygonbegin = false; - if(vm_current_vertices > 2 || (vm_current_vertices >= 2 && vm_polygons[vm_drawpolygons_num].flags & VM_POLYGON_FLLINES)) + CL_Gecko_GetTextureExtent( instance, + PRVM_G_VECTOR(OFS_RETURN), PRVM_G_VECTOR(OFS_RETURN)+1 ); +} + + + +/* +============== +VM_makevectors + +Writes new values for v_forward, v_up, and v_right based on angles +void makevectors(vector angle) +============== +*/ +void VM_makevectors (void) +{ + prvm_eval_t *valforward, *valright, *valup; + valforward = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.v_forward); + valright = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.v_right); + valup = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.v_up); + if (!valforward || !valright || !valup) { - if(vm_polygons[vm_drawpolygons_num].flags & VM_POLYGON_FL2D) //[515]: don't use qcpolygons memory if 2D - VM_AddPolygonTo2DScene(&vm_polygons[vm_drawpolygons_num]); - else - vm_drawpolygons_num++; + VM_Warning("makevectors: could not find v_forward, v_right, or v_up global variables\n"); + return; } - else - VM_Warning("VM_R_PolygonEnd: %i vertices isn't a good choice\n", vm_current_vertices); + VM_SAFEPARMCOUNT(1, VM_makevectors); + AngleVectors (PRVM_G_VECTOR(OFS_PARM0), valforward->vector, valright->vector, valup->vector); } -void VM_AddPolygonsToMeshQueue (void) +/* +============== +VM_vectorvectors + +Writes new values for v_forward, v_up, and v_right based on the given forward vector +vectorvectors(vector) +============== +*/ +void VM_vectorvectors (void) { - unsigned int i; - if(!vm_drawpolygons_num) + prvm_eval_t *valforward, *valright, *valup; + valforward = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.v_forward); + valright = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.v_right); + valup = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.v_up); + if (!valforward || !valright || !valup) + { + VM_Warning("vectorvectors: could not find v_forward, v_right, or v_up global variables\n"); return; - for(i = 0;i < vm_drawpolygons_num;i++) - VM_DrawPolygonCallback(NULL, NULL, i, NULL); - vm_drawpolygons_num = 0; + } + VM_SAFEPARMCOUNT(1, VM_vectorvectors); + VectorNormalize2(PRVM_G_VECTOR(OFS_PARM0), valforward->vector); + VectorVectors(valforward->vector, valright->vector, valup->vector); } +/* +======================== +VM_drawline +void drawline(float width, vector pos1, vector pos2, vector rgb, float alpha, float flags) +======================== +*/ +void VM_drawline (void) +{ + float *c1, *c2, *rgb; + float alpha, width; + unsigned char flags; + VM_SAFEPARMCOUNT(6, VM_drawline); + width = PRVM_G_FLOAT(OFS_PARM0); + c1 = PRVM_G_VECTOR(OFS_PARM1); + c2 = PRVM_G_VECTOR(OFS_PARM2); + rgb = PRVM_G_VECTOR(OFS_PARM3); + alpha = PRVM_G_FLOAT(OFS_PARM4); + flags = (int)PRVM_G_FLOAT(OFS_PARM5); + DrawQ_Line(width, c1[0], c1[1], c2[0], c2[1], rgb[0], rgb[1], rgb[2], alpha, flags); +} // float(float number, float quantity) bitshift (EXT_BITSHIFT) void VM_bitshift (void) @@ -3351,17 +3920,16 @@ string altstr_prepare(string) */ void VM_altstr_prepare( void ) { - char *outstr, *out; + char *out; const char *instr, *in; int size; + char outstr[VM_STRINGTEMP_LENGTH]; VM_SAFEPARMCOUNT( 1, VM_altstr_prepare ); instr = PRVM_G_STRING( OFS_PARM0 ); - //VM_CheckEmptyString( instr ); - outstr = VM_GetTempString(); - for( out = outstr, in = instr, size = VM_STRINGTEMP_LENGTH - 1 ; size && *in ; size--, in++, out++ ) + for( out = outstr, in = instr, size = sizeof(outstr) - 1 ; size && *in ; size--, in++, out++ ) if( *in == '\'' ) { *out++ = '\\'; *out = '\''; @@ -3370,7 +3938,7 @@ void VM_altstr_prepare( void ) *out = *in; *out = 0; - PRVM_G_INT( OFS_RETURN ) = PRVM_SetEngineString( outstr ); + PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString( outstr ); } /* @@ -3383,13 +3951,13 @@ string altstr_get(string, float) void VM_altstr_get( void ) { const char *altstr, *pos; - char *outstr, *out; + char *out; int count, size; + char outstr[VM_STRINGTEMP_LENGTH]; VM_SAFEPARMCOUNT( 2, VM_altstr_get ); altstr = PRVM_G_STRING( OFS_PARM0 ); - //VM_CheckEmptyString( altstr ); count = (int)PRVM_G_FLOAT( OFS_PARM1 ); count = count * 2 + 1; @@ -3402,12 +3970,11 @@ void VM_altstr_get( void ) count--; if( !*pos ) { - PRVM_G_INT( OFS_RETURN ) = PRVM_SetEngineString( NULL ); + PRVM_G_INT( OFS_RETURN ) = 0; return; } - outstr = VM_GetTempString(); - for( out = outstr, size = VM_STRINGTEMP_LENGTH - 1 ; size && *pos ; size--, pos++, out++ ) + for( out = outstr, size = sizeof(outstr) - 1 ; size && *pos ; size--, pos++, out++ ) if( *pos == '\\' ) { if( !*++pos ) break; @@ -3419,7 +3986,7 @@ void VM_altstr_get( void ) *out = *pos; *out = 0; - PRVM_G_INT( OFS_RETURN ) = PRVM_SetEngineString( outstr ); + PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString( outstr ); } /* @@ -3434,19 +4001,18 @@ void VM_altstr_set( void ) int num; const char *altstr, *str; const char *in; - char *outstr, *out; + char *out; + char outstr[VM_STRINGTEMP_LENGTH]; VM_SAFEPARMCOUNT( 3, VM_altstr_set ); altstr = PRVM_G_STRING( OFS_PARM0 ); - //VM_CheckEmptyString( altstr ); num = (int)PRVM_G_FLOAT( OFS_PARM1 ); str = PRVM_G_STRING( OFS_PARM2 ); - //VM_CheckEmptyString( str ); - outstr = out = VM_GetTempString(); + out = outstr; for( num = num * 2 + 1, in = altstr; *in && num; *out++ = *in++ ) if( *in == '\\' ) { if( !*++in ) { @@ -3456,10 +4022,6 @@ void VM_altstr_set( void ) num--; } - if( !in ) { - PRVM_G_INT( OFS_RETURN ) = PRVM_SetEngineString( altstr ); - return; - } // copy set in for( ; *str; *out++ = *str++ ); // now jump over the old content @@ -3467,13 +4029,8 @@ void VM_altstr_set( void ) if( *in == '\'' || (*in == '\\' && !*++in) ) break; - if( !in ) { - PRVM_G_INT( OFS_RETURN ) = PRVM_SetEngineString( NULL ); - return; - } - - strlcpy(out, in, VM_STRINGTEMP_LENGTH); - PRVM_G_INT( OFS_RETURN ) = PRVM_SetEngineString( outstr ); + strlcpy(out, in, outstr + sizeof(outstr) - out); + PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString( outstr ); } /* @@ -3490,14 +4047,16 @@ void VM_altstr_ins(void) const char *set; const char *instr; const char *in; - char *outstr; char *out; + char outstr[VM_STRINGTEMP_LENGTH]; + + VM_SAFEPARMCOUNT(3, VM_altstr_ins); in = instr = PRVM_G_STRING( OFS_PARM0 ); num = (int)PRVM_G_FLOAT( OFS_PARM1 ); set = setstr = PRVM_G_STRING( OFS_PARM2 ); - out = outstr = VM_GetTempString(); + out = outstr; for( num = num * 2 + 2 ; *in && num > 0 ; *out++ = *in++ ) if( *in == '\\' ) { if( !*++in ) { @@ -3511,8 +4070,8 @@ void VM_altstr_ins(void) for( ; *set ; *out++ = *set++ ); *out++ = '\''; - strlcpy(out, in, VM_STRINGTEMP_LENGTH); - PRVM_G_INT( OFS_RETURN ) = PRVM_SetEngineString( outstr ); + strlcpy(out, in, outstr + sizeof(outstr) - out); + PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString( outstr ); } @@ -3520,66 +4079,41 @@ void VM_altstr_ins(void) // BufString functions //////////////////////////////////////// //[515]: string buffers support -#define MAX_QCSTR_BUFFERS 128 -#define MAX_QCSTR_STRINGS 1024 - -typedef struct -{ - int num_strings; - char *strings[MAX_QCSTR_STRINGS]; -}qcstrbuffer_t; -static qcstrbuffer_t *qcstringbuffers[MAX_QCSTR_BUFFERS]; -static int num_qcstringbuffers; -static int buf_sortpower; +static size_t stringbuffers_sortlength; -#define BUFSTR_BUFFER(a) (a>=MAX_QCSTR_BUFFERS) ? NULL : (qcstringbuffers[a]) -#define BUFSTR_ISFREE(a) (anum_strings<=0) ? 1 : 0 - -static int BufStr_FindFreeBuffer (void) +static void BufStr_Expand(prvm_stringbuffer_t *stringbuffer, int strindex) { - int i; - if(num_qcstringbuffers == MAX_QCSTR_BUFFERS) - return -1; - for(i=0;imax_strings <= strindex) + { + char **oldstrings = stringbuffer->strings; + stringbuffer->max_strings = max(stringbuffer->max_strings * 2, 128); + while (stringbuffer->max_strings <= strindex) + stringbuffer->max_strings *= 2; + stringbuffer->strings = (char **) Mem_Alloc(prog->progs_mempool, stringbuffer->max_strings * sizeof(stringbuffer->strings[0])); + if (stringbuffer->num_strings > 0) + memcpy(stringbuffer->strings, oldstrings, stringbuffer->num_strings * sizeof(stringbuffer->strings[0])); + if (oldstrings) + Mem_Free(oldstrings); + } } -static void BufStr_ClearBuffer (int index) +static void BufStr_Shrink(prvm_stringbuffer_t *stringbuffer) { - qcstrbuffer_t *b = qcstringbuffers[index]; - int i; + // reduce num_strings if there are empty string slots at the end + while (stringbuffer->num_strings > 0 && stringbuffer->strings[stringbuffer->num_strings - 1] == NULL) + stringbuffer->num_strings--; - if(b) + // if empty, free the string pointer array + if (stringbuffer->num_strings == 0) { - if(b->num_strings > 0) - { - for(i=0;inum_strings;i++) - if(b->strings[i]) - Z_Free(b->strings[i]); - num_qcstringbuffers--; - } - Z_Free(qcstringbuffers[index]); - qcstringbuffers[index] = NULL; + stringbuffer->max_strings = 0; + if (stringbuffer->strings) + Mem_Free(stringbuffer->strings); + stringbuffer->strings = NULL; } } -static int BufStr_FindFreeString (qcstrbuffer_t *b) -{ - int i; - for(i=0;inum_strings;i++) - if(!b->strings[i] || !b->strings[i][0]) - return i; - if(i == MAX_QCSTR_STRINGS) return -1; - else return i; -} - static int BufStr_SortStringsUP (const void *in1, const void *in2) { const char *a, *b; @@ -3587,7 +4121,7 @@ static int BufStr_SortStringsUP (const void *in1, const void *in2) b = *((const char **) in2); if(!a[0]) return 1; if(!b[0]) return -1; - return strncmp(a, b, buf_sortpower); + return strncmp(a, b, stringbuffers_sortlength); } static int BufStr_SortStringsDOWN (const void *in1, const void *in2) @@ -3597,24 +4131,9 @@ static int BufStr_SortStringsDOWN (const void *in1, const void *in2) b = *((const char **) in2); if(!a[0]) return 1; if(!b[0]) return -1; - return strncmp(b, a, buf_sortpower); + return strncmp(b, a, stringbuffers_sortlength); } -#ifdef REMOVETHIS -static void VM_BufStr_Init (void) -{ - memset(qcstringbuffers, 0, sizeof(qcstringbuffers)); - num_qcstringbuffers = 0; -} - -static void VM_BufStr_ShutDown (void) -{ - int i; - for(i=0;i= 0) - num_qcstringbuffers++; - //else - //Con_Printf("VM_buf_create: buffers overflow in %s\n", PRVM_NAME); + stringbuffer = (prvm_stringbuffer_t *) Mem_ExpandableArray_AllocRecord(&prog->stringbuffersarray); + for (i = 0;stringbuffer != Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, i);i++); + stringbuffer->origin = PRVM_AllocationOrigin(); PRVM_G_FLOAT(OFS_RETURN) = i; } @@ -3643,9 +4161,21 @@ void buf_del(float bufhandle) = #461; */ void VM_buf_del (void) { + prvm_stringbuffer_t *stringbuffer; VM_SAFEPARMCOUNT(1, VM_buf_del); - if(BUFSTR_BUFFER((int)PRVM_G_FLOAT(OFS_PARM0))) - BufStr_ClearBuffer((int)PRVM_G_FLOAT(OFS_PARM0)); + stringbuffer = (prvm_stringbuffer_t *)Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, (int)PRVM_G_FLOAT(OFS_PARM0)); + if (stringbuffer) + { + int i; + for (i = 0;i < stringbuffer->num_strings;i++) + if (stringbuffer->strings[i]) + Mem_Free(stringbuffer->strings[i]); + if (stringbuffer->strings) + Mem_Free(stringbuffer->strings); + if(stringbuffer->origin) + PRVM_Free((char *)stringbuffer->origin); + Mem_ExpandableArray_FreeRecord(&prog->stringbuffersarray, stringbuffer); + } else { VM_Warning("VM_buf_del: invalid buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), PRVM_NAME); @@ -3662,18 +4192,18 @@ float buf_getsize(float bufhandle) = #462; */ void VM_buf_getsize (void) { - qcstrbuffer_t *b; + prvm_stringbuffer_t *stringbuffer; VM_SAFEPARMCOUNT(1, VM_buf_getsize); - b = BUFSTR_BUFFER((int)PRVM_G_FLOAT(OFS_PARM0)); - if(!b) + stringbuffer = (prvm_stringbuffer_t *)Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, (int)PRVM_G_FLOAT(OFS_PARM0)); + if(!stringbuffer) { PRVM_G_FLOAT(OFS_RETURN) = -1; VM_Warning("VM_buf_getsize: invalid buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), PRVM_NAME); return; } else - PRVM_G_FLOAT(OFS_RETURN) = b->num_strings; + PRVM_G_FLOAT(OFS_RETURN) = stringbuffer->num_strings; } /* @@ -3685,12 +4215,12 @@ void buf_copy(float bufhandle_from, float bufhandle_to) = #463; */ void VM_buf_copy (void) { - qcstrbuffer_t *b1, *b2; - int i; + prvm_stringbuffer_t *srcstringbuffer, *dststringbuffer; + int i; VM_SAFEPARMCOUNT(2, VM_buf_copy); - b1 = BUFSTR_BUFFER((int)PRVM_G_FLOAT(OFS_PARM0)); - if(!b1) + srcstringbuffer = (prvm_stringbuffer_t *)Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, (int)PRVM_G_FLOAT(OFS_PARM0)); + if(!srcstringbuffer) { VM_Warning("VM_buf_copy: invalid source buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), PRVM_NAME); return; @@ -3701,81 +4231,68 @@ void VM_buf_copy (void) VM_Warning("VM_buf_copy: source == destination (%i) in %s\n", i, PRVM_NAME); return; } - b2 = BUFSTR_BUFFER(i); - if(!b2) + dststringbuffer = (prvm_stringbuffer_t *)Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, (int)PRVM_G_FLOAT(OFS_PARM0)); + if(!dststringbuffer) { VM_Warning("VM_buf_copy: invalid destination buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM1), PRVM_NAME); return; } - BufStr_ClearBuffer(i); - qcstringbuffers[i] = (qcstrbuffer_t *)Z_Malloc(sizeof(qcstrbuffer_t)); - memset(qcstringbuffers[i], 0, sizeof(qcstrbuffer_t)); - b2->num_strings = b1->num_strings; + for (i = 0;i < dststringbuffer->num_strings;i++) + if (dststringbuffer->strings[i]) + Mem_Free(dststringbuffer->strings[i]); + if (dststringbuffer->strings) + Mem_Free(dststringbuffer->strings); + *dststringbuffer = *srcstringbuffer; + if (dststringbuffer->max_strings) + dststringbuffer->strings = (char **)Mem_Alloc(prog->progs_mempool, sizeof(dststringbuffer->strings[0]) * dststringbuffer->max_strings); - for(i=0;inum_strings;i++) - if(b1->strings[i] && b1->strings[i][0]) + for (i = 0;i < dststringbuffer->num_strings;i++) + { + if (srcstringbuffer->strings[i]) { size_t stringlen; - stringlen = strlen(b1->strings[i]) + 1; - b2->strings[i] = (char *)Z_Malloc(stringlen); - if(!b2->strings[i]) - { - VM_Warning("VM_buf_copy: not enough memory for buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM1), PRVM_NAME); - break; - } - memcpy(b2->strings[i], b1->strings[i], stringlen); + stringlen = strlen(srcstringbuffer->strings[i]) + 1; + dststringbuffer->strings[i] = (char *)Mem_Alloc(prog->progs_mempool, stringlen); + memcpy(dststringbuffer->strings[i], srcstringbuffer->strings[i], stringlen); } + } } /* ======================== VM_buf_sort -sort buffer by beginnings of strings (sortpower defaults it's lenght) +sort buffer by beginnings of strings (cmplength defaults it's length) "backward == TRUE" means that sorting goes upside-down -void buf_sort(float bufhandle, float sortpower, float backward) = #464; +void buf_sort(float bufhandle, float cmplength, float backward) = #464; ======================== */ void VM_buf_sort (void) { - qcstrbuffer_t *b; - int i; + prvm_stringbuffer_t *stringbuffer; VM_SAFEPARMCOUNT(3, VM_buf_sort); - b = BUFSTR_BUFFER((int)PRVM_G_FLOAT(OFS_PARM0)); - if(!b) + stringbuffer = (prvm_stringbuffer_t *)Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, (int)PRVM_G_FLOAT(OFS_PARM0)); + if(!stringbuffer) { VM_Warning("VM_buf_sort: invalid buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), PRVM_NAME); return; } - if(b->num_strings <= 0) + if(stringbuffer->num_strings <= 0) { VM_Warning("VM_buf_sort: tried to sort empty buffer %i in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), PRVM_NAME); return; } - buf_sortpower = (int)PRVM_G_FLOAT(OFS_PARM1); - if(buf_sortpower <= 0) - buf_sortpower = 99999999; + stringbuffers_sortlength = (int)PRVM_G_FLOAT(OFS_PARM1); + if(stringbuffers_sortlength <= 0) + stringbuffers_sortlength = 0x7FFFFFFF; if(!PRVM_G_FLOAT(OFS_PARM2)) - qsort(b->strings, b->num_strings, sizeof(char*), BufStr_SortStringsUP); + qsort(stringbuffer->strings, stringbuffer->num_strings, sizeof(char*), BufStr_SortStringsUP); else - qsort(b->strings, b->num_strings, sizeof(char*), BufStr_SortStringsDOWN); + qsort(stringbuffer->strings, stringbuffer->num_strings, sizeof(char*), BufStr_SortStringsDOWN); - for(i=b->num_strings-1;i>=0;i--) //[515]: delete empty lines - if(b->strings) - { - if(b->strings[i][0]) - break; - else - { - Z_Free(b->strings[i]); - --b->num_strings; - b->strings[i] = NULL; - } - } - else - --b->num_strings; + BufStr_Shrink(stringbuffer); } /* @@ -3787,73 +4304,66 @@ string buf_implode(float bufhandle, string glue) = #465; */ void VM_buf_implode (void) { - qcstrbuffer_t *b; - char *k; + prvm_stringbuffer_t *stringbuffer; + char k[VM_STRINGTEMP_LENGTH]; const char *sep; int i; size_t l; VM_SAFEPARMCOUNT(2, VM_buf_implode); - b = BUFSTR_BUFFER((int)PRVM_G_FLOAT(OFS_PARM0)); - PRVM_G_INT(OFS_RETURN) = 0; - if(!b) + stringbuffer = (prvm_stringbuffer_t *)Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, (int)PRVM_G_FLOAT(OFS_PARM0)); + PRVM_G_INT(OFS_RETURN) = OFS_NULL; + if(!stringbuffer) { VM_Warning("VM_buf_implode: invalid buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), PRVM_NAME); return; } - if(!b->num_strings) + if(!stringbuffer->num_strings) return; sep = PRVM_G_STRING(OFS_PARM1); - k = VM_GetTempString(); k[0] = 0; - for(l=i=0;inum_strings;i++) - if(b->strings[i]) + for(l = i = 0;i < stringbuffer->num_strings;i++) + { + if(stringbuffer->strings[i]) { - l += strlen(b->strings[i]); - if(l>=4095) + l += (i > 0 ? strlen(sep) : 0) + strlen(stringbuffer->strings[i]); + if (l >= sizeof(k) - 1) break; - strlcat(k, b->strings[i], VM_STRINGTEMP_LENGTH); - if(sep && (i != b->num_strings-1)) - { - l += strlen(sep); - if(l>=4095) - break; - strlcat(k, sep, VM_STRINGTEMP_LENGTH); - } + strlcat(k, sep, sizeof(k)); + strlcat(k, stringbuffer->strings[i], sizeof(k)); } - PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(k); + } + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(k); } /* ======================== VM_bufstr_get -get a string from buffer, returns direct pointer, dont str_unzone it! +get a string from buffer, returns tempstring, dont str_unzone it! string bufstr_get(float bufhandle, float string_index) = #465; ======================== */ void VM_bufstr_get (void) { - qcstrbuffer_t *b; + prvm_stringbuffer_t *stringbuffer; int strindex; VM_SAFEPARMCOUNT(2, VM_bufstr_get); - b = BUFSTR_BUFFER((int)PRVM_G_FLOAT(OFS_PARM0)); - if(!b) + PRVM_G_INT(OFS_RETURN) = OFS_NULL; + stringbuffer = (prvm_stringbuffer_t *)Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, (int)PRVM_G_FLOAT(OFS_PARM0)); + if(!stringbuffer) { VM_Warning("VM_bufstr_get: invalid buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), PRVM_NAME); return; } strindex = (int)PRVM_G_FLOAT(OFS_PARM1); - if(strindex < 0 || strindex > MAX_QCSTR_STRINGS) + if (strindex < 0) { VM_Warning("VM_bufstr_get: invalid string index %i used in %s\n", strindex, PRVM_NAME); return; } - PRVM_G_INT(OFS_RETURN) = 0; - if(b->num_strings <= strindex) - return; - if(b->strings[strindex]) - PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(b->strings[strindex]); + if (strindex < stringbuffer->num_strings && stringbuffer->strings[strindex]) + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(stringbuffer->strings[strindex]); } /* @@ -3865,99 +4375,88 @@ void bufstr_set(float bufhandle, float string_index, string str) = #466; */ void VM_bufstr_set (void) { - int bufindex, strindex; - qcstrbuffer_t *b; + int strindex; + prvm_stringbuffer_t *stringbuffer; const char *news; - size_t alloclen; VM_SAFEPARMCOUNT(3, VM_bufstr_set); - bufindex = (int)PRVM_G_FLOAT(OFS_PARM0); - b = BUFSTR_BUFFER(bufindex); - if(!b) + stringbuffer = (prvm_stringbuffer_t *)Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, (int)PRVM_G_FLOAT(OFS_PARM0)); + if(!stringbuffer) { - VM_Warning("VM_bufstr_set: invalid buffer %i used in %s\n", bufindex, PRVM_NAME); + VM_Warning("VM_bufstr_set: invalid buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), PRVM_NAME); return; } strindex = (int)PRVM_G_FLOAT(OFS_PARM1); - if(strindex < 0 || strindex > MAX_QCSTR_STRINGS) + if(strindex < 0 || strindex >= 1000000) // huge number of strings { VM_Warning("VM_bufstr_set: invalid string index %i used in %s\n", strindex, PRVM_NAME); return; } + + BufStr_Expand(stringbuffer, strindex); + stringbuffer->num_strings = max(stringbuffer->num_strings, strindex + 1); + + if(stringbuffer->strings[strindex]) + Mem_Free(stringbuffer->strings[strindex]); + stringbuffer->strings[strindex] = NULL; + news = PRVM_G_STRING(OFS_PARM2); - if(!news) + if (news && news[0]) { - VM_Warning("VM_bufstr_set: null string used in %s\n", PRVM_NAME); - return; + size_t alloclen = strlen(news) + 1; + stringbuffer->strings[strindex] = (char *)Mem_Alloc(prog->progs_mempool, alloclen); + memcpy(stringbuffer->strings[strindex], news, alloclen); } - if(b->strings[strindex]) - Z_Free(b->strings[strindex]); - alloclen = strlen(news) + 1; - b->strings[strindex] = (char *)Z_Malloc(alloclen); - memcpy(b->strings[strindex], news, alloclen); + + BufStr_Shrink(stringbuffer); } /* ======================== VM_bufstr_add -adds string to buffer in nearest free slot and returns it +adds string to buffer in first free slot and returns its index "order == TRUE" means that string will be added after last "full" slot float bufstr_add(float bufhandle, string str, float order) = #467; ======================== */ void VM_bufstr_add (void) { - int bufindex, order, strindex; - qcstrbuffer_t *b; + int order, strindex; + prvm_stringbuffer_t *stringbuffer; const char *string; size_t alloclen; VM_SAFEPARMCOUNT(3, VM_bufstr_add); - bufindex = (int)PRVM_G_FLOAT(OFS_PARM0); - b = BUFSTR_BUFFER(bufindex); + stringbuffer = (prvm_stringbuffer_t *)Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, (int)PRVM_G_FLOAT(OFS_PARM0)); PRVM_G_FLOAT(OFS_RETURN) = -1; - if(!b) + if(!stringbuffer) { - VM_Warning("VM_bufstr_add: invalid buffer %i used in %s\n", bufindex, PRVM_NAME); + VM_Warning("VM_bufstr_add: invalid buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), PRVM_NAME); return; } string = PRVM_G_STRING(OFS_PARM1); - if(!string) + if(!string || !string[0]) { - VM_Warning("VM_bufstr_add: null string used in %s\n", PRVM_NAME); + VM_Warning("VM_bufstr_add: can not add an empty string to buffer %i in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), PRVM_NAME); return; } - order = (int)PRVM_G_FLOAT(OFS_PARM2); if(order) - strindex = b->num_strings; + strindex = stringbuffer->num_strings; else - { - strindex = BufStr_FindFreeString(b); - if(strindex < 0) - { - VM_Warning("VM_bufstr_add: buffer %i has no free string slots in %s\n", bufindex, PRVM_NAME); - return; - } - } + for (strindex = 0;strindex < stringbuffer->num_strings;strindex++) + if (stringbuffer->strings[strindex] == NULL) + break; - while(b->num_strings <= strindex) - { - if(b->num_strings == MAX_QCSTR_STRINGS) - { - VM_Warning("VM_bufstr_add: buffer %i has no free string slots in %s\n", bufindex, PRVM_NAME); - return; - } - b->strings[b->num_strings] = NULL; - b->num_strings++; - } - if(b->strings[strindex]) - Z_Free(b->strings[strindex]); + BufStr_Expand(stringbuffer, strindex); + + stringbuffer->num_strings = max(stringbuffer->num_strings, strindex + 1); alloclen = strlen(string) + 1; - b->strings[strindex] = (char *)Z_Malloc(alloclen); - memcpy(b->strings[strindex], string, alloclen); + stringbuffer->strings[strindex] = (char *)Mem_Alloc(prog->progs_mempool, alloclen); + memcpy(stringbuffer->strings[strindex], string, alloclen); + PRVM_G_FLOAT(OFS_RETURN) = strindex; } @@ -3971,26 +4470,567 @@ void bufstr_free(float bufhandle, float string_index) = #468; void VM_bufstr_free (void) { int i; - qcstrbuffer_t *b; + prvm_stringbuffer_t *stringbuffer; VM_SAFEPARMCOUNT(2, VM_bufstr_free); - b = BUFSTR_BUFFER((int)PRVM_G_FLOAT(OFS_PARM0)); - if(!b) + stringbuffer = (prvm_stringbuffer_t *)Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, (int)PRVM_G_FLOAT(OFS_PARM0)); + if(!stringbuffer) { VM_Warning("VM_bufstr_free: invalid buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), PRVM_NAME); return; } i = (int)PRVM_G_FLOAT(OFS_PARM1); - if(i < 0 || i > MAX_QCSTR_STRINGS) + if(i < 0) { VM_Warning("VM_bufstr_free: invalid string index %i used in %s\n", i, PRVM_NAME); return; } - if(b->strings[i]) - Z_Free(b->strings[i]); - b->strings[i] = NULL; - if(i+1 == b->num_strings) - --b->num_strings; + + if (i < stringbuffer->num_strings) + { + if(stringbuffer->strings[i]) + Mem_Free(stringbuffer->strings[i]); + stringbuffer->strings[i] = NULL; + } + + BufStr_Shrink(stringbuffer); +} + + + + + + + +void VM_buf_cvarlist(void) +{ + cvar_t *cvar; + const char *partial, *antipartial; + size_t len, antilen; + size_t alloclen; + qboolean ispattern, antiispattern; + int n; + prvm_stringbuffer_t *stringbuffer; + VM_SAFEPARMCOUNTRANGE(2, 3, VM_buf_cvarlist); + + stringbuffer = (prvm_stringbuffer_t *)Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, (int)PRVM_G_FLOAT(OFS_PARM0)); + if(!stringbuffer) + { + VM_Warning("VM_bufstr_free: invalid buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), PRVM_NAME); + return; + } + + partial = PRVM_G_STRING(OFS_PARM1); + if(!partial) + len = 0; + else + len = strlen(partial); + + if(prog->argc == 3) + antipartial = PRVM_G_STRING(OFS_PARM2); + else + antipartial = NULL; + if(!antipartial) + antilen = 0; + else + antilen = strlen(antipartial); + + for (n = 0;n < stringbuffer->num_strings;n++) + if (stringbuffer->strings[n]) + Mem_Free(stringbuffer->strings[n]); + if (stringbuffer->strings) + Mem_Free(stringbuffer->strings); + stringbuffer->strings = NULL; + + ispattern = partial && (strchr(partial, '*') || strchr(partial, '?')); + antiispattern = antipartial && (strchr(antipartial, '*') || strchr(antipartial, '?')); + + n = 0; + for(cvar = cvar_vars; cvar; cvar = cvar->next) + { + if(len && (ispattern ? !matchpattern_with_separator(cvar->name, partial, false, "", false) : strncmp(partial, cvar->name, len))) + continue; + + if(antilen && (antiispattern ? matchpattern_with_separator(cvar->name, antipartial, false, "", false) : !strncmp(antipartial, cvar->name, antilen))) + continue; + + ++n; + } + + stringbuffer->max_strings = stringbuffer->num_strings = n; + if (stringbuffer->max_strings) + stringbuffer->strings = (char **)Mem_Alloc(prog->progs_mempool, sizeof(stringbuffer->strings[0]) * stringbuffer->max_strings); + + n = 0; + for(cvar = cvar_vars; cvar; cvar = cvar->next) + { + if(len && (ispattern ? !matchpattern_with_separator(cvar->name, partial, false, "", false) : strncmp(partial, cvar->name, len))) + continue; + + if(antilen && (antiispattern ? matchpattern_with_separator(cvar->name, antipartial, false, "", false) : !strncmp(antipartial, cvar->name, antilen))) + continue; + + alloclen = strlen(cvar->name) + 1; + stringbuffer->strings[n] = (char *)Mem_Alloc(prog->progs_mempool, alloclen); + memcpy(stringbuffer->strings[n], cvar->name, alloclen); + + ++n; + } +} + + + + +//============= + +/* +============== +VM_changeyaw + +This was a major timewaster in progs, so it was converted to C +============== +*/ +void VM_changeyaw (void) +{ + prvm_edict_t *ent; + float ideal, current, move, speed; + + // this is called (VERY HACKISHLY) by SV_MoveToGoal, so it can not use any + // parameters because they are the parameters to SV_MoveToGoal, not this + //VM_SAFEPARMCOUNT(0, VM_changeyaw); + + ent = PRVM_PROG_TO_EDICT(PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict); + if (ent == prog->edicts) + { + VM_Warning("changeyaw: can not modify world entity\n"); + return; + } + if (ent->priv.server->free) + { + VM_Warning("changeyaw: can not modify free entity\n"); + return; + } + if (prog->fieldoffsets.angles < 0 || prog->fieldoffsets.ideal_yaw < 0 || prog->fieldoffsets.yaw_speed < 0) + { + VM_Warning("changeyaw: angles, ideal_yaw, or yaw_speed field(s) not found\n"); + return; + } + current = ANGLEMOD(PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.angles)->vector[1]); + ideal = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.ideal_yaw)->_float; + speed = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.yaw_speed)->_float; + + if (current == ideal) + return; + move = ideal - current; + if (ideal > current) + { + if (move >= 180) + move = move - 360; + } + else + { + if (move <= -180) + move = move + 360; + } + if (move > 0) + { + if (move > speed) + move = speed; + } + else + { + if (move < -speed) + move = -speed; + } + + PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.angles)->vector[1] = ANGLEMOD (current + move); +} + +/* +============== +VM_changepitch +============== +*/ +void VM_changepitch (void) +{ + prvm_edict_t *ent; + float ideal, current, move, speed; + + VM_SAFEPARMCOUNT(1, VM_changepitch); + + ent = PRVM_G_EDICT(OFS_PARM0); + if (ent == prog->edicts) + { + VM_Warning("changepitch: can not modify world entity\n"); + return; + } + if (ent->priv.server->free) + { + VM_Warning("changepitch: can not modify free entity\n"); + return; + } + if (prog->fieldoffsets.angles < 0 || prog->fieldoffsets.idealpitch < 0 || prog->fieldoffsets.pitch_speed < 0) + { + VM_Warning("changepitch: angles, idealpitch, or pitch_speed field(s) not found\n"); + return; + } + current = ANGLEMOD(PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.angles)->vector[0]); + ideal = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.idealpitch)->_float; + speed = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.pitch_speed)->_float; + + if (current == ideal) + return; + move = ideal - current; + if (ideal > current) + { + if (move >= 180) + move = move - 360; + } + else + { + if (move <= -180) + move = move + 360; + } + if (move > 0) + { + if (move > speed) + move = speed; + } + else + { + if (move < -speed) + move = -speed; + } + + PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.angles)->vector[0] = ANGLEMOD (current + move); +} + + +void VM_uncolorstring (void) +{ + char szNewString[VM_STRINGTEMP_LENGTH]; + const char *szString; + + // Prepare Strings + VM_SAFEPARMCOUNT(1, VM_uncolorstring); + szString = PRVM_G_STRING(OFS_PARM0); + COM_StringDecolorize(szString, 0, szNewString, sizeof(szNewString), TRUE); + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(szNewString); + +} + +// #221 float(string str, string sub[, float startpos]) strstrofs (FTE_STRINGS) +//strstr, without generating a new string. Use in conjunction with FRIK_FILE's substring for more similar strstr. +void VM_strstrofs (void) +{ + const char *instr, *match; + int firstofs; + VM_SAFEPARMCOUNTRANGE(2, 3, VM_strstrofs); + instr = PRVM_G_STRING(OFS_PARM0); + match = PRVM_G_STRING(OFS_PARM1); + firstofs = (prog->argc > 2)?(int)PRVM_G_FLOAT(OFS_PARM2):0; + + if (firstofs && (firstofs < 0 || firstofs > (int)strlen(instr))) + { + PRVM_G_FLOAT(OFS_RETURN) = -1; + return; + } + + match = strstr(instr+firstofs, match); + if (!match) + PRVM_G_FLOAT(OFS_RETURN) = -1; + else + PRVM_G_FLOAT(OFS_RETURN) = match - instr; +} + +//#222 string(string s, float index) str2chr (FTE_STRINGS) +void VM_str2chr (void) +{ + const char *s; + VM_SAFEPARMCOUNT(2, VM_str2chr); + s = PRVM_G_STRING(OFS_PARM0); + if((unsigned)PRVM_G_FLOAT(OFS_PARM1) < strlen(s)) + PRVM_G_FLOAT(OFS_RETURN) = (unsigned char)s[(unsigned)PRVM_G_FLOAT(OFS_PARM1)]; + else + PRVM_G_FLOAT(OFS_RETURN) = 0; +} + +//#223 string(float c, ...) chr2str (FTE_STRINGS) +void VM_chr2str (void) +{ + char t[9]; + int i; + VM_SAFEPARMCOUNTRANGE(0, 8, VM_chr2str); + for(i = 0;i < prog->argc && i < (int)sizeof(t) - 1;i++) + t[i] = (unsigned char)PRVM_G_FLOAT(OFS_PARM0+i*3); + t[i] = 0; + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(t); +} + +static int chrconv_number(int i, int base, int conv) +{ + i -= base; + switch (conv) + { + default: + case 5: + case 6: + case 0: + break; + case 1: + base = '0'; + break; + case 2: + base = '0'+128; + break; + case 3: + base = '0'-30; + break; + case 4: + base = '0'+128-30; + break; + } + return i + base; +} +static int chrconv_punct(int i, int base, int conv) +{ + i -= base; + switch (conv) + { + default: + case 0: + break; + case 1: + base = 0; + break; + case 2: + base = 128; + break; + } + return i + base; +} + +static int chrchar_alpha(int i, int basec, int baset, int convc, int convt, int charnum) +{ + //convert case and colour seperatly... + + i -= baset + basec; + switch (convt) + { + default: + case 0: + break; + case 1: + baset = 0; + break; + case 2: + baset = 128; + break; + + case 5: + case 6: + baset = 128*((charnum&1) == (convt-5)); + break; + } + + switch (convc) + { + default: + case 0: + break; + case 1: + basec = 'a'; + break; + case 2: + basec = 'A'; + break; + } + return i + basec + baset; +} +// #224 string(float ccase, float calpha, float cnum, string s, ...) strconv (FTE_STRINGS) +//bulk convert a string. change case or colouring. +void VM_strconv (void) +{ + int ccase, redalpha, rednum, len, i; + unsigned char resbuf[VM_STRINGTEMP_LENGTH]; + unsigned char *result = resbuf; + + VM_SAFEPARMCOUNTRANGE(3, 8, VM_strconv); + + ccase = (int) PRVM_G_FLOAT(OFS_PARM0); //0 same, 1 lower, 2 upper + redalpha = (int) PRVM_G_FLOAT(OFS_PARM1); //0 same, 1 white, 2 red, 5 alternate, 6 alternate-alternate + rednum = (int) PRVM_G_FLOAT(OFS_PARM2); //0 same, 1 white, 2 red, 3 redspecial, 4 whitespecial, 5 alternate, 6 alternate-alternate + VM_VarString(3, (char *) resbuf, sizeof(resbuf)); + len = strlen((char *) resbuf); + + for (i = 0; i < len; i++, result++) //should this be done backwards? + { + if (*result >= '0' && *result <= '9') //normal numbers... + *result = chrconv_number(*result, '0', rednum); + else if (*result >= '0'+128 && *result <= '9'+128) + *result = chrconv_number(*result, '0'+128, rednum); + else if (*result >= '0'+128-30 && *result <= '9'+128-30) + *result = chrconv_number(*result, '0'+128-30, rednum); + else if (*result >= '0'-30 && *result <= '9'-30) + *result = chrconv_number(*result, '0'-30, rednum); + + else if (*result >= 'a' && *result <= 'z') //normal numbers... + *result = chrchar_alpha(*result, 'a', 0, ccase, redalpha, i); + else if (*result >= 'A' && *result <= 'Z') //normal numbers... + *result = chrchar_alpha(*result, 'A', 0, ccase, redalpha, i); + else if (*result >= 'a'+128 && *result <= 'z'+128) //normal numbers... + *result = chrchar_alpha(*result, 'a', 128, ccase, redalpha, i); + else if (*result >= 'A'+128 && *result <= 'Z'+128) //normal numbers... + *result = chrchar_alpha(*result, 'A', 128, ccase, redalpha, i); + + else if ((*result & 127) < 16 || !redalpha) //special chars.. + *result = *result; + else if (*result < 128) + *result = chrconv_punct(*result, 0, redalpha); + else + *result = chrconv_punct(*result, 128, redalpha); + } + *result = '\0'; + + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString((char *) resbuf); +} + +// #225 string(float chars, string s, ...) strpad (FTE_STRINGS) +void VM_strpad (void) +{ + char src[VM_STRINGTEMP_LENGTH]; + char destbuf[VM_STRINGTEMP_LENGTH]; + int pad; + VM_SAFEPARMCOUNTRANGE(1, 8, VM_strpad); + pad = (int) PRVM_G_FLOAT(OFS_PARM0); + VM_VarString(1, src, sizeof(src)); + + // note: < 0 = left padding, > 0 = right padding, + // this is reverse logic of printf! + dpsnprintf(destbuf, sizeof(destbuf), "%*s", -pad, src); + + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(destbuf); +} + +// #226 string(string info, string key, string value, ...) infoadd (FTE_STRINGS) +//uses qw style \key\value strings +void VM_infoadd (void) +{ + const char *info, *key; + char value[VM_STRINGTEMP_LENGTH]; + char temp[VM_STRINGTEMP_LENGTH]; + + VM_SAFEPARMCOUNTRANGE(2, 8, VM_infoadd); + info = PRVM_G_STRING(OFS_PARM0); + key = PRVM_G_STRING(OFS_PARM1); + VM_VarString(2, value, sizeof(value)); + + strlcpy(temp, info, VM_STRINGTEMP_LENGTH); + + InfoString_SetValue(temp, VM_STRINGTEMP_LENGTH, key, value); + + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(temp); +} + +// #227 string(string info, string key) infoget (FTE_STRINGS) +//uses qw style \key\value strings +void VM_infoget (void) +{ + const char *info; + const char *key; + char value[VM_STRINGTEMP_LENGTH]; + + VM_SAFEPARMCOUNT(2, VM_infoget); + info = PRVM_G_STRING(OFS_PARM0); + key = PRVM_G_STRING(OFS_PARM1); + + InfoString_GetValue(info, key, value, VM_STRINGTEMP_LENGTH); + + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(value); +} + +//#228 float(string s1, string s2, float len) strncmp (FTE_STRINGS) +// also float(string s1, string s2) strcmp (FRIK_FILE) +void VM_strncmp (void) +{ + const char *s1, *s2; + VM_SAFEPARMCOUNTRANGE(2, 3, VM_strncmp); + s1 = PRVM_G_STRING(OFS_PARM0); + s2 = PRVM_G_STRING(OFS_PARM1); + if (prog->argc > 2) + { + PRVM_G_FLOAT(OFS_RETURN) = strncmp(s1, s2, (size_t)PRVM_G_FLOAT(OFS_PARM2)); + } + else + { + PRVM_G_FLOAT(OFS_RETURN) = strcmp(s1, s2); + } +} + +// #229 float(string s1, string s2) strcasecmp (FTE_STRINGS) +// #230 float(string s1, string s2, float len) strncasecmp (FTE_STRINGS) +void VM_strncasecmp (void) +{ + const char *s1, *s2; + VM_SAFEPARMCOUNTRANGE(2, 3, VM_strncasecmp); + s1 = PRVM_G_STRING(OFS_PARM0); + s2 = PRVM_G_STRING(OFS_PARM1); + if (prog->argc > 2) + { + PRVM_G_FLOAT(OFS_RETURN) = strncasecmp(s1, s2, (size_t)PRVM_G_FLOAT(OFS_PARM2)); + } + else + { + PRVM_G_FLOAT(OFS_RETURN) = strcasecmp(s1, s2); + } +} + +// #494 float(float caseinsensitive, string s, ...) crc16 +void VM_crc16(void) +{ + float insensitive; + static char s[VM_STRINGTEMP_LENGTH]; + VM_SAFEPARMCOUNTRANGE(2, 8, VM_hash); + insensitive = PRVM_G_FLOAT(OFS_PARM0); + VM_VarString(1, s, sizeof(s)); + PRVM_G_FLOAT(OFS_RETURN) = (unsigned short) ((insensitive ? CRC_Block_CaseInsensitive : CRC_Block) ((unsigned char *) s, strlen(s))); +} + +void VM_wasfreed (void) +{ + VM_SAFEPARMCOUNT(1, VM_wasfreed); + PRVM_G_FLOAT(OFS_RETURN) = PRVM_G_EDICT(OFS_PARM0)->priv.required->free; +} + +void VM_SetTraceGlobals(const trace_t *trace) +{ + prvm_eval_t *val; + if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_allsolid))) + val->_float = trace->allsolid; + if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_startsolid))) + val->_float = trace->startsolid; + if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_fraction))) + val->_float = trace->fraction; + if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_inwater))) + val->_float = trace->inwater; + if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_inopen))) + val->_float = trace->inopen; + if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_endpos))) + VectorCopy(trace->endpos, val->vector); + if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_plane_normal))) + VectorCopy(trace->plane.normal, val->vector); + if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_plane_dist))) + val->_float = trace->plane.dist; + if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_ent))) + val->edict = PRVM_EDICT_TO_PROG(trace->ent ? trace->ent : prog->edicts); + if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_dpstartcontents))) + val->_float = trace->startsupercontents; + if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_dphitcontents))) + val->_float = trace->hitsupercontents; + if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_dphitq3surfaceflags))) + val->_float = trace->hitq3surfaceflags; + if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_dphittexturename))) + val->string = trace->hittexture ? PRVM_SetTempString(trace->hittexture->name) : 0; } //============= @@ -4000,12 +5040,8 @@ void VM_Cmd_Init(void) // only init the stuff for the current prog VM_Files_Init(); VM_Search_Init(); + VM_Gecko_Init(); // VM_BufStr_Init(); - if(vm_polygons_initialized) - { - Mem_FreePool(&vm_polygons_pool); - vm_polygons_initialized = false; - } } void VM_Cmd_Reset(void) @@ -4013,11 +5049,190 @@ void VM_Cmd_Reset(void) CL_PurgeOwner( MENUOWNER ); VM_Search_Reset(); VM_Files_CloseAll(); + VM_Gecko_Destroy(); // VM_BufStr_ShutDown(); - if(vm_polygons_initialized) +} + +// #510 string(string input, ...) uri_escape (DP_QC_URI_ESCAPE) +// does URI escaping on a string (replace evil stuff by %AB escapes) +void VM_uri_escape (void) +{ + char src[VM_STRINGTEMP_LENGTH]; + char dest[VM_STRINGTEMP_LENGTH]; + char *p, *q; + static const char *hex = "0123456789ABCDEF"; + + VM_SAFEPARMCOUNTRANGE(1, 8, VM_uri_escape); + VM_VarString(0, src, sizeof(src)); + + for(p = src, q = dest; *p && q < dest + sizeof(dest) - 3; ++p) + { + if((*p >= 'A' && *p <= 'Z') + || (*p >= 'a' && *p <= 'z') + || (*p >= '0' && *p <= '9') + || (*p == '-') || (*p == '_') || (*p == '.') + || (*p == '!') || (*p == '~') || (*p == '*') + || (*p == '\'') || (*p == '(') || (*p == ')')) + *q++ = *p; + else + { + *q++ = '%'; + *q++ = hex[(*(unsigned char *)p >> 4) & 0xF]; + *q++ = hex[ *(unsigned char *)p & 0xF]; + } + } + *q++ = 0; + + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(dest); +} + +// #510 string(string input, ...) uri_unescape (DP_QC_URI_ESCAPE) +// does URI unescaping on a string (get back the evil stuff) +void VM_uri_unescape (void) +{ + char src[VM_STRINGTEMP_LENGTH]; + char dest[VM_STRINGTEMP_LENGTH]; + char *p, *q; + int hi, lo; + + VM_SAFEPARMCOUNTRANGE(1, 8, VM_uri_unescape); + VM_VarString(0, src, sizeof(src)); + + for(p = src, q = dest; *p; ) // no need to check size, because unescape can't expand + { + if(*p == '%') + { + if(p[1] >= '0' && p[1] <= '9') + hi = p[1] - '0'; + else if(p[1] >= 'a' && p[1] <= 'f') + hi = p[1] - 'a' + 10; + else if(p[1] >= 'A' && p[1] <= 'F') + hi = p[1] - 'A' + 10; + else + goto nohex; + if(p[2] >= '0' && p[2] <= '9') + lo = p[2] - '0'; + else if(p[2] >= 'a' && p[2] <= 'f') + lo = p[2] - 'a' + 10; + else if(p[2] >= 'A' && p[2] <= 'F') + lo = p[2] - 'A' + 10; + else + goto nohex; + if(hi != 0 || lo != 0) // don't unescape NUL bytes + *q++ = (char) (hi * 0x10 + lo); + p += 3; + continue; + } + +nohex: + // otherwise: + *q++ = *p++; + } + *q++ = 0; + + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(dest); +} + +// #502 string(string filename) whichpack (DP_QC_WHICHPACK) +// returns the name of the pack containing a file, or "" if it is not in any pack (but local or non-existant) +void VM_whichpack (void) +{ + const char *fn, *pack; + + VM_SAFEPARMCOUNT(1, VM_whichpack); + fn = PRVM_G_STRING(OFS_PARM0); + pack = FS_WhichPack(fn); + + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(pack ? pack : ""); +} + +typedef struct +{ + int prognr; + double starttime; + float id; + char buffer[MAX_INPUTLINE]; +} +uri_to_prog_t; + +static void uri_to_string_callback(int status, size_t length_received, unsigned char *buffer, void *cbdata) +{ + uri_to_prog_t *handle = (uri_to_prog_t *) cbdata; + + if(!PRVM_ProgLoaded(handle->prognr)) + { + // curl reply came too late... so just drop it + Z_Free(handle); + return; + } + + PRVM_SetProg(handle->prognr); + PRVM_Begin; + if((prog->starttime == handle->starttime) && (prog->funcoffsets.URI_Get_Callback)) + { + if(length_received >= sizeof(handle->buffer)) + length_received = sizeof(handle->buffer) - 1; + handle->buffer[length_received] = 0; + + PRVM_G_FLOAT(OFS_PARM0) = handle->id; + PRVM_G_FLOAT(OFS_PARM1) = status; + PRVM_G_INT(OFS_PARM2) = PRVM_SetTempString(handle->buffer); + PRVM_ExecuteProgram(prog->funcoffsets.URI_Get_Callback, "QC function URI_Get_Callback is missing"); + } + PRVM_End; + + Z_Free(handle); +} + +// uri_get() gets content from an URL and calls a callback "uri_get_callback" with it set as string; an unique ID of the transfer is returned +// returns 1 on success, and then calls the callback with the ID, 0 or the HTTP status code, and the received data in a string +void VM_uri_get (void) +{ + const char *url; + float id; + qboolean ret; + uri_to_prog_t *handle; + + if(!prog->funcoffsets.URI_Get_Callback) + PRVM_ERROR("uri_get called by %s without URI_Get_Callback defined", PRVM_NAME); + + VM_SAFEPARMCOUNT(2, VM_uri_get); + + url = PRVM_G_STRING(OFS_PARM0); + id = PRVM_G_FLOAT(OFS_PARM1); + handle = (uri_to_prog_t *) Z_Malloc(sizeof(*handle)); // this can't be the prog's mem pool, as curl may call the callback later! + + handle->prognr = PRVM_GetProgNr(); + handle->starttime = prog->starttime; + handle->id = id; + ret = Curl_Begin_ToMemory(url, (unsigned char *) handle->buffer, sizeof(handle->buffer), uri_to_string_callback, handle); + if(ret) { - Mem_FreePool(&vm_polygons_pool); - vm_polygons_initialized = false; + PRVM_G_INT(OFS_RETURN) = 1; + } + else + { + Z_Free(handle); + PRVM_G_INT(OFS_RETURN) = 0; } } +void VM_netaddress_resolve (void) +{ + const char *ip; + char normalized[128]; + int port; + lhnetaddress_t addr; + + VM_SAFEPARMCOUNTRANGE(1, 2, VM_netaddress_resolve); + + ip = PRVM_G_STRING(OFS_PARM0); + port = 0; + if(prog->argc > 1) + port = (int) PRVM_G_FLOAT(OFS_PARM1); + + if(LHNETADDRESS_FromString(&addr, ip, port) && LHNETADDRESS_ToString(&addr, normalized, sizeof(normalized), prog->argc > 1)) + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(normalized); + else + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(""); +}