57 StopMessages(Gear^.Message); |
57 StopMessages(Gear^.Message); |
58 |
58 |
59 BestActions.Count:= 0; |
59 BestActions.Count:= 0; |
60 BestActions.Pos:= 0 |
60 BestActions.Pos:= 0 |
61 end; |
61 end; |
|
62 |
|
63 |
|
64 |
|
65 const cBranchStackSize = 12; |
|
66 type TStackEntry = record |
|
67 WastedTicks: Longword; |
|
68 MadeActions: TActions; |
|
69 Hedgehog: TGear; |
|
70 end; |
|
71 |
|
72 var Stack: record |
|
73 Count: Longword; |
|
74 States: array[0..Pred(cBranchStackSize)] of TStackEntry; |
|
75 end; |
|
76 |
|
77 function Push(Ticks: Longword; const Actions: TActions; const Me: TGear; Dir: integer): boolean; |
|
78 var bRes: boolean; |
|
79 begin |
|
80 bRes:= (Stack.Count < cBranchStackSize) and (Actions.Count < MAXACTIONS - 5); |
|
81 if bRes then |
|
82 with Stack.States[Stack.Count] do |
|
83 begin |
|
84 WastedTicks:= Ticks; |
|
85 MadeActions:= Actions; |
|
86 Hedgehog:= Me; |
|
87 Hedgehog.Message:= Dir; |
|
88 inc(Stack.Count) |
|
89 end; |
|
90 Push:= bRes |
|
91 end; |
|
92 |
|
93 procedure Pop(var Ticks: Longword; var Actions: TActions; var Me: TGear); |
|
94 begin |
|
95 dec(Stack.Count); |
|
96 with Stack.States[Stack.Count] do |
|
97 begin |
|
98 Ticks:= WastedTicks; |
|
99 Actions:= MadeActions; |
|
100 Me:= Hedgehog |
|
101 end |
|
102 end; |
|
103 |
|
104 |
62 |
105 |
63 procedure TestAmmos(var Actions: TActions; Me: PGear; isMoved: boolean); |
106 procedure TestAmmos(var Actions: TActions; Me: PGear; isMoved: boolean); |
64 var BotLevel: Byte; |
107 var BotLevel: Byte; |
65 ap: TAttackParams; |
108 ap: TAttackParams; |
66 Score, i: LongInt; |
109 Score, i: LongInt; |
87 if Actions.Score + Score > BestActions.Score then |
130 if Actions.Score + Score > BestActions.Score then |
88 if (BestActions.Score < 0) or (Actions.Score + Score > BestActions.Score + Byte(BotLevel) * 2048) then |
131 if (BestActions.Score < 0) or (Actions.Score + Score > BestActions.Score + Byte(BotLevel) * 2048) then |
89 begin |
132 begin |
90 BestActions:= Actions; |
133 BestActions:= Actions; |
91 inc(BestActions.Score, Score); |
134 inc(BestActions.Score, Score); |
|
135 BestActions.isWalkingToABetterPlace:= false; |
92 |
136 |
93 if (ap.Angle > 0) then AddAction(BestActions, aia_LookRight, 0, 200, 0, 0) |
137 if (ap.Angle > 0) then AddAction(BestActions, aia_LookRight, 0, 200, 0, 0) |
94 else if (ap.Angle < 0) then AddAction(BestActions, aia_LookLeft, 0, 200, 0, 0); |
138 else if (ap.Angle < 0) then AddAction(BestActions, aia_LookLeft, 0, 200, 0, 0); |
95 |
139 |
96 AddAction(BestActions, aia_Weapon, Longword(a), 300 + random(400), 0, 0); |
140 AddAction(BestActions, aia_Weapon, Longword(a), 300 + random(400), 0, 0); |
127 (CurrentHedgehog^.MultiShootAttacks > 0) or // shooting same weapon |
171 (CurrentHedgehog^.MultiShootAttacks > 0) or // shooting same weapon |
128 StopThinking |
172 StopThinking |
129 end |
173 end |
130 end; |
174 end; |
131 |
175 |
132 procedure Walk(Me: PGear); |
176 procedure Walk(Me: PGear; var Actions: TActions); |
133 const FallPixForBranching = cHHRadius * 2 + 8; |
177 const FallPixForBranching = cHHRadius * 2 + 8; |
134 cBranchStackSize = 12; |
178 var |
135 |
|
136 type TStackEntry = record |
|
137 WastedTicks: Longword; |
|
138 MadeActions: TActions; |
|
139 Hedgehog: TGear; |
|
140 end; |
|
141 |
|
142 var Stack: record |
|
143 Count: Longword; |
|
144 States: array[0..Pred(cBranchStackSize)] of TStackEntry; |
|
145 end; |
|
146 |
|
147 function Push(Ticks: Longword; const Actions: TActions; const Me: TGear; Dir: integer): boolean; |
|
148 var bRes: boolean; |
|
149 begin |
|
150 bRes:= (Stack.Count < cBranchStackSize) and (Actions.Count < MAXACTIONS - 5); |
|
151 if bRes then |
|
152 with Stack.States[Stack.Count] do |
|
153 begin |
|
154 WastedTicks:= Ticks; |
|
155 MadeActions:= Actions; |
|
156 Hedgehog:= Me; |
|
157 Hedgehog.Message:= Dir; |
|
158 inc(Stack.Count) |
|
159 end; |
|
160 Push:= bRes |
|
161 end; |
|
162 |
|
163 procedure Pop(var Ticks: Longword; var Actions: TActions; var Me: TGear); |
|
164 begin |
|
165 dec(Stack.Count); |
|
166 with Stack.States[Stack.Count] do |
|
167 begin |
|
168 Ticks:= WastedTicks; |
|
169 Actions:= MadeActions; |
|
170 Me:= Hedgehog |
|
171 end |
|
172 end; |
|
173 |
|
174 var Actions: TActions; |
|
175 ticks, maxticks, steps, tmp: Longword; |
179 ticks, maxticks, steps, tmp: Longword; |
176 BaseRate, BestRate, Rate: integer; |
180 BaseRate, BestRate, Rate: integer; |
177 GoInfo: TGoInfo; |
181 GoInfo: TGoInfo; |
178 CanGo: boolean; |
182 CanGo: boolean; |
179 AltMe: TGear; |
183 AltMe: TGear; |
180 BotLevel: Byte; |
184 BotLevel: Byte; |
|
185 a: TAmmoType; |
181 begin |
186 begin |
182 ticks:= 0; // avoid compiler hint |
187 ticks:= 0; // avoid compiler hint |
183 Actions.Count:= 0; |
|
184 Actions.Pos:= 0; |
|
185 Actions.Score:= 0; |
|
186 Stack.Count:= 0; |
188 Stack.Count:= 0; |
|
189 |
|
190 for a:= Low(TAmmoType) to High(TAmmoType) do |
|
191 CanUseAmmo[a]:= Assigned(AmmoTests[a].proc) and HHHasAmmo(Me^.Hedgehog^, a); |
|
192 |
187 BotLevel:= Me^.Hedgehog^.BotLevel; |
193 BotLevel:= Me^.Hedgehog^.BotLevel; |
188 |
194 |
189 tmp:= random(2) + 1; |
195 tmp:= random(2) + 1; |
190 Push(0, Actions, Me^, tmp); |
196 Push(0, Actions, Me^, tmp); |
191 Push(0, Actions, Me^, tmp xor 3); |
197 Push(0, Actions, Me^, tmp xor 3); |
238 Actions.actions[Pred(Actions.Count)].Param:= hwRound(Me^.X); |
244 Actions.actions[Pred(Actions.Count)].Param:= hwRound(Me^.X); |
239 Rate:= RatePlace(Me); |
245 Rate:= RatePlace(Me); |
240 if Rate > BestRate then |
246 if Rate > BestRate then |
241 begin |
247 begin |
242 BestActions:= Actions; |
248 BestActions:= Actions; |
|
249 BestActions.isWalkingToABetterPlace:= true; |
243 BestRate:= Rate; |
250 BestRate:= Rate; |
244 Me^.State:= Me^.State or gstAttacked // we have better place, go there and do not use ammo |
251 Me^.State:= Me^.State or gstAttacked // we have better place, go there and do not use ammo |
245 end |
252 end |
246 else if Rate < BestRate then break; |
253 else if Rate < BestRate then break; |
247 if ((Me^.State and gstAttacked) = 0) |
254 if ((Me^.State and gstAttacked) = 0) |
254 end |
261 end |
255 end; |
262 end; |
256 |
263 |
257 function Think(Me: Pointer): ptrint; |
264 function Think(Me: Pointer): ptrint; |
258 var BackMe, WalkMe: TGear; |
265 var BackMe, WalkMe: TGear; |
259 StartTicks: Longword; |
266 StartTicks, currHedgehogIndex, itHedgehog, switchesNum, i: Longword; |
|
267 switchImmediatelyAvailable, switchAvailable: boolean; |
|
268 Actions: TActions; |
260 begin |
269 begin |
261 InterlockedIncrement(hasThread); |
270 InterlockedIncrement(hasThread); |
262 StartTicks:= GameTicks; |
271 StartTicks:= GameTicks; |
263 BackMe:= PGear(Me)^; |
272 currHedgehogIndex:= CurrentTeam^.CurrHedgehog; |
|
273 itHedgehog:= currHedgehogIndex; |
|
274 switchesNum:= 0; |
|
275 |
|
276 switchImmediatelyAvailable:= (CurAmmoGear <> nil) and (CurAmmoGear^.Kind = gtSwitcher); |
|
277 switchAvailable:= HHHasAmmo(PGear(Me)^.Hedgehog^, amSwitch); |
264 |
278 |
265 if (PGear(Me)^.State and gstAttacked) = 0 then |
279 if (PGear(Me)^.State and gstAttacked) = 0 then |
266 if Targets.Count > 0 then |
280 if Targets.Count > 0 then |
267 begin |
281 begin |
268 WalkMe:= BackMe; |
282 // iterate over current team hedgehogs |
269 Walk(@WalkMe); |
283 repeat |
270 if (StartTicks > GameTicks - 1500) and (not StopThinking) then SDL_Delay(1000); |
284 WalkMe:= CurrentTeam^.Hedgehogs[itHedgehog].Gear^; |
271 if BestActions.Score < -1023 then |
285 |
272 begin |
286 Actions.Count:= 0; |
273 BestActions.Count:= 0; |
287 Actions.Pos:= 0; |
274 AddAction(BestActions, aia_Skip, 0, 250, 0, 0); |
288 Actions.Score:= 0; |
275 end; |
289 if switchesNum > 0 then |
|
290 begin |
|
291 if not switchImmediatelyAvailable then |
|
292 begin |
|
293 // when AI has to use switcher, make it cost smth |
|
294 Actions.Score:= -20000; |
|
295 AddAction(Actions, aia_Weapon, Longword(amSwitch), 300 + random(200), 0, 0); |
|
296 AddAction(Actions, aia_attack, aim_push, 300 + random(300), 0, 0); |
|
297 AddAction(Actions, aia_attack, aim_release, 1, 0, 0); |
|
298 end; |
|
299 for i:= 1 to switchesNum do |
|
300 AddAction(Actions, aia_Switch, 0, 300 + random(200), 0, 0); |
|
301 end; |
|
302 Walk(@WalkMe, Actions); |
|
303 |
|
304 // find another hog in team |
|
305 repeat |
|
306 itHedgehog:= Succ(itHedgehog) mod CurrentTeam^.HedgehogsNumber; |
|
307 until (itHedgehog = currHedgehogIndex) or (CurrentTeam^.Hedgehogs[itHedgehog].Gear <> nil); |
|
308 |
|
309 inc(switchesNum); |
|
310 until (not (switchImmediatelyAvailable or switchAvailable)) |
|
311 or StopThinking |
|
312 or (itHedgehog = currHedgehogIndex) |
|
313 or BestActions.isWalkingToABetterPlace; |
|
314 |
|
315 if (StartTicks > GameTicks - 1500) and (not StopThinking) then SDL_Delay(1000); |
|
316 |
|
317 if (BestActions.Score < -1023) and (not BestActions.isWalkingToABetterPlace) then |
|
318 begin |
|
319 BestActions.Count:= 0; |
|
320 AddAction(BestActions, aia_Skip, 0, 250, 0, 0); |
|
321 end; |
|
322 |
276 end else |
323 end else |
277 else begin |
324 else begin |
278 while (not StopThinking) and (BestActions.Count = 0) do |
325 BackMe:= PGear(Me)^; |
279 begin |
326 while (not StopThinking) and (BestActions.Count = 0) do |
280 FillBonuses(true); |
327 begin |
281 WalkMe:= BackMe; |
328 FillBonuses(true); |
282 Walk(@WalkMe); |
329 WalkMe:= BackMe; |
283 if not StopThinking then SDL_Delay(100) |
330 Actions.Count:= 0; |
284 end |
331 Actions.Pos:= 0; |
285 end; |
332 Actions.Score:= 0; |
|
333 Walk(@WalkMe, Actions); |
|
334 if not StopThinking then SDL_Delay(100) |
|
335 end |
|
336 end; |
|
337 |
286 PGear(Me)^.State:= PGear(Me)^.State and not gstHHThinking; |
338 PGear(Me)^.State:= PGear(Me)^.State and not gstHHThinking; |
287 Think:= 0; |
339 Think:= 0; |
288 InterlockedDecrement(hasThread) |
340 InterlockedDecrement(hasThread) |
289 end; |
341 end; |
290 |
342 |
291 procedure StartThink(Me: PGear); |
343 procedure StartThink(Me: PGear); |
292 var a: TAmmoType; |
|
293 begin |
344 begin |
294 if ((Me^.State and (gstAttacking or gstHHJumping or gstMoving)) <> 0) |
345 if ((Me^.State and (gstAttacking or gstHHJumping or gstMoving)) <> 0) |
295 or isInMultiShoot then exit; |
346 or isInMultiShoot then exit; |
296 |
347 |
297 //DeleteCI(Me); // this might break demo |
348 //DeleteCI(Me); // this might break demo |