Merge branch 'master' into terencehill/translated_keys
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / util.qc
index deba86c..9c9896e 100644 (file)
@@ -2,7 +2,7 @@
 
 #if defined(CSQC)
     #include "constants.qh"
-       #include "../client/mutators/events.qh"
+       #include <client/mutators/_mod.qh>
     #include "mapinfo.qh"
     #include "notifications/all.qh"
        #include "scores.qh"
 #elif defined(MENUQC)
 #elif defined(SVQC)
     #include "constants.qh"
-       #include "../server/mutators/events.qh"
+       #include <server/mutators/_mod.qh>
     #include "notifications/all.qh"
     #include <common/deathtypes/all.qh>
        #include "scores.qh"
     #include "mapinfo.qh"
 #endif
 
+#ifdef SVQC
+float tracebox_inverted (vector v1, vector mi, vector ma, vector v2, float nomonsters, entity forent, float stopatentity, entity ignorestopatentity) // returns the number of traces done, for benchmarking
+{
+       vector pos, dir, t;
+       float nudge;
+       entity stopentity;
+
+       //nudge = 2 * cvar("collision_impactnudge"); // why not?
+       nudge = 0.5;
+
+       dir = normalize(v2 - v1);
+
+       pos = v1 + dir * nudge;
+
+       float c;
+       c = 0;
+
+       for (;;)
+       {
+               if(pos * dir >= v2 * dir)
+               {
+                       // went too far
+                       trace_fraction = 1;
+                       trace_endpos = v2;
+                       return c;
+               }
+
+               tracebox(pos, mi, ma, v2, nomonsters, forent);
+               ++c;
+
+               if(c == 50)
+               {
+                       LOG_TRACE("When tracing from ", vtos(v1), " to ", vtos(v2));
+                       LOG_TRACE("  Nudging gets us nowhere at ", vtos(pos));
+                       LOG_TRACE("  trace_endpos is ", vtos(trace_endpos));
+                       LOG_TRACE("  trace distance is ", ftos(vlen(pos - trace_endpos)));
+               }
+
+               stopentity = trace_ent;
+
+               if(trace_startsolid)
+               {
+                       // we started inside solid.
+                       // then trace from endpos to pos
+                       t = trace_endpos;
+                       tracebox(t, mi, ma, pos, nomonsters, forent);
+                       ++c;
+                       if(trace_startsolid)
+                       {
+                               // t is still inside solid? bad
+                               // force advance, then, and retry
+                               pos = t + dir * nudge;
+
+                               // but if we hit an entity, stop RIGHT before it
+                               if(stopatentity && stopentity && stopentity != ignorestopatentity)
+                               {
+                                       trace_ent = stopentity;
+                                       trace_endpos = t;
+                                       trace_fraction = ((trace_endpos - v1) * dir) / ((v2 - v1) * dir);
+                                       return c;
+                               }
+                       }
+                       else
+                       {
+                               // we actually LEFT solid!
+                               trace_fraction = ((trace_endpos - v1) * dir) / ((v2 - v1) * dir);
+                               return c;
+                       }
+               }
+               else
+               {
+                       // pos is outside solid?!? but why?!? never mind, just return it.
+                       trace_endpos = pos;
+                       trace_fraction = ((trace_endpos - v1) * dir) / ((v2 - v1) * dir);
+                       return c;
+               }
+       }
+}
+
+void traceline_inverted (vector v1, vector v2, float nomonsters, entity forent, float stopatentity, entity ignorestopatentity)
+{
+       tracebox_inverted(v1, '0 0 0', '0 0 0', v2, nomonsters, forent, stopatentity, ignorestopatentity);
+}
+#endif
+
 #ifdef GAMEQC
 /*
+==================
+findbetterlocation
+
+Returns a point at least 12 units away from walls
+(useful for explosion animations, although the blast is performed where it really happened)
+Ripped from DPMod
+==================
+*/
+vector findbetterlocation (vector org, float mindist)
+{
+       vector vec = mindist * '1 0 0';
+       int c = 0;
+       while (c < 6)
+       {
+               traceline (org, org + vec, true, NULL);
+               vec = vec * -1;
+               if (trace_fraction < 1)
+               {
+                       vector loc = trace_endpos;
+                       traceline (loc, loc + vec, true, NULL);
+                       if (trace_fraction >= 1)
+                               org = loc + vec;
+               }
+               if (c & 1)
+               {
+                       float h = vec.y;
+                       vec.y = vec.x;
+                       vec.x = vec.z;
+                       vec.z = h;
+               }
+               c = c + 1;
+       }
+
+       return org;
+}
+
+/*
 * Get "real" origin, in worldspace, even if ent is attached to something else.
 */
 vector real_origin(entity ent)
