DEADSOFTWARE

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