DEADSOFTWARE

Movement: Implement WASD move/resize
[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 FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
208 procedure FormResize(Sender: TObject);
209 procedure lbTextureListClick(Sender: TObject);
210 procedure lbTextureListDrawItem(Control: TWinControl; Index: Integer;
211 ARect: TRect; State: TOwnerDrawState);
212 procedure RenderPanelMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
213 procedure RenderPanelMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
214 procedure RenderPanelMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
215 procedure RenderPanelPaint(Sender: TObject);
216 procedure RenderPanelResize(Sender: TObject);
217 procedure Splitter1Moved(Sender: TObject);
218 procedure vleObjectPropertyEditButtonClick(Sender: TObject);
219 procedure vleObjectPropertyApply(Sender: TObject);
220 procedure vleObjectPropertyGetPickList(Sender: TObject; const KeyName: String; Values: TStrings);
221 procedure vleObjectPropertyKeyDown(Sender: TObject; var Key: Word;
222 Shift: TShiftState);
223 procedure tbGridOnClick(Sender: TObject);
224 procedure miMapPreviewClick(Sender: TObject);
225 procedure miLayer1Click(Sender: TObject);
226 procedure miLayer2Click(Sender: TObject);
227 procedure miLayer3Click(Sender: TObject);
228 procedure miLayer4Click(Sender: TObject);
229 procedure miLayer5Click(Sender: TObject);
230 procedure miLayer6Click(Sender: TObject);
231 procedure miLayer7Click(Sender: TObject);
232 procedure miLayer8Click(Sender: TObject);
233 procedure miLayer9Click(Sender: TObject);
234 procedure tbShowClick(Sender: TObject);
235 procedure miSnapToGridClick(Sender: TObject);
236 procedure miMiniMapClick(Sender: TObject);
237 procedure miSwitchGridClick(Sender: TObject);
238 procedure miShowEdgesClick(Sender: TObject);
239 procedure minexttabClick(Sender: TObject);
240 procedure miSaveMiniMapClick(Sender: TObject);
241 procedure bClearTextureClick(Sender: TObject);
242 procedure miPackMapClick(Sender: TObject);
243 procedure aRecentFileExecute(Sender: TObject);
244 procedure miMapTestSettingsClick(Sender: TObject);
245 procedure miTestMapClick(Sender: TObject);
246 procedure sbVerticalScroll(Sender: TObject; ScrollCode: TScrollCode;
247 var ScrollPos: Integer);
248 procedure sbHorizontalScroll(Sender: TObject; ScrollCode: TScrollCode;
249 var ScrollPos: Integer);
250 procedure miOpenWadMapClick(Sender: TObject);
251 procedure selectall1Click(Sender: TObject);
252 procedure Splitter1CanResize(Sender: TObject; var NewSize: Integer;
253 var Accept: Boolean);
254 procedure Splitter2CanResize(Sender: TObject; var NewSize: Integer;
255 var Accept: Boolean);
256 procedure vleObjectPropertyEnter(Sender: TObject);
257 procedure vleObjectPropertyExit(Sender: TObject);
258 procedure FormKeyUp(Sender: TObject; var Key: Word;
259 Shift: TShiftState);
260 private
261 procedure Draw();
262 procedure OnIdle(Sender: TObject; var Done: Boolean);
263 public
264 procedure RefreshRecentMenu();
265 end;
267 const
268 LAYER_BACK = 0;
269 LAYER_WALLS = 1;
270 LAYER_FOREGROUND = 2;
271 LAYER_STEPS = 3;
272 LAYER_WATER = 4;
273 LAYER_ITEMS = 5;
274 LAYER_MONSTERS = 6;
275 LAYER_AREAS = 7;
276 LAYER_TRIGGERS = 8;
278 TEST_MAP_NAME = '$$$_TEST_$$$';
279 LANGUAGE_FILE_NAME = '_Editor.txt';
281 var
282 MainForm: TMainForm;
283 EditorDir: String;
284 OpenedMap: String;
285 OpenedWAD: String;
287 DotColor: TColor;
288 DotEnable: Boolean;
289 DotStep: Byte;
290 DotStepOne, DotStepTwo: Byte;
291 DotSize: Byte;
292 DrawTexturePanel: Boolean;
293 DrawPanelSize: Boolean;
294 BackColor: TColor;
295 PreviewColor: TColor;
296 Scale: Byte;
297 RecentCount: Integer;
298 RecentFiles: TStringList;
299 slInvalidTextures: TStringList;
301 TestGameMode: String;
302 TestLimTime: String;
303 TestLimScore: String;
304 TestOptionsTwoPlayers: Boolean;
305 TestOptionsTeamDamage: Boolean;
306 TestOptionsAllowExit: Boolean;
307 TestOptionsWeaponStay: Boolean;
308 TestOptionsMonstersDM: Boolean;
309 TestD2dExe: String;
310 TestMapOnce: Boolean;
312 LayerEnabled: Array [LAYER_BACK..LAYER_TRIGGERS] of Boolean =
313 (True, True, True, True, True, True, True, True, True);
314 PreviewMode: Byte = 0;
315 gLanguage: String;
317 FormCaption: String;
320 procedure OpenMap(FileName: String; mapN: String);
321 function AddTexture(aWAD, aSection, aTex: String; silent: Boolean): Boolean;
322 procedure RemoveSelectFromObjects();
323 procedure ChangeShownProperty(Name: String; NewValue: String);
325 implementation
327 uses
328 f_options, e_graphics, e_log, GL, Math,
329 f_mapoptions, g_basic, f_about, f_mapoptimization,
330 f_mapcheck, f_addresource_texture, g_textures,
331 f_activationtype, f_keys,
332 MAPREADER, f_selectmap, f_savemap, WADEDITOR, WADSTRUCT, MAPDEF,
333 g_map, f_saveminimap, f_addresource, CONFIG, f_packmap,
334 f_addresource_sound, f_maptest, f_choosetype,
335 g_language, f_selectlang, ClipBrd;
337 const
338 UNDO_DELETE_PANEL = 1;
339 UNDO_DELETE_ITEM = 2;
340 UNDO_DELETE_AREA = 3;
341 UNDO_DELETE_MONSTER = 4;
342 UNDO_DELETE_TRIGGER = 5;
343 UNDO_ADD_PANEL = 6;
344 UNDO_ADD_ITEM = 7;
345 UNDO_ADD_AREA = 8;
346 UNDO_ADD_MONSTER = 9;
347 UNDO_ADD_TRIGGER = 10;
348 UNDO_MOVE_PANEL = 11;
349 UNDO_MOVE_ITEM = 12;
350 UNDO_MOVE_AREA = 13;
351 UNDO_MOVE_MONSTER = 14;
352 UNDO_MOVE_TRIGGER = 15;
353 UNDO_RESIZE_PANEL = 16;
354 UNDO_RESIZE_TRIGGER = 17;
356 MOUSEACTION_NONE = 0;
357 MOUSEACTION_DRAWPANEL = 1;
358 MOUSEACTION_DRAWTRIGGER = 2;
359 MOUSEACTION_MOVEOBJ = 3;
360 MOUSEACTION_RESIZE = 4;
361 MOUSEACTION_MOVEMAP = 5;
362 MOUSEACTION_DRAWPRESS = 6;
363 MOUSEACTION_NOACTION = 7;
365 RESIZETYPE_NONE = 0;
366 RESIZETYPE_VERTICAL = 1;
367 RESIZETYPE_HORIZONTAL = 2;
369 RESIZEDIR_NONE = 0;
370 RESIZEDIR_DOWN = 1;
371 RESIZEDIR_UP = 2;
372 RESIZEDIR_RIGHT = 3;
373 RESIZEDIR_LEFT = 4;
375 SELECTFLAG_NONE = 0;
376 SELECTFLAG_TELEPORT = 1;
377 SELECTFLAG_DOOR = 2;
378 SELECTFLAG_TEXTURE = 3;
379 SELECTFLAG_LIFT = 4;
380 SELECTFLAG_MONSTER = 5;
381 SELECTFLAG_SPAWNPOINT = 6;
382 SELECTFLAG_SHOTPANEL = 7;
383 SELECTFLAG_SELECTED = 8;
385 RECENT_FILES_MENU_START = 11;
387 CLIPBOARD_SIG = 'DF:ED';
389 type
390 TUndoRec = record
391 UndoType: Byte;
392 case Byte of
393 UNDO_DELETE_PANEL: (Panel: ^TPanel);
394 UNDO_DELETE_ITEM: (Item: TItem);
395 UNDO_DELETE_AREA: (Area: TArea);
396 UNDO_DELETE_MONSTER: (Monster: TMonster);
397 UNDO_DELETE_TRIGGER: (Trigger: TTrigger);
398 UNDO_ADD_PANEL,
399 UNDO_ADD_ITEM,
400 UNDO_ADD_AREA,
401 UNDO_ADD_MONSTER,
402 UNDO_ADD_TRIGGER: (AddID: DWORD);
403 UNDO_MOVE_PANEL,
404 UNDO_MOVE_ITEM,
405 UNDO_MOVE_AREA,
406 UNDO_MOVE_MONSTER,
407 UNDO_MOVE_TRIGGER: (MoveID: DWORD; dX, dY: Integer);
408 UNDO_RESIZE_PANEL,
409 UNDO_RESIZE_TRIGGER: (ResizeID: DWORD; dW, dH: Integer);
410 end;
412 TCopyRec = record
413 ObjectType: Byte;
414 ID: Cardinal;
415 case Byte of
416 OBJECT_PANEL: (Panel: ^TPanel);
417 OBJECT_ITEM: (Item: TItem);
418 OBJECT_AREA: (Area: TArea);
419 OBJECT_MONSTER: (Monster: TMonster);
420 OBJECT_TRIGGER: (Trigger: TTrigger);
421 end;
423 TCopyRecArray = Array of TCopyRec;
425 var
426 gEditorFont: DWORD;
427 gDataLoaded: Boolean = False;
428 ShowMap: Boolean = False;
429 DrawRect: PRect = nil;
430 SnapToGrid: Boolean = True;
432 MousePos: Types.TPoint;
433 LastMovePoint: Types.TPoint;
434 MouseLDown: Boolean;
435 MouseRDown: Boolean;
436 MouseLDownPos: Types.TPoint;
437 MouseRDownPos: Types.TPoint;
438 WASDOffset: TPoint;
440 SelectFlag: Byte = SELECTFLAG_NONE;
441 MouseAction: Byte = MOUSEACTION_NONE;
442 ResizeType: Byte = RESIZETYPE_NONE;
443 ResizeDirection: Byte = RESIZEDIR_NONE;
445 DrawPressRect: Boolean = False;
446 EditingProperties: Boolean = False;
448 UndoBuffer: Array of Array of TUndoRec = nil;
451 {$R *.lfm}
453 //----------------------------------------
454 //Далее идут вспомогательные процедуры
455 //----------------------------------------
457 function NameToBool(Name: String): Boolean;
458 begin
459 if Name = BoolNames[True] then
460 Result := True
461 else
462 Result := False;
463 end;
465 function NameToDir(Name: String): TDirection;
466 begin
467 if Name = DirNames[D_LEFT] then
468 Result := D_LEFT
469 else
470 Result := D_RIGHT;
471 end;
473 function NameToDirAdv(Name: String): Byte;
474 begin
475 if Name = DirNamesAdv[1] then
476 Result := 1
477 else
478 if Name = DirNamesAdv[2] then
479 Result := 2
480 else
481 if Name = DirNamesAdv[3] then
482 Result := 3
483 else
484 Result := 0;
485 end;
487 function ActivateToStr(ActivateType: Byte): String;
488 begin
489 Result := '';
491 if ByteBool(ACTIVATE_PLAYERCOLLIDE and ActivateType) then
492 Result := Result + '+PC';
493 if ByteBool(ACTIVATE_MONSTERCOLLIDE and ActivateType) then
494 Result := Result + '+MC';
495 if ByteBool(ACTIVATE_PLAYERPRESS and ActivateType) then
496 Result := Result + '+PP';
497 if ByteBool(ACTIVATE_MONSTERPRESS and ActivateType) then
498 Result := Result + '+MP';
499 if ByteBool(ACTIVATE_SHOT and ActivateType) then
500 Result := Result + '+SH';
501 if ByteBool(ACTIVATE_NOMONSTER and ActivateType) then
502 Result := Result + '+NM';
504 if (Result <> '') and (Result[1] = '+') then
505 Delete(Result, 1, 1);
506 end;
508 function StrToActivate(Str: String): Byte;
509 begin
510 Result := 0;
512 if Pos('PC', Str) > 0 then
513 Result := ACTIVATE_PLAYERCOLLIDE;
514 if Pos('MC', Str) > 0 then
515 Result := Result or ACTIVATE_MONSTERCOLLIDE;
516 if Pos('PP', Str) > 0 then
517 Result := Result or ACTIVATE_PLAYERPRESS;
518 if Pos('MP', Str) > 0 then
519 Result := Result or ACTIVATE_MONSTERPRESS;
520 if Pos('SH', Str) > 0 then
521 Result := Result or ACTIVATE_SHOT;
522 if Pos('NM', Str) > 0 then
523 Result := Result or ACTIVATE_NOMONSTER;
524 end;
526 function KeyToStr(Key: Byte): String;
527 begin
528 Result := '';
530 if ByteBool(KEY_RED and Key) then
531 Result := Result + '+RK';
532 if ByteBool(KEY_GREEN and Key) then
533 Result := Result + '+GK';
534 if ByteBool(KEY_BLUE and Key) then
535 Result := Result + '+BK';
536 if ByteBool(KEY_REDTEAM and Key) then
537 Result := Result + '+RT';
538 if ByteBool(KEY_BLUETEAM and Key) then
539 Result := Result + '+BT';
541 if (Result <> '') and (Result[1] = '+') then
542 Delete(Result, 1, 1);
543 end;
545 function StrToKey(Str: String): Byte;
546 begin
547 Result := 0;
549 if Pos('RK', Str) > 0 then
550 Result := KEY_RED;
551 if Pos('GK', Str) > 0 then
552 Result := Result or KEY_GREEN;
553 if Pos('BK', Str) > 0 then
554 Result := Result or KEY_BLUE;
555 if Pos('RT', Str) > 0 then
556 Result := Result or KEY_REDTEAM;
557 if Pos('BT', Str) > 0 then
558 Result := Result or KEY_BLUETEAM;
559 end;
561 function EffectToStr(Effect: Byte): String;
562 begin
563 if Effect in [EFFECT_TELEPORT..EFFECT_FIRE] then
564 Result := EffectNames[Effect]
565 else
566 Result := EffectNames[EFFECT_NONE];
567 end;
569 function StrToEffect(Str: String): Byte;
570 var
571 i: Integer;
572 begin
573 Result := EFFECT_NONE;
574 for i := EFFECT_TELEPORT to EFFECT_FIRE do
575 if EffectNames[i] = Str then
576 begin
577 Result := i;
578 Exit;
579 end;
580 end;
582 function MonsterToStr(MonType: Byte): String;
583 begin
584 if MonType in [MONSTER_DEMON..MONSTER_MAN] then
585 Result := MonsterNames[MonType]
586 else
587 Result := MonsterNames[MONSTER_ZOMBY];
588 end;
590 function StrToMonster(Str: String): Byte;
591 var
592 i: Integer;
593 begin
594 Result := MONSTER_ZOMBY;
595 for i := MONSTER_DEMON to MONSTER_MAN do
596 if MonsterNames[i] = Str then
597 begin
598 Result := i;
599 Exit;
600 end;
601 end;
603 function ItemToStr(ItemType: Byte): String;
604 begin
605 if ItemType in [ITEM_MEDKIT_SMALL..ITEM_MAX] then
606 Result := ItemNames[ItemType]
607 else
608 Result := ItemNames[ITEM_AMMO_BULLETS];
609 end;
611 function StrToItem(Str: String): Byte;
612 var
613 i: Integer;
614 begin
615 Result := ITEM_AMMO_BULLETS;
616 for i := ITEM_MEDKIT_SMALL to ITEM_MAX do
617 if ItemNames[i] = Str then
618 begin
619 Result := i;
620 Exit;
621 end;
622 end;
624 function ShotToStr(ShotType: Byte): String;
625 begin
626 if ShotType in [TRIGGER_SHOT_PISTOL..TRIGGER_SHOT_MAX] then
627 Result := ShotNames[ShotType]
628 else
629 Result := ShotNames[TRIGGER_SHOT_PISTOL];
630 end;
632 function StrToShot(Str: String): Byte;
633 var
634 i: Integer;
635 begin
636 Result := TRIGGER_SHOT_PISTOL;
637 for i := TRIGGER_SHOT_PISTOL to TRIGGER_SHOT_MAX do
638 if ShotNames[i] = Str then
639 begin
640 Result := i;
641 Exit;
642 end;
643 end;
645 function SelectedObjectCount(): Word;
646 var
647 a: Integer;
648 begin
649 Result := 0;
651 if SelectedObjects = nil then
652 Exit;
654 for a := 0 to High(SelectedObjects) do
655 if SelectedObjects[a].Live then
656 Result := Result + 1;
657 end;
659 function GetFirstSelected(): Integer;
660 var
661 a: Integer;
662 begin
663 Result := -1;
665 if SelectedObjects = nil then
666 Exit;
668 for a := 0 to High(SelectedObjects) do
669 if SelectedObjects[a].Live then
670 begin
671 Result := a;
672 Exit;
673 end;
674 end;
676 function Normalize16(x: Integer): Integer;
677 begin
678 Result := (x div 16) * 16;
679 end;
681 procedure MoveMap(X, Y: Integer);
682 var
683 rx, ry, ScaleSz: Integer;
684 begin
685 with MainForm.RenderPanel do
686 begin
687 ScaleSz := 16 div Scale;
688 // Размер видимой части карты:
689 rx := min(Normalize16(Width), Normalize16(gMapInfo.Width)) div 2;
690 ry := min(Normalize16(Height), Normalize16(gMapInfo.Height)) div 2;
691 // Место клика на мини-карте:
692 MapOffset.X := X - (Width-max(gMapInfo.Width div ScaleSz, 1)-1);
693 MapOffset.Y := Y - 1;
694 // Это же место на "большой" карте:
695 MapOffset.X := MapOffset.X * ScaleSz;
696 MapOffset.Y := MapOffset.Y * ScaleSz;
697 // Левый верхний угол новой видимой части карты:
698 MapOffset.X := MapOffset.X - rx;
699 MapOffset.Y := MapOffset.Y - ry;
700 // Выход за границы:
701 if MapOffset.X < 0 then
702 MapOffset.X := 0;
703 if MapOffset.Y < 0 then
704 MapOffset.Y := 0;
705 if MapOffset.X > MainForm.sbHorizontal.Max then
706 MapOffset.X := MainForm.sbHorizontal.Max;
707 if MapOffset.Y > MainForm.sbVertical.Max then
708 MapOffset.Y := MainForm.sbVertical.Max;
709 // Кратно 16:
710 MapOffset.X := Normalize16(MapOffset.X);
711 MapOffset.Y := Normalize16(MapOffset.Y);
712 end;
714 MainForm.sbHorizontal.Position := MapOffset.X;
715 MainForm.sbVertical.Position := MapOffset.Y;
717 MapOffset.X := -MapOffset.X;
718 MapOffset.Y := -MapOffset.Y;
720 MainForm.Resize();
721 end;
723 function IsTexturedPanel(PanelType: Word): Boolean;
724 begin
725 Result := WordBool(PanelType and (PANEL_WALL or PANEL_BACK or PANEL_FORE or
726 PANEL_STEP or PANEL_OPENDOOR or PANEL_CLOSEDOOR or
727 PANEL_WATER or PANEL_ACID1 or PANEL_ACID2));
728 end;
730 procedure FillProperty();
731 var
732 _id: DWORD;
733 str: String;
734 begin
735 MainForm.vleObjectProperty.Strings.Clear();
737 // Отображаем свойства если выделен только один объект:
738 if SelectedObjectCount() <> 1 then
739 Exit;
741 _id := GetFirstSelected();
742 if not SelectedObjects[_id].Live then
743 Exit;
745 with MainForm.vleObjectProperty do
746 with ItemProps[InsertRow(_lc[I_PROP_ID], IntToStr(SelectedObjects[_id].ID), True)] do
747 begin
748 EditStyle := esSimple;
749 ReadOnly := True;
750 end;
752 case SelectedObjects[0].ObjectType of
753 OBJECT_PANEL:
754 begin
755 with MainForm.vleObjectProperty,
756 gPanels[SelectedObjects[_id].ID] do
757 begin
758 with ItemProps[InsertRow(_lc[I_PROP_X], IntToStr(X), True)] do
759 begin
760 EditStyle := esSimple;
761 MaxLength := 5;
762 end;
764 with ItemProps[InsertRow(_lc[I_PROP_Y], IntToStr(Y), True)] do
765 begin
766 EditStyle := esSimple;
767 MaxLength := 5;
768 end;
770 with ItemProps[InsertRow(_lc[I_PROP_WIDTH], IntToStr(Width), True)] do
771 begin
772 EditStyle := esSimple;
773 MaxLength := 5;
774 end;
776 with ItemProps[InsertRow(_lc[I_PROP_HEIGHT], IntToStr(Height), True)] do
777 begin
778 EditStyle := esSimple;
779 MaxLength := 5;
780 end;
782 with ItemProps[InsertRow(_lc[I_PROP_PANEL_TYPE], GetPanelName(PanelType), True)] do
783 begin
784 EditStyle := esEllipsis;
785 ReadOnly := True;
786 end;
788 if IsTexturedPanel(PanelType) then
789 begin // Может быть текстура
790 with ItemProps[InsertRow(_lc[I_PROP_PANEL_TEX], TextureName, True)] do
791 begin
792 EditStyle := esEllipsis;
793 ReadOnly := True;
794 end;
796 if TextureName <> '' then
797 begin // Есть текстура
798 with ItemProps[InsertRow(_lc[I_PROP_PANEL_ALPHA], IntToStr(Alpha), True)] do
799 begin
800 EditStyle := esSimple;
801 MaxLength := 3;
802 end;
804 with ItemProps[InsertRow(_lc[I_PROP_PANEL_BLEND], BoolNames[Blending], True)] do
805 begin
806 EditStyle := esPickList;
807 ReadOnly := True;
808 end;
809 end;
810 end;
811 end;
812 end;
814 OBJECT_ITEM:
815 begin
816 with MainForm.vleObjectProperty,
817 gItems[SelectedObjects[_id].ID] do
818 begin
819 with ItemProps[InsertRow(_lc[I_PROP_X], IntToStr(X), True)] do
820 begin
821 EditStyle := esSimple;
822 MaxLength := 5;
823 end;
825 with ItemProps[InsertRow(_lc[I_PROP_Y], IntToStr(Y), True)] do
826 begin
827 EditStyle := esSimple;
828 MaxLength := 5;
829 end;
831 with ItemProps[InsertRow(_lc[I_PROP_DM_ONLY], BoolNames[OnlyDM], True)] do
832 begin
833 EditStyle := esPickList;
834 ReadOnly := True;
835 end;
837 with ItemProps[InsertRow(_lc[I_PROP_ITEM_FALLS], BoolNames[Fall], True)] do
838 begin
839 EditStyle := esPickList;
840 ReadOnly := True;
841 end;
842 end;
843 end;
845 OBJECT_MONSTER:
846 begin
847 with MainForm.vleObjectProperty,
848 gMonsters[SelectedObjects[_id].ID] do
849 begin
850 with ItemProps[InsertRow(_lc[I_PROP_X], IntToStr(X), True)] do
851 begin
852 EditStyle := esSimple;
853 MaxLength := 5;
854 end;
856 with ItemProps[InsertRow(_lc[I_PROP_Y], IntToStr(Y), True)] do
857 begin
858 EditStyle := esSimple;
859 MaxLength := 5;
860 end;
862 with ItemProps[InsertRow(_lc[I_PROP_DIRECTION], DirNames[Direction], True)] do
863 begin
864 EditStyle := esPickList;
865 ReadOnly := True;
866 end;
867 end;
868 end;
870 OBJECT_AREA:
871 begin
872 with MainForm.vleObjectProperty,
873 gAreas[SelectedObjects[_id].ID] do
874 begin
875 with ItemProps[InsertRow(_lc[I_PROP_X], IntToStr(X), True)] do
876 begin
877 EditStyle := esSimple;
878 MaxLength := 5;
879 end;
881 with ItemProps[InsertRow(_lc[I_PROP_Y], IntToStr(Y), True)] do
882 begin
883 EditStyle := esSimple;
884 MaxLength := 5;
885 end;
887 with ItemProps[InsertRow(_lc[I_PROP_DIRECTION], DirNames[Direction], True)] do
888 begin
889 EditStyle := esPickList;
890 ReadOnly := True;
891 end;
892 end;
893 end;
895 OBJECT_TRIGGER:
896 begin
897 with MainForm.vleObjectProperty,
898 gTriggers[SelectedObjects[_id].ID] do
899 begin
900 with ItemProps[InsertRow(_lc[I_PROP_TR_TYPE], GetTriggerName(TriggerType), True)] do
901 begin
902 EditStyle := esSimple;
903 ReadOnly := True;
904 end;
906 with ItemProps[InsertRow(_lc[I_PROP_X], IntToStr(X), True)] do
907 begin
908 EditStyle := esSimple;
909 MaxLength := 5;
910 end;
912 with ItemProps[InsertRow(_lc[I_PROP_Y], IntToStr(Y), True)] do
913 begin
914 EditStyle := esSimple;
915 MaxLength := 5;
916 end;
918 with ItemProps[InsertRow(_lc[I_PROP_WIDTH], IntToStr(Width), True)] do
919 begin
920 EditStyle := esSimple;
921 MaxLength := 5;
922 end;
924 with ItemProps[InsertRow(_lc[I_PROP_HEIGHT], IntToStr(Height), True)] do
925 begin
926 EditStyle := esSimple;
927 MaxLength := 5;
928 end;
930 with ItemProps[InsertRow(_lc[I_PROP_TR_ENABLED], BoolNames[Enabled], True)] do
931 begin
932 EditStyle := esPickList;
933 ReadOnly := True;
934 end;
936 with ItemProps[InsertRow(_lc[I_PROP_TR_TEXTURE_PANEL], IntToStr(TexturePanel), True)] do
937 begin
938 EditStyle := esEllipsis;
939 ReadOnly := True;
940 end;
942 with ItemProps[InsertRow(_lc[I_PROP_TR_ACTIVATION], ActivateToStr(ActivateType), True)] do
943 begin
944 EditStyle := esEllipsis;
945 ReadOnly := True;
946 end;
948 with ItemProps[InsertRow(_lc[I_PROP_TR_KEYS], KeyToStr(Key), True)] do
949 begin
950 EditStyle := esEllipsis;
951 ReadOnly := True;
952 end;
954 case TriggerType of
955 TRIGGER_EXIT:
956 begin
957 str := win2utf(Data.MapName);
958 with ItemProps[InsertRow(_lc[I_PROP_TR_NEXT_MAP], str, True)] do
959 begin
960 EditStyle := esEllipsis;
961 ReadOnly := True;
962 end;
963 end;
965 TRIGGER_TELEPORT:
966 begin
967 with ItemProps[InsertRow(_lc[I_PROP_TR_TELEPORT_TO], Format('(%d:%d)', [Data.TargetPoint.X, Data.TargetPoint.Y]), True)] do
968 begin
969 EditStyle := esEllipsis;
970 ReadOnly := True;
971 end;
973 with ItemProps[InsertRow(_lc[I_PROP_TR_D2D], BoolNames[Data.d2d_teleport], True)] do
974 begin
975 EditStyle := esPickList;
976 ReadOnly := True;
977 end;
979 with ItemProps[InsertRow(_lc[I_PROP_TR_TELEPORT_SILENT], BoolNames[Data.silent_teleport], True)] do
980 begin
981 EditStyle := esPickList;
982 ReadOnly := True;
983 end;
985 with ItemProps[InsertRow(_lc[I_PROP_TR_TELEPORT_DIR], DirNamesAdv[Data.TlpDir], True)] do
986 begin
987 EditStyle := esPickList;
988 ReadOnly := True;
989 end;
990 end;
992 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR,
993 TRIGGER_DOOR, TRIGGER_DOOR5:
994 begin
995 with ItemProps[InsertRow(_lc[I_PROP_TR_DOOR_PANEL], IntToStr(Data.PanelID), True)] do
996 begin
997 EditStyle := esEllipsis;
998 ReadOnly := True;
999 end;
1001 with ItemProps[InsertRow(_lc[I_PROP_TR_SILENT], BoolNames[Data.NoSound], True)] do
1002 begin
1003 EditStyle := esPickList;
1004 ReadOnly := True;
1005 end;
1007 with ItemProps[InsertRow(_lc[I_PROP_TR_D2D], BoolNames[Data.d2d_doors], True)] do
1008 begin
1009 EditStyle := esPickList;
1010 ReadOnly := True;
1011 end;
1012 end;
1014 TRIGGER_CLOSETRAP, TRIGGER_TRAP:
1015 begin
1016 with ItemProps[InsertRow(_lc[I_PROP_TR_TRAP_PANEL], IntToStr(Data.PanelID), True)] do
1017 begin
1018 EditStyle := esEllipsis;
1019 ReadOnly := True;
1020 end;
1022 with ItemProps[InsertRow(_lc[I_PROP_TR_SILENT], BoolNames[Data.NoSound], True)] do
1023 begin
1024 EditStyle := esPickList;
1025 ReadOnly := True;
1026 end;
1028 with ItemProps[InsertRow(_lc[I_PROP_TR_D2D], BoolNames[Data.d2d_doors], True)] do
1029 begin
1030 EditStyle := esPickList;
1031 ReadOnly := True;
1032 end;
1033 end;
1035 TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF,
1036 TRIGGER_ONOFF:
1037 begin
1038 with ItemProps[InsertRow(_lc[I_PROP_TR_EX_AREA],
1039 Format('(%d:%d %d:%d)', [Data.tX, Data.tY, Data.tWidth, Data.tHeight]), True)] do
1040 begin
1041 EditStyle := esEllipsis;
1042 ReadOnly := True;
1043 end;
1045 with ItemProps[InsertRow(_lc[I_PROP_TR_EX_DELAY], IntToStr(Data.Wait), True)] do
1046 begin
1047 EditStyle := esSimple;
1048 MaxLength := 5;
1049 end;
1051 with ItemProps[InsertRow(_lc[I_PROP_TR_EX_COUNT], IntToStr(Data.Count), True)] do
1052 begin
1053 EditStyle := esSimple;
1054 MaxLength := 5;
1055 end;
1057 with ItemProps[InsertRow(_lc[I_PROP_TR_EX_MONSTER], IntToStr(Data.MonsterID-1), True)] do
1058 begin
1059 EditStyle := esEllipsis;
1060 ReadOnly := True;
1061 end;
1063 if TriggerType = TRIGGER_PRESS then
1064 with ItemProps[InsertRow(_lc[I_PROP_TR_EX_RANDOM], BoolNames[Data.ExtRandom], True)] do
1065 begin
1066 EditStyle := esPickList;
1067 ReadOnly := True;
1068 end;
1069 end;
1071 TRIGGER_SECRET:
1074 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
1075 begin
1076 with ItemProps[InsertRow(_lc[I_PROP_TR_LIFT_PANEL], IntToStr(Data.PanelID), True)] do
1077 begin
1078 EditStyle := esEllipsis;
1079 ReadOnly := True;
1080 end;
1082 with ItemProps[InsertRow(_lc[I_PROP_TR_SILENT], BoolNames[Data.NoSound], True)] do
1083 begin
1084 EditStyle := esPickList;
1085 ReadOnly := True;
1086 end;
1088 with ItemProps[InsertRow(_lc[I_PROP_TR_D2D], BoolNames[Data.d2d_doors], True)] do
1089 begin
1090 EditStyle := esPickList;
1091 ReadOnly := True;
1092 end;
1093 end;
1095 TRIGGER_TEXTURE:
1096 begin
1097 with ItemProps[InsertRow(_lc[I_PROP_TR_TEXTURE_ONCE], BoolNames[Data.ActivateOnce], True)] do
1098 begin
1099 EditStyle := esPickList;
1100 ReadOnly := True;
1101 end;
1103 with ItemProps[InsertRow(_lc[I_PROP_TR_TEXTURE_ANIM_ONCE], BoolNames[Data.AnimOnce], True)] do
1104 begin
1105 EditStyle := esPickList;
1106 ReadOnly := True;
1107 end;
1108 end;
1110 TRIGGER_SOUND:
1111 begin
1112 str := win2utf(Data.SoundName);
1113 with ItemProps[InsertRow(_lc[I_PROP_TR_SOUND_NAME], str, True)] do
1114 begin
1115 EditStyle := esEllipsis;
1116 ReadOnly := True;
1117 end;
1119 with ItemProps[InsertRow(_lc[I_PROP_TR_SOUND_VOLUME], IntToStr(Data.Volume), True)] do
1120 begin
1121 EditStyle := esSimple;
1122 MaxLength := 3;
1123 end;
1125 with ItemProps[InsertRow(_lc[I_PROP_TR_SOUND_PAN], IntToStr(Data.Pan), True)] do
1126 begin
1127 EditStyle := esSimple;
1128 MaxLength := 3;
1129 end;
1131 with ItemProps[InsertRow(_lc[I_PROP_TR_SOUND_COUNT], IntToStr(Data.PlayCount), True)] do
1132 begin
1133 EditStyle := esSimple;
1134 MaxLength := 3;
1135 end;
1137 with ItemProps[InsertRow(_lc[I_PROP_TR_SOUND_LOCAL], BoolNames[Data.Local], True)] do
1138 begin
1139 EditStyle := esPickList;
1140 ReadOnly := True;
1141 end;
1143 with ItemProps[InsertRow(_lc[I_PROP_TR_SOUND_SWITCH], BoolNames[Data.SoundSwitch], True)] do
1144 begin
1145 EditStyle := esPickList;
1146 ReadOnly := True;
1147 end;
1148 end;
1150 TRIGGER_SPAWNMONSTER:
1151 begin
1152 with ItemProps[InsertRow(_lc[I_PROP_TR_MONSTER_TYPE], MonsterToStr(Data.MonType), True)] do
1153 begin
1154 EditStyle := esEllipsis;
1155 ReadOnly := True;
1156 end;
1158 with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_TO],
1159 Format('(%d:%d)', [Data.MonPos.X, Data.MonPos.Y]), True)] do
1160 begin
1161 EditStyle := esEllipsis;
1162 ReadOnly := True;
1163 end;
1165 with ItemProps[InsertRow(_lc[I_PROP_DIRECTION], DirNames[TDirection(Data.MonDir)], True)] do
1166 begin
1167 EditStyle := esPickList;
1168 ReadOnly := True;
1169 end;
1171 with ItemProps[InsertRow(_lc[I_PROP_TR_HEALTH], IntToStr(Data.MonHealth), True)] do
1172 begin
1173 EditStyle := esSimple;
1174 MaxLength := 5;
1175 end;
1177 with ItemProps[InsertRow(_lc[I_PROP_TR_MONSTER_ACTIVE], BoolNames[Data.MonActive], True)] do
1178 begin
1179 EditStyle := esPickList;
1180 ReadOnly := True;
1181 end;
1183 with ItemProps[InsertRow(_lc[I_PROP_TR_COUNT], IntToStr(Data.MonCount), True)] do
1184 begin
1185 EditStyle := esSimple;
1186 MaxLength := 5;
1187 end;
1189 with ItemProps[InsertRow(_lc[I_PROP_TR_FX_TYPE], EffectToStr(Data.MonEffect), True)] do
1190 begin
1191 EditStyle := esEllipsis;
1192 ReadOnly := True;
1193 end;
1195 with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_MAX], IntToStr(Data.MonMax), True)] do
1196 begin
1197 EditStyle := esSimple;
1198 MaxLength := 5;
1199 end;
1201 with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_DELAY], IntToStr(Data.MonDelay), True)] do
1202 begin
1203 EditStyle := esSimple;
1204 MaxLength := 5;
1205 end;
1207 case Data.MonBehav of
1208 1: str := _lc[I_PROP_TR_MONSTER_BEHAVIOUR_1];
1209 2: str := _lc[I_PROP_TR_MONSTER_BEHAVIOUR_2];
1210 3: str := _lc[I_PROP_TR_MONSTER_BEHAVIOUR_3];
1211 4: str := _lc[I_PROP_TR_MONSTER_BEHAVIOUR_4];
1212 5: str := _lc[I_PROP_TR_MONSTER_BEHAVIOUR_5];
1213 else str := _lc[I_PROP_TR_MONSTER_BEHAVIOUR_0];
1214 end;
1215 with ItemProps[InsertRow(_lc[I_PROP_TR_MONSTER_BEHAVIOUR], str, True)] do
1216 begin
1217 EditStyle := esPickList;
1218 ReadOnly := True;
1219 end;
1220 end;
1222 TRIGGER_SPAWNITEM:
1223 begin
1224 with ItemProps[InsertRow(_lc[I_PROP_TR_ITEM_TYPE], ItemToStr(Data.ItemType), True)] do
1225 begin
1226 EditStyle := esEllipsis;
1227 ReadOnly := True;
1228 end;
1230 with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_TO],
1231 Format('(%d:%d)', [Data.ItemPos.X, Data.ItemPos.Y]), True)] do
1232 begin
1233 EditStyle := esEllipsis;
1234 ReadOnly := True;
1235 end;
1237 with ItemProps[InsertRow(_lc[I_PROP_DM_ONLY], BoolNames[Data.ItemOnlyDM], True)] do
1238 begin
1239 EditStyle := esPickList;
1240 ReadOnly := True;
1241 end;
1243 with ItemProps[InsertRow(_lc[I_PROP_ITEM_FALLS], BoolNames[Data.ItemFalls], True)] do
1244 begin
1245 EditStyle := esPickList;
1246 ReadOnly := True;
1247 end;
1249 with ItemProps[InsertRow(_lc[I_PROP_TR_COUNT], IntToStr(Data.ItemCount), True)] do
1250 begin
1251 EditStyle := esSimple;
1252 MaxLength := 5;
1253 end;
1255 with ItemProps[InsertRow(_lc[I_PROP_TR_FX_TYPE], EffectToStr(Data.ItemEffect), True)] do
1256 begin
1257 EditStyle := esEllipsis;
1258 ReadOnly := True;
1259 end;
1261 with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_MAX], IntToStr(Data.ItemMax), True)] do
1262 begin
1263 EditStyle := esSimple;
1264 MaxLength := 5;
1265 end;
1267 with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_DELAY], IntToStr(Data.ItemDelay), True)] do
1268 begin
1269 EditStyle := esSimple;
1270 MaxLength := 5;
1271 end;
1272 end;
1274 TRIGGER_MUSIC:
1275 begin
1276 str := win2utf(Data.MusicName);
1277 with ItemProps[InsertRow(_lc[I_PROP_TR_MUSIC_NAME], str, True)] do
1278 begin
1279 EditStyle := esEllipsis;
1280 ReadOnly := True;
1281 end;
1283 if Data.MusicAction = 1 then
1284 str := _lc[I_PROP_TR_MUSIC_ON]
1285 else
1286 str := _lc[I_PROP_TR_MUSIC_OFF];
1288 with ItemProps[InsertRow(_lc[I_PROP_TR_MUSIC_ACT], str, True)] do
1289 begin
1290 EditStyle := esPickList;
1291 ReadOnly := True;
1292 end;
1293 end;
1295 TRIGGER_PUSH:
1296 begin
1297 with ItemProps[InsertRow(_lc[I_PROP_TR_PUSH_ANGLE], IntToStr(Data.PushAngle), True)] do
1298 begin
1299 EditStyle := esSimple;
1300 MaxLength := 4;
1301 end;
1302 with ItemProps[InsertRow(_lc[I_PROP_TR_PUSH_FORCE], IntToStr(Data.PushForce), True)] do
1303 begin
1304 EditStyle := esSimple;
1305 MaxLength := 4;
1306 end;
1307 with ItemProps[InsertRow(_lc[I_PROP_TR_PUSH_RESET], BoolNames[Data.ResetVel], True)] do
1308 begin
1309 EditStyle := esPickList;
1310 ReadOnly := True;
1311 end;
1312 end;
1314 TRIGGER_SCORE:
1315 begin
1316 case Data.ScoreAction of
1317 1: str := _lc[I_PROP_TR_SCORE_ACT_1];
1318 2: str := _lc[I_PROP_TR_SCORE_ACT_2];
1319 3: str := _lc[I_PROP_TR_SCORE_ACT_3];
1320 else str := _lc[I_PROP_TR_SCORE_ACT_0];
1321 end;
1322 with ItemProps[InsertRow(_lc[I_PROP_TR_SCORE_ACT], str, True)] do
1323 begin
1324 EditStyle := esPickList;
1325 ReadOnly := True;
1326 end;
1327 with ItemProps[InsertRow(_lc[I_PROP_TR_COUNT], IntToStr(Data.ScoreCount), True)] do
1328 begin
1329 EditStyle := esSimple;
1330 MaxLength := 3;
1331 end;
1332 case Data.ScoreTeam of
1333 1: str := _lc[I_PROP_TR_SCORE_TEAM_1];
1334 2: str := _lc[I_PROP_TR_SCORE_TEAM_2];
1335 3: str := _lc[I_PROP_TR_SCORE_TEAM_3];
1336 else str := _lc[I_PROP_TR_SCORE_TEAM_0];
1337 end;
1338 with ItemProps[InsertRow(_lc[I_PROP_TR_SCORE_TEAM], str, True)] do
1339 begin
1340 EditStyle := esPickList;
1341 ReadOnly := True;
1342 end;
1343 with ItemProps[InsertRow(_lc[I_PROP_TR_SCORE_CON], BoolNames[Data.ScoreCon], True)] do
1344 begin
1345 EditStyle := esPickList;
1346 ReadOnly := True;
1347 end;
1348 with ItemProps[InsertRow(_lc[I_PROP_TR_SCORE_MSG], BoolNames[Data.ScoreMsg], True)] do
1349 begin
1350 EditStyle := esPickList;
1351 ReadOnly := True;
1352 end;
1353 end;
1355 TRIGGER_MESSAGE:
1356 begin
1357 case Data.MessageKind of
1358 1: str := _lc[I_PROP_TR_MESSAGE_KIND_1];
1359 else str := _lc[I_PROP_TR_MESSAGE_KIND_0];
1360 end;
1361 with ItemProps[InsertRow(_lc[I_PROP_TR_MESSAGE_KIND], str, True)] do
1362 begin
1363 EditStyle := esPickList;
1364 ReadOnly := True;
1365 end;
1366 case Data.MessageSendTo of
1367 1: str := _lc[I_PROP_TR_MESSAGE_TO_1];
1368 2: str := _lc[I_PROP_TR_MESSAGE_TO_2];
1369 3: str := _lc[I_PROP_TR_MESSAGE_TO_3];
1370 4: str := _lc[I_PROP_TR_MESSAGE_TO_4];
1371 5: str := _lc[I_PROP_TR_MESSAGE_TO_5];
1372 else str := _lc[I_PROP_TR_MESSAGE_TO_0];
1373 end;
1374 with ItemProps[InsertRow(_lc[I_PROP_TR_MESSAGE_TO], str, True)] do
1375 begin
1376 EditStyle := esPickList;
1377 ReadOnly := True;
1378 end;
1379 str := win2utf(Data.MessageText);
1380 with ItemProps[InsertRow(_lc[I_PROP_TR_MESSAGE_TEXT], str, True)] do
1381 begin
1382 EditStyle := esSimple;
1383 MaxLength := 100;
1384 end;
1385 with ItemProps[InsertRow(_lc[I_PROP_TR_MESSAGE_TIME], IntToStr(Data.MessageTime), True)] do
1386 begin
1387 EditStyle := esSimple;
1388 MaxLength := 5;
1389 end;
1390 end;
1392 TRIGGER_DAMAGE:
1393 begin
1394 with ItemProps[InsertRow(_lc[I_PROP_TR_DAMAGE_VALUE], IntToStr(Data.DamageValue), True)] do
1395 begin
1396 EditStyle := esSimple;
1397 MaxLength := 5;
1398 end;
1399 with ItemProps[InsertRow(_lc[I_PROP_TR_INTERVAL], IntToStr(Data.DamageInterval), True)] do
1400 begin
1401 EditStyle := esSimple;
1402 MaxLength := 5;
1403 end;
1404 end;
1406 TRIGGER_HEALTH:
1407 begin
1408 with ItemProps[InsertRow(_lc[I_PROP_TR_HEALTH], IntToStr(Data.HealValue), True)] do
1409 begin
1410 EditStyle := esSimple;
1411 MaxLength := 5;
1412 end;
1413 with ItemProps[InsertRow(_lc[I_PROP_TR_INTERVAL], IntToStr(Data.HealInterval), True)] do
1414 begin
1415 EditStyle := esSimple;
1416 MaxLength := 5;
1417 end;
1418 with ItemProps[InsertRow(_lc[I_PROP_TR_HEALTH_MAX], BoolNames[Data.HealMax], True)] do
1419 begin
1420 EditStyle := esPickList;
1421 ReadOnly := True;
1422 end;
1423 with ItemProps[InsertRow(_lc[I_PROP_TR_SILENT], BoolNames[Data.HealSilent], True)] do
1424 begin
1425 EditStyle := esPickList;
1426 ReadOnly := True;
1427 end;
1428 end;
1430 TRIGGER_SHOT:
1431 begin
1432 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_TYPE], ShotToStr(Data.ShotType), True)] do
1433 begin
1434 EditStyle := esEllipsis;
1435 ReadOnly := True;
1436 end;
1438 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_SOUND], BoolNames[Data.ShotSound], True)] do
1439 begin
1440 EditStyle := esPickList;
1441 ReadOnly := True;
1442 end;
1444 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_PANEL], IntToStr(Data.ShotPanelID), True)] do
1445 begin
1446 EditStyle := esEllipsis;
1447 ReadOnly := True;
1448 end;
1450 case Data.ShotTarget of
1451 1: str := _lc[I_PROP_TR_SHOT_TO_1];
1452 2: str := _lc[I_PROP_TR_SHOT_TO_2];
1453 3: str := _lc[I_PROP_TR_SHOT_TO_3];
1454 4: str := _lc[I_PROP_TR_SHOT_TO_4];
1455 5: str := _lc[I_PROP_TR_SHOT_TO_5];
1456 6: str := _lc[I_PROP_TR_SHOT_TO_6];
1457 else str := _lc[I_PROP_TR_SHOT_TO_0];
1458 end;
1459 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_TO], str, True)] do
1460 begin
1461 EditStyle := esPickList;
1462 ReadOnly := True;
1463 end;
1465 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_SIGHT], IntToStr(Data.ShotIntSight), True)] do
1466 begin
1467 EditStyle := esSimple;
1468 MaxLength := 3;
1469 end;
1471 case Data.ShotAim of
1472 1: str := _lc[I_PROP_TR_SHOT_AIM_1];
1473 2: str := _lc[I_PROP_TR_SHOT_AIM_2];
1474 3: str := _lc[I_PROP_TR_SHOT_AIM_3];
1475 else str := _lc[I_PROP_TR_SHOT_AIM_0];
1476 end;
1477 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_AIM], str, True)-1] do
1478 begin
1479 EditStyle := esPickList;
1480 ReadOnly := True;
1481 end;
1483 with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_TO],
1484 Format('(%d:%d)', [Data.ShotPos.X, Data.ShotPos.Y]), True)] do
1485 begin
1486 EditStyle := esEllipsis;
1487 ReadOnly := True;
1488 end;
1490 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_ANGLE], IntToStr(Data.ShotAngle), True)] do
1491 begin
1492 EditStyle := esSimple;
1493 MaxLength := 4;
1494 end;
1496 with ItemProps[InsertRow(_lc[I_PROP_TR_EX_DELAY], IntToStr(Data.ShotWait), True)] do
1497 begin
1498 EditStyle := esSimple;
1499 MaxLength := 5;
1500 end;
1502 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_ACC], IntToStr(Data.ShotAccuracy), True)] do
1503 begin
1504 EditStyle := esSimple;
1505 MaxLength := 5;
1506 end;
1508 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_AMMO], IntToStr(Data.ShotAmmo), True)] do
1509 begin
1510 EditStyle := esSimple;
1511 MaxLength := 5;
1512 end;
1514 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_RELOAD], IntToStr(Data.ShotIntReload), True)] do
1515 begin
1516 EditStyle := esSimple;
1517 MaxLength := 4;
1518 end;
1519 end;
1521 TRIGGER_EFFECT:
1522 begin
1523 with ItemProps[InsertRow(_lc[I_PROP_TR_COUNT], IntToStr(Data.FXCount), True)] do
1524 begin
1525 EditStyle := esSimple;
1526 MaxLength := 3;
1527 end;
1529 if Data.FXType = 0 then
1530 str := _lc[I_PROP_TR_EFFECT_PARTICLE]
1531 else
1532 str := _lc[I_PROP_TR_EFFECT_ANIMATION];
1533 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_TYPE], str, True)] do
1534 begin
1535 EditStyle := esEllipsis;
1536 ReadOnly := True;
1537 end;
1539 str := '';
1540 if Data.FXType = 0 then
1541 case Data.FXSubType of
1542 TRIGGER_EFFECT_SLIQUID:
1543 str := _lc[I_PROP_TR_EFFECT_SLIQUID];
1544 TRIGGER_EFFECT_LLIQUID:
1545 str := _lc[I_PROP_TR_EFFECT_LLIQUID];
1546 TRIGGER_EFFECT_DLIQUID:
1547 str := _lc[I_PROP_TR_EFFECT_DLIQUID];
1548 TRIGGER_EFFECT_BLOOD:
1549 str := _lc[I_PROP_TR_EFFECT_BLOOD];
1550 TRIGGER_EFFECT_SPARK:
1551 str := _lc[I_PROP_TR_EFFECT_SPARK];
1552 TRIGGER_EFFECT_BUBBLE:
1553 str := _lc[I_PROP_TR_EFFECT_BUBBLE];
1554 end;
1555 if Data.FXType = 1 then
1556 begin
1557 if (Data.FXSubType = 0) or (Data.FXSubType > EFFECT_FIRE) then
1558 Data.FXSubType := EFFECT_TELEPORT;
1559 str := EffectToStr(Data.FXSubType);
1560 end;
1561 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_SUBTYPE], str, True)] do
1562 begin
1563 EditStyle := esEllipsis;
1564 ReadOnly := True;
1565 end;
1567 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_COLOR], IntToStr(Data.FXColorR or (Data.FXColorG shl 8) or (Data.FXColorB shl 16)), True)] do
1568 begin
1569 EditStyle := esEllipsis;
1570 ReadOnly := True;
1571 end;
1573 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_CENTER], BoolNames[Data.FXPos = 0], True)] do
1574 begin
1575 EditStyle := esPickList;
1576 ReadOnly := True;
1577 end;
1579 with ItemProps[InsertRow(_lc[I_PROP_TR_EX_DELAY], IntToStr(Data.FXWait), True)] do
1580 begin
1581 EditStyle := esSimple;
1582 MaxLength := 5;
1583 end;
1585 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_VELX], IntToStr(Data.FXVelX), True)] do
1586 begin
1587 EditStyle := esSimple;
1588 MaxLength := 4;
1589 end;
1591 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_VELY], IntToStr(Data.FXVelY), True)] do
1592 begin
1593 EditStyle := esSimple;
1594 MaxLength := 4;
1595 end;
1597 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_SPL], IntToStr(Data.FXSpreadL), True)] do
1598 begin
1599 EditStyle := esSimple;
1600 MaxLength := 3;
1601 end;
1603 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_SPR], IntToStr(Data.FXSpreadR), True)] do
1604 begin
1605 EditStyle := esSimple;
1606 MaxLength := 3;
1607 end;
1609 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_SPU], IntToStr(Data.FXSpreadU), True)] do
1610 begin
1611 EditStyle := esSimple;
1612 MaxLength := 3;
1613 end;
1615 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_SPD], IntToStr(Data.FXSpreadD), True)] do
1616 begin
1617 EditStyle := esSimple;
1618 MaxLength := 3;
1619 end;
1620 end;
1621 end; //case TriggerType
1622 end;
1623 end; // OBJECT_TRIGGER:
1624 end;
1625 end;
1627 procedure ChangeShownProperty(Name: String; NewValue: String);
1628 var
1629 row: Integer;
1630 begin
1631 if SelectedObjectCount() <> 1 then
1632 Exit;
1633 if not SelectedObjects[GetFirstSelected()].Live then
1634 Exit;
1636 // Есть ли такой ключ:
1637 if MainForm.vleObjectProperty.FindRow(Name, row) then
1638 begin
1639 MainForm.vleObjectProperty.Values[Name] := NewValue;
1640 end;
1641 end;
1643 procedure SelectObject(fObjectType: Byte; fID: DWORD; Multi: Boolean);
1644 var
1645 a: Integer;
1646 b: Boolean;
1647 begin
1648 if Multi then
1649 begin
1650 b := False;
1652 // Уже выделен - убираем:
1653 if SelectedObjects <> nil then
1654 for a := 0 to High(SelectedObjects) do
1655 with SelectedObjects[a] do
1656 if Live and (ID = fID) and
1657 (ObjectType = fObjectType) then
1658 begin
1659 Live := False;
1660 b := True;
1661 end;
1663 if b then
1664 Exit;
1666 SetLength(SelectedObjects, Length(SelectedObjects)+1);
1668 with SelectedObjects[High(SelectedObjects)] do
1669 begin
1670 ObjectType := fObjectType;
1671 ID := fID;
1672 Live := True;
1673 end;
1674 end
1675 else // not Multi
1676 begin
1677 SetLength(SelectedObjects, 1);
1679 with SelectedObjects[0] do
1680 begin
1681 ObjectType := fObjectType;
1682 ID := fID;
1683 Live := True;
1684 end;
1685 end;
1687 MainForm.miCopy.Enabled := True;
1688 MainForm.miCut.Enabled := True;
1690 if fObjectType = OBJECT_PANEL then
1691 begin
1692 MainForm.miToFore.Enabled := True;
1693 MainForm.miToBack.Enabled := True;
1694 end;
1695 end;
1697 procedure RemoveSelectFromObjects();
1698 begin
1699 SelectedObjects := nil;
1700 DrawPressRect := False;
1701 MouseLDown := False;
1702 MouseRDown := False;
1703 MouseAction := MOUSEACTION_NONE;
1704 SelectFlag := SELECTFLAG_NONE;
1705 ResizeType := RESIZETYPE_NONE;
1706 ResizeDirection := RESIZEDIR_NONE;
1708 MainForm.vleObjectProperty.Strings.Clear();
1710 MainForm.miCopy.Enabled := False;
1711 MainForm.miCut.Enabled := False;
1712 MainForm.miToFore.Enabled := False;
1713 MainForm.miToBack.Enabled := False;
1714 end;
1716 procedure DeleteSelectedObjects();
1717 var
1718 i, a, ii: Integer;
1719 b: Boolean;
1720 begin
1721 if SelectedObjects = nil then
1722 Exit;
1724 b := False;
1725 i := 0;
1727 for a := 0 to High(SelectedObjects) do
1728 with SelectedObjects[a] do
1729 if Live then
1730 begin
1731 if not b then
1732 begin
1733 SetLength(UndoBuffer, Length(UndoBuffer)+1);
1734 i := High(UndoBuffer);
1735 b := True;
1736 end;
1738 SetLength(UndoBuffer[i], Length(UndoBuffer[i])+1);
1739 ii := High(UndoBuffer[i]);
1741 case ObjectType of
1742 OBJECT_PANEL:
1743 begin
1744 UndoBuffer[i, ii].UndoType := UNDO_DELETE_PANEL;
1745 New(UndoBuffer[i, ii].Panel);
1746 UndoBuffer[i, ii].Panel^ := gPanels[ID];
1747 end;
1748 OBJECT_ITEM:
1749 begin
1750 UndoBuffer[i, ii].UndoType := UNDO_DELETE_ITEM;
1751 UndoBuffer[i, ii].Item := gItems[ID];
1752 end;
1753 OBJECT_AREA:
1754 begin
1755 UndoBuffer[i, ii].UndoType := UNDO_DELETE_AREA;
1756 UndoBuffer[i, ii].Area := gAreas[ID];
1757 end;
1758 OBJECT_TRIGGER:
1759 begin
1760 UndoBuffer[i, ii].UndoType := UNDO_DELETE_TRIGGER;
1761 UndoBuffer[i, ii].Trigger := gTriggers[ID];
1762 end;
1763 end;
1765 RemoveObject(ID, ObjectType);
1766 end;
1768 RemoveSelectFromObjects();
1770 MainForm.miUndo.Enabled := UndoBuffer <> nil;
1771 end;
1773 procedure Undo_Add(ObjectType: Byte; ID: DWORD; Group: Boolean = False);
1774 var
1775 i, ii: Integer;
1776 begin
1777 if (not Group) or (Length(UndoBuffer) = 0) then
1778 SetLength(UndoBuffer, Length(UndoBuffer)+1);
1779 SetLength(UndoBuffer[High(UndoBuffer)], Length(UndoBuffer[High(UndoBuffer)])+1);
1780 i := High(UndoBuffer);
1781 ii := High(UndoBuffer[i]);
1783 case ObjectType of
1784 OBJECT_PANEL:
1785 UndoBuffer[i, ii].UndoType := UNDO_ADD_PANEL;
1786 OBJECT_ITEM:
1787 UndoBuffer[i, ii].UndoType := UNDO_ADD_ITEM;
1788 OBJECT_MONSTER:
1789 UndoBuffer[i, ii].UndoType := UNDO_ADD_MONSTER;
1790 OBJECT_AREA:
1791 UndoBuffer[i, ii].UndoType := UNDO_ADD_AREA;
1792 OBJECT_TRIGGER:
1793 UndoBuffer[i, ii].UndoType := UNDO_ADD_TRIGGER;
1794 end;
1796 UndoBuffer[i, ii].AddID := ID;
1798 MainForm.miUndo.Enabled := UndoBuffer <> nil;
1799 end;
1801 procedure FullClear();
1802 begin
1803 RemoveSelectFromObjects();
1804 ClearMap();
1805 LoadSky(gMapInfo.SkyName);
1806 UndoBuffer := nil;
1807 slInvalidTextures.Clear();
1808 MapCheckForm.lbErrorList.Clear();
1809 MapCheckForm.mErrorDescription.Clear();
1811 MainForm.miUndo.Enabled := False;
1812 MainForm.sbHorizontal.Position := 0;
1813 MainForm.sbVertical.Position := 0;
1814 MainForm.FormResize(nil);
1815 MainForm.Caption := FormCaption;
1816 OpenedMap := '';
1817 OpenedWAD := '';
1818 end;
1820 procedure ErrorMessageBox(str: String);
1821 begin
1822 MessageBox(0, PChar(str), PChar(_lc[I_MSG_ERROR]),
1823 MB_ICONINFORMATION or MB_OK or MB_DEFBUTTON1);
1824 end;
1826 function CheckProperty(): Boolean;
1827 var
1828 _id: Integer;
1829 begin
1830 Result := False;
1832 _id := GetFirstSelected();
1834 if SelectedObjects[_id].ObjectType = OBJECT_PANEL then
1835 with gPanels[SelectedObjects[_id].ID] do
1836 begin
1837 if TextureWidth <> 0 then
1838 if StrToIntDef(MainForm.vleObjectProperty.Values[_lc[I_PROP_WIDTH]], 1) mod TextureWidth <> 0 then
1839 begin
1840 ErrorMessageBox(Format(_lc[I_MSG_WRONG_TEXWIDTH],
1841 [TextureWidth]));
1842 Exit;
1843 end;
1845 if TextureHeight <> 0 then
1846 if StrToIntDef(Trim(MainForm.vleObjectProperty.Values[_lc[I_PROP_HEIGHT]]), 1) mod TextureHeight <> 0 then
1847 begin
1848 ErrorMessageBox(Format(_lc[I_MSG_WRONG_TEXHEIGHT],
1849 [TextureHeight]));
1850 Exit;
1851 end;
1853 if IsTexturedPanel(PanelType) and (TextureName <> '') then
1854 if not (StrToIntDef(MainForm.vleObjectProperty.Values[_lc[I_PROP_PANEL_ALPHA]], -1) in [0..255]) then
1855 begin
1856 ErrorMessageBox(_lc[I_MSG_WRONG_ALPHA]);
1857 Exit;
1858 end;
1859 end;
1861 if SelectedObjects[_id].ObjectType in [OBJECT_PANEL, OBJECT_TRIGGER] then
1862 if (StrToIntDef(MainForm.vleObjectProperty.Values[_lc[I_PROP_WIDTH]], 0) <= 0) or
1863 (StrToIntDef(MainForm.vleObjectProperty.Values[_lc[I_PROP_HEIGHT]], 0) <= 0) then
1864 begin
1865 ErrorMessageBox(_lc[I_MSG_WRONG_SIZE]);
1866 Exit;
1867 end;
1869 if (Trim(MainForm.vleObjectProperty.Values[_lc[I_PROP_X]]) = '') or
1870 (Trim(MainForm.vleObjectProperty.Values[_lc[I_PROP_Y]]) = '') then
1871 begin
1872 ErrorMessageBox(_lc[I_MSG_WRONG_XY]);
1873 Exit;
1874 end;
1876 Result := True;
1877 end;
1879 procedure SelectTexture(ID: Integer);
1880 begin
1881 MainForm.lbTextureList.ItemIndex := ID;
1882 MainForm.lbTextureListClick(nil);
1883 end;
1885 function AddTexture(aWAD, aSection, aTex: String; silent: Boolean): Boolean;
1886 var
1887 a, FrameLen: Integer;
1888 ok: Boolean;
1889 FileName: String;
1890 ResourceName: String;
1891 FullResourceName: String;
1892 SectionName: String;
1893 Data: Pointer;
1894 Width, Height: Word;
1895 fn: String;
1896 begin
1897 Data := nil;
1898 FrameLen := 0;
1899 Width := 0;
1900 Height := 0;
1902 if aSection = '..' then
1903 SectionName := ''
1904 else
1905 SectionName := aSection;
1907 if aWAD = _lc[I_WAD_SPECIAL_MAP] then
1908 begin // Файл карты
1909 g_ProcessResourceStr(OpenedMap, @fn, nil, nil);
1910 //FileName := EditorDir+'maps\'+ExtractFileName(fn);
1911 FileName := fn;
1912 ResourceName := ':'+SectionName+'\'+aTex;
1913 end
1914 else
1915 if aWAD = _lc[I_WAD_SPECIAL_TEXS] then
1916 begin // Спец. текстуры
1917 FileName := '';
1918 ResourceName := aTex;
1919 end
1920 else
1921 begin // Внешний WAD
1922 FileName := EditorDir+'wads/'+aWAD;
1923 ResourceName := aWAD+':'+SectionName+'\'+aTex;
1924 end;
1926 ok := True;
1928 // Есть ли уже такая текстура:
1929 for a := 0 to MainForm.lbTextureList.Items.Count-1 do
1930 if ResourceName = MainForm.lbTextureList.Items[a] then
1931 begin
1932 if not silent then
1933 ErrorMessageBox(Format(_lc[I_MSG_TEXTURE_ALREADY],
1934 [ResourceName]));
1935 ok := False;
1936 end;
1938 // Название ресурса <= 64 символов:
1939 if Length(ResourceName) > 64 then
1940 begin
1941 if not silent then
1942 ErrorMessageBox(Format(_lc[I_MSG_RES_NAME_64],
1943 [ResourceName]));
1944 ok := False;
1945 end;
1947 if ok then
1948 begin
1949 a := -1;
1950 if aWAD = _lc[I_WAD_SPECIAL_TEXS] then
1951 begin
1952 a := MainForm.lbTextureList.Items.Add(ResourceName);
1953 if not silent then
1954 SelectTexture(a);
1955 Result := True;
1956 Exit;
1957 end;
1959 FullResourceName := FileName+':'+SectionName+'\'+aTex;
1961 if IsAnim(FullResourceName) then
1962 begin // Аним. текстура
1963 GetFrame(FullResourceName, Data, FrameLen, Width, Height);
1965 if g_CreateTextureMemorySize(Data, FrameLen, ResourceName, 0, 0, Width, Height, 1) then
1966 a := MainForm.lbTextureList.Items.Add(ResourceName);
1967 end
1968 else // Обычная текстура
1969 begin
1970 if g_CreateTextureWAD(ResourceName, FullResourceName) then
1971 a := MainForm.lbTextureList.Items.Add(ResourceName);
1972 end;
1973 if (a > -1) and (not silent) then
1974 SelectTexture(a);
1975 end;
1977 Result := ok;
1978 end;
1980 procedure UpdateCaption(sMap, sFile, sRes: String);
1981 begin
1982 with MainForm do
1983 if (sFile = '') and (sRes = '') and (sMap = '') then
1984 Caption := FormCaption
1985 else
1986 if sMap = '' then
1987 Caption := Format('%s - %s:%s', [FormCaption, sFile, sRes])
1988 else
1989 if (sFile <> '') and (sRes <> '') then
1990 Caption := Format('%s - %s (%s:%s)', [FormCaption, sMap, sFile, sRes])
1991 else
1992 Caption := Format('%s - %s', [FormCaption, sMap]);
1993 end;
1995 procedure OpenMap(FileName: String; mapN: String);
1996 var
1997 MapName: String;
1998 idx: Integer;
1999 begin
2000 SelectMapForm.Caption := _lc[I_CAP_OPEN];
2001 SelectMapForm.GetMaps(FileName);
2003 if (FileName = OpenedWAD) and
2004 (OpenedMap <> '') then
2005 begin
2006 MapName := OpenedMap;
2007 while (Pos(':\', MapName) > 0) do
2008 Delete(MapName, 1, Pos(':\', MapName) + 1);
2010 idx := SelectMapForm.lbMapList.Items.IndexOf(MapName);
2011 SelectMapForm.lbMapList.ItemIndex := idx;
2012 end
2013 else
2014 if SelectMapForm.lbMapList.Count > 0 then
2015 SelectMapForm.lbMapList.ItemIndex := 0
2016 else
2017 SelectMapForm.lbMapList.ItemIndex := -1;
2019 if mapN = '' then
2020 idx := -1
2021 else
2022 idx := SelectMapForm.lbMapList.Items.IndexOf(mapN);
2024 if idx < 0 then
2025 begin
2026 if (SelectMapForm.ShowModal() = mrOK) and
2027 (SelectMapForm.lbMapList.ItemIndex <> -1) then
2028 idx := SelectMapForm.lbMapList.ItemIndex
2029 else
2030 Exit;
2031 end;
2033 MapName := SelectMapForm.lbMapList.Items[idx];
2035 with MainForm do
2036 begin
2037 FullClear();
2039 pLoadProgress.Left := (RenderPanel.Width div 2)-(pLoadProgress.Width div 2);
2040 pLoadProgress.Top := (RenderPanel.Height div 2)-(pLoadProgress.Height div 2);
2041 pLoadProgress.Show();
2043 OpenedMap := FileName+':\'+MapName;
2044 OpenedWAD := FileName;
2046 idx := RecentFiles.IndexOf(OpenedMap);
2047 // Такая карта уже недавно открывалась:
2048 if idx >= 0 then
2049 RecentFiles.Delete(idx);
2050 RecentFiles.Insert(0, OpenedMap);
2051 RefreshRecentMenu();
2053 LoadMap(OpenedMap);
2055 pLoadProgress.Hide();
2056 FormResize(nil);
2058 lbTextureList.Sorted := True;
2059 lbTextureList.Sorted := False;
2061 UpdateCaption(gMapInfo.Name, ExtractFileName(FileName), MapName);
2062 end;
2063 end;
2065 procedure MoveSelectedObjects(Wall, alt: Boolean; dx, dy: Integer);
2066 var
2067 okX, okY: Boolean;
2068 a: Integer;
2069 begin
2070 if SelectedObjects = nil then
2071 Exit;
2073 okX := True;
2074 okY := True;
2076 if Wall then
2077 for a := 0 to High(SelectedObjects) do
2078 if SelectedObjects[a].Live then
2079 begin
2080 if ObjectCollideLevel(SelectedObjects[a].ID, SelectedObjects[a].ObjectType, dx, 0) then
2081 okX := False;
2083 if ObjectCollideLevel(SelectedObjects[a].ID, SelectedObjects[a].ObjectType, 0, dy) then
2084 okY := False;
2086 if (not okX) or (not okY) then
2087 Break;
2088 end;
2090 if okX or okY then
2091 begin
2092 for a := 0 to High(SelectedObjects) do
2093 if SelectedObjects[a].Live then
2094 begin
2095 if okX then
2096 MoveObject(SelectedObjects[a].ObjectType, SelectedObjects[a].ID, dx, 0);
2098 if okY then
2099 MoveObject(SelectedObjects[a].ObjectType, SelectedObjects[a].ID, 0, dy);
2101 if alt and (SelectedObjects[a].ObjectType = OBJECT_TRIGGER) then
2102 begin
2103 if gTriggers[SelectedObjects[a].ID].TriggerType in [TRIGGER_PRESS,
2104 TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF] then
2105 begin // Двигаем зону Расширителя
2106 if okX then
2107 gTriggers[SelectedObjects[a].ID].Data.tX := gTriggers[SelectedObjects[a].ID].Data.tX+dx;
2108 if okY then
2109 gTriggers[SelectedObjects[a].ID].Data.tY := gTriggers[SelectedObjects[a].ID].Data.tY+dy;
2110 end;
2112 if gTriggers[SelectedObjects[a].ID].TriggerType in [TRIGGER_TELEPORT] then
2113 begin // Двигаем точку назначения Телепорта
2114 if okX then
2115 gTriggers[SelectedObjects[a].ID].Data.TargetPoint.X := gTriggers[SelectedObjects[a].ID].Data.TargetPoint.X+dx;
2116 if okY then
2117 gTriggers[SelectedObjects[a].ID].Data.TargetPoint.Y := gTriggers[SelectedObjects[a].ID].Data.TargetPoint.Y+dy;
2118 end;
2120 if gTriggers[SelectedObjects[a].ID].TriggerType in [TRIGGER_SPAWNMONSTER] then
2121 begin // Двигаем точку создания монстра
2122 if okX then
2123 gTriggers[SelectedObjects[a].ID].Data.MonPos.X := gTriggers[SelectedObjects[a].ID].Data.MonPos.X+dx;
2124 if okY then
2125 gTriggers[SelectedObjects[a].ID].Data.MonPos.Y := gTriggers[SelectedObjects[a].ID].Data.MonPos.Y+dy;
2126 end;
2128 if gTriggers[SelectedObjects[a].ID].TriggerType in [TRIGGER_SPAWNITEM] then
2129 begin // Двигаем точку создания предмета
2130 if okX then
2131 gTriggers[SelectedObjects[a].ID].Data.ItemPos.X := gTriggers[SelectedObjects[a].ID].Data.ItemPos.X+dx;
2132 if okY then
2133 gTriggers[SelectedObjects[a].ID].Data.ItemPos.Y := gTriggers[SelectedObjects[a].ID].Data.ItemPos.Y+dy;
2134 end;
2136 if gTriggers[SelectedObjects[a].ID].TriggerType in [TRIGGER_SHOT] then
2137 begin // Двигаем точку создания выстрела
2138 if okX then
2139 gTriggers[SelectedObjects[a].ID].Data.ShotPos.X := gTriggers[SelectedObjects[a].ID].Data.ShotPos.X+dx;
2140 if okY then
2141 gTriggers[SelectedObjects[a].ID].Data.ShotPos.Y := gTriggers[SelectedObjects[a].ID].Data.ShotPos.Y+dy;
2142 end;
2143 end;
2144 end;
2146 LastMovePoint := MousePos;
2147 end;
2148 end;
2150 procedure ShowLayer(Layer: Byte; show: Boolean);
2151 begin
2152 LayerEnabled[Layer] := show;
2154 case Layer of
2155 LAYER_BACK:
2156 begin
2157 MainForm.miLayer1.Checked := show;
2158 MainForm.miLayerP1.Checked := show;
2159 end;
2160 LAYER_WALLS:
2161 begin
2162 MainForm.miLayer2.Checked := show;
2163 MainForm.miLayerP2.Checked := show;
2164 end;
2165 LAYER_FOREGROUND:
2166 begin
2167 MainForm.miLayer3.Checked := show;
2168 MainForm.miLayerP3.Checked := show;
2169 end;
2170 LAYER_STEPS:
2171 begin
2172 MainForm.miLayer4.Checked := show;
2173 MainForm.miLayerP4.Checked := show;
2174 end;
2175 LAYER_WATER:
2176 begin
2177 MainForm.miLayer5.Checked := show;
2178 MainForm.miLayerP5.Checked := show;
2179 end;
2180 LAYER_ITEMS:
2181 begin
2182 MainForm.miLayer6.Checked := show;
2183 MainForm.miLayerP6.Checked := show;
2184 end;
2185 LAYER_MONSTERS:
2186 begin
2187 MainForm.miLayer7.Checked := show;
2188 MainForm.miLayerP7.Checked := show;
2189 end;
2190 LAYER_AREAS:
2191 begin
2192 MainForm.miLayer8.Checked := show;
2193 MainForm.miLayerP8.Checked := show;
2194 end;
2195 LAYER_TRIGGERS:
2196 begin
2197 MainForm.miLayer9.Checked := show;
2198 MainForm.miLayerP9.Checked := show;
2199 end;
2200 end;
2202 RemoveSelectFromObjects();
2203 end;
2205 procedure SwitchLayer(Layer: Byte);
2206 begin
2207 ShowLayer(Layer, not LayerEnabled[Layer]);
2208 end;
2210 procedure SwitchMap();
2211 begin
2212 ShowMap := not ShowMap;
2213 MainForm.tbShowMap.Down := ShowMap;
2214 end;
2216 procedure ShowEdges();
2217 begin
2218 if drEdge[3] < 255 then
2219 drEdge[3] := 255
2220 else
2221 drEdge[3] := gAlphaEdge;
2222 end;
2224 function SelectedTexture(): String;
2225 begin
2226 if MainForm.lbTextureList.ItemIndex <> -1 then
2227 Result := MainForm.lbTextureList.Items[MainForm.lbTextureList.ItemIndex]
2228 else
2229 Result := '';
2230 end;
2232 function IsSpecialTextureSel(): Boolean;
2233 begin
2234 Result := (MainForm.lbTextureList.ItemIndex <> -1) and
2235 IsSpecialTexture(MainForm.lbTextureList.Items[MainForm.lbTextureList.ItemIndex]);
2236 end;
2238 function CopyBufferToString(var CopyBuf: TCopyRecArray): String;
2239 var
2240 i, j: Integer;
2241 Res: String;
2243 procedure AddInt(x: Integer);
2244 begin
2245 Res := Res + IntToStr(x) + ' ';
2246 end;
2248 begin
2249 Result := '';
2251 if Length(CopyBuf) = 0 then
2252 Exit;
2254 Res := CLIPBOARD_SIG + ' ';
2256 for i := 0 to High(CopyBuf) do
2257 begin
2258 if (CopyBuf[i].ObjectType = OBJECT_PANEL) and
2259 (CopyBuf[i].Panel = nil) then
2260 Continue;
2262 // Тип объекта:
2263 AddInt(CopyBuf[i].ObjectType);
2264 Res := Res + '; ';
2266 // Свойства объекта:
2267 case CopyBuf[i].ObjectType of
2268 OBJECT_PANEL:
2269 with CopyBuf[i].Panel^ do
2270 begin
2271 AddInt(PanelType);
2272 AddInt(X);
2273 AddInt(Y);
2274 AddInt(Width);
2275 AddInt(Height);
2276 Res := Res + '"' + TextureName + '" ';
2277 AddInt(Alpha);
2278 AddInt(IfThen(Blending, 1, 0));
2279 end;
2281 OBJECT_ITEM:
2282 with CopyBuf[i].Item do
2283 begin
2284 AddInt(ItemType);
2285 AddInt(X);
2286 AddInt(Y);
2287 AddInt(IfThen(OnlyDM, 1, 0));
2288 AddInt(IfThen(Fall, 1, 0));
2289 end;
2291 OBJECT_MONSTER:
2292 with CopyBuf[i].Monster do
2293 begin
2294 AddInt(MonsterType);
2295 AddInt(X);
2296 AddInt(Y);
2297 AddInt(IfThen(Direction = D_LEFT, 1, 0));
2298 end;
2300 OBJECT_AREA:
2301 with CopyBuf[i].Area do
2302 begin
2303 AddInt(AreaType);
2304 AddInt(X);
2305 AddInt(Y);
2306 AddInt(IfThen(Direction = D_LEFT, 1, 0));
2307 end;
2309 OBJECT_TRIGGER:
2310 with CopyBuf[i].Trigger do
2311 begin
2312 AddInt(TriggerType);
2313 AddInt(X);
2314 AddInt(Y);
2315 AddInt(Width);
2316 AddInt(Height);
2317 AddInt(ActivateType);
2318 AddInt(Key);
2319 AddInt(IfThen(Enabled, 1, 0));
2320 AddInt(TexturePanel);
2322 for j := 0 to 127 do
2323 AddInt(Data.Default[j]);
2324 end;
2325 end;
2326 end;
2328 Result := Res;
2329 end;
2331 procedure StringToCopyBuffer(Str: String; var CopyBuf: TCopyRecArray);
2332 var
2333 i, j, t: Integer;
2335 function GetNext(): String;
2336 var
2337 p: Integer;
2339 begin
2340 if Str[1] = '"' then
2341 begin
2342 Delete(Str, 1, 1);
2343 p := Pos('"', Str);
2345 if p = 0 then
2346 begin
2347 Result := Str;
2348 Str := '';
2349 end
2350 else
2351 begin
2352 Result := Copy(Str, 1, p-1);
2353 Delete(Str, 1, p);
2354 Str := Trim(Str);
2355 end;
2356 end
2357 else
2358 begin
2359 p := Pos(' ', Str);
2361 if p = 0 then
2362 begin
2363 Result := Str;
2364 Str := '';
2365 end
2366 else
2367 begin
2368 Result := Copy(Str, 1, p-1);
2369 Delete(Str, 1, p);
2370 Str := Trim(Str);
2371 end;
2372 end;
2373 end;
2375 begin
2376 Str := Trim(Str);
2378 if GetNext() <> CLIPBOARD_SIG then
2379 Exit;
2381 while Str <> '' do
2382 begin
2383 // Тип объекта:
2384 t := StrToIntDef(GetNext(), 0);
2386 if (t < OBJECT_PANEL) or (t > OBJECT_TRIGGER) or
2387 (GetNext() <> ';') then
2388 begin // Что-то не то => пропускаем:
2389 t := Pos(';', Str);
2390 Delete(Str, 1, t);
2391 Str := Trim(Str);
2393 Continue;
2394 end;
2396 i := Length(CopyBuf);
2397 SetLength(CopyBuf, i + 1);
2399 CopyBuf[i].ObjectType := t;
2400 CopyBuf[i].Panel := nil;
2402 // Свойства объекта:
2403 case t of
2404 OBJECT_PANEL:
2405 begin
2406 New(CopyBuf[i].Panel);
2408 with CopyBuf[i].Panel^ do
2409 begin
2410 PanelType := StrToIntDef(GetNext(), PANEL_WALL);
2411 X := StrToIntDef(GetNext(), 0);
2412 Y := StrToIntDef(GetNext(), 0);
2413 Width := StrToIntDef(GetNext(), 16);
2414 Height := StrToIntDef(GetNext(), 16);
2415 TextureName := GetNext();
2416 Alpha := StrToIntDef(GetNext(), 0);
2417 Blending := (GetNext() = '1');
2418 end;
2419 end;
2421 OBJECT_ITEM:
2422 with CopyBuf[i].Item do
2423 begin
2424 ItemType := StrToIntDef(GetNext(), ITEM_MEDKIT_SMALL);
2425 X := StrToIntDef(GetNext(), 0);
2426 Y := StrToIntDef(GetNext(), 0);
2427 OnlyDM := (GetNext() = '1');
2428 Fall := (GetNext() = '1');
2429 end;
2431 OBJECT_MONSTER:
2432 with CopyBuf[i].Monster do
2433 begin
2434 MonsterType := StrToIntDef(GetNext(), MONSTER_DEMON);
2435 X := StrToIntDef(GetNext(), 0);
2436 Y := StrToIntDef(GetNext(), 0);
2438 if GetNext() = '1' then
2439 Direction := D_LEFT
2440 else
2441 Direction := D_RIGHT;
2442 end;
2444 OBJECT_AREA:
2445 with CopyBuf[i].Area do
2446 begin
2447 AreaType := StrToIntDef(GetNext(), AREA_PLAYERPOINT1);
2448 X := StrToIntDef(GetNext(), 0);
2449 Y := StrToIntDef(GetNext(), 0);
2450 if GetNext() = '1' then
2451 Direction := D_LEFT
2452 else
2453 Direction := D_RIGHT;
2454 end;
2456 OBJECT_TRIGGER:
2457 with CopyBuf[i].Trigger do
2458 begin
2459 TriggerType := StrToIntDef(GetNext(), TRIGGER_EXIT);
2460 X := StrToIntDef(GetNext(), 0);
2461 Y := StrToIntDef(GetNext(), 0);
2462 Width := StrToIntDef(GetNext(), 16);
2463 Height := StrToIntDef(GetNext(), 16);
2464 ActivateType := StrToIntDef(GetNext(), 0);
2465 Key := StrToIntDef(GetNext(), 0);
2466 Enabled := (GetNext() = '1');
2467 TexturePanel := StrToIntDef(GetNext(), 0);
2469 for j := 0 to 127 do
2470 Data.Default[j] := StrToIntDef(GetNext(), 0);
2471 end;
2472 end;
2473 end;
2474 end;
2476 //----------------------------------------
2477 //Закончились вспомогательные процедуры
2478 //----------------------------------------
2480 procedure TMainForm.RefreshRecentMenu();
2481 var
2482 i: Integer;
2483 MI: TMenuItem;
2484 begin
2485 // Лишние запомненные карты:
2486 while RecentFiles.Count > RecentCount do
2487 RecentFiles.Delete(RecentFiles.Count-1);
2489 // Лишние строки меню:
2490 while MainMenu.Items[0].Count > RECENT_FILES_MENU_START do
2491 MainMenu.Items[0].Delete(MainMenu.Items[0].Count-1);
2493 // Отделение списка карт от строки "Выход":
2494 if RecentFiles.Count > 0 then
2495 begin
2496 MI := TMenuItem.Create(MainMenu.Items[0]);
2497 MI.Caption := '-';
2498 MainMenu.Items[0].Add(MI);
2499 end;
2501 // Добавление в меню списка запомненных карт:
2502 for i := 0 to RecentFiles.Count-1 do
2503 begin
2504 MI := TMenuItem.Create(MainMenu.Items[0]);
2505 MI.Caption := IntToStr(i+1) + ' ' + RecentFiles[i];
2506 MI.OnClick := aRecentFileExecute;
2507 MainMenu.Items[0].Add(MI);
2508 end;
2509 end;
2511 procedure TMainForm.aRecentFileExecute(Sender: TObject);
2512 var
2513 n, pw: Integer;
2514 s, fn: String;
2515 b: Boolean;
2516 begin
2517 s := LowerCase((Sender as TMenuItem).Caption);
2518 Delete(s, Pos('&', s), 1);
2519 s := Trim(Copy(s, 1, 2));
2520 n := StrToIntDef(s, 0) - 1;
2522 if (n < 0) or (n >= RecentFiles.Count) then
2523 Exit;
2525 s := RecentFiles[n];
2526 pw := Pos('.wad:\', LowerCase(s));
2527 b := False;
2529 if pw > 0 then
2530 begin // Map name included
2531 fn := Copy(s, 1, pw + 3);
2532 Delete(s, 1, pw + 5);
2533 if (FileExists(fn)) then
2534 begin
2535 OpenMap(fn, s);
2536 b := True;
2537 end;
2538 end
2539 else // Only wad name
2540 if (FileExists(s)) then
2541 begin
2542 OpenMap(s, '');
2543 b := True;
2544 end;
2546 if (not b) and (MessageBox(0, PChar(_lc[I_MSG_DEL_RECENT_PROMT]),
2547 PChar(_lc[I_MSG_DEL_RECENT]), MB_ICONQUESTION or MB_YESNO) = idYes) then
2548 begin
2549 RecentFiles.Delete(n);
2550 RefreshRecentMenu();
2551 end;
2552 end;
2554 procedure TMainForm.aEditorOptionsExecute(Sender: TObject);
2555 begin
2556 OptionsForm.ShowModal();
2557 end;
2559 procedure LoadStdFont(cfgres, texture: string; var FontID: DWORD);
2560 var
2561 cwdt, chgt: Byte;
2562 spc: ShortInt;
2563 ID: DWORD;
2564 wad: TWADEditor_1;
2565 cfgdata: Pointer;
2566 cfglen: Integer;
2567 config: TConfig;
2568 begin
2569 cfgdata := nil;
2570 cfglen := 0;
2571 ID := 0;
2573 wad := TWADEditor_1.Create;
2574 if wad.ReadFile(EditorDir+'data/Game.wad') then
2575 wad.GetResource('FONTS', cfgres, cfgdata, cfglen);
2576 wad.Free();
2578 if cfglen <> 0 then
2579 begin
2580 if not g_CreateTextureWAD('FONT_STD', EditorDir+'data/Game.wad:FONTS\'+texture) then
2581 e_WriteLog('ERROR ERROR ERROR', MSG_WARNING);
2583 config := TConfig.CreateMem(cfgdata, cfglen);
2584 cwdt := Min(Max(config.ReadInt('FontMap', 'CharWidth', 0), 0), 255);
2585 chgt := Min(Max(config.ReadInt('FontMap', 'CharHeight', 0), 0), 255);
2586 spc := Min(Max(config.ReadInt('FontMap', 'Kerning', 0), -128), 127);
2588 if g_GetTexture('FONT_STD', ID) then
2589 e_TextureFontBuild(ID, FontID, cwdt, chgt, spc-2);
2591 config.Free();
2592 end
2593 else
2594 e_WriteLog('Could not load FONT_STD', MSG_WARNING);
2596 if cfglen <> 0 then FreeMem(cfgdata);
2597 end;
2599 procedure TMainForm.FormCreate(Sender: TObject);
2600 var
2601 config: TConfig;
2602 i: Integer;
2603 s: String;
2604 begin
2605 Randomize();
2607 EditorDir := ExtractFilePath(Application.ExeName);
2609 e_InitLog(EditorDir+'Editor.log', WM_NEWFILE);
2611 slInvalidTextures := TStringList.Create;
2613 ShowLayer(LAYER_BACK, True);
2614 ShowLayer(LAYER_WALLS, True);
2615 ShowLayer(LAYER_FOREGROUND, True);
2616 ShowLayer(LAYER_STEPS, True);
2617 ShowLayer(LAYER_WATER, True);
2618 ShowLayer(LAYER_ITEMS, True);
2619 ShowLayer(LAYER_MONSTERS, True);
2620 ShowLayer(LAYER_AREAS, True);
2621 ShowLayer(LAYER_TRIGGERS, True);
2623 ClearMap();
2625 FormCaption := MainForm.Caption;
2626 OpenedMap := '';
2627 OpenedWAD := '';
2629 config := TConfig.CreateFile(EditorDir+'Editor.cfg');
2631 if config.ReadInt('Editor', 'XPos', -1) = -1 then
2632 Position := poDesktopCenter
2633 else begin
2634 Left := config.ReadInt('Editor', 'XPos', Left);
2635 Top := config.ReadInt('Editor', 'YPos', Top);
2636 Width := config.ReadInt('Editor', 'Width', Width);
2637 Height := config.ReadInt('Editor', 'Height', Height);
2638 end;
2639 if config.ReadBool('Editor', 'Maximize', False) then
2640 WindowState := wsMaximized;
2641 ShowMap := config.ReadBool('Editor', 'Minimap', False);
2642 PanelProps.Width := config.ReadInt('Editor', 'PanelProps', PanelProps.ClientWidth);
2643 Splitter1.Left := PanelProps.Left;
2644 PanelObjs.Height := config.ReadInt('Editor', 'PanelObjs', PanelObjs.ClientHeight);
2645 Splitter2.Top := PanelObjs.Top;
2646 StatusBar.Top := PanelObjs.BoundsRect.Bottom;
2647 DotEnable := config.ReadBool('Editor', 'DotEnable', True);
2648 DotColor := config.ReadInt('Editor', 'DotColor', $FFFFFF);
2649 DotStepOne := config.ReadInt('Editor', 'DotStepOne', 16);
2650 DotStepTwo := config.ReadInt('Editor', 'DotStepTwo', 8);
2651 DotStep := config.ReadInt('Editor', 'DotStep', DotStepOne);
2652 DrawTexturePanel := config.ReadBool('Editor', 'DrawTexturePanel', True);
2653 DrawPanelSize := config.ReadBool('Editor', 'DrawPanelSize', True);
2654 BackColor := config.ReadInt('Editor', 'BackColor', $7F6040);
2655 PreviewColor := config.ReadInt('Editor', 'PreviewColor', $00FF00);
2656 gColorEdge := config.ReadInt('Editor', 'EdgeColor', COLOR_EDGE);
2657 gAlphaEdge := config.ReadInt('Editor', 'EdgeAlpha', ALPHA_EDGE);
2658 if gAlphaEdge = 255 then
2659 gAlphaEdge := ALPHA_EDGE;
2660 drEdge[0] := GetRValue(gColorEdge);
2661 drEdge[1] := GetGValue(gColorEdge);
2662 drEdge[2] := GetBValue(gColorEdge);
2663 if not config.ReadBool('Editor', 'EdgeShow', True) then
2664 drEdge[3] := 255
2665 else
2666 drEdge[3] := gAlphaEdge;
2667 gAlphaTriggerLine := config.ReadInt('Editor', 'LineAlpha', ALPHA_LINE);
2668 if gAlphaTriggerLine = 255 then
2669 gAlphaTriggerLine := ALPHA_LINE;
2670 gAlphaTriggerArea := config.ReadInt('Editor', 'TriggerAlpha', ALPHA_AREA);
2671 if gAlphaTriggerArea = 255 then
2672 gAlphaTriggerArea := ALPHA_AREA;
2673 if config.ReadInt('Editor', 'Scale', 0) = 1 then
2674 Scale := 2
2675 else
2676 Scale := 1;
2677 if config.ReadInt('Editor', 'DotSize', 0) = 1 then
2678 DotSize := 2
2679 else
2680 DotSize := 1;
2681 OpenDialog.InitialDir := config.ReadStr('Editor', 'LastOpenDir', EditorDir);
2682 SaveDialog.InitialDir := config.ReadStr('Editor', 'LastSaveDir', EditorDir);
2684 s := config.ReadStr('Editor', 'Language', '');
2685 gLanguage := s;
2687 RecentCount := config.ReadInt('Editor', 'RecentCount', 5);
2688 if RecentCount > 10 then
2689 RecentCount := 10;
2690 if RecentCount < 2 then
2691 RecentCount := 2;
2693 RecentFiles := TStringList.Create();
2694 for i := 0 to RecentCount-1 do
2695 begin
2696 s := config.ReadStr('RecentFiles', IntToStr(i+1), '');
2697 if s <> '' then
2698 RecentFiles.Add(s);
2699 end;
2700 RefreshRecentMenu();
2702 config.Free();
2704 tbShowMap.Down := ShowMap;
2705 tbGridOn.Down := DotEnable;
2706 pcObjects.ActivePageIndex := 0;
2707 Application.Title := _lc[I_EDITOR_TITLE];
2709 Application.OnIdle := OnIdle;
2710 end;
2712 procedure PrintBlack(X, Y: Integer; Text: string; FontID: DWORD);
2713 begin
2714 // NOTE: all the font printing routines assume CP1251
2715 e_TextureFontPrintEx(X, Y, Text, FontID, 0, 0, 0, 1.0);
2716 end;
2718 procedure TMainForm.Draw();
2719 var
2720 x, y: Integer;
2721 a, b: Integer;
2722 ID, PID: DWORD;
2723 Width, Height: Word;
2724 Rect: TRectWH;
2725 ObjCount: Word;
2726 aX, aY, aX2, aY2, XX, ScaleSz: Integer;
2727 begin
2728 ID := 0;
2729 PID := 0;
2730 Width := 0;
2731 Height := 0;
2733 e_BeginRender();
2735 e_Clear(GL_COLOR_BUFFER_BIT,
2736 GetRValue(BackColor)/255,
2737 GetGValue(BackColor)/255,
2738 GetBValue(BackColor)/255);
2740 DrawMap();
2742 ObjCount := SelectedObjectCount();
2744 // Обводим выделенные объекты красной рамкой:
2745 if ObjCount > 0 then
2746 begin
2747 for a := 0 to High(SelectedObjects) do
2748 if SelectedObjects[a].Live then
2749 begin
2750 Rect := ObjectGetRect(SelectedObjects[a].ObjectType, SelectedObjects[a].ID);
2752 with Rect do
2753 begin
2754 e_DrawQuad(X+MapOffset.X, Y+MapOffset.Y,
2755 X+MapOffset.X+Width-1, Y+MapOffset.Y+Height-1,
2756 255, 0, 0);
2758 // Рисуем точки изменения размеров:
2759 if (ObjCount = 1) and
2760 (SelectedObjects[GetFirstSelected].ObjectType in [OBJECT_PANEL, OBJECT_TRIGGER]) then
2761 begin
2762 e_DrawPoint(5, X+MapOffset.X, Y+MapOffset.Y+(Height div 2), 255, 255, 255);
2763 e_DrawPoint(5, X+MapOffset.X+Width-1, Y+MapOffset.Y+(Height div 2), 255, 255, 255);
2764 e_DrawPoint(5, X+MapOffset.X+(Width div 2), Y+MapOffset.Y, 255, 255, 255);
2765 e_DrawPoint(5, X+MapOffset.X+(Width div 2), Y+MapOffset.Y+Height-1, 255, 255, 255);
2767 e_DrawPoint(3, X+MapOffset.X, Y+MapOffset.Y+(Height div 2), 255, 0, 0);
2768 e_DrawPoint(3, X+MapOffset.X+Width-1, Y+MapOffset.Y+(Height div 2), 255, 0, 0);
2769 e_DrawPoint(3, X+MapOffset.X+(Width div 2), Y+MapOffset.Y, 255, 0, 0);
2770 e_DrawPoint(3, X+MapOffset.X+(Width div 2), Y+MapOffset.Y+Height-1, 255, 0, 0);
2771 end;
2772 end;
2773 end;
2774 end;
2776 // Рисуем сетку:
2777 if DotEnable and (PreviewMode = 0) then
2778 begin
2779 if DotSize = 2 then
2780 a := -1
2781 else
2782 a := 0;
2784 for x := 0 to (RenderPanel.Width div DotStep) do
2785 for y := 0 to (RenderPanel.Height div DotStep) do
2786 e_DrawPoint(DotSize, x*DotStep + a, y*DotStep + a,
2787 GetRValue(DotColor),
2788 GetGValue(DotColor),
2789 GetBValue(DotColor));
2790 end;
2792 // Превью текстуры:
2793 if (lbTextureList.ItemIndex <> -1) and (cbPreview.Checked) and
2794 (not IsSpecialTextureSel()) and (PreviewMode = 0) then
2795 begin
2796 if not g_GetTexture(SelectedTexture(), ID) then
2797 g_GetTexture('NOTEXTURE', ID);
2798 g_GetTextureSizeByID(ID, Width, Height);
2799 if g_GetTexture('PREVIEW', PID) then
2800 e_DrawFill(PID, RenderPanel.Width-Width, RenderPanel.Height-Height, Width div 16 + 1, Height div 16 + 1, 0, True, False);
2801 e_Draw(ID, RenderPanel.Width-Width, RenderPanel.Height-Height, 0, True, False);
2802 end;
2804 // Подсказка при выборе точки Телепорта:
2805 if SelectFlag = SELECTFLAG_TELEPORT then
2806 begin
2807 with gTriggers[SelectedObjects[GetFirstSelected()].ID] do
2808 if Data.d2d_teleport then
2809 e_DrawLine(2, MousePos.X-16, MousePos.Y-1,
2810 MousePos.X+16, MousePos.Y-1,
2811 0, 0, 255)
2812 else
2813 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+AreaSize[AREA_DMPOINT].Width-1,
2814 MousePos.Y+AreaSize[AREA_DMPOINT].Height-1, 255, 255, 255);
2816 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 192, 192, 192, 127);
2817 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 255, 255, 255);
2818 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_TELEPORT], gEditorFont);
2819 end;
2821 // Подсказка при выборе точки появления:
2822 if SelectFlag = SELECTFLAG_SPAWNPOINT then
2823 begin
2824 e_DrawLine(2, MousePos.X-16, MousePos.Y-1,
2825 MousePos.X+16, MousePos.Y-1,
2826 0, 0, 255);
2827 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 192, 192, 192, 127);
2828 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 255, 255, 255);
2829 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_SPAWN], gEditorFont);
2830 end;
2832 // Подсказка при выборе панели двери:
2833 if SelectFlag = SELECTFLAG_DOOR then
2834 begin
2835 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 192, 192, 192, 127);
2836 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 255, 255, 255);
2837 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_PANEL_DOOR], gEditorFont);
2838 end;
2840 // Подсказка при выборе панели с текстурой:
2841 if SelectFlag = SELECTFLAG_TEXTURE then
2842 begin
2843 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+196, MousePos.Y+18, 192, 192, 192, 127);
2844 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+196, MousePos.Y+18, 255, 255, 255);
2845 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_PANEL_TEXTURE], gEditorFont);
2846 end;
2848 // Подсказка при выборе панели индикации выстрела:
2849 if SelectFlag = SELECTFLAG_SHOTPANEL then
2850 begin
2851 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+316, MousePos.Y+18, 192, 192, 192, 127);
2852 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+316, MousePos.Y+18, 255, 255, 255);
2853 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_PANEL_SHOT], gEditorFont);
2854 end;
2856 // Подсказка при выборе панели лифта:
2857 if SelectFlag = SELECTFLAG_LIFT then
2858 begin
2859 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 192, 192, 192, 127);
2860 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 255, 255, 255);
2861 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_PANEL_LIFT], gEditorFont);
2862 end;
2864 // Подсказка при выборе монстра:
2865 if SelectFlag = SELECTFLAG_MONSTER then
2866 begin
2867 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+120, MousePos.Y+18, 192, 192, 192, 127);
2868 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+120, MousePos.Y+18, 255, 255, 255);
2869 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_MONSTER], gEditorFont);
2870 end;
2872 // Подсказка при выборе области воздействия:
2873 if DrawPressRect then
2874 begin
2875 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+204, MousePos.Y+18, 192, 192, 192, 127);
2876 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+204, MousePos.Y+18, 255, 255, 255);
2877 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_EXT_AREA], gEditorFont);
2878 end;
2880 // Рисуем текстуры, если чертим панель:
2881 if (MouseAction = MOUSEACTION_DRAWPANEL) and (DrawTexturePanel) and
2882 (lbTextureList.ItemIndex <> -1) and (DrawRect <> nil) and
2883 (lbPanelType.ItemIndex in [0..8]) and not IsSpecialTextureSel() then
2884 begin
2885 if not g_GetTexture(SelectedTexture(), ID) then
2886 g_GetTexture('NOTEXTURE', ID);
2887 g_GetTextureSizeByID(ID, Width, Height);
2888 with DrawRect^ do
2889 e_DrawFill(ID, Min(Left, Right), Min(Top, Bottom), Abs(Right-Left) div Width,
2890 Abs(Bottom-Top) div Height, 0, True, False);
2891 end;
2893 // Прямоугольник выделения:
2894 if DrawRect <> nil then
2895 with DrawRect^ do
2896 e_DrawQuad(Left, Top, Right-1, Bottom-1, 255, 255, 255);
2898 // Чертим мышью панель/триггер или меняем мышью их размер:
2899 if (MouseAction in [MOUSEACTION_DRAWPANEL, MOUSEACTION_DRAWTRIGGER, MOUSEACTION_RESIZE]) and
2900 (DrawPanelSize) then
2901 begin
2902 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+88, MousePos.Y+33, 192, 192, 192, 127);
2903 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+88, MousePos.Y+33, 255, 255, 255);
2905 if MouseAction in [MOUSEACTION_DRAWPANEL, MOUSEACTION_DRAWTRIGGER] then
2906 begin // Чертим новый
2907 PrintBlack(MousePos.X+2, MousePos.Y+2, Format(_glc[I_HINT_WIDTH],
2908 [Abs(MousePos.X-MouseLDownPos.X)]), gEditorFont);
2909 PrintBlack(MousePos.X+2, MousePos.Y+14, Format(_glc[I_HINT_HEIGHT],
2910 [Abs(MousePos.Y-MouseLDownPos.Y)]), gEditorFont);
2911 end
2912 else // Растягиваем существующий
2913 if SelectedObjects[GetFirstSelected].ObjectType in [OBJECT_PANEL, OBJECT_TRIGGER] then
2914 begin
2915 if SelectedObjects[GetFirstSelected].ObjectType = OBJECT_PANEL then
2916 begin
2917 Width := gPanels[SelectedObjects[GetFirstSelected].ID].Width;
2918 Height := gPanels[SelectedObjects[GetFirstSelected].ID].Height;
2919 end
2920 else
2921 begin
2922 Width := gTriggers[SelectedObjects[GetFirstSelected].ID].Width;
2923 Height := gTriggers[SelectedObjects[GetFirstSelected].ID].Height;
2924 end;
2926 PrintBlack(MousePos.X+2, MousePos.Y+2, Format(_glc[I_HINT_WIDTH], [Width]),
2927 gEditorFont);
2928 PrintBlack(MousePos.X+2, MousePos.Y+14, Format(_glc[I_HINT_HEIGHT], [Height]),
2929 gEditorFont);
2930 end;
2931 end;
2933 // Ближайшая к курсору мыши точка на сетке:
2934 e_DrawPoint(3, MousePos.X, MousePos.Y, 0, 0, 255);
2936 // Мини-карта:
2937 if ShowMap then
2938 begin
2939 // Сколько пикселов карты в 1 пикселе мини-карты:
2940 ScaleSz := 16 div Scale;
2941 // Размеры мини-карты:
2942 aX := max(gMapInfo.Width div ScaleSz, 1);
2943 aY := max(gMapInfo.Height div ScaleSz, 1);
2944 // X-координата на RenderPanel нулевой x-координаты карты:
2945 XX := RenderPanel.Width - aX - 1;
2946 // Рамка карты:
2947 e_DrawFillQuad(XX-1, 0, RenderPanel.Width-1, aY+1, 0, 0, 0, 0);
2948 e_DrawQuad(XX-1, 0, RenderPanel.Width-1, aY+1, 197, 197, 197);
2950 if gPanels <> nil then
2951 begin
2952 // Рисуем панели:
2953 for a := 0 to High(gPanels) do
2954 with gPanels[a] do
2955 if PanelType <> 0 then
2956 begin
2957 // Левый верхний угол:
2958 aX := XX + (X div ScaleSz);
2959 aY := 1 + (Y div ScaleSz);
2960 // Размеры:
2961 aX2 := max(Width div ScaleSz, 1);
2962 aY2 := max(Height div ScaleSz, 1);
2963 // Правый нижний угол:
2964 aX2 := aX + aX2 - 1;
2965 aY2 := aY + aY2 - 1;
2967 case PanelType of
2968 PANEL_WALL: e_DrawFillQuad(aX, aY, aX2, aY2, 208, 208, 208, 0);
2969 PANEL_WATER: e_DrawFillQuad(aX, aY, aX2, aY2, 0, 0, 192, 0);
2970 PANEL_ACID1: e_DrawFillQuad(aX, aY, aX2, aY2, 0, 176, 0, 0);
2971 PANEL_ACID2: e_DrawFillQuad(aX, aY, aX2, aY2, 176, 0, 0, 0);
2972 PANEL_STEP: e_DrawFillQuad(aX, aY, aX2, aY2, 128, 128, 128, 0);
2973 PANEL_LIFTUP: e_DrawFillQuad(aX, aY, aX2, aY2, 116, 72, 36, 0);
2974 PANEL_LIFTDOWN: e_DrawFillQuad(aX, aY, aX2, aY2, 116, 124, 96, 0);
2975 PANEL_LIFTLEFT: e_DrawFillQuad(aX, aY, aX2, aY2, 200, 80, 4, 0);
2976 PANEL_LIFTRIGHT: e_DrawFillQuad(aX, aY, aX2, aY2, 252, 140, 56, 0);
2977 PANEL_OPENDOOR: e_DrawFillQuad(aX, aY, aX2, aY2, 100, 220, 92, 0);
2978 PANEL_CLOSEDOOR: e_DrawFillQuad(aX, aY, aX2, aY2, 212, 184, 64, 0);
2979 PANEL_BLOCKMON: e_DrawFillQuad(aX, aY, aX2, aY2, 192, 0, 192, 0);
2980 end;
2981 end;
2983 // Рисуем красным выделенные панели:
2984 if SelectedObjects <> nil then
2985 for b := 0 to High(SelectedObjects) do
2986 with SelectedObjects[b] do
2987 if Live and (ObjectType = OBJECT_PANEL) then
2988 with gPanels[SelectedObjects[b].ID] do
2989 if PanelType and not(PANEL_BACK or PANEL_FORE) <> 0 then
2990 begin
2991 // Левый верхний угол:
2992 aX := XX + (X div ScaleSz);
2993 aY := 1 + (Y div ScaleSz);
2994 // Размеры:
2995 aX2 := max(Width div ScaleSz, 1);
2996 aY2 := max(Height div ScaleSz, 1);
2997 // Правый нижний угол:
2998 aX2 := aX + aX2 - 1;
2999 aY2 := aY + aY2 - 1;
3001 e_DrawFillQuad(aX, aY, aX2, aY2, 255, 0, 0, 0)
3002 end;
3003 end;
3005 if (gMapInfo.Width > RenderPanel.Width) or
3006 (gMapInfo.Height > RenderPanel.Height) then
3007 begin
3008 // Окно, показывающее текущее положение экрана на карте:
3009 // Размеры окна:
3010 x := max(min(RenderPanel.Width, gMapInfo.Width) div ScaleSz, 1);
3011 y := max(min(RenderPanel.Height, gMapInfo.Height) div ScaleSz, 1);
3012 // Левый верхний угол:
3013 aX := XX + ((-MapOffset.X) div ScaleSz);
3014 aY := 1 + ((-MapOffset.Y) div ScaleSz);
3015 // Правый нижний угол:
3016 aX2 := aX + x - 1;
3017 aY2 := aY + y - 1;
3019 e_DrawFillQuad(aX, aY, aX2, aY2, 127, 192, 127, 127, B_BLEND);
3020 e_DrawQuad(aX, aY, aX2, aY2, 255, 0, 0);
3021 end;
3022 end; // Мини-карта
3024 e_EndRender();
3025 RenderPanel.SwapBuffers();
3026 end;
3028 procedure TMainForm.FormResize(Sender: TObject);
3029 begin
3030 e_SetViewPort(0, 0, RenderPanel.Width, RenderPanel.Height);
3032 if gMapInfo.Width >= RenderPanel.Width then
3033 sbHorizontal.Max := Normalize16(gMapInfo.Width-RenderPanel.Width+16)
3034 else
3035 sbHorizontal.Max := 0;
3037 if gMapInfo.Height >= RenderPanel.Height then
3038 sbVertical.Max := Normalize16(gMapInfo.Height-RenderPanel.Height+16)
3039 else
3040 sbVertical.Max := 0;
3042 MapOffset.X := -Normalize16(sbHorizontal.Position);
3043 MapOffset.Y := -Normalize16(sbVertical.Position);
3044 end;
3046 procedure SelectNextObject(X, Y: Integer; ObjectType: Byte; ID: DWORD);
3047 var
3048 j, j_max: Integer;
3049 res: Boolean;
3050 begin
3051 j_max := 0; // shut up compiler
3052 case ObjectType of
3053 OBJECT_PANEL:
3054 begin
3055 res := (gPanels <> nil) and
3056 PanelInShownLayer(gPanels[ID].PanelType) and
3057 g_CollidePoint(X, Y, gPanels[ID].X, gPanels[ID].Y,
3058 gPanels[ID].Width,
3059 gPanels[ID].Height);
3060 j_max := Length(gPanels) - 1;
3061 end;
3063 OBJECT_ITEM:
3064 begin
3065 res := (gItems <> nil) and
3066 LayerEnabled[LAYER_ITEMS] and
3067 g_CollidePoint(X, Y, gItems[ID].X, gItems[ID].Y,
3068 ItemSize[gItems[ID].ItemType][0],
3069 ItemSize[gItems[ID].ItemType][1]);
3070 j_max := Length(gItems) - 1;
3071 end;
3073 OBJECT_MONSTER:
3074 begin
3075 res := (gMonsters <> nil) and
3076 LayerEnabled[LAYER_MONSTERS] and
3077 g_CollidePoint(X, Y, gMonsters[ID].X, gMonsters[ID].Y,
3078 MonsterSize[gMonsters[ID].MonsterType].Width,
3079 MonsterSize[gMonsters[ID].MonsterType].Height);
3080 j_max := Length(gMonsters) - 1;
3081 end;
3083 OBJECT_AREA:
3084 begin
3085 res := (gAreas <> nil) and
3086 LayerEnabled[LAYER_AREAS] and
3087 g_CollidePoint(X, Y, gAreas[ID].X, gAreas[ID].Y,
3088 AreaSize[gAreas[ID].AreaType].Width,
3089 AreaSize[gAreas[ID].AreaType].Height);
3090 j_max := Length(gAreas) - 1;
3091 end;
3093 OBJECT_TRIGGER:
3094 begin
3095 res := (gTriggers <> nil) and
3096 LayerEnabled[LAYER_TRIGGERS] and
3097 g_CollidePoint(X, Y, gTriggers[ID].X, gTriggers[ID].Y,
3098 gTriggers[ID].Width,
3099 gTriggers[ID].Height);
3100 j_max := Length(gTriggers) - 1;
3101 end;
3103 else
3104 res := False;
3105 end;
3107 if not res then
3108 Exit;
3110 // Перебор ID: от ID-1 до 0; потом от High до ID+1:
3111 j := ID;
3113 while True do
3114 begin
3115 Dec(j);
3117 if j < 0 then
3118 j := j_max;
3119 if j = Integer(ID) then
3120 Break;
3122 case ObjectType of
3123 OBJECT_PANEL:
3124 res := PanelInShownLayer(gPanels[j].PanelType) and
3125 g_CollidePoint(X, Y, gPanels[j].X, gPanels[j].Y,
3126 gPanels[j].Width,
3127 gPanels[j].Height);
3128 OBJECT_ITEM:
3129 res := (gItems[j].ItemType <> ITEM_NONE) and
3130 g_CollidePoint(X, Y, gItems[j].X, gItems[j].Y,
3131 ItemSize[gItems[j].ItemType][0],
3132 ItemSize[gItems[j].ItemType][1]);
3133 OBJECT_MONSTER:
3134 res := (gMonsters[j].MonsterType <> MONSTER_NONE) and
3135 g_CollidePoint(X, Y, gMonsters[j].X, gMonsters[j].Y,
3136 MonsterSize[gMonsters[j].MonsterType].Width,
3137 MonsterSize[gMonsters[j].MonsterType].Height);
3138 OBJECT_AREA:
3139 res := (gAreas[j].AreaType <> AREA_NONE) and
3140 g_CollidePoint(X, Y, gAreas[j].X, gAreas[j].Y,
3141 AreaSize[gAreas[j].AreaType].Width,
3142 AreaSize[gAreas[j].AreaType].Height);
3143 OBJECT_TRIGGER:
3144 res := (gTriggers[j].TriggerType <> TRIGGER_NONE) and
3145 g_CollidePoint(X, Y, gTriggers[j].X, gTriggers[j].Y,
3146 gTriggers[j].Width,
3147 gTriggers[j].Height);
3148 else
3149 res := False;
3150 end;
3152 if res then
3153 begin
3154 SetLength(SelectedObjects, 1);
3156 SelectedObjects[0].ObjectType := ObjectType;
3157 SelectedObjects[0].ID := j;
3158 SelectedObjects[0].Live := True;
3160 FillProperty();
3161 Break;
3162 end;
3163 end;
3164 end;
3166 procedure TMainForm.RenderPanelMouseDown(Sender: TObject;
3167 Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
3168 var
3169 i: Integer;
3170 Rect: TRectWH;
3171 c1, c2, c3, c4: Boolean;
3172 item: TItem;
3173 area: TArea;
3174 monster: TMonster;
3175 IDArray: DWArray;
3176 begin
3177 MainForm.ActiveControl := RenderPanel;
3178 RenderPanel.SetFocus();
3180 RenderPanelMouseMove(RenderPanel, Shift, X, Y);
3182 if Button = mbLeft then // Left Mouse Button
3183 begin
3184 // Двигаем карту с помощью мыши и мини-карты:
3185 if ShowMap and
3186 g_CollidePoint(X, Y,
3187 RenderPanel.Width-max(gMapInfo.Width div (16 div Scale), 1)-1,
3188 1,
3189 max(gMapInfo.Width div (16 div Scale), 1),
3190 max(gMapInfo.Height div (16 div Scale), 1) ) then
3191 begin
3192 MoveMap(X, Y);
3193 MouseAction := MOUSEACTION_MOVEMAP;
3194 end
3195 else // Ставим предмет/монстра/область:
3196 if (pcObjects.ActivePageIndex in [1, 2, 3]) and
3197 (not (ssShift in Shift)) then
3198 begin
3199 case pcObjects.ActivePageIndex of
3200 1:
3201 if lbItemList.ItemIndex = -1 then
3202 ErrorMessageBox(_lc[I_MSG_CHOOSE_ITEM])
3203 else
3204 begin
3205 item.ItemType := lbItemList.ItemIndex + ITEM_MEDKIT_SMALL;
3206 if item.ItemType >= ITEM_WEAPON_KASTET then
3207 item.ItemType := item.ItemType + 2;
3208 item.X := MousePos.X-MapOffset.X;
3209 item.Y := MousePos.Y-MapOffset.Y;
3211 if not (ssCtrl in Shift) then
3212 begin
3213 item.X := item.X - (ItemSize[item.ItemType][0] div 2);
3214 item.Y := item.Y - ItemSize[item.ItemType][1];
3215 end;
3217 item.OnlyDM := cbOnlyDM.Checked;
3218 item.Fall := cbFall.Checked;
3219 Undo_Add(OBJECT_ITEM, AddItem(item));
3220 end;
3221 2:
3222 if lbMonsterList.ItemIndex = -1 then
3223 ErrorMessageBox(_lc[I_MSG_CHOOSE_MONSTER])
3224 else
3225 begin
3226 monster.MonsterType := lbMonsterList.ItemIndex + MONSTER_DEMON;
3227 monster.X := MousePos.X-MapOffset.X;
3228 monster.Y := MousePos.Y-MapOffset.Y;
3230 if not (ssCtrl in Shift) then
3231 begin
3232 monster.X := monster.X - (MonsterSize[monster.MonsterType].Width div 2);
3233 monster.Y := monster.Y - MonsterSize[monster.MonsterType].Height;
3234 end;
3236 if rbMonsterLeft.Checked then
3237 monster.Direction := D_LEFT
3238 else
3239 monster.Direction := D_RIGHT;
3240 Undo_Add(OBJECT_MONSTER, AddMonster(monster));
3241 end;
3242 3:
3243 if lbAreasList.ItemIndex = -1 then
3244 ErrorMessageBox(_lc[I_MSG_CHOOSE_AREA])
3245 else
3246 if (lbAreasList.ItemIndex + 1) <> AREA_DOMFLAG then
3247 begin
3248 area.AreaType := lbAreasList.ItemIndex + AREA_PLAYERPOINT1;
3249 area.X := MousePos.X-MapOffset.X;
3250 area.Y := MousePos.Y-MapOffset.Y;
3252 if not (ssCtrl in Shift) then
3253 begin
3254 area.X := area.X - (AreaSize[area.AreaType].Width div 2);
3255 area.Y := area.Y - AreaSize[area.AreaType].Height;
3256 end;
3258 if rbAreaLeft.Checked then
3259 area.Direction := D_LEFT
3260 else
3261 area.Direction := D_RIGHT;
3262 Undo_Add(OBJECT_AREA, AddArea(area));
3263 end;
3264 end;
3265 end
3266 else
3267 begin
3268 i := GetFirstSelected();
3270 // Выбираем объект под текущим:
3271 if (SelectedObjects <> nil) and
3272 (ssShift in Shift) and (i >= 0) and
3273 (SelectedObjects[i].Live) then
3274 begin
3275 if SelectedObjectCount() = 1 then
3276 SelectNextObject(X-MapOffset.X, Y-MapOffset.Y,
3277 SelectedObjects[i].ObjectType,
3278 SelectedObjects[i].ID);
3279 end
3280 else
3281 begin
3282 // Рисуем область триггера "Расширитель":
3283 if DrawPressRect and (i >= 0) and
3284 (SelectedObjects[i].ObjectType = OBJECT_TRIGGER) and
3285 (gTriggers[SelectedObjects[i].ID].TriggerType in
3286 [TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF]) then
3287 MouseAction := MOUSEACTION_DRAWPRESS
3288 else // Рисуем панель:
3289 if pcObjects.ActivePageIndex = 0 then
3290 begin
3291 if (lbPanelType.ItemIndex >= 0) then
3292 MouseAction := MOUSEACTION_DRAWPANEL
3293 end
3294 else // Рисуем триггер:
3295 if (lbTriggersList.ItemIndex >= 0) then
3296 begin
3297 MouseAction := MOUSEACTION_DRAWTRIGGER;
3298 end;
3299 end;
3300 end;
3301 end; // if Button = mbLeft
3303 if Button = mbRight then // Right Mouse Button
3304 begin
3305 // Клик по мини-карте:
3306 if ShowMap and
3307 g_CollidePoint(X, Y,
3308 RenderPanel.Width-max(gMapInfo.Width div (16 div Scale), 1)-1,
3309 1,
3310 max(gMapInfo.Width div (16 div Scale), 1),
3311 max(gMapInfo.Height div (16 div Scale), 1) ) then
3312 begin
3313 MouseAction := MOUSEACTION_NOACTION;
3314 end
3315 else // Нужно что-то выбрать мышью:
3316 if SelectFlag <> SELECTFLAG_NONE then
3317 begin
3318 case SelectFlag of
3319 SELECTFLAG_TELEPORT:
3320 // Точку назначения телепортации:
3321 with gTriggers[SelectedObjects[
3322 GetFirstSelected() ].ID].Data.TargetPoint do
3323 begin
3324 X := MousePos.X-MapOffset.X;
3325 Y := MousePos.Y-MapOffset.Y;
3326 end;
3328 SELECTFLAG_SPAWNPOINT:
3329 // Точку создания монстра:
3330 with gTriggers[SelectedObjects[GetFirstSelected()].ID] do
3331 if TriggerType = TRIGGER_SPAWNMONSTER then
3332 begin
3333 Data.MonPos.X := MousePos.X-MapOffset.X;
3334 Data.MonPos.Y := MousePos.Y-MapOffset.Y;
3335 end
3336 else if TriggerType = TRIGGER_SPAWNITEM then
3337 begin // Точка создания предмета:
3338 Data.ItemPos.X := MousePos.X-MapOffset.X;
3339 Data.ItemPos.Y := MousePos.Y-MapOffset.Y;
3340 end
3341 else if TriggerType = TRIGGER_SHOT then
3342 begin // Точка создания выстрела:
3343 Data.ShotPos.X := MousePos.X-MapOffset.X;
3344 Data.ShotPos.Y := MousePos.Y-MapOffset.Y;
3345 end;
3347 SELECTFLAG_DOOR:
3348 // Дверь:
3349 begin
3350 IDArray := ObjectInRect(X-MapOffset.X,
3351 Y-MapOffset.Y,
3352 2, 2, OBJECT_PANEL, True);
3353 if IDArray <> nil then
3354 begin
3355 for i := 0 to High(IDArray) do
3356 if (gPanels[IDArray[i]].PanelType = PANEL_OPENDOOR) or
3357 (gPanels[IDArray[i]].PanelType = PANEL_CLOSEDOOR) then
3358 begin
3359 gTriggers[SelectedObjects[
3360 GetFirstSelected() ].ID].Data.PanelID := IDArray[i];
3361 Break;
3362 end;
3363 end
3364 else
3365 gTriggers[SelectedObjects[
3366 GetFirstSelected() ].ID].Data.PanelID := -1;
3367 end;
3369 SELECTFLAG_TEXTURE:
3370 // Панель с текстурой:
3371 begin
3372 IDArray := ObjectInRect(X-MapOffset.X,
3373 Y-MapOffset.Y,
3374 2, 2, OBJECT_PANEL, True);
3375 if IDArray <> nil then
3376 begin
3377 for i := 0 to High(IDArray) do
3378 if ((gPanels[IDArray[i]].PanelType in
3379 [PANEL_WALL, PANEL_BACK, PANEL_FORE,
3380 PANEL_WATER, PANEL_ACID1, PANEL_ACID2,
3381 PANEL_STEP]) or
3382 (gPanels[IDArray[i]].PanelType = PANEL_OPENDOOR) or
3383 (gPanels[IDArray[i]].PanelType = PANEL_CLOSEDOOR)) and
3384 (gPanels[IDArray[i]].TextureName <> '') then
3385 begin
3386 gTriggers[SelectedObjects[
3387 GetFirstSelected() ].ID].TexturePanel := IDArray[i];
3388 Break;
3389 end;
3390 end
3391 else
3392 gTriggers[SelectedObjects[
3393 GetFirstSelected() ].ID].TexturePanel := -1;
3394 end;
3396 SELECTFLAG_LIFT:
3397 // Лифт:
3398 begin
3399 IDArray := ObjectInRect(X-MapOffset.X,
3400 Y-MapOffset.Y,
3401 2, 2, OBJECT_PANEL, True);
3402 if IDArray <> nil then
3403 begin
3404 for i := 0 to High(IDArray) do
3405 if (gPanels[IDArray[i]].PanelType = PANEL_LIFTUP) or
3406 (gPanels[IDArray[i]].PanelType = PANEL_LIFTDOWN) or
3407 (gPanels[IDArray[i]].PanelType = PANEL_LIFTLEFT) or
3408 (gPanels[IDArray[i]].PanelType = PANEL_LIFTRIGHT) then
3409 begin
3410 gTriggers[SelectedObjects[
3411 GetFirstSelected() ].ID].Data.PanelID := IDArray[i];
3412 Break;
3413 end;
3414 end
3415 else
3416 gTriggers[SelectedObjects[
3417 GetFirstSelected() ].ID].Data.PanelID := -1;
3418 end;
3420 SELECTFLAG_MONSTER:
3421 // Монстра:
3422 begin
3423 IDArray := ObjectInRect(X-MapOffset.X,
3424 Y-MapOffset.Y,
3425 2, 2, OBJECT_MONSTER, False);
3426 if IDArray <> nil then
3427 gTriggers[SelectedObjects[
3428 GetFirstSelected() ].ID].Data.MonsterID := IDArray[0]+1
3429 else
3430 gTriggers[SelectedObjects[
3431 GetFirstSelected() ].ID].Data.MonsterID := 0;
3432 end;
3434 SELECTFLAG_SHOTPANEL:
3435 // Панель индикации выстрела:
3436 begin
3437 if gTriggers[SelectedObjects[
3438 GetFirstSelected() ].ID].TriggerType = TRIGGER_SHOT then
3439 begin
3440 IDArray := ObjectInRect(X-MapOffset.X,
3441 Y-MapOffset.Y,
3442 2, 2, OBJECT_PANEL, True);
3443 if IDArray <> nil then
3444 begin
3445 for i := 0 to High(IDArray) do
3446 if ((gPanels[IDArray[i]].PanelType in
3447 [PANEL_WALL, PANEL_BACK, PANEL_FORE,
3448 PANEL_WATER, PANEL_ACID1, PANEL_ACID2,
3449 PANEL_STEP]) or
3450 (gPanels[IDArray[i]].PanelType = PANEL_OPENDOOR) or
3451 (gPanels[IDArray[i]].PanelType = PANEL_CLOSEDOOR)) and
3452 (gPanels[IDArray[i]].TextureName <> '') then
3453 begin
3454 gTriggers[SelectedObjects[
3455 GetFirstSelected() ].ID].Data.ShotPanelID := IDArray[i];
3456 Break;
3457 end;
3458 end
3459 else
3460 gTriggers[SelectedObjects[
3461 GetFirstSelected() ].ID].Data.ShotPanelID := -1;
3462 end;
3463 end;
3464 end;
3466 SelectFlag := SELECTFLAG_SELECTED;
3467 end
3468 else // if SelectFlag <> SELECTFLAG_NONE...
3469 begin
3470 // Что уже выбрано и не нажат Ctrl:
3471 if (SelectedObjects <> nil) and
3472 (not (ssCtrl in Shift)) then
3473 for i := 0 to High(SelectedObjects) do
3474 with SelectedObjects[i] do
3475 if Live then
3476 begin
3477 if (ObjectType in [OBJECT_PANEL, OBJECT_TRIGGER]) and
3478 (SelectedObjectCount() = 1) then
3479 begin
3480 Rect := ObjectGetRect(ObjectType, ID);
3482 c1 := g_Collide(X-MapOffset.X-1, Y-MapOffset.Y-1, 2, 2,
3483 Rect.X-2, Rect.Y+(Rect.Height div 2)-2, 4, 4);
3484 c2 := g_Collide(X-MapOffset.X-1, Y-MapOffset.Y-1, 2, 2,
3485 Rect.X+Rect.Width-3, Rect.Y+(Rect.Height div 2)-2, 4, 4);
3486 c3 := g_Collide(X-MapOffset.X-1, Y-MapOffset.Y-1, 2, 2,
3487 Rect.X+(Rect.Width div 2)-2, Rect.Y-2, 4, 4);
3488 c4 := g_Collide(X-MapOffset.X-1, Y-MapOffset.Y-1, 2, 2,
3489 Rect.X+(Rect.Width div 2)-2, Rect.Y+Rect.Height-3, 4, 4);
3491 // Меняем размер панели или триггера:
3492 if c1 or c2 or c3 or c4 then
3493 begin
3494 MouseAction := MOUSEACTION_RESIZE;
3495 LastMovePoint := MousePos;
3497 if c1 or c2 then
3498 begin // Шире/уже
3499 ResizeType := RESIZETYPE_HORIZONTAL;
3500 if c1 then
3501 ResizeDirection := RESIZEDIR_LEFT
3502 else
3503 ResizeDirection := RESIZEDIR_RIGHT;
3504 RenderPanel.Cursor := crSizeWE;
3505 end
3506 else
3507 begin // Выше/ниже
3508 ResizeType := RESIZETYPE_VERTICAL;
3509 if c3 then
3510 ResizeDirection := RESIZEDIR_UP
3511 else
3512 ResizeDirection := RESIZEDIR_DOWN;
3513 RenderPanel.Cursor := crSizeNS;
3514 end;
3516 Break;
3517 end;
3518 end;
3520 // Перемещаем панель или триггер:
3521 if ObjectCollide(ObjectType, ID,
3522 X-MapOffset.X-1,
3523 Y-MapOffset.Y-1, 2, 2) then
3524 begin
3525 MouseAction := MOUSEACTION_MOVEOBJ;
3526 LastMovePoint := MousePos;
3528 Break;
3529 end;
3530 end;
3531 end;
3532 end; // if Button = mbRight
3534 MouseRDown := Button = mbRight;
3535 if MouseRDown then
3536 MouseRDownPos := MousePos;
3538 MouseLDown := Button = mbLeft;
3539 if MouseLDown then
3540 MouseLDownPos := MousePos;
3541 end;
3543 procedure TMainForm.RenderPanelMouseUp(Sender: TObject;
3544 Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
3545 var
3546 panel: TPanel;
3547 trigger: TTrigger;
3548 i: Integer;
3549 IDArray: DWArray;
3550 rRect: TRectWH;
3551 rSelectRect: Boolean;
3552 begin
3553 if Button = mbLeft then
3554 MouseLDown := False;
3555 if Button = mbRight then
3556 MouseRDown := False;
3558 DrawRect := nil;
3559 ResizeType := RESIZETYPE_NONE;
3561 if Button = mbLeft then // Left Mouse Button
3562 begin
3563 if MouseAction <> MOUSEACTION_NONE then
3564 begin // Было действие мышью
3565 // Мышь сдвинулась во время удержания клавиши:
3566 if (MousePos.X <> MouseLDownPos.X) and
3567 (MousePos.Y <> MouseLDownPos.Y) then
3568 case MouseAction of
3569 // Рисовали панель:
3570 MOUSEACTION_DRAWPANEL:
3571 begin
3572 // Фон или передний план без текстуры - ошибка:
3573 if (lbPanelType.ItemIndex in [1, 2]) and
3574 (lbTextureList.ItemIndex = -1) then
3575 ErrorMessageBox(_lc[I_MSG_CHOOSE_TEXTURE])
3576 else // Назначаем параметры панели:
3577 begin
3578 case lbPanelType.ItemIndex of
3579 0: Panel.PanelType := PANEL_WALL;
3580 1: Panel.PanelType := PANEL_BACK;
3581 2: Panel.PanelType := PANEL_FORE;
3582 3: Panel.PanelType := PANEL_OPENDOOR;
3583 4: Panel.PanelType := PANEL_CLOSEDOOR;
3584 5: Panel.PanelType := PANEL_STEP;
3585 6: Panel.PanelType := PANEL_WATER;
3586 7: Panel.PanelType := PANEL_ACID1;
3587 8: Panel.PanelType := PANEL_ACID2;
3588 9: Panel.PanelType := PANEL_LIFTUP;
3589 10: Panel.PanelType := PANEL_LIFTDOWN;
3590 11: Panel.PanelType := PANEL_LIFTLEFT;
3591 12: Panel.PanelType := PANEL_LIFTRIGHT;
3592 13: Panel.PanelType := PANEL_BLOCKMON;
3593 end;
3595 Panel.X := Min(MousePos.X-MapOffset.X, MouseLDownPos.X-MapOffset.X);
3596 Panel.Y := Min(MousePos.Y-MapOffset.Y, MouseLDownPos.Y-MapOffset.Y);
3597 Panel.Width := Abs(MousePos.X-MouseLDownPos.X);
3598 Panel.Height := Abs(MousePos.Y-MouseLDownPos.Y);
3600 // Лифты, блокМон или отсутствие текстуры - пустая текстура:
3601 if (lbPanelType.ItemIndex in [9, 10, 11, 12, 13]) or
3602 (lbTextureList.ItemIndex = -1) then
3603 begin
3604 Panel.TextureHeight := 1;
3605 Panel.TextureWidth := 1;
3606 Panel.TextureName := '';
3607 Panel.TextureID := TEXTURE_SPECIAL_NONE;
3608 end
3609 else // Есть текстура:
3610 begin
3611 Panel.TextureName := SelectedTexture();
3613 // Обычная текстура:
3614 if not IsSpecialTextureSel() then
3615 begin
3616 g_GetTextureSizeByName(Panel.TextureName,
3617 Panel.TextureWidth, Panel.TextureHeight);
3618 g_GetTexture(Panel.TextureName, Panel.TextureID);
3619 end
3620 else // Спец.текстура:
3621 begin
3622 Panel.TextureHeight := 1;
3623 Panel.TextureWidth := 1;
3624 Panel.TextureID := SpecialTextureID(SelectedTexture());
3625 end;
3626 end;
3628 Panel.Alpha := 0;
3629 Panel.Blending := False;
3631 Undo_Add(OBJECT_PANEL, AddPanel(Panel));
3632 end;
3633 end;
3635 // Рисовали триггер:
3636 MOUSEACTION_DRAWTRIGGER:
3637 begin
3638 trigger.X := Min(MousePos.X-MapOffset.X, MouseLDownPos.X-MapOffset.X);
3639 trigger.Y := Min(MousePos.Y-MapOffset.Y, MouseLDownPos.Y-MapOffset.Y);
3640 trigger.Width := Abs(MousePos.X-MouseLDownPos.X);
3641 trigger.Height := Abs(MousePos.Y-MouseLDownPos.Y);
3643 trigger.Enabled := True;
3644 trigger.TriggerType := lbTriggersList.ItemIndex+1;
3645 trigger.TexturePanel := -1;
3647 // Типы активации:
3648 trigger.ActivateType := 0;
3650 if clbActivationType.Checked[0] then
3651 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_PLAYERCOLLIDE;
3652 if clbActivationType.Checked[1] then
3653 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_MONSTERCOLLIDE;
3654 if clbActivationType.Checked[2] then
3655 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_PLAYERPRESS;
3656 if clbActivationType.Checked[3] then
3657 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_MONSTERPRESS;
3658 if clbActivationType.Checked[4] then
3659 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_SHOT;
3660 if clbActivationType.Checked[5] then
3661 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_NOMONSTER;
3663 // Необходимые для активации ключи:
3664 trigger.Key := 0;
3666 if clbKeys.Checked[0] then
3667 trigger.Key := Trigger.Key or KEY_RED;
3668 if clbKeys.Checked[1] then
3669 trigger.Key := Trigger.Key or KEY_GREEN;
3670 if clbKeys.Checked[2] then
3671 trigger.Key := Trigger.Key or KEY_BLUE;
3672 if clbKeys.Checked[3] then
3673 trigger.Key := Trigger.Key or KEY_REDTEAM;
3674 if clbKeys.Checked[4] then
3675 trigger.Key := Trigger.Key or KEY_BLUETEAM;
3677 // Параметры триггера:
3678 FillByte(trigger.Data.Default[0], 128, 0);
3680 case trigger.TriggerType of
3681 // Переключаемая панель:
3682 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
3683 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP,
3684 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
3685 begin
3686 Trigger.Data.PanelID := -1;
3687 end;
3689 // Телепортация:
3690 TRIGGER_TELEPORT:
3691 begin
3692 trigger.Data.TargetPoint.X := trigger.X-64;
3693 trigger.Data.TargetPoint.Y := trigger.Y-64;
3694 trigger.Data.d2d_teleport := True;
3695 trigger.Data.TlpDir := 0;
3696 end;
3698 // Изменение других триггеров:
3699 TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF,
3700 TRIGGER_ONOFF:
3701 begin
3702 trigger.Data.Count := 1;
3703 end;
3705 // Звук:
3706 TRIGGER_SOUND:
3707 begin
3708 trigger.Data.Volume := 255;
3709 trigger.Data.Pan := 127;
3710 trigger.Data.PlayCount := 1;
3711 trigger.Data.Local := True;
3712 trigger.Data.SoundSwitch := False;
3713 end;
3715 // Музыка:
3716 TRIGGER_MUSIC:
3717 begin
3718 trigger.Data.MusicAction := 1;
3719 end;
3721 // Создание монстра:
3722 TRIGGER_SPAWNMONSTER:
3723 begin
3724 trigger.Data.MonType := MONSTER_ZOMBY;
3725 trigger.Data.MonPos.X := trigger.X-64;
3726 trigger.Data.MonPos.Y := trigger.Y-64;
3727 trigger.Data.MonHealth := 0;
3728 trigger.Data.MonActive := False;
3729 trigger.Data.MonCount := 1;
3730 end;
3732 // Создание предмета:
3733 TRIGGER_SPAWNITEM:
3734 begin
3735 trigger.Data.ItemType := ITEM_AMMO_BULLETS;
3736 trigger.Data.ItemPos.X := trigger.X-64;
3737 trigger.Data.ItemPos.Y := trigger.Y-64;
3738 trigger.Data.ItemOnlyDM := False;
3739 trigger.Data.ItemFalls := False;
3740 trigger.Data.ItemCount := 1;
3741 trigger.Data.ItemMax := 0;
3742 trigger.Data.ItemDelay := 0;
3743 end;
3745 // Ускорение:
3746 TRIGGER_PUSH:
3747 begin
3748 trigger.Data.PushAngle := 90;
3749 trigger.Data.PushForce := 10;
3750 trigger.Data.ResetVel := True;
3751 end;
3753 TRIGGER_SCORE:
3754 begin
3755 trigger.Data.ScoreCount := 1;
3756 trigger.Data.ScoreCon := True;
3757 trigger.Data.ScoreMsg := True;
3758 end;
3760 TRIGGER_MESSAGE:
3761 begin
3762 trigger.Data.MessageKind := 0;
3763 trigger.Data.MessageSendTo := 0;
3764 trigger.Data.MessageText := '';
3765 trigger.Data.MessageTime := 144;
3766 end;
3768 TRIGGER_DAMAGE:
3769 begin
3770 trigger.Data.DamageValue := 5;
3771 trigger.Data.DamageInterval := 12;
3772 end;
3774 TRIGGER_HEALTH:
3775 begin
3776 trigger.Data.HealValue := 5;
3777 trigger.Data.HealInterval := 36;
3778 end;
3780 TRIGGER_SHOT:
3781 begin
3782 trigger.Data.ShotType := TRIGGER_SHOT_BULLET;
3783 trigger.Data.ShotSound := True;
3784 trigger.Data.ShotPanelID := -1;
3785 trigger.Data.ShotTarget := 0;
3786 trigger.Data.ShotIntSight := 0;
3787 trigger.Data.ShotAim := TRIGGER_SHOT_AIM_DEFAULT;
3788 trigger.Data.ShotPos.X := trigger.X-64;
3789 trigger.Data.ShotPos.Y := trigger.Y-64;
3790 trigger.Data.ShotAngle := 0;
3791 trigger.Data.ShotWait := 18;
3792 trigger.Data.ShotAccuracy := 0;
3793 trigger.Data.ShotAmmo := 0;
3794 trigger.Data.ShotIntReload := 0;
3795 end;
3797 TRIGGER_EFFECT:
3798 begin
3799 trigger.Data.FXCount := 1;
3800 trigger.Data.FXType := TRIGGER_EFFECT_PARTICLE;
3801 trigger.Data.FXSubType := TRIGGER_EFFECT_SLIQUID;
3802 trigger.Data.FXColorR := 0;
3803 trigger.Data.FXColorG := 0;
3804 trigger.Data.FXColorB := 255;
3805 trigger.Data.FXPos := TRIGGER_EFFECT_POS_CENTER;
3806 trigger.Data.FXWait := 1;
3807 trigger.Data.FXVelX := 0;
3808 trigger.Data.FXVelY := -20;
3809 trigger.Data.FXSpreadL := 5;
3810 trigger.Data.FXSpreadR := 5;
3811 trigger.Data.FXSpreadU := 4;
3812 trigger.Data.FXSpreadD := 0;
3813 end;
3814 end;
3816 Undo_Add(OBJECT_TRIGGER, AddTrigger(trigger));
3817 end;
3819 // Рисовали область триггера "Расширитель":
3820 MOUSEACTION_DRAWPRESS:
3821 with gTriggers[SelectedObjects[GetFirstSelected].ID] do
3822 begin
3823 Data.tX := Min(MousePos.X-MapOffset.X, MouseLDownPos.X-MapOffset.X);
3824 Data.tY := Min(MousePos.Y-MapOffset.Y, MouseLDownPos.Y-MapOffset.Y);
3825 Data.tWidth := Abs(MousePos.X-MouseLDownPos.X);
3826 Data.tHeight := Abs(MousePos.Y-MouseLDownPos.Y);
3828 DrawPressRect := False;
3829 end;
3830 end;
3832 MouseAction := MOUSEACTION_NONE;
3833 end;
3834 end // if Button = mbLeft...
3835 else // Right Mouse Button:
3836 begin
3837 if MouseAction = MOUSEACTION_NOACTION then
3838 begin
3839 MouseAction := MOUSEACTION_NONE;
3840 Exit;
3841 end;
3843 // Объект передвинут или изменен в размере:
3844 if MouseAction in [MOUSEACTION_MOVEOBJ, MOUSEACTION_RESIZE] then
3845 begin
3846 MouseAction := MOUSEACTION_NONE;
3847 FillProperty();
3848 Exit;
3849 end;
3851 // Еще не все выбрали:
3852 if SelectFlag <> SELECTFLAG_NONE then
3853 begin
3854 if SelectFlag = SELECTFLAG_SELECTED then
3855 SelectFlag := SELECTFLAG_NONE;
3856 FillProperty();
3857 Exit;
3858 end;
3860 // Мышь сдвинулась во время удержания клавиши:
3861 if (MousePos.X <> MouseRDownPos.X) and
3862 (MousePos.Y <> MouseRDownPos.Y) then
3863 begin
3864 rSelectRect := True;
3866 rRect.X := Min(MousePos.X, MouseRDownPos.X)-MapOffset.X;
3867 rRect.Y := Min(MousePos.Y, MouseRDownPos.Y)-MapOffset.Y;
3868 rRect.Width := Abs(MousePos.X-MouseRDownPos.X);
3869 rRect.Height := Abs(MousePos.Y-MouseRDownPos.Y);
3870 end
3871 else // Мышь не сдвинулась - нет прямоугольника:
3872 begin
3873 rSelectRect := False;
3875 rRect.X := X-MapOffset.X-1;
3876 rRect.Y := Y-MapOffset.Y-1;
3877 rRect.Width := 2;
3878 rRect.Height := 2;
3879 end;
3881 // Если зажат Ctrl - выделять еще, иначе только один выделенный объект:
3882 if not (ssCtrl in Shift) then
3883 RemoveSelectFromObjects();
3885 // Выделяем всё в выбранном прямоугольнике:
3886 IDArray := ObjectInRect(rRect.X, rRect.Y,
3887 rRect.Width, rRect.Height,
3888 pcObjects.ActivePageIndex+1, rSelectRect);
3890 if IDArray <> nil then
3891 for i := 0 to High(IDArray) do
3892 SelectObject(pcObjects.ActivePageIndex+1, IDArray[i],
3893 (ssCtrl in Shift) or rSelectRect);
3895 FillProperty();
3896 end;
3897 end;
3899 procedure TMainForm.RenderPanelPaint(Sender: TObject);
3900 begin
3901 Draw();
3902 end;
3904 procedure TMainForm.RenderPanelMouseMove(Sender: TObject;
3905 Shift: TShiftState; X, Y: Integer);
3906 var
3907 sX, sY: Integer;
3908 dWidth, dHeight: Integer;
3909 _id: Integer;
3910 begin
3911 _id := GetFirstSelected();
3913 // Рисуем панель с текстурой, сетка - размеры текстуры:
3914 if (MouseAction = MOUSEACTION_DRAWPANEL) and
3915 (lbPanelType.ItemIndex in [0..8]) and
3916 (lbTextureList.ItemIndex <> -1) and
3917 (not IsSpecialTextureSel()) then
3918 begin
3919 sX := StrToIntDef(lTextureWidth.Caption, DotStep);
3920 sY := StrToIntDef(lTextureHeight.Caption, DotStep);
3921 end
3922 else
3923 // Меняем размер панели с текстурой, сетка - размеры текстуры:
3924 if (MouseAction = MOUSEACTION_RESIZE) and
3925 ( (SelectedObjects[_id].ObjectType = OBJECT_PANEL) and
3926 IsTexturedPanel(gPanels[SelectedObjects[_id].ID].PanelType) and
3927 (gPanels[SelectedObjects[_id].ID].TextureName <> '') and
3928 (not IsSpecialTexture(gPanels[SelectedObjects[_id].ID].TextureName)) ) then
3929 begin
3930 sX := gPanels[SelectedObjects[_id].ID].TextureWidth;
3931 sY := gPanels[SelectedObjects[_id].ID].TextureHeight;
3932 end
3933 else
3934 // Выравнивание по сетке:
3935 if SnapToGrid then
3936 begin
3937 sX := DotStep;
3938 sY := DotStep;
3939 end
3940 else // Нет выравнивания по сетке:
3941 begin
3942 sX := 1;
3943 sY := 1;
3944 end;
3946 // Новая позиция мыши:
3947 if MouseLDown then
3948 begin // Зажата левая кнопка мыши
3949 MousePos.X := (Round((X-MouseLDownPos.X)/sX)*sX)+MouseLDownPos.X;
3950 MousePos.Y := (Round((Y-MouseLDownPos.Y)/sY)*sY)+MouseLDownPos.Y;
3951 end
3952 else
3953 if MouseRDown then
3954 begin // Зажата правая кнопка мыши
3955 MousePos.X := (Round((X-MouseRDownPos.X)/sX)*sX)+MouseRDownPos.X;
3956 MousePos.Y := (Round((Y-MouseRDownPos.Y)/sY)*sY)+MouseRDownPos.Y;
3957 end
3958 else
3959 begin // Кнопки мыши не зажаты
3960 MousePos.X := (Round(X/sX)*sX);
3961 MousePos.Y := (Round(Y/sY)*sY);
3962 end;
3964 // Изменение размера закончилось - ставим обычный курсор:
3965 if ResizeType = RESIZETYPE_NONE then
3966 RenderPanel.Cursor := crDefault;
3968 // Зажата только правая кнопка мыши:
3969 if (not MouseLDown) and (MouseRDown) then
3970 begin
3971 // Рисуем прямоугольник выделения:
3972 if MouseAction = MOUSEACTION_NONE then
3973 begin
3974 if DrawRect = nil then
3975 New(DrawRect);
3976 DrawRect.Top := MouseRDownPos.y;
3977 DrawRect.Left := MouseRDownPos.x;
3978 DrawRect.Bottom := MousePos.y;
3979 DrawRect.Right := MousePos.x;
3980 end
3981 else
3982 // Двигаем выделенные объекты:
3983 if MouseAction = MOUSEACTION_MOVEOBJ then
3984 begin
3985 MoveSelectedObjects(ssShift in Shift, ssCtrl in Shift,
3986 MousePos.X-LastMovePoint.X+WASDOffset.X,
3987 MousePos.Y-LastMovePoint.Y+WASDOffset.Y);
3988 WASDOffset.X := 0;
3989 WASDOffset.Y := 0;
3990 end
3991 else
3992 // Меняем размер выделенного объекта:
3993 if MouseAction = MOUSEACTION_RESIZE then
3994 begin
3995 if (SelectedObjectCount = 1) and
3996 (SelectedObjects[GetFirstSelected].Live) then
3997 begin
3998 dWidth := MousePos.X-LastMovePoint.X+WASDOffset.X;
3999 dHeight := MousePos.Y-LastMovePoint.Y+WASDOffset.Y;
4000 WASDOffset.X := 0;
4001 WASDOffset.Y := 0;
4003 case ResizeType of
4004 RESIZETYPE_VERTICAL: dWidth := 0;
4005 RESIZETYPE_HORIZONTAL: dHeight := 0;
4006 end;
4008 case ResizeDirection of
4009 RESIZEDIR_UP: dHeight := -dHeight;
4010 RESIZEDIR_LEFT: dWidth := -dWidth;
4011 end;
4013 ResizeObject(SelectedObjects[GetFirstSelected].ObjectType,
4014 SelectedObjects[GetFirstSelected].ID,
4015 dWidth, dHeight, ResizeDirection);
4017 LastMovePoint := MousePos;
4018 end;
4019 end;
4020 end;
4022 // Зажата только левая кнопка мыши:
4023 if (not MouseRDown) and (MouseLDown) then
4024 begin
4025 // Рисуем прямоугольник планирования панели:
4026 if MouseAction in [MOUSEACTION_DRAWPANEL,
4027 MOUSEACTION_DRAWTRIGGER,
4028 MOUSEACTION_DRAWPRESS] then
4029 begin
4030 if DrawRect = nil then
4031 New(DrawRect);
4032 DrawRect.Top := MouseLDownPos.y;
4033 DrawRect.Left := MouseLDownPos.x;
4034 DrawRect.Bottom := MousePos.y;
4035 DrawRect.Right := MousePos.x;
4036 end
4037 else // Двигаем карту:
4038 if MouseAction = MOUSEACTION_MOVEMAP then
4039 begin
4040 MoveMap(X, Y);
4041 end;
4042 end;
4044 // Клавиши мыши не зажаты:
4045 if (not MouseRDown) and (not MouseLDown) then
4046 DrawRect := nil;
4048 // Строка состояния - координаты мыши:
4049 StatusBar.Panels[1].Text := Format('(%d:%d)',
4050 [MousePos.X-MapOffset.X, MousePos.Y-MapOffset.Y]);
4051 end;
4053 procedure TMainForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
4054 begin
4055 CanClose := MessageBox(0, PChar(_lc[I_MSG_EXIT_PROMT]),
4056 PChar(_lc[I_MSG_EXIT]),
4057 MB_ICONQUESTION or MB_YESNO or
4058 MB_DEFBUTTON1) = idYes;
4059 end;
4061 procedure TMainForm.aExitExecute(Sender: TObject);
4062 begin
4063 Close();
4064 end;
4066 procedure TMainForm.FormDestroy(Sender: TObject);
4067 var
4068 config: TConfig;
4069 i: Integer;
4070 begin
4071 config := TConfig.CreateFile(EditorDir+'Editor.cfg');
4073 if WindowState <> wsMaximized then
4074 begin
4075 config.WriteInt('Editor', 'XPos', Left);
4076 config.WriteInt('Editor', 'YPos', Top);
4077 config.WriteInt('Editor', 'Width', Width);
4078 config.WriteInt('Editor', 'Height', Height);
4079 end
4080 else
4081 begin
4082 config.WriteInt('Editor', 'XPos', RestoredLeft);
4083 config.WriteInt('Editor', 'YPos', RestoredTop);
4084 config.WriteInt('Editor', 'Width', RestoredWidth);
4085 config.WriteInt('Editor', 'Height', RestoredHeight);
4086 end;
4087 config.WriteBool('Editor', 'Maximize', WindowState = wsMaximized);
4088 config.WriteBool('Editor', 'Minimap', ShowMap);
4089 config.WriteInt('Editor', 'PanelProps', PanelProps.ClientWidth);
4090 config.WriteInt('Editor', 'PanelObjs', PanelObjs.ClientHeight);
4091 config.WriteBool('Editor', 'DotEnable', DotEnable);
4092 config.WriteInt('Editor', 'DotStep', DotStep);
4093 config.WriteStr('Editor', 'LastOpenDir', OpenDialog.InitialDir);
4094 config.WriteStr('Editor', 'LastSaveDir', SaveDialog.InitialDir);
4095 config.WriteBool('Editor', 'EdgeShow', drEdge[3] < 255);
4096 config.WriteInt('Editor', 'EdgeColor', gColorEdge);
4097 config.WriteInt('Editor', 'EdgeAlpha', gAlphaEdge);
4098 config.WriteInt('Editor', 'LineAlpha', gAlphaTriggerLine);
4099 config.WriteInt('Editor', 'TriggerAlpha', gAlphaTriggerArea);
4101 for i := 0 to RecentCount-1 do
4102 if i < RecentFiles.Count then
4103 config.WriteStr('RecentFiles', IntToStr(i+1), RecentFiles[i])
4104 else
4105 config.WriteStr('RecentFiles', IntToStr(i+1), '');
4106 RecentFiles.Free();
4108 config.SaveFile(EditorDir+'Editor.cfg');
4109 config.Free();
4111 slInvalidTextures.Free;
4112 end;
4114 procedure TMainForm.RenderPanelResize(Sender: TObject);
4115 begin
4116 if MainForm.Visible then
4117 MainForm.Resize();
4118 end;
4120 procedure TMainForm.Splitter1Moved(Sender: TObject);
4121 begin
4122 FormResize(Sender);
4123 end;
4125 procedure TMainForm.aMapOptionsExecute(Sender: TObject);
4126 var
4127 ResName: String;
4128 begin
4129 MapOptionsForm.ShowModal();
4131 ResName := OpenedMap;
4132 while (Pos(':\', ResName) > 0) do
4133 Delete(ResName, 1, Pos(':\', ResName) + 1);
4135 UpdateCaption(gMapInfo.Name, ExtractFileName(OpenedWAD), ResName);
4136 end;
4138 procedure TMainForm.aAboutExecute(Sender: TObject);
4139 begin
4140 AboutForm.ShowModal();
4141 end;
4143 procedure TMainForm.FormKeyDown(Sender: TObject; var Key: Word;
4144 Shift: TShiftState);
4145 var
4146 dx, dy, i: Integer;
4147 FileName: String;
4148 begin
4149 if (not EditingProperties) then
4150 begin
4151 if Key = Ord('1') then
4152 SwitchLayer(LAYER_BACK);
4153 if Key = Ord('2') then
4154 SwitchLayer(LAYER_WALLS);
4155 if Key = Ord('3') then
4156 SwitchLayer(LAYER_FOREGROUND);
4157 if Key = Ord('4') then
4158 SwitchLayer(LAYER_STEPS);
4159 if Key = Ord('5') then
4160 SwitchLayer(LAYER_WATER);
4161 if Key = Ord('6') then
4162 SwitchLayer(LAYER_ITEMS);
4163 if Key = Ord('7') then
4164 SwitchLayer(LAYER_MONSTERS);
4165 if Key = Ord('8') then
4166 SwitchLayer(LAYER_AREAS);
4167 if Key = Ord('9') then
4168 SwitchLayer(LAYER_TRIGGERS);
4169 if Key = Ord('0') then
4170 tbShowClick(tbShow);
4172 if Key = Ord('V') then
4173 begin // Поворот монстров и областей:
4174 if (SelectedObjects <> nil) then
4175 begin
4176 for i := 0 to High(SelectedObjects) do
4177 if (SelectedObjects[i].Live) then
4178 begin
4179 if (SelectedObjects[i].ObjectType = OBJECT_MONSTER) then
4180 begin
4181 g_ChangeDir(gMonsters[SelectedObjects[i].ID].Direction);
4182 end
4183 else
4184 if (SelectedObjects[i].ObjectType = OBJECT_AREA) then
4185 begin
4186 g_ChangeDir(gAreas[SelectedObjects[i].ID].Direction);
4187 end;
4188 end;
4189 end
4190 else
4191 begin
4192 if pcObjects.ActivePage = tsMonsters then
4193 begin
4194 if rbMonsterLeft.Checked then
4195 rbMonsterRight.Checked := True
4196 else
4197 rbMonsterLeft.Checked := True;
4198 end;
4199 if pcObjects.ActivePage = tsAreas then
4200 begin
4201 if rbAreaLeft.Checked then
4202 rbAreaRight.Checked := True
4203 else
4204 rbAreaLeft.Checked := True;
4205 end;
4206 end;
4207 end;
4209 if not (ssCtrl in Shift) then
4210 begin
4211 // Быстрое превью карты:
4212 if Key = Ord('E') then
4213 begin
4214 if PreviewMode = 0 then
4215 PreviewMode := 2;
4216 end;
4218 // Вертикальный скролл карты:
4219 with sbVertical do
4220 begin
4221 if Key = Ord('W') then
4222 begin
4223 if (MouseLDown or MouseRDown) and (Position >= DotStep) then
4224 begin
4225 Dec(WASDOffset.Y, DotStep);
4226 RenderPanelMouseMove(Sender, Shift, LastMovePoint.X, LastMovePoint.Y);
4227 end;
4228 Position := IfThen(Position > DotStep, Position-DotStep, 0);
4229 MapOffset.Y := -Round(Position/16) * 16;
4230 end;
4232 if Key = Ord('S') then
4233 begin
4234 if (MouseLDown or MouseRDown) and (Position+DotStep <= Max) then
4235 begin
4236 Inc(WASDOffset.Y, DotStep);
4237 RenderPanelMouseMove(Sender, Shift, LastMovePoint.X, LastMovePoint.Y);
4238 end;
4239 Position := IfThen(Position+DotStep < Max, Position+DotStep, Max);
4240 MapOffset.Y := -Round(Position/16) * 16;
4241 end;
4242 end;
4244 // Горизонтальный скролл карты:
4245 with sbHorizontal do
4246 begin
4247 if Key = Ord('A') then
4248 begin
4249 if (MouseLDown or MouseRDown) and (Position >= DotStep) then
4250 begin
4251 Dec(WASDOffset.X, DotStep);
4252 RenderPanelMouseMove(Sender, Shift, LastMovePoint.X, LastMovePoint.Y);
4253 end;
4254 Position := IfThen(Position > DotStep, Position-DotStep, 0);
4255 MapOffset.X := -Round(Position/16) * 16;
4256 end;
4258 if Key = Ord('D') then
4259 begin
4260 if (MouseLDown or MouseRDown) and (Position+DotStep <= Max) then
4261 begin
4262 Inc(WASDOffset.X, DotStep);
4263 RenderPanelMouseMove(Sender, Shift, LastMovePoint.X, LastMovePoint.Y);
4264 end;
4265 Position := IfThen(Position+DotStep < Max, Position+DotStep, Max);
4266 MapOffset.X := -Round(Position/16) * 16;
4267 end;
4268 end;
4269 end;
4270 end;
4272 // Удалить выделенные объекты:
4273 if (Key = VK_DELETE) and (SelectedObjects <> nil) and
4274 RenderPanel.Focused() then
4275 DeleteSelectedObjects();
4277 // Снять выделение:
4278 if (Key = VK_ESCAPE) and (SelectedObjects <> nil) then
4279 RemoveSelectFromObjects();
4281 // Передвинуть объекты:
4282 if MainForm.ActiveControl = RenderPanel then
4283 begin
4284 dx := 0;
4285 dy := 0;
4287 if Key = VK_NUMPAD4 then
4288 dx := IfThen(ssAlt in Shift, -1, -DotStep);
4289 if Key = VK_NUMPAD6 then
4290 dx := IfThen(ssAlt in Shift, 1, DotStep);
4291 if Key = VK_NUMPAD8 then
4292 dy := IfThen(ssAlt in Shift, -1, -DotStep);
4293 if Key = VK_NUMPAD5 then
4294 dy := IfThen(ssAlt in Shift, 1, DotStep);
4296 if (dx <> 0) or (dy <> 0) then
4297 begin
4298 MoveSelectedObjects(ssShift in Shift, ssCtrl in Shift, dx, dy);
4299 Key := 0;
4300 end;
4301 end;
4303 if ssCtrl in Shift then
4304 begin
4305 // Выбор панели с текстурой для триггера
4306 if Key = Ord('T') then
4307 begin
4308 DrawPressRect := False;
4309 if SelectFlag = SELECTFLAG_TEXTURE then
4310 begin
4311 SelectFlag := SELECTFLAG_NONE;
4312 Exit;
4313 end;
4314 vleObjectProperty.FindRow(_lc[I_PROP_TR_TEXTURE_PANEL], i);
4315 if i > 0 then
4316 SelectFlag := SELECTFLAG_TEXTURE;
4317 end;
4319 if Key = Ord('D') then
4320 begin
4321 SelectFlag := SELECTFLAG_NONE;
4322 if DrawPressRect then
4323 begin
4324 DrawPressRect := False;
4325 Exit;
4326 end;
4327 i := -1;
4329 // Выбор области воздействия, в зависимости от типа триггера
4330 vleObjectProperty.FindRow(_lc[I_PROP_TR_EX_AREA], i);
4331 if i > 0 then
4332 begin
4333 DrawPressRect := True;
4334 Exit;
4335 end;
4336 vleObjectProperty.FindRow(_lc[I_PROP_TR_DOOR_PANEL], i);
4337 if i <= 0 then
4338 vleObjectProperty.FindRow(_lc[I_PROP_TR_TRAP_PANEL], i);
4339 if i > 0 then
4340 begin
4341 SelectFlag := SELECTFLAG_DOOR;
4342 Exit;
4343 end;
4344 vleObjectProperty.FindRow(_lc[I_PROP_TR_LIFT_PANEL], i);
4345 if i > 0 then
4346 begin
4347 SelectFlag := SELECTFLAG_LIFT;
4348 Exit;
4349 end;
4350 vleObjectProperty.FindRow(_lc[I_PROP_TR_TELEPORT_TO], i);
4351 if i > 0 then
4352 begin
4353 SelectFlag := SELECTFLAG_TELEPORT;
4354 Exit;
4355 end;
4356 vleObjectProperty.FindRow(_lc[I_PROP_TR_SPAWN_TO], i);
4357 if i > 0 then
4358 begin
4359 SelectFlag := SELECTFLAG_SPAWNPOINT;
4360 Exit;
4361 end;
4363 // Выбор основного параметра, в зависимости от типа триггера
4364 vleObjectProperty.FindRow(_lc[I_PROP_TR_NEXT_MAP], i);
4365 if i > 0 then
4366 begin
4367 g_ProcessResourceStr(OpenedMap, @FileName, nil, nil);
4368 SelectMapForm.Caption := _lc[I_CAP_SELECT];
4369 SelectMapForm.GetMaps(FileName);
4371 if SelectMapForm.ShowModal() = mrOK then
4372 begin
4373 vleObjectProperty.Cells[1, i] := SelectMapForm.lbMapList.Items[SelectMapForm.lbMapList.ItemIndex];
4374 bApplyProperty.Click();
4375 end;
4376 Exit;
4377 end;
4378 vleObjectProperty.FindRow(_lc[I_PROP_TR_SOUND_NAME], i);
4379 if i <= 0 then
4380 vleObjectProperty.FindRow(_lc[I_PROP_TR_MUSIC_NAME], i);
4381 if i > 0 then
4382 begin
4383 AddSoundForm.OKFunction := nil;
4384 AddSoundForm.lbResourcesList.MultiSelect := False;
4385 AddSoundForm.SetResource := vleObjectProperty.Cells[1, i];
4387 if (AddSoundForm.ShowModal() = mrOk) then
4388 begin
4389 vleObjectProperty.Cells[1, i] := AddSoundForm.ResourceName;
4390 bApplyProperty.Click();
4391 end;
4392 Exit;
4393 end;
4394 vleObjectProperty.FindRow(_lc[I_PROP_TR_PUSH_ANGLE], i);
4395 if i <= 0 then
4396 vleObjectProperty.FindRow(_lc[I_PROP_TR_MESSAGE_TEXT], i);
4397 if i > 0 then
4398 begin
4399 vleObjectProperty.Row := i;
4400 vleObjectProperty.SetFocus();
4401 Exit;
4402 end;
4403 end;
4404 end;
4405 end;
4407 procedure TMainForm.aOptimizeExecute(Sender: TObject);
4408 begin
4409 RemoveSelectFromObjects();
4410 MapOptimizationForm.ShowModal();
4411 end;
4413 procedure TMainForm.aCheckMapExecute(Sender: TObject);
4414 begin
4415 MapCheckForm.ShowModal();
4416 end;
4418 procedure TMainForm.bbAddTextureClick(Sender: TObject);
4419 begin
4420 AddTextureForm.lbResourcesList.MultiSelect := True;
4421 AddTextureForm.ShowModal();
4422 end;
4424 procedure TMainForm.lbTextureListClick(Sender: TObject);
4425 var
4426 TextureID: DWORD;
4427 TextureWidth, TextureHeight: Word;
4428 begin
4429 TextureID := 0;
4430 TextureWidth := 0;
4431 TextureHeight := 0;
4432 if (lbTextureList.ItemIndex <> -1) and
4433 (not IsSpecialTextureSel()) then
4434 begin
4435 if g_GetTexture(SelectedTexture(), TextureID) then
4436 begin
4437 g_GetTextureSizeByID(TextureID, TextureWidth, TextureHeight);
4439 lTextureWidth.Caption := IntToStr(TextureWidth);
4440 lTextureHeight.Caption := IntToStr(TextureHeight);
4441 end else
4442 begin
4443 lTextureWidth.Caption := _lc[I_NOT_ACCESSIBLE];
4444 lTextureHeight.Caption := _lc[I_NOT_ACCESSIBLE];
4445 end;
4446 end
4447 else
4448 begin
4449 lTextureWidth.Caption := '';
4450 lTextureHeight.Caption := '';
4451 end;
4452 end;
4454 procedure TMainForm.lbTextureListDrawItem(Control: TWinControl; Index: Integer;
4455 ARect: TRect; State: TOwnerDrawState);
4456 begin
4457 with Control as TListBox do
4458 begin
4459 if LCLType.odSelected in State then
4460 begin
4461 Canvas.Brush.Color := clHighlight;
4462 Canvas.Font.Color := clHighlightText;
4463 end else
4464 if (Items <> nil) and (Index >= 0) then
4465 if slInvalidTextures.IndexOf(Items[Index]) > -1 then
4466 begin
4467 Canvas.Brush.Color := clRed;
4468 Canvas.Font.Color := clWhite;
4469 end;
4470 Canvas.FillRect(ARect);
4471 Canvas.TextRect(ARect, ARect.Left, ARect.Top, Items[Index]);
4472 end;
4473 end;
4475 procedure TMainForm.vleObjectPropertyGetPickList(Sender: TObject;
4476 const KeyName: String; Values: TStrings);
4477 begin
4478 if vleObjectProperty.ItemProps[KeyName].EditStyle = esPickList then
4479 begin
4480 if KeyName = _lc[I_PROP_DIRECTION] then
4481 begin
4482 Values.Add(DirNames[D_LEFT]);
4483 Values.Add(DirNames[D_RIGHT]);
4484 end
4485 else if KeyName = _lc[I_PROP_TR_TELEPORT_DIR] then
4486 begin
4487 Values.Add(DirNamesAdv[0]);
4488 Values.Add(DirNamesAdv[1]);
4489 Values.Add(DirNamesAdv[2]);
4490 Values.Add(DirNamesAdv[3]);
4491 end
4492 else if KeyName = _lc[I_PROP_TR_MUSIC_ACT] then
4493 begin
4494 Values.Add(_lc[I_PROP_TR_MUSIC_ON]);
4495 Values.Add(_lc[I_PROP_TR_MUSIC_OFF]);
4496 end
4497 else if KeyName = _lc[I_PROP_TR_MONSTER_BEHAVIOUR] then
4498 begin
4499 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_0]);
4500 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_1]);
4501 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_2]);
4502 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_3]);
4503 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_4]);
4504 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_5]);
4505 end
4506 else if KeyName = _lc[I_PROP_TR_SCORE_ACT] then
4507 begin
4508 Values.Add(_lc[I_PROP_TR_SCORE_ACT_0]);
4509 Values.Add(_lc[I_PROP_TR_SCORE_ACT_1]);
4510 Values.Add(_lc[I_PROP_TR_SCORE_ACT_2]);
4511 Values.Add(_lc[I_PROP_TR_SCORE_ACT_3]);
4512 end
4513 else if KeyName = _lc[I_PROP_TR_SCORE_TEAM] then
4514 begin
4515 Values.Add(_lc[I_PROP_TR_SCORE_TEAM_0]);
4516 Values.Add(_lc[I_PROP_TR_SCORE_TEAM_1]);
4517 Values.Add(_lc[I_PROP_TR_SCORE_TEAM_2]);
4518 Values.Add(_lc[I_PROP_TR_SCORE_TEAM_3]);
4519 end
4520 else if KeyName = _lc[I_PROP_TR_MESSAGE_KIND] then
4521 begin
4522 Values.Add(_lc[I_PROP_TR_MESSAGE_KIND_0]);
4523 Values.Add(_lc[I_PROP_TR_MESSAGE_KIND_1]);
4524 end
4525 else if KeyName = _lc[I_PROP_TR_MESSAGE_TO] then
4526 begin
4527 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_0]);
4528 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_1]);
4529 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_2]);
4530 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_3]);
4531 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_4]);
4532 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_5]);
4533 end
4534 else if KeyName = _lc[I_PROP_TR_SHOT_TO] then
4535 begin
4536 Values.Add(_lc[I_PROP_TR_SHOT_TO_0]);
4537 Values.Add(_lc[I_PROP_TR_SHOT_TO_1]);
4538 Values.Add(_lc[I_PROP_TR_SHOT_TO_2]);
4539 Values.Add(_lc[I_PROP_TR_SHOT_TO_3]);
4540 Values.Add(_lc[I_PROP_TR_SHOT_TO_4]);
4541 Values.Add(_lc[I_PROP_TR_SHOT_TO_5]);
4542 Values.Add(_lc[I_PROP_TR_SHOT_TO_6]);
4543 end
4544 else if KeyName = _lc[I_PROP_TR_SHOT_AIM] then
4545 begin
4546 Values.Add(_lc[I_PROP_TR_SHOT_AIM_0]);
4547 Values.Add(_lc[I_PROP_TR_SHOT_AIM_1]);
4548 Values.Add(_lc[I_PROP_TR_SHOT_AIM_2]);
4549 Values.Add(_lc[I_PROP_TR_SHOT_AIM_3]);
4550 end
4551 else if (KeyName = _lc[I_PROP_PANEL_BLEND]) or
4552 (KeyName = _lc[I_PROP_DM_ONLY]) or
4553 (KeyName = _lc[I_PROP_ITEM_FALLS]) or
4554 (KeyName = _lc[I_PROP_TR_ENABLED]) or
4555 (KeyName = _lc[I_PROP_TR_D2D]) or
4556 (KeyName = _lc[I_PROP_TR_SILENT]) or
4557 (KeyName = _lc[I_PROP_TR_TELEPORT_SILENT]) or
4558 (KeyName = _lc[I_PROP_TR_EX_RANDOM]) or
4559 (KeyName = _lc[I_PROP_TR_TEXTURE_ONCE]) or
4560 (KeyName = _lc[I_PROP_TR_TEXTURE_ANIM_ONCE]) or
4561 (KeyName = _lc[I_PROP_TR_SOUND_LOCAL]) or
4562 (KeyName = _lc[I_PROP_TR_SOUND_SWITCH]) or
4563 (KeyName = _lc[I_PROP_TR_MONSTER_ACTIVE]) or
4564 (KeyName = _lc[I_PROP_TR_PUSH_RESET]) or
4565 (KeyName = _lc[I_PROP_TR_SCORE_CON]) or
4566 (KeyName = _lc[I_PROP_TR_SCORE_MSG]) or
4567 (KeyName = _lc[I_PROP_TR_HEALTH_MAX]) or
4568 (KeyName = _lc[I_PROP_TR_SHOT_SOUND]) or
4569 (KeyName = _lc[I_PROP_TR_EFFECT_CENTER]) then
4570 begin
4571 Values.Add(BoolNames[True]);
4572 Values.Add(BoolNames[False]);
4573 end;
4574 end;
4575 end;
4577 procedure TMainForm.bApplyPropertyClick(Sender: TObject);
4578 var
4579 _id, a, r, c: Integer;
4580 s: String;
4581 res: Boolean;
4582 NoTextureID: DWORD;
4583 NW, NH: Word;
4584 begin
4585 NoTextureID := 0;
4586 NW := 0;
4587 NH := 0;
4589 if SelectedObjectCount() <> 1 then
4590 Exit;
4591 if not SelectedObjects[GetFirstSelected()].Live then
4592 Exit;
4594 try
4595 if not CheckProperty() then
4596 Exit;
4597 except
4598 Exit;
4599 end;
4601 _id := GetFirstSelected();
4603 r := vleObjectProperty.Row;
4604 c := vleObjectProperty.Col;
4606 case SelectedObjects[_id].ObjectType of
4607 OBJECT_PANEL:
4608 begin
4609 with gPanels[SelectedObjects[_id].ID] do
4610 begin
4611 X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
4612 Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
4613 Width := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_WIDTH]]));
4614 Height := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_HEIGHT]]));
4616 PanelType := GetPanelType(vleObjectProperty.Values[_lc[I_PROP_PANEL_TYPE]]);
4618 // Сброс ссылки на триггеры смены текстуры:
4619 if not WordBool(PanelType and (PANEL_WALL or PANEL_FORE or PANEL_BACK)) then
4620 if gTriggers <> nil then
4621 for a := 0 to High(gTriggers) do
4622 begin
4623 if (gTriggers[a].TriggerType <> 0) and
4624 (gTriggers[a].TexturePanel = Integer(SelectedObjects[_id].ID)) then
4625 gTriggers[a].TexturePanel := -1;
4626 if (gTriggers[a].TriggerType = TRIGGER_SHOT) and
4627 (gTriggers[a].Data.ShotPanelID = Integer(SelectedObjects[_id].ID)) then
4628 gTriggers[a].Data.ShotPanelID := -1;
4629 end;
4631 // Сброс ссылки на триггеры лифта:
4632 if not WordBool(PanelType and (PANEL_LIFTUP or PANEL_LIFTDOWN or PANEL_LIFTLEFT or PANEL_LIFTRIGHT)) then
4633 if gTriggers <> nil then
4634 for a := 0 to High(gTriggers) do
4635 if (gTriggers[a].TriggerType in [TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT]) and
4636 (gTriggers[a].Data.PanelID = Integer(SelectedObjects[_id].ID)) then
4637 gTriggers[a].Data.PanelID := -1;
4639 // Сброс ссылки на триггеры двери:
4640 if not WordBool(PanelType and (PANEL_OPENDOOR or PANEL_CLOSEDOOR)) then
4641 if gTriggers <> nil then
4642 for a := 0 to High(gTriggers) do
4643 if (gTriggers[a].TriggerType in [TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
4644 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP]) and
4645 (gTriggers[a].Data.PanelID = Integer(SelectedObjects[_id].ID)) then
4646 gTriggers[a].Data.PanelID := -1;
4648 if IsTexturedPanel(PanelType) then
4649 begin // Может быть текстура
4650 if TextureName <> '' then
4651 begin // Была текстура
4652 Alpha := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_PANEL_ALPHA]]));
4653 Blending := NameToBool(vleObjectProperty.Values[_lc[I_PROP_PANEL_BLEND]]);
4654 end
4655 else // Не было
4656 begin
4657 Alpha := 0;
4658 Blending := False;
4659 end;
4661 // Новая текстура:
4662 TextureName := vleObjectProperty.Values[_lc[I_PROP_PANEL_TEX]];
4664 if TextureName <> '' then
4665 begin // Есть текстура
4666 // Обычная текстура:
4667 if not IsSpecialTexture(TextureName) then
4668 begin
4669 g_GetTextureSizeByName(TextureName,
4670 TextureWidth, TextureHeight);
4672 // Проверка кратности размеров панели:
4673 res := True;
4674 if TextureWidth <> 0 then
4675 if gPanels[SelectedObjects[_id].ID].Width mod TextureWidth <> 0 then
4676 begin
4677 ErrorMessageBox(Format(_lc[I_MSG_WRONG_TEXWIDTH],
4678 [TextureWidth]));
4679 Res := False;
4680 end;
4681 if Res and (TextureHeight <> 0) then
4682 if gPanels[SelectedObjects[_id].ID].Height mod TextureHeight <> 0 then
4683 begin
4684 ErrorMessageBox(Format(_lc[I_MSG_WRONG_TEXHEIGHT],
4685 [TextureHeight]));
4686 Res := False;
4687 end;
4689 if Res then
4690 begin
4691 if not g_GetTexture(TextureName, TextureID) then
4692 // Не удалось загрузить текстуру, рисуем NOTEXTURE
4693 if g_GetTexture('NOTEXTURE', NoTextureID) then
4694 begin
4695 TextureID := TEXTURE_SPECIAL_NOTEXTURE;
4696 g_GetTextureSizeByID(NoTextureID, NW, NH);
4697 TextureWidth := NW;
4698 TextureHeight := NH;
4699 end else
4700 begin
4701 TextureID := TEXTURE_SPECIAL_NONE;
4702 TextureWidth := 1;
4703 TextureHeight := 1;
4704 end;
4705 end
4706 else
4707 begin
4708 TextureName := '';
4709 TextureWidth := 1;
4710 TextureHeight := 1;
4711 TextureID := TEXTURE_SPECIAL_NONE;
4712 end;
4713 end
4714 else // Спец.текстура
4715 begin
4716 TextureHeight := 1;
4717 TextureWidth := 1;
4718 TextureID := SpecialTextureID(TextureName);
4719 end;
4720 end
4721 else // Нет текстуры
4722 begin
4723 TextureWidth := 1;
4724 TextureHeight := 1;
4725 TextureID := TEXTURE_SPECIAL_NONE;
4726 end;
4727 end
4728 else // Не может быть текстуры
4729 begin
4730 Alpha := 0;
4731 Blending := False;
4732 TextureName := '';
4733 TextureWidth := 1;
4734 TextureHeight := 1;
4735 TextureID := TEXTURE_SPECIAL_NONE;
4736 end;
4737 end;
4738 end;
4740 OBJECT_ITEM:
4741 begin
4742 with gItems[SelectedObjects[_id].ID] do
4743 begin
4744 X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
4745 Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
4746 OnlyDM := NameToBool(vleObjectProperty.Values[_lc[I_PROP_DM_ONLY]]);
4747 Fall := NameToBool(vleObjectProperty.Values[_lc[I_PROP_ITEM_FALLS]]);
4748 end;
4749 end;
4751 OBJECT_MONSTER:
4752 begin
4753 with gMonsters[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 Direction := NameToDir(vleObjectProperty.Values[_lc[I_PROP_DIRECTION]]);
4758 end;
4759 end;
4761 OBJECT_AREA:
4762 begin
4763 with gAreas[SelectedObjects[_id].ID] do
4764 begin
4765 X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
4766 Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
4767 Direction := NameToDir(vleObjectProperty.Values[_lc[I_PROP_DIRECTION]]);
4768 end;
4769 end;
4771 OBJECT_TRIGGER:
4772 begin
4773 with gTriggers[SelectedObjects[_id].ID] do
4774 begin
4775 X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
4776 Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
4777 Width := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_WIDTH]]));
4778 Height := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_HEIGHT]]));
4779 Enabled := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_ENABLED]]);
4780 ActivateType := StrToActivate(vleObjectProperty.Values[_lc[I_PROP_TR_ACTIVATION]]);
4781 Key := StrToKey(vleObjectProperty.Values[_lc[I_PROP_TR_KEYS]]);
4783 case TriggerType of
4784 TRIGGER_EXIT:
4785 begin
4786 s := utf2win(vleObjectProperty.Values[_lc[I_PROP_TR_NEXT_MAP]]);
4787 FillByte(Data.MapName[0], 16, 0);
4788 if s <> '' then
4789 Move(s[1], Data.MapName[0], Min(Length(s), 16));
4790 end;
4792 TRIGGER_TEXTURE:
4793 begin
4794 Data.ActivateOnce := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_TEXTURE_ONCE]]);
4795 Data.AnimOnce := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_TEXTURE_ANIM_ONCE]]);
4796 end;
4798 TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF:
4799 begin
4800 Data.Wait := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EX_DELAY]], 0), 65535);
4801 Data.Count := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EX_COUNT]], 0), 65535);
4802 if Data.Count < 1 then
4803 Data.Count := 1;
4804 if TriggerType = TRIGGER_PRESS then
4805 Data.ExtRandom := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_EX_RANDOM]]);
4806 end;
4808 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR, TRIGGER_DOOR5,
4809 TRIGGER_CLOSETRAP, TRIGGER_TRAP, TRIGGER_LIFTUP, TRIGGER_LIFTDOWN,
4810 TRIGGER_LIFT:
4811 begin
4812 Data.NoSound := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SILENT]]);
4813 Data.d2d_doors := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_D2D]]);
4814 end;
4816 TRIGGER_TELEPORT:
4817 begin
4818 Data.d2d_teleport := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_D2D]]);
4819 Data.silent_teleport := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_TELEPORT_SILENT]]);
4820 Data.TlpDir := NameToDirAdv(vleObjectProperty.Values[_lc[I_PROP_TR_TELEPORT_DIR]]);
4821 end;
4823 TRIGGER_SOUND:
4824 begin
4825 s := utf2win(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_NAME]]);
4826 FillByte(Data.SoundName[0], 64, 0);
4827 if s <> '' then
4828 Move(s[1], Data.SoundName[0], Min(Length(s), 64));
4830 Data.Volume := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_VOLUME]], 0), 255);
4831 Data.Pan := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_PAN]], 0), 255);
4832 Data.PlayCount := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_COUNT]], 0), 255);
4833 Data.Local := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_LOCAL]]);
4834 Data.SoundSwitch := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_SWITCH]]);
4835 end;
4837 TRIGGER_SPAWNMONSTER:
4838 begin
4839 Data.MonType := StrToMonster(vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_TYPE]]);
4840 Data.MonDir := Byte(NameToDir(vleObjectProperty.Values[_lc[I_PROP_DIRECTION]]));
4841 Data.MonHealth := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_HEALTH]], 0), 1000000);
4842 if Data.MonHealth < 0 then
4843 Data.MonHealth := 0;
4844 Data.MonActive := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_ACTIVE]]);
4845 Data.MonCount := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_COUNT]], 0), 64);
4846 if Data.MonCount < 1 then
4847 Data.MonCount := 1;
4848 Data.MonEffect := StrToEffect(vleObjectProperty.Values[_lc[I_PROP_TR_FX_TYPE]]);
4849 Data.MonMax := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SPAWN_MAX]], 0), 65535);
4850 Data.MonDelay := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SPAWN_DELAY]], 0), 65535);
4851 Data.MonBehav := 0;
4852 if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_1] then
4853 Data.MonBehav := 1;
4854 if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_2] then
4855 Data.MonBehav := 2;
4856 if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_3] then
4857 Data.MonBehav := 3;
4858 if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_4] then
4859 Data.MonBehav := 4;
4860 if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_5] then
4861 Data.MonBehav := 5;
4862 end;
4864 TRIGGER_SPAWNITEM:
4865 begin
4866 Data.ItemType := StrToItem(vleObjectProperty.Values[_lc[I_PROP_TR_ITEM_TYPE]]);
4867 Data.ItemOnlyDM := NameToBool(vleObjectProperty.Values[_lc[I_PROP_DM_ONLY]]);
4868 Data.ItemFalls := NameToBool(vleObjectProperty.Values[_lc[I_PROP_ITEM_FALLS]]);
4869 Data.ItemCount := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_COUNT]], 0), 64);
4870 if Data.ItemCount < 1 then
4871 Data.ItemCount := 1;
4872 Data.ItemEffect := StrToEffect(vleObjectProperty.Values[_lc[I_PROP_TR_FX_TYPE]]);
4873 Data.ItemMax := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SPAWN_MAX]], 0), 65535);
4874 Data.ItemDelay := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SPAWN_DELAY]], 0), 65535);
4875 end;
4877 TRIGGER_MUSIC:
4878 begin
4879 s := utf2win(vleObjectProperty.Values[_lc[I_PROP_TR_MUSIC_NAME]]);
4880 FillByte(Data.MusicName[0], 64, 0);
4881 if s <> '' then
4882 Move(s[1], Data.MusicName[0], Min(Length(s), 64));
4884 if vleObjectProperty.Values[_lc[I_PROP_TR_MUSIC_ACT]] = _lc[I_PROP_TR_MUSIC_ON] then
4885 Data.MusicAction := 1
4886 else
4887 Data.MusicAction := 2;
4888 end;
4890 TRIGGER_PUSH:
4891 begin
4892 Data.PushAngle := Min(
4893 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_PUSH_ANGLE]], 0), 360);
4894 Data.PushForce := Min(
4895 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_PUSH_FORCE]], 0), 255);
4896 Data.ResetVel := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_PUSH_RESET]]);
4897 end;
4899 TRIGGER_SCORE:
4900 begin
4901 Data.ScoreAction := 0;
4902 if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_ACT]] = _lc[I_PROP_TR_SCORE_ACT_1] then
4903 Data.ScoreAction := 1
4904 else if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_ACT]] = _lc[I_PROP_TR_SCORE_ACT_2] then
4905 Data.ScoreAction := 2
4906 else if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_ACT]] = _lc[I_PROP_TR_SCORE_ACT_3] then
4907 Data.ScoreAction := 3;
4908 Data.ScoreCount := Min(Max(
4909 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_COUNT]], 0), 0), 255);
4910 Data.ScoreTeam := 0;
4911 if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_TEAM]] = _lc[I_PROP_TR_SCORE_TEAM_1] then
4912 Data.ScoreTeam := 1
4913 else if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_TEAM]] = _lc[I_PROP_TR_SCORE_TEAM_2] then
4914 Data.ScoreTeam := 2
4915 else if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_TEAM]] = _lc[I_PROP_TR_SCORE_TEAM_3] then
4916 Data.ScoreTeam := 3;
4917 Data.ScoreCon := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_CON]]);
4918 Data.ScoreMsg := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_MSG]]);
4919 end;
4921 TRIGGER_MESSAGE:
4922 begin
4923 Data.MessageKind := 0;
4924 if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_KIND]] = _lc[I_PROP_TR_MESSAGE_KIND_1] then
4925 Data.MessageKind := 1;
4927 Data.MessageSendTo := 0;
4928 if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_1] then
4929 Data.MessageSendTo := 1
4930 else if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_2] then
4931 Data.MessageSendTo := 2
4932 else if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_3] then
4933 Data.MessageSendTo := 3
4934 else if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_4] then
4935 Data.MessageSendTo := 4
4936 else if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_5] then
4937 Data.MessageSendTo := 5;
4939 s := utf2win(vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TEXT]]);
4940 FillByte(Data.MessageText[0], 100, 0);
4941 if s <> '' then
4942 Move(s[1], Data.MessageText[0], Min(Length(s), 100));
4944 Data.MessageTime := Min(Max(
4945 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TIME]], 0), 0), 65535);
4946 end;
4948 TRIGGER_DAMAGE:
4949 begin
4950 Data.DamageValue := Min(Max(
4951 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_DAMAGE_VALUE]], 0), 0), 65535);
4952 Data.DamageInterval := Min(Max(
4953 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_INTERVAL]], 0), 0), 65535);
4954 end;
4956 TRIGGER_HEALTH:
4957 begin
4958 Data.HealValue := Min(Max(
4959 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_HEALTH]], 0), 0), 65535);
4960 Data.HealInterval := Min(Max(
4961 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_INTERVAL]], 0), 0), 65535);
4962 Data.HealMax := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_HEALTH_MAX]]);
4963 Data.HealSilent := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SILENT]]);
4964 end;
4966 TRIGGER_SHOT:
4967 begin
4968 Data.ShotType := StrToShot(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TYPE]]);
4969 Data.ShotSound := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_SOUND]]);
4970 Data.ShotTarget := 0;
4971 if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_1] then
4972 Data.ShotTarget := 1
4973 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_2] then
4974 Data.ShotTarget := 2
4975 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_3] then
4976 Data.ShotTarget := 3
4977 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_4] then
4978 Data.ShotTarget := 4
4979 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_5] then
4980 Data.ShotTarget := 5
4981 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_6] then
4982 Data.ShotTarget := 6;
4983 Data.ShotIntSight := Min(Max(
4984 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_SIGHT]], 0), 0), 65535);
4985 Data.ShotAim := 0;
4986 if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_AIM]] = _lc[I_PROP_TR_SHOT_AIM_1] then
4987 Data.ShotAim := 1
4988 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_AIM]] = _lc[I_PROP_TR_SHOT_AIM_2] then
4989 Data.ShotAim := 2
4990 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_AIM]] = _lc[I_PROP_TR_SHOT_AIM_3] then
4991 Data.ShotAim := 3;
4992 Data.ShotAngle := Min(
4993 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_ANGLE]], 0), 360);
4994 Data.ShotWait := Min(Max(
4995 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EX_DELAY]], 0), 0), 65535);
4996 Data.ShotAccuracy := Min(Max(
4997 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_ACC]], 0), 0), 65535);
4998 Data.ShotAmmo := Min(Max(
4999 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_AMMO]], 0), 0), 65535);
5000 Data.ShotIntReload := Min(Max(
5001 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_RELOAD]], 0), 0), 65535);
5002 end;
5004 TRIGGER_EFFECT:
5005 begin
5006 Data.FXCount := Min(Max(
5007 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_COUNT]], 0), 0), 255);
5008 if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_TYPE]] = _lc[I_PROP_TR_EFFECT_PARTICLE] then
5009 begin
5010 Data.FXType := TRIGGER_EFFECT_PARTICLE;
5011 Data.FXSubType := TRIGGER_EFFECT_SLIQUID;
5012 if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_SLIQUID] then
5013 Data.FXSubType := TRIGGER_EFFECT_SLIQUID
5014 else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_LLIQUID] then
5015 Data.FXSubType := TRIGGER_EFFECT_LLIQUID
5016 else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_DLIQUID] then
5017 Data.FXSubType := TRIGGER_EFFECT_DLIQUID
5018 else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_BLOOD] then
5019 Data.FXSubType := TRIGGER_EFFECT_BLOOD
5020 else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_SPARK] then
5021 Data.FXSubType := TRIGGER_EFFECT_SPARK
5022 else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_BUBBLE] then
5023 Data.FXSubType := TRIGGER_EFFECT_BUBBLE;
5024 end else
5025 begin
5026 Data.FXType := TRIGGER_EFFECT_ANIMATION;
5027 Data.FXSubType := StrToEffect(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]]);
5028 end;
5029 a := Min(Max(
5030 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_COLOR]], 0), 0), $FFFFFF);
5031 Data.FXColorR := a and $FF;
5032 Data.FXColorG := (a shr 8) and $FF;
5033 Data.FXColorB := (a shr 16) and $FF;
5034 if NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_CENTER]]) then
5035 Data.FXPos := 0
5036 else
5037 Data.FXPos := 1;
5038 Data.FXWait := Min(Max(
5039 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EX_DELAY]], 0), 0), 65535);
5040 Data.FXVelX := Min(Max(
5041 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_VELX]], 0), -128), 127);
5042 Data.FXVelY := Min(Max(
5043 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_VELY]], 0), -128), 127);
5044 Data.FXSpreadL := Min(Max(
5045 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SPL]], 0), 0), 255);
5046 Data.FXSpreadR := Min(Max(
5047 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SPR]], 0), 0), 255);
5048 Data.FXSpreadU := Min(Max(
5049 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SPU]], 0), 0), 255);
5050 Data.FXSpreadD := Min(Max(
5051 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SPD]], 0), 0), 255);
5052 end;
5053 end;
5054 end;
5055 end;
5056 end;
5058 FillProperty();
5060 vleObjectProperty.Row := r;
5061 vleObjectProperty.Col := c;
5062 end;
5064 procedure TMainForm.bbRemoveTextureClick(Sender: TObject);
5065 var
5066 a, i: Integer;
5067 begin
5068 i := lbTextureList.ItemIndex;
5069 if i = -1 then
5070 Exit;
5072 if MessageBox(0, PChar(Format(_lc[I_MSG_DEL_TEXTURE_PROMT],
5073 [SelectedTexture()])),
5074 PChar(_lc[I_MSG_DEL_TEXTURE]),
5075 MB_ICONQUESTION or MB_YESNO or
5076 MB_DEFBUTTON1) <> idYes then
5077 Exit;
5079 if gPanels <> nil then
5080 for a := 0 to High(gPanels) do
5081 if (gPanels[a].PanelType <> 0) and
5082 (gPanels[a].TextureName = SelectedTexture()) then
5083 begin
5084 ErrorMessageBox(_lc[I_MSG_DEL_TEXTURE_CANT]);
5085 Exit;
5086 end;
5088 g_DeleteTexture(SelectedTexture());
5089 i := slInvalidTextures.IndexOf(lbTextureList.Items[i]);
5090 if i > -1 then
5091 slInvalidTextures.Delete(i);
5092 if lbTextureList.ItemIndex > -1 then
5093 lbTextureList.Items.Delete(lbTextureList.ItemIndex)
5094 end;
5096 procedure TMainForm.aNewMapExecute(Sender: TObject);
5097 begin
5098 if (MessageBox(0, PChar(_lc[I_MSG_CLEAR_MAP_PROMT]),
5099 PChar(_lc[I_MSG_CLEAR_MAP]),
5100 MB_ICONQUESTION or MB_YESNO or
5101 MB_DEFBUTTON1) = mrYes) then
5102 FullClear();
5103 end;
5105 procedure TMainForm.aUndoExecute(Sender: TObject);
5106 var
5107 a: Integer;
5108 begin
5109 if UndoBuffer = nil then
5110 Exit;
5111 if UndoBuffer[High(UndoBuffer)] = nil then
5112 Exit;
5114 for a := 0 to High(UndoBuffer[High(UndoBuffer)]) do
5115 with UndoBuffer[High(UndoBuffer)][a] do
5116 begin
5117 case UndoType of
5118 UNDO_DELETE_PANEL:
5119 begin
5120 AddPanel(Panel^);
5121 Panel := nil;
5122 end;
5123 UNDO_DELETE_ITEM: AddItem(Item);
5124 UNDO_DELETE_AREA: AddArea(Area);
5125 UNDO_DELETE_MONSTER: AddMonster(Monster);
5126 UNDO_DELETE_TRIGGER: AddTrigger(Trigger);
5127 UNDO_ADD_PANEL: RemoveObject(AddID, OBJECT_PANEL);
5128 UNDO_ADD_ITEM: RemoveObject(AddID, OBJECT_ITEM);
5129 UNDO_ADD_AREA: RemoveObject(AddID, OBJECT_AREA);
5130 UNDO_ADD_MONSTER: RemoveObject(AddID, OBJECT_MONSTER);
5131 UNDO_ADD_TRIGGER: RemoveObject(AddID, OBJECT_TRIGGER);
5132 end;
5133 end;
5135 SetLength(UndoBuffer, Length(UndoBuffer)-1);
5137 RemoveSelectFromObjects();
5139 miUndo.Enabled := UndoBuffer <> nil;
5140 end;
5143 procedure TMainForm.aCopyObjectExecute(Sender: TObject);
5144 var
5145 a, b: Integer;
5146 CopyBuffer: TCopyRecArray;
5147 str: String;
5148 ok: Boolean;
5150 function CB_Compare(I1, I2: TCopyRec): Integer;
5151 begin
5152 Result := Integer(I1.ObjectType) - Integer(I2.ObjectType);
5154 if Result = 0 then // Одного типа
5155 Result := Integer(I1.ID) - Integer(I2.ID);
5156 end;
5158 procedure QuickSortCopyBuffer(L, R: Integer);
5159 var
5160 I, J: Integer;
5161 P, T: TCopyRec;
5162 begin
5163 repeat
5164 I := L;
5165 J := R;
5166 P := CopyBuffer[(L + R) shr 1];
5168 repeat
5169 while CB_Compare(CopyBuffer[I], P) < 0 do
5170 Inc(I);
5171 while CB_Compare(CopyBuffer[J], P) > 0 do
5172 Dec(J);
5174 if I <= J then
5175 begin
5176 T := CopyBuffer[I];
5177 CopyBuffer[I] := CopyBuffer[J];
5178 CopyBuffer[J] := T;
5179 Inc(I);
5180 Dec(J);
5181 end;
5182 until I > J;
5184 if L < J then
5185 QuickSortCopyBuffer(L, J);
5187 L := I;
5188 until I >= R;
5189 end;
5191 begin
5192 if SelectedObjects = nil then
5193 Exit;
5195 b := -1;
5196 CopyBuffer := nil;
5198 // Копируем объекты:
5199 for a := 0 to High(SelectedObjects) do
5200 if SelectedObjects[a].Live then
5201 with SelectedObjects[a] do
5202 begin
5203 SetLength(CopyBuffer, Length(CopyBuffer)+1);
5204 b := High(CopyBuffer);
5205 CopyBuffer[b].ID := ID;
5206 CopyBuffer[b].Panel := nil;
5208 case ObjectType of
5209 OBJECT_PANEL:
5210 begin
5211 CopyBuffer[b].ObjectType := OBJECT_PANEL;
5212 New(CopyBuffer[b].Panel);
5213 CopyBuffer[b].Panel^ := gPanels[ID];
5214 end;
5216 OBJECT_ITEM:
5217 begin
5218 CopyBuffer[b].ObjectType := OBJECT_ITEM;
5219 CopyBuffer[b].Item := gItems[ID];
5220 end;
5222 OBJECT_MONSTER:
5223 begin
5224 CopyBuffer[b].ObjectType := OBJECT_MONSTER;
5225 CopyBuffer[b].Monster := gMonsters[ID];
5226 end;
5228 OBJECT_AREA:
5229 begin
5230 CopyBuffer[b].ObjectType := OBJECT_AREA;
5231 CopyBuffer[b].Area := gAreas[ID];
5232 end;
5234 OBJECT_TRIGGER:
5235 begin
5236 CopyBuffer[b].ObjectType := OBJECT_TRIGGER;
5237 CopyBuffer[b].Trigger := gTriggers[ID];
5238 end;
5239 end;
5240 end;
5242 // Сортировка по ID:
5243 if CopyBuffer <> nil then
5244 begin
5245 QuickSortCopyBuffer(0, b);
5246 end;
5248 // Пестановка ссылок триггеров:
5249 for a := 0 to Length(CopyBuffer)-1 do
5250 if CopyBuffer[a].ObjectType = OBJECT_TRIGGER then
5251 begin
5252 case CopyBuffer[a].Trigger.TriggerType of
5253 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
5254 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP,
5255 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
5256 if CopyBuffer[a].Trigger.Data.PanelID <> -1 then
5257 begin
5258 ok := False;
5260 for b := 0 to Length(CopyBuffer)-1 do
5261 if (CopyBuffer[b].ObjectType = OBJECT_PANEL) and
5262 (Integer(CopyBuffer[b].ID) = CopyBuffer[a].Trigger.Data.PanelID) then
5263 begin
5264 CopyBuffer[a].Trigger.Data.PanelID := b;
5265 ok := True;
5266 Break;
5267 end;
5269 // Этих панелей нет среди копируемых:
5270 if not ok then
5271 CopyBuffer[a].Trigger.Data.PanelID := -1;
5272 end;
5274 TRIGGER_PRESS, TRIGGER_ON,
5275 TRIGGER_OFF, TRIGGER_ONOFF:
5276 if CopyBuffer[a].Trigger.Data.MonsterID <> 0 then
5277 begin
5278 ok := False;
5280 for b := 0 to Length(CopyBuffer)-1 do
5281 if (CopyBuffer[b].ObjectType = OBJECT_MONSTER) and
5282 (Integer(CopyBuffer[b].ID) = CopyBuffer[a].Trigger.Data.MonsterID-1) then
5283 begin
5284 CopyBuffer[a].Trigger.Data.MonsterID := b+1;
5285 ok := True;
5286 Break;
5287 end;
5289 // Этих монстров нет среди копируемых:
5290 if not ok then
5291 CopyBuffer[a].Trigger.Data.MonsterID := 0;
5292 end;
5294 TRIGGER_SHOT:
5295 if CopyBuffer[a].Trigger.Data.ShotPanelID <> -1 then
5296 begin
5297 ok := False;
5299 for b := 0 to Length(CopyBuffer)-1 do
5300 if (CopyBuffer[b].ObjectType = OBJECT_PANEL) and
5301 (Integer(CopyBuffer[b].ID) = CopyBuffer[a].Trigger.Data.ShotPanelID) then
5302 begin
5303 CopyBuffer[a].Trigger.Data.ShotPanelID := b;
5304 ok := True;
5305 Break;
5306 end;
5308 // Этих панелей нет среди копируемых:
5309 if not ok then
5310 CopyBuffer[a].Trigger.Data.ShotPanelID := -1;
5311 end;
5312 end;
5314 if CopyBuffer[a].Trigger.TexturePanel <> -1 then
5315 begin
5316 ok := False;
5318 for b := 0 to Length(CopyBuffer)-1 do
5319 if (CopyBuffer[b].ObjectType = OBJECT_PANEL) and
5320 (Integer(CopyBuffer[b].ID) = CopyBuffer[a].Trigger.TexturePanel) then
5321 begin
5322 CopyBuffer[a].Trigger.TexturePanel := b;
5323 ok := True;
5324 Break;
5325 end;
5327 // Этих панелей нет среди копируемых:
5328 if not ok then
5329 CopyBuffer[a].Trigger.TexturePanel := -1;
5330 end;
5331 end;
5333 // В буфер обмена:
5334 str := CopyBufferToString(CopyBuffer);
5335 ClipBoard.AsText := str;
5337 for a := 0 to Length(CopyBuffer)-1 do
5338 if (CopyBuffer[a].ObjectType = OBJECT_PANEL) and
5339 (CopyBuffer[a].Panel <> nil) then
5340 Dispose(CopyBuffer[a].Panel);
5342 CopyBuffer := nil;
5343 end;
5345 procedure TMainForm.aPasteObjectExecute(Sender: TObject);
5346 var
5347 a, h: Integer;
5348 CopyBuffer: TCopyRecArray;
5349 res: Boolean;
5350 swad, ssec, sres: String;
5351 begin
5352 CopyBuffer := nil;
5354 StringToCopyBuffer(ClipBoard.AsText, CopyBuffer);
5356 if CopyBuffer = nil then
5357 Exit;
5359 RemoveSelectFromObjects();
5361 h := High(CopyBuffer);
5362 for a := 0 to h do
5363 with CopyBuffer[a] do
5364 begin
5365 case ObjectType of
5366 OBJECT_PANEL:
5367 if Panel <> nil then
5368 begin
5369 Panel^.X := Panel^.X + 16;
5370 Panel^.Y := Panel^.Y + 16;
5372 Panel^.TextureID := TEXTURE_SPECIAL_NONE;
5373 Panel^.TextureWidth := 1;
5374 Panel^.TextureHeight := 1;
5376 if (Panel^.PanelType = PANEL_LIFTUP) or
5377 (Panel^.PanelType = PANEL_LIFTDOWN) or
5378 (Panel^.PanelType = PANEL_LIFTLEFT) or
5379 (Panel^.PanelType = PANEL_LIFTRIGHT) or
5380 (Panel^.PanelType = PANEL_BLOCKMON) or
5381 (Panel^.TextureName = '') then
5382 begin // Нет или не может быть текстуры:
5383 end
5384 else // Есть текстура:
5385 begin
5386 // Обычная текстура:
5387 if not IsSpecialTexture(Panel^.TextureName) then
5388 begin
5389 res := g_GetTexture(Panel^.TextureName, Panel^.TextureID);
5391 if not res then
5392 begin
5393 g_ProcessResourceStr(Panel^.TextureName, swad, ssec, sres);
5394 AddTexture(swad, ssec, sres, True);
5395 res := g_GetTexture(Panel^.TextureName, Panel^.TextureID);
5396 end;
5398 if res then
5399 g_GetTextureSizeByName(Panel^.TextureName,
5400 Panel^.TextureWidth, Panel^.TextureHeight)
5401 else
5402 Panel^.TextureName := '';
5403 end
5404 else // Спец.текстура:
5405 begin
5406 Panel^.TextureID := SpecialTextureID(Panel^.TextureName);
5407 with MainForm.lbTextureList.Items do
5408 if IndexOf(Panel^.TextureName) = -1 then
5409 Add(Panel^.TextureName);
5410 end;
5411 end;
5413 ID := AddPanel(Panel^);
5414 Dispose(Panel);
5415 Undo_Add(OBJECT_PANEL, ID, a > 0);
5416 SelectObject(OBJECT_PANEL, ID, True);
5417 end;
5419 OBJECT_ITEM:
5420 begin
5421 Item.X := Item.X + 16;
5422 Item.Y := Item.Y + 16;
5424 ID := AddItem(Item);
5425 Undo_Add(OBJECT_ITEM, ID, a > 0);
5426 SelectObject(OBJECT_ITEM, ID, True);
5427 end;
5429 OBJECT_MONSTER:
5430 begin
5431 Monster.X := Monster.X + 16;
5432 Monster.Y := Monster.Y + 16;
5434 ID := AddMonster(Monster);
5435 Undo_Add(OBJECT_MONSTER, ID, a > 0);
5436 SelectObject(OBJECT_MONSTER, ID, True);
5437 end;
5439 OBJECT_AREA:
5440 begin
5441 Area.X := Area.X + 16;
5442 Area.Y := Area.Y + 16;
5444 ID := AddArea(Area);
5445 Undo_Add(OBJECT_AREA, ID, a > 0);
5446 SelectObject(OBJECT_AREA, ID, True);
5447 end;
5449 OBJECT_TRIGGER:
5450 begin
5451 Trigger.X := Trigger.X + 16;
5452 Trigger.Y := Trigger.Y + 16;
5454 ID := AddTrigger(Trigger);
5455 Undo_Add(OBJECT_TRIGGER, ID, a > 0);
5456 SelectObject(OBJECT_TRIGGER, ID, True);
5457 end;
5458 end;
5459 end;
5461 // Переставляем ссылки триггеров:
5462 for a := 0 to High(CopyBuffer) do
5463 if CopyBuffer[a].ObjectType = OBJECT_TRIGGER then
5464 begin
5465 case CopyBuffer[a].Trigger.TriggerType of
5466 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
5467 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP,
5468 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
5469 if CopyBuffer[a].Trigger.Data.PanelID <> -1 then
5470 gTriggers[CopyBuffer[a].ID].Data.PanelID :=
5471 CopyBuffer[CopyBuffer[a].Trigger.Data.PanelID].ID;
5473 TRIGGER_PRESS, TRIGGER_ON,
5474 TRIGGER_OFF, TRIGGER_ONOFF:
5475 if CopyBuffer[a].Trigger.Data.MonsterID <> 0 then
5476 gTriggers[CopyBuffer[a].ID].Data.MonsterID :=
5477 CopyBuffer[CopyBuffer[a].Trigger.Data.MonsterID-1].ID+1;
5479 TRIGGER_SHOT:
5480 if CopyBuffer[a].Trigger.Data.ShotPanelID <> -1 then
5481 gTriggers[CopyBuffer[a].ID].Data.ShotPanelID :=
5482 CopyBuffer[CopyBuffer[a].Trigger.Data.ShotPanelID].ID;
5483 end;
5485 if CopyBuffer[a].Trigger.TexturePanel <> -1 then
5486 gTriggers[CopyBuffer[a].ID].TexturePanel :=
5487 CopyBuffer[CopyBuffer[a].Trigger.TexturePanel].ID;
5488 end;
5490 CopyBuffer := nil;
5492 if h = 0 then
5493 FillProperty();
5494 end;
5496 procedure TMainForm.aCutObjectExecute(Sender: TObject);
5497 begin
5498 miCopy.Click();
5499 DeleteSelectedObjects();
5500 end;
5502 procedure TMainForm.vleObjectPropertyEditButtonClick(Sender: TObject);
5503 var
5504 Key, FileName: String;
5505 b: Byte;
5506 begin
5507 Key := vleObjectProperty.Keys[vleObjectProperty.Row];
5509 if Key = _lc[I_PROP_PANEL_TYPE] then
5510 begin
5511 with ChooseTypeForm, vleObjectProperty do
5512 begin // Выбор типа панели:
5513 Caption := _lc[I_PROP_PANEL_TYPE];
5514 lbTypeSelect.Items.Clear();
5516 for b := 0 to High(PANELNAMES) do
5517 begin
5518 lbTypeSelect.Items.Add(PANELNAMES[b]);
5519 if Values[Key] = PANELNAMES[b] then
5520 lbTypeSelect.ItemIndex := b;
5521 end;
5523 if ShowModal() = mrOK then
5524 begin
5525 b := lbTypeSelect.ItemIndex;
5526 Values[Key] := PANELNAMES[b];
5527 vleObjectPropertyApply(Sender);
5528 end;
5529 end
5530 end
5531 else if Key = _lc[I_PROP_TR_TELEPORT_TO] then
5532 SelectFlag := SELECTFLAG_TELEPORT
5533 else if Key = _lc[I_PROP_TR_SPAWN_TO] then
5534 SelectFlag := SELECTFLAG_SPAWNPOINT
5535 else if (Key = _lc[I_PROP_TR_DOOR_PANEL]) or
5536 (Key = _lc[I_PROP_TR_TRAP_PANEL]) then
5537 SelectFlag := SELECTFLAG_DOOR
5538 else if Key = _lc[I_PROP_TR_TEXTURE_PANEL] then
5539 begin
5540 DrawPressRect := False;
5541 SelectFlag := SELECTFLAG_TEXTURE;
5542 end
5543 else if Key = _lc[I_PROP_TR_SHOT_PANEL] then
5544 SelectFlag := SELECTFLAG_SHOTPANEL
5545 else if Key = _lc[I_PROP_TR_LIFT_PANEL] then
5546 SelectFlag := SELECTFLAG_LIFT
5547 else if key = _lc[I_PROP_TR_EX_MONSTER] then
5548 SelectFlag := SELECTFLAG_MONSTER
5549 else if Key = _lc[I_PROP_TR_EX_AREA] then
5550 begin
5551 SelectFlag := SELECTFLAG_NONE;
5552 DrawPressRect := True;
5553 end
5554 else if Key = _lc[I_PROP_TR_NEXT_MAP] then
5555 begin // Выбор следующей карты:
5556 g_ProcessResourceStr(OpenedMap, @FileName, nil, nil);
5557 SelectMapForm.Caption := _lc[I_CAP_SELECT];
5558 SelectMapForm.GetMaps(FileName);
5560 if SelectMapForm.ShowModal() = mrOK then
5561 begin
5562 vleObjectProperty.Values[Key] := SelectMapForm.lbMapList.Items[SelectMapForm.lbMapList.ItemIndex];
5563 vleObjectPropertyApply(Sender);
5564 end;
5565 end
5566 else if (Key = _lc[I_PROP_TR_SOUND_NAME]) or
5567 (Key = _lc[I_PROP_TR_MUSIC_NAME]) then
5568 begin // Выбор файла звука/музыки:
5569 AddSoundForm.OKFunction := nil;
5570 AddSoundForm.lbResourcesList.MultiSelect := False;
5571 AddSoundForm.SetResource := vleObjectProperty.Values[Key];
5573 if (AddSoundForm.ShowModal() = mrOk) then
5574 begin
5575 vleObjectProperty.Values[Key] := AddSoundForm.ResourceName;
5576 vleObjectPropertyApply(Sender);
5577 end;
5578 end
5579 else if Key = _lc[I_PROP_TR_ACTIVATION] then
5580 with ActivationTypeForm, vleObjectProperty do
5581 begin // Выбор типов активации:
5582 cbPlayerCollide.Checked := Pos('PC', Values[Key]) > 0;
5583 cbMonsterCollide.Checked := Pos('MC', Values[Key]) > 0;
5584 cbPlayerPress.Checked := Pos('PP', Values[Key]) > 0;
5585 cbMonsterPress.Checked := Pos('MP', Values[Key]) > 0;
5586 cbShot.Checked := Pos('SH', Values[Key]) > 0;
5587 cbNoMonster.Checked := Pos('NM', Values[Key]) > 0;
5589 if ShowModal() = mrOK then
5590 begin
5591 b := 0;
5592 if cbPlayerCollide.Checked then
5593 b := ACTIVATE_PLAYERCOLLIDE;
5594 if cbMonsterCollide.Checked then
5595 b := b or ACTIVATE_MONSTERCOLLIDE;
5596 if cbPlayerPress.Checked then
5597 b := b or ACTIVATE_PLAYERPRESS;
5598 if cbMonsterPress.Checked then
5599 b := b or ACTIVATE_MONSTERPRESS;
5600 if cbShot.Checked then
5601 b := b or ACTIVATE_SHOT;
5602 if cbNoMonster.Checked then
5603 b := b or ACTIVATE_NOMONSTER;
5605 Values[Key] := ActivateToStr(b);
5606 vleObjectPropertyApply(Sender);
5607 end;
5608 end
5609 else if Key = _lc[I_PROP_TR_KEYS] then
5610 with KeysForm, vleObjectProperty do
5611 begin // Выбор необходимых ключей:
5612 cbRedKey.Checked := Pos('RK', Values[Key]) > 0;
5613 cbGreenKey.Checked := Pos('GK', Values[Key]) > 0;
5614 cbBlueKey.Checked := Pos('BK', Values[Key]) > 0;
5615 cbRedTeam.Checked := Pos('RT', Values[Key]) > 0;
5616 cbBlueTeam.Checked := Pos('BT', Values[Key]) > 0;
5618 if ShowModal() = mrOK then
5619 begin
5620 b := 0;
5621 if cbRedKey.Checked then
5622 b := KEY_RED;
5623 if cbGreenKey.Checked then
5624 b := b or KEY_GREEN;
5625 if cbBlueKey.Checked then
5626 b := b or KEY_BLUE;
5627 if cbRedTeam.Checked then
5628 b := b or KEY_REDTEAM;
5629 if cbBlueTeam.Checked then
5630 b := b or KEY_BLUETEAM;
5632 Values[Key] := KeyToStr(b);
5633 vleObjectPropertyApply(Sender);
5634 end;
5635 end
5636 else if Key = _lc[I_PROP_TR_FX_TYPE] then
5637 with ChooseTypeForm, vleObjectProperty do
5638 begin // Выбор типа эффекта:
5639 Caption := _lc[I_CAP_FX_TYPE];
5640 lbTypeSelect.Items.Clear();
5642 for b := EFFECT_NONE to EFFECT_FIRE do
5643 lbTypeSelect.Items.Add(EffectToStr(b));
5645 lbTypeSelect.ItemIndex := StrToEffect(Values[Key]);
5647 if ShowModal() = mrOK then
5648 begin
5649 b := lbTypeSelect.ItemIndex;
5650 Values[Key] := EffectToStr(b);
5651 vleObjectPropertyApply(Sender);
5652 end;
5653 end
5654 else if Key = _lc[I_PROP_TR_MONSTER_TYPE] then
5655 with ChooseTypeForm, vleObjectProperty do
5656 begin // Выбор типа монстра:
5657 Caption := _lc[I_CAP_MONSTER_TYPE];
5658 lbTypeSelect.Items.Clear();
5660 for b := MONSTER_DEMON to MONSTER_MAN do
5661 lbTypeSelect.Items.Add(MonsterToStr(b));
5663 lbTypeSelect.ItemIndex := StrToMonster(Values[Key]) - MONSTER_DEMON;
5665 if ShowModal() = mrOK then
5666 begin
5667 b := lbTypeSelect.ItemIndex + MONSTER_DEMON;
5668 Values[Key] := MonsterToStr(b);
5669 vleObjectPropertyApply(Sender);
5670 end;
5671 end
5672 else if Key = _lc[I_PROP_TR_ITEM_TYPE] then
5673 with ChooseTypeForm, vleObjectProperty do
5674 begin // Выбор типа предмета:
5675 Caption := _lc[I_CAP_ITEM_TYPE];
5676 lbTypeSelect.Items.Clear();
5678 for b := ITEM_MEDKIT_SMALL to ITEM_KEY_BLUE do
5679 lbTypeSelect.Items.Add(ItemToStr(b));
5680 lbTypeSelect.Items.Add(ItemToStr(ITEM_BOTTLE));
5681 lbTypeSelect.Items.Add(ItemToStr(ITEM_HELMET));
5682 lbTypeSelect.Items.Add(ItemToStr(ITEM_JETPACK));
5683 lbTypeSelect.Items.Add(ItemToStr(ITEM_INVIS));
5684 lbTypeSelect.Items.Add(ItemToStr(ITEM_WEAPON_FLAMETHROWER));
5685 lbTypeSelect.Items.Add(ItemToStr(ITEM_AMMO_FUELCAN));
5687 b := StrToItem(Values[Key]);
5688 if b >= ITEM_BOTTLE then
5689 b := b - 2;
5690 lbTypeSelect.ItemIndex := b - ITEM_MEDKIT_SMALL;
5692 if ShowModal() = mrOK then
5693 begin
5694 b := lbTypeSelect.ItemIndex + ITEM_MEDKIT_SMALL;
5695 if b >= ITEM_WEAPON_KASTET then
5696 b := b + 2;
5697 Values[Key] := ItemToStr(b);
5698 vleObjectPropertyApply(Sender);
5699 end;
5700 end
5701 else if Key = _lc[I_PROP_TR_SHOT_TYPE] then
5702 with ChooseTypeForm, vleObjectProperty do
5703 begin // Выбор типа предмета:
5704 Caption := _lc[I_PROP_TR_SHOT_TYPE];
5705 lbTypeSelect.Items.Clear();
5707 for b := TRIGGER_SHOT_PISTOL to TRIGGER_SHOT_MAX do
5708 lbTypeSelect.Items.Add(ShotToStr(b));
5710 lbTypeSelect.ItemIndex := StrToShot(Values[Key]);
5712 if ShowModal() = mrOK then
5713 begin
5714 b := lbTypeSelect.ItemIndex;
5715 Values[Key] := ShotToStr(b);
5716 vleObjectPropertyApply(Sender);
5717 end;
5718 end
5719 else if Key = _lc[I_PROP_TR_EFFECT_TYPE] then
5720 with ChooseTypeForm, vleObjectProperty do
5721 begin // Выбор типа эффекта:
5722 Caption := _lc[I_CAP_FX_TYPE];
5723 lbTypeSelect.Items.Clear();
5725 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_PARTICLE]);
5726 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_ANIMATION]);
5727 if Values[Key] = _lc[I_PROP_TR_EFFECT_ANIMATION] then
5728 lbTypeSelect.ItemIndex := 1
5729 else
5730 lbTypeSelect.ItemIndex := 0;
5732 if ShowModal() = mrOK then
5733 begin
5734 b := lbTypeSelect.ItemIndex;
5735 if b = 0 then
5736 Values[Key] := _lc[I_PROP_TR_EFFECT_PARTICLE]
5737 else
5738 Values[Key] := _lc[I_PROP_TR_EFFECT_ANIMATION];
5739 vleObjectPropertyApply(Sender);
5740 end;
5741 end
5742 else if Key = _lc[I_PROP_TR_EFFECT_SUBTYPE] then
5743 with ChooseTypeForm, vleObjectProperty do
5744 begin // Выбор подтипа эффекта:
5745 Caption := _lc[I_CAP_FX_TYPE];
5746 lbTypeSelect.Items.Clear();
5748 if Values[_lc[I_PROP_TR_EFFECT_TYPE]] = _lc[I_PROP_TR_EFFECT_ANIMATION] then
5749 begin
5750 for b := EFFECT_TELEPORT to EFFECT_FIRE do
5751 lbTypeSelect.Items.Add(EffectToStr(b));
5753 lbTypeSelect.ItemIndex := StrToEffect(Values[Key]) - 1;
5754 end else
5755 begin
5756 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_SLIQUID]);
5757 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_LLIQUID]);
5758 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_DLIQUID]);
5759 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_BLOOD]);
5760 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_SPARK]);
5761 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_BUBBLE]);
5762 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_SLIQUID;
5763 if Values[Key] = _lc[I_PROP_TR_EFFECT_LLIQUID] then
5764 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_LLIQUID;
5765 if Values[Key] = _lc[I_PROP_TR_EFFECT_DLIQUID] then
5766 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_DLIQUID;
5767 if Values[Key] = _lc[I_PROP_TR_EFFECT_BLOOD] then
5768 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_BLOOD;
5769 if Values[Key] = _lc[I_PROP_TR_EFFECT_SPARK] then
5770 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_SPARK;
5771 if Values[Key] = _lc[I_PROP_TR_EFFECT_BUBBLE] then
5772 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_BUBBLE;
5773 end;
5775 if ShowModal() = mrOK then
5776 begin
5777 b := lbTypeSelect.ItemIndex;
5779 if Values[_lc[I_PROP_TR_EFFECT_TYPE]] = _lc[I_PROP_TR_EFFECT_ANIMATION] then
5780 Values[Key] := EffectToStr(b + 1)
5781 else begin
5782 Values[Key] := _lc[I_PROP_TR_EFFECT_SLIQUID];
5783 if b = TRIGGER_EFFECT_LLIQUID then
5784 Values[Key] := _lc[I_PROP_TR_EFFECT_LLIQUID];
5785 if b = TRIGGER_EFFECT_DLIQUID then
5786 Values[Key] := _lc[I_PROP_TR_EFFECT_DLIQUID];
5787 if b = TRIGGER_EFFECT_BLOOD then
5788 Values[Key] := _lc[I_PROP_TR_EFFECT_BLOOD];
5789 if b = TRIGGER_EFFECT_SPARK then
5790 Values[Key] := _lc[I_PROP_TR_EFFECT_SPARK];
5791 if b = TRIGGER_EFFECT_BUBBLE then
5792 Values[Key] := _lc[I_PROP_TR_EFFECT_BUBBLE];
5793 end;
5795 vleObjectPropertyApply(Sender);
5796 end;
5797 end
5798 else if Key = _lc[I_PROP_TR_EFFECT_COLOR] then
5799 with vleObjectProperty do
5800 begin // Выбор цвета эффекта:
5801 ColorDialog.Color := StrToIntDef(Values[Key], 0);
5802 if ColorDialog.Execute then
5803 begin
5804 Values[Key] := IntToStr(ColorDialog.Color);
5805 vleObjectPropertyApply(Sender);
5806 end;
5807 end
5808 else if Key = _lc[I_PROP_PANEL_TEX] then
5809 begin // Смена текстуры:
5810 vleObjectProperty.Values[Key] := SelectedTexture();
5811 vleObjectPropertyApply(Sender);
5812 end;
5813 end;
5815 procedure TMainForm.vleObjectPropertyApply(Sender: TObject);
5816 begin
5817 // hack to prevent empty ID in list
5818 RenderPanel.SetFocus();
5819 bApplyProperty.Click();
5820 vleObjectProperty.SetFocus();
5821 end;
5823 procedure TMainForm.aSaveMapExecute(Sender: TObject);
5824 var
5825 FileName, Section, Res: String;
5826 begin
5827 if OpenedMap = '' then
5828 begin
5829 aSaveMapAsExecute(nil);
5830 Exit;
5831 end;
5833 g_ProcessResourceStr(OpenedMap, FileName, Section, Res);
5835 SaveMap(FileName+':\'+Res);
5836 end;
5838 procedure TMainForm.aOpenMapExecute(Sender: TObject);
5839 begin
5840 OpenDialog.Filter := _lc[I_FILE_FILTER_ALL];
5842 if OpenDialog.Execute() then
5843 begin
5844 if (Pos('.ini', LowerCase(ExtractFileName(OpenDialog.FileName))) > 0) then
5845 begin // INI карты:
5846 FullClear();
5848 pLoadProgress.Left := (RenderPanel.Width div 2)-(pLoadProgress.Width div 2);
5849 pLoadProgress.Top := (RenderPanel.Height div 2)-(pLoadProgress.Height div 2);
5850 pLoadProgress.Show();
5852 OpenedMap := '';
5853 OpenedWAD := '';
5855 LoadMapOld(OpenDialog.FileName);
5857 MainForm.Caption := Format('%s - %s', [FormCaption, ExtractFileName(OpenDialog.FileName)]);
5859 pLoadProgress.Hide();
5860 MainForm.FormResize(Self);
5861 end
5862 else // Карты из WAD:
5863 begin
5864 OpenMap(OpenDialog.FileName, '');
5865 end;
5867 OpenDialog.InitialDir := ExtractFileDir(OpenDialog.FileName);
5868 end;
5869 end;
5871 procedure TMainForm.FormActivate(Sender: TObject);
5872 var
5873 lang: Integer;
5874 config: TConfig;
5875 begin
5876 MainForm.ActiveControl := RenderPanel;
5878 // Язык:
5879 if gLanguage = '' then
5880 begin
5881 lang := SelectLanguageForm.ShowModal();
5882 case lang of
5883 1: gLanguage := LANGUAGE_ENGLISH;
5884 else gLanguage := LANGUAGE_RUSSIAN;
5885 end;
5887 config := TConfig.CreateFile(EditorDir+'Editor.cfg');
5888 config.WriteStr('Editor', 'Language', gLanguage);
5889 config.SaveFile(EditorDir+'Editor.cfg');
5890 config.Free();
5891 end;
5893 //e_WriteLog('Read language file', MSG_NOTIFY);
5894 //g_Language_Load(EditorDir+'\data\'+gLanguage+LANGUAGE_FILE_NAME);
5895 g_Language_Set(gLanguage);
5896 end;
5898 procedure TMainForm.aDeleteMap(Sender: TObject);
5899 var
5900 WAD: TWADEditor_1;
5901 MapList: SArray;
5902 MapName: Char16;
5903 a: Integer;
5904 str: String;
5905 begin
5906 OpenDialog.Filter := _lc[I_FILE_FILTER_WAD];
5908 if not OpenDialog.Execute() then
5909 Exit;
5911 WAD := TWADEditor_1.Create();
5913 if not WAD.ReadFile(OpenDialog.FileName) then
5914 begin
5915 WAD.Free();
5916 Exit;
5917 end;
5919 WAD.CreateImage();
5921 MapList := WAD.GetResourcesList('');
5923 SelectMapForm.Caption := _lc[I_CAP_REMOVE];
5924 SelectMapForm.lbMapList.Items.Clear();
5926 if MapList <> nil then
5927 for a := 0 to High(MapList) do
5928 SelectMapForm.lbMapList.Items.Add(win2utf(MapList[a]));
5930 if (SelectMapForm.ShowModal() = mrOK) then
5931 begin
5932 str := SelectMapForm.lbMapList.Items[SelectMapForm.lbMapList.ItemIndex];
5933 MapName := '';
5934 Move(str[1], MapName[0], Min(16, Length(str)));
5936 if MessageBox(0, PChar(Format(_lc[I_MSG_DELETE_MAP_PROMT],
5937 [MapName, OpenDialog.FileName])),
5938 PChar(_lc[I_MSG_DELETE_MAP]),
5939 MB_ICONQUESTION or MB_YESNO or
5940 MB_DEFBUTTON2) <> mrYes then
5941 Exit;
5943 WAD.RemoveResource('', utf2win(MapName));
5945 MessageBox(0, PChar(Format(_lc[I_MSG_MAP_DELETED_PROMT],
5946 [MapName])),
5947 PChar(_lc[I_MSG_MAP_DELETED]),
5948 MB_ICONINFORMATION or MB_OK or
5949 MB_DEFBUTTON1);
5951 WAD.SaveTo(OpenDialog.FileName);
5953 // Удалили текущую карту - сохранять по старому ее нельзя:
5954 if OpenedMap = (OpenDialog.FileName+':\'+MapName) then
5955 begin
5956 OpenedMap := '';
5957 OpenedWAD := '';
5958 MainForm.Caption := FormCaption;
5959 end;
5960 end;
5962 WAD.Free();
5963 end;
5965 procedure TMainForm.vleObjectPropertyKeyDown(Sender: TObject;
5966 var Key: Word; Shift: TShiftState);
5967 begin
5968 if Key = VK_RETURN then
5969 vleObjectPropertyApply(Sender);
5970 end;
5972 procedure MovePanel(var ID: DWORD; MoveType: Byte);
5973 var
5974 _id, a: Integer;
5975 tmp: TPanel;
5976 begin
5977 if (ID = 0) and (MoveType = 0) then
5978 Exit;
5979 if (ID = DWORD(High(gPanels))) and (MoveType <> 0) then
5980 Exit;
5981 if (ID > DWORD(High(gPanels))) then
5982 Exit;
5984 _id := Integer(ID);
5986 if MoveType = 0 then // to Back
5987 begin
5988 if gTriggers <> nil then
5989 for a := 0 to High(gTriggers) do
5990 with gTriggers[a] do
5991 begin
5992 if TriggerType = TRIGGER_NONE then
5993 Continue;
5995 if TexturePanel = _id then
5996 TexturePanel := 0
5997 else
5998 if (TexturePanel >= 0) and (TexturePanel < _id) then
5999 Inc(TexturePanel);
6001 case TriggerType of
6002 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
6003 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP,
6004 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
6005 if Data.PanelID = _id then
6006 Data.PanelID := 0
6007 else
6008 if (Data.PanelID >= 0) and (Data.PanelID < _id) then
6009 Inc(Data.PanelID);
6011 TRIGGER_SHOT:
6012 if Data.ShotPanelID = _id then
6013 Data.ShotPanelID := 0
6014 else
6015 if (Data.ShotPanelID >= 0) and (Data.ShotPanelID < _id) then
6016 Inc(Data.ShotPanelID);
6017 end;
6018 end;
6020 tmp := gPanels[_id];
6022 for a := _id downto 1 do
6023 gPanels[a] := gPanels[a-1];
6025 gPanels[0] := tmp;
6027 ID := 0;
6028 end
6029 else // to Front
6030 begin
6031 if gTriggers <> nil then
6032 for a := 0 to High(gTriggers) do
6033 with gTriggers[a] do
6034 begin
6035 if TriggerType = TRIGGER_NONE then
6036 Continue;
6038 if TexturePanel = _id then
6039 TexturePanel := High(gPanels)
6040 else
6041 if TexturePanel > _id then
6042 Dec(TexturePanel);
6044 case TriggerType of
6045 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
6046 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP,
6047 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
6048 if Data.PanelID = _id then
6049 Data.PanelID := High(gPanels)
6050 else
6051 if Data.PanelID > _id then
6052 Dec(Data.PanelID);
6054 TRIGGER_SHOT:
6055 if Data.ShotPanelID = _id then
6056 Data.ShotPanelID := High(gPanels)
6057 else
6058 if Data.ShotPanelID > _id then
6059 Dec(Data.ShotPanelID);
6060 end;
6061 end;
6063 tmp := gPanels[_id];
6065 for a := _id to High(gPanels)-1 do
6066 gPanels[a] := gPanels[a+1];
6068 gPanels[High(gPanels)] := tmp;
6070 ID := High(gPanels);
6071 end;
6072 end;
6074 procedure TMainForm.aMoveToBack(Sender: TObject);
6075 var
6076 a: Integer;
6077 begin
6078 if SelectedObjects = nil then
6079 Exit;
6081 for a := 0 to High(SelectedObjects) do
6082 with SelectedObjects[a] do
6083 if Live and (ObjectType = OBJECT_PANEL) then
6084 begin
6085 SelectedObjects[0] := SelectedObjects[a];
6086 SetLength(SelectedObjects, 1);
6087 MovePanel(ID, 0);
6088 FillProperty();
6089 Break;
6090 end;
6091 end;
6093 procedure TMainForm.aMoveToFore(Sender: TObject);
6094 var
6095 a: Integer;
6096 begin
6097 if SelectedObjects = nil then
6098 Exit;
6100 for a := 0 to High(SelectedObjects) do
6101 with SelectedObjects[a] do
6102 if Live and (ObjectType = OBJECT_PANEL) then
6103 begin
6104 SelectedObjects[0] := SelectedObjects[a];
6105 SetLength(SelectedObjects, 1);
6106 MovePanel(ID, 1);
6107 FillProperty();
6108 Break;
6109 end;
6110 end;
6112 procedure TMainForm.aSaveMapAsExecute(Sender: TObject);
6113 var
6114 idx: Integer;
6115 begin
6116 SaveDialog.Filter := _lc[I_FILE_FILTER_WAD];
6118 if not SaveDialog.Execute() then
6119 Exit;
6121 SaveMapForm.GetMaps(SaveDialog.FileName, True);
6123 if SaveMapForm.ShowModal() <> mrOK then
6124 Exit;
6126 SaveDialog.InitialDir := ExtractFileDir(SaveDialog.FileName);
6127 OpenedMap := SaveDialog.FileName+':\'+SaveMapForm.eMapName.Text;
6128 OpenedWAD := SaveDialog.FileName;
6130 idx := RecentFiles.IndexOf(OpenedMap);
6131 // Такая карта уже недавно открывалась:
6132 if idx >= 0 then
6133 RecentFiles.Delete(idx);
6134 RecentFiles.Insert(0, OpenedMap);
6135 RefreshRecentMenu;
6137 SaveMap(OpenedMap);
6139 gMapInfo.FileName := SaveDialog.FileName;
6140 gMapInfo.MapName := SaveMapForm.eMapName.Text;
6141 UpdateCaption(gMapInfo.Name, ExtractFileName(gMapInfo.FileName), gMapInfo.MapName);
6142 end;
6144 procedure TMainForm.aSelectAllExecute(Sender: TObject);
6145 var
6146 a: Integer;
6147 begin
6148 RemoveSelectFromObjects();
6150 case pcObjects.ActivePageIndex+1 of
6151 OBJECT_PANEL:
6152 if gPanels <> nil then
6153 for a := 0 to High(gPanels) do
6154 if gPanels[a].PanelType <> PANEL_NONE then
6155 SelectObject(OBJECT_PANEL, a, True);
6156 OBJECT_ITEM:
6157 if gItems <> nil then
6158 for a := 0 to High(gItems) do
6159 if gItems[a].ItemType <> ITEM_NONE then
6160 SelectObject(OBJECT_ITEM, a, True);
6161 OBJECT_MONSTER:
6162 if gMonsters <> nil then
6163 for a := 0 to High(gMonsters) do
6164 if gMonsters[a].MonsterType <> MONSTER_NONE then
6165 SelectObject(OBJECT_MONSTER, a, True);
6166 OBJECT_AREA:
6167 if gAreas <> nil then
6168 for a := 0 to High(gAreas) do
6169 if gAreas[a].AreaType <> AREA_NONE then
6170 SelectObject(OBJECT_AREA, a, True);
6171 OBJECT_TRIGGER:
6172 if gTriggers <> nil then
6173 for a := 0 to High(gTriggers) do
6174 if gTriggers[a].TriggerType <> TRIGGER_NONE then
6175 SelectObject(OBJECT_TRIGGER, a, True);
6176 end;
6177 end;
6179 procedure TMainForm.tbGridOnClick(Sender: TObject);
6180 begin
6181 DotEnable := not DotEnable;
6182 (Sender as TToolButton).Down := DotEnable;
6183 end;
6185 procedure TMainForm.OnIdle(Sender: TObject; var Done: Boolean);
6186 begin
6187 // FIXME: this is a shitty hack
6188 if not gDataLoaded then
6189 begin
6190 e_WriteLog('Init OpenGL', MSG_NOTIFY);
6191 e_InitGL();
6192 e_WriteLog('Loading data', MSG_NOTIFY);
6193 LoadStdFont('STDTXT', 'STDFONT', gEditorFont);
6194 e_WriteLog('Loading more data', MSG_NOTIFY);
6195 LoadData();
6196 e_WriteLog('Loading even more data', MSG_NOTIFY);
6197 gDataLoaded := True;
6198 MainForm.FormResize(nil);
6199 end;
6200 Draw();
6201 end;
6203 procedure TMainForm.miMapPreviewClick(Sender: TObject);
6204 begin
6205 if PreviewMode = 2 then
6206 Exit;
6208 if PreviewMode = 0 then
6209 begin
6210 Splitter2.Visible := False;
6211 Splitter1.Visible := False;
6212 StatusBar.Visible := False;
6213 PanelObjs.Visible := False;
6214 PanelProps.Visible := False;
6215 MainToolBar.Visible := False;
6216 sbHorizontal.Visible := False;
6217 sbVertical.Visible := False;
6218 end
6219 else
6220 begin
6221 StatusBar.Visible := True;
6222 PanelObjs.Visible := True;
6223 PanelProps.Visible := True;
6224 Splitter2.Visible := True;
6225 Splitter1.Visible := True;
6226 MainToolBar.Visible := True;
6227 sbHorizontal.Visible := True;
6228 sbVertical.Visible := True;
6229 end;
6231 PreviewMode := PreviewMode xor 1;
6232 (Sender as TMenuItem).Checked := PreviewMode > 0;
6234 FormResize(Self);
6235 end;
6237 procedure TMainForm.miLayer1Click(Sender: TObject);
6238 begin
6239 SwitchLayer(LAYER_BACK);
6240 end;
6242 procedure TMainForm.miLayer2Click(Sender: TObject);
6243 begin
6244 SwitchLayer(LAYER_WALLS);
6245 end;
6247 procedure TMainForm.miLayer3Click(Sender: TObject);
6248 begin
6249 SwitchLayer(LAYER_FOREGROUND);
6250 end;
6252 procedure TMainForm.miLayer4Click(Sender: TObject);
6253 begin
6254 SwitchLayer(LAYER_STEPS);
6255 end;
6257 procedure TMainForm.miLayer5Click(Sender: TObject);
6258 begin
6259 SwitchLayer(LAYER_WATER);
6260 end;
6262 procedure TMainForm.miLayer6Click(Sender: TObject);
6263 begin
6264 SwitchLayer(LAYER_ITEMS);
6265 end;
6267 procedure TMainForm.miLayer7Click(Sender: TObject);
6268 begin
6269 SwitchLayer(LAYER_MONSTERS);
6270 end;
6272 procedure TMainForm.miLayer8Click(Sender: TObject);
6273 begin
6274 SwitchLayer(LAYER_AREAS);
6275 end;
6277 procedure TMainForm.miLayer9Click(Sender: TObject);
6278 begin
6279 SwitchLayer(LAYER_TRIGGERS);
6280 end;
6282 procedure TMainForm.tbShowClick(Sender: TObject);
6283 var
6284 a: Integer;
6285 b: Boolean;
6286 begin
6287 b := True;
6288 for a := 0 to High(LayerEnabled) do
6289 b := b and LayerEnabled[a];
6291 b := not b;
6293 ShowLayer(LAYER_BACK, b);
6294 ShowLayer(LAYER_WALLS, b);
6295 ShowLayer(LAYER_FOREGROUND, b);
6296 ShowLayer(LAYER_STEPS, b);
6297 ShowLayer(LAYER_WATER, b);
6298 ShowLayer(LAYER_ITEMS, b);
6299 ShowLayer(LAYER_MONSTERS, b);
6300 ShowLayer(LAYER_AREAS, b);
6301 ShowLayer(LAYER_TRIGGERS, b);
6302 end;
6304 procedure TMainForm.miMiniMapClick(Sender: TObject);
6305 begin
6306 SwitchMap();
6307 end;
6309 procedure TMainForm.miSwitchGridClick(Sender: TObject);
6310 begin
6311 if DotStep = DotStepOne then
6312 DotStep := DotStepTwo
6313 else
6314 DotStep := DotStepOne;
6316 MousePos.X := (MousePos.X div DotStep) * DotStep;
6317 MousePos.Y := (MousePos.Y div DotStep) * DotStep;
6318 end;
6320 procedure TMainForm.miShowEdgesClick(Sender: TObject);
6321 begin
6322 ShowEdges();
6323 end;
6325 procedure TMainForm.miSnapToGridClick(Sender: TObject);
6326 begin
6327 SnapToGrid := not SnapToGrid;
6329 MousePos.X := (MousePos.X div DotStep) * DotStep;
6330 MousePos.Y := (MousePos.Y div DotStep) * DotStep;
6332 miSnapToGrid.Checked := SnapToGrid;
6333 end;
6335 procedure TMainForm.minexttabClick(Sender: TObject);
6336 begin
6337 if pcObjects.ActivePageIndex < pcObjects.PageCount-1 then
6338 pcObjects.ActivePageIndex := pcObjects.ActivePageIndex+1
6339 else
6340 pcObjects.ActivePageIndex := 0;
6341 end;
6343 procedure TMainForm.miSaveMiniMapClick(Sender: TObject);
6344 begin
6345 SaveMiniMapForm.ShowModal();
6346 end;
6348 procedure TMainForm.bClearTextureClick(Sender: TObject);
6349 begin
6350 lbTextureList.ItemIndex := -1;
6351 lTextureWidth.Caption := '';
6352 lTextureHeight.Caption := '';
6353 end;
6355 procedure TMainForm.miPackMapClick(Sender: TObject);
6356 begin
6357 PackMapForm.ShowModal();
6358 end;
6360 procedure TMainForm.miMapTestSettingsClick(Sender: TObject);
6361 begin
6362 MapTestForm.ShowModal();
6363 end;
6365 procedure TMainForm.miTestMapClick(Sender: TObject);
6366 var
6367 cmd, mapWAD, mapToRun, tempWAD: String;
6368 opt: LongWord;
6369 time: Integer;
6370 proc: TProcessUTF8;
6371 res: Boolean;
6372 begin
6373 mapToRun := '';
6374 if OpenedMap <> '' then
6375 begin
6376 // Указываем текущую карту для теста:
6377 g_ProcessResourceStr(OpenedMap, @mapWAD, nil, @mapToRun);
6378 mapToRun := mapWAD + ':\' + mapToRun;
6379 mapToRun := ExtractRelativePath(ExtractFilePath(TestD2dExe) + 'maps/', mapToRun);
6380 end;
6381 // Сохраняем временную карту:
6382 time := 0;
6383 repeat
6384 mapWAD := ExtractFilePath(TestD2dExe) + Format('maps/temp%.4d.wad', [time]);
6385 Inc(time);
6386 until not FileExists(mapWAD);
6387 tempWAD := mapWAD + ':\' + TEST_MAP_NAME;
6388 SaveMap(tempWAD);
6390 tempWAD := ExtractRelativePath(ExtractFilePath(TestD2dExe) + 'maps/', tempWAD);
6391 // Если карта не была открыта, указываем временную в качестве текущей:
6392 if mapToRun = '' then
6393 mapToRun := tempWAD;
6395 // Опции игры:
6396 opt := 32 + 64;
6397 if TestOptionsTwoPlayers then
6398 opt := opt + 1;
6399 if TestOptionsTeamDamage then
6400 opt := opt + 2;
6401 if TestOptionsAllowExit then
6402 opt := opt + 4;
6403 if TestOptionsWeaponStay then
6404 opt := opt + 8;
6405 if TestOptionsMonstersDM then
6406 opt := opt + 16;
6408 // Составляем командную строку:
6409 cmd := '-map "' + mapToRun + '"';
6410 cmd := cmd + ' -testmap "' + tempWAD + '"';
6411 cmd := cmd + ' -gm ' + TestGameMode;
6412 cmd := cmd + ' -limt ' + TestLimTime;
6413 cmd := cmd + ' -lims ' + TestLimScore;
6414 cmd := cmd + ' -opt ' + IntToStr(opt);
6416 if TestMapOnce then
6417 cmd := cmd + ' --close';
6419 cmd := cmd + ' --debug';
6421 // Запускаем:
6422 proc := TProcessUTF8.Create(nil);
6423 proc.Executable := TestD2dExe;
6424 proc.Parameters.Add(cmd);
6425 res := True;
6426 try
6427 proc.Execute();
6428 except
6429 res := False;
6430 end;
6431 if res then
6432 begin
6433 Application.Minimize();
6434 proc.WaitOnExit();
6435 end;
6436 if (not res) or (proc.ExitCode < 0) then
6437 begin
6438 MessageBox(0, 'FIXME',
6439 PChar(_lc[I_MSG_EXEC_ERROR]),
6440 MB_OK or MB_ICONERROR);
6441 end;
6442 proc.Free();
6444 SysUtils.DeleteFile(mapWAD);
6445 Application.Restore();
6446 end;
6448 procedure TMainForm.sbVerticalScroll(Sender: TObject;
6449 ScrollCode: TScrollCode; var ScrollPos: Integer);
6450 begin
6451 MapOffset.Y := -Normalize16(sbVertical.Position);
6452 end;
6454 procedure TMainForm.sbHorizontalScroll(Sender: TObject;
6455 ScrollCode: TScrollCode; var ScrollPos: Integer);
6456 begin
6457 MapOffset.X := -Normalize16(sbHorizontal.Position);
6458 end;
6460 procedure TMainForm.miOpenWadMapClick(Sender: TObject);
6461 begin
6462 if OpenedWAD <> '' then
6463 begin
6464 OpenMap(OpenedWAD, '');
6465 end;
6466 end;
6468 procedure TMainForm.selectall1Click(Sender: TObject);
6469 var
6470 a: Integer;
6471 begin
6472 RemoveSelectFromObjects();
6474 if gPanels <> nil then
6475 for a := 0 to High(gPanels) do
6476 if gPanels[a].PanelType <> PANEL_NONE then
6477 SelectObject(OBJECT_PANEL, a, True);
6479 if gItems <> nil then
6480 for a := 0 to High(gItems) do
6481 if gItems[a].ItemType <> ITEM_NONE then
6482 SelectObject(OBJECT_ITEM, a, True);
6484 if gMonsters <> nil then
6485 for a := 0 to High(gMonsters) do
6486 if gMonsters[a].MonsterType <> MONSTER_NONE then
6487 SelectObject(OBJECT_MONSTER, a, True);
6489 if gAreas <> nil then
6490 for a := 0 to High(gAreas) do
6491 if gAreas[a].AreaType <> AREA_NONE then
6492 SelectObject(OBJECT_AREA, a, True);
6494 if gTriggers <> nil then
6495 for a := 0 to High(gTriggers) do
6496 if gTriggers[a].TriggerType <> TRIGGER_NONE then
6497 SelectObject(OBJECT_TRIGGER, a, True);
6498 end;
6500 procedure TMainForm.Splitter1CanResize(Sender: TObject;
6501 var NewSize: Integer; var Accept: Boolean);
6502 begin
6503 Accept := (NewSize > 140);
6504 end;
6506 procedure TMainForm.Splitter2CanResize(Sender: TObject;
6507 var NewSize: Integer; var Accept: Boolean);
6508 begin
6509 Accept := (NewSize > 110);
6510 end;
6512 procedure TMainForm.vleObjectPropertyEnter(Sender: TObject);
6513 begin
6514 EditingProperties := True;
6515 end;
6517 procedure TMainForm.vleObjectPropertyExit(Sender: TObject);
6518 begin
6519 EditingProperties := False;
6520 end;
6522 procedure TMainForm.FormKeyUp(Sender: TObject; var Key: Word;
6523 Shift: TShiftState);
6524 begin
6525 // Объекты передвигались:
6526 if MainForm.ActiveControl = RenderPanel then
6527 begin
6528 if (Key = VK_NUMPAD4) or
6529 (Key = VK_NUMPAD6) or
6530 (Key = VK_NUMPAD8) or
6531 (Key = VK_NUMPAD5) or
6532 (Key = Ord('V')) then
6533 FillProperty();
6534 end;
6535 // Быстрое превью карты:
6536 if Key = Ord('E') then
6537 begin
6538 if PreviewMode = 2 then
6539 PreviewMode := 0;
6540 end;
6541 end;
6543 end.