]> git.rm.cloudns.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
HUD: Show a 2d directional indicator around the screen center when a player hits you
authorterencehill <piuntn@gmail.com>
Sat, 27 Jan 2024 23:45:07 +0000 (00:45 +0100)
committerterencehill <piuntn@gmail.com>
Sat, 27 Jan 2024 23:45:07 +0000 (00:45 +0100)
qcsrc/client/view.qc
qcsrc/client/view.qh
qcsrc/common/effects/qc/damageeffects.qc
xonotic-client.cfg

index 689f4b4cecbdd80ad0c119f2c42fce5be85977bc..a1e2c6f91e9cbc93edf121b0d57f85c0538dd6b3 100644 (file)
@@ -753,6 +753,30 @@ void View_EventChase(entity this)
        }
 }
 
+void HitIndicatorShow()
+{
+       if (!autocvar_cl_hit_indicator || autocvar_cl_hit_indicator_size <= 0
+               || time > HitIndicator_time + 1
+               || !HitIndicator_attacker || !CSQCModel_server2csqc(HitIndicator_attacker - 1))
+       {
+               return;
+       }
+
+       entity attacker = CSQCModel_server2csqc(HitIndicator_attacker - 1);
+       vector org = project_3d_to_2d(attacker.origin);
+       vector scr_center = '0.5 0 0' * vid_conwidth + '0 0.5 0' * vid_conheight;
+       float radius = autocvar_cl_hit_indicator_radius * min(vid_conwidth, vid_conheight);
+       vector ofs = normalize(org - scr_center - org.z * eZ) * radius;
+       float ang = atan2(-ofs.x, -ofs.y);
+       if (org.z < 0)
+       {
+               ang += M_PI;
+               ofs = -ofs;
+       }
+       org = scr_centersss + ofs;
+       drawspritearrow(org, ang, '1 0 0', 0.8, autocvar_cl_hit_indicator_size);
+}
+
 vector damage_blurpostprocess, content_blurpostprocess;
 
 void UpdateDamage()
@@ -907,6 +931,8 @@ void HUD_Draw(entity this)
                }
        }
 
+       HitIndicatorShow();
+
        // crosshair goes VERY LAST
        UpdateDamage();
        HUD_Crosshair(this);
index cd33ebfb6a1201e41f9caa706209c1cc2fcb3d92..76bedbdabc0f28be78cee9da61a5baf9669617ec 100644 (file)
@@ -94,6 +94,12 @@ int autocvar_cl_nade_timer;
 bool autocvar_r_drawviewmodel;
 vector autocvar_cl_gunoffset;
 
+bool autocvar_cl_hit_indicator = 1;
+float autocvar_cl_hit_indicator_radius = 0.15;
+float autocvar_cl_hit_indicator_size = 1.1;
+int HitIndicator_attacker;
+int HitIndicator_time;
+
 void calc_followmodel_ofs(entity view);
 
 vector project_3d_to_2d(vector vec);
index dbc138f41f3e7e0e1eb16de7c4ab1e4a52c7d5eb..d77af71f35ba8690c7fc214db921472a02eba8b6 100644 (file)
@@ -9,6 +9,7 @@ bool Damage_DamageInfo_SendEntity(entity this, entity to, int sf)
        vector org = vec3(floor(this.origin.x), floor(this.origin.y), floor(this.origin.z));
        WriteHeader(MSG_ENTITY, ENT_CLIENT_DAMAGEINFO);
        WriteShort(MSG_ENTITY, this.projectiledeathtype);
+       WriteByte(MSG_ENTITY, etof(this.owner)); // attacker
        WriteVector(MSG_ENTITY, org);
        WriteByte(MSG_ENTITY, bound(1, this.dmg, 255));
        WriteByte(MSG_ENTITY, bound(0, this.dmg_radius, 255));
