unit uSEditorForm;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, dglOpenGL, uTextures, glBitmap, uArt, uStatic, ComCtrls, uItem, uMap,
  uTiledata, Menus, uConfig, Math, uInfoForm, GR32, uHues, uAnimdata, uItems,
  uWorldFile, uStaticDiff, rmBrowseFor, uStaticDiffForm;

const   LClick_Info_Static = 1;
        LClick_Delete_Static = 2;
        LClick_Add_Static = 3;
        LClick_Color_Static = 4;
        LClick_ID_Static = 5;
        LClick_Tile_Static = 6;

        LClick_Move_Static_OL = 7;
        LClick_Move_Static_O = 8;
        LClick_Move_Static_OR = 9;
        LClick_Move_Static_R = 10;
        LClick_Move_Static_UR = 11;
        LClick_Move_Static_U = 12;
        LClick_Move_Static_UL = 13;
        LClick_Move_Static_L = 14;
        LClick_Move_Static_UP = 15;
        LClick_Move_Static_DOWN = 16;

        LClick_Nuke_Static = 17;
        LClick_GetId_Static = 18;
        LClick_GetColor_Static = 19;

        LClick_GetId_Map = 20;
        LClick_SetId_Map = 21;
        LClick_MoveUp_Map = 22;
        LClick_MoveDown_Map = 23;
        LClick_SetZ_Map = 24;
        LClick_SetRandomZ_Map = 25;             
type
  TSEditorForm = class(TForm)
    MainMenu1: TMainMenu;
    Options1: TMenuItem;
    Solution1: TMenuItem;
    N640x4801: TMenuItem;
    N800x6001: TMenuItem;
    N1024x7681: TMenuItem;
    View1: TMenuItem;
    ShowStatictool1: TMenuItem;
    mMap: TMenuItem;
    StatusBar: TStatusBar;
    Save1: TMenuItem;
    PatchMap1: TMenuItem;
    PatchStatics1: TMenuItem;
    ShowMaptool1: TMenuItem;
    ShowMap2D: TMenuItem;
    ClearStatics1: TMenuItem;
    ChooseZLevel: TMenuItem;
    ShowWeb: TMenuItem;
    Items1: TMenuItem;
    StaticVisible: TMenuItem;
    WorldfileVisible: TMenuItem;
    ools1: TMenuItem;
    Map1: TMenuItem;
    Worldfile1: TMenuItem;
    LoadWorldfile1: TMenuItem;
    SaveWorldfile1: TMenuItem;
    ClearWorldfile1: TMenuItem;
    PatchStaticsallnewitemsincluded1: TMenuItem;
    PatchStaticsallnewitemsandthecompleteworldfileincluded1: TMenuItem;
    PatchStatics2: TMenuItem;
    LoadWorldfilefromSphere51a1: TMenuItem;
    LoadWorldfilefromWsc1: TMenuItem;
    SaveWorldfiletoWsc1: TMenuItem;
    SaveWorldfiletoSphere51a1: TMenuItem;
    StaticDiffsVisible: TMenuItem;
    LoadStaticDiffs1: TMenuItem;
    DIffs1: TMenuItem;
    LoadStaticDiffs2: TMenuItem;
    ShowStaticDiffOverview1: TMenuItem;
    SaveStaticDiffschangesonly1: TMenuItem;
    SaveStaticDiffsnewitemsincluded1: TMenuItem;
    SaveStaticDiffsnewitemsandcompleteworldfileincluded1: TMenuItem;
    SetCustomCursor1: TMenuItem;
        procedure FormCreate(Sender: TObject);
        procedure FormDestroy(Sender: TObject);
        procedure ApplicationEventsIdle(Sender: TObject; var Done: Boolean);
        procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    procedure FormKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure N640x4801Click(Sender: TObject);
    procedure N800x6001Click(Sender: TObject);
    procedure N1024x7681Click(Sender: TObject);
    procedure FormHide(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure ShowStatictool1Click(Sender: TObject);
    procedure FormMouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure mMapClick(Sender: TObject);
    procedure PatchMap1Click(Sender: TObject);
    procedure PatchStatics1Click(Sender: TObject);
    procedure ShowMaptool1Click(Sender: TObject);
    procedure ShowMap2DClick(Sender: TObject);
    procedure ClearStatics1Click(Sender: TObject);
    procedure ChooseZLevelClick(Sender: TObject);
    procedure ShowWebClick(Sender: TObject);
    procedure StaticVisibleClick(Sender: TObject);
    procedure WorldfileVisibleClick(Sender: TObject);
    procedure SaveWorldfile1Click(Sender: TObject);
    procedure LoadWorldfile1Click(Sender: TObject);
    procedure ClearWorldfile1Click(Sender: TObject);
    procedure PatchStaticsallnewitemsincluded1Click(Sender: TObject);
    procedure PatchStaticsallnewitemsandthecompleteworldfileincluded1Click(
      Sender: TObject);
    procedure SaveWorldfiletoSphere51a1Click(Sender: TObject);
    procedure SaveWorldfiletoWsc1Click(Sender: TObject);
    procedure StaticDiffsVisibleClick(Sender: TObject);
    procedure LoadStaticDiffs2Click(Sender: TObject);
    procedure ShowStaticDiffOverview1Click(Sender: TObject);
    procedure SaveStaticDiffschangesonly1Click(Sender: TObject);
    procedure SaveStaticDiffsnewitemsincluded1Click(Sender: TObject);
    procedure SaveStaticDiffsnewitemsandcompleteworldfileincluded1Click(
      Sender: TObject);
    procedure LoadWorldfilefromSphere51a1Click(Sender: TObject);
    procedure LoadWorldfilefromWsc1Click(Sender: TObject);
    procedure SetCustomCursor1Click(Sender: TObject);
  private
        MouseLClickX, MouseLClickY : Integer;
        MouseLShiftState : TShiftState;
        MouseX, MouseY : Integer;
        RC        : HGLRC;
        DC        : HDC;
        StartTick : Cardinal;
        Frames    : Integer;
        FPS       : Single;
        TexListe : TList;
        ObjectList : TList;
        AnimList : TList;
        SelectedItem : Integer;
        TileX, TileY : Integer;
        AreaMoveX, AreaMoveY : Integer;
        NukeX, NukeY : Integer;
        MapVisible : Boolean;
        LastSelectedIsMap : Boolean;
        Zoom : Real;
        function GetItemFromSerial( Serial : Integer ) : PStaticItem;
        procedure ChangeResolution( NewBreite, NewHoehe : Word );
        procedure BuildFont;
        function IsStaticItem( Item : PStaticItem ) : Boolean;
  public
        LClickType : Integer;
        SHoehe, SBreite : Word;
        MaxZ : Integer;
        MapCursorX, MapCursorY : Integer;
        CenterX, CenterY : Integer;
        ObjectListChanged, NewSort : Boolean;
        Map2D, ShowZLevel, ShowGitter : Boolean;
        FontBase  : GLUInt;
        procedure PaintWorld( X, Y : Integer );
        procedure LeftClick( Serial : Integer );
        procedure MoveMouse( Serial : Integer );
        function GetTexId( ItemId, ItemColor : Integer ) : Integer;
        procedure ChangePos( X, Y : Integer );
        function SaveFile( Filename : String ) : String;
        procedure PrintText( pX,pY : Integer; const pText : String);
  end;

  TexIndex = packed record
        Id, Color : Integer;
  end;

  PTexIndex = ^TexIndex;

  TAnimIndex = packed record
        BaseId : Integer;
        NextChange : Integer;
        CurrentCount : Integer;
        CurrentId : Integer;
        CurrentHeight : Integer;
  end;

  PAnimIndex = ^TAnimIndex;

var
  SEditorForm: TSEditorForm;

implementation

{$R *.dfm}

uses uUtilities, StrLib, uGaugeForm, uMapForm, uStaticToolForm, uMulpatcher,
        uMapToolForm;

procedure TSEditorForm.FormCreate(Sender: TObject);
begin
        TexListe := TList.Create;
        AnimList := TList.Create;
        SBreite := Config.GetInteger( 'EditorWidth' );
        SHoehe := Config.GetInteger( 'EditorHeight' );
        if SHoehe = 0 then
                SHoehe := 600;
        if SBreite = 0 then
                SBreite := 800;
        ClientWidth := SBreite;
        ClientHeight := SHoehe;
        ObjectListChanged := True;
        MouseLClickX := -1;
        MouseLClickY := -1;
        MouseX := -1;
        MouseY := -1;
        AreaMoveX := -1;
        AreaMoveY := -1;
        NukeX := -1;
        NukeY := -1;
        SelectedItem := -1;
        MaxZ := 127;
        MapCursorX := 1;
        MapCursorY := 1;

        TileX := -1;
        TileY := -1;

        MapVisible := True;
        StaticVisible.Checked := True;
        LastSelectedIsMap := False;
        Map2D := False;
        ShowZLevel := True;
        ShowGitter := False;
        Zoom := 1;

        if Config.GetInteger( 'LastX' ) <> 0 then
                CenterX := Config.GetInteger( 'LastX' )
        else
                CenterX := 1580;
        if Config.GetInteger( 'LastY' ) <> 0 then
                CenterY := Config.GetInteger( 'LastY' )
        else
                CenterY := 1580;

        InitOpenGL;
        DC := GetDC(Handle);
        RC := CreateRenderingContext(DC, [opDoubleBuffered], 32, 24, 0, 0, 0, 0);
        ActivateRenderingContext(DC, RC);
        glEnable(GL_DEPTH_TEST);
        glDepthFunc(GL_LESS);
        glClearColor(0,0,0,0);
        BuildFont;
        Application.OnIdle := ApplicationEventsIdle;
        StartTick := GetTickCount;
end;

procedure TSEditorForm.FormDestroy(Sender: TObject);
begin
        DeactivateRenderingContext;
        wglDeleteContext(RC);
        ReleaseDC(Handle, DC);
        ChangeDisplaySettings(devmode(nil^), 0);
end;

procedure TSEditorForm.BuildFont;
var
        Font : HFONT;
        pFontName : String;
begin
        pFontName := 'MS Sans Serif';
        FontBase := glGenLists(96);
        Font     := CreateFont(16, 0, 0, 0, FW_MEDIUM, 0, 0, 0, ANSI_CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS,
                               ANTIALIASED_QUALITY, FF_DONTCARE or DEFAULT_PITCH, PChar(pFontName));
        SelectObject(DC, Font);
        wglUseFontBitmaps(DC, 0, 256, FontBase);
        DeleteObject(Font);
end;

procedure TSEditorForm.PrintText( pX,pY : Integer; const pText : String);
begin
        if ( pText = '' ) then exit;
        glPushAttrib( GL_LIST_BIT );
                glRasterPos2i( pX, pY );
                glListBase( FontBase );
                glCallLists( Length(pText), GL_UNSIGNED_BYTE, PChar(pText) );
        glPopAttrib;
end;

function TSEditorForm.GetTexId( ItemId, ItemColor : Integer ) : Integer;
var     J : Integer;
        TIndex : PTexIndex;
begin
        Result := -1;

        if TexListe.Count = 0 then begin
                Result := -1;
        end;
        
        for J := 0 to TexListe.Count-1 do begin
                TIndex := TexListe.Items[ J ];
                if (TIndex.Id = ItemId) and (TIndex.Color = ItemColor) then begin
                        Result := J;
                        break;
                end;
        end;
end;

function TSEditorForm.GetItemFromSerial( Serial : Integer ) : PStaticItem;
var     I : Integer;
begin
        for I := 0 to ObjectList.Count-1 do
                if PStaticItem( ObjectList.Items[I] )^.Serial = Serial then begin
                        Result := PStaticItem( ObjectList.Items[I] );
                        exit;
                end;
        Result := nil;
end;

procedure TSEditorForm.ApplicationEventsIdle(Sender: TObject; var Done: Boolean);
begin
        if not SEditorForm.Visible then exit;

        glLoadIdentity;
        glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);

        glViewport(0, 0, SBreite, SHoehe);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity;
        glOrtho(0,SBreite*Zoom,SHoehe*Zoom,0, -1,1);

        glMatrixMode(GL_TEXTURE);
        glLoadIdentity;

        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity;

        glEnable( GL_TEXTURE_2D );
        glAlphaFunc(GL_GREATER, 0.1);
        glEnable(GL_ALPHA_TEST);

        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        glEnable(GL_BLEND);

        PaintWorld( CenterX, CenterY );

        SwapBuffers(DC);
        Done := False;
        inc(Frames);
        if GetTickCount - StartTick >= 500 then begin
                FPS       := Frames/(GetTickCount-StartTick)*1000;
                Frames    := 0;
                StartTick := GetTickCount;
                Caption := Format( 'Editor (%d FPS)', [trunc( FPS )] );
        end;
