@@ -12,95 +12,47 @@ namespace C7Engine {
1212 using System ;
1313 using System . Threading . Tasks ;
1414
15- public class BarbarianAI {
15+ // TODO: The AI state (plans, strategy, ..) should be stored somewhere in game state.
16+ // For now, we have a stateless random AI.
1617
17- private ILogger log = Log . ForContext < BarbarianAI > ( ) ;
18+ public static class BarbarianAI {
1819
19- public async Task PlayTurn ( Player player , GameData gameData ) {
20+ private static ILogger log = Log . ForContext < TurnHandling > ( ) ;
21+
22+ public static async Task PlayTurn ( Player player , GameData gameData ) {
2023 if ( ! player . isBarbarians ) {
21- throw new System . Exception ( "Barbarian AI can only play barbarian players" ) ;
24+ throw new Exception ( "Barbarian AI can only play barbarian players" ) ;
2225 }
2326
24- foreach ( MapUnit unit in player . units . ToArray ( ) ) {
25- // Make the barbarians wake up if they see a unit or a civ's
26- // borders. This will happen each turn, so eventually the barb
27- // should muster the courage to attack.
28- foreach ( Tile t in unit . location . neighbors . Values ) {
29- if ( t . unitsOnTile . Count > 0 && t . unitsOnTile [ 0 ] . owner != player ) {
30- unit . wake ( ) ;
31- break ;
32- }
33- if ( t . OwningPlayer ( ) != null ) {
34- unit . wake ( ) ;
35- break ;
36- }
37- }
38-
39- // Don't waste time recalculating behaviors for fortified units.
40- if ( unit . isFortified ) {
41- continue ;
42- }
43-
44- // For each unit, if there's already an AI task assigned, it will attempt to complete its goal.
45- // It may fail due to conditions having changed since that goal was assigned; in that case it will
46- // get a new task to try to complete.
47- //
48- // Cap our attempts at 2 to avoid getting stuck in bad situations.
49- for ( int attempt = 0 ; attempt < 2 ; ++ attempt ) {
50- if ( unit . currentAI == null ) {
51- unit . currentAI = GetAIForUnit ( unit , player ) ;
52- }
53-
54- // If the unit is still the process of doing its plan, allow
55- // it to continue next turn.
56- UnitAI . Result result = await unit . currentAI . PlayTurn ( player , unit ) ;
57- if ( result == UnitAI . Result . InProgress ) {
58- break ;
59- }
60-
61- if ( result == UnitAI . Result . Error ) {
62- unit . currentAI = null ;
63- break ;
64- }
27+ if ( gameData . barbarianInfo . barbarianActivity == BarbarianActivity . None )
28+ return ;
6529
66- if ( unit . hitPointsRemaining <= 0 || unit . isFortified ) {
67- unit . currentAI = null ;
68- break ;
69- }
30+ var strategy = SelectStrategy ( gameData . barbarianInfo . barbarianActivity ) ;
7031
71- // Otherwise we need a new plan for next turn. Pick it now
72- // to avoid things like new units being preferred for
73- // exploration instead of units already far away from home
74- // for exploration.
75- unit . currentAI = GetAIForUnit ( unit , player ) ;
76- }
32+ // TODO: Band units into tribes, decide at the tribe level --> work together
7733
34+ foreach ( MapUnit unit in player . units . ToArray ( ) ) {
35+ await strategy . PlayUnitTurn ( player , unit ) ;
7836 player . tileKnowledge . AddTilesToKnown ( unit . location ) ;
7937 }
8038 }
8139
82- public static UnitAI GetAIForUnit ( MapUnit unit , Player player ) {
83- // Barbarians should always defend their camp if it is unguarded.
84- if ( unit . location . hasBarbarianCamp && unit . location . unitsOnTile . Count == 1 ) {
85- return new DefenderAI ( DefenderAI . MakeAiDataForDefendInPlace ( unit , player ) ) ;
86- }
87-
88- // If the barbarian can fight, it should.
89- CombatAIData maybeCombat = CombatAI . MakeAiData ( unit , player ) ;
90- if ( maybeCombat != null ) {
91- return new CombatAI ( maybeCombat ) ;
40+ private static IBarbarianStrategy SelectStrategy ( BarbarianActivity barbarianActivity ) {
41+ switch ( barbarianActivity ) {
42+ case BarbarianActivity . None :
43+ throw new Exception ( "Cannot select an AI strategy for BarbarianActivity 'None'." ) ;
44+ case BarbarianActivity . Sedentary :
45+ return new SedentaryStrategy ( ) ;
46+ case BarbarianActivity . Roaming :
47+ return new RoamingStrategy ( ) ;
48+ case BarbarianActivity . Restless :
49+ return new RestlessStrategy ( ) ;
50+ case BarbarianActivity . Raging :
51+ return new RagingStrategy ( ) ;
52+ default :
53+ log . Warning ( "Unknown BarbarianActivity. Defaulting to Sedentary." ) ;
54+ return new SedentaryStrategy ( ) ;
9255 }
93-
94- // Give barbarians a chance to explore if they can't fight.
95- if ( GameData . rng . Next ( 100 ) < 30 ) {
96- ExplorerAIData ? maybeAiData = ExplorerAI . MaybeMakeAiData ( unit , player ) ;
97- if ( maybeAiData != null ) {
98- return new ExplorerAI ( maybeAiData ) ;
99- }
100- }
101-
102- // Otherwise just sit tight.
103- return new DefenderAI ( DefenderAI . MakeAiDataForDefendInPlace ( unit , player ) ) ;
10456 }
10557 }
10658}
0 commit comments