From 7029c1b56f76ec1efa593c4509dffee0c393a2a9 Mon Sep 17 00:00:00 2001 From: TimePath Date: Thu, 8 Oct 2015 12:37:22 +1100 Subject: [PATCH] Lib: re-home functions from common/util --- qcsrc/common/util-pre.qh | 7 - qcsrc/common/util.qc | 521 +---------------------- qcsrc/common/util.qh | 28 -- qcsrc/common/weapons/weapon/shockwave.qc | 2 +- qcsrc/lib/_all.inc | 3 +- qcsrc/lib/bits.qh | 22 + qcsrc/lib/math.qh | 262 ++++++++++-- qcsrc/lib/net.qh | 45 ++ qcsrc/lib/prandom.qc | 49 --- qcsrc/lib/random.qc | 81 ++++ qcsrc/lib/{prandom.qh => random.qh} | 13 +- qcsrc/lib/string.qh | 175 +++++++- qcsrc/lib/vector.qh | 76 +++- qcsrc/server/g_world.qc | 16 - 14 files changed, 622 insertions(+), 678 deletions(-) create mode 100644 qcsrc/lib/bits.qh delete mode 100644 qcsrc/lib/prandom.qc create mode 100644 qcsrc/lib/random.qc rename qcsrc/lib/{prandom.qh => random.qh} (51%) diff --git a/qcsrc/common/util-pre.qh b/qcsrc/common/util-pre.qh index ad9be12cb..dfb407160 100644 --- a/qcsrc/common/util-pre.qh +++ b/qcsrc/common/util-pre.qh @@ -113,11 +113,4 @@ #define GET(name) name##get #define GETTER(type, name) type GET(name)() { return name; } -#define BIT(n) (1 << (n)) -#ifndef BRANCHLESS_BITSET - #define BITSET(var, mask, flag) (flag ? (var) | (mask) : (var) &~ (mask)) -#else - #define BITSET(var, mask, flag) ((var) ^ (-(flag) ^ (var)) & (mask)) -#endif - #endif diff --git a/qcsrc/common/util.qc b/qcsrc/common/util.qc index e93fd6a39..c304ed88d 100644 --- a/qcsrc/common/util.qc +++ b/qcsrc/common/util.qc @@ -72,37 +72,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; @@ -168,17 +137,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; @@ -208,13 +166,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) @@ -226,9 +177,9 @@ string ftos_decimals(float number, float decimals) return sprintf("%.*f", decimals, number); } -vector colormapPaletteColor(float c, float isPants) +vector colormapPaletteColor(float c, bool isPants) { - switch(c) + switch (c) { case 0: return '1.000000 1.000000 1.000000'; case 1: return '1.000000 0.333333 0.000000'; @@ -246,7 +197,7 @@ vector colormapPaletteColor(float c, float isPants) case 13: return '0.000000 0.333333 1.000000'; case 14: return '1.000000 0.666667 0.000000'; case 15: - if(isPants) + 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)) @@ -260,17 +211,6 @@ vector colormapPaletteColor(float c, float isPants) } } -// 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; -} - // Databases (hash tables) const float DB_BUCKETS = 8192; void db_save(float db, string pFilename) @@ -932,103 +872,6 @@ float cvar_settemp_restore() return i; } -float almost_equals(float a, float b) -{ - 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); -} - -float power2of(float e) -{ - return pow(2, e); -} -float log2of(float x) -{ - // 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; -} - float rgb_mi_ma_to_hue(vector rgb, float mi, float ma) { if(mi == ma) @@ -1173,15 +1016,6 @@ string rgb_to_hexcolor(vector rgb) ); } -// 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. @@ -1500,47 +1334,6 @@ float isGametypeInFilter(float gt, float tp, float ts, string pattern) return 1; } -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; @@ -1730,37 +1523,6 @@ vector decompressShotOrigin(int f) return v; } - -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 vector healtharmor_maxdamage(float h, float a, float armorblock, int deathtype) { @@ -1810,63 +1572,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; @@ -1888,22 +1593,6 @@ float gsl_ran_gaussian(float sigma) } } -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; @@ -1937,14 +1626,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) { @@ -2069,28 +1750,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; @@ -2142,26 +1801,6 @@ float vercmp(string v1, string v2) 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; -} - // x-encoding (encoding as zero length invisible string) const string XENCODE_2 = "xX"; const string XENCODE_22 = "0123456789abcdefABCDEF"; @@ -2196,16 +1835,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,80 +1951,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) { @@ -2438,61 +1993,6 @@ 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 - -// 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 vector animfixfps(entity e, vector a, vector b) { @@ -2668,18 +2168,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; -} diff --git a/qcsrc/common/util.qh b/qcsrc/common/util.qh index 4af16801d..a2774aa50 100644 --- a/qcsrc/common/util.qh +++ b/qcsrc/common/util.qh @@ -152,14 +152,6 @@ string rankings_reply, ladder_reply, lsmaps_reply, maplist_reply, monsterlist_re string records_reply[10]; #endif -float RandomSelection_totalweight; -float RandomSelection_best_priority; -entity RandomSelection_chosen_ent; -float RandomSelection_chosen_float; -string RandomSelection_chosen_string; -void RandomSelection_Init(); -void RandomSelection_Add(entity e, float f, string s, float weight, float priority); - #ifndef MENUQC vector healtharmor_maxdamage(float h, float a, float armorblock, int deathtype); // returns vector: maxdamage, armorideal, 1 if fully armored vector healtharmor_applydamage(float a, float armorblock, int deathtype, float damage); // returns vector: take, save, 0 @@ -225,8 +217,6 @@ const float XENCODE_LEN = 5; string xencode(float f); float xdecode(string s); -int lowestbit(float f); - #ifdef CSQC entity ReadCSQCEntity(); #endif @@ -276,11 +266,6 @@ typedef entity(entity cur, entity near, entity pass) findNextEntityNearFunction_ typedef float(entity a, entity b, entity pass) isConnectedFunction_t; void FindConnectedComponent(entity e, .entity fld, findNextEntityNearFunction_t nxt, isConnectedFunction_t iscon, entity pass); -#ifdef SVQC -vector combine_to_vector(float x, float y, float z); -vector get_corner_position(entity box, float corner); -#endif - // expand multiple arguments into one argument by stripping parenthesis #define XPD(...) __VA_ARGS__ @@ -288,19 +273,6 @@ vector get_corner_position(entity box, float corner); #define fprintf(file, ...) fputs(file, sprintf(__VA_ARGS__)) #define bprintf(...) bprint(sprintf(__VA_ARGS__)) -// color code replace, place inside of sprintf and parse the string... defaults described as constants -// foreground/normal colors -string autocvar_hud_colorset_foreground_1 = "2"; // F1 - Green // primary priority (important names, etc) -string autocvar_hud_colorset_foreground_2 = "3"; // F2 - Yellow // secondary priority (items, locations, numbers, etc) -string autocvar_hud_colorset_foreground_3 = "4"; // F3 - Blue // tertiary priority or relatively inconsequential text -string autocvar_hud_colorset_foreground_4 = "1"; // F4 - Red // notice/attention grabbing texting -// "kill" colors -string autocvar_hud_colorset_kill_1 = "1"; // K1 - Red // "bad" or "dangerous" text (death messages against you, kill notifications, etc) -string autocvar_hud_colorset_kill_2 = "3"; // K2 - Yellow // similar to above, but less important... OR, a highlight out of above message type -string autocvar_hud_colorset_kill_3 = "4"; // K3 - Blue // "good" or "beneficial" text (you fragging someone, etc) -// background color -string autocvar_hud_colorset_background = "7"; // BG - White // neutral/unimportant text - string CCR(string input); #ifndef MENUQC diff --git a/qcsrc/common/weapons/weapon/shockwave.qc b/qcsrc/common/weapons/weapon/shockwave.qc index 4965ba6f2..cc4daf048 100644 --- a/qcsrc/common/weapons/weapon/shockwave.qc +++ b/qcsrc/common/weapons/weapon/shockwave.qc @@ -439,7 +439,7 @@ void W_Shockwave_Attack(void) ); // figure out the direction of force - vel = normalize(combine_to_vector(head.velocity.x, head.velocity.y, 0)); + vel = normalize(vec3(head.velocity.x, head.velocity.y, 0)); vel *= ( bound(0, (vlen(vel) / autocvar_sv_maxspeed), 1) diff --git a/qcsrc/lib/_all.inc b/qcsrc/lib/_all.inc index 7dc607405..c00c5a12a 100644 --- a/qcsrc/lib/_all.inc +++ b/qcsrc/lib/_all.inc @@ -3,6 +3,7 @@ #include "../warpzonelib/mathlib.qc" #include "accumulate.qh" +#include "bits.qh" #include "counting.qh" #include "cvar.qh" #include "defer.qh" @@ -18,8 +19,8 @@ #include "oo.qh" #include "p2mathlib.qc" #include "player.qh" -#include "prandom.qc" #include "progname.qh" +#include "random.qc" #include "registry.qh" #include "replicate.qh" #include "sort.qh" diff --git a/qcsrc/lib/bits.qh b/qcsrc/lib/bits.qh new file mode 100644 index 000000000..86b5df597 --- /dev/null +++ b/qcsrc/lib/bits.qh @@ -0,0 +1,22 @@ +#ifndef BITS_H +#define BITS_H + +#define BIT(n) (1 << (n)) +#define BITS(n) (BIT(n) - 1) +#ifndef BRANCHLESS_BITSET + #define BITSET(var, mask, flag) (flag ? (var) | (mask) : (var) &~ (mask)) +#else + #define BITSET(var, mask, flag) ((var) ^ (-(flag) ^ (var)) & (mask)) +#endif + +int lowestbit(int f) +{ + f &= ~(f << 1); + f &= ~(f << 2); + f &= ~(f << 4); + f &= ~(f << 8); + f &= ~(f << 16); + return f; +} + +#endif diff --git a/qcsrc/lib/math.qh b/qcsrc/lib/math.qh index a8a52907a..1a707a435 100644 --- a/qcsrc/lib/math.qh +++ b/qcsrc/lib/math.qh @@ -3,23 +3,23 @@ void mean_accumulate(entity e, .float a, .float c, float mean, float value, float weight) { - if (weight == 0) - return; - if (mean == 0) - e.(a) *= pow(value, weight); - else - e.(a) += pow(value, mean) * weight; - e.(c) += weight; + if (weight == 0) + return; + if (mean == 0) + e.(a) *= pow(value, weight); + else + e.(a) += pow(value, mean) * weight; + e.(c) += weight; } float mean_evaluate(entity e, .float a, .float c, float mean) { - if (e.(c) == 0) - return 0; - if (mean == 0) - return pow(e.(a), 1.0 / e.(c)); - else - return pow(e.(a) / e.(c), 1.0 / mean); + if (e.(c) == 0) + return 0; + if (mean == 0) + return pow(e.(a), 1.0 / e.(c)); + else + return pow(e.(a) / e.(c), 1.0 / mean); } #define MEAN_ACCUMULATE(prefix,v,w) mean_accumulate(self,prefix##_accumulator,prefix##_count,prefix##_mean,v,w) @@ -33,9 +33,9 @@ crandom Returns a random number between -1.0 and 1.0 ================== */ -float crandom (void) +float crandom() { - return 2 * (random () - 0.5); + return 2 * (random() - 0.5); } @@ -46,27 +46,16 @@ Angc used for animations */ -float angc (float a1, float a2) +float angc(float a1, float a2) { - float a; - - while (a1 > 180) - a1 = a1 - 360; - while (a1 < -179) - a1 = a1 + 360; - - while (a2 > 180) - a2 = a2 - 360; - while (a2 < -179) - a2 = a2 + 360; - - a = a1 - a2; - while (a > 180) - a = a - 360; - while (a < -179) - a = a + 360; - - return a; + while (a1 > 180) a1 -= 360; + while (a1 < -179) a1 += 360; + while (a2 > 180) a2 -= 360; + while (a2 < -179) a2 += 360; + float a = a1 - a2; + while (a > 180) a -= 360; + while (a < -179) a += 360; + return a; } float fsnap(float val,float fsize) @@ -87,7 +76,208 @@ vector vsnap(vector point,float fsize) vector lerpv(float t0, vector v0, float t1, vector v1, float t) { - return v0 + (v1 - v0) * ((t - t0) / (t1 - t0)); + return v0 + (v1 - v0) * ((t - t0) / (t1 - t0)); +} + +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; +} + +float cubic_speedfunc(float startspeedfactor, float endspeedfactor, float x) +{ + return + ((( startspeedfactor + endspeedfactor - 2 + ) * x - 2 * startspeedfactor - endspeedfactor + 3 + ) * x + startspeedfactor + ) * x; +} + +bool 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) + */ +} + +/** continuous function mapping all reals into -1..1 */ +float float2range11(float f) +{ + return f / (fabs(f) + 1); } +/** continuous function mapping all reals into 0..1 */ +float float2range01(float f) +{ + return 0.5 + 0.5 * float2range11(f); +} + +float median(float a, float b, float c) +{ + return (a < c) ? bound(a, b, c) : bound(c, b, a); +} + +float almost_equals(float a, float b) +{ + float eps = (max(a, -a) + max(b, -b)) * 0.001; + return a - b < eps && b - a < eps; +} + +float almost_in_bounds(float a, float b, float c) +{ + float eps = (max(a, -a) + max(c, -c)) * 0.001; + if (a > c) + eps = -eps; + return b == median(a - eps, b, c + eps); +} + +float power2of(float e) +{ + return pow(2, e); +} + +float log2of(float x) +{ + // 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; +} + + #endif diff --git a/qcsrc/lib/net.qh b/qcsrc/lib/net.qh index 2928ce84a..04faffc4a 100644 --- a/qcsrc/lib/net.qh +++ b/qcsrc/lib/net.qh @@ -118,4 +118,49 @@ STATIC_INIT(RegisterTempEntities_renumber) { } } +#ifndef MENUQC +#ifdef CSQC +int ReadInt24_t() +{ + int v = ReadShort() << 8; // 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 >> 8))); + WriteByte(dst, val - (v << 8)); // 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 + #endif diff --git a/qcsrc/lib/prandom.qc b/qcsrc/lib/prandom.qc deleted file mode 100644 index 4f5882269..000000000 --- a/qcsrc/lib/prandom.qc +++ /dev/null @@ -1,49 +0,0 @@ -#include "prandom.qh" - -// prandom - PREDICTABLE random number generator (not seeded yet) - -#ifdef USE_PRANDOM -float prandom_seed; -float prandom() -{ - float c; - c = crc16(false, strcat(ftos(prandom_seed), ftos(prandom_seed + M_PI))); - prandom_seed = c; - -#ifdef USE_PRANDOM_DEBUG - LOG_TRACE("RANDOM -> ", ftos(c), "\n"); -#endif - - return c / 65536; // in [0..1[ -} - -vector prandomvec() -{ - vector v; - - do - { - v.x = prandom(); - v.y = prandom(); - v.z = prandom(); - } - while(v * v > 1); - - return v; -} - -void psrandom(float seed) -{ - prandom_seed = seed; -#ifdef USE_PRANDOM_DEBUG - LOG_TRACE("SRANDOM ", ftos(seed), "\n"); -#endif -} - -#ifdef USE_PRANDOM_DEBUG -void prandom_debug() -{ - LOG_TRACE("Current random seed = ", ftos(prandom_seed), "\n"); -} -#endif -#endif diff --git a/qcsrc/lib/random.qc b/qcsrc/lib/random.qc new file mode 100644 index 000000000..149323b8f --- /dev/null +++ b/qcsrc/lib/random.qc @@ -0,0 +1,81 @@ +#include "random.qh" + +void RandomSelection_Init() +{ + RandomSelection_totalweight = 0; + RandomSelection_chosen_ent = NULL; + 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; + } + } +} + + +// prandom - PREDICTABLE random number generator (not seeded yet) + +#ifdef USE_PRANDOM +float prandom_seed; +float prandom() +{ + float c; + c = crc16(false, strcat(ftos(prandom_seed), ftos(prandom_seed + M_PI))); + prandom_seed = c; + +#ifdef USE_PRANDOM_DEBUG + LOG_TRACE("RANDOM -> ", ftos(c), "\n"); +#endif + + return c / 65536; // in [0..1[ +} + +vector prandomvec() +{ + vector v; + + do + { + v.x = prandom(); + v.y = prandom(); + v.z = prandom(); + } + while(v * v > 1); + + return v; +} + +void psrandom(float seed) +{ + prandom_seed = seed; +#ifdef USE_PRANDOM_DEBUG + LOG_TRACE("SRANDOM ", ftos(seed), "\n"); +#endif +} + +#ifdef USE_PRANDOM_DEBUG +void prandom_debug() +{ + LOG_TRACE("Current random seed = ", ftos(prandom_seed), "\n"); +} +#endif +#endif diff --git a/qcsrc/lib/prandom.qh b/qcsrc/lib/random.qh similarity index 51% rename from qcsrc/lib/prandom.qh rename to qcsrc/lib/random.qh index a7653a505..551cf216d 100644 --- a/qcsrc/lib/prandom.qh +++ b/qcsrc/lib/random.qh @@ -1,5 +1,14 @@ -#ifndef PRANDOM_H -#define PRANDOM_H +#ifndef RANDOM_H +#define RANDOM_H + +float RandomSelection_totalweight; +float RandomSelection_best_priority; +entity RandomSelection_chosen_ent; +float RandomSelection_chosen_float; +string RandomSelection_chosen_string; + +void RandomSelection_Init(); +void RandomSelection_Add(entity e, float f, string s, float weight, float priority); // prandom - PREDICTABLE random number generator diff --git a/qcsrc/lib/string.qh b/qcsrc/lib/string.qh index faf81b29d..ede2edf1f 100644 --- a/qcsrc/lib/string.qh +++ b/qcsrc/lib/string.qh @@ -4,12 +4,12 @@ #ifndef SVQC float stringwidth_colors(string s, vector theSize) { - return stringwidth(s, true, theSize); + return stringwidth(s, true, theSize); } float stringwidth_nocolors(string s, vector theSize) { - return stringwidth(s, false, theSize); + return stringwidth(s, false, theSize); } #endif @@ -18,21 +18,174 @@ float stringwidth_nocolors(string s, vector theSize) // TODO: macro string seconds_tostring(float sec) { - float minutes; - minutes = floor(sec / 60); - - sec -= minutes * 60; - return sprintf("%d:%02d", minutes, sec); + float minutes = floor(sec / 60); + sec -= minutes * 60; + return sprintf("%d:%02d", minutes, sec); } int ColorTranslateMode; string ColorTranslateRGB(string s) { - if(ColorTranslateMode & 1) - return strdecolorize(s); - else - return s; + return (ColorTranslateMode & 1) ? strdecolorize(s) : s; +} + +// color code replace, place inside of sprintf and parse the string... defaults described as constants +// foreground/normal colors +string autocvar_hud_colorset_foreground_1 = "2"; // F1 - Green // primary priority (important names, etc) +string autocvar_hud_colorset_foreground_2 = "3"; // F2 - Yellow // secondary priority (items, locations, numbers, etc) +string autocvar_hud_colorset_foreground_3 = "4"; // F3 - Blue // tertiary priority or relatively inconsequential text +string autocvar_hud_colorset_foreground_4 = "1"; // F4 - Red // notice/attention grabbing texting +// "kill" colors +string autocvar_hud_colorset_kill_1 = "1"; // K1 - Red // "bad" or "dangerous" text (death messages against you, kill notifications, etc) +string autocvar_hud_colorset_kill_2 = "3"; // K2 - Yellow // similar to above, but less important... OR, a highlight out of above message type +string autocvar_hud_colorset_kill_3 = "4"; // K3 - Blue // "good" or "beneficial" text (you fragging someone, etc) +// background color +string autocvar_hud_colorset_background = "7"; // BG - White // neutral/unimportant text + +/** 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; +} + +bool startsWith(string haystack, string needle) +{ + return substring(haystack, 0, strlen(needle)) == needle; +} + +bool startsWithNocase(string haystack, string needle) +{ + return strcasecmp(substring(haystack, 0, strlen(needle)), needle) == 0; +} + +/** unzone the string, and return it as tempstring. Safe to be called on string_null */ +string fstrunzone(string s) +{ + if (!s) return s; + string sc = strcat(s, ""); + strunzone(s); + return sc; +} + +string car(string s) +{ + int o = strstrofs(s, " ", 0); + if (o < 0) return s; + return substring(s, 0, o); +} + +string cdr(string s) +{ + int o = strstrofs(s, " ", 0); + if (o < 0) return string_null; + return substring(s, o + 1, strlen(s) - (o + 1)); +} + +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) +{ + _shufflewords_str = str; + int n = tokenizebyseparator(str, " "); + shuffle(n, _shufflewords_swapfunc, NULL); + str = _shufflewords_str; + _shufflewords_str = string_null; + return str; +} + +string unescape(string in) +{ + in = strzone(in); // but it doesn't seem to be necessary in my tests at least + + int len = strlen(in); + string str = ""; + for (int i = 0; i < len; ++i) { + string 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; + continue; + } + str = strcat(str, s); + } + strunzone(in); + return str; +} + +string strwords(string s, int w) +{ + int endpos = 0; + for (; w && endpos >= 0; --w) endpos = strstrofs(s, " ", endpos + 1); + if (endpos < 0) return s; + return substring(s, 0, endpos); +} + +bool strhasword(string s, string w) +{ + return strstrofs(strcat(" ", s, " "), strcat(" ", w, " "), 0) >= 0; +} + +int u8_strsize(string s) +{ + int l = 0; + for (int i = 0, c; (c = str2chr(s, i)) > 0; ++i, ++l) + { + l += (c >= 0x80); + l += (c >= 0x800); + l += (c >= 0x10000); + } + return l; } #endif diff --git a/qcsrc/lib/vector.qh b/qcsrc/lib/vector.qh index d81a79571..b57e27aeb 100644 --- a/qcsrc/lib/vector.qh +++ b/qcsrc/lib/vector.qh @@ -7,28 +7,86 @@ const vector eZ = '0 0 1'; vector randompos(vector m1, vector m2) { - vector v; - m2 = m2 - m1; - v_x = m2_x * random() + m1_x; - v_y = m2_y * random() + m1_y; - v_z = m2_z * random() + m1_z; - return v; + vector v; + m2 = m2 - m1; + v_x = m2_x * random() + m1_x; + v_y = m2_y * random() + m1_y; + v_z = m2_z * random() + m1_z; + return v; } float vlen2d(vector v) { - return sqrt(v.x * v.x + v.y * v.y); + return sqrt(v.x * v.x + v.y * v.y); } float vlen_maxnorm2d(vector v) { - return max(v.x, v.y, -v.x, -v.y); + return max(v.x, v.y, -v.x, -v.y); } float vlen_minnorm2d(vector v) { - return min(max(v.x, -v.x), max(v.y, -v.y)); + return min(max(v.x, -v.x), max(v.y, -v.y)); } +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); +} + +/** 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 as boxesoverlap, 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;} + + +vector vec2(vector v) +{ + v.z = 0; + return v; +} + +vector vec3(float x, float y, float z) +{ + vector v; v.x = x; v.y = y; v.z = z; + return v; +} + +#ifndef MENUQC +vector get_corner_position(entity box, int corner) +{ + switch (corner) { + case 1: return vec3(box.absmin.x, box.absmin.y, box.absmin.z); + case 2: return vec3(box.absmax.x, box.absmin.y, box.absmin.z); + case 3: return vec3(box.absmin.x, box.absmax.y, box.absmin.z); + case 4: return vec3(box.absmin.x, box.absmin.y, box.absmax.z); + case 5: return vec3(box.absmax.x, box.absmax.y, box.absmin.z); + case 6: return vec3(box.absmin.x, box.absmax.y, box.absmax.z); + case 7: return vec3(box.absmax.x, box.absmin.y, box.absmax.z); + case 8: return vec3(box.absmax.x, box.absmax.y, box.absmax.z); + default: return '0 0 0'; + } +} + +vector NearestPointOnBox(entity box, vector org) +{ + vector m1 = box.mins + box.origin; + vector m2 = box.maxs + box.origin; + + vector ret; + ret.x = bound(m1.x, org.x, m2.x); + ret.y = bound(m1.y, org.y, m2.y); + ret.z = bound(m1.z, org.z, m2.z); + return ret; +} +#endif #endif diff --git a/qcsrc/server/g_world.qc b/qcsrc/server/g_world.qc index d6ffeeb5d..a0f9a3f13 100644 --- a/qcsrc/server/g_world.qc +++ b/qcsrc/server/g_world.qc @@ -1000,22 +1000,6 @@ string Map_Filename(float position) return strcat("maps/", argv(position), ".bsp"); } -string strwords(string s, float w) -{ - float endpos; - for(endpos = 0; w && endpos >= 0; --w) - endpos = strstrofs(s, " ", endpos + 1); - if(endpos < 0) - return s; - else - return substring(s, 0, endpos); -} - -float strhasword(string s, string w) -{ - return strstrofs(strcat(" ", s, " "), strcat(" ", w, " "), 0) >= 0; -} - void Map_MarkAsRecent(string m) { cvar_set("g_maplist_mostrecent", strwords(strcat(m, " ", autocvar_g_maplist_mostrecent), max(0, autocvar_g_maplist_mostrecent_count))); -- 2.39.2