end;

procedure TSEditorForm.PaintWorld( X, Y : Integer );
        function SortItems( Item1, Item2 : Pointer ) : Integer;
                function IsStaticItem( Item : PStaticItem ) : Boolean;
                begin
                        if (Item.Typ <> Typ_Item_Map) and (Item.Typ <> Typ_Item_Tex) then
                                Result := True
                        else
                                Result := False;
                end;
        var     Item_1, Item_2 : PStaticItem;
                MapBonus1, MapBonus2 : Integer;
        begin
                Item_1 := PStaticItem( Item1 );
                Item_2 := PStaticItem( Item2 );
                if (Item_1.X+Item_1.Y < Item_2.X+Item_2.Y ) then begin
                        Result := -1;
                        exit;
                end
                else if (Item_1.X+Item_1.Y > Item_2.X+Item_2.Y) then begin
                        Result := 1;
                        exit;
                end
                else begin
                        if not IsStaticItem( Item_1 ) then
                                MapBonus1 := 0
                        else if Tiledata.GetStaticFlag( Item_1.ID, dBACKGROUND ) and Tiledata.GetStaticFlag( Item_1.ID, dSURFACE ) then
                                MapBonus1 := 1
                        else
                                MapBonus1 := 2;

                        if not IsStaticItem( Item_2 ) then
                                MapBonus2 := 0
                        else if Tiledata.GetStaticFlag( Item_2.ID, dBACKGROUND ) and Tiledata.GetStaticFlag( Item_2.ID, dSURFACE ) then
                                MapBonus2 := 1
                        else
                                MapBonus2 := 2;
                        
                        if (Item_1.Z+MapBonus1 < Item_2.Z+MapBonus2) then begin
                                Result := -1;
                                exit;
                        end
                        else if (Item_1.Z+MapBonus1 > Item_2.Z+MapBonus2) then begin
                                Result := 1;
                                exit;
                        end
                        else if ( not IsStaticItem( Item_1 ) ) and IsStaticItem( Item_2 ) then begin
                                Result := -1;
                                exit;
                        end
                        else if IsStaticItem( Item_1 ) and ( not IsStaticItem( Item_2 ) ) then begin
                                Result := 1;
                                exit;
                        end
                        else if IsStaticItem( Item_1 ) and IsStaticItem( Item_2 ) then begin
                                if Tiledata.GetStaticHeight( Item_1.ID ) < Tiledata.GetStaticHeight( Item_2.ID ) then begin
                                        Result := -1;
                                        exit;
                                end
                                else if Tiledata.GetStaticHeight( Item_1.ID ) > Tiledata.GetStaticHeight( Item_2.ID ) then begin
                                        Result := 1;
                                        exit;
                                end
                                else begin
                                        if (Item_1.Color = 0) and (Item_2.Color > 0) then begin
                                                Result := -1;
                                                exit;
                                        end
                                        else if (Item_1.Color > 0) and (Item_2.Color = 0) then begin
                                                Result := 1;
                                                exit;
                                        end
                                        else begin
                                                Result := 0;
                                                exit;
                                        end;
                                end;
                        end
                        else begin
                                Result := 0;
                                exit;
                        end;
                end;
        end;
