DEADSOFTWARE

Add contours
[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: Byte;
296 DotStepOne, DotStepTwo: Byte;
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: 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 < 0 then
710 MapOffset.X := 0;
711 if MapOffset.Y < 0 then
712 MapOffset.Y := 0;
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 end;
1415 TRIGGER_HEALTH:
1416 begin
1417 with ItemProps[InsertRow(_lc[I_PROP_TR_HEALTH], IntToStr(Data.HealValue), True)] do
1418 begin
1419 EditStyle := esSimple;
1420 MaxLength := 5;
1421 end;
1422 with ItemProps[InsertRow(_lc[I_PROP_TR_INTERVAL], IntToStr(Data.HealInterval), True)] do
1423 begin
1424 EditStyle := esSimple;
1425 MaxLength := 5;
1426 end;
1427 with ItemProps[InsertRow(_lc[I_PROP_TR_HEALTH_MAX], BoolNames[Data.HealMax], True)] do
1428 begin
1429 EditStyle := esPickList;
1430 ReadOnly := True;
1431 end;
1432 with ItemProps[InsertRow(_lc[I_PROP_TR_SILENT], BoolNames[Data.HealSilent], True)] do
1433 begin
1434 EditStyle := esPickList;
1435 ReadOnly := True;
1436 end;
1437 end;
1439 TRIGGER_SHOT:
1440 begin
1441 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_TYPE], ShotToStr(Data.ShotType), True)] do
1442 begin
1443 EditStyle := esEllipsis;
1444 ReadOnly := True;
1445 end;
1447 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_SOUND], BoolNames[Data.ShotSound], True)] do
1448 begin
1449 EditStyle := esPickList;
1450 ReadOnly := True;
1451 end;
1453 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_PANEL], IntToStr(Data.ShotPanelID), True)] do
1454 begin
1455 EditStyle := esEllipsis;
1456 ReadOnly := True;
1457 end;
1459 case Data.ShotTarget of
1460 1: str := _lc[I_PROP_TR_SHOT_TO_1];
1461 2: str := _lc[I_PROP_TR_SHOT_TO_2];
1462 3: str := _lc[I_PROP_TR_SHOT_TO_3];
1463 4: str := _lc[I_PROP_TR_SHOT_TO_4];
1464 5: str := _lc[I_PROP_TR_SHOT_TO_5];
1465 6: str := _lc[I_PROP_TR_SHOT_TO_6];
1466 else str := _lc[I_PROP_TR_SHOT_TO_0];
1467 end;
1468 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_TO], str, True)] do
1469 begin
1470 EditStyle := esPickList;
1471 ReadOnly := True;
1472 end;
1474 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_SIGHT], IntToStr(Data.ShotIntSight), True)] do
1475 begin
1476 EditStyle := esSimple;
1477 MaxLength := 3;
1478 end;
1480 case Data.ShotAim of
1481 1: str := _lc[I_PROP_TR_SHOT_AIM_1];
1482 2: str := _lc[I_PROP_TR_SHOT_AIM_2];
1483 3: str := _lc[I_PROP_TR_SHOT_AIM_3];
1484 else str := _lc[I_PROP_TR_SHOT_AIM_0];
1485 end;
1486 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_AIM], str, True)] do
1487 begin
1488 EditStyle := esPickList;
1489 ReadOnly := True;
1490 end;
1492 with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_TO],
1493 Format('(%d:%d)', [Data.ShotPos.X, Data.ShotPos.Y]), True)] do
1494 begin
1495 EditStyle := esEllipsis;
1496 ReadOnly := True;
1497 end;
1499 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_ANGLE], IntToStr(Data.ShotAngle), True)] do
1500 begin
1501 EditStyle := esSimple;
1502 MaxLength := 4;
1503 end;
1505 with ItemProps[InsertRow(_lc[I_PROP_TR_EX_DELAY], IntToStr(Data.ShotWait), True)] do
1506 begin
1507 EditStyle := esSimple;
1508 MaxLength := 5;
1509 end;
1511 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_ACC], IntToStr(Data.ShotAccuracy), True)] do
1512 begin
1513 EditStyle := esSimple;
1514 MaxLength := 5;
1515 end;
1517 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_AMMO], IntToStr(Data.ShotAmmo), True)] do
1518 begin
1519 EditStyle := esSimple;
1520 MaxLength := 5;
1521 end;
1523 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_RELOAD], IntToStr(Data.ShotIntReload), True)] do
1524 begin
1525 EditStyle := esSimple;
1526 MaxLength := 4;
1527 end;
1528 end;
1530 TRIGGER_EFFECT:
1531 begin
1532 with ItemProps[InsertRow(_lc[I_PROP_TR_COUNT], IntToStr(Data.FXCount), True)] do
1533 begin
1534 EditStyle := esSimple;
1535 MaxLength := 3;
1536 end;
1538 if Data.FXType = 0 then
1539 str := _lc[I_PROP_TR_EFFECT_PARTICLE]
1540 else
1541 str := _lc[I_PROP_TR_EFFECT_ANIMATION];
1542 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_TYPE], str, True)] do
1543 begin
1544 EditStyle := esEllipsis;
1545 ReadOnly := True;
1546 end;
1548 str := '';
1549 if Data.FXType = 0 then
1550 case Data.FXSubType of
1551 TRIGGER_EFFECT_SLIQUID:
1552 str := _lc[I_PROP_TR_EFFECT_SLIQUID];
1553 TRIGGER_EFFECT_LLIQUID:
1554 str := _lc[I_PROP_TR_EFFECT_LLIQUID];
1555 TRIGGER_EFFECT_DLIQUID:
1556 str := _lc[I_PROP_TR_EFFECT_DLIQUID];
1557 TRIGGER_EFFECT_BLOOD:
1558 str := _lc[I_PROP_TR_EFFECT_BLOOD];
1559 TRIGGER_EFFECT_SPARK:
1560 str := _lc[I_PROP_TR_EFFECT_SPARK];
1561 TRIGGER_EFFECT_BUBBLE:
1562 str := _lc[I_PROP_TR_EFFECT_BUBBLE];
1563 end;
1564 if Data.FXType = 1 then
1565 begin
1566 if (Data.FXSubType = 0) or (Data.FXSubType > EFFECT_FIRE) then
1567 Data.FXSubType := EFFECT_TELEPORT;
1568 str := EffectToStr(Data.FXSubType);
1569 end;
1570 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_SUBTYPE], str, True)] do
1571 begin
1572 EditStyle := esEllipsis;
1573 ReadOnly := True;
1574 end;
1576 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_COLOR], IntToStr(Data.FXColorR or (Data.FXColorG shl 8) or (Data.FXColorB shl 16)), True)] do
1577 begin
1578 EditStyle := esEllipsis;
1579 ReadOnly := True;
1580 end;
1582 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_CENTER], BoolNames[Data.FXPos = 0], True)] do
1583 begin
1584 EditStyle := esPickList;
1585 ReadOnly := True;
1586 end;
1588 with ItemProps[InsertRow(_lc[I_PROP_TR_EX_DELAY], IntToStr(Data.FXWait), True)] do
1589 begin
1590 EditStyle := esSimple;
1591 MaxLength := 5;
1592 end;
1594 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_VELX], IntToStr(Data.FXVelX), True)] do
1595 begin
1596 EditStyle := esSimple;
1597 MaxLength := 4;
1598 end;
1600 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_VELY], IntToStr(Data.FXVelY), True)] do
1601 begin
1602 EditStyle := esSimple;
1603 MaxLength := 4;
1604 end;
1606 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_SPL], IntToStr(Data.FXSpreadL), True)] do
1607 begin
1608 EditStyle := esSimple;
1609 MaxLength := 3;
1610 end;
1612 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_SPR], IntToStr(Data.FXSpreadR), True)] do
1613 begin
1614 EditStyle := esSimple;
1615 MaxLength := 3;
1616 end;
1618 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_SPU], IntToStr(Data.FXSpreadU), True)] do
1619 begin
1620 EditStyle := esSimple;
1621 MaxLength := 3;
1622 end;
1624 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_SPD], IntToStr(Data.FXSpreadD), True)] do
1625 begin
1626 EditStyle := esSimple;
1627 MaxLength := 3;
1628 end;
1629 end;
1630 end; //case TriggerType
1631 end;
1632 end; // OBJECT_TRIGGER:
1633 end;
1634 end;
1636 procedure ChangeShownProperty(Name: String; NewValue: String);
1637 var
1638 row: Integer;
1639 begin
1640 if SelectedObjectCount() <> 1 then
1641 Exit;
1642 if not SelectedObjects[GetFirstSelected()].Live then
1643 Exit;
1645 // Есть ли такой ключ:
1646 if MainForm.vleObjectProperty.FindRow(Name, row) then
1647 begin
1648 MainForm.vleObjectProperty.Values[Name] := NewValue;
1649 end;
1650 end;
1652 procedure SelectObject(fObjectType: Byte; fID: DWORD; Multi: Boolean);
1653 var
1654 a: Integer;
1655 b: Boolean;
1656 begin
1657 if Multi then
1658 begin
1659 b := False;
1661 // Уже выделен - убираем:
1662 if SelectedObjects <> nil then
1663 for a := 0 to High(SelectedObjects) do
1664 with SelectedObjects[a] do
1665 if Live and (ID = fID) and
1666 (ObjectType = fObjectType) then
1667 begin
1668 Live := False;
1669 b := True;
1670 end;
1672 if b then
1673 Exit;
1675 SetLength(SelectedObjects, Length(SelectedObjects)+1);
1677 with SelectedObjects[High(SelectedObjects)] do
1678 begin
1679 ObjectType := fObjectType;
1680 ID := fID;
1681 Live := True;
1682 end;
1683 end
1684 else // not Multi
1685 begin
1686 SetLength(SelectedObjects, 1);
1688 with SelectedObjects[0] do
1689 begin
1690 ObjectType := fObjectType;
1691 ID := fID;
1692 Live := True;
1693 end;
1694 end;
1696 MainForm.miCopy.Enabled := True;
1697 MainForm.miCut.Enabled := True;
1699 if fObjectType = OBJECT_PANEL then
1700 begin
1701 MainForm.miToFore.Enabled := True;
1702 MainForm.miToBack.Enabled := True;
1703 end;
1704 end;
1706 procedure RemoveSelectFromObjects();
1707 begin
1708 SelectedObjects := nil;
1709 DrawPressRect := False;
1710 MouseLDown := False;
1711 MouseRDown := False;
1712 MouseAction := MOUSEACTION_NONE;
1713 SelectFlag := SELECTFLAG_NONE;
1714 ResizeType := RESIZETYPE_NONE;
1715 ResizeDirection := RESIZEDIR_NONE;
1717 MainForm.vleObjectProperty.Strings.Clear();
1719 MainForm.miCopy.Enabled := False;
1720 MainForm.miCut.Enabled := False;
1721 MainForm.miToFore.Enabled := False;
1722 MainForm.miToBack.Enabled := False;
1723 end;
1725 procedure DeleteSelectedObjects();
1726 var
1727 i, a, ii: Integer;
1728 b: Boolean;
1729 begin
1730 if SelectedObjects = nil then
1731 Exit;
1733 b := False;
1734 i := 0;
1736 for a := 0 to High(SelectedObjects) do
1737 with SelectedObjects[a] do
1738 if Live then
1739 begin
1740 if not b then
1741 begin
1742 SetLength(UndoBuffer, Length(UndoBuffer)+1);
1743 i := High(UndoBuffer);
1744 b := True;
1745 end;
1747 SetLength(UndoBuffer[i], Length(UndoBuffer[i])+1);
1748 ii := High(UndoBuffer[i]);
1750 case ObjectType of
1751 OBJECT_PANEL:
1752 begin
1753 UndoBuffer[i, ii].UndoType := UNDO_DELETE_PANEL;
1754 New(UndoBuffer[i, ii].Panel);
1755 UndoBuffer[i, ii].Panel^ := gPanels[ID];
1756 end;
1757 OBJECT_ITEM:
1758 begin
1759 UndoBuffer[i, ii].UndoType := UNDO_DELETE_ITEM;
1760 UndoBuffer[i, ii].Item := gItems[ID];
1761 end;
1762 OBJECT_AREA:
1763 begin
1764 UndoBuffer[i, ii].UndoType := UNDO_DELETE_AREA;
1765 UndoBuffer[i, ii].Area := gAreas[ID];
1766 end;
1767 OBJECT_TRIGGER:
1768 begin
1769 UndoBuffer[i, ii].UndoType := UNDO_DELETE_TRIGGER;
1770 UndoBuffer[i, ii].Trigger := gTriggers[ID];
1771 end;
1772 end;
1774 RemoveObject(ID, ObjectType);
1775 end;
1777 RemoveSelectFromObjects();
1779 MainForm.miUndo.Enabled := UndoBuffer <> nil;
1780 MainForm.RecountSelectedObjects();
1781 end;
1783 procedure Undo_Add(ObjectType: Byte; ID: DWORD; Group: Boolean = False);
1784 var
1785 i, ii: Integer;
1786 begin
1787 if (not Group) or (Length(UndoBuffer) = 0) then
1788 SetLength(UndoBuffer, Length(UndoBuffer)+1);
1789 SetLength(UndoBuffer[High(UndoBuffer)], Length(UndoBuffer[High(UndoBuffer)])+1);
1790 i := High(UndoBuffer);
1791 ii := High(UndoBuffer[i]);
1793 case ObjectType of
1794 OBJECT_PANEL:
1795 UndoBuffer[i, ii].UndoType := UNDO_ADD_PANEL;
1796 OBJECT_ITEM:
1797 UndoBuffer[i, ii].UndoType := UNDO_ADD_ITEM;
1798 OBJECT_MONSTER:
1799 UndoBuffer[i, ii].UndoType := UNDO_ADD_MONSTER;
1800 OBJECT_AREA:
1801 UndoBuffer[i, ii].UndoType := UNDO_ADD_AREA;
1802 OBJECT_TRIGGER:
1803 UndoBuffer[i, ii].UndoType := UNDO_ADD_TRIGGER;
1804 end;
1806 UndoBuffer[i, ii].AddID := ID;
1808 MainForm.miUndo.Enabled := UndoBuffer <> nil;
1809 end;
1811 procedure FullClear();
1812 begin
1813 RemoveSelectFromObjects();
1814 ClearMap();
1815 LoadSky(gMapInfo.SkyName);
1816 UndoBuffer := nil;
1817 slInvalidTextures.Clear();
1818 MapCheckForm.lbErrorList.Clear();
1819 MapCheckForm.mErrorDescription.Clear();
1821 MainForm.miUndo.Enabled := False;
1822 MainForm.sbHorizontal.Position := 0;
1823 MainForm.sbVertical.Position := 0;
1824 MainForm.FormResize(nil);
1825 MainForm.Caption := FormCaption;
1826 OpenedMap := '';
1827 OpenedWAD := '';
1828 end;
1830 procedure ErrorMessageBox(str: String);
1831 begin
1832 MessageBox(0, PChar(str), PChar(_lc[I_MSG_ERROR]),
1833 MB_ICONINFORMATION or MB_OK or MB_DEFBUTTON1);
1834 end;
1836 function CheckProperty(): Boolean;
1837 var
1838 _id: Integer;
1839 begin
1840 Result := False;
1842 _id := GetFirstSelected();
1844 if SelectedObjects[_id].ObjectType = OBJECT_PANEL then
1845 with gPanels[SelectedObjects[_id].ID] do
1846 begin
1847 if TextureWidth <> 0 then
1848 if StrToIntDef(MainForm.vleObjectProperty.Values[_lc[I_PROP_WIDTH]], 1) mod TextureWidth <> 0 then
1849 begin
1850 ErrorMessageBox(Format(_lc[I_MSG_WRONG_TEXWIDTH],
1851 [TextureWidth]));
1852 Exit;
1853 end;
1855 if TextureHeight <> 0 then
1856 if StrToIntDef(Trim(MainForm.vleObjectProperty.Values[_lc[I_PROP_HEIGHT]]), 1) mod TextureHeight <> 0 then
1857 begin
1858 ErrorMessageBox(Format(_lc[I_MSG_WRONG_TEXHEIGHT],
1859 [TextureHeight]));
1860 Exit;
1861 end;
1863 if IsTexturedPanel(PanelType) and (TextureName <> '') then
1864 if not (StrToIntDef(MainForm.vleObjectProperty.Values[_lc[I_PROP_PANEL_ALPHA]], -1) in [0..255]) then
1865 begin
1866 ErrorMessageBox(_lc[I_MSG_WRONG_ALPHA]);
1867 Exit;
1868 end;
1869 end;
1871 if SelectedObjects[_id].ObjectType in [OBJECT_PANEL, OBJECT_TRIGGER] then
1872 if (StrToIntDef(MainForm.vleObjectProperty.Values[_lc[I_PROP_WIDTH]], 0) <= 0) or
1873 (StrToIntDef(MainForm.vleObjectProperty.Values[_lc[I_PROP_HEIGHT]], 0) <= 0) then
1874 begin
1875 ErrorMessageBox(_lc[I_MSG_WRONG_SIZE]);
1876 Exit;
1877 end;
1879 if (Trim(MainForm.vleObjectProperty.Values[_lc[I_PROP_X]]) = '') or
1880 (Trim(MainForm.vleObjectProperty.Values[_lc[I_PROP_Y]]) = '') then
1881 begin
1882 ErrorMessageBox(_lc[I_MSG_WRONG_XY]);
1883 Exit;
1884 end;
1886 Result := True;
1887 end;
1889 procedure SelectTexture(ID: Integer);
1890 begin
1891 MainForm.lbTextureList.ItemIndex := ID;
1892 MainForm.lbTextureListClick(nil);
1893 end;
1895 function AddTexture(aWAD, aSection, aTex: String; silent: Boolean): Boolean;
1896 var
1897 a, FrameLen: Integer;
1898 ok: Boolean;
1899 FileName: String;
1900 ResourceName: String;
1901 FullResourceName: String;
1902 SectionName: String;
1903 Data: Pointer;
1904 Width, Height: Word;
1905 fn: String;
1906 begin
1907 Data := nil;
1908 FrameLen := 0;
1909 Width := 0;
1910 Height := 0;
1912 if aSection = '..' then
1913 SectionName := ''
1914 else
1915 SectionName := aSection;
1917 if aWAD = '' then
1918 aWAD := _lc[I_WAD_SPECIAL_MAP];
1920 if aWAD = _lc[I_WAD_SPECIAL_MAP] then
1921 begin // Файл карты
1922 g_ProcessResourceStr(OpenedMap, @fn, nil, nil);
1923 //FileName := EditorDir+'maps\'+ExtractFileName(fn);
1924 FileName := fn;
1925 ResourceName := ':'+SectionName+'\'+aTex;
1926 end
1927 else
1928 if aWAD = _lc[I_WAD_SPECIAL_TEXS] then
1929 begin // Спец. текстуры
1930 FileName := '';
1931 ResourceName := aTex;
1932 end
1933 else
1934 begin // Внешний WAD
1935 FileName := EditorDir+'wads/'+aWAD;
1936 ResourceName := aWAD+':'+SectionName+'\'+aTex;
1937 end;
1939 ok := True;
1941 // Есть ли уже такая текстура:
1942 for a := 0 to MainForm.lbTextureList.Items.Count-1 do
1943 if ResourceName = MainForm.lbTextureList.Items[a] then
1944 begin
1945 if not silent then
1946 ErrorMessageBox(Format(_lc[I_MSG_TEXTURE_ALREADY],
1947 [ResourceName]));
1948 ok := False;
1949 end;
1951 // Название ресурса <= 64 символов:
1952 if Length(ResourceName) > 64 then
1953 begin
1954 if not silent then
1955 ErrorMessageBox(Format(_lc[I_MSG_RES_NAME_64],
1956 [ResourceName]));
1957 ok := False;
1958 end;
1960 if ok then
1961 begin
1962 a := -1;
1963 if aWAD = _lc[I_WAD_SPECIAL_TEXS] then
1964 begin
1965 a := MainForm.lbTextureList.Items.Add(ResourceName);
1966 if not silent then
1967 SelectTexture(a);
1968 Result := True;
1969 Exit;
1970 end;
1972 FullResourceName := FileName+':'+SectionName+'\'+aTex;
1974 if IsAnim(FullResourceName) then
1975 begin // Аним. текстура
1976 GetFrame(FullResourceName, Data, FrameLen, Width, Height);
1978 if not g_CreateTextureMemorySize(Data, FrameLen, ResourceName, 0, 0, Width, Height, 1) then
1979 ok := False;
1980 a := MainForm.lbTextureList.Items.Add(ResourceName);
1981 end
1982 else // Обычная текстура
1983 begin
1984 if not g_CreateTextureWAD(ResourceName, FullResourceName) then
1985 ok := False;
1986 a := MainForm.lbTextureList.Items.Add(ResourceName);
1987 end;
1988 if (not ok) and (slInvalidTextures.IndexOf(ResourceName) = -1) then
1989 begin
1990 slInvalidTextures.Add(ResourceName);
1991 ok := True;
1992 end;
1993 if (a > -1) and (not silent) then
1994 SelectTexture(a);
1995 end;
1997 Result := ok;
1998 end;
2000 procedure UpdateCaption(sMap, sFile, sRes: String);
2001 begin
2002 with MainForm do
2003 if (sFile = '') and (sRes = '') and (sMap = '') then
2004 Caption := FormCaption
2005 else
2006 if sMap = '' then
2007 Caption := Format('%s - %s:%s', [FormCaption, sFile, sRes])
2008 else
2009 if (sFile <> '') and (sRes <> '') then
2010 Caption := Format('%s - %s (%s:%s)', [FormCaption, sMap, sFile, sRes])
2011 else
2012 Caption := Format('%s - %s', [FormCaption, sMap]);
2013 end;
2015 procedure OpenMap(FileName: String; mapN: String);
2016 var
2017 MapName: String;
2018 idx: Integer;
2019 begin
2020 SelectMapForm.Caption := _lc[I_CAP_OPEN];
2021 SelectMapForm.GetMaps(FileName);
2023 if (FileName = OpenedWAD) and
2024 (OpenedMap <> '') then
2025 begin
2026 MapName := OpenedMap;
2027 while (Pos(':\', MapName) > 0) do
2028 Delete(MapName, 1, Pos(':\', MapName) + 1);
2030 idx := SelectMapForm.lbMapList.Items.IndexOf(MapName);
2031 SelectMapForm.lbMapList.ItemIndex := idx;
2032 end
2033 else
2034 if SelectMapForm.lbMapList.Count > 0 then
2035 SelectMapForm.lbMapList.ItemIndex := 0
2036 else
2037 SelectMapForm.lbMapList.ItemIndex := -1;
2039 if mapN = '' then
2040 idx := -1
2041 else
2042 idx := SelectMapForm.lbMapList.Items.IndexOf(mapN);
2044 if idx < 0 then
2045 begin
2046 if (SelectMapForm.ShowModal() = mrOK) and
2047 (SelectMapForm.lbMapList.ItemIndex <> -1) then
2048 idx := SelectMapForm.lbMapList.ItemIndex
2049 else
2050 Exit;
2051 end;
2053 MapName := SelectMapForm.lbMapList.Items[idx];
2055 with MainForm do
2056 begin
2057 FullClear();
2059 pLoadProgress.Left := (RenderPanel.Width div 2)-(pLoadProgress.Width div 2);
2060 pLoadProgress.Top := (RenderPanel.Height div 2)-(pLoadProgress.Height div 2);
2061 pLoadProgress.Show();
2063 OpenedMap := FileName+':\'+MapName;
2064 OpenedWAD := FileName;
2066 idx := RecentFiles.IndexOf(OpenedMap);
2067 // Такая карта уже недавно открывалась:
2068 if idx >= 0 then
2069 RecentFiles.Delete(idx);
2070 RecentFiles.Insert(0, OpenedMap);
2071 RefreshRecentMenu();
2073 LoadMap(OpenedMap);
2075 pLoadProgress.Hide();
2076 FormResize(nil);
2078 lbTextureList.Sorted := True;
2079 lbTextureList.Sorted := False;
2081 UpdateCaption(gMapInfo.Name, ExtractFileName(FileName), MapName);
2082 end;
2083 end;
2085 procedure MoveSelectedObjects(Wall, alt: Boolean; dx, dy: Integer);
2086 var
2087 okX, okY: Boolean;
2088 a: Integer;
2089 begin
2090 if SelectedObjects = nil then
2091 Exit;
2093 okX := True;
2094 okY := True;
2096 if Wall then
2097 for a := 0 to High(SelectedObjects) do
2098 if SelectedObjects[a].Live then
2099 begin
2100 if ObjectCollideLevel(SelectedObjects[a].ID, SelectedObjects[a].ObjectType, dx, 0) then
2101 okX := False;
2103 if ObjectCollideLevel(SelectedObjects[a].ID, SelectedObjects[a].ObjectType, 0, dy) then
2104 okY := False;
2106 if (not okX) or (not okY) then
2107 Break;
2108 end;
2110 if okX or okY then
2111 begin
2112 for a := 0 to High(SelectedObjects) do
2113 if SelectedObjects[a].Live then
2114 begin
2115 if okX then
2116 MoveObject(SelectedObjects[a].ObjectType, SelectedObjects[a].ID, dx, 0);
2118 if okY then
2119 MoveObject(SelectedObjects[a].ObjectType, SelectedObjects[a].ID, 0, dy);
2121 if alt and (SelectedObjects[a].ObjectType = OBJECT_TRIGGER) then
2122 begin
2123 if gTriggers[SelectedObjects[a].ID].TriggerType in [TRIGGER_PRESS,
2124 TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF] then
2125 begin // Двигаем зону Расширителя
2126 if okX then
2127 gTriggers[SelectedObjects[a].ID].Data.tX := gTriggers[SelectedObjects[a].ID].Data.tX+dx;
2128 if okY then
2129 gTriggers[SelectedObjects[a].ID].Data.tY := gTriggers[SelectedObjects[a].ID].Data.tY+dy;
2130 end;
2132 if gTriggers[SelectedObjects[a].ID].TriggerType in [TRIGGER_TELEPORT] then
2133 begin // Двигаем точку назначения Телепорта
2134 if okX then
2135 gTriggers[SelectedObjects[a].ID].Data.TargetPoint.X := gTriggers[SelectedObjects[a].ID].Data.TargetPoint.X+dx;
2136 if okY then
2137 gTriggers[SelectedObjects[a].ID].Data.TargetPoint.Y := gTriggers[SelectedObjects[a].ID].Data.TargetPoint.Y+dy;
2138 end;
2140 if gTriggers[SelectedObjects[a].ID].TriggerType in [TRIGGER_SPAWNMONSTER] then
2141 begin // Двигаем точку создания монстра
2142 if okX then
2143 gTriggers[SelectedObjects[a].ID].Data.MonPos.X := gTriggers[SelectedObjects[a].ID].Data.MonPos.X+dx;
2144 if okY then
2145 gTriggers[SelectedObjects[a].ID].Data.MonPos.Y := gTriggers[SelectedObjects[a].ID].Data.MonPos.Y+dy;
2146 end;
2148 if gTriggers[SelectedObjects[a].ID].TriggerType in [TRIGGER_SPAWNITEM] then
2149 begin // Двигаем точку создания предмета
2150 if okX then
2151 gTriggers[SelectedObjects[a].ID].Data.ItemPos.X := gTriggers[SelectedObjects[a].ID].Data.ItemPos.X+dx;
2152 if okY then
2153 gTriggers[SelectedObjects[a].ID].Data.ItemPos.Y := gTriggers[SelectedObjects[a].ID].Data.ItemPos.Y+dy;
2154 end;
2156 if gTriggers[SelectedObjects[a].ID].TriggerType in [TRIGGER_SHOT] then
2157 begin // Двигаем точку создания выстрела
2158 if okX then
2159 gTriggers[SelectedObjects[a].ID].Data.ShotPos.X := gTriggers[SelectedObjects[a].ID].Data.ShotPos.X+dx;
2160 if okY then
2161 gTriggers[SelectedObjects[a].ID].Data.ShotPos.Y := gTriggers[SelectedObjects[a].ID].Data.ShotPos.Y+dy;
2162 end;
2163 end;
2164 end;
2166 LastMovePoint := MousePos;
2167 end;
2168 end;
2170 procedure ShowLayer(Layer: Byte; show: Boolean);
2171 begin
2172 LayerEnabled[Layer] := show;
2174 case Layer of
2175 LAYER_BACK:
2176 begin
2177 MainForm.miLayer1.Checked := show;
2178 MainForm.miLayerP1.Checked := show;
2179 end;
2180 LAYER_WALLS:
2181 begin
2182 MainForm.miLayer2.Checked := show;
2183 MainForm.miLayerP2.Checked := show;
2184 end;
2185 LAYER_FOREGROUND:
2186 begin
2187 MainForm.miLayer3.Checked := show;
2188 MainForm.miLayerP3.Checked := show;
2189 end;
2190 LAYER_STEPS:
2191 begin
2192 MainForm.miLayer4.Checked := show;
2193 MainForm.miLayerP4.Checked := show;
2194 end;
2195 LAYER_WATER:
2196 begin
2197 MainForm.miLayer5.Checked := show;
2198 MainForm.miLayerP5.Checked := show;
2199 end;
2200 LAYER_ITEMS:
2201 begin
2202 MainForm.miLayer6.Checked := show;
2203 MainForm.miLayerP6.Checked := show;
2204 end;
2205 LAYER_MONSTERS:
2206 begin
2207 MainForm.miLayer7.Checked := show;
2208 MainForm.miLayerP7.Checked := show;
2209 end;
2210 LAYER_AREAS:
2211 begin
2212 MainForm.miLayer8.Checked := show;
2213 MainForm.miLayerP8.Checked := show;
2214 end;
2215 LAYER_TRIGGERS:
2216 begin
2217 MainForm.miLayer9.Checked := show;
2218 MainForm.miLayerP9.Checked := show;
2219 end;
2220 end;
2222 RemoveSelectFromObjects();
2223 end;
2225 procedure SwitchLayer(Layer: Byte);
2226 begin
2227 ShowLayer(Layer, not LayerEnabled[Layer]);
2228 end;
2230 procedure SwitchMap();
2231 begin
2232 ShowMap := not ShowMap;
2233 MainForm.tbShowMap.Down := ShowMap;
2234 end;
2236 procedure ShowEdges();
2237 begin
2238 if drEdge[3] < 255 then
2239 drEdge[3] := 255
2240 else
2241 drEdge[3] := gAlphaEdge;
2242 end;
2244 function SelectedTexture(): String;
2245 begin
2246 if MainForm.lbTextureList.ItemIndex <> -1 then
2247 Result := MainForm.lbTextureList.Items[MainForm.lbTextureList.ItemIndex]
2248 else
2249 Result := '';
2250 end;
2252 function IsSpecialTextureSel(): Boolean;
2253 begin
2254 Result := (MainForm.lbTextureList.ItemIndex <> -1) and
2255 IsSpecialTexture(MainForm.lbTextureList.Items[MainForm.lbTextureList.ItemIndex]);
2256 end;
2258 function CopyBufferToString(var CopyBuf: TCopyRecArray): String;
2259 var
2260 i, j: Integer;
2261 Res: String;
2263 procedure AddInt(x: Integer);
2264 begin
2265 Res := Res + IntToStr(x) + ' ';
2266 end;
2268 begin
2269 Result := '';
2271 if Length(CopyBuf) = 0 then
2272 Exit;
2274 Res := CLIPBOARD_SIG + ' ';
2276 for i := 0 to High(CopyBuf) do
2277 begin
2278 if (CopyBuf[i].ObjectType = OBJECT_PANEL) and
2279 (CopyBuf[i].Panel = nil) then
2280 Continue;
2282 // Тип объекта:
2283 AddInt(CopyBuf[i].ObjectType);
2284 Res := Res + '; ';
2286 // Свойства объекта:
2287 case CopyBuf[i].ObjectType of
2288 OBJECT_PANEL:
2289 with CopyBuf[i].Panel^ do
2290 begin
2291 AddInt(PanelType);
2292 AddInt(X);
2293 AddInt(Y);
2294 AddInt(Width);
2295 AddInt(Height);
2296 Res := Res + '"' + TextureName + '" ';
2297 AddInt(Alpha);
2298 AddInt(IfThen(Blending, 1, 0));
2299 end;
2301 OBJECT_ITEM:
2302 with CopyBuf[i].Item do
2303 begin
2304 AddInt(ItemType);
2305 AddInt(X);
2306 AddInt(Y);
2307 AddInt(IfThen(OnlyDM, 1, 0));
2308 AddInt(IfThen(Fall, 1, 0));
2309 end;
2311 OBJECT_MONSTER:
2312 with CopyBuf[i].Monster do
2313 begin
2314 AddInt(MonsterType);
2315 AddInt(X);
2316 AddInt(Y);
2317 AddInt(IfThen(Direction = D_LEFT, 1, 0));
2318 end;
2320 OBJECT_AREA:
2321 with CopyBuf[i].Area do
2322 begin
2323 AddInt(AreaType);
2324 AddInt(X);
2325 AddInt(Y);
2326 AddInt(IfThen(Direction = D_LEFT, 1, 0));
2327 end;
2329 OBJECT_TRIGGER:
2330 with CopyBuf[i].Trigger do
2331 begin
2332 AddInt(TriggerType);
2333 AddInt(X);
2334 AddInt(Y);
2335 AddInt(Width);
2336 AddInt(Height);
2337 AddInt(ActivateType);
2338 AddInt(Key);
2339 AddInt(IfThen(Enabled, 1, 0));
2340 AddInt(TexturePanel);
2342 for j := 0 to 127 do
2343 AddInt(Data.Default[j]);
2344 end;
2345 end;
2346 end;
2348 Result := Res;
2349 end;
2351 procedure StringToCopyBuffer(Str: String; var CopyBuf: TCopyRecArray;
2352 var pmin: TPoint);
2353 var
2354 i, j, t: Integer;
2356 function GetNext(): String;
2357 var
2358 p: Integer;
2360 begin
2361 if Str[1] = '"' then
2362 begin
2363 Delete(Str, 1, 1);
2364 p := Pos('"', Str);
2366 if p = 0 then
2367 begin
2368 Result := Str;
2369 Str := '';
2370 end
2371 else
2372 begin
2373 Result := Copy(Str, 1, p-1);
2374 Delete(Str, 1, p);
2375 Str := Trim(Str);
2376 end;
2377 end
2378 else
2379 begin
2380 p := Pos(' ', Str);
2382 if p = 0 then
2383 begin
2384 Result := Str;
2385 Str := '';
2386 end
2387 else
2388 begin
2389 Result := Copy(Str, 1, p-1);
2390 Delete(Str, 1, p);
2391 Str := Trim(Str);
2392 end;
2393 end;
2394 end;
2396 begin
2397 Str := Trim(Str);
2399 if GetNext() <> CLIPBOARD_SIG then
2400 Exit;
2402 while Str <> '' do
2403 begin
2404 // Тип объекта:
2405 t := StrToIntDef(GetNext(), 0);
2407 if (t < OBJECT_PANEL) or (t > OBJECT_TRIGGER) or
2408 (GetNext() <> ';') then
2409 begin // Что-то не то => пропускаем:
2410 t := Pos(';', Str);
2411 Delete(Str, 1, t);
2412 Str := Trim(Str);
2414 Continue;
2415 end;
2417 i := Length(CopyBuf);
2418 SetLength(CopyBuf, i + 1);
2420 CopyBuf[i].ObjectType := t;
2421 CopyBuf[i].Panel := nil;
2423 // Свойства объекта:
2424 case t of
2425 OBJECT_PANEL:
2426 begin
2427 New(CopyBuf[i].Panel);
2429 with CopyBuf[i].Panel^ do
2430 begin
2431 PanelType := StrToIntDef(GetNext(), PANEL_WALL);
2432 X := StrToIntDef(GetNext(), 0);
2433 Y := StrToIntDef(GetNext(), 0);
2434 pmin.X := Min(X, pmin.X);
2435 pmin.Y := Min(Y, pmin.Y);
2436 Width := StrToIntDef(GetNext(), 16);
2437 Height := StrToIntDef(GetNext(), 16);
2438 TextureName := GetNext();
2439 Alpha := StrToIntDef(GetNext(), 0);
2440 Blending := (GetNext() = '1');
2441 end;
2442 end;
2444 OBJECT_ITEM:
2445 with CopyBuf[i].Item do
2446 begin
2447 ItemType := StrToIntDef(GetNext(), ITEM_MEDKIT_SMALL);
2448 X := StrToIntDef(GetNext(), 0);
2449 Y := StrToIntDef(GetNext(), 0);
2450 pmin.X := Min(X, pmin.X);
2451 pmin.Y := Min(Y, pmin.Y);
2452 OnlyDM := (GetNext() = '1');
2453 Fall := (GetNext() = '1');
2454 end;
2456 OBJECT_MONSTER:
2457 with CopyBuf[i].Monster do
2458 begin
2459 MonsterType := StrToIntDef(GetNext(), MONSTER_DEMON);
2460 X := StrToIntDef(GetNext(), 0);
2461 Y := StrToIntDef(GetNext(), 0);
2462 pmin.X := Min(X, pmin.X);
2463 pmin.Y := Min(Y, pmin.Y);
2465 if GetNext() = '1' then
2466 Direction := D_LEFT
2467 else
2468 Direction := D_RIGHT;
2469 end;
2471 OBJECT_AREA:
2472 with CopyBuf[i].Area do
2473 begin
2474 AreaType := StrToIntDef(GetNext(), AREA_PLAYERPOINT1);
2475 X := StrToIntDef(GetNext(), 0);
2476 Y := StrToIntDef(GetNext(), 0);
2477 pmin.X := Min(X, pmin.X);
2478 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_TRIGGER:
2486 with CopyBuf[i].Trigger do
2487 begin
2488 TriggerType := StrToIntDef(GetNext(), TRIGGER_EXIT);
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 Width := StrToIntDef(GetNext(), 16);
2494 Height := StrToIntDef(GetNext(), 16);
2495 ActivateType := StrToIntDef(GetNext(), 0);
2496 Key := StrToIntDef(GetNext(), 0);
2497 Enabled := (GetNext() = '1');
2498 TexturePanel := StrToIntDef(GetNext(), 0);
2500 for j := 0 to 127 do
2501 Data.Default[j] := StrToIntDef(GetNext(), 0);
2503 case TriggerType of
2504 TRIGGER_TELEPORT:
2505 begin
2506 pmin.X := Min(Data.TargetPoint.X, pmin.X);
2507 pmin.Y := Min(Data.TargetPoint.Y, pmin.Y);
2508 end;
2509 TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF:
2510 begin
2511 pmin.X := Min(Data.tX, pmin.X);
2512 pmin.Y := Min(Data.tY, pmin.Y);
2513 end;
2514 TRIGGER_SPAWNMONSTER:
2515 begin
2516 pmin.X := Min(Data.MonPos.X, pmin.X);
2517 pmin.Y := Min(Data.MonPos.Y, pmin.Y);
2518 end;
2519 TRIGGER_SPAWNITEM:
2520 begin
2521 pmin.X := Min(Data.ItemPos.X, pmin.X);
2522 pmin.Y := Min(Data.ItemPos.Y, pmin.Y);
2523 end;
2524 TRIGGER_SHOT:
2525 begin
2526 pmin.X := Min(Data.ShotPos.X, pmin.X);
2527 pmin.Y := Min(Data.ShotPos.Y, pmin.Y);
2528 end;
2529 end;
2530 end;
2531 end;
2532 end;
2533 end;
2535 //----------------------------------------
2536 //Закончились вспомогательные процедуры
2537 //----------------------------------------
2539 procedure TMainForm.RefreshRecentMenu();
2540 var
2541 i: Integer;
2542 MI: TMenuItem;
2543 begin
2544 // Лишние запомненные карты:
2545 while RecentFiles.Count > RecentCount do
2546 RecentFiles.Delete(RecentFiles.Count-1);
2548 // Лишние строки меню:
2549 while MainMenu.Items[0].Count > RECENT_FILES_MENU_START do
2550 MainMenu.Items[0].Delete(MainMenu.Items[0].Count-1);
2552 // Отделение списка карт от строки "Выход":
2553 if RecentFiles.Count > 0 then
2554 begin
2555 MI := TMenuItem.Create(MainMenu.Items[0]);
2556 MI.Caption := '-';
2557 MainMenu.Items[0].Add(MI);
2558 end;
2560 // Добавление в меню списка запомненных карт:
2561 for i := 0 to RecentFiles.Count-1 do
2562 begin
2563 MI := TMenuItem.Create(MainMenu.Items[0]);
2564 MI.Caption := IntToStr(i+1) + ' ' + RecentFiles[i];
2565 MI.OnClick := aRecentFileExecute;
2566 MainMenu.Items[0].Add(MI);
2567 end;
2568 end;
2570 procedure TMainForm.aRecentFileExecute(Sender: TObject);
2571 var
2572 n, pw: Integer;
2573 s, fn: String;
2574 b: Boolean;
2575 begin
2576 s := LowerCase((Sender as TMenuItem).Caption);
2577 Delete(s, Pos('&', s), 1);
2578 s := Trim(Copy(s, 1, 2));
2579 n := StrToIntDef(s, 0) - 1;
2581 if (n < 0) or (n >= RecentFiles.Count) then
2582 Exit;
2584 s := RecentFiles[n];
2585 pw := Pos('.wad:\', LowerCase(s));
2586 b := False;
2588 if pw > 0 then
2589 begin // Map name included
2590 fn := Copy(s, 1, pw + 3);
2591 Delete(s, 1, pw + 5);
2592 if (FileExists(fn)) then
2593 begin
2594 OpenMap(fn, s);
2595 b := True;
2596 end;
2597 end
2598 else // Only wad name
2599 if (FileExists(s)) then
2600 begin
2601 OpenMap(s, '');
2602 b := True;
2603 end;
2605 if (not b) and (MessageBox(0, PChar(_lc[I_MSG_DEL_RECENT_PROMT]),
2606 PChar(_lc[I_MSG_DEL_RECENT]), MB_ICONQUESTION or MB_YESNO) = idYes) then
2607 begin
2608 RecentFiles.Delete(n);
2609 RefreshRecentMenu();
2610 end;
2611 end;
2613 procedure TMainForm.aEditorOptionsExecute(Sender: TObject);
2614 begin
2615 OptionsForm.ShowModal();
2616 end;
2618 procedure LoadStdFont(cfgres, texture: string; var FontID: DWORD);
2619 var
2620 cwdt, chgt: Byte;
2621 spc: ShortInt;
2622 ID: DWORD;
2623 cfgdata: Pointer;
2624 cfglen: Integer;
2625 config: TConfig;
2626 begin
2627 ID := 0;
2628 g_ReadResource(EditorDir + 'data/game.wad', 'FONTS', cfgres, cfgdata, cfglen);
2629 if cfgdata <> nil then
2630 begin
2631 if not g_CreateTextureWAD('FONT_STD', EditorDir + 'data/game.wad:FONTS\' + texture) then
2632 e_WriteLog('ERROR ERROR ERROR', MSG_WARNING);
2634 config := TConfig.CreateMem(cfgdata, cfglen);
2635 cwdt := Min(Max(config.ReadInt('FontMap', 'CharWidth', 0), 0), 255);
2636 chgt := Min(Max(config.ReadInt('FontMap', 'CharHeight', 0), 0), 255);
2637 spc := Min(Max(config.ReadInt('FontMap', 'Kerning', 0), -128), 127);
2639 if g_GetTexture('FONT_STD', ID) then
2640 e_TextureFontBuild(ID, FontID, cwdt, chgt, spc - 2);
2642 config.Free();
2643 FreeMem(cfgdata)
2644 end
2645 else
2646 begin
2647 e_WriteLog('Could not load FONT_STD', MSG_WARNING)
2648 end
2649 end;
2651 procedure TMainForm.FormCreate(Sender: TObject);
2652 var
2653 config: TConfig;
2654 i: Integer;
2655 s: String;
2656 begin
2657 Randomize();
2659 EditorDir := ExtractFilePath(Application.ExeName);
2661 e_InitLog(EditorDir+'Editor.log', WM_NEWFILE);
2663 slInvalidTextures := TStringList.Create;
2665 ShowLayer(LAYER_BACK, True);
2666 ShowLayer(LAYER_WALLS, True);
2667 ShowLayer(LAYER_FOREGROUND, True);
2668 ShowLayer(LAYER_STEPS, True);
2669 ShowLayer(LAYER_WATER, True);
2670 ShowLayer(LAYER_ITEMS, True);
2671 ShowLayer(LAYER_MONSTERS, True);
2672 ShowLayer(LAYER_AREAS, True);
2673 ShowLayer(LAYER_TRIGGERS, True);
2675 ClearMap();
2677 FormCaption := MainForm.Caption;
2678 OpenedMap := '';
2679 OpenedWAD := '';
2681 config := TConfig.CreateFile(EditorDir+'Editor.cfg');
2683 if config.ReadInt('Editor', 'XPos', -1) = -1 then
2684 Position := poDesktopCenter
2685 else begin
2686 Left := config.ReadInt('Editor', 'XPos', Left);
2687 Top := config.ReadInt('Editor', 'YPos', Top);
2688 Width := config.ReadInt('Editor', 'Width', Width);
2689 Height := config.ReadInt('Editor', 'Height', Height);
2690 end;
2691 if config.ReadBool('Editor', 'Maximize', False) then
2692 WindowState := wsMaximized;
2693 ShowMap := config.ReadBool('Editor', 'Minimap', False);
2694 PanelProps.Width := config.ReadInt('Editor', 'PanelProps', PanelProps.ClientWidth);
2695 Splitter1.Left := PanelProps.Left;
2696 PanelObjs.Height := config.ReadInt('Editor', 'PanelObjs', PanelObjs.ClientHeight);
2697 Splitter2.Top := PanelObjs.Top;
2698 StatusBar.Top := PanelObjs.BoundsRect.Bottom;
2699 DotEnable := config.ReadBool('Editor', 'DotEnable', True);
2700 DotColor := config.ReadInt('Editor', 'DotColor', $FFFFFF);
2701 DotStepOne := config.ReadInt('Editor', 'DotStepOne', 16);
2702 DotStepTwo := config.ReadInt('Editor', 'DotStepTwo', 8);
2703 DotStep := config.ReadInt('Editor', 'DotStep', DotStepOne);
2704 DrawTexturePanel := config.ReadBool('Editor', 'DrawTexturePanel', True);
2705 DrawPanelSize := config.ReadBool('Editor', 'DrawPanelSize', True);
2706 BackColor := config.ReadInt('Editor', 'BackColor', $7F6040);
2707 PreviewColor := config.ReadInt('Editor', 'PreviewColor', $00FF00);
2708 UseCheckerboard := config.ReadBool('Editor', 'UseCheckerboard', True);
2709 gColorEdge := config.ReadInt('Editor', 'EdgeColor', COLOR_EDGE);
2710 gAlphaEdge := config.ReadInt('Editor', 'EdgeAlpha', ALPHA_EDGE);
2711 if gAlphaEdge = 255 then
2712 gAlphaEdge := ALPHA_EDGE;
2713 drEdge[0] := GetRValue(gColorEdge);
2714 drEdge[1] := GetGValue(gColorEdge);
2715 drEdge[2] := GetBValue(gColorEdge);
2716 if not config.ReadBool('Editor', 'EdgeShow', True) then
2717 drEdge[3] := 255
2718 else
2719 drEdge[3] := gAlphaEdge;
2720 gAlphaTriggerLine := config.ReadInt('Editor', 'LineAlpha', ALPHA_LINE);
2721 if gAlphaTriggerLine = 255 then
2722 gAlphaTriggerLine := ALPHA_LINE;
2723 gAlphaTriggerArea := config.ReadInt('Editor', 'TriggerAlpha', ALPHA_AREA);
2724 if gAlphaTriggerArea = 255 then
2725 gAlphaTriggerArea := ALPHA_AREA;
2726 gAlphaMonsterRect := config.ReadInt('Editor', 'MonsterRectAlpha', 0);
2727 gAlphaAreaRect := config.ReadInt('Editor', 'AreaRectAlpha', 0);
2728 if config.ReadInt('Editor', 'Scale', 0) = 1 then
2729 Scale := 2
2730 else
2731 Scale := 1;
2732 if config.ReadInt('Editor', 'DotSize', 0) = 1 then
2733 DotSize := 2
2734 else
2735 DotSize := 1;
2736 OpenDialog.InitialDir := config.ReadStr('Editor', 'LastOpenDir', EditorDir);
2737 SaveDialog.InitialDir := config.ReadStr('Editor', 'LastSaveDir', EditorDir);
2739 s := config.ReadStr('Editor', 'Language', '');
2740 gLanguage := s;
2742 Compress := config.ReadBool('Editor', 'Compress', True);
2743 Backup := config.ReadBool('Editor', 'Backup', True);
2745 RecentCount := config.ReadInt('Editor', 'RecentCount', 5);
2746 if RecentCount > 10 then
2747 RecentCount := 10;
2748 if RecentCount < 2 then
2749 RecentCount := 2;
2751 RecentFiles := TStringList.Create();
2752 for i := 0 to RecentCount-1 do
2753 begin
2754 s := config.ReadStr('RecentFiles', IntToStr(i+1), '');
2755 if s <> '' then
2756 RecentFiles.Add(s);
2757 end;
2758 RefreshRecentMenu();
2760 config.Free();
2762 tbShowMap.Down := ShowMap;
2763 tbGridOn.Down := DotEnable;
2764 pcObjects.ActivePageIndex := 0;
2765 Application.Title := _lc[I_EDITOR_TITLE];
2767 Application.OnIdle := OnIdle;
2768 end;
2770 procedure PrintBlack(X, Y: Integer; Text: string; FontID: DWORD);
2771 begin
2772 // NOTE: all the font printing routines assume CP1251
2773 e_TextureFontPrintEx(X, Y, Text, FontID, 0, 0, 0, 1.0);
2774 end;
2776 procedure TMainForm.Draw();
2777 var
2778 x, y: Integer;
2779 a, b: Integer;
2780 ID, PID: DWORD;
2781 Width, Height: Word;
2782 Rect: TRectWH;
2783 ObjCount: Word;
2784 aX, aY, aX2, aY2, XX, ScaleSz: Integer;
2785 begin
2786 ID := 0;
2787 PID := 0;
2788 Width := 0;
2789 Height := 0;
2791 e_BeginRender();
2793 e_Clear(GL_COLOR_BUFFER_BIT,
2794 GetRValue(BackColor)/255,
2795 GetGValue(BackColor)/255,
2796 GetBValue(BackColor)/255);
2798 DrawMap();
2800 ObjCount := SelectedObjectCount();
2802 // Обводим выделенные объекты красной рамкой:
2803 if ObjCount > 0 then
2804 begin
2805 for a := 0 to High(SelectedObjects) do
2806 if SelectedObjects[a].Live then
2807 begin
2808 Rect := ObjectGetRect(SelectedObjects[a].ObjectType, SelectedObjects[a].ID);
2810 with Rect do
2811 begin
2812 e_DrawQuad(X+MapOffset.X, Y+MapOffset.Y,
2813 X+MapOffset.X+Width-1, Y+MapOffset.Y+Height-1,
2814 255, 0, 0);
2816 // Рисуем точки изменения размеров:
2817 if (ObjCount = 1) and
2818 (SelectedObjects[GetFirstSelected].ObjectType in [OBJECT_PANEL, OBJECT_TRIGGER]) then
2819 begin
2820 e_DrawPoint(5, X+MapOffset.X, Y+MapOffset.Y+(Height div 2), 255, 255, 255);
2821 e_DrawPoint(5, X+MapOffset.X+Width-1, Y+MapOffset.Y+(Height div 2), 255, 255, 255);
2822 e_DrawPoint(5, X+MapOffset.X+(Width div 2), Y+MapOffset.Y, 255, 255, 255);
2823 e_DrawPoint(5, X+MapOffset.X+(Width div 2), Y+MapOffset.Y+Height-1, 255, 255, 255);
2825 e_DrawPoint(3, X+MapOffset.X, Y+MapOffset.Y+(Height div 2), 255, 0, 0);
2826 e_DrawPoint(3, X+MapOffset.X+Width-1, Y+MapOffset.Y+(Height div 2), 255, 0, 0);
2827 e_DrawPoint(3, X+MapOffset.X+(Width div 2), Y+MapOffset.Y, 255, 0, 0);
2828 e_DrawPoint(3, X+MapOffset.X+(Width div 2), Y+MapOffset.Y+Height-1, 255, 0, 0);
2829 end;
2830 end;
2831 end;
2832 end;
2834 // Рисуем сетку:
2835 if DotEnable and (PreviewMode = 0) then
2836 begin
2837 if DotSize = 2 then
2838 a := -1
2839 else
2840 a := 0;
2842 for x := 0 to (RenderPanel.Width div DotStep) do
2843 for y := 0 to (RenderPanel.Height div DotStep) do
2844 e_DrawPoint(DotSize, x*DotStep + a, y*DotStep + a,
2845 GetRValue(DotColor),
2846 GetGValue(DotColor),
2847 GetBValue(DotColor));
2848 end;
2850 // Превью текстуры:
2851 if (lbTextureList.ItemIndex <> -1) and (cbPreview.Checked) and
2852 (not IsSpecialTextureSel()) and (PreviewMode = 0) then
2853 begin
2854 if not g_GetTexture(SelectedTexture(), ID) then
2855 g_GetTexture('NOTEXTURE', ID);
2856 g_GetTextureSizeByID(ID, Width, Height);
2857 if UseCheckerboard then
2858 begin
2859 if g_GetTexture('PREVIEW', PID) then
2860 e_DrawFill(PID, RenderPanel.Width-Width, RenderPanel.Height-Height, Width div 16 + 1, Height div 16 + 1, 0, True, False);
2861 end else
2862 e_DrawFillQuad(RenderPanel.Width-Width-2, RenderPanel.Height-Height-2,
2863 RenderPanel.Width-1, RenderPanel.Height-1,
2864 GetRValue(PreviewColor), GetGValue(PreviewColor), GetBValue(PreviewColor), 0);
2865 e_Draw(ID, RenderPanel.Width-Width, RenderPanel.Height-Height, 0, True, False);
2866 end;
2868 // Подсказка при выборе точки Телепорта:
2869 if SelectFlag = SELECTFLAG_TELEPORT then
2870 begin
2871 with gTriggers[SelectedObjects[GetFirstSelected()].ID] do
2872 if Data.d2d_teleport then
2873 e_DrawLine(2, MousePos.X-16, MousePos.Y-1,
2874 MousePos.X+16, MousePos.Y-1,
2875 0, 0, 255)
2876 else
2877 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+AreaSize[AREA_DMPOINT].Width-1,
2878 MousePos.Y+AreaSize[AREA_DMPOINT].Height-1, 255, 255, 255);
2880 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 192, 192, 192, 127);
2881 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 255, 255, 255);
2882 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_TELEPORT], gEditorFont);
2883 end;
2885 // Подсказка при выборе точки появления:
2886 if SelectFlag = SELECTFLAG_SPAWNPOINT then
2887 begin
2888 e_DrawLine(2, MousePos.X-16, MousePos.Y-1,
2889 MousePos.X+16, MousePos.Y-1,
2890 0, 0, 255);
2891 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 192, 192, 192, 127);
2892 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 255, 255, 255);
2893 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_SPAWN], gEditorFont);
2894 end;
2896 // Подсказка при выборе панели двери:
2897 if SelectFlag = SELECTFLAG_DOOR then
2898 begin
2899 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 192, 192, 192, 127);
2900 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 255, 255, 255);
2901 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_PANEL_DOOR], gEditorFont);
2902 end;
2904 // Подсказка при выборе панели с текстурой:
2905 if SelectFlag = SELECTFLAG_TEXTURE then
2906 begin
2907 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+196, MousePos.Y+18, 192, 192, 192, 127);
2908 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+196, MousePos.Y+18, 255, 255, 255);
2909 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_PANEL_TEXTURE], gEditorFont);
2910 end;
2912 // Подсказка при выборе панели индикации выстрела:
2913 if SelectFlag = SELECTFLAG_SHOTPANEL then
2914 begin
2915 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+316, MousePos.Y+18, 192, 192, 192, 127);
2916 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+316, MousePos.Y+18, 255, 255, 255);
2917 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_PANEL_SHOT], gEditorFont);
2918 end;
2920 // Подсказка при выборе панели лифта:
2921 if SelectFlag = SELECTFLAG_LIFT 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_LIFT], gEditorFont);
2926 end;
2928 // Подсказка при выборе монстра:
2929 if SelectFlag = SELECTFLAG_MONSTER then
2930 begin
2931 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+120, MousePos.Y+18, 192, 192, 192, 127);
2932 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+120, MousePos.Y+18, 255, 255, 255);
2933 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_MONSTER], gEditorFont);
2934 end;
2936 // Подсказка при выборе области воздействия:
2937 if DrawPressRect then
2938 begin
2939 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+204, MousePos.Y+18, 192, 192, 192, 127);
2940 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+204, MousePos.Y+18, 255, 255, 255);
2941 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_EXT_AREA], gEditorFont);
2942 end;
2944 // Рисуем текстуры, если чертим панель:
2945 if (MouseAction = MOUSEACTION_DRAWPANEL) and (DrawTexturePanel) and
2946 (lbTextureList.ItemIndex <> -1) and (DrawRect <> nil) and
2947 (lbPanelType.ItemIndex in [0..8]) and not IsSpecialTextureSel() then
2948 begin
2949 if not g_GetTexture(SelectedTexture(), ID) then
2950 g_GetTexture('NOTEXTURE', ID);
2951 g_GetTextureSizeByID(ID, Width, Height);
2952 with DrawRect^ do
2953 if (Abs(Right-Left) >= Width) and (Abs(Bottom-Top) >= Height) then
2954 e_DrawFill(ID, Min(Left, Right), Min(Top, Bottom), Abs(Right-Left) div Width,
2955 Abs(Bottom-Top) div Height, 64, True, False);
2956 end;
2958 // Прямоугольник выделения:
2959 if DrawRect <> nil then
2960 with DrawRect^ do
2961 e_DrawQuad(Left, Top, Right-1, Bottom-1, 255, 255, 255);
2963 // Чертим мышью панель/триггер или меняем мышью их размер:
2964 if (((MouseAction in [MOUSEACTION_DRAWPANEL, MOUSEACTION_DRAWTRIGGER]) and
2965 not(ssCtrl in GetKeyShiftState())) or (MouseAction = MOUSEACTION_RESIZE)) and
2966 (DrawPanelSize) then
2967 begin
2968 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+88, MousePos.Y+33, 192, 192, 192, 127);
2969 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+88, MousePos.Y+33, 255, 255, 255);
2971 if MouseAction in [MOUSEACTION_DRAWPANEL, MOUSEACTION_DRAWTRIGGER] then
2972 begin // Чертим новый
2973 PrintBlack(MousePos.X+2, MousePos.Y+2, Format(_glc[I_HINT_WIDTH],
2974 [Abs(MousePos.X-MouseLDownPos.X)]), gEditorFont);
2975 PrintBlack(MousePos.X+2, MousePos.Y+16, Format(_glc[I_HINT_HEIGHT],
2976 [Abs(MousePos.Y-MouseLDownPos.Y)]), gEditorFont);
2977 end
2978 else // Растягиваем существующий
2979 if SelectedObjects[GetFirstSelected].ObjectType in [OBJECT_PANEL, OBJECT_TRIGGER] then
2980 begin
2981 if SelectedObjects[GetFirstSelected].ObjectType = OBJECT_PANEL then
2982 begin
2983 Width := gPanels[SelectedObjects[GetFirstSelected].ID].Width;
2984 Height := gPanels[SelectedObjects[GetFirstSelected].ID].Height;
2985 end
2986 else
2987 begin
2988 Width := gTriggers[SelectedObjects[GetFirstSelected].ID].Width;
2989 Height := gTriggers[SelectedObjects[GetFirstSelected].ID].Height;
2990 end;
2992 PrintBlack(MousePos.X+2, MousePos.Y+2, Format(_glc[I_HINT_WIDTH], [Width]),
2993 gEditorFont);
2994 PrintBlack(MousePos.X+2, MousePos.Y+16, Format(_glc[I_HINT_HEIGHT], [Height]),
2995 gEditorFont);
2996 end;
2997 end;
2999 // Ближайшая к курсору мыши точка на сетке:
3000 e_DrawPoint(3, MousePos.X, MousePos.Y, 0, 0, 255);
3002 // Мини-карта:
3003 if ShowMap then
3004 begin
3005 // Сколько пикселов карты в 1 пикселе мини-карты:
3006 ScaleSz := 16 div Scale;
3007 // Размеры мини-карты:
3008 aX := max(gMapInfo.Width div ScaleSz, 1);
3009 aY := max(gMapInfo.Height div ScaleSz, 1);
3010 // X-координата на RenderPanel нулевой x-координаты карты:
3011 XX := RenderPanel.Width - aX - 1;
3012 // Рамка карты:
3013 e_DrawFillQuad(XX-1, 0, RenderPanel.Width-1, aY+1, 0, 0, 0, 0);
3014 e_DrawQuad(XX-1, 0, RenderPanel.Width-1, aY+1, 197, 197, 197);
3016 if gPanels <> nil then
3017 begin
3018 // Рисуем панели:
3019 for a := 0 to High(gPanels) do
3020 with gPanels[a] do
3021 if PanelType <> 0 then
3022 begin
3023 // Левый верхний угол:
3024 aX := XX + (X div ScaleSz);
3025 aY := 1 + (Y div ScaleSz);
3026 // Размеры:
3027 aX2 := max(Width div ScaleSz, 1);
3028 aY2 := max(Height div ScaleSz, 1);
3029 // Правый нижний угол:
3030 aX2 := aX + aX2 - 1;
3031 aY2 := aY + aY2 - 1;
3033 case PanelType of
3034 PANEL_WALL: e_DrawFillQuad(aX, aY, aX2, aY2, 208, 208, 208, 0);
3035 PANEL_WATER: e_DrawFillQuad(aX, aY, aX2, aY2, 0, 0, 192, 0);
3036 PANEL_ACID1: e_DrawFillQuad(aX, aY, aX2, aY2, 0, 176, 0, 0);
3037 PANEL_ACID2: e_DrawFillQuad(aX, aY, aX2, aY2, 176, 0, 0, 0);
3038 PANEL_STEP: e_DrawFillQuad(aX, aY, aX2, aY2, 128, 128, 128, 0);
3039 PANEL_LIFTUP: e_DrawFillQuad(aX, aY, aX2, aY2, 116, 72, 36, 0);
3040 PANEL_LIFTDOWN: e_DrawFillQuad(aX, aY, aX2, aY2, 116, 124, 96, 0);
3041 PANEL_LIFTLEFT: e_DrawFillQuad(aX, aY, aX2, aY2, 200, 80, 4, 0);
3042 PANEL_LIFTRIGHT: e_DrawFillQuad(aX, aY, aX2, aY2, 252, 140, 56, 0);
3043 PANEL_OPENDOOR: e_DrawFillQuad(aX, aY, aX2, aY2, 100, 220, 92, 0);
3044 PANEL_CLOSEDOOR: e_DrawFillQuad(aX, aY, aX2, aY2, 212, 184, 64, 0);
3045 PANEL_BLOCKMON: e_DrawFillQuad(aX, aY, aX2, aY2, 192, 0, 192, 0);
3046 end;
3047 end;
3049 // Рисуем красным выделенные панели:
3050 if SelectedObjects <> nil then
3051 for b := 0 to High(SelectedObjects) do
3052 with SelectedObjects[b] do
3053 if Live and (ObjectType = OBJECT_PANEL) then
3054 with gPanels[SelectedObjects[b].ID] do
3055 if PanelType and not(PANEL_BACK or PANEL_FORE) <> 0 then
3056 begin
3057 // Левый верхний угол:
3058 aX := XX + (X div ScaleSz);
3059 aY := 1 + (Y div ScaleSz);
3060 // Размеры:
3061 aX2 := max(Width div ScaleSz, 1);
3062 aY2 := max(Height div ScaleSz, 1);
3063 // Правый нижний угол:
3064 aX2 := aX + aX2 - 1;
3065 aY2 := aY + aY2 - 1;
3067 e_DrawFillQuad(aX, aY, aX2, aY2, 255, 0, 0, 0)
3068 end;
3069 end;
3071 if (gMapInfo.Width > RenderPanel.Width) or
3072 (gMapInfo.Height > RenderPanel.Height) then
3073 begin
3074 // Окно, показывающее текущее положение экрана на карте:
3075 // Размеры окна:
3076 x := max(min(RenderPanel.Width, gMapInfo.Width) div ScaleSz, 1);
3077 y := max(min(RenderPanel.Height, gMapInfo.Height) div ScaleSz, 1);
3078 // Левый верхний угол:
3079 aX := XX + ((-MapOffset.X) div ScaleSz);
3080 aY := 1 + ((-MapOffset.Y) div ScaleSz);
3081 // Правый нижний угол:
3082 aX2 := aX + x - 1;
3083 aY2 := aY + y - 1;
3085 e_DrawFillQuad(aX, aY, aX2, aY2, 127, 192, 127, 127, B_BLEND);
3086 e_DrawQuad(aX, aY, aX2, aY2, 255, 0, 0);
3087 end;
3088 end; // Мини-карта
3090 e_EndRender();
3091 RenderPanel.SwapBuffers();
3092 end;
3094 procedure TMainForm.FormResize(Sender: TObject);
3095 begin
3096 e_SetViewPort(0, 0, RenderPanel.Width, RenderPanel.Height);
3098 if gMapInfo.Width >= RenderPanel.Width then
3099 sbHorizontal.Max := Normalize16(gMapInfo.Width-RenderPanel.Width+16)
3100 else
3101 sbHorizontal.Max := 0;
3103 if gMapInfo.Height >= RenderPanel.Height then
3104 sbVertical.Max := Normalize16(gMapInfo.Height-RenderPanel.Height+16)
3105 else
3106 sbVertical.Max := 0;
3108 MapOffset.X := -Normalize16(sbHorizontal.Position);
3109 MapOffset.Y := -Normalize16(sbVertical.Position);
3110 end;
3112 procedure SelectNextObject(X, Y: Integer; ObjectType: Byte; ID: DWORD);
3113 var
3114 j, j_max: Integer;
3115 res: Boolean;
3116 begin
3117 j_max := 0; // shut up compiler
3118 case ObjectType of
3119 OBJECT_PANEL:
3120 begin
3121 res := (gPanels <> nil) and
3122 PanelInShownLayer(gPanels[ID].PanelType) and
3123 g_CollidePoint(X, Y, gPanels[ID].X, gPanels[ID].Y,
3124 gPanels[ID].Width,
3125 gPanels[ID].Height);
3126 j_max := Length(gPanels) - 1;
3127 end;
3129 OBJECT_ITEM:
3130 begin
3131 res := (gItems <> nil) and
3132 LayerEnabled[LAYER_ITEMS] and
3133 g_CollidePoint(X, Y, gItems[ID].X, gItems[ID].Y,
3134 ItemSize[gItems[ID].ItemType][0],
3135 ItemSize[gItems[ID].ItemType][1]);
3136 j_max := Length(gItems) - 1;
3137 end;
3139 OBJECT_MONSTER:
3140 begin
3141 res := (gMonsters <> nil) and
3142 LayerEnabled[LAYER_MONSTERS] and
3143 g_CollidePoint(X, Y, gMonsters[ID].X, gMonsters[ID].Y,
3144 MonsterSize[gMonsters[ID].MonsterType].Width,
3145 MonsterSize[gMonsters[ID].MonsterType].Height);
3146 j_max := Length(gMonsters) - 1;
3147 end;
3149 OBJECT_AREA:
3150 begin
3151 res := (gAreas <> nil) and
3152 LayerEnabled[LAYER_AREAS] and
3153 g_CollidePoint(X, Y, gAreas[ID].X, gAreas[ID].Y,
3154 AreaSize[gAreas[ID].AreaType].Width,
3155 AreaSize[gAreas[ID].AreaType].Height);
3156 j_max := Length(gAreas) - 1;
3157 end;
3159 OBJECT_TRIGGER:
3160 begin
3161 res := (gTriggers <> nil) and
3162 LayerEnabled[LAYER_TRIGGERS] and
3163 g_CollidePoint(X, Y, gTriggers[ID].X, gTriggers[ID].Y,
3164 gTriggers[ID].Width,
3165 gTriggers[ID].Height);
3166 j_max := Length(gTriggers) - 1;
3167 end;
3169 else
3170 res := False;
3171 end;
3173 if not res then
3174 Exit;
3176 // Перебор ID: от ID-1 до 0; потом от High до ID+1:
3177 j := ID;
3179 while True do
3180 begin
3181 Dec(j);
3183 if j < 0 then
3184 j := j_max;
3185 if j = Integer(ID) then
3186 Break;
3188 case ObjectType of
3189 OBJECT_PANEL:
3190 res := PanelInShownLayer(gPanels[j].PanelType) and
3191 g_CollidePoint(X, Y, gPanels[j].X, gPanels[j].Y,
3192 gPanels[j].Width,
3193 gPanels[j].Height);
3194 OBJECT_ITEM:
3195 res := (gItems[j].ItemType <> ITEM_NONE) and
3196 g_CollidePoint(X, Y, gItems[j].X, gItems[j].Y,
3197 ItemSize[gItems[j].ItemType][0],
3198 ItemSize[gItems[j].ItemType][1]);
3199 OBJECT_MONSTER:
3200 res := (gMonsters[j].MonsterType <> MONSTER_NONE) and
3201 g_CollidePoint(X, Y, gMonsters[j].X, gMonsters[j].Y,
3202 MonsterSize[gMonsters[j].MonsterType].Width,
3203 MonsterSize[gMonsters[j].MonsterType].Height);
3204 OBJECT_AREA:
3205 res := (gAreas[j].AreaType <> AREA_NONE) and
3206 g_CollidePoint(X, Y, gAreas[j].X, gAreas[j].Y,
3207 AreaSize[gAreas[j].AreaType].Width,
3208 AreaSize[gAreas[j].AreaType].Height);
3209 OBJECT_TRIGGER:
3210 res := (gTriggers[j].TriggerType <> TRIGGER_NONE) and
3211 g_CollidePoint(X, Y, gTriggers[j].X, gTriggers[j].Y,
3212 gTriggers[j].Width,
3213 gTriggers[j].Height);
3214 else
3215 res := False;
3216 end;
3218 if res then
3219 begin
3220 SetLength(SelectedObjects, 1);
3222 SelectedObjects[0].ObjectType := ObjectType;
3223 SelectedObjects[0].ID := j;
3224 SelectedObjects[0].Live := True;
3226 FillProperty();
3227 Break;
3228 end;
3229 end;
3230 end;
3232 procedure TMainForm.RenderPanelMouseDown(Sender: TObject;
3233 Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
3234 var
3235 i: Integer;
3236 Rect: TRectWH;
3237 c1, c2, c3, c4: Boolean;
3238 item: TItem;
3239 area: TArea;
3240 monster: TMonster;
3241 IDArray: DWArray;
3242 begin
3243 MainForm.ActiveControl := RenderPanel;
3244 RenderPanel.SetFocus();
3246 RenderPanelMouseMove(RenderPanel, Shift, X, Y);
3248 if Button = mbLeft then // Left Mouse Button
3249 begin
3250 // Двигаем карту с помощью мыши и мини-карты:
3251 if ShowMap and
3252 g_CollidePoint(X, Y,
3253 RenderPanel.Width-max(gMapInfo.Width div (16 div Scale), 1)-1,
3254 1,
3255 max(gMapInfo.Width div (16 div Scale), 1),
3256 max(gMapInfo.Height div (16 div Scale), 1) ) then
3257 begin
3258 MoveMap(X, Y);
3259 MouseAction := MOUSEACTION_MOVEMAP;
3260 end
3261 else // Ставим предмет/монстра/область:
3262 if (pcObjects.ActivePageIndex in [1, 2, 3]) and
3263 (not (ssShift in Shift)) then
3264 begin
3265 case pcObjects.ActivePageIndex of
3266 1:
3267 if lbItemList.ItemIndex = -1 then
3268 ErrorMessageBox(_lc[I_MSG_CHOOSE_ITEM])
3269 else
3270 begin
3271 item.ItemType := lbItemList.ItemIndex + ITEM_MEDKIT_SMALL;
3272 if item.ItemType >= ITEM_WEAPON_KASTET then
3273 item.ItemType := item.ItemType + 2;
3274 item.X := MousePos.X-MapOffset.X;
3275 item.Y := MousePos.Y-MapOffset.Y;
3277 if not (ssCtrl in Shift) then
3278 begin
3279 item.X := item.X - (ItemSize[item.ItemType][0] div 2);
3280 item.Y := item.Y - ItemSize[item.ItemType][1];
3281 end;
3283 item.OnlyDM := cbOnlyDM.Checked;
3284 item.Fall := cbFall.Checked;
3285 Undo_Add(OBJECT_ITEM, AddItem(item));
3286 end;
3287 2:
3288 if lbMonsterList.ItemIndex = -1 then
3289 ErrorMessageBox(_lc[I_MSG_CHOOSE_MONSTER])
3290 else
3291 begin
3292 monster.MonsterType := lbMonsterList.ItemIndex + MONSTER_DEMON;
3293 monster.X := MousePos.X-MapOffset.X;
3294 monster.Y := MousePos.Y-MapOffset.Y;
3296 if not (ssCtrl in Shift) then
3297 begin
3298 monster.X := monster.X - (MonsterSize[monster.MonsterType].Width div 2);
3299 monster.Y := monster.Y - MonsterSize[monster.MonsterType].Height;
3300 end;
3302 if rbMonsterLeft.Checked then
3303 monster.Direction := D_LEFT
3304 else
3305 monster.Direction := D_RIGHT;
3306 Undo_Add(OBJECT_MONSTER, AddMonster(monster));
3307 end;
3308 3:
3309 if lbAreasList.ItemIndex = -1 then
3310 ErrorMessageBox(_lc[I_MSG_CHOOSE_AREA])
3311 else
3312 if (lbAreasList.ItemIndex + 1) <> AREA_DOMFLAG then
3313 begin
3314 area.AreaType := lbAreasList.ItemIndex + AREA_PLAYERPOINT1;
3315 area.X := MousePos.X-MapOffset.X;
3316 area.Y := MousePos.Y-MapOffset.Y;
3318 if not (ssCtrl in Shift) then
3319 begin
3320 area.X := area.X - (AreaSize[area.AreaType].Width div 2);
3321 area.Y := area.Y - AreaSize[area.AreaType].Height;
3322 end;
3324 if rbAreaLeft.Checked then
3325 area.Direction := D_LEFT
3326 else
3327 area.Direction := D_RIGHT;
3328 Undo_Add(OBJECT_AREA, AddArea(area));
3329 end;
3330 end;
3331 end
3332 else
3333 begin
3334 i := GetFirstSelected();
3336 // Выбираем объект под текущим:
3337 if (SelectedObjects <> nil) and
3338 (ssShift in Shift) and (i >= 0) and
3339 (SelectedObjects[i].Live) then
3340 begin
3341 if SelectedObjectCount() = 1 then
3342 SelectNextObject(X-MapOffset.X, Y-MapOffset.Y,
3343 SelectedObjects[i].ObjectType,
3344 SelectedObjects[i].ID);
3345 end
3346 else
3347 begin
3348 // Рисуем область триггера "Расширитель":
3349 if DrawPressRect and (i >= 0) and
3350 (SelectedObjects[i].ObjectType = OBJECT_TRIGGER) and
3351 (gTriggers[SelectedObjects[i].ID].TriggerType in
3352 [TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF]) then
3353 MouseAction := MOUSEACTION_DRAWPRESS
3354 else // Рисуем панель:
3355 if pcObjects.ActivePageIndex = 0 then
3356 begin
3357 if (lbPanelType.ItemIndex >= 0) then
3358 MouseAction := MOUSEACTION_DRAWPANEL
3359 end
3360 else // Рисуем триггер:
3361 if (lbTriggersList.ItemIndex >= 0) then
3362 begin
3363 MouseAction := MOUSEACTION_DRAWTRIGGER;
3364 end;
3365 end;
3366 end;
3367 end; // if Button = mbLeft
3369 if Button = mbRight then // Right Mouse Button
3370 begin
3371 // Клик по мини-карте:
3372 if ShowMap and
3373 g_CollidePoint(X, Y,
3374 RenderPanel.Width-max(gMapInfo.Width div (16 div Scale), 1)-1,
3375 1,
3376 max(gMapInfo.Width div (16 div Scale), 1),
3377 max(gMapInfo.Height div (16 div Scale), 1) ) then
3378 begin
3379 MouseAction := MOUSEACTION_NOACTION;
3380 end
3381 else // Нужно что-то выбрать мышью:
3382 if SelectFlag <> SELECTFLAG_NONE then
3383 begin
3384 case SelectFlag of
3385 SELECTFLAG_TELEPORT:
3386 // Точку назначения телепортации:
3387 with gTriggers[SelectedObjects[
3388 GetFirstSelected() ].ID].Data.TargetPoint do
3389 begin
3390 X := MousePos.X-MapOffset.X;
3391 Y := MousePos.Y-MapOffset.Y;
3392 end;
3394 SELECTFLAG_SPAWNPOINT:
3395 // Точку создания монстра:
3396 with gTriggers[SelectedObjects[GetFirstSelected()].ID] do
3397 if TriggerType = TRIGGER_SPAWNMONSTER then
3398 begin
3399 Data.MonPos.X := MousePos.X-MapOffset.X;
3400 Data.MonPos.Y := MousePos.Y-MapOffset.Y;
3401 end
3402 else if TriggerType = TRIGGER_SPAWNITEM then
3403 begin // Точка создания предмета:
3404 Data.ItemPos.X := MousePos.X-MapOffset.X;
3405 Data.ItemPos.Y := MousePos.Y-MapOffset.Y;
3406 end
3407 else if TriggerType = TRIGGER_SHOT then
3408 begin // Точка создания выстрела:
3409 Data.ShotPos.X := MousePos.X-MapOffset.X;
3410 Data.ShotPos.Y := MousePos.Y-MapOffset.Y;
3411 end;
3413 SELECTFLAG_DOOR:
3414 // Дверь:
3415 begin
3416 IDArray := ObjectInRect(X-MapOffset.X,
3417 Y-MapOffset.Y,
3418 2, 2, OBJECT_PANEL, True);
3419 if IDArray <> nil then
3420 begin
3421 for i := 0 to High(IDArray) do
3422 if (gPanels[IDArray[i]].PanelType = PANEL_OPENDOOR) or
3423 (gPanels[IDArray[i]].PanelType = PANEL_CLOSEDOOR) then
3424 begin
3425 gTriggers[SelectedObjects[
3426 GetFirstSelected() ].ID].Data.PanelID := IDArray[i];
3427 Break;
3428 end;
3429 end
3430 else
3431 gTriggers[SelectedObjects[
3432 GetFirstSelected() ].ID].Data.PanelID := -1;
3433 end;
3435 SELECTFLAG_TEXTURE:
3436 // Панель с текстурой:
3437 begin
3438 IDArray := ObjectInRect(X-MapOffset.X,
3439 Y-MapOffset.Y,
3440 2, 2, OBJECT_PANEL, True);
3441 if IDArray <> nil then
3442 begin
3443 for i := 0 to High(IDArray) do
3444 if ((gPanels[IDArray[i]].PanelType in
3445 [PANEL_WALL, PANEL_BACK, PANEL_FORE,
3446 PANEL_WATER, PANEL_ACID1, PANEL_ACID2,
3447 PANEL_STEP]) or
3448 (gPanels[IDArray[i]].PanelType = PANEL_OPENDOOR) or
3449 (gPanels[IDArray[i]].PanelType = PANEL_CLOSEDOOR)) and
3450 (gPanels[IDArray[i]].TextureName <> '') then
3451 begin
3452 gTriggers[SelectedObjects[
3453 GetFirstSelected() ].ID].TexturePanel := IDArray[i];
3454 Break;
3455 end;
3456 end
3457 else
3458 gTriggers[SelectedObjects[
3459 GetFirstSelected() ].ID].TexturePanel := -1;
3460 end;
3462 SELECTFLAG_LIFT:
3463 // Лифт:
3464 begin
3465 IDArray := ObjectInRect(X-MapOffset.X,
3466 Y-MapOffset.Y,
3467 2, 2, OBJECT_PANEL, True);
3468 if IDArray <> nil then
3469 begin
3470 for i := 0 to High(IDArray) do
3471 if (gPanels[IDArray[i]].PanelType = PANEL_LIFTUP) or
3472 (gPanels[IDArray[i]].PanelType = PANEL_LIFTDOWN) or
3473 (gPanels[IDArray[i]].PanelType = PANEL_LIFTLEFT) or
3474 (gPanels[IDArray[i]].PanelType = PANEL_LIFTRIGHT) then
3475 begin
3476 gTriggers[SelectedObjects[
3477 GetFirstSelected() ].ID].Data.PanelID := IDArray[i];
3478 Break;
3479 end;
3480 end
3481 else
3482 gTriggers[SelectedObjects[
3483 GetFirstSelected() ].ID].Data.PanelID := -1;
3484 end;
3486 SELECTFLAG_MONSTER:
3487 // Монстра:
3488 begin
3489 IDArray := ObjectInRect(X-MapOffset.X,
3490 Y-MapOffset.Y,
3491 2, 2, OBJECT_MONSTER, False);
3492 if IDArray <> nil then
3493 gTriggers[SelectedObjects[
3494 GetFirstSelected() ].ID].Data.MonsterID := IDArray[0]+1
3495 else
3496 gTriggers[SelectedObjects[
3497 GetFirstSelected() ].ID].Data.MonsterID := 0;
3498 end;
3500 SELECTFLAG_SHOTPANEL:
3501 // Панель индикации выстрела:
3502 begin
3503 if gTriggers[SelectedObjects[
3504 GetFirstSelected() ].ID].TriggerType = TRIGGER_SHOT then
3505 begin
3506 IDArray := ObjectInRect(X-MapOffset.X,
3507 Y-MapOffset.Y,
3508 2, 2, OBJECT_PANEL, True);
3509 if IDArray <> nil then
3510 begin
3511 for i := 0 to High(IDArray) do
3512 if ((gPanels[IDArray[i]].PanelType in
3513 [PANEL_WALL, PANEL_BACK, PANEL_FORE,
3514 PANEL_WATER, PANEL_ACID1, PANEL_ACID2,
3515 PANEL_STEP]) or
3516 (gPanels[IDArray[i]].PanelType = PANEL_OPENDOOR) or
3517 (gPanels[IDArray[i]].PanelType = PANEL_CLOSEDOOR)) and
3518 (gPanels[IDArray[i]].TextureName <> '') then
3519 begin
3520 gTriggers[SelectedObjects[
3521 GetFirstSelected() ].ID].Data.ShotPanelID := IDArray[i];
3522 Break;
3523 end;
3524 end
3525 else
3526 gTriggers[SelectedObjects[
3527 GetFirstSelected() ].ID].Data.ShotPanelID := -1;
3528 end;
3529 end;
3530 end;
3532 SelectFlag := SELECTFLAG_SELECTED;
3533 end
3534 else // if SelectFlag <> SELECTFLAG_NONE...
3535 begin
3536 // Что уже выбрано и не нажат Ctrl:
3537 if (SelectedObjects <> nil) and
3538 (not (ssCtrl in Shift)) then
3539 for i := 0 to High(SelectedObjects) do
3540 with SelectedObjects[i] do
3541 if Live then
3542 begin
3543 if (ObjectType in [OBJECT_PANEL, OBJECT_TRIGGER]) and
3544 (SelectedObjectCount() = 1) then
3545 begin
3546 Rect := ObjectGetRect(ObjectType, ID);
3548 c1 := g_Collide(X-MapOffset.X-1, Y-MapOffset.Y-1, 2, 2,
3549 Rect.X-2, Rect.Y+(Rect.Height div 2)-2, 4, 4);
3550 c2 := g_Collide(X-MapOffset.X-1, Y-MapOffset.Y-1, 2, 2,
3551 Rect.X+Rect.Width-3, Rect.Y+(Rect.Height div 2)-2, 4, 4);
3552 c3 := g_Collide(X-MapOffset.X-1, Y-MapOffset.Y-1, 2, 2,
3553 Rect.X+(Rect.Width div 2)-2, Rect.Y-2, 4, 4);
3554 c4 := g_Collide(X-MapOffset.X-1, Y-MapOffset.Y-1, 2, 2,
3555 Rect.X+(Rect.Width div 2)-2, Rect.Y+Rect.Height-3, 4, 4);
3557 // Меняем размер панели или триггера:
3558 if c1 or c2 or c3 or c4 then
3559 begin
3560 MouseAction := MOUSEACTION_RESIZE;
3561 LastMovePoint := MousePos;
3563 if c1 or c2 then
3564 begin // Шире/уже
3565 ResizeType := RESIZETYPE_HORIZONTAL;
3566 if c1 then
3567 ResizeDirection := RESIZEDIR_LEFT
3568 else
3569 ResizeDirection := RESIZEDIR_RIGHT;
3570 RenderPanel.Cursor := crSizeWE;
3571 end
3572 else
3573 begin // Выше/ниже
3574 ResizeType := RESIZETYPE_VERTICAL;
3575 if c3 then
3576 ResizeDirection := RESIZEDIR_UP
3577 else
3578 ResizeDirection := RESIZEDIR_DOWN;
3579 RenderPanel.Cursor := crSizeNS;
3580 end;
3582 Break;
3583 end;
3584 end;
3586 // Перемещаем панель или триггер:
3587 if ObjectCollide(ObjectType, ID,
3588 X-MapOffset.X-1,
3589 Y-MapOffset.Y-1, 2, 2) then
3590 begin
3591 MouseAction := MOUSEACTION_MOVEOBJ;
3592 LastMovePoint := MousePos;
3594 Break;
3595 end;
3596 end;
3597 end;
3598 end; // if Button = mbRight
3600 MouseRDown := Button = mbRight;
3601 if MouseRDown then
3602 MouseRDownPos := MousePos;
3604 MouseLDown := Button = mbLeft;
3605 if MouseLDown then
3606 MouseLDownPos := MousePos;
3607 end;
3609 procedure TMainForm.RenderPanelMouseUp(Sender: TObject;
3610 Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
3611 var
3612 panel: TPanel;
3613 trigger: TTrigger;
3614 rRect: TRectWH;
3615 rSelectRect: Boolean;
3616 wWidth, wHeight: Word;
3617 TextureID: DWORD;
3619 procedure SelectObjects(ObjectType: Byte);
3620 var
3621 i: Integer;
3622 IDArray: DWArray;
3623 begin
3624 IDArray := ObjectInRect(rRect.X, rRect.Y,
3625 rRect.Width, rRect.Height,
3626 ObjectType, rSelectRect);
3628 if IDArray <> nil then
3629 for i := 0 to High(IDArray) do
3630 SelectObject(ObjectType, IDArray[i], (ssCtrl in Shift) or rSelectRect);
3631 end;
3632 begin
3633 if Button = mbLeft then
3634 MouseLDown := False;
3635 if Button = mbRight then
3636 MouseRDown := False;
3638 DrawRect := nil;
3639 ResizeType := RESIZETYPE_NONE;
3640 TextureID := 0;
3642 if Button = mbLeft then // Left Mouse Button
3643 begin
3644 if MouseAction <> MOUSEACTION_NONE then
3645 begin // Было действие мышью
3646 // Мышь сдвинулась во время удержания клавиши,
3647 // либо активирован режим быстрого рисования:
3648 if ((MousePos.X <> MouseLDownPos.X) and
3649 (MousePos.Y <> MouseLDownPos.Y)) or
3650 ((MouseAction in [MOUSEACTION_DRAWPANEL, MOUSEACTION_DRAWTRIGGER]) and
3651 (ssCtrl in Shift)) then
3652 case MouseAction of
3653 // Рисовали панель:
3654 MOUSEACTION_DRAWPANEL:
3655 begin
3656 // Фон или передний план без текстуры - ошибка:
3657 if (lbPanelType.ItemIndex in [1, 2]) and
3658 (lbTextureList.ItemIndex = -1) then
3659 ErrorMessageBox(_lc[I_MSG_CHOOSE_TEXTURE])
3660 else // Назначаем параметры панели:
3661 begin
3662 case lbPanelType.ItemIndex of
3663 0: Panel.PanelType := PANEL_WALL;
3664 1: Panel.PanelType := PANEL_BACK;
3665 2: Panel.PanelType := PANEL_FORE;
3666 3: Panel.PanelType := PANEL_OPENDOOR;
3667 4: Panel.PanelType := PANEL_CLOSEDOOR;
3668 5: Panel.PanelType := PANEL_STEP;
3669 6: Panel.PanelType := PANEL_WATER;
3670 7: Panel.PanelType := PANEL_ACID1;
3671 8: Panel.PanelType := PANEL_ACID2;
3672 9: Panel.PanelType := PANEL_LIFTUP;
3673 10: Panel.PanelType := PANEL_LIFTDOWN;
3674 11: Panel.PanelType := PANEL_LIFTLEFT;
3675 12: Panel.PanelType := PANEL_LIFTRIGHT;
3676 13: Panel.PanelType := PANEL_BLOCKMON;
3677 end;
3679 Panel.X := Min(MousePos.X-MapOffset.X, MouseLDownPos.X-MapOffset.X);
3680 Panel.Y := Min(MousePos.Y-MapOffset.Y, MouseLDownPos.Y-MapOffset.Y);
3681 if ssCtrl in Shift then
3682 begin
3683 wWidth := DotStep;
3684 wHeight := DotStep;
3685 if (lbTextureList.ItemIndex <> -1) and
3686 (not IsSpecialTextureSel()) then
3687 begin
3688 if not g_GetTexture(SelectedTexture(), TextureID) then
3689 g_GetTexture('NOTEXTURE', TextureID);
3690 g_GetTextureSizeByID(TextureID, wWidth, wHeight);
3691 end;
3692 Panel.Width := wWidth;
3693 Panel.Height := wHeight;
3694 end
3695 else
3696 begin
3697 Panel.Width := Abs(MousePos.X-MouseLDownPos.X);
3698 Panel.Height := Abs(MousePos.Y-MouseLDownPos.Y);
3699 end;
3701 // Лифты, блокМон или отсутствие текстуры - пустая текстура:
3702 if (lbPanelType.ItemIndex in [9, 10, 11, 12, 13]) or
3703 (lbTextureList.ItemIndex = -1) then
3704 begin
3705 Panel.TextureHeight := 1;
3706 Panel.TextureWidth := 1;
3707 Panel.TextureName := '';
3708 Panel.TextureID := TEXTURE_SPECIAL_NONE;
3709 end
3710 else // Есть текстура:
3711 begin
3712 Panel.TextureName := SelectedTexture();
3714 // Обычная текстура:
3715 if not IsSpecialTextureSel() then
3716 begin
3717 g_GetTextureSizeByName(Panel.TextureName,
3718 Panel.TextureWidth, Panel.TextureHeight);
3719 g_GetTexture(Panel.TextureName, Panel.TextureID);
3720 end
3721 else // Спец.текстура:
3722 begin
3723 Panel.TextureHeight := 1;
3724 Panel.TextureWidth := 1;
3725 Panel.TextureID := SpecialTextureID(SelectedTexture());
3726 end;
3727 end;
3729 Panel.Alpha := 0;
3730 Panel.Blending := False;
3732 Undo_Add(OBJECT_PANEL, AddPanel(Panel));
3733 end;
3734 end;
3736 // Рисовали триггер:
3737 MOUSEACTION_DRAWTRIGGER:
3738 begin
3739 trigger.X := Min(MousePos.X-MapOffset.X, MouseLDownPos.X-MapOffset.X);
3740 trigger.Y := Min(MousePos.Y-MapOffset.Y, MouseLDownPos.Y-MapOffset.Y);
3741 if ssCtrl in Shift then
3742 begin
3743 wWidth := DotStep;
3744 wHeight := DotStep;
3745 trigger.Width := wWidth;
3746 trigger.Height := wHeight;
3747 end
3748 else
3749 begin
3750 trigger.Width := Abs(MousePos.X-MouseLDownPos.X);
3751 trigger.Height := Abs(MousePos.Y-MouseLDownPos.Y);
3752 end;
3754 trigger.Enabled := True;
3755 trigger.TriggerType := lbTriggersList.ItemIndex+1;
3756 trigger.TexturePanel := -1;
3758 // Типы активации:
3759 trigger.ActivateType := 0;
3761 if clbActivationType.Checked[0] then
3762 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_PLAYERCOLLIDE;
3763 if clbActivationType.Checked[1] then
3764 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_MONSTERCOLLIDE;
3765 if clbActivationType.Checked[2] then
3766 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_PLAYERPRESS;
3767 if clbActivationType.Checked[3] then
3768 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_MONSTERPRESS;
3769 if clbActivationType.Checked[4] then
3770 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_SHOT;
3771 if clbActivationType.Checked[5] then
3772 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_NOMONSTER;
3774 // Необходимые для активации ключи:
3775 trigger.Key := 0;
3777 if clbKeys.Checked[0] then
3778 trigger.Key := Trigger.Key or KEY_RED;
3779 if clbKeys.Checked[1] then
3780 trigger.Key := Trigger.Key or KEY_GREEN;
3781 if clbKeys.Checked[2] then
3782 trigger.Key := Trigger.Key or KEY_BLUE;
3783 if clbKeys.Checked[3] then
3784 trigger.Key := Trigger.Key or KEY_REDTEAM;
3785 if clbKeys.Checked[4] then
3786 trigger.Key := Trigger.Key or KEY_BLUETEAM;
3788 // Параметры триггера:
3789 FillByte(trigger.Data.Default[0], 128, 0);
3791 case trigger.TriggerType of
3792 // Переключаемая панель:
3793 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
3794 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP,
3795 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
3796 begin
3797 Trigger.Data.PanelID := -1;
3798 end;
3800 // Телепортация:
3801 TRIGGER_TELEPORT:
3802 begin
3803 trigger.Data.TargetPoint.X := trigger.X-64;
3804 trigger.Data.TargetPoint.Y := trigger.Y-64;
3805 trigger.Data.d2d_teleport := True;
3806 trigger.Data.TlpDir := 0;
3807 end;
3809 // Изменение других триггеров:
3810 TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF,
3811 TRIGGER_ONOFF:
3812 begin
3813 trigger.Data.Count := 1;
3814 end;
3816 // Звук:
3817 TRIGGER_SOUND:
3818 begin
3819 trigger.Data.Volume := 255;
3820 trigger.Data.Pan := 127;
3821 trigger.Data.PlayCount := 1;
3822 trigger.Data.Local := True;
3823 trigger.Data.SoundSwitch := False;
3824 end;
3826 // Музыка:
3827 TRIGGER_MUSIC:
3828 begin
3829 trigger.Data.MusicAction := 1;
3830 end;
3832 // Создание монстра:
3833 TRIGGER_SPAWNMONSTER:
3834 begin
3835 trigger.Data.MonType := MONSTER_ZOMBY;
3836 trigger.Data.MonPos.X := trigger.X-64;
3837 trigger.Data.MonPos.Y := trigger.Y-64;
3838 trigger.Data.MonHealth := 0;
3839 trigger.Data.MonActive := False;
3840 trigger.Data.MonCount := 1;
3841 end;
3843 // Создание предмета:
3844 TRIGGER_SPAWNITEM:
3845 begin
3846 trigger.Data.ItemType := ITEM_AMMO_BULLETS;
3847 trigger.Data.ItemPos.X := trigger.X-64;
3848 trigger.Data.ItemPos.Y := trigger.Y-64;
3849 trigger.Data.ItemOnlyDM := False;
3850 trigger.Data.ItemFalls := False;
3851 trigger.Data.ItemCount := 1;
3852 trigger.Data.ItemMax := 0;
3853 trigger.Data.ItemDelay := 0;
3854 end;
3856 // Ускорение:
3857 TRIGGER_PUSH:
3858 begin
3859 trigger.Data.PushAngle := 90;
3860 trigger.Data.PushForce := 10;
3861 trigger.Data.ResetVel := True;
3862 end;
3864 TRIGGER_SCORE:
3865 begin
3866 trigger.Data.ScoreCount := 1;
3867 trigger.Data.ScoreCon := True;
3868 trigger.Data.ScoreMsg := True;
3869 end;
3871 TRIGGER_MESSAGE:
3872 begin
3873 trigger.Data.MessageKind := 0;
3874 trigger.Data.MessageSendTo := 0;
3875 trigger.Data.MessageText := '';
3876 trigger.Data.MessageTime := 144;
3877 end;
3879 TRIGGER_DAMAGE:
3880 begin
3881 trigger.Data.DamageValue := 5;
3882 trigger.Data.DamageInterval := 12;
3883 end;
3885 TRIGGER_HEALTH:
3886 begin
3887 trigger.Data.HealValue := 5;
3888 trigger.Data.HealInterval := 36;
3889 end;
3891 TRIGGER_SHOT:
3892 begin
3893 trigger.Data.ShotType := TRIGGER_SHOT_BULLET;
3894 trigger.Data.ShotSound := True;
3895 trigger.Data.ShotPanelID := -1;
3896 trigger.Data.ShotTarget := 0;
3897 trigger.Data.ShotIntSight := 0;
3898 trigger.Data.ShotAim := TRIGGER_SHOT_AIM_DEFAULT;
3899 trigger.Data.ShotPos.X := trigger.X-64;
3900 trigger.Data.ShotPos.Y := trigger.Y-64;
3901 trigger.Data.ShotAngle := 0;
3902 trigger.Data.ShotWait := 18;
3903 trigger.Data.ShotAccuracy := 0;
3904 trigger.Data.ShotAmmo := 0;
3905 trigger.Data.ShotIntReload := 0;
3906 end;
3908 TRIGGER_EFFECT:
3909 begin
3910 trigger.Data.FXCount := 1;
3911 trigger.Data.FXType := TRIGGER_EFFECT_PARTICLE;
3912 trigger.Data.FXSubType := TRIGGER_EFFECT_SLIQUID;
3913 trigger.Data.FXColorR := 0;
3914 trigger.Data.FXColorG := 0;
3915 trigger.Data.FXColorB := 255;
3916 trigger.Data.FXPos := TRIGGER_EFFECT_POS_CENTER;
3917 trigger.Data.FXWait := 1;
3918 trigger.Data.FXVelX := 0;
3919 trigger.Data.FXVelY := -20;
3920 trigger.Data.FXSpreadL := 5;
3921 trigger.Data.FXSpreadR := 5;
3922 trigger.Data.FXSpreadU := 4;
3923 trigger.Data.FXSpreadD := 0;
3924 end;
3925 end;
3927 Undo_Add(OBJECT_TRIGGER, AddTrigger(trigger));
3928 end;
3930 // Рисовали область триггера "Расширитель":
3931 MOUSEACTION_DRAWPRESS:
3932 with gTriggers[SelectedObjects[GetFirstSelected].ID] do
3933 begin
3934 Data.tX := Min(MousePos.X-MapOffset.X, MouseLDownPos.X-MapOffset.X);
3935 Data.tY := Min(MousePos.Y-MapOffset.Y, MouseLDownPos.Y-MapOffset.Y);
3936 Data.tWidth := Abs(MousePos.X-MouseLDownPos.X);
3937 Data.tHeight := Abs(MousePos.Y-MouseLDownPos.Y);
3939 DrawPressRect := False;
3940 end;
3941 end;
3943 MouseAction := MOUSEACTION_NONE;
3944 end;
3945 end // if Button = mbLeft...
3946 else // Right Mouse Button:
3947 begin
3948 if MouseAction = MOUSEACTION_NOACTION then
3949 begin
3950 MouseAction := MOUSEACTION_NONE;
3951 Exit;
3952 end;
3954 // Объект передвинут или изменен в размере:
3955 if MouseAction in [MOUSEACTION_MOVEOBJ, MOUSEACTION_RESIZE] then
3956 begin
3957 MouseAction := MOUSEACTION_NONE;
3958 FillProperty();
3959 Exit;
3960 end;
3962 // Еще не все выбрали:
3963 if SelectFlag <> SELECTFLAG_NONE then
3964 begin
3965 if SelectFlag = SELECTFLAG_SELECTED then
3966 SelectFlag := SELECTFLAG_NONE;
3967 FillProperty();
3968 Exit;
3969 end;
3971 // Мышь сдвинулась во время удержания клавиши:
3972 if (MousePos.X <> MouseRDownPos.X) and
3973 (MousePos.Y <> MouseRDownPos.Y) then
3974 begin
3975 rSelectRect := True;
3977 rRect.X := Min(MousePos.X, MouseRDownPos.X)-MapOffset.X;
3978 rRect.Y := Min(MousePos.Y, MouseRDownPos.Y)-MapOffset.Y;
3979 rRect.Width := Abs(MousePos.X-MouseRDownPos.X);
3980 rRect.Height := Abs(MousePos.Y-MouseRDownPos.Y);
3981 end
3982 else // Мышь не сдвинулась - нет прямоугольника:
3983 begin
3984 rSelectRect := False;
3986 rRect.X := X-MapOffset.X-1;
3987 rRect.Y := Y-MapOffset.Y-1;
3988 rRect.Width := 2;
3989 rRect.Height := 2;
3990 end;
3992 // Если зажат Ctrl - выделять еще, иначе только один выделенный объект:
3993 if not (ssCtrl in Shift) then
3994 RemoveSelectFromObjects();
3996 // Выделяем всё в выбранном прямоугольнике:
3997 if (ssCtrl in Shift) and (ssAlt in Shift) then
3998 begin
3999 SelectObjects(OBJECT_PANEL);
4000 SelectObjects(OBJECT_ITEM);
4001 SelectObjects(OBJECT_MONSTER);
4002 SelectObjects(OBJECT_AREA);
4003 SelectObjects(OBJECT_TRIGGER);
4004 end
4005 else
4006 SelectObjects(pcObjects.ActivePageIndex+1);
4008 FillProperty();
4009 end;
4010 end;
4012 procedure TMainForm.RenderPanelPaint(Sender: TObject);
4013 begin
4014 Draw();
4015 end;
4017 function TMainForm.RenderMousePos(): Types.TPoint;
4018 begin
4019 Result := RenderPanel.ScreenToClient(Mouse.CursorPos);
4020 end;
4022 procedure TMainForm.RecountSelectedObjects();
4023 begin
4024 if SelectedObjectCount() = 0 then
4025 StatusBar.Panels[0].Text := ''
4026 else
4027 StatusBar.Panels[0].Text := Format(_lc[I_CAP_STAT_SELECTED], [SelectedObjectCount()]);
4028 end;
4030 procedure TMainForm.RenderPanelMouseMove(Sender: TObject;
4031 Shift: TShiftState; X, Y: Integer);
4032 var
4033 sX, sY: Integer;
4034 dWidth, dHeight: Integer;
4035 _id: Integer;
4036 TextureID: DWORD;
4037 wWidth, wHeight: Word;
4038 begin
4039 _id := GetFirstSelected();
4040 TextureID := 0;
4042 // Рисуем панель с текстурой, сетка - размеры текстуры:
4043 if (MouseAction = MOUSEACTION_DRAWPANEL) and
4044 (lbPanelType.ItemIndex in [0..8]) and
4045 (lbTextureList.ItemIndex <> -1) and
4046 (not IsSpecialTextureSel()) then
4047 begin
4048 sX := StrToIntDef(lTextureWidth.Caption, DotStep);
4049 sY := StrToIntDef(lTextureHeight.Caption, DotStep);
4050 end
4051 else
4052 // Меняем размер панели с текстурой, сетка - размеры текстуры:
4053 if (MouseAction = MOUSEACTION_RESIZE) and
4054 ( (SelectedObjects[_id].ObjectType = OBJECT_PANEL) and
4055 IsTexturedPanel(gPanels[SelectedObjects[_id].ID].PanelType) and
4056 (gPanels[SelectedObjects[_id].ID].TextureName <> '') and
4057 (not IsSpecialTexture(gPanels[SelectedObjects[_id].ID].TextureName)) ) then
4058 begin
4059 sX := gPanels[SelectedObjects[_id].ID].TextureWidth;
4060 sY := gPanels[SelectedObjects[_id].ID].TextureHeight;
4061 end
4062 else
4063 // Выравнивание по сетке:
4064 if SnapToGrid then
4065 begin
4066 sX := DotStep;
4067 sY := DotStep;
4068 end
4069 else // Нет выравнивания по сетке:
4070 begin
4071 sX := 1;
4072 sY := 1;
4073 end;
4075 // Новая позиция мыши:
4076 if MouseLDown then
4077 begin // Зажата левая кнопка мыши
4078 MousePos.X := (Round((X-MouseLDownPos.X)/sX)*sX)+MouseLDownPos.X;
4079 MousePos.Y := (Round((Y-MouseLDownPos.Y)/sY)*sY)+MouseLDownPos.Y;
4080 end
4081 else
4082 if MouseRDown then
4083 begin // Зажата правая кнопка мыши
4084 MousePos.X := (Round((X-MouseRDownPos.X)/sX)*sX)+MouseRDownPos.X;
4085 MousePos.Y := (Round((Y-MouseRDownPos.Y)/sY)*sY)+MouseRDownPos.Y;
4086 end
4087 else
4088 begin // Кнопки мыши не зажаты
4089 MousePos.X := (Round(X/sX)*sX);
4090 MousePos.Y := (Round(Y/sY)*sY);
4091 end;
4093 // Изменение размера закончилось - ставим обычный курсор:
4094 if ResizeType = RESIZETYPE_NONE then
4095 RenderPanel.Cursor := crDefault;
4097 // Зажата только правая кнопка мыши:
4098 if (not MouseLDown) and (MouseRDown) then
4099 begin
4100 // Рисуем прямоугольник выделения:
4101 if MouseAction = MOUSEACTION_NONE then
4102 begin
4103 if DrawRect = nil then
4104 New(DrawRect);
4105 DrawRect.Top := MouseRDownPos.y;
4106 DrawRect.Left := MouseRDownPos.x;
4107 DrawRect.Bottom := MousePos.y;
4108 DrawRect.Right := MousePos.x;
4109 end
4110 else
4111 // Двигаем выделенные объекты:
4112 if MouseAction = MOUSEACTION_MOVEOBJ then
4113 begin
4114 MoveSelectedObjects(ssShift in Shift, ssCtrl in Shift,
4115 MousePos.X-LastMovePoint.X,
4116 MousePos.Y-LastMovePoint.Y);
4117 end
4118 else
4119 // Меняем размер выделенного объекта:
4120 if MouseAction = MOUSEACTION_RESIZE then
4121 begin
4122 if (SelectedObjectCount = 1) and
4123 (SelectedObjects[GetFirstSelected].Live) then
4124 begin
4125 dWidth := MousePos.X-LastMovePoint.X;
4126 dHeight := MousePos.Y-LastMovePoint.Y;
4128 case ResizeType of
4129 RESIZETYPE_VERTICAL: dWidth := 0;
4130 RESIZETYPE_HORIZONTAL: dHeight := 0;
4131 end;
4133 case ResizeDirection of
4134 RESIZEDIR_UP: dHeight := -dHeight;
4135 RESIZEDIR_LEFT: dWidth := -dWidth;
4136 end;
4138 if ResizeObject(SelectedObjects[GetFirstSelected].ObjectType,
4139 SelectedObjects[GetFirstSelected].ID,
4140 dWidth, dHeight, ResizeDirection) then
4141 LastMovePoint := MousePos;
4142 end;
4143 end;
4144 end;
4146 // Зажата только левая кнопка мыши:
4147 if (not MouseRDown) and (MouseLDown) then
4148 begin
4149 // Рисуем прямоугольник планирования панели:
4150 if MouseAction in [MOUSEACTION_DRAWPANEL,
4151 MOUSEACTION_DRAWTRIGGER,
4152 MOUSEACTION_DRAWPRESS] then
4153 begin
4154 if DrawRect = nil then
4155 New(DrawRect);
4156 if ssCtrl in Shift then
4157 begin
4158 wWidth := DotStep;
4159 wHeight := DotStep;
4160 if (lbTextureList.ItemIndex <> -1) and (not IsSpecialTextureSel()) and
4161 (MouseAction = MOUSEACTION_DRAWPANEL) then
4162 begin
4163 if not g_GetTexture(SelectedTexture(), TextureID) then
4164 g_GetTexture('NOTEXTURE', TextureID);
4165 g_GetTextureSizeByID(TextureID, wWidth, wHeight);
4166 end;
4167 DrawRect.Top := MouseLDownPos.y;
4168 DrawRect.Left := MouseLDownPos.x;
4169 DrawRect.Bottom := DrawRect.Top + wHeight;
4170 DrawRect.Right := DrawRect.Left + wWidth;
4171 end
4172 else
4173 begin
4174 DrawRect.Top := MouseLDownPos.y;
4175 DrawRect.Left := MouseLDownPos.x;
4176 DrawRect.Bottom := MousePos.y;
4177 DrawRect.Right := MousePos.x;
4178 end;
4179 end
4180 else // Двигаем карту:
4181 if MouseAction = MOUSEACTION_MOVEMAP then
4182 begin
4183 MoveMap(X, Y);
4184 end;
4185 end;
4187 // Клавиши мыши не зажаты:
4188 if (not MouseRDown) and (not MouseLDown) then
4189 DrawRect := nil;
4191 // Строка состояния - координаты мыши:
4192 StatusBar.Panels[1].Text := Format('(%d:%d)',
4193 [MousePos.X-MapOffset.X, MousePos.Y-MapOffset.Y]);
4194 end;
4196 procedure TMainForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
4197 begin
4198 CanClose := MessageBox(0, PChar(_lc[I_MSG_EXIT_PROMT]),
4199 PChar(_lc[I_MSG_EXIT]),
4200 MB_ICONQUESTION or MB_YESNO or
4201 MB_DEFBUTTON1) = idYes;
4202 end;
4204 procedure TMainForm.aExitExecute(Sender: TObject);
4205 begin
4206 Close();
4207 end;
4209 procedure TMainForm.FormDestroy(Sender: TObject);
4210 var
4211 config: TConfig;
4212 i: Integer;
4213 begin
4214 config := TConfig.CreateFile(EditorDir+'Editor.cfg');
4216 if WindowState <> wsMaximized then
4217 begin
4218 config.WriteInt('Editor', 'XPos', Left);
4219 config.WriteInt('Editor', 'YPos', Top);
4220 config.WriteInt('Editor', 'Width', Width);
4221 config.WriteInt('Editor', 'Height', Height);
4222 end
4223 else
4224 begin
4225 config.WriteInt('Editor', 'XPos', RestoredLeft);
4226 config.WriteInt('Editor', 'YPos', RestoredTop);
4227 config.WriteInt('Editor', 'Width', RestoredWidth);
4228 config.WriteInt('Editor', 'Height', RestoredHeight);
4229 end;
4230 config.WriteBool('Editor', 'Maximize', WindowState = wsMaximized);
4231 config.WriteBool('Editor', 'Minimap', ShowMap);
4232 config.WriteInt('Editor', 'PanelProps', PanelProps.ClientWidth);
4233 config.WriteInt('Editor', 'PanelObjs', PanelObjs.ClientHeight);
4234 config.WriteBool('Editor', 'DotEnable', DotEnable);
4235 config.WriteInt('Editor', 'DotStep', DotStep);
4236 config.WriteStr('Editor', 'LastOpenDir', OpenDialog.InitialDir);
4237 config.WriteStr('Editor', 'LastSaveDir', SaveDialog.InitialDir);
4238 config.WriteBool('Editor', 'EdgeShow', drEdge[3] < 255);
4239 config.WriteInt('Editor', 'EdgeColor', gColorEdge);
4240 config.WriteInt('Editor', 'EdgeAlpha', gAlphaEdge);
4241 config.WriteInt('Editor', 'LineAlpha', gAlphaTriggerLine);
4242 config.WriteInt('Editor', 'TriggerAlpha', gAlphaTriggerArea);
4243 config.WriteInt('Editor', 'MonsterRectAlpha', gAlphaMonsterRect);
4244 config.WriteInt('Editor', 'AreaRectAlpha', gAlphaAreaRect);
4246 for i := 0 to RecentCount-1 do
4247 if i < RecentFiles.Count then
4248 config.WriteStr('RecentFiles', IntToStr(i+1), RecentFiles[i])
4249 else
4250 config.WriteStr('RecentFiles', IntToStr(i+1), '');
4251 RecentFiles.Free();
4253 config.SaveFile(EditorDir+'Editor.cfg');
4254 config.Free();
4256 slInvalidTextures.Free;
4257 end;
4259 procedure TMainForm.FormDropFiles(Sender: TObject;
4260 const FileNames: array of String);
4261 begin
4262 if Length(FileNames) <> 1 then
4263 Exit;
4265 OpenMapFile(FileNames[0]);
4266 end;
4268 procedure TMainForm.RenderPanelResize(Sender: TObject);
4269 begin
4270 if MainForm.Visible then
4271 MainForm.Resize();
4272 end;
4274 procedure TMainForm.Splitter1Moved(Sender: TObject);
4275 begin
4276 FormResize(Sender);
4277 end;
4279 procedure TMainForm.aMapOptionsExecute(Sender: TObject);
4280 var
4281 ResName: String;
4282 begin
4283 MapOptionsForm.ShowModal();
4285 ResName := OpenedMap;
4286 while (Pos(':\', ResName) > 0) do
4287 Delete(ResName, 1, Pos(':\', ResName) + 1);
4289 UpdateCaption(gMapInfo.Name, ExtractFileName(OpenedWAD), ResName);
4290 end;
4292 procedure TMainForm.aAboutExecute(Sender: TObject);
4293 begin
4294 AboutForm.ShowModal();
4295 end;
4297 procedure TMainForm.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
4298 var
4299 dx, dy, i: Integer;
4300 FileName: String;
4301 ok: Boolean;
4302 begin
4303 if (not EditingProperties) then
4304 begin
4305 if ssCtrl in Shift then
4306 begin
4307 case Chr(Key) of
4308 '1': ContourEnabled[LAYER_BACK] := not ContourEnabled[LAYER_BACK];
4309 '2': ContourEnabled[LAYER_WALLS] := not ContourEnabled[LAYER_WALLS];
4310 '3': ContourEnabled[LAYER_FOREGROUND] := not ContourEnabled[LAYER_FOREGROUND];
4311 '4': ContourEnabled[LAYER_STEPS] := not ContourEnabled[LAYER_STEPS];
4312 '5': ContourEnabled[LAYER_WATER] := not ContourEnabled[LAYER_WATER];
4313 '6': ContourEnabled[LAYER_ITEMS] := not ContourEnabled[LAYER_ITEMS];
4314 '7': ContourEnabled[LAYER_MONSTERS] := not ContourEnabled[LAYER_MONSTERS];
4315 '8': ContourEnabled[LAYER_AREAS] := not ContourEnabled[LAYER_AREAS];
4316 '9': ContourEnabled[LAYER_TRIGGERS] := not ContourEnabled[LAYER_TRIGGERS];
4317 '0':
4318 begin
4319 ok := False;
4320 for i := Low(ContourEnabled) to High(ContourEnabled) do
4321 if ContourEnabled[i] then
4322 ok := True;
4323 for i := Low(ContourEnabled) to High(ContourEnabled) do
4324 ContourEnabled[i] := not ok
4325 end
4326 end
4327 end
4328 else
4329 begin
4330 case Chr(key) of
4331 '1': SwitchLayer(LAYER_BACK);
4332 '2': SwitchLayer(LAYER_WALLS);
4333 '3': SwitchLayer(LAYER_FOREGROUND);
4334 '4': SwitchLayer(LAYER_STEPS);
4335 '5': SwitchLayer(LAYER_WATER);
4336 '6': SwitchLayer(LAYER_ITEMS);
4337 '7': SwitchLayer(LAYER_MONSTERS);
4338 '8': SwitchLayer(LAYER_AREAS);
4339 '9': SwitchLayer(LAYER_TRIGGERS);
4340 '0': tbShowClick(tbShow);
4341 end
4342 end;
4344 if Key = Ord('V') then
4345 begin // Поворот монстров и областей:
4346 if (SelectedObjects <> nil) then
4347 begin
4348 for i := 0 to High(SelectedObjects) do
4349 if (SelectedObjects[i].Live) then
4350 begin
4351 if (SelectedObjects[i].ObjectType = OBJECT_MONSTER) then
4352 begin
4353 g_ChangeDir(gMonsters[SelectedObjects[i].ID].Direction);
4354 end
4355 else
4356 if (SelectedObjects[i].ObjectType = OBJECT_AREA) then
4357 begin
4358 g_ChangeDir(gAreas[SelectedObjects[i].ID].Direction);
4359 end;
4360 end;
4361 end
4362 else
4363 begin
4364 if pcObjects.ActivePage = tsMonsters then
4365 begin
4366 if rbMonsterLeft.Checked then
4367 rbMonsterRight.Checked := True
4368 else
4369 rbMonsterLeft.Checked := True;
4370 end;
4371 if pcObjects.ActivePage = tsAreas then
4372 begin
4373 if rbAreaLeft.Checked then
4374 rbAreaRight.Checked := True
4375 else
4376 rbAreaLeft.Checked := True;
4377 end;
4378 end;
4379 end;
4381 if not (ssCtrl in Shift) then
4382 begin
4383 // Быстрое превью карты:
4384 if Key = Ord('E') then
4385 begin
4386 if PreviewMode = 0 then
4387 PreviewMode := 2;
4388 end;
4390 // Вертикальный скролл карты:
4391 with sbVertical do
4392 begin
4393 if Key = Ord('W') then
4394 begin
4395 if (MouseLDown or MouseRDown) and (Position >= DotStep) then
4396 begin
4397 if DrawRect <> nil then
4398 begin
4399 Inc(MouseLDownPos.y, DotStep);
4400 Inc(MouseRDownPos.y, DotStep);
4401 end;
4402 Inc(LastMovePoint.Y, DotStep);
4403 RenderPanelMouseMove(Sender, Shift, RenderMousePos().X, RenderMousePos().Y);
4404 end;
4405 Position := IfThen(Position > DotStep, Position-DotStep, 0);
4406 MapOffset.Y := -Round(Position/16) * 16;
4407 end;
4409 if Key = Ord('S') then
4410 begin
4411 if (MouseLDown or MouseRDown) and (Position+DotStep <= Max) then
4412 begin
4413 if DrawRect <> nil then
4414 begin
4415 Dec(MouseLDownPos.y, DotStep);
4416 Dec(MouseRDownPos.y, DotStep);
4417 end;
4418 Dec(LastMovePoint.Y, DotStep);
4419 RenderPanelMouseMove(Sender, Shift, RenderMousePos().X, RenderMousePos().Y);
4420 end;
4421 Position := IfThen(Position+DotStep < Max, Position+DotStep, Max);
4422 MapOffset.Y := -Round(Position/16) * 16;
4423 end;
4424 end;
4426 // Горизонтальный скролл карты:
4427 with sbHorizontal do
4428 begin
4429 if Key = Ord('A') then
4430 begin
4431 if (MouseLDown or MouseRDown) and (Position >= DotStep) then
4432 begin
4433 if DrawRect <> nil then
4434 begin
4435 Inc(MouseLDownPos.x, DotStep);
4436 Inc(MouseRDownPos.x, DotStep);
4437 end;
4438 Inc(LastMovePoint.X, DotStep);
4439 RenderPanelMouseMove(Sender, Shift, RenderMousePos().X, RenderMousePos().Y);
4440 end;
4441 Position := IfThen(Position > DotStep, Position-DotStep, 0);
4442 MapOffset.X := -Round(Position/16) * 16;
4443 end;
4445 if Key = Ord('D') then
4446 begin
4447 if (MouseLDown or MouseRDown) and (Position+DotStep <= Max) then
4448 begin
4449 if DrawRect <> nil then
4450 begin
4451 Dec(MouseLDownPos.x, DotStep);
4452 Dec(MouseRDownPos.x, DotStep);
4453 end;
4454 Dec(LastMovePoint.X, DotStep);
4455 RenderPanelMouseMove(Sender, Shift, RenderMousePos().X, RenderMousePos().Y);
4456 end;
4457 Position := IfThen(Position+DotStep < Max, Position+DotStep, Max);
4458 MapOffset.X := -Round(Position/16) * 16;
4459 end;
4460 end;
4461 end
4462 else // ssCtrl in Shift
4463 begin
4464 if ssShift in Shift then
4465 begin
4466 // Вставка по абсолютному смещению:
4467 if Key = Ord('V') then
4468 aPasteObjectExecute(Sender);
4469 end;
4470 RenderPanelMouseMove(Sender, Shift, RenderMousePos().X, RenderMousePos().Y);
4471 end;
4472 end;
4474 // Удалить выделенные объекты:
4475 if (Key = VK_DELETE) and (SelectedObjects <> nil) and
4476 RenderPanel.Focused() then
4477 DeleteSelectedObjects();
4479 // Снять выделение:
4480 if (Key = VK_ESCAPE) and (SelectedObjects <> nil) then
4481 RemoveSelectFromObjects();
4483 // Передвинуть объекты:
4484 if MainForm.ActiveControl = RenderPanel then
4485 begin
4486 dx := 0;
4487 dy := 0;
4489 if Key = VK_NUMPAD4 then
4490 dx := IfThen(ssAlt in Shift, -1, -DotStep);
4491 if Key = VK_NUMPAD6 then
4492 dx := IfThen(ssAlt in Shift, 1, DotStep);
4493 if Key = VK_NUMPAD8 then
4494 dy := IfThen(ssAlt in Shift, -1, -DotStep);
4495 if Key = VK_NUMPAD5 then
4496 dy := IfThen(ssAlt in Shift, 1, DotStep);
4498 if (dx <> 0) or (dy <> 0) then
4499 begin
4500 MoveSelectedObjects(ssShift in Shift, ssCtrl in Shift, dx, dy);
4501 Key := 0;
4502 end;
4503 end;
4505 if ssCtrl in Shift then
4506 begin
4507 // Выбор панели с текстурой для триггера
4508 if Key = Ord('T') then
4509 begin
4510 DrawPressRect := False;
4511 if SelectFlag = SELECTFLAG_TEXTURE then
4512 begin
4513 SelectFlag := SELECTFLAG_NONE;
4514 Exit;
4515 end;
4516 vleObjectProperty.FindRow(_lc[I_PROP_TR_TEXTURE_PANEL], i);
4517 if i > 0 then
4518 SelectFlag := SELECTFLAG_TEXTURE;
4519 end;
4521 if Key = Ord('D') then
4522 begin
4523 SelectFlag := SELECTFLAG_NONE;
4524 if DrawPressRect then
4525 begin
4526 DrawPressRect := False;
4527 Exit;
4528 end;
4529 i := -1;
4531 // Выбор области воздействия, в зависимости от типа триггера
4532 vleObjectProperty.FindRow(_lc[I_PROP_TR_EX_AREA], i);
4533 if i > 0 then
4534 begin
4535 DrawPressRect := True;
4536 Exit;
4537 end;
4538 vleObjectProperty.FindRow(_lc[I_PROP_TR_DOOR_PANEL], i);
4539 if i <= 0 then
4540 vleObjectProperty.FindRow(_lc[I_PROP_TR_TRAP_PANEL], i);
4541 if i > 0 then
4542 begin
4543 SelectFlag := SELECTFLAG_DOOR;
4544 Exit;
4545 end;
4546 vleObjectProperty.FindRow(_lc[I_PROP_TR_LIFT_PANEL], i);
4547 if i > 0 then
4548 begin
4549 SelectFlag := SELECTFLAG_LIFT;
4550 Exit;
4551 end;
4552 vleObjectProperty.FindRow(_lc[I_PROP_TR_TELEPORT_TO], i);
4553 if i > 0 then
4554 begin
4555 SelectFlag := SELECTFLAG_TELEPORT;
4556 Exit;
4557 end;
4558 vleObjectProperty.FindRow(_lc[I_PROP_TR_SPAWN_TO], i);
4559 if i > 0 then
4560 begin
4561 SelectFlag := SELECTFLAG_SPAWNPOINT;
4562 Exit;
4563 end;
4565 // Выбор основного параметра, в зависимости от типа триггера
4566 vleObjectProperty.FindRow(_lc[I_PROP_TR_NEXT_MAP], i);
4567 if i > 0 then
4568 begin
4569 g_ProcessResourceStr(OpenedMap, @FileName, nil, nil);
4570 SelectMapForm.Caption := _lc[I_CAP_SELECT];
4571 SelectMapForm.GetMaps(FileName);
4573 if SelectMapForm.ShowModal() = mrOK then
4574 begin
4575 vleObjectProperty.Cells[1, i] := SelectMapForm.lbMapList.Items[SelectMapForm.lbMapList.ItemIndex];
4576 bApplyProperty.Click();
4577 end;
4578 Exit;
4579 end;
4580 vleObjectProperty.FindRow(_lc[I_PROP_TR_SOUND_NAME], i);
4581 if i <= 0 then
4582 vleObjectProperty.FindRow(_lc[I_PROP_TR_MUSIC_NAME], i);
4583 if i > 0 then
4584 begin
4585 AddSoundForm.OKFunction := nil;
4586 AddSoundForm.lbResourcesList.MultiSelect := False;
4587 AddSoundForm.SetResource := vleObjectProperty.Cells[1, i];
4589 if (AddSoundForm.ShowModal() = mrOk) then
4590 begin
4591 vleObjectProperty.Cells[1, i] := AddSoundForm.ResourceName;
4592 bApplyProperty.Click();
4593 end;
4594 Exit;
4595 end;
4596 vleObjectProperty.FindRow(_lc[I_PROP_TR_PUSH_ANGLE], i);
4597 if i <= 0 then
4598 vleObjectProperty.FindRow(_lc[I_PROP_TR_MESSAGE_TEXT], i);
4599 if i > 0 then
4600 begin
4601 vleObjectProperty.Row := i;
4602 vleObjectProperty.SetFocus();
4603 Exit;
4604 end;
4605 end;
4606 end;
4607 end;
4609 procedure TMainForm.aOptimizeExecute(Sender: TObject);
4610 begin
4611 RemoveSelectFromObjects();
4612 MapOptimizationForm.ShowModal();
4613 end;
4615 procedure TMainForm.aCheckMapExecute(Sender: TObject);
4616 begin
4617 MapCheckForm.ShowModal();
4618 end;
4620 procedure TMainForm.bbAddTextureClick(Sender: TObject);
4621 begin
4622 AddTextureForm.lbResourcesList.MultiSelect := True;
4623 AddTextureForm.ShowModal();
4624 end;
4626 procedure TMainForm.lbTextureListClick(Sender: TObject);
4627 var
4628 TextureID: DWORD;
4629 TextureWidth, TextureHeight: Word;
4630 begin
4631 TextureID := 0;
4632 TextureWidth := 0;
4633 TextureHeight := 0;
4634 if (lbTextureList.ItemIndex <> -1) and
4635 (not IsSpecialTextureSel()) then
4636 begin
4637 if g_GetTexture(SelectedTexture(), TextureID) then
4638 begin
4639 g_GetTextureSizeByID(TextureID, TextureWidth, TextureHeight);
4641 lTextureWidth.Caption := IntToStr(TextureWidth);
4642 lTextureHeight.Caption := IntToStr(TextureHeight);
4643 end else
4644 begin
4645 lTextureWidth.Caption := _lc[I_NOT_ACCESSIBLE];
4646 lTextureHeight.Caption := _lc[I_NOT_ACCESSIBLE];
4647 end;
4648 end
4649 else
4650 begin
4651 lTextureWidth.Caption := '';
4652 lTextureHeight.Caption := '';
4653 end;
4654 end;
4656 procedure TMainForm.lbTextureListDrawItem(Control: TWinControl; Index: Integer;
4657 ARect: TRect; State: TOwnerDrawState);
4658 begin
4659 with Control as TListBox do
4660 begin
4661 if LCLType.odSelected in State then
4662 begin
4663 Canvas.Brush.Color := clHighlight;
4664 Canvas.Font.Color := clHighlightText;
4665 end else
4666 if (Items <> nil) and (Index >= 0) then
4667 if slInvalidTextures.IndexOf(Items[Index]) > -1 then
4668 begin
4669 Canvas.Brush.Color := clRed;
4670 Canvas.Font.Color := clWhite;
4671 end;
4672 Canvas.FillRect(ARect);
4673 Canvas.TextRect(ARect, ARect.Left, ARect.Top, Items[Index]);
4674 end;
4675 end;
4677 procedure TMainForm.miReopenMapClick(Sender: TObject);
4678 var
4679 FileName, Resource: String;
4680 begin
4681 if OpenedMap = '' then
4682 Exit;
4684 if MessageBox(0, PChar(_lc[I_MSG_REOPEN_MAP_PROMT]),
4685 PChar(_lc[I_MENU_FILE_REOPEN]), MB_ICONQUESTION or MB_YESNO) <> idYes then
4686 Exit;
4688 g_ProcessResourceStr(OpenedMap, @FileName, nil, @Resource);
4689 OpenMap(FileName, Resource);
4690 end;
4692 procedure TMainForm.vleObjectPropertyGetPickList(Sender: TObject;
4693 const KeyName: String; Values: TStrings);
4694 begin
4695 if vleObjectProperty.ItemProps[KeyName].EditStyle = esPickList then
4696 begin
4697 if KeyName = _lc[I_PROP_DIRECTION] then
4698 begin
4699 Values.Add(DirNames[D_LEFT]);
4700 Values.Add(DirNames[D_RIGHT]);
4701 end
4702 else if KeyName = _lc[I_PROP_TR_TELEPORT_DIR] then
4703 begin
4704 Values.Add(DirNamesAdv[0]);
4705 Values.Add(DirNamesAdv[1]);
4706 Values.Add(DirNamesAdv[2]);
4707 Values.Add(DirNamesAdv[3]);
4708 end
4709 else if KeyName = _lc[I_PROP_TR_MUSIC_ACT] then
4710 begin
4711 Values.Add(_lc[I_PROP_TR_MUSIC_ON]);
4712 Values.Add(_lc[I_PROP_TR_MUSIC_OFF]);
4713 end
4714 else if KeyName = _lc[I_PROP_TR_MONSTER_BEHAVIOUR] then
4715 begin
4716 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_0]);
4717 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_1]);
4718 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_2]);
4719 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_3]);
4720 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_4]);
4721 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_5]);
4722 end
4723 else if KeyName = _lc[I_PROP_TR_SCORE_ACT] then
4724 begin
4725 Values.Add(_lc[I_PROP_TR_SCORE_ACT_0]);
4726 Values.Add(_lc[I_PROP_TR_SCORE_ACT_1]);
4727 Values.Add(_lc[I_PROP_TR_SCORE_ACT_2]);
4728 Values.Add(_lc[I_PROP_TR_SCORE_ACT_3]);
4729 end
4730 else if KeyName = _lc[I_PROP_TR_SCORE_TEAM] then
4731 begin
4732 Values.Add(_lc[I_PROP_TR_SCORE_TEAM_0]);
4733 Values.Add(_lc[I_PROP_TR_SCORE_TEAM_1]);
4734 Values.Add(_lc[I_PROP_TR_SCORE_TEAM_2]);
4735 Values.Add(_lc[I_PROP_TR_SCORE_TEAM_3]);
4736 end
4737 else if KeyName = _lc[I_PROP_TR_MESSAGE_KIND] then
4738 begin
4739 Values.Add(_lc[I_PROP_TR_MESSAGE_KIND_0]);
4740 Values.Add(_lc[I_PROP_TR_MESSAGE_KIND_1]);
4741 end
4742 else if KeyName = _lc[I_PROP_TR_MESSAGE_TO] then
4743 begin
4744 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_0]);
4745 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_1]);
4746 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_2]);
4747 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_3]);
4748 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_4]);
4749 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_5]);
4750 end
4751 else if KeyName = _lc[I_PROP_TR_SHOT_TO] then
4752 begin
4753 Values.Add(_lc[I_PROP_TR_SHOT_TO_0]);
4754 Values.Add(_lc[I_PROP_TR_SHOT_TO_1]);
4755 Values.Add(_lc[I_PROP_TR_SHOT_TO_2]);
4756 Values.Add(_lc[I_PROP_TR_SHOT_TO_3]);
4757 Values.Add(_lc[I_PROP_TR_SHOT_TO_4]);
4758 Values.Add(_lc[I_PROP_TR_SHOT_TO_5]);
4759 Values.Add(_lc[I_PROP_TR_SHOT_TO_6]);
4760 end
4761 else if KeyName = _lc[I_PROP_TR_SHOT_AIM] then
4762 begin
4763 Values.Add(_lc[I_PROP_TR_SHOT_AIM_0]);
4764 Values.Add(_lc[I_PROP_TR_SHOT_AIM_1]);
4765 Values.Add(_lc[I_PROP_TR_SHOT_AIM_2]);
4766 Values.Add(_lc[I_PROP_TR_SHOT_AIM_3]);
4767 end
4768 else if (KeyName = _lc[I_PROP_PANEL_BLEND]) or
4769 (KeyName = _lc[I_PROP_DM_ONLY]) or
4770 (KeyName = _lc[I_PROP_ITEM_FALLS]) or
4771 (KeyName = _lc[I_PROP_TR_ENABLED]) or
4772 (KeyName = _lc[I_PROP_TR_D2D]) or
4773 (KeyName = _lc[I_PROP_TR_SILENT]) or
4774 (KeyName = _lc[I_PROP_TR_TELEPORT_SILENT]) or
4775 (KeyName = _lc[I_PROP_TR_EX_RANDOM]) or
4776 (KeyName = _lc[I_PROP_TR_TEXTURE_ONCE]) or
4777 (KeyName = _lc[I_PROP_TR_TEXTURE_ANIM_ONCE]) or
4778 (KeyName = _lc[I_PROP_TR_SOUND_LOCAL]) or
4779 (KeyName = _lc[I_PROP_TR_SOUND_SWITCH]) or
4780 (KeyName = _lc[I_PROP_TR_MONSTER_ACTIVE]) or
4781 (KeyName = _lc[I_PROP_TR_PUSH_RESET]) or
4782 (KeyName = _lc[I_PROP_TR_SCORE_CON]) or
4783 (KeyName = _lc[I_PROP_TR_SCORE_MSG]) or
4784 (KeyName = _lc[I_PROP_TR_HEALTH_MAX]) or
4785 (KeyName = _lc[I_PROP_TR_SHOT_SOUND]) or
4786 (KeyName = _lc[I_PROP_TR_EFFECT_CENTER]) then
4787 begin
4788 Values.Add(BoolNames[True]);
4789 Values.Add(BoolNames[False]);
4790 end;
4791 end;
4792 end;
4794 procedure TMainForm.bApplyPropertyClick(Sender: TObject);
4795 var
4796 _id, a, r, c: Integer;
4797 s: String;
4798 res: Boolean;
4799 NoTextureID: DWORD;
4800 NW, NH: Word;
4801 begin
4802 NoTextureID := 0;
4803 NW := 0;
4804 NH := 0;
4806 if SelectedObjectCount() <> 1 then
4807 Exit;
4808 if not SelectedObjects[GetFirstSelected()].Live then
4809 Exit;
4811 try
4812 if not CheckProperty() then
4813 Exit;
4814 except
4815 Exit;
4816 end;
4818 _id := GetFirstSelected();
4820 r := vleObjectProperty.Row;
4821 c := vleObjectProperty.Col;
4823 case SelectedObjects[_id].ObjectType of
4824 OBJECT_PANEL:
4825 begin
4826 with gPanels[SelectedObjects[_id].ID] do
4827 begin
4828 X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
4829 Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
4830 Width := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_WIDTH]]));
4831 Height := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_HEIGHT]]));
4833 PanelType := GetPanelType(vleObjectProperty.Values[_lc[I_PROP_PANEL_TYPE]]);
4835 // Сброс ссылки на триггеры смены текстуры:
4836 if not WordBool(PanelType and (PANEL_WALL or PANEL_FORE or PANEL_BACK)) then
4837 if gTriggers <> nil then
4838 for a := 0 to High(gTriggers) do
4839 begin
4840 if (gTriggers[a].TriggerType <> 0) and
4841 (gTriggers[a].TexturePanel = Integer(SelectedObjects[_id].ID)) then
4842 gTriggers[a].TexturePanel := -1;
4843 if (gTriggers[a].TriggerType = TRIGGER_SHOT) and
4844 (gTriggers[a].Data.ShotPanelID = Integer(SelectedObjects[_id].ID)) then
4845 gTriggers[a].Data.ShotPanelID := -1;
4846 end;
4848 // Сброс ссылки на триггеры лифта:
4849 if not WordBool(PanelType and (PANEL_LIFTUP or PANEL_LIFTDOWN or PANEL_LIFTLEFT or PANEL_LIFTRIGHT)) then
4850 if gTriggers <> nil then
4851 for a := 0 to High(gTriggers) do
4852 if (gTriggers[a].TriggerType in [TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT]) and
4853 (gTriggers[a].Data.PanelID = Integer(SelectedObjects[_id].ID)) then
4854 gTriggers[a].Data.PanelID := -1;
4856 // Сброс ссылки на триггеры двери:
4857 if not WordBool(PanelType and (PANEL_OPENDOOR or PANEL_CLOSEDOOR)) then
4858 if gTriggers <> nil then
4859 for a := 0 to High(gTriggers) do
4860 if (gTriggers[a].TriggerType in [TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
4861 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP]) and
4862 (gTriggers[a].Data.PanelID = Integer(SelectedObjects[_id].ID)) then
4863 gTriggers[a].Data.PanelID := -1;
4865 if IsTexturedPanel(PanelType) then
4866 begin // Может быть текстура
4867 if TextureName <> '' then
4868 begin // Была текстура
4869 Alpha := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_PANEL_ALPHA]]));
4870 Blending := NameToBool(vleObjectProperty.Values[_lc[I_PROP_PANEL_BLEND]]);
4871 end
4872 else // Не было
4873 begin
4874 Alpha := 0;
4875 Blending := False;
4876 end;
4878 // Новая текстура:
4879 TextureName := vleObjectProperty.Values[_lc[I_PROP_PANEL_TEX]];
4881 if TextureName <> '' then
4882 begin // Есть текстура
4883 // Обычная текстура:
4884 if not IsSpecialTexture(TextureName) then
4885 begin
4886 g_GetTextureSizeByName(TextureName,
4887 TextureWidth, TextureHeight);
4889 // Проверка кратности размеров панели:
4890 res := True;
4891 if TextureWidth <> 0 then
4892 if gPanels[SelectedObjects[_id].ID].Width mod TextureWidth <> 0 then
4893 begin
4894 ErrorMessageBox(Format(_lc[I_MSG_WRONG_TEXWIDTH],
4895 [TextureWidth]));
4896 Res := False;
4897 end;
4898 if Res and (TextureHeight <> 0) then
4899 if gPanels[SelectedObjects[_id].ID].Height mod TextureHeight <> 0 then
4900 begin
4901 ErrorMessageBox(Format(_lc[I_MSG_WRONG_TEXHEIGHT],
4902 [TextureHeight]));
4903 Res := False;
4904 end;
4906 if Res then
4907 begin
4908 if not g_GetTexture(TextureName, TextureID) then
4909 // Не удалось загрузить текстуру, рисуем NOTEXTURE
4910 if g_GetTexture('NOTEXTURE', NoTextureID) then
4911 begin
4912 TextureID := TEXTURE_SPECIAL_NOTEXTURE;
4913 g_GetTextureSizeByID(NoTextureID, NW, NH);
4914 TextureWidth := NW;
4915 TextureHeight := NH;
4916 end else
4917 begin
4918 TextureID := TEXTURE_SPECIAL_NONE;
4919 TextureWidth := 1;
4920 TextureHeight := 1;
4921 end;
4922 end
4923 else
4924 begin
4925 TextureName := '';
4926 TextureWidth := 1;
4927 TextureHeight := 1;
4928 TextureID := TEXTURE_SPECIAL_NONE;
4929 end;
4930 end
4931 else // Спец.текстура
4932 begin
4933 TextureHeight := 1;
4934 TextureWidth := 1;
4935 TextureID := SpecialTextureID(TextureName);
4936 end;
4937 end
4938 else // Нет текстуры
4939 begin
4940 TextureWidth := 1;
4941 TextureHeight := 1;
4942 TextureID := TEXTURE_SPECIAL_NONE;
4943 end;
4944 end
4945 else // Не может быть текстуры
4946 begin
4947 Alpha := 0;
4948 Blending := False;
4949 TextureName := '';
4950 TextureWidth := 1;
4951 TextureHeight := 1;
4952 TextureID := TEXTURE_SPECIAL_NONE;
4953 end;
4954 end;
4955 end;
4957 OBJECT_ITEM:
4958 begin
4959 with gItems[SelectedObjects[_id].ID] do
4960 begin
4961 X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
4962 Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
4963 OnlyDM := NameToBool(vleObjectProperty.Values[_lc[I_PROP_DM_ONLY]]);
4964 Fall := NameToBool(vleObjectProperty.Values[_lc[I_PROP_ITEM_FALLS]]);
4965 end;
4966 end;
4968 OBJECT_MONSTER:
4969 begin
4970 with gMonsters[SelectedObjects[_id].ID] do
4971 begin
4972 X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
4973 Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
4974 Direction := NameToDir(vleObjectProperty.Values[_lc[I_PROP_DIRECTION]]);
4975 end;
4976 end;
4978 OBJECT_AREA:
4979 begin
4980 with gAreas[SelectedObjects[_id].ID] do
4981 begin
4982 X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
4983 Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
4984 Direction := NameToDir(vleObjectProperty.Values[_lc[I_PROP_DIRECTION]]);
4985 end;
4986 end;
4988 OBJECT_TRIGGER:
4989 begin
4990 with gTriggers[SelectedObjects[_id].ID] do
4991 begin
4992 X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
4993 Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
4994 Width := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_WIDTH]]));
4995 Height := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_HEIGHT]]));
4996 Enabled := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_ENABLED]]);
4997 ActivateType := StrToActivate(vleObjectProperty.Values[_lc[I_PROP_TR_ACTIVATION]]);
4998 Key := StrToKey(vleObjectProperty.Values[_lc[I_PROP_TR_KEYS]]);
5000 case TriggerType of
5001 TRIGGER_EXIT:
5002 begin
5003 s := utf2win(vleObjectProperty.Values[_lc[I_PROP_TR_NEXT_MAP]]);
5004 FillByte(Data.MapName[0], 16, 0);
5005 if s <> '' then
5006 Move(s[1], Data.MapName[0], Min(Length(s), 16));
5007 end;
5009 TRIGGER_TEXTURE:
5010 begin
5011 Data.ActivateOnce := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_TEXTURE_ONCE]]);
5012 Data.AnimOnce := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_TEXTURE_ANIM_ONCE]]);
5013 end;
5015 TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF:
5016 begin
5017 Data.Wait := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EX_DELAY]], 0), 65535);
5018 Data.Count := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EX_COUNT]], 0), 65535);
5019 if Data.Count < 1 then
5020 Data.Count := 1;
5021 if TriggerType = TRIGGER_PRESS then
5022 Data.ExtRandom := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_EX_RANDOM]]);
5023 end;
5025 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR, TRIGGER_DOOR5,
5026 TRIGGER_CLOSETRAP, TRIGGER_TRAP, TRIGGER_LIFTUP, TRIGGER_LIFTDOWN,
5027 TRIGGER_LIFT:
5028 begin
5029 Data.NoSound := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SILENT]]);
5030 Data.d2d_doors := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_D2D]]);
5031 end;
5033 TRIGGER_TELEPORT:
5034 begin
5035 Data.d2d_teleport := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_D2D]]);
5036 Data.silent_teleport := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_TELEPORT_SILENT]]);
5037 Data.TlpDir := NameToDirAdv(vleObjectProperty.Values[_lc[I_PROP_TR_TELEPORT_DIR]]);
5038 end;
5040 TRIGGER_SOUND:
5041 begin
5042 s := utf2win(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_NAME]]);
5043 FillByte(Data.SoundName[0], 64, 0);
5044 if s <> '' then
5045 Move(s[1], Data.SoundName[0], Min(Length(s), 64));
5047 Data.Volume := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_VOLUME]], 0), 255);
5048 Data.Pan := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_PAN]], 0), 255);
5049 Data.PlayCount := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_COUNT]], 0), 255);
5050 Data.Local := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_LOCAL]]);
5051 Data.SoundSwitch := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_SWITCH]]);
5052 end;
5054 TRIGGER_SPAWNMONSTER:
5055 begin
5056 Data.MonType := StrToMonster(vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_TYPE]]);
5057 Data.MonDir := Byte(NameToDir(vleObjectProperty.Values[_lc[I_PROP_DIRECTION]]));
5058 Data.MonHealth := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_HEALTH]], 0), 1000000);
5059 if Data.MonHealth < 0 then
5060 Data.MonHealth := 0;
5061 Data.MonActive := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_ACTIVE]]);
5062 Data.MonCount := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_COUNT]], 0), 64);
5063 if Data.MonCount < 1 then
5064 Data.MonCount := 1;
5065 Data.MonEffect := StrToEffect(vleObjectProperty.Values[_lc[I_PROP_TR_FX_TYPE]]);
5066 Data.MonMax := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SPAWN_MAX]], 0), 65535);
5067 Data.MonDelay := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SPAWN_DELAY]], 0), 65535);
5068 Data.MonBehav := 0;
5069 if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_1] then
5070 Data.MonBehav := 1;
5071 if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_2] then
5072 Data.MonBehav := 2;
5073 if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_3] then
5074 Data.MonBehav := 3;
5075 if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_4] then
5076 Data.MonBehav := 4;
5077 if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_5] then
5078 Data.MonBehav := 5;
5079 end;
5081 TRIGGER_SPAWNITEM:
5082 begin
5083 Data.ItemType := StrToItem(vleObjectProperty.Values[_lc[I_PROP_TR_ITEM_TYPE]]);
5084 Data.ItemOnlyDM := NameToBool(vleObjectProperty.Values[_lc[I_PROP_DM_ONLY]]);
5085 Data.ItemFalls := NameToBool(vleObjectProperty.Values[_lc[I_PROP_ITEM_FALLS]]);
5086 Data.ItemCount := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_COUNT]], 0), 64);
5087 if Data.ItemCount < 1 then
5088 Data.ItemCount := 1;
5089 Data.ItemEffect := StrToEffect(vleObjectProperty.Values[_lc[I_PROP_TR_FX_TYPE]]);
5090 Data.ItemMax := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SPAWN_MAX]], 0), 65535);
5091 Data.ItemDelay := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SPAWN_DELAY]], 0), 65535);
5092 end;
5094 TRIGGER_MUSIC:
5095 begin
5096 s := utf2win(vleObjectProperty.Values[_lc[I_PROP_TR_MUSIC_NAME]]);
5097 FillByte(Data.MusicName[0], 64, 0);
5098 if s <> '' then
5099 Move(s[1], Data.MusicName[0], Min(Length(s), 64));
5101 if vleObjectProperty.Values[_lc[I_PROP_TR_MUSIC_ACT]] = _lc[I_PROP_TR_MUSIC_ON] then
5102 Data.MusicAction := 1
5103 else
5104 Data.MusicAction := 2;
5105 end;
5107 TRIGGER_PUSH:
5108 begin
5109 Data.PushAngle := Min(
5110 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_PUSH_ANGLE]], 0), 360);
5111 Data.PushForce := Min(
5112 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_PUSH_FORCE]], 0), 255);
5113 Data.ResetVel := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_PUSH_RESET]]);
5114 end;
5116 TRIGGER_SCORE:
5117 begin
5118 Data.ScoreAction := 0;
5119 if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_ACT]] = _lc[I_PROP_TR_SCORE_ACT_1] then
5120 Data.ScoreAction := 1
5121 else if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_ACT]] = _lc[I_PROP_TR_SCORE_ACT_2] then
5122 Data.ScoreAction := 2
5123 else if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_ACT]] = _lc[I_PROP_TR_SCORE_ACT_3] then
5124 Data.ScoreAction := 3;
5125 Data.ScoreCount := Min(Max(
5126 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_COUNT]], 0), 0), 255);
5127 Data.ScoreTeam := 0;
5128 if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_TEAM]] = _lc[I_PROP_TR_SCORE_TEAM_1] then
5129 Data.ScoreTeam := 1
5130 else if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_TEAM]] = _lc[I_PROP_TR_SCORE_TEAM_2] then
5131 Data.ScoreTeam := 2
5132 else if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_TEAM]] = _lc[I_PROP_TR_SCORE_TEAM_3] then
5133 Data.ScoreTeam := 3;
5134 Data.ScoreCon := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_CON]]);
5135 Data.ScoreMsg := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_MSG]]);
5136 end;
5138 TRIGGER_MESSAGE:
5139 begin
5140 Data.MessageKind := 0;
5141 if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_KIND]] = _lc[I_PROP_TR_MESSAGE_KIND_1] then
5142 Data.MessageKind := 1;
5144 Data.MessageSendTo := 0;
5145 if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_1] then
5146 Data.MessageSendTo := 1
5147 else if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_2] then
5148 Data.MessageSendTo := 2
5149 else if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_3] then
5150 Data.MessageSendTo := 3
5151 else if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_4] then
5152 Data.MessageSendTo := 4
5153 else if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_5] then
5154 Data.MessageSendTo := 5;
5156 s := utf2win(vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TEXT]]);
5157 FillByte(Data.MessageText[0], 100, 0);
5158 if s <> '' then
5159 Move(s[1], Data.MessageText[0], Min(Length(s), 100));
5161 Data.MessageTime := Min(Max(
5162 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TIME]], 0), 0), 65535);
5163 end;
5165 TRIGGER_DAMAGE:
5166 begin
5167 Data.DamageValue := Min(Max(
5168 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_DAMAGE_VALUE]], 0), 0), 65535);
5169 Data.DamageInterval := Min(Max(
5170 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_INTERVAL]], 0), 0), 65535);
5171 end;
5173 TRIGGER_HEALTH:
5174 begin
5175 Data.HealValue := Min(Max(
5176 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_HEALTH]], 0), 0), 65535);
5177 Data.HealInterval := Min(Max(
5178 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_INTERVAL]], 0), 0), 65535);
5179 Data.HealMax := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_HEALTH_MAX]]);
5180 Data.HealSilent := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SILENT]]);
5181 end;
5183 TRIGGER_SHOT:
5184 begin
5185 Data.ShotType := StrToShot(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TYPE]]);
5186 Data.ShotSound := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_SOUND]]);
5187 Data.ShotTarget := 0;
5188 if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_1] then
5189 Data.ShotTarget := 1
5190 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_2] then
5191 Data.ShotTarget := 2
5192 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_3] then
5193 Data.ShotTarget := 3
5194 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_4] then
5195 Data.ShotTarget := 4
5196 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_5] then
5197 Data.ShotTarget := 5
5198 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_6] then
5199 Data.ShotTarget := 6;
5200 Data.ShotIntSight := Min(Max(
5201 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_SIGHT]], 0), 0), 65535);
5202 Data.ShotAim := 0;
5203 if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_AIM]] = _lc[I_PROP_TR_SHOT_AIM_1] then
5204 Data.ShotAim := 1
5205 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_AIM]] = _lc[I_PROP_TR_SHOT_AIM_2] then
5206 Data.ShotAim := 2
5207 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_AIM]] = _lc[I_PROP_TR_SHOT_AIM_3] then
5208 Data.ShotAim := 3;
5209 Data.ShotAngle := Min(
5210 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_ANGLE]], 0), 360);
5211 Data.ShotWait := Min(Max(
5212 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EX_DELAY]], 0), 0), 65535);
5213 Data.ShotAccuracy := Min(Max(
5214 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_ACC]], 0), 0), 65535);
5215 Data.ShotAmmo := Min(Max(
5216 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_AMMO]], 0), 0), 65535);
5217 Data.ShotIntReload := Min(Max(
5218 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_RELOAD]], 0), 0), 65535);
5219 end;
5221 TRIGGER_EFFECT:
5222 begin
5223 Data.FXCount := Min(Max(
5224 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_COUNT]], 0), 0), 255);
5225 if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_TYPE]] = _lc[I_PROP_TR_EFFECT_PARTICLE] then
5226 begin
5227 Data.FXType := TRIGGER_EFFECT_PARTICLE;
5228 Data.FXSubType := TRIGGER_EFFECT_SLIQUID;
5229 if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_SLIQUID] then
5230 Data.FXSubType := TRIGGER_EFFECT_SLIQUID
5231 else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_LLIQUID] then
5232 Data.FXSubType := TRIGGER_EFFECT_LLIQUID
5233 else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_DLIQUID] then
5234 Data.FXSubType := TRIGGER_EFFECT_DLIQUID
5235 else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_BLOOD] then
5236 Data.FXSubType := TRIGGER_EFFECT_BLOOD
5237 else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_SPARK] then
5238 Data.FXSubType := TRIGGER_EFFECT_SPARK
5239 else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_BUBBLE] then
5240 Data.FXSubType := TRIGGER_EFFECT_BUBBLE;
5241 end else
5242 begin
5243 Data.FXType := TRIGGER_EFFECT_ANIMATION;
5244 Data.FXSubType := StrToEffect(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]]);
5245 end;
5246 a := Min(Max(
5247 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_COLOR]], 0), 0), $FFFFFF);
5248 Data.FXColorR := a and $FF;
5249 Data.FXColorG := (a shr 8) and $FF;
5250 Data.FXColorB := (a shr 16) and $FF;
5251 if NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_CENTER]]) then
5252 Data.FXPos := 0
5253 else
5254 Data.FXPos := 1;
5255 Data.FXWait := Min(Max(
5256 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EX_DELAY]], 0), 0), 65535);
5257 Data.FXVelX := Min(Max(
5258 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_VELX]], 0), -128), 127);
5259 Data.FXVelY := Min(Max(
5260 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_VELY]], 0), -128), 127);
5261 Data.FXSpreadL := Min(Max(
5262 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SPL]], 0), 0), 255);
5263 Data.FXSpreadR := Min(Max(
5264 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SPR]], 0), 0), 255);
5265 Data.FXSpreadU := Min(Max(
5266 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SPU]], 0), 0), 255);
5267 Data.FXSpreadD := Min(Max(
5268 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SPD]], 0), 0), 255);
5269 end;
5270 end;
5271 end;
5272 end;
5273 end;
5275 FillProperty();
5277 vleObjectProperty.Row := r;
5278 vleObjectProperty.Col := c;
5279 end;
5281 procedure TMainForm.bbRemoveTextureClick(Sender: TObject);
5282 var
5283 a, i: Integer;
5284 begin
5285 i := lbTextureList.ItemIndex;
5286 if i = -1 then
5287 Exit;
5289 if MessageBox(0, PChar(Format(_lc[I_MSG_DEL_TEXTURE_PROMT],
5290 [SelectedTexture()])),
5291 PChar(_lc[I_MSG_DEL_TEXTURE]),
5292 MB_ICONQUESTION or MB_YESNO or
5293 MB_DEFBUTTON1) <> idYes then
5294 Exit;
5296 if gPanels <> nil then
5297 for a := 0 to High(gPanels) do
5298 if (gPanels[a].PanelType <> 0) and
5299 (gPanels[a].TextureName = SelectedTexture()) then
5300 begin
5301 ErrorMessageBox(_lc[I_MSG_DEL_TEXTURE_CANT]);
5302 Exit;
5303 end;
5305 g_DeleteTexture(SelectedTexture());
5306 i := slInvalidTextures.IndexOf(lbTextureList.Items[i]);
5307 if i > -1 then
5308 slInvalidTextures.Delete(i);
5309 if lbTextureList.ItemIndex > -1 then
5310 lbTextureList.Items.Delete(lbTextureList.ItemIndex)
5311 end;
5313 procedure TMainForm.aNewMapExecute(Sender: TObject);
5314 begin
5315 if (MessageBox(0, PChar(_lc[I_MSG_CLEAR_MAP_PROMT]),
5316 PChar(_lc[I_MSG_CLEAR_MAP]),
5317 MB_ICONQUESTION or MB_YESNO or
5318 MB_DEFBUTTON1) = mrYes) then
5319 FullClear();
5320 end;
5322 procedure TMainForm.aUndoExecute(Sender: TObject);
5323 var
5324 a: Integer;
5325 begin
5326 if UndoBuffer = nil then
5327 Exit;
5328 if UndoBuffer[High(UndoBuffer)] = nil then
5329 Exit;
5331 for a := 0 to High(UndoBuffer[High(UndoBuffer)]) do
5332 with UndoBuffer[High(UndoBuffer)][a] do
5333 begin
5334 case UndoType of
5335 UNDO_DELETE_PANEL:
5336 begin
5337 AddPanel(Panel^);
5338 Panel := nil;
5339 end;
5340 UNDO_DELETE_ITEM: AddItem(Item);
5341 UNDO_DELETE_AREA: AddArea(Area);
5342 UNDO_DELETE_MONSTER: AddMonster(Monster);
5343 UNDO_DELETE_TRIGGER: AddTrigger(Trigger);
5344 UNDO_ADD_PANEL: RemoveObject(AddID, OBJECT_PANEL);
5345 UNDO_ADD_ITEM: RemoveObject(AddID, OBJECT_ITEM);
5346 UNDO_ADD_AREA: RemoveObject(AddID, OBJECT_AREA);
5347 UNDO_ADD_MONSTER: RemoveObject(AddID, OBJECT_MONSTER);
5348 UNDO_ADD_TRIGGER: RemoveObject(AddID, OBJECT_TRIGGER);
5349 end;
5350 end;
5352 SetLength(UndoBuffer, Length(UndoBuffer)-1);
5354 RemoveSelectFromObjects();
5356 miUndo.Enabled := UndoBuffer <> nil;
5357 end;
5360 procedure TMainForm.aCopyObjectExecute(Sender: TObject);
5361 var
5362 a, b: Integer;
5363 CopyBuffer: TCopyRecArray;
5364 str: String;
5365 ok: Boolean;
5367 function CB_Compare(I1, I2: TCopyRec): Integer;
5368 begin
5369 Result := Integer(I1.ObjectType) - Integer(I2.ObjectType);
5371 if Result = 0 then // Одного типа
5372 Result := Integer(I1.ID) - Integer(I2.ID);
5373 end;
5375 procedure QuickSortCopyBuffer(L, R: Integer);
5376 var
5377 I, J: Integer;
5378 P, T: TCopyRec;
5379 begin
5380 repeat
5381 I := L;
5382 J := R;
5383 P := CopyBuffer[(L + R) shr 1];
5385 repeat
5386 while CB_Compare(CopyBuffer[I], P) < 0 do
5387 Inc(I);
5388 while CB_Compare(CopyBuffer[J], P) > 0 do
5389 Dec(J);
5391 if I <= J then
5392 begin
5393 T := CopyBuffer[I];
5394 CopyBuffer[I] := CopyBuffer[J];
5395 CopyBuffer[J] := T;
5396 Inc(I);
5397 Dec(J);
5398 end;
5399 until I > J;
5401 if L < J then
5402 QuickSortCopyBuffer(L, J);
5404 L := I;
5405 until I >= R;
5406 end;
5408 begin
5409 if SelectedObjects = nil then
5410 Exit;
5412 b := -1;
5413 CopyBuffer := nil;
5415 // Копируем объекты:
5416 for a := 0 to High(SelectedObjects) do
5417 if SelectedObjects[a].Live then
5418 with SelectedObjects[a] do
5419 begin
5420 SetLength(CopyBuffer, Length(CopyBuffer)+1);
5421 b := High(CopyBuffer);
5422 CopyBuffer[b].ID := ID;
5423 CopyBuffer[b].Panel := nil;
5425 case ObjectType of
5426 OBJECT_PANEL:
5427 begin
5428 CopyBuffer[b].ObjectType := OBJECT_PANEL;
5429 New(CopyBuffer[b].Panel);
5430 CopyBuffer[b].Panel^ := gPanels[ID];
5431 end;
5433 OBJECT_ITEM:
5434 begin
5435 CopyBuffer[b].ObjectType := OBJECT_ITEM;
5436 CopyBuffer[b].Item := gItems[ID];
5437 end;
5439 OBJECT_MONSTER:
5440 begin
5441 CopyBuffer[b].ObjectType := OBJECT_MONSTER;
5442 CopyBuffer[b].Monster := gMonsters[ID];
5443 end;
5445 OBJECT_AREA:
5446 begin
5447 CopyBuffer[b].ObjectType := OBJECT_AREA;
5448 CopyBuffer[b].Area := gAreas[ID];
5449 end;
5451 OBJECT_TRIGGER:
5452 begin
5453 CopyBuffer[b].ObjectType := OBJECT_TRIGGER;
5454 CopyBuffer[b].Trigger := gTriggers[ID];
5455 end;
5456 end;
5457 end;
5459 // Сортировка по ID:
5460 if CopyBuffer <> nil then
5461 begin
5462 QuickSortCopyBuffer(0, b);
5463 end;
5465 // Пестановка ссылок триггеров:
5466 for a := 0 to Length(CopyBuffer)-1 do
5467 if CopyBuffer[a].ObjectType = OBJECT_TRIGGER then
5468 begin
5469 case CopyBuffer[a].Trigger.TriggerType of
5470 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
5471 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP,
5472 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
5473 if CopyBuffer[a].Trigger.Data.PanelID <> -1 then
5474 begin
5475 ok := False;
5477 for b := 0 to Length(CopyBuffer)-1 do
5478 if (CopyBuffer[b].ObjectType = OBJECT_PANEL) and
5479 (Integer(CopyBuffer[b].ID) = CopyBuffer[a].Trigger.Data.PanelID) then
5480 begin
5481 CopyBuffer[a].Trigger.Data.PanelID := b;
5482 ok := True;
5483 Break;
5484 end;
5486 // Этих панелей нет среди копируемых:
5487 if not ok then
5488 CopyBuffer[a].Trigger.Data.PanelID := -1;
5489 end;
5491 TRIGGER_PRESS, TRIGGER_ON,
5492 TRIGGER_OFF, TRIGGER_ONOFF:
5493 if CopyBuffer[a].Trigger.Data.MonsterID <> 0 then
5494 begin
5495 ok := False;
5497 for b := 0 to Length(CopyBuffer)-1 do
5498 if (CopyBuffer[b].ObjectType = OBJECT_MONSTER) and
5499 (Integer(CopyBuffer[b].ID) = CopyBuffer[a].Trigger.Data.MonsterID-1) then
5500 begin
5501 CopyBuffer[a].Trigger.Data.MonsterID := b+1;
5502 ok := True;
5503 Break;
5504 end;
5506 // Этих монстров нет среди копируемых:
5507 if not ok then
5508 CopyBuffer[a].Trigger.Data.MonsterID := 0;
5509 end;
5511 TRIGGER_SHOT:
5512 if CopyBuffer[a].Trigger.Data.ShotPanelID <> -1 then
5513 begin
5514 ok := False;
5516 for b := 0 to Length(CopyBuffer)-1 do
5517 if (CopyBuffer[b].ObjectType = OBJECT_PANEL) and
5518 (Integer(CopyBuffer[b].ID) = CopyBuffer[a].Trigger.Data.ShotPanelID) then
5519 begin
5520 CopyBuffer[a].Trigger.Data.ShotPanelID := b;
5521 ok := True;
5522 Break;
5523 end;
5525 // Этих панелей нет среди копируемых:
5526 if not ok then
5527 CopyBuffer[a].Trigger.Data.ShotPanelID := -1;
5528 end;
5529 end;
5531 if CopyBuffer[a].Trigger.TexturePanel <> -1 then
5532 begin
5533 ok := False;
5535 for b := 0 to Length(CopyBuffer)-1 do
5536 if (CopyBuffer[b].ObjectType = OBJECT_PANEL) and
5537 (Integer(CopyBuffer[b].ID) = CopyBuffer[a].Trigger.TexturePanel) then
5538 begin
5539 CopyBuffer[a].Trigger.TexturePanel := b;
5540 ok := True;
5541 Break;
5542 end;
5544 // Этих панелей нет среди копируемых:
5545 if not ok then
5546 CopyBuffer[a].Trigger.TexturePanel := -1;
5547 end;
5548 end;
5550 // В буфер обмена:
5551 str := CopyBufferToString(CopyBuffer);
5552 ClipBoard.AsText := str;
5554 for a := 0 to Length(CopyBuffer)-1 do
5555 if (CopyBuffer[a].ObjectType = OBJECT_PANEL) and
5556 (CopyBuffer[a].Panel <> nil) then
5557 Dispose(CopyBuffer[a].Panel);
5559 CopyBuffer := nil;
5560 end;
5562 procedure TMainForm.aPasteObjectExecute(Sender: TObject);
5563 var
5564 a, h: Integer;
5565 CopyBuffer: TCopyRecArray;
5566 res, rel: Boolean;
5567 swad, ssec, sres: String;
5568 NoTextureID: DWORD;
5569 pmin: TPoint;
5570 begin
5571 CopyBuffer := nil;
5572 NoTextureID := 0;
5573 pmin.X := High(pmin.X);
5574 pmin.Y := High(pmin.Y);
5576 StringToCopyBuffer(ClipBoard.AsText, CopyBuffer, pmin);
5577 rel := not(ssShift in GetKeyShiftState());
5579 if CopyBuffer = nil then
5580 Exit;
5582 RemoveSelectFromObjects();
5584 h := High(CopyBuffer);
5585 for a := 0 to h do
5586 with CopyBuffer[a] do
5587 begin
5588 case ObjectType of
5589 OBJECT_PANEL:
5590 if Panel <> nil then
5591 begin
5592 if rel then
5593 begin
5594 Panel^.X := Panel^.X - pmin.X - MapOffset.X + 32;
5595 Panel^.Y := Panel^.Y - pmin.Y - MapOffset.Y + 32;
5596 end;
5598 Panel^.TextureID := TEXTURE_SPECIAL_NONE;
5599 Panel^.TextureWidth := 1;
5600 Panel^.TextureHeight := 1;
5602 if (Panel^.PanelType = PANEL_LIFTUP) or
5603 (Panel^.PanelType = PANEL_LIFTDOWN) or
5604 (Panel^.PanelType = PANEL_LIFTLEFT) or
5605 (Panel^.PanelType = PANEL_LIFTRIGHT) or
5606 (Panel^.PanelType = PANEL_BLOCKMON) or
5607 (Panel^.TextureName = '') then
5608 begin // Нет или не может быть текстуры:
5609 end
5610 else // Есть текстура:
5611 begin
5612 // Обычная текстура:
5613 if not IsSpecialTexture(Panel^.TextureName) then
5614 begin
5615 res := g_GetTexture(Panel^.TextureName, Panel^.TextureID);
5617 if not res then
5618 begin
5619 g_ProcessResourceStr(Panel^.TextureName, swad, ssec, sres);
5620 AddTexture(swad, ssec, sres, True);
5621 res := g_GetTexture(Panel^.TextureName, Panel^.TextureID);
5622 end;
5624 if res then
5625 g_GetTextureSizeByName(Panel^.TextureName,
5626 Panel^.TextureWidth, Panel^.TextureHeight)
5627 else
5628 if g_GetTexture('NOTEXTURE', NoTextureID) then
5629 begin
5630 Panel^.TextureID := TEXTURE_SPECIAL_NOTEXTURE;
5631 g_GetTextureSizeByID(NoTextureID, Panel^.TextureWidth, Panel^.TextureHeight);
5632 end;
5633 end
5634 else // Спец.текстура:
5635 begin
5636 Panel^.TextureID := SpecialTextureID(Panel^.TextureName);
5637 with MainForm.lbTextureList.Items do
5638 if IndexOf(Panel^.TextureName) = -1 then
5639 Add(Panel^.TextureName);
5640 end;
5641 end;
5643 ID := AddPanel(Panel^);
5644 Dispose(Panel);
5645 Undo_Add(OBJECT_PANEL, ID, a > 0);
5646 SelectObject(OBJECT_PANEL, ID, True);
5647 end;
5649 OBJECT_ITEM:
5650 begin
5651 if rel then
5652 begin
5653 Item.X := Item.X - pmin.X - MapOffset.X + 32;
5654 Item.Y := Item.Y - pmin.Y - MapOffset.Y + 32;
5655 end;
5657 ID := AddItem(Item);
5658 Undo_Add(OBJECT_ITEM, ID, a > 0);
5659 SelectObject(OBJECT_ITEM, ID, True);
5660 end;
5662 OBJECT_MONSTER:
5663 begin
5664 if rel then
5665 begin
5666 Monster.X := Monster.X - pmin.X - MapOffset.X + 32;
5667 Monster.Y := Monster.Y - pmin.Y - MapOffset.Y + 32;
5668 end;
5670 ID := AddMonster(Monster);
5671 Undo_Add(OBJECT_MONSTER, ID, a > 0);
5672 SelectObject(OBJECT_MONSTER, ID, True);
5673 end;
5675 OBJECT_AREA:
5676 begin
5677 if rel then
5678 begin
5679 Area.X := Area.X - pmin.X - MapOffset.X + 32;
5680 Area.Y := Area.Y - pmin.Y - MapOffset.Y + 32;
5681 end;
5683 ID := AddArea(Area);
5684 Undo_Add(OBJECT_AREA, ID, a > 0);
5685 SelectObject(OBJECT_AREA, ID, True);
5686 end;
5688 OBJECT_TRIGGER:
5689 begin
5690 if rel then
5691 with Trigger do
5692 begin
5693 X := X - pmin.X - MapOffset.X + 32;
5694 Y := Y - pmin.Y - MapOffset.Y + 32;
5696 case TriggerType of
5697 TRIGGER_TELEPORT:
5698 begin
5699 Data.TargetPoint.X :=
5700 Data.TargetPoint.X - pmin.X - MapOffset.X + 32;
5701 Data.TargetPoint.Y :=
5702 Data.TargetPoint.Y - pmin.Y - MapOffset.Y + 32;
5703 end;
5704 TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF:
5705 begin
5706 Data.tX := Data.tX - pmin.X - MapOffset.X + 32;
5707 Data.tY := Data.tY - pmin.Y - MapOffset.Y + 32;
5708 end;
5709 TRIGGER_SPAWNMONSTER:
5710 begin
5711 Data.MonPos.X :=
5712 Data.MonPos.X - pmin.X - MapOffset.X + 32;
5713 Data.MonPos.Y :=
5714 Data.MonPos.Y - pmin.Y - MapOffset.Y + 32;
5715 end;
5716 TRIGGER_SPAWNITEM:
5717 begin
5718 Data.ItemPos.X :=
5719 Data.ItemPos.X - pmin.X - MapOffset.X + 32;
5720 Data.ItemPos.Y :=
5721 Data.ItemPos.Y - pmin.Y - MapOffset.Y + 32;
5722 end;
5723 TRIGGER_SHOT:
5724 begin
5725 Data.ShotPos.X :=
5726 Data.ShotPos.X - pmin.X - MapOffset.X + 32;
5727 Data.ShotPos.Y :=
5728 Data.ShotPos.Y - pmin.Y - MapOffset.Y + 32;
5729 end;
5730 end;
5731 end;
5733 ID := AddTrigger(Trigger);
5734 Undo_Add(OBJECT_TRIGGER, ID, a > 0);
5735 SelectObject(OBJECT_TRIGGER, ID, True);
5736 end;
5737 end;
5738 end;
5740 // Переставляем ссылки триггеров:
5741 for a := 0 to High(CopyBuffer) do
5742 if CopyBuffer[a].ObjectType = OBJECT_TRIGGER then
5743 begin
5744 case CopyBuffer[a].Trigger.TriggerType of
5745 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
5746 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP,
5747 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
5748 if CopyBuffer[a].Trigger.Data.PanelID <> -1 then
5749 gTriggers[CopyBuffer[a].ID].Data.PanelID :=
5750 CopyBuffer[CopyBuffer[a].Trigger.Data.PanelID].ID;
5752 TRIGGER_PRESS, TRIGGER_ON,
5753 TRIGGER_OFF, TRIGGER_ONOFF:
5754 if CopyBuffer[a].Trigger.Data.MonsterID <> 0 then
5755 gTriggers[CopyBuffer[a].ID].Data.MonsterID :=
5756 CopyBuffer[CopyBuffer[a].Trigger.Data.MonsterID-1].ID+1;
5758 TRIGGER_SHOT:
5759 if CopyBuffer[a].Trigger.Data.ShotPanelID <> -1 then
5760 gTriggers[CopyBuffer[a].ID].Data.ShotPanelID :=
5761 CopyBuffer[CopyBuffer[a].Trigger.Data.ShotPanelID].ID;
5762 end;
5764 if CopyBuffer[a].Trigger.TexturePanel <> -1 then
5765 gTriggers[CopyBuffer[a].ID].TexturePanel :=
5766 CopyBuffer[CopyBuffer[a].Trigger.TexturePanel].ID;
5767 end;
5769 CopyBuffer := nil;
5771 if h = 0 then
5772 FillProperty();
5773 end;
5775 procedure TMainForm.aCutObjectExecute(Sender: TObject);
5776 begin
5777 miCopy.Click();
5778 DeleteSelectedObjects();
5779 end;
5781 procedure TMainForm.vleObjectPropertyEditButtonClick(Sender: TObject);
5782 var
5783 Key, FileName: String;
5784 b: Byte;
5785 begin
5786 Key := vleObjectProperty.Keys[vleObjectProperty.Row];
5788 if Key = _lc[I_PROP_PANEL_TYPE] then
5789 begin
5790 with ChooseTypeForm, vleObjectProperty do
5791 begin // Выбор типа панели:
5792 Caption := _lc[I_PROP_PANEL_TYPE];
5793 lbTypeSelect.Items.Clear();
5795 for b := 0 to High(PANELNAMES) do
5796 begin
5797 lbTypeSelect.Items.Add(PANELNAMES[b]);
5798 if Values[Key] = PANELNAMES[b] then
5799 lbTypeSelect.ItemIndex := b;
5800 end;
5802 if ShowModal() = mrOK then
5803 begin
5804 b := lbTypeSelect.ItemIndex;
5805 Values[Key] := PANELNAMES[b];
5806 vleObjectPropertyApply(Sender);
5807 end;
5808 end
5809 end
5810 else if Key = _lc[I_PROP_TR_TELEPORT_TO] then
5811 SelectFlag := SELECTFLAG_TELEPORT
5812 else if Key = _lc[I_PROP_TR_SPAWN_TO] then
5813 SelectFlag := SELECTFLAG_SPAWNPOINT
5814 else if (Key = _lc[I_PROP_TR_DOOR_PANEL]) or
5815 (Key = _lc[I_PROP_TR_TRAP_PANEL]) then
5816 SelectFlag := SELECTFLAG_DOOR
5817 else if Key = _lc[I_PROP_TR_TEXTURE_PANEL] then
5818 begin
5819 DrawPressRect := False;
5820 SelectFlag := SELECTFLAG_TEXTURE;
5821 end
5822 else if Key = _lc[I_PROP_TR_SHOT_PANEL] then
5823 SelectFlag := SELECTFLAG_SHOTPANEL
5824 else if Key = _lc[I_PROP_TR_LIFT_PANEL] then
5825 SelectFlag := SELECTFLAG_LIFT
5826 else if key = _lc[I_PROP_TR_EX_MONSTER] then
5827 SelectFlag := SELECTFLAG_MONSTER
5828 else if Key = _lc[I_PROP_TR_EX_AREA] then
5829 begin
5830 SelectFlag := SELECTFLAG_NONE;
5831 DrawPressRect := True;
5832 end
5833 else if Key = _lc[I_PROP_TR_NEXT_MAP] then
5834 begin // Выбор следующей карты:
5835 g_ProcessResourceStr(OpenedMap, @FileName, nil, nil);
5836 SelectMapForm.Caption := _lc[I_CAP_SELECT];
5837 SelectMapForm.GetMaps(FileName);
5839 if SelectMapForm.ShowModal() = mrOK then
5840 begin
5841 vleObjectProperty.Values[Key] := SelectMapForm.lbMapList.Items[SelectMapForm.lbMapList.ItemIndex];
5842 vleObjectPropertyApply(Sender);
5843 end;
5844 end
5845 else if (Key = _lc[I_PROP_TR_SOUND_NAME]) or
5846 (Key = _lc[I_PROP_TR_MUSIC_NAME]) then
5847 begin // Выбор файла звука/музыки:
5848 AddSoundForm.OKFunction := nil;
5849 AddSoundForm.lbResourcesList.MultiSelect := False;
5850 AddSoundForm.SetResource := vleObjectProperty.Values[Key];
5852 if (AddSoundForm.ShowModal() = mrOk) then
5853 begin
5854 vleObjectProperty.Values[Key] := AddSoundForm.ResourceName;
5855 vleObjectPropertyApply(Sender);
5856 end;
5857 end
5858 else if Key = _lc[I_PROP_TR_ACTIVATION] then
5859 with ActivationTypeForm, vleObjectProperty do
5860 begin // Выбор типов активации:
5861 cbPlayerCollide.Checked := Pos('PC', Values[Key]) > 0;
5862 cbMonsterCollide.Checked := Pos('MC', Values[Key]) > 0;
5863 cbPlayerPress.Checked := Pos('PP', Values[Key]) > 0;
5864 cbMonsterPress.Checked := Pos('MP', Values[Key]) > 0;
5865 cbShot.Checked := Pos('SH', Values[Key]) > 0;
5866 cbNoMonster.Checked := Pos('NM', Values[Key]) > 0;
5868 if ShowModal() = mrOK then
5869 begin
5870 b := 0;
5871 if cbPlayerCollide.Checked then
5872 b := ACTIVATE_PLAYERCOLLIDE;
5873 if cbMonsterCollide.Checked then
5874 b := b or ACTIVATE_MONSTERCOLLIDE;
5875 if cbPlayerPress.Checked then
5876 b := b or ACTIVATE_PLAYERPRESS;
5877 if cbMonsterPress.Checked then
5878 b := b or ACTIVATE_MONSTERPRESS;
5879 if cbShot.Checked then
5880 b := b or ACTIVATE_SHOT;
5881 if cbNoMonster.Checked then
5882 b := b or ACTIVATE_NOMONSTER;
5884 Values[Key] := ActivateToStr(b);
5885 vleObjectPropertyApply(Sender);
5886 end;
5887 end
5888 else if Key = _lc[I_PROP_TR_KEYS] then
5889 with KeysForm, vleObjectProperty do
5890 begin // Выбор необходимых ключей:
5891 cbRedKey.Checked := Pos('RK', Values[Key]) > 0;
5892 cbGreenKey.Checked := Pos('GK', Values[Key]) > 0;
5893 cbBlueKey.Checked := Pos('BK', Values[Key]) > 0;
5894 cbRedTeam.Checked := Pos('RT', Values[Key]) > 0;
5895 cbBlueTeam.Checked := Pos('BT', Values[Key]) > 0;
5897 if ShowModal() = mrOK then
5898 begin
5899 b := 0;
5900 if cbRedKey.Checked then
5901 b := KEY_RED;
5902 if cbGreenKey.Checked then
5903 b := b or KEY_GREEN;
5904 if cbBlueKey.Checked then
5905 b := b or KEY_BLUE;
5906 if cbRedTeam.Checked then
5907 b := b or KEY_REDTEAM;
5908 if cbBlueTeam.Checked then
5909 b := b or KEY_BLUETEAM;
5911 Values[Key] := KeyToStr(b);
5912 vleObjectPropertyApply(Sender);
5913 end;
5914 end
5915 else if Key = _lc[I_PROP_TR_FX_TYPE] then
5916 with ChooseTypeForm, vleObjectProperty do
5917 begin // Выбор типа эффекта:
5918 Caption := _lc[I_CAP_FX_TYPE];
5919 lbTypeSelect.Items.Clear();
5921 for b := EFFECT_NONE to EFFECT_FIRE do
5922 lbTypeSelect.Items.Add(EffectToStr(b));
5924 lbTypeSelect.ItemIndex := StrToEffect(Values[Key]);
5926 if ShowModal() = mrOK then
5927 begin
5928 b := lbTypeSelect.ItemIndex;
5929 Values[Key] := EffectToStr(b);
5930 vleObjectPropertyApply(Sender);
5931 end;
5932 end
5933 else if Key = _lc[I_PROP_TR_MONSTER_TYPE] then
5934 with ChooseTypeForm, vleObjectProperty do
5935 begin // Выбор типа монстра:
5936 Caption := _lc[I_CAP_MONSTER_TYPE];
5937 lbTypeSelect.Items.Clear();
5939 for b := MONSTER_DEMON to MONSTER_MAN do
5940 lbTypeSelect.Items.Add(MonsterToStr(b));
5942 lbTypeSelect.ItemIndex := StrToMonster(Values[Key]) - MONSTER_DEMON;
5944 if ShowModal() = mrOK then
5945 begin
5946 b := lbTypeSelect.ItemIndex + MONSTER_DEMON;
5947 Values[Key] := MonsterToStr(b);
5948 vleObjectPropertyApply(Sender);
5949 end;
5950 end
5951 else if Key = _lc[I_PROP_TR_ITEM_TYPE] then
5952 with ChooseTypeForm, vleObjectProperty do
5953 begin // Выбор типа предмета:
5954 Caption := _lc[I_CAP_ITEM_TYPE];
5955 lbTypeSelect.Items.Clear();
5957 for b := ITEM_MEDKIT_SMALL to ITEM_KEY_BLUE do
5958 lbTypeSelect.Items.Add(ItemToStr(b));
5959 lbTypeSelect.Items.Add(ItemToStr(ITEM_BOTTLE));
5960 lbTypeSelect.Items.Add(ItemToStr(ITEM_HELMET));
5961 lbTypeSelect.Items.Add(ItemToStr(ITEM_JETPACK));
5962 lbTypeSelect.Items.Add(ItemToStr(ITEM_INVIS));
5963 lbTypeSelect.Items.Add(ItemToStr(ITEM_WEAPON_FLAMETHROWER));
5964 lbTypeSelect.Items.Add(ItemToStr(ITEM_AMMO_FUELCAN));
5966 b := StrToItem(Values[Key]);
5967 if b >= ITEM_BOTTLE then
5968 b := b - 2;
5969 lbTypeSelect.ItemIndex := b - ITEM_MEDKIT_SMALL;
5971 if ShowModal() = mrOK then
5972 begin
5973 b := lbTypeSelect.ItemIndex + ITEM_MEDKIT_SMALL;
5974 if b >= ITEM_WEAPON_KASTET then
5975 b := b + 2;
5976 Values[Key] := ItemToStr(b);
5977 vleObjectPropertyApply(Sender);
5978 end;
5979 end
5980 else if Key = _lc[I_PROP_TR_SHOT_TYPE] then
5981 with ChooseTypeForm, vleObjectProperty do
5982 begin // Выбор типа предмета:
5983 Caption := _lc[I_PROP_TR_SHOT_TYPE];
5984 lbTypeSelect.Items.Clear();
5986 for b := TRIGGER_SHOT_PISTOL to TRIGGER_SHOT_MAX do
5987 lbTypeSelect.Items.Add(ShotToStr(b));
5989 lbTypeSelect.ItemIndex := StrToShot(Values[Key]);
5991 if ShowModal() = mrOK then
5992 begin
5993 b := lbTypeSelect.ItemIndex;
5994 Values[Key] := ShotToStr(b);
5995 vleObjectPropertyApply(Sender);
5996 end;
5997 end
5998 else if Key = _lc[I_PROP_TR_EFFECT_TYPE] then
5999 with ChooseTypeForm, vleObjectProperty do
6000 begin // Выбор типа эффекта:
6001 Caption := _lc[I_CAP_FX_TYPE];
6002 lbTypeSelect.Items.Clear();
6004 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_PARTICLE]);
6005 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_ANIMATION]);
6006 if Values[Key] = _lc[I_PROP_TR_EFFECT_ANIMATION] then
6007 lbTypeSelect.ItemIndex := 1
6008 else
6009 lbTypeSelect.ItemIndex := 0;
6011 if ShowModal() = mrOK then
6012 begin
6013 b := lbTypeSelect.ItemIndex;
6014 if b = 0 then
6015 Values[Key] := _lc[I_PROP_TR_EFFECT_PARTICLE]
6016 else
6017 Values[Key] := _lc[I_PROP_TR_EFFECT_ANIMATION];
6018 vleObjectPropertyApply(Sender);
6019 end;
6020 end
6021 else if Key = _lc[I_PROP_TR_EFFECT_SUBTYPE] then
6022 with ChooseTypeForm, vleObjectProperty do
6023 begin // Выбор подтипа эффекта:
6024 Caption := _lc[I_CAP_FX_TYPE];
6025 lbTypeSelect.Items.Clear();
6027 if Values[_lc[I_PROP_TR_EFFECT_TYPE]] = _lc[I_PROP_TR_EFFECT_ANIMATION] then
6028 begin
6029 for b := EFFECT_TELEPORT to EFFECT_FIRE do
6030 lbTypeSelect.Items.Add(EffectToStr(b));
6032 lbTypeSelect.ItemIndex := StrToEffect(Values[Key]) - 1;
6033 end else
6034 begin
6035 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_SLIQUID]);
6036 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_LLIQUID]);
6037 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_DLIQUID]);
6038 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_BLOOD]);
6039 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_SPARK]);
6040 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_BUBBLE]);
6041 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_SLIQUID;
6042 if Values[Key] = _lc[I_PROP_TR_EFFECT_LLIQUID] then
6043 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_LLIQUID;
6044 if Values[Key] = _lc[I_PROP_TR_EFFECT_DLIQUID] then
6045 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_DLIQUID;
6046 if Values[Key] = _lc[I_PROP_TR_EFFECT_BLOOD] then
6047 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_BLOOD;
6048 if Values[Key] = _lc[I_PROP_TR_EFFECT_SPARK] then
6049 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_SPARK;
6050 if Values[Key] = _lc[I_PROP_TR_EFFECT_BUBBLE] then
6051 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_BUBBLE;
6052 end;
6054 if ShowModal() = mrOK then
6055 begin
6056 b := lbTypeSelect.ItemIndex;
6058 if Values[_lc[I_PROP_TR_EFFECT_TYPE]] = _lc[I_PROP_TR_EFFECT_ANIMATION] then
6059 Values[Key] := EffectToStr(b + 1)
6060 else begin
6061 Values[Key] := _lc[I_PROP_TR_EFFECT_SLIQUID];
6062 if b = TRIGGER_EFFECT_LLIQUID then
6063 Values[Key] := _lc[I_PROP_TR_EFFECT_LLIQUID];
6064 if b = TRIGGER_EFFECT_DLIQUID then
6065 Values[Key] := _lc[I_PROP_TR_EFFECT_DLIQUID];
6066 if b = TRIGGER_EFFECT_BLOOD then
6067 Values[Key] := _lc[I_PROP_TR_EFFECT_BLOOD];
6068 if b = TRIGGER_EFFECT_SPARK then
6069 Values[Key] := _lc[I_PROP_TR_EFFECT_SPARK];
6070 if b = TRIGGER_EFFECT_BUBBLE then
6071 Values[Key] := _lc[I_PROP_TR_EFFECT_BUBBLE];
6072 end;
6074 vleObjectPropertyApply(Sender);
6075 end;
6076 end
6077 else if Key = _lc[I_PROP_TR_EFFECT_COLOR] then
6078 with vleObjectProperty do
6079 begin // Выбор цвета эффекта:
6080 ColorDialog.Color := StrToIntDef(Values[Key], 0);
6081 if ColorDialog.Execute then
6082 begin
6083 Values[Key] := IntToStr(ColorDialog.Color);
6084 vleObjectPropertyApply(Sender);
6085 end;
6086 end
6087 else if Key = _lc[I_PROP_PANEL_TEX] then
6088 begin // Смена текстуры:
6089 vleObjectProperty.Values[Key] := SelectedTexture();
6090 vleObjectPropertyApply(Sender);
6091 end;
6092 end;
6094 procedure TMainForm.vleObjectPropertyApply(Sender: TObject);
6095 begin
6096 // hack to prevent empty ID in list
6097 RenderPanel.SetFocus();
6098 bApplyProperty.Click();
6099 vleObjectProperty.SetFocus();
6100 end;
6102 procedure TMainForm.aSaveMapExecute(Sender: TObject);
6103 var
6104 FileName, Section, Res: String;
6105 begin
6106 if OpenedMap = '' then
6107 begin
6108 aSaveMapAsExecute(nil);
6109 Exit;
6110 end;
6112 g_ProcessResourceStr(OpenedMap, FileName, Section, Res);
6114 SaveMap(FileName+':\'+Res);
6115 end;
6117 procedure TMainForm.aOpenMapExecute(Sender: TObject);
6118 begin
6119 OpenDialog.Filter := _lc[I_FILE_FILTER_ALL];
6121 if OpenDialog.Execute() then
6122 begin
6123 OpenMapFile(OpenDialog.FileName);
6124 OpenDialog.InitialDir := ExtractFileDir(OpenDialog.FileName);
6125 end;
6126 end;
6128 procedure TMainForm.OpenMapFile(FileName: String);
6129 begin
6130 if (Pos('.ini', LowerCase(ExtractFileName(FileName))) > 0) then
6131 begin // INI карты:
6132 FullClear();
6134 pLoadProgress.Left := (RenderPanel.Width div 2)-(pLoadProgress.Width div 2);
6135 pLoadProgress.Top := (RenderPanel.Height div 2)-(pLoadProgress.Height div 2);
6136 pLoadProgress.Show();
6138 OpenedMap := '';
6139 OpenedWAD := '';
6141 LoadMapOld(FileName);
6143 MainForm.Caption := Format('%s - %s', [FormCaption, ExtractFileName(FileName)]);
6145 pLoadProgress.Hide();
6146 MainForm.FormResize(Self);
6147 end
6148 else // Карты из WAD:
6149 begin
6150 OpenMap(FileName, '');
6151 end;
6152 end;
6154 procedure TMainForm.FormActivate(Sender: TObject);
6155 var
6156 lang: Integer;
6157 config: TConfig;
6158 begin
6159 MainForm.ActiveControl := RenderPanel;
6161 // Язык:
6162 if gLanguage = '' then
6163 begin
6164 lang := SelectLanguageForm.ShowModal();
6165 case lang of
6166 1: gLanguage := LANGUAGE_ENGLISH;
6167 else gLanguage := LANGUAGE_RUSSIAN;
6168 end;
6170 config := TConfig.CreateFile(EditorDir+'Editor.cfg');
6171 config.WriteStr('Editor', 'Language', gLanguage);
6172 config.SaveFile(EditorDir+'Editor.cfg');
6173 config.Free();
6174 end;
6176 //e_WriteLog('Read language file', MSG_NOTIFY);
6177 //g_Language_Load(EditorDir+'\data\'+gLanguage+LANGUAGE_FILE_NAME);
6178 g_Language_Set(gLanguage);
6179 end;
6181 procedure TMainForm.aDeleteMap(Sender: TObject);
6182 var
6183 res: Integer;
6184 FileName: String;
6185 MapName: String;
6186 begin
6187 OpenDialog.Filter := _lc[I_FILE_FILTER_WAD];
6189 if not OpenDialog.Execute() then
6190 Exit;
6192 FileName := OpenDialog.FileName;
6193 SelectMapForm.Caption := _lc[I_CAP_REMOVE];
6194 SelectMapForm.lbMapList.Items.Clear();
6195 SelectMapForm.GetMaps(FileName);
6197 if SelectMapForm.ShowModal() <> mrOK then
6198 Exit;
6200 MapName := SelectMapForm.lbMapList.Items[SelectMapForm.lbMapList.ItemIndex];
6201 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
6202 Exit;
6204 g_DeleteResource(FileName, '', MapName, res);
6205 if res <> 0 then
6206 begin
6207 MessageBox(0, PChar('Cant delete map res=' + IntToStr(res)), PChar('Map not deleted!'), MB_ICONINFORMATION or MB_OK or MB_DEFBUTTON1);
6208 Exit
6209 end;
6211 MessageBox(
6212 0,
6213 PChar(Format(_lc[I_MSG_MAP_DELETED_PROMT], [MapName])),
6214 PChar(_lc[I_MSG_MAP_DELETED]),
6215 MB_ICONINFORMATION or MB_OK or MB_DEFBUTTON1
6216 );
6218 // Удалили текущую карту - сохранять по старому ее нельзя:
6219 if OpenedMap = (FileName + ':\' + MapName) then
6220 begin
6221 OpenedMap := '';
6222 OpenedWAD := '';
6223 MainForm.Caption := FormCaption
6224 end
6225 end;
6227 procedure TMainForm.vleObjectPropertyKeyDown(Sender: TObject;
6228 var Key: Word; Shift: TShiftState);
6229 begin
6230 if Key = VK_RETURN then
6231 vleObjectPropertyApply(Sender);
6232 end;
6234 procedure MovePanel(var ID: DWORD; MoveType: Byte);
6235 var
6236 _id, a: Integer;
6237 tmp: TPanel;
6238 begin
6239 if (ID = 0) and (MoveType = 0) then
6240 Exit;
6241 if (ID = DWORD(High(gPanels))) and (MoveType <> 0) then
6242 Exit;
6243 if (ID > DWORD(High(gPanels))) then
6244 Exit;
6246 _id := Integer(ID);
6248 if MoveType = 0 then // to Back
6249 begin
6250 if gTriggers <> nil then
6251 for a := 0 to High(gTriggers) do
6252 with gTriggers[a] do
6253 begin
6254 if TriggerType = TRIGGER_NONE then
6255 Continue;
6257 if TexturePanel = _id then
6258 TexturePanel := 0
6259 else
6260 if (TexturePanel >= 0) and (TexturePanel < _id) then
6261 Inc(TexturePanel);
6263 case TriggerType of
6264 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
6265 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP,
6266 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
6267 if Data.PanelID = _id then
6268 Data.PanelID := 0
6269 else
6270 if (Data.PanelID >= 0) and (Data.PanelID < _id) then
6271 Inc(Data.PanelID);
6273 TRIGGER_SHOT:
6274 if Data.ShotPanelID = _id then
6275 Data.ShotPanelID := 0
6276 else
6277 if (Data.ShotPanelID >= 0) and (Data.ShotPanelID < _id) then
6278 Inc(Data.ShotPanelID);
6279 end;
6280 end;
6282 tmp := gPanels[_id];
6284 for a := _id downto 1 do
6285 gPanels[a] := gPanels[a-1];
6287 gPanels[0] := tmp;
6289 ID := 0;
6290 end
6291 else // to Front
6292 begin
6293 if gTriggers <> nil then
6294 for a := 0 to High(gTriggers) do
6295 with gTriggers[a] do
6296 begin
6297 if TriggerType = TRIGGER_NONE then
6298 Continue;
6300 if TexturePanel = _id then
6301 TexturePanel := High(gPanels)
6302 else
6303 if TexturePanel > _id then
6304 Dec(TexturePanel);
6306 case TriggerType of
6307 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
6308 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP,
6309 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
6310 if Data.PanelID = _id then
6311 Data.PanelID := High(gPanels)
6312 else
6313 if Data.PanelID > _id then
6314 Dec(Data.PanelID);
6316 TRIGGER_SHOT:
6317 if Data.ShotPanelID = _id then
6318 Data.ShotPanelID := High(gPanels)
6319 else
6320 if Data.ShotPanelID > _id then
6321 Dec(Data.ShotPanelID);
6322 end;
6323 end;
6325 tmp := gPanels[_id];
6327 for a := _id to High(gPanels)-1 do
6328 gPanels[a] := gPanels[a+1];
6330 gPanels[High(gPanels)] := tmp;
6332 ID := High(gPanels);
6333 end;
6334 end;
6336 procedure TMainForm.aMoveToBack(Sender: TObject);
6337 var
6338 a: Integer;
6339 begin
6340 if SelectedObjects = nil then
6341 Exit;
6343 for a := 0 to High(SelectedObjects) do
6344 with SelectedObjects[a] do
6345 if Live and (ObjectType = OBJECT_PANEL) then
6346 begin
6347 SelectedObjects[0] := SelectedObjects[a];
6348 SetLength(SelectedObjects, 1);
6349 MovePanel(ID, 0);
6350 FillProperty();
6351 Break;
6352 end;
6353 end;
6355 procedure TMainForm.aMoveToFore(Sender: TObject);
6356 var
6357 a: Integer;
6358 begin
6359 if SelectedObjects = nil then
6360 Exit;
6362 for a := 0 to High(SelectedObjects) do
6363 with SelectedObjects[a] do
6364 if Live and (ObjectType = OBJECT_PANEL) then
6365 begin
6366 SelectedObjects[0] := SelectedObjects[a];
6367 SetLength(SelectedObjects, 1);
6368 MovePanel(ID, 1);
6369 FillProperty();
6370 Break;
6371 end;
6372 end;
6374 procedure TMainForm.aSaveMapAsExecute(Sender: TObject);
6375 var
6376 idx: Integer;
6377 begin
6378 SaveDialog.Filter := _lc[I_FILE_FILTER_WAD];
6380 if not SaveDialog.Execute() then
6381 Exit;
6383 SaveMapForm.GetMaps(SaveDialog.FileName, True);
6385 if SaveMapForm.ShowModal() <> mrOK then
6386 Exit;
6388 SaveDialog.InitialDir := ExtractFileDir(SaveDialog.FileName);
6389 OpenedMap := SaveDialog.FileName+':\'+SaveMapForm.eMapName.Text;
6390 OpenedWAD := SaveDialog.FileName;
6392 idx := RecentFiles.IndexOf(OpenedMap);
6393 // Такая карта уже недавно открывалась:
6394 if idx >= 0 then
6395 RecentFiles.Delete(idx);
6396 RecentFiles.Insert(0, OpenedMap);
6397 RefreshRecentMenu;
6399 SaveMap(OpenedMap);
6401 gMapInfo.FileName := SaveDialog.FileName;
6402 gMapInfo.MapName := SaveMapForm.eMapName.Text;
6403 UpdateCaption(gMapInfo.Name, ExtractFileName(gMapInfo.FileName), gMapInfo.MapName);
6404 end;
6406 procedure TMainForm.aSelectAllExecute(Sender: TObject);
6407 var
6408 a: Integer;
6409 begin
6410 RemoveSelectFromObjects();
6412 case pcObjects.ActivePageIndex+1 of
6413 OBJECT_PANEL:
6414 if gPanels <> nil then
6415 for a := 0 to High(gPanels) do
6416 if gPanels[a].PanelType <> PANEL_NONE then
6417 SelectObject(OBJECT_PANEL, a, True);
6418 OBJECT_ITEM:
6419 if gItems <> nil then
6420 for a := 0 to High(gItems) do
6421 if gItems[a].ItemType <> ITEM_NONE then
6422 SelectObject(OBJECT_ITEM, a, True);
6423 OBJECT_MONSTER:
6424 if gMonsters <> nil then
6425 for a := 0 to High(gMonsters) do
6426 if gMonsters[a].MonsterType <> MONSTER_NONE then
6427 SelectObject(OBJECT_MONSTER, a, True);
6428 OBJECT_AREA:
6429 if gAreas <> nil then
6430 for a := 0 to High(gAreas) do
6431 if gAreas[a].AreaType <> AREA_NONE then
6432 SelectObject(OBJECT_AREA, a, True);
6433 OBJECT_TRIGGER:
6434 if gTriggers <> nil then
6435 for a := 0 to High(gTriggers) do
6436 if gTriggers[a].TriggerType <> TRIGGER_NONE then
6437 SelectObject(OBJECT_TRIGGER, a, True);
6438 end;
6440 RecountSelectedObjects();
6441 end;
6443 procedure TMainForm.tbGridOnClick(Sender: TObject);
6444 begin
6445 DotEnable := not DotEnable;
6446 (Sender as TToolButton).Down := DotEnable;
6447 end;
6449 procedure TMainForm.OnIdle(Sender: TObject; var Done: Boolean);
6450 begin
6451 // FIXME: this is a shitty hack
6452 if not gDataLoaded then
6453 begin
6454 e_WriteLog('Init OpenGL', MSG_NOTIFY);
6455 e_InitGL();
6456 e_WriteLog('Loading data', MSG_NOTIFY);
6457 LoadStdFont('STDTXT', 'STDFONT', gEditorFont);
6458 e_WriteLog('Loading more data', MSG_NOTIFY);
6459 LoadData();
6460 e_WriteLog('Loading even more data', MSG_NOTIFY);
6461 gDataLoaded := True;
6462 MainForm.FormResize(nil);
6463 end;
6464 Draw();
6465 end;
6467 procedure TMainForm.miMapPreviewClick(Sender: TObject);
6468 begin
6469 if PreviewMode = 2 then
6470 Exit;
6472 if PreviewMode = 0 then
6473 begin
6474 Splitter2.Visible := False;
6475 Splitter1.Visible := False;
6476 StatusBar.Visible := False;
6477 PanelObjs.Visible := False;
6478 PanelProps.Visible := False;
6479 MainToolBar.Visible := False;
6480 sbHorizontal.Visible := False;
6481 sbVertical.Visible := False;
6482 end
6483 else
6484 begin
6485 StatusBar.Visible := True;
6486 PanelObjs.Visible := True;
6487 PanelProps.Visible := True;
6488 Splitter2.Visible := True;
6489 Splitter1.Visible := True;
6490 MainToolBar.Visible := True;
6491 sbHorizontal.Visible := True;
6492 sbVertical.Visible := True;
6493 end;
6495 PreviewMode := PreviewMode xor 1;
6496 (Sender as TMenuItem).Checked := PreviewMode > 0;
6498 FormResize(Self);
6499 end;
6501 procedure TMainForm.miLayer1Click(Sender: TObject);
6502 begin
6503 SwitchLayer(LAYER_BACK);
6504 end;
6506 procedure TMainForm.miLayer2Click(Sender: TObject);
6507 begin
6508 SwitchLayer(LAYER_WALLS);
6509 end;
6511 procedure TMainForm.miLayer3Click(Sender: TObject);
6512 begin
6513 SwitchLayer(LAYER_FOREGROUND);
6514 end;
6516 procedure TMainForm.miLayer4Click(Sender: TObject);
6517 begin
6518 SwitchLayer(LAYER_STEPS);
6519 end;
6521 procedure TMainForm.miLayer5Click(Sender: TObject);
6522 begin
6523 SwitchLayer(LAYER_WATER);
6524 end;
6526 procedure TMainForm.miLayer6Click(Sender: TObject);
6527 begin
6528 SwitchLayer(LAYER_ITEMS);
6529 end;
6531 procedure TMainForm.miLayer7Click(Sender: TObject);
6532 begin
6533 SwitchLayer(LAYER_MONSTERS);
6534 end;
6536 procedure TMainForm.miLayer8Click(Sender: TObject);
6537 begin
6538 SwitchLayer(LAYER_AREAS);
6539 end;
6541 procedure TMainForm.miLayer9Click(Sender: TObject);
6542 begin
6543 SwitchLayer(LAYER_TRIGGERS);
6544 end;
6546 procedure TMainForm.tbShowClick(Sender: TObject);
6547 var
6548 a: Integer;
6549 b: Boolean;
6550 begin
6551 b := True;
6552 for a := 0 to High(LayerEnabled) do
6553 b := b and LayerEnabled[a];
6555 b := not b;
6557 ShowLayer(LAYER_BACK, b);
6558 ShowLayer(LAYER_WALLS, b);
6559 ShowLayer(LAYER_FOREGROUND, b);
6560 ShowLayer(LAYER_STEPS, b);
6561 ShowLayer(LAYER_WATER, b);
6562 ShowLayer(LAYER_ITEMS, b);
6563 ShowLayer(LAYER_MONSTERS, b);
6564 ShowLayer(LAYER_AREAS, b);
6565 ShowLayer(LAYER_TRIGGERS, b);
6566 end;
6568 procedure TMainForm.miMiniMapClick(Sender: TObject);
6569 begin
6570 SwitchMap();
6571 end;
6573 procedure TMainForm.miSwitchGridClick(Sender: TObject);
6574 begin
6575 if DotStep = DotStepOne then
6576 DotStep := DotStepTwo
6577 else
6578 DotStep := DotStepOne;
6580 MousePos.X := (MousePos.X div DotStep) * DotStep;
6581 MousePos.Y := (MousePos.Y div DotStep) * DotStep;
6582 end;
6584 procedure TMainForm.miShowEdgesClick(Sender: TObject);
6585 begin
6586 ShowEdges();
6587 end;
6589 procedure TMainForm.miSnapToGridClick(Sender: TObject);
6590 begin
6591 SnapToGrid := not SnapToGrid;
6593 MousePos.X := (MousePos.X div DotStep) * DotStep;
6594 MousePos.Y := (MousePos.Y div DotStep) * DotStep;
6596 miSnapToGrid.Checked := SnapToGrid;
6597 end;
6599 procedure TMainForm.minexttabClick(Sender: TObject);
6600 begin
6601 if pcObjects.ActivePageIndex < pcObjects.PageCount-1 then
6602 pcObjects.ActivePageIndex := pcObjects.ActivePageIndex+1
6603 else
6604 pcObjects.ActivePageIndex := 0;
6605 end;
6607 procedure TMainForm.miSaveMiniMapClick(Sender: TObject);
6608 begin
6609 SaveMiniMapForm.ShowModal();
6610 end;
6612 procedure TMainForm.bClearTextureClick(Sender: TObject);
6613 begin
6614 lbTextureList.ItemIndex := -1;
6615 lTextureWidth.Caption := '';
6616 lTextureHeight.Caption := '';
6617 end;
6619 procedure TMainForm.miPackMapClick(Sender: TObject);
6620 begin
6621 PackMapForm.ShowModal();
6622 end;
6624 procedure TMainForm.miMapTestSettingsClick(Sender: TObject);
6625 begin
6626 MapTestForm.ShowModal();
6627 end;
6629 procedure TMainForm.miTestMapClick(Sender: TObject);
6630 var
6631 cmd, mapWAD, mapToRun, tempWAD: String;
6632 opt: LongWord;
6633 time: Integer;
6634 proc: TProcessUTF8;
6635 res: Boolean;
6636 begin
6637 mapToRun := '';
6638 if OpenedMap <> '' then
6639 begin
6640 // Указываем текущую карту для теста:
6641 g_ProcessResourceStr(OpenedMap, @mapWAD, nil, @mapToRun);
6642 mapToRun := mapWAD + ':\' + mapToRun;
6643 mapToRun := ExtractRelativePath(ExtractFilePath(TestD2dExe) + 'maps/', mapToRun);
6644 end;
6645 // Сохраняем временную карту:
6646 time := 0;
6647 repeat
6648 mapWAD := ExtractFilePath(TestD2dExe) + Format('maps/temp%.4d.wad', [time]);
6649 Inc(time);
6650 until not FileExists(mapWAD);
6651 tempWAD := mapWAD + ':\' + TEST_MAP_NAME;
6652 SaveMap(tempWAD);
6654 tempWAD := ExtractRelativePath(ExtractFilePath(TestD2dExe) + 'maps/', tempWAD);
6655 // Если карта не была открыта, указываем временную в качестве текущей:
6656 if mapToRun = '' then
6657 mapToRun := tempWAD;
6659 // Опции игры:
6660 opt := 32 + 64;
6661 if TestOptionsTwoPlayers then
6662 opt := opt + 1;
6663 if TestOptionsTeamDamage then
6664 opt := opt + 2;
6665 if TestOptionsAllowExit then
6666 opt := opt + 4;
6667 if TestOptionsWeaponStay then
6668 opt := opt + 8;
6669 if TestOptionsMonstersDM then
6670 opt := opt + 16;
6672 // Составляем командную строку:
6673 cmd := '-map "' + mapToRun + '"';
6674 cmd := cmd + ' -testmap "' + tempWAD + '"';
6675 cmd := cmd + ' -gm ' + TestGameMode;
6676 cmd := cmd + ' -limt ' + TestLimTime;
6677 cmd := cmd + ' -lims ' + TestLimScore;
6678 cmd := cmd + ' -opt ' + IntToStr(opt);
6680 if TestMapOnce then
6681 cmd := cmd + ' --close';
6683 cmd := cmd + ' --debug';
6685 // Запускаем:
6686 proc := TProcessUTF8.Create(nil);
6687 proc.Executable := TestD2dExe;
6688 proc.Parameters.Add(cmd);
6689 res := True;
6690 try
6691 proc.Execute();
6692 except
6693 res := False;
6694 end;
6695 if res then
6696 begin
6697 Application.Minimize();
6698 proc.WaitOnExit();
6699 end;
6700 if (not res) or (proc.ExitCode < 0) then
6701 begin
6702 MessageBox(0, 'FIXME',
6703 PChar(_lc[I_MSG_EXEC_ERROR]),
6704 MB_OK or MB_ICONERROR);
6705 end;
6706 proc.Free();
6708 SysUtils.DeleteFile(mapWAD);
6709 Application.Restore();
6710 end;
6712 procedure TMainForm.sbVerticalScroll(Sender: TObject;
6713 ScrollCode: TScrollCode; var ScrollPos: Integer);
6714 begin
6715 MapOffset.Y := -Normalize16(sbVertical.Position);
6716 end;
6718 procedure TMainForm.sbHorizontalScroll(Sender: TObject;
6719 ScrollCode: TScrollCode; var ScrollPos: Integer);
6720 begin
6721 MapOffset.X := -Normalize16(sbHorizontal.Position);
6722 end;
6724 procedure TMainForm.miOpenWadMapClick(Sender: TObject);
6725 begin
6726 if OpenedWAD <> '' then
6727 begin
6728 OpenMap(OpenedWAD, '');
6729 end;
6730 end;
6732 procedure TMainForm.selectall1Click(Sender: TObject);
6733 var
6734 a: Integer;
6735 begin
6736 RemoveSelectFromObjects();
6738 if gPanels <> nil then
6739 for a := 0 to High(gPanels) do
6740 if gPanels[a].PanelType <> PANEL_NONE then
6741 SelectObject(OBJECT_PANEL, a, True);
6743 if gItems <> nil then
6744 for a := 0 to High(gItems) do
6745 if gItems[a].ItemType <> ITEM_NONE then
6746 SelectObject(OBJECT_ITEM, a, True);
6748 if gMonsters <> nil then
6749 for a := 0 to High(gMonsters) do
6750 if gMonsters[a].MonsterType <> MONSTER_NONE then
6751 SelectObject(OBJECT_MONSTER, a, True);
6753 if gAreas <> nil then
6754 for a := 0 to High(gAreas) do
6755 if gAreas[a].AreaType <> AREA_NONE then
6756 SelectObject(OBJECT_AREA, a, True);
6758 if gTriggers <> nil then
6759 for a := 0 to High(gTriggers) do
6760 if gTriggers[a].TriggerType <> TRIGGER_NONE then
6761 SelectObject(OBJECT_TRIGGER, a, True);
6763 RecountSelectedObjects();
6764 end;
6766 procedure TMainForm.Splitter1CanResize(Sender: TObject;
6767 var NewSize: Integer; var Accept: Boolean);
6768 begin
6769 Accept := (NewSize > 140);
6770 end;
6772 procedure TMainForm.Splitter2CanResize(Sender: TObject;
6773 var NewSize: Integer; var Accept: Boolean);
6774 begin
6775 Accept := (NewSize > 110);
6776 end;
6778 procedure TMainForm.vleObjectPropertyEnter(Sender: TObject);
6779 begin
6780 EditingProperties := True;
6781 end;
6783 procedure TMainForm.vleObjectPropertyExit(Sender: TObject);
6784 begin
6785 EditingProperties := False;
6786 end;
6788 procedure TMainForm.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
6789 begin
6790 // Объекты передвигались:
6791 if MainForm.ActiveControl = RenderPanel then
6792 begin
6793 if (Key = VK_NUMPAD4) or
6794 (Key = VK_NUMPAD6) or
6795 (Key = VK_NUMPAD8) or
6796 (Key = VK_NUMPAD5) or
6797 (Key = Ord('V')) then
6798 FillProperty();
6799 end;
6800 // Быстрое превью карты:
6801 if Key = Ord('E') then
6802 begin
6803 if PreviewMode = 2 then
6804 PreviewMode := 0;
6805 end;
6806 RenderPanelMouseMove(Sender, Shift, RenderMousePos().X, RenderMousePos().Y);
6807 end;
6809 end.