84 AddAction(BestActions, aia_AwareExpl, ExplR, 10, ExplX, ExplY); |
92 AddAction(BestActions, aia_AwareExpl, ExplR, 10, ExplX, ExplY); |
85 end |
93 end |
86 end; |
94 end; |
87 if a = High(TAmmoType) then a:= Low(TAmmoType) |
95 if a = High(TAmmoType) then a:= Low(TAmmoType) |
88 else inc(a) |
96 else inc(a) |
89 until (a = aa) or (PHedgehog(Me^.Hedgehog)^.AttacksNum > 0) |
97 until (a = aa) or (CurrentTeam^.Hedgehogs[CurrentTeam^.CurrHedgehog].AttacksNum > 0) |
90 end |
98 end |
91 end; |
99 end; |
92 |
100 |
93 procedure Walk(Me: PGear); |
101 procedure Walk(Me: PGear); |
94 const FallPixForBranching = cHHRadius * 2 + 8; |
102 const FallPixForBranching = cHHRadius * 2 + 8; |
95 |
103 cBranchStackSize = 12; |
|
104 |
|
105 type TStackEntry = record |
|
106 WastedTicks: Longword; |
|
107 MadeActions: TActions; |
|
108 Hedgehog: TGear; |
|
109 end; |
|
110 |
|
111 var Stack: record |
|
112 Count: Longword; |
|
113 States: array[0..Pred(cBranchStackSize)] of TStackEntry; |
|
114 end; |
|
115 |
|
116 function Push(Ticks: Longword; const Actions: TActions; const Me: TGear; Dir: integer): boolean; |
|
117 var Result: boolean; |
|
118 begin |
|
119 Result:= (Stack.Count < cBranchStackSize) and (Actions.Count < MAXACTIONS - 5); |
|
120 if Result then |
|
121 with Stack.States[Stack.Count] do |
|
122 begin |
|
123 WastedTicks:= Ticks; |
|
124 MadeActions:= Actions; |
|
125 Hedgehog:= Me; |
|
126 Hedgehog.Message:= Dir; |
|
127 inc(Stack.Count) |
|
128 end; |
|
129 Push:= Result |
|
130 end; |
|
131 |
|
132 procedure Pop(var Ticks: Longword; var Actions: TActions; var Me: TGear); |
|
133 begin |
|
134 dec(Stack.Count); |
|
135 with Stack.States[Stack.Count] do |
|
136 begin |
|
137 Ticks:= WastedTicks; |
|
138 Actions:= MadeActions; |
|
139 Me:= Hedgehog |
|
140 end |
|
141 end; |
|
142 |
|
143 function PosInThinkStack(Me: PGear): boolean; |
|
144 var i: Longword; |
|
145 begin |
|
146 i:= 0; |
|
147 while (i < Stack.Count) do |
|
148 begin |
|
149 if(not(hwAbs(Stack.States[i].Hedgehog.X - Me^.X) + |
|
150 hwAbs(Stack.States[i].Hedgehog.Y - Me^.Y) > 2)) and |
|
151 (Stack.States[i].Hedgehog.Message = Me^.Message) then exit(true); |
|
152 inc(i) |
|
153 end; |
|
154 PosInThinkStack:= false |
|
155 end; |
|
156 |
|
157 |
96 var Actions: TActions; |
158 var Actions: TActions; |
97 ticks, maxticks, steps, BotLevel: Longword; |
159 ticks, maxticks, steps, BotLevel, tmp: Longword; |
98 BaseRate, Rate: LongInt; |
160 BaseRate, BestRate, Rate: integer; |
99 GoInfo: TGoInfo; |
161 GoInfo: TGoInfo; |
100 CanGo: boolean; |
162 CanGo: boolean; |
101 AltMe: TGear; |
163 AltMe: TGear; |
102 begin |
164 begin |
|
165 Actions.Count:= 0; |
|
166 Actions.Pos:= 0; |
|
167 Actions.Score:= 0; |
|
168 Stack.Count:= 0; |
103 BotLevel:= PHedgehog(Me^.Hedgehog)^.BotLevel; |
169 BotLevel:= PHedgehog(Me^.Hedgehog)^.BotLevel; |
104 |
170 |
|
171 tmp:= random(2) + 1; |
|
172 Push(0, Actions, Me^, tmp); |
|
173 Push(0, Actions, Me^, tmp xor 3); |
|
174 |
105 if (Me^.State and gstAttacked) = 0 then maxticks:= max(0, TurnTimeLeft - 5000 - 4000 * BotLevel) |
175 if (Me^.State and gstAttacked) = 0 then maxticks:= max(0, TurnTimeLeft - 5000 - 4000 * BotLevel) |
106 else maxticks:= TurnTimeLeft; |
176 else maxticks:= TurnTimeLeft; |
107 |
177 |
108 BaseRate:= RatePlace(Me); |
178 if (Me^.State and gstAttacked) = 0 then TestAmmos(Actions, Me); |
109 |
179 BestRate:= RatePlace(Me); |
110 repeat |
180 BaseRate:= max(BestRate, 0); |
111 if not Pop(ticks, Actions, Me^) then |
181 |
112 begin |
182 while (Stack.Count > 0) and not StopThinking do |
113 isThinking:= false; |
183 begin |
114 exit |
184 Pop(ticks, Actions, Me^); |
115 end; |
185 |
116 |
186 AddAction(Actions, Me^.Message, aim_push, 250, 0, 0); |
117 AddAction(Actions, Me^.Message, aim_push, 10, 0, 0); |
|
118 if (Me^.Message and gm_Left) <> 0 then AddAction(Actions, aia_WaitXL, hwRound(Me^.X), 0, 0, 0) |
187 if (Me^.Message and gm_Left) <> 0 then AddAction(Actions, aia_WaitXL, hwRound(Me^.X), 0, 0, 0) |
119 else AddAction(Actions, aia_WaitXR, hwRound(Me^.X), 0, 0, 0); |
188 else AddAction(Actions, aia_WaitXR, hwRound(Me^.X), 0, 0, 0); |
120 AddAction(Actions, Me^.Message, aim_release, 0, 0, 0); |
189 AddAction(Actions, Me^.Message, aim_release, 0, 0, 0); |
121 steps:= 0; |
190 steps:= 0; |
122 if ((Me^.State and gstAttacked) = 0) then TestAmmos(Actions, Me); |
191 |
123 |
192 while (not StopThinking) and (not PosInThinkStack(Me)) do |
124 while not PosInThinkStack(Me) do |
|
125 begin |
193 begin |
126 CanGo:= HHGo(Me, @AltMe, GoInfo); |
194 CanGo:= HHGo(Me, @AltMe, GoInfo); |
127 inc(ticks, GoInfo.Ticks); |
195 inc(ticks, GoInfo.Ticks); |
128 if ticks > maxticks then break; |
196 if ticks > maxticks then break; |
129 |
197 |
130 if (BotLevel < 5) and (GoInfo.JumpType = jmpHJump) then // hjump support |
198 if (BotLevel < 5) and (GoInfo.JumpType = jmpHJump) then // hjump support |
131 if Push(ticks, Actions, AltMe, Me^.Message) then |
199 if Push(ticks, Actions, AltMe, Me^.Message) then |
132 with ThinkStack.States[Pred(ThinkStack.Count)] do |
200 with Stack.States[Pred(Stack.Count)] do |
133 begin |
201 begin |
134 AddAction(MadeActions, aia_HJump, 0, 305, 0, 0); |
202 AddAction(MadeActions, aia_HJump, 0, 305, 0, 0); |
135 AddAction(MadeActions, aia_HJump, 0, 350, 0, 0); |
203 AddAction(MadeActions, aia_HJump, 0, 350, 0, 0); |
136 if (Me^.dX < 0) then AddAction(MadeActions, aia_WaitXL, hwRound(AltMe.X), 0, 0, 0) |
|
137 else AddAction(MadeActions, aia_WaitXR, hwRound(AltMe.X), 0, 0, 0); |
|
138 end; |
204 end; |
139 if (BotLevel < 3) and (GoInfo.JumpType = jmpLJump) then // ljump support |
205 if (BotLevel < 3) and (GoInfo.JumpType = jmpLJump) then // ljump support |
140 if Push(ticks, Actions, AltMe, Me^.Message) then |
206 if Push(ticks, Actions, AltMe, Me^.Message) then |
141 with ThinkStack.States[Pred(ThinkStack.Count)] do |
207 with Stack.States[Pred(Stack.Count)] do |
142 begin |
|
143 AddAction(MadeActions, aia_LJump, 0, 305, 0, 0); |
208 AddAction(MadeActions, aia_LJump, 0, 305, 0, 0); |
144 if (Me^.dX < 0) then AddAction(MadeActions, aia_WaitXL, hwRound(AltMe.X), 0, 0, 0) |
209 |
145 else AddAction(MadeActions, aia_WaitXR, hwRound(AltMe.X), 0, 0, 0); |
|
146 end; |
|
147 if not CanGo then break; |
210 if not CanGo then break; |
148 inc(steps); |
211 inc(steps); |
149 Actions.actions[Actions.Count - 2].Param:= hwRound(Me^.X); |
212 Actions.actions[Actions.Count - 2].Param:= hwRound(Me^.X); |
150 Rate:= RatePlace(Me); |
213 Rate:= RatePlace(Me); |
151 if Rate > BaseRate then |
214 if Rate > BestRate then |
152 begin |
215 begin |
153 BestActions:= Actions; |
216 BestActions:= Actions; |
154 BestActions.Score:= 1; |
217 BestRate:= Rate; |
155 isThinking:= false; |
218 Me^.State:= Me^.State or gstAttacked // we have better place, go there and don't use ammo |
156 exit |
|
157 end |
219 end |
158 else if Rate < BaseRate then break; |
220 else if Rate < BestRate then break; |
|
221 if ((Me^.State and gstAttacked) = 0) |
|
222 and ((steps mod 4) = 0) then TestAmmos(Actions, Me); |
159 if GoInfo.FallPix >= FallPixForBranching then |
223 if GoInfo.FallPix >= FallPixForBranching then |
160 Push(ticks, Actions, Me^, Me^.Message xor 3); // aia_Left xor 3 = aia_Right |
224 Push(ticks, Actions, Me^, Me^.Message xor 3); // aia_Left xor 3 = aia_Right |
161 |
|
162 if ((Me^.State and gstAttacked) = 0) |
|
163 and ((steps mod 4) = 0) then |
|
164 begin |
|
165 TestAmmos(Actions, Me); |
|
166 if SDL_GetTicks - AIThinkStart >= Pred(cTimerInterval) then |
|
167 begin |
|
168 dec(Actions.Count, 3); |
|
169 Push(ticks, Actions, Me^, Me^.Message); |
|
170 exit |
|
171 end |
|
172 end |
|
173 end; |
225 end; |
174 until false |
226 |
175 end; |
227 if BestRate > BaseRate then exit |
176 |
228 end |
177 procedure Think(Me: PGear); |
229 end; |
|
230 |
|
231 procedure Think(Me: PGear); cdecl; |
178 var BackMe, WalkMe: TGear; |
232 var BackMe, WalkMe: TGear; |
179 begin |
233 StartTicks: Longword; |
180 AIThinkStart:= SDL_GetTicks; |
234 begin |
|
235 StartTicks:= GameTicks; |
|
236 BestActions.Count:= 0; |
|
237 BestActions.Pos:= 0; |
|
238 BestActions.Score:= Low(integer); |
181 BackMe:= Me^; |
239 BackMe:= Me^; |
182 WalkMe:= BackMe; |
240 WalkMe:= BackMe; |
183 if (Me^.State and gstAttacked) = 0 then |
241 if (Me^.State and gstAttacked) = 0 then |
184 if Targets.Count > 0 then |
242 if Targets.Count > 0 then |
185 begin |
243 begin |
186 Walk(@WalkMe); |
244 Walk(@WalkMe); |
187 if not isThinking then |
245 if (StartTicks > GameTicks - 1500) and not StopThinking then SDL_Delay(2000); |
|
246 if BestActions.Score < -1023 then |
188 begin |
247 begin |
189 if BestActions.Score < -1023 then |
248 BestActions.Count:= 0; |
190 begin |
249 AddAction(BestActions, aia_Skip, 0, 250, 0, 0); |
191 BestActions.Count:= 0; |
250 end; |
192 AddAction(BestActions, aia_Skip, 0, 250, 0, 0); |
|
193 end; |
|
194 Me^.State:= Me^.State and not gstHHThinking |
|
195 end |
|
196 end else |
251 end else |
197 else begin |
252 else begin |
198 FillBonuses(true); |
|
199 Walk(@WalkMe); |
253 Walk(@WalkMe); |
200 AddAction(BestActions, aia_Wait, GameTicks + 100, 100, 0, 0); |
254 while (not StopThinking) and (BestActions.Count = 0) do |
201 end |
255 begin |
|
256 SDL_Delay(100); |
|
257 FillBonuses(true); |
|
258 WalkMe:= BackMe; |
|
259 Walk(@WalkMe) |
|
260 end |
|
261 end; |
|
262 Me^.State:= Me^.State and not gstHHThinking |
202 end; |
263 end; |
203 |
264 |
204 procedure StartThink(Me: PGear); |
265 procedure StartThink(Me: PGear); |
205 var a: TAmmoType; |
266 var a: TAmmoType; |
206 tmp: LongInt; |
|
207 begin |
267 begin |
208 if ((Me^.State and gstAttacking) <> 0) or isInMultiShoot then exit; |
268 if ((Me^.State and gstAttacking) <> 0) or isInMultiShoot then exit; |
209 ThinkingHH:= Me; |
|
210 isThinking:= true; |
|
211 |
|
212 ClearThinkStack; |
|
213 |
|
214 Me^.State:= Me^.State or gstHHThinking; |
269 Me^.State:= Me^.State or gstHHThinking; |
215 Me^.Message:= 0; |
270 Me^.Message:= 0; |
|
271 StopThinking:= false; |
|
272 ThinkingHH:= Me; |
216 FillTargets; |
273 FillTargets; |
217 if Targets.Count = 0 then |
274 if Targets.Count = 0 then |
218 begin |
275 begin |
219 OutError('AI: no targets!?', false); |
276 OutError('AI: no targets!?', false); |
220 exit |
277 exit |
221 end; |
278 end; |
222 |
|
223 FillBonuses((Me^.State and gstAttacked) <> 0); |
279 FillBonuses((Me^.State and gstAttacked) <> 0); |
224 |
|
225 for a:= Low(TAmmoType) to High(TAmmoType) do |
280 for a:= Low(TAmmoType) to High(TAmmoType) do |
226 CanUseAmmo[a]:= Assigned(AmmoTests[a]) and HHHasAmmo(PHedgehog(Me^.Hedgehog), a); |
281 CanUseAmmo[a]:= Assigned(AmmoTests[a]) and HHHasAmmo(PHedgehog(Me^.Hedgehog), a); |
227 |
282 {$IFDEF DEBUGFILE}AddFileLog('Enter Think Thread');{$ENDIF} |
228 BestActions.Count:= 0; |
283 ThinkThread:= SDL_CreateThread(@Think, Me) |
229 BestActions.Pos:= 0; |
284 end; |
230 BestActions.Score:= 0; |
285 |
231 tmp:= random(2) + 1; |
286 procedure ProcessBot; |
232 Push(0, BestActions, Me^, tmp); |
287 const StartTicks: Longword = 0; |
233 Push(0, BestActions, Me^, tmp xor 3); |
|
234 BestActions.Score:= Low(LongInt); |
|
235 |
|
236 Think(Me) |
|
237 end; |
|
238 |
|
239 procedure ProcessBot(FrameNo: Longword); |
|
240 const LastFrameNo: Longword = 0; |
|
241 begin |
288 begin |
242 with CurrentTeam^.Hedgehogs[CurrentTeam^.CurrHedgehog] do |
289 with CurrentTeam^.Hedgehogs[CurrentTeam^.CurrHedgehog] do |
243 if (Gear <> nil) |
290 if (Gear <> nil) |
244 and ((Gear^.State and gstHHDriven) <> 0) |
291 and ((Gear^.State and gstHHDriven) <> 0) |
245 and (TurnTimeLeft < cHedgehogTurnTime - 50) then |
292 and (TurnTimeLeft < cHedgehogTurnTime - 50) then |
246 if not isThinking then |
293 if ((Gear^.State and gstHHThinking) = 0) then |
247 if (BestActions.Pos >= BestActions.Count) then StartThink(Gear) |
294 if (BestActions.Pos >= BestActions.Count) then |
248 else ProcessAction(BestActions, Gear) |
295 begin |
249 else if FrameNo <> LastFrameNo then |
296 StartThink(Gear); |
250 begin |
297 StartTicks:= GameTicks |
251 LastFrameNo:= FrameNo; |
298 end else ProcessAction(BestActions, Gear) |
252 Think(Gear) |
299 else if (GameTicks - StartTicks) > cMaxAIThinkTime then StopThinking:= true |
253 end; |
300 end; |
254 end; |
301 |
255 |
302 |
256 end. |
303 end. |