var     MinX, MaxX, MinY, MaxY, Diag : Integer;
        SMinX, SMaxX, SMinY, SMaxY : Integer;
        I, Count, Down, K : Integer;
        Item : PStaticItem;
        Tex : tglBitmap2D;
        Bitmap : TBitmap;
        PosX, PosY : Integer;
        Index, J : Integer;
        LPixel, OldLPixel, MPixel, OldMPixel : array[0..3] of Byte;
        LSerial, MSerial : Integer;
        TIndex : PTexIndex;
        ItemColor : Integer;
        AnimFound : Boolean;
        ShownAnimId, ItemHeight : Integer;
        AnimIndex : PAnimIndex;
        CurrentBreite, CurrentHoehe : Integer;
        DeleteList : TList;
begin
        CurrentBreite := Round( SBreite * Zoom );
        CurrentHoehe := Round( SHoehe * Zoom );

        LSerial := -1;
        MSerial := -1;
        OldLPixel[0] := 0;
        OldLPixel[1] := 0;
        OldLPixel[2] := 0;
        OldLPixel[3] := 0;
        OldMPixel[0] := 0;
        OldMPixel[1] := 0;
        OldMPixel[2] := 0;
        OldMPixel[3] := 0;

        Diag := Trunc( sqrt( CurrentHoehe*CurrentHoehe + CurrentBreite*CurrentBreite ) / 2 ) div 25;
        MinX := (X - Diag -2);
        MaxX := (X + Diag +2);
        MinY := (Y - Diag -2);
        MaxY := (Y + Diag +2);

        if ObjectListChanged then begin
                ObjectList.Free;
                AnimList.Clear;
                if StaticVisible.Checked then
                        ObjectList := Statics.GetItems( MinX, MaxX, MinY, MaxY )
                else
                        ObjectList := TList.Create;

                if WorldfileVisible.Checked then
                        ObjectList := WorldFile.GetItems( MinX, MaxX, MinY, MaxY, ObjectList );

                if StaticDiffsVisible.Checked then
                        ObjectList := StaticDiff.GetItems( MinX, MaxX, MinY, MaxY, ObjectList );

                if MapVisible then
                        ObjectList := Map.GetItems( MinX, MaxX, MinY, MaxY, ObjectList );

                ObjectListChanged := False;
                NewSort := True;
        end;

        if NewSort then begin
                ObjectList.Sort( @SortItems );
                NewSort := False;
        end;

        if AnimList.Count > 0 then
                for K := 0 to AnimList.Count-1 do
                        if PAnimIndex( AnimList.Items[K] ).NextChange <= GetTickCount then begin
                                PAnimIndex( AnimList.Items[K] ).CurrentCount := (PAnimIndex( AnimList.Items[K] ).CurrentCount+1) mod Animdata.GetCount( PAnimIndex( AnimList.Items[K] ).BaseId );
                                PAnimIndex( AnimList.Items[K] ).CurrentId := Animdata.GetFrame( PAnimIndex( AnimList.Items[K] ).BaseId, PAnimIndex( AnimList.Items[K] ).CurrentCount );
                                PAnimIndex( AnimList.Items[K] ).CurrentHeight := Art.GetStaticTileHeight( PAnimIndex( AnimList.Items[K] ).CurrentId );
                                if PAnimIndex( AnimList.Items[K] ).CurrentCount = 0 then
                                        PAnimIndex( AnimList.Items[K] ).NextChange := GetTickCount + (Animdata.GetStartTime( PAnimIndex( AnimList.Items[K] ).BaseId ) + Animdata.GetDelay( PAnimIndex( AnimList.Items[K] ).BaseId ))*50
                                else
                                        PAnimIndex( AnimList.Items[K] ).NextChange := GetTickCount + Animdata.GetDelay( PAnimIndex( AnimList.Items[K] ).BaseId )*50;
                        end;

        if ObjectList.Count = 0 then exit;

        DeleteList := TList.Create;

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

                if Item.isAnimated then begin
                        AnimFound := False;
                        if AnimList.Count > 0 then
                                for K := 0 to AnimList.Count-1 do
                                        if PAnimIndex( AnimList.Items[K] ).BaseId = Item.ID then begin
                                                AnimFound := True;
                                                ShownAnimId := PAnimIndex( AnimList.Items[K] ).CurrentId;
                                                ItemHeight := PAnimIndex( AnimList.Items[K] ).CurrentHeight;
                                                break;
                                        end;
                        
                        if not AnimFound then begin
                                new( AnimIndex );
                                AnimIndex.BaseId := Item.ID;
                                AnimIndex.NextChange := GetTickCount + Animdata.GetStartTime( Item.ID )*50;
                                AnimIndex.CurrentCount := 0;
                                AnimIndex.CurrentId := Item.ID;
                                ShownAnimId := Item.ID;
                                ItemHeight := Art.GetStaticTileHeight( Item.ID );
                                AnimIndex.CurrentHeight := ItemHeight;

                                AnimList.Add( AnimIndex );
                        end;
                end
                else
                        ItemHeight := Item.Hoehe;

                if IsStaticItem( Item ) then begin
                        PosX := (CurrentBreite div 2) + (Item.X-X - Item.Y+Y) * 22 - ( Item.Breite div 2 );
                        PosY := (CurrentHoehe div 2) + (Item.X-X + Item.Y-Y) * 22 -Item.Z*4 -ItemHeight +44;
                end
                else if Map2D then begin
                        PosX := (CurrentBreite div 2) + (Item.X-X - Item.Y+Y) * 22 - 22;
                        PosY := (CurrentHoehe div 2) + (Item.X-X + Item.Y-Y) * 22;
                end
                else if Item.Typ = Typ_Item_Map then begin
                        PosX := (CurrentBreite div 2) + (Item.X-X - Item.Y+Y) * 22 - 22;
                        PosY := (CurrentHoehe div 2) + (Item.X-X + Item.Y-Y) * 22 -Item.Z*4;
                end
                else if Item.Typ = Typ_Item_Tex then begin
                        PosX := (CurrentBreite div 2) + (Item.X-X - Item.Y+Y) * 22;
                        PosY := (CurrentHoehe div 2) + (Item.X-X + Item.Y-Y) * 22;
                end;

                if (((PosX+Item.Breite > 0) and (PosX < CurrentBreite) and (PosY+Item.Hoehe > 0) and (PosY < CurrentHoehe)) or (Item.Typ = Typ_Item_Tex)) and (not Item.Deleted) and not (IsStaticItem( Item ) and (Item.Z > MaxZ)) then begin
                        if Item.Selected then
                                ItemColor := -1
                        else
                                ItemColor := Item.Color;

                        if ItemColor = 1 then ItemColor := $455;

                        if Item.isAnimated then begin
                                Index := GetTexId( ShownAnimId+$F000, ItemColor );
                        end
                        else if IsStaticItem( Item ) then begin
                                Index := GetTexId( Item.ID+$F000, ItemColor )
                        end
                        else if Map2D then begin
                                Index := GetTexId( Item.ID, ItemColor );
                        end
                        else if Item.Typ = Typ_Item_Tex then begin
                                Index := GetTexId( Item.ID+$8000, ItemColor )
                        end
                        else if Item.Typ = Typ_Item_Map then begin
                                Index := GetTexId( Item.ID, ItemColor );
                        end;

                        if Index = -1 then begin
                                new( TIndex );
                                TIndex.Color := ItemColor;

                                Bitmap := TBitmap.Create;
                                Bitmap.Width := GetNextBit( Item.Breite );
                                Bitmap.Height := GetNextBit( ItemHeight );

                                if Item.isAnimated then begin
                                        Art.PaintStaticTile24( ShownAnimId, 0, 0, ItemColor, Bitmap );
                                        TIndex.Id := ShownAnimId +$F000;
                                end
                                else if IsStaticItem( Item ) then begin
                                        Art.PaintStaticTile24( Item.ID, 0, 0, ItemColor, Bitmap );
                                        TIndex.Id := Item.ID +$F000;
                                end
                                else if Map2D then begin
                                        Art.PaintMapTile24( Item.ID, 0, 0, ItemColor, Bitmap );
                                        TIndex.Id := Item.ID;
                                end
                                else if Item.Typ = Typ_Item_Tex then begin
                                        TIndex.Id := Item.ID +$8000;
                                        Bitmap.Free;
                                        Bitmap := Textures.GetTex24( Tiledata.GetLandTexId( Item.ID ), ItemColor );
                                end
                                else if Item.Typ = Typ_Item_Map then begin
                                        Art.PaintMapTile24( Item.ID, 0, 0, ItemColor, Bitmap );
                                        TIndex.Id := Item.ID;
                                end;
                                TexListe.Add( TIndex );

                                Tex := tglBitmap2D.Create();
                                Tex.AssignFromBitmap( Bitmap );
                                Tex.AddAlphaFromColorKey( 255, 255, 255 );
                                Tex.SetFilter( GL_NEAREST, GL_NEAREST );
                                Tex.GenTexture();
                                Tex.bind();

                                Bitmap.Free;
                                //Tex.free;
                        end
                        else begin
                                glBindTexture( GL_TEXTURE_2D, Index+1 );
                        end;

                        if IsStaticItem( Item ) then begin
                                glColor3f( 1, 1, 1 );
                                glBegin(gl_Quads);
                                        gltexcoord2f(0,0);
                                        glvertex2f(PosX,PosY);
                                        gltexcoord2f(0,1);
                                        glvertex2f(PosX,PosY+GetNextBit( ItemHeight ));
                                        gltexcoord2f(1,1);
                                        glvertex2f(PosX+GetNextBit( Item.Breite ),PosY+GetNextBit( ItemHeight ));
                                        gltexcoord2f(1,0);
                                        glvertex2f(PosX+GetNextBit( Item.Breite ),PosY);
                                glEnd;
                        end
                        else if Map2D then begin
                                glColor3f( 1, 1, 1 );
                                glBegin(gl_Quads);
                                        gltexcoord2f(0,0);
                                        glvertex2f(PosX,PosY);
                                        gltexcoord2f(0,1);
                                        glvertex2f(PosX,PosY+GetNextBit( ItemHeight ));
                                        gltexcoord2f(1,1);
                                        glvertex2f(PosX+GetNextBit( Item.Breite ),PosY+GetNextBit( ItemHeight ));
                                        gltexcoord2f(1,0);
                                        glvertex2f(PosX+GetNextBit( Item.Breite ),PosY);
                                glEnd;

                                if ShowZLevel then begin
                                        glDisable(GL_DEPTH_TEST);
                                        glDisable(GL_TEXTURE_2D);
                                        PrintText( PosX+10, PosY+25, Format( '%d', [Item.Z] ) );
                                        glEnable(GL_DEPTH_TEST);
                                        glEnable(GL_TEXTURE_2D);
                                end;

                                if ShowGitter then begin
                                        glDisable(GL_DEPTH_TEST);
                                        glDisable(GL_TEXTURE_2D);
                                        glBegin(gl_Lines);
                                                glvertex2f(PosX, PosY+22);

                                                glvertex2f(PosX+22,PosY);
                                                glvertex2f(PosX+22,PosY);

                                                glvertex2f(PosX+44,PosY+22);
                                        glEnd;
                                        glEnable(GL_DEPTH_TEST);
                                        glEnable(GL_TEXTURE_2D);
                                end;
                        end
                        else if (Item.Typ = Typ_Item_Map) and (Item.ID <> $2) then begin
                                glColor3f( 1, 1, 1 );
                                glBegin(gl_Quads);
                                        gltexcoord2f(0,0);
                                        glvertex2f(PosX,PosY);
                                        gltexcoord2f(0,1);
                                        glvertex2f(PosX,PosY+GetNextBit( Item.Hoehe ));
                                        gltexcoord2f(1,1);
                                        glvertex2f(PosX+GetNextBit( Item.Breite ),PosY+GetNextBit( Item.Hoehe ));
                                        gltexcoord2f(1,0);
                                        glvertex2f(PosX+GetNextBit( Item.Breite ),PosY);
                                glEnd;

                                if ShowGitter then begin
                                        glDisable(GL_DEPTH_TEST);
                                        glDisable(GL_TEXTURE_2D);
                                        glBegin(gl_Line_Loop);
                                                glvertex2f(PosX, PosY+22);
                                                glvertex2f(PosX+22,PosY);
                                                glvertex2f(PosX+44,PosY+22);
                                                glvertex2f(PosX+22,PosY+44);
                                        glEnd;
                                        glEnable(GL_DEPTH_TEST);
                                        glEnable(GL_TEXTURE_2D);
                                end;
                        end
                        else if (Item.ID <> $2) then begin
                                glColor3f( 0.8, 0.8, 0.8 );
                                glBegin(gl_Quads);
                                        gltexcoord2f(0,0);
                                        glvertex2f(PosX+Item.X0,PosY+Item.Y0);
                                        gltexcoord2f(0,1);
                                        glvertex2f(PosX+Item.X1,PosY+Item.Y1);
                                        gltexcoord2f(1,1);
                                        glvertex2f(PosX+Item.X2,PosY+Item.Y2);
                                        gltexcoord2f(1,0);
                                        glvertex2f(PosX+Item.X3,PosY+Item.Y3);
                                glEnd;

                                if ShowGitter then begin
                                        glDisable(GL_DEPTH_TEST);
                                        glDisable(GL_TEXTURE_2D);
                                        glBegin(gl_Line_Loop);
                                                glvertex2f(PosX+Item.X0,PosY+Item.Y0);
                                                glvertex2f(PosX+Item.X1,PosY+Item.Y1);
                                                glvertex2f(PosX+Item.X2,PosY+Item.Y2);
                                                glvertex2f(PosX+Item.X3,PosY+Item.Y3);
                                        glEnd;
                                        glEnable(GL_DEPTH_TEST);
                                        glEnable(GL_TEXTURE_2D);
                                end;
                        end;

                        if ((MouseLClickX > -1) and (MouseLClickY > -1 ) and (PosX+Item.Breite >= MouseLClickX*Zoom) and (PosX <= MouseLClickX*Zoom) and (PosY+Item.Hoehe >= MouseLClickY*Zoom) and (PosY <= MouseLClickY*Zoom)) or (Item.Typ = Typ_Item_Tex) then begin
                                glReadPixels( MouseLClickX, SHoehe-MouseLClickY, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, @LPixel );
                                if (OldLPixel[0] <> LPixel[0]) or (OldLPixel[1] <> LPixel[1]) or (OldLPixel[2] <> LPixel[2]) then begin
                                        LSerial := Item.Serial;
                                        OldLPixel[0] := LPixel[0];
                                        OldLPixel[1] := LPixel[1];
                                        OldLPixel[2] := LPixel[2];
                                        OldLPixel[3] := LPixel[3];
                                end;
                        end;

                        if ((MouseX > -1) and (MouseY > -1 ) and (PosX+Item.Breite >= MouseX*Zoom) and (PosX <= MouseX*Zoom) and (PosY+Item.Hoehe >= MouseY*Zoom) and (PosY <= MouseY*Zoom)) or (Item.Typ = Typ_Item_Tex) then begin
                                glReadPixels( MouseX, SHoehe-MouseY, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, @MPixel );
                                if (OldMPixel[0] <> MPixel[0]) or (OldMPixel[1] <> MPixel[1]) or (OldMPixel[2] <> MPixel[2]) then begin
                                        MSerial := Item.Serial;
                                        OldMPixel[0] := MPixel[0];
                                        OldMPixel[1] := MPixel[1];
                                        OldMPixel[2] := MPixel[2];
                                        OldMPixel[3] := MPixel[3];
                                end;
                        end;
                end
                else if not ((((PosX+Item.Breite > 0) and (PosX < CurrentBreite) and (PosY+Item.Hoehe > 0) and (PosY < CurrentHoehe)) or (Item.Typ = Typ_Item_Tex)) and (not Item.Deleted)) then begin
                        DeleteList.Add( Pointer( I ) );
                end;
        end;

        if (MouseLClickX > -1) and (MouseLClickY > -1) then begin
                MouseLClickX := -1;
                MouseLClickY := -1;
                LeftClick( LSerial );
        end;

        if (MouseX > -1) and (MouseY > -1) then begin
                Statusbar.Panels[1].Text := Format( '%d,%d Zoom:%g', [MouseX,MouseY,Zoom] );
                MouseX := -1;
                MouseY := -1;
                MoveMouse( MSerial );
        end;

        if DeleteList.Count <> 0 then
                for J := 0 to DeleteList.Count-1 do begin
                        ObjectList.Delete( Integer( DeleteList.Items[J] ) );
                end;
        DeleteList.Free;
