Merge branch 'terencehill/ft_bugfix' into 'master'
authorMario <zacjardine@y7mail.com>
Thu, 27 Sep 2018 01:26:44 +0000 (01:26 +0000)
committerMario <zacjardine@y7mail.com>
Thu, 27 Sep 2018 01:26:44 +0000 (01:26 +0000)
FT bugfixes

Closes #2098 and #2079

See merge request xonotic/xonotic-data.pk3dir!600

38 files changed:
_hud_common.cfg
qcsrc/client/hud/hud.qc
qcsrc/client/hud/panel/scoreboard.qc
qcsrc/client/hud/panel/scoreboard.qh
qcsrc/client/hud/panel/timer.qc
qcsrc/client/main.qc
qcsrc/client/view.qc
qcsrc/common/gamemodes/gamemode/clanarena/sv_clanarena.qc
qcsrc/common/mapobjects/func/bobbing.qc
qcsrc/common/mapobjects/func/button.qc
qcsrc/common/mapobjects/func/plat.qc
qcsrc/common/mutators/mutator/buffs/sv_buffs.qc
qcsrc/common/mutators/mutator/spawn_near_teammate/sv_spawn_near_teammate.qc
qcsrc/common/physics/movetypes/movetypes.qc
qcsrc/common/physics/movetypes/movetypes.qh
qcsrc/common/physics/movetypes/walk.qc
qcsrc/common/physics/player.qc
qcsrc/common/physics/player.qh
qcsrc/common/t_items.qc
qcsrc/common/weapons/weapon/shotgun.qc
qcsrc/menu/item.qc
qcsrc/menu/item.qh
qcsrc/menu/item/container.qh
qcsrc/menu/item/image.qh
qcsrc/menu/item/inputbox.qc
qcsrc/menu/item/label.qh
qcsrc/menu/item/listbox.qh
qcsrc/menu/xonotic/crosshairpreview.qh
qcsrc/menu/xonotic/picker.qh
qcsrc/server/cheats.qc
qcsrc/server/cheats.qh
qcsrc/server/client.qc
qcsrc/server/client.qh
qcsrc/server/defs.qh
qcsrc/server/miscfunctions.qc
qcsrc/server/player.qc
qcsrc/server/weapons/weaponsystem.qc
xonotic-client.cfg

index 3631df7eb4882cc7d2dc9d85063c845bff47c887..ee1babe195f253b7e6611d69ffef9b8c53015fc0 100644 (file)
@@ -115,6 +115,9 @@ seta hud_panel_scoreboard_spectators_showping 1 "show ping of spectators"
 seta hud_panel_scoreboard_spectators_aligned 0 "align spectators in columns"
 seta hud_panel_scoreboard_minwidth 0.6 "minimum width of the scoreboard"
 
+seta hud_panel_scoreboard_accuracy_showdelay 2 "how long to delay displaying accuracy below the scoreboard if it's too far down"
+seta hud_panel_scoreboard_accuracy_showdelay_minpos 0.75 "delay displaying the accuracy panel only if its position is lower than this percentage of the screen height from the top"
+
 // hud panel aliases
 alias quickmenu "cl_cmd hud quickmenu ${* ?}"
 
index a00accb0e8e917698b19ac36e488995412f9c0dc..bee8d0568ec2ac1afe7b7ba2704cb3dc77b08f9f 100644 (file)
@@ -574,7 +574,7 @@ bool HUD_WouldShowCursor()
                //return true;
        if(HUD_Radar_Clickable())
                return true;
-       if(HUD_MinigameMenu_IsOpened() || active_minigame)
+       if(HUD_MinigameMenu_IsOpened())
                return true;
        if(QuickMenu_IsOpened())
                return true;
index 32ccccfca3355dedfa235c20e96f316ee61ed2b4..3d9e333bab70f949d2e13dc0fac7a8d5b75abc17 100644 (file)
@@ -61,6 +61,9 @@ float autocvar_hud_panel_scoreboard_namesize = 15;
 bool autocvar_hud_panel_scoreboard_accuracy = true;
 bool autocvar_hud_panel_scoreboard_accuracy_doublerows = false;
 bool autocvar_hud_panel_scoreboard_accuracy_nocolors = false;
+float autocvar_hud_panel_scoreboard_accuracy_showdelay = 2;
+float autocvar_hud_panel_scoreboard_accuracy_showdelay_minpos = 0.75;
+
 bool autocvar_hud_panel_scoreboard_ctf_leaderboard = true;
 
 bool autocvar_hud_panel_scoreboard_dynamichud = false;
@@ -1025,6 +1028,12 @@ vector Scoreboard_DrawOthers(vector item_pos, vector rgb, int this_team, entity
                        field_pos.x += fieldpadding + (max(fieldsize, min_fieldsize) - fieldsize) * 0.5;
                        drawstring(field_pos, field, hud_fontsize, sbt_field_rgb, sbt_fg_alpha, DRAWFLAG_NORMAL);
                }
+               if(pl.eliminated)
+               {
+                       h_size.x = column_width + hud_fontsize.x * 0.25;
+                       h_size.y = hud_fontsize.y;
+                       drawfill(pos - hud_fontsize.x * 0.25 * eX, h_size, '0 0 0', 0.5 * panel_fg_alpha, DRAWFLAG_NORMAL);
+               }
                pos.x += column_width;
                pos.x += hud_fontsize.x;
        }
