unit uWorldFile;

interface

uses Classes, Windows, SysUtils, GR32, Dialogs, Graphics, Math, uArt, uItem,
        uTiledata, uAnimdata, StrLib;

type    TWorldFile = class
        private
                SerialCount : Integer;
                ItemList : TList;
        public
                constructor Create;
                destructor Free;
                procedure LoadFromTextfile( Path : String );
                procedure LoadFromWsc( Path : String );
                procedure LoadFromSphere51a( Path : String );
                procedure SaveToTextfile( Path : String );
                procedure SaveToWsc( Path : String );
                procedure SaveToSphere51a( Path : String );
                function AddItem( Id, X, Y, Z, Color : Integer ) : Integer;
                function GetItems( MinX, MaxX, MinY, MaxY : Integer; Liste : TList ) : TList;
                procedure Select( Serial : Integer );
                procedure UnSelect( Serial : Integer );
                procedure Delete( Serial : Integer );
                procedure SetColor( Serial, Color : Integer );
                procedure SetId( Serial, Id : Integer );
                procedure SetPos( Serial, X, Y, Z : Integer );
                procedure Move( Serial, MX, MY, MZ : Integer );
                procedure ClearAll;
                procedure ClearAllNew;
                function GetNewItems: TList;
                function GetAllItems: TList;
        end;

var     WorldFile : TWorldFile;

implementation

constructor TWorldFile.Create;
begin
        SerialCount := $2FFFFFF;
        ItemList := TList.Create;
end;

destructor TWorldFile.Free;
begin
        ItemList.Free;
end;

procedure TWorldFile.LoadFromTextfile( Path : String );
var     I : Integer;
        Liste : TStringList;
        Zeile : TStringList;
        ItemId, X, Y, Z, Color : Integer;
begin
        Liste := TStringList.Create;
        Liste.LoadFromFile( Path );

        if Liste.Count = 0 then begin
                Liste.Free;
                exit;
        end;

        for I := 0 to Liste.Count-1 do begin
                Zeile := TStringList.Create;
                StrLib.Split( Liste.Strings[I], ' ', Zeile );

                ItemID := StrToInt( Zeile.Strings[0] );
                X := StrToInt( Zeile.Strings[1] );
                Y := StrToInt( Zeile.Strings[2] );
                Z := StrToInt( Zeile.Strings[3] );
                Color := StrToInt( Zeile.Strings[4] );

                AddItem( ItemID, X, Y, Z, Color );
                Zeile.Free;
        end;
        Liste.Free;
end;

procedure TWorldFile.LoadFromWsc( Path : String );
var     I : Integer;
        Liste : TStringList;
        Zeile, Temp : String;
        ItemId, X, Y, Z, Color : Integer;
begin
        Liste := TStringList.Create;
        Liste.LoadFromFile( Path );

        if Liste.Count = 0 then begin
                Liste.Free;
                exit;
        end;

        ItemId := -1;
        X := 0;
        Y := 0;
        Z := 0;
        Color := 0;

        for I := 0 to Liste.Count-1 do begin
                Zeile := Liste.Strings[ I ];
                if Pos( 'SECTION WORLDITEM ', Zeile ) <> 0 then begin
                        if ItemId <> -1 then begin
                                AddItem( ItemId, X, Y, Z, Color );
                                ItemId := -1;
                                X := 0;
                                Y := 0;
                                Z := 0;
                                Color := 0;
                        end;
                end
                else if Pos( 'ID ', Zeile ) <> 0 then begin
                        Temp := Copy( Zeile, 4, Length( Zeile )-3 );
                        ItemId := StrToInt( Temp );
                end
                else if Pos( 'X ', Zeile ) <> 0 then begin
                        Temp := Copy( Zeile, 3, Length( Zeile )-2 );
                        X := StrToInt( Temp );
                end
                else if Pos( 'Y ', Zeile ) <> 0 then begin
                        Temp := Copy( Zeile, 3, Length( Zeile )-2 );
                        Y := StrToInt( Temp );
                end
                else if Pos( 'Z ', Zeile ) <> 0 then begin
                        Temp := Copy( Zeile, 3, Length( Zeile )-2 );
                        Z := StrToInt( Temp );
                end
                else if Pos( 'Color ', Zeile ) <> 0 then begin
                        Temp := Copy( Zeile, 7, Length( Zeile )-6 );
                        Color := StrToInt( Temp );
                end;
        end;

        if ItemId <> -1 then begin
                AddItem( ItemId, X, Y, Z, Color );
        end;
        Liste.Free;
end;

