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 |
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. |