From aca92a63f3a09d0cdd1e174206aed945894da402 Mon Sep 17 00:00:00 2001 From: Juhu <5894800-Juhu_@users.noreply.gitlab.com> Date: Thu, 25 May 2023 19:35:23 +0200 Subject: [PATCH] various minimap improvements for battle royale and draw ring zone on minimap --- gfx/inverted_circle.tga | Bin 0 -> 7916 bytes qcsrc/client/csqcmodel_hooks.qc | 4 +- qcsrc/client/hud/panel/radar.qc | 19 +- qcsrc/common/gamemodes/gamemode/br/cl_ring.qc | 185 ++++++++++++++++++ qcsrc/common/gamemodes/gamemode/br/cl_ring.qh | 2 + .../common/gamemodes/gamemode/br/cl_squad.qc | 4 +- .../common/gamemodes/gamemode/br/cl_squad.qh | 2 +- .../mutator/waypoints/waypointsprites.qc | 3 + 8 files changed, 211 insertions(+), 8 deletions(-) create mode 100644 gfx/inverted_circle.tga diff --git a/gfx/inverted_circle.tga b/gfx/inverted_circle.tga new file mode 100644 index 0000000000000000000000000000000000000000..a634bbe30a034f3c49dd962d8fad033670071667 GIT binary patch literal 7916 zcmeHM`HNLY7XI$*ww?J8)L-mhY=4j${XrW=QBWc_$S69a6C@~#NJuauLNNIy#%SAV z_df3XzH5vc_qgx4FL8_7sA%IxCyI$W)_kX`-kV!>r@=4;24>!aOMSQQt9PsFobR0T z6_P&!Gf)cso1NxF1aWUvirZe*J9%C^B~Bwf21nI%cLu8IscB5Bgy$O1{a^X)hC&N?JLcxM^! z^iX858c79zwT8c{P-L(Y=xJn=@XEHqG9T>>=a(vHdqMsHL_25 zW!qprz#$I_uWTF4LDH|kkzXckc7fP(=n4kPPFm zxEKA0DKZ$(`E%qa9GUYU&pYFQRz~WDSGEnt0v{TAA-u9}Fb4R@$gjdH+Xnd9$UlTv zyak3EF@oW5@do%r+hYZvyumAAgrZ8ph*$W9|2a}2cXMRLFL()*DV!uIdx;moC`H`a zQ7`Zu;D#Bg5p;i!pMchiW(ivVgnFP<(Huc(J)QxdDq0};^ckK4qZKU@jDCv8z-Nk< z2|jy_N5JQbRtP?SggRiDqBVkHb+mhQRJ2ae@gW`n%@l1AG<$&ir&W`qIPam~;D1m}K@eh8YVkyC=+S8)Xxr0A?*&=p(;sua<> zsxIRaP_5{qp!yOn`Z>_jiZ9Z4F;V+|5KO#)^M2*8aplkB98jWtHv}c;aMthikKF6C zIOFGVn{zlrkH-{!vQ{wVG)@826x|n0JB5=#TSX59ZBOC^P@||$P;-LJ;QAi1?>LV6 z-#y{)juGi|&*T`6`q7_p^rJZ9|C!cWegud8Tm8(pI!s=1Z%oTAIfR3LHZM7wgE-)4 zN-Lgt0Q>zayyhzGC;zw=qD@!t!}osmXw_BUW3OLXr6vs8ORVpuR=$@k<@UhZeD6Kj z?RUt?IPTGI?DG3(y*pp-jw)=TnA1U9C@4O8e znL;c2PPx!pnDv@5+pyK!pY@x;TZ!FRGh{2acuO@hgSNT_-}>2GuPXkQ%;~J$`c-bT zGO2x!d9oSbcz-Z5j~?+2HhFKcUe|FGIoA1-^}Askm2>THm&itJ@Lp$R3H@#Z)_b3H zUb&vwJ-b5IlbN0OS|1&~4r{${8(Br~UQ6trT_bC;rm)UyxXx?H;f^D$54T>eoNnJ? zgRI6XZw1z)yRTBNALV+<_oG%S-`i(5%Sx>9tYrPYYz3AB6|R>aU$I=VB{9nYBbPHW zIF7R%Fk+cT3Om+zS%#&a4UKFkA1)x}CshF>rK|sI6 z1LtF2VIRpo!{#Yw*w8O=|9O}T40V`nG<2?F1{(bm51Gpt=lIXa2{Pau#lD|-$Q;Zr z_z@Xv&}_wieB%DIH9od?<1t3IpQYHpAMrrNuJ^3W!b}@06_f8im`UvV&dW?6R~3`} z2F%ddYTxpr%z)S!te9N*z7V^<%R)K=`sES&)hPDwN2ctr*!BJ(HJEOry<+lax9P;L z@0v`L1%6|kYyB07 z+vJ}_8^sR2kcQjL>5B4Cp=hk;c+C0q%V^n3u|qGV;r5q6i~Lh)@g<1M3b@STmId5W zu|vN~!)@l4Hp8;{Wp0e-n$7dSLUW5t3%FFVL$BrC+DYD2S!*;wl3xU(BBG}G!IGv# zHt{pUzGhk{+0|iA@Y~x-;kQYCb{r>{|8usBTqbGr=wdV~Jm1J=F!p{48W-;Smc##x z*YsKhYm{C)o1ObL_113J+FO|2gY@3~2YVb^OKeI0&%Kp-va}ZXTkV(r5ZQmmKLY=G z7oVfwMt+*{!cu zSzZr$KOGaY@xoP+HhwUkG!%ET@hOa74aK=Q9ySy=v+*^Izv0Bb4XXJBFmxrWtlsJD$=Qi2AC(Mh|Ia8cZHI#S7`B^%5i}Sj4&X>&x!+bHF zOU8L-ItO*Sk6NS4Pt&<;oY$sv-fTXcw@sHX$N6-eZ^!v~oUh0Ee4Ovc^*~%N#Pvj6 zZ^ZRTx>kwnm~@R3*FWjnD6X60x+-0B#r0UaR*UPnxXvRE>cAC+yk|4@s}(^F8P}I_ z{h6*!+HA=PuJ*i{T|o%as8jx24dYH))iviA+1TodPS^f z#Ck`phorTV9g&W*GtyahMLNvxLQEZJb(%ee`f4oet383n6YD>rIut5L`vXHu{``I|9@Is&>UJMk*OM&_rDw9{dCcrA5s^!%{(Y)sOi0T2=&g+2^dLvLtZw3nL zEk6e;B2-sz2g>W6K$Wcx6x+LjntRXBfw~Ws-ur9|r1iU7##K3RLIEfg=4h zP^+H>N_M@U`y9@_K2pG+`<1U@rTsio&R+(qdaSv>3KaP_fm;98@3rdqCZ+FZwSVS$ z)SQ^p`LhA$UcuQx_H-e80+BtX$ev_mPdl?VU(g8 zK?Tg8+b|LZ=Q@li!MRWNWQcqpoE>FPm$D~N*;A_QNf!B#b?~&pSy%QnEPG-WpQ&X} y-Hu1+a`Cxc_GB-6`uFe72pc+4Wa(@_f9> #include #include +#include +#include +#include // Radar (#6) @@ -204,7 +207,7 @@ void HUD_Radar() else { if (autocvar_hud_panel_radar == 0) return; - if (autocvar_hud_panel_radar != 2 && !teamplay) return; + if (autocvar_hud_panel_radar != 2 && (!teamplay && !ISGAMETYPE(BR))) return; if(radar_panel_modified) { panel.update_time = time; // forces reload of panel attributes @@ -310,6 +313,9 @@ void HUD_Radar() drawsetcliparea(pos.x, pos.y, mySize.x, mySize.y); + if(ISGAMETYPE(BR)) + draw_teamradar_ring(pos, mySize, panel_fg_alpha); + draw_teamradar_background(hud_panel_radar_foreground_alpha); IL_EACH(g_radarlinks, true, draw_teamradar_link(it.origin, it.velocity, it.team)); @@ -337,8 +343,15 @@ void HUD_Radar() AL_EACH(_entcs, e, it != NULL, { if (!it.m_entcs_private) continue; if (it.sv_entnum == current_player) continue; - color2 = entcs_GetTeam(it.sv_entnum); - draw_teamradar_player(it.origin, it.angles, Team_ColorRGB(color2)); + if(!(ISGAMETYPE(BR) && br_isSameSquad(it.sv_entnum + 1))) + { + color2 = entcs_GetTeam(it.sv_entnum); + draw_teamradar_player(it.origin, it.angles, Team_ColorRGB(color2)); + } + else + { + draw_teamradar_player(it.origin, it.angles, '0.0625 1 0.0625'); // 0x0FFF0F + } }); draw_teamradar_player(entcs_receiver(current_player).origin, view_angles, '1 1 1'); diff --git a/qcsrc/common/gamemodes/gamemode/br/cl_ring.qc b/qcsrc/common/gamemodes/gamemode/br/cl_ring.qc index 5f830769b..9ebc6de2f 100644 --- a/qcsrc/common/gamemodes/gamemode/br/cl_ring.qc +++ b/qcsrc/common/gamemodes/gamemode/br/cl_ring.qc @@ -2,6 +2,7 @@ // TODO: support dark colors +entity br_ring; bool ring_is_closing(entity this); #define RING_MODEL_PATH "models/sphere/sphere.md3" @@ -65,6 +66,10 @@ void ring_construct(entity this, bool isnew) if(isnew) { + if(br_ring) + LOG_FATAL("server sent ring entity twice"); + + br_ring = this; IL_PUSH(g_drawables, this); IL_PUSH(g_drawables_2d, this); } @@ -135,3 +140,183 @@ bool ring_is_closing(entity this) return (time_elapsed < (this.br_ring_duration + this.br_ring_stage_waittime * this.br_ring_stage_count)); } + +void draw_circle_fill_inverted(vector clip_pos, vector clip_size, vector center, float r, vector c, float a); +void draw_teamradar_ring(vector clip_pos, vector clip_size, float fg) +{ + if(fg <= 0) + return; + + if(!br_ring) + return; + + float a = max(fg / 3, 0.01); + float radius = ring_calculate_current_radius(br_ring); + float radius_at_height = 0; + float height_offset = view_origin.z - br_ring.origin.z; + + if(fabs(height_offset) < radius) + radius_at_height = sqrt(radius ** 2 - height_offset ** 2); + + draw_circle_fill_inverted(clip_pos, clip_size, br_ring.origin, radius, br_ring.colormod, a); + draw_circle_fill_inverted(clip_pos, clip_size, br_ring.origin, radius_at_height, br_ring.colormod, a); +} + +void draw_circle_fill_inverted(vector clip_pos, vector clip_size, vector center, float r, vector c, float a) +{ + float diameter = r * 2; + + // all four clipping corners in texture coordinates + vector _clip_pos0 = teamradar_2dcoord_to_texcoord(clip_pos + eY * clip_size.y); + vector _clip_pos1 = teamradar_2dcoord_to_texcoord(clip_pos + clip_size); + vector _clip_pos2 = teamradar_2dcoord_to_texcoord(clip_pos + eX * clip_size.x); + vector _clip_pos3 = teamradar_2dcoord_to_texcoord(clip_pos); + + // find the minimum and maximum extents in texture coordinates + vector _clip_mins, _clip_maxs; + _clip_mins.x = _clip_mins.y = min(_clip_pos0.x, _clip_pos0.y, _clip_pos1.x, _clip_pos1.y, _clip_pos2.x, _clip_pos2.y, _clip_pos3.x, _clip_pos3.y); + _clip_maxs.x = _clip_maxs.y = max(_clip_pos0.x, _clip_pos0.y, _clip_pos1.x, _clip_pos1.y, _clip_pos2.x, _clip_pos2.y, _clip_pos3.x, _clip_pos3.y); + _clip_mins.z = _clip_maxs.z = 0; + + // each of the corners of the clipping rectangle in texture coordinates + vector _clip_rect_coord0 = eX * _clip_mins.x + eY * _clip_maxs.y; + vector _clip_rect_coord1 = _clip_maxs; + vector _clip_rect_coord2 = eX * _clip_maxs.x + eY * _clip_mins.y; + vector _clip_rect_coord3 = _clip_mins; + + if(diameter > 0) + { + // convert diameter to texture coordinates + vector _circle_size; + _circle_size.x = diameter / (mi_picmax.x - mi_picmin.x); + _circle_size.y = diameter / (mi_picmax.y - mi_picmin.y); + _circle_size.z = 0; + + // convert center to origin in texture coordinates + vector _circle_origin = teamradar_3dcoord_to_texcoord(center) - _circle_size / 2; + + // each of the corners of the circle square in texture coordinates + vector _circle_coord0 = _circle_origin + eY * _circle_size.y; + vector _circle_coord1 = _circle_origin + _circle_size; + vector _circle_coord2 = _circle_origin + eX * _circle_size.x; + vector _circle_coord3 = _circle_origin; + + // clip the circle square + _circle_coord0.x = bound(_clip_mins.x, _circle_coord0.x, _clip_maxs.x); + _circle_coord0.y = bound(_clip_mins.y, _circle_coord0.y, _clip_maxs.y); + _circle_coord1.x = bound(_clip_mins.x, _circle_coord1.x, _clip_maxs.x); + _circle_coord1.y = bound(_clip_mins.y, _circle_coord1.y, _clip_maxs.y); + _circle_coord2.x = bound(_clip_mins.x, _circle_coord2.x, _clip_maxs.x); + _circle_coord2.y = bound(_clip_mins.y, _circle_coord2.y, _clip_maxs.y); + _circle_coord3.x = bound(_clip_mins.x, _circle_coord3.x, _clip_maxs.x); + _circle_coord3.y = bound(_clip_mins.y, _circle_coord3.y, _clip_maxs.y); + + // top fill rectangle corners in 2D screen coordinates + vector rect0_coord0 = teamradar_texcoord_to_2dcoord(_clip_rect_coord0); + vector rect0_coord1 = teamradar_texcoord_to_2dcoord(_clip_rect_coord1); + vector rect0_coord2 = teamradar_texcoord_to_2dcoord(eX * _clip_rect_coord1.x + eY * _circle_coord1.y); + vector rect0_coord3 = teamradar_texcoord_to_2dcoord(eX * _clip_rect_coord0.x + eY * _circle_coord0.y); + + // bottom fill rectangle corners in 2D screen coordinates + vector rect2_coord0 = teamradar_texcoord_to_2dcoord(_clip_rect_coord2); + vector rect2_coord1 = teamradar_texcoord_to_2dcoord(_clip_rect_coord3); + vector rect2_coord2 = teamradar_texcoord_to_2dcoord(eX * _clip_rect_coord3.x + eY * _circle_coord3.y); + vector rect2_coord3 = teamradar_texcoord_to_2dcoord(eX * _clip_rect_coord2.x + eY * _circle_coord2.y); + + // right fill rectangle corners in 2D screen coordinates + vector rect1_coord0 = rect0_coord2; + vector rect1_coord1 = rect2_coord3; + vector rect1_coord2 = teamradar_texcoord_to_2dcoord(_circle_coord2); + vector rect1_coord3 = teamradar_texcoord_to_2dcoord(_circle_coord1); + + // left fill rectangle corners in 2D screen coordinates + vector rect3_coord0 = rect2_coord2; + vector rect3_coord1 = rect0_coord3; + vector rect3_coord2 = teamradar_texcoord_to_2dcoord(_circle_coord0); + vector rect3_coord3 = teamradar_texcoord_to_2dcoord(_circle_coord3); + + // draw top fill rectangle + if((_circle_origin.y + _circle_size.y) < _clip_maxs.y) + { + R_BeginPolygon("", DRAWFLAG_NORMAL, true); + R_PolygonVertex(rect0_coord0, '0 0 0', c, a); + R_PolygonVertex(rect0_coord1, '1 0 0', c, a); + R_PolygonVertex(rect0_coord2, '1 1 0', c, a); + R_PolygonVertex(rect0_coord3, '0 1 0', c, a); + R_EndPolygon(); + } + + // draw right fill rectangle + if((_circle_origin.x + _circle_size.x) < _clip_maxs.x) + { + R_BeginPolygon("", DRAWFLAG_NORMAL, true); + R_PolygonVertex(rect1_coord0, '0 0 0', c, a); + R_PolygonVertex(rect1_coord1, '1 0 0', c, a); + R_PolygonVertex(rect1_coord2, '1 1 0', c, a); + R_PolygonVertex(rect1_coord3, '0 1 0', c, a); + R_EndPolygon(); + } + + // draw bottom fill rectangle + if(_circle_origin.y > _clip_mins.y) + { + R_BeginPolygon("", DRAWFLAG_NORMAL, true); + R_PolygonVertex(rect2_coord0, '0 0 0', c, a); + R_PolygonVertex(rect2_coord1, '1 0 0', c, a); + R_PolygonVertex(rect2_coord2, '1 1 0', c, a); + R_PolygonVertex(rect2_coord3, '0 1 0', c, a); + R_EndPolygon(); + } + + // draw left fill rectangle + if(_circle_origin.x > _clip_mins.x) + { + R_BeginPolygon("", DRAWFLAG_NORMAL, true); + R_PolygonVertex(rect3_coord0, '0 0 0', c, a); + R_PolygonVertex(rect3_coord1, '1 0 0', c, a); + R_PolygonVertex(rect3_coord2, '1 1 0', c, a); + R_PolygonVertex(rect3_coord3, '0 1 0', c, a); + R_EndPolygon(); + } + + // draw circle square + if((_circle_origin.x < _clip_maxs.x) && (_circle_origin.y < _clip_maxs.y) && ((_circle_origin.x + _circle_size.x) > _clip_mins.x) && ((_circle_origin.y + _circle_size.y) > _clip_mins.y)) + { + // circle square corners in 2D screen coordinates + vector circle_coord0 = teamradar_texcoord_to_2dcoord(_circle_coord0); + vector circle_coord1 = teamradar_texcoord_to_2dcoord(_circle_coord1); + vector circle_coord2 = teamradar_texcoord_to_2dcoord(_circle_coord2); + vector circle_coord3 = teamradar_texcoord_to_2dcoord(_circle_coord3); + + // calculate texture coordinates in case of clipping + vector circle_tex0, circle_tex1, circle_tex2, circle_tex3; + circle_tex0.x = circle_tex3.x = max(0, (_clip_mins.x - _circle_origin.x) / _circle_size.x); + circle_tex1.x = circle_tex2.x = min(1 - ((_circle_origin.x + _circle_size.x) - _clip_maxs.x) / _circle_size.x, 1); + circle_tex2.y = circle_tex3.y = 1 - max(0, (_clip_mins.y - _circle_origin.y) / _circle_size.y); + circle_tex0.y = circle_tex1.y = 1 - min(1 - ((_circle_origin.y + _circle_size.y) - _clip_maxs.y) / _circle_size.y, 1); + circle_tex0.z = circle_tex1.z = circle_tex2.z = circle_tex3.z = 0; + + R_BeginPolygon("gfx/inverted_circle", DRAWFLAG_NORMAL, true); + R_PolygonVertex(circle_coord0, circle_tex0, c, a); + R_PolygonVertex(circle_coord1, circle_tex1, c, a); + R_PolygonVertex(circle_coord2, circle_tex2, c, a); + R_PolygonVertex(circle_coord3, circle_tex3, c, a); + R_EndPolygon(); + } + } + else + { + // circle with zero length diameter, draw a single fill rectangle + vector fill_coord0 = teamradar_texcoord_to_2dcoord(_clip_rect_coord0); + vector fill_coord1 = teamradar_texcoord_to_2dcoord(_clip_rect_coord1); + vector fill_coord2 = teamradar_texcoord_to_2dcoord(_clip_rect_coord2); + vector fill_coord3 = teamradar_texcoord_to_2dcoord(_clip_rect_coord3); + + R_BeginPolygon("", DRAWFLAG_NORMAL, true); + R_PolygonVertex(fill_coord0, '0 0 0', c, a); + R_PolygonVertex(fill_coord1, '1 0 0', c, a); + R_PolygonVertex(fill_coord2, '1 1 0', c, a); + R_PolygonVertex(fill_coord3, '0 1 0', c, a); + R_EndPolygon(); + } +} diff --git a/qcsrc/common/gamemodes/gamemode/br/cl_ring.qh b/qcsrc/common/gamemodes/gamemode/br/cl_ring.qh index 6f70f09be..4d0bb218a 100644 --- a/qcsrc/common/gamemodes/gamemode/br/cl_ring.qh +++ b/qcsrc/common/gamemodes/gamemode/br/cl_ring.qh @@ -1 +1,3 @@ #pragma once + +void draw_teamradar_ring(vector clip_pos, vector clip_size, float fg); diff --git a/qcsrc/common/gamemodes/gamemode/br/cl_squad.qc b/qcsrc/common/gamemodes/gamemode/br/cl_squad.qc index 9c167bc77..24e30722d 100644 --- a/qcsrc/common/gamemodes/gamemode/br/cl_squad.qc +++ b/qcsrc/common/gamemodes/gamemode/br/cl_squad.qc @@ -22,13 +22,13 @@ NET_HANDLE(TE_CSQC_BR_SQUAD, bool isNew) return true; } -bool br_isSameSquad(entity this) +bool br_isSameSquad(int entnum) { for(int i = 0; i < csqcsquad_cnt; ++i) { int member = csqcsquad[i]; - if(this.entnum == member) + if(entnum == member) return true; } diff --git a/qcsrc/common/gamemodes/gamemode/br/cl_squad.qh b/qcsrc/common/gamemodes/gamemode/br/cl_squad.qh index 4440abb01..c5800dcab 100644 --- a/qcsrc/common/gamemodes/gamemode/br/cl_squad.qh +++ b/qcsrc/common/gamemodes/gamemode/br/cl_squad.qh @@ -1,4 +1,4 @@ #pragma once -bool br_isSameSquad(entity this); +bool br_isSameSquad(int entnum); bool br_inSquad(); diff --git a/qcsrc/common/mutators/mutator/waypoints/waypointsprites.qc b/qcsrc/common/mutators/mutator/waypoints/waypointsprites.qc index 97c26f360..831204819 100644 --- a/qcsrc/common/mutators/mutator/waypoints/waypointsprites.qc +++ b/qcsrc/common/mutators/mutator/waypoints/waypointsprites.qc @@ -161,6 +161,9 @@ void Ent_WaypointSprite(entity this, bool isnew) if (sendflags & 2) { strcpy(this.netname, ReadString()); + + if (this.netname == WP_BRAlly.netname && IL_CONTAINS(g_radaricons, this)) + IL_REMOVE(g_radaricons, this); } if (sendflags & 4) -- 2.39.2