DEADSOFTWARE

get rid of "kastet" and "pulemet" in symbols
[d2df-editor.git] / src / editor / f_main.pas
index 292bcdafb9e7f3faf9e276b0e03ab08803bd2901..d40610abd027e358c38bd3916a6ba3f53c979e57 100644 (file)
@@ -8,30 +8,51 @@ uses
   LCLIntf, LCLType, SysUtils, Variants, Classes, Graphics,
   Controls, Forms, Dialogs, StdCtrls, Buttons,
   ComCtrls, ValEdit, Types, Menus, ExtCtrls,
   LCLIntf, LCLType, SysUtils, Variants, Classes, Graphics,
   Controls, Forms, Dialogs, StdCtrls, Buttons,
   ComCtrls, ValEdit, Types, Menus, ExtCtrls,
-  CheckLst, Grids, OpenGLContext, utils, UTF8Process;
+  CheckLst, Grids, OpenGLContext, Utils, UTF8Process;
 
 type
 
   { TMainForm }
 
   TMainForm = class(TForm)
 
 type
 
   { TMainForm }
 
   TMainForm = class(TForm)
-    lLoad: TLabel;
-  // Главное меню:
+    MapTestTimer: TTimer;
+    Splitter1: TSplitter;
+    Splitter2: TSplitter;
+    StatusBar: TStatusBar;
+    OpenDialog: TOpenDialog;
+    SaveDialog: TSaveDialog;
+    ColorDialog: TColorDialog;
+
+  // Menu:
     MainMenu: TMainMenu;
     MainMenu: TMainMenu;
-  // "Файл":
+    ImageList: TImageList;
+  // Apple menu:
+    miApple: TMenuItem;
+    miAppleAbout: TMenuItem;
+    miAppleLine0: TMenuItem;
+    miApplePref: TMenuItem;
+    miAppleLine1: TMenuItem;
+  // File menu:
     miMenuFile: TMenuItem;
     miNewMap: TMenuItem;
     miOpenMap: TMenuItem;
     miMenuFile: TMenuItem;
     miNewMap: TMenuItem;
     miOpenMap: TMenuItem;
+    miMacRecentSubMenu: TMenuItem;
+    miMacRecentEnd: TMenuItem;
+    miMacRecentClear: TMenuItem;
+    Separator1: TMenuItem;
     miSaveMap: TMenuItem;
     miSaveMapAs: TMenuItem;
     miOpenWadMap: TMenuItem;
     miLine1: TMenuItem;
     miSaveMap: TMenuItem;
     miSaveMapAs: TMenuItem;
     miOpenWadMap: TMenuItem;
     miLine1: TMenuItem;
+    miReopenMap: TMenuItem;
     miSaveMiniMap: TMenuItem;
     miDeleteMap: TMenuItem;
     miPackMap: TMenuItem;
     miSaveMiniMap: TMenuItem;
     miDeleteMap: TMenuItem;
     miPackMap: TMenuItem;
+    miWinRecentStart: TMenuItem;
+    miWinRecent: TMenuItem;
     miLine2: TMenuItem;
     miExit: TMenuItem;
     miLine2: TMenuItem;
     miExit: TMenuItem;
-  // "Правка":
+  // Edit menu:
     miMenuEdit: TMenuItem;
     miUndo: TMenuItem;
     miLine3: TMenuItem;
     miMenuEdit: TMenuItem;
     miUndo: TMenuItem;
     miLine3: TMenuItem;
@@ -41,14 +62,16 @@ type
     miLine4: TMenuItem;
     miSelectAll: TMenuItem;
     miLine5: TMenuItem;
     miLine4: TMenuItem;
     miSelectAll: TMenuItem;
     miLine5: TMenuItem;
-    miToFore: TMenuItem;
-    miToBack: TMenuItem;
-  // "Инструменты":
-    miMenuTools: TMenuItem;
     miSnapToGrid: TMenuItem;
     miSnapToGrid: TMenuItem;
-    miMiniMap: TMenuItem;
     miSwitchGrid: TMenuItem;
     miSwitchGrid: TMenuItem;
-    miShowEdges: TMenuItem;
+    Separator2: TMenuItem;
+    miToFore: TMenuItem;
+    miToBack: TMenuItem;
+    miLine6: TMenuItem;
+    miMapOptions: TMenuItem;
+    miOptions: TMenuItem;
+  // View menu:
+    miMenuView: TMenuItem;
     miLayers: TMenuItem;
     miLayer1: TMenuItem;
     miLayer2: TMenuItem;
     miLayers: TMenuItem;
     miLayer1: TMenuItem;
     miLayer2: TMenuItem;
@@ -59,31 +82,31 @@ type
     miLayer7: TMenuItem;
     miLayer8: TMenuItem;
     miLayer9: TMenuItem;
     miLayer7: TMenuItem;
     miLayer8: TMenuItem;
     miLayer9: TMenuItem;
-  // "Сервис":
+    miViewLine1: TMenuItem;
+    miMiniMap: TMenuItem;
+    miShowEdges: TMenuItem;
+    miViewLine2: TMenuItem;
+    miMapPreview: TMenuItem;
+  // Service menu:
     miMenuService: TMenuItem;
     miCheckMap: TMenuItem;
     miOptimmization: TMenuItem;
     miMenuService: TMenuItem;
     miCheckMap: TMenuItem;
     miOptimmization: TMenuItem;
-    miMapPreview: TMenuItem;
     miTestMap: TMenuItem;
     miTestMap: TMenuItem;
-  // "Настройка":
-    miMenuSettings: TMenuItem;
-    miMapOptions: TMenuItem;
-    miLine6: TMenuItem;
-    miOptions: TMenuItem;
-    miLine7: TMenuItem;
-    miMapTestSettings: TMenuItem;
-  // "Справка":
+  // Window menu:
+    miMenuWindow: TMenuItem;
+    miMacMinimize: TMenuItem;
+    miMacZoom: TMenuItem;
+  // Help Menu:
     miMenuHelp: TMenuItem;
     miAbout: TMenuItem;
     miMenuHelp: TMenuItem;
     miAbout: TMenuItem;
-  // Скрытый пункт меню для Ctrl+Tab:
-    miHidden1: TMenuItem;
+  // HIDDEN menu:
+    miMenuHidden: TMenuItem;
     minexttab: TMenuItem;
     minexttab: TMenuItem;
+    selectall1: TMenuItem;
 
 
-  // Панель инструментов:
+  // Toolbar:
+    ilToolbar: TImageList;
     MainToolBar: TToolBar;
     MainToolBar: TToolBar;
-    pbLoad: TProgressBar;
-    pLoadProgress: TPanel;
-    RenderPanel: TOpenGLControl;
     tbNewMap: TToolButton;
     tbOpenMap: TToolButton;
     tbSaveMap: TToolButton;
     tbNewMap: TToolButton;
     tbOpenMap: TToolButton;
     tbSaveMap: TToolButton;
@@ -92,12 +115,6 @@ type
     tbShowMap: TToolButton;
     tbLine2: TToolButton;
     tbShow: TToolButton;
     tbShowMap: TToolButton;
     tbLine2: TToolButton;
     tbShow: TToolButton;
-    tbLine3: TToolButton;
-    tbGridOn: TToolButton;
-    tbGrid: TToolButton;
-    tbLine4: TToolButton;
-    tbTestMap: TToolButton;
-  // Всплывающее меню для кнопки слоев:
     pmShow: TPopupMenu;
     miLayerP1: TMenuItem;
     miLayerP2: TMenuItem;
     pmShow: TPopupMenu;
     miLayerP1: TMenuItem;
     miLayerP2: TMenuItem;
@@ -108,31 +125,37 @@ type
     miLayerP7: TMenuItem;
     miLayerP8: TMenuItem;
     miLayerP9: TMenuItem;
     miLayerP7: TMenuItem;
     miLayerP8: TMenuItem;
     miLayerP9: TMenuItem;
-  // Всплывающее меню для кнопки теста карты:
-    pmMapTest: TPopupMenu;
-    miMapTestPMSet: TMenuItem;
+    tbLine3: TToolButton;
+    tbGridOn: TToolButton;
+    tbGrid: TToolButton;
+    tbLine4: TToolButton;
+    tbTestMap: TToolButton;
 
 
-  // Панель карты:
+  // Progress bar:
+    pLoadProgress: TPanel;
+    lLoad: TLabel;
+    pbLoad: TProgressBar;
+
+  // Map edit area:
     PanelMap: TPanel;
     PanelMap: TPanel;
-  // Полосы прокрутки:
+    RenderPanel: TOpenGLControl;
     sbHorizontal: TScrollBar;
     sbVertical: TScrollBar;
 
     sbHorizontal: TScrollBar;
     sbVertical: TScrollBar;
 
-  // Панель свойств:
+  // Object propertiy editor:
     PanelProps: TPanel;
     PanelProps: TPanel;
-  // Панель применения свойств:
     PanelPropApply: TPanel;
     bApplyProperty: TButton;
     PanelPropApply: TPanel;
     bApplyProperty: TButton;
-  // Редактор свойств объектов:
     vleObjectProperty: TValueListEditor;
 
     vleObjectProperty: TValueListEditor;
 
-  // Панель объектов - вкладки:
+  // Object palette:
     PanelObjs: TPanel;
     pcObjects: TPageControl;
     PanelObjs: TPanel;
     pcObjects: TPageControl;
-  // Вкладка "Панели":
+  // Panels Tab:
     tsPanels: TTabSheet;
     tsPanels: TTabSheet;
+    PanelPanelType: TPanel;
+    lbPanelType: TListBox;
     lbTextureList: TListBox;
     lbTextureList: TListBox;
-  // Панель настройки текстур:
     PanelTextures: TPanel;
     LabelTxW: TLabel;
     lTextureWidth: TLabel;
     PanelTextures: TPanel;
     LabelTxW: TLabel;
     lTextureWidth: TLabel;
@@ -142,43 +165,27 @@ type
     bbAddTexture: TBitBtn;
     bbRemoveTexture: TBitBtn;
     bClearTexture: TButton;
     bbAddTexture: TBitBtn;
     bbRemoveTexture: TBitBtn;
     bClearTexture: TButton;
-  // Панель типов панелей:
-    PanelPanelType: TPanel;
-    lbPanelType: TListBox;
-  // Вкладка "Предметы":
+  // Items Tab:
     tsItems: TTabSheet;
     lbItemList: TListBox;
     cbOnlyDM: TCheckBox;
     cbFall: TCheckBox;
     tsItems: TTabSheet;
     lbItemList: TListBox;
     cbOnlyDM: TCheckBox;
     cbFall: TCheckBox;
-  // Вкладка "Монстры":
+  // Monsters Tab:
     tsMonsters: TTabSheet;
     lbMonsterList: TListBox;
     rbMonsterLeft: TRadioButton;
     rbMonsterRight: TRadioButton;
     tsMonsters: TTabSheet;
     lbMonsterList: TListBox;
     rbMonsterLeft: TRadioButton;
     rbMonsterRight: TRadioButton;
-  // Вкладка "Области":
+  // Areas Tab:
     tsAreas: TTabSheet;
     lbAreasList: TListBox;
     rbAreaLeft: TRadioButton;
     rbAreaRight: TRadioButton;
     tsAreas: TTabSheet;
     lbAreasList: TListBox;
     rbAreaLeft: TRadioButton;
     rbAreaRight: TRadioButton;
-  // Вкладка "Триггеры":
+  // Triggers Tab:
     tsTriggers: TTabSheet;
     lbTriggersList: TListBox;
     clbActivationType: TCheckListBox;
     clbKeys: TCheckListBox;
 
     tsTriggers: TTabSheet;
     lbTriggersList: TListBox;
     clbActivationType: TCheckListBox;
     clbKeys: TCheckListBox;
 
-  // Остальные панели
-    Splitter1: TSplitter;
-    Splitter2: TSplitter;
-    StatusBar: TStatusBar;
-
-  // Специальные объекты:
-    ImageList: TImageList;
-    ilToolbar: TImageList;
-    OpenDialog: TOpenDialog;
-    SaveDialog: TSaveDialog;
-    selectall1: TMenuItem;
-    ColorDialog: TColorDialog;
-
     procedure aAboutExecute(Sender: TObject);
     procedure aCheckMapExecute(Sender: TObject);
     procedure aMoveToFore(Sender: TObject);
     procedure aAboutExecute(Sender: TObject);
     procedure aCheckMapExecute(Sender: TObject);
     procedure aMoveToFore(Sender: TObject);
@@ -207,15 +214,22 @@ type
     procedure FormDropFiles(Sender: TObject; const FileNames: array of String);
     procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
     procedure FormResize(Sender: TObject);
     procedure FormDropFiles(Sender: TObject; const FileNames: array of String);
     procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
     procedure FormResize(Sender: TObject);
+    procedure FormWindowStateChange(Sender: TObject);
+    procedure miRecentFileExecute(Sender: TObject);
+    procedure miMacRecentClearClick(Sender: TObject);
+    procedure miMacZoomClick(Sender: TObject);
     procedure lbTextureListClick(Sender: TObject);
     procedure lbTextureListDrawItem(Control: TWinControl; Index: Integer;
       ARect: TRect; State: TOwnerDrawState);
     procedure lbTextureListClick(Sender: TObject);
     procedure lbTextureListDrawItem(Control: TWinControl; Index: Integer;
       ARect: TRect; State: TOwnerDrawState);
+    procedure miMacMinimizeClick(Sender: TObject);
+    procedure miReopenMapClick(Sender: TObject);
     procedure RenderPanelMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
     procedure RenderPanelMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
     procedure RenderPanelMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
     procedure RenderPanelPaint(Sender: TObject);
     procedure RenderPanelResize(Sender: TObject);
     procedure Splitter1Moved(Sender: TObject);
     procedure RenderPanelMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
     procedure RenderPanelMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
     procedure RenderPanelMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
     procedure RenderPanelPaint(Sender: TObject);
     procedure RenderPanelResize(Sender: TObject);
     procedure Splitter1Moved(Sender: TObject);
+    procedure MapTestCheck(Sender: TObject);
     procedure vleObjectPropertyEditButtonClick(Sender: TObject);
     procedure vleObjectPropertyApply(Sender: TObject);
     procedure vleObjectPropertyGetPickList(Sender: TObject; const KeyName: String; Values: TStrings);
     procedure vleObjectPropertyEditButtonClick(Sender: TObject);
     procedure vleObjectPropertyApply(Sender: TObject);
     procedure vleObjectPropertyGetPickList(Sender: TObject; const KeyName: String; Values: TStrings);
@@ -241,8 +255,6 @@ type
     procedure miSaveMiniMapClick(Sender: TObject);
     procedure bClearTextureClick(Sender: TObject);
     procedure miPackMapClick(Sender: TObject);
     procedure miSaveMiniMapClick(Sender: TObject);
     procedure bClearTextureClick(Sender: TObject);
     procedure miPackMapClick(Sender: TObject);
-    procedure aRecentFileExecute(Sender: TObject);
-    procedure miMapTestSettingsClick(Sender: TObject);
     procedure miTestMapClick(Sender: TObject);
     procedure sbVerticalScroll(Sender: TObject; ScrollCode: TScrollCode;
       var ScrollPos: Integer);
     procedure miTestMapClick(Sender: TObject);
     procedure sbVerticalScroll(Sender: TObject; ScrollCode: TScrollCode;
       var ScrollPos: Integer);
@@ -259,11 +271,15 @@ type
     procedure FormKeyUp(Sender: TObject; var Key: Word;
       Shift: TShiftState);
   private
     procedure FormKeyUp(Sender: TObject; var Key: Word;
       Shift: TShiftState);
   private
+    LastDrawTime: UInt64;
     procedure Draw();
     procedure OnIdle(Sender: TObject; var Done: Boolean);
     procedure Draw();
     procedure OnIdle(Sender: TObject; var Done: Boolean);
+    procedure RefillRecentMenu (menu: TMenuItem; start: Integer; fmt: AnsiString);
   public
     procedure RefreshRecentMenu();
     procedure OpenMapFile(FileName: String);
   public
     procedure RefreshRecentMenu();
     procedure OpenMapFile(FileName: String);
+    function RenderMousePos(): TPoint;
+    procedure RecountSelectedObjects();
   end;
 
 const
   end;
 
 const
@@ -282,14 +298,14 @@ const
 
 var
   MainForm: TMainForm;
 
 var
   MainForm: TMainForm;
-  EditorDir: String;
+  StartMap: String;
   OpenedMap: String;
   OpenedWAD: String;
 
   DotColor: TColor;
   DotEnable: Boolean;
   OpenedMap: String;
   OpenedWAD: String;
 
   DotColor: TColor;
   DotEnable: Boolean;
-  DotStep: Byte;
-  DotStepOne, DotStepTwo: Byte;
+  DotStep: Word;
+  DotStepOne, DotStepTwo: Word;
   DotSize: Byte;
   DrawTexturePanel: Boolean;
   DrawPanelSize: Boolean;
   DotSize: Byte;
   DrawTexturePanel: Boolean;
   DrawPanelSize: Boolean;
@@ -309,11 +325,13 @@ var
   TestOptionsAllowExit: Boolean;
   TestOptionsWeaponStay: Boolean;
   TestOptionsMonstersDM: Boolean;
   TestOptionsAllowExit: Boolean;
   TestOptionsWeaponStay: Boolean;
   TestOptionsMonstersDM: Boolean;
-  TestD2dExe: String;
+  TestD2dExe, TestD2DArgs: String;
   TestMapOnce: Boolean;
 
   LayerEnabled: Array [LAYER_BACK..LAYER_TRIGGERS] of Boolean =
     (True, True, True, True, True, True, True, True, True);
   TestMapOnce: Boolean;
 
   LayerEnabled: Array [LAYER_BACK..LAYER_TRIGGERS] of Boolean =
     (True, True, True, True, True, True, True, True, True);
+  ContourEnabled: Array [LAYER_BACK..LAYER_TRIGGERS] of Boolean =
+    (False, False, False, False, False, False, False, False, False);
   PreviewMode: Byte = 0;
   gLanguage: String;
 
   PreviewMode: Byte = 0;
   gLanguage: String;
 
@@ -331,11 +349,11 @@ uses
   f_options, e_graphics, e_log, GL, Math,
   f_mapoptions, g_basic, f_about, f_mapoptimization,
   f_mapcheck, f_addresource_texture, g_textures,
   f_options, e_graphics, e_log, GL, Math,
   f_mapoptions, g_basic, f_about, f_mapoptimization,
   f_mapcheck, f_addresource_texture, g_textures,
-  f_activationtype, f_keys,
+  f_activationtype, f_keys, wadreader, fileutil,
   MAPREADER, f_selectmap, f_savemap, WADEDITOR, WADSTRUCT, MAPDEF,
   g_map, f_saveminimap, f_addresource, CONFIG, f_packmap,
   MAPREADER, f_selectmap, f_savemap, WADEDITOR, WADSTRUCT, MAPDEF,
   g_map, f_saveminimap, f_addresource, CONFIG, f_packmap,
-  f_addresource_sound, f_maptest, f_choosetype,
-  g_language, f_selectlang, ClipBrd;
+  f_addresource_sound, f_choosetype,
+  g_language, ClipBrd, g_options;
 
 const
   UNDO_DELETE_PANEL   = 1;
 
 const
   UNDO_DELETE_PANEL   = 1;
@@ -385,14 +403,13 @@ const
   SELECTFLAG_SHOTPANEL  = 7;
   SELECTFLAG_SELECTED   = 8;
 
   SELECTFLAG_SHOTPANEL  = 7;
   SELECTFLAG_SELECTED   = 8;
 
-  RECENT_FILES_MENU_START = 11;
+  RECENT_FILES_MENU_START = 12;
 
   CLIPBOARD_SIG         = 'DF:ED';
 
 type
   TUndoRec = record
 
   CLIPBOARD_SIG         = 'DF:ED';
 
 type
   TUndoRec = record
-    UndoType: Byte;
-    case Byte of
+    case UndoType: Byte of
       UNDO_DELETE_PANEL:   (Panel: ^TPanel);
       UNDO_DELETE_ITEM:    (Item: TItem);
       UNDO_DELETE_AREA:    (Area: TArea);
       UNDO_DELETE_PANEL:   (Panel: ^TPanel);
       UNDO_DELETE_ITEM:    (Item: TItem);
       UNDO_DELETE_AREA:    (Area: TArea);
@@ -413,9 +430,8 @@ type
   end;
 
   TCopyRec = record
   end;
 
   TCopyRec = record
-    ObjectType: Byte;
     ID: Cardinal;
     ID: Cardinal;
-    case Byte of
+    case ObjectType: Byte of
       OBJECT_PANEL: (Panel: ^TPanel);
       OBJECT_ITEM: (Item: TItem);
       OBJECT_AREA: (Area: TArea);
       OBJECT_PANEL: (Panel: ^TPanel);
       OBJECT_ITEM: (Item: TItem);
       OBJECT_AREA: (Area: TArea);
@@ -436,9 +452,10 @@ var
   LastMovePoint: Types.TPoint;
   MouseLDown: Boolean;
   MouseRDown: Boolean;
   LastMovePoint: Types.TPoint;
   MouseLDown: Boolean;
   MouseRDown: Boolean;
+  MouseMDown: Boolean;
   MouseLDownPos: Types.TPoint;
   MouseRDownPos: Types.TPoint;
   MouseLDownPos: Types.TPoint;
   MouseRDownPos: Types.TPoint;
-  WASDOffset: TPoint;
+  MouseMDownPos: Types.TPoint;
 
   SelectFlag: Byte = SELECTFLAG_NONE;
   MouseAction: Byte = MOUSEACTION_NONE;
 
   SelectFlag: Byte = SELECTFLAG_NONE;
   MouseAction: Byte = MOUSEACTION_NONE;
@@ -450,6 +467,8 @@ var
 
   UndoBuffer: Array of Array of TUndoRec = nil;
 
 
   UndoBuffer: Array of Array of TUndoRec = nil;
 
+  MapTestProcess: TProcessUTF8;
+  MapTestFile: String;
 
 {$R *.lfm}
 
 
 {$R *.lfm}
 
@@ -689,10 +708,10 @@ begin
   begin
     ScaleSz := 16 div Scale;
   // Размер видимой части карты:
   begin
     ScaleSz := 16 div Scale;
   // Размер видимой части карты:
-    rx := min(Normalize16(Width), Normalize16(gMapInfo.Width)) div 2;
-    ry := min(Normalize16(Height), Normalize16(gMapInfo.Height)) div 2;
+    rx := Min(Normalize16(Width), Normalize16(gMapInfo.Width)) div 2;
+    ry := Min(Normalize16(Height), Normalize16(gMapInfo.Height)) div 2;
   // Место клика на мини-карте:
   // Место клика на мини-карте:
-    MapOffset.X := X - (Width-max(gMapInfo.Width div ScaleSz, 1)-1);
+    MapOffset.X := X - (Width - Max(gMapInfo.Width div ScaleSz, 1) - 1);
     MapOffset.Y := Y - 1;
   // Это же место на "большой" карте:
     MapOffset.X := MapOffset.X * ScaleSz;
     MapOffset.Y := Y - 1;
   // Это же место на "большой" карте:
     MapOffset.X := MapOffset.X * ScaleSz;
@@ -701,17 +720,11 @@ begin
     MapOffset.X := MapOffset.X - rx;
     MapOffset.Y := MapOffset.Y - ry;
   // Выход за границы:
     MapOffset.X := MapOffset.X - rx;
     MapOffset.Y := MapOffset.Y - ry;
   // Выход за границы:
-    if MapOffset.X < 0 then
-      MapOffset.X := 0;
-    if MapOffset.Y < 0 then
-      MapOffset.Y := 0;
-    if MapOffset.X > MainForm.sbHorizontal.Max then
-      MapOffset.X := MainForm.sbHorizontal.Max;
-    if MapOffset.Y > MainForm.sbVertical.Max then
-      MapOffset.Y := MainForm.sbVertical.Max;
+    MapOffset.X := EnsureRange(MapOffset.X, MainForm.sbHorizontal.Min, MainForm.sbHorizontal.Max);
+    MapOffset.Y := EnsureRange(MapOffset.Y, MainForm.sbVertical.Min, MainForm.sbVertical.Max);
   // Кратно 16:
   // Кратно 16:
-    MapOffset.X := Normalize16(MapOffset.X);
-    MapOffset.Y := Normalize16(MapOffset.Y);
+  //  MapOffset.X := Normalize16(MapOffset.X);
+  //  MapOffset.Y := Normalize16(MapOffset.Y);
   end;
 
   MainForm.sbHorizontal.Position := MapOffset.X;
   end;
 
   MainForm.sbHorizontal.Position := MapOffset.X;
@@ -736,6 +749,7 @@ var
   str: String;
 begin
   MainForm.vleObjectProperty.Strings.Clear();
   str: String;
 begin
   MainForm.vleObjectProperty.Strings.Clear();
+  MainForm.RecountSelectedObjects();
 
 // Отображаем свойства если выделен только один объект:
   if SelectedObjectCount() <> 1 then
 
 // Отображаем свойства если выделен только один объект:
   if SelectedObjectCount() <> 1 then
@@ -746,7 +760,7 @@ begin
     Exit;
 
   with MainForm.vleObjectProperty do
     Exit;
 
   with MainForm.vleObjectProperty do
-    with ItemProps[InsertRow(_lc[I_PROP_ID], IntToStr(SelectedObjects[_id].ID), True)] do
+    with ItemProps[InsertRow(MsgPropId, IntToStr(SelectedObjects[_id].ID), True)] do
     begin
       EditStyle := esSimple;
       ReadOnly := True;
     begin
       EditStyle := esSimple;
       ReadOnly := True;
@@ -758,31 +772,31 @@ begin
         with MainForm.vleObjectProperty,
              gPanels[SelectedObjects[_id].ID] do
         begin
         with MainForm.vleObjectProperty,
              gPanels[SelectedObjects[_id].ID] do
         begin
-          with ItemProps[InsertRow(_lc[I_PROP_X], IntToStr(X), True)] do
+          with ItemProps[InsertRow(MsgPropX, IntToStr(X), True)] do
           begin
             EditStyle := esSimple;
             MaxLength := 5;
           end;
 
           begin
             EditStyle := esSimple;
             MaxLength := 5;
           end;
 
-          with ItemProps[InsertRow(_lc[I_PROP_Y], IntToStr(Y), True)] do
+          with ItemProps[InsertRow(MsgPropY, IntToStr(Y), True)] do
           begin
             EditStyle := esSimple;
             MaxLength := 5;
           end;
 
           begin
             EditStyle := esSimple;
             MaxLength := 5;
           end;
 
-          with ItemProps[InsertRow(_lc[I_PROP_WIDTH], IntToStr(Width), True)] do
+          with ItemProps[InsertRow(MsgPropWidth, IntToStr(Width), True)] do
           begin
             EditStyle := esSimple;
             MaxLength := 5;
           end;
 
           begin
             EditStyle := esSimple;
             MaxLength := 5;
           end;
 
-          with ItemProps[InsertRow(_lc[I_PROP_HEIGHT], IntToStr(Height), True)] do
+          with ItemProps[InsertRow(MsgPropHeight, IntToStr(Height), True)] do
           begin
             EditStyle := esSimple;
             MaxLength := 5;
           end;
 
           begin
             EditStyle := esSimple;
             MaxLength := 5;
           end;
 
-          with ItemProps[InsertRow(_lc[I_PROP_PANEL_TYPE], GetPanelName(PanelType), True)] do
+          with ItemProps[InsertRow(MsgPropPanelType, GetPanelName(PanelType), True)] do
           begin
             EditStyle := esEllipsis;
             ReadOnly := True;
           begin
             EditStyle := esEllipsis;
             ReadOnly := True;
@@ -790,7 +804,7 @@ begin
 
           if IsTexturedPanel(PanelType) then
           begin // Может быть текстура
 
           if IsTexturedPanel(PanelType) then
           begin // Может быть текстура
-            with ItemProps[InsertRow(_lc[I_PROP_PANEL_TEX], TextureName, True)] do
+            with ItemProps[InsertRow(MsgPropPanelTex, TextureName, True)] do
             begin
               EditStyle := esEllipsis;
               ReadOnly := True;
             begin
               EditStyle := esEllipsis;
               ReadOnly := True;
@@ -798,13 +812,13 @@ begin
 
             if TextureName <> '' then
             begin // Есть текстура
 
             if TextureName <> '' then
             begin // Есть текстура
-              with ItemProps[InsertRow(_lc[I_PROP_PANEL_ALPHA], IntToStr(Alpha), True)] do
+              with ItemProps[InsertRow(MsgPropPanelAlpha, IntToStr(Alpha), True)] do
               begin
                 EditStyle := esSimple;
                 MaxLength := 3;
               end;
 
               begin
                 EditStyle := esSimple;
                 MaxLength := 3;
               end;
 
-              with ItemProps[InsertRow(_lc[I_PROP_PANEL_BLEND], BoolNames[Blending], True)] do
+              with ItemProps[InsertRow(MsgPropPanelBlend, BoolNames[Blending], True)] do
               begin
                 EditStyle := esPickList;
                 ReadOnly := True;
               begin
                 EditStyle := esPickList;
                 ReadOnly := True;
@@ -819,25 +833,25 @@ begin
         with MainForm.vleObjectProperty,
              gItems[SelectedObjects[_id].ID] do
         begin
         with MainForm.vleObjectProperty,
              gItems[SelectedObjects[_id].ID] do
         begin
-          with ItemProps[InsertRow(_lc[I_PROP_X], IntToStr(X), True)] do
+          with ItemProps[InsertRow(MsgPropX, IntToStr(X), True)] do
           begin
             EditStyle := esSimple;
             MaxLength := 5;
           end;
 
           begin
             EditStyle := esSimple;
             MaxLength := 5;
           end;
 
-          with ItemProps[InsertRow(_lc[I_PROP_Y], IntToStr(Y), True)] do
+          with ItemProps[InsertRow(MsgPropY, IntToStr(Y), True)] do
           begin
             EditStyle := esSimple;
             MaxLength := 5;
           end;
 
           begin
             EditStyle := esSimple;
             MaxLength := 5;
           end;
 
-          with ItemProps[InsertRow(_lc[I_PROP_DM_ONLY], BoolNames[OnlyDM], True)] do
+          with ItemProps[InsertRow(MsgPropDmOnly, BoolNames[OnlyDM], True)] do
           begin
             EditStyle := esPickList;
             ReadOnly := True;
           end;
 
           begin
             EditStyle := esPickList;
             ReadOnly := True;
           end;
 
-          with ItemProps[InsertRow(_lc[I_PROP_ITEM_FALLS], BoolNames[Fall], True)] do
+          with ItemProps[InsertRow(MsgPropItemFalls, BoolNames[Fall], True)] do
           begin
             EditStyle := esPickList;
             ReadOnly := True;
           begin
             EditStyle := esPickList;
             ReadOnly := True;
@@ -850,19 +864,19 @@ begin
         with MainForm.vleObjectProperty,
              gMonsters[SelectedObjects[_id].ID] do
         begin
         with MainForm.vleObjectProperty,
              gMonsters[SelectedObjects[_id].ID] do
         begin
-          with ItemProps[InsertRow(_lc[I_PROP_X], IntToStr(X), True)] do
+          with ItemProps[InsertRow(MsgPropX, IntToStr(X), True)] do
           begin
             EditStyle := esSimple;
             MaxLength := 5;
           end;
 
           begin
             EditStyle := esSimple;
             MaxLength := 5;
           end;
 
-          with ItemProps[InsertRow(_lc[I_PROP_Y], IntToStr(Y), True)] do
+          with ItemProps[InsertRow(MsgPropY, IntToStr(Y), True)] do
           begin
             EditStyle := esSimple;
             MaxLength := 5;
           end;
 
           begin
             EditStyle := esSimple;
             MaxLength := 5;
           end;
 
-          with ItemProps[InsertRow(_lc[I_PROP_DIRECTION], DirNames[Direction], True)] do
+          with ItemProps[InsertRow(MsgPropDirection, DirNames[Direction], True)] do
           begin
             EditStyle := esPickList;
             ReadOnly := True;
           begin
             EditStyle := esPickList;
             ReadOnly := True;
@@ -875,19 +889,19 @@ begin
         with MainForm.vleObjectProperty,
              gAreas[SelectedObjects[_id].ID] do
         begin
         with MainForm.vleObjectProperty,
              gAreas[SelectedObjects[_id].ID] do
         begin
-          with ItemProps[InsertRow(_lc[I_PROP_X], IntToStr(X), True)] do
+          with ItemProps[InsertRow(MsgPropX, IntToStr(X), True)] do
           begin
             EditStyle := esSimple;
             MaxLength := 5;
           end;
 
           begin
             EditStyle := esSimple;
             MaxLength := 5;
           end;
 
-          with ItemProps[InsertRow(_lc[I_PROP_Y], IntToStr(Y), True)] do
+          with ItemProps[InsertRow(MsgPropY, IntToStr(Y), True)] do
           begin
             EditStyle := esSimple;
             MaxLength := 5;
           end;
 
           begin
             EditStyle := esSimple;
             MaxLength := 5;
           end;
 
