diff --git a/game/neo/cfg/callout.cfg b/game/neo/cfg/callout.cfg new file mode 100644 index 0000000000..7fb0173ee8 --- /dev/null +++ b/game/neo/cfg/callout.cfg @@ -0,0 +1,5 @@ +alias +enablePlacePainting nav_toggle_place_painting +alias -enablePlacePainting nav_toggle_place_painting + +bind mouse1 +enablePlacePainting +bind mouse2 nav_place_pick diff --git a/game/neo/scripts/HudLayout.res b/game/neo/scripts/HudLayout.res index 363158d816..b5b2842d54 100644 --- a/game/neo/scripts/HudLayout.res +++ b/game/neo/scripts/HudLayout.res @@ -1026,4 +1026,15 @@ "SmallWeaponsFont" "NHudSpectatorOverlaySmallWeapons" "DeadTexture" "vgui/hud/kill_kill" } + + neo_place_name + { + "fieldName" "neo_place_name" + + "textXpos" "-4" + "textYpos" "4" + "textFont" "NHudOCRSmallNoAdditive" + "textColor" "255 255 255 255" + "textXAlignment" "2" + } } diff --git a/game/neo/scripts/kb_act.lst b/game/neo/scripts/kb_act.lst index 966a3d43e2..ce5ca00eed 100644 --- a/game/neo/scripts/kb_act.lst +++ b/game/neo/scripts/kb_act.lst @@ -48,6 +48,7 @@ "messagemode" "#Valve_Chat_Message" "messagemode2" "#Valve_Team_Message" "+attack3" "Ping Location" +"+showplacenames" "Show Nearby Place Names" "joinstar 0" "Join Alpha Star" "joinstar 1" "Join Bravo Star" "joinstar 2" "Join Charlie Star" diff --git a/src/game/client/CMakeLists.txt b/src/game/client/CMakeLists.txt index 317cbb87a5..2f5a7c40a9 100644 --- a/src/game/client/CMakeLists.txt +++ b/src/game/client/CMakeLists.txt @@ -1571,6 +1571,7 @@ target_sources_grouped( set(UNITY_SOURCE_NEO_SRC_CLIENT neo/c_neo_message.cpp neo/c_neo_npc_dummy.cpp + neo/c_neo_point_world_text.cpp neo/c_neo_player.cpp neo/c_neo_te_tocflash.cpp neo/neo_fixup_glshaders.cpp @@ -1589,6 +1590,7 @@ target_sources_grouped( FILES neo/c_neo_message.h neo/c_neo_npc_dummy.h + neo/c_neo_point_world_text.h neo/c_neo_player.h neo/c_neo_te_tocflash.h neo/neo_fixup_glshaders.h @@ -1665,6 +1667,7 @@ set(UNITY_SOURCE_NEO_UI neo/ui/neo_hud_health_thermoptic_aux.cpp neo/ui/neo_hud_hint.cpp neo/ui/neo_hud_message.cpp + neo/ui/neo_hud_place_name.cpp neo/ui/neo_hud_player_ping.cpp neo/ui/neo_hud_round_state.cpp neo/ui/neo_hud_spectator_overlay.cpp @@ -1707,6 +1710,7 @@ target_sources_grouped( neo/ui/neo_hud_health_thermoptic_aux.h neo/ui/neo_hud_hint.h neo/ui/neo_hud_message.h + neo/ui/neo_hud_place_name.h neo/ui/neo_hud_player_ping.h neo/ui/neo_hud_round_state.h neo/ui/neo_hud_spectator_overlay.h @@ -1748,6 +1752,7 @@ target_sources_grouped( NAME "Source Files\\Shared" FILES ${CMAKE_SOURCE_DIR}/game/shared/neo/achievements_neo.h + ${CMAKE_SOURCE_DIR}/game/shared/neo/nav_shared.h ${CMAKE_SOURCE_DIR}/game/shared/neo/neo_gamerules.h ${CMAKE_SOURCE_DIR}/game/shared/neo/neo_ghost_cap_point.h ${CMAKE_SOURCE_DIR}/game/shared/neo/neo_juggernaut.h diff --git a/src/game/client/neo/c_neo_point_world_text.cpp b/src/game/client/neo/c_neo_point_world_text.cpp new file mode 100644 index 0000000000..4cf124e292 --- /dev/null +++ b/src/game/client/neo/c_neo_point_world_text.cpp @@ -0,0 +1,339 @@ +#include "c_neo_point_world_text.h" +#include "view_scene.h" +#include "view.h" + +typedef struct Character { + int codePoint, x, y, width, height, originX, originY, advance; +} Character; + +typedef struct Font { + const char *name; + int size, bold, italic, width, height, characterCount; + Character *characters; +} Font; + +static Character characters_Roboto_Mono[] = { + {' ', 167, 352, 12, 12, 6, 6, 77}, + {'!', 675, 144, 27, 104, -24, 97, 77}, + {'"', 1859, 249, 44, 42, -16, 102, 77}, + {'#', 702, 144, 82, 103, 2, 97, 77}, + {'$', 324, 0, 70, 131, -4, 112, 77}, + {'%', 1322, 0, 83, 106, 3, 98, 77}, + {'&', 1405, 0, 80, 106, -1, 98, 77}, + {'\'', 1903, 249, 22, 42, -25, 102, 77}, + {'(', 0, 0, 45, 144, -16, 109, 77}, + {')', 45, 0, 45, 144, -14, 109, 77}, + {'*', 1497, 249, 72, 73, -4, 97, 77}, + {'+', 1422, 249, 75, 78, -1, 81, 77}, + {',', 1829, 249, 30, 47, -16, 20, 77}, + {'-', 37, 352, 60, 22, -8, 51, 77}, + {'.', 2008, 249, 30, 30, -25, 22, 77}, + {'/', 568, 0, 60, 111, -10, 97, 77}, + {'0', 1788, 0, 71, 106, -3, 98, 77}, + {'1', 342, 249, 47, 103, -7, 97, 77}, + {'2', 0, 144, 74, 105, 1, 98, 77}, + {'3', 1859, 0, 70, 106, 0, 98, 77}, + {'4', 1263, 144, 78, 103, 1, 97, 77}, + {'5', 572, 144, 69, 104, -6, 97, 77}, + {'6', 74, 144, 70, 105, -3, 97, 77}, + {'7', 1491, 144, 73, 103, -1, 97, 77}, + {'8', 1929, 0, 70, 106, -5, 98, 77}, + {'9', 144, 144, 70, 105, -3, 98, 77}, + {':', 459, 249, 30, 85, -28, 77, 77}, + {';', 641, 144, 34, 104, -24, 77, 77}, + {'<', 1636, 249, 65, 69, -5, 75, 77}, + {'=', 1761, 249, 68, 48, -5, 65, 77}, + {'>', 1569, 249, 67, 69, -5, 75, 77}, + {'?', 283, 144, 66, 105, -6, 98, 77}, + {'@', 349, 144, 80, 104, 2, 97, 77}, + {'A', 865, 144, 80, 103, 1, 97, 77}, + {'B', 1852, 144, 71, 103, -5, 97, 77}, + {'C', 1713, 0, 75, 106, -1, 98, 77}, + {'D', 1417, 144, 74, 103, -4, 97, 77}, + {'E', 71, 249, 68, 103, -5, 97, 77}, + {'F', 139, 249, 68, 103, -6, 97, 77}, + {'G', 1485, 0, 76, 106, 0, 98, 77}, + {'H', 1923, 144, 71, 103, -3, 97, 77}, + {'I', 275, 249, 67, 103, -5, 97, 77}, + {'J', 501, 144, 71, 104, 0, 97, 77}, + {'K', 1341, 144, 76, 103, -5, 97, 77}, + {'L', 207, 249, 68, 103, -6, 97, 77}, + {'M', 1564, 144, 72, 103, -3, 97, 77}, + {'N', 0, 249, 71, 103, -3, 97, 77}, + {'O', 1561, 0, 76, 106, -1, 98, 77}, + {'P', 1636, 144, 72, 103, -6, 97, 77}, + {'Q', 416, 0, 79, 120, 0, 98, 77}, + {'R', 1708, 144, 72, 103, -5, 97, 77}, + {'S', 1637, 0, 76, 106, -1, 98, 77}, + {'T', 945, 144, 80, 103, 1, 97, 77}, + {'U', 429, 144, 72, 104, -3, 97, 77}, + {'V', 1105, 144, 79, 103, 1, 97, 77}, + {'W', 784, 144, 81, 103, 1, 97, 77}, + {'X', 1184, 144, 79, 103, 0, 97, 77}, + {'Y', 1025, 144, 80, 103, 2, 97, 77}, + {'Z', 1780, 144, 72, 103, -1, 97, 77}, + {'[', 90, 0, 37, 136, -21, 110, 77}, + {'\\', 628, 0, 60, 111, -9, 97, 77}, + {']', 127, 0, 37, 136, -19, 110, 77}, + {'^', 1701, 249, 60, 61, -9, 97, 77}, + {'_', 97, 352, 70, 21, -4, 6, 77}, + {'`', 0, 352, 37, 29, -20, 99, 77}, + {'a', 706, 249, 70, 82, -4, 75, 77}, + {'b', 688, 0, 70, 109, -5, 102, 77}, + {'c', 635, 249, 71, 82, -3, 75, 77}, + {'d', 758, 0, 69, 109, -3, 102, 77}, + {'e', 563, 249, 72, 82, -2, 75, 77}, + {'f', 495, 0, 73, 111, -4, 105, 77}, + {'g', 898, 0, 69, 108, -3, 75, 77}, + {'h', 1036, 0, 68, 108, -5, 102, 77}, + {'i', 214, 144, 69, 105, -7, 98, 77}, + {'j', 272, 0, 52, 132, -7, 98, 77}, + {'k', 827, 0, 71, 108, -5, 102, 77}, + {'l', 967, 0, 69, 108, -7, 102, 77}, + {'m', 845, 249, 78, 81, 0, 75, 77}, + {'n', 923, 249, 68, 81, -5, 75, 77}, + {'o', 489, 249, 74, 82, -2, 75, 77}, + {'p', 1184, 0, 69, 107, -5, 75, 77}, + {'q', 1253, 0, 69, 107, -3, 75, 77}, + {'r', 1058, 249, 59, 81, -15, 75, 77}, + {'s', 776, 249, 69, 82, -5, 75, 77}, + {'t', 389, 249, 70, 97, -3, 90, 77}, + {'u', 991, 249, 67, 81, -5, 74, 77}, + {'v', 1200, 249, 76, 80, 0, 74, 77}, + {'w', 1117, 249, 83, 80, 3, 74, 77}, + {'x', 1276, 249, 76, 80, -1, 74, 77}, + {'y', 1104, 0, 80, 107, 2, 74, 77}, + {'z', 1352, 249, 70, 80, -4, 74, 77}, + {'{', 164, 0, 54, 135, -14, 106, 77}, + {'|', 394, 0, 22, 128, -28, 97, 77}, + {'}', 218, 0, 54, 135, -14, 106, 77}, + {'~', 1925, 249, 83, 37, 3, 56, 77}, +}; + +static Font font_Roboto_Mono = {"Roboto Mono", 128, 0, 0, 2048, 512, 95, characters_Roboto_Mono}; + +PointWorldText::PointWorldText() +{ + V_memset(m_szText, 0, sizeof(m_szText)); +} + +PointWorldText::PointWorldText(char* pszText, Vector pos, CMaterialReference* font) +{ + m_vecAbsOrigin = pos; + m_Font = font; + SetText(pszText); +} + +PointWorldText::~PointWorldText() +{ +} + +void PointWorldText::SetText( const char* pszText ) +{ + V_strncpy( m_szText, pszText, sizeof(m_szText) ); + m_nTextLength = V_strlen( m_szText ); + UpdateTextWorldSize(); +} + +void PointWorldText::UpdateTextWorldSize() +{ + CalcTextTotalSize( m_flTextWorldWidth, m_flTextWorldHeight ); +} + +void PointWorldText::CalcTextTotalSize(float &outWidth, float &outHeight) +{ + outWidth = 0.0f; + outHeight = 0.0f; + + const char *szText = m_szText; + if ( !szText[0] ) + return; + + int nNumChars = m_nTextLength; + if ( !nNumChars ) + return; + + float screenSize = m_flTextSize; + float screenSpacingX = GetTextSpacingX(); + float screenSpacingY = GetTextSpacingY(); + Font* font = &font_Roboto_Mono; + outHeight += font->size; + float flLineWidth = 0.0f; + for ( int i = 0; i < nNumChars; i++ ) + { + char nChar = *(szText++); + unsigned int nCharIdx = Clamp( ( unsigned int )( nChar ) - 32, 0u, ( unsigned int )( ARRAYSIZE( characters_Roboto_Mono ) - 1u ) ); + Character *character = &font->characters[ nCharIdx ]; + float scale = screenSize / (float)font->size; + if ( nChar == '\n' ) + { + outWidth = Max( outWidth, flLineWidth ); + flLineWidth = 0.0f; + outHeight += (font->size + screenSpacingY) * scale; + continue; + } + flLineWidth += (character->advance + screenSpacingX) * scale; + } + outWidth = Max( outWidth, flLineWidth ); +} + +float PointWorldText::GetTextWorldWidth() const +{ + return m_flTextWorldWidth; +} +float PointWorldText::GetTextWorldHeight() const +{ + return m_flTextWorldHeight; +} +float PointWorldText::GetTextSpacingX() const +{ + return m_flTextSpacingX; +} +float PointWorldText::GetTextSpacingY() const +{ + return m_flTextSpacingY; +} + +void PointWorldText::DrawModel() +{ + const char *szText = m_szText; + if (!szText[0]) + return; + + int nNumChars = m_nTextLength; + if (!nNumChars) + return; + + IMaterial* pDebugText = *m_Font; + if (!pDebugText) + return; + + if (m_colTextColor.a <= 0) + return; + + Vector ViewForward( 1.0f, 0.0f, 0.0f ); + Vector ViewUp( 0.0f, 1.0f, 0.0f ); + Vector ViewRight( 0.0f, 0.0f, -1.0f ); + Vector vecStartPos; + VectorCopy( GetAbsOrigin(), vecStartPos ); + + float screenSize = m_flTextSize; + float screenSpacingX = GetTextSpacingX(); + float screenSpacingY = GetTextSpacingY(); + + switch ( m_nOrientation ) + { + case POINTWORLDTEXTORIENTATION_VIEW_DIRECTION: + ViewForward = -CurrentViewForward(); + ViewUp = CurrentViewUp(); + ViewRight = CurrentViewRight(); + vecStartPos -= GetTextWorldWidth() * 0.5f * ViewRight; + break; + case POINTWORLDTEXTORIENTATION_VIEW_DIRECTION_Z_ALIGNED: + ViewForward = -CurrentViewForward(); + ViewUp = Vector(0, 0, 1); + ViewRight = CurrentViewRight(); + // center the text for nicer rotation + vecStartPos -= GetTextWorldWidth() * 0.5f * ViewRight; + break; + case POINTWORLDTEXTORIENTATION_VIEW_ORIGIN_Z_ALIGNED: + ViewForward = -CurrentViewOrigin() + GetAbsOrigin(); + ViewUp = Vector(0, 0, 1); + ViewRight = ViewForward.Cross(ViewUp).Normalized(); + // center the text for nicer rotation + vecStartPos -= GetTextWorldWidth() * 0.5f * ViewRight; + break; + case POINTWORLDTEXTORIENTATION_ENTITY_ORIENTATION: + default: + AngleVectors( GetAbsAngles(), &ViewForward, &ViewRight, &ViewUp ); + break; + } + + Vector vecOrigStartPos = vecStartPos; + { + Vector screen; + if (bool behind = ScreenTransform(vecStartPos, screen); + behind) + { + Vector vecEndPos = vecStartPos + (ViewRight * GetTextWorldWidth()); + if (bool behind = ScreenTransform(vecEndPos, screen); + behind) + { + return; + } + } + } + + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + pRenderContext->Bind( pDebugText ); + + IMesh* pMesh = pRenderContext->GetDynamicMesh(); + CMeshBuilder meshBuilder; + meshBuilder.Begin( pMesh, MATERIAL_QUADS, nNumChars ); + + Font *font = &font_Roboto_Mono; + color32 color = m_colTextColor; + byte* pColor = (byte*)&color; + + for ( int i = 0; i < nNumChars; i++ ) + { + char nChar = *(szText++); + unsigned int nCharIdx = Clamp( ( unsigned int )( nChar ) - 32, 0u, ( unsigned int )( ARRAYSIZE( characters_Roboto_Mono ) - 1u ) ); + Character *character = &font->characters[ nCharIdx ]; + float scale = screenSize / (float)font->size; + if ( nChar == '\n' ) + { + vecOrigStartPos -= ( ViewUp * ( (font->size + screenSpacingY) * scale ) ); + vecStartPos = vecOrigStartPos; + continue; + } + if ( nChar != ' ' ) + { + float x, y, s, t; + + x = -character->originX; + y = -character->originY; + s = character->x / (float)font->width; + t = character->y / (float)font->height; + Vector v0 = vecStartPos + ViewRight * x * scale + ViewUp * (- y) * scale; + meshBuilder.Position3fv( v0.Base() ); + meshBuilder.TexCoord2f( 0, s, t ); + meshBuilder.Color4ubv( pColor ); + meshBuilder.AdvanceVertex(); + + x = -character->originX; + y = -character->originY + character->height; + s = character->x / (float)font->width; + t = (character->y + character->height) / (float)font->height; + Vector v2 = vecStartPos + ViewRight * x * scale + ViewUp * (- y) * scale; + meshBuilder.Position3fv( v2.Base() ); + meshBuilder.TexCoord2f( 0, s, t ); + meshBuilder.Color4ubv( pColor ); + meshBuilder.AdvanceVertex(); + + x = -character->originX + character->width; + y = -character->originY + character->height; + s = (character->x + character->width) / (float)font->width; + t = (character->y + character->height) / (float)font->height; + Vector v3 = vecStartPos + ViewRight * x * scale + ViewUp * (- y) * scale; + meshBuilder.Position3fv( v3.Base() ); + meshBuilder.TexCoord2f( 0, s, t ); + meshBuilder.Color4ubv( pColor ); + meshBuilder.AdvanceVertex(); + + x = -character->originX + character->width; + y = -character->originY; + s = (character->x + character->width) / (float)font->width; + t = (character->y) / (float)font->height; + Vector v1 = vecStartPos + ViewRight * x * scale + ViewUp * (- y) * scale; + meshBuilder.Position3fv( v1.Base() ); + meshBuilder.TexCoord2f( 0, s, t ); + meshBuilder.Color4ubv( pColor ); + meshBuilder.AdvanceVertex(); + } + vecStartPos += ViewRight * ((character->advance + screenSpacingX) * scale); + } + meshBuilder.End(); + pMesh->Draw(); + return; +} \ No newline at end of file diff --git a/src/game/client/neo/c_neo_point_world_text.h b/src/game/client/neo/c_neo_point_world_text.h new file mode 100644 index 0000000000..4e384b14a8 --- /dev/null +++ b/src/game/client/neo/c_neo_point_world_text.h @@ -0,0 +1,62 @@ +#pragma once + +/////////////////////////////////////////////// +// A non-networked non-entity PointWorldText // +/////////////////////////////////////////////// + +#include "neo_player_shared.h" + +enum PointWorldTextOrientation +{ + POINTWORLDTEXTORIENTATION_ENTITY_ORIENTATION = 0, + POINTWORLDTEXTORIENTATION_VIEW_DIRECTION, + POINTWORLDTEXTORIENTATION_VIEW_DIRECTION_Z_ALIGNED, + POINTWORLDTEXTORIENTATION_VIEW_ORIGIN_Z_ALIGNED, + + POINTWORLDTEXTORIENTATION__TOTAL +}; + +class PointWorldText +{ +public: + PointWorldText(); + PointWorldText(char* pszText, Vector pos, CMaterialReference* font); + ~PointWorldText(); + + void DrawModel(); + + void SetAbsOrigin(Vector origin) { m_vecAbsOrigin = origin; }; + void SetText(const char* pszText); + void SetAlpha(const float alpha) { m_colTextColor.a = alpha; }; + void SetTextSize(const float size) { m_flTextSize = size; UpdateTextWorldSize(); }; + void SetTextSpacingX(const float spacing) { m_flTextSpacingX = spacing; UpdateTextWorldSize(); }; + void SetOrientation(const PointWorldTextOrientation orientation) { m_nOrientation = orientation; }; + + Vector GetAbsOrigin() { return m_vecAbsOrigin; } + QAngle GetAbsAngles() { return m_vecAbsAngles; } + +private: + void CalcTextTotalSize(float &outWidth, float &outHeight); + void UpdateTextWorldSize(); + + float GetTextWorldWidth() const; + float GetTextWorldHeight() const; + float GetTextSpacingX() const; + float GetTextSpacingY() const; + + Vector m_vecAbsOrigin = {0, 0, 0}; + QAngle m_vecAbsAngles = {0, 0, 0}; + + float m_flTextSize = 64.f; + float m_flTextSpacingX = 0.f; + float m_flTextSpacingY = 0.f; + color32 m_colTextColor = {(byte)COLOR_NEO_WHITE.r(), (byte)COLOR_NEO_WHITE.g(), (byte)COLOR_NEO_WHITE.b(), (byte)COLOR_NEO_WHITE.a()}; + PointWorldTextOrientation m_nOrientation = POINTWORLDTEXTORIENTATION_VIEW_ORIGIN_Z_ALIGNED; + + char m_szText[ MAX_PLACE_NAME_LENGTH ]; + int m_nTextLength = 0; + float m_flTextWorldWidth = 0.f; + float m_flTextWorldHeight = 0.f; + + CMaterialReference* m_Font; +}; \ No newline at end of file diff --git a/src/game/client/neo/ui/neo_hud_place_name.cpp b/src/game/client/neo/ui/neo_hud_place_name.cpp new file mode 100644 index 0000000000..340dbb4e71 --- /dev/null +++ b/src/game/client/neo/ui/neo_hud_place_name.cpp @@ -0,0 +1,524 @@ +#include "neo_hud_place_name.h" + +#include "iclientmode.h" +#include +#include "c_neo_player.h" +#include "view.h" +#include "tier1/lzmaDecoder.h" +#include "smoke_fog_overlay.h" +#include "nav_shared.h" +#include "filesystem.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +DECLARE_NAMED_HUDELEMENT(CNEOHud_PlaceName, neo_place_name); + +NEO_HUD_ELEMENT_DECLARE_FREQ_CVAR(PlaceName, 0.1) + +static CNEOHud_PlaceName *g_PlaceName = nullptr; + +static const char* TEXT_MATERIAL = "vgui/callout_text"; + +static float placeNameRadiusSquared = 0.f; +extern ConVar cl_neo_hud_place_name_radius; +void placeNameRadiusChangeCallback(IConVar* var = nullptr, const char* pOldValue = nullptr, float flOldValue = 0.f) +{ + placeNameRadiusSquared = pow(cl_neo_hud_place_name_radius.GetFloat(), 2); +} +ConVar cl_neo_hud_place_name_radius("cl_neo_hud_place_name_radius", "1024", FCVAR_ARCHIVE, "Radius from the camera within which to draw the names of all nearby places", true, 0.0f, false, 0.0f, + placeNameRadiusChangeCallback); + +CNEOHud_PlaceName::CNEOHud_PlaceName(const char *pElementName, vgui::Panel *parent) + : CHudElement(pElementName), Panel(parent, pElementName) +{ + SetAutoDelete(true); + m_iHideHudElementNumber = NEO_HUD_ELEMENT_PLACE_NAME; + + if (parent) + { + SetParent(parent); + } + else + { + SetParent(g_pClientMode->GetViewport()); + } + + SetVisible(true); + + g_PlaceName = this; + m_szPlaceName[0] = L'\0'; + + PrecacheMaterial( TEXT_MATERIAL ); + m_Font.Init(TEXT_MATERIAL, TEXTURE_GROUP_PRECACHED, true); + + placeNameRadiusChangeCallback(); +} + +CNEOHud_PlaceName::~CNEOHud_PlaceName() +{ + if (g_PlaceName == this) + { + g_PlaceName = nullptr; + } +} + +void CNEOHud_PlaceName::ApplySchemeSettings(vgui::IScheme* pScheme) +{ + BaseClass::ApplySchemeSettings(pScheme); + + int tall = 0; + vgui::surface()->GetScreenSize(wide, tall); + SetBounds(0, 0, wide, tall); + + SetFgColor(COLOR_TRANSPARENT); + SetBgColor(COLOR_TRANSPARENT); +} + +enum +{ + TEXTALIGN_LEFT = 0, + TEXTALIGN_CENTER, + TEXTALIGN_RIGHT +}; +void CNEOHud_PlaceName::UpdateStateForNeoHudElementDraw() +{ + C_NEO_Player* pTargetPlayer = C_NEO_Player::GetLocalNEOPlayer(); + if (!pTargetPlayer) + { + return; + } + + if (pTargetPlayer->IsPlayerDead()) + { + if (const int observerMode = pTargetPlayer->GetObserverMode(); + observerMode == OBS_MODE_IN_EYE || observerMode == OBS_MODE_CHASE) + { + if (C_BaseEntity* pObserverTarget = pTargetPlayer->GetObserverTarget(); + pObserverTarget && pObserverTarget->IsPlayer()) + { + pTargetPlayer = static_cast(pObserverTarget); + } + } + } + + V_snwprintf(m_szPlaceName, MAX_PLACE_NAME_LENGTH, L"%hs", pTargetPlayer->GetLastKnownPlaceName()); + switch (textXAlignment) + { + case TEXTALIGN_LEFT: + default: + textXOffset = 0; + break; + case TEXTALIGN_CENTER: + case TEXTALIGN_RIGHT: + int textWidth = 0, textHeight = 0; + vgui::surface()->GetTextSize(textFont, m_szPlaceName, textWidth, textHeight); + textXOffset = textXAlignment == TEXTALIGN_CENTER ? (wide / 2) - (textWidth / 2) : wide - textWidth; + break; + } +} + +ConVar cl_neo_hud_current_place_name_draw("cl_neo_hud_current_place_name_draw", "1", FCVAR_ARCHIVE, "Draw the current place name", true, 0.0f, true, 1.0f); + +void CNEOHud_PlaceName::DrawNeoHudElement() +{ + if (!ShouldDraw()) + return; + + if (cl_neo_hud_current_place_name_draw.GetBool()) + { + vgui::surface()->DrawSetTextFont(textFont); + vgui::surface()->DrawSetTextColor(textColor); + vgui::surface()->DrawSetTextPos(textXpos + textXOffset, textYpos); + vgui::surface()->DrawPrintText(m_szPlaceName, V_wcslen(m_szPlaceName)); + } +} + +void CNEOHud_PlaceName::Paint() +{ + BaseClass::Paint(); + PaintNeoElement(); +} + +static bool shouldDrawPlaceNames = false; +static ConCommand startshowplacenames("+showPlaceNames", [](const CCommand& args)->void {shouldDrawPlaceNames = true; }); +static ConCommand endshowplacenames("-showPlaceNames", [](const CCommand& args)->void {shouldDrawPlaceNames = false; }); + +static float animationAlpha = 0.f; +void CNEOHud_PlaceName::DrawPlaceNames() +{ + constexpr int ANIMATION_SPEED = 2; + animationAlpha = shouldDrawPlaceNames ? min(1.0f, animationAlpha + (gpGlobals->frametime * ANIMATION_SPEED)) + : max(0.0f, animationAlpha - (gpGlobals->frametime * ANIMATION_SPEED)); + + for (PlaceNameCallout place : places) + { + if (place.navAreaCount <= 0) + { + continue; + } + + float alpha = animationAlpha; + if (placeNameRadiusSquared != 0) + { + if (const float distanceSquared = MainViewOrigin().DistToSqr(place.pointWorldText.GetAbsOrigin()); + distanceSquared > placeNameRadiusSquared) + { + alpha *= 1.f - min(1.f, ((distanceSquared - placeNameRadiusSquared) / placeNameRadiusSquared)); + } + } + + alpha -= g_SmokeFogOverlayAlpha; + alpha = clamp(alpha, 0.f, 1.f); + + place.pointWorldText.SetAlpha(255 * alpha); + place.pointWorldText.DrawModel(); + } +} + +ConVar cl_neo_hud_place_name_text_size("cl_neo_hud_place_name_text_size", "32", FCVAR_ARCHIVE, "Place name text size", true, 1.f, false, 0.f, + [](IConVar* var, const char* pOldValue, float flOldValue)->void{ + if (g_PlaceName) + { + g_PlaceName->SetPlaceNameTextSize(cl_neo_hud_place_name_text_size.GetFloat()); + } + +}); +void CNEOHud_PlaceName::SetPlaceNameTextSize(const float textSize) +{ + for (int i=0; ivoid{ + if (g_PlaceName) + { + g_PlaceName->SetPlaceNameTextSpacingX(cl_neo_hud_place_name_text_spacing_x.GetFloat()); + } + +}); +void CNEOHud_PlaceName::SetPlaceNameTextSpacingX(const float textSpacingX) +{ + for (int i=0; ivoid{ + if (g_PlaceName) + { + g_PlaceName->SetPlaceNameOffset(cl_neo_hud_place_name_offset.GetFloat()); + } + +}); +void CNEOHud_PlaceName::SetPlaceNameOffset(const float offset) +{ + const Vector vOffset = Vector(0, 0, offset); + for (int i=0; ivoid{ + if (g_PlaceName) + { + g_PlaceName->SetPlaceNameOrientation((PointWorldTextOrientation)cl_neo_hud_place_name_orientation.GetInt()); + } + +}); +void CNEOHud_PlaceName::SetPlaceNameOrientation(const PointWorldTextOrientation orientation) +{ + for (int i=0; iGetLevelName(), maptmp, sizeof( maptmp) ); + const char* pszMapName = maptmp; + + // nav filename is derived from map filename + char filename[MAX_PATH] = { 0 }; + Q_snprintf( filename, sizeof( filename ), FORMAT_NAVFILE, pszMapName ); + + if ( !filesystem->ReadFile( filename, "MOD", outBuffer ) ) // this ignores .nav files embedded in the .bsp ... + { + if ( !filesystem->ReadFile( filename, "BSP", outBuffer ) ) // ... and this looks for one if it's the only one around. + { + // Finally, check for the special embed name for in-BSP nav meshes only + if ( !filesystem->ReadFile( PATH_NAVFILE_EMBEDDED, "BSP", outBuffer ) ) + { + return NAV_CANT_ACCESS_FILE; + } + } + if ( pNavDataFromBSP ) + { + *pNavDataFromBSP = true; + } + } + + if ( IsX360() ) + { + // 360 has compressed NAVs + if ( CLZMA::IsCompressed( (unsigned char *)outBuffer.Base() ) ) + { + int originalSize = CLZMA::GetActualSize( (unsigned char *)outBuffer.Base() ); + unsigned char *pOriginalData = new unsigned char[originalSize]; + CLZMA::Uncompress( (unsigned char *)outBuffer.Base(), pOriginalData ); + outBuffer.AssumeMemory( pOriginalData, originalSize, originalSize, CUtlBuffer::READ_ONLY ); + } + } + + return NAV_OK; +} + +//-------------------------------------------------------------------------------------------------------------- +/** + * Reads the used place names from the nav file (can be used to selectively precache before the nav is loaded) + */ +void CNEOHud_PlaceName::GetPlacesFromNavFile() +{ + places.RemoveAll(); + // nav filename is derived from map filename + char filename[256]; + Q_snprintf( filename, sizeof( filename ), FORMAT_NAVFILE, STRING( engine->GetLevelName() ) ); + + CUtlBuffer fileBuffer( 4096, 1024*1024, CUtlBuffer::READ_ONLY ); + if ( GetNavDataFromFile( fileBuffer ) != NAV_OK ) + { + return; + } + + // check magic number + unsigned int magic = fileBuffer.GetUnsignedInt(); + if ( !fileBuffer.IsValid() || magic != NAV_MAGIC_NUMBER ) + { + return; // Corrupt nav file? + } + + // read file version number + unsigned int version = fileBuffer.GetUnsignedInt(); + if ( !fileBuffer.IsValid() || version > NavCurrentVersion ) + { + return; // Unknown nav file version + } + + if ( version < 5 ) + { + return; // Too old to have place names + } + + unsigned int subVersion = 0; + if ( version >= 10 ) + { + subVersion = fileBuffer.GetUnsignedInt(); + if ( !fileBuffer.IsValid() ) + { + return; // No sub-version + } + } + + fileBuffer.GetUnsignedInt(); // skip BSP file size (version >= 4) + if ( version >= 14 ) + { + fileBuffer.GetUnsignedChar(); // skip m_isAnalyzed + } + + { + // read number of entries + unsigned short placeCount = fileBuffer.GetUnsignedShort(); + + places.RemoveAll(); + + // read each entry + char placeName[256]; + unsigned short len; + for( int i=0; i 11) + { + fileBuffer.GetUnsignedChar(); // Skip has unnamed areas + } + } + + // get number of areas + unsigned int areaCount = fileBuffer.GetUnsignedInt(); + unsigned int i; + + if (areaCount == 0) + { + return; + } + + // Read each nav area + for (i = 0; i < areaCount; ++i) + { + fileBuffer.GetUnsignedInt(); // Skip ID + + if (version <= 8) // Skip attribute flags + { + fileBuffer.GetUnsignedChar(); + } + else if (version < 13) + { + fileBuffer.GetUnsignedShort(); + } + else + { + fileBuffer.GetUnsignedInt(); + } + + Vector nwCorner; + Vector seCorner; + fileBuffer.Get(&nwCorner, 3 * sizeof(float)); + fileBuffer.Get(&seCorner, 3 * sizeof(float)); + + fileBuffer.GetFloat(); // Skip heights of implicit corners + fileBuffer.GetFloat(); + + for (int d = 0; d < NavDirType::NUM_DIRECTIONS; d++) + { + unsigned int connectionCount = fileBuffer.GetUnsignedInt(); + Assert(fileBuffer.IsValid()); + + for (unsigned int j = 0; j < connectionCount; ++j) + { + fileBuffer.GetUnsignedInt(); // Skip connection ID + Assert(fileBuffer.IsValid()); + } + } + + unsigned char hidingSpotCount = fileBuffer.GetUnsignedChar(); + for (unsigned char h = 0; h < hidingSpotCount; ++h) + { + fileBuffer.GetUnsignedInt(); // Skip hiding spot ID + fileBuffer.GetFloat(); // Skip hiding spot pos X + fileBuffer.GetFloat(); // Skip hiding spot pos Y + fileBuffer.GetFloat(); // Skip hiding spot pos Z + fileBuffer.GetUnsignedChar(); // Skip hiding spot flags + } + + if (version < 15) + { + // Skip the approach areas + unsigned char nToEat = fileBuffer.GetUnsignedChar(); + for (unsigned char a = 0; a < nToEat; ++a) + { + fileBuffer.GetUnsignedInt(); + fileBuffer.GetUnsignedInt(); + fileBuffer.GetUnsignedChar(); + fileBuffer.GetUnsignedInt(); + fileBuffer.GetUnsignedChar(); + } + } + + // Skip encounter paths + unsigned int encounterCount = fileBuffer.GetUnsignedInt(); + for (unsigned int e = 0; e < encounterCount; ++e) + { + fileBuffer.GetUnsignedInt(); // Skip from ID + fileBuffer.GetUnsignedChar(); // Skip from dir + fileBuffer.GetUnsignedInt(); // Skip to ID + fileBuffer.GetUnsignedChar(); // Skip to dir + + unsigned char spotCount = fileBuffer.GetUnsignedChar(); + for(unsigned char s=0; s 0 && entry <= places.Count()) + { + entry -= 1; + Vector newNavCenter = (nwCorner + seCorner) / 2.f; + places[entry].origin = ((places[entry].origin * places[entry].navAreaCount) + newNavCenter) / ++places[entry].navAreaCount; + places[entry].pointWorldText.SetAbsOrigin(places[entry].origin + Vector(0, 0, cl_neo_hud_place_name_offset.GetFloat())); + } + + if (version < 7) + { + continue; + } + + // Skip ladder data + for (int dir=0; dir + +enum NavErrorType +{ + NAV_OK, + NAV_CANT_ACCESS_FILE, + NAV_INVALID_FILE, + NAV_BAD_FILE_VERSION, + NAV_FILE_OUT_OF_DATE, + NAV_CORRUPT_DATA, + NAV_OUT_OF_MEMORY, +}; + +struct PlaceNameCallout +{ + PointWorldText pointWorldText; + Vector origin; + int navAreaCount; +}; + +class CNEOHud_PlaceName : public CNEOHud_ChildElement, public CHudElement, public vgui::Panel, public CAutoGameSystem +{ + DECLARE_CLASS_SIMPLE(CNEOHud_PlaceName, Panel); + +public: + CNEOHud_PlaceName(const char *pElementName, vgui::Panel *parent = NULL); + ~CNEOHud_PlaceName(); + void ApplySchemeSettings(vgui::IScheme* pScheme) override; + virtual void Paint() override; + void DrawPlaceNames(); + CMaterialReference GetFont() const { return m_Font; }; + + void SetPlaceNameOffset(const float offset); + void SetPlaceNameTextSize(const float textSize); + void SetPlaceNameTextSpacingX(const float textSpacing); + void SetPlaceNameOrientation(const PointWorldTextOrientation orientation); + +protected: + virtual void UpdateStateForNeoHudElementDraw() override; + virtual void DrawNeoHudElement() override; + virtual ConVar* GetUpdateFrequencyConVar() const override; + +private: + CNEOHud_PlaceName(const CNEOHud_PlaceName&other); + + NavErrorType GetNavDataFromFile(CUtlBuffer& outBuffer, bool* pNavDataFromBSP = nullptr); + void GetPlacesFromNavFile(); + + // CAutoGameSystem + + virtual void LevelInitPostEntity() override + { + GetPlacesFromNavFile(); + } + + wchar_t m_szPlaceName[MAX_PLACE_NAME_LENGTH]; + int textXOffset = 0; + int wide = 0; + + CUtlVector places; + CMaterialReference m_Font; + + CPanelAnimationVarAliasType(int, textXpos, "textXpos", "80", "proportional_xpos"); + CPanelAnimationVarAliasType(int, textYpos, "textYpos", "80", "proportional_ypos"); + CPanelAnimationVar(vgui::HFont, textFont, "textFont", ""); + CPanelAnimationVar(Color, textColor, "textColor", "255 255 255 255"); + CPanelAnimationVar(int, textXAlignment, "textXAlignment", "0"); +}; + +CNEOHud_PlaceName* GetPlaceName(); \ No newline at end of file diff --git a/src/game/client/viewrender.cpp b/src/game/client/viewrender.cpp index 19b69e0654..b7df5e0013 100644 --- a/src/game/client/viewrender.cpp +++ b/src/game/client/viewrender.cpp @@ -68,6 +68,7 @@ #ifdef NEO #include "neo_player_shared.h" #include +#include "ui/neo_hud_place_name.h" #endif // NEO #include "rendertexture.h" #include "viewpostprocess.h" @@ -2000,6 +2001,22 @@ void CViewRender::RenderPlayerSprites() GetClientVoiceMgr()->DrawHeadLabels(); } +#ifdef NEO +//----------------------------------------------------------------------------- +// Purpose: Renders navigation mesh place names +// Input : none +//----------------------------------------------------------------------------- +void CViewRender::RenderPlaceNames() +{ + tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ ); + + if (auto placeNameHudElement = GetPlaceName()) + { + placeNameHudElement->DrawPlaceNames(); + } +} +#endif // NEO + //----------------------------------------------------------------------------- // Sets up, cleans up the main 3D view //----------------------------------------------------------------------------- @@ -2333,6 +2350,7 @@ void CViewRender::RenderView( const CViewSetup &viewRender, int nClearFlags, int #ifdef NEO // && defined GLOWS_ENABLE? // Add glow effect after HDR stuff is done and vision modes are applied, so the colour of the effect doesn't vary GetClientModeNormal()->DoPostScreenSpaceEffects(&viewRender); + RenderPlaceNames(); #endif // NEO CleanupMain3DView( viewRender ); diff --git a/src/game/client/viewrender.h b/src/game/client/viewrender.h index 6e62349866..5199f4508f 100644 --- a/src/game/client/viewrender.h +++ b/src/game/client/viewrender.h @@ -362,6 +362,9 @@ class CViewRender : public IViewRender, virtual void Render( vrect_t *rect ); virtual void RenderView( const CViewSetup &view, int nClearFlags, int whatToDraw ); virtual void RenderPlayerSprites(); +#ifdef NEO + virtual void RenderPlaceNames(); +#endif // NEO virtual void Render2DEffectsPreHUD( const CViewSetup &view ); virtual void Render2DEffectsPostHUD( const CViewSetup &view ); diff --git a/src/game/server/CMakeLists.txt b/src/game/server/CMakeLists.txt index a05ccbb8a2..bc5a57683d 100644 --- a/src/game/server/CMakeLists.txt +++ b/src/game/server/CMakeLists.txt @@ -1471,6 +1471,7 @@ target_sources_grouped( NAME "NEO" FILES ${CMAKE_SOURCE_DIR}/game/shared/neo/achievements_neo.h + ${CMAKE_SOURCE_DIR}/game/shared/neo/nav_shared.h ${CMAKE_SOURCE_DIR}/game/shared/neo/neo_gamerules.h ${CMAKE_SOURCE_DIR}/game/shared/neo/neo_ghost_cap_point.h ${CMAKE_SOURCE_DIR}/game/shared/neo/neo_juggernaut.h diff --git a/src/game/server/nav.h b/src/game/server/nav.h index 78dcd77254..35899935e4 100644 --- a/src/game/server/nav.h +++ b/src/game/server/nav.h @@ -14,6 +14,9 @@ #include "modelentities.h" // for CFuncBrush #include "doors.h" +#ifdef NEO +#include "nav_shared.h" +#endif // NEO /** * Below are several constants used by the navigation system. @@ -60,8 +63,9 @@ const float CliffHeight = 300.0f; // height which we consider a significant c #define HumanCrouchHeight 55 #define HumanCrouchEyeHeight 37 - +#ifndef NEO #define NAV_MAGIC_NUMBER 0xFEEDFACE // to help identify nav files +#endif // NEO /** * A place is a named group of navigation areas @@ -111,6 +115,7 @@ enum NavAttributeType extern NavAttributeType NameToNavAttribute( const char *name ); +#ifndef NEO enum NavDirType { NORTH = 0, @@ -120,6 +125,7 @@ enum NavDirType NUM_DIRECTIONS }; +#endif // NEO /** * Defines possible ways to move from one area to another @@ -141,6 +147,7 @@ enum NavTraverseType NUM_TRAVERSE_TYPES }; +#ifndef NEO enum NavCornerType { NORTH_WEST = 0, @@ -150,6 +157,7 @@ enum NavCornerType NUM_CORNERS }; +#endif // NEO enum NavRelativeDirType { diff --git a/src/game/server/nav_area.cpp b/src/game/server/nav_area.cpp index 156e2b598e..e5e33113cd 100644 --- a/src/game/server/nav_area.cpp +++ b/src/game/server/nav_area.cpp @@ -35,6 +35,10 @@ #include "team.h" #include "nav_entities.h" +#ifdef NEO +#include "nav_shared.h" +#endif // NEO + // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -1265,6 +1269,12 @@ bool CNavArea::SplitEdit( bool splitAlongX, float splitEdge, CNavArea **outAlpha SplitNotification notify( this, alpha, beta ); TheNavMesh->ForAllLadders( notify ); +#ifdef NEO + // If the old area had a place name, the new areas will inherit it + alpha->SetPlace( m_place ); + beta->SetPlace( m_place ); +#endif // NEO + // return new areas if (outAlpha) *outAlpha = alpha; @@ -4702,6 +4712,21 @@ bool CNavArea::IsBlocked( int teamID, bool ignoreNavBlockers ) const return m_isBlocked[ teamIdx ]; } +#ifdef NEO +void CNavArea::SetPlace(Place place) +{ + if (m_place == place) + return; + + if (this == TheNavMesh->GetNavAreaByID(GetID())) + { + TheNavMesh->DecrementNumPlaces(m_place, this); + TheNavMesh->IncrementNumPlaces(place, this); + } + m_place = place; +} +#endif // NEO + //-------------------------------------------------------------------------------------------------------- void CNavArea::MarkAsBlocked( int teamID, CBaseEntity *blocker, bool bGenerateEvent ) { diff --git a/src/game/server/nav_area.h b/src/game/server/nav_area.h index ee8afa5bb7..cc631c6ee7 100644 --- a/src/game/server/nav_area.h +++ b/src/game/server/nav_area.h @@ -15,8 +15,12 @@ #include "nav_ladder.h" #include "tier1/memstack.h" +#ifdef NEO +#include "nav_shared.h" +#else // BOTPORT: Clean up relationship between team index and danger storage in nav areas enum { MAX_NAV_TEAMS = 2 }; +#endif // NEO #define DebuggerBreakOnNaN_StagingOnly( _val ) @@ -299,7 +303,11 @@ class CNavArea : protected CNavAreaCriticalData bool HasAttributes( int bits ) const { return ( m_attributeFlags & bits ) ? true : false; } void RemoveAttributes( int bits ) { m_attributeFlags &= ( ~bits ); } +#ifdef NEO + void SetPlace( Place place ); // set place descriptor +#else void SetPlace( Place place ) { m_place = place; } // set place descriptor +#endif // NEO Place GetPlace( void ) const { return m_place; } // get place descriptor void MarkAsBlocked( int teamID, CBaseEntity *blocker, bool bGenerateEvent = true ); // An entity can force a nav area to be blocked diff --git a/src/game/server/nav_file.cpp b/src/game/server/nav_file.cpp index e2c1641017..3a46fec004 100644 --- a/src/game/server/nav_file.cpp +++ b/src/game/server/nav_file.cpp @@ -34,10 +34,15 @@ #include "util_shared.h" +#ifdef NEO +#include "nav_shared.h" +#endif // NEO + // NOTE: This has to be the last file included! #include "tier0/memdbgon.h" +#ifndef NEO //-------------------------------------------------------------------------------------------------------------- /// The current version of the nav file format @@ -45,6 +50,7 @@ /// must be updated to match. If not, this will break the Xbox 360. // TODO: Was changed from 15, update when latest 360 code is integrated (MSB 5/5/09) const int NavCurrentVersion = 16; +#endif // NEO //-------------------------------------------------------------------------------------------------------------- // @@ -162,7 +168,9 @@ void PlaceDirectory::Load( CUtlBuffer &fileBuffer, int version ) { len = fileBuffer.GetUnsignedShort(); fileBuffer.Get( placeName, MIN( sizeof( placeName ), len ) ); - +#ifdef NEO + TheNavMesh->LoadPlace(placeName); +#endif // NEO Place place = TheNavMesh->NameToPlace( placeName ); if (place == UNDEFINED_PLACE) { @@ -181,18 +189,16 @@ void PlaceDirectory::Load( CUtlBuffer &fileBuffer, int version ) PlaceDirectory placeDirectory; +#ifndef NEO #if defined( _X360 ) #define FORMAT_BSPFILE "maps\\%s.360.bsp" #define FORMAT_NAVFILE "maps\\%s.360.nav" #else #define FORMAT_BSPFILE "maps\\%s.bsp" -#ifdef NEO - #define FORMAT_NAVFILE "maps\\nav\\%s.nav" -#else #define FORMAT_NAVFILE "maps\\%s.nav" -#endif // NEO #define PATH_NAVFILE_EMBEDDED "maps\\embed.nav" #endif +#endif // NEO //-------------------------------------------------------------------------------------------------------------- /** diff --git a/src/game/server/nav_mesh.cpp b/src/game/server/nav_mesh.cpp index 299bf76ff3..2a74a6be5e 100644 --- a/src/game/server/nav_mesh.cpp +++ b/src/game/server/nav_mesh.cpp @@ -69,10 +69,12 @@ CNavMesh::CNavMesh( void ) m_editMode = NORMAL; m_bQuitWhenFinished = false; m_hostThreadModeRestoreValue = 0; +#ifndef NEO m_placeCount = 0; m_placeName = NULL; LoadPlaceDatabase(); +#endif // NEO ListenForGameEvent( "round_start" ); // ListenForGameEvent( "round_start_pre_entity" ); @@ -89,11 +91,15 @@ CNavMesh::~CNavMesh() if (m_spawnName) delete [] m_spawnName; +#ifdef NEO + m_placeName.RemoveAll(); +#else // !!!!bug!!! why does this crash in linux on server exit for( unsigned int i=0; iGetPlace(), area); +#endif // NEO ++m_areaCount; } @@ -568,6 +582,10 @@ void CNavMesh::RemoveNavArea( CNavArea *area ) m_avoidanceObstacleAreas.FindAndRemove( area ); m_blockedAreas.FindAndRemove( area ); +#ifdef NEO + DecrementNumPlaces(area->GetPlace(), area); +#endif // NEO + --m_areaCount; } @@ -1100,6 +1118,7 @@ unsigned int CNavMesh::GetPlace( const Vector &pos ) const return UNDEFINED_PLACE; } +#ifndef NEO //-------------------------------------------------------------------------------------------------------------- /** * Load the place names from a file @@ -1184,6 +1203,7 @@ void CNavMesh::LoadPlaceDatabase( void ) m_placeName[i] = placeNames[i]; } } +#endif // NEO //-------------------------------------------------------------------------------------------------------------- /** @@ -1192,8 +1212,13 @@ void CNavMesh::LoadPlaceDatabase( void ) */ const char *CNavMesh::PlaceToName( Place place ) const { +#ifdef NEO + if (place >= 1 && place <= (Place)m_placeName.Count()) + return m_placeName[ (int)place - 1 ].name; +#else if (place >= 1 && place <= m_placeCount) return m_placeName[ (int)place - 1 ]; +#endif // NEO return NULL; } @@ -1206,10 +1231,17 @@ const char *CNavMesh::PlaceToName( Place place ) const */ Place CNavMesh::NameToPlace( const char *name ) const { +#ifdef NEO + for( unsigned int i=0; i<(Place)m_placeName.Count(); ++i ) + { + if (FStrEq( m_placeName[i].name, name )) + return i+1; +#else for( unsigned int i=0; i= 1 && place <= (Place)m_placeName.Count()) + return m_placeName[ (int)place - 1 ].averageCenter; + + return vec3_origin; +} + +//-------------------------------------------------------------------------------------------------------------- +/** + * Return the first unused index in m_placeName + */ +Place CNavMesh::LoadPlace(const char* name) +{ + PlaceNameAndCount placeNameAndCount = { "", 0 }; + V_strcpy_safe(placeNameAndCount.name, name); + return m_placeName.AddToTail(placeNameAndCount) + 1; +} + +//-------------------------------------------------------------------------------------------------------------- +/** + * Return the first unused or empty index in m_placeName + */ +Place CNavMesh::NextAvailablePlace(const char* name) +{ + for (int i = 0; i < m_placeName.Count(); i++) + { + if (m_placeName[i].count <= 0) + { + V_strcpy_safe(m_placeName[i].name, name); + m_placeName[i].count = 0; + return i+1; + } + } + + PlaceNameAndCount placeNameAndCount = { "", 0 }; + V_strcpy_safe(placeNameAndCount.name, name); + return m_placeName.AddToTail(placeNameAndCount) + 1; +} + +void CNavMesh::IncrementNumPlaces(Place place, CNavArea* area) +{ + if (place <= UNDEFINED_PLACE || place > (Place)m_placeName.Count()) + { + return; + } + + const int i = place - 1; + const int newCount = m_placeName[i].count + 1; + if (newCount != 0) + { + m_placeName[i].averageCenter = ((m_placeName[i].averageCenter * m_placeName[i].count) + area->GetCenter()) / newCount; + } + else + { + m_placeName[i].averageCenter = vec3_origin; + } + m_placeName[i].count = newCount; +} + +void CNavMesh::DecrementNumPlaces(Place place, CNavArea* area) +{ + if (place <= UNDEFINED_PLACE || place > (Place)m_placeName.Count()) + { + return; + } + + const int i = place - 1; + const int newCount = m_placeName[i].count - 1; + if (newCount != 0) + { + m_placeName[i].averageCenter = ((m_placeName[i].averageCenter * m_placeName[i].count) - area->GetCenter()) / newCount; + } + else + { + m_placeName[i].averageCenter = vec3_origin; + } + m_placeName[i].count = newCount; +} +#endif // NEO //-------------------------------------------------------------------------------------------------------------- /** @@ -1264,12 +1401,24 @@ int CNavMesh::PlaceNameAutocomplete( char const *partial, char commands[ COMMAND partial += Q_strlen( "nav_use_place " ); int partialLength = Q_strlen( partial ); +#ifdef NEO + for( unsigned int i=0; i<(Place)m_placeName.Count(); i++ ) +#else for( unsigned int i=0; i placeNames; +#ifdef NEO + for ( i=0; i<(Place)m_placeName.Count(); i++ ) +#else for ( i=0; iNameToPlace(args[1]); + place != UNDEFINED_PLACE) + { + Msg( "Current place set to '%s'\n", args[1] ); + TheNavMesh->SetNavPlace(place); + return; + } + + Msg( "Current place set to new place '%s'\n", args[1] ); + TheNavMesh->SetNavPlace(TheNavMesh->NextAvailablePlace(args[1])); +#else if (args.ArgC() == 1) { // no arguments = list all available places @@ -2404,6 +2583,7 @@ void CommandNavUsePlace( const CCommand &args ) TheNavMesh->SetNavPlace( place ); } } +#endif // NEO } static ConCommand nav_use_place( "nav_use_place", CommandNavUsePlace, "If used without arguments, all available Places will be listed. If a Place argument is given, the current Place is set.", FCVAR_GAMEDLL | FCVAR_CHEAT, PlaceNameAutocompleteCallback ); @@ -2422,6 +2602,20 @@ void CommandNavPlaceReplace( const CCommand &args ) else { // two arguments - replace the first place with the second +#ifdef NEO + Place oldPlace = TheNavMesh->NameToPlace(args[1]); + if (oldPlace == UNDEFINED_PLACE) + { + Msg("Old place name not found"); + return; + } + + Place newPlace = TheNavMesh->NameToPlace(args[2]); + if (newPlace == UNDEFINED_PLACE) + { + newPlace = TheNavMesh->NextAvailablePlace(args[2]); + } +#else Place oldPlace = TheNavMesh->PartialNameToPlace( args[ 1 ] ); Place newPlace = TheNavMesh->PartialNameToPlace( args[ 2 ] ); @@ -2430,6 +2624,7 @@ void CommandNavPlaceReplace( const CCommand &args ) Msg( "Ambiguous\n" ); } else +#endif // NEO { FOR_EACH_VEC( TheNavAreas, it ) { diff --git a/src/game/server/nav_mesh.h b/src/game/server/nav_mesh.h index e778b03cd1..ecd20fc8f5 100644 --- a/src/game/server/nav_mesh.h +++ b/src/game/server/nav_mesh.h @@ -342,6 +342,13 @@ class CNavMesh : public CGameEventListener Place NameToPlace( const char *name ) const; // given a place name, return a place ID or zero if no place is defined Place PartialNameToPlace( const char *name ) const; // given the first part of a place name, return a place ID or zero if no place is defined, or the partial match is ambiguous void PrintAllPlaces( void ) const; // output a list of names to the console +#ifdef NEO + const Vector PlaceToLocation(Place place) const; + Place LoadPlace(const char* name); + Place NextAvailablePlace(const char* name); + void IncrementNumPlaces(Place place, CNavArea* area); + void DecrementNumPlaces(Place place, CNavArea* area); +#endif // NEO int PlaceNameAutocomplete( char const *partial, char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ] ); // Given a partial place name, fill in possible place names for ConCommand autocomplete bool GetGroundHeight( const Vector &pos, float *height, Vector *normal = NULL ) const; // get the Z coordinate of the topmost ground level below the given point @@ -1128,9 +1135,19 @@ class CNavMesh : public CGameEventListener //---------------------------------------------------------------------------------- // Place directory // +#ifdef NEO + struct PlaceNameAndCount + { + char name[MAX_PLACE_NAME_LENGTH]; + int count; + Vector averageCenter; + }; + CUtlVectorm_placeName; // master directory of place names (i.e: "places") +#else char **m_placeName; // master directory of place names (ie: "places") unsigned int m_placeCount; // number of "places" defined in placeName[] void LoadPlaceDatabase( void ); // load the place names from a file +#endif // NEO //---------------------------------------------------------------------------------- // Edit mode diff --git a/src/game/server/neo/neo_player.cpp b/src/game/server/neo/neo_player.cpp index bfe41aaec4..e27818028a 100644 --- a/src/game/server/neo/neo_player.cpp +++ b/src/game/server/neo/neo_player.cpp @@ -41,6 +41,7 @@ #include "nav_mesh.h" #include "neo_spawn_manager.h" #include "recipientfilter.h" +#include "nav_mesh.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -1192,6 +1193,19 @@ void CNEO_Player::PreThink(void) SuperJump(); } } + + if (TheNavMesh) + { + const char* placeName = TheNavMesh->PlaceToName(TheNavMesh->GetPlace(GetAbsOrigin())); + if (!placeName || !placeName[0]) + { + placeName = ""; + } + if (Q_strcmp(m_szLastPlaceName.Get(), placeName)) + { + Q_strncpy(m_szLastPlaceName.GetForModify(), placeName, sizeof(m_szLastPlaceName)); + } + } } void CNEO_Player::PlayCloakSound(bool removeLocalPlayer) diff --git a/src/game/shared/neo/nav_shared.h b/src/game/shared/neo/nav_shared.h new file mode 100644 index 0000000000..25f87b27b3 --- /dev/null +++ b/src/game/shared/neo/nav_shared.h @@ -0,0 +1,57 @@ +#pragma once + +#if defined( _X360 ) + #define FORMAT_BSPFILE "maps\\%s.360.bsp" + #define FORMAT_NAVFILE "maps\\%s.360.nav" +#else + #define FORMAT_BSPFILE "maps\\%s.bsp" +#ifdef NEO + #define FORMAT_NAVFILE "maps\\nav\\%s.nav" +#else + #define FORMAT_NAVFILE "maps\\%s.nav" +#endif // NEO + #define PATH_NAVFILE_EMBEDDED "maps\\embed.nav" +#endif + +#define NAV_MAGIC_NUMBER 0xFEEDFACE // to help identify nav files + +//-------------------------------------------------------------------------------------------------------------- +/// The current version of the nav file format + +/// IMPORTANT: If this version changes, the swap function in makegamedata +/// must be updated to match. If not, this will break the Xbox 360. +// TODO: Was changed from 15, update when latest 360 code is integrated (MSB 5/5/09) +const int NavCurrentVersion = 16; + +enum NavDirType +{ + NORTH = 0, + EAST = 1, + SOUTH = 2, + WEST = 3, + + NUM_DIRECTIONS +}; + +enum { MAX_NAV_TEAMS = 2 }; + +enum NavCornerType +{ + NORTH_WEST = 0, + NORTH_EAST = 1, + SOUTH_EAST = 2, + SOUTH_WEST = 3, + + NUM_CORNERS +}; + +#ifdef CLIENT_DLL +// defined in CNavLadder +enum LadderDirectionType +{ + LADDER_UP = 0, + LADDER_DOWN, + + NUM_LADDER_DIRECTIONS +}; +#endif // CLIENT_DLL \ No newline at end of file diff --git a/src/game/shared/neo/neo_gamerules.h b/src/game/shared/neo/neo_gamerules.h index e59b8071be..48f008ee8f 100644 --- a/src/game/shared/neo/neo_gamerules.h +++ b/src/game/shared/neo/neo_gamerules.h @@ -171,6 +171,7 @@ enum NeoHudElements : NEO_HUD_BITS_UNDERLYING_TYPE { NEO_HUD_ELEMENT_PLAYER_PING = (static_cast(1) << 15), NEO_HUD_ELEMENT_WORLDPOS_MARKER_ENT = (static_cast(1) << 16), NEO_HUD_ELEMENT_SPECTATOR_OVERLAY = (static_cast(1) << 17), + NEO_HUD_ELEMENT_PLACE_NAME = (static_cast(1) << 18), }; enum NeoSpectateEvent {