hedgewars/uAIMisc.pas
changeset 64 9df467527ae5
parent 53 0e27949850e3
child 66 9643d75baf1e
equal deleted inserted replaced
63:27e2b5bb6d4b 64:9df467527ae5
     1 (*
       
     2  * Hedgewars, a worms-like game
       
     3  * Copyright (c) 2005 Andrey Korotaev <unC0Rr@gmail.com>
       
     4  *
       
     5  * Distributed under the terms of the BSD-modified licence:
       
     6  *
       
     7  * Permission is hereby granted, free of charge, to any person obtaining a copy
       
     8  * of this software and associated documentation files (the "Software"), to deal
       
     9  * with the Software without restriction, including without limitation the
       
    10  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
       
    11  * sell copies of the Software, and to permit persons to whom the Software is
       
    12  * furnished to do so, subject to the following conditions:
       
    13  *
       
    14  * 1. Redistributions of source code must retain the above copyright notice,
       
    15  *    this list of conditions and the following disclaimer.
       
    16  * 2. Redistributions in binary form must reproduce the above copyright notice,
       
    17  *    this list of conditions and the following disclaimer in the documentation
       
    18  *    and/or other materials provided with the distribution.
       
    19  * 3. The name of the author may not be used to endorse or promote products
       
    20  *    derived from this software without specific prior written permission.
       
    21  *
       
    22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
       
    23  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
       
    24  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
       
    25  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
       
    26  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
       
    27  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
       
    28  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
       
    29  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
       
    30  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
       
    31  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
       
    32  *)
       
    33 
       
    34 unit uAIMisc;
     1 unit uAIMisc;
    35 interface
     2 interface
    36 uses uConsts, uGears, SDLh;
     3 uses SDLh, uConsts;
    37 {$INCLUDE options.inc}
       
    38 
     4 
    39 type TTargets = record
     5 type TTarget = record
    40                 Count: integer;
     6                Point: TPoint;
    41                 ar: array[0..cMaxHHIndex*5] of TPoint;
     7                Score: integer;
       
     8                end;
       
     9      TTargets = record
       
    10                 Count: Longword;
       
    11                 ar: array[0..cMaxHHIndex*5] of TTarget;
    42                 end;
    12                 end;
    43                 
    13 
    44 procedure FillTargets(var Targets: TTargets);
    14 procedure FillTargets(var Targets: TTargets);
    45 function DxDy2Angle(const _dY, _dX: Extended): integer;
    15 function DxDy2AttackAngle(const _dY, _dX: Extended): integer;
    46 function TestColl(x, y, r: integer): boolean;
    16 function TestColl(x, y, r: integer): boolean;
    47 function NoMyHHNear(x, y, r: integer): boolean;
    17 function NoMyHHNear(x, y, r: integer): boolean;
    48 function HHGo(Gear: PGear): boolean;
       
    49 
    18 
    50 implementation
    19 implementation
    51 uses uTeams, uStore, uMisc, uLand, uCollisions;
    20 uses uTeams, uMisc, uLand;
    52 
    21 
    53 procedure FillTargets(var Targets: TTargets);
    22 procedure FillTargets(var Targets: TTargets);
    54 var t: PTeam;
    23 var t: PTeam;
    55     i, k: integer;
    24     i: Longword;
    56     r: integer;
       
    57     MaxHealth: integer;
       
    58     score: array[0..cMaxHHIndex*5] of integer;
       
    59 
       
    60   procedure qSort(iLo, iHi: Integer);
       
    61   var
       
    62     Lo, Hi, Mid, T: Integer;
       
    63     P: TPoint;
       
    64   begin
       
    65     Lo := iLo;
       
    66     Hi := iHi;
       
    67     Mid := score[(Lo + Hi) div 2];
       
    68     repeat
       
    69       while score[Lo] > Mid do Inc(Lo);
       
    70       while score[Hi] < Mid do Dec(Hi);
       
    71       if Lo <= Hi then
       
    72       begin
       
    73         T := score[Lo];
       
    74         score[Lo] := score[Hi];
       
    75         score[Hi] := T;
       
    76         P := Targets.ar[Lo];
       
    77         Targets.ar[Lo] := Targets.ar[Hi];
       
    78         Targets.ar[Hi] := P;
       
    79         Inc(Lo);
       
    80         Dec(Hi)
       
    81       end;
       
    82     until Lo > Hi;
       
    83     if Hi > iLo then qSort(iLo, Hi);
       
    84     if Lo < iHi then qSort(Lo, iHi);
       
    85   end;
       
    86 
       
    87 begin
    25 begin
    88 Targets.Count:= 0;
    26 Targets.Count:= 0;
    89 t:= TeamsList;
    27 t:= TeamsList;
    90 MaxHealth:= 0;
       
    91 while t <> nil do
    28 while t <> nil do
    92       begin
    29       begin
    93       if t <> CurrentTeam then
    30       if t <> CurrentTeam then
    94          for i:= 0 to cMaxHHIndex do
    31          for i:= 0 to cMaxHHIndex do
    95              if t.Hedgehogs[i].Gear <> nil then
    32              if t.Hedgehogs[i].Gear <> nil then
    96                 begin
    33                 begin
    97                 with Targets.ar[Targets.Count], t.Hedgehogs[i] do
    34                 with Targets.ar[Targets.Count], t.Hedgehogs[i] do
    98                      begin
    35                      begin
    99                      X:= Round(Gear.X);
    36                      Point.X:= Round(Gear.X);
   100                      Y:= Round(Gear.Y);
    37                      Point.Y:= Round(Gear.Y);
   101                      if integer(Gear.Health) > MaxHealth then MaxHealth:= Gear.Health;
    38                      Score:= 100 - Gear.Health
   102                      score[Targets.Count]:= random(3) - integer(Gear.Health div 5)
       
   103                      end;
    39                      end;
   104                 inc(Targets.Count)
    40                 inc(Targets.Count)
   105                 end;
    41                 end;
   106       t:= t.Next
    42       t:= t.Next
   107       end;
    43       end
   108 // выставляем оценку за попадание в ёжика:
       
   109 //  - если есть соседи-противники, то оценка увеличивается
       
   110 //  - чем меньше хелса у ёжика, тем больше оценка (код см. выше)
       
   111 //  - если есть соседи-"свои", то уменьшается
       
   112 with Targets do
       
   113      for i:= 0 to Targets.Count - 1 do
       
   114          begin
       
   115          for k:= Succ(i) to Pred(Targets.Count) do
       
   116              begin
       
   117              r:= 100 - round(sqrt(sqr(ar[i].X - ar[k].X) + sqr(ar[i].Y - ar[k].Y)));
       
   118              if r > 0 then
       
   119                 begin
       
   120                 inc(score[i], r);
       
   121                 inc(score[k], r)
       
   122                 end;
       
   123              end;
       
   124          for k:= 0 to cMaxHHIndex do
       
   125              with CurrentTeam.Hedgehogs[k] do
       
   126                   if Gear <> nil then
       
   127                      begin
       
   128                      r:= 100 - round(sqrt(sqr(ar[i].X - round(Gear.X)) + sqr(ar[i].Y - round(Gear.Y))));
       
   129                      if r > 0 then dec(score[i], (r * 3) div 2 + MaxHealth + 5 - integer(Gear.Health));
       
   130                      end;
       
   131          end;
       
   132 // сортируем по убыванию согласно оценке
       
   133 if Targets.Count >= 2 then qSort(0, Pred(Targets.Count));
       
   134 end;
    44 end;
   135 
    45 
   136 function DxDy2Angle(const _dY, _dX: Extended): integer;
    46 function DxDy2AttackAngle(const _dY, _dX: Extended): integer;
   137 const piDIVMaxAngle: Extended = pi/cMaxAngle;
    47 const piDIVMaxAngle: Extended = pi/cMaxAngle;
   138 asm
    48 asm
   139         fld     _dY
    49         fld     _dY
   140         fld     _dX
    50         fld     _dX
   141         fpatan
    51         fpatan
   173              end;
    83              end;
   174 inc(i)
    84 inc(i)
   175 until i > cMaxHHIndex
    85 until i > cMaxHHIndex
   176 end;
    86 end;
   177 
    87 
   178 function HHGo(Gear: PGear): boolean; // false если нельзя двигаться
       
   179 var pX, pY: integer;
       
   180 begin
       
   181 Result:= false;
       
   182 repeat
       
   183 pX:= round(Gear.X);
       
   184 pY:= round(Gear.Y);
       
   185 if pY + cHHRadius >= cWaterLine then exit;
       
   186 if (Gear.State and gstFalling) <> 0 then
       
   187    begin
       
   188    Gear.dY:= Gear.dY + cGravity;
       
   189    if Gear.dY > 0.35 then exit;
       
   190    Gear.Y:= Gear.Y + Gear.dY;
       
   191    if HHTestCollisionYwithGear(Gear, 1) then
       
   192       begin
       
   193       Gear.State:= Gear.State and not (gstFalling or gstHHJumping);
       
   194       Gear.dY:= 0
       
   195       end;
       
   196    continue
       
   197    end;
       
   198    {if ((Gear.Message and gm_LJump )<>0) then
       
   199       begin
       
   200       Gear.Message:= 0;
       
   201       if not HHTestCollisionYwithGear(Gear, -1) then
       
   202          if not TestCollisionXwithXYShift(Gear, 0, -2, Sign(Gear.dX)) then Gear.Y:= Gear.Y - 2 else
       
   203          if not TestCollisionXwithXYShift(Gear, 0, -1, Sign(Gear.dX)) then Gear.Y:= Gear.Y - 1;
       
   204       if not (TestCollisionXwithGear(Gear, Sign(Gear.dX))
       
   205          or   HHTestCollisionYwithGear(Gear, -1)) then
       
   206          begin
       
   207          Gear.dY:= -0.15;
       
   208          Gear.dX:= Sign(Gear.dX) * 0.15;
       
   209          Gear.State:= Gear.State or gstFalling or gstHHJumping;
       
   210          exit
       
   211          end;
       
   212       end;}
       
   213    if (Gear.Message and gm_Left  )<>0 then Gear.dX:= -1.0 else
       
   214    if (Gear.Message and gm_Right )<>0 then Gear.dX:=  1.0 else exit;
       
   215    if TestCollisionXwithGear(Gear, Sign(Gear.dX)) then
       
   216       begin
       
   217       if not (TestCollisionXwithXYShift(Gear, 0, -6, Sign(Gear.dX))
       
   218          or HHTestCollisionYwithGear(Gear, -1)) then Gear.Y:= Gear.Y - 1;
       
   219       if not (TestCollisionXwithXYShift(Gear, 0, -5, Sign(Gear.dX))
       
   220          or HHTestCollisionYwithGear(Gear, -1)) then Gear.Y:= Gear.Y - 1;
       
   221       if not (TestCollisionXwithXYShift(Gear, 0, -4, Sign(Gear.dX))
       
   222          or HHTestCollisionYwithGear(Gear, -1)) then Gear.Y:= Gear.Y - 1;
       
   223       if not (TestCollisionXwithXYShift(Gear, 0, -3, Sign(Gear.dX))
       
   224          or HHTestCollisionYwithGear(Gear, -1)) then Gear.Y:= Gear.Y - 1;
       
   225       if not (TestCollisionXwithXYShift(Gear, 0, -2, Sign(Gear.dX))
       
   226          or HHTestCollisionYwithGear(Gear, -1)) then Gear.Y:= Gear.Y - 1;
       
   227       if not (TestCollisionXwithXYShift(Gear, 0, -1, Sign(Gear.dX))
       
   228          or HHTestCollisionYwithGear(Gear, -1)) then Gear.Y:= Gear.Y - 1;
       
   229       end;
       
   230 
       
   231    if not TestCollisionXwithGear(Gear, Sign(Gear.dX)) then Gear.X:= Gear.X + Gear.dX;
       
   232    if not HHTestCollisionYwithGear(Gear, 1) then
       
   233    begin
       
   234    Gear.Y:= Gear.Y + 1;
       
   235    if not HHTestCollisionYwithGear(Gear, 1) then
       
   236    begin
       
   237    Gear.Y:= Gear.Y + 1;
       
   238    if not HHTestCollisionYwithGear(Gear, 1) then
       
   239    begin
       
   240    Gear.Y:= Gear.Y + 1;
       
   241    if not HHTestCollisionYwithGear(Gear, 1) then
       
   242    begin
       
   243    Gear.Y:= Gear.Y + 1;
       
   244    if not HHTestCollisionYwithGear(Gear, 1) then
       
   245    begin
       
   246    Gear.Y:= Gear.Y + 1;
       
   247    if not HHTestCollisionYwithGear(Gear, 1) then
       
   248    begin
       
   249    Gear.Y:= Gear.Y + 1;
       
   250    if not HHTestCollisionYwithGear(Gear, 1) then
       
   251       begin
       
   252       Gear.Y:= Gear.Y - 6;
       
   253       Gear.dY:= 0;
       
   254       Gear.dX:= 0.0000001 * Sign(Gear.dX);
       
   255       Gear.State:= Gear.State or gstFalling
       
   256       end
       
   257    end
       
   258    end
       
   259    end
       
   260    end
       
   261    end
       
   262    end;
       
   263 if (pX <> round(Gear.X))and ((Gear.State and gstFalling) = 0) then
       
   264    begin
       
   265    Result:= true;
       
   266    exit
       
   267    end;
       
   268 until (pX = round(Gear.X)) and (pY = round(Gear.Y)) and ((Gear.State and gstFalling) = 0);
       
   269 end;
       
   270 
       
   271 end.
    88 end.