DEADSOFTWARE

790a646a334b9ff69700d3237260483e6baf427b
[d2df-editor.git] / src / editor / f_main.pas
1 unit f_main;
3 {$INCLUDE ../shared/a_modes.inc}
5 interface
7 uses
8 LCLIntf, LCLType, SysUtils, Variants, Classes, Graphics,
9 Controls, Forms, Dialogs, StdCtrls, Buttons,
10 ComCtrls, ValEdit, Types, Menus, ExtCtrls,
11 CheckLst, Grids, OpenGLContext, Utils, UTF8Process;
13 type
15 { TMainForm }
17 TMainForm = class(TForm)
18 lLoad: TLabel;
19 // Главное меню:
20 MainMenu: TMainMenu;
21 // Apple menu:
22 miApple: TMenuItem;
23 miAppleAbout: TMenuItem;
24 miAppleLine0: TMenuItem;
25 miApplePref: TMenuItem;
26 miAppleLine1: TMenuItem;
27 // "Файл":
28 miMenuFile: TMenuItem;
29 miNewMap: TMenuItem;
30 miOpenMap: TMenuItem;
31 miSaveMap: TMenuItem;
32 miSaveMapAs: TMenuItem;
33 miMacRecentSubMenu: TMenuItem;
34 miMacRecentClear: TMenuItem;
35 miOpenWadMap: TMenuItem;
36 miLine1: TMenuItem;
37 miReopenMap: TMenuItem;
38 miSaveMiniMap: TMenuItem;
39 miDeleteMap: TMenuItem;
40 miPackMap: TMenuItem;
41 miWinRecent: TMenuItem;
42 miLine2: TMenuItem;
43 miExit: TMenuItem;
44 // "Правка":
45 miMenuEdit: TMenuItem;
46 miUndo: TMenuItem;
47 miLine3: TMenuItem;
48 miCopy: TMenuItem;
49 miCut: TMenuItem;
50 miPaste: TMenuItem;
51 miLine4: TMenuItem;
52 miSelectAll: TMenuItem;
53 miLine5: TMenuItem;
54 miToFore: TMenuItem;
55 miToBack: TMenuItem;
56 // View menu:
57 miMenuView: TMenuItem;
58 miShowEdges: TMenuItem;
59 miLayers: TMenuItem;
60 miLayer1: TMenuItem;
61 miLayer2: TMenuItem;
62 miLayer3: TMenuItem;
63 miLayer4: TMenuItem;
64 miLayer5: TMenuItem;
65 miLayer6: TMenuItem;
66 miLayer7: TMenuItem;
67 miLayer8: TMenuItem;
68 miLayer9: TMenuItem;
69 miViewLine1: TMenuItem;
70 miMiniMap: TMenuItem;
71 miViewLine2: TMenuItem;
72 miMapPreview: TMenuItem;
73 miSnapToGrid: TMenuItem;
74 miSwitchGrid: TMenuItem;
75 miLine6: TMenuItem;
76 miOptions: TMenuItem;
77 miMapOptions: TMenuItem;
78 // "Сервис":
79 miMenuService: TMenuItem;
80 miCheckMap: TMenuItem;
81 miOptimmization: TMenuItem;
82 miTestMap: TMenuItem;
83 // Window menu:
84 miMenuWindow: TMenuItem;
85 miMacMinimize: TMenuItem;
86 miMacZoom: TMenuItem;
87 // "Справка":
88 miMenuHelp: TMenuItem;
89 miAbout: TMenuItem;
90 // Скрытый пункт меню для Ctrl+Tab:
91 miMenuHidden: TMenuItem;
92 minexttab: TMenuItem;
94 // Панель инструментов:
95 MainToolBar: TToolBar;
96 pbLoad: TProgressBar;
97 pLoadProgress: TPanel;
98 RenderPanel: TOpenGLControl;
99 Separator1: TMenuItem;
100 miMacRecentEnd: TMenuItem;
101 miWinRecentStart: TMenuItem;
102 Separator2: TMenuItem;
103 tbNewMap: TToolButton;
104 tbOpenMap: TToolButton;
105 tbSaveMap: TToolButton;
106 tbOpenWadMap: TToolButton;
107 tbLine1: TToolButton;
108 tbShowMap: TToolButton;
109 tbLine2: TToolButton;
110 tbShow: TToolButton;
111 tbLine3: TToolButton;
112 tbGridOn: TToolButton;
113 tbGrid: TToolButton;
114 tbLine4: TToolButton;
115 tbTestMap: TToolButton;
116 // Всплывающее меню для кнопки слоев:
117 pmShow: TPopupMenu;
118 miLayerP1: TMenuItem;
119 miLayerP2: TMenuItem;
120 miLayerP3: TMenuItem;
121 miLayerP4: TMenuItem;
122 miLayerP5: TMenuItem;
123 miLayerP6: TMenuItem;
124 miLayerP7: TMenuItem;
125 miLayerP8: TMenuItem;
126 miLayerP9: TMenuItem;
128 // Панель карты:
129 PanelMap: TPanel;
130 // Полосы прокрутки:
131 sbHorizontal: TScrollBar;
132 sbVertical: TScrollBar;
134 // Панель свойств:
135 PanelProps: TPanel;
136 // Панель применения свойств:
137 PanelPropApply: TPanel;
138 bApplyProperty: TButton;
139 MapTestTimer: TTimer;
140 // Редактор свойств объектов:
141 vleObjectProperty: TValueListEditor;
143 // Панель объектов - вкладки:
144 PanelObjs: TPanel;
145 pcObjects: TPageControl;
146 // Вкладка "Панели":
147 tsPanels: TTabSheet;
148 lbTextureList: TListBox;
149 // Панель настройки текстур:
150 PanelTextures: TPanel;
151 LabelTxW: TLabel;
152 lTextureWidth: TLabel;
153 LabelTxH: TLabel;
154 lTextureHeight: TLabel;
155 cbPreview: TCheckBox;
156 bbAddTexture: TBitBtn;
157 bbRemoveTexture: TBitBtn;
158 bClearTexture: TButton;
159 // Панель типов панелей:
160 PanelPanelType: TPanel;
161 lbPanelType: TListBox;
162 // Вкладка "Предметы":
163 tsItems: TTabSheet;
164 lbItemList: TListBox;
165 cbOnlyDM: TCheckBox;
166 cbFall: TCheckBox;
167 // Вкладка "Монстры":
168 tsMonsters: TTabSheet;
169 lbMonsterList: TListBox;
170 rbMonsterLeft: TRadioButton;
171 rbMonsterRight: TRadioButton;
172 // Вкладка "Области":
173 tsAreas: TTabSheet;
174 lbAreasList: TListBox;
175 rbAreaLeft: TRadioButton;
176 rbAreaRight: TRadioButton;
177 // Вкладка "Триггеры":
178 tsTriggers: TTabSheet;
179 lbTriggersList: TListBox;
180 clbActivationType: TCheckListBox;
181 clbKeys: TCheckListBox;
183 // Остальные панели
184 Splitter1: TSplitter;
185 Splitter2: TSplitter;
186 StatusBar: TStatusBar;
188 // Специальные объекты:
189 ImageList: TImageList;
190 ilToolbar: TImageList;
191 OpenDialog: TOpenDialog;
192 SaveDialog: TSaveDialog;
193 selectall1: TMenuItem;
194 ColorDialog: TColorDialog;
196 procedure aAboutExecute(Sender: TObject);
197 procedure aCheckMapExecute(Sender: TObject);
198 procedure aMoveToFore(Sender: TObject);
199 procedure aMoveToBack(Sender: TObject);
200 procedure aCopyObjectExecute(Sender: TObject);
201 procedure aCutObjectExecute(Sender: TObject);
202 procedure aEditorOptionsExecute(Sender: TObject);
203 procedure aExitExecute(Sender: TObject);
204 procedure aMapOptionsExecute(Sender: TObject);
205 procedure aNewMapExecute(Sender: TObject);
206 procedure aOpenMapExecute(Sender: TObject);
207 procedure aOptimizeExecute(Sender: TObject);
208 procedure aPasteObjectExecute(Sender: TObject);
209 procedure aSelectAllExecute(Sender: TObject);
210 procedure aSaveMapExecute(Sender: TObject);
211 procedure aSaveMapAsExecute(Sender: TObject);
212 procedure aUndoExecute(Sender: TObject);
213 procedure aDeleteMap(Sender: TObject);
214 procedure bApplyPropertyClick(Sender: TObject);
215 procedure bbAddTextureClick(Sender: TObject);
216 procedure bbRemoveTextureClick(Sender: TObject);
217 procedure FormActivate(Sender: TObject);
218 procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
219 procedure FormCreate(Sender: TObject);
220 procedure FormDestroy(Sender: TObject);
221 procedure FormDropFiles(Sender: TObject; const FileNames: array of String);
222 procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
223 procedure FormResize(Sender: TObject);
224 procedure FormWindowStateChange(Sender: TObject);
225 procedure miMacRecentClearClick(Sender: TObject);
226 procedure miMacZoomClick(Sender: TObject);
227 procedure lbTextureListClick(Sender: TObject);
228 procedure lbTextureListDrawItem(Control: TWinControl; Index: Integer;
229 ARect: TRect; State: TOwnerDrawState);
230 procedure miMacMinimizeClick(Sender: TObject);
231 procedure miReopenMapClick(Sender: TObject);
232 procedure RenderPanelMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
233 procedure RenderPanelMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
234 procedure RenderPanelMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
235 procedure RenderPanelPaint(Sender: TObject);
236 procedure RenderPanelResize(Sender: TObject);
237 procedure Splitter1Moved(Sender: TObject);
238 procedure MapTestCheck(Sender: TObject);
239 procedure vleObjectPropertyEditButtonClick(Sender: TObject);
240 procedure vleObjectPropertyApply(Sender: TObject);
241 procedure vleObjectPropertyGetPickList(Sender: TObject; const KeyName: String; Values: TStrings);
242 procedure vleObjectPropertyKeyDown(Sender: TObject; var Key: Word;
243 Shift: TShiftState);
244 procedure tbGridOnClick(Sender: TObject);
245 procedure miMapPreviewClick(Sender: TObject);
246 procedure miLayer1Click(Sender: TObject);
247 procedure miLayer2Click(Sender: TObject);
248 procedure miLayer3Click(Sender: TObject);
249 procedure miLayer4Click(Sender: TObject);
250 procedure miLayer5Click(Sender: TObject);
251 procedure miLayer6Click(Sender: TObject);
252 procedure miLayer7Click(Sender: TObject);
253 procedure miLayer8Click(Sender: TObject);
254 procedure miLayer9Click(Sender: TObject);
255 procedure tbShowClick(Sender: TObject);
256 procedure miSnapToGridClick(Sender: TObject);
257 procedure miMiniMapClick(Sender: TObject);
258 procedure miSwitchGridClick(Sender: TObject);
259 procedure miShowEdgesClick(Sender: TObject);
260 procedure minexttabClick(Sender: TObject);
261 procedure miSaveMiniMapClick(Sender: TObject);
262 procedure bClearTextureClick(Sender: TObject);
263 procedure miPackMapClick(Sender: TObject);
264 procedure miTestMapClick(Sender: TObject);
265 procedure sbVerticalScroll(Sender: TObject; ScrollCode: TScrollCode;
266 var ScrollPos: Integer);
267 procedure sbHorizontalScroll(Sender: TObject; ScrollCode: TScrollCode;
268 var ScrollPos: Integer);
269 procedure miOpenWadMapClick(Sender: TObject);
270 procedure selectall1Click(Sender: TObject);
271 procedure Splitter1CanResize(Sender: TObject; var NewSize: Integer;
272 var Accept: Boolean);
273 procedure Splitter2CanResize(Sender: TObject; var NewSize: Integer;
274 var Accept: Boolean);
275 procedure vleObjectPropertyEnter(Sender: TObject);
276 procedure vleObjectPropertyExit(Sender: TObject);
277 procedure FormKeyUp(Sender: TObject; var Key: Word;
278 Shift: TShiftState);
279 private
280 procedure Draw();
281 procedure OnIdle(Sender: TObject; var Done: Boolean);
282 procedure RefillRecentMenu (menu: TMenuItem; start: Integer; fmt: AnsiString);
283 public
284 procedure RefreshRecentMenu();
285 procedure OpenMapFile(FileName: String);
286 function RenderMousePos(): TPoint;
287 procedure RecountSelectedObjects();
288 end;
290 const
291 LAYER_BACK = 0;
292 LAYER_WALLS = 1;
293 LAYER_FOREGROUND = 2;
294 LAYER_STEPS = 3;
295 LAYER_WATER = 4;
296 LAYER_ITEMS = 5;
297 LAYER_MONSTERS = 6;
298 LAYER_AREAS = 7;
299 LAYER_TRIGGERS = 8;
301 TEST_MAP_NAME = '$$$_TEST_$$$';
302 LANGUAGE_FILE_NAME = '_Editor.txt';
304 var
305 MainForm: TMainForm;
306 StartMap: String;
307 OpenedMap: String;
308 OpenedWAD: String;
310 DotColor: TColor;
311 DotEnable: Boolean;
312 DotStep: Word;
313 DotStepOne, DotStepTwo: Word;
314 DotSize: Byte;
315 DrawTexturePanel: Boolean;
316 DrawPanelSize: Boolean;
317 BackColor: TColor;
318 PreviewColor: TColor;
319 UseCheckerboard: Boolean;
320 Scale: Byte;
321 RecentCount: Integer;
322 RecentFiles: TStringList;
323 slInvalidTextures: TStringList;
325 TestGameMode: String;
326 TestLimTime: String;
327 TestLimScore: String;
328 TestOptionsTwoPlayers: Boolean;
329 TestOptionsTeamDamage: Boolean;
330 TestOptionsAllowExit: Boolean;
331 TestOptionsWeaponStay: Boolean;
332 TestOptionsMonstersDM: Boolean;
333 TestD2dExe, TestD2DArgs: String;
334 TestMapOnce: Boolean;
336 LayerEnabled: Array [LAYER_BACK..LAYER_TRIGGERS] of Boolean =
337 (True, True, True, True, True, True, True, True, True);
338 ContourEnabled: Array [LAYER_BACK..LAYER_TRIGGERS] of Boolean =
339 (False, False, False, False, False, False, False, False, False);
340 PreviewMode: Byte = 0;
341 gLanguage: String;
343 FormCaption: String;
346 procedure OpenMap(FileName: String; mapN: String);
347 function AddTexture(aWAD, aSection, aTex: String; silent: Boolean): Boolean;
348 procedure RemoveSelectFromObjects();
349 procedure ChangeShownProperty(Name: String; NewValue: String);
351 implementation
353 uses
354 f_options, e_graphics, e_log, GL, Math,
355 f_mapoptions, g_basic, f_about, f_mapoptimization,
356 f_mapcheck, f_addresource_texture, g_textures,
357 f_activationtype, f_keys, wadreader, fileutil,
358 MAPREADER, f_selectmap, f_savemap, WADEDITOR, MAPDEF,
359 g_map, f_saveminimap, f_addresource, CONFIG, f_packmap,
360 f_addresource_sound, f_choosetype,
361 g_language, f_selectlang, ClipBrd, g_resources, g_options;
363 const
364 UNDO_DELETE_PANEL = 1;
365 UNDO_DELETE_ITEM = 2;
366 UNDO_DELETE_AREA = 3;
367 UNDO_DELETE_MONSTER = 4;
368 UNDO_DELETE_TRIGGER = 5;
369 UNDO_ADD_PANEL = 6;
370 UNDO_ADD_ITEM = 7;
371 UNDO_ADD_AREA = 8;
372 UNDO_ADD_MONSTER = 9;
373 UNDO_ADD_TRIGGER = 10;
374 UNDO_MOVE_PANEL = 11;
375 UNDO_MOVE_ITEM = 12;
376 UNDO_MOVE_AREA = 13;
377 UNDO_MOVE_MONSTER = 14;
378 UNDO_MOVE_TRIGGER = 15;
379 UNDO_RESIZE_PANEL = 16;
380 UNDO_RESIZE_TRIGGER = 17;
382 MOUSEACTION_NONE = 0;
383 MOUSEACTION_DRAWPANEL = 1;
384 MOUSEACTION_DRAWTRIGGER = 2;
385 MOUSEACTION_MOVEOBJ = 3;
386 MOUSEACTION_RESIZE = 4;
387 MOUSEACTION_MOVEMAP = 5;
388 MOUSEACTION_DRAWPRESS = 6;
389 MOUSEACTION_NOACTION = 7;
391 RESIZETYPE_NONE = 0;
392 RESIZETYPE_VERTICAL = 1;
393 RESIZETYPE_HORIZONTAL = 2;
395 RESIZEDIR_NONE = 0;
396 RESIZEDIR_DOWN = 1;
397 RESIZEDIR_UP = 2;
398 RESIZEDIR_RIGHT = 3;
399 RESIZEDIR_LEFT = 4;
401 SELECTFLAG_NONE = 0;
402 SELECTFLAG_TELEPORT = 1;
403 SELECTFLAG_DOOR = 2;
404 SELECTFLAG_TEXTURE = 3;
405 SELECTFLAG_LIFT = 4;
406 SELECTFLAG_MONSTER = 5;
407 SELECTFLAG_SPAWNPOINT = 6;
408 SELECTFLAG_SHOTPANEL = 7;
409 SELECTFLAG_SELECTED = 8;
411 RECENT_FILES_MENU_START = 12;
413 CLIPBOARD_SIG = 'DF:ED';
415 type
416 TUndoRec = record
417 UndoType: Byte;
418 case Byte of
419 UNDO_DELETE_PANEL: (Panel: ^TPanel);
420 UNDO_DELETE_ITEM: (Item: TItem);
421 UNDO_DELETE_AREA: (Area: TArea);
422 UNDO_DELETE_MONSTER: (Monster: TMonster);
423 UNDO_DELETE_TRIGGER: (Trigger: TTrigger);
424 UNDO_ADD_PANEL,
425 UNDO_ADD_ITEM,
426 UNDO_ADD_AREA,
427 UNDO_ADD_MONSTER,
428 UNDO_ADD_TRIGGER: (AddID: DWORD);
429 UNDO_MOVE_PANEL,
430 UNDO_MOVE_ITEM,
431 UNDO_MOVE_AREA,
432 UNDO_MOVE_MONSTER,
433 UNDO_MOVE_TRIGGER: (MoveID: DWORD; dX, dY: Integer);
434 UNDO_RESIZE_PANEL,
435 UNDO_RESIZE_TRIGGER: (ResizeID: DWORD; dW, dH: Integer);
436 end;
438 TCopyRec = record
439 ObjectType: Byte;
440 ID: Cardinal;
441 case Byte of
442 OBJECT_PANEL: (Panel: ^TPanel);
443 OBJECT_ITEM: (Item: TItem);
444 OBJECT_AREA: (Area: TArea);
445 OBJECT_MONSTER: (Monster: TMonster);
446 OBJECT_TRIGGER: (Trigger: TTrigger);
447 end;
449 TCopyRecArray = Array of TCopyRec;
451 var
452 gEditorFont: DWORD;
453 gDataLoaded: Boolean = False;
454 ShowMap: Boolean = False;
455 DrawRect: PRect = nil;
456 SnapToGrid: Boolean = True;
458 MousePos: Types.TPoint;
459 LastMovePoint: Types.TPoint;
460 MouseLDown: Boolean;
461 MouseRDown: Boolean;
462 MouseMDown: Boolean;
463 MouseLDownPos: Types.TPoint;
464 MouseRDownPos: Types.TPoint;
465 MouseMDownPos: Types.TPoint;
467 SelectFlag: Byte = SELECTFLAG_NONE;
468 MouseAction: Byte = MOUSEACTION_NONE;
469 ResizeType: Byte = RESIZETYPE_NONE;
470 ResizeDirection: Byte = RESIZEDIR_NONE;
472 DrawPressRect: Boolean = False;
473 EditingProperties: Boolean = False;
475 UndoBuffer: Array of Array of TUndoRec = nil;
477 MapTestProcess: TProcessUTF8;
478 MapTestFile: String;
480 {$R *.lfm}
482 //----------------------------------------
483 //Далее идут вспомогательные процедуры
484 //----------------------------------------
486 function NameToBool(Name: String): Boolean;
487 begin
488 if Name = BoolNames[True] then
489 Result := True
490 else
491 Result := False;
492 end;
494 function NameToDir(Name: String): TDirection;
495 begin
496 if Name = DirNames[D_LEFT] then
497 Result := D_LEFT
498 else
499 Result := D_RIGHT;
500 end;
502 function NameToDirAdv(Name: String): Byte;
503 begin
504 if Name = DirNamesAdv[1] then
505 Result := 1
506 else
507 if Name = DirNamesAdv[2] then
508 Result := 2
509 else
510 if Name = DirNamesAdv[3] then
511 Result := 3
512 else
513 Result := 0;
514 end;
516 function ActivateToStr(ActivateType: Byte): String;
517 begin
518 Result := '';
520 if ByteBool(ACTIVATE_PLAYERCOLLIDE and ActivateType) then
521 Result := Result + '+PC';
522 if ByteBool(ACTIVATE_MONSTERCOLLIDE and ActivateType) then
523 Result := Result + '+MC';
524 if ByteBool(ACTIVATE_PLAYERPRESS and ActivateType) then
525 Result := Result + '+PP';
526 if ByteBool(ACTIVATE_MONSTERPRESS and ActivateType) then
527 Result := Result + '+MP';
528 if ByteBool(ACTIVATE_SHOT and ActivateType) then
529 Result := Result + '+SH';
530 if ByteBool(ACTIVATE_NOMONSTER and ActivateType) then
531 Result := Result + '+NM';
533 if (Result <> '') and (Result[1] = '+') then
534 Delete(Result, 1, 1);
535 end;
537 function StrToActivate(Str: String): Byte;
538 begin
539 Result := 0;
541 if Pos('PC', Str) > 0 then
542 Result := ACTIVATE_PLAYERCOLLIDE;
543 if Pos('MC', Str) > 0 then
544 Result := Result or ACTIVATE_MONSTERCOLLIDE;
545 if Pos('PP', Str) > 0 then
546 Result := Result or ACTIVATE_PLAYERPRESS;
547 if Pos('MP', Str) > 0 then
548 Result := Result or ACTIVATE_MONSTERPRESS;
549 if Pos('SH', Str) > 0 then
550 Result := Result or ACTIVATE_SHOT;
551 if Pos('NM', Str) > 0 then
552 Result := Result or ACTIVATE_NOMONSTER;
553 end;
555 function KeyToStr(Key: Byte): String;
556 begin
557 Result := '';
559 if ByteBool(KEY_RED and Key) then
560 Result := Result + '+RK';
561 if ByteBool(KEY_GREEN and Key) then
562 Result := Result + '+GK';
563 if ByteBool(KEY_BLUE and Key) then
564 Result := Result + '+BK';
565 if ByteBool(KEY_REDTEAM and Key) then
566 Result := Result + '+RT';
567 if ByteBool(KEY_BLUETEAM and Key) then
568 Result := Result + '+BT';
570 if (Result <> '') and (Result[1] = '+') then
571 Delete(Result, 1, 1);
572 end;
574 function StrToKey(Str: String): Byte;
575 begin
576 Result := 0;
578 if Pos('RK', Str) > 0 then
579 Result := KEY_RED;
580 if Pos('GK', Str) > 0 then
581 Result := Result or KEY_GREEN;
582 if Pos('BK', Str) > 0 then
583 Result := Result or KEY_BLUE;
584 if Pos('RT', Str) > 0 then
585 Result := Result or KEY_REDTEAM;
586 if Pos('BT', Str) > 0 then
587 Result := Result or KEY_BLUETEAM;
588 end;
590 function EffectToStr(Effect: Byte): String;
591 begin
592 if Effect in [EFFECT_TELEPORT..EFFECT_FIRE] then
593 Result := EffectNames[Effect]
594 else
595 Result := EffectNames[EFFECT_NONE];
596 end;
598 function StrToEffect(Str: String): Byte;
599 var
600 i: Integer;
601 begin
602 Result := EFFECT_NONE;
603 for i := EFFECT_TELEPORT to EFFECT_FIRE do
604 if EffectNames[i] = Str then
605 begin
606 Result := i;
607 Exit;
608 end;
609 end;
611 function MonsterToStr(MonType: Byte): String;
612 begin
613 if MonType in [MONSTER_DEMON..MONSTER_MAN] then
614 Result := MonsterNames[MonType]
615 else
616 Result := MonsterNames[MONSTER_ZOMBY];
617 end;
619 function StrToMonster(Str: String): Byte;
620 var
621 i: Integer;
622 begin
623 Result := MONSTER_ZOMBY;
624 for i := MONSTER_DEMON to MONSTER_MAN do
625 if MonsterNames[i] = Str then
626 begin
627 Result := i;
628 Exit;
629 end;
630 end;
632 function ItemToStr(ItemType: Byte): String;
633 begin
634 if ItemType in [ITEM_MEDKIT_SMALL..ITEM_MAX] then
635 Result := ItemNames[ItemType]
636 else
637 Result := ItemNames[ITEM_AMMO_BULLETS];
638 end;
640 function StrToItem(Str: String): Byte;
641 var
642 i: Integer;
643 begin
644 Result := ITEM_AMMO_BULLETS;
645 for i := ITEM_MEDKIT_SMALL to ITEM_MAX do
646 if ItemNames[i] = Str then
647 begin
648 Result := i;
649 Exit;
650 end;
651 end;
653 function ShotToStr(ShotType: Byte): String;
654 begin
655 if ShotType in [TRIGGER_SHOT_PISTOL..TRIGGER_SHOT_MAX] then
656 Result := ShotNames[ShotType]
657 else
658 Result := ShotNames[TRIGGER_SHOT_PISTOL];
659 end;
661 function StrToShot(Str: String): Byte;
662 var
663 i: Integer;
664 begin
665 Result := TRIGGER_SHOT_PISTOL;
666 for i := TRIGGER_SHOT_PISTOL to TRIGGER_SHOT_MAX do
667 if ShotNames[i] = Str then
668 begin
669 Result := i;
670 Exit;
671 end;
672 end;
674 function SelectedObjectCount(): Word;
675 var
676 a: Integer;
677 begin
678 Result := 0;
680 if SelectedObjects = nil then
681 Exit;
683 for a := 0 to High(SelectedObjects) do
684 if SelectedObjects[a].Live then
685 Result := Result + 1;
686 end;
688 function GetFirstSelected(): Integer;
689 var
690 a: Integer;
691 begin
692 Result := -1;
694 if SelectedObjects = nil then
695 Exit;
697 for a := 0 to High(SelectedObjects) do
698 if SelectedObjects[a].Live then
699 begin
700 Result := a;
701 Exit;
702 end;
703 end;
705 function Normalize16(x: Integer): Integer;
706 begin
707 Result := (x div 16) * 16;
708 end;
710 procedure MoveMap(X, Y: Integer);
711 var
712 rx, ry, ScaleSz: Integer;
713 begin
714 with MainForm.RenderPanel do
715 begin
716 ScaleSz := 16 div Scale;
717 // Размер видимой части карты:
718 rx := Min(Normalize16(Width), Normalize16(gMapInfo.Width)) div 2;
719 ry := Min(Normalize16(Height), Normalize16(gMapInfo.Height)) div 2;
720 // Место клика на мини-карте:
721 MapOffset.X := X - (Width - Max(gMapInfo.Width div ScaleSz, 1) - 1);
722 MapOffset.Y := Y - 1;
723 // Это же место на "большой" карте:
724 MapOffset.X := MapOffset.X * ScaleSz;
725 MapOffset.Y := MapOffset.Y * ScaleSz;
726 // Левый верхний угол новой видимой части карты:
727 MapOffset.X := MapOffset.X - rx;
728 MapOffset.Y := MapOffset.Y - ry;
729 // Выход за границы:
730 MapOffset.X := EnsureRange(MapOffset.X, MainForm.sbHorizontal.Min, MainForm.sbHorizontal.Max);
731 MapOffset.Y := EnsureRange(MapOffset.Y, MainForm.sbVertical.Min, MainForm.sbVertical.Max);
732 // Кратно 16:
733 // MapOffset.X := Normalize16(MapOffset.X);
734 // MapOffset.Y := Normalize16(MapOffset.Y);
735 end;
737 MainForm.sbHorizontal.Position := MapOffset.X;
738 MainForm.sbVertical.Position := MapOffset.Y;
740 MapOffset.X := -MapOffset.X;
741 MapOffset.Y := -MapOffset.Y;
743 MainForm.Resize();
744 end;
746 function IsTexturedPanel(PanelType: Word): Boolean;
747 begin
748 Result := WordBool(PanelType and (PANEL_WALL or PANEL_BACK or PANEL_FORE or
749 PANEL_STEP or PANEL_OPENDOOR or PANEL_CLOSEDOOR or
750 PANEL_WATER or PANEL_ACID1 or PANEL_ACID2));
751 end;
753 procedure FillProperty();
754 var
755 _id: DWORD;
756 str: String;
757 begin
758 MainForm.vleObjectProperty.Strings.Clear();
759 MainForm.RecountSelectedObjects();
761 // Отображаем свойства если выделен только один объект:
762 if SelectedObjectCount() <> 1 then
763 Exit;
765 _id := GetFirstSelected();
766 if not SelectedObjects[_id].Live then
767 Exit;
769 with MainForm.vleObjectProperty do
770 with ItemProps[InsertRow(_lc[I_PROP_ID], IntToStr(SelectedObjects[_id].ID), True)] do
771 begin
772 EditStyle := esSimple;
773 ReadOnly := True;
774 end;
776 case SelectedObjects[0].ObjectType of
777 OBJECT_PANEL:
778 begin
779 with MainForm.vleObjectProperty,
780 gPanels[SelectedObjects[_id].ID] do
781 begin
782 with ItemProps[InsertRow(_lc[I_PROP_X], IntToStr(X), True)] do
783 begin
784 EditStyle := esSimple;
785 MaxLength := 5;
786 end;
788 with ItemProps[InsertRow(_lc[I_PROP_Y], IntToStr(Y), True)] do
789 begin
790 EditStyle := esSimple;
791 MaxLength := 5;
792 end;
794 with ItemProps[InsertRow(_lc[I_PROP_WIDTH], IntToStr(Width), True)] do
795 begin
796 EditStyle := esSimple;
797 MaxLength := 5;
798 end;
800 with ItemProps[InsertRow(_lc[I_PROP_HEIGHT], IntToStr(Height), True)] do
801 begin
802 EditStyle := esSimple;
803 MaxLength := 5;
804 end;
806 with ItemProps[InsertRow(_lc[I_PROP_PANEL_TYPE], GetPanelName(PanelType), True)] do
807 begin
808 EditStyle := esEllipsis;
809 ReadOnly := True;
810 end;
812 if IsTexturedPanel(PanelType) then
813 begin // Может быть текстура
814 with ItemProps[InsertRow(_lc[I_PROP_PANEL_TEX], TextureName, True)] do
815 begin
816 EditStyle := esEllipsis;
817 ReadOnly := True;
818 end;
820 if TextureName <> '' then
821 begin // Есть текстура
822 with ItemProps[InsertRow(_lc[I_PROP_PANEL_ALPHA], IntToStr(Alpha), True)] do
823 begin
824 EditStyle := esSimple;
825 MaxLength := 3;
826 end;
828 with ItemProps[InsertRow(_lc[I_PROP_PANEL_BLEND], BoolNames[Blending], True)] do
829 begin
830 EditStyle := esPickList;
831 ReadOnly := True;
832 end;
833 end;
834 end;
835 end;
836 end;
838 OBJECT_ITEM:
839 begin
840 with MainForm.vleObjectProperty,
841 gItems[SelectedObjects[_id].ID] do
842 begin
843 with ItemProps[InsertRow(_lc[I_PROP_X], IntToStr(X), True)] do
844 begin
845 EditStyle := esSimple;
846 MaxLength := 5;
847 end;
849 with ItemProps[InsertRow(_lc[I_PROP_Y], IntToStr(Y), True)] do
850 begin
851 EditStyle := esSimple;
852 MaxLength := 5;
853 end;
855 with ItemProps[InsertRow(_lc[I_PROP_DM_ONLY], BoolNames[OnlyDM], True)] do
856 begin
857 EditStyle := esPickList;
858 ReadOnly := True;
859 end;
861 with ItemProps[InsertRow(_lc[I_PROP_ITEM_FALLS], BoolNames[Fall], True)] do
862 begin
863 EditStyle := esPickList;
864 ReadOnly := True;
865 end;
866 end;
867 end;
869 OBJECT_MONSTER:
870 begin
871 with MainForm.vleObjectProperty,
872 gMonsters[SelectedObjects[_id].ID] do
873 begin
874 with ItemProps[InsertRow(_lc[I_PROP_X], IntToStr(X), True)] do
875 begin
876 EditStyle := esSimple;
877 MaxLength := 5;
878 end;
880 with ItemProps[InsertRow(_lc[I_PROP_Y], IntToStr(Y), True)] do
881 begin
882 EditStyle := esSimple;
883 MaxLength := 5;
884 end;
886 with ItemProps[InsertRow(_lc[I_PROP_DIRECTION], DirNames[Direction], True)] do
887 begin
888 EditStyle := esPickList;
889 ReadOnly := True;
890 end;
891 end;
892 end;
894 OBJECT_AREA:
895 begin
896 with MainForm.vleObjectProperty,
897 gAreas[SelectedObjects[_id].ID] do
898 begin
899 with ItemProps[InsertRow(_lc[I_PROP_X], IntToStr(X), True)] do
900 begin
901 EditStyle := esSimple;
902 MaxLength := 5;
903 end;
905 with ItemProps[InsertRow(_lc[I_PROP_Y], IntToStr(Y), True)] do
906 begin
907 EditStyle := esSimple;
908 MaxLength := 5;
909 end;
911 with ItemProps[InsertRow(_lc[I_PROP_DIRECTION], DirNames[Direction], True)] do
912 begin
913 EditStyle := esPickList;
914 ReadOnly := True;
915 end;
916 end;
917 end;
919 OBJECT_TRIGGER:
920 begin
921 with MainForm.vleObjectProperty,
922 gTriggers[SelectedObjects[_id].ID] do
923 begin
924 with ItemProps[InsertRow(_lc[I_PROP_TR_TYPE], GetTriggerName(TriggerType), True)] do
925 begin
926 EditStyle := esSimple;
927 ReadOnly := True;
928 end;
930 with ItemProps[InsertRow(_lc[I_PROP_X], IntToStr(X), True)] do
931 begin
932 EditStyle := esSimple;
933 MaxLength := 5;
934 end;
936 with ItemProps[InsertRow(_lc[I_PROP_Y], IntToStr(Y), True)] do
937 begin
938 EditStyle := esSimple;
939 MaxLength := 5;
940 end;
942 with ItemProps[InsertRow(_lc[I_PROP_WIDTH], IntToStr(Width), True)] do
943 begin
944 EditStyle := esSimple;
945 MaxLength := 5;
946 end;
948 with ItemProps[InsertRow(_lc[I_PROP_HEIGHT], IntToStr(Height), True)] do
949 begin
950 EditStyle := esSimple;
951 MaxLength := 5;
952 end;
954 with ItemProps[InsertRow(_lc[I_PROP_TR_ENABLED], BoolNames[Enabled], True)] do
955 begin
956 EditStyle := esPickList;
957 ReadOnly := True;
958 end;
960 with ItemProps[InsertRow(_lc[I_PROP_TR_TEXTURE_PANEL], IntToStr(TexturePanel), True)] do
961 begin
962 EditStyle := esEllipsis;
963 ReadOnly := True;
964 end;
966 with ItemProps[InsertRow(_lc[I_PROP_TR_ACTIVATION], ActivateToStr(ActivateType), True)] do
967 begin
968 EditStyle := esEllipsis;
969 ReadOnly := True;
970 end;
972 with ItemProps[InsertRow(_lc[I_PROP_TR_KEYS], KeyToStr(Key), True)] do
973 begin
974 EditStyle := esEllipsis;
975 ReadOnly := True;
976 end;
978 case TriggerType of
979 TRIGGER_EXIT:
980 begin
981 str := win2utf(Data.MapName);
982 with ItemProps[InsertRow(_lc[I_PROP_TR_NEXT_MAP], str, True)] do
983 begin
984 EditStyle := esEllipsis;
985 ReadOnly := True;
986 end;
987 end;
989 TRIGGER_TELEPORT:
990 begin
991 with ItemProps[InsertRow(_lc[I_PROP_TR_TELEPORT_TO], Format('(%d:%d)', [Data.TargetPoint.X, Data.TargetPoint.Y]), True)] do
992 begin
993 EditStyle := esEllipsis;
994 ReadOnly := True;
995 end;
997 with ItemProps[InsertRow(_lc[I_PROP_TR_D2D], BoolNames[Data.d2d_teleport], True)] do
998 begin
999 EditStyle := esPickList;
1000 ReadOnly := True;
1001 end;
1003 with ItemProps[InsertRow(_lc[I_PROP_TR_TELEPORT_SILENT], BoolNames[Data.silent_teleport], True)] do
1004 begin
1005 EditStyle := esPickList;
1006 ReadOnly := True;
1007 end;
1009 with ItemProps[InsertRow(_lc[I_PROP_TR_TELEPORT_DIR], DirNamesAdv[Data.TlpDir], True)] do
1010 begin
1011 EditStyle := esPickList;
1012 ReadOnly := True;
1013 end;
1014 end;
1016 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR,
1017 TRIGGER_DOOR, TRIGGER_DOOR5:
1018 begin
1019 with ItemProps[InsertRow(_lc[I_PROP_TR_DOOR_PANEL], IntToStr(Data.PanelID), True)] do
1020 begin
1021 EditStyle := esEllipsis;
1022 ReadOnly := True;
1023 end;
1025 with ItemProps[InsertRow(_lc[I_PROP_TR_SILENT], BoolNames[Data.NoSound], True)] do
1026 begin
1027 EditStyle := esPickList;
1028 ReadOnly := True;
1029 end;
1031 with ItemProps[InsertRow(_lc[I_PROP_TR_D2D], BoolNames[Data.d2d_doors], True)] do
1032 begin
1033 EditStyle := esPickList;
1034 ReadOnly := True;
1035 end;
1036 end;
1038 TRIGGER_CLOSETRAP, TRIGGER_TRAP:
1039 begin
1040 with ItemProps[InsertRow(_lc[I_PROP_TR_TRAP_PANEL], IntToStr(Data.PanelID), True)] do
1041 begin
1042 EditStyle := esEllipsis;
1043 ReadOnly := True;
1044 end;
1046 with ItemProps[InsertRow(_lc[I_PROP_TR_SILENT], BoolNames[Data.NoSound], True)] do
1047 begin
1048 EditStyle := esPickList;
1049 ReadOnly := True;
1050 end;
1052 with ItemProps[InsertRow(_lc[I_PROP_TR_D2D], BoolNames[Data.d2d_doors], True)] do
1053 begin
1054 EditStyle := esPickList;
1055 ReadOnly := True;
1056 end;
1057 end;
1059 TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF,
1060 TRIGGER_ONOFF:
1061 begin
1062 with ItemProps[InsertRow(_lc[I_PROP_TR_EX_AREA],
1063 Format('(%d:%d %d:%d)', [Data.tX, Data.tY, Data.tWidth, Data.tHeight]), True)] do
1064 begin
1065 EditStyle := esEllipsis;
1066 ReadOnly := True;
1067 end;
1069 with ItemProps[InsertRow(_lc[I_PROP_TR_EX_DELAY], IntToStr(Data.Wait), True)] do
1070 begin
1071 EditStyle := esSimple;
1072 MaxLength := 5;
1073 end;
1075 with ItemProps[InsertRow(_lc[I_PROP_TR_EX_COUNT], IntToStr(Data.Count), True)] do
1076 begin
1077 EditStyle := esSimple;
1078 MaxLength := 5;
1079 end;
1081 with ItemProps[InsertRow(_lc[I_PROP_TR_EX_MONSTER], IntToStr(Data.MonsterID-1), True)] do
1082 begin
1083 EditStyle := esEllipsis;
1084 ReadOnly := True;
1085 end;
1087 if TriggerType = TRIGGER_PRESS then
1088 with ItemProps[InsertRow(_lc[I_PROP_TR_EX_RANDOM], BoolNames[Data.ExtRandom], True)] do
1089 begin
1090 EditStyle := esPickList;
1091 ReadOnly := True;
1092 end;
1093 end;
1095 TRIGGER_SECRET:
1098 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
1099 begin
1100 with ItemProps[InsertRow(_lc[I_PROP_TR_LIFT_PANEL], IntToStr(Data.PanelID), True)] do
1101 begin
1102 EditStyle := esEllipsis;
1103 ReadOnly := True;
1104 end;
1106 with ItemProps[InsertRow(_lc[I_PROP_TR_SILENT], BoolNames[Data.NoSound], True)] do
1107 begin
1108 EditStyle := esPickList;
1109 ReadOnly := True;
1110 end;
1112 with ItemProps[InsertRow(_lc[I_PROP_TR_D2D], BoolNames[Data.d2d_doors], True)] do
1113 begin
1114 EditStyle := esPickList;
1115 ReadOnly := True;
1116 end;
1117 end;
1119 TRIGGER_TEXTURE:
1120 begin
1121 with ItemProps[InsertRow(_lc[I_PROP_TR_TEXTURE_ONCE], BoolNames[Data.ActivateOnce], True)] do
1122 begin
1123 EditStyle := esPickList;
1124 ReadOnly := True;
1125 end;
1127 with ItemProps[InsertRow(_lc[I_PROP_TR_TEXTURE_ANIM_ONCE], BoolNames[Data.AnimOnce], True)] do
1128 begin
1129 EditStyle := esPickList;
1130 ReadOnly := True;
1131 end;
1132 end;
1134 TRIGGER_SOUND:
1135 begin
1136 str := win2utf(Data.SoundName);
1137 with ItemProps[InsertRow(_lc[I_PROP_TR_SOUND_NAME], str, True)] do
1138 begin
1139 EditStyle := esEllipsis;
1140 ReadOnly := True;
1141 end;
1143 with ItemProps[InsertRow(_lc[I_PROP_TR_SOUND_VOLUME], IntToStr(Data.Volume), True)] do
1144 begin
1145 EditStyle := esSimple;
1146 MaxLength := 3;
1147 end;
1149 with ItemProps[InsertRow(_lc[I_PROP_TR_SOUND_PAN], IntToStr(Data.Pan), True)] do
1150 begin
1151 EditStyle := esSimple;
1152 MaxLength := 3;
1153 end;
1155 with ItemProps[InsertRow(_lc[I_PROP_TR_SOUND_COUNT], IntToStr(Data.PlayCount), True)] do
1156 begin
1157 EditStyle := esSimple;
1158 MaxLength := 3;
1159 end;
1161 with ItemProps[InsertRow(_lc[I_PROP_TR_SOUND_LOCAL], BoolNames[Data.Local], True)] do
1162 begin
1163 EditStyle := esPickList;
1164 ReadOnly := True;
1165 end;
1167 with ItemProps[InsertRow(_lc[I_PROP_TR_SOUND_SWITCH], BoolNames[Data.SoundSwitch], True)] do
1168 begin
1169 EditStyle := esPickList;
1170 ReadOnly := True;
1171 end;
1172 end;
1174 TRIGGER_SPAWNMONSTER:
1175 begin
1176 with ItemProps[InsertRow(_lc[I_PROP_TR_MONSTER_TYPE], MonsterToStr(Data.MonType), True)] do
1177 begin
1178 EditStyle := esEllipsis;
1179 ReadOnly := True;
1180 end;
1182 with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_TO],
1183 Format('(%d:%d)', [Data.MonPos.X, Data.MonPos.Y]), True)] do
1184 begin
1185 EditStyle := esEllipsis;
1186 ReadOnly := True;
1187 end;
1189 with ItemProps[InsertRow(_lc[I_PROP_DIRECTION], DirNames[TDirection(Data.MonDir)], True)] do
1190 begin
1191 EditStyle := esPickList;
1192 ReadOnly := True;
1193 end;
1195 with ItemProps[InsertRow(_lc[I_PROP_TR_HEALTH], IntToStr(Data.MonHealth), True)] do
1196 begin
1197 EditStyle := esSimple;
1198 MaxLength := 5;
1199 end;
1201 with ItemProps[InsertRow(_lc[I_PROP_TR_MONSTER_ACTIVE], BoolNames[Data.MonActive], True)] do
1202 begin
1203 EditStyle := esPickList;
1204 ReadOnly := True;
1205 end;
1207 with ItemProps[InsertRow(_lc[I_PROP_TR_COUNT], IntToStr(Data.MonCount), True)] do
1208 begin
1209 EditStyle := esSimple;
1210 MaxLength := 5;
1211 end;
1213 with ItemProps[InsertRow(_lc[I_PROP_TR_FX_TYPE], EffectToStr(Data.MonEffect), True)] do
1214 begin
1215 EditStyle := esEllipsis;
1216 ReadOnly := True;
1217 end;
1219 with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_MAX], IntToStr(Data.MonMax), True)] do
1220 begin
1221 EditStyle := esSimple;
1222 MaxLength := 5;
1223 end;
1225 with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_DELAY], IntToStr(Data.MonDelay), True)] do
1226 begin
1227 EditStyle := esSimple;
1228 MaxLength := 5;
1229 end;
1231 case Data.MonBehav of
1232 1: str := _lc[I_PROP_TR_MONSTER_BEHAVIOUR_1];
1233 2: str := _lc[I_PROP_TR_MONSTER_BEHAVIOUR_2];
1234 3: str := _lc[I_PROP_TR_MONSTER_BEHAVIOUR_3];
1235 4: str := _lc[I_PROP_TR_MONSTER_BEHAVIOUR_4];
1236 5: str := _lc[I_PROP_TR_MONSTER_BEHAVIOUR_5];
1237 else str := _lc[I_PROP_TR_MONSTER_BEHAVIOUR_0];
1238 end;
1239 with ItemProps[InsertRow(_lc[I_PROP_TR_MONSTER_BEHAVIOUR], str, True)] do
1240 begin
1241 EditStyle := esPickList;
1242 ReadOnly := True;
1243 end;
1244 end;
1246 TRIGGER_SPAWNITEM:
1247 begin
1248 with ItemProps[InsertRow(_lc[I_PROP_TR_ITEM_TYPE], ItemToStr(Data.ItemType), True)] do
1249 begin
1250 EditStyle := esEllipsis;
1251 ReadOnly := True;
1252 end;
1254 with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_TO],
1255 Format('(%d:%d)', [Data.ItemPos.X, Data.ItemPos.Y]), True)] do
1256 begin
1257 EditStyle := esEllipsis;
1258 ReadOnly := True;
1259 end;
1261 with ItemProps[InsertRow(_lc[I_PROP_DM_ONLY], BoolNames[Data.ItemOnlyDM], True)] do
1262 begin
1263 EditStyle := esPickList;
1264 ReadOnly := True;
1265 end;
1267 with ItemProps[InsertRow(_lc[I_PROP_ITEM_FALLS], BoolNames[Data.ItemFalls], True)] do
1268 begin
1269 EditStyle := esPickList;
1270 ReadOnly := True;
1271 end;
1273 with ItemProps[InsertRow(_lc[I_PROP_TR_COUNT], IntToStr(Data.ItemCount), True)] do
1274 begin
1275 EditStyle := esSimple;
1276 MaxLength := 5;
1277 end;
1279 with ItemProps[InsertRow(_lc[I_PROP_TR_FX_TYPE], EffectToStr(Data.ItemEffect), True)] do
1280 begin
1281 EditStyle := esEllipsis;
1282 ReadOnly := True;
1283 end;
1285 with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_MAX], IntToStr(Data.ItemMax), True)] do
1286 begin
1287 EditStyle := esSimple;
1288 MaxLength := 5;
1289 end;
1291 with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_DELAY], IntToStr(Data.ItemDelay), True)] do
1292 begin
1293 EditStyle := esSimple;
1294 MaxLength := 5;
1295 end;
1296 end;
1298 TRIGGER_MUSIC:
1299 begin
1300 str := win2utf(Data.MusicName);
1301 with ItemProps[InsertRow(_lc[I_PROP_TR_MUSIC_NAME], str, True)] do
1302 begin
1303 EditStyle := esEllipsis;
1304 ReadOnly := True;
1305 end;
1307 if Data.MusicAction = 1 then
1308 str := _lc[I_PROP_TR_MUSIC_ON]
1309 else
1310 str := _lc[I_PROP_TR_MUSIC_OFF];
1312 with ItemProps[InsertRow(_lc[I_PROP_TR_MUSIC_ACT], str, True)] do
1313 begin
1314 EditStyle := esPickList;
1315 ReadOnly := True;
1316 end;
1317 end;
1319 TRIGGER_PUSH:
1320 begin
1321 with ItemProps[InsertRow(_lc[I_PROP_TR_PUSH_ANGLE], IntToStr(Data.PushAngle), True)] do
1322 begin
1323 EditStyle := esSimple;
1324 MaxLength := 4;
1325 end;
1326 with ItemProps[InsertRow(_lc[I_PROP_TR_PUSH_FORCE], IntToStr(Data.PushForce), True)] do
1327 begin
1328 EditStyle := esSimple;
1329 MaxLength := 4;
1330 end;
1331 with ItemProps[InsertRow(_lc[I_PROP_TR_PUSH_RESET], BoolNames[Data.ResetVel], True)] do
1332 begin
1333 EditStyle := esPickList;
1334 ReadOnly := True;
1335 end;
1336 end;
1338 TRIGGER_SCORE:
1339 begin
1340 case Data.ScoreAction of
1341 1: str := _lc[I_PROP_TR_SCORE_ACT_1];
1342 2: str := _lc[I_PROP_TR_SCORE_ACT_2];
1343 3: str := _lc[I_PROP_TR_SCORE_ACT_3];
1344 else str := _lc[I_PROP_TR_SCORE_ACT_0];
1345 end;
1346 with ItemProps[InsertRow(_lc[I_PROP_TR_SCORE_ACT], str, True)] do
1347 begin
1348 EditStyle := esPickList;
1349 ReadOnly := True;
1350 end;
1351 with ItemProps[InsertRow(_lc[I_PROP_TR_COUNT], IntToStr(Data.ScoreCount), True)] do
1352 begin
1353 EditStyle := esSimple;
1354 MaxLength := 3;
1355 end;
1356 case Data.ScoreTeam of
1357 1: str := _lc[I_PROP_TR_SCORE_TEAM_1];
1358 2: str := _lc[I_PROP_TR_SCORE_TEAM_2];
1359 3: str := _lc[I_PROP_TR_SCORE_TEAM_3];
1360 else str := _lc[I_PROP_TR_SCORE_TEAM_0];
1361 end;
1362 with ItemProps[InsertRow(_lc[I_PROP_TR_SCORE_TEAM], str, True)] do
1363 begin
1364 EditStyle := esPickList;
1365 ReadOnly := True;
1366 end;
1367 with ItemProps[InsertRow(_lc[I_PROP_TR_SCORE_CON], BoolNames[Data.ScoreCon], True)] do
1368 begin
1369 EditStyle := esPickList;
1370 ReadOnly := True;
1371 end;
1372 with ItemProps[InsertRow(_lc[I_PROP_TR_SCORE_MSG], BoolNames[Data.ScoreMsg], True)] do
1373 begin
1374 EditStyle := esPickList;
1375 ReadOnly := True;
1376 end;
1377 end;
1379 TRIGGER_MESSAGE:
1380 begin
1381 case Data.MessageKind of
1382 1: str := _lc[I_PROP_TR_MESSAGE_KIND_1];
1383 else str := _lc[I_PROP_TR_MESSAGE_KIND_0];
1384 end;
1385 with ItemProps[InsertRow(_lc[I_PROP_TR_MESSAGE_KIND], str, True)] do
1386 begin
1387 EditStyle := esPickList;
1388 ReadOnly := True;
1389 end;
1390 case Data.MessageSendTo of
1391 1: str := _lc[I_PROP_TR_MESSAGE_TO_1];
1392 2: str := _lc[I_PROP_TR_MESSAGE_TO_2];
1393 3: str := _lc[I_PROP_TR_MESSAGE_TO_3];
1394 4: str := _lc[I_PROP_TR_MESSAGE_TO_4];
1395 5: str := _lc[I_PROP_TR_MESSAGE_TO_5];
1396 else str := _lc[I_PROP_TR_MESSAGE_TO_0];
1397 end;
1398 with ItemProps[InsertRow(_lc[I_PROP_TR_MESSAGE_TO], str, True)] do
1399 begin
1400 EditStyle := esPickList;
1401 ReadOnly := True;
1402 end;
1403 str := win2utf(Data.MessageText);
1404 with ItemProps[InsertRow(_lc[I_PROP_TR_MESSAGE_TEXT], str, True)] do
1405 begin
1406 EditStyle := esSimple;
1407 MaxLength := 100;
1408 end;
1409 with ItemProps[InsertRow(_lc[I_PROP_TR_MESSAGE_TIME], IntToStr(Data.MessageTime), True)] do
1410 begin
1411 EditStyle := esSimple;
1412 MaxLength := 5;
1413 end;
1414 end;
1416 TRIGGER_DAMAGE:
1417 begin
1418 with ItemProps[InsertRow(_lc[I_PROP_TR_DAMAGE_VALUE], IntToStr(Data.DamageValue), True)] do
1419 begin
1420 EditStyle := esSimple;
1421 MaxLength := 5;
1422 end;
1423 with ItemProps[InsertRow(_lc[I_PROP_TR_INTERVAL], IntToStr(Data.DamageInterval), True)] do
1424 begin
1425 EditStyle := esSimple;
1426 MaxLength := 5;
1427 end;
1428 case Data.DamageKind of
1429 3: str := _lc[I_PROP_TR_DAMAGE_KIND_3];
1430 4: str := _lc[I_PROP_TR_DAMAGE_KIND_4];
1431 5: str := _lc[I_PROP_TR_DAMAGE_KIND_5];
1432 6: str := _lc[I_PROP_TR_DAMAGE_KIND_6];
1433 7: str := _lc[I_PROP_TR_DAMAGE_KIND_7];
1434 8: str := _lc[I_PROP_TR_DAMAGE_KIND_8];
1435 else str := _lc[I_PROP_TR_DAMAGE_KIND_0];
1436 end;
1437 with ItemProps[InsertRow(_lc[I_PROP_TR_DAMAGE_KIND], str, True)] do
1438 begin
1439 EditStyle := esPickList;
1440 ReadOnly := True;
1441 end;
1442 end;
1444 TRIGGER_HEALTH:
1445 begin
1446 with ItemProps[InsertRow(_lc[I_PROP_TR_HEALTH], IntToStr(Data.HealValue), True)] do
1447 begin
1448 EditStyle := esSimple;
1449 MaxLength := 5;
1450 end;
1451 with ItemProps[InsertRow(_lc[I_PROP_TR_INTERVAL], IntToStr(Data.HealInterval), True)] do
1452 begin
1453 EditStyle := esSimple;
1454 MaxLength := 5;
1455 end;
1456 with ItemProps[InsertRow(_lc[I_PROP_TR_HEALTH_MAX], BoolNames[Data.HealMax], True)] do
1457 begin
1458 EditStyle := esPickList;
1459 ReadOnly := True;
1460 end;
1461 with ItemProps[InsertRow(_lc[I_PROP_TR_SILENT], BoolNames[Data.HealSilent], True)] do
1462 begin
1463 EditStyle := esPickList;
1464 ReadOnly := True;
1465 end;
1466 end;
1468 TRIGGER_SHOT:
1469 begin
1470 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_TYPE], ShotToStr(Data.ShotType), True)] do
1471 begin
1472 EditStyle := esEllipsis;
1473 ReadOnly := True;
1474 end;
1476 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_SOUND], BoolNames[Data.ShotSound], True)] do
1477 begin
1478 EditStyle := esPickList;
1479 ReadOnly := True;
1480 end;
1482 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_PANEL], IntToStr(Data.ShotPanelID), True)] do
1483 begin
1484 EditStyle := esEllipsis;
1485 ReadOnly := True;
1486 end;
1488 case Data.ShotTarget of
1489 1: str := _lc[I_PROP_TR_SHOT_TO_1];
1490 2: str := _lc[I_PROP_TR_SHOT_TO_2];
1491 3: str := _lc[I_PROP_TR_SHOT_TO_3];
1492 4: str := _lc[I_PROP_TR_SHOT_TO_4];
1493 5: str := _lc[I_PROP_TR_SHOT_TO_5];
1494 6: str := _lc[I_PROP_TR_SHOT_TO_6];
1495 else str := _lc[I_PROP_TR_SHOT_TO_0];
1496 end;
1497 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_TO], str, True)] do
1498 begin
1499 EditStyle := esPickList;
1500 ReadOnly := True;
1501 end;
1503 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_SIGHT], IntToStr(Data.ShotIntSight), True)] do
1504 begin
1505 EditStyle := esSimple;
1506 MaxLength := 3;
1507 end;
1509 case Data.ShotAim of
1510 1: str := _lc[I_PROP_TR_SHOT_AIM_1];
1511 2: str := _lc[I_PROP_TR_SHOT_AIM_2];
1512 3: str := _lc[I_PROP_TR_SHOT_AIM_3];
1513 else str := _lc[I_PROP_TR_SHOT_AIM_0];
1514 end;
1515 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_AIM], str, True)] do
1516 begin
1517 EditStyle := esPickList;
1518 ReadOnly := True;
1519 end;
1521 with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_TO],
1522 Format('(%d:%d)', [Data.ShotPos.X, Data.ShotPos.Y]), True)] do
1523 begin
1524 EditStyle := esEllipsis;
1525 ReadOnly := True;
1526 end;
1528 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_ANGLE], IntToStr(Data.ShotAngle), True)] do
1529 begin
1530 EditStyle := esSimple;
1531 MaxLength := 4;
1532 end;
1534 with ItemProps[InsertRow(_lc[I_PROP_TR_EX_DELAY], IntToStr(Data.ShotWait), True)] do
1535 begin
1536 EditStyle := esSimple;
1537 MaxLength := 5;
1538 end;
1540 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_ACC], IntToStr(Data.ShotAccuracy), True)] do
1541 begin
1542 EditStyle := esSimple;
1543 MaxLength := 5;
1544 end;
1546 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_AMMO], IntToStr(Data.ShotAmmo), True)] do
1547 begin
1548 EditStyle := esSimple;
1549 MaxLength := 5;
1550 end;
1552 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_RELOAD], IntToStr(Data.ShotIntReload), True)] do
1553 begin
1554 EditStyle := esSimple;
1555 MaxLength := 4;
1556 end;
1557 end;
1559 TRIGGER_EFFECT:
1560 begin
1561 with ItemProps[InsertRow(_lc[I_PROP_TR_COUNT], IntToStr(Data.FXCount), True)] do
1562 begin
1563 EditStyle := esSimple;
1564 MaxLength := 3;
1565 end;
1567 if Data.FXType = 0 then
1568 str := _lc[I_PROP_TR_EFFECT_PARTICLE]
1569 else
1570 str := _lc[I_PROP_TR_EFFECT_ANIMATION];
1571 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_TYPE], str, True)] do
1572 begin
1573 EditStyle := esEllipsis;
1574 ReadOnly := True;
1575 end;
1577 str := '';
1578 if Data.FXType = 0 then
1579 case Data.FXSubType of
1580 TRIGGER_EFFECT_SLIQUID:
1581 str := _lc[I_PROP_TR_EFFECT_SLIQUID];
1582 TRIGGER_EFFECT_LLIQUID:
1583 str := _lc[I_PROP_TR_EFFECT_LLIQUID];
1584 TRIGGER_EFFECT_DLIQUID:
1585 str := _lc[I_PROP_TR_EFFECT_DLIQUID];
1586 TRIGGER_EFFECT_BLOOD:
1587 str := _lc[I_PROP_TR_EFFECT_BLOOD];
1588 TRIGGER_EFFECT_SPARK:
1589 str := _lc[I_PROP_TR_EFFECT_SPARK];
1590 TRIGGER_EFFECT_BUBBLE:
1591 str := _lc[I_PROP_TR_EFFECT_BUBBLE];
1592 end;
1593 if Data.FXType = 1 then
1594 begin
1595 if (Data.FXSubType = 0) or (Data.FXSubType > EFFECT_FIRE) then
1596 Data.FXSubType := EFFECT_TELEPORT;
1597 str := EffectToStr(Data.FXSubType);
1598 end;
1599 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_SUBTYPE], str, True)] do
1600 begin
1601 EditStyle := esEllipsis;
1602 ReadOnly := True;
1603 end;
1605 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_COLOR], IntToStr(Data.FXColorR or (Data.FXColorG shl 8) or (Data.FXColorB shl 16)), True)] do
1606 begin
1607 EditStyle := esEllipsis;
1608 ReadOnly := True;
1609 end;
1611 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_CENTER], BoolNames[Data.FXPos = 0], True)] do
1612 begin
1613 EditStyle := esPickList;
1614 ReadOnly := True;
1615 end;
1617 with ItemProps[InsertRow(_lc[I_PROP_TR_EX_DELAY], IntToStr(Data.FXWait), True)] do
1618 begin
1619 EditStyle := esSimple;
1620 MaxLength := 5;
1621 end;
1623 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_VELX], IntToStr(Data.FXVelX), True)] do
1624 begin
1625 EditStyle := esSimple;
1626 MaxLength := 4;
1627 end;
1629 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_VELY], IntToStr(Data.FXVelY), True)] do
1630 begin
1631 EditStyle := esSimple;
1632 MaxLength := 4;
1633 end;
1635 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_SPL], IntToStr(Data.FXSpreadL), True)] do
1636 begin
1637 EditStyle := esSimple;
1638 MaxLength := 3;
1639 end;
1641 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_SPR], IntToStr(Data.FXSpreadR), True)] do
1642 begin
1643 EditStyle := esSimple;
1644 MaxLength := 3;
1645 end;
1647 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_SPU], IntToStr(Data.FXSpreadU), True)] do
1648 begin
1649 EditStyle := esSimple;
1650 MaxLength := 3;
1651 end;
1653 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_SPD], IntToStr(Data.FXSpreadD), True)] do
1654 begin
1655 EditStyle := esSimple;
1656 MaxLength := 3;
1657 end;
1658 end;
1659 end; //case TriggerType
1660 end;
1661 end; // OBJECT_TRIGGER:
1662 end;
1663 end;
1665 procedure ChangeShownProperty(Name: String; NewValue: String);
1666 var
1667 row: Integer;
1668 begin
1669 if SelectedObjectCount() <> 1 then
1670 Exit;
1671 if not SelectedObjects[GetFirstSelected()].Live then
1672 Exit;
1674 // Есть ли такой ключ:
1675 if MainForm.vleObjectProperty.FindRow(Name, row) then
1676 begin
1677 MainForm.vleObjectProperty.Values[Name] := NewValue;
1678 end;
1679 end;
1681 procedure SelectObject(fObjectType: Byte; fID: DWORD; Multi: Boolean);
1682 var
1683 a: Integer;
1684 b: Boolean;
1685 begin
1686 if Multi then
1687 begin
1688 b := False;
1690 // Уже выделен - убираем:
1691 if SelectedObjects <> nil then
1692 for a := 0 to High(SelectedObjects) do
1693 with SelectedObjects[a] do
1694 if Live and (ID = fID) and
1695 (ObjectType = fObjectType) then
1696 begin
1697 Live := False;
1698 b := True;
1699 end;
1701 if b then
1702 Exit;
1704 SetLength(SelectedObjects, Length(SelectedObjects)+1);
1706 with SelectedObjects[High(SelectedObjects)] do
1707 begin
1708 ObjectType := fObjectType;
1709 ID := fID;
1710 Live := True;
1711 end;
1712 end
1713 else // not Multi
1714 begin
1715 SetLength(SelectedObjects, 1);
1717 with SelectedObjects[0] do
1718 begin
1719 ObjectType := fObjectType;
1720 ID := fID;
1721 Live := True;
1722 end;
1723 end;
1725 MainForm.miCopy.Enabled := True;
1726 MainForm.miCut.Enabled := True;
1728 if fObjectType = OBJECT_PANEL then
1729 begin
1730 MainForm.miToFore.Enabled := True;
1731 MainForm.miToBack.Enabled := True;
1732 end;
1733 end;
1735 procedure RemoveSelectFromObjects();
1736 begin
1737 SelectedObjects := nil;
1738 DrawPressRect := False;
1739 MouseLDown := False;
1740 MouseRDown := False;
1741 MouseAction := MOUSEACTION_NONE;
1742 SelectFlag := SELECTFLAG_NONE;
1743 ResizeType := RESIZETYPE_NONE;
1744 ResizeDirection := RESIZEDIR_NONE;
1746 MainForm.vleObjectProperty.Strings.Clear();
1748 MainForm.miCopy.Enabled := False;
1749 MainForm.miCut.Enabled := False;
1750 MainForm.miToFore.Enabled := False;
1751 MainForm.miToBack.Enabled := False;
1752 end;
1754 procedure DeleteSelectedObjects();
1755 var
1756 i, a, ii: Integer;
1757 b: Boolean;
1758 begin
1759 if SelectedObjects = nil then
1760 Exit;
1762 b := False;
1763 i := 0;
1765 for a := 0 to High(SelectedObjects) do
1766 with SelectedObjects[a] do
1767 if Live then
1768 begin
1769 if not b then
1770 begin
1771 SetLength(UndoBuffer, Length(UndoBuffer)+1);
1772 i := High(UndoBuffer);
1773 b := True;
1774 end;
1776 SetLength(UndoBuffer[i], Length(UndoBuffer[i])+1);
1777 ii := High(UndoBuffer[i]);
1779 case ObjectType of
1780 OBJECT_PANEL:
1781 begin
1782 UndoBuffer[i, ii].UndoType := UNDO_DELETE_PANEL;
1783 New(UndoBuffer[i, ii].Panel);
1784 UndoBuffer[i, ii].Panel^ := gPanels[ID];
1785 end;
1786 OBJECT_ITEM:
1787 begin
1788 UndoBuffer[i, ii].UndoType := UNDO_DELETE_ITEM;
1789 UndoBuffer[i, ii].Item := gItems[ID];
1790 end;
1791 OBJECT_AREA:
1792 begin
1793 UndoBuffer[i, ii].UndoType := UNDO_DELETE_AREA;
1794 UndoBuffer[i, ii].Area := gAreas[ID];
1795 end;
1796 OBJECT_TRIGGER:
1797 begin
1798 UndoBuffer[i, ii].UndoType := UNDO_DELETE_TRIGGER;
1799 UndoBuffer[i, ii].Trigger := gTriggers[ID];
1800 end;
1801 end;
1803 RemoveObject(ID, ObjectType);
1804 end;
1806 RemoveSelectFromObjects();
1808 MainForm.miUndo.Enabled := UndoBuffer <> nil;
1809 MainForm.RecountSelectedObjects();
1810 end;
1812 procedure Undo_Add(ObjectType: Byte; ID: DWORD; Group: Boolean = False);
1813 var
1814 i, ii: Integer;
1815 begin
1816 if (not Group) or (Length(UndoBuffer) = 0) then
1817 SetLength(UndoBuffer, Length(UndoBuffer)+1);
1818 SetLength(UndoBuffer[High(UndoBuffer)], Length(UndoBuffer[High(UndoBuffer)])+1);
1819 i := High(UndoBuffer);
1820 ii := High(UndoBuffer[i]);
1822 case ObjectType of
1823 OBJECT_PANEL:
1824 UndoBuffer[i, ii].UndoType := UNDO_ADD_PANEL;
1825 OBJECT_ITEM:
1826 UndoBuffer[i, ii].UndoType := UNDO_ADD_ITEM;
1827 OBJECT_MONSTER:
1828 UndoBuffer[i, ii].UndoType := UNDO_ADD_MONSTER;
1829 OBJECT_AREA:
1830 UndoBuffer[i, ii].UndoType := UNDO_ADD_AREA;
1831 OBJECT_TRIGGER:
1832 UndoBuffer[i, ii].UndoType := UNDO_ADD_TRIGGER;
1833 end;
1835 UndoBuffer[i, ii].AddID := ID;
1837 MainForm.miUndo.Enabled := UndoBuffer <> nil;
1838 end;
1840 procedure FullClear();
1841 begin
1842 RemoveSelectFromObjects();
1843 ClearMap();
1844 LoadSky(gMapInfo.SkyName);
1845 UndoBuffer := nil;
1846 slInvalidTextures.Clear();
1847 MapCheckForm.lbErrorList.Clear();
1848 MapCheckForm.mErrorDescription.Clear();
1850 MainForm.miUndo.Enabled := False;
1851 MainForm.sbHorizontal.Position := 0;
1852 MainForm.sbVertical.Position := 0;
1853 MainForm.FormResize(nil);
1854 MainForm.Caption := FormCaption;
1855 OpenedMap := '';
1856 OpenedWAD := '';
1857 end;
1859 procedure ErrorMessageBox(str: String);
1860 begin
1861 Application.MessageBox(PChar(str), PChar(_lc[I_MSG_ERROR]),
1862 MB_ICONINFORMATION or MB_OK or MB_DEFBUTTON1);
1863 end;
1865 function CheckProperty(): Boolean;
1866 var
1867 _id: Integer;
1868 begin
1869 Result := False;
1871 _id := GetFirstSelected();
1873 if SelectedObjects[_id].ObjectType = OBJECT_PANEL then
1874 with gPanels[SelectedObjects[_id].ID] do
1875 begin
1876 if TextureWidth <> 0 then
1877 if StrToIntDef(MainForm.vleObjectProperty.Values[_lc[I_PROP_WIDTH]], 1) mod TextureWidth <> 0 then
1878 begin
1879 ErrorMessageBox(Format(_lc[I_MSG_WRONG_TEXWIDTH],
1880 [TextureWidth]));
1881 Exit;
1882 end;
1884 if TextureHeight <> 0 then
1885 if StrToIntDef(Trim(MainForm.vleObjectProperty.Values[_lc[I_PROP_HEIGHT]]), 1) mod TextureHeight <> 0 then
1886 begin
1887 ErrorMessageBox(Format(_lc[I_MSG_WRONG_TEXHEIGHT],
1888 [TextureHeight]));
1889 Exit;
1890 end;
1892 if IsTexturedPanel(PanelType) and (TextureName <> '') then
1893 if not (StrToIntDef(MainForm.vleObjectProperty.Values[_lc[I_PROP_PANEL_ALPHA]], -1) in [0..255]) then
1894 begin
1895 ErrorMessageBox(_lc[I_MSG_WRONG_ALPHA]);
1896 Exit;
1897 end;
1898 end;
1900 if SelectedObjects[_id].ObjectType in [OBJECT_PANEL, OBJECT_TRIGGER] then
1901 if (StrToIntDef(MainForm.vleObjectProperty.Values[_lc[I_PROP_WIDTH]], 0) <= 0) or
1902 (StrToIntDef(MainForm.vleObjectProperty.Values[_lc[I_PROP_HEIGHT]], 0) <= 0) then
1903 begin
1904 ErrorMessageBox(_lc[I_MSG_WRONG_SIZE]);
1905 Exit;
1906 end;
1908 if (Trim(MainForm.vleObjectProperty.Values[_lc[I_PROP_X]]) = '') or
1909 (Trim(MainForm.vleObjectProperty.Values[_lc[I_PROP_Y]]) = '') then
1910 begin
1911 ErrorMessageBox(_lc[I_MSG_WRONG_XY]);
1912 Exit;
1913 end;
1915 Result := True;
1916 end;
1918 procedure SelectTexture(ID: Integer);
1919 begin
1920 MainForm.lbTextureList.ItemIndex := ID;
1921 MainForm.lbTextureListClick(nil);
1922 end;
1924 function AddTexture(aWAD, aSection, aTex: String; silent: Boolean): Boolean;
1925 var
1926 a, FrameLen: Integer;
1927 ok: Boolean;
1928 FileName: String;
1929 ResourceName: String;
1930 FullResourceName: String;
1931 SectionName: String;
1932 Data: Pointer;
1933 Width, Height: Word;
1934 fn: String;
1935 begin
1936 Data := nil;
1937 FrameLen := 0;
1938 Width := 0;
1939 Height := 0;
1941 if aSection = '..' then
1942 SectionName := ''
1943 else
1944 SectionName := aSection;
1946 if aWAD = '' then
1947 aWAD := _lc[I_WAD_SPECIAL_MAP];
1949 if aWAD = _lc[I_WAD_SPECIAL_MAP] then
1950 begin // Файл карты
1951 g_ProcessResourceStr(OpenedMap, @fn, nil, nil);
1952 FileName := fn;
1953 ResourceName := ':'+SectionName+'\'+aTex;
1954 end
1955 else
1956 if aWAD = _lc[I_WAD_SPECIAL_TEXS] then
1957 begin // Спец. текстуры
1958 FileName := '';
1959 ResourceName := aTex;
1960 end
1961 else
1962 begin // Внешний WAD
1963 FileName := WadsDir + DirectorySeparator + aWAD;
1964 ResourceName := aWAD+':'+SectionName+'\'+aTex;
1965 end;
1967 ok := True;
1969 // Есть ли уже такая текстура:
1970 for a := 0 to MainForm.lbTextureList.Items.Count-1 do
1971 if ResourceName = MainForm.lbTextureList.Items[a] then
1972 begin
1973 if not silent then
1974 ErrorMessageBox(Format(_lc[I_MSG_TEXTURE_ALREADY],
1975 [ResourceName]));
1976 ok := False;
1977 end;
1979 // Название ресурса <= 64 символов:
1980 if Length(ResourceName) > 64 then
1981 begin
1982 if not silent then
1983 ErrorMessageBox(Format(_lc[I_MSG_RES_NAME_64],
1984 [ResourceName]));
1985 ok := False;
1986 end;
1988 if ok then
1989 begin
1990 a := -1;
1991 if aWAD = _lc[I_WAD_SPECIAL_TEXS] then
1992 begin
1993 a := MainForm.lbTextureList.Items.Add(ResourceName);
1994 if not silent then
1995 SelectTexture(a);
1996 Result := True;
1997 Exit;
1998 end;
2000 FullResourceName := FileName+':'+SectionName+'\'+aTex;
2002 if IsAnim(FullResourceName) then
2003 begin // Аним. текстура
2004 GetFrame(FullResourceName, Data, FrameLen, Width, Height);
2006 if not g_CreateTextureMemorySize(Data, FrameLen, ResourceName, 0, 0, Width, Height, 1) then
2007 ok := False;
2008 a := MainForm.lbTextureList.Items.Add(ResourceName);
2009 end
2010 else // Обычная текстура
2011 begin
2012 if not g_CreateTextureWAD(ResourceName, FullResourceName) then
2013 ok := False;
2014 a := MainForm.lbTextureList.Items.Add(ResourceName);
2015 end;
2016 if (not ok) and (slInvalidTextures.IndexOf(ResourceName) = -1) then
2017 begin
2018 slInvalidTextures.Add(ResourceName);
2019 ok := True;
2020 end;
2021 if (a > -1) and (not silent) then
2022 SelectTexture(a);
2023 end;
2025 Result := ok;
2026 end;
2028 procedure UpdateCaption(sMap, sFile, sRes: String);
2029 begin
2030 with MainForm do
2031 if (sFile = '') and (sRes = '') and (sMap = '') then
2032 Caption := FormCaption
2033 else
2034 if sMap = '' then
2035 Caption := Format('%s - %s:%s', [FormCaption, sFile, sRes])
2036 else
2037 if (sFile <> '') and (sRes <> '') then
2038 Caption := Format('%s - %s (%s:%s)', [FormCaption, sMap, sFile, sRes])
2039 else
2040 Caption := Format('%s - %s', [FormCaption, sMap]);
2041 end;
2043 procedure OpenMap(FileName: String; mapN: String);
2044 var
2045 MapName: String;
2046 idx: Integer;
2047 begin
2048 SelectMapForm.Caption := _lc[I_CAP_OPEN];
2049 SelectMapForm.GetMaps(FileName);
2051 if (FileName = OpenedWAD) and
2052 (OpenedMap <> '') then
2053 begin
2054 MapName := OpenedMap;
2055 while (Pos(':\', MapName) > 0) do
2056 Delete(MapName, 1, Pos(':\', MapName) + 1);
2058 idx := SelectMapForm.lbMapList.Items.IndexOf(MapName);
2059 SelectMapForm.lbMapList.ItemIndex := idx;
2060 end
2061 else
2062 if SelectMapForm.lbMapList.Count > 0 then
2063 SelectMapForm.lbMapList.ItemIndex := 0
2064 else
2065 SelectMapForm.lbMapList.ItemIndex := -1;
2067 if mapN = '' then
2068 idx := -1
2069 else
2070 idx := SelectMapForm.lbMapList.Items.IndexOf(mapN);
2072 if idx < 0 then
2073 begin
2074 if (SelectMapForm.ShowModal() = mrOK) and
2075 (SelectMapForm.lbMapList.ItemIndex <> -1) then
2076 idx := SelectMapForm.lbMapList.ItemIndex
2077 else
2078 Exit;
2079 end;
2081 MapName := SelectMapForm.lbMapList.Items[idx];
2083 with MainForm do
2084 begin
2085 FullClear();
2087 pLoadProgress.Left := (RenderPanel.Width div 2)-(pLoadProgress.Width div 2);
2088 pLoadProgress.Top := (RenderPanel.Height div 2)-(pLoadProgress.Height div 2);
2089 pLoadProgress.Show();
2091 OpenedMap := FileName+':\'+MapName;
2092 OpenedWAD := FileName;
2094 idx := RecentFiles.IndexOf(OpenedMap);
2095 // Такая карта уже недавно открывалась:
2096 if idx >= 0 then
2097 RecentFiles.Delete(idx);
2098 RecentFiles.Insert(0, OpenedMap);
2099 RefreshRecentMenu();
2101 LoadMap(OpenedMap);
2103 pLoadProgress.Hide();
2104 FormResize(nil);
2106 lbTextureList.Sorted := True;
2107 lbTextureList.Sorted := False;
2109 UpdateCaption(gMapInfo.Name, ExtractFileName(FileName), MapName);
2110 end;
2111 end;
2113 procedure MoveSelectedObjects(Wall, alt: Boolean; dx, dy: Integer);
2114 var
2115 okX, okY: Boolean;
2116 a: Integer;
2117 begin
2118 if SelectedObjects = nil then
2119 Exit;
2121 okX := True;
2122 okY := True;
2124 if Wall then
2125 for a := 0 to High(SelectedObjects) do
2126 if SelectedObjects[a].Live then
2127 begin
2128 if ObjectCollideLevel(SelectedObjects[a].ID, SelectedObjects[a].ObjectType, dx, 0) then
2129 okX := False;
2131 if ObjectCollideLevel(SelectedObjects[a].ID, SelectedObjects[a].ObjectType, 0, dy) then
2132 okY := False;
2134 if (not okX) or (not okY) then
2135 Break;
2136 end;
2138 if okX or okY then
2139 begin
2140 for a := 0 to High(SelectedObjects) do
2141 if SelectedObjects[a].Live then
2142 begin
2143 if okX then
2144 MoveObject(SelectedObjects[a].ObjectType, SelectedObjects[a].ID, dx, 0);
2146 if okY then
2147 MoveObject(SelectedObjects[a].ObjectType, SelectedObjects[a].ID, 0, dy);
2149 if alt and (SelectedObjects[a].ObjectType = OBJECT_TRIGGER) then
2150 begin
2151 if gTriggers[SelectedObjects[a].ID].TriggerType in [TRIGGER_PRESS,
2152 TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF] then
2153 begin // Двигаем зону Расширителя
2154 if okX then
2155 gTriggers[SelectedObjects[a].ID].Data.tX := gTriggers[SelectedObjects[a].ID].Data.tX+dx;
2156 if okY then
2157 gTriggers[SelectedObjects[a].ID].Data.tY := gTriggers[SelectedObjects[a].ID].Data.tY+dy;
2158 end;
2160 if gTriggers[SelectedObjects[a].ID].TriggerType in [TRIGGER_TELEPORT] then
2161 begin // Двигаем точку назначения Телепорта
2162 if okX then
2163 gTriggers[SelectedObjects[a].ID].Data.TargetPoint.X := gTriggers[SelectedObjects[a].ID].Data.TargetPoint.X+dx;
2164 if okY then
2165 gTriggers[SelectedObjects[a].ID].Data.TargetPoint.Y := gTriggers[SelectedObjects[a].ID].Data.TargetPoint.Y+dy;
2166 end;
2168 if gTriggers[SelectedObjects[a].ID].TriggerType in [TRIGGER_SPAWNMONSTER] then
2169 begin // Двигаем точку создания монстра
2170 if okX then
2171 gTriggers[SelectedObjects[a].ID].Data.MonPos.X := gTriggers[SelectedObjects[a].ID].Data.MonPos.X+dx;
2172 if okY then
2173 gTriggers[SelectedObjects[a].ID].Data.MonPos.Y := gTriggers[SelectedObjects[a].ID].Data.MonPos.Y+dy;
2174 end;
2176 if gTriggers[SelectedObjects[a].ID].TriggerType in [TRIGGER_SPAWNITEM] then
2177 begin // Двигаем точку создания предмета
2178 if okX then
2179 gTriggers[SelectedObjects[a].ID].Data.ItemPos.X := gTriggers[SelectedObjects[a].ID].Data.ItemPos.X+dx;
2180 if okY then
2181 gTriggers[SelectedObjects[a].ID].Data.ItemPos.Y := gTriggers[SelectedObjects[a].ID].Data.ItemPos.Y+dy;
2182 end;
2184 if gTriggers[SelectedObjects[a].ID].TriggerType in [TRIGGER_SHOT] then
2185 begin // Двигаем точку создания выстрела
2186 if okX then
2187 gTriggers[SelectedObjects[a].ID].Data.ShotPos.X := gTriggers[SelectedObjects[a].ID].Data.ShotPos.X+dx;
2188 if okY then
2189 gTriggers[SelectedObjects[a].ID].Data.ShotPos.Y := gTriggers[SelectedObjects[a].ID].Data.ShotPos.Y+dy;
2190 end;
2191 end;
2192 end;
2194 LastMovePoint := MousePos;
2195 end;
2196 end;
2198 procedure ShowLayer(Layer: Byte; show: Boolean);
2199 begin
2200 LayerEnabled[Layer] := show;
2202 case Layer of
2203 LAYER_BACK:
2204 begin
2205 MainForm.miLayer1.Checked := show;
2206 MainForm.miLayerP1.Checked := show;
2207 end;
2208 LAYER_WALLS:
2209 begin
2210 MainForm.miLayer2.Checked := show;
2211 MainForm.miLayerP2.Checked := show;
2212 end;
2213 LAYER_FOREGROUND:
2214 begin
2215 MainForm.miLayer3.Checked := show;
2216 MainForm.miLayerP3.Checked := show;
2217 end;
2218 LAYER_STEPS:
2219 begin
2220 MainForm.miLayer4.Checked := show;
2221 MainForm.miLayerP4.Checked := show;
2222 end;
2223 LAYER_WATER:
2224 begin
2225 MainForm.miLayer5.Checked := show;
2226 MainForm.miLayerP5.Checked := show;
2227 end;
2228 LAYER_ITEMS:
2229 begin
2230 MainForm.miLayer6.Checked := show;
2231 MainForm.miLayerP6.Checked := show;
2232 end;
2233 LAYER_MONSTERS:
2234 begin
2235 MainForm.miLayer7.Checked := show;
2236 MainForm.miLayerP7.Checked := show;
2237 end;
2238 LAYER_AREAS:
2239 begin
2240 MainForm.miLayer8.Checked := show;
2241 MainForm.miLayerP8.Checked := show;
2242 end;
2243 LAYER_TRIGGERS:
2244 begin
2245 MainForm.miLayer9.Checked := show;
2246 MainForm.miLayerP9.Checked := show;
2247 end;
2248 end;
2250 RemoveSelectFromObjects();
2251 end;
2253 procedure SwitchLayer(Layer: Byte);
2254 begin
2255 ShowLayer(Layer, not LayerEnabled[Layer]);
2256 end;
2258 procedure SwitchMap();
2259 begin
2260 ShowMap := not ShowMap;
2261 MainForm.tbShowMap.Down := ShowMap;
2262 MainForm.miMiniMap.Checked := ShowMap;
2263 end;
2265 procedure ShowEdges();
2266 begin
2267 if drEdge[3] < 255 then
2268 drEdge[3] := 255
2269 else
2270 drEdge[3] := gAlphaEdge;
2271 MainForm.miShowEdges.Checked := drEdge[3] <> 255;
2272 end;
2274 function SelectedTexture(): String;
2275 begin
2276 if MainForm.lbTextureList.ItemIndex <> -1 then
2277 Result := MainForm.lbTextureList.Items[MainForm.lbTextureList.ItemIndex]
2278 else
2279 Result := '';
2280 end;
2282 function IsSpecialTextureSel(): Boolean;
2283 begin
2284 Result := (MainForm.lbTextureList.ItemIndex <> -1) and
2285 IsSpecialTexture(MainForm.lbTextureList.Items[MainForm.lbTextureList.ItemIndex]);
2286 end;
2288 function CopyBufferToString(var CopyBuf: TCopyRecArray): String;
2289 var
2290 i, j: Integer;
2291 Res: String;
2293 procedure AddInt(x: Integer);
2294 begin
2295 Res := Res + IntToStr(x) + ' ';
2296 end;
2298 begin
2299 Result := '';
2301 if Length(CopyBuf) = 0 then
2302 Exit;
2304 Res := CLIPBOARD_SIG + ' ';
2306 for i := 0 to High(CopyBuf) do
2307 begin
2308 if (CopyBuf[i].ObjectType = OBJECT_PANEL) and
2309 (CopyBuf[i].Panel = nil) then
2310 Continue;
2312 // Тип объекта:
2313 AddInt(CopyBuf[i].ObjectType);
2314 Res := Res + '; ';
2316 // Свойства объекта:
2317 case CopyBuf[i].ObjectType of
2318 OBJECT_PANEL:
2319 with CopyBuf[i].Panel^ do
2320 begin
2321 AddInt(PanelType);
2322 AddInt(X);
2323 AddInt(Y);
2324 AddInt(Width);
2325 AddInt(Height);
2326 Res := Res + '"' + TextureName + '" ';
2327 AddInt(Alpha);
2328 AddInt(IfThen(Blending, 1, 0));
2329 end;
2331 OBJECT_ITEM:
2332 with CopyBuf[i].Item do
2333 begin
2334 AddInt(ItemType);
2335 AddInt(X);
2336 AddInt(Y);
2337 AddInt(IfThen(OnlyDM, 1, 0));
2338 AddInt(IfThen(Fall, 1, 0));
2339 end;
2341 OBJECT_MONSTER:
2342 with CopyBuf[i].Monster do
2343 begin
2344 AddInt(MonsterType);
2345 AddInt(X);
2346 AddInt(Y);
2347 AddInt(IfThen(Direction = D_LEFT, 1, 0));
2348 end;
2350 OBJECT_AREA:
2351 with CopyBuf[i].Area do
2352 begin
2353 AddInt(AreaType);
2354 AddInt(X);
2355 AddInt(Y);
2356 AddInt(IfThen(Direction = D_LEFT, 1, 0));
2357 end;
2359 OBJECT_TRIGGER:
2360 with CopyBuf[i].Trigger do
2361 begin
2362 AddInt(TriggerType);
2363 AddInt(X);
2364 AddInt(Y);
2365 AddInt(Width);
2366 AddInt(Height);
2367 AddInt(ActivateType);
2368 AddInt(Key);
2369 AddInt(IfThen(Enabled, 1, 0));
2370 AddInt(TexturePanel);
2372 for j := 0 to 127 do
2373 AddInt(Data.Default[j]);
2374 end;
2375 end;
2376 end;
2378 Result := Res;
2379 end;
2381 procedure StringToCopyBuffer(Str: String; var CopyBuf: TCopyRecArray;
2382 var pmin: TPoint);
2383 var
2384 i, j, t: Integer;
2386 function GetNext(): String;
2387 var
2388 p: Integer;
2390 begin
2391 if Str[1] = '"' then
2392 begin
2393 Delete(Str, 1, 1);
2394 p := Pos('"', Str);
2396 if p = 0 then
2397 begin
2398 Result := Str;
2399 Str := '';
2400 end
2401 else
2402 begin
2403 Result := Copy(Str, 1, p-1);
2404 Delete(Str, 1, p);
2405 Str := Trim(Str);
2406 end;
2407 end
2408 else
2409 begin
2410 p := Pos(' ', Str);
2412 if p = 0 then
2413 begin
2414 Result := Str;
2415 Str := '';
2416 end
2417 else
2418 begin
2419 Result := Copy(Str, 1, p-1);
2420 Delete(Str, 1, p);
2421 Str := Trim(Str);
2422 end;
2423 end;
2424 end;
2426 begin
2427 Str := Trim(Str);
2429 if GetNext() <> CLIPBOARD_SIG then
2430 Exit;
2432 while Str <> '' do
2433 begin
2434 // Тип объекта:
2435 t := StrToIntDef(GetNext(), 0);
2437 if (t < OBJECT_PANEL) or (t > OBJECT_TRIGGER) or
2438 (GetNext() <> ';') then
2439 begin // Что-то не то => пропускаем:
2440 t := Pos(';', Str);
2441 Delete(Str, 1, t);
2442 Str := Trim(Str);
2444 Continue;
2445 end;
2447 i := Length(CopyBuf);
2448 SetLength(CopyBuf, i + 1);
2450 CopyBuf[i].ObjectType := t;
2451 CopyBuf[i].Panel := nil;
2453 // Свойства объекта:
2454 case t of
2455 OBJECT_PANEL:
2456 begin
2457 New(CopyBuf[i].Panel);
2459 with CopyBuf[i].Panel^ do
2460 begin
2461 PanelType := StrToIntDef(GetNext(), PANEL_WALL);
2462 X := StrToIntDef(GetNext(), 0);
2463 Y := StrToIntDef(GetNext(), 0);
2464 pmin.X := Min(X, pmin.X);
2465 pmin.Y := Min(Y, pmin.Y);
2466 Width := StrToIntDef(GetNext(), 16);
2467 Height := StrToIntDef(GetNext(), 16);
2468 TextureName := GetNext();
2469 Alpha := StrToIntDef(GetNext(), 0);
2470 Blending := (GetNext() = '1');
2471 end;
2472 end;
2474 OBJECT_ITEM:
2475 with CopyBuf[i].Item do
2476 begin
2477 ItemType := StrToIntDef(GetNext(), ITEM_MEDKIT_SMALL);
2478 X := StrToIntDef(GetNext(), 0);
2479 Y := StrToIntDef(GetNext(), 0);
2480 pmin.X := Min(X, pmin.X);
2481 pmin.Y := Min(Y, pmin.Y);
2482 OnlyDM := (GetNext() = '1');
2483 Fall := (GetNext() = '1');
2484 end;
2486 OBJECT_MONSTER:
2487 with CopyBuf[i].Monster do
2488 begin
2489 MonsterType := StrToIntDef(GetNext(), MONSTER_DEMON);
2490 X := StrToIntDef(GetNext(), 0);
2491 Y := StrToIntDef(GetNext(), 0);
2492 pmin.X := Min(X, pmin.X);
2493 pmin.Y := Min(Y, pmin.Y);
2495 if GetNext() = '1' then
2496 Direction := D_LEFT
2497 else
2498 Direction := D_RIGHT;
2499 end;
2501 OBJECT_AREA:
2502 with CopyBuf[i].Area do
2503 begin
2504 AreaType := StrToIntDef(GetNext(), AREA_PLAYERPOINT1);
2505 X := StrToIntDef(GetNext(), 0);
2506 Y := StrToIntDef(GetNext(), 0);
2507 pmin.X := Min(X, pmin.X);
2508 pmin.Y := Min(Y, pmin.Y);
2509 if GetNext() = '1' then
2510 Direction := D_LEFT
2511 else
2512 Direction := D_RIGHT;
2513 end;
2515 OBJECT_TRIGGER:
2516 with CopyBuf[i].Trigger do
2517 begin
2518 TriggerType := StrToIntDef(GetNext(), TRIGGER_EXIT);
2519 X := StrToIntDef(GetNext(), 0);
2520 Y := StrToIntDef(GetNext(), 0);
2521 pmin.X := Min(X, pmin.X);
2522 pmin.Y := Min(Y, pmin.Y);
2523 Width := StrToIntDef(GetNext(), 16);
2524 Height := StrToIntDef(GetNext(), 16);
2525 ActivateType := StrToIntDef(GetNext(), 0);
2526 Key := StrToIntDef(GetNext(), 0);
2527 Enabled := (GetNext() = '1');
2528 TexturePanel := StrToIntDef(GetNext(), 0);
2530 for j := 0 to 127 do
2531 Data.Default[j] := StrToIntDef(GetNext(), 0);
2533 case TriggerType of
2534 TRIGGER_TELEPORT:
2535 begin
2536 pmin.X := Min(Data.TargetPoint.X, pmin.X);
2537 pmin.Y := Min(Data.TargetPoint.Y, pmin.Y);
2538 end;
2539 TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF:
2540 begin
2541 pmin.X := Min(Data.tX, pmin.X);
2542 pmin.Y := Min(Data.tY, pmin.Y);
2543 end;
2544 TRIGGER_SPAWNMONSTER:
2545 begin
2546 pmin.X := Min(Data.MonPos.X, pmin.X);
2547 pmin.Y := Min(Data.MonPos.Y, pmin.Y);
2548 end;
2549 TRIGGER_SPAWNITEM:
2550 begin
2551 pmin.X := Min(Data.ItemPos.X, pmin.X);
2552 pmin.Y := Min(Data.ItemPos.Y, pmin.Y);
2553 end;
2554 TRIGGER_SHOT:
2555 begin
2556 pmin.X := Min(Data.ShotPos.X, pmin.X);
2557 pmin.Y := Min(Data.ShotPos.Y, pmin.Y);
2558 end;
2559 end;
2560 end;
2561 end;
2562 end;
2563 end;
2565 //----------------------------------------
2566 //Закончились вспомогательные процедуры
2567 //----------------------------------------
2569 type
2570 TRecentHandler = class
2571 private
2572 FForm: TMainForm;
2573 FPath: String;
2574 public
2575 constructor Create (form: TMainForm; path: String);
2576 procedure Execute (Sender: TObject);
2577 end;
2579 constructor TRecentHandler.Create (form: TMainForm; path: String);
2580 begin
2581 Assert(form <> nil);
2582 FForm := form;
2583 FPath := path;
2584 end;
2586 procedure TRecentHandler.Execute (Sender: TObject);
2587 var fn: AnsiString;
2588 begin
2589 fn := g_ExtractWadName(FPath);
2590 if FileExists(fn) then
2591 OpenMap(fn, g_ExtractFilePathName(FPath))
2592 else
2593 Application.MessageBox('', 'File not available anymore', MB_OK);
2594 // if Application.MessageBox(PChar(_lc[I_MSG_DEL_RECENT_PROMT]), PChar(_lc[I_MSG_DEL_RECENT]), MB_ICONQUESTION or MB_YESNO) = idYes then
2595 // begin
2596 // RecentFiles.Delete(n);
2597 // RefreshRecentMenu();
2598 // end;
2599 end;
2601 procedure TMainForm.RefillRecentMenu (menu: TMenuItem; start: Integer; fmt: AnsiString);
2602 var i: Integer; MI: TMenuItem; cb: TMethod; h: TRecentHandler; s: AnsiString;
2603 begin
2604 Assert(menu <> nil);
2605 Assert(start >= 0);
2606 Assert(start <= menu.Count);
2608 // clear all recent entries from menu
2609 i := start;
2610 while i < menu.Count do
2611 begin
2612 MI := menu.Items[i];
2613 cb := TMethod(MI.OnClick);
2614 if cb.Code = @TRecentHandler.Execute then
2615 begin
2616 // this is recent menu entry
2617 // remove it and free callback handler
2618 h := TRecentHandler(cb.Data);
2619 menu.Delete(i);
2620 MI.Free();
2621 h.Free();
2622 end
2623 else
2624 Inc(i);
2625 end;
2627 // fill with a new ones
2628 for i := 0 to RecentFiles.Count - 1 do
2629 begin
2630 s := RecentFiles[i];
2631 h := TRecentHandler.Create(self, s);
2632 MI := TMenuItem.Create(menu);
2633 MI.Caption := Format(fmt, [i + 1, g_ExtractWadNameNoPath(s), g_ExtractFilePathName(s)]);
2634 MI.OnClick := h.Execute;
2635 menu.Insert(start + i, MI);
2636 end;
2637 end;
2639 procedure TMainForm.RefreshRecentMenu();
2640 var start: Integer;
2641 begin
2642 while RecentFiles.Count > RecentCount do
2643 RecentFiles.Delete(RecentFiles.Count - 1);
2645 if miMacRecentSubMenu.Visible then
2646 begin
2647 // Reconstruct OSX-like recent list
2648 RefillRecentMenu(miMacRecentSubMenu, 0, '%1:s - %2:s');
2649 miMacRecentEnd.Enabled := RecentFiles.Count <> 0;
2650 miMacRecentEnd.Visible := RecentFiles.Count <> 0;
2651 end;
2653 if miWinRecentStart.Visible then
2654 begin
2655 // Reconstruct Windows-like recent list
2656 start := miMenuFile.IndexOf(miWinRecent);
2657 if start < 0 then start := miMenuFile.Count else start := start + 1;
2658 RefillRecentMenu(miMenuFile, start, '%0:d %1:s:%2:s');
2659 miWinRecent.Enabled := False;
2660 miWinRecent.Visible := RecentFiles.Count = 0;
2661 end;
2662 end;
2664 procedure TMainForm.miMacRecentClearClick(Sender: TObject);
2665 begin
2666 RecentFiles.Clear();
2667 RefreshRecentMenu();
2668 end;
2670 procedure TMainForm.aEditorOptionsExecute(Sender: TObject);
2671 begin
2672 OptionsForm.ShowModal();
2673 end;
2675 procedure LoadStdFont(cfgres, texture: string; var FontID: DWORD);
2676 var
2677 cwdt, chgt: Byte;
2678 spc: ShortInt;
2679 ID: DWORD;
2680 cfgdata: Pointer;
2681 cfglen: Integer;
2682 config: TConfig;
2683 begin
2684 ID := 0;
2685 g_ReadResource(GameWad, 'FONTS', cfgres, cfgdata, cfglen);
2686 if cfgdata <> nil then
2687 begin
2688 if not g_CreateTextureWAD('FONT_STD', GameWad + ':FONTS\' + texture) then
2689 e_WriteLog('ERROR ERROR ERROR', MSG_WARNING);
2691 config := TConfig.CreateMem(cfgdata, cfglen);
2692 cwdt := Min(Max(config.ReadInt('FontMap', 'CharWidth', 0), 0), 255);
2693 chgt := Min(Max(config.ReadInt('FontMap', 'CharHeight', 0), 0), 255);
2694 spc := Min(Max(config.ReadInt('FontMap', 'Kerning', 0), -128), 127);
2696 if g_GetTexture('FONT_STD', ID) then
2697 e_TextureFontBuild(ID, FontID, cwdt, chgt, spc - 2);
2699 config.Free();
2700 FreeMem(cfgdata)
2701 end
2702 else
2703 begin
2704 e_WriteLog('Could not load FONT_STD', MSG_WARNING)
2705 end
2706 end;
2708 procedure TMainForm.FormCreate(Sender: TObject);
2709 var
2710 config: TConfig;
2711 i: Integer;
2712 s: String;
2713 begin
2714 Randomize();
2716 {$IFDEF DARWIN}
2717 miApple.Enabled := True;
2718 miApple.Visible := True;
2719 miMacRecentSubMenu.Enabled := True;
2720 miMacRecentSubMenu.Visible := True;
2721 miWinRecentStart.Enabled := False;
2722 miWinRecentStart.Visible := False;
2723 miWinRecent.Enabled := False;
2724 miWinRecent.Visible := False;
2725 miLine2.Enabled := False;
2726 miLine2.Visible := False;
2727 miExit.Enabled := False;
2728 miExit.Visible := False;
2729 miOptions.Enabled := False;
2730 miOptions.Visible := False;
2731 miMenuWindow.Enabled := True;
2732 miMenuWindow.Visible := True;
2733 miAbout.Enabled := False;
2734 miAbout.Visible := False;
2735 {$ELSE}
2736 miApple.Enabled := False;
2737 miApple.Visible := False;
2738 miMacRecentSubMenu.Enabled := False;
2739 miMacRecentSubMenu.Visible := False;
2740 miWinRecentStart.Enabled := True;
2741 miWinRecentStart.Visible := True;
2742 miWinRecent.Enabled := True;
2743 miWinRecent.Visible := True;
2744 miLine2.Enabled := True;
2745 miLine2.Visible := True;
2746 miExit.Enabled := True;
2747 miExit.Visible := True;
2748 miOptions.Enabled := True;
2749 miOptions.Visible := True;
2750 miMenuWindow.Enabled := False;
2751 miMenuWindow.Visible := False;
2752 miAbout.Enabled := True;
2753 miAbout.Visible := True;
2754 {$ENDIF}
2756 miNewMap.ShortCut := ShortCut(VK_N, [ssModifier]);
2757 miOpenMap.ShortCut := ShortCut(VK_O, [ssModifier]);
2758 miSaveMap.ShortCut := ShortCut(VK_S, [ssModifier]);
2759 {$IFDEF DARWIN}
2760 miSaveMapAs.ShortCut := ShortCut(VK_S, [ssModifier, ssShift]);
2761 miReopenMap.ShortCut := ShortCut(VK_F5, [ssModifier]);
2762 {$ENDIF}
2763 miUndo.ShortCut := ShortCut(VK_Z, [ssModifier]);
2764 miCopy.ShortCut := ShortCut(VK_C, [ssModifier]);
2765 miCut.ShortCut := ShortCut(VK_X, [ssModifier]);
2766 miPaste.ShortCut := ShortCut(VK_V, [ssModifier]);
2767 miSelectAll.ShortCut := ShortCut(VK_A, [ssModifier]);
2768 miToFore.ShortCut := ShortCut(VK_LCL_CLOSE_BRACKET, [ssModifier]);
2769 miToBack.ShortCut := ShortCut(VK_LCL_OPEN_BRACKET, [ssModifier]);
2770 {$IFDEF DARWIN}
2771 miMapOptions.Shortcut := ShortCut(VK_P, [ssModifier, ssAlt]);
2772 selectall1.Shortcut := ShortCut(VK_A, [ssModifier, ssAlt]);
2773 {$ENDIF}
2775 e_WriteLog('Doom 2D: Forever Editor version ' + EDITOR_VERSION, MSG_NOTIFY);
2776 e_WriteLog('Build date: ' + EDITOR_BUILDDATE + ' ' + EDITOR_BUILDTIME, MSG_NOTIFY);
2777 e_WriteLog('Build hash: ' + g_GetBuildHash(), MSG_NOTIFY);
2778 e_WriteLog('Build by: ' + g_GetBuilderName(), MSG_NOTIFY);
2780 slInvalidTextures := TStringList.Create;
2782 ShowLayer(LAYER_BACK, True);
2783 ShowLayer(LAYER_WALLS, True);
2784 ShowLayer(LAYER_FOREGROUND, True);
2785 ShowLayer(LAYER_STEPS, True);
2786 ShowLayer(LAYER_WATER, True);
2787 ShowLayer(LAYER_ITEMS, True);
2788 ShowLayer(LAYER_MONSTERS, True);
2789 ShowLayer(LAYER_AREAS, True);
2790 ShowLayer(LAYER_TRIGGERS, True);
2792 ClearMap();
2794 FormCaption := MainForm.Caption;
2795 OpenedMap := '';
2796 OpenedWAD := '';
2798 config := TConfig.CreateFile(CfgFileName);
2800 if config.ReadInt('Editor', 'XPos', -1) = -1 then
2801 Position := poDesktopCenter
2802 else begin
2803 Left := config.ReadInt('Editor', 'XPos', Left);
2804 Top := config.ReadInt('Editor', 'YPos', Top);
2805 Width := config.ReadInt('Editor', 'Width', Width);
2806 Height := config.ReadInt('Editor', 'Height', Height);
2807 end;
2808 if config.ReadBool('Editor', 'Maximize', False) then
2809 WindowState := wsMaximized;
2810 ShowMap := config.ReadBool('Editor', 'Minimap', False);
2811 PanelProps.Width := config.ReadInt('Editor', 'PanelProps', PanelProps.ClientWidth);
2812 Splitter1.Left := PanelProps.Left;
2813 PanelObjs.Height := config.ReadInt('Editor', 'PanelObjs', PanelObjs.ClientHeight);
2814 Splitter2.Top := PanelObjs.Top;
2815 StatusBar.Top := PanelObjs.BoundsRect.Bottom;
2816 DotEnable := config.ReadBool('Editor', 'DotEnable', True);
2817 DotColor := config.ReadInt('Editor', 'DotColor', $FFFFFF);
2818 DotStepOne := config.ReadInt('Editor', 'DotStepOne', 16);
2819 DotStepTwo := config.ReadInt('Editor', 'DotStepTwo', 8);
2820 DotStep := config.ReadInt('Editor', 'DotStep', DotStepOne);
2821 DrawTexturePanel := config.ReadBool('Editor', 'DrawTexturePanel', True);
2822 DrawPanelSize := config.ReadBool('Editor', 'DrawPanelSize', True);
2823 BackColor := config.ReadInt('Editor', 'BackColor', $7F6040);
2824 PreviewColor := config.ReadInt('Editor', 'PreviewColor', $00FF00);
2825 UseCheckerboard := config.ReadBool('Editor', 'UseCheckerboard', True);
2826 gColorEdge := config.ReadInt('Editor', 'EdgeColor', COLOR_EDGE);
2827 gAlphaEdge := config.ReadInt('Editor', 'EdgeAlpha', ALPHA_EDGE);
2828 if gAlphaEdge = 255 then
2829 gAlphaEdge := ALPHA_EDGE;
2830 drEdge[0] := GetRValue(gColorEdge);
2831 drEdge[1] := GetGValue(gColorEdge);
2832 drEdge[2] := GetBValue(gColorEdge);
2833 if not config.ReadBool('Editor', 'EdgeShow', True) then
2834 drEdge[3] := 255
2835 else
2836 drEdge[3] := gAlphaEdge;
2837 gAlphaTriggerLine := config.ReadInt('Editor', 'LineAlpha', ALPHA_LINE);
2838 if gAlphaTriggerLine = 255 then
2839 gAlphaTriggerLine := ALPHA_LINE;
2840 gAlphaTriggerArea := config.ReadInt('Editor', 'TriggerAlpha', ALPHA_AREA);
2841 if gAlphaTriggerArea = 255 then
2842 gAlphaTriggerArea := ALPHA_AREA;
2843 gAlphaMonsterRect := config.ReadInt('Editor', 'MonsterRectAlpha', 0);
2844 gAlphaAreaRect := config.ReadInt('Editor', 'AreaRectAlpha', 0);
2845 if config.ReadInt('Editor', 'Scale', 0) = 1 then
2846 Scale := 2
2847 else
2848 Scale := 1;
2849 if config.ReadInt('Editor', 'DotSize', 0) = 1 then
2850 DotSize := 2
2851 else
2852 DotSize := 1;
2853 OpenDialog.InitialDir := config.ReadStr('Editor', 'LastOpenDir', MapsDir);
2854 SaveDialog.InitialDir := config.ReadStr('Editor', 'LastSaveDir', MapsDir);
2856 s := config.ReadStr('Editor', 'Language', '');
2857 gLanguage := s;
2859 Compress := config.ReadBool('Editor', 'Compress', True);
2860 Backup := config.ReadBool('Editor', 'Backup', True);
2862 TestGameMode := config.ReadStr('TestRun', 'GameMode', 'DM');
2863 TestLimTime := config.ReadStr('TestRun', 'LimTime', '0');
2864 TestLimScore := config.ReadStr('TestRun', 'LimScore', '0');
2865 TestOptionsTwoPlayers := config.ReadBool('TestRun', 'TwoPlayers', False);
2866 TestOptionsTeamDamage := config.ReadBool('TestRun', 'TeamDamage', False);
2867 TestOptionsAllowExit := config.ReadBool('TestRun', 'AllowExit', True);
2868 TestOptionsWeaponStay := config.ReadBool('TestRun', 'WeaponStay', False);
2869 TestOptionsMonstersDM := config.ReadBool('TestRun', 'MonstersDM', False);
2870 TestMapOnce := config.ReadBool('TestRun', 'MapOnce', False);
2871 {$IF DEFINED(DARWIN)}
2872 TestD2dExe := config.ReadStr('TestRun', 'ExeDrawin', GameExeFile);
2873 {$ELSEIF DEFINED(WINDOWS)}
2874 TestD2dExe := config.ReadStr('TestRun', 'ExeWindows', GameExeFile);
2875 {$ELSE}
2876 TestD2dExe := config.ReadStr('TestRun', 'ExeUnix', GameExeFile);
2877 {$ENDIF}
2878 TestD2DArgs := config.ReadStr('TestRun', 'Args', '');
2880 RecentCount := config.ReadInt('Editor', 'RecentCount', 5);
2881 if RecentCount > 10 then
2882 RecentCount := 10;
2883 if RecentCount < 2 then
2884 RecentCount := 2;
2886 RecentFiles := TStringList.Create();
2887 for i := 0 to RecentCount-1 do
2888 begin
2889 {$IFDEF WINDOWS}
2890 s := config.ReadStr('RecentFilesWin', IntToStr(i), '');
2891 {$ELSE}
2892 s := config.ReadStr('RecentFilesUnix', IntToStr(i), '');
2893 {$ENDIF}
2894 if s <> '' then
2895 RecentFiles.Add(s);
2896 end;
2897 RefreshRecentMenu();
2899 config.Free();
2901 tbShowMap.Down := ShowMap;
2902 tbGridOn.Down := DotEnable;
2903 pcObjects.ActivePageIndex := 0;
2904 Application.Title := _lc[I_EDITOR_TITLE];
2906 Application.OnIdle := OnIdle;
2907 end;
2909 procedure PrintBlack(X, Y: Integer; Text: string; FontID: DWORD);
2910 begin
2911 // NOTE: all the font printing routines assume CP1251
2912 e_TextureFontPrintEx(X, Y, Text, FontID, 0, 0, 0, 1.0);
2913 end;
2915 procedure TMainForm.Draw();
2916 var
2917 x, y: Integer;
2918 a, b: Integer;
2919 ID, PID: DWORD;
2920 Width, Height: Word;
2921 Rect: TRectWH;
2922 ObjCount: Word;
2923 aX, aY, aX2, aY2, XX, ScaleSz: Integer;
2924 begin
2925 ID := 0;
2926 PID := 0;
2927 Width := 0;
2928 Height := 0;
2930 e_BeginRender();
2932 e_Clear(GL_COLOR_BUFFER_BIT,
2933 GetRValue(BackColor)/255,
2934 GetGValue(BackColor)/255,
2935 GetBValue(BackColor)/255);
2937 DrawMap();
2939 ObjCount := SelectedObjectCount();
2941 // Обводим выделенные объекты красной рамкой:
2942 if ObjCount > 0 then
2943 begin
2944 for a := 0 to High(SelectedObjects) do
2945 if SelectedObjects[a].Live then
2946 begin
2947 Rect := ObjectGetRect(SelectedObjects[a].ObjectType, SelectedObjects[a].ID);
2949 with Rect do
2950 begin
2951 e_DrawQuad(X+MapOffset.X, Y+MapOffset.Y,
2952 X+MapOffset.X+Width-1, Y+MapOffset.Y+Height-1,
2953 255, 0, 0);
2955 // Рисуем точки изменения размеров:
2956 if (ObjCount = 1) and
2957 (SelectedObjects[GetFirstSelected].ObjectType in [OBJECT_PANEL, OBJECT_TRIGGER]) then
2958 begin
2959 e_DrawPoint(5, X+MapOffset.X, Y+MapOffset.Y+(Height div 2), 255, 255, 255);
2960 e_DrawPoint(5, X+MapOffset.X+Width-1, Y+MapOffset.Y+(Height div 2), 255, 255, 255);
2961 e_DrawPoint(5, X+MapOffset.X+(Width div 2), Y+MapOffset.Y, 255, 255, 255);
2962 e_DrawPoint(5, X+MapOffset.X+(Width div 2), Y+MapOffset.Y+Height-1, 255, 255, 255);
2964 e_DrawPoint(3, X+MapOffset.X, Y+MapOffset.Y+(Height div 2), 255, 0, 0);
2965 e_DrawPoint(3, X+MapOffset.X+Width-1, Y+MapOffset.Y+(Height div 2), 255, 0, 0);
2966 e_DrawPoint(3, X+MapOffset.X+(Width div 2), Y+MapOffset.Y, 255, 0, 0);
2967 e_DrawPoint(3, X+MapOffset.X+(Width div 2), Y+MapOffset.Y+Height-1, 255, 0, 0);
2968 end;
2969 end;
2970 end;
2971 end;
2973 // Рисуем сетку:
2974 if DotEnable and (PreviewMode = 0) then
2975 begin
2976 if DotSize = 2 then
2977 a := -1
2978 else
2979 a := 0;
2981 x := MapOffset.X mod DotStep;
2982 y := MapOffset.Y mod DotStep;
2984 while x < RenderPanel.Width do
2985 begin
2986 while y < RenderPanel.Height do
2987 begin
2988 e_DrawPoint(DotSize, x + a, y + a,
2989 GetRValue(DotColor),
2990 GetGValue(DotColor),
2991 GetBValue(DotColor));
2992 y += DotStep;
2993 end;
2994 x += DotStep;
2995 y := MapOffset.Y mod DotStep;
2996 end;
2997 end;
2999 // Превью текстуры:
3000 if (lbTextureList.ItemIndex <> -1) and (cbPreview.Checked) and
3001 (not IsSpecialTextureSel()) and (PreviewMode = 0) then
3002 begin
3003 if not g_GetTexture(SelectedTexture(), ID) then
3004 g_GetTexture('NOTEXTURE', ID);
3005 g_GetTextureSizeByID(ID, Width, Height);
3006 if UseCheckerboard then
3007 begin
3008 if g_GetTexture('PREVIEW', PID) then
3009 e_DrawFill(PID, RenderPanel.Width-Width, RenderPanel.Height-Height, Width div 16 + 1, Height div 16 + 1, 0, True, False);
3010 end else
3011 e_DrawFillQuad(RenderPanel.Width-Width-2, RenderPanel.Height-Height-2,
3012 RenderPanel.Width-1, RenderPanel.Height-1,
3013 GetRValue(PreviewColor), GetGValue(PreviewColor), GetBValue(PreviewColor), 0);
3014 e_Draw(ID, RenderPanel.Width-Width, RenderPanel.Height-Height, 0, True, False);
3015 end;
3017 // Подсказка при выборе точки Телепорта:
3018 if SelectFlag = SELECTFLAG_TELEPORT then
3019 begin
3020 with gTriggers[SelectedObjects[GetFirstSelected()].ID] do
3021 if Data.d2d_teleport then
3022 e_DrawLine(2, MousePos.X-16, MousePos.Y-1,
3023 MousePos.X+16, MousePos.Y-1,
3024 0, 0, 255)
3025 else
3026 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+AreaSize[AREA_DMPOINT].Width-1,
3027 MousePos.Y+AreaSize[AREA_DMPOINT].Height-1, 255, 255, 255);
3029 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 192, 192, 192, 127);
3030 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 255, 255, 255);
3031 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_TELEPORT], gEditorFont);
3032 end;
3034 // Подсказка при выборе точки появления:
3035 if SelectFlag = SELECTFLAG_SPAWNPOINT then
3036 begin
3037 e_DrawLine(2, MousePos.X-16, MousePos.Y-1,
3038 MousePos.X+16, MousePos.Y-1,
3039 0, 0, 255);
3040 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 192, 192, 192, 127);
3041 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 255, 255, 255);
3042 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_SPAWN], gEditorFont);
3043 end;
3045 // Подсказка при выборе панели двери:
3046 if SelectFlag = SELECTFLAG_DOOR then
3047 begin
3048 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 192, 192, 192, 127);
3049 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 255, 255, 255);
3050 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_PANEL_DOOR], gEditorFont);
3051 end;
3053 // Подсказка при выборе панели с текстурой:
3054 if SelectFlag = SELECTFLAG_TEXTURE then
3055 begin
3056 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+196, MousePos.Y+18, 192, 192, 192, 127);
3057 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+196, MousePos.Y+18, 255, 255, 255);
3058 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_PANEL_TEXTURE], gEditorFont);
3059 end;
3061 // Подсказка при выборе панели индикации выстрела:
3062 if SelectFlag = SELECTFLAG_SHOTPANEL then
3063 begin
3064 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+316, MousePos.Y+18, 192, 192, 192, 127);
3065 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+316, MousePos.Y+18, 255, 255, 255);
3066 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_PANEL_SHOT], gEditorFont);
3067 end;
3069 // Подсказка при выборе панели лифта:
3070 if SelectFlag = SELECTFLAG_LIFT then
3071 begin
3072 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 192, 192, 192, 127);
3073 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 255, 255, 255);
3074 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_PANEL_LIFT], gEditorFont);
3075 end;
3077 // Подсказка при выборе монстра:
3078 if SelectFlag = SELECTFLAG_MONSTER then
3079 begin
3080 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+120, MousePos.Y+18, 192, 192, 192, 127);
3081 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+120, MousePos.Y+18, 255, 255, 255);
3082 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_MONSTER], gEditorFont);
3083 end;
3085 // Подсказка при выборе области воздействия:
3086 if DrawPressRect then
3087 begin
3088 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+204, MousePos.Y+18, 192, 192, 192, 127);
3089 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+204, MousePos.Y+18, 255, 255, 255);
3090 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_EXT_AREA], gEditorFont);
3091 end;
3093 // Рисуем текстуры, если чертим панель:
3094 if (MouseAction = MOUSEACTION_DRAWPANEL) and (DrawTexturePanel) and
3095 (lbTextureList.ItemIndex <> -1) and (DrawRect <> nil) and
3096 (lbPanelType.ItemIndex in [0..8]) and not IsSpecialTextureSel() then
3097 begin
3098 if not g_GetTexture(SelectedTexture(), ID) then
3099 g_GetTexture('NOTEXTURE', ID);
3100 g_GetTextureSizeByID(ID, Width, Height);
3101 with DrawRect^ do
3102 if (Abs(Right-Left) >= Width) and (Abs(Bottom-Top) >= Height) then
3103 e_DrawFill(ID, Min(Left, Right), Min(Top, Bottom), Abs(Right-Left) div Width,
3104 Abs(Bottom-Top) div Height, 64, True, False);
3105 end;
3107 // Прямоугольник выделения:
3108 if DrawRect <> nil then
3109 with DrawRect^ do
3110 e_DrawQuad(Left, Top, Right-1, Bottom-1, 255, 255, 255);
3112 // Чертим мышью панель/триггер или меняем мышью их размер:
3113 if (((MouseAction in [MOUSEACTION_DRAWPANEL, MOUSEACTION_DRAWTRIGGER]) and
3114 not(ssCtrl in GetKeyShiftState())) or (MouseAction = MOUSEACTION_RESIZE)) and
3115 (DrawPanelSize) then
3116 begin
3117 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+88, MousePos.Y+33, 192, 192, 192, 127);
3118 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+88, MousePos.Y+33, 255, 255, 255);
3120 if MouseAction in [MOUSEACTION_DRAWPANEL, MOUSEACTION_DRAWTRIGGER] then
3121 begin // Чертим новый
3122 PrintBlack(MousePos.X+2, MousePos.Y+2, Format(_glc[I_HINT_WIDTH],
3123 [Abs(MousePos.X-MouseLDownPos.X)]), gEditorFont);
3124 PrintBlack(MousePos.X+2, MousePos.Y+16, Format(_glc[I_HINT_HEIGHT],
3125 [Abs(MousePos.Y-MouseLDownPos.Y)]), gEditorFont);
3126 end
3127 else // Растягиваем существующий
3128 if SelectedObjects[GetFirstSelected].ObjectType in [OBJECT_PANEL, OBJECT_TRIGGER] then
3129 begin
3130 if SelectedObjects[GetFirstSelected].ObjectType = OBJECT_PANEL then
3131 begin
3132 Width := gPanels[SelectedObjects[GetFirstSelected].ID].Width;
3133 Height := gPanels[SelectedObjects[GetFirstSelected].ID].Height;
3134 end
3135 else
3136 begin
3137 Width := gTriggers[SelectedObjects[GetFirstSelected].ID].Width;
3138 Height := gTriggers[SelectedObjects[GetFirstSelected].ID].Height;
3139 end;
3141 PrintBlack(MousePos.X+2, MousePos.Y+2, Format(_glc[I_HINT_WIDTH], [Width]),
3142 gEditorFont);
3143 PrintBlack(MousePos.X+2, MousePos.Y+16, Format(_glc[I_HINT_HEIGHT], [Height]),
3144 gEditorFont);
3145 end;
3146 end;
3148 // Ближайшая к курсору мыши точка на сетке:
3149 e_DrawPoint(3, MousePos.X, MousePos.Y, 0, 0, 255);
3151 // Мини-карта:
3152 if ShowMap then
3153 begin
3154 // Сколько пикселов карты в 1 пикселе мини-карты:
3155 ScaleSz := 16 div Scale;
3156 // Размеры мини-карты:
3157 aX := max(gMapInfo.Width div ScaleSz, 1);
3158 aY := max(gMapInfo.Height div ScaleSz, 1);
3159 // X-координата на RenderPanel нулевой x-координаты карты:
3160 XX := RenderPanel.Width - aX - 1;
3161 // Рамка карты:
3162 e_DrawFillQuad(XX-1, 0, RenderPanel.Width-1, aY+1, 0, 0, 0, 0);
3163 e_DrawQuad(XX-1, 0, RenderPanel.Width-1, aY+1, 197, 197, 197);
3165 if gPanels <> nil then
3166 begin
3167 // Рисуем панели:
3168 for a := 0 to High(gPanels) do
3169 with gPanels[a] do
3170 if PanelType <> 0 then
3171 begin
3172 // Левый верхний угол:
3173 aX := XX + (X div ScaleSz);
3174 aY := 1 + (Y div ScaleSz);
3175 // Размеры:
3176 aX2 := max(Width div ScaleSz, 1);
3177 aY2 := max(Height div ScaleSz, 1);
3178 // Правый нижний угол:
3179 aX2 := aX + aX2 - 1;
3180 aY2 := aY + aY2 - 1;
3182 case PanelType of
3183 PANEL_WALL: e_DrawFillQuad(aX, aY, aX2, aY2, 208, 208, 208, 0);
3184 PANEL_WATER: e_DrawFillQuad(aX, aY, aX2, aY2, 0, 0, 192, 0);
3185 PANEL_ACID1: e_DrawFillQuad(aX, aY, aX2, aY2, 0, 176, 0, 0);
3186 PANEL_ACID2: e_DrawFillQuad(aX, aY, aX2, aY2, 176, 0, 0, 0);
3187 PANEL_STEP: e_DrawFillQuad(aX, aY, aX2, aY2, 128, 128, 128, 0);
3188 PANEL_LIFTUP: e_DrawFillQuad(aX, aY, aX2, aY2, 116, 72, 36, 0);
3189 PANEL_LIFTDOWN: e_DrawFillQuad(aX, aY, aX2, aY2, 116, 124, 96, 0);
3190 PANEL_LIFTLEFT: e_DrawFillQuad(aX, aY, aX2, aY2, 200, 80, 4, 0);
3191 PANEL_LIFTRIGHT: e_DrawFillQuad(aX, aY, aX2, aY2, 252, 140, 56, 0);
3192 PANEL_OPENDOOR: e_DrawFillQuad(aX, aY, aX2, aY2, 100, 220, 92, 0);
3193 PANEL_CLOSEDOOR: e_DrawFillQuad(aX, aY, aX2, aY2, 212, 184, 64, 0);
3194 PANEL_BLOCKMON: e_DrawFillQuad(aX, aY, aX2, aY2, 192, 0, 192, 0);
3195 end;
3196 end;
3198 // Рисуем красным выделенные панели:
3199 if SelectedObjects <> nil then
3200 for b := 0 to High(SelectedObjects) do
3201 with SelectedObjects[b] do
3202 if Live and (ObjectType = OBJECT_PANEL) then
3203 with gPanels[SelectedObjects[b].ID] do
3204 if PanelType and not(PANEL_BACK or PANEL_FORE) <> 0 then
3205 begin
3206 // Левый верхний угол:
3207 aX := XX + (X div ScaleSz);
3208 aY := 1 + (Y div ScaleSz);
3209 // Размеры:
3210 aX2 := max(Width div ScaleSz, 1);
3211 aY2 := max(Height div ScaleSz, 1);
3212 // Правый нижний угол:
3213 aX2 := aX + aX2 - 1;
3214 aY2 := aY + aY2 - 1;
3216 e_DrawFillQuad(aX, aY, aX2, aY2, 255, 0, 0, 0)
3217 end;
3218 end;
3220 if (gMapInfo.Width > RenderPanel.Width) or
3221 (gMapInfo.Height > RenderPanel.Height) then
3222 begin
3223 // Окно, показывающее текущее положение экрана на карте:
3224 // Размеры окна:
3225 x := max(min(RenderPanel.Width, gMapInfo.Width) div ScaleSz, 1);
3226 y := max(min(RenderPanel.Height, gMapInfo.Height) div ScaleSz, 1);
3227 // Левый верхний угол:
3228 aX := XX + ((-MapOffset.X) div ScaleSz);
3229 aY := 1 + ((-MapOffset.Y) div ScaleSz);
3230 // Правый нижний угол:
3231 aX2 := aX + x - 1;
3232 aY2 := aY + y - 1;
3234 e_DrawFillQuad(aX, aY, aX2, aY2, 127, 192, 127, 127, B_BLEND);
3235 e_DrawQuad(aX, aY, aX2, aY2, 255, 0, 0);
3236 end;
3237 end; // Мини-карта
3239 e_EndRender();
3240 RenderPanel.SwapBuffers();
3241 end;
3243 procedure TMainForm.FormResize(Sender: TObject);
3244 begin
3245 e_SetViewPort(0, 0, RenderPanel.Width, RenderPanel.Height);
3247 sbHorizontal.Min := Min(gMapInfo.Width - RenderPanel.Width, -RenderPanel.Width div 2);
3248 sbHorizontal.Max := Max(0, gMapInfo.Width - RenderPanel.Width div 2);
3249 sbVertical.Min := Min(gMapInfo.Height - RenderPanel.Height, -RenderPanel.Height div 2);
3250 sbVertical.Max := Max(0, gMapInfo.Height - RenderPanel.Height div 2);
3252 MapOffset.X := -sbHorizontal.Position;
3253 MapOffset.Y := -sbVertical.Position;
3254 end;
3256 procedure TMainForm.FormWindowStateChange(Sender: TObject);
3257 {$IFDEF DARWIN}
3258 var e: Boolean;
3259 {$ENDIF}
3260 begin
3261 {$IFDEF DARWIN}
3262 // deactivate all menus when main window minimized
3263 e := self.WindowState <> wsMinimized;
3264 miMenuFile.Enabled := e;
3265 miMenuEdit.Enabled := e;
3266 miMenuView.Enabled := e;
3267 miMenuService.Enabled := e;
3268 miMenuWindow.Enabled := e;
3269 miMenuHelp.Enabled := e;
3270 miMenuHidden.Enabled := e;
3271 {$ENDIF}
3272 end;
3274 procedure SelectNextObject(X, Y: Integer; ObjectType: Byte; ID: DWORD);
3275 var
3276 j, j_max: Integer;
3277 res: Boolean;
3278 begin
3279 j_max := 0; // shut up compiler
3280 case ObjectType of
3281 OBJECT_PANEL:
3282 begin
3283 res := (gPanels <> nil) and
3284 PanelInShownLayer(gPanels[ID].PanelType) and
3285 g_CollidePoint(X, Y, gPanels[ID].X, gPanels[ID].Y,
3286 gPanels[ID].Width,
3287 gPanels[ID].Height);
3288 j_max := Length(gPanels) - 1;
3289 end;
3291 OBJECT_ITEM:
3292 begin
3293 res := (gItems <> nil) and
3294 LayerEnabled[LAYER_ITEMS] and
3295 g_CollidePoint(X, Y, gItems[ID].X, gItems[ID].Y,
3296 ItemSize[gItems[ID].ItemType][0],
3297 ItemSize[gItems[ID].ItemType][1]);
3298 j_max := Length(gItems) - 1;
3299 end;
3301 OBJECT_MONSTER:
3302 begin
3303 res := (gMonsters <> nil) and
3304 LayerEnabled[LAYER_MONSTERS] and
3305 g_CollidePoint(X, Y, gMonsters[ID].X, gMonsters[ID].Y,
3306 MonsterSize[gMonsters[ID].MonsterType].Width,
3307 MonsterSize[gMonsters[ID].MonsterType].Height);
3308 j_max := Length(gMonsters) - 1;
3309 end;
3311 OBJECT_AREA:
3312 begin
3313 res := (gAreas <> nil) and
3314 LayerEnabled[LAYER_AREAS] and
3315 g_CollidePoint(X, Y, gAreas[ID].X, gAreas[ID].Y,
3316 AreaSize[gAreas[ID].AreaType].Width,
3317 AreaSize[gAreas[ID].AreaType].Height);
3318 j_max := Length(gAreas) - 1;
3319 end;
3321 OBJECT_TRIGGER:
3322 begin
3323 res := (gTriggers <> nil) and
3324 LayerEnabled[LAYER_TRIGGERS] and
3325 g_CollidePoint(X, Y, gTriggers[ID].X, gTriggers[ID].Y,
3326 gTriggers[ID].Width,
3327 gTriggers[ID].Height);
3328 j_max := Length(gTriggers) - 1;
3329 end;
3331 else
3332 res := False;
3333 end;
3335 if not res then
3336 Exit;
3338 // Перебор ID: от ID-1 до 0; потом от High до ID+1:
3339 j := ID;
3341 while True do
3342 begin
3343 Dec(j);
3345 if j < 0 then
3346 j := j_max;
3347 if j = Integer(ID) then
3348 Break;
3350 case ObjectType of
3351 OBJECT_PANEL:
3352 res := PanelInShownLayer(gPanels[j].PanelType) and
3353 g_CollidePoint(X, Y, gPanels[j].X, gPanels[j].Y,
3354 gPanels[j].Width,
3355 gPanels[j].Height);
3356 OBJECT_ITEM:
3357 res := (gItems[j].ItemType <> ITEM_NONE) and
3358 g_CollidePoint(X, Y, gItems[j].X, gItems[j].Y,
3359 ItemSize[gItems[j].ItemType][0],
3360 ItemSize[gItems[j].ItemType][1]);
3361 OBJECT_MONSTER:
3362 res := (gMonsters[j].MonsterType <> MONSTER_NONE) and
3363 g_CollidePoint(X, Y, gMonsters[j].X, gMonsters[j].Y,
3364 MonsterSize[gMonsters[j].MonsterType].Width,
3365 MonsterSize[gMonsters[j].MonsterType].Height);
3366 OBJECT_AREA:
3367 res := (gAreas[j].AreaType <> AREA_NONE) and
3368 g_CollidePoint(X, Y, gAreas[j].X, gAreas[j].Y,
3369 AreaSize[gAreas[j].AreaType].Width,
3370 AreaSize[gAreas[j].AreaType].Height);
3371 OBJECT_TRIGGER:
3372 res := (gTriggers[j].TriggerType <> TRIGGER_NONE) and
3373 g_CollidePoint(X, Y, gTriggers[j].X, gTriggers[j].Y,
3374 gTriggers[j].Width,
3375 gTriggers[j].Height);
3376 else
3377 res := False;
3378 end;
3380 if res then
3381 begin
3382 SetLength(SelectedObjects, 1);
3384 SelectedObjects[0].ObjectType := ObjectType;
3385 SelectedObjects[0].ID := j;
3386 SelectedObjects[0].Live := True;
3388 FillProperty();
3389 Break;
3390 end;
3391 end;
3392 end;
3394 procedure TMainForm.RenderPanelMouseDown(Sender: TObject;
3395 Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
3396 var
3397 i: Integer;
3398 Rect: TRectWH;
3399 c1, c2, c3, c4: Boolean;
3400 item: TItem;
3401 area: TArea;
3402 monster: TMonster;
3403 IDArray: DWArray;
3404 begin
3405 MainForm.ActiveControl := RenderPanel;
3406 RenderPanel.SetFocus();
3408 RenderPanelMouseMove(RenderPanel, Shift, X, Y);
3410 if Button = mbLeft then // Left Mouse Button
3411 begin
3412 // Двигаем карту с помощью мыши и мини-карты:
3413 if ShowMap and
3414 g_CollidePoint(X, Y,
3415 RenderPanel.Width-max(gMapInfo.Width div (16 div Scale), 1)-1,
3416 1,
3417 max(gMapInfo.Width div (16 div Scale), 1),
3418 max(gMapInfo.Height div (16 div Scale), 1) ) then
3419 begin
3420 MoveMap(X, Y);
3421 MouseAction := MOUSEACTION_MOVEMAP;
3422 end
3423 else // Ставим предмет/монстра/область:
3424 if (pcObjects.ActivePageIndex in [1, 2, 3]) and
3425 (not (ssShift in Shift)) then
3426 begin
3427 case pcObjects.ActivePageIndex of
3428 1:
3429 if lbItemList.ItemIndex = -1 then
3430 ErrorMessageBox(_lc[I_MSG_CHOOSE_ITEM])
3431 else
3432 begin
3433 item.ItemType := lbItemList.ItemIndex + ITEM_MEDKIT_SMALL;
3434 if item.ItemType >= ITEM_WEAPON_KASTET then
3435 item.ItemType := item.ItemType + 2;
3436 item.X := MousePos.X-MapOffset.X;
3437 item.Y := MousePos.Y-MapOffset.Y;
3439 if not (ssCtrl in Shift) then
3440 begin
3441 item.X := item.X - (ItemSize[item.ItemType][0] div 2);
3442 item.Y := item.Y - ItemSize[item.ItemType][1];
3443 end;
3445 item.OnlyDM := cbOnlyDM.Checked;
3446 item.Fall := cbFall.Checked;
3447 Undo_Add(OBJECT_ITEM, AddItem(item));
3448 end;
3449 2:
3450 if lbMonsterList.ItemIndex = -1 then
3451 ErrorMessageBox(_lc[I_MSG_CHOOSE_MONSTER])
3452 else
3453 begin
3454 monster.MonsterType := lbMonsterList.ItemIndex + MONSTER_DEMON;
3455 monster.X := MousePos.X-MapOffset.X;
3456 monster.Y := MousePos.Y-MapOffset.Y;
3458 if not (ssCtrl in Shift) then
3459 begin
3460 monster.X := monster.X - (MonsterSize[monster.MonsterType].Width div 2);
3461 monster.Y := monster.Y - MonsterSize[monster.MonsterType].Height;
3462 end;
3464 if rbMonsterLeft.Checked then
3465 monster.Direction := D_LEFT
3466 else
3467 monster.Direction := D_RIGHT;
3468 Undo_Add(OBJECT_MONSTER, AddMonster(monster));
3469 end;
3470 3:
3471 if lbAreasList.ItemIndex = -1 then
3472 ErrorMessageBox(_lc[I_MSG_CHOOSE_AREA])
3473 else
3474 if (lbAreasList.ItemIndex + 1) <> AREA_DOMFLAG then
3475 begin
3476 area.AreaType := lbAreasList.ItemIndex + AREA_PLAYERPOINT1;
3477 area.X := MousePos.X-MapOffset.X;
3478 area.Y := MousePos.Y-MapOffset.Y;
3480 if not (ssCtrl in Shift) then
3481 begin
3482 area.X := area.X - (AreaSize[area.AreaType].Width div 2);
3483 area.Y := area.Y - AreaSize[area.AreaType].Height;
3484 end;
3486 if rbAreaLeft.Checked then
3487 area.Direction := D_LEFT
3488 else
3489 area.Direction := D_RIGHT;
3490 Undo_Add(OBJECT_AREA, AddArea(area));
3491 end;
3492 end;
3493 end
3494 else
3495 begin
3496 i := GetFirstSelected();
3498 // Выбираем объект под текущим:
3499 if (SelectedObjects <> nil) and
3500 (ssShift in Shift) and (i >= 0) and
3501 (SelectedObjects[i].Live) then
3502 begin
3503 if SelectedObjectCount() = 1 then
3504 SelectNextObject(X-MapOffset.X, Y-MapOffset.Y,
3505 SelectedObjects[i].ObjectType,
3506 SelectedObjects[i].ID);
3507 end
3508 else
3509 begin
3510 // Рисуем область триггера "Расширитель":
3511 if DrawPressRect and (i >= 0) and
3512 (SelectedObjects[i].ObjectType = OBJECT_TRIGGER) and
3513 (gTriggers[SelectedObjects[i].ID].TriggerType in
3514 [TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF]) then
3515 MouseAction := MOUSEACTION_DRAWPRESS
3516 else // Рисуем панель:
3517 if pcObjects.ActivePageIndex = 0 then
3518 begin
3519 if (lbPanelType.ItemIndex >= 0) then
3520 MouseAction := MOUSEACTION_DRAWPANEL
3521 end
3522 else // Рисуем триггер:
3523 if (lbTriggersList.ItemIndex >= 0) then
3524 begin
3525 MouseAction := MOUSEACTION_DRAWTRIGGER;
3526 end;
3527 end;
3528 end;
3529 end; // if Button = mbLeft
3531 if Button = mbRight then // Right Mouse Button
3532 begin
3533 // Клик по мини-карте:
3534 if ShowMap and
3535 g_CollidePoint(X, Y,
3536 RenderPanel.Width-max(gMapInfo.Width div (16 div Scale), 1)-1,
3537 1,
3538 max(gMapInfo.Width div (16 div Scale), 1),
3539 max(gMapInfo.Height div (16 div Scale), 1) ) then
3540 begin
3541 MouseAction := MOUSEACTION_NOACTION;
3542 end
3543 else // Нужно что-то выбрать мышью:
3544 if SelectFlag <> SELECTFLAG_NONE then
3545 begin
3546 case SelectFlag of
3547 SELECTFLAG_TELEPORT:
3548 // Точку назначения телепортации:
3549 with gTriggers[SelectedObjects[
3550 GetFirstSelected() ].ID].Data.TargetPoint do
3551 begin
3552 X := MousePos.X-MapOffset.X;
3553 Y := MousePos.Y-MapOffset.Y;
3554 end;
3556 SELECTFLAG_SPAWNPOINT:
3557 // Точку создания монстра:
3558 with gTriggers[SelectedObjects[GetFirstSelected()].ID] do
3559 if TriggerType = TRIGGER_SPAWNMONSTER then
3560 begin
3561 Data.MonPos.X := MousePos.X-MapOffset.X;
3562 Data.MonPos.Y := MousePos.Y-MapOffset.Y;
3563 end
3564 else if TriggerType = TRIGGER_SPAWNITEM then
3565 begin // Точка создания предмета:
3566 Data.ItemPos.X := MousePos.X-MapOffset.X;
3567 Data.ItemPos.Y := MousePos.Y-MapOffset.Y;
3568 end
3569 else if TriggerType = TRIGGER_SHOT then
3570 begin // Точка создания выстрела:
3571 Data.ShotPos.X := MousePos.X-MapOffset.X;
3572 Data.ShotPos.Y := MousePos.Y-MapOffset.Y;
3573 end;
3575 SELECTFLAG_DOOR:
3576 // Дверь:
3577 begin
3578 IDArray := ObjectInRect(X-MapOffset.X,
3579 Y-MapOffset.Y,
3580 2, 2, OBJECT_PANEL, True);
3581 if IDArray <> nil then
3582 begin
3583 for i := 0 to High(IDArray) do
3584 if (gPanels[IDArray[i]].PanelType = PANEL_OPENDOOR) or
3585 (gPanels[IDArray[i]].PanelType = PANEL_CLOSEDOOR) then
3586 begin
3587 gTriggers[SelectedObjects[
3588 GetFirstSelected() ].ID].Data.PanelID := IDArray[i];
3589 Break;
3590 end;
3591 end
3592 else
3593 gTriggers[SelectedObjects[
3594 GetFirstSelected() ].ID].Data.PanelID := -1;
3595 end;
3597 SELECTFLAG_TEXTURE:
3598 // Панель с текстурой:
3599 begin
3600 IDArray := ObjectInRect(X-MapOffset.X,
3601 Y-MapOffset.Y,
3602 2, 2, OBJECT_PANEL, True);
3603 if IDArray <> nil then
3604 begin
3605 for i := 0 to High(IDArray) do
3606 if ((gPanels[IDArray[i]].PanelType in
3607 [PANEL_WALL, PANEL_BACK, PANEL_FORE,
3608 PANEL_WATER, PANEL_ACID1, PANEL_ACID2,
3609 PANEL_STEP]) or
3610 (gPanels[IDArray[i]].PanelType = PANEL_OPENDOOR) or
3611 (gPanels[IDArray[i]].PanelType = PANEL_CLOSEDOOR)) and
3612 (gPanels[IDArray[i]].TextureName <> '') then
3613 begin
3614 gTriggers[SelectedObjects[
3615 GetFirstSelected() ].ID].TexturePanel := IDArray[i];
3616 Break;
3617 end;
3618 end
3619 else
3620 gTriggers[SelectedObjects[
3621 GetFirstSelected() ].ID].TexturePanel := -1;
3622 end;
3624 SELECTFLAG_LIFT:
3625 // Лифт:
3626 begin
3627 IDArray := ObjectInRect(X-MapOffset.X,
3628 Y-MapOffset.Y,
3629 2, 2, OBJECT_PANEL, True);
3630 if IDArray <> nil then
3631 begin
3632 for i := 0 to High(IDArray) do
3633 if (gPanels[IDArray[i]].PanelType = PANEL_LIFTUP) or
3634 (gPanels[IDArray[i]].PanelType = PANEL_LIFTDOWN) or
3635 (gPanels[IDArray[i]].PanelType = PANEL_LIFTLEFT) or
3636 (gPanels[IDArray[i]].PanelType = PANEL_LIFTRIGHT) then
3637 begin
3638 gTriggers[SelectedObjects[
3639 GetFirstSelected() ].ID].Data.PanelID := IDArray[i];
3640 Break;
3641 end;
3642 end
3643 else
3644 gTriggers[SelectedObjects[
3645 GetFirstSelected() ].ID].Data.PanelID := -1;
3646 end;
3648 SELECTFLAG_MONSTER:
3649 // Монстра:
3650 begin
3651 IDArray := ObjectInRect(X-MapOffset.X,
3652 Y-MapOffset.Y,
3653 2, 2, OBJECT_MONSTER, False);
3654 if IDArray <> nil then
3655 gTriggers[SelectedObjects[
3656 GetFirstSelected() ].ID].Data.MonsterID := IDArray[0]+1
3657 else
3658 gTriggers[SelectedObjects[
3659 GetFirstSelected() ].ID].Data.MonsterID := 0;
3660 end;
3662 SELECTFLAG_SHOTPANEL:
3663 // Панель индикации выстрела:
3664 begin
3665 if gTriggers[SelectedObjects[
3666 GetFirstSelected() ].ID].TriggerType = TRIGGER_SHOT then
3667 begin
3668 IDArray := ObjectInRect(X-MapOffset.X,
3669 Y-MapOffset.Y,
3670 2, 2, OBJECT_PANEL, True);
3671 if IDArray <> nil then
3672 begin
3673 for i := 0 to High(IDArray) do
3674 if ((gPanels[IDArray[i]].PanelType in
3675 [PANEL_WALL, PANEL_BACK, PANEL_FORE,
3676 PANEL_WATER, PANEL_ACID1, PANEL_ACID2,
3677 PANEL_STEP]) or
3678 (gPanels[IDArray[i]].PanelType = PANEL_OPENDOOR) or
3679 (gPanels[IDArray[i]].PanelType = PANEL_CLOSEDOOR)) and
3680 (gPanels[IDArray[i]].TextureName <> '') then
3681 begin
3682 gTriggers[SelectedObjects[
3683 GetFirstSelected() ].ID].Data.ShotPanelID := IDArray[i];
3684 Break;
3685 end;
3686 end
3687 else
3688 gTriggers[SelectedObjects[
3689 GetFirstSelected() ].ID].Data.ShotPanelID := -1;
3690 end;
3691 end;
3692 end;
3694 SelectFlag := SELECTFLAG_SELECTED;
3695 end
3696 else // if SelectFlag <> SELECTFLAG_NONE...
3697 begin
3698 // Что уже выбрано и не нажат Ctrl:
3699 if (SelectedObjects <> nil) and
3700 (not (ssCtrl in Shift)) then
3701 for i := 0 to High(SelectedObjects) do
3702 with SelectedObjects[i] do
3703 if Live then
3704 begin
3705 if (ObjectType in [OBJECT_PANEL, OBJECT_TRIGGER]) and
3706 (SelectedObjectCount() = 1) then
3707 begin
3708 Rect := ObjectGetRect(ObjectType, ID);
3710 c1 := g_Collide(X-MapOffset.X-1, Y-MapOffset.Y-1, 2, 2,
3711 Rect.X-2, Rect.Y+(Rect.Height div 2)-2, 4, 4);
3712 c2 := g_Collide(X-MapOffset.X-1, Y-MapOffset.Y-1, 2, 2,
3713 Rect.X+Rect.Width-3, Rect.Y+(Rect.Height div 2)-2, 4, 4);
3714 c3 := g_Collide(X-MapOffset.X-1, Y-MapOffset.Y-1, 2, 2,
3715 Rect.X+(Rect.Width div 2)-2, Rect.Y-2, 4, 4);
3716 c4 := g_Collide(X-MapOffset.X-1, Y-MapOffset.Y-1, 2, 2,
3717 Rect.X+(Rect.Width div 2)-2, Rect.Y+Rect.Height-3, 4, 4);
3719 // Меняем размер панели или триггера:
3720 if c1 or c2 or c3 or c4 then
3721 begin
3722 MouseAction := MOUSEACTION_RESIZE;
3723 LastMovePoint := MousePos;
3725 if c1 or c2 then
3726 begin // Шире/уже
3727 ResizeType := RESIZETYPE_HORIZONTAL;
3728 if c1 then
3729 ResizeDirection := RESIZEDIR_LEFT
3730 else
3731 ResizeDirection := RESIZEDIR_RIGHT;
3732 RenderPanel.Cursor := crSizeWE;
3733 end
3734 else
3735 begin // Выше/ниже
3736 ResizeType := RESIZETYPE_VERTICAL;
3737 if c3 then
3738 ResizeDirection := RESIZEDIR_UP
3739 else
3740 ResizeDirection := RESIZEDIR_DOWN;
3741 RenderPanel.Cursor := crSizeNS;
3742 end;
3744 Break;
3745 end;
3746 end;
3748 // Перемещаем панель или триггер:
3749 if ObjectCollide(ObjectType, ID,
3750 X-MapOffset.X-1,
3751 Y-MapOffset.Y-1, 2, 2) then
3752 begin
3753 MouseAction := MOUSEACTION_MOVEOBJ;
3754 LastMovePoint := MousePos;
3756 Break;
3757 end;
3758 end;
3759 end;
3760 end; // if Button = mbRight
3762 if Button = mbMiddle then // Middle Mouse Button
3763 begin
3764 SetCapture(RenderPanel.Handle);
3765 RenderPanel.Cursor := crSize;
3766 end;
3768 MouseMDown := Button = mbMiddle;
3769 if MouseMDown then
3770 MouseMDownPos := Mouse.CursorPos;
3772 MouseRDown := Button = mbRight;
3773 if MouseRDown then
3774 MouseRDownPos := MousePos;
3776 MouseLDown := Button = mbLeft;
3777 if MouseLDown then
3778 MouseLDownPos := MousePos;
3779 end;
3781 procedure TMainForm.RenderPanelMouseUp(Sender: TObject;
3782 Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
3783 var
3784 panel: TPanel;
3785 trigger: TTrigger;
3786 rRect: TRectWH;
3787 rSelectRect: Boolean;
3788 wWidth, wHeight: Word;
3789 TextureID: DWORD;
3791 procedure SelectObjects(ObjectType: Byte);
3792 var
3793 i: Integer;
3794 IDArray: DWArray;
3795 begin
3796 IDArray := ObjectInRect(rRect.X, rRect.Y,
3797 rRect.Width, rRect.Height,
3798 ObjectType, rSelectRect);
3800 if IDArray <> nil then
3801 for i := 0 to High(IDArray) do
3802 SelectObject(ObjectType, IDArray[i], (ssCtrl in Shift) or rSelectRect);
3803 end;
3804 begin
3805 if Button = mbLeft then
3806 MouseLDown := False;
3807 if Button = mbRight then
3808 MouseRDown := False;
3809 if Button = mbMiddle then
3810 MouseMDown := False;
3812 DrawRect := nil;
3813 ResizeType := RESIZETYPE_NONE;
3814 TextureID := 0;
3816 if Button = mbLeft then // Left Mouse Button
3817 begin
3818 if MouseAction <> MOUSEACTION_NONE then
3819 begin // Было действие мышью
3820 // Мышь сдвинулась во время удержания клавиши,
3821 // либо активирован режим быстрого рисования:
3822 if ((MousePos.X <> MouseLDownPos.X) and
3823 (MousePos.Y <> MouseLDownPos.Y)) or
3824 ((MouseAction in [MOUSEACTION_DRAWPANEL, MOUSEACTION_DRAWTRIGGER]) and
3825 (ssCtrl in Shift)) then
3826 case MouseAction of
3827 // Рисовали панель:
3828 MOUSEACTION_DRAWPANEL:
3829 begin
3830 // Фон или передний план без текстуры - ошибка:
3831 if (lbPanelType.ItemIndex in [1, 2]) and
3832 (lbTextureList.ItemIndex = -1) then
3833 ErrorMessageBox(_lc[I_MSG_CHOOSE_TEXTURE])
3834 else // Назначаем параметры панели:
3835 begin
3836 case lbPanelType.ItemIndex of
3837 0: Panel.PanelType := PANEL_WALL;
3838 1: Panel.PanelType := PANEL_BACK;
3839 2: Panel.PanelType := PANEL_FORE;
3840 3: Panel.PanelType := PANEL_OPENDOOR;
3841 4: Panel.PanelType := PANEL_CLOSEDOOR;
3842 5: Panel.PanelType := PANEL_STEP;
3843 6: Panel.PanelType := PANEL_WATER;
3844 7: Panel.PanelType := PANEL_ACID1;
3845 8: Panel.PanelType := PANEL_ACID2;
3846 9: Panel.PanelType := PANEL_LIFTUP;
3847 10: Panel.PanelType := PANEL_LIFTDOWN;
3848 11: Panel.PanelType := PANEL_LIFTLEFT;
3849 12: Panel.PanelType := PANEL_LIFTRIGHT;
3850 13: Panel.PanelType := PANEL_BLOCKMON;
3851 end;
3853 Panel.X := Min(MousePos.X-MapOffset.X, MouseLDownPos.X-MapOffset.X);
3854 Panel.Y := Min(MousePos.Y-MapOffset.Y, MouseLDownPos.Y-MapOffset.Y);
3855 if ssCtrl in Shift then
3856 begin
3857 wWidth := DotStep;
3858 wHeight := DotStep;
3859 if (lbTextureList.ItemIndex <> -1) and
3860 (not IsSpecialTextureSel()) then
3861 begin
3862 if not g_GetTexture(SelectedTexture(), TextureID) then
3863 g_GetTexture('NOTEXTURE', TextureID);
3864 g_GetTextureSizeByID(TextureID, wWidth, wHeight);
3865 end;
3866 Panel.Width := wWidth;
3867 Panel.Height := wHeight;
3868 end
3869 else
3870 begin
3871 Panel.Width := Abs(MousePos.X-MouseLDownPos.X);
3872 Panel.Height := Abs(MousePos.Y-MouseLDownPos.Y);
3873 end;
3875 // Лифты, блокМон или отсутствие текстуры - пустая текстура:
3876 if (lbPanelType.ItemIndex in [9, 10, 11, 12, 13]) or
3877 (lbTextureList.ItemIndex = -1) then
3878 begin
3879 Panel.TextureHeight := 1;
3880 Panel.TextureWidth := 1;
3881 Panel.TextureName := '';
3882 Panel.TextureID := TEXTURE_SPECIAL_NONE;
3883 end
3884 else // Есть текстура:
3885 begin
3886 Panel.TextureName := SelectedTexture();
3888 // Обычная текстура:
3889 if not IsSpecialTextureSel() then
3890 begin
3891 g_GetTextureSizeByName(Panel.TextureName,
3892 Panel.TextureWidth, Panel.TextureHeight);
3893 g_GetTexture(Panel.TextureName, Panel.TextureID);
3894 end
3895 else // Спец.текстура:
3896 begin
3897 Panel.TextureHeight := 1;
3898 Panel.TextureWidth := 1;
3899 Panel.TextureID := SpecialTextureID(SelectedTexture());
3900 end;
3901 end;
3903 Panel.Alpha := 0;
3904 Panel.Blending := False;
3906 Undo_Add(OBJECT_PANEL, AddPanel(Panel));
3907 end;
3908 end;
3910 // Рисовали триггер:
3911 MOUSEACTION_DRAWTRIGGER:
3912 begin
3913 trigger.X := Min(MousePos.X-MapOffset.X, MouseLDownPos.X-MapOffset.X);
3914 trigger.Y := Min(MousePos.Y-MapOffset.Y, MouseLDownPos.Y-MapOffset.Y);
3915 if ssCtrl in Shift then
3916 begin
3917 wWidth := DotStep;
3918 wHeight := DotStep;
3919 trigger.Width := wWidth;
3920 trigger.Height := wHeight;
3921 end
3922 else
3923 begin
3924 trigger.Width := Abs(MousePos.X-MouseLDownPos.X);
3925 trigger.Height := Abs(MousePos.Y-MouseLDownPos.Y);
3926 end;
3928 trigger.Enabled := True;
3929 trigger.TriggerType := lbTriggersList.ItemIndex+1;
3930 trigger.TexturePanel := -1;
3932 // Типы активации:
3933 trigger.ActivateType := 0;
3935 if clbActivationType.Checked[0] then
3936 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_PLAYERCOLLIDE;
3937 if clbActivationType.Checked[1] then
3938 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_MONSTERCOLLIDE;
3939 if clbActivationType.Checked[2] then
3940 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_PLAYERPRESS;
3941 if clbActivationType.Checked[3] then
3942 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_MONSTERPRESS;
3943 if clbActivationType.Checked[4] then
3944 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_SHOT;
3945 if clbActivationType.Checked[5] then
3946 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_NOMONSTER;
3948 // Необходимые для активации ключи:
3949 trigger.Key := 0;
3951 if clbKeys.Checked[0] then
3952 trigger.Key := Trigger.Key or KEY_RED;
3953 if clbKeys.Checked[1] then
3954 trigger.Key := Trigger.Key or KEY_GREEN;
3955 if clbKeys.Checked[2] then
3956 trigger.Key := Trigger.Key or KEY_BLUE;
3957 if clbKeys.Checked[3] then
3958 trigger.Key := Trigger.Key or KEY_REDTEAM;
3959 if clbKeys.Checked[4] then
3960 trigger.Key := Trigger.Key or KEY_BLUETEAM;
3962 // Параметры триггера:
3963 FillByte(trigger.Data.Default[0], 128, 0);
3965 case trigger.TriggerType of
3966 // Переключаемая панель:
3967 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
3968 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP,
3969 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
3970 begin
3971 Trigger.Data.PanelID := -1;
3972 end;
3974 // Телепортация:
3975 TRIGGER_TELEPORT:
3976 begin
3977 trigger.Data.TargetPoint.X := trigger.X-64;
3978 trigger.Data.TargetPoint.Y := trigger.Y-64;
3979 trigger.Data.d2d_teleport := True;
3980 trigger.Data.TlpDir := 0;
3981 end;
3983 // Изменение других триггеров:
3984 TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF,
3985 TRIGGER_ONOFF:
3986 begin
3987 trigger.Data.Count := 1;
3988 end;
3990 // Звук:
3991 TRIGGER_SOUND:
3992 begin
3993 trigger.Data.Volume := 255;
3994 trigger.Data.Pan := 127;
3995 trigger.Data.PlayCount := 1;
3996 trigger.Data.Local := True;
3997 trigger.Data.SoundSwitch := False;
3998 end;
4000 // Музыка:
4001 TRIGGER_MUSIC:
4002 begin
4003 trigger.Data.MusicAction := 1;
4004 end;
4006 // Создание монстра:
4007 TRIGGER_SPAWNMONSTER:
4008 begin
4009 trigger.Data.MonType := MONSTER_ZOMBY;
4010 trigger.Data.MonPos.X := trigger.X-64;
4011 trigger.Data.MonPos.Y := trigger.Y-64;
4012 trigger.Data.MonHealth := 0;
4013 trigger.Data.MonActive := False;
4014 trigger.Data.MonCount := 1;
4015 end;
4017 // Создание предмета:
4018 TRIGGER_SPAWNITEM:
4019 begin
4020 trigger.Data.ItemType := ITEM_AMMO_BULLETS;
4021 trigger.Data.ItemPos.X := trigger.X-64;
4022 trigger.Data.ItemPos.Y := trigger.Y-64;
4023 trigger.Data.ItemOnlyDM := False;
4024 trigger.Data.ItemFalls := False;
4025 trigger.Data.ItemCount := 1;
4026 trigger.Data.ItemMax := 0;
4027 trigger.Data.ItemDelay := 0;
4028 end;
4030 // Ускорение:
4031 TRIGGER_PUSH:
4032 begin
4033 trigger.Data.PushAngle := 90;
4034 trigger.Data.PushForce := 10;
4035 trigger.Data.ResetVel := True;
4036 end;
4038 TRIGGER_SCORE:
4039 begin
4040 trigger.Data.ScoreCount := 1;
4041 trigger.Data.ScoreCon := True;
4042 trigger.Data.ScoreMsg := True;
4043 end;
4045 TRIGGER_MESSAGE:
4046 begin
4047 trigger.Data.MessageKind := 0;
4048 trigger.Data.MessageSendTo := 0;
4049 trigger.Data.MessageText := '';
4050 trigger.Data.MessageTime := 144;
4051 end;
4053 TRIGGER_DAMAGE:
4054 begin
4055 trigger.Data.DamageValue := 5;
4056 trigger.Data.DamageInterval := 12;
4057 end;
4059 TRIGGER_HEALTH:
4060 begin
4061 trigger.Data.HealValue := 5;
4062 trigger.Data.HealInterval := 36;
4063 end;
4065 TRIGGER_SHOT:
4066 begin
4067 trigger.Data.ShotType := TRIGGER_SHOT_BULLET;
4068 trigger.Data.ShotSound := True;
4069 trigger.Data.ShotPanelID := -1;
4070 trigger.Data.ShotTarget := 0;
4071 trigger.Data.ShotIntSight := 0;
4072 trigger.Data.ShotAim := TRIGGER_SHOT_AIM_DEFAULT;
4073 trigger.Data.ShotPos.X := trigger.X-64;
4074 trigger.Data.ShotPos.Y := trigger.Y-64;
4075 trigger.Data.ShotAngle := 0;
4076 trigger.Data.ShotWait := 18;
4077 trigger.Data.ShotAccuracy := 0;
4078 trigger.Data.ShotAmmo := 0;
4079 trigger.Data.ShotIntReload := 0;
4080 end;
4082 TRIGGER_EFFECT:
4083 begin
4084 trigger.Data.FXCount := 1;
4085 trigger.Data.FXType := TRIGGER_EFFECT_PARTICLE;
4086 trigger.Data.FXSubType := TRIGGER_EFFECT_SLIQUID;
4087 trigger.Data.FXColorR := 0;
4088 trigger.Data.FXColorG := 0;
4089 trigger.Data.FXColorB := 255;
4090 trigger.Data.FXPos := TRIGGER_EFFECT_POS_CENTER;
4091 trigger.Data.FXWait := 1;
4092 trigger.Data.FXVelX := 0;
4093 trigger.Data.FXVelY := -20;
4094 trigger.Data.FXSpreadL := 5;
4095 trigger.Data.FXSpreadR := 5;
4096 trigger.Data.FXSpreadU := 4;
4097 trigger.Data.FXSpreadD := 0;
4098 end;
4099 end;
4101 Undo_Add(OBJECT_TRIGGER, AddTrigger(trigger));
4102 end;
4104 // Рисовали область триггера "Расширитель":
4105 MOUSEACTION_DRAWPRESS:
4106 with gTriggers[SelectedObjects[GetFirstSelected].ID] do
4107 begin
4108 Data.tX := Min(MousePos.X-MapOffset.X, MouseLDownPos.X-MapOffset.X);
4109 Data.tY := Min(MousePos.Y-MapOffset.Y, MouseLDownPos.Y-MapOffset.Y);
4110 Data.tWidth := Abs(MousePos.X-MouseLDownPos.X);
4111 Data.tHeight := Abs(MousePos.Y-MouseLDownPos.Y);
4113 DrawPressRect := False;
4114 end;
4115 end;
4117 MouseAction := MOUSEACTION_NONE;
4118 end;
4119 end // if Button = mbLeft...
4120 else if Button = mbRight then // Right Mouse Button:
4121 begin
4122 if MouseAction = MOUSEACTION_NOACTION then
4123 begin
4124 MouseAction := MOUSEACTION_NONE;
4125 Exit;
4126 end;
4128 // Объект передвинут или изменен в размере:
4129 if MouseAction in [MOUSEACTION_MOVEOBJ, MOUSEACTION_RESIZE] then
4130 begin
4131 RenderPanel.Cursor := crDefault;
4132 MouseAction := MOUSEACTION_NONE;
4133 FillProperty();
4134 Exit;
4135 end;
4137 // Еще не все выбрали:
4138 if SelectFlag <> SELECTFLAG_NONE then
4139 begin
4140 if SelectFlag = SELECTFLAG_SELECTED then
4141 SelectFlag := SELECTFLAG_NONE;
4142 FillProperty();
4143 Exit;
4144 end;
4146 // Мышь сдвинулась во время удержания клавиши:
4147 if (MousePos.X <> MouseRDownPos.X) and
4148 (MousePos.Y <> MouseRDownPos.Y) then
4149 begin
4150 rSelectRect := True;
4152 rRect.X := Min(MousePos.X, MouseRDownPos.X)-MapOffset.X;
4153 rRect.Y := Min(MousePos.Y, MouseRDownPos.Y)-MapOffset.Y;
4154 rRect.Width := Abs(MousePos.X-MouseRDownPos.X);
4155 rRect.Height := Abs(MousePos.Y-MouseRDownPos.Y);
4156 end
4157 else // Мышь не сдвинулась - нет прямоугольника:
4158 begin
4159 rSelectRect := False;
4161 rRect.X := X-MapOffset.X-1;
4162 rRect.Y := Y-MapOffset.Y-1;
4163 rRect.Width := 2;
4164 rRect.Height := 2;
4165 end;
4167 // Если зажат Ctrl - выделять еще, иначе только один выделенный объект:
4168 if not (ssCtrl in Shift) then
4169 RemoveSelectFromObjects();
4171 // Выделяем всё в выбранном прямоугольнике:
4172 if (ssCtrl in Shift) and (ssAlt in Shift) then
4173 begin
4174 SelectObjects(OBJECT_PANEL);
4175 SelectObjects(OBJECT_ITEM);
4176 SelectObjects(OBJECT_MONSTER);
4177 SelectObjects(OBJECT_AREA);
4178 SelectObjects(OBJECT_TRIGGER);
4179 end
4180 else
4181 SelectObjects(pcObjects.ActivePageIndex+1);
4183 FillProperty();
4184 end
4186 else // Middle Mouse Button
4187 begin
4188 RenderPanel.Cursor := crDefault;
4189 ReleaseCapture();
4190 end;
4191 end;
4193 procedure TMainForm.RenderPanelPaint(Sender: TObject);
4194 begin
4195 Draw();
4196 end;
4198 function TMainForm.RenderMousePos(): Types.TPoint;
4199 begin
4200 Result := RenderPanel.ScreenToClient(Mouse.CursorPos);
4201 end;
4203 procedure TMainForm.RecountSelectedObjects();
4204 begin
4205 if SelectedObjectCount() = 0 then
4206 StatusBar.Panels[0].Text := ''
4207 else
4208 StatusBar.Panels[0].Text := Format(_lc[I_CAP_STAT_SELECTED], [SelectedObjectCount()]);
4209 end;
4211 procedure TMainForm.RenderPanelMouseMove(Sender: TObject;
4212 Shift: TShiftState; X, Y: Integer);
4213 var
4214 sX, sY: Integer;
4215 dWidth, dHeight: Integer;
4216 _id: Integer;
4217 TextureID: DWORD;
4218 wWidth, wHeight: Word;
4219 begin
4220 _id := GetFirstSelected();
4221 TextureID := 0;
4223 // Рисуем панель с текстурой, сетка - размеры текстуры:
4224 if (MouseAction = MOUSEACTION_DRAWPANEL) and
4225 (lbPanelType.ItemIndex in [0..8]) and
4226 (lbTextureList.ItemIndex <> -1) and
4227 (not IsSpecialTextureSel()) then
4228 begin
4229 sX := StrToIntDef(lTextureWidth.Caption, DotStep);
4230 sY := StrToIntDef(lTextureHeight.Caption, DotStep);
4231 end
4232 else
4233 // Меняем размер панели с текстурой, сетка - размеры текстуры:
4234 if (MouseAction = MOUSEACTION_RESIZE) and
4235 ( (SelectedObjects[_id].ObjectType = OBJECT_PANEL) and
4236 IsTexturedPanel(gPanels[SelectedObjects[_id].ID].PanelType) and
4237 (gPanels[SelectedObjects[_id].ID].TextureName <> '') and
4238 (not IsSpecialTexture(gPanels[SelectedObjects[_id].ID].TextureName)) ) then
4239 begin
4240 sX := gPanels[SelectedObjects[_id].ID].TextureWidth;
4241 sY := gPanels[SelectedObjects[_id].ID].TextureHeight;
4242 end
4243 else
4244 // Выравнивание по сетке:
4245 if SnapToGrid then
4246 begin
4247 sX := DotStep;
4248 sY := DotStep;
4249 end
4250 else // Нет выравнивания по сетке:
4251 begin
4252 sX := 1;
4253 sY := 1;
4254 end;
4256 // Новая позиция мыши:
4257 if MouseLDown then
4258 begin // Зажата левая кнопка мыши
4259 MousePos.X := (Round((X-MouseLDownPos.X)/sX)*sX)+MouseLDownPos.X;
4260 MousePos.Y := (Round((Y-MouseLDownPos.Y)/sY)*sY)+MouseLDownPos.Y;
4261 end
4262 else
4263 if MouseRDown then
4264 begin // Зажата правая кнопка мыши
4265 MousePos.X := (Round((X-MouseRDownPos.X)/sX)*sX)+MouseRDownPos.X;
4266 MousePos.Y := (Round((Y-MouseRDownPos.Y)/sY)*sY)+MouseRDownPos.Y;
4267 end
4268 else
4269 begin // Кнопки мыши не зажаты
4270 MousePos.X := Round((-MapOffset.X + X) / sX) * sX + MapOffset.X;
4271 MousePos.Y := Round((-MapOffset.Y + Y) / sY) * sY + MapOffset.Y;
4272 end;
4274 // Зажата только правая кнопка мыши:
4275 if (not MouseLDown) and (MouseRDown) and (not MouseMDown) then
4276 begin
4277 // Рисуем прямоугольник выделения:
4278 if MouseAction = MOUSEACTION_NONE then
4279 begin
4280 if DrawRect = nil then
4281 New(DrawRect);
4282 DrawRect.Top := MouseRDownPos.y;
4283 DrawRect.Left := MouseRDownPos.x;
4284 DrawRect.Bottom := MousePos.y;
4285 DrawRect.Right := MousePos.x;
4286 end
4287 else
4288 // Двигаем выделенные объекты:
4289 if MouseAction = MOUSEACTION_MOVEOBJ then
4290 begin
4291 MoveSelectedObjects(ssShift in Shift, ssCtrl in Shift,
4292 MousePos.X-LastMovePoint.X,
4293 MousePos.Y-LastMovePoint.Y);
4294 end
4295 else
4296 // Меняем размер выделенного объекта:
4297 if MouseAction = MOUSEACTION_RESIZE then
4298 begin
4299 if (SelectedObjectCount = 1) and
4300 (SelectedObjects[GetFirstSelected].Live) then
4301 begin
4302 dWidth := MousePos.X-LastMovePoint.X;
4303 dHeight := MousePos.Y-LastMovePoint.Y;
4305 case ResizeType of
4306 RESIZETYPE_VERTICAL: dWidth := 0;
4307 RESIZETYPE_HORIZONTAL: dHeight := 0;
4308 end;
4310 case ResizeDirection of
4311 RESIZEDIR_UP: dHeight := -dHeight;
4312 RESIZEDIR_LEFT: dWidth := -dWidth;
4313 end;
4315 if ResizeObject(SelectedObjects[GetFirstSelected].ObjectType,
4316 SelectedObjects[GetFirstSelected].ID,
4317 dWidth, dHeight, ResizeDirection) then
4318 LastMovePoint := MousePos;
4319 end;
4320 end;
4321 end;
4323 // Зажата только левая кнопка мыши:
4324 if (not MouseRDown) and (MouseLDown) and (not MouseMDown) then
4325 begin
4326 // Рисуем прямоугольник планирования панели:
4327 if MouseAction in [MOUSEACTION_DRAWPANEL,
4328 MOUSEACTION_DRAWTRIGGER,
4329 MOUSEACTION_DRAWPRESS] then
4330 begin
4331 if DrawRect = nil then
4332 New(DrawRect);
4333 if ssCtrl in Shift then
4334 begin
4335 wWidth := DotStep;
4336 wHeight := DotStep;
4337 if (lbTextureList.ItemIndex <> -1) and (not IsSpecialTextureSel()) and
4338 (MouseAction = MOUSEACTION_DRAWPANEL) then
4339 begin
4340 if not g_GetTexture(SelectedTexture(), TextureID) then
4341 g_GetTexture('NOTEXTURE', TextureID);
4342 g_GetTextureSizeByID(TextureID, wWidth, wHeight);
4343 end;
4344 DrawRect.Top := MouseLDownPos.y;
4345 DrawRect.Left := MouseLDownPos.x;
4346 DrawRect.Bottom := DrawRect.Top + wHeight;
4347 DrawRect.Right := DrawRect.Left + wWidth;
4348 end
4349 else
4350 begin
4351 DrawRect.Top := MouseLDownPos.y;
4352 DrawRect.Left := MouseLDownPos.x;
4353 DrawRect.Bottom := MousePos.y;
4354 DrawRect.Right := MousePos.x;
4355 end;
4356 end
4357 else // Двигаем карту:
4358 if MouseAction = MOUSEACTION_MOVEMAP then
4359 begin
4360 MoveMap(X, Y);
4361 end;
4362 end;
4364 // Only Middle Mouse Button is pressed
4365 if (not MouseLDown) and (not MouseRDown) and (MouseMDown) then
4366 begin
4367 MapOffset.X := -EnsureRange(-MapOffset.X + MouseMDownPos.X - Mouse.CursorPos.X,
4368 sbHorizontal.Min, sbHorizontal.Max);
4369 sbHorizontal.Position := -MapOffset.X;
4370 MapOffset.Y := -EnsureRange(-MapOffset.Y + MouseMDownPos.Y - Mouse.CursorPos.Y,
4371 sbVertical.Min, sbVertical.Max);
4372 sbVertical.Position := -MapOffset.Y;
4373 MouseMDownPos := Mouse.CursorPos;
4374 end;
4376 // Клавиши мыши не зажаты:
4377 if (not MouseRDown) and (not MouseLDown) then
4378 DrawRect := nil;
4380 // Строка состояния - координаты мыши:
4381 StatusBar.Panels[1].Text := Format('(%d:%d)',
4382 [MousePos.X-MapOffset.X, MousePos.Y-MapOffset.Y]);
4383 end;
4385 procedure TMainForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
4386 begin
4387 CanClose := Application.MessageBox(PChar(_lc[I_MSG_EXIT_PROMT]),
4388 PChar(_lc[I_MSG_EXIT]),
4389 MB_ICONQUESTION or MB_YESNO or
4390 MB_DEFBUTTON1) = idYes;
4391 end;
4393 procedure TMainForm.aExitExecute(Sender: TObject);
4394 begin
4395 Close();
4396 end;
4398 procedure TMainForm.FormDestroy(Sender: TObject);
4399 var
4400 config: TConfig;
4401 s: AnsiString;
4402 i: Integer;
4403 begin
4404 config := TConfig.CreateFile(CfgFileName);
4406 if WindowState <> wsMaximized then
4407 begin
4408 config.WriteInt('Editor', 'XPos', Left);
4409 config.WriteInt('Editor', 'YPos', Top);
4410 config.WriteInt('Editor', 'Width', Width);
4411 config.WriteInt('Editor', 'Height', Height);
4412 end
4413 else
4414 begin
4415 config.WriteInt('Editor', 'XPos', RestoredLeft);
4416 config.WriteInt('Editor', 'YPos', RestoredTop);
4417 config.WriteInt('Editor', 'Width', RestoredWidth);
4418 config.WriteInt('Editor', 'Height', RestoredHeight);
4419 end;
4420 config.WriteBool('Editor', 'Maximize', WindowState = wsMaximized);
4421 config.WriteBool('Editor', 'Minimap', ShowMap);
4422 config.WriteInt('Editor', 'PanelProps', PanelProps.ClientWidth);
4423 config.WriteInt('Editor', 'PanelObjs', PanelObjs.ClientHeight);
4424 config.WriteBool('Editor', 'DotEnable', DotEnable);
4425 config.WriteInt('Editor', 'DotStep', DotStep);
4426 config.WriteStr('Editor', 'LastOpenDir', OpenDialog.InitialDir);
4427 config.WriteStr('Editor', 'LastSaveDir', SaveDialog.InitialDir);
4428 config.WriteBool('Editor', 'EdgeShow', drEdge[3] < 255);
4429 config.WriteInt('Editor', 'EdgeColor', gColorEdge);
4430 config.WriteInt('Editor', 'EdgeAlpha', gAlphaEdge);
4431 config.WriteInt('Editor', 'LineAlpha', gAlphaTriggerLine);
4432 config.WriteInt('Editor', 'TriggerAlpha', gAlphaTriggerArea);
4433 config.WriteInt('Editor', 'MonsterRectAlpha', gAlphaMonsterRect);
4434 config.WriteInt('Editor', 'AreaRectAlpha', gAlphaAreaRect);
4436 for i := 0 to RecentCount - 1 do
4437 begin
4438 if i < RecentFiles.Count then s := RecentFiles[i] else s := '';
4439 {$IFDEF WINDOWS}
4440 config.WriteStr('RecentFilesWin', IntToStr(i), s);
4441 {$ELSE}
4442 config.WriteStr('RecentFilesUnix', IntToStr(i), s);
4443 {$ENDIF}
4444 end;
4445 RecentFiles.Free();
4447 config.SaveFile(CfgFileName);
4448 config.Free();
4450 slInvalidTextures.Free;
4451 end;
4453 procedure TMainForm.FormDropFiles(Sender: TObject;
4454 const FileNames: array of String);
4455 begin
4456 if Length(FileNames) <> 1 then
4457 Exit;
4459 OpenMapFile(FileNames[0]);
4460 end;
4462 procedure TMainForm.RenderPanelResize(Sender: TObject);
4463 begin
4464 if MainForm.Visible then
4465 MainForm.Resize();
4466 end;
4468 procedure TMainForm.Splitter1Moved(Sender: TObject);
4469 begin
4470 FormResize(Sender);
4471 end;
4473 procedure TMainForm.MapTestCheck(Sender: TObject);
4474 begin
4475 if MapTestProcess <> nil then
4476 begin
4477 if MapTestProcess.Running = false then
4478 begin
4479 if MapTestProcess.ExitCode <> 0 then
4480 Application.MessageBox(PChar(_lc[I_MSG_EXEC_ERROR]), 'FIXME', MB_OK or MB_ICONERROR);
4481 SysUtils.DeleteFile(MapTestFile);
4482 MapTestFile := '';
4483 FreeAndNil(MapTestProcess);
4484 tbTestMap.Enabled := True;
4485 end;
4486 end;
4487 end;
4489 procedure TMainForm.aMapOptionsExecute(Sender: TObject);
4490 var
4491 ResName: String;
4492 begin
4493 MapOptionsForm.ShowModal();
4495 ResName := OpenedMap;
4496 while (Pos(':\', ResName) > 0) do
4497 Delete(ResName, 1, Pos(':\', ResName) + 1);
4499 UpdateCaption(gMapInfo.Name, ExtractFileName(OpenedWAD), ResName);
4500 end;
4502 procedure TMainForm.aAboutExecute(Sender: TObject);
4503 begin
4504 AboutForm.ShowModal();
4505 end;
4507 procedure TMainForm.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
4508 var
4509 dx, dy, i: Integer;
4510 FileName: String;
4511 ok: Boolean;
4512 begin
4513 if (not EditingProperties) then
4514 begin
4515 if ssCtrl in Shift then
4516 begin
4517 case Chr(Key) of
4518 '1': ContourEnabled[LAYER_BACK] := not ContourEnabled[LAYER_BACK];
4519 '2': ContourEnabled[LAYER_WALLS] := not ContourEnabled[LAYER_WALLS];
4520 '3': ContourEnabled[LAYER_FOREGROUND] := not ContourEnabled[LAYER_FOREGROUND];
4521 '4': ContourEnabled[LAYER_STEPS] := not ContourEnabled[LAYER_STEPS];
4522 '5': ContourEnabled[LAYER_WATER] := not ContourEnabled[LAYER_WATER];
4523 '6': ContourEnabled[LAYER_ITEMS] := not ContourEnabled[LAYER_ITEMS];
4524 '7': ContourEnabled[LAYER_MONSTERS] := not ContourEnabled[LAYER_MONSTERS];
4525 '8': ContourEnabled[LAYER_AREAS] := not ContourEnabled[LAYER_AREAS];
4526 '9': ContourEnabled[LAYER_TRIGGERS] := not ContourEnabled[LAYER_TRIGGERS];
4527 '0':
4528 begin
4529 ok := False;
4530 for i := Low(ContourEnabled) to High(ContourEnabled) do
4531 if ContourEnabled[i] then
4532 ok := True;
4533 for i := Low(ContourEnabled) to High(ContourEnabled) do
4534 ContourEnabled[i] := not ok
4535 end
4536 end
4537 end
4538 else
4539 begin
4540 case Chr(key) of
4541 '1': SwitchLayer(LAYER_BACK);
4542 '2': SwitchLayer(LAYER_WALLS);
4543 '3': SwitchLayer(LAYER_FOREGROUND);
4544 '4': SwitchLayer(LAYER_STEPS);
4545 '5': SwitchLayer(LAYER_WATER);
4546 '6': SwitchLayer(LAYER_ITEMS);
4547 '7': SwitchLayer(LAYER_MONSTERS);
4548 '8': SwitchLayer(LAYER_AREAS);
4549 '9': SwitchLayer(LAYER_TRIGGERS);
4550 '0': tbShowClick(tbShow);
4551 end
4552 end;
4554 if Key = Ord('V') then
4555 begin // Поворот монстров и областей:
4556 if (SelectedObjects <> nil) then
4557 begin
4558 for i := 0 to High(SelectedObjects) do
4559 if (SelectedObjects[i].Live) then
4560 begin
4561 if (SelectedObjects[i].ObjectType = OBJECT_MONSTER) then
4562 begin
4563 g_ChangeDir(gMonsters[SelectedObjects[i].ID].Direction);
4564 end
4565 else
4566 if (SelectedObjects[i].ObjectType = OBJECT_AREA) then
4567 begin
4568 g_ChangeDir(gAreas[SelectedObjects[i].ID].Direction);
4569 end;
4570 end;
4571 end
4572 else
4573 begin
4574 if pcObjects.ActivePage = tsMonsters then
4575 begin
4576 if rbMonsterLeft.Checked then
4577 rbMonsterRight.Checked := True
4578 else
4579 rbMonsterLeft.Checked := True;
4580 end;
4581 if pcObjects.ActivePage = tsAreas then
4582 begin
4583 if rbAreaLeft.Checked then
4584 rbAreaRight.Checked := True
4585 else
4586 rbAreaLeft.Checked := True;
4587 end;
4588 end;
4589 end;
4591 if not (ssCtrl in Shift) then
4592 begin
4593 // Быстрое превью карты:
4594 if Key = Ord('E') then
4595 begin
4596 if PreviewMode = 0 then
4597 PreviewMode := 2;
4598 end;
4600 // Вертикальный скролл карты:
4601 with sbVertical do
4602 begin
4603 if Key = Ord('W') then
4604 begin
4605 dy := Position;
4606 if ssShift in Shift then Position := EnsureRange(Position - DotStep * 4, Min, Max)
4607 else Position := EnsureRange(Position - DotStep, Min, Max);
4608 MapOffset.Y := -Position;
4609 dy -= Position;
4611 if (MouseLDown or MouseRDown) then
4612 begin
4613 if DrawRect <> nil then
4614 begin
4615 Inc(MouseLDownPos.y, dy);
4616 Inc(MouseRDownPos.y, dy);
4617 end;
4618 Inc(LastMovePoint.Y, dy);
4619 RenderPanelMouseMove(Sender, Shift, RenderMousePos().X, RenderMousePos().Y);
4620 end;
4621 end;
4623 if Key = Ord('S') then
4624 begin
4625 dy := Position;
4626 if ssShift in Shift then Position := EnsureRange(Position + DotStep * 4, Min, Max)
4627 else Position := EnsureRange(Position + DotStep, Min, Max);
4628 MapOffset.Y := -Position;
4629 dy -= Position;
4631 if (MouseLDown or MouseRDown) then
4632 begin
4633 if DrawRect <> nil then
4634 begin
4635 Inc(MouseLDownPos.y, dy);
4636 Inc(MouseRDownPos.y, dy);
4637 end;
4638 Inc(LastMovePoint.Y, dy);
4639 RenderPanelMouseMove(Sender, Shift, RenderMousePos().X, RenderMousePos().Y);
4640 end;
4641 end;
4642 end;
4644 // Горизонтальный скролл карты:
4645 with sbHorizontal do
4646 begin
4647 if Key = Ord('A') then
4648 begin
4649 dx := Position;
4650 if ssShift in Shift then Position := EnsureRange(Position - DotStep * 4, Min, Max)
4651 else Position := EnsureRange(Position - DotStep, Min, Max);
4652 MapOffset.X := -Position;
4653 dx -= Position;
4655 if (MouseLDown or MouseRDown) then
4656 begin
4657 if DrawRect <> nil then
4658 begin
4659 Inc(MouseLDownPos.x, dx);
4660 Inc(MouseRDownPos.x, dx);
4661 end;
4662 Inc(LastMovePoint.X, dx);
4663 RenderPanelMouseMove(Sender, Shift, RenderMousePos().X, RenderMousePos().Y);
4664 end;
4665 end;
4667 if Key = Ord('D') then
4668 begin
4669 dx := Position;
4670 if ssShift in Shift then Position := EnsureRange(Position + DotStep * 4, Min, Max)
4671 else Position := EnsureRange(Position + DotStep, Min, Max);
4672 MapOffset.X := -Position;
4673 dx -= Position;
4675 if (MouseLDown or MouseRDown) then
4676 begin
4677 if DrawRect <> nil then
4678 begin
4679 Inc(MouseLDownPos.x, dx);
4680 Inc(MouseRDownPos.x, dx);
4681 end;
4682 Inc(LastMovePoint.X, dx);
4683 RenderPanelMouseMove(Sender, Shift, RenderMousePos().X, RenderMousePos().Y);
4684 end;
4685 end;
4686 end;
4687 end
4688 else // ssCtrl in Shift
4689 begin
4690 if ssShift in Shift then
4691 begin
4692 // Вставка по абсолютному смещению:
4693 if Key = Ord('V') then
4694 aPasteObjectExecute(Sender);
4695 end;
4696 RenderPanelMouseMove(Sender, Shift, RenderMousePos().X, RenderMousePos().Y);
4697 end;
4698 end;
4700 // Удалить выделенные объекты:
4701 if (Key = VK_DELETE) and (SelectedObjects <> nil) and
4702 RenderPanel.Focused() then
4703 DeleteSelectedObjects();
4705 // Снять выделение:
4706 if (Key = VK_ESCAPE) and (SelectedObjects <> nil) then
4707 RemoveSelectFromObjects();
4709 // Передвинуть объекты:
4710 if MainForm.ActiveControl = RenderPanel then
4711 begin
4712 dx := 0;
4713 dy := 0;
4715 if Key = VK_NUMPAD4 then
4716 dx := IfThen(ssAlt in Shift, -1, -DotStep);
4717 if Key = VK_NUMPAD6 then
4718 dx := IfThen(ssAlt in Shift, 1, DotStep);
4719 if Key = VK_NUMPAD8 then
4720 dy := IfThen(ssAlt in Shift, -1, -DotStep);
4721 if Key = VK_NUMPAD5 then
4722 dy := IfThen(ssAlt in Shift, 1, DotStep);
4724 if (dx <> 0) or (dy <> 0) then
4725 begin
4726 MoveSelectedObjects(ssShift in Shift, ssCtrl in Shift, dx, dy);
4727 Key := 0;
4728 end;
4729 end;
4731 if ssCtrl in Shift then
4732 begin
4733 // Выбор панели с текстурой для триггера
4734 if Key = Ord('T') then
4735 begin
4736 DrawPressRect := False;
4737 if SelectFlag = SELECTFLAG_TEXTURE then
4738 begin
4739 SelectFlag := SELECTFLAG_NONE;
4740 Exit;
4741 end;
4742 vleObjectProperty.FindRow(_lc[I_PROP_TR_TEXTURE_PANEL], i);
4743 if i > 0 then
4744 SelectFlag := SELECTFLAG_TEXTURE;
4745 end;
4747 if Key = Ord('D') then
4748 begin
4749 SelectFlag := SELECTFLAG_NONE;
4750 if DrawPressRect then
4751 begin
4752 DrawPressRect := False;
4753 Exit;
4754 end;
4755 i := -1;
4757 // Выбор области воздействия, в зависимости от типа триггера
4758 vleObjectProperty.FindRow(_lc[I_PROP_TR_EX_AREA], i);
4759 if i > 0 then
4760 begin
4761 DrawPressRect := True;
4762 Exit;
4763 end;
4764 vleObjectProperty.FindRow(_lc[I_PROP_TR_DOOR_PANEL], i);
4765 if i <= 0 then
4766 vleObjectProperty.FindRow(_lc[I_PROP_TR_TRAP_PANEL], i);
4767 if i > 0 then
4768 begin
4769 SelectFlag := SELECTFLAG_DOOR;
4770 Exit;
4771 end;
4772 vleObjectProperty.FindRow(_lc[I_PROP_TR_LIFT_PANEL], i);
4773 if i > 0 then
4774 begin
4775 SelectFlag := SELECTFLAG_LIFT;
4776 Exit;
4777 end;
4778 vleObjectProperty.FindRow(_lc[I_PROP_TR_TELEPORT_TO], i);
4779 if i > 0 then
4780 begin
4781 SelectFlag := SELECTFLAG_TELEPORT;
4782 Exit;
4783 end;
4784 vleObjectProperty.FindRow(_lc[I_PROP_TR_SPAWN_TO], i);
4785 if i > 0 then
4786 begin
4787 SelectFlag := SELECTFLAG_SPAWNPOINT;
4788 Exit;
4789 end;
4791 // Выбор основного параметра, в зависимости от типа триггера
4792 vleObjectProperty.FindRow(_lc[I_PROP_TR_NEXT_MAP], i);
4793 if i > 0 then
4794 begin
4795 g_ProcessResourceStr(OpenedMap, @FileName, nil, nil);
4796 SelectMapForm.Caption := _lc[I_CAP_SELECT];
4797 SelectMapForm.GetMaps(FileName);
4799 if SelectMapForm.ShowModal() = mrOK then
4800 begin
4801 vleObjectProperty.Cells[1, i] := SelectMapForm.lbMapList.Items[SelectMapForm.lbMapList.ItemIndex];
4802 bApplyProperty.Click();
4803 end;
4804 Exit;
4805 end;
4806 vleObjectProperty.FindRow(_lc[I_PROP_TR_SOUND_NAME], i);
4807 if i <= 0 then
4808 vleObjectProperty.FindRow(_lc[I_PROP_TR_MUSIC_NAME], i);
4809 if i > 0 then
4810 begin
4811 AddSoundForm.OKFunction := nil;
4812 AddSoundForm.lbResourcesList.MultiSelect := False;
4813 AddSoundForm.SetResource := vleObjectProperty.Cells[1, i];
4815 if (AddSoundForm.ShowModal() = mrOk) then
4816 begin
4817 vleObjectProperty.Cells[1, i] := AddSoundForm.ResourceName;
4818 bApplyProperty.Click();
4819 end;
4820 Exit;
4821 end;
4822 vleObjectProperty.FindRow(_lc[I_PROP_TR_PUSH_ANGLE], i);
4823 if i <= 0 then
4824 vleObjectProperty.FindRow(_lc[I_PROP_TR_MESSAGE_TEXT], i);
4825 if i > 0 then
4826 begin
4827 vleObjectProperty.Row := i;
4828 vleObjectProperty.SetFocus();
4829 Exit;
4830 end;
4831 end;
4832 end;
4833 end;
4835 procedure TMainForm.aOptimizeExecute(Sender: TObject);
4836 begin
4837 RemoveSelectFromObjects();
4838 MapOptimizationForm.ShowModal();
4839 end;
4841 procedure TMainForm.aCheckMapExecute(Sender: TObject);
4842 begin
4843 MapCheckForm.ShowModal();
4844 end;
4846 procedure TMainForm.bbAddTextureClick(Sender: TObject);
4847 begin
4848 AddTextureForm.lbResourcesList.MultiSelect := True;
4849 AddTextureForm.ShowModal();
4850 end;
4852 procedure TMainForm.lbTextureListClick(Sender: TObject);
4853 var
4854 TextureID: DWORD;
4855 TextureWidth, TextureHeight: Word;
4856 begin
4857 TextureID := 0;
4858 TextureWidth := 0;
4859 TextureHeight := 0;
4860 if (lbTextureList.ItemIndex <> -1) and
4861 (not IsSpecialTextureSel()) then
4862 begin
4863 if g_GetTexture(SelectedTexture(), TextureID) then
4864 begin
4865 g_GetTextureSizeByID(TextureID, TextureWidth, TextureHeight);
4867 lTextureWidth.Caption := IntToStr(TextureWidth);
4868 lTextureHeight.Caption := IntToStr(TextureHeight);
4869 end else
4870 begin
4871 lTextureWidth.Caption := _lc[I_NOT_ACCESSIBLE];
4872 lTextureHeight.Caption := _lc[I_NOT_ACCESSIBLE];
4873 end;
4874 end
4875 else
4876 begin
4877 lTextureWidth.Caption := '';
4878 lTextureHeight.Caption := '';
4879 end;
4880 end;
4882 procedure TMainForm.lbTextureListDrawItem(Control: TWinControl; Index: Integer;
4883 ARect: TRect; State: TOwnerDrawState);
4884 begin
4885 with Control as TListBox do
4886 begin
4887 if LCLType.odSelected in State then
4888 begin
4889 Canvas.Brush.Color := clHighlight;
4890 Canvas.Font.Color := clHighlightText;
4891 end else
4892 if (Items <> nil) and (Index >= 0) then
4893 if slInvalidTextures.IndexOf(Items[Index]) > -1 then
4894 begin
4895 Canvas.Brush.Color := clRed;
4896 Canvas.Font.Color := clWhite;
4897 end;
4898 Canvas.FillRect(ARect);
4899 Canvas.TextRect(ARect, ARect.Left, ARect.Top, Items[Index]);
4900 end;
4901 end;
4903 procedure TMainForm.miMacMinimizeClick(Sender: TObject);
4904 begin
4905 self.WindowState := wsMinimized;
4906 self.FormWindowStateChange(Sender);
4907 end;
4909 procedure TMainForm.miMacZoomClick(Sender: TObject);
4910 begin
4911 if self.WindowState = wsMaximized then
4912 self.WindowState := wsNormal
4913 else
4914 self.WindowState := wsMaximized;
4915 self.FormWindowStateChange(Sender);
4916 end;
4918 procedure TMainForm.miReopenMapClick(Sender: TObject);
4919 var
4920 FileName, Resource: String;
4921 begin
4922 if OpenedMap = '' then
4923 Exit;
4925 if Application.MessageBox(PChar(_lc[I_MSG_REOPEN_MAP_PROMT]),
4926 PChar(_lc[I_MENU_FILE_REOPEN]), MB_ICONQUESTION or MB_YESNO) <> idYes then
4927 Exit;
4929 g_ProcessResourceStr(OpenedMap, @FileName, nil, @Resource);
4930 OpenMap(FileName, Resource);
4931 end;
4933 procedure TMainForm.vleObjectPropertyGetPickList(Sender: TObject;
4934 const KeyName: String; Values: TStrings);
4935 begin
4936 if vleObjectProperty.ItemProps[KeyName].EditStyle = esPickList then
4937 begin
4938 if KeyName = _lc[I_PROP_DIRECTION] then
4939 begin
4940 Values.Add(DirNames[D_LEFT]);
4941 Values.Add(DirNames[D_RIGHT]);
4942 end
4943 else if KeyName = _lc[I_PROP_TR_TELEPORT_DIR] then
4944 begin
4945 Values.Add(DirNamesAdv[0]);
4946 Values.Add(DirNamesAdv[1]);
4947 Values.Add(DirNamesAdv[2]);
4948 Values.Add(DirNamesAdv[3]);
4949 end
4950 else if KeyName = _lc[I_PROP_TR_MUSIC_ACT] then
4951 begin
4952 Values.Add(_lc[I_PROP_TR_MUSIC_ON]);
4953 Values.Add(_lc[I_PROP_TR_MUSIC_OFF]);
4954 end
4955 else if KeyName = _lc[I_PROP_TR_MONSTER_BEHAVIOUR] then
4956 begin
4957 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_0]);
4958 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_1]);
4959 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_2]);
4960 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_3]);
4961 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_4]);
4962 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_5]);
4963 end
4964 else if KeyName = _lc[I_PROP_TR_SCORE_ACT] then
4965 begin
4966 Values.Add(_lc[I_PROP_TR_SCORE_ACT_0]);
4967 Values.Add(_lc[I_PROP_TR_SCORE_ACT_1]);
4968 Values.Add(_lc[I_PROP_TR_SCORE_ACT_2]);
4969 Values.Add(_lc[I_PROP_TR_SCORE_ACT_3]);
4970 end
4971 else if KeyName = _lc[I_PROP_TR_SCORE_TEAM] then
4972 begin
4973 Values.Add(_lc[I_PROP_TR_SCORE_TEAM_0]);
4974 Values.Add(_lc[I_PROP_TR_SCORE_TEAM_1]);
4975 Values.Add(_lc[I_PROP_TR_SCORE_TEAM_2]);
4976 Values.Add(_lc[I_PROP_TR_SCORE_TEAM_3]);
4977 end
4978 else if KeyName = _lc[I_PROP_TR_MESSAGE_KIND] then
4979 begin
4980 Values.Add(_lc[I_PROP_TR_MESSAGE_KIND_0]);
4981 Values.Add(_lc[I_PROP_TR_MESSAGE_KIND_1]);
4982 end
4983 else if KeyName = _lc[I_PROP_TR_MESSAGE_TO] then
4984 begin
4985 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_0]);
4986 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_1]);
4987 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_2]);
4988 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_3]);
4989 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_4]);
4990 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_5]);
4991 end
4992 else if KeyName = _lc[I_PROP_TR_SHOT_TO] then
4993 begin
4994 Values.Add(_lc[I_PROP_TR_SHOT_TO_0]);
4995 Values.Add(_lc[I_PROP_TR_SHOT_TO_1]);
4996 Values.Add(_lc[I_PROP_TR_SHOT_TO_2]);
4997 Values.Add(_lc[I_PROP_TR_SHOT_TO_3]);
4998 Values.Add(_lc[I_PROP_TR_SHOT_TO_4]);
4999 Values.Add(_lc[I_PROP_TR_SHOT_TO_5]);
5000 Values.Add(_lc[I_PROP_TR_SHOT_TO_6]);
5001 end
5002 else if KeyName = _lc[I_PROP_TR_SHOT_AIM] then
5003 begin
5004 Values.Add(_lc[I_PROP_TR_SHOT_AIM_0]);
5005 Values.Add(_lc[I_PROP_TR_SHOT_AIM_1]);
5006 Values.Add(_lc[I_PROP_TR_SHOT_AIM_2]);
5007 Values.Add(_lc[I_PROP_TR_SHOT_AIM_3]);
5008 end
5009 else if KeyName = _lc[I_PROP_TR_DAMAGE_KIND] then
5010 begin
5011 Values.Add(_lc[I_PROP_TR_DAMAGE_KIND_0]);
5012 Values.Add(_lc[I_PROP_TR_DAMAGE_KIND_3]);
5013 Values.Add(_lc[I_PROP_TR_DAMAGE_KIND_4]);
5014 Values.Add(_lc[I_PROP_TR_DAMAGE_KIND_5]);
5015 Values.Add(_lc[I_PROP_TR_DAMAGE_KIND_6]);
5016 Values.Add(_lc[I_PROP_TR_DAMAGE_KIND_7]);
5017 Values.Add(_lc[I_PROP_TR_DAMAGE_KIND_8]);
5018 end
5019 else if (KeyName = _lc[I_PROP_PANEL_BLEND]) or
5020 (KeyName = _lc[I_PROP_DM_ONLY]) or
5021 (KeyName = _lc[I_PROP_ITEM_FALLS]) or
5022 (KeyName = _lc[I_PROP_TR_ENABLED]) or
5023 (KeyName = _lc[I_PROP_TR_D2D]) or
5024 (KeyName = _lc[I_PROP_TR_SILENT]) or
5025 (KeyName = _lc[I_PROP_TR_TELEPORT_SILENT]) or
5026 (KeyName = _lc[I_PROP_TR_EX_RANDOM]) or
5027 (KeyName = _lc[I_PROP_TR_TEXTURE_ONCE]) or
5028 (KeyName = _lc[I_PROP_TR_TEXTURE_ANIM_ONCE]) or
5029 (KeyName = _lc[I_PROP_TR_SOUND_LOCAL]) or
5030 (KeyName = _lc[I_PROP_TR_SOUND_SWITCH]) or
5031 (KeyName = _lc[I_PROP_TR_MONSTER_ACTIVE]) or
5032 (KeyName = _lc[I_PROP_TR_PUSH_RESET]) or
5033 (KeyName = _lc[I_PROP_TR_SCORE_CON]) or
5034 (KeyName = _lc[I_PROP_TR_SCORE_MSG]) or
5035 (KeyName = _lc[I_PROP_TR_HEALTH_MAX]) or
5036 (KeyName = _lc[I_PROP_TR_SHOT_SOUND]) or
5037 (KeyName = _lc[I_PROP_TR_EFFECT_CENTER]) then
5038 begin
5039 Values.Add(BoolNames[True]);
5040 Values.Add(BoolNames[False]);
5041 end;
5042 end;
5043 end;
5045 procedure TMainForm.bApplyPropertyClick(Sender: TObject);
5046 var
5047 _id, a, r, c: Integer;
5048 s: String;
5049 res: Boolean;
5050 NoTextureID: DWORD;
5051 NW, NH: Word;
5052 begin
5053 NoTextureID := 0;
5054 NW := 0;
5055 NH := 0;
5057 if SelectedObjectCount() <> 1 then
5058 Exit;
5059 if not SelectedObjects[GetFirstSelected()].Live then
5060 Exit;
5062 try
5063 if not CheckProperty() then
5064 Exit;
5065 except
5066 Exit;
5067 end;
5069 _id := GetFirstSelected();
5071 r := vleObjectProperty.Row;
5072 c := vleObjectProperty.Col;
5074 case SelectedObjects[_id].ObjectType of
5075 OBJECT_PANEL:
5076 begin
5077 with gPanels[SelectedObjects[_id].ID] do
5078 begin
5079 X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
5080 Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
5081 Width := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_WIDTH]]));
5082 Height := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_HEIGHT]]));
5084 PanelType := GetPanelType(vleObjectProperty.Values[_lc[I_PROP_PANEL_TYPE]]);
5086 // Сброс ссылки на триггеры смены текстуры:
5087 if not WordBool(PanelType and (PANEL_WALL or PANEL_FORE or PANEL_BACK)) then
5088 if gTriggers <> nil then
5089 for a := 0 to High(gTriggers) do
5090 begin
5091 if (gTriggers[a].TriggerType <> 0) and
5092 (gTriggers[a].TexturePanel = Integer(SelectedObjects[_id].ID)) then
5093 gTriggers[a].TexturePanel := -1;
5094 if (gTriggers[a].TriggerType = TRIGGER_SHOT) and
5095 (gTriggers[a].Data.ShotPanelID = Integer(SelectedObjects[_id].ID)) then
5096 gTriggers[a].Data.ShotPanelID := -1;
5097 end;
5099 // Сброс ссылки на триггеры лифта:
5100 if not WordBool(PanelType and (PANEL_LIFTUP or PANEL_LIFTDOWN or PANEL_LIFTLEFT or PANEL_LIFTRIGHT)) then
5101 if gTriggers <> nil then
5102 for a := 0 to High(gTriggers) do
5103 if (gTriggers[a].TriggerType in [TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT]) and
5104 (gTriggers[a].Data.PanelID = Integer(SelectedObjects[_id].ID)) then
5105 gTriggers[a].Data.PanelID := -1;
5107 // Сброс ссылки на триггеры двери:
5108 if not WordBool(PanelType and (PANEL_OPENDOOR or PANEL_CLOSEDOOR)) then
5109 if gTriggers <> nil then
5110 for a := 0 to High(gTriggers) do
5111 if (gTriggers[a].TriggerType in [TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
5112 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP]) and
5113 (gTriggers[a].Data.PanelID = Integer(SelectedObjects[_id].ID)) then
5114 gTriggers[a].Data.PanelID := -1;
5116 if IsTexturedPanel(PanelType) then
5117 begin // Может быть текстура
5118 if TextureName <> '' then
5119 begin // Была текстура
5120 Alpha := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_PANEL_ALPHA]]));
5121 Blending := NameToBool(vleObjectProperty.Values[_lc[I_PROP_PANEL_BLEND]]);
5122 end
5123 else // Не было
5124 begin
5125 Alpha := 0;
5126 Blending := False;
5127 end;
5129 // Новая текстура:
5130 TextureName := vleObjectProperty.Values[_lc[I_PROP_PANEL_TEX]];
5132 if TextureName <> '' then
5133 begin // Есть текстура
5134 // Обычная текстура:
5135 if not IsSpecialTexture(TextureName) then
5136 begin
5137 g_GetTextureSizeByName(TextureName,
5138 TextureWidth, TextureHeight);
5140 // Проверка кратности размеров панели:
5141 res := True;
5142 if TextureWidth <> 0 then
5143 if gPanels[SelectedObjects[_id].ID].Width mod TextureWidth <> 0 then
5144 begin
5145 ErrorMessageBox(Format(_lc[I_MSG_WRONG_TEXWIDTH],
5146 [TextureWidth]));
5147 Res := False;
5148 end;
5149 if Res and (TextureHeight <> 0) then
5150 if gPanels[SelectedObjects[_id].ID].Height mod TextureHeight <> 0 then
5151 begin
5152 ErrorMessageBox(Format(_lc[I_MSG_WRONG_TEXHEIGHT],
5153 [TextureHeight]));
5154 Res := False;
5155 end;
5157 if Res then
5158 begin
5159 if not g_GetTexture(TextureName, TextureID) then
5160 // Не удалось загрузить текстуру, рисуем NOTEXTURE
5161 if g_GetTexture('NOTEXTURE', NoTextureID) then
5162 begin
5163 TextureID := TEXTURE_SPECIAL_NOTEXTURE;
5164 g_GetTextureSizeByID(NoTextureID, NW, NH);
5165 TextureWidth := NW;
5166 TextureHeight := NH;
5167 end else
5168 begin
5169 TextureID := TEXTURE_SPECIAL_NONE;
5170 TextureWidth := 1;
5171 TextureHeight := 1;
5172 end;
5173 end
5174 else
5175 begin
5176 TextureName := '';
5177 TextureWidth := 1;
5178 TextureHeight := 1;
5179 TextureID := TEXTURE_SPECIAL_NONE;
5180 end;
5181 end
5182 else // Спец.текстура
5183 begin
5184 TextureHeight := 1;
5185 TextureWidth := 1;
5186 TextureID := SpecialTextureID(TextureName);
5187 end;
5188 end
5189 else // Нет текстуры
5190 begin
5191 TextureWidth := 1;
5192 TextureHeight := 1;
5193 TextureID := TEXTURE_SPECIAL_NONE;
5194 end;
5195 end
5196 else // Не может быть текстуры
5197 begin
5198 Alpha := 0;
5199 Blending := False;
5200 TextureName := '';
5201 TextureWidth := 1;
5202 TextureHeight := 1;
5203 TextureID := TEXTURE_SPECIAL_NONE;
5204 end;
5205 end;
5206 end;
5208 OBJECT_ITEM:
5209 begin
5210 with gItems[SelectedObjects[_id].ID] do
5211 begin
5212 X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
5213 Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
5214 OnlyDM := NameToBool(vleObjectProperty.Values[_lc[I_PROP_DM_ONLY]]);
5215 Fall := NameToBool(vleObjectProperty.Values[_lc[I_PROP_ITEM_FALLS]]);
5216 end;
5217 end;
5219 OBJECT_MONSTER:
5220 begin
5221 with gMonsters[SelectedObjects[_id].ID] do
5222 begin
5223 X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
5224 Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
5225 Direction := NameToDir(vleObjectProperty.Values[_lc[I_PROP_DIRECTION]]);
5226 end;
5227 end;
5229 OBJECT_AREA:
5230 begin
5231 with gAreas[SelectedObjects[_id].ID] do
5232 begin
5233 X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
5234 Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
5235 Direction := NameToDir(vleObjectProperty.Values[_lc[I_PROP_DIRECTION]]);
5236 end;
5237 end;
5239 OBJECT_TRIGGER:
5240 begin
5241 with gTriggers[SelectedObjects[_id].ID] do
5242 begin
5243 X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
5244 Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
5245 Width := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_WIDTH]]));
5246 Height := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_HEIGHT]]));
5247 Enabled := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_ENABLED]]);
5248 ActivateType := StrToActivate(vleObjectProperty.Values[_lc[I_PROP_TR_ACTIVATION]]);
5249 Key := StrToKey(vleObjectProperty.Values[_lc[I_PROP_TR_KEYS]]);
5251 case TriggerType of
5252 TRIGGER_EXIT:
5253 begin
5254 s := utf2win(vleObjectProperty.Values[_lc[I_PROP_TR_NEXT_MAP]]);
5255 FillByte(Data.MapName[0], 16, 0);
5256 if s <> '' then
5257 Move(s[1], Data.MapName[0], Min(Length(s), 16));
5258 end;
5260 TRIGGER_TEXTURE:
5261 begin
5262 Data.ActivateOnce := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_TEXTURE_ONCE]]);
5263 Data.AnimOnce := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_TEXTURE_ANIM_ONCE]]);
5264 end;
5266 TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF:
5267 begin
5268 Data.Wait := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EX_DELAY]], 0), 65535);
5269 Data.Count := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EX_COUNT]], 0), 65535);
5270 if Data.Count < 1 then
5271 Data.Count := 1;
5272 if TriggerType = TRIGGER_PRESS then
5273 Data.ExtRandom := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_EX_RANDOM]]);
5274 end;
5276 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR, TRIGGER_DOOR5,
5277 TRIGGER_CLOSETRAP, TRIGGER_TRAP, TRIGGER_LIFTUP, TRIGGER_LIFTDOWN,
5278 TRIGGER_LIFT:
5279 begin
5280 Data.NoSound := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SILENT]]);
5281 Data.d2d_doors := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_D2D]]);
5282 end;
5284 TRIGGER_TELEPORT:
5285 begin
5286 Data.d2d_teleport := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_D2D]]);
5287 Data.silent_teleport := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_TELEPORT_SILENT]]);
5288 Data.TlpDir := NameToDirAdv(vleObjectProperty.Values[_lc[I_PROP_TR_TELEPORT_DIR]]);
5289 end;
5291 TRIGGER_SOUND:
5292 begin
5293 s := utf2win(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_NAME]]);
5294 FillByte(Data.SoundName[0], 64, 0);
5295 if s <> '' then
5296 Move(s[1], Data.SoundName[0], Min(Length(s), 64));
5298 Data.Volume := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_VOLUME]], 0), 255);
5299 Data.Pan := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_PAN]], 0), 255);
5300 Data.PlayCount := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_COUNT]], 0), 255);
5301 Data.Local := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_LOCAL]]);
5302 Data.SoundSwitch := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_SWITCH]]);
5303 end;
5305 TRIGGER_SPAWNMONSTER:
5306 begin
5307 Data.MonType := StrToMonster(vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_TYPE]]);
5308 Data.MonDir := Byte(NameToDir(vleObjectProperty.Values[_lc[I_PROP_DIRECTION]]));
5309 Data.MonHealth := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_HEALTH]], 0), 1000000);
5310 if Data.MonHealth < 0 then
5311 Data.MonHealth := 0;
5312 Data.MonActive := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_ACTIVE]]);
5313 Data.MonCount := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_COUNT]], 0), 64);
5314 if Data.MonCount < 1 then
5315 Data.MonCount := 1;
5316 Data.MonEffect := StrToEffect(vleObjectProperty.Values[_lc[I_PROP_TR_FX_TYPE]]);
5317 Data.MonMax := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SPAWN_MAX]], 0), 65535);
5318 Data.MonDelay := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SPAWN_DELAY]], 0), 65535);
5319 Data.MonBehav := 0;
5320 if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_1] then
5321 Data.MonBehav := 1;
5322 if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_2] then
5323 Data.MonBehav := 2;
5324 if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_3] then
5325 Data.MonBehav := 3;
5326 if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_4] then
5327 Data.MonBehav := 4;
5328 if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_5] then
5329 Data.MonBehav := 5;
5330 end;
5332 TRIGGER_SPAWNITEM:
5333 begin
5334 Data.ItemType := StrToItem(vleObjectProperty.Values[_lc[I_PROP_TR_ITEM_TYPE]]);
5335 Data.ItemOnlyDM := NameToBool(vleObjectProperty.Values[_lc[I_PROP_DM_ONLY]]);
5336 Data.ItemFalls := NameToBool(vleObjectProperty.Values[_lc[I_PROP_ITEM_FALLS]]);
5337 Data.ItemCount := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_COUNT]], 0), 64);
5338 if Data.ItemCount < 1 then
5339 Data.ItemCount := 1;
5340 Data.ItemEffect := StrToEffect(vleObjectProperty.Values[_lc[I_PROP_TR_FX_TYPE]]);
5341 Data.ItemMax := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SPAWN_MAX]], 0), 65535);
5342 Data.ItemDelay := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SPAWN_DELAY]], 0), 65535);
5343 end;
5345 TRIGGER_MUSIC:
5346 begin
5347 s := utf2win(vleObjectProperty.Values[_lc[I_PROP_TR_MUSIC_NAME]]);
5348 FillByte(Data.MusicName[0], 64, 0);
5349 if s <> '' then
5350 Move(s[1], Data.MusicName[0], Min(Length(s), 64));
5352 if vleObjectProperty.Values[_lc[I_PROP_TR_MUSIC_ACT]] = _lc[I_PROP_TR_MUSIC_ON] then
5353 Data.MusicAction := 1
5354 else
5355 Data.MusicAction := 0;
5356 end;
5358 TRIGGER_PUSH:
5359 begin
5360 Data.PushAngle := Min(
5361 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_PUSH_ANGLE]], 0), 360);
5362 Data.PushForce := Min(
5363 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_PUSH_FORCE]], 0), 255);
5364 Data.ResetVel := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_PUSH_RESET]]);
5365 end;
5367 TRIGGER_SCORE:
5368 begin
5369 Data.ScoreAction := 0;
5370 if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_ACT]] = _lc[I_PROP_TR_SCORE_ACT_1] then
5371 Data.ScoreAction := 1
5372 else if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_ACT]] = _lc[I_PROP_TR_SCORE_ACT_2] then
5373 Data.ScoreAction := 2
5374 else if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_ACT]] = _lc[I_PROP_TR_SCORE_ACT_3] then
5375 Data.ScoreAction := 3;
5376 Data.ScoreCount := Min(Max(
5377 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_COUNT]], 0), 0), 255);
5378 Data.ScoreTeam := 0;
5379 if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_TEAM]] = _lc[I_PROP_TR_SCORE_TEAM_1] then
5380 Data.ScoreTeam := 1
5381 else if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_TEAM]] = _lc[I_PROP_TR_SCORE_TEAM_2] then
5382 Data.ScoreTeam := 2
5383 else if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_TEAM]] = _lc[I_PROP_TR_SCORE_TEAM_3] then
5384 Data.ScoreTeam := 3;
5385 Data.ScoreCon := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_CON]]);
5386 Data.ScoreMsg := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_MSG]]);
5387 end;
5389 TRIGGER_MESSAGE:
5390 begin
5391 Data.MessageKind := 0;
5392 if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_KIND]] = _lc[I_PROP_TR_MESSAGE_KIND_1] then
5393 Data.MessageKind := 1;
5395 Data.MessageSendTo := 0;
5396 if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_1] then
5397 Data.MessageSendTo := 1
5398 else if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_2] then
5399 Data.MessageSendTo := 2
5400 else if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_3] then
5401 Data.MessageSendTo := 3
5402 else if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_4] then
5403 Data.MessageSendTo := 4
5404 else if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_5] then
5405 Data.MessageSendTo := 5;
5407 s := utf2win(vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TEXT]]);
5408 FillByte(Data.MessageText[0], 100, 0);
5409 if s <> '' then
5410 Move(s[1], Data.MessageText[0], Min(Length(s), 100));
5412 Data.MessageTime := Min(Max(
5413 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TIME]], 0), 0), 65535);
5414 end;
5416 TRIGGER_DAMAGE:
5417 begin
5418 Data.DamageValue := Min(Max(
5419 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_DAMAGE_VALUE]], 0), 0), 65535);
5420 Data.DamageInterval := Min(Max(
5421 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_INTERVAL]], 0), 0), 65535);
5422 s := vleObjectProperty.Values[_lc[I_PROP_TR_DAMAGE_KIND]];
5423 if s = _lc[I_PROP_TR_DAMAGE_KIND_3] then
5424 Data.DamageKind := 3
5425 else if s = _lc[I_PROP_TR_DAMAGE_KIND_4] then
5426 Data.DamageKind := 4
5427 else if s = _lc[I_PROP_TR_DAMAGE_KIND_5] then
5428 Data.DamageKind := 5
5429 else if s = _lc[I_PROP_TR_DAMAGE_KIND_6] then
5430 Data.DamageKind := 6
5431 else if s = _lc[I_PROP_TR_DAMAGE_KIND_7] then
5432 Data.DamageKind := 7
5433 else if s = _lc[I_PROP_TR_DAMAGE_KIND_8] then
5434 Data.DamageKind := 8
5435 else
5436 Data.DamageKind := 0;
5437 end;
5439 TRIGGER_HEALTH:
5440 begin
5441 Data.HealValue := Min(Max(
5442 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_HEALTH]], 0), 0), 65535);
5443 Data.HealInterval := Min(Max(
5444 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_INTERVAL]], 0), 0), 65535);
5445 Data.HealMax := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_HEALTH_MAX]]);
5446 Data.HealSilent := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SILENT]]);
5447 end;
5449 TRIGGER_SHOT:
5450 begin
5451 Data.ShotType := StrToShot(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TYPE]]);
5452 Data.ShotSound := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_SOUND]]);
5453 Data.ShotTarget := 0;
5454 if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_1] then
5455 Data.ShotTarget := 1
5456 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_2] then
5457 Data.ShotTarget := 2
5458 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_3] then
5459 Data.ShotTarget := 3
5460 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_4] then
5461 Data.ShotTarget := 4
5462 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_5] then
5463 Data.ShotTarget := 5
5464 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_6] then
5465 Data.ShotTarget := 6;
5466 Data.ShotIntSight := Min(Max(
5467 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_SIGHT]], 0), 0), 65535);
5468 Data.ShotAim := 0;
5469 if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_AIM]] = _lc[I_PROP_TR_SHOT_AIM_1] then
5470 Data.ShotAim := 1
5471 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_AIM]] = _lc[I_PROP_TR_SHOT_AIM_2] then
5472 Data.ShotAim := 2
5473 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_AIM]] = _lc[I_PROP_TR_SHOT_AIM_3] then
5474 Data.ShotAim := 3;
5475 Data.ShotAngle := Min(
5476 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_ANGLE]], 0), 360);
5477 Data.ShotWait := Min(Max(
5478 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EX_DELAY]], 0), 0), 65535);
5479 Data.ShotAccuracy := Min(Max(
5480 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_ACC]], 0), 0), 65535);
5481 Data.ShotAmmo := Min(Max(
5482 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_AMMO]], 0), 0), 65535);
5483 Data.ShotIntReload := Min(Max(
5484 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_RELOAD]], 0), 0), 65535);
5485 end;
5487 TRIGGER_EFFECT:
5488 begin
5489 Data.FXCount := Min(Max(
5490 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_COUNT]], 0), 0), 255);
5491 if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_TYPE]] = _lc[I_PROP_TR_EFFECT_PARTICLE] then
5492 begin
5493 Data.FXType := TRIGGER_EFFECT_PARTICLE;
5494 Data.FXSubType := TRIGGER_EFFECT_SLIQUID;
5495 if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_SLIQUID] then
5496 Data.FXSubType := TRIGGER_EFFECT_SLIQUID
5497 else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_LLIQUID] then
5498 Data.FXSubType := TRIGGER_EFFECT_LLIQUID
5499 else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_DLIQUID] then
5500 Data.FXSubType := TRIGGER_EFFECT_DLIQUID
5501 else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_BLOOD] then
5502 Data.FXSubType := TRIGGER_EFFECT_BLOOD
5503 else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_SPARK] then
5504 Data.FXSubType := TRIGGER_EFFECT_SPARK
5505 else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_BUBBLE] then
5506 Data.FXSubType := TRIGGER_EFFECT_BUBBLE;
5507 end else
5508 begin
5509 Data.FXType := TRIGGER_EFFECT_ANIMATION;
5510 Data.FXSubType := StrToEffect(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]]);
5511 end;
5512 a := Min(Max(
5513 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_COLOR]], 0), 0), $FFFFFF);
5514 Data.FXColorR := a and $FF;
5515 Data.FXColorG := (a shr 8) and $FF;
5516 Data.FXColorB := (a shr 16) and $FF;
5517 if NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_CENTER]]) then
5518 Data.FXPos := 0
5519 else
5520 Data.FXPos := 1;
5521 Data.FXWait := Min(Max(
5522 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EX_DELAY]], 0), 0), 65535);
5523 Data.FXVelX := Min(Max(
5524 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_VELX]], 0), -128), 127);
5525 Data.FXVelY := Min(Max(
5526 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_VELY]], 0), -128), 127);
5527 Data.FXSpreadL := Min(Max(
5528 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SPL]], 0), 0), 255);
5529 Data.FXSpreadR := Min(Max(
5530 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SPR]], 0), 0), 255);
5531 Data.FXSpreadU := Min(Max(
5532 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SPU]], 0), 0), 255);
5533 Data.FXSpreadD := Min(Max(
5534 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SPD]], 0), 0), 255);
5535 end;
5536 end;
5537 end;
5538 end;
5539 end;
5541 FillProperty();
5543 vleObjectProperty.Row := r;
5544 vleObjectProperty.Col := c;
5545 end;
5547 procedure TMainForm.bbRemoveTextureClick(Sender: TObject);
5548 var
5549 a, i: Integer;
5550 begin
5551 i := lbTextureList.ItemIndex;
5552 if i = -1 then
5553 Exit;
5555 if Application.MessageBox(PChar(Format(_lc[I_MSG_DEL_TEXTURE_PROMT],
5556 [SelectedTexture()])),
5557 PChar(_lc[I_MSG_DEL_TEXTURE]),
5558 MB_ICONQUESTION or MB_YESNO or
5559 MB_DEFBUTTON1) <> idYes then
5560 Exit;
5562 if gPanels <> nil then
5563 for a := 0 to High(gPanels) do
5564 if (gPanels[a].PanelType <> 0) and
5565 (gPanels[a].TextureName = SelectedTexture()) then
5566 begin
5567 ErrorMessageBox(_lc[I_MSG_DEL_TEXTURE_CANT]);
5568 Exit;
5569 end;
5571 g_DeleteTexture(SelectedTexture());
5572 i := slInvalidTextures.IndexOf(lbTextureList.Items[i]);
5573 if i > -1 then
5574 slInvalidTextures.Delete(i);
5575 if lbTextureList.ItemIndex > -1 then
5576 lbTextureList.Items.Delete(lbTextureList.ItemIndex)
5577 end;
5579 procedure TMainForm.aNewMapExecute(Sender: TObject);
5580 begin
5581 if Application.MessageBox(PChar(_lc[I_MSG_CLEAR_MAP_PROMT]), PChar(_lc[I_MSG_CLEAR_MAP]), MB_ICONQUESTION or MB_YESNO or MB_DEFBUTTON1) = mrYes then
5582 FullClear();
5583 end;
5585 procedure TMainForm.aUndoExecute(Sender: TObject);
5586 var
5587 a: Integer;
5588 begin
5589 if UndoBuffer = nil then
5590 Exit;
5591 if UndoBuffer[High(UndoBuffer)] = nil then
5592 Exit;
5594 for a := 0 to High(UndoBuffer[High(UndoBuffer)]) do
5595 with UndoBuffer[High(UndoBuffer)][a] do
5596 begin
5597 case UndoType of
5598 UNDO_DELETE_PANEL:
5599 begin
5600 AddPanel(Panel^);
5601 Panel := nil;
5602 end;
5603 UNDO_DELETE_ITEM: AddItem(Item);
5604 UNDO_DELETE_AREA: AddArea(Area);
5605 UNDO_DELETE_MONSTER: AddMonster(Monster);
5606 UNDO_DELETE_TRIGGER: AddTrigger(Trigger);
5607 UNDO_ADD_PANEL: RemoveObject(AddID, OBJECT_PANEL);
5608 UNDO_ADD_ITEM: RemoveObject(AddID, OBJECT_ITEM);
5609 UNDO_ADD_AREA: RemoveObject(AddID, OBJECT_AREA);
5610 UNDO_ADD_MONSTER: RemoveObject(AddID, OBJECT_MONSTER);
5611 UNDO_ADD_TRIGGER: RemoveObject(AddID, OBJECT_TRIGGER);
5612 end;
5613 end;
5615 SetLength(UndoBuffer, Length(UndoBuffer)-1);
5617 RemoveSelectFromObjects();
5619 miUndo.Enabled := UndoBuffer <> nil;
5620 end;
5623 procedure TMainForm.aCopyObjectExecute(Sender: TObject);
5624 var
5625 a, b: Integer;
5626 CopyBuffer: TCopyRecArray;
5627 str: String;
5628 ok: Boolean;
5630 function CB_Compare(I1, I2: TCopyRec): Integer;
5631 begin
5632 Result := Integer(I1.ObjectType) - Integer(I2.ObjectType);
5634 if Result = 0 then // Одного типа
5635 Result := Integer(I1.ID) - Integer(I2.ID);
5636 end;
5638 procedure QuickSortCopyBuffer(L, R: Integer);
5639 var
5640 I, J: Integer;
5641 P, T: TCopyRec;
5642 begin
5643 repeat
5644 I := L;
5645 J := R;
5646 P := CopyBuffer[(L + R) shr 1];
5648 repeat
5649 while CB_Compare(CopyBuffer[I], P) < 0 do
5650 Inc(I);
5651 while CB_Compare(CopyBuffer[J], P) > 0 do
5652 Dec(J);
5654 if I <= J then
5655 begin
5656 T := CopyBuffer[I];
5657 CopyBuffer[I] := CopyBuffer[J];
5658 CopyBuffer[J] := T;
5659 Inc(I);
5660 Dec(J);
5661 end;
5662 until I > J;
5664 if L < J then
5665 QuickSortCopyBuffer(L, J);
5667 L := I;
5668 until I >= R;
5669 end;
5671 begin
5672 if SelectedObjects = nil then
5673 Exit;
5675 b := -1;
5676 CopyBuffer := nil;
5678 // Копируем объекты:
5679 for a := 0 to High(SelectedObjects) do
5680 if SelectedObjects[a].Live then
5681 with SelectedObjects[a] do
5682 begin
5683 SetLength(CopyBuffer, Length(CopyBuffer)+1);
5684 b := High(CopyBuffer);
5685 CopyBuffer[b].ID := ID;
5686 CopyBuffer[b].Panel := nil;
5688 case ObjectType of
5689 OBJECT_PANEL:
5690 begin
5691 CopyBuffer[b].ObjectType := OBJECT_PANEL;
5692 New(CopyBuffer[b].Panel);
5693 CopyBuffer[b].Panel^ := gPanels[ID];
5694 end;
5696 OBJECT_ITEM:
5697 begin
5698 CopyBuffer[b].ObjectType := OBJECT_ITEM;
5699 CopyBuffer[b].Item := gItems[ID];
5700 end;
5702 OBJECT_MONSTER:
5703 begin
5704 CopyBuffer[b].ObjectType := OBJECT_MONSTER;
5705 CopyBuffer[b].Monster := gMonsters[ID];
5706 end;
5708 OBJECT_AREA:
5709 begin
5710 CopyBuffer[b].ObjectType := OBJECT_AREA;
5711 CopyBuffer[b].Area := gAreas[ID];
5712 end;
5714 OBJECT_TRIGGER:
5715 begin
5716 CopyBuffer[b].ObjectType := OBJECT_TRIGGER;
5717 CopyBuffer[b].Trigger := gTriggers[ID];
5718 end;
5719 end;
5720 end;
5722 // Сортировка по ID:
5723 if CopyBuffer <> nil then
5724 begin
5725 QuickSortCopyBuffer(0, b);
5726 end;
5728 // Пестановка ссылок триггеров:
5729 for a := 0 to Length(CopyBuffer)-1 do
5730 if CopyBuffer[a].ObjectType = OBJECT_TRIGGER then
5731 begin
5732 case CopyBuffer[a].Trigger.TriggerType of
5733 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
5734 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP,
5735 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
5736 if CopyBuffer[a].Trigger.Data.PanelID <> -1 then
5737 begin
5738 ok := False;
5740 for b := 0 to Length(CopyBuffer)-1 do
5741 if (CopyBuffer[b].ObjectType = OBJECT_PANEL) and
5742 (Integer(CopyBuffer[b].ID) = CopyBuffer[a].Trigger.Data.PanelID) then
5743 begin
5744 CopyBuffer[a].Trigger.Data.PanelID := b;
5745 ok := True;
5746 Break;
5747 end;
5749 // Этих панелей нет среди копируемых:
5750 if not ok then
5751 CopyBuffer[a].Trigger.Data.PanelID := -1;
5752 end;
5754 TRIGGER_PRESS, TRIGGER_ON,
5755 TRIGGER_OFF, TRIGGER_ONOFF:
5756 if CopyBuffer[a].Trigger.Data.MonsterID <> 0 then
5757 begin
5758 ok := False;
5760 for b := 0 to Length(CopyBuffer)-1 do
5761 if (CopyBuffer[b].ObjectType = OBJECT_MONSTER) and
5762 (Integer(CopyBuffer[b].ID) = CopyBuffer[a].Trigger.Data.MonsterID-1) then
5763 begin
5764 CopyBuffer[a].Trigger.Data.MonsterID := b+1;
5765 ok := True;
5766 Break;
5767 end;
5769 // Этих монстров нет среди копируемых:
5770 if not ok then
5771 CopyBuffer[a].Trigger.Data.MonsterID := 0;
5772 end;
5774 TRIGGER_SHOT:
5775 if CopyBuffer[a].Trigger.Data.ShotPanelID <> -1 then
5776 begin
5777 ok := False;
5779 for b := 0 to Length(CopyBuffer)-1 do
5780 if (CopyBuffer[b].ObjectType = OBJECT_PANEL) and
5781 (Integer(CopyBuffer[b].ID) = CopyBuffer[a].Trigger.Data.ShotPanelID) then
5782 begin
5783 CopyBuffer[a].Trigger.Data.ShotPanelID := b;
5784 ok := True;
5785 Break;
5786 end;
5788 // Этих панелей нет среди копируемых:
5789 if not ok then
5790 CopyBuffer[a].Trigger.Data.ShotPanelID := -1;
5791 end;
5792 end;
5794 if CopyBuffer[a].Trigger.TexturePanel <> -1 then
5795 begin
5796 ok := False;
5798 for b := 0 to Length(CopyBuffer)-1 do
5799 if (CopyBuffer[b].ObjectType = OBJECT_PANEL) and
5800 (Integer(CopyBuffer[b].ID) = CopyBuffer[a].Trigger.TexturePanel) then
5801 begin
5802 CopyBuffer[a].Trigger.TexturePanel := b;
5803 ok := True;
5804 Break;
5805 end;
5807 // Этих панелей нет среди копируемых:
5808 if not ok then
5809 CopyBuffer[a].Trigger.TexturePanel := -1;
5810 end;
5811 end;
5813 // В буфер обмена:
5814 str := CopyBufferToString(CopyBuffer);
5815 ClipBoard.AsText := str;
5817 for a := 0 to Length(CopyBuffer)-1 do
5818 if (CopyBuffer[a].ObjectType = OBJECT_PANEL) and
5819 (CopyBuffer[a].Panel <> nil) then
5820 Dispose(CopyBuffer[a].Panel);
5822 CopyBuffer := nil;
5823 end;
5825 procedure TMainForm.aPasteObjectExecute(Sender: TObject);
5826 var
5827 a, h: Integer;
5828 CopyBuffer: TCopyRecArray;
5829 res, rel: Boolean;
5830 swad, ssec, sres: String;
5831 NoTextureID: DWORD;
5832 pmin: TPoint;
5833 begin
5834 CopyBuffer := nil;
5835 NoTextureID := 0;
5836 pmin.X := High(pmin.X);
5837 pmin.Y := High(pmin.Y);
5839 StringToCopyBuffer(ClipBoard.AsText, CopyBuffer, pmin);
5840 rel := not(ssShift in GetKeyShiftState());
5842 if CopyBuffer = nil then
5843 Exit;
5845 RemoveSelectFromObjects();
5847 h := High(CopyBuffer);
5848 for a := 0 to h do
5849 with CopyBuffer[a] do
5850 begin
5851 case ObjectType of
5852 OBJECT_PANEL:
5853 if Panel <> nil then
5854 begin
5855 if rel then
5856 begin
5857 Panel^.X := Panel^.X - pmin.X - MapOffset.X + 32;
5858 Panel^.Y := Panel^.Y - pmin.Y - MapOffset.Y + 32;
5859 end;
5861 Panel^.TextureID := TEXTURE_SPECIAL_NONE;
5862 Panel^.TextureWidth := 1;
5863 Panel^.TextureHeight := 1;
5865 if (Panel^.PanelType = PANEL_LIFTUP) or
5866 (Panel^.PanelType = PANEL_LIFTDOWN) or
5867 (Panel^.PanelType = PANEL_LIFTLEFT) or
5868 (Panel^.PanelType = PANEL_LIFTRIGHT) or
5869 (Panel^.PanelType = PANEL_BLOCKMON) or
5870 (Panel^.TextureName = '') then
5871 begin // Нет или не может быть текстуры:
5872 end
5873 else // Есть текстура:
5874 begin
5875 // Обычная текстура:
5876 if not IsSpecialTexture(Panel^.TextureName) then
5877 begin
5878 res := g_GetTexture(Panel^.TextureName, Panel^.TextureID);
5880 if not res then
5881 begin
5882 g_ProcessResourceStr(Panel^.TextureName, swad, ssec, sres);
5883 AddTexture(swad, ssec, sres, True);
5884 res := g_GetTexture(Panel^.TextureName, Panel^.TextureID);
5885 end;
5887 if res then
5888 g_GetTextureSizeByName(Panel^.TextureName,
5889 Panel^.TextureWidth, Panel^.TextureHeight)
5890 else
5891 if g_GetTexture('NOTEXTURE', NoTextureID) then
5892 begin
5893 Panel^.TextureID := TEXTURE_SPECIAL_NOTEXTURE;
5894 g_GetTextureSizeByID(NoTextureID, Panel^.TextureWidth, Panel^.TextureHeight);
5895 end;
5896 end
5897 else // Спец.текстура:
5898 begin
5899 Panel^.TextureID := SpecialTextureID(Panel^.TextureName);
5900 with MainForm.lbTextureList.Items do
5901 if IndexOf(Panel^.TextureName) = -1 then
5902 Add(Panel^.TextureName);
5903 end;
5904 end;
5906 ID := AddPanel(Panel^);
5907 Dispose(Panel);
5908 Undo_Add(OBJECT_PANEL, ID, a > 0);
5909 SelectObject(OBJECT_PANEL, ID, True);
5910 end;
5912 OBJECT_ITEM:
5913 begin
5914 if rel then
5915 begin
5916 Item.X := Item.X - pmin.X - MapOffset.X + 32;
5917 Item.Y := Item.Y - pmin.Y - MapOffset.Y + 32;
5918 end;
5920 ID := AddItem(Item);
5921 Undo_Add(OBJECT_ITEM, ID, a > 0);
5922 SelectObject(OBJECT_ITEM, ID, True);
5923 end;
5925 OBJECT_MONSTER:
5926 begin
5927 if rel then
5928 begin
5929 Monster.X := Monster.X - pmin.X - MapOffset.X + 32;
5930 Monster.Y := Monster.Y - pmin.Y - MapOffset.Y + 32;
5931 end;
5933 ID := AddMonster(Monster);
5934 Undo_Add(OBJECT_MONSTER, ID, a > 0);
5935 SelectObject(OBJECT_MONSTER, ID, True);
5936 end;
5938 OBJECT_AREA:
5939 begin
5940 if rel then
5941 begin
5942 Area.X := Area.X - pmin.X - MapOffset.X + 32;
5943 Area.Y := Area.Y - pmin.Y - MapOffset.Y + 32;
5944 end;
5946 ID := AddArea(Area);
5947 Undo_Add(OBJECT_AREA, ID, a > 0);
5948 SelectObject(OBJECT_AREA, ID, True);
5949 end;
5951 OBJECT_TRIGGER:
5952 begin
5953 if rel then
5954 with Trigger do
5955 begin
5956 X := X - pmin.X - MapOffset.X + 32;
5957 Y := Y - pmin.Y - MapOffset.Y + 32;
5959 case TriggerType of
5960 TRIGGER_TELEPORT:
5961 begin
5962 Data.TargetPoint.X :=
5963 Data.TargetPoint.X - pmin.X - MapOffset.X + 32;
5964 Data.TargetPoint.Y :=
5965 Data.TargetPoint.Y - pmin.Y - MapOffset.Y + 32;
5966 end;
5967 TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF:
5968 begin
5969 Data.tX := Data.tX - pmin.X - MapOffset.X + 32;
5970 Data.tY := Data.tY - pmin.Y - MapOffset.Y + 32;
5971 end;
5972 TRIGGER_SPAWNMONSTER:
5973 begin
5974 Data.MonPos.X :=
5975 Data.MonPos.X - pmin.X - MapOffset.X + 32;
5976 Data.MonPos.Y :=
5977 Data.MonPos.Y - pmin.Y - MapOffset.Y + 32;
5978 end;
5979 TRIGGER_SPAWNITEM:
5980 begin
5981 Data.ItemPos.X :=
5982 Data.ItemPos.X - pmin.X - MapOffset.X + 32;
5983 Data.ItemPos.Y :=
5984 Data.ItemPos.Y - pmin.Y - MapOffset.Y + 32;
5985 end;
5986 TRIGGER_SHOT:
5987 begin
5988 Data.ShotPos.X :=
5989 Data.ShotPos.X - pmin.X - MapOffset.X + 32;
5990 Data.ShotPos.Y :=
5991 Data.ShotPos.Y - pmin.Y - MapOffset.Y + 32;
5992 end;
5993 end;
5994 end;
5996 ID := AddTrigger(Trigger);
5997 Undo_Add(OBJECT_TRIGGER, ID, a > 0);
5998 SelectObject(OBJECT_TRIGGER, ID, True);
5999 end;
6000 end;
6001 end;
6003 // Переставляем ссылки триггеров:
6004 for a := 0 to High(CopyBuffer) do
6005 if CopyBuffer[a].ObjectType = OBJECT_TRIGGER then
6006 begin
6007 case CopyBuffer[a].Trigger.TriggerType of
6008 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
6009 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP,
6010 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
6011 if CopyBuffer[a].Trigger.Data.PanelID <> -1 then
6012 gTriggers[CopyBuffer[a].ID].Data.PanelID :=
6013 CopyBuffer[CopyBuffer[a].Trigger.Data.PanelID].ID;
6015 TRIGGER_PRESS, TRIGGER_ON,
6016 TRIGGER_OFF, TRIGGER_ONOFF:
6017 if CopyBuffer[a].Trigger.Data.MonsterID <> 0 then
6018 gTriggers[CopyBuffer[a].ID].Data.MonsterID :=
6019 CopyBuffer[CopyBuffer[a].Trigger.Data.MonsterID-1].ID+1;
6021 TRIGGER_SHOT:
6022 if CopyBuffer[a].Trigger.Data.ShotPanelID <> -1 then
6023 gTriggers[CopyBuffer[a].ID].Data.ShotPanelID :=
6024 CopyBuffer[CopyBuffer[a].Trigger.Data.ShotPanelID].ID;
6025 end;
6027 if CopyBuffer[a].Trigger.TexturePanel <> -1 then
6028 gTriggers[CopyBuffer[a].ID].TexturePanel :=
6029 CopyBuffer[CopyBuffer[a].Trigger.TexturePanel].ID;
6030 end;
6032 CopyBuffer := nil;
6034 if h = 0 then
6035 FillProperty();
6036 end;
6038 procedure TMainForm.aCutObjectExecute(Sender: TObject);
6039 begin
6040 miCopy.Click();
6041 DeleteSelectedObjects();
6042 end;
6044 procedure TMainForm.vleObjectPropertyEditButtonClick(Sender: TObject);
6045 var
6046 Key, FileName: String;
6047 b: Byte;
6048 begin
6049 Key := vleObjectProperty.Keys[vleObjectProperty.Row];
6051 if Key = _lc[I_PROP_PANEL_TYPE] then
6052 begin
6053 with ChooseTypeForm, vleObjectProperty do
6054 begin // Выбор типа панели:
6055 Caption := _lc[I_PROP_PANEL_TYPE];
6056 lbTypeSelect.Items.Clear();
6058 for b := 0 to High(PANELNAMES) do
6059 begin
6060 lbTypeSelect.Items.Add(PANELNAMES[b]);
6061 if Values[Key] = PANELNAMES[b] then
6062 lbTypeSelect.ItemIndex := b;
6063 end;
6065 if ShowModal() = mrOK then
6066 begin
6067 b := lbTypeSelect.ItemIndex;
6068 Values[Key] := PANELNAMES[b];
6069 vleObjectPropertyApply(Sender);
6070 end;
6071 end
6072 end
6073 else if Key = _lc[I_PROP_TR_TELEPORT_TO] then
6074 SelectFlag := SELECTFLAG_TELEPORT
6075 else if Key = _lc[I_PROP_TR_SPAWN_TO] then
6076 SelectFlag := SELECTFLAG_SPAWNPOINT
6077 else if (Key = _lc[I_PROP_TR_DOOR_PANEL]) or
6078 (Key = _lc[I_PROP_TR_TRAP_PANEL]) then
6079 SelectFlag := SELECTFLAG_DOOR
6080 else if Key = _lc[I_PROP_TR_TEXTURE_PANEL] then
6081 begin
6082 DrawPressRect := False;
6083 SelectFlag := SELECTFLAG_TEXTURE;
6084 end
6085 else if Key = _lc[I_PROP_TR_SHOT_PANEL] then
6086 SelectFlag := SELECTFLAG_SHOTPANEL
6087 else if Key = _lc[I_PROP_TR_LIFT_PANEL] then
6088 SelectFlag := SELECTFLAG_LIFT
6089 else if key = _lc[I_PROP_TR_EX_MONSTER] then
6090 SelectFlag := SELECTFLAG_MONSTER
6091 else if Key = _lc[I_PROP_TR_EX_AREA] then
6092 begin
6093 SelectFlag := SELECTFLAG_NONE;
6094 DrawPressRect := True;
6095 end
6096 else if Key = _lc[I_PROP_TR_NEXT_MAP] then
6097 begin // Выбор следующей карты:
6098 g_ProcessResourceStr(OpenedMap, @FileName, nil, nil);
6099 SelectMapForm.Caption := _lc[I_CAP_SELECT];
6100 SelectMapForm.GetMaps(FileName);
6102 if SelectMapForm.ShowModal() = mrOK then
6103 begin
6104 vleObjectProperty.Values[Key] := SelectMapForm.lbMapList.Items[SelectMapForm.lbMapList.ItemIndex];
6105 vleObjectPropertyApply(Sender);
6106 end;
6107 end
6108 else if (Key = _lc[I_PROP_TR_SOUND_NAME]) or
6109 (Key = _lc[I_PROP_TR_MUSIC_NAME]) then
6110 begin // Выбор файла звука/музыки:
6111 AddSoundForm.OKFunction := nil;
6112 AddSoundForm.lbResourcesList.MultiSelect := False;
6113 AddSoundForm.SetResource := vleObjectProperty.Values[Key];
6115 if (AddSoundForm.ShowModal() = mrOk) then
6116 begin
6117 vleObjectProperty.Values[Key] := AddSoundForm.ResourceName;
6118 vleObjectPropertyApply(Sender);
6119 end;
6120 end
6121 else if Key = _lc[I_PROP_TR_ACTIVATION] then
6122 with ActivationTypeForm, vleObjectProperty do
6123 begin // Выбор типов активации:
6124 cbPlayerCollide.Checked := Pos('PC', Values[Key]) > 0;
6125 cbMonsterCollide.Checked := Pos('MC', Values[Key]) > 0;
6126 cbPlayerPress.Checked := Pos('PP', Values[Key]) > 0;
6127 cbMonsterPress.Checked := Pos('MP', Values[Key]) > 0;
6128 cbShot.Checked := Pos('SH', Values[Key]) > 0;
6129 cbNoMonster.Checked := Pos('NM', Values[Key]) > 0;
6131 if ShowModal() = mrOK then
6132 begin
6133 b := 0;
6134 if cbPlayerCollide.Checked then
6135 b := ACTIVATE_PLAYERCOLLIDE;
6136 if cbMonsterCollide.Checked then
6137 b := b or ACTIVATE_MONSTERCOLLIDE;
6138 if cbPlayerPress.Checked then
6139 b := b or ACTIVATE_PLAYERPRESS;
6140 if cbMonsterPress.Checked then
6141 b := b or ACTIVATE_MONSTERPRESS;
6142 if cbShot.Checked then
6143 b := b or ACTIVATE_SHOT;
6144 if cbNoMonster.Checked then
6145 b := b or ACTIVATE_NOMONSTER;
6147 Values[Key] := ActivateToStr(b);
6148 vleObjectPropertyApply(Sender);
6149 end;
6150 end
6151 else if Key = _lc[I_PROP_TR_KEYS] then
6152 with KeysForm, vleObjectProperty do
6153 begin // Выбор необходимых ключей:
6154 cbRedKey.Checked := Pos('RK', Values[Key]) > 0;
6155 cbGreenKey.Checked := Pos('GK', Values[Key]) > 0;
6156 cbBlueKey.Checked := Pos('BK', Values[Key]) > 0;
6157 cbRedTeam.Checked := Pos('RT', Values[Key]) > 0;
6158 cbBlueTeam.Checked := Pos('BT', Values[Key]) > 0;
6160 if ShowModal() = mrOK then
6161 begin
6162 b := 0;
6163 if cbRedKey.Checked then
6164 b := KEY_RED;
6165 if cbGreenKey.Checked then
6166 b := b or KEY_GREEN;
6167 if cbBlueKey.Checked then
6168 b := b or KEY_BLUE;
6169 if cbRedTeam.Checked then
6170 b := b or KEY_REDTEAM;
6171 if cbBlueTeam.Checked then
6172 b := b or KEY_BLUETEAM;
6174 Values[Key] := KeyToStr(b);
6175 vleObjectPropertyApply(Sender);
6176 end;
6177 end
6178 else if Key = _lc[I_PROP_TR_FX_TYPE] then
6179 with ChooseTypeForm, vleObjectProperty do
6180 begin // Выбор типа эффекта:
6181 Caption := _lc[I_CAP_FX_TYPE];
6182 lbTypeSelect.Items.Clear();
6184 for b := EFFECT_NONE to EFFECT_FIRE do
6185 lbTypeSelect.Items.Add(EffectToStr(b));
6187 lbTypeSelect.ItemIndex := StrToEffect(Values[Key]);
6189 if ShowModal() = mrOK then
6190 begin
6191 b := lbTypeSelect.ItemIndex;
6192 Values[Key] := EffectToStr(b);
6193 vleObjectPropertyApply(Sender);
6194 end;
6195 end
6196 else if Key = _lc[I_PROP_TR_MONSTER_TYPE] then
6197 with ChooseTypeForm, vleObjectProperty do
6198 begin // Выбор типа монстра:
6199 Caption := _lc[I_CAP_MONSTER_TYPE];
6200 lbTypeSelect.Items.Clear();
6202 for b := MONSTER_DEMON to MONSTER_MAN do
6203 lbTypeSelect.Items.Add(MonsterToStr(b));
6205 lbTypeSelect.ItemIndex := StrToMonster(Values[Key]) - MONSTER_DEMON;
6207 if ShowModal() = mrOK then
6208 begin
6209 b := lbTypeSelect.ItemIndex + MONSTER_DEMON;
6210 Values[Key] := MonsterToStr(b);
6211 vleObjectPropertyApply(Sender);
6212 end;
6213 end
6214 else if Key = _lc[I_PROP_TR_ITEM_TYPE] then
6215 with ChooseTypeForm, vleObjectProperty do
6216 begin // Выбор типа предмета:
6217 Caption := _lc[I_CAP_ITEM_TYPE];
6218 lbTypeSelect.Items.Clear();
6220 for b := ITEM_MEDKIT_SMALL to ITEM_KEY_BLUE do
6221 lbTypeSelect.Items.Add(ItemToStr(b));
6222 lbTypeSelect.Items.Add(ItemToStr(ITEM_BOTTLE));
6223 lbTypeSelect.Items.Add(ItemToStr(ITEM_HELMET));
6224 lbTypeSelect.Items.Add(ItemToStr(ITEM_JETPACK));
6225 lbTypeSelect.Items.Add(ItemToStr(ITEM_INVIS));
6226 lbTypeSelect.Items.Add(ItemToStr(ITEM_WEAPON_FLAMETHROWER));
6227 lbTypeSelect.Items.Add(ItemToStr(ITEM_AMMO_FUELCAN));
6229 b := StrToItem(Values[Key]);
6230 if b >= ITEM_BOTTLE then
6231 b := b - 2;
6232 lbTypeSelect.ItemIndex := b - ITEM_MEDKIT_SMALL;
6234 if ShowModal() = mrOK then
6235 begin
6236 b := lbTypeSelect.ItemIndex + ITEM_MEDKIT_SMALL;
6237 if b >= ITEM_WEAPON_KASTET then
6238 b := b + 2;
6239 Values[Key] := ItemToStr(b);
6240 vleObjectPropertyApply(Sender);
6241 end;
6242 end
6243 else if Key = _lc[I_PROP_TR_SHOT_TYPE] then
6244 with ChooseTypeForm, vleObjectProperty do
6245 begin // Выбор типа предмета:
6246 Caption := _lc[I_PROP_TR_SHOT_TYPE];
6247 lbTypeSelect.Items.Clear();
6249 for b := TRIGGER_SHOT_PISTOL to TRIGGER_SHOT_MAX do
6250 lbTypeSelect.Items.Add(ShotToStr(b));
6252 lbTypeSelect.ItemIndex := StrToShot(Values[Key]);
6254 if ShowModal() = mrOK then
6255 begin
6256 b := lbTypeSelect.ItemIndex;
6257 Values[Key] := ShotToStr(b);
6258 vleObjectPropertyApply(Sender);
6259 end;
6260 end
6261 else if Key = _lc[I_PROP_TR_EFFECT_TYPE] then
6262 with ChooseTypeForm, vleObjectProperty do
6263 begin // Выбор типа эффекта:
6264 Caption := _lc[I_CAP_FX_TYPE];
6265 lbTypeSelect.Items.Clear();
6267 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_PARTICLE]);
6268 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_ANIMATION]);
6269 if Values[Key] = _lc[I_PROP_TR_EFFECT_ANIMATION] then
6270 lbTypeSelect.ItemIndex := 1
6271 else
6272 lbTypeSelect.ItemIndex := 0;
6274 if ShowModal() = mrOK then
6275 begin
6276 b := lbTypeSelect.ItemIndex;
6277 if b = 0 then
6278 Values[Key] := _lc[I_PROP_TR_EFFECT_PARTICLE]
6279 else
6280 Values[Key] := _lc[I_PROP_TR_EFFECT_ANIMATION];
6281 vleObjectPropertyApply(Sender);
6282 end;
6283 end
6284 else if Key = _lc[I_PROP_TR_EFFECT_SUBTYPE] then
6285 with ChooseTypeForm, vleObjectProperty do
6286 begin // Выбор подтипа эффекта:
6287 Caption := _lc[I_CAP_FX_TYPE];
6288 lbTypeSelect.Items.Clear();
6290 if Values[_lc[I_PROP_TR_EFFECT_TYPE]] = _lc[I_PROP_TR_EFFECT_ANIMATION] then
6291 begin
6292 for b := EFFECT_TELEPORT to EFFECT_FIRE do
6293 lbTypeSelect.Items.Add(EffectToStr(b));
6295 lbTypeSelect.ItemIndex := StrToEffect(Values[Key]) - 1;
6296 end else
6297 begin
6298 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_SLIQUID]);
6299 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_LLIQUID]);
6300 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_DLIQUID]);
6301 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_BLOOD]);
6302 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_SPARK]);
6303 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_BUBBLE]);
6304 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_SLIQUID;
6305 if Values[Key] = _lc[I_PROP_TR_EFFECT_LLIQUID] then
6306 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_LLIQUID;
6307 if Values[Key] = _lc[I_PROP_TR_EFFECT_DLIQUID] then
6308 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_DLIQUID;
6309 if Values[Key] = _lc[I_PROP_TR_EFFECT_BLOOD] then
6310 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_BLOOD;
6311 if Values[Key] = _lc[I_PROP_TR_EFFECT_SPARK] then
6312 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_SPARK;
6313 if Values[Key] = _lc[I_PROP_TR_EFFECT_BUBBLE] then
6314 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_BUBBLE;
6315 end;
6317 if ShowModal() = mrOK then
6318 begin
6319 b := lbTypeSelect.ItemIndex;
6321 if Values[_lc[I_PROP_TR_EFFECT_TYPE]] = _lc[I_PROP_TR_EFFECT_ANIMATION] then
6322 Values[Key] := EffectToStr(b + 1)
6323 else begin
6324 Values[Key] := _lc[I_PROP_TR_EFFECT_SLIQUID];
6325 if b = TRIGGER_EFFECT_LLIQUID then
6326 Values[Key] := _lc[I_PROP_TR_EFFECT_LLIQUID];
6327 if b = TRIGGER_EFFECT_DLIQUID then
6328 Values[Key] := _lc[I_PROP_TR_EFFECT_DLIQUID];
6329 if b = TRIGGER_EFFECT_BLOOD then
6330 Values[Key] := _lc[I_PROP_TR_EFFECT_BLOOD];
6331 if b = TRIGGER_EFFECT_SPARK then
6332 Values[Key] := _lc[I_PROP_TR_EFFECT_SPARK];
6333 if b = TRIGGER_EFFECT_BUBBLE then
6334 Values[Key] := _lc[I_PROP_TR_EFFECT_BUBBLE];
6335 end;
6337 vleObjectPropertyApply(Sender);
6338 end;
6339 end
6340 else if Key = _lc[I_PROP_TR_EFFECT_COLOR] then
6341 with vleObjectProperty do
6342 begin // Выбор цвета эффекта:
6343 ColorDialog.Color := StrToIntDef(Values[Key], 0);
6344 if ColorDialog.Execute then
6345 begin
6346 Values[Key] := IntToStr(ColorDialog.Color);
6347 vleObjectPropertyApply(Sender);
6348 end;
6349 end
6350 else if Key = _lc[I_PROP_PANEL_TEX] then
6351 begin // Смена текстуры:
6352 vleObjectProperty.Values[Key] := SelectedTexture();
6353 vleObjectPropertyApply(Sender);
6354 end;
6355 end;
6357 procedure TMainForm.vleObjectPropertyApply(Sender: TObject);
6358 begin
6359 // hack to prevent empty ID in list
6360 RenderPanel.SetFocus();
6361 bApplyProperty.Click();
6362 vleObjectProperty.SetFocus();
6363 end;
6365 procedure TMainForm.aSaveMapExecute(Sender: TObject);
6366 var
6367 FileName, Section, Res: String;
6368 begin
6369 if OpenedMap = '' then
6370 begin
6371 aSaveMapAsExecute(nil);
6372 Exit;
6373 end;
6375 g_ProcessResourceStr(OpenedMap, FileName, Section, Res);
6377 SaveMap(FileName+':\'+Res);
6378 end;
6380 procedure TMainForm.aOpenMapExecute(Sender: TObject);
6381 begin
6382 OpenDialog.Filter := _lc[I_FILE_FILTER_ALL];
6384 if OpenDialog.Execute() then
6385 begin
6386 OpenMapFile(OpenDialog.FileName);
6387 OpenDialog.InitialDir := ExtractFileDir(OpenDialog.FileName);
6388 end;
6389 end;
6391 procedure TMainForm.OpenMapFile(FileName: String);
6392 begin
6393 if (Pos('.ini', LowerCase(ExtractFileName(FileName))) > 0) then
6394 begin // INI карты:
6395 FullClear();
6397 pLoadProgress.Left := (RenderPanel.Width div 2)-(pLoadProgress.Width div 2);
6398 pLoadProgress.Top := (RenderPanel.Height div 2)-(pLoadProgress.Height div 2);
6399 pLoadProgress.Show();
6401 OpenedMap := '';
6402 OpenedWAD := '';
6404 LoadMapOld(FileName);
6406 MainForm.Caption := Format('%s - %s', [FormCaption, ExtractFileName(FileName)]);
6408 pLoadProgress.Hide();
6409 MainForm.FormResize(Self);
6410 end
6411 else // Карты из WAD:
6412 begin
6413 OpenMap(FileName, '');
6414 end;
6415 end;
6417 procedure TMainForm.FormActivate(Sender: TObject);
6418 var
6419 lang: Integer;
6420 config: TConfig;
6421 begin
6422 MainForm.ActiveControl := RenderPanel;
6424 // Язык:
6425 if (gLanguage = '') and not (fsModal in SelectLanguageForm.FormState) then
6426 begin
6427 lang := SelectLanguageForm.ShowModal();
6428 case lang of
6429 1: gLanguage := LANGUAGE_ENGLISH;
6430 2: gLanguage := LANGUAGE_RUSSIAN;
6431 else gLanguage := LANGUAGE_ENGLISH;
6432 end;
6434 config := TConfig.CreateFile(CfgFileName);
6435 config.WriteStr('Editor', 'Language', gLanguage);
6436 config.SaveFile(CfgFileName);
6437 config.Free();
6438 end;
6440 //e_WriteLog('Read language file', MSG_NOTIFY);
6441 //g_Language_Load(EditorDir+'\data\'+gLanguage+LANGUAGE_FILE_NAME);
6442 g_Language_Set(gLanguage);
6443 end;
6445 procedure TMainForm.aDeleteMap(Sender: TObject);
6446 var
6447 res: Integer;
6448 FileName: String;
6449 MapName: String;
6450 begin
6451 OpenDialog.Filter := _lc[I_FILE_FILTER_WAD];
6453 if not OpenDialog.Execute() then
6454 Exit;
6456 FileName := OpenDialog.FileName;
6457 SelectMapForm.Caption := _lc[I_CAP_REMOVE];
6458 SelectMapForm.lbMapList.Items.Clear();
6459 SelectMapForm.GetMaps(FileName);
6461 if SelectMapForm.ShowModal() <> mrOK then
6462 Exit;
6464 MapName := SelectMapForm.lbMapList.Items[SelectMapForm.lbMapList.ItemIndex];
6465 if Application.MessageBox(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
6466 Exit;
6468 g_DeleteResource(FileName, '', MapName, res);
6469 if res <> 0 then
6470 begin
6471 Application.MessageBox(PChar('Cant delete map res=' + IntToStr(res)), PChar('Map not deleted!'), MB_ICONINFORMATION or MB_OK or MB_DEFBUTTON1);
6472 Exit
6473 end;
6475 Application.MessageBox(
6476 PChar(Format(_lc[I_MSG_MAP_DELETED_PROMT], [MapName])),
6477 PChar(_lc[I_MSG_MAP_DELETED]),
6478 MB_ICONINFORMATION or MB_OK or MB_DEFBUTTON1
6479 );
6481 // Удалили текущую карту - сохранять по старому ее нельзя:
6482 if OpenedMap = (FileName + ':\' + MapName) then
6483 begin
6484 OpenedMap := '';
6485 OpenedWAD := '';
6486 MainForm.Caption := FormCaption
6487 end
6488 end;
6490 procedure TMainForm.vleObjectPropertyKeyDown(Sender: TObject;
6491 var Key: Word; Shift: TShiftState);
6492 begin
6493 if Key = VK_RETURN then
6494 vleObjectPropertyApply(Sender);
6495 end;
6497 procedure MovePanel(var ID: DWORD; MoveType: Byte);
6498 var
6499 _id, a: Integer;
6500 tmp: TPanel;
6501 begin
6502 if (ID = 0) and (MoveType = 0) then
6503 Exit;
6504 if (ID = DWORD(High(gPanels))) and (MoveType <> 0) then
6505 Exit;
6506 if (ID > DWORD(High(gPanels))) then
6507 Exit;
6509 _id := Integer(ID);
6511 if MoveType = 0 then // to Back
6512 begin
6513 if gTriggers <> nil then
6514 for a := 0 to High(gTriggers) do
6515 with gTriggers[a] do
6516 begin
6517 if TriggerType = TRIGGER_NONE then
6518 Continue;
6520 if TexturePanel = _id then
6521 TexturePanel := 0
6522 else
6523 if (TexturePanel >= 0) and (TexturePanel < _id) then
6524 Inc(TexturePanel);
6526 case TriggerType of
6527 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
6528 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP,
6529 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
6530 if Data.PanelID = _id then
6531 Data.PanelID := 0
6532 else
6533 if (Data.PanelID >= 0) and (Data.PanelID < _id) then
6534 Inc(Data.PanelID);
6536 TRIGGER_SHOT:
6537 if Data.ShotPanelID = _id then
6538 Data.ShotPanelID := 0
6539 else
6540 if (Data.ShotPanelID >= 0) and (Data.ShotPanelID < _id) then
6541 Inc(Data.ShotPanelID);
6542 end;
6543 end;
6545 tmp := gPanels[_id];
6547 for a := _id downto 1 do
6548 gPanels[a] := gPanels[a-1];
6550 gPanels[0] := tmp;
6552 ID := 0;
6553 end
6554 else // to Front
6555 begin
6556 if gTriggers <> nil then
6557 for a := 0 to High(gTriggers) do
6558 with gTriggers[a] do
6559 begin
6560 if TriggerType = TRIGGER_NONE then
6561 Continue;
6563 if TexturePanel = _id then
6564 TexturePanel := High(gPanels)
6565 else
6566 if TexturePanel > _id then
6567 Dec(TexturePanel);
6569 case TriggerType of
6570 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
6571 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP,
6572 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
6573 if Data.PanelID = _id then
6574 Data.PanelID := High(gPanels)
6575 else
6576 if Data.PanelID > _id then
6577 Dec(Data.PanelID);
6579 TRIGGER_SHOT:
6580 if Data.ShotPanelID = _id then
6581 Data.ShotPanelID := High(gPanels)
6582 else
6583 if Data.ShotPanelID > _id then
6584 Dec(Data.ShotPanelID);
6585 end;
6586 end;
6588 tmp := gPanels[_id];
6590 for a := _id to High(gPanels)-1 do
6591 gPanels[a] := gPanels[a+1];
6593 gPanels[High(gPanels)] := tmp;
6595 ID := High(gPanels);
6596 end;
6597 end;
6599 procedure TMainForm.aMoveToBack(Sender: TObject);
6600 var
6601 a: Integer;
6602 begin
6603 if SelectedObjects = nil then
6604 Exit;
6606 for a := 0 to High(SelectedObjects) do
6607 with SelectedObjects[a] do
6608 if Live and (ObjectType = OBJECT_PANEL) then
6609 begin
6610 SelectedObjects[0] := SelectedObjects[a];
6611 SetLength(SelectedObjects, 1);
6612 MovePanel(ID, 0);
6613 FillProperty();
6614 Break;
6615 end;
6616 end;
6618 procedure TMainForm.aMoveToFore(Sender: TObject);
6619 var
6620 a: Integer;
6621 begin
6622 if SelectedObjects = nil then
6623 Exit;
6625 for a := 0 to High(SelectedObjects) do
6626 with SelectedObjects[a] do
6627 if Live and (ObjectType = OBJECT_PANEL) then
6628 begin
6629 SelectedObjects[0] := SelectedObjects[a];
6630 SetLength(SelectedObjects, 1);
6631 MovePanel(ID, 1);
6632 FillProperty();
6633 Break;
6634 end;
6635 end;
6637 procedure TMainForm.aSaveMapAsExecute(Sender: TObject);
6638 var
6639 idx: Integer;
6640 begin
6641 SaveDialog.Filter := _lc[I_FILE_FILTER_WAD];
6643 if not SaveDialog.Execute() then
6644 Exit;
6646 SaveMapForm.GetMaps(SaveDialog.FileName, True);
6648 if SaveMapForm.ShowModal() <> mrOK then
6649 Exit;
6651 SaveDialog.InitialDir := ExtractFileDir(SaveDialog.FileName);
6652 OpenedMap := SaveDialog.FileName+':\'+SaveMapForm.eMapName.Text;
6653 OpenedWAD := SaveDialog.FileName;
6655 idx := RecentFiles.IndexOf(OpenedMap);
6656 // Такая карта уже недавно открывалась:
6657 if idx >= 0 then
6658 RecentFiles.Delete(idx);
6659 RecentFiles.Insert(0, OpenedMap);
6660 RefreshRecentMenu;
6662 SaveMap(OpenedMap);
6664 gMapInfo.FileName := SaveDialog.FileName;
6665 gMapInfo.MapName := SaveMapForm.eMapName.Text;
6666 UpdateCaption(gMapInfo.Name, ExtractFileName(gMapInfo.FileName), gMapInfo.MapName);
6667 end;
6669 procedure TMainForm.aSelectAllExecute(Sender: TObject);
6670 var
6671 a: Integer;
6672 begin
6673 RemoveSelectFromObjects();
6675 case pcObjects.ActivePageIndex+1 of
6676 OBJECT_PANEL:
6677 if gPanels <> nil then
6678 for a := 0 to High(gPanels) do
6679 if gPanels[a].PanelType <> PANEL_NONE then
6680 SelectObject(OBJECT_PANEL, a, True);
6681 OBJECT_ITEM:
6682 if gItems <> nil then
6683 for a := 0 to High(gItems) do
6684 if gItems[a].ItemType <> ITEM_NONE then
6685 SelectObject(OBJECT_ITEM, a, True);
6686 OBJECT_MONSTER:
6687 if gMonsters <> nil then
6688 for a := 0 to High(gMonsters) do
6689 if gMonsters[a].MonsterType <> MONSTER_NONE then
6690 SelectObject(OBJECT_MONSTER, a, True);
6691 OBJECT_AREA:
6692 if gAreas <> nil then
6693 for a := 0 to High(gAreas) do
6694 if gAreas[a].AreaType <> AREA_NONE then
6695 SelectObject(OBJECT_AREA, a, True);
6696 OBJECT_TRIGGER:
6697 if gTriggers <> nil then
6698 for a := 0 to High(gTriggers) do
6699 if gTriggers[a].TriggerType <> TRIGGER_NONE then
6700 SelectObject(OBJECT_TRIGGER, a, True);
6701 end;
6703 RecountSelectedObjects();
6704 end;
6706 procedure TMainForm.tbGridOnClick(Sender: TObject);
6707 begin
6708 DotEnable := not DotEnable;
6709 (Sender as TToolButton).Down := DotEnable;
6710 end;
6712 procedure TMainForm.OnIdle(Sender: TObject; var Done: Boolean);
6713 var f: AnsiString;
6714 begin
6715 // FIXME: this is a shitty hack
6716 if not gDataLoaded then
6717 begin
6718 e_WriteLog('Init OpenGL', MSG_NOTIFY);
6719 e_InitGL();
6720 e_WriteLog('Loading data', MSG_NOTIFY);
6721 LoadStdFont('STDTXT', 'STDFONT', gEditorFont);
6722 e_WriteLog('Loading more data', MSG_NOTIFY);
6723 LoadData();
6724 e_WriteLog('Loading even more data', MSG_NOTIFY);
6725 gDataLoaded := True;
6726 MainForm.FormResize(nil);
6727 end;
6728 Draw();
6729 if StartMap <> '' then
6730 begin
6731 f := StartMap;
6732 StartMap := '';
6733 OpenMap(f, '');
6734 end;
6735 end;
6737 procedure TMainForm.miMapPreviewClick(Sender: TObject);
6738 begin
6739 if PreviewMode = 2 then
6740 Exit;
6742 if PreviewMode = 0 then
6743 begin
6744 Splitter2.Visible := False;
6745 Splitter1.Visible := False;
6746 StatusBar.Visible := False;
6747 PanelObjs.Visible := False;
6748 PanelProps.Visible := False;
6749 MainToolBar.Visible := False;
6750 sbHorizontal.Visible := False;
6751 sbVertical.Visible := False;
6752 end
6753 else
6754 begin
6755 StatusBar.Visible := True;
6756 PanelObjs.Visible := True;
6757 PanelProps.Visible := True;
6758 Splitter2.Visible := True;
6759 Splitter1.Visible := True;
6760 MainToolBar.Visible := True;
6761 sbHorizontal.Visible := True;
6762 sbVertical.Visible := True;
6763 end;
6765 PreviewMode := PreviewMode xor 1;
6766 (Sender as TMenuItem).Checked := PreviewMode > 0;
6768 FormResize(Self);
6769 end;
6771 procedure TMainForm.miLayer1Click(Sender: TObject);
6772 begin
6773 SwitchLayer(LAYER_BACK);
6774 end;
6776 procedure TMainForm.miLayer2Click(Sender: TObject);
6777 begin
6778 SwitchLayer(LAYER_WALLS);
6779 end;
6781 procedure TMainForm.miLayer3Click(Sender: TObject);
6782 begin
6783 SwitchLayer(LAYER_FOREGROUND);
6784 end;
6786 procedure TMainForm.miLayer4Click(Sender: TObject);
6787 begin
6788 SwitchLayer(LAYER_STEPS);
6789 end;
6791 procedure TMainForm.miLayer5Click(Sender: TObject);
6792 begin
6793 SwitchLayer(LAYER_WATER);
6794 end;
6796 procedure TMainForm.miLayer6Click(Sender: TObject);
6797 begin
6798 SwitchLayer(LAYER_ITEMS);
6799 end;
6801 procedure TMainForm.miLayer7Click(Sender: TObject);
6802 begin
6803 SwitchLayer(LAYER_MONSTERS);
6804 end;
6806 procedure TMainForm.miLayer8Click(Sender: TObject);
6807 begin
6808 SwitchLayer(LAYER_AREAS);
6809 end;
6811 procedure TMainForm.miLayer9Click(Sender: TObject);
6812 begin
6813 SwitchLayer(LAYER_TRIGGERS);
6814 end;
6816 procedure TMainForm.tbShowClick(Sender: TObject);
6817 var
6818 a: Integer;
6819 b: Boolean;
6820 begin
6821 b := True;
6822 for a := 0 to High(LayerEnabled) do
6823 b := b and LayerEnabled[a];
6825 b := not b;
6827 ShowLayer(LAYER_BACK, b);
6828 ShowLayer(LAYER_WALLS, b);
6829 ShowLayer(LAYER_FOREGROUND, b);
6830 ShowLayer(LAYER_STEPS, b);
6831 ShowLayer(LAYER_WATER, b);
6832 ShowLayer(LAYER_ITEMS, b);
6833 ShowLayer(LAYER_MONSTERS, b);
6834 ShowLayer(LAYER_AREAS, b);
6835 ShowLayer(LAYER_TRIGGERS, b);
6836 end;
6838 procedure TMainForm.miMiniMapClick(Sender: TObject);
6839 begin
6840 SwitchMap();
6841 end;
6843 procedure TMainForm.miSwitchGridClick(Sender: TObject);
6844 begin
6845 if DotStep = DotStepOne then
6846 DotStep := DotStepTwo
6847 else
6848 DotStep := DotStepOne;
6850 MousePos.X := (MousePos.X div DotStep) * DotStep;
6851 MousePos.Y := (MousePos.Y div DotStep) * DotStep;
6852 end;
6854 procedure TMainForm.miShowEdgesClick(Sender: TObject);
6855 begin
6856 ShowEdges();
6857 end;
6859 procedure TMainForm.miSnapToGridClick(Sender: TObject);
6860 begin
6861 SnapToGrid := not SnapToGrid;
6863 MousePos.X := (MousePos.X div DotStep) * DotStep;
6864 MousePos.Y := (MousePos.Y div DotStep) * DotStep;
6866 miSnapToGrid.Checked := SnapToGrid;
6867 end;
6869 procedure TMainForm.minexttabClick(Sender: TObject);
6870 begin
6871 if pcObjects.ActivePageIndex < pcObjects.PageCount-1 then
6872 pcObjects.ActivePageIndex := pcObjects.ActivePageIndex+1
6873 else
6874 pcObjects.ActivePageIndex := 0;
6875 end;
6877 procedure TMainForm.miSaveMiniMapClick(Sender: TObject);
6878 begin
6879 SaveMiniMapForm.ShowModal();
6880 end;
6882 procedure TMainForm.bClearTextureClick(Sender: TObject);
6883 begin
6884 lbTextureList.ItemIndex := -1;
6885 lTextureWidth.Caption := '';
6886 lTextureHeight.Caption := '';
6887 end;
6889 procedure TMainForm.miPackMapClick(Sender: TObject);
6890 begin
6891 PackMapForm.ShowModal();
6892 end;
6894 type SSArray = array of String;
6896 function ParseString (Str: AnsiString): SSArray;
6897 function GetStr (var Str: AnsiString): AnsiString;
6898 var a, b: Integer;
6899 begin
6900 Result := '';
6901 if Str[1] = '"' then
6902 for b := 1 to Length(Str) do
6903 if (b = Length(Str)) or (Str[b + 1] = '"') then
6904 begin
6905 Result := Copy(Str, 2, b - 1);
6906 Delete(Str, 1, b + 1);
6907 Str := Trim(Str);
6908 Exit;
6909 end;
6910 for a := 1 to Length(Str) do
6911 if (a = Length(Str)) or (Str[a + 1] = ' ') then
6912 begin
6913 Result := Copy(Str, 1, a);
6914 Delete(Str, 1, a + 1);
6915 Str := Trim(Str);
6916 Exit;
6917 end;
6918 end;
6919 begin
6920 Result := nil;
6921 Str := Trim(Str);
6922 while Str <> '' do
6923 begin
6924 SetLength(Result, Length(Result)+1);
6925 Result[High(Result)] := GetStr(Str);
6926 end;
6927 end;
6929 procedure TMainForm.miTestMapClick(Sender: TObject);
6930 var
6931 newWAD, oldWAD, tempMap, ext: String;
6932 args: SSArray;
6933 opt: LongWord;
6934 time, i: Integer;
6935 proc: TProcessUTF8;
6936 res: Boolean;
6937 begin
6938 // Ignore while map testing in progress
6939 if MapTestProcess <> nil then
6940 Exit;
6942 // Сохраняем временную карту:
6943 time := 0;
6944 repeat
6945 newWAD := Format('%s/temp%.4d', [MapsDir, time]);
6946 Inc(time);
6947 until not FileExists(newWAD);
6948 if OpenedMap <> '' then
6949 begin
6950 oldWad := g_ExtractWadName(OpenedMap);
6951 newWad := newWad + ExtractFileExt(oldWad);
6952 if CopyFile(oldWad, newWad) = false then
6953 e_WriteLog('MapTest: unable to copy [' + oldWad + '] to [' + newWad + ']', MSG_WARNING)
6954 end
6955 else
6956 begin
6957 newWad := newWad + '.wad'
6958 end;
6959 tempMap := newWAD + ':\' + TEST_MAP_NAME;
6960 SaveMap(tempMap);
6962 // Опции игры:
6963 opt := 32 + 64;
6964 if TestOptionsTwoPlayers then
6965 opt := opt + 1;
6966 if TestOptionsTeamDamage then
6967 opt := opt + 2;
6968 if TestOptionsAllowExit then
6969 opt := opt + 4;
6970 if TestOptionsWeaponStay then
6971 opt := opt + 8;
6972 if TestOptionsMonstersDM then
6973 opt := opt + 16;
6975 // Запускаем:
6976 proc := TProcessUTF8.Create(nil);
6977 proc.Executable := TestD2dExe;
6978 {$IFDEF DARWIN}
6979 // TODO: get real executable name from Info.plist
6980 if LowerCase(ExtractFileExt(TestD2dExe)) = '.app' then
6981 proc.Executable := TestD2dExe + DirectorySeparator + 'Contents' + DirectorySeparator + 'MacOS' + DirectorySeparator + 'Doom2DF';
6982 {$ENDIF}
6983 proc.Parameters.Add('-map');
6984 proc.Parameters.Add(tempMap);
6985 proc.Parameters.Add('-gm');
6986 proc.Parameters.Add(TestGameMode);
6987 proc.Parameters.Add('-limt');
6988 proc.Parameters.Add(TestLimTime);
6989 proc.Parameters.Add('-lims');
6990 proc.Parameters.Add(TestLimScore);
6991 proc.Parameters.Add('-opt');
6992 proc.Parameters.Add(IntToStr(opt));
6993 proc.Parameters.Add('--debug');
6994 if TestMapOnce then
6995 proc.Parameters.Add('--close');
6997 args := ParseString(TestD2DArgs);
6998 for i := 0 to High(args) do
6999 proc.Parameters.Add(args[i]);
7001 res := True;
7002 try
7003 proc.Execute();
7004 except
7005 res := False;
7006 end;
7007 if res then
7008 begin
7009 tbTestMap.Enabled := False;
7010 MapTestFile := newWAD;
7011 MapTestProcess := proc;
7012 end
7013 else
7014 begin
7015 Application.MessageBox(PChar(_lc[I_MSG_EXEC_ERROR]), 'FIXME', MB_OK or MB_ICONERROR);
7016 SysUtils.DeleteFile(newWAD);
7017 proc.Free();
7018 end;
7019 end;
7021 procedure TMainForm.sbVerticalScroll(Sender: TObject;
7022 ScrollCode: TScrollCode; var ScrollPos: Integer);
7023 begin
7024 MapOffset.Y := -sbVertical.Position;
7025 end;
7027 procedure TMainForm.sbHorizontalScroll(Sender: TObject;
7028 ScrollCode: TScrollCode; var ScrollPos: Integer);
7029 begin
7030 MapOffset.X := -sbHorizontal.Position;
7031 end;
7033 procedure TMainForm.miOpenWadMapClick(Sender: TObject);
7034 begin
7035 if OpenedWAD <> '' then
7036 begin
7037 OpenMap(OpenedWAD, '');
7038 end;
7039 end;
7041 procedure TMainForm.selectall1Click(Sender: TObject);
7042 var
7043 a: Integer;
7044 begin
7045 RemoveSelectFromObjects();
7047 if gPanels <> nil then
7048 for a := 0 to High(gPanels) do
7049 if gPanels[a].PanelType <> PANEL_NONE then
7050 SelectObject(OBJECT_PANEL, a, True);
7052 if gItems <> nil then
7053 for a := 0 to High(gItems) do
7054 if gItems[a].ItemType <> ITEM_NONE then
7055 SelectObject(OBJECT_ITEM, a, True);
7057 if gMonsters <> nil then
7058 for a := 0 to High(gMonsters) do
7059 if gMonsters[a].MonsterType <> MONSTER_NONE then
7060 SelectObject(OBJECT_MONSTER, a, True);
7062 if gAreas <> nil then
7063 for a := 0 to High(gAreas) do
7064 if gAreas[a].AreaType <> AREA_NONE then
7065 SelectObject(OBJECT_AREA, a, True);
7067 if gTriggers <> nil then
7068 for a := 0 to High(gTriggers) do
7069 if gTriggers[a].TriggerType <> TRIGGER_NONE then
7070 SelectObject(OBJECT_TRIGGER, a, True);
7072 RecountSelectedObjects();
7073 end;
7075 procedure TMainForm.Splitter1CanResize(Sender: TObject;
7076 var NewSize: Integer; var Accept: Boolean);
7077 begin
7078 Accept := (NewSize > 140);
7079 end;
7081 procedure TMainForm.Splitter2CanResize(Sender: TObject;
7082 var NewSize: Integer; var Accept: Boolean);
7083 begin
7084 Accept := (NewSize > 110);
7085 end;
7087 procedure TMainForm.vleObjectPropertyEnter(Sender: TObject);
7088 begin
7089 EditingProperties := True;
7090 end;
7092 procedure TMainForm.vleObjectPropertyExit(Sender: TObject);
7093 begin
7094 EditingProperties := False;
7095 end;
7097 procedure TMainForm.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
7098 begin
7099 // Объекты передвигались:
7100 if MainForm.ActiveControl = RenderPanel then
7101 begin
7102 if (Key = VK_NUMPAD4) or
7103 (Key = VK_NUMPAD6) or
7104 (Key = VK_NUMPAD8) or
7105 (Key = VK_NUMPAD5) or
7106 (Key = Ord('V')) then
7107 FillProperty();
7108 end;
7109 // Быстрое превью карты:
7110 if Key = Ord('E') then
7111 begin
7112 if PreviewMode = 2 then
7113 PreviewMode := 0;
7114 end;
7115 RenderPanelMouseMove(Sender, Shift, RenderMousePos().X, RenderMousePos().Y);
7116 end;
7118 end.