{*************************************************************************}
{                                                                         }
{ ZoneUnit.pas - Zone Editor window                                       }
{                                                                         }
{ This file is a part of the project:                                     }
{   Dizzy Quest Editor - the quest editor for Dizzy-like games            }
{                                                                         }
{ © Parfenov Alexey Andreevich, 2007                                      }
{                                                                         }
{ e-mail: AlkatrazStudio@yandex.ru                                        }
{                                                                         }
{ This program is free software; you can redistribute it and/or modify    }
{ it under the terms of the GNU General Public License as published by    }
{ the Free Software Foundation; either version 2 of the License, or       }
{ (at your option) any later version.                                     }
{                                                                         }
{ This program is distributed in the hope that it will be useful,         }
{ but WITHOUT ANY WARRANTY; without even the implied warranty of          }
{ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the            }
{ GNU General Public License for more details.                            }
{                                                                         }
{ You may read GNU General Public License at:                             }
{   http://www.gnu.org/copyleft/gpl.html                                  }
{                                                                         }
{*************************************************************************}
unit ZoneUnit;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls, Spin, GR32_Image, Buttons,dqe2_types,gr32,
  gr32_layers,alkatraz,gameplayer,gameplayervisual;

type
  TForm_Zones = class(TForm)
    GroupBox1: TGroupBox;
    Label1: TLabel;
    SpinEdit1: TSpinEdit;
    Label2: TLabel;
    SpinEdit2: TSpinEdit;
    Label4: TLabel;
    SpinEdit3: TSpinEdit;
    SpinEdit4: TSpinEdit;
    Label3: TLabel;
    Button1: TButton;
    ScrollBar1: TScrollBar;
    ScrollBar2: TScrollBar;
    SpeedButton1: TSpeedButton;
    Preview: TImage32;
    ComboBox2: TComboBox;
    Button3: TButton;
    ComboBox3: TComboBox;
    Label6: TLabel;
    Label7: TLabel;
    GroupBox2: TGroupBox;
    Button2: TButton;
    CheckBox1: TCheckBox;
    ComboBox1: TComboBox;
    Label5: TLabel;
    GroupBox3: TGroupBox;
    ListBox1: TListBox;
    Button4: TButton;
    Button5: TButton;
    Button6: TButton;
    GroupBox4: TGroupBox;
    Edit1: TEdit;
    SpeedButton2: TSpeedButton;
    ColorBox1: TColorBox;
    Label8: TLabel;
    GroupBox5: TGroupBox;
    ComboBox4: TComboBox;
    Label9: TLabel;
    Label10: TLabel;
    SpinEdit5: TSpinEdit;
    Label11: TLabel;
    Label12: TLabel;
    SpinEdit6: TSpinEdit;
    SpinEdit7: TSpinEdit;
    Button7: TButton;
    procedure FormDestroy(Sender: TObject);
    procedure PreviewMouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
    procedure Button2Click(Sender: TObject);
    procedure CheckBox1Click(Sender: TObject);
    procedure ColorBox1Change(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Button6Click(Sender: TObject);
    procedure ComboBox2Change(Sender: TObject);
    procedure SpeedButton2Click(Sender: TObject);
    procedure Button5Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
    procedure UpdateForm;
    procedure UpdateObject;
    procedure UpdateList;
    procedure ChangeRect;
    function CheckCollision(l,t,r,b:integer;Zone:DQE2_Zone=nil):boolean;
    procedure UpdateSpins;
    procedure RedrawSelection;
    procedure PreviewMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
    procedure PreviewMouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer; Layer: TCustomLayer);
    procedure ScrollBar2Change(Sender: TObject);
    procedure ScrollBar1Change(Sender: TObject);
    procedure ComboBox3Change(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure UpdatePreview;
    procedure FormCreate(Sender: TObject);
    procedure SpeedButton1Click(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure ComboBox4Change(Sender: TObject);
    procedure SpinEdit5Change(Sender: TObject);
    procedure SpinEdit6Change(Sender: TObject);
    procedure SpinEdit7Change(Sender: TObject);
    procedure Localize;
    procedure Button7Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form_Zones: TForm_Zones;
  CurZone:DQE2_Zone=nil;
  CurSel:DQE2_Zone=nil;
  CurRect,VisRect,NewRect:TRect;
  _x,_y,mx,my,stx,sty:integer;
  sc:integer;
  can:boolean=true;
  Mode:(mmNone,mmNew,mmDrag);
  tmph,tmpw:integer;
  Mus:TGPMusic;

implementation

uses Types, ChooseUnit, GameUnit, ObjectUnit, MainUnit;

{$R *.dfm}

var lng:array of string;

procedure TForm_Zones.Button2Click(Sender: TObject);
var
  x:TGPStore;
  mus:TGPMusic;
begin
  if ComboBox1.Text='' then exit;
  mus:=TGPMusic.Create;
  if mus.Open(world.SharedDir+'\music\'+ComboBox1.Text) then
  begin
    x:=CurZone.Environment;
    mus.LoadState(x);
    ShowGPVisualForm(mus);
    mus.SaveState(x);
    CurZone.Environment:=x;
  end;
  mus.Free;
end;

procedure TForm_Zones.Button3Click(Sender: TObject);
begin
  if curzone<>nil then
  begin
    world.Player.MoveToZone(CurZone,0,0);
  end;
end;

procedure TForm_Zones.Button4Click(Sender: TObject);
var
  sc:dqe2_script;
  a:integer;
  ok:boolean;
begin
  if world.Scripts.Count=0 then
    MessageDlgRus(lng[26],lng[27],MB_OK or MB_ICONINFORMATION)
  else
  repeat
    sc:=DQE2_Script(Form_Choose.ShowIt(world.Scripts));
    if sc<>nil then
    begin
      ok:=true;
      for a:=0 to CurZone.StartScripts.Count-1 do
        if sc=CurZone.StartScripts[a] then
          begin ok:=false;break;end;
      if ok then
      begin
        CurZone.StartScripts.Add(sc);
        ListBox1.items.Add(sc.Name);
        break;
      end
      else
        MessageDlgRus(lng[41],lng[42]+#13#10+sc.Name,MB_OK or MB_ICONWARNING);
    end
    else
      break;
  until false;
end;

procedure TForm_Zones.Button5Click(Sender: TObject);
begin
  if ListBox1.ItemIndex>=0 then
    if MessageDlgRus(lng[28],lng[29]+#13#10+ListBox1.Items[ListBox1.itemindex],MB_OKCANCEL or MB_ICONWARNING)=mrok then
    begin
      CurZone.StartScripts.Delete(ListBox1.ItemIndex);
      ListBox1.DeleteSelected;
    end;
end;

procedure TForm_Zones.Button6Click(Sender: TObject);
var
  it:boolean;
  a:integer;
begin
  if CurZone=nil then exit;
  it:=false;
  for a:=0 to World.Items.Count-1 do
    if DQE2_Item(World.Items[a]).Zone=CurZone then
    begin
      it:=true;
      break;
    end;
  if (CurZone.Objects.Count>0) or it then
    MessageDlgRus(lng[30],lng[31], MB_OK or MB_ICONINFORMATION)
  else
    if CurZone=world.CurrentZone then
      MessageDlgRus(lng[32],lng[33], MB_OK or MB_ICONINFORMATION)
    else
      if CurZone=world.CurrentZone then
        MessageDlgRus(lng[34],lng[35], MB_OK or MB_ICONINFORMATION)
      else
  if MessageDlgRus(lng[36],lng[37]+#13#10+CurZone.Name,MB_OKCANCEL or MB_ICONWARNING)=mrok then
  begin
    World.Stop;
    FreeAndNil(CurZone);
    UpdateList;
    UpdateForm;
    Form_Objects.UpdateZoneList;
  end;
end;

procedure TForm_Zones.Button7Click(Sender: TObject);
begin
  if can then
    try
      StrToInt(SpinEdit1.Text);
      StrToInt(SpinEdit2.Text);
      StrToInt(SpinEdit3.Text);
      StrToInt(SpinEdit4.Text);
      ChangeRect;
    except
    end;
end;

procedure TForm_Zones.ChangeRect;
begin
  CurZone.SetNewPos(SpinEdit1.Value,SpinEdit2.Value,SpinEdit3.Value,SpinEdit4.Value);
  UpdateSpins;
end;

procedure TForm_Zones.CheckBox1Click(Sender: TObject);
begin
  if can then CurZone.DisableEnvironment:=CheckBox1.Checked;
end;

function TForm_Zones.CheckCollision(l, t, r, b: integer;Zone:DQE2_Zone=nil): boolean;
var
  a:integer;
  zn:DQE2_Zone;
begin
  result:=false;
  for a:=0 to world.Zones.Count-1 do
  begin
    zn:=DQE2_Zone(World.Zones[a]);
    if zn<>Zone then
      if(r>zn.Left)and(zn.Right>l)and(b>zn.Top)and(zn.Bottom>t)then
      begin
        Result:=true;
        break;
      end;
  end;
end;

procedure TForm_Zones.ColorBox1Change(Sender: TObject);
begin
  if can then CurZone.Color:=ColorBox1.Selected;
end;

procedure TForm_Zones.ComboBox2Change(Sender: TObject);
begin
  if not can then exit;
  UpdateObject;
  if ComboBox2.ItemIndex=-1 then CurZone:=nil
    else CurZone:=DQE2_Zone(world.Zones[ComboBox2.ItemIndex]);
  UpdateForm;
end;

procedure TForm_Zones.ComboBox3Change(Sender: TObject);
begin
  UpdatePreview;
end;

procedure TForm_Zones.ComboBox4Change(Sender: TObject);
begin
  if (CurZone<>nil) and can then
  begin
    if ComboBox4.ItemIndex=0 then
      CurZone.PreRenderZone:=nil
    else
      CurZone.PreRenderZone:=DQE2_Zone(World.Zones[ComboBox4.ItemIndex-1]);
  end;
end;

procedure TForm_Zones.FormCreate(Sender: TObject);
var
  f:TSearchRec;
  mus:TGPMusic;
begin
  Preview.SetupBitmap(true,clBlack32);sc:=2;
  ComboBox1.Clear;mus:=TGPMusic.Create;
  if (FindFirst(world.SharedDir+'\music\*.*',faAnyFile,f)=0)then
  repeat
    if(f.Name<>'.')and(f.Name<>'.')and((f.Attr and fadirectory)=0)then
      if mus.Open(world.SharedDir+'\music\'+f.Name) then
        ComboBox1.Items.Add(f.Name);
  until FindNext(f)<>0;
  mus.Free;
  if ComboBox1.Items.Count>0 then ComboBox1.ItemIndex:=0;
  SetLength(lng,44);
end;

procedure TForm_Zones.FormDestroy(Sender: TObject);
begin
  mus.free;
end;

procedure TForm_Zones.FormShow(Sender: TObject);
begin
  CurZone:=world.CurrentZone;
  Mode:=mmNone;SpeedButton1.Down:=False;
  UpdateForm;
end;

procedure TForm_Zones.Localize;
var
  n:integer;
begin
  LoadStringsFromIni(MainUnit.lang_ini,Name,lng);
  Caption:=lng[0];
  Label6.Caption:=lng[1];
  Label7.Caption:=lng[2];
  GroupBox4.Caption:=lng[3];
  GroupBox1.Caption:=lng[4];
  Label4.Caption:=lng[5];
  Label3.Caption:=lng[6];
  Label1.Caption:=lng[7];
  Label2.Caption:=lng[8];
  Label8.Caption:=lng[9];
  GroupBox2.Caption:=lng[10];
  CheckBox1.Caption:=lng[11];
  Button2.Caption:=lng[12];
  Label5.Caption:=lng[13];
  GroupBox3.Caption:=lng[14];
  Button4.Caption:=lng[15];
  Button5.Caption:=lng[16];
  GroupBox5.Caption:=lng[17];
  Label9.Caption:=lng[18];
  Label10.Caption:=lng[19];
  Label11.Caption:=lng[20];
  Label12.Caption:=lng[21];
  SpeedButton1.Caption:=lng[22];
  Button6.Caption:=lng[23];
  Button3.Caption:=lng[24];
  Button1.Caption:=lng[25];
  Button7.Caption:=lng[43];
  if ComboBox4.Items.Count>0 then
  begin
    n:=ComboBox4.ItemIndex;
    ComboBox4.Items[0]:=lng[40];
    ComboBox4.ItemIndex:=n;
  end;
end;

procedure TForm_Zones.PreviewMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
var
  l,t,r,b:integer;
  s:string;
begin
  if Mode=mmNew then
  begin
    if ssright in Shift then
    begin
      Mode:=mmNone;UpdatePreview;SpeedButton1.Down:=False;
    end
    else
    begin
      l:=world.ScreenWidth*round((NewRect.Left*sc+_x)/World.ScreenWidth);
      t:=world.ScreenHeight*round((NewRect.Top*sc+_y)/World.ScreenHeight);
      r:=l+world.ScreenWidth;
      b:=t+World.ScreenHeight;
      if CheckCollision(l,t,r,b) then exit;
      if InputQuery(lng[38],lng[39],s) then
      begin
        CurZone:=DQE2_Zone.Create(world.Zones,l,t,r,b);
        CurSel:=CurZone;
        SpeedButton1.Down:=false;
        Mode:=mmNone;
        CurZone.Name:=s;
        can:=false;
          ComboBox2.AddItem(CurZone.Name,CurZone);
          ComboBox4.AddItem(CurZone.Name,CurZone);
          ComboBox2.ItemIndex:=ComboBox2.Items.Count-1;
        can:=true;
        Form_Objects.UpdateZoneList;
      end;
    end;
  end;
  UpdateObject;CurZone:=CurSel;UpdateForm;
  if CurZone<>nil then
  begin
    mx:=x;my:=y;
  end;
end;

procedure TForm_Zones.PreviewMouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer; Layer: TCustomLayer);
var
  a:integer;
  p:TPoint;
  zn:DQE2_Zone;
  ox,oy:integer;
begin
  if(ssleft in shift)and(CurZone<>nil) then
  begin
    tmph:=round(CurZone.Height/sc);
    tmpw:=round(CurZone.Width/sc);
    Mode:=mmDrag;
  end;
  if Mode<>mmNone then
  begin
    ox:=x+ScrollBar1.Position;oy:=y+ScrollBar2.Position;
    ox:=round((ox/(World.ScreenWidth/sc))*(World.ScreenWidth/sc)-ScrollBar1.Position);
    oy:=round((oy/(World.ScreenHeight/sc))*(World.ScreenHeight/sc)-ScrollBar2.Position);
    NewRect:=rect(ox,oy,ox+tmpw,oy+tmph);
  end
  else
  begin
    CurSel:=nil;
    p:=Point(x,y);
    for a:=0 to World.Zones.Count-1 do
    begin
      zn:=DQE2_Zone(World.Zones[a]);
      if PtInRect(zn.TagRect,p) then
      begin
        CurSel:=zn;
        Break;
      end;
    end;
  end;
  UpdatePreview;
end;

procedure TForm_Zones.PreviewMouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
var
  l,t,r,b:integer;
begin
  if Mode=mmDrag then
  begin
    l:=world.ScreenWidth*round((NewRect.Left*sc+_x)/World.ScreenWidth);
    t:=world.ScreenHeight*round((NewRect.Top*sc+_y)/World.ScreenHeight);
    r:=l+CurZone.Width;
    b:=t+CurZone.Height;
    CurZone.SetNewPos(l,t,r,b);
    UpdateForm;
  end;
  Mode:=mmNone;
end;

procedure TForm_Zones.RedrawSelection;
begin
  if CurSel<>nil then preview.Bitmap.FrameRectS(CurSel.TagRect,clBlue32);
  if CurZone<>nil then preview.Bitmap.FrameRectS(CurZone.TagRect,clRed32);
  if Mode<>mmNone then preview.Bitmap.FrameRectS(NewRect,clWhite32);
end;

procedure TForm_Zones.ScrollBar1Change(Sender: TObject);
begin
  UpdatePreview;
end;

procedure TForm_Zones.ScrollBar2Change(Sender: TObject);
begin
  UpdatePreview;
end;

procedure TForm_Zones.SpeedButton1Click(Sender: TObject);
begin
  if SpeedButton1.Down then
  begin
    tmph:=round(World.ScreenHeight/sc);
    tmpw:=round(World.ScreenWidth/sc);
    Mode:=mmNew;
    CurZone:=nil;UpdateForm;
  end
  else
  begin
    Mode:=mmNone;
    UpdatePreview;
  end;
end;

procedure TForm_Zones.SpeedButton2Click(Sender: TObject);
var
  i:integer;
begin
  can:=false;
    CurZone.Name:=Edit1.Text;edit1.Text:=CurZone.Name;
    i:=ComboBox2.ItemIndex;
    ComboBox2.Items[i]:=CurZone.Name;ComboBox2.ItemIndex:=i;
    if CurZone=world.CurrentZone then
      Form_Game.UpdateZoneInfo(CurZone);
  can:=true;
end;

procedure TForm_Zones.SpinEdit5Change(Sender: TObject);
begin
  if CurZone<>nil then
    CurZone.BackSpeed:=SpinEdit5.Value;
end;

procedure TForm_Zones.SpinEdit6Change(Sender: TObject);
begin
  if CurZone<>nil then
    CurZone.BackOffsetX:=SpinEdit6.Value;
end;

procedure TForm_Zones.SpinEdit7Change(Sender: TObject);
begin
  if CurZone<>nil then
    CurZone.BackOffsetY:=SpinEdit7.Value;
end;

procedure TForm_Zones.UpdateForm;
var
  a:integer;
begin
  if CurZone<>nil then
  begin
    can:=false;
    UpdateSpins;
    CheckBox1.Checked:=CurZone.DisableEnvironment;
    edit1.Text:=CurZone.Name;
    ColorBox1.Selected:=CurZone.Color;
    ListBox1.Clear;
    for a:=0 to CurZone.StartScripts.Count-1 do
      Listbox1.Items.Add(DQE2_Script(CurZone.StartScripts[a]).Name);
    ComboBox2.ItemIndex:=CurZone.Index;
    if CurZone.PreRenderZone<>nil then
      ComboBox4.ItemIndex:=CurZone.PreRenderZone.Index+1
    else
      ComboBox4.ItemIndex:=0;
    SpinEdit5.Value:=CurZone.BackSpeed;
    SpinEdit6.Value:=CurZone.BackOffsetX;
    SpinEdit7.Value:=CurZone.BackOffsetY;
    GroupBox1.Visible:=true;GroupBox2.Visible:=true;
    GroupBox3.Visible:=true;GroupBox4.Visible:=true;
    GroupBox5.Visible:=true;
    can:=true;
  end
  else
  begin
    ComboBox2.ItemIndex:=-1;
    GroupBox1.Visible:=false;GroupBox2.Visible:=false;
    GroupBox3.Visible:=false;GroupBox4.Visible:=false;
    GroupBox5.Visible:=false;
  end;
end;

procedure TForm_Zones.UpdateList;
var
  a:integer;
  zn:DQE2_Zone;
begin
  CurZone:=world.CurrentZone;
  ComboBox2.Clear;ComboBox4.Clear;
  ComboBox4.AddItem(lng[40],nil);
  for a:=0 to world.Zones.Count-1 do
  begin
    zn:=DQE2_Zone(world.Zones[a]);
    ComboBox2.Additem(zn.Name,zn);
    ComboBox4.Additem(zn.Name,zn);
  end;
  ComboBox2.ItemIndex:=-1;
  UpdateForm;UpdatePreview;
end;

procedure TForm_Zones.UpdateObject;
begin
  if CurZone<>nil then
    CurZone.DisableEnvironment:=CheckBox1.Checked;
end;

procedure TForm_Zones.UpdatePreview;
var
  a:integer;
  zn:DQE2_Zone;
begin
  Preview.Bitmap.Clear;
  _x:=round(ScrollBar1.Position*sc);_y:=round(ScrollBar2.Position*sc);
  Sc:=2 shl ComboBox3.ItemIndex;
  stx:=round(World.ScreenWidth/sc);sty:=round(World.ScreenHeight/sc);
  ScrollBar1.Max:=round(SpinEdit1.MaxValue/sc);ScrollBar2.Max:=round(SpinEdit2.MaxValue/sc);
  ScrollBar1.Position:=round(_x/sc);ScrollBar2.Position:=round(_y/sc);
  VisRect:=rect(_x,_y,round(_x+((World.ScreenWidth/2)*sc)),round(_y+((World.ScreenHeight/2)*sc)));
  for a:=0 to world.Zones.Count-1 do
  begin
    zn:=DQE2_Zone(world.Zones[a]);
    zn.TagRect:=rect(
      round((zn.Left-_x)/sc),
      round((zn.Top-_y)/sc),
      round((zn.Right-_x)/sc),
      round((zn.Bottom-_y)/sc));
    if(VisRect.Right>zn.Left)and(zn.Right>VisRect.Left)and
    (VisRect.Bottom>zn.Top)and(zn.Bottom>VisRect.Top)then
    begin
      if zn.Thumbnail<>nil then
        Preview.Bitmap.Draw(zn.TagRect,zn.Thumbnail.Canvas.ClipRect,zn.Thumbnail.Canvas.Handle);
      preview.Bitmap.FillRectS(zn.TagRect,Color32(zn.Color));
      preview.Bitmap.FrameRectS(zn.TagRect,clYellow32);
    end;
  end;
  RedrawSelection;
end;

procedure TForm_Zones.UpdateSpins;
begin
  SpinEdit1.Value:=CurZone.Left;
  SpinEdit2.Value:=CurZone.Top;
  SpinEdit3.Value:=CurZone.Right;
  SpinEdit4.Value:=CurZone.Bottom;
  UpdatePreview;
end;

procedure TForm_Zones.Button1Click(Sender: TObject);
begin
  UpdateObject;close;
end;

end.
