DEADSOFTWARE

7282c785c430a7a5342aa2f6e52a2821e14413d1
[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 // "Файл":
22 miMenuFile: TMenuItem;
23 miNewMap: TMenuItem;
24 miOpenMap: TMenuItem;
25 miSaveMap: TMenuItem;
26 miSaveMapAs: TMenuItem;
27 miOpenWadMap: TMenuItem;
28 miLine1: TMenuItem;
29 miReopenMap: TMenuItem;
30 miSaveMiniMap: TMenuItem;
31 miDeleteMap: TMenuItem;
32 miPackMap: TMenuItem;
33 miLine2: TMenuItem;
34 miExit: TMenuItem;
35 // "Правка":
36 miMenuEdit: TMenuItem;
37 miUndo: TMenuItem;
38 miLine3: TMenuItem;
39 miCopy: TMenuItem;
40 miCut: TMenuItem;
41 miPaste: TMenuItem;
42 miLine4: TMenuItem;
43 miSelectAll: TMenuItem;
44 miLine5: TMenuItem;
45 miToFore: TMenuItem;
46 miToBack: TMenuItem;
47 // "Инструменты":
48 miMenuTools: TMenuItem;
49 miSnapToGrid: TMenuItem;
50 miMiniMap: TMenuItem;
51 miSwitchGrid: TMenuItem;
52 miShowEdges: TMenuItem;
53 miLayers: TMenuItem;
54 miLayer1: TMenuItem;
55 miLayer2: TMenuItem;
56 miLayer3: TMenuItem;
57 miLayer4: TMenuItem;
58 miLayer5: TMenuItem;
59 miLayer6: TMenuItem;
60 miLayer7: TMenuItem;
61 miLayer8: TMenuItem;
62 miLayer9: TMenuItem;
63 // "Сервис":
64 miMenuService: TMenuItem;
65 miCheckMap: TMenuItem;
66 miOptimmization: TMenuItem;
67 miMapPreview: TMenuItem;
68 miTestMap: TMenuItem;
69 // "Настройка":
70 miMenuSettings: TMenuItem;
71 miMapOptions: TMenuItem;
72 miLine6: TMenuItem;
73 miOptions: TMenuItem;
74 miLine7: TMenuItem;
75 miMapTestSettings: TMenuItem;
76 // "Справка":
77 miMenuHelp: TMenuItem;
78 miAbout: TMenuItem;
79 // Скрытый пункт меню для Ctrl+Tab:
80 miHidden1: TMenuItem;
81 minexttab: TMenuItem;
83 // Панель инструментов:
84 MainToolBar: TToolBar;
85 pbLoad: TProgressBar;
86 pLoadProgress: TPanel;
87 RenderPanel: TOpenGLControl;
88 tbNewMap: TToolButton;
89 tbOpenMap: TToolButton;
90 tbSaveMap: TToolButton;
91 tbOpenWadMap: TToolButton;
92 tbLine1: TToolButton;
93 tbShowMap: TToolButton;
94 tbLine2: TToolButton;
95 tbShow: TToolButton;
96 tbLine3: TToolButton;
97 tbGridOn: TToolButton;
98 tbGrid: TToolButton;
99 tbLine4: TToolButton;
100 tbTestMap: TToolButton;
101 // Всплывающее меню для кнопки слоев:
102 pmShow: TPopupMenu;
103 miLayerP1: TMenuItem;
104 miLayerP2: TMenuItem;
105 miLayerP3: TMenuItem;
106 miLayerP4: TMenuItem;
107 miLayerP5: TMenuItem;
108 miLayerP6: TMenuItem;
109 miLayerP7: TMenuItem;
110 miLayerP8: TMenuItem;
111 miLayerP9: TMenuItem;
112 // Всплывающее меню для кнопки теста карты:
113 pmMapTest: TPopupMenu;
114 miMapTestPMSet: TMenuItem;
116 // Панель карты:
117 PanelMap: TPanel;
118 // Полосы прокрутки:
119 sbHorizontal: TScrollBar;
120 sbVertical: TScrollBar;
122 // Панель свойств:
123 PanelProps: TPanel;
124 // Панель применения свойств:
125 PanelPropApply: TPanel;
126 bApplyProperty: TButton;
127 // Редактор свойств объектов:
128 vleObjectProperty: TValueListEditor;
130 // Панель объектов - вкладки:
131 PanelObjs: TPanel;
132 pcObjects: TPageControl;
133 // Вкладка "Панели":
134 tsPanels: TTabSheet;
135 lbTextureList: TListBox;
136 // Панель настройки текстур:
137 PanelTextures: TPanel;
138 LabelTxW: TLabel;
139 lTextureWidth: TLabel;
140 LabelTxH: TLabel;
141 lTextureHeight: TLabel;
142 cbPreview: TCheckBox;
143 bbAddTexture: TBitBtn;
144 bbRemoveTexture: TBitBtn;
145 bClearTexture: TButton;
146 // Панель типов панелей:
147 PanelPanelType: TPanel;
148 lbPanelType: TListBox;
149 // Вкладка "Предметы":
150 tsItems: TTabSheet;
151 lbItemList: TListBox;
152 cbOnlyDM: TCheckBox;
153 cbFall: TCheckBox;
154 // Вкладка "Монстры":
155 tsMonsters: TTabSheet;
156 lbMonsterList: TListBox;
157 rbMonsterLeft: TRadioButton;
158 rbMonsterRight: TRadioButton;
159 // Вкладка "Области":
160 tsAreas: TTabSheet;
161 lbAreasList: TListBox;
162 rbAreaLeft: TRadioButton;
163 rbAreaRight: TRadioButton;
164 // Вкладка "Триггеры":
165 tsTriggers: TTabSheet;
166 lbTriggersList: TListBox;
167 clbActivationType: TCheckListBox;
168 clbKeys: TCheckListBox;
170 // Остальные панели
171 Splitter1: TSplitter;
172 Splitter2: TSplitter;
173 StatusBar: TStatusBar;
175 // Специальные объекты:
176 ImageList: TImageList;
177 ilToolbar: TImageList;
178 OpenDialog: TOpenDialog;
179 SaveDialog: TSaveDialog;
180 selectall1: TMenuItem;
181 ColorDialog: TColorDialog;
183 procedure aAboutExecute(Sender: TObject);
184 procedure aCheckMapExecute(Sender: TObject);
185 procedure aMoveToFore(Sender: TObject);
186 procedure aMoveToBack(Sender: TObject);
187 procedure aCopyObjectExecute(Sender: TObject);
188 procedure aCutObjectExecute(Sender: TObject);
189 procedure aEditorOptionsExecute(Sender: TObject);
190 procedure aExitExecute(Sender: TObject);
191 procedure aMapOptionsExecute(Sender: TObject);
192 procedure aNewMapExecute(Sender: TObject);
193 procedure aOpenMapExecute(Sender: TObject);
194 procedure aOptimizeExecute(Sender: TObject);
195 procedure aPasteObjectExecute(Sender: TObject);
196 procedure aSelectAllExecute(Sender: TObject);
197 procedure aSaveMapExecute(Sender: TObject);
198 procedure aSaveMapAsExecute(Sender: TObject);
199 procedure aUndoExecute(Sender: TObject);
200 procedure aDeleteMap(Sender: TObject);
201 procedure bApplyPropertyClick(Sender: TObject);
202 procedure bbAddTextureClick(Sender: TObject);
203 procedure bbRemoveTextureClick(Sender: TObject);
204 procedure FormActivate(Sender: TObject);
205 procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
206 procedure FormCreate(Sender: TObject);
207 procedure FormDestroy(Sender: TObject);
208 procedure FormDropFiles(Sender: TObject; const FileNames: array of String);
209 procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
210 procedure FormResize(Sender: TObject);
211 procedure lbTextureListClick(Sender: TObject);
212 procedure lbTextureListDrawItem(Control: TWinControl; Index: Integer;
213 ARect: TRect; State: TOwnerDrawState);
214 procedure miReopenMapClick(Sender: TObject);
215 procedure RenderPanelMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
216 procedure RenderPanelMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
217 procedure RenderPanelMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
218 procedure RenderPanelPaint(Sender: TObject);
219 procedure RenderPanelResize(Sender: TObject);
220 procedure Splitter1Moved(Sender: TObject);
221 procedure vleObjectPropertyEditButtonClick(Sender: TObject);
222 procedure vleObjectPropertyApply(Sender: TObject);
223 procedure vleObjectPropertyGetPickList(Sender: TObject; const KeyName: String; Values: TStrings);
224 procedure vleObjectPropertyKeyDown(Sender: TObject; var Key: Word;
225 Shift: TShiftState);
226 procedure tbGridOnClick(Sender: TObject);
227 procedure miMapPreviewClick(Sender: TObject);
228 procedure miLayer1Click(Sender: TObject);
229 procedure miLayer2Click(Sender: TObject);
230 procedure miLayer3Click(Sender: TObject);
231 procedure miLayer4Click(Sender: TObject);
232 procedure miLayer5Click(Sender: TObject);
233 procedure miLayer6Click(Sender: TObject);
234 procedure miLayer7Click(Sender: TObject);
235 procedure miLayer8Click(Sender: TObject);
236 procedure miLayer9Click(Sender: TObject);
237 procedure tbShowClick(Sender: TObject);
238 procedure miSnapToGridClick(Sender: TObject);
239 procedure miMiniMapClick(Sender: TObject);
240 procedure miSwitchGridClick(Sender: TObject);
241 procedure miShowEdgesClick(Sender: TObject);
242 procedure minexttabClick(Sender: TObject);
243 procedure miSaveMiniMapClick(Sender: TObject);
244 procedure bClearTextureClick(Sender: TObject);
245 procedure miPackMapClick(Sender: TObject);
246 procedure aRecentFileExecute(Sender: TObject);
247 procedure miMapTestSettingsClick(Sender: TObject);
248 procedure miTestMapClick(Sender: TObject);
249 procedure sbVerticalScroll(Sender: TObject; ScrollCode: TScrollCode;
250 var ScrollPos: Integer);
251 procedure sbHorizontalScroll(Sender: TObject; ScrollCode: TScrollCode;
252 var ScrollPos: Integer);
253 procedure miOpenWadMapClick(Sender: TObject);
254 procedure selectall1Click(Sender: TObject);
255 procedure Splitter1CanResize(Sender: TObject; var NewSize: Integer;
256 var Accept: Boolean);
257 procedure Splitter2CanResize(Sender: TObject; var NewSize: Integer;
258 var Accept: Boolean);
259 procedure vleObjectPropertyEnter(Sender: TObject);
260 procedure vleObjectPropertyExit(Sender: TObject);
261 procedure FormKeyUp(Sender: TObject; var Key: Word;
262 Shift: TShiftState);
263 private
264 procedure Draw();
265 procedure OnIdle(Sender: TObject; var Done: Boolean);
266 public
267 procedure RefreshRecentMenu();
268 procedure OpenMapFile(FileName: String);
269 function RenderMousePos(): TPoint;
270 procedure RecountSelectedObjects();
271 end;
273 const
274 LAYER_BACK = 0;
275 LAYER_WALLS = 1;
276 LAYER_FOREGROUND = 2;
277 LAYER_STEPS = 3;
278 LAYER_WATER = 4;
279 LAYER_ITEMS = 5;
280 LAYER_MONSTERS = 6;
281 LAYER_AREAS = 7;
282 LAYER_TRIGGERS = 8;
284 TEST_MAP_NAME = '$$$_TEST_$$$';
285 LANGUAGE_FILE_NAME = '_Editor.txt';
287 var
288 MainForm: TMainForm;
289 EditorDir: String;
290 OpenedMap: String;
291 OpenedWAD: String;
293 DotColor: TColor;
294 DotEnable: Boolean;
295 DotStep: Word;
296 DotStepOne, DotStepTwo: Word;
297 DotSize: Byte;
298 DrawTexturePanel: Boolean;
299 DrawPanelSize: Boolean;
300 BackColor: TColor;
301 PreviewColor: TColor;
302 UseCheckerboard: Boolean;
303 Scale: Byte;
304 RecentCount: Integer;
305 RecentFiles: TStringList;
306 slInvalidTextures: TStringList;
308 TestGameMode: String;
309 TestLimTime: String;
310 TestLimScore: String;
311 TestOptionsTwoPlayers: Boolean;
312 TestOptionsTeamDamage: Boolean;
313 TestOptionsAllowExit: Boolean;
314 TestOptionsWeaponStay: Boolean;
315 TestOptionsMonstersDM: Boolean;
316 TestD2dExe, TestD2DArgs: String;
317 TestMapOnce: Boolean;
319 LayerEnabled: Array [LAYER_BACK..LAYER_TRIGGERS] of Boolean =
320 (True, True, True, True, True, True, True, True, True);
321 ContourEnabled: Array [LAYER_BACK..LAYER_TRIGGERS] of Boolean =
322 (False, False, False, False, False, False, False, False, False);
323 PreviewMode: Byte = 0;
324 gLanguage: String;
326 FormCaption: String;
329 procedure OpenMap(FileName: String; mapN: String);
330 function AddTexture(aWAD, aSection, aTex: String; silent: Boolean): Boolean;
331 procedure RemoveSelectFromObjects();
332 procedure ChangeShownProperty(Name: String; NewValue: String);
334 implementation
336 uses
337 f_options, e_graphics, e_log, GL, Math,
338 f_mapoptions, g_basic, f_about, f_mapoptimization,
339 f_mapcheck, f_addresource_texture, g_textures,
340 f_activationtype, f_keys,
341 MAPREADER, f_selectmap, f_savemap, WADEDITOR, MAPDEF,
342 g_map, f_saveminimap, f_addresource, CONFIG, f_packmap,
343 f_addresource_sound, f_maptest, f_choosetype,
344 g_language, f_selectlang, ClipBrd, g_resources;
346 const
347 UNDO_DELETE_PANEL = 1;
348 UNDO_DELETE_ITEM = 2;
349 UNDO_DELETE_AREA = 3;
350 UNDO_DELETE_MONSTER = 4;
351 UNDO_DELETE_TRIGGER = 5;
352 UNDO_ADD_PANEL = 6;
353 UNDO_ADD_ITEM = 7;
354 UNDO_ADD_AREA = 8;
355 UNDO_ADD_MONSTER = 9;
356 UNDO_ADD_TRIGGER = 10;
357 UNDO_MOVE_PANEL = 11;
358 UNDO_MOVE_ITEM = 12;
359 UNDO_MOVE_AREA = 13;
360 UNDO_MOVE_MONSTER = 14;
361 UNDO_MOVE_TRIGGER = 15;
362 UNDO_RESIZE_PANEL = 16;
363 UNDO_RESIZE_TRIGGER = 17;
365 MOUSEACTION_NONE = 0;
366 MOUSEACTION_DRAWPANEL = 1;
367 MOUSEACTION_DRAWTRIGGER = 2;
368 MOUSEACTION_MOVEOBJ = 3;
369 MOUSEACTION_RESIZE = 4;
370 MOUSEACTION_MOVEMAP = 5;
371 MOUSEACTION_DRAWPRESS = 6;
372 MOUSEACTION_NOACTION = 7;
374 RESIZETYPE_NONE = 0;
375 RESIZETYPE_VERTICAL = 1;
376 RESIZETYPE_HORIZONTAL = 2;
378 RESIZEDIR_NONE = 0;
379 RESIZEDIR_DOWN = 1;
380 RESIZEDIR_UP = 2;
381 RESIZEDIR_RIGHT = 3;
382 RESIZEDIR_LEFT = 4;
384 SELECTFLAG_NONE = 0;
385 SELECTFLAG_TELEPORT = 1;
386 SELECTFLAG_DOOR = 2;
387 SELECTFLAG_TEXTURE = 3;
388 SELECTFLAG_LIFT = 4;
389 SELECTFLAG_MONSTER = 5;
390 SELECTFLAG_SPAWNPOINT = 6;
391 SELECTFLAG_SHOTPANEL = 7;
392 SELECTFLAG_SELECTED = 8;
394 RECENT_FILES_MENU_START = 12;
396 CLIPBOARD_SIG = 'DF:ED';
398 type
399 TUndoRec = record
400 UndoType: Byte;
401 case Byte of
402 UNDO_DELETE_PANEL: (Panel: ^TPanel);
403 UNDO_DELETE_ITEM: (Item: TItem);
404 UNDO_DELETE_AREA: (Area: TArea);
405 UNDO_DELETE_MONSTER: (Monster: TMonster);
406 UNDO_DELETE_TRIGGER: (Trigger: TTrigger);
407 UNDO_ADD_PANEL,
408 UNDO_ADD_ITEM,
409 UNDO_ADD_AREA,
410 UNDO_ADD_MONSTER,
411 UNDO_ADD_TRIGGER: (AddID: DWORD);
412 UNDO_MOVE_PANEL,
413 UNDO_MOVE_ITEM,
414 UNDO_MOVE_AREA,
415 UNDO_MOVE_MONSTER,
416 UNDO_MOVE_TRIGGER: (MoveID: DWORD; dX, dY: Integer);
417 UNDO_RESIZE_PANEL,
418 UNDO_RESIZE_TRIGGER: (ResizeID: DWORD; dW, dH: Integer);
419 end;
421 TCopyRec = record
422 ObjectType: Byte;
423 ID: Cardinal;
424 case Byte of
425 OBJECT_PANEL: (Panel: ^TPanel);
426 OBJECT_ITEM: (Item: TItem);
427 OBJECT_AREA: (Area: TArea);
428 OBJECT_MONSTER: (Monster: TMonster);
429 OBJECT_TRIGGER: (Trigger: TTrigger);
430 end;
432 TCopyRecArray = Array of TCopyRec;
434 var
435 gEditorFont: DWORD;
436 gDataLoaded: Boolean = False;
437 ShowMap: Boolean = False;
438 DrawRect: PRect = nil;
439 SnapToGrid: Boolean = True;
441 MousePos: Types.TPoint;
442 LastMovePoint: Types.TPoint;
443 MouseLDown: Boolean;
444 MouseRDown: Boolean;
445 MouseLDownPos: Types.TPoint;
446 MouseRDownPos: Types.TPoint;
448 SelectFlag: Byte = SELECTFLAG_NONE;
449 MouseAction: Byte = MOUSEACTION_NONE;
450 ResizeType: Byte = RESIZETYPE_NONE;
451 ResizeDirection: Byte = RESIZEDIR_NONE;
453 DrawPressRect: Boolean = False;
454 EditingProperties: Boolean = False;
456 UndoBuffer: Array of Array of TUndoRec = nil;
459 {$R *.lfm}
461 //----------------------------------------
462 //Далее идут вспомогательные процедуры
463 //----------------------------------------
465 function NameToBool(Name: String): Boolean;
466 begin
467 if Name = BoolNames[True] then
468 Result := True
469 else
470 Result := False;
471 end;
473 function NameToDir(Name: String): TDirection;
474 begin
475 if Name = DirNames[D_LEFT] then
476 Result := D_LEFT
477 else
478 Result := D_RIGHT;
479 end;
481 function NameToDirAdv(Name: String): Byte;
482 begin
483 if Name = DirNamesAdv[1] then
484 Result := 1
485 else
486 if Name = DirNamesAdv[2] then
487 Result := 2
488 else
489 if Name = DirNamesAdv[3] then
490 Result := 3
491 else
492 Result := 0;
493 end;
495 function ActivateToStr(ActivateType: Byte): String;
496 begin
497 Result := '';
499 if ByteBool(ACTIVATE_PLAYERCOLLIDE and ActivateType) then
500 Result := Result + '+PC';
501 if ByteBool(ACTIVATE_MONSTERCOLLIDE and ActivateType) then
502 Result := Result + '+MC';
503 if ByteBool(ACTIVATE_PLAYERPRESS and ActivateType) then
504 Result := Result + '+PP';
505 if ByteBool(ACTIVATE_MONSTERPRESS and ActivateType) then
506 Result := Result + '+MP';
507 if ByteBool(ACTIVATE_SHOT and ActivateType) then
508 Result := Result + '+SH';
509 if ByteBool(ACTIVATE_NOMONSTER and ActivateType) then
510 Result := Result + '+NM';
512 if (Result <> '') and (Result[1] = '+') then
513 Delete(Result, 1, 1);
514 end;
516 function StrToActivate(Str: String): Byte;
517 begin
518 Result := 0;
520 if Pos('PC', Str) > 0 then
521 Result := ACTIVATE_PLAYERCOLLIDE;
522 if Pos('MC', Str) > 0 then
523 Result := Result or ACTIVATE_MONSTERCOLLIDE;
524 if Pos('PP', Str) > 0 then
525 Result := Result or ACTIVATE_PLAYERPRESS;
526 if Pos('MP', Str) > 0 then
527 Result := Result or ACTIVATE_MONSTERPRESS;
528 if Pos('SH', Str) > 0 then
529 Result := Result or ACTIVATE_SHOT;
530 if Pos('NM', Str) > 0 then
531 Result := Result or ACTIVATE_NOMONSTER;
532 end;
534 function KeyToStr(Key: Byte): String;
535 begin
536 Result := '';
538 if ByteBool(KEY_RED and Key) then
539 Result := Result + '+RK';
540 if ByteBool(KEY_GREEN and Key) then
541 Result := Result + '+GK';
542 if ByteBool(KEY_BLUE and Key) then
543 Result := Result + '+BK';
544 if ByteBool(KEY_REDTEAM and Key) then
545 Result := Result + '+RT';
546 if ByteBool(KEY_BLUETEAM and Key) then
547 Result := Result + '+BT';
549 if (Result <> '') and (Result[1] = '+') then
550 Delete(Result, 1, 1);
551 end;
553 function StrToKey(Str: String): Byte;
554 begin
555 Result := 0;
557 if Pos('RK', Str) > 0 then
558 Result := KEY_RED;
559 if Pos('GK', Str) > 0 then
560 Result := Result or KEY_GREEN;
561 if Pos('BK', Str) > 0 then
562 Result := Result or KEY_BLUE;
563 if Pos('RT', Str) > 0 then
564 Result := Result or KEY_REDTEAM;
565 if Pos('BT', Str) > 0 then
566 Result := Result or KEY_BLUETEAM;
567 end;
569 function EffectToStr(Effect: Byte): String;
570 begin
571 if Effect in [EFFECT_TELEPORT..EFFECT_FIRE] then
572 Result := EffectNames[Effect]
573 else
574 Result := EffectNames[EFFECT_NONE];
575 end;
577 function StrToEffect(Str: String): Byte;
578 var
579 i: Integer;
580 begin
581 Result := EFFECT_NONE;
582 for i := EFFECT_TELEPORT to EFFECT_FIRE do
583 if EffectNames[i] = Str then
584 begin
585 Result := i;
586 Exit;
587 end;
588 end;
590 function MonsterToStr(MonType: Byte): String;
591 begin
592 if MonType in [MONSTER_DEMON..MONSTER_MAN] then
593 Result := MonsterNames[MonType]
594 else
595 Result := MonsterNames[MONSTER_ZOMBY];
596 end;
598 function StrToMonster(Str: String): Byte;
599 var
600 i: Integer;
601 begin
602 Result := MONSTER_ZOMBY;
603 for i := MONSTER_DEMON to MONSTER_MAN do
604 if MonsterNames[i] = Str then
605 begin
606 Result := i;
607 Exit;
608 end;
609 end;
611 function ItemToStr(ItemType: Byte): String;
612 begin
613 if ItemType in [ITEM_MEDKIT_SMALL..ITEM_MAX] then
614 Result := ItemNames[ItemType]
615 else
616 Result := ItemNames[ITEM_AMMO_BULLETS];
617 end;
619 function StrToItem(Str: String): Byte;
620 var
621 i: Integer;
622 begin
623 Result := ITEM_AMMO_BULLETS;
624 for i := ITEM_MEDKIT_SMALL to ITEM_MAX do
625 if ItemNames[i] = Str then
626 begin
627 Result := i;
628 Exit;
629 end;
630 end;
632 function ShotToStr(ShotType: Byte): String;
633 begin
634 if ShotType in [TRIGGER_SHOT_PISTOL..TRIGGER_SHOT_MAX] then
635 Result := ShotNames[ShotType]
636 else
637 Result := ShotNames[TRIGGER_SHOT_PISTOL];
638 end;
640 function StrToShot(Str: String): Byte;
641 var
642 i: Integer;
643 begin
644 Result := TRIGGER_SHOT_PISTOL;
645 for i := TRIGGER_SHOT_PISTOL to TRIGGER_SHOT_MAX do
646 if ShotNames[i] = Str then
647 begin
648 Result := i;
649 Exit;
650 end;
651 end;
653 function SelectedObjectCount(): Word;
654 var
655 a: Integer;
656 begin
657 Result := 0;
659 if SelectedObjects = nil then
660 Exit;
662 for a := 0 to High(SelectedObjects) do
663 if SelectedObjects[a].Live then
664 Result := Result + 1;
665 end;
667 function GetFirstSelected(): Integer;
668 var
669 a: Integer;
670 begin
671 Result := -1;
673 if SelectedObjects = nil then
674 Exit;
676 for a := 0 to High(SelectedObjects) do
677 if SelectedObjects[a].Live then
678 begin
679 Result := a;
680 Exit;
681 end;
682 end;
684 function Normalize16(x: Integer): Integer;
685 begin
686 Result := (x div 16) * 16;
687 end;
689 procedure MoveMap(X, Y: Integer);
690 var
691 rx, ry, ScaleSz: Integer;
692 begin
693 with MainForm.RenderPanel do
694 begin
695 ScaleSz := 16 div Scale;
696 // Размер видимой части карты:
697 rx := Min(Normalize16(Width), Normalize16(gMapInfo.Width)) div 2;
698 ry := Min(Normalize16(Height), Normalize16(gMapInfo.Height)) div 2;
699 // Место клика на мини-карте:
700 MapOffset.X := X - (Width - Max(gMapInfo.Width div ScaleSz, 1) - 1);
701 MapOffset.Y := Y - 1;
702 // Это же место на "большой" карте:
703 MapOffset.X := MapOffset.X * ScaleSz;
704 MapOffset.Y := MapOffset.Y * ScaleSz;
705 // Левый верхний угол новой видимой части карты:
706 MapOffset.X := MapOffset.X - rx;
707 MapOffset.Y := MapOffset.Y - ry;
708 // Выход за границы:
709 if MapOffset.X < MainForm.sbHorizontal.Min then
710 MapOffset.X := MainForm.sbHorizontal.Min;
711 if MapOffset.Y < MainForm.sbVertical.Min then
712 MapOffset.Y := MainForm.sbVertical.Min;
713 if MapOffset.X > MainForm.sbHorizontal.Max then
714 MapOffset.X := MainForm.sbHorizontal.Max;
715 if MapOffset.Y > MainForm.sbVertical.Max then
716 MapOffset.Y := MainForm.sbVertical.Max;
717 // Кратно 16:
718 // MapOffset.X := Normalize16(MapOffset.X);
719 // MapOffset.Y := Normalize16(MapOffset.Y);
720 end;
722 MainForm.sbHorizontal.Position := MapOffset.X;
723 MainForm.sbVertical.Position := MapOffset.Y;
725 MapOffset.X := -MapOffset.X;
726 MapOffset.Y := -MapOffset.Y;
728 MainForm.Resize();
729 end;
731 function IsTexturedPanel(PanelType: Word): Boolean;
732 begin
733 Result := WordBool(PanelType and (PANEL_WALL or PANEL_BACK or PANEL_FORE or
734 PANEL_STEP or PANEL_OPENDOOR or PANEL_CLOSEDOOR or
735 PANEL_WATER or PANEL_ACID1 or PANEL_ACID2));
736 end;
738 procedure FillProperty();
739 var
740 _id: DWORD;
741 str: String;
742 begin
743 MainForm.vleObjectProperty.Strings.Clear();
744 MainForm.RecountSelectedObjects();
746 // Отображаем свойства если выделен только один объект:
747 if SelectedObjectCount() <> 1 then
748 Exit;
750 _id := GetFirstSelected();
751 if not SelectedObjects[_id].Live then
752 Exit;
754 with MainForm.vleObjectProperty do
755 with ItemProps[InsertRow(_lc[I_PROP_ID], IntToStr(SelectedObjects[_id].ID), True)] do
756 begin
757 EditStyle := esSimple;
758 ReadOnly := True;
759 end;
761 case SelectedObjects[0].ObjectType of
762 OBJECT_PANEL:
763 begin
764 with MainForm.vleObjectProperty,
765 gPanels[SelectedObjects[_id].ID] do
766 begin
767 with ItemProps[InsertRow(_lc[I_PROP_X], IntToStr(X), True)] do
768 begin
769 EditStyle := esSimple;
770 MaxLength := 5;
771 end;
773 with ItemProps[InsertRow(_lc[I_PROP_Y], IntToStr(Y), True)] do
774 begin
775 EditStyle := esSimple;
776 MaxLength := 5;
777 end;
779 with ItemProps[InsertRow(_lc[I_PROP_WIDTH], IntToStr(Width), True)] do
780 begin
781 EditStyle := esSimple;
782 MaxLength := 5;
783 end;
785 with ItemProps[InsertRow(_lc[I_PROP_HEIGHT], IntToStr(Height), True)] do
786 begin
787 EditStyle := esSimple;
788 MaxLength := 5;
789 end;
791 with ItemProps[InsertRow(_lc[I_PROP_PANEL_TYPE], GetPanelName(PanelType), True)] do
792 begin
793 EditStyle := esEllipsis;
794 ReadOnly := True;
795 end;
797 if IsTexturedPanel(PanelType) then
798 begin // Может быть текстура
799 with ItemProps[InsertRow(_lc[I_PROP_PANEL_TEX], TextureName, True)] do
800 begin
801 EditStyle := esEllipsis;
802 ReadOnly := True;
803 end;
805 if TextureName <> '' then
806 begin // Есть текстура
807 with ItemProps[InsertRow(_lc[I_PROP_PANEL_ALPHA], IntToStr(Alpha), True)] do
808 begin
809 EditStyle := esSimple;
810 MaxLength := 3;
811 end;
813 with ItemProps[InsertRow(_lc[I_PROP_PANEL_BLEND], BoolNames[Blending], True)] do
814 begin
815 EditStyle := esPickList;
816 ReadOnly := True;
817 end;
818 end;
819 end;
820 end;
821 end;
823 OBJECT_ITEM:
824 begin
825 with MainForm.vleObjectProperty,
826 gItems[SelectedObjects[_id].ID] do
827 begin
828 with ItemProps[InsertRow(_lc[I_PROP_X], IntToStr(X), True)] do
829 begin
830 EditStyle := esSimple;
831 MaxLength := 5;
832 end;
834 with ItemProps[InsertRow(_lc[I_PROP_Y], IntToStr(Y), True)] do
835 begin
836 EditStyle := esSimple;
837 MaxLength := 5;
838 end;
840 with ItemProps[InsertRow(_lc[I_PROP_DM_ONLY], BoolNames[OnlyDM], True)] do
841 begin
842 EditStyle := esPickList;
843 ReadOnly := True;
844 end;
846 with ItemProps[InsertRow(_lc[I_PROP_ITEM_FALLS], BoolNames[Fall], True)] do
847 begin
848 EditStyle := esPickList;
849 ReadOnly := True;
850 end;
851 end;
852 end;
854 OBJECT_MONSTER:
855 begin
856 with MainForm.vleObjectProperty,
857 gMonsters[SelectedObjects[_id].ID] do
858 begin
859 with ItemProps[InsertRow(_lc[I_PROP_X], IntToStr(X), True)] do
860 begin
861 EditStyle := esSimple;
862 MaxLength := 5;
863 end;
865 with ItemProps[InsertRow(_lc[I_PROP_Y], IntToStr(Y), True)] do
866 begin
867 EditStyle := esSimple;
868 MaxLength := 5;
869 end;
871 with ItemProps[InsertRow(_lc[I_PROP_DIRECTION], DirNames[Direction], True)] do
872 begin
873 EditStyle := esPickList;
874 ReadOnly := True;
875 end;
876 end;
877 end;
879 OBJECT_AREA:
880 begin
881 with MainForm.vleObjectProperty,
882 gAreas[SelectedObjects[_id].ID] do
883 begin
884 with ItemProps[InsertRow(_lc[I_PROP_X], IntToStr(X), True)] do
885 begin
886 EditStyle := esSimple;
887 MaxLength := 5;
888 end;
890 with ItemProps[InsertRow(_lc[I_PROP_Y], IntToStr(Y), True)] do
891 begin
892 EditStyle := esSimple;
893 MaxLength := 5;
894 end;
896 with ItemProps[InsertRow(_lc[I_PROP_DIRECTION], DirNames[Direction], True)] do
897 begin
898 EditStyle := esPickList;
899 ReadOnly := True;
900 end;
901 end;
902 end;
904 OBJECT_TRIGGER:
905 begin
906 with MainForm.vleObjectProperty,
907 gTriggers[SelectedObjects[_id].ID] do
908 begin
909 with ItemProps[InsertRow(_lc[I_PROP_TR_TYPE], GetTriggerName(TriggerType), True)] do
910 begin
911 EditStyle := esSimple;
912 ReadOnly := True;
913 end;
915 with ItemProps[InsertRow(_lc[I_PROP_X], IntToStr(X), True)] do
916 begin
917 EditStyle := esSimple;
918 MaxLength := 5;
919 end;
921 with ItemProps[InsertRow(_lc[I_PROP_Y], IntToStr(Y), True)] do
922 begin
923 EditStyle := esSimple;
924 MaxLength := 5;
925 end;
927 with ItemProps[InsertRow(_lc[I_PROP_WIDTH], IntToStr(Width), True)] do
928 begin
929 EditStyle := esSimple;
930 MaxLength := 5;
931 end;
933 with ItemProps[InsertRow(_lc[I_PROP_HEIGHT], IntToStr(Height), True)] do
934 begin
935 EditStyle := esSimple;
936 MaxLength := 5;
937 end;
939 with ItemProps[InsertRow(_lc[I_PROP_TR_ENABLED], BoolNames[Enabled], True)] do
940 begin
941 EditStyle := esPickList;
942 ReadOnly := True;
943 end;
945 with ItemProps[InsertRow(_lc[I_PROP_TR_TEXTURE_PANEL], IntToStr(TexturePanel), True)] do
946 begin
947 EditStyle := esEllipsis;
948 ReadOnly := True;
949 end;
951 with ItemProps[InsertRow(_lc[I_PROP_TR_ACTIVATION], ActivateToStr(ActivateType), True)] do
952 begin
953 EditStyle := esEllipsis;
954 ReadOnly := True;
955 end;
957 with ItemProps[InsertRow(_lc[I_PROP_TR_KEYS], KeyToStr(Key), True)] do
958 begin
959 EditStyle := esEllipsis;
960 ReadOnly := True;
961 end;
963 case TriggerType of
964 TRIGGER_EXIT:
965 begin
966 str := win2utf(Data.MapName);
967 with ItemProps[InsertRow(_lc[I_PROP_TR_NEXT_MAP], str, True)] do
968 begin
969 EditStyle := esEllipsis;
970 ReadOnly := True;
971 end;
972 end;
974 TRIGGER_TELEPORT:
975 begin
976 with ItemProps[InsertRow(_lc[I_PROP_TR_TELEPORT_TO], Format('(%d:%d)', [Data.TargetPoint.X, Data.TargetPoint.Y]), True)] do
977 begin
978 EditStyle := esEllipsis;
979 ReadOnly := True;
980 end;
982 with ItemProps[InsertRow(_lc[I_PROP_TR_D2D], BoolNames[Data.d2d_teleport], True)] do
983 begin
984 EditStyle := esPickList;
985 ReadOnly := True;
986 end;
988 with ItemProps[InsertRow(_lc[I_PROP_TR_TELEPORT_SILENT], BoolNames[Data.silent_teleport], True)] do
989 begin
990 EditStyle := esPickList;
991 ReadOnly := True;
992 end;
994 with ItemProps[InsertRow(_lc[I_PROP_TR_TELEPORT_DIR], DirNamesAdv[Data.TlpDir], True)] do
995 begin
996 EditStyle := esPickList;
997 ReadOnly := True;
998 end;
999 end;
1001 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR,
1002 TRIGGER_DOOR, TRIGGER_DOOR5:
1003 begin
1004 with ItemProps[InsertRow(_lc[I_PROP_TR_DOOR_PANEL], IntToStr(Data.PanelID), True)] do
1005 begin
1006 EditStyle := esEllipsis;
1007 ReadOnly := True;
1008 end;
1010 with ItemProps[InsertRow(_lc[I_PROP_TR_SILENT], BoolNames[Data.NoSound], True)] do
1011 begin
1012 EditStyle := esPickList;
1013 ReadOnly := True;
1014 end;
1016 with ItemProps[InsertRow(_lc[I_PROP_TR_D2D], BoolNames[Data.d2d_doors], True)] do
1017 begin
1018 EditStyle := esPickList;
1019 ReadOnly := True;
1020 end;
1021 end;
1023 TRIGGER_CLOSETRAP, TRIGGER_TRAP:
1024 begin
1025 with ItemProps[InsertRow(_lc[I_PROP_TR_TRAP_PANEL], IntToStr(Data.PanelID), True)] do
1026 begin
1027 EditStyle := esEllipsis;
1028 ReadOnly := True;
1029 end;
1031 with ItemProps[InsertRow(_lc[I_PROP_TR_SILENT], BoolNames[Data.NoSound], True)] do
1032 begin
1033 EditStyle := esPickList;
1034 ReadOnly := True;
1035 end;
1037 with ItemProps[InsertRow(_lc[I_PROP_TR_D2D], BoolNames[Data.d2d_doors], True)] do
1038 begin
1039 EditStyle := esPickList;
1040 ReadOnly := True;
1041 end;
1042 end;
1044 TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF,
1045 TRIGGER_ONOFF:
1046 begin
1047 with ItemProps[InsertRow(_lc[I_PROP_TR_EX_AREA],
1048 Format('(%d:%d %d:%d)', [Data.tX, Data.tY, Data.tWidth, Data.tHeight]), True)] do
1049 begin
1050 EditStyle := esEllipsis;
1051 ReadOnly := True;
1052 end;
1054 with ItemProps[InsertRow(_lc[I_PROP_TR_EX_DELAY], IntToStr(Data.Wait), True)] do
1055 begin
1056 EditStyle := esSimple;
1057 MaxLength := 5;
1058 end;
1060 with ItemProps[InsertRow(_lc[I_PROP_TR_EX_COUNT], IntToStr(Data.Count), True)] do
1061 begin
1062 EditStyle := esSimple;
1063 MaxLength := 5;
1064 end;
1066 with ItemProps[InsertRow(_lc[I_PROP_TR_EX_MONSTER], IntToStr(Data.MonsterID-1), True)] do
1067 begin
1068 EditStyle := esEllipsis;
1069 ReadOnly := True;
1070 end;
1072 if TriggerType = TRIGGER_PRESS then
1073 with ItemProps[InsertRow(_lc[I_PROP_TR_EX_RANDOM], BoolNames[Data.ExtRandom], True)] do
1074 begin
1075 EditStyle := esPickList;
1076 ReadOnly := True;
1077 end;
1078 end;
1080 TRIGGER_SECRET:
1083 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
1084 begin
1085 with ItemProps[InsertRow(_lc[I_PROP_TR_LIFT_PANEL], IntToStr(Data.PanelID), True)] do
1086 begin
1087 EditStyle := esEllipsis;
1088 ReadOnly := True;
1089 end;
1091 with ItemProps[InsertRow(_lc[I_PROP_TR_SILENT], BoolNames[Data.NoSound], True)] do
1092 begin
1093 EditStyle := esPickList;
1094 ReadOnly := True;
1095 end;
1097 with ItemProps[InsertRow(_lc[I_PROP_TR_D2D], BoolNames[Data.d2d_doors], True)] do
1098 begin
1099 EditStyle := esPickList;
1100 ReadOnly := True;
1101 end;
1102 end;
1104 TRIGGER_TEXTURE:
1105 begin
1106 with ItemProps[InsertRow(_lc[I_PROP_TR_TEXTURE_ONCE], BoolNames[Data.ActivateOnce], True)] do
1107 begin
1108 EditStyle := esPickList;
1109 ReadOnly := True;
1110 end;
1112 with ItemProps[InsertRow(_lc[I_PROP_TR_TEXTURE_ANIM_ONCE], BoolNames[Data.AnimOnce], True)] do
1113 begin
1114 EditStyle := esPickList;
1115 ReadOnly := True;
1116 end;
1117 end;
1119 TRIGGER_SOUND:
1120 begin
1121 str := win2utf(Data.SoundName);
1122 with ItemProps[InsertRow(_lc[I_PROP_TR_SOUND_NAME], str, True)] do
1123 begin
1124 EditStyle := esEllipsis;
1125 ReadOnly := True;
1126 end;
1128 with ItemProps[InsertRow(_lc[I_PROP_TR_SOUND_VOLUME], IntToStr(Data.Volume), True)] do
1129 begin
1130 EditStyle := esSimple;
1131 MaxLength := 3;
1132 end;
1134 with ItemProps[InsertRow(_lc[I_PROP_TR_SOUND_PAN], IntToStr(Data.Pan), True)] do
1135 begin
1136 EditStyle := esSimple;
1137 MaxLength := 3;
1138 end;
1140 with ItemProps[InsertRow(_lc[I_PROP_TR_SOUND_COUNT], IntToStr(Data.PlayCount), True)] do
1141 begin
1142 EditStyle := esSimple;
1143 MaxLength := 3;
1144 end;
1146 with ItemProps[InsertRow(_lc[I_PROP_TR_SOUND_LOCAL], BoolNames[Data.Local], True)] do
1147 begin
1148 EditStyle := esPickList;
1149 ReadOnly := True;
1150 end;
1152 with ItemProps[InsertRow(_lc[I_PROP_TR_SOUND_SWITCH], BoolNames[Data.SoundSwitch], True)] do
1153 begin
1154 EditStyle := esPickList;
1155 ReadOnly := True;
1156 end;
1157 end;
1159 TRIGGER_SPAWNMONSTER:
1160 begin
1161 with ItemProps[InsertRow(_lc[I_PROP_TR_MONSTER_TYPE], MonsterToStr(Data.MonType), True)] do
1162 begin
1163 EditStyle := esEllipsis;
1164 ReadOnly := True;
1165 end;
1167 with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_TO],
1168 Format('(%d:%d)', [Data.MonPos.X, Data.MonPos.Y]), True)] do
1169 begin
1170 EditStyle := esEllipsis;
1171 ReadOnly := True;
1172 end;
1174 with ItemProps[InsertRow(_lc[I_PROP_DIRECTION], DirNames[TDirection(Data.MonDir)], True)] do
1175 begin
1176 EditStyle := esPickList;
1177 ReadOnly := True;
1178 end;
1180 with ItemProps[InsertRow(_lc[I_PROP_TR_HEALTH], IntToStr(Data.MonHealth), True)] do
1181 begin
1182 EditStyle := esSimple;
1183 MaxLength := 5;
1184 end;
1186 with ItemProps[InsertRow(_lc[I_PROP_TR_MONSTER_ACTIVE], BoolNames[Data.MonActive], True)] do
1187 begin
1188 EditStyle := esPickList;
1189 ReadOnly := True;
1190 end;
1192 with ItemProps[InsertRow(_lc[I_PROP_TR_COUNT], IntToStr(Data.MonCount), True)] do
1193 begin
1194 EditStyle := esSimple;
1195 MaxLength := 5;
1196 end;
1198 with ItemProps[InsertRow(_lc[I_PROP_TR_FX_TYPE], EffectToStr(Data.MonEffect), True)] do
1199 begin
1200 EditStyle := esEllipsis;
1201 ReadOnly := True;
1202 end;
1204 with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_MAX], IntToStr(Data.MonMax), True)] do
1205 begin
1206 EditStyle := esSimple;
1207 MaxLength := 5;
1208 end;
1210 with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_DELAY], IntToStr(Data.MonDelay), True)] do
1211 begin
1212 EditStyle := esSimple;
1213 MaxLength := 5;
1214 end;
1216 case Data.MonBehav of
1217 1: str := _lc[I_PROP_TR_MONSTER_BEHAVIOUR_1];
1218 2: str := _lc[I_PROP_TR_MONSTER_BEHAVIOUR_2];
1219 3: str := _lc[I_PROP_TR_MONSTER_BEHAVIOUR_3];
1220 4: str := _lc[I_PROP_TR_MONSTER_BEHAVIOUR_4];
1221 5: str := _lc[I_PROP_TR_MONSTER_BEHAVIOUR_5];
1222 else str := _lc[I_PROP_TR_MONSTER_BEHAVIOUR_0];
1223 end;
1224 with ItemProps[InsertRow(_lc[I_PROP_TR_MONSTER_BEHAVIOUR], str, True)] do
1225 begin
1226 EditStyle := esPickList;
1227 ReadOnly := True;
1228 end;
1229 end;
1231 TRIGGER_SPAWNITEM:
1232 begin
1233 with ItemProps[InsertRow(_lc[I_PROP_TR_ITEM_TYPE], ItemToStr(Data.ItemType), True)] do
1234 begin
1235 EditStyle := esEllipsis;
1236 ReadOnly := True;
1237 end;
1239 with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_TO],
1240 Format('(%d:%d)', [Data.ItemPos.X, Data.ItemPos.Y]), True)] do
1241 begin
1242 EditStyle := esEllipsis;
1243 ReadOnly := True;
1244 end;
1246 with ItemProps[InsertRow(_lc[I_PROP_DM_ONLY], BoolNames[Data.ItemOnlyDM], True)] do
1247 begin
1248 EditStyle := esPickList;
1249 ReadOnly := True;
1250 end;
1252 with ItemProps[InsertRow(_lc[I_PROP_ITEM_FALLS], BoolNames[Data.ItemFalls], True)] do
1253 begin
1254 EditStyle := esPickList;
1255 ReadOnly := True;
1256 end;
1258 with ItemProps[InsertRow(_lc[I_PROP_TR_COUNT], IntToStr(Data.ItemCount), True)] do
1259 begin
1260 EditStyle := esSimple;
1261 MaxLength := 5;
1262 end;
1264 with ItemProps[InsertRow(_lc[I_PROP_TR_FX_TYPE], EffectToStr(Data.ItemEffect), True)] do
1265 begin
1266 EditStyle := esEllipsis;
1267 ReadOnly := True;
1268 end;
1270 with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_MAX], IntToStr(Data.ItemMax), True)] do
1271 begin
1272 EditStyle := esSimple;
1273 MaxLength := 5;
1274 end;
1276 with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_DELAY], IntToStr(Data.ItemDelay), True)] do
1277 begin
1278 EditStyle := esSimple;
1279 MaxLength := 5;
1280 end;
1281 end;
1283 TRIGGER_MUSIC:
1284 begin
1285 str := win2utf(Data.MusicName);
1286 with ItemProps[InsertRow(_lc[I_PROP_TR_MUSIC_NAME], str, True)] do
1287 begin
1288 EditStyle := esEllipsis;
1289 ReadOnly := True;
1290 end;
1292 if Data.MusicAction = 1 then
1293 str := _lc[I_PROP_TR_MUSIC_ON]
1294 else
1295 str := _lc[I_PROP_TR_MUSIC_OFF];
1297 with ItemProps[InsertRow(_lc[I_PROP_TR_MUSIC_ACT], str, True)] do
1298 begin
1299 EditStyle := esPickList;
1300 ReadOnly := True;
1301 end;
1302 end;
1304 TRIGGER_PUSH:
1305 begin
1306 with ItemProps[InsertRow(_lc[I_PROP_TR_PUSH_ANGLE], IntToStr(Data.PushAngle), True)] do
1307 begin
1308 EditStyle := esSimple;
1309 MaxLength := 4;
1310 end;
1311 with ItemProps[InsertRow(_lc[I_PROP_TR_PUSH_FORCE], IntToStr(Data.PushForce), True)] do
1312 begin
1313 EditStyle := esSimple;
1314 MaxLength := 4;
1315 end;
1316 with ItemProps[InsertRow(_lc[I_PROP_TR_PUSH_RESET], BoolNames[Data.ResetVel], True)] do
1317 begin
1318 EditStyle := esPickList;
1319 ReadOnly := True;
1320 end;
1321 end;
1323 TRIGGER_SCORE:
1324 begin
1325 case Data.ScoreAction of
1326 1: str := _lc[I_PROP_TR_SCORE_ACT_1];
1327 2: str := _lc[I_PROP_TR_SCORE_ACT_2];
1328 3: str := _lc[I_PROP_TR_SCORE_ACT_3];
1329 else str := _lc[I_PROP_TR_SCORE_ACT_0];
1330 end;
1331 with ItemProps[InsertRow(_lc[I_PROP_TR_SCORE_ACT], str, True)] do
1332 begin
1333 EditStyle := esPickList;
1334 ReadOnly := True;
1335 end;
1336 with ItemProps[InsertRow(_lc[I_PROP_TR_COUNT], IntToStr(Data.ScoreCount), True)] do
1337 begin
1338 EditStyle := esSimple;
1339 MaxLength := 3;
1340 end;
1341 case Data.ScoreTeam of
1342 1: str := _lc[I_PROP_TR_SCORE_TEAM_1];
1343 2: str := _lc[I_PROP_TR_SCORE_TEAM_2];
1344 3: str := _lc[I_PROP_TR_SCORE_TEAM_3];
1345 else str := _lc[I_PROP_TR_SCORE_TEAM_0];
1346 end;
1347 with ItemProps[InsertRow(_lc[I_PROP_TR_SCORE_TEAM], str, True)] do
1348 begin
1349 EditStyle := esPickList;
1350 ReadOnly := True;
1351 end;
1352 with ItemProps[InsertRow(_lc[I_PROP_TR_SCORE_CON], BoolNames[Data.ScoreCon], True)] do
1353 begin
1354 EditStyle := esPickList;
1355 ReadOnly := True;
1356 end;
1357 with ItemProps[InsertRow(_lc[I_PROP_TR_SCORE_MSG], BoolNames[Data.ScoreMsg], True)] do
1358 begin
1359 EditStyle := esPickList;
1360 ReadOnly := True;
1361 end;
1362 end;
1364 TRIGGER_MESSAGE:
1365 begin
1366 case Data.MessageKind of
1367 1: str := _lc[I_PROP_TR_MESSAGE_KIND_1];
1368 else str := _lc[I_PROP_TR_MESSAGE_KIND_0];
1369 end;
1370 with ItemProps[InsertRow(_lc[I_PROP_TR_MESSAGE_KIND], str, True)] do
1371 begin
1372 EditStyle := esPickList;
1373 ReadOnly := True;
1374 end;
1375 case Data.MessageSendTo of
1376 1: str := _lc[I_PROP_TR_MESSAGE_TO_1];
1377 2: str := _lc[I_PROP_TR_MESSAGE_TO_2];
1378 3: str := _lc[I_PROP_TR_MESSAGE_TO_3];
1379 4: str := _lc[I_PROP_TR_MESSAGE_TO_4];
1380 5: str := _lc[I_PROP_TR_MESSAGE_TO_5];
1381 else str := _lc[I_PROP_TR_MESSAGE_TO_0];
1382 end;
1383 with ItemProps[InsertRow(_lc[I_PROP_TR_MESSAGE_TO], str, True)] do
1384 begin
1385 EditStyle := esPickList;
1386 ReadOnly := True;
1387 end;
1388 str := win2utf(Data.MessageText);
1389 with ItemProps[InsertRow(_lc[I_PROP_TR_MESSAGE_TEXT], str, True)] do
1390 begin
1391 EditStyle := esSimple;
1392 MaxLength := 100;
1393 end;
1394 with ItemProps[InsertRow(_lc[I_PROP_TR_MESSAGE_TIME], IntToStr(Data.MessageTime), True)] do
1395 begin
1396 EditStyle := esSimple;
1397 MaxLength := 5;
1398 end;
1399 end;
1401 TRIGGER_DAMAGE:
1402 begin
1403 with ItemProps[InsertRow(_lc[I_PROP_TR_DAMAGE_VALUE], IntToStr(Data.DamageValue), True)] do
1404 begin
1405 EditStyle := esSimple;
1406 MaxLength := 5;
1407 end;
1408 with ItemProps[InsertRow(_lc[I_PROP_TR_INTERVAL], IntToStr(Data.DamageInterval), True)] do
1409 begin
1410 EditStyle := esSimple;
1411 MaxLength := 5;
1412 end;
1413 case Data.DamageKind of
1414 3: str := _lc[I_PROP_TR_DAMAGE_KIND_3];
1415 4: str := _lc[I_PROP_TR_DAMAGE_KIND_4];
1416 5: str := _lc[I_PROP_TR_DAMAGE_KIND_5];
1417 6: str := _lc[I_PROP_TR_DAMAGE_KIND_6];
1418 7: str := _lc[I_PROP_TR_DAMAGE_KIND_7];
1419 8: str := _lc[I_PROP_TR_DAMAGE_KIND_8];
1420 else str := _lc[I_PROP_TR_DAMAGE_KIND_0];
1421 end;
1422 with ItemProps[InsertRow(_lc[I_PROP_TR_DAMAGE_KIND], str, True)] do
1423 begin
1424 EditStyle := esPickList;
1425 ReadOnly := True;
1426 end;
1427 end;
1429 TRIGGER_HEALTH:
1430 begin
1431 with ItemProps[InsertRow(_lc[I_PROP_TR_HEALTH], IntToStr(Data.HealValue), True)] do
1432 begin
1433 EditStyle := esSimple;
1434 MaxLength := 5;
1435 end;
1436 with ItemProps[InsertRow(_lc[I_PROP_TR_INTERVAL], IntToStr(Data.HealInterval), True)] do
1437 begin
1438 EditStyle := esSimple;
1439 MaxLength := 5;
1440 end;
1441 with ItemProps[InsertRow(_lc[I_PROP_TR_HEALTH_MAX], BoolNames[Data.HealMax], True)] do
1442 begin
1443 EditStyle := esPickList;
1444 ReadOnly := True;
1445 end;
1446 with ItemProps[InsertRow(_lc[I_PROP_TR_SILENT], BoolNames[Data.HealSilent], True)] do
1447 begin
1448 EditStyle := esPickList;
1449 ReadOnly := True;
1450 end;
1451 end;
1453 TRIGGER_SHOT:
1454 begin
1455 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_TYPE], ShotToStr(Data.ShotType), True)] do
1456 begin
1457 EditStyle := esEllipsis;
1458 ReadOnly := True;
1459 end;
1461 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_SOUND], BoolNames[Data.ShotSound], True)] do
1462 begin
1463 EditStyle := esPickList;
1464 ReadOnly := True;
1465 end;
1467 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_PANEL], IntToStr(Data.ShotPanelID), True)] do
1468 begin
1469 EditStyle := esEllipsis;
1470 ReadOnly := True;
1471 end;
1473 case Data.ShotTarget of
1474 1: str := _lc[I_PROP_TR_SHOT_TO_1];
1475 2: str := _lc[I_PROP_TR_SHOT_TO_2];
1476 3: str := _lc[I_PROP_TR_SHOT_TO_3];
1477 4: str := _lc[I_PROP_TR_SHOT_TO_4];
1478 5: str := _lc[I_PROP_TR_SHOT_TO_5];
1479 6: str := _lc[I_PROP_TR_SHOT_TO_6];
1480 else str := _lc[I_PROP_TR_SHOT_TO_0];
1481 end;
1482 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_TO], str, True)] do
1483 begin
1484 EditStyle := esPickList;
1485 ReadOnly := True;
1486 end;
1488 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_SIGHT], IntToStr(Data.ShotIntSight), True)] do
1489 begin
1490 EditStyle := esSimple;
1491 MaxLength := 3;
1492 end;
1494 case Data.ShotAim of
1495 1: str := _lc[I_PROP_TR_SHOT_AIM_1];
1496 2: str := _lc[I_PROP_TR_SHOT_AIM_2];
1497 3: str := _lc[I_PROP_TR_SHOT_AIM_3];
1498 else str := _lc[I_PROP_TR_SHOT_AIM_0];
1499 end;
1500 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_AIM], str, True)] do
1501 begin
1502 EditStyle := esPickList;
1503 ReadOnly := True;
1504 end;
1506 with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_TO],
1507 Format('(%d:%d)', [Data.ShotPos.X, Data.ShotPos.Y]), True)] do
1508 begin
1509 EditStyle := esEllipsis;
1510 ReadOnly := True;
1511 end;
1513 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_ANGLE], IntToStr(Data.ShotAngle), True)] do
1514 begin
1515 EditStyle := esSimple;
1516 MaxLength := 4;
1517 end;
1519 with ItemProps[InsertRow(_lc[I_PROP_TR_EX_DELAY], IntToStr(Data.ShotWait), True)] do
1520 begin
1521 EditStyle := esSimple;
1522 MaxLength := 5;
1523 end;
1525 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_ACC], IntToStr(Data.ShotAccuracy), True)] do
1526 begin
1527 EditStyle := esSimple;
1528 MaxLength := 5;
1529 end;
1531 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_AMMO], IntToStr(Data.ShotAmmo), True)] do
1532 begin
1533 EditStyle := esSimple;
1534 MaxLength := 5;
1535 end;
1537 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_RELOAD], IntToStr(Data.ShotIntReload), True)] do
1538 begin
1539 EditStyle := esSimple;
1540 MaxLength := 4;
1541 end;
1542 end;
1544 TRIGGER_EFFECT:
1545 begin
1546 with ItemProps[InsertRow(_lc[I_PROP_TR_COUNT], IntToStr(Data.FXCount), True)] do
1547 begin
1548 EditStyle := esSimple;
1549 MaxLength := 3;
1550 end;
1552 if Data.FXType = 0 then
1553 str := _lc[I_PROP_TR_EFFECT_PARTICLE]
1554 else
1555 str := _lc[I_PROP_TR_EFFECT_ANIMATION];
1556 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_TYPE], str, True)] do
1557 begin
1558 EditStyle := esEllipsis;
1559 ReadOnly := True;
1560 end;
1562 str := '';
1563 if Data.FXType = 0 then
1564 case Data.FXSubType of
1565 TRIGGER_EFFECT_SLIQUID:
1566 str := _lc[I_PROP_TR_EFFECT_SLIQUID];
1567 TRIGGER_EFFECT_LLIQUID:
1568 str := _lc[I_PROP_TR_EFFECT_LLIQUID];
1569 TRIGGER_EFFECT_DLIQUID:
1570 str := _lc[I_PROP_TR_EFFECT_DLIQUID];
1571 TRIGGER_EFFECT_BLOOD:
1572 str := _lc[I_PROP_TR_EFFECT_BLOOD];
1573 TRIGGER_EFFECT_SPARK:
1574 str := _lc[I_PROP_TR_EFFECT_SPARK];
1575 TRIGGER_EFFECT_BUBBLE:
1576 str := _lc[I_PROP_TR_EFFECT_BUBBLE];
1577 end;
1578 if Data.FXType = 1 then
1579 begin
1580 if (Data.FXSubType = 0) or (Data.FXSubType > EFFECT_FIRE) then
1581 Data.FXSubType := EFFECT_TELEPORT;
1582 str := EffectToStr(Data.FXSubType);
1583 end;
1584 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_SUBTYPE], str, True)] do
1585 begin
1586 EditStyle := esEllipsis;
1587 ReadOnly := True;
1588 end;
1590 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_COLOR], IntToStr(Data.FXColorR or (Data.FXColorG shl 8) or (Data.FXColorB shl 16)), True)] do
1591 begin
1592 EditStyle := esEllipsis;
1593 ReadOnly := True;
1594 end;
1596 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_CENTER], BoolNames[Data.FXPos = 0], True)] do
1597 begin
1598 EditStyle := esPickList;
1599 ReadOnly := True;
1600 end;
1602 with ItemProps[InsertRow(_lc[I_PROP_TR_EX_DELAY], IntToStr(Data.FXWait), True)] do
1603 begin
1604 EditStyle := esSimple;
1605 MaxLength := 5;
1606 end;
1608 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_VELX], IntToStr(Data.FXVelX), True)] do
1609 begin
1610 EditStyle := esSimple;
1611 MaxLength := 4;
1612 end;
1614 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_VELY], IntToStr(Data.FXVelY), True)] do
1615 begin
1616 EditStyle := esSimple;
1617 MaxLength := 4;
1618 end;
1620 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_SPL], IntToStr(Data.FXSpreadL), True)] do
1621 begin
1622 EditStyle := esSimple;
1623 MaxLength := 3;
1624 end;
1626 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_SPR], IntToStr(Data.FXSpreadR), True)] do
1627 begin
1628 EditStyle := esSimple;
1629 MaxLength := 3;
1630 end;
1632 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_SPU], IntToStr(Data.FXSpreadU), True)] do
1633 begin
1634 EditStyle := esSimple;
1635 MaxLength := 3;
1636 end;
1638 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_SPD], IntToStr(Data.FXSpreadD), True)] do
1639 begin
1640 EditStyle := esSimple;
1641 MaxLength := 3;
1642 end;
1643 end;
1644 end; //case TriggerType
1645 end;
1646 end; // OBJECT_TRIGGER:
1647 end;
1648 end;
1650 procedure ChangeShownProperty(Name: String; NewValue: String);
1651 var
1652 row: Integer;
1653 begin
1654 if SelectedObjectCount() <> 1 then
1655 Exit;
1656 if not SelectedObjects[GetFirstSelected()].Live then
1657 Exit;
1659 // Есть ли такой ключ:
1660 if MainForm.vleObjectProperty.FindRow(Name, row) then
1661 begin
1662 MainForm.vleObjectProperty.Values[Name] := NewValue;
1663 end;
1664 end;
1666 procedure SelectObject(fObjectType: Byte; fID: DWORD; Multi: Boolean);
1667 var
1668 a: Integer;
1669 b: Boolean;
1670 begin
1671 if Multi then
1672 begin
1673 b := False;
1675 // Уже выделен - убираем:
1676 if SelectedObjects <> nil then
1677 for a := 0 to High(SelectedObjects) do
1678 with SelectedObjects[a] do
1679 if Live and (ID = fID) and
1680 (ObjectType = fObjectType) then
1681 begin
1682 Live := False;
1683 b := True;
1684 end;
1686 if b then
1687 Exit;
1689 SetLength(SelectedObjects, Length(SelectedObjects)+1);
1691 with SelectedObjects[High(SelectedObjects)] do
1692 begin
1693 ObjectType := fObjectType;
1694 ID := fID;
1695 Live := True;
1696 end;
1697 end
1698 else // not Multi
1699 begin
1700 SetLength(SelectedObjects, 1);
1702 with SelectedObjects[0] do
1703 begin
1704 ObjectType := fObjectType;
1705 ID := fID;
1706 Live := True;
1707 end;
1708 end;
1710 MainForm.miCopy.Enabled := True;
1711 MainForm.miCut.Enabled := True;
1713 if fObjectType = OBJECT_PANEL then
1714 begin
1715 MainForm.miToFore.Enabled := True;
1716 MainForm.miToBack.Enabled := True;
1717 end;
1718 end;
1720 procedure RemoveSelectFromObjects();
1721 begin
1722 SelectedObjects := nil;
1723 DrawPressRect := False;
1724 MouseLDown := False;
1725 MouseRDown := False;
1726 MouseAction := MOUSEACTION_NONE;
1727 SelectFlag := SELECTFLAG_NONE;
1728 ResizeType := RESIZETYPE_NONE;
1729 ResizeDirection := RESIZEDIR_NONE;
1731 MainForm.vleObjectProperty.Strings.Clear();
1733 MainForm.miCopy.Enabled := False;
1734 MainForm.miCut.Enabled := False;
1735 MainForm.miToFore.Enabled := False;
1736 MainForm.miToBack.Enabled := False;
1737 end;
1739 procedure DeleteSelectedObjects();
1740 var
1741 i, a, ii: Integer;
1742 b: Boolean;
1743 begin
1744 if SelectedObjects = nil then
1745 Exit;
1747 b := False;
1748 i := 0;
1750 for a := 0 to High(SelectedObjects) do
1751 with SelectedObjects[a] do
1752 if Live then
1753 begin
1754 if not b then
1755 begin
1756 SetLength(UndoBuffer, Length(UndoBuffer)+1);
1757 i := High(UndoBuffer);
1758 b := True;
1759 end;
1761 SetLength(UndoBuffer[i], Length(UndoBuffer[i])+1);
1762 ii := High(UndoBuffer[i]);
1764 case ObjectType of
1765 OBJECT_PANEL:
1766 begin
1767 UndoBuffer[i, ii].UndoType := UNDO_DELETE_PANEL;
1768 New(UndoBuffer[i, ii].Panel);
1769 UndoBuffer[i, ii].Panel^ := gPanels[ID];
1770 end;
1771 OBJECT_ITEM:
1772 begin
1773 UndoBuffer[i, ii].UndoType := UNDO_DELETE_ITEM;
1774 UndoBuffer[i, ii].Item := gItems[ID];
1775 end;
1776 OBJECT_AREA:
1777 begin
1778 UndoBuffer[i, ii].UndoType := UNDO_DELETE_AREA;
1779 UndoBuffer[i, ii].Area := gAreas[ID];
1780 end;
1781 OBJECT_TRIGGER:
1782 begin
1783 UndoBuffer[i, ii].UndoType := UNDO_DELETE_TRIGGER;
1784 UndoBuffer[i, ii].Trigger := gTriggers[ID];
1785 end;
1786 end;
1788 RemoveObject(ID, ObjectType);
1789 end;
1791 RemoveSelectFromObjects();
1793 MainForm.miUndo.Enabled := UndoBuffer <> nil;
1794 MainForm.RecountSelectedObjects();
1795 end;
1797 procedure Undo_Add(ObjectType: Byte; ID: DWORD; Group: Boolean = False);
1798 var
1799 i, ii: Integer;
1800 begin
1801 if (not Group) or (Length(UndoBuffer) = 0) then
1802 SetLength(UndoBuffer, Length(UndoBuffer)+1);
1803 SetLength(UndoBuffer[High(UndoBuffer)], Length(UndoBuffer[High(UndoBuffer)])+1);
1804 i := High(UndoBuffer);
1805 ii := High(UndoBuffer[i]);
1807 case ObjectType of
1808 OBJECT_PANEL:
1809 UndoBuffer[i, ii].UndoType := UNDO_ADD_PANEL;
1810 OBJECT_ITEM:
1811 UndoBuffer[i, ii].UndoType := UNDO_ADD_ITEM;
1812 OBJECT_MONSTER:
1813 UndoBuffer[i, ii].UndoType := UNDO_ADD_MONSTER;
1814 OBJECT_AREA:
1815 UndoBuffer[i, ii].UndoType := UNDO_ADD_AREA;
1816 OBJECT_TRIGGER:
1817 UndoBuffer[i, ii].UndoType := UNDO_ADD_TRIGGER;
1818 end;
1820 UndoBuffer[i, ii].AddID := ID;
1822 MainForm.miUndo.Enabled := UndoBuffer <> nil;
1823 end;
1825 procedure FullClear();
1826 begin
1827 RemoveSelectFromObjects();
1828 ClearMap();
1829 LoadSky(gMapInfo.SkyName);
1830 UndoBuffer := nil;
1831 slInvalidTextures.Clear();
1832 MapCheckForm.lbErrorList.Clear();
1833 MapCheckForm.mErrorDescription.Clear();
1835 MainForm.miUndo.Enabled := False;
1836 MainForm.sbHorizontal.Position := 0;
1837 MainForm.sbVertical.Position := 0;
1838 MainForm.FormResize(nil);
1839 MainForm.Caption := FormCaption;
1840 OpenedMap := '';
1841 OpenedWAD := '';
1842 end;
1844 procedure ErrorMessageBox(str: String);
1845 begin
1846 MessageBox(0, PChar(str), PChar(_lc[I_MSG_ERROR]),
1847 MB_ICONINFORMATION or MB_OK or MB_DEFBUTTON1);
1848 end;
1850 function CheckProperty(): Boolean;
1851 var
1852 _id: Integer;
1853 begin
1854 Result := False;
1856 _id := GetFirstSelected();
1858 if SelectedObjects[_id].ObjectType = OBJECT_PANEL then
1859 with gPanels[SelectedObjects[_id].ID] do
1860 begin
1861 if TextureWidth <> 0 then
1862 if StrToIntDef(MainForm.vleObjectProperty.Values[_lc[I_PROP_WIDTH]], 1) mod TextureWidth <> 0 then
1863 begin
1864 ErrorMessageBox(Format(_lc[I_MSG_WRONG_TEXWIDTH],
1865 [TextureWidth]));
1866 Exit;
1867 end;
1869 if TextureHeight <> 0 then
1870 if StrToIntDef(Trim(MainForm.vleObjectProperty.Values[_lc[I_PROP_HEIGHT]]), 1) mod TextureHeight <> 0 then
1871 begin
1872 ErrorMessageBox(Format(_lc[I_MSG_WRONG_TEXHEIGHT],
1873 [TextureHeight]));
1874 Exit;
1875 end;
1877 if IsTexturedPanel(PanelType) and (TextureName <> '') then
1878 if not (StrToIntDef(MainForm.vleObjectProperty.Values[_lc[I_PROP_PANEL_ALPHA]], -1) in [0..255]) then
1879 begin
1880 ErrorMessageBox(_lc[I_MSG_WRONG_ALPHA]);
1881 Exit;
1882 end;
1883 end;
1885 if SelectedObjects[_id].ObjectType in [OBJECT_PANEL, OBJECT_TRIGGER] then
1886 if (StrToIntDef(MainForm.vleObjectProperty.Values[_lc[I_PROP_WIDTH]], 0) <= 0) or
1887 (StrToIntDef(MainForm.vleObjectProperty.Values[_lc[I_PROP_HEIGHT]], 0) <= 0) then
1888 begin
1889 ErrorMessageBox(_lc[I_MSG_WRONG_SIZE]);
1890 Exit;
1891 end;
1893 if (Trim(MainForm.vleObjectProperty.Values[_lc[I_PROP_X]]) = '') or
1894 (Trim(MainForm.vleObjectProperty.Values[_lc[I_PROP_Y]]) = '') then
1895 begin
1896 ErrorMessageBox(_lc[I_MSG_WRONG_XY]);
1897 Exit;
1898 end;
1900 Result := True;
1901 end;
1903 procedure SelectTexture(ID: Integer);
1904 begin
1905 MainForm.lbTextureList.ItemIndex := ID;
1906 MainForm.lbTextureListClick(nil);
1907 end;
1909 function AddTexture(aWAD, aSection, aTex: String; silent: Boolean): Boolean;
1910 var
1911 a, FrameLen: Integer;
1912 ok: Boolean;
1913 FileName: String;
1914 ResourceName: String;
1915 FullResourceName: String;
1916 SectionName: String;
1917 Data: Pointer;
1918 Width, Height: Word;
1919 fn: String;
1920 begin
1921 Data := nil;
1922 FrameLen := 0;
1923 Width := 0;
1924 Height := 0;
1926 if aSection = '..' then
1927 SectionName := ''
1928 else
1929 SectionName := aSection;
1931 if aWAD = '' then
1932 aWAD := _lc[I_WAD_SPECIAL_MAP];
1934 if aWAD = _lc[I_WAD_SPECIAL_MAP] then
1935 begin // Файл карты
1936 g_ProcessResourceStr(OpenedMap, @fn, nil, nil);
1937 //FileName := EditorDir+'maps\'+ExtractFileName(fn);
1938 FileName := fn;
1939 ResourceName := ':'+SectionName+'\'+aTex;
1940 end
1941 else
1942 if aWAD = _lc[I_WAD_SPECIAL_TEXS] then
1943 begin // Спец. текстуры
1944 FileName := '';
1945 ResourceName := aTex;
1946 end
1947 else
1948 begin // Внешний WAD
1949 FileName := EditorDir+'wads/'+aWAD;
1950 ResourceName := aWAD+':'+SectionName+'\'+aTex;
1951 end;
1953 ok := True;
1955 // Есть ли уже такая текстура:
1956 for a := 0 to MainForm.lbTextureList.Items.Count-1 do
1957 if ResourceName = MainForm.lbTextureList.Items[a] then
1958 begin
1959 if not silent then
1960 ErrorMessageBox(Format(_lc[I_MSG_TEXTURE_ALREADY],
1961 [ResourceName]));
1962 ok := False;
1963 end;
1965 // Название ресурса <= 64 символов:
1966 if Length(ResourceName) > 64 then
1967 begin
1968 if not silent then
1969 ErrorMessageBox(Format(_lc[I_MSG_RES_NAME_64],
1970 [ResourceName]));
1971 ok := False;
1972 end;
1974 if ok then
1975 begin
1976 a := -1;
1977 if aWAD = _lc[I_WAD_SPECIAL_TEXS] then
1978 begin
1979 a := MainForm.lbTextureList.Items.Add(ResourceName);
1980 if not silent then
1981 SelectTexture(a);
1982 Result := True;
1983 Exit;
1984 end;
1986 FullResourceName := FileName+':'+SectionName+'\'+aTex;
1988 if IsAnim(FullResourceName) then
1989 begin // Аним. текстура
1990 GetFrame(FullResourceName, Data, FrameLen, Width, Height);
1992 if not g_CreateTextureMemorySize(Data, FrameLen, ResourceName, 0, 0, Width, Height, 1) then
1993 ok := False;
1994 a := MainForm.lbTextureList.Items.Add(ResourceName);
1995 end
1996 else // Обычная текстура
1997 begin
1998 if not g_CreateTextureWAD(ResourceName, FullResourceName) then
1999 ok := False;
2000 a := MainForm.lbTextureList.Items.Add(ResourceName);
2001 end;
2002 if (not ok) and (slInvalidTextures.IndexOf(ResourceName) = -1) then
2003 begin
2004 slInvalidTextures.Add(ResourceName);
2005 ok := True;
2006 end;
2007 if (a > -1) and (not silent) then
2008 SelectTexture(a);
2009 end;
2011 Result := ok;
2012 end;
2014 procedure UpdateCaption(sMap, sFile, sRes: String);
2015 begin
2016 with MainForm do
2017 if (sFile = '') and (sRes = '') and (sMap = '') then
2018 Caption := FormCaption
2019 else
2020 if sMap = '' then
2021 Caption := Format('%s - %s:%s', [FormCaption, sFile, sRes])
2022 else
2023 if (sFile <> '') and (sRes <> '') then
2024 Caption := Format('%s - %s (%s:%s)', [FormCaption, sMap, sFile, sRes])
2025 else
2026 Caption := Format('%s - %s', [FormCaption, sMap]);
2027 end;
2029 procedure OpenMap(FileName: String; mapN: String);
2030 var
2031 MapName: String;
2032 idx: Integer;
2033 begin
2034 SelectMapForm.Caption := _lc[I_CAP_OPEN];
2035 SelectMapForm.GetMaps(FileName);
2037 if (FileName = OpenedWAD) and
2038 (OpenedMap <> '') then
2039 begin
2040 MapName := OpenedMap;
2041 while (Pos(':\', MapName) > 0) do
2042 Delete(MapName, 1, Pos(':\', MapName) + 1);
2044 idx := SelectMapForm.lbMapList.Items.IndexOf(MapName);
2045 SelectMapForm.lbMapList.ItemIndex := idx;
2046 end
2047 else
2048 if SelectMapForm.lbMapList.Count > 0 then
2049 SelectMapForm.lbMapList.ItemIndex := 0
2050 else
2051 SelectMapForm.lbMapList.ItemIndex := -1;
2053 if mapN = '' then
2054 idx := -1
2055 else
2056 idx := SelectMapForm.lbMapList.Items.IndexOf(mapN);
2058 if idx < 0 then
2059 begin
2060 if (SelectMapForm.ShowModal() = mrOK) and
2061 (SelectMapForm.lbMapList.ItemIndex <> -1) then
2062 idx := SelectMapForm.lbMapList.ItemIndex
2063 else
2064 Exit;
2065 end;
2067 MapName := SelectMapForm.lbMapList.Items[idx];
2069 with MainForm do
2070 begin
2071 FullClear();
2073 pLoadProgress.Left := (RenderPanel.Width div 2)-(pLoadProgress.Width div 2);
2074 pLoadProgress.Top := (RenderPanel.Height div 2)-(pLoadProgress.Height div 2);
2075 pLoadProgress.Show();
2077 OpenedMap := FileName+':\'+MapName;
2078 OpenedWAD := FileName;
2080 idx := RecentFiles.IndexOf(OpenedMap);
2081 // Такая карта уже недавно открывалась:
2082 if idx >= 0 then
2083 RecentFiles.Delete(idx);
2084 RecentFiles.Insert(0, OpenedMap);
2085 RefreshRecentMenu();
2087 LoadMap(OpenedMap);
2089 pLoadProgress.Hide();
2090 FormResize(nil);
2092 lbTextureList.Sorted := True;
2093 lbTextureList.Sorted := False;
2095 UpdateCaption(gMapInfo.Name, ExtractFileName(FileName), MapName);
2096 end;
2097 end;
2099 procedure MoveSelectedObjects(Wall, alt: Boolean; dx, dy: Integer);
2100 var
2101 okX, okY: Boolean;
2102 a: Integer;
2103 begin
2104 if SelectedObjects = nil then
2105 Exit;
2107 okX := True;
2108 okY := True;
2110 if Wall then
2111 for a := 0 to High(SelectedObjects) do
2112 if SelectedObjects[a].Live then
2113 begin
2114 if ObjectCollideLevel(SelectedObjects[a].ID, SelectedObjects[a].ObjectType, dx, 0) then
2115 okX := False;
2117 if ObjectCollideLevel(SelectedObjects[a].ID, SelectedObjects[a].ObjectType, 0, dy) then
2118 okY := False;
2120 if (not okX) or (not okY) then
2121 Break;
2122 end;
2124 if okX or okY then
2125 begin
2126 for a := 0 to High(SelectedObjects) do
2127 if SelectedObjects[a].Live then
2128 begin
2129 if okX then
2130 MoveObject(SelectedObjects[a].ObjectType, SelectedObjects[a].ID, dx, 0);
2132 if okY then
2133 MoveObject(SelectedObjects[a].ObjectType, SelectedObjects[a].ID, 0, dy);
2135 if alt and (SelectedObjects[a].ObjectType = OBJECT_TRIGGER) then
2136 begin
2137 if gTriggers[SelectedObjects[a].ID].TriggerType in [TRIGGER_PRESS,
2138 TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF] then
2139 begin // Двигаем зону Расширителя
2140 if okX then
2141 gTriggers[SelectedObjects[a].ID].Data.tX := gTriggers[SelectedObjects[a].ID].Data.tX+dx;
2142 if okY then
2143 gTriggers[SelectedObjects[a].ID].Data.tY := gTriggers[SelectedObjects[a].ID].Data.tY+dy;
2144 end;
2146 if gTriggers[SelectedObjects[a].ID].TriggerType in [TRIGGER_TELEPORT] then
2147 begin // Двигаем точку назначения Телепорта
2148 if okX then
2149 gTriggers[SelectedObjects[a].ID].Data.TargetPoint.X := gTriggers[SelectedObjects[a].ID].Data.TargetPoint.X+dx;
2150 if okY then
2151 gTriggers[SelectedObjects[a].ID].Data.TargetPoint.Y := gTriggers[SelectedObjects[a].ID].Data.TargetPoint.Y+dy;
2152 end;
2154 if gTriggers[SelectedObjects[a].ID].TriggerType in [TRIGGER_SPAWNMONSTER] then
2155 begin // Двигаем точку создания монстра
2156 if okX then
2157 gTriggers[SelectedObjects[a].ID].Data.MonPos.X := gTriggers[SelectedObjects[a].ID].Data.MonPos.X+dx;
2158 if okY then
2159 gTriggers[SelectedObjects[a].ID].Data.MonPos.Y := gTriggers[SelectedObjects[a].ID].Data.MonPos.Y+dy;
2160 end;
2162 if gTriggers[SelectedObjects[a].ID].TriggerType in [TRIGGER_SPAWNITEM] then
2163 begin // Двигаем точку создания предмета
2164 if okX then
2165 gTriggers[SelectedObjects[a].ID].Data.ItemPos.X := gTriggers[SelectedObjects[a].ID].Data.ItemPos.X+dx;
2166 if okY then
2167 gTriggers[SelectedObjects[a].ID].Data.ItemPos.Y := gTriggers[SelectedObjects[a].ID].Data.ItemPos.Y+dy;
2168 end;
2170 if gTriggers[SelectedObjects[a].ID].TriggerType in [TRIGGER_SHOT] then
2171 begin // Двигаем точку создания выстрела
2172 if okX then
2173 gTriggers[SelectedObjects[a].ID].Data.ShotPos.X := gTriggers[SelectedObjects[a].ID].Data.ShotPos.X+dx;
2174 if okY then
2175 gTriggers[SelectedObjects[a].ID].Data.ShotPos.Y := gTriggers[SelectedObjects[a].ID].Data.ShotPos.Y+dy;
2176 end;
2177 end;
2178 end;
2180 LastMovePoint := MousePos;
2181 end;
2182 end;
2184 procedure ShowLayer(Layer: Byte; show: Boolean);
2185 begin
2186 LayerEnabled[Layer] := show;
2188 case Layer of
2189 LAYER_BACK:
2190 begin
2191 MainForm.miLayer1.Checked := show;
2192 MainForm.miLayerP1.Checked := show;
2193 end;
2194 LAYER_WALLS:
2195 begin
2196 MainForm.miLayer2.Checked := show;
2197 MainForm.miLayerP2.Checked := show;
2198 end;
2199 LAYER_FOREGROUND:
2200 begin
2201 MainForm.miLayer3.Checked := show;
2202 MainForm.miLayerP3.Checked := show;
2203 end;
2204 LAYER_STEPS:
2205 begin
2206 MainForm.miLayer4.Checked := show;
2207 MainForm.miLayerP4.Checked := show;
2208 end;
2209 LAYER_WATER:
2210 begin
2211 MainForm.miLayer5.Checked := show;
2212 MainForm.miLayerP5.Checked := show;
2213 end;
2214 LAYER_ITEMS:
2215 begin
2216 MainForm.miLayer6.Checked := show;
2217 MainForm.miLayerP6.Checked := show;
2218 end;
2219 LAYER_MONSTERS:
2220 begin
2221 MainForm.miLayer7.Checked := show;
2222 MainForm.miLayerP7.Checked := show;
2223 end;
2224 LAYER_AREAS:
2225 begin
2226 MainForm.miLayer8.Checked := show;
2227 MainForm.miLayerP8.Checked := show;
2228 end;
2229 LAYER_TRIGGERS:
2230 begin
2231 MainForm.miLayer9.Checked := show;
2232 MainForm.miLayerP9.Checked := show;
2233 end;
2234 end;
2236 RemoveSelectFromObjects();
2237 end;
2239 procedure SwitchLayer(Layer: Byte);
2240 begin
2241 ShowLayer(Layer, not LayerEnabled[Layer]);
2242 end;
2244 procedure SwitchMap();
2245 begin
2246 ShowMap := not ShowMap;
2247 MainForm.tbShowMap.Down := ShowMap;
2248 end;
2250 procedure ShowEdges();
2251 begin
2252 if drEdge[3] < 255 then
2253 drEdge[3] := 255
2254 else
2255 drEdge[3] := gAlphaEdge;
2256 end;
2258 function SelectedTexture(): String;
2259 begin
2260 if MainForm.lbTextureList.ItemIndex <> -1 then
2261 Result := MainForm.lbTextureList.Items[MainForm.lbTextureList.ItemIndex]
2262 else
2263 Result := '';
2264 end;
2266 function IsSpecialTextureSel(): Boolean;
2267 begin
2268 Result := (MainForm.lbTextureList.ItemIndex <> -1) and
2269 IsSpecialTexture(MainForm.lbTextureList.Items[MainForm.lbTextureList.ItemIndex]);
2270 end;
2272 function CopyBufferToString(var CopyBuf: TCopyRecArray): String;
2273 var
2274 i, j: Integer;
2275 Res: String;
2277 procedure AddInt(x: Integer);
2278 begin
2279 Res := Res + IntToStr(x) + ' ';
2280 end;
2282 begin
2283 Result := '';
2285 if Length(CopyBuf) = 0 then
2286 Exit;
2288 Res := CLIPBOARD_SIG + ' ';
2290 for i := 0 to High(CopyBuf) do
2291 begin
2292 if (CopyBuf[i].ObjectType = OBJECT_PANEL) and
2293 (CopyBuf[i].Panel = nil) then
2294 Continue;
2296 // Тип объекта:
2297 AddInt(CopyBuf[i].ObjectType);
2298 Res := Res + '; ';
2300 // Свойства объекта:
2301 case CopyBuf[i].ObjectType of
2302 OBJECT_PANEL:
2303 with CopyBuf[i].Panel^ do
2304 begin
2305 AddInt(PanelType);
2306 AddInt(X);
2307 AddInt(Y);
2308 AddInt(Width);
2309 AddInt(Height);
2310 Res := Res + '"' + TextureName + '" ';
2311 AddInt(Alpha);
2312 AddInt(IfThen(Blending, 1, 0));
2313 end;
2315 OBJECT_ITEM:
2316 with CopyBuf[i].Item do
2317 begin
2318 AddInt(ItemType);
2319 AddInt(X);
2320 AddInt(Y);
2321 AddInt(IfThen(OnlyDM, 1, 0));
2322 AddInt(IfThen(Fall, 1, 0));
2323 end;
2325 OBJECT_MONSTER:
2326 with CopyBuf[i].Monster do
2327 begin
2328 AddInt(MonsterType);
2329 AddInt(X);
2330 AddInt(Y);
2331 AddInt(IfThen(Direction = D_LEFT, 1, 0));
2332 end;
2334 OBJECT_AREA:
2335 with CopyBuf[i].Area do
2336 begin
2337 AddInt(AreaType);
2338 AddInt(X);
2339 AddInt(Y);
2340 AddInt(IfThen(Direction = D_LEFT, 1, 0));
2341 end;
2343 OBJECT_TRIGGER:
2344 with CopyBuf[i].Trigger do
2345 begin
2346 AddInt(TriggerType);
2347 AddInt(X);
2348 AddInt(Y);
2349 AddInt(Width);
2350 AddInt(Height);
2351 AddInt(ActivateType);
2352 AddInt(Key);
2353 AddInt(IfThen(Enabled, 1, 0));
2354 AddInt(TexturePanel);
2356 for j := 0 to 127 do
2357 AddInt(Data.Default[j]);
2358 end;
2359 end;
2360 end;
2362 Result := Res;
2363 end;
2365 procedure StringToCopyBuffer(Str: String; var CopyBuf: TCopyRecArray;
2366 var pmin: TPoint);
2367 var
2368 i, j, t: Integer;
2370 function GetNext(): String;
2371 var
2372 p: Integer;
2374 begin
2375 if Str[1] = '"' then
2376 begin
2377 Delete(Str, 1, 1);
2378 p := Pos('"', Str);
2380 if p = 0 then
2381 begin
2382 Result := Str;
2383 Str := '';
2384 end
2385 else
2386 begin
2387 Result := Copy(Str, 1, p-1);
2388 Delete(Str, 1, p);
2389 Str := Trim(Str);
2390 end;
2391 end
2392 else
2393 begin
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 end;
2410 begin
2411 Str := Trim(Str);
2413 if GetNext() <> CLIPBOARD_SIG then
2414 Exit;
2416 while Str <> '' do
2417 begin
2418 // Тип объекта:
2419 t := StrToIntDef(GetNext(), 0);
2421 if (t < OBJECT_PANEL) or (t > OBJECT_TRIGGER) or
2422 (GetNext() <> ';') then
2423 begin // Что-то не то => пропускаем:
2424 t := Pos(';', Str);
2425 Delete(Str, 1, t);
2426 Str := Trim(Str);
2428 Continue;
2429 end;
2431 i := Length(CopyBuf);
2432 SetLength(CopyBuf, i + 1);
2434 CopyBuf[i].ObjectType := t;
2435 CopyBuf[i].Panel := nil;
2437 // Свойства объекта:
2438 case t of
2439 OBJECT_PANEL:
2440 begin
2441 New(CopyBuf[i].Panel);
2443 with CopyBuf[i].Panel^ do
2444 begin
2445 PanelType := StrToIntDef(GetNext(), PANEL_WALL);
2446 X := StrToIntDef(GetNext(), 0);
2447 Y := StrToIntDef(GetNext(), 0);
2448 pmin.X := Min(X, pmin.X);
2449 pmin.Y := Min(Y, pmin.Y);
2450 Width := StrToIntDef(GetNext(), 16);
2451 Height := StrToIntDef(GetNext(), 16);
2452 TextureName := GetNext();
2453 Alpha := StrToIntDef(GetNext(), 0);
2454 Blending := (GetNext() = '1');
2455 end;
2456 end;
2458 OBJECT_ITEM:
2459 with CopyBuf[i].Item do
2460 begin
2461 ItemType := StrToIntDef(GetNext(), ITEM_MEDKIT_SMALL);
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 OnlyDM := (GetNext() = '1');
2467 Fall := (GetNext() = '1');
2468 end;
2470 OBJECT_MONSTER:
2471 with CopyBuf[i].Monster do
2472 begin
2473 MonsterType := StrToIntDef(GetNext(), MONSTER_DEMON);
2474 X := StrToIntDef(GetNext(), 0);
2475 Y := StrToIntDef(GetNext(), 0);
2476 pmin.X := Min(X, pmin.X);
2477 pmin.Y := Min(Y, pmin.Y);
2479 if GetNext() = '1' then
2480 Direction := D_LEFT
2481 else
2482 Direction := D_RIGHT;
2483 end;
2485 OBJECT_AREA:
2486 with CopyBuf[i].Area do
2487 begin
2488 AreaType := StrToIntDef(GetNext(), AREA_PLAYERPOINT1);
2489 X := StrToIntDef(GetNext(), 0);
2490 Y := StrToIntDef(GetNext(), 0);
2491 pmin.X := Min(X, pmin.X);
2492 pmin.Y := Min(Y, pmin.Y);
2493 if GetNext() = '1' then
2494 Direction := D_LEFT
2495 else
2496 Direction := D_RIGHT;
2497 end;
2499 OBJECT_TRIGGER:
2500 with CopyBuf[i].Trigger do
2501 begin
2502 TriggerType := StrToIntDef(GetNext(), TRIGGER_EXIT);
2503 X := StrToIntDef(GetNext(), 0);
2504 Y := StrToIntDef(GetNext(), 0);
2505 pmin.X := Min(X, pmin.X);
2506 pmin.Y := Min(Y, pmin.Y);
2507 Width := StrToIntDef(GetNext(), 16);
2508 Height := StrToIntDef(GetNext(), 16);
2509 ActivateType := StrToIntDef(GetNext(), 0);
2510 Key := StrToIntDef(GetNext(), 0);
2511 Enabled := (GetNext() = '1');
2512 TexturePanel := StrToIntDef(GetNext(), 0);
2514 for j := 0 to 127 do
2515 Data.Default[j] := StrToIntDef(GetNext(), 0);
2517 case TriggerType of
2518 TRIGGER_TELEPORT:
2519 begin
2520 pmin.X := Min(Data.TargetPoint.X, pmin.X);
2521 pmin.Y := Min(Data.TargetPoint.Y, pmin.Y);
2522 end;
2523 TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF:
2524 begin
2525 pmin.X := Min(Data.tX, pmin.X);
2526 pmin.Y := Min(Data.tY, pmin.Y);
2527 end;
2528 TRIGGER_SPAWNMONSTER:
2529 begin
2530 pmin.X := Min(Data.MonPos.X, pmin.X);
2531 pmin.Y := Min(Data.MonPos.Y, pmin.Y);
2532 end;
2533 TRIGGER_SPAWNITEM:
2534 begin
2535 pmin.X := Min(Data.ItemPos.X, pmin.X);
2536 pmin.Y := Min(Data.ItemPos.Y, pmin.Y);
2537 end;
2538 TRIGGER_SHOT:
2539 begin
2540 pmin.X := Min(Data.ShotPos.X, pmin.X);
2541 pmin.Y := Min(Data.ShotPos.Y, pmin.Y);
2542 end;
2543 end;
2544 end;
2545 end;
2546 end;
2547 end;
2549 //----------------------------------------
2550 //Закончились вспомогательные процедуры
2551 //----------------------------------------
2553 procedure TMainForm.RefreshRecentMenu();
2554 var
2555 i: Integer;
2556 MI: TMenuItem;
2557 begin
2558 // Лишние запомненные карты:
2559 while RecentFiles.Count > RecentCount do
2560 RecentFiles.Delete(RecentFiles.Count-1);
2562 // Лишние строки меню:
2563 while MainMenu.Items[0].Count > RECENT_FILES_MENU_START do
2564 MainMenu.Items[0].Delete(MainMenu.Items[0].Count-1);
2566 // Отделение списка карт от строки "Выход":
2567 if RecentFiles.Count > 0 then
2568 begin
2569 MI := TMenuItem.Create(MainMenu.Items[0]);
2570 MI.Caption := '-';
2571 MainMenu.Items[0].Add(MI);
2572 end;
2574 // Добавление в меню списка запомненных карт:
2575 for i := 0 to RecentFiles.Count-1 do
2576 begin
2577 MI := TMenuItem.Create(MainMenu.Items[0]);
2578 MI.Caption := IntToStr(i+1) + ' ' + RecentFiles[i];
2579 MI.OnClick := aRecentFileExecute;
2580 MainMenu.Items[0].Add(MI);
2581 end;
2582 end;
2584 procedure TMainForm.aRecentFileExecute(Sender: TObject);
2585 var
2586 n, pw: Integer;
2587 s, fn: String;
2588 b: Boolean;
2589 begin
2590 s := LowerCase((Sender as TMenuItem).Caption);
2591 Delete(s, Pos('&', s), 1);
2592 s := Trim(Copy(s, 1, 2));
2593 n := StrToIntDef(s, 0) - 1;
2595 if (n < 0) or (n >= RecentFiles.Count) then
2596 Exit;
2598 s := RecentFiles[n];
2599 pw := Pos('.wad:\', LowerCase(s));
2600 b := False;
2602 if pw > 0 then
2603 begin // Map name included
2604 fn := Copy(s, 1, pw + 3);
2605 Delete(s, 1, pw + 5);
2606 if (FileExists(fn)) then
2607 begin
2608 OpenMap(fn, s);
2609 b := True;
2610 end;
2611 end
2612 else // Only wad name
2613 if (FileExists(s)) then
2614 begin
2615 OpenMap(s, '');
2616 b := True;
2617 end;
2619 if (not b) and (MessageBox(0, PChar(_lc[I_MSG_DEL_RECENT_PROMT]),
2620 PChar(_lc[I_MSG_DEL_RECENT]), MB_ICONQUESTION or MB_YESNO) = idYes) then
2621 begin
2622 RecentFiles.Delete(n);
2623 RefreshRecentMenu();
2624 end;
2625 end;
2627 procedure TMainForm.aEditorOptionsExecute(Sender: TObject);
2628 begin
2629 OptionsForm.ShowModal();
2630 end;
2632 procedure LoadStdFont(cfgres, texture: string; var FontID: DWORD);
2633 var
2634 cwdt, chgt: Byte;
2635 spc: ShortInt;
2636 ID: DWORD;
2637 cfgdata: Pointer;
2638 cfglen: Integer;
2639 config: TConfig;
2640 begin
2641 ID := 0;
2642 g_ReadResource(EditorDir + 'data/game.wad', 'FONTS', cfgres, cfgdata, cfglen);
2643 if cfgdata <> nil then
2644 begin
2645 if not g_CreateTextureWAD('FONT_STD', EditorDir + 'data/game.wad:FONTS\' + texture) then
2646 e_WriteLog('ERROR ERROR ERROR', MSG_WARNING);
2648 config := TConfig.CreateMem(cfgdata, cfglen);
2649 cwdt := Min(Max(config.ReadInt('FontMap', 'CharWidth', 0), 0), 255);
2650 chgt := Min(Max(config.ReadInt('FontMap', 'CharHeight', 0), 0), 255);
2651 spc := Min(Max(config.ReadInt('FontMap', 'Kerning', 0), -128), 127);
2653 if g_GetTexture('FONT_STD', ID) then
2654 e_TextureFontBuild(ID, FontID, cwdt, chgt, spc - 2);
2656 config.Free();
2657 FreeMem(cfgdata)
2658 end
2659 else
2660 begin
2661 e_WriteLog('Could not load FONT_STD', MSG_WARNING)
2662 end
2663 end;
2665 procedure TMainForm.FormCreate(Sender: TObject);
2666 var
2667 config: TConfig;
2668 i: Integer;
2669 s: String;
2670 begin
2671 Randomize();
2673 EditorDir := ExtractFilePath(Application.ExeName);
2675 e_InitLog(EditorDir+'Editor.log', WM_NEWFILE);
2677 slInvalidTextures := TStringList.Create;
2679 ShowLayer(LAYER_BACK, True);
2680 ShowLayer(LAYER_WALLS, True);
2681 ShowLayer(LAYER_FOREGROUND, True);
2682 ShowLayer(LAYER_STEPS, True);
2683 ShowLayer(LAYER_WATER, True);
2684 ShowLayer(LAYER_ITEMS, True);
2685 ShowLayer(LAYER_MONSTERS, True);
2686 ShowLayer(LAYER_AREAS, True);
2687 ShowLayer(LAYER_TRIGGERS, True);
2689 ClearMap();
2691 FormCaption := MainForm.Caption;
2692 OpenedMap := '';
2693 OpenedWAD := '';
2695 config := TConfig.CreateFile(EditorDir+'Editor.cfg');
2697 if config.ReadInt('Editor', 'XPos', -1) = -1 then
2698 Position := poDesktopCenter
2699 else begin
2700 Left := config.ReadInt('Editor', 'XPos', Left);
2701 Top := config.ReadInt('Editor', 'YPos', Top);
2702 Width := config.ReadInt('Editor', 'Width', Width);
2703 Height := config.ReadInt('Editor', 'Height', Height);
2704 end;
2705 if config.ReadBool('Editor', 'Maximize', False) then
2706 WindowState := wsMaximized;
2707 ShowMap := config.ReadBool('Editor', 'Minimap', False);
2708 PanelProps.Width := config.ReadInt('Editor', 'PanelProps', PanelProps.ClientWidth);
2709 Splitter1.Left := PanelProps.Left;
2710 PanelObjs.Height := config.ReadInt('Editor', 'PanelObjs', PanelObjs.ClientHeight);
2711 Splitter2.Top := PanelObjs.Top;
2712 StatusBar.Top := PanelObjs.BoundsRect.Bottom;
2713 DotEnable := config.ReadBool('Editor', 'DotEnable', True);
2714 DotColor := config.ReadInt('Editor', 'DotColor', $FFFFFF);
2715 DotStepOne := config.ReadInt('Editor', 'DotStepOne', 16);
2716 DotStepTwo := config.ReadInt('Editor', 'DotStepTwo', 8);
2717 DotStep := config.ReadInt('Editor', 'DotStep', DotStepOne);
2718 DrawTexturePanel := config.ReadBool('Editor', 'DrawTexturePanel', True);
2719 DrawPanelSize := config.ReadBool('Editor', 'DrawPanelSize', True);
2720 BackColor := config.ReadInt('Editor', 'BackColor', $7F6040);
2721 PreviewColor := config.ReadInt('Editor', 'PreviewColor', $00FF00);
2722 UseCheckerboard := config.ReadBool('Editor', 'UseCheckerboard', True);
2723 gColorEdge := config.ReadInt('Editor', 'EdgeColor', COLOR_EDGE);
2724 gAlphaEdge := config.ReadInt('Editor', 'EdgeAlpha', ALPHA_EDGE);
2725 if gAlphaEdge = 255 then
2726 gAlphaEdge := ALPHA_EDGE;
2727 drEdge[0] := GetRValue(gColorEdge);
2728 drEdge[1] := GetGValue(gColorEdge);
2729 drEdge[2] := GetBValue(gColorEdge);
2730 if not config.ReadBool('Editor', 'EdgeShow', True) then
2731 drEdge[3] := 255
2732 else
2733 drEdge[3] := gAlphaEdge;
2734 gAlphaTriggerLine := config.ReadInt('Editor', 'LineAlpha', ALPHA_LINE);
2735 if gAlphaTriggerLine = 255 then
2736 gAlphaTriggerLine := ALPHA_LINE;
2737 gAlphaTriggerArea := config.ReadInt('Editor', 'TriggerAlpha', ALPHA_AREA);
2738 if gAlphaTriggerArea = 255 then
2739 gAlphaTriggerArea := ALPHA_AREA;
2740 gAlphaMonsterRect := config.ReadInt('Editor', 'MonsterRectAlpha', 0);
2741 gAlphaAreaRect := config.ReadInt('Editor', 'AreaRectAlpha', 0);
2742 if config.ReadInt('Editor', 'Scale', 0) = 1 then
2743 Scale := 2
2744 else
2745 Scale := 1;
2746 if config.ReadInt('Editor', 'DotSize', 0) = 1 then
2747 DotSize := 2
2748 else
2749 DotSize := 1;
2750 OpenDialog.InitialDir := config.ReadStr('Editor', 'LastOpenDir', EditorDir);
2751 SaveDialog.InitialDir := config.ReadStr('Editor', 'LastSaveDir', EditorDir);
2753 s := config.ReadStr('Editor', 'Language', '');
2754 gLanguage := s;
2756 Compress := config.ReadBool('Editor', 'Compress', True);
2757 Backup := config.ReadBool('Editor', 'Backup', True);
2759 RecentCount := config.ReadInt('Editor', 'RecentCount', 5);
2760 if RecentCount > 10 then
2761 RecentCount := 10;
2762 if RecentCount < 2 then
2763 RecentCount := 2;
2765 RecentFiles := TStringList.Create();
2766 for i := 0 to RecentCount-1 do
2767 begin
2768 s := config.ReadStr('RecentFiles', IntToStr(i+1), '');
2769 if s <> '' then
2770 RecentFiles.Add(s);
2771 end;
2772 RefreshRecentMenu();
2774 config.Free();
2776 tbShowMap.Down := ShowMap;
2777 tbGridOn.Down := DotEnable;
2778 pcObjects.ActivePageIndex := 0;
2779 Application.Title := _lc[I_EDITOR_TITLE];
2781 Application.OnIdle := OnIdle;
2782 end;
2784 procedure PrintBlack(X, Y: Integer; Text: string; FontID: DWORD);
2785 begin
2786 // NOTE: all the font printing routines assume CP1251
2787 e_TextureFontPrintEx(X, Y, Text, FontID, 0, 0, 0, 1.0);
2788 end;
2790 procedure TMainForm.Draw();
2791 var
2792 x, y: Integer;
2793 a, b: Integer;
2794 ID, PID: DWORD;
2795 Width, Height: Word;
2796 Rect: TRectWH;
2797 ObjCount: Word;
2798 aX, aY, aX2, aY2, XX, ScaleSz: Integer;
2799 begin
2800 ID := 0;
2801 PID := 0;
2802 Width := 0;
2803 Height := 0;
2805 e_BeginRender();
2807 e_Clear(GL_COLOR_BUFFER_BIT,
2808 GetRValue(BackColor)/255,
2809 GetGValue(BackColor)/255,
2810 GetBValue(BackColor)/255);
2812 DrawMap();
2814 ObjCount := SelectedObjectCount();
2816 // Обводим выделенные объекты красной рамкой:
2817 if ObjCount > 0 then
2818 begin
2819 for a := 0 to High(SelectedObjects) do
2820 if SelectedObjects[a].Live then
2821 begin
2822 Rect := ObjectGetRect(SelectedObjects[a].ObjectType, SelectedObjects[a].ID);
2824 with Rect do
2825 begin
2826 e_DrawQuad(X+MapOffset.X, Y+MapOffset.Y,
2827 X+MapOffset.X+Width-1, Y+MapOffset.Y+Height-1,
2828 255, 0, 0);
2830 // Рисуем точки изменения размеров:
2831 if (ObjCount = 1) and
2832 (SelectedObjects[GetFirstSelected].ObjectType in [OBJECT_PANEL, OBJECT_TRIGGER]) then
2833 begin
2834 e_DrawPoint(5, X+MapOffset.X, Y+MapOffset.Y+(Height div 2), 255, 255, 255);
2835 e_DrawPoint(5, X+MapOffset.X+Width-1, Y+MapOffset.Y+(Height div 2), 255, 255, 255);
2836 e_DrawPoint(5, X+MapOffset.X+(Width div 2), Y+MapOffset.Y, 255, 255, 255);
2837 e_DrawPoint(5, X+MapOffset.X+(Width div 2), Y+MapOffset.Y+Height-1, 255, 255, 255);
2839 e_DrawPoint(3, X+MapOffset.X, Y+MapOffset.Y+(Height div 2), 255, 0, 0);
2840 e_DrawPoint(3, X+MapOffset.X+Width-1, Y+MapOffset.Y+(Height div 2), 255, 0, 0);
2841 e_DrawPoint(3, X+MapOffset.X+(Width div 2), Y+MapOffset.Y, 255, 0, 0);
2842 e_DrawPoint(3, X+MapOffset.X+(Width div 2), Y+MapOffset.Y+Height-1, 255, 0, 0);
2843 end;
2844 end;
2845 end;
2846 end;
2848 // Рисуем сетку:
2849 if DotEnable and (PreviewMode = 0) then
2850 begin
2851 if DotSize = 2 then
2852 a := -1
2853 else
2854 a := 0;
2856 x := MapOffset.X mod DotStep;
2857 y := MapOffset.Y mod DotStep;
2859 while x < RenderPanel.Width do
2860 begin
2861 while y < RenderPanel.Height do
2862 begin
2863 e_DrawPoint(DotSize, x + a, y + a,
2864 GetRValue(DotColor),
2865 GetGValue(DotColor),
2866 GetBValue(DotColor));
2867 y += DotStep;
2868 end;
2869 x += DotStep;
2870 y := MapOffset.Y mod DotStep;
2871 end;
2872 end;
2874 // Превью текстуры:
2875 if (lbTextureList.ItemIndex <> -1) and (cbPreview.Checked) and
2876 (not IsSpecialTextureSel()) and (PreviewMode = 0) then
2877 begin
2878 if not g_GetTexture(SelectedTexture(), ID) then
2879 g_GetTexture('NOTEXTURE', ID);
2880 g_GetTextureSizeByID(ID, Width, Height);
2881 if UseCheckerboard then
2882 begin
2883 if g_GetTexture('PREVIEW', PID) then
2884 e_DrawFill(PID, RenderPanel.Width-Width, RenderPanel.Height-Height, Width div 16 + 1, Height div 16 + 1, 0, True, False);
2885 end else
2886 e_DrawFillQuad(RenderPanel.Width-Width-2, RenderPanel.Height-Height-2,
2887 RenderPanel.Width-1, RenderPanel.Height-1,
2888 GetRValue(PreviewColor), GetGValue(PreviewColor), GetBValue(PreviewColor), 0);
2889 e_Draw(ID, RenderPanel.Width-Width, RenderPanel.Height-Height, 0, True, False);
2890 end;
2892 // Подсказка при выборе точки Телепорта:
2893 if SelectFlag = SELECTFLAG_TELEPORT then
2894 begin
2895 with gTriggers[SelectedObjects[GetFirstSelected()].ID] do
2896 if Data.d2d_teleport then
2897 e_DrawLine(2, MousePos.X-16, MousePos.Y-1,
2898 MousePos.X+16, MousePos.Y-1,
2899 0, 0, 255)
2900 else
2901 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+AreaSize[AREA_DMPOINT].Width-1,
2902 MousePos.Y+AreaSize[AREA_DMPOINT].Height-1, 255, 255, 255);
2904 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 192, 192, 192, 127);
2905 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 255, 255, 255);
2906 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_TELEPORT], gEditorFont);
2907 end;
2909 // Подсказка при выборе точки появления:
2910 if SelectFlag = SELECTFLAG_SPAWNPOINT then
2911 begin
2912 e_DrawLine(2, MousePos.X-16, MousePos.Y-1,
2913 MousePos.X+16, MousePos.Y-1,
2914 0, 0, 255);
2915 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 192, 192, 192, 127);
2916 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 255, 255, 255);
2917 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_SPAWN], gEditorFont);
2918 end;
2920 // Подсказка при выборе панели двери:
2921 if SelectFlag = SELECTFLAG_DOOR then
2922 begin
2923 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 192, 192, 192, 127);
2924 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 255, 255, 255);
2925 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_PANEL_DOOR], gEditorFont);
2926 end;
2928 // Подсказка при выборе панели с текстурой:
2929 if SelectFlag = SELECTFLAG_TEXTURE then
2930 begin
2931 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+196, MousePos.Y+18, 192, 192, 192, 127);
2932 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+196, MousePos.Y+18, 255, 255, 255);
2933 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_PANEL_TEXTURE], gEditorFont);
2934 end;
2936 // Подсказка при выборе панели индикации выстрела:
2937 if SelectFlag = SELECTFLAG_SHOTPANEL then
2938 begin
2939 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+316, MousePos.Y+18, 192, 192, 192, 127);
2940 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+316, MousePos.Y+18, 255, 255, 255);
2941 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_PANEL_SHOT], gEditorFont);
2942 end;
2944 // Подсказка при выборе панели лифта:
2945 if SelectFlag = SELECTFLAG_LIFT then
2946 begin
2947 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 192, 192, 192, 127);
2948 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 255, 255, 255);
2949 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_PANEL_LIFT], gEditorFont);
2950 end;
2952 // Подсказка при выборе монстра:
2953 if SelectFlag = SELECTFLAG_MONSTER then
2954 begin
2955 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+120, MousePos.Y+18, 192, 192, 192, 127);
2956 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+120, MousePos.Y+18, 255, 255, 255);
2957 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_MONSTER], gEditorFont);
2958 end;
2960 // Подсказка при выборе области воздействия:
2961 if DrawPressRect then
2962 begin
2963 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+204, MousePos.Y+18, 192, 192, 192, 127);
2964 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+204, MousePos.Y+18, 255, 255, 255);
2965 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_EXT_AREA], gEditorFont);
2966 end;
2968 // Рисуем текстуры, если чертим панель:
2969 if (MouseAction = MOUSEACTION_DRAWPANEL) and (DrawTexturePanel) and
2970 (lbTextureList.ItemIndex <> -1) and (DrawRect <> nil) and
2971 (lbPanelType.ItemIndex in [0..8]) and not IsSpecialTextureSel() then
2972 begin
2973 if not g_GetTexture(SelectedTexture(), ID) then
2974 g_GetTexture('NOTEXTURE', ID);
2975 g_GetTextureSizeByID(ID, Width, Height);
2976 with DrawRect^ do
2977 if (Abs(Right-Left) >= Width) and (Abs(Bottom-Top) >= Height) then
2978 e_DrawFill(ID, Min(Left, Right), Min(Top, Bottom), Abs(Right-Left) div Width,
2979 Abs(Bottom-Top) div Height, 64, True, False);
2980 end;
2982 // Прямоугольник выделения:
2983 if DrawRect <> nil then
2984 with DrawRect^ do
2985 e_DrawQuad(Left, Top, Right-1, Bottom-1, 255, 255, 255);
2987 // Чертим мышью панель/триггер или меняем мышью их размер:
2988 if (((MouseAction in [MOUSEACTION_DRAWPANEL, MOUSEACTION_DRAWTRIGGER]) and
2989 not(ssCtrl in GetKeyShiftState())) or (MouseAction = MOUSEACTION_RESIZE)) and
2990 (DrawPanelSize) then
2991 begin
2992 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+88, MousePos.Y+33, 192, 192, 192, 127);
2993 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+88, MousePos.Y+33, 255, 255, 255);
2995 if MouseAction in [MOUSEACTION_DRAWPANEL, MOUSEACTION_DRAWTRIGGER] then
2996 begin // Чертим новый
2997 PrintBlack(MousePos.X+2, MousePos.Y+2, Format(_glc[I_HINT_WIDTH],
2998 [Abs(MousePos.X-MouseLDownPos.X)]), gEditorFont);
2999 PrintBlack(MousePos.X+2, MousePos.Y+16, Format(_glc[I_HINT_HEIGHT],
3000 [Abs(MousePos.Y-MouseLDownPos.Y)]), gEditorFont);
3001 end
3002 else // Растягиваем существующий
3003 if SelectedObjects[GetFirstSelected].ObjectType in [OBJECT_PANEL, OBJECT_TRIGGER] then
3004 begin
3005 if SelectedObjects[GetFirstSelected].ObjectType = OBJECT_PANEL then
3006 begin
3007 Width := gPanels[SelectedObjects[GetFirstSelected].ID].Width;
3008 Height := gPanels[SelectedObjects[GetFirstSelected].ID].Height;
3009 end
3010 else
3011 begin
3012 Width := gTriggers[SelectedObjects[GetFirstSelected].ID].Width;
3013 Height := gTriggers[SelectedObjects[GetFirstSelected].ID].Height;
3014 end;
3016 PrintBlack(MousePos.X+2, MousePos.Y+2, Format(_glc[I_HINT_WIDTH], [Width]),
3017 gEditorFont);
3018 PrintBlack(MousePos.X+2, MousePos.Y+16, Format(_glc[I_HINT_HEIGHT], [Height]),
3019 gEditorFont);
3020 end;
3021 end;
3023 // Ближайшая к курсору мыши точка на сетке:
3024 e_DrawPoint(3, MousePos.X, MousePos.Y, 0, 0, 255);
3026 // Мини-карта:
3027 if ShowMap then
3028 begin
3029 // Сколько пикселов карты в 1 пикселе мини-карты:
3030 ScaleSz := 16 div Scale;
3031 // Размеры мини-карты:
3032 aX := max(gMapInfo.Width div ScaleSz, 1);
3033 aY := max(gMapInfo.Height div ScaleSz, 1);
3034 // X-координата на RenderPanel нулевой x-координаты карты:
3035 XX := RenderPanel.Width - aX - 1;
3036 // Рамка карты:
3037 e_DrawFillQuad(XX-1, 0, RenderPanel.Width-1, aY+1, 0, 0, 0, 0);
3038 e_DrawQuad(XX-1, 0, RenderPanel.Width-1, aY+1, 197, 197, 197);
3040 if gPanels <> nil then
3041 begin
3042 // Рисуем панели:
3043 for a := 0 to High(gPanels) do
3044 with gPanels[a] do
3045 if PanelType <> 0 then
3046 begin
3047 // Левый верхний угол:
3048 aX := XX + (X div ScaleSz);
3049 aY := 1 + (Y div ScaleSz);
3050 // Размеры:
3051 aX2 := max(Width div ScaleSz, 1);
3052 aY2 := max(Height div ScaleSz, 1);
3053 // Правый нижний угол:
3054 aX2 := aX + aX2 - 1;
3055 aY2 := aY + aY2 - 1;
3057 case PanelType of
3058 PANEL_WALL: e_DrawFillQuad(aX, aY, aX2, aY2, 208, 208, 208, 0);
3059 PANEL_WATER: e_DrawFillQuad(aX, aY, aX2, aY2, 0, 0, 192, 0);
3060 PANEL_ACID1: e_DrawFillQuad(aX, aY, aX2, aY2, 0, 176, 0, 0);
3061 PANEL_ACID2: e_DrawFillQuad(aX, aY, aX2, aY2, 176, 0, 0, 0);
3062 PANEL_STEP: e_DrawFillQuad(aX, aY, aX2, aY2, 128, 128, 128, 0);
3063 PANEL_LIFTUP: e_DrawFillQuad(aX, aY, aX2, aY2, 116, 72, 36, 0);
3064 PANEL_LIFTDOWN: e_DrawFillQuad(aX, aY, aX2, aY2, 116, 124, 96, 0);
3065 PANEL_LIFTLEFT: e_DrawFillQuad(aX, aY, aX2, aY2, 200, 80, 4, 0);
3066 PANEL_LIFTRIGHT: e_DrawFillQuad(aX, aY, aX2, aY2, 252, 140, 56, 0);
3067 PANEL_OPENDOOR: e_DrawFillQuad(aX, aY, aX2, aY2, 100, 220, 92, 0);
3068 PANEL_CLOSEDOOR: e_DrawFillQuad(aX, aY, aX2, aY2, 212, 184, 64, 0);
3069 PANEL_BLOCKMON: e_DrawFillQuad(aX, aY, aX2, aY2, 192, 0, 192, 0);
3070 end;
3071 end;
3073 // Рисуем красным выделенные панели:
3074 if SelectedObjects <> nil then
3075 for b := 0 to High(SelectedObjects) do
3076 with SelectedObjects[b] do
3077 if Live and (ObjectType = OBJECT_PANEL) then
3078 with gPanels[SelectedObjects[b].ID] do
3079 if PanelType and not(PANEL_BACK or PANEL_FORE) <> 0 then
3080 begin
3081 // Левый верхний угол:
3082 aX := XX + (X div ScaleSz);
3083 aY := 1 + (Y div ScaleSz);
3084 // Размеры:
3085 aX2 := max(Width div ScaleSz, 1);
3086 aY2 := max(Height div ScaleSz, 1);
3087 // Правый нижний угол:
3088 aX2 := aX + aX2 - 1;
3089 aY2 := aY + aY2 - 1;
3091 e_DrawFillQuad(aX, aY, aX2, aY2, 255, 0, 0, 0)
3092 end;
3093 end;
3095 if (gMapInfo.Width > RenderPanel.Width) or
3096 (gMapInfo.Height > RenderPanel.Height) then
3097 begin
3098 // Окно, показывающее текущее положение экрана на карте:
3099 // Размеры окна:
3100 x := max(min(RenderPanel.Width, gMapInfo.Width) div ScaleSz, 1);
3101 y := max(min(RenderPanel.Height, gMapInfo.Height) div ScaleSz, 1);
3102 // Левый верхний угол:
3103 aX := XX + ((-MapOffset.X) div ScaleSz);
3104 aY := 1 + ((-MapOffset.Y) div ScaleSz);
3105 // Правый нижний угол:
3106 aX2 := aX + x - 1;
3107 aY2 := aY + y - 1;
3109 e_DrawFillQuad(aX, aY, aX2, aY2, 127, 192, 127, 127, B_BLEND);
3110 e_DrawQuad(aX, aY, aX2, aY2, 255, 0, 0);
3111 end;
3112 end; // Мини-карта
3114 e_EndRender();
3115 RenderPanel.SwapBuffers();
3116 end;
3118 procedure TMainForm.FormResize(Sender: TObject);
3119 begin
3120 e_SetViewPort(0, 0, RenderPanel.Width, RenderPanel.Height);
3122 sbHorizontal.Min := Min(gMapInfo.Width - RenderPanel.Width, -RenderPanel.Width div 2);
3123 sbHorizontal.Max := Max(0, gMapInfo.Width - RenderPanel.Width div 2);
3124 sbVertical.Min := Min(gMapInfo.Height - RenderPanel.Height, -RenderPanel.Height div 2);
3125 sbVertical.Max := Max(0, gMapInfo.Height - RenderPanel.Height div 2);
3127 MapOffset.X := -sbHorizontal.Position;
3128 MapOffset.Y := -sbVertical.Position;
3129 end;
3131 procedure SelectNextObject(X, Y: Integer; ObjectType: Byte; ID: DWORD);
3132 var
3133 j, j_max: Integer;
3134 res: Boolean;
3135 begin
3136 j_max := 0; // shut up compiler
3137 case ObjectType of
3138 OBJECT_PANEL:
3139 begin
3140 res := (gPanels <> nil) and
3141 PanelInShownLayer(gPanels[ID].PanelType) and
3142 g_CollidePoint(X, Y, gPanels[ID].X, gPanels[ID].Y,
3143 gPanels[ID].Width,
3144 gPanels[ID].Height);
3145 j_max := Length(gPanels) - 1;
3146 end;
3148 OBJECT_ITEM:
3149 begin
3150 res := (gItems <> nil) and
3151 LayerEnabled[LAYER_ITEMS] and
3152 g_CollidePoint(X, Y, gItems[ID].X, gItems[ID].Y,
3153 ItemSize[gItems[ID].ItemType][0],
3154 ItemSize[gItems[ID].ItemType][1]);
3155 j_max := Length(gItems) - 1;
3156 end;
3158 OBJECT_MONSTER:
3159 begin
3160 res := (gMonsters <> nil) and
3161 LayerEnabled[LAYER_MONSTERS] and
3162 g_CollidePoint(X, Y, gMonsters[ID].X, gMonsters[ID].Y,
3163 MonsterSize[gMonsters[ID].MonsterType].Width,
3164 MonsterSize[gMonsters[ID].MonsterType].Height);
3165 j_max := Length(gMonsters) - 1;
3166 end;
3168 OBJECT_AREA:
3169 begin
3170 res := (gAreas <> nil) and
3171 LayerEnabled[LAYER_AREAS] and
3172 g_CollidePoint(X, Y, gAreas[ID].X, gAreas[ID].Y,
3173 AreaSize[gAreas[ID].AreaType].Width,
3174 AreaSize[gAreas[ID].AreaType].Height);
3175 j_max := Length(gAreas) - 1;
3176 end;
3178 OBJECT_TRIGGER:
3179 begin
3180 res := (gTriggers <> nil) and
3181 LayerEnabled[LAYER_TRIGGERS] and
3182 g_CollidePoint(X, Y, gTriggers[ID].X, gTriggers[ID].Y,
3183 gTriggers[ID].Width,
3184 gTriggers[ID].Height);
3185 j_max := Length(gTriggers) - 1;
3186 end;
3188 else
3189 res := False;
3190 end;
3192 if not res then
3193 Exit;
3195 // Перебор ID: от ID-1 до 0; потом от High до ID+1:
3196 j := ID;
3198 while True do
3199 begin
3200 Dec(j);
3202 if j < 0 then
3203 j := j_max;
3204 if j = Integer(ID) then
3205 Break;
3207 case ObjectType of
3208 OBJECT_PANEL:
3209 res := PanelInShownLayer(gPanels[j].PanelType) and
3210 g_CollidePoint(X, Y, gPanels[j].X, gPanels[j].Y,
3211 gPanels[j].Width,
3212 gPanels[j].Height);
3213 OBJECT_ITEM:
3214 res := (gItems[j].ItemType <> ITEM_NONE) and
3215 g_CollidePoint(X, Y, gItems[j].X, gItems[j].Y,
3216 ItemSize[gItems[j].ItemType][0],
3217 ItemSize[gItems[j].ItemType][1]);
3218 OBJECT_MONSTER:
3219 res := (gMonsters[j].MonsterType <> MONSTER_NONE) and
3220 g_CollidePoint(X, Y, gMonsters[j].X, gMonsters[j].Y,
3221 MonsterSize[gMonsters[j].MonsterType].Width,
3222 MonsterSize[gMonsters[j].MonsterType].Height);
3223 OBJECT_AREA:
3224 res := (gAreas[j].AreaType <> AREA_NONE) and
3225 g_CollidePoint(X, Y, gAreas[j].X, gAreas[j].Y,
3226 AreaSize[gAreas[j].AreaType].Width,
3227 AreaSize[gAreas[j].AreaType].Height);
3228 OBJECT_TRIGGER:
3229 res := (gTriggers[j].TriggerType <> TRIGGER_NONE) and
3230 g_CollidePoint(X, Y, gTriggers[j].X, gTriggers[j].Y,
3231 gTriggers[j].Width,
3232 gTriggers[j].Height);
3233 else
3234 res := False;
3235 end;
3237 if res then
3238 begin
3239 SetLength(SelectedObjects, 1);
3241 SelectedObjects[0].ObjectType := ObjectType;
3242 SelectedObjects[0].ID := j;
3243 SelectedObjects[0].Live := True;
3245 FillProperty();
3246 Break;
3247 end;
3248 end;
3249 end;
3251 procedure TMainForm.RenderPanelMouseDown(Sender: TObject;
3252 Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
3253 var
3254 i: Integer;
3255 Rect: TRectWH;
3256 c1, c2, c3, c4: Boolean;
3257 item: TItem;
3258 area: TArea;
3259 monster: TMonster;
3260 IDArray: DWArray;
3261 begin
3262 MainForm.ActiveControl := RenderPanel;
3263 RenderPanel.SetFocus();
3265 RenderPanelMouseMove(RenderPanel, Shift, X, Y);
3267 if Button = mbLeft then // Left Mouse Button
3268 begin
3269 // Двигаем карту с помощью мыши и мини-карты:
3270 if ShowMap and
3271 g_CollidePoint(X, Y,
3272 RenderPanel.Width-max(gMapInfo.Width div (16 div Scale), 1)-1,
3273 1,
3274 max(gMapInfo.Width div (16 div Scale), 1),
3275 max(gMapInfo.Height div (16 div Scale), 1) ) then
3276 begin
3277 MoveMap(X, Y);
3278 MouseAction := MOUSEACTION_MOVEMAP;
3279 end
3280 else // Ставим предмет/монстра/область:
3281 if (pcObjects.ActivePageIndex in [1, 2, 3]) and
3282 (not (ssShift in Shift)) then
3283 begin
3284 case pcObjects.ActivePageIndex of
3285 1:
3286 if lbItemList.ItemIndex = -1 then
3287 ErrorMessageBox(_lc[I_MSG_CHOOSE_ITEM])
3288 else
3289 begin
3290 item.ItemType := lbItemList.ItemIndex + ITEM_MEDKIT_SMALL;
3291 if item.ItemType >= ITEM_WEAPON_KASTET then
3292 item.ItemType := item.ItemType + 2;
3293 item.X := MousePos.X-MapOffset.X;
3294 item.Y := MousePos.Y-MapOffset.Y;
3296 if not (ssCtrl in Shift) then
3297 begin
3298 item.X := item.X - (ItemSize[item.ItemType][0] div 2);
3299 item.Y := item.Y - ItemSize[item.ItemType][1];
3300 end;
3302 item.OnlyDM := cbOnlyDM.Checked;
3303 item.Fall := cbFall.Checked;
3304 Undo_Add(OBJECT_ITEM, AddItem(item));
3305 end;
3306 2:
3307 if lbMonsterList.ItemIndex = -1 then
3308 ErrorMessageBox(_lc[I_MSG_CHOOSE_MONSTER])
3309 else
3310 begin
3311 monster.MonsterType := lbMonsterList.ItemIndex + MONSTER_DEMON;
3312 monster.X := MousePos.X-MapOffset.X;
3313 monster.Y := MousePos.Y-MapOffset.Y;
3315 if not (ssCtrl in Shift) then
3316 begin
3317 monster.X := monster.X - (MonsterSize[monster.MonsterType].Width div 2);
3318 monster.Y := monster.Y - MonsterSize[monster.MonsterType].Height;
3319 end;
3321 if rbMonsterLeft.Checked then
3322 monster.Direction := D_LEFT
3323 else
3324 monster.Direction := D_RIGHT;
3325 Undo_Add(OBJECT_MONSTER, AddMonster(monster));
3326 end;
3327 3:
3328 if lbAreasList.ItemIndex = -1 then
3329 ErrorMessageBox(_lc[I_MSG_CHOOSE_AREA])
3330 else
3331 if (lbAreasList.ItemIndex + 1) <> AREA_DOMFLAG then
3332 begin
3333 area.AreaType := lbAreasList.ItemIndex + AREA_PLAYERPOINT1;
3334 area.X := MousePos.X-MapOffset.X;
3335 area.Y := MousePos.Y-MapOffset.Y;
3337 if not (ssCtrl in Shift) then
3338 begin
3339 area.X := area.X - (AreaSize[area.AreaType].Width div 2);
3340 area.Y := area.Y - AreaSize[area.AreaType].Height;
3341 end;
3343 if rbAreaLeft.Checked then
3344 area.Direction := D_LEFT
3345 else
3346 area.Direction := D_RIGHT;
3347 Undo_Add(OBJECT_AREA, AddArea(area));
3348 end;
3349 end;
3350 end
3351 else
3352 begin
3353 i := GetFirstSelected();
3355 // Выбираем объект под текущим:
3356 if (SelectedObjects <> nil) and
3357 (ssShift in Shift) and (i >= 0) and
3358 (SelectedObjects[i].Live) then
3359 begin
3360 if SelectedObjectCount() = 1 then
3361 SelectNextObject(X-MapOffset.X, Y-MapOffset.Y,
3362 SelectedObjects[i].ObjectType,
3363 SelectedObjects[i].ID);
3364 end
3365 else
3366 begin
3367 // Рисуем область триггера "Расширитель":
3368 if DrawPressRect and (i >= 0) and
3369 (SelectedObjects[i].ObjectType = OBJECT_TRIGGER) and
3370 (gTriggers[SelectedObjects[i].ID].TriggerType in
3371 [TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF]) then
3372 MouseAction := MOUSEACTION_DRAWPRESS
3373 else // Рисуем панель:
3374 if pcObjects.ActivePageIndex = 0 then
3375 begin
3376 if (lbPanelType.ItemIndex >= 0) then
3377 MouseAction := MOUSEACTION_DRAWPANEL
3378 end
3379 else // Рисуем триггер:
3380 if (lbTriggersList.ItemIndex >= 0) then
3381 begin
3382 MouseAction := MOUSEACTION_DRAWTRIGGER;
3383 end;
3384 end;
3385 end;
3386 end; // if Button = mbLeft
3388 if Button = mbRight then // Right Mouse Button
3389 begin
3390 // Клик по мини-карте:
3391 if ShowMap and
3392 g_CollidePoint(X, Y,
3393 RenderPanel.Width-max(gMapInfo.Width div (16 div Scale), 1)-1,
3394 1,
3395 max(gMapInfo.Width div (16 div Scale), 1),
3396 max(gMapInfo.Height div (16 div Scale), 1) ) then
3397 begin
3398 MouseAction := MOUSEACTION_NOACTION;
3399 end
3400 else // Нужно что-то выбрать мышью:
3401 if SelectFlag <> SELECTFLAG_NONE then
3402 begin
3403 case SelectFlag of
3404 SELECTFLAG_TELEPORT:
3405 // Точку назначения телепортации:
3406 with gTriggers[SelectedObjects[
3407 GetFirstSelected() ].ID].Data.TargetPoint do
3408 begin
3409 X := MousePos.X-MapOffset.X;
3410 Y := MousePos.Y-MapOffset.Y;
3411 end;
3413 SELECTFLAG_SPAWNPOINT:
3414 // Точку создания монстра:
3415 with gTriggers[SelectedObjects[GetFirstSelected()].ID] do
3416 if TriggerType = TRIGGER_SPAWNMONSTER then
3417 begin
3418 Data.MonPos.X := MousePos.X-MapOffset.X;
3419 Data.MonPos.Y := MousePos.Y-MapOffset.Y;
3420 end
3421 else if TriggerType = TRIGGER_SPAWNITEM then
3422 begin // Точка создания предмета:
3423 Data.ItemPos.X := MousePos.X-MapOffset.X;
3424 Data.ItemPos.Y := MousePos.Y-MapOffset.Y;
3425 end
3426 else if TriggerType = TRIGGER_SHOT then
3427 begin // Точка создания выстрела:
3428 Data.ShotPos.X := MousePos.X-MapOffset.X;
3429 Data.ShotPos.Y := MousePos.Y-MapOffset.Y;
3430 end;
3432 SELECTFLAG_DOOR:
3433 // Дверь:
3434 begin
3435 IDArray := ObjectInRect(X-MapOffset.X,
3436 Y-MapOffset.Y,
3437 2, 2, OBJECT_PANEL, True);
3438 if IDArray <> nil then
3439 begin
3440 for i := 0 to High(IDArray) do
3441 if (gPanels[IDArray[i]].PanelType = PANEL_OPENDOOR) or
3442 (gPanels[IDArray[i]].PanelType = PANEL_CLOSEDOOR) then
3443 begin
3444 gTriggers[SelectedObjects[
3445 GetFirstSelected() ].ID].Data.PanelID := IDArray[i];
3446 Break;
3447 end;
3448 end
3449 else
3450 gTriggers[SelectedObjects[
3451 GetFirstSelected() ].ID].Data.PanelID := -1;
3452 end;
3454 SELECTFLAG_TEXTURE:
3455 // Панель с текстурой:
3456 begin
3457 IDArray := ObjectInRect(X-MapOffset.X,
3458 Y-MapOffset.Y,
3459 2, 2, OBJECT_PANEL, True);
3460 if IDArray <> nil then
3461 begin
3462 for i := 0 to High(IDArray) do
3463 if ((gPanels[IDArray[i]].PanelType in
3464 [PANEL_WALL, PANEL_BACK, PANEL_FORE,
3465 PANEL_WATER, PANEL_ACID1, PANEL_ACID2,
3466 PANEL_STEP]) or
3467 (gPanels[IDArray[i]].PanelType = PANEL_OPENDOOR) or
3468 (gPanels[IDArray[i]].PanelType = PANEL_CLOSEDOOR)) and
3469 (gPanels[IDArray[i]].TextureName <> '') then
3470 begin
3471 gTriggers[SelectedObjects[
3472 GetFirstSelected() ].ID].TexturePanel := IDArray[i];
3473 Break;
3474 end;
3475 end
3476 else
3477 gTriggers[SelectedObjects[
3478 GetFirstSelected() ].ID].TexturePanel := -1;
3479 end;
3481 SELECTFLAG_LIFT:
3482 // Лифт:
3483 begin
3484 IDArray := ObjectInRect(X-MapOffset.X,
3485 Y-MapOffset.Y,
3486 2, 2, OBJECT_PANEL, True);
3487 if IDArray <> nil then
3488 begin
3489 for i := 0 to High(IDArray) do
3490 if (gPanels[IDArray[i]].PanelType = PANEL_LIFTUP) or
3491 (gPanels[IDArray[i]].PanelType = PANEL_LIFTDOWN) or
3492 (gPanels[IDArray[i]].PanelType = PANEL_LIFTLEFT) or
3493 (gPanels[IDArray[i]].PanelType = PANEL_LIFTRIGHT) then
3494 begin
3495 gTriggers[SelectedObjects[
3496 GetFirstSelected() ].ID].Data.PanelID := IDArray[i];
3497 Break;
3498 end;
3499 end
3500 else
3501 gTriggers[SelectedObjects[
3502 GetFirstSelected() ].ID].Data.PanelID := -1;
3503 end;
3505 SELECTFLAG_MONSTER:
3506 // Монстра:
3507 begin
3508 IDArray := ObjectInRect(X-MapOffset.X,
3509 Y-MapOffset.Y,
3510 2, 2, OBJECT_MONSTER, False);
3511 if IDArray <> nil then
3512 gTriggers[SelectedObjects[
3513 GetFirstSelected() ].ID].Data.MonsterID := IDArray[0]+1
3514 else
3515 gTriggers[SelectedObjects[
3516 GetFirstSelected() ].ID].Data.MonsterID := 0;
3517 end;
3519 SELECTFLAG_SHOTPANEL:
3520 // Панель индикации выстрела:
3521 begin
3522 if gTriggers[SelectedObjects[
3523 GetFirstSelected() ].ID].TriggerType = TRIGGER_SHOT then
3524 begin
3525 IDArray := ObjectInRect(X-MapOffset.X,
3526 Y-MapOffset.Y,
3527 2, 2, OBJECT_PANEL, True);
3528 if IDArray <> nil then
3529 begin
3530 for i := 0 to High(IDArray) do
3531 if ((gPanels[IDArray[i]].PanelType in
3532 [PANEL_WALL, PANEL_BACK, PANEL_FORE,
3533 PANEL_WATER, PANEL_ACID1, PANEL_ACID2,
3534 PANEL_STEP]) or
3535 (gPanels[IDArray[i]].PanelType = PANEL_OPENDOOR) or
3536 (gPanels[IDArray[i]].PanelType = PANEL_CLOSEDOOR)) and
3537 (gPanels[IDArray[i]].TextureName <> '') then
3538 begin
3539 gTriggers[SelectedObjects[
3540 GetFirstSelected() ].ID].Data.ShotPanelID := IDArray[i];
3541 Break;
3542 end;
3543 end
3544 else
3545 gTriggers[SelectedObjects[
3546 GetFirstSelected() ].ID].Data.ShotPanelID := -1;
3547 end;
3548 end;
3549 end;
3551 SelectFlag := SELECTFLAG_SELECTED;
3552 end
3553 else // if SelectFlag <> SELECTFLAG_NONE...
3554 begin
3555 // Что уже выбрано и не нажат Ctrl:
3556 if (SelectedObjects <> nil) and
3557 (not (ssCtrl in Shift)) then
3558 for i := 0 to High(SelectedObjects) do
3559 with SelectedObjects[i] do
3560 if Live then
3561 begin
3562 if (ObjectType in [OBJECT_PANEL, OBJECT_TRIGGER]) and
3563 (SelectedObjectCount() = 1) then
3564 begin
3565 Rect := ObjectGetRect(ObjectType, ID);
3567 c1 := g_Collide(X-MapOffset.X-1, Y-MapOffset.Y-1, 2, 2,
3568 Rect.X-2, Rect.Y+(Rect.Height div 2)-2, 4, 4);
3569 c2 := g_Collide(X-MapOffset.X-1, Y-MapOffset.Y-1, 2, 2,
3570 Rect.X+Rect.Width-3, Rect.Y+(Rect.Height div 2)-2, 4, 4);
3571 c3 := g_Collide(X-MapOffset.X-1, Y-MapOffset.Y-1, 2, 2,
3572 Rect.X+(Rect.Width div 2)-2, Rect.Y-2, 4, 4);
3573 c4 := g_Collide(X-MapOffset.X-1, Y-MapOffset.Y-1, 2, 2,
3574 Rect.X+(Rect.Width div 2)-2, Rect.Y+Rect.Height-3, 4, 4);
3576 // Меняем размер панели или триггера:
3577 if c1 or c2 or c3 or c4 then
3578 begin
3579 MouseAction := MOUSEACTION_RESIZE;
3580 LastMovePoint := MousePos;
3582 if c1 or c2 then
3583 begin // Шире/уже
3584 ResizeType := RESIZETYPE_HORIZONTAL;
3585 if c1 then
3586 ResizeDirection := RESIZEDIR_LEFT
3587 else
3588 ResizeDirection := RESIZEDIR_RIGHT;
3589 RenderPanel.Cursor := crSizeWE;
3590 end
3591 else
3592 begin // Выше/ниже
3593 ResizeType := RESIZETYPE_VERTICAL;
3594 if c3 then
3595 ResizeDirection := RESIZEDIR_UP
3596 else
3597 ResizeDirection := RESIZEDIR_DOWN;
3598 RenderPanel.Cursor := crSizeNS;
3599 end;
3601 Break;
3602 end;
3603 end;
3605 // Перемещаем панель или триггер:
3606 if ObjectCollide(ObjectType, ID,
3607 X-MapOffset.X-1,
3608 Y-MapOffset.Y-1, 2, 2) then
3609 begin
3610 MouseAction := MOUSEACTION_MOVEOBJ;
3611 LastMovePoint := MousePos;
3613 Break;
3614 end;
3615 end;
3616 end;
3617 end; // if Button = mbRight
3619 MouseRDown := Button = mbRight;
3620 if MouseRDown then
3621 MouseRDownPos := MousePos;
3623 MouseLDown := Button = mbLeft;
3624 if MouseLDown then
3625 MouseLDownPos := MousePos;
3626 end;
3628 procedure TMainForm.RenderPanelMouseUp(Sender: TObject;
3629 Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
3630 var
3631 panel: TPanel;
3632 trigger: TTrigger;
3633 rRect: TRectWH;
3634 rSelectRect: Boolean;
3635 wWidth, wHeight: Word;
3636 TextureID: DWORD;
3638 procedure SelectObjects(ObjectType: Byte);
3639 var
3640 i: Integer;
3641 IDArray: DWArray;
3642 begin
3643 IDArray := ObjectInRect(rRect.X, rRect.Y,
3644 rRect.Width, rRect.Height,
3645 ObjectType, rSelectRect);
3647 if IDArray <> nil then
3648 for i := 0 to High(IDArray) do
3649 SelectObject(ObjectType, IDArray[i], (ssCtrl in Shift) or rSelectRect);
3650 end;
3651 begin
3652 if Button = mbLeft then
3653 MouseLDown := False;
3654 if Button = mbRight then
3655 MouseRDown := False;
3657 DrawRect := nil;
3658 ResizeType := RESIZETYPE_NONE;
3659 TextureID := 0;
3661 if Button = mbLeft then // Left Mouse Button
3662 begin
3663 if MouseAction <> MOUSEACTION_NONE then
3664 begin // Было действие мышью
3665 // Мышь сдвинулась во время удержания клавиши,
3666 // либо активирован режим быстрого рисования:
3667 if ((MousePos.X <> MouseLDownPos.X) and
3668 (MousePos.Y <> MouseLDownPos.Y)) or
3669 ((MouseAction in [MOUSEACTION_DRAWPANEL, MOUSEACTION_DRAWTRIGGER]) and
3670 (ssCtrl in Shift)) then
3671 case MouseAction of
3672 // Рисовали панель:
3673 MOUSEACTION_DRAWPANEL:
3674 begin
3675 // Фон или передний план без текстуры - ошибка:
3676 if (lbPanelType.ItemIndex in [1, 2]) and
3677 (lbTextureList.ItemIndex = -1) then
3678 ErrorMessageBox(_lc[I_MSG_CHOOSE_TEXTURE])
3679 else // Назначаем параметры панели:
3680 begin
3681 case lbPanelType.ItemIndex of
3682 0: Panel.PanelType := PANEL_WALL;
3683 1: Panel.PanelType := PANEL_BACK;
3684 2: Panel.PanelType := PANEL_FORE;
3685 3: Panel.PanelType := PANEL_OPENDOOR;
3686 4: Panel.PanelType := PANEL_CLOSEDOOR;
3687 5: Panel.PanelType := PANEL_STEP;
3688 6: Panel.PanelType := PANEL_WATER;
3689 7: Panel.PanelType := PANEL_ACID1;
3690 8: Panel.PanelType := PANEL_ACID2;
3691 9: Panel.PanelType := PANEL_LIFTUP;
3692 10: Panel.PanelType := PANEL_LIFTDOWN;
3693 11: Panel.PanelType := PANEL_LIFTLEFT;
3694 12: Panel.PanelType := PANEL_LIFTRIGHT;
3695 13: Panel.PanelType := PANEL_BLOCKMON;
3696 end;
3698 Panel.X := Min(MousePos.X-MapOffset.X, MouseLDownPos.X-MapOffset.X);
3699 Panel.Y := Min(MousePos.Y-MapOffset.Y, MouseLDownPos.Y-MapOffset.Y);
3700 if ssCtrl in Shift then
3701 begin
3702 wWidth := DotStep;
3703 wHeight := DotStep;
3704 if (lbTextureList.ItemIndex <> -1) and
3705 (not IsSpecialTextureSel()) then
3706 begin
3707 if not g_GetTexture(SelectedTexture(), TextureID) then
3708 g_GetTexture('NOTEXTURE', TextureID);
3709 g_GetTextureSizeByID(TextureID, wWidth, wHeight);
3710 end;
3711 Panel.Width := wWidth;
3712 Panel.Height := wHeight;
3713 end
3714 else
3715 begin
3716 Panel.Width := Abs(MousePos.X-MouseLDownPos.X);
3717 Panel.Height := Abs(MousePos.Y-MouseLDownPos.Y);
3718 end;
3720 // Лифты, блокМон или отсутствие текстуры - пустая текстура:
3721 if (lbPanelType.ItemIndex in [9, 10, 11, 12, 13]) or
3722 (lbTextureList.ItemIndex = -1) then
3723 begin
3724 Panel.TextureHeight := 1;
3725 Panel.TextureWidth := 1;
3726 Panel.TextureName := '';
3727 Panel.TextureID := TEXTURE_SPECIAL_NONE;
3728 end
3729 else // Есть текстура:
3730 begin
3731 Panel.TextureName := SelectedTexture();
3733 // Обычная текстура:
3734 if not IsSpecialTextureSel() then
3735 begin
3736 g_GetTextureSizeByName(Panel.TextureName,
3737 Panel.TextureWidth, Panel.TextureHeight);
3738 g_GetTexture(Panel.TextureName, Panel.TextureID);
3739 end
3740 else // Спец.текстура:
3741 begin
3742 Panel.TextureHeight := 1;
3743 Panel.TextureWidth := 1;
3744 Panel.TextureID := SpecialTextureID(SelectedTexture());
3745 end;
3746 end;
3748 Panel.Alpha := 0;
3749 Panel.Blending := False;
3751 Undo_Add(OBJECT_PANEL, AddPanel(Panel));
3752 end;
3753 end;
3755 // Рисовали триггер:
3756 MOUSEACTION_DRAWTRIGGER:
3757 begin
3758 trigger.X := Min(MousePos.X-MapOffset.X, MouseLDownPos.X-MapOffset.X);
3759 trigger.Y := Min(MousePos.Y-MapOffset.Y, MouseLDownPos.Y-MapOffset.Y);
3760 if ssCtrl in Shift then
3761 begin
3762 wWidth := DotStep;
3763 wHeight := DotStep;
3764 trigger.Width := wWidth;
3765 trigger.Height := wHeight;
3766 end
3767 else
3768 begin
3769 trigger.Width := Abs(MousePos.X-MouseLDownPos.X);
3770 trigger.Height := Abs(MousePos.Y-MouseLDownPos.Y);
3771 end;
3773 trigger.Enabled := True;
3774 trigger.TriggerType := lbTriggersList.ItemIndex+1;
3775 trigger.TexturePanel := -1;
3777 // Типы активации:
3778 trigger.ActivateType := 0;
3780 if clbActivationType.Checked[0] then
3781 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_PLAYERCOLLIDE;
3782 if clbActivationType.Checked[1] then
3783 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_MONSTERCOLLIDE;
3784 if clbActivationType.Checked[2] then
3785 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_PLAYERPRESS;
3786 if clbActivationType.Checked[3] then
3787 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_MONSTERPRESS;
3788 if clbActivationType.Checked[4] then
3789 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_SHOT;
3790 if clbActivationType.Checked[5] then
3791 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_NOMONSTER;
3793 // Необходимые для активации ключи:
3794 trigger.Key := 0;
3796 if clbKeys.Checked[0] then
3797 trigger.Key := Trigger.Key or KEY_RED;
3798 if clbKeys.Checked[1] then
3799 trigger.Key := Trigger.Key or KEY_GREEN;
3800 if clbKeys.Checked[2] then
3801 trigger.Key := Trigger.Key or KEY_BLUE;
3802 if clbKeys.Checked[3] then
3803 trigger.Key := Trigger.Key or KEY_REDTEAM;
3804 if clbKeys.Checked[4] then
3805 trigger.Key := Trigger.Key or KEY_BLUETEAM;
3807 // Параметры триггера:
3808 FillByte(trigger.Data.Default[0], 128, 0);
3810 case trigger.TriggerType of
3811 // Переключаемая панель:
3812 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
3813 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP,
3814 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
3815 begin
3816 Trigger.Data.PanelID := -1;
3817 end;
3819 // Телепортация:
3820 TRIGGER_TELEPORT:
3821 begin
3822 trigger.Data.TargetPoint.X := trigger.X-64;
3823 trigger.Data.TargetPoint.Y := trigger.Y-64;
3824 trigger.Data.d2d_teleport := True;
3825 trigger.Data.TlpDir := 0;
3826 end;
3828 // Изменение других триггеров:
3829 TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF,
3830 TRIGGER_ONOFF:
3831 begin
3832 trigger.Data.Count := 1;
3833 end;
3835 // Звук:
3836 TRIGGER_SOUND:
3837 begin
3838 trigger.Data.Volume := 255;
3839 trigger.Data.Pan := 127;
3840 trigger.Data.PlayCount := 1;
3841 trigger.Data.Local := True;
3842 trigger.Data.SoundSwitch := False;
3843 end;
3845 // Музыка:
3846 TRIGGER_MUSIC:
3847 begin
3848 trigger.Data.MusicAction := 1;
3849 end;
3851 // Создание монстра:
3852 TRIGGER_SPAWNMONSTER:
3853 begin
3854 trigger.Data.MonType := MONSTER_ZOMBY;
3855 trigger.Data.MonPos.X := trigger.X-64;
3856 trigger.Data.MonPos.Y := trigger.Y-64;
3857 trigger.Data.MonHealth := 0;
3858 trigger.Data.MonActive := False;
3859 trigger.Data.MonCount := 1;
3860 end;
3862 // Создание предмета:
3863 TRIGGER_SPAWNITEM:
3864 begin
3865 trigger.Data.ItemType := ITEM_AMMO_BULLETS;
3866 trigger.Data.ItemPos.X := trigger.X-64;
3867 trigger.Data.ItemPos.Y := trigger.Y-64;
3868 trigger.Data.ItemOnlyDM := False;
3869 trigger.Data.ItemFalls := False;
3870 trigger.Data.ItemCount := 1;
3871 trigger.Data.ItemMax := 0;
3872 trigger.Data.ItemDelay := 0;
3873 end;
3875 // Ускорение:
3876 TRIGGER_PUSH:
3877 begin
3878 trigger.Data.PushAngle := 90;
3879 trigger.Data.PushForce := 10;
3880 trigger.Data.ResetVel := True;
3881 end;
3883 TRIGGER_SCORE:
3884 begin
3885 trigger.Data.ScoreCount := 1;
3886 trigger.Data.ScoreCon := True;
3887 trigger.Data.ScoreMsg := True;
3888 end;
3890 TRIGGER_MESSAGE:
3891 begin
3892 trigger.Data.MessageKind := 0;
3893 trigger.Data.MessageSendTo := 0;
3894 trigger.Data.MessageText := '';
3895 trigger.Data.MessageTime := 144;
3896 end;
3898 TRIGGER_DAMAGE:
3899 begin
3900 trigger.Data.DamageValue := 5;
3901 trigger.Data.DamageInterval := 12;
3902 end;
3904 TRIGGER_HEALTH:
3905 begin
3906 trigger.Data.HealValue := 5;
3907 trigger.Data.HealInterval := 36;
3908 end;
3910 TRIGGER_SHOT:
3911 begin
3912 trigger.Data.ShotType := TRIGGER_SHOT_BULLET;
3913 trigger.Data.ShotSound := True;
3914 trigger.Data.ShotPanelID := -1;
3915 trigger.Data.ShotTarget := 0;
3916 trigger.Data.ShotIntSight := 0;
3917 trigger.Data.ShotAim := TRIGGER_SHOT_AIM_DEFAULT;
3918 trigger.Data.ShotPos.X := trigger.X-64;
3919 trigger.Data.ShotPos.Y := trigger.Y-64;
3920 trigger.Data.ShotAngle := 0;
3921 trigger.Data.ShotWait := 18;
3922 trigger.Data.ShotAccuracy := 0;
3923 trigger.Data.ShotAmmo := 0;
3924 trigger.Data.ShotIntReload := 0;
3925 end;
3927 TRIGGER_EFFECT:
3928 begin
3929 trigger.Data.FXCount := 1;
3930 trigger.Data.FXType := TRIGGER_EFFECT_PARTICLE;
3931 trigger.Data.FXSubType := TRIGGER_EFFECT_SLIQUID;
3932 trigger.Data.FXColorR := 0;
3933 trigger.Data.FXColorG := 0;
3934 trigger.Data.FXColorB := 255;
3935 trigger.Data.FXPos := TRIGGER_EFFECT_POS_CENTER;
3936 trigger.Data.FXWait := 1;
3937 trigger.Data.FXVelX := 0;
3938 trigger.Data.FXVelY := -20;
3939 trigger.Data.FXSpreadL := 5;
3940 trigger.Data.FXSpreadR := 5;
3941 trigger.Data.FXSpreadU := 4;
3942 trigger.Data.FXSpreadD := 0;
3943 end;
3944 end;
3946 Undo_Add(OBJECT_TRIGGER, AddTrigger(trigger));
3947 end;
3949 // Рисовали область триггера "Расширитель":
3950 MOUSEACTION_DRAWPRESS:
3951 with gTriggers[SelectedObjects[GetFirstSelected].ID] do
3952 begin
3953 Data.tX := Min(MousePos.X-MapOffset.X, MouseLDownPos.X-MapOffset.X);
3954 Data.tY := Min(MousePos.Y-MapOffset.Y, MouseLDownPos.Y-MapOffset.Y);
3955 Data.tWidth := Abs(MousePos.X-MouseLDownPos.X);
3956 Data.tHeight := Abs(MousePos.Y-MouseLDownPos.Y);
3958 DrawPressRect := False;
3959 end;
3960 end;
3962 MouseAction := MOUSEACTION_NONE;
3963 end;
3964 end // if Button = mbLeft...
3965 else // Right Mouse Button:
3966 begin
3967 if MouseAction = MOUSEACTION_NOACTION then
3968 begin
3969 MouseAction := MOUSEACTION_NONE;
3970 Exit;
3971 end;
3973 // Объект передвинут или изменен в размере:
3974 if MouseAction in [MOUSEACTION_MOVEOBJ, MOUSEACTION_RESIZE] then
3975 begin
3976 MouseAction := MOUSEACTION_NONE;
3977 FillProperty();
3978 Exit;
3979 end;
3981 // Еще не все выбрали:
3982 if SelectFlag <> SELECTFLAG_NONE then
3983 begin
3984 if SelectFlag = SELECTFLAG_SELECTED then
3985 SelectFlag := SELECTFLAG_NONE;
3986 FillProperty();
3987 Exit;
3988 end;
3990 // Мышь сдвинулась во время удержания клавиши:
3991 if (MousePos.X <> MouseRDownPos.X) and
3992 (MousePos.Y <> MouseRDownPos.Y) then
3993 begin
3994 rSelectRect := True;
3996 rRect.X := Min(MousePos.X, MouseRDownPos.X)-MapOffset.X;
3997 rRect.Y := Min(MousePos.Y, MouseRDownPos.Y)-MapOffset.Y;
3998 rRect.Width := Abs(MousePos.X-MouseRDownPos.X);
3999 rRect.Height := Abs(MousePos.Y-MouseRDownPos.Y);
4000 end
4001 else // Мышь не сдвинулась - нет прямоугольника:
4002 begin
4003 rSelectRect := False;
4005 rRect.X := X-MapOffset.X-1;
4006 rRect.Y := Y-MapOffset.Y-1;
4007 rRect.Width := 2;
4008 rRect.Height := 2;
4009 end;
4011 // Если зажат Ctrl - выделять еще, иначе только один выделенный объект:
4012 if not (ssCtrl in Shift) then
4013 RemoveSelectFromObjects();
4015 // Выделяем всё в выбранном прямоугольнике:
4016 if (ssCtrl in Shift) and (ssAlt in Shift) then
4017 begin
4018 SelectObjects(OBJECT_PANEL);
4019 SelectObjects(OBJECT_ITEM);
4020 SelectObjects(OBJECT_MONSTER);
4021 SelectObjects(OBJECT_AREA);
4022 SelectObjects(OBJECT_TRIGGER);
4023 end
4024 else
4025 SelectObjects(pcObjects.ActivePageIndex+1);
4027 FillProperty();
4028 end;
4029 end;
4031 procedure TMainForm.RenderPanelPaint(Sender: TObject);
4032 begin
4033 Draw();
4034 end;
4036 function TMainForm.RenderMousePos(): Types.TPoint;
4037 begin
4038 Result := RenderPanel.ScreenToClient(Mouse.CursorPos);
4039 end;
4041 procedure TMainForm.RecountSelectedObjects();
4042 begin
4043 if SelectedObjectCount() = 0 then
4044 StatusBar.Panels[0].Text := ''
4045 else
4046 StatusBar.Panels[0].Text := Format(_lc[I_CAP_STAT_SELECTED], [SelectedObjectCount()]);
4047 end;
4049 procedure TMainForm.RenderPanelMouseMove(Sender: TObject;
4050 Shift: TShiftState; X, Y: Integer);
4051 var
4052 sX, sY: Integer;
4053 dWidth, dHeight: Integer;
4054 _id: Integer;
4055 TextureID: DWORD;
4056 wWidth, wHeight: Word;
4057 begin
4058 _id := GetFirstSelected();
4059 TextureID := 0;
4061 // Рисуем панель с текстурой, сетка - размеры текстуры:
4062 if (MouseAction = MOUSEACTION_DRAWPANEL) and
4063 (lbPanelType.ItemIndex in [0..8]) and
4064 (lbTextureList.ItemIndex <> -1) and
4065 (not IsSpecialTextureSel()) then
4066 begin
4067 sX := StrToIntDef(lTextureWidth.Caption, DotStep);
4068 sY := StrToIntDef(lTextureHeight.Caption, DotStep);
4069 end
4070 else
4071 // Меняем размер панели с текстурой, сетка - размеры текстуры:
4072 if (MouseAction = MOUSEACTION_RESIZE) and
4073 ( (SelectedObjects[_id].ObjectType = OBJECT_PANEL) and
4074 IsTexturedPanel(gPanels[SelectedObjects[_id].ID].PanelType) and
4075 (gPanels[SelectedObjects[_id].ID].TextureName <> '') and
4076 (not IsSpecialTexture(gPanels[SelectedObjects[_id].ID].TextureName)) ) then
4077 begin
4078 sX := gPanels[SelectedObjects[_id].ID].TextureWidth;
4079 sY := gPanels[SelectedObjects[_id].ID].TextureHeight;
4080 end
4081 else
4082 // Выравнивание по сетке:
4083 if SnapToGrid then
4084 begin
4085 sX := DotStep;
4086 sY := DotStep;
4087 end
4088 else // Нет выравнивания по сетке:
4089 begin
4090 sX := 1;
4091 sY := 1;
4092 end;
4094 // Новая позиция мыши:
4095 if MouseLDown then
4096 begin // Зажата левая кнопка мыши
4097 MousePos.X := (Round((X-MouseLDownPos.X)/sX)*sX)+MouseLDownPos.X;
4098 MousePos.Y := (Round((Y-MouseLDownPos.Y)/sY)*sY)+MouseLDownPos.Y;
4099 end
4100 else
4101 if MouseRDown then
4102 begin // Зажата правая кнопка мыши
4103 MousePos.X := (Round((X-MouseRDownPos.X)/sX)*sX)+MouseRDownPos.X;
4104 MousePos.Y := (Round((Y-MouseRDownPos.Y)/sY)*sY)+MouseRDownPos.Y;
4105 end
4106 else
4107 begin // Кнопки мыши не зажаты
4108 MousePos.X := Round((-MapOffset.X + X) / sX) * sX + MapOffset.X;
4109 MousePos.Y := Round((-MapOffset.Y + Y) / sY) * sY + MapOffset.Y;
4110 end;
4112 // Изменение размера закончилось - ставим обычный курсор:
4113 if ResizeType = RESIZETYPE_NONE then
4114 RenderPanel.Cursor := crDefault;
4116 // Зажата только правая кнопка мыши:
4117 if (not MouseLDown) and (MouseRDown) then
4118 begin
4119 // Рисуем прямоугольник выделения:
4120 if MouseAction = MOUSEACTION_NONE then
4121 begin
4122 if DrawRect = nil then
4123 New(DrawRect);
4124 DrawRect.Top := MouseRDownPos.y;
4125 DrawRect.Left := MouseRDownPos.x;
4126 DrawRect.Bottom := MousePos.y;
4127 DrawRect.Right := MousePos.x;
4128 end
4129 else
4130 // Двигаем выделенные объекты:
4131 if MouseAction = MOUSEACTION_MOVEOBJ then
4132 begin
4133 MoveSelectedObjects(ssShift in Shift, ssCtrl in Shift,
4134 MousePos.X-LastMovePoint.X,
4135 MousePos.Y-LastMovePoint.Y);
4136 end
4137 else
4138 // Меняем размер выделенного объекта:
4139 if MouseAction = MOUSEACTION_RESIZE then
4140 begin
4141 if (SelectedObjectCount = 1) and
4142 (SelectedObjects[GetFirstSelected].Live) then
4143 begin
4144 dWidth := MousePos.X-LastMovePoint.X;
4145 dHeight := MousePos.Y-LastMovePoint.Y;
4147 case ResizeType of
4148 RESIZETYPE_VERTICAL: dWidth := 0;
4149 RESIZETYPE_HORIZONTAL: dHeight := 0;
4150 end;
4152 case ResizeDirection of
4153 RESIZEDIR_UP: dHeight := -dHeight;
4154 RESIZEDIR_LEFT: dWidth := -dWidth;
4155 end;
4157 if ResizeObject(SelectedObjects[GetFirstSelected].ObjectType,
4158 SelectedObjects[GetFirstSelected].ID,
4159 dWidth, dHeight, ResizeDirection) then
4160 LastMovePoint := MousePos;
4161 end;
4162 end;
4163 end;
4165 // Зажата только левая кнопка мыши:
4166 if (not MouseRDown) and (MouseLDown) then
4167 begin
4168 // Рисуем прямоугольник планирования панели:
4169 if MouseAction in [MOUSEACTION_DRAWPANEL,
4170 MOUSEACTION_DRAWTRIGGER,
4171 MOUSEACTION_DRAWPRESS] then
4172 begin
4173 if DrawRect = nil then
4174 New(DrawRect);
4175 if ssCtrl in Shift then
4176 begin
4177 wWidth := DotStep;
4178 wHeight := DotStep;
4179 if (lbTextureList.ItemIndex <> -1) and (not IsSpecialTextureSel()) and
4180 (MouseAction = MOUSEACTION_DRAWPANEL) then
4181 begin
4182 if not g_GetTexture(SelectedTexture(), TextureID) then
4183 g_GetTexture('NOTEXTURE', TextureID);
4184 g_GetTextureSizeByID(TextureID, wWidth, wHeight);
4185 end;
4186 DrawRect.Top := MouseLDownPos.y;
4187 DrawRect.Left := MouseLDownPos.x;
4188 DrawRect.Bottom := DrawRect.Top + wHeight;
4189 DrawRect.Right := DrawRect.Left + wWidth;
4190 end
4191 else
4192 begin
4193 DrawRect.Top := MouseLDownPos.y;
4194 DrawRect.Left := MouseLDownPos.x;
4195 DrawRect.Bottom := MousePos.y;
4196 DrawRect.Right := MousePos.x;
4197 end;
4198 end
4199 else // Двигаем карту:
4200 if MouseAction = MOUSEACTION_MOVEMAP then
4201 begin
4202 MoveMap(X, Y);
4203 end;
4204 end;
4206 // Клавиши мыши не зажаты:
4207 if (not MouseRDown) and (not MouseLDown) then
4208 DrawRect := nil;
4210 // Строка состояния - координаты мыши:
4211 StatusBar.Panels[1].Text := Format('(%d:%d)',
4212 [MousePos.X-MapOffset.X, MousePos.Y-MapOffset.Y]);
4213 end;
4215 procedure TMainForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
4216 begin
4217 CanClose := MessageBox(0, PChar(_lc[I_MSG_EXIT_PROMT]),
4218 PChar(_lc[I_MSG_EXIT]),
4219 MB_ICONQUESTION or MB_YESNO or
4220 MB_DEFBUTTON1) = idYes;
4221 end;
4223 procedure TMainForm.aExitExecute(Sender: TObject);
4224 begin
4225 Close();
4226 end;
4228 procedure TMainForm.FormDestroy(Sender: TObject);
4229 var
4230 config: TConfig;
4231 i: Integer;
4232 begin
4233 config := TConfig.CreateFile(EditorDir+'Editor.cfg');
4235 if WindowState <> wsMaximized then
4236 begin
4237 config.WriteInt('Editor', 'XPos', Left);
4238 config.WriteInt('Editor', 'YPos', Top);
4239 config.WriteInt('Editor', 'Width', Width);
4240 config.WriteInt('Editor', 'Height', Height);
4241 end
4242 else
4243 begin
4244 config.WriteInt('Editor', 'XPos', RestoredLeft);
4245 config.WriteInt('Editor', 'YPos', RestoredTop);
4246 config.WriteInt('Editor', 'Width', RestoredWidth);
4247 config.WriteInt('Editor', 'Height', RestoredHeight);
4248 end;
4249 config.WriteBool('Editor', 'Maximize', WindowState = wsMaximized);
4250 config.WriteBool('Editor', 'Minimap', ShowMap);
4251 config.WriteInt('Editor', 'PanelProps', PanelProps.ClientWidth);
4252 config.WriteInt('Editor', 'PanelObjs', PanelObjs.ClientHeight);
4253 config.WriteBool('Editor', 'DotEnable', DotEnable);
4254 config.WriteInt('Editor', 'DotStep', DotStep);
4255 config.WriteStr('Editor', 'LastOpenDir', OpenDialog.InitialDir);
4256 config.WriteStr('Editor', 'LastSaveDir', SaveDialog.InitialDir);
4257 config.WriteBool('Editor', 'EdgeShow', drEdge[3] < 255);
4258 config.WriteInt('Editor', 'EdgeColor', gColorEdge);
4259 config.WriteInt('Editor', 'EdgeAlpha', gAlphaEdge);
4260 config.WriteInt('Editor', 'LineAlpha', gAlphaTriggerLine);
4261 config.WriteInt('Editor', 'TriggerAlpha', gAlphaTriggerArea);
4262 config.WriteInt('Editor', 'MonsterRectAlpha', gAlphaMonsterRect);
4263 config.WriteInt('Editor', 'AreaRectAlpha', gAlphaAreaRect);
4265 for i := 0 to RecentCount-1 do
4266 if i < RecentFiles.Count then
4267 config.WriteStr('RecentFiles', IntToStr(i+1), RecentFiles[i])
4268 else
4269 config.WriteStr('RecentFiles', IntToStr(i+1), '');
4270 RecentFiles.Free();
4272 config.SaveFile(EditorDir+'Editor.cfg');
4273 config.Free();
4275 slInvalidTextures.Free;
4276 end;
4278 procedure TMainForm.FormDropFiles(Sender: TObject;
4279 const FileNames: array of String);
4280 begin
4281 if Length(FileNames) <> 1 then
4282 Exit;
4284 OpenMapFile(FileNames[0]);
4285 end;
4287 procedure TMainForm.RenderPanelResize(Sender: TObject);
4288 begin
4289 if MainForm.Visible then
4290 MainForm.Resize();
4291 end;
4293 procedure TMainForm.Splitter1Moved(Sender: TObject);
4294 begin
4295 FormResize(Sender);
4296 end;
4298 procedure TMainForm.aMapOptionsExecute(Sender: TObject);
4299 var
4300 ResName: String;
4301 begin
4302 MapOptionsForm.ShowModal();
4304 ResName := OpenedMap;
4305 while (Pos(':\', ResName) > 0) do
4306 Delete(ResName, 1, Pos(':\', ResName) + 1);
4308 UpdateCaption(gMapInfo.Name, ExtractFileName(OpenedWAD), ResName);
4309 end;
4311 procedure TMainForm.aAboutExecute(Sender: TObject);
4312 begin
4313 AboutForm.ShowModal();
4314 end;
4316 procedure TMainForm.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
4317 var
4318 dx, dy, i: Integer;
4319 FileName: String;
4320 ok: Boolean;
4321 begin
4322 if (not EditingProperties) then
4323 begin
4324 if ssCtrl in Shift then
4325 begin
4326 case Chr(Key) of
4327 '1': ContourEnabled[LAYER_BACK] := not ContourEnabled[LAYER_BACK];
4328 '2': ContourEnabled[LAYER_WALLS] := not ContourEnabled[LAYER_WALLS];
4329 '3': ContourEnabled[LAYER_FOREGROUND] := not ContourEnabled[LAYER_FOREGROUND];
4330 '4': ContourEnabled[LAYER_STEPS] := not ContourEnabled[LAYER_STEPS];
4331 '5': ContourEnabled[LAYER_WATER] := not ContourEnabled[LAYER_WATER];
4332 '6': ContourEnabled[LAYER_ITEMS] := not ContourEnabled[LAYER_ITEMS];
4333 '7': ContourEnabled[LAYER_MONSTERS] := not ContourEnabled[LAYER_MONSTERS];
4334 '8': ContourEnabled[LAYER_AREAS] := not ContourEnabled[LAYER_AREAS];
4335 '9': ContourEnabled[LAYER_TRIGGERS] := not ContourEnabled[LAYER_TRIGGERS];
4336 '0':
4337 begin
4338 ok := False;
4339 for i := Low(ContourEnabled) to High(ContourEnabled) do
4340 if ContourEnabled[i] then
4341 ok := True;
4342 for i := Low(ContourEnabled) to High(ContourEnabled) do
4343 ContourEnabled[i] := not ok
4344 end
4345 end
4346 end
4347 else
4348 begin
4349 case Chr(key) of
4350 '1': SwitchLayer(LAYER_BACK);
4351 '2': SwitchLayer(LAYER_WALLS);
4352 '3': SwitchLayer(LAYER_FOREGROUND);
4353 '4': SwitchLayer(LAYER_STEPS);
4354 '5': SwitchLayer(LAYER_WATER);
4355 '6': SwitchLayer(LAYER_ITEMS);
4356 '7': SwitchLayer(LAYER_MONSTERS);
4357 '8': SwitchLayer(LAYER_AREAS);
4358 '9': SwitchLayer(LAYER_TRIGGERS);
4359 '0': tbShowClick(tbShow);
4360 end
4361 end;
4363 if Key = Ord('V') then
4364 begin // Поворот монстров и областей:
4365 if (SelectedObjects <> nil) then
4366 begin
4367 for i := 0 to High(SelectedObjects) do
4368 if (SelectedObjects[i].Live) then
4369 begin
4370 if (SelectedObjects[i].ObjectType = OBJECT_MONSTER) then
4371 begin
4372 g_ChangeDir(gMonsters[SelectedObjects[i].ID].Direction);
4373 end
4374 else
4375 if (SelectedObjects[i].ObjectType = OBJECT_AREA) then
4376 begin
4377 g_ChangeDir(gAreas[SelectedObjects[i].ID].Direction);
4378 end;
4379 end;
4380 end
4381 else
4382 begin
4383 if pcObjects.ActivePage = tsMonsters then
4384 begin
4385 if rbMonsterLeft.Checked then
4386 rbMonsterRight.Checked := True
4387 else
4388 rbMonsterLeft.Checked := True;
4389 end;
4390 if pcObjects.ActivePage = tsAreas then
4391 begin
4392 if rbAreaLeft.Checked then
4393 rbAreaRight.Checked := True
4394 else
4395 rbAreaLeft.Checked := True;
4396 end;
4397 end;
4398 end;
4400 if not (ssCtrl in Shift) then
4401 begin
4402 // Быстрое превью карты:
4403 if Key = Ord('E') then
4404 begin
4405 if PreviewMode = 0 then
4406 PreviewMode := 2;
4407 end;
4409 // Вертикальный скролл карты:
4410 with sbVertical do
4411 begin
4412 if Key = Ord('W') then
4413 begin
4414 dy := Position;
4415 if ssShift in Shift then Position := EnsureRange(Position - DotStep * 4, Min, Max)
4416 else Position := EnsureRange(Position - DotStep, Min, Max);
4417 MapOffset.Y := -Position;
4418 dy -= Position;
4420 if (MouseLDown or MouseRDown) then
4421 begin
4422 if DrawRect <> nil then
4423 begin
4424 Inc(MouseLDownPos.y, dy);
4425 Inc(MouseRDownPos.y, dy);
4426 end;
4427 Inc(LastMovePoint.Y, dy);
4428 RenderPanelMouseMove(Sender, Shift, RenderMousePos().X, RenderMousePos().Y);
4429 end;
4430 end;
4432 if Key = Ord('S') then
4433 begin
4434 dy := Position;
4435 if ssShift in Shift then Position := EnsureRange(Position + DotStep * 4, Min, Max)
4436 else Position := EnsureRange(Position + DotStep, Min, Max);
4437 MapOffset.Y := -Position;
4438 dy -= Position;
4440 if (MouseLDown or MouseRDown) then
4441 begin
4442 if DrawRect <> nil then
4443 begin
4444 Inc(MouseLDownPos.y, dy);
4445 Inc(MouseRDownPos.y, dy);
4446 end;
4447 Inc(LastMovePoint.Y, dy);
4448 RenderPanelMouseMove(Sender, Shift, RenderMousePos().X, RenderMousePos().Y);
4449 end;
4450 end;
4451 end;
4453 // Горизонтальный скролл карты:
4454 with sbHorizontal do
4455 begin
4456 if Key = Ord('A') then
4457 begin
4458 dx := Position;
4459 if ssShift in Shift then Position := EnsureRange(Position - DotStep * 4, Min, Max)
4460 else Position := EnsureRange(Position - DotStep, Min, Max);
4461 MapOffset.X := -Position;
4462 dx -= Position;
4464 if (MouseLDown or MouseRDown) then
4465 begin
4466 if DrawRect <> nil then
4467 begin
4468 Inc(MouseLDownPos.x, dx);
4469 Inc(MouseRDownPos.x, dx);
4470 end;
4471 Inc(LastMovePoint.X, dx);
4472 RenderPanelMouseMove(Sender, Shift, RenderMousePos().X, RenderMousePos().Y);
4473 end;
4474 end;
4476 if Key = Ord('D') then
4477 begin
4478 dx := Position;
4479 if ssShift in Shift then Position := EnsureRange(Position + DotStep * 4, Min, Max)
4480 else Position := EnsureRange(Position + DotStep, Min, Max);
4481 MapOffset.X := -Position;
4482 dx -= Position;
4484 if (MouseLDown or MouseRDown) then
4485 begin
4486 if DrawRect <> nil then
4487 begin
4488 Inc(MouseLDownPos.x, dx);
4489 Inc(MouseRDownPos.x, dx);
4490 end;
4491 Inc(LastMovePoint.X, dx);
4492 RenderPanelMouseMove(Sender, Shift, RenderMousePos().X, RenderMousePos().Y);
4493 end;
4494 end;
4495 end;
4496 end
4497 else // ssCtrl in Shift
4498 begin
4499 if ssShift in Shift then
4500 begin
4501 // Вставка по абсолютному смещению:
4502 if Key = Ord('V') then
4503 aPasteObjectExecute(Sender);
4504 end;
4505 RenderPanelMouseMove(Sender, Shift, RenderMousePos().X, RenderMousePos().Y);
4506 end;
4507 end;
4509 // Удалить выделенные объекты:
4510 if (Key = VK_DELETE) and (SelectedObjects <> nil) and
4511 RenderPanel.Focused() then
4512 DeleteSelectedObjects();
4514 // Снять выделение:
4515 if (Key = VK_ESCAPE) and (SelectedObjects <> nil) then
4516 RemoveSelectFromObjects();
4518 // Передвинуть объекты:
4519 if MainForm.ActiveControl = RenderPanel then
4520 begin
4521 dx := 0;
4522 dy := 0;
4524 if Key = VK_NUMPAD4 then
4525 dx := IfThen(ssAlt in Shift, -1, -DotStep);
4526 if Key = VK_NUMPAD6 then
4527 dx := IfThen(ssAlt in Shift, 1, DotStep);
4528 if Key = VK_NUMPAD8 then
4529 dy := IfThen(ssAlt in Shift, -1, -DotStep);
4530 if Key = VK_NUMPAD5 then
4531 dy := IfThen(ssAlt in Shift, 1, DotStep);
4533 if (dx <> 0) or (dy <> 0) then
4534 begin
4535 MoveSelectedObjects(ssShift in Shift, ssCtrl in Shift, dx, dy);
4536 Key := 0;
4537 end;
4538 end;
4540 if ssCtrl in Shift then
4541 begin
4542 // Выбор панели с текстурой для триггера
4543 if Key = Ord('T') then
4544 begin
4545 DrawPressRect := False;
4546 if SelectFlag = SELECTFLAG_TEXTURE then
4547 begin
4548 SelectFlag := SELECTFLAG_NONE;
4549 Exit;
4550 end;
4551 vleObjectProperty.FindRow(_lc[I_PROP_TR_TEXTURE_PANEL], i);
4552 if i > 0 then
4553 SelectFlag := SELECTFLAG_TEXTURE;
4554 end;
4556 if Key = Ord('D') then
4557 begin
4558 SelectFlag := SELECTFLAG_NONE;
4559 if DrawPressRect then
4560 begin
4561 DrawPressRect := False;
4562 Exit;
4563 end;
4564 i := -1;
4566 // Выбор области воздействия, в зависимости от типа триггера
4567 vleObjectProperty.FindRow(_lc[I_PROP_TR_EX_AREA], i);
4568 if i > 0 then
4569 begin
4570 DrawPressRect := True;
4571 Exit;
4572 end;
4573 vleObjectProperty.FindRow(_lc[I_PROP_TR_DOOR_PANEL], i);
4574 if i <= 0 then
4575 vleObjectProperty.FindRow(_lc[I_PROP_TR_TRAP_PANEL], i);
4576 if i > 0 then
4577 begin
4578 SelectFlag := SELECTFLAG_DOOR;
4579 Exit;
4580 end;
4581 vleObjectProperty.FindRow(_lc[I_PROP_TR_LIFT_PANEL], i);
4582 if i > 0 then
4583 begin
4584 SelectFlag := SELECTFLAG_LIFT;
4585 Exit;
4586 end;
4587 vleObjectProperty.FindRow(_lc[I_PROP_TR_TELEPORT_TO], i);
4588 if i > 0 then
4589 begin
4590 SelectFlag := SELECTFLAG_TELEPORT;
4591 Exit;
4592 end;
4593 vleObjectProperty.FindRow(_lc[I_PROP_TR_SPAWN_TO], i);
4594 if i > 0 then
4595 begin
4596 SelectFlag := SELECTFLAG_SPAWNPOINT;
4597 Exit;
4598 end;
4600 // Выбор основного параметра, в зависимости от типа триггера
4601 vleObjectProperty.FindRow(_lc[I_PROP_TR_NEXT_MAP], i);
4602 if i > 0 then
4603 begin
4604 g_ProcessResourceStr(OpenedMap, @FileName, nil, nil);
4605 SelectMapForm.Caption := _lc[I_CAP_SELECT];
4606 SelectMapForm.GetMaps(FileName);
4608 if SelectMapForm.ShowModal() = mrOK then
4609 begin
4610 vleObjectProperty.Cells[1, i] := SelectMapForm.lbMapList.Items[SelectMapForm.lbMapList.ItemIndex];
4611 bApplyProperty.Click();
4612 end;
4613 Exit;
4614 end;
4615 vleObjectProperty.FindRow(_lc[I_PROP_TR_SOUND_NAME], i);
4616 if i <= 0 then
4617 vleObjectProperty.FindRow(_lc[I_PROP_TR_MUSIC_NAME], i);
4618 if i > 0 then
4619 begin
4620 AddSoundForm.OKFunction := nil;
4621 AddSoundForm.lbResourcesList.MultiSelect := False;
4622 AddSoundForm.SetResource := vleObjectProperty.Cells[1, i];
4624 if (AddSoundForm.ShowModal() = mrOk) then
4625 begin
4626 vleObjectProperty.Cells[1, i] := AddSoundForm.ResourceName;
4627 bApplyProperty.Click();
4628 end;
4629 Exit;
4630 end;
4631 vleObjectProperty.FindRow(_lc[I_PROP_TR_PUSH_ANGLE], i);
4632 if i <= 0 then
4633 vleObjectProperty.FindRow(_lc[I_PROP_TR_MESSAGE_TEXT], i);
4634 if i > 0 then
4635 begin
4636 vleObjectProperty.Row := i;
4637 vleObjectProperty.SetFocus();
4638 Exit;
4639 end;
4640 end;
4641 end;
4642 end;
4644 procedure TMainForm.aOptimizeExecute(Sender: TObject);
4645 begin
4646 RemoveSelectFromObjects();
4647 MapOptimizationForm.ShowModal();
4648 end;
4650 procedure TMainForm.aCheckMapExecute(Sender: TObject);
4651 begin
4652 MapCheckForm.ShowModal();
4653 end;
4655 procedure TMainForm.bbAddTextureClick(Sender: TObject);
4656 begin
4657 AddTextureForm.lbResourcesList.MultiSelect := True;
4658 AddTextureForm.ShowModal();
4659 end;
4661 procedure TMainForm.lbTextureListClick(Sender: TObject);
4662 var
4663 TextureID: DWORD;
4664 TextureWidth, TextureHeight: Word;
4665 begin
4666 TextureID := 0;
4667 TextureWidth := 0;
4668 TextureHeight := 0;
4669 if (lbTextureList.ItemIndex <> -1) and
4670 (not IsSpecialTextureSel()) then
4671 begin
4672 if g_GetTexture(SelectedTexture(), TextureID) then
4673 begin
4674 g_GetTextureSizeByID(TextureID, TextureWidth, TextureHeight);
4676 lTextureWidth.Caption := IntToStr(TextureWidth);
4677 lTextureHeight.Caption := IntToStr(TextureHeight);
4678 end else
4679 begin
4680 lTextureWidth.Caption := _lc[I_NOT_ACCESSIBLE];
4681 lTextureHeight.Caption := _lc[I_NOT_ACCESSIBLE];
4682 end;
4683 end
4684 else
4685 begin
4686 lTextureWidth.Caption := '';
4687 lTextureHeight.Caption := '';
4688 end;
4689 end;
4691 procedure TMainForm.lbTextureListDrawItem(Control: TWinControl; Index: Integer;
4692 ARect: TRect; State: TOwnerDrawState);
4693 begin
4694 with Control as TListBox do
4695 begin
4696 if LCLType.odSelected in State then
4697 begin
4698 Canvas.Brush.Color := clHighlight;
4699 Canvas.Font.Color := clHighlightText;
4700 end else
4701 if (Items <> nil) and (Index >= 0) then
4702 if slInvalidTextures.IndexOf(Items[Index]) > -1 then
4703 begin
4704 Canvas.Brush.Color := clRed;
4705 Canvas.Font.Color := clWhite;
4706 end;
4707 Canvas.FillRect(ARect);
4708 Canvas.TextRect(ARect, ARect.Left, ARect.Top, Items[Index]);
4709 end;
4710 end;
4712 procedure TMainForm.miReopenMapClick(Sender: TObject);
4713 var
4714 FileName, Resource: String;
4715 begin
4716 if OpenedMap = '' then
4717 Exit;
4719 if MessageBox(0, PChar(_lc[I_MSG_REOPEN_MAP_PROMT]),
4720 PChar(_lc[I_MENU_FILE_REOPEN]), MB_ICONQUESTION or MB_YESNO) <> idYes then
4721 Exit;
4723 g_ProcessResourceStr(OpenedMap, @FileName, nil, @Resource);
4724 OpenMap(FileName, Resource);
4725 end;
4727 procedure TMainForm.vleObjectPropertyGetPickList(Sender: TObject;
4728 const KeyName: String; Values: TStrings);
4729 begin
4730 if vleObjectProperty.ItemProps[KeyName].EditStyle = esPickList then
4731 begin
4732 if KeyName = _lc[I_PROP_DIRECTION] then
4733 begin
4734 Values.Add(DirNames[D_LEFT]);
4735 Values.Add(DirNames[D_RIGHT]);
4736 end
4737 else if KeyName = _lc[I_PROP_TR_TELEPORT_DIR] then
4738 begin
4739 Values.Add(DirNamesAdv[0]);
4740 Values.Add(DirNamesAdv[1]);
4741 Values.Add(DirNamesAdv[2]);
4742 Values.Add(DirNamesAdv[3]);
4743 end
4744 else if KeyName = _lc[I_PROP_TR_MUSIC_ACT] then
4745 begin
4746 Values.Add(_lc[I_PROP_TR_MUSIC_ON]);
4747 Values.Add(_lc[I_PROP_TR_MUSIC_OFF]);
4748 end
4749 else if KeyName = _lc[I_PROP_TR_MONSTER_BEHAVIOUR] then
4750 begin
4751 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_0]);
4752 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_1]);
4753 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_2]);
4754 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_3]);
4755 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_4]);
4756 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_5]);
4757 end
4758 else if KeyName = _lc[I_PROP_TR_SCORE_ACT] then
4759 begin
4760 Values.Add(_lc[I_PROP_TR_SCORE_ACT_0]);
4761 Values.Add(_lc[I_PROP_TR_SCORE_ACT_1]);
4762 Values.Add(_lc[I_PROP_TR_SCORE_ACT_2]);
4763 Values.Add(_lc[I_PROP_TR_SCORE_ACT_3]);
4764 end
4765 else if KeyName = _lc[I_PROP_TR_SCORE_TEAM] then
4766 begin
4767 Values.Add(_lc[I_PROP_TR_SCORE_TEAM_0]);
4768 Values.Add(_lc[I_PROP_TR_SCORE_TEAM_1]);
4769 Values.Add(_lc[I_PROP_TR_SCORE_TEAM_2]);
4770 Values.Add(_lc[I_PROP_TR_SCORE_TEAM_3]);
4771 end
4772 else if KeyName = _lc[I_PROP_TR_MESSAGE_KIND] then
4773 begin
4774 Values.Add(_lc[I_PROP_TR_MESSAGE_KIND_0]);
4775 Values.Add(_lc[I_PROP_TR_MESSAGE_KIND_1]);
4776 end
4777 else if KeyName = _lc[I_PROP_TR_MESSAGE_TO] then
4778 begin
4779 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_0]);
4780 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_1]);
4781 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_2]);
4782 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_3]);
4783 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_4]);
4784 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_5]);
4785 end
4786 else if KeyName = _lc[I_PROP_TR_SHOT_TO] then
4787 begin
4788 Values.Add(_lc[I_PROP_TR_SHOT_TO_0]);
4789 Values.Add(_lc[I_PROP_TR_SHOT_TO_1]);
4790 Values.Add(_lc[I_PROP_TR_SHOT_TO_2]);
4791 Values.Add(_lc[I_PROP_TR_SHOT_TO_3]);
4792 Values.Add(_lc[I_PROP_TR_SHOT_TO_4]);
4793 Values.Add(_lc[I_PROP_TR_SHOT_TO_5]);
4794 Values.Add(_lc[I_PROP_TR_SHOT_TO_6]);
4795 end
4796 else if KeyName = _lc[I_PROP_TR_SHOT_AIM] then
4797 begin
4798 Values.Add(_lc[I_PROP_TR_SHOT_AIM_0]);
4799 Values.Add(_lc[I_PROP_TR_SHOT_AIM_1]);
4800 Values.Add(_lc[I_PROP_TR_SHOT_AIM_2]);
4801 Values.Add(_lc[I_PROP_TR_SHOT_AIM_3]);
4802 end
4803 else if KeyName = _lc[I_PROP_TR_DAMAGE_KIND] then
4804 begin
4805 Values.Add(_lc[I_PROP_TR_DAMAGE_KIND_0]);
4806 Values.Add(_lc[I_PROP_TR_DAMAGE_KIND_3]);
4807 Values.Add(_lc[I_PROP_TR_DAMAGE_KIND_4]);
4808 Values.Add(_lc[I_PROP_TR_DAMAGE_KIND_5]);
4809 Values.Add(_lc[I_PROP_TR_DAMAGE_KIND_6]);
4810 Values.Add(_lc[I_PROP_TR_DAMAGE_KIND_7]);
4811 Values.Add(_lc[I_PROP_TR_DAMAGE_KIND_8]);
4812 end
4813 else if (KeyName = _lc[I_PROP_PANEL_BLEND]) or
4814 (KeyName = _lc[I_PROP_DM_ONLY]) or
4815 (KeyName = _lc[I_PROP_ITEM_FALLS]) or
4816 (KeyName = _lc[I_PROP_TR_ENABLED]) or
4817 (KeyName = _lc[I_PROP_TR_D2D]) or
4818 (KeyName = _lc[I_PROP_TR_SILENT]) or
4819 (KeyName = _lc[I_PROP_TR_TELEPORT_SILENT]) or
4820 (KeyName = _lc[I_PROP_TR_EX_RANDOM]) or
4821 (KeyName = _lc[I_PROP_TR_TEXTURE_ONCE]) or
4822 (KeyName = _lc[I_PROP_TR_TEXTURE_ANIM_ONCE]) or
4823 (KeyName = _lc[I_PROP_TR_SOUND_LOCAL]) or
4824 (KeyName = _lc[I_PROP_TR_SOUND_SWITCH]) or
4825 (KeyName = _lc[I_PROP_TR_MONSTER_ACTIVE]) or
4826 (KeyName = _lc[I_PROP_TR_PUSH_RESET]) or
4827 (KeyName = _lc[I_PROP_TR_SCORE_CON]) or
4828 (KeyName = _lc[I_PROP_TR_SCORE_MSG]) or
4829 (KeyName = _lc[I_PROP_TR_HEALTH_MAX]) or
4830 (KeyName = _lc[I_PROP_TR_SHOT_SOUND]) or
4831 (KeyName = _lc[I_PROP_TR_EFFECT_CENTER]) then
4832 begin
4833 Values.Add(BoolNames[True]);
4834 Values.Add(BoolNames[False]);
4835 end;
4836 end;
4837 end;
4839 procedure TMainForm.bApplyPropertyClick(Sender: TObject);
4840 var
4841 _id, a, r, c: Integer;
4842 s: String;
4843 res: Boolean;
4844 NoTextureID: DWORD;
4845 NW, NH: Word;
4846 begin
4847 NoTextureID := 0;
4848 NW := 0;
4849 NH := 0;
4851 if SelectedObjectCount() <> 1 then
4852 Exit;
4853 if not SelectedObjects[GetFirstSelected()].Live then
4854 Exit;
4856 try
4857 if not CheckProperty() then
4858 Exit;
4859 except
4860 Exit;
4861 end;
4863 _id := GetFirstSelected();
4865 r := vleObjectProperty.Row;
4866 c := vleObjectProperty.Col;
4868 case SelectedObjects[_id].ObjectType of
4869 OBJECT_PANEL:
4870 begin
4871 with gPanels[SelectedObjects[_id].ID] do
4872 begin
4873 X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
4874 Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
4875 Width := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_WIDTH]]));
4876 Height := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_HEIGHT]]));
4878 PanelType := GetPanelType(vleObjectProperty.Values[_lc[I_PROP_PANEL_TYPE]]);
4880 // Сброс ссылки на триггеры смены текстуры:
4881 if not WordBool(PanelType and (PANEL_WALL or PANEL_FORE or PANEL_BACK)) then
4882 if gTriggers <> nil then
4883 for a := 0 to High(gTriggers) do
4884 begin
4885 if (gTriggers[a].TriggerType <> 0) and
4886 (gTriggers[a].TexturePanel = Integer(SelectedObjects[_id].ID)) then
4887 gTriggers[a].TexturePanel := -1;
4888 if (gTriggers[a].TriggerType = TRIGGER_SHOT) and
4889 (gTriggers[a].Data.ShotPanelID = Integer(SelectedObjects[_id].ID)) then
4890 gTriggers[a].Data.ShotPanelID := -1;
4891 end;
4893 // Сброс ссылки на триггеры лифта:
4894 if not WordBool(PanelType and (PANEL_LIFTUP or PANEL_LIFTDOWN or PANEL_LIFTLEFT or PANEL_LIFTRIGHT)) then
4895 if gTriggers <> nil then
4896 for a := 0 to High(gTriggers) do
4897 if (gTriggers[a].TriggerType in [TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT]) and
4898 (gTriggers[a].Data.PanelID = Integer(SelectedObjects[_id].ID)) then
4899 gTriggers[a].Data.PanelID := -1;
4901 // Сброс ссылки на триггеры двери:
4902 if not WordBool(PanelType and (PANEL_OPENDOOR or PANEL_CLOSEDOOR)) then
4903 if gTriggers <> nil then
4904 for a := 0 to High(gTriggers) do
4905 if (gTriggers[a].TriggerType in [TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
4906 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP]) and
4907 (gTriggers[a].Data.PanelID = Integer(SelectedObjects[_id].ID)) then
4908 gTriggers[a].Data.PanelID := -1;
4910 if IsTexturedPanel(PanelType) then
4911 begin // Может быть текстура
4912 if TextureName <> '' then
4913 begin // Была текстура
4914 Alpha := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_PANEL_ALPHA]]));
4915 Blending := NameToBool(vleObjectProperty.Values[_lc[I_PROP_PANEL_BLEND]]);
4916 end
4917 else // Не было
4918 begin
4919 Alpha := 0;
4920 Blending := False;
4921 end;
4923 // Новая текстура:
4924 TextureName := vleObjectProperty.Values[_lc[I_PROP_PANEL_TEX]];
4926 if TextureName <> '' then
4927 begin // Есть текстура
4928 // Обычная текстура:
4929 if not IsSpecialTexture(TextureName) then
4930 begin
4931 g_GetTextureSizeByName(TextureName,
4932 TextureWidth, TextureHeight);
4934 // Проверка кратности размеров панели:
4935 res := True;
4936 if TextureWidth <> 0 then
4937 if gPanels[SelectedObjects[_id].ID].Width mod TextureWidth <> 0 then
4938 begin
4939 ErrorMessageBox(Format(_lc[I_MSG_WRONG_TEXWIDTH],
4940 [TextureWidth]));
4941 Res := False;
4942 end;
4943 if Res and (TextureHeight <> 0) then
4944 if gPanels[SelectedObjects[_id].ID].Height mod TextureHeight <> 0 then
4945 begin
4946 ErrorMessageBox(Format(_lc[I_MSG_WRONG_TEXHEIGHT],
4947 [TextureHeight]));
4948 Res := False;
4949 end;
4951 if Res then
4952 begin
4953 if not g_GetTexture(TextureName, TextureID) then
4954 // Не удалось загрузить текстуру, рисуем NOTEXTURE
4955 if g_GetTexture('NOTEXTURE', NoTextureID) then
4956 begin
4957 TextureID := TEXTURE_SPECIAL_NOTEXTURE;
4958 g_GetTextureSizeByID(NoTextureID, NW, NH);
4959 TextureWidth := NW;
4960 TextureHeight := NH;
4961 end else
4962 begin
4963 TextureID := TEXTURE_SPECIAL_NONE;
4964 TextureWidth := 1;
4965 TextureHeight := 1;
4966 end;
4967 end
4968 else
4969 begin
4970 TextureName := '';
4971 TextureWidth := 1;
4972 TextureHeight := 1;
4973 TextureID := TEXTURE_SPECIAL_NONE;
4974 end;
4975 end
4976 else // Спец.текстура
4977 begin
4978 TextureHeight := 1;
4979 TextureWidth := 1;
4980 TextureID := SpecialTextureID(TextureName);
4981 end;
4982 end
4983 else // Нет текстуры
4984 begin
4985 TextureWidth := 1;
4986 TextureHeight := 1;
4987 TextureID := TEXTURE_SPECIAL_NONE;
4988 end;
4989 end
4990 else // Не может быть текстуры
4991 begin
4992 Alpha := 0;
4993 Blending := False;
4994 TextureName := '';
4995 TextureWidth := 1;
4996 TextureHeight := 1;
4997 TextureID := TEXTURE_SPECIAL_NONE;
4998 end;
4999 end;
5000 end;
5002 OBJECT_ITEM:
5003 begin
5004 with gItems[SelectedObjects[_id].ID] do
5005 begin
5006 X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
5007 Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
5008 OnlyDM := NameToBool(vleObjectProperty.Values[_lc[I_PROP_DM_ONLY]]);
5009 Fall := NameToBool(vleObjectProperty.Values[_lc[I_PROP_ITEM_FALLS]]);
5010 end;
5011 end;
5013 OBJECT_MONSTER:
5014 begin
5015 with gMonsters[SelectedObjects[_id].ID] do
5016 begin
5017 X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
5018 Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
5019 Direction := NameToDir(vleObjectProperty.Values[_lc[I_PROP_DIRECTION]]);
5020 end;
5021 end;
5023 OBJECT_AREA:
5024 begin
5025 with gAreas[SelectedObjects[_id].ID] do
5026 begin
5027 X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
5028 Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
5029 Direction := NameToDir(vleObjectProperty.Values[_lc[I_PROP_DIRECTION]]);
5030 end;
5031 end;
5033 OBJECT_TRIGGER:
5034 begin
5035 with gTriggers[SelectedObjects[_id].ID] do
5036 begin
5037 X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
5038 Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
5039 Width := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_WIDTH]]));
5040 Height := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_HEIGHT]]));
5041 Enabled := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_ENABLED]]);
5042 ActivateType := StrToActivate(vleObjectProperty.Values[_lc[I_PROP_TR_ACTIVATION]]);
5043 Key := StrToKey(vleObjectProperty.Values[_lc[I_PROP_TR_KEYS]]);
5045 case TriggerType of
5046 TRIGGER_EXIT:
5047 begin
5048 s := utf2win(vleObjectProperty.Values[_lc[I_PROP_TR_NEXT_MAP]]);
5049 FillByte(Data.MapName[0], 16, 0);
5050 if s <> '' then
5051 Move(s[1], Data.MapName[0], Min(Length(s), 16));
5052 end;
5054 TRIGGER_TEXTURE:
5055 begin
5056 Data.ActivateOnce := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_TEXTURE_ONCE]]);
5057 Data.AnimOnce := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_TEXTURE_ANIM_ONCE]]);
5058 end;
5060 TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF:
5061 begin
5062 Data.Wait := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EX_DELAY]], 0), 65535);
5063 Data.Count := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EX_COUNT]], 0), 65535);
5064 if Data.Count < 1 then
5065 Data.Count := 1;
5066 if TriggerType = TRIGGER_PRESS then
5067 Data.ExtRandom := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_EX_RANDOM]]);
5068 end;
5070 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR, TRIGGER_DOOR5,
5071 TRIGGER_CLOSETRAP, TRIGGER_TRAP, TRIGGER_LIFTUP, TRIGGER_LIFTDOWN,
5072 TRIGGER_LIFT:
5073 begin
5074 Data.NoSound := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SILENT]]);
5075 Data.d2d_doors := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_D2D]]);
5076 end;
5078 TRIGGER_TELEPORT:
5079 begin
5080 Data.d2d_teleport := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_D2D]]);
5081 Data.silent_teleport := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_TELEPORT_SILENT]]);
5082 Data.TlpDir := NameToDirAdv(vleObjectProperty.Values[_lc[I_PROP_TR_TELEPORT_DIR]]);
5083 end;
5085 TRIGGER_SOUND:
5086 begin
5087 s := utf2win(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_NAME]]);
5088 FillByte(Data.SoundName[0], 64, 0);
5089 if s <> '' then
5090 Move(s[1], Data.SoundName[0], Min(Length(s), 64));
5092 Data.Volume := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_VOLUME]], 0), 255);
5093 Data.Pan := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_PAN]], 0), 255);
5094 Data.PlayCount := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_COUNT]], 0), 255);
5095 Data.Local := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_LOCAL]]);
5096 Data.SoundSwitch := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_SWITCH]]);
5097 end;
5099 TRIGGER_SPAWNMONSTER:
5100 begin
5101 Data.MonType := StrToMonster(vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_TYPE]]);
5102 Data.MonDir := Byte(NameToDir(vleObjectProperty.Values[_lc[I_PROP_DIRECTION]]));
5103 Data.MonHealth := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_HEALTH]], 0), 1000000);
5104 if Data.MonHealth < 0 then
5105 Data.MonHealth := 0;
5106 Data.MonActive := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_ACTIVE]]);
5107 Data.MonCount := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_COUNT]], 0), 64);
5108 if Data.MonCount < 1 then
5109 Data.MonCount := 1;
5110 Data.MonEffect := StrToEffect(vleObjectProperty.Values[_lc[I_PROP_TR_FX_TYPE]]);
5111 Data.MonMax := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SPAWN_MAX]], 0), 65535);
5112 Data.MonDelay := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SPAWN_DELAY]], 0), 65535);
5113 Data.MonBehav := 0;
5114 if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_1] then
5115 Data.MonBehav := 1;
5116 if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_2] then
5117 Data.MonBehav := 2;
5118 if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_3] then
5119 Data.MonBehav := 3;
5120 if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_4] then
5121 Data.MonBehav := 4;
5122 if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_5] then
5123 Data.MonBehav := 5;
5124 end;
5126 TRIGGER_SPAWNITEM:
5127 begin
5128 Data.ItemType := StrToItem(vleObjectProperty.Values[_lc[I_PROP_TR_ITEM_TYPE]]);
5129 Data.ItemOnlyDM := NameToBool(vleObjectProperty.Values[_lc[I_PROP_DM_ONLY]]);
5130 Data.ItemFalls := NameToBool(vleObjectProperty.Values[_lc[I_PROP_ITEM_FALLS]]);
5131 Data.ItemCount := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_COUNT]], 0), 64);
5132 if Data.ItemCount < 1 then
5133 Data.ItemCount := 1;
5134 Data.ItemEffect := StrToEffect(vleObjectProperty.Values[_lc[I_PROP_TR_FX_TYPE]]);
5135 Data.ItemMax := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SPAWN_MAX]], 0), 65535);
5136 Data.ItemDelay := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SPAWN_DELAY]], 0), 65535);
5137 end;
5139 TRIGGER_MUSIC:
5140 begin
5141 s := utf2win(vleObjectProperty.Values[_lc[I_PROP_TR_MUSIC_NAME]]);
5142 FillByte(Data.MusicName[0], 64, 0);
5143 if s <> '' then
5144 Move(s[1], Data.MusicName[0], Min(Length(s), 64));
5146 if vleObjectProperty.Values[_lc[I_PROP_TR_MUSIC_ACT]] = _lc[I_PROP_TR_MUSIC_ON] then
5147 Data.MusicAction := 1
5148 else
5149 Data.MusicAction := 2;
5150 end;
5152 TRIGGER_PUSH:
5153 begin
5154 Data.PushAngle := Min(
5155 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_PUSH_ANGLE]], 0), 360);
5156 Data.PushForce := Min(
5157 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_PUSH_FORCE]], 0), 255);
5158 Data.ResetVel := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_PUSH_RESET]]);
5159 end;
5161 TRIGGER_SCORE:
5162 begin
5163 Data.ScoreAction := 0;
5164 if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_ACT]] = _lc[I_PROP_TR_SCORE_ACT_1] then
5165 Data.ScoreAction := 1
5166 else if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_ACT]] = _lc[I_PROP_TR_SCORE_ACT_2] then
5167 Data.ScoreAction := 2
5168 else if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_ACT]] = _lc[I_PROP_TR_SCORE_ACT_3] then
5169 Data.ScoreAction := 3;
5170 Data.ScoreCount := Min(Max(
5171 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_COUNT]], 0), 0), 255);
5172 Data.ScoreTeam := 0;
5173 if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_TEAM]] = _lc[I_PROP_TR_SCORE_TEAM_1] then
5174 Data.ScoreTeam := 1
5175 else if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_TEAM]] = _lc[I_PROP_TR_SCORE_TEAM_2] then
5176 Data.ScoreTeam := 2
5177 else if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_TEAM]] = _lc[I_PROP_TR_SCORE_TEAM_3] then
5178 Data.ScoreTeam := 3;
5179 Data.ScoreCon := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_CON]]);
5180 Data.ScoreMsg := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_MSG]]);
5181 end;
5183 TRIGGER_MESSAGE:
5184 begin
5185 Data.MessageKind := 0;
5186 if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_KIND]] = _lc[I_PROP_TR_MESSAGE_KIND_1] then
5187 Data.MessageKind := 1;
5189 Data.MessageSendTo := 0;
5190 if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_1] then
5191 Data.MessageSendTo := 1
5192 else if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_2] then
5193 Data.MessageSendTo := 2
5194 else if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_3] then
5195 Data.MessageSendTo := 3
5196 else if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_4] then
5197 Data.MessageSendTo := 4
5198 else if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_5] then
5199 Data.MessageSendTo := 5;
5201 s := utf2win(vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TEXT]]);
5202 FillByte(Data.MessageText[0], 100, 0);
5203 if s <> '' then
5204 Move(s[1], Data.MessageText[0], Min(Length(s), 100));
5206 Data.MessageTime := Min(Max(
5207 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TIME]], 0), 0), 65535);
5208 end;
5210 TRIGGER_DAMAGE:
5211 begin
5212 Data.DamageValue := Min(Max(
5213 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_DAMAGE_VALUE]], 0), 0), 65535);
5214 Data.DamageInterval := Min(Max(
5215 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_INTERVAL]], 0), 0), 65535);
5216 s := vleObjectProperty.Values[_lc[I_PROP_TR_DAMAGE_KIND]];
5217 if s = _lc[I_PROP_TR_DAMAGE_KIND_3] then
5218 Data.DamageKind := 3
5219 else if s = _lc[I_PROP_TR_DAMAGE_KIND_4] then
5220 Data.DamageKind := 4
5221 else if s = _lc[I_PROP_TR_DAMAGE_KIND_5] then
5222 Data.DamageKind := 5
5223 else if s = _lc[I_PROP_TR_DAMAGE_KIND_6] then
5224 Data.DamageKind := 6
5225 else if s = _lc[I_PROP_TR_DAMAGE_KIND_7] then
5226 Data.DamageKind := 7
5227 else if s = _lc[I_PROP_TR_DAMAGE_KIND_8] then
5228 Data.DamageKind := 8
5229 else
5230 Data.DamageKind := 0;
5231 end;
5233 TRIGGER_HEALTH:
5234 begin
5235 Data.HealValue := Min(Max(
5236 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_HEALTH]], 0), 0), 65535);
5237 Data.HealInterval := Min(Max(
5238 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_INTERVAL]], 0), 0), 65535);
5239 Data.HealMax := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_HEALTH_MAX]]);
5240 Data.HealSilent := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SILENT]]);
5241 end;
5243 TRIGGER_SHOT:
5244 begin
5245 Data.ShotType := StrToShot(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TYPE]]);
5246 Data.ShotSound := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_SOUND]]);
5247 Data.ShotTarget := 0;
5248 if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_1] then
5249 Data.ShotTarget := 1
5250 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_2] then
5251 Data.ShotTarget := 2
5252 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_3] then
5253 Data.ShotTarget := 3
5254 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_4] then
5255 Data.ShotTarget := 4
5256 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_5] then
5257 Data.ShotTarget := 5
5258 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_6] then
5259 Data.ShotTarget := 6;
5260 Data.ShotIntSight := Min(Max(
5261 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_SIGHT]], 0), 0), 65535);
5262 Data.ShotAim := 0;
5263 if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_AIM]] = _lc[I_PROP_TR_SHOT_AIM_1] then
5264 Data.ShotAim := 1
5265 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_AIM]] = _lc[I_PROP_TR_SHOT_AIM_2] then
5266 Data.ShotAim := 2
5267 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_AIM]] = _lc[I_PROP_TR_SHOT_AIM_3] then
5268 Data.ShotAim := 3;
5269 Data.ShotAngle := Min(
5270 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_ANGLE]], 0), 360);
5271 Data.ShotWait := Min(Max(
5272 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EX_DELAY]], 0), 0), 65535);
5273 Data.ShotAccuracy := Min(Max(
5274 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_ACC]], 0), 0), 65535);
5275 Data.ShotAmmo := Min(Max(
5276 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_AMMO]], 0), 0), 65535);
5277 Data.ShotIntReload := Min(Max(
5278 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_RELOAD]], 0), 0), 65535);
5279 end;
5281 TRIGGER_EFFECT:
5282 begin
5283 Data.FXCount := Min(Max(
5284 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_COUNT]], 0), 0), 255);
5285 if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_TYPE]] = _lc[I_PROP_TR_EFFECT_PARTICLE] then
5286 begin
5287 Data.FXType := TRIGGER_EFFECT_PARTICLE;
5288 Data.FXSubType := TRIGGER_EFFECT_SLIQUID;
5289 if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_SLIQUID] then
5290 Data.FXSubType := TRIGGER_EFFECT_SLIQUID
5291 else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_LLIQUID] then
5292 Data.FXSubType := TRIGGER_EFFECT_LLIQUID
5293 else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_DLIQUID] then
5294 Data.FXSubType := TRIGGER_EFFECT_DLIQUID
5295 else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_BLOOD] then
5296 Data.FXSubType := TRIGGER_EFFECT_BLOOD
5297 else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_SPARK] then
5298 Data.FXSubType := TRIGGER_EFFECT_SPARK
5299 else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_BUBBLE] then
5300 Data.FXSubType := TRIGGER_EFFECT_BUBBLE;
5301 end else
5302 begin
5303 Data.FXType := TRIGGER_EFFECT_ANIMATION;
5304 Data.FXSubType := StrToEffect(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]]);
5305 end;
5306 a := Min(Max(
5307 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_COLOR]], 0), 0), $FFFFFF);
5308 Data.FXColorR := a and $FF;
5309 Data.FXColorG := (a shr 8) and $FF;
5310 Data.FXColorB := (a shr 16) and $FF;
5311 if NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_CENTER]]) then
5312 Data.FXPos := 0
5313 else
5314 Data.FXPos := 1;
5315 Data.FXWait := Min(Max(
5316 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EX_DELAY]], 0), 0), 65535);
5317 Data.FXVelX := Min(Max(
5318 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_VELX]], 0), -128), 127);
5319 Data.FXVelY := Min(Max(
5320 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_VELY]], 0), -128), 127);
5321 Data.FXSpreadL := Min(Max(
5322 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SPL]], 0), 0), 255);
5323 Data.FXSpreadR := Min(Max(
5324 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SPR]], 0), 0), 255);
5325 Data.FXSpreadU := Min(Max(
5326 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SPU]], 0), 0), 255);
5327 Data.FXSpreadD := Min(Max(
5328 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SPD]], 0), 0), 255);
5329 end;
5330 end;
5331 end;
5332 end;
5333 end;
5335 FillProperty();
5337 vleObjectProperty.Row := r;
5338 vleObjectProperty.Col := c;
5339 end;
5341 procedure TMainForm.bbRemoveTextureClick(Sender: TObject);
5342 var
5343 a, i: Integer;
5344 begin
5345 i := lbTextureList.ItemIndex;
5346 if i = -1 then
5347 Exit;
5349 if MessageBox(0, PChar(Format(_lc[I_MSG_DEL_TEXTURE_PROMT],
5350 [SelectedTexture()])),
5351 PChar(_lc[I_MSG_DEL_TEXTURE]),
5352 MB_ICONQUESTION or MB_YESNO or
5353 MB_DEFBUTTON1) <> idYes then
5354 Exit;
5356 if gPanels <> nil then
5357 for a := 0 to High(gPanels) do
5358 if (gPanels[a].PanelType <> 0) and
5359 (gPanels[a].TextureName = SelectedTexture()) then
5360 begin
5361 ErrorMessageBox(_lc[I_MSG_DEL_TEXTURE_CANT]);
5362 Exit;
5363 end;
5365 g_DeleteTexture(SelectedTexture());
5366 i := slInvalidTextures.IndexOf(lbTextureList.Items[i]);
5367 if i > -1 then
5368 slInvalidTextures.Delete(i);
5369 if lbTextureList.ItemIndex > -1 then
5370 lbTextureList.Items.Delete(lbTextureList.ItemIndex)
5371 end;
5373 procedure TMainForm.aNewMapExecute(Sender: TObject);
5374 begin
5375 if (MessageBox(0, PChar(_lc[I_MSG_CLEAR_MAP_PROMT]),
5376 PChar(_lc[I_MSG_CLEAR_MAP]),
5377 MB_ICONQUESTION or MB_YESNO or
5378 MB_DEFBUTTON1) = mrYes) then
5379 FullClear();
5380 end;
5382 procedure TMainForm.aUndoExecute(Sender: TObject);
5383 var
5384 a: Integer;
5385 begin
5386 if UndoBuffer = nil then
5387 Exit;
5388 if UndoBuffer[High(UndoBuffer)] = nil then
5389 Exit;
5391 for a := 0 to High(UndoBuffer[High(UndoBuffer)]) do
5392 with UndoBuffer[High(UndoBuffer)][a] do
5393 begin
5394 case UndoType of
5395 UNDO_DELETE_PANEL:
5396 begin
5397 AddPanel(Panel^);
5398 Panel := nil;
5399 end;
5400 UNDO_DELETE_ITEM: AddItem(Item);
5401 UNDO_DELETE_AREA: AddArea(Area);
5402 UNDO_DELETE_MONSTER: AddMonster(Monster);
5403 UNDO_DELETE_TRIGGER: AddTrigger(Trigger);
5404 UNDO_ADD_PANEL: RemoveObject(AddID, OBJECT_PANEL);
5405 UNDO_ADD_ITEM: RemoveObject(AddID, OBJECT_ITEM);
5406 UNDO_ADD_AREA: RemoveObject(AddID, OBJECT_AREA);
5407 UNDO_ADD_MONSTER: RemoveObject(AddID, OBJECT_MONSTER);
5408 UNDO_ADD_TRIGGER: RemoveObject(AddID, OBJECT_TRIGGER);
5409 end;
5410 end;
5412 SetLength(UndoBuffer, Length(UndoBuffer)-1);
5414 RemoveSelectFromObjects();
5416 miUndo.Enabled := UndoBuffer <> nil;
5417 end;
5420 procedure TMainForm.aCopyObjectExecute(Sender: TObject);
5421 var
5422 a, b: Integer;
5423 CopyBuffer: TCopyRecArray;
5424 str: String;
5425 ok: Boolean;
5427 function CB_Compare(I1, I2: TCopyRec): Integer;
5428 begin
5429 Result := Integer(I1.ObjectType) - Integer(I2.ObjectType);
5431 if Result = 0 then // Одного типа
5432 Result := Integer(I1.ID) - Integer(I2.ID);
5433 end;
5435 procedure QuickSortCopyBuffer(L, R: Integer);
5436 var
5437 I, J: Integer;
5438 P, T: TCopyRec;
5439 begin
5440 repeat
5441 I := L;
5442 J := R;
5443 P := CopyBuffer[(L + R) shr 1];
5445 repeat
5446 while CB_Compare(CopyBuffer[I], P) < 0 do
5447 Inc(I);
5448 while CB_Compare(CopyBuffer[J], P) > 0 do
5449 Dec(J);
5451 if I <= J then
5452 begin
5453 T := CopyBuffer[I];
5454 CopyBuffer[I] := CopyBuffer[J];
5455 CopyBuffer[J] := T;
5456 Inc(I);
5457 Dec(J);
5458 end;
5459 until I > J;
5461 if L < J then
5462 QuickSortCopyBuffer(L, J);
5464 L := I;
5465 until I >= R;
5466 end;
5468 begin
5469 if SelectedObjects = nil then
5470 Exit;
5472 b := -1;
5473 CopyBuffer := nil;
5475 // Копируем объекты:
5476 for a := 0 to High(SelectedObjects) do
5477 if SelectedObjects[a].Live then
5478 with SelectedObjects[a] do
5479 begin
5480 SetLength(CopyBuffer, Length(CopyBuffer)+1);
5481 b := High(CopyBuffer);
5482 CopyBuffer[b].ID := ID;
5483 CopyBuffer[b].Panel := nil;
5485 case ObjectType of
5486 OBJECT_PANEL:
5487 begin
5488 CopyBuffer[b].ObjectType := OBJECT_PANEL;
5489 New(CopyBuffer[b].Panel);
5490 CopyBuffer[b].Panel^ := gPanels[ID];
5491 end;
5493 OBJECT_ITEM:
5494 begin
5495 CopyBuffer[b].ObjectType := OBJECT_ITEM;
5496 CopyBuffer[b].Item := gItems[ID];
5497 end;
5499 OBJECT_MONSTER:
5500 begin
5501 CopyBuffer[b].ObjectType := OBJECT_MONSTER;
5502 CopyBuffer[b].Monster := gMonsters[ID];
5503 end;
5505 OBJECT_AREA:
5506 begin
5507 CopyBuffer[b].ObjectType := OBJECT_AREA;
5508 CopyBuffer[b].Area := gAreas[ID];
5509 end;
5511 OBJECT_TRIGGER:
5512 begin
5513 CopyBuffer[b].ObjectType := OBJECT_TRIGGER;
5514 CopyBuffer[b].Trigger := gTriggers[ID];
5515 end;
5516 end;
5517 end;
5519 // Сортировка по ID:
5520 if CopyBuffer <> nil then
5521 begin
5522 QuickSortCopyBuffer(0, b);
5523 end;
5525 // Пестановка ссылок триггеров:
5526 for a := 0 to Length(CopyBuffer)-1 do
5527 if CopyBuffer[a].ObjectType = OBJECT_TRIGGER then
5528 begin
5529 case CopyBuffer[a].Trigger.TriggerType of
5530 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
5531 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP,
5532 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
5533 if CopyBuffer[a].Trigger.Data.PanelID <> -1 then
5534 begin
5535 ok := False;
5537 for b := 0 to Length(CopyBuffer)-1 do
5538 if (CopyBuffer[b].ObjectType = OBJECT_PANEL) and
5539 (Integer(CopyBuffer[b].ID) = CopyBuffer[a].Trigger.Data.PanelID) then
5540 begin
5541 CopyBuffer[a].Trigger.Data.PanelID := b;
5542 ok := True;
5543 Break;
5544 end;
5546 // Этих панелей нет среди копируемых:
5547 if not ok then
5548 CopyBuffer[a].Trigger.Data.PanelID := -1;
5549 end;
5551 TRIGGER_PRESS, TRIGGER_ON,
5552 TRIGGER_OFF, TRIGGER_ONOFF:
5553 if CopyBuffer[a].Trigger.Data.MonsterID <> 0 then
5554 begin
5555 ok := False;
5557 for b := 0 to Length(CopyBuffer)-1 do
5558 if (CopyBuffer[b].ObjectType = OBJECT_MONSTER) and
5559 (Integer(CopyBuffer[b].ID) = CopyBuffer[a].Trigger.Data.MonsterID-1) then
5560 begin
5561 CopyBuffer[a].Trigger.Data.MonsterID := b+1;
5562 ok := True;
5563 Break;
5564 end;
5566 // Этих монстров нет среди копируемых:
5567 if not ok then
5568 CopyBuffer[a].Trigger.Data.MonsterID := 0;
5569 end;
5571 TRIGGER_SHOT:
5572 if CopyBuffer[a].Trigger.Data.ShotPanelID <> -1 then
5573 begin
5574 ok := False;
5576 for b := 0 to Length(CopyBuffer)-1 do
5577 if (CopyBuffer[b].ObjectType = OBJECT_PANEL) and
5578 (Integer(CopyBuffer[b].ID) = CopyBuffer[a].Trigger.Data.ShotPanelID) then
5579 begin
5580 CopyBuffer[a].Trigger.Data.ShotPanelID := b;
5581 ok := True;
5582 Break;
5583 end;
5585 // Этих панелей нет среди копируемых:
5586 if not ok then
5587 CopyBuffer[a].Trigger.Data.ShotPanelID := -1;
5588 end;
5589 end;
5591 if CopyBuffer[a].Trigger.TexturePanel <> -1 then
5592 begin
5593 ok := False;
5595 for b := 0 to Length(CopyBuffer)-1 do
5596 if (CopyBuffer[b].ObjectType = OBJECT_PANEL) and
5597 (Integer(CopyBuffer[b].ID) = CopyBuffer[a].Trigger.TexturePanel) then
5598 begin
5599 CopyBuffer[a].Trigger.TexturePanel := b;
5600 ok := True;
5601 Break;
5602 end;
5604 // Этих панелей нет среди копируемых:
5605 if not ok then
5606 CopyBuffer[a].Trigger.TexturePanel := -1;
5607 end;
5608 end;
5610 // В буфер обмена:
5611 str := CopyBufferToString(CopyBuffer);
5612 ClipBoard.AsText := str;
5614 for a := 0 to Length(CopyBuffer)-1 do
5615 if (CopyBuffer[a].ObjectType = OBJECT_PANEL) and
5616 (CopyBuffer[a].Panel <> nil) then
5617 Dispose(CopyBuffer[a].Panel);
5619 CopyBuffer := nil;
5620 end;
5622 procedure TMainForm.aPasteObjectExecute(Sender: TObject);
5623 var
5624 a, h: Integer;
5625 CopyBuffer: TCopyRecArray;
5626 res, rel: Boolean;
5627 swad, ssec, sres: String;
5628 NoTextureID: DWORD;
5629 pmin: TPoint;
5630 begin
5631 CopyBuffer := nil;
5632 NoTextureID := 0;
5633 pmin.X := High(pmin.X);
5634 pmin.Y := High(pmin.Y);
5636 StringToCopyBuffer(ClipBoard.AsText, CopyBuffer, pmin);
5637 rel := not(ssShift in GetKeyShiftState());
5639 if CopyBuffer = nil then
5640 Exit;
5642 RemoveSelectFromObjects();
5644 h := High(CopyBuffer);
5645 for a := 0 to h do
5646 with CopyBuffer[a] do
5647 begin
5648 case ObjectType of
5649 OBJECT_PANEL:
5650 if Panel <> nil then
5651 begin
5652 if rel then
5653 begin
5654 Panel^.X := Panel^.X - pmin.X - MapOffset.X + 32;
5655 Panel^.Y := Panel^.Y - pmin.Y - MapOffset.Y + 32;
5656 end;
5658 Panel^.TextureID := TEXTURE_SPECIAL_NONE;
5659 Panel^.TextureWidth := 1;
5660 Panel^.TextureHeight := 1;
5662 if (Panel^.PanelType = PANEL_LIFTUP) or
5663 (Panel^.PanelType = PANEL_LIFTDOWN) or
5664 (Panel^.PanelType = PANEL_LIFTLEFT) or
5665 (Panel^.PanelType = PANEL_LIFTRIGHT) or
5666 (Panel^.PanelType = PANEL_BLOCKMON) or
5667 (Panel^.TextureName = '') then
5668 begin // Нет или не может быть текстуры:
5669 end
5670 else // Есть текстура:
5671 begin
5672 // Обычная текстура:
5673 if not IsSpecialTexture(Panel^.TextureName) then
5674 begin
5675 res := g_GetTexture(Panel^.TextureName, Panel^.TextureID);
5677 if not res then
5678 begin
5679 g_ProcessResourceStr(Panel^.TextureName, swad, ssec, sres);
5680 AddTexture(swad, ssec, sres, True);
5681 res := g_GetTexture(Panel^.TextureName, Panel^.TextureID);
5682 end;
5684 if res then
5685 g_GetTextureSizeByName(Panel^.TextureName,
5686 Panel^.TextureWidth, Panel^.TextureHeight)
5687 else
5688 if g_GetTexture('NOTEXTURE', NoTextureID) then
5689 begin
5690 Panel^.TextureID := TEXTURE_SPECIAL_NOTEXTURE;
5691 g_GetTextureSizeByID(NoTextureID, Panel^.TextureWidth, Panel^.TextureHeight);
5692 end;
5693 end
5694 else // Спец.текстура:
5695 begin
5696 Panel^.TextureID := SpecialTextureID(Panel^.TextureName);
5697 with MainForm.lbTextureList.Items do
5698 if IndexOf(Panel^.TextureName) = -1 then
5699 Add(Panel^.TextureName);
5700 end;
5701 end;
5703 ID := AddPanel(Panel^);
5704 Dispose(Panel);
5705 Undo_Add(OBJECT_PANEL, ID, a > 0);
5706 SelectObject(OBJECT_PANEL, ID, True);
5707 end;
5709 OBJECT_ITEM:
5710 begin
5711 if rel then
5712 begin
5713 Item.X := Item.X - pmin.X - MapOffset.X + 32;
5714 Item.Y := Item.Y - pmin.Y - MapOffset.Y + 32;
5715 end;
5717 ID := AddItem(Item);
5718 Undo_Add(OBJECT_ITEM, ID, a > 0);
5719 SelectObject(OBJECT_ITEM, ID, True);
5720 end;
5722 OBJECT_MONSTER:
5723 begin
5724 if rel then
5725 begin
5726 Monster.X := Monster.X - pmin.X - MapOffset.X + 32;
5727 Monster.Y := Monster.Y - pmin.Y - MapOffset.Y + 32;
5728 end;
5730 ID := AddMonster(Monster);
5731 Undo_Add(OBJECT_MONSTER, ID, a > 0);
5732 SelectObject(OBJECT_MONSTER, ID, True);
5733 end;
5735 OBJECT_AREA:
5736 begin
5737 if rel then
5738 begin
5739 Area.X := Area.X - pmin.X - MapOffset.X + 32;
5740 Area.Y := Area.Y - pmin.Y - MapOffset.Y + 32;
5741 end;
5743 ID := AddArea(Area);
5744 Undo_Add(OBJECT_AREA, ID, a > 0);
5745 SelectObject(OBJECT_AREA, ID, True);
5746 end;
5748 OBJECT_TRIGGER:
5749 begin
5750 if rel then
5751 with Trigger do
5752 begin
5753 X := X - pmin.X - MapOffset.X + 32;
5754 Y := Y - pmin.Y - MapOffset.Y + 32;
5756 case TriggerType of
5757 TRIGGER_TELEPORT:
5758 begin
5759 Data.TargetPoint.X :=
5760 Data.TargetPoint.X - pmin.X - MapOffset.X + 32;
5761 Data.TargetPoint.Y :=
5762 Data.TargetPoint.Y - pmin.Y - MapOffset.Y + 32;
5763 end;
5764 TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF:
5765 begin
5766 Data.tX := Data.tX - pmin.X - MapOffset.X + 32;
5767 Data.tY := Data.tY - pmin.Y - MapOffset.Y + 32;
5768 end;
5769 TRIGGER_SPAWNMONSTER:
5770 begin
5771 Data.MonPos.X :=
5772 Data.MonPos.X - pmin.X - MapOffset.X + 32;
5773 Data.MonPos.Y :=
5774 Data.MonPos.Y - pmin.Y - MapOffset.Y + 32;
5775 end;
5776 TRIGGER_SPAWNITEM:
5777 begin
5778 Data.ItemPos.X :=
5779 Data.ItemPos.X - pmin.X - MapOffset.X + 32;
5780 Data.ItemPos.Y :=
5781 Data.ItemPos.Y - pmin.Y - MapOffset.Y + 32;
5782 end;
5783 TRIGGER_SHOT:
5784 begin
5785 Data.ShotPos.X :=
5786 Data.ShotPos.X - pmin.X - MapOffset.X + 32;
5787 Data.ShotPos.Y :=
5788 Data.ShotPos.Y - pmin.Y - MapOffset.Y + 32;
5789 end;
5790 end;
5791 end;
5793 ID := AddTrigger(Trigger);
5794 Undo_Add(OBJECT_TRIGGER, ID, a > 0);
5795 SelectObject(OBJECT_TRIGGER, ID, True);
5796 end;
5797 end;
5798 end;
5800 // Переставляем ссылки триггеров:
5801 for a := 0 to High(CopyBuffer) do
5802 if CopyBuffer[a].ObjectType = OBJECT_TRIGGER then
5803 begin
5804 case CopyBuffer[a].Trigger.TriggerType of
5805 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
5806 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP,
5807 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
5808 if CopyBuffer[a].Trigger.Data.PanelID <> -1 then
5809 gTriggers[CopyBuffer[a].ID].Data.PanelID :=
5810 CopyBuffer[CopyBuffer[a].Trigger.Data.PanelID].ID;
5812 TRIGGER_PRESS, TRIGGER_ON,
5813 TRIGGER_OFF, TRIGGER_ONOFF:
5814 if CopyBuffer[a].Trigger.Data.MonsterID <> 0 then
5815 gTriggers[CopyBuffer[a].ID].Data.MonsterID :=
5816 CopyBuffer[CopyBuffer[a].Trigger.Data.MonsterID-1].ID+1;
5818 TRIGGER_SHOT:
5819 if CopyBuffer[a].Trigger.Data.ShotPanelID <> -1 then
5820 gTriggers[CopyBuffer[a].ID].Data.ShotPanelID :=
5821 CopyBuffer[CopyBuffer[a].Trigger.Data.ShotPanelID].ID;
5822 end;
5824 if CopyBuffer[a].Trigger.TexturePanel <> -1 then
5825 gTriggers[CopyBuffer[a].ID].TexturePanel :=
5826 CopyBuffer[CopyBuffer[a].Trigger.TexturePanel].ID;
5827 end;
5829 CopyBuffer := nil;
5831 if h = 0 then
5832 FillProperty();
5833 end;
5835 procedure TMainForm.aCutObjectExecute(Sender: TObject);
5836 begin
5837 miCopy.Click();
5838 DeleteSelectedObjects();
5839 end;
5841 procedure TMainForm.vleObjectPropertyEditButtonClick(Sender: TObject);
5842 var
5843 Key, FileName: String;
5844 b: Byte;
5845 begin
5846 Key := vleObjectProperty.Keys[vleObjectProperty.Row];
5848 if Key = _lc[I_PROP_PANEL_TYPE] then
5849 begin
5850 with ChooseTypeForm, vleObjectProperty do
5851 begin // Выбор типа панели:
5852 Caption := _lc[I_PROP_PANEL_TYPE];
5853 lbTypeSelect.Items.Clear();
5855 for b := 0 to High(PANELNAMES) do
5856 begin
5857 lbTypeSelect.Items.Add(PANELNAMES[b]);
5858 if Values[Key] = PANELNAMES[b] then
5859 lbTypeSelect.ItemIndex := b;
5860 end;
5862 if ShowModal() = mrOK then
5863 begin
5864 b := lbTypeSelect.ItemIndex;
5865 Values[Key] := PANELNAMES[b];
5866 vleObjectPropertyApply(Sender);
5867 end;
5868 end
5869 end
5870 else if Key = _lc[I_PROP_TR_TELEPORT_TO] then
5871 SelectFlag := SELECTFLAG_TELEPORT
5872 else if Key = _lc[I_PROP_TR_SPAWN_TO] then
5873 SelectFlag := SELECTFLAG_SPAWNPOINT
5874 else if (Key = _lc[I_PROP_TR_DOOR_PANEL]) or
5875 (Key = _lc[I_PROP_TR_TRAP_PANEL]) then
5876 SelectFlag := SELECTFLAG_DOOR
5877 else if Key = _lc[I_PROP_TR_TEXTURE_PANEL] then
5878 begin
5879 DrawPressRect := False;
5880 SelectFlag := SELECTFLAG_TEXTURE;
5881 end
5882 else if Key = _lc[I_PROP_TR_SHOT_PANEL] then
5883 SelectFlag := SELECTFLAG_SHOTPANEL
5884 else if Key = _lc[I_PROP_TR_LIFT_PANEL] then
5885 SelectFlag := SELECTFLAG_LIFT
5886 else if key = _lc[I_PROP_TR_EX_MONSTER] then
5887 SelectFlag := SELECTFLAG_MONSTER
5888 else if Key = _lc[I_PROP_TR_EX_AREA] then
5889 begin
5890 SelectFlag := SELECTFLAG_NONE;
5891 DrawPressRect := True;
5892 end
5893 else if Key = _lc[I_PROP_TR_NEXT_MAP] then
5894 begin // Выбор следующей карты:
5895 g_ProcessResourceStr(OpenedMap, @FileName, nil, nil);
5896 SelectMapForm.Caption := _lc[I_CAP_SELECT];
5897 SelectMapForm.GetMaps(FileName);
5899 if SelectMapForm.ShowModal() = mrOK then
5900 begin
5901 vleObjectProperty.Values[Key] := SelectMapForm.lbMapList.Items[SelectMapForm.lbMapList.ItemIndex];
5902 vleObjectPropertyApply(Sender);
5903 end;
5904 end
5905 else if (Key = _lc[I_PROP_TR_SOUND_NAME]) or
5906 (Key = _lc[I_PROP_TR_MUSIC_NAME]) then
5907 begin // Выбор файла звука/музыки:
5908 AddSoundForm.OKFunction := nil;
5909 AddSoundForm.lbResourcesList.MultiSelect := False;
5910 AddSoundForm.SetResource := vleObjectProperty.Values[Key];
5912 if (AddSoundForm.ShowModal() = mrOk) then
5913 begin
5914 vleObjectProperty.Values[Key] := AddSoundForm.ResourceName;
5915 vleObjectPropertyApply(Sender);
5916 end;
5917 end
5918 else if Key = _lc[I_PROP_TR_ACTIVATION] then
5919 with ActivationTypeForm, vleObjectProperty do
5920 begin // Выбор типов активации:
5921 cbPlayerCollide.Checked := Pos('PC', Values[Key]) > 0;
5922 cbMonsterCollide.Checked := Pos('MC', Values[Key]) > 0;
5923 cbPlayerPress.Checked := Pos('PP', Values[Key]) > 0;
5924 cbMonsterPress.Checked := Pos('MP', Values[Key]) > 0;
5925 cbShot.Checked := Pos('SH', Values[Key]) > 0;
5926 cbNoMonster.Checked := Pos('NM', Values[Key]) > 0;
5928 if ShowModal() = mrOK then
5929 begin
5930 b := 0;
5931 if cbPlayerCollide.Checked then
5932 b := ACTIVATE_PLAYERCOLLIDE;
5933 if cbMonsterCollide.Checked then
5934 b := b or ACTIVATE_MONSTERCOLLIDE;
5935 if cbPlayerPress.Checked then
5936 b := b or ACTIVATE_PLAYERPRESS;
5937 if cbMonsterPress.Checked then
5938 b := b or ACTIVATE_MONSTERPRESS;
5939 if cbShot.Checked then
5940 b := b or ACTIVATE_SHOT;
5941 if cbNoMonster.Checked then
5942 b := b or ACTIVATE_NOMONSTER;
5944 Values[Key] := ActivateToStr(b);
5945 vleObjectPropertyApply(Sender);
5946 end;
5947 end
5948 else if Key = _lc[I_PROP_TR_KEYS] then
5949 with KeysForm, vleObjectProperty do
5950 begin // Выбор необходимых ключей:
5951 cbRedKey.Checked := Pos('RK', Values[Key]) > 0;
5952 cbGreenKey.Checked := Pos('GK', Values[Key]) > 0;
5953 cbBlueKey.Checked := Pos('BK', Values[Key]) > 0;
5954 cbRedTeam.Checked := Pos('RT', Values[Key]) > 0;
5955 cbBlueTeam.Checked := Pos('BT', Values[Key]) > 0;
5957 if ShowModal() = mrOK then
5958 begin
5959 b := 0;
5960 if cbRedKey.Checked then
5961 b := KEY_RED;
5962 if cbGreenKey.Checked then
5963 b := b or KEY_GREEN;
5964 if cbBlueKey.Checked then
5965 b := b or KEY_BLUE;
5966 if cbRedTeam.Checked then
5967 b := b or KEY_REDTEAM;
5968 if cbBlueTeam.Checked then
5969 b := b or KEY_BLUETEAM;
5971 Values[Key] := KeyToStr(b);
5972 vleObjectPropertyApply(Sender);
5973 end;
5974 end
5975 else if Key = _lc[I_PROP_TR_FX_TYPE] then
5976 with ChooseTypeForm, vleObjectProperty do
5977 begin // Выбор типа эффекта:
5978 Caption := _lc[I_CAP_FX_TYPE];
5979 lbTypeSelect.Items.Clear();
5981 for b := EFFECT_NONE to EFFECT_FIRE do
5982 lbTypeSelect.Items.Add(EffectToStr(b));
5984 lbTypeSelect.ItemIndex := StrToEffect(Values[Key]);
5986 if ShowModal() = mrOK then
5987 begin
5988 b := lbTypeSelect.ItemIndex;
5989 Values[Key] := EffectToStr(b);
5990 vleObjectPropertyApply(Sender);
5991 end;
5992 end
5993 else if Key = _lc[I_PROP_TR_MONSTER_TYPE] then
5994 with ChooseTypeForm, vleObjectProperty do
5995 begin // Выбор типа монстра:
5996 Caption := _lc[I_CAP_MONSTER_TYPE];
5997 lbTypeSelect.Items.Clear();
5999 for b := MONSTER_DEMON to MONSTER_MAN do
6000 lbTypeSelect.Items.Add(MonsterToStr(b));
6002 lbTypeSelect.ItemIndex := StrToMonster(Values[Key]) - MONSTER_DEMON;
6004 if ShowModal() = mrOK then
6005 begin
6006 b := lbTypeSelect.ItemIndex + MONSTER_DEMON;
6007 Values[Key] := MonsterToStr(b);
6008 vleObjectPropertyApply(Sender);
6009 end;
6010 end
6011 else if Key = _lc[I_PROP_TR_ITEM_TYPE] then
6012 with ChooseTypeForm, vleObjectProperty do
6013 begin // Выбор типа предмета:
6014 Caption := _lc[I_CAP_ITEM_TYPE];
6015 lbTypeSelect.Items.Clear();
6017 for b := ITEM_MEDKIT_SMALL to ITEM_KEY_BLUE do
6018 lbTypeSelect.Items.Add(ItemToStr(b));
6019 lbTypeSelect.Items.Add(ItemToStr(ITEM_BOTTLE));
6020 lbTypeSelect.Items.Add(ItemToStr(ITEM_HELMET));
6021 lbTypeSelect.Items.Add(ItemToStr(ITEM_JETPACK));
6022 lbTypeSelect.Items.Add(ItemToStr(ITEM_INVIS));
6023 lbTypeSelect.Items.Add(ItemToStr(ITEM_WEAPON_FLAMETHROWER));
6024 lbTypeSelect.Items.Add(ItemToStr(ITEM_AMMO_FUELCAN));
6026 b := StrToItem(Values[Key]);
6027 if b >= ITEM_BOTTLE then
6028 b := b - 2;
6029 lbTypeSelect.ItemIndex := b - ITEM_MEDKIT_SMALL;
6031 if ShowModal() = mrOK then
6032 begin
6033 b := lbTypeSelect.ItemIndex + ITEM_MEDKIT_SMALL;
6034 if b >= ITEM_WEAPON_KASTET then
6035 b := b + 2;
6036 Values[Key] := ItemToStr(b);
6037 vleObjectPropertyApply(Sender);
6038 end;
6039 end
6040 else if Key = _lc[I_PROP_TR_SHOT_TYPE] then
6041 with ChooseTypeForm, vleObjectProperty do
6042 begin // Выбор типа предмета:
6043 Caption := _lc[I_PROP_TR_SHOT_TYPE];
6044 lbTypeSelect.Items.Clear();
6046 for b := TRIGGER_SHOT_PISTOL to TRIGGER_SHOT_MAX do
6047 lbTypeSelect.Items.Add(ShotToStr(b));
6049 lbTypeSelect.ItemIndex := StrToShot(Values[Key]);
6051 if ShowModal() = mrOK then
6052 begin
6053 b := lbTypeSelect.ItemIndex;
6054 Values[Key] := ShotToStr(b);
6055 vleObjectPropertyApply(Sender);
6056 end;
6057 end
6058 else if Key = _lc[I_PROP_TR_EFFECT_TYPE] then
6059 with ChooseTypeForm, vleObjectProperty do
6060 begin // Выбор типа эффекта:
6061 Caption := _lc[I_CAP_FX_TYPE];
6062 lbTypeSelect.Items.Clear();
6064 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_PARTICLE]);
6065 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_ANIMATION]);
6066 if Values[Key] = _lc[I_PROP_TR_EFFECT_ANIMATION] then
6067 lbTypeSelect.ItemIndex := 1
6068 else
6069 lbTypeSelect.ItemIndex := 0;
6071 if ShowModal() = mrOK then
6072 begin
6073 b := lbTypeSelect.ItemIndex;
6074 if b = 0 then
6075 Values[Key] := _lc[I_PROP_TR_EFFECT_PARTICLE]
6076 else
6077 Values[Key] := _lc[I_PROP_TR_EFFECT_ANIMATION];
6078 vleObjectPropertyApply(Sender);
6079 end;
6080 end
6081 else if Key = _lc[I_PROP_TR_EFFECT_SUBTYPE] then
6082 with ChooseTypeForm, vleObjectProperty do
6083 begin // Выбор подтипа эффекта:
6084 Caption := _lc[I_CAP_FX_TYPE];
6085 lbTypeSelect.Items.Clear();
6087 if Values[_lc[I_PROP_TR_EFFECT_TYPE]] = _lc[I_PROP_TR_EFFECT_ANIMATION] then
6088 begin
6089 for b := EFFECT_TELEPORT to EFFECT_FIRE do
6090 lbTypeSelect.Items.Add(EffectToStr(b));
6092 lbTypeSelect.ItemIndex := StrToEffect(Values[Key]) - 1;
6093 end else
6094 begin
6095 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_SLIQUID]);
6096 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_LLIQUID]);
6097 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_DLIQUID]);
6098 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_BLOOD]);
6099 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_SPARK]);
6100 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_BUBBLE]);
6101 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_SLIQUID;
6102 if Values[Key] = _lc[I_PROP_TR_EFFECT_LLIQUID] then
6103 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_LLIQUID;
6104 if Values[Key] = _lc[I_PROP_TR_EFFECT_DLIQUID] then
6105 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_DLIQUID;
6106 if Values[Key] = _lc[I_PROP_TR_EFFECT_BLOOD] then
6107 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_BLOOD;
6108 if Values[Key] = _lc[I_PROP_TR_EFFECT_SPARK] then
6109 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_SPARK;
6110 if Values[Key] = _lc[I_PROP_TR_EFFECT_BUBBLE] then
6111 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_BUBBLE;
6112 end;
6114 if ShowModal() = mrOK then
6115 begin
6116 b := lbTypeSelect.ItemIndex;
6118 if Values[_lc[I_PROP_TR_EFFECT_TYPE]] = _lc[I_PROP_TR_EFFECT_ANIMATION] then
6119 Values[Key] := EffectToStr(b + 1)
6120 else begin
6121 Values[Key] := _lc[I_PROP_TR_EFFECT_SLIQUID];
6122 if b = TRIGGER_EFFECT_LLIQUID then
6123 Values[Key] := _lc[I_PROP_TR_EFFECT_LLIQUID];
6124 if b = TRIGGER_EFFECT_DLIQUID then
6125 Values[Key] := _lc[I_PROP_TR_EFFECT_DLIQUID];
6126 if b = TRIGGER_EFFECT_BLOOD then
6127 Values[Key] := _lc[I_PROP_TR_EFFECT_BLOOD];
6128 if b = TRIGGER_EFFECT_SPARK then
6129 Values[Key] := _lc[I_PROP_TR_EFFECT_SPARK];
6130 if b = TRIGGER_EFFECT_BUBBLE then
6131 Values[Key] := _lc[I_PROP_TR_EFFECT_BUBBLE];
6132 end;
6134 vleObjectPropertyApply(Sender);
6135 end;
6136 end
6137 else if Key = _lc[I_PROP_TR_EFFECT_COLOR] then
6138 with vleObjectProperty do
6139 begin // Выбор цвета эффекта:
6140 ColorDialog.Color := StrToIntDef(Values[Key], 0);
6141 if ColorDialog.Execute then
6142 begin
6143 Values[Key] := IntToStr(ColorDialog.Color);
6144 vleObjectPropertyApply(Sender);
6145 end;
6146 end
6147 else if Key = _lc[I_PROP_PANEL_TEX] then
6148 begin // Смена текстуры:
6149 vleObjectProperty.Values[Key] := SelectedTexture();
6150 vleObjectPropertyApply(Sender);
6151 end;
6152 end;
6154 procedure TMainForm.vleObjectPropertyApply(Sender: TObject);
6155 begin
6156 // hack to prevent empty ID in list
6157 RenderPanel.SetFocus();
6158 bApplyProperty.Click();
6159 vleObjectProperty.SetFocus();
6160 end;
6162 procedure TMainForm.aSaveMapExecute(Sender: TObject);
6163 var
6164 FileName, Section, Res: String;
6165 begin
6166 if OpenedMap = '' then
6167 begin
6168 aSaveMapAsExecute(nil);
6169 Exit;
6170 end;
6172 g_ProcessResourceStr(OpenedMap, FileName, Section, Res);
6174 SaveMap(FileName+':\'+Res);
6175 end;
6177 procedure TMainForm.aOpenMapExecute(Sender: TObject);
6178 begin
6179 OpenDialog.Filter := _lc[I_FILE_FILTER_ALL];
6181 if OpenDialog.Execute() then
6182 begin
6183 OpenMapFile(OpenDialog.FileName);
6184 OpenDialog.InitialDir := ExtractFileDir(OpenDialog.FileName);
6185 end;
6186 end;
6188 procedure TMainForm.OpenMapFile(FileName: String);
6189 begin
6190 if (Pos('.ini', LowerCase(ExtractFileName(FileName))) > 0) then
6191 begin // INI карты:
6192 FullClear();
6194 pLoadProgress.Left := (RenderPanel.Width div 2)-(pLoadProgress.Width div 2);
6195 pLoadProgress.Top := (RenderPanel.Height div 2)-(pLoadProgress.Height div 2);
6196 pLoadProgress.Show();
6198 OpenedMap := '';
6199 OpenedWAD := '';
6201 LoadMapOld(FileName);
6203 MainForm.Caption := Format('%s - %s', [FormCaption, ExtractFileName(FileName)]);
6205 pLoadProgress.Hide();
6206 MainForm.FormResize(Self);
6207 end
6208 else // Карты из WAD:
6209 begin
6210 OpenMap(FileName, '');
6211 end;
6212 end;
6214 procedure TMainForm.FormActivate(Sender: TObject);
6215 var
6216 lang: Integer;
6217 config: TConfig;
6218 begin
6219 MainForm.ActiveControl := RenderPanel;
6221 // Язык:
6222 if gLanguage = '' then
6223 begin
6224 lang := SelectLanguageForm.ShowModal();
6225 case lang of
6226 1: gLanguage := LANGUAGE_ENGLISH;
6227 else gLanguage := LANGUAGE_RUSSIAN;
6228 end;
6230 config := TConfig.CreateFile(EditorDir+'Editor.cfg');
6231 config.WriteStr('Editor', 'Language', gLanguage);
6232 config.SaveFile(EditorDir+'Editor.cfg');
6233 config.Free();
6234 end;
6236 //e_WriteLog('Read language file', MSG_NOTIFY);
6237 //g_Language_Load(EditorDir+'\data\'+gLanguage+LANGUAGE_FILE_NAME);
6238 g_Language_Set(gLanguage);
6239 end;
6241 procedure TMainForm.aDeleteMap(Sender: TObject);
6242 var
6243 res: Integer;
6244 FileName: String;
6245 MapName: String;
6246 begin
6247 OpenDialog.Filter := _lc[I_FILE_FILTER_WAD];
6249 if not OpenDialog.Execute() then
6250 Exit;
6252 FileName := OpenDialog.FileName;
6253 SelectMapForm.Caption := _lc[I_CAP_REMOVE];
6254 SelectMapForm.lbMapList.Items.Clear();
6255 SelectMapForm.GetMaps(FileName);
6257 if SelectMapForm.ShowModal() <> mrOK then
6258 Exit;
6260 MapName := SelectMapForm.lbMapList.Items[SelectMapForm.lbMapList.ItemIndex];
6261 if MessageBox(0, PChar(Format(_lc[I_MSG_DELETE_MAP_PROMT], [MapName, OpenDialog.FileName])), PChar(_lc[I_MSG_DELETE_MAP]), MB_ICONQUESTION or MB_YESNO or MB_DEFBUTTON2) <> mrYes then
6262 Exit;
6264 g_DeleteResource(FileName, '', MapName, res);
6265 if res <> 0 then
6266 begin
6267 MessageBox(0, PChar('Cant delete map res=' + IntToStr(res)), PChar('Map not deleted!'), MB_ICONINFORMATION or MB_OK or MB_DEFBUTTON1);
6268 Exit
6269 end;
6271 MessageBox(
6272 0,
6273 PChar(Format(_lc[I_MSG_MAP_DELETED_PROMT], [MapName])),
6274 PChar(_lc[I_MSG_MAP_DELETED]),
6275 MB_ICONINFORMATION or MB_OK or MB_DEFBUTTON1
6276 );
6278 // Удалили текущую карту - сохранять по старому ее нельзя:
6279 if OpenedMap = (FileName + ':\' + MapName) then
6280 begin
6281 OpenedMap := '';
6282 OpenedWAD := '';
6283 MainForm.Caption := FormCaption
6284 end
6285 end;
6287 procedure TMainForm.vleObjectPropertyKeyDown(Sender: TObject;
6288 var Key: Word; Shift: TShiftState);
6289 begin
6290 if Key = VK_RETURN then
6291 vleObjectPropertyApply(Sender);
6292 end;
6294 procedure MovePanel(var ID: DWORD; MoveType: Byte);
6295 var
6296 _id, a: Integer;
6297 tmp: TPanel;
6298 begin
6299 if (ID = 0) and (MoveType = 0) then
6300 Exit;
6301 if (ID = DWORD(High(gPanels))) and (MoveType <> 0) then
6302 Exit;
6303 if (ID > DWORD(High(gPanels))) then
6304 Exit;
6306 _id := Integer(ID);
6308 if MoveType = 0 then // to Back
6309 begin
6310 if gTriggers <> nil then
6311 for a := 0 to High(gTriggers) do
6312 with gTriggers[a] do
6313 begin
6314 if TriggerType = TRIGGER_NONE then
6315 Continue;
6317 if TexturePanel = _id then
6318 TexturePanel := 0
6319 else
6320 if (TexturePanel >= 0) and (TexturePanel < _id) then
6321 Inc(TexturePanel);
6323 case TriggerType of
6324 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
6325 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP,
6326 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
6327 if Data.PanelID = _id then
6328 Data.PanelID := 0
6329 else
6330 if (Data.PanelID >= 0) and (Data.PanelID < _id) then
6331 Inc(Data.PanelID);
6333 TRIGGER_SHOT:
6334 if Data.ShotPanelID = _id then
6335 Data.ShotPanelID := 0
6336 else
6337 if (Data.ShotPanelID >= 0) and (Data.ShotPanelID < _id) then
6338 Inc(Data.ShotPanelID);
6339 end;
6340 end;
6342 tmp := gPanels[_id];
6344 for a := _id downto 1 do
6345 gPanels[a] := gPanels[a-1];
6347 gPanels[0] := tmp;
6349 ID := 0;
6350 end
6351 else // to Front
6352 begin
6353 if gTriggers <> nil then
6354 for a := 0 to High(gTriggers) do
6355 with gTriggers[a] do
6356 begin
6357 if TriggerType = TRIGGER_NONE then
6358 Continue;
6360 if TexturePanel = _id then
6361 TexturePanel := High(gPanels)
6362 else
6363 if TexturePanel > _id then
6364 Dec(TexturePanel);
6366 case TriggerType of
6367 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
6368 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP,
6369 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
6370 if Data.PanelID = _id then
6371 Data.PanelID := High(gPanels)
6372 else
6373 if Data.PanelID > _id then
6374 Dec(Data.PanelID);
6376 TRIGGER_SHOT:
6377 if Data.ShotPanelID = _id then
6378 Data.ShotPanelID := High(gPanels)
6379 else
6380 if Data.ShotPanelID > _id then
6381 Dec(Data.ShotPanelID);
6382 end;
6383 end;
6385 tmp := gPanels[_id];
6387 for a := _id to High(gPanels)-1 do
6388 gPanels[a] := gPanels[a+1];
6390 gPanels[High(gPanels)] := tmp;
6392 ID := High(gPanels);
6393 end;
6394 end;
6396 procedure TMainForm.aMoveToBack(Sender: TObject);
6397 var
6398 a: Integer;
6399 begin
6400 if SelectedObjects = nil then
6401 Exit;
6403 for a := 0 to High(SelectedObjects) do
6404 with SelectedObjects[a] do
6405 if Live and (ObjectType = OBJECT_PANEL) then
6406 begin
6407 SelectedObjects[0] := SelectedObjects[a];
6408 SetLength(SelectedObjects, 1);
6409 MovePanel(ID, 0);
6410 FillProperty();
6411 Break;
6412 end;
6413 end;
6415 procedure TMainForm.aMoveToFore(Sender: TObject);
6416 var
6417 a: Integer;
6418 begin
6419 if SelectedObjects = nil then
6420 Exit;
6422 for a := 0 to High(SelectedObjects) do
6423 with SelectedObjects[a] do
6424 if Live and (ObjectType = OBJECT_PANEL) then
6425 begin
6426 SelectedObjects[0] := SelectedObjects[a];
6427 SetLength(SelectedObjects, 1);
6428 MovePanel(ID, 1);
6429 FillProperty();
6430 Break;
6431 end;
6432 end;
6434 procedure TMainForm.aSaveMapAsExecute(Sender: TObject);
6435 var
6436 idx: Integer;
6437 begin
6438 SaveDialog.Filter := _lc[I_FILE_FILTER_WAD];
6440 if not SaveDialog.Execute() then
6441 Exit;
6443 SaveMapForm.GetMaps(SaveDialog.FileName, True);
6445 if SaveMapForm.ShowModal() <> mrOK then
6446 Exit;
6448 SaveDialog.InitialDir := ExtractFileDir(SaveDialog.FileName);
6449 OpenedMap := SaveDialog.FileName+':\'+SaveMapForm.eMapName.Text;
6450 OpenedWAD := SaveDialog.FileName;
6452 idx := RecentFiles.IndexOf(OpenedMap);
6453 // Такая карта уже недавно открывалась:
6454 if idx >= 0 then
6455 RecentFiles.Delete(idx);
6456 RecentFiles.Insert(0, OpenedMap);
6457 RefreshRecentMenu;
6459 SaveMap(OpenedMap);
6461 gMapInfo.FileName := SaveDialog.FileName;
6462 gMapInfo.MapName := SaveMapForm.eMapName.Text;
6463 UpdateCaption(gMapInfo.Name, ExtractFileName(gMapInfo.FileName), gMapInfo.MapName);
6464 end;
6466 procedure TMainForm.aSelectAllExecute(Sender: TObject);
6467 var
6468 a: Integer;
6469 begin
6470 RemoveSelectFromObjects();
6472 case pcObjects.ActivePageIndex+1 of
6473 OBJECT_PANEL:
6474 if gPanels <> nil then
6475 for a := 0 to High(gPanels) do
6476 if gPanels[a].PanelType <> PANEL_NONE then
6477 SelectObject(OBJECT_PANEL, a, True);
6478 OBJECT_ITEM:
6479 if gItems <> nil then
6480 for a := 0 to High(gItems) do
6481 if gItems[a].ItemType <> ITEM_NONE then
6482 SelectObject(OBJECT_ITEM, a, True);
6483 OBJECT_MONSTER:
6484 if gMonsters <> nil then
6485 for a := 0 to High(gMonsters) do
6486 if gMonsters[a].MonsterType <> MONSTER_NONE then
6487 SelectObject(OBJECT_MONSTER, a, True);
6488 OBJECT_AREA:
6489 if gAreas <> nil then
6490 for a := 0 to High(gAreas) do
6491 if gAreas[a].AreaType <> AREA_NONE then
6492 SelectObject(OBJECT_AREA, a, True);
6493 OBJECT_TRIGGER:
6494 if gTriggers <> nil then
6495 for a := 0 to High(gTriggers) do
6496 if gTriggers[a].TriggerType <> TRIGGER_NONE then
6497 SelectObject(OBJECT_TRIGGER, a, True);
6498 end;
6500 RecountSelectedObjects();
6501 end;
6503 procedure TMainForm.tbGridOnClick(Sender: TObject);
6504 begin
6505 DotEnable := not DotEnable;
6506 (Sender as TToolButton).Down := DotEnable;
6507 end;
6509 procedure TMainForm.OnIdle(Sender: TObject; var Done: Boolean);
6510 begin
6511 // FIXME: this is a shitty hack
6512 if not gDataLoaded then
6513 begin
6514 e_WriteLog('Init OpenGL', MSG_NOTIFY);
6515 e_InitGL();
6516 e_WriteLog('Loading data', MSG_NOTIFY);
6517 LoadStdFont('STDTXT', 'STDFONT', gEditorFont);
6518 e_WriteLog('Loading more data', MSG_NOTIFY);
6519 LoadData();
6520 e_WriteLog('Loading even more data', MSG_NOTIFY);
6521 gDataLoaded := True;
6522 MainForm.FormResize(nil);
6523 end;
6524 Draw();
6525 end;
6527 procedure TMainForm.miMapPreviewClick(Sender: TObject);
6528 begin
6529 if PreviewMode = 2 then
6530 Exit;
6532 if PreviewMode = 0 then
6533 begin
6534 Splitter2.Visible := False;
6535 Splitter1.Visible := False;
6536 StatusBar.Visible := False;
6537 PanelObjs.Visible := False;
6538 PanelProps.Visible := False;
6539 MainToolBar.Visible := False;
6540 sbHorizontal.Visible := False;
6541 sbVertical.Visible := False;
6542 end
6543 else
6544 begin
6545 StatusBar.Visible := True;
6546 PanelObjs.Visible := True;
6547 PanelProps.Visible := True;
6548 Splitter2.Visible := True;
6549 Splitter1.Visible := True;
6550 MainToolBar.Visible := True;
6551 sbHorizontal.Visible := True;
6552 sbVertical.Visible := True;
6553 end;
6555 PreviewMode := PreviewMode xor 1;
6556 (Sender as TMenuItem).Checked := PreviewMode > 0;
6558 FormResize(Self);
6559 end;
6561 procedure TMainForm.miLayer1Click(Sender: TObject);
6562 begin
6563 SwitchLayer(LAYER_BACK);
6564 end;
6566 procedure TMainForm.miLayer2Click(Sender: TObject);
6567 begin
6568 SwitchLayer(LAYER_WALLS);
6569 end;
6571 procedure TMainForm.miLayer3Click(Sender: TObject);
6572 begin
6573 SwitchLayer(LAYER_FOREGROUND);
6574 end;
6576 procedure TMainForm.miLayer4Click(Sender: TObject);
6577 begin
6578 SwitchLayer(LAYER_STEPS);
6579 end;
6581 procedure TMainForm.miLayer5Click(Sender: TObject);
6582 begin
6583 SwitchLayer(LAYER_WATER);
6584 end;
6586 procedure TMainForm.miLayer6Click(Sender: TObject);
6587 begin
6588 SwitchLayer(LAYER_ITEMS);
6589 end;
6591 procedure TMainForm.miLayer7Click(Sender: TObject);
6592 begin
6593 SwitchLayer(LAYER_MONSTERS);
6594 end;
6596 procedure TMainForm.miLayer8Click(Sender: TObject);
6597 begin
6598 SwitchLayer(LAYER_AREAS);
6599 end;
6601 procedure TMainForm.miLayer9Click(Sender: TObject);
6602 begin
6603 SwitchLayer(LAYER_TRIGGERS);
6604 end;
6606 procedure TMainForm.tbShowClick(Sender: TObject);
6607 var
6608 a: Integer;
6609 b: Boolean;
6610 begin
6611 b := True;
6612 for a := 0 to High(LayerEnabled) do
6613 b := b and LayerEnabled[a];
6615 b := not b;
6617 ShowLayer(LAYER_BACK, b);
6618 ShowLayer(LAYER_WALLS, b);
6619 ShowLayer(LAYER_FOREGROUND, b);
6620 ShowLayer(LAYER_STEPS, b);
6621 ShowLayer(LAYER_WATER, b);
6622 ShowLayer(LAYER_ITEMS, b);
6623 ShowLayer(LAYER_MONSTERS, b);
6624 ShowLayer(LAYER_AREAS, b);
6625 ShowLayer(LAYER_TRIGGERS, b);
6626 end;
6628 procedure TMainForm.miMiniMapClick(Sender: TObject);
6629 begin
6630 SwitchMap();
6631 end;
6633 procedure TMainForm.miSwitchGridClick(Sender: TObject);
6634 begin
6635 if DotStep = DotStepOne then
6636 DotStep := DotStepTwo
6637 else
6638 DotStep := DotStepOne;
6640 MousePos.X := (MousePos.X div DotStep) * DotStep;
6641 MousePos.Y := (MousePos.Y div DotStep) * DotStep;
6642 end;
6644 procedure TMainForm.miShowEdgesClick(Sender: TObject);
6645 begin
6646 ShowEdges();
6647 end;
6649 procedure TMainForm.miSnapToGridClick(Sender: TObject);
6650 begin
6651 SnapToGrid := not SnapToGrid;
6653 MousePos.X := (MousePos.X div DotStep) * DotStep;
6654 MousePos.Y := (MousePos.Y div DotStep) * DotStep;
6656 miSnapToGrid.Checked := SnapToGrid;
6657 end;
6659 procedure TMainForm.minexttabClick(Sender: TObject);
6660 begin
6661 if pcObjects.ActivePageIndex < pcObjects.PageCount-1 then
6662 pcObjects.ActivePageIndex := pcObjects.ActivePageIndex+1
6663 else
6664 pcObjects.ActivePageIndex := 0;
6665 end;
6667 procedure TMainForm.miSaveMiniMapClick(Sender: TObject);
6668 begin
6669 SaveMiniMapForm.ShowModal();
6670 end;
6672 procedure TMainForm.bClearTextureClick(Sender: TObject);
6673 begin
6674 lbTextureList.ItemIndex := -1;
6675 lTextureWidth.Caption := '';
6676 lTextureHeight.Caption := '';
6677 end;
6679 procedure TMainForm.miPackMapClick(Sender: TObject);
6680 begin
6681 PackMapForm.ShowModal();
6682 end;
6684 procedure TMainForm.miMapTestSettingsClick(Sender: TObject);
6685 begin
6686 MapTestForm.ShowModal();
6687 end;
6689 type SSArray = array of String;
6691 function ParseString (Str: AnsiString): SSArray;
6692 function GetStr (var Str: AnsiString): AnsiString;
6693 var a, b: Integer;
6694 begin
6695 Result := '';
6696 if Str[1] = '"' then
6697 for b := 1 to Length(Str) do
6698 if (b = Length(Str)) or (Str[b + 1] = '"') then
6699 begin
6700 Result := Copy(Str, 2, b - 1);
6701 Delete(Str, 1, b + 1);
6702 Str := Trim(Str);
6703 Exit;
6704 end;
6705 for a := 1 to Length(Str) do
6706 if (a = Length(Str)) or (Str[a + 1] = ' ') then
6707 begin
6708 Result := Copy(Str, 1, a);
6709 Delete(Str, 1, a + 1);
6710 Str := Trim(Str);
6711 Exit;
6712 end;
6713 end;
6714 begin
6715 Result := nil;
6716 Str := Trim(Str);
6717 while Str <> '' do
6718 begin
6719 SetLength(Result, Length(Result)+1);
6720 Result[High(Result)] := GetStr(Str);
6721 end;
6722 end;
6724 procedure TMainForm.miTestMapClick(Sender: TObject);
6725 var
6726 mapWAD, mapToRun, tempWAD: String;
6727 args: SSArray;
6728 opt: LongWord;
6729 time, i: Integer;
6730 proc: TProcessUTF8;
6731 res: Boolean;
6732 begin
6733 mapToRun := '';
6734 if OpenedMap <> '' then
6735 begin
6736 // Указываем текущую карту для теста:
6737 g_ProcessResourceStr(OpenedMap, @mapWAD, nil, @mapToRun);
6738 mapToRun := mapWAD + ':\' + mapToRun;
6739 mapToRun := ExtractRelativePath(ExtractFilePath(TestD2dExe) + 'maps/', mapToRun);
6740 end;
6741 // Сохраняем временную карту:
6742 time := 0;
6743 repeat
6744 mapWAD := ExtractFilePath(TestD2dExe) + Format('maps/temp%.4d.wad', [time]);
6745 Inc(time);
6746 until not FileExists(mapWAD);
6747 tempWAD := mapWAD + ':\' + TEST_MAP_NAME;
6748 SaveMap(tempWAD);
6750 tempWAD := ExtractRelativePath(ExtractFilePath(TestD2dExe) + 'maps/', tempWAD);
6751 // Если карта не была открыта, указываем временную в качестве текущей:
6752 if mapToRun = '' then
6753 mapToRun := tempWAD;
6755 // Опции игры:
6756 opt := 32 + 64;
6757 if TestOptionsTwoPlayers then
6758 opt := opt + 1;
6759 if TestOptionsTeamDamage then
6760 opt := opt + 2;
6761 if TestOptionsAllowExit then
6762 opt := opt + 4;
6763 if TestOptionsWeaponStay then
6764 opt := opt + 8;
6765 if TestOptionsMonstersDM then
6766 opt := opt + 16;
6768 // Запускаем:
6769 proc := TProcessUTF8.Create(nil);
6770 proc.Executable := TestD2dExe;
6771 proc.Parameters.Add('-map');
6772 proc.Parameters.Add(mapToRun);
6773 proc.Parameters.Add('-testmap');
6774 proc.Parameters.Add(tempWAD);
6775 proc.Parameters.Add('-gm');
6776 proc.Parameters.Add(TestGameMode);
6777 proc.Parameters.Add('-limt');
6778 proc.Parameters.Add(TestLimTime);
6779 proc.Parameters.Add('-lims');
6780 proc.Parameters.Add(TestLimScore);
6781 proc.Parameters.Add('-opt');
6782 proc.Parameters.Add(IntToStr(opt));
6783 proc.Parameters.Add('--debug');
6784 if TestMapOnce then
6785 proc.Parameters.Add('--close');
6787 args := ParseString(TestD2DArgs);
6788 for i := 0 to High(args) do
6789 proc.Parameters.Add(args[i]);
6791 res := True;
6792 try
6793 proc.Execute();
6794 except
6795 res := False;
6796 end;
6797 if res then
6798 begin
6799 Application.Minimize();
6800 proc.WaitOnExit();
6801 end;
6802 if (not res) or (proc.ExitCode < 0) then
6803 begin
6804 MessageBox(0, 'FIXME',
6805 PChar(_lc[I_MSG_EXEC_ERROR]),
6806 MB_OK or MB_ICONERROR);
6807 end;
6808 proc.Free();
6810 SysUtils.DeleteFile(mapWAD);
6811 Application.Restore();
6812 end;
6814 procedure TMainForm.sbVerticalScroll(Sender: TObject;
6815 ScrollCode: TScrollCode; var ScrollPos: Integer);
6816 begin
6817 MapOffset.Y := -sbVertical.Position;
6818 end;
6820 procedure TMainForm.sbHorizontalScroll(Sender: TObject;
6821 ScrollCode: TScrollCode; var ScrollPos: Integer);
6822 begin
6823 MapOffset.X := -sbHorizontal.Position;
6824 end;
6826 procedure TMainForm.miOpenWadMapClick(Sender: TObject);
6827 begin
6828 if OpenedWAD <> '' then
6829 begin
6830 OpenMap(OpenedWAD, '');
6831 end;
6832 end;
6834 procedure TMainForm.selectall1Click(Sender: TObject);
6835 var
6836 a: Integer;
6837 begin
6838 RemoveSelectFromObjects();
6840 if gPanels <> nil then
6841 for a := 0 to High(gPanels) do
6842 if gPanels[a].PanelType <> PANEL_NONE then
6843 SelectObject(OBJECT_PANEL, a, True);
6845 if gItems <> nil then
6846 for a := 0 to High(gItems) do
6847 if gItems[a].ItemType <> ITEM_NONE then
6848 SelectObject(OBJECT_ITEM, a, True);
6850 if gMonsters <> nil then
6851 for a := 0 to High(gMonsters) do
6852 if gMonsters[a].MonsterType <> MONSTER_NONE then
6853 SelectObject(OBJECT_MONSTER, a, True);
6855 if gAreas <> nil then
6856 for a := 0 to High(gAreas) do
6857 if gAreas[a].AreaType <> AREA_NONE then
6858 SelectObject(OBJECT_AREA, a, True);
6860 if gTriggers <> nil then
6861 for a := 0 to High(gTriggers) do
6862 if gTriggers[a].TriggerType <> TRIGGER_NONE then
6863 SelectObject(OBJECT_TRIGGER, a, True);
6865 RecountSelectedObjects();
6866 end;
6868 procedure TMainForm.Splitter1CanResize(Sender: TObject;
6869 var NewSize: Integer; var Accept: Boolean);
6870 begin
6871 Accept := (NewSize > 140);
6872 end;
6874 procedure TMainForm.Splitter2CanResize(Sender: TObject;
6875 var NewSize: Integer; var Accept: Boolean);
6876 begin
6877 Accept := (NewSize > 110);
6878 end;
6880 procedure TMainForm.vleObjectPropertyEnter(Sender: TObject);
6881 begin
6882 EditingProperties := True;
6883 end;
6885 procedure TMainForm.vleObjectPropertyExit(Sender: TObject);
6886 begin
6887 EditingProperties := False;
6888 end;
6890 procedure TMainForm.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
6891 begin
6892 // Объекты передвигались:
6893 if MainForm.ActiveControl = RenderPanel then
6894 begin
6895 if (Key = VK_NUMPAD4) or
6896 (Key = VK_NUMPAD6) or
6897 (Key = VK_NUMPAD8) or
6898 (Key = VK_NUMPAD5) or
6899 (Key = Ord('V')) then
6900 FillProperty();
6901 end;
6902 // Быстрое превью карты:
6903 if Key = Ord('E') then
6904 begin
6905 if PreviewMode = 2 then
6906 PreviewMode := 0;
6907 end;
6908 RenderPanelMouseMove(Sender, Shift, RenderMousePos().X, RenderMousePos().Y);
6909 end;
6911 end.