]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/client/view.qc
Viewmodel: mimic player model effects
[xonotic/xonotic-data.pk3dir.git] / qcsrc / client / view.qc
index fad769d0161d39b67e82a6edfe063ea2a807c580..95167a1c4c752c4189d6a6e5568f02b6d0c2d5fa 100644 (file)
 
 #include "mutators/events.qh"
 
+#include "../common/anim.qh"
 #include "../common/constants.qh"
 #include "../common/mapinfo.qh"
+#include "../common/gamemodes/all.qh"
 #include "../common/nades/all.qh"
 #include "../common/stats.qh"
 #include "../common/triggers/target/music.qh"
 #include "../lib/warpzone/client.qh"
 #include "../lib/warpzone/common.qh"
 
+#define EFMASK_CHEAP (EF_ADDITIVE | EF_DOUBLESIDED | EF_FULLBRIGHT | EF_NODEPTHTEST | EF_NODRAW | EF_NOSHADOW | EF_SELECTABLE | EF_TELEPORT_BIT)
+
+void viewmodel_draw(entity this)
+{
+       int mask = (intermission || (getstati(STAT_HEALTH) <= 0) || autocvar_chase_active) ? 0 : MASK_NORMAL;
+       int c = stof(getplayerkeyvalue(current_player, "colors"));
+       vector g = colormapPaletteColor(c & 0x0F, true) * 2;
+       entity me = CSQCModel_server2csqc(player_localentnum);
+       int fx = ((me.csqcmodel_effects & EFMASK_CHEAP)
+               | EF_NODEPTHTEST)
+               &~ (EF_FULLBRIGHT); // can mask team color, so get rid of it
+       for (entity e = this; e; e = e.weaponchild)
+       {
+               e.drawmask = mask;
+               e.colormap = c;
+               e.glowmod = g;
+               e.csqcmodel_effects = fx;
+               WITH(entity, self, e, CSQCModel_Effects_Apply());
+       }
+}
+
+entity viewmodel;
+STATIC_INIT(viewmodel) {
+    viewmodel = new(viewmodel);
+       viewmodel.draw = viewmodel_draw;
+}
+
 entity porto;
 vector polyline[16];
 void Porto_Draw(entity this)
@@ -397,8 +426,6 @@ float TrueAimCheck()
        return SHOTTYPE_HITWORLD;
 }
 
-void CSQC_common_hud(void);
-
 void PostInit(void);
 void CSQC_Demo_Camera();
 float HUD_WouldDrawScoreboard();
@@ -460,6 +487,15 @@ bool WantEventchase()
        return false;
 }
 
+void HUD_Crosshair_Vehicle()
+{
+       if(hud != HUD_BUMBLEBEE_GUN)
+       {
+               Vehicle info = get_vehicleinfo(hud);
+               info.vr_crosshair(info);
+       }
+}
+
 vector damage_blurpostprocess, content_blurpostprocess;
 
 float unaccounted_damage = 0;
@@ -487,7 +523,7 @@ void UpdateDamage()
        spectatee_status_prev = spectatee_status;
 }
 
-void UpdateHitsound()
+void HitSound()
 {
        // varying sound pitch
 
@@ -536,41 +572,26 @@ void UpdateHitsound()
        }
 }
 
