DEADSOFTWARE

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