Merge branch 'master' into martin-t/globals
authorMartin Taibr <taibr.martin@gmail.com>
Mon, 1 Jul 2019 16:22:58 +0000 (18:22 +0200)
committerMartin Taibr <taibr.martin@gmail.com>
Mon, 1 Jul 2019 16:22:58 +0000 (18:22 +0200)
1  2 
qcsrc/client/csqcmodel_hooks.qc
qcsrc/client/view.qc
qcsrc/common/debug.qh
qcsrc/common/mutators/mutator/damagetext/cl_damagetext.qc
qcsrc/common/mutators/mutator/spawn_near_teammate/sv_spawn_near_teammate.qc
qcsrc/common/weapons/weapon/shockwave.qc
qcsrc/lib/_all.inc
qcsrc/lib/deglobalization.qh
qcsrc/lib/warpzone/anglestransform.qh
qcsrc/lib/warpzone/server.qc
qcsrc/server/weapons/weaponsystem.qc

@@@ -341,10 -341,10 +341,10 @@@ void CSQCPlayer_FallbackFrame_PostUpdat
        // player "pops in"
        if(isnew)
        {
- #define FIX_FRAMETIME(f,ft) MACRO_BEGIN {                                                                                                                                                     \
-               if(IS_DEAD_FRAME(this.f) && this.ft != 0 && this.death_time != 0)                                                                                       \
-                       this.ft = this.death_time;                                                                                                                                                              \
MACRO_END
+ #define FIX_FRAMETIME(f,ft) MACRO_BEGIN \
+               if(IS_DEAD_FRAME(this.f) && this.ft != 0 && this.death_time != 0) \
+                       this.ft = this.death_time; \
+ MACRO_END
                FIX_FRAMETIME(frame, frame1time);
                FIX_FRAMETIME(frame2, frame2time);
  #ifdef CSQCMODEL_HAVE_TWO_FRAMES
@@@ -441,7 -441,7 +441,7 @@@ void CSQCModel_AutoTagIndex_Apply(entit
                                                        LOG_TRACE("h_ model lacks weapon attachment, but v_ model is attached to it");
                                                }
                                        }