@@ -95,7 +217,8 @@ void wordwrap_cb(string s, float l, void(string) callback)
 
        s = strzone(s);
        lleft = l;
-       for (i = 0;i < strlen(s);++i)
+       int len = strlen(s);
+       for (i = 0; i < len; ++i)
        {
                if (substring(s, i, 2) == "\\n")
                {
@@ -113,12 +236,12 @@ void wordwrap_cb(string s, float l, void(string) callback)
                        if (lleft > 0)
                        {
                                callback(" ");
-                               lleft = lleft - 1;
+                               --lleft;
                        }
                }
                else
                {
-                       for (j = i+1;j < strlen(s);++j)
+                       for (j = i+1; j < len; ++j)
                                //    ^^ this skips over the first character of a word, which
                                //       is ALWAYS part of the word
                                //       this is safe since if i+1 == strlen(s), i will become
@@ -146,7 +269,7 @@ void wordwrap_cb(string s, float l, void(string) callback)
                                lleft = l;
                        }
                        callback(substring(s, i, wlen));
-                       lleft = lleft - wlen;
+                       lleft -= wlen;
                        i = j - 1;
                }
        }
@@ -336,19 +459,18 @@ STATIC_INIT(compressShortVector)
 
        if(cvar("developer"))
        {
-               LOG_INFO("Verifying vector compression table...");
+               LOG_TRACE("Verifying vector compression table...");
                for(i = 0x0F00; i < 0xFFFF; ++i)
                        if(i != compressShortVector(decompressShortVector(i)))
                        {
-                               LOG_INFOF(
+                               LOG_FATALF(
                                    "BROKEN vector compression: %s -> %s -> %s",
                                    ftos(i),
                                    vtos(decompressShortVector(i)),
                                    ftos(compressShortVector(decompressShortVector(i)))
                 );
-                               error("b0rk");
                        }
-               LOG_INFO("Done.");
+               LOG_TRACE("Done.");
        }
 }
 
@@ -453,14 +575,12 @@ void get_mi_min_max(float mode)
 {
        vector mi, ma;
 
-       if(mi_shortname)
-               strunzone(mi_shortname);
-       mi_shortname = mapname;
-       if(!strcasecmp(substring(mi_shortname, 0, 5), "maps/"))
-               mi_shortname = substring(mi_shortname, 5, strlen(mi_shortname) - 5);
-       if(!strcasecmp(substring(mi_shortname, strlen(mi_shortname) - 4, 4), ".bsp"))
-               mi_shortname = substring(mi_shortname, 0, strlen(mi_shortname) - 4);
-       mi_shortname = strzone(mi_shortname);
+       string s = mapname;
+       if(!strcasecmp(substring(s, 0, 5), "maps/"))
+               s = substring(s, 5, strlen(s) - 5);
+       if(!strcasecmp(substring(s, strlen(s) - 4, 4), ".bsp"))
+               s = substring(s, 0, strlen(s) - 4);
+       strcpy(mi_shortname, s);
 
 #ifdef CSQC
        mi = world.mins;
@@ -1129,6 +1249,8 @@ vector healtharmor_applydamage(float a, float armorblock, int deathtype, float d
        vector v;
        if (DEATH_IS(deathtype, DEATH_DROWN))  // Why should armor help here...
                armorblock = 0;
+       if (deathtype & HITTYPE_ARMORPIERCE)
+               armorblock = 0;
        v.y = bound(0, damage * armorblock, a); // save
        v.x = bound(0, damage - v.y, damage); // take
        v.z = 0;
@@ -1177,11 +1299,19 @@ float matchacl(string acl, string str)
                if(s == t)
                {
                        r = d;
+                       break; // if we found a killing case, apply it! other settings may be allowed in the future, but this one is caught
                }
        }
        return r;
 }
 
+ERASEABLE
+void write_String_To_File(int fh, string str, bool alsoprint)
+{
+       fputs(fh, str);
+       if (alsoprint) LOG_INFO(str);
+}
+
 string get_model_datafilename(string m, float sk, string fil)
 {
        if(m)
@@ -1308,6 +1438,148 @@ float get_model_parameters(string m, float sk)
        return 1;
 }
 