-          with ItemProps[InsertRow(_lc[I_PROP_DIRECTION], DirNames[Direction], True)] do
+          with ItemProps[InsertRow(MsgPropDirection, DirNames[Direction], True)] do
           begin
             EditStyle := esPickList;
             ReadOnly := True;
           begin
             EditStyle := esPickList;
             ReadOnly := True;
@@ -900,55 +914,55 @@ begin
         with MainForm.vleObjectProperty,
              gTriggers[SelectedObjects[_id].ID] do
         begin
         with MainForm.vleObjectProperty,
              gTriggers[SelectedObjects[_id].ID] do
         begin
-          with ItemProps[InsertRow(_lc[I_PROP_TR_TYPE], GetTriggerName(TriggerType), True)] do
+          with ItemProps[InsertRow(MsgPropTrType, GetTriggerName(TriggerType), True)] do
           begin
             EditStyle := esSimple;
             ReadOnly := True;
           end;
 
           begin
             EditStyle := esSimple;
             ReadOnly := True;
           end;
 
-          with ItemProps[InsertRow(_lc[I_PROP_X], IntToStr(X), True)] do
+          with ItemProps[InsertRow(MsgPropX, IntToStr(X), True)] do
           begin
             EditStyle := esSimple;
             MaxLength := 5;
           end;
 
           begin
             EditStyle := esSimple;
             MaxLength := 5;
           end;
 
-          with ItemProps[InsertRow(_lc[I_PROP_Y], IntToStr(Y), True)] do
+          with ItemProps[InsertRow(MsgPropY, IntToStr(Y), True)] do
           begin
             EditStyle := esSimple;
             MaxLength := 5;
           end;
 
           begin
             EditStyle := esSimple;
             MaxLength := 5;
           end;
 
-          with ItemProps[InsertRow(_lc[I_PROP_WIDTH], IntToStr(Width), True)] do
+          with ItemProps[InsertRow(MsgPropWidth, IntToStr(Width), True)] do
           begin
             EditStyle := esSimple;
             MaxLength := 5;
           end;
 
           begin
             EditStyle := esSimple;
             MaxLength := 5;
           end;
 
-          with ItemProps[InsertRow(_lc[I_PROP_HEIGHT], IntToStr(Height), True)] do
+          with ItemProps[InsertRow(MsgPropHeight, IntToStr(Height), True)] do
           begin
             EditStyle := esSimple;
             MaxLength := 5;
           end;
 
           begin
             EditStyle := esSimple;
             MaxLength := 5;
           end;
 
-          with ItemProps[InsertRow(_lc[I_PROP_TR_ENABLED], BoolNames[Enabled], True)] do
+          with ItemProps[InsertRow(MsgPropTrEnabled, BoolNames[Enabled], True)] do
           begin
             EditStyle := esPickList;
             ReadOnly := True;
           end;
 
           begin
             EditStyle := esPickList;
             ReadOnly := True;
           end;
 
-          with ItemProps[InsertRow(_lc[I_PROP_TR_TEXTURE_PANEL], IntToStr(TexturePanel), True)] do
+          with ItemProps[InsertRow(MsgPropTrTexturePanel, IntToStr(TexturePanel), True)] do
           begin
             EditStyle := esEllipsis;
             ReadOnly := True;
           end;
 
           begin
             EditStyle := esEllipsis;
             ReadOnly := True;
           end;
 
-          with ItemProps[InsertRow(_lc[I_PROP_TR_ACTIVATION], ActivateToStr(ActivateType), True)] do
+          with ItemProps[InsertRow(MsgPropTrActivation, ActivateToStr(ActivateType), True)] do
           begin
             EditStyle := esEllipsis;
             ReadOnly := True;
           end;
 
           begin
             EditStyle := esEllipsis;
             ReadOnly := True;
           end;
 
-          with ItemProps[InsertRow(_lc[I_PROP_TR_KEYS], KeyToStr(Key), True)] do
+          with ItemProps[InsertRow(MsgPropTrKeys, KeyToStr(Key), True)] do
           begin
             EditStyle := esEllipsis;
             ReadOnly := True;
           begin
             EditStyle := esEllipsis;
             ReadOnly := True;
@@ -958,7 +972,7 @@ begin
             TRIGGER_EXIT:
               begin
                 str := win2utf(Data.MapName);
             TRIGGER_EXIT:
               begin
                 str := win2utf(Data.MapName);
-                with ItemProps[InsertRow(_lc[I_PROP_TR_NEXT_MAP], str, True)] do
+                with ItemProps[InsertRow(MsgPropTrNextMap, str, True)] do
                 begin
                   EditStyle := esEllipsis;
                   ReadOnly := True;
                 begin
                   EditStyle := esEllipsis;
                   ReadOnly := True;
@@ -967,25 +981,25 @@ begin
 
             TRIGGER_TELEPORT:
               begin
 
             TRIGGER_TELEPORT:
               begin
-                with ItemProps[InsertRow(_lc[I_PROP_TR_TELEPORT_TO], Format('(%d:%d)', [Data.TargetPoint.X, Data.TargetPoint.Y]), True)] do
+                with ItemProps[InsertRow(MsgPropTrTeleportTo, Format('(%d:%d)', [Data.TargetPoint.X, Data.TargetPoint.Y]), True)] do
                 begin
                   EditStyle := esEllipsis;
                   ReadOnly := True;
                 end;
 
                 begin
                   EditStyle := esEllipsis;
                   ReadOnly := True;
                 end;
 
-                with ItemProps[InsertRow(_lc[I_PROP_TR_D2D], BoolNames[Data.d2d_teleport], True)] do
+                with ItemProps[InsertRow(MsgPropTrD2d, BoolNames[Data.d2d_teleport], True)] do
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
                 end;
 
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
                 end;
 
-                with ItemProps[InsertRow(_lc[I_PROP_TR_TELEPORT_SILENT], BoolNames[Data.silent_teleport], True)] do
+                with ItemProps[InsertRow(MsgPropTrTeleportSilent, BoolNames[Data.silent_teleport], True)] do
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
                 end;
 
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
                 end;
 
-                with ItemProps[InsertRow(_lc[I_PROP_TR_TELEPORT_DIR], DirNamesAdv[Data.TlpDir], True)] do
+                with ItemProps[InsertRow(MsgPropTrTeleportDir, DirNamesAdv[Data.TlpDir], True)] do
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
@@ -995,19 +1009,19 @@ begin
             TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR,
             TRIGGER_DOOR, TRIGGER_DOOR5:
               begin
             TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR,
             TRIGGER_DOOR, TRIGGER_DOOR5:
               begin
-                with ItemProps[InsertRow(_lc[I_PROP_TR_DOOR_PANEL], IntToStr(Data.PanelID), True)] do
+                with ItemProps[InsertRow(MsgPropTrDoorPanel, IntToStr(Data.PanelID), True)] do
                 begin
                   EditStyle := esEllipsis;
                   ReadOnly := True;
                 end;
 
                 begin
                   EditStyle := esEllipsis;
                   ReadOnly := True;
                 end;
 
-                with ItemProps[InsertRow(_lc[I_PROP_TR_SILENT], BoolNames[Data.NoSound], True)] do
+                with ItemProps[InsertRow(MsgPropTrSilent, BoolNames[Data.NoSound], True)] do
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
                 end;
 
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
                 end;
 
-                with ItemProps[InsertRow(_lc[I_PROP_TR_D2D], BoolNames[Data.d2d_doors], True)] do
+                with ItemProps[InsertRow(MsgPropTrD2d, BoolNames[Data.d2d_doors], True)] do
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
@@ -1016,19 +1030,19 @@ begin
 
             TRIGGER_CLOSETRAP, TRIGGER_TRAP:
               begin
 
             TRIGGER_CLOSETRAP, TRIGGER_TRAP:
               begin
-                with ItemProps[InsertRow(_lc[I_PROP_TR_TRAP_PANEL], IntToStr(Data.PanelID), True)] do
+                with ItemProps[InsertRow(MsgPropTrTrapPanel, IntToStr(Data.PanelID), True)] do
                 begin
                   EditStyle := esEllipsis;
                   ReadOnly := True;
                 end;
 
                 begin
                   EditStyle := esEllipsis;
                   ReadOnly := True;
                 end;
 
-                with ItemProps[InsertRow(_lc[I_PROP_TR_SILENT], BoolNames[Data.NoSound], True)] do
+                with ItemProps[InsertRow(MsgPropTrSilent, BoolNames[Data.NoSound], True)] do
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
                 end;
 
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
                 end;
 
-                with ItemProps[InsertRow(_lc[I_PROP_TR_D2D], BoolNames[Data.d2d_doors], True)] do
+                with ItemProps[InsertRow(MsgPropTrD2d, BoolNames[Data.d2d_doors], True)] do
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
@@ -1038,33 +1052,33 @@ begin
             TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF,
             TRIGGER_ONOFF:
               begin
             TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF,
             TRIGGER_ONOFF:
               begin
-                with ItemProps[InsertRow(_lc[I_PROP_TR_EX_AREA],
+                with ItemProps[InsertRow(MsgPropTrExArea,
                                  Format('(%d:%d %d:%d)', [Data.tX, Data.tY, Data.tWidth, Data.tHeight]), True)] do
                 begin
                   EditStyle := esEllipsis;
                   ReadOnly := True;
                 end;
 
                                  Format('(%d:%d %d:%d)', [Data.tX, Data.tY, Data.tWidth, Data.tHeight]), True)] do
                 begin
                   EditStyle := esEllipsis;
                   ReadOnly := True;
                 end;
 
-                with ItemProps[InsertRow(_lc[I_PROP_TR_EX_DELAY], IntToStr(Data.Wait), True)] do
+                with ItemProps[InsertRow(MsgPropTrExDelay, IntToStr(Data.Wait), True)] do
                 begin
                   EditStyle := esSimple;
                   MaxLength := 5;
                 end;
 
                 begin
                   EditStyle := esSimple;
                   MaxLength := 5;
                 end;
 
-                with ItemProps[InsertRow(_lc[I_PROP_TR_EX_COUNT], IntToStr(Data.Count), True)] do
+                with ItemProps[InsertRow(MsgPropTrExCount, IntToStr(Data.Count), True)] do
                 begin
                   EditStyle := esSimple;
                   MaxLength := 5;
                 end;
 
                 begin
                   EditStyle := esSimple;
                   MaxLength := 5;
                 end;
 
-                with ItemProps[InsertRow(_lc[I_PROP_TR_EX_MONSTER], IntToStr(Data.MonsterID-1), True)] do
+                with ItemProps[InsertRow(MsgPropTrExMonster, IntToStr(Data.MonsterID-1), True)] do
                 begin
                   EditStyle := esEllipsis;
                   ReadOnly := True;
                 end;
 
                 if TriggerType = TRIGGER_PRESS then
                 begin
                   EditStyle := esEllipsis;
                   ReadOnly := True;
                 end;
 
                 if TriggerType = TRIGGER_PRESS then
-                  with ItemProps[InsertRow(_lc[I_PROP_TR_EX_RANDOM], BoolNames[Data.ExtRandom], True)] do
+                  with ItemProps[InsertRow(MsgPropTrExRandom, BoolNames[Data.ExtRandom], True)] do
                   begin
                     EditStyle := esPickList;
                     ReadOnly := True;
                   begin
                     EditStyle := esPickList;
                     ReadOnly := True;
@@ -1076,19 +1090,19 @@ begin
 
             TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
               begin
 
             TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
               begin
-                with ItemProps[InsertRow(_lc[I_PROP_TR_LIFT_PANEL], IntToStr(Data.PanelID), True)] do
+                with ItemProps[InsertRow(MsgPropTrLiftPanel, IntToStr(Data.PanelID), True)] do
                 begin
                   EditStyle := esEllipsis;
                   ReadOnly := True;
                 end;
 
                 begin
                   EditStyle := esEllipsis;
                   ReadOnly := True;
                 end;
 
-                with ItemProps[InsertRow(_lc[I_PROP_TR_SILENT], BoolNames[Data.NoSound], True)] do
+                with ItemProps[InsertRow(MsgPropTrSilent, BoolNames[Data.NoSound], True)] do
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
                 end;
 
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
                 end;
 
-                with ItemProps[InsertRow(_lc[I_PROP_TR_D2D], BoolNames[Data.d2d_doors], True)] do
+                with ItemProps[InsertRow(MsgPropTrD2d, BoolNames[Data.d2d_doors], True)] do
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
@@ -1097,13 +1111,13 @@ begin
 
             TRIGGER_TEXTURE:
               begin
 
             TRIGGER_TEXTURE:
               begin
-                with ItemProps[InsertRow(_lc[I_PROP_TR_TEXTURE_ONCE], BoolNames[Data.ActivateOnce], True)] do
+                with ItemProps[InsertRow(MsgPropTrTextureOnce, BoolNames[Data.ActivateOnce], True)] do
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
                 end;
 
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
                 end;
 
-                with ItemProps[InsertRow(_lc[I_PROP_TR_TEXTURE_ANIM_ONCE], BoolNames[Data.AnimOnce], True)] do
+                with ItemProps[InsertRow(MsgPropTrTextureAnimOnce, BoolNames[Data.AnimOnce], True)] do
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
@@ -1113,37 +1127,37 @@ begin
             TRIGGER_SOUND:
               begin
                 str := win2utf(Data.SoundName);
             TRIGGER_SOUND:
               begin
                 str := win2utf(Data.SoundName);
-                with ItemProps[InsertRow(_lc[I_PROP_TR_SOUND_NAME], str, True)] do
+                with ItemProps[InsertRow(MsgPropTrSoundName, str, True)] do
                 begin
                   EditStyle := esEllipsis;
                   ReadOnly := True;
                 end;
 
                 begin
                   EditStyle := esEllipsis;
                   ReadOnly := True;
                 end;
 
-                with ItemProps[InsertRow(_lc[I_PROP_TR_SOUND_VOLUME], IntToStr(Data.Volume), True)] do
+                with ItemProps[InsertRow(MsgPropTrSoundVolume, IntToStr(Data.Volume), True)] do
                 begin
                   EditStyle := esSimple;
                   MaxLength := 3;
                 end;
 
                 begin
                   EditStyle := esSimple;
                   MaxLength := 3;
                 end;
 
-                with ItemProps[InsertRow(_lc[I_PROP_TR_SOUND_PAN], IntToStr(Data.Pan), True)] do
+                with ItemProps[InsertRow(MsgPropTrSoundPan, IntToStr(Data.Pan), True)] do
                 begin
                   EditStyle := esSimple;
                   MaxLength := 3;
                 end;
 
                 begin
                   EditStyle := esSimple;
                   MaxLength := 3;
                 end;
 
-                with ItemProps[InsertRow(_lc[I_PROP_TR_SOUND_COUNT], IntToStr(Data.PlayCount), True)] do
+                with ItemProps[InsertRow(MsgPropTrSoundCount, IntToStr(Data.PlayCount), True)] do
                 begin
                   EditStyle := esSimple;
                   MaxLength := 3;
                 end;
 
                 begin
                   EditStyle := esSimple;
                   MaxLength := 3;
                 end;
 
-                with ItemProps[InsertRow(_lc[I_PROP_TR_SOUND_LOCAL], BoolNames[Data.Local], True)] do
+                with ItemProps[InsertRow(MsgPropTrSoundLocal, BoolNames[Data.Local], True)] do
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
                 end;
 
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
                 end;
 
-                with ItemProps[InsertRow(_lc[I_PROP_TR_SOUND_SWITCH], BoolNames[Data.SoundSwitch], True)] do
+                with ItemProps[InsertRow(MsgPropTrSoundSwitch, BoolNames[Data.SoundSwitch], True)] do
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
@@ -1152,70 +1166,70 @@ begin
 
             TRIGGER_SPAWNMONSTER:
               begin
 
             TRIGGER_SPAWNMONSTER:
               begin
-                with ItemProps[InsertRow(_lc[I_PROP_TR_MONSTER_TYPE], MonsterToStr(Data.MonType), True)] do
+                with ItemProps[InsertRow(MsgPropTrMonsterType, MonsterToStr(Data.MonType), True)] do
                 begin
                   EditStyle := esEllipsis;
                   ReadOnly := True;
                 end;
 
                 begin
                   EditStyle := esEllipsis;
                   ReadOnly := True;
                 end;
 
-                with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_TO],
+                with ItemProps[InsertRow(MsgPropTrSpawnTo,
                                  Format('(%d:%d)', [Data.MonPos.X, Data.MonPos.Y]), True)] do
                 begin
                   EditStyle := esEllipsis;
                   ReadOnly := True;
                 end;
 
                                  Format('(%d:%d)', [Data.MonPos.X, Data.MonPos.Y]), True)] do
                 begin
                   EditStyle := esEllipsis;
                   ReadOnly := True;
                 end;
 
-                with ItemProps[InsertRow(_lc[I_PROP_DIRECTION], DirNames[TDirection(Data.MonDir)], True)] do
+                with ItemProps[InsertRow(MsgPropDirection, DirNames[TDirection(Data.MonDir)], True)] do
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
                 end;
 
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
                 end;
 
-                with ItemProps[InsertRow(_lc[I_PROP_TR_HEALTH], IntToStr(Data.MonHealth), True)] do
+                with ItemProps[InsertRow(MsgPropTrHealth, IntToStr(Data.MonHealth), True)] do
                 begin
                   EditStyle := esSimple;
                   MaxLength := 5;
                 end;
 
                 begin
                   EditStyle := esSimple;
                   MaxLength := 5;
                 end;
 
-                with ItemProps[InsertRow(_lc[I_PROP_TR_MONSTER_ACTIVE], BoolNames[Data.MonActive], True)] do
+                with ItemProps[InsertRow(MsgPropTrMonsterActive, BoolNames[Data.MonActive], True)] do
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
                 end;
 
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
                 end;
 
-                with ItemProps[InsertRow(_lc[I_PROP_TR_COUNT], IntToStr(Data.MonCount), True)] do
+                with ItemProps[InsertRow(MsgPropTrCount, IntToStr(Data.MonCount), True)] do
                 begin
                   EditStyle := esSimple;
                   MaxLength := 5;
                 end;
 
                 begin
                   EditStyle := esSimple;
                   MaxLength := 5;
                 end;
 
-                with ItemProps[InsertRow(_lc[I_PROP_TR_FX_TYPE], EffectToStr(Data.MonEffect), True)] do
+                with ItemProps[InsertRow(MsgPropTrFxType, EffectToStr(Data.MonEffect), True)] do
                 begin
                   EditStyle := esEllipsis;
                   ReadOnly := True;
                 end;
 
                 begin
                   EditStyle := esEllipsis;
                   ReadOnly := True;
                 end;
 
-                with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_MAX], IntToStr(Data.MonMax), True)] do
+                with ItemProps[InsertRow(MsgPropTrSpawnMax, IntToStr(Data.MonMax), True)] do
                 begin
                   EditStyle := esSimple;
                   MaxLength := 5;
                 end;
 
                 begin
                   EditStyle := esSimple;
                   MaxLength := 5;
                 end;
 
-                with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_DELAY], IntToStr(Data.MonDelay), True)] do
+                with ItemProps[InsertRow(MsgPropTrSpawnDelay, IntToStr(Data.MonDelay), True)] do
                 begin
                   EditStyle := esSimple;
                   MaxLength := 5;
                 end;
 
                 case Data.MonBehav of
                 begin
                   EditStyle := esSimple;
                   MaxLength := 5;
                 end;
 
                 case Data.MonBehav of
-                  1: str := _lc[I_PROP_TR_MONSTER_BEHAVIOUR_1];
-                  2: str := _lc[I_PROP_TR_MONSTER_BEHAVIOUR_2];
-                  3: str := _lc[I_PROP_TR_MONSTER_BEHAVIOUR_3];
-                  4: str := _lc[I_PROP_TR_MONSTER_BEHAVIOUR_4];
-                  5: str := _lc[I_PROP_TR_MONSTER_BEHAVIOUR_5];
-                  else str := _lc[I_PROP_TR_MONSTER_BEHAVIOUR_0];
+                  1: str := MsgPropTrMonsterBehaviour1;
+                  2: str := MsgPropTrMonsterBehaviour2;
+                  3: str := MsgPropTrMonsterBehaviour3;
+                  4: str := MsgPropTrMonsterBehaviour4;
+                  5: str := MsgPropTrMonsterBehaviour5;
+                  else str := MsgPropTrMonsterBehaviour0;
                 end;
                 end;
-                with ItemProps[InsertRow(_lc[I_PROP_TR_MONSTER_BEHAVIOUR], str, True)] do
+                with ItemProps[InsertRow(MsgPropTrMonsterBehaviour, str, True)] do
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
@@ -1224,50 +1238,50 @@ begin
 
             TRIGGER_SPAWNITEM:
               begin
 
             TRIGGER_SPAWNITEM:
               begin
-                with ItemProps[InsertRow(_lc[I_PROP_TR_ITEM_TYPE], ItemToStr(Data.ItemType), True)] do
+                with ItemProps[InsertRow(MsgPropTrItemType, ItemToStr(Data.ItemType), True)] do
                 begin
                   EditStyle := esEllipsis;
                   ReadOnly := True;
                 end;
 
                 begin
                   EditStyle := esEllipsis;
                   ReadOnly := True;
                 end;
 
-                with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_TO],
+                with ItemProps[InsertRow(MsgPropTrSpawnTo,
                                  Format('(%d:%d)', [Data.ItemPos.X, Data.ItemPos.Y]), True)] do
                 begin
                   EditStyle := esEllipsis;
                   ReadOnly := True;
                 end;
 
                                  Format('(%d:%d)', [Data.ItemPos.X, Data.ItemPos.Y]), True)] do
                 begin
                   EditStyle := esEllipsis;
                   ReadOnly := True;
                 end;
 
-                with ItemProps[InsertRow(_lc[I_PROP_DM_ONLY], BoolNames[Data.ItemOnlyDM], True)] do
+                with ItemProps[InsertRow(MsgPropDmOnly, BoolNames[Data.ItemOnlyDM], True)] do
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
                 end;
 
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
                 end;
 
-                with ItemProps[InsertRow(_lc[I_PROP_ITEM_FALLS], BoolNames[Data.ItemFalls], True)] do
+                with ItemProps[InsertRow(MsgPropItemFalls, BoolNames[Data.ItemFalls], True)] do
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
                 end;
 
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
                 end;
 
-                with ItemProps[InsertRow(_lc[I_PROP_TR_COUNT], IntToStr(Data.ItemCount), True)] do
+                with ItemProps[InsertRow(MsgPropTrCount, IntToStr(Data.ItemCount), True)] do
                 begin
                   EditStyle := esSimple;
                   MaxLength := 5;
                 end;
 
                 begin
                   EditStyle := esSimple;
                   MaxLength := 5;
                 end;
 
-                with ItemProps[InsertRow(_lc[I_PROP_TR_FX_TYPE], EffectToStr(Data.ItemEffect), True)] do
+                with ItemProps[InsertRow(MsgPropTrFxType, EffectToStr(Data.ItemEffect), True)] do
                 begin
                   EditStyle := esEllipsis;
                   ReadOnly := True;
                 end;
 
                 begin
                   EditStyle := esEllipsis;
                   ReadOnly := True;
                 end;
 
-                with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_MAX], IntToStr(Data.ItemMax), True)] do
+                with ItemProps[InsertRow(MsgPropTrSpawnMax, IntToStr(Data.ItemMax), True)] do
                 begin
                   EditStyle := esSimple;
                   MaxLength := 5;
                 end;
 
                 begin
                   EditStyle := esSimple;
                   MaxLength := 5;
                 end;
 
-                with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_DELAY], IntToStr(Data.ItemDelay), True)] do
+                with ItemProps[InsertRow(MsgPropTrSpawnDelay, IntToStr(Data.ItemDelay), True)] do
                 begin
                   EditStyle := esSimple;
                   MaxLength := 5;
                 begin
                   EditStyle := esSimple;
                   MaxLength := 5;
@@ -1277,18 +1291,18 @@ begin
            TRIGGER_MUSIC:
              begin
                str := win2utf(Data.MusicName);
            TRIGGER_MUSIC:
              begin
                str := win2utf(Data.MusicName);
-               with ItemProps[InsertRow(_lc[I_PROP_TR_MUSIC_NAME], str, True)] do
+               with ItemProps[InsertRow(MsgPropTrMusicName, str, True)] do
                begin
                  EditStyle := esEllipsis;
                  ReadOnly := True;
                end;
 
                if Data.MusicAction = 1 then
                begin
                  EditStyle := esEllipsis;
                  ReadOnly := True;
                end;
 
                if Data.MusicAction = 1 then
-                 str := _lc[I_PROP_TR_MUSIC_ON]
+                 str := MsgPropTrMusicOn
                else
                else
-                 str := _lc[I_PROP_TR_MUSIC_OFF];
+                 str := MsgPropTrMusicOff;
 
 
-               with ItemProps[InsertRow(_lc[I_PROP_TR_MUSIC_ACT], str, True)] do
+               with ItemProps[InsertRow(MsgPropTrMusicAct, str, True)] do
                begin
                  EditStyle := esPickList;
                  ReadOnly := True;
                begin
                  EditStyle := esPickList;
                  ReadOnly := True;
@@ -1297,17 +1311,17 @@ begin
 
             TRIGGER_PUSH:
               begin
 
             TRIGGER_PUSH:
               begin
-                with ItemProps[InsertRow(_lc[I_PROP_TR_PUSH_ANGLE], IntToStr(Data.PushAngle), True)] do
+                with ItemProps[InsertRow(MsgPropTrPushAngle, IntToStr(Data.PushAngle), True)] do
                 begin
                   EditStyle := esSimple;
                   MaxLength := 4;
                 end;
                 begin
                   EditStyle := esSimple;
                   MaxLength := 4;
                 end;
-                with ItemProps[InsertRow(_lc[I_PROP_TR_PUSH_FORCE], IntToStr(Data.PushForce), True)] do
+                with ItemProps[InsertRow(MsgPropTrPushForce, IntToStr(Data.PushForce), True)] do
                 begin
                   EditStyle := esSimple;
                   MaxLength := 4;
                 end;
                 begin
                   EditStyle := esSimple;
                   MaxLength := 4;
                 end;
-                with ItemProps[InsertRow(_lc[I_PROP_TR_PUSH_RESET], BoolNames[Data.ResetVel], True)] do
+                with ItemProps[InsertRow(MsgPropTrPushReset, BoolNames[Data.ResetVel], True)] do
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
@@ -1317,38 +1331,38 @@ begin
             TRIGGER_SCORE:
               begin
                 case Data.ScoreAction of
             TRIGGER_SCORE:
               begin
                 case Data.ScoreAction of
-                  1: str := _lc[I_PROP_TR_SCORE_ACT_1];
-                  2: str := _lc[I_PROP_TR_SCORE_ACT_2];
-                  3: str := _lc[I_PROP_TR_SCORE_ACT_3];
-                  else str := _lc[I_PROP_TR_SCORE_ACT_0];
+                  1: str := MsgPropTrScoreAct1;
+                  2: str := MsgPropTrScoreAct2;
+                  3: str := MsgPropTrScoreAct3;
+                  else str := MsgPropTrScoreAct0;
                 end;
                 end;
-                with ItemProps[InsertRow(_lc[I_PROP_TR_SCORE_ACT], str, True)] do
+                with ItemProps[InsertRow(MsgPropTrScoreAct, str, True)] do
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
                 end;
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
                 end;
-                with ItemProps[InsertRow(_lc[I_PROP_TR_COUNT], IntToStr(Data.ScoreCount), True)] do
+                with ItemProps[InsertRow(MsgPropTrCount, IntToStr(Data.ScoreCount), True)] do
                 begin
                   EditStyle := esSimple;
                   MaxLength := 3;
                 end;
                 case Data.ScoreTeam of
                 begin
                   EditStyle := esSimple;
                   MaxLength := 3;
                 end;
                 case Data.ScoreTeam of
-                  1: str := _lc[I_PROP_TR_SCORE_TEAM_1];
-                  2: str := _lc[I_PROP_TR_SCORE_TEAM_2];
-                  3: str := _lc[I_PROP_TR_SCORE_TEAM_3];
-                  else str := _lc[I_PROP_TR_SCORE_TEAM_0];
+                  1: str := MsgPropTrScoreTeam1;
+                  2: str := MsgPropTrScoreTeam2;
+                  3: str := MsgPropTrScoreTeam3;
+                  else str := MsgPropTrScoreTeam0;
                 end;
                 end;
-                with ItemProps[InsertRow(_lc[I_PROP_TR_SCORE_TEAM], str, True)] do
+                with ItemProps[InsertRow(MsgPropTrScoreTeam, str, True)] do
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
                 end;
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
                 end;
-                with ItemProps[InsertRow(_lc[I_PROP_TR_SCORE_CON], BoolNames[Data.ScoreCon], True)] do
+                with ItemProps[InsertRow(MsgPropTrScoreCon, BoolNames[Data.ScoreCon], True)] do
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
                 end;
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
                 end;
-                with ItemProps[InsertRow(_lc[I_PROP_TR_SCORE_MSG], BoolNames[Data.ScoreMsg], True)] do
+                with ItemProps[InsertRow(MsgPropTrScoreMsg, BoolNames[Data.ScoreMsg], True)] do
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
@@ -1358,34 +1372,34 @@ begin
             TRIGGER_MESSAGE:
               begin
                 case Data.MessageKind of
             TRIGGER_MESSAGE:
               begin
                 case Data.MessageKind of
-                  1: str := _lc[I_PROP_TR_MESSAGE_KIND_1];
-                  else str := _lc[I_PROP_TR_MESSAGE_KIND_0];
+                  1: str := MsgPropTrMessageKind1;
+                  else str := MsgPropTrMessageKind0;
                 end;
                 end;
-                with ItemProps[InsertRow(_lc[I_PROP_TR_MESSAGE_KIND], str, True)] do
+                with ItemProps[InsertRow(MsgPropTrMessageKind, str, True)] do
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
                 end;
                 case Data.MessageSendTo of
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
                 end;
                 case Data.MessageSendTo of
-                  1: str := _lc[I_PROP_TR_MESSAGE_TO_1];
-                  2: str := _lc[I_PROP_TR_MESSAGE_TO_2];
-                  3: str := _lc[I_PROP_TR_MESSAGE_TO_3];
-                  4: str := _lc[I_PROP_TR_MESSAGE_TO_4];
-                  5: str := _lc[I_PROP_TR_MESSAGE_TO_5];
-                  else str := _lc[I_PROP_TR_MESSAGE_TO_0];
+                  1: str := MsgPropTrMessageTo1;
+                  2: str := MsgPropTrMessageTo2;
+                  3: str := MsgPropTrMessageTo3;
+                  4: str := MsgPropTrMessageTo4;
+                  5: str := MsgPropTrMessageTo5;
+                  else str := MsgPropTrMessageTo0;
                 end;
                 end;
-                with ItemProps[InsertRow(_lc[I_PROP_TR_MESSAGE_TO], str, True)] do
+                with ItemProps[InsertRow(MsgPropTrMessageTo, str, True)] do
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
                 end;
                 str := win2utf(Data.MessageText);
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
                 end;
                 str := win2utf(Data.MessageText);
-                with ItemProps[InsertRow(_lc[I_PROP_TR_MESSAGE_TEXT], str, True)] do
+                with ItemProps[InsertRow(MsgPropTrMessageText, str, True)] do
                 begin
                   EditStyle := esSimple;
                   MaxLength := 100;
                 end;
                 begin
                   EditStyle := esSimple;
                   MaxLength := 100;
                 end;
-                with ItemProps[InsertRow(_lc[I_PROP_TR_MESSAGE_TIME], IntToStr(Data.MessageTime), True)] do
+                with ItemProps[InsertRow(MsgPropTrMessageTime, IntToStr(Data.MessageTime), True)] do
                 begin
                   EditStyle := esSimple;
                   MaxLength := 5;
                 begin
                   EditStyle := esSimple;
                   MaxLength := 5;
@@ -1394,36 +1408,50 @@ begin
 
             TRIGGER_DAMAGE:
               begin
 
             TRIGGER_DAMAGE:
               begin
-                with ItemProps[InsertRow(_lc[I_PROP_TR_DAMAGE_VALUE], IntToStr(Data.DamageValue), True)] do
+                with ItemProps[InsertRow(MsgPropTrDamageValue, IntToStr(Data.DamageValue), True)] do
                 begin
                   EditStyle := esSimple;
                   MaxLength := 5;
                 end;
                 begin
                   EditStyle := esSimple;
                   MaxLength := 5;
                 end;
-                with ItemProps[InsertRow(_lc[I_PROP_TR_INTERVAL], IntToStr(Data.DamageInterval), True)] do
+                with ItemProps[InsertRow(MsgPropTrInterval, IntToStr(Data.DamageInterval), True)] do
                 begin
                   EditStyle := esSimple;
                   MaxLength := 5;
                 end;
                 begin
                   EditStyle := esSimple;
                   MaxLength := 5;
                 end;
+                case Data.DamageKind of
+                  3: str := MsgPropTrDamageKind3;
+                  4: str := MsgPropTrDamageKind4;
+                  5: str := MsgPropTrDamageKind5;
+                  6: str := MsgPropTrDamageKind6;
+                  7: str := MsgPropTrDamageKind7;
+                  8: str := MsgPropTrDamageKind8;
+                  else str := MsgPropTrDamageKind0;
+                end;
+                with ItemProps[InsertRow(MsgPropTrDamageKind, str, True)] do
+                begin
+                  EditStyle := esPickList;
+                  ReadOnly := True;
+                end;
               end;
 
             TRIGGER_HEALTH:
               begin
               end;
 
             TRIGGER_HEALTH:
               begin
