unit CustomObject;

interface

uses
  Winapi.Windows, System.SysUtils, System.Variants, System.Classes, System.Generics.Collections, IniFiles,
  Vec2f, GameOverlay, Units.Custom;

type
  TCustomObject = class;

  TObjectType = (
    otNone = 0,
    otSrartPoint = 1,
    otButton = 2,
    otSwitch = 3,
    otDoorClose = 4,
    otDoorOpen = 5,
    otSpaceSuit = 6,
    otTimer = 7,
    otNot = 8,
    otConsole = 9,
    otTrap = 10,
    otLight = 11,
    otActionRegion = 12,
    otIPADConsole = 13,
    otMonster = 14,
    otCapacitor = 15,
    otOr = 16,
    otDamageRegion = 17
  );

  TFieldType = (
    ftNone = 0,
    ftStone = 1,
    ftWall = 2,
    ftTree = 3,
    ftFloor = 4,
    ftGlass = 5
  );

  PField = ^TField;
  TField = record
    FieldType: TFieldType;
    Obj: TCustomObject;
    Position: TVec2i;
    Angle: Single;
    Frame: Integer;
    Damage: Integer;
  end;

  TCustomObject = class
  private
    FID: Integer;
    FLevel: Integer;
    FField: PField;
    FPosition: TVec2f;
    FTalks: array of TSpeech;
    FTalkCount: Integer;
  protected
    FChildList: TList<TCustomObject>;
    FParentList: TList<TCustomObject>;
    FParentAction: Boolean;
    FTalkAction: Boolean;
    FAction: Boolean;
    FHero: TCustomUnit;
    procedure UpdateParentAction; virtual;
    function IsActive: Boolean; virtual;
  public
    class var ObjectList: TList<TCustomObject>;
    class function ObjByID(const AID: Integer): TCustomObject;
    constructor Create(AField: PField; AID: Integer = 0);
    destructor Destroy; override;
    procedure ParentAdd(AObj: TCustomObject);
    procedure ChildAdd(AObj: TCustomObject);
    procedure Learning(AObj: TCustomObject);
    procedure SetLevel(ALevel: Integer);
    property Field: PField read FField write FField;
  published
    procedure SetActive(AAction: Boolean); virtual;
    procedure Load(Aini: TIniFile); virtual;
    procedure Process(const Delta: Double); virtual;
    procedure Draw; virtual;
    procedure DrawLight; virtual;
    procedure SetHero(AHero: TCustomUnit); virtual;
    procedure TalkAction;

    property ID: Integer read FID write FID;
    property Position: TVec2f read FPosition write FPosition;
    property Action: Boolean read FAction;
    property ParentAction: Boolean read FParentAction;
    property Level: Integer read FLevel write FLevel;

  end;

implementation

uses
  Resources;

constructor TCustomObject.Create(AField: PField; AID: Integer = 0);
begin
  FLevel := -1;
  FID := AID;
  FTalkAction := False;
  FField := AField;
  FParentAction := False;
  FAction := False;
  FPosition := TVec2f.Create(TGlobals.GameModes.Level.LevelMap.FieldSize, TGlobals.GameModes.Level.LevelMap.FieldSize);
  FPosition := FPosition * FField.Position + FPosition / 2;
  FParentList := TList<TCustomObject>.Create;
  FChildList := TList<TCustomObject>.Create;
  ObjectList.Add(Self);
end;

procedure TCustomObject.SetHero(AHero: TCustomUnit);
begin
  FHero := AHero;
end;

destructor TCustomObject.Destroy;
var
  i: Integer;
begin
  for i := 0 to FParentList.Count - 1 do
    FParentList[i].Learning(Self);
  FParentList.Free;

  for i := 0 to FChildList.Count - 1 do
    FChildList[i].Learning(Self);
  FChildList.Free;
  ObjectList.Remove(Self);
  inherited;
end;

procedure TCustomObject.Load(Aini: TIniFile);
var
  Strings: TStringList;
  i: Integer;
  Str: String;
  Obj: TCustomObject;
begin
  Strings := TStringList.Create;
  Str := 'Join_' + IntToStr(ID);
  Aini.ReadSection('Join_' + IntToStr(ID), Strings);
  if Strings.Count = 0 then
    FLevel := 0;
  for i := 0 to Strings.Count - 1 do
  begin
    Obj := ObjByID(Aini.ReadInteger(Str, Strings[i], 0));
    if Assigned(Obj) then
    begin
      ParentAdd(Obj);
      Obj.ChildAdd(Self);
    end;
  end;
  Strings.Clear;
  Str := 'Talks_' + IntToStr(ID);
  Aini.ReadSection(Str, Strings);
  FTalkCount := Strings.Count;
  SetLength(FTalks, FTalkCount);
  for i := 0 to FTalkCount - 1 do
  begin
    FTalks[i].Text := Aini.ReadString(Str, Strings[i], '');
    FTalks[i].CharID := 1;
    FTalks[i].Language := lEarth;
  end;

  Strings.Free;
  SetActive(False);
end;

procedure TCustomObject.Learning(AObj: TCustomObject);
begin
  FParentList.Remove(AObj);
  FChildList.Remove(AObj);
end;

procedure TCustomObject.ParentAdd(AObj: TCustomObject);
begin
  FParentList.Add(AObj);
end;

procedure TCustomObject.ChildAdd(AObj: TCustomObject);
begin
  FChildList.Add(AObj);
end;

class function TCustomObject.ObjByID(const AID: Integer): TCustomObject;
var
  i: Integer;
begin
  if AID = 0 then
    Exit(nil);
  for i := 0 to ObjectList.Count - 1 do
    if ObjectList[i].ID = AID then
      Exit(ObjectList[i]);
  Result := nil;
end;

procedure TCustomObject.SetLevel(ALevel: Integer);
var
  i: Integer;
begin
  if FLevel < ALevel then
  begin
    FLevel := ALevel;
    for i := 0 to FChildList.Count - 1 do
      FChildList[i].SetLevel(FLevel + 1);
  end;
end;

procedure TCustomObject.UpdateParentAction;
var
  i: Integer;
  Ac: Boolean;
begin
  FParentAction := True;
  for i := 0 to FParentList.Count - 1 do
    if not FParentList[i].Action then
    begin
      FParentAction := False;
      Break;
    end;
end;

procedure TCustomObject.Process(const Delta: Double);
var
  Ac: Boolean;
begin
  UpdateParentAction;
  Ac := ParentAction;
  if Ac then
    Ac := IsActive;

  if FAction <> Ac then
    SetActive(Ac);
end;

procedure TCustomObject.TalkAction;
var
  i: Integer;
begin
  if not FTalkAction then
  begin
    for i := 0 to FTalkCount - 1 do
      TGameOverlay.AddDialog(FTalks[i]);
    FTalkAction := True;
  end;
end;

procedure TCustomObject.SetActive(AAction: Boolean);
begin
  FAction := AAction;
  if FAction then
    TalkAction;
end;

function TCustomObject.IsActive: Boolean;
begin
  Result := True;
end;

procedure TCustomObject.Draw;
begin

end;

procedure TCustomObject.DrawLight;
begin

end;

initialization
  TCustomObject.ObjectList := TList<TCustomObject>.Create;

finalization
  if Assigned(TCustomObject.ObjectList) then
    TCustomObject.ObjectList.Free;

end.
