1919// memdbgon must be the last include file in a .cpp file!!!
2020#include " tier0/memdbgon.h"
2121
22- #define UNICODE_NEO_COMPASS_SIZE_BYTES (UNICODE_NEO_COMPASS_STR_LENGTH * sizeof (wchar_t ))
23-
2422using vgui::surface;
2523
26- ConVar cl_neo_hud_debug_compass_enabled (" cl_neo_hud_debug_compass_enabled" , " 0" , FCVAR_USERINFO | FCVAR_CHEAT,
27- " Whether the Debug HUD compass is enabled or not." , true , 0 .0f , true , 1 .0f );
28- ConVar cl_neo_hud_debug_compass_pos_x (" cl_neo_hud_debug_compass_pos_x" , " 0.45" , FCVAR_USERINFO | FCVAR_CHEAT,
29- " Horizontal position of the Debug compass, in range 0 to 1." , true , 0 .0f , true , 1 .0f );
30- ConVar cl_neo_hud_debug_compass_pos_y (" cl_neo_hud_debug_compass_pos_y" , " 0.925" , FCVAR_USERINFO | FCVAR_CHEAT,
31- " Vertical position of the Debug compass, in range 0 to 1." , true , 0 .0f , true , 1 .0f );
32- ConVar cl_neo_hud_debug_compass_color_r (" cl_neo_hud_debug_compass_color_r" , " 190" , FCVAR_USERINFO | FCVAR_CHEAT,
33- " Red color value of the Debug compass, in range 0 - 255." , true , 0 .0f , true , 255 .0f );
34- ConVar cl_neo_hud_debug_compass_color_g (" cl_neo_hud_debug_compass_color_g" , " 185" , FCVAR_USERINFO | FCVAR_CHEAT,
35- " Green color value of the Debug compass, in range 0 - 255." , true , 0 .0f , true , 255 .0f );
36- ConVar cl_neo_hud_debug_compass_color_b (" cl_neo_hud_debug_compass_color_b" , " 205" , FCVAR_USERINFO | FCVAR_CHEAT,
37- " Blue value of the Debug compass, in range 0 - 255." , true , 0 .0f , true , 255 .0f );
38- ConVar cl_neo_hud_debug_compass_color_a (" cl_neo_hud_debug_compass_color_a" , " 255" , FCVAR_USERINFO | FCVAR_CHEAT,
39- " Alpha color value of the Debug compass, in range 0 - 255." , true , 0 .0f , true , 255 .0f );
40-
4124ConVar cl_neo_hud_rangefinder_enabled (" cl_neo_hud_rangefinder_enabled" , " 1" , FCVAR_ARCHIVE,
4225 " Whether the rangefinder HUD is enabled or not." , true , 0 .0f , true , 1 .0f );
4326ConVar cl_neo_hud_rangefinder_pos_frac_x (" cl_neo_hud_rangefinder_pos_frac_x" , " 0.55" , FCVAR_ARCHIVE,
@@ -72,10 +55,6 @@ CNEOHud_Compass::CNEOHud_Compass(const char *pElementName, vgui::Panel *parent)
7255 m_hFont = 0 ;
7356
7457 SetVisible (true );
75-
76- COMPILE_TIME_ASSERT (sizeof (m_wszCompassUnicode) == UNICODE_NEO_COMPASS_SIZE_BYTES);
77- Assert (g_pVGuiLocalize);
78- g_pVGuiLocalize->ConvertANSIToUnicode (" \0 " , m_wszCompassUnicode, UNICODE_NEO_COMPASS_SIZE_BYTES);
7958}
8059
8160void CNEOHud_Compass::Paint ()
@@ -88,44 +67,6 @@ void CNEOHud_Compass::Paint()
8867 BaseClass::Paint ();
8968}
9069
91- void CNEOHud_Compass::GetCompassUnicodeString (const float angle, wchar_t * outUnicodeStr) const
92- {
93- // Char representation of the compass strip
94- static constexpr char ROSE[] =
95- " N | NE |\
96- E | SE |\
97- S | SW |\
98- W | NW |\
99- " ;
100-
101- // One compass tick represents this many degrees of rotation
102- const float unitAccuracy = 360 .0f / sizeof (ROSE);
103-
104- // Get index offset for this angle's compass position
105- int offset = RoundFloatToInt (angle / unitAccuracy) - UNICODE_NEO_COMPASS_VIS_AROUND;
106- if (offset < 0 )
107- {
108- offset += sizeof (ROSE);
109- }
110-
111- // Both sides + center + terminator
112- char compass[UNICODE_NEO_COMPASS_STR_LENGTH];
113- int i;
114- for (i = 0 ; i < UNICODE_NEO_COMPASS_STR_LENGTH - 1 ; i++)
115- {
116- // Get our index by circling around the compass strip.
117- // We do modulo -1, because sizeof would land us on NULL
118- // and terminate the string early.
119- const int wrappedIndex = (offset + i) % (sizeof (ROSE) - 1 );
120-
121- compass[i] = ROSE[wrappedIndex];
122- }
123- // Finally, make sure we have a null terminator
124- compass[i] = ' \0 ' ;
125-
126- g_pVGuiLocalize->ConvertANSIToUnicode (compass, outUnicodeStr, UNICODE_NEO_COMPASS_SIZE_BYTES);
127- }
128-
12970static C_NEO_Player *GetFirstPersonPlayer ()
13071{
13172 auto pLocalPlayer = C_NEO_Player::GetLocalNEOPlayer ();
@@ -141,29 +82,30 @@ static C_NEO_Player *GetFirstPersonPlayer()
14182 return pFPPlayer;
14283}
14384
85+ static float safeAngle (float angle) {
86+ while (angle < -180 ) {
87+ angle += 360 ;
88+ }
89+ while (angle >= 180 ) {
90+ angle -= 360 ;
91+ }
92+ return angle;
93+ }
94+
14495void CNEOHud_Compass::UpdateStateForNeoHudElementDraw ()
14596{
14697 auto pLocalPlayer = C_NEO_Player::GetLocalNEOPlayer ();
14798 Assert (pLocalPlayer);
14899
149- static auto safeAngle = [](const float angle) -> float {
150- if (angle > 180 .0f )
151- {
152- return angle - 360 .0f ;
153- }
154- else if (angle < -180 .0f )
155- {
156- return angle + 360 .0f ;
157- }
158- return angle;
159- };
160-
161- // Direction in -180 to 180
162- float angle = pLocalPlayer->EyeAngles ()[YAW] * -1 ;
163- angle = safeAngle (angle);
164- angle += 180 .0f ; // NEO NOTE (nullsystem): Adjust it again to match OG:NT's compass angle
165- angle = safeAngle (angle);
166- GetCompassUnicodeString (angle, m_wszCompassUnicode);
100+ // Point the objective arrow to the ghost, if it exists
101+ if (NEORules ()->GhostExists () || NEORules ()->JuggernautItemExists ())
102+ {
103+ const Vector objPos = NEORules ()->GetGameType () == NEO_GAME_TYPE_JGR ? NEORules ()->GetJuggernautMarkerPos () : NEORules ()->GetGhostPos ();
104+ const Vector objVec = objPos - pLocalPlayer->EyePosition ();
105+ const float objYaw = RAD2DEG (atan2f (objVec.y , objVec.x ));
106+ float objAngle = safeAngle (- objYaw + pLocalPlayer->EyeAngles ()[YAW]);
107+ m_objAngle = Clamp (objAngle, -(float )m_fov / 2 , (float )m_fov / 2 );
108+ }
167109
168110 if (cl_neo_hud_rangefinder_enabled.GetBool ())
169111 {
@@ -201,11 +143,6 @@ void CNEOHud_Compass::DrawNeoHudElement(void)
201143 DrawCompass ();
202144 }
203145
204- if (cl_neo_hud_debug_compass_enabled.GetBool ())
205- {
206- DrawDebugCompass ();
207- }
208-
209146 if (cl_neo_hud_rangefinder_enabled.GetBool () && GetFirstPersonPlayer ()->IsInAim ())
210147 {
211148 surface ()->DrawSetTextColor (COLOR_NEO_WHITE);
@@ -223,174 +160,77 @@ void CNEOHud_Compass::ApplySchemeSettings(vgui::IScheme *pScheme)
223160 LoadControlSettings (" scripts/HudLayout.res" );
224161
225162 m_hFont = pScheme->GetFont (" NHudOCRSmall" );
226- m_savedXBoxWidth = 0 ;
227163
228164 surface ()->GetScreenSize (m_resX, m_resY);
229165 SetBounds (0 , 0 , m_resX, m_resY);
230166 SetZPos (90 );
167+ m_fov = Clamp (m_fov, 45 , 360 );
168+ m_fadeExp = Clamp (m_fadeExp, 0 , 10 );
231169}
232170
233171void CNEOHud_Compass::DrawCompass () const
234172{
173+ static const wchar_t * ROSE[] = {
174+ L" S" , L" |" , L" SW" , L" |" , L" W" , L" |" , L" NW" , L" |" , L" N" , L" |" , L" NE" , L" |" , L" E" , L" |" , L" SE" , L" |" ,
175+ };
176+
235177 auto player = C_NEO_Player::GetLocalNEOPlayer ();
236178 Assert (player);
237179
238180 surface ()->DrawSetTextFont (m_hFont);
239181
240- int fontWidth, fontHeight;
241- surface ()->GetTextSize (m_hFont, m_wszCompassUnicode, fontWidth, fontHeight);
242-
243- if (m_savedXBoxWidth == 0 )
244- {
245- // Using the fontHeight for padding works out
246- m_savedXBoxWidth = fontWidth + fontHeight;
247- }
248- // These are the compass box dimension, just based on the font's dimensions
249- const int xBoxWidth = m_savedXBoxWidth;
250- const int yBoxHeight = fontHeight;
251-
252- const int resXHalf = m_resX / 2 ;
253- const int xBoxWidthHalf = xBoxWidth / 2 ;
254- const int margin = m_yFromBottomPos;
255-
256182 DrawNeoHudRoundedBox (
257- resXHalf - xBoxWidthHalf, m_resY - yBoxHeight - margin ,
258- resXHalf + xBoxWidthHalf, m_resY - margin ,
183+ m_xPos, m_yPos ,
184+ m_xPos + m_width, m_yPos + m_height ,
259185 m_boxColor);
260186
261- // Draw the compass "needle"
262- if (m_needleVisible)
263- {
264- static const Color COMPASS_NEEDLE_COLOR_GREEN{25 , 255 , 25 , 150 };
265- static const Color COMPASS_NEEDLE_COLOR_BLUE{25 , 25 , 255 , 150 };
266- static const Color COMPASS_NEEDLE_COLOR_WHITE{255 , 255 , 255 , 150 };
267- Color needleColor = COMPASS_NEEDLE_COLOR_WHITE;
268- if (m_needleColored)
269- {
270- const int playerTeam = player->GetTeamNumber ();
271- switch (playerTeam)
272- {
273- break ; case TEAM_JINRAI: needleColor = COMPASS_NEEDLE_COLOR_GREEN;
274- break ; case TEAM_NSF: needleColor = COMPASS_NEEDLE_COLOR_BLUE;
275- break ; default : break ;
276- }
187+ const float angle = -player->EyeAngles ()[YAW];
188+ const int steps = ARRAYSIZE (ROSE);
189+ for (int i = 0 ; i < steps; i += m_separators ? 1 : 2 ) {
190+ const float stepAngle = (float )(i * 360 ) / steps;
191+ float drawAngle = safeAngle (stepAngle - angle + (float )m_fov / 2 );
192+ if (drawAngle < 0 ) {
193+ drawAngle += 360 ;
194+ }
195+ if (drawAngle >= m_fov) {
196+ continue ;
277197 }
278- surface ()->DrawSetColor (needleColor);
279- surface ()->DrawFilledRect (resXHalf - 1 , m_resY - yBoxHeight - margin, resXHalf + 1 , m_resY - margin);
198+ const float proportion = drawAngle / m_fov;
199+ const float alpha = !m_fadeExp ? 1 : 1 - pow (abs (2 * (proportion - 0.5 )), m_fadeExp);
200+ surface ()->DrawSetTextColor (m_textColor.r (), m_textColor.g (), m_textColor.b (), alpha * m_textColor.a ());
201+ int labelWidth, labelHeight;
202+ surface ()->GetTextSize (m_hFont, ROSE[i], labelWidth, labelHeight);
203+ const float padding = (float )labelHeight;
204+ surface ()->DrawSetTextPos (m_xPos + padding + (m_width - padding * 2 ) * proportion - (float )labelWidth / 2 , m_yPos + (float )m_height / 2 - (float )labelHeight / 2 );
205+ surface ()->DrawPrintText (ROSE[i], Q_UnicodeLength (ROSE[i]));
280206 }
281207
282- surface ()->DrawSetTextColor (COLOR_WHITE);
283- surface ()->DrawSetTextPos (resXHalf - fontWidth / 2 , m_resY - fontHeight - margin);
284- surface ()->DrawPrintText (m_wszCompassUnicode, UNICODE_NEO_COMPASS_STR_LENGTH);
285-
286208 // Print compass objective arrow
287- if (m_objectiveVisible && !player->IsCarryingGhost ())
209+ if (m_objectiveVisible && !player->IsObjective ())
288210 {
289211 // Point the objective arrow to the ghost, if it exists
290212 if (NEORules ()->GhostExists () || NEORules ()->JuggernautItemExists ())
291213 {
292- int ghostMarkerX, ghostMarkerY;
293- bool ghostIsInView = false ;
294- if (NEORules ()->GetGameType () != NEO_GAME_TYPE_JGR)
295- {
296- ghostIsInView = GetVectorInScreenSpace (NEORules ()->GetGhostPos (), ghostMarkerX, ghostMarkerY);
297- }
298- else
299- {
300- ghostIsInView = GetVectorInScreenSpace (NEORules ()->GetJuggernautMarkerPos (), ghostMarkerX, ghostMarkerY);
301- }
302- if (ghostIsInView) {
303- // Print a unicode arrow to signify compass needle
304- const wchar_t arrowUnicode[] = L" ▼" ;
305-
306- ghostMarkerX = clamp (ghostMarkerX, resXHalf - xBoxWidthHalf, resXHalf + xBoxWidthHalf);
307-
308- const int ghosterTeam = NEORules ()->GetGhosterTeam ();
309- const int ownTeam = player->GetTeam ()->GetTeamNumber ();
310-
311- const auto teamClr32 = player->GetTeam ()->GetRenderColor ();
312- const Color teamColor = Color (teamClr32.r , teamClr32.g , teamClr32.b , teamClr32.a );
313-
314- const bool ghostIsBeingCarried = (ghosterTeam == TEAM_JINRAI || ghosterTeam == TEAM_NSF);
315- const bool ghostIsCarriedByEnemyTeam = (ghosterTeam != ownTeam);
316-
317- surface ()->DrawSetTextColor (ghostIsBeingCarried ? ghostIsCarriedByEnemyTeam ? COLOR_RED : teamColor : COLOR_WHITE);
318- surface ()->DrawSetTextPos (ghostMarkerX, m_resY - fontHeight - margin * 2 .25f );
319- surface ()->DrawPrintText (arrowUnicode, Q_UnicodeLength (arrowUnicode));
320- }
214+ const float proportion = m_objAngle / m_fov + 0.5 ;
215+
216+ // Print a unicode arrow to signify objective
217+ const wchar_t arrowUnicode[] = L" ▼" ;
218+
219+ const int ghosterTeam = NEORules ()->GetGhosterTeam ();
220+ const int ownTeam = player->GetTeam ()->GetTeamNumber ();
221+
222+ const auto teamClr32 = player->GetTeam ()->GetRenderColor ();
223+ const Color teamColor = Color (teamClr32.r , teamClr32.g , teamClr32.b , teamClr32.a );
224+
225+ const bool ghostIsBeingCarried = (ghosterTeam == TEAM_JINRAI || ghosterTeam == TEAM_NSF);
226+ const bool ghostIsCarriedByEnemyTeam = (ghosterTeam != ownTeam);
227+
228+ surface ()->DrawSetTextColor (ghostIsBeingCarried ? ghostIsCarriedByEnemyTeam ? COLOR_RED : teamColor : COLOR_WHITE);
229+ int labelWidth, labelHeight;
230+ surface ()->GetTextSize (m_hFont, arrowUnicode, labelWidth, labelHeight);
231+ const float padding = (float )labelHeight;
232+ surface ()->DrawSetTextPos (m_xPos + padding + (m_width - padding * 2 ) * proportion - (float )labelWidth / 2 , m_yPos - labelHeight);
233+ surface ()->DrawPrintText (arrowUnicode, Q_UnicodeLength (arrowUnicode));
321234 }
322235 }
323-
324- static const Color FADE_END_COLOR (116 , 116 , 116 , 255 );
325- DrawNeoHudRoundedBoxFaded (
326- resXHalf - xBoxWidthHalf, m_resY - yBoxHeight - margin,
327- resXHalf, m_resY - margin,
328- FADE_END_COLOR, 255 , 0 , true ,
329- true , false , true , false );
330- DrawNeoHudRoundedBoxFaded (
331- resXHalf, m_resY - yBoxHeight - margin,
332- resXHalf + xBoxWidthHalf, m_resY - margin,
333- FADE_END_COLOR, 0 , 255 , true ,
334- false , true , false , true );
335- }
336-
337- void CNEOHud_Compass::DrawDebugCompass () const
338- {
339- auto player = C_NEO_Player::GetLocalNEOPlayer ();
340- Assert (player);
341-
342- // Direction in -180 to 180
343- float angle = -(player->EyeAngles ()[YAW]);
344-
345- // Clamp in 180 turn range.
346- if (angle > 180 )
347- {
348- angle -= 360 ;
349- }
350- else if (angle < -180 )
351- {
352- angle += 360 ;
353- }
354-
355- // Char representation of the compass strip
356- const char rose[] = " N -- ne -- E -- se -- S -- sw -- W -- nw -- " ;
357-
358- // One compass tick represents this many degrees of rotation
359- const float unitAccuracy = 360 .0f / sizeof (rose);
360-
361- // How many characters should be visible around each side of the needle position
362- const int numCharsVisibleAroundNeedle = 6 ;
363-
364- // Get index offset for this angle's compass position
365- int offset = RoundFloatToInt ((angle / unitAccuracy)) - numCharsVisibleAroundNeedle;
366- if (offset < 0 )
367- {
368- offset += sizeof (rose);
369- }
370-
371- // Both sides + center + terminator
372- char compass[numCharsVisibleAroundNeedle * 2 + 2 ];
373- int i;
374- for (i = 0 ; i < sizeof (compass) - 1 ; i++)
375- {
376- // Get our index by circling around the compass strip.
377- // We do modulo -1, because sizeof would land us on NULL
378- // and terminate the string early.
379- const int wrappedIndex = (offset + i) % (sizeof (rose) - 1 );
380-
381- compass[i] = rose[wrappedIndex];
382- }
383- // Finally, make sure we have a null terminator
384- compass[i] = ' \0 ' ;
385-
386- // Draw the compass for this frame
387- debugoverlay->AddScreenTextOverlay (
388- cl_neo_hud_debug_compass_pos_x.GetFloat (),
389- cl_neo_hud_debug_compass_pos_y.GetFloat (),
390- gpGlobals->frametime ,
391- cl_neo_hud_debug_compass_color_r.GetInt (),
392- cl_neo_hud_debug_compass_color_g.GetInt (),
393- cl_neo_hud_debug_compass_color_b.GetInt (),
394- cl_neo_hud_debug_compass_color_a.GetInt (),
395- compass);
396236}
0 commit comments