+string translate_key(string key)
+{
+       if (prvm_language == "en") return key;
+
+       switch(key)
+       {
+               case "TAB":                             return _("TAB");
+               case "ENTER":                   return _("ENTER");
+               case "ESCAPE":                  return _("ESCAPE");
+               case "SPACE":                   return _("SPACE");
+
+               case "BACKSPACE":               return _("BACKSPACE");
+               case "UPARROW":                 return _("UPARROW");
+               case "DOWNARROW":               return _("DOWNARROW");
+               case "LEFTARROW":               return _("LEFTARROW");
+               case "RIGHTARROW":              return _("RIGHTARROW");
+
+               case "ALT":                             return _("ALT");
+               case "CTRL":                    return _("CTRL");
+               case "SHIFT":                   return _("SHIFT");
+
+               case "F1":                              return _("F1");
+               case "F2":                              return _("F2");
+               case "F3":                              return _("F3");
+               case "F4":                              return _("F4");
+               case "F5":                              return _("F5");
+               case "F6":                              return _("F6");
+               case "F7":                              return _("F7");
+               case "F8":                              return _("F8");
+               case "F9":                              return _("F9");
+               case "F10":                             return _("F10");
+               case "F11":                             return _("F11");
+               case "F12":                             return _("F12");
+
+               case "INS":                             return _("INS");
+               case "DEL":                             return _("DEL");
+               case "PGDN":                    return _("PGDN");
+               case "PGUP":                    return _("PGUP");
+               case "HOME":                    return _("HOME");
+               case "END":                             return _("END");
+
+               case "PAUSE":                   return _("PAUSE");
+
+               case "NUMLOCK":                 return _("NUMLOCK");
+               case "CAPSLOCK":                return _("CAPSLOCK");
+               case "SCROLLOCK":               return _("SCROLLOCK");
+       }
+
+       if (substring(key, 0, 3) == "KP_")
+       {
+               string subkey = substring(key, 3, -1);
+               if (IS_DIGIT(substring(key, 3, 1))) // check only first digit
+               {
+                       return sprintf(_("KP_%d"), stof(subkey));
+               }
+
+               switch(subkey)
+               {
+                       case "INS":                             return sprintf(_("KP_%s"), _("INS"));
+                       case "END":                             return sprintf(_("KP_%s"), _("END"));
+                       case "DOWNARROW":               return sprintf(_("KP_%s"), _("DOWNARROW"));
+                       case "PGDN":                    return sprintf(_("KP_%s"), _("PGDN"));
+                       case "LEFTARROW":               return sprintf(_("KP_%s"), _("LEFTARROW"));
+                       case "RIGHTARROW":              return sprintf(_("KP_%s"), _("RIGHTARROW"));
+                       case "HOME":                    return sprintf(_("KP_%s"), _("HOME"));
+                       case "UPARROW":                 return sprintf(_("KP_%s"), _("UPARROW"));
+                       case "PGUP":                    return sprintf(_("KP_%s"), _("PGUP"));
+                       case "PERIOD":                  return sprintf(_("KP_%s"), _("PERIOD"));
+                       case "DEL":                             return sprintf(_("KP_%s"), _("DEL"));
+                       case "DIVIDE":                  return sprintf(_("KP_%s"), _("DIVIDE"));
+                       case "SLASH":                   return sprintf(_("KP_%s"), _("SLASH"));
+                       case "MULTIPLY":                return sprintf(_("KP_%s"), _("MULTIPLY"));
+                       case "MINUS":                   return sprintf(_("KP_%s"), _("MINUS"));
+                       case "PLUS":                    return sprintf(_("KP_%s"), _("PLUS"));
+                       case "ENTER":                   return sprintf(_("KP_%s"), _("ENTER"));
+                       case "EQUALS":                  return sprintf(_("KP_%s"), _("EQUALS"));
+                       default:                                return key;
+               }
+       }
+
+       if (key == "PRINTSCREEN") return _("PRINTSCREEN");
+
+       if (substring(key, 0, 5) == "MOUSE")
+               return sprintf(_("MOUSE%d"), stof(substring(key, 5, -1)));
+
+       if (key == "MWHEELUP") return _("MWHEELUP");
+       if (key == "MWHEELDOWN") return _("MWHEELDOWN");
+
+       if (substring(key, 0,3) == "JOY")
+               return sprintf(_("JOY%d"), stof(substring(key, 3, -1)));
+
+       if (substring(key, 0,3) == "AUX")
+               return sprintf(_("AUX%d"), stof(substring(key, 3, -1)));
+
+       if (substring(key, 0, 4) == "X360_")
+       {
+               string subkey = substring(key, 4, -1);
+               switch(subkey)
+               {
+                       case "DPAD_UP":                                 return sprintf(_("X360_%s"), _("DPAD_UP"));
+                       case "DPAD_DOWN":                               return sprintf(_("X360_%s"), _("DPAD_DOWN"));
+                       case "DPAD_LEFT":                               return sprintf(_("X360_%s"), _("DPAD_LEFT"));
+                       case "DPAD_RIGHT":                              return sprintf(_("X360_%s"), _("DPAD_RIGHT"));
+                       case "START":                                   return sprintf(_("X360_%s"), _("START"));
+                       case "BACK":                                    return sprintf(_("X360_%s"), _("BACK"));
+                       case "LEFT_THUMB":                              return sprintf(_("X360_%s"), _("LEFT_THUMB"));
+                       case "RIGHT_THUMB":                             return sprintf(_("X360_%s"), _("RIGHT_THUMB"));
+                       case "LEFT_SHOULDER":                   return sprintf(_("X360_%s"), _("LEFT_SHOULDER"));
+                       case "RIGHT_SHOULDER":                  return sprintf(_("X360_%s"), _("RIGHT_SHOULDER"));
+                       case "LEFT_TRIGGER":                    return sprintf(_("X360_%s"), _("LEFT_TRIGGER"));
+                       case "RIGHT_TRIGGER":                   return sprintf(_("X360_%s"), _("RIGHT_TRIGGER"));
+                       case "LEFT_THUMB_UP":                   return sprintf(_("X360_%s"), _("LEFT_THUMB_UP"));
+                       case "LEFT_THUMB_DOWN":                 return sprintf(_("X360_%s"), _("LEFT_THUMB_DOWN"));
+                       case "LEFT_THUMB_LEFT":                 return sprintf(_("X360_%s"), _("LEFT_THUMB_LEFT"));
+                       case "LEFT_THUMB_RIGHT":                return sprintf(_("X360_%s"), _("LEFT_THUMB_RIGHT"));
+                       case "RIGHT_THUMB_UP":                  return sprintf(_("X360_%s"), _("RIGHT_THUMB_UP"));
+                       case "RIGHT_THUMB_DOWN":                return sprintf(_("X360_%s"), _("RIGHT_THUMB_DOWN"));
+                       case "RIGHT_THUMB_LEFT":                return sprintf(_("X360_%s"), _("RIGHT_THUMB_LEFT"));
+                       case "RIGHT_THUMB_RIGHT":               return sprintf(_("X360_%s"), _("RIGHT_THUMB_RIGHT"));
+                       default:                                                return key;
+               }
+       }
+
+       if (substring(key, 0, 4) == "JOY_")
+       {
+               string subkey = substring(key, 4, -1);
+               switch(subkey)
+               {
+                       case "UP":                      return sprintf(_("JOY_%s"), _("UP"));
+                       case "DOWN":            return sprintf(_("JOY_%s"), _("DOWN"));
+                       case "LEFT":            return sprintf(_("JOY_%s"), _("LEFT"));
+                       case "RIGHT":           return sprintf(_("JOY_%s"), _("RIGHT"));
+                       default:                        return key;
+               }
+       }
+
+       if (substring(key, 0, 8) == "MIDINOTE")
+               return sprintf(_("MIDINOTE%d"), stof(substring(key, 8, -1)));
+
+       return key;
+}
+
 // x-encoding (encoding as zero length invisible string)
 const string XENCODE_2  = "xX";
 const string XENCODE_22 = "0123456789abcdefABCDEF";
@@ -1397,8 +1669,7 @@ void execute_next_frame()
        if(to_execute_next_frame)
        {
                localcmd("\n", to_execute_next_frame, "\n");
-               strunzone(to_execute_next_frame);
-               to_execute_next_frame = string_null;
+               strfree(to_execute_next_frame);
        }
 }
 void queue_to_execute_next_frame(string s)
@@ -1406,9 +1677,8 @@ void queue_to_execute_next_frame(string s)
        if(to_execute_next_frame)
        {
                s = strcat(s, "\n", to_execute_next_frame);
-               strunzone(to_execute_next_frame);
        }
-       to_execute_next_frame = strzone(s);
+       strcpy(to_execute_next_frame, s);
 }
 
 .float FindConnectedComponent_processing;