//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ // //=============================================================================// // nav_area.cpp // AI Navigation areas // Author: Michael S. Booth (mike@turtlerockstudios.com), January 2003 #include "cbase.h" #include "cs_nav_mesh.h" #include "cs_nav_area.h" #include "cs_gamerules.h" #include "nav_pathfind.h" #include "nav_colors.h" #include "fmtstr.h" #include "props_shared.h" #include "func_breakablesurf.h" #include "color.h" #include "collisionutils.h" #include "point_hiding_spot.h" // memdbgon must be the last include file in a .cpp file!!! #include #ifdef _WIN32 #pragma warning (disable:4701) // disable warning that variable *may* not be initialized #endif //-------------------------------------------------------------------------------------------------------------- /** * Constructor used during normal runtime. */ CCSNavArea::CCSNavArea( void ) { #ifndef PLATFORM_64BITS // TODO64: this is probably just alignment for performance, but perhaps the sizes are hardcoded somewhere COMPILE_TIME_ASSERT( sizeof( CNavAreaCriticalData ) == 128 ); COMPILE_TIME_ASSERT( sizeof( CCSNavArea ) == 768 ); #endif m_approachCount = 0; } //-------------------------------------------------------------------------------------------------------------- /** * Destructor */ CCSNavArea::~CCSNavArea() { } void CCSNavArea::OnServerActivate( void ) { CNavArea::OnServerActivate(); } void CCSNavArea::OnRoundRestart( void ) { CNavArea::OnRoundRestart(); } void CCSNavArea::Save( CUtlBuffer &fileBuffer, unsigned int version ) const { CNavArea::Save( fileBuffer, version ); // // Save the approach areas for this area // // save number of approach areas fileBuffer.PutUnsignedChar(m_approachCount); // save approach area info for( int a=0; aGetID()); else fileBuffer.PutUnsignedInt(0); if (m_approach[a].prev.area) fileBuffer.PutUnsignedInt(m_approach[a].prev.area->GetID()); else fileBuffer.PutUnsignedInt(0); fileBuffer.PutUnsignedChar(m_approach[a].prevToHereHow); if (m_approach[a].next.area) fileBuffer.PutUnsignedInt(m_approach[a].next.area->GetID()); else fileBuffer.PutUnsignedInt(0); fileBuffer.PutUnsignedChar(m_approach[a].hereToNextHow); } } NavErrorType CCSNavArea::Load( CUtlBuffer &fileBuffer, unsigned int version, unsigned int subVersion ) { if ( version < 15 ) return LoadLegacy(fileBuffer, version, subVersion); // load base class data NavErrorType error = CNavArea::Load( fileBuffer, version, subVersion ); switch ( subVersion ) { case 1: // // Load number of approach areas // m_approachCount = fileBuffer.GetUnsignedChar(); // load approach area info (IDs) for( int a = 0; a < m_approachCount; ++a ) { m_approach[a].here.id = fileBuffer.GetUnsignedInt(); m_approach[a].prev.id = fileBuffer.GetUnsignedInt(); m_approach[a].prevToHereHow = (NavTraverseType)fileBuffer.GetUnsignedChar(); m_approach[a].next.id = fileBuffer.GetUnsignedInt(); m_approach[a].hereToNextHow = (NavTraverseType)fileBuffer.GetUnsignedChar(); } if ( !fileBuffer.IsValid() ) error = NAV_INVALID_FILE; // fall through case 0: // legacy version break; default: Warning( "Unknown NavArea sub-version number\n" ); error = NAV_INVALID_FILE; } return error; } NavErrorType CCSNavArea::PostLoad( void ) { NavErrorType error = CNavArea::PostLoad(); // resolve approach area IDs for ( int a = 0; a < m_approachCount; ++a ) { m_approach[a].here.area = TheNavMesh->GetNavAreaByID( m_approach[a].here.id ); if (m_approach[a].here.id && m_approach[a].here.area == NULL) { Msg( "CNavArea::PostLoad: Corrupt navigation data. Missing Approach Area (here).\n" ); error = NAV_CORRUPT_DATA; } m_approach[a].prev.area = TheNavMesh->GetNavAreaByID( m_approach[a].prev.id ); if (m_approach[a].prev.id && m_approach[a].prev.area == NULL) { Msg( "CNavArea::PostLoad: Corrupt navigation data. Missing Approach Area (prev).\n" ); error = NAV_CORRUPT_DATA; } m_approach[a].next.area = TheNavMesh->GetNavAreaByID( m_approach[a].next.id ); if (m_approach[a].next.id && m_approach[a].next.area == NULL) { Msg( "CNavArea::PostLoad: Corrupt navigation data. Missing Approach Area (next).\n" ); error = NAV_CORRUPT_DATA; } } return error; } void CCSNavArea::Draw( void ) const { CNavArea::Draw(); } void CCSNavArea::CustomAnalysis( bool isIncremental /*= false */ ) { ComputeApproachAreas(); } //-------------------------------------------------------------------------------------------------------------- // return danger decay rate per second float CCSNavArea::GetDangerDecayRate( void ) const { if ( CSGameRules()->IsPlayingGunGameTRBomb() ) { // decay danger faster in this aggressive bomb planting mode return 1.0f / 30.0f; } // one kill == 1.0, which we will forget about in two minutes return 1.0f / 120.0f; } float CCSNavArea::GetEarliestOccupyTime( int teamID ) const { if ( CSGameRules()->IsPlayingCoopMission() ) return 0.0f; return BaseClass::GetEarliestOccupyTime( teamID ); } void CCSNavArea::UpdateBlocked( bool force /*= false*/, int teamID /*= TEAM_ANY */ ) { if ( CSGameRules() && CSGameRules()->IsPlayingCoopMission() ) BaseClass::UpdateBlocked( force, teamID ); } bool CCSNavArea::IsBlocked( int teamID, bool ignoreNavBlockers /*= false */ ) const { return ( CSGameRules() && CSGameRules()->IsPlayingCoopMission() ) ? BaseClass::IsBlocked( teamID, ignoreNavBlockers ) : false; } //-------------------------------------------------------------------------------------------------------------- /** * Load legacy navigation area from the file */ NavErrorType CCSNavArea::LoadLegacy( CUtlBuffer &fileBuffer, unsigned int version, unsigned int subVersion ) { // load ID m_id = fileBuffer.GetUnsignedInt(); // update nextID to avoid collisions if (m_id >= m_nextID) m_nextID = m_id+1; // load attribute flags if ( version <= 8 ) { m_attributeFlags = fileBuffer.GetUnsignedChar(); } else if ( version < 13 ) { m_attributeFlags = fileBuffer.GetUnsignedShort(); } else { m_attributeFlags = fileBuffer.GetInt(); } // load extent of area fileBuffer.Get( &m_nwCorner, 3*sizeof(float) ); fileBuffer.Get( &m_seCorner, 3*sizeof(float) ); if ( ( m_seCorner.x - m_nwCorner.x ) > 0.0f && ( m_seCorner.y - m_nwCorner.y ) > 0.0f ) { m_invDxCorners = 1.0f / ( m_seCorner.x - m_nwCorner.x ); m_invDyCorners = 1.0f / ( m_seCorner.y - m_nwCorner.y ); } else { m_invDxCorners = m_invDyCorners = 0; DevWarning( "Degenerate Navigation Area #%d at setpos %g %g %g\n", m_id, m_nwCorner.x, m_nwCorner.y, m_nwCorner.z ); } // load heights of implicit corners m_neZ = fileBuffer.GetFloat(); m_swZ = fileBuffer.GetFloat(); CheckWaterLevel(); // load connections (IDs) to adjacent areas // in the enum order NORTH, EAST, SOUTH, WEST for( int d=0; dCreateHidingSpot(); spot->SetPosition( pos ); spot->SetFlags( HidingSpot::IN_COVER ); m_hidingSpots.AddToTail( spot ); } } else { // load HidingSpot objects for this area for( int h=0; hCreateHidingSpot(); spot->Load( fileBuffer, version ); m_hidingSpots.AddToTail( spot ); } } if ( version < 15 ) { // // Load number of approach areas // m_approachCount = fileBuffer.GetUnsignedChar(); // load approach area info (IDs) for( int a = 0; a < m_approachCount; ++a ) { m_approach[a].here.id = fileBuffer.GetUnsignedInt(); m_approach[a].prev.id = fileBuffer.GetUnsignedInt(); m_approach[a].prevToHereHow = (NavTraverseType)fileBuffer.GetUnsignedChar(); m_approach[a].next.id = fileBuffer.GetUnsignedInt(); m_approach[a].hereToNextHow = (NavTraverseType)fileBuffer.GetUnsignedChar(); } } // // Load encounter paths for this area // unsigned int count = fileBuffer.GetUnsignedInt(); if (version < 3) { // old data, read and discard for( unsigned int e=0; efrom.id = fileBuffer.GetUnsignedInt(); unsigned char dir = fileBuffer.GetUnsignedChar(); encounter->fromDir = static_cast( dir ); encounter->to.id = fileBuffer.GetUnsignedInt(); dir = fileBuffer.GetUnsignedChar(); encounter->toDir = static_cast( dir ); // read list of spots along this path unsigned char spotCount = fileBuffer.GetUnsignedChar(); SpotOrder order; for( int s=0; sspots.AddToTail( order ); } m_spotEncounters.AddToTail( encounter ); } if (version < 5) return NAV_OK; // // Load Place data // PlaceDirectory::IndexType entry = fileBuffer.GetUnsignedShort(); // convert entry to actual Place SetPlace( placeDirectory.IndexToPlace( entry ) ); if ( version < 7 ) return NAV_OK; // load ladder data for ( int dir=0; dirDetachFromHidingSpot(); }