]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/common/util.qc
Merge branch 'master' into terencehill/scoreboard_item_stats
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / util.qc
index 3b7513013dc036475976c872d628ec572d8a4b67..ee0eb1058575e45e14db2221683793684ef15b30 100644 (file)
@@ -1,20 +1,22 @@
 #include "util.qh"
 
 #if defined(CSQC)
-    #include "constants.qh"
        #include <client/mutators/_mod.qh>
-    #include "mapinfo.qh"
-    #include "notifications/all.qh"
-       #include "scores.qh"
-    #include <common/deathtypes/all.qh>
+       #include <common/constants.qh>
+       #include <common/deathtypes/all.qh>
+       #include <common/gamemodes/_mod.qh>
+       #include <common/mapinfo.qh>
+       #include <common/notifications/all.qh>
+       #include <common/scores.qh>
 #elif defined(MENUQC)
 #elif defined(SVQC)
-    #include "constants.qh"
+       #include <common/constants.qh>
+       #include <common/deathtypes/all.qh>
+       #include <common/gamemodes/_mod.qh>
+       #include <common/mapinfo.qh>
+       #include <common/notifications/all.qh>
+       #include <common/scores.qh>
        #include <server/mutators/_mod.qh>
-    #include "notifications/all.qh"
-    #include <common/deathtypes/all.qh>
-       #include "scores.qh"
-    #include "mapinfo.qh"
 #endif
 
 #ifdef SVQC
@@ -508,7 +510,7 @@ 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;
+                       int wflags = REGISTRY_GET(Weapons, w).spawnflags;
                        if(wflags & WEP_FLAG_SPECIALATTACK)
                                continue;
                        for(i = 0; i < n; ++i)
@@ -1892,3 +1894,216 @@ int Mod_Q1BSP_NativeContentsFromSuperContents(int supercontents)
        return CONTENT_EMPTY;
 }
 #endif
