]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/client/view.qc
Merge branch 'master' into develop
[xonotic/xonotic-data.pk3dir.git] / qcsrc / client / view.qc
index 2b4081aba8a477e379105df27480434754d77082..7183d80c8be432be81153e230e98e58c0f110cdf 100644 (file)
@@ -1,47 +1,41 @@
 #include "view.qh"
 
-#include "autocvars.qh"
+#include <client/announcer.qh>
+#include <client/csqcmodel_hooks.qh>
 #include <client/draw.qh>
-#include "announcer.qh"
-#include "hud/_mod.qh"
-#include "main.qh"
-#include "mapvoting.qh"
-#include "shownames.qh"
-#include "hud/panel/scoreboard.qh"
-#include "hud/panel/quickmenu.qh"
-
+#include <client/hud/_mod.qh>
+#include <client/hud/panel/quickmenu.qh>
+#include <client/hud/panel/scoreboard.qh>
+#include <client/mapvoting.qh>
 #include <client/mutators/_mod.qh>
-
+#include <client/shownames.qh>
+#include <common/anim.qh>
 #include <common/animdecide.qh>
+#include <common/constants.qh>
 #include <common/deathtypes/all.qh>
+#include <common/debug.qh>
 #include <common/ent_cs.qh>
-#include <common/anim.qh>
-#include <common/constants.qh>
+#include <common/gamemodes/_mod.qh>
+#include <common/mapinfo.qh>
+#include <common/mapobjects/target/music.qh>
+#include <common/mapobjects/trigger/viewloc.qh>
+#include <common/minigames/cl_minigames.qh>
+#include <common/minigames/cl_minigames_hud.qh>
+#include <common/mutators/mutator/powerups/_mod.qh>
+#include <common/mutators/mutator/status_effects/_mod.qh>
+#include <common/mutators/mutator/waypoints/all.qh>
 #include <common/net_linked.qh>
 #include <common/net_notice.qh>
-#include <common/debug.qh>
-#include <common/mapinfo.qh>
-#include <common/gamemodes/_mod.qh>
 #include <common/physics/player.qh>
 #include <common/stats.qh>
-#include <common/mapobjects/target/music.qh>
 #include <common/teams.qh>
-#include <common/wepent.qh>
-
-#include <common/weapons/weapon/tuba.qh>
-
 #include <common/vehicles/all.qh>
-#include <common/weapons/_all.qh>
-#include <common/mutators/mutator/waypoints/all.qh>
 #include <common/viewloc.qh>
-#include <common/mapobjects/trigger/viewloc.qh>
-#include <common/minigames/cl_minigames.qh>
-#include <common/minigames/cl_minigames_hud.qh>
-
-#include <lib/csqcmodel/cl_player.qh>
+#include <common/weapons/_all.qh>
+#include <common/weapons/weapon/tuba.qh>
+#include <common/wepent.qh>
 #include <lib/csqcmodel/cl_model.qh>
-#include "csqcmodel_hooks.qh"
-
+#include <lib/csqcmodel/cl_player.qh>
 #include <lib/warpzone/client.qh>
 #include <lib/warpzone/common.qh>
 
@@ -247,8 +241,7 @@ vector bobmodel_ofs(entity view)
 
 void viewmodel_animate(entity this)
 {
-       if (autocvar_chase_active) return;
-       if (STAT(HEALTH) <= 0) return;
+       if (autocvar_chase_active || STAT(HEALTH) <= 0) return;
 
        entity view = CSQCModel_server2csqc(player_localentnum - 1);
 
@@ -390,7 +383,6 @@ void update_mousepos()
        mousepos.y = bound(0, mousepos.y, vid_conheight);
 }
 
-float showfps_prevfps;
 float showfps_prevfps_time;
 int showfps_framecounter;
 
@@ -404,13 +396,13 @@ void fpscounter_update()
        showfps_framecounter += 1;
        if(currentTime - showfps_prevfps_time > STAT(SHOWFPS))
        {
-               showfps_prevfps = showfps_framecounter/(currentTime - showfps_prevfps_time);
+               float fps = showfps_framecounter / (currentTime - showfps_prevfps_time);
                showfps_framecounter = 0;
                showfps_prevfps_time = currentTime;
 
                int channel = MSG_C2S;
                WriteHeader(channel, fpsreport);
-               WriteShort(channel, bound(0, rint(showfps_prevfps), 65535)); // prevent insane fps values
+               WriteShort(channel, bound(0, rint(fps), 32767)); // prevent insane fps values
        }
 }
 
