CentrED/UOLib/UTiledata.pas

429 lines
11 KiB
Plaintext

(*
* 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 2012 Andreas Schneider
*)
unit UTiledata;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, UMulBlock;
const
LandTileDataSize = 26;
LandTileGroupSize = 4 + 32 * LandTileDataSize;
StaticTileDataSize = 37;
StaticTileGroupSize = 4 + 32 * StaticTileDataSize;
type
TTileDataFlag = (tdfBackground, tdfWeapon, tdfTransparent, tdfTranslucent,
tdfWall, tdfDamaging, tdfImpassable, tdfWet, tdfUnknown1,
tdfSurface, tdfBridge, tdfGeneric, tdfWindow, tdfNoShoot,
tdfArticleA, tdfArticleAn, tdfInternal, tdfFoliage,
tdfPartialHue, tdfUnknown2, tdfMap, tdfContainer,
tdfWearable, tdfLightSource, tdfAnimation, tdfNoDiagonal,
tdfArtUsed, tdfArmor, tdfRoof, tdfDoor, tdfStairBack,
tdfStairRight);
TTileDataFlags = set of TTileDataFlag;
TTileDataVersion = (tdvLegacy, tdvHighSeas);
{ TTiledata }
TTiledata = class(TMulBlock)
protected
FVersion: TTileDataVersion;
FFlags: TTileDataFlags;
FNewFlags: LongWord; //HighSeas added new flags
FTileName: string;
procedure ReadFlags(AData: TStream);
procedure WriteFlags(AData: TStream);
procedure PopulateClone(const AClone: TTiledata);
public
property Flags: TTileDataFlags read FFlags write FFlags;
property TileName: string read FTileName write FTileName;
end;
{ TLandTiledata }
TLandTiledata = class(TTiledata)
constructor Create(AData: TStream; AVersion: TTileDataVersion = tdvLegacy);
destructor Destroy; override;
function Clone: TLandTiledata; override;
function GetSize: Integer; override;
procedure Write(AData: TStream); override;
protected
FTextureID: Word;
procedure PopulateClone(const AClone: TLandTiledata);
public
property TextureID: Word read FTextureID write FTextureID;
end;
{ TStaticTiledata }
TStaticTiledata = class(TTiledata)
constructor Create(AData: TStream; AVersion: TTileDataVersion = tdvLegacy);
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;
procedure PopulateClone(const AClone: TStaticTiledata);
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 }
TLandTileGroup = class(TMulBlock)
constructor Create(AData: TStream; AVersion: TTileDataVersion = tdvLegacy);
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 }
TStaticTileGroup = class(TMulBlock)
constructor Create(AData: TStream; AVersion: TTileDataVersion = tdvLegacy);
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;
{ TTiledata }
procedure TTiledata.ReadFlags(AData: TStream);
begin
AData.Read(FFlags, SizeOf(LongWord));
if FVersion >= tdvHighSeas then
AData.Read(FNewFlags, SizeOf(LongWord));
end;
procedure TTiledata.WriteFlags(AData: TStream);
begin
AData.Write(FFlags, SizeOf(LongWord));
if FVersion >= tdvHighSeas then
AData.Write(FNewFlags, SizeOf(LongWord));
end;
procedure TTiledata.PopulateClone(const AClone: TTiledata);
begin
AClone.FVersion := FVersion;
AClone.FFlags := FFlags;
AClone.FNewFlags := FNewFlags;
AClone.FTileName := FTileName;
end;
{ TLandTiledata }
constructor TLandTiledata.Create(AData: TStream;
AVersion: TTileDataVersion = tdvLegacy);
var
legacyFlags: LongWord;
highSeasFlags: QWord;
begin
FVersion := AVersion;
SetLength(FTileName, 20);
if assigned(AData) then
begin
ReadFlags(AData);
AData.Read(FTextureID, SizeOf(Word));
AData.Read(PChar(FTileName)^, 20);
end;
FTileName := Trim(FTileName);
end;
destructor TLandTiledata.Destroy;
begin
SetLength(FTileName, 0);
inherited;
end;
function TLandTiledata.Clone: TLandTiledata;
begin
Result := TLandTiledata.Create(nil);
PopulateClone(Result);
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;
WriteFlags(AData);
AData.Write(FTextureID, SizeOf(Word));
AData.Write(PChar(FTileName)^, 20);
end;
procedure TLandTiledata.PopulateClone(const AClone: TLandTiledata);
begin
inherited PopulateClone(AClone);
AClone.FTextureID := FTextureID;
end;
function TLandTiledata.GetSize: Integer;
begin
GetSize := LandTileDataSize;
end;
{ TStaticTiledata}
constructor TStaticTiledata.Create(AData: TStream;
AVersion: TTileDataVersion = tdvLegacy);
begin
FVersion := AVersion;
SetLength(FTileName, 20);
if AData <> nil then
begin
ReadFlags(AData);
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;
FTileName := Trim(FTileName);
end;
destructor TStaticTiledata.Destroy;
begin
SetLength(FTileName, 0);
inherited;
end;
function TStaticTiledata.Clone: TStaticTiledata;
begin
Result := TStaticTiledata.Create(nil);
PopulateClone(Result);
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;
WriteFlags(AData);
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;
procedure TStaticTiledata.PopulateClone(const AClone: TStaticTiledata);
begin
inherited PopulateClone(AClone);
AClone.FWeight := FWeight;
AClone.FQuality := FQuality;
AClone.FUnknown1 := FUnknown1;
AClone.FUnknown2 := FUnknown2;
AClone.FQuantity := FQuantity;
AClone.FAnimID := FAnimID;
AClone.FUnknown3 := FUnknown3;
AClone.FHue := FHue;
AClone.FUnknown4 := FUnknown4;
AClone.FHeight := FHeight;
end;
function TStaticTiledata.GetSize: Integer;
begin
GetSize := StaticTileDataSize;
end;
{ TLandTileGroup }
constructor TLandTileGroup.Create(AData: TStream;
AVersion: TTileDataVersion = tdvLegacy);
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, AVersion);
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;
{ TStaticTileGroup }
constructor TStaticTileGroup.Create(AData: TStream;
AVersion: TTileDataVersion = tdvLegacy);
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, AVersion);
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;
end.