end;

procedure TSEditorForm.LeftClick( Serial : Integer );
var     Item, OldItem : PStaticItem;
        I, Color, Id, J, K : Integer;
        X, Y : Integer;
        MX, MY, MZ : Integer;
        PX, PY, PZ : Integer;
        NukeIt : Boolean;
        Bitmap : TBitmap32;
        AnimationExists : Boolean;
begin
        if Serial = -1 then exit;
        
        if LClickType = LClick_Tile_Static then begin
                if ( TileX = -1 ) or ( TileY = -1 ) then begin
                        Item := GetItemFromSerial( Serial );
                        TileX := Item.X;
                        TileY := Item.Y;
                end
                else begin
                        OldItem := GetItemFromSerial( Serial );
                        for X := Min( TileX, OldItem.X ) to Max( TileX, OldItem.X ) do begin
                                for Y := Min( TileY, OldItem.Y ) to Max( TileY, OldItem.Y ) do begin
                                        new( Item );
                                        if StaticToolForm.cbColor.Checked then
                                                Item.Color := StaticToolForm.iColor.Tag
                                        else
                                                Item.Color := 0;

                                        Item.ID := StaticToolForm.iID.Tag;
                                        Item.X := X;
                                        Item.Y := Y;
                                        Item.Z := StrToInt( StaticToolForm.eTileZ.Text );
                                        Item.Deleted := False;
                                        Item.Selected := False;
                                        Item.Serial := Items.AddItem( Item.ID, Item.X, Item.Y, Item.Z, Item.Color );
                                        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;

                                        ObjectList.Add( Item );
                                        NewSort := True;
                                end;
                        end;
                TileX := -1;
                TileY := -1;
                end;
        end
        else if ( TileX <> -1 ) or ( TileY <> -1 ) then begin
                TileX := -1;
                TileY := -1;
        end;

        if (LClickType >= LClick_Move_Static_OL) and (LClickType <= LClick_Move_Static_DOWN ) then begin
                if StaticToolForm.cbArea.Checked and (( AreaMoveX = -1 ) or ( AreaMoveY = -1 )) then begin
                        OldItem := GetItemFromSerial( Serial );
                        AreaMoveX := OldItem.X;
                        AreaMoveY := OldItem.Y;
                end
                else begin
                        MX := 0;
                        MY := 0;
                        MZ := 0;
                        if LClickType = LClick_Move_Static_OL then begin
                                MX := -StrToInt( StaticToolForm.eMove.Text );
                        end
                        else if LClickType = LClick_Move_Static_O then begin
                                MX := -StrToInt( StaticToolForm.eMove.Text );
                                MY := -StrToInt( StaticToolForm.eMove.Text );
                        end
                        else if LClickType = LClick_Move_Static_OR then begin
                                MY := -StrToInt( StaticToolForm.eMove.Text );
                        end
                        else if LClickType = LClick_Move_Static_R then begin
                                MX := StrToInt( StaticToolForm.eMove.Text );
                                MY := -StrToInt( StaticToolForm.eMove.Text );
                        end
                        else if LClickType = LClick_Move_Static_UR then begin
                                MX := StrToInt( StaticToolForm.eMove.Text );
                        end
                        else if LClickType = LClick_Move_Static_U then begin
                                MX := StrToInt( StaticToolForm.eMove.Text );
                                MY := StrToInt( StaticToolForm.eMove.Text );
                        end
                        else if LClickType = LClick_Move_Static_UL then begin
                                MY := StrToInt( StaticToolForm.eMove.Text );
                        end
                        else if LClickType = LClick_Move_Static_L then begin
                                MX := -StrToInt( StaticToolForm.eMove.Text );
                                MY := StrToInt( StaticToolForm.eMove.Text );
                        end
                        else if LClickType = LClick_Move_Static_UP then begin
                                MZ := StrToInt( StaticToolForm.eUpDown.Text );
                        end
                        else if LClickType = LClick_Move_Static_DOWN then begin
                                MZ := -StrToInt( StaticToolForm.eUpDown.Text );
                        end;
                        if not StaticToolForm.cbArea.Checked then begin
                                for I := 0 to ObjectList.Count-1 do
                                        if PStaticItem( ObjectList.Items[I] ).Serial = Serial then begin
                                                if not IsStaticItem( PStaticItem( ObjectList.Items[I] ) ) then continue;
                                                PStaticItem( ObjectList.Items[I] ).X := PStaticItem( ObjectList.Items[I] ).X + MX;
                                                PStaticItem( ObjectList.Items[I] ).Y := PStaticItem( ObjectList.Items[I] ).Y + MY;
                                                PStaticItem( ObjectList.Items[I] ).Z := PStaticItem( ObjectList.Items[I] ).Z + MZ;
                                                break;
                                        end;
                                Items.Move( GetItemFromSerial( Serial ), MX, MY, MZ );
                        end
                        else begin
                                OldItem := GetItemFromSerial( Serial );
                                for I := 0 to ObjectList.Count-1 do begin
                                        if (PStaticItem( ObjectList.Items[I] ).X >= Min( AreaMoveX, OldItem.X )) and
                                                (PStaticItem( ObjectList.Items[I] ).X <= Max( AreaMoveX, OldItem.X )) and
                                                (PStaticItem( ObjectList.Items[I] ).Y >= Min( AreaMoveY, OldItem.Y )) and
                                                (PStaticItem( ObjectList.Items[I] ).Y <= Max( AreaMoveY, OldItem.Y )) and
                                                (IsStaticItem( PStaticItem( ObjectList.Items[I] ) )) then begin
                                                        if StaticToolForm.cbMoveTestID.Checked then begin
                                                                if PStaticItem( ObjectList.Items[I] ).ID = StaticToolForm.iID.Tag then
                                                                        Items.Move( PStaticItem( ObjectList.Items[I] ), MX, MY, MZ );
                                                        end
                                                        else begin
                                                                Items.Move( PStaticItem( ObjectList.Items[I] ), MX, MY, MZ );
                                                        end;
                                        end;
                                end;
                                AreaMoveX := -1;
                                AreaMoveY := -1;
                        end;
                        NewSort := True;
                end;
        end
        else begin
                AreaMoveX := -1;
                AreaMoveY := -1;
        end;

        if LClickType = LClick_Nuke_Static then begin
                if ( NukeX = -1 ) or ( NukeY = -1 ) then begin
                        Item := GetItemFromSerial( Serial );
                        NukeX := Item.X;
                        NukeY := Item.Y;
                end
                else begin
                        OldItem := GetItemFromSerial( Serial );
                        for I := 0 to ObjectList.Count-1 do begin
                                if (PStaticItem( ObjectList.Items[I] ).X >= Min( NukeX, OldItem.X )) and
                                        (PStaticItem( ObjectList.Items[I] ).X <= Max( NukeX, OldItem.X )) and
                                        (PStaticItem( ObjectList.Items[I] ).Y >= Min( NukeY, OldItem.Y )) and
                                        (PStaticItem( ObjectList.Items[I] ).Y <= Max( NukeY, OldItem.Y )) and
                                        (IsStaticItem( PStaticItem( ObjectList.Items[I] ) )) then begin
                                        NukeIt := True;

                                        if StaticToolForm.cbTestId.Checked then
                                                if PStaticItem( ObjectList.Items[I] ).ID <> StaticToolForm.iID.Tag then
                                                        NukeIt := False;
                                        if StaticToolForm.cbTestHeight.Checked then
                                                if (PStaticItem( ObjectList.Items[I] ).Z < StrToInt( StaticToolForm.eDown.Text )) or (PStaticItem( ObjectList.Items[I] ).Z > StrToInt( StaticToolForm.eUp.Text )) then
                                                        NukeIt := False;

                                        if NukeIt then begin
                                                if StaticToolForm.cbSetColor.Checked then begin
                                                        PStaticItem( ObjectList.Items[I] ).Color := StaticToolForm.iColor.Tag;
                                                        Items.SetColor( PStaticItem( ObjectList.Items[I] ), StaticToolForm.iColor.Tag );
                                                end
                                                else begin
                                                        PStaticItem( ObjectList.Items[I] ).Deleted := True;
                                                        Items.Delete( PStaticItem( ObjectList.Items[I] ) );
                                                end;
                                        end;
                                end;
                        end;
                        NukeX := -1;
                        NukeY := -1;
                end;
        end
        else begin
                NukeX := -1;
                NukeY := -1;
        end;

        if LClickType = LClick_Info_Static then begin
                MouseLShiftState := [];
                Item := GetItemFromSerial( Serial );
                if Item <> nil then begin
                        InfoForm.lID.Caption := Format( '0x%x (internal Serial: %x)', [Item.Id, Item.Serial] );
                        InfoForm.lPos.Caption := Format( '%d,%d,%d', [Item.X,Item.Y,Item.Z] );
                        InfoForm.lColor.Caption := Format( '0x%x', [Item.Color] );
                        InfoForm.Show;
                end;
        end
        else if LClickType = LClick_Delete_Static then begin
                for I := 0 to ObjectList.Count-1 do
                        if PStaticItem( ObjectList.Items[I] ).Serial = Serial then begin
                                if not IsStaticItem( PStaticItem( ObjectList.Items[I] ) ) then exit;
                                PStaticItem( ObjectList.Items[I] ).Deleted := True;
                                break;
                        end;
                Items.Delete( GetItemFromSerial( Serial ) );
        end
        else if LClickType = LClick_Add_Static then begin
                OldItem := GetItemFromSerial( Serial );

                new( Item );
                if StaticToolForm.cbColor.Checked then
                        Item.Color := StaticToolForm.iColor.Tag
                else
                        Item.Color := 0;
                Item.ID := StaticToolForm.iID.Tag;
                Item.X := OldItem.X;
                Item.Y := OldItem.Y;
                if IsStaticItem( OldItem ) then
                        Item.Z := OldItem.Z + Tiledata.GetStaticHeight( OldItem.ID )
                else
                        Item.Z := OldItem.Z;
                Item.Deleted := False;
                Item.Selected := False;
                Item.Serial := Items.AddItem( Item.ID, Item.X, Item.Y, Item.Z, Item.Color );
                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;                

                J := 0;
                ObjectList.Insert( J, Item );
                NewSort := True;
        end
        else if LClickType = LClick_Color_Static then begin
                Color := StaticToolForm.iColor.Tag;
                for I := 0 to ObjectList.Count-1 do
                        if PStaticItem( ObjectList.Items[I] ).Serial = Serial then begin
                                if not IsStaticItem( PStaticItem( ObjectList.Items[I] ) ) then exit;
                                PStaticItem( ObjectList.Items[I] ).Color := Color;
                                break;
                        end;
                Items.SetColor( GetItemFromSerial( Serial ), Color );
        end
        else if LClickType = LClick_ID_Static then begin
                Id := StaticToolForm.iID.Tag;
                for I := 0 to ObjectList.Count-1 do
                        if PStaticItem( ObjectList.Items[I] ).Serial = Serial then begin
                                if not IsStaticItem( PStaticItem( ObjectList.Items[I] ) ) then continue;
                                PStaticItem( ObjectList.Items[I] ).Id := Id;
                                PStaticItem( ObjectList.Items[I] ).Hoehe := Art.GetStaticTileHeight( Id );
                                PStaticItem( ObjectList.Items[I] ).Breite := Art.GetStaticTileWidth( Id );
                                if (Tiledata.GetStaticFlag( Id, dANIMATION )) and (Animdata.GetCount( Id ) > 0) then
                                        PStaticItem( ObjectList.Items[I] ).isAnimated := True
                                else
                                        PStaticItem( ObjectList.Items[I] ).isAnimated := False;                                                                          
                                break;
                        end;
                Items.SetId( GetItemFromSerial( Serial ), Id );
        end
        else if LClickType = LClick_GetID_Static then begin
                OldItem := GetItemFromSerial( Serial );
                if IsStaticItem( OldItem ) then begin
                        StaticToolForm.iID.Tag := OldItem.ID;
                        StaticToolForm.iID.Bitmap.SetSize( 65, 65 );
                        StaticToolForm.iID.Bitmap.Clear( Color32( clWhite ) );
                        Bitmap := Art.GetStaticTile( OldItem.ID );
                        StaticToolForm.iID.Bitmap.Draw( ( 65 - Bitmap.Width ) div 2, ( 65 - Bitmap.Height ) div 2, Bitmap );
                        StaticToolForm.HistoryAdd( OldItem.ID );
                end;
        end
        else if LClickType = LClick_GetColor_Static then begin
                OldItem := GetItemFromSerial( Serial );
                if IsStaticItem( OldItem ) then begin
                        StaticToolForm.iColor.Tag := OldItem.Color;
                        StaticToolForm.iColor.Bitmap.SetSize( 44, 20 );
                        if OldItem.Color > 0 then
                                StaticToolForm.iColor.Bitmap.Clear( Color15to32( Hues.GetColor( OldItem.Color-1, 28 ) ) )
                        else
                                StaticToolForm.iColor.Bitmap.Clear( Color32( StaticToolForm.iColor.Color ) );
                        StaticToolForm.ColorHistoryAdd( OldItem.Color );
                end;
        end
        else if LClickType = LClick_GetId_Map then begin
                OldItem := GetItemFromSerial( Serial );
                if not IsStaticItem( OldItem ) then begin
                        MapToolForm.iID.Tag := OldItem.ID;
                        MapToolForm.iID.Bitmap.SetSize( 65, 65 );
                        MapToolForm.iID.Bitmap.Clear( Color32( clWhite ) );
                        Bitmap := Art.GetMapTile( OldItem.ID );
                        MapToolForm.iID.Bitmap.Draw( ( 65 - Bitmap.Width ) div 2, ( 65 - Bitmap.Height ) div 2, Bitmap );
                        MapToolForm.HistoryAdd( OldItem.ID );
                end;
        end
        else if (LClickType = LClick_MoveUp_Map) or (LClickType = LClick_MoveDown_Map) then begin
                OldItem := GetItemFromSerial( Serial );
                for PX := ( OldItem.X-MapCursorX+1 ) to ( OldItem.X+MapCursorX-1 ) do
                        for PY := ( OldItem.Y-MapCursorY+1 ) to ( OldItem.Y+MapCursorY-1 ) do begin
                                if LClickType = LClick_MoveUp_Map then
                                        Map.MoveZ( PX, PY, StrToInt( MapToolForm.eUpDown.Text ) )
                                else
                                        Map.MoveZ( PX, PY, -StrToInt( MapToolForm.eUpDown.Text ) );
                        end;
                ObjectListChanged := True;
        end
        else if LClickType = LClick_SetId_Map then begin
                OldItem := GetItemFromSerial( Serial );
                for PX := ( OldItem.X-MapCursorX+1 ) to ( OldItem.X+MapCursorX-1 ) do
                        for PY := ( OldItem.Y-MapCursorY+1 ) to ( OldItem.Y+MapCursorY-1 ) do begin
                                Map.ChangeId( PX, PY, MapToolForm.iID.Tag );
                        end;
                ObjectListChanged := True;                        
        end
        else if LClickType = LClick_SetZ_Map then begin
                OldItem := GetItemFromSerial( Serial );
                for PX := ( OldItem.X-MapCursorX+1 ) to ( OldItem.X+MapCursorX-1 ) do
                        for PY := ( OldItem.Y-MapCursorY+1 ) to ( OldItem.Y+MapCursorY-1 ) do begin
                                Map.ChangeZ( PX, PY, StrToInt( MapToolForm.eUpDown.Text ) )
                        end;
                ObjectListChanged := True;
        end
        else if LClickType = LClick_SetRandomZ_Map then begin
                OldItem := GetItemFromSerial( Serial );
                for PX := ( OldItem.X-MapCursorX+1 ) to ( OldItem.X+MapCursorX-1 ) do
                        for PY := ( OldItem.Y-MapCursorY+1 ) to ( OldItem.Y+MapCursorY-1 ) do begin
                                Map.ChangeZ( PX, PY, Random(StrToInt( MapToolForm.eRHMax.Text ) - StrToInt( MapToolForm.eRHMin.Text )) + StrToInt( MapToolForm.eRHMin.Text ) );
                        end;
                ObjectListChanged := True;
        end;