@@ -778,7 +770,7 @@ void UpdateDamage()
 {
        // accumulate damage with each stat update
        static float damage_total_prev = 0;
-       float damage_total = STAT(DAMAGE_DEALT_TOTAL);
+       float damage_total = STAT(HITSOUND_DAMAGE_DEALT_TOTAL);
        float unaccounted_damage_new = COMPARE_INCREASING(damage_total, damage_total_prev);
        damage_total_prev = damage_total;
 
@@ -818,22 +810,22 @@ void HitSound()
        {
                if (autocvar_cl_hitsound && unaccounted_damage)
                {
-                       // customizable gradient function that crosses (0,a), (c,1) and asymptotically approaches b
-                       float a = autocvar_cl_hitsound_max_pitch;
-                       float b = autocvar_cl_hitsound_min_pitch;
-                       float c = autocvar_cl_hitsound_nom_damage;
-                       float d = unaccounted_damage;
-                       float pitch_shift = (b*d*(a-1) + a*c*(1-b)) / (d*(a-1) + c*(1-b));
-
-                       // if sound variation is disabled, set pitch_shift to 1
-                       if (autocvar_cl_hitsound == 1)
-                               pitch_shift = 1;
-
-                       // if pitch shift is reversed, mirror in (max-min)/2 + min
-                       if (autocvar_cl_hitsound == 3)
+                       float pitch_shift = 1;
+                       if (autocvar_cl_hitsound == 2 || autocvar_cl_hitsound == 3)
                        {
-                               float mirror_value = (a-b)/2 + b;
-                               pitch_shift = mirror_value + (mirror_value - pitch_shift);
+                               // customizable gradient function that crosses (0,a), (c,1) and asymptotically approaches b
+                               float a = autocvar_cl_hitsound_max_pitch;
+                               float b = autocvar_cl_hitsound_min_pitch;
+                               float c = autocvar_cl_hitsound_nom_damage;
+                               float d = unaccounted_damage;
+                               pitch_shift = (b*d*(a-1) + a*c*(1-b)) / (d*(a-1) + c*(1-b));
+
+                               // if pitch shift is reversed, mirror in (max-min)/2 + min
+                               if (autocvar_cl_hitsound == 3)
+                               {
+                                       float mirror_value = (a-b)/2 + b;
+                                       pitch_shift = mirror_value + (mirror_value - pitch_shift);
+                               }
                        }
 
                        //LOG_TRACE("dmg total (dmg): ", ftos(unaccounted_damage), " , pitch shift: ", ftos(pitch_shift));
@@ -864,75 +856,6 @@ void HitSound()
        }
 }
 
-const int MAX_SPECIALCOMMAND = 15;
-vector specialcommand_slots[MAX_SPECIALCOMMAND];
-vector specialcommand_colors[MAX_SPECIALCOMMAND];
-const float SPECIALCOMMAND_SPEED = 150;
-const float SPECIALCOMMAND_TURNSPEED = 2;
-const float SPECIALCOMMAND_SIZE = 0.025;
-const float SPECIALCOMMAND_CHANCE = 0.35;
-float sc_spawntime, sc_changetime;
-vector sc_color = '1 1 1';
-void SpecialCommand()
-{
-       if(!STAT(MOVEVARS_SPECIALCOMMAND))
-               return;
-
-       if(time >= sc_changetime)
-       {
-               sc_changetime = time + 1;
-               sc_color = randomvec() * 1.5;
-               sc_color.x = bound(0.2, sc_color.x, 0.75);
-               sc_color.y = bound(0.2, sc_color.y, 0.75);
-               sc_color.z = bound(0.2, sc_color.z, 0.75);
-       }
-       drawfill('0 0 0', vec2(vid_conwidth, vid_conheight), sc_color, autocvar_hud_colorflash_alpha * bound(0.1, sc_changetime - time, 0.3), DRAWFLAG_ADDITIVE);
-
-       if(!precache_pic("gfx/smile"))
-               return; // damn party poopers
-
-       for(int j = MAX_SPECIALCOMMAND - 1; j >= 0; --j)
-       {
-               vector slot = specialcommand_slots[j];
-               if(slot.y)
-                       slot.y += SPECIALCOMMAND_SPEED * frametime;
-               //if(slot.z)
-                       //slot.z = sin(SPECIALCOMMAND_TURNSPEED * M_PI * time);
-               if(slot.y >= vid_conheight)
-                       slot = '0 0 0';
-
-               if(slot == '0 0 0')
-               {
-                       if(random() <= SPECIALCOMMAND_CHANCE && time > sc_spawntime) // low chance to spawn!
-                       {
-                               slot.x = bound(0, (random() * vid_conwidth + 1), vid_conwidth);
-                               slot.y = 1; // start it off 0 so we can use it
-                               slot.z = floor(random() * REGISTRY_MAX(Weapons));
-                               sc_spawntime = time + bound(0.4, random(), 0.75); // prevent spawning another one for this amount of time!
-                               vector newcolor = randomvec() * 2;
-                               newcolor.x = bound(0.4, newcolor.x, 1);
-                               newcolor.y = bound(0.4, newcolor.y, 1);
-                               newcolor.z = bound(0.4, newcolor.z, 1);
-                               specialcommand_colors[j] = newcolor;
-                       }
-               }
-               else
-               {
-                       vector splash_size = '0 0 0';
-                       splash_size.x = max(vid_conwidth, vid_conheight) * SPECIALCOMMAND_SIZE;
-                       splash_size.y = max(vid_conwidth, vid_conheight) * SPECIALCOMMAND_SIZE;
-                       entity wep = REGISTRY_GET(Weapons, slot.z);
-                       if(wep == WEP_Null)
-                               drawpic(vec2(slot), "gfx/smile", vec2(splash_size), specialcommand_colors[j], 0.95, DRAWFLAG_NORMAL);
-                       else
-                               drawpic_skin(vec2(slot), wep.model2, vec2(splash_size), specialcommand_colors[j], 0.95, DRAWFLAG_NORMAL);
-                       //drawrotpic(vec2(slot), slot.z, "gfx/smile", vec2(splash_size), vec2(splash_size) / 2, specialcommand_colors[j], 0.95, DRAWFLAG_NORMAL);
-               }
-
-               specialcommand_slots[j] = slot;
-       }
-}
-
 void HUD_Draw(entity this)
 {
        // if we don't know gametype and scores yet avoid drawing the scoreboard
@@ -952,9 +875,11 @@ void HUD_Draw(entity this)
        else if(STAT(FROZEN))
        {
                vector col = '0.25 0.90 1';
-               if(STAT(REVIVE_PROGRESS))
-                       col += vec3(STAT(REVIVE_PROGRESS), -STAT(REVIVE_PROGRESS), -STAT(REVIVE_PROGRESS));
-               drawfill('0 0 0', vec2(vid_conwidth, vid_conheight), col, autocvar_hud_colorflash_alpha, DRAWFLAG_ADDITIVE);
+               float col_fade = max(0, STAT(REVIVE_PROGRESS) * 2 - 1);
+               float alpha_fade = 0.3 + 0.7 * (1 - max(0, STAT(REVIVE_PROGRESS) * 4 - 3));
+               if(col_fade)
+                       col += vec3(col_fade, -col_fade, -col_fade);
+               drawfill('0 0 0', vec2(vid_conwidth, vid_conheight), col, autocvar_hud_colorflash_alpha * alpha_fade, DRAWFLAG_ADDITIVE);
        }
 
        HUD_Scale_Enable();
@@ -962,17 +887,17 @@ void HUD_Draw(entity this)
        if(STAT(NADE_TIMER) && autocvar_cl_nade_timer) // give nade top priority, as it's a matter of life and death
        {
                vector col = '0.25 0.90 1' + vec3(STAT(NADE_TIMER), -STAT(NADE_TIMER), -STAT(NADE_TIMER));
-               DrawCircleClippedPic(vec2(0.5 * vid_conwidth, 0.6 * vid_conheight), 0.1 * vid_conheight, "gfx/crosshair_ring.tga", STAT(NADE_TIMER), col, autocvar_hud_colorflash_alpha, DRAWFLAG_ADDITIVE);
+               DrawCircleClippedPic(vec2(0.5 * vid_conwidth, 0.6 * vid_conheight), 0.1 * vid_conheight, "gfx/crosshair_ring", STAT(NADE_TIMER), col, autocvar_hud_colorflash_alpha, DRAWFLAG_ADDITIVE);
                drawstring_aspect(eY * 0.64 * vid_conheight, ((autocvar_cl_nade_timer == 2) ? _("Nade timer") : ""), vec2(vid_conwidth, 0.025 * vid_conheight), '1 1 1', 1, DRAWFLAG_NORMAL);
        }
        else if(STAT(CAPTURE_PROGRESS))
        {
-               DrawCircleClippedPic(vec2(0.5 * vid_conwidth, 0.6 * vid_conheight), 0.1 * vid_conheight, "gfx/crosshair_ring.tga", STAT(CAPTURE_PROGRESS), '0.25 0.90 1', autocvar_hud_colorflash_alpha, DRAWFLAG_ADDITIVE);
+               DrawCircleClippedPic(vec2(0.5 * vid_conwidth, 0.6 * vid_conheight), 0.1 * vid_conheight, "gfx/crosshair_ring", STAT(CAPTURE_PROGRESS), '0.25 0.90 1', autocvar_hud_colorflash_alpha, DRAWFLAG_ADDITIVE);
                drawstring_aspect(eY * 0.64 * vid_conheight, _("Capture progress"), vec2(vid_conwidth, 0.025 * vid_conheight), '1 1 1', 1, DRAWFLAG_NORMAL);
        }
        else if(STAT(REVIVE_PROGRESS))
        {
-               DrawCircleClippedPic(vec2(0.5 * vid_conwidth, 0.6 * vid_conheight), 0.1 * vid_conheight, "gfx/crosshair_ring.tga", STAT(REVIVE_PROGRESS), '0.25 0.90 1', autocvar_hud_colorflash_alpha, DRAWFLAG_ADDITIVE);
+               DrawCircleClippedPic(vec2(0.5 * vid_conwidth, 0.6 * vid_conheight), 0.1 * vid_conheight, "gfx/crosshair_ring", STAT(REVIVE_PROGRESS), '0.25 0.90 1', autocvar_hud_colorflash_alpha, DRAWFLAG_ADDITIVE);
                drawstring_aspect(eY * 0.64 * vid_conheight, _("Revival progress"), vec2(vid_conwidth, 0.025 * vid_conheight), '1 1 1', 1, DRAWFLAG_NORMAL);
        }
        HUD_Scale_Disable();
@@ -988,7 +913,6 @@ void HUD_Draw(entity this)
                }
 
        // crosshair goes VERY LAST
-       SpecialCommand();
        UpdateDamage();
        HUD_Crosshair(this);
        HitSound();
@@ -1093,7 +1017,7 @@ void View_NightVision()
        tc_10 = '1.5 0 0' - '0.2 0 0' * sin(time * 0.5) + '0 0.5 0' * cos(time * 1.7);
        //tc_11 = '1 1 0' + '0.6 0 0' * sin(time * 0.6) + '0 0.3 0' * cos(time * 0.1);
        tc_11 = tc_01 + tc_10 - tc_00;
-       R_BeginPolygon("gfx/nightvision-bg.tga", DRAWFLAG_ADDITIVE, true);
+       R_BeginPolygon("gfx/nightvision-bg", DRAWFLAG_ADDITIVE, true);
        R_PolygonVertex('0 0 0', tc_00, rgb, a);
        R_PolygonVertex(autocvar_vid_conwidth * '1 0 0', tc_10, rgb, a);
        R_PolygonVertex(autocvar_vid_conwidth * '1 0 0' + autocvar_vid_conheight * '0 1 0', tc_11, rgb, a);
@@ -1107,7 +1031,7 @@ void View_NightVision()
        tc_01 = tc_00 + '0 3 0' * (1 + Noise_White(nightvision_noise2, frametime) * 0.2);
        tc_10 = tc_00 + '2 0 0' * (1 + Noise_White(nightvision_noise2, frametime) * 0.3);
        tc_11 = tc_01 + tc_10 - tc_00;
-       R_BeginPolygon("gfx/nightvision-fg.tga", DRAWFLAG_ADDITIVE, true);
+       R_BeginPolygon("gfx/nightvision-fg", DRAWFLAG_ADDITIVE, true);
        R_PolygonVertex('0 0 0', tc_00, rgb, a);
        R_PolygonVertex(autocvar_vid_conwidth * '1 0 0', tc_10, rgb, a);
        R_PolygonVertex(autocvar_vid_conwidth * '1 0 0' + autocvar_vid_conheight * '0 1 0', tc_11, rgb, a);
@@ -1306,9 +1230,13 @@ void View_PostProcessing()
                }
 
                // edge detection postprocess handling done second (used by hud_powerup)