-                with ItemProps[InsertRow(_lc[I_PROP_TR_HEALTH], IntToStr(Data.HealValue), True)] do
+                with ItemProps[InsertRow(MsgPropTrHealth, IntToStr(Data.HealValue), True)] do
                 begin
                   EditStyle := esSimple;
                   MaxLength := 5;
                 end;
                 begin
                   EditStyle := esSimple;
                   MaxLength := 5;
                 end;
-                with ItemProps[InsertRow(_lc[I_PROP_TR_INTERVAL], IntToStr(Data.HealInterval), True)] do
+                with ItemProps[InsertRow(MsgPropTrInterval, IntToStr(Data.HealInterval), True)] do
                 begin
                   EditStyle := esSimple;
                   MaxLength := 5;
                 end;
                 begin
                   EditStyle := esSimple;
                   MaxLength := 5;
                 end;
-                with ItemProps[InsertRow(_lc[I_PROP_TR_HEALTH_MAX], BoolNames[Data.HealMax], True)] do
+                with ItemProps[InsertRow(MsgPropTrHealthMax, BoolNames[Data.HealMax], True)] do
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
                 end;
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
                 end;
-                with ItemProps[InsertRow(_lc[I_PROP_TR_SILENT], BoolNames[Data.HealSilent], True)] do
+                with ItemProps[InsertRow(MsgPropTrSilent, BoolNames[Data.HealSilent], True)] do
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
@@ -1432,89 +1460,89 @@ begin
 
             TRIGGER_SHOT:
               begin
 
             TRIGGER_SHOT:
               begin
-                with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_TYPE], ShotToStr(Data.ShotType), True)] do
+                with ItemProps[InsertRow(MsgPropTrShotType, ShotToStr(Data.ShotType), True)] do
                 begin
                   EditStyle := esEllipsis;
                   ReadOnly := True;
                 end;
 
                 begin
                   EditStyle := esEllipsis;
                   ReadOnly := True;
                 end;
 
-                with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_SOUND], BoolNames[Data.ShotSound], True)] do
+                with ItemProps[InsertRow(MsgPropTrShotSound, BoolNames[Data.ShotSound], True)] do
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
                 end;
 
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
                 end;
 
-                with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_PANEL], IntToStr(Data.ShotPanelID), True)] do
+                with ItemProps[InsertRow(MsgPropTrShotPanel, IntToStr(Data.ShotPanelID), True)] do
                 begin
                   EditStyle := esEllipsis;
                   ReadOnly := True;
                 end;
 
                 case Data.ShotTarget of
                 begin
                   EditStyle := esEllipsis;
                   ReadOnly := True;
                 end;
 
                 case Data.ShotTarget of
-                  1: str := _lc[I_PROP_TR_SHOT_TO_1];
-                  2: str := _lc[I_PROP_TR_SHOT_TO_2];
-                  3: str := _lc[I_PROP_TR_SHOT_TO_3];
-                  4: str := _lc[I_PROP_TR_SHOT_TO_4];
-                  5: str := _lc[I_PROP_TR_SHOT_TO_5];
-                  6: str := _lc[I_PROP_TR_SHOT_TO_6];
-                  else str := _lc[I_PROP_TR_SHOT_TO_0];
+                  1: str := MsgPropTrShotTo1;
+                  2: str := MsgPropTrShotTo2;
+                  3: str := MsgPropTrShotTo3;
+                  4: str := MsgPropTrShotTo4;
+                  5: str := MsgPropTrShotTo5;
+                  6: str := MsgPropTrShotTo6;
+                  else str := MsgPropTrShotTo0;
                 end;
                 end;
-                with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_TO], str, True)] do
+                with ItemProps[InsertRow(MsgPropTrShotTo, str, True)] do
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
                 end;
 
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
                 end;
 
-                with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_SIGHT], IntToStr(Data.ShotIntSight), True)] do
+                with ItemProps[InsertRow(MsgPropTrShotSight, IntToStr(Data.ShotIntSight), True)] do
                 begin
                   EditStyle := esSimple;
                   MaxLength := 3;
                 end;
 
                 case Data.ShotAim of
                 begin
                   EditStyle := esSimple;
                   MaxLength := 3;
                 end;
 
                 case Data.ShotAim of
-                  1: str := _lc[I_PROP_TR_SHOT_AIM_1];
-                  2: str := _lc[I_PROP_TR_SHOT_AIM_2];
-                  3: str := _lc[I_PROP_TR_SHOT_AIM_3];
-                  else str := _lc[I_PROP_TR_SHOT_AIM_0];
+                  1: str := MsgPropTrShotAim1;
+                  2: str := MsgPropTrShotAim2;
+                  3: str := MsgPropTrShotAim3;
+                  else str := MsgPropTrShotAim0;
                 end;
                 end;
-                with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_AIM], str, True)-1] do
+                with ItemProps[InsertRow(MsgPropTrShotAim, str, True)] do
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
                 end;
 
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
                 end;
 
-                with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_TO],
+                with ItemProps[InsertRow(MsgPropTrSpawnTo,
                                  Format('(%d:%d)', [Data.ShotPos.X, Data.ShotPos.Y]), True)] do
                 begin
                   EditStyle := esEllipsis;
                   ReadOnly := True;
                 end;
 
                                  Format('(%d:%d)', [Data.ShotPos.X, Data.ShotPos.Y]), True)] do
                 begin
                   EditStyle := esEllipsis;
                   ReadOnly := True;
                 end;
 
-                with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_ANGLE], IntToStr(Data.ShotAngle), True)] do
+                with ItemProps[InsertRow(MsgPropTrShotAngle, IntToStr(Data.ShotAngle), True)] do
                 begin
                   EditStyle := esSimple;
                   MaxLength := 4;
                 end;
 
                 begin
                   EditStyle := esSimple;
                   MaxLength := 4;
                 end;
 
-                with ItemProps[InsertRow(_lc[I_PROP_TR_EX_DELAY], IntToStr(Data.ShotWait), True)] do
+                with ItemProps[InsertRow(MsgPropTrExDelay, IntToStr(Data.ShotWait), True)] do
                 begin
                   EditStyle := esSimple;
                   MaxLength := 5;
                 end;
 
                 begin
                   EditStyle := esSimple;
                   MaxLength := 5;
                 end;
 
-                with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_ACC], IntToStr(Data.ShotAccuracy), True)] do
+                with ItemProps[InsertRow(MsgPropTrShotAcc, IntToStr(Data.ShotAccuracy), True)] do
                 begin
                   EditStyle := esSimple;
                   MaxLength := 5;
                 end;
 
                 begin
                   EditStyle := esSimple;
                   MaxLength := 5;
                 end;
 
-                with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_AMMO], IntToStr(Data.ShotAmmo), True)] do
+                with ItemProps[InsertRow(MsgPropTrShotAmmo, IntToStr(Data.ShotAmmo), True)] do
                 begin
                   EditStyle := esSimple;
                   MaxLength := 5;
                 end;
 
                 begin
                   EditStyle := esSimple;
                   MaxLength := 5;
                 end;
 
-                with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_RELOAD], IntToStr(Data.ShotIntReload), True)] do
+                with ItemProps[InsertRow(MsgPropTrShotReload, IntToStr(Data.ShotIntReload), True)] do
                 begin
                   EditStyle := esSimple;
                   MaxLength := 4;
                 begin
                   EditStyle := esSimple;
                   MaxLength := 4;
@@ -1523,17 +1551,17 @@ begin
 
             TRIGGER_EFFECT:
               begin
 
             TRIGGER_EFFECT:
               begin
-                with ItemProps[InsertRow(_lc[I_PROP_TR_COUNT], IntToStr(Data.FXCount), True)] do
+                with ItemProps[InsertRow(MsgPropTrCount, IntToStr(Data.FXCount), True)] do
                 begin
                   EditStyle := esSimple;
                   MaxLength := 3;
                 end;
 
                 if Data.FXType = 0 then
                 begin
                   EditStyle := esSimple;
                   MaxLength := 3;
                 end;
 
                 if Data.FXType = 0 then
-                  str := _lc[I_PROP_TR_EFFECT_PARTICLE]
+                  str := MsgPropTrEffectParticle
                 else
                 else
-                  str := _lc[I_PROP_TR_EFFECT_ANIMATION];
-                with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_TYPE], str, True)] do
+                  str := MsgPropTrEffectAnimation;
+                with ItemProps[InsertRow(MsgPropTrEffectType, str, True)] do
                 begin
                   EditStyle := esEllipsis;
                   ReadOnly := True;
                 begin
                   EditStyle := esEllipsis;
                   ReadOnly := True;
@@ -1543,17 +1571,17 @@ begin
                 if Data.FXType = 0 then
                   case Data.FXSubType of
                     TRIGGER_EFFECT_SLIQUID:
                 if Data.FXType = 0 then
                   case Data.FXSubType of
                     TRIGGER_EFFECT_SLIQUID:
-                      str := _lc[I_PROP_TR_EFFECT_SLIQUID];
+                      str := MsgPropTrEffectSliquid;
                     TRIGGER_EFFECT_LLIQUID:
                     TRIGGER_EFFECT_LLIQUID:
-                      str := _lc[I_PROP_TR_EFFECT_LLIQUID];
+                      str := MsgPropTrEffectLliquid;
                     TRIGGER_EFFECT_DLIQUID:
                     TRIGGER_EFFECT_DLIQUID:
-                      str := _lc[I_PROP_TR_EFFECT_DLIQUID];
+                      str := MsgPropTrEffectDliquid;
                     TRIGGER_EFFECT_BLOOD:
                     TRIGGER_EFFECT_BLOOD:
-                      str := _lc[I_PROP_TR_EFFECT_BLOOD];
+                      str := MsgPropTrEffectBlood;
                     TRIGGER_EFFECT_SPARK:
                     TRIGGER_EFFECT_SPARK:
-                      str := _lc[I_PROP_TR_EFFECT_SPARK];
+                      str := MsgPropTrEffectSpark;
                     TRIGGER_EFFECT_BUBBLE:
                     TRIGGER_EFFECT_BUBBLE:
-                      str := _lc[I_PROP_TR_EFFECT_BUBBLE];
+                      str := MsgPropTrEffectBubble;
                   end;
                 if Data.FXType = 1 then
                 begin
                   end;
                 if Data.FXType = 1 then
                 begin
@@ -1561,61 +1589,61 @@ begin
                     Data.FXSubType := EFFECT_TELEPORT;
                   str := EffectToStr(Data.FXSubType);
                 end;
                     Data.FXSubType := EFFECT_TELEPORT;
                   str := EffectToStr(Data.FXSubType);
                 end;
-                with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_SUBTYPE], str, True)] do
+                with ItemProps[InsertRow(MsgPropTrEffectSubtype, str, True)] do
                 begin
                   EditStyle := esEllipsis;
                   ReadOnly := True;
                 end;
 
                 begin
                   EditStyle := esEllipsis;
                   ReadOnly := True;
                 end;
 
-                with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_COLOR], IntToStr(Data.FXColorR or (Data.FXColorG shl 8) or (Data.FXColorB shl 16)), True)] do
+                with ItemProps[InsertRow(MsgPropTrEffectColor, IntToStr(Data.FXColorR or (Data.FXColorG shl 8) or (Data.FXColorB shl 16)), True)] do
                 begin
                   EditStyle := esEllipsis;
                   ReadOnly := True;
                 end;
 
                 begin
                   EditStyle := esEllipsis;
                   ReadOnly := True;
                 end;
 
-                with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_CENTER], BoolNames[Data.FXPos = 0], True)] do
+                with ItemProps[InsertRow(MsgPropTrEffectCenter, BoolNames[Data.FXPos = 0], True)] do
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
                 end;
 
                 begin
                   EditStyle := esPickList;
                   ReadOnly := True;
                 end;
 
-                with ItemProps[InsertRow(_lc[I_PROP_TR_EX_DELAY], IntToStr(Data.FXWait), True)] do
+                with ItemProps[InsertRow(MsgPropTrExDelay, IntToStr(Data.FXWait), True)] do
                 begin
                   EditStyle := esSimple;
                   MaxLength := 5;
                 end;
 
                 begin
                   EditStyle := esSimple;
                   MaxLength := 5;
                 end;
 
-                with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_VELX], IntToStr(Data.FXVelX), True)] do
+                with ItemProps[InsertRow(MsgPropTrEffectVelx, IntToStr(Data.FXVelX), True)] do
                 begin
                   EditStyle := esSimple;
                   MaxLength := 4;
                 end;
 
                 begin
                   EditStyle := esSimple;
                   MaxLength := 4;
                 end;
 
-                with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_VELY], IntToStr(Data.FXVelY), True)] do
+                with ItemProps[InsertRow(MsgPropTrEffectVely, IntToStr(Data.FXVelY), True)] do
                 begin
                   EditStyle := esSimple;
                   MaxLength := 4;
                 end;
 
                 begin
                   EditStyle := esSimple;
                   MaxLength := 4;
                 end;
 
-                with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_SPL], IntToStr(Data.FXSpreadL), True)] do
+                with ItemProps[InsertRow(MsgPropTrEffectSpl, IntToStr(Data.FXSpreadL), True)] do
                 begin
                   EditStyle := esSimple;
                   MaxLength := 3;
                 end;
 
                 begin
                   EditStyle := esSimple;
                   MaxLength := 3;
                 end;
 
-                with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_SPR], IntToStr(Data.FXSpreadR), True)] do
+                with ItemProps[InsertRow(MsgPropTrEffectSpr, IntToStr(Data.FXSpreadR), True)] do
                 begin
                   EditStyle := esSimple;
                   MaxLength := 3;
                 end;
 
                 begin
                   EditStyle := esSimple;
                   MaxLength := 3;
                 end;
 
-                with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_SPU], IntToStr(Data.FXSpreadU), True)] do
+                with ItemProps[InsertRow(MsgPropTrEffectSpu, IntToStr(Data.FXSpreadU), True)] do
                 begin
                   EditStyle := esSimple;
                   MaxLength := 3;
                 end;
 
                 begin
                   EditStyle := esSimple;
                   MaxLength := 3;
                 end;
 
-                with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_SPD], IntToStr(Data.FXSpreadD), True)] do
+                with ItemProps[InsertRow(MsgPropTrEffectSpd, IntToStr(Data.FXSpreadD), True)] do
                 begin
                   EditStyle := esSimple;
                   MaxLength := 3;
                 begin
                   EditStyle := esSimple;
                   MaxLength := 3;
@@ -1771,6 +1799,7 @@ begin
   RemoveSelectFromObjects();
 
   MainForm.miUndo.Enabled := UndoBuffer <> nil;
   RemoveSelectFromObjects();
 
   MainForm.miUndo.Enabled := UndoBuffer <> nil;
+  MainForm.RecountSelectedObjects();
 end;
 
 procedure Undo_Add(ObjectType: Byte; ID: DWORD; Group: Boolean = False);
 end;
 
 procedure Undo_Add(ObjectType: Byte; ID: DWORD; Group: Boolean = False);
@@ -1797,16 +1826,28 @@ begin
   end;
 
   UndoBuffer[i, ii].AddID := ID;
   end;
 
   UndoBuffer[i, ii].AddID := ID;
-
   MainForm.miUndo.Enabled := UndoBuffer <> nil;
 end;
 
   MainForm.miUndo.Enabled := UndoBuffer <> nil;
 end;
 
+procedure DiscardUndoBuffer();
+var
+  i, k: Integer;
+begin
+  for i := 0 to High(UndoBuffer) do
+    for k := 0 to High(UndoBuffer[i]) do
+      with UndoBuffer[i][k] do
+        if UndoType = UNDO_DELETE_PANEL then
+          Dispose(Panel);
+
+  UndoBuffer := nil;
+end;
+
 procedure FullClear();
 begin
   RemoveSelectFromObjects();
   ClearMap();
   LoadSky(gMapInfo.SkyName);
 procedure FullClear();
 begin
   RemoveSelectFromObjects();
   ClearMap();
   LoadSky(gMapInfo.SkyName);
-  UndoBuffer := nil;
+  DiscardUndoBuffer();
   slInvalidTextures.Clear();
   MapCheckForm.lbErrorList.Clear();
   MapCheckForm.mErrorDescription.Clear();
   slInvalidTextures.Clear();
   MapCheckForm.lbErrorList.Clear();
   MapCheckForm.mErrorDescription.Clear();
@@ -1822,7 +1863,7 @@ end;
 
 procedure ErrorMessageBox(str: String);
 begin
 
 procedure ErrorMessageBox(str: String);
 begin
-  MessageBox(0, PChar(str), PChar(_lc[I_MSG_ERROR]),
+  Application.MessageBox(PChar(str), PChar(MsgMsgError),
              MB_ICONINFORMATION or MB_OK or MB_DEFBUTTON1);
 end;
 
              MB_ICONINFORMATION or MB_OK or MB_DEFBUTTON1);
 end;
 
@@ -1838,41 +1879,41 @@ begin
     with gPanels[SelectedObjects[_id].ID] do
     begin
       if TextureWidth <> 0 then
     with gPanels[SelectedObjects[_id].ID] do
     begin
       if TextureWidth <> 0 then
-        if StrToIntDef(MainForm.vleObjectProperty.Values[_lc[I_PROP_WIDTH]], 1) mod TextureWidth <> 0 then
+        if StrToIntDef(MainForm.vleObjectProperty.Values[MsgPropWidth], 1) mod TextureWidth <> 0 then
         begin
         begin
-          ErrorMessageBox(Format(_lc[I_MSG_WRONG_TEXWIDTH],
+          ErrorMessageBox(Format(MsgMsgWrongTexwidth,
                                  [TextureWidth]));
           Exit;
         end;
 
       if TextureHeight <> 0 then
                                  [TextureWidth]));
           Exit;
         end;
 
       if TextureHeight <> 0 then
-        if StrToIntDef(Trim(MainForm.vleObjectProperty.Values[_lc[I_PROP_HEIGHT]]), 1) mod TextureHeight <> 0 then
+        if StrToIntDef(Trim(MainForm.vleObjectProperty.Values[MsgPropHeight]), 1) mod TextureHeight <> 0 then
         begin
         begin
-          ErrorMessageBox(Format(_lc[I_MSG_WRONG_TEXHEIGHT],
+          ErrorMessageBox(Format(MsgMsgWrongTexheight,
                                  [TextureHeight]));
           Exit;
         end;
 
       if IsTexturedPanel(PanelType) and (TextureName <> '') then
                                  [TextureHeight]));
           Exit;
         end;
 
       if IsTexturedPanel(PanelType) and (TextureName <> '') then
-        if not (StrToIntDef(MainForm.vleObjectProperty.Values[_lc[I_PROP_PANEL_ALPHA]], -1) in [0..255]) then
+        if not (StrToIntDef(MainForm.vleObjectProperty.Values[MsgPropPanelAlpha], -1) in [0..255]) then
         begin
         begin
-          ErrorMessageBox(_lc[I_MSG_WRONG_ALPHA]);
+          ErrorMessageBox(MsgMsgWrongAlpha);
           Exit;
         end;
     end;
 
   if SelectedObjects[_id].ObjectType in [OBJECT_PANEL, OBJECT_TRIGGER] then
           Exit;
         end;
     end;
 
   if SelectedObjects[_id].ObjectType in [OBJECT_PANEL, OBJECT_TRIGGER] then
-    if (StrToIntDef(MainForm.vleObjectProperty.Values[_lc[I_PROP_WIDTH]], 0) <= 0) or
-       (StrToIntDef(MainForm.vleObjectProperty.Values[_lc[I_PROP_HEIGHT]], 0) <= 0) then
+    if (StrToIntDef(MainForm.vleObjectProperty.Values[MsgPropWidth], 0) <= 0) or
+       (StrToIntDef(MainForm.vleObjectProperty.Values[MsgPropHeight], 0) <= 0) then
     begin
     begin
-      ErrorMessageBox(_lc[I_MSG_WRONG_SIZE]);
+      ErrorMessageBox(MsgMsgWrongSize);
       Exit;
     end;
 
       Exit;
     end;
 
-  if (Trim(MainForm.vleObjectProperty.Values[_lc[I_PROP_X]]) = '') or
-     (Trim(MainForm.vleObjectProperty.Values[_lc[I_PROP_Y]]) = '') then
+  if (Trim(MainForm.vleObjectProperty.Values[MsgPropX]) = '') or
+     (Trim(MainForm.vleObjectProperty.Values[MsgPropY]) = '') then
   begin
   begin
-    ErrorMessageBox(_lc[I_MSG_WRONG_XY]);
+    ErrorMessageBox(MsgMsgWrongXy);
     Exit;
   end;
 
     Exit;
   end;
 
@@ -1908,24 +1949,23 @@ begin
     SectionName := aSection;
 
   if aWAD = '' then
     SectionName := aSection;
 
   if aWAD = '' then
-    aWAD := _lc[I_WAD_SPECIAL_MAP];
+    aWAD := MsgWadSpecialMap;
 
 
-  if aWAD = _lc[I_WAD_SPECIAL_MAP] then
+  if aWAD = MsgWadSpecialMap then
     begin // Файл карты
       g_ProcessResourceStr(OpenedMap, @fn, nil, nil);
     begin // Файл карты
       g_ProcessResourceStr(OpenedMap, @fn, nil, nil);
-    //FileName := EditorDir+'maps\'+ExtractFileName(fn);
       FileName := fn;
       ResourceName := ':'+SectionName+'\'+aTex;
     end
   else
       FileName := fn;
       ResourceName := ':'+SectionName+'\'+aTex;
     end
   else
-    if aWAD = _lc[I_WAD_SPECIAL_TEXS] then
+    if aWAD = MsgWadSpecialTexs then
       begin // Спец. текстуры
         FileName := '';
         ResourceName := aTex;
       end
     else
       begin // Внешний WAD
       begin // Спец. текстуры
         FileName := '';
         ResourceName := aTex;
       end
     else
       begin // Внешний WAD
-        FileName := EditorDir+'wads/'+aWAD;
+        FileName := WadsDir + DirectorySeparator + aWAD;
         ResourceName := aWAD+':'+SectionName+'\'+aTex;
       end;
 
         ResourceName := aWAD+':'+SectionName+'\'+aTex;
       end;
 
@@ -1936,7 +1976,7 @@ begin
     if ResourceName = MainForm.lbTextureList.Items[a] then
     begin
       if not silent then
     if ResourceName = MainForm.lbTextureList.Items[a] then
     begin
       if not silent then
-        ErrorMessageBox(Format(_lc[I_MSG_TEXTURE_ALREADY],
+        ErrorMessageBox(Format(MsgMsgTextureAlready,
                                [ResourceName]));
       ok := False;
     end;
                                [ResourceName]));
       ok := False;
     end;
@@ -1945,7 +1985,7 @@ begin
   if Length(ResourceName) > 64 then
   begin
     if not silent then
   if Length(ResourceName) > 64 then
   begin
     if not silent then
-      ErrorMessageBox(Format(_lc[I_MSG_RES_NAME_64],
+      ErrorMessageBox(Format(MsgMsgResName64,
                              [ResourceName]));
     ok := False;
   end;
                              [ResourceName]));
     ok := False;
   end;
@@ -1953,7 +1993,7 @@ begin
   if ok then
   begin
     a := -1;
   if ok then
   begin
     a := -1;
-    if aWAD = _lc[I_WAD_SPECIAL_TEXS] then
+    if aWAD = MsgWadSpecialTexs then
     begin
       a := MainForm.lbTextureList.Items.Add(ResourceName);
       if not silent then
     begin
       a := MainForm.lbTextureList.Items.Add(ResourceName);
       if not silent then
@@ -2010,7 +2050,7 @@ var
   MapName: String;
   idx: Integer;
 begin
   MapName: String;
   idx: Integer;
 begin
-  SelectMapForm.Caption := _lc[I_CAP_OPEN];
+  SelectMapForm.Caption := MsgCapOpen;
   SelectMapForm.GetMaps(FileName);
 
   if (FileName = OpenedWAD) and
   SelectMapForm.GetMaps(FileName);
 
   if (FileName = OpenedWAD) and
@@ -2224,6 +2264,7 @@ procedure SwitchMap();
 begin
   ShowMap := not ShowMap;
   MainForm.tbShowMap.Down := ShowMap;
 begin
   ShowMap := not ShowMap;
   MainForm.tbShowMap.Down := ShowMap;
+  MainForm.miMiniMap.Checked := ShowMap;
 end;
 
 procedure ShowEdges();
 end;
 
 procedure ShowEdges();
@@ -2232,6 +2273,7 @@ begin
     drEdge[3] := 255
   else
     drEdge[3] := gAlphaEdge;
     drEdge[3] := 255
   else
     drEdge[3] := gAlphaEdge;
+  MainForm.miShowEdges.Checked := drEdge[3] <> 255;
 end;
 
 function SelectedTexture(): String;
 end;
 
 function SelectedTexture(): String;
@@ -2341,10 +2383,10 @@ begin
   Result := Res;
 end;
 
   Result := Res;
 end;
 
-procedure StringToCopyBuffer(Str: String; var CopyBuf: TCopyRecArray;
-  var pmin: TPoint);
+procedure StringToCopyBuffer(Str: String; var CopyBuf: TCopyRecArray; var pmin: TPoint);
 var
   i, j, t: Integer;
 var
   i, j, t: Integer;
+  minArea, newArea, newX, newY: LongInt;
 
   function GetNext(): String;
   var
 
   function GetNext(): String;
   var
@@ -2387,6 +2429,7 @@ var
   end;
 
 begin
   end;
 
 begin
+  minArea := High(minArea);
   Str := Trim(Str);
 
   if GetNext() <> CLIPBOARD_SIG then
   Str := Trim(Str);
 
   if GetNext() <> CLIPBOARD_SIG then
@@ -2397,8 +2440,7 @@ begin
   // Тип объекта:
     t := StrToIntDef(GetNext(), 0);
 
   // Тип объекта:
     t := StrToIntDef(GetNext(), 0);
 
-    if (t < OBJECT_PANEL) or (t > OBJECT_TRIGGER) or
-       (GetNext() <> ';') then
+    if (t < OBJECT_PANEL) or (t > OBJECT_TRIGGER) or (GetNext() <> ';') then
     begin // Что-то не то => пропускаем:
       t := Pos(';', Str);
       Delete(Str, 1, t);
     begin // Что-то не то => пропускаем:
       t := Pos(';', Str);
       Delete(Str, 1, t);
@@ -2424,13 +2466,14 @@ begin
             PanelType := StrToIntDef(GetNext(), PANEL_WALL);
             X := StrToIntDef(GetNext(), 0);
             Y := StrToIntDef(GetNext(), 0);
             PanelType := StrToIntDef(GetNext(), PANEL_WALL);
             X := StrToIntDef(GetNext(), 0);
             Y := StrToIntDef(GetNext(), 0);
-            pmin.X := Min(X, pmin.X);
-            pmin.Y := Min(Y, pmin.Y);
             Width := StrToIntDef(GetNext(), 16);
             Height := StrToIntDef(GetNext(), 16);
             TextureName := GetNext();
             Alpha := StrToIntDef(GetNext(), 0);
             Blending := (GetNext() = '1');
             Width := StrToIntDef(GetNext(), 16);
             Height := StrToIntDef(GetNext(), 16);
             TextureName := GetNext();
             Alpha := StrToIntDef(GetNext(), 0);
             Blending := (GetNext() = '1');
+            newArea := X * Y - Width * Height;
+            newX := X;
+            newY := Y;
           end;
         end;
 
           end;
         end;
 
@@ -2440,10 +2483,11 @@ begin
           ItemType := StrToIntDef(GetNext(), ITEM_MEDKIT_SMALL);
           X := StrToIntDef(GetNext(), 0);
           Y := StrToIntDef(GetNext(), 0);
           ItemType := StrToIntDef(GetNext(), ITEM_MEDKIT_SMALL);
           X := StrToIntDef(GetNext(), 0);
           Y := StrToIntDef(GetNext(), 0);
-          pmin.X := Min(X, pmin.X);
-          pmin.Y := Min(Y, pmin.Y);
           OnlyDM := (GetNext() = '1');
           Fall := (GetNext() = '1');
           OnlyDM := (GetNext() = '1');
           Fall := (GetNext() = '1');
+          newArea := X * Y;
+          newX := X;
+          newY := Y;
         end;
 
       OBJECT_MONSTER:
         end;
 
       OBJECT_MONSTER:
@@ -2452,13 +2496,12 @@ begin
           MonsterType := StrToIntDef(GetNext(), MONSTER_DEMON);
           X := StrToIntDef(GetNext(), 0);
           Y := StrToIntDef(GetNext(), 0);
           MonsterType := StrToIntDef(GetNext(), MONSTER_DEMON);
           X := StrToIntDef(GetNext(), 0);
           Y := StrToIntDef(GetNext(), 0);
-          pmin.X := Min(X, pmin.X);
-          pmin.Y := Min(Y, pmin.Y);
-
-          if GetNext() = '1' then
-            Direction := D_LEFT
-          else
-            Direction := D_RIGHT;
+          if GetNext() = '1'
+            then Direction := D_LEFT
+            else Direction := D_RIGHT;
+          newArea := X * Y;
+          newX := X;
+          newY := Y;
         end;
 
       OBJECT_AREA:
         end;
 
       OBJECT_AREA:
@@ -2467,12 +2510,12 @@ begin
           AreaType := StrToIntDef(GetNext(), AREA_PLAYERPOINT1);
           X := StrToIntDef(GetNext(), 0);
           Y := StrToIntDef(GetNext(), 0);
           AreaType := StrToIntDef(GetNext(), AREA_PLAYERPOINT1);
           X := StrToIntDef(GetNext(), 0);
           Y := StrToIntDef(GetNext(), 0);
-          pmin.X := Min(X, pmin.X);
-          pmin.Y := Min(Y, pmin.Y);
-          if GetNext() = '1' then
-            Direction := D_LEFT
-          else
-            Direction := D_RIGHT;
+          if GetNext() = '1'
+            then Direction := D_LEFT
+            else Direction := D_RIGHT;
+          newArea := X * Y;
+          newX := X;
+          newY := Y;
         end;
 
       OBJECT_TRIGGER:
         end;
 
       OBJECT_TRIGGER:
@@ -2481,47 +2524,26 @@ begin
           TriggerType := StrToIntDef(GetNext(), TRIGGER_EXIT);
           X := StrToIntDef(GetNext(), 0);
           Y := StrToIntDef(GetNext(), 0);
           TriggerType := StrToIntDef(GetNext(), TRIGGER_EXIT);
           X := StrToIntDef(GetNext(), 0);
           Y := StrToIntDef(GetNext(), 0);
-          pmin.X := Min(X, pmin.X);
-          pmin.Y := Min(Y, pmin.Y);
           Width := StrToIntDef(GetNext(), 16);
           Height := StrToIntDef(GetNext(), 16);
           ActivateType := StrToIntDef(GetNext(), 0);
           Key := StrToIntDef(GetNext(), 0);
           Enabled := (GetNext() = '1');
           TexturePanel := StrToIntDef(GetNext(), 0);
           Width := StrToIntDef(GetNext(), 16);
           Height := StrToIntDef(GetNext(), 16);
           ActivateType := StrToIntDef(GetNext(), 0);
           Key := StrToIntDef(GetNext(), 0);
           Enabled := (GetNext() = '1');
           TexturePanel := StrToIntDef(GetNext(), 0);
-
-          for j := 0 to 127 do
-            Data.Default[j] := StrToIntDef(GetNext(), 0);
-
-          case TriggerType of
-            TRIGGER_TELEPORT:
-              begin
-                pmin.X := Min(Data.TargetPoint.X, pmin.X);
-                pmin.Y := Min(Data.TargetPoint.Y, pmin.Y);
-              end;
-            TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF:
-              begin
-                pmin.X := Min(Data.tX, pmin.X);
-                pmin.Y := Min(Data.tY, pmin.Y);
-              end;
-            TRIGGER_SPAWNMONSTER:
-              begin
-                pmin.X := Min(Data.MonPos.X, pmin.X);
-                pmin.Y := Min(Data.MonPos.Y, pmin.Y);
-              end;
-            TRIGGER_SPAWNITEM:
-              begin
-                pmin.X := Min(Data.ItemPos.X, pmin.X);
-                pmin.Y := Min(Data.ItemPos.Y, pmin.Y);
-              end;
-            TRIGGER_SHOT:
-              begin
-                pmin.X := Min(Data.ShotPos.X, pmin.X);
-                pmin.Y := Min(Data.ShotPos.Y, pmin.Y);
-              end;
-          end;
+          for j := 0 to 127
+            do Data.Default[j] := StrToIntDef(GetNext(), 0);
+          newArea := X * Y - Width * Height;
+          newX := X;
+          newY := Y;
         end;
     end;
         end;
     end;
+
+    if newArea < minArea then
+    begin
+      minArea := newArea;
+      pmin.X := newX;
+      pmin.Y := newY;
+    end;
   end;
 end;
 
   end;
 end;
 
