(*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * http://www.opensource.org/licenses/cddl1.php.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * http://www.opensource.org/licenses/cddl1.php.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying * information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2007 Andreas Schneider
 *)
unit UTiledata;

{$mode objfpc}{$H+}

interface

uses
  Classes, UMulBlock;

const
  tdfBackground = $00000001;
  tdfWeapon = $00000002;
  tdfTransparent = $00000004;
  tdfTranslucent = $00000008;
  tdfWall = $00000010;
  tdfDamaging = $00000020;
  tdfImpassable = $00000040;
  tdfWet = $00000080;
  tdfUnknown1 = $00000100;
  tdfSurface = $00000200;
  tdfBridge = $00000400;
  tdfGeneric = $00000800;
  tdfWindow = $00001000;
  tdfNoShoot = $00002000;
  tdfArticleA = $00004000;
  tdfArticleAn = $00008000;
  tdfInternal = $00010000;
  tdfFoliage = $00020000;
  tdfPartialHue = $00040000;
  tdfUnknown2 = $00080000;
  tdfMap = $00100000;
  tdfContainer = $00200000;
  tdfWearable = $00400000;
  tdfLightSource = $00800000;
  tdfAnimation = $01000000;
  tdfNoDiagonal = $02000000;
  tdfArtUsed = $04000000;
  tdfArmor = $08000000;
  tdfRoof = $10000000;
  tdfDoor = $20000000;
  tdfStairBack = $40000000;
  tdfStairRight = $80000000;

  LandTileDataSize = 26;
  LandTileGroupSize = 4 + 32 * LandTileDataSize;
  StaticTileDataSize = 37;
  StaticTileGroupSize = 4 + 32 * StaticTileDataSize;

type

  { TTiledata }

  TTiledata = class(TMulBlock)
  protected
    FFlags: LongWord;
    FTileName: string;
  public
    property Flags: LongWord read FFlags write FFlags;
    property TileName: string read FTileName write FTileName;
    
    function HasFlag(AFlag: LongWord): Boolean;
  end;
  TLandTiledata = class(TTiledata)
    constructor Create(AData: TStream);
    destructor Destroy; override;
    function Clone: TLandTiledata; override;
    function GetSize: Integer; override;
    procedure Write(AData: TStream); override;
  protected
    FTextureID: Word;
  public
    property TextureID: Word read FTextureID write FTextureID;
  end;
  TStaticTiledata = class(TTiledata)
    constructor Create(AData: TStream);
    destructor Destroy; override;
    function Clone: TStaticTiledata; override;
    function GetSize: Integer; override;
    procedure Write(AData: TStream); override;
  protected
    FWeight: Byte;
    FQuality: Byte;
    FUnknown1: Word;
    FUnknown2: Byte;
    FQuantity: Byte;
    FAnimID: Word;
    FUnknown3: Byte;
    FHue: Byte;
    FUnknown4: Word;
    FHeight: Byte;
  public
    property Weight: Byte read FWeight write FWeight;
    property Quality: Byte read FQuality write FQuality;
    property Unknown1: Word read FUnknown1 write FUnknown1;
    property Unknown2: Byte read FUnknown2 write FUnknown2;
    property Quantity: Byte read FQuantity write FQuantity;
    property AnimID: Word read FAnimID write FAnimID;
    property Unknown3: Byte read FUnknown3 write FUnknown3;
    property Hue: Byte read FHue write FHue;
    property Unknown4: Word read FUnknown4 write FUnknown4;
    property Height: Byte read FHeight write FHeight;
  end;
  TLandTileGroup = class(TMulBlock)
    constructor Create(AData: TStream);
    destructor Destroy; override;
    function Clone: TLandTileGroup; override;
    function GetSize: Integer; override;
    procedure Write(AData: TStream); override;
  protected
    FUnknown: LongInt;
  public
    LandTileData: array[0..31] of TLandTiledata;
    property Unknown: LongInt read FUnknown write FUnknown;
  end;
  TStaticTileGroup = class(TMulBlock)
    constructor Create(AData: TStream);
    destructor Destroy; override;
    function Clone: TStaticTileGroup; override;
    function GetSize: Integer; override;
    procedure Write(AData: TStream); override;
  protected
    FUnknown: LongInt;
  public
    StaticTileData: array[0..31] of TStaticTiledata;
    property Unknown: LongInt read FUnknown write FUnknown;
  end;

function GetTileDataOffset(ABlock: Integer): Integer;

implementation

function GetTileDataOffset(ABlock: Integer): Integer;
var
  group, tile: Integer;
begin
  if ABlock > $3FFF then
  begin
    ABlock := ABlock - $4000;
    group := ABlock div 32;
    tile := ABlock mod 32;

    Result := 512 * LandTileGroupSize + group * StaticTileGroupSize + 4 + tile * StaticTileDataSize;
  end else
  begin
    group := ABlock div 32;
    tile := ABlock mod 32;

    Result := group * LandTileGroupSize + 4 + tile * LandTileDataSize;
  end;
end;

constructor TLandTiledata.Create(AData: TStream);
begin
  SetLength(FTileName, 20);
  if assigned(AData) then
  begin
    AData.Read(FFlags, SizeOf(LongWord));
    AData.Read(FTextureID, SizeOf(Word));
    AData.Read(PChar(FTileName)^, 20);
  end;
end;

destructor TLandTiledata.Destroy;
begin
  SetLength(FTileName, 0);
  inherited;
end;

function TLandTiledata.Clone: TLandTiledata;
begin
  Result := TLandTiledata.Create(nil);
  Result.FFlags := FFlags;
  Result.FTextureID := FTextureID;
  Result.FTileName := FTileName;
