258 inc(rate, Score * (Radius - r)) |
292 inc(rate, Score * (Radius - r)) |
259 end; |
293 end; |
260 RatePlace:= rate; |
294 RatePlace:= rate; |
261 end; |
295 end; |
262 |
296 |
|
297 function CheckBounds(x, y, r: Longint): boolean; inline; |
|
298 begin |
|
299 CheckBounds := (((x-r) and LAND_WIDTH_MASK) = 0) and |
|
300 (((x+r) and LAND_WIDTH_MASK) = 0) and |
|
301 (((y-r) and LAND_HEIGHT_MASK) = 0) and |
|
302 (((y+r) and LAND_HEIGHT_MASK) = 0); |
|
303 end; |
|
304 |
|
305 |
|
306 function TestCollWithEverything(x, y, r: LongInt): boolean; inline; |
|
307 begin |
|
308 if not CheckBounds(x, y, r) then |
|
309 exit(false); |
|
310 |
|
311 if (Land[y-r, x-r] <> 0) or |
|
312 (Land[y+r, x-r] <> 0) or |
|
313 (Land[y-r, x+r] <> 0) or |
|
314 (Land[y+r, x+r] <> 0) then |
|
315 exit(true); |
|
316 |
|
317 TestCollWithEverything := false; |
|
318 end; |
|
319 |
|
320 function TestCollExcludingObjects(x, y, r: LongInt): boolean; inline; |
|
321 begin |
|
322 if not CheckBounds(x, y, r) then |
|
323 exit(false); |
|
324 |
|
325 if (Land[y-r, x-r] > lfAllObjMask) or |
|
326 (Land[y+r, x-r] > lfAllObjMask) or |
|
327 (Land[y-r, x-r] > lfAllObjMask) or |
|
328 (Land[y+r, x+r] > lfAllObjMask) then |
|
329 exit(true); |
|
330 |
|
331 TestCollExcludingObjects:= false; |
|
332 end; |
|
333 |
|
334 function TestColl(x, y, r: LongInt): boolean; inline; |
|
335 begin |
|
336 if not CheckBounds(x, y, r) then |
|
337 exit(false); |
|
338 |
|
339 if (Land[y-r, x-r] and lfNotCurrentMask <> 0) or |
|
340 (Land[y+r, x-r] and lfNotCurrentMask <> 0) or |
|
341 (Land[y+r, x-r] and lfNotCurrentMask <> 0) or |
|
342 (Land[y+r, x+r] and lfNotCurrentMask <> 0) then |
|
343 exit(true); |
|
344 |
|
345 TestColl:= false; |
|
346 end; |
|
347 |
|
348 |
263 // Wrapper to test various approaches. If it works reasonably, will just replace. |
349 // Wrapper to test various approaches. If it works reasonably, will just replace. |
264 // Right now, converting to hwFloat is a tad inefficient since the x/y were hwFloat to begin with... |
350 // Right now, converting to hwFloat is a tad inefficient since the x/y were hwFloat to begin with... |
265 function TestCollExcludingMe(Me: PGear; x, y, r: LongInt): boolean; inline; |
351 function TestCollExcludingMe(Me: PGear; x, y, r: LongInt): boolean; inline; |
266 var MeX, MeY: LongInt; |
352 var MeX, MeY: LongInt; |
267 begin |
353 begin |
268 if ((x and LAND_WIDTH_MASK) = 0) and ((y and LAND_HEIGHT_MASK) = 0) then |
354 if ((x and LAND_WIDTH_MASK) = 0) and ((y and LAND_HEIGHT_MASK) = 0) then |
269 begin |
355 begin |
270 MeX:= hwRound(Me^.X); |
356 MeX:= hwRound(Me^.X); |
271 MeY:= hwRound(Me^.Y); |
357 MeY:= hwRound(Me^.Y); |
272 // We are still inside the hog. Skip radius test |
358 // We are still inside the hog. Skip radius test |
273 if ((((x-MeX)*(x-MeX)) + ((y-MeY)*(y-MeY))) < 256) and (Land[y, x] <= lfAllObjMask) and ((Land[y, x] and lfObjMask) < 2) then |
359 if ((sqr(x-MeX) + sqr(y-MeY)) < 256) and (Land[y, x] and lfObjMask = 0) then |
274 exit(false); |
360 exit(false); |
275 end; |
361 end; |
276 TestCollExcludingMe:= TestColl(x, y, r) |
362 TestCollExcludingMe:= TestCollWithEverything(x, y, r) |
277 end; |
363 end; |
278 |
364 |
279 function TestCollExcludingObjects(x, y, r: LongInt): boolean; inline; |
365 |
280 var b: boolean; |
366 |
281 begin |
367 function TraceFall(eX, eY: LongInt; var x, y: Real; dX, dY: Real; r: LongWord; Target: TTarget): LongInt; |
282 b:= (((x-r) and LAND_WIDTH_MASK) = 0) and (((y-r) and LAND_HEIGHT_MASK) = 0) and (Land[y-r, x-r] > lfAllObjMask); |
|
283 if b then |
|
284 exit(true); |
|
285 |
|
286 b:= (((x-r) and LAND_WIDTH_MASK) = 0) and (((y+r) and LAND_HEIGHT_MASK) = 0) and (Land[y+r, x-r] > lfAllObjMask); |
|
287 if b then |
|
288 exit(true); |
|
289 |
|
290 b:= (((x+r) and LAND_WIDTH_MASK) = 0) and (((y-r) and LAND_HEIGHT_MASK) = 0) and (Land[y-r, x+r] > lfAllObjMask); |
|
291 if b then |
|
292 exit(true); |
|
293 |
|
294 b:= (((x+r) and LAND_WIDTH_MASK) = 0) and (((y+r) and LAND_HEIGHT_MASK) = 0) and (Land[y+r, x+r] > lfAllObjMask); |
|
295 if b then |
|
296 exit(true); |
|
297 |
|
298 TestCollExcludingObjects:= false; |
|
299 end; |
|
300 |
|
301 function TestColl(x, y, r: LongInt): boolean; inline; |
|
302 var b: boolean; |
|
303 begin |
|
304 b:= (((x-r) and LAND_WIDTH_MASK) = 0) and (((y-r) and LAND_HEIGHT_MASK) = 0) and (Land[y-r, x-r] and lfNotCurrentMask <> 0); |
|
305 if b then |
|
306 exit(true); |
|
307 |
|
308 b:= (((x-r) and LAND_WIDTH_MASK) = 0) and (((y+r) and LAND_HEIGHT_MASK) = 0) and (Land[y+r, x-r] and lfNotCurrentMask <> 0); |
|
309 if b then |
|
310 exit(true); |
|
311 |
|
312 b:= (((x+r) and LAND_WIDTH_MASK) = 0) and (((y-r) and LAND_HEIGHT_MASK) = 0) and (Land[y-r, x+r] and lfNotCurrentMask <> 0); |
|
313 if b then |
|
314 exit(true); |
|
315 |
|
316 b:= (((x+r) and LAND_WIDTH_MASK) = 0) and (((y+r) and LAND_HEIGHT_MASK) = 0) and (Land[y+r, x+r] and lfNotCurrentMask <> 0); |
|
317 if b then |
|
318 exit(true); |
|
319 |
|
320 TestColl:= false; |
|
321 end; |
|
322 |
|
323 function TestCollWithLand(x, y, r: LongInt): boolean; inline; |
|
324 var b: boolean; |
|
325 begin |
|
326 b:= (((x-r) and LAND_WIDTH_MASK) = 0) and (((y-r) and LAND_HEIGHT_MASK) = 0) and (Land[y-r, x-r] > lfAllObjMask); |
|
327 if b then |
|
328 exit(true); |
|
329 |
|
330 b:= (((x-r) and LAND_WIDTH_MASK) = 0) and (((y+r) and LAND_HEIGHT_MASK) = 0) and (Land[y+r, x-r] > lfAllObjMask); |
|
331 if b then |
|
332 exit(true); |
|
333 |
|
334 b:= (((x+r) and LAND_WIDTH_MASK) = 0) and (((y-r) and LAND_HEIGHT_MASK) = 0) and (Land[y-r, x+r] > lfAllObjMask); |
|
335 if b then |
|
336 exit(true); |
|
337 |
|
338 b:= (((x+r) and LAND_WIDTH_MASK) = 0) and (((y+r) and LAND_HEIGHT_MASK) = 0) and (Land[y+r, x+r] > lfAllObjMask); |
|
339 if b then |
|
340 exit(true); |
|
341 |
|
342 TestCollWithLand:= false; |
|
343 end; |
|
344 |
|
345 function TraceFall(eX, eY: LongInt; x, y, dX, dY: Real; r: LongWord): LongInt; |
|
346 var skipLandCheck: boolean; |
368 var skipLandCheck: boolean; |
347 rCorner: real; |
369 rCorner, dxdy, odX, odY: real; |
348 dmg: LongInt; |
370 dmg: LongInt; |
349 begin |
371 begin |
|
372 odX:= dX; |
|
373 odY:= dY; |
350 skipLandCheck:= true; |
374 skipLandCheck:= true; |
351 if x - eX < 0 then dX:= -dX; |
|
352 if y - eY < 0 then dY:= -dY; |
|
353 // ok. attempt approximate search for an unbroken trajectory into water. if it continues far enough, assume out of map |
375 // ok. attempt approximate search for an unbroken trajectory into water. if it continues far enough, assume out of map |
354 rCorner:= r * 0.75; |
376 rCorner:= r * 0.75; |
355 while true do |
377 while true do |
356 begin |
378 begin |
357 x:= x + dX; |
379 x:= x + dX; |
358 y:= y + dY; |
380 y:= y + dY; |
359 dY:= dY + cGravityf; |
381 dY:= dY + cGravityf; |
360 skipLandCheck:= skipLandCheck and (r <> 0) and (abs(eX-x) + abs(eY-y) < r) and ((abs(eX-x) < rCorner) or (abs(eY-y) < rCorner)); |
382 skipLandCheck:= skipLandCheck and (r <> 0) and (abs(eX-x) + abs(eY-y) < r) and ((abs(eX-x) < rCorner) or (abs(eY-y) < rCorner)); |
361 if (not skipLandCheck) and TestCollWithLand(trunc(x), trunc(y), cHHRadius) then |
383 if not skipLandCheck and TestCollExcludingObjects(trunc(x), trunc(y), Target.Radius) then |
362 begin |
384 with Target do |
363 if 0.4 < dY then |
385 begin |
364 begin |
386 if (Kind = gtHedgehog) and (0.4 < dY) then |
365 dmg := 1 + trunc((abs(dY) - 0.4) * 70); |
387 begin |
366 if dmg >= 1 then |
388 dmg := 1 + trunc((dY - 0.4) * 70); |
367 exit(dmg); |
389 exit(dmg) |
368 end; |
390 end |
|
391 else |
|
392 begin |
|
393 dxdy:= abs(dX)+abs(dY); |
|
394 if ((Kind = gtMine) and (dxdy > 0.35)) or |
|
395 ((Kind = gtExplosives) and |
|
396 (((State and gstTmpFlag <> 0) and (dxdy > 0.35)) or |
|
397 ((State and gstTmpFlag = 0) and |
|
398 ((abs(odX) > 0.15) or ((abs(odY) > 0.15) and |
|
399 (abs(odX) > 0.02))) and (dxdy > 0.35)))) then |
|
400 begin |
|
401 dmg := trunc(dxdy * 25); |
|
402 exit(dmg) |
|
403 end |
|
404 else if (Kind = gtExplosives) and not((abs(odX) > 0.15) or ((abs(odY) > 0.15) and (abs(odX) > 0.02))) and (dY > 0.2) then |
|
405 begin |
|
406 dmg := trunc(dy * 70); |
|
407 exit(dmg) |
|
408 end |
|
409 end; |
369 exit(0) |
410 exit(0) |
370 end; |
411 end; |
371 if (y > cWaterLine) or (x > 4096) or (x < 0) then |
412 if (y > cWaterLine) or (x > rightX) or (x < leftX) then exit(-1) |
372 exit(-1); |
413 end |
373 end; |
414 end; |
374 end; |
415 |
375 |
416 function TraceShoveFall(var x, y: Real; dX, dY: Real; Target: TTarget): LongInt; |
376 function TraceShoveFall(x, y, dX, dY: Real): LongInt; |
|
377 var dmg: LongInt; |
417 var dmg: LongInt; |
378 begin |
418 dxdy, odX, odY: real; |
|
419 begin |
|
420 odX:= dX; |
|
421 odY:= dY; |
379 //v:= random($FFFFFFFF); |
422 //v:= random($FFFFFFFF); |
380 while true do |
423 while true do |
381 begin |
424 begin |
382 x:= x + dX; |
425 x:= x + dX; |
383 y:= y + dY; |
426 y:= y + dY; |
384 dY:= dY + cGravityf; |
427 dY:= dY + cGravityf; |
385 |
428 |
386 { if ((trunc(y) and LAND_HEIGHT_MASK) = 0) and ((trunc(x) and LAND_WIDTH_MASK) = 0) then |
429 { if ((trunc(y) and LAND_HEIGHT_MASK) = 0) and ((trunc(x) and LAND_WIDTH_MASK) = 0) then |
387 begin |
430 begin |
388 LandPixels[trunc(y), trunc(x)]:= v; |
431 LandPixels[trunc(y), trunc(x)]:= v; |
389 UpdateLandTexture(trunc(X), 1, trunc(Y), 1, true); |
432 UpdateLandTexture(trunc(X), 1, trunc(Y), 1, true); |
390 end;} |
433 end;} |
391 |
434 |
392 |
435 if TestCollExcludingObjects(trunc(x), trunc(y), Target.Radius) then |
393 // consider adding dX/dY calc here for fall damage |
436 with Target do |
394 if TestCollExcludingObjects(trunc(x), trunc(y), cHHRadius) then |
437 begin |
395 begin |
438 if (Kind = gtHedgehog) and (0.4 < dY) then |
396 if 0.4 < dY then |
439 begin |
397 begin |
440 dmg := trunc((dY - 0.4) * 70); |
398 dmg := 1 + trunc((abs(dY) - 0.4) * 70); |
|
399 if dmg >= 1 then |
|
400 exit(dmg); |
441 exit(dmg); |
401 end; |
442 end |
|
443 else |
|
444 begin |
|
445 dxdy:= abs(dX)+abs(dY); |
|
446 if ((Kind = gtMine) and (dxdy > 0.4)) or |
|
447 ((Kind = gtExplosives) and |
|
448 (((State and gstTmpFlag <> 0) and (dxdy > 0.4)) or |
|
449 ((State and gstTmpFlag = 0) and |
|
450 ((abs(odX) > 0.15) or ((abs(odY) > 0.15) and |
|
451 (abs(odX) > 0.02))) and (dxdy > 0.35)))) then |
|
452 begin |
|
453 dmg := trunc(dxdy * 50); |
|
454 exit(dmg) |
|
455 end |
|
456 else if (Kind = gtExplosives) and not((abs(odX) > 0.15) or ((abs(odY) > 0.15) and (abs(odX) > 0.02))) and (dY > 0.2) then |
|
457 begin |
|
458 dmg := trunc(dy * 70); |
|
459 exit(dmg) |
|
460 end |
|
461 end; |
402 exit(0) |
462 exit(0) |
403 end; |
463 end; |
404 if (y > cWaterLine) or (x > 4096) or (x < 0) then |
464 if (y > cWaterLine) or (x > rightX) or (x < leftX) then |
405 // returning -1 for drowning so it can be considered in the Rate routine |
465 // returning -1 for drowning so it can be considered in the Rate routine |
406 exit(-1) |
466 exit(-1) |
407 end; |
467 end; |
408 end; |
468 end; |
409 |
469 |
410 function RateExplosion(Me: PGear; x, y, r: LongInt): LongInt; |
470 function RateExplosion(Me: PGear; x, y, r: LongInt): LongInt; inline; |
411 begin |
471 begin |
412 RateExplosion:= RateExplosion(Me, x, y, r, 0); |
472 RateExplosion:= RealRateExplosion(Me, x, y, r, 0); |
413 end; |
473 ResetTargets; |
414 |
474 end; |
415 function RateExplosion(Me: PGear; x, y, r: LongInt; Flags: LongWord): LongInt; |
475 function RateExplosion(Me: PGear; x, y, r: LongInt; Flags: LongWord): LongInt; inline; |
416 var i, fallDmg, dmg, dmgBase, rate, erasure: LongInt; |
476 begin |
417 dX, dY, dmgMod: real; |
477 RateExplosion:= RealRateExplosion(Me, x, y, r, Flags); |
|
478 ResetTargets; |
|
479 end; |
|
480 |
|
481 function RealRateExplosion(Me: PGear; x, y, r: LongInt; Flags: LongWord): LongInt; |
|
482 var i, fallDmg, dmg, dmgBase, rate, subrate, erasure: LongInt; |
|
483 pX, pY, dX, dY: real; |
418 hadSkips: boolean; |
484 hadSkips: boolean; |
419 begin |
485 begin |
420 fallDmg:= 0; |
486 fallDmg:= 0; |
421 dmgMod:= 0.01 * hwFloat2Float(cDamageModifier) * cDamagePercent; |
|
422 rate:= 0; |
487 rate:= 0; |
423 // add our virtual position |
488 // add our virtual position |
424 with Targets.ar[Targets.Count] do |
489 with Targets.ar[Targets.Count] do |
425 begin |
490 begin |
426 Point.x:= hwRound(Me^.X); |
491 Point.x:= hwRound(Me^.X); |
427 Point.y:= hwRound(Me^.Y); |
492 Point.y:= hwRound(Me^.Y); |
428 skip:= false; |
493 skip:= false; |
429 matters:= true; |
494 matters:= true; |
|
495 Kind:= gtHedgehog; |
|
496 Density:= 1; |
|
497 Radius:= cHHRadius; |
430 Score:= - ThinkingHH^.Health |
498 Score:= - ThinkingHH^.Health |
431 end; |
499 end; |
432 // rate explosion |
500 // rate explosion |
433 dmgBase:= r + cHHRadius div 2; |
|
434 |
501 |
435 if (Flags and afErasesLand <> 0) and (GameFlags and gfSolidLand = 0) then erasure:= r |
502 if (Flags and afErasesLand <> 0) and (GameFlags and gfSolidLand = 0) then erasure:= r |
436 else erasure:= 0; |
503 else erasure:= 0; |
437 |
504 |
438 hadSkips:= false; |
505 hadSkips:= false; |
439 |
506 |
440 for i:= 0 to Targets.Count do |
507 for i:= 0 to Targets.Count do |
441 with Targets.ar[i] do |
508 if not Targets.ar[i].dead then |
442 if not matters then hadSkips:= true |
509 with Targets.ar[i] do |
443 else |
510 if not matters then hadSkips:= true |
444 begin |
511 else |
445 dmg:= 0; |
512 begin |
446 if abs(Point.x - x) + abs(Point.y - y) < dmgBase then |
513 dmg:= 0; |
447 dmg:= trunc(dmgMod * min((dmgBase - trunc(sqrt(sqr(Point.x - x)+sqr(Point.y - y)))) div 2, r)); |
514 dmgBase:= r + Radius div 2; |
448 |
515 if abs(Point.x - x) + abs(Point.y - y) < dmgBase then |
449 if dmg > 0 then |
516 dmg:= trunc(dmgMod * min((dmgBase - trunc(sqrt(sqr(Point.x - x)+sqr(Point.y - y)))) div 2, r)); |
450 begin |
517 |
451 if (Flags and afTrackFall <> 0) and (dmg < abs(Score)) then |
518 if dmg > 0 then |
452 begin |
519 begin |
453 dX:= 0.005 * dmg + 0.01; |
520 pX:= Point.x; |
454 dY:= dX; |
521 pY:= Point.y; |
455 if (x and LAND_WIDTH_MASK = 0) and ((y+cHHRadius+2) and LAND_HEIGHT_MASK = 0) and |
522 fallDmg:= 0; |
456 (Land[y+cHHRadius+2, x] and lfIndestructible <> 0) then |
523 if (Flags and afTrackFall <> 0) and (Score > 0) and (dmg < Score) then |
457 fallDmg:= trunc(TraceFall(x, y, Point.x, Point.y, dX, dY, 0) * dmgMod) |
524 begin |
458 else fallDmg:= trunc(TraceFall(x, y, Point.x, Point.y, dX, dY, erasure) * dmgMod) |
525 dX:= (0.005 * dmg + 0.01) / Density; |
459 end; |
526 dY:= dX; |
460 if fallDmg < 0 then // drowning. score healthier hogs higher, since their death is more likely to benefit the AI |
527 if (Kind = gtExplosives) and (State and gstTmpFlag = 0) and |
461 if Score > 0 then |
528 (((abs(dY) > 0.15) and (abs(dX) < 0.02)) or |
462 inc(rate, (KillScore + Score div 10) * 1024) // Add a bit of a bonus for bigger hog drownings |
529 ((abs(dY) < 0.15) and (abs(dX) < 0.15))) then |
463 else |
530 dX:= 0; |
464 dec(rate, (KillScore * friendlyfactor div 100 - Score div 10) * 1024) // and more of a punishment for drowning bigger friendly hogs |
531 |
465 else if (dmg+fallDmg) >= abs(Score) then |
532 if pX - x < 0 then dX:= -dX; |
466 if Score > 0 then |
533 if pY - y < 0 then dY:= -dY; |
467 inc(rate, KillScore * 1024 + (dmg + fallDmg)) // tiny bonus for dealing more damage than needed to kill |
534 |
468 else |
535 if (x and LAND_WIDTH_MASK = 0) and ((y+cHHRadius+2) and LAND_HEIGHT_MASK = 0) and |
469 dec(rate, KillScore * friendlyfactor div 100 * 1024) |
536 (Land[y+cHHRadius+2, x] and lfIndestructible <> 0) then |
470 else |
537 fallDmg:= trunc(TraceFall(x, y, pX, pY, dX, dY, 0, Targets.ar[i]) * dmgMod) |
471 if Score > 0 then |
538 else fallDmg:= trunc(TraceFall(x, y, pX, pY, dX, dY, erasure, Targets.ar[i]) * dmgMod) |
472 inc(rate, (dmg + fallDmg) * 1024) |
539 end; |
473 else dec(rate, (dmg + fallDmg) * friendlyfactor div 100 * 1024) |
540 if Kind = gtHedgehog then |
474 end; |
541 begin |
475 end; |
542 if fallDmg < 0 then // drowning. score healthier hogs higher, since their death is more likely to benefit the AI |
|
543 begin |
|
544 if Score > 0 then |
|
545 inc(rate, (KillScore + Score div 10) * 1024) // Add a bit of a bonus for bigger hog drownings |
|
546 else |
|
547 dec(rate, (KillScore * friendlyfactor div 100 - Score div 10) * 1024) // and more of a punishment for drowning bigger friendly hogs |
|
548 end |
|
549 else if (dmg+fallDmg) >= abs(Score) then |
|
550 begin |
|
551 dead:= true; |
|
552 Targets.reset:= true; |
|
553 if dX < 0.035 then |
|
554 begin |
|
555 subrate:= RealRateExplosion(Me, round(pX), round(pY), 61, afErasesLand or (Flags and afTrackFall)); |
|
556 if abs(subrate) > 2000 then inc(Rate,subrate) |
|
557 end; |
|
558 if Score > 0 then |
|
559 inc(rate, KillScore * 1024 + (dmg + fallDmg)) // tiny bonus for dealing more damage than needed to kill |
|
560 else dec(rate, KillScore * friendlyfactor div 100 * 1024) |
|
561 end |
|
562 else |
|
563 begin |
|
564 if Score > 0 then |
|
565 inc(rate, (dmg + fallDmg) * 1024) |
|
566 else dec(rate, (dmg + fallDmg) * friendlyfactor div 100 * 1024) |
|
567 end |
|
568 end |
|
569 else if (fallDmg >= 0) and ((dmg+fallDmg) >= Score) then |
|
570 begin |
|
571 dead:= true; |
|
572 Targets.reset:= true; |
|
573 if Kind = gtExplosives then |
|
574 subrate:= RealRateExplosion(Me, round(pX), round(pY), 151, afErasesLand or (Flags and afTrackFall)) |
|
575 else subrate:= RealRateExplosion(Me, round(pX), round(pY), 101, afErasesLand or (Flags and afTrackFall)); |
|
576 if abs(subrate) > 2000 then inc(Rate,subrate); |
|
577 end |
|
578 end |
|
579 end; |
476 |
580 |
477 if hadSkips and (rate = 0) then |
581 if hadSkips and (rate = 0) then |
478 RateExplosion:= BadTurn |
582 RealRateExplosion:= BadTurn |
479 else |
583 else |
480 RateExplosion:= rate; |
584 RealRateExplosion:= rate; |
481 end; |
585 end; |
482 |
586 |
483 function RateShove(x, y, r, power, kick: LongInt; gdX, gdY: real; Flags: LongWord): LongInt; |
587 function RateShove(Me: PGear; x, y, r, power, kick: LongInt; gdX, gdY: real; Flags: LongWord): LongInt; |
484 var i, fallDmg, dmg, rate: LongInt; |
588 var i, fallDmg, dmg, rate, subrate: LongInt; |
485 dX, dY, dmgMod: real; |
589 dX, dY, pX, pY: real; |
486 begin |
590 begin |
487 fallDmg:= 0; |
591 fallDmg:= 0; |
488 dX:= gdX * 0.01 * kick; |
592 dX:= gdX * 0.01 * kick; |
489 dY:= gdY * 0.01 * kick; |
593 dY:= gdY * 0.01 * kick; |
490 dmgMod:= 0.01 * hwFloat2Float(cDamageModifier) * cDamagePercent; |
|
491 rate:= 0; |
594 rate:= 0; |
492 for i:= 0 to Pred(Targets.Count) do |
595 for i:= 0 to Pred(Targets.Count) do |
493 with Targets.ar[i] do |
596 with Targets.ar[i] do |
494 if skip then |
597 if skip then |
495 if (Flags and afSetSkip = 0) then skip:= false else {still skip} |
598 begin |
496 else if matters then |
599 if Flags and afSetSkip = 0 then skip:= false |
497 begin |
600 end |
498 dmg:= 0; |
601 else if matters then |
499 if abs(Point.x - x) + abs(Point.y - y) < r then |
602 begin |
500 dmg:= r - trunc(sqrt(sqr(Point.x - x)+sqr(Point.y - y))); |
603 dmg:= 0; |
501 |
604 if abs(Point.x - x) + abs(Point.y - y) < r then |
502 if dmg > 0 then |
605 dmg:= r - trunc(sqrt(sqr(Point.x - x)+sqr(Point.y - y))); |
503 begin |
606 |
504 if (Flags and afSetSkip <> 0) then skip:= true; |
607 if dmg > 0 then |
505 if (Flags and afTrackFall <> 0) and (Score > 0) then |
608 begin |
506 fallDmg:= trunc(TraceShoveFall(Point.x, Point.y - 2, dX, dY) * dmgMod); |
609 pX:= Point.x; |
507 if fallDmg < 0 then // drowning. score healthier hogs higher, since their death is more likely to benefit the AI |
610 pY:= Point.y-2; |
508 if Score > 0 then |
611 fallDmg:= 0; |
509 inc(rate, KillScore + Score div 10) // Add a bit of a bonus for bigger hog drownings |
612 if (Flags and afSetSkip <> 0) then skip:= true; |
510 else |
613 if not(dead) and (Flags and afTrackFall <> 0) and (Score > 0) and (power < Score) then |
511 dec(rate, KillScore * friendlyfactor div 100 - Score div 10) // and more of a punishment for drowning bigger friendly hogs |
614 if (Kind = gtExplosives) and (State and gstTmpFlag = 0) and |
512 else if power+fallDmg >= abs(Score) then |
615 (((abs(dY) > 0.15) and (abs(dX) < 0.02)) or |
513 if Score > 0 then |
616 ((abs(dY) < 0.15) and (abs(dX) < 0.15))) then |
514 inc(rate, KillScore) |
617 fallDmg:= trunc(TraceShoveFall(pX, pY, 0, dY, Targets.ar[i]) * dmgMod) |
515 else |
618 else |
516 dec(rate, KillScore * friendlyfactor div 100) |
619 fallDmg:= trunc(TraceShoveFall(pX, pY, dX, dY, Targets.ar[i]) * dmgMod); |
517 else |
620 if Kind = gtHedgehog then |
518 if Score > 0 then |
621 begin |
519 inc(rate, power+fallDmg) |
622 if fallDmg < 0 then // drowning. score healthier hogs higher, since their death is more likely to benefit the AI |
520 else |
623 begin |
521 dec(rate, (power+fallDmg) * friendlyfactor div 100) |
624 if Score > 0 then |
522 end; |
625 inc(rate, KillScore + Score div 10) // Add a bit of a bonus for bigger hog drownings |
523 end; |
626 else |
524 RateShove:= rate * 1024 |
627 dec(rate, KillScore * friendlyfactor div 100 - Score div 10) // and more of a punishment for drowning bigger friendly hogs |
|
628 end |
|
629 else if power+fallDmg >= abs(Score) then |
|
630 begin |
|
631 dead:= true; |
|
632 Targets.reset:= true; |
|
633 if dX < 0.035 then |
|
634 begin |
|
635 subrate:= RealRateExplosion(Me, round(pX), round(pY), 61, afErasesLand or afTrackFall); |
|
636 if abs(subrate) > 2000 then inc(Rate,subrate div 1024) |
|
637 end; |
|
638 if Score > 0 then |
|
639 inc(rate, KillScore) |
|
640 else |
|
641 dec(rate, KillScore * friendlyfactor div 100) |
|
642 end |
|
643 else |
|
644 begin |
|
645 if Score > 0 then |
|
646 inc(rate, power+fallDmg) |
|
647 else |
|
648 dec(rate, (power+fallDmg) * friendlyfactor div 100) |
|
649 end |
|
650 end |
|
651 else if (fallDmg >= 0) and ((dmg+fallDmg) >= Score) then |
|
652 begin |
|
653 dead:= true; |
|
654 Targets.reset:= true; |
|
655 if Kind = gtExplosives then |
|
656 subrate:= RealRateExplosion(Me, round(pX), round(pY), 151, afErasesLand or (Flags and afTrackFall)) |
|
657 else subrate:= RealRateExplosion(Me, round(pX), round(pY), 101, afErasesLand or (Flags and afTrackFall)); |
|
658 if abs(subrate) > 2000 then inc(Rate,subrate div 1024); |
|
659 end |
|
660 end |
|
661 end; |
|
662 RateShove:= rate * 1024; |
|
663 ResetTargets |
525 end; |
664 end; |
526 |
665 |
527 function RateShotgun(Me: PGear; gdX, gdY: real; x, y: LongInt): LongInt; |
666 function RateShotgun(Me: PGear; gdX, gdY: real; x, y: LongInt): LongInt; |
528 var i, dmg, fallDmg, baseDmg, rate, erasure: LongInt; |
667 var i, dmg, fallDmg, baseDmg, rate, subrate, erasure: LongInt; |
529 dX, dY, dmgMod: real; |
668 pX, pY, dX, dY: real; |
530 hadSkips: boolean; |
669 hadSkips: boolean; |
531 begin |
670 begin |
532 dmgMod:= 0.01 * hwFloat2Float(cDamageModifier) * cDamagePercent; |
|
533 rate:= 0; |
671 rate:= 0; |
534 gdX:= gdX * 0.01; |
672 gdX:= gdX * 0.01; |
535 gdY:= gdX * 0.01; |
673 gdY:= gdX * 0.01; |
536 // add our virtual position |
674 // add our virtual position |
537 with Targets.ar[Targets.Count] do |
675 with Targets.ar[Targets.Count] do |
538 begin |
676 begin |
539 Point.x:= hwRound(Me^.X); |
677 Point.x:= hwRound(Me^.X); |
540 Point.y:= hwRound(Me^.Y); |
678 Point.y:= hwRound(Me^.Y); |
541 skip:= false; |
679 skip:= false; |
542 matters:= true; |
680 matters:= true; |
|
681 Kind:= gtHedgehog; |
|
682 Density:= 1; |
|
683 Radius:= cHHRadius; |
543 Score:= - ThinkingHH^.Health |
684 Score:= - ThinkingHH^.Health |
544 end; |
685 end; |
545 // rate shot |
686 // rate shot |
546 baseDmg:= cHHRadius + cShotgunRadius + 4; |
687 baseDmg:= cHHRadius + cShotgunRadius + 4; |
547 |
688 |
549 else erasure:= 0; |
690 else erasure:= 0; |
550 |
691 |
551 hadSkips:= false; |
692 hadSkips:= false; |
552 |
693 |
553 for i:= 0 to Targets.Count do |
694 for i:= 0 to Targets.Count do |
554 with Targets.ar[i] do |
695 if not Targets.ar[i].dead then |
555 if not matters then hadSkips:= true |
696 with Targets.ar[i] do |
556 else |
697 if not matters then hadSkips:= true |
557 begin |
|
558 dmg:= 0; |
|
559 if abs(Point.x - x) + abs(Point.y - y) < baseDmg then |
|
560 begin |
|
561 dmg:= min(baseDmg - trunc(sqrt(sqr(Point.x - x)+sqr(Point.y - y))), 25); |
|
562 dmg:= trunc(dmg * dmgMod); |
|
563 end; |
|
564 if dmg > 0 then |
|
565 begin |
|
566 dX:= gdX * dmg; |
|
567 dY:= gdY * dmg; |
|
568 if dX < 0 then dX:= dX - 0.01 |
|
569 else dX:= dX + 0.01; |
|
570 if (x and LAND_WIDTH_MASK = 0) and ((y+cHHRadius+2) and LAND_HEIGHT_MASK = 0) and |
|
571 (Land[y+cHHRadius+2, x] and lfIndestructible <> 0) then |
|
572 fallDmg:= trunc(TraceFall(x, y, Point.x, Point.y, dX, dY, 0) * dmgMod) |
|
573 else fallDmg:= trunc(TraceFall(x, y, Point.x, Point.y, dX, dY, erasure) * dmgMod); |
|
574 if fallDmg < 0 then // drowning. score healthier hogs higher, since their death is more likely to benefit the AI |
|
575 if Score > 0 then |
|
576 inc(rate, KillScore + Score div 10) // Add a bit of a bonus for bigger hog drownings |
|
577 else |
|
578 dec(rate, KillScore * friendlyfactor div 100 - Score div 10) // and more of a punishment for drowning bigger friendly hogs |
|
579 else if (dmg+fallDmg) >= abs(Score) then |
|
580 if Score > 0 then |
|
581 inc(rate, KillScore) |
|
582 else |
|
583 dec(rate, KillScore * friendlyfactor div 100) |
|
584 else |
698 else |
585 if Score > 0 then |
699 begin |
586 inc(rate, dmg+fallDmg) |
700 dmg:= 0; |
587 else |
701 if abs(Point.x - x) + abs(Point.y - y) < baseDmg then |
588 dec(rate, (dmg+fallDmg) * friendlyfactor div 100) |
702 begin |
589 end; |
703 dmg:= min(baseDmg - trunc(sqrt(sqr(Point.x - x)+sqr(Point.y - y))), 25); |
590 end; |
704 dmg:= trunc(dmg * dmgMod); |
|
705 end; |
|
706 if dmg > 0 then |
|
707 begin |
|
708 if not(dead) and (Score > 0) and (dmg < Score) then |
|
709 begin |
|
710 pX:= Point.x; |
|
711 pY:= Point.y; |
|
712 dX:= gdX * dmg / Density; |
|
713 dY:= gdY * dmg / Density; |
|
714 if dX < 0 then dX:= dX - 0.01 |
|
715 else dX:= dX + 0.01; |
|
716 if (Kind = gtExplosives) and (State and gstTmpFlag = 0) and |
|
717 (((abs(dY) > 0.15) and (abs(dX) < 0.02)) or |
|
718 ((abs(dY) < 0.15) and (abs(dX) < 0.15))) then |
|
719 dX:= 0; |
|
720 if (x and LAND_WIDTH_MASK = 0) and ((y+cHHRadius+2) and LAND_HEIGHT_MASK = 0) and |
|
721 (Land[y+cHHRadius+2, x] and lfIndestructible <> 0) then |
|
722 fallDmg:= trunc(TraceFall(x, y, pX, pY, dX, dY, 0, Targets.ar[i]) * dmgMod) |
|
723 else fallDmg:= trunc(TraceFall(x, y, pX, pY, dX, dY, erasure, Targets.ar[i]) * dmgMod) |
|
724 end; |
|
725 if Kind = gtHedgehog then |
|
726 begin |
|
727 if fallDmg < 0 then // drowning. score healthier hogs higher, since their death is more likely to benefit the AI |
|
728 begin |
|
729 if Score > 0 then |
|
730 inc(rate, KillScore + Score div 10) // Add a bit of a bonus for bigger hog drownings |
|
731 else |
|
732 dec(rate, KillScore * friendlyfactor div 100 - Score div 10) // and more of a punishment for drowning bigger friendly hogs |
|
733 end |
|
734 else if (dmg+fallDmg) >= abs(Score) then |
|
735 begin |
|
736 dead:= true; |
|
737 Targets.reset:= true; |
|
738 if dX < 0.035 then |
|
739 begin |
|
740 subrate:= RealRateExplosion(Me, round(pX), round(pY), 61, afErasesLand or afTrackFall); |
|
741 if abs(subrate) > 2000 then inc(Rate,subrate div 1024) |
|
742 end; |
|
743 if Score > 0 then |
|
744 inc(rate, KillScore) |
|
745 else |
|
746 dec(rate, KillScore * friendlyfactor div 100) |
|
747 end |
|
748 else if Score > 0 then |
|
749 inc(rate, dmg+fallDmg) |
|
750 else dec(rate, (dmg+fallDmg) * friendlyfactor div 100) |
|
751 end |
|
752 else if (fallDmg >= 0) and ((dmg+fallDmg) >= Score) then |
|
753 begin |
|
754 dead:= true; |
|
755 Targets.reset:= true; |
|
756 if Kind = gtExplosives then |
|
757 subrate:= RealRateExplosion(Me, round(pX), round(pY), 151, afErasesLand or afTrackFall) |
|
758 else subrate:= RealRateExplosion(Me, round(pX), round(pY), 101, afErasesLand or afTrackFall); |
|
759 if abs(subrate) > 2000 then inc(Rate,subrate div 1024); |
|
760 end |
|
761 end |
|
762 end; |
591 |
763 |
592 if hadSkips and (rate = 0) then |
764 if hadSkips and (rate = 0) then |
593 RateShotgun:= BadTurn |
765 RateShotgun:= BadTurn |
594 else |
766 else |
595 RateShotgun:= rate * 1024; |
767 RateShotgun:= rate * 1024; |
|
768 ResetTargets; |
596 end; |
769 end; |
597 |
770 |
598 function RateHammer(Me: PGear): LongInt; |
771 function RateHammer(Me: PGear): LongInt; |
599 var x, y, i, r, rate: LongInt; |
772 var x, y, i, r, rate: LongInt; |
600 begin |
773 begin |