end;

procedure TSEditorForm.MoveMouse( Serial : Integer );
var     I : Integer;
        Item : PStaticItem;
begin
        if Serial = SelectedItem then exit;
        if ObjectList.Count = 0 then exit;

        if (ssLeft in MouseLShiftState) and (LClickType <> LClick_Info_Static) and (LClickType <> LClick_Tile_Static) and ((LClickType < LClick_Move_Static_OL) or (LClickType > LClick_Move_Static_DOWN)) then begin
                LeftClick( Serial );
        end;

        if LastSelectedIsMap then begin
                for I := 0 to ObjectList.Count-1 do
                        if not IsStaticItem( PStaticItem( ObjectList.Items[I] ) ) then
                                PStaticItem( ObjectList.Items[I] ).Selected := False;
                LastSelectedIsMap := False;
        end
        else if SelectedItem <> -1 then begin
                for I := 0 to ObjectList.Count-1 do begin
                        if PStaticItem( ObjectList.Items[I] ).Serial = SelectedItem then begin
                                PStaticItem( ObjectList.Items[I] ).Selected := False;
                                break;
                        end;
                end;
        end;

        if (MapCursorX = 1) and (MapCursorY = 1) then begin
                for I := 0 to ObjectList.Count-1 do begin
                        if PStaticItem( ObjectList.Items[I] ).Serial = Serial then begin
                                PStaticItem( ObjectList.Items[I] ).Selected := True;
                                Item := PStaticItem( ObjectList.Items[I] );
                                StatusBar.Panels[0].Text := Format( 'ID: 0x%x   Pos: %d,%d,%d   Color: 0x%x', [Item.ID, Item.X, Item.Y, Item.Z, Item.Color] );
                        end
                        else if PStaticItem( ObjectList.Items[I] ).Serial = SelectedItem then
                                PStaticItem( ObjectList.Items[I] ).Selected := False;
                end;
                Items.Select( GetItemFromSerial( Serial ) );
        end
        else begin
                Item := GetItemFromSerial( Serial );
                if Item = nil then exit;                
                StatusBar.Panels[0].Text := Format( 'Pos: %d,%d', [Item.X, Item.Y] );
                for I := 0 to ObjectList.Count-1 do begin
                        if not IsStaticItem( PStaticItem( ObjectList.Items[I] ) ) and
                                (PStaticItem( ObjectList.Items[I] ).X >= Item.X-MapCursorX+1) and
                                (PStaticItem( ObjectList.Items[I] ).X <= Item.X+MapCursorX-1) and
                                (PStaticItem( ObjectList.Items[I] ).Y >= Item.Y-MapCursorY+1) and
                                (PStaticItem( ObjectList.Items[I] ).Y <= Item.Y+MapCursorY-1) then
                                PStaticItem( ObjectList.Items[I] ).Selected := True;
                end;
                LastSelectedIsMap := True;
        end;

        if SelectedItem <> -1 then Items.UnSelect( GetItemFromSerial( SelectedItem ) );
        SelectedItem := Serial;
