hedgewars/uAI.pas
changeset 6580 6155187bf599
parent 6462 0758fbec9b9f
child 6700 e04da46ee43c
equal deleted inserted replaced
6579:fc52f7c22c9b 6580:6155187bf599
    28 procedure ProcessBot;
    28 procedure ProcessBot;
    29 procedure FreeActionsList;
    29 procedure FreeActionsList;
    30 
    30 
    31 implementation
    31 implementation
    32 uses uConsts, SDLh, uAIMisc, uAIAmmoTests, uAIActions,
    32 uses uConsts, SDLh, uAIMisc, uAIAmmoTests, uAIActions,
    33      uAmmos, SysUtils{$IFNDEF USE_SDLTHREADS} {$IFDEF UNIX}, cthreads{$ENDIF} {$ENDIF}, uTypes,
    33     uAmmos, SysUtils{$IFNDEF USE_SDLTHREADS} {$IFDEF UNIX}, cthreads{$ENDIF} {$ENDIF}, uTypes,
    34      uVariables, uCommands, uUtils, uDebug;
    34     uVariables, uCommands, uUtils, uDebug;
    35 
    35 
    36 var BestActions: TActions;
    36 var BestActions: TActions;
    37     CanUseAmmo: array [TAmmoType] of boolean;
    37     CanUseAmmo: array [TAmmoType] of boolean;
    38     StopThinking: boolean;
    38     StopThinking: boolean;
    39 {$IFDEF USE_SDLTHREADS} 
    39 {$IFDEF USE_SDLTHREADS} 
    45 
    45 
    46 procedure FreeActionsList;
    46 procedure FreeActionsList;
    47 begin
    47 begin
    48 AddFileLog('FreeActionsList called');
    48 AddFileLog('FreeActionsList called');
    49 if hasThread <> 0 then
    49 if hasThread <> 0 then
    50    begin
    50     begin
    51    AddFileLog('Waiting AI thread to finish');
    51     AddFileLog('Waiting AI thread to finish');
    52    StopThinking:= true;
    52     StopThinking:= true;
    53    repeat
    53     repeat
    54      SDL_Delay(10)
    54         SDL_Delay(10)
    55    until hasThread = 0
    55     until hasThread = 0
    56    end;
    56     end;
    57 
    57 
    58 with CurrentHedgehog^ do
    58 with CurrentHedgehog^ do
    59      if Gear <> nil then
    59     if Gear <> nil then
    60         if BotLevel <> 0 then
    60         if BotLevel <> 0 then
    61            StopMessages(Gear^.Message);
    61             StopMessages(Gear^.Message);
    62 
    62 
    63 BestActions.Count:= 0;
    63 BestActions.Count:= 0;
    64 BestActions.Pos:= 0
    64 BestActions.Pos:= 0
    65 end;
    65 end;
    66 
    66 
   115 begin
   115 begin
   116 BotLevel:= Me^.Hedgehog^.BotLevel;
   116 BotLevel:= Me^.Hedgehog^.BotLevel;
   117 
   117 
   118 for i:= 0 to Pred(Targets.Count) do
   118 for i:= 0 to Pred(Targets.Count) do
   119     if (Targets.ar[i].Score >= 0) and (not StopThinking) then
   119     if (Targets.ar[i].Score >= 0) and (not StopThinking) then
   120        begin
   120         begin
   121        with CurrentHedgehog^ do
   121         with CurrentHedgehog^ do
   122             a:= CurAmmoType;
   122             a:= CurAmmoType;
   123        aa:= a;
   123         aa:= a;
   124 {$IFDEF USE_SDLTHREADS}
   124 {$IFDEF USE_SDLTHREADS}
   125        SDL_delay(0);    //ThreadSwitch was only a hint
   125         SDL_delay(0);    //ThreadSwitch was only a hint
   126 {$ELSE}
   126 {$ELSE}
   127        ThreadSwitch();
   127         ThreadSwitch();
   128 {$ENDIF}       
   128 {$ENDIF}       
   129        repeat
   129         repeat
   130         if (CanUseAmmo[a]) and
   130         if (CanUseAmmo[a]) and
   131            ((not isMoved) or ((AmmoTests[a].flags and amtest_OnTurn) = 0)) then
   131             ((not isMoved) or ((AmmoTests[a].flags and amtest_OnTurn) = 0)) then
   132            begin
   132             begin
   133 {$HINTS OFF}
   133 {$HINTS OFF}
   134            Score:= AmmoTests[a].proc(Me, Targets.ar[i].Point, BotLevel, ap);
   134             Score:= AmmoTests[a].proc(Me, Targets.ar[i].Point, BotLevel, ap);
   135 {$HINTS ON}
   135 {$HINTS ON}
   136            if Actions.Score + Score > BestActions.Score then
   136             if Actions.Score + Score > BestActions.Score then
   137             if (BestActions.Score < 0) or (Actions.Score + Score > BestActions.Score + Byte(BotLevel) * 2048) then
   137                 if (BestActions.Score < 0) or (Actions.Score + Score > BestActions.Score + Byte(BotLevel) * 2048) then
   138               begin
   138                     begin
   139               BestActions:= Actions;
   139                     BestActions:= Actions;
   140               inc(BestActions.Score, Score);
   140                     inc(BestActions.Score, Score);
   141               BestActions.isWalkingToABetterPlace:= false;
   141                     BestActions.isWalkingToABetterPlace:= false;
   142 
   142 
   143               if (ap.Angle > 0) then AddAction(BestActions, aia_LookRight, 0, 200, 0, 0)
   143                 if (ap.Angle > 0) then
   144               else if (ap.Angle < 0) then AddAction(BestActions, aia_LookLeft, 0, 200, 0, 0);
   144                     AddAction(BestActions, aia_LookRight, 0, 200, 0, 0)
   145 
   145             else if (ap.Angle < 0) then
   146               AddAction(BestActions, aia_Weapon, Longword(a), 300 + random(400), 0, 0);
   146                 AddAction(BestActions, aia_LookLeft, 0, 200, 0, 0);
   147               if (ap.Time <> 0) then AddAction(BestActions, aia_Timer, ap.Time div 1000, 400, 0, 0);
   147 
   148               if (Ammoz[a].Ammo.Propz and ammoprop_NoCrosshair) = 0 then
   148                 AddAction(BestActions, aia_Weapon, Longword(a), 300 + random(400), 0, 0);
   149                  begin
   149                 
   150                  ap.Angle:= LongInt(Me^.Angle) - Abs(ap.Angle);
   150                 if (ap.Time <> 0) then
   151                  if ap.Angle > 0 then
   151                     AddAction(BestActions, aia_Timer, ap.Time div 1000, 400, 0, 0);
   152                     begin
   152                 if (Ammoz[a].Ammo.Propz and ammoprop_NoCrosshair) = 0 then
   153                     AddAction(BestActions, aia_Up, aim_push, 300 + random(250), 0, 0);
   153                     begin
   154                     AddAction(BestActions, aia_Up, aim_release, ap.Angle, 0, 0)
   154                     ap.Angle:= LongInt(Me^.Angle) - Abs(ap.Angle);
   155                     end else if ap.Angle < 0 then
   155                     if ap.Angle > 0 then
   156                     begin
   156                         begin
   157                     AddAction(BestActions, aia_Down, aim_push, 300 + random(250), 0, 0);
   157                         AddAction(BestActions, aia_Up, aim_push, 300 + random(250), 0, 0);
   158                     AddAction(BestActions, aia_Down, aim_release, -ap.Angle, 0, 0)
   158                         AddAction(BestActions, aia_Up, aim_release, ap.Angle, 0, 0)
   159                     end
   159                         end
   160                  end;
   160                     else if ap.Angle < 0 then
   161               if (Ammoz[a].Ammo.Propz and ammoprop_NeedTarget) <> 0 then
   161                         begin
   162                  begin
   162                         AddAction(BestActions, aia_Down, aim_push, 300 + random(250), 0, 0);
   163                  AddAction(BestActions, aia_Put, 0, 1, ap.AttackPutX, ap.AttackPutY)
   163                         AddAction(BestActions, aia_Down, aim_release, -ap.Angle, 0, 0)
   164                  end;
   164                         end
   165               if (Ammoz[a].Ammo.Propz and ammoprop_AttackingPut) = 0 then
   165                     end;
   166                  begin
   166                 if (Ammoz[a].Ammo.Propz and ammoprop_NeedTarget) <> 0 then
   167                  AddAction(BestActions, aia_attack, aim_push, 650 + random(300), 0, 0);
   167                     begin
   168                  AddAction(BestActions, aia_attack, aim_release, ap.Power, 0, 0);
   168                     AddAction(BestActions, aia_Put, 0, 1, ap.AttackPutX, ap.AttackPutY)
   169                  end;
   169                     end;
   170               if ap.ExplR > 0 then
   170                 if (Ammoz[a].Ammo.Propz and ammoprop_AttackingPut) = 0 then
   171                  AddAction(BestActions, aia_AwareExpl, ap.ExplR, 10, ap.ExplX, ap.ExplY);
   171                     begin
   172               end
   172                     AddAction(BestActions, aia_attack, aim_push, 650 + random(300), 0, 0);
   173            end;
   173                     AddAction(BestActions, aia_attack, aim_release, ap.Power, 0, 0);
   174         if a = High(TAmmoType) then a:= Low(TAmmoType)
   174                     end;
   175                                else inc(a)
   175                 if ap.ExplR > 0 then
   176        until (a = aa) or
   176                     AddAction(BestActions, aia_AwareExpl, ap.ExplR, 10, ap.ExplX, ap.ExplY);
   177              (CurrentHedgehog^.MultiShootAttacks > 0) or // shooting same weapon
   177                 end
   178              StopThinking
   178             end;
   179        end
   179         if a = High(TAmmoType) then
       
   180             a:= Low(TAmmoType)
       
   181         else inc(a)
       
   182         until (a = aa) or (CurrentHedgehog^.MultiShootAttacks > 0) or // shooting same weapon
       
   183         StopThinking
       
   184         end
   180 end;
   185 end;
   181 
   186 
   182 procedure Walk(Me: PGear; var Actions: TActions);
   187 procedure Walk(Me: PGear; var Actions: TActions);
   183 const FallPixForBranching = cHHRadius * 2 + 8;
   188 const FallPixForBranching = cHHRadius * 2 + 8;
   184 var
   189 var
   200 
   205 
   201 tmp:= random(2) + 1;
   206 tmp:= random(2) + 1;
   202 Push(0, Actions, Me^, tmp);
   207 Push(0, Actions, Me^, tmp);
   203 Push(0, Actions, Me^, tmp xor 3);
   208 Push(0, Actions, Me^, tmp xor 3);
   204 
   209 
   205 if (Me^.State and gstAttacked) = 0 then maxticks:= Max(0, TurnTimeLeft - 5000 - LongWord(4000 * BotLevel))
   210 if (Me^.State and gstAttacked) = 0 then
   206                                    else maxticks:= TurnTimeLeft;
   211     maxticks:= Max(0, TurnTimeLeft - 5000 - LongWord(4000 * BotLevel))
   207 
   212 else
   208 if (Me^.State and gstAttacked) = 0 then TestAmmos(Actions, Me, false);
   213     maxticks:= TurnTimeLeft;
       
   214 
       
   215 if (Me^.State and gstAttacked) = 0 then
       
   216     TestAmmos(Actions, Me, false);
       
   217     
   209 BestRate:= RatePlace(Me);
   218 BestRate:= RatePlace(Me);
   210 BaseRate:= Max(BestRate, 0);
   219 BaseRate:= Max(BestRate, 0);
   211 
   220 
   212 if (Ammoz[Me^.Hedgehog^.CurAmmoType].Ammo.Propz and ammoprop_NeedTarget) <> 0 then
   221 if (Ammoz[Me^.Hedgehog^.CurAmmoType].Ammo.Propz and ammoprop_NeedTarget) <> 0 then
   213     AddAction(Actions, aia_Weapon, Longword(amNothing), 100 + random(200), 0, 0);
   222     AddAction(Actions, aia_Weapon, Longword(amNothing), 100 + random(200), 0, 0);
   215 while (Stack.Count > 0) and (not StopThinking) and (GameFlags and gfArtillery = 0) do
   224 while (Stack.Count > 0) and (not StopThinking) and (GameFlags and gfArtillery = 0) do
   216     begin
   225     begin
   217     Pop(ticks, Actions, Me^);
   226     Pop(ticks, Actions, Me^);
   218 
   227 
   219     AddAction(Actions, Me^.Message, aim_push, 250, 0, 0);
   228     AddAction(Actions, Me^.Message, aim_push, 250, 0, 0);
   220     if (Me^.Message and gmLeft) <> 0 then AddAction(Actions, aia_WaitXL, hwRound(Me^.X), 0, 0, 0)
   229     if (Me^.Message and gmLeft) <> 0 then
   221                                       else AddAction(Actions, aia_WaitXR, hwRound(Me^.X), 0, 0, 0);
   230         AddAction(Actions, aia_WaitXL, hwRound(Me^.X), 0, 0, 0)
       
   231     else
       
   232         AddAction(Actions, aia_WaitXR, hwRound(Me^.X), 0, 0, 0);
       
   233     
   222     steps:= 0;
   234     steps:= 0;
   223 
   235 
   224     while (not StopThinking) do
   236     while (not StopThinking) do
   225        begin
   237         begin
   226 {$HINTS OFF}
   238 {$HINTS OFF}
   227        CanGo:= HHGo(Me, @AltMe, GoInfo);
   239         CanGo:= HHGo(Me, @AltMe, GoInfo);
   228 {$HINTS ON}
   240 {$HINTS ON}
   229        inc(ticks, GoInfo.Ticks);
   241         inc(ticks, GoInfo.Ticks);
   230        if ticks > maxticks then break;
   242         if ticks > maxticks then
   231 
   243             break;
   232        if (BotLevel < 5) and (GoInfo.JumpType = jmpHJump) then // hjump support
   244 
   233           if Push(ticks, Actions, AltMe, Me^.Message) then
   245         if (BotLevel < 5) and (GoInfo.JumpType = jmpHJump) then // hjump support
   234              with Stack.States[Pred(Stack.Count)] do
   246             if Push(ticks, Actions, AltMe, Me^.Message) then
   235                   begin
   247                 with Stack.States[Pred(Stack.Count)] do
   236                   if Me^.dX.isNegative then AddAction(MadeActions, aia_LookRight, 0, 200, 0, 0)
   248                     begin
   237                                        else AddAction(MadeActions, aia_LookLeft, 0, 200, 0, 0);
   249                     if Me^.dX.isNegative then
   238                   AddAction(MadeActions, aia_HJump, 0, 305 + random(50), 0, 0);
   250                         AddAction(MadeActions, aia_LookRight, 0, 200, 0, 0)
   239                   AddAction(MadeActions, aia_HJump, 0, 350, 0, 0);
   251                     else
   240                   if Me^.dX.isNegative then AddAction(MadeActions, aia_LookLeft, 0, 200, 0, 0)
   252                         AddAction(MadeActions, aia_LookLeft, 0, 200, 0, 0);
   241                                        else AddAction(MadeActions, aia_LookRight, 0, 200, 0, 0);
   253                         
   242                   end;
   254                     AddAction(MadeActions, aia_HJump, 0, 305 + random(50), 0, 0);
   243        if (BotLevel < 3) and (GoInfo.JumpType = jmpLJump) then // ljump support
   255                     AddAction(MadeActions, aia_HJump, 0, 350, 0, 0);
   244           if Push(ticks, Actions, AltMe, Me^.Message) then
   256                     
   245              with Stack.States[Pred(Stack.Count)] do
   257                     if Me^.dX.isNegative then
   246                   AddAction(MadeActions, aia_LJump, 0, 305 + random(50), 0, 0);
   258                         AddAction(MadeActions, aia_LookLeft, 0, 200, 0, 0)
   247 
   259                     else
   248        if not CanGo then break;
   260                         AddAction(MadeActions, aia_LookRight, 0, 200, 0, 0);
   249        inc(steps);
   261                     end;
   250        Actions.actions[Pred(Actions.Count)].Param:= hwRound(Me^.X);
   262         if (BotLevel < 3) and (GoInfo.JumpType = jmpLJump) then // ljump support
   251        Rate:= RatePlace(Me);
   263             if Push(ticks, Actions, AltMe, Me^.Message) then
   252        if Rate > BestRate then
   264                 with Stack.States[Pred(Stack.Count)] do
   253           begin
   265                     AddAction(MadeActions, aia_LJump, 0, 305 + random(50), 0, 0);
   254           BestActions:= Actions;
   266 
   255           BestActions.isWalkingToABetterPlace:= true;
   267         if not CanGo then
   256           BestRate:= Rate;
   268             break;
   257           Me^.State:= Me^.State or gstAttacked // we have better place, go there and do not use ammo
   269         inc(steps);
   258           end
   270          Actions.actions[Pred(Actions.Count)].Param:= hwRound(Me^.X);
   259        else if Rate < BestRate then break;
   271          Rate:= RatePlace(Me);
   260        if ((Me^.State and gstAttacked) = 0)
   272          if Rate > BestRate then
   261            and ((steps mod 4) = 0) then TestAmmos(Actions, Me, true);
   273             begin
   262        if GoInfo.FallPix >= FallPixForBranching then
   274             BestActions:= Actions;
   263           Push(ticks, Actions, Me^, Me^.Message xor 3); // aia_Left xor 3 = aia_Right
   275             BestActions.isWalkingToABetterPlace:= true;
   264        end;
   276             BestRate:= Rate;
   265 
   277             Me^.State:= Me^.State or gstAttacked // we have better place, go there and do not use ammo
   266     if BestRate > BaseRate then exit
   278             end
   267     end
   279         else if Rate < BestRate then
       
   280             break;
       
   281         if ((Me^.State and gstAttacked) = 0) and ((steps mod 4) = 0) then
       
   282             TestAmmos(Actions, Me, true);
       
   283         if GoInfo.FallPix >= FallPixForBranching then
       
   284             Push(ticks, Actions, Me^, Me^.Message xor 3); // aia_Left xor 3 = aia_Right
       
   285         end;
       
   286 
       
   287     if BestRate > BaseRate then
       
   288         exit
       
   289         end
   268 end;
   290 end;
   269 
   291 
   270 function Think(Me: Pointer): ptrint;
   292 function Think(Me: Pointer): ptrint;
   271 var BackMe, WalkMe: TGear;
   293 var BackMe, WalkMe: TGear;
   272     StartTicks, currHedgehogIndex, itHedgehog, switchesNum, i: Longword;
   294     StartTicks, currHedgehogIndex, itHedgehog, switchesNum, i: Longword;
   281 
   303 
   282 switchImmediatelyAvailable:= (CurAmmoGear <> nil) and (CurAmmoGear^.Kind = gtSwitcher);
   304 switchImmediatelyAvailable:= (CurAmmoGear <> nil) and (CurAmmoGear^.Kind = gtSwitcher);
   283 switchAvailable:= HHHasAmmo(PGear(Me)^.Hedgehog^, amSwitch);
   305 switchAvailable:= HHHasAmmo(PGear(Me)^.Hedgehog^, amSwitch);
   284 
   306 
   285 if (PGear(Me)^.State and gstAttacked) = 0 then
   307 if (PGear(Me)^.State and gstAttacked) = 0 then
   286    if Targets.Count > 0 then
   308     if Targets.Count > 0 then
   287       begin
   309         begin
   288         // iterate over current team hedgehogs
   310         // iterate over current team hedgehogs
   289         repeat
   311         repeat
   290             WalkMe:= CurrentTeam^.Hedgehogs[itHedgehog].Gear^;
   312             WalkMe:= CurrentTeam^.Hedgehogs[itHedgehog].Gear^;
   291 
   313 
   292             Actions.Count:= 0;
   314             Actions.Count:= 0;
   316         until (not (switchImmediatelyAvailable or switchAvailable))
   338         until (not (switchImmediatelyAvailable or switchAvailable))
   317             or StopThinking 
   339             or StopThinking 
   318             or (itHedgehog = currHedgehogIndex)
   340             or (itHedgehog = currHedgehogIndex)
   319             or BestActions.isWalkingToABetterPlace;
   341             or BestActions.isWalkingToABetterPlace;
   320 
   342 
   321         if (StartTicks > GameTicks - 1500) and (not StopThinking) then SDL_Delay(1000);
   343         if (StartTicks > GameTicks - 1500) and (not StopThinking) then
       
   344             SDL_Delay(1000);
   322 
   345 
   323         if (BestActions.Score < -1023) and (not BestActions.isWalkingToABetterPlace) then
   346         if (BestActions.Score < -1023) and (not BestActions.isWalkingToABetterPlace) then
   324             begin
   347             begin
   325             BestActions.Count:= 0;
   348             BestActions.Count:= 0;
   326             AddAction(BestActions, aia_Skip, 0, 250, 0, 0);
   349             AddAction(BestActions, aia_Skip, 0, 250, 0, 0);
   327             end;
   350             end;
   328 
   351 
   329       end else
   352         end else
   330 else begin
   353 else
       
   354     begin
   331     BackMe:= PGear(Me)^;
   355     BackMe:= PGear(Me)^;
   332     while (not StopThinking) and (BestActions.Count = 0) do
   356     while (not StopThinking) and (BestActions.Count = 0) do
   333         begin
   357         begin
   334         FillBonuses(true);
   358         FillBonuses(true);
   335         WalkMe:= BackMe;
   359         WalkMe:= BackMe;
   336         Actions.Count:= 0;
   360         Actions.Count:= 0;
   337         Actions.Pos:= 0;
   361         Actions.Pos:= 0;
   338         Actions.Score:= 0;
   362         Actions.Score:= 0;
   339         Walk(@WalkMe, Actions);
   363         Walk(@WalkMe, Actions);
   340         if not StopThinking then SDL_Delay(100)
   364         if not StopThinking then
       
   365             SDL_Delay(100)
   341         end
   366         end
   342     end;
   367     end;
   343 
   368 
   344 PGear(Me)^.State:= PGear(Me)^.State and not gstHHThinking;
   369 PGear(Me)^.State:= PGear(Me)^.State and not gstHHThinking;
   345 Think:= 0;
   370 Think:= 0;
   347 end;
   372 end;
   348 
   373 
   349 procedure StartThink(Me: PGear);
   374 procedure StartThink(Me: PGear);
   350 begin
   375 begin
   351 if ((Me^.State and (gstAttacking or gstHHJumping or gstMoving)) <> 0)
   376 if ((Me^.State and (gstAttacking or gstHHJumping or gstMoving)) <> 0)
   352    or isInMultiShoot then exit;
   377 or isInMultiShoot then
       
   378     exit;
   353 
   379 
   354 //DeleteCI(Me); // this might break demo
   380 //DeleteCI(Me); // this might break demo
   355 Me^.State:= Me^.State or gstHHThinking;
   381 Me^.State:= Me^.State or gstHHThinking;
   356 Me^.Message:= 0;
   382 Me^.Message:= 0;
   357 
   383 
   363 StopThinking:= false;
   389 StopThinking:= false;
   364 ThinkingHH:= Me;
   390 ThinkingHH:= Me;
   365 
   391 
   366 FillTargets;
   392 FillTargets;
   367 if Targets.Count = 0 then
   393 if Targets.Count = 0 then
   368    begin
   394     begin
   369    OutError('AI: no targets!?', false);
   395     OutError('AI: no targets!?', false);
   370    exit
   396     exit
   371    end;
   397     end;
   372 
   398 
   373 FillBonuses((Me^.State and gstAttacked) <> 0);
   399 FillBonuses((Me^.State and gstAttacked) <> 0);
   374 AddFileLog('Enter Think Thread');
   400 AddFileLog('Enter Think Thread');
   375 {$IFDEF USE_SDLTHREADS}
   401 {$IFDEF USE_SDLTHREADS}
   376 ThinkThread := SDL_CreateThread(@Think{$IFDEF SDL13}, nil{$ENDIF}, Me);
   402 ThinkThread := SDL_CreateThread(@Think{$IFDEF SDL13}, nil{$ENDIF}, Me);
   383 procedure ProcessBot;
   409 procedure ProcessBot;
   384 const StartTicks: Longword = 0;
   410 const StartTicks: Longword = 0;
   385       cStopThinkTime = 40;
   411       cStopThinkTime = 40;
   386 begin
   412 begin
   387 with CurrentHedgehog^ do
   413 with CurrentHedgehog^ do
   388      if (Gear <> nil)
   414     if (Gear <> nil)
   389         and ((Gear^.State and gstHHDriven) <> 0)
   415     and ((Gear^.State and gstHHDriven) <> 0)
   390         and (TurnTimeLeft < cHedgehogTurnTime - 50) then
   416     and (TurnTimeLeft < cHedgehogTurnTime - 50) then
   391         if ((Gear^.State and gstHHThinking) = 0) then
   417         if ((Gear^.State and gstHHThinking) = 0) then
   392            if (BestActions.Pos >= BestActions.Count)
   418             if (BestActions.Pos >= BestActions.Count)
   393               and (TurnTimeLeft > cStopThinkTime) then
   419             and (TurnTimeLeft > cStopThinkTime) then
   394               begin
   420                 begin
   395               if Gear^.Message <> 0 then
   421                 if Gear^.Message <> 0 then
   396                  begin
   422                     begin
   397                  StopMessages(Gear^.Message);
   423                     StopMessages(Gear^.Message);
   398                  TryDo((Gear^.Message and gmAllStoppable) = 0, 'Engine bug: AI may break demos playing', true);
   424                     TryDo((Gear^.Message and gmAllStoppable) = 0, 'Engine bug: AI may break demos playing', true);
   399                  end;
   425                     end;
   400               if Gear^.Message <> 0 then exit;
   426                 if Gear^.Message <> 0 then
   401               StartThink(Gear);
   427                     exit;
   402               StartTicks:= GameTicks
   428                 StartThink(Gear);
   403               end else ProcessAction(BestActions, Gear)
   429                 StartTicks:= GameTicks
       
   430                 
       
   431                 end else
       
   432                     ProcessAction(BestActions, Gear)
   404         else if ((GameTicks - StartTicks) > cMaxAIThinkTime)
   433         else if ((GameTicks - StartTicks) > cMaxAIThinkTime)
   405                 or (TurnTimeLeft <= cStopThinkTime) then StopThinking:= true
   434         or (TurnTimeLeft <= cStopThinkTime) then
       
   435             StopThinking:= true
   406 end;
   436 end;
   407 
   437 
   408 procedure initModule;
   438 procedure initModule;
   409 begin
   439 begin
   410     hasThread:= 0;
   440     hasThread:= 0;