-                                       else if(this.tag_entity.isplayermodel)
+                                       else if((this.tag_entity.isplayermodel & ISPLAYER_MODEL))
                                        {
                                                skeleton_loadinfo(this.tag_entity);
                                                this.tag_index = this.tag_entity.bone_weapon;
@@@ -540,11 -540,8 +540,11 @@@ void CSQCModel_Effects_Apply(entity thi
                tref = EFFECT_TR_BLOOD.m_id;
        if(this.csqcmodel_modelflags & MF_ROTATE)
        {
 +              // This will be hard to replace with MAKE_VECTORS because it's called as part of the predraw function
 +              // as documented in csprogs.h in the engine. The globals can then be read in many places in the engine.
 +              // However MR_ROTATE is currently only used in one place - might be possible to get rid of it entirely.
                this.renderflags |= RF_USEAXIS;
 -              MAKEVECTORS(makevectors, this.angles + '0 100 0' * fmod(time, 3.6), v_forward, v_right, v_up);
 +              makevectors(this.angles + '0 100 0' * fmod(time, 3.6));
        }
        if(this.csqcmodel_modelflags & MF_TRACER)
                tref = EFFECT_TR_WIZSPIKE.m_id;
@@@ -604,12 -601,17 +604,17 @@@ void CSQCModel_Hook_PreDraw(entity this
        if(!this.modelindex || this.model == "null" || this.alpha < 0)
        {
                this.drawmask = 0;
+               if(this.snd_looping > 0)
+               {
+                       sound(this, this.snd_looping, SND_Null, VOL_BASE, autocvar_cl_jetpack_attenuation);
+                       this.snd_looping = 0;
+               }
                return;
        }
        else
                this.drawmask = MASK_NORMAL;
  
-       if(this.isplayermodel && this.drawmask) // this checks if it's a player MODEL!
+       if((this.isplayermodel & ISPLAYER_MODEL) && this.drawmask) // this checks if it's a player MODEL!
        {
                CSQCPlayer_ModelAppearance_Apply(this, (this.isplayermodel & ISPLAYER_LOCAL));
                CSQCPlayer_LOD_Apply(this);
@@@ -700,7 -702,7 +705,7 @@@ void CSQCModel_Hook_PreUpdate(entity th
        this.iflags |= IFLAG_V_ANGLE_X;
        // revert to values from server
        CSQCModel_Effects_PreUpdate(this);
-       if(this.isplayermodel)
+       if((this.isplayermodel & ISPLAYER_MODEL))
        {
                if(!isplayer)
                        CSQCPlayer_FallbackFrame_PreUpdate(this);
@@@ -716,7 -718,7 +721,7 @@@ void CSQCModel_Hook_PostUpdate(entity t
        this.isplayermodel = BITSET(this.isplayermodel, ISPLAYER_MODEL, is_playermodel);
  
        // save values set by server
-       if(this.isplayermodel)
+       if((this.isplayermodel & ISPLAYER_MODEL))
        {
                CSQCPlayer_ModelAppearance_PostUpdate(this);
                if(isplayer)
diff --combined qcsrc/client/view.qc
@@@ -76,54 -76,46 +76,46 @@@ float autocvar_cl_leanmodel_lowpass = 0
        ret = ref_store = ref_store * (1 - frac) + (value) * frac;
  
  #define lowpass_limited(value, frac, limit, ref_store, ret) MACRO_BEGIN \
- { \
        float __ignore; lowpass(value, frac, ref_store, __ignore); \
        ret = ref_store = bound((value) - (limit), ref_store, (value) + (limit)); \
MACRO_END
+ MACRO_END
  
  #define highpass(value, frac, ref_store, ret) MACRO_BEGIN \
- { \
        float __f = 0; lowpass(value, frac, ref_store, __f); \
        ret = (value) - __f; \
MACRO_END
+ MACRO_END
  
  #define highpass_limited(value, frac, limit, ref_store, ret) MACRO_BEGIN \
- { \
        float __f = 0; lowpass_limited(value, frac, limit, ref_store, __f); \
        ret = (value) - __f; \
MACRO_END
+ MACRO_END
  
  #define lowpass2(value, frac, ref_store, ref_out) MACRO_BEGIN \
- { \
        lowpass(value.x, frac, ref_store.x, ref_out.x); \
        lowpass(value.y, frac, ref_store.y, ref_out.y); \
MACRO_END
+ MACRO_END
  
  #define highpass2(value, frac, ref_store, ref_out) MACRO_BEGIN \
- { \
        highpass(value.x, frac, ref_store.x, ref_out.x); \
        highpass(value.y, frac, ref_store.y, ref_out.y); \
MACRO_END
+ MACRO_END
  
  #define highpass2_limited(value, frac, limit, ref_store, ref_out) MACRO_BEGIN \
- { \
        highpass_limited(value.x, frac, limit, ref_store.x, ref_out.x); \
        highpass_limited(value.y, frac, limit, ref_store.y, ref_out.y); \
MACRO_END
+ MACRO_END
  
  #define lowpass3(value, frac, ref_store, ref_out) MACRO_BEGIN \
- { \
        lowpass(value.x, frac, ref_store.x, ref_out.x); \
        lowpass(value.y, frac, ref_store.y, ref_out.y); \
        lowpass(value.z, frac, ref_store.z, ref_out.z); \
MACRO_END
+ MACRO_END
  
  #define highpass3(value, frac, ref_store, ref_out) MACRO_BEGIN \
- { \
        highpass(value.x, frac, ref_store.x, ref_out.x); \
        highpass(value.y, frac, ref_store.y, ref_out.y); \
        highpass(value.z, frac, ref_store.z, ref_out.z); \
MACRO_END
+ MACRO_END
  
  void calc_followmodel_ofs(entity view)
  {
                vel = view.velocity;
        else
        {
 -              vector forward = '0 0 0', right = '0 0 0', up = '0 0 0';
 -              MAKEVECTORS(makevectors, view_angles, forward, right, up);
 +              MAKE_VECTORS_NEW(view_angles, forward, right, up);
                vel.x = view.velocity * forward;
                vel.y = view.velocity * right * -1;
                vel.z = view.velocity * up;
        if (autocvar_cl_followmodel_velocity_absolute)
        {
                vector fixed_gunorg;
 -              vector forward = '0 0 0', right = '0 0 0', up = '0 0 0';
 -              MAKEVECTORS(makevectors, view_angles, forward, right, up);
 +              MAKE_VECTORS_NEW(view_angles, forward, right, up);
                fixed_gunorg.x = gunorg * forward;
                fixed_gunorg.y = gunorg * right * -1;
                fixed_gunorg.z = gunorg * up;
@@@ -423,14 -417,14 +415,14 @@@ void Porto_Draw(entity this
  
                vector pos = view_origin;
                vector dir = view_forward;
 -              makevectors(((autocvar_chase_active) ? warpzone_save_view_angles : view_angles));
 -              pos += v_right * -wepent.movedir.y
 -                      +  v_up * wepent.movedir.z;
 +              MAKE_VECTORS_NEW(autocvar_chase_active ? warpzone_save_view_angles : view_angles, forward, right, up);
 +              pos += right * -wepent.movedir.y
 +                      +  up * wepent.movedir.z;
  
                if (wepent.angles_held_status)
                {
 -                      makevectors(wepent.angles_held);
 -                      dir = v_forward;
 +                      MAKE_VECTORS(wepent.angles_held, forward, right, up);
 +                      dir = forward;
                }
  
                wepent.polyline[0] = pos;
                        {
                                vector ang = vectoangles2(trace_plane_normal, dir);
                                ang.x = -ang.x;
 -                              makevectors(ang);
 -                              if (!CheckWireframeBox(this, pos - 48 * v_right - 48 * v_up + 16 * v_forward, 96 * v_right, 96 * v_up, 96 * v_forward))
 +                              MAKE_VECTORS(ang, forward, right, up);
 +                              if (!CheckWireframeBox(this, pos - 48 * right - 48 * up + 16 * forward, 96 * right, 96 * up, 96 * forward))
                                {
                                        n = max(2, idx);
                                        break;
@@@ -577,15 -571,15 +569,15 @@@ vector GetCurrentFov(float fov
                        curspeed = 0;
                else
                {
 -                      makevectors(view_angles);
 +                      MAKE_VECTORS_NEW(view_angles, forward, right, up);
                        v = pmove_vel;
                        if(csqcplayer)
                                v = csqcplayer.velocity;
  
                        switch(autocvar_cl_velocityzoom_type)
                        {
 -                              case 3: curspeed = max(0, v_forward * v); break;
 -                              case 2: curspeed = (v_forward * v); break;
 +                              case 3: curspeed = max(0, forward * v); break;
 +                              case 2: curspeed = (forward * v); break;
                                case 1: default: curspeed = vlen(v); break;
                        }
                }
@@@ -1354,21 -1348,22 +1346,22 @@@ void HUD_Crosshair(entity this
                        }
  
  #define CROSSHAIR_DO_BLUR(M,sz,wcross_name,wcross_alpha) \
-                       MACRO_BEGIN { \
+                       MACRO_BEGIN \
+                               vector scaled_sz = sz * wcross_size; \
                                if(wcross_blur > 0) \
                                { \
                                        for(i = -2; i <= 2; ++i) \
                                        for(j = -2; j <= 2; ++j) \
-                                       M(i,j,sz,wcross_name,wcross_alpha*0.04); \
+                                       M(i,j,sz,scaled_sz,wcross_name,wcross_alpha*0.04); \
                                } \
                                else \
                                { \
-                                       M(0,0,sz,wcross_name,wcross_alpha); \
+                                       M(0,0,sz,scaled_sz,wcross_name,wcross_alpha); \
                                } \
-                       MACRO_END
+                       MACRO_END
  
- #define CROSSHAIR_DRAW_SINGLE(i,j,sz,wcross_name,wcross_alpha) \
-                       drawpic(wcross_origin - ('0.5 0 0' * (sz * wcross_size.x + i * wcross_blur) + '0 0.5 0' * (sz * wcross_size.y + j * wcross_blur)), wcross_name, sz * wcross_size, wcross_color, wcross_alpha, DRAWFLAG_NORMAL)
+ #define CROSSHAIR_DRAW_SINGLE(i,j,sz,scaled_sz,wcross_name,wcross_alpha) \
+                       drawpic(wcross_origin - ('0.5 0 0' * (scaled_sz.x + i * wcross_blur) + '0 0.5 0' * (scaled_sz.y + j * wcross_blur)), wcross_name, scaled_sz, wcross_color, wcross_alpha, DRAWFLAG_NORMAL)
  
  #define CROSSHAIR_DRAW(sz,wcross_name,wcross_alpha) \
                        CROSSHAIR_DO_BLUR(CROSSHAIR_DRAW_SINGLE,sz,wcross_name,wcross_alpha)
@@@ -1589,6 -1584,15 +1582,15 @@@ void HUD_Mouse(entity player
                return;
        }
  
+       if (cursor_active == -1) // starting to display the cursor
+       {
+               // since HUD_Mouse is called by CSQC_UpdateView before CSQC_InputEvent,
+               // in the first frame mousepos is the mouse position of the last time
+               // the cursor was displayed, thus we ignore it to avoid a glictch
+               cursor_active = 1;
+               return;
+       }
        if(!autocvar_hud_cursormode)
                update_mousepos();
  
@@@ -1806,18 -1810,18 +1808,18 @@@ void CSQC_UpdateView(entity this, floa
                        else if(eventchase_current_distance != chase_distance)
                                eventchase_current_distance = chase_distance;
  
 -                      makevectors(view_angles);
 +                      MAKE_VECTORS_NEW(view_angles, forward, right, up);
  
 -                      vector eventchase_target_origin = (current_view_origin - (v_forward * eventchase_current_distance));
 +                      vector eventchase_target_origin = (current_view_origin - (forward * eventchase_current_distance));
                        WarpZone_TraceBox(current_view_origin, autocvar_cl_eventchase_mins, autocvar_cl_eventchase_maxs, eventchase_target_origin, MOVE_WORLDONLY, this);
  
                        // If the boxtrace fails, revert back to line tracing.
                        if(!local_player.viewloc)
                        if(trace_startsolid)
                        {
 -                              eventchase_target_origin = (current_view_origin - (v_forward * eventchase_current_distance));
 +                              eventchase_target_origin = (current_view_origin - (forward * eventchase_current_distance));
                                WarpZone_TraceLine(current_view_origin, eventchase_target_origin, MOVE_WORLDONLY, this);
 -                              setproperty(VF_ORIGIN, (trace_endpos - (v_forward * autocvar_cl_eventchase_mins.z)));
 +                              setproperty(VF_ORIGIN, (trace_endpos - (forward * autocvar_cl_eventchase_mins.z)));
                        }
                        else { setproperty(VF_ORIGIN, trace_endpos); }
  
        // Render the Scene
        view_origin = getpropertyvec(VF_ORIGIN);
        view_angles = getpropertyvec(VF_ANGLES);
 -      MAKEVECTORS(makevectors, view_angles, view_forward, view_right, view_up);
 +      MAKE_VECTORS(view_angles, view_forward, view_right, view_up);
  
  #ifdef BLURTEST
        if(time > blurtest_time0 && time < blurtest_time1)
        {
                if(!minigame_wasactive)
                {
-                       localcmd("+button14\n");
+                       localcmd("+button12\n");
                        minigame_wasactive = true;
                }
        }
        else if(minigame_wasactive)
        {
-               localcmd("-button14\n");
+               localcmd("-button12\n");
                minigame_wasactive = false;
        }
  
                R_EndPolygon();
        }
  
-       if(autocvar_cl_reticle)
+       if(autocvar_cl_reticle && !MUTATOR_CALLHOOK(DrawReticle))
        {
                string reticle_image = string_null;
                bool wep_zoomed = false;
                setproperty(VF_ORIGIN, '0 0 0');
                setproperty(VF_ANGLES, '0 0 0');
                setproperty(VF_PERSPECTIVE, 1);
 -              makevectors('0 0 0');
 +              MAKE_VECTORS_NEW('0 0 0', forward, right, up);
                vector v1, v2;
                cvar_set("vid_conwidth", "800");
                cvar_set("vid_conheight", "600");
 -              v1 = cs_project(v_forward);
 +              v1 = cs_project(forward);
                cvar_set("vid_conwidth", "640");
                cvar_set("vid_conheight", "480");
 -              v2 = cs_project(v_forward);
 +              v2 = cs_project(forward);
                if(v1 == v2)
                        cs_project_is_b0rked = 1;
                else
diff --combined qcsrc/common/debug.qh
@@@ -205,8 -205,7 +205,7 @@@ GENERIC_COMMAND(bufstr_get, "Examine a 
                {
                        int bufhandle = stof(argv(1));
                        int string_index = stof(argv(2));
-                       string s = bufstr_get(bufhandle, string_index);
-                       LOG_INFOF("%s", s);
+                       LOG_INFO(bufstr_get(bufhandle, string_index));
                        return;
                }
  
@@@ -296,7 -295,7 +295,7 @@@ MUTATOR_HOOKFUNCTION(trace, SV_StartFra
                        it.solid = SOLID_BBOX;
                });
                vector forward = '0 0 0'; vector right = '0 0 0'; vector up = '0 0 0';
 -              MAKEVECTORS(makevectors, it.v_angle, forward, right, up);
 +              MAKE_VECTORS(it.v_angle, forward, right, up);
                vector pos = it.origin + it.view_ofs;
                traceline(pos, pos + forward * max_shot_distance, MOVE_NORMAL, it);
                FOREACH_ENTITY(true, {
@@@ -407,7 -406,7 +406,7 @@@ CLASS(DebugText3d, Object
                CONSTRUCT(DebugText3d);
                this.origin = pos;
                this.message = strzone(msg);
-               SetResourceAmount(this, RESOURCE_HEALTH, align);
+               SetResource(this, RES_HEALTH, align);
                this.hit_time = time;
                this.fade_rate = fade_rate_;
                this.velocity = vel;
                if (screen_pos.z < 0) return; // behind camera
  
                screen_pos.z = 0;
-               float align = GetResourceAmount(this, RESOURCE_HEALTH);
+               float align = GetResource(this, RES_HEALTH);
                string msg;
                vector msg_pos;
  
@@@ -74,9 -74,9 +74,9 @@@ CLASS(DamageText, Object
          if (this.m_screen_coords) {
              screen_pos = this.origin + since_hit * autocvar_cl_damagetext_2d_velocity;
          } else {
 -            makevectors(view_angles);
 +            MAKE_VECTORS_NEW(view_angles, forward, right, up);
              vector world_offset = since_hit * autocvar_cl_damagetext_velocity_world + autocvar_cl_damagetext_offset_world;
 -            vector world_pos = this.origin + world_offset.x * v_forward + world_offset.y * v_right + world_offset.z * v_up;
 +            vector world_pos = this.origin + world_offset.x * forward + world_offset.y * right + world_offset.z * up;
              screen_pos = project_3d_to_2d(world_pos) + since_hit * autocvar_cl_damagetext_velocity_screen + autocvar_cl_damagetext_offset_screen;
          }
          screen_pos.y += size / 2;
@@@ -237,7 -237,7 +237,7 @@@ NET_HANDLE(damagetext, bool isNew
  
      if (can_use_3d && !prefer_2d) {
          // world coords
-         // using 1 as minimum because of shotgun (same as menu)
+         // 1 as min because shotgun sends damagetext per pellet (see https://gitlab.com/xonotic/xonotic-data.pk3dir/issues/1994).
          for (entity e = findradius(entcs.origin, max(autocvar_cl_damagetext_accumulate_range, 1)); e; e = e.chain) {
              if (e.instanceOfDamageText
                  && !e.m_screen_coords // we're using origin for both world coords and screen coords so avoid mismatches
@@@ -91,11 -91,11 +91,11 @@@ MUTATOR_HOOKFUNCTION(spawn_near_teammat
  
                        if (PHYS_INPUT_BUTTON_CHAT(it)) continue;
                        if (DIFF_TEAM(player, it)) continue;
-                       if (autocvar_g_spawn_near_teammate_ignore_spawnpoint_check_health && GetResourceAmount(it, RESOURCE_HEALTH) < autocvar_g_balance_health_regenstable) continue;
+                       if (autocvar_g_spawn_near_teammate_ignore_spawnpoint_check_health && GetResource(it, RES_HEALTH) < autocvar_g_balance_health_regenstable) continue;
                        if (IS_DEAD(it)) continue;
                        if (time < it.msnt_timer) continue;
                        if (time < it.spawnshieldtime) continue;
-                       if (forbidWeaponUse(it)) continue;
+                       if (weaponLocked(it)) continue;
                        if (it == player) continue;
  
                        tested++; // i consider a teammate to be available when he passes the checks above
                        vector horiz_vel = vec2(it.velocity);
                        // when walking slowly sideways, we assume the player wants a clear shot ahead - spawn behind him according to where he's looking
                        // when running fast, spawn behind him according to his direction of movement to prevent colliding with the newly spawned player
 +                      vector forward = '0 0 0'; vector right = '0 0 0'; vector up = '0 0 0';
                        if (vdist(horiz_vel, >, autocvar_sv_maxspeed + 50))
 -                              fixedmakevectors(vectoangles(horiz_vel));
 +                      {
 +                              FIXED_MAKE_VECTORS(vectoangles(horiz_vel), forward, right, up);
 +                      }
                        else
 -                              fixedmakevectors(it.angles); // .angles is the angle of the model - usually/always 0 pitch
 +                      {
 +                              FIXED_MAKE_VECTORS(it.angles, forward, right, up);
 +                      }
  
                        // test different spots close to mate - trace upwards so it works on uneven surfaces
                        // don't spawn in front of player or directly behind to avoid players shooting each other
                                switch(i)
                                {
                                        case 0:
 -                                              tracebox(it.origin, STAT(PL_MIN, player), STAT(PL_MAX, player), it.origin - v_forward * 64 + v_right * 128 + v_up * 64, MOVE_NOMONSTERS, it);
 +                                              tracebox(it.origin, STAT(PL_MIN, player), STAT(PL_MAX, player), it.origin - forward * 64 + right * 128 + up * 64, MOVE_NOMONSTERS, it);
                                                break;
                                        case 1:
 -                                              tracebox(it.origin, STAT(PL_MIN, player), STAT(PL_MAX, player), it.origin - v_forward * 64 - v_right * 128 + v_up * 64, MOVE_NOMONSTERS, it);
 +                                              tracebox(it.origin, STAT(PL_MIN, player), STAT(PL_MAX, player), it.origin - forward * 64 - right * 128 + up * 64, MOVE_NOMONSTERS, it);
                                                break;
                                        case 2:
 -                                              tracebox(it.origin, STAT(PL_MIN, player), STAT(PL_MAX, player), it.origin + v_right * 192 + v_up * 64, MOVE_NOMONSTERS, it);
 +                                              tracebox(it.origin, STAT(PL_MIN, player), STAT(PL_MAX, player), it.origin + right * 192 + up * 64, MOVE_NOMONSTERS, it);
                                                break;
                                        case 3:
 -                                              tracebox(it.origin, STAT(PL_MIN, player), STAT(PL_MAX, player), it.origin - v_right * 192 + v_up * 64, MOVE_NOMONSTERS, it);
 +                                              tracebox(it.origin, STAT(PL_MIN, player), STAT(PL_MAX, player), it.origin - right * 192 + up * 64, MOVE_NOMONSTERS, it);
                                                break;
                                        case 4:
 -                                              tracebox(it.origin, STAT(PL_MIN, player), STAT(PL_MAX, player), it.origin - v_forward * 128 + v_right * 64 + v_up * 64, MOVE_NOMONSTERS, it);
 +                                              tracebox(it.origin, STAT(PL_MIN, player), STAT(PL_MAX, player), it.origin - forward * 128 + right * 64 + up * 64, MOVE_NOMONSTERS, it);
                                                break;
                                        case 5:
 -                                              tracebox(it.origin, STAT(PL_MIN, player), STAT(PL_MAX, player), it.origin - v_forward * 128 - v_right * 64 + v_up * 64, MOVE_NOMONSTERS, it);
 +                                              tracebox(it.origin, STAT(PL_MIN, player), STAT(PL_MAX, player), it.origin - forward * 128 - right * 64 + up * 64, MOVE_NOMONSTERS, it);
                                                break;
                                }
  
  
                                // 400 is about the height of a typical laser jump (in overkill)
                                // not traceline because we need space for the whole player, not just his origin
 -                              tracebox(horizontal_trace_endpos, STAT(PL_MIN, player), STAT(PL_MAX, player), horizontal_trace_endpos - '0 0 400', MOVE_NORMAL, it);
 +                              tracebox(horizontal_trace_endpos, STAT(PL_MIN, player), STAT(PL_MAX, player), horizontal_trace_endpos - 400 * up, MOVE_NORMAL, it);
                                vector vectical_trace_endpos = trace_endpos;
                                //te_lightning1(NULL, horizontal_trace_endpos, vectical_trace_endpos);
                                if (trace_startsolid) goto skip; // inside another player
                                if (tracebox_hits_trigger_hurt(horizontal_trace_endpos, STAT(PL_MIN, player), STAT(PL_MAX, player), vectical_trace_endpos)) goto skip;
  
                                // make sure the spawned player will have floor ahead (or at least a wall - he shouldn't fall as soon as he starts moving)
 -                              vector floor_test_start = vectical_trace_endpos + v_up * STAT(PL_MAX, player).z + v_forward * STAT(PL_MAX, player).x; // top front of player's bbox - highest point we know is not inside solid
 -                              traceline(floor_test_start, floor_test_start + v_forward * 100 - v_up * 128, MOVE_NOMONSTERS, it);
 +                              // top front of player's bbox - highest point we know is not inside solid
 +                              vector floor_test_start = vectical_trace_endpos + up * STAT(PL_MAX, player).z + forward * STAT(PL_MAX, player).x; 
 +                              traceline(floor_test_start, floor_test_start + forward * 100 - up * 128, MOVE_NOMONSTERS, it);
                                //te_beam(NULL, floor_test_start, trace_endpos);
                                if (trace_fraction == 1.0) goto skip;
  
  
                                // here, we know we found a good spot
                                RandomSelection_Add(it, 0, string_null, vectical_trace_endpos, 1, 1);
 -                              //te_lightning1(NULL, vectical_trace_endpos, vectical_trace_endpos + v_forward * 10);
 +                              //te_lightning1(NULL, vectical_trace_endpos, vectical_trace_endpos + forward * 10);
  
  LABEL(skip)
                                if (i % 2 == 1 && RandomSelection_chosen_ent)
@@@ -658,12 -658,14 +658,12 @@@ void Draw_Shockwave(entity this
        if(a < ALPHA_MIN_VISIBLE) { delete(this); }
  
        // WEAPONTODO: save this only once when creating the entity
-       vector sw_color = entcs_GetColor(this.sv_entnum - 1); // GetTeamRGB(entcs_GetTeam(this.sv_entnum));
+       vector sw_color = entcs_GetColor(this.sv_entnum - 1); // Team_ColorRGB(entcs_GetTeam(this.sv_entnum));
  
        // WEAPONTODO: trace to find what we actually hit
        vector endpos = (this.sw_shotorg + (this.sw_shotdir * this.sw_distance));
  
 -      vectorvectors(this.sw_shotdir);
 -      vector right = v_right; // save this for when we do makevectors later
 -      vector up = v_up; // save this for when we do makevectors later
 +      VECTOR_VECTORS_NEW(this.sw_shotdir, _forward, right, up);
  
        // WEAPONTODO: combine and simplify these calculations
        vector min_end = ((this.sw_shotorg + (this.sw_shotdir * SW_DISTTOMIN)) + (up * this.sw_spread_min));
diff --combined qcsrc/lib/_all.inc
  #include "counting.qh"
  #include "cvar.qh"
  #include "defer.qh"
 +#include "deglobalization.qh"
  #include "draw.qh"
  #include "enumclass.qh"
  #include "file.qh"
 +#include "float.qh"
  #include "functional.qh"
  #include "i18n.qh"
  #include "intrusivelist.qh"
@@@ -164,14 -162,14 +164,14 @@@ void make_safe_for_remove(entity this)
      #define objerror_safe(e) make_safe_for_remove(e)
  #endif
  
- #define objerror(this, msg) MACRO_BEGIN \
+ #define objerror(this, msg) MACRO_BEGIN \
        LOG_WARN("======OBJECT ERROR======"); \
        entity _e = (this); \
        eprint(_e); \
        objerror_safe(_e); \
        delete(_e); \
        LOG_WARNF("%s OBJECT ERROR in %s:\n%s\nTip: read above for entity information", PROGNAME, __FUNC__, msg); \
MACRO_END
+ MACRO_END
  
  #ifdef MENUQC
        void _m_init();
index bd43ab1,0000000..55dbbe5
mode 100644,000000..100644
--- /dev/null
@@@ -1,90 -1,0 +1,90 @@@
- #define MAKE_VECTORS(angles, forward, right, up) MACRO_BEGIN { \
 +#include "lib/float.qh"
 +#include "lib/misc.qh"
 +#include "lib/static.qh"
 +#include "lib/vector.qh"
 +
 +// These macros wrap functions which use globals so mutation only occurs inside them and is not visible from outside.
 +// Functions for which all usages are replaced with these macros can be hidden by #defines inside our `*defs.qh` files
 +// to prevent anyone from using them accidentally in the future
 +
 +// TODO stuff in the engine that uses the v_forward/v_right/v_up globals and is not wrapped yet:
 +//  - RF_USEAXIS, addentities, predraw,
 +//    - CL_GetEntityMatrix (in engine but is called from other functions so transitively any of them can use the globals - e.g. V_CalcRefdef, maybe others)
 +//    - however RF_USEAXIS is only used if MF_ROTATE is used which is only set in one place
 +//  - e.camera_transform / CL_VM_TransformView (in engine)
 +//    - this is the only used function that both sets and gets the globals (aim does too but isn't used in our code)
 +
 +// convenience for deglobalization code - don't use these just to hide that globals are still used
 +#define CLEAR_V_GLOBALS() v_forward = VEC_NAN; v_right = VEC_NAN; v_up = VEC_NAN
 +#define GET_V_GLOBALS(forward, right, up) forward = v_forward; right = v_right; up = v_up
 +#define SET_V_GLOBALS(forward, right, up) v_forward = forward; v_right = right; v_up = up
 +
 +#ifdef GAMEQC
 +STATIC_INIT(globals) {
 +      // set to NaN to more easily detect uninitialized use
 +      // TODO when all functions are wrapped and the raw functions are not used anymore,
 +      // uncomment the defines in *progs.qh files that hide the raw functions
 +      // and assert that the global vectors are NaN before calling the raw functions here
 +      // to make sure nobody (even builtins) is accidentally using them - NaN is the most likely value to expose remaining usages
 +
 +      CLEAR_V_GLOBALS();
 +}
 +#endif
 +
 +/// Same as the `makevectors` builtin but uses the provided locals instead of the `v_*` globals.
 +/// Always use this instead of raw `makevectors` to make the data flow clear.
 +/// Note that you might prefer `FIXED_MAKE_VECTORS` for new code.
- } MACRO_END
++#define MAKE_VECTORS(angles, forward, right, up) MACRO_BEGIN \
 +      _makevectors_hidden(angles); \
 +      GET_V_GLOBALS(forward, right, up); \
 +      CLEAR_V_GLOBALS(); \
- #define SKEL_GET_BONE_ABS(skel, bonenum, forward, right, up, origin) MACRO_BEGIN { \
++MACRO_END
 +
 +/// Same as `MAKE_VECTORS` but also creates the locals for convenience.
 +#define MAKE_VECTORS_NEW(angles, forward, right, up) \
 +      vector forward = '0 0 0', right = '0 0 0', up = '0 0 0'; \
 +      MAKE_VECTORS(angles, forward, right, up);
 +
 +/// Returns all 4 vectors by assigning to them (instead of returning a value) for consistency (and sanity)
- } MACRO_END
++#define SKEL_GET_BONE_ABS(skel, bonenum, forward, right, up, origin) MACRO_BEGIN \
 +      origin = _skel_get_boneabs_hidden(skel, bonenum) \
 +      GET_V_GLOBALS(forward, right, up); \
 +      CLEAR_V_GLOBALS(); \
- #define SKEL_SET_BONE(skel, bonenum, org, forward, right, up) MACRO_BEGIN { \
++MACRO_END
 +
 +#define SKEL_GET_BONE_ABS_NEW(skel, bonenum, forward, right, up, origin) \
 +      vector forward = '0 0 0', right = '0 0 0', up = '0 0 0', origin = '0 0 0'; \
 +      SKEL_GET_BONE_ABS(skel, bonenum, forward, right, up, origin)
 +
- } MACRO_END
++#define SKEL_SET_BONE(skel, bonenum, org, forward, right, up) MACRO_BEGIN \
 +      SET_V_GLOBALS(forward, right, up); \
 +      _skel_set_bone_hidden(skel, bonenum, org); \
 +      CLEAR_V_GLOBALS(); \
- #define ADD_DYNAMIC_LIGHT(org, radius, lightcolours, forward, right, up) MACRO_BEGIN { \
++MACRO_END
 +
- } MACRO_END
++#define ADD_DYNAMIC_LIGHT(org, radius, lightcolours, forward, right, up) MACRO_BEGIN \
 +      SET_V_GLOBALS(forward, right, up); \
 +      _adddynamiclight_hidden(org, radius, lightcolours); \
 +      CLEAR_V_GLOBALS(); \
- #define VECTOR_VECTORS(forward_in, forward, right, up) MACRO_BEGIN { \
++MACRO_END
 +
- } MACRO_END
++#define VECTOR_VECTORS(forward_in, forward, right, up) MACRO_BEGIN \
 +      _vectorvectors_hidden(forward_in); \
 +      GET_V_GLOBALS(forward, right, up); \
 +      CLEAR_V_GLOBALS(); \
- #define GET_TAG_INFO(ent, tagindex, forward, right, up, origin) MACRO_BEGIN {  \
++MACRO_END
 +
 +#define VECTOR_VECTORS_NEW(forward_in, forward, right, up) \
 +      vector forward = '0 0 0', right = '0 0 0', up = '0 0 0'; \
 +      VECTOR_VECTORS(forward_in, forward, right, up);
 +
 +/// Note that this only avoids the v_* globals, not the gettaginfo_* ones
- } MACRO_END
++#define GET_TAG_INFO(ent, tagindex, forward, right, up, origin) MACRO_BEGIN \
 +      origin = _gettaginfo_hidden(ent, tagindex); \
 +      GET_V_GLOBALS(forward, right, up); \
 +      CLEAR_V_GLOBALS(); \
++MACRO_END
 +
 +#define GET_TAG_INFO_NEW(ent, tagindex, forward, right, up, origin) \
 +      vector forward = '0 0 0', right = '0 0 0', up = '0 0 0', origin = '0 0 0'; \
 +      GET_TAG_INFO(ent, tagindex, forward, right, up, origin);
@@@ -6,8 -6,6 +6,8 @@@
  
  #if POSITIVE_PITCH_IS_DOWN
      #define fixedmakevectors makevectors
 +    #define FIXED_MAKE_VECTORS MAKE_VECTORS
 +    #define FIXED_MAKE_VECTORS_NEW MAKE_VECTORS_NEW
      noref vector _fixedvectoangles;
      #define fixedvectoangles(a) (_fixedvectoangles = vectoangles(a), _fixedvectoangles.x *= -1, _fixedvectoangles)
      noref vector _fixedvectoangles2;
          a.x = -a.x;
          makevectors(a);
      }
-     #define FIXED_MAKE_VECTORS(angles, forward, right, up) MACRO_BEGIN { \
++    #define FIXED_MAKE_VECTORS(angles, forward, right, up) MACRO_BEGIN \
 +        fixedmakevectors(angles); \
 +        GET_V_GLOBALS(forward, right, up); \
 +        CLEAR_V_GLOBALS(); \
-     } MACRO_END
++    MACRO_END
 +    #define FIXED_MAKE_VECTORS_NEW(angles, forward, right, up) \
 +        VECS_NEW(forward, right, up); \
 +        FIXED_MAKE_VECTORS(angles, forward, right, up);
      #define fixedvectoangles2 vectoangles2
      #define fixedvectoangles vectoangles
  #endif
@@@ -10,6 -10,7 +10,7 @@@
        #include <common/util.qh>
        #include <server/constants.qh>
        #include <server/defs.qh>
+       #include <server/utils.qh>
  #endif
  
  #ifdef WARPZONELIB_KEEPDEBUG
  .float warpzone_teleport_finishtime;
  .entity warpzone_teleport_zone;
  
- #define WarpZone_StoreProjectileData(e_) MACRO_BEGIN \
+ #define WarpZone_StoreProjectileData(e_) MACRO_BEGIN \
        entity e = e_; \
        e.warpzone_oldorigin = e.origin; \
        e.warpzone_oldvelocity = e.velocity; \
        e.warpzone_oldangles = e.angles; \
-       MACRO_END
+       MACRO_END
  
  void WarpZone_TeleportPlayer(entity teleporter, entity player, vector to, vector to_angles, vector to_velocity)
  {
        player.lastteleporttime = time;
  #endif
        setorigin(player, to); // NOTE: this also aborts the move, when this is called by touch
+       player.angles = to_angles;
  #ifdef SVQC
        player.oldorigin = to; // for DP's unsticking
        player.fixangle = true;
+       if (IS_BOT_CLIENT(player))
+       {
+               // FIXME find a way to smooth view's angles change for bots too
+               player.v_angle = player.angles;
+               bot_aim_reset(player);
+       }
  #endif
-       player.angles = to_angles;
        player.velocity = to_velocity;
  
        BITXOR_ASSIGN(player.effects, EF_TELEPORT_BIT);
@@@ -595,15 -602,15 +602,15 @@@ void WarpZone_InitStep_UpdateTransform(
                if(area > 0)
                {
                        org = org - ((org - point) * norm) * norm; // project to plane
 -                      makevectors(ang);
 -                      if(norm * v_forward < 0)
 +                      MAKE_VECTORS_NEW(ang, forward, right, up);
 +                      if(norm * forward < 0)
                        {
                                LOG_INFO("Position target of trigger_warpzone near ", vtos(this.aiment.origin), " points into trigger_warpzone. BEWARE.");
                                norm = -1 * norm;
                        }
 -                      ang = vectoangles2(norm, v_up); // keep rotation, but turn exactly against plane
 +                      ang = vectoangles2(norm, up); // keep rotation, but turn exactly against plane
                        ang.x = -ang.x;
 -                      if(norm * v_forward < 0.99)
 +                      if(norm * forward < 0.99)
                                LOG_INFO("trigger_warpzone near ", vtos(this.aiment.origin), " has been turned to match plane orientation (", vtos(this.aiment.angles), " -> ", vtos(ang));
                        if(vdist(org - this.aiment.origin, >, 0.5))
                                LOG_INFO("trigger_warpzone near ", vtos(this.aiment.origin), " has been moved to match the plane (", vtos(this.aiment.origin), " -> ", vtos(org), ").");
@@@ -373,6 -373,10 +373,6 @@@ void weapon_thinkf(entity actor, .entit
                restartanim = fr != WFRAME_IDLE;
        }
  
 -      vector of = v_forward;
 -      vector or = v_right;
 -      vector ou = v_up;
 -
        vector a = '0 0 0';
      this.wframe = fr;
      if (fr == WFRAME_IDLE) a = this.anim_idle;
          a = this.anim_reload;
      a.z *= g_weaponratefactor;
  
 -      v_forward = of;
 -      v_right = or;
 -      v_up = ou;
 -
        if (this.weapon_think == w_ready && func != w_ready && this.state == WS_RAISE) backtrace(
                        "Tried to override initial weapon think function - should this really happen?");
  
        }
  }
  
- bool forbidWeaponUse(entity player)
+ bool weaponUseForbidden(entity player)
+ {
+       if (round_handler_IsActive() && !round_handler_IsRoundStarted()) return true;
+       if (MUTATOR_CALLHOOK(ForbidWeaponUse, player)) return true;
+       return false;
+ }
+ bool weaponLocked(entity player)
  {
        if (time < game_starttime && !sv_ready_restart_after_countdown) return true;
        if (player.player_blocked) return true;
        if (game_stopped) return true;
        if (STAT(FROZEN, player)) return true;
-       if (MUTATOR_CALLHOOK(ForbidWeaponUse, player)) return true;
+       if (MUTATOR_CALLHOOK(LockWeapon, player)) return true;
        return false;
  }
  
@@@ -446,15 -461,15 +453,15 @@@ void W_WeaponFrame(Player actor, .entit
        entity this = actor.(weaponentity);
        if (frametime) this.weapon_frametime = frametime;
  
-       if (!this || GetResourceAmount(actor, RESOURCE_HEALTH) < 1) return;  // Dead player can't use weapons and injure impulse commands
+       if (!this || GetResource(actor, RES_HEALTH) < 1) return;  // Dead player can't use weapons and injure impulse commands
  
        int button_atck = PHYS_INPUT_BUTTON_ATCK(actor);
        int button_atck2 = PHYS_INPUT_BUTTON_ATCK2(actor);
  
-       if (round_handler_IsActive() && !round_handler_IsRoundStarted())
+       if (weaponUseForbidden(actor))
                button_atck = button_atck2 = 0; // forbid primary and secondary fire, switching is allowed
  
-       if (forbidWeaponUse(actor))
+       if (weaponLocked(actor))
        {
                if (this.state != WS_CLEAR)
                {
                return;
        }
  
 -      makevectors(actor.v_angle);
 -      vector fo = v_forward;  // save them in case the weapon think functions change it
 -      vector ri = v_right;
 -      vector up = v_up;
 +      MAKE_VECTORS_NEW(actor.v_angle, fo, ri, up);
  
        // Change weapon
        if (this.m_weapon != this.m_switchweapon)
                bool block_weapon = false;
                {
                        bool key_pressed = PHYS_INPUT_BUTTON_HOOK(actor) && !actor.vehicle;
-                       if (round_handler_IsActive() && !round_handler_IsRoundStarted())
+                       if (weaponUseForbidden(actor))
                                key_pressed = false;
  
                        Weapon off = actor.offhand;
@@@ -681,9 -699,9 +688,9 @@@ void W_DecreaseAmmo(Weapon wep, entity 
                w_ent.clip_load -= ammo_use;
                w_ent.(weapon_load[w_ent.m_weapon.m_id]) = w_ent.clip_load;
        }
-       else if (wep.ammo_type != RESOURCE_NONE)
+       else if (wep.ammo_type != RES_NONE)
        {
-               float ammo = GetResourceAmount(actor, wep.ammo_type);
+               float ammo = GetResource(actor, wep.ammo_type);
                if (ammo < ammo_use)
                {
                        backtrace(sprintf(
                                ammo
                                             ));
                }
-               SetResourceAmount(actor, wep.ammo_type, ammo - ammo_use);
+               SetResource(actor, wep.ammo_type, ammo - ammo_use);
        }
  }
  
@@@ -716,17 -734,17 +723,17 @@@ void W_ReloadedAndReady(Weapon thiswep
        w_ent.clip_load = w_ent.old_clip_load;  // restore the ammo counter, in case we still had ammo in the weapon before reloading
  
        // if the gun uses no ammo, max out weapon load, else decrease ammo as we increase weapon load
-       if (!w_ent.reload_ammo_min || (actor.items & IT_UNLIMITED_WEAPON_AMMO) || wpn.ammo_type == RESOURCE_NONE)
+       if (!w_ent.reload_ammo_min || (actor.items & IT_UNLIMITED_WEAPON_AMMO) || wpn.ammo_type == RES_NONE)
        {
                w_ent.clip_load = w_ent.reload_ammo_amount;
        }
        else
        {
                // make sure we don't add more ammo than we have
-               float ammo = GetResourceAmount(actor, wpn.ammo_type);
+               float ammo = GetResource(actor, wpn.ammo_type);
                float load = min(w_ent.reload_ammo_amount - w_ent.clip_load, ammo);
                w_ent.clip_load += load;
-               SetResourceAmount(actor, wpn.ammo_type, ammo - load);
+               SetResource(actor, wpn.ammo_type, ammo - load);
        }
        w_ent.(weapon_load[w_ent.m_weapon.m_id]) = w_ent.clip_load;
  
@@@ -768,9 -786,9 +775,9 @@@ void W_Reload(entity actor, .entity wea
        if (this.clip_load >= this.reload_ammo_amount) return;
  
        // no ammo, so nothing to load
-       if (e.ammo_type != RESOURCE_NONE)
+       if (e.ammo_type != RES_NONE)
        {
-               if (!GetResourceAmount(actor, e.ammo_type) && this.reload_ammo_min)
+               if (!GetResource(actor, e.ammo_type) && this.reload_ammo_min)
                {
                        if (!(actor.items & IT_UNLIMITED_WEAPON_AMMO))
                        {