end;

procedure TSEditorForm.FormMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
        if not Active then exit;
        if Button = mbLeft then begin
                MouseLClickX := X;
                MouseLClickY := Y;
                MouseLShiftState := Shift;
        end
        else if Button = mbRight then begin
                CenterX := CenterX + Trunc( ( (Y- Trunc(SHoehe/2)) + (X- Trunc(SBreite/2)) ) / 30*Zoom );
                CenterY := CenterY + Trunc( ( (Y- Trunc(SHoehe/2)) - (X- Trunc(SBreite/2)) ) / 30*Zoom );
                ObjectListChanged := True;
        end;
end;

procedure TSEditorForm.FormMouseMove(Sender: TObject; Shift: TShiftState;
  X, Y: Integer);
begin
        MouseX := X;
        MouseY := Y;
end;

procedure TSEditorForm.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
        if Key = VK_LEFT then begin
                CenterX := CenterX -1;
                CenterY := CenterY +1;
                ObjectListChanged := True;
        end
        else if Key = VK_RIGHT then begin
                CenterX := CenterX +1;
                CenterY := CenterY -1;
                ObjectListChanged := True;
        end
        else if Key = VK_UP then begin
                CenterX := CenterX -1;
                CenterY := CenterY -1;
                ObjectListChanged := True;
        end
        else if Key = VK_DOWN then begin
                CenterX := CenterX +1;
                CenterY := CenterY +1;
                ObjectListChanged := True;
        end
        else if Key in [ 109, 189 ] then begin
                if Zoom < 10 then begin
                        Zoom := Zoom + 0.1;
                        ObjectListChanged := True;
                end;
        end
        else if Key in [ 107, 187 ] then begin
                if Zoom > 0.2 then begin
                        Zoom := Zoom - 0.1;
                        ObjectListChanged := True;
                end;
        end;
