├── CONTRIBUTING ├── LICENSE ├── README.md └── bots ├── bot.cpp ├── bot.h ├── bot_ai.cpp ├── bot_debug.cpp ├── bot_defs.h ├── bot_maker.cpp ├── bot_maker.h ├── bot_manager.cpp ├── bot_manager.h ├── bot_memory.cpp ├── bot_senses.cpp ├── bot_skill.cpp ├── bot_squad.cpp ├── bot_squad.h ├── bot_state.cpp ├── bot_utils.cpp ├── bot_utils.h ├── components ├── bot_component_attack.cpp ├── bot_component_decision.cpp ├── bot_component_follow.cpp ├── bot_component_locomotion.cpp ├── bot_component_memory.cpp ├── bot_component_vision.cpp └── bot_components.h ├── in_utils.cpp ├── in_utils.h ├── interfaces ├── ibot.h ├── ibotattack.h ├── ibotcomponent.h ├── ibotdecision.h ├── ibotfollow.h ├── ibotlocomotion.h ├── ibotmemory.h ├── ibotschedule.h ├── ibotvision.h └── improv.h ├── nav_path.cpp ├── nav_path.h ├── schedules ├── bot_schedule.cpp ├── bot_schedule_call_backup.cpp ├── bot_schedule_change_weapon.cpp ├── bot_schedule_cover.cpp ├── bot_schedule_defend_spawn.cpp ├── bot_schedule_help_dejected_friend.cpp ├── bot_schedule_hide_and_heal.cpp ├── bot_schedule_hide_and_reload.cpp ├── bot_schedule_hunt_enemy.cpp ├── bot_schedule_investigate_location.cpp ├── bot_schedule_move_aside.cpp ├── bot_schedule_reload.cpp └── bot_schedules.h ├── squad.cpp ├── squad.h ├── squad_manager.cpp └── squad_manager.h /CONTRIBUTING: -------------------------------------------------------------------------------- 1 | Thanks for your interest in the Source SDK 2013 project. When you make a 2 | contribution to the project (e.g. create an Issue or submit a Pull Request) 3 | (a "Contribution"), Valve wants to be able to use your Contribution to improve 4 | the SDK and other Valve products. 5 | 6 | As a condition of providing a Contribution, you agree that: 7 | - You grant Valve a non-exclusive, irrevocable, royalty-free, worldwide license 8 | to make, use, sell, reproduce, modify, distribute (directly and indirectly), 9 | and publicly display and perform the Contribution, and any derivative works 10 | that Valve may make from the Contribution, under any intellectual property you 11 | own or have the right to license. 12 | - You warrant and represent that the Contribution is your original creation, 13 | that you have the authority to grant this license to Valve, and that this 14 | license does not require the permission of any third party. Otherwise, you 15 | provide your Contribution "as is" without warranties. 16 | 17 | Should you wish to submit a suggestion or work that is not your original 18 | creation, you may submit it to Valve separate from any Contribution, 19 | explicitly identifying it as sourced from a third party, stating the details 20 | of its origin, and informing Valve of any license or other restriction of 21 | which you are personally aware. 22 | 23 | 24 | Valve is happy to accept pull requests and issues in the source-sdk-2013 25 | repository in these cases: 26 | * Changes that fix bugs in the SDK deployment process itself. The repository 27 | should build out of the box, and anything that prevents that is a pull 28 | request we want. 29 | * High priority bugs in HL2, the Episodes, or HL2MP that can be fixed in 30 | client.dll or server.dll. 31 | 32 | For other changes we suggest that you issue a pull request to one of these 33 | fine community-maintained repositories instead: 34 | https://developer.valvesoftware.com/wiki/Source-sdk-2013-community-repos 35 | 36 | If you are going to make a pull request, please keep them as granular as 37 | possible. Pull requests with 3-4 unrelated changes in them aren't going to 38 | be accepted. 39 | 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/sourcebots/72863dfb3924bfa9001b4e2c3b924f88c7ba46ea/LICENSE -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SourceBots 2 | 3 | SourceBots is an AI system to create Bots (CPU controlled players) for the Source Engine in a similar way to the NPC's AI. 4 | 5 | SouceBots can be implemented in: 6 | 7 | * [Source SDK 2013](https://github.com/ValveSoftware/source-sdk-2013) 8 | * [Alien Swarm branch](https://github.com/Sandern/aswscratch) 9 | 10 | > ⚠️ Although the code works, this code is part of the [first C++ project](https://github.com/kolessios/insource-legacy) of the developer and it has several optimization problems. Not suitable for production use. 11 | 12 | > ⚠️ This project is not actively under development but PR's are welcome. 13 | 14 | > 🌎 Most of the comments and debug messages are in Spanish. 15 | 16 | ## 🍕 Features 17 | 18 | - Create Bots and program their AI with a code similar to the [NPCs AI](https://developer.valvesoftware.com/wiki/AI_Programming_Overview). 19 | - [🔗](https://github.com/kolessios/sourcebots/blob/master/bots/schedules) Each set of tasks is separated into "schedules". 20 | - [🔗](https://github.com/kolessios/sourcebots/blob/master/bots/schedules/bot_schedule_hide_and_reload.cpp#L21) Each schedule executes [tasks](https://github.com/kolessios/sourcebots/blob/master/bots/bot_defs.h#L433) (actions to be performed by the Bot) from top to bottom. 21 | - [🔗](https://github.com/kolessios/sourcebots/blob/master/bots/schedules/bot_schedule_hide_and_reload.cpp#L34) Each schedule has interrupt conditions, the [conditions](https://github.com/kolessios/sourcebots/blob/master/bots/bot_defs.h#L597) are obtained in each frame according to the Bot status. 22 | - [🔗](https://github.com/kolessios/sourcebots/blob/master/bots/schedules/bot_schedule_hide_and_reload.cpp#L48) Each schedule has a level of desire. The Bot will start the schedule with the highest desire and will try to finish it (if no interruption condition occurs). 23 | - [🔗](https://github.com/kolessios/sourcebots/blob/master/bots/schedules/bot_schedule_hide_and_reload.cpp#L66) If necessary, you can add or modify the operation of the tasks in each schedule. 24 | - [🔗](https://github.com/kolessios/sourcebots/tree/master/bots/components) Movement, vision, memory and others are componentized. You can add or remove capabilities according to the type of Bot you want to create. 25 | - [🔗](https://github.com/kolessios/sourcebots/blob/master/bots/components/bot_component_locomotion.cpp#L111) Move to entities or vectors using the [Navigation mesh](https://developer.valvesoftware.com/wiki/Navigation_Meshes). 26 | - Aim to entities or vectors. 27 | - Detection of friends, enemies, neutral targets and objects such as weapons. 28 | - [🔗](https://github.com/kolessios/sourcebots/blob/master/bots/components/bot_component_decision.cpp#L746) Ability to prioritize enemies. 29 | - [🔗](https://github.com/kolessios/sourcebots/blob/master/bots/squad_manager.cpp) Create squads and make decisions respecitively. 30 | - [🔗](https://github.com/kolessios/sourcebots/blob/master/bots/bot_utils.cpp#L114) Hitbox detection and customization of the "preferred" hitbox when aiming. 31 | - [🔗](https://github.com/kolessios/sourcebots/blob/master/bots/components/bot_component_memory.cpp) Memory system to store information such as strings or numbers as well as positions of visible entities, including enemies and allies. 32 | - [🔗](https://github.com/kolessios/sourcebots/blob/master/bots/bot_skill.cpp) Easy configuration depending on the difficulty of the Bot. 33 | - [🔗](https://github.com/kolessios/sourcebots/blob/master/bots/bot_maker.cpp) Map entities to create Bots in events, highly customizable. 34 | 35 | ## 📖 How to start 36 | 37 | The [wiki](https://github.com/kolessios/sourcebots/wiki) has some help documents including installation and initial configuration. 38 | 39 | ## 🧪 TODO 40 | 41 | You can find all comments with the word [TODO](https://github.com/kolessios/sourcebots/search?q=TODO&type=Code), try to fix as many as you can! 42 | 43 | Some of them: 44 | 45 | - Optimization problems. 46 | - Detect and fix memory leaks. 47 | - Navigation problems. 48 | - Melee weapons 49 | - Doors 50 | - Make the code easier to read. 51 | - Add English comments. 52 | - Being able to use the AI in NPC's [(Like NextBot)](https://developer.valvesoftware.com/wiki/NextBot) 53 | 54 | ## 🎬 Videos 55 | 56 | You can watch this [YouTube playlist](https://youtu.be/W5N_w7dwxuw?list=PLOUVJcNedgYEfzMJvK8wiI9GzvLKRR2IW) to see examples of Bots and a bit of the history of the project's development. 57 | 58 | ## 📞 Contact 59 | 60 | You can contact me at: 61 | 62 | * [@kolessios](https://twitter.com/kolessios) 63 | * [Steam](http://steamcommunity.com/profiles/76561198040059089) 64 | * kolessios [at] gmail.com 65 | -------------------------------------------------------------------------------- /bots/bot.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/sourcebots/72863dfb3924bfa9001b4e2c3b924f88c7ba46ea/bots/bot.cpp -------------------------------------------------------------------------------- /bots/bot.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/sourcebots/72863dfb3924bfa9001b4e2c3b924f88c7ba46ea/bots/bot.h -------------------------------------------------------------------------------- /bots/bot_ai.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/sourcebots/72863dfb3924bfa9001b4e2c3b924f88c7ba46ea/bots/bot_ai.cpp -------------------------------------------------------------------------------- /bots/bot_debug.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/sourcebots/72863dfb3924bfa9001b4e2c3b924f88c7ba46ea/bots/bot_debug.cpp -------------------------------------------------------------------------------- /bots/bot_defs.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/sourcebots/72863dfb3924bfa9001b4e2c3b924f88c7ba46ea/bots/bot_defs.h -------------------------------------------------------------------------------- /bots/bot_maker.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/sourcebots/72863dfb3924bfa9001b4e2c3b924f88c7ba46ea/bots/bot_maker.cpp -------------------------------------------------------------------------------- /bots/bot_maker.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/sourcebots/72863dfb3924bfa9001b4e2c3b924f88c7ba46ea/bots/bot_maker.h -------------------------------------------------------------------------------- /bots/bot_manager.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/sourcebots/72863dfb3924bfa9001b4e2c3b924f88c7ba46ea/bots/bot_manager.cpp -------------------------------------------------------------------------------- /bots/bot_manager.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/sourcebots/72863dfb3924bfa9001b4e2c3b924f88c7ba46ea/bots/bot_manager.h -------------------------------------------------------------------------------- /bots/bot_memory.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/sourcebots/72863dfb3924bfa9001b4e2c3b924f88c7ba46ea/bots/bot_memory.cpp -------------------------------------------------------------------------------- /bots/bot_senses.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/sourcebots/72863dfb3924bfa9001b4e2c3b924f88c7ba46ea/bots/bot_senses.cpp -------------------------------------------------------------------------------- /bots/bot_skill.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/sourcebots/72863dfb3924bfa9001b4e2c3b924f88c7ba46ea/bots/bot_skill.cpp -------------------------------------------------------------------------------- /bots/bot_squad.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/sourcebots/72863dfb3924bfa9001b4e2c3b924f88c7ba46ea/bots/bot_squad.cpp -------------------------------------------------------------------------------- /bots/bot_squad.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/sourcebots/72863dfb3924bfa9001b4e2c3b924f88c7ba46ea/bots/bot_squad.h -------------------------------------------------------------------------------- /bots/bot_state.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/sourcebots/72863dfb3924bfa9001b4e2c3b924f88c7ba46ea/bots/bot_state.cpp -------------------------------------------------------------------------------- /bots/bot_utils.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/sourcebots/72863dfb3924bfa9001b4e2c3b924f88c7ba46ea/bots/bot_utils.cpp -------------------------------------------------------------------------------- /bots/bot_utils.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/sourcebots/72863dfb3924bfa9001b4e2c3b924f88c7ba46ea/bots/bot_utils.h -------------------------------------------------------------------------------- /bots/components/bot_component_attack.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/sourcebots/72863dfb3924bfa9001b4e2c3b924f88c7ba46ea/bots/components/bot_component_attack.cpp -------------------------------------------------------------------------------- /bots/components/bot_component_decision.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/sourcebots/72863dfb3924bfa9001b4e2c3b924f88c7ba46ea/bots/components/bot_component_decision.cpp -------------------------------------------------------------------------------- /bots/components/bot_component_follow.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/sourcebots/72863dfb3924bfa9001b4e2c3b924f88c7ba46ea/bots/components/bot_component_follow.cpp -------------------------------------------------------------------------------- /bots/components/bot_component_locomotion.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/sourcebots/72863dfb3924bfa9001b4e2c3b924f88c7ba46ea/bots/components/bot_component_locomotion.cpp -------------------------------------------------------------------------------- /bots/components/bot_component_memory.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/sourcebots/72863dfb3924bfa9001b4e2c3b924f88c7ba46ea/bots/components/bot_component_memory.cpp -------------------------------------------------------------------------------- /bots/components/bot_component_vision.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/sourcebots/72863dfb3924bfa9001b4e2c3b924f88c7ba46ea/bots/components/bot_component_vision.cpp -------------------------------------------------------------------------------- /bots/components/bot_components.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/sourcebots/72863dfb3924bfa9001b4e2c3b924f88c7ba46ea/bots/components/bot_components.h -------------------------------------------------------------------------------- /bots/in_utils.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/sourcebots/72863dfb3924bfa9001b4e2c3b924f88c7ba46ea/bots/in_utils.cpp -------------------------------------------------------------------------------- /bots/in_utils.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/sourcebots/72863dfb3924bfa9001b4e2c3b924f88c7ba46ea/bots/in_utils.h -------------------------------------------------------------------------------- /bots/interfaces/ibot.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/sourcebots/72863dfb3924bfa9001b4e2c3b924f88c7ba46ea/bots/interfaces/ibot.h -------------------------------------------------------------------------------- /bots/interfaces/ibotattack.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/sourcebots/72863dfb3924bfa9001b4e2c3b924f88c7ba46ea/bots/interfaces/ibotattack.h -------------------------------------------------------------------------------- /bots/interfaces/ibotcomponent.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/sourcebots/72863dfb3924bfa9001b4e2c3b924f88c7ba46ea/bots/interfaces/ibotcomponent.h -------------------------------------------------------------------------------- /bots/interfaces/ibotdecision.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/sourcebots/72863dfb3924bfa9001b4e2c3b924f88c7ba46ea/bots/interfaces/ibotdecision.h -------------------------------------------------------------------------------- /bots/interfaces/ibotfollow.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/sourcebots/72863dfb3924bfa9001b4e2c3b924f88c7ba46ea/bots/interfaces/ibotfollow.h -------------------------------------------------------------------------------- /bots/interfaces/ibotlocomotion.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/sourcebots/72863dfb3924bfa9001b4e2c3b924f88c7ba46ea/bots/interfaces/ibotlocomotion.h -------------------------------------------------------------------------------- /bots/interfaces/ibotmemory.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/sourcebots/72863dfb3924bfa9001b4e2c3b924f88c7ba46ea/bots/interfaces/ibotmemory.h -------------------------------------------------------------------------------- /bots/interfaces/ibotschedule.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/sourcebots/72863dfb3924bfa9001b4e2c3b924f88c7ba46ea/bots/interfaces/ibotschedule.h -------------------------------------------------------------------------------- /bots/interfaces/ibotvision.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/sourcebots/72863dfb3924bfa9001b4e2c3b924f88c7ba46ea/bots/interfaces/ibotvision.h -------------------------------------------------------------------------------- /bots/interfaces/improv.h: -------------------------------------------------------------------------------- 1 | // improv.h 2 | // Improv interface 3 | // Author: Michael S. Booth (mike@turtlerockstudios.com), November 2003 4 | // https://github.com/ValveSoftware/halflife/tree/master/game_shared/bot 5 | // Ported to Source from the HL1 SDK with adjustments for SourceBots by Bitl 6 | 7 | #ifndef _IMPROV_H_ 8 | #define _IMPROV_H_ 9 | 10 | #include "nav_path.h" 11 | 12 | class CBaseEntity; 13 | 14 | 15 | //-------------------------------------------------------------------------------------------------------- 16 | /** 17 | * Improv-specific events 18 | */ 19 | class IImprovEvent 20 | { 21 | public: 22 | virtual void OnMoveToSuccess( const Vector &goal ) { } ///< invoked when an improv reaches its MoveTo goal 23 | 24 | enum MoveToFailureType 25 | { 26 | FAIL_INVALID_PATH, 27 | FAIL_STUCK, 28 | FAIL_FELL_OFF, 29 | }; 30 | virtual void OnMoveToFailure( const Vector &goal, MoveToFailureType reason ) { } ///< invoked when an improv fails to reach a MoveTo goal 31 | 32 | //virtual void OnInjury( float amount ) { } ///< invoked when the improv is injured 33 | }; 34 | 35 | //-------------------------------------------------------------------------------------------------------- 36 | /** 37 | * The Improv interface definition 38 | * 39 | * An "Improv" is an improvisational actor that simulates the 40 | * behavor of a human in an unscripted, "make it up as you go" manner. 41 | * 42 | * Bitl: 43 | * Changed to reflect the features of CImprovLocomotor, which CSS uses. 44 | * Since there are some similar functions from HL1/CS 1.6, it's easy to comment out the majority of these functions for the ones we need. 45 | */ 46 | class CImprov : public IImprovEvent 47 | { 48 | public: 49 | //virtual ~CImprov() { } 50 | 51 | //virtual bool IsAlive( void ) const = 0; ///< return true if this improv is alive 52 | 53 | //virtual void MoveTo( const Vector &goal ) = 0; ///< move improv towards far-away goal (pathfind) 54 | //virtual void LookAt( const Vector &target ) = 0; ///< define desired view target 55 | //virtual void ClearLookAt( void ) = 0; ///< remove view goal 56 | //virtual void FaceTo( const Vector &goal ) = 0; ///< orient body towards goal 57 | //virtual void ClearFaceTo( void ) = 0; ///< remove body orientation goal 58 | 59 | //virtual bool IsAtMoveGoal( float error = 20.0f ) const = 0; ///< return true if improv is standing on its movement goal 60 | //virtual bool HasLookAt( void ) const = 0; ///< return true if improv has a look at goal 61 | //virtual bool HasFaceTo( void ) const = 0; ///< return true if improv has a face to goal 62 | //virtual bool IsAtFaceGoal( void ) const = 0; ///< return true if improv is facing towards its face goal 63 | //virtual bool IsFriendInTheWay( const Vector &goalPos ) const = 0; ///< return true if a friend is blocking our line to the given goal position 64 | //virtual bool IsFriendInTheWay( CBaseEntity *myFriend, const Vector &goalPos ) const = 0; ///< return true if the given friend is blocking our line to the given goal position 65 | 66 | //virtual void MoveForward( void ) = 0; 67 | //virtual void MoveBackward( void ) = 0; 68 | //virtual void StrafeLeft( void ) = 0; 69 | //virtual void StrafeRight( void ) = 0; 70 | virtual void Jump( void ) = 0; 71 | virtual void Crouch( void ) = 0; 72 | virtual void StandUp( void ) = 0; ///< "un-crouch" 73 | 74 | virtual void TrackPath( const Vector &pathGoal, float deltaT ) = 0; ///< move along path by following "pathGoal" 75 | 76 | virtual void StartLadder( const CNavLadder *ladder, NavTraverseType how, const Vector &approachPos, const Vector &departPos ) = 0; ///< invoked when a ladder is encountered while following a path 77 | virtual bool TraverseLadder( const CNavLadder *ladder, NavTraverseType how, const Vector &approachPos, const Vector &departPos, float deltaT ) = 0; ///< traverse given ladder 78 | 79 | virtual bool GetSimpleGroundHeightWithFloor( const Vector &pos, float *height, Vector *normal = NULL ) = 0; ///< find "simple" ground height, treating current nav area as part of the floor 80 | 81 | virtual void Run( void ) = 0; 82 | virtual void Walk( void ) = 0; 83 | //virtual void Sneak(void) = 0; 84 | //virtual void Stop( void ) = 0; 85 | 86 | virtual float GetMoveAngle( void ) const = 0; ///< return direction of movement 87 | //virtual float GetFaceAngle( void ) const = 0; ///< return direction of view 88 | 89 | virtual const Vector &GetFeet( void ) const = 0; ///< return position of "feet" - point below centroid of improv at feet level 90 | virtual const Vector &GetCentroid( void ) const = 0; 91 | virtual const Vector &GetEyes( void ) const = 0; 92 | 93 | virtual bool IsRunning( void ) const = 0; 94 | //virtual bool IsWalking( void ) const = 0; 95 | //virtual bool IsSneaking(void) const = 0; 96 | //virtual bool IsStopped( void ) const = 0; 97 | 98 | virtual bool IsCrouching( void ) const = 0; 99 | virtual bool IsJumping( void ) const = 0; 100 | virtual bool IsUsingLadder( void ) const = 0; 101 | //virtual bool IsOnGround( void ) const = 0; 102 | //virtual bool IsMoving( void ) const = 0; ///< if true, improv is walking, crawling, running somewhere 103 | 104 | //virtual bool CanRun( void ) const = 0; 105 | //virtual bool CanCrouch( void ) const = 0; 106 | //virtual bool CanJump( void ) const = 0; 107 | 108 | //#define CHECK_FOV true 109 | //virtual bool IsVisible( const Vector &pos, bool testFOV = false ) const = 0; ///< return true if improv can see position 110 | 111 | //virtual bool IsPlayerLookingAtMe( CBasePlayer *other, float cosTolerance = 0.95f ) const = 0; ///< return true if 'other' is looking right at me 112 | //virtual CBasePlayer *IsAnyPlayerLookingAtMe( int team = 0, float cosTolerance = 0.95f ) const = 0; ///< return player on given team that is looking right at me (team == 0 means any team), NULL otherwise 113 | 114 | //virtual CBasePlayer *GetClosestPlayerByTravelDistance( int team = 0, float *range = NULL ) const = 0; ///< return actual travel distance to closest player on given team (team == 0 means any team) 115 | 116 | virtual CNavArea *GetLastKnownArea( void ) const = 0; 117 | 118 | //virtual void OnUpdate( float deltaT ) = 0; ///< a less frequent, full update 'tick' 119 | //virtual void OnUpkeep( float deltaT ) = 0; ///< a frequent, lightweight update 'tick' 120 | //virtual void OnReset( void ) = 0; ///< reset improv to initial state 121 | //virtual void OnGameEvent( GameEventType event, CBaseEntity *entity, CBaseEntity *other ) = 0; ///< invoked when an event occurs in the game 122 | //virtual void OnTouch( CBaseEntity *other ) = 0; ///< "other" has touched us 123 | }; 124 | 125 | 126 | #endif // _IMPROV_H_ 127 | -------------------------------------------------------------------------------- /bots/nav_path.cpp: -------------------------------------------------------------------------------- 1 | // nav_path.cpp 2 | // Encapsulation of a path through space 3 | // Author: Michael S. Booth (mike@turtlerockstudios.com), November 2003 4 | // https://github.com/ValveSoftware/halflife/tree/master/game_shared/bot 5 | // Ported to Source from the HL1 SDK with adjustments for SourceBots by Bitl 6 | 7 | #include "cbase.h" 8 | 9 | #include "nav_mesh.h" 10 | #include "nav_path.h" 11 | #include "bots/interfaces/improv.h" 12 | // memdbgon must be the last include file in a .cpp file!!! 13 | #include "tier0/memdbgon.h" 14 | 15 | #ifdef _WIN32 16 | #pragma warning (disable:4701) 17 | #endif 18 | 19 | //-------------------------------------------------------------------------------------------------------------- 20 | /** 21 | * Determine actual path positions 22 | */ 23 | bool CNavPath::ComputePathPositions( const Vector &start ) 24 | { 25 | if (m_segmentCount == 0) 26 | return false; 27 | 28 | // start in first area's center 29 | m_path[0].pos = start; 30 | m_path[0].ladder = NULL; 31 | m_path[0].how = NUM_TRAVERSE_TYPES; 32 | 33 | for( int i=1; ihow <= GO_WEST) // walk along the floor to the next area 39 | { 40 | to->ladder = NULL; 41 | 42 | // compute next point, keeping path as straight as possible 43 | from->area->ComputeClosestPointInPortal( to->area, (NavDirType)to->how, from->pos, &to->pos ); 44 | 45 | // move goal position into the goal area a bit 46 | const float stepInDist = 5.0f; // how far to "step into" an area - must be less than min area size 47 | AddDirectionVector( &to->pos, (NavDirType)to->how, stepInDist ); 48 | 49 | // we need to walk out of "from" area, so keep Z where we can reach it 50 | to->pos.z = from->area->GetZ( to->pos ); 51 | 52 | // if this is a "jump down" connection, we must insert an additional point on the path 53 | if (to->area->IsConnected( from->area, NUM_DIRECTIONS ) == false) 54 | { 55 | // this is a "jump down" link 56 | 57 | // compute direction of path just prior to "jump down" 58 | Vector2D dir; 59 | DirectionToVector2D( (NavDirType)to->how, &dir ); 60 | 61 | // shift top of "jump down" out a bit to "get over the ledge" 62 | const float pushDist = 25.0f; 63 | to->pos.x += pushDist * dir.x; 64 | to->pos.y += pushDist * dir.y; 65 | 66 | // insert a duplicate node to represent the bottom of the fall 67 | if (m_segmentCount < MAX_PATH_SEGMENTS-1) 68 | { 69 | // copy nodes down 70 | for( int j=m_segmentCount; j>i; --j ) 71 | m_path[j] = m_path[j-1]; 72 | 73 | // path is one node longer 74 | ++m_segmentCount; 75 | 76 | // move index ahead into the new node we just duplicated 77 | ++i; 78 | 79 | m_path[i].pos.x = to->pos.x + pushDist * dir.x; 80 | m_path[i].pos.y = to->pos.y + pushDist * dir.y; 81 | 82 | // put this one at the bottom of the fall 83 | m_path[i].pos.z = to->area->GetZ( m_path[i].pos ); 84 | } 85 | } 86 | } 87 | else if (to->how == GO_LADDER_UP) // to get to next area, must go up a ladder 88 | { 89 | // find our ladder 90 | const NavLadderConnectVector *list = from->area->GetLadders( CNavLadder::LADDER_UP ); 91 | int it; 92 | for( it = 0; it < list->Count(); ++it ) 93 | { 94 | CNavLadder *ladder = (*list)[ it ].ladder; 95 | 96 | // can't use "behind" area when ascending... 97 | if (ladder->m_topForwardArea == to->area || 98 | ladder->m_topLeftArea == to->area || 99 | ladder->m_topRightArea == to->area) 100 | { 101 | to->ladder = ladder; 102 | to->pos = ladder->m_bottom + ladder->GetNormal() * 2.0f * HalfHumanWidth; 103 | break; 104 | } 105 | } 106 | 107 | if (it == list->InvalidIndex()) 108 | { 109 | //PrintIfWatched( "ERROR: Can't find ladder in path\n" ); 110 | return false; 111 | } 112 | } 113 | else if (to->how == GO_LADDER_DOWN) // to get to next area, must go down a ladder 114 | { 115 | // find our ladder 116 | const NavLadderConnectVector *list = from->area->GetLadders( CNavLadder::LADDER_DOWN ); 117 | int it; 118 | for( it = 0; it < list->Count(); ++it ) 119 | { 120 | CNavLadder *ladder = (*list)[ it ].ladder; 121 | 122 | if (ladder->m_bottomArea == to->area) 123 | { 124 | to->ladder = ladder; 125 | to->pos = ladder->m_top; 126 | to->pos = ladder->m_top - ladder->GetNormal() * 2.0f * HalfHumanWidth; 127 | break; 128 | } 129 | } 130 | 131 | if (it == list->InvalidIndex()) 132 | { 133 | //PrintIfWatched( "ERROR: Can't find ladder in path\n" ); 134 | return false; 135 | } 136 | } 137 | } 138 | 139 | return true; 140 | } 141 | 142 | //-------------------------------------------------------------------------------------------------------------- 143 | /** 144 | * Return true if position is at the end of the path 145 | */ 146 | bool CNavPath::IsAtEnd( const Vector &pos ) const 147 | { 148 | if (!IsValid()) 149 | return false; 150 | 151 | const float epsilon = 20.0f; 152 | return (pos - GetEndpoint()).IsLengthLessThan( epsilon ); 153 | } 154 | 155 | //-------------------------------------------------------------------------------------------------------------- 156 | /** 157 | * Return length of path from start to finish 158 | */ 159 | float CNavPath::GetLength( void ) const 160 | { 161 | float length = 0.0f; 162 | for( int i=1; i= distAlong) 195 | { 196 | // desired point is on this segment of the path 197 | float delta = distAlong - lengthSoFar; 198 | float t = delta / segmentLength; 199 | 200 | *pointOnPath = m_path[i].pos + t * dir; 201 | 202 | return true; 203 | } 204 | 205 | lengthSoFar += segmentLength; 206 | } 207 | 208 | *pointOnPath = m_path[ GetSegmentCount()-1 ].pos; 209 | return true; 210 | } 211 | 212 | //-------------------------------------------------------------------------------------------------------------- 213 | /** 214 | * Return the node index closest to the given distance along the path without going over - returns (-1) if error 215 | */ 216 | int CNavPath::GetSegmentIndexAlongPath( float distAlong ) const 217 | { 218 | if (!IsValid()) 219 | return -1; 220 | 221 | if (distAlong <= 0.0f) 222 | { 223 | return 0; 224 | } 225 | 226 | float lengthSoFar = 0.0f; 227 | Vector dir; 228 | for( int i=1; i distAlong) 233 | { 234 | return i-1; 235 | } 236 | } 237 | 238 | return GetSegmentCount()-1; 239 | } 240 | 241 | 242 | 243 | //-------------------------------------------------------------------------------------------------------------- 244 | /** 245 | * Compute closest point on path to given point 246 | * NOTE: This does not do line-of-sight tests, so closest point may be thru the floor, etc 247 | */ 248 | bool CNavPath::FindClosestPointOnPath( const Vector *worldPos, int startIndex, int endIndex, Vector *close ) const 249 | { 250 | if (!IsValid() || close == NULL) 251 | return false; 252 | 253 | Vector along, toWorldPos; 254 | Vector pos; 255 | const Vector *from, *to; 256 | float length; 257 | float closeLength; 258 | float closeDistSq = 9999999999.9; 259 | float distSq; 260 | 261 | for( int i=startIndex; i<=endIndex; ++i ) 262 | { 263 | from = &m_path[i-1].pos; 264 | to = &m_path[i].pos; 265 | 266 | // compute ray along this path segment 267 | along = *to - *from; 268 | 269 | // make it a unit vector along the path 270 | length = along.NormalizeInPlace(); 271 | 272 | // compute vector from start of segment to our point 273 | toWorldPos = *worldPos - *from; 274 | 275 | // find distance of closest point on ray 276 | closeLength = DotProduct( toWorldPos, along ); 277 | 278 | // constrain point to be on path segment 279 | if (closeLength <= 0.0f) 280 | pos = *from; 281 | else if (closeLength >= length) 282 | pos = *to; 283 | else 284 | pos = *from + closeLength * along; 285 | 286 | distSq = (pos - *worldPos).LengthSqr(); 287 | 288 | // keep the closest point so far 289 | if (distSq < closeDistSq) 290 | { 291 | closeDistSq = distSq; 292 | *close = pos; 293 | } 294 | } 295 | 296 | return true; 297 | } 298 | 299 | //-------------------------------------------------------------------------------------------------------------- 300 | /** 301 | * Build trivial path when start and goal are in the same nav area 302 | */ 303 | bool CNavPath::BuildTrivialPath( const Vector &start, const Vector &goal ) 304 | { 305 | m_segmentCount = 0; 306 | 307 | CNavArea *startArea = TheNavMesh->GetNearestNavArea( start ); 308 | if (startArea == NULL) 309 | return false; 310 | 311 | CNavArea *goalArea = TheNavMesh->GetNearestNavArea( goal ); 312 | if (goalArea == NULL) 313 | return false; 314 | 315 | m_segmentCount = 2; 316 | 317 | m_path[0].area = startArea; 318 | m_path[0].pos.x = start.x; 319 | m_path[0].pos.y = start.y; 320 | m_path[0].pos.z = startArea->GetZ( start ); 321 | m_path[0].ladder = NULL; 322 | m_path[0].how = NUM_TRAVERSE_TYPES; 323 | 324 | m_path[1].area = goalArea; 325 | m_path[1].pos.x = goal.x; 326 | m_path[1].pos.y = goal.y; 327 | m_path[1].pos.z = goalArea->GetZ( goal ); 328 | m_path[1].ladder = NULL; 329 | m_path[1].how = NUM_TRAVERSE_TYPES; 330 | 331 | return true; 332 | } 333 | 334 | //-------------------------------------------------------------------------------------------------------------- 335 | /** 336 | * Draw the path for debugging. 337 | */ 338 | void CNavPath::Draw( void ) 339 | { 340 | if (!IsValid()) 341 | return; 342 | 343 | for( int i=1; i anchor) 410 | { 411 | // remove redundant nodes between anchor and nextAnchor 412 | int removeCount = nextAnchor - anchor - 1; 413 | if (removeCount > 0) 414 | { 415 | for( int i=nextAnchor; iIsValid() == false) 460 | return; 461 | 462 | const CNavPath::PathSegment *node = (*m_path)[ m_segmentIndex ]; 463 | 464 | if (node == NULL) 465 | { 466 | m_improv->OnMoveToFailure( m_path->GetEndpoint(), IImprovEvent::FAIL_INVALID_PATH ); 467 | m_path->Invalidate(); 468 | return; 469 | } 470 | 471 | // handle ladders 472 | if (node->ladder) 473 | { 474 | const Vector *approachPos = NULL; 475 | const Vector *departPos = NULL; 476 | 477 | if (m_segmentIndex) 478 | approachPos = &(*m_path)[ m_segmentIndex-1 ]->pos; 479 | 480 | if (m_segmentIndex < m_path->GetSegmentCount()-1) 481 | departPos = &(*m_path)[ m_segmentIndex+1 ]->pos; 482 | 483 | if (!m_isLadderStarted) 484 | { 485 | // set up ladder movement 486 | m_improv->StartLadder( node->ladder, node->how, *approachPos, *departPos ); 487 | m_isLadderStarted = true; 488 | } 489 | 490 | // move improv along ladder 491 | if (m_improv->TraverseLadder( node->ladder, node->how, *approachPos, *departPos, deltaT )) 492 | { 493 | // completed ladder 494 | ++m_segmentIndex; 495 | } 496 | return; 497 | } 498 | 499 | // reset ladder init flag 500 | m_isLadderStarted = false; 501 | 502 | // 503 | // Check if we reached the end of the path 504 | // 505 | const float closeRange = 20.0f; 506 | if ((m_improv->GetFeet() - node->pos).IsLengthLessThan( closeRange )) 507 | { 508 | ++m_segmentIndex; 509 | 510 | if (m_segmentIndex >= m_path->GetSegmentCount()) 511 | { 512 | m_improv->OnMoveToSuccess( m_path->GetEndpoint() ); 513 | m_path->Invalidate(); 514 | return; 515 | } 516 | } 517 | 518 | 519 | m_goal = node->pos; 520 | 521 | const float aheadRange = 300.0f; 522 | m_segmentIndex = FindPathPoint( aheadRange, &m_goal, &m_behindIndex ); 523 | if (m_segmentIndex >= m_path->GetSegmentCount()) 524 | m_segmentIndex = m_path->GetSegmentCount()-1; 525 | 526 | 527 | bool isApproachingJumpArea = false; 528 | 529 | // 530 | // Crouching 531 | // 532 | if (!m_improv->IsUsingLadder()) 533 | { 534 | // because hostage crouching is not really supported by the engine, 535 | // if we are standing in a crouch area, we must crouch to avoid collisions 536 | if (m_improv->GetLastKnownArea() && 537 | m_improv->GetLastKnownArea()->GetAttributes() & NAV_MESH_CROUCH && 538 | !(m_improv->GetLastKnownArea()->GetAttributes() & NAV_MESH_JUMP)) 539 | { 540 | m_improv->Crouch(); 541 | } 542 | 543 | // if we are approaching a crouch area, crouch 544 | // if there are no crouch areas coming up, stand 545 | const float crouchRange = 50.0f; 546 | bool didCrouch = false; 547 | for( int i=m_segmentIndex; iGetSegmentCount(); ++i ) 548 | { 549 | const CNavArea *to = (*m_path)[i]->area; 550 | 551 | // if there is a jump area on the way to the crouch area, don't crouch as it messes up the jump 552 | if (to->GetAttributes() & NAV_MESH_JUMP) 553 | { 554 | isApproachingJumpArea = true; 555 | break; 556 | } 557 | 558 | Vector close; 559 | to->GetClosestPointOnArea( m_improv->GetCentroid(), &close ); 560 | 561 | if ((close - m_improv->GetFeet()).AsVector2D().IsLengthGreaterThan( crouchRange )) 562 | break; 563 | 564 | if (to->GetAttributes() & NAV_MESH_CROUCH) 565 | { 566 | m_improv->Crouch(); 567 | didCrouch = true; 568 | break; 569 | } 570 | 571 | } 572 | 573 | if (!didCrouch && !m_improv->IsJumping()) 574 | { 575 | // no crouch areas coming up 576 | m_improv->StandUp(); 577 | } 578 | 579 | } // end crouching logic 580 | 581 | 582 | if (m_isDebug) 583 | { 584 | m_path->Draw(); 585 | NDebugOverlay::Line( m_improv->GetCentroid(), m_goal + Vector( 0, 0, StepHeight ), 255, 0, 255, true, 0.1f ); 586 | //UTIL_DrawBeamPoints( m_goal + Vector( 0, 0, StepHeight ), m_improv->GetCentroid(), 1, 255, 0, 255 ); 587 | } 588 | 589 | // check if improv becomes stuck 590 | m_stuckMonitor.Update( m_improv ); 591 | 592 | 593 | // if improv has been stuck for too long, give up 594 | const float giveUpTime = 4.0f; 595 | if (m_stuckMonitor.GetDuration() > giveUpTime) 596 | { 597 | m_improv->OnMoveToFailure( m_path->GetEndpoint(), IImprovEvent::FAIL_STUCK ); 598 | m_path->Invalidate(); 599 | return; 600 | } 601 | 602 | 603 | // if our goal is high above us, we must have fallen 604 | if (m_goal.z - m_improv->GetFeet().z > JumpCrouchHeight) 605 | { 606 | m_improv->OnMoveToFailure( m_path->GetEndpoint(), IImprovEvent::FAIL_FELL_OFF ); 607 | m_path->Invalidate(); 608 | /*const float closeRange = 75.0f; 609 | Vector2D to( m_improv->GetFeet().x - m_goal.x, m_improv->GetFeet().y - m_goal.y ); 610 | if (to.IsLengthLessThan( closeRange )) 611 | { 612 | // we can't reach the goal position 613 | // check if we can reach the next node, in case this was a "jump down" situation 614 | const CNavPath::PathSegment *nextNode = (*m_path)[ m_behindIndex+1 ]; 615 | if (m_behindIndex >=0 && nextNode) 616 | { 617 | if (nextNode->pos.z - m_improv->GetFeet().z > JumpCrouchHeight) 618 | { 619 | // the next node is too high, too - we really did fall of the path 620 | m_improv->OnMoveToFailure( m_path->GetEndpoint(), IImprovEvent::FAIL_FELL_OFF ); 621 | m_path->Invalidate(); 622 | return; 623 | } 624 | } 625 | else 626 | { 627 | // fell trying to get to the last node in the path 628 | m_improv->OnMoveToFailure( m_path->GetEndpoint(), IImprovEvent::FAIL_FELL_OFF ); 629 | m_path->Invalidate(); 630 | return; 631 | } 632 | }*/ 633 | } 634 | 635 | 636 | // avoid small obstacles 637 | if (avoidObstacles && !isApproachingJumpArea && !m_improv->IsJumping() /*&& m_segmentIndex < m_path->GetSegmentCount()-1*/) 638 | { 639 | FeelerReflexAdjustment( &m_goal ); 640 | 641 | // currently, this is only used for hostages, and their collision physics stinks 642 | // do more feeler checks to avoid short obstacles 643 | /* 644 | const float inc = 0.25f; 645 | for( float t = 0.5f; t < 1.0f; t += inc ) 646 | { 647 | FeelerReflexAdjustment( &m_goal, t * StepHeight ); 648 | } 649 | */ 650 | 651 | } 652 | 653 | // move improv along path 654 | m_improv->TrackPath( m_goal, deltaT ); 655 | } 656 | 657 | //-------------------------------------------------------------------------------------------------------------- 658 | /** 659 | * Return the closest point to our current position on our current path 660 | * If "local" is true, only check the portion of the path surrounding m_pathIndex. 661 | */ 662 | int CNavPathFollower::FindOurPositionOnPath( Vector *close, bool local ) const 663 | { 664 | if (!m_path->IsValid()) 665 | return -1; 666 | 667 | Vector along, toFeet; 668 | Vector feet = m_improv->GetFeet(); 669 | Vector eyes = m_improv->GetEyes(); 670 | Vector pos; 671 | const Vector *from, *to; 672 | float length; 673 | float closeLength; 674 | float closeDistSq = 9999999999.9; 675 | int closeIndex = -1; 676 | float distSq; 677 | 678 | int start, end; 679 | 680 | if (local) 681 | { 682 | start = m_segmentIndex - 3; 683 | if (start < 1) 684 | start = 1; 685 | 686 | end = m_segmentIndex + 3; 687 | if (end > m_path->GetSegmentCount()) 688 | end = m_path->GetSegmentCount(); 689 | } 690 | else 691 | { 692 | start = 1; 693 | end = m_path->GetSegmentCount(); 694 | } 695 | 696 | for( int i=start; ipos; 699 | to = &(*m_path)[i]->pos; 700 | 701 | // compute ray along this path segment 702 | along = *to - *from; 703 | 704 | // make it a unit vector along the path 705 | length = along.NormalizeInPlace(); 706 | 707 | // compute vector from start of segment to our point 708 | toFeet = feet - *from; 709 | 710 | // find distance of closest point on ray 711 | closeLength = DotProduct( toFeet, along ); 712 | 713 | // constrain point to be on path segment 714 | if (closeLength <= 0.0f) 715 | pos = *from; 716 | else if (closeLength >= length) 717 | pos = *to; 718 | else 719 | pos = *from + closeLength * along; 720 | 721 | distSq = (pos - feet).LengthSqr(); 722 | 723 | // keep the closest point so far 724 | if (distSq < closeDistSq) 725 | { 726 | // don't use points we cant see 727 | Vector probe = pos + Vector( 0, 0, HalfHumanHeight ); 728 | if (!IsWalkableTraceLineClear( eyes, probe, WALK_THRU_DOORS | WALK_THRU_BREAKABLES )) 729 | continue; 730 | 731 | // don't use points we cant reach 732 | //if (!IsStraightLinePathWalkable( &pos )) 733 | // continue; 734 | 735 | closeDistSq = distSq; 736 | if (close) 737 | *close = pos; 738 | closeIndex = i-1; 739 | } 740 | } 741 | 742 | return closeIndex; 743 | } 744 | 745 | //-------------------------------------------------------------------------------------------------------------- 746 | /** 747 | * Compute a point a fixed distance ahead along our path. 748 | * Returns path index just after point. 749 | */ 750 | int CNavPathFollower::FindPathPoint( float aheadRange, Vector *point, int *prevIndex ) 751 | { 752 | // find path index just past aheadRange 753 | int afterIndex; 754 | 755 | // finds the closest point on local area of path, and returns the path index just prior to it 756 | Vector close; 757 | int startIndex = FindOurPositionOnPath( &close, false ); 758 | 759 | if (prevIndex) 760 | *prevIndex = startIndex; 761 | 762 | if (startIndex <= 0) 763 | { 764 | // went off the end of the path 765 | // or next point in path is unwalkable (ie: jump-down) 766 | // keep same point 767 | return m_segmentIndex; 768 | } 769 | 770 | // if we are crouching, just follow the path exactly 771 | if (m_improv->IsCrouching() || m_bShouldFollowPathExactly) 772 | { 773 | // we want to move to the immediately next point along the path from where we are now 774 | int index = startIndex+1; 775 | if (index >= m_path->GetSegmentCount()) 776 | index = m_path->GetSegmentCount()-1; 777 | 778 | *point = (*m_path)[ index ]->pos; 779 | 780 | // if we are very close to the next point in the path, skip ahead to the next one to avoid wiggling 781 | // we must do a 2D check here, in case the goal point is floating in space due to jump down, etc 782 | const float closeEpsilon = 20.0f; // 10 783 | while ((*point - close).AsVector2D().IsLengthLessThan( closeEpsilon )) 784 | { 785 | ++index; 786 | 787 | if (index >= m_path->GetSegmentCount()) 788 | { 789 | index = m_path->GetSegmentCount()-1; 790 | break; 791 | } 792 | 793 | *point = (*m_path)[ index ]->pos; 794 | } 795 | 796 | return index; 797 | } 798 | 799 | // make sure we use a node a minimum distance ahead of us, to avoid wiggling 800 | while (startIndex < m_path->GetSegmentCount()-1) 801 | { 802 | Vector pos = (*m_path)[ startIndex+1 ]->pos; 803 | 804 | // we must do a 2D check here, in case the goal point is floating in space due to jump down, etc 805 | const float closeEpsilon = 20.0f; 806 | if ((pos - close).AsVector2D().IsLengthLessThan( closeEpsilon )) 807 | { 808 | ++startIndex; 809 | } 810 | else 811 | { 812 | break; 813 | } 814 | } 815 | 816 | // if we hit a ladder or jump area, must stop (dont use ladder behind us) 817 | if (startIndex > m_segmentIndex && startIndex < m_path->GetSegmentCount() && 818 | ((*m_path)[ startIndex ]->ladder || (*m_path)[ startIndex ]->area->GetAttributes() & NAV_MESH_JUMP)) 819 | { 820 | *point = (*m_path)[ startIndex ]->pos; 821 | return startIndex; 822 | } 823 | 824 | // we need the point just *ahead* of us 825 | ++startIndex; 826 | if (startIndex >= m_path->GetSegmentCount()) 827 | startIndex = m_path->GetSegmentCount()-1; 828 | 829 | // if we hit a ladder or jump area, must stop 830 | if (startIndex < m_path->GetSegmentCount() && 831 | ((*m_path)[ startIndex ]->ladder || (*m_path)[ startIndex ]->area->GetAttributes() & NAV_MESH_JUMP)) 832 | { 833 | *point = (*m_path)[ startIndex ]->pos; 834 | return startIndex; 835 | } 836 | 837 | // note direction of path segment we are standing on 838 | Vector initDir = (*m_path)[ startIndex ]->pos - (*m_path)[ startIndex-1 ]->pos; 839 | initDir.NormalizeInPlace(); 840 | 841 | Vector feet = m_improv->GetFeet(); 842 | Vector eyes = m_improv->GetEyes(); 843 | float rangeSoFar = 0; 844 | 845 | // this flag is true if our ahead point is visible 846 | bool visible = true; 847 | 848 | Vector prevDir = initDir; 849 | 850 | // step along the path until we pass aheadRange 851 | bool isCorner = false; 852 | int i; 853 | for( i=startIndex; iGetSegmentCount(); ++i ) 854 | { 855 | Vector pos = (*m_path)[i]->pos; 856 | Vector to = pos - (*m_path)[i-1]->pos; 857 | Vector dir = to; 858 | dir.NormalizeInPlace(); 859 | 860 | // don't allow path to double-back from our starting direction (going upstairs, down curved passages, etc) 861 | if (DotProduct( dir, initDir ) < 0.0f) // -0.25f 862 | { 863 | --i; 864 | break; 865 | } 866 | 867 | // if the path turns a corner, we want to move towards the corner, not into the wall/stairs/etc 868 | if (DotProduct( dir, prevDir ) < 0.5f) 869 | { 870 | isCorner = true; 871 | --i; 872 | break; 873 | } 874 | prevDir = dir; 875 | 876 | // don't use points we cant see 877 | Vector probe = pos + Vector( 0, 0, HalfHumanHeight ); 878 | if (!IsWalkableTraceLineClear( eyes, probe, WALK_THRU_BREAKABLES )) 879 | { 880 | // presumably, the previous point is visible, so we will interpolate 881 | visible = false; 882 | break; 883 | } 884 | 885 | // if we encounter a ladder or jump area, we must stop 886 | if (i < m_path->GetSegmentCount() && 887 | ((*m_path)[ i ]->ladder || (*m_path)[ i ]->area->GetAttributes() & NAV_MESH_JUMP)) 888 | break; 889 | 890 | // Check straight-line path from our current position to this position 891 | // Test for un-jumpable height change, or unrecoverable fall 892 | //if (!IsStraightLinePathWalkable( &pos )) 893 | //{ 894 | // --i; 895 | // break; 896 | //} 897 | 898 | Vector along = (i == startIndex) ? (pos - feet) : (pos - (*m_path)[i-1]->pos); 899 | rangeSoFar += along.Length2D(); 900 | 901 | // stop if we have gone farther than aheadRange 902 | if (rangeSoFar >= aheadRange) 903 | break; 904 | } 905 | 906 | if (i < startIndex) 907 | afterIndex = startIndex; 908 | else if (i < m_path->GetSegmentCount()) 909 | afterIndex = i; 910 | else 911 | afterIndex = m_path->GetSegmentCount()-1; 912 | 913 | 914 | // compute point on the path at aheadRange 915 | if (afterIndex == 0) 916 | { 917 | *point = (*m_path)[0]->pos; 918 | } 919 | else 920 | { 921 | // interpolate point along path segment 922 | const Vector *afterPoint = &(*m_path)[ afterIndex ]->pos; 923 | const Vector *beforePoint = &(*m_path)[ afterIndex-1 ]->pos; 924 | 925 | Vector to = *afterPoint - *beforePoint; 926 | float length = to.Length2D(); 927 | 928 | float t = 1.0f - ((rangeSoFar - aheadRange) / length); 929 | 930 | if (t < 0.0f) 931 | t = 0.0f; 932 | else if (t > 1.0f) 933 | t = 1.0f; 934 | 935 | *point = *beforePoint + t * to; 936 | 937 | // if afterPoint wasn't visible, slide point backwards towards beforePoint until it is 938 | if (!visible) 939 | { 940 | const float sightStepSize = 25.0f; 941 | float dt = sightStepSize / length; 942 | 943 | Vector probe = *point + Vector( 0, 0, HalfHumanHeight ); 944 | while( t > 0.0f && !IsWalkableTraceLineClear( eyes, probe, WALK_THRU_BREAKABLES ) ) 945 | { 946 | t -= dt; 947 | *point = *beforePoint + t * to; 948 | } 949 | 950 | if (t <= 0.0f) 951 | *point = *beforePoint; 952 | } 953 | } 954 | 955 | // if position found is too close to us, or behind us, force it farther down the path so we don't stop and wiggle 956 | if (!isCorner) 957 | { 958 | const float epsilon = 50.0f; 959 | Vector2D toPoint; 960 | Vector2D centroid( m_improv->GetCentroid().x, m_improv->GetCentroid().y ); 961 | 962 | toPoint.x = point->x - centroid.x; 963 | toPoint.y = point->y - centroid.y; 964 | 965 | if (DotProduct2D( toPoint, initDir.AsVector2D() ) < 0.0f || toPoint.IsLengthLessThan( epsilon )) 966 | { 967 | int i; 968 | for( i=startIndex; iGetSegmentCount(); ++i ) 969 | { 970 | toPoint.x = (*m_path)[i]->pos.x - centroid.x; 971 | toPoint.y = (*m_path)[i]->pos.y - centroid.y; 972 | if ((*m_path)[i]->ladder || (*m_path)[i]->area->GetAttributes() & NAV_MESH_JUMP || toPoint.IsLengthGreaterThan( epsilon )) 973 | { 974 | *point = (*m_path)[i]->pos; 975 | startIndex = i; 976 | break; 977 | } 978 | } 979 | 980 | if (i == m_path->GetSegmentCount()) 981 | { 982 | *point = m_path->GetEndpoint(); 983 | startIndex = m_path->GetSegmentCount()-1; 984 | } 985 | } 986 | } 987 | 988 | // m_pathIndex should always be the next point on the path, even if we're not moving directly towards it 989 | if (startIndex < m_path->GetSegmentCount()) 990 | return startIndex; 991 | 992 | return m_path->GetSegmentCount()-1; 993 | } 994 | 995 | 996 | //-------------------------------------------------------------------------------------------------------------- 997 | /** 998 | * Do reflex avoidance movements if our "feelers" are touched 999 | * @todo Parameterize feeler spacing 1000 | */ 1001 | void CNavPathFollower::FeelerReflexAdjustment( Vector *goalPosition, float height ) 1002 | { 1003 | // if we are in a "precise" area, do not do feeler adjustments 1004 | if (m_improv->GetLastKnownArea() && m_improv->GetLastKnownArea()->GetAttributes() & NAV_MESH_PRECISE) 1005 | return; 1006 | 1007 | Vector dir = *goalPosition - m_improv->GetFeet(); 1008 | dir.z = 0.0f; 1009 | dir.NormalizeInPlace(); 1010 | 1011 | Vector lat( -dir.y, dir.x, 0.0f ); 1012 | 1013 | const float feelerOffset = (m_improv->IsCrouching()) ? 20.0f : 25.0f; // 15, 20 1014 | const float feelerLengthRun = 30.0f; // 100 - too long for tight hallways (cs_747) 1015 | const float feelerLengthWalk = 20.0f; 1016 | 1017 | const float feelerHeight = (height > 0.0f) ? height : StepHeight + 0.1f; // if obstacle is lower than StepHeight, we'll walk right over it 1018 | 1019 | float feelerLength = (m_improv->IsRunning()) ? feelerLengthRun : feelerLengthWalk; 1020 | 1021 | feelerLength = (m_improv->IsCrouching()) ? 20.0f : feelerLength; 1022 | 1023 | // 1024 | // Feelers must follow floor slope 1025 | // 1026 | float ground; 1027 | Vector normal; 1028 | if (m_improv->GetSimpleGroundHeightWithFloor( m_improv->GetEyes(), &ground, &normal ) == false) 1029 | return; 1030 | 1031 | // get forward vector along floor 1032 | dir = CrossProduct( lat, normal ); 1033 | 1034 | // correct the sideways vector 1035 | lat = CrossProduct( dir, normal ); 1036 | 1037 | 1038 | Vector feet = m_improv->GetFeet(); 1039 | feet.z += feelerHeight; 1040 | 1041 | Vector from = feet + feelerOffset * lat; 1042 | Vector to = from + feelerLength * dir; 1043 | 1044 | bool leftClear = IsWalkableTraceLineClear( from, to, WALK_THRU_DOORS | WALK_THRU_BREAKABLES ); 1045 | 1046 | // draw debug beams 1047 | if (m_isDebug) 1048 | { 1049 | if (leftClear) 1050 | NDebugOverlay::SweptBox( from, to, Vector( -2, -2, 0 ), Vector( 2, 2, 10.0f ), vec3_angle, 0, 255, 0, 150.0f, 0.1f ); 1051 | else 1052 | NDebugOverlay::SweptBox( from, to, Vector( -2, -2, 0 ), Vector( 2, 2, 10.0f ), vec3_angle, 255, 0, 0, 150.0f, 0.1f ); 1053 | } 1054 | 1055 | from = feet - feelerOffset * lat; 1056 | to = from + feelerLength * dir; 1057 | 1058 | bool rightClear = IsWalkableTraceLineClear( from, to, WALK_THRU_DOORS | WALK_THRU_BREAKABLES ); 1059 | 1060 | // draw debug beams 1061 | if (m_isDebug) 1062 | { 1063 | if (rightClear) 1064 | NDebugOverlay::SweptBox( from, to, Vector( -2, -2, 0 ), Vector( 2, 2, 10.0f ), vec3_angle, 0, 255, 0, 150.0f, 0.1f ); 1065 | else 1066 | NDebugOverlay::SweptBox( from, to, Vector( -2, -2, 0 ), Vector( 2, 2, 10.0f ), vec3_angle, 255, 0, 0, 150.0f, 0.1f ); 1067 | } 1068 | 1069 | 1070 | 1071 | const float avoidRange = (m_improv->IsCrouching()) ? 150.0f : 200.0f; 1072 | 1073 | if (!rightClear) 1074 | { 1075 | if (leftClear) 1076 | { 1077 | // right hit, left clear - veer left 1078 | *goalPosition = *goalPosition + avoidRange * lat; 1079 | //*goalPosition = m_improv->GetFeet() + avoidRange * lat; 1080 | 1081 | //m_improv->StrafeLeft(); 1082 | } 1083 | } 1084 | else if (!leftClear) 1085 | { 1086 | // right clear, left hit - veer right 1087 | *goalPosition = *goalPosition - avoidRange * lat; 1088 | //*goalPosition = m_improv->GetFeet() - avoidRange * lat; 1089 | 1090 | //m_improv->StrafeRight(); 1091 | } 1092 | 1093 | } 1094 | 1095 | //-------------------------------------------------------------------------------------------------------------- 1096 | /** 1097 | * Reset the stuck-checker. 1098 | */ 1099 | CStuckMonitor::CStuckMonitor( void ) 1100 | { 1101 | m_isStuck = false; 1102 | m_avgVelIndex = 0; 1103 | m_avgVelCount = 0; 1104 | } 1105 | 1106 | /** 1107 | * Reset the stuck-checker. 1108 | */ 1109 | void CStuckMonitor::Reset( void ) 1110 | { 1111 | m_isStuck = false; 1112 | m_avgVelIndex = 0; 1113 | m_avgVelCount = 0; 1114 | } 1115 | 1116 | //-------------------------------------------------------------------------------------------------------------- 1117 | /** 1118 | * Test if the improv has become stuck 1119 | */ 1120 | void CStuckMonitor::Update( CImprov *improv ) 1121 | { 1122 | if (m_isStuck) 1123 | { 1124 | // improv is stuck - see if it has moved far enough to be considered unstuck 1125 | const float unstuckRange = 75.0f; 1126 | if ((improv->GetCentroid() - m_stuckSpot).IsLengthGreaterThan( unstuckRange )) 1127 | { 1128 | // no longer stuck 1129 | Reset(); 1130 | //PrintIfWatched( "UN-STUCK\n" ); 1131 | } 1132 | } 1133 | else 1134 | { 1135 | // check if improv has become stuck 1136 | 1137 | // compute average velocity over a short period (for stuck check) 1138 | Vector vel = improv->GetCentroid() - m_lastCentroid; 1139 | 1140 | // if we are jumping, ignore Z 1141 | //if (improv->IsJumping()) 1142 | // vel.z = 0.0f; 1143 | 1144 | // ignore Z unless we are on a ladder (which is only Z) 1145 | if (!improv->IsUsingLadder()) 1146 | vel.z = 0.0f; 1147 | 1148 | // cannot be Length2D, or will break ladder movement (they are only Z) 1149 | float moveDist = vel.Length(); 1150 | 1151 | float deltaT = gpGlobals->curtime - m_lastTime; 1152 | if (deltaT <= 0.0f) 1153 | return; 1154 | 1155 | m_lastTime = gpGlobals->curtime; 1156 | 1157 | // compute current velocity 1158 | m_avgVel[ m_avgVelIndex++ ] = moveDist/deltaT; 1159 | 1160 | if (m_avgVelIndex == MAX_VEL_SAMPLES) 1161 | m_avgVelIndex = 0; 1162 | 1163 | if (m_avgVelCount < MAX_VEL_SAMPLES) 1164 | { 1165 | ++m_avgVelCount; 1166 | } 1167 | else 1168 | { 1169 | // we have enough samples to know if we're stuck 1170 | 1171 | float avgVel = 0.0f; 1172 | for( int t=0; tIsUsingLadder()) ? 10.0f : 40.0f; 1179 | 1180 | if (avgVel < stuckVel) 1181 | { 1182 | // note when and where we initially become stuck 1183 | m_stuckTimer.Start(); 1184 | m_stuckSpot = improv->GetCentroid(); 1185 | m_isStuck = true; 1186 | } 1187 | } 1188 | } 1189 | 1190 | // always need to track this 1191 | m_lastCentroid = improv->GetCentroid(); 1192 | } 1193 | 1194 | -------------------------------------------------------------------------------- /bots/nav_path.h: -------------------------------------------------------------------------------- 1 | // nav_path.h 2 | // Navigation Path encapsulation 3 | // Author: Michael S. Booth (mike@turtlerockstudios.com), November 2003 4 | // https://github.com/ValveSoftware/halflife/tree/master/game_shared/bot 5 | // Ported to Source from the HL1 SDK with adjustments for SourceBots by Bitl 6 | 7 | #ifndef _NAV_PATH_H_ 8 | #define _NAV_PATH_H_ 9 | 10 | #include "nav_area.h" 11 | 12 | class CImprov; 13 | 14 | //-------------------------------------------------------------------------------------------------------- 15 | /** 16 | * The CNavPath class encapsulates a path through space 17 | */ 18 | class CNavPath 19 | { 20 | public: 21 | CNavPath( void ) 22 | { 23 | m_segmentCount = 0; 24 | } 25 | 26 | struct PathSegment 27 | { 28 | CNavArea *area; ///< the area along the path 29 | NavTraverseType how; ///< how to enter this area from the previous one 30 | Vector pos; ///< our movement goal position at this point in the path 31 | const CNavLadder *ladder; ///< if "how" refers to a ladder, this is it 32 | }; 33 | 34 | const PathSegment * operator[] ( int i ) const { return (i >= 0 && i < m_segmentCount) ? &m_path[i] : NULL; } 35 | const PathSegment *GetSegment( int i ) const { return (i >= 0 && i < m_segmentCount) ? &m_path[i] : NULL; } 36 | int GetSegmentCount( void ) const { return m_segmentCount; } 37 | const Vector &GetEndpoint( void ) const { return m_path[ m_segmentCount-1 ].pos; } 38 | bool IsAtEnd( const Vector &pos ) const; ///< return true if position is at the end of the path 39 | 40 | float GetLength( void ) const; ///< return length of path from start to finish 41 | bool GetPointAlongPath( float distAlong, Vector *pointOnPath ) const; ///< return point a given distance along the path - if distance is out of path bounds, point is clamped to start/end 42 | 43 | /// return the node index closest to the given distance along the path without going over - returns (-1) if error 44 | int GetSegmentIndexAlongPath( float distAlong ) const; 45 | 46 | bool IsValid( void ) const { return (m_segmentCount > 0); } 47 | void Invalidate( void ) { m_segmentCount = 0; m_bCanReach = true; m_Timer.Invalidate(); } 48 | bool IsUnreachable() const { return !m_bCanReach; } 49 | float GetElapsedTimeSinceBuild() const { return m_Timer.GetElapsedTime(); } 50 | 51 | void Draw( void ); ///< draw the path for debugging 52 | 53 | /// compute closest point on path to given point 54 | bool FindClosestPointOnPath( const Vector *worldPos, int startIndex, int endIndex, Vector *close ) const; 55 | 56 | void Optimize( void ); 57 | 58 | /** 59 | * Compute shortest path from 'start' to 'goal' via A* algorithm 60 | */ 61 | template< typename CostFunctor > 62 | bool Compute( const Vector &start, const Vector &goal, CostFunctor &costFunc ) 63 | { 64 | Invalidate(); 65 | 66 | if (start == NULL || goal == NULL) 67 | return false; 68 | 69 | CNavArea *startArea = TheNavMesh->GetNearestNavArea(start + Vector(0.0f,0.0f,1.0f)); 70 | if (startArea == NULL) 71 | return false; 72 | 73 | CNavArea *goalArea = TheNavMesh->GetNavArea( goal ); 74 | 75 | // if we are already in the goal area, build trivial path 76 | if (startArea == goalArea) 77 | { 78 | BuildTrivialPath( start, goal ); 79 | return true; 80 | } 81 | 82 | // make sure path end position is on the ground 83 | Vector pathEndPosition = goal; 84 | if (goalArea) 85 | pathEndPosition.z = goalArea->GetZ( &pathEndPosition ); 86 | else 87 | TheNavMesh->GetGroundHeight( pathEndPosition, &pathEndPosition.z ); 88 | 89 | // 90 | // Compute shortest path to goal 91 | // 92 | CNavArea *closestArea; 93 | bool pathToGoalExists = NavAreaBuildPath( startArea, goalArea, &goal, costFunc, &closestArea ); 94 | 95 | m_Timer.Start(); 96 | m_bCanReach = pathToGoalExists; 97 | 98 | // 99 | // Build path by following parent links 100 | // 101 | 102 | // get count 103 | int count = 0; 104 | CNavArea *area; 105 | for( area = closestArea; area; area = area->GetParent() ) 106 | ++count; 107 | 108 | // save room for endpoint 109 | if (count > MAX_PATH_SEGMENTS-1) 110 | count = MAX_PATH_SEGMENTS-1; 111 | 112 | if (count == 0) 113 | return false; 114 | 115 | if (count == 1) 116 | { 117 | BuildTrivialPath( start, goal ); 118 | return true; 119 | } 120 | 121 | // build path 122 | m_segmentCount = count; 123 | for( area = closestArea; count && area; area = area->GetParent() ) 124 | { 125 | --count; 126 | m_path[ count ].area = area; 127 | m_path[ count ].how = area->GetParentHow(); 128 | } 129 | 130 | // compute path positions 131 | if (ComputePathPositions(start) == false) 132 | { 133 | //PrintIfWatched( "Error building path\n" ); 134 | Invalidate(); 135 | return false; 136 | } 137 | 138 | // append path end position 139 | m_path[ m_segmentCount ].area = closestArea; 140 | m_path[ m_segmentCount ].pos = pathEndPosition; 141 | m_path[ m_segmentCount ].ladder = NULL; 142 | m_path[ m_segmentCount ].how = NUM_TRAVERSE_TYPES; 143 | ++m_segmentCount; 144 | 145 | return pathToGoalExists; 146 | } 147 | 148 | private: 149 | enum { MAX_PATH_SEGMENTS = 256 }; 150 | PathSegment m_path[ MAX_PATH_SEGMENTS ]; 151 | int m_segmentCount; 152 | bool m_bCanReach; 153 | IntervalTimer m_Timer; 154 | 155 | bool ComputePathPositions( const Vector &start ); ///< determine actual path positions 156 | bool BuildTrivialPath( const Vector &start, const Vector &goal ); ///< utility function for when start and goal are in the same area 157 | 158 | int FindNextOccludedNode( int anchor ); ///< used by Optimize() 159 | }; 160 | 161 | //-------------------------------------------------------------------------------------------------------- 162 | /** 163 | * Monitor improv movement and determine if it becomes stuck 164 | */ 165 | class CStuckMonitor 166 | { 167 | public: 168 | CStuckMonitor( void ); 169 | 170 | void Reset( void ); 171 | void Update( CImprov *improv ); 172 | bool IsStuck( void ) const { return m_isStuck; } 173 | 174 | float GetDuration( void ) const { return (m_isStuck) ? m_stuckTimer.GetElapsedTime() : 0.0f; } 175 | 176 | private: 177 | bool m_isStuck; ///< if true, we are stuck 178 | Vector m_stuckSpot; ///< the location where we became stuck 179 | IntervalTimer m_stuckTimer; ///< how long we have been stuck 180 | 181 | enum { MAX_VEL_SAMPLES = 5 }; 182 | float m_avgVel[ MAX_VEL_SAMPLES ]; 183 | int m_avgVelIndex; 184 | int m_avgVelCount; 185 | Vector m_lastCentroid; 186 | float m_lastTime; 187 | }; 188 | 189 | //-------------------------------------------------------------------------------------------------------- 190 | /** 191 | * The CNavPathFollower class implements path following behavior 192 | */ 193 | class CNavPathFollower 194 | { 195 | public: 196 | CNavPathFollower( void ); 197 | 198 | void SetImprov( CImprov *improv ) { m_improv = improv; } 199 | void SetPath( CNavPath *path ) { m_path = path; } 200 | void SetFollowPathExactly( bool value ) { m_bShouldFollowPathExactly = value; } 201 | 202 | void Reset( void ); 203 | 204 | #define DONT_AVOID_OBSTACLES false 205 | void Update( float deltaT, bool avoidObstacles = true ); ///< move improv along path 206 | void Debug( bool status ) { m_isDebug = status; } ///< turn debugging on/off 207 | 208 | bool IsStuck( void ) const { return m_stuckMonitor.IsStuck(); } ///< return true if improv is stuck 209 | void ResetStuck( void ) { m_stuckMonitor.Reset(); } 210 | float GetStuckDuration( void ) const { return m_stuckMonitor.GetDuration(); } ///< return how long we've been stuck 211 | 212 | void FeelerReflexAdjustment( Vector *goalPosition, float height = -1.0f ); ///< adjust goal position if "feelers" are touched 213 | 214 | private: 215 | CImprov *m_improv; ///< who is doing the path following 216 | 217 | CNavPath *m_path; ///< the path being followed 218 | 219 | int m_segmentIndex; ///< the point on the path the improv is moving towards 220 | int m_behindIndex; ///< index of the node on the path just behind us 221 | Vector m_goal; ///< last computed follow goal 222 | 223 | bool m_isLadderStarted; 224 | 225 | bool m_isDebug; 226 | bool m_bShouldFollowPathExactly; 227 | 228 | int FindOurPositionOnPath( Vector *close, bool local ) const; ///< return the closest point to our current position on current path 229 | int FindPathPoint( float aheadRange, Vector *point, int *prevIndex ); ///< compute a point a fixed distance ahead along our path. 230 | 231 | public: 232 | CStuckMonitor m_stuckMonitor; 233 | }; 234 | 235 | 236 | 237 | #endif // _NAV_PATH_H_ 238 | 239 | -------------------------------------------------------------------------------- /bots/schedules/bot_schedule.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/sourcebots/72863dfb3924bfa9001b4e2c3b924f88c7ba46ea/bots/schedules/bot_schedule.cpp -------------------------------------------------------------------------------- /bots/schedules/bot_schedule_call_backup.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/sourcebots/72863dfb3924bfa9001b4e2c3b924f88c7ba46ea/bots/schedules/bot_schedule_call_backup.cpp -------------------------------------------------------------------------------- /bots/schedules/bot_schedule_change_weapon.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/sourcebots/72863dfb3924bfa9001b4e2c3b924f88c7ba46ea/bots/schedules/bot_schedule_change_weapon.cpp -------------------------------------------------------------------------------- /bots/schedules/bot_schedule_cover.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/sourcebots/72863dfb3924bfa9001b4e2c3b924f88c7ba46ea/bots/schedules/bot_schedule_cover.cpp -------------------------------------------------------------------------------- /bots/schedules/bot_schedule_defend_spawn.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/sourcebots/72863dfb3924bfa9001b4e2c3b924f88c7ba46ea/bots/schedules/bot_schedule_defend_spawn.cpp -------------------------------------------------------------------------------- /bots/schedules/bot_schedule_help_dejected_friend.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/sourcebots/72863dfb3924bfa9001b4e2c3b924f88c7ba46ea/bots/schedules/bot_schedule_help_dejected_friend.cpp -------------------------------------------------------------------------------- /bots/schedules/bot_schedule_hide_and_heal.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/sourcebots/72863dfb3924bfa9001b4e2c3b924f88c7ba46ea/bots/schedules/bot_schedule_hide_and_heal.cpp -------------------------------------------------------------------------------- /bots/schedules/bot_schedule_hide_and_reload.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/sourcebots/72863dfb3924bfa9001b4e2c3b924f88c7ba46ea/bots/schedules/bot_schedule_hide_and_reload.cpp -------------------------------------------------------------------------------- /bots/schedules/bot_schedule_hunt_enemy.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/sourcebots/72863dfb3924bfa9001b4e2c3b924f88c7ba46ea/bots/schedules/bot_schedule_hunt_enemy.cpp -------------------------------------------------------------------------------- /bots/schedules/bot_schedule_investigate_location.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/sourcebots/72863dfb3924bfa9001b4e2c3b924f88c7ba46ea/bots/schedules/bot_schedule_investigate_location.cpp -------------------------------------------------------------------------------- /bots/schedules/bot_schedule_move_aside.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/sourcebots/72863dfb3924bfa9001b4e2c3b924f88c7ba46ea/bots/schedules/bot_schedule_move_aside.cpp -------------------------------------------------------------------------------- /bots/schedules/bot_schedule_reload.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/sourcebots/72863dfb3924bfa9001b4e2c3b924f88c7ba46ea/bots/schedules/bot_schedule_reload.cpp -------------------------------------------------------------------------------- /bots/schedules/bot_schedules.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/sourcebots/72863dfb3924bfa9001b4e2c3b924f88c7ba46ea/bots/schedules/bot_schedules.h -------------------------------------------------------------------------------- /bots/squad.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/sourcebots/72863dfb3924bfa9001b4e2c3b924f88c7ba46ea/bots/squad.cpp -------------------------------------------------------------------------------- /bots/squad.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/sourcebots/72863dfb3924bfa9001b4e2c3b924f88c7ba46ea/bots/squad.h -------------------------------------------------------------------------------- /bots/squad_manager.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/sourcebots/72863dfb3924bfa9001b4e2c3b924f88c7ba46ea/bots/squad_manager.cpp -------------------------------------------------------------------------------- /bots/squad_manager.h: -------------------------------------------------------------------------------- 1 | //==== Woots 2016. http://creativecommons.org/licenses/by/2.5/mx/ ===========// 2 | 3 | #ifndef SQUAD_MANAGER_H 4 | #define SQUAD_MANAGER_H 5 | 6 | #ifdef _WIN32 7 | #pragma once 8 | #endif 9 | 10 | #include "bots\squad.h" 11 | 12 | //================================================================================ 13 | // Administrador de escuadrones 14 | //================================================================================ 15 | class CSquadManager : public CAutoGameSystemPerFrame 16 | { 17 | public: 18 | CSquadManager(); 19 | 20 | public: 21 | virtual void LevelShutdownPostEntity(); 22 | virtual void FrameUpdatePostEntityThink(); 23 | 24 | public: 25 | virtual CSquad *GetSquad( const char *name ); 26 | virtual CSquad *GetOrCreateSquad( const char *name ); 27 | virtual void AddSquad( CSquad *pSquad ); 28 | 29 | protected: 30 | CUtlVector m_nSquads; 31 | }; 32 | 33 | extern CSquadManager *TheSquads; 34 | 35 | #endif // SQUAD_MANAGER_H --------------------------------------------------------------------------------