@@ -1146,6 +1155,15 @@ bool Scoreboard_WouldDraw()
 float average_accuracy;
 vector Scoreboard_AccuracyStats_Draw(vector pos, vector rgb, vector bg_size)
 {
+       if (frametime)
+       {
+               if (scoreboard_fade_alpha == 1)
+                       scoreboard_acc_fade_alpha = min(1, scoreboard_acc_fade_alpha + frametime * 10);
+               else
+                       scoreboard_acc_fade_alpha = 1; // sync fading with the scoreboard
+       }
+       vector initial_pos = pos;
+
        WepSet weapons_stat = WepSet_GetFromStat();
        WepSet weapons_inmap = WepSet_GetFromStat_InMap();
        int disownedcnt = 0;
@@ -1179,7 +1197,7 @@ vector Scoreboard_AccuracyStats_Draw(vector pos, vector rgb, vector bg_size)
        float weapon_height = 29;
        float height = hud_fontsize.y + weapon_height;
 
-       drawstring(pos + eX * panel_bg_padding, sprintf(_("Accuracy stats (average %d%%)"), average_accuracy), hud_fontsize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+       drawstring(pos + eX * panel_bg_padding, sprintf(_("Accuracy stats (average %d%%)"), average_accuracy), hud_fontsize, '1 1 1', panel_fg_alpha * scoreboard_acc_fade_alpha, DRAWFLAG_NORMAL);
        pos.y += 1.25 * hud_fontsize.y;
        if(panel.current_panel_bg != "0")
                pos.y += panel_bg_border;
@@ -1187,7 +1205,11 @@ vector Scoreboard_AccuracyStats_Draw(vector pos, vector rgb, vector bg_size)
        panel_pos = pos;
        panel_size.y = height * rows;
        panel_size.y += panel_bg_padding * 2;
+
+       float panel_bg_alpha_save = panel_bg_alpha;
+       panel_bg_alpha *= scoreboard_acc_fade_alpha;
        HUD_Panel_DrawBg();
+       panel_bg_alpha = panel_bg_alpha_save;
 
        vector end_pos = panel_pos + eY * (panel_size.y + hud_fontsize.y);
        if(panel.current_panel_bg != "0")
@@ -1205,18 +1227,18 @@ vector Scoreboard_AccuracyStats_Draw(vector pos, vector rgb, vector bg_size)
        float weapon_width = tmp.x / columnns / rows;
 
        if (sbt_bg_alpha)
-               drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb, sbt_bg_alpha, DRAWFLAG_NORMAL);
+               drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb, sbt_bg_alpha * scoreboard_acc_fade_alpha, DRAWFLAG_NORMAL);
 
        if(sbt_highlight)
        {
                // column highlighting
                for (int i = 0; i < columnns; ++i)
                        if ((i % 2) == 0)
-                               drawfill(pos + eX * weapon_width * rows * i, vec2(weapon_width * rows, height * rows), '0 0 0', sbt_highlight_alpha, DRAWFLAG_NORMAL);
+                               drawfill(pos + eX * weapon_width * rows * i, vec2(weapon_width * rows, height * rows), '0 0 0', sbt_highlight_alpha * scoreboard_acc_fade_alpha, DRAWFLAG_NORMAL);
 
                // row highlighting
                for (int i = 0; i < rows; ++i)
-                       drawfill(pos + eY * (weapon_height + height * i), vec2(tmp.x, hud_fontsize.y), rgb, sbt_highlight_alpha, DRAWFLAG_NORMAL);
+                       drawfill(pos + eY * (weapon_height + height * i), vec2(tmp.x, hud_fontsize.y), rgb, sbt_highlight_alpha * scoreboard_acc_fade_alpha, DRAWFLAG_NORMAL);
        }
 
        average_accuracy = 0;
@@ -1249,7 +1271,7 @@ vector Scoreboard_AccuracyStats_Draw(vector pos, vector rgb, vector bg_size)
                        weapon_alpha = 0.2 * sbt_fg_alpha;
 
                // weapon icon
-               drawpic_aspect_skin(tmpos, it.model2, vec2(weapon_width, weapon_height), '1 1 1', weapon_alpha, DRAWFLAG_NORMAL);
+               drawpic_aspect_skin(tmpos, it.model2, vec2(weapon_width, weapon_height), '1 1 1', weapon_alpha * scoreboard_acc_fade_alpha, DRAWFLAG_NORMAL);
                // the accuracy
                if (weapon_stats >= 0) {
                        weapons_with_stats += 1;
@@ -1264,7 +1286,7 @@ vector Scoreboard_AccuracyStats_Draw(vector pos, vector rgb, vector bg_size)
                        if(!autocvar_hud_panel_scoreboard_accuracy_nocolors)
                                rgb = Accuracy_GetColor(weapon_stats);
 
-                       drawstring(tmpos + vec2(padding, weapon_height), s, hud_fontsize, rgb, sbt_fg_alpha, DRAWFLAG_NORMAL);
+                       drawstring(tmpos + vec2(padding, weapon_height), s, hud_fontsize, rgb, sbt_fg_alpha * scoreboard_acc_fade_alpha, DRAWFLAG_NORMAL);
                }
                tmpos.x += weapon_width * rows;
                pos.x += weapon_width * rows;
@@ -1280,7 +1302,10 @@ vector Scoreboard_AccuracyStats_Draw(vector pos, vector rgb, vector bg_size)
                average_accuracy = floor((average_accuracy * 100 / weapons_with_stats) + 0.5);
 
        panel_size.x += panel_bg_padding * 2; // restore initial width
-       return end_pos;
+
+       if (scoreboard_acc_fade_alpha == 1)
+               return end_pos;
+       return initial_pos + (end_pos - initial_pos) * scoreboard_acc_fade_alpha;
 }
 
 vector MapStats_DrawKeyValue(vector pos, string key, string value) {
@@ -1469,6 +1494,39 @@ vector Scoreboard_Rankings_Draw(vector pos, entity pl, vector rgb, vector bg_siz
        return end_pos;
 }
 
+float scoreboard_time;
+bool have_weapon_stats;
+bool Scoreboard_AccuracyStats_WouldDraw(float ypos)
+{
+       if (gametype == MAPINFO_TYPE_CTS || gametype == MAPINFO_TYPE_RACE || gametype == MAPINFO_TYPE_NEXBALL)
+               return false;
+       if (!autocvar_hud_panel_scoreboard_accuracy || warmup_stage || ypos > 0.91 * vid_conheight)
+               return false;
+
+       if (time < scoreboard_time + autocvar_hud_panel_scoreboard_accuracy_showdelay
+               && ypos > autocvar_hud_panel_scoreboard_accuracy_showdelay_minpos * vid_conheight
+               && !intermission)
+       {
+               return false;
+       }
+
+       if (!have_weapon_stats)
+       {
+               FOREACH(Weapons, it != WEP_Null, {
+                       int weapon_stats = weapon_accuracy[i - WEP_FIRST];
+                       if (weapon_stats >= 0)
+                       {
+                               have_weapon_stats = true;
+                               break;
+                       }
+               });
+               if (!have_weapon_stats)
+                       return false;
+       }
+
+       return true;
+}
+
 void Scoreboard_Draw()
 {
        if(!autocvar__hud_configure)
@@ -1477,6 +1535,8 @@ void Scoreboard_Draw()
 
                // frametime checks allow to toggle the scoreboard even when the game is paused
                if(scoreboard_active) {
+                       if (scoreboard_fade_alpha < 1)
+                               scoreboard_time = time;
                        if(hud_configure_menu_open == 1)
                                scoreboard_fade_alpha = 1;
                        float scoreboard_fadeinspeed = autocvar_hud_panel_scoreboard_fadeinspeed;
@@ -1500,7 +1560,10 @@ void Scoreboard_Draw()
                }
 
                if (!scoreboard_fade_alpha)
+               {
+                       scoreboard_acc_fade_alpha = 0;
                        return;
+               }
        }
        else
                scoreboard_fade_alpha = 0;
@@ -1600,9 +1663,7 @@ void Scoreboard_Draw()
                pos = Scoreboard_MakeTable(pos, tm, panel_bg_color, bg_size);
        }
 