-               float sharpen_intensity = 0, strength_finished = STAT(STRENGTH_FINISHED), invincible_finished = STAT(INVINCIBLE_FINISHED);
-               if (strength_finished - time > 0) { sharpen_intensity += (strength_finished - time); }
-               if (invincible_finished - time > 0) { sharpen_intensity += (invincible_finished - time); }
+               float sharpen_intensity = 0;
+               FOREACH(StatusEffect, it.instanceOfPowerups,
+               {
+                       float powerup_finished = StatusEffects_gettime(it, g_statuseffects) - time;
+                       if(powerup_finished > 0)
+                               sharpen_intensity += powerup_finished;
+               });
 
                sharpen_intensity = bound(0, ((STAT(HEALTH) > 0) ? sharpen_intensity : 0), 5); // Check to see if player is alive (if not, set 0) - also bound to fade out starting at 5 seconds.
 
@@ -1612,9 +1540,7 @@ void CSQC_UpdateView(entity this, float w, float h)
        stats_get();
        hud = STAT(HUD);
 
-       ReplicateVars(false);
-       if (ReplicateVars_NOT_SENDING())
-               ReplicateVars_DELAY(0.8 + random() * 0.4); // no need to check cvars every frame
+       ReplicateVars(REPLICATEVARS_CHECK);
 
        HUD_Scale_Disable();
 