end;

procedure TSEditorForm.ChangeResolution( NewBreite, NewHoehe : Word );
begin
        Config.SetInteger( 'EditorWidth', NewBreite );
        Config.SetInteger( 'EditorHeight', NewHoehe );
        showmessage( 'Restart Mulpatcher now.' );
end;

procedure TSEditorForm.N640x4801Click(Sender: TObject);
begin
        ChangeResolution( 640, 480 );
end;

procedure TSEditorForm.N800x6001Click(Sender: TObject);
begin
        ChangeResolution( 800, 600 );
end;

procedure TSEditorForm.N1024x7681Click(Sender: TObject);
begin
        ChangeResolution( 1024, 768 );
end;

procedure TSEditorForm.ChangePos( X, Y : Integer );
begin
        CenterX := X;
        CenterY := Y;
        ObjectListChanged := True;
end;

procedure TSEditorForm.FormHide(Sender: TObject);
begin
        StaticToolForm.Hide;
        MapToolForm.Hide;
        MapForm.Hide;
        MainForm.Show;
        StaticDiffForm.Hide;
        Config.SetInteger( 'LastX', CenterX );
        Config.SetInteger( 'LastY', CenterY );        
end;

procedure TSEditorForm.FormShow(Sender: TObject);
begin
        LClickType := 0;
        StaticToolForm.Show;
        MapToolForm.Show;
end;

procedure TSEditorForm.ShowStatictool1Click(Sender: TObject);
begin
        StaticToolForm.Show;
end;

procedure TSEditorForm.FormMouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
        if Button = mbLeft then begin
                MouseLShiftState := Shift;
        end;
end;

procedure TSEditorForm.mMapClick(Sender: TObject);
begin
        if MapVisible then begin
                MapVisible := False;
                mMap.Caption := 'Show Map';
        end
        else begin
                MapVisible := True;
                mMap.Caption := 'Hide Map';
        end;
        ObjectListChanged := True;
end;

procedure TSEditorForm.PatchMap1Click(Sender: TObject);
begin
        Map.Save;
end;

procedure TSEditorForm.PatchStatics1Click(Sender: TObject);
var     idxPath, mulPath : String;
begin
        idxPath := SaveFile( 'Staidx0.mul' );
        mulPath := SaveFile( 'Statics0.mul' );

        if ( idxPath <> '' ) and ( mulPath <> '' ) then begin
                Statics.Save( idxPath, mulPath );
        end;
end;

function TSEditorForm.SaveFile( Filename : String ) : String;
var     SaveDialog : TSaveDialog;
begin
        SaveDialog := TSaveDialog.Create( nil );
        SaveDialog.Filter := Filename + '|' + Filename;

        if not SaveDialog.Execute then begin
                SaveDialog.Free;
                Result := '';
                exit;
        end;

        Result := SaveDialog.FileName;
        SaveDialog.Free;
end;