-       bool show_accuracy = (gametype != MAPINFO_TYPE_CTS && gametype != MAPINFO_TYPE_RACE && gametype != MAPINFO_TYPE_NEXBALL);
-
-       if (show_accuracy && autocvar_hud_panel_scoreboard_accuracy && !warmup_stage)
+       if (Scoreboard_AccuracyStats_WouldDraw(pos.y))
                pos = Scoreboard_AccuracyStats_Draw(pos, panel_bg_color, bg_size);
 
        if(gametype == MAPINFO_TYPE_CTS || gametype == MAPINFO_TYPE_RACE || (autocvar_hud_panel_scoreboard_ctf_leaderboard && gametype == MAPINFO_TYPE_CTF && STAT(CTF_SHOWLEADERBOARD))) {
index b2bda4829e1084b71652488f78b1444ca10b203e..f585b480fe70b119f2491c3df712d5475aa2f3b3 100644 (file)
@@ -3,6 +3,7 @@
 
 bool scoreboard_active;
 float scoreboard_fade_alpha;
+float scoreboard_acc_fade_alpha;
 
 void Cmd_Scoreboard_SetFields(int argc);
 void Scoreboard_Draw();
index 0dcbb70dba3cfe067d51160d74b2c26d8be70196..e01aa751757e3087b25038cdac422e6b162c4049 100644 (file)
@@ -63,6 +63,8 @@ void HUD_Timer()
 
        if (intermission_time) {
                timer = seconds_tostring(max(0, floor(intermission_time - STAT(GAMESTARTTIME))));
+       } else if (warmup_stage && warmup_timeleft >= 60) {
+               timer = _("WARMUP");
        } else if (autocvar_hud_panel_timer_increment || (!warmup_stage && timelimit == 0) || (warmup_stage && warmup_timeleft <= 0)) {
                if (time < STAT(GAMESTARTTIME))
                        timer = seconds_tostring(0); //while restart is still active, show 00:00
index c0d56c7981326507803b618014c733c557adde09..51324e1c5e09aa320895b35d1725ba572d21382d 100644 (file)
@@ -223,6 +223,8 @@ void Shutdown()
 
        localcmd("\ncl_hook_shutdown\n");
 
+       localcmd("\n-button14\n");
+
        deactivate_minigame();
        HUD_MinigameMenu_Close(NULL, NULL, NULL);
 }
index 2341cec7797120e9b69617d607767fb3c3f86106..00c3001c16a523abb107f795fea3612eb059e167 100644 (file)
@@ -633,6 +633,8 @@ vector GetOrthoviewFOV(vector ov_worldmin, vector ov_worldmax, vector ov_mid, ve
 // this function must match W_SetupShot!
 float zoomscript_caught;
 
+bool minigame_wasactive;
+
 vector wcross_origin;
 float wcross_scale_prev, wcross_alpha_prev;
 vector wcross_color_prev;
@@ -1592,7 +1594,7 @@ void HUD_Mouse(entity player)
                HUD_Panel_Mouse();
        else
        {
-               if (HUD_MinigameMenu_IsOpened() || active_minigame)
+               if (HUD_MinigameMenu_IsOpened())
                        HUD_Minigame_Mouse();
                if (QuickMenu_IsOpened())
                        QuickMenu_Mouse();
@@ -2010,6 +2012,20 @@ void CSQC_UpdateView(entity this, float w, float h)
                }
        }
 
+       if(active_minigame && HUD_MinigameMenu_IsOpened())
+       {
+               if(!minigame_wasactive)
+               {
+                       localcmd("+button14\n");
+                       minigame_wasactive = true;
+               }
+       }
+       else if(minigame_wasactive)
+       {
+               localcmd("-button14\n");
+               minigame_wasactive = false;
+       }
+
        ColorTranslateMode = autocvar_cl_stripcolorcodes;
 
        for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
index 4c889cb24be655fe22afa1af098046b1a0219082..9cd378f0fe6eacd521fe22e6f0bf3c5557b00ce5 100644 (file)
@@ -380,12 +380,12 @@ MUTATOR_HOOKFUNCTION(ca, PlayerDamage_SplitHealthArmor)
        entity frag_attacker = M_ARGV(1, entity);
        entity frag_target = M_ARGV(2, entity);
        float frag_damage = M_ARGV(7, float);
-       float damage_take = M_ARGV(4, float);
-       float damage_save = M_ARGV(5, float);
+       float damage_take = bound(0, M_ARGV(4, float), GetResourceAmount(frag_target, RESOURCE_HEALTH));
+       float damage_save = bound(0, M_ARGV(5, float), GetResourceAmount(frag_target, RESOURCE_ARMOR));
 
        float excess = max(0, frag_damage - damage_take - damage_save);
 
-       if (frag_target != frag_attacker && IS_PLAYER(frag_attacker))
+       if (frag_target != frag_attacker && IS_PLAYER(frag_attacker) && DIFF_TEAM(frag_target, frag_attacker))
                GameRules_scoring_add_team(frag_attacker, SCORE, (frag_damage - excess) * autocvar_g_ca_damage2score_multiplier);
 }
 
index b647e15a826e48164f03db46c5f62114a8e6afc6..60920fafb8c5c95599af7b2090570bfc30ae84d6 100644 (file)
@@ -48,6 +48,8 @@ spawnfunc(func_bobbing)
 
        this.active = ACTIVE_ACTIVE;
 
+       this.draggable = drag_undraggable;
+
        // damage when blocked
        setblocked(this, generic_plat_blocked);
        if(this.dmg && (this.message == ""))
index 44e31284336aae99eb35f580dff390b5db98797b..a8537f172534225adce4855a8713e34fdaecbcfb 100644 (file)
@@ -158,6 +158,7 @@ spawnfunc(func_button)
         precache_sound(this.noise);
 
        this.active = ACTIVE_ACTIVE;
+       this.draggable = drag_undraggable;
 
        this.pos1 = this.origin;
        this.pos2 = this.pos1 + this.movedir*(fabs(this.movedir*this.size) - this.lip);
