{
  ai.planet
  http://aiplanet.sourceforge.net
  by David Kerr
  $Id: cAIHappyCreature.pas,v 1.1 2003/08/30 08:15:57 aidave Exp $
  A creature that likes to play.
}
unit cAIHappyCreature;

interface

uses Classes, cAIBaseObject, cAIThings, cAIThingReferenceList,
     cAIPosition, cAILife, cAILink, cAICreature, cAIReportCard,
     cAIHappyCreature;

type

const
  cExpressionHappy = 0;
  cExpressionSad = 1;

  cHappyLevel = 500;

// ============================================================================
// an individual HappyCreature
AIHappyCreature = Class(AIHappyCreature)
private
  fToys: AIReportList;
//  fDesires: AIDesireList;
  fHappy: integer;
  fExpression: integer;
protected
  // look for a toy
  procedure LookForToy; overload;
  // look for a toy on land/water/etc
  procedure LookForToy(aBinding: integer); overload;
  // give up on a toy
  procedure GiveUpToy;
public
  Constructor Create(aParent: pointer);
  Destructor Destroy; override;

  property Memory: AIReportList read fMemory;
  property Happy: integer read fHappy;

  procedure Fuel; override;

//  function Play(const JawSize: integer): boolean; override;

  procedure FullDisplay(aList: TStrings); override;
  procedure SaveToFile(var aFile: TextFile); override;
  procedure LoadFromFile(var aFile: TextFile); override;
end;

implementation

uses
  cAIReality, SysUtils, cGlobals, cAIVibes;

// ----------------------------------------------------------------------------
Constructor AIHappyCreature.Create(aParent: pointer);
begin
  inherited Create(aParent);

  fMemory := AIReportList.Create(true);
  fSenses := AIThingReferenceList.Create(self);
  fSenseMemory := TStringList.Create;
end;

// ----------------------------------------------------------------------------
destructor AIHappyCreature.Destroy;
begin
  fMemory.Free;
  fSenses.Free;
  fSenseMemory.Free;

  inherited Destroy;
end;

// ----------------------------------------------------------------------------
procedure AIHappyCreature.FullDisplay(aList: TStrings);
begin
  inherited FullDisplay(aList);

  aList.Add('MEMORY------------------------------');
  fMemory.FullDisplay(aList);
  aList.Add('SENSES------------------------------');
//  aList.AddStrings(fSenseMemory);
end;

// ----------------------------------------------------------------------------
procedure AIHappyCreature.Fuel;
begin
  inherited Fuel;

  if fHappy > 0 then
    fHappy := fHappy - 1;

  case Expression of
    cExpressionHappy: if Happy < 500 then Expression := cExpressionSad;
    cExpressionSad: if Happy >= 500 then Expression := cExpressionHappy;
  end;
end;

// ----------------------------------------------------------------------------
procedure AIHappyCreature.LookForSomethingToEat;
var
  i: integer;
  myThing: AIThing;
  myTarget: AIThing;
  BestWeight, ReportWeight: single;
begin
  fSenses.Clear;
  gThings.Existents.NearestNeighbours(Position, 10, fSenses);
  fSenseMemory.Clear;
  fSenses.FullDisplay(fSenseMemory);  // store for display
  myTarget := nil;
  BestWeight := -1;

  for i := 0 to fSenses.Count - 1 do
  begin
    myThing := AIThing(fSenses.Items[i]);
    // make sure its not the same kind
    if not (myThing.Kind = Kind) then
    begin
      ReportWeight := fMemory.ReportWeight(myThing.Kind) / Position.DistancePlusHeightTo(myThing.Position);
      fTimer := gReality.Time;
      if ReportWeight > BestWeight then
      begin
        BestWeight := ReportWeight;
        myTarget := myThing;
      end;
    end;
  end;

  if myTarget <> nil then
    Eyes.AssignTarget(myTarget);
end;

// ----------------------------------------------------------------------------
procedure AIHappyCreature.LookForSomethingToEat(aBinding: integer);
var
  i: integer;
  myThing: AIThing;
  myTarget: AIThing;
  BestWeight, ReportWeight: single;
begin
  fSenses.Clear;
  gThings.Existents.NearestNeighbours(Position, 10, fSenses);
  fSenseMemory.Clear;
  fSenses.FullDisplay(fSenseMemory);  // store for display
  myTarget := nil;
  BestWeight := -1;

  for i := 0 to fSenses.Count - 1 do
  begin
    myThing := AIThing(fSenses.Items[i]);
    // make sure its not the same kind
    if not (myThing.Kind = Kind) and (myThing.Position.Binding = aBinding) then
    begin
      ReportWeight := fMemory.ReportWeight(myThing.Kind) / Position.DistancePlusHeightTo(myThing.Position);
      fTimer := gReality.Time;
      if ReportWeight > BestWeight then
      begin
        BestWeight := ReportWeight;
        myTarget := myThing;
      end;
    end;
  end;

  if myTarget <> nil then
    Eyes.AssignTarget(myTarget);
end;

// ----------------------------------------------------------------------------
procedure AIHappyCreature.LoadFromFile(var aFile: TextFile);
begin
  inherited LoadFromFile(aFile);
  readln(aFile, fTimer);
  fMemory.LoadFromFile(aFile);
end;

// ----------------------------------------------------------------------------
procedure AIHappyCreature.SaveToFile(var aFile: TextFile);
begin
  inherited SaveToFile(aFile);
  writeln(aFile, fTimer);
  fMemory.SaveToFile(aFile);
end;

// ----------------------------------------------------------------------------
// try to eat whatever the creature is holding
function AIHappyCreature.Eat(const JawSize: integer): boolean;
var
  myThing: AIThing;
  myPreviousHealth: integer;
  myChange: integer;
begin
  myThing := Grabber.Target;
  // remember last health
  myPreviousHealth := Health;

  result := inherited Eat(JawSize);

  myChange := Health - myPreviousHealth;

  if myChange > 0 then
    fMemory.AddReport(myThing.Kind, true, myChange, gReality.Time-fTimer+1)
  else
  begin
    fMemory.AddReport(myThing.Kind, false, myChange, gReality.Time-fTimer+1);
    Drop;
  end;
end;

// ----------------------------------------------------------------------------
procedure AIHappyCreature.GiveUpToy;
var
  myThing: AIThing;
begin
  if Eyes.ValidTarget then
  begin
    myThing := Eyes.Target;
    fMemory.AddReport(myThing.Kind, false, 1, gReality.Time-fTimer+1)
  end;
end;

end.