end;

procedure TLandTiledata.Write(AData: TStream);
var
  i: Integer;
begin
  if Length(FTileName) < 20 then
    for i := Length(FTileName) to 20 do
      FTileName := FTileName + #0;
  AData.Write(FFlags, SizeOf(LongWord));
  AData.Write(FTextureID, SizeOf(Word));
  AData.Write(PChar(FTileName)^, 20);
end;

function TLandTiledata.GetSize: Integer;
begin
  GetSize := LandTileDataSize;
end;

constructor TStaticTiledata.Create(AData: TStream);
begin
  SetLength(FTileName, 20);
  if assigned(AData) then
  begin
    AData.Read(FFlags, SizeOf(LongWord));
    AData.Read(FWeight, SizeOf(Byte));
    AData.Read(FQuality, SizeOf(Byte));
    AData.Read(FUnknown1, SizeOf(Word));
    AData.Read(FUnknown2, SizeOf(Byte));
    AData.Read(FQuantity, SizeOf(Byte));
    AData.Read(FAnimID, SizeOf(Word));
    AData.Read(FUnknown3, SizeOf(Byte));
    AData.Read(FHue, SizeOf(Byte));
    AData.Read(FUnknown4, SizeOf(Word));
    AData.Read(FHeight, SizeOf(Byte));
    AData.Read(PChar(FTileName)^, 20);
  end;
end;

destructor TStaticTiledata.Destroy;
begin
  SetLength(FTileName, 0);
  inherited;
end;

function TStaticTiledata.Clone: TStaticTiledata;
begin
  Result := TStaticTiledata.Create(nil);
  Result.FFlags := FFlags;
  Result.FWeight := FWeight;
  Result.FQuality := FQuality;
  Result.FUnknown1 := FUnknown1;
  Result.FUnknown2 := FUnknown2;
  Result.FQuantity := FQuantity;
  Result.FAnimID := FAnimID;
  Result.FUnknown3 := FUnknown3;
  Result.FHue := FHue;
  Result.FUnknown4 := FUnknown4;
  Result.FHeight := FHeight;
  Result.FTileName := FTileName;
end;

procedure TStaticTiledata.Write(AData: TStream);
var
  i: Integer;
begin
  if Length(FTileName) < 20 then
    for i := Length(FTileName) to 20 do
      FTileName := FTileName + #0;
  AData.Write(FFlags, SizeOf(LongWord));
  AData.Write(FWeight, SizeOf(Byte));
  AData.Write(FQuality, SizeOf(Byte));
  AData.Write(FUnknown1, SizeOf(Word));
  AData.Write(FUnknown2, SizeOf(Byte));
  AData.Write(FQuantity, SizeOf(Byte));
  AData.Write(FAnimID, SizeOf(Word));
  AData.Write(FUnknown3, SizeOf(Byte));
  AData.Write(FHue, SizeOf(Byte));
  AData.Write(FUnknown4, SizeOf(Word));
  AData.Write(FHeight, SizeOf(Byte));
  AData.Write(PChar(FTileName)^, 20);
end;

function TStaticTiledata.GetSize: Integer;
begin
  GetSize := StaticTileDataSize;
end;

constructor TLandTileGroup.Create(AData: TStream);
var
  i: Integer;
begin
  if assigned(AData) then
  begin
    AData.Read(FUnknown, SizeOf(LongInt));
  end;
  for i := 0 to 31 do
    LandTileData[i] := TLandTiledata.Create(AData);
end;

destructor TLandTileGroup.Destroy;
var
  i: Integer;
begin
  for i := 0 to 31 do
    LandTileData[i].Free;
  inherited;
end;

function TLandTileGroup.Clone: TLandTileGroup;
var
  i: Integer;
begin
  Result := TLandTileGroup.Create(nil);
  Result.FUnknown := FUnknown;
  for i := 0 to 31 do
    Result.LandTileData[i] := LandTileData[i].Clone;
end;

procedure TLandTileGroup.Write(AData: TStream);
var
  i: Integer;
begin
  AData.Write(FUnknown, SizeOf(LongInt));
  for i := 0 to 31 do
    LandTileData[i].Write(AData);
end;

function TLandTileGroup.GetSize: Integer;
begin
  GetSize := LandTileGroupSize;
end;

constructor TStaticTileGroup.Create(AData: TStream);
var
  i: Integer;
begin
  if assigned(AData) then
  begin
    AData.Read(FUnknown, SizeOf(LongInt));
  end;
  for i := 0 to 31 do
    StaticTileData[i] := TStaticTiledata.Create(AData);
end;

destructor TStaticTileGroup.Destroy;
var
  i: Integer;
begin
  for i := 0 to 31 do
    StaticTileData[i].Free;
  inherited;
end;

function TStaticTileGroup.Clone: TStaticTileGroup;
var
  i: Integer;
begin
  Result := TStaticTileGroup.Create(nil);
  Result.FUnknown := FUnknown;
  for i := 0 to 31 do
    Result.StaticTileData[i] := StaticTileData[i].Clone;
end;

procedure TStaticTileGroup.Write(AData: TStream);
var
  i: Integer;
begin
  AData.Write(FUnknown, SizeOf(LongInt));
  for i := 0 to 31 do
    StaticTileData[i].Write(AData);
end;

function TStaticTileGroup.GetSize: Integer;
begin
  GetSize := StaticTileGroupSize;
end;

{ TTiledata }

function TTiledata.HasFlag(AFlag: LongWord): Boolean;
begin
  Result := (FFlags and AFlag) = AFlag;
end;

end.