index b052336217990a32a646d852679bc3c0d1d83c20..53dbed02fa42a50580b69efe7ef80143ba0b0f5e 100644 (file)
@@ -103,6 +103,7 @@ spawnfunc(func_plat)
        this.angles = '0 0 0';
 
        this.classname = "plat";
+       this.draggable = drag_undraggable;
        if (!InitMovingBrushTrigger(this))
                return;
        this.effects |= EF_LOWPRECISION;
index b7cdbf05b83c171ad278e61a3eb7e9c021ff78d6..9338c986c9d6ca3e3cd571c51895697a113e0543 100644 (file)
@@ -423,7 +423,7 @@ void buff_Medic_Heal(entity this)
 {
        FOREACH_CLIENT(IS_PLAYER(it) && it != this && vdist(it.origin - this.origin, <=, autocvar_g_buffs_medic_heal_range),
        {
-               if (!SAME_TEAM(it, this))
+               if (DIFF_TEAM(it, this))
                {
                        continue;
                }
index ee2a5be7f504d11c376bd85b31ec28b505b7eeec..fdcc4beee5fb51ab89c4ca8774638aa435241d14 100644 (file)
@@ -90,7 +90,7 @@ MUTATOR_HOOKFUNCTION(spawn_near_teammate, PlayerSpawn)
                        if (autocvar_g_spawn_near_teammate_ignore_spawnpoint_max && tested >= autocvar_g_spawn_near_teammate_ignore_spawnpoint_max) break;
 
                        if (PHYS_INPUT_BUTTON_CHAT(it)) continue;
-                       if (!SAME_TEAM(player, 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 (IS_DEAD(it)) continue;
                        if (time < it.msnt_timer) continue;
index e518fe21027fa5089623adf331c4ecabae65607d..e31b4076beca1072f2e1870f61fa0b73ec6800da 100644 (file)
@@ -406,11 +406,11 @@ entity _Movetype_TestEntityPosition_ent;
 bool _Movetype_TestEntityPosition(vector ofs)  // SV_TestEntityPosition
 {
     entity this = _Movetype_TestEntityPosition_ent;
-//     vector org = this.origin + ofs;
+       vector org = this.origin + ofs;
 
        int cont = this.dphitcontentsmask;
        this.dphitcontentsmask = DPCONTENTS_SOLID;
-       tracebox(this.origin, this.mins, this.maxs, this.origin, ((this.move_movetype == MOVETYPE_FLY_WORLDONLY) ? MOVE_WORLDONLY : MOVE_NOMONSTERS), this);
+       tracebox(org, this.mins, this.maxs, org, ((this.move_movetype == MOVETYPE_FLY_WORLDONLY) ? MOVE_WORLDONLY : MOVE_NOMONSTERS), this);
        this.dphitcontentsmask = cont;
 
        if(trace_startsolid)
@@ -421,11 +421,11 @@ bool _Movetype_TestEntityPosition(vector ofs)  // SV_TestEntityPosition
        return false;
 }
 
-bool _Movetype_UnstickEntity(entity this)  // SV_UnstickEntity
+int _Movetype_UnstickEntity(entity this)  // SV_UnstickEntity
 {
     _Movetype_TestEntityPosition_ent = this;
        if (!_Movetype_TestEntityPosition(' 0  0  0')) {
-           return true;
+           return UNSTICK_FINE;
        }
        #define X(v) if (_Movetype_TestEntityPosition(v))
        X('-1  0  0') X(' 1  0  0')
@@ -444,13 +444,32 @@ bool _Movetype_UnstickEntity(entity this)  // SV_UnstickEntity
         {
             LOG_DEBUGF("Can't unstick an entity (edict: %d, classname: %s, origin: %s)",
                 etof(this), this.classname, vtos(this.origin));
-            return false;
+            return UNSTICK_STUCK;
         }
        }
        LOG_DEBUGF("Sucessfully unstuck an entity (edict: %d, classname: %s, origin: %s)",
                etof(this), this.classname, vtos(this.origin));
        _Movetype_LinkEdict(this, true);
-       return true;
+       return UNSTICK_FIXED;
+}
+
+void _Movetype_CheckStuck(entity this)  // SV_CheckStuck
+{
+       int unstick = _Movetype_UnstickEntity(this); // sets test position entity
+       switch(unstick)
+       {
+               case UNSTICK_FINE:
+                       this.oldorigin = this.origin;
+                       break;
+               case UNSTICK_FIXED:
+                       break; // already sorted
+               case UNSTICK_STUCK:
+                       vector offset = this.oldorigin - this.origin;
+                       if(!_Movetype_TestEntityPosition(offset))
+                               _Movetype_LinkEdict(this, false);
+                       // couldn't unstick, should we warn about this?
+                       break;
+       }
 }
 
 vector _Movetype_ClipVelocity(vector vel, vector norm, float f)  // SV_ClipVelocity
index 20f9adba1076a7b3499f60b0ed9096ec41f0d6d2..62b7964d98db09a2906f7731658c99085d79d43b 100644 (file)
@@ -80,10 +80,16 @@ void set_movetype(entity this, int mt);
 .float move_suspendedinair;
 .float move_didgravity;
 
+// unsticking
+const int UNSTICK_FINE = 0;
+const int UNSTICK_FIXED = 1;
+const int UNSTICK_STUCK = 2;
+
 void _Movetype_WallFriction(entity this, vector stepnormal);
 int _Movetype_FlyMove(entity this, float dt, bool applygravity, vector stepnormal, float stepheight);
 void _Movetype_CheckVelocity(entity this);
 void _Movetype_CheckWaterTransition(entity ent);
+void _Movetype_CheckStuck(entity this);
 float _Movetype_CheckWater(entity ent);
 void _Movetype_LinkEdict_TouchAreaGrid(entity this);
 void _Movetype_LinkEdict(entity this, float touch_triggers);
@@ -98,7 +104,7 @@ void Movetype_Physics_NoMatchServer(entity this);
 void _Movetype_LinkEdict(entity this, float touch_triggers);
 void _Movetype_LinkEdict_TouchAreaGrid(entity this);
 
-float _Movetype_UnstickEntity(entity this);
+int _Movetype_UnstickEntity(entity this);
 
 const int MAX_CLIP_PLANES = 5;
 
@@ -126,6 +132,8 @@ const int MOVETYPE_ANGLENOCLIP      = 1;
 const int MOVETYPE_ANGLECLIP        = 2;
 #endif
 
+const int MOVETYPE_QCPLAYER = 150; // QC-driven player physics, no think functions!
+
 const int FL_ONSLICK = BIT(20);
 
 const int MOVETYPE_FAKEPUSH         = 13;
index 6e4c548d6cd8aecdd2ced19a27d7f31b406524bf..c0f2fac9640be94fa6c550536f029c2197180e38 100644 (file)
@@ -8,7 +8,7 @@ void _Movetype_Physics_Walk(entity this, float dt)  // SV_WalkMove
                return;
 
        if (GAMEPLAYFIX_UNSTICKPLAYERS(this))
-               _Movetype_UnstickEntity(this);
+               _Movetype_CheckStuck(this);
 
        bool applygravity = (!_Movetype_CheckWater(this) && this.move_movetype == MOVETYPE_WALK && !(this.flags & FL_WATERJUMP));
 
@@ -170,6 +170,13 @@ void _Movetype_Physics_Walk(entity this, float dt)  // SV_WalkMove
        {
                // this has been disabled so that you can't jump when you are stepping
                // up while already jumping (also known as the Quake2 double jump bug)
+               // LordHavoc: disabled this check so you can walk on monsters/players
+               //if (PRVM_serveredictfloat(ent, solid) == SOLID_BSP)
+               if(GAMEPLAYFIX_STEPDOWN(this) == 2)
+               {
+                       SET_ONGROUND(this);
+                       this.groundentity = trace_ent;
+               }
        }
        else
        {
index 572bee349f205ca81caac2d23d0ff6da1d839696..3f220e84d9cf42f559c23882b45377939b7dd03c 100644 (file)
 // client side physics
 bool Physics_Valid(string thecvar)
 {
-       return autocvar_g_physics_clientselect && thecvar != "" && thecvar && thecvar != "default" && strhasword(autocvar_g_physics_clientselect_options, thecvar);
+       return thecvar != "" && thecvar && thecvar != "default" && strhasword(autocvar_g_physics_clientselect_options, thecvar);
 }
 
 float Physics_ClientOption(entity this, string option, float defaultval)
 {
+       if(!autocvar_g_physics_clientselect)
+               return defaultval;
+
        if(IS_REAL_CLIENT(this) && Physics_Valid(CS(this).cvar_cl_physics))
        {
                string s = strcat("g_physics_", CS(this).cvar_cl_physics, "_", option);
                if(cvar_type(s) & CVAR_TYPEFLAG_EXISTS)
                        return cvar(s);
        }
-       if(autocvar_g_physics_clientselect && autocvar_g_physics_clientselect_default && autocvar_g_physics_clientselect_default != "")
+       if(autocvar_g_physics_clientselect_default && autocvar_g_physics_clientselect_default != "" && autocvar_g_physics_clientselect_default != "default")
        {
+               // NOTE: not using Physics_Valid here, so the default can be forced to something normally unavailable
                string s = strcat("g_physics_", autocvar_g_physics_clientselect_default, "_", option);
                if(cvar_type(s) & CVAR_TYPEFLAG_EXISTS)
                        return cvar(s);
index 478789dc2e784d51d708382273ac1a106f84a5da..29c028f03267500aed3f84994ff0b524e14c6c7c 100644 (file)
@@ -109,6 +109,7 @@ bool IsFlying(entity a);
 #define PHYS_INPUT_BUTTON_ZOOMSCRIPT(s)     PHYS_INPUT_BUTTON_BUTTON9(s)
 #define PHYS_INPUT_BUTTON_JETPACK(s)        PHYS_INPUT_BUTTON_BUTTON10(s)
 #define PHYS_INPUT_BUTTON_DODGE(s)                     PHYS_INPUT_BUTTON_BUTTON11(s)
+#define PHYS_INPUT_BUTTON_MINIGAME(s)          PHYS_INPUT_BUTTON_BUTTON14(s)
 
 #ifdef CSQC
 STATIC_INIT(PHYS_INPUT_BUTTON)
index 0d4d2b92ab2c7221621379a5bf0b77b2d0730146..dfee5330df713431f4afba5cc9be713504171323 100644 (file)
@@ -856,7 +856,7 @@ float Item_GiveTo(entity item, entity player)
                return 0;
 
        // crude hack to enforce switching weapons
-       if(g_cts && item.itemdef.instanceOfWeaponPickup)
+       if(g_cts && item.itemdef.instanceOfWeaponPickup && !CS(player).cvar_cl_cts_noautoswitch)
        {
                for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
                {
index 4acceed7184c924af8ffca37017fe3b8794191b4..c31a32de22222153480d38d42a73d8d5c97cefe6 100644 (file)
@@ -6,9 +6,9 @@ void W_Shotgun_Attack(Weapon thiswep, entity actor, .entity weaponentity, float
 {
        W_DecreaseAmmo(thiswep, actor, ammocount, weaponentity);
 
-       W_SetupShot(actor, weaponentity, true, 5, SND_SHOTGUN_FIRE, ((isprimary) ? CH_WEAPON_A : CH_WEAPON_SINGLE), damage * bullets, WEP_SHOTGUN.m_id);
+       W_SetupShot(actor, weaponentity, true, 5, SND_SHOTGUN_FIRE, ((isprimary) ? CH_WEAPON_A : CH_WEAPON_SINGLE), damage * bullets, thiswep.m_id);
        for(int sc = 0;sc < bullets;sc = sc + 1)
-               fireBullet(actor, weaponentity, w_shotorg, w_shotdir, spread, solidpenetration, damage, force, WEP_SHOTGUN.m_id, 0);
+               fireBullet(actor, weaponentity, w_shotorg, w_shotdir, spread, solidpenetration, damage, force, thiswep.m_id, 0);
 
 
        Send_Effect(EFFECT_SHOTGUN_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, ammocount);
index a5c7cfa8544c70219099a4a12079b7a87dd5a408..6d725259d281ffeb8297902f8c4c62712e54b62f 100644 (file)
@@ -3,26 +3,26 @@
 #include "item/container.qh"
 #include "item/borderimage.qh"
 
-       METHOD(Item, destroy, void(Item this))
+       METHOD(MenuItem, destroy, void(MenuItem this))
        {
                // free memory associated with this
        }
 
-       METHOD(Item, relinquishFocus, void(Item this))
+       METHOD(MenuItem, relinquishFocus, void(MenuItem this))
        {
                entity par = this.parent;
                if (!par) return;
                if (par.instanceOfContainer) par.setFocus(par, NULL);
        }
 
-       METHOD(Item, resizeNotify, void(Item this, vector relOrigin, vector relSize, vector absOrigin, vector absSize))
+       METHOD(MenuItem, resizeNotify, void(MenuItem this, vector relOrigin, vector relSize, vector absOrigin, vector absSize))
        {
                this.origin = absOrigin;
                this.size = absSize;
        }
 
        int autocvar_menu_showboxes;
-       METHOD(Item, draw, void(Item this))
+       METHOD(MenuItem, draw, void(MenuItem this))
        {
                if (!autocvar_menu_showboxes) return;
                vector rgb = '1 0 1';
                }
        }
 
-       METHOD(Item, showNotify, void(Item this))
+       METHOD(MenuItem, showNotify, void(MenuItem this))
        {}
 
-       METHOD(Item, hideNotify, void(Item this))
+       METHOD(MenuItem, hideNotify, void(MenuItem this))
        {}
 
-       METHOD(Item, keyDown, float(Item this, float scan, float ascii, float shift))
+       METHOD(MenuItem, keyDown, float(MenuItem this, float scan, float ascii, float shift))
        {
                return 0;  // unhandled
        }
 
-       METHOD(Item, keyUp, float(Item this, float scan, float ascii, float shift))
+       METHOD(MenuItem, keyUp, float(MenuItem this, float scan, float ascii, float shift))
        {
                return 0;  // unhandled
        }
 
-       METHOD(Item, mouseMove, float(Item this, vector pos))
+       METHOD(MenuItem, mouseMove, float(MenuItem this, vector pos))
        {
                return 0;  // unhandled
        }
 
-       METHOD(Item, mousePress, bool(Item this, vector pos))
+       METHOD(MenuItem, mousePress, bool(MenuItem this, vector pos))
        {
                return false;  // unhandled
        }
 
-       METHOD(Item, mouseDrag, float(Item this, vector pos))
+       METHOD(MenuItem, mouseDrag, float(MenuItem this, vector pos))
        {
                return 0;  // unhandled
        }
 
-       METHOD(Item, mouseRelease, float(Item this, vector pos))
+       METHOD(MenuItem, mouseRelease, float(MenuItem this, vector pos))
        {
                return 0;  // unhandled
        }
 
     void m_play_focus_sound();
 
-       METHOD(Item, focusEnter, void(Item this))
+       METHOD(MenuItem, focusEnter, void(MenuItem this))
        {
                if (this.allowFocusSound) m_play_focus_sound();
        }
 
-       METHOD(Item, focusLeave, void(Item this))
+       METHOD(MenuItem, focusLeave, void(MenuItem this))
        {}
 
-       METHOD(Item, toString, string(Item this))
+       METHOD(MenuItem, toString, string(MenuItem this))
        {
                return string_null;
        }
index 6cee17b3fdd5f9ccd24a66d078f040aaee9110a2..dd1d0679bed6c106e0ff8cad1fd4c9a1064c07e7 100644 (file)
@@ -5,28 +5,28 @@
 #include "draw.qh"
 #include "menu.qh"
 
-CLASS(Item, Object)
-       METHOD(Item, draw, void(Item));
-       METHOD(Item, keyDown, float(Item, float, float, float));
-       METHOD(Item, keyUp, float(Item, float, float, float));
-       METHOD(Item, mouseMove, float(Item, vector));
-       METHOD(Item, mousePress, bool(Item this, vector pos));
-       METHOD(Item, mouseDrag, float(Item, vector));
-       METHOD(Item, mouseRelease, float(Item, vector));
-       METHOD(Item, focusEnter, void(Item));
-       METHOD(Item, focusLeave, void(Item));
-       METHOD(Item, resizeNotify, void(Item, vector, vector, vector, vector));
-       METHOD(Item, relinquishFocus, void(Item));
-       METHOD(Item, showNotify, void(Item));
-       METHOD(Item, hideNotify, void(Item));
-       METHOD(Item, toString, string(Item));
-       METHOD(Item, destroy, void(Item));
-       ATTRIB(Item, focused, float, 0);
-       ATTRIB(Item, focusable, float, 0);
-       ATTRIB(Item, allowFocusSound, float, 0);
-       ATTRIB(Item, parent, entity);
-       ATTRIB(Item, preferredFocusPriority, float, 0);
-       ATTRIB(Item, origin, vector, '0 0 0');
-       ATTRIB(Item, size, vector, '0 0 0');
-       ATTRIB(Item, tooltip, string);
-ENDCLASS(Item)
+CLASS(MenuItem, Object)
+       METHOD(MenuItem, draw, void(MenuItem));
+       METHOD(MenuItem, keyDown, float(MenuItem, float, float, float));
+       METHOD(MenuItem, keyUp, float(MenuItem, float, float, float));
+       METHOD(MenuItem, mouseMove, float(MenuItem, vector));
+       METHOD(MenuItem, mousePress, bool(MenuItem this, vector pos));
+       METHOD(MenuItem, mouseDrag, float(MenuItem, vector));
+       METHOD(MenuItem, mouseRelease, float(MenuItem, vector));
+       METHOD(MenuItem, focusEnter, void(MenuItem));
+       METHOD(MenuItem, focusLeave, void(MenuItem));
+       METHOD(MenuItem, resizeNotify, void(MenuItem, vector, vector, vector, vector));
+       METHOD(MenuItem, relinquishFocus, void(MenuItem));
+       METHOD(MenuItem, showNotify, void(MenuItem));
+       METHOD(MenuItem, hideNotify, void(MenuItem));
+       METHOD(MenuItem, toString, string(MenuItem));
+       METHOD(MenuItem, destroy, void(MenuItem));
+       ATTRIB(MenuItem, focused, float, 0);
+       ATTRIB(MenuItem, focusable, float, 0);
+       ATTRIB(MenuItem, allowFocusSound, float, 0);
+       ATTRIB(MenuItem, parent, entity);
+       ATTRIB(MenuItem, preferredFocusPriority, float, 0);
+       ATTRIB(MenuItem, origin, vector, '0 0 0');
+       ATTRIB(MenuItem, size, vector, '0 0 0');
+       ATTRIB(MenuItem, tooltip, string);
+ENDCLASS(MenuItem)
index b73752685030a8ef57277ddaf3a3b7b7279f26f1..bc2d8e6d0bcce9e991861781e7ff3a76e0f0c760 100644 (file)
@@ -2,7 +2,7 @@
 
 #include <menu/item.qh>
 
-CLASS(Container, Item)
+CLASS(Container, MenuItem)
        METHOD(Container, draw, void(entity));
        METHOD(Container, keyUp, float(entity, float, float, float));
        METHOD(Container, keyDown, float(entity, float, float, float));
index 726f328600d79b570c210b3bb234006868ef2982..0db9c3719ac8ae9135e9662680dfc57ac6686190 100644 (file)
@@ -1,7 +1,7 @@
 #pragma once
 
 #include "../item.qh"
-CLASS(Image, Item)
+CLASS(Image, MenuItem)
        METHOD(Image, configureImage, void(entity, string));
        METHOD(Image, draw, void(entity));
        METHOD(Image, toString, string(entity));
index d02f4661f5cd84bf891af26a6c1bef694244f463..3272ed54f39ec1953ff8e61b822cced36287b414 100644 (file)
                        }
 
                // skipping SUPER(InputBox).draw(me);
-               Item_draw(me);
+               MenuItem_draw(me);
        }
 
        void InputBox_showNotify(entity me)
index f91ae8ad3cb12a13265d085fe937cf32959f2a95..2439d1d5beafbfa72c206bfe422a25c9135517e3 100644 (file)
@@ -1,7 +1,7 @@
 #pragma once
 
 #include "../item.qh"
-CLASS(Label, Item)
+CLASS(Label, MenuItem)
        METHOD(Label, configureLabel, void(entity, string, float, float));
        METHOD(Label, draw, void(entity));
        METHOD(Label, resizeNotify, void(entity, vector, vector, vector, vector));
index b3f5164a4d0937f769a55c68fb9cfbf474b07a99..f60066cd7b3d941526040fa85cbea64f6c5247de 100644 (file)
@@ -1,7 +1,7 @@
 #pragma once
 
 #include "../item.qh"
-CLASS(ListBox, Item)
+CLASS(ListBox, MenuItem)
        METHOD(ListBox, resizeNotify, void(entity, vector, vector, vector, vector));
        METHOD(ListBox, configureListBox, void(entity, float, float));
        METHOD(ListBox, draw, void(entity));
index 7bf363def7f4b42ebf413bcea99b7871a7418a39..7499f4462dab79698e1609d071becad5f80f139f 100644 (file)
@@ -1,7 +1,7 @@
 #pragma once
 
 #include "../item.qh"
-CLASS(XonoticCrosshairPreview, Item)
+CLASS(XonoticCrosshairPreview, MenuItem)
        METHOD(XonoticCrosshairPreview, configureXonoticCrosshairPreview, void(entity));
        METHOD(XonoticCrosshairPreview, draw, void(entity));
        ATTRIB(XonoticCrosshairPreview, src, string);
index c98e9fc9b6fa8f082a3bd346dad51c48edd36048..bbff7d551be6b22d04c68b0f2da9a13ba9af9958 100644 (file)
@@ -1,7 +1,7 @@
 #pragma once
 
 #include "../item.qh"
-CLASS(XonoticPicker, Item)
+CLASS(XonoticPicker, MenuItem)
        METHOD(XonoticPicker, configureXonoticPicker, void(entity));
        METHOD(XonoticPicker, mousePress, bool(XonoticPicker this, vector pos));
        METHOD(XonoticPicker, mouseRelease, float(entity, vector));
index e894e85b4fa045026bd09683b8a5dd57f0e02327..5ca5270d614dda0b5212a827c5fa5922162e8f51 100644 (file)
@@ -839,7 +839,7 @@ float Drag(entity this, float force_allow_pick, float ischeat)
                                                }
                                                // Find e and pick
                                                if(e && pick)
-                                                       if(Drag_IsDraggable(e))
+                                                       if(Drag_IsDraggable(e, this))
                                                        {
                                                                if(ischeat)
                                                                        IS_CHEAT(this, 0, 0, CHRAME_DRAG);
@@ -915,31 +915,24 @@ void Drag_Finish(entity dragger)
        }
 }
 
-float Drag_IsDraggable(entity draggee)
+bool drag_undraggable(entity draggee, entity dragger)
+{
+       // stuff probably shouldn't need this, we should figure out why they do!
+       // exceptions of course are observers and weapon entities, where things mess up
+       return false;
+}
+
+float Drag_IsDraggable(entity draggee, entity dragger)
 {
        // TODO add more checks for bad stuff here
        if(draggee == NULL)
                return false;
-       if(draggee.classname == "func_bobbing")
-               return false;
        if(draggee.classname == "door") // FIXME find out why these must be excluded, or work around the problem (trying to drag these causes like 4 fps)
-               return false;
-       if(draggee.classname == "plat")
-               return false;
-       if(draggee.classname == "func_button")
-               return false;
+               return false; // probably due to BSP collision
 //     if(draggee.model == "")
 //             return false;
-       if(IS_SPEC(draggee))
-               return false;
-       if(IS_OBSERVER(draggee))
-               return false;
-       if(draggee.classname == "exteriorweaponentity")
-               return false;
-       if(draggee.classname == "weaponentity")
-               return false;
 
-       return true;
+       return ((draggee.draggable) ? draggee.draggable(draggee, dragger) : true);
 }
 
 float Drag_MayChangeAngles(entity draggee)
@@ -1017,7 +1010,7 @@ float Drag_IsDragging(entity dragger)
                dragger.dragentity = NULL;
                return false;
        }
-       if(!Drag_CanDrag(dragger) || !Drag_IsDraggable(dragger.dragentity))
+       if(!Drag_CanDrag(dragger) || !Drag_IsDraggable(dragger.dragentity, dragger))
        {
                Drag_Finish(dragger);
                return false;
index 0dc6a92d9c45b5f103e432fabaa59f8c3db45bb1..962e017a19d6dad9e4919c86d53b20bb92efb84c 100644 (file)
@@ -14,12 +14,15 @@ float CheatFrame(entity this);
 
 const float CHRAME_DRAG = 8;
 
+bool drag_undraggable(entity draggee, entity dragger);
+
+.bool(entity this, entity dragger) draggable;
 void Drag_MoveDrag(entity from, entity to); // call this from CopyBody
 void DragBox_Think(entity this);
 float Drag(entity this, float force_allow_pick, float ischeat);
 void Drag_Begin(entity dragger, entity draggee, vector touchpoint);
 void Drag_Finish(entity dragger);
-float Drag_IsDraggable(entity draggee);
+bool Drag_IsDraggable(entity draggee, entity dragger);
 float Drag_MayChangeAngles(entity draggee);
 void Drag_MoveForward(entity dragger);
 void Drag_SetSpeed(entity dragger, float s);
index 489f2cc764a1f5bbeb82b176e96a8acc0ea0746a..3e457df14e740a9c2b24e8f3938f8bf8e2e706ed 100644 (file)
@@ -347,6 +347,7 @@ void PutObserverInServer(entity this)
        this.crouch = false;
        STAT(REVIVE_PROGRESS, this) = 0;
        this.revival_time = 0;
+       this.draggable = drag_undraggable;
 
        this.items = 0;
        STAT(WEAPONS, this) = '0 0 0';
@@ -677,6 +678,8 @@ void PutPlayerInServer(entity this)
        this.event_damage = PlayerDamage;
        this.event_heal = PlayerHeal;
 
+       this.draggable = func_null;
+
        if(!this.bot_attack)
                IL_PUSH(g_bot_targets, this);
        this.bot_attack = true;
@@ -1143,6 +1146,8 @@ void ClientConnect(entity this)
        if (IS_REAL_CLIENT(this))
                sv_notice_join(this);
 
+       this.move_qcphysics = true;
+
        // update physics stats (players can spawn before physics runs)
        Physics_UpdateStats(this);
 
@@ -1236,7 +1241,7 @@ void ChatBubbleThink(entity this)
 
        if ( !IS_DEAD(this.owner) && IS_PLAYER(this.owner) )
        {
-               if ( CS(this.owner).active_minigame )
+               if ( CS(this.owner).active_minigame && PHYS_INPUT_BUTTON_MINIGAME(this.owner) )
                        this.mdl = "models/sprites/minigame_busy.iqm";
                else if (PHYS_INPUT_BUTTON_CHAT(this.owner))
                        this.mdl = "models/misc/chatbubble.spr";
@@ -2562,7 +2567,7 @@ void DrownPlayer(entity this)
 
 void Player_Physics(entity this)
 {
-       set_movetype(this, this.move_movetype);
+       this.movetype = (this.move_qcphysics) ? MOVETYPE_QCPLAYER : this.move_movetype;
 
        if(!this.move_qcphysics)
                return;
@@ -2674,7 +2679,7 @@ void PM_UpdateButtons(entity this, entity store)
                store.impulse = this.impulse;
        this.impulse = 0;
 
-       bool typing = this.buttonchat;
+       bool typing = this.buttonchat || this.button14;
 
        store.button0 = (typing) ? 0 : this.button0;
        //button1?!
index 26388e7b37e417cab785c318673ffec45462c6a5..80965de759808a0fb8b9c0fe190532b4b4d10ef2 100644 (file)
@@ -145,6 +145,7 @@ CLASS(Client, Object)
     ATTRIB(Client, cvar_cl_accuracy_data_receive, bool, this.cvar_cl_accuracy_data_receive);
     ATTRIBARRAY(Client, cvar_cl_weaponpriorities, string, 10);
     ATTRIB(Client, cvar_cl_weaponpriority, string, this.cvar_cl_weaponpriority);
+    ATTRIB(Client, cvar_cl_cts_noautoswitch, bool, this.cvar_cl_cts_noautoswitch);
 
     METHOD(Client, m_unwind, bool(Client this));
 
index e81cf7228b937c6b2c1a108c388d4bb898d995d9..90bc1fb200a4cd3a2eaca29eae32b7a2983fe4f4 100644 (file)
@@ -168,6 +168,7 @@ float default_weapon_alpha;
 .float cvar_cl_jetpack_jump;
 .float cvar_cl_movement_track_canjump;
 .float cvar_cl_newusekeysupported;
+.float cvar_cl_cts_noautoswitch;
 
 .string cvar_g_xonoticversion;
 .string cvar_cl_weaponpriority;
index cf7266b483a9cb837b6a879ee35559128556da3d..47c0cb2fe4615af49105c651d2bc3192c9452b5f 100644 (file)
@@ -416,6 +416,8 @@ REPLICATE(cvar_cl_weaponimpulsemode, int, "cl_weaponimpulsemode");
 
 REPLICATE(cvar_g_xonoticversion, string, "g_xonoticversion");
 
+REPLICATE(cvar_cl_cts_noautoswitch, bool, "cl_cts_noautoswitch");
+
 /**
  * @param f -1: cleanup, 0: request, 1: receive
  */
index a0d622c7734c79605a6c1787e1bd6777cb6c68d5..30c7171ea3c8b33d084bd08c2eba035c2969b442 100644 (file)
@@ -468,7 +468,7 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage,
 
                        if (this != attacker) {
                                float realdmg = damage - excess;
-                               if (IS_PLAYER(attacker)) {
+                               if (IS_PLAYER(attacker) && DIFF_TEAM(attacker, this)) {
                                        GameRules_scoring_add(attacker, DMG, realdmg);
                                }
                                if (IS_PLAYER(this)) {
index 2017e65a760792fd3d8f0db24603729a139e4cc5..d9155c2237b5b8f2e8d5582c6dc88e7834e906ce 100644 (file)
@@ -178,6 +178,7 @@ void CL_SpawnWeaponentity(entity actor, .entity weaponentity)
        setthink(view, CL_Weaponentity_Think);
        view.nextthink = time;
        view.viewmodelforclient = actor;
+       view.draggable = drag_undraggable;
        setcefc(view, CL_Weaponentity_CustomizeEntityForClient);
 
        wepent_link(view);
@@ -187,6 +188,7 @@ void CL_SpawnWeaponentity(entity actor, .entity weaponentity)
                entity exterior = actor.exteriorweaponentity = new(exteriorweaponentity);
                exterior.solid = SOLID_NOT;
                exterior.owner = actor;
+               exterior.draggable = drag_undraggable;
                exterior.weaponentity_fld = weaponentity;
                setorigin(exterior, '0 0 0');
                setthink(exterior, CL_ExteriorWeaponentity_Think);
index ed81e0fb558ebb17c1645912208ab96e1f161e8b..51c66081fc539c0d324b3573f4aadeb7cbba3423 100644 (file)
@@ -650,6 +650,8 @@ seta cl_jetpack_jump 1 "Activate jetpack by pressing jump in the air. 0 = Disabl
 seta cl_race_cptimes_showself 1 "Always show your own times as well as the current best on checkpoints in Race/CTS"
 seta cl_race_cptimes_onlyself 0 "Only show your own times on checkpoints in Race/CTS"
 
+seta cl_cts_noautoswitch 0 "Prevent forced switching to new weapons in CTS"
+
 set cl_stripcolorcodes 0       "experimental feature (notes: strips ALL color codes from messages!)"
 
 // Demo camera