@@ -1640,6 +1566,21 @@ void CSQC_UpdateView(entity this, float w, float h)
 
        ticrate = STAT(MOVEVARS_TICRATE) * STAT(MOVEVARS_TIMESCALE);
 
+       if (autocvar_chase_active)
+       {
+               // in first person view if r_drawviewmodel is off weapon isn't visible
+               // and server doesn't throw any casing
+               // switching to 3rd person view r_drawviewmodel is set to -1 to let know the server casings
+               // can be thrown for self since own weapon model is visible
+               if (autocvar_r_drawviewmodel == 0 && STAT(HEALTH) > 0)
+                       cvar_set("r_drawviewmodel", "-1");
+       }
+       else
+       {
+               if (autocvar_r_drawviewmodel < 0)
+                       cvar_set("r_drawviewmodel", "0");
+       }
+
        WaypointSprite_Load();
 
        CSQCPlayer_SetCamera();
@@ -1650,7 +1591,6 @@ void CSQC_UpdateView(entity this, float w, float h)
                current_player = player_localnum;
        myteam = entcs_GetTeam(current_player);
 
-       // abused multiple places below
        entity local_player = ((csqcplayer) ? csqcplayer : CSQCModel_server2csqc(player_localentnum - 1));
        if(!local_player)
                local_player = this; // fall back!