+
+#ifdef SVQC
+void attach_sameorigin(entity e, entity to, string tag)
+{
+    vector org, t_forward, t_left, t_up, e_forward, e_up;
+    float tagscale;
+
+    org = e.origin - gettaginfo(to, gettagindex(to, tag));
+    tagscale = (vlen(v_forward) ** -2); // undo a scale on the tag
+    t_forward = v_forward * tagscale;
+    t_left = v_right * -tagscale;
+    t_up = v_up * tagscale;
+
+    e.origin_x = org * t_forward;
+    e.origin_y = org * t_left;
+    e.origin_z = org * t_up;
+
+    // current forward and up directions
+    if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
+               e.angles = AnglesTransform_FromVAngles(e.angles);
+       else
+               e.angles = AnglesTransform_FromAngles(e.angles);
+    fixedmakevectors(e.angles);
+
+    // untransform forward, up!
+    e_forward.x = v_forward * t_forward;
+    e_forward.y = v_forward * t_left;
+    e_forward.z = v_forward * t_up;
+    e_up.x = v_up * t_forward;
+    e_up.y = v_up * t_left;
+    e_up.z = v_up * t_up;
+
+    e.angles = fixedvectoangles2(e_forward, e_up);
+    if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
+               e.angles = AnglesTransform_ToVAngles(e.angles);
+       else
+               e.angles = AnglesTransform_ToAngles(e.angles);
+
+    setattachment(e, to, tag);
+    setorigin(e, e.origin);
+}
+
+void detach_sameorigin(entity e)
+{
+    vector org;
+    org = gettaginfo(e, 0);
+    e.angles = fixedvectoangles2(v_forward, v_up);
+    if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
+               e.angles = AnglesTransform_ToVAngles(e.angles);
+       else
+               e.angles = AnglesTransform_ToAngles(e.angles);
+    setorigin(e, org);
+    setattachment(e, NULL, "");
+    setorigin(e, e.origin);
+}
+
+void follow_sameorigin(entity e, entity to)
+{
+    set_movetype(e, MOVETYPE_FOLLOW); // make the hole follow
+    e.aiment = to; // make the hole follow bmodel
+    e.punchangle = to.angles; // the original angles of bmodel
+    e.view_ofs = e.origin - to.origin; // relative origin
+    e.v_angle = e.angles - to.angles; // relative angles
+}
+
+#if 0
+// TODO: unused, likely for a reason, possibly needs extensions (allow setting the new movetype as a parameter?)
+void unfollow_sameorigin(entity e)
+{
+    set_movetype(e, MOVETYPE_NONE);
+}
+#endif
+
+.string aiment_classname;
+.float aiment_deadflag;
+void SetMovetypeFollow(entity ent, entity e)
+{
+       // FIXME this may not be warpzone aware
+       set_movetype(ent, MOVETYPE_FOLLOW); // make the hole follow
+       ent.solid = SOLID_NOT; // MOVETYPE_FOLLOW is always non-solid - this means this cannot be teleported by warpzones any more! Instead, we must notice when our owner gets teleported.
+       ent.aiment = e; // make the hole follow bmodel
+       ent.punchangle = e.angles; // the original angles of bmodel
+       ent.view_ofs = ent.origin - e.origin; // relative origin
+       ent.v_angle = ent.angles - e.angles; // relative angles
+       ent.aiment_classname = strzone(e.classname);
+       ent.aiment_deadflag = e.deadflag;
+}
+void UnsetMovetypeFollow(entity ent)
+{
+       set_movetype(ent, MOVETYPE_FLY);
+       PROJECTILE_MAKETRIGGER(ent);
+       ent.aiment = NULL;
+}
+float LostMovetypeFollow(entity ent)
+{
+/*
+       if(ent.move_movetype != MOVETYPE_FOLLOW)
+               if(ent.aiment)
+                       error("???");
+*/
+       if(ent.aiment)
+       {
+               if(ent.aiment.classname != ent.aiment_classname)
+                       return 1;
+               if(ent.aiment.deadflag != ent.aiment_deadflag)
+                       return 1;
+       }
+       return 0;
+}
+#endif
+
+#ifdef GAMEQC
+// decolorizes and team colors the player name when needed
+string playername(string thename, int teamid, bool team_colorize)
+{
+       TC(int, teamid);
+       bool do_colorize = (teamplay && team_colorize);
+#ifdef SVQC
+       if(do_colorize && !intermission_running)
+#else
+       if(do_colorize)
+#endif
+    {
+        string t = Team_ColorCode(teamid);
+        return strcat(t, strdecolorize(thename));
+    }
+    else
+        return thename;
+}
+
+float trace_hits_box_a0, trace_hits_box_a1;
+
+float trace_hits_box_1d(float end, float thmi, float thma)
+{
+    if (end == 0)
+    {
+        // just check if x is in range
+        if (0 < thmi)
+            return false;
+        if (0 > thma)
+            return false;
+    }
+    else
+    {
+        // do the trace with respect to x
+        // 0 -> end has to stay in thmi -> thma
+        trace_hits_box_a0 = max(trace_hits_box_a0, min(thmi / end, thma / end));
+        trace_hits_box_a1 = min(trace_hits_box_a1, max(thmi / end, thma / end));
+        if (trace_hits_box_a0 > trace_hits_box_a1)
+            return false;
+    }
+    return true;
+}
+
+float trace_hits_box(vector start, vector end, vector thmi, vector thma)
+{
+    end -= start;
+    thmi -= start;
+    thma -= start;
+    // now it is a trace from 0 to end
+
+    trace_hits_box_a0 = 0;
+    trace_hits_box_a1 = 1;
+
+    if (!trace_hits_box_1d(end.x, thmi.x, thma.x))
+        return false;
+    if (!trace_hits_box_1d(end.y, thmi.y, thma.y))
+        return false;
+    if (!trace_hits_box_1d(end.z, thmi.z, thma.z))
+        return false;
+
+    return true;
+}
+
+float tracebox_hits_box(vector start, vector mi, vector ma, vector end, vector thmi, vector thma)
+{
+    return trace_hits_box(start, end, thmi - ma, thma - mi);
+}
+#endif
+
+ERASEABLE
+float cvar_or(string cv, float v)
+{
+       string s = cvar_string(cv);
+       if(s == "")
+               return v;
+       else
+               return stof(s);
+}
+
+// NOTE base is the central value
+// freq: circle frequency, = 2*pi*frequency in hertz
+// start_pos:
+//  -1 start from the lower value
+//   0 start from the base value
+//   1 start from the higher value
+ERASEABLE
+float blink_synced(float base, float range, float freq, float start_time, int start_pos)
+{
+       // note:
+       //   RMS = sqrt(base^2 + 0.5 * range^2)
+       // thus
+       //   base = sqrt(RMS^2 - 0.5 * range^2)
+       // ensure RMS == 1
+
+       return base + range * sin((time - start_time - (M_PI / 2) * start_pos) * freq);
+}
+
+ERASEABLE
+float blink(float base, float range, float freq)
+{
+       return blink_synced(base, range, freq, 0, 0);
+}