X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fxonotic-data.pk3dir.git;a=blobdiff_plain;f=qcsrc%2Fcommon%2Futil.qc;h=a087c9faa07851db1bb0134161223772de880381;hp=c1ae4ad1aa99f430e7227b7ed34aadb9e4e5d51e;hb=2f215c603bf1b4dd44b9d166180f535c88602e9f;hpb=7bae88d09fbd53cce732e31633aea92671b43699 diff --git a/qcsrc/common/util.qc b/qcsrc/common/util.qc index c1ae4ad1aa..91d68f1ba1 100644 --- a/qcsrc/common/util.qc +++ b/qcsrc/common/util.qc @@ -1,28 +1,42 @@ #include "util.qh" #if defined(CSQC) - #include "../dpdefs/csprogsdefs.qh" #include "../client/defs.qh" #include "constants.qh" - #include "../warpzonelib/mathlib.qh" #include "../client/mutators/events.qh" #include "mapinfo.qh" - #include "notifications.qh" - #include "deathtypes.qh" + #include "notifications/all.qh" + #include #elif defined(MENUQC) #elif defined(SVQC) - #include "../dpdefs/progsdefs.qh" - #include "../dpdefs/dpextensions.qh" - #include "../warpzonelib/mathlib.qh" #include "constants.qh" #include "../server/autocvars.qh" #include "../server/defs.qh" #include "../server/mutators/events.qh" - #include "notifications.qh" - #include "deathtypes.qh" + #include "notifications/all.qh" + #include #include "mapinfo.qh" #endif +#ifdef GAMEQC +/* +* Get "real" origin, in worldspace, even if ent is attached to something else. +*/ +vector real_origin(entity ent) +{ + vector v = ((ent.absmin + ent.absmax) * 0.5); + entity e = ent.tag_entity; + + while(e) + { + v = v + ((e.absmin + e.absmax) * 0.5); + e = e.tag_entity; + } + + return v; +} +#endif + string wordwrap_buffer; void wordwrap_buffer_put(string s) @@ -40,29 +54,30 @@ string wordwrap(string s, float l) return r; } -#ifndef MENUQC -#ifndef CSQC +#ifdef SVQC +entity _wordwrap_buffer_sprint_ent; void wordwrap_buffer_sprint(string s) { wordwrap_buffer = strcat(wordwrap_buffer, s); if(s == "\n") { - sprint(self, wordwrap_buffer); + sprint(_wordwrap_buffer_sprint_ent, wordwrap_buffer); wordwrap_buffer = ""; } } -void wordwrap_sprint(string s, float l) +void wordwrap_sprint(entity to, string s, float l) { wordwrap_buffer = ""; + _wordwrap_buffer_sprint_ent = to; wordwrap_cb(s, l, wordwrap_buffer_sprint); + _wordwrap_buffer_sprint_ent = NULL; if(wordwrap_buffer != "") - sprint(self, strcat(wordwrap_buffer, "\n")); + sprint(to, strcat(wordwrap_buffer, "\n")); wordwrap_buffer = ""; return; } #endif -#endif #ifndef SVQC string draw_UseSkinFor(string pic) @@ -74,37 +89,6 @@ string draw_UseSkinFor(string pic) } #endif -string unescape(string in) -{ - float i, len; - string str, s; - - // but it doesn't seem to be necessary in my tests at least - in = strzone(in); - - len = strlen(in); - str = ""; - for(i = 0; i < len; ++i) - { - s = substring(in, i, 1); - if(s == "\\") - { - s = substring(in, i+1, 1); - if(s == "n") - str = strcat(str, "\n"); - else if(s == "\\") - str = strcat(str, "\\"); - else - str = strcat(str, substring(in, i, 2)); - ++i; - } else - str = strcat(str, s); - } - - strunzone(in); - return str; -} - void wordwrap_cb(string s, float l, void(string) callback) { string c; @@ -170,17 +154,6 @@ void wordwrap_cb(string s, float l, void(string) callback) strunzone(s); } -float dist_point_line(vector p, vector l0, vector ldir) -{ - ldir = normalize(ldir); - - // remove the component in line direction - p = p - (p * ldir) * ldir; - - // vlen of the remaining vector - return vlen(p); -} - void depthfirst(entity start, .entity up, .entity downleft, .entity right, void(entity, entity) funcPre, void(entity, entity) funcPost, entity pass) { entity e; @@ -210,266 +183,6 @@ void depthfirst(entity start, .entity up, .entity downleft, .entity right, void( } } -float median(float a, float b, float c) -{ - if(a < c) - return bound(a, b, c); - return bound(c, b, a); -} - -// converts a number to a string with the indicated number of decimals -// works for up to 10 decimals! -string ftos_decimals(float number, float decimals) -{ - // inhibit stupid negative zero - if(number == 0) - number = 0; - // we have sprintf... - return sprintf("%.*f", decimals, number); -} - -vector colormapPaletteColor(float c, float isPants) -{ - switch(c) - { - case 0: return '1.000000 1.000000 1.000000'; - case 1: return '1.000000 0.333333 0.000000'; - case 2: return '0.000000 1.000000 0.501961'; - case 3: return '0.000000 1.000000 0.000000'; - case 4: return '1.000000 0.000000 0.000000'; - case 5: return '0.000000 0.666667 1.000000'; - case 6: return '0.000000 1.000000 1.000000'; - case 7: return '0.501961 1.000000 0.000000'; - case 8: return '0.501961 0.000000 1.000000'; - case 9: return '1.000000 0.000000 1.000000'; - case 10: return '1.000000 0.000000 0.501961'; - case 11: return '0.000000 0.000000 1.000000'; - case 12: return '1.000000 1.000000 0.000000'; - case 13: return '0.000000 0.333333 1.000000'; - case 14: return '1.000000 0.666667 0.000000'; - case 15: - if(isPants) - return - '1 0 0' * (0.502 + 0.498 * sin(time / 2.7182818285 + 0.0000000000)) - + '0 1 0' * (0.502 + 0.498 * sin(time / 2.7182818285 + 2.0943951024)) - + '0 0 1' * (0.502 + 0.498 * sin(time / 2.7182818285 + 4.1887902048)); - else - return - '1 0 0' * (0.502 + 0.498 * sin(time / 3.1415926536 + 5.2359877560)) - + '0 1 0' * (0.502 + 0.498 * sin(time / 3.1415926536 + 3.1415926536)) - + '0 0 1' * (0.502 + 0.498 * sin(time / 3.1415926536 + 1.0471975512)); - default: return '0.000 0.000 0.000'; - } -} - -// unzone the string, and return it as tempstring. Safe to be called on string_null -string fstrunzone(string s) -{ - string sc; - if (!s) - return s; - sc = strcat(s, ""); - strunzone(s); - return sc; -} - -bool fexists(string f) -{ - int fh = fopen(f, FILE_READ); - if (fh < 0) - return false; - fclose(fh); - return true; -} - -// Databases (hash tables) -const float DB_BUCKETS = 8192; -void db_save(float db, string pFilename) -{ - float fh, i, n; - fh = fopen(pFilename, FILE_WRITE); - if(fh < 0) - { - print(strcat("^1Can't write DB to ", pFilename)); - return; - } - n = buf_getsize(db); - fputs(fh, strcat(ftos(DB_BUCKETS), "\n")); - for(i = 0; i < n; ++i) - fputs(fh, strcat(bufstr_get(db, i), "\n")); - fclose(fh); -} - -int db_create() -{ - return buf_create(); -} - -int db_load(string pFilename) -{ - float db, fh, i, j, n; - string l; - db = buf_create(); - if(db < 0) - return -1; - fh = fopen(pFilename, FILE_READ); - if(fh < 0) - return db; - l = fgets(fh); - if(stof(l) == DB_BUCKETS) - { - i = 0; - while((l = fgets(fh))) - { - if(l != "") - bufstr_set(db, i, l); - ++i; - } - } - else - { - // different count of buckets, or a dump? - // need to reorganize the database then (SLOW) - // - // note: we also parse the first line (l) in case the DB file is - // missing the bucket count - do - { - n = tokenizebyseparator(l, "\\"); - for(j = 2; j < n; j += 2) - db_put(db, argv(j-1), uri_unescape(argv(j))); - } - while((l = fgets(fh))); - } - fclose(fh); - return db; -} - -void db_dump(float db, string pFilename) -{ - float fh, i, j, n, m; - fh = fopen(pFilename, FILE_WRITE); - if(fh < 0) - error(strcat("Can't dump DB to ", pFilename)); - n = buf_getsize(db); - fputs(fh, "0\n"); - for(i = 0; i < n; ++i) - { - m = tokenizebyseparator(bufstr_get(db, i), "\\"); - for(j = 2; j < m; j += 2) - fputs(fh, strcat("\\", argv(j-1), "\\", argv(j), "\n")); - } - fclose(fh); -} - -void db_close(float db) -{ - buf_del(db); -} - -string db_get(float db, string pKey) -{ - float h; - h = crc16(false, pKey) % DB_BUCKETS; - return uri_unescape(infoget(bufstr_get(db, h), pKey)); -} - -void db_put(float db, string pKey, string pValue) -{ - float h; - h = crc16(false, pKey) % DB_BUCKETS; - bufstr_set(db, h, infoadd(bufstr_get(db, h), pKey, uri_escape(pValue))); -} - -void db_test() -{ - float db, i; - print("LOAD...\n"); - db = db_load("foo.db"); - print("LOADED. FILL...\n"); - for(i = 0; i < DB_BUCKETS; ++i) - db_put(db, ftos(random()), "X"); - print("FILLED. SAVE...\n"); - db_save(db, "foo.db"); - print("SAVED. CLOSE...\n"); - db_close(db); - print("CLOSED.\n"); -} - -// Multiline text file buffers -int buf_load(string pFilename) -{ - float buf, fh, i; - string l; - buf = buf_create(); - if(buf < 0) - return -1; - fh = fopen(pFilename, FILE_READ); - if(fh < 0) - { - buf_del(buf); - return -1; - } - i = 0; - while((l = fgets(fh))) - { - bufstr_set(buf, i, l); - ++i; - } - fclose(fh); - return buf; -} - -void buf_save(float buf, string pFilename) -{ - float fh, i, n; - fh = fopen(pFilename, FILE_WRITE); - if(fh < 0) - error(strcat("Can't write buf to ", pFilename)); - n = buf_getsize(buf); - for(i = 0; i < n; ++i) - fputs(fh, strcat(bufstr_get(buf, i), "\n")); - fclose(fh); -} - -string format_time(float seconds) -{ - float days, hours, minutes; - seconds = floor(seconds + 0.5); - days = floor(seconds / 864000); - seconds -= days * 864000; - hours = floor(seconds / 36000); - seconds -= hours * 36000; - minutes = floor(seconds / 600); - seconds -= minutes * 600; - if (days > 0) - return sprintf(_("%d days, %02d:%02d:%02d"), days, hours, minutes, seconds); - else - return sprintf(_("%02d:%02d:%02d"), hours, minutes, seconds); -} - -string mmsss(float tenths) -{ - float minutes; - string s; - tenths = floor(tenths + 0.5); - minutes = floor(tenths / 600); - tenths -= minutes * 600; - s = ftos(1000 + tenths); - return strcat(ftos(minutes), ":", substring(s, 1, 2), ".", substring(s, 3, 1)); -} - -string mmssss(float hundredths) -{ - float minutes; - string s; - hundredths = floor(hundredths + 0.5); - minutes = floor(hundredths / 6000); - hundredths -= minutes * 6000; - s = ftos(10000 + hundredths); - return strcat(ftos(minutes), ":", substring(s, 1, 2), ".", substring(s, 3, 2)); -} - string ScoreString(int pFlags, float pValue) { string valstr; @@ -514,13 +227,13 @@ string ScoreString(int pFlags, float pValue) float lengthLogTable[128]; -float invertLengthLog(float x) +float invertLengthLog(float dist) { int l, r, m; - if(x >= lengthLogTable[127]) + if(dist >= lengthLogTable[127]) return 127; - if(x <= lengthLogTable[0]) + if(dist <= lengthLogTable[0]) return 0; l = 0; @@ -529,15 +242,15 @@ float invertLengthLog(float x) while(r - l > 1) { m = floor((l + r) / 2); - if(lengthLogTable[m] < x) + if(lengthLogTable[m] < dist) l = m; else r = m; } // now: r is >=, l is < - float lerr = (x - lengthLogTable[l]); - float rerr = (lengthLogTable[r] - x); + float lerr = (dist - lengthLogTable[l]); + float rerr = (lengthLogTable[r] - dist); if(lerr < rerr) return l; return r; @@ -549,26 +262,26 @@ vector decompressShortVector(int data) if(data == 0) return '0 0 0'; float p = (data & 0xF000) / 0x1000; - float y = (data & 0x0F80) / 0x80; + float q = (data & 0x0F80) / 0x80; int len = (data & 0x007F); - //print("\ndecompress: p ", ftos(p)); print("y ", ftos(y)); print("len ", ftos(len), "\n"); + //print("\ndecompress: p ", ftos(p)); print("q ", ftos(q)); print("len ", ftos(len), "\n"); if(p == 0) { out.x = 0; out.y = 0; - if(y == 31) + if(q == 31) out.z = -1; else out.z = +1; } else { - y = .19634954084936207740 * y; + q = .19634954084936207740 * q; p = .19634954084936207740 * p - 1.57079632679489661922; - out.x = cos(y) * cos(p); - out.y = sin(y) * cos(p); + out.x = cos(q) * cos(p); + out.y = sin(q) * cos(p); out.z = -sin(p); } @@ -581,7 +294,7 @@ float compressShortVector(vector vec) { vector ang; float p, y, len; - if(vlen(vec) == 0) + if(vec == '0 0 0') return 0; //print("compress: ", vtos(vec), "\n"); ang = vectoangles(vec); @@ -609,10 +322,10 @@ float compressShortVector(vector vec) return (p * 0x1000) + (y * 0x80) + len; } -void compressShortVector_init() +STATIC_INIT(compressShortVector) { float l = 1; - float f = pow(2, 1/8); + float f = (2 ** (1/8)); int i; for(i = 0; i < 128; ++i) { @@ -622,21 +335,21 @@ void compressShortVector_init() if(cvar("developer")) { - print("Verifying vector compression table...\n"); + LOG_INFO("Verifying vector compression table...\n"); for(i = 0x0F00; i < 0xFFFF; ++i) if(i != compressShortVector(decompressShortVector(i))) { - print("BROKEN vector compression: ", ftos(i)); - print(" -> ", vtos(decompressShortVector(i))); - print(" -> ", ftos(compressShortVector(decompressShortVector(i)))); - print("\n"); + LOG_INFO("BROKEN vector compression: ", ftos(i)); + LOG_INFO(" -> ", vtos(decompressShortVector(i))); + LOG_INFO(" -> ", ftos(compressShortVector(decompressShortVector(i)))); + LOG_INFO("\n"); error("b0rk"); } - print("Done.\n"); + LOG_INFO("Done.\n"); } } -#ifndef MENUQC +#ifdef GAMEQC float CheckWireframeBox(entity forent, vector v0, vector dvx, vector dvy, vector dvz) { traceline(v0, v0 + dvx, true, forent); if(trace_fraction < 1) return 0; @@ -683,6 +396,9 @@ string fixPriorityList(string order, float from, float to, float subtract, float n = tokenize_console(neworder); for(w = to; w >= from; --w) { + int wflags = Weapons_from(w).spawnflags; + if((wflags & WEP_FLAG_HIDDEN) && (wflags & WEP_FLAG_MUTATORBLOCKED) && !(wflags & WEP_FLAG_NORMAL)) + continue; for(i = 0; i < n; ++i) if(stof(argv(i)) == w) break; @@ -697,11 +413,11 @@ string fixPriorityList(string order, float from, float to, float subtract, float string mapPriorityList(string order, string(string) mapfunc) { string neworder; - float i, n; + float n; n = tokenize_console(order); neworder = ""; - for(i = 0; i < n; ++i) + for(float i = 0; i < n; ++i) neworder = strcat(neworder, mapfunc(argv(i)), " "); return substring(neworder, 0, strlen(neworder) - 1); @@ -709,15 +425,12 @@ string mapPriorityList(string order, string(string) mapfunc) string swapInPriorityList(string order, float i, float j) { - string s; - float w, n; - - n = tokenize_console(order); + float n = tokenize_console(order); if(i >= 0 && i < n && j >= 0 && j < n && i != j) { - s = ""; - for(w = 0; w < n; ++w) + string s = ""; + for(float w = 0; w < n; ++w) { if(w == i) s = strcat(s, argv(j), " "); @@ -732,24 +445,7 @@ string swapInPriorityList(string order, float i, float j) return order; } -float cvar_value_issafe(string s) -{ - if(strstrofs(s, "\"", 0) >= 0) - return 0; - if(strstrofs(s, "\\", 0) >= 0) - return 0; - if(strstrofs(s, ";", 0) >= 0) - return 0; - if(strstrofs(s, "$", 0) >= 0) - return 0; - if(strstrofs(s, "\r", 0) >= 0) - return 0; - if(strstrofs(s, "\n", 0) >= 0) - return 0; - return 1; -} - -#ifndef MENUQC +#ifdef GAMEQC void get_mi_min_max(float mode) { vector mi, ma; @@ -773,7 +469,7 @@ void get_mi_min_max(float mode) mi_min = mi; mi_max = ma; - MapInfo_Get_ByName(mi_shortname, 0, 0); + MapInfo_Get_ByName(mi_shortname, 0, NULL); if(MapInfo_Map_mins.x < MapInfo_Map_maxs.x) { mi_min = MapInfo_Map_mins; @@ -790,7 +486,7 @@ void get_mi_min_max(float mode) '0 1 0' * ma.y + '0 0 1' * ma.z, '1 0 0' * ma.x, MOVE_WORLDONLY, - world); + NULL); if(!trace_startsolid) mi_min.x = trace_endpos.x; @@ -799,7 +495,7 @@ void get_mi_min_max(float mode) '1 0 0' * ma.x + '0 0 1' * ma.z, '0 1 0' * ma.y, MOVE_WORLDONLY, - world); + NULL); if(!trace_startsolid) mi_min.y = trace_endpos.y; @@ -808,7 +504,7 @@ void get_mi_min_max(float mode) '1 0 0' * ma.x + '0 1 0' * ma.y, '0 0 1' * ma.z, MOVE_WORLDONLY, - world); + NULL); if(!trace_startsolid) mi_min.z = trace_endpos.z; @@ -817,7 +513,7 @@ void get_mi_min_max(float mode) '0 1 0' * ma.y + '0 0 1' * ma.z, '1 0 0' * mi.x, MOVE_WORLDONLY, - world); + NULL); if(!trace_startsolid) mi_max.x = trace_endpos.x; @@ -826,7 +522,7 @@ void get_mi_min_max(float mode) '1 0 0' * ma.x + '0 0 1' * ma.z, '0 1 0' * mi.y, MOVE_WORLDONLY, - world); + NULL); if(!trace_startsolid) mi_max.y = trace_endpos.y; @@ -835,7 +531,7 @@ void get_mi_min_max(float mode) '1 0 0' * ma.x + '0 1 0' * ma.y, '0 0 1' * mi.z, MOVE_WORLDONLY, - world); + NULL); if(!trace_startsolid) mi_max.z = trace_endpos.z; } @@ -888,31 +584,32 @@ void get_mi_min_max_texcoords(float mode) float cvar_settemp(string tmp_cvar, string tmp_value) { float created_saved_value; - entity e; created_saved_value = 0; if (!(tmp_cvar || tmp_value)) { - dprint("Error: Invalid usage of cvar_settemp(string, string); !\n"); + LOG_TRACE("Error: Invalid usage of cvar_settemp(string, string); !"); return 0; } if(!cvar_type(tmp_cvar)) { - printf("Error: cvar %s doesn't exist!\n", tmp_cvar); + LOG_INFOF("Error: cvar %s doesn't exist!\n", tmp_cvar); return 0; } - for(e = world; (e = find(e, classname, "saved_cvar_value")); ) - if(e.netname == tmp_cvar) - created_saved_value = -1; // skip creation + IL_EACH(g_saved_cvars, it.netname == tmp_cvar, + { + created_saved_value = -1; // skip creation + break; // no need to continue + }); if(created_saved_value != -1) { // creating a new entity to keep track of this cvar - e = spawn(); - e.classname = "saved_cvar_value"; + entity e = new_pure(saved_cvar_value); + IL_PUSH(g_saved_cvars, e); e.netname = strzone(tmp_cvar); e.message = strzone(cvar_string(tmp_cvar)); created_saved_value = 1; @@ -924,275 +621,94 @@ float cvar_settemp(string tmp_cvar, string tmp_value) return created_saved_value; } -float cvar_settemp_restore() +int cvar_settemp_restore() { - float i = 0; - entity e = world; + int j = 0; + // FIXME this new-style loop fails! +#if 0 + FOREACH_ENTITY_CLASS("saved_cvar_value", true, + { + if(cvar_type(it.netname)) + { + cvar_set(it.netname, it.message); + strunzone(it.netname); + strunzone(it.message); + delete(it); + ++j; + } + else + LOG_INFOF("Error: cvar %s doesn't exist anymore! It can still be restored once it's manually recreated.\n", it.netname); + }); + +#else + entity e = NULL; while((e = find(e, classname, "saved_cvar_value"))) { if(cvar_type(e.netname)) { cvar_set(e.netname, e.message); - remove(e); - ++i; + delete(e); + ++j; } else - printf("Error: cvar %s doesn't exist anymore! It can still be restored once it's manually recreated.\n", e.netname); + print(sprintf("Error: cvar %s doesn't exist anymore! It can still be restored once it's manually recreated.\n", e.netname)); } +#endif - return i; + return j; } -float almost_equals(float a, float b) +bool isCaretEscaped(string theText, float pos) { - float eps; - eps = (max(a, -a) + max(b, -b)) * 0.001; - if(a - b < eps && b - a < eps) - return true; - return false; -} - -float almost_in_bounds(float a, float b, float c) -{ - float eps; - eps = (max(a, -a) + max(c, -c)) * 0.001; - if(a > c) - eps = -eps; - return b == median(a - eps, b, c + eps); + int i = 0; + while(pos - i >= 1 && substring(theText, pos - i - 1, 1) == "^") + ++i; + return (i & 1); } -float power2of(float e) -{ - return pow(2, e); -} -float log2of(float x) +int skipIncompleteTag(string theText, float pos, int len) { - // NOTE: generated code - if(x > 2048) - if(x > 131072) - if(x > 1048576) - if(x > 4194304) - return 23; - else - if(x > 2097152) - return 22; - else - return 21; - else - if(x > 524288) - return 20; - else - if(x > 262144) - return 19; - else - return 18; - else - if(x > 16384) - if(x > 65536) - return 17; - else - if(x > 32768) - return 16; - else - return 15; - else - if(x > 8192) - return 14; - else - if(x > 4096) - return 13; - else - return 12; - else - if(x > 32) - if(x > 256) - if(x > 1024) - return 11; - else - if(x > 512) - return 10; - else - return 9; - else - if(x > 128) - return 8; - else - if(x > 64) - return 7; - else - return 6; - else - if(x > 4) - if(x > 16) - return 5; - else - if(x > 8) - return 4; - else - return 3; - else - if(x > 2) - return 2; - else - if(x > 1) - return 1; - else - return 0; -} + int tag_start = -1; -float rgb_mi_ma_to_hue(vector rgb, float mi, float ma) -{ - if(mi == ma) - return 0; - else if(ma == rgb.x) + if(substring(theText, pos - 1, 1) == "^") { - if(rgb.y >= rgb.z) - return (rgb.y - rgb.z) / (ma - mi); - else - return (rgb.y - rgb.z) / (ma - mi) + 6; - } - else if(ma == rgb.y) - return (rgb.z - rgb.x) / (ma - mi) + 2; - else // if(ma == rgb_z) - return (rgb.x - rgb.y) / (ma - mi) + 4; -} - -vector hue_mi_ma_to_rgb(float hue, float mi, float ma) -{ - vector rgb; - - hue -= 6 * floor(hue / 6); + if(isCaretEscaped(theText, pos - 1) || pos >= len) + return 0; - //else if(ma == rgb_x) - // hue = 60 * (rgb_y - rgb_z) / (ma - mi); - if(hue <= 1) - { - rgb.x = ma; - rgb.y = hue * (ma - mi) + mi; - rgb.z = mi; - } - //else if(ma == rgb_y) - // hue = 60 * (rgb_z - rgb_x) / (ma - mi) + 120; - else if(hue <= 2) - { - rgb.x = (2 - hue) * (ma - mi) + mi; - rgb.y = ma; - rgb.z = mi; - } - else if(hue <= 3) - { - rgb.x = mi; - rgb.y = ma; - rgb.z = (hue - 2) * (ma - mi) + mi; - } - //else // if(ma == rgb_z) - // hue = 60 * (rgb_x - rgb_y) / (ma - mi) + 240; - else if(hue <= 4) - { - rgb.x = mi; - rgb.y = (4 - hue) * (ma - mi) + mi; - rgb.z = ma; + int ch = str2chr(theText, pos); + if(ch >= '0' && ch <= '9') + return 1; // ^[0-9] color code found + else if (ch == 'x') + tag_start = pos - 1; // ^x tag found + else + return 0; } - else if(hue <= 5) + else { - rgb.x = (hue - 4) * (ma - mi) + mi; - rgb.y = mi; - rgb.z = ma; + for(int i = 2; pos - i >= 0 && i <= 4; ++i) + { + if(substring(theText, pos - i, 2) == "^x") + { + tag_start = pos - i; // ^x tag found + break; + } + } } - //else if(ma == rgb_x) - // hue = 60 * (rgb_y - rgb_z) / (ma - mi); - else // if(hue <= 6) + + if(tag_start >= 0) { - rgb.x = ma; - rgb.y = mi; - rgb.z = (6 - hue) * (ma - mi) + mi; + if(tag_start + 5 < len) + if(IS_HEXDIGIT(substring(theText, tag_start + 2, 1))) + if(IS_HEXDIGIT(substring(theText, tag_start + 3, 1))) + if(IS_HEXDIGIT(substring(theText, tag_start + 4, 1))) + { + if(!isCaretEscaped(theText, tag_start)) + return 5 - (pos - tag_start); // ^xRGB color code found + } } - - return rgb; -} - -vector rgb_to_hsv(vector rgb) -{ - float mi, ma; - vector hsv; - - mi = min(rgb.x, rgb.y, rgb.z); - ma = max(rgb.x, rgb.y, rgb.z); - - hsv.x = rgb_mi_ma_to_hue(rgb, mi, ma); - hsv.z = ma; - - if(ma == 0) - hsv.y = 0; - else - hsv.y = 1 - mi/ma; - - return hsv; -} - -vector hsv_to_rgb(vector hsv) -{ - return hue_mi_ma_to_rgb(hsv.x, hsv.z * (1 - hsv.y), hsv.z); -} - -vector rgb_to_hsl(vector rgb) -{ - float mi, ma; - vector hsl; - - mi = min(rgb.x, rgb.y, rgb.z); - ma = max(rgb.x, rgb.y, rgb.z); - - hsl.x = rgb_mi_ma_to_hue(rgb, mi, ma); - - hsl.z = 0.5 * (mi + ma); - if(mi == ma) - hsl.y = 0; - else if(hsl.z <= 0.5) - hsl.y = (ma - mi) / (2*hsl.z); - else // if(hsl_z > 0.5) - hsl.y = (ma - mi) / (2 - 2*hsl.z); - - return hsl; -} - -vector hsl_to_rgb(vector hsl) -{ - float mi, ma, maminusmi; - - if(hsl.z <= 0.5) - maminusmi = hsl.y * 2 * hsl.z; - else - maminusmi = hsl.y * (2 - 2 * hsl.z); - - // hsl_z = 0.5 * mi + 0.5 * ma - // maminusmi = - mi + ma - mi = hsl.z - 0.5 * maminusmi; - ma = hsl.z + 0.5 * maminusmi; - - return hue_mi_ma_to_rgb(hsl.x, mi, ma); -} - -string rgb_to_hexcolor(vector rgb) -{ - return - strcat( - "^x", - DEC_TO_HEXDIGIT(floor(rgb.x * 15 + 0.5)), - DEC_TO_HEXDIGIT(floor(rgb.y * 15 + 0.5)), - DEC_TO_HEXDIGIT(floor(rgb.z * 15 + 0.5)) - ); + return 0; } -// requires that m2>m1 in all coordinates, and that m4>m3 -float boxesoverlap(vector m1, vector m2, vector m3, vector m4) {return m2_x >= m3_x && m1_x <= m4_x && m2_y >= m3_y && m1_y <= m4_y && m2_z >= m3_z && m1_z <= m4_z;} - -// requires the same, but is a stronger condition -float boxinsidebox(vector smins, vector smaxs, vector bmins, vector bmaxs) {return smins.x >= bmins.x && smaxs.x <= bmaxs.x && smins.y >= bmins.y && smaxs.y <= bmaxs.y && smins.z >= bmins.z && smaxs.z <= bmaxs.z;} - -#ifndef MENUQC -#endif - float textLengthUpToWidth(string theText, float maxWidth, vector theSize, textLengthUpToWidth_widthFunction_t w) { // STOP. @@ -1203,57 +719,25 @@ float textLengthUpToWidth(string theText, float maxWidth, vector theSize, textLe if(w(theText, theSize) <= maxWidth) return strlen(theText); // yeah! + bool colors = (w("^7", theSize) == 0); + // binary search for right place to cut string - float ch; - float left, right, middle; // this always works + int len, left, right, middle; left = 0; - right = strlen(theText); // this always fails + right = len = strlen(theText); + int ofs = 0; do { middle = floor((left + right) / 2); - if(w(substring(theText, 0, middle), theSize) <= maxWidth) - left = middle; + if(colors) + ofs = skipIncompleteTag(theText, middle, len); + if(w(substring(theText, 0, middle + ofs), theSize) <= maxWidth) + left = middle + ofs; else right = middle; } while(left < right - 1); - if(w("^7", theSize) == 0) // detect color codes support in the width function - { - // NOTE: when color codes are involved, this binary search is, - // mathematically, BROKEN. However, it is obviously guaranteed to - // terminate, as the range still halves each time - but nevertheless, it is - // guaranteed that it finds ONE valid cutoff place (where "left" is in - // range, and "right" is outside). - - // terencehill: the following code detects truncated ^xrgb tags (e.g. ^x or ^x4) - // and decrease left on the basis of the chars detected of the truncated tag - // Even if the ^xrgb tag is not complete/correct, left is decreased - // (sometimes too much but with a correct result) - // it fixes also ^[0-9] - while(left >= 1 && substring(theText, left-1, 1) == "^") - left-=1; - - if (left >= 2 && substring(theText, left-2, 2) == "^x") // ^x/ - left-=2; - else if (left >= 3 && substring(theText, left-3, 2) == "^x") - { - ch = str2chr(theText, left-1); - if( (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F') ) // ^xr/ - left-=3; - } - else if (left >= 4 && substring(theText, left-4, 2) == "^x") - { - ch = str2chr(theText, left-2); - if ( (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F') ) - { - ch = str2chr(theText, left-1); - if ( (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F') ) // ^xrg/ - left-=4; - } - } - } - return left; } @@ -1267,57 +751,25 @@ float textLengthUpToLength(string theText, float maxWidth, textLengthUpToLength_ if(w(theText) <= maxWidth) return strlen(theText); // yeah! + bool colors = (w("^7") == 0); + // binary search for right place to cut string - float ch; - float left, right, middle; // this always works + int len, left, right, middle; left = 0; - right = strlen(theText); // this always fails + right = len = strlen(theText); + int ofs = 0; do { middle = floor((left + right) / 2); - if(w(substring(theText, 0, middle)) <= maxWidth) - left = middle; + if(colors) + ofs = skipIncompleteTag(theText, middle, len); + if(w(substring(theText, 0, middle + ofs)) <= maxWidth) + left = middle + ofs; else right = middle; } while(left < right - 1); - if(w("^7") == 0) // detect color codes support in the width function - { - // NOTE: when color codes are involved, this binary search is, - // mathematically, BROKEN. However, it is obviously guaranteed to - // terminate, as the range still halves each time - but nevertheless, it is - // guaranteed that it finds ONE valid cutoff place (where "left" is in - // range, and "right" is outside). - - // terencehill: the following code detects truncated ^xrgb tags (e.g. ^x or ^x4) - // and decrease left on the basis of the chars detected of the truncated tag - // Even if the ^xrgb tag is not complete/correct, left is decreased - // (sometimes too much but with a correct result) - // it fixes also ^[0-9] - while(left >= 1 && substring(theText, left-1, 1) == "^") - left-=1; - - if (left >= 2 && substring(theText, left-2, 2) == "^x") // ^x/ - left-=2; - else if (left >= 3 && substring(theText, left-3, 2) == "^x") - { - ch = str2chr(theText, left-1); - if( (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F') ) // ^xr/ - left-=3; - } - else if (left >= 4 && substring(theText, left-4, 2) == "^x") - { - ch = str2chr(theText, left-2); - if ( (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F') ) - { - ch = str2chr(theText, left-1); - if ( (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F') ) // ^xrg/ - left-=4; - } - } - } - return left; } @@ -1327,8 +779,7 @@ string find_last_color_code(string s) if (start == -1) // no caret found return ""; int len = strlen(s)-1; - int i; - for(i = len; i >= start; --i) + for(int i = len; i >= start; --i) { if(substring(s, i, 1) != "^") continue; @@ -1341,14 +792,14 @@ string find_last_color_code(string s) if (carets & 1) { if(i+1 <= len) - if(strstrofs("0123456789", substring(s, i+1, 1), 0) >= 0) + if(IS_DIGIT(substring(s, i+1, 1))) return substring(s, i, 2); if(i+4 <= len) if(substring(s, i+1, 1) == "x") - if(strstrofs("0123456789abcdefABCDEF", substring(s, i+2, 1), 0) >= 0) - if(strstrofs("0123456789abcdefABCDEF", substring(s, i+3, 1), 0) >= 0) - if(strstrofs("0123456789abcdefABCDEF", substring(s, i+4, 1), 0) >= 0) + if(IS_HEXDIGIT(substring(s, i + 2, 1))) + if(IS_HEXDIGIT(substring(s, i + 3, 1))) + if(IS_HEXDIGIT(substring(s, i + 4, 1))) return substring(s, i, 5); } i -= carets; // this also skips one char before the carets @@ -1465,7 +916,7 @@ string textShortenToLength(string theText, float maxWidth, textLengthUpToLength_ return strcat(substring(theText, 0, textLengthUpToLength(theText, maxWidth - tw("..."), tw)), "..."); } -float isGametypeInFilter(float gt, float tp, float ts, string pattern) +float isGametypeInFilter(Gametype gt, float tp, float ts, string pattern) { string subpattern, subpattern2, subpattern3, subpattern4; subpattern = strcat(",", MapInfo_Type_ToString(gt), ","); @@ -1511,121 +962,6 @@ float isGametypeInFilter(float gt, float tp, float ts, string pattern) return 1; } -void shuffle(float n, swapfunc_t swap, entity pass) -{ - float i, j; - for(i = 1; i < n; ++i) - { - // swap i-th item at a random position from 0 to i - // proof for even distribution: - // n = 1: obvious - // n -> n+1: - // item n+1 gets at any position with chance 1/(n+1) - // all others will get their 1/n chance reduced by factor n/(n+1) - // to be on place n+1, their chance will be 1/(n+1) - // 1/n * n/(n+1) = 1/(n+1) - // q.e.d. - j = floor(random() * (i + 1)); - if(j != i) - swap(j, i, pass); - } -} - -string substring_range(string s, float b, float e) -{ - return substring(s, b, e - b); -} - -string swapwords(string str, float i, float j) -{ - float n; - string s1, s2, s3, s4, s5; - float si, ei, sj, ej, s0, en; - n = tokenizebyseparator(str, " "); // must match g_maplist processing in ShuffleMaplist and "shuffle" - si = argv_start_index(i); - sj = argv_start_index(j); - ei = argv_end_index(i); - ej = argv_end_index(j); - s0 = argv_start_index(0); - en = argv_end_index(n-1); - s1 = substring_range(str, s0, si); - s2 = substring_range(str, si, ei); - s3 = substring_range(str, ei, sj); - s4 = substring_range(str, sj, ej); - s5 = substring_range(str, ej, en); - return strcat(s1, s4, s3, s2, s5); -} - -string _shufflewords_str; -void _shufflewords_swapfunc(float i, float j, entity pass) -{ - _shufflewords_str = swapwords(_shufflewords_str, i, j); -} -string shufflewords(string str) -{ - float n; - _shufflewords_str = str; - n = tokenizebyseparator(str, " "); - shuffle(n, _shufflewords_swapfunc, world); - str = _shufflewords_str; - _shufflewords_str = string_null; - return str; -} - -vector solve_quadratic(float a, float b, float c) // ax^2 + bx + c = 0 -{ - vector v; - float D; - v = '0 0 0'; - if(a == 0) - { - if(b != 0) - { - v.x = v.y = -c / b; - v.z = 1; - } - else - { - if(c == 0) - { - // actually, every number solves the equation! - v.z = 1; - } - } - } - else - { - D = b*b - 4*a*c; - if(D >= 0) - { - D = sqrt(D); - if(a > 0) // put the smaller solution first - { - v.x = ((-b)-D) / (2*a); - v.y = ((-b)+D) / (2*a); - } - else - { - v.x = (-b+D) / (2*a); - v.y = (-b-D) / (2*a); - } - v.z = 1; - } - else - { - // complex solutions! - D = sqrt(-D); - v.x = -b / (2*a); - if(a > 0) - v.y = D / (2*a); - else - v.y = -D / (2*a); - v.z = 0; - } - } - return v; -} - vector solve_shotdirection(vector myorg, vector myvel, vector eorg, vector evel, float spd, float newton_style) { vector ret; @@ -1731,26 +1067,25 @@ vector get_shotvelocity(vector myvel, vector mydir, float spd, float newton_styl float compressShotOrigin(vector v) { - float x, y, z; - x = rint(v.x * 2); - y = rint(v.y * 4) + 128; - z = rint(v.z * 4) + 128; - if(x > 255 || x < 0) + float rx = rint(v.x * 2); + float ry = rint(v.y * 4) + 128; + float rz = rint(v.z * 4) + 128; + if(rx > 255 || rx < 0) { - print("shot origin ", vtos(v), " x out of bounds\n"); - x = bound(0, x, 255); + LOG_DEBUG("shot origin ", vtos(v), " x out of bounds\n"); + rx = bound(0, rx, 255); } - if(y > 255 || y < 0) + if(ry > 255 || ry < 0) { - print("shot origin ", vtos(v), " y out of bounds\n"); - y = bound(0, y, 255); + LOG_DEBUG("shot origin ", vtos(v), " y out of bounds\n"); + ry = bound(0, ry, 255); } - if(z > 255 || z < 0) + if(rz > 255 || rz < 0) { - print("shot origin ", vtos(v), " z out of bounds\n"); - z = bound(0, z, 255); + LOG_DEBUG("shot origin ", vtos(v), " z out of bounds\n"); + rz = bound(0, rz, 255); } - return x * 0x10000 + y * 0x100 + z; + return rx * 0x10000 + ry * 0x100 + rz; } vector decompressShotOrigin(int f) { @@ -1761,95 +1096,12 @@ vector decompressShotOrigin(int f) return v; } -void heapsort(float n, swapfunc_t swap, comparefunc_t cmp, entity pass) -{ - float start, end, root, child; - - // heapify - start = floor((n - 2) / 2); - while(start >= 0) - { - // siftdown(start, count-1); - root = start; - while(root * 2 + 1 <= n-1) - { - child = root * 2 + 1; - if(child < n-1) - if(cmp(child, child+1, pass) < 0) - ++child; - if(cmp(root, child, pass) < 0) - { - swap(root, child, pass); - root = child; - } - else - break; - } - // end of siftdown - --start; - } - - // extract - end = n - 1; - while(end > 0) - { - swap(0, end, pass); - --end; - // siftdown(0, end); - root = 0; - while(root * 2 + 1 <= end) - { - child = root * 2 + 1; - if(child < end && cmp(child, child+1, pass) < 0) - ++child; - if(cmp(root, child, pass) < 0) - { - swap(root, child, pass); - root = child; - } - else - break; - } - // end of siftdown - } -} - -void RandomSelection_Init() -{ - RandomSelection_totalweight = 0; - RandomSelection_chosen_ent = world; - RandomSelection_chosen_float = 0; - RandomSelection_chosen_string = string_null; - RandomSelection_best_priority = -1; -} -void RandomSelection_Add(entity e, float f, string s, float weight, float priority) -{ - if(priority > RandomSelection_best_priority) - { - RandomSelection_best_priority = priority; - RandomSelection_chosen_ent = e; - RandomSelection_chosen_float = f; - RandomSelection_chosen_string = s; - RandomSelection_totalweight = weight; - } - else if(priority == RandomSelection_best_priority) - { - RandomSelection_totalweight += weight; - if(random() * RandomSelection_totalweight <= weight) - { - RandomSelection_chosen_ent = e; - RandomSelection_chosen_float = f; - RandomSelection_chosen_string = s; - } - } -} - -#ifndef MENUQC +#ifdef GAMEQC vector healtharmor_maxdamage(float h, float a, float armorblock, int deathtype) { // NOTE: we'll always choose the SMALLER value... float healthdamage, armordamage, armorideal; - if (deathtype == DEATH_DROWN) // Why should armor help here... + if (DEATH_IS(deathtype, DEATH_DROWN)) // Why should armor help here... armorblock = 0; vector v; healthdamage = (h - 1) / (1 - armorblock); // damage we can take if we could use more health @@ -1872,7 +1124,7 @@ vector healtharmor_maxdamage(float h, float a, float armorblock, int deathtype) vector healtharmor_applydamage(float a, float armorblock, int deathtype, float damage) { vector v; - if (deathtype == DEATH_DROWN) // Why should armor help here... + if (DEATH_IS(deathtype, DEATH_DROWN)) // Why should armor help here... armorblock = 0; v.y = bound(0, damage * armorblock, a); // save v.x = bound(0, damage - v.y, damage); // take @@ -1893,100 +1145,6 @@ string getcurrentmod() return argv(n - 1); } -#ifndef MENUQC -#ifdef CSQC -int ReadInt24_t() -{ - int v = ReadShort() * 256; // note: this is signed - v += ReadByte(); // note: this is unsigned - return v; -} -vector ReadInt48_t() -{ - vector v; - v.x = ReadInt24_t(); - v.y = ReadInt24_t(); - v.z = 0; - return v; -} -vector ReadInt72_t() -{ - vector v; - v.x = ReadInt24_t(); - v.y = ReadInt24_t(); - v.z = ReadInt24_t(); - return v; -} -#else -void WriteInt24_t(float dst, float val) -{ - float v; - WriteShort(dst, (v = floor(val / 256))); - WriteByte(dst, val - v * 256); // 0..255 -} -void WriteInt48_t(float dst, vector val) -{ - WriteInt24_t(dst, val.x); - WriteInt24_t(dst, val.y); -} -void WriteInt72_t(float dst, vector val) -{ - WriteInt24_t(dst, val.x); - WriteInt24_t(dst, val.y); - WriteInt24_t(dst, val.z); -} -#endif -#endif - -float float2range11(float f) -{ - // continuous function mapping all reals into -1..1 - return f / (fabs(f) + 1); -} - -float float2range01(float f) -{ - // continuous function mapping all reals into 0..1 - return 0.5 + 0.5 * float2range11(f); -} - -// from the GNU Scientific Library -float gsl_ran_gaussian_lastvalue; -float gsl_ran_gaussian_lastvalue_set; -float gsl_ran_gaussian(float sigma) -{ - float a, b; - if(gsl_ran_gaussian_lastvalue_set) - { - gsl_ran_gaussian_lastvalue_set = 0; - return sigma * gsl_ran_gaussian_lastvalue; - } - else - { - a = random() * 2 * M_PI; - b = sqrt(-2 * log(random())); - gsl_ran_gaussian_lastvalue = cos(a) * b; - gsl_ran_gaussian_lastvalue_set = 1; - return sigma * sin(a) * b; - } -} - -string car(string s) -{ - float o; - o = strstrofs(s, " ", 0); - if(o < 0) - return s; - return substring(s, 0, o); -} -string cdr(string s) -{ - float o; - o = strstrofs(s, " ", 0); - if(o < 0) - return string_null; - return substring(s, o + 1, strlen(s) - (o + 1)); -} float matchacl(string acl, string str) { string t, s; @@ -2020,14 +1178,6 @@ float matchacl(string acl, string str) } return r; } -float startsWith(string haystack, string needle) -{ - return substring(haystack, 0, strlen(needle)) == needle; -} -float startsWithNocase(string haystack, string needle) -{ - return strcasecmp(substring(haystack, 0, strlen(needle)), needle) == 0; -} string get_model_datafilename(string m, float sk, string fil) { @@ -2060,8 +1210,9 @@ float get_model_parameters(string m, float sk) get_model_parameters_bone_aimweight[i] = 0; } get_model_parameters_fixbone = 0; + get_model_parameters_hidden = false; -#ifndef MENUQC +#ifdef GAMEQC MUTATOR_CALLHOOK(ClearModelParams); #endif @@ -2126,7 +1277,7 @@ float get_model_parameters(string m, float sk) get_model_parameters_bone_upperbody = s; if(c == "bone_weapon") get_model_parameters_bone_weapon = s; - #ifndef MENUQC + #ifdef GAMEQC MUTATOR_CALLHOOK(GetModelParams, c, s); #endif for(int i = 0; i < MAX_AIM_BONES; ++i) @@ -2137,6 +1288,8 @@ float get_model_parameters(string m, float sk) } if(c == "fixbone") get_model_parameters_fixbone = stof(s); + if(c == "hidden") + get_model_parameters_hidden = stob(s); } while((s = fgets(fh))) @@ -2152,123 +1305,6 @@ float get_model_parameters(string m, float sk) return 1; } -vector vec2(vector v) -{ - v.z = 0; - return v; -} - -#ifndef MENUQC -vector NearestPointOnBox(entity box, vector org) -{ - vector m1, m2, nearest; - - m1 = box.mins + box.origin; - m2 = box.maxs + box.origin; - - nearest.x = bound(m1_x, org.x, m2_x); - nearest.y = bound(m1_y, org.y, m2_y); - nearest.z = bound(m1_z, org.z, m2_z); - - return nearest; -} -#endif - -float vercmp_recursive(string v1, string v2) -{ - float dot1, dot2; - string s1, s2; - float r; - - dot1 = strstrofs(v1, ".", 0); - dot2 = strstrofs(v2, ".", 0); - if(dot1 == -1) - s1 = v1; - else - s1 = substring(v1, 0, dot1); - if(dot2 == -1) - s2 = v2; - else - s2 = substring(v2, 0, dot2); - - r = stof(s1) - stof(s2); - if(r != 0) - return r; - - r = strcasecmp(s1, s2); - if(r != 0) - return r; - - if(dot1 == -1) - if(dot2 == -1) - return 0; - else - return -1; - else - if(dot2 == -1) - return 1; - else - return vercmp_recursive(substring(v1, dot1 + 1, 999), substring(v2, dot2 + 1, 999)); -} - -float vercmp(string v1, string v2) -{ - if(strcasecmp(v1, v2) == 0) // early out check - return 0; - - // "git" beats all - if(v1 == "git") - return 1; - if(v2 == "git") - return -1; - - return vercmp_recursive(v1, v2); -} - -float u8_strsize(string s) -{ - float l, i, c; - l = 0; - for(i = 0; ; ++i) - { - c = str2chr(s, i); - if(c <= 0) - break; - ++l; - if(c >= 0x80) - ++l; - if(c >= 0x800) - ++l; - if(c >= 0x10000) - ++l; - } - return l; -} - -// translation helpers -string language_filename(string s) -{ - string fn; - float fh; - fn = prvm_language; - if(fn == "" || fn == "dump") - return s; - fn = strcat(s, ".", fn); - if((fh = fopen(fn, FILE_READ)) >= 0) - { - fclose(fh); - return fn; - } - return s; -} -string CTX(string s) -{ - float p = strstrofs(s, "^", 0); - if(p < 0) - return s; - return substring(s, p+1, -1); -} - // x-encoding (encoding as zero length invisible string) const string XENCODE_2 = "xX"; const string XENCODE_22 = "0123456789abcdefABCDEF"; @@ -2303,16 +1339,6 @@ float xdecode(string s) return ((a * 22 + b) * 22 + c) * 22 + d; } -int lowestbit(int f) -{ - f &= ~(f * 2); - f &= ~(f * 4); - f &= ~(f * 16); - f &= ~(f * 256); - f &= ~(f * 65536); - return f; -} - /* string strlimitedlen(string input, string truncation, float strip_colors, float limit) { @@ -2322,47 +1348,6 @@ string strlimitedlen(string input, string truncation, float strip_colors, float return strcat(substring(input, 0, (strlen(input) - strlen(truncation))), truncation); }*/ -// escape the string to make it safe for consoles -string MakeConsoleSafe(string input) -{ - input = strreplace("\n", "", input); - input = strreplace("\\", "\\\\", input); - input = strreplace("$", "$$", input); - input = strreplace("\"", "\\\"", input); - return input; -} - -#ifndef MENUQC -// get true/false value of a string with multiple different inputs -float InterpretBoolean(string input) -{ - switch(strtolower(input)) - { - case "yes": - case "true": - case "on": - return true; - - case "no": - case "false": - case "off": - return false; - - default: return stof(input); - } -} -#endif - -#ifdef CSQC -entity ReadCSQCEntity() -{ - int f = ReadShort(); - if(f == 0) - return world; - return findfloat(world, entnum, f); -} -#endif - float shutdown_running; #ifdef SVQC void SV_Shutdown() @@ -2376,55 +1361,18 @@ void m_shutdown() { if(shutdown_running) { - print("Recursive shutdown detected! Only restoring cvars...\n"); + LOG_INFO("Recursive shutdown detected! Only restoring cvars...\n"); } else { shutdown_running = 1; Shutdown(); + shutdownhooks(); } cvar_settemp_restore(); // this must be done LAST, but in any case } -const float APPROXPASTTIME_ACCURACY_REQUIREMENT = 0.05; -#define APPROXPASTTIME_MAX (16384 * APPROXPASTTIME_ACCURACY_REQUIREMENT) -#define APPROXPASTTIME_RANGE (64 * APPROXPASTTIME_ACCURACY_REQUIREMENT) -// this will use the value: -// 128 -// accuracy near zero is APPROXPASTTIME_MAX/(256*255) -// accuracy at x is 1/derivative, i.e. -// APPROXPASTTIME_MAX * (1 + 256 * (dt / APPROXPASTTIME_MAX))^2 / 65536 -#ifdef SVQC -void WriteApproxPastTime(float dst, float t) -{ - float dt = time - t; - - // warning: this is approximate; do not resend when you don't have to! - // be careful with sendflags here! - // we want: 0 -> 0.05, 1 -> 0.1, ..., 255 -> 12.75 - - // map to range... - dt = 256 * (dt / ((APPROXPASTTIME_MAX / 256) + dt)); - - // round... - dt = rint(bound(0, dt, 255)); - - WriteByte(dst, dt); -} -#endif -#ifdef CSQC -float ReadApproxPastTime() -{ - float dt = ReadByte(); - - // map from range...PPROXPASTTIME_MAX / 256 - dt = (APPROXPASTTIME_MAX / 256) * (dt / (256 - dt)); - - return servertime - dt; -} -#endif - -#ifndef MENUQC +#ifdef GAMEQC .float skeleton_bones_index; void Skeleton_SetBones(entity e) { @@ -2460,80 +1408,6 @@ void queue_to_execute_next_frame(string s) to_execute_next_frame = strzone(s); } -float cubic_speedfunc(float startspeedfactor, float endspeedfactor, float x) -{ - return - ((( startspeedfactor + endspeedfactor - 2 - ) * x - 2 * startspeedfactor - endspeedfactor + 3 - ) * x + startspeedfactor - ) * x; -} - -float cubic_speedfunc_is_sane(float startspeedfactor, float endspeedfactor) -{ - if(startspeedfactor < 0 || endspeedfactor < 0) - return false; - - /* - // if this is the case, the possible zeros of the first derivative are outside - // 0..1 - We can calculate this condition as condition - if(se <= 3) - return true; - */ - - // better, see below: - if(startspeedfactor <= 3 && endspeedfactor <= 3) - return true; - - // if this is the case, the first derivative has no zeros at all - float se = startspeedfactor + endspeedfactor; - float s_e = startspeedfactor - endspeedfactor; - if(3 * (se - 4) * (se - 4) + s_e * s_e <= 12) // an ellipse - return true; - - // Now let s <= 3, s <= 3, s+e >= 3 (triangle) then we get se <= 6 (top right corner). - // we also get s_e <= 6 - se - // 3 * (se - 4)^2 + (6 - se)^2 - // is quadratic, has value 12 at 3 and 6, and value < 12 in between. - // Therefore, above "better" check works! - - return false; - - // known good cases: - // (0, [0..3]) - // (0.5, [0..3.8]) - // (1, [0..4]) - // (1.5, [0..3.9]) - // (2, [0..3.7]) - // (2.5, [0..3.4]) - // (3, [0..3]) - // (3.5, [0.2..2.3]) - // (4, 1) - - /* - On another note: - inflection point is always at (2s + e - 3) / (3s + 3e - 6). - - s + e - 2 == 0: no inflection - - s + e > 2: - 0 < inflection < 1 if: - 0 < 2s + e - 3 < 3s + 3e - 6 - 2s + e > 3 and 2e + s > 3 - - s + e < 2: - 0 < inflection < 1 if: - 0 > 2s + e - 3 > 3s + 3e - 6 - 2s + e < 3 and 2e + s < 3 - - Therefore: there is an inflection point iff: - e outside (3 - s)/2 .. 3 - s*2 - - in other words, if (s,e) in triangle (1,1)(0,3)(0,1.5) or in triangle (1,1)(3,0)(1.5,0) - */ -} - .float FindConnectedComponent_processing; void FindConnectedComponent(entity e, .entity fld, findNextEntityNearFunction_t nxt, isConnectedFunction_t iscon, entity pass) { @@ -2548,7 +1422,7 @@ void FindConnectedComponent(entity e, .entity fld, findNextEntityNearFunction_t // start with a 1-element queue queue_start = queue_end = e; - queue_end.(fld) = world; + queue_end.(fld) = NULL; queue_end.FindConnectedComponent_processing = 1; // for each queued item: @@ -2556,7 +1430,7 @@ void FindConnectedComponent(entity e, .entity fld, findNextEntityNearFunction_t { // find all neighbors of queue_start entity t; - for(t = world; (t = nxt(t, queue_start, pass)); ) + for(t = NULL; (t = nxt(t, queue_start, pass)); ) { if(t.FindConnectedComponent_processing) continue; @@ -2565,7 +1439,7 @@ void FindConnectedComponent(entity e, .entity fld, findNextEntityNearFunction_t // it is connected? ADD IT. It will look for neighbors soon too. queue_end.(fld) = t; queue_end = t; - queue_end.(fld) = world; + queue_end.(fld) = NULL; queue_end.FindConnectedComponent_processing = 1; } } @@ -2576,115 +1450,30 @@ void FindConnectedComponent(entity e, .entity fld, findNextEntityNearFunction_t queue_start.FindConnectedComponent_processing = 0; } -#ifdef SVQC -vector combine_to_vector(float x, float y, float z) -{ - vector result; result_x = x; result_y = y; result_z = z; - return result; -} - -vector get_corner_position(entity box, float corner) -{ - switch(corner) - { - case 1: return combine_to_vector(box.absmin.x, box.absmin.y, box.absmin.z); - case 2: return combine_to_vector(box.absmax.x, box.absmin.y, box.absmin.z); - case 3: return combine_to_vector(box.absmin.x, box.absmax.y, box.absmin.z); - case 4: return combine_to_vector(box.absmin.x, box.absmin.y, box.absmax.z); - case 5: return combine_to_vector(box.absmax.x, box.absmax.y, box.absmin.z); - case 6: return combine_to_vector(box.absmin.x, box.absmax.y, box.absmax.z); - case 7: return combine_to_vector(box.absmax.x, box.absmin.y, box.absmax.z); - case 8: return combine_to_vector(box.absmax.x, box.absmax.y, box.absmax.z); - default: return '0 0 0'; - } -} -#endif - -// todo: this sucks, lets find a better way to do backtraces? -void backtrace(string msg) -{ - float dev, war; - #ifdef SVQC - dev = autocvar_developer; - war = autocvar_prvm_backtraceforwarnings; - #else - dev = cvar("developer"); - war = cvar("prvm_backtraceforwarnings"); - #endif - cvar_set("developer", "1"); - cvar_set("prvm_backtraceforwarnings", "1"); - print("\n"); - print("--- CUT HERE ---\nWARNING: "); - print(msg); - print("\n"); - remove(world); // isn't there any better way to cause a backtrace? - print("\n--- CUT UNTIL HERE ---\n"); - cvar_set("developer", ftos(dev)); - cvar_set("prvm_backtraceforwarnings", ftos(war)); -} - -// color code replace, place inside of sprintf and parse the string -string CCR(string input) -{ - // See the autocvar declarations in util.qh for default values - - // foreground/normal colors - input = strreplace("^F1", strcat("^", autocvar_hud_colorset_foreground_1), input); - input = strreplace("^F2", strcat("^", autocvar_hud_colorset_foreground_2), input); - input = strreplace("^F3", strcat("^", autocvar_hud_colorset_foreground_3), input); - input = strreplace("^F4", strcat("^", autocvar_hud_colorset_foreground_4), input); - - // "kill" colors - input = strreplace("^K1", strcat("^", autocvar_hud_colorset_kill_1), input); - input = strreplace("^K2", strcat("^", autocvar_hud_colorset_kill_2), input); - input = strreplace("^K3", strcat("^", autocvar_hud_colorset_kill_3), input); - - // background colors - input = strreplace("^BG", strcat("^", autocvar_hud_colorset_background), input); - input = strreplace("^N", "^7", input); // "none"-- reset to white... - return input; -} - -vector vec3(float x, float y, float z) -{ - vector v; - v.x = x; - v.y = y; - v.z = z; - return v; -} - -#ifndef MENUQC +#ifdef GAMEQC vector animfixfps(entity e, vector a, vector b) { // multi-frame anim: keep as-is if(a.y == 1) { - float dur; - dur = frameduration(e.modelindex, a.x); - if(dur <= 0 && b.y) + float dur = frameduration(e.modelindex, a.x); + if (dur <= 0 && b.y) { a = b; dur = frameduration(e.modelindex, a.x); } - if(dur > 0) + if (dur > 0) a.z = 1.0 / dur; } return a; } #endif -#ifdef SVQC -void dedicated_print(string input) // print(), but only print if the server is not local +#ifdef GAMEQC +Notification Announcer_PickNumber(int type, int num) { - if(server_is_dedicated) { print(input); } -} -#endif - -#ifndef MENUQC -float Announcer_PickNumber(float type, float num) -{ - switch(type) + return = NULL; + switch (type) { case CNT_GAMESTART: { @@ -2789,11 +1578,10 @@ float Announcer_PickNumber(float type, float num) break; } } - return NOTIF_ABORT; // abort sending if none of these numbers were right } #endif -#ifndef MENUQC +#ifdef GAMEQC int Mod_Q1BSP_SuperContentsFromNativeContents(int nativecontents) { switch(nativecontents) @@ -2829,18 +1617,3 @@ int Mod_Q1BSP_NativeContentsFromSuperContents(int supercontents) return CONTENT_EMPTY; } #endif - -vector bezier_quadratic_getpoint(vector a, vector b, vector c, float t) -{ - return - (c - 2 * b + a) * (t * t) + - (b - a) * (2 * t) + - a; -} - -vector bezier_quadratic_getderivative(vector a, vector b, vector c, float t) -{ - return - (c - 2 * b + a) * (2 * t) + - (b - a) * 2; -}