procedure TWorldFile.LoadFromSphere51a( Path : String );
var     I : Integer;
        Liste, PosListe : TStringList;
        Zeile, Temp : String;
        ItemId, X, Y, Z, Color : Integer;
begin
        Liste := TStringList.Create;
        Liste.LoadFromFile( Path );

        if Liste.Count = 0 then begin
                Liste.Free;
                exit;
        end;

        ItemId := -1;
        X := 0;
        Y := 0;
        Z := 0;
        Color := 0;

        for I := 0 to Liste.Count-1 do begin
                Zeile := Liste.Strings[ I ];
                if Pos( '[WORLDITEM ', Zeile ) <> 0 then begin
                        if ItemId <> -1 then begin
                                AddItem( ItemId, X, Y, Z, Color );
                                X := 0;
                                Y := 0;
                                Z := 0;
                                Color := 0;
                        end;
                        Temp := '0x' + Copy( Zeile, 13, Length( Zeile )-13 );
                        ItemId := StrToInt( Temp );
                end
                else if Pos( 'ID=', Zeile ) <> 0 then begin
                        Temp := '0x' + Copy( Zeile, 5, Length( Zeile )-4 );
                        ItemId := StrToInt( Temp );
                end
                else if Pos( 'P=', Zeile ) <> 0 then begin
                        Temp := Copy( Zeile, 3, Length( Zeile )-2 );

                        PosListe := TStringList.Create;
                        StrLib.Split( Temp, ',', PosListe );
                        X := StrToInt( PosListe.Strings[0] );
                        Y := StrToInt( PosListe.Strings[1] );
                        Z := StrToInt( PosListe.Strings[2] );
                        PosListe.Free;
                end
                else if Pos( 'Color=', Zeile ) <> 0 then begin
                        Temp := Copy( Zeile, 7, Length( Zeile )-6 );
                        Color := StrToInt( Temp );
                end;
        end;

        if ItemId <> -1 then begin
                AddItem( ItemId, X, Y, Z, Color );
        end;
        Liste.Free;
end;

procedure TWorldFile.SaveToTextfile( Path : String );
var     I : Integer;
        Liste : TStringList;
        Item : PStaticItem;
begin
        if ItemList.Count = 0 then exit;

        Liste := TStringList.Create;

        for I := 0 to ItemList.Count-1 do begin
                Item := PStaticItem( ItemList.Items[I] );
                Liste.Add( Format( '0x%x %d %d %d 0x%x', [Item.Id,Item.X,Item.Y,Item.Z,Item.Color] ) );
                if Item.Typ = Typ_Item_New then
                        PStaticItem( ItemList.Items[I] ).Typ := Typ_Item_WorldFile;
        end;
        Liste.SaveToFile( Path );
        Liste.Free;
end;

procedure TWorldFile.SaveToSphere51a( Path : String );
var     I : Integer;
        Liste : TStringList;
        Item : PStaticItem;
begin
        if ItemList.Count = 0 then exit;

        Liste := TStringList.Create;

        for I := 0 to ItemList.Count-1 do begin
                Item := PStaticItem( ItemList.Items[I] );
                Liste.Add( Format( '[WORLDITEM 0%x]', [Item.Id] ) );
                Liste.Add( Format( 'SERIAL=0%x', [Item.Serial+$FFFFFFF] ) );
                Liste.Add( Format( 'ID=0%x', [Item.Id] ) );
                Liste.Add( Format( 'P=%d,%d,%d', [Item.X,Item.Y,Item.Z] ) );
                Liste.Add( Format( 'Color=0x%x', [Item.Color] ) );
                Liste.Add( '' );
                if Item.Typ = Typ_Item_New then
                        PStaticItem( ItemList.Items[I] ).Typ := Typ_Item_WorldFile;
        end;
        Liste.SaveToFile( Path );
        Liste.Free;
end;

procedure TWorldFile.SaveToWsc( Path : String );
var     I : Integer;
        Liste : TStringList;
        Item : PStaticItem;
begin
        if ItemList.Count = 0 then exit;

        Liste := TStringList.Create;

        for I := 0 to ItemList.Count-1 do begin
                Item := PStaticItem( ItemList.Items[I] );
                Liste.Add( Format( 'SECTION WORLDITEM %d', [I] ) );
                Liste.Add( '{' );
                Liste.Add( Format( 'SERIAL %d', [Item.Serial+$FFFFFFF] ) );
                Liste.Add( Format( 'ID %d', [Item.Id] ) );
                Liste.Add( Format( 'X %d', [Item.X] ) );
                Liste.Add( Format( 'Y %d', [Item.Y] ) );
                Liste.Add( Format( 'Z %d', [Item.Z] ) );
                Liste.Add( Format( 'Color %d', [Item.Color] ) );
                Liste.Add( '}' );
                Liste.Add( '' );
                if Item.Typ = Typ_Item_New then
                        PStaticItem( ItemList.Items[I] ).Typ := Typ_Item_WorldFile;
        end;
        Liste.SaveToFile( Path );
        Liste.Free;