@@ -2529,80 +2551,89 @@ end;
 //Закончились вспомогательные процедуры
 //----------------------------------------
 
 //Закончились вспомогательные процедуры
 //----------------------------------------
 
-procedure TMainForm.RefreshRecentMenu();
+procedure TMainForm.miRecentFileExecute (Sender: TObject);
 var
 var
-  i: Integer;
-  MI: TMenuItem;
+  s, fn: AnsiString;
+  n: LongInt;
 begin
 begin
-// Лишние запомненные карты:
-  while RecentFiles.Count > RecentCount do
-    RecentFiles.Delete(RecentFiles.Count-1);
+  n := (Sender as TMenuItem).Tag;
+  s := RecentFiles[n];
+  fn := g_ExtractWadName(s);
+  if FileExists(fn) then
+    OpenMap(fn, g_ExtractFilePathName(s))
+  else
+    Application.MessageBox('File not available anymore', '', MB_OK);
+//  if Application.MessageBox(PChar(MsgMsgDelRecentPrompt), PChar(MsgMsgDelRecent), MB_ICONQUESTION or MB_YESNO) = idYes then
+//  begin
+//    RecentFiles.Delete(n);
+//    RefreshRecentMenu();
+//  end;
+end;
 
 
-// Лишние строки меню:
-  while MainMenu.Items[0].Count > RECENT_FILES_MENU_START do
-    MainMenu.Items[0].Delete(MainMenu.Items[0].Count-1);
+procedure TMainForm.RefillRecentMenu (menu: TMenuItem; start: Integer; fmt: AnsiString);
+  var i: Integer; MI: TMenuItem; s: AnsiString;
+begin
+  Assert(menu <> nil);
+  Assert(start >= 0);
+  Assert(start <= menu.Count);
 
 
-// Отделение списка карт от строки "Выход":
-  if RecentFiles.Count > 0 then
+  // clear all the recent entries from menu
+  i := start;
+  while i < menu.Count do
   begin
   begin
-    MI := TMenuItem.Create(MainMenu.Items[0]);
-    MI.Caption := '-';
-    MainMenu.Items[0].Add(MI);
+    MI := menu.Items[i];
+    if @MI.OnClick <> @TMainForm.miRecentFileExecute then
+      i += 1
+    else
+    begin
+      menu.Delete(i);
+      Application.ReleaseComponent(MI);
+    end;
   end;
 
   end;
 
-// Добавление в меню списка запомненных карт:
+  // fill with a new ones
   for i := 0 to RecentFiles.Count-1 do
   begin
   for i := 0 to RecentFiles.Count-1 do
   begin
-    MI := TMenuItem.Create(MainMenu.Items[0]);
-    MI.Caption := IntToStr(i+1) + '  ' + RecentFiles[i];
-    MI.OnClick := aRecentFileExecute;
-    MainMenu.Items[0].Add(MI);
+    MI := TMenuItem.Create(menu);
+    s := RecentFiles[i];
+    MI.Caption := Format(fmt, [i+1, g_ExtractWadNameNoPath(s), g_ExtractFilePathName(s)]);
+    MI.OnClick := miRecentFileExecute;
+    MI.Tag := i;
+    menu.Insert(start + i, MI);  // transfers ownership
   end;
 end;
 
   end;
 end;
 
-procedure TMainForm.aRecentFileExecute(Sender: TObject);
-var
-  n, pw: Integer;
-  s, fn: String;
-  b: Boolean;
+procedure TMainForm.RefreshRecentMenu();
+  var start: Integer;
 begin
 begin
-  s := LowerCase((Sender as TMenuItem).Caption);
-  Delete(s, Pos('&', s), 1);
-  s := Trim(Copy(s, 1, 2));
-  n := StrToIntDef(s, 0) - 1;
-
-  if (n < 0) or (n >= RecentFiles.Count) then
-    Exit;
+  while RecentFiles.Count > RecentCount do
+    RecentFiles.Delete(RecentFiles.Count - 1);
 
 
-  s := RecentFiles[n];
-  pw := Pos('.wad:\', LowerCase(s));
-  b := False;
-  
-  if pw > 0 then
-    begin // Map name included
-      fn := Copy(s, 1, pw + 3);
-      Delete(s, 1, pw + 5);
-      if (FileExists(fn)) then
-      begin
-        OpenMap(fn, s);
-        b := True;
-      end;
-    end
-  else // Only wad name
-    if (FileExists(s)) then
-    begin
-      OpenMap(s, '');
-      b := True;
-    end;
+  if miMacRecentSubMenu.Visible then
+  begin
+    // Reconstruct OSX-like recent list
+    RefillRecentMenu(miMacRecentSubMenu, 0, '%1:s - %2:s');
+    miMacRecentEnd.Enabled := RecentFiles.Count <> 0;
+    miMacRecentEnd.Visible := RecentFiles.Count <> 0;
+  end;
 
 
-  if (not b) and (MessageBox(0, PChar(_lc[I_MSG_DEL_RECENT_PROMT]),
-    PChar(_lc[I_MSG_DEL_RECENT]), MB_ICONQUESTION or MB_YESNO) = idYes) then
+  if miWinRecentStart.Visible then
   begin
   begin
-    RecentFiles.Delete(n);
-    RefreshRecentMenu();
+    // Reconstruct Windows-like recent list
+    start := miMenuFile.IndexOf(miWinRecent);
+    if start < 0 then start := miMenuFile.Count else start += 1;
+    RefillRecentMenu(miMenuFile, start, '%0:d %1:s:%2:s');
+    miWinRecent.Enabled := False;
+    miWinRecent.Visible := RecentFiles.Count = 0;
   end;
 end;
 
   end;
 end;
 
+procedure TMainForm.miMacRecentClearClick(Sender: TObject);
+begin
+  RecentFiles.Clear();
+  RefreshRecentMenu();
+end;
+
 procedure TMainForm.aEditorOptionsExecute(Sender: TObject);
 begin
   OptionsForm.ShowModal();
 procedure TMainForm.aEditorOptionsExecute(Sender: TObject);
 begin
   OptionsForm.ShowModal();
@@ -2623,13 +2654,13 @@ begin
   ID := 0;
 
   wad := TWADEditor_1.Create;
   ID := 0;
 
   wad := TWADEditor_1.Create;
-  if wad.ReadFile(EditorDir+'data/Game.wad') then
+  if wad.ReadFile(GameWad) then
     wad.GetResource('FONTS', cfgres, cfgdata, cfglen);
   wad.Free();
 
   if cfglen <> 0 then
   begin
     wad.GetResource('FONTS', cfgres, cfgdata, cfglen);
   wad.Free();
 
   if cfglen <> 0 then
   begin
-    if not g_CreateTextureWAD('FONT_STD', EditorDir+'data/Game.wad:FONTS\'+texture) then
+    if not g_CreateTextureWAD('FONT_STD', GameWad + ':FONTS\' + texture) then
       e_WriteLog('ERROR ERROR ERROR', MSG_WARNING);
 
     config := TConfig.CreateMem(cfgdata, cfglen);
       e_WriteLog('ERROR ERROR ERROR', MSG_WARNING);
 
     config := TConfig.CreateMem(cfgdata, cfglen);
@@ -2655,10 +2686,71 @@ var
   s: String;
 begin
   Randomize();
   s: String;
 begin
   Randomize();
-
-  EditorDir := ExtractFilePath(Application.ExeName);
-
-  e_InitLog(EditorDir+'Editor.log', WM_NEWFILE);
+  LastDrawTime := 0;
+
+  {$IFDEF DARWIN}
+    miApple.Enabled := True;
+    miApple.Visible := True;
+    miMacRecentSubMenu.Enabled := True;
+    miMacRecentSubMenu.Visible := True;
+    miWinRecentStart.Enabled := False;
+    miWinRecentStart.Visible := False;
+    miWinRecent.Enabled := False;
+    miWinRecent.Visible := False;
+    miLine2.Enabled := False;
+    miLine2.Visible := False;
+    miExit.Enabled := False;
+    miExit.Visible := False;
+    miOptions.Enabled := False;
+    miOptions.Visible := False;
+    miMenuWindow.Enabled := True;
+    miMenuWindow.Visible := True;
+    miAbout.Enabled := False;
+    miAbout.Visible := False;
+  {$ELSE}
+    miApple.Enabled := False;
+    miApple.Visible := False;
+    miMacRecentSubMenu.Enabled := False;
+    miMacRecentSubMenu.Visible := False;
+    miWinRecentStart.Enabled := True;
+    miWinRecentStart.Visible := True;
+    miWinRecent.Enabled := True;
+    miWinRecent.Visible := True;
+    miLine2.Enabled := True;
+    miLine2.Visible := True;
+    miExit.Enabled := True;
+    miExit.Visible := True;
+    miOptions.Enabled := True;
+    miOptions.Visible := True;
+    miMenuWindow.Enabled := False;
+    miMenuWindow.Visible := False;
+    miAbout.Enabled := True;
+    miAbout.Visible := True;
+  {$ENDIF}
+
+  miNewMap.ShortCut := ShortCut(VK_N, [ssModifier]);
+  miOpenMap.ShortCut := ShortCut(VK_O, [ssModifier]);
+  miSaveMap.ShortCut := ShortCut(VK_S, [ssModifier]);
+  {$IFDEF DARWIN}
+    miSaveMapAs.ShortCut := ShortCut(VK_S, [ssModifier, ssShift]);
+    miReopenMap.ShortCut := ShortCut(VK_F5, [ssModifier]);
+  {$ENDIF}
+  miUndo.ShortCut := ShortCut(VK_Z, [ssModifier]);
+  miCopy.ShortCut := ShortCut(VK_C, [ssModifier]);
+  miCut.ShortCut := ShortCut(VK_X, [ssModifier]);
+  miPaste.ShortCut := ShortCut(VK_V, [ssModifier]);
+  miSelectAll.ShortCut := ShortCut(VK_A, [ssModifier]);
+  miToFore.ShortCut := ShortCut(VK_LCL_CLOSE_BRACKET, [ssModifier]);
+  miToBack.ShortCut := ShortCut(VK_LCL_OPEN_BRACKET, [ssModifier]);
+  {$IFDEF DARWIN}
+    miMapOptions.Shortcut := ShortCut(VK_P, [ssModifier, ssAlt]);
+    selectall1.Shortcut := ShortCut(VK_A, [ssModifier, ssAlt]);
+  {$ENDIF}
+
+  e_WriteLog('Doom 2D: Forever Editor version ' + EDITOR_VERSION, MSG_NOTIFY);
+  e_WriteLog('Build date: ' + EDITOR_BUILDDATE + ' ' + EDITOR_BUILDTIME, MSG_NOTIFY);
+  e_WriteLog('Build hash: ' + g_GetBuildHash(), MSG_NOTIFY);
+  e_WriteLog('Build by: ' + g_GetBuilderName(), MSG_NOTIFY);
 
   slInvalidTextures := TStringList.Create;
 
 
   slInvalidTextures := TStringList.Create;
 
@@ -2678,7 +2770,9 @@ begin
   OpenedMap := '';
   OpenedWAD := '';
 
   OpenedMap := '';
   OpenedWAD := '';
 
-  config := TConfig.CreateFile(EditorDir+'Editor.cfg');
+  config := TConfig.CreateFile(CfgFileName);
+
+  gWADEditorLogLevel := config.ReadInt('WADEditor', 'LogLevel', DFWAD_LOG_DEFAULT);
 
   if config.ReadInt('Editor', 'XPos', -1) = -1 then
     Position := poDesktopCenter
 
   if config.ReadInt('Editor', 'XPos', -1) = -1 then
     Position := poDesktopCenter
@@ -2723,20 +2817,34 @@ begin
   gAlphaTriggerArea := config.ReadInt('Editor', 'TriggerAlpha', ALPHA_AREA);
   if gAlphaTriggerArea = 255 then
     gAlphaTriggerArea := ALPHA_AREA;
   gAlphaTriggerArea := config.ReadInt('Editor', 'TriggerAlpha', ALPHA_AREA);
   if gAlphaTriggerArea = 255 then
     gAlphaTriggerArea := ALPHA_AREA;
-  if config.ReadInt('Editor', 'Scale', 0) = 1 then
-    Scale := 2
-  else
-    Scale := 1;
-  if config.ReadInt('Editor', 'DotSize', 0) = 1 then
-    DotSize := 2
-  else
-    DotSize := 1;
-  OpenDialog.InitialDir := config.ReadStr('Editor', 'LastOpenDir', EditorDir);
-  SaveDialog.InitialDir := config.ReadStr('Editor', 'LastSaveDir', EditorDir);
+  gAlphaMonsterRect := config.ReadInt('Editor', 'MonsterRectAlpha', 0);
+  gAlphaAreaRect := config.ReadInt('Editor', 'AreaRectAlpha', 0);
+  Scale := Max(config.ReadInt('Editor', 'Scale', 1), 1);
+  DotSize := Max(config.ReadInt('Editor', 'DotSize', 1), 1);
+  OpenDialog.InitialDir := config.ReadStr('Editor', 'LastOpenDir', MapsDir);
+  SaveDialog.InitialDir := config.ReadStr('Editor', 'LastSaveDir', MapsDir);
 
   s := config.ReadStr('Editor', 'Language', '');
   gLanguage := s;
 
 
   s := config.ReadStr('Editor', 'Language', '');
   gLanguage := s;
 
+  TestGameMode := config.ReadStr('TestRun', 'GameMode', 'DM');
+  TestLimTime := config.ReadStr('TestRun', 'LimTime', '0');
+  TestLimScore := config.ReadStr('TestRun', 'LimScore', '0');
+  TestOptionsTwoPlayers := config.ReadBool('TestRun', 'TwoPlayers', False);
+  TestOptionsTeamDamage := config.ReadBool('TestRun', 'TeamDamage', False);
+  TestOptionsAllowExit := config.ReadBool('TestRun', 'AllowExit', True);
+  TestOptionsWeaponStay := config.ReadBool('TestRun', 'WeaponStay', False);
+  TestOptionsMonstersDM := config.ReadBool('TestRun', 'MonstersDM', False);
+  TestMapOnce := config.ReadBool('TestRun', 'MapOnce', False);
+  {$IF DEFINED(DARWIN)}
+    TestD2dExe := config.ReadStr('TestRun', 'ExeDrawin', GameExeFile);
+  {$ELSEIF DEFINED(WINDOWS)}
+    TestD2dExe := config.ReadStr('TestRun', 'ExeWindows', GameExeFile);
+  {$ELSE}
+    TestD2dExe := config.ReadStr('TestRun', 'ExeUnix', GameExeFile);
+  {$ENDIF}
+  TestD2DArgs := config.ReadStr('TestRun', 'Args', '');
+
   RecentCount := config.ReadInt('Editor', 'RecentCount', 5);
   if RecentCount > 10 then
     RecentCount := 10;
   RecentCount := config.ReadInt('Editor', 'RecentCount', 5);
   if RecentCount > 10 then
     RecentCount := 10;
@@ -2746,7 +2854,11 @@ begin
   RecentFiles := TStringList.Create();
   for i := 0 to RecentCount-1 do
   begin
   RecentFiles := TStringList.Create();
   for i := 0 to RecentCount-1 do
   begin
-    s := config.ReadStr('RecentFiles', IntToStr(i+1), '');
+    {$IFDEF WINDOWS}
+      s := config.ReadStr('RecentFilesWin', IntToStr(i), '');
+    {$ELSE}
+      s := config.ReadStr('RecentFilesUnix', IntToStr(i), '');
+    {$ENDIF}
     if s <> '' then
       RecentFiles.Add(s);
   end;
     if s <> '' then
       RecentFiles.Add(s);
   end;
@@ -2757,7 +2869,7 @@ begin
   tbShowMap.Down := ShowMap;
   tbGridOn.Down := DotEnable;
   pcObjects.ActivePageIndex := 0;
   tbShowMap.Down := ShowMap;
   tbGridOn.Down := DotEnable;
   pcObjects.ActivePageIndex := 0;
-  Application.Title := _lc[I_EDITOR_TITLE];
+  Application.Title := MsgEditorTitle;
 
   Application.OnIdle := OnIdle;
 end;
 
   Application.OnIdle := OnIdle;
 end;
@@ -2768,6 +2880,23 @@ begin
   e_TextureFontPrintEx(X, Y, Text, FontID, 0, 0, 0, 1.0);
 end;
 
   e_TextureFontPrintEx(X, Y, Text, FontID, 0, 0, 0, 1.0);
 end;
 
+procedure InitGraphics;
+begin
+  // FIXME: this is a shitty hack
+  if not gDataLoaded then
+  begin
+    e_WriteLog('Init OpenGL', MSG_NOTIFY);
+    e_InitGL();
+    e_WriteLog('Loading data', MSG_NOTIFY);
+    LoadStdFont('STDTXT', 'STDFONT', gEditorFont);
+    e_WriteLog('Loading more data', MSG_NOTIFY);
+    LoadData();
+    e_WriteLog('Loading even more data', MSG_NOTIFY);
+    gDataLoaded := True;
+    MainForm.FormResize(nil);
+  end;
+end;
+
 procedure TMainForm.Draw();
 var
   x, y: Integer;
 procedure TMainForm.Draw();
 var
   x, y: Integer;
@@ -2778,11 +2907,14 @@ var
   ObjCount: Word;
   aX, aY, aX2, aY2, XX, ScaleSz: Integer;
 begin
   ObjCount: Word;
   aX, aY, aX2, aY2, XX, ScaleSz: Integer;
 begin
+  LastDrawTime := GetTickCount64();
   ID := 0;
   PID := 0;
   Width := 0;
   Height := 0;
 
   ID := 0;
   PID := 0;
   Width := 0;
   Height := 0;
 
+  InitGraphics();
+
   e_BeginRender();
 
   e_Clear(GL_COLOR_BUFFER_BIT,
   e_BeginRender();
 
   e_Clear(GL_COLOR_BUFFER_BIT,
@@ -2834,12 +2966,23 @@ begin
     else
       a := 0;
 
     else
       a := 0;
 
-    for x := 0 to (RenderPanel.Width div DotStep) do
-      for y := 0 to (RenderPanel.Height div DotStep) do
-        e_DrawPoint(DotSize, x*DotStep + a, y*DotStep + a,
-                    GetRValue(DotColor),
-                    GetGValue(DotColor),
-                    GetBValue(DotColor));
+    glDisable(GL_TEXTURE_2D);
+    glColor3ub(GetRValue(DotColor), GetGValue(DotColor), GetBValue(DotColor));
+    glPointSize(DotSize);
+    glBegin(GL_POINTS);
+    x := MapOffset.X mod DotStep;
+    while x < RenderPanel.Width do
+    begin
+      y := MapOffset.Y mod DotStep;
+      while y < RenderPanel.Height do
+      begin
+        glVertex2i(x + a, y + a);
+        y += DotStep;
+      end;
+      x += DotStep;
+    end;
+    glEnd();
+    glColor4ub(e_Colors.R, e_Colors.G, e_Colors.B, 255);
   end;
 
 // Превью текстуры:
   end;
 
 // Превью текстуры:
@@ -2874,7 +3017,7 @@ begin
 
     e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 192, 192, 192, 127);
     e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 255, 255, 255);
 
     e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 192, 192, 192, 127);
     e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 255, 255, 255);
-    PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_TELEPORT], gEditorFont);
+    PrintBlack(MousePos.X+2, MousePos.Y+2, utf8to1251(MsgHintTeleport), gEditorFont);
   end;
 
 // Подсказка при выборе точки появления:
   end;
 
 // Подсказка при выборе точки появления:
@@ -2885,7 +3028,7 @@ begin
                0, 0, 255);
     e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 192, 192, 192, 127);
     e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 255, 255, 255);
                0, 0, 255);
     e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 192, 192, 192, 127);
     e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 255, 255, 255);
-    PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_SPAWN], gEditorFont);
+    PrintBlack(MousePos.X+2, MousePos.Y+2, utf8to1251(MsgHintSpawn), gEditorFont);
   end;
 
 // Подсказка при выборе панели двери:
   end;
 
 // Подсказка при выборе панели двери:
@@ -2893,7 +3036,7 @@ begin
   begin
     e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 192, 192, 192, 127);
     e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 255, 255, 255);
   begin
     e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 192, 192, 192, 127);
     e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 255, 255, 255);
-    PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_PANEL_DOOR], gEditorFont);
+    PrintBlack(MousePos.X+2, MousePos.Y+2, utf8to1251(MsgHintPanelDoor), gEditorFont);
   end;
 
 // Подсказка при выборе панели с текстурой:
   end;
 
 // Подсказка при выборе панели с текстурой:
@@ -2901,7 +3044,7 @@ begin
   begin
     e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+196, MousePos.Y+18, 192, 192, 192, 127);
     e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+196, MousePos.Y+18, 255, 255, 255);
   begin
     e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+196, MousePos.Y+18, 192, 192, 192, 127);
     e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+196, MousePos.Y+18, 255, 255, 255);
-    PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_PANEL_TEXTURE], gEditorFont);
+    PrintBlack(MousePos.X+2, MousePos.Y+2, utf8to1251(MsgHintPanelTexture), gEditorFont);
   end;
 
 // Подсказка при выборе панели индикации выстрела:
   end;
 
 // Подсказка при выборе панели индикации выстрела:
@@ -2909,7 +3052,7 @@ begin
   begin
     e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+316, MousePos.Y+18, 192, 192, 192, 127);
     e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+316, MousePos.Y+18, 255, 255, 255);
   begin
     e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+316, MousePos.Y+18, 192, 192, 192, 127);
     e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+316, MousePos.Y+18, 255, 255, 255);
-    PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_PANEL_SHOT], gEditorFont);
+    PrintBlack(MousePos.X+2, MousePos.Y+2, utf8to1251(MsgHintPanelShot), gEditorFont);
   end;
 
 // Подсказка при выборе панели лифта:
   end;
 
 // Подсказка при выборе панели лифта:
@@ -2917,7 +3060,7 @@ begin
   begin
     e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 192, 192, 192, 127);
     e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 255, 255, 255);
   begin
     e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 192, 192, 192, 127);
     e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 255, 255, 255);
-    PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_PANEL_LIFT], gEditorFont);
+    PrintBlack(MousePos.X+2, MousePos.Y+2, utf8to1251(MsgHintPanelLift), gEditorFont);
   end;
 
 // Подсказка при выборе монстра:
   end;
 
 // Подсказка при выборе монстра:
@@ -2925,7 +3068,7 @@ begin
   begin
     e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+120, MousePos.Y+18, 192, 192, 192, 127);
     e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+120, MousePos.Y+18, 255, 255, 255);
   begin
     e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+120, MousePos.Y+18, 192, 192, 192, 127);
     e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+120, MousePos.Y+18, 255, 255, 255);
-    PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_MONSTER], gEditorFont);
+    PrintBlack(MousePos.X+2, MousePos.Y+2, utf8to1251(MsgHintMonster), gEditorFont);
   end;
 
 // Подсказка при выборе области воздействия:
   end;
 
 // Подсказка при выборе области воздействия:
@@ -2933,7 +3076,7 @@ begin
   begin
     e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+204, MousePos.Y+18, 192, 192, 192, 127);
     e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+204, MousePos.Y+18, 255, 255, 255);
   begin
     e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+204, MousePos.Y+18, 192, 192, 192, 127);
     e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+204, MousePos.Y+18, 255, 255, 255);
-    PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_EXT_AREA], gEditorFont);
+    PrintBlack(MousePos.X+2, MousePos.Y+2, utf8to1251(MsgHintExtArea), gEditorFont);
   end;
 
 // Рисуем текстуры, если чертим панель:
   end;
 
 // Рисуем текстуры, если чертим панель:
@@ -2945,8 +3088,9 @@ begin
       g_GetTexture('NOTEXTURE', ID);
     g_GetTextureSizeByID(ID, Width, Height);
     with DrawRect^ do
       g_GetTexture('NOTEXTURE', ID);
     g_GetTextureSizeByID(ID, Width, Height);
     with DrawRect^ do
-      e_DrawFill(ID, Min(Left, Right), Min(Top, Bottom), Abs(Right-Left) div Width,
-                 Abs(Bottom-Top) div Height, 0, True, False);
+      if (Abs(Right-Left) >= Width) and (Abs(Bottom-Top) >= Height) then
+        e_DrawFill(ID, Min(Left, Right), Min(Top, Bottom), Abs(Right-Left) div Width,
+                   Abs(Bottom-Top) div Height, 64, True, False);
   end;
 
 // Прямоугольник выделения:
   end;
 
 // Прямоугольник выделения:
@@ -2955,7 +3099,8 @@ begin
       e_DrawQuad(Left, Top, Right-1, Bottom-1, 255, 255, 255);
 
 // Чертим мышью панель/триггер или меняем мышью их размер:
       e_DrawQuad(Left, Top, Right-1, Bottom-1, 255, 255, 255);
 
 // Чертим мышью панель/триггер или меняем мышью их размер:
-  if (MouseAction in [MOUSEACTION_DRAWPANEL, MOUSEACTION_DRAWTRIGGER, MOUSEACTION_RESIZE]) and
+  if (((MouseAction in [MOUSEACTION_DRAWPANEL, MOUSEACTION_DRAWTRIGGER]) and
+     not(ssCtrl in GetKeyShiftState())) or (MouseAction = MOUSEACTION_RESIZE)) and
      (DrawPanelSize) then
   begin
     e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+88, MousePos.Y+33, 192, 192, 192, 127);
      (DrawPanelSize) then
   begin
     e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+88, MousePos.Y+33, 192, 192, 192, 127);
@@ -2963,9 +3108,9 @@ begin
 
     if MouseAction in [MOUSEACTION_DRAWPANEL, MOUSEACTION_DRAWTRIGGER] then
       begin // Чертим новый
 
     if MouseAction in [MOUSEACTION_DRAWPANEL, MOUSEACTION_DRAWTRIGGER] then
       begin // Чертим новый
-        PrintBlack(MousePos.X+2, MousePos.Y+2, Format(_glc[I_HINT_WIDTH],
+        PrintBlack(MousePos.X+2, MousePos.Y+2, Format(utf8to1251(MsgHintWidth),
                           [Abs(MousePos.X-MouseLDownPos.X)]), gEditorFont);
                           [Abs(MousePos.X-MouseLDownPos.X)]), gEditorFont);
-        PrintBlack(MousePos.X+2, MousePos.Y+14, Format(_glc[I_HINT_HEIGHT],
+        PrintBlack(MousePos.X+2, MousePos.Y+16, Format(utf8to1251(MsgHintHeight),
                           [Abs(MousePos.Y-MouseLDownPos.Y)]), gEditorFont);
       end
     else // Растягиваем существующий
                           [Abs(MousePos.Y-MouseLDownPos.Y)]), gEditorFont);
       end
     else // Растягиваем существующий
@@ -2982,9 +3127,9 @@ begin
             Height := gTriggers[SelectedObjects[GetFirstSelected].ID].Height;
           end;
 
             Height := gTriggers[SelectedObjects[GetFirstSelected].ID].Height;
           end;
 
-        PrintBlack(MousePos.X+2, MousePos.Y+2, Format(_glc[I_HINT_WIDTH], [Width]),
+        PrintBlack(MousePos.X+2, MousePos.Y+2, Format(utf8to1251(MsgHintWidth), [Width]),
                           gEditorFont);
                           gEditorFont);
-        PrintBlack(MousePos.X+2, MousePos.Y+14, Format(_glc[I_HINT_HEIGHT], [Height]),
+        PrintBlack(MousePos.X+2, MousePos.Y+16, Format(utf8to1251(MsgHintHeight), [Height]),
                           gEditorFont);
       end;
   end;
                           gEditorFont);
       end;
   end;
@@ -3088,18 +3233,31 @@ procedure TMainForm.FormResize(Sender: TObject);
 begin
   e_SetViewPort(0, 0, RenderPanel.Width, RenderPanel.Height);
 
 begin
   e_SetViewPort(0, 0, RenderPanel.Width, RenderPanel.Height);
 
-  if gMapInfo.Width >= RenderPanel.Width then
-    sbHorizontal.Max := Normalize16(gMapInfo.Width-RenderPanel.Width+16)
-  else
-    sbHorizontal.Max := 0;
+  sbHorizontal.Min := Min(gMapInfo.Width - RenderPanel.Width, -RenderPanel.Width div 2);
+  sbHorizontal.Max := Max(0, gMapInfo.Width - RenderPanel.Width div 2);
+  sbVertical.Min := Min(gMapInfo.Height - RenderPanel.Height, -RenderPanel.Height div 2);
+  sbVertical.Max := Max(0, gMapInfo.Height - RenderPanel.Height div 2);
 
 
-  if gMapInfo.Height >= RenderPanel.Height then
-    sbVertical.Max := Normalize16(gMapInfo.Height-RenderPanel.Height+16)
-  else
-    sbVertical.Max := 0;
+  MapOffset.X := -sbHorizontal.Position;
+  MapOffset.Y := -sbVertical.Position;
+end;
 
 
-  MapOffset.X := -Normalize16(sbHorizontal.Position);
-  MapOffset.Y := -Normalize16(sbVertical.Position);
+procedure TMainForm.FormWindowStateChange(Sender: TObject);
+  {$IFDEF DARWIN}
+    var e: Boolean;
+  {$ENDIF}
+begin
+  {$IFDEF DARWIN}
+    // deactivate all menus when main window minimized
+    e := self.WindowState <> wsMinimized;
+    miMenuFile.Enabled := e;
+    miMenuEdit.Enabled := e;
+    miMenuView.Enabled := e;
+    miMenuService.Enabled := e;
+    miMenuWindow.Enabled := e;
+    miMenuHelp.Enabled := e;
+    miMenuHidden.Enabled := e;
+  {$ENDIF}
 end;
 
 procedure SelectNextObject(X, Y: Integer; ObjectType: Byte; ID: DWORD);
 end;
 
 procedure SelectNextObject(X, Y: Integer; ObjectType: Byte; ID: DWORD);
@@ -3258,11 +3416,11 @@ begin
           case pcObjects.ActivePageIndex of
             1:
               if lbItemList.ItemIndex = -1 then
           case pcObjects.ActivePageIndex of
             1:
               if lbItemList.ItemIndex = -1 then
-                ErrorMessageBox(_lc[I_MSG_CHOOSE_ITEM])
+                ErrorMessageBox(MsgMsgChooseItem)
               else
                 begin
                   item.ItemType := lbItemList.ItemIndex + ITEM_MEDKIT_SMALL;
               else
                 begin
                   item.ItemType := lbItemList.ItemIndex + ITEM_MEDKIT_SMALL;
-                  if item.ItemType >= ITEM_WEAPON_KASTET then
+                  if item.ItemType >= ITEM_WEAPON_IRONFIST then
                     item.ItemType := item.ItemType + 2;
                   item.X := MousePos.X-MapOffset.X;
                   item.Y := MousePos.Y-MapOffset.Y;
                     item.ItemType := item.ItemType + 2;
                   item.X := MousePos.X-MapOffset.X;
                   item.Y := MousePos.Y-MapOffset.Y;
@@ -3279,7 +3437,7 @@ begin
                 end;
             2:
               if lbMonsterList.ItemIndex = -1 then
                 end;
             2:
               if lbMonsterList.ItemIndex = -1 then
-                ErrorMessageBox(_lc[I_MSG_CHOOSE_MONSTER])
+                ErrorMessageBox(MsgMsgChooseMonster)
               else
                 begin
                   monster.MonsterType := lbMonsterList.ItemIndex + MONSTER_DEMON;
               else
                 begin
                   monster.MonsterType := lbMonsterList.ItemIndex + MONSTER_DEMON;
@@ -3300,7 +3458,7 @@ begin
                 end;
             3:
               if lbAreasList.ItemIndex = -1 then
                 end;
             3:
               if lbAreasList.ItemIndex = -1 then
-                ErrorMessageBox(_lc[I_MSG_CHOOSE_AREA])
+                ErrorMessageBox(MsgMsgChooseArea)
               else
                 if (lbAreasList.ItemIndex + 1) <> AREA_DOMFLAG then
                   begin
               else
                 if (lbAreasList.ItemIndex + 1) <> AREA_DOMFLAG then
                   begin
@@ -3590,6 +3748,16 @@ begin
         end;
   end; // if Button = mbRight
 
         end;
   end; // if Button = mbRight
 
+  if Button = mbMiddle then // Middle Mouse Button
+  begin
+    SetCapture(RenderPanel.Handle);
+    RenderPanel.Cursor := crSize;
+  end;
+
+  MouseMDown := Button = mbMiddle;
+  if MouseMDown then
+    MouseMDownPos := Mouse.CursorPos;
+
   MouseRDown := Button = mbRight;
   if MouseRDown then
     MouseRDownPos := MousePos;
   MouseRDown := Button = mbRight;
   if MouseRDown then
     MouseRDownPos := MousePos;
