X-Git-Url: http://deadsoftware.ru/gitweb?a=blobdiff_plain;f=src%2Feditor%2Ff_main.pas;h=d40610abd027e358c38bd3916a6ba3f53c979e57;hb=HEAD;hp=645e4c1d365bfa0c4139dc1ba123aab2540b4ff4;hpb=1fb1b203de2d204939df9112dda1f72760c956ee;p=d2df-editor.git diff --git a/src/editor/f_main.pas b/src/editor/f_main.pas index 645e4c1..d40610a 100644 --- a/src/editor/f_main.pas +++ b/src/editor/f_main.pas @@ -1,37 +1,58 @@ unit f_main; -{$MODE Delphi} +{$INCLUDE ../shared/a_modes.inc} interface uses - LCLIntf, LCLType, LMessages, SysUtils, Variants, Classes, Graphics, - Controls, Forms, Dialogs, ImgList, StdCtrls, Buttons, - ComCtrls, ValEdit, Types, ToolWin, Menus, ExtCtrls, - CheckLst, Grids, OpenGLContext; + LCLIntf, LCLType, SysUtils, Variants, Classes, Graphics, + Controls, Forms, Dialogs, StdCtrls, Buttons, + ComCtrls, ValEdit, Types, Menus, ExtCtrls, + CheckLst, Grids, OpenGLContext, Utils, UTF8Process; type { TMainForm } TMainForm = class(TForm) - lLoad: TLabel; - // Главное меню: + MapTestTimer: TTimer; + Splitter1: TSplitter; + Splitter2: TSplitter; + StatusBar: TStatusBar; + OpenDialog: TOpenDialog; + SaveDialog: TSaveDialog; + ColorDialog: TColorDialog; + + // Menu: MainMenu: TMainMenu; - // "Файл": + ImageList: TImageList; + // Apple menu: + miApple: TMenuItem; + miAppleAbout: TMenuItem; + miAppleLine0: TMenuItem; + miApplePref: TMenuItem; + miAppleLine1: TMenuItem; + // File menu: miMenuFile: TMenuItem; miNewMap: TMenuItem; miOpenMap: TMenuItem; + miMacRecentSubMenu: TMenuItem; + miMacRecentEnd: TMenuItem; + miMacRecentClear: TMenuItem; + Separator1: TMenuItem; miSaveMap: TMenuItem; miSaveMapAs: TMenuItem; miOpenWadMap: TMenuItem; miLine1: TMenuItem; + miReopenMap: TMenuItem; miSaveMiniMap: TMenuItem; miDeleteMap: TMenuItem; miPackMap: TMenuItem; + miWinRecentStart: TMenuItem; + miWinRecent: TMenuItem; miLine2: TMenuItem; miExit: TMenuItem; - // "Правка": + // Edit menu: miMenuEdit: TMenuItem; miUndo: TMenuItem; miLine3: TMenuItem; @@ -41,14 +62,16 @@ type miLine4: TMenuItem; miSelectAll: TMenuItem; miLine5: TMenuItem; - miToFore: TMenuItem; - miToBack: TMenuItem; - // "Инструменты": - miMenuTools: TMenuItem; miSnapToGrid: TMenuItem; - miMiniMap: 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; @@ -59,31 +82,31 @@ type miLayer7: TMenuItem; miLayer8: TMenuItem; miLayer9: TMenuItem; - // "Сервис": + miViewLine1: TMenuItem; + miMiniMap: TMenuItem; + miShowEdges: TMenuItem; + miViewLine2: TMenuItem; + miMapPreview: TMenuItem; + // Service menu: miMenuService: TMenuItem; miCheckMap: TMenuItem; miOptimmization: TMenuItem; - miMapPreview: 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; - // Скрытый пункт меню для Ctrl+Tab: - miHidden1: TMenuItem; + // HIDDEN menu: + miMenuHidden: TMenuItem; minexttab: TMenuItem; + selectall1: TMenuItem; - // Панель инструментов: + // Toolbar: + ilToolbar: TImageList; MainToolBar: TToolBar; - pbLoad: TProgressBar; - pLoadProgress: TPanel; - RenderPanel: TOpenGLControl; tbNewMap: TToolButton; tbOpenMap: TToolButton; tbSaveMap: TToolButton; @@ -92,12 +115,6 @@ type tbShowMap: TToolButton; tbLine2: TToolButton; tbShow: TToolButton; - tbLine3: TToolButton; - tbGridOn: TToolButton; - tbGrid: TToolButton; - tbLine4: TToolButton; - tbTestMap: TToolButton; - // Всплывающее меню для кнопки слоев: pmShow: TPopupMenu; miLayerP1: TMenuItem; miLayerP2: TMenuItem; @@ -108,31 +125,37 @@ type 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; - // Полосы прокрутки: + RenderPanel: TOpenGLControl; sbHorizontal: TScrollBar; sbVertical: TScrollBar; - // Панель свойств: + // Object propertiy editor: PanelProps: TPanel; - // Панель применения свойств: PanelPropApply: TPanel; bApplyProperty: TButton; - // Редактор свойств объектов: vleObjectProperty: TValueListEditor; - // Панель объектов - вкладки: + // Object palette: PanelObjs: TPanel; pcObjects: TPageControl; - // Вкладка "Панели": + // Panels Tab: tsPanels: TTabSheet; + PanelPanelType: TPanel; + lbPanelType: TListBox; lbTextureList: TListBox; - // Панель настройки текстур: PanelTextures: TPanel; LabelTxW: TLabel; lTextureWidth: TLabel; @@ -142,43 +165,27 @@ type bbAddTexture: TBitBtn; bbRemoveTexture: TBitBtn; bClearTexture: TButton; - // Панель типов панелей: - PanelPanelType: TPanel; - lbPanelType: TListBox; - // Вкладка "Предметы": + // Items Tab: tsItems: TTabSheet; lbItemList: TListBox; cbOnlyDM: TCheckBox; cbFall: TCheckBox; - // Вкладка "Монстры": + // Monsters Tab: tsMonsters: TTabSheet; lbMonsterList: TListBox; rbMonsterLeft: TRadioButton; rbMonsterRight: TRadioButton; - // Вкладка "Области": + // Areas Tab: tsAreas: TTabSheet; lbAreasList: TListBox; rbAreaLeft: TRadioButton; rbAreaRight: TRadioButton; - // Вкладка "Триггеры": + // Triggers Tab: 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); @@ -204,15 +211,27 @@ type procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean); procedure FormCreate(Sender: TObject); procedure FormDestroy(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 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 MapTestCheck(Sender: TObject); procedure vleObjectPropertyEditButtonClick(Sender: TObject); + procedure vleObjectPropertyApply(Sender: TObject); procedure vleObjectPropertyGetPickList(Sender: TObject; const KeyName: String; Values: TStrings); procedure vleObjectPropertyKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); @@ -236,8 +255,6 @@ type 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); @@ -254,12 +271,15 @@ type procedure FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); private + LastDrawTime: UInt64; procedure Draw(); procedure OnIdle(Sender: TObject; var Done: Boolean); + procedure RefillRecentMenu (menu: TMenuItem; start: Integer; fmt: AnsiString); public procedure RefreshRecentMenu(); - { procedure lbTextureListDrawItem(Control: TWinControl; Index: Integer; - Rect: TRect; State: TOwnerDrawState); } + procedure OpenMapFile(FileName: String); + function RenderMousePos(): TPoint; + procedure RecountSelectedObjects(); end; const @@ -278,19 +298,20 @@ const var MainForm: TMainForm; - EditorDir: String; + StartMap: String; OpenedMap: String; OpenedWAD: String; DotColor: TColor; DotEnable: Boolean; - DotStep: Byte; - DotStepOne, DotStepTwo: Byte; + DotStep: Word; + DotStepOne, DotStepTwo: Word; DotSize: Byte; DrawTexturePanel: Boolean; DrawPanelSize: Boolean; BackColor: TColor; PreviewColor: TColor; + UseCheckerboard: Boolean; Scale: Byte; RecentCount: Integer; RecentFiles: TStringList; @@ -304,12 +325,14 @@ var 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); - PreviewMode: Boolean = False; + ContourEnabled: Array [LAYER_BACK..LAYER_TRIGGERS] of Boolean = + (False, False, False, False, False, False, False, False, False); + PreviewMode: Byte = 0; gLanguage: String; FormCaption: String; @@ -323,14 +346,14 @@ procedure ChangeShownProperty(Name: String; NewValue: String); implementation uses - f_options, e_graphics, e_log, GL, GLExt, Math, + 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, MAPWRITER, MAPSTRUCT, + f_activationtype, f_keys, wadreader, fileutil, 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; @@ -380,14 +403,13 @@ const SELECTFLAG_SHOTPANEL = 7; SELECTFLAG_SELECTED = 8; - RECENT_FILES_MENU_START = 11; + RECENT_FILES_MENU_START = 12; 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); @@ -408,9 +430,8 @@ type end; TCopyRec = record - ObjectType: Byte; ID: Cardinal; - case Byte of + case ObjectType: Byte of OBJECT_PANEL: (Panel: ^TPanel); OBJECT_ITEM: (Item: TItem); OBJECT_AREA: (Area: TArea); @@ -431,8 +452,10 @@ var LastMovePoint: Types.TPoint; MouseLDown: Boolean; MouseRDown: Boolean; + MouseMDown: Boolean; MouseLDownPos: Types.TPoint; MouseRDownPos: Types.TPoint; + MouseMDownPos: Types.TPoint; SelectFlag: Byte = SELECTFLAG_NONE; MouseAction: Byte = MOUSEACTION_NONE; @@ -444,6 +467,8 @@ var UndoBuffer: Array of Array of TUndoRec = nil; + MapTestProcess: TProcessUTF8; + MapTestFile: String; {$R *.lfm} @@ -683,10 +708,10 @@ begin 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; @@ -695,17 +720,11 @@ begin 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: - 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; @@ -730,6 +749,7 @@ var str: String; begin MainForm.vleObjectProperty.Strings.Clear(); + MainForm.RecountSelectedObjects(); // Отображаем свойства если выделен только один объект: if SelectedObjectCount() <> 1 then @@ -740,7 +760,7 @@ begin 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; @@ -752,31 +772,31 @@ 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; - 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; - 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; - 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; - 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; @@ -784,7 +804,7 @@ 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; @@ -792,13 +812,13 @@ 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; - 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; @@ -813,25 +833,25 @@ 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; - 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; - 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; - 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; @@ -844,19 +864,19 @@ 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; - 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; - with ItemProps[InsertRow(_lc[I_PROP_DIRECTION], DirNames[Direction], True)] do + with ItemProps[InsertRow(MsgPropDirection, DirNames[Direction], True)] do begin EditStyle := esPickList; ReadOnly := True; @@ -869,19 +889,19 @@ 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; - 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; - with ItemProps[InsertRow(_lc[I_PROP_DIRECTION], DirNames[Direction], True)] do + with ItemProps[InsertRow(MsgPropDirection, DirNames[Direction], True)] do begin EditStyle := esPickList; ReadOnly := True; @@ -894,55 +914,55 @@ 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; - 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; - 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; - 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; - 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; - 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; - 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; - 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; - 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; @@ -951,7 +971,8 @@ begin case TriggerType of TRIGGER_EXIT: begin - with ItemProps[InsertRow(_lc[I_PROP_TR_NEXT_MAP], Data.MapName, True)] do + str := win2utf(Data.MapName); + with ItemProps[InsertRow(MsgPropTrNextMap, str, True)] do begin EditStyle := esEllipsis; ReadOnly := True; @@ -960,25 +981,25 @@ 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; - 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; - 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; - 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; @@ -988,19 +1009,19 @@ 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; - 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; - 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; @@ -1009,19 +1030,19 @@ 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; - 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; - 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; @@ -1031,33 +1052,33 @@ 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; - 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; - 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; - 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 - 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; @@ -1069,19 +1090,19 @@ 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; - 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; - 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; @@ -1090,13 +1111,13 @@ 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; - 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; @@ -1105,37 +1126,38 @@ begin TRIGGER_SOUND: begin - with ItemProps[InsertRow(_lc[I_PROP_TR_SOUND_NAME], Data.SoundName, True)] do + str := win2utf(Data.SoundName); + with ItemProps[InsertRow(MsgPropTrSoundName, str, True)] do 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; - 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; - 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; - 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; - 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; @@ -1144,70 +1166,70 @@ 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; - 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; - 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; - 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; - 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; - 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; - 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; - 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; - 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 - 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; - with ItemProps[InsertRow(_lc[I_PROP_TR_MONSTER_BEHAVIOUR], str, True)] do + with ItemProps[InsertRow(MsgPropTrMonsterBehaviour, str, True)] do begin EditStyle := esPickList; ReadOnly := True; @@ -1216,50 +1238,50 @@ 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; - 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; - 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; - 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; - 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; - 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; - 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; - 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; @@ -1268,18 +1290,19 @@ begin TRIGGER_MUSIC: begin - with ItemProps[InsertRow(_lc[I_PROP_TR_MUSIC_NAME], Data.MusicName, True)] do + str := win2utf(Data.MusicName); + with ItemProps[InsertRow(MsgPropTrMusicName, str, True)] do begin EditStyle := esEllipsis; ReadOnly := True; end; if Data.MusicAction = 1 then - str := _lc[I_PROP_TR_MUSIC_ON] + str := MsgPropTrMusicOn 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; @@ -1288,17 +1311,17 @@ 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; - 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; - 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; @@ -1308,38 +1331,38 @@ begin 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; - 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; - 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 - 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; - 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; - 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; - 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; @@ -1349,33 +1372,34 @@ begin 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; - 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 - 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; - 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; - with ItemProps[InsertRow(_lc[I_PROP_TR_MESSAGE_TEXT], Data.MessageText, True)] do + str := win2utf(Data.MessageText); + with ItemProps[InsertRow(MsgPropTrMessageText, str, True)] do 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; @@ -1384,36 +1408,50 @@ 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; - 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; + 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 - 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; - 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; - 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; - 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; @@ -1422,89 +1460,89 @@ 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; - 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; - 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 - 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; - 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; - 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 - 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; - 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; - 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; - 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; - 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; - 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; - 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; - 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; @@ -1513,17 +1551,17 @@ 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 - str := _lc[I_PROP_TR_EFFECT_PARTICLE] + str := MsgPropTrEffectParticle 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; @@ -1533,17 +1571,17 @@ begin if Data.FXType = 0 then case Data.FXSubType of TRIGGER_EFFECT_SLIQUID: - str := _lc[I_PROP_TR_EFFECT_SLIQUID]; + str := MsgPropTrEffectSliquid; TRIGGER_EFFECT_LLIQUID: - str := _lc[I_PROP_TR_EFFECT_LLIQUID]; + str := MsgPropTrEffectLliquid; TRIGGER_EFFECT_DLIQUID: - str := _lc[I_PROP_TR_EFFECT_DLIQUID]; + str := MsgPropTrEffectDliquid; TRIGGER_EFFECT_BLOOD: - str := _lc[I_PROP_TR_EFFECT_BLOOD]; + str := MsgPropTrEffectBlood; TRIGGER_EFFECT_SPARK: - str := _lc[I_PROP_TR_EFFECT_SPARK]; + str := MsgPropTrEffectSpark; TRIGGER_EFFECT_BUBBLE: - str := _lc[I_PROP_TR_EFFECT_BUBBLE]; + str := MsgPropTrEffectBubble; end; if Data.FXType = 1 then begin @@ -1551,61 +1589,61 @@ begin 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; - 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; - 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; - 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; - 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; - 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; - 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; - 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; - 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; - 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; @@ -1761,6 +1799,7 @@ begin RemoveSelectFromObjects(); MainForm.miUndo.Enabled := UndoBuffer <> nil; + MainForm.RecountSelectedObjects(); end; procedure Undo_Add(ObjectType: Byte; ID: DWORD; Group: Boolean = False); @@ -1787,15 +1826,28 @@ begin end; UndoBuffer[i, ii].AddID := ID; - 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(); - UndoBuffer := nil; + LoadSky(gMapInfo.SkyName); + DiscardUndoBuffer(); slInvalidTextures.Clear(); MapCheckForm.lbErrorList.Clear(); MapCheckForm.mErrorDescription.Clear(); @@ -1811,7 +1863,7 @@ end; 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; @@ -1827,41 +1879,41 @@ begin 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 - ErrorMessageBox(Format(_lc[I_MSG_WRONG_TEXWIDTH], + ErrorMessageBox(Format(MsgMsgWrongTexwidth, [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 - ErrorMessageBox(Format(_lc[I_MSG_WRONG_TEXHEIGHT], + ErrorMessageBox(Format(MsgMsgWrongTexheight, [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 - ErrorMessageBox(_lc[I_MSG_WRONG_ALPHA]); + ErrorMessageBox(MsgMsgWrongAlpha); 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 - ErrorMessageBox(_lc[I_MSG_WRONG_SIZE]); + ErrorMessageBox(MsgMsgWrongSize); 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 - ErrorMessageBox(_lc[I_MSG_WRONG_XY]); + ErrorMessageBox(MsgMsgWrongXy); Exit; end; @@ -1886,27 +1938,34 @@ var Width, Height: Word; fn: String; begin + Data := nil; + FrameLen := 0; + Width := 0; + Height := 0; + if aSection = '..' then SectionName := '' else SectionName := aSection; - if aWAD = _lc[I_WAD_SPECIAL_MAP] then + if aWAD = '' then + aWAD := MsgWadSpecialMap; + + if aWAD = MsgWadSpecialMap then begin // Файл карты g_ProcessResourceStr(OpenedMap, @fn, nil, nil); - //FileName := EditorDir+'maps\'+ExtractFileName(fn); 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 - FileName := EditorDir+'wads\'+aWAD; + FileName := WadsDir + DirectorySeparator + aWAD; ResourceName := aWAD+':'+SectionName+'\'+aTex; end; @@ -1917,7 +1976,7 @@ begin 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; @@ -1926,7 +1985,7 @@ begin 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; @@ -1934,7 +1993,7 @@ begin 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 @@ -1949,14 +2008,21 @@ begin begin // Аним. текстура GetFrame(FullResourceName, Data, FrameLen, Width, Height); - if g_CreateTextureMemorySize(Data, FrameLen, ResourceName, 0, 0, Width, Height, 1) then - a := MainForm.lbTextureList.Items.Add(ResourceName); + if not g_CreateTextureMemorySize(Data, FrameLen, ResourceName, 0, 0, Width, Height, 1) then + ok := False; + a := MainForm.lbTextureList.Items.Add(ResourceName); end else // Обычная текстура begin - if g_CreateTextureWAD(ResourceName, FullResourceName) then - a := MainForm.lbTextureList.Items.Add(ResourceName); + if not g_CreateTextureWAD(ResourceName, FullResourceName) then + ok := False; + a := MainForm.lbTextureList.Items.Add(ResourceName); end; + if (not ok) and (slInvalidTextures.IndexOf(ResourceName) = -1) then + begin + slInvalidTextures.Add(ResourceName); + ok := True; + end; if (a > -1) and (not silent) then SelectTexture(a); end; @@ -1984,6 +2050,7 @@ var MapName: String; idx: Integer; begin + SelectMapForm.Caption := MsgCapOpen; SelectMapForm.GetMaps(FileName); if (FileName = OpenedWAD) and @@ -2197,6 +2264,7 @@ procedure SwitchMap(); begin ShowMap := not ShowMap; MainForm.tbShowMap.Down := ShowMap; + MainForm.miMiniMap.Checked := ShowMap; end; procedure ShowEdges(); @@ -2205,6 +2273,7 @@ begin drEdge[3] := 255 else drEdge[3] := gAlphaEdge; + MainForm.miShowEdges.Checked := drEdge[3] <> 255; end; function SelectedTexture(): String; @@ -2314,9 +2383,10 @@ begin Result := Res; end; -procedure StringToCopyBuffer(Str: String; var CopyBuf: TCopyRecArray); +procedure StringToCopyBuffer(Str: String; var CopyBuf: TCopyRecArray; var pmin: TPoint); var i, j, t: Integer; + minArea, newArea, newX, newY: LongInt; function GetNext(): String; var @@ -2359,6 +2429,7 @@ var end; begin + minArea := High(minArea); Str := Trim(Str); if GetNext() <> CLIPBOARD_SIG then @@ -2369,8 +2440,7 @@ begin // Тип объекта: 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); @@ -2401,6 +2471,9 @@ begin TextureName := GetNext(); Alpha := StrToIntDef(GetNext(), 0); Blending := (GetNext() = '1'); + newArea := X * Y - Width * Height; + newX := X; + newY := Y; end; end; @@ -2412,6 +2485,9 @@ begin Y := StrToIntDef(GetNext(), 0); OnlyDM := (GetNext() = '1'); Fall := (GetNext() = '1'); + newArea := X * Y; + newX := X; + newY := Y; end; OBJECT_MONSTER: @@ -2420,11 +2496,12 @@ begin MonsterType := StrToIntDef(GetNext(), MONSTER_DEMON); X := StrToIntDef(GetNext(), 0); Y := StrToIntDef(GetNext(), 0); - - 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: @@ -2433,10 +2510,12 @@ begin AreaType := StrToIntDef(GetNext(), AREA_PLAYERPOINT1); X := StrToIntDef(GetNext(), 0); Y := StrToIntDef(GetNext(), 0); - 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: @@ -2451,11 +2530,20 @@ begin Key := StrToIntDef(GetNext(), 0); Enabled := (GetNext() = '1'); TexturePanel := StrToIntDef(GetNext(), 0); - - for j := 0 to 127 do - Data.Default[j] := StrToIntDef(GetNext(), 0); + for j := 0 to 127 + do Data.Default[j] := StrToIntDef(GetNext(), 0); + newArea := X * Y - Width * Height; + newX := X; + newY := Y; end; end; + + if newArea < minArea then + begin + minArea := newArea; + pmin.X := newX; + pmin.Y := newY; + end; end; end; @@ -2463,63 +2551,87 @@ end; //Закончились вспомогательные процедуры //---------------------------------------- -procedure TMainForm.RefreshRecentMenu(); +procedure TMainForm.miRecentFileExecute (Sender: TObject); var - i: Integer; - MI: TMenuItem; + s, fn: AnsiString; + n: LongInt; 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 - 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; -// Добавление в меню списка запомненных карт: + // fill with a new ones 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; -procedure TMainForm.aRecentFileExecute(Sender: TObject); -var - n, pw: Integer; - s, fn: String; +procedure TMainForm.RefreshRecentMenu(); + var start: Integer; begin - s := LowerCase((Sender as TMenuItem).Caption); - Delete(s, Pos('&', s), 1); - s := Trim(Copy(s, 1, 2)); - n := StrToIntDef(s, 0) - 1; + while RecentFiles.Count > RecentCount do + RecentFiles.Delete(RecentFiles.Count - 1); - if (n < 0) or (n >= RecentFiles.Count) then - Exit; + 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; - s := RecentFiles[n]; - pw := Pos('.wad:\', LowerCase(s)); - - if pw > 0 then - begin // Map name included - fn := Copy(s, 1, pw + 3); - Delete(s, 1, pw + 5); - if (FileExists(fn)) then - OpenMap(fn, s); - end - else // Only wad name - if (FileExists(s)) then - OpenMap(s, ''); + if miWinRecentStart.Visible then + begin + // 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; + +procedure TMainForm.miMacRecentClearClick(Sender: TObject); +begin + RecentFiles.Clear(); + RefreshRecentMenu(); end; procedure TMainForm.aEditorOptionsExecute(Sender: TObject); @@ -2537,16 +2649,18 @@ var cfglen: Integer; config: TConfig; begin + cfgdata := nil; cfglen := 0; + 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 - 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); @@ -2572,10 +2686,71 @@ var 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; @@ -2595,8 +2770,18 @@ begin 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 + else begin + Left := config.ReadInt('Editor', 'XPos', Left); + Top := config.ReadInt('Editor', 'YPos', Top); + Width := config.ReadInt('Editor', 'Width', Width); + Height := config.ReadInt('Editor', 'Height', Height); + end; if config.ReadBool('Editor', 'Maximize', False) then WindowState := wsMaximized; ShowMap := config.ReadBool('Editor', 'Minimap', False); @@ -2614,6 +2799,7 @@ begin DrawPanelSize := config.ReadBool('Editor', 'DrawPanelSize', True); BackColor := config.ReadInt('Editor', 'BackColor', $7F6040); PreviewColor := config.ReadInt('Editor', 'PreviewColor', $00FF00); + UseCheckerboard := config.ReadBool('Editor', 'UseCheckerboard', True); gColorEdge := config.ReadInt('Editor', 'EdgeColor', COLOR_EDGE); gAlphaEdge := config.ReadInt('Editor', 'EdgeAlpha', ALPHA_EDGE); if gAlphaEdge = 255 then @@ -2631,20 +2817,34 @@ begin 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; + 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; @@ -2654,7 +2854,11 @@ 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; @@ -2665,7 +2869,7 @@ begin tbShowMap.Down := ShowMap; tbGridOn.Down := DotEnable; pcObjects.ActivePageIndex := 0; - Application.Title := _lc[I_EDITOR_TITLE]; + Application.Title := MsgEditorTitle; Application.OnIdle := OnIdle; end; @@ -2676,6 +2880,23 @@ begin 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; @@ -2686,6 +2907,14 @@ var ObjCount: Word; aX, aY, aX2, aY2, XX, ScaleSz: Integer; begin + LastDrawTime := GetTickCount64(); + ID := 0; + PID := 0; + Width := 0; + Height := 0; + + InitGraphics(); + e_BeginRender(); e_Clear(GL_COLOR_BUFFER_BIT, @@ -2730,30 +2959,47 @@ begin end; // Рисуем сетку: - if DotEnable and (not PreviewMode) then + if DotEnable and (PreviewMode = 0) then begin if DotSize = 2 then a := -1 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; // Превью текстуры: if (lbTextureList.ItemIndex <> -1) and (cbPreview.Checked) and - (not IsSpecialTextureSel()) and (not PreviewMode) then + (not IsSpecialTextureSel()) and (PreviewMode = 0) then begin if not g_GetTexture(SelectedTexture(), ID) then g_GetTexture('NOTEXTURE', ID); g_GetTextureSizeByID(ID, Width, Height); - if g_GetTexture('PREVIEW', PID) then - e_DrawFill(PID, RenderPanel.Width-Width, RenderPanel.Height-Height, Width div 16 + 1, Height div 16 + 1, 0, True, False); + if UseCheckerboard then + begin + if g_GetTexture('PREVIEW', PID) then + e_DrawFill(PID, RenderPanel.Width-Width, RenderPanel.Height-Height, Width div 16 + 1, Height div 16 + 1, 0, True, False); + end else + e_DrawFillQuad(RenderPanel.Width-Width-2, RenderPanel.Height-Height-2, + RenderPanel.Width-1, RenderPanel.Height-1, + GetRValue(PreviewColor), GetGValue(PreviewColor), GetBValue(PreviewColor), 0); e_Draw(ID, RenderPanel.Width-Width, RenderPanel.Height-Height, 0, True, False); end; @@ -2771,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); - PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_TELEPORT], gEditorFont); + PrintBlack(MousePos.X+2, MousePos.Y+2, utf8to1251(MsgHintTeleport), gEditorFont); end; // Подсказка при выборе точки появления: @@ -2782,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); - PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_SPAWN], gEditorFont); + PrintBlack(MousePos.X+2, MousePos.Y+2, utf8to1251(MsgHintSpawn), gEditorFont); end; // Подсказка при выборе панели двери: @@ -2790,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); - PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_PANEL_DOOR], gEditorFont); + PrintBlack(MousePos.X+2, MousePos.Y+2, utf8to1251(MsgHintPanelDoor), gEditorFont); end; // Подсказка при выборе панели с текстурой: @@ -2798,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); - PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_PANEL_TEXTURE], gEditorFont); + PrintBlack(MousePos.X+2, MousePos.Y+2, utf8to1251(MsgHintPanelTexture), gEditorFont); end; // Подсказка при выборе панели индикации выстрела: @@ -2806,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); - PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_PANEL_SHOT], gEditorFont); + PrintBlack(MousePos.X+2, MousePos.Y+2, utf8to1251(MsgHintPanelShot), gEditorFont); end; // Подсказка при выборе панели лифта: @@ -2814,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); - PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_PANEL_LIFT], gEditorFont); + PrintBlack(MousePos.X+2, MousePos.Y+2, utf8to1251(MsgHintPanelLift), gEditorFont); end; // Подсказка при выборе монстра: @@ -2822,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); - PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_MONSTER], gEditorFont); + PrintBlack(MousePos.X+2, MousePos.Y+2, utf8to1251(MsgHintMonster), gEditorFont); end; // Подсказка при выборе области воздействия: @@ -2830,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); - PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_EXT_AREA], gEditorFont); + PrintBlack(MousePos.X+2, MousePos.Y+2, utf8to1251(MsgHintExtArea), gEditorFont); end; // Рисуем текстуры, если чертим панель: @@ -2842,8 +3088,9 @@ begin 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; // Прямоугольник выделения: @@ -2852,7 +3099,8 @@ begin 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); @@ -2860,9 +3108,9 @@ 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); - 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 // Растягиваем существующий @@ -2879,9 +3127,9 @@ begin 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); - 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; @@ -2985,18 +3233,31 @@ procedure TMainForm.FormResize(Sender: TObject); 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); @@ -3155,11 +3416,11 @@ begin 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; - 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; @@ -3176,7 +3437,7 @@ begin end; 2: if lbMonsterList.ItemIndex = -1 then - ErrorMessageBox(_lc[I_MSG_CHOOSE_MONSTER]) + ErrorMessageBox(MsgMsgChooseMonster) else begin monster.MonsterType := lbMonsterList.ItemIndex + MONSTER_DEMON; @@ -3197,7 +3458,7 @@ begin end; 3: if lbAreasList.ItemIndex = -1 then - ErrorMessageBox(_lc[I_MSG_CHOOSE_AREA]) + ErrorMessageBox(MsgMsgChooseArea) else if (lbAreasList.ItemIndex + 1) <> AREA_DOMFLAG then begin @@ -3487,6 +3748,16 @@ begin 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; @@ -3501,26 +3772,51 @@ procedure TMainForm.RenderPanelMouseUp(Sender: TObject; var panel: TPanel; trigger: TTrigger; - i: Integer; - IDArray: DWArray; 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; + if Button = mbMiddle then + MouseMDown := False; + + if DrawRect <> nil then + begin + Dispose(DrawRect); + DrawRect := nil; + end; - DrawRect := nil; ResizeType := RESIZETYPE_NONE; + TextureID := 0; 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: @@ -3528,7 +3824,7 @@ begin // Фон или передний план без текстуры - ошибка: 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 @@ -3550,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.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 @@ -3593,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); - 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; @@ -3788,7 +4111,7 @@ begin 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 @@ -3799,6 +4122,7 @@ begin // Объект передвинут или изменен в размере: if MouseAction in [MOUSEACTION_MOVEOBJ, MOUSEACTION_RESIZE] then begin + RenderPanel.Cursor := crDefault; MouseAction := MOUSEACTION_NONE; FillProperty(); Exit; @@ -3839,16 +4163,24 @@ begin 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(); + end + + else // Middle Mouse Button + begin + RenderPanel.Cursor := crDefault; + ReleaseCapture(); end; end; @@ -3857,14 +4189,30 @@ begin 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; + TextureID: DWORD; + wWidth, wHeight: Word; begin _id := GetFirstSelected(); + TextureID := 0; // Рисуем панель с текстурой, сетка - размеры текстуры: if (MouseAction = MOUSEACTION_DRAWPANEL) and @@ -3913,16 +4261,12 @@ 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; -// Изменение размера закончилось - ставим обычный курсор: - 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 @@ -3962,17 +4306,16 @@ begin 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; // Зажата только левая кнопка мыши: - if (not MouseRDown) and (MouseLDown) then + if (not MouseRDown) and (MouseLDown) and (not MouseMDown) then begin // Рисуем прямоугольник планирования панели: if MouseAction in [MOUSEACTION_DRAWPANEL, @@ -3981,10 +4324,29 @@ begin 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 @@ -3993,19 +4355,36 @@ begin 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; + end; // Строка состояния - координаты мыши: 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 - 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; @@ -4018,10 +4397,27 @@ end; procedure TMainForm.FormDestroy(Sender: TObject); var config: TConfig; + s: AnsiString; i: Integer; begin - config := TConfig.CreateFile(EditorDir+'\Editor.cfg'); + config := TConfig.CreateFile(CfgFileName); + + config.WriteInt('WADEditor', 'LogLevel', gWADEditorLogLevel); + if WindowState <> wsMaximized then + begin + config.WriteInt('Editor', 'XPos', Left); + config.WriteInt('Editor', 'YPos', Top); + config.WriteInt('Editor', 'Width', Width); + config.WriteInt('Editor', 'Height', Height); + end + else + begin + config.WriteInt('Editor', 'XPos', RestoredLeft); + config.WriteInt('Editor', 'YPos', RestoredTop); + config.WriteInt('Editor', 'Width', RestoredWidth); + config.WriteInt('Editor', 'Height', RestoredHeight); + end; config.WriteBool('Editor', 'Maximize', WindowState = wsMaximized); config.WriteBool('Editor', 'Minimap', ShowMap); config.WriteInt('Editor', 'PanelProps', PanelProps.ClientWidth); @@ -4030,23 +4426,40 @@ begin 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.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(); - config.SaveFile(EditorDir+'\Editor.cfg'); + config.SaveFile(CfgFileName); config.Free(); - slInvalidTextures.Free; + slInvalidTextures.Free(); + DiscardUndoBuffer(); +end; + +procedure TMainForm.FormDropFiles(Sender: TObject; + const FileNames: array of String); +begin + if Length(FileNames) <> 1 then + Exit; + + OpenMapFile(FileNames[0]); end; procedure TMainForm.RenderPanelResize(Sender: TObject); @@ -4055,6 +4468,27 @@ begin MainForm.Resize(); end; +procedure TMainForm.Splitter1Moved(Sender: TObject); +begin + 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; @@ -4073,36 +4507,54 @@ begin 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; + ok: Boolean; 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 @@ -4141,19 +4593,54 @@ begin if not (ssCtrl in Shift) then begin + // Быстрое превью карты: + if Key = Ord('E') then + begin + if PreviewMode = 0 then + PreviewMode := 2; + end; + // Вертикальный скролл карты: with sbVertical do begin if Key = Ord('W') then begin - Position := IfThen(Position > DotStep, Position-DotStep, 0); - MapOffset.Y := -Round(Position/16) * 16; + 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 + 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; if Key = Ord('S') then begin - Position := IfThen(Position+DotStep < Max, Position+DotStep, Max); - MapOffset.Y := -Round(Position/16) * 16; + 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 + 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; end; @@ -4162,22 +4649,59 @@ begin begin if Key = Ord('A') then begin - Position := IfThen(Position > DotStep, Position-DotStep, 0); - MapOffset.X := -Round(Position/16) * 16; + 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 + 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; if Key = Ord('D') then begin - Position := IfThen(Position+DotStep < Max, Position+DotStep, Max); - MapOffset.X := -Round(Position/16) * 16; + 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 + 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; end; + end + else // ssCtrl in Shift + begin + if ssShift in Shift then + begin + // Вставка по абсолютному смещению: + if Key = Ord('V') then + aPasteObjectExecute(Sender); + end; + RenderPanelMouseMove(Sender, Shift, RenderMousePos().X, RenderMousePos().Y); 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(); // Снять выделение: @@ -4217,7 +4741,7 @@ begin 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; @@ -4230,35 +4754,36 @@ begin DrawPressRect := False; Exit; end; + i := -1; // Выбор области воздействия, в зависимости от типа триггера - vleObjectProperty.FindRow(_lc[I_PROP_TR_EX_AREA], i); + vleObjectProperty.FindRow(MsgPropTrExArea, i); 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 - vleObjectProperty.FindRow(_lc[I_PROP_TR_TRAP_PANEL], i); + vleObjectProperty.FindRow(MsgPropTrTrapPanel, i); 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; - vleObjectProperty.FindRow(_lc[I_PROP_TR_TELEPORT_TO], i); + vleObjectProperty.FindRow(MsgPropTrTeleportTo, i); 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; @@ -4266,10 +4791,11 @@ begin 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); + SelectMapForm.Caption := MsgCapSelect; SelectMapForm.GetMaps(FileName); if SelectMapForm.ShowModal() = mrOK then @@ -4279,9 +4805,9 @@ begin end; Exit; end; - vleObjectProperty.FindRow(_lc[I_PROP_TR_SOUND_NAME], i); + vleObjectProperty.FindRow(MsgPropTrSoundName, i); 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; @@ -4295,9 +4821,9 @@ begin end; Exit; end; - vleObjectProperty.FindRow(_lc[I_PROP_TR_PUSH_ANGLE], i); + vleObjectProperty.FindRow(MsgPropTrPushAngle, i); 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; @@ -4330,6 +4856,9 @@ var TextureID: DWORD; TextureWidth, TextureHeight: Word; begin + TextureID := 0; + TextureWidth := 0; + TextureHeight := 0; if (lbTextureList.ItemIndex <> -1) and (not IsSpecialTextureSel()) then begin @@ -4341,8 +4870,8 @@ 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 @@ -4352,101 +4881,162 @@ begin end; end; +procedure TMainForm.lbTextureListDrawItem(Control: TWinControl; Index: Integer; + ARect: TRect; State: TOwnerDrawState); +begin + with Control as TListBox do + begin + if LCLType.odSelected in State then + begin + Canvas.Brush.Color := clHighlight; + Canvas.Font.Color := clHighlightText; + end else + if (Items <> nil) and (Index >= 0) then + if slInvalidTextures.IndexOf(Items[Index]) > -1 then + begin + Canvas.Brush.Color := clRed; + Canvas.Font.Color := clWhite; + end; + Canvas.FillRect(ARect); + Canvas.TextRect(ARect, ARect.Left, ARect.Top, Items[Index]); + 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 - if KeyName = _lc[I_PROP_DIRECTION] then + if KeyName = MsgPropDirection then 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 - else if KeyName = _lc[I_PROP_TR_MUSIC_ACT] then + else if KeyName = MsgPropTrMusicAct then begin - Values.Add(_lc[I_PROP_TR_MUSIC_ON]); - Values.Add(_lc[I_PROP_TR_MUSIC_OFF]); + Values.Add(MsgPropTrMusicOn); + Values.Add(MsgPropTrMusicOff); end - else if KeyName = _lc[I_PROP_TR_MONSTER_BEHAVIOUR] then + else if KeyName = MsgPropTrMonsterBehaviour then 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 - else if KeyName = _lc[I_PROP_TR_SCORE_ACT] then + else if KeyName = MsgPropTrScoreAct then 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 - else if KeyName = _lc[I_PROP_TR_SCORE_TEAM] then + else if KeyName = MsgPropTrScoreTeam then 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 - else if KeyName = _lc[I_PROP_TR_MESSAGE_KIND] then + else if KeyName = MsgPropTrMessageKind then 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 - else if KeyName = _lc[I_PROP_TR_MESSAGE_TO] then + else if KeyName = MsgPropTrMessageTo then 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 - else if KeyName = _lc[I_PROP_TR_SHOT_TO] then + else if KeyName = MsgPropTrShotTo then 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 - else if KeyName = _lc[I_PROP_TR_SHOT_AIM] then + else if KeyName = MsgPropTrShotAim then 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 - 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]); @@ -4462,6 +5052,10 @@ var NoTextureID: DWORD; NW, NH: Word; begin + NoTextureID := 0; + NW := 0; + NH := 0; + if SelectedObjectCount() <> 1 then Exit; if not SelectedObjects[GetFirstSelected()].Live then @@ -4484,12 +5078,12 @@ 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 @@ -4525,8 +5119,8 @@ 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 @@ -4535,7 +5129,7 @@ begin end; // Новая текстура: - TextureName := vleObjectProperty.Values[_lc[I_PROP_PANEL_TEX]]; + TextureName := vleObjectProperty.Values[MsgPropPanelTex]; if TextureName <> '' then begin // Есть текстура @@ -4550,14 +5144,14 @@ 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 - ErrorMessageBox(Format(_lc[I_MSG_WRONG_TEXHEIGHT], + ErrorMessageBox(Format(MsgMsgWrongTexheight, [TextureHeight])); Res := False; end; @@ -4617,10 +5211,10 @@ 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; @@ -4628,9 +5222,9 @@ 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; @@ -4638,9 +5232,9 @@ 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; @@ -4648,283 +5242,298 @@ 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 - s := vleObjectProperty.Values[_lc[I_PROP_TR_NEXT_MAP]]; + s := utf2win(vleObjectProperty.Values[MsgPropTrNextMap]); FillByte(Data.MapName[0], 16, 0); if s <> '' then - Move(Data.MapName[0], s[1], Min(Length(s), 16)); + Move(s[1], Data.MapName[0], Min(Length(s), 16)); end; 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 - 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 - 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 - 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 - 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 - s := vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_NAME]]; + s := utf2win(vleObjectProperty.Values[MsgPropTrSoundName]); FillByte(Data.SoundName[0], 64, 0); if s <> '' then - Move(Data.SoundName[0], s[1], Min(Length(s), 64)); + 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 - 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; - 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; - 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; - 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; - 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; - 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; - 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; - 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.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; - 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 - s := vleObjectProperty.Values[_lc[I_PROP_TR_MUSIC_NAME]]; + s := utf2win(vleObjectProperty.Values[MsgPropTrMusicName]); FillByte(Data.MusicName[0], 64, 0); if s <> '' then - Move(Data.MusicName[0], s[1], Min(Length(s), 64)); + 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 := 2; + Data.MusicAction := 0; 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( - 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; - 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 - 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 - 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( - StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_COUNT]], 0), 0), 255); + StrToIntDef(vleObjectProperty.Values[MsgPropTrCount], 0), 0), 255); 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 - 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 - 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.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; - 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; - 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 - 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 - 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 - 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 - 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; - s := vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TEXT]]; + s := utf2win(vleObjectProperty.Values[MsgPropTrMessageText]); FillByte(Data.MessageText[0], 100, 0); if s <> '' then - Move(Data.MessageText[0], s[1], Min(Length(s), 100)); + 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( - StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_DAMAGE_VALUE]], 0), 0), 65535); + StrToIntDef(vleObjectProperty.Values[MsgPropTrDamageValue], 0), 0), 65535); 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( - StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_HEALTH]], 0), 0), 65535); + StrToIntDef(vleObjectProperty.Values[MsgPropTrHealth], 0), 0), 65535); 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 - 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; - 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 - 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 - 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 - 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 - 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 - 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( - StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_SIGHT]], 0), 0), 65535); + StrToIntDef(vleObjectProperty.Values[MsgPropTrShotSight], 0), 0), 65535); 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 - 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 - 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( - StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_ANGLE]], 0), 360); + StrToIntDef(vleObjectProperty.Values[MsgPropTrShotAngle], 0), 360); 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( - StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_ACC]], 0), 0), 65535); + StrToIntDef(vleObjectProperty.Values[MsgPropTrShotAcc], 0), 0), 65535); 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( - 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( - 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; - 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 - 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 - 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 - 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 - 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 - 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 := StrToEffect(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]]); + Data.FXSubType := StrToEffect(vleObjectProperty.Values[MsgPropTrEffectSubtype]); 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; - 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( - StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EX_DELAY]], 0), 0), 65535); + StrToIntDef(vleObjectProperty.Values[MsgPropTrExDelay], 0), 0), 65535); 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( - StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_VELY]], 0), -128), 127); + StrToIntDef(vleObjectProperty.Values[MsgPropTrEffectVely], 0), -128), 127); 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( - StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SPR]], 0), 0), 255); + StrToIntDef(vleObjectProperty.Values[MsgPropTrEffectSpr], 0), 0), 255); 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( - StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SPD]], 0), 0), 255); + StrToIntDef(vleObjectProperty.Values[MsgPropTrEffectSpd], 0), 0), 255); end; end; end; @@ -4945,9 +5554,9 @@ begin if i = -1 then Exit; - if MessageBox(0, PChar(Format(_lc[I_MSG_DEL_TEXTURE_PROMT], + if Application.MessageBox(PChar(Format(MsgMsgDelTexturePrompt, [SelectedTexture()])), - PChar(_lc[I_MSG_DEL_TEXTURE]), + PChar(MsgMsgDelTexture), MB_ICONQUESTION or MB_YESNO or MB_DEFBUTTON1) <> idYes then Exit; @@ -4957,7 +5566,7 @@ begin if (gPanels[a].PanelType <> 0) and (gPanels[a].TextureName = SelectedTexture()) then begin - ErrorMessageBox(_lc[I_MSG_DEL_TEXTURE_CANT]); + ErrorMessageBox(MsgMsgDelTextureCant); Exit; end; @@ -4971,10 +5580,7 @@ end; 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; @@ -4994,7 +5600,7 @@ begin UNDO_DELETE_PANEL: begin AddPanel(Panel^); - Panel := nil; + Dispose(Panel); end; UNDO_DELETE_ITEM: AddItem(Item); UNDO_DELETE_AREA: AddArea(Area); @@ -5009,9 +5615,7 @@ begin end; SetLength(UndoBuffer, Length(UndoBuffer)-1); - RemoveSelectFromObjects(); - miUndo.Enabled := UndoBuffer <> nil; end; @@ -5121,7 +5725,7 @@ begin QuickSortCopyBuffer(0, b); end; -// Пестановка ссылок триггеров: +// Постановка ссылок триггеров: for a := 0 to Length(CopyBuffer)-1 do if CopyBuffer[a].ObjectType = OBJECT_TRIGGER then begin @@ -5222,19 +5826,38 @@ procedure TMainForm.aPasteObjectExecute(Sender: TObject); var a, h: Integer; CopyBuffer: TCopyRecArray; - res: Boolean; + res, rel: Boolean; swad, ssec, sres: String; + NoTextureID: DWORD; + pmin: TPoint; + xadj, yadj: LongInt; begin CopyBuffer := nil; + NoTextureID := 0; - StringToCopyBuffer(ClipBoard.AsText, CopyBuffer); + pmin.X := High(pmin.X); + pmin.Y := High(pmin.Y); + StringToCopyBuffer(ClipBoard.AsText, CopyBuffer, pmin); if CopyBuffer = nil then Exit; + rel := not(ssShift in GetKeyShiftState()); + h := High(CopyBuffer); 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 @@ -5242,8 +5865,11 @@ begin OBJECT_PANEL: if Panel <> nil then begin - Panel^.X := Panel^.X + 16; - Panel^.Y := Panel^.Y + 16; + if rel then + begin + Panel^.X += xadj; + Panel^.Y += yadj; + end; Panel^.TextureID := TEXTURE_SPECIAL_NONE; Panel^.TextureWidth := 1; @@ -5275,7 +5901,11 @@ begin g_GetTextureSizeByName(Panel^.TextureName, Panel^.TextureWidth, Panel^.TextureHeight) else - Panel^.TextureName := ''; + if g_GetTexture('NOTEXTURE', NoTextureID) then + begin + Panel^.TextureID := TEXTURE_SPECIAL_NOTEXTURE; + g_GetTextureSizeByID(NoTextureID, Panel^.TextureWidth, Panel^.TextureHeight); + end; end else // Спец.текстура: begin @@ -5294,8 +5924,11 @@ begin OBJECT_ITEM: begin - Item.X := Item.X + 16; - Item.Y := Item.Y + 16; + if rel then + begin + Item.X += xadj; + Item.Y += yadj; + end; ID := AddItem(Item); Undo_Add(OBJECT_ITEM, ID, a > 0); @@ -5304,8 +5937,11 @@ begin OBJECT_MONSTER: begin - Monster.X := Monster.X + 16; - Monster.Y := Monster.Y + 16; + if rel then + begin + Monster.X += xadj; + Monster.Y += yadj; + end; ID := AddMonster(Monster); Undo_Add(OBJECT_MONSTER, ID, a > 0); @@ -5314,8 +5950,11 @@ begin OBJECT_AREA: begin - Area.X := Area.X + 16; - Area.Y := Area.Y + 16; + if rel then + begin + Area.X += xadj; + Area.Y += yadj; + end; ID := AddArea(Area); Undo_Add(OBJECT_AREA, ID, a > 0); @@ -5324,8 +5963,40 @@ begin OBJECT_TRIGGER: begin - Trigger.X := Trigger.X + 16; - Trigger.Y := Trigger.Y + 16; + if rel then + with Trigger do + begin + X += xadj; + Y += yadj; + + case TriggerType of + TRIGGER_TELEPORT: + begin + Data.TargetPoint.X += xadj; + Data.TargetPoint.Y += yadj; + end; + TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF: + begin + Data.tX += xadj; + Data.tY += yadj; + end; + TRIGGER_SPAWNMONSTER: + begin + Data.MonPos.X += xadj; + Data.MonPos.Y += yadj; + end; + TRIGGER_SPAWNITEM: + begin + Data.ItemPos.X += xadj; + Data.ItemPos.Y += yadj; + end; + TRIGGER_SHOT: + begin + Data.ShotPos.X += xadj; + Data.ShotPos.Y += yadj; + end; + end; + end; ID := AddTrigger(Trigger); Undo_Add(OBJECT_TRIGGER, ID, a > 0); @@ -5382,11 +6053,11 @@ var begin Key := vleObjectProperty.Keys[vleObjectProperty.Row]; - if Key = _lc[I_PROP_PANEL_TYPE] then + if Key = MsgPropPanelType then begin with ChooseTypeForm, vleObjectProperty do begin // Выбор типа панели: - Caption := _lc[I_PROP_PANEL_TYPE]; + Caption := MsgPropPanelType; lbTypeSelect.Items.Clear(); for b := 0 to High(PANELNAMES) do @@ -5400,46 +6071,47 @@ begin begin b := lbTypeSelect.ItemIndex; Values[Key] := PANELNAMES[b]; - bApplyProperty.Click(); + vleObjectPropertyApply(Sender); end; end end - else if Key = _lc[I_PROP_TR_TELEPORT_TO] then + else if Key = MsgPropTrTeleportTo then SelectFlag := SELECTFLAG_TELEPORT - else if Key = _lc[I_PROP_TR_SPAWN_TO] then + else if Key = MsgPropTrSpawnTo then 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 - else if Key = _lc[I_PROP_TR_TEXTURE_PANEL] then + else if Key = MsgPropTrTexturePanel then 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 - else if Key = _lc[I_PROP_TR_LIFT_PANEL] then + else if Key = MsgPropTrLiftPanel then SelectFlag := SELECTFLAG_LIFT - else if key = _lc[I_PROP_TR_EX_MONSTER] then + else if key = MsgPropTrExMonster then 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 - else if Key = _lc[I_PROP_TR_NEXT_MAP] then + else if Key = MsgPropTrNextMap then begin // Выбор следующей карты: g_ProcessResourceStr(OpenedMap, @FileName, nil, nil); + SelectMapForm.Caption := MsgCapSelect; SelectMapForm.GetMaps(FileName); if SelectMapForm.ShowModal() = mrOK then begin vleObjectProperty.Values[Key] := SelectMapForm.lbMapList.Items[SelectMapForm.lbMapList.ItemIndex]; - bApplyProperty.Click(); + 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; @@ -5448,10 +6120,10 @@ begin if (AddSoundForm.ShowModal() = mrOk) then begin vleObjectProperty.Values[Key] := AddSoundForm.ResourceName; - bApplyProperty.Click(); + 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; @@ -5478,10 +6150,10 @@ begin b := b or ACTIVATE_NOMONSTER; Values[Key] := ActivateToStr(b); - bApplyProperty.Click(); + 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; @@ -5505,13 +6177,13 @@ begin b := b or KEY_BLUETEAM; Values[Key] := KeyToStr(b); - bApplyProperty.Click(); + vleObjectPropertyApply(Sender); end; end - else if Key = _lc[I_PROP_TR_FX_TYPE] then + else if Key = MsgPropTrFxType then with ChooseTypeForm, vleObjectProperty do begin // Выбор типа эффекта: - Caption := _lc[I_CAP_FX_TYPE]; + Caption := MsgCapFxType; lbTypeSelect.Items.Clear(); for b := EFFECT_NONE to EFFECT_FIRE do @@ -5523,13 +6195,13 @@ begin begin b := lbTypeSelect.ItemIndex; Values[Key] := EffectToStr(b); - bApplyProperty.Click(); + vleObjectPropertyApply(Sender); end; end - else if Key = _lc[I_PROP_TR_MONSTER_TYPE] then + else if Key = MsgPropTrMonsterType then with ChooseTypeForm, vleObjectProperty do begin // Выбор типа монстра: - Caption := _lc[I_CAP_MONSTER_TYPE]; + Caption := MsgCapMonsterType; lbTypeSelect.Items.Clear(); for b := MONSTER_DEMON to MONSTER_MAN do @@ -5541,13 +6213,13 @@ begin begin b := lbTypeSelect.ItemIndex + MONSTER_DEMON; Values[Key] := MonsterToStr(b); - bApplyProperty.Click(); + vleObjectPropertyApply(Sender); end; end - else if Key = _lc[I_PROP_TR_ITEM_TYPE] then + else if Key = MsgPropTrItemType then 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 @@ -5567,16 +6239,16 @@ begin 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); - bApplyProperty.Click(); + vleObjectPropertyApply(Sender); end; end - else if Key = _lc[I_PROP_TR_SHOT_TYPE] then + else if Key = MsgPropTrShotType then 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 @@ -5588,18 +6260,18 @@ begin begin b := lbTypeSelect.ItemIndex; Values[Key] := ShotToStr(b); - bApplyProperty.Click(); + vleObjectPropertyApply(Sender); end; end - else if Key = _lc[I_PROP_TR_EFFECT_TYPE] then + else if Key = MsgPropTrEffectType then with ChooseTypeForm, vleObjectProperty do begin // Выбор типа эффекта: - Caption := _lc[I_CAP_FX_TYPE]; + Caption := MsgCapFxType; 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; @@ -5608,19 +6280,19 @@ begin begin b := lbTypeSelect.ItemIndex; if b = 0 then - Values[Key] := _lc[I_PROP_TR_EFFECT_PARTICLE] + Values[Key] := MsgPropTrEffectParticle else - Values[Key] := _lc[I_PROP_TR_EFFECT_ANIMATION]; - bApplyProperty.Click(); + Values[Key] := MsgPropTrEffectAnimation; + vleObjectPropertyApply(Sender); end; end - else if Key = _lc[I_PROP_TR_EFFECT_SUBTYPE] then + else if Key = MsgPropTrEffectSubtype then with ChooseTypeForm, vleObjectProperty do begin // Выбор подтипа эффекта: - Caption := _lc[I_CAP_FX_TYPE]; + Caption := MsgCapFxType; 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)); @@ -5628,22 +6300,22 @@ 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; - if Values[Key] = _lc[I_PROP_TR_EFFECT_LLIQUID] then + if Values[Key] = MsgPropTrEffectLliquid then 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; - if Values[Key] = _lc[I_PROP_TR_EFFECT_BLOOD] then + if Values[Key] = MsgPropTrEffectBlood then 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; - if Values[Key] = _lc[I_PROP_TR_EFFECT_BUBBLE] then + if Values[Key] = MsgPropTrEffectBubble then lbTypeSelect.ItemIndex := TRIGGER_EFFECT_BUBBLE; end; @@ -5651,42 +6323,50 @@ begin 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] := _lc[I_PROP_TR_EFFECT_SLIQUID]; + Values[Key] := MsgPropTrEffectSliquid; if b = TRIGGER_EFFECT_LLIQUID then - Values[Key] := _lc[I_PROP_TR_EFFECT_LLIQUID]; + Values[Key] := MsgPropTrEffectLliquid; if b = TRIGGER_EFFECT_DLIQUID then - Values[Key] := _lc[I_PROP_TR_EFFECT_DLIQUID]; + Values[Key] := MsgPropTrEffectDliquid; if b = TRIGGER_EFFECT_BLOOD then - Values[Key] := _lc[I_PROP_TR_EFFECT_BLOOD]; + Values[Key] := MsgPropTrEffectBlood; if b = TRIGGER_EFFECT_SPARK then - Values[Key] := _lc[I_PROP_TR_EFFECT_SPARK]; + Values[Key] := MsgPropTrEffectSpark; if b = TRIGGER_EFFECT_BUBBLE then - Values[Key] := _lc[I_PROP_TR_EFFECT_BUBBLE]; + Values[Key] := MsgPropTrEffectBubble; end; - bApplyProperty.Click(); + 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); if ColorDialog.Execute then begin Values[Key] := IntToStr(ColorDialog.Color); - bApplyProperty.Click(); + vleObjectPropertyApply(Sender); end; end - else if Key = _lc[I_PROP_PANEL_TEX] then + else if Key = MsgPropPanelTex then begin // Смена текстуры: vleObjectProperty.Values[Key] := SelectedTexture(); - bApplyProperty.Click(); + vleObjectPropertyApply(Sender); end; end; +procedure TMainForm.vleObjectPropertyApply(Sender: TObject); +begin + // hack to prevent empty ID in list + RenderPanel.SetFocus(); + bApplyProperty.Click(); + vleObjectProperty.SetFocus(); +end; + procedure TMainForm.aSaveMapExecute(Sender: TObject); var FileName, Section, Res: String; @@ -5699,67 +6379,49 @@ begin g_ProcessResourceStr(OpenedMap, FileName, Section, Res); - SaveMap(FileName+':\'+Res); + SaveMap(FileName+':\'+Res, ''); end; procedure TMainForm.aOpenMapExecute(Sender: TObject); begin - OpenDialog.Filter := _lc[I_FILE_FILTER_ALL]; + OpenDialog.Filter := MsgFileFilterAll; if OpenDialog.Execute() then begin - if (Pos('.ini', LowerCase(ExtractFileName(OpenDialog.FileName))) > 0) then - begin // INI карты: - FullClear(); + OpenMapFile(OpenDialog.FileName); + OpenDialog.InitialDir := ExtractFileDir(OpenDialog.FileName); + end; +end; - pLoadProgress.Left := (RenderPanel.Width div 2)-(pLoadProgress.Width div 2); - pLoadProgress.Top := (RenderPanel.Height div 2)-(pLoadProgress.Height div 2); - pLoadProgress.Show(); +procedure TMainForm.OpenMapFile(FileName: String); +begin + if (Pos('.ini', LowerCase(ExtractFileName(FileName))) > 0) then + begin // INI карты: + FullClear(); - OpenedMap := ''; - OpenedWAD := ''; + pLoadProgress.Left := (RenderPanel.Width div 2)-(pLoadProgress.Width div 2); + pLoadProgress.Top := (RenderPanel.Height div 2)-(pLoadProgress.Height div 2); + pLoadProgress.Show(); - LoadMapOld(OpenDialog.FileName); + OpenedMap := ''; + OpenedWAD := ''; - MainForm.Caption := Format('%s - %s', [FormCaption, ExtractFileName(OpenDialog.FileName)]); + LoadMapOld(FileName); - pLoadProgress.Hide(); - MainForm.FormResize(Self); - end - else // Карты из WAD: - begin - OpenMap(OpenDialog.FileName, ''); - end; + MainForm.Caption := Format('%s - %s', [FormCaption, ExtractFileName(FileName)]); - OpenDialog.InitialDir := ExtractFileDir(OpenDialog.FileName); - end; + pLoadProgress.Hide(); + MainForm.FormResize(Self); + end + else // Карты из WAD: + begin + OpenMap(FileName, ''); + end; end; procedure TMainForm.FormActivate(Sender: TObject); -var - lang: Integer; - config: TConfig; 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); @@ -5770,7 +6432,7 @@ var a: Integer; str: String; begin - OpenDialog.Filter := _lc[I_FILE_FILTER_WAD]; + OpenDialog.Filter := MsgFileFilterWad; if not OpenDialog.Execute() then Exit; @@ -5787,32 +6449,29 @@ begin MapList := WAD.GetResourcesList(''); + SelectMapForm.Caption := MsgCapRemove; SelectMapForm.lbMapList.Items.Clear(); if MapList <> nil then for a := 0 to High(MapList) do - SelectMapForm.lbMapList.Items.Add(MapList[a]); + SelectMapForm.lbMapList.Items.Add(win2utf(MapList[a])); if (SelectMapForm.ShowModal() = mrOK) then begin str := SelectMapForm.lbMapList.Items[SelectMapForm.lbMapList.ItemIndex]; MapName := ''; - Move(MapName[0], str[1], Min(16, Length(str))); + 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('', 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); + WAD.RemoveResource('', utf2win(MapName)); + + Application.MessageBox( + PChar(Format(MsgMsgMapDeletedPrompt, [MapName])), + PChar(MsgMsgMapDeleted), + MB_ICONINFORMATION or MB_OK or MB_DEFBUTTON1 + ); WAD.SaveTo(OpenDialog.FileName); @@ -5832,7 +6491,7 @@ procedure TMainForm.vleObjectPropertyKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin if Key = VK_RETURN then - bApplyProperty.Click(); + vleObjectPropertyApply(Sender); end; procedure MovePanel(var ID: DWORD; MoveType: Byte); @@ -5976,35 +6635,59 @@ begin end; procedure TMainForm.aSaveMapAsExecute(Sender: TObject); -var - idx: Integer; + var i, idx: Integer; list: TStringList; fmt: String; 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); @@ -6040,6 +6723,8 @@ begin if gTriggers[a].TriggerType <> TRIGGER_NONE then SelectObject(OBJECT_TRIGGER, a, True); end; + + RecountSelectedObjects(); end; procedure TMainForm.tbGridOnClick(Sender: TObject); @@ -6049,24 +6734,29 @@ begin end; procedure TMainForm.OnIdle(Sender: TObject; var Done: Boolean); + const MaxFPS = 60; + var f: AnsiString; 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 - e_WriteLog('Init OpenGL', MSG_NOTIFY); - e_InitGL(); - e_WriteLog('Loading data', MSG_NOTIFY); - LoadStdFont('STDTXT', 'STDFONT', gEditorFont); - LoadData(); - gDataLoaded := True; - MainForm.FormResize(nil); + PanelMap.Refresh; + end; + + if StartMap <> '' then + begin + f := StartMap; + StartMap := ''; + OpenMap(f, ''); end; - Draw(); end; procedure TMainForm.miMapPreviewClick(Sender: TObject); begin - if not PreviewMode then + if PreviewMode = 2 then + Exit; + + if PreviewMode = 0 then begin Splitter2.Visible := False; Splitter1.Visible := False; @@ -6089,8 +6779,10 @@ begin sbVertical.Visible := True; end; - PreviewMode := not PreviewMode; - (Sender as TMenuItem).Checked := PreviewMode; + PreviewMode := PreviewMode xor 1; + (Sender as TMenuItem).Checked := PreviewMode > 0; + + FormResize(Self); end; procedure TMainForm.miLayer1Click(Sender: TObject); @@ -6216,28 +6908,73 @@ begin 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 - 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 - cmd, mapWAD, mapToRun: String; + newWAD, oldWAD, tempMap, ext: String; + args: SSArray; opt: LongWord; - time: Integer; - lpMsgBuf: PChar; + time, i: Integer; + proc: TProcessUTF8; + res: Boolean; begin + // Ignore while map testing in progress + if MapTestProcess <> nil then + Exit; + // Сохраняем временную карту: time := 0; repeat - mapWAD := ExtractFilePath(TestD2dExe) + Format('maps\temp%.4d.wad', [time]); + newWAD := Format('%s/temp%.4d', [MapsDir, time]); Inc(time); - until not FileExists(mapWAD); - mapToRun := mapWAD + ':\' + TEST_MAP_NAME; - SaveMap(mapToRun); - - mapToRun := ExtractRelativePath(ExtractFilePath(TestD2dExe) + 'maps\', mapToRun); + 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; @@ -6252,42 +6989,64 @@ begin if TestOptionsMonstersDM then opt := opt + 16; -// Составляем командную строку: - cmd := ' -map "' + mapToRun + '"'; - cmd := cmd + ' -gm ' + TestGameMode; - cmd := cmd + ' -limt ' + TestLimTime; - cmd := cmd + ' -lims ' + TestLimScore; - cmd := cmd + ' -opt ' + IntToStr(opt); - +// Запускаем: + proc := TProcessUTF8.Create(nil); + proc.Executable := TestD2dExe; + {$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 - cmd := cmd + ' --close'; + proc.Parameters.Add('--close'); - cmd := cmd + ' --debug'; - cmd := cmd + ' --tempdelete'; + args := ParseString(TestD2DArgs); + for i := 0 to High(args) do + proc.Parameters.Add(args[i]); -// Запускаем: - Application.Minimize(); - if ExecuteProcess(TestD2dExe, cmd) < 0 then + res := True; + try + proc.Execute(); + except + res := False; + end; + if res then + begin + tbTestMap.Enabled := False; + MapTestFile := newWAD; + MapTestProcess := proc; + end + else 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; - - SysUtils.DeleteFile(mapWAD); - Application.Restore(); 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 - MapOffset.X := -Normalize16(sbHorizontal.Position); + MapOffset.X := -sbHorizontal.Position; + RenderPanel.Invalidate; end; procedure TMainForm.miOpenWadMapClick(Sender: TObject); @@ -6328,6 +7087,8 @@ begin 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; @@ -6352,8 +7113,7 @@ begin 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 @@ -6365,28 +7125,13 @@ begin (Key = Ord('V')) then FillProperty(); end; -end; - -{ -procedure TMainForm.lbTextureListDrawItem(Control: TWinControl; Index: Integer; - Rect: TRect; State: LCLType.TOwnerDrawState); -begin - with Control as TListBox do +// Быстрое превью карты: + if Key = Ord('E') then begin - if LCLType.odSelected in State then - begin - Canvas.Brush.Color := clHighlight; - Canvas.Font.Color := clHighlightText; - end else - if (Items <> nil) and (Index >= 0) then - if slInvalidTextures.IndexOf(Items[Index]) > -1 then - begin - Canvas.Brush.Color := clRed; - Canvas.Font.Color := clWhite; - end; - Canvas.FillRect(Rect); - Canvas.TextRect(Rect, Rect.Left, Rect.Top, Items[Index]); + if PreviewMode = 2 then + PreviewMode := 0; end; + RenderPanelMouseMove(Sender, Shift, RenderMousePos().X, RenderMousePos().Y); end; -} + end.