end;

function TWorldFile.AddItem( Id, X, Y, Z, Color : Integer ) : Integer;
var     Item : PStaticItem;
begin
        new( Item );
        Item.ID := Id;
        Item.X := X;
        Item.Y := Y;
        Item.Z := Z;
        Item.Color := Color;
        Item.Deleted := False;
        Item.Selected := False;
        Item.Serial := SerialCount;
        SerialCount := SerialCount+1;
        Item.Hoehe := Art.GetStaticTileHeight( Item.Id );
        Item.Breite := Art.GetStaticTileWidth( Item.Id );
        Item.Typ := Typ_Item_New;

        if (Tiledata.GetStaticFlag( Item.ID, dANIMATION )) and (Animdata.GetCount( Item.ID ) > 0) then
                Item.isAnimated := True
        else
                Item.isAnimated := False;

        ItemList.Add( Item );
        Result := Item.Serial;
end;

function TWorldFile.GetItems( MinX, MaxX, MinY, MaxY : Integer; Liste : TList ) : TList;
var     I : Integer;
        Item, NewItem : PStaticItem;
begin
        Result := Liste;

        if ItemList.Count = 0 then exit;

        MinX := Min( MinX, MaxX );
        MinY := Min( MinY, MaxY );
        MaxX := Max( MinX, MaxX );
        MaxY := Max( MinY, MaxY );

        MinX := Max( MinX, 0 );
        MinY := Max( MinY, 0 );
        MaxX := Min( MaxX, 6143 );
        MaxY := Min( MaxY, 4095 );        

        for I := 0 to ItemList.Count-1 do begin
                Item := PStaticItem( ItemList.Items[I] );
                if (Item.X >= MinX) and (Item.X <= MaxX) and (Item.Y >= MinY) and (Item.Y <= MaxY) and not (Item.Deleted) then begin

                        new( NewItem );
                        NewItem.X := Item.X;
                        NewItem.Y := Item.Y;
                        NewItem.Z := Item.Z;
                        NewItem.ID := Item.ID;
                        NewItem.Serial := Item.Serial;
                        NewItem.Hoehe := Item.Hoehe;
                        NewItem.Breite := Item.Breite;
                        NewItem.Selected := Item.Selected;
                        NewItem.Deleted := Item.Deleted;
                        NewItem.Color := Item.Color;
                        NewItem.isAnimated := Item.isAnimated;
                        NewItem.Typ := Item.Typ;

                        Result.Add( NewItem );
                end;
        end;
end;

procedure TWorldFile.Select( Serial : Integer );
begin
        Serial := Serial - $2FFFFFF;
        if (Serial >= 0) and (Serial < ItemList.Count) then begin
        end;
end;

procedure TWorldFile.UnSelect( Serial : Integer );
begin
        Serial := Serial - $2FFFFFF;
        if (Serial >= 0) and (Serial < ItemList.Count) then begin
        end;
end;

procedure TWorldFile.Delete( Serial : Integer );
begin
        Serial := Serial - $2FFFFFF;
        if (Serial >= 0) and (Serial < ItemList.Count) then begin
                PStaticItem( ItemList.Items[ Serial ] ).Deleted := True;
        end;
end;

procedure TWorldFile.SetColor( Serial, Color : Integer );
begin
        Serial := Serial - $2FFFFFF;
        if (Serial >= 0) and (Serial < ItemList.Count) then begin
                PStaticItem( ItemList.Items[ Serial ] ).Color := Color;
        end;
end;

procedure TWorldFile.SetId( Serial, Id : Integer );
begin
        Serial := Serial - $2FFFFFF;
        if (Serial >= 0) and (Serial < ItemList.Count) then begin
                PStaticItem( ItemList.Items[ Serial ] ).Id := Id;
                PStaticItem( ItemList.Items[ Serial ] ).Hoehe := Art.GetStaticTileHeight( Id );
                PStaticItem( ItemList.Items[ Serial ] ).Breite := Art.GetStaticTileWidth( Id );
                if (Tiledata.GetStaticFlag( Id, dANIMATION )) and (Animdata.GetCount( Id ) > 0) then
                        PStaticItem( ItemList.Items[ Serial ] ).isAnimated := True
                else
                        PStaticItem( ItemList.Items[ Serial ] ).isAnimated := False;
        end;