-void UpdateCrosshair()
+void HUD_Crosshair()
 {SELFPARAM();
        static float rainbow_last_flicker;
-    static vector rainbow_prev_color;
+       static vector rainbow_prev_color;
        entity e = self;
        float f, i, j;
        vector v;
-       if(getstati(STAT_FROZEN))
-               drawfill('0 0 0', eX * vid_conwidth + eY * vid_conheight, ((getstatf(STAT_REVIVE_PROGRESS)) ? ('0.25 0.90 1' + ('1 0 0' * getstatf(STAT_REVIVE_PROGRESS)) + ('0 1 1' * getstatf(STAT_REVIVE_PROGRESS) * -1)) : '0.25 0.90 1'), autocvar_hud_colorflash_alpha, DRAWFLAG_ADDITIVE);
-       else if (getstatf(STAT_HEALING_ORB)>time)
-               drawfill('0 0 0', eX * vid_conwidth + eY * vid_conheight, NADE_TYPE_HEAL.m_color, autocvar_hud_colorflash_alpha*getstatf(STAT_HEALING_ORB_ALPHA), DRAWFLAG_ADDITIVE);
-       if(!intermission)
-       if(getstatf(STAT_NADE_TIMER) && autocvar_cl_nade_timer) // give nade top priority, as it's a matter of life and death
-       {
-               DrawCircleClippedPic(eX * 0.5 * vid_conwidth + eY * 0.6 * vid_conheight, 0.1 * vid_conheight, "gfx/crosshair_ring.tga", getstatf(STAT_NADE_TIMER), '0.25 0.90 1' + ('1 0 0' * getstatf(STAT_NADE_TIMER)) - ('0 1 1' * getstatf(STAT_NADE_TIMER)), autocvar_hud_colorflash_alpha, DRAWFLAG_ADDITIVE);
-               drawstring_aspect(eY * 0.64 * vid_conheight, ((autocvar_cl_nade_timer == 2) ? _("Nade timer") : ""), eX * vid_conwidth + eY * 0.025 * vid_conheight, '1 1 1', 1, DRAWFLAG_NORMAL);
-       }
-       else if(getstatf(STAT_REVIVE_PROGRESS))
-       {
-               DrawCircleClippedPic(eX * 0.5 * vid_conwidth + eY * 0.6 * vid_conheight, 0.1 * vid_conheight, "gfx/crosshair_ring.tga", getstatf(STAT_REVIVE_PROGRESS), '0.25 0.90 1', autocvar_hud_colorflash_alpha, DRAWFLAG_ADDITIVE);
-               drawstring_aspect(eY * 0.64 * vid_conheight, _("Revival progress"), eX * vid_conwidth + eY * 0.025 * vid_conheight, '1 1 1', 1, DRAWFLAG_NORMAL);
-       }
-
-       if(autocvar_r_letterbox == 0)
-               if(autocvar_viewsize < 120)
-                       CSQC_common_hud();
-
-       // crosshair goes VERY LAST
        if(!scoreboard_active && !camera_active && intermission != 2 &&
-               spectatee_status != -1 && hud == HUD_NORMAL && !csqcplayer.viewloc &&
+               spectatee_status != -1 && !csqcplayer.viewloc &&
                !HUD_MinigameMenu_IsOpened() )
        {
                if (!autocvar_crosshair_enabled) // main toggle for crosshair rendering
                        return;
 
+               if (hud != HUD_NORMAL)
+               {
+                       HUD_Crosshair_Vehicle();
+                       return;
+               }
+
                string wcross_style;
                float wcross_alpha, wcross_resolution;
                wcross_style = autocvar_crosshair;
@@ -1010,6 +1031,40 @@ void UpdateCrosshair()
        }
 }
 
+void HUD_Draw()
+{
+       if(getstati(STAT_FROZEN))
+               drawfill('0 0 0', eX * vid_conwidth + eY * vid_conheight, ((getstatf(STAT_REVIVE_PROGRESS)) ? ('0.25 0.90 1' + ('1 0 0' * getstatf(STAT_REVIVE_PROGRESS)) + ('0 1 1' * getstatf(STAT_REVIVE_PROGRESS) * -1)) : '0.25 0.90 1'), autocvar_hud_colorflash_alpha, DRAWFLAG_ADDITIVE);
+       else if (getstatf(STAT_HEALING_ORB)>time)
+               drawfill('0 0 0', eX * vid_conwidth + eY * vid_conheight, NADE_TYPE_HEAL.m_color, autocvar_hud_colorflash_alpha*getstatf(STAT_HEALING_ORB_ALPHA), DRAWFLAG_ADDITIVE);
+       if(!intermission)
+       if(getstatf(STAT_NADE_TIMER) && autocvar_cl_nade_timer) // give nade top priority, as it's a matter of life and death
+       {
+               DrawCircleClippedPic(eX * 0.5 * vid_conwidth + eY * 0.6 * vid_conheight, 0.1 * vid_conheight, "gfx/crosshair_ring.tga", getstatf(STAT_NADE_TIMER), '0.25 0.90 1' + ('1 0 0' * getstatf(STAT_NADE_TIMER)) - ('0 1 1' * getstatf(STAT_NADE_TIMER)), autocvar_hud_colorflash_alpha, DRAWFLAG_ADDITIVE);
+               drawstring_aspect(eY * 0.64 * vid_conheight, ((autocvar_cl_nade_timer == 2) ? _("Nade timer") : ""), eX * vid_conwidth + eY * 0.025 * vid_conheight, '1 1 1', 1, DRAWFLAG_NORMAL);
+       }
+       else if(getstatf(STAT_REVIVE_PROGRESS))
+       {
+               DrawCircleClippedPic(eX * 0.5 * vid_conwidth + eY * 0.6 * vid_conheight, 0.1 * vid_conheight, "gfx/crosshair_ring.tga", getstatf(STAT_REVIVE_PROGRESS), '0.25 0.90 1', autocvar_hud_colorflash_alpha, DRAWFLAG_ADDITIVE);
+               drawstring_aspect(eY * 0.64 * vid_conheight, _("Revival progress"), eX * vid_conwidth + eY * 0.025 * vid_conheight, '1 1 1', 1, DRAWFLAG_NORMAL);
+       }
+
+       if(autocvar_r_letterbox == 0)
+               if(autocvar_viewsize < 120)
+               {
+                       if(!(gametype == MAPINFO_TYPE_RACE || gametype == MAPINFO_TYPE_CTS))
+                               Accuracy_LoadLevels();
+
+                       HUD_Main();
+                       HUD_DrawScoreboard();
+               }
+
+       // crosshair goes VERY LAST
+       UpdateDamage();
+       HUD_Crosshair();
+       HitSound();
+}
+
 bool ov_enabled;
 float oldr_nearclip;
 float oldr_farclip_base;
