hedgewars/uAIMisc.pas
changeset 8962 9780e79619ed
parent 8961 b157302674cf
child 8963 1a8335f0d968
equal deleted inserted replaced
8961:b157302674cf 8962:9780e79619ed
    28       afErasesLand = $00000002;
    28       afErasesLand = $00000002;
    29       afSetSkip    = $00000004;
    29       afSetSkip    = $00000004;
    30 
    30 
    31       BadTurn = Low(LongInt) div 4;
    31       BadTurn = Low(LongInt) div 4;
    32 
    32 
    33 type TTarget = record
    33 type TTarget = record // starting to look more and more like a gear
    34     Point: TPoint;
    34     Point: TPoint;
    35     Score: LongInt;
    35     Score, Radius: LongInt;
       
    36     Flags: LongWord;
    36     Density: real;
    37     Density: real;
    37     skip, matters, dead: boolean;
    38     skip, matters, dead: boolean;
    38     Kind: TGearType;
    39     Kind: TGearType;
    39     end;
    40     end;
    40 TTargets = record
    41 TTargets = record
   121 f:= 0;
   122 f:= 0;
   122 e:= 0;
   123 e:= 0;
   123 Gear:= GearsList;
   124 Gear:= GearsList;
   124 while Gear <> nil do
   125 while Gear <> nil do
   125     begin
   126     begin
   126     if  ((Gear^.Kind = gtHedgehog) and
   127     if  (((Gear^.Kind = gtHedgehog) and
   127             (Gear <> ThinkingHH) and
   128             (Gear <> ThinkingHH) and
   128             (Gear^.Health > Gear^.Damage) and
   129             (Gear^.Health > Gear^.Damage) and
   129             not(Gear^.Hedgehog^.Team^.hasgone)) or
   130             not(Gear^.Hedgehog^.Team^.hasgone)) or
   130         ((Gear^.Kind = gtExplosives) and
   131         ((Gear^.Kind = gtExplosives) and
   131             (Gear^.Health > Gear^.Damage)) or
   132             (Gear^.Health > Gear^.Damage)) or
   133             ((Gear^.Health = 0) and
   134             ((Gear^.Health = 0) and
   134              (Gear^.Damage < 35)) or
   135              (Gear^.Damage < 35)) or
   135             ((Gear^.Health > 0) and 
   136             ((Gear^.Health > 0) and 
   136              (cMineDudPercent > 95) and
   137              (cMineDudPercent > 95) and
   137              (cMinesTime < 3000)) 
   138              (cMinesTime < 3000)) 
   138              ) and
   139              ))  and 
   139         (Targets.Count < 256) then
   140         (Targets.Count < 256) then
   140         begin
   141         begin
   141         with Targets.ar[Targets.Count] do
   142         with Targets.ar[Targets.Count] do
   142             begin
   143             begin
   143             skip:= false;
   144             skip:= false;
   144             dead:= false;
   145             dead:= false;
   145             Kind:= Gear^.Kind;
   146             Kind:= Gear^.Kind;
       
   147             Radius:= Gear^.Radius;
       
   148             Flags:= Gear^.State;
   146             matters:= (Gear^.AIHints and aihDoesntMatter) = 0;
   149             matters:= (Gear^.AIHints and aihDoesntMatter) = 0;
   147 
   150 
   148             Point.X:= hwRound(Gear^.X);
   151             Point.X:= hwRound(Gear^.X);
   149             Point.Y:= hwRound(Gear^.Y);
   152             Point.Y:= hwRound(Gear^.Y);
   150             if (Gear^.Kind = gtHedgehog) then
   153             if (Gear^.Kind = gtHedgehog) then
   364     TestCollExcludingMe:= TestCollWithEverything(x, y, r)
   367     TestCollExcludingMe:= TestCollWithEverything(x, y, r)
   365 end;
   368 end;
   366 
   369 
   367 
   370 
   368 
   371 
   369 function TraceFall(eX, eY: LongInt; var x, y: Real; dX, dY: Real; r: LongWord; Kind: TGearType): LongInt;
   372 function TraceFall(eX, eY: LongInt; var x, y: Real; dX, dY: Real; r: LongWord; Target: TTarget): LongInt;
   370 var skipLandCheck: boolean;
   373 var skipLandCheck: boolean;
   371     rCorner, dxdy: real;
   374     rCorner, dxdy, odX, odY: real;
   372     dmg, radius: LongInt;
   375     dmg: LongInt;
   373 begin
   376 begin
       
   377     odX:= dX;
       
   378     odY:= dY;
   374     skipLandCheck:= true;
   379     skipLandCheck:= true;
   375     if x - eX < 0 then dX:= -dX;
   380     if x - eX < 0 then dX:= -dX;
   376     if y - eY < 0 then dY:= -dY;
   381     if y - eY < 0 then dY:= -dY;
   377     // ok. attempt approximate search for an unbroken trajectory into water.  if it continues far enough, assume out of map
   382     // ok. attempt approximate search for an unbroken trajectory into water.  if it continues far enough, assume out of map
   378     if Kind = gtHedgehog then 
       
   379         radius:= cHHRadius
       
   380     else if Kind = gtExplosives then
       
   381         radius:= 16
       
   382     else if Kind = gtMine then
       
   383         radius:= 2;
       
   384     rCorner:= r * 0.75;
   383     rCorner:= r * 0.75;
   385     while true do
   384     while true do
   386         begin
   385         begin
   387         x:= x + dX;
   386         x:= x + dX;
   388         y:= y + dY;
   387         y:= y + dY;
   389         dY:= dY + cGravityf;
   388         dY:= dY + cGravityf;
   390         skipLandCheck:= skipLandCheck and (r <> 0) and (abs(eX-x) + abs(eY-y) < r) and ((abs(eX-x) < rCorner) or (abs(eY-y) < rCorner));
   389         skipLandCheck:= skipLandCheck and (r <> 0) and (abs(eX-x) + abs(eY-y) < r) and ((abs(eX-x) < rCorner) or (abs(eY-y) < rCorner));
   391         if not skipLandCheck and TestCollExcludingObjects(trunc(x), trunc(y), radius) then
   390         if not skipLandCheck and TestCollExcludingObjects(trunc(x), trunc(y), Target.Radius) then
   392             begin
   391             with Target do
   393             if (Kind = gtHedgehog) and (0.4 < dY) then
   392                 begin
   394                 begin
   393                 if (Kind = gtHedgehog) and (0.4 < dY) then
   395                 dmg := 1 + trunc((abs(dY) - 0.4) * 70);
   394                     begin
   396                 if dmg >= 1 then exit(dmg)
   395                     dmg := 1 + trunc((abs(dY) - 0.4) * 70);
   397                 end
   396                     if dmg >= 1 then exit(dmg)
   398             else 
       
   399                 begin
       
   400                 dxdy:= abs(dX)+abs(dY);
       
   401 // so we don't know at present if a barrel is already rolling.  Would need to add that to target info I guess
       
   402 // a barrel oriented vertically only considers dY. however, AI doesn't know to use hammer, and could only bat vertically w/ bat, so probably shouldn't matter
       
   403                 if (dxdy > 0.3) then
       
   404                     begin
       
   405                     dmg := 1 + trunc(dxdy * 25);
       
   406                     exit(dmg)
       
   407                     end
   397                     end
   408                 end;
   398                 else 
       
   399                     begin
       
   400                     dxdy:= abs(dX)+abs(dY);
       
   401                     if ((Kind = gtMine) and (dxdy > 0.35)) or 
       
   402                        ((Kind = gtExplosives) and 
       
   403                             (((Flags and gstTmpFlag <> 0) and (dxdy > 0.35)) or
       
   404                              ((Flags and gstTmpFlag <> 0) and 
       
   405                                 ((abs(odX) > 0.15) or ((abs(odY) > 0.15) and 
       
   406                                 (abs(odX) > 0.02))) and (dxdy > 0.35)))) then
       
   407                         begin
       
   408                         dmg := 1 + trunc(dxdy * 25);
       
   409                         exit(dmg)
       
   410                         end
       
   411                     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
       
   412                         begin
       
   413                         dmg := 1 + trunc(dy * 70);
       
   414                         exit(dmg)
       
   415                         end
       
   416                     end;
   409             exit(0)
   417             exit(0)
   410             end;
   418             end;
   411         if (y > cWaterLine) or (x > leftX) or (x < rightX) then exit(-1)
   419         if (y > cWaterLine) or (x > leftX) or (x < rightX) then exit(-1)
   412         end
   420         end
   413 end;
   421 end;
   414 
   422 
   415 function TraceShoveFall(var x, y: Real; dX, dY: Real; Kind: TGearType): LongInt;
   423 function TraceShoveFall(var x, y: Real; dX, dY: Real; Target: TTarget): LongInt;
   416 var dmg, radius: LongInt;
   424 var dmg: LongInt;
   417     dxdy: real;
   425     dxdy, odX, odY: real;
   418 begin
   426 begin
       
   427     odX:= dX;
       
   428     odY:= dY;
   419 //v:= random($FFFFFFFF);
   429 //v:= random($FFFFFFFF);
   420     if Kind = gtHedgehog then 
       
   421         radius:= cHHRadius
       
   422     else if Kind = gtExplosives then
       
   423         radius:= 16
       
   424     else if Kind = gtMine then
       
   425         radius:= 2;
       
   426     while true do
   430     while true do
   427         begin
   431         begin
   428         x:= x + dX;
   432         x:= x + dX;
   429         y:= y + dY;
   433         y:= y + dY;
   430         dY:= dY + cGravityf;
   434         dY:= dY + cGravityf;
   433             begin
   437             begin
   434             LandPixels[trunc(y), trunc(x)]:= v;
   438             LandPixels[trunc(y), trunc(x)]:= v;
   435             UpdateLandTexture(trunc(X), 1, trunc(Y), 1, true);
   439             UpdateLandTexture(trunc(X), 1, trunc(Y), 1, true);
   436             end;}
   440             end;}
   437 
   441 
   438 
   442         if TestCollExcludingObjects(trunc(x), trunc(y), Target.Radius) then
   439         // consider adding dX/dY calc here for fall damage
   443             with Target do
   440         if TestCollExcludingObjects(trunc(x), trunc(y), cHHRadius) then
   444                 begin
   441             begin
   445                 if (Kind = gtHedgehog) and (0.4 < dY) then
   442             if (Kind = gtHedgehog) and (0.4 < dY) then
   446                     begin
   443                 begin
   447                     dmg := 1 + trunc((abs(dY) - 0.4) * 70);
   444                 dmg := 1 + trunc((abs(dY) - 0.4) * 70);
   448                     if dmg >= 1 then
   445                 if dmg >= 1 then
   449                         exit(dmg);
   446                     exit(dmg);
       
   447                 end
       
   448             else 
       
   449                 begin
       
   450                 dxdy:= abs(dX)+abs(dY);
       
   451 // so we don't know at present if a barrel is already rolling.  Would need to add that to target info I guess
       
   452 // a barrel oriented vertically only considers dY. however, AI doesn't know to use hammer, and could only bat vertically w/ bat, so probably shouldn't matter
       
   453                 if (dxdy > 0.3) then
       
   454                     begin
       
   455                     dmg := 1 + trunc(dxdy * 25);
       
   456                     exit(dmg)
       
   457                     end
   450                     end
   458                 end;
   451                 else 
       
   452                     begin
       
   453                     dxdy:= abs(dX)+abs(dY);
       
   454                     if ((Kind = gtMine) and (dxdy > 0.35)) or 
       
   455                        ((Kind = gtExplosives) and 
       
   456                             (((Flags and gstTmpFlag <> 0) and (dxdy > 0.35)) or
       
   457                              ((Flags and gstTmpFlag <> 0) and 
       
   458                                 ((abs(odX) > 0.15) or ((abs(odY) > 0.15) and 
       
   459                                 (abs(odX) > 0.02))) and (dxdy > 0.35)))) then
       
   460                         begin
       
   461                         dmg := 1 + trunc(dxdy * 25);
       
   462                         exit(dmg)
       
   463                         end
       
   464                     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
       
   465                         begin
       
   466                         dmg := 1 + trunc(dy * 70);
       
   467                         exit(dmg)
       
   468                         end
       
   469                     end;
   459             exit(0)
   470             exit(0)
   460         end;
   471         end;
   461         if (y > cWaterLine) or (x > leftX) or (x < rightX) then
   472         if (y > cWaterLine) or (x > leftX) or (x < rightX) then
   462             // returning -1 for drowning so it can be considered in the Rate routine
   473             // returning -1 for drowning so it can be considered in the Rate routine
   463             exit(-1)
   474             exit(-1)
   513 
   524 
   514             if dmg > 0 then
   525             if dmg > 0 then
   515                 begin
   526                 begin
   516                 pX:= Point.x;
   527                 pX:= Point.x;
   517                 pY:= Point.y;
   528                 pY:= Point.y;
       
   529                 fallDmg:= 0;
   518                 if (Flags and afTrackFall <> 0) and (dmg < abs(Score)) then
   530                 if (Flags and afTrackFall <> 0) and (dmg < abs(Score)) then
   519                     begin
   531                     begin
   520                     dX:= (0.005 * dmg + 0.01) / Density;
   532                     dX:= (0.005 * dmg + 0.01) / Density;
   521                     dY:= dX;
   533                     dY:= dX;
   522                     if (Kind = gtExplosives) and 
   534                     if (Kind = gtExplosives) and 
   523                        (((abs(dY) > 0.15) and (abs(dX) < 0.02)) or
   535                        (((abs(dY) > 0.15) and (abs(dX) < 0.02)) or
   524                         ((abs(dY) < 0.15) and (abs(dX) < 0.15))) then
   536                         ((abs(dY) < 0.15) and (abs(dX) < 0.15))) then
   525                         dX:= 0;
   537                         dX:= 0;
   526                     if (x and LAND_WIDTH_MASK = 0) and ((y+cHHRadius+2) and LAND_HEIGHT_MASK = 0) and
   538                     if (x and LAND_WIDTH_MASK = 0) and ((y+cHHRadius+2) and LAND_HEIGHT_MASK = 0) and
   527                        (Land[y+cHHRadius+2, x] and lfIndestructible <> 0) then
   539                        (Land[y+cHHRadius+2, x] and lfIndestructible <> 0) then
   528                          fallDmg:= trunc(TraceFall(x, y, pX, pY, dX, dY, 0, Kind) * dmgMod)
   540                          fallDmg:= trunc(TraceFall(x, y, pX, pY, dX, dY, 0, Targets.ar[i]) * dmgMod)
   529                     else fallDmg:= trunc(TraceFall(x, y, pX, pY, dX, dY, erasure, Kind) * dmgMod)
   541                     else fallDmg:= trunc(TraceFall(x, y, pX, pY, dX, dY, erasure, Targets.ar[i]) * dmgMod)
   530                     end;
   542                     end;
   531                 if Kind = gtHedgehog then
   543                 if Kind = gtHedgehog then
   532                     begin
   544                     begin
   533                     if fallDmg < 0 then // drowning. score healthier hogs higher, since their death is more likely to benefit the AI
   545                     if fallDmg < 0 then // drowning. score healthier hogs higher, since their death is more likely to benefit the AI
   534                         begin
   546                         begin
   555                         if Score > 0 then
   567                         if Score > 0 then
   556                              inc(rate, (dmg + fallDmg) * 1024)
   568                              inc(rate, (dmg + fallDmg) * 1024)
   557                         else dec(rate, (dmg + fallDmg) * friendlyfactor div 100 * 1024)
   569                         else dec(rate, (dmg + fallDmg) * friendlyfactor div 100 * 1024)
   558                         end
   570                         end
   559                     end
   571                     end
   560 // FIXME - need to make TraceFall calculate damage for barrels/mines correctly
   572                 else if (fallDmg >= 0) and ((dmg+fallDmg) >= Score) then
   561                 else if (Kind <> gtHedgehog) and (FallDmg >= 0) and ((dmg+fallDmg) >= Score) then
       
   562                     begin
   573                     begin
   563                     dead:= true;
   574                     dead:= true;
   564                     Targets.reset:= true;
   575                     Targets.reset:= true;
   565                     if Kind = gtExplosives then
   576                     if Kind = gtExplosives then
   566                          subrate:= RealRateExplosion(Me, round(pX), round(pY), 151, afErasesLand or (Flags and afTrackFall))
   577                          subrate:= RealRateExplosion(Me, round(pX), round(pY), 151, afErasesLand or (Flags and afTrackFall))
   596 
   607 
   597         if dmg > 0 then
   608         if dmg > 0 then
   598             begin
   609             begin
   599             pX:= Point.x;
   610             pX:= Point.x;
   600             pY:= Point.y-2;
   611             pY:= Point.y-2;
       
   612             fallDmg:= 0;
   601             if (Flags and afSetSkip <> 0) then skip:= true;
   613             if (Flags and afSetSkip <> 0) then skip:= true;
   602             if (Flags and afTrackFall <> 0) and (Score > 0) then
   614             if (Flags and afTrackFall <> 0) and (Score > 0) then
   603                 fallDmg:= trunc(TraceShoveFall(pX, pY, dX, dY, Kind) * dmgMod);
   615                 fallDmg:= trunc(TraceShoveFall(pX, pY, dX, dY, Targets.ar[i]) * dmgMod);
   604             if Kind = gtHedgehog then
   616             if Kind = gtHedgehog then
   605                 begin
   617                 begin
   606                 if fallDmg < 0 then // drowning. score healthier hogs higher, since their death is more likely to benefit the AI
   618                 if fallDmg < 0 then // drowning. score healthier hogs higher, since their death is more likely to benefit the AI
   607                     begin
   619                     begin
   608                     if Score > 0 then
   620                     if Score > 0 then
   630                         inc(rate, power+fallDmg)
   642                         inc(rate, power+fallDmg)
   631                     else
   643                     else
   632                         dec(rate, (power+fallDmg) * friendlyfactor div 100)
   644                         dec(rate, (power+fallDmg) * friendlyfactor div 100)
   633                     end
   645                     end
   634                 end
   646                 end
   635 // FIXME - need to make TraceFall calculate damage for barrels/mines correctly
   647             else if (fallDmg >= 0) and ((dmg+fallDmg) >= Score) then
   636             else if (Kind <> gtHedgehog) and (fallDmg >= 0) and ((power+fallDmg) >= Score) then
       
   637                 begin
   648                 begin
   638                 dead:= true;
   649                 dead:= true;
   639                 Targets.reset:= true;
   650                 Targets.reset:= true;
   640                 if Kind = gtExplosives then
   651                 if Kind = gtExplosives then
   641                      subrate:= RealRateExplosion(Me, round(pX), round(pY), 151, afErasesLand or (Flags and afTrackFall))
   652                      subrate:= RealRateExplosion(Me, round(pX), round(pY), 151, afErasesLand or (Flags and afTrackFall))
   694                 dY:= gdY * dmg / Density;
   705                 dY:= gdY * dmg / Density;
   695                 if dX < 0 then dX:= dX - 0.01
   706                 if dX < 0 then dX:= dX - 0.01
   696                 else dX:= dX + 0.01;
   707                 else dX:= dX + 0.01;
   697                 if (x and LAND_WIDTH_MASK = 0) and ((y+cHHRadius+2) and LAND_HEIGHT_MASK = 0) and
   708                 if (x and LAND_WIDTH_MASK = 0) and ((y+cHHRadius+2) and LAND_HEIGHT_MASK = 0) and
   698                    (Land[y+cHHRadius+2, x] and lfIndestructible <> 0) then
   709                    (Land[y+cHHRadius+2, x] and lfIndestructible <> 0) then
   699                      fallDmg:= trunc(TraceFall(x, y, pX, pY, dX, dY, 0, Kind) * dmgMod)
   710                      fallDmg:= trunc(TraceFall(x, y, pX, pY, dX, dY, 0, Targets.ar[i]) * dmgMod)
   700                 else fallDmg:= trunc(TraceFall(x, y, pX, pY, dX, dY, erasure, Kind) * dmgMod);
   711                 else fallDmg:= trunc(TraceFall(x, y, pX, pY, dX, dY, erasure, Targets.ar[i]) * dmgMod);
   701                 if Kind = gtHedgehog then
   712                 if Kind = gtHedgehog then
   702                     begin
   713                     begin
   703                     if fallDmg < 0 then // drowning. score healthier hogs higher, since their death is more likely to benefit the AI
   714                     if fallDmg < 0 then // drowning. score healthier hogs higher, since their death is more likely to benefit the AI
   704                         begin
   715                         begin
   705                         if Score > 0 then
   716                         if Score > 0 then
   723                         end
   734                         end
   724                     else if Score > 0 then
   735                     else if Score > 0 then
   725                          inc(rate, dmg+fallDmg)
   736                          inc(rate, dmg+fallDmg)
   726                     else dec(rate, (dmg+fallDmg) * friendlyfactor div 100)
   737                     else dec(rate, (dmg+fallDmg) * friendlyfactor div 100)
   727                     end
   738                     end
   728 // FIXME - need to make TraceFall calculate damage for barrels/mines correctly
   739                 else if (fallDmg >= 0) and ((dmg+fallDmg) >= Score) then
   729                 else if (Kind <> gtHedgehog) and (fallDmg >= 0) and ((dmg+fallDmg) >= Score) then
       
   730                     begin
   740                     begin
   731                     dead:= true;
   741                     dead:= true;
   732                     Targets.reset:= true;
   742                     Targets.reset:= true;
   733                     if Kind = gtExplosives then
   743                     if Kind = gtExplosives then
   734                          subrate:= RealRateExplosion(Me, round(pX), round(pY), 151, afErasesLand or afTrackFall)
   744                          subrate:= RealRateExplosion(Me, round(pX), round(pY), 151, afErasesLand or afTrackFall)