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