@@ -35,6 +36,7 @@ void Damage_DamageInfo(vector org, float coredamage, float edgedamage, float rad
        // origin is just data to be sent
        //setorigin(e, org);
        e.origin = org;
+       e.owner = dmgowner;
        e.projectiledeathtype = deathtype;
        e.dmg = coredamage;
        e.dmg_edge = edgedamage;
@@ -191,7 +193,7 @@ void DamageEffect(entity this, vector hitorg, float thedamage, int type, int spe
 NET_HANDLE(ENT_CLIENT_DAMAGEINFO, bool isNew)
 {
        float thedamage, rad, edge, thisdmg;
-       bool hitplayer = false;
+       bool hitplayer = false, hitme = false;
        int species, forcemul;
        vector force, thisforce;
 
@@ -199,6 +201,8 @@ NET_HANDLE(ENT_CLIENT_DAMAGEINFO, bool isNew)
        w_issilent = (w_deathtype & 0x8000);
        w_deathtype = (w_deathtype & 0x7FFF);
 
+       int attacker = ReadByte();
+
        w_org = ReadVector();
 
        thedamage = ReadByte();
@@ -263,7 +267,9 @@ NET_HANDLE(ENT_CLIENT_DAMAGEINFO, bool isNew)
 
                DamageEffect(it, w_org, thisdmg, w_deathtype, species);
 
-               if(it != csqcplayer && (it.isplayermodel & ISPLAYER_MODEL))
+               if(it == csqcplayer)
+                       hitme = true; // this impact damaged me
+               else if(it != csqcplayer && (it.isplayermodel & ISPLAYER_MODEL))
                        hitplayer = true; // this impact damaged another player
        });
 
@@ -400,29 +406,37 @@ NET_HANDLE(ENT_CLIENT_DAMAGEINFO, bool isNew)
 
        MUTATOR_CALLHOOK(DamageInfo, this, w_deathtype, w_org);
 
-       // TODO spawn particle effects and sounds based on w_deathtype
        if(!DEATH_ISSPECIAL(w_deathtype))
-       if(!hitplayer || rad) // don't show ground impacts for hitscan weapons if a player was hit
        {
-               Weapon hitwep = DEATH_WEAPONOF(w_deathtype);
-               w_random = prandom();
-
-               vector force_dir = normalize(force);
-               // this traceline usually starts in solid when a hitscan shot hits a surface with a very small angle
-               // if so, try another traceline starting further back (may still start in solid but only with extremely small angles)
-               traceline(w_org - force_dir * 16, w_org + force_dir * 16, MOVE_NOMONSTERS, NULL);
-               if(trace_startsolid)
-                       traceline(w_org - force_dir * 40, w_org + force_dir * 16, MOVE_NOMONSTERS, NULL);
-               if(trace_fraction < 1)
-                       w_backoff = trace_plane_normal;
-               else
-                       w_backoff = -force_dir;
-               setorigin(this, w_org + w_backoff * 2); // for sound() calls
+               if(hitme)
+               {
+                       HitIndicator_attacker = attacker;
+                       HitIndicator_time = time;
+               }
 
-               if(!(trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY))
+               // TODO spawn particle effects and sounds based on w_deathtype
+               if(!hitplayer || rad) // don't show ground impacts for hitscan weapons if a player was hit
                {
-                       if(!MUTATOR_CALLHOOK(Weapon_ImpactEffect, hitwep, this))
-                               hitwep.wr_impacteffect(hitwep, this);
+                       Weapon hitwep = DEATH_WEAPONOF(w_deathtype);
+                       w_random = prandom();
+
+                       vector force_dir = normalize(force);
+                       // this traceline usually starts in solid when a hitscan shot hits a surface with a very small angle
+                       // if so, try another traceline starting further back (may still start in solid but only with extremely small angles)
+                       traceline(w_org - force_dir * 16, w_org + force_dir * 16, MOVE_NOMONSTERS, NULL);
+                       if(trace_startsolid)
+                               traceline(w_org - force_dir * 40, w_org + force_dir * 16, MOVE_NOMONSTERS, NULL);
+                       if(trace_fraction < 1)
+                               w_backoff = trace_plane_normal;
+                       else
+                               w_backoff = -force_dir;
+                       setorigin(this, w_org + w_backoff * 2); // for sound() calls
+
+                       if(!(trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY))
+                       {
+                               if(!MUTATOR_CALLHOOK(Weapon_ImpactEffect, hitwep, this))
+                                       hitwep.wr_impacteffect(hitwep, this);
+                       }
                }
        }
 }
index d1b449f475d8ac5608a069854660ec72626e739e..16f752b1f150db202dc73b87bfee143227dc4024 100644 (file)
@@ -201,6 +201,10 @@ seta cl_autotaunt 0 "automatically taunt enemies when fragging them"
 seta cl_voice_directional 1    "0 = all voices are non-directional, 1 = all voices are directional, 2 = only taunts are directional"
 seta cl_voice_directional_taunt_attenuation 0.5 "this defines the distance from which taunts can be heard"
 
+seta cl_hit_indicator 1 "show a 2d directional indicator around the screen center when a player hits you"
+seta cl_hit_indicator_radius 0.15 "show the directional indicator at this percentage of the screen from the center"
+seta cl_hit_indicator_size 1.1 "directional indicator size"
+
 seta cl_hitsound 1 "play a hit notifier sound when you have hit an enemy, 1: same pitch 2: decrease pitch with more damage 3: increase pitch with more damage"
 set cl_hitsound_antispam_time 0.05 "don't play the hitsound more often than this"
 seta cl_hitsound_min_pitch 0.75 "minimum pitch of hit sound"