hedgewars/uAI.pas
branchwebgl
changeset 9127 e350500c4edb
parent 8833 c13ebed437cb
parent 9080 9b42757d7e71
child 9521 8054d9d775fd
equal deleted inserted replaced
8860:bde641cf53c8 9127:e350500c4edb
     1 (*
     1 (*
     2  * Hedgewars, a free turn based strategy game
     2  * Hedgewars, a free turn based strategy game
     3  * Copyright (c) 2004-2012 Andrey Korotaev <unC0Rr@gmail.com>
     3  * Copyright (c) 2004-2013 Andrey Korotaev <unC0Rr@gmail.com>
     4  *
     4  *
     5  * This program is free software; you can redistribute it and/or modify
     5  * This program is free software; you can redistribute it and/or modify
     6  * it under the terms of the GNU General Public License as published by
     6  * it under the terms of the GNU General Public License as published by
     7  * the Free Software Foundation; version 2 of the License
     7  * the Free Software Foundation; version 2 of the License
     8  *
     8  *
    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, uTypes,
    34     uVariables, uCommands, uUtils, uDebug, uAILandMarks;
    34     uVariables, uCommands, uUtils, uDebug, uAILandMarks;
    35 
    35 
    36 {$IFDEF AI_MAINTHREAD}
    36 {$IFDEF AI_MAINTHREAD}
    37 const
    37 const
    38     mainThreadMaxThinkTime:Integer = 1500;
    38     mainThreadMaxThinkTime:Integer = 1500;
    39 {$ENDIF}
    39 {$ENDIF}
    40 
    40 
    41 var BestActions: TActions;
    41 var BestActions: TActions;
    42     CanUseAmmo: array [TAmmoType] of boolean;
    42     CanUseAmmo: array [TAmmoType] of boolean;
    43     StopThinking: boolean;
    43     StopThinking: boolean;
    44 {$IFDEF USE_SDLTHREADS} 
    44     StartTicks: Longword;
    45     ThinkThread: PSDL_Thread = nil;
    45     ThinkThread: PSDL_Thread;
    46 {$ELSE}
    46     ThreadLock: PSDL_Mutex;
    47     ThinkThread: TThreadID;
       
    48 {$ENDIF}
       
    49     hasThread: LongInt;
       
    50     StartTicks: LongInt;
       
    51 
    47 
    52 procedure FreeActionsList;
    48 procedure FreeActionsList;
    53 begin
    49 begin
    54     AddFileLog('FreeActionsList called');
    50     AddFileLog('FreeActionsList called');
    55     if hasThread <> 0 then
    51     if (ThinkThread <> nil) then
    56     begin
    52         begin
    57         AddFileLog('Waiting AI thread to finish');
       
    58         StopThinking:= true;
    53         StopThinking:= true;
    59         repeat
    54         SDL_WaitThread(ThinkThread, nil);
    60             SDL_Delay(10)
    55         end;
    61         until hasThread = 0
    56     SDL_LockMutex(ThreadLock);
    62     end;
    57     ThinkThread:= nil;
       
    58     SDL_UnlockMutex(ThreadLock);
    63 
    59 
    64     with CurrentHedgehog^ do
    60     with CurrentHedgehog^ do
    65         if Gear <> nil then
    61         if Gear <> nil then
    66             if BotLevel <> 0 then
    62             if BotLevel <> 0 then
    67                 StopMessages(Gear^.Message);
    63                 StopMessages(Gear^.Message);
    68 
    64 
    69     BestActions.Count:= 0;
    65     BestActions.Count:= 0;
    70     BestActions.Pos:= 0
    66     BestActions.Pos:= 0
    71 end;
    67 end;
    72 
       
    73 
    68 
    74 
    69 
    75 const cBranchStackSize = 12;
    70 const cBranchStackSize = 12;
    76 type TStackEntry = record
    71 type TStackEntry = record
    77                    WastedTicks: Longword;
    72                    WastedTicks: Longword;
   126     if (Targets.ar[i].Score >= 0) and (not StopThinking) then
   121     if (Targets.ar[i].Score >= 0) and (not StopThinking) then
   127         begin
   122         begin
   128         with Me^.Hedgehog^ do
   123         with Me^.Hedgehog^ do
   129             a:= CurAmmoType;
   124             a:= CurAmmoType;
   130         aa:= a;
   125         aa:= a;
   131 {$IFDEF USE_SDLTHREADS}
   126         SDL_delay(0); // hint to let the context switch run
   132         SDL_delay(0);    //ThreadSwitch was only a hint
       
   133 {$ELSE}
       
   134         ThreadSwitch();
       
   135 {$ENDIF}       
       
   136         repeat
   127         repeat
   137         if (CanUseAmmo[a]) 
   128         if (CanUseAmmo[a])
   138             and ((not rareChecks) or ((AmmoTests[a].flags and amtest_Rare) = 0)) 
   129             and ((not rareChecks) or ((AmmoTests[a].flags and amtest_Rare) = 0))
   139             and ((i = 0) or ((AmmoTests[a].flags and amtest_NoTarget) = 0)) 
   130             and ((i = 0) or ((AmmoTests[a].flags and amtest_NoTarget) = 0))
   140             then
   131             then
   141             begin
   132             begin
   142 {$HINTS OFF}
   133 {$HINTS OFF}
   143             Score:= AmmoTests[a].proc(Me, Targets.ar[i].Point, BotLevel, ap);
   134             Score:= AmmoTests[a].proc(Me, Targets.ar[i], BotLevel, ap);
   144 {$HINTS ON}
   135 {$HINTS ON}
   145             if Actions.Score + Score > BestActions.Score then
   136             if Actions.Score + Score > BestActions.Score then
   146                 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 - 1) * 2048) then
   147                     begin
   138                     begin
   148                     BestActions:= Actions;
   139                     BestActions:= Actions;
   149                     inc(BestActions.Score, Score);
   140                     inc(BestActions.Score, Score);
   150                     BestActions.isWalkingToABetterPlace:= false;
   141                     BestActions.isWalkingToABetterPlace:= false;
   151 
   142 
   153 
   144 
   154                     if (ap.Angle > 0) then
   145                     if (ap.Angle > 0) then
   155                         AddAction(BestActions, aia_LookRight, 0, 200, 0, 0)
   146                         AddAction(BestActions, aia_LookRight, 0, 200, 0, 0)
   156                     else if (ap.Angle < 0) then
   147                     else if (ap.Angle < 0) then
   157                         AddAction(BestActions, aia_LookLeft, 0, 200, 0, 0);
   148                         AddAction(BestActions, aia_LookLeft, 0, 200, 0, 0);
   158                     
   149 
   159                     if (Ammoz[a].Ammo.Propz and ammoprop_Timerable) <> 0 then
   150                     if (Ammoz[a].Ammo.Propz and ammoprop_Timerable) <> 0 then
   160                         AddAction(BestActions, aia_Timer, ap.Time div 1000, 400, 0, 0);
   151                         AddAction(BestActions, aia_Timer, ap.Time div 1000, 400, 0, 0);
   161                         
   152 
   162                     if (Ammoz[a].Ammo.Propz and ammoprop_NoCrosshair) = 0 then
   153                     if (Ammoz[a].Ammo.Propz and ammoprop_NoCrosshair) = 0 then
   163                         begin
   154                         begin
   164                         dAngle:= LongInt(Me^.Angle) - Abs(ap.Angle);
   155                         dAngle:= LongInt(Me^.Angle) - Abs(ap.Angle);
   165                         if dAngle > 0 then
   156                         if dAngle > 0 then
   166                             begin
   157                             begin
   171                             begin
   162                             begin
   172                             AddAction(BestActions, aia_Down, aim_push, 300 + random(250), 0, 0);
   163                             AddAction(BestActions, aia_Down, aim_push, 300 + random(250), 0, 0);
   173                             AddAction(BestActions, aia_Down, aim_release, -dAngle, 0, 0)
   164                             AddAction(BestActions, aia_Down, aim_release, -dAngle, 0, 0)
   174                             end
   165                             end
   175                         end;
   166                         end;
   176                         
   167 
   177                     if (Ammoz[a].Ammo.Propz and ammoprop_NeedTarget) <> 0 then
   168                     if (Ammoz[a].Ammo.Propz and ammoprop_NeedTarget) <> 0 then
   178                         begin
   169                         begin
   179                         AddAction(BestActions, aia_Put, 0, 1, ap.AttackPutX, ap.AttackPutY)
   170                         AddAction(BestActions, aia_Put, 0, 1, ap.AttackPutX, ap.AttackPutY)
   180                         end;
   171                         end;
   181                         
   172 
   182                     if (Ammoz[a].Ammo.Propz and ammoprop_OscAim) <> 0 then
   173                     if (Ammoz[a].Ammo.Propz and ammoprop_OscAim) <> 0 then
   183                         begin
   174                         begin
   184                         AddAction(BestActions, aia_attack, aim_push, 350 + random(200), 0, 0);
   175                         AddAction(BestActions, aia_attack, aim_push, 350 + random(200), 0, 0);
   185                         AddAction(BestActions, aia_attack, aim_release, 1, 0, 0);
   176                         AddAction(BestActions, aia_attack, aim_release, 1, 0, 0);
   186                          
   177 
   187                         if abs(ap.Angle) > 32 then
   178                         if abs(ap.Angle) > 32 then
   188                            begin
   179                            begin
   189                            AddAction(BestActions, aia_Down, aim_push, 100 + random(150), 0, 0);
   180                            AddAction(BestActions, aia_Down, aim_push, 100 + random(150), 0, 0);
   190                            AddAction(BestActions, aia_Down, aim_release, 32, 0, 0);
   181                            AddAction(BestActions, aia_Down, aim_release, 32, 0, 0);
   191                            end;
   182                            end;
   192                         
   183 
   193                         AddAction(BestActions, aia_waitAngle, ap.Angle, 250, 0, 0);
   184                         AddAction(BestActions, aia_waitAngle, ap.Angle, 250, 0, 0);
   194                         AddAction(BestActions, aia_attack, aim_push, 1, 0, 0);
   185                         AddAction(BestActions, aia_attack, aim_push, 1, 0, 0);
   195                         AddAction(BestActions, aia_attack, aim_release, 1, 0, 0);
   186                         AddAction(BestActions, aia_attack, aim_release, 1, 0, 0);
   196                         end else
   187                         end else
   197                         if (Ammoz[a].Ammo.Propz and ammoprop_AttackingPut) = 0 then
   188                         if (Ammoz[a].Ammo.Propz and ammoprop_AttackingPut) = 0 then
   246 else
   237 else
   247     maxticks:= TurnTimeLeft;
   238     maxticks:= TurnTimeLeft;
   248 
   239 
   249 if (Me^.State and gstAttacked) = 0 then
   240 if (Me^.State and gstAttacked) = 0 then
   250     TestAmmos(Actions, Me, false);
   241     TestAmmos(Actions, Me, false);
   251     
   242 
   252 BestRate:= RatePlace(Me);
   243 BestRate:= RatePlace(Me);
   253 BaseRate:= Max(BestRate, 0);
   244 BaseRate:= Max(BestRate, 0);
   254 
   245 
   255 // switch to 'skip' if we can't move because of mouse cursor being shown
   246 // switch to 'skip' if we cannot move because of mouse cursor being shown
   256 if (Ammoz[Me^.Hedgehog^.CurAmmoType].Ammo.Propz and ammoprop_NeedTarget) <> 0 then
   247 if (Ammoz[Me^.Hedgehog^.CurAmmoType].Ammo.Propz and ammoprop_NeedTarget) <> 0 then
   257     AddAction(Actions, aia_Weapon, Longword(amSkip), 100 + random(200), 0, 0);
   248     AddAction(Actions, aia_Weapon, Longword(amSkip), 100 + random(200), 0, 0);
   258     
   249 
   259 if ((CurrentHedgehog^.MultiShootAttacks = 0) or ((Ammoz[Me^.Hedgehog^.CurAmmoType].Ammo.Propz and ammoprop_NoMoveAfter) = 0)) 
   250 if ((CurrentHedgehog^.MultiShootAttacks = 0) or ((Ammoz[Me^.Hedgehog^.CurAmmoType].Ammo.Propz and ammoprop_NoMoveAfter) = 0))
   260     and (GameFlags and gfArtillery = 0) then
   251     and (GameFlags and gfArtillery = 0) then
   261     begin
   252     begin
   262     tmp:= random(2) + 1;
   253     tmp:= random(2) + 1;
   263     Push(0, Actions, Me^, tmp);
   254     Push(0, Actions, Me^, tmp);
   264     Push(0, Actions, Me^, tmp xor 3);
   255     Push(0, Actions, Me^, tmp xor 3);
   265     
   256 
   266     while (Stack.Count > 0) and (not StopThinking) do
   257     while (Stack.Count > 0) and (not StopThinking) do
   267         begin
   258         begin
   268         Pop(ticks, Actions, Me^);
   259         Pop(ticks, Actions, Me^);
   269 
   260 
   270         AddAction(Actions, Me^.Message, aim_push, 250, 0, 0);
   261         AddAction(Actions, Me^.Message, aim_push, 250, 0, 0);
   271         if (Me^.Message and gmLeft) <> 0 then
   262         if (Me^.Message and gmLeft) <> 0 then
   272             AddAction(Actions, aia_WaitXL, hwRound(Me^.X), 0, 0, 0)
   263             AddAction(Actions, aia_WaitXL, hwRound(Me^.X), 0, 0, 0)
   273         else
   264         else
   274             AddAction(Actions, aia_WaitXR, hwRound(Me^.X), 0, 0, 0);
   265             AddAction(Actions, aia_WaitXR, hwRound(Me^.X), 0, 0, 0);
   275         
   266 
   276         steps:= 0;
   267         steps:= 0;
   277 
   268 
   278         while (not StopThinking) do
   269         while (not StopThinking) do
   279             begin
   270             begin
   280     {$HINTS OFF}
   271     {$HINTS OFF}
   283             oldticks:= ticks;
   274             oldticks:= ticks;
   284             inc(ticks, GoInfo.Ticks);
   275             inc(ticks, GoInfo.Ticks);
   285             if ticks > maxticks then
   276             if ticks > maxticks then
   286                 break;
   277                 break;
   287 
   278 
   288             if (BotLevel < 5) 
   279             if (BotLevel < 5)
   289                 and (GoInfo.JumpType = jmpHJump) 
   280                 and (GoInfo.JumpType = jmpHJump)
   290                 and (not checkMark(hwRound(Me^.X), hwRound(Me^.Y), markHJumped))
   281                 and (not checkMark(hwRound(Me^.X), hwRound(Me^.Y), markHJumped))
   291                 then // hjump support
   282                 then // hjump support
   292                 begin
   283                 begin
   293                 // check if we could go backwards and maybe ljump over a gap after this hjump
   284                 // check if we could go backwards and maybe ljump over a gap after this hjump
   294                 addMark(hwRound(Me^.X), hwRound(Me^.Y), markHJumped);
   285                 addMark(hwRound(Me^.X), hwRound(Me^.Y), markHJumped);
   298                         begin
   289                         begin
   299                         if (Me^.Message and gmLeft) <> 0 then
   290                         if (Me^.Message and gmLeft) <> 0 then
   300                             AddAction(MadeActions, aia_LookRight, 0, 200, 0, 0)
   291                             AddAction(MadeActions, aia_LookRight, 0, 200, 0, 0)
   301                         else
   292                         else
   302                             AddAction(MadeActions, aia_LookLeft, 0, 200, 0, 0);
   293                             AddAction(MadeActions, aia_LookLeft, 0, 200, 0, 0);
   303                             
   294 
   304                         AddAction(MadeActions, aia_HJump, 0, 305 + random(50), 0, 0);
   295                         AddAction(MadeActions, aia_HJump, 0, 305 + random(50), 0, 0);
   305                         AddAction(MadeActions, aia_HJump, 0, 350, 0, 0);
   296                         AddAction(MadeActions, aia_HJump, 0, 350, 0, 0);
   306                         end;
   297                         end;
   307                     // but first check walking forward
   298                     // but first check walking forward
   308                     Push(ticks, Stack.States[Pred(Stack.Count)].MadeActions, AltMe, Me^.Message)
   299                     Push(ticks, Stack.States[Pred(Stack.Count)].MadeActions, AltMe, Me^.Message)
   309                     end;
   300                     end;
   310                 end;
   301                 end;
   311             if (BotLevel < 3) 
   302             if (BotLevel < 3)
   312                 and (GoInfo.JumpType = jmpLJump) 
   303                 and (GoInfo.JumpType = jmpLJump)
   313                 and (not checkMark(hwRound(Me^.X), hwRound(Me^.Y), markLJumped))
   304                 and (not checkMark(hwRound(Me^.X), hwRound(Me^.Y), markLJumped))
   314                 then // ljump support
   305                 then // ljump support
   315                 begin
   306                 begin
   316                 addMark(hwRound(Me^.X), hwRound(Me^.Y), markLJumped);
   307                 addMark(hwRound(Me^.X), hwRound(Me^.Y), markLJumped);
   317                 // at final check where we go after jump walking backward
   308                 // at final check where we go after jump walking backward
   326                         AddAction(MadeActions, aia_LJump, 0, 305 + random(50), 0, 0);
   317                         AddAction(MadeActions, aia_LJump, 0, 305 + random(50), 0, 0);
   327                         end;
   318                         end;
   328 
   319 
   329                 // push current position so we proceed from it after checking jump+forward walk opportunities
   320                 // push current position so we proceed from it after checking jump+forward walk opportunities
   330                 if CanGo then Push(ticks, Actions, Me^, Me^.Message);
   321                 if CanGo then Push(ticks, Actions, Me^, Me^.Message);
   331                 
   322 
   332                 // first check where we go after jump walking forward
   323                 // first check where we go after jump walking forward
   333                 if Push(ticks, Actions, AltMe, Me^.Message) then
   324                 if Push(ticks, Actions, AltMe, Me^.Message) then
   334                     with Stack.States[Pred(Stack.Count)] do
   325                     with Stack.States[Pred(Stack.Count)] do
   335                         AddAction(MadeActions, aia_LJump, 0, 305 + random(50), 0, 0);
   326                         AddAction(MadeActions, aia_LJump, 0, 305 + random(50), 0, 0);
   336                 break
   327                 break
   337                 end;
   328                 end;
   338 
   329 
   339             // 'not CanGO' means we can't go straight, possible jumps are checked above
   330             // 'not CanGO' means we cannot go straight, possible jumps are checked above
   340             if (not CanGo) then
   331             if not CanGo then
   341                 break;
   332                 break;
   342             
   333 
   343              inc(steps);
   334              inc(steps);
   344              Actions.actions[Pred(Actions.Count)].Param:= hwRound(Me^.X);
   335              Actions.actions[Pred(Actions.Count)].Param:= hwRound(Me^.X);
   345              Rate:= RatePlace(Me);
   336              Rate:= RatePlace(Me);
   346              if Rate > BestRate then
   337              if Rate > BestRate then
   347                 begin
   338                 begin
   350                 BestRate:= Rate;
   341                 BestRate:= Rate;
   351                 Me^.State:= Me^.State or gstAttacked // we have better place, go there and do not use ammo
   342                 Me^.State:= Me^.State or gstAttacked // we have better place, go there and do not use ammo
   352                 end
   343                 end
   353             else if Rate < BestRate then
   344             else if Rate < BestRate then
   354                 break;
   345                 break;
   355                 
   346 
   356             if ((Me^.State and gstAttacked) = 0) and ((steps mod 4) = 0) then
   347             if ((Me^.State and gstAttacked) = 0) and ((steps mod 4) = 0) then
   357                 begin
   348                 begin
   358                 if (steps > 4) and checkMark(hwRound(Me^.X), hwRound(Me^.Y), markWalkedHere) then
   349                 if (steps > 4) and checkMark(hwRound(Me^.X), hwRound(Me^.Y), markWalkedHere) then
   359                     break;                    
   350                     break;
   360                 addMark(hwRound(Me^.X), hwRound(Me^.Y), markWalkedHere);
   351                 addMark(hwRound(Me^.X), hwRound(Me^.Y), markWalkedHere);
   361 
   352 
   362                 TestAmmos(Actions, Me, ticks shr 12 = oldticks shr 12);
   353                 TestAmmos(Actions, Me, ticks shr 12 = oldticks shr 12);
   363                 
   354 
   364                 end;
   355                 end;
   365                 
   356 
   366             if GoInfo.FallPix >= FallPixForBranching then
   357             if GoInfo.FallPix >= FallPixForBranching then
   367                 Push(ticks, Actions, Me^, Me^.Message xor 3); // aia_Left xor 3 = aia_Right
   358                 Push(ticks, Actions, Me^, Me^.Message xor 3); // aia_Left xor 3 = aia_Right
   368 
   359 
   369 {$IFDEF AI_MAINTHREAD}
   360 {$IFDEF AI_MAINTHREAD}
   370             if StartTicks < (SDL_GetTicks() - mainThreadMaxThinkTime) then
   361             if StartTicks < (SDL_GetTicks() - mainThreadMaxThinkTime) then
   380             exit
   371             exit
   381         end {while}
   372         end {while}
   382     end {if}
   373     end {if}
   383 end;
   374 end;
   384 
   375 
   385 function Think(Me: Pointer): ptrint;
   376 function Think(Me: PGear): LongInt; cdecl; export;
   386 var BackMe, WalkMe: TGear;
   377 var BackMe, WalkMe: TGear;
   387     switchCount: LongInt;
   378     switchCount: LongInt;
   388     currHedgehogIndex, itHedgehog, switchesNum, i: Longword;
   379     currHedgehogIndex, itHedgehog, switchesNum, i: Longword;
   389     switchImmediatelyAvailable: boolean;
   380     switchImmediatelyAvailable: boolean;
   390     Actions: TActions;
   381     Actions: TActions;
   391 begin
   382 begin
   392 InterlockedIncrement(hasThread);
   383 dmgMod:= 0.01 * hwFloat2Float(cDamageModifier) * cDamagePercent;
   393 
       
   394 {$IFDEF AI_MAINTHREAD}
       
   395 StartTicks:= SDL_GetTicks();
       
   396 {$ELSE}
       
   397 StartTicks:= GameTicks;
   384 StartTicks:= GameTicks;
   398 {$ENDIF}
       
   399 
   385 
   400 currHedgehogIndex:= CurrentTeam^.CurrHedgehog;
   386 currHedgehogIndex:= CurrentTeam^.CurrHedgehog;
   401 itHedgehog:= currHedgehogIndex;
   387 itHedgehog:= currHedgehogIndex;
   402 switchesNum:= 0;
   388 switchesNum:= 0;
   403 
   389 
   404 switchImmediatelyAvailable:= (CurAmmoGear <> nil) and (CurAmmoGear^.Kind = gtSwitcher);
   390 switchImmediatelyAvailable:= (CurAmmoGear <> nil) and (CurAmmoGear^.Kind = gtSwitcher);
   405 if PGear(Me)^.Hedgehog^.BotLevel <> 5 then
   391 if Me^.Hedgehog^.BotLevel <> 5 then
   406     switchCount:= HHHasAmmo(PGear(Me)^.Hedgehog^, amSwitch)
   392     switchCount:= HHHasAmmo(PGear(Me)^.Hedgehog^, amSwitch)
   407 else switchCount:= 0;
   393 else switchCount:= 0;
   408 
   394 
   409 if (PGear(Me)^.State and gstAttacking) = 0 then
   395 if ((Me^.State and gstAttacked) = 0) or isInMultiShoot then
   410     if Targets.Count > 0 then
   396     if Targets.Count > 0 then
   411         begin
   397         begin
   412         // iterate over current team hedgehogs
   398         // iterate over current team hedgehogs
   413         repeat
   399         repeat
   414             WalkMe:= CurrentTeam^.Hedgehogs[itHedgehog].Gear^;
   400             WalkMe:= CurrentTeam^.Hedgehogs[itHedgehog].Gear^;
   420                 begin
   406                 begin
   421                 if (not switchImmediatelyAvailable)  then
   407                 if (not switchImmediatelyAvailable)  then
   422                     begin
   408                     begin
   423                     // when AI has to use switcher, make it cost smth unless they have a lot of switches
   409                     // when AI has to use switcher, make it cost smth unless they have a lot of switches
   424                     if (switchCount < 10) then Actions.Score:= (-27+switchCount*3)*4000;
   410                     if (switchCount < 10) then Actions.Score:= (-27+switchCount*3)*4000;
   425                     AddAction(Actions, aia_Weapon, Longword(amSwitch), 300 + random(200), 0, 0);                    
   411                     AddAction(Actions, aia_Weapon, Longword(amSwitch), 300 + random(200), 0, 0);
   426                     AddAction(Actions, aia_attack, aim_push, 300 + random(300), 0, 0);
   412                     AddAction(Actions, aia_attack, aim_push, 300 + random(300), 0, 0);
   427                     AddAction(Actions, aia_attack, aim_release, 1, 0, 0);
   413                     AddAction(Actions, aia_attack, aim_release, 1, 0, 0);
   428                     end;
   414                     end;
   429                 for i:= 1 to switchesNum do
   415                 for i:= 1 to switchesNum do
   430                     AddAction(Actions, aia_Switch, 0, 300 + random(200), 0, 0);
   416                     AddAction(Actions, aia_Switch, 0, 300 + random(200), 0, 0);
   434             // find another hog in team
   420             // find another hog in team
   435             repeat
   421             repeat
   436                 itHedgehog:= Succ(itHedgehog) mod CurrentTeam^.HedgehogsNumber;
   422                 itHedgehog:= Succ(itHedgehog) mod CurrentTeam^.HedgehogsNumber;
   437             until (itHedgehog = currHedgehogIndex) or ((CurrentTeam^.Hedgehogs[itHedgehog].Gear <> nil) and (CurrentTeam^.Hedgehogs[itHedgehog].Effects[heFrozen]=0));
   423             until (itHedgehog = currHedgehogIndex) or ((CurrentTeam^.Hedgehogs[itHedgehog].Gear <> nil) and (CurrentTeam^.Hedgehogs[itHedgehog].Effects[heFrozen]=0));
   438 
   424 
   439 
       
   440             inc(switchesNum);
   425             inc(switchesNum);
   441         until (not (switchImmediatelyAvailable or (switchCount > 0)))
   426         until (not (switchImmediatelyAvailable or (switchCount > 0)))
   442             or StopThinking 
   427             or StopThinking
   443             or (itHedgehog = currHedgehogIndex)
   428             or (itHedgehog = currHedgehogIndex)
   444             or BestActions.isWalkingToABetterPlace;
   429             or BestActions.isWalkingToABetterPlace;
   445 
   430 
   446             {$IFDEF AI_MAINTHREAD}
   431             {$IFDEF AI_MAINTHREAD}
   447                 if StartTicks < (SDL_GetTicks() - mainThreadMaxThinkTime) then
   432                 if StartTicks < (SDL_GetTicks() - mainThreadMaxThinkTime) then
   458             end;
   443             end;
   459 
   444 
   460         end else SDL_Delay(100)
   445         end else SDL_Delay(100)
   461 else
   446 else
   462     begin
   447     begin
   463     BackMe:= PGear(Me)^;
   448     BackMe:= Me^;
   464     
   449     i:= 12;
   465 //{$IFNDEF AI_MAINTHREAD}
   450     while (not StopThinking) and (BestActions.Count = 0) and (i > 0) do
   466     while (not StopThinking) and (BestActions.Count = 0) do
       
   467         begin
   451         begin
   468 
   452 
   469 (*
   453 (*
   470         // Maybe this would get a bit of movement out of them? Hopefully not *toward* water. Need to check how often he'd choose that strategy
   454         // Maybe this would get a bit of movement out of them? Hopefully not *toward* water. Need to check how often he'd choose that strategy
   471         if SuddenDeathDmg and ((hwRound(BackMe.Y)+cWaterRise*2) > cWaterLine) then
   455         if SuddenDeathDmg and ((hwRound(BackMe.Y)+cWaterRise*2) > cWaterLine) then
   476         WalkMe:= BackMe;
   460         WalkMe:= BackMe;
   477         Actions.Count:= 0;
   461         Actions.Count:= 0;
   478         Actions.Pos:= 0;
   462         Actions.Pos:= 0;
   479         Actions.Score:= 0;
   463         Actions.Score:= 0;
   480         Walk(@WalkMe, Actions);
   464         Walk(@WalkMe, Actions);
   481 {$IFNDEF AI_MAINTHREAD}
   465         dec(i);
   482         if (not StopThinking) then
   466         if not StopThinking then
   483             SDL_Delay(100)
   467             SDL_Delay(100)
   484 {$ENDIF}
       
   485         end
   468         end
   486 //{$ENDIF}
       
   487     end;
   469     end;
   488 
   470 
   489 PGear(Me)^.State:= PGear(Me)^.State and (not gstHHThinking);
   471 Me^.State:= Me^.State and (not gstHHThinking);
       
   472 SDL_LockMutex(ThreadLock);
       
   473 ThinkThread:= nil;
       
   474 SDL_UnlockMutex(ThreadLock);
   490 Think:= 0;
   475 Think:= 0;
   491 InterlockedDecrement(hasThread)
       
   492 end;
   476 end;
   493 
   477 
   494 procedure StartThink(Me: PGear);
   478 procedure StartThink(Me: PGear);
   495 begin
   479 begin
   496 if ((Me^.State and (gstAttacking or gstHHJumping or gstMoving)) <> 0)
   480 if ((Me^.State and (gstAttacking or gstHHJumping or gstMoving)) <> 0)
   515     begin
   499     begin
   516     OutError('AI: no targets!?', false);
   500     OutError('AI: no targets!?', false);
   517     exit
   501     exit
   518     end;
   502     end;
   519 
   503 
   520 FillBonuses((Me^.State and gstAttacked) <> 0);
   504 FillBonuses(((Me^.State and gstAttacked) <> 0) and (not isInMultiShoot));
   521 AddFileLog('Enter Think Thread');
   505 
   522 
   506 SDL_LockMutex(ThreadLock);
   523 {$IFDEF AI_MAINTHREAD}
   507 ThinkThread:= SDL_CreateThread(@Think{$IFDEF SDL13}, 'think'{$ENDIF}, Me);
   524 Think(Me);
   508 SDL_UnlockMutex(ThreadLock);
   525 {$ELSE}
   509 end;
   526 {$IFDEF USE_SDLTHREADS}
   510 
   527 ThinkThread := SDL_CreateThread(@Think{$IFDEF SDL13}, nil{$ENDIF}, Me);
   511 {$IFDEF DEBUGAI}
   528 {$ELSE}
   512 var scoreShown: boolean = false;
   529 BeginThread(@Think, Me, ThinkThread);
       
   530 {$ENDIF}
   513 {$ENDIF}
   531 AddFileLog('Thread started');
       
   532 {$ENDIF}
       
   533 end;
       
   534 
       
   535 //var scoreShown: boolean = false;
       
   536 
   514 
   537 procedure ProcessBot;
   515 procedure ProcessBot;
   538 const cStopThinkTime = 40;
   516 const cStopThinkTime = 40;
   539 begin
   517 begin
   540 with CurrentHedgehog^ do
   518 with CurrentHedgehog^ do
   548                 if Gear^.Message <> 0 then
   526                 if Gear^.Message <> 0 then
   549                     begin
   527                     begin
   550                     StopMessages(Gear^.Message);
   528                     StopMessages(Gear^.Message);
   551                     TryDo((Gear^.Message and gmAllStoppable) = 0, 'Engine bug: AI may break demos playing', true);
   529                     TryDo((Gear^.Message and gmAllStoppable) = 0, 'Engine bug: AI may break demos playing', true);
   552                     end;
   530                     end;
   553                     
   531 
   554                 if Gear^.Message <> 0 then
   532                 if Gear^.Message <> 0 then
   555                     exit;
   533                     exit;
   556                     
   534 
   557                 //scoreShown:= false;   
   535 {$IFDEF DEBUGAI}
       
   536                 scoreShown:= false;
       
   537 {$ENDIF}
   558                 StartThink(Gear);
   538                 StartThink(Gear);
   559                 StartTicks:= GameTicks
   539                 StartTicks:= GameTicks
   560                 
   540 
   561             end else
   541             end else
   562                 begin
   542                 begin
   563                 {if not scoreShown then
   543 {$IFDEF DEBUGAI}
       
   544                 if not scoreShown then
   564                     begin
   545                     begin
   565                     if BestActions.Score > 0 then ParseCommand('/say Expected score = ' + inttostr(BestActions.Score div 1024), true);
   546                     if BestActions.Score > 0 then ParseCommand('/say Expected score = ' + inttostr(BestActions.Score div 1024), true);
   566                     scoreShown:= true
   547                     scoreShown:= true
   567                     end;}
   548                     end;
       
   549 {$ENDIF}
   568                 ProcessAction(BestActions, Gear)
   550                 ProcessAction(BestActions, Gear)
   569                 end
   551                 end
   570         else if ((GameTicks - StartTicks) > cMaxAIThinkTime)
   552         else if ((GameTicks - StartTicks) > cMaxAIThinkTime)
   571             or (TurnTimeLeft <= cStopThinkTime) then
   553             or (TurnTimeLeft <= cStopThinkTime) then
   572                 StopThinking:= true
   554                 StopThinking:= true
   573 end;
   555 end;
   574 
   556 
   575 procedure initModule;
   557 procedure initModule;
   576 begin
   558 begin
   577     hasThread:= 0;
       
   578     StartTicks:= 0;
   559     StartTicks:= 0;
   579 {$IFNDEF PAS2C}
   560     ThinkThread:= nil;
   580     ThinkThread:= ThinkThread;
   561     ThreadLock:= SDL_CreateMutex();
   581 {$ENDIF}
       
   582 end;
   562 end;
   583 
   563 
   584 procedure freeModule;
   564 procedure freeModule;
   585 begin
   565 begin
   586     FreeActionsList();
   566     FreeActionsList();
       
   567     SDL_DestroyMutex(ThreadLock);
   587 end;
   568 end;
   588 
   569 
   589 end.
   570 end.