@@ -3604,26 +3772,51 @@ procedure TMainForm.RenderPanelMouseUp(Sender: TObject;
 var
   panel: TPanel;
   trigger: TTrigger;
 var
   panel: TPanel;
   trigger: TTrigger;
-  i: Integer;
-  IDArray: DWArray;
   rRect: TRectWH;
   rSelectRect: Boolean;
   rRect: TRectWH;
   rSelectRect: Boolean;
+  wWidth, wHeight: Word;
+  TextureID: DWORD;
+
+  procedure SelectObjects(ObjectType: Byte);
+  var
+    i: Integer;
+    IDArray: DWArray;
+  begin
+    IDArray := ObjectInRect(rRect.X, rRect.Y,
+                 rRect.Width, rRect.Height,
+                 ObjectType, rSelectRect);
+
+    if IDArray <> nil then
+      for i := 0 to High(IDArray) do
+        SelectObject(ObjectType, IDArray[i], (ssCtrl in Shift) or rSelectRect);
+  end;
 begin
   if Button = mbLeft then
     MouseLDown := False;
   if Button = mbRight then
     MouseRDown := False;
 begin
   if Button = mbLeft then
     MouseLDown := False;
   if Button = mbRight then
     MouseRDown := False;
+  if Button = mbMiddle then
+    MouseMDown := False;
+
+  if DrawRect <> nil then
+  begin
+    Dispose(DrawRect);
+    DrawRect := nil;
+  end;
 
 
-  DrawRect := nil;
   ResizeType := RESIZETYPE_NONE;
   ResizeType := RESIZETYPE_NONE;
+  TextureID := 0;
 
   if Button = mbLeft then // Left Mouse Button
     begin
       if MouseAction <> MOUSEACTION_NONE then
       begin // Было действие мышью
 
   if Button = mbLeft then // Left Mouse Button
     begin
       if MouseAction <> MOUSEACTION_NONE then
       begin // Было действие мышью
-      // Мышь сдвинулась во время удержания клавиши:
-        if (MousePos.X <> MouseLDownPos.X) and
-           (MousePos.Y <> MouseLDownPos.Y) then
+      // Мышь сдвинулась во время удержания клавиши,
+      // либо активирован режим быстрого рисования:
+        if ((MousePos.X <> MouseLDownPos.X) and
+           (MousePos.Y <> MouseLDownPos.Y)) or
+           ((MouseAction in [MOUSEACTION_DRAWPANEL, MOUSEACTION_DRAWTRIGGER]) and
+           (ssCtrl in Shift)) then
           case MouseAction of
           // Рисовали панель:
             MOUSEACTION_DRAWPANEL:
           case MouseAction of
           // Рисовали панель:
             MOUSEACTION_DRAWPANEL:
@@ -3631,7 +3824,7 @@ begin
               // Фон или передний план без текстуры - ошибка:
                 if (lbPanelType.ItemIndex in [1, 2]) and
                    (lbTextureList.ItemIndex = -1) then
               // Фон или передний план без текстуры - ошибка:
                 if (lbPanelType.ItemIndex in [1, 2]) and
                    (lbTextureList.ItemIndex = -1) then
-                  ErrorMessageBox(_lc[I_MSG_CHOOSE_TEXTURE])
+                  ErrorMessageBox(MsgMsgChooseTexture)
                 else // Назначаем параметры панели:
                   begin
                     case lbPanelType.ItemIndex of
                 else // Назначаем параметры панели:
                   begin
                     case lbPanelType.ItemIndex of
@@ -3653,8 +3846,25 @@ begin
 
                     Panel.X := Min(MousePos.X-MapOffset.X, MouseLDownPos.X-MapOffset.X);
                     Panel.Y := Min(MousePos.Y-MapOffset.Y, MouseLDownPos.Y-MapOffset.Y);
 
                     Panel.X := Min(MousePos.X-MapOffset.X, MouseLDownPos.X-MapOffset.X);
                     Panel.Y := Min(MousePos.Y-MapOffset.Y, MouseLDownPos.Y-MapOffset.Y);
-                    Panel.Width := Abs(MousePos.X-MouseLDownPos.X);
-                    Panel.Height := Abs(MousePos.Y-MouseLDownPos.Y);
+                    if ssCtrl in Shift then
+                      begin
+                        wWidth := DotStep;
+                        wHeight := DotStep;
+                        if (lbTextureList.ItemIndex <> -1) and
+                           (not IsSpecialTextureSel()) then
+                        begin
+                          if not g_GetTexture(SelectedTexture(), TextureID) then
+                            g_GetTexture('NOTEXTURE', TextureID);
+                          g_GetTextureSizeByID(TextureID, wWidth, wHeight);
+                        end;
+                        Panel.Width := wWidth;
+                        Panel.Height := wHeight;
+                      end
+                    else
+                      begin
+                        Panel.Width := Abs(MousePos.X-MouseLDownPos.X);
+                        Panel.Height := Abs(MousePos.Y-MouseLDownPos.Y);
+                      end;
 
                   // Лифты, блокМон или отсутствие текстуры - пустая текстура:
                     if (lbPanelType.ItemIndex in [9, 10, 11, 12, 13]) or
 
                   // Лифты, блокМон или отсутствие текстуры - пустая текстура:
                     if (lbPanelType.ItemIndex in [9, 10, 11, 12, 13]) or
@@ -3696,8 +3906,18 @@ begin
               begin
                 trigger.X := Min(MousePos.X-MapOffset.X, MouseLDownPos.X-MapOffset.X);
                 trigger.Y := Min(MousePos.Y-MapOffset.Y, MouseLDownPos.Y-MapOffset.Y);
               begin
                 trigger.X := Min(MousePos.X-MapOffset.X, MouseLDownPos.X-MapOffset.X);
                 trigger.Y := Min(MousePos.Y-MapOffset.Y, MouseLDownPos.Y-MapOffset.Y);
-                trigger.Width := Abs(MousePos.X-MouseLDownPos.X);
-                trigger.Height := Abs(MousePos.Y-MouseLDownPos.Y);
+                if ssCtrl in Shift then
+                  begin
+                    wWidth := DotStep;
+                    wHeight := DotStep;
+                    trigger.Width := wWidth;
+                    trigger.Height := wHeight;
+                  end
+                else
+                  begin
+                    trigger.Width := Abs(MousePos.X-MouseLDownPos.X);
+                    trigger.Height := Abs(MousePos.Y-MouseLDownPos.Y);
+                  end;
 
                 trigger.Enabled := True;
                 trigger.TriggerType := lbTriggersList.ItemIndex+1;
 
                 trigger.Enabled := True;
                 trigger.TriggerType := lbTriggersList.ItemIndex+1;
@@ -3891,7 +4111,7 @@ begin
         MouseAction := MOUSEACTION_NONE;
       end;
     end // if Button = mbLeft...
         MouseAction := MOUSEACTION_NONE;
       end;
     end // if Button = mbLeft...
-  else // Right Mouse Button:
+  else if Button = mbRight then // Right Mouse Button:
     begin
       if MouseAction = MOUSEACTION_NOACTION then
       begin
     begin
       if MouseAction = MOUSEACTION_NOACTION then
       begin
@@ -3902,6 +4122,7 @@ begin
     // Объект передвинут или изменен в размере:
       if MouseAction in [MOUSEACTION_MOVEOBJ, MOUSEACTION_RESIZE] then
       begin
     // Объект передвинут или изменен в размере:
       if MouseAction in [MOUSEACTION_MOVEOBJ, MOUSEACTION_RESIZE] then
       begin
+        RenderPanel.Cursor := crDefault;
         MouseAction := MOUSEACTION_NONE;
         FillProperty();
         Exit;
         MouseAction := MOUSEACTION_NONE;
         FillProperty();
         Exit;
@@ -3942,16 +4163,24 @@ begin
         RemoveSelectFromObjects();
 
     // Выделяем всё в выбранном прямоугольнике:
         RemoveSelectFromObjects();
 
     // Выделяем всё в выбранном прямоугольнике:
-      IDArray := ObjectInRect(rRect.X, rRect.Y,
-                   rRect.Width, rRect.Height,
-                   pcObjects.ActivePageIndex+1, rSelectRect);
-
-      if IDArray <> nil then
-        for i := 0 to High(IDArray) do
-          SelectObject(pcObjects.ActivePageIndex+1, IDArray[i],
-            (ssCtrl in Shift) or rSelectRect);
+      if (ssCtrl in Shift) and (ssAlt in Shift) then
+        begin
+          SelectObjects(OBJECT_PANEL);
+          SelectObjects(OBJECT_ITEM);
+          SelectObjects(OBJECT_MONSTER);
+          SelectObjects(OBJECT_AREA);
+          SelectObjects(OBJECT_TRIGGER);
+        end
+      else
+        SelectObjects(pcObjects.ActivePageIndex+1);
 
       FillProperty();
 
       FillProperty();
+    end
+
+  else // Middle Mouse Button
+    begin
+      RenderPanel.Cursor := crDefault;
+      ReleaseCapture();
     end;
 end;
 
     end;
 end;
 
@@ -3960,14 +4189,30 @@ begin
   Draw();
 end;
 
   Draw();
 end;
 
+function TMainForm.RenderMousePos(): Types.TPoint;
+begin
+  Result := RenderPanel.ScreenToClient(Mouse.CursorPos);
+end;
+
+procedure TMainForm.RecountSelectedObjects();
+begin
+  if SelectedObjectCount() = 0 then
+    StatusBar.Panels[0].Text := ''
+  else
+    StatusBar.Panels[0].Text := Format(MsgCapStatSelected, [SelectedObjectCount()]);
+end;
+
 procedure TMainForm.RenderPanelMouseMove(Sender: TObject;
   Shift: TShiftState; X, Y: Integer);
 var
   sX, sY: Integer;
   dWidth, dHeight: Integer;
   _id: Integer;
 procedure TMainForm.RenderPanelMouseMove(Sender: TObject;
   Shift: TShiftState; X, Y: Integer);
 var
   sX, sY: Integer;
   dWidth, dHeight: Integer;
   _id: Integer;
+  TextureID: DWORD;
+  wWidth, wHeight: Word;
 begin
   _id := GetFirstSelected();
 begin
   _id := GetFirstSelected();
+  TextureID := 0;
 
 // Рисуем панель с текстурой, сетка - размеры текстуры:
   if (MouseAction = MOUSEACTION_DRAWPANEL) and
 
 // Рисуем панель с текстурой, сетка - размеры текстуры:
   if (MouseAction = MOUSEACTION_DRAWPANEL) and
@@ -4016,16 +4261,12 @@ begin
       end
     else
       begin // Кнопки мыши не зажаты
       end
     else
       begin // Кнопки мыши не зажаты
-        MousePos.X := (Round(X/sX)*sX);
-        MousePos.Y := (Round(Y/sY)*sY);
+        MousePos.X := Round((-MapOffset.X + X) / sX) * sX + MapOffset.X;
+        MousePos.Y := Round((-MapOffset.Y + Y) / sY) * sY + MapOffset.Y;
       end;
 
       end;
 
-// Изменение размера закончилось - ставим обычный курсор:
-  if ResizeType = RESIZETYPE_NONE then
-    RenderPanel.Cursor := crDefault;
-
 // Зажата только правая кнопка мыши:
 // Зажата только правая кнопка мыши:
-  if (not MouseLDown) and (MouseRDown) then
+  if (not MouseLDown) and (MouseRDown) and (not MouseMDown) then
   begin
   // Рисуем прямоугольник выделения:
     if MouseAction = MOUSEACTION_NONE then
   begin
   // Рисуем прямоугольник выделения:
     if MouseAction = MOUSEACTION_NONE then
@@ -4042,10 +4283,8 @@ begin
       if MouseAction = MOUSEACTION_MOVEOBJ then
         begin
           MoveSelectedObjects(ssShift in Shift, ssCtrl in Shift,
       if MouseAction = MOUSEACTION_MOVEOBJ then
         begin
           MoveSelectedObjects(ssShift in Shift, ssCtrl in Shift,
-                              MousePos.X-LastMovePoint.X+WASDOffset.X,
-                              MousePos.Y-LastMovePoint.Y+WASDOffset.Y);
-          WASDOffset.X := 0;
-          WASDOffset.Y := 0;
+                              MousePos.X-LastMovePoint.X,
+                              MousePos.Y-LastMovePoint.Y);
         end
       else
       // Меняем размер выделенного объекта:
         end
       else
       // Меняем размер выделенного объекта:
@@ -4054,10 +4293,8 @@ begin
           if (SelectedObjectCount = 1) and
              (SelectedObjects[GetFirstSelected].Live) then
           begin
           if (SelectedObjectCount = 1) and
              (SelectedObjects[GetFirstSelected].Live) then
           begin
-            dWidth := MousePos.X-LastMovePoint.X+WASDOffset.X;
-            dHeight := MousePos.Y-LastMovePoint.Y+WASDOffset.Y;
-            WASDOffset.X := 0;
-            WASDOffset.Y := 0;
+            dWidth := MousePos.X-LastMovePoint.X;
+            dHeight := MousePos.Y-LastMovePoint.Y;
 
             case ResizeType of
               RESIZETYPE_VERTICAL: dWidth := 0;
 
             case ResizeType of
               RESIZETYPE_VERTICAL: dWidth := 0;
@@ -4069,17 +4306,16 @@ begin
               RESIZEDIR_LEFT: dWidth := -dWidth;
             end;
 
               RESIZEDIR_LEFT: dWidth := -dWidth;
             end;
 
-            ResizeObject(SelectedObjects[GetFirstSelected].ObjectType,
-                         SelectedObjects[GetFirstSelected].ID,
-                         dWidth, dHeight, ResizeDirection);
-
-            LastMovePoint := MousePos;
+            if ResizeObject(SelectedObjects[GetFirstSelected].ObjectType,
+                           SelectedObjects[GetFirstSelected].ID,
+                           dWidth, dHeight, ResizeDirection) then
+              LastMovePoint := MousePos;
           end;
         end;
   end;
 
 // Зажата только левая кнопка мыши:
           end;
         end;
   end;
 
 // Зажата только левая кнопка мыши:
-  if (not MouseRDown) and (MouseLDown) then
+  if (not MouseRDown) and (MouseLDown) and (not MouseMDown) then
   begin
   // Рисуем прямоугольник планирования панели:
     if MouseAction in [MOUSEACTION_DRAWPANEL,
   begin
   // Рисуем прямоугольник планирования панели:
     if MouseAction in [MOUSEACTION_DRAWPANEL,
@@ -4088,10 +4324,29 @@ begin
       begin
         if DrawRect = nil then
           New(DrawRect);
       begin
         if DrawRect = nil then
           New(DrawRect);
-        DrawRect.Top := MouseLDownPos.y;
-        DrawRect.Left := MouseLDownPos.x;
-        DrawRect.Bottom := MousePos.y;
-        DrawRect.Right := MousePos.x;
+        if ssCtrl in Shift then
+          begin
+            wWidth := DotStep;
+            wHeight := DotStep;
+            if (lbTextureList.ItemIndex <> -1) and (not IsSpecialTextureSel()) and
+               (MouseAction = MOUSEACTION_DRAWPANEL) then
+            begin
+              if not g_GetTexture(SelectedTexture(), TextureID) then
+                g_GetTexture('NOTEXTURE', TextureID);
+              g_GetTextureSizeByID(TextureID, wWidth, wHeight);
+            end;
+            DrawRect.Top := MouseLDownPos.y;
+            DrawRect.Left := MouseLDownPos.x;
+            DrawRect.Bottom := DrawRect.Top + wHeight;
+            DrawRect.Right := DrawRect.Left + wWidth;
+          end
+        else
+          begin
+            DrawRect.Top := MouseLDownPos.y;
+            DrawRect.Left := MouseLDownPos.x;
+            DrawRect.Bottom := MousePos.y;
+            DrawRect.Right := MousePos.x;
+          end;
       end
     else // Двигаем карту:
       if MouseAction = MOUSEACTION_MOVEMAP then
       end
     else // Двигаем карту:
       if MouseAction = MOUSEACTION_MOVEMAP then
@@ -4100,19 +4355,36 @@ begin
       end;
   end;
 
       end;
   end;
 
+// Only Middle Mouse Button is pressed
+  if (not MouseLDown) and (not MouseRDown) and (MouseMDown) then
+  begin
+    MapOffset.X := -EnsureRange(-MapOffset.X + MouseMDownPos.X - Mouse.CursorPos.X,
+                                sbHorizontal.Min, sbHorizontal.Max);
+    sbHorizontal.Position := -MapOffset.X;
+    MapOffset.Y := -EnsureRange(-MapOffset.Y + MouseMDownPos.Y - Mouse.CursorPos.Y,
+                                sbVertical.Min, sbVertical.Max);
+    sbVertical.Position := -MapOffset.Y;
+    MouseMDownPos := Mouse.CursorPos;
+  end;
+
 // Клавиши мыши не зажаты:
 // Клавиши мыши не зажаты:
-  if (not MouseRDown) and (not MouseLDown) then
+  if (not MouseRDown) and (not MouseLDown) and (DrawRect <> nil) then
+  begin
+    Dispose(DrawRect);
     DrawRect := nil;
     DrawRect := nil;
+  end;
 
 // Строка состояния - координаты мыши:
   StatusBar.Panels[1].Text := Format('(%d:%d)',
     [MousePos.X-MapOffset.X, MousePos.Y-MapOffset.Y]);
 
 // Строка состояния - координаты мыши:
   StatusBar.Panels[1].Text := Format('(%d:%d)',
     [MousePos.X-MapOffset.X, MousePos.Y-MapOffset.Y]);
+
+  RenderPanel.Invalidate;
 end;
 
 procedure TMainForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
 begin
 end;
 
 procedure TMainForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
 begin
-  CanClose := MessageBox(0, PChar(_lc[I_MSG_EXIT_PROMT]),
-                         PChar(_lc[I_MSG_EXIT]),
+  CanClose := Application.MessageBox(PChar(MsgMsgExitPrompt),
+                         PChar(MsgMsgExit),
                          MB_ICONQUESTION or MB_YESNO or
                          MB_DEFBUTTON1) = idYes;
 end;
                          MB_ICONQUESTION or MB_YESNO or
                          MB_DEFBUTTON1) = idYes;
 end;
@@ -4125,9 +4397,12 @@ end;
 procedure TMainForm.FormDestroy(Sender: TObject);
 var
   config: TConfig;
 procedure TMainForm.FormDestroy(Sender: TObject);
 var
   config: TConfig;
+  s: AnsiString;
   i: Integer;
 begin
   i: Integer;
 begin
-  config := TConfig.CreateFile(EditorDir+'Editor.cfg');
+  config := TConfig.CreateFile(CfgFileName);
+
+  config.WriteInt('WADEditor', 'LogLevel', gWADEditorLogLevel);
 
   if WindowState <> wsMaximized then
   begin
 
   if WindowState <> wsMaximized then
   begin
@@ -4151,23 +4426,31 @@ begin
   config.WriteInt('Editor', 'DotStep', DotStep);
   config.WriteStr('Editor', 'LastOpenDir', OpenDialog.InitialDir);
   config.WriteStr('Editor', 'LastSaveDir', SaveDialog.InitialDir);
   config.WriteInt('Editor', 'DotStep', DotStep);
   config.WriteStr('Editor', 'LastOpenDir', OpenDialog.InitialDir);
   config.WriteStr('Editor', 'LastSaveDir', SaveDialog.InitialDir);
+  config.WriteStr('Editor', 'Language', gLanguage);
   config.WriteBool('Editor', 'EdgeShow', drEdge[3] < 255);
   config.WriteInt('Editor', 'EdgeColor', gColorEdge);
   config.WriteInt('Editor', 'EdgeAlpha', gAlphaEdge);
   config.WriteInt('Editor', 'LineAlpha', gAlphaTriggerLine);
   config.WriteInt('Editor', 'TriggerAlpha', gAlphaTriggerArea);
   config.WriteBool('Editor', 'EdgeShow', drEdge[3] < 255);
   config.WriteInt('Editor', 'EdgeColor', gColorEdge);
   config.WriteInt('Editor', 'EdgeAlpha', gAlphaEdge);
   config.WriteInt('Editor', 'LineAlpha', gAlphaTriggerLine);
   config.WriteInt('Editor', 'TriggerAlpha', gAlphaTriggerArea);
+  config.WriteInt('Editor', 'MonsterRectAlpha', gAlphaMonsterRect);
+  config.WriteInt('Editor', 'AreaRectAlpha', gAlphaAreaRect);
 
 
-  for i := 0 to RecentCount-1 do
-    if i < RecentFiles.Count then
-      config.WriteStr('RecentFiles', IntToStr(i+1), RecentFiles[i])
-    else
-      config.WriteStr('RecentFiles', IntToStr(i+1), '');
+  for i := 0 to RecentCount - 1 do
+  begin
+    if i < RecentFiles.Count then s := RecentFiles[i] else s := '';
+    {$IFDEF WINDOWS}
+      config.WriteStr('RecentFilesWin', IntToStr(i), s);
+    {$ELSE}
+      config.WriteStr('RecentFilesUnix', IntToStr(i), s);
+    {$ENDIF}
+  end;
   RecentFiles.Free();
 
   RecentFiles.Free();
 
-  config.SaveFile(EditorDir+'Editor.cfg');
+  config.SaveFile(CfgFileName);
   config.Free();
 
   config.Free();
 
-  slInvalidTextures.Free;
+  slInvalidTextures.Free();
+  DiscardUndoBuffer();
 end;
 
 procedure TMainForm.FormDropFiles(Sender: TObject;
 end;
 
 procedure TMainForm.FormDropFiles(Sender: TObject;
@@ -4190,6 +4473,22 @@ begin
   FormResize(Sender);
 end;
 
   FormResize(Sender);
 end;
 
+procedure TMainForm.MapTestCheck(Sender: TObject);
+begin
+  if MapTestProcess <> nil then
+  begin
+    if MapTestProcess.Running = false then
+    begin
+      if MapTestProcess.ExitCode <> 0 then
+        Application.MessageBox(PChar(MsgMsgExecError), 'FIXME', MB_OK or MB_ICONERROR);
+      SysUtils.DeleteFile(MapTestFile);
+      MapTestFile := '';
+      FreeAndNil(MapTestProcess);
+      tbTestMap.Enabled := True;
+    end;
+  end;
+end;
+
 procedure TMainForm.aMapOptionsExecute(Sender: TObject);
 var
   ResName: String;
 procedure TMainForm.aMapOptionsExecute(Sender: TObject);
 var
   ResName: String;
@@ -4208,36 +4507,54 @@ begin
   AboutForm.ShowModal();
 end;
 
   AboutForm.ShowModal();
 end;
 
-procedure TMainForm.FormKeyDown(Sender: TObject; var Key: Word;
-  Shift: TShiftState);
+procedure TMainForm.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
 var
   dx, dy, i: Integer;
   FileName: String;
 var
   dx, dy, i: Integer;
   FileName: String;
+  ok: Boolean;
 begin
   if (not EditingProperties) then
   begin
 begin
   if (not EditingProperties) then
   begin
-    if Key = Ord('1') then
-      SwitchLayer(LAYER_BACK);
-    if Key = Ord('2') then
-      SwitchLayer(LAYER_WALLS);
-    if Key = Ord('3') then
-      SwitchLayer(LAYER_FOREGROUND);
-    if Key = Ord('4') then
-      SwitchLayer(LAYER_STEPS);
-    if Key = Ord('5') then
-      SwitchLayer(LAYER_WATER);
-    if Key = Ord('6') then
-      SwitchLayer(LAYER_ITEMS);
-    if Key = Ord('7') then
-      SwitchLayer(LAYER_MONSTERS);
-    if Key = Ord('8') then
-      SwitchLayer(LAYER_AREAS);
-    if Key = Ord('9') then
-      SwitchLayer(LAYER_TRIGGERS);
-    if Key = Ord('0') then
-      tbShowClick(tbShow);
-
-    if Key = Ord('V') then
+    if ssCtrl in Shift then
+    begin
+      case Chr(Key) of
+        '1': ContourEnabled[LAYER_BACK] := not ContourEnabled[LAYER_BACK];
+        '2': ContourEnabled[LAYER_WALLS] := not ContourEnabled[LAYER_WALLS];
+        '3': ContourEnabled[LAYER_FOREGROUND] := not ContourEnabled[LAYER_FOREGROUND];
+        '4': ContourEnabled[LAYER_STEPS] := not ContourEnabled[LAYER_STEPS];
+        '5': ContourEnabled[LAYER_WATER] := not ContourEnabled[LAYER_WATER];
+        '6': ContourEnabled[LAYER_ITEMS] := not ContourEnabled[LAYER_ITEMS];
+        '7': ContourEnabled[LAYER_MONSTERS] := not ContourEnabled[LAYER_MONSTERS];
+        '8': ContourEnabled[LAYER_AREAS] := not ContourEnabled[LAYER_AREAS];
+        '9': ContourEnabled[LAYER_TRIGGERS] := not ContourEnabled[LAYER_TRIGGERS];
+        '0':
+           begin
+             ok := False;
+             for i := Low(ContourEnabled) to High(ContourEnabled) do
+               if ContourEnabled[i] then
+                 ok := True;
+             for i := Low(ContourEnabled) to High(ContourEnabled) do
+               ContourEnabled[i] := not ok
+           end
+      end
+    end
+    else
+    begin
+      case Chr(key) of
+        '1': SwitchLayer(LAYER_BACK);
+        '2': SwitchLayer(LAYER_WALLS);
+        '3': SwitchLayer(LAYER_FOREGROUND);
+        '4': SwitchLayer(LAYER_STEPS);
+        '5': SwitchLayer(LAYER_WATER);
+        '6': SwitchLayer(LAYER_ITEMS);
+        '7': SwitchLayer(LAYER_MONSTERS);
+        '8': SwitchLayer(LAYER_AREAS);
+        '9': SwitchLayer(LAYER_TRIGGERS);
+        '0': tbShowClick(tbShow);
+      end
+    end;
+
+    if Key = Ord('I') then
     begin // Поворот монстров и областей:
       if (SelectedObjects <> nil) then
       begin
     begin // Поворот монстров и областей:
       if (SelectedObjects <> nil) then
       begin
@@ -4288,24 +4605,42 @@ begin
       begin
         if Key = Ord('W') then
         begin
       begin
         if Key = Ord('W') then
         begin
-          if (MouseLDown or MouseRDown) and (Position >= DotStep) then
+          dy := Position;
+          if ssShift in Shift then Position := EnsureRange(Position - DotStep * 4, Min, Max)
+          else Position := EnsureRange(Position - DotStep, Min, Max);
+          MapOffset.Y := -Position;
+          dy -= Position;
+
+          if (MouseLDown or MouseRDown) then
           begin
           begin
-            Dec(WASDOffset.Y, DotStep);
-            RenderPanelMouseMove(Sender, Shift, LastMovePoint.X, LastMovePoint.Y);
+            if DrawRect <> nil then
+            begin
+              Inc(MouseLDownPos.y, dy);
+              Inc(MouseRDownPos.y, dy);
+            end;
+            Inc(LastMovePoint.Y, dy);
+            RenderPanelMouseMove(Sender, Shift, RenderMousePos().X, RenderMousePos().Y);
           end;
           end;
-          Position := IfThen(Position > DotStep, Position-DotStep, 0);
-          MapOffset.Y := -Round(Position/16) * 16;
         end;
 
         if Key = Ord('S') then
         begin
         end;
 
         if Key = Ord('S') then
         begin
-          if (MouseLDown or MouseRDown) and (Position+DotStep <= Max) then
+          dy := Position;
+          if ssShift in Shift then Position := EnsureRange(Position + DotStep * 4, Min, Max)
+          else Position := EnsureRange(Position + DotStep, Min, Max);
+          MapOffset.Y := -Position;
+          dy -= Position;
+
+          if (MouseLDown or MouseRDown) then
           begin
           begin
-            Inc(WASDOffset.Y, DotStep);
-            RenderPanelMouseMove(Sender, Shift, LastMovePoint.X, LastMovePoint.Y);
+            if DrawRect <> nil then
+            begin
+              Inc(MouseLDownPos.y, dy);
+              Inc(MouseRDownPos.y, dy);
+            end;
+            Inc(LastMovePoint.Y, dy);
+            RenderPanelMouseMove(Sender, Shift, RenderMousePos().X, RenderMousePos().Y);
           end;
           end;
-          Position := IfThen(Position+DotStep < Max, Position+DotStep, Max);
-          MapOffset.Y := -Round(Position/16) * 16;
         end;
       end;
 
         end;
       end;
 
@@ -4314,24 +4649,42 @@ begin
       begin
         if Key = Ord('A') then
         begin
       begin
         if Key = Ord('A') then
         begin
-          if (MouseLDown or MouseRDown) and (Position >= DotStep) then
+          dx := Position;
+          if ssShift in Shift then Position := EnsureRange(Position - DotStep * 4, Min, Max)
+          else Position := EnsureRange(Position - DotStep, Min, Max);
+          MapOffset.X := -Position;
+          dx -= Position;
+
+          if (MouseLDown or MouseRDown) then
           begin
           begin
-            Dec(WASDOffset.X, DotStep);
-            RenderPanelMouseMove(Sender, Shift, LastMovePoint.X, LastMovePoint.Y);
+            if DrawRect <> nil then
+            begin
+              Inc(MouseLDownPos.x, dx);
+              Inc(MouseRDownPos.x, dx);
+            end;
+            Inc(LastMovePoint.X, dx);
+            RenderPanelMouseMove(Sender, Shift, RenderMousePos().X, RenderMousePos().Y);
           end;
           end;
-          Position := IfThen(Position > DotStep, Position-DotStep, 0);
-          MapOffset.X := -Round(Position/16) * 16;
         end;
 
         if Key = Ord('D') then
         begin
         end;
 
         if Key = Ord('D') then
         begin
-          if (MouseLDown or MouseRDown) and (Position+DotStep <= Max) then
+          dx := Position;
+          if ssShift in Shift then Position := EnsureRange(Position + DotStep * 4, Min, Max)
+          else Position := EnsureRange(Position + DotStep, Min, Max);
+          MapOffset.X := -Position;
+          dx -= Position;
+
+          if (MouseLDown or MouseRDown) then
           begin
           begin
-            Inc(WASDOffset.X, DotStep);
-            RenderPanelMouseMove(Sender, Shift, LastMovePoint.X, LastMovePoint.Y);
+            if DrawRect <> nil then
+            begin
+              Inc(MouseLDownPos.x, dx);
+              Inc(MouseRDownPos.x, dx);
+            end;
+            Inc(LastMovePoint.X, dx);
+            RenderPanelMouseMove(Sender, Shift, RenderMousePos().X, RenderMousePos().Y);
           end;
           end;
-          Position := IfThen(Position+DotStep < Max, Position+DotStep, Max);
-          MapOffset.X := -Round(Position/16) * 16;
         end;
       end;
     end
         end;
       end;
     end
@@ -4343,12 +4696,12 @@ begin
         if Key = Ord('V') then
           aPasteObjectExecute(Sender);
       end;
         if Key = Ord('V') then
           aPasteObjectExecute(Sender);
       end;
+      RenderPanelMouseMove(Sender, Shift, RenderMousePos().X, RenderMousePos().Y);
     end;
   end;
 
 // Удалить выделенные объекты:
     end;
   end;
 
 // Удалить выделенные объекты:
-  if (Key = VK_DELETE) and (SelectedObjects <> nil) and
-     RenderPanel.Focused() then
+  if (Key = VK_DELETE) and (SelectedObjects <> nil) and RenderPanel.Focused() then
     DeleteSelectedObjects();
 
 // Снять выделение:
     DeleteSelectedObjects();
 
 // Снять выделение:
@@ -4388,7 +4741,7 @@ begin
         SelectFlag := SELECTFLAG_NONE;
         Exit;
       end;
         SelectFlag := SELECTFLAG_NONE;
         Exit;
       end;
-      vleObjectProperty.FindRow(_lc[I_PROP_TR_TEXTURE_PANEL], i);
+      vleObjectProperty.FindRow(MsgPropTrTexturePanel, i);
       if i > 0 then
         SelectFlag := SELECTFLAG_TEXTURE;
     end;
       if i > 0 then
         SelectFlag := SELECTFLAG_TEXTURE;
     end;
@@ -4404,33 +4757,33 @@ begin
       i := -1;
 
     // Выбор области воздействия, в зависимости от типа триггера
       i := -1;
 
     // Выбор области воздействия, в зависимости от типа триггера
-      vleObjectProperty.FindRow(_lc[I_PROP_TR_EX_AREA], i);
+      vleObjectProperty.FindRow(MsgPropTrExArea, i);
       if i > 0 then
       begin
         DrawPressRect := True;
         Exit;
       end;
       if i > 0 then
       begin
         DrawPressRect := True;
         Exit;
       end;
-      vleObjectProperty.FindRow(_lc[I_PROP_TR_DOOR_PANEL], i);
+      vleObjectProperty.FindRow(MsgPropTrDoorPanel, i);
       if i <= 0 then
       if i <= 0 then
-        vleObjectProperty.FindRow(_lc[I_PROP_TR_TRAP_PANEL], i);
+        vleObjectProperty.FindRow(MsgPropTrTrapPanel, i);
       if i > 0 then
       begin
         SelectFlag := SELECTFLAG_DOOR;
         Exit;
       end;
       if i > 0 then
       begin
         SelectFlag := SELECTFLAG_DOOR;
         Exit;
       end;
-      vleObjectProperty.FindRow(_lc[I_PROP_TR_LIFT_PANEL], i);
+      vleObjectProperty.FindRow(MsgPropTrLiftPanel, i);
       if i > 0 then
       begin
         SelectFlag := SELECTFLAG_LIFT;
         Exit;
       end;
       if i > 0 then
       begin
         SelectFlag := SELECTFLAG_LIFT;
         Exit;
       end;
-      vleObjectProperty.FindRow(_lc[I_PROP_TR_TELEPORT_TO], i);
+      vleObjectProperty.FindRow(MsgPropTrTeleportTo, i);
       if i > 0 then
       begin
         SelectFlag := SELECTFLAG_TELEPORT;
         Exit;
       end;
       if i > 0 then
       begin
         SelectFlag := SELECTFLAG_TELEPORT;
         Exit;
       end;
-      vleObjectProperty.FindRow(_lc[I_PROP_TR_SPAWN_TO], i);
+      vleObjectProperty.FindRow(MsgPropTrSpawnTo, i);
       if i > 0 then
       begin
         SelectFlag := SELECTFLAG_SPAWNPOINT;
       if i > 0 then
       begin
         SelectFlag := SELECTFLAG_SPAWNPOINT;
@@ -4438,11 +4791,11 @@ begin
       end;
 
     // Выбор основного параметра, в зависимости от типа триггера
       end;
 
     // Выбор основного параметра, в зависимости от типа триггера
-      vleObjectProperty.FindRow(_lc[I_PROP_TR_NEXT_MAP], i);
+      vleObjectProperty.FindRow(MsgPropTrNextMap, i);
       if i > 0 then
       begin
         g_ProcessResourceStr(OpenedMap, @FileName, nil, nil);
       if i > 0 then
       begin
         g_ProcessResourceStr(OpenedMap, @FileName, nil, nil);
-        SelectMapForm.Caption := _lc[I_CAP_SELECT];
+        SelectMapForm.Caption := MsgCapSelect;
         SelectMapForm.GetMaps(FileName);
 
         if SelectMapForm.ShowModal() = mrOK then
         SelectMapForm.GetMaps(FileName);
 
         if SelectMapForm.ShowModal() = mrOK then
@@ -4452,9 +4805,9 @@ begin
         end;
         Exit;
       end;
         end;
         Exit;
       end;
-      vleObjectProperty.FindRow(_lc[I_PROP_TR_SOUND_NAME], i);
+      vleObjectProperty.FindRow(MsgPropTrSoundName, i);
       if i <= 0 then
       if i <= 0 then
-        vleObjectProperty.FindRow(_lc[I_PROP_TR_MUSIC_NAME], i);
+        vleObjectProperty.FindRow(MsgPropTrMusicName, i);
       if i > 0 then
       begin
         AddSoundForm.OKFunction := nil;
       if i > 0 then
       begin
         AddSoundForm.OKFunction := nil;
@@ -4468,9 +4821,9 @@ begin
         end;
         Exit;
       end;
         end;
         Exit;
       end;
-      vleObjectProperty.FindRow(_lc[I_PROP_TR_PUSH_ANGLE], i);
+      vleObjectProperty.FindRow(MsgPropTrPushAngle, i);
       if i <= 0 then
       if i <= 0 then
-        vleObjectProperty.FindRow(_lc[I_PROP_TR_MESSAGE_TEXT], i);
+        vleObjectProperty.FindRow(MsgPropTrMessageText, i);
       if i > 0 then
       begin
         vleObjectProperty.Row := i;
       if i > 0 then
       begin
         vleObjectProperty.Row := i;
@@ -4517,8 +4870,8 @@ begin
         lTextureHeight.Caption := IntToStr(TextureHeight);
       end else
       begin
         lTextureHeight.Caption := IntToStr(TextureHeight);
       end else
       begin
-        lTextureWidth.Caption := _lc[I_NOT_ACCESSIBLE];
-        lTextureHeight.Caption := _lc[I_NOT_ACCESSIBLE];
+        lTextureWidth.Caption := MsgNotAccessible;
+        lTextureHeight.Caption := MsgNotAccessible;
       end;
     end
   else
       end;
     end
   else
@@ -4549,101 +4902,141 @@ begin
   end;
 end;
 
   end;
 end;
 
+procedure TMainForm.miMacMinimizeClick(Sender: TObject);
+begin
+  self.WindowState := wsMinimized;
+  self.FormWindowStateChange(Sender);
+end;
+
+procedure TMainForm.miMacZoomClick(Sender: TObject);
+begin
+  if self.WindowState = wsMaximized then
+    self.WindowState := wsNormal
+  else
+    self.WindowState := wsMaximized;
+  self.FormWindowStateChange(Sender);
+end;
+
+procedure TMainForm.miReopenMapClick(Sender: TObject);
+var
+  FileName, Resource: String;
+begin
+  if OpenedMap = '' then
+    Exit;
+
+  if Application.MessageBox(PChar(MsgMsgReopenMapPrompt),
+  PChar(MsgMenuFileReopen), MB_ICONQUESTION or MB_YESNO) <> idYes then
+    Exit;
+
+  g_ProcessResourceStr(OpenedMap, @FileName, nil, @Resource);
+  OpenMap(FileName, Resource);
+end;
+
 procedure TMainForm.vleObjectPropertyGetPickList(Sender: TObject;
   const KeyName: String; Values: TStrings);
 begin
   if vleObjectProperty.ItemProps[KeyName].EditStyle = esPickList then
   begin
 procedure TMainForm.vleObjectPropertyGetPickList(Sender: TObject;
   const KeyName: String; Values: TStrings);
 begin
   if vleObjectProperty.ItemProps[KeyName].EditStyle = esPickList then
   begin
-    if KeyName = _lc[I_PROP_DIRECTION] then
+    if KeyName = MsgPropDirection then
       begin
         Values.Add(DirNames[D_LEFT]);
         Values.Add(DirNames[D_RIGHT]);
       end
       begin
         Values.Add(DirNames[D_LEFT]);
         Values.Add(DirNames[D_RIGHT]);
       end
-    else if KeyName = _lc[I_PROP_TR_TELEPORT_DIR] then
+    else if KeyName = MsgPropTrTeleportDir then
       begin
         Values.Add(DirNamesAdv[0]);
         Values.Add(DirNamesAdv[1]);
         Values.Add(DirNamesAdv[2]);
         Values.Add(DirNamesAdv[3]);
       end
       begin
         Values.Add(DirNamesAdv[0]);
         Values.Add(DirNamesAdv[1]);
         Values.Add(DirNamesAdv[2]);
         Values.Add(DirNamesAdv[3]);
       end
-    else if KeyName = _lc[I_PROP_TR_MUSIC_ACT] then
+    else if KeyName = MsgPropTrMusicAct then
       begin
       begin
-        Values.Add(_lc[I_PROP_TR_MUSIC_ON]);
-        Values.Add(_lc[I_PROP_TR_MUSIC_OFF]);
+        Values.Add(MsgPropTrMusicOn);
+        Values.Add(MsgPropTrMusicOff);
       end
       end
-    else if KeyName = _lc[I_PROP_TR_MONSTER_BEHAVIOUR] then
+    else if KeyName = MsgPropTrMonsterBehaviour then
       begin
       begin
-        Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_0]);
-        Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_1]);
-        Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_2]);
-        Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_3]);
-        Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_4]);
-        Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_5]);
+        Values.Add(MsgPropTrMonsterBehaviour0);
+        Values.Add(MsgPropTrMonsterBehaviour1);
+        Values.Add(MsgPropTrMonsterBehaviour2);
+        Values.Add(MsgPropTrMonsterBehaviour3);
+        Values.Add(MsgPropTrMonsterBehaviour4);
+        Values.Add(MsgPropTrMonsterBehaviour5);
       end
       end