procedure TSEditorForm.ShowMaptool1Click(Sender: TObject);
begin
        MapToolForm.Show;
end;

procedure TSEditorForm.ShowMap2DClick(Sender: TObject);
begin
        if Map2D then begin
                Map2D := False;
                ShowMap2D.Caption := 'Show Map 2D';
        end
        else begin
                Map2D := True;
                ShowMap2D.Caption := 'Show Map 3D';
        end;
end;

procedure TSEditorForm.ClearStatics1Click(Sender: TObject);
begin
        Statics.Clear;
        ObjectListChanged := True;
end;

procedure TSEditorForm.ChooseZLevelClick(Sender: TObject);
begin
        if ShowZLevel then begin
                ShowZLevel := False;
                ChooseZLevel.Caption := 'Show Z-Level';
        end
        else begin
                ShowZLevel := True;
                ChooseZLevel.Caption := 'Hide Z-Level';
        end;
end;

procedure TSEditorForm.ShowWebClick(Sender: TObject);
begin
        if ShowGitter then begin
                ShowGitter := False;
                ShowWeb.Caption := 'Show Web';
        end
        else begin
                ShowGitter := True;
                ShowWeb.Caption := 'Hide Web';
        end;
end;

function TSEditorForm.IsStaticItem( Item : PStaticItem ) : Boolean;
begin
        if (Item.Typ <> Typ_Item_Map) and (Item.Typ <> Typ_Item_Tex) then
                Result := True
        else
                Result := False;
end;

procedure TSEditorForm.StaticVisibleClick(Sender: TObject);
begin
        if StaticVisible.Checked then begin
                StaticVisible.Checked := False;
        end
        else begin
                StaticVisible.Checked := True;
        end;
        ObjectListChanged := True;
end;

procedure TSEditorForm.WorldfileVisibleClick(Sender: TObject);
begin
        if WorldFileVisible.Checked then begin
                WorldFileVisible.Checked := False;
        end
        else begin
                WorldFileVisible.Checked := True;
        end;
        ObjectListChanged := True;
end;

procedure TSEditorForm.SaveWorldfile1Click(Sender: TObject);
var     Path : String;
begin
        Path := SaveFile( '*.txt' );
        WorldFile.SaveToTextfile( Path );
end;

procedure TSEditorForm.LoadWorldfile1Click(Sender: TObject);
var     Path : String;
        OpenDialog : TOpenDialog;
begin
        OpenDialog := TOpenDialog.Create( nil );
        OpenDialog.Filter := '*.txt|*.txt';

        if not OpenDialog.Execute then begin
                OpenDialog.Free;
                exit;
        end;

        Path := OpenDialog.FileName;
        OpenDialog.Free;

        WorldFile.LoadFromTextfile( Path );
        ObjectListChanged := True;
end;

procedure TSEditorForm.ClearWorldfile1Click(Sender: TObject);
begin
        WorldFile.ClearAll;
        ObjectListChanged := True;
end;

procedure TSEditorForm.PatchStaticsallnewitemsincluded1Click(
  Sender: TObject);
var     idxPath, mulPath : String;
begin
        idxPath := SaveFile( 'Staidx0.mul' );
        mulPath := SaveFile( 'Statics0.mul' );

        if ( idxPath <> '' ) and ( mulPath <> '' ) then begin
                Statics.Save( idxPath, mulPath, 1 );
        end;
end;

procedure TSEditorForm.PatchStaticsallnewitemsandthecompleteworldfileincluded1Click(
  Sender: TObject);
var     idxPath, mulPath : String;
begin
        idxPath := SaveFile( 'Staidx0.mul' );
        mulPath := SaveFile( 'Statics0.mul' );

        if ( idxPath <> '' ) and ( mulPath <> '' ) then begin
                Statics.Save( idxPath, mulPath, 2 );
        end;
end;

procedure TSEditorForm.SaveWorldfiletoSphere51a1Click(Sender: TObject);
var     Path : String;
begin
        Path := SaveFile( '*.scp' );
        WorldFile.SaveToSphere51a( Path );
end;

procedure TSEditorForm.SaveWorldfiletoWsc1Click(Sender: TObject);
var     Path : String;
begin
        Path := SaveFile( '*.wsc' );
        WorldFile.SaveToWsc( Path );
end;

procedure TSEditorForm.StaticDiffsVisibleClick(Sender: TObject);
begin
        if StaticDiffsVisible.Checked then begin
                StaticDiffsVisible.Checked := False;
        end
        else begin
                StaticDiffsVisible.Checked := True;
        end;
        ObjectListChanged := True;
end;

procedure TSEditorForm.LoadStaticDiffs2Click(Sender: TObject);
var     OpenDialog : TrmBrowseForFolder;
begin
        OpenDialog := TrmBrowseForFolder.create( nil );
        OpenDialog.Title := 'Where are your Diff-Files?';

        if not OpenDialog.Execute then begin
                OpenDialog.Free;
                exit;
        end;

        StaticDiff.Load( OpenDialog.Folder +'\' );
        OpenDialog.Free;
        ObjectListChanged := True;
end;

procedure TSEditorForm.ShowStaticDiffOverview1Click(Sender: TObject);
begin
        StaticDiffForm.Show;
end;

procedure TSEditorForm.SaveStaticDiffschangesonly1Click(Sender: TObject);
var     OpenDialog : TrmBrowseForFolder;
begin
        OpenDialog := TrmBrowseForFolder.create( nil );
        OpenDialog.Title := 'Where do you want to have your Diff-Files?';

        if not OpenDialog.Execute then begin
                OpenDialog.Free;
                exit;
        end;

        StaticDiff.Save( OpenDialog.Folder +'\' );
        OpenDialog.Free;
end;

procedure TSEditorForm.SaveStaticDiffsnewitemsincluded1Click(
  Sender: TObject);
var     OpenDialog : TrmBrowseForFolder;
begin
        OpenDialog := TrmBrowseForFolder.create( nil );
        OpenDialog.Title := 'Where do you want to have your Diff-Files?';

        if not OpenDialog.Execute then begin
                OpenDialog.Free;
                exit;
        end;

        StaticDiff.Save( OpenDialog.Folder +'\', 1 );
        OpenDialog.Free;
end;

procedure TSEditorForm.SaveStaticDiffsnewitemsandcompleteworldfileincluded1Click(
  Sender: TObject);
var     OpenDialog : TrmBrowseForFolder;
begin
        OpenDialog := TrmBrowseForFolder.create( nil );
        OpenDialog.Title := 'Where do you want to have your Diff-Files?';

        if not OpenDialog.Execute then begin
                OpenDialog.Free;
                exit;
        end;

        StaticDiff.Save( OpenDialog.Folder +'\', 2 );
        OpenDialog.Free;
end;

procedure TSEditorForm.LoadWorldfilefromSphere51a1Click(Sender: TObject);
var     Path : String;
        OpenDialog : TOpenDialog;
begin
        OpenDialog := TOpenDialog.Create( nil );
        OpenDialog.Filter := '*.scp|*.scp';

        if not OpenDialog.Execute then begin
                OpenDialog.Free;
                exit;
        end;

        Path := OpenDialog.FileName;
        OpenDialog.Free;

        WorldFile.LoadFromSphere51a( Path );
        ObjectListChanged := True;
end;

procedure TSEditorForm.LoadWorldfilefromWsc1Click(Sender: TObject);
var     Path : String;
        OpenDialog : TOpenDialog;
begin
        OpenDialog := TOpenDialog.Create( nil );
        OpenDialog.Filter := '*.wsc|*.wsc';

        if not OpenDialog.Execute then begin
                OpenDialog.Free;
                exit;
        end;

        Path := OpenDialog.FileName;
        OpenDialog.Free;

        WorldFile.LoadFromWsc( Path );
        ObjectListChanged := True;
end;

procedure TSEditorForm.SetCustomCursor1Click(Sender: TObject);
begin
        MapCursorX := ( StrToInt( InputBox( 'Cursorlength X', '', '1' ) ) +1 ) div 2;
        MapCursorY := ( StrToInt( InputBox( 'Cursorlength Y', '', '1' ) ) +1 ) div 2;
end;

end.