@@ -1207,6 +1262,18 @@ void CSQC_UpdateView(float w, float h)
 
        WarpZone_FixView();
        //WarpZone_FixPMove();
+       {
+               static string name_last;
+               string name = get_weaponinfo(switchingweapon).mdl;
+               if (name != name_last)
+               {
+                   name_last = name;
+                       CL_WeaponEntity_SetModel(viewmodel, name);
+                       updateanim(viewmodel);
+                       if (!viewmodel.animstate_override)
+                               setanim(viewmodel, viewmodel.anim_idle, true, false, false);
+               }
+       }
 
        vector ov_org = '0 0 0';
        vector ov_mid = '0 0 0';
@@ -1714,16 +1781,15 @@ void CSQC_UpdateView(float w, float h)
                        if(autocvar_cl_gentle_damage == 2)
                        {
                                if(myhealth_flash < pain_threshold) // only randomize when the flash is gone
-                               {
                                        myhealth_gentlergb = eX * random() + eY * random() + eZ * random();
-                               }
                        }
                        else
                                myhealth_gentlergb = stov(autocvar_hud_damage_gentle_color);
 
-                       drawfill('0 0 0', eX * vid_conwidth + eY * vid_conheight, myhealth_gentlergb, autocvar_hud_damage_gentle_alpha_multiplier * bound(0, myhealth_flash_temp, 1) * autocvar_hud_damage, DRAWFLAG_NORMAL);
+                       if(myhealth_flash_temp > 0)
+                               drawfill('0 0 0', eX * vid_conwidth + eY * vid_conheight, myhealth_gentlergb, autocvar_hud_damage_gentle_alpha_multiplier * bound(0, myhealth_flash_temp, 1) * autocvar_hud_damage, DRAWFLAG_NORMAL);
                }
-               else
+               else if(myhealth_flash_temp > 0)
                        drawpic(splash_pos, "gfx/blood", splash_size, stov(autocvar_hud_damage_color), bound(0, myhealth_flash_temp, 1) * autocvar_hud_damage, DRAWFLAG_NORMAL);
 
                if(autocvar_hud_postprocessing) // we still need to set this anyway even when chase_active is set, this way it doesn't get stuck on.
@@ -1813,9 +1879,7 @@ void CSQC_UpdateView(float w, float h)
 
        scoreboard_active = HUD_WouldDrawScoreboard();
 
-       UpdateDamage();
-       UpdateCrosshair();
-       UpdateHitsound();
+       HUD_Draw();
 
        if(NextFrameCommand)
        {
@@ -1859,14 +1923,6 @@ void CSQC_UpdateView(float w, float h)
        else
                HUD_Radar_Mouse();
 
-    if(hud && !intermission)
-    if(hud == HUD_BUMBLEBEE_GUN)
-       CSQC_BUMBLE_GUN_HUD();
-    else {
-       Vehicle info = get_vehicleinfo(hud);
-               info.vr_hud(info);
-       }
-
        cl_notice_run();
 
        // let's reset the view back to normal for the end
@@ -1875,20 +1931,6 @@ void CSQC_UpdateView(float w, float h)
 }
 
 
-void CSQC_common_hud(void)
-{
-       if(!(gametype == MAPINFO_TYPE_RACE || gametype == MAPINFO_TYPE_CTS))
-               Accuracy_LoadLevels();
-
-       HUD_Main(); // always run these functions for alpha checks
-       HUD_DrawScoreboard();
-
-       // scoreboard/accuracy, map/gametype voting screen
-       if (scoreboard_active || intermission == 2)
-               HUD_Reset();
-}
-
-
 // following vectors must be global to allow seamless switching between camera modes
 vector camera_offset, current_camera_offset, mouse_angles, current_angles, current_origin, current_position;
 void CSQC_Demo_Camera()