-    else if KeyName = _lc[I_PROP_TR_SCORE_ACT] then
+    else if KeyName = MsgPropTrScoreAct then
       begin
       begin
-        Values.Add(_lc[I_PROP_TR_SCORE_ACT_0]);
-        Values.Add(_lc[I_PROP_TR_SCORE_ACT_1]);
-        Values.Add(_lc[I_PROP_TR_SCORE_ACT_2]);
-        Values.Add(_lc[I_PROP_TR_SCORE_ACT_3]);
+        Values.Add(MsgPropTrScoreAct0);
+        Values.Add(MsgPropTrScoreAct1);
+        Values.Add(MsgPropTrScoreAct2);
+        Values.Add(MsgPropTrScoreAct3);
       end
       end
-    else if KeyName = _lc[I_PROP_TR_SCORE_TEAM] then
+    else if KeyName = MsgPropTrScoreTeam then
       begin
       begin
-        Values.Add(_lc[I_PROP_TR_SCORE_TEAM_0]);
-        Values.Add(_lc[I_PROP_TR_SCORE_TEAM_1]);
-        Values.Add(_lc[I_PROP_TR_SCORE_TEAM_2]);
-        Values.Add(_lc[I_PROP_TR_SCORE_TEAM_3]);
+        Values.Add(MsgPropTrScoreTeam0);
+        Values.Add(MsgPropTrScoreTeam1);
+        Values.Add(MsgPropTrScoreTeam2);
+        Values.Add(MsgPropTrScoreTeam3);
       end
       end
-    else if KeyName = _lc[I_PROP_TR_MESSAGE_KIND] then
+    else if KeyName = MsgPropTrMessageKind then
       begin
       begin
-        Values.Add(_lc[I_PROP_TR_MESSAGE_KIND_0]);
-        Values.Add(_lc[I_PROP_TR_MESSAGE_KIND_1]);
+        Values.Add(MsgPropTrMessageKind0);
+        Values.Add(MsgPropTrMessageKind1);
       end
       end
-    else if KeyName = _lc[I_PROP_TR_MESSAGE_TO] then
+    else if KeyName = MsgPropTrMessageTo then
       begin
       begin
-        Values.Add(_lc[I_PROP_TR_MESSAGE_TO_0]);
-        Values.Add(_lc[I_PROP_TR_MESSAGE_TO_1]);
-        Values.Add(_lc[I_PROP_TR_MESSAGE_TO_2]);
-        Values.Add(_lc[I_PROP_TR_MESSAGE_TO_3]);
-        Values.Add(_lc[I_PROP_TR_MESSAGE_TO_4]);
-        Values.Add(_lc[I_PROP_TR_MESSAGE_TO_5]);
+        Values.Add(MsgPropTrMessageTo0);
+        Values.Add(MsgPropTrMessageTo1);
+        Values.Add(MsgPropTrMessageTo2);
+        Values.Add(MsgPropTrMessageTo3);
+        Values.Add(MsgPropTrMessageTo4);
+        Values.Add(MsgPropTrMessageTo5);
       end
       end
-    else if KeyName = _lc[I_PROP_TR_SHOT_TO] then
+    else if KeyName = MsgPropTrShotTo then
       begin
       begin
-        Values.Add(_lc[I_PROP_TR_SHOT_TO_0]);
-        Values.Add(_lc[I_PROP_TR_SHOT_TO_1]);
-        Values.Add(_lc[I_PROP_TR_SHOT_TO_2]);
-        Values.Add(_lc[I_PROP_TR_SHOT_TO_3]);
-        Values.Add(_lc[I_PROP_TR_SHOT_TO_4]);
-        Values.Add(_lc[I_PROP_TR_SHOT_TO_5]);
-        Values.Add(_lc[I_PROP_TR_SHOT_TO_6]);
+        Values.Add(MsgPropTrShotTo0);
+        Values.Add(MsgPropTrShotTo1);
+        Values.Add(MsgPropTrShotTo2);
+        Values.Add(MsgPropTrShotTo3);
+        Values.Add(MsgPropTrShotTo4);
+        Values.Add(MsgPropTrShotTo5);
+        Values.Add(MsgPropTrShotTo6);
       end
       end
-    else if KeyName = _lc[I_PROP_TR_SHOT_AIM] then
+    else if KeyName = MsgPropTrShotAim then
       begin
       begin
-        Values.Add(_lc[I_PROP_TR_SHOT_AIM_0]);
-        Values.Add(_lc[I_PROP_TR_SHOT_AIM_1]);
-        Values.Add(_lc[I_PROP_TR_SHOT_AIM_2]);
-        Values.Add(_lc[I_PROP_TR_SHOT_AIM_3]);
+        Values.Add(MsgPropTrShotAim0);
+        Values.Add(MsgPropTrShotAim1);
+        Values.Add(MsgPropTrShotAim2);
+        Values.Add(MsgPropTrShotAim3);
       end
       end
-    else if (KeyName = _lc[I_PROP_PANEL_BLEND]) or
-            (KeyName = _lc[I_PROP_DM_ONLY]) or
-            (KeyName = _lc[I_PROP_ITEM_FALLS]) or
-            (KeyName = _lc[I_PROP_TR_ENABLED]) or
-            (KeyName = _lc[I_PROP_TR_D2D]) or
-            (KeyName = _lc[I_PROP_TR_SILENT]) or
-            (KeyName = _lc[I_PROP_TR_TELEPORT_SILENT]) or
-            (KeyName = _lc[I_PROP_TR_EX_RANDOM]) or
-            (KeyName = _lc[I_PROP_TR_TEXTURE_ONCE]) or
-            (KeyName = _lc[I_PROP_TR_TEXTURE_ANIM_ONCE]) or
-            (KeyName = _lc[I_PROP_TR_SOUND_LOCAL]) or
-            (KeyName = _lc[I_PROP_TR_SOUND_SWITCH]) or
-            (KeyName = _lc[I_PROP_TR_MONSTER_ACTIVE]) or
-            (KeyName = _lc[I_PROP_TR_PUSH_RESET]) or
-            (KeyName = _lc[I_PROP_TR_SCORE_CON]) or
-            (KeyName = _lc[I_PROP_TR_SCORE_MSG]) or
-            (KeyName = _lc[I_PROP_TR_HEALTH_MAX]) or
-            (KeyName = _lc[I_PROP_TR_SHOT_SOUND]) or
-            (KeyName = _lc[I_PROP_TR_EFFECT_CENTER]) then
+    else if KeyName = MsgPropTrDamageKind then
+      begin
+        Values.Add(MsgPropTrDamageKind0);
+        Values.Add(MsgPropTrDamageKind3);
+        Values.Add(MsgPropTrDamageKind4);
+        Values.Add(MsgPropTrDamageKind5);
+        Values.Add(MsgPropTrDamageKind6);
+        Values.Add(MsgPropTrDamageKind7);
+        Values.Add(MsgPropTrDamageKind8);
+      end
+    else if (KeyName = MsgPropPanelBlend) or
+            (KeyName = MsgPropDmOnly) or
+            (KeyName = MsgPropItemFalls) or
+            (KeyName = MsgPropTrEnabled) or
+            (KeyName = MsgPropTrD2d) or
+            (KeyName = MsgPropTrSilent) or
+            (KeyName = MsgPropTrTeleportSilent) or
+            (KeyName = MsgPropTrExRandom) or
+            (KeyName = MsgPropTrTextureOnce) or
+            (KeyName = MsgPropTrTextureAnimOnce) or
+            (KeyName = MsgPropTrSoundLocal) or
+            (KeyName = MsgPropTrSoundSwitch) or
+            (KeyName = MsgPropTrMonsterActive) or
+            (KeyName = MsgPropTrPushReset) or
+            (KeyName = MsgPropTrScoreCon) or
+            (KeyName = MsgPropTrScoreMsg) or
+            (KeyName = MsgPropTrHealthMax) or
+            (KeyName = MsgPropTrShotSound) or
+            (KeyName = MsgPropTrEffectCenter) then
       begin
         Values.Add(BoolNames[True]);
         Values.Add(BoolNames[False]);
       begin
         Values.Add(BoolNames[True]);
         Values.Add(BoolNames[False]);
@@ -4685,12 +5078,12 @@ begin
       begin
         with gPanels[SelectedObjects[_id].ID] do
         begin
       begin
         with gPanels[SelectedObjects[_id].ID] do
         begin
-          X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
-          Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
-          Width := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_WIDTH]]));
-          Height := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_HEIGHT]]));
+          X := StrToInt(Trim(vleObjectProperty.Values[MsgPropX]));
+          Y := StrToInt(Trim(vleObjectProperty.Values[MsgPropY]));
+          Width := StrToInt(Trim(vleObjectProperty.Values[MsgPropWidth]));
+          Height := StrToInt(Trim(vleObjectProperty.Values[MsgPropHeight]));
 
 
-          PanelType := GetPanelType(vleObjectProperty.Values[_lc[I_PROP_PANEL_TYPE]]);
+          PanelType := GetPanelType(vleObjectProperty.Values[MsgPropPanelType]);
 
         // Сброс ссылки на триггеры смены текстуры:
           if not WordBool(PanelType and (PANEL_WALL or PANEL_FORE or PANEL_BACK)) then
 
         // Сброс ссылки на триггеры смены текстуры:
           if not WordBool(PanelType and (PANEL_WALL or PANEL_FORE or PANEL_BACK)) then
@@ -4726,8 +5119,8 @@ begin
             begin // Может быть текстура
               if TextureName <> '' then
                 begin // Была текстура
             begin // Может быть текстура
               if TextureName <> '' then
                 begin // Была текстура
-                  Alpha := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_PANEL_ALPHA]]));
-                  Blending := NameToBool(vleObjectProperty.Values[_lc[I_PROP_PANEL_BLEND]]);
+                  Alpha := StrToInt(Trim(vleObjectProperty.Values[MsgPropPanelAlpha]));
+                  Blending := NameToBool(vleObjectProperty.Values[MsgPropPanelBlend]);
                 end
               else // Не было
                 begin
                 end
               else // Не было
                 begin
@@ -4736,7 +5129,7 @@ begin
                 end;
 
             // Новая текстура:
                 end;
 
             // Новая текстура:
-              TextureName := vleObjectProperty.Values[_lc[I_PROP_PANEL_TEX]];
+              TextureName := vleObjectProperty.Values[MsgPropPanelTex];
 
               if TextureName <> '' then
                 begin // Есть текстура
 
               if TextureName <> '' then
                 begin // Есть текстура
@@ -4751,14 +5144,14 @@ begin
                       if TextureWidth <> 0 then
                         if gPanels[SelectedObjects[_id].ID].Width mod TextureWidth <> 0 then
                         begin
                       if TextureWidth <> 0 then
                         if gPanels[SelectedObjects[_id].ID].Width mod TextureWidth <> 0 then
                         begin
-                          ErrorMessageBox(Format(_lc[I_MSG_WRONG_TEXWIDTH],
+                          ErrorMessageBox(Format(MsgMsgWrongTexwidth,
                                           [TextureWidth]));
                           Res := False;
                         end;
                       if Res and (TextureHeight <> 0) then
                         if gPanels[SelectedObjects[_id].ID].Height mod TextureHeight <> 0 then
                         begin
                                           [TextureWidth]));
                           Res := False;
                         end;
                       if Res and (TextureHeight <> 0) then
                         if gPanels[SelectedObjects[_id].ID].Height mod TextureHeight <> 0 then
                         begin
-                          ErrorMessageBox(Format(_lc[I_MSG_WRONG_TEXHEIGHT],
+                          ErrorMessageBox(Format(MsgMsgWrongTexheight,
                                           [TextureHeight]));
                           Res := False;
                         end;
                                           [TextureHeight]));
                           Res := False;
                         end;
@@ -4818,10 +5211,10 @@ begin
       begin
         with gItems[SelectedObjects[_id].ID] do
         begin
       begin
         with gItems[SelectedObjects[_id].ID] do
         begin
-          X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
-          Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
-          OnlyDM := NameToBool(vleObjectProperty.Values[_lc[I_PROP_DM_ONLY]]);
-          Fall := NameToBool(vleObjectProperty.Values[_lc[I_PROP_ITEM_FALLS]]);
+          X := StrToInt(Trim(vleObjectProperty.Values[MsgPropX]));
+          Y := StrToInt(Trim(vleObjectProperty.Values[MsgPropY]));
+          OnlyDM := NameToBool(vleObjectProperty.Values[MsgPropDmOnly]);
+          Fall := NameToBool(vleObjectProperty.Values[MsgPropItemFalls]);
         end;
       end;
 
         end;
       end;
 
@@ -4829,9 +5222,9 @@ begin
       begin
         with gMonsters[SelectedObjects[_id].ID] do
         begin
       begin
         with gMonsters[SelectedObjects[_id].ID] do
         begin
-          X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
-          Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
-          Direction := NameToDir(vleObjectProperty.Values[_lc[I_PROP_DIRECTION]]);
+          X := StrToInt(Trim(vleObjectProperty.Values[MsgPropX]));
+          Y := StrToInt(Trim(vleObjectProperty.Values[MsgPropY]));
+          Direction := NameToDir(vleObjectProperty.Values[MsgPropDirection]);
         end;
       end;
 
         end;
       end;
 
@@ -4839,9 +5232,9 @@ begin
       begin
         with gAreas[SelectedObjects[_id].ID] do
         begin
       begin
         with gAreas[SelectedObjects[_id].ID] do
         begin
-          X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
-          Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
-          Direction := NameToDir(vleObjectProperty.Values[_lc[I_PROP_DIRECTION]]);
+          X := StrToInt(Trim(vleObjectProperty.Values[MsgPropX]));
+          Y := StrToInt(Trim(vleObjectProperty.Values[MsgPropY]));
+          Direction := NameToDir(vleObjectProperty.Values[MsgPropDirection]);
         end;
       end;
 
         end;
       end;
 
@@ -4849,18 +5242,18 @@ begin
       begin
         with gTriggers[SelectedObjects[_id].ID] do
         begin
       begin
         with gTriggers[SelectedObjects[_id].ID] do
         begin
-          X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
-          Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
-          Width := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_WIDTH]]));
-          Height := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_HEIGHT]]));
-          Enabled := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_ENABLED]]);
-          ActivateType := StrToActivate(vleObjectProperty.Values[_lc[I_PROP_TR_ACTIVATION]]);
-          Key := StrToKey(vleObjectProperty.Values[_lc[I_PROP_TR_KEYS]]);
+          X := StrToInt(Trim(vleObjectProperty.Values[MsgPropX]));
+          Y := StrToInt(Trim(vleObjectProperty.Values[MsgPropY]));
+          Width := StrToInt(Trim(vleObjectProperty.Values[MsgPropWidth]));
+          Height := StrToInt(Trim(vleObjectProperty.Values[MsgPropHeight]));
+          Enabled := NameToBool(vleObjectProperty.Values[MsgPropTrEnabled]);
+          ActivateType := StrToActivate(vleObjectProperty.Values[MsgPropTrActivation]);
+          Key := StrToKey(vleObjectProperty.Values[MsgPropTrKeys]);
 
           case TriggerType of
             TRIGGER_EXIT:
               begin
 
           case TriggerType of
             TRIGGER_EXIT:
               begin
-                s := utf2win(vleObjectProperty.Values[_lc[I_PROP_TR_NEXT_MAP]]);
+                s := utf2win(vleObjectProperty.Values[MsgPropTrNextMap]);
                 FillByte(Data.MapName[0], 16, 0);
                 if s <> '' then
                   Move(s[1], Data.MapName[0], Min(Length(s), 16));
                 FillByte(Data.MapName[0], 16, 0);
                 if s <> '' then
                   Move(s[1], Data.MapName[0], Min(Length(s), 16));
@@ -4868,264 +5261,279 @@ begin
 
             TRIGGER_TEXTURE:
               begin
 
             TRIGGER_TEXTURE:
               begin
-                Data.ActivateOnce := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_TEXTURE_ONCE]]);
-                Data.AnimOnce := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_TEXTURE_ANIM_ONCE]]);
+                Data.ActivateOnce := NameToBool(vleObjectProperty.Values[MsgPropTrTextureOnce]);
+                Data.AnimOnce := NameToBool(vleObjectProperty.Values[MsgPropTrTextureAnimOnce]);
               end;
 
             TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF:
               begin
               end;
 
             TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF:
               begin
-                Data.Wait := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EX_DELAY]], 0), 65535);
-                Data.Count := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EX_COUNT]], 0), 65535);
+                Data.Wait := Min(StrToIntDef(vleObjectProperty.Values[MsgPropTrExDelay], 0), 65535);
+                Data.Count := Min(StrToIntDef(vleObjectProperty.Values[MsgPropTrExCount], 0), 65535);
                 if Data.Count < 1 then
                   Data.Count := 1;
                 if TriggerType = TRIGGER_PRESS then
                 if Data.Count < 1 then
                   Data.Count := 1;
                 if TriggerType = TRIGGER_PRESS then
-                  Data.ExtRandom := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_EX_RANDOM]]);
+                  Data.ExtRandom := NameToBool(vleObjectProperty.Values[MsgPropTrExRandom]);
               end;
 
             TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR, TRIGGER_DOOR5,
             TRIGGER_CLOSETRAP, TRIGGER_TRAP, TRIGGER_LIFTUP, TRIGGER_LIFTDOWN,
             TRIGGER_LIFT:
               begin
               end;
 
             TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR, TRIGGER_DOOR5,
             TRIGGER_CLOSETRAP, TRIGGER_TRAP, TRIGGER_LIFTUP, TRIGGER_LIFTDOWN,
             TRIGGER_LIFT:
               begin
-                Data.NoSound := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SILENT]]);
-                Data.d2d_doors := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_D2D]]);
+                Data.NoSound := NameToBool(vleObjectProperty.Values[MsgPropTrSilent]);
+                Data.d2d_doors := NameToBool(vleObjectProperty.Values[MsgPropTrD2d]);
               end;
 
             TRIGGER_TELEPORT:
               begin
               end;
 
             TRIGGER_TELEPORT:
               begin
-                Data.d2d_teleport := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_D2D]]);
-                Data.silent_teleport := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_TELEPORT_SILENT]]);
-                Data.TlpDir := NameToDirAdv(vleObjectProperty.Values[_lc[I_PROP_TR_TELEPORT_DIR]]);
+                Data.d2d_teleport := NameToBool(vleObjectProperty.Values[MsgPropTrD2d]);
+                Data.silent_teleport := NameToBool(vleObjectProperty.Values[MsgPropTrTeleportSilent]);
+                Data.TlpDir := NameToDirAdv(vleObjectProperty.Values[MsgPropTrTeleportDir]);
               end;
 
             TRIGGER_SOUND:
               begin
               end;
 
             TRIGGER_SOUND:
               begin
-                s := utf2win(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_NAME]]);
+                s := utf2win(vleObjectProperty.Values[MsgPropTrSoundName]);
                 FillByte(Data.SoundName[0], 64, 0);
                 if s <> '' then
                   Move(s[1], Data.SoundName[0], Min(Length(s), 64));
 
                 FillByte(Data.SoundName[0], 64, 0);
                 if s <> '' then
                   Move(s[1], Data.SoundName[0], Min(Length(s), 64));
 
-                Data.Volume := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_VOLUME]], 0), 255);
-                Data.Pan := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_PAN]], 0), 255);
-                Data.PlayCount := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_COUNT]], 0), 255);
-                Data.Local := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_LOCAL]]);
-                Data.SoundSwitch := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_SWITCH]]);
+                Data.Volume := Min(StrToIntDef(vleObjectProperty.Values[MsgPropTrSoundVolume], 0), 255);
+                Data.Pan := Min(StrToIntDef(vleObjectProperty.Values[MsgPropTrSoundPan], 0), 255);
+                Data.PlayCount := Min(StrToIntDef(vleObjectProperty.Values[MsgPropTrSoundCount], 0), 255);
+                Data.Local := NameToBool(vleObjectProperty.Values[MsgPropTrSoundLocal]);
+                Data.SoundSwitch := NameToBool(vleObjectProperty.Values[MsgPropTrSoundSwitch]);
               end;
 
             TRIGGER_SPAWNMONSTER:
               begin
               end;
 
             TRIGGER_SPAWNMONSTER:
               begin
-                Data.MonType := StrToMonster(vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_TYPE]]);
-                Data.MonDir := Byte(NameToDir(vleObjectProperty.Values[_lc[I_PROP_DIRECTION]]));
-                Data.MonHealth := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_HEALTH]], 0), 1000000);
+                Data.MonType := StrToMonster(vleObjectProperty.Values[MsgPropTrMonsterType]);
+                Data.MonDir := Byte(NameToDir(vleObjectProperty.Values[MsgPropDirection]));
+                Data.MonHealth := Min(StrToIntDef(vleObjectProperty.Values[MsgPropTrHealth], 0), 1000000);
                 if Data.MonHealth < 0 then
                   Data.MonHealth := 0;
                 if Data.MonHealth < 0 then
                   Data.MonHealth := 0;
-                Data.MonActive := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_ACTIVE]]);
-                Data.MonCount := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_COUNT]], 0), 64);
+                Data.MonActive := NameToBool(vleObjectProperty.Values[MsgPropTrMonsterActive]);
+                Data.MonCount := Min(StrToIntDef(vleObjectProperty.Values[MsgPropTrCount], 0), 64);
                 if Data.MonCount < 1 then
                   Data.MonCount := 1;
                 if Data.MonCount < 1 then
                   Data.MonCount := 1;
-                Data.MonEffect := StrToEffect(vleObjectProperty.Values[_lc[I_PROP_TR_FX_TYPE]]);
-                Data.MonMax := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SPAWN_MAX]], 0), 65535);
-                Data.MonDelay := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SPAWN_DELAY]], 0), 65535);
+                Data.MonEffect := StrToEffect(vleObjectProperty.Values[MsgPropTrFxType]);
+                Data.MonMax := Min(StrToIntDef(vleObjectProperty.Values[MsgPropTrSpawnMax], 0), 65535);
+                Data.MonDelay := Min(StrToIntDef(vleObjectProperty.Values[MsgPropTrSpawnDelay], 0), 65535);
                 Data.MonBehav := 0;
                 Data.MonBehav := 0;
-                if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_1] then
+                if vleObjectProperty.Values[MsgPropTrMonsterBehaviour] = MsgPropTrMonsterBehaviour1 then
                   Data.MonBehav := 1;
                   Data.MonBehav := 1;
-                if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_2] then
+                if vleObjectProperty.Values[MsgPropTrMonsterBehaviour] = MsgPropTrMonsterBehaviour2 then
                   Data.MonBehav := 2;
                   Data.MonBehav := 2;
-                if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_3] then
+                if vleObjectProperty.Values[MsgPropTrMonsterBehaviour] = MsgPropTrMonsterBehaviour3 then
                   Data.MonBehav := 3;
                   Data.MonBehav := 3;
-                if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_4] then
+                if vleObjectProperty.Values[MsgPropTrMonsterBehaviour] = MsgPropTrMonsterBehaviour4 then
                   Data.MonBehav := 4;
                   Data.MonBehav := 4;
-                if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_5] then
+                if vleObjectProperty.Values[MsgPropTrMonsterBehaviour] = MsgPropTrMonsterBehaviour5 then
                   Data.MonBehav := 5;
               end;
 
             TRIGGER_SPAWNITEM:
               begin
                   Data.MonBehav := 5;
               end;
 
             TRIGGER_SPAWNITEM:
               begin
-                Data.ItemType := StrToItem(vleObjectProperty.Values[_lc[I_PROP_TR_ITEM_TYPE]]);
-                Data.ItemOnlyDM := NameToBool(vleObjectProperty.Values[_lc[I_PROP_DM_ONLY]]);
-                Data.ItemFalls := NameToBool(vleObjectProperty.Values[_lc[I_PROP_ITEM_FALLS]]);
-                Data.ItemCount := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_COUNT]], 0), 64);
+                Data.ItemType := StrToItem(vleObjectProperty.Values[MsgPropTrItemType]);
+                Data.ItemOnlyDM := NameToBool(vleObjectProperty.Values[MsgPropDmOnly]);
+                Data.ItemFalls := NameToBool(vleObjectProperty.Values[MsgPropItemFalls]);
+                Data.ItemCount := Min(StrToIntDef(vleObjectProperty.Values[MsgPropTrCount], 0), 64);
                 if Data.ItemCount < 1 then
                   Data.ItemCount := 1;
                 if Data.ItemCount < 1 then
                   Data.ItemCount := 1;
-                Data.ItemEffect := StrToEffect(vleObjectProperty.Values[_lc[I_PROP_TR_FX_TYPE]]);
-                Data.ItemMax := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SPAWN_MAX]], 0), 65535);
-                Data.ItemDelay := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SPAWN_DELAY]], 0), 65535);
+                Data.ItemEffect := StrToEffect(vleObjectProperty.Values[MsgPropTrFxType]);
+                Data.ItemMax := Min(StrToIntDef(vleObjectProperty.Values[MsgPropTrSpawnMax], 0), 65535);
+                Data.ItemDelay := Min(StrToIntDef(vleObjectProperty.Values[MsgPropTrSpawnDelay], 0), 65535);
               end;
 
             TRIGGER_MUSIC:
               begin
               end;
 
             TRIGGER_MUSIC:
               begin
-                s := utf2win(vleObjectProperty.Values[_lc[I_PROP_TR_MUSIC_NAME]]);
+                s := utf2win(vleObjectProperty.Values[MsgPropTrMusicName]);
                 FillByte(Data.MusicName[0], 64, 0);
                 if s <> '' then
                   Move(s[1], Data.MusicName[0], Min(Length(s), 64));
 
                 FillByte(Data.MusicName[0], 64, 0);
                 if s <> '' then
                   Move(s[1], Data.MusicName[0], Min(Length(s), 64));
 