@@ -1698,15 +1638,27 @@ void CSQC_UpdateView(entity this, float w, float h)
        if(intermission && !intermission_time)
                intermission_time = time;
 
+       if(STAT(GAME_STOPPED) && !game_stopped_time)
+               game_stopped_time = time;
+       else if(game_stopped_time && !STAT(GAME_STOPPED))
+               game_stopped_time = 0;
+
        if(intermission && !isdemo() && !(calledhooks & HOOK_END))
        {
                if(calledhooks & HOOK_START)
                {
+                       int gamecount = cvar("cl_matchcount");
                        localcmd("\ncl_hook_gameend\n");
+                       // NOTE: using localcmd here to ensure it's executed AFTER cl_hook_gameend
+                       // earlier versions of the game abuse the hook to set this cvar
+                       localcmd(strcat("cl_matchcount ", itos(gamecount + 1), "\n"));
+                       //cvar_set("cl_matchcount", itos(gamecount + 1));
                        calledhooks |= HOOK_END;
                }
        }
 
+       Welcome_Message_Show_Try();
+
        Announcer();
 
        View_CheckButtonStatus();
@@ -1727,7 +1679,6 @@ void CSQC_UpdateView(entity this, float w, float h)
        // Draw the World (and sky)
        setproperty(VF_DRAWWORLD, 1);
 
-       // Set the console size vars
        vid_conwidth = autocvar_vid_conwidth;
        vid_conheight = autocvar_vid_conheight;
        vid_pixelheight = autocvar_vid_pixelheight;
@@ -1736,18 +1687,8 @@ void CSQC_UpdateView(entity this, float w, float h)
 
        View_DemoCamera();
 
-       // Draw the Crosshair
-       setproperty(VF_DRAWCROSSHAIR, 0); //Make sure engine crosshairs are always hidden
-
-       // Draw the Engine Status Bar (the default Quake HUD)
-       setproperty(VF_DRAWENGINESBAR, 0);
-
-       // Update the mouse position
-       /*
-          mousepos_x = vid_conwidth;
-          mousepos_y = vid_conheight;
-          mousepos = mousepos*0.5 + getmousepos();
-        */
+       setproperty(VF_DRAWCROSSHAIR, 0); // hide engine crosshair
+       setproperty(VF_DRAWENGINESBAR, 0); // hide engine status bar
 
        IL_EACH(g_drawables, it.draw, it.draw(it));