{*************************************************************************}
{                                                                         }
{ GameUnit.pas - Preview 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 GameUnit;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls,dqe2_types, ExtCtrls,JvGIF,asphyredef, AsphyreTimers,
  AsphyreSubsc, AsphyreDevices, AsphyreFonts,alkatraz, Menus,ComCtrls, Spin;

type TPts4=array[0..3]of TPoint;

type
  TForm_Game = class(TForm)
    PopupMenu1: TPopupMenu;
    Name1: TMenuItem;
    N1: TMenuItem;
    N2: TMenuItem;
    N3: TMenuItem;
    N4: TMenuItem;
    N5: TMenuItem;
    Panel1: TPanel;
    StatusBar1: TStatusBar;
    N6: TMenuItem;
    N7: TMenuItem;
    N8: TMenuItem;
    N9: TMenuItem;
    N10: TMenuItem;
    N11: TMenuItem;
    N12: TMenuItem;
    N13: TMenuItem;
    UpgradetoEntity1: TMenuItem;
    DowngradetoObject1: TMenuItem;
    procedure OnStep;
    procedure UpdateINI(toini:boolean);
    procedure N10Click(Sender: TObject);
    procedure N12Click(Sender: TObject);
    procedure N11Click(Sender: TObject);
    procedure MoveToBuffer;
    procedure MoveFromBuffer;
    procedure N8Click(Sender: TObject);
    procedure N7Click(Sender: TObject);
    procedure OnZoneChange(NewZone:DQE2_Zone);
    procedure N5Click(Sender: TObject);
    procedure N4Click(Sender: TObject);
    procedure N3Click(Sender: TObject);
    procedure Name1Click(Sender: TObject);
    procedure N1Click(Sender: TObject);
    procedure DeletePickList;
    procedure GetObjRect(Obj:DQE2_Graphical;var p:TPts4);
    function GetGamePos(p:TPoint):TPoint;
    procedure ResetMouse;
    function InPickList(obj:DQE2_Graphical):integer;
    procedure PickIt(obj:DQE2_Graphical);
    procedure PostRender;
    procedure FormCreate(Sender: TObject);
    procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure FormMouseUp(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 FormClose(Sender: TObject; var Action: TCloseAction);
    procedure UpdateZoneInfo(NewZone:DQE2_Zone);
    procedure SortPickList;
    procedure Localize;
    procedure UpgradetoEntity1Click(Sender: TObject);
    procedure DowngradetoObject1Click(Sender: TObject);
    function GetMessageForPickList(v1,v2:integer):string;
    procedure OnVideoUpdate;
  private
    { Private declarations }
  public
    { Public declarations }
  end;

type  TMouseState=(msNone,msNew,msDrag,msTile);

type TBufRec=record
  Name:string;
  TheType:integer;
  State:DQE2_ObjectState;
  Sprite:DQE2_Sprite;
end;

var
  Form_Game: TForm_Game;
  an,w,h:integer;
  MState:TMouseState;
  CurDrag,tmpobj,CurSel:DQE2_Graphical;
  omx,omy,cmx,cmy,spd,_spd,obx,oby:integer;
  nowPressed:boolean;
  ang,dx,dy:single;
  Buf:array of TBufRec;
  _s:integer;
  form_done:boolean=false;
  LastX,LastY:integer;
  MousePos:TPoint;

const PiDiv180=pi/180;

implementation

uses ObjectUnit,Math, MainUnit, ScriptUnit, FontUnit, VarUnit, OptionsUnit,
  ItemUnit, ChooseUnit, ZoneUnit;

{$R *.dfm}

var lng:array of string;

procedure PtRotate(RotAng: Single; x, y: Integer; var Nx, Ny: Integer);
var
  SinVal,CosVal:Extended;
begin
  SinCos(RotAng * PIDiv180,SinVal,CosVal);
  Nx := trunc(x * CosVal - y * SinVal);
  Ny := trunc(y * CosVal + x * SinVal);
end;

procedure TForm_Game.FormCreate(Sender: TObject);
begin
  nowPressed:=false;
  if form_done then exit else form_done:=true;
  DQE2_World.Create(Form_Game.Panel1.Handle,true);
  if ParamCount>0 then
  begin
    CurFileName:=ParamStr(1);
    world.LoadFromFile(CurFileName,false,true);
  end;
  world.OnPostRender:=Form_Game.PostRender;
  world.OnStateChange:=Form_Main_DQE.OnStateChange;
  world.OnZoneChange:=Form_Game.OnZoneChange;
  SetLength(GameUnit.Buf,0);
  tmpobj:=DQE2_Object.Create(nil,nil);
  GameUnit.CurDrag:=tmpobj;
  World.OnStep:=OnStep;
  World.OnVideoUpdate:=OnVideoUpdate;
  SetLength(lng,35);
end;

procedure TForm_Game.PostRender;
var
  c1:Cardinal;
  a,n:integer;
  obj:DQE2_Graphical;
  p:TPts4;

procedure Quad(c:Cardinal);
begin
  World.Canvas.Line(p[0],p[1],c,c,fxNone);
  World.Canvas.Line(p[1],p[2],c,c,fxNone);
  World.Canvas.Line(p[2],p[3],c,c,fxNone);
  World.Canvas.Line(p[3],p[0],c,c,fxNone);
end;

begin
  if(CurDrag.Sprite<>nil)then
  begin
    if(MState<>msDrag)then
      if CurDrag is DQE2_Object then
        world.PutSprite(CurDrag as DQE2_Object)
      else
        world.PutSprite(CurDrag.Sprite.Images.Item[0],CurDrag.X,CurDrag.Y,CurDrag.Width,CurDrag.Height,0,0,0,CurDrag.Alpha,0,CurDrag.DrawFX,false,false);
  end;
  if CurSel<>nil then
  begin
    c1:=crgb1(255,0,0,255);
    GetObjRect(CurSel,p);Quad(c1);
  end;
  n:=PickList.Count-1;
  for a:=0 to n do
  begin
    obj:=DQE2_Graphical(PickList[a]);
    c1:=crgb1(128+trunc(64*cos(ang)),128+trunc(64*sin(ang)),0,255);
    GetObjRect(obj,p);Quad(c1);
  end;
  Form_Fonts.Timer1Timer(nil);
end;

procedure TForm_Game.FormMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  obj:DQE2_Graphical;
  s,p:boolean;
  to_obj,to_ent:boolean;
  a:integer;
  ss:string;
begin
  if world.State=wsPlay then world.Pause;
  if(ssleft in shift) then
  case MState of
    msNew,msTile:
    begin
      if CurDrag.Sprite=nil then exit;
      if(MState=msTile)then
      begin
        obj:=dqe2_object(world.Objects[world.Objects.count-1]);
        if(abs(CurDrag.X-obj.X)<obj.width)and
          (abs(CurDrag.Y-obj.Y)<obj.height)then exit;
      end;
      obj:=DQE2_Object.Create(world.Objects,world.CurrentZone);
      obj.Sprite:=CurDrag.Sprite;
      obj.Name:=CurDrag.Sprite.DefaultName;
      obj.X:=CurDrag.X;obj.Y:=CurDrag.Y;
      obj.Angle:=CurDrag.Angle;
      LastX:=X;LastY:=Y;
      if not Form_Objects.CheckBox2.Checked then
        CurDrag.Sprite:=nil
      else
        if Form_Objects.CheckBox4.Checked then
          CurDrag.Angle:=random(360);
      Form_Objects.UpdateList;
      Form_Objects.GenerateProperties;
      if Form_Objects.CheckBox2.Checked then
      begin
        MState:=msTile;
      end
      else MState:=msNone;
      UpdateZoneInfo(World.CurrentZone);
    end;
    msNone:
    begin
      if CurSel<>nil then
      begin
        MState:=msDrag;
        CurDrag:=CurSel;
        p:=(InPickList(CurSel)>=0);s:=ssshift in shift;
        if(not s)and(not p)then PickList.Clear;
        if s or(not p)then PickIt(CurSel);
        Form_Objects.GenerateProperties;
        omx:=x;omy:=y;
      end;
    end;
  end;
  if ssright in shift then
    case MState of
      msNew,msDrag,msTile:
        begin CurDrag.Sprite:=nil;MState:=msNone;PickList.Clear;exit;end;
      msNone:
      begin
        if Cursel<>nil then
        begin
          p:=(InPickList(CurSel)>=0);s:=ssshift in shift;
          if(not s)and(not p)then PickList.Clear;
          if s or(not p)then PickIt(CurSel);
        end;
        Form_Objects.GenerateProperties;
        if PickList.Count>0 then
        begin
          Name1.Enabled:=true;
          N1.Enabled:=true;
          N10.Enabled:=true;
          N11.Enabled:=true;
          N6.Enabled:=true;
          if PickList.Count=1 then
            Name1.Caption:='['+DQE2_Graphical(PickList[0]).Name+']'
          else
            Name1.Caption:=format(lng[12],[PickList.Count]);
          to_obj:=false;to_ent:=false;
          for a:=0 to PickList.Count-1 do
          begin
            ss:=DQE2_Dummy(PickList[a]).ClassName;
            if ss='DQE2_Object' then to_ent:=true else
            if ss='DQE2_Entity' then to_obj:=true;
          end;
          N13.Visible:=to_ent or to_obj;
          UpgradetoEntity1.Visible:=to_ent;
          DowngradetoObject1.Visible:=to_obj;
        end
        else
        begin
          Name1.Enabled:=false;
          N10.Enabled:=false;
          N11.Enabled:=false;
          N6.Enabled:=false;
          UpgradetoEntity1.Visible:=false;
          DowngradetoObject1.Visible:=false;
          N13.Visible:=false;
          Name1.Caption:='-=(xxx)=-';
          N1.Enabled:=false;
        end;
        PopupMenu1.Popup(Mouse.CursorPos.X,Mouse.CursorPos.Y);
      end;
    end;
end;

procedure TForm_Game.FormMouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  case MState of
    msDrag:
    begin
      CurDrag:=tmpobj;CurDrag.Sprite:=nil;
      MState:=msNone;ResetMouse;
      Form_Objects.GenerateProperties;
    end;
    msTile:MState:=msNew;
    else begin PickList.Clear;ResetMouse;form_objects.GenerateProperties;end;
  end;
end;

procedure TForm_Game.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
var
  obj:DQE2_Graphical;
  a:integer;
  mx,my:integer;
  it:DQE2_Item;

  function SelectIt(go:DQE2_Graphical):boolean;
  begin
    if go.Visible then
      if go.PixelCollision(x+World.OffsetX,y+World.OffsetY)then
      begin
        CurSel:=go;
        if World.KeyPressed[9] then
          if(go.ClassNameIs('DQE2_Object'))or(go.ClassNameIs('DQE2_Entity'))then
          begin
            a:=InPickList(go);
            if World.KeyPressed[160] or World.KeyPressed[161] then
              begin if a>=0 then begin PickList.Delete(a);Form_Objects.GenerateProperties;end;end
            else
              if(a<0)then begin PickIt(go);Form_Objects.GenerateProperties;end;
          end;
        result:=true;
      end else result:=false
    else result:=false;
   end;

begin
  if(ssleft in shift)then
    case MState of
      msTile:
      begin
        mx:=_spd*trunc(x/_spd);my:=_spd*trunc(y/_spd);
        if(LastX=mx)and(LastY=my)then exit;
        obj:=DQE2_Graphical(world.Objects[world.Objects.count-1]);
        if(abs(mx-obj.x)>obj.Width)or(abs(my-obj.y)>obj.Height)then
          FormMouseDown(nil,mbleft,[ssleft],mx,my);
      end;        
    end;
  case MState of
    msNone:
      begin
        if SelectIt(world.Player)then exit;
        for a:=World.Items.Count-1 downto 0 do
        begin
          it:=DQE2_Item(world.Items[a]);
          if(it.Zone=world.CurrentZone)and(it.InBagIndex<0)then
            if SelectIt(it)then exit;
        end;
        for a:=World.CurrentZone.Objects.Count-1 downto 0 do
          if SelectIt(DQE2_Object(world.CurrentZone.Objects[a]))then
            exit;
        cursel:=nil;
      end;
  end;
end;

procedure TForm_Game.PickIt(obj: DQE2_Graphical);
var
  a:integer;
begin
  a:=InPickList(obj);if a>=0 then PickList.Delete(a) else picklist.Add(obj);
end;

function TForm_Game.InPickList(obj: DQE2_Graphical): integer;
var
  a,n:integer;
begin
  n:=PickList.Count;result:=-1;
  for a:=0 to n-1 do
    if PickList[a]=obj then begin result:=a;exit;end;
end;

procedure TForm_Game.Localize;
begin
  LoadStringsFromIni(MainUnit.lang_ini,Name,lng);
  N2.Caption:=lng[1];
  N3.Caption:=lng[2];
  N4.Caption:=lng[3];
  N5.Caption:=lng[4];
  N6.Caption:=lng[5];
  N8.Caption:=lng[6];
  N7.Caption:=lng[7];
  N10.Caption:=lng[8];
  N11.Caption:=lng[9];
  N12.Caption:=lng[10];
  N1.Caption:=lng[11];
  UpgradetoEntity1.Caption:=lng[24];
  DowngradetoObject1.Caption:=lng[25];
  UpdateZoneInfo(World.CurrentZone);
end;

procedure TForm_Game.MoveFromBuffer;
var
  a,n:integer;
  obj:DQE2_Object;
  ent:DQE2_Entity;
  dx,dy:integer;
begin
  n:=Length(buf);
  if n>0 then
  begin
    PickList.Clear;
    dx:=buf[0].State.X;dy:=buf[0].State.y;
    for a:=1 to n-1 do
    begin
      if buf[a].State.X<dx then dx:=buf[a].State.x;
      if buf[a].State.y<dy then dy:=buf[a].State.y;
    end;
    dx:=_spd*trunc(dx/_spd);dy:=_spd*trunc(dy/_spd);
    for a:=0 to n-1 do
    begin
      if buf[a].TheType=1 then
      begin
        ent:=DQE2_Entity.Create(World.Objects,World.CurrentZone,nil);
        obj:=ent;
      end
      else
        obj:=DQE2_Object.Create(world.Objects,World.CurrentZone);
      obj.Sprite:=buf[a].Sprite;
      obj.Name:=buf[a].Name;
      obj.State:=buf[a].State;
      obj.LoadState;
      obj.x:=obj.x-dx+world.OffsetX;
      obj.y:=obj.y-dy+world.OffsetY;
      PickList.Add(obj);
    end;
    MState:=msDrag;
  end;
  Form_Objects.UpdateList;
  UpdateZoneInfo(World.CurrentZone);
end;

procedure TForm_Game.MoveToBuffer;
var
  a:Integer;
  obj:DQE2_Object;
begin
  if(PickList.Count>0)and(MState=msNone)then
  begin
    SortPickList;
    SetLength(Buf,PickList.Count);
    for a:=0 to PickList.Count-1 do
    begin
      obj:=DQE2_Object(PickList[a]);
      Buf[a].Name:=obj.Name;
      obj.SaveState;
      if obj.ClassNameIs('DQE2_Entity') then
        Buf[a].TheType:=1
      else
        buf[a].TheType:=0;
      buf[a].State:=obj.State;
      buf[a].Sprite:=obj.Sprite;
    end;
  end;
end;

procedure TForm_Game.N10Click(Sender: TObject);
var
  a:integer;
begin
  if PickList.Count>0 then
  begin
    MoveToBuffer;
    for a:=0 to PickList.Count-1 do
      if DQE2_Dummy(PickList[a]).ClassNameis('DQE2_Object') then
        DQE2_Object(PickList[a]).Destroy
      else
      if DQE2_Dummy(PickList[a]).ClassNameIs('DQE2_Entity') then
        DQE2_Entity(PickList[a]).Destroy;
    PickList.Clear;
    CurSel:=nil;
    world.PackObjects(world.CurrentZone);
    Form_Objects.GenerateProperties;
    UpdateZoneInfo(World.CurrentZone);
  end;
end;

procedure TForm_Game.N11Click(Sender: TObject);
begin
  MoveToBuffer;
end;

procedure TForm_Game.N12Click(Sender: TObject);
begin
  MoveFromBuffer;
end;

procedure TForm_Game.N1Click(Sender: TObject);
begin
  DeletePickList;
end;

procedure TForm_Game.N3Click(Sender: TObject);
var
  a:integer;
begin
  if world.CurrentZone.Objects.Count>0 then
  begin
    PickList.Clear;
    for a:=0 to world.CurrentZone.Objects.Count-1 do
      PickIt(DQE2_Graphical(world.CurrentZone.Objects[a]));
  end;
end;

procedure TForm_Game.N4Click(Sender: TObject);
var
  a:integer;
  obj:DQE2_Graphical;
begin
  if world.CurrentZone.Objects.Count>0 then
  begin
    PickList.Clear;
    for a:=0 to world.CurrentZone.Objects.Count-1 do
    begin
      obj:=DQE2_Graphical(world.CurrentZone.Objects[a]);
      if obj is DQE2_Object then
        if (obj as DQE2_Object).Marked then PickIt(obj);
    end;
  end;
end;

procedure TForm_Game.N5Click(Sender: TObject);
var
  a:integer;
begin
  if world.CurrentZone.Objects.Count>0 then
    for a:=0 to world.CurrentZone.Objects.Count-1 do
      PickIt(DQE2_Graphical(world.CurrentZone.Objects[a]));
end;

procedure TForm_Game.N7Click(Sender: TObject);
var
  a:integer;
begin
  if PickList.Count>0 then
  begin
    SortPickList;
    for a:=PickList.Count-1 downto 0 do
      if TObject(PickList[a]).ClassName='DQE2_Object' then
        DQE2_Object(PickList[a]).SendToBack
      else
        if TObject(PickList[a]).ClassName='DQE2_Item' then
        begin
          DQE2_Item(PickList[a]).SendToBack;
          form_items.UpdateList;
        end;
  end;
end;

procedure TForm_Game.N8Click(Sender: TObject);
var
  a:integer;
begin
  if PickList.Count>0 then
  begin
    SortPickList;
    for a:=0 to PickList.Count-1 do
      if TObject(PickList[a]).ClassName='DQE2_Object' then
        DQE2_Object(PickList[a]).BringToFront
      else
        if TObject(PickList[a]).ClassName='DQE2_Item' then
        begin
          DQE2_Item(PickList[a]).BringToFront;
          form_items.UpdateList;
        end;
  end;
end;

procedure TForm_Game.Name1Click(Sender: TObject);
var
  s:string;
  obj:DQE2_Graphical;
begin
  if PickList.Count=1 then
  begin
    obj:=DQE2_Graphical(PickList[0]);
    s:=obj.Name;
    if InputQuery(lng[13],lng[14],s) then
    begin
      obj.Name:=s;
      if obj.Name<>s then
        MessageDlgRus(lng[15],lng[16]+#13#10+obj.Name,MB_OK or MB_ICONINFORMATION);
    end;
    Form_Objects.NameChanged;
    Form_Objects.GenerateProperties;
  end;
end;

procedure TForm_Game.OnVideoUpdate;
begin
  ClientWidth:=World.ScreenWidth;
  ClientHeight:=World.ScreenHeight+Statusbar1.Height;
  Panel1.Height:=World.ScreenHeight;
  Panel1.Width:=World.ScreenWidth;
  //
  Form_Zones.SpinEdit1.MaxValue:=world.ScreenWidth*trunc(65535/world.ScreenWidth);
  Form_Zones.SpinEdit1.Increment:=world.ScreenWidth;
  Form_Zones.SpinEdit3.MinValue:=world.ScreenWidth;
  Form_Zones.SpinEdit3.MaxValue:=world.ScreenWidth*trunc(65535/world.ScreenWidth);
  Form_Zones.SpinEdit3.Increment:=world.ScreenWidth;
  Form_Zones.SpinEdit2.MaxValue:=world.ScreenHeight*trunc(65535/world.ScreenHeight);
  Form_Zones.SpinEdit2.Increment:=world.ScreenHeight;
  Form_Zones.SpinEdit4.MinValue:=world.ScreenHeight;
  Form_Zones.SpinEdit4.MaxValue:=world.ScreenHeight*trunc(65535/world.ScreenHeight);
  Form_Zones.SpinEdit4.Increment:=world.ScreenHeight;
end;

procedure TForm_Game.OnStep;
var
  obj:DQE2_Graphical;
  a:integer;
  dx,dy:integer;
  s:string;
begin
  MousePos:=GetGamePos(Mouse.CursorPos);
  if MState<>msNone then
  begin
    if(MState<>msDrag) then
    begin
      if World.KeyPressed[27] then
        begin CurDrag.Sprite:=nil;MState:=msNone;PickList.Clear;end
      else
        CurDrag.Step;
    end;
    if World.KeyPressed[164] or World.KeyPressed[165] then
      _spd:=1
    else
      _spd:=spd;
    dx:=_spd*trunc((MousePos.x-omx)/_spd);dy:=_spd*trunc((MousePos.y-omy)/_spd);
    omx:=omx+dx;omy:=omy+dy;
    for a:=0 to PickList.Count-1 do
    begin
      obj:=DQE2_Graphical(PickList[a]);
      obj.X:=obj.X+dx;obj.Y:=obj.Y+dy;
    end;
  end;
  ang:=ang+0.25;
  s:='('+inttostr(MousePos.X+world.OffsetX)+', '+inttostr(MousePos.y+world.OffsetY)+') ';
  try
  if CurSel<>nil then
  begin
    if CurSel.ClassName='DQE2_Object' then
      with DQE2_Object(CurSel) do
      begin
        s:=s+Format(lng[17],[Name,X,Y,Width,Height,Angle,Alpha,Sprite.ShortName]);
      end
    else
    if CurSel.ClassName='DQE2_Item' then
      with dqe2_item(CurSel) do
      begin
        s:=s+Format(lng[18],[Name,X,Y,Width,Height,Angle,Alpha,Sprite.ShortName]);;
      end
    else
    if CurSel.ClassName='DQE2_Player' then
      with DQE2_Player(CurSel) do
      begin
        s:=s+Format(lng[19],[Name,X,Y,Lifes,Energy]);
      end
    else
    if CurSel.ClassName='DQE2_Entity' then
      with DQE2_Entity(CurSel) do
      begin
        s:=s+Format(lng[34],[Name,EntityType.Name,X,Y,Width,Height,Angle,Alpha,Sprite.ShortName]);
      end
  end
  else
    if CurDrag<>nil then
      if CurDrag.Sprite<>nil then
    begin
      with DQE2_Object(CurDrag) do
      begin
        s:=s+Format(lng[17],[Name,X,Y,Width,Height,Angle,Alpha,Sprite.ShortName]);
      end;
    end;
  except
    s:='';
  end;
  StatusBar1.Panels[0].Text:=s;
end;

procedure TForm_Game.OnZoneChange(NewZone: DQE2_Zone);
begin
  UpdateZoneInfo(NewZone);
  CurDrag.Sprite:=nil;MState:=msNone;PickList.Clear;CurSel:=nil;
  Form_Objects.ComboBox2.ItemIndex:=NewZone.Index;
  Form_Objects.UpdateList;
end;

procedure TForm_Game.ResetMouse;
begin
  MState:=msNone;omx:=0;omy:=0;obx:=0;oby:=0;
end;

procedure TForm_Game.SortPickList;
var
  a,b:integer;
  x,y:TObject;
begin
  for a:=0 to PickList.Count-2 do
    for b:=a+1 to PickList.Count-1 do
    begin
      x:=TObject(PickList[a]);y:=TObject(PickList[b]);
      if x.ClassNameIs('DQE2_Object') and y.ClassNameIs('DQE2_Object') then
        if DQE2_Object(PickList[a]).InZoneIndex>DQE2_Object(PickList[b]).InZoneIndex then
          PickList.Exchange(a,b);
    end;
end;

function TForm_Game.GetGamePos(p: TPoint): TPoint;
begin
  result:=ScreenToClient(Mouse.CursorPos);
end;

function TForm_Game.GetMessageForPickList(v1, v2: integer): string;
const maxobjects=20;
var
  a:integer;
begin
  if PickList.Count=1 then
    result:=lng[v1]+#13#10
  else
    result:=format(lng[v2],[PickList.Count])+#13#10;
  if PickList.Count>maxobjects then
  begin
    for a:=0 to maxobjects-1 do
      result:=result+DQE2_Dummy(PickList[a]).Name+#13#10;
    result:=result+'...';
  end
  else
    for a:=0 to PickList.Count-1 do
      result:=result+DQE2_Dummy(PickList[a]).Name+#13#10;
end;

procedure TForm_Game.GetObjRect(Obj: DQE2_Graphical; var p:TPts4);
var
  a:integer;
  pt:TPoint4;
begin
  if obj.Angle=0 then
  begin
    p[0].x:=obj.X-World.OffsetX;p[0].y:=obj.Y-World.OffsetY;
    p[1].x:=p[0].x+obj.Width;p[1].y:=p[0].y;
    p[2].x:=p[1].x;p[2].y:=p[0].y+obj.Height;
    p[3].x:=p[0].x;p[3].y:=p[2].y;
  end
  else
  begin
    pt:=pRotate4(Point2(obj.x+obj.CenterX-World.OffsetX,obj.Y+obj.CenterY-World.OffsetY),Point2(obj.Width,obj.Height),Point2(obj.CenterX,obj.CenterY),degtorad(obj.Angle),1);
    for a:=0 to 3 do begin p[a].X:=trunc(pt[a].x);p[a].Y:=trunc(pt[a].y);end;
  end;
end;

procedure TForm_Game.UpdateINI(toini: boolean);
begin
  if toini then
  begin
    world.INI.WriteInteger('Editor.Form_Main','Form.Left',Form_Main_DQE.Left);
    world.INI.WriteInteger('Editor.Form_Main','Form.Top',Form_Main_DQE.Top);
    //
    world.INI.WriteInteger('Editor.Form_Game','Form.Left',Form_Game.Left);
    world.INI.WriteInteger('Editor.Form_Game','Form.Top',Form_Game.Top);
    world.INI.WriteBool('Editor.Form_Game','Form.Visible',Form_Game.Visible);
    //
    world.INI.WriteInteger('Editor.Form_Vars','Form.Left',Form_Vars.Left);
    world.INI.WriteInteger('Editor.Form_Vars','Form.Top',Form_Vars.Top);
    world.INI.WriteInteger('Editor.Form_Vars','Form.Height',Form_Vars.Height);
    world.INI.WriteInteger('Editor.Form_Vars','Form.Width',Form_Vars.Width);
    world.INI.WriteBool('Editor.Form_Vars','Form.Visible',Form_Vars.Visible);
    //
    world.INI.WriteInteger('Editor.Form_Objects','Form.Left',Form_Objects.Left);
    world.INI.WriteInteger('Editor.Form_Objects','Form.Top',Form_Objects.Top);
    world.INI.WriteInteger('Editor.Form_Objects','Form.Height',Form_Objects.Height);
    world.INI.WriteBool('Editor.Form_Objects','Form.Visible',Form_Objects.Visible);
    world.INI.WriteInteger('Editor.Form_Objects','PageControl.ActivePageIndex',Form_Objects.PageControl1.ActivePageIndex);
    world.INI.WriteInteger('Editor.Form_Objects','SpriteTabSheet.Display',Form_Objects.ComboBox4.ItemIndex);
    world.INI.WriteInteger('Editor.Form_Objects','SpriteTabSheet.Grid',Form_Objects.ComboBox5.ItemIndex);
    world.INI.WriteBool('Editor.Form_Objects','SpriteTabSheet.Tile',Form_Objects.CheckBox2.Checked);
    world.INI.WriteBool('Editor.Form_Objects','SpriteTabSheet.RandomAngle',Form_Objects.CheckBox4.Checked);
    world.INI.WriteBool('Editor.Form_Objects','PropertiesTabSheet.Zone',Form_Objects.CheckBox1.Checked);
    world.INI.WriteBool('Editor.Form_Objects','PropertiesTabSheet.Mark',Form_Objects.CheckBox3.Checked);
    //
    world.INI.WriteInteger('Editor.Options','FilesTabSheet.Backups',BackupCount);
    world.INI.WriteInteger('Editor.Options','FilesTabSheet.Recent',RecentCount);
    world.INI.WriteBool('Editor.Options','FilesTabSheet.AutoLoadLast',DoOpenLast);
    world.INI.WriteBool('Editor.Options','FilesTabSheet.SaveBPW',DoSaveBPW);
    //
    world.INI.WriteString('Editor.Localization','Language.ID',cur_lang);
  end
  else
  begin
    Form_Main_DQE.Left:=World.INI.ReadInteger('Editor.Form_Main','Form.Left',Form_Main_DQE.Left);
    Form_Main_DQE.Top:=World.INI.ReadInteger('Editor.Form_Main','Form.Top',Form_Main_DQE.Top);
    //
    Form_Game.Left:=World.INI.ReadInteger('Editor.Form_Game','Form.Left',Form_Game.Left);
    Form_Game.Top:=World.INI.ReadInteger('Editor.Form_Game','Form.Top',Form_Game.Top);
    Form_Game.Visible:=World.INI.ReadBool('Editor.Form_Game','Form.Visible',true);
    //
    Form_Vars.Top:=World.INI.ReadInteger('Editor.Form_Vars','Form.Top',Form_Vars.Top);
    Form_Vars.Left:=World.INI.ReadInteger('Editor.Form_Vars','Form.Left',Form_Vars.Left);
    Form_Vars.Height:=World.INI.ReadInteger('Editor.Form_Vars','Form.Height',Form_Vars.Height);
    Form_Vars.Width:=World.INI.ReadInteger('Editor.Form_Vars','Form.Width',Form_Vars.Width);
    Form_Vars.Visible:=World.INI.ReadBool('Editor.Form_Vars','Form.Visible',true);
    //
    Form_Objects.Left:=World.INI.ReadInteger('Editor.Form_Objects','Form.Left',Form_Objects.Left);
    Form_Objects.Top:=World.INI.ReadInteger('Editor.Form_Objects','Form.Top',Form_Objects.Top);
    Form_Objects.Height:=World.INI.ReadInteger('Editor.Form_Objects','Form.Height',Form_Objects.Height);
    Form_Objects.Visible:=World.INI.ReadBool('Editor.Form_Objects','Form.Visible',true);
    Form_Objects.PageControl1.ActivePageIndex:=world.INI.ReadInteger('Editor.Form_Objects','PageControl.ActivePageIndex',0);
    Form_Objects.ComboBox4.ItemIndex:=world.INI.ReadInteger('Editor.Form_Objects','SpriteTabSheet.Display',2);
    Form_Objects.ComboBox5.ItemIndex:=world.INI.ReadInteger('Editor.Form_Objects','SpriteTabSheet.Grid',4);
    Form_Objects.CheckBox2.Checked:=world.INI.ReadBool('Editor.Form_Objects','SpriteTabSheet.Tile',false);
    Form_Objects.CheckBox4.Checked:=world.INI.ReadBool('Editor.Form_Objects','SpriteTabSheet.RandomAngle',false);
    Form_Objects.CheckBox1.Checked:=world.INI.ReadBool('Editor.Form_Objects','PropertiesTabSheet.Zone',true);
    Form_Objects.CheckBox3.Checked:=world.INI.ReadBool('Editor.Form_Objects','PropertiesTabSheet.Mark',false);
    //
    BackupCount:=world.INI.ReadInteger('Editor.Options','FilesTabSheet.Backups',10);
    RecentCount:=world.INI.ReadInteger('Editor.Options','FilesTabSheet.Recent',10);
    DoOpenLast:=world.INI.ReadBool('Editor.Options','FilesTabSheet.AutoLoadLast',false);
    DoSaveBPW:=world.INI.ReadBool('Editor.Options','FilesTabSheet.SaveBPW',true);
    //
    tmp_lang:=world.INI.ReadString('Editor.Localization','Language.ID','en');
    Form_Objects.ComboBox5Change(nil);
    Form_Objects.ComboBox4Change(nil);
    Form_Objects.CheckBox3Click(nil);
    Form_Objects.CheckBox1Click(nil);
  end;
end;

procedure TForm_Game.UpdateZoneInfo(NewZone:DQE2_Zone);
begin
  Caption:=Format(lng[20],[NewZone.Name,
    (NewZone.Right-NewZone.Left)div World.ScreenWidth,
    (NewZone.Bottom-NewZone.Top)div World.ScreenHeight,
  NewZone.Objects.Count,NewZone.StartScripts.Count]);
end;

procedure TForm_Game.UpgradetoEntity1Click(Sender: TObject);
var
  et:DQE2_EntityType;
  a:integer;
begin
  if World.EntityTypes.Count=0 then
  begin
    MessageDlgRus(lng[33],lng[32],MB_OK or MB_ICONINFORMATION);
    exit;
  end;
  if MessageDlgRus(lng[26],GetMessageForPickList(27,28),MB_OKCANCEL or MB_ICONWARNING)=mrok then
  begin
    et:=DQE2_EntityType(Form_Choose.ShowIt(world.EntityTypes));
    if et<>nil then
    begin
      for a:=0 to PickList.Count-1 do
      begin
        if DQE2_Dummy(PickList[a]).ClassNameIs('DQE2_Object') then
          PickList[a]:=DQE2_Object(PickList[a]).UpgradeToEntity(et);
      end;
      CurSel:=nil;
      Form_Objects.GenerateProperties;
    end;
  end;
end;

procedure TForm_Game.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  case key of
    46:N1Click(nil);//Delete
    88:if(ssCtrl in Shift)and(MState=msNone)then N10Click(nil);//Ctrl-X
    67:if(ssCtrl in Shift)and(MState=msNone) then N11Click(nil);//Ctrl-C
    86:if(ssCtrl in Shift)and(MState=msNone) then N12Click(nil);//Ctrl-V
    65:if(ssCtrl in Shift)and(MState=msNone)then
          if(ssShift in Shift)then
            N4Click(nil)//Ctrl-Shift-A
          else
            N3Click(nil);//Ctrl-A
    73:if(ssCtrl in Shift)and(MState=msNone)then N5Click(nil);//Ctrl-I
    38:if(ssCtrl in Shift)and(ssAlt in Shift)and(MState=msNone)then N8Click(nil);//Ctrl-Alt-Up
    40:if(ssCtrl in Shift)and(ssAlt in Shift)and(MState=msNone)then N7Click(nil);//Ctrl-Alt-Down
    32:if PickList.Count>0 then // Space
          if MState=msNone then
            begin MState:=msDrag;omx:=MousePos.x;omy:=MousePos.y;end
          else
            MState:=msNone;
    27:if MState=msNone then PickList.Clear; // Escape
  end;
end;

procedure TForm_Game.DeletePickList;
var
  a:integer;
  obj:DQE2_Graphical;
begin
  if PickList.Count>0 then
  begin
    if MessageDlgRus(lng[23],GetMessageForPickList(21,22),MB_OKCANCEL or MB_ICONWARNING)=mrok then
    begin
      for a:=0 to PickList.Count-1 do
      begin
        obj:=DQE2_Graphical(PickList[a]);
        if obj<>nil then
          if obj.ClassName='DQE2_Object' then
            DQE2_Object(obj).Destroy
          else
            if obj.ClassName='DQE2_Entity' then
              DQE2_Entity(obj).Free;
      end;
      PickList.Clear;
      CurSel:=nil;
      world.PackObjects(world.CurrentZone);
      Form_Objects.GenerateProperties;
    end;
  end;
  Form_Objects.UpdateList;
  UpdateZoneInfo(World.CurrentZone);
end;

procedure TForm_Game.DowngradetoObject1Click(Sender: TObject);
var
  a:integer;
begin
  if MessageDlgRus(lng[29],GetMessageForPickList(30,31),MB_OKCANCEL or MB_ICONWARNING)=mrok then
  begin
    for a:=0 to PickList.Count-1 do
    begin
      if DQE2_Dummy(PickList[a]).ClassNameIs('DQE2_Entity') then
        PickList[a]:=DQE2_Entity(PickList[a]).DowngradeToObject;
    end;
    Form_Objects.GenerateProperties;
  end;
end;

procedure TForm_Game.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Form_Main_DQE.N7.Checked:=false;
end;

end.