-                if vleObjectProperty.Values[_lc[I_PROP_TR_MUSIC_ACT]] = _lc[I_PROP_TR_MUSIC_ON] then
+                if vleObjectProperty.Values[MsgPropTrMusicAct] = MsgPropTrMusicOn then
                   Data.MusicAction := 1
                 else
                   Data.MusicAction := 1
                 else
-                  Data.MusicAction := 2;
+                  Data.MusicAction := 0;
               end;
 
             TRIGGER_PUSH:
               begin
                 Data.PushAngle := Min(
               end;
 
             TRIGGER_PUSH:
               begin
                 Data.PushAngle := Min(
-                  StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_PUSH_ANGLE]], 0), 360);
+                  StrToIntDef(vleObjectProperty.Values[MsgPropTrPushAngle], 0), 360);
                 Data.PushForce := Min(
                 Data.PushForce := Min(
-                  StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_PUSH_FORCE]], 0), 255);
-                Data.ResetVel := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_PUSH_RESET]]);
+                  StrToIntDef(vleObjectProperty.Values[MsgPropTrPushForce], 0), 255);
+                Data.ResetVel := NameToBool(vleObjectProperty.Values[MsgPropTrPushReset]);
               end;
 
             TRIGGER_SCORE:
               begin
                 Data.ScoreAction := 0;
               end;
 
             TRIGGER_SCORE:
               begin
                 Data.ScoreAction := 0;
-                if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_ACT]] = _lc[I_PROP_TR_SCORE_ACT_1] then
+                if vleObjectProperty.Values[MsgPropTrScoreAct] = MsgPropTrScoreAct1 then
                   Data.ScoreAction := 1
                   Data.ScoreAction := 1
-                else if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_ACT]] = _lc[I_PROP_TR_SCORE_ACT_2] then
+                else if vleObjectProperty.Values[MsgPropTrScoreAct] = MsgPropTrScoreAct2 then
                   Data.ScoreAction := 2
                   Data.ScoreAction := 2
-                else if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_ACT]] = _lc[I_PROP_TR_SCORE_ACT_3] then
+                else if vleObjectProperty.Values[MsgPropTrScoreAct] = MsgPropTrScoreAct3 then
                   Data.ScoreAction := 3;
                 Data.ScoreCount := Min(Max(
                   Data.ScoreAction := 3;
                 Data.ScoreCount := Min(Max(
-                  StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_COUNT]], 0), 0), 255);
+                  StrToIntDef(vleObjectProperty.Values[MsgPropTrCount], 0), 0), 255);
                 Data.ScoreTeam := 0;
                 Data.ScoreTeam := 0;
-                if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_TEAM]] = _lc[I_PROP_TR_SCORE_TEAM_1] then
+                if vleObjectProperty.Values[MsgPropTrScoreTeam] = MsgPropTrScoreTeam1 then
                   Data.ScoreTeam := 1
                   Data.ScoreTeam := 1
-                else if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_TEAM]] = _lc[I_PROP_TR_SCORE_TEAM_2] then
+                else if vleObjectProperty.Values[MsgPropTrScoreTeam] = MsgPropTrScoreTeam2 then
                   Data.ScoreTeam := 2
                   Data.ScoreTeam := 2
-                else if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_TEAM]] = _lc[I_PROP_TR_SCORE_TEAM_3] then
+                else if vleObjectProperty.Values[MsgPropTrScoreTeam] = MsgPropTrScoreTeam3 then
                   Data.ScoreTeam := 3;
                   Data.ScoreTeam := 3;
-                Data.ScoreCon := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_CON]]);
-                Data.ScoreMsg := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_MSG]]);
+                Data.ScoreCon := NameToBool(vleObjectProperty.Values[MsgPropTrScoreCon]);
+                Data.ScoreMsg := NameToBool(vleObjectProperty.Values[MsgPropTrScoreMsg]);
               end;
 
             TRIGGER_MESSAGE:
               begin
                 Data.MessageKind := 0;
               end;
 
             TRIGGER_MESSAGE:
               begin
                 Data.MessageKind := 0;
-                if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_KIND]] = _lc[I_PROP_TR_MESSAGE_KIND_1] then
+                if vleObjectProperty.Values[MsgPropTrMessageKind] = MsgPropTrMessageKind1 then
                   Data.MessageKind := 1;
 
                 Data.MessageSendTo := 0;
                   Data.MessageKind := 1;
 
                 Data.MessageSendTo := 0;
-                if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_1] then
+                if vleObjectProperty.Values[MsgPropTrMessageTo] = MsgPropTrMessageTo1 then
                   Data.MessageSendTo := 1
                   Data.MessageSendTo := 1
-                else if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_2] then
+                else if vleObjectProperty.Values[MsgPropTrMessageTo] = MsgPropTrMessageTo2 then
                   Data.MessageSendTo := 2
                   Data.MessageSendTo := 2
-                else if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_3] then
+                else if vleObjectProperty.Values[MsgPropTrMessageTo] = MsgPropTrMessageTo3 then
                   Data.MessageSendTo := 3
                   Data.MessageSendTo := 3
-                else if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_4] then
+                else if vleObjectProperty.Values[MsgPropTrMessageTo] = MsgPropTrMessageTo4 then
                   Data.MessageSendTo := 4
                   Data.MessageSendTo := 4
-                else if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_5] then
+                else if vleObjectProperty.Values[MsgPropTrMessageTo] = MsgPropTrMessageTo5 then
                   Data.MessageSendTo := 5;
 
                   Data.MessageSendTo := 5;
 
-                s := utf2win(vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TEXT]]);
+                s := utf2win(vleObjectProperty.Values[MsgPropTrMessageText]);
                 FillByte(Data.MessageText[0], 100, 0);
                 if s <> '' then
                   Move(s[1], Data.MessageText[0], Min(Length(s), 100));
 
                 Data.MessageTime := Min(Max(
                 FillByte(Data.MessageText[0], 100, 0);
                 if s <> '' then
                   Move(s[1], Data.MessageText[0], Min(Length(s), 100));
 
                 Data.MessageTime := Min(Max(
-                  StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TIME]], 0), 0), 65535);
+                  StrToIntDef(vleObjectProperty.Values[MsgPropTrMessageTime], 0), 0), 65535);
               end;
 
             TRIGGER_DAMAGE:
               begin
                 Data.DamageValue := Min(Max(
               end;
 
             TRIGGER_DAMAGE:
               begin
                 Data.DamageValue := Min(Max(
-                  StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_DAMAGE_VALUE]], 0), 0), 65535);
+                  StrToIntDef(vleObjectProperty.Values[MsgPropTrDamageValue], 0), 0), 65535);
                 Data.DamageInterval := Min(Max(
                 Data.DamageInterval := Min(Max(
-                  StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_INTERVAL]], 0), 0), 65535);
+                  StrToIntDef(vleObjectProperty.Values[MsgPropTrInterval], 0), 0), 65535);
+                s := vleObjectProperty.Values[MsgPropTrDamageKind];
+                if s = MsgPropTrDamageKind3 then
+                  Data.DamageKind := 3
+                else if s = MsgPropTrDamageKind4 then
+                  Data.DamageKind := 4
+                else if s = MsgPropTrDamageKind5 then
+                  Data.DamageKind := 5
+                else if s = MsgPropTrDamageKind6 then
+                  Data.DamageKind := 6
+                else if s = MsgPropTrDamageKind7 then
+                  Data.DamageKind := 7
+                else if s = MsgPropTrDamageKind8 then
+                  Data.DamageKind := 8
+                else
+                  Data.DamageKind := 0;
               end;
 
             TRIGGER_HEALTH:
               begin
                 Data.HealValue := Min(Max(
               end;
 
             TRIGGER_HEALTH:
               begin
                 Data.HealValue := Min(Max(
-                  StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_HEALTH]], 0), 0), 65535);
+                  StrToIntDef(vleObjectProperty.Values[MsgPropTrHealth], 0), 0), 65535);
                 Data.HealInterval := Min(Max(
                 Data.HealInterval := Min(Max(
-                  StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_INTERVAL]], 0), 0), 65535);
-                Data.HealMax := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_HEALTH_MAX]]);
-                Data.HealSilent := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SILENT]]);
+                  StrToIntDef(vleObjectProperty.Values[MsgPropTrInterval], 0), 0), 65535);
+                Data.HealMax := NameToBool(vleObjectProperty.Values[MsgPropTrHealthMax]);
+                Data.HealSilent := NameToBool(vleObjectProperty.Values[MsgPropTrSilent]);
               end;
 
             TRIGGER_SHOT:
               begin
               end;
 
             TRIGGER_SHOT:
               begin
-                Data.ShotType := StrToShot(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TYPE]]);
-                Data.ShotSound := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_SOUND]]);
+                Data.ShotType := StrToShot(vleObjectProperty.Values[MsgPropTrShotType]);
+                Data.ShotSound := NameToBool(vleObjectProperty.Values[MsgPropTrShotSound]);
                 Data.ShotTarget := 0;
                 Data.ShotTarget := 0;
-                if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_1] then
+                if vleObjectProperty.Values[MsgPropTrShotTo] = MsgPropTrShotTo1 then
                   Data.ShotTarget := 1
                   Data.ShotTarget := 1
-                else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_2] then
+                else if vleObjectProperty.Values[MsgPropTrShotTo] = MsgPropTrShotTo2 then
                   Data.ShotTarget := 2
                   Data.ShotTarget := 2
-                else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_3] then
+                else if vleObjectProperty.Values[MsgPropTrShotTo] = MsgPropTrShotTo3 then
                   Data.ShotTarget := 3
                   Data.ShotTarget := 3
-                else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_4] then
+                else if vleObjectProperty.Values[MsgPropTrShotTo] = MsgPropTrShotTo4 then
                   Data.ShotTarget := 4
                   Data.ShotTarget := 4
-                else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_5] then
+                else if vleObjectProperty.Values[MsgPropTrShotTo] = MsgPropTrShotTo5 then
                   Data.ShotTarget := 5
                   Data.ShotTarget := 5
-                else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_6] then
+                else if vleObjectProperty.Values[MsgPropTrShotTo] = MsgPropTrShotTo6 then
                   Data.ShotTarget := 6;
                 Data.ShotIntSight := Min(Max(
                   Data.ShotTarget := 6;
                 Data.ShotIntSight := Min(Max(
-                  StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_SIGHT]], 0), 0), 65535);
+                  StrToIntDef(vleObjectProperty.Values[MsgPropTrShotSight], 0), 0), 65535);
                 Data.ShotAim := 0;
                 Data.ShotAim := 0;
-                if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_AIM]] = _lc[I_PROP_TR_SHOT_AIM_1] then
+                if vleObjectProperty.Values[MsgPropTrShotAim] = MsgPropTrShotAim1 then
                   Data.ShotAim := 1
                   Data.ShotAim := 1
-                else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_AIM]] = _lc[I_PROP_TR_SHOT_AIM_2] then
+                else if vleObjectProperty.Values[MsgPropTrShotAim] = MsgPropTrShotAim2 then
                   Data.ShotAim := 2
                   Data.ShotAim := 2
-                else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_AIM]] = _lc[I_PROP_TR_SHOT_AIM_3] then
+                else if vleObjectProperty.Values[MsgPropTrShotAim] = MsgPropTrShotAim3 then
                   Data.ShotAim := 3;
                 Data.ShotAngle := Min(
                   Data.ShotAim := 3;
                 Data.ShotAngle := Min(
-                  StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_ANGLE]], 0), 360);
+                  StrToIntDef(vleObjectProperty.Values[MsgPropTrShotAngle], 0), 360);
                 Data.ShotWait := Min(Max(
                 Data.ShotWait := Min(Max(
-                  StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EX_DELAY]], 0), 0), 65535);
+                  StrToIntDef(vleObjectProperty.Values[MsgPropTrExDelay], 0), 0), 65535);
                 Data.ShotAccuracy := Min(Max(
                 Data.ShotAccuracy := Min(Max(
-                  StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_ACC]], 0), 0), 65535);
+                  StrToIntDef(vleObjectProperty.Values[MsgPropTrShotAcc], 0), 0), 65535);
                 Data.ShotAmmo := Min(Max(
                 Data.ShotAmmo := Min(Max(
-                  StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_AMMO]], 0), 0), 65535);
+                  StrToIntDef(vleObjectProperty.Values[MsgPropTrShotAmmo], 0), 0), 65535);
                 Data.ShotIntReload := Min(Max(
                 Data.ShotIntReload := Min(Max(
-                  StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_RELOAD]], 0), 0), 65535);
+                  StrToIntDef(vleObjectProperty.Values[MsgPropTrShotReload], 0), 0), 65535);
               end;
 
             TRIGGER_EFFECT:
               begin
                 Data.FXCount := Min(Max(
               end;
 
             TRIGGER_EFFECT:
               begin
                 Data.FXCount := Min(Max(
-                  StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_COUNT]], 0), 0), 255);
-                if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_TYPE]] = _lc[I_PROP_TR_EFFECT_PARTICLE] then
+                  StrToIntDef(vleObjectProperty.Values[MsgPropTrCount], 0), 0), 255);
+                if vleObjectProperty.Values[MsgPropTrEffectType] = MsgPropTrEffectParticle then
                 begin
                   Data.FXType := TRIGGER_EFFECT_PARTICLE;
                   Data.FXSubType := TRIGGER_EFFECT_SLIQUID;
                 begin
                   Data.FXType := TRIGGER_EFFECT_PARTICLE;
                   Data.FXSubType := TRIGGER_EFFECT_SLIQUID;
-                  if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_SLIQUID] then
+                  if vleObjectProperty.Values[MsgPropTrEffectSubtype] = MsgPropTrEffectSliquid then
                     Data.FXSubType := TRIGGER_EFFECT_SLIQUID
                     Data.FXSubType := TRIGGER_EFFECT_SLIQUID
-                  else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_LLIQUID] then
+                  else if vleObjectProperty.Values[MsgPropTrEffectSubtype] = MsgPropTrEffectLliquid then
                     Data.FXSubType := TRIGGER_EFFECT_LLIQUID
                     Data.FXSubType := TRIGGER_EFFECT_LLIQUID
-                  else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_DLIQUID] then
+                  else if vleObjectProperty.Values[MsgPropTrEffectSubtype] = MsgPropTrEffectDliquid then
                     Data.FXSubType := TRIGGER_EFFECT_DLIQUID
                     Data.FXSubType := TRIGGER_EFFECT_DLIQUID
-                  else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_BLOOD] then
+                  else if vleObjectProperty.Values[MsgPropTrEffectSubtype] = MsgPropTrEffectBlood then
                     Data.FXSubType := TRIGGER_EFFECT_BLOOD
                     Data.FXSubType := TRIGGER_EFFECT_BLOOD
-                  else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_SPARK] then
+                  else if vleObjectProperty.Values[MsgPropTrEffectSubtype] = MsgPropTrEffectSpark then
                     Data.FXSubType := TRIGGER_EFFECT_SPARK
                     Data.FXSubType := TRIGGER_EFFECT_SPARK
-                  else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_BUBBLE] then
+                  else if vleObjectProperty.Values[MsgPropTrEffectSubtype] = MsgPropTrEffectBubble then
                     Data.FXSubType := TRIGGER_EFFECT_BUBBLE;
                 end else
                 begin
                   Data.FXType := TRIGGER_EFFECT_ANIMATION;
                     Data.FXSubType := TRIGGER_EFFECT_BUBBLE;
                 end else
                 begin
                   Data.FXType := TRIGGER_EFFECT_ANIMATION;
-                  Data.FXSubType := StrToEffect(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]]);
+                  Data.FXSubType := StrToEffect(vleObjectProperty.Values[MsgPropTrEffectSubtype]);
                 end;
                 a := Min(Max(
                 end;
                 a := Min(Max(
-                  StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_COLOR]], 0), 0), $FFFFFF);
+                  StrToIntDef(vleObjectProperty.Values[MsgPropTrEffectColor], 0), 0), $FFFFFF);
                 Data.FXColorR := a and $FF;
                 Data.FXColorG := (a shr 8) and $FF;
                 Data.FXColorB := (a shr 16) and $FF;
                 Data.FXColorR := a and $FF;
                 Data.FXColorG := (a shr 8) and $FF;
                 Data.FXColorB := (a shr 16) and $FF;
-                if NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_CENTER]]) then
+                if NameToBool(vleObjectProperty.Values[MsgPropTrEffectCenter]) then
                   Data.FXPos := 0
                 else
                   Data.FXPos := 1;
                 Data.FXWait := Min(Max(
                   Data.FXPos := 0
                 else
                   Data.FXPos := 1;
                 Data.FXWait := Min(Max(
-                  StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EX_DELAY]], 0), 0), 65535);
+                  StrToIntDef(vleObjectProperty.Values[MsgPropTrExDelay], 0), 0), 65535);
                 Data.FXVelX := Min(Max(
                 Data.FXVelX := Min(Max(
-                  StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_VELX]], 0), -128), 127);
+                  StrToIntDef(vleObjectProperty.Values[MsgPropTrEffectVelx], 0), -128), 127);
                 Data.FXVelY := Min(Max(
                 Data.FXVelY := Min(Max(
-                  StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_VELY]], 0), -128), 127);
+                  StrToIntDef(vleObjectProperty.Values[MsgPropTrEffectVely], 0), -128), 127);
                 Data.FXSpreadL := Min(Max(
                 Data.FXSpreadL := Min(Max(
-                  StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SPL]], 0), 0), 255);
+                  StrToIntDef(vleObjectProperty.Values[MsgPropTrEffectSpl], 0), 0), 255);
                 Data.FXSpreadR := Min(Max(
                 Data.FXSpreadR := Min(Max(
-                  StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SPR]], 0), 0), 255);
+                  StrToIntDef(vleObjectProperty.Values[MsgPropTrEffectSpr], 0), 0), 255);
                 Data.FXSpreadU := Min(Max(
                 Data.FXSpreadU := Min(Max(
-                  StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SPU]], 0), 0), 255);
+                  StrToIntDef(vleObjectProperty.Values[MsgPropTrEffectSpu], 0), 0), 255);
                 Data.FXSpreadD := Min(Max(
                 Data.FXSpreadD := Min(Max(
-                  StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SPD]], 0), 0), 255);
+                  StrToIntDef(vleObjectProperty.Values[MsgPropTrEffectSpd], 0), 0), 255);
               end;
           end;
         end;
               end;
           end;
         end;
@@ -5146,9 +5554,9 @@ begin
   if i = -1 then
     Exit;
 
   if i = -1 then
     Exit;
 
-  if MessageBox(0, PChar(Format(_lc[I_MSG_DEL_TEXTURE_PROMT],
+  if Application.MessageBox(PChar(Format(MsgMsgDelTexturePrompt,
                                 [SelectedTexture()])),
                                 [SelectedTexture()])),
-                PChar(_lc[I_MSG_DEL_TEXTURE]),
+                PChar(MsgMsgDelTexture),
                 MB_ICONQUESTION or MB_YESNO or
                 MB_DEFBUTTON1) <> idYes then
     Exit;
                 MB_ICONQUESTION or MB_YESNO or
                 MB_DEFBUTTON1) <> idYes then
     Exit;
@@ -5158,7 +5566,7 @@ begin
       if (gPanels[a].PanelType <> 0) and
          (gPanels[a].TextureName = SelectedTexture()) then
       begin
       if (gPanels[a].PanelType <> 0) and
          (gPanels[a].TextureName = SelectedTexture()) then
       begin
-        ErrorMessageBox(_lc[I_MSG_DEL_TEXTURE_CANT]);
+        ErrorMessageBox(MsgMsgDelTextureCant);
         Exit;
       end;
 
         Exit;
       end;
 
@@ -5172,10 +5580,7 @@ end;
 
 procedure TMainForm.aNewMapExecute(Sender: TObject);
 begin
 
 procedure TMainForm.aNewMapExecute(Sender: TObject);
 begin
-  if (MessageBox(0, PChar(_lc[I_MSG_CLEAR_MAP_PROMT]),
-                 PChar(_lc[I_MSG_CLEAR_MAP]),
-                 MB_ICONQUESTION or MB_YESNO or
-                 MB_DEFBUTTON1) = mrYes) then
+  if Application.MessageBox(PChar(MsgMsgClearMapPrompt), PChar(MsgMsgClearMap), MB_ICONQUESTION or MB_YESNO or MB_DEFBUTTON1) = mrYes then
     FullClear();
 end;
 
     FullClear();
 end;
 
@@ -5195,7 +5600,7 @@ begin
         UNDO_DELETE_PANEL:
           begin
             AddPanel(Panel^);
         UNDO_DELETE_PANEL:
           begin
             AddPanel(Panel^);
-            Panel := nil;
+            Dispose(Panel);
           end;
         UNDO_DELETE_ITEM: AddItem(Item);
         UNDO_DELETE_AREA: AddArea(Area);
           end;
         UNDO_DELETE_ITEM: AddItem(Item);
         UNDO_DELETE_AREA: AddArea(Area);
@@ -5210,9 +5615,7 @@ begin
     end;
 
   SetLength(UndoBuffer, Length(UndoBuffer)-1);
     end;
 
   SetLength(UndoBuffer, Length(UndoBuffer)-1);
-
   RemoveSelectFromObjects();
   RemoveSelectFromObjects();
-
   miUndo.Enabled := UndoBuffer <> nil;
 end;
 
   miUndo.Enabled := UndoBuffer <> nil;
 end;
 
@@ -5322,7 +5725,7 @@ begin
     QuickSortCopyBuffer(0, b);
   end;
 
     QuickSortCopyBuffer(0, b);
   end;
 
-// Ð\9fестановка ссылок триггеров:
+// Ð\9fостановка ссылок триггеров:
   for a := 0 to Length(CopyBuffer)-1 do
     if CopyBuffer[a].ObjectType = OBJECT_TRIGGER then
     begin
   for a := 0 to Length(CopyBuffer)-1 do
     if CopyBuffer[a].ObjectType = OBJECT_TRIGGER then
     begin
@@ -5427,21 +5830,34 @@ var
   swad, ssec, sres: String;
   NoTextureID: DWORD;
   pmin: TPoint;
   swad, ssec, sres: String;
   NoTextureID: DWORD;
   pmin: TPoint;
+  xadj, yadj: LongInt;
 begin
   CopyBuffer := nil;
   NoTextureID := 0;
 begin
   CopyBuffer := nil;
   NoTextureID := 0;
+
   pmin.X := High(pmin.X);
   pmin.Y := High(pmin.Y);
 
   StringToCopyBuffer(ClipBoard.AsText, CopyBuffer, pmin);
   pmin.X := High(pmin.X);
   pmin.Y := High(pmin.Y);
 
   StringToCopyBuffer(ClipBoard.AsText, CopyBuffer, pmin);
-  rel := not(ssShift in GetKeyShiftState());
-
   if CopyBuffer = nil then
     Exit;
 
   if CopyBuffer = nil then
     Exit;
 
+  rel := not(ssShift in GetKeyShiftState());
+  h := High(CopyBuffer);
   RemoveSelectFromObjects();
 
   RemoveSelectFromObjects();
 
-  h := High(CopyBuffer);
+  if g_CollidePoint(
+    pmin.X, pmin.Y, -MapOffset.X-32, -MapOffset.Y-32, RenderPanel.Width, RenderPanel.Height) then
+  begin
+    xadj := DotStep;
+    yadj := DotStep;
+  end
+  else
+  begin
+    xadj := Floor((-pmin.X - MapOffset.X + 32) / DotStep) * DotStep;
+    yadj := Floor((-pmin.Y - MapOffset.Y + 32) / DotStep) * DotStep;
+  end;
+
   for a := 0 to h do
     with CopyBuffer[a] do
     begin
   for a := 0 to h do
     with CopyBuffer[a] do
     begin
@@ -5451,8 +5867,8 @@ begin
           begin
             if rel then
             begin
           begin
             if rel then
             begin
-              Panel^.X := Panel^.X - pmin.X - MapOffset.X + 32;
-              Panel^.Y := Panel^.Y - pmin.Y - MapOffset.Y + 32;
+              Panel^.X += xadj;
+              Panel^.Y += yadj;
             end;
 
             Panel^.TextureID := TEXTURE_SPECIAL_NONE;
             end;
 
             Panel^.TextureID := TEXTURE_SPECIAL_NONE;
@@ -5510,8 +5926,8 @@ begin
           begin
             if rel then
             begin
           begin
             if rel then
             begin
-              Item.X := Item.X - pmin.X - MapOffset.X + 32;
-              Item.Y := Item.Y - pmin.Y - MapOffset.Y + 32;
+              Item.X += xadj;
+              Item.Y += yadj;
             end;
 
             ID := AddItem(Item);
             end;
 
             ID := AddItem(Item);
@@ -5523,8 +5939,8 @@ begin
           begin
             if rel then
             begin
           begin
             if rel then
             begin
-              Monster.X := Monster.X - pmin.X - MapOffset.X + 32;
-              Monster.Y := Monster.Y - pmin.Y - MapOffset.Y + 32;
+              Monster.X += xadj;
+              Monster.Y += yadj;
             end;
 
             ID := AddMonster(Monster);
             end;
 
             ID := AddMonster(Monster);
@@ -5536,8 +5952,8 @@ begin
           begin
             if rel then
             begin
           begin
             if rel then
             begin
-              Area.X := Area.X - pmin.X - MapOffset.X + 32;
-              Area.Y := Area.Y - pmin.Y - MapOffset.Y + 32;
+              Area.X += xadj;
+              Area.Y += yadj;
             end;
 
             ID := AddArea(Area);
             end;
 
             ID := AddArea(Area);
@@ -5550,42 +5966,34 @@ begin
             if rel then
               with Trigger do
               begin
             if rel then
               with Trigger do
               begin
-                X := X - pmin.X - MapOffset.X + 32;
-                Y := Y - pmin.Y - MapOffset.Y + 32;
+                X += xadj;
+                Y += yadj;
 
                 case TriggerType of
                   TRIGGER_TELEPORT:
                     begin
 
                 case TriggerType of
                   TRIGGER_TELEPORT:
                     begin
-                      Data.TargetPoint.X :=
-                      Data.TargetPoint.X - pmin.X - MapOffset.X + 32;
-                      Data.TargetPoint.Y :=
-                      Data.TargetPoint.Y - pmin.Y - MapOffset.Y + 32;
+                      Data.TargetPoint.X += xadj;
+                      Data.TargetPoint.Y += yadj;
                     end;
                   TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF:
                     begin
                     end;
                   TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF:
                     begin
-                      Data.tX := Data.tX - pmin.X - MapOffset.X + 32;
-                      Data.tY := Data.tY - pmin.Y - MapOffset.Y + 32;
+                      Data.tX += xadj;
+                      Data.tY += yadj;
                     end;
                   TRIGGER_SPAWNMONSTER:
                     begin
                     end;
                   TRIGGER_SPAWNMONSTER:
                     begin
-                      Data.MonPos.X :=
-                      Data.MonPos.X - pmin.X - MapOffset.X + 32;
-                      Data.MonPos.Y :=
-                      Data.MonPos.Y - pmin.Y - MapOffset.Y + 32;
+                      Data.MonPos.X += xadj;
+                      Data.MonPos.Y += yadj;
                     end;
                   TRIGGER_SPAWNITEM:
                     begin
                     end;
                   TRIGGER_SPAWNITEM:
                     begin
-                      Data.ItemPos.X :=
-                      Data.ItemPos.X - pmin.X - MapOffset.X + 32;
-                      Data.ItemPos.Y :=
-                      Data.ItemPos.Y - pmin.Y - MapOffset.Y + 32;
+                      Data.ItemPos.X += xadj;
+                      Data.ItemPos.Y += yadj;
                     end;
                   TRIGGER_SHOT:
                     begin
                     end;
                   TRIGGER_SHOT:
                     begin
-                      Data.ShotPos.X :=
-                      Data.ShotPos.X - pmin.X - MapOffset.X + 32;
-                      Data.ShotPos.Y :=
-                      Data.ShotPos.Y - pmin.Y - MapOffset.Y + 32;
+                      Data.ShotPos.X += xadj;
+                      Data.ShotPos.Y += yadj;
                     end;
                 end;
               end;
                     end;
                 end;
               end;
@@ -5645,11 +6053,11 @@ var
 begin
   Key := vleObjectProperty.Keys[vleObjectProperty.Row];
 
 begin
   Key := vleObjectProperty.Keys[vleObjectProperty.Row];
 
-  if Key = _lc[I_PROP_PANEL_TYPE] then
+  if Key = MsgPropPanelType then
     begin
       with ChooseTypeForm, vleObjectProperty do
       begin // Выбор типа панели:
     begin
       with ChooseTypeForm, vleObjectProperty do
       begin // Выбор типа панели:
-        Caption := _lc[I_PROP_PANEL_TYPE];
+        Caption := MsgPropPanelType;
         lbTypeSelect.Items.Clear();
 
         for b := 0 to High(PANELNAMES) do
         lbTypeSelect.Items.Clear();
 
         for b := 0 to High(PANELNAMES) do
@@ -5667,33 +6075,33 @@ begin
         end;
       end
     end
         end;
       end
     end
-  else if Key = _lc[I_PROP_TR_TELEPORT_TO] then
+  else if Key = MsgPropTrTeleportTo then
     SelectFlag := SELECTFLAG_TELEPORT
     SelectFlag := SELECTFLAG_TELEPORT
-  else if Key = _lc[I_PROP_TR_SPAWN_TO] then
+  else if Key = MsgPropTrSpawnTo then
     SelectFlag := SELECTFLAG_SPAWNPOINT
     SelectFlag := SELECTFLAG_SPAWNPOINT
-  else if (Key = _lc[I_PROP_TR_DOOR_PANEL]) or
-          (Key = _lc[I_PROP_TR_TRAP_PANEL]) then
+  else if (Key = MsgPropTrDoorPanel) or
+          (Key = MsgPropTrTrapPanel) then
     SelectFlag := SELECTFLAG_DOOR
     SelectFlag := SELECTFLAG_DOOR
-  else if Key = _lc[I_PROP_TR_TEXTURE_PANEL] then
+  else if Key = MsgPropTrTexturePanel then
   begin
     DrawPressRect := False;
     SelectFlag := SELECTFLAG_TEXTURE;
   end
   begin
     DrawPressRect := False;
     SelectFlag := SELECTFLAG_TEXTURE;
   end
-  else if Key = _lc[I_PROP_TR_SHOT_PANEL] then
+  else if Key = MsgPropTrShotPanel then
     SelectFlag := SELECTFLAG_SHOTPANEL
     SelectFlag := SELECTFLAG_SHOTPANEL
-  else if Key = _lc[I_PROP_TR_LIFT_PANEL] then
+  else if Key = MsgPropTrLiftPanel then
     SelectFlag := SELECTFLAG_LIFT
     SelectFlag := SELECTFLAG_LIFT
-  else if key = _lc[I_PROP_TR_EX_MONSTER] then
+  else if key = MsgPropTrExMonster then
     SelectFlag := SELECTFLAG_MONSTER
     SelectFlag := SELECTFLAG_MONSTER
-  else if Key = _lc[I_PROP_TR_EX_AREA] then
+  else if Key = MsgPropTrExArea then
   begin
     SelectFlag := SELECTFLAG_NONE;
     DrawPressRect := True;
   end
   begin
     SelectFlag := SELECTFLAG_NONE;
     DrawPressRect := True;
   end
-  else if Key = _lc[I_PROP_TR_NEXT_MAP] then
+  else if Key = MsgPropTrNextMap then
     begin // Выбор следующей карты:
       g_ProcessResourceStr(OpenedMap, @FileName, nil, nil);
     begin // Выбор следующей карты:
       g_ProcessResourceStr(OpenedMap, @FileName, nil, nil);
-      SelectMapForm.Caption := _lc[I_CAP_SELECT];
+      SelectMapForm.Caption := MsgCapSelect;
       SelectMapForm.GetMaps(FileName);
 
       if SelectMapForm.ShowModal() = mrOK then
       SelectMapForm.GetMaps(FileName);
 
       if SelectMapForm.ShowModal() = mrOK then
@@ -5702,8 +6110,8 @@ begin
         vleObjectPropertyApply(Sender);
       end;
     end
         vleObjectPropertyApply(Sender);
       end;
     end
-  else if (Key = _lc[I_PROP_TR_SOUND_NAME]) or
-          (Key = _lc[I_PROP_TR_MUSIC_NAME]) then
+  else if (Key = MsgPropTrSoundName) or
+          (Key = MsgPropTrMusicName) then
     begin // Выбор файла звука/музыки:
       AddSoundForm.OKFunction := nil;
       AddSoundForm.lbResourcesList.MultiSelect := False;
     begin // Выбор файла звука/музыки:
       AddSoundForm.OKFunction := nil;
       AddSoundForm.lbResourcesList.MultiSelect := False;
@@ -5715,7 +6123,7 @@ begin
         vleObjectPropertyApply(Sender);
       end;
     end
         vleObjectPropertyApply(Sender);
       end;
     end
-  else if Key = _lc[I_PROP_TR_ACTIVATION] then
+  else if Key = MsgPropTrActivation then
     with ActivationTypeForm, vleObjectProperty do
     begin // Выбор типов активации:
       cbPlayerCollide.Checked := Pos('PC', Values[Key]) > 0;
     with ActivationTypeForm, vleObjectProperty do
     begin // Выбор типов активации:
       cbPlayerCollide.Checked := Pos('PC', Values[Key]) > 0;
