www.pudn.com > SiegeOfAvalon.rar > AI1.pas


unit AI1; 
{******************************************************************************} 
{                                                                              } 
{               Siege Of Avalon : Open Source Edition                          } 
{               -------------------------------------                          } 
{                                                                              } 
{ Portions created by Digital Tome L.P. Texas USA are                          } 
{ Copyright ©1999-2000 Digital Tome L.P. Texas USA                             } 
{ All Rights Reserved.                                                         } 
{                                                                              } 
{ Portions created by Team SOAOS are                                           } 
{ Copyright (C) 2003 - Team SOAOS.                                             } 
{                                                                              } 
{                                                                              } 
{ Contributor(s)                                                               } 
{ --------------                                                               } 
{ Dominique Louis                             } 
{                                                                              } 
{                                                                              } 
{                                                                              } 
{ You may retrieve the latest version of this file at the SOAOS project page : } 
{   http://www.sourceforge.com/projects/soaos                                  } 
{                                                                              } 
{ The contents of this file maybe used with permission, subject to             } 
{ the GNU Lesser General Public License Version 2.1 (the "License"); you may   } 
{ not use this file except in compliance with the License. You may             } 
{ obtain a copy of the License at                                              } 
{ http://www.opensource.org/licenses/lgpl-license.php                          } 
{                                                                              } 
{ Software distributed under the License is distributed on an                  } 
{ "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or               } 
{ implied. See the License for the specific language governing                 } 
{ rights and limitations under the License.                                    } 
{                                                                              } 
{ Description                                                                  } 
{ -----------                                                                  } 
{                                                                              } 
{                                                                              } 
{                                                                              } 
{                                                                              } 
{                                                                              } 
{                                                                              } 
{                                                                              } 
{ Requires                                                                     } 
{ --------                                                                     } 
{   DirectX Runtime libraris on Win32                                          } 
{   They are available from...                                                 } 
{   http://www.microsoft.com.                                                  } 
{                                                                              } 
{ Programming Notes                                                            } 
{ -----------------                                                            } 
{                                                                              } 
{                                                                              } 
{                                                                              } 
{                                                                              } 
{ Revision History                                                             } 
{ ----------------                                                             } 
{   July    13 2003 - DL : Initial Upload to CVS                               } 
{                                                                              } 
{******************************************************************************} 
 
interface 
 
{$INCLUDE Anigrp30cfg.inc} 
 
uses 
  Classes, 
  SysUtils, 
  Character, 
  Resource, 
  Engine, 
  Anigrp30, 
  LogFile; 
 
type 
  TMeander = class( TAI ) 
  private 
    Walking : Boolean; 
    Delay : Integer; 
    Leash : Integer; 
    CenterX : Integer; 
    CenterY : Integer; 
  protected 
    procedure OnStop; override; 
    procedure OnNoPath; override; 
    procedure WasAttacked( Source : TAniFigure; Damage : Single ); override; 
    function OnCollideFigure( Target : TAniFigure ) : Boolean; override; 
  public 
    procedure Init; override; 
    procedure Execute; override; 
  end; 
 
  TBanditCombat = class( TAI ) 
  private 
    Walking : Boolean; 
    Waiting : Boolean; 
    ReadyToAttack : Boolean; 
    OldTrack : TCharacter; 
    RunAway : Boolean; 
    CollideCount : Integer; 
    TrackX, TrackY : Longint; 
    Delay, PostDelay : Integer; 
  protected 
    procedure OnStop; override; 
    procedure OnNoPath; override; 
    procedure WasAttacked( Source : TAniFigure; Damage : Single ); override; 
    function OnCollideFigure( Target : TAniFigure ) : Boolean; override; 
  public 
    procedure Init; override; 
    procedure Execute; override; 
  end; 
 
  TFollowPath = class( TAI ) 
  private 
    CurrentPath : TGameObject; 
    Walking : boolean; 
  protected 
    procedure OnStop; override; 
    procedure OnNoPath; override; 
  public 
    procedure Init; override; 
    procedure Execute; override; 
  end; 
 
 
function AssignAI1( AIName : string ) : TAI; 
 
implementation 
 
const 
  PI = 3.1415926535; 
  pi2 = 2 * PI; 
 
function AssignAI1( AIName : string ) : TAI; 
var 
  S : string; 
const 
  FailName : string = 'AssignAI1'; 
begin 
  Result := nil; 
 
{$IFDEF DODEBUG} 
  if ( CurrDbgLvl >= DbgLvlSevere ) then 
    Log.LogEntry( FailName ); 
{$ENDIF} 
  try 
 
    S := LowerCase( AIName ); 
    if S = 'meander' then 
      Result := TMeander.Create 
    else if ( S = 'banditcombat' ) or ( S = 'basicfight' ) then 
      Result := TBanditCombat.Create 
    else if ( S = 'followpath' ) then 
      Result := TFollowPath.Create; 
 
  except 
    on E : Exception do 
      Log.log( FailName, E.Message, [ ] ); 
  end; 
end; 
 
{ TMeander } 
 
procedure TMeander.Execute; 
var 
  r : Integer; 
  T : Single; 
  X, Y : Integer; 
const 
  FailName : string = 'TMeander.Execute'; 
begin 
{$IFDEF DODEBUG} 
  if ( CurrDbgLvl >= DbgLvlSevere ) then 
    Log.LogEntry( FailName ); 
{$ENDIF} 
  try 
 
    if not Walking then 
    begin 
      if Delay <= 0 then 
      begin 
        r := random( Leash ); 
        T := pi2 * random( 360 ) / 360; 
        X := Round( r * cos( T ) ) + CenterX; 
        Y := Round( r * sin( T ) / 2 ) + CenterY; 
        Character.WalkTo( X, Y, 4 ); 
        Walking := True; 
      end 
      else 
      begin 
        Dec( Delay ); 
      end; 
    end; 
 
  except 
    on E : Exception do 
      Log.log( FailName, E.Message, [ ] ); 
  end; 
end; 
 
procedure TMeander.Init; 
var 
  S : string; 
const 
  FailName : string = 'TMeander.Init'; 
begin 
{$IFDEF DODEBUG} 
  if ( CurrDbgLvl >= DbgLvlSevere ) then 
    Log.LogEntry( FailName ); 
{$ENDIF} 
  try 
 
    S := Character.Properties[ 'CenterX' ]; 
    if S = '' then 
    begin 
      CenterX := Character.X; 
      Character.Properties[ 'CenterX' ] := IntToStr( CenterX ); 
    end 
    else 
    begin 
      try 
        CenterX := StrToInt( S ); 
      except 
        CenterX := Character.X; 
      end; 
    end; 
 
    S := Character.Properties[ 'CenterY' ]; 
    if S = '' then 
    begin 
      CenterY := Character.Y; 
      Character.Properties[ 'CenterY' ] := IntToStr( CenterY ); 
    end 
    else 
    begin 
      try 
        CenterY := StrToInt( S ); 
      except 
        CenterY := Character.Y; 
      end; 
    end; 
 
    S := Character.Properties[ 'LeashLength' ]; 
    try 
      if S = '' then 
        Leash := 50 
      else 
        Leash := StrToInt( S ); 
    except 
      Leash := 50; 
    end; 
 
  except 
    on E : Exception do 
      Log.log( FailName, E.Message, [ ] ); 
  end; 
end; 
 
function TMeander.OnCollideFigure( Target : TAniFigure ) : Boolean; 
const 
  FailName : string = 'TMeander.OnCollideFigure'; 
begin 
  Result := True; 
 
{$IFDEF DODEBUG} 
  if ( CurrDbgLvl >= DbgLvlSevere ) then 
    Log.LogEntry( FailName ); 
{$ENDIF} 
  try 
 
    Character.Face( Target.X, Target.Y ); //This will appear as though the character 
    Character.Stand; //has stopped to talk to someone or examine 
    Walking := False; //an object. 
    Delay := 400; 
 
  except 
    on E : Exception do 
      Log.log( FailName, E.Message, [ ] ); 
  end; 
end; 
 
procedure TMeander.OnNoPath; 
const 
  FailName : string = 'TMeander.OnNoPath'; 
begin 
{$IFDEF DODEBUG} 
  if ( CurrDbgLvl >= DbgLvlSevere ) then 
    Log.LogEntry( FailName ); 
{$ENDIF} 
  try 
 
    Walking := False; 
    Delay := 100; 
 
  except 
    on E : Exception do 
      Log.log( FailName, E.Message, [ ] ); 
  end; 
end; 
 
procedure TMeander.OnStop; 
const 
  FailName : string = 'TMeander.OnStop'; 
begin 
{$IFDEF DODEBUG} 
  if ( CurrDbgLvl >= DbgLvlSevere ) then 
    Log.LogEntry( FailName ); 
{$ENDIF} 
  try 
 
    Walking := False; 
    Delay := 100; 
 
  except 
    on E : Exception do 
      Log.log( FailName, E.Message, [ ] ); 
  end; 
end; 
 
procedure TMeander.WasAttacked( Source : TAniFigure; Damage : Single ); 
var 
  x : longint; 
  y : longint; 
const 
  FailName : string = 'TMeander.WasAttacked'; 
begin 
{$IFDEF DODEBUG} 
  if ( CurrDbgLvl >= DbgLvlSevere ) then 
    Log.LogEntry( FailName ); 
{$ENDIF} 
 
  try 
    if Source is TCharacter then 
      Character.Face( TCharacter( Source ).x, TCharacter( Source ).y ); 
 
    if Source is TCharacter then 
    begin 
      if not ( Character.IsAlly( TCharacter( Source ) ) ) then 
      begin 
        Character.Track := TCharacter( Source ); 
        if TCharacter( Source ).PartyMember then 
          Player.MakeEnemy( Character.Alliance ); 
        TCharacter( Source ).MakeEnemy( Character.Alliance ); 
        Character.AIMode := aiCombat; 
      end; 
    end 
    else 
    begin 
      X := random( 100 ) + 50; 
      Y := random( 100 ) + 50; 
      Walking := True; 
      Character.WalkTo( X, Y, 16 ); 
    end 
  except 
    on E : Exception do 
      Log.log( 'Error Meander WasAttacked: ' + E.Message ); 
  end; 
 
  inherited; 
end; 
 
{ TBanditCombat } 
 
procedure TBanditCombat.Execute; 
var 
  List : TStringList; 
const 
  FailName : string = 'TBanditCombat.Execute'; 
begin 
{$IFDEF DODEBUG} 
  if ( CurrDbgLvl >= DbgLvlSevere ) then 
    Log.LogEntry( FailName ); 
{$ENDIF} 
  try 
 
    if Delay > 0 then 
    begin 
      Dec( Delay ); 
      Exit; 
    end; 
 
    inherited; 
 
    if RunAway then 
    begin 
      Character.WalkTo( Character.X + random( 500 ) - 250, Character.Y + random( 250 ) - 125, 16 ); 
      CollideCount := 0; 
      Walking := True; 
      OldTrack := Character.Track; 
      Character.Track := nil; 
      ReadyToAttack := False; 
      RunAway := False; 
      PostDelay := random( 70 ); 
    end 
    else if Waiting then 
    begin 
      Waiting := False; 
      Character.WalkTo( Character.X + random( 80 ) - 40, Character.Y + random( 40 ) - 20, 4 ); 
      CollideCount := 0; 
      Walking := True; 
      PostDelay := random( 10 ) + 10; 
    end 
    else if ReadyToAttack then 
    begin 
      Character.Attack( Character.Track ); 
      ReadyToAttack := False; 
      Walking := False; 
    end 
    else if Walking then 
    begin 
      if Assigned( Character.Track ) then 
      begin 
        if Character.Track.Dead then 
        begin 
          Character.Track := nil; 
          Walking := False; 
        end 
        else 
        begin 
          if ( FrameCount mod 90 ) = 0 then 
          begin 
            if Character.InRange( Character.Track ) then 
            begin 
              ReadyToAttack := True; 
              PostDelay := 0; 
            end 
            else 
            begin 
              Character.Stand; 
              Delay := random( 30 ) + 30; 
              if Character.Track.Strength > Character.Strength * 1.5 then 
                Inc( Delay, 30 ); 
            end; 
          end 
          else if ( Character.Track.X <> TrackX ) or ( Character.Track.Y <> TrackY ) then 
          begin 
            if ( FrameCount mod 25 ) = 0 then 
            begin 
              if Character.InRange( Character.Track ) then 
              begin 
                ReadyToAttack := True; 
                PostDelay := 0; 
              end 
              else 
              begin 
                Character.Stand; 
                Delay := random( 10 ) + 10; 
              end; 
            end; 
          end; 
        end; 
      end; 
    end 
    else 
    begin 
      if PostDelay > 0 then 
      begin 
        Delay := PostDelay; 
        PostDelay := 0; 
      end 
      else 
      begin 
        if Assigned( Character.Track ) then 
        begin 
          if TCharacter( Character.Track ).Dead then 
            Character.Track := nil; 
        end; 
        if not Assigned( Character.Track ) then 
        begin 
          if ( FrameCount mod 40 ) = 0 then 
          begin 
            List := GetPerceptibleEnemies( Character, 1 ); 
            try 
              if Assigned( List ) then 
              begin 
                if List.Count = 1 then 
                  Character.Track := TCharacter( List.Objects[ 0 ] ) 
                else 
                  Character.Track := TCharacter( List.Objects[ random( List.Count ) ] ); 
              end 
              else 
              begin 
                if Assigned( OldTrack ) then 
                begin 
                  if not ( OldTrack ).Dead then 
                  begin 
                    Character.Track := OldTrack; 
                    OldTrack := nil; 
                  end; 
                end 
                else 
                begin 
                  if ( FrameCount mod 120 ) = 0 then 
                  begin 
                    Character.WalkTo( Character.X + random( 160 ) - 80, Character.Y + random( 80 ) - 40, 4 ); 
                    CollideCount := 0; 
                    Walking := True; 
                    PostDelay := random( 120 ); 
                  end; 
                end; 
              end; 
            finally 
              List.free; 
            end; 
          end; 
        end; 
        if Assigned( Character.Track ) then 
        begin 
          if Character.InRange( Character.Track ) then 
          begin 
            Character.Attack( Character.Track ); 
          end 
          else 
          begin 
            Character.WalkTo( Character.Track.X, Character.Track.Y, 64 ); 
            CollideCount := 0; 
            TrackX := Character.Track.X; 
            TrackY := Character.Track.Y; 
            Walking := True; 
          end; 
        end; 
      end; 
    end; 
 
  except 
    on E : Exception do 
      Log.log( FailName, E.Message, [ ] ); 
  end; 
end; 
 
procedure TBanditCombat.Init; 
const 
  FailName : string = 'TBanditCombat.Init'; 
begin 
{$IFDEF DODEBUG} 
  if ( CurrDbgLvl >= DbgLvlSevere ) then 
    Log.LogEntry( FailName ); 
{$ENDIF} 
  try 
 
    Delay := random( 60 ); 
 
  except 
    on E : Exception do 
      Log.log( FailName, E.Message, [ ] ); 
  end; 
end; 
 
function TBanditCombat.OnCollideFigure( Target : TAniFigure ) : Boolean; 
const 
  FailName : string = 'TBanditCombat.OnCollideFigure'; 
begin 
  Result := False; 
 
{$IFDEF DODEBUG} 
  if ( CurrDbgLvl >= DbgLvlSevere ) then 
    Log.LogEntry( FailName ); 
{$ENDIF} 
  try 
 
    PostDelay := 0; 
    if Target = Character.Track then 
    begin 
      ReadyToAttack := True; 
      Result := True; 
    end 
    else 
    begin 
      if Target is TCharacter then 
      begin 
        if Character.IsEnemy( TCharacter( Target ) ) then 
        begin 
          Character.Track := TCharacter( Target ); 
          ReadyToAttack := True; 
          Result := True; 
          Exit; 
        end; 
      end; 
      if Assigned( Character.Track ) and Character.InRange( Character.Track ) then 
      begin 
        ReadyToAttack := True; 
        Result := True; 
      end 
      else 
      begin 
        Inc( CollideCount ); 
        if ( CollideCount > 1 ) then 
        begin 
          Character.Stand; 
          Delay := Random( 20 ) + 20; 
          Waiting := True; 
          Result := True; 
        // Log.Log('Stop and Wait'); jrs 
        end; 
      end; 
    end; 
 
  except 
    on E : Exception do 
      Log.log( FailName, E.Message, [ ] ); 
  end; 
end; 
 
procedure TBanditCombat.OnNoPath; 
const 
  FailName : string = 'TBanditCombat.OnNoPath'; 
begin 
{$IFDEF DODEBUG} 
  if ( CurrDbgLvl >= DbgLvlSevere ) then 
    Log.LogEntry( FailName ); 
{$ENDIF} 
  try 
 
    Walking := False; 
 
  except 
    on E : Exception do 
      Log.log( FailName, E.Message, [ ] ); 
  end; 
end; 
 
procedure TBanditCombat.OnStop; 
const 
  FailName : string = 'TBanditCombat.OnStop'; 
begin 
{$IFDEF DODEBUG} 
  if ( CurrDbgLvl >= DbgLvlSevere ) then 
    Log.LogEntry( FailName ); 
{$ENDIF} 
  try 
 
    Walking := False; 
 
  except 
    on E : Exception do 
      Log.log( FailName, E.Message, [ ] ); 
  end; 
end; 
 
procedure TBanditCombat.WasAttacked( Source : TAniFigure; Damage : Single ); 
const 
  FailName : string = 'TBanditCombat.WasAttacked'; 
begin 
{$IFDEF DODEBUG} 
  if ( CurrDbgLvl >= DbgLvlSevere ) then 
    Log.LogEntry( FailName ); 
{$ENDIF} 
  try 
 
    if Source is TCharacter then 
    begin 
      if Character.Wounds > ( Character.HitPoints / 2 ) then 
      begin 
        RunAway := True; 
      end 
      else 
      begin 
        Character.Track := TCharacter( Source ); 
      end; 
    end; 
    inherited; 
 
  except 
    on E : Exception do 
      Log.log( FailName, E.Message, [ ] ); 
  end; 
end; 
 
{ TFollowPath } 
 
procedure TFollowPath.Execute; 
const 
  FailName : string = 'TFollowPath.Execute'; 
begin 
{$IFDEF DODEBUG} 
  if ( CurrDbgLvl >= DbgLvlSevere ) then 
    Log.LogEntry( FailName ); 
{$ENDIF} 
  try 
 
    if not Walking and assigned( CurrentPath ) then 
    begin 
      Character.WalkTo( CurrentPath.X, CurrentPath.Y, 4 ); 
      Walking := true; 
    end; 
 
  except 
    on E : Exception do 
      Log.log( FailName, E.Message, [ ] ); 
  end; 
end; 
 
procedure TFollowPath.Init; 
var 
  S : string; 
const 
  FailName : string = 'TFollowPath.Init'; 
begin 
{$IFDEF DODEBUG} 
  if ( CurrDbgLvl >= DbgLvlSevere ) then 
    Log.LogEntry( FailName ); 
{$ENDIF} 
  try 
 
    S := Character.Properties[ 'PathCorner' ]; 
    CurrentPath := GetGUID( S ); 
    if not ( CurrentPath is TPathCorner ) then 
      CurrentPath := nil; 
 
  except 
    on E : Exception do 
      Log.log( FailName, E.Message, [ ] ); 
  end; 
end; 
 
procedure TFollowPath.OnNoPath; 
const 
  FailName : string = 'TFollowPath.OnNoPath'; 
begin 
{$IFDEF DODEBUG} 
  if ( CurrDbgLvl >= DbgLvlSevere ) then 
    Log.LogEntry( FailName ); 
{$ENDIF} 
  try 
 
    Walking := false; 
    if TPathCorner( CurrentPath ).NextDestination = '' then 
      CurrentPath := nil 
    else 
    begin 
      CurrentPath := GetGUID( TPathCorner( CurrentPath ).NextDestination ); 
      if not ( CurrentPath is TPathCorner ) then 
        CurrentPath := nil; 
    end; 
 
  except 
    on E : Exception do 
      Log.log( FailName, E.Message, [ ] ); 
  end; 
end; 
 
procedure TFollowPath.OnStop; 
const 
  FailName : string = 'TFollowPath.OnStop'; 
begin 
{$IFDEF DODEBUG} 
  if ( CurrDbgLvl >= DbgLvlSevere ) then 
    Log.LogEntry( FailName ); 
{$ENDIF} 
  try 
 
    Walking := false; 
    if TPathCorner( CurrentPath ).NextDestination = '' then 
      CurrentPath := nil 
    else 
    begin 
      CurrentPath := GetGUID( TPathCorner( CurrentPath ).NextDestination ); 
      if not ( CurrentPath is TPathCorner ) then 
        CurrentPath := nil; 
    end; 
 
  except 
    on E : Exception do 
      Log.log( FailName, E.Message, [ ] ); 
  end; 
end; 
 
end.