]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/common/util.qc
Merge branch 'amade/small-fixes' into 'master'
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / util.qc
index a506a59fcd2808ac26419691fe3c1b5ca7f90b17..91d68f1ba1313cb0a7eb543dd7b6406fafd26d7e 100644 (file)
@@ -1,26 +1,42 @@
 #include "util.qh"
 
 #if defined(CSQC)
-       #include "../dpdefs/csprogsdefs.qh"
     #include "../client/defs.qh"
     #include "constants.qh"
        #include "../client/mutators/events.qh"
     #include "mapinfo.qh"
-    #include "notifications.qh"
-    #include "deathtypes.qh"
+    #include "notifications/all.qh"
+    #include <common/deathtypes/all.qh>
 #elif defined(MENUQC)
 #elif defined(SVQC)
-       #include "../dpdefs/progsdefs.qh"
-    #include "../dpdefs/dpextensions.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 <common/deathtypes/all.qh>
     #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)
@@ -38,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)
-{SELFPARAM();
+{
        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)
-{SELFPARAM();
+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)
@@ -72,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;
@@ -168,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;
@@ -208,257 +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;
-}
-
-// 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)
-       {
-               LOG_INFO(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;
-       LOG_INFO("LOAD...\n");
-       db = db_load("foo.db");
-       LOG_INFO("LOADED. FILL...\n");
-       for(i = 0; i < DB_BUCKETS; ++i)
-               db_put(db, ftos(random()), "X");
-       LOG_INFO("FILLED. SAVE...\n");
-       db_save(db, "foo.db");
-       LOG_INFO("SAVED. CLOSE...\n");
-       db_close(db);
-       LOG_INFO("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;
@@ -503,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;
@@ -518,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;
@@ -538,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);
        }
 
@@ -570,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);
@@ -598,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)
        {
@@ -625,7 +349,7 @@ void compressShortVector_init()
        }
 }
 
-#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;
@@ -672,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;
@@ -686,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);
@@ -698,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), " ");
@@ -721,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;
@@ -762,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;
@@ -779,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;
 
@@ -788,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;
 
@@ -797,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;
 
@@ -806,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;
 
@@ -815,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;
 
@@ -824,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;
                }
@@ -877,13 +584,12 @@ 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))
        {
-               LOG_TRACE("Error: Invalid usage of cvar_settemp(string, string); !\n");
+               LOG_TRACE("Error: Invalid usage of cvar_settemp(string, string); !");
                return 0;
        }
 
@@ -893,15 +599,17 @@ float cvar_settemp(string tmp_cvar, string tmp_value)
                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;
@@ -913,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
-                       LOG_INFOF("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;
+       int i = 0;
+       while(pos - i >= 1 && substring(theText, pos - i - 1, 1) == "^")
+               ++i;
+       return (i & 1);
 }
 
-float almost_in_bounds(float a, float b, float c)
+int skipIncompleteTag(string theText, float pos, int len)
 {
-       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 tag_start = -1;
 
-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)
-               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.
@@ -1192,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;
 }
 
@@ -1256,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;
 }
 
@@ -1316,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;
@@ -1330,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
@@ -1454,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), ",");
@@ -1500,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;
@@ -1720,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)
        {
-               LOG_INFO("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)
        {
-               LOG_INFO("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)
        {
-               LOG_INFO("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)
 {
@@ -1750,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
@@ -1861,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
@@ -1882,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;
@@ -2009,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)
 {
@@ -2049,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
 
@@ -2115,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)
@@ -2126,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)))
@@ -2141,99 +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;
-}
-
 // x-encoding (encoding as zero length invisible string)
 const string XENCODE_2  = "xX";
 const string XENCODE_22 = "0123456789abcdefABCDEF";
@@ -2268,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)
 {
@@ -2287,26 +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;
-}
-
-#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()
@@ -2326,49 +1367,12 @@ void m_shutdown()
        {
                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)
 {
@@ -2404,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)
 {
@@ -2492,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:
@@ -2500,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;
@@ -2509,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;
                        }
                }
@@ -2520,92 +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
-
-// 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
-{
-       if(server_is_dedicated) { LOG_INFO(input); }
-}
-#endif
-
-#ifndef MENUQC
-float Announcer_PickNumber(float type, float num)
+#ifdef GAMEQC
+Notification Announcer_PickNumber(int type, int num)
 {
-       switch(type)
+    return = NULL;
+       switch (type)
        {
                case CNT_GAMESTART:
                {
@@ -2710,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)
@@ -2750,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;
-}