end;

procedure TWorldFile.SetPos( Serial, X, Y, Z : Integer );
begin
        Serial := Serial - $2FFFFFF;
        if (Serial >= 0) and (Serial < ItemList.Count) then begin
                PStaticItem( ItemList.Items[ Serial ] ).X := X;
                PStaticItem( ItemList.Items[ Serial ] ).Y := Y;
                PStaticItem( ItemList.Items[ Serial ] ).Z := Z;
        end;
end;

procedure TWorldFile.Move( Serial, MX, MY, MZ : Integer );
begin
        Serial := Serial - $2FFFFFF;
        if (Serial >= 0) and (Serial < ItemList.Count) then begin
                PStaticItem( ItemList.Items[ Serial ] ).X := PStaticItem( ItemList.Items[ Serial ] ).X +MX;
                PStaticItem( ItemList.Items[ Serial ] ).Y := PStaticItem( ItemList.Items[ Serial ] ).Y +MY;
                PStaticItem( ItemList.Items[ Serial ] ).Z := PStaticItem( ItemList.Items[ Serial ] ).Z +MZ;
        end;
end;

procedure TWorldFile.ClearAll;
begin
        ItemList.Clear;
        SerialCount := $2FFFFFF;
end;

procedure TWorldFile.ClearAllNew;
var     OldList : TList;
        I : Integer;
        Item, NewItem : PStaticItem;
begin
        OldList := TList.Create;
        OldList.Assign( ItemList );

        ItemList.Clear;
        SerialCount := $2FFFFFF;

        if OldList.Count = 0 then exit;

        for I := 0 to OldList.Count-1 do begin
                Item := PStaticItem( OldList.Items[I] );

                if Item.Typ = Typ_Item_WorldFile then begin
                        new( NewItem );
                        NewItem.X := Item.X;
                        NewItem.Y := Item.Y;
                        NewItem.Z := Item.Z;
                        NewItem.ID := Item.ID;
                        NewItem.Serial := Item.Serial;
                        NewItem.Hoehe := Item.Hoehe;
                        NewItem.Breite := Item.Breite;
                        NewItem.Selected := Item.Selected;
                        NewItem.Deleted := Item.Deleted;
                        NewItem.Color := Item.Color;
                        NewItem.isAnimated := Item.isAnimated;
                        NewItem.Typ := Item.Typ;

                        ItemList.Add( NewItem );
                end;
        end;
        OldList.Free;
end;

function TWorldFile.GetNewItems: TList;
var     I : Integer;
        Item, NewItem : PStaticItem;
begin
        Result := TList.Create;

        if ItemList.Count = 0 then exit;

        for I := 0 to ItemList.Count-1 do begin
                Item := PStaticItem( ItemList.Items[I] );
                if Item.Typ = Typ_Item_New then begin
                        new( NewItem );
                        NewItem.X := Item.X;
                        NewItem.Y := Item.Y;
                        NewItem.Z := Item.Z;
                        NewItem.ID := Item.ID;
                        NewItem.Serial := Item.Serial;
                        NewItem.Hoehe := Item.Hoehe;
                        NewItem.Breite := Item.Breite;
                        NewItem.Selected := Item.Selected;
                        NewItem.Deleted := Item.Deleted;
                        NewItem.Color := Item.Color;
                        NewItem.isAnimated := Item.isAnimated;
                        NewItem.Typ := Item.Typ;

                        Result.Add( NewItem );
                end;
        end;
end;

function TWorldFile.GetAllItems: TList;
var     I : Integer;
        Item, NewItem : PStaticItem;
begin
        Result := TList.Create;

        if ItemList.Count = 0 then exit;

        for I := 0 to ItemList.Count-1 do begin
                Item := PStaticItem( ItemList.Items[I] );

                new( NewItem );
                NewItem.X := Item.X;
                NewItem.Y := Item.Y;
                NewItem.Z := Item.Z;
                NewItem.ID := Item.ID;
                NewItem.Serial := Item.Serial;
                NewItem.Hoehe := Item.Hoehe;
                NewItem.Breite := Item.Breite;
                NewItem.Selected := Item.Selected;
                NewItem.Deleted := Item.Deleted;
                NewItem.Color := Item.Color;
                NewItem.isAnimated := Item.isAnimated;
                NewItem.Typ := Item.Typ;

                Result.Add( NewItem );
        end;
end;

end.
