DEADSOFTWARE

Main: Allow drop files
[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 miSaveMiniMap: TMenuItem;
30 miDeleteMap: TMenuItem;
31 miPackMap: TMenuItem;
32 miLine2: TMenuItem;
33 miExit: TMenuItem;
34 // "Правка":
35 miMenuEdit: TMenuItem;
36 miUndo: TMenuItem;
37 miLine3: TMenuItem;
38 miCopy: TMenuItem;
39 miCut: TMenuItem;
40 miPaste: TMenuItem;
41 miLine4: TMenuItem;
42 miSelectAll: TMenuItem;
43 miLine5: TMenuItem;
44 miToFore: TMenuItem;
45 miToBack: TMenuItem;
46 // "Инструменты":
47 miMenuTools: TMenuItem;
48 miSnapToGrid: TMenuItem;
49 miMiniMap: TMenuItem;
50 miSwitchGrid: TMenuItem;
51 miShowEdges: TMenuItem;
52 miLayers: TMenuItem;
53 miLayer1: TMenuItem;
54 miLayer2: TMenuItem;
55 miLayer3: TMenuItem;
56 miLayer4: TMenuItem;
57 miLayer5: TMenuItem;
58 miLayer6: TMenuItem;
59 miLayer7: TMenuItem;
60 miLayer8: TMenuItem;
61 miLayer9: TMenuItem;
62 // "Сервис":
63 miMenuService: TMenuItem;
64 miCheckMap: TMenuItem;
65 miOptimmization: TMenuItem;
66 miMapPreview: TMenuItem;
67 miTestMap: TMenuItem;
68 // "Настройка":
69 miMenuSettings: TMenuItem;
70 miMapOptions: TMenuItem;
71 miLine6: TMenuItem;
72 miOptions: TMenuItem;
73 miLine7: TMenuItem;
74 miMapTestSettings: TMenuItem;
75 // "Справка":
76 miMenuHelp: TMenuItem;
77 miAbout: TMenuItem;
78 // Скрытый пункт меню для Ctrl+Tab:
79 miHidden1: TMenuItem;
80 minexttab: TMenuItem;
82 // Панель инструментов:
83 MainToolBar: TToolBar;
84 pbLoad: TProgressBar;
85 pLoadProgress: TPanel;
86 RenderPanel: TOpenGLControl;
87 tbNewMap: TToolButton;
88 tbOpenMap: TToolButton;
89 tbSaveMap: TToolButton;
90 tbOpenWadMap: TToolButton;
91 tbLine1: TToolButton;
92 tbShowMap: TToolButton;
93 tbLine2: TToolButton;
94 tbShow: TToolButton;
95 tbLine3: TToolButton;
96 tbGridOn: TToolButton;
97 tbGrid: TToolButton;
98 tbLine4: TToolButton;
99 tbTestMap: TToolButton;
100 // Всплывающее меню для кнопки слоев:
101 pmShow: TPopupMenu;
102 miLayerP1: TMenuItem;
103 miLayerP2: TMenuItem;
104 miLayerP3: TMenuItem;
105 miLayerP4: TMenuItem;
106 miLayerP5: TMenuItem;
107 miLayerP6: TMenuItem;
108 miLayerP7: TMenuItem;
109 miLayerP8: TMenuItem;
110 miLayerP9: TMenuItem;
111 // Всплывающее меню для кнопки теста карты:
112 pmMapTest: TPopupMenu;
113 miMapTestPMSet: TMenuItem;
115 // Панель карты:
116 PanelMap: TPanel;
117 // Полосы прокрутки:
118 sbHorizontal: TScrollBar;
119 sbVertical: TScrollBar;
121 // Панель свойств:
122 PanelProps: TPanel;
123 // Панель применения свойств:
124 PanelPropApply: TPanel;
125 bApplyProperty: TButton;
126 // Редактор свойств объектов:
127 vleObjectProperty: TValueListEditor;
129 // Панель объектов - вкладки:
130 PanelObjs: TPanel;
131 pcObjects: TPageControl;
132 // Вкладка "Панели":
133 tsPanels: TTabSheet;
134 lbTextureList: TListBox;
135 // Панель настройки текстур:
136 PanelTextures: TPanel;
137 LabelTxW: TLabel;
138 lTextureWidth: TLabel;
139 LabelTxH: TLabel;
140 lTextureHeight: TLabel;
141 cbPreview: TCheckBox;
142 bbAddTexture: TBitBtn;
143 bbRemoveTexture: TBitBtn;
144 bClearTexture: TButton;
145 // Панель типов панелей:
146 PanelPanelType: TPanel;
147 lbPanelType: TListBox;
148 // Вкладка "Предметы":
149 tsItems: TTabSheet;
150 lbItemList: TListBox;
151 cbOnlyDM: TCheckBox;
152 cbFall: TCheckBox;
153 // Вкладка "Монстры":
154 tsMonsters: TTabSheet;
155 lbMonsterList: TListBox;
156 rbMonsterLeft: TRadioButton;
157 rbMonsterRight: TRadioButton;
158 // Вкладка "Области":
159 tsAreas: TTabSheet;
160 lbAreasList: TListBox;
161 rbAreaLeft: TRadioButton;
162 rbAreaRight: TRadioButton;
163 // Вкладка "Триггеры":
164 tsTriggers: TTabSheet;
165 lbTriggersList: TListBox;
166 clbActivationType: TCheckListBox;
167 clbKeys: TCheckListBox;
169 // Остальные панели
170 Splitter1: TSplitter;
171 Splitter2: TSplitter;
172 StatusBar: TStatusBar;
174 // Специальные объекты:
175 ImageList: TImageList;
176 ilToolbar: TImageList;
177 OpenDialog: TOpenDialog;
178 SaveDialog: TSaveDialog;
179 selectall1: TMenuItem;
180 ColorDialog: TColorDialog;
182 procedure aAboutExecute(Sender: TObject);
183 procedure aCheckMapExecute(Sender: TObject);
184 procedure aMoveToFore(Sender: TObject);
185 procedure aMoveToBack(Sender: TObject);
186 procedure aCopyObjectExecute(Sender: TObject);
187 procedure aCutObjectExecute(Sender: TObject);
188 procedure aEditorOptionsExecute(Sender: TObject);
189 procedure aExitExecute(Sender: TObject);
190 procedure aMapOptionsExecute(Sender: TObject);
191 procedure aNewMapExecute(Sender: TObject);
192 procedure aOpenMapExecute(Sender: TObject);
193 procedure aOptimizeExecute(Sender: TObject);
194 procedure aPasteObjectExecute(Sender: TObject);
195 procedure aSelectAllExecute(Sender: TObject);
196 procedure aSaveMapExecute(Sender: TObject);
197 procedure aSaveMapAsExecute(Sender: TObject);
198 procedure aUndoExecute(Sender: TObject);
199 procedure aDeleteMap(Sender: TObject);
200 procedure bApplyPropertyClick(Sender: TObject);
201 procedure bbAddTextureClick(Sender: TObject);
202 procedure bbRemoveTextureClick(Sender: TObject);
203 procedure FormActivate(Sender: TObject);
204 procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
205 procedure FormCreate(Sender: TObject);
206 procedure FormDestroy(Sender: TObject);
207 procedure FormDropFiles(Sender: TObject; const FileNames: array of String);
208 procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
209 procedure FormResize(Sender: TObject);
210 procedure lbTextureListClick(Sender: TObject);
211 procedure lbTextureListDrawItem(Control: TWinControl; Index: Integer;
212 ARect: TRect; State: TOwnerDrawState);
213 procedure RenderPanelMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
214 procedure RenderPanelMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
215 procedure RenderPanelMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
216 procedure RenderPanelPaint(Sender: TObject);
217 procedure RenderPanelResize(Sender: TObject);
218 procedure Splitter1Moved(Sender: TObject);
219 procedure vleObjectPropertyEditButtonClick(Sender: TObject);
220 procedure vleObjectPropertyApply(Sender: TObject);
221 procedure vleObjectPropertyGetPickList(Sender: TObject; const KeyName: String; Values: TStrings);
222 procedure vleObjectPropertyKeyDown(Sender: TObject; var Key: Word;
223 Shift: TShiftState);
224 procedure tbGridOnClick(Sender: TObject);
225 procedure miMapPreviewClick(Sender: TObject);
226 procedure miLayer1Click(Sender: TObject);
227 procedure miLayer2Click(Sender: TObject);
228 procedure miLayer3Click(Sender: TObject);
229 procedure miLayer4Click(Sender: TObject);
230 procedure miLayer5Click(Sender: TObject);
231 procedure miLayer6Click(Sender: TObject);
232 procedure miLayer7Click(Sender: TObject);
233 procedure miLayer8Click(Sender: TObject);
234 procedure miLayer9Click(Sender: TObject);
235 procedure tbShowClick(Sender: TObject);
236 procedure miSnapToGridClick(Sender: TObject);
237 procedure miMiniMapClick(Sender: TObject);
238 procedure miSwitchGridClick(Sender: TObject);
239 procedure miShowEdgesClick(Sender: TObject);
240 procedure minexttabClick(Sender: TObject);
241 procedure miSaveMiniMapClick(Sender: TObject);
242 procedure bClearTextureClick(Sender: TObject);
243 procedure miPackMapClick(Sender: TObject);
244 procedure aRecentFileExecute(Sender: TObject);
245 procedure miMapTestSettingsClick(Sender: TObject);
246 procedure miTestMapClick(Sender: TObject);
247 procedure sbVerticalScroll(Sender: TObject; ScrollCode: TScrollCode;
248 var ScrollPos: Integer);
249 procedure sbHorizontalScroll(Sender: TObject; ScrollCode: TScrollCode;
250 var ScrollPos: Integer);
251 procedure miOpenWadMapClick(Sender: TObject);
252 procedure selectall1Click(Sender: TObject);
253 procedure Splitter1CanResize(Sender: TObject; var NewSize: Integer;
254 var Accept: Boolean);
255 procedure Splitter2CanResize(Sender: TObject; var NewSize: Integer;
256 var Accept: Boolean);
257 procedure vleObjectPropertyEnter(Sender: TObject);
258 procedure vleObjectPropertyExit(Sender: TObject);
259 procedure FormKeyUp(Sender: TObject; var Key: Word;
260 Shift: TShiftState);
261 private
262 procedure Draw();
263 procedure OnIdle(Sender: TObject; var Done: Boolean);
264 public
265 procedure RefreshRecentMenu();
266 procedure OpenMapFile(FileName: String);
267 end;
269 const
270 LAYER_BACK = 0;
271 LAYER_WALLS = 1;
272 LAYER_FOREGROUND = 2;
273 LAYER_STEPS = 3;
274 LAYER_WATER = 4;
275 LAYER_ITEMS = 5;
276 LAYER_MONSTERS = 6;
277 LAYER_AREAS = 7;
278 LAYER_TRIGGERS = 8;
280 TEST_MAP_NAME = '$$$_TEST_$$$';
281 LANGUAGE_FILE_NAME = '_Editor.txt';
283 var
284 MainForm: TMainForm;
285 EditorDir: String;
286 OpenedMap: String;
287 OpenedWAD: String;
289 DotColor: TColor;
290 DotEnable: Boolean;
291 DotStep: Byte;
292 DotStepOne, DotStepTwo: Byte;
293 DotSize: Byte;
294 DrawTexturePanel: Boolean;
295 DrawPanelSize: Boolean;
296 BackColor: TColor;
297 PreviewColor: TColor;
298 Scale: Byte;
299 RecentCount: Integer;
300 RecentFiles: TStringList;
301 slInvalidTextures: TStringList;
303 TestGameMode: String;
304 TestLimTime: String;
305 TestLimScore: String;
306 TestOptionsTwoPlayers: Boolean;
307 TestOptionsTeamDamage: Boolean;
308 TestOptionsAllowExit: Boolean;
309 TestOptionsWeaponStay: Boolean;
310 TestOptionsMonstersDM: Boolean;
311 TestD2dExe: String;
312 TestMapOnce: Boolean;
314 LayerEnabled: Array [LAYER_BACK..LAYER_TRIGGERS] of Boolean =
315 (True, True, True, True, True, True, True, True, True);
316 PreviewMode: Byte = 0;
317 gLanguage: String;
319 FormCaption: String;
322 procedure OpenMap(FileName: String; mapN: String);
323 function AddTexture(aWAD, aSection, aTex: String; silent: Boolean): Boolean;
324 procedure RemoveSelectFromObjects();
325 procedure ChangeShownProperty(Name: String; NewValue: String);
327 implementation
329 uses
330 f_options, e_graphics, e_log, GL, Math,
331 f_mapoptions, g_basic, f_about, f_mapoptimization,
332 f_mapcheck, f_addresource_texture, g_textures,
333 f_activationtype, f_keys,
334 MAPREADER, f_selectmap, f_savemap, WADEDITOR, WADSTRUCT, MAPDEF,
335 g_map, f_saveminimap, f_addresource, CONFIG, f_packmap,
336 f_addresource_sound, f_maptest, f_choosetype,
337 g_language, f_selectlang, ClipBrd;
339 const
340 UNDO_DELETE_PANEL = 1;
341 UNDO_DELETE_ITEM = 2;
342 UNDO_DELETE_AREA = 3;
343 UNDO_DELETE_MONSTER = 4;
344 UNDO_DELETE_TRIGGER = 5;
345 UNDO_ADD_PANEL = 6;
346 UNDO_ADD_ITEM = 7;
347 UNDO_ADD_AREA = 8;
348 UNDO_ADD_MONSTER = 9;
349 UNDO_ADD_TRIGGER = 10;
350 UNDO_MOVE_PANEL = 11;
351 UNDO_MOVE_ITEM = 12;
352 UNDO_MOVE_AREA = 13;
353 UNDO_MOVE_MONSTER = 14;
354 UNDO_MOVE_TRIGGER = 15;
355 UNDO_RESIZE_PANEL = 16;
356 UNDO_RESIZE_TRIGGER = 17;
358 MOUSEACTION_NONE = 0;
359 MOUSEACTION_DRAWPANEL = 1;
360 MOUSEACTION_DRAWTRIGGER = 2;
361 MOUSEACTION_MOVEOBJ = 3;
362 MOUSEACTION_RESIZE = 4;
363 MOUSEACTION_MOVEMAP = 5;
364 MOUSEACTION_DRAWPRESS = 6;
365 MOUSEACTION_NOACTION = 7;
367 RESIZETYPE_NONE = 0;
368 RESIZETYPE_VERTICAL = 1;
369 RESIZETYPE_HORIZONTAL = 2;
371 RESIZEDIR_NONE = 0;
372 RESIZEDIR_DOWN = 1;
373 RESIZEDIR_UP = 2;
374 RESIZEDIR_RIGHT = 3;
375 RESIZEDIR_LEFT = 4;
377 SELECTFLAG_NONE = 0;
378 SELECTFLAG_TELEPORT = 1;
379 SELECTFLAG_DOOR = 2;
380 SELECTFLAG_TEXTURE = 3;
381 SELECTFLAG_LIFT = 4;
382 SELECTFLAG_MONSTER = 5;
383 SELECTFLAG_SPAWNPOINT = 6;
384 SELECTFLAG_SHOTPANEL = 7;
385 SELECTFLAG_SELECTED = 8;
387 RECENT_FILES_MENU_START = 11;
389 CLIPBOARD_SIG = 'DF:ED';
391 type
392 TUndoRec = record
393 UndoType: Byte;
394 case Byte of
395 UNDO_DELETE_PANEL: (Panel: ^TPanel);
396 UNDO_DELETE_ITEM: (Item: TItem);
397 UNDO_DELETE_AREA: (Area: TArea);
398 UNDO_DELETE_MONSTER: (Monster: TMonster);
399 UNDO_DELETE_TRIGGER: (Trigger: TTrigger);
400 UNDO_ADD_PANEL,
401 UNDO_ADD_ITEM,
402 UNDO_ADD_AREA,
403 UNDO_ADD_MONSTER,
404 UNDO_ADD_TRIGGER: (AddID: DWORD);
405 UNDO_MOVE_PANEL,
406 UNDO_MOVE_ITEM,
407 UNDO_MOVE_AREA,
408 UNDO_MOVE_MONSTER,
409 UNDO_MOVE_TRIGGER: (MoveID: DWORD; dX, dY: Integer);
410 UNDO_RESIZE_PANEL,
411 UNDO_RESIZE_TRIGGER: (ResizeID: DWORD; dW, dH: Integer);
412 end;
414 TCopyRec = record
415 ObjectType: Byte;
416 ID: Cardinal;
417 case Byte of
418 OBJECT_PANEL: (Panel: ^TPanel);
419 OBJECT_ITEM: (Item: TItem);
420 OBJECT_AREA: (Area: TArea);
421 OBJECT_MONSTER: (Monster: TMonster);
422 OBJECT_TRIGGER: (Trigger: TTrigger);
423 end;
425 TCopyRecArray = Array of TCopyRec;
427 var
428 gEditorFont: DWORD;
429 gDataLoaded: Boolean = False;
430 ShowMap: Boolean = False;
431 DrawRect: PRect = nil;
432 SnapToGrid: Boolean = True;
434 MousePos: Types.TPoint;
435 LastMovePoint: Types.TPoint;
436 MouseLDown: Boolean;
437 MouseRDown: Boolean;
438 MouseLDownPos: Types.TPoint;
439 MouseRDownPos: Types.TPoint;
440 WASDOffset: TPoint;
442 SelectFlag: Byte = SELECTFLAG_NONE;
443 MouseAction: Byte = MOUSEACTION_NONE;
444 ResizeType: Byte = RESIZETYPE_NONE;
445 ResizeDirection: Byte = RESIZEDIR_NONE;
447 DrawPressRect: Boolean = False;
448 EditingProperties: Boolean = False;
450 UndoBuffer: Array of Array of TUndoRec = nil;
453 {$R *.lfm}
455 //----------------------------------------
456 //Далее идут вспомогательные процедуры
457 //----------------------------------------
459 function NameToBool(Name: String): Boolean;
460 begin
461 if Name = BoolNames[True] then
462 Result := True
463 else
464 Result := False;
465 end;
467 function NameToDir(Name: String): TDirection;
468 begin
469 if Name = DirNames[D_LEFT] then
470 Result := D_LEFT
471 else
472 Result := D_RIGHT;
473 end;
475 function NameToDirAdv(Name: String): Byte;
476 begin
477 if Name = DirNamesAdv[1] then
478 Result := 1
479 else
480 if Name = DirNamesAdv[2] then
481 Result := 2
482 else
483 if Name = DirNamesAdv[3] then
484 Result := 3
485 else
486 Result := 0;
487 end;
489 function ActivateToStr(ActivateType: Byte): String;
490 begin
491 Result := '';
493 if ByteBool(ACTIVATE_PLAYERCOLLIDE and ActivateType) then
494 Result := Result + '+PC';
495 if ByteBool(ACTIVATE_MONSTERCOLLIDE and ActivateType) then
496 Result := Result + '+MC';
497 if ByteBool(ACTIVATE_PLAYERPRESS and ActivateType) then
498 Result := Result + '+PP';
499 if ByteBool(ACTIVATE_MONSTERPRESS and ActivateType) then
500 Result := Result + '+MP';
501 if ByteBool(ACTIVATE_SHOT and ActivateType) then
502 Result := Result + '+SH';
503 if ByteBool(ACTIVATE_NOMONSTER and ActivateType) then
504 Result := Result + '+NM';
506 if (Result <> '') and (Result[1] = '+') then
507 Delete(Result, 1, 1);
508 end;
510 function StrToActivate(Str: String): Byte;
511 begin
512 Result := 0;
514 if Pos('PC', Str) > 0 then
515 Result := ACTIVATE_PLAYERCOLLIDE;
516 if Pos('MC', Str) > 0 then
517 Result := Result or ACTIVATE_MONSTERCOLLIDE;
518 if Pos('PP', Str) > 0 then
519 Result := Result or ACTIVATE_PLAYERPRESS;
520 if Pos('MP', Str) > 0 then
521 Result := Result or ACTIVATE_MONSTERPRESS;
522 if Pos('SH', Str) > 0 then
523 Result := Result or ACTIVATE_SHOT;
524 if Pos('NM', Str) > 0 then
525 Result := Result or ACTIVATE_NOMONSTER;
526 end;
528 function KeyToStr(Key: Byte): String;
529 begin
530 Result := '';
532 if ByteBool(KEY_RED and Key) then
533 Result := Result + '+RK';
534 if ByteBool(KEY_GREEN and Key) then
535 Result := Result + '+GK';
536 if ByteBool(KEY_BLUE and Key) then
537 Result := Result + '+BK';
538 if ByteBool(KEY_REDTEAM and Key) then
539 Result := Result + '+RT';
540 if ByteBool(KEY_BLUETEAM and Key) then
541 Result := Result + '+BT';
543 if (Result <> '') and (Result[1] = '+') then
544 Delete(Result, 1, 1);
545 end;
547 function StrToKey(Str: String): Byte;
548 begin
549 Result := 0;
551 if Pos('RK', Str) > 0 then
552 Result := KEY_RED;
553 if Pos('GK', Str) > 0 then
554 Result := Result or KEY_GREEN;
555 if Pos('BK', Str) > 0 then
556 Result := Result or KEY_BLUE;
557 if Pos('RT', Str) > 0 then
558 Result := Result or KEY_REDTEAM;
559 if Pos('BT', Str) > 0 then
560 Result := Result or KEY_BLUETEAM;
561 end;
563 function EffectToStr(Effect: Byte): String;
564 begin
565 if Effect in [EFFECT_TELEPORT..EFFECT_FIRE] then
566 Result := EffectNames[Effect]
567 else
568 Result := EffectNames[EFFECT_NONE];
569 end;
571 function StrToEffect(Str: String): Byte;
572 var
573 i: Integer;
574 begin
575 Result := EFFECT_NONE;
576 for i := EFFECT_TELEPORT to EFFECT_FIRE do
577 if EffectNames[i] = Str then
578 begin
579 Result := i;
580 Exit;
581 end;
582 end;
584 function MonsterToStr(MonType: Byte): String;
585 begin
586 if MonType in [MONSTER_DEMON..MONSTER_MAN] then
587 Result := MonsterNames[MonType]
588 else
589 Result := MonsterNames[MONSTER_ZOMBY];
590 end;
592 function StrToMonster(Str: String): Byte;
593 var
594 i: Integer;
595 begin
596 Result := MONSTER_ZOMBY;
597 for i := MONSTER_DEMON to MONSTER_MAN do
598 if MonsterNames[i] = Str then
599 begin
600 Result := i;
601 Exit;
602 end;
603 end;
605 function ItemToStr(ItemType: Byte): String;
606 begin
607 if ItemType in [ITEM_MEDKIT_SMALL..ITEM_MAX] then
608 Result := ItemNames[ItemType]
609 else
610 Result := ItemNames[ITEM_AMMO_BULLETS];
611 end;
613 function StrToItem(Str: String): Byte;
614 var
615 i: Integer;
616 begin
617 Result := ITEM_AMMO_BULLETS;
618 for i := ITEM_MEDKIT_SMALL to ITEM_MAX do
619 if ItemNames[i] = Str then
620 begin
621 Result := i;
622 Exit;
623 end;
624 end;
626 function ShotToStr(ShotType: Byte): String;
627 begin
628 if ShotType in [TRIGGER_SHOT_PISTOL..TRIGGER_SHOT_MAX] then
629 Result := ShotNames[ShotType]
630 else
631 Result := ShotNames[TRIGGER_SHOT_PISTOL];
632 end;
634 function StrToShot(Str: String): Byte;
635 var
636 i: Integer;
637 begin
638 Result := TRIGGER_SHOT_PISTOL;
639 for i := TRIGGER_SHOT_PISTOL to TRIGGER_SHOT_MAX do
640 if ShotNames[i] = Str then
641 begin
642 Result := i;
643 Exit;
644 end;
645 end;
647 function SelectedObjectCount(): Word;
648 var
649 a: Integer;
650 begin
651 Result := 0;
653 if SelectedObjects = nil then
654 Exit;
656 for a := 0 to High(SelectedObjects) do
657 if SelectedObjects[a].Live then
658 Result := Result + 1;
659 end;
661 function GetFirstSelected(): Integer;
662 var
663 a: Integer;
664 begin
665 Result := -1;
667 if SelectedObjects = nil then
668 Exit;
670 for a := 0 to High(SelectedObjects) do
671 if SelectedObjects[a].Live then
672 begin
673 Result := a;
674 Exit;
675 end;
676 end;
678 function Normalize16(x: Integer): Integer;
679 begin
680 Result := (x div 16) * 16;
681 end;
683 procedure MoveMap(X, Y: Integer);
684 var
685 rx, ry, ScaleSz: Integer;
686 begin
687 with MainForm.RenderPanel do
688 begin
689 ScaleSz := 16 div Scale;
690 // Размер видимой части карты:
691 rx := min(Normalize16(Width), Normalize16(gMapInfo.Width)) div 2;
692 ry := min(Normalize16(Height), Normalize16(gMapInfo.Height)) div 2;
693 // Место клика на мини-карте:
694 MapOffset.X := X - (Width-max(gMapInfo.Width div ScaleSz, 1)-1);
695 MapOffset.Y := Y - 1;
696 // Это же место на "большой" карте:
697 MapOffset.X := MapOffset.X * ScaleSz;
698 MapOffset.Y := MapOffset.Y * ScaleSz;
699 // Левый верхний угол новой видимой части карты:
700 MapOffset.X := MapOffset.X - rx;
701 MapOffset.Y := MapOffset.Y - ry;
702 // Выход за границы:
703 if MapOffset.X < 0 then
704 MapOffset.X := 0;
705 if MapOffset.Y < 0 then
706 MapOffset.Y := 0;
707 if MapOffset.X > MainForm.sbHorizontal.Max then
708 MapOffset.X := MainForm.sbHorizontal.Max;
709 if MapOffset.Y > MainForm.sbVertical.Max then
710 MapOffset.Y := MainForm.sbVertical.Max;
711 // Кратно 16:
712 MapOffset.X := Normalize16(MapOffset.X);
713 MapOffset.Y := Normalize16(MapOffset.Y);
714 end;
716 MainForm.sbHorizontal.Position := MapOffset.X;
717 MainForm.sbVertical.Position := MapOffset.Y;
719 MapOffset.X := -MapOffset.X;
720 MapOffset.Y := -MapOffset.Y;
722 MainForm.Resize();
723 end;
725 function IsTexturedPanel(PanelType: Word): Boolean;
726 begin
727 Result := WordBool(PanelType and (PANEL_WALL or PANEL_BACK or PANEL_FORE or
728 PANEL_STEP or PANEL_OPENDOOR or PANEL_CLOSEDOOR or
729 PANEL_WATER or PANEL_ACID1 or PANEL_ACID2));
730 end;
732 procedure FillProperty();
733 var
734 _id: DWORD;
735 str: String;
736 begin
737 MainForm.vleObjectProperty.Strings.Clear();
739 // Отображаем свойства если выделен только один объект:
740 if SelectedObjectCount() <> 1 then
741 Exit;
743 _id := GetFirstSelected();
744 if not SelectedObjects[_id].Live then
745 Exit;
747 with MainForm.vleObjectProperty do
748 with ItemProps[InsertRow(_lc[I_PROP_ID], IntToStr(SelectedObjects[_id].ID), True)] do
749 begin
750 EditStyle := esSimple;
751 ReadOnly := True;
752 end;
754 case SelectedObjects[0].ObjectType of
755 OBJECT_PANEL:
756 begin
757 with MainForm.vleObjectProperty,
758 gPanels[SelectedObjects[_id].ID] do
759 begin
760 with ItemProps[InsertRow(_lc[I_PROP_X], IntToStr(X), True)] do
761 begin
762 EditStyle := esSimple;
763 MaxLength := 5;
764 end;
766 with ItemProps[InsertRow(_lc[I_PROP_Y], IntToStr(Y), True)] do
767 begin
768 EditStyle := esSimple;
769 MaxLength := 5;
770 end;
772 with ItemProps[InsertRow(_lc[I_PROP_WIDTH], IntToStr(Width), True)] do
773 begin
774 EditStyle := esSimple;
775 MaxLength := 5;
776 end;
778 with ItemProps[InsertRow(_lc[I_PROP_HEIGHT], IntToStr(Height), True)] do
779 begin
780 EditStyle := esSimple;
781 MaxLength := 5;
782 end;
784 with ItemProps[InsertRow(_lc[I_PROP_PANEL_TYPE], GetPanelName(PanelType), True)] do
785 begin
786 EditStyle := esEllipsis;
787 ReadOnly := True;
788 end;
790 if IsTexturedPanel(PanelType) then
791 begin // Может быть текстура
792 with ItemProps[InsertRow(_lc[I_PROP_PANEL_TEX], TextureName, True)] do
793 begin
794 EditStyle := esEllipsis;
795 ReadOnly := True;
796 end;
798 if TextureName <> '' then
799 begin // Есть текстура
800 with ItemProps[InsertRow(_lc[I_PROP_PANEL_ALPHA], IntToStr(Alpha), True)] do
801 begin
802 EditStyle := esSimple;
803 MaxLength := 3;
804 end;
806 with ItemProps[InsertRow(_lc[I_PROP_PANEL_BLEND], BoolNames[Blending], True)] do
807 begin
808 EditStyle := esPickList;
809 ReadOnly := True;
810 end;
811 end;
812 end;
813 end;
814 end;
816 OBJECT_ITEM:
817 begin
818 with MainForm.vleObjectProperty,
819 gItems[SelectedObjects[_id].ID] do
820 begin
821 with ItemProps[InsertRow(_lc[I_PROP_X], IntToStr(X), True)] do
822 begin
823 EditStyle := esSimple;
824 MaxLength := 5;
825 end;
827 with ItemProps[InsertRow(_lc[I_PROP_Y], IntToStr(Y), True)] do
828 begin
829 EditStyle := esSimple;
830 MaxLength := 5;
831 end;
833 with ItemProps[InsertRow(_lc[I_PROP_DM_ONLY], BoolNames[OnlyDM], True)] do
834 begin
835 EditStyle := esPickList;
836 ReadOnly := True;
837 end;
839 with ItemProps[InsertRow(_lc[I_PROP_ITEM_FALLS], BoolNames[Fall], True)] do
840 begin
841 EditStyle := esPickList;
842 ReadOnly := True;
843 end;
844 end;
845 end;
847 OBJECT_MONSTER:
848 begin
849 with MainForm.vleObjectProperty,
850 gMonsters[SelectedObjects[_id].ID] do
851 begin
852 with ItemProps[InsertRow(_lc[I_PROP_X], IntToStr(X), True)] do
853 begin
854 EditStyle := esSimple;
855 MaxLength := 5;
856 end;
858 with ItemProps[InsertRow(_lc[I_PROP_Y], IntToStr(Y), True)] do
859 begin
860 EditStyle := esSimple;
861 MaxLength := 5;
862 end;
864 with ItemProps[InsertRow(_lc[I_PROP_DIRECTION], DirNames[Direction], True)] do
865 begin
866 EditStyle := esPickList;
867 ReadOnly := True;
868 end;
869 end;
870 end;
872 OBJECT_AREA:
873 begin
874 with MainForm.vleObjectProperty,
875 gAreas[SelectedObjects[_id].ID] do
876 begin
877 with ItemProps[InsertRow(_lc[I_PROP_X], IntToStr(X), True)] do
878 begin
879 EditStyle := esSimple;
880 MaxLength := 5;
881 end;
883 with ItemProps[InsertRow(_lc[I_PROP_Y], IntToStr(Y), True)] do
884 begin
885 EditStyle := esSimple;
886 MaxLength := 5;
887 end;
889 with ItemProps[InsertRow(_lc[I_PROP_DIRECTION], DirNames[Direction], True)] do
890 begin
891 EditStyle := esPickList;
892 ReadOnly := True;
893 end;
894 end;
895 end;
897 OBJECT_TRIGGER:
898 begin
899 with MainForm.vleObjectProperty,
900 gTriggers[SelectedObjects[_id].ID] do
901 begin
902 with ItemProps[InsertRow(_lc[I_PROP_TR_TYPE], GetTriggerName(TriggerType), True)] do
903 begin
904 EditStyle := esSimple;
905 ReadOnly := True;
906 end;
908 with ItemProps[InsertRow(_lc[I_PROP_X], IntToStr(X), True)] do
909 begin
910 EditStyle := esSimple;
911 MaxLength := 5;
912 end;
914 with ItemProps[InsertRow(_lc[I_PROP_Y], IntToStr(Y), True)] do
915 begin
916 EditStyle := esSimple;
917 MaxLength := 5;
918 end;
920 with ItemProps[InsertRow(_lc[I_PROP_WIDTH], IntToStr(Width), True)] do
921 begin
922 EditStyle := esSimple;
923 MaxLength := 5;
924 end;
926 with ItemProps[InsertRow(_lc[I_PROP_HEIGHT], IntToStr(Height), True)] do
927 begin
928 EditStyle := esSimple;
929 MaxLength := 5;
930 end;
932 with ItemProps[InsertRow(_lc[I_PROP_TR_ENABLED], BoolNames[Enabled], True)] do
933 begin
934 EditStyle := esPickList;
935 ReadOnly := True;
936 end;
938 with ItemProps[InsertRow(_lc[I_PROP_TR_TEXTURE_PANEL], IntToStr(TexturePanel), True)] do
939 begin
940 EditStyle := esEllipsis;
941 ReadOnly := True;
942 end;
944 with ItemProps[InsertRow(_lc[I_PROP_TR_ACTIVATION], ActivateToStr(ActivateType), True)] do
945 begin
946 EditStyle := esEllipsis;
947 ReadOnly := True;
948 end;
950 with ItemProps[InsertRow(_lc[I_PROP_TR_KEYS], KeyToStr(Key), True)] do
951 begin
952 EditStyle := esEllipsis;
953 ReadOnly := True;
954 end;
956 case TriggerType of
957 TRIGGER_EXIT:
958 begin
959 str := win2utf(Data.MapName);
960 with ItemProps[InsertRow(_lc[I_PROP_TR_NEXT_MAP], str, True)] do
961 begin
962 EditStyle := esEllipsis;
963 ReadOnly := True;
964 end;
965 end;
967 TRIGGER_TELEPORT:
968 begin
969 with ItemProps[InsertRow(_lc[I_PROP_TR_TELEPORT_TO], Format('(%d:%d)', [Data.TargetPoint.X, Data.TargetPoint.Y]), True)] do
970 begin
971 EditStyle := esEllipsis;
972 ReadOnly := True;
973 end;
975 with ItemProps[InsertRow(_lc[I_PROP_TR_D2D], BoolNames[Data.d2d_teleport], True)] do
976 begin
977 EditStyle := esPickList;
978 ReadOnly := True;
979 end;
981 with ItemProps[InsertRow(_lc[I_PROP_TR_TELEPORT_SILENT], BoolNames[Data.silent_teleport], True)] do
982 begin
983 EditStyle := esPickList;
984 ReadOnly := True;
985 end;
987 with ItemProps[InsertRow(_lc[I_PROP_TR_TELEPORT_DIR], DirNamesAdv[Data.TlpDir], True)] do
988 begin
989 EditStyle := esPickList;
990 ReadOnly := True;
991 end;
992 end;
994 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR,
995 TRIGGER_DOOR, TRIGGER_DOOR5:
996 begin
997 with ItemProps[InsertRow(_lc[I_PROP_TR_DOOR_PANEL], IntToStr(Data.PanelID), True)] do
998 begin
999 EditStyle := esEllipsis;
1000 ReadOnly := True;
1001 end;
1003 with ItemProps[InsertRow(_lc[I_PROP_TR_SILENT], BoolNames[Data.NoSound], True)] do
1004 begin
1005 EditStyle := esPickList;
1006 ReadOnly := True;
1007 end;
1009 with ItemProps[InsertRow(_lc[I_PROP_TR_D2D], BoolNames[Data.d2d_doors], True)] do
1010 begin
1011 EditStyle := esPickList;
1012 ReadOnly := True;
1013 end;
1014 end;
1016 TRIGGER_CLOSETRAP, TRIGGER_TRAP:
1017 begin
1018 with ItemProps[InsertRow(_lc[I_PROP_TR_TRAP_PANEL], IntToStr(Data.PanelID), True)] do
1019 begin
1020 EditStyle := esEllipsis;
1021 ReadOnly := True;
1022 end;
1024 with ItemProps[InsertRow(_lc[I_PROP_TR_SILENT], BoolNames[Data.NoSound], True)] do
1025 begin
1026 EditStyle := esPickList;
1027 ReadOnly := True;
1028 end;
1030 with ItemProps[InsertRow(_lc[I_PROP_TR_D2D], BoolNames[Data.d2d_doors], True)] do
1031 begin
1032 EditStyle := esPickList;
1033 ReadOnly := True;
1034 end;
1035 end;
1037 TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF,
1038 TRIGGER_ONOFF:
1039 begin
1040 with ItemProps[InsertRow(_lc[I_PROP_TR_EX_AREA],
1041 Format('(%d:%d %d:%d)', [Data.tX, Data.tY, Data.tWidth, Data.tHeight]), True)] do
1042 begin
1043 EditStyle := esEllipsis;
1044 ReadOnly := True;
1045 end;
1047 with ItemProps[InsertRow(_lc[I_PROP_TR_EX_DELAY], IntToStr(Data.Wait), True)] do
1048 begin
1049 EditStyle := esSimple;
1050 MaxLength := 5;
1051 end;
1053 with ItemProps[InsertRow(_lc[I_PROP_TR_EX_COUNT], IntToStr(Data.Count), True)] do
1054 begin
1055 EditStyle := esSimple;
1056 MaxLength := 5;
1057 end;
1059 with ItemProps[InsertRow(_lc[I_PROP_TR_EX_MONSTER], IntToStr(Data.MonsterID-1), True)] do
1060 begin
1061 EditStyle := esEllipsis;
1062 ReadOnly := True;
1063 end;
1065 if TriggerType = TRIGGER_PRESS then
1066 with ItemProps[InsertRow(_lc[I_PROP_TR_EX_RANDOM], BoolNames[Data.ExtRandom], True)] do
1067 begin
1068 EditStyle := esPickList;
1069 ReadOnly := True;
1070 end;
1071 end;
1073 TRIGGER_SECRET:
1076 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
1077 begin
1078 with ItemProps[InsertRow(_lc[I_PROP_TR_LIFT_PANEL], IntToStr(Data.PanelID), True)] do
1079 begin
1080 EditStyle := esEllipsis;
1081 ReadOnly := True;
1082 end;
1084 with ItemProps[InsertRow(_lc[I_PROP_TR_SILENT], BoolNames[Data.NoSound], True)] do
1085 begin
1086 EditStyle := esPickList;
1087 ReadOnly := True;
1088 end;
1090 with ItemProps[InsertRow(_lc[I_PROP_TR_D2D], BoolNames[Data.d2d_doors], True)] do
1091 begin
1092 EditStyle := esPickList;
1093 ReadOnly := True;
1094 end;
1095 end;
1097 TRIGGER_TEXTURE:
1098 begin
1099 with ItemProps[InsertRow(_lc[I_PROP_TR_TEXTURE_ONCE], BoolNames[Data.ActivateOnce], True)] do
1100 begin
1101 EditStyle := esPickList;
1102 ReadOnly := True;
1103 end;
1105 with ItemProps[InsertRow(_lc[I_PROP_TR_TEXTURE_ANIM_ONCE], BoolNames[Data.AnimOnce], True)] do
1106 begin
1107 EditStyle := esPickList;
1108 ReadOnly := True;
1109 end;
1110 end;
1112 TRIGGER_SOUND:
1113 begin
1114 str := win2utf(Data.SoundName);
1115 with ItemProps[InsertRow(_lc[I_PROP_TR_SOUND_NAME], str, True)] do
1116 begin
1117 EditStyle := esEllipsis;
1118 ReadOnly := True;
1119 end;
1121 with ItemProps[InsertRow(_lc[I_PROP_TR_SOUND_VOLUME], IntToStr(Data.Volume), True)] do
1122 begin
1123 EditStyle := esSimple;
1124 MaxLength := 3;
1125 end;
1127 with ItemProps[InsertRow(_lc[I_PROP_TR_SOUND_PAN], IntToStr(Data.Pan), True)] do
1128 begin
1129 EditStyle := esSimple;
1130 MaxLength := 3;
1131 end;
1133 with ItemProps[InsertRow(_lc[I_PROP_TR_SOUND_COUNT], IntToStr(Data.PlayCount), True)] do
1134 begin
1135 EditStyle := esSimple;
1136 MaxLength := 3;
1137 end;
1139 with ItemProps[InsertRow(_lc[I_PROP_TR_SOUND_LOCAL], BoolNames[Data.Local], True)] do
1140 begin
1141 EditStyle := esPickList;
1142 ReadOnly := True;
1143 end;
1145 with ItemProps[InsertRow(_lc[I_PROP_TR_SOUND_SWITCH], BoolNames[Data.SoundSwitch], True)] do
1146 begin
1147 EditStyle := esPickList;
1148 ReadOnly := True;
1149 end;
1150 end;
1152 TRIGGER_SPAWNMONSTER:
1153 begin
1154 with ItemProps[InsertRow(_lc[I_PROP_TR_MONSTER_TYPE], MonsterToStr(Data.MonType), True)] do
1155 begin
1156 EditStyle := esEllipsis;
1157 ReadOnly := True;
1158 end;
1160 with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_TO],
1161 Format('(%d:%d)', [Data.MonPos.X, Data.MonPos.Y]), True)] do
1162 begin
1163 EditStyle := esEllipsis;
1164 ReadOnly := True;
1165 end;
1167 with ItemProps[InsertRow(_lc[I_PROP_DIRECTION], DirNames[TDirection(Data.MonDir)], True)] do
1168 begin
1169 EditStyle := esPickList;
1170 ReadOnly := True;
1171 end;
1173 with ItemProps[InsertRow(_lc[I_PROP_TR_HEALTH], IntToStr(Data.MonHealth), True)] do
1174 begin
1175 EditStyle := esSimple;
1176 MaxLength := 5;
1177 end;
1179 with ItemProps[InsertRow(_lc[I_PROP_TR_MONSTER_ACTIVE], BoolNames[Data.MonActive], True)] do
1180 begin
1181 EditStyle := esPickList;
1182 ReadOnly := True;
1183 end;
1185 with ItemProps[InsertRow(_lc[I_PROP_TR_COUNT], IntToStr(Data.MonCount), True)] do
1186 begin
1187 EditStyle := esSimple;
1188 MaxLength := 5;
1189 end;
1191 with ItemProps[InsertRow(_lc[I_PROP_TR_FX_TYPE], EffectToStr(Data.MonEffect), True)] do
1192 begin
1193 EditStyle := esEllipsis;
1194 ReadOnly := True;
1195 end;
1197 with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_MAX], IntToStr(Data.MonMax), True)] do
1198 begin
1199 EditStyle := esSimple;
1200 MaxLength := 5;
1201 end;
1203 with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_DELAY], IntToStr(Data.MonDelay), True)] do
1204 begin
1205 EditStyle := esSimple;
1206 MaxLength := 5;
1207 end;
1209 case Data.MonBehav of
1210 1: str := _lc[I_PROP_TR_MONSTER_BEHAVIOUR_1];
1211 2: str := _lc[I_PROP_TR_MONSTER_BEHAVIOUR_2];
1212 3: str := _lc[I_PROP_TR_MONSTER_BEHAVIOUR_3];
1213 4: str := _lc[I_PROP_TR_MONSTER_BEHAVIOUR_4];
1214 5: str := _lc[I_PROP_TR_MONSTER_BEHAVIOUR_5];
1215 else str := _lc[I_PROP_TR_MONSTER_BEHAVIOUR_0];
1216 end;
1217 with ItemProps[InsertRow(_lc[I_PROP_TR_MONSTER_BEHAVIOUR], str, True)] do
1218 begin
1219 EditStyle := esPickList;
1220 ReadOnly := True;
1221 end;
1222 end;
1224 TRIGGER_SPAWNITEM:
1225 begin
1226 with ItemProps[InsertRow(_lc[I_PROP_TR_ITEM_TYPE], ItemToStr(Data.ItemType), True)] do
1227 begin
1228 EditStyle := esEllipsis;
1229 ReadOnly := True;
1230 end;
1232 with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_TO],
1233 Format('(%d:%d)', [Data.ItemPos.X, Data.ItemPos.Y]), True)] do
1234 begin
1235 EditStyle := esEllipsis;
1236 ReadOnly := True;
1237 end;
1239 with ItemProps[InsertRow(_lc[I_PROP_DM_ONLY], BoolNames[Data.ItemOnlyDM], True)] do
1240 begin
1241 EditStyle := esPickList;
1242 ReadOnly := True;
1243 end;
1245 with ItemProps[InsertRow(_lc[I_PROP_ITEM_FALLS], BoolNames[Data.ItemFalls], True)] do
1246 begin
1247 EditStyle := esPickList;
1248 ReadOnly := True;
1249 end;
1251 with ItemProps[InsertRow(_lc[I_PROP_TR_COUNT], IntToStr(Data.ItemCount), True)] do
1252 begin
1253 EditStyle := esSimple;
1254 MaxLength := 5;
1255 end;
1257 with ItemProps[InsertRow(_lc[I_PROP_TR_FX_TYPE], EffectToStr(Data.ItemEffect), True)] do
1258 begin
1259 EditStyle := esEllipsis;
1260 ReadOnly := True;
1261 end;
1263 with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_MAX], IntToStr(Data.ItemMax), True)] do
1264 begin
1265 EditStyle := esSimple;
1266 MaxLength := 5;
1267 end;
1269 with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_DELAY], IntToStr(Data.ItemDelay), True)] do
1270 begin
1271 EditStyle := esSimple;
1272 MaxLength := 5;
1273 end;
1274 end;
1276 TRIGGER_MUSIC:
1277 begin
1278 str := win2utf(Data.MusicName);
1279 with ItemProps[InsertRow(_lc[I_PROP_TR_MUSIC_NAME], str, True)] do
1280 begin
1281 EditStyle := esEllipsis;
1282 ReadOnly := True;
1283 end;
1285 if Data.MusicAction = 1 then
1286 str := _lc[I_PROP_TR_MUSIC_ON]
1287 else
1288 str := _lc[I_PROP_TR_MUSIC_OFF];
1290 with ItemProps[InsertRow(_lc[I_PROP_TR_MUSIC_ACT], str, True)] do
1291 begin
1292 EditStyle := esPickList;
1293 ReadOnly := True;
1294 end;
1295 end;
1297 TRIGGER_PUSH:
1298 begin
1299 with ItemProps[InsertRow(_lc[I_PROP_TR_PUSH_ANGLE], IntToStr(Data.PushAngle), True)] do
1300 begin
1301 EditStyle := esSimple;
1302 MaxLength := 4;
1303 end;
1304 with ItemProps[InsertRow(_lc[I_PROP_TR_PUSH_FORCE], IntToStr(Data.PushForce), True)] do
1305 begin
1306 EditStyle := esSimple;
1307 MaxLength := 4;
1308 end;
1309 with ItemProps[InsertRow(_lc[I_PROP_TR_PUSH_RESET], BoolNames[Data.ResetVel], True)] do
1310 begin
1311 EditStyle := esPickList;
1312 ReadOnly := True;
1313 end;
1314 end;
1316 TRIGGER_SCORE:
1317 begin
1318 case Data.ScoreAction of
1319 1: str := _lc[I_PROP_TR_SCORE_ACT_1];
1320 2: str := _lc[I_PROP_TR_SCORE_ACT_2];
1321 3: str := _lc[I_PROP_TR_SCORE_ACT_3];
1322 else str := _lc[I_PROP_TR_SCORE_ACT_0];
1323 end;
1324 with ItemProps[InsertRow(_lc[I_PROP_TR_SCORE_ACT], str, True)] do
1325 begin
1326 EditStyle := esPickList;
1327 ReadOnly := True;
1328 end;
1329 with ItemProps[InsertRow(_lc[I_PROP_TR_COUNT], IntToStr(Data.ScoreCount), True)] do
1330 begin
1331 EditStyle := esSimple;
1332 MaxLength := 3;
1333 end;
1334 case Data.ScoreTeam of
1335 1: str := _lc[I_PROP_TR_SCORE_TEAM_1];
1336 2: str := _lc[I_PROP_TR_SCORE_TEAM_2];
1337 3: str := _lc[I_PROP_TR_SCORE_TEAM_3];
1338 else str := _lc[I_PROP_TR_SCORE_TEAM_0];
1339 end;
1340 with ItemProps[InsertRow(_lc[I_PROP_TR_SCORE_TEAM], str, True)] do
1341 begin
1342 EditStyle := esPickList;
1343 ReadOnly := True;
1344 end;
1345 with ItemProps[InsertRow(_lc[I_PROP_TR_SCORE_CON], BoolNames[Data.ScoreCon], True)] do
1346 begin
1347 EditStyle := esPickList;
1348 ReadOnly := True;
1349 end;
1350 with ItemProps[InsertRow(_lc[I_PROP_TR_SCORE_MSG], BoolNames[Data.ScoreMsg], True)] do
1351 begin
1352 EditStyle := esPickList;
1353 ReadOnly := True;
1354 end;
1355 end;
1357 TRIGGER_MESSAGE:
1358 begin
1359 case Data.MessageKind of
1360 1: str := _lc[I_PROP_TR_MESSAGE_KIND_1];
1361 else str := _lc[I_PROP_TR_MESSAGE_KIND_0];
1362 end;
1363 with ItemProps[InsertRow(_lc[I_PROP_TR_MESSAGE_KIND], str, True)] do
1364 begin
1365 EditStyle := esPickList;
1366 ReadOnly := True;
1367 end;
1368 case Data.MessageSendTo of
1369 1: str := _lc[I_PROP_TR_MESSAGE_TO_1];
1370 2: str := _lc[I_PROP_TR_MESSAGE_TO_2];
1371 3: str := _lc[I_PROP_TR_MESSAGE_TO_3];
1372 4: str := _lc[I_PROP_TR_MESSAGE_TO_4];
1373 5: str := _lc[I_PROP_TR_MESSAGE_TO_5];
1374 else str := _lc[I_PROP_TR_MESSAGE_TO_0];
1375 end;
1376 with ItemProps[InsertRow(_lc[I_PROP_TR_MESSAGE_TO], str, True)] do
1377 begin
1378 EditStyle := esPickList;
1379 ReadOnly := True;
1380 end;
1381 str := win2utf(Data.MessageText);
1382 with ItemProps[InsertRow(_lc[I_PROP_TR_MESSAGE_TEXT], str, True)] do
1383 begin
1384 EditStyle := esSimple;
1385 MaxLength := 100;
1386 end;
1387 with ItemProps[InsertRow(_lc[I_PROP_TR_MESSAGE_TIME], IntToStr(Data.MessageTime), True)] do
1388 begin
1389 EditStyle := esSimple;
1390 MaxLength := 5;
1391 end;
1392 end;
1394 TRIGGER_DAMAGE:
1395 begin
1396 with ItemProps[InsertRow(_lc[I_PROP_TR_DAMAGE_VALUE], IntToStr(Data.DamageValue), True)] do
1397 begin
1398 EditStyle := esSimple;
1399 MaxLength := 5;
1400 end;
1401 with ItemProps[InsertRow(_lc[I_PROP_TR_INTERVAL], IntToStr(Data.DamageInterval), True)] do
1402 begin
1403 EditStyle := esSimple;
1404 MaxLength := 5;
1405 end;
1406 end;
1408 TRIGGER_HEALTH:
1409 begin
1410 with ItemProps[InsertRow(_lc[I_PROP_TR_HEALTH], IntToStr(Data.HealValue), True)] do
1411 begin
1412 EditStyle := esSimple;
1413 MaxLength := 5;
1414 end;
1415 with ItemProps[InsertRow(_lc[I_PROP_TR_INTERVAL], IntToStr(Data.HealInterval), True)] do
1416 begin
1417 EditStyle := esSimple;
1418 MaxLength := 5;
1419 end;
1420 with ItemProps[InsertRow(_lc[I_PROP_TR_HEALTH_MAX], BoolNames[Data.HealMax], True)] do
1421 begin
1422 EditStyle := esPickList;
1423 ReadOnly := True;
1424 end;
1425 with ItemProps[InsertRow(_lc[I_PROP_TR_SILENT], BoolNames[Data.HealSilent], True)] do
1426 begin
1427 EditStyle := esPickList;
1428 ReadOnly := True;
1429 end;
1430 end;
1432 TRIGGER_SHOT:
1433 begin
1434 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_TYPE], ShotToStr(Data.ShotType), True)] do
1435 begin
1436 EditStyle := esEllipsis;
1437 ReadOnly := True;
1438 end;
1440 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_SOUND], BoolNames[Data.ShotSound], True)] do
1441 begin
1442 EditStyle := esPickList;
1443 ReadOnly := True;
1444 end;
1446 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_PANEL], IntToStr(Data.ShotPanelID), True)] do
1447 begin
1448 EditStyle := esEllipsis;
1449 ReadOnly := True;
1450 end;
1452 case Data.ShotTarget of
1453 1: str := _lc[I_PROP_TR_SHOT_TO_1];
1454 2: str := _lc[I_PROP_TR_SHOT_TO_2];
1455 3: str := _lc[I_PROP_TR_SHOT_TO_3];
1456 4: str := _lc[I_PROP_TR_SHOT_TO_4];
1457 5: str := _lc[I_PROP_TR_SHOT_TO_5];
1458 6: str := _lc[I_PROP_TR_SHOT_TO_6];
1459 else str := _lc[I_PROP_TR_SHOT_TO_0];
1460 end;
1461 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_TO], str, True)] do
1462 begin
1463 EditStyle := esPickList;
1464 ReadOnly := True;
1465 end;
1467 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_SIGHT], IntToStr(Data.ShotIntSight), True)] do
1468 begin
1469 EditStyle := esSimple;
1470 MaxLength := 3;
1471 end;
1473 case Data.ShotAim of
1474 1: str := _lc[I_PROP_TR_SHOT_AIM_1];
1475 2: str := _lc[I_PROP_TR_SHOT_AIM_2];
1476 3: str := _lc[I_PROP_TR_SHOT_AIM_3];
1477 else str := _lc[I_PROP_TR_SHOT_AIM_0];
1478 end;
1479 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_AIM], str, True)-1] do
1480 begin
1481 EditStyle := esPickList;
1482 ReadOnly := True;
1483 end;
1485 with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_TO],
1486 Format('(%d:%d)', [Data.ShotPos.X, Data.ShotPos.Y]), True)] do
1487 begin
1488 EditStyle := esEllipsis;
1489 ReadOnly := True;
1490 end;
1492 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_ANGLE], IntToStr(Data.ShotAngle), True)] do
1493 begin
1494 EditStyle := esSimple;
1495 MaxLength := 4;
1496 end;
1498 with ItemProps[InsertRow(_lc[I_PROP_TR_EX_DELAY], IntToStr(Data.ShotWait), True)] do
1499 begin
1500 EditStyle := esSimple;
1501 MaxLength := 5;
1502 end;
1504 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_ACC], IntToStr(Data.ShotAccuracy), True)] do
1505 begin
1506 EditStyle := esSimple;
1507 MaxLength := 5;
1508 end;
1510 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_AMMO], IntToStr(Data.ShotAmmo), True)] do
1511 begin
1512 EditStyle := esSimple;
1513 MaxLength := 5;
1514 end;
1516 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_RELOAD], IntToStr(Data.ShotIntReload), True)] do
1517 begin
1518 EditStyle := esSimple;
1519 MaxLength := 4;
1520 end;
1521 end;
1523 TRIGGER_EFFECT:
1524 begin
1525 with ItemProps[InsertRow(_lc[I_PROP_TR_COUNT], IntToStr(Data.FXCount), True)] do
1526 begin
1527 EditStyle := esSimple;
1528 MaxLength := 3;
1529 end;
1531 if Data.FXType = 0 then
1532 str := _lc[I_PROP_TR_EFFECT_PARTICLE]
1533 else
1534 str := _lc[I_PROP_TR_EFFECT_ANIMATION];
1535 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_TYPE], str, True)] do
1536 begin
1537 EditStyle := esEllipsis;
1538 ReadOnly := True;
1539 end;
1541 str := '';
1542 if Data.FXType = 0 then
1543 case Data.FXSubType of
1544 TRIGGER_EFFECT_SLIQUID:
1545 str := _lc[I_PROP_TR_EFFECT_SLIQUID];
1546 TRIGGER_EFFECT_LLIQUID:
1547 str := _lc[I_PROP_TR_EFFECT_LLIQUID];
1548 TRIGGER_EFFECT_DLIQUID:
1549 str := _lc[I_PROP_TR_EFFECT_DLIQUID];
1550 TRIGGER_EFFECT_BLOOD:
1551 str := _lc[I_PROP_TR_EFFECT_BLOOD];
1552 TRIGGER_EFFECT_SPARK:
1553 str := _lc[I_PROP_TR_EFFECT_SPARK];
1554 TRIGGER_EFFECT_BUBBLE:
1555 str := _lc[I_PROP_TR_EFFECT_BUBBLE];
1556 end;
1557 if Data.FXType = 1 then
1558 begin
1559 if (Data.FXSubType = 0) or (Data.FXSubType > EFFECT_FIRE) then
1560 Data.FXSubType := EFFECT_TELEPORT;
1561 str := EffectToStr(Data.FXSubType);
1562 end;
1563 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_SUBTYPE], str, True)] do
1564 begin
1565 EditStyle := esEllipsis;
1566 ReadOnly := True;
1567 end;
1569 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_COLOR], IntToStr(Data.FXColorR or (Data.FXColorG shl 8) or (Data.FXColorB shl 16)), True)] do
1570 begin
1571 EditStyle := esEllipsis;
1572 ReadOnly := True;
1573 end;
1575 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_CENTER], BoolNames[Data.FXPos = 0], True)] do
1576 begin
1577 EditStyle := esPickList;
1578 ReadOnly := True;
1579 end;
1581 with ItemProps[InsertRow(_lc[I_PROP_TR_EX_DELAY], IntToStr(Data.FXWait), True)] do
1582 begin
1583 EditStyle := esSimple;
1584 MaxLength := 5;
1585 end;
1587 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_VELX], IntToStr(Data.FXVelX), True)] do
1588 begin
1589 EditStyle := esSimple;
1590 MaxLength := 4;
1591 end;
1593 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_VELY], IntToStr(Data.FXVelY), True)] do
1594 begin
1595 EditStyle := esSimple;
1596 MaxLength := 4;
1597 end;
1599 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_SPL], IntToStr(Data.FXSpreadL), True)] do
1600 begin
1601 EditStyle := esSimple;
1602 MaxLength := 3;
1603 end;
1605 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_SPR], IntToStr(Data.FXSpreadR), True)] do
1606 begin
1607 EditStyle := esSimple;
1608 MaxLength := 3;
1609 end;
1611 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_SPU], IntToStr(Data.FXSpreadU), True)] do
1612 begin
1613 EditStyle := esSimple;
1614 MaxLength := 3;
1615 end;
1617 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_SPD], IntToStr(Data.FXSpreadD), True)] do
1618 begin
1619 EditStyle := esSimple;
1620 MaxLength := 3;
1621 end;
1622 end;
1623 end; //case TriggerType
1624 end;
1625 end; // OBJECT_TRIGGER:
1626 end;
1627 end;
1629 procedure ChangeShownProperty(Name: String; NewValue: String);
1630 var
1631 row: Integer;
1632 begin
1633 if SelectedObjectCount() <> 1 then
1634 Exit;
1635 if not SelectedObjects[GetFirstSelected()].Live then
1636 Exit;
1638 // Есть ли такой ключ:
1639 if MainForm.vleObjectProperty.FindRow(Name, row) then
1640 begin
1641 MainForm.vleObjectProperty.Values[Name] := NewValue;
1642 end;
1643 end;
1645 procedure SelectObject(fObjectType: Byte; fID: DWORD; Multi: Boolean);
1646 var
1647 a: Integer;
1648 b: Boolean;
1649 begin
1650 if Multi then
1651 begin
1652 b := False;
1654 // Уже выделен - убираем:
1655 if SelectedObjects <> nil then
1656 for a := 0 to High(SelectedObjects) do
1657 with SelectedObjects[a] do
1658 if Live and (ID = fID) and
1659 (ObjectType = fObjectType) then
1660 begin
1661 Live := False;
1662 b := True;
1663 end;
1665 if b then
1666 Exit;
1668 SetLength(SelectedObjects, Length(SelectedObjects)+1);
1670 with SelectedObjects[High(SelectedObjects)] do
1671 begin
1672 ObjectType := fObjectType;
1673 ID := fID;
1674 Live := True;
1675 end;
1676 end
1677 else // not Multi
1678 begin
1679 SetLength(SelectedObjects, 1);
1681 with SelectedObjects[0] do
1682 begin
1683 ObjectType := fObjectType;
1684 ID := fID;
1685 Live := True;
1686 end;
1687 end;
1689 MainForm.miCopy.Enabled := True;
1690 MainForm.miCut.Enabled := True;
1692 if fObjectType = OBJECT_PANEL then
1693 begin
1694 MainForm.miToFore.Enabled := True;
1695 MainForm.miToBack.Enabled := True;
1696 end;
1697 end;
1699 procedure RemoveSelectFromObjects();
1700 begin
1701 SelectedObjects := nil;
1702 DrawPressRect := False;
1703 MouseLDown := False;
1704 MouseRDown := False;
1705 MouseAction := MOUSEACTION_NONE;
1706 SelectFlag := SELECTFLAG_NONE;
1707 ResizeType := RESIZETYPE_NONE;
1708 ResizeDirection := RESIZEDIR_NONE;
1710 MainForm.vleObjectProperty.Strings.Clear();
1712 MainForm.miCopy.Enabled := False;
1713 MainForm.miCut.Enabled := False;
1714 MainForm.miToFore.Enabled := False;
1715 MainForm.miToBack.Enabled := False;
1716 end;
1718 procedure DeleteSelectedObjects();
1719 var
1720 i, a, ii: Integer;
1721 b: Boolean;
1722 begin
1723 if SelectedObjects = nil then
1724 Exit;
1726 b := False;
1727 i := 0;
1729 for a := 0 to High(SelectedObjects) do
1730 with SelectedObjects[a] do
1731 if Live then
1732 begin
1733 if not b then
1734 begin
1735 SetLength(UndoBuffer, Length(UndoBuffer)+1);
1736 i := High(UndoBuffer);
1737 b := True;
1738 end;
1740 SetLength(UndoBuffer[i], Length(UndoBuffer[i])+1);
1741 ii := High(UndoBuffer[i]);
1743 case ObjectType of
1744 OBJECT_PANEL:
1745 begin
1746 UndoBuffer[i, ii].UndoType := UNDO_DELETE_PANEL;
1747 New(UndoBuffer[i, ii].Panel);
1748 UndoBuffer[i, ii].Panel^ := gPanels[ID];
1749 end;
1750 OBJECT_ITEM:
1751 begin
1752 UndoBuffer[i, ii].UndoType := UNDO_DELETE_ITEM;
1753 UndoBuffer[i, ii].Item := gItems[ID];
1754 end;
1755 OBJECT_AREA:
1756 begin
1757 UndoBuffer[i, ii].UndoType := UNDO_DELETE_AREA;
1758 UndoBuffer[i, ii].Area := gAreas[ID];
1759 end;
1760 OBJECT_TRIGGER:
1761 begin
1762 UndoBuffer[i, ii].UndoType := UNDO_DELETE_TRIGGER;
1763 UndoBuffer[i, ii].Trigger := gTriggers[ID];
1764 end;
1765 end;
1767 RemoveObject(ID, ObjectType);
1768 end;
1770 RemoveSelectFromObjects();
1772 MainForm.miUndo.Enabled := UndoBuffer <> nil;
1773 end;
1775 procedure Undo_Add(ObjectType: Byte; ID: DWORD; Group: Boolean = False);
1776 var
1777 i, ii: Integer;
1778 begin
1779 if (not Group) or (Length(UndoBuffer) = 0) then
1780 SetLength(UndoBuffer, Length(UndoBuffer)+1);
1781 SetLength(UndoBuffer[High(UndoBuffer)], Length(UndoBuffer[High(UndoBuffer)])+1);
1782 i := High(UndoBuffer);
1783 ii := High(UndoBuffer[i]);
1785 case ObjectType of
1786 OBJECT_PANEL:
1787 UndoBuffer[i, ii].UndoType := UNDO_ADD_PANEL;
1788 OBJECT_ITEM:
1789 UndoBuffer[i, ii].UndoType := UNDO_ADD_ITEM;
1790 OBJECT_MONSTER:
1791 UndoBuffer[i, ii].UndoType := UNDO_ADD_MONSTER;
1792 OBJECT_AREA:
1793 UndoBuffer[i, ii].UndoType := UNDO_ADD_AREA;
1794 OBJECT_TRIGGER:
1795 UndoBuffer[i, ii].UndoType := UNDO_ADD_TRIGGER;
1796 end;
1798 UndoBuffer[i, ii].AddID := ID;
1800 MainForm.miUndo.Enabled := UndoBuffer <> nil;
1801 end;
1803 procedure FullClear();
1804 begin
1805 RemoveSelectFromObjects();
1806 ClearMap();
1807 LoadSky(gMapInfo.SkyName);
1808 UndoBuffer := nil;
1809 slInvalidTextures.Clear();
1810 MapCheckForm.lbErrorList.Clear();
1811 MapCheckForm.mErrorDescription.Clear();
1813 MainForm.miUndo.Enabled := False;
1814 MainForm.sbHorizontal.Position := 0;
1815 MainForm.sbVertical.Position := 0;
1816 MainForm.FormResize(nil);
1817 MainForm.Caption := FormCaption;
1818 OpenedMap := '';
1819 OpenedWAD := '';
1820 end;
1822 procedure ErrorMessageBox(str: String);
1823 begin
1824 MessageBox(0, PChar(str), PChar(_lc[I_MSG_ERROR]),
1825 MB_ICONINFORMATION or MB_OK or MB_DEFBUTTON1);
1826 end;
1828 function CheckProperty(): Boolean;
1829 var
1830 _id: Integer;
1831 begin
1832 Result := False;
1834 _id := GetFirstSelected();
1836 if SelectedObjects[_id].ObjectType = OBJECT_PANEL then
1837 with gPanels[SelectedObjects[_id].ID] do
1838 begin
1839 if TextureWidth <> 0 then
1840 if StrToIntDef(MainForm.vleObjectProperty.Values[_lc[I_PROP_WIDTH]], 1) mod TextureWidth <> 0 then
1841 begin
1842 ErrorMessageBox(Format(_lc[I_MSG_WRONG_TEXWIDTH],
1843 [TextureWidth]));
1844 Exit;
1845 end;
1847 if TextureHeight <> 0 then
1848 if StrToIntDef(Trim(MainForm.vleObjectProperty.Values[_lc[I_PROP_HEIGHT]]), 1) mod TextureHeight <> 0 then
1849 begin
1850 ErrorMessageBox(Format(_lc[I_MSG_WRONG_TEXHEIGHT],
1851 [TextureHeight]));
1852 Exit;
1853 end;
1855 if IsTexturedPanel(PanelType) and (TextureName <> '') then
1856 if not (StrToIntDef(MainForm.vleObjectProperty.Values[_lc[I_PROP_PANEL_ALPHA]], -1) in [0..255]) then
1857 begin
1858 ErrorMessageBox(_lc[I_MSG_WRONG_ALPHA]);
1859 Exit;
1860 end;
1861 end;
1863 if SelectedObjects[_id].ObjectType in [OBJECT_PANEL, OBJECT_TRIGGER] then
1864 if (StrToIntDef(MainForm.vleObjectProperty.Values[_lc[I_PROP_WIDTH]], 0) <= 0) or
1865 (StrToIntDef(MainForm.vleObjectProperty.Values[_lc[I_PROP_HEIGHT]], 0) <= 0) then
1866 begin
1867 ErrorMessageBox(_lc[I_MSG_WRONG_SIZE]);
1868 Exit;
1869 end;
1871 if (Trim(MainForm.vleObjectProperty.Values[_lc[I_PROP_X]]) = '') or
1872 (Trim(MainForm.vleObjectProperty.Values[_lc[I_PROP_Y]]) = '') then
1873 begin
1874 ErrorMessageBox(_lc[I_MSG_WRONG_XY]);
1875 Exit;
1876 end;
1878 Result := True;
1879 end;
1881 procedure SelectTexture(ID: Integer);
1882 begin
1883 MainForm.lbTextureList.ItemIndex := ID;
1884 MainForm.lbTextureListClick(nil);
1885 end;
1887 function AddTexture(aWAD, aSection, aTex: String; silent: Boolean): Boolean;
1888 var
1889 a, FrameLen: Integer;
1890 ok: Boolean;
1891 FileName: String;
1892 ResourceName: String;
1893 FullResourceName: String;
1894 SectionName: String;
1895 Data: Pointer;
1896 Width, Height: Word;
1897 fn: String;
1898 begin
1899 Data := nil;
1900 FrameLen := 0;
1901 Width := 0;
1902 Height := 0;
1904 if aSection = '..' then
1905 SectionName := ''
1906 else
1907 SectionName := aSection;
1909 if aWAD = _lc[I_WAD_SPECIAL_MAP] then
1910 begin // Файл карты
1911 g_ProcessResourceStr(OpenedMap, @fn, nil, nil);
1912 //FileName := EditorDir+'maps\'+ExtractFileName(fn);
1913 FileName := fn;
1914 ResourceName := ':'+SectionName+'\'+aTex;
1915 end
1916 else
1917 if aWAD = _lc[I_WAD_SPECIAL_TEXS] then
1918 begin // Спец. текстуры
1919 FileName := '';
1920 ResourceName := aTex;
1921 end
1922 else
1923 begin // Внешний WAD
1924 FileName := EditorDir+'wads/'+aWAD;
1925 ResourceName := aWAD+':'+SectionName+'\'+aTex;
1926 end;
1928 ok := True;
1930 // Есть ли уже такая текстура:
1931 for a := 0 to MainForm.lbTextureList.Items.Count-1 do
1932 if ResourceName = MainForm.lbTextureList.Items[a] then
1933 begin
1934 if not silent then
1935 ErrorMessageBox(Format(_lc[I_MSG_TEXTURE_ALREADY],
1936 [ResourceName]));
1937 ok := False;
1938 end;
1940 // Название ресурса <= 64 символов:
1941 if Length(ResourceName) > 64 then
1942 begin
1943 if not silent then
1944 ErrorMessageBox(Format(_lc[I_MSG_RES_NAME_64],
1945 [ResourceName]));
1946 ok := False;
1947 end;
1949 if ok then
1950 begin
1951 a := -1;
1952 if aWAD = _lc[I_WAD_SPECIAL_TEXS] then
1953 begin
1954 a := MainForm.lbTextureList.Items.Add(ResourceName);
1955 if not silent then
1956 SelectTexture(a);
1957 Result := True;
1958 Exit;
1959 end;
1961 FullResourceName := FileName+':'+SectionName+'\'+aTex;
1963 if IsAnim(FullResourceName) then
1964 begin // Аним. текстура
1965 GetFrame(FullResourceName, Data, FrameLen, Width, Height);
1967 if g_CreateTextureMemorySize(Data, FrameLen, ResourceName, 0, 0, Width, Height, 1) then
1968 a := MainForm.lbTextureList.Items.Add(ResourceName);
1969 end
1970 else // Обычная текстура
1971 begin
1972 if g_CreateTextureWAD(ResourceName, FullResourceName) then
1973 a := MainForm.lbTextureList.Items.Add(ResourceName);
1974 end;
1975 if (a > -1) and (not silent) then
1976 SelectTexture(a);
1977 end;
1979 Result := ok;
1980 end;
1982 procedure UpdateCaption(sMap, sFile, sRes: String);
1983 begin
1984 with MainForm do
1985 if (sFile = '') and (sRes = '') and (sMap = '') then
1986 Caption := FormCaption
1987 else
1988 if sMap = '' then
1989 Caption := Format('%s - %s:%s', [FormCaption, sFile, sRes])
1990 else
1991 if (sFile <> '') and (sRes <> '') then
1992 Caption := Format('%s - %s (%s:%s)', [FormCaption, sMap, sFile, sRes])
1993 else
1994 Caption := Format('%s - %s', [FormCaption, sMap]);
1995 end;
1997 procedure OpenMap(FileName: String; mapN: String);
1998 var
1999 MapName: String;
2000 idx: Integer;
2001 begin
2002 SelectMapForm.Caption := _lc[I_CAP_OPEN];
2003 SelectMapForm.GetMaps(FileName);
2005 if (FileName = OpenedWAD) and
2006 (OpenedMap <> '') then
2007 begin
2008 MapName := OpenedMap;
2009 while (Pos(':\', MapName) > 0) do
2010 Delete(MapName, 1, Pos(':\', MapName) + 1);
2012 idx := SelectMapForm.lbMapList.Items.IndexOf(MapName);
2013 SelectMapForm.lbMapList.ItemIndex := idx;
2014 end
2015 else
2016 if SelectMapForm.lbMapList.Count > 0 then
2017 SelectMapForm.lbMapList.ItemIndex := 0
2018 else
2019 SelectMapForm.lbMapList.ItemIndex := -1;
2021 if mapN = '' then
2022 idx := -1
2023 else
2024 idx := SelectMapForm.lbMapList.Items.IndexOf(mapN);
2026 if idx < 0 then
2027 begin
2028 if (SelectMapForm.ShowModal() = mrOK) and
2029 (SelectMapForm.lbMapList.ItemIndex <> -1) then
2030 idx := SelectMapForm.lbMapList.ItemIndex
2031 else
2032 Exit;
2033 end;
2035 MapName := SelectMapForm.lbMapList.Items[idx];
2037 with MainForm do
2038 begin
2039 FullClear();
2041 pLoadProgress.Left := (RenderPanel.Width div 2)-(pLoadProgress.Width div 2);
2042 pLoadProgress.Top := (RenderPanel.Height div 2)-(pLoadProgress.Height div 2);
2043 pLoadProgress.Show();
2045 OpenedMap := FileName+':\'+MapName;
2046 OpenedWAD := FileName;
2048 idx := RecentFiles.IndexOf(OpenedMap);
2049 // Такая карта уже недавно открывалась:
2050 if idx >= 0 then
2051 RecentFiles.Delete(idx);
2052 RecentFiles.Insert(0, OpenedMap);
2053 RefreshRecentMenu();
2055 LoadMap(OpenedMap);
2057 pLoadProgress.Hide();
2058 FormResize(nil);
2060 lbTextureList.Sorted := True;
2061 lbTextureList.Sorted := False;
2063 UpdateCaption(gMapInfo.Name, ExtractFileName(FileName), MapName);
2064 end;
2065 end;
2067 procedure MoveSelectedObjects(Wall, alt: Boolean; dx, dy: Integer);
2068 var
2069 okX, okY: Boolean;
2070 a: Integer;
2071 begin
2072 if SelectedObjects = nil then
2073 Exit;
2075 okX := True;
2076 okY := True;
2078 if Wall then
2079 for a := 0 to High(SelectedObjects) do
2080 if SelectedObjects[a].Live then
2081 begin
2082 if ObjectCollideLevel(SelectedObjects[a].ID, SelectedObjects[a].ObjectType, dx, 0) then
2083 okX := False;
2085 if ObjectCollideLevel(SelectedObjects[a].ID, SelectedObjects[a].ObjectType, 0, dy) then
2086 okY := False;
2088 if (not okX) or (not okY) then
2089 Break;
2090 end;
2092 if okX or okY then
2093 begin
2094 for a := 0 to High(SelectedObjects) do
2095 if SelectedObjects[a].Live then
2096 begin
2097 if okX then
2098 MoveObject(SelectedObjects[a].ObjectType, SelectedObjects[a].ID, dx, 0);
2100 if okY then
2101 MoveObject(SelectedObjects[a].ObjectType, SelectedObjects[a].ID, 0, dy);
2103 if alt and (SelectedObjects[a].ObjectType = OBJECT_TRIGGER) then
2104 begin
2105 if gTriggers[SelectedObjects[a].ID].TriggerType in [TRIGGER_PRESS,
2106 TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF] then
2107 begin // Двигаем зону Расширителя
2108 if okX then
2109 gTriggers[SelectedObjects[a].ID].Data.tX := gTriggers[SelectedObjects[a].ID].Data.tX+dx;
2110 if okY then
2111 gTriggers[SelectedObjects[a].ID].Data.tY := gTriggers[SelectedObjects[a].ID].Data.tY+dy;
2112 end;
2114 if gTriggers[SelectedObjects[a].ID].TriggerType in [TRIGGER_TELEPORT] then
2115 begin // Двигаем точку назначения Телепорта
2116 if okX then
2117 gTriggers[SelectedObjects[a].ID].Data.TargetPoint.X := gTriggers[SelectedObjects[a].ID].Data.TargetPoint.X+dx;
2118 if okY then
2119 gTriggers[SelectedObjects[a].ID].Data.TargetPoint.Y := gTriggers[SelectedObjects[a].ID].Data.TargetPoint.Y+dy;
2120 end;
2122 if gTriggers[SelectedObjects[a].ID].TriggerType in [TRIGGER_SPAWNMONSTER] then
2123 begin // Двигаем точку создания монстра
2124 if okX then
2125 gTriggers[SelectedObjects[a].ID].Data.MonPos.X := gTriggers[SelectedObjects[a].ID].Data.MonPos.X+dx;
2126 if okY then
2127 gTriggers[SelectedObjects[a].ID].Data.MonPos.Y := gTriggers[SelectedObjects[a].ID].Data.MonPos.Y+dy;
2128 end;
2130 if gTriggers[SelectedObjects[a].ID].TriggerType in [TRIGGER_SPAWNITEM] then
2131 begin // Двигаем точку создания предмета
2132 if okX then
2133 gTriggers[SelectedObjects[a].ID].Data.ItemPos.X := gTriggers[SelectedObjects[a].ID].Data.ItemPos.X+dx;
2134 if okY then
2135 gTriggers[SelectedObjects[a].ID].Data.ItemPos.Y := gTriggers[SelectedObjects[a].ID].Data.ItemPos.Y+dy;
2136 end;
2138 if gTriggers[SelectedObjects[a].ID].TriggerType in [TRIGGER_SHOT] then
2139 begin // Двигаем точку создания выстрела
2140 if okX then
2141 gTriggers[SelectedObjects[a].ID].Data.ShotPos.X := gTriggers[SelectedObjects[a].ID].Data.ShotPos.X+dx;
2142 if okY then
2143 gTriggers[SelectedObjects[a].ID].Data.ShotPos.Y := gTriggers[SelectedObjects[a].ID].Data.ShotPos.Y+dy;
2144 end;
2145 end;
2146 end;
2148 LastMovePoint := MousePos;
2149 end;
2150 end;
2152 procedure ShowLayer(Layer: Byte; show: Boolean);
2153 begin
2154 LayerEnabled[Layer] := show;
2156 case Layer of
2157 LAYER_BACK:
2158 begin
2159 MainForm.miLayer1.Checked := show;
2160 MainForm.miLayerP1.Checked := show;
2161 end;
2162 LAYER_WALLS:
2163 begin
2164 MainForm.miLayer2.Checked := show;
2165 MainForm.miLayerP2.Checked := show;
2166 end;
2167 LAYER_FOREGROUND:
2168 begin
2169 MainForm.miLayer3.Checked := show;
2170 MainForm.miLayerP3.Checked := show;
2171 end;
2172 LAYER_STEPS:
2173 begin
2174 MainForm.miLayer4.Checked := show;
2175 MainForm.miLayerP4.Checked := show;
2176 end;
2177 LAYER_WATER:
2178 begin
2179 MainForm.miLayer5.Checked := show;
2180 MainForm.miLayerP5.Checked := show;
2181 end;
2182 LAYER_ITEMS:
2183 begin
2184 MainForm.miLayer6.Checked := show;
2185 MainForm.miLayerP6.Checked := show;
2186 end;
2187 LAYER_MONSTERS:
2188 begin
2189 MainForm.miLayer7.Checked := show;
2190 MainForm.miLayerP7.Checked := show;
2191 end;
2192 LAYER_AREAS:
2193 begin
2194 MainForm.miLayer8.Checked := show;
2195 MainForm.miLayerP8.Checked := show;
2196 end;
2197 LAYER_TRIGGERS:
2198 begin
2199 MainForm.miLayer9.Checked := show;
2200 MainForm.miLayerP9.Checked := show;
2201 end;
2202 end;
2204 RemoveSelectFromObjects();
2205 end;
2207 procedure SwitchLayer(Layer: Byte);
2208 begin
2209 ShowLayer(Layer, not LayerEnabled[Layer]);
2210 end;
2212 procedure SwitchMap();
2213 begin
2214 ShowMap := not ShowMap;
2215 MainForm.tbShowMap.Down := ShowMap;
2216 end;
2218 procedure ShowEdges();
2219 begin
2220 if drEdge[3] < 255 then
2221 drEdge[3] := 255
2222 else
2223 drEdge[3] := gAlphaEdge;
2224 end;
2226 function SelectedTexture(): String;
2227 begin
2228 if MainForm.lbTextureList.ItemIndex <> -1 then
2229 Result := MainForm.lbTextureList.Items[MainForm.lbTextureList.ItemIndex]
2230 else
2231 Result := '';
2232 end;
2234 function IsSpecialTextureSel(): Boolean;
2235 begin
2236 Result := (MainForm.lbTextureList.ItemIndex <> -1) and
2237 IsSpecialTexture(MainForm.lbTextureList.Items[MainForm.lbTextureList.ItemIndex]);
2238 end;
2240 function CopyBufferToString(var CopyBuf: TCopyRecArray): String;
2241 var
2242 i, j: Integer;
2243 Res: String;
2245 procedure AddInt(x: Integer);
2246 begin
2247 Res := Res + IntToStr(x) + ' ';
2248 end;
2250 begin
2251 Result := '';
2253 if Length(CopyBuf) = 0 then
2254 Exit;
2256 Res := CLIPBOARD_SIG + ' ';
2258 for i := 0 to High(CopyBuf) do
2259 begin
2260 if (CopyBuf[i].ObjectType = OBJECT_PANEL) and
2261 (CopyBuf[i].Panel = nil) then
2262 Continue;
2264 // Тип объекта:
2265 AddInt(CopyBuf[i].ObjectType);
2266 Res := Res + '; ';
2268 // Свойства объекта:
2269 case CopyBuf[i].ObjectType of
2270 OBJECT_PANEL:
2271 with CopyBuf[i].Panel^ do
2272 begin
2273 AddInt(PanelType);
2274 AddInt(X);
2275 AddInt(Y);
2276 AddInt(Width);
2277 AddInt(Height);
2278 Res := Res + '"' + TextureName + '" ';
2279 AddInt(Alpha);
2280 AddInt(IfThen(Blending, 1, 0));
2281 end;
2283 OBJECT_ITEM:
2284 with CopyBuf[i].Item do
2285 begin
2286 AddInt(ItemType);
2287 AddInt(X);
2288 AddInt(Y);
2289 AddInt(IfThen(OnlyDM, 1, 0));
2290 AddInt(IfThen(Fall, 1, 0));
2291 end;
2293 OBJECT_MONSTER:
2294 with CopyBuf[i].Monster do
2295 begin
2296 AddInt(MonsterType);
2297 AddInt(X);
2298 AddInt(Y);
2299 AddInt(IfThen(Direction = D_LEFT, 1, 0));
2300 end;
2302 OBJECT_AREA:
2303 with CopyBuf[i].Area do
2304 begin
2305 AddInt(AreaType);
2306 AddInt(X);
2307 AddInt(Y);
2308 AddInt(IfThen(Direction = D_LEFT, 1, 0));
2309 end;
2311 OBJECT_TRIGGER:
2312 with CopyBuf[i].Trigger do
2313 begin
2314 AddInt(TriggerType);
2315 AddInt(X);
2316 AddInt(Y);
2317 AddInt(Width);
2318 AddInt(Height);
2319 AddInt(ActivateType);
2320 AddInt(Key);
2321 AddInt(IfThen(Enabled, 1, 0));
2322 AddInt(TexturePanel);
2324 for j := 0 to 127 do
2325 AddInt(Data.Default[j]);
2326 end;
2327 end;
2328 end;
2330 Result := Res;
2331 end;
2333 procedure StringToCopyBuffer(Str: String; var CopyBuf: TCopyRecArray);
2334 var
2335 i, j, t: Integer;
2337 function GetNext(): String;
2338 var
2339 p: Integer;
2341 begin
2342 if Str[1] = '"' then
2343 begin
2344 Delete(Str, 1, 1);
2345 p := Pos('"', Str);
2347 if p = 0 then
2348 begin
2349 Result := Str;
2350 Str := '';
2351 end
2352 else
2353 begin
2354 Result := Copy(Str, 1, p-1);
2355 Delete(Str, 1, p);
2356 Str := Trim(Str);
2357 end;
2358 end
2359 else
2360 begin
2361 p := Pos(' ', Str);
2363 if p = 0 then
2364 begin
2365 Result := Str;
2366 Str := '';
2367 end
2368 else
2369 begin
2370 Result := Copy(Str, 1, p-1);
2371 Delete(Str, 1, p);
2372 Str := Trim(Str);
2373 end;
2374 end;
2375 end;
2377 begin
2378 Str := Trim(Str);
2380 if GetNext() <> CLIPBOARD_SIG then
2381 Exit;
2383 while Str <> '' do
2384 begin
2385 // Тип объекта:
2386 t := StrToIntDef(GetNext(), 0);
2388 if (t < OBJECT_PANEL) or (t > OBJECT_TRIGGER) or
2389 (GetNext() <> ';') then
2390 begin // Что-то не то => пропускаем:
2391 t := Pos(';', Str);
2392 Delete(Str, 1, t);
2393 Str := Trim(Str);
2395 Continue;
2396 end;
2398 i := Length(CopyBuf);
2399 SetLength(CopyBuf, i + 1);
2401 CopyBuf[i].ObjectType := t;
2402 CopyBuf[i].Panel := nil;
2404 // Свойства объекта:
2405 case t of
2406 OBJECT_PANEL:
2407 begin
2408 New(CopyBuf[i].Panel);
2410 with CopyBuf[i].Panel^ do
2411 begin
2412 PanelType := StrToIntDef(GetNext(), PANEL_WALL);
2413 X := StrToIntDef(GetNext(), 0);
2414 Y := StrToIntDef(GetNext(), 0);
2415 Width := StrToIntDef(GetNext(), 16);
2416 Height := StrToIntDef(GetNext(), 16);
2417 TextureName := GetNext();
2418 Alpha := StrToIntDef(GetNext(), 0);
2419 Blending := (GetNext() = '1');
2420 end;
2421 end;
2423 OBJECT_ITEM:
2424 with CopyBuf[i].Item do
2425 begin
2426 ItemType := StrToIntDef(GetNext(), ITEM_MEDKIT_SMALL);
2427 X := StrToIntDef(GetNext(), 0);
2428 Y := StrToIntDef(GetNext(), 0);
2429 OnlyDM := (GetNext() = '1');
2430 Fall := (GetNext() = '1');
2431 end;
2433 OBJECT_MONSTER:
2434 with CopyBuf[i].Monster do
2435 begin
2436 MonsterType := StrToIntDef(GetNext(), MONSTER_DEMON);
2437 X := StrToIntDef(GetNext(), 0);
2438 Y := StrToIntDef(GetNext(), 0);
2440 if GetNext() = '1' then
2441 Direction := D_LEFT
2442 else
2443 Direction := D_RIGHT;
2444 end;
2446 OBJECT_AREA:
2447 with CopyBuf[i].Area do
2448 begin
2449 AreaType := StrToIntDef(GetNext(), AREA_PLAYERPOINT1);
2450 X := StrToIntDef(GetNext(), 0);
2451 Y := StrToIntDef(GetNext(), 0);
2452 if GetNext() = '1' then
2453 Direction := D_LEFT
2454 else
2455 Direction := D_RIGHT;
2456 end;
2458 OBJECT_TRIGGER:
2459 with CopyBuf[i].Trigger do
2460 begin
2461 TriggerType := StrToIntDef(GetNext(), TRIGGER_EXIT);
2462 X := StrToIntDef(GetNext(), 0);
2463 Y := StrToIntDef(GetNext(), 0);
2464 Width := StrToIntDef(GetNext(), 16);
2465 Height := StrToIntDef(GetNext(), 16);
2466 ActivateType := StrToIntDef(GetNext(), 0);
2467 Key := StrToIntDef(GetNext(), 0);
2468 Enabled := (GetNext() = '1');
2469 TexturePanel := StrToIntDef(GetNext(), 0);
2471 for j := 0 to 127 do
2472 Data.Default[j] := StrToIntDef(GetNext(), 0);
2473 end;
2474 end;
2475 end;
2476 end;
2478 //----------------------------------------
2479 //Закончились вспомогательные процедуры
2480 //----------------------------------------
2482 procedure TMainForm.RefreshRecentMenu();
2483 var
2484 i: Integer;
2485 MI: TMenuItem;
2486 begin
2487 // Лишние запомненные карты:
2488 while RecentFiles.Count > RecentCount do
2489 RecentFiles.Delete(RecentFiles.Count-1);
2491 // Лишние строки меню:
2492 while MainMenu.Items[0].Count > RECENT_FILES_MENU_START do
2493 MainMenu.Items[0].Delete(MainMenu.Items[0].Count-1);
2495 // Отделение списка карт от строки "Выход":
2496 if RecentFiles.Count > 0 then
2497 begin
2498 MI := TMenuItem.Create(MainMenu.Items[0]);
2499 MI.Caption := '-';
2500 MainMenu.Items[0].Add(MI);
2501 end;
2503 // Добавление в меню списка запомненных карт:
2504 for i := 0 to RecentFiles.Count-1 do
2505 begin
2506 MI := TMenuItem.Create(MainMenu.Items[0]);
2507 MI.Caption := IntToStr(i+1) + ' ' + RecentFiles[i];
2508 MI.OnClick := aRecentFileExecute;
2509 MainMenu.Items[0].Add(MI);
2510 end;
2511 end;
2513 procedure TMainForm.aRecentFileExecute(Sender: TObject);
2514 var
2515 n, pw: Integer;
2516 s, fn: String;
2517 b: Boolean;
2518 begin
2519 s := LowerCase((Sender as TMenuItem).Caption);
2520 Delete(s, Pos('&', s), 1);
2521 s := Trim(Copy(s, 1, 2));
2522 n := StrToIntDef(s, 0) - 1;
2524 if (n < 0) or (n >= RecentFiles.Count) then
2525 Exit;
2527 s := RecentFiles[n];
2528 pw := Pos('.wad:\', LowerCase(s));
2529 b := False;
2531 if pw > 0 then
2532 begin // Map name included
2533 fn := Copy(s, 1, pw + 3);
2534 Delete(s, 1, pw + 5);
2535 if (FileExists(fn)) then
2536 begin
2537 OpenMap(fn, s);
2538 b := True;
2539 end;
2540 end
2541 else // Only wad name
2542 if (FileExists(s)) then
2543 begin
2544 OpenMap(s, '');
2545 b := True;
2546 end;
2548 if (not b) and (MessageBox(0, PChar(_lc[I_MSG_DEL_RECENT_PROMT]),
2549 PChar(_lc[I_MSG_DEL_RECENT]), MB_ICONQUESTION or MB_YESNO) = idYes) then
2550 begin
2551 RecentFiles.Delete(n);
2552 RefreshRecentMenu();
2553 end;
2554 end;
2556 procedure TMainForm.aEditorOptionsExecute(Sender: TObject);
2557 begin
2558 OptionsForm.ShowModal();
2559 end;
2561 procedure LoadStdFont(cfgres, texture: string; var FontID: DWORD);
2562 var
2563 cwdt, chgt: Byte;
2564 spc: ShortInt;
2565 ID: DWORD;
2566 wad: TWADEditor_1;
2567 cfgdata: Pointer;
2568 cfglen: Integer;
2569 config: TConfig;
2570 begin
2571 cfgdata := nil;
2572 cfglen := 0;
2573 ID := 0;
2575 wad := TWADEditor_1.Create;
2576 if wad.ReadFile(EditorDir+'data/Game.wad') then
2577 wad.GetResource('FONTS', cfgres, cfgdata, cfglen);
2578 wad.Free();
2580 if cfglen <> 0 then
2581 begin
2582 if not g_CreateTextureWAD('FONT_STD', EditorDir+'data/Game.wad:FONTS\'+texture) then
2583 e_WriteLog('ERROR ERROR ERROR', MSG_WARNING);
2585 config := TConfig.CreateMem(cfgdata, cfglen);
2586 cwdt := Min(Max(config.ReadInt('FontMap', 'CharWidth', 0), 0), 255);
2587 chgt := Min(Max(config.ReadInt('FontMap', 'CharHeight', 0), 0), 255);
2588 spc := Min(Max(config.ReadInt('FontMap', 'Kerning', 0), -128), 127);
2590 if g_GetTexture('FONT_STD', ID) then
2591 e_TextureFontBuild(ID, FontID, cwdt, chgt, spc-2);
2593 config.Free();
2594 end
2595 else
2596 e_WriteLog('Could not load FONT_STD', MSG_WARNING);
2598 if cfglen <> 0 then FreeMem(cfgdata);
2599 end;
2601 procedure TMainForm.FormCreate(Sender: TObject);
2602 var
2603 config: TConfig;
2604 i: Integer;
2605 s: String;
2606 begin
2607 Randomize();
2609 EditorDir := ExtractFilePath(Application.ExeName);
2611 e_InitLog(EditorDir+'Editor.log', WM_NEWFILE);
2613 slInvalidTextures := TStringList.Create;
2615 ShowLayer(LAYER_BACK, True);
2616 ShowLayer(LAYER_WALLS, True);
2617 ShowLayer(LAYER_FOREGROUND, True);
2618 ShowLayer(LAYER_STEPS, True);
2619 ShowLayer(LAYER_WATER, True);
2620 ShowLayer(LAYER_ITEMS, True);
2621 ShowLayer(LAYER_MONSTERS, True);
2622 ShowLayer(LAYER_AREAS, True);
2623 ShowLayer(LAYER_TRIGGERS, True);
2625 ClearMap();
2627 FormCaption := MainForm.Caption;
2628 OpenedMap := '';
2629 OpenedWAD := '';
2631 config := TConfig.CreateFile(EditorDir+'Editor.cfg');
2633 if config.ReadInt('Editor', 'XPos', -1) = -1 then
2634 Position := poDesktopCenter
2635 else begin
2636 Left := config.ReadInt('Editor', 'XPos', Left);
2637 Top := config.ReadInt('Editor', 'YPos', Top);
2638 Width := config.ReadInt('Editor', 'Width', Width);
2639 Height := config.ReadInt('Editor', 'Height', Height);
2640 end;
2641 if config.ReadBool('Editor', 'Maximize', False) then
2642 WindowState := wsMaximized;
2643 ShowMap := config.ReadBool('Editor', 'Minimap', False);
2644 PanelProps.Width := config.ReadInt('Editor', 'PanelProps', PanelProps.ClientWidth);
2645 Splitter1.Left := PanelProps.Left;
2646 PanelObjs.Height := config.ReadInt('Editor', 'PanelObjs', PanelObjs.ClientHeight);
2647 Splitter2.Top := PanelObjs.Top;
2648 StatusBar.Top := PanelObjs.BoundsRect.Bottom;
2649 DotEnable := config.ReadBool('Editor', 'DotEnable', True);
2650 DotColor := config.ReadInt('Editor', 'DotColor', $FFFFFF);
2651 DotStepOne := config.ReadInt('Editor', 'DotStepOne', 16);
2652 DotStepTwo := config.ReadInt('Editor', 'DotStepTwo', 8);
2653 DotStep := config.ReadInt('Editor', 'DotStep', DotStepOne);
2654 DrawTexturePanel := config.ReadBool('Editor', 'DrawTexturePanel', True);
2655 DrawPanelSize := config.ReadBool('Editor', 'DrawPanelSize', True);
2656 BackColor := config.ReadInt('Editor', 'BackColor', $7F6040);
2657 PreviewColor := config.ReadInt('Editor', 'PreviewColor', $00FF00);
2658 gColorEdge := config.ReadInt('Editor', 'EdgeColor', COLOR_EDGE);
2659 gAlphaEdge := config.ReadInt('Editor', 'EdgeAlpha', ALPHA_EDGE);
2660 if gAlphaEdge = 255 then
2661 gAlphaEdge := ALPHA_EDGE;
2662 drEdge[0] := GetRValue(gColorEdge);
2663 drEdge[1] := GetGValue(gColorEdge);
2664 drEdge[2] := GetBValue(gColorEdge);
2665 if not config.ReadBool('Editor', 'EdgeShow', True) then
2666 drEdge[3] := 255
2667 else
2668 drEdge[3] := gAlphaEdge;
2669 gAlphaTriggerLine := config.ReadInt('Editor', 'LineAlpha', ALPHA_LINE);
2670 if gAlphaTriggerLine = 255 then
2671 gAlphaTriggerLine := ALPHA_LINE;
2672 gAlphaTriggerArea := config.ReadInt('Editor', 'TriggerAlpha', ALPHA_AREA);
2673 if gAlphaTriggerArea = 255 then
2674 gAlphaTriggerArea := ALPHA_AREA;
2675 if config.ReadInt('Editor', 'Scale', 0) = 1 then
2676 Scale := 2
2677 else
2678 Scale := 1;
2679 if config.ReadInt('Editor', 'DotSize', 0) = 1 then
2680 DotSize := 2
2681 else
2682 DotSize := 1;
2683 OpenDialog.InitialDir := config.ReadStr('Editor', 'LastOpenDir', EditorDir);
2684 SaveDialog.InitialDir := config.ReadStr('Editor', 'LastSaveDir', EditorDir);
2686 s := config.ReadStr('Editor', 'Language', '');
2687 gLanguage := s;
2689 RecentCount := config.ReadInt('Editor', 'RecentCount', 5);
2690 if RecentCount > 10 then
2691 RecentCount := 10;
2692 if RecentCount < 2 then
2693 RecentCount := 2;
2695 RecentFiles := TStringList.Create();
2696 for i := 0 to RecentCount-1 do
2697 begin
2698 s := config.ReadStr('RecentFiles', IntToStr(i+1), '');
2699 if s <> '' then
2700 RecentFiles.Add(s);
2701 end;
2702 RefreshRecentMenu();
2704 config.Free();
2706 tbShowMap.Down := ShowMap;
2707 tbGridOn.Down := DotEnable;
2708 pcObjects.ActivePageIndex := 0;
2709 Application.Title := _lc[I_EDITOR_TITLE];
2711 Application.OnIdle := OnIdle;
2712 end;
2714 procedure PrintBlack(X, Y: Integer; Text: string; FontID: DWORD);
2715 begin
2716 // NOTE: all the font printing routines assume CP1251
2717 e_TextureFontPrintEx(X, Y, Text, FontID, 0, 0, 0, 1.0);
2718 end;
2720 procedure TMainForm.Draw();
2721 var
2722 x, y: Integer;
2723 a, b: Integer;
2724 ID, PID: DWORD;
2725 Width, Height: Word;
2726 Rect: TRectWH;
2727 ObjCount: Word;
2728 aX, aY, aX2, aY2, XX, ScaleSz: Integer;
2729 begin
2730 ID := 0;
2731 PID := 0;
2732 Width := 0;
2733 Height := 0;
2735 e_BeginRender();
2737 e_Clear(GL_COLOR_BUFFER_BIT,
2738 GetRValue(BackColor)/255,
2739 GetGValue(BackColor)/255,
2740 GetBValue(BackColor)/255);
2742 DrawMap();
2744 ObjCount := SelectedObjectCount();
2746 // Обводим выделенные объекты красной рамкой:
2747 if ObjCount > 0 then
2748 begin
2749 for a := 0 to High(SelectedObjects) do
2750 if SelectedObjects[a].Live then
2751 begin
2752 Rect := ObjectGetRect(SelectedObjects[a].ObjectType, SelectedObjects[a].ID);
2754 with Rect do
2755 begin
2756 e_DrawQuad(X+MapOffset.X, Y+MapOffset.Y,
2757 X+MapOffset.X+Width-1, Y+MapOffset.Y+Height-1,
2758 255, 0, 0);
2760 // Рисуем точки изменения размеров:
2761 if (ObjCount = 1) and
2762 (SelectedObjects[GetFirstSelected].ObjectType in [OBJECT_PANEL, OBJECT_TRIGGER]) then
2763 begin
2764 e_DrawPoint(5, X+MapOffset.X, Y+MapOffset.Y+(Height div 2), 255, 255, 255);
2765 e_DrawPoint(5, X+MapOffset.X+Width-1, Y+MapOffset.Y+(Height div 2), 255, 255, 255);
2766 e_DrawPoint(5, X+MapOffset.X+(Width div 2), Y+MapOffset.Y, 255, 255, 255);
2767 e_DrawPoint(5, X+MapOffset.X+(Width div 2), Y+MapOffset.Y+Height-1, 255, 255, 255);
2769 e_DrawPoint(3, X+MapOffset.X, Y+MapOffset.Y+(Height div 2), 255, 0, 0);
2770 e_DrawPoint(3, X+MapOffset.X+Width-1, Y+MapOffset.Y+(Height div 2), 255, 0, 0);
2771 e_DrawPoint(3, X+MapOffset.X+(Width div 2), Y+MapOffset.Y, 255, 0, 0);
2772 e_DrawPoint(3, X+MapOffset.X+(Width div 2), Y+MapOffset.Y+Height-1, 255, 0, 0);
2773 end;
2774 end;
2775 end;
2776 end;
2778 // Рисуем сетку:
2779 if DotEnable and (PreviewMode = 0) then
2780 begin
2781 if DotSize = 2 then
2782 a := -1
2783 else
2784 a := 0;
2786 for x := 0 to (RenderPanel.Width div DotStep) do
2787 for y := 0 to (RenderPanel.Height div DotStep) do
2788 e_DrawPoint(DotSize, x*DotStep + a, y*DotStep + a,
2789 GetRValue(DotColor),
2790 GetGValue(DotColor),
2791 GetBValue(DotColor));
2792 end;
2794 // Превью текстуры:
2795 if (lbTextureList.ItemIndex <> -1) and (cbPreview.Checked) and
2796 (not IsSpecialTextureSel()) and (PreviewMode = 0) then
2797 begin
2798 if not g_GetTexture(SelectedTexture(), ID) then
2799 g_GetTexture('NOTEXTURE', ID);
2800 g_GetTextureSizeByID(ID, Width, Height);
2801 if g_GetTexture('PREVIEW', PID) then
2802 e_DrawFill(PID, RenderPanel.Width-Width, RenderPanel.Height-Height, Width div 16 + 1, Height div 16 + 1, 0, True, False);
2803 e_Draw(ID, RenderPanel.Width-Width, RenderPanel.Height-Height, 0, True, False);
2804 end;
2806 // Подсказка при выборе точки Телепорта:
2807 if SelectFlag = SELECTFLAG_TELEPORT then
2808 begin
2809 with gTriggers[SelectedObjects[GetFirstSelected()].ID] do
2810 if Data.d2d_teleport then
2811 e_DrawLine(2, MousePos.X-16, MousePos.Y-1,
2812 MousePos.X+16, MousePos.Y-1,
2813 0, 0, 255)
2814 else
2815 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+AreaSize[AREA_DMPOINT].Width-1,
2816 MousePos.Y+AreaSize[AREA_DMPOINT].Height-1, 255, 255, 255);
2818 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 192, 192, 192, 127);
2819 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 255, 255, 255);
2820 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_TELEPORT], gEditorFont);
2821 end;
2823 // Подсказка при выборе точки появления:
2824 if SelectFlag = SELECTFLAG_SPAWNPOINT then
2825 begin
2826 e_DrawLine(2, MousePos.X-16, MousePos.Y-1,
2827 MousePos.X+16, MousePos.Y-1,
2828 0, 0, 255);
2829 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 192, 192, 192, 127);
2830 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 255, 255, 255);
2831 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_SPAWN], gEditorFont);
2832 end;
2834 // Подсказка при выборе панели двери:
2835 if SelectFlag = SELECTFLAG_DOOR then
2836 begin
2837 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 192, 192, 192, 127);
2838 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 255, 255, 255);
2839 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_PANEL_DOOR], gEditorFont);
2840 end;
2842 // Подсказка при выборе панели с текстурой:
2843 if SelectFlag = SELECTFLAG_TEXTURE then
2844 begin
2845 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+196, MousePos.Y+18, 192, 192, 192, 127);
2846 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+196, MousePos.Y+18, 255, 255, 255);
2847 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_PANEL_TEXTURE], gEditorFont);
2848 end;
2850 // Подсказка при выборе панели индикации выстрела:
2851 if SelectFlag = SELECTFLAG_SHOTPANEL then
2852 begin
2853 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+316, MousePos.Y+18, 192, 192, 192, 127);
2854 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+316, MousePos.Y+18, 255, 255, 255);
2855 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_PANEL_SHOT], gEditorFont);
2856 end;
2858 // Подсказка при выборе панели лифта:
2859 if SelectFlag = SELECTFLAG_LIFT then
2860 begin
2861 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 192, 192, 192, 127);
2862 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 255, 255, 255);
2863 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_PANEL_LIFT], gEditorFont);
2864 end;
2866 // Подсказка при выборе монстра:
2867 if SelectFlag = SELECTFLAG_MONSTER then
2868 begin
2869 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+120, MousePos.Y+18, 192, 192, 192, 127);
2870 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+120, MousePos.Y+18, 255, 255, 255);
2871 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_MONSTER], gEditorFont);
2872 end;
2874 // Подсказка при выборе области воздействия:
2875 if DrawPressRect then
2876 begin
2877 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+204, MousePos.Y+18, 192, 192, 192, 127);
2878 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+204, MousePos.Y+18, 255, 255, 255);
2879 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_EXT_AREA], gEditorFont);
2880 end;
2882 // Рисуем текстуры, если чертим панель:
2883 if (MouseAction = MOUSEACTION_DRAWPANEL) and (DrawTexturePanel) and
2884 (lbTextureList.ItemIndex <> -1) and (DrawRect <> nil) and
2885 (lbPanelType.ItemIndex in [0..8]) and not IsSpecialTextureSel() then
2886 begin
2887 if not g_GetTexture(SelectedTexture(), ID) then
2888 g_GetTexture('NOTEXTURE', ID);
2889 g_GetTextureSizeByID(ID, Width, Height);
2890 with DrawRect^ do
2891 e_DrawFill(ID, Min(Left, Right), Min(Top, Bottom), Abs(Right-Left) div Width,
2892 Abs(Bottom-Top) div Height, 0, True, False);
2893 end;
2895 // Прямоугольник выделения:
2896 if DrawRect <> nil then
2897 with DrawRect^ do
2898 e_DrawQuad(Left, Top, Right-1, Bottom-1, 255, 255, 255);
2900 // Чертим мышью панель/триггер или меняем мышью их размер:
2901 if (MouseAction in [MOUSEACTION_DRAWPANEL, MOUSEACTION_DRAWTRIGGER, MOUSEACTION_RESIZE]) and
2902 (DrawPanelSize) then
2903 begin
2904 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+88, MousePos.Y+33, 192, 192, 192, 127);
2905 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+88, MousePos.Y+33, 255, 255, 255);
2907 if MouseAction in [MOUSEACTION_DRAWPANEL, MOUSEACTION_DRAWTRIGGER] then
2908 begin // Чертим новый
2909 PrintBlack(MousePos.X+2, MousePos.Y+2, Format(_glc[I_HINT_WIDTH],
2910 [Abs(MousePos.X-MouseLDownPos.X)]), gEditorFont);
2911 PrintBlack(MousePos.X+2, MousePos.Y+14, Format(_glc[I_HINT_HEIGHT],
2912 [Abs(MousePos.Y-MouseLDownPos.Y)]), gEditorFont);
2913 end
2914 else // Растягиваем существующий
2915 if SelectedObjects[GetFirstSelected].ObjectType in [OBJECT_PANEL, OBJECT_TRIGGER] then
2916 begin
2917 if SelectedObjects[GetFirstSelected].ObjectType = OBJECT_PANEL then
2918 begin
2919 Width := gPanels[SelectedObjects[GetFirstSelected].ID].Width;
2920 Height := gPanels[SelectedObjects[GetFirstSelected].ID].Height;
2921 end
2922 else
2923 begin
2924 Width := gTriggers[SelectedObjects[GetFirstSelected].ID].Width;
2925 Height := gTriggers[SelectedObjects[GetFirstSelected].ID].Height;
2926 end;
2928 PrintBlack(MousePos.X+2, MousePos.Y+2, Format(_glc[I_HINT_WIDTH], [Width]),
2929 gEditorFont);
2930 PrintBlack(MousePos.X+2, MousePos.Y+14, Format(_glc[I_HINT_HEIGHT], [Height]),
2931 gEditorFont);
2932 end;
2933 end;
2935 // Ближайшая к курсору мыши точка на сетке:
2936 e_DrawPoint(3, MousePos.X, MousePos.Y, 0, 0, 255);
2938 // Мини-карта:
2939 if ShowMap then
2940 begin
2941 // Сколько пикселов карты в 1 пикселе мини-карты:
2942 ScaleSz := 16 div Scale;
2943 // Размеры мини-карты:
2944 aX := max(gMapInfo.Width div ScaleSz, 1);
2945 aY := max(gMapInfo.Height div ScaleSz, 1);
2946 // X-координата на RenderPanel нулевой x-координаты карты:
2947 XX := RenderPanel.Width - aX - 1;
2948 // Рамка карты:
2949 e_DrawFillQuad(XX-1, 0, RenderPanel.Width-1, aY+1, 0, 0, 0, 0);
2950 e_DrawQuad(XX-1, 0, RenderPanel.Width-1, aY+1, 197, 197, 197);
2952 if gPanels <> nil then
2953 begin
2954 // Рисуем панели:
2955 for a := 0 to High(gPanels) do
2956 with gPanels[a] do
2957 if PanelType <> 0 then
2958 begin
2959 // Левый верхний угол:
2960 aX := XX + (X div ScaleSz);
2961 aY := 1 + (Y div ScaleSz);
2962 // Размеры:
2963 aX2 := max(Width div ScaleSz, 1);
2964 aY2 := max(Height div ScaleSz, 1);
2965 // Правый нижний угол:
2966 aX2 := aX + aX2 - 1;
2967 aY2 := aY + aY2 - 1;
2969 case PanelType of
2970 PANEL_WALL: e_DrawFillQuad(aX, aY, aX2, aY2, 208, 208, 208, 0);
2971 PANEL_WATER: e_DrawFillQuad(aX, aY, aX2, aY2, 0, 0, 192, 0);
2972 PANEL_ACID1: e_DrawFillQuad(aX, aY, aX2, aY2, 0, 176, 0, 0);
2973 PANEL_ACID2: e_DrawFillQuad(aX, aY, aX2, aY2, 176, 0, 0, 0);
2974 PANEL_STEP: e_DrawFillQuad(aX, aY, aX2, aY2, 128, 128, 128, 0);
2975 PANEL_LIFTUP: e_DrawFillQuad(aX, aY, aX2, aY2, 116, 72, 36, 0);
2976 PANEL_LIFTDOWN: e_DrawFillQuad(aX, aY, aX2, aY2, 116, 124, 96, 0);
2977 PANEL_LIFTLEFT: e_DrawFillQuad(aX, aY, aX2, aY2, 200, 80, 4, 0);
2978 PANEL_LIFTRIGHT: e_DrawFillQuad(aX, aY, aX2, aY2, 252, 140, 56, 0);
2979 PANEL_OPENDOOR: e_DrawFillQuad(aX, aY, aX2, aY2, 100, 220, 92, 0);
2980 PANEL_CLOSEDOOR: e_DrawFillQuad(aX, aY, aX2, aY2, 212, 184, 64, 0);
2981 PANEL_BLOCKMON: e_DrawFillQuad(aX, aY, aX2, aY2, 192, 0, 192, 0);
2982 end;
2983 end;
2985 // Рисуем красным выделенные панели:
2986 if SelectedObjects <> nil then
2987 for b := 0 to High(SelectedObjects) do
2988 with SelectedObjects[b] do
2989 if Live and (ObjectType = OBJECT_PANEL) then
2990 with gPanels[SelectedObjects[b].ID] do
2991 if PanelType and not(PANEL_BACK or PANEL_FORE) <> 0 then
2992 begin
2993 // Левый верхний угол:
2994 aX := XX + (X div ScaleSz);
2995 aY := 1 + (Y div ScaleSz);
2996 // Размеры:
2997 aX2 := max(Width div ScaleSz, 1);
2998 aY2 := max(Height div ScaleSz, 1);
2999 // Правый нижний угол:
3000 aX2 := aX + aX2 - 1;
3001 aY2 := aY + aY2 - 1;
3003 e_DrawFillQuad(aX, aY, aX2, aY2, 255, 0, 0, 0)
3004 end;
3005 end;
3007 if (gMapInfo.Width > RenderPanel.Width) or
3008 (gMapInfo.Height > RenderPanel.Height) then
3009 begin
3010 // Окно, показывающее текущее положение экрана на карте:
3011 // Размеры окна:
3012 x := max(min(RenderPanel.Width, gMapInfo.Width) div ScaleSz, 1);
3013 y := max(min(RenderPanel.Height, gMapInfo.Height) div ScaleSz, 1);
3014 // Левый верхний угол:
3015 aX := XX + ((-MapOffset.X) div ScaleSz);
3016 aY := 1 + ((-MapOffset.Y) div ScaleSz);
3017 // Правый нижний угол:
3018 aX2 := aX + x - 1;
3019 aY2 := aY + y - 1;
3021 e_DrawFillQuad(aX, aY, aX2, aY2, 127, 192, 127, 127, B_BLEND);
3022 e_DrawQuad(aX, aY, aX2, aY2, 255, 0, 0);
3023 end;
3024 end; // Мини-карта
3026 e_EndRender();
3027 RenderPanel.SwapBuffers();
3028 end;
3030 procedure TMainForm.FormResize(Sender: TObject);
3031 begin
3032 e_SetViewPort(0, 0, RenderPanel.Width, RenderPanel.Height);
3034 if gMapInfo.Width >= RenderPanel.Width then
3035 sbHorizontal.Max := Normalize16(gMapInfo.Width-RenderPanel.Width+16)
3036 else
3037 sbHorizontal.Max := 0;
3039 if gMapInfo.Height >= RenderPanel.Height then
3040 sbVertical.Max := Normalize16(gMapInfo.Height-RenderPanel.Height+16)
3041 else
3042 sbVertical.Max := 0;
3044 MapOffset.X := -Normalize16(sbHorizontal.Position);
3045 MapOffset.Y := -Normalize16(sbVertical.Position);
3046 end;
3048 procedure SelectNextObject(X, Y: Integer; ObjectType: Byte; ID: DWORD);
3049 var
3050 j, j_max: Integer;
3051 res: Boolean;
3052 begin
3053 j_max := 0; // shut up compiler
3054 case ObjectType of
3055 OBJECT_PANEL:
3056 begin
3057 res := (gPanels <> nil) and
3058 PanelInShownLayer(gPanels[ID].PanelType) and
3059 g_CollidePoint(X, Y, gPanels[ID].X, gPanels[ID].Y,
3060 gPanels[ID].Width,
3061 gPanels[ID].Height);
3062 j_max := Length(gPanels) - 1;
3063 end;
3065 OBJECT_ITEM:
3066 begin
3067 res := (gItems <> nil) and
3068 LayerEnabled[LAYER_ITEMS] and
3069 g_CollidePoint(X, Y, gItems[ID].X, gItems[ID].Y,
3070 ItemSize[gItems[ID].ItemType][0],
3071 ItemSize[gItems[ID].ItemType][1]);
3072 j_max := Length(gItems) - 1;
3073 end;
3075 OBJECT_MONSTER:
3076 begin
3077 res := (gMonsters <> nil) and
3078 LayerEnabled[LAYER_MONSTERS] and
3079 g_CollidePoint(X, Y, gMonsters[ID].X, gMonsters[ID].Y,
3080 MonsterSize[gMonsters[ID].MonsterType].Width,
3081 MonsterSize[gMonsters[ID].MonsterType].Height);
3082 j_max := Length(gMonsters) - 1;
3083 end;
3085 OBJECT_AREA:
3086 begin
3087 res := (gAreas <> nil) and
3088 LayerEnabled[LAYER_AREAS] and
3089 g_CollidePoint(X, Y, gAreas[ID].X, gAreas[ID].Y,
3090 AreaSize[gAreas[ID].AreaType].Width,
3091 AreaSize[gAreas[ID].AreaType].Height);
3092 j_max := Length(gAreas) - 1;
3093 end;
3095 OBJECT_TRIGGER:
3096 begin
3097 res := (gTriggers <> nil) and
3098 LayerEnabled[LAYER_TRIGGERS] and
3099 g_CollidePoint(X, Y, gTriggers[ID].X, gTriggers[ID].Y,
3100 gTriggers[ID].Width,
3101 gTriggers[ID].Height);
3102 j_max := Length(gTriggers) - 1;
3103 end;
3105 else
3106 res := False;
3107 end;
3109 if not res then
3110 Exit;
3112 // Перебор ID: от ID-1 до 0; потом от High до ID+1:
3113 j := ID;
3115 while True do
3116 begin
3117 Dec(j);
3119 if j < 0 then
3120 j := j_max;
3121 if j = Integer(ID) then
3122 Break;
3124 case ObjectType of
3125 OBJECT_PANEL:
3126 res := PanelInShownLayer(gPanels[j].PanelType) and
3127 g_CollidePoint(X, Y, gPanels[j].X, gPanels[j].Y,
3128 gPanels[j].Width,
3129 gPanels[j].Height);
3130 OBJECT_ITEM:
3131 res := (gItems[j].ItemType <> ITEM_NONE) and
3132 g_CollidePoint(X, Y, gItems[j].X, gItems[j].Y,
3133 ItemSize[gItems[j].ItemType][0],
3134 ItemSize[gItems[j].ItemType][1]);
3135 OBJECT_MONSTER:
3136 res := (gMonsters[j].MonsterType <> MONSTER_NONE) and
3137 g_CollidePoint(X, Y, gMonsters[j].X, gMonsters[j].Y,
3138 MonsterSize[gMonsters[j].MonsterType].Width,
3139 MonsterSize[gMonsters[j].MonsterType].Height);
3140 OBJECT_AREA:
3141 res := (gAreas[j].AreaType <> AREA_NONE) and
3142 g_CollidePoint(X, Y, gAreas[j].X, gAreas[j].Y,
3143 AreaSize[gAreas[j].AreaType].Width,
3144 AreaSize[gAreas[j].AreaType].Height);
3145 OBJECT_TRIGGER:
3146 res := (gTriggers[j].TriggerType <> TRIGGER_NONE) and
3147 g_CollidePoint(X, Y, gTriggers[j].X, gTriggers[j].Y,
3148 gTriggers[j].Width,
3149 gTriggers[j].Height);
3150 else
3151 res := False;
3152 end;
3154 if res then
3155 begin
3156 SetLength(SelectedObjects, 1);
3158 SelectedObjects[0].ObjectType := ObjectType;
3159 SelectedObjects[0].ID := j;
3160 SelectedObjects[0].Live := True;
3162 FillProperty();
3163 Break;
3164 end;
3165 end;
3166 end;
3168 procedure TMainForm.RenderPanelMouseDown(Sender: TObject;
3169 Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
3170 var
3171 i: Integer;
3172 Rect: TRectWH;
3173 c1, c2, c3, c4: Boolean;
3174 item: TItem;
3175 area: TArea;
3176 monster: TMonster;
3177 IDArray: DWArray;
3178 begin
3179 MainForm.ActiveControl := RenderPanel;
3180 RenderPanel.SetFocus();
3182 RenderPanelMouseMove(RenderPanel, Shift, X, Y);
3184 if Button = mbLeft then // Left Mouse Button
3185 begin
3186 // Двигаем карту с помощью мыши и мини-карты:
3187 if ShowMap and
3188 g_CollidePoint(X, Y,
3189 RenderPanel.Width-max(gMapInfo.Width div (16 div Scale), 1)-1,
3190 1,
3191 max(gMapInfo.Width div (16 div Scale), 1),
3192 max(gMapInfo.Height div (16 div Scale), 1) ) then
3193 begin
3194 MoveMap(X, Y);
3195 MouseAction := MOUSEACTION_MOVEMAP;
3196 end
3197 else // Ставим предмет/монстра/область:
3198 if (pcObjects.ActivePageIndex in [1, 2, 3]) and
3199 (not (ssShift in Shift)) then
3200 begin
3201 case pcObjects.ActivePageIndex of
3202 1:
3203 if lbItemList.ItemIndex = -1 then
3204 ErrorMessageBox(_lc[I_MSG_CHOOSE_ITEM])
3205 else
3206 begin
3207 item.ItemType := lbItemList.ItemIndex + ITEM_MEDKIT_SMALL;
3208 if item.ItemType >= ITEM_WEAPON_KASTET then
3209 item.ItemType := item.ItemType + 2;
3210 item.X := MousePos.X-MapOffset.X;
3211 item.Y := MousePos.Y-MapOffset.Y;
3213 if not (ssCtrl in Shift) then
3214 begin
3215 item.X := item.X - (ItemSize[item.ItemType][0] div 2);
3216 item.Y := item.Y - ItemSize[item.ItemType][1];
3217 end;
3219 item.OnlyDM := cbOnlyDM.Checked;
3220 item.Fall := cbFall.Checked;
3221 Undo_Add(OBJECT_ITEM, AddItem(item));
3222 end;
3223 2:
3224 if lbMonsterList.ItemIndex = -1 then
3225 ErrorMessageBox(_lc[I_MSG_CHOOSE_MONSTER])
3226 else
3227 begin
3228 monster.MonsterType := lbMonsterList.ItemIndex + MONSTER_DEMON;
3229 monster.X := MousePos.X-MapOffset.X;
3230 monster.Y := MousePos.Y-MapOffset.Y;
3232 if not (ssCtrl in Shift) then
3233 begin
3234 monster.X := monster.X - (MonsterSize[monster.MonsterType].Width div 2);
3235 monster.Y := monster.Y - MonsterSize[monster.MonsterType].Height;
3236 end;
3238 if rbMonsterLeft.Checked then
3239 monster.Direction := D_LEFT
3240 else
3241 monster.Direction := D_RIGHT;
3242 Undo_Add(OBJECT_MONSTER, AddMonster(monster));
3243 end;
3244 3:
3245 if lbAreasList.ItemIndex = -1 then
3246 ErrorMessageBox(_lc[I_MSG_CHOOSE_AREA])
3247 else
3248 if (lbAreasList.ItemIndex + 1) <> AREA_DOMFLAG then
3249 begin
3250 area.AreaType := lbAreasList.ItemIndex + AREA_PLAYERPOINT1;
3251 area.X := MousePos.X-MapOffset.X;
3252 area.Y := MousePos.Y-MapOffset.Y;
3254 if not (ssCtrl in Shift) then
3255 begin
3256 area.X := area.X - (AreaSize[area.AreaType].Width div 2);
3257 area.Y := area.Y - AreaSize[area.AreaType].Height;
3258 end;
3260 if rbAreaLeft.Checked then
3261 area.Direction := D_LEFT
3262 else
3263 area.Direction := D_RIGHT;
3264 Undo_Add(OBJECT_AREA, AddArea(area));
3265 end;
3266 end;
3267 end
3268 else
3269 begin
3270 i := GetFirstSelected();
3272 // Выбираем объект под текущим:
3273 if (SelectedObjects <> nil) and
3274 (ssShift in Shift) and (i >= 0) and
3275 (SelectedObjects[i].Live) then
3276 begin
3277 if SelectedObjectCount() = 1 then
3278 SelectNextObject(X-MapOffset.X, Y-MapOffset.Y,
3279 SelectedObjects[i].ObjectType,
3280 SelectedObjects[i].ID);
3281 end
3282 else
3283 begin
3284 // Рисуем область триггера "Расширитель":
3285 if DrawPressRect and (i >= 0) and
3286 (SelectedObjects[i].ObjectType = OBJECT_TRIGGER) and
3287 (gTriggers[SelectedObjects[i].ID].TriggerType in
3288 [TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF]) then
3289 MouseAction := MOUSEACTION_DRAWPRESS
3290 else // Рисуем панель:
3291 if pcObjects.ActivePageIndex = 0 then
3292 begin
3293 if (lbPanelType.ItemIndex >= 0) then
3294 MouseAction := MOUSEACTION_DRAWPANEL
3295 end
3296 else // Рисуем триггер:
3297 if (lbTriggersList.ItemIndex >= 0) then
3298 begin
3299 MouseAction := MOUSEACTION_DRAWTRIGGER;
3300 end;
3301 end;
3302 end;
3303 end; // if Button = mbLeft
3305 if Button = mbRight then // Right Mouse Button
3306 begin
3307 // Клик по мини-карте:
3308 if ShowMap and
3309 g_CollidePoint(X, Y,
3310 RenderPanel.Width-max(gMapInfo.Width div (16 div Scale), 1)-1,
3311 1,
3312 max(gMapInfo.Width div (16 div Scale), 1),
3313 max(gMapInfo.Height div (16 div Scale), 1) ) then
3314 begin
3315 MouseAction := MOUSEACTION_NOACTION;
3316 end
3317 else // Нужно что-то выбрать мышью:
3318 if SelectFlag <> SELECTFLAG_NONE then
3319 begin
3320 case SelectFlag of
3321 SELECTFLAG_TELEPORT:
3322 // Точку назначения телепортации:
3323 with gTriggers[SelectedObjects[
3324 GetFirstSelected() ].ID].Data.TargetPoint do
3325 begin
3326 X := MousePos.X-MapOffset.X;
3327 Y := MousePos.Y-MapOffset.Y;
3328 end;
3330 SELECTFLAG_SPAWNPOINT:
3331 // Точку создания монстра:
3332 with gTriggers[SelectedObjects[GetFirstSelected()].ID] do
3333 if TriggerType = TRIGGER_SPAWNMONSTER then
3334 begin
3335 Data.MonPos.X := MousePos.X-MapOffset.X;
3336 Data.MonPos.Y := MousePos.Y-MapOffset.Y;
3337 end
3338 else if TriggerType = TRIGGER_SPAWNITEM then
3339 begin // Точка создания предмета:
3340 Data.ItemPos.X := MousePos.X-MapOffset.X;
3341 Data.ItemPos.Y := MousePos.Y-MapOffset.Y;
3342 end
3343 else if TriggerType = TRIGGER_SHOT then
3344 begin // Точка создания выстрела:
3345 Data.ShotPos.X := MousePos.X-MapOffset.X;
3346 Data.ShotPos.Y := MousePos.Y-MapOffset.Y;
3347 end;
3349 SELECTFLAG_DOOR:
3350 // Дверь:
3351 begin
3352 IDArray := ObjectInRect(X-MapOffset.X,
3353 Y-MapOffset.Y,
3354 2, 2, OBJECT_PANEL, True);
3355 if IDArray <> nil then
3356 begin
3357 for i := 0 to High(IDArray) do
3358 if (gPanels[IDArray[i]].PanelType = PANEL_OPENDOOR) or
3359 (gPanels[IDArray[i]].PanelType = PANEL_CLOSEDOOR) then
3360 begin
3361 gTriggers[SelectedObjects[
3362 GetFirstSelected() ].ID].Data.PanelID := IDArray[i];
3363 Break;
3364 end;
3365 end
3366 else
3367 gTriggers[SelectedObjects[
3368 GetFirstSelected() ].ID].Data.PanelID := -1;
3369 end;
3371 SELECTFLAG_TEXTURE:
3372 // Панель с текстурой:
3373 begin
3374 IDArray := ObjectInRect(X-MapOffset.X,
3375 Y-MapOffset.Y,
3376 2, 2, OBJECT_PANEL, True);
3377 if IDArray <> nil then
3378 begin
3379 for i := 0 to High(IDArray) do
3380 if ((gPanels[IDArray[i]].PanelType in
3381 [PANEL_WALL, PANEL_BACK, PANEL_FORE,
3382 PANEL_WATER, PANEL_ACID1, PANEL_ACID2,
3383 PANEL_STEP]) or
3384 (gPanels[IDArray[i]].PanelType = PANEL_OPENDOOR) or
3385 (gPanels[IDArray[i]].PanelType = PANEL_CLOSEDOOR)) and
3386 (gPanels[IDArray[i]].TextureName <> '') then
3387 begin
3388 gTriggers[SelectedObjects[
3389 GetFirstSelected() ].ID].TexturePanel := IDArray[i];
3390 Break;
3391 end;
3392 end
3393 else
3394 gTriggers[SelectedObjects[
3395 GetFirstSelected() ].ID].TexturePanel := -1;
3396 end;
3398 SELECTFLAG_LIFT:
3399 // Лифт:
3400 begin
3401 IDArray := ObjectInRect(X-MapOffset.X,
3402 Y-MapOffset.Y,
3403 2, 2, OBJECT_PANEL, True);
3404 if IDArray <> nil then
3405 begin
3406 for i := 0 to High(IDArray) do
3407 if (gPanels[IDArray[i]].PanelType = PANEL_LIFTUP) or
3408 (gPanels[IDArray[i]].PanelType = PANEL_LIFTDOWN) or
3409 (gPanels[IDArray[i]].PanelType = PANEL_LIFTLEFT) or
3410 (gPanels[IDArray[i]].PanelType = PANEL_LIFTRIGHT) then
3411 begin
3412 gTriggers[SelectedObjects[
3413 GetFirstSelected() ].ID].Data.PanelID := IDArray[i];
3414 Break;
3415 end;
3416 end
3417 else
3418 gTriggers[SelectedObjects[
3419 GetFirstSelected() ].ID].Data.PanelID := -1;
3420 end;
3422 SELECTFLAG_MONSTER:
3423 // Монстра:
3424 begin
3425 IDArray := ObjectInRect(X-MapOffset.X,
3426 Y-MapOffset.Y,
3427 2, 2, OBJECT_MONSTER, False);
3428 if IDArray <> nil then
3429 gTriggers[SelectedObjects[
3430 GetFirstSelected() ].ID].Data.MonsterID := IDArray[0]+1
3431 else
3432 gTriggers[SelectedObjects[
3433 GetFirstSelected() ].ID].Data.MonsterID := 0;
3434 end;
3436 SELECTFLAG_SHOTPANEL:
3437 // Панель индикации выстрела:
3438 begin
3439 if gTriggers[SelectedObjects[
3440 GetFirstSelected() ].ID].TriggerType = TRIGGER_SHOT then
3441 begin
3442 IDArray := ObjectInRect(X-MapOffset.X,
3443 Y-MapOffset.Y,
3444 2, 2, OBJECT_PANEL, True);
3445 if IDArray <> nil then
3446 begin
3447 for i := 0 to High(IDArray) do
3448 if ((gPanels[IDArray[i]].PanelType in
3449 [PANEL_WALL, PANEL_BACK, PANEL_FORE,
3450 PANEL_WATER, PANEL_ACID1, PANEL_ACID2,
3451 PANEL_STEP]) or
3452 (gPanels[IDArray[i]].PanelType = PANEL_OPENDOOR) or
3453 (gPanels[IDArray[i]].PanelType = PANEL_CLOSEDOOR)) and
3454 (gPanels[IDArray[i]].TextureName <> '') then
3455 begin
3456 gTriggers[SelectedObjects[
3457 GetFirstSelected() ].ID].Data.ShotPanelID := IDArray[i];
3458 Break;
3459 end;
3460 end
3461 else
3462 gTriggers[SelectedObjects[
3463 GetFirstSelected() ].ID].Data.ShotPanelID := -1;
3464 end;
3465 end;
3466 end;
3468 SelectFlag := SELECTFLAG_SELECTED;
3469 end
3470 else // if SelectFlag <> SELECTFLAG_NONE...
3471 begin
3472 // Что уже выбрано и не нажат Ctrl:
3473 if (SelectedObjects <> nil) and
3474 (not (ssCtrl in Shift)) then
3475 for i := 0 to High(SelectedObjects) do
3476 with SelectedObjects[i] do
3477 if Live then
3478 begin
3479 if (ObjectType in [OBJECT_PANEL, OBJECT_TRIGGER]) and
3480 (SelectedObjectCount() = 1) then
3481 begin
3482 Rect := ObjectGetRect(ObjectType, ID);
3484 c1 := g_Collide(X-MapOffset.X-1, Y-MapOffset.Y-1, 2, 2,
3485 Rect.X-2, Rect.Y+(Rect.Height div 2)-2, 4, 4);
3486 c2 := g_Collide(X-MapOffset.X-1, Y-MapOffset.Y-1, 2, 2,
3487 Rect.X+Rect.Width-3, Rect.Y+(Rect.Height div 2)-2, 4, 4);
3488 c3 := g_Collide(X-MapOffset.X-1, Y-MapOffset.Y-1, 2, 2,
3489 Rect.X+(Rect.Width div 2)-2, Rect.Y-2, 4, 4);
3490 c4 := g_Collide(X-MapOffset.X-1, Y-MapOffset.Y-1, 2, 2,
3491 Rect.X+(Rect.Width div 2)-2, Rect.Y+Rect.Height-3, 4, 4);
3493 // Меняем размер панели или триггера:
3494 if c1 or c2 or c3 or c4 then
3495 begin
3496 MouseAction := MOUSEACTION_RESIZE;
3497 LastMovePoint := MousePos;
3499 if c1 or c2 then
3500 begin // Шире/уже
3501 ResizeType := RESIZETYPE_HORIZONTAL;
3502 if c1 then
3503 ResizeDirection := RESIZEDIR_LEFT
3504 else
3505 ResizeDirection := RESIZEDIR_RIGHT;
3506 RenderPanel.Cursor := crSizeWE;
3507 end
3508 else
3509 begin // Выше/ниже
3510 ResizeType := RESIZETYPE_VERTICAL;
3511 if c3 then
3512 ResizeDirection := RESIZEDIR_UP
3513 else
3514 ResizeDirection := RESIZEDIR_DOWN;
3515 RenderPanel.Cursor := crSizeNS;
3516 end;
3518 Break;
3519 end;
3520 end;
3522 // Перемещаем панель или триггер:
3523 if ObjectCollide(ObjectType, ID,
3524 X-MapOffset.X-1,
3525 Y-MapOffset.Y-1, 2, 2) then
3526 begin
3527 MouseAction := MOUSEACTION_MOVEOBJ;
3528 LastMovePoint := MousePos;
3530 Break;
3531 end;
3532 end;
3533 end;
3534 end; // if Button = mbRight
3536 MouseRDown := Button = mbRight;
3537 if MouseRDown then
3538 MouseRDownPos := MousePos;
3540 MouseLDown := Button = mbLeft;
3541 if MouseLDown then
3542 MouseLDownPos := MousePos;
3543 end;
3545 procedure TMainForm.RenderPanelMouseUp(Sender: TObject;
3546 Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
3547 var
3548 panel: TPanel;
3549 trigger: TTrigger;
3550 i: Integer;
3551 IDArray: DWArray;
3552 rRect: TRectWH;
3553 rSelectRect: Boolean;
3554 begin
3555 if Button = mbLeft then
3556 MouseLDown := False;
3557 if Button = mbRight then
3558 MouseRDown := False;
3560 DrawRect := nil;
3561 ResizeType := RESIZETYPE_NONE;
3563 if Button = mbLeft then // Left Mouse Button
3564 begin
3565 if MouseAction <> MOUSEACTION_NONE then
3566 begin // Было действие мышью
3567 // Мышь сдвинулась во время удержания клавиши:
3568 if (MousePos.X <> MouseLDownPos.X) and
3569 (MousePos.Y <> MouseLDownPos.Y) then
3570 case MouseAction of
3571 // Рисовали панель:
3572 MOUSEACTION_DRAWPANEL:
3573 begin
3574 // Фон или передний план без текстуры - ошибка:
3575 if (lbPanelType.ItemIndex in [1, 2]) and
3576 (lbTextureList.ItemIndex = -1) then
3577 ErrorMessageBox(_lc[I_MSG_CHOOSE_TEXTURE])
3578 else // Назначаем параметры панели:
3579 begin
3580 case lbPanelType.ItemIndex of
3581 0: Panel.PanelType := PANEL_WALL;
3582 1: Panel.PanelType := PANEL_BACK;
3583 2: Panel.PanelType := PANEL_FORE;
3584 3: Panel.PanelType := PANEL_OPENDOOR;
3585 4: Panel.PanelType := PANEL_CLOSEDOOR;
3586 5: Panel.PanelType := PANEL_STEP;
3587 6: Panel.PanelType := PANEL_WATER;
3588 7: Panel.PanelType := PANEL_ACID1;
3589 8: Panel.PanelType := PANEL_ACID2;
3590 9: Panel.PanelType := PANEL_LIFTUP;
3591 10: Panel.PanelType := PANEL_LIFTDOWN;
3592 11: Panel.PanelType := PANEL_LIFTLEFT;
3593 12: Panel.PanelType := PANEL_LIFTRIGHT;
3594 13: Panel.PanelType := PANEL_BLOCKMON;
3595 end;
3597 Panel.X := Min(MousePos.X-MapOffset.X, MouseLDownPos.X-MapOffset.X);
3598 Panel.Y := Min(MousePos.Y-MapOffset.Y, MouseLDownPos.Y-MapOffset.Y);
3599 Panel.Width := Abs(MousePos.X-MouseLDownPos.X);
3600 Panel.Height := Abs(MousePos.Y-MouseLDownPos.Y);
3602 // Лифты, блокМон или отсутствие текстуры - пустая текстура:
3603 if (lbPanelType.ItemIndex in [9, 10, 11, 12, 13]) or
3604 (lbTextureList.ItemIndex = -1) then
3605 begin
3606 Panel.TextureHeight := 1;
3607 Panel.TextureWidth := 1;
3608 Panel.TextureName := '';
3609 Panel.TextureID := TEXTURE_SPECIAL_NONE;
3610 end
3611 else // Есть текстура:
3612 begin
3613 Panel.TextureName := SelectedTexture();
3615 // Обычная текстура:
3616 if not IsSpecialTextureSel() then
3617 begin
3618 g_GetTextureSizeByName(Panel.TextureName,
3619 Panel.TextureWidth, Panel.TextureHeight);
3620 g_GetTexture(Panel.TextureName, Panel.TextureID);
3621 end
3622 else // Спец.текстура:
3623 begin
3624 Panel.TextureHeight := 1;
3625 Panel.TextureWidth := 1;
3626 Panel.TextureID := SpecialTextureID(SelectedTexture());
3627 end;
3628 end;
3630 Panel.Alpha := 0;
3631 Panel.Blending := False;
3633 Undo_Add(OBJECT_PANEL, AddPanel(Panel));
3634 end;
3635 end;
3637 // Рисовали триггер:
3638 MOUSEACTION_DRAWTRIGGER:
3639 begin
3640 trigger.X := Min(MousePos.X-MapOffset.X, MouseLDownPos.X-MapOffset.X);
3641 trigger.Y := Min(MousePos.Y-MapOffset.Y, MouseLDownPos.Y-MapOffset.Y);
3642 trigger.Width := Abs(MousePos.X-MouseLDownPos.X);
3643 trigger.Height := Abs(MousePos.Y-MouseLDownPos.Y);
3645 trigger.Enabled := True;
3646 trigger.TriggerType := lbTriggersList.ItemIndex+1;
3647 trigger.TexturePanel := -1;
3649 // Типы активации:
3650 trigger.ActivateType := 0;
3652 if clbActivationType.Checked[0] then
3653 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_PLAYERCOLLIDE;
3654 if clbActivationType.Checked[1] then
3655 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_MONSTERCOLLIDE;
3656 if clbActivationType.Checked[2] then
3657 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_PLAYERPRESS;
3658 if clbActivationType.Checked[3] then
3659 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_MONSTERPRESS;
3660 if clbActivationType.Checked[4] then
3661 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_SHOT;
3662 if clbActivationType.Checked[5] then
3663 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_NOMONSTER;
3665 // Необходимые для активации ключи:
3666 trigger.Key := 0;
3668 if clbKeys.Checked[0] then
3669 trigger.Key := Trigger.Key or KEY_RED;
3670 if clbKeys.Checked[1] then
3671 trigger.Key := Trigger.Key or KEY_GREEN;
3672 if clbKeys.Checked[2] then
3673 trigger.Key := Trigger.Key or KEY_BLUE;
3674 if clbKeys.Checked[3] then
3675 trigger.Key := Trigger.Key or KEY_REDTEAM;
3676 if clbKeys.Checked[4] then
3677 trigger.Key := Trigger.Key or KEY_BLUETEAM;
3679 // Параметры триггера:
3680 FillByte(trigger.Data.Default[0], 128, 0);
3682 case trigger.TriggerType of
3683 // Переключаемая панель:
3684 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
3685 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP,
3686 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
3687 begin
3688 Trigger.Data.PanelID := -1;
3689 end;
3691 // Телепортация:
3692 TRIGGER_TELEPORT:
3693 begin
3694 trigger.Data.TargetPoint.X := trigger.X-64;
3695 trigger.Data.TargetPoint.Y := trigger.Y-64;
3696 trigger.Data.d2d_teleport := True;
3697 trigger.Data.TlpDir := 0;
3698 end;
3700 // Изменение других триггеров:
3701 TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF,
3702 TRIGGER_ONOFF:
3703 begin
3704 trigger.Data.Count := 1;
3705 end;
3707 // Звук:
3708 TRIGGER_SOUND:
3709 begin
3710 trigger.Data.Volume := 255;
3711 trigger.Data.Pan := 127;
3712 trigger.Data.PlayCount := 1;
3713 trigger.Data.Local := True;
3714 trigger.Data.SoundSwitch := False;
3715 end;
3717 // Музыка:
3718 TRIGGER_MUSIC:
3719 begin
3720 trigger.Data.MusicAction := 1;
3721 end;
3723 // Создание монстра:
3724 TRIGGER_SPAWNMONSTER:
3725 begin
3726 trigger.Data.MonType := MONSTER_ZOMBY;
3727 trigger.Data.MonPos.X := trigger.X-64;
3728 trigger.Data.MonPos.Y := trigger.Y-64;
3729 trigger.Data.MonHealth := 0;
3730 trigger.Data.MonActive := False;
3731 trigger.Data.MonCount := 1;
3732 end;
3734 // Создание предмета:
3735 TRIGGER_SPAWNITEM:
3736 begin
3737 trigger.Data.ItemType := ITEM_AMMO_BULLETS;
3738 trigger.Data.ItemPos.X := trigger.X-64;
3739 trigger.Data.ItemPos.Y := trigger.Y-64;
3740 trigger.Data.ItemOnlyDM := False;
3741 trigger.Data.ItemFalls := False;
3742 trigger.Data.ItemCount := 1;
3743 trigger.Data.ItemMax := 0;
3744 trigger.Data.ItemDelay := 0;
3745 end;
3747 // Ускорение:
3748 TRIGGER_PUSH:
3749 begin
3750 trigger.Data.PushAngle := 90;
3751 trigger.Data.PushForce := 10;
3752 trigger.Data.ResetVel := True;
3753 end;
3755 TRIGGER_SCORE:
3756 begin
3757 trigger.Data.ScoreCount := 1;
3758 trigger.Data.ScoreCon := True;
3759 trigger.Data.ScoreMsg := True;
3760 end;
3762 TRIGGER_MESSAGE:
3763 begin
3764 trigger.Data.MessageKind := 0;
3765 trigger.Data.MessageSendTo := 0;
3766 trigger.Data.MessageText := '';
3767 trigger.Data.MessageTime := 144;
3768 end;
3770 TRIGGER_DAMAGE:
3771 begin
3772 trigger.Data.DamageValue := 5;
3773 trigger.Data.DamageInterval := 12;
3774 end;
3776 TRIGGER_HEALTH:
3777 begin
3778 trigger.Data.HealValue := 5;
3779 trigger.Data.HealInterval := 36;
3780 end;
3782 TRIGGER_SHOT:
3783 begin
3784 trigger.Data.ShotType := TRIGGER_SHOT_BULLET;
3785 trigger.Data.ShotSound := True;
3786 trigger.Data.ShotPanelID := -1;
3787 trigger.Data.ShotTarget := 0;
3788 trigger.Data.ShotIntSight := 0;
3789 trigger.Data.ShotAim := TRIGGER_SHOT_AIM_DEFAULT;
3790 trigger.Data.ShotPos.X := trigger.X-64;
3791 trigger.Data.ShotPos.Y := trigger.Y-64;
3792 trigger.Data.ShotAngle := 0;
3793 trigger.Data.ShotWait := 18;
3794 trigger.Data.ShotAccuracy := 0;
3795 trigger.Data.ShotAmmo := 0;
3796 trigger.Data.ShotIntReload := 0;
3797 end;
3799 TRIGGER_EFFECT:
3800 begin
3801 trigger.Data.FXCount := 1;
3802 trigger.Data.FXType := TRIGGER_EFFECT_PARTICLE;
3803 trigger.Data.FXSubType := TRIGGER_EFFECT_SLIQUID;
3804 trigger.Data.FXColorR := 0;
3805 trigger.Data.FXColorG := 0;
3806 trigger.Data.FXColorB := 255;
3807 trigger.Data.FXPos := TRIGGER_EFFECT_POS_CENTER;
3808 trigger.Data.FXWait := 1;
3809 trigger.Data.FXVelX := 0;
3810 trigger.Data.FXVelY := -20;
3811 trigger.Data.FXSpreadL := 5;
3812 trigger.Data.FXSpreadR := 5;
3813 trigger.Data.FXSpreadU := 4;
3814 trigger.Data.FXSpreadD := 0;
3815 end;
3816 end;
3818 Undo_Add(OBJECT_TRIGGER, AddTrigger(trigger));
3819 end;
3821 // Рисовали область триггера "Расширитель":
3822 MOUSEACTION_DRAWPRESS:
3823 with gTriggers[SelectedObjects[GetFirstSelected].ID] do
3824 begin
3825 Data.tX := Min(MousePos.X-MapOffset.X, MouseLDownPos.X-MapOffset.X);
3826 Data.tY := Min(MousePos.Y-MapOffset.Y, MouseLDownPos.Y-MapOffset.Y);
3827 Data.tWidth := Abs(MousePos.X-MouseLDownPos.X);
3828 Data.tHeight := Abs(MousePos.Y-MouseLDownPos.Y);
3830 DrawPressRect := False;
3831 end;
3832 end;
3834 MouseAction := MOUSEACTION_NONE;
3835 end;
3836 end // if Button = mbLeft...
3837 else // Right Mouse Button:
3838 begin
3839 if MouseAction = MOUSEACTION_NOACTION then
3840 begin
3841 MouseAction := MOUSEACTION_NONE;
3842 Exit;
3843 end;
3845 // Объект передвинут или изменен в размере:
3846 if MouseAction in [MOUSEACTION_MOVEOBJ, MOUSEACTION_RESIZE] then
3847 begin
3848 MouseAction := MOUSEACTION_NONE;
3849 FillProperty();
3850 Exit;
3851 end;
3853 // Еще не все выбрали:
3854 if SelectFlag <> SELECTFLAG_NONE then
3855 begin
3856 if SelectFlag = SELECTFLAG_SELECTED then
3857 SelectFlag := SELECTFLAG_NONE;
3858 FillProperty();
3859 Exit;
3860 end;
3862 // Мышь сдвинулась во время удержания клавиши:
3863 if (MousePos.X <> MouseRDownPos.X) and
3864 (MousePos.Y <> MouseRDownPos.Y) then
3865 begin
3866 rSelectRect := True;
3868 rRect.X := Min(MousePos.X, MouseRDownPos.X)-MapOffset.X;
3869 rRect.Y := Min(MousePos.Y, MouseRDownPos.Y)-MapOffset.Y;
3870 rRect.Width := Abs(MousePos.X-MouseRDownPos.X);
3871 rRect.Height := Abs(MousePos.Y-MouseRDownPos.Y);
3872 end
3873 else // Мышь не сдвинулась - нет прямоугольника:
3874 begin
3875 rSelectRect := False;
3877 rRect.X := X-MapOffset.X-1;
3878 rRect.Y := Y-MapOffset.Y-1;
3879 rRect.Width := 2;
3880 rRect.Height := 2;
3881 end;
3883 // Если зажат Ctrl - выделять еще, иначе только один выделенный объект:
3884 if not (ssCtrl in Shift) then
3885 RemoveSelectFromObjects();
3887 // Выделяем всё в выбранном прямоугольнике:
3888 IDArray := ObjectInRect(rRect.X, rRect.Y,
3889 rRect.Width, rRect.Height,
3890 pcObjects.ActivePageIndex+1, rSelectRect);
3892 if IDArray <> nil then
3893 for i := 0 to High(IDArray) do
3894 SelectObject(pcObjects.ActivePageIndex+1, IDArray[i],
3895 (ssCtrl in Shift) or rSelectRect);
3897 FillProperty();
3898 end;
3899 end;
3901 procedure TMainForm.RenderPanelPaint(Sender: TObject);
3902 begin
3903 Draw();
3904 end;
3906 procedure TMainForm.RenderPanelMouseMove(Sender: TObject;
3907 Shift: TShiftState; X, Y: Integer);
3908 var
3909 sX, sY: Integer;
3910 dWidth, dHeight: Integer;
3911 _id: Integer;
3912 begin
3913 _id := GetFirstSelected();
3915 // Рисуем панель с текстурой, сетка - размеры текстуры:
3916 if (MouseAction = MOUSEACTION_DRAWPANEL) and
3917 (lbPanelType.ItemIndex in [0..8]) and
3918 (lbTextureList.ItemIndex <> -1) and
3919 (not IsSpecialTextureSel()) then
3920 begin
3921 sX := StrToIntDef(lTextureWidth.Caption, DotStep);
3922 sY := StrToIntDef(lTextureHeight.Caption, DotStep);
3923 end
3924 else
3925 // Меняем размер панели с текстурой, сетка - размеры текстуры:
3926 if (MouseAction = MOUSEACTION_RESIZE) and
3927 ( (SelectedObjects[_id].ObjectType = OBJECT_PANEL) and
3928 IsTexturedPanel(gPanels[SelectedObjects[_id].ID].PanelType) and
3929 (gPanels[SelectedObjects[_id].ID].TextureName <> '') and
3930 (not IsSpecialTexture(gPanels[SelectedObjects[_id].ID].TextureName)) ) then
3931 begin
3932 sX := gPanels[SelectedObjects[_id].ID].TextureWidth;
3933 sY := gPanels[SelectedObjects[_id].ID].TextureHeight;
3934 end
3935 else
3936 // Выравнивание по сетке:
3937 if SnapToGrid then
3938 begin
3939 sX := DotStep;
3940 sY := DotStep;
3941 end
3942 else // Нет выравнивания по сетке:
3943 begin
3944 sX := 1;
3945 sY := 1;
3946 end;
3948 // Новая позиция мыши:
3949 if MouseLDown then
3950 begin // Зажата левая кнопка мыши
3951 MousePos.X := (Round((X-MouseLDownPos.X)/sX)*sX)+MouseLDownPos.X;
3952 MousePos.Y := (Round((Y-MouseLDownPos.Y)/sY)*sY)+MouseLDownPos.Y;
3953 end
3954 else
3955 if MouseRDown then
3956 begin // Зажата правая кнопка мыши
3957 MousePos.X := (Round((X-MouseRDownPos.X)/sX)*sX)+MouseRDownPos.X;
3958 MousePos.Y := (Round((Y-MouseRDownPos.Y)/sY)*sY)+MouseRDownPos.Y;
3959 end
3960 else
3961 begin // Кнопки мыши не зажаты
3962 MousePos.X := (Round(X/sX)*sX);
3963 MousePos.Y := (Round(Y/sY)*sY);
3964 end;
3966 // Изменение размера закончилось - ставим обычный курсор:
3967 if ResizeType = RESIZETYPE_NONE then
3968 RenderPanel.Cursor := crDefault;
3970 // Зажата только правая кнопка мыши:
3971 if (not MouseLDown) and (MouseRDown) then
3972 begin
3973 // Рисуем прямоугольник выделения:
3974 if MouseAction = MOUSEACTION_NONE then
3975 begin
3976 if DrawRect = nil then
3977 New(DrawRect);
3978 DrawRect.Top := MouseRDownPos.y;
3979 DrawRect.Left := MouseRDownPos.x;
3980 DrawRect.Bottom := MousePos.y;
3981 DrawRect.Right := MousePos.x;
3982 end
3983 else
3984 // Двигаем выделенные объекты:
3985 if MouseAction = MOUSEACTION_MOVEOBJ then
3986 begin
3987 MoveSelectedObjects(ssShift in Shift, ssCtrl in Shift,
3988 MousePos.X-LastMovePoint.X+WASDOffset.X,
3989 MousePos.Y-LastMovePoint.Y+WASDOffset.Y);
3990 WASDOffset.X := 0;
3991 WASDOffset.Y := 0;
3992 end
3993 else
3994 // Меняем размер выделенного объекта:
3995 if MouseAction = MOUSEACTION_RESIZE then
3996 begin
3997 if (SelectedObjectCount = 1) and
3998 (SelectedObjects[GetFirstSelected].Live) then
3999 begin
4000 dWidth := MousePos.X-LastMovePoint.X+WASDOffset.X;
4001 dHeight := MousePos.Y-LastMovePoint.Y+WASDOffset.Y;
4002 WASDOffset.X := 0;
4003 WASDOffset.Y := 0;
4005 case ResizeType of
4006 RESIZETYPE_VERTICAL: dWidth := 0;
4007 RESIZETYPE_HORIZONTAL: dHeight := 0;
4008 end;
4010 case ResizeDirection of
4011 RESIZEDIR_UP: dHeight := -dHeight;
4012 RESIZEDIR_LEFT: dWidth := -dWidth;
4013 end;
4015 ResizeObject(SelectedObjects[GetFirstSelected].ObjectType,
4016 SelectedObjects[GetFirstSelected].ID,
4017 dWidth, dHeight, ResizeDirection);
4019 LastMovePoint := MousePos;
4020 end;
4021 end;
4022 end;
4024 // Зажата только левая кнопка мыши:
4025 if (not MouseRDown) and (MouseLDown) then
4026 begin
4027 // Рисуем прямоугольник планирования панели:
4028 if MouseAction in [MOUSEACTION_DRAWPANEL,
4029 MOUSEACTION_DRAWTRIGGER,
4030 MOUSEACTION_DRAWPRESS] then
4031 begin
4032 if DrawRect = nil then
4033 New(DrawRect);
4034 DrawRect.Top := MouseLDownPos.y;
4035 DrawRect.Left := MouseLDownPos.x;
4036 DrawRect.Bottom := MousePos.y;
4037 DrawRect.Right := MousePos.x;
4038 end
4039 else // Двигаем карту:
4040 if MouseAction = MOUSEACTION_MOVEMAP then
4041 begin
4042 MoveMap(X, Y);
4043 end;
4044 end;
4046 // Клавиши мыши не зажаты:
4047 if (not MouseRDown) and (not MouseLDown) then
4048 DrawRect := nil;
4050 // Строка состояния - координаты мыши:
4051 StatusBar.Panels[1].Text := Format('(%d:%d)',
4052 [MousePos.X-MapOffset.X, MousePos.Y-MapOffset.Y]);
4053 end;
4055 procedure TMainForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
4056 begin
4057 CanClose := MessageBox(0, PChar(_lc[I_MSG_EXIT_PROMT]),
4058 PChar(_lc[I_MSG_EXIT]),
4059 MB_ICONQUESTION or MB_YESNO or
4060 MB_DEFBUTTON1) = idYes;
4061 end;
4063 procedure TMainForm.aExitExecute(Sender: TObject);
4064 begin
4065 Close();
4066 end;
4068 procedure TMainForm.FormDestroy(Sender: TObject);
4069 var
4070 config: TConfig;
4071 i: Integer;
4072 begin
4073 config := TConfig.CreateFile(EditorDir+'Editor.cfg');
4075 if WindowState <> wsMaximized then
4076 begin
4077 config.WriteInt('Editor', 'XPos', Left);
4078 config.WriteInt('Editor', 'YPos', Top);
4079 config.WriteInt('Editor', 'Width', Width);
4080 config.WriteInt('Editor', 'Height', Height);
4081 end
4082 else
4083 begin
4084 config.WriteInt('Editor', 'XPos', RestoredLeft);
4085 config.WriteInt('Editor', 'YPos', RestoredTop);
4086 config.WriteInt('Editor', 'Width', RestoredWidth);
4087 config.WriteInt('Editor', 'Height', RestoredHeight);
4088 end;
4089 config.WriteBool('Editor', 'Maximize', WindowState = wsMaximized);
4090 config.WriteBool('Editor', 'Minimap', ShowMap);
4091 config.WriteInt('Editor', 'PanelProps', PanelProps.ClientWidth);
4092 config.WriteInt('Editor', 'PanelObjs', PanelObjs.ClientHeight);
4093 config.WriteBool('Editor', 'DotEnable', DotEnable);
4094 config.WriteInt('Editor', 'DotStep', DotStep);
4095 config.WriteStr('Editor', 'LastOpenDir', OpenDialog.InitialDir);
4096 config.WriteStr('Editor', 'LastSaveDir', SaveDialog.InitialDir);
4097 config.WriteBool('Editor', 'EdgeShow', drEdge[3] < 255);
4098 config.WriteInt('Editor', 'EdgeColor', gColorEdge);
4099 config.WriteInt('Editor', 'EdgeAlpha', gAlphaEdge);
4100 config.WriteInt('Editor', 'LineAlpha', gAlphaTriggerLine);
4101 config.WriteInt('Editor', 'TriggerAlpha', gAlphaTriggerArea);
4103 for i := 0 to RecentCount-1 do
4104 if i < RecentFiles.Count then
4105 config.WriteStr('RecentFiles', IntToStr(i+1), RecentFiles[i])
4106 else
4107 config.WriteStr('RecentFiles', IntToStr(i+1), '');
4108 RecentFiles.Free();
4110 config.SaveFile(EditorDir+'Editor.cfg');
4111 config.Free();
4113 slInvalidTextures.Free;
4114 end;
4116 procedure TMainForm.FormDropFiles(Sender: TObject;
4117 const FileNames: array of String);
4118 begin
4119 if Length(FileNames) <> 1 then
4120 Exit;
4122 OpenMapFile(FileNames[0]);
4123 end;
4125 procedure TMainForm.RenderPanelResize(Sender: TObject);
4126 begin
4127 if MainForm.Visible then
4128 MainForm.Resize();
4129 end;
4131 procedure TMainForm.Splitter1Moved(Sender: TObject);
4132 begin
4133 FormResize(Sender);
4134 end;
4136 procedure TMainForm.aMapOptionsExecute(Sender: TObject);
4137 var
4138 ResName: String;
4139 begin
4140 MapOptionsForm.ShowModal();
4142 ResName := OpenedMap;
4143 while (Pos(':\', ResName) > 0) do
4144 Delete(ResName, 1, Pos(':\', ResName) + 1);
4146 UpdateCaption(gMapInfo.Name, ExtractFileName(OpenedWAD), ResName);
4147 end;
4149 procedure TMainForm.aAboutExecute(Sender: TObject);
4150 begin
4151 AboutForm.ShowModal();
4152 end;
4154 procedure TMainForm.FormKeyDown(Sender: TObject; var Key: Word;
4155 Shift: TShiftState);
4156 var
4157 dx, dy, i: Integer;
4158 FileName: String;
4159 begin
4160 if (not EditingProperties) then
4161 begin
4162 if Key = Ord('1') then
4163 SwitchLayer(LAYER_BACK);
4164 if Key = Ord('2') then
4165 SwitchLayer(LAYER_WALLS);
4166 if Key = Ord('3') then
4167 SwitchLayer(LAYER_FOREGROUND);
4168 if Key = Ord('4') then
4169 SwitchLayer(LAYER_STEPS);
4170 if Key = Ord('5') then
4171 SwitchLayer(LAYER_WATER);
4172 if Key = Ord('6') then
4173 SwitchLayer(LAYER_ITEMS);
4174 if Key = Ord('7') then
4175 SwitchLayer(LAYER_MONSTERS);
4176 if Key = Ord('8') then
4177 SwitchLayer(LAYER_AREAS);
4178 if Key = Ord('9') then
4179 SwitchLayer(LAYER_TRIGGERS);
4180 if Key = Ord('0') then
4181 tbShowClick(tbShow);
4183 if Key = Ord('V') then
4184 begin // Поворот монстров и областей:
4185 if (SelectedObjects <> nil) then
4186 begin
4187 for i := 0 to High(SelectedObjects) do
4188 if (SelectedObjects[i].Live) then
4189 begin
4190 if (SelectedObjects[i].ObjectType = OBJECT_MONSTER) then
4191 begin
4192 g_ChangeDir(gMonsters[SelectedObjects[i].ID].Direction);
4193 end
4194 else
4195 if (SelectedObjects[i].ObjectType = OBJECT_AREA) then
4196 begin
4197 g_ChangeDir(gAreas[SelectedObjects[i].ID].Direction);
4198 end;
4199 end;
4200 end
4201 else
4202 begin
4203 if pcObjects.ActivePage = tsMonsters then
4204 begin
4205 if rbMonsterLeft.Checked then
4206 rbMonsterRight.Checked := True
4207 else
4208 rbMonsterLeft.Checked := True;
4209 end;
4210 if pcObjects.ActivePage = tsAreas then
4211 begin
4212 if rbAreaLeft.Checked then
4213 rbAreaRight.Checked := True
4214 else
4215 rbAreaLeft.Checked := True;
4216 end;
4217 end;
4218 end;
4220 if not (ssCtrl in Shift) then
4221 begin
4222 // Быстрое превью карты:
4223 if Key = Ord('E') then
4224 begin
4225 if PreviewMode = 0 then
4226 PreviewMode := 2;
4227 end;
4229 // Вертикальный скролл карты:
4230 with sbVertical do
4231 begin
4232 if Key = Ord('W') then
4233 begin
4234 if (MouseLDown or MouseRDown) and (Position >= DotStep) then
4235 begin
4236 Dec(WASDOffset.Y, DotStep);
4237 RenderPanelMouseMove(Sender, Shift, LastMovePoint.X, LastMovePoint.Y);
4238 end;
4239 Position := IfThen(Position > DotStep, Position-DotStep, 0);
4240 MapOffset.Y := -Round(Position/16) * 16;
4241 end;
4243 if Key = Ord('S') then
4244 begin
4245 if (MouseLDown or MouseRDown) and (Position+DotStep <= Max) then
4246 begin
4247 Inc(WASDOffset.Y, DotStep);
4248 RenderPanelMouseMove(Sender, Shift, LastMovePoint.X, LastMovePoint.Y);
4249 end;
4250 Position := IfThen(Position+DotStep < Max, Position+DotStep, Max);
4251 MapOffset.Y := -Round(Position/16) * 16;
4252 end;
4253 end;
4255 // Горизонтальный скролл карты:
4256 with sbHorizontal do
4257 begin
4258 if Key = Ord('A') then
4259 begin
4260 if (MouseLDown or MouseRDown) and (Position >= DotStep) then
4261 begin
4262 Dec(WASDOffset.X, DotStep);
4263 RenderPanelMouseMove(Sender, Shift, LastMovePoint.X, LastMovePoint.Y);
4264 end;
4265 Position := IfThen(Position > DotStep, Position-DotStep, 0);
4266 MapOffset.X := -Round(Position/16) * 16;
4267 end;
4269 if Key = Ord('D') then
4270 begin
4271 if (MouseLDown or MouseRDown) and (Position+DotStep <= Max) then
4272 begin
4273 Inc(WASDOffset.X, DotStep);
4274 RenderPanelMouseMove(Sender, Shift, LastMovePoint.X, LastMovePoint.Y);
4275 end;
4276 Position := IfThen(Position+DotStep < Max, Position+DotStep, Max);
4277 MapOffset.X := -Round(Position/16) * 16;
4278 end;
4279 end;
4280 end;
4281 end;
4283 // Удалить выделенные объекты:
4284 if (Key = VK_DELETE) and (SelectedObjects <> nil) and
4285 RenderPanel.Focused() then
4286 DeleteSelectedObjects();
4288 // Снять выделение:
4289 if (Key = VK_ESCAPE) and (SelectedObjects <> nil) then
4290 RemoveSelectFromObjects();
4292 // Передвинуть объекты:
4293 if MainForm.ActiveControl = RenderPanel then
4294 begin
4295 dx := 0;
4296 dy := 0;
4298 if Key = VK_NUMPAD4 then
4299 dx := IfThen(ssAlt in Shift, -1, -DotStep);
4300 if Key = VK_NUMPAD6 then
4301 dx := IfThen(ssAlt in Shift, 1, DotStep);
4302 if Key = VK_NUMPAD8 then
4303 dy := IfThen(ssAlt in Shift, -1, -DotStep);
4304 if Key = VK_NUMPAD5 then
4305 dy := IfThen(ssAlt in Shift, 1, DotStep);
4307 if (dx <> 0) or (dy <> 0) then
4308 begin
4309 MoveSelectedObjects(ssShift in Shift, ssCtrl in Shift, dx, dy);
4310 Key := 0;
4311 end;
4312 end;
4314 if ssCtrl in Shift then
4315 begin
4316 // Выбор панели с текстурой для триггера
4317 if Key = Ord('T') then
4318 begin
4319 DrawPressRect := False;
4320 if SelectFlag = SELECTFLAG_TEXTURE then
4321 begin
4322 SelectFlag := SELECTFLAG_NONE;
4323 Exit;
4324 end;
4325 vleObjectProperty.FindRow(_lc[I_PROP_TR_TEXTURE_PANEL], i);
4326 if i > 0 then
4327 SelectFlag := SELECTFLAG_TEXTURE;
4328 end;
4330 if Key = Ord('D') then
4331 begin
4332 SelectFlag := SELECTFLAG_NONE;
4333 if DrawPressRect then
4334 begin
4335 DrawPressRect := False;
4336 Exit;
4337 end;
4338 i := -1;
4340 // Выбор области воздействия, в зависимости от типа триггера
4341 vleObjectProperty.FindRow(_lc[I_PROP_TR_EX_AREA], i);
4342 if i > 0 then
4343 begin
4344 DrawPressRect := True;
4345 Exit;
4346 end;
4347 vleObjectProperty.FindRow(_lc[I_PROP_TR_DOOR_PANEL], i);
4348 if i <= 0 then
4349 vleObjectProperty.FindRow(_lc[I_PROP_TR_TRAP_PANEL], i);
4350 if i > 0 then
4351 begin
4352 SelectFlag := SELECTFLAG_DOOR;
4353 Exit;
4354 end;
4355 vleObjectProperty.FindRow(_lc[I_PROP_TR_LIFT_PANEL], i);
4356 if i > 0 then
4357 begin
4358 SelectFlag := SELECTFLAG_LIFT;
4359 Exit;
4360 end;
4361 vleObjectProperty.FindRow(_lc[I_PROP_TR_TELEPORT_TO], i);
4362 if i > 0 then
4363 begin
4364 SelectFlag := SELECTFLAG_TELEPORT;
4365 Exit;
4366 end;
4367 vleObjectProperty.FindRow(_lc[I_PROP_TR_SPAWN_TO], i);
4368 if i > 0 then
4369 begin
4370 SelectFlag := SELECTFLAG_SPAWNPOINT;
4371 Exit;
4372 end;
4374 // Выбор основного параметра, в зависимости от типа триггера
4375 vleObjectProperty.FindRow(_lc[I_PROP_TR_NEXT_MAP], i);
4376 if i > 0 then
4377 begin
4378 g_ProcessResourceStr(OpenedMap, @FileName, nil, nil);
4379 SelectMapForm.Caption := _lc[I_CAP_SELECT];
4380 SelectMapForm.GetMaps(FileName);
4382 if SelectMapForm.ShowModal() = mrOK then
4383 begin
4384 vleObjectProperty.Cells[1, i] := SelectMapForm.lbMapList.Items[SelectMapForm.lbMapList.ItemIndex];
4385 bApplyProperty.Click();
4386 end;
4387 Exit;
4388 end;
4389 vleObjectProperty.FindRow(_lc[I_PROP_TR_SOUND_NAME], i);
4390 if i <= 0 then
4391 vleObjectProperty.FindRow(_lc[I_PROP_TR_MUSIC_NAME], i);
4392 if i > 0 then
4393 begin
4394 AddSoundForm.OKFunction := nil;
4395 AddSoundForm.lbResourcesList.MultiSelect := False;
4396 AddSoundForm.SetResource := vleObjectProperty.Cells[1, i];
4398 if (AddSoundForm.ShowModal() = mrOk) then
4399 begin
4400 vleObjectProperty.Cells[1, i] := AddSoundForm.ResourceName;
4401 bApplyProperty.Click();
4402 end;
4403 Exit;
4404 end;
4405 vleObjectProperty.FindRow(_lc[I_PROP_TR_PUSH_ANGLE], i);
4406 if i <= 0 then
4407 vleObjectProperty.FindRow(_lc[I_PROP_TR_MESSAGE_TEXT], i);
4408 if i > 0 then
4409 begin
4410 vleObjectProperty.Row := i;
4411 vleObjectProperty.SetFocus();
4412 Exit;
4413 end;
4414 end;
4415 end;
4416 end;
4418 procedure TMainForm.aOptimizeExecute(Sender: TObject);
4419 begin
4420 RemoveSelectFromObjects();
4421 MapOptimizationForm.ShowModal();
4422 end;
4424 procedure TMainForm.aCheckMapExecute(Sender: TObject);
4425 begin
4426 MapCheckForm.ShowModal();
4427 end;
4429 procedure TMainForm.bbAddTextureClick(Sender: TObject);
4430 begin
4431 AddTextureForm.lbResourcesList.MultiSelect := True;
4432 AddTextureForm.ShowModal();
4433 end;
4435 procedure TMainForm.lbTextureListClick(Sender: TObject);
4436 var
4437 TextureID: DWORD;
4438 TextureWidth, TextureHeight: Word;
4439 begin
4440 TextureID := 0;
4441 TextureWidth := 0;
4442 TextureHeight := 0;
4443 if (lbTextureList.ItemIndex <> -1) and
4444 (not IsSpecialTextureSel()) then
4445 begin
4446 if g_GetTexture(SelectedTexture(), TextureID) then
4447 begin
4448 g_GetTextureSizeByID(TextureID, TextureWidth, TextureHeight);
4450 lTextureWidth.Caption := IntToStr(TextureWidth);
4451 lTextureHeight.Caption := IntToStr(TextureHeight);
4452 end else
4453 begin
4454 lTextureWidth.Caption := _lc[I_NOT_ACCESSIBLE];
4455 lTextureHeight.Caption := _lc[I_NOT_ACCESSIBLE];
4456 end;
4457 end
4458 else
4459 begin
4460 lTextureWidth.Caption := '';
4461 lTextureHeight.Caption := '';
4462 end;
4463 end;
4465 procedure TMainForm.lbTextureListDrawItem(Control: TWinControl; Index: Integer;
4466 ARect: TRect; State: TOwnerDrawState);
4467 begin
4468 with Control as TListBox do
4469 begin
4470 if LCLType.odSelected in State then
4471 begin
4472 Canvas.Brush.Color := clHighlight;
4473 Canvas.Font.Color := clHighlightText;
4474 end else
4475 if (Items <> nil) and (Index >= 0) then
4476 if slInvalidTextures.IndexOf(Items[Index]) > -1 then
4477 begin
4478 Canvas.Brush.Color := clRed;
4479 Canvas.Font.Color := clWhite;
4480 end;
4481 Canvas.FillRect(ARect);
4482 Canvas.TextRect(ARect, ARect.Left, ARect.Top, Items[Index]);
4483 end;
4484 end;
4486 procedure TMainForm.vleObjectPropertyGetPickList(Sender: TObject;
4487 const KeyName: String; Values: TStrings);
4488 begin
4489 if vleObjectProperty.ItemProps[KeyName].EditStyle = esPickList then
4490 begin
4491 if KeyName = _lc[I_PROP_DIRECTION] then
4492 begin
4493 Values.Add(DirNames[D_LEFT]);
4494 Values.Add(DirNames[D_RIGHT]);
4495 end
4496 else if KeyName = _lc[I_PROP_TR_TELEPORT_DIR] then
4497 begin
4498 Values.Add(DirNamesAdv[0]);
4499 Values.Add(DirNamesAdv[1]);
4500 Values.Add(DirNamesAdv[2]);
4501 Values.Add(DirNamesAdv[3]);
4502 end
4503 else if KeyName = _lc[I_PROP_TR_MUSIC_ACT] then
4504 begin
4505 Values.Add(_lc[I_PROP_TR_MUSIC_ON]);
4506 Values.Add(_lc[I_PROP_TR_MUSIC_OFF]);
4507 end
4508 else if KeyName = _lc[I_PROP_TR_MONSTER_BEHAVIOUR] then
4509 begin
4510 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_0]);
4511 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_1]);
4512 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_2]);
4513 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_3]);
4514 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_4]);
4515 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_5]);
4516 end
4517 else if KeyName = _lc[I_PROP_TR_SCORE_ACT] then
4518 begin
4519 Values.Add(_lc[I_PROP_TR_SCORE_ACT_0]);
4520 Values.Add(_lc[I_PROP_TR_SCORE_ACT_1]);
4521 Values.Add(_lc[I_PROP_TR_SCORE_ACT_2]);
4522 Values.Add(_lc[I_PROP_TR_SCORE_ACT_3]);
4523 end
4524 else if KeyName = _lc[I_PROP_TR_SCORE_TEAM] then
4525 begin
4526 Values.Add(_lc[I_PROP_TR_SCORE_TEAM_0]);
4527 Values.Add(_lc[I_PROP_TR_SCORE_TEAM_1]);
4528 Values.Add(_lc[I_PROP_TR_SCORE_TEAM_2]);
4529 Values.Add(_lc[I_PROP_TR_SCORE_TEAM_3]);
4530 end
4531 else if KeyName = _lc[I_PROP_TR_MESSAGE_KIND] then
4532 begin
4533 Values.Add(_lc[I_PROP_TR_MESSAGE_KIND_0]);
4534 Values.Add(_lc[I_PROP_TR_MESSAGE_KIND_1]);
4535 end
4536 else if KeyName = _lc[I_PROP_TR_MESSAGE_TO] then
4537 begin
4538 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_0]);
4539 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_1]);
4540 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_2]);
4541 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_3]);
4542 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_4]);
4543 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_5]);
4544 end
4545 else if KeyName = _lc[I_PROP_TR_SHOT_TO] then
4546 begin
4547 Values.Add(_lc[I_PROP_TR_SHOT_TO_0]);
4548 Values.Add(_lc[I_PROP_TR_SHOT_TO_1]);
4549 Values.Add(_lc[I_PROP_TR_SHOT_TO_2]);
4550 Values.Add(_lc[I_PROP_TR_SHOT_TO_3]);
4551 Values.Add(_lc[I_PROP_TR_SHOT_TO_4]);
4552 Values.Add(_lc[I_PROP_TR_SHOT_TO_5]);
4553 Values.Add(_lc[I_PROP_TR_SHOT_TO_6]);
4554 end
4555 else if KeyName = _lc[I_PROP_TR_SHOT_AIM] then
4556 begin
4557 Values.Add(_lc[I_PROP_TR_SHOT_AIM_0]);
4558 Values.Add(_lc[I_PROP_TR_SHOT_AIM_1]);
4559 Values.Add(_lc[I_PROP_TR_SHOT_AIM_2]);
4560 Values.Add(_lc[I_PROP_TR_SHOT_AIM_3]);
4561 end
4562 else if (KeyName = _lc[I_PROP_PANEL_BLEND]) or
4563 (KeyName = _lc[I_PROP_DM_ONLY]) or
4564 (KeyName = _lc[I_PROP_ITEM_FALLS]) or
4565 (KeyName = _lc[I_PROP_TR_ENABLED]) or
4566 (KeyName = _lc[I_PROP_TR_D2D]) or
4567 (KeyName = _lc[I_PROP_TR_SILENT]) or
4568 (KeyName = _lc[I_PROP_TR_TELEPORT_SILENT]) or
4569 (KeyName = _lc[I_PROP_TR_EX_RANDOM]) or
4570 (KeyName = _lc[I_PROP_TR_TEXTURE_ONCE]) or
4571 (KeyName = _lc[I_PROP_TR_TEXTURE_ANIM_ONCE]) or
4572 (KeyName = _lc[I_PROP_TR_SOUND_LOCAL]) or
4573 (KeyName = _lc[I_PROP_TR_SOUND_SWITCH]) or
4574 (KeyName = _lc[I_PROP_TR_MONSTER_ACTIVE]) or
4575 (KeyName = _lc[I_PROP_TR_PUSH_RESET]) or
4576 (KeyName = _lc[I_PROP_TR_SCORE_CON]) or
4577 (KeyName = _lc[I_PROP_TR_SCORE_MSG]) or
4578 (KeyName = _lc[I_PROP_TR_HEALTH_MAX]) or
4579 (KeyName = _lc[I_PROP_TR_SHOT_SOUND]) or
4580 (KeyName = _lc[I_PROP_TR_EFFECT_CENTER]) then
4581 begin
4582 Values.Add(BoolNames[True]);
4583 Values.Add(BoolNames[False]);
4584 end;
4585 end;
4586 end;
4588 procedure TMainForm.bApplyPropertyClick(Sender: TObject);
4589 var
4590 _id, a, r, c: Integer;
4591 s: String;
4592 res: Boolean;
4593 NoTextureID: DWORD;
4594 NW, NH: Word;
4595 begin
4596 NoTextureID := 0;
4597 NW := 0;
4598 NH := 0;
4600 if SelectedObjectCount() <> 1 then
4601 Exit;
4602 if not SelectedObjects[GetFirstSelected()].Live then
4603 Exit;
4605 try
4606 if not CheckProperty() then
4607 Exit;
4608 except
4609 Exit;
4610 end;
4612 _id := GetFirstSelected();
4614 r := vleObjectProperty.Row;
4615 c := vleObjectProperty.Col;
4617 case SelectedObjects[_id].ObjectType of
4618 OBJECT_PANEL:
4619 begin
4620 with gPanels[SelectedObjects[_id].ID] do
4621 begin
4622 X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
4623 Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
4624 Width := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_WIDTH]]));
4625 Height := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_HEIGHT]]));
4627 PanelType := GetPanelType(vleObjectProperty.Values[_lc[I_PROP_PANEL_TYPE]]);
4629 // Сброс ссылки на триггеры смены текстуры:
4630 if not WordBool(PanelType and (PANEL_WALL or PANEL_FORE or PANEL_BACK)) then
4631 if gTriggers <> nil then
4632 for a := 0 to High(gTriggers) do
4633 begin
4634 if (gTriggers[a].TriggerType <> 0) and
4635 (gTriggers[a].TexturePanel = Integer(SelectedObjects[_id].ID)) then
4636 gTriggers[a].TexturePanel := -1;
4637 if (gTriggers[a].TriggerType = TRIGGER_SHOT) and
4638 (gTriggers[a].Data.ShotPanelID = Integer(SelectedObjects[_id].ID)) then
4639 gTriggers[a].Data.ShotPanelID := -1;
4640 end;
4642 // Сброс ссылки на триггеры лифта:
4643 if not WordBool(PanelType and (PANEL_LIFTUP or PANEL_LIFTDOWN or PANEL_LIFTLEFT or PANEL_LIFTRIGHT)) then
4644 if gTriggers <> nil then
4645 for a := 0 to High(gTriggers) do
4646 if (gTriggers[a].TriggerType in [TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT]) and
4647 (gTriggers[a].Data.PanelID = Integer(SelectedObjects[_id].ID)) then
4648 gTriggers[a].Data.PanelID := -1;
4650 // Сброс ссылки на триггеры двери:
4651 if not WordBool(PanelType and (PANEL_OPENDOOR or PANEL_CLOSEDOOR)) then
4652 if gTriggers <> nil then
4653 for a := 0 to High(gTriggers) do
4654 if (gTriggers[a].TriggerType in [TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
4655 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP]) and
4656 (gTriggers[a].Data.PanelID = Integer(SelectedObjects[_id].ID)) then
4657 gTriggers[a].Data.PanelID := -1;
4659 if IsTexturedPanel(PanelType) then
4660 begin // Может быть текстура
4661 if TextureName <> '' then
4662 begin // Была текстура
4663 Alpha := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_PANEL_ALPHA]]));
4664 Blending := NameToBool(vleObjectProperty.Values[_lc[I_PROP_PANEL_BLEND]]);
4665 end
4666 else // Не было
4667 begin
4668 Alpha := 0;
4669 Blending := False;
4670 end;
4672 // Новая текстура:
4673 TextureName := vleObjectProperty.Values[_lc[I_PROP_PANEL_TEX]];
4675 if TextureName <> '' then
4676 begin // Есть текстура
4677 // Обычная текстура:
4678 if not IsSpecialTexture(TextureName) then
4679 begin
4680 g_GetTextureSizeByName(TextureName,
4681 TextureWidth, TextureHeight);
4683 // Проверка кратности размеров панели:
4684 res := True;
4685 if TextureWidth <> 0 then
4686 if gPanels[SelectedObjects[_id].ID].Width mod TextureWidth <> 0 then
4687 begin
4688 ErrorMessageBox(Format(_lc[I_MSG_WRONG_TEXWIDTH],
4689 [TextureWidth]));
4690 Res := False;
4691 end;
4692 if Res and (TextureHeight <> 0) then
4693 if gPanels[SelectedObjects[_id].ID].Height mod TextureHeight <> 0 then
4694 begin
4695 ErrorMessageBox(Format(_lc[I_MSG_WRONG_TEXHEIGHT],
4696 [TextureHeight]));
4697 Res := False;
4698 end;
4700 if Res then
4701 begin
4702 if not g_GetTexture(TextureName, TextureID) then
4703 // Не удалось загрузить текстуру, рисуем NOTEXTURE
4704 if g_GetTexture('NOTEXTURE', NoTextureID) then
4705 begin
4706 TextureID := TEXTURE_SPECIAL_NOTEXTURE;
4707 g_GetTextureSizeByID(NoTextureID, NW, NH);
4708 TextureWidth := NW;
4709 TextureHeight := NH;
4710 end else
4711 begin
4712 TextureID := TEXTURE_SPECIAL_NONE;
4713 TextureWidth := 1;
4714 TextureHeight := 1;
4715 end;
4716 end
4717 else
4718 begin
4719 TextureName := '';
4720 TextureWidth := 1;
4721 TextureHeight := 1;
4722 TextureID := TEXTURE_SPECIAL_NONE;
4723 end;
4724 end
4725 else // Спец.текстура
4726 begin
4727 TextureHeight := 1;
4728 TextureWidth := 1;
4729 TextureID := SpecialTextureID(TextureName);
4730 end;
4731 end
4732 else // Нет текстуры
4733 begin
4734 TextureWidth := 1;
4735 TextureHeight := 1;
4736 TextureID := TEXTURE_SPECIAL_NONE;
4737 end;
4738 end
4739 else // Не может быть текстуры
4740 begin
4741 Alpha := 0;
4742 Blending := False;
4743 TextureName := '';
4744 TextureWidth := 1;
4745 TextureHeight := 1;
4746 TextureID := TEXTURE_SPECIAL_NONE;
4747 end;
4748 end;
4749 end;
4751 OBJECT_ITEM:
4752 begin
4753 with gItems[SelectedObjects[_id].ID] do
4754 begin
4755 X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
4756 Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
4757 OnlyDM := NameToBool(vleObjectProperty.Values[_lc[I_PROP_DM_ONLY]]);
4758 Fall := NameToBool(vleObjectProperty.Values[_lc[I_PROP_ITEM_FALLS]]);
4759 end;
4760 end;
4762 OBJECT_MONSTER:
4763 begin
4764 with gMonsters[SelectedObjects[_id].ID] do
4765 begin
4766 X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
4767 Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
4768 Direction := NameToDir(vleObjectProperty.Values[_lc[I_PROP_DIRECTION]]);
4769 end;
4770 end;
4772 OBJECT_AREA:
4773 begin
4774 with gAreas[SelectedObjects[_id].ID] do
4775 begin
4776 X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
4777 Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
4778 Direction := NameToDir(vleObjectProperty.Values[_lc[I_PROP_DIRECTION]]);
4779 end;
4780 end;
4782 OBJECT_TRIGGER:
4783 begin
4784 with gTriggers[SelectedObjects[_id].ID] do
4785 begin
4786 X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
4787 Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
4788 Width := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_WIDTH]]));
4789 Height := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_HEIGHT]]));
4790 Enabled := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_ENABLED]]);
4791 ActivateType := StrToActivate(vleObjectProperty.Values[_lc[I_PROP_TR_ACTIVATION]]);
4792 Key := StrToKey(vleObjectProperty.Values[_lc[I_PROP_TR_KEYS]]);
4794 case TriggerType of
4795 TRIGGER_EXIT:
4796 begin
4797 s := utf2win(vleObjectProperty.Values[_lc[I_PROP_TR_NEXT_MAP]]);
4798 FillByte(Data.MapName[0], 16, 0);
4799 if s <> '' then
4800 Move(s[1], Data.MapName[0], Min(Length(s), 16));
4801 end;
4803 TRIGGER_TEXTURE:
4804 begin
4805 Data.ActivateOnce := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_TEXTURE_ONCE]]);
4806 Data.AnimOnce := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_TEXTURE_ANIM_ONCE]]);
4807 end;
4809 TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF:
4810 begin
4811 Data.Wait := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EX_DELAY]], 0), 65535);
4812 Data.Count := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EX_COUNT]], 0), 65535);
4813 if Data.Count < 1 then
4814 Data.Count := 1;
4815 if TriggerType = TRIGGER_PRESS then
4816 Data.ExtRandom := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_EX_RANDOM]]);
4817 end;
4819 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR, TRIGGER_DOOR5,
4820 TRIGGER_CLOSETRAP, TRIGGER_TRAP, TRIGGER_LIFTUP, TRIGGER_LIFTDOWN,
4821 TRIGGER_LIFT:
4822 begin
4823 Data.NoSound := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SILENT]]);
4824 Data.d2d_doors := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_D2D]]);
4825 end;
4827 TRIGGER_TELEPORT:
4828 begin
4829 Data.d2d_teleport := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_D2D]]);
4830 Data.silent_teleport := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_TELEPORT_SILENT]]);
4831 Data.TlpDir := NameToDirAdv(vleObjectProperty.Values[_lc[I_PROP_TR_TELEPORT_DIR]]);
4832 end;
4834 TRIGGER_SOUND:
4835 begin
4836 s := utf2win(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_NAME]]);
4837 FillByte(Data.SoundName[0], 64, 0);
4838 if s <> '' then
4839 Move(s[1], Data.SoundName[0], Min(Length(s), 64));
4841 Data.Volume := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_VOLUME]], 0), 255);
4842 Data.Pan := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_PAN]], 0), 255);
4843 Data.PlayCount := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_COUNT]], 0), 255);
4844 Data.Local := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_LOCAL]]);
4845 Data.SoundSwitch := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_SWITCH]]);
4846 end;
4848 TRIGGER_SPAWNMONSTER:
4849 begin
4850 Data.MonType := StrToMonster(vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_TYPE]]);
4851 Data.MonDir := Byte(NameToDir(vleObjectProperty.Values[_lc[I_PROP_DIRECTION]]));
4852 Data.MonHealth := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_HEALTH]], 0), 1000000);
4853 if Data.MonHealth < 0 then
4854 Data.MonHealth := 0;
4855 Data.MonActive := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_ACTIVE]]);
4856 Data.MonCount := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_COUNT]], 0), 64);
4857 if Data.MonCount < 1 then
4858 Data.MonCount := 1;
4859 Data.MonEffect := StrToEffect(vleObjectProperty.Values[_lc[I_PROP_TR_FX_TYPE]]);
4860 Data.MonMax := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SPAWN_MAX]], 0), 65535);
4861 Data.MonDelay := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SPAWN_DELAY]], 0), 65535);
4862 Data.MonBehav := 0;
4863 if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_1] then
4864 Data.MonBehav := 1;
4865 if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_2] then
4866 Data.MonBehav := 2;
4867 if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_3] then
4868 Data.MonBehav := 3;
4869 if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_4] then
4870 Data.MonBehav := 4;
4871 if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_5] then
4872 Data.MonBehav := 5;
4873 end;
4875 TRIGGER_SPAWNITEM:
4876 begin
4877 Data.ItemType := StrToItem(vleObjectProperty.Values[_lc[I_PROP_TR_ITEM_TYPE]]);
4878 Data.ItemOnlyDM := NameToBool(vleObjectProperty.Values[_lc[I_PROP_DM_ONLY]]);
4879 Data.ItemFalls := NameToBool(vleObjectProperty.Values[_lc[I_PROP_ITEM_FALLS]]);
4880 Data.ItemCount := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_COUNT]], 0), 64);
4881 if Data.ItemCount < 1 then
4882 Data.ItemCount := 1;
4883 Data.ItemEffect := StrToEffect(vleObjectProperty.Values[_lc[I_PROP_TR_FX_TYPE]]);
4884 Data.ItemMax := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SPAWN_MAX]], 0), 65535);
4885 Data.ItemDelay := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SPAWN_DELAY]], 0), 65535);
4886 end;
4888 TRIGGER_MUSIC:
4889 begin
4890 s := utf2win(vleObjectProperty.Values[_lc[I_PROP_TR_MUSIC_NAME]]);
4891 FillByte(Data.MusicName[0], 64, 0);
4892 if s <> '' then
4893 Move(s[1], Data.MusicName[0], Min(Length(s), 64));
4895 if vleObjectProperty.Values[_lc[I_PROP_TR_MUSIC_ACT]] = _lc[I_PROP_TR_MUSIC_ON] then
4896 Data.MusicAction := 1
4897 else
4898 Data.MusicAction := 2;
4899 end;
4901 TRIGGER_PUSH:
4902 begin
4903 Data.PushAngle := Min(
4904 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_PUSH_ANGLE]], 0), 360);
4905 Data.PushForce := Min(
4906 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_PUSH_FORCE]], 0), 255);
4907 Data.ResetVel := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_PUSH_RESET]]);
4908 end;
4910 TRIGGER_SCORE:
4911 begin
4912 Data.ScoreAction := 0;
4913 if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_ACT]] = _lc[I_PROP_TR_SCORE_ACT_1] then
4914 Data.ScoreAction := 1
4915 else if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_ACT]] = _lc[I_PROP_TR_SCORE_ACT_2] then
4916 Data.ScoreAction := 2
4917 else if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_ACT]] = _lc[I_PROP_TR_SCORE_ACT_3] then
4918 Data.ScoreAction := 3;
4919 Data.ScoreCount := Min(Max(
4920 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_COUNT]], 0), 0), 255);
4921 Data.ScoreTeam := 0;
4922 if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_TEAM]] = _lc[I_PROP_TR_SCORE_TEAM_1] then
4923 Data.ScoreTeam := 1
4924 else if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_TEAM]] = _lc[I_PROP_TR_SCORE_TEAM_2] then
4925 Data.ScoreTeam := 2
4926 else if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_TEAM]] = _lc[I_PROP_TR_SCORE_TEAM_3] then
4927 Data.ScoreTeam := 3;
4928 Data.ScoreCon := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_CON]]);
4929 Data.ScoreMsg := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_MSG]]);
4930 end;
4932 TRIGGER_MESSAGE:
4933 begin
4934 Data.MessageKind := 0;
4935 if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_KIND]] = _lc[I_PROP_TR_MESSAGE_KIND_1] then
4936 Data.MessageKind := 1;
4938 Data.MessageSendTo := 0;
4939 if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_1] then
4940 Data.MessageSendTo := 1
4941 else if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_2] then
4942 Data.MessageSendTo := 2
4943 else if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_3] then
4944 Data.MessageSendTo := 3
4945 else if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_4] then
4946 Data.MessageSendTo := 4
4947 else if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_5] then
4948 Data.MessageSendTo := 5;
4950 s := utf2win(vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TEXT]]);
4951 FillByte(Data.MessageText[0], 100, 0);
4952 if s <> '' then
4953 Move(s[1], Data.MessageText[0], Min(Length(s), 100));
4955 Data.MessageTime := Min(Max(
4956 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TIME]], 0), 0), 65535);
4957 end;
4959 TRIGGER_DAMAGE:
4960 begin
4961 Data.DamageValue := Min(Max(
4962 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_DAMAGE_VALUE]], 0), 0), 65535);
4963 Data.DamageInterval := Min(Max(
4964 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_INTERVAL]], 0), 0), 65535);
4965 end;
4967 TRIGGER_HEALTH:
4968 begin
4969 Data.HealValue := Min(Max(
4970 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_HEALTH]], 0), 0), 65535);
4971 Data.HealInterval := Min(Max(
4972 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_INTERVAL]], 0), 0), 65535);
4973 Data.HealMax := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_HEALTH_MAX]]);
4974 Data.HealSilent := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SILENT]]);
4975 end;
4977 TRIGGER_SHOT:
4978 begin
4979 Data.ShotType := StrToShot(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TYPE]]);
4980 Data.ShotSound := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_SOUND]]);
4981 Data.ShotTarget := 0;
4982 if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_1] then
4983 Data.ShotTarget := 1
4984 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_2] then
4985 Data.ShotTarget := 2
4986 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_3] then
4987 Data.ShotTarget := 3
4988 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_4] then
4989 Data.ShotTarget := 4
4990 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_5] then
4991 Data.ShotTarget := 5
4992 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_6] then
4993 Data.ShotTarget := 6;
4994 Data.ShotIntSight := Min(Max(
4995 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_SIGHT]], 0), 0), 65535);
4996 Data.ShotAim := 0;
4997 if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_AIM]] = _lc[I_PROP_TR_SHOT_AIM_1] then
4998 Data.ShotAim := 1
4999 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_AIM]] = _lc[I_PROP_TR_SHOT_AIM_2] then
5000 Data.ShotAim := 2
5001 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_AIM]] = _lc[I_PROP_TR_SHOT_AIM_3] then
5002 Data.ShotAim := 3;
5003 Data.ShotAngle := Min(
5004 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_ANGLE]], 0), 360);
5005 Data.ShotWait := Min(Max(
5006 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EX_DELAY]], 0), 0), 65535);
5007 Data.ShotAccuracy := Min(Max(
5008 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_ACC]], 0), 0), 65535);
5009 Data.ShotAmmo := Min(Max(
5010 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_AMMO]], 0), 0), 65535);
5011 Data.ShotIntReload := Min(Max(
5012 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_RELOAD]], 0), 0), 65535);
5013 end;
5015 TRIGGER_EFFECT:
5016 begin
5017 Data.FXCount := Min(Max(
5018 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_COUNT]], 0), 0), 255);
5019 if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_TYPE]] = _lc[I_PROP_TR_EFFECT_PARTICLE] then
5020 begin
5021 Data.FXType := TRIGGER_EFFECT_PARTICLE;
5022 Data.FXSubType := TRIGGER_EFFECT_SLIQUID;
5023 if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_SLIQUID] then
5024 Data.FXSubType := TRIGGER_EFFECT_SLIQUID
5025 else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_LLIQUID] then
5026 Data.FXSubType := TRIGGER_EFFECT_LLIQUID
5027 else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_DLIQUID] then
5028 Data.FXSubType := TRIGGER_EFFECT_DLIQUID
5029 else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_BLOOD] then
5030 Data.FXSubType := TRIGGER_EFFECT_BLOOD
5031 else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_SPARK] then
5032 Data.FXSubType := TRIGGER_EFFECT_SPARK
5033 else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_BUBBLE] then
5034 Data.FXSubType := TRIGGER_EFFECT_BUBBLE;
5035 end else
5036 begin
5037 Data.FXType := TRIGGER_EFFECT_ANIMATION;
5038 Data.FXSubType := StrToEffect(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]]);
5039 end;
5040 a := Min(Max(
5041 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_COLOR]], 0), 0), $FFFFFF);
5042 Data.FXColorR := a and $FF;
5043 Data.FXColorG := (a shr 8) and $FF;
5044 Data.FXColorB := (a shr 16) and $FF;
5045 if NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_CENTER]]) then
5046 Data.FXPos := 0
5047 else
5048 Data.FXPos := 1;
5049 Data.FXWait := Min(Max(
5050 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EX_DELAY]], 0), 0), 65535);
5051 Data.FXVelX := Min(Max(
5052 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_VELX]], 0), -128), 127);
5053 Data.FXVelY := Min(Max(
5054 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_VELY]], 0), -128), 127);
5055 Data.FXSpreadL := Min(Max(
5056 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SPL]], 0), 0), 255);
5057 Data.FXSpreadR := Min(Max(
5058 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SPR]], 0), 0), 255);
5059 Data.FXSpreadU := Min(Max(
5060 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SPU]], 0), 0), 255);
5061 Data.FXSpreadD := Min(Max(
5062 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SPD]], 0), 0), 255);
5063 end;
5064 end;
5065 end;
5066 end;
5067 end;
5069 FillProperty();
5071 vleObjectProperty.Row := r;
5072 vleObjectProperty.Col := c;
5073 end;
5075 procedure TMainForm.bbRemoveTextureClick(Sender: TObject);
5076 var
5077 a, i: Integer;
5078 begin
5079 i := lbTextureList.ItemIndex;
5080 if i = -1 then
5081 Exit;
5083 if MessageBox(0, PChar(Format(_lc[I_MSG_DEL_TEXTURE_PROMT],
5084 [SelectedTexture()])),
5085 PChar(_lc[I_MSG_DEL_TEXTURE]),
5086 MB_ICONQUESTION or MB_YESNO or
5087 MB_DEFBUTTON1) <> idYes then
5088 Exit;
5090 if gPanels <> nil then
5091 for a := 0 to High(gPanels) do
5092 if (gPanels[a].PanelType <> 0) and
5093 (gPanels[a].TextureName = SelectedTexture()) then
5094 begin
5095 ErrorMessageBox(_lc[I_MSG_DEL_TEXTURE_CANT]);
5096 Exit;
5097 end;
5099 g_DeleteTexture(SelectedTexture());
5100 i := slInvalidTextures.IndexOf(lbTextureList.Items[i]);
5101 if i > -1 then
5102 slInvalidTextures.Delete(i);
5103 if lbTextureList.ItemIndex > -1 then
5104 lbTextureList.Items.Delete(lbTextureList.ItemIndex)
5105 end;
5107 procedure TMainForm.aNewMapExecute(Sender: TObject);
5108 begin
5109 if (MessageBox(0, PChar(_lc[I_MSG_CLEAR_MAP_PROMT]),
5110 PChar(_lc[I_MSG_CLEAR_MAP]),
5111 MB_ICONQUESTION or MB_YESNO or
5112 MB_DEFBUTTON1) = mrYes) then
5113 FullClear();
5114 end;
5116 procedure TMainForm.aUndoExecute(Sender: TObject);
5117 var
5118 a: Integer;
5119 begin
5120 if UndoBuffer = nil then
5121 Exit;
5122 if UndoBuffer[High(UndoBuffer)] = nil then
5123 Exit;
5125 for a := 0 to High(UndoBuffer[High(UndoBuffer)]) do
5126 with UndoBuffer[High(UndoBuffer)][a] do
5127 begin
5128 case UndoType of
5129 UNDO_DELETE_PANEL:
5130 begin
5131 AddPanel(Panel^);
5132 Panel := nil;
5133 end;
5134 UNDO_DELETE_ITEM: AddItem(Item);
5135 UNDO_DELETE_AREA: AddArea(Area);
5136 UNDO_DELETE_MONSTER: AddMonster(Monster);
5137 UNDO_DELETE_TRIGGER: AddTrigger(Trigger);
5138 UNDO_ADD_PANEL: RemoveObject(AddID, OBJECT_PANEL);
5139 UNDO_ADD_ITEM: RemoveObject(AddID, OBJECT_ITEM);
5140 UNDO_ADD_AREA: RemoveObject(AddID, OBJECT_AREA);
5141 UNDO_ADD_MONSTER: RemoveObject(AddID, OBJECT_MONSTER);
5142 UNDO_ADD_TRIGGER: RemoveObject(AddID, OBJECT_TRIGGER);
5143 end;
5144 end;
5146 SetLength(UndoBuffer, Length(UndoBuffer)-1);
5148 RemoveSelectFromObjects();
5150 miUndo.Enabled := UndoBuffer <> nil;
5151 end;
5154 procedure TMainForm.aCopyObjectExecute(Sender: TObject);
5155 var
5156 a, b: Integer;
5157 CopyBuffer: TCopyRecArray;
5158 str: String;
5159 ok: Boolean;
5161 function CB_Compare(I1, I2: TCopyRec): Integer;
5162 begin
5163 Result := Integer(I1.ObjectType) - Integer(I2.ObjectType);
5165 if Result = 0 then // Одного типа
5166 Result := Integer(I1.ID) - Integer(I2.ID);
5167 end;
5169 procedure QuickSortCopyBuffer(L, R: Integer);
5170 var
5171 I, J: Integer;
5172 P, T: TCopyRec;
5173 begin
5174 repeat
5175 I := L;
5176 J := R;
5177 P := CopyBuffer[(L + R) shr 1];
5179 repeat
5180 while CB_Compare(CopyBuffer[I], P) < 0 do
5181 Inc(I);
5182 while CB_Compare(CopyBuffer[J], P) > 0 do
5183 Dec(J);
5185 if I <= J then
5186 begin
5187 T := CopyBuffer[I];
5188 CopyBuffer[I] := CopyBuffer[J];
5189 CopyBuffer[J] := T;
5190 Inc(I);
5191 Dec(J);
5192 end;
5193 until I > J;
5195 if L < J then
5196 QuickSortCopyBuffer(L, J);
5198 L := I;
5199 until I >= R;
5200 end;
5202 begin
5203 if SelectedObjects = nil then
5204 Exit;
5206 b := -1;
5207 CopyBuffer := nil;
5209 // Копируем объекты:
5210 for a := 0 to High(SelectedObjects) do
5211 if SelectedObjects[a].Live then
5212 with SelectedObjects[a] do
5213 begin
5214 SetLength(CopyBuffer, Length(CopyBuffer)+1);
5215 b := High(CopyBuffer);
5216 CopyBuffer[b].ID := ID;
5217 CopyBuffer[b].Panel := nil;
5219 case ObjectType of
5220 OBJECT_PANEL:
5221 begin
5222 CopyBuffer[b].ObjectType := OBJECT_PANEL;
5223 New(CopyBuffer[b].Panel);
5224 CopyBuffer[b].Panel^ := gPanels[ID];
5225 end;
5227 OBJECT_ITEM:
5228 begin
5229 CopyBuffer[b].ObjectType := OBJECT_ITEM;
5230 CopyBuffer[b].Item := gItems[ID];
5231 end;
5233 OBJECT_MONSTER:
5234 begin
5235 CopyBuffer[b].ObjectType := OBJECT_MONSTER;
5236 CopyBuffer[b].Monster := gMonsters[ID];
5237 end;
5239 OBJECT_AREA:
5240 begin
5241 CopyBuffer[b].ObjectType := OBJECT_AREA;
5242 CopyBuffer[b].Area := gAreas[ID];
5243 end;
5245 OBJECT_TRIGGER:
5246 begin
5247 CopyBuffer[b].ObjectType := OBJECT_TRIGGER;
5248 CopyBuffer[b].Trigger := gTriggers[ID];
5249 end;
5250 end;
5251 end;
5253 // Сортировка по ID:
5254 if CopyBuffer <> nil then
5255 begin
5256 QuickSortCopyBuffer(0, b);
5257 end;
5259 // Пестановка ссылок триггеров:
5260 for a := 0 to Length(CopyBuffer)-1 do
5261 if CopyBuffer[a].ObjectType = OBJECT_TRIGGER then
5262 begin
5263 case CopyBuffer[a].Trigger.TriggerType of
5264 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
5265 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP,
5266 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
5267 if CopyBuffer[a].Trigger.Data.PanelID <> -1 then
5268 begin
5269 ok := False;
5271 for b := 0 to Length(CopyBuffer)-1 do
5272 if (CopyBuffer[b].ObjectType = OBJECT_PANEL) and
5273 (Integer(CopyBuffer[b].ID) = CopyBuffer[a].Trigger.Data.PanelID) then
5274 begin
5275 CopyBuffer[a].Trigger.Data.PanelID := b;
5276 ok := True;
5277 Break;
5278 end;
5280 // Этих панелей нет среди копируемых:
5281 if not ok then
5282 CopyBuffer[a].Trigger.Data.PanelID := -1;
5283 end;
5285 TRIGGER_PRESS, TRIGGER_ON,
5286 TRIGGER_OFF, TRIGGER_ONOFF:
5287 if CopyBuffer[a].Trigger.Data.MonsterID <> 0 then
5288 begin
5289 ok := False;
5291 for b := 0 to Length(CopyBuffer)-1 do
5292 if (CopyBuffer[b].ObjectType = OBJECT_MONSTER) and
5293 (Integer(CopyBuffer[b].ID) = CopyBuffer[a].Trigger.Data.MonsterID-1) then
5294 begin
5295 CopyBuffer[a].Trigger.Data.MonsterID := b+1;
5296 ok := True;
5297 Break;
5298 end;
5300 // Этих монстров нет среди копируемых:
5301 if not ok then
5302 CopyBuffer[a].Trigger.Data.MonsterID := 0;
5303 end;
5305 TRIGGER_SHOT:
5306 if CopyBuffer[a].Trigger.Data.ShotPanelID <> -1 then
5307 begin
5308 ok := False;
5310 for b := 0 to Length(CopyBuffer)-1 do
5311 if (CopyBuffer[b].ObjectType = OBJECT_PANEL) and
5312 (Integer(CopyBuffer[b].ID) = CopyBuffer[a].Trigger.Data.ShotPanelID) then
5313 begin
5314 CopyBuffer[a].Trigger.Data.ShotPanelID := b;
5315 ok := True;
5316 Break;
5317 end;
5319 // Этих панелей нет среди копируемых:
5320 if not ok then
5321 CopyBuffer[a].Trigger.Data.ShotPanelID := -1;
5322 end;
5323 end;
5325 if CopyBuffer[a].Trigger.TexturePanel <> -1 then
5326 begin
5327 ok := False;
5329 for b := 0 to Length(CopyBuffer)-1 do
5330 if (CopyBuffer[b].ObjectType = OBJECT_PANEL) and
5331 (Integer(CopyBuffer[b].ID) = CopyBuffer[a].Trigger.TexturePanel) then
5332 begin
5333 CopyBuffer[a].Trigger.TexturePanel := b;
5334 ok := True;
5335 Break;
5336 end;
5338 // Этих панелей нет среди копируемых:
5339 if not ok then
5340 CopyBuffer[a].Trigger.TexturePanel := -1;
5341 end;
5342 end;
5344 // В буфер обмена:
5345 str := CopyBufferToString(CopyBuffer);
5346 ClipBoard.AsText := str;
5348 for a := 0 to Length(CopyBuffer)-1 do
5349 if (CopyBuffer[a].ObjectType = OBJECT_PANEL) and
5350 (CopyBuffer[a].Panel <> nil) then
5351 Dispose(CopyBuffer[a].Panel);
5353 CopyBuffer := nil;
5354 end;
5356 procedure TMainForm.aPasteObjectExecute(Sender: TObject);
5357 var
5358 a, h: Integer;
5359 CopyBuffer: TCopyRecArray;
5360 res: Boolean;
5361 swad, ssec, sres: String;
5362 begin
5363 CopyBuffer := nil;
5365 StringToCopyBuffer(ClipBoard.AsText, CopyBuffer);
5367 if CopyBuffer = nil then
5368 Exit;
5370 RemoveSelectFromObjects();
5372 h := High(CopyBuffer);
5373 for a := 0 to h do
5374 with CopyBuffer[a] do
5375 begin
5376 case ObjectType of
5377 OBJECT_PANEL:
5378 if Panel <> nil then
5379 begin
5380 Panel^.X := Panel^.X + 16;
5381 Panel^.Y := Panel^.Y + 16;
5383 Panel^.TextureID := TEXTURE_SPECIAL_NONE;
5384 Panel^.TextureWidth := 1;
5385 Panel^.TextureHeight := 1;
5387 if (Panel^.PanelType = PANEL_LIFTUP) or
5388 (Panel^.PanelType = PANEL_LIFTDOWN) or
5389 (Panel^.PanelType = PANEL_LIFTLEFT) or
5390 (Panel^.PanelType = PANEL_LIFTRIGHT) or
5391 (Panel^.PanelType = PANEL_BLOCKMON) or
5392 (Panel^.TextureName = '') then
5393 begin // Нет или не может быть текстуры:
5394 end
5395 else // Есть текстура:
5396 begin
5397 // Обычная текстура:
5398 if not IsSpecialTexture(Panel^.TextureName) then
5399 begin
5400 res := g_GetTexture(Panel^.TextureName, Panel^.TextureID);
5402 if not res then
5403 begin
5404 g_ProcessResourceStr(Panel^.TextureName, swad, ssec, sres);
5405 AddTexture(swad, ssec, sres, True);
5406 res := g_GetTexture(Panel^.TextureName, Panel^.TextureID);
5407 end;
5409 if res then
5410 g_GetTextureSizeByName(Panel^.TextureName,
5411 Panel^.TextureWidth, Panel^.TextureHeight)
5412 else
5413 Panel^.TextureName := '';
5414 end
5415 else // Спец.текстура:
5416 begin
5417 Panel^.TextureID := SpecialTextureID(Panel^.TextureName);
5418 with MainForm.lbTextureList.Items do
5419 if IndexOf(Panel^.TextureName) = -1 then
5420 Add(Panel^.TextureName);
5421 end;
5422 end;
5424 ID := AddPanel(Panel^);
5425 Dispose(Panel);
5426 Undo_Add(OBJECT_PANEL, ID, a > 0);
5427 SelectObject(OBJECT_PANEL, ID, True);
5428 end;
5430 OBJECT_ITEM:
5431 begin
5432 Item.X := Item.X + 16;
5433 Item.Y := Item.Y + 16;
5435 ID := AddItem(Item);
5436 Undo_Add(OBJECT_ITEM, ID, a > 0);
5437 SelectObject(OBJECT_ITEM, ID, True);
5438 end;
5440 OBJECT_MONSTER:
5441 begin
5442 Monster.X := Monster.X + 16;
5443 Monster.Y := Monster.Y + 16;
5445 ID := AddMonster(Monster);
5446 Undo_Add(OBJECT_MONSTER, ID, a > 0);
5447 SelectObject(OBJECT_MONSTER, ID, True);
5448 end;
5450 OBJECT_AREA:
5451 begin
5452 Area.X := Area.X + 16;
5453 Area.Y := Area.Y + 16;
5455 ID := AddArea(Area);
5456 Undo_Add(OBJECT_AREA, ID, a > 0);
5457 SelectObject(OBJECT_AREA, ID, True);
5458 end;
5460 OBJECT_TRIGGER:
5461 begin
5462 Trigger.X := Trigger.X + 16;
5463 Trigger.Y := Trigger.Y + 16;
5465 ID := AddTrigger(Trigger);
5466 Undo_Add(OBJECT_TRIGGER, ID, a > 0);
5467 SelectObject(OBJECT_TRIGGER, ID, True);
5468 end;
5469 end;
5470 end;
5472 // Переставляем ссылки триггеров:
5473 for a := 0 to High(CopyBuffer) do
5474 if CopyBuffer[a].ObjectType = OBJECT_TRIGGER then
5475 begin
5476 case CopyBuffer[a].Trigger.TriggerType of
5477 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
5478 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP,
5479 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
5480 if CopyBuffer[a].Trigger.Data.PanelID <> -1 then
5481 gTriggers[CopyBuffer[a].ID].Data.PanelID :=
5482 CopyBuffer[CopyBuffer[a].Trigger.Data.PanelID].ID;
5484 TRIGGER_PRESS, TRIGGER_ON,
5485 TRIGGER_OFF, TRIGGER_ONOFF:
5486 if CopyBuffer[a].Trigger.Data.MonsterID <> 0 then
5487 gTriggers[CopyBuffer[a].ID].Data.MonsterID :=
5488 CopyBuffer[CopyBuffer[a].Trigger.Data.MonsterID-1].ID+1;
5490 TRIGGER_SHOT:
5491 if CopyBuffer[a].Trigger.Data.ShotPanelID <> -1 then
5492 gTriggers[CopyBuffer[a].ID].Data.ShotPanelID :=
5493 CopyBuffer[CopyBuffer[a].Trigger.Data.ShotPanelID].ID;
5494 end;
5496 if CopyBuffer[a].Trigger.TexturePanel <> -1 then
5497 gTriggers[CopyBuffer[a].ID].TexturePanel :=
5498 CopyBuffer[CopyBuffer[a].Trigger.TexturePanel].ID;
5499 end;
5501 CopyBuffer := nil;
5503 if h = 0 then
5504 FillProperty();
5505 end;
5507 procedure TMainForm.aCutObjectExecute(Sender: TObject);
5508 begin
5509 miCopy.Click();
5510 DeleteSelectedObjects();
5511 end;
5513 procedure TMainForm.vleObjectPropertyEditButtonClick(Sender: TObject);
5514 var
5515 Key, FileName: String;
5516 b: Byte;
5517 begin
5518 Key := vleObjectProperty.Keys[vleObjectProperty.Row];
5520 if Key = _lc[I_PROP_PANEL_TYPE] then
5521 begin
5522 with ChooseTypeForm, vleObjectProperty do
5523 begin // Выбор типа панели:
5524 Caption := _lc[I_PROP_PANEL_TYPE];
5525 lbTypeSelect.Items.Clear();
5527 for b := 0 to High(PANELNAMES) do
5528 begin
5529 lbTypeSelect.Items.Add(PANELNAMES[b]);
5530 if Values[Key] = PANELNAMES[b] then
5531 lbTypeSelect.ItemIndex := b;
5532 end;
5534 if ShowModal() = mrOK then
5535 begin
5536 b := lbTypeSelect.ItemIndex;
5537 Values[Key] := PANELNAMES[b];
5538 vleObjectPropertyApply(Sender);
5539 end;
5540 end
5541 end
5542 else if Key = _lc[I_PROP_TR_TELEPORT_TO] then
5543 SelectFlag := SELECTFLAG_TELEPORT
5544 else if Key = _lc[I_PROP_TR_SPAWN_TO] then
5545 SelectFlag := SELECTFLAG_SPAWNPOINT
5546 else if (Key = _lc[I_PROP_TR_DOOR_PANEL]) or
5547 (Key = _lc[I_PROP_TR_TRAP_PANEL]) then
5548 SelectFlag := SELECTFLAG_DOOR
5549 else if Key = _lc[I_PROP_TR_TEXTURE_PANEL] then
5550 begin
5551 DrawPressRect := False;
5552 SelectFlag := SELECTFLAG_TEXTURE;
5553 end
5554 else if Key = _lc[I_PROP_TR_SHOT_PANEL] then
5555 SelectFlag := SELECTFLAG_SHOTPANEL
5556 else if Key = _lc[I_PROP_TR_LIFT_PANEL] then
5557 SelectFlag := SELECTFLAG_LIFT
5558 else if key = _lc[I_PROP_TR_EX_MONSTER] then
5559 SelectFlag := SELECTFLAG_MONSTER
5560 else if Key = _lc[I_PROP_TR_EX_AREA] then
5561 begin
5562 SelectFlag := SELECTFLAG_NONE;
5563 DrawPressRect := True;
5564 end
5565 else if Key = _lc[I_PROP_TR_NEXT_MAP] then
5566 begin // Выбор следующей карты:
5567 g_ProcessResourceStr(OpenedMap, @FileName, nil, nil);
5568 SelectMapForm.Caption := _lc[I_CAP_SELECT];
5569 SelectMapForm.GetMaps(FileName);
5571 if SelectMapForm.ShowModal() = mrOK then
5572 begin
5573 vleObjectProperty.Values[Key] := SelectMapForm.lbMapList.Items[SelectMapForm.lbMapList.ItemIndex];
5574 vleObjectPropertyApply(Sender);
5575 end;
5576 end
5577 else if (Key = _lc[I_PROP_TR_SOUND_NAME]) or
5578 (Key = _lc[I_PROP_TR_MUSIC_NAME]) then
5579 begin // Выбор файла звука/музыки:
5580 AddSoundForm.OKFunction := nil;
5581 AddSoundForm.lbResourcesList.MultiSelect := False;
5582 AddSoundForm.SetResource := vleObjectProperty.Values[Key];
5584 if (AddSoundForm.ShowModal() = mrOk) then
5585 begin
5586 vleObjectProperty.Values[Key] := AddSoundForm.ResourceName;
5587 vleObjectPropertyApply(Sender);
5588 end;
5589 end
5590 else if Key = _lc[I_PROP_TR_ACTIVATION] then
5591 with ActivationTypeForm, vleObjectProperty do
5592 begin // Выбор типов активации:
5593 cbPlayerCollide.Checked := Pos('PC', Values[Key]) > 0;
5594 cbMonsterCollide.Checked := Pos('MC', Values[Key]) > 0;
5595 cbPlayerPress.Checked := Pos('PP', Values[Key]) > 0;
5596 cbMonsterPress.Checked := Pos('MP', Values[Key]) > 0;
5597 cbShot.Checked := Pos('SH', Values[Key]) > 0;
5598 cbNoMonster.Checked := Pos('NM', Values[Key]) > 0;
5600 if ShowModal() = mrOK then
5601 begin
5602 b := 0;
5603 if cbPlayerCollide.Checked then
5604 b := ACTIVATE_PLAYERCOLLIDE;
5605 if cbMonsterCollide.Checked then
5606 b := b or ACTIVATE_MONSTERCOLLIDE;
5607 if cbPlayerPress.Checked then
5608 b := b or ACTIVATE_PLAYERPRESS;
5609 if cbMonsterPress.Checked then
5610 b := b or ACTIVATE_MONSTERPRESS;
5611 if cbShot.Checked then
5612 b := b or ACTIVATE_SHOT;
5613 if cbNoMonster.Checked then
5614 b := b or ACTIVATE_NOMONSTER;
5616 Values[Key] := ActivateToStr(b);
5617 vleObjectPropertyApply(Sender);
5618 end;
5619 end
5620 else if Key = _lc[I_PROP_TR_KEYS] then
5621 with KeysForm, vleObjectProperty do
5622 begin // Выбор необходимых ключей:
5623 cbRedKey.Checked := Pos('RK', Values[Key]) > 0;
5624 cbGreenKey.Checked := Pos('GK', Values[Key]) > 0;
5625 cbBlueKey.Checked := Pos('BK', Values[Key]) > 0;
5626 cbRedTeam.Checked := Pos('RT', Values[Key]) > 0;
5627 cbBlueTeam.Checked := Pos('BT', Values[Key]) > 0;
5629 if ShowModal() = mrOK then
5630 begin
5631 b := 0;
5632 if cbRedKey.Checked then
5633 b := KEY_RED;
5634 if cbGreenKey.Checked then
5635 b := b or KEY_GREEN;
5636 if cbBlueKey.Checked then
5637 b := b or KEY_BLUE;
5638 if cbRedTeam.Checked then
5639 b := b or KEY_REDTEAM;
5640 if cbBlueTeam.Checked then
5641 b := b or KEY_BLUETEAM;
5643 Values[Key] := KeyToStr(b);
5644 vleObjectPropertyApply(Sender);
5645 end;
5646 end
5647 else if Key = _lc[I_PROP_TR_FX_TYPE] then
5648 with ChooseTypeForm, vleObjectProperty do
5649 begin // Выбор типа эффекта:
5650 Caption := _lc[I_CAP_FX_TYPE];
5651 lbTypeSelect.Items.Clear();
5653 for b := EFFECT_NONE to EFFECT_FIRE do
5654 lbTypeSelect.Items.Add(EffectToStr(b));
5656 lbTypeSelect.ItemIndex := StrToEffect(Values[Key]);
5658 if ShowModal() = mrOK then
5659 begin
5660 b := lbTypeSelect.ItemIndex;
5661 Values[Key] := EffectToStr(b);
5662 vleObjectPropertyApply(Sender);
5663 end;
5664 end
5665 else if Key = _lc[I_PROP_TR_MONSTER_TYPE] then
5666 with ChooseTypeForm, vleObjectProperty do
5667 begin // Выбор типа монстра:
5668 Caption := _lc[I_CAP_MONSTER_TYPE];
5669 lbTypeSelect.Items.Clear();
5671 for b := MONSTER_DEMON to MONSTER_MAN do
5672 lbTypeSelect.Items.Add(MonsterToStr(b));
5674 lbTypeSelect.ItemIndex := StrToMonster(Values[Key]) - MONSTER_DEMON;
5676 if ShowModal() = mrOK then
5677 begin
5678 b := lbTypeSelect.ItemIndex + MONSTER_DEMON;
5679 Values[Key] := MonsterToStr(b);
5680 vleObjectPropertyApply(Sender);
5681 end;
5682 end
5683 else if Key = _lc[I_PROP_TR_ITEM_TYPE] then
5684 with ChooseTypeForm, vleObjectProperty do
5685 begin // Выбор типа предмета:
5686 Caption := _lc[I_CAP_ITEM_TYPE];
5687 lbTypeSelect.Items.Clear();
5689 for b := ITEM_MEDKIT_SMALL to ITEM_KEY_BLUE do
5690 lbTypeSelect.Items.Add(ItemToStr(b));
5691 lbTypeSelect.Items.Add(ItemToStr(ITEM_BOTTLE));
5692 lbTypeSelect.Items.Add(ItemToStr(ITEM_HELMET));
5693 lbTypeSelect.Items.Add(ItemToStr(ITEM_JETPACK));
5694 lbTypeSelect.Items.Add(ItemToStr(ITEM_INVIS));
5695 lbTypeSelect.Items.Add(ItemToStr(ITEM_WEAPON_FLAMETHROWER));
5696 lbTypeSelect.Items.Add(ItemToStr(ITEM_AMMO_FUELCAN));
5698 b := StrToItem(Values[Key]);
5699 if b >= ITEM_BOTTLE then
5700 b := b - 2;
5701 lbTypeSelect.ItemIndex := b - ITEM_MEDKIT_SMALL;
5703 if ShowModal() = mrOK then
5704 begin
5705 b := lbTypeSelect.ItemIndex + ITEM_MEDKIT_SMALL;
5706 if b >= ITEM_WEAPON_KASTET then
5707 b := b + 2;
5708 Values[Key] := ItemToStr(b);
5709 vleObjectPropertyApply(Sender);
5710 end;
5711 end
5712 else if Key = _lc[I_PROP_TR_SHOT_TYPE] then
5713 with ChooseTypeForm, vleObjectProperty do
5714 begin // Выбор типа предмета:
5715 Caption := _lc[I_PROP_TR_SHOT_TYPE];
5716 lbTypeSelect.Items.Clear();
5718 for b := TRIGGER_SHOT_PISTOL to TRIGGER_SHOT_MAX do
5719 lbTypeSelect.Items.Add(ShotToStr(b));
5721 lbTypeSelect.ItemIndex := StrToShot(Values[Key]);
5723 if ShowModal() = mrOK then
5724 begin
5725 b := lbTypeSelect.ItemIndex;
5726 Values[Key] := ShotToStr(b);
5727 vleObjectPropertyApply(Sender);
5728 end;
5729 end
5730 else if Key = _lc[I_PROP_TR_EFFECT_TYPE] then
5731 with ChooseTypeForm, vleObjectProperty do
5732 begin // Выбор типа эффекта:
5733 Caption := _lc[I_CAP_FX_TYPE];
5734 lbTypeSelect.Items.Clear();
5736 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_PARTICLE]);
5737 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_ANIMATION]);
5738 if Values[Key] = _lc[I_PROP_TR_EFFECT_ANIMATION] then
5739 lbTypeSelect.ItemIndex := 1
5740 else
5741 lbTypeSelect.ItemIndex := 0;
5743 if ShowModal() = mrOK then
5744 begin
5745 b := lbTypeSelect.ItemIndex;
5746 if b = 0 then
5747 Values[Key] := _lc[I_PROP_TR_EFFECT_PARTICLE]
5748 else
5749 Values[Key] := _lc[I_PROP_TR_EFFECT_ANIMATION];
5750 vleObjectPropertyApply(Sender);
5751 end;
5752 end
5753 else if Key = _lc[I_PROP_TR_EFFECT_SUBTYPE] then
5754 with ChooseTypeForm, vleObjectProperty do
5755 begin // Выбор подтипа эффекта:
5756 Caption := _lc[I_CAP_FX_TYPE];
5757 lbTypeSelect.Items.Clear();
5759 if Values[_lc[I_PROP_TR_EFFECT_TYPE]] = _lc[I_PROP_TR_EFFECT_ANIMATION] then
5760 begin
5761 for b := EFFECT_TELEPORT to EFFECT_FIRE do
5762 lbTypeSelect.Items.Add(EffectToStr(b));
5764 lbTypeSelect.ItemIndex := StrToEffect(Values[Key]) - 1;
5765 end else
5766 begin
5767 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_SLIQUID]);
5768 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_LLIQUID]);
5769 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_DLIQUID]);
5770 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_BLOOD]);
5771 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_SPARK]);
5772 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_BUBBLE]);
5773 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_SLIQUID;
5774 if Values[Key] = _lc[I_PROP_TR_EFFECT_LLIQUID] then
5775 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_LLIQUID;
5776 if Values[Key] = _lc[I_PROP_TR_EFFECT_DLIQUID] then
5777 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_DLIQUID;
5778 if Values[Key] = _lc[I_PROP_TR_EFFECT_BLOOD] then
5779 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_BLOOD;
5780 if Values[Key] = _lc[I_PROP_TR_EFFECT_SPARK] then
5781 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_SPARK;
5782 if Values[Key] = _lc[I_PROP_TR_EFFECT_BUBBLE] then
5783 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_BUBBLE;
5784 end;
5786 if ShowModal() = mrOK then
5787 begin
5788 b := lbTypeSelect.ItemIndex;
5790 if Values[_lc[I_PROP_TR_EFFECT_TYPE]] = _lc[I_PROP_TR_EFFECT_ANIMATION] then
5791 Values[Key] := EffectToStr(b + 1)
5792 else begin
5793 Values[Key] := _lc[I_PROP_TR_EFFECT_SLIQUID];
5794 if b = TRIGGER_EFFECT_LLIQUID then
5795 Values[Key] := _lc[I_PROP_TR_EFFECT_LLIQUID];
5796 if b = TRIGGER_EFFECT_DLIQUID then
5797 Values[Key] := _lc[I_PROP_TR_EFFECT_DLIQUID];
5798 if b = TRIGGER_EFFECT_BLOOD then
5799 Values[Key] := _lc[I_PROP_TR_EFFECT_BLOOD];
5800 if b = TRIGGER_EFFECT_SPARK then
5801 Values[Key] := _lc[I_PROP_TR_EFFECT_SPARK];
5802 if b = TRIGGER_EFFECT_BUBBLE then
5803 Values[Key] := _lc[I_PROP_TR_EFFECT_BUBBLE];
5804 end;
5806 vleObjectPropertyApply(Sender);
5807 end;
5808 end
5809 else if Key = _lc[I_PROP_TR_EFFECT_COLOR] then
5810 with vleObjectProperty do
5811 begin // Выбор цвета эффекта:
5812 ColorDialog.Color := StrToIntDef(Values[Key], 0);
5813 if ColorDialog.Execute then
5814 begin
5815 Values[Key] := IntToStr(ColorDialog.Color);
5816 vleObjectPropertyApply(Sender);
5817 end;
5818 end
5819 else if Key = _lc[I_PROP_PANEL_TEX] then
5820 begin // Смена текстуры:
5821 vleObjectProperty.Values[Key] := SelectedTexture();
5822 vleObjectPropertyApply(Sender);
5823 end;
5824 end;
5826 procedure TMainForm.vleObjectPropertyApply(Sender: TObject);
5827 begin
5828 // hack to prevent empty ID in list
5829 RenderPanel.SetFocus();
5830 bApplyProperty.Click();
5831 vleObjectProperty.SetFocus();
5832 end;
5834 procedure TMainForm.aSaveMapExecute(Sender: TObject);
5835 var
5836 FileName, Section, Res: String;
5837 begin
5838 if OpenedMap = '' then
5839 begin
5840 aSaveMapAsExecute(nil);
5841 Exit;
5842 end;
5844 g_ProcessResourceStr(OpenedMap, FileName, Section, Res);
5846 SaveMap(FileName+':\'+Res);
5847 end;
5849 procedure TMainForm.aOpenMapExecute(Sender: TObject);
5850 begin
5851 OpenDialog.Filter := _lc[I_FILE_FILTER_ALL];
5853 if OpenDialog.Execute() then
5854 begin
5855 OpenMapFile(OpenDialog.FileName);
5856 OpenDialog.InitialDir := ExtractFileDir(OpenDialog.FileName);
5857 end;
5858 end;
5860 procedure TMainForm.OpenMapFile(FileName: String);
5861 begin
5862 if (Pos('.ini', LowerCase(ExtractFileName(FileName))) > 0) then
5863 begin // INI карты:
5864 FullClear();
5866 pLoadProgress.Left := (RenderPanel.Width div 2)-(pLoadProgress.Width div 2);
5867 pLoadProgress.Top := (RenderPanel.Height div 2)-(pLoadProgress.Height div 2);
5868 pLoadProgress.Show();
5870 OpenedMap := '';
5871 OpenedWAD := '';
5873 LoadMapOld(FileName);
5875 MainForm.Caption := Format('%s - %s', [FormCaption, ExtractFileName(FileName)]);
5877 pLoadProgress.Hide();
5878 MainForm.FormResize(Self);
5879 end
5880 else // Карты из WAD:
5881 begin
5882 OpenMap(FileName, '');
5883 end;
5884 end;
5886 procedure TMainForm.FormActivate(Sender: TObject);
5887 var
5888 lang: Integer;
5889 config: TConfig;
5890 begin
5891 MainForm.ActiveControl := RenderPanel;
5893 // Язык:
5894 if gLanguage = '' then
5895 begin
5896 lang := SelectLanguageForm.ShowModal();
5897 case lang of
5898 1: gLanguage := LANGUAGE_ENGLISH;
5899 else gLanguage := LANGUAGE_RUSSIAN;
5900 end;
5902 config := TConfig.CreateFile(EditorDir+'Editor.cfg');
5903 config.WriteStr('Editor', 'Language', gLanguage);
5904 config.SaveFile(EditorDir+'Editor.cfg');
5905 config.Free();
5906 end;
5908 //e_WriteLog('Read language file', MSG_NOTIFY);
5909 //g_Language_Load(EditorDir+'\data\'+gLanguage+LANGUAGE_FILE_NAME);
5910 g_Language_Set(gLanguage);
5911 end;
5913 procedure TMainForm.aDeleteMap(Sender: TObject);
5914 var
5915 WAD: TWADEditor_1;
5916 MapList: SArray;
5917 MapName: Char16;
5918 a: Integer;
5919 str: String;
5920 begin
5921 OpenDialog.Filter := _lc[I_FILE_FILTER_WAD];
5923 if not OpenDialog.Execute() then
5924 Exit;
5926 WAD := TWADEditor_1.Create();
5928 if not WAD.ReadFile(OpenDialog.FileName) then
5929 begin
5930 WAD.Free();
5931 Exit;
5932 end;
5934 WAD.CreateImage();
5936 MapList := WAD.GetResourcesList('');
5938 SelectMapForm.Caption := _lc[I_CAP_REMOVE];
5939 SelectMapForm.lbMapList.Items.Clear();
5941 if MapList <> nil then
5942 for a := 0 to High(MapList) do
5943 SelectMapForm.lbMapList.Items.Add(win2utf(MapList[a]));
5945 if (SelectMapForm.ShowModal() = mrOK) then
5946 begin
5947 str := SelectMapForm.lbMapList.Items[SelectMapForm.lbMapList.ItemIndex];
5948 MapName := '';
5949 Move(str[1], MapName[0], Min(16, Length(str)));
5951 if MessageBox(0, PChar(Format(_lc[I_MSG_DELETE_MAP_PROMT],
5952 [MapName, OpenDialog.FileName])),
5953 PChar(_lc[I_MSG_DELETE_MAP]),
5954 MB_ICONQUESTION or MB_YESNO or
5955 MB_DEFBUTTON2) <> mrYes then
5956 Exit;
5958 WAD.RemoveResource('', utf2win(MapName));
5960 MessageBox(0, PChar(Format(_lc[I_MSG_MAP_DELETED_PROMT],
5961 [MapName])),
5962 PChar(_lc[I_MSG_MAP_DELETED]),
5963 MB_ICONINFORMATION or MB_OK or
5964 MB_DEFBUTTON1);
5966 WAD.SaveTo(OpenDialog.FileName);
5968 // Удалили текущую карту - сохранять по старому ее нельзя:
5969 if OpenedMap = (OpenDialog.FileName+':\'+MapName) then
5970 begin
5971 OpenedMap := '';
5972 OpenedWAD := '';
5973 MainForm.Caption := FormCaption;
5974 end;
5975 end;
5977 WAD.Free();
5978 end;
5980 procedure TMainForm.vleObjectPropertyKeyDown(Sender: TObject;
5981 var Key: Word; Shift: TShiftState);
5982 begin
5983 if Key = VK_RETURN then
5984 vleObjectPropertyApply(Sender);
5985 end;
5987 procedure MovePanel(var ID: DWORD; MoveType: Byte);
5988 var
5989 _id, a: Integer;
5990 tmp: TPanel;
5991 begin
5992 if (ID = 0) and (MoveType = 0) then
5993 Exit;
5994 if (ID = DWORD(High(gPanels))) and (MoveType <> 0) then
5995 Exit;
5996 if (ID > DWORD(High(gPanels))) then
5997 Exit;
5999 _id := Integer(ID);
6001 if MoveType = 0 then // to Back
6002 begin
6003 if gTriggers <> nil then
6004 for a := 0 to High(gTriggers) do
6005 with gTriggers[a] do
6006 begin
6007 if TriggerType = TRIGGER_NONE then
6008 Continue;
6010 if TexturePanel = _id then
6011 TexturePanel := 0
6012 else
6013 if (TexturePanel >= 0) and (TexturePanel < _id) then
6014 Inc(TexturePanel);
6016 case TriggerType of
6017 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
6018 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP,
6019 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
6020 if Data.PanelID = _id then
6021 Data.PanelID := 0
6022 else
6023 if (Data.PanelID >= 0) and (Data.PanelID < _id) then
6024 Inc(Data.PanelID);
6026 TRIGGER_SHOT:
6027 if Data.ShotPanelID = _id then
6028 Data.ShotPanelID := 0
6029 else
6030 if (Data.ShotPanelID >= 0) and (Data.ShotPanelID < _id) then
6031 Inc(Data.ShotPanelID);
6032 end;
6033 end;
6035 tmp := gPanels[_id];
6037 for a := _id downto 1 do
6038 gPanels[a] := gPanels[a-1];
6040 gPanels[0] := tmp;
6042 ID := 0;
6043 end
6044 else // to Front
6045 begin
6046 if gTriggers <> nil then
6047 for a := 0 to High(gTriggers) do
6048 with gTriggers[a] do
6049 begin
6050 if TriggerType = TRIGGER_NONE then
6051 Continue;
6053 if TexturePanel = _id then
6054 TexturePanel := High(gPanels)
6055 else
6056 if TexturePanel > _id then
6057 Dec(TexturePanel);
6059 case TriggerType of
6060 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
6061 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP,
6062 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
6063 if Data.PanelID = _id then
6064 Data.PanelID := High(gPanels)
6065 else
6066 if Data.PanelID > _id then
6067 Dec(Data.PanelID);
6069 TRIGGER_SHOT:
6070 if Data.ShotPanelID = _id then
6071 Data.ShotPanelID := High(gPanels)
6072 else
6073 if Data.ShotPanelID > _id then
6074 Dec(Data.ShotPanelID);
6075 end;
6076 end;
6078 tmp := gPanels[_id];
6080 for a := _id to High(gPanels)-1 do
6081 gPanels[a] := gPanels[a+1];
6083 gPanels[High(gPanels)] := tmp;
6085 ID := High(gPanels);
6086 end;
6087 end;
6089 procedure TMainForm.aMoveToBack(Sender: TObject);
6090 var
6091 a: Integer;
6092 begin
6093 if SelectedObjects = nil then
6094 Exit;
6096 for a := 0 to High(SelectedObjects) do
6097 with SelectedObjects[a] do
6098 if Live and (ObjectType = OBJECT_PANEL) then
6099 begin
6100 SelectedObjects[0] := SelectedObjects[a];
6101 SetLength(SelectedObjects, 1);
6102 MovePanel(ID, 0);
6103 FillProperty();
6104 Break;
6105 end;
6106 end;
6108 procedure TMainForm.aMoveToFore(Sender: TObject);
6109 var
6110 a: Integer;
6111 begin
6112 if SelectedObjects = nil then
6113 Exit;
6115 for a := 0 to High(SelectedObjects) do
6116 with SelectedObjects[a] do
6117 if Live and (ObjectType = OBJECT_PANEL) then
6118 begin
6119 SelectedObjects[0] := SelectedObjects[a];
6120 SetLength(SelectedObjects, 1);
6121 MovePanel(ID, 1);
6122 FillProperty();
6123 Break;
6124 end;
6125 end;
6127 procedure TMainForm.aSaveMapAsExecute(Sender: TObject);
6128 var
6129 idx: Integer;
6130 begin
6131 SaveDialog.Filter := _lc[I_FILE_FILTER_WAD];
6133 if not SaveDialog.Execute() then
6134 Exit;
6136 SaveMapForm.GetMaps(SaveDialog.FileName, True);
6138 if SaveMapForm.ShowModal() <> mrOK then
6139 Exit;
6141 SaveDialog.InitialDir := ExtractFileDir(SaveDialog.FileName);
6142 OpenedMap := SaveDialog.FileName+':\'+SaveMapForm.eMapName.Text;
6143 OpenedWAD := SaveDialog.FileName;
6145 idx := RecentFiles.IndexOf(OpenedMap);
6146 // Такая карта уже недавно открывалась:
6147 if idx >= 0 then
6148 RecentFiles.Delete(idx);
6149 RecentFiles.Insert(0, OpenedMap);
6150 RefreshRecentMenu;
6152 SaveMap(OpenedMap);
6154 gMapInfo.FileName := SaveDialog.FileName;
6155 gMapInfo.MapName := SaveMapForm.eMapName.Text;
6156 UpdateCaption(gMapInfo.Name, ExtractFileName(gMapInfo.FileName), gMapInfo.MapName);
6157 end;
6159 procedure TMainForm.aSelectAllExecute(Sender: TObject);
6160 var
6161 a: Integer;
6162 begin
6163 RemoveSelectFromObjects();
6165 case pcObjects.ActivePageIndex+1 of
6166 OBJECT_PANEL:
6167 if gPanels <> nil then
6168 for a := 0 to High(gPanels) do
6169 if gPanels[a].PanelType <> PANEL_NONE then
6170 SelectObject(OBJECT_PANEL, a, True);
6171 OBJECT_ITEM:
6172 if gItems <> nil then
6173 for a := 0 to High(gItems) do
6174 if gItems[a].ItemType <> ITEM_NONE then
6175 SelectObject(OBJECT_ITEM, a, True);
6176 OBJECT_MONSTER:
6177 if gMonsters <> nil then
6178 for a := 0 to High(gMonsters) do
6179 if gMonsters[a].MonsterType <> MONSTER_NONE then
6180 SelectObject(OBJECT_MONSTER, a, True);
6181 OBJECT_AREA:
6182 if gAreas <> nil then
6183 for a := 0 to High(gAreas) do
6184 if gAreas[a].AreaType <> AREA_NONE then
6185 SelectObject(OBJECT_AREA, a, True);
6186 OBJECT_TRIGGER:
6187 if gTriggers <> nil then
6188 for a := 0 to High(gTriggers) do
6189 if gTriggers[a].TriggerType <> TRIGGER_NONE then
6190 SelectObject(OBJECT_TRIGGER, a, True);
6191 end;
6192 end;
6194 procedure TMainForm.tbGridOnClick(Sender: TObject);
6195 begin
6196 DotEnable := not DotEnable;
6197 (Sender as TToolButton).Down := DotEnable;
6198 end;
6200 procedure TMainForm.OnIdle(Sender: TObject; var Done: Boolean);
6201 begin
6202 // FIXME: this is a shitty hack
6203 if not gDataLoaded then
6204 begin
6205 e_WriteLog('Init OpenGL', MSG_NOTIFY);
6206 e_InitGL();
6207 e_WriteLog('Loading data', MSG_NOTIFY);
6208 LoadStdFont('STDTXT', 'STDFONT', gEditorFont);
6209 e_WriteLog('Loading more data', MSG_NOTIFY);
6210 LoadData();
6211 e_WriteLog('Loading even more data', MSG_NOTIFY);
6212 gDataLoaded := True;
6213 MainForm.FormResize(nil);
6214 end;
6215 Draw();
6216 end;
6218 procedure TMainForm.miMapPreviewClick(Sender: TObject);
6219 begin
6220 if PreviewMode = 2 then
6221 Exit;
6223 if PreviewMode = 0 then
6224 begin
6225 Splitter2.Visible := False;
6226 Splitter1.Visible := False;
6227 StatusBar.Visible := False;
6228 PanelObjs.Visible := False;
6229 PanelProps.Visible := False;
6230 MainToolBar.Visible := False;
6231 sbHorizontal.Visible := False;
6232 sbVertical.Visible := False;
6233 end
6234 else
6235 begin
6236 StatusBar.Visible := True;
6237 PanelObjs.Visible := True;
6238 PanelProps.Visible := True;
6239 Splitter2.Visible := True;
6240 Splitter1.Visible := True;
6241 MainToolBar.Visible := True;
6242 sbHorizontal.Visible := True;
6243 sbVertical.Visible := True;
6244 end;
6246 PreviewMode := PreviewMode xor 1;
6247 (Sender as TMenuItem).Checked := PreviewMode > 0;
6249 FormResize(Self);
6250 end;
6252 procedure TMainForm.miLayer1Click(Sender: TObject);
6253 begin
6254 SwitchLayer(LAYER_BACK);
6255 end;
6257 procedure TMainForm.miLayer2Click(Sender: TObject);
6258 begin
6259 SwitchLayer(LAYER_WALLS);
6260 end;
6262 procedure TMainForm.miLayer3Click(Sender: TObject);
6263 begin
6264 SwitchLayer(LAYER_FOREGROUND);
6265 end;
6267 procedure TMainForm.miLayer4Click(Sender: TObject);
6268 begin
6269 SwitchLayer(LAYER_STEPS);
6270 end;
6272 procedure TMainForm.miLayer5Click(Sender: TObject);
6273 begin
6274 SwitchLayer(LAYER_WATER);
6275 end;
6277 procedure TMainForm.miLayer6Click(Sender: TObject);
6278 begin
6279 SwitchLayer(LAYER_ITEMS);
6280 end;
6282 procedure TMainForm.miLayer7Click(Sender: TObject);
6283 begin
6284 SwitchLayer(LAYER_MONSTERS);
6285 end;
6287 procedure TMainForm.miLayer8Click(Sender: TObject);
6288 begin
6289 SwitchLayer(LAYER_AREAS);
6290 end;
6292 procedure TMainForm.miLayer9Click(Sender: TObject);
6293 begin
6294 SwitchLayer(LAYER_TRIGGERS);
6295 end;
6297 procedure TMainForm.tbShowClick(Sender: TObject);
6298 var
6299 a: Integer;
6300 b: Boolean;
6301 begin
6302 b := True;
6303 for a := 0 to High(LayerEnabled) do
6304 b := b and LayerEnabled[a];
6306 b := not b;
6308 ShowLayer(LAYER_BACK, b);
6309 ShowLayer(LAYER_WALLS, b);
6310 ShowLayer(LAYER_FOREGROUND, b);
6311 ShowLayer(LAYER_STEPS, b);
6312 ShowLayer(LAYER_WATER, b);
6313 ShowLayer(LAYER_ITEMS, b);
6314 ShowLayer(LAYER_MONSTERS, b);
6315 ShowLayer(LAYER_AREAS, b);
6316 ShowLayer(LAYER_TRIGGERS, b);
6317 end;
6319 procedure TMainForm.miMiniMapClick(Sender: TObject);
6320 begin
6321 SwitchMap();
6322 end;
6324 procedure TMainForm.miSwitchGridClick(Sender: TObject);
6325 begin
6326 if DotStep = DotStepOne then
6327 DotStep := DotStepTwo
6328 else
6329 DotStep := DotStepOne;
6331 MousePos.X := (MousePos.X div DotStep) * DotStep;
6332 MousePos.Y := (MousePos.Y div DotStep) * DotStep;
6333 end;
6335 procedure TMainForm.miShowEdgesClick(Sender: TObject);
6336 begin
6337 ShowEdges();
6338 end;
6340 procedure TMainForm.miSnapToGridClick(Sender: TObject);
6341 begin
6342 SnapToGrid := not SnapToGrid;
6344 MousePos.X := (MousePos.X div DotStep) * DotStep;
6345 MousePos.Y := (MousePos.Y div DotStep) * DotStep;
6347 miSnapToGrid.Checked := SnapToGrid;
6348 end;
6350 procedure TMainForm.minexttabClick(Sender: TObject);
6351 begin
6352 if pcObjects.ActivePageIndex < pcObjects.PageCount-1 then
6353 pcObjects.ActivePageIndex := pcObjects.ActivePageIndex+1
6354 else
6355 pcObjects.ActivePageIndex := 0;
6356 end;
6358 procedure TMainForm.miSaveMiniMapClick(Sender: TObject);
6359 begin
6360 SaveMiniMapForm.ShowModal();
6361 end;
6363 procedure TMainForm.bClearTextureClick(Sender: TObject);
6364 begin
6365 lbTextureList.ItemIndex := -1;
6366 lTextureWidth.Caption := '';
6367 lTextureHeight.Caption := '';
6368 end;
6370 procedure TMainForm.miPackMapClick(Sender: TObject);
6371 begin
6372 PackMapForm.ShowModal();
6373 end;
6375 procedure TMainForm.miMapTestSettingsClick(Sender: TObject);
6376 begin
6377 MapTestForm.ShowModal();
6378 end;
6380 procedure TMainForm.miTestMapClick(Sender: TObject);
6381 var
6382 cmd, mapWAD, mapToRun, tempWAD: String;
6383 opt: LongWord;
6384 time: Integer;
6385 proc: TProcessUTF8;
6386 res: Boolean;
6387 begin
6388 mapToRun := '';
6389 if OpenedMap <> '' then
6390 begin
6391 // Указываем текущую карту для теста:
6392 g_ProcessResourceStr(OpenedMap, @mapWAD, nil, @mapToRun);
6393 mapToRun := mapWAD + ':\' + mapToRun;
6394 mapToRun := ExtractRelativePath(ExtractFilePath(TestD2dExe) + 'maps/', mapToRun);
6395 end;
6396 // Сохраняем временную карту:
6397 time := 0;
6398 repeat
6399 mapWAD := ExtractFilePath(TestD2dExe) + Format('maps/temp%.4d.wad', [time]);
6400 Inc(time);
6401 until not FileExists(mapWAD);
6402 tempWAD := mapWAD + ':\' + TEST_MAP_NAME;
6403 SaveMap(tempWAD);
6405 tempWAD := ExtractRelativePath(ExtractFilePath(TestD2dExe) + 'maps/', tempWAD);
6406 // Если карта не была открыта, указываем временную в качестве текущей:
6407 if mapToRun = '' then
6408 mapToRun := tempWAD;
6410 // Опции игры:
6411 opt := 32 + 64;
6412 if TestOptionsTwoPlayers then
6413 opt := opt + 1;
6414 if TestOptionsTeamDamage then
6415 opt := opt + 2;
6416 if TestOptionsAllowExit then
6417 opt := opt + 4;
6418 if TestOptionsWeaponStay then
6419 opt := opt + 8;
6420 if TestOptionsMonstersDM then
6421 opt := opt + 16;
6423 // Составляем командную строку:
6424 cmd := '-map "' + mapToRun + '"';
6425 cmd := cmd + ' -testmap "' + tempWAD + '"';
6426 cmd := cmd + ' -gm ' + TestGameMode;
6427 cmd := cmd + ' -limt ' + TestLimTime;
6428 cmd := cmd + ' -lims ' + TestLimScore;
6429 cmd := cmd + ' -opt ' + IntToStr(opt);
6431 if TestMapOnce then
6432 cmd := cmd + ' --close';
6434 cmd := cmd + ' --debug';
6436 // Запускаем:
6437 proc := TProcessUTF8.Create(nil);
6438 proc.Executable := TestD2dExe;
6439 proc.Parameters.Add(cmd);
6440 res := True;
6441 try
6442 proc.Execute();
6443 except
6444 res := False;
6445 end;
6446 if res then
6447 begin
6448 Application.Minimize();
6449 proc.WaitOnExit();
6450 end;
6451 if (not res) or (proc.ExitCode < 0) then
6452 begin
6453 MessageBox(0, 'FIXME',
6454 PChar(_lc[I_MSG_EXEC_ERROR]),
6455 MB_OK or MB_ICONERROR);
6456 end;
6457 proc.Free();
6459 SysUtils.DeleteFile(mapWAD);
6460 Application.Restore();
6461 end;
6463 procedure TMainForm.sbVerticalScroll(Sender: TObject;
6464 ScrollCode: TScrollCode; var ScrollPos: Integer);
6465 begin
6466 MapOffset.Y := -Normalize16(sbVertical.Position);
6467 end;
6469 procedure TMainForm.sbHorizontalScroll(Sender: TObject;
6470 ScrollCode: TScrollCode; var ScrollPos: Integer);
6471 begin
6472 MapOffset.X := -Normalize16(sbHorizontal.Position);
6473 end;
6475 procedure TMainForm.miOpenWadMapClick(Sender: TObject);
6476 begin
6477 if OpenedWAD <> '' then
6478 begin
6479 OpenMap(OpenedWAD, '');
6480 end;
6481 end;
6483 procedure TMainForm.selectall1Click(Sender: TObject);
6484 var
6485 a: Integer;
6486 begin
6487 RemoveSelectFromObjects();
6489 if gPanels <> nil then
6490 for a := 0 to High(gPanels) do
6491 if gPanels[a].PanelType <> PANEL_NONE then
6492 SelectObject(OBJECT_PANEL, a, True);
6494 if gItems <> nil then
6495 for a := 0 to High(gItems) do
6496 if gItems[a].ItemType <> ITEM_NONE then
6497 SelectObject(OBJECT_ITEM, a, True);
6499 if gMonsters <> nil then
6500 for a := 0 to High(gMonsters) do
6501 if gMonsters[a].MonsterType <> MONSTER_NONE then
6502 SelectObject(OBJECT_MONSTER, a, True);
6504 if gAreas <> nil then
6505 for a := 0 to High(gAreas) do
6506 if gAreas[a].AreaType <> AREA_NONE then
6507 SelectObject(OBJECT_AREA, a, True);
6509 if gTriggers <> nil then
6510 for a := 0 to High(gTriggers) do
6511 if gTriggers[a].TriggerType <> TRIGGER_NONE then
6512 SelectObject(OBJECT_TRIGGER, a, True);
6513 end;
6515 procedure TMainForm.Splitter1CanResize(Sender: TObject;
6516 var NewSize: Integer; var Accept: Boolean);
6517 begin
6518 Accept := (NewSize > 140);
6519 end;
6521 procedure TMainForm.Splitter2CanResize(Sender: TObject;
6522 var NewSize: Integer; var Accept: Boolean);
6523 begin
6524 Accept := (NewSize > 110);
6525 end;
6527 procedure TMainForm.vleObjectPropertyEnter(Sender: TObject);
6528 begin
6529 EditingProperties := True;
6530 end;
6532 procedure TMainForm.vleObjectPropertyExit(Sender: TObject);
6533 begin
6534 EditingProperties := False;
6535 end;
6537 procedure TMainForm.FormKeyUp(Sender: TObject; var Key: Word;
6538 Shift: TShiftState);
6539 begin
6540 // Объекты передвигались:
6541 if MainForm.ActiveControl = RenderPanel then
6542 begin
6543 if (Key = VK_NUMPAD4) or
6544 (Key = VK_NUMPAD6) or
6545 (Key = VK_NUMPAD8) or
6546 (Key = VK_NUMPAD5) or
6547 (Key = Ord('V')) then
6548 FillProperty();
6549 end;
6550 // Быстрое превью карты:
6551 if Key = Ord('E') then
6552 begin
6553 if PreviewMode = 2 then
6554 PreviewMode := 0;
6555 end;
6556 end;
6558 end.