@@ -5745,7 +6153,7 @@ begin
         vleObjectPropertyApply(Sender);
       end;
     end
         vleObjectPropertyApply(Sender);
       end;
     end
-  else if Key = _lc[I_PROP_TR_KEYS] then
+  else if Key = MsgPropTrKeys then
     with KeysForm, vleObjectProperty do
     begin // Выбор необходимых ключей:
       cbRedKey.Checked := Pos('RK', Values[Key]) > 0;
     with KeysForm, vleObjectProperty do
     begin // Выбор необходимых ключей:
       cbRedKey.Checked := Pos('RK', Values[Key]) > 0;
@@ -5772,10 +6180,10 @@ begin
         vleObjectPropertyApply(Sender);
       end;
     end
         vleObjectPropertyApply(Sender);
       end;
     end
-  else if Key = _lc[I_PROP_TR_FX_TYPE] then
+  else if Key = MsgPropTrFxType then
     with ChooseTypeForm, vleObjectProperty do
     begin // Выбор типа эффекта:
     with ChooseTypeForm, vleObjectProperty do
     begin // Выбор типа эффекта:
-      Caption := _lc[I_CAP_FX_TYPE];
+      Caption := MsgCapFxType;
       lbTypeSelect.Items.Clear();
 
       for b := EFFECT_NONE to EFFECT_FIRE do
       lbTypeSelect.Items.Clear();
 
       for b := EFFECT_NONE to EFFECT_FIRE do
@@ -5790,10 +6198,10 @@ begin
         vleObjectPropertyApply(Sender);
       end;
     end
         vleObjectPropertyApply(Sender);
       end;
     end
-  else if Key = _lc[I_PROP_TR_MONSTER_TYPE] then
+  else if Key = MsgPropTrMonsterType then
     with ChooseTypeForm, vleObjectProperty do
     begin // Выбор типа монстра:
     with ChooseTypeForm, vleObjectProperty do
     begin // Выбор типа монстра:
-      Caption := _lc[I_CAP_MONSTER_TYPE];
+      Caption := MsgCapMonsterType;
       lbTypeSelect.Items.Clear();
 
       for b := MONSTER_DEMON to MONSTER_MAN do
       lbTypeSelect.Items.Clear();
 
       for b := MONSTER_DEMON to MONSTER_MAN do
@@ -5808,10 +6216,10 @@ begin
         vleObjectPropertyApply(Sender);
       end;
     end
         vleObjectPropertyApply(Sender);
       end;
     end
-  else if Key = _lc[I_PROP_TR_ITEM_TYPE] then
+  else if Key = MsgPropTrItemType then
     with ChooseTypeForm, vleObjectProperty do
     begin // Выбор типа предмета:
     with ChooseTypeForm, vleObjectProperty do
     begin // Выбор типа предмета:
-      Caption := _lc[I_CAP_ITEM_TYPE];
+      Caption := MsgCapItemType;
       lbTypeSelect.Items.Clear();
 
       for b := ITEM_MEDKIT_SMALL to ITEM_KEY_BLUE do
       lbTypeSelect.Items.Clear();
 
       for b := ITEM_MEDKIT_SMALL to ITEM_KEY_BLUE do
@@ -5831,16 +6239,16 @@ begin
       if ShowModal() = mrOK then
       begin
         b := lbTypeSelect.ItemIndex + ITEM_MEDKIT_SMALL;
       if ShowModal() = mrOK then
       begin
         b := lbTypeSelect.ItemIndex + ITEM_MEDKIT_SMALL;
-        if b >= ITEM_WEAPON_KASTET then
+        if b >= ITEM_WEAPON_IRONFIST then
           b := b + 2;
         Values[Key] := ItemToStr(b);
         vleObjectPropertyApply(Sender);
       end;
     end
           b := b + 2;
         Values[Key] := ItemToStr(b);
         vleObjectPropertyApply(Sender);
       end;
     end
-  else if Key = _lc[I_PROP_TR_SHOT_TYPE] then
+  else if Key = MsgPropTrShotType then
     with ChooseTypeForm, vleObjectProperty do
     begin // Выбор типа предмета:
     with ChooseTypeForm, vleObjectProperty do
     begin // Выбор типа предмета:
-      Caption := _lc[I_PROP_TR_SHOT_TYPE];
+      Caption := MsgPropTrShotType;
       lbTypeSelect.Items.Clear();
 
       for b := TRIGGER_SHOT_PISTOL to TRIGGER_SHOT_MAX do
       lbTypeSelect.Items.Clear();
 
       for b := TRIGGER_SHOT_PISTOL to TRIGGER_SHOT_MAX do
@@ -5855,15 +6263,15 @@ begin
         vleObjectPropertyApply(Sender);
       end;
     end
         vleObjectPropertyApply(Sender);
       end;
     end
-  else if Key = _lc[I_PROP_TR_EFFECT_TYPE] then
+  else if Key = MsgPropTrEffectType then
     with ChooseTypeForm, vleObjectProperty do
     begin // Выбор типа эффекта:
     with ChooseTypeForm, vleObjectProperty do
     begin // Выбор типа эффекта:
-      Caption := _lc[I_CAP_FX_TYPE];
+      Caption := MsgCapFxType;
       lbTypeSelect.Items.Clear();
 
       lbTypeSelect.Items.Clear();
 
-      lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_PARTICLE]);
-      lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_ANIMATION]);
-      if Values[Key] = _lc[I_PROP_TR_EFFECT_ANIMATION] then
+      lbTypeSelect.Items.Add(MsgPropTrEffectParticle);
+      lbTypeSelect.Items.Add(MsgPropTrEffectAnimation);
+      if Values[Key] = MsgPropTrEffectAnimation then
         lbTypeSelect.ItemIndex := 1
       else
         lbTypeSelect.ItemIndex := 0;
         lbTypeSelect.ItemIndex := 1
       else
         lbTypeSelect.ItemIndex := 0;
@@ -5872,19 +6280,19 @@ begin
       begin
         b := lbTypeSelect.ItemIndex;
         if b = 0 then
       begin
         b := lbTypeSelect.ItemIndex;
         if b = 0 then
-          Values[Key] := _lc[I_PROP_TR_EFFECT_PARTICLE]
+          Values[Key] := MsgPropTrEffectParticle
         else
         else
-          Values[Key] := _lc[I_PROP_TR_EFFECT_ANIMATION];
+          Values[Key] := MsgPropTrEffectAnimation;
         vleObjectPropertyApply(Sender);
       end;
     end
         vleObjectPropertyApply(Sender);
       end;
     end
-  else if Key = _lc[I_PROP_TR_EFFECT_SUBTYPE] then
+  else if Key = MsgPropTrEffectSubtype then
     with ChooseTypeForm, vleObjectProperty do
     begin // Выбор подтипа эффекта:
     with ChooseTypeForm, vleObjectProperty do
     begin // Выбор подтипа эффекта:
-      Caption := _lc[I_CAP_FX_TYPE];
+      Caption := MsgCapFxType;
       lbTypeSelect.Items.Clear();
 
       lbTypeSelect.Items.Clear();
 
-      if Values[_lc[I_PROP_TR_EFFECT_TYPE]] = _lc[I_PROP_TR_EFFECT_ANIMATION] then
+      if Values[MsgPropTrEffectType] = MsgPropTrEffectAnimation then
       begin
         for b := EFFECT_TELEPORT to EFFECT_FIRE do
           lbTypeSelect.Items.Add(EffectToStr(b));
       begin
         for b := EFFECT_TELEPORT to EFFECT_FIRE do
           lbTypeSelect.Items.Add(EffectToStr(b));
@@ -5892,22 +6300,22 @@ begin
         lbTypeSelect.ItemIndex := StrToEffect(Values[Key]) - 1;
       end else
       begin
         lbTypeSelect.ItemIndex := StrToEffect(Values[Key]) - 1;
       end else
       begin
-        lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_SLIQUID]);
-        lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_LLIQUID]);
-        lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_DLIQUID]);
-        lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_BLOOD]);
-        lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_SPARK]);
-        lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_BUBBLE]);
+        lbTypeSelect.Items.Add(MsgPropTrEffectSliquid);
+        lbTypeSelect.Items.Add(MsgPropTrEffectLliquid);
+        lbTypeSelect.Items.Add(MsgPropTrEffectDliquid);
+        lbTypeSelect.Items.Add(MsgPropTrEffectBlood);
+        lbTypeSelect.Items.Add(MsgPropTrEffectSpark);
+        lbTypeSelect.Items.Add(MsgPropTrEffectBubble);
         lbTypeSelect.ItemIndex := TRIGGER_EFFECT_SLIQUID;
         lbTypeSelect.ItemIndex := TRIGGER_EFFECT_SLIQUID;
-        if Values[Key] = _lc[I_PROP_TR_EFFECT_LLIQUID] then
+        if Values[Key] = MsgPropTrEffectLliquid then
           lbTypeSelect.ItemIndex := TRIGGER_EFFECT_LLIQUID;
           lbTypeSelect.ItemIndex := TRIGGER_EFFECT_LLIQUID;
-        if Values[Key] = _lc[I_PROP_TR_EFFECT_DLIQUID] then
+        if Values[Key] = MsgPropTrEffectDliquid then
           lbTypeSelect.ItemIndex := TRIGGER_EFFECT_DLIQUID;
           lbTypeSelect.ItemIndex := TRIGGER_EFFECT_DLIQUID;
-        if Values[Key] = _lc[I_PROP_TR_EFFECT_BLOOD] then
+        if Values[Key] = MsgPropTrEffectBlood then
           lbTypeSelect.ItemIndex := TRIGGER_EFFECT_BLOOD;
           lbTypeSelect.ItemIndex := TRIGGER_EFFECT_BLOOD;
-        if Values[Key] = _lc[I_PROP_TR_EFFECT_SPARK] then
+        if Values[Key] = MsgPropTrEffectSpark then
           lbTypeSelect.ItemIndex := TRIGGER_EFFECT_SPARK;
           lbTypeSelect.ItemIndex := TRIGGER_EFFECT_SPARK;
-        if Values[Key] = _lc[I_PROP_TR_EFFECT_BUBBLE] then
+        if Values[Key] = MsgPropTrEffectBubble then
           lbTypeSelect.ItemIndex := TRIGGER_EFFECT_BUBBLE;
       end;
 
           lbTypeSelect.ItemIndex := TRIGGER_EFFECT_BUBBLE;
       end;
 
@@ -5915,26 +6323,26 @@ begin
       begin
         b := lbTypeSelect.ItemIndex;
 
       begin
         b := lbTypeSelect.ItemIndex;
 
-        if Values[_lc[I_PROP_TR_EFFECT_TYPE]] = _lc[I_PROP_TR_EFFECT_ANIMATION] then
+        if Values[MsgPropTrEffectType] = MsgPropTrEffectAnimation then
           Values[Key] := EffectToStr(b + 1)
         else begin
           Values[Key] := EffectToStr(b + 1)
         else begin
-          Values[Key] := _lc[I_PROP_TR_EFFECT_SLIQUID];
+          Values[Key] := MsgPropTrEffectSliquid;
           if b = TRIGGER_EFFECT_LLIQUID then
           if b = TRIGGER_EFFECT_LLIQUID then
-            Values[Key] := _lc[I_PROP_TR_EFFECT_LLIQUID];
+            Values[Key] := MsgPropTrEffectLliquid;
           if b = TRIGGER_EFFECT_DLIQUID then
           if b = TRIGGER_EFFECT_DLIQUID then
-            Values[Key] := _lc[I_PROP_TR_EFFECT_DLIQUID];
+            Values[Key] := MsgPropTrEffectDliquid;
           if b = TRIGGER_EFFECT_BLOOD then
           if b = TRIGGER_EFFECT_BLOOD then
-            Values[Key] := _lc[I_PROP_TR_EFFECT_BLOOD];
+            Values[Key] := MsgPropTrEffectBlood;
           if b = TRIGGER_EFFECT_SPARK then
           if b = TRIGGER_EFFECT_SPARK then
-            Values[Key] := _lc[I_PROP_TR_EFFECT_SPARK];
+            Values[Key] := MsgPropTrEffectSpark;
           if b = TRIGGER_EFFECT_BUBBLE then
           if b = TRIGGER_EFFECT_BUBBLE then
-            Values[Key] := _lc[I_PROP_TR_EFFECT_BUBBLE];
+            Values[Key] := MsgPropTrEffectBubble;
         end;
 
         vleObjectPropertyApply(Sender);
       end;
     end
         end;
 
         vleObjectPropertyApply(Sender);
       end;
     end
-  else if Key = _lc[I_PROP_TR_EFFECT_COLOR] then
+  else if Key = MsgPropTrEffectColor then
     with vleObjectProperty do
     begin // Выбор цвета эффекта:
       ColorDialog.Color := StrToIntDef(Values[Key], 0);
     with vleObjectProperty do
     begin // Выбор цвета эффекта:
       ColorDialog.Color := StrToIntDef(Values[Key], 0);
@@ -5944,7 +6352,7 @@ begin
         vleObjectPropertyApply(Sender);
       end;
     end
         vleObjectPropertyApply(Sender);
       end;
     end
-  else if Key = _lc[I_PROP_PANEL_TEX] then
+  else if Key = MsgPropPanelTex then
     begin // Смена текстуры:
       vleObjectProperty.Values[Key] := SelectedTexture();
       vleObjectPropertyApply(Sender);
     begin // Смена текстуры:
       vleObjectProperty.Values[Key] := SelectedTexture();
       vleObjectPropertyApply(Sender);
@@ -5971,12 +6379,12 @@ begin
 
   g_ProcessResourceStr(OpenedMap, FileName, Section, Res);
 
 
   g_ProcessResourceStr(OpenedMap, FileName, Section, Res);
 
-  SaveMap(FileName+':\'+Res);
+  SaveMap(FileName+':\'+Res, '');
 end;
 
 procedure TMainForm.aOpenMapExecute(Sender: TObject);
 begin
 end;
 
 procedure TMainForm.aOpenMapExecute(Sender: TObject);
 begin
-  OpenDialog.Filter := _lc[I_FILE_FILTER_ALL];
+  OpenDialog.Filter := MsgFileFilterAll;
 
   if OpenDialog.Execute() then
   begin
 
   if OpenDialog.Execute() then
   begin
@@ -6012,30 +6420,8 @@ begin
 end;
 
 procedure TMainForm.FormActivate(Sender: TObject);
 end;
 
 procedure TMainForm.FormActivate(Sender: TObject);
-var
-  lang: Integer;
-  config: TConfig;
 begin
   MainForm.ActiveControl := RenderPanel;
 begin
   MainForm.ActiveControl := RenderPanel;
-
-// Язык:
-  if gLanguage = '' then
-  begin
-    lang := SelectLanguageForm.ShowModal();
-    case lang of
-      1:   gLanguage := LANGUAGE_ENGLISH;
-      else gLanguage := LANGUAGE_RUSSIAN;
-    end;
-
-    config := TConfig.CreateFile(EditorDir+'Editor.cfg');
-    config.WriteStr('Editor', 'Language', gLanguage);
-    config.SaveFile(EditorDir+'Editor.cfg');
-    config.Free();
-  end;
-
-  //e_WriteLog('Read language file', MSG_NOTIFY);
-  //g_Language_Load(EditorDir+'\data\'+gLanguage+LANGUAGE_FILE_NAME);
-  g_Language_Set(gLanguage);
 end;
 
 procedure TMainForm.aDeleteMap(Sender: TObject);
 end;
 
 procedure TMainForm.aDeleteMap(Sender: TObject);
@@ -6046,7 +6432,7 @@ var
   a: Integer;
   str: String;
 begin
   a: Integer;
   str: String;
 begin
-  OpenDialog.Filter := _lc[I_FILE_FILTER_WAD];
+  OpenDialog.Filter := MsgFileFilterWad;
 
   if not OpenDialog.Execute() then
     Exit;
 
   if not OpenDialog.Execute() then
     Exit;
@@ -6063,7 +6449,7 @@ begin
 
   MapList := WAD.GetResourcesList('');
 
 
   MapList := WAD.GetResourcesList('');
 
-  SelectMapForm.Caption := _lc[I_CAP_REMOVE];
+  SelectMapForm.Caption := MsgCapRemove;
   SelectMapForm.lbMapList.Items.Clear();
 
   if MapList <> nil then
   SelectMapForm.lbMapList.Items.Clear();
 
   if MapList <> nil then
@@ -6076,20 +6462,16 @@ begin
     MapName := '';
     Move(str[1], MapName[0], Min(16, Length(str)));
 
     MapName := '';
     Move(str[1], MapName[0], Min(16, Length(str)));
 
-    if MessageBox(0, PChar(Format(_lc[I_MSG_DELETE_MAP_PROMT],
-                           [MapName, OpenDialog.FileName])),
-                  PChar(_lc[I_MSG_DELETE_MAP]),
-                  MB_ICONQUESTION or MB_YESNO or
-                  MB_DEFBUTTON2) <> mrYes then
+    if Application.MessageBox(PChar(Format(MsgMsgDeleteMapPrompt, [MapName, OpenDialog.FileName])), PChar(MsgMsgDeleteMap), MB_ICONQUESTION or MB_YESNO or MB_DEFBUTTON2) <> mrYes then
       Exit;
 
     WAD.RemoveResource('', utf2win(MapName));
       Exit;
 
     WAD.RemoveResource('', utf2win(MapName));
-    
-    MessageBox(0, PChar(Format(_lc[I_MSG_MAP_DELETED_PROMT],
-                               [MapName])),
-               PChar(_lc[I_MSG_MAP_DELETED]),
-               MB_ICONINFORMATION or MB_OK or
-               MB_DEFBUTTON1);
+
+    Application.MessageBox(
+      PChar(Format(MsgMsgMapDeletedPrompt, [MapName])),
+      PChar(MsgMsgMapDeleted),
+      MB_ICONINFORMATION or MB_OK or MB_DEFBUTTON1
+    );
 
     WAD.SaveTo(OpenDialog.FileName);
 
 
     WAD.SaveTo(OpenDialog.FileName);
 
@@ -6253,35 +6635,59 @@ begin
 end;
 
 procedure TMainForm.aSaveMapAsExecute(Sender: TObject);
 end;
 
 procedure TMainForm.aSaveMapAsExecute(Sender: TObject);
-var
-  idx: Integer;
+  var i, idx: Integer; list: TStringList; fmt: String;
 begin
 begin
-  SaveDialog.Filter := _lc[I_FILE_FILTER_WAD];
-
-  if not SaveDialog.Execute() then
-    Exit;
-
-  SaveMapForm.GetMaps(SaveDialog.FileName, True);
+  list := TStringList.Create();
+
+  // TODO: get loclized strings automatically from language files
+  SaveDialog.DefaultExt := '.dfz';
+  SaveDialog.FilterIndex := 1;
+  SaveDialog.Filter := '';
+  gWADEditorFactory.GetRegistredEditors(list);
+  for i := 0 to list.Count - 1 do
+  begin
+    if list[i] = 'DFZIP' then
+      SaveDialog.FilterIndex := i + 1;
 
 
-  if SaveMapForm.ShowModal() <> mrOK then
-    Exit;
+    if i <> 0 then
+      SaveDialog.Filter := SaveDialog.Filter + '|';
 
 
-  SaveDialog.InitialDir := ExtractFileDir(SaveDialog.FileName);
-  OpenedMap := SaveDialog.FileName+':\'+SaveMapForm.eMapName.Text;
-  OpenedWAD := SaveDialog.FileName;
+    if list[i] = 'DFWAD' then
+      SaveDialog.Filter := SaveDialog.Filter + MsgFileFilterSaveDFWAD
+    else if list[i] = 'DFZIP' then
+      SaveDialog.Filter := SaveDialog.Filter + MsgFileFilterSaveDFZIP
+    else
+      SaveDialog.Filter := SaveDialog.Filter + list[i] + '|*.*';
+  end;
 
 
-  idx := RecentFiles.IndexOf(OpenedMap);
-// Такая карта уже недавно открывалась:
-  if idx >= 0 then
-    RecentFiles.Delete(idx);
-  RecentFiles.Insert(0, OpenedMap);
-  RefreshRecentMenu;
+  if SaveDialog.Execute() then
+  begin
+    i := SaveDialog.FilterIndex - 1;
+    if (i >= 0) and (i < list.Count) then fmt := list[i] else fmt := '';
 
 
-  SaveMap(OpenedMap);
+    SaveMapForm.GetMaps(SaveDialog.FileName, True, fmt);
+    if SaveMapForm.ShowModal() = mrOK then
+    begin
+      SaveDialog.InitialDir := ExtractFileDir(SaveDialog.FileName);
+      OpenedMap := SaveDialog.FileName+':\'+SaveMapForm.eMapName.Text;
+      OpenedWAD := SaveDialog.FileName;
+
+      idx := RecentFiles.IndexOf(OpenedMap);
+      // Такая карта уже недавно открывалась:
+      if idx >= 0 then
+        RecentFiles.Delete(idx);
+      RecentFiles.Insert(0, OpenedMap);
+      RefreshRecentMenu;
+
+      SaveMap(OpenedMap, fmt);
+
+      gMapInfo.FileName := SaveDialog.FileName;
+      gMapInfo.MapName := SaveMapForm.eMapName.Text;
+      UpdateCaption(gMapInfo.Name, ExtractFileName(gMapInfo.FileName), gMapInfo.MapName);
+    end;
+  end;
 
 
-  gMapInfo.FileName := SaveDialog.FileName;
-  gMapInfo.MapName := SaveMapForm.eMapName.Text;
-  UpdateCaption(gMapInfo.Name, ExtractFileName(gMapInfo.FileName), gMapInfo.MapName);
+  list.Free();
 end;
 
 procedure TMainForm.aSelectAllExecute(Sender: TObject);
 end;
 
 procedure TMainForm.aSelectAllExecute(Sender: TObject);
@@ -6317,6 +6723,8 @@ begin
           if gTriggers[a].TriggerType <> TRIGGER_NONE then
             SelectObject(OBJECT_TRIGGER, a, True);
   end;
           if gTriggers[a].TriggerType <> TRIGGER_NONE then
             SelectObject(OBJECT_TRIGGER, a, True);
   end;
+
+  RecountSelectedObjects();
 end;
 
 procedure TMainForm.tbGridOnClick(Sender: TObject);
 end;
 
 procedure TMainForm.tbGridOnClick(Sender: TObject);
@@ -6326,21 +6734,21 @@ begin
 end;
 
 procedure TMainForm.OnIdle(Sender: TObject; var Done: Boolean);
 end;
 
 procedure TMainForm.OnIdle(Sender: TObject; var Done: Boolean);
+  const MaxFPS = 60;
+  var f: AnsiString;
 begin
 begin
-  // FIXME: this is a shitty hack
-  if not gDataLoaded then
+  // TODO: move refresh to user actions (ask to repaint only when something changed)
+  if GetTickCount64() - LastDrawTime >= 1000 div MaxFPS then
   begin
   begin
-    e_WriteLog('Init OpenGL', MSG_NOTIFY);
-    e_InitGL();
-    e_WriteLog('Loading data', MSG_NOTIFY);
-    LoadStdFont('STDTXT', 'STDFONT', gEditorFont);
-    e_WriteLog('Loading more data', MSG_NOTIFY);
-    LoadData();
-    e_WriteLog('Loading even more data', MSG_NOTIFY);
-    gDataLoaded := True;
-    MainForm.FormResize(nil);
+    PanelMap.Refresh;
+  end;
+
+  if StartMap <> '' then
+  begin
+    f := StartMap;
+    StartMap := '';
+    OpenMap(f, '');
   end;
   end;
-  Draw();
 end;
 
 procedure TMainForm.miMapPreviewClick(Sender: TObject);
 end;
 
 procedure TMainForm.miMapPreviewClick(Sender: TObject);
@@ -6500,40 +6908,73 @@ begin
   PackMapForm.ShowModal();
 end;
 
   PackMapForm.ShowModal();
 end;
 
-procedure TMainForm.miMapTestSettingsClick(Sender: TObject);
+type SSArray = array of String;
+
+function ParseString (Str: AnsiString): SSArray;
+  function GetStr (var Str: AnsiString): AnsiString;
+    var a, b: Integer;
+  begin
+    Result := '';
+    if Str[1] = '"' then
+      for b := 1 to Length(Str) do
+        if (b = Length(Str)) or (Str[b + 1] = '"') then
+        begin
+          Result := Copy(Str, 2, b - 1);
+          Delete(Str, 1, b + 1);
+          Str := Trim(Str);
+          Exit;
+        end;
+    for a := 1 to Length(Str) do
+      if (a = Length(Str)) or (Str[a + 1] = ' ') then
+      begin
+        Result := Copy(Str, 1, a);
+        Delete(Str, 1, a + 1);
+        Str := Trim(Str);
+        Exit;
+      end;
+  end;
 begin
 begin
-  MapTestForm.ShowModal();
+  Result := nil;
+  Str := Trim(Str);
+  while Str <> '' do
+  begin
+    SetLength(Result, Length(Result)+1);
+    Result[High(Result)] := GetStr(Str);
+  end;
 end;
 
 procedure TMainForm.miTestMapClick(Sender: TObject);
 var
 end;
 
 procedure TMainForm.miTestMapClick(Sender: TObject);
 var
-  cmd, mapWAD, mapToRun, tempWAD: String;
+  newWAD, oldWAD, tempMap, ext: String;
+  args: SSArray;
   opt: LongWord;
   opt: LongWord;
-  time: Integer;
+  time, i: Integer;
   proc: TProcessUTF8;
   res: Boolean;
 begin
   proc: TProcessUTF8;
   res: Boolean;
 begin
-  mapToRun := '';
-  if OpenedMap <> '' then
-  begin
-    // Указываем текущую карту для теста:
-    g_ProcessResourceStr(OpenedMap, @mapWAD, nil, @mapToRun);
-    mapToRun := mapWAD + ':\' + mapToRun;
-    mapToRun := ExtractRelativePath(ExtractFilePath(TestD2dExe) + 'maps/', mapToRun);
-  end;
+  // Ignore while map testing in progress
+  if MapTestProcess <> nil then
+    Exit;
+
   // Сохраняем временную карту:
   time := 0;
   repeat
   // Сохраняем временную карту:
   time := 0;
   repeat
-    mapWAD := ExtractFilePath(TestD2dExe) + Format('maps/temp%.4d.wad', [time]);
+    newWAD := Format('%s/temp%.4d', [MapsDir, time]);
     Inc(time);
     Inc(time);
-  until not FileExists(mapWAD);
-  tempWAD := mapWAD + ':\' + TEST_MAP_NAME;
-  SaveMap(tempWAD);
-
-  tempWAD := ExtractRelativePath(ExtractFilePath(TestD2dExe) + 'maps/', tempWAD);
-// Если карта не была открыта, указываем временную в качестве текущей:
-  if mapToRun = '' then
-    mapToRun := tempWAD;
+  until not FileExists(newWAD);
+  if OpenedMap <> '' then
+  begin
+    oldWad := g_ExtractWadName(OpenedMap);
+    newWad := newWad + ExtractFileExt(oldWad);
+    if CopyFile(oldWad, newWad) = false then
+      e_WriteLog('MapTest: unable to copy [' + oldWad + '] to [' + newWad + ']', MSG_WARNING)
+  end
+  else
+  begin
+    newWad := newWad + '.wad'
+  end;
+  tempMap := newWAD + ':\' + TEST_MAP_NAME;
+  SaveMap(tempMap, '');
 
 // Опции игры:
   opt := 32 + 64;
 
 // Опции игры:
   opt := 32 + 64;
@@ -6548,23 +6989,32 @@ begin
   if TestOptionsMonstersDM then
     opt := opt + 16;
 
   if TestOptionsMonstersDM then
     opt := opt + 16;
 
-// Составляем командную строку:
-  cmd := '-map "' + mapToRun + '"';
-  cmd := cmd + ' -testmap "' + tempWAD + '"';
-  cmd := cmd + ' -gm ' + TestGameMode;
-  cmd := cmd + ' -limt ' + TestLimTime;
-  cmd := cmd + ' -lims ' + TestLimScore;
-  cmd := cmd + ' -opt ' + IntToStr(opt);
-
-  if TestMapOnce then
-    cmd := cmd + ' --close';
-
-  cmd := cmd + ' --debug';
-
 // Запускаем:
   proc := TProcessUTF8.Create(nil);
   proc.Executable := TestD2dExe;
 // Запускаем:
   proc := TProcessUTF8.Create(nil);
   proc.Executable := TestD2dExe;
-  proc.Parameters.Add(cmd);
+  {$IFDEF DARWIN}
+    // TODO: get real executable name from Info.plist
+    if LowerCase(ExtractFileExt(TestD2dExe)) = '.app' then
+      proc.Executable := TestD2dExe + DirectorySeparator + 'Contents' + DirectorySeparator + 'MacOS' + DirectorySeparator + 'Doom2DF';
+  {$ENDIF}
+  proc.Parameters.Add('-map');
+  proc.Parameters.Add(tempMap);
+  proc.Parameters.Add('-gm');
+  proc.Parameters.Add(TestGameMode);
+  proc.Parameters.Add('-limt');
+  proc.Parameters.Add(TestLimTime);
+  proc.Parameters.Add('-lims');
+  proc.Parameters.Add(TestLimScore);
+  proc.Parameters.Add('-opt');
+  proc.Parameters.Add(IntToStr(opt));
+  proc.Parameters.Add('--debug');
+  if TestMapOnce then
+    proc.Parameters.Add('--close');
+
+  args := ParseString(TestD2DArgs);
+  for i := 0 to High(args) do
+    proc.Parameters.Add(args[i]);
+
   res := True;
   try
     proc.Execute();
   res := True;
   try
     proc.Execute();
@@ -6573,31 +7023,30 @@ begin
   end;
   if res then
   begin
   end;
   if res then
   begin
-    Application.Minimize();
-    proc.WaitOnExit();
-  end;
-  if (not res) or (proc.ExitCode < 0) then
+    tbTestMap.Enabled := False;
+    MapTestFile := newWAD;
+    MapTestProcess := proc;
+  end
+  else
   begin
   begin
-    MessageBox(0, 'FIXME',
-               PChar(_lc[I_MSG_EXEC_ERROR]),
-               MB_OK or MB_ICONERROR);
+    Application.MessageBox(PChar(MsgMsgExecError), 'FIXME', MB_OK or MB_ICONERROR);
+    SysUtils.DeleteFile(newWAD);
+    proc.Free();
   end;
   end;
-  proc.Free();
-
-  SysUtils.DeleteFile(mapWAD);
-  Application.Restore();
 end;
 
 procedure TMainForm.sbVerticalScroll(Sender: TObject;
   ScrollCode: TScrollCode; var ScrollPos: Integer);
 begin
 end;
 
 procedure TMainForm.sbVerticalScroll(Sender: TObject;
   ScrollCode: TScrollCode; var ScrollPos: Integer);
 begin
-  MapOffset.Y := -Normalize16(sbVertical.Position);
+  MapOffset.Y := -sbVertical.Position;
+  RenderPanel.Invalidate;
 end;
 
 procedure TMainForm.sbHorizontalScroll(Sender: TObject;
   ScrollCode: TScrollCode; var ScrollPos: Integer);
 begin
 end;
 
 procedure TMainForm.sbHorizontalScroll(Sender: TObject;
   ScrollCode: TScrollCode; var ScrollPos: Integer);
 begin
-  MapOffset.X := -Normalize16(sbHorizontal.Position);
+  MapOffset.X := -sbHorizontal.Position;
+  RenderPanel.Invalidate;
 end;
 
 procedure TMainForm.miOpenWadMapClick(Sender: TObject);
 end;
 
 procedure TMainForm.miOpenWadMapClick(Sender: TObject);
@@ -6638,6 +7087,8 @@ begin
     for a := 0 to High(gTriggers) do
       if gTriggers[a].TriggerType <> TRIGGER_NONE then
         SelectObject(OBJECT_TRIGGER, a, True);
     for a := 0 to High(gTriggers) do
       if gTriggers[a].TriggerType <> TRIGGER_NONE then
         SelectObject(OBJECT_TRIGGER, a, True);
+
+  RecountSelectedObjects();
 end;
 
 procedure TMainForm.Splitter1CanResize(Sender: TObject;
 end;
 
 procedure TMainForm.Splitter1CanResize(Sender: TObject;
@@ -6662,8 +7113,7 @@ begin
   EditingProperties := False;
 end;
 
   EditingProperties := False;
 end;
 
-procedure TMainForm.FormKeyUp(Sender: TObject; var Key: Word;
-  Shift: TShiftState);
+procedure TMainForm.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
 begin
 // Объекты передвигались:
   if MainForm.ActiveControl = RenderPanel then
 begin
 // Объекты передвигались:
   if MainForm.ActiveControl = RenderPanel then
@@ -6681,6 +7131,7 @@ begin
     if PreviewMode = 2 then
       PreviewMode := 0;
   end;
     if PreviewMode = 2 then
       PreviewMode := 0;
   end;
+  RenderPanelMouseMove(Sender, Shift, RenderMousePos().X, RenderMousePos().Y);
 end;
 
 end.
 end;
 
 end.