DEADSOFTWARE

Maps can be saved to zip
[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 RecentCount := config.ReadInt('Editor', 'RecentCount', 5);
2741 if RecentCount > 10 then
2742 RecentCount := 10;
2743 if RecentCount < 2 then
2744 RecentCount := 2;
2746 RecentFiles := TStringList.Create();
2747 for i := 0 to RecentCount-1 do
2748 begin
2749 s := config.ReadStr('RecentFiles', IntToStr(i+1), '');
2750 if s <> '' then
2751 RecentFiles.Add(s);
2752 end;
2753 RefreshRecentMenu();
2755 config.Free();
2757 tbShowMap.Down := ShowMap;
2758 tbGridOn.Down := DotEnable;
2759 pcObjects.ActivePageIndex := 0;
2760 Application.Title := _lc[I_EDITOR_TITLE];
2762 Application.OnIdle := OnIdle;
2763 end;
2765 procedure PrintBlack(X, Y: Integer; Text: string; FontID: DWORD);
2766 begin
2767 // NOTE: all the font printing routines assume CP1251
2768 e_TextureFontPrintEx(X, Y, Text, FontID, 0, 0, 0, 1.0);
2769 end;
2771 procedure TMainForm.Draw();
2772 var
2773 x, y: Integer;
2774 a, b: Integer;
2775 ID, PID: DWORD;
2776 Width, Height: Word;
2777 Rect: TRectWH;
2778 ObjCount: Word;
2779 aX, aY, aX2, aY2, XX, ScaleSz: Integer;
2780 begin
2781 ID := 0;
2782 PID := 0;
2783 Width := 0;
2784 Height := 0;
2786 e_BeginRender();
2788 e_Clear(GL_COLOR_BUFFER_BIT,
2789 GetRValue(BackColor)/255,
2790 GetGValue(BackColor)/255,
2791 GetBValue(BackColor)/255);
2793 DrawMap();
2795 ObjCount := SelectedObjectCount();
2797 // Обводим выделенные объекты красной рамкой:
2798 if ObjCount > 0 then
2799 begin
2800 for a := 0 to High(SelectedObjects) do
2801 if SelectedObjects[a].Live then
2802 begin
2803 Rect := ObjectGetRect(SelectedObjects[a].ObjectType, SelectedObjects[a].ID);
2805 with Rect do
2806 begin
2807 e_DrawQuad(X+MapOffset.X, Y+MapOffset.Y,
2808 X+MapOffset.X+Width-1, Y+MapOffset.Y+Height-1,
2809 255, 0, 0);
2811 // Рисуем точки изменения размеров:
2812 if (ObjCount = 1) and
2813 (SelectedObjects[GetFirstSelected].ObjectType in [OBJECT_PANEL, OBJECT_TRIGGER]) then
2814 begin
2815 e_DrawPoint(5, X+MapOffset.X, Y+MapOffset.Y+(Height div 2), 255, 255, 255);
2816 e_DrawPoint(5, X+MapOffset.X+Width-1, Y+MapOffset.Y+(Height div 2), 255, 255, 255);
2817 e_DrawPoint(5, X+MapOffset.X+(Width div 2), Y+MapOffset.Y, 255, 255, 255);
2818 e_DrawPoint(5, X+MapOffset.X+(Width div 2), Y+MapOffset.Y+Height-1, 255, 255, 255);
2820 e_DrawPoint(3, X+MapOffset.X, Y+MapOffset.Y+(Height div 2), 255, 0, 0);
2821 e_DrawPoint(3, X+MapOffset.X+Width-1, Y+MapOffset.Y+(Height div 2), 255, 0, 0);
2822 e_DrawPoint(3, X+MapOffset.X+(Width div 2), Y+MapOffset.Y, 255, 0, 0);
2823 e_DrawPoint(3, X+MapOffset.X+(Width div 2), Y+MapOffset.Y+Height-1, 255, 0, 0);
2824 end;
2825 end;
2826 end;
2827 end;
2829 // Рисуем сетку:
2830 if DotEnable and (PreviewMode = 0) then
2831 begin
2832 if DotSize = 2 then
2833 a := -1
2834 else
2835 a := 0;
2837 for x := 0 to (RenderPanel.Width div DotStep) do
2838 for y := 0 to (RenderPanel.Height div DotStep) do
2839 e_DrawPoint(DotSize, x*DotStep + a, y*DotStep + a,
2840 GetRValue(DotColor),
2841 GetGValue(DotColor),
2842 GetBValue(DotColor));
2843 end;
2845 // Превью текстуры:
2846 if (lbTextureList.ItemIndex <> -1) and (cbPreview.Checked) and
2847 (not IsSpecialTextureSel()) and (PreviewMode = 0) then
2848 begin
2849 if not g_GetTexture(SelectedTexture(), ID) then
2850 g_GetTexture('NOTEXTURE', ID);
2851 g_GetTextureSizeByID(ID, Width, Height);
2852 if UseCheckerboard then
2853 begin
2854 if g_GetTexture('PREVIEW', PID) then
2855 e_DrawFill(PID, RenderPanel.Width-Width, RenderPanel.Height-Height, Width div 16 + 1, Height div 16 + 1, 0, True, False);
2856 end else
2857 e_DrawFillQuad(RenderPanel.Width-Width-2, RenderPanel.Height-Height-2,
2858 RenderPanel.Width-1, RenderPanel.Height-1,
2859 GetRValue(PreviewColor), GetGValue(PreviewColor), GetBValue(PreviewColor), 0);
2860 e_Draw(ID, RenderPanel.Width-Width, RenderPanel.Height-Height, 0, True, False);
2861 end;
2863 // Подсказка при выборе точки Телепорта:
2864 if SelectFlag = SELECTFLAG_TELEPORT then
2865 begin
2866 with gTriggers[SelectedObjects[GetFirstSelected()].ID] do
2867 if Data.d2d_teleport then
2868 e_DrawLine(2, MousePos.X-16, MousePos.Y-1,
2869 MousePos.X+16, MousePos.Y-1,
2870 0, 0, 255)
2871 else
2872 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+AreaSize[AREA_DMPOINT].Width-1,
2873 MousePos.Y+AreaSize[AREA_DMPOINT].Height-1, 255, 255, 255);
2875 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 192, 192, 192, 127);
2876 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 255, 255, 255);
2877 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_TELEPORT], gEditorFont);
2878 end;
2880 // Подсказка при выборе точки появления:
2881 if SelectFlag = SELECTFLAG_SPAWNPOINT then
2882 begin
2883 e_DrawLine(2, MousePos.X-16, MousePos.Y-1,
2884 MousePos.X+16, MousePos.Y-1,
2885 0, 0, 255);
2886 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 192, 192, 192, 127);
2887 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 255, 255, 255);
2888 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_SPAWN], gEditorFont);
2889 end;
2891 // Подсказка при выборе панели двери:
2892 if SelectFlag = SELECTFLAG_DOOR then
2893 begin
2894 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 192, 192, 192, 127);
2895 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 255, 255, 255);
2896 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_PANEL_DOOR], gEditorFont);
2897 end;
2899 // Подсказка при выборе панели с текстурой:
2900 if SelectFlag = SELECTFLAG_TEXTURE then
2901 begin
2902 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+196, MousePos.Y+18, 192, 192, 192, 127);
2903 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+196, MousePos.Y+18, 255, 255, 255);
2904 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_PANEL_TEXTURE], gEditorFont);
2905 end;
2907 // Подсказка при выборе панели индикации выстрела:
2908 if SelectFlag = SELECTFLAG_SHOTPANEL then
2909 begin
2910 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+316, MousePos.Y+18, 192, 192, 192, 127);
2911 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+316, MousePos.Y+18, 255, 255, 255);
2912 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_PANEL_SHOT], gEditorFont);
2913 end;
2915 // Подсказка при выборе панели лифта:
2916 if SelectFlag = SELECTFLAG_LIFT then
2917 begin
2918 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 192, 192, 192, 127);
2919 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 255, 255, 255);
2920 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_PANEL_LIFT], gEditorFont);
2921 end;
2923 // Подсказка при выборе монстра:
2924 if SelectFlag = SELECTFLAG_MONSTER then
2925 begin
2926 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+120, MousePos.Y+18, 192, 192, 192, 127);
2927 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+120, MousePos.Y+18, 255, 255, 255);
2928 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_MONSTER], gEditorFont);
2929 end;
2931 // Подсказка при выборе области воздействия:
2932 if DrawPressRect then
2933 begin
2934 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+204, MousePos.Y+18, 192, 192, 192, 127);
2935 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+204, MousePos.Y+18, 255, 255, 255);
2936 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_EXT_AREA], gEditorFont);
2937 end;
2939 // Рисуем текстуры, если чертим панель:
2940 if (MouseAction = MOUSEACTION_DRAWPANEL) and (DrawTexturePanel) and
2941 (lbTextureList.ItemIndex <> -1) and (DrawRect <> nil) and
2942 (lbPanelType.ItemIndex in [0..8]) and not IsSpecialTextureSel() then
2943 begin
2944 if not g_GetTexture(SelectedTexture(), ID) then
2945 g_GetTexture('NOTEXTURE', ID);
2946 g_GetTextureSizeByID(ID, Width, Height);
2947 with DrawRect^ do
2948 if (Abs(Right-Left) >= Width) and (Abs(Bottom-Top) >= Height) then
2949 e_DrawFill(ID, Min(Left, Right), Min(Top, Bottom), Abs(Right-Left) div Width,
2950 Abs(Bottom-Top) div Height, 64, True, False);
2951 end;
2953 // Прямоугольник выделения:
2954 if DrawRect <> nil then
2955 with DrawRect^ do
2956 e_DrawQuad(Left, Top, Right-1, Bottom-1, 255, 255, 255);
2958 // Чертим мышью панель/триггер или меняем мышью их размер:
2959 if (((MouseAction in [MOUSEACTION_DRAWPANEL, MOUSEACTION_DRAWTRIGGER]) and
2960 not(ssCtrl in GetKeyShiftState())) or (MouseAction = MOUSEACTION_RESIZE)) and
2961 (DrawPanelSize) then
2962 begin
2963 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+88, MousePos.Y+33, 192, 192, 192, 127);
2964 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+88, MousePos.Y+33, 255, 255, 255);
2966 if MouseAction in [MOUSEACTION_DRAWPANEL, MOUSEACTION_DRAWTRIGGER] then
2967 begin // Чертим новый
2968 PrintBlack(MousePos.X+2, MousePos.Y+2, Format(_glc[I_HINT_WIDTH],
2969 [Abs(MousePos.X-MouseLDownPos.X)]), gEditorFont);
2970 PrintBlack(MousePos.X+2, MousePos.Y+16, Format(_glc[I_HINT_HEIGHT],
2971 [Abs(MousePos.Y-MouseLDownPos.Y)]), gEditorFont);
2972 end
2973 else // Растягиваем существующий
2974 if SelectedObjects[GetFirstSelected].ObjectType in [OBJECT_PANEL, OBJECT_TRIGGER] then
2975 begin
2976 if SelectedObjects[GetFirstSelected].ObjectType = OBJECT_PANEL then
2977 begin
2978 Width := gPanels[SelectedObjects[GetFirstSelected].ID].Width;
2979 Height := gPanels[SelectedObjects[GetFirstSelected].ID].Height;
2980 end
2981 else
2982 begin
2983 Width := gTriggers[SelectedObjects[GetFirstSelected].ID].Width;
2984 Height := gTriggers[SelectedObjects[GetFirstSelected].ID].Height;
2985 end;
2987 PrintBlack(MousePos.X+2, MousePos.Y+2, Format(_glc[I_HINT_WIDTH], [Width]),
2988 gEditorFont);
2989 PrintBlack(MousePos.X+2, MousePos.Y+16, Format(_glc[I_HINT_HEIGHT], [Height]),
2990 gEditorFont);
2991 end;
2992 end;
2994 // Ближайшая к курсору мыши точка на сетке:
2995 e_DrawPoint(3, MousePos.X, MousePos.Y, 0, 0, 255);
2997 // Мини-карта:
2998 if ShowMap then
2999 begin
3000 // Сколько пикселов карты в 1 пикселе мини-карты:
3001 ScaleSz := 16 div Scale;
3002 // Размеры мини-карты:
3003 aX := max(gMapInfo.Width div ScaleSz, 1);
3004 aY := max(gMapInfo.Height div ScaleSz, 1);
3005 // X-координата на RenderPanel нулевой x-координаты карты:
3006 XX := RenderPanel.Width - aX - 1;
3007 // Рамка карты:
3008 e_DrawFillQuad(XX-1, 0, RenderPanel.Width-1, aY+1, 0, 0, 0, 0);
3009 e_DrawQuad(XX-1, 0, RenderPanel.Width-1, aY+1, 197, 197, 197);
3011 if gPanels <> nil then
3012 begin
3013 // Рисуем панели:
3014 for a := 0 to High(gPanels) do
3015 with gPanels[a] do
3016 if PanelType <> 0 then
3017 begin
3018 // Левый верхний угол:
3019 aX := XX + (X div ScaleSz);
3020 aY := 1 + (Y div ScaleSz);
3021 // Размеры:
3022 aX2 := max(Width div ScaleSz, 1);
3023 aY2 := max(Height div ScaleSz, 1);
3024 // Правый нижний угол:
3025 aX2 := aX + aX2 - 1;
3026 aY2 := aY + aY2 - 1;
3028 case PanelType of
3029 PANEL_WALL: e_DrawFillQuad(aX, aY, aX2, aY2, 208, 208, 208, 0);
3030 PANEL_WATER: e_DrawFillQuad(aX, aY, aX2, aY2, 0, 0, 192, 0);
3031 PANEL_ACID1: e_DrawFillQuad(aX, aY, aX2, aY2, 0, 176, 0, 0);
3032 PANEL_ACID2: e_DrawFillQuad(aX, aY, aX2, aY2, 176, 0, 0, 0);
3033 PANEL_STEP: e_DrawFillQuad(aX, aY, aX2, aY2, 128, 128, 128, 0);
3034 PANEL_LIFTUP: e_DrawFillQuad(aX, aY, aX2, aY2, 116, 72, 36, 0);
3035 PANEL_LIFTDOWN: e_DrawFillQuad(aX, aY, aX2, aY2, 116, 124, 96, 0);
3036 PANEL_LIFTLEFT: e_DrawFillQuad(aX, aY, aX2, aY2, 200, 80, 4, 0);
3037 PANEL_LIFTRIGHT: e_DrawFillQuad(aX, aY, aX2, aY2, 252, 140, 56, 0);
3038 PANEL_OPENDOOR: e_DrawFillQuad(aX, aY, aX2, aY2, 100, 220, 92, 0);
3039 PANEL_CLOSEDOOR: e_DrawFillQuad(aX, aY, aX2, aY2, 212, 184, 64, 0);
3040 PANEL_BLOCKMON: e_DrawFillQuad(aX, aY, aX2, aY2, 192, 0, 192, 0);
3041 end;
3042 end;
3044 // Рисуем красным выделенные панели:
3045 if SelectedObjects <> nil then
3046 for b := 0 to High(SelectedObjects) do
3047 with SelectedObjects[b] do
3048 if Live and (ObjectType = OBJECT_PANEL) then
3049 with gPanels[SelectedObjects[b].ID] do
3050 if PanelType and not(PANEL_BACK or PANEL_FORE) <> 0 then
3051 begin
3052 // Левый верхний угол:
3053 aX := XX + (X div ScaleSz);
3054 aY := 1 + (Y div ScaleSz);
3055 // Размеры:
3056 aX2 := max(Width div ScaleSz, 1);
3057 aY2 := max(Height div ScaleSz, 1);
3058 // Правый нижний угол:
3059 aX2 := aX + aX2 - 1;
3060 aY2 := aY + aY2 - 1;
3062 e_DrawFillQuad(aX, aY, aX2, aY2, 255, 0, 0, 0)
3063 end;
3064 end;
3066 if (gMapInfo.Width > RenderPanel.Width) or
3067 (gMapInfo.Height > RenderPanel.Height) then
3068 begin
3069 // Окно, показывающее текущее положение экрана на карте:
3070 // Размеры окна:
3071 x := max(min(RenderPanel.Width, gMapInfo.Width) div ScaleSz, 1);
3072 y := max(min(RenderPanel.Height, gMapInfo.Height) div ScaleSz, 1);
3073 // Левый верхний угол:
3074 aX := XX + ((-MapOffset.X) div ScaleSz);
3075 aY := 1 + ((-MapOffset.Y) div ScaleSz);
3076 // Правый нижний угол:
3077 aX2 := aX + x - 1;
3078 aY2 := aY + y - 1;
3080 e_DrawFillQuad(aX, aY, aX2, aY2, 127, 192, 127, 127, B_BLEND);
3081 e_DrawQuad(aX, aY, aX2, aY2, 255, 0, 0);
3082 end;
3083 end; // Мини-карта
3085 e_EndRender();
3086 RenderPanel.SwapBuffers();
3087 end;
3089 procedure TMainForm.FormResize(Sender: TObject);
3090 begin
3091 e_SetViewPort(0, 0, RenderPanel.Width, RenderPanel.Height);
3093 if gMapInfo.Width >= RenderPanel.Width then
3094 sbHorizontal.Max := Normalize16(gMapInfo.Width-RenderPanel.Width+16)
3095 else
3096 sbHorizontal.Max := 0;
3098 if gMapInfo.Height >= RenderPanel.Height then
3099 sbVertical.Max := Normalize16(gMapInfo.Height-RenderPanel.Height+16)
3100 else
3101 sbVertical.Max := 0;
3103 MapOffset.X := -Normalize16(sbHorizontal.Position);
3104 MapOffset.Y := -Normalize16(sbVertical.Position);
3105 end;
3107 procedure SelectNextObject(X, Y: Integer; ObjectType: Byte; ID: DWORD);
3108 var
3109 j, j_max: Integer;
3110 res: Boolean;
3111 begin
3112 j_max := 0; // shut up compiler
3113 case ObjectType of
3114 OBJECT_PANEL:
3115 begin
3116 res := (gPanels <> nil) and
3117 PanelInShownLayer(gPanels[ID].PanelType) and
3118 g_CollidePoint(X, Y, gPanels[ID].X, gPanels[ID].Y,
3119 gPanels[ID].Width,
3120 gPanels[ID].Height);
3121 j_max := Length(gPanels) - 1;
3122 end;
3124 OBJECT_ITEM:
3125 begin
3126 res := (gItems <> nil) and
3127 LayerEnabled[LAYER_ITEMS] and
3128 g_CollidePoint(X, Y, gItems[ID].X, gItems[ID].Y,
3129 ItemSize[gItems[ID].ItemType][0],
3130 ItemSize[gItems[ID].ItemType][1]);
3131 j_max := Length(gItems) - 1;
3132 end;
3134 OBJECT_MONSTER:
3135 begin
3136 res := (gMonsters <> nil) and
3137 LayerEnabled[LAYER_MONSTERS] and
3138 g_CollidePoint(X, Y, gMonsters[ID].X, gMonsters[ID].Y,
3139 MonsterSize[gMonsters[ID].MonsterType].Width,
3140 MonsterSize[gMonsters[ID].MonsterType].Height);
3141 j_max := Length(gMonsters) - 1;
3142 end;
3144 OBJECT_AREA:
3145 begin
3146 res := (gAreas <> nil) and
3147 LayerEnabled[LAYER_AREAS] and
3148 g_CollidePoint(X, Y, gAreas[ID].X, gAreas[ID].Y,
3149 AreaSize[gAreas[ID].AreaType].Width,
3150 AreaSize[gAreas[ID].AreaType].Height);
3151 j_max := Length(gAreas) - 1;
3152 end;
3154 OBJECT_TRIGGER:
3155 begin
3156 res := (gTriggers <> nil) and
3157 LayerEnabled[LAYER_TRIGGERS] and
3158 g_CollidePoint(X, Y, gTriggers[ID].X, gTriggers[ID].Y,
3159 gTriggers[ID].Width,
3160 gTriggers[ID].Height);
3161 j_max := Length(gTriggers) - 1;
3162 end;
3164 else
3165 res := False;
3166 end;
3168 if not res then
3169 Exit;
3171 // Перебор ID: от ID-1 до 0; потом от High до ID+1:
3172 j := ID;
3174 while True do
3175 begin
3176 Dec(j);
3178 if j < 0 then
3179 j := j_max;
3180 if j = Integer(ID) then
3181 Break;
3183 case ObjectType of
3184 OBJECT_PANEL:
3185 res := PanelInShownLayer(gPanels[j].PanelType) and
3186 g_CollidePoint(X, Y, gPanels[j].X, gPanels[j].Y,
3187 gPanels[j].Width,
3188 gPanels[j].Height);
3189 OBJECT_ITEM:
3190 res := (gItems[j].ItemType <> ITEM_NONE) and
3191 g_CollidePoint(X, Y, gItems[j].X, gItems[j].Y,
3192 ItemSize[gItems[j].ItemType][0],
3193 ItemSize[gItems[j].ItemType][1]);
3194 OBJECT_MONSTER:
3195 res := (gMonsters[j].MonsterType <> MONSTER_NONE) and
3196 g_CollidePoint(X, Y, gMonsters[j].X, gMonsters[j].Y,
3197 MonsterSize[gMonsters[j].MonsterType].Width,
3198 MonsterSize[gMonsters[j].MonsterType].Height);
3199 OBJECT_AREA:
3200 res := (gAreas[j].AreaType <> AREA_NONE) and
3201 g_CollidePoint(X, Y, gAreas[j].X, gAreas[j].Y,
3202 AreaSize[gAreas[j].AreaType].Width,
3203 AreaSize[gAreas[j].AreaType].Height);
3204 OBJECT_TRIGGER:
3205 res := (gTriggers[j].TriggerType <> TRIGGER_NONE) and
3206 g_CollidePoint(X, Y, gTriggers[j].X, gTriggers[j].Y,
3207 gTriggers[j].Width,
3208 gTriggers[j].Height);
3209 else
3210 res := False;
3211 end;
3213 if res then
3214 begin
3215 SetLength(SelectedObjects, 1);
3217 SelectedObjects[0].ObjectType := ObjectType;
3218 SelectedObjects[0].ID := j;
3219 SelectedObjects[0].Live := True;
3221 FillProperty();
3222 Break;
3223 end;
3224 end;
3225 end;
3227 procedure TMainForm.RenderPanelMouseDown(Sender: TObject;
3228 Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
3229 var
3230 i: Integer;
3231 Rect: TRectWH;
3232 c1, c2, c3, c4: Boolean;
3233 item: TItem;
3234 area: TArea;
3235 monster: TMonster;
3236 IDArray: DWArray;
3237 begin
3238 MainForm.ActiveControl := RenderPanel;
3239 RenderPanel.SetFocus();
3241 RenderPanelMouseMove(RenderPanel, Shift, X, Y);
3243 if Button = mbLeft then // Left Mouse Button
3244 begin
3245 // Двигаем карту с помощью мыши и мини-карты:
3246 if ShowMap and
3247 g_CollidePoint(X, Y,
3248 RenderPanel.Width-max(gMapInfo.Width div (16 div Scale), 1)-1,
3249 1,
3250 max(gMapInfo.Width div (16 div Scale), 1),
3251 max(gMapInfo.Height div (16 div Scale), 1) ) then
3252 begin
3253 MoveMap(X, Y);
3254 MouseAction := MOUSEACTION_MOVEMAP;
3255 end
3256 else // Ставим предмет/монстра/область:
3257 if (pcObjects.ActivePageIndex in [1, 2, 3]) and
3258 (not (ssShift in Shift)) then
3259 begin
3260 case pcObjects.ActivePageIndex of
3261 1:
3262 if lbItemList.ItemIndex = -1 then
3263 ErrorMessageBox(_lc[I_MSG_CHOOSE_ITEM])
3264 else
3265 begin
3266 item.ItemType := lbItemList.ItemIndex + ITEM_MEDKIT_SMALL;
3267 if item.ItemType >= ITEM_WEAPON_KASTET then
3268 item.ItemType := item.ItemType + 2;
3269 item.X := MousePos.X-MapOffset.X;
3270 item.Y := MousePos.Y-MapOffset.Y;
3272 if not (ssCtrl in Shift) then
3273 begin
3274 item.X := item.X - (ItemSize[item.ItemType][0] div 2);
3275 item.Y := item.Y - ItemSize[item.ItemType][1];
3276 end;
3278 item.OnlyDM := cbOnlyDM.Checked;
3279 item.Fall := cbFall.Checked;
3280 Undo_Add(OBJECT_ITEM, AddItem(item));
3281 end;
3282 2:
3283 if lbMonsterList.ItemIndex = -1 then
3284 ErrorMessageBox(_lc[I_MSG_CHOOSE_MONSTER])
3285 else
3286 begin
3287 monster.MonsterType := lbMonsterList.ItemIndex + MONSTER_DEMON;
3288 monster.X := MousePos.X-MapOffset.X;
3289 monster.Y := MousePos.Y-MapOffset.Y;
3291 if not (ssCtrl in Shift) then
3292 begin
3293 monster.X := monster.X - (MonsterSize[monster.MonsterType].Width div 2);
3294 monster.Y := monster.Y - MonsterSize[monster.MonsterType].Height;
3295 end;
3297 if rbMonsterLeft.Checked then
3298 monster.Direction := D_LEFT
3299 else
3300 monster.Direction := D_RIGHT;
3301 Undo_Add(OBJECT_MONSTER, AddMonster(monster));
3302 end;
3303 3:
3304 if lbAreasList.ItemIndex = -1 then
3305 ErrorMessageBox(_lc[I_MSG_CHOOSE_AREA])
3306 else
3307 if (lbAreasList.ItemIndex + 1) <> AREA_DOMFLAG then
3308 begin
3309 area.AreaType := lbAreasList.ItemIndex + AREA_PLAYERPOINT1;
3310 area.X := MousePos.X-MapOffset.X;
3311 area.Y := MousePos.Y-MapOffset.Y;
3313 if not (ssCtrl in Shift) then
3314 begin
3315 area.X := area.X - (AreaSize[area.AreaType].Width div 2);
3316 area.Y := area.Y - AreaSize[area.AreaType].Height;
3317 end;
3319 if rbAreaLeft.Checked then
3320 area.Direction := D_LEFT
3321 else
3322 area.Direction := D_RIGHT;
3323 Undo_Add(OBJECT_AREA, AddArea(area));
3324 end;
3325 end;
3326 end
3327 else
3328 begin
3329 i := GetFirstSelected();
3331 // Выбираем объект под текущим:
3332 if (SelectedObjects <> nil) and
3333 (ssShift in Shift) and (i >= 0) and
3334 (SelectedObjects[i].Live) then
3335 begin
3336 if SelectedObjectCount() = 1 then
3337 SelectNextObject(X-MapOffset.X, Y-MapOffset.Y,
3338 SelectedObjects[i].ObjectType,
3339 SelectedObjects[i].ID);
3340 end
3341 else
3342 begin
3343 // Рисуем область триггера "Расширитель":
3344 if DrawPressRect and (i >= 0) and
3345 (SelectedObjects[i].ObjectType = OBJECT_TRIGGER) and
3346 (gTriggers[SelectedObjects[i].ID].TriggerType in
3347 [TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF]) then
3348 MouseAction := MOUSEACTION_DRAWPRESS
3349 else // Рисуем панель:
3350 if pcObjects.ActivePageIndex = 0 then
3351 begin
3352 if (lbPanelType.ItemIndex >= 0) then
3353 MouseAction := MOUSEACTION_DRAWPANEL
3354 end
3355 else // Рисуем триггер:
3356 if (lbTriggersList.ItemIndex >= 0) then
3357 begin
3358 MouseAction := MOUSEACTION_DRAWTRIGGER;
3359 end;
3360 end;
3361 end;
3362 end; // if Button = mbLeft
3364 if Button = mbRight then // Right Mouse Button
3365 begin
3366 // Клик по мини-карте:
3367 if ShowMap and
3368 g_CollidePoint(X, Y,
3369 RenderPanel.Width-max(gMapInfo.Width div (16 div Scale), 1)-1,
3370 1,
3371 max(gMapInfo.Width div (16 div Scale), 1),
3372 max(gMapInfo.Height div (16 div Scale), 1) ) then
3373 begin
3374 MouseAction := MOUSEACTION_NOACTION;
3375 end
3376 else // Нужно что-то выбрать мышью:
3377 if SelectFlag <> SELECTFLAG_NONE then
3378 begin
3379 case SelectFlag of
3380 SELECTFLAG_TELEPORT:
3381 // Точку назначения телепортации:
3382 with gTriggers[SelectedObjects[
3383 GetFirstSelected() ].ID].Data.TargetPoint do
3384 begin
3385 X := MousePos.X-MapOffset.X;
3386 Y := MousePos.Y-MapOffset.Y;
3387 end;
3389 SELECTFLAG_SPAWNPOINT:
3390 // Точку создания монстра:
3391 with gTriggers[SelectedObjects[GetFirstSelected()].ID] do
3392 if TriggerType = TRIGGER_SPAWNMONSTER then
3393 begin
3394 Data.MonPos.X := MousePos.X-MapOffset.X;
3395 Data.MonPos.Y := MousePos.Y-MapOffset.Y;
3396 end
3397 else if TriggerType = TRIGGER_SPAWNITEM then
3398 begin // Точка создания предмета:
3399 Data.ItemPos.X := MousePos.X-MapOffset.X;
3400 Data.ItemPos.Y := MousePos.Y-MapOffset.Y;
3401 end
3402 else if TriggerType = TRIGGER_SHOT then
3403 begin // Точка создания выстрела:
3404 Data.ShotPos.X := MousePos.X-MapOffset.X;
3405 Data.ShotPos.Y := MousePos.Y-MapOffset.Y;
3406 end;
3408 SELECTFLAG_DOOR:
3409 // Дверь:
3410 begin
3411 IDArray := ObjectInRect(X-MapOffset.X,
3412 Y-MapOffset.Y,
3413 2, 2, OBJECT_PANEL, True);
3414 if IDArray <> nil then
3415 begin
3416 for i := 0 to High(IDArray) do
3417 if (gPanels[IDArray[i]].PanelType = PANEL_OPENDOOR) or
3418 (gPanels[IDArray[i]].PanelType = PANEL_CLOSEDOOR) then
3419 begin
3420 gTriggers[SelectedObjects[
3421 GetFirstSelected() ].ID].Data.PanelID := IDArray[i];
3422 Break;
3423 end;
3424 end
3425 else
3426 gTriggers[SelectedObjects[
3427 GetFirstSelected() ].ID].Data.PanelID := -1;
3428 end;
3430 SELECTFLAG_TEXTURE:
3431 // Панель с текстурой:
3432 begin
3433 IDArray := ObjectInRect(X-MapOffset.X,
3434 Y-MapOffset.Y,
3435 2, 2, OBJECT_PANEL, True);
3436 if IDArray <> nil then
3437 begin
3438 for i := 0 to High(IDArray) do
3439 if ((gPanels[IDArray[i]].PanelType in
3440 [PANEL_WALL, PANEL_BACK, PANEL_FORE,
3441 PANEL_WATER, PANEL_ACID1, PANEL_ACID2,
3442 PANEL_STEP]) or
3443 (gPanels[IDArray[i]].PanelType = PANEL_OPENDOOR) or
3444 (gPanels[IDArray[i]].PanelType = PANEL_CLOSEDOOR)) and
3445 (gPanels[IDArray[i]].TextureName <> '') then
3446 begin
3447 gTriggers[SelectedObjects[
3448 GetFirstSelected() ].ID].TexturePanel := IDArray[i];
3449 Break;
3450 end;
3451 end
3452 else
3453 gTriggers[SelectedObjects[
3454 GetFirstSelected() ].ID].TexturePanel := -1;
3455 end;
3457 SELECTFLAG_LIFT:
3458 // Лифт:
3459 begin
3460 IDArray := ObjectInRect(X-MapOffset.X,
3461 Y-MapOffset.Y,
3462 2, 2, OBJECT_PANEL, True);
3463 if IDArray <> nil then
3464 begin
3465 for i := 0 to High(IDArray) do
3466 if (gPanels[IDArray[i]].PanelType = PANEL_LIFTUP) or
3467 (gPanels[IDArray[i]].PanelType = PANEL_LIFTDOWN) or
3468 (gPanels[IDArray[i]].PanelType = PANEL_LIFTLEFT) or
3469 (gPanels[IDArray[i]].PanelType = PANEL_LIFTRIGHT) then
3470 begin
3471 gTriggers[SelectedObjects[
3472 GetFirstSelected() ].ID].Data.PanelID := IDArray[i];
3473 Break;
3474 end;
3475 end
3476 else
3477 gTriggers[SelectedObjects[
3478 GetFirstSelected() ].ID].Data.PanelID := -1;
3479 end;
3481 SELECTFLAG_MONSTER:
3482 // Монстра:
3483 begin
3484 IDArray := ObjectInRect(X-MapOffset.X,
3485 Y-MapOffset.Y,
3486 2, 2, OBJECT_MONSTER, False);
3487 if IDArray <> nil then
3488 gTriggers[SelectedObjects[
3489 GetFirstSelected() ].ID].Data.MonsterID := IDArray[0]+1
3490 else
3491 gTriggers[SelectedObjects[
3492 GetFirstSelected() ].ID].Data.MonsterID := 0;
3493 end;
3495 SELECTFLAG_SHOTPANEL:
3496 // Панель индикации выстрела:
3497 begin
3498 if gTriggers[SelectedObjects[
3499 GetFirstSelected() ].ID].TriggerType = TRIGGER_SHOT then
3500 begin
3501 IDArray := ObjectInRect(X-MapOffset.X,
3502 Y-MapOffset.Y,
3503 2, 2, OBJECT_PANEL, True);
3504 if IDArray <> nil then
3505 begin
3506 for i := 0 to High(IDArray) do
3507 if ((gPanels[IDArray[i]].PanelType in
3508 [PANEL_WALL, PANEL_BACK, PANEL_FORE,
3509 PANEL_WATER, PANEL_ACID1, PANEL_ACID2,
3510 PANEL_STEP]) or
3511 (gPanels[IDArray[i]].PanelType = PANEL_OPENDOOR) or
3512 (gPanels[IDArray[i]].PanelType = PANEL_CLOSEDOOR)) and
3513 (gPanels[IDArray[i]].TextureName <> '') then
3514 begin
3515 gTriggers[SelectedObjects[
3516 GetFirstSelected() ].ID].Data.ShotPanelID := IDArray[i];
3517 Break;
3518 end;
3519 end
3520 else
3521 gTriggers[SelectedObjects[
3522 GetFirstSelected() ].ID].Data.ShotPanelID := -1;
3523 end;
3524 end;
3525 end;
3527 SelectFlag := SELECTFLAG_SELECTED;
3528 end
3529 else // if SelectFlag <> SELECTFLAG_NONE...
3530 begin
3531 // Что уже выбрано и не нажат Ctrl:
3532 if (SelectedObjects <> nil) and
3533 (not (ssCtrl in Shift)) then
3534 for i := 0 to High(SelectedObjects) do
3535 with SelectedObjects[i] do
3536 if Live then
3537 begin
3538 if (ObjectType in [OBJECT_PANEL, OBJECT_TRIGGER]) and
3539 (SelectedObjectCount() = 1) then
3540 begin
3541 Rect := ObjectGetRect(ObjectType, ID);
3543 c1 := g_Collide(X-MapOffset.X-1, Y-MapOffset.Y-1, 2, 2,
3544 Rect.X-2, Rect.Y+(Rect.Height div 2)-2, 4, 4);
3545 c2 := g_Collide(X-MapOffset.X-1, Y-MapOffset.Y-1, 2, 2,
3546 Rect.X+Rect.Width-3, Rect.Y+(Rect.Height div 2)-2, 4, 4);
3547 c3 := g_Collide(X-MapOffset.X-1, Y-MapOffset.Y-1, 2, 2,
3548 Rect.X+(Rect.Width div 2)-2, Rect.Y-2, 4, 4);
3549 c4 := g_Collide(X-MapOffset.X-1, Y-MapOffset.Y-1, 2, 2,
3550 Rect.X+(Rect.Width div 2)-2, Rect.Y+Rect.Height-3, 4, 4);
3552 // Меняем размер панели или триггера:
3553 if c1 or c2 or c3 or c4 then
3554 begin
3555 MouseAction := MOUSEACTION_RESIZE;
3556 LastMovePoint := MousePos;
3558 if c1 or c2 then
3559 begin // Шире/уже
3560 ResizeType := RESIZETYPE_HORIZONTAL;
3561 if c1 then
3562 ResizeDirection := RESIZEDIR_LEFT
3563 else
3564 ResizeDirection := RESIZEDIR_RIGHT;
3565 RenderPanel.Cursor := crSizeWE;
3566 end
3567 else
3568 begin // Выше/ниже
3569 ResizeType := RESIZETYPE_VERTICAL;
3570 if c3 then
3571 ResizeDirection := RESIZEDIR_UP
3572 else
3573 ResizeDirection := RESIZEDIR_DOWN;
3574 RenderPanel.Cursor := crSizeNS;
3575 end;
3577 Break;
3578 end;
3579 end;
3581 // Перемещаем панель или триггер:
3582 if ObjectCollide(ObjectType, ID,
3583 X-MapOffset.X-1,
3584 Y-MapOffset.Y-1, 2, 2) then
3585 begin
3586 MouseAction := MOUSEACTION_MOVEOBJ;
3587 LastMovePoint := MousePos;
3589 Break;
3590 end;
3591 end;
3592 end;
3593 end; // if Button = mbRight
3595 MouseRDown := Button = mbRight;
3596 if MouseRDown then
3597 MouseRDownPos := MousePos;
3599 MouseLDown := Button = mbLeft;
3600 if MouseLDown then
3601 MouseLDownPos := MousePos;
3602 end;
3604 procedure TMainForm.RenderPanelMouseUp(Sender: TObject;
3605 Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
3606 var
3607 panel: TPanel;
3608 trigger: TTrigger;
3609 rRect: TRectWH;
3610 rSelectRect: Boolean;
3611 wWidth, wHeight: Word;
3612 TextureID: DWORD;
3614 procedure SelectObjects(ObjectType: Byte);
3615 var
3616 i: Integer;
3617 IDArray: DWArray;
3618 begin
3619 IDArray := ObjectInRect(rRect.X, rRect.Y,
3620 rRect.Width, rRect.Height,
3621 ObjectType, rSelectRect);
3623 if IDArray <> nil then
3624 for i := 0 to High(IDArray) do
3625 SelectObject(ObjectType, IDArray[i], (ssCtrl in Shift) or rSelectRect);
3626 end;
3627 begin
3628 if Button = mbLeft then
3629 MouseLDown := False;
3630 if Button = mbRight then
3631 MouseRDown := False;
3633 DrawRect := nil;
3634 ResizeType := RESIZETYPE_NONE;
3635 TextureID := 0;
3637 if Button = mbLeft then // Left Mouse Button
3638 begin
3639 if MouseAction <> MOUSEACTION_NONE then
3640 begin // Было действие мышью
3641 // Мышь сдвинулась во время удержания клавиши,
3642 // либо активирован режим быстрого рисования:
3643 if ((MousePos.X <> MouseLDownPos.X) and
3644 (MousePos.Y <> MouseLDownPos.Y)) or
3645 ((MouseAction in [MOUSEACTION_DRAWPANEL, MOUSEACTION_DRAWTRIGGER]) and
3646 (ssCtrl in Shift)) then
3647 case MouseAction of
3648 // Рисовали панель:
3649 MOUSEACTION_DRAWPANEL:
3650 begin
3651 // Фон или передний план без текстуры - ошибка:
3652 if (lbPanelType.ItemIndex in [1, 2]) and
3653 (lbTextureList.ItemIndex = -1) then
3654 ErrorMessageBox(_lc[I_MSG_CHOOSE_TEXTURE])
3655 else // Назначаем параметры панели:
3656 begin
3657 case lbPanelType.ItemIndex of
3658 0: Panel.PanelType := PANEL_WALL;
3659 1: Panel.PanelType := PANEL_BACK;
3660 2: Panel.PanelType := PANEL_FORE;
3661 3: Panel.PanelType := PANEL_OPENDOOR;
3662 4: Panel.PanelType := PANEL_CLOSEDOOR;
3663 5: Panel.PanelType := PANEL_STEP;
3664 6: Panel.PanelType := PANEL_WATER;
3665 7: Panel.PanelType := PANEL_ACID1;
3666 8: Panel.PanelType := PANEL_ACID2;
3667 9: Panel.PanelType := PANEL_LIFTUP;
3668 10: Panel.PanelType := PANEL_LIFTDOWN;
3669 11: Panel.PanelType := PANEL_LIFTLEFT;
3670 12: Panel.PanelType := PANEL_LIFTRIGHT;
3671 13: Panel.PanelType := PANEL_BLOCKMON;
3672 end;
3674 Panel.X := Min(MousePos.X-MapOffset.X, MouseLDownPos.X-MapOffset.X);
3675 Panel.Y := Min(MousePos.Y-MapOffset.Y, MouseLDownPos.Y-MapOffset.Y);
3676 if ssCtrl in Shift then
3677 begin
3678 wWidth := DotStep;
3679 wHeight := DotStep;
3680 if (lbTextureList.ItemIndex <> -1) and
3681 (not IsSpecialTextureSel()) then
3682 begin
3683 if not g_GetTexture(SelectedTexture(), TextureID) then
3684 g_GetTexture('NOTEXTURE', TextureID);
3685 g_GetTextureSizeByID(TextureID, wWidth, wHeight);
3686 end;
3687 Panel.Width := wWidth;
3688 Panel.Height := wHeight;
3689 end
3690 else
3691 begin
3692 Panel.Width := Abs(MousePos.X-MouseLDownPos.X);
3693 Panel.Height := Abs(MousePos.Y-MouseLDownPos.Y);
3694 end;
3696 // Лифты, блокМон или отсутствие текстуры - пустая текстура:
3697 if (lbPanelType.ItemIndex in [9, 10, 11, 12, 13]) or
3698 (lbTextureList.ItemIndex = -1) then
3699 begin
3700 Panel.TextureHeight := 1;
3701 Panel.TextureWidth := 1;
3702 Panel.TextureName := '';
3703 Panel.TextureID := TEXTURE_SPECIAL_NONE;
3704 end
3705 else // Есть текстура:
3706 begin
3707 Panel.TextureName := SelectedTexture();
3709 // Обычная текстура:
3710 if not IsSpecialTextureSel() then
3711 begin
3712 g_GetTextureSizeByName(Panel.TextureName,
3713 Panel.TextureWidth, Panel.TextureHeight);
3714 g_GetTexture(Panel.TextureName, Panel.TextureID);
3715 end
3716 else // Спец.текстура:
3717 begin
3718 Panel.TextureHeight := 1;
3719 Panel.TextureWidth := 1;
3720 Panel.TextureID := SpecialTextureID(SelectedTexture());
3721 end;
3722 end;
3724 Panel.Alpha := 0;
3725 Panel.Blending := False;
3727 Undo_Add(OBJECT_PANEL, AddPanel(Panel));
3728 end;
3729 end;
3731 // Рисовали триггер:
3732 MOUSEACTION_DRAWTRIGGER:
3733 begin
3734 trigger.X := Min(MousePos.X-MapOffset.X, MouseLDownPos.X-MapOffset.X);
3735 trigger.Y := Min(MousePos.Y-MapOffset.Y, MouseLDownPos.Y-MapOffset.Y);
3736 if ssCtrl in Shift then
3737 begin
3738 wWidth := DotStep;
3739 wHeight := DotStep;
3740 trigger.Width := wWidth;
3741 trigger.Height := wHeight;
3742 end
3743 else
3744 begin
3745 trigger.Width := Abs(MousePos.X-MouseLDownPos.X);
3746 trigger.Height := Abs(MousePos.Y-MouseLDownPos.Y);
3747 end;
3749 trigger.Enabled := True;
3750 trigger.TriggerType := lbTriggersList.ItemIndex+1;
3751 trigger.TexturePanel := -1;
3753 // Типы активации:
3754 trigger.ActivateType := 0;
3756 if clbActivationType.Checked[0] then
3757 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_PLAYERCOLLIDE;
3758 if clbActivationType.Checked[1] then
3759 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_MONSTERCOLLIDE;
3760 if clbActivationType.Checked[2] then
3761 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_PLAYERPRESS;
3762 if clbActivationType.Checked[3] then
3763 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_MONSTERPRESS;
3764 if clbActivationType.Checked[4] then
3765 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_SHOT;
3766 if clbActivationType.Checked[5] then
3767 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_NOMONSTER;
3769 // Необходимые для активации ключи:
3770 trigger.Key := 0;
3772 if clbKeys.Checked[0] then
3773 trigger.Key := Trigger.Key or KEY_RED;
3774 if clbKeys.Checked[1] then
3775 trigger.Key := Trigger.Key or KEY_GREEN;
3776 if clbKeys.Checked[2] then
3777 trigger.Key := Trigger.Key or KEY_BLUE;
3778 if clbKeys.Checked[3] then
3779 trigger.Key := Trigger.Key or KEY_REDTEAM;
3780 if clbKeys.Checked[4] then
3781 trigger.Key := Trigger.Key or KEY_BLUETEAM;
3783 // Параметры триггера:
3784 FillByte(trigger.Data.Default[0], 128, 0);
3786 case trigger.TriggerType of
3787 // Переключаемая панель:
3788 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
3789 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP,
3790 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
3791 begin
3792 Trigger.Data.PanelID := -1;
3793 end;
3795 // Телепортация:
3796 TRIGGER_TELEPORT:
3797 begin
3798 trigger.Data.TargetPoint.X := trigger.X-64;
3799 trigger.Data.TargetPoint.Y := trigger.Y-64;
3800 trigger.Data.d2d_teleport := True;
3801 trigger.Data.TlpDir := 0;
3802 end;
3804 // Изменение других триггеров:
3805 TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF,
3806 TRIGGER_ONOFF:
3807 begin
3808 trigger.Data.Count := 1;
3809 end;
3811 // Звук:
3812 TRIGGER_SOUND:
3813 begin
3814 trigger.Data.Volume := 255;
3815 trigger.Data.Pan := 127;
3816 trigger.Data.PlayCount := 1;
3817 trigger.Data.Local := True;
3818 trigger.Data.SoundSwitch := False;
3819 end;
3821 // Музыка:
3822 TRIGGER_MUSIC:
3823 begin
3824 trigger.Data.MusicAction := 1;
3825 end;
3827 // Создание монстра:
3828 TRIGGER_SPAWNMONSTER:
3829 begin
3830 trigger.Data.MonType := MONSTER_ZOMBY;
3831 trigger.Data.MonPos.X := trigger.X-64;
3832 trigger.Data.MonPos.Y := trigger.Y-64;
3833 trigger.Data.MonHealth := 0;
3834 trigger.Data.MonActive := False;
3835 trigger.Data.MonCount := 1;
3836 end;
3838 // Создание предмета:
3839 TRIGGER_SPAWNITEM:
3840 begin
3841 trigger.Data.ItemType := ITEM_AMMO_BULLETS;
3842 trigger.Data.ItemPos.X := trigger.X-64;
3843 trigger.Data.ItemPos.Y := trigger.Y-64;
3844 trigger.Data.ItemOnlyDM := False;
3845 trigger.Data.ItemFalls := False;
3846 trigger.Data.ItemCount := 1;
3847 trigger.Data.ItemMax := 0;
3848 trigger.Data.ItemDelay := 0;
3849 end;
3851 // Ускорение:
3852 TRIGGER_PUSH:
3853 begin
3854 trigger.Data.PushAngle := 90;
3855 trigger.Data.PushForce := 10;
3856 trigger.Data.ResetVel := True;
3857 end;
3859 TRIGGER_SCORE:
3860 begin
3861 trigger.Data.ScoreCount := 1;
3862 trigger.Data.ScoreCon := True;
3863 trigger.Data.ScoreMsg := True;
3864 end;
3866 TRIGGER_MESSAGE:
3867 begin
3868 trigger.Data.MessageKind := 0;
3869 trigger.Data.MessageSendTo := 0;
3870 trigger.Data.MessageText := '';
3871 trigger.Data.MessageTime := 144;
3872 end;
3874 TRIGGER_DAMAGE:
3875 begin
3876 trigger.Data.DamageValue := 5;
3877 trigger.Data.DamageInterval := 12;
3878 end;
3880 TRIGGER_HEALTH:
3881 begin
3882 trigger.Data.HealValue := 5;
3883 trigger.Data.HealInterval := 36;
3884 end;
3886 TRIGGER_SHOT:
3887 begin
3888 trigger.Data.ShotType := TRIGGER_SHOT_BULLET;
3889 trigger.Data.ShotSound := True;
3890 trigger.Data.ShotPanelID := -1;
3891 trigger.Data.ShotTarget := 0;
3892 trigger.Data.ShotIntSight := 0;
3893 trigger.Data.ShotAim := TRIGGER_SHOT_AIM_DEFAULT;
3894 trigger.Data.ShotPos.X := trigger.X-64;
3895 trigger.Data.ShotPos.Y := trigger.Y-64;
3896 trigger.Data.ShotAngle := 0;
3897 trigger.Data.ShotWait := 18;
3898 trigger.Data.ShotAccuracy := 0;
3899 trigger.Data.ShotAmmo := 0;
3900 trigger.Data.ShotIntReload := 0;
3901 end;
3903 TRIGGER_EFFECT:
3904 begin
3905 trigger.Data.FXCount := 1;
3906 trigger.Data.FXType := TRIGGER_EFFECT_PARTICLE;
3907 trigger.Data.FXSubType := TRIGGER_EFFECT_SLIQUID;
3908 trigger.Data.FXColorR := 0;
3909 trigger.Data.FXColorG := 0;
3910 trigger.Data.FXColorB := 255;
3911 trigger.Data.FXPos := TRIGGER_EFFECT_POS_CENTER;
3912 trigger.Data.FXWait := 1;
3913 trigger.Data.FXVelX := 0;
3914 trigger.Data.FXVelY := -20;
3915 trigger.Data.FXSpreadL := 5;
3916 trigger.Data.FXSpreadR := 5;
3917 trigger.Data.FXSpreadU := 4;
3918 trigger.Data.FXSpreadD := 0;
3919 end;
3920 end;
3922 Undo_Add(OBJECT_TRIGGER, AddTrigger(trigger));
3923 end;
3925 // Рисовали область триггера "Расширитель":
3926 MOUSEACTION_DRAWPRESS:
3927 with gTriggers[SelectedObjects[GetFirstSelected].ID] do
3928 begin
3929 Data.tX := Min(MousePos.X-MapOffset.X, MouseLDownPos.X-MapOffset.X);
3930 Data.tY := Min(MousePos.Y-MapOffset.Y, MouseLDownPos.Y-MapOffset.Y);
3931 Data.tWidth := Abs(MousePos.X-MouseLDownPos.X);
3932 Data.tHeight := Abs(MousePos.Y-MouseLDownPos.Y);
3934 DrawPressRect := False;
3935 end;
3936 end;
3938 MouseAction := MOUSEACTION_NONE;
3939 end;
3940 end // if Button = mbLeft...
3941 else // Right Mouse Button:
3942 begin
3943 if MouseAction = MOUSEACTION_NOACTION then
3944 begin
3945 MouseAction := MOUSEACTION_NONE;
3946 Exit;
3947 end;
3949 // Объект передвинут или изменен в размере:
3950 if MouseAction in [MOUSEACTION_MOVEOBJ, MOUSEACTION_RESIZE] then
3951 begin
3952 MouseAction := MOUSEACTION_NONE;
3953 FillProperty();
3954 Exit;
3955 end;
3957 // Еще не все выбрали:
3958 if SelectFlag <> SELECTFLAG_NONE then
3959 begin
3960 if SelectFlag = SELECTFLAG_SELECTED then
3961 SelectFlag := SELECTFLAG_NONE;
3962 FillProperty();
3963 Exit;
3964 end;
3966 // Мышь сдвинулась во время удержания клавиши:
3967 if (MousePos.X <> MouseRDownPos.X) and
3968 (MousePos.Y <> MouseRDownPos.Y) then
3969 begin
3970 rSelectRect := True;
3972 rRect.X := Min(MousePos.X, MouseRDownPos.X)-MapOffset.X;
3973 rRect.Y := Min(MousePos.Y, MouseRDownPos.Y)-MapOffset.Y;
3974 rRect.Width := Abs(MousePos.X-MouseRDownPos.X);
3975 rRect.Height := Abs(MousePos.Y-MouseRDownPos.Y);
3976 end
3977 else // Мышь не сдвинулась - нет прямоугольника:
3978 begin
3979 rSelectRect := False;
3981 rRect.X := X-MapOffset.X-1;
3982 rRect.Y := Y-MapOffset.Y-1;
3983 rRect.Width := 2;
3984 rRect.Height := 2;
3985 end;
3987 // Если зажат Ctrl - выделять еще, иначе только один выделенный объект:
3988 if not (ssCtrl in Shift) then
3989 RemoveSelectFromObjects();
3991 // Выделяем всё в выбранном прямоугольнике:
3992 if (ssCtrl in Shift) and (ssAlt in Shift) then
3993 begin
3994 SelectObjects(OBJECT_PANEL);
3995 SelectObjects(OBJECT_ITEM);
3996 SelectObjects(OBJECT_MONSTER);
3997 SelectObjects(OBJECT_AREA);
3998 SelectObjects(OBJECT_TRIGGER);
3999 end
4000 else
4001 SelectObjects(pcObjects.ActivePageIndex+1);
4003 FillProperty();
4004 end;
4005 end;
4007 procedure TMainForm.RenderPanelPaint(Sender: TObject);
4008 begin
4009 Draw();
4010 end;
4012 function TMainForm.RenderMousePos(): Types.TPoint;
4013 begin
4014 Result := RenderPanel.ScreenToClient(Mouse.CursorPos);
4015 end;
4017 procedure TMainForm.RecountSelectedObjects();
4018 begin
4019 if SelectedObjectCount() = 0 then
4020 StatusBar.Panels[0].Text := ''
4021 else
4022 StatusBar.Panels[0].Text := Format(_lc[I_CAP_STAT_SELECTED], [SelectedObjectCount()]);
4023 end;
4025 procedure TMainForm.RenderPanelMouseMove(Sender: TObject;
4026 Shift: TShiftState; X, Y: Integer);
4027 var
4028 sX, sY: Integer;
4029 dWidth, dHeight: Integer;
4030 _id: Integer;
4031 TextureID: DWORD;
4032 wWidth, wHeight: Word;
4033 begin
4034 _id := GetFirstSelected();
4035 TextureID := 0;
4037 // Рисуем панель с текстурой, сетка - размеры текстуры:
4038 if (MouseAction = MOUSEACTION_DRAWPANEL) and
4039 (lbPanelType.ItemIndex in [0..8]) and
4040 (lbTextureList.ItemIndex <> -1) and
4041 (not IsSpecialTextureSel()) then
4042 begin
4043 sX := StrToIntDef(lTextureWidth.Caption, DotStep);
4044 sY := StrToIntDef(lTextureHeight.Caption, DotStep);
4045 end
4046 else
4047 // Меняем размер панели с текстурой, сетка - размеры текстуры:
4048 if (MouseAction = MOUSEACTION_RESIZE) and
4049 ( (SelectedObjects[_id].ObjectType = OBJECT_PANEL) and
4050 IsTexturedPanel(gPanels[SelectedObjects[_id].ID].PanelType) and
4051 (gPanels[SelectedObjects[_id].ID].TextureName <> '') and
4052 (not IsSpecialTexture(gPanels[SelectedObjects[_id].ID].TextureName)) ) then
4053 begin
4054 sX := gPanels[SelectedObjects[_id].ID].TextureWidth;
4055 sY := gPanels[SelectedObjects[_id].ID].TextureHeight;
4056 end
4057 else
4058 // Выравнивание по сетке:
4059 if SnapToGrid then
4060 begin
4061 sX := DotStep;
4062 sY := DotStep;
4063 end
4064 else // Нет выравнивания по сетке:
4065 begin
4066 sX := 1;
4067 sY := 1;
4068 end;
4070 // Новая позиция мыши:
4071 if MouseLDown then
4072 begin // Зажата левая кнопка мыши
4073 MousePos.X := (Round((X-MouseLDownPos.X)/sX)*sX)+MouseLDownPos.X;
4074 MousePos.Y := (Round((Y-MouseLDownPos.Y)/sY)*sY)+MouseLDownPos.Y;
4075 end
4076 else
4077 if MouseRDown then
4078 begin // Зажата правая кнопка мыши
4079 MousePos.X := (Round((X-MouseRDownPos.X)/sX)*sX)+MouseRDownPos.X;
4080 MousePos.Y := (Round((Y-MouseRDownPos.Y)/sY)*sY)+MouseRDownPos.Y;
4081 end
4082 else
4083 begin // Кнопки мыши не зажаты
4084 MousePos.X := (Round(X/sX)*sX);
4085 MousePos.Y := (Round(Y/sY)*sY);
4086 end;
4088 // Изменение размера закончилось - ставим обычный курсор:
4089 if ResizeType = RESIZETYPE_NONE then
4090 RenderPanel.Cursor := crDefault;
4092 // Зажата только правая кнопка мыши:
4093 if (not MouseLDown) and (MouseRDown) then
4094 begin
4095 // Рисуем прямоугольник выделения:
4096 if MouseAction = MOUSEACTION_NONE then
4097 begin
4098 if DrawRect = nil then
4099 New(DrawRect);
4100 DrawRect.Top := MouseRDownPos.y;
4101 DrawRect.Left := MouseRDownPos.x;
4102 DrawRect.Bottom := MousePos.y;
4103 DrawRect.Right := MousePos.x;
4104 end
4105 else
4106 // Двигаем выделенные объекты:
4107 if MouseAction = MOUSEACTION_MOVEOBJ then
4108 begin
4109 MoveSelectedObjects(ssShift in Shift, ssCtrl in Shift,
4110 MousePos.X-LastMovePoint.X,
4111 MousePos.Y-LastMovePoint.Y);
4112 end
4113 else
4114 // Меняем размер выделенного объекта:
4115 if MouseAction = MOUSEACTION_RESIZE then
4116 begin
4117 if (SelectedObjectCount = 1) and
4118 (SelectedObjects[GetFirstSelected].Live) then
4119 begin
4120 dWidth := MousePos.X-LastMovePoint.X;
4121 dHeight := MousePos.Y-LastMovePoint.Y;
4123 case ResizeType of
4124 RESIZETYPE_VERTICAL: dWidth := 0;
4125 RESIZETYPE_HORIZONTAL: dHeight := 0;
4126 end;
4128 case ResizeDirection of
4129 RESIZEDIR_UP: dHeight := -dHeight;
4130 RESIZEDIR_LEFT: dWidth := -dWidth;
4131 end;
4133 if ResizeObject(SelectedObjects[GetFirstSelected].ObjectType,
4134 SelectedObjects[GetFirstSelected].ID,
4135 dWidth, dHeight, ResizeDirection) then
4136 LastMovePoint := MousePos;
4137 end;
4138 end;
4139 end;
4141 // Зажата только левая кнопка мыши:
4142 if (not MouseRDown) and (MouseLDown) then
4143 begin
4144 // Рисуем прямоугольник планирования панели:
4145 if MouseAction in [MOUSEACTION_DRAWPANEL,
4146 MOUSEACTION_DRAWTRIGGER,
4147 MOUSEACTION_DRAWPRESS] then
4148 begin
4149 if DrawRect = nil then
4150 New(DrawRect);
4151 if ssCtrl in Shift then
4152 begin
4153 wWidth := DotStep;
4154 wHeight := DotStep;
4155 if (lbTextureList.ItemIndex <> -1) and (not IsSpecialTextureSel()) and
4156 (MouseAction = MOUSEACTION_DRAWPANEL) then
4157 begin
4158 if not g_GetTexture(SelectedTexture(), TextureID) then
4159 g_GetTexture('NOTEXTURE', TextureID);
4160 g_GetTextureSizeByID(TextureID, wWidth, wHeight);
4161 end;
4162 DrawRect.Top := MouseLDownPos.y;
4163 DrawRect.Left := MouseLDownPos.x;
4164 DrawRect.Bottom := DrawRect.Top + wHeight;
4165 DrawRect.Right := DrawRect.Left + wWidth;
4166 end
4167 else
4168 begin
4169 DrawRect.Top := MouseLDownPos.y;
4170 DrawRect.Left := MouseLDownPos.x;
4171 DrawRect.Bottom := MousePos.y;
4172 DrawRect.Right := MousePos.x;
4173 end;
4174 end
4175 else // Двигаем карту:
4176 if MouseAction = MOUSEACTION_MOVEMAP then
4177 begin
4178 MoveMap(X, Y);
4179 end;
4180 end;
4182 // Клавиши мыши не зажаты:
4183 if (not MouseRDown) and (not MouseLDown) then
4184 DrawRect := nil;
4186 // Строка состояния - координаты мыши:
4187 StatusBar.Panels[1].Text := Format('(%d:%d)',
4188 [MousePos.X-MapOffset.X, MousePos.Y-MapOffset.Y]);
4189 end;
4191 procedure TMainForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
4192 begin
4193 CanClose := MessageBox(0, PChar(_lc[I_MSG_EXIT_PROMT]),
4194 PChar(_lc[I_MSG_EXIT]),
4195 MB_ICONQUESTION or MB_YESNO or
4196 MB_DEFBUTTON1) = idYes;
4197 end;
4199 procedure TMainForm.aExitExecute(Sender: TObject);
4200 begin
4201 Close();
4202 end;
4204 procedure TMainForm.FormDestroy(Sender: TObject);
4205 var
4206 config: TConfig;
4207 i: Integer;
4208 begin
4209 config := TConfig.CreateFile(EditorDir+'Editor.cfg');
4211 if WindowState <> wsMaximized then
4212 begin
4213 config.WriteInt('Editor', 'XPos', Left);
4214 config.WriteInt('Editor', 'YPos', Top);
4215 config.WriteInt('Editor', 'Width', Width);
4216 config.WriteInt('Editor', 'Height', Height);
4217 end
4218 else
4219 begin
4220 config.WriteInt('Editor', 'XPos', RestoredLeft);
4221 config.WriteInt('Editor', 'YPos', RestoredTop);
4222 config.WriteInt('Editor', 'Width', RestoredWidth);
4223 config.WriteInt('Editor', 'Height', RestoredHeight);
4224 end;
4225 config.WriteBool('Editor', 'Maximize', WindowState = wsMaximized);
4226 config.WriteBool('Editor', 'Minimap', ShowMap);
4227 config.WriteInt('Editor', 'PanelProps', PanelProps.ClientWidth);
4228 config.WriteInt('Editor', 'PanelObjs', PanelObjs.ClientHeight);
4229 config.WriteBool('Editor', 'DotEnable', DotEnable);
4230 config.WriteInt('Editor', 'DotStep', DotStep);
4231 config.WriteStr('Editor', 'LastOpenDir', OpenDialog.InitialDir);
4232 config.WriteStr('Editor', 'LastSaveDir', SaveDialog.InitialDir);
4233 config.WriteBool('Editor', 'EdgeShow', drEdge[3] < 255);
4234 config.WriteInt('Editor', 'EdgeColor', gColorEdge);
4235 config.WriteInt('Editor', 'EdgeAlpha', gAlphaEdge);
4236 config.WriteInt('Editor', 'LineAlpha', gAlphaTriggerLine);
4237 config.WriteInt('Editor', 'TriggerAlpha', gAlphaTriggerArea);
4238 config.WriteInt('Editor', 'MonsterRectAlpha', gAlphaMonsterRect);
4239 config.WriteInt('Editor', 'AreaRectAlpha', gAlphaAreaRect);
4241 for i := 0 to RecentCount-1 do
4242 if i < RecentFiles.Count then
4243 config.WriteStr('RecentFiles', IntToStr(i+1), RecentFiles[i])
4244 else
4245 config.WriteStr('RecentFiles', IntToStr(i+1), '');
4246 RecentFiles.Free();
4248 config.SaveFile(EditorDir+'Editor.cfg');
4249 config.Free();
4251 slInvalidTextures.Free;
4252 end;
4254 procedure TMainForm.FormDropFiles(Sender: TObject;
4255 const FileNames: array of String);
4256 begin
4257 if Length(FileNames) <> 1 then
4258 Exit;
4260 OpenMapFile(FileNames[0]);
4261 end;
4263 procedure TMainForm.RenderPanelResize(Sender: TObject);
4264 begin
4265 if MainForm.Visible then
4266 MainForm.Resize();
4267 end;
4269 procedure TMainForm.Splitter1Moved(Sender: TObject);
4270 begin
4271 FormResize(Sender);
4272 end;
4274 procedure TMainForm.aMapOptionsExecute(Sender: TObject);
4275 var
4276 ResName: String;
4277 begin
4278 MapOptionsForm.ShowModal();
4280 ResName := OpenedMap;
4281 while (Pos(':\', ResName) > 0) do
4282 Delete(ResName, 1, Pos(':\', ResName) + 1);
4284 UpdateCaption(gMapInfo.Name, ExtractFileName(OpenedWAD), ResName);
4285 end;
4287 procedure TMainForm.aAboutExecute(Sender: TObject);
4288 begin
4289 AboutForm.ShowModal();
4290 end;
4292 procedure TMainForm.FormKeyDown(Sender: TObject; var Key: Word;
4293 Shift: TShiftState);
4294 var
4295 dx, dy, i: Integer;
4296 FileName: String;
4297 begin
4298 if (not EditingProperties) then
4299 begin
4300 if Key = Ord('1') then
4301 SwitchLayer(LAYER_BACK);
4302 if Key = Ord('2') then
4303 SwitchLayer(LAYER_WALLS);
4304 if Key = Ord('3') then
4305 SwitchLayer(LAYER_FOREGROUND);
4306 if Key = Ord('4') then
4307 SwitchLayer(LAYER_STEPS);
4308 if Key = Ord('5') then
4309 SwitchLayer(LAYER_WATER);
4310 if Key = Ord('6') then
4311 SwitchLayer(LAYER_ITEMS);
4312 if Key = Ord('7') then
4313 SwitchLayer(LAYER_MONSTERS);
4314 if Key = Ord('8') then
4315 SwitchLayer(LAYER_AREAS);
4316 if Key = Ord('9') then
4317 SwitchLayer(LAYER_TRIGGERS);
4318 if Key = Ord('0') then
4319 tbShowClick(tbShow);
4321 if Key = Ord('V') then
4322 begin // Поворот монстров и областей:
4323 if (SelectedObjects <> nil) then
4324 begin
4325 for i := 0 to High(SelectedObjects) do
4326 if (SelectedObjects[i].Live) then
4327 begin
4328 if (SelectedObjects[i].ObjectType = OBJECT_MONSTER) then
4329 begin
4330 g_ChangeDir(gMonsters[SelectedObjects[i].ID].Direction);
4331 end
4332 else
4333 if (SelectedObjects[i].ObjectType = OBJECT_AREA) then
4334 begin
4335 g_ChangeDir(gAreas[SelectedObjects[i].ID].Direction);
4336 end;
4337 end;
4338 end
4339 else
4340 begin
4341 if pcObjects.ActivePage = tsMonsters then
4342 begin
4343 if rbMonsterLeft.Checked then
4344 rbMonsterRight.Checked := True
4345 else
4346 rbMonsterLeft.Checked := True;
4347 end;
4348 if pcObjects.ActivePage = tsAreas then
4349 begin
4350 if rbAreaLeft.Checked then
4351 rbAreaRight.Checked := True
4352 else
4353 rbAreaLeft.Checked := True;
4354 end;
4355 end;
4356 end;
4358 if not (ssCtrl in Shift) then
4359 begin
4360 // Быстрое превью карты:
4361 if Key = Ord('E') then
4362 begin
4363 if PreviewMode = 0 then
4364 PreviewMode := 2;
4365 end;
4367 // Вертикальный скролл карты:
4368 with sbVertical do
4369 begin
4370 if Key = Ord('W') then
4371 begin
4372 if (MouseLDown or MouseRDown) and (Position >= DotStep) then
4373 begin
4374 if DrawRect <> nil then
4375 begin
4376 Inc(MouseLDownPos.y, DotStep);
4377 Inc(MouseRDownPos.y, DotStep);
4378 end;
4379 Inc(LastMovePoint.Y, DotStep);
4380 RenderPanelMouseMove(Sender, Shift, RenderMousePos().X, RenderMousePos().Y);
4381 end;
4382 Position := IfThen(Position > DotStep, Position-DotStep, 0);
4383 MapOffset.Y := -Round(Position/16) * 16;
4384 end;
4386 if Key = Ord('S') then
4387 begin
4388 if (MouseLDown or MouseRDown) and (Position+DotStep <= Max) then
4389 begin
4390 if DrawRect <> nil then
4391 begin
4392 Dec(MouseLDownPos.y, DotStep);
4393 Dec(MouseRDownPos.y, DotStep);
4394 end;
4395 Dec(LastMovePoint.Y, DotStep);
4396 RenderPanelMouseMove(Sender, Shift, RenderMousePos().X, RenderMousePos().Y);
4397 end;
4398 Position := IfThen(Position+DotStep < Max, Position+DotStep, Max);
4399 MapOffset.Y := -Round(Position/16) * 16;
4400 end;
4401 end;
4403 // Горизонтальный скролл карты:
4404 with sbHorizontal do
4405 begin
4406 if Key = Ord('A') then
4407 begin
4408 if (MouseLDown or MouseRDown) and (Position >= DotStep) then
4409 begin
4410 if DrawRect <> nil then
4411 begin
4412 Inc(MouseLDownPos.x, DotStep);
4413 Inc(MouseRDownPos.x, DotStep);
4414 end;
4415 Inc(LastMovePoint.X, DotStep);
4416 RenderPanelMouseMove(Sender, Shift, RenderMousePos().X, RenderMousePos().Y);
4417 end;
4418 Position := IfThen(Position > DotStep, Position-DotStep, 0);
4419 MapOffset.X := -Round(Position/16) * 16;
4420 end;
4422 if Key = Ord('D') then
4423 begin
4424 if (MouseLDown or MouseRDown) and (Position+DotStep <= Max) then
4425 begin
4426 if DrawRect <> nil then
4427 begin
4428 Dec(MouseLDownPos.x, DotStep);
4429 Dec(MouseRDownPos.x, DotStep);
4430 end;
4431 Dec(LastMovePoint.X, DotStep);
4432 RenderPanelMouseMove(Sender, Shift, RenderMousePos().X, RenderMousePos().Y);
4433 end;
4434 Position := IfThen(Position+DotStep < Max, Position+DotStep, Max);
4435 MapOffset.X := -Round(Position/16) * 16;
4436 end;
4437 end;
4438 end
4439 else // ssCtrl in Shift
4440 begin
4441 if ssShift in Shift then
4442 begin
4443 // Вставка по абсолютному смещению:
4444 if Key = Ord('V') then
4445 aPasteObjectExecute(Sender);
4446 end;
4447 RenderPanelMouseMove(Sender, Shift, RenderMousePos().X, RenderMousePos().Y);
4448 end;
4449 end;
4451 // Удалить выделенные объекты:
4452 if (Key = VK_DELETE) and (SelectedObjects <> nil) and
4453 RenderPanel.Focused() then
4454 DeleteSelectedObjects();
4456 // Снять выделение:
4457 if (Key = VK_ESCAPE) and (SelectedObjects <> nil) then
4458 RemoveSelectFromObjects();
4460 // Передвинуть объекты:
4461 if MainForm.ActiveControl = RenderPanel then
4462 begin
4463 dx := 0;
4464 dy := 0;
4466 if Key = VK_NUMPAD4 then
4467 dx := IfThen(ssAlt in Shift, -1, -DotStep);
4468 if Key = VK_NUMPAD6 then
4469 dx := IfThen(ssAlt in Shift, 1, DotStep);
4470 if Key = VK_NUMPAD8 then
4471 dy := IfThen(ssAlt in Shift, -1, -DotStep);
4472 if Key = VK_NUMPAD5 then
4473 dy := IfThen(ssAlt in Shift, 1, DotStep);
4475 if (dx <> 0) or (dy <> 0) then
4476 begin
4477 MoveSelectedObjects(ssShift in Shift, ssCtrl in Shift, dx, dy);
4478 Key := 0;
4479 end;
4480 end;
4482 if ssCtrl in Shift then
4483 begin
4484 // Выбор панели с текстурой для триггера
4485 if Key = Ord('T') then
4486 begin
4487 DrawPressRect := False;
4488 if SelectFlag = SELECTFLAG_TEXTURE then
4489 begin
4490 SelectFlag := SELECTFLAG_NONE;
4491 Exit;
4492 end;
4493 vleObjectProperty.FindRow(_lc[I_PROP_TR_TEXTURE_PANEL], i);
4494 if i > 0 then
4495 SelectFlag := SELECTFLAG_TEXTURE;
4496 end;
4498 if Key = Ord('D') then
4499 begin
4500 SelectFlag := SELECTFLAG_NONE;
4501 if DrawPressRect then
4502 begin
4503 DrawPressRect := False;
4504 Exit;
4505 end;
4506 i := -1;
4508 // Выбор области воздействия, в зависимости от типа триггера
4509 vleObjectProperty.FindRow(_lc[I_PROP_TR_EX_AREA], i);
4510 if i > 0 then
4511 begin
4512 DrawPressRect := True;
4513 Exit;
4514 end;
4515 vleObjectProperty.FindRow(_lc[I_PROP_TR_DOOR_PANEL], i);
4516 if i <= 0 then
4517 vleObjectProperty.FindRow(_lc[I_PROP_TR_TRAP_PANEL], i);
4518 if i > 0 then
4519 begin
4520 SelectFlag := SELECTFLAG_DOOR;
4521 Exit;
4522 end;
4523 vleObjectProperty.FindRow(_lc[I_PROP_TR_LIFT_PANEL], i);
4524 if i > 0 then
4525 begin
4526 SelectFlag := SELECTFLAG_LIFT;
4527 Exit;
4528 end;
4529 vleObjectProperty.FindRow(_lc[I_PROP_TR_TELEPORT_TO], i);
4530 if i > 0 then
4531 begin
4532 SelectFlag := SELECTFLAG_TELEPORT;
4533 Exit;
4534 end;
4535 vleObjectProperty.FindRow(_lc[I_PROP_TR_SPAWN_TO], i);
4536 if i > 0 then
4537 begin
4538 SelectFlag := SELECTFLAG_SPAWNPOINT;
4539 Exit;
4540 end;
4542 // Выбор основного параметра, в зависимости от типа триггера
4543 vleObjectProperty.FindRow(_lc[I_PROP_TR_NEXT_MAP], i);
4544 if i > 0 then
4545 begin
4546 g_ProcessResourceStr(OpenedMap, @FileName, nil, nil);
4547 SelectMapForm.Caption := _lc[I_CAP_SELECT];
4548 SelectMapForm.GetMaps(FileName);
4550 if SelectMapForm.ShowModal() = mrOK then
4551 begin
4552 vleObjectProperty.Cells[1, i] := SelectMapForm.lbMapList.Items[SelectMapForm.lbMapList.ItemIndex];
4553 bApplyProperty.Click();
4554 end;
4555 Exit;
4556 end;
4557 vleObjectProperty.FindRow(_lc[I_PROP_TR_SOUND_NAME], i);
4558 if i <= 0 then
4559 vleObjectProperty.FindRow(_lc[I_PROP_TR_MUSIC_NAME], i);
4560 if i > 0 then
4561 begin
4562 AddSoundForm.OKFunction := nil;
4563 AddSoundForm.lbResourcesList.MultiSelect := False;
4564 AddSoundForm.SetResource := vleObjectProperty.Cells[1, i];
4566 if (AddSoundForm.ShowModal() = mrOk) then
4567 begin
4568 vleObjectProperty.Cells[1, i] := AddSoundForm.ResourceName;
4569 bApplyProperty.Click();
4570 end;
4571 Exit;
4572 end;
4573 vleObjectProperty.FindRow(_lc[I_PROP_TR_PUSH_ANGLE], i);
4574 if i <= 0 then
4575 vleObjectProperty.FindRow(_lc[I_PROP_TR_MESSAGE_TEXT], i);
4576 if i > 0 then
4577 begin
4578 vleObjectProperty.Row := i;
4579 vleObjectProperty.SetFocus();
4580 Exit;
4581 end;
4582 end;
4583 end;
4584 end;
4586 procedure TMainForm.aOptimizeExecute(Sender: TObject);
4587 begin
4588 RemoveSelectFromObjects();
4589 MapOptimizationForm.ShowModal();
4590 end;
4592 procedure TMainForm.aCheckMapExecute(Sender: TObject);
4593 begin
4594 MapCheckForm.ShowModal();
4595 end;
4597 procedure TMainForm.bbAddTextureClick(Sender: TObject);
4598 begin
4599 AddTextureForm.lbResourcesList.MultiSelect := True;
4600 AddTextureForm.ShowModal();
4601 end;
4603 procedure TMainForm.lbTextureListClick(Sender: TObject);
4604 var
4605 TextureID: DWORD;
4606 TextureWidth, TextureHeight: Word;
4607 begin
4608 TextureID := 0;
4609 TextureWidth := 0;
4610 TextureHeight := 0;
4611 if (lbTextureList.ItemIndex <> -1) and
4612 (not IsSpecialTextureSel()) then
4613 begin
4614 if g_GetTexture(SelectedTexture(), TextureID) then
4615 begin
4616 g_GetTextureSizeByID(TextureID, TextureWidth, TextureHeight);
4618 lTextureWidth.Caption := IntToStr(TextureWidth);
4619 lTextureHeight.Caption := IntToStr(TextureHeight);
4620 end else
4621 begin
4622 lTextureWidth.Caption := _lc[I_NOT_ACCESSIBLE];
4623 lTextureHeight.Caption := _lc[I_NOT_ACCESSIBLE];
4624 end;
4625 end
4626 else
4627 begin
4628 lTextureWidth.Caption := '';
4629 lTextureHeight.Caption := '';
4630 end;
4631 end;
4633 procedure TMainForm.lbTextureListDrawItem(Control: TWinControl; Index: Integer;
4634 ARect: TRect; State: TOwnerDrawState);
4635 begin
4636 with Control as TListBox do
4637 begin
4638 if LCLType.odSelected in State then
4639 begin
4640 Canvas.Brush.Color := clHighlight;
4641 Canvas.Font.Color := clHighlightText;
4642 end else
4643 if (Items <> nil) and (Index >= 0) then
4644 if slInvalidTextures.IndexOf(Items[Index]) > -1 then
4645 begin
4646 Canvas.Brush.Color := clRed;
4647 Canvas.Font.Color := clWhite;
4648 end;
4649 Canvas.FillRect(ARect);
4650 Canvas.TextRect(ARect, ARect.Left, ARect.Top, Items[Index]);
4651 end;
4652 end;
4654 procedure TMainForm.miReopenMapClick(Sender: TObject);
4655 var
4656 FileName, Resource: String;
4657 begin
4658 if OpenedMap = '' then
4659 Exit;
4661 if MessageBox(0, PChar(_lc[I_MSG_REOPEN_MAP_PROMT]),
4662 PChar(_lc[I_MENU_FILE_REOPEN]), MB_ICONQUESTION or MB_YESNO) <> idYes then
4663 Exit;
4665 g_ProcessResourceStr(OpenedMap, @FileName, nil, @Resource);
4666 OpenMap(FileName, Resource);
4667 end;
4669 procedure TMainForm.vleObjectPropertyGetPickList(Sender: TObject;
4670 const KeyName: String; Values: TStrings);
4671 begin
4672 if vleObjectProperty.ItemProps[KeyName].EditStyle = esPickList then
4673 begin
4674 if KeyName = _lc[I_PROP_DIRECTION] then
4675 begin
4676 Values.Add(DirNames[D_LEFT]);
4677 Values.Add(DirNames[D_RIGHT]);
4678 end
4679 else if KeyName = _lc[I_PROP_TR_TELEPORT_DIR] then
4680 begin
4681 Values.Add(DirNamesAdv[0]);
4682 Values.Add(DirNamesAdv[1]);
4683 Values.Add(DirNamesAdv[2]);
4684 Values.Add(DirNamesAdv[3]);
4685 end
4686 else if KeyName = _lc[I_PROP_TR_MUSIC_ACT] then
4687 begin
4688 Values.Add(_lc[I_PROP_TR_MUSIC_ON]);
4689 Values.Add(_lc[I_PROP_TR_MUSIC_OFF]);
4690 end
4691 else if KeyName = _lc[I_PROP_TR_MONSTER_BEHAVIOUR] then
4692 begin
4693 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_0]);
4694 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_1]);
4695 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_2]);
4696 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_3]);
4697 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_4]);
4698 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_5]);
4699 end
4700 else if KeyName = _lc[I_PROP_TR_SCORE_ACT] then
4701 begin
4702 Values.Add(_lc[I_PROP_TR_SCORE_ACT_0]);
4703 Values.Add(_lc[I_PROP_TR_SCORE_ACT_1]);
4704 Values.Add(_lc[I_PROP_TR_SCORE_ACT_2]);
4705 Values.Add(_lc[I_PROP_TR_SCORE_ACT_3]);
4706 end
4707 else if KeyName = _lc[I_PROP_TR_SCORE_TEAM] then
4708 begin
4709 Values.Add(_lc[I_PROP_TR_SCORE_TEAM_0]);
4710 Values.Add(_lc[I_PROP_TR_SCORE_TEAM_1]);
4711 Values.Add(_lc[I_PROP_TR_SCORE_TEAM_2]);
4712 Values.Add(_lc[I_PROP_TR_SCORE_TEAM_3]);
4713 end
4714 else if KeyName = _lc[I_PROP_TR_MESSAGE_KIND] then
4715 begin
4716 Values.Add(_lc[I_PROP_TR_MESSAGE_KIND_0]);
4717 Values.Add(_lc[I_PROP_TR_MESSAGE_KIND_1]);
4718 end
4719 else if KeyName = _lc[I_PROP_TR_MESSAGE_TO] then
4720 begin
4721 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_0]);
4722 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_1]);
4723 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_2]);
4724 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_3]);
4725 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_4]);
4726 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_5]);
4727 end
4728 else if KeyName = _lc[I_PROP_TR_SHOT_TO] then
4729 begin
4730 Values.Add(_lc[I_PROP_TR_SHOT_TO_0]);
4731 Values.Add(_lc[I_PROP_TR_SHOT_TO_1]);
4732 Values.Add(_lc[I_PROP_TR_SHOT_TO_2]);
4733 Values.Add(_lc[I_PROP_TR_SHOT_TO_3]);
4734 Values.Add(_lc[I_PROP_TR_SHOT_TO_4]);
4735 Values.Add(_lc[I_PROP_TR_SHOT_TO_5]);
4736 Values.Add(_lc[I_PROP_TR_SHOT_TO_6]);
4737 end
4738 else if KeyName = _lc[I_PROP_TR_SHOT_AIM] then
4739 begin
4740 Values.Add(_lc[I_PROP_TR_SHOT_AIM_0]);
4741 Values.Add(_lc[I_PROP_TR_SHOT_AIM_1]);
4742 Values.Add(_lc[I_PROP_TR_SHOT_AIM_2]);
4743 Values.Add(_lc[I_PROP_TR_SHOT_AIM_3]);
4744 end
4745 else if (KeyName = _lc[I_PROP_PANEL_BLEND]) or
4746 (KeyName = _lc[I_PROP_DM_ONLY]) or
4747 (KeyName = _lc[I_PROP_ITEM_FALLS]) or
4748 (KeyName = _lc[I_PROP_TR_ENABLED]) or
4749 (KeyName = _lc[I_PROP_TR_D2D]) or
4750 (KeyName = _lc[I_PROP_TR_SILENT]) or
4751 (KeyName = _lc[I_PROP_TR_TELEPORT_SILENT]) or
4752 (KeyName = _lc[I_PROP_TR_EX_RANDOM]) or
4753 (KeyName = _lc[I_PROP_TR_TEXTURE_ONCE]) or
4754 (KeyName = _lc[I_PROP_TR_TEXTURE_ANIM_ONCE]) or
4755 (KeyName = _lc[I_PROP_TR_SOUND_LOCAL]) or
4756 (KeyName = _lc[I_PROP_TR_SOUND_SWITCH]) or
4757 (KeyName = _lc[I_PROP_TR_MONSTER_ACTIVE]) or
4758 (KeyName = _lc[I_PROP_TR_PUSH_RESET]) or
4759 (KeyName = _lc[I_PROP_TR_SCORE_CON]) or
4760 (KeyName = _lc[I_PROP_TR_SCORE_MSG]) or
4761 (KeyName = _lc[I_PROP_TR_HEALTH_MAX]) or
4762 (KeyName = _lc[I_PROP_TR_SHOT_SOUND]) or
4763 (KeyName = _lc[I_PROP_TR_EFFECT_CENTER]) then
4764 begin
4765 Values.Add(BoolNames[True]);
4766 Values.Add(BoolNames[False]);
4767 end;
4768 end;
4769 end;
4771 procedure TMainForm.bApplyPropertyClick(Sender: TObject);
4772 var
4773 _id, a, r, c: Integer;
4774 s: String;
4775 res: Boolean;
4776 NoTextureID: DWORD;
4777 NW, NH: Word;
4778 begin
4779 NoTextureID := 0;
4780 NW := 0;
4781 NH := 0;
4783 if SelectedObjectCount() <> 1 then
4784 Exit;
4785 if not SelectedObjects[GetFirstSelected()].Live then
4786 Exit;
4788 try
4789 if not CheckProperty() then
4790 Exit;
4791 except
4792 Exit;
4793 end;
4795 _id := GetFirstSelected();
4797 r := vleObjectProperty.Row;
4798 c := vleObjectProperty.Col;
4800 case SelectedObjects[_id].ObjectType of
4801 OBJECT_PANEL:
4802 begin
4803 with gPanels[SelectedObjects[_id].ID] do
4804 begin
4805 X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
4806 Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
4807 Width := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_WIDTH]]));
4808 Height := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_HEIGHT]]));
4810 PanelType := GetPanelType(vleObjectProperty.Values[_lc[I_PROP_PANEL_TYPE]]);
4812 // Сброс ссылки на триггеры смены текстуры:
4813 if not WordBool(PanelType and (PANEL_WALL or PANEL_FORE or PANEL_BACK)) then
4814 if gTriggers <> nil then
4815 for a := 0 to High(gTriggers) do
4816 begin
4817 if (gTriggers[a].TriggerType <> 0) and
4818 (gTriggers[a].TexturePanel = Integer(SelectedObjects[_id].ID)) then
4819 gTriggers[a].TexturePanel := -1;
4820 if (gTriggers[a].TriggerType = TRIGGER_SHOT) and
4821 (gTriggers[a].Data.ShotPanelID = Integer(SelectedObjects[_id].ID)) then
4822 gTriggers[a].Data.ShotPanelID := -1;
4823 end;
4825 // Сброс ссылки на триггеры лифта:
4826 if not WordBool(PanelType and (PANEL_LIFTUP or PANEL_LIFTDOWN or PANEL_LIFTLEFT or PANEL_LIFTRIGHT)) then
4827 if gTriggers <> nil then
4828 for a := 0 to High(gTriggers) do
4829 if (gTriggers[a].TriggerType in [TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT]) and
4830 (gTriggers[a].Data.PanelID = Integer(SelectedObjects[_id].ID)) then
4831 gTriggers[a].Data.PanelID := -1;
4833 // Сброс ссылки на триггеры двери:
4834 if not WordBool(PanelType and (PANEL_OPENDOOR or PANEL_CLOSEDOOR)) then
4835 if gTriggers <> nil then
4836 for a := 0 to High(gTriggers) do
4837 if (gTriggers[a].TriggerType in [TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
4838 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP]) and
4839 (gTriggers[a].Data.PanelID = Integer(SelectedObjects[_id].ID)) then
4840 gTriggers[a].Data.PanelID := -1;
4842 if IsTexturedPanel(PanelType) then
4843 begin // Может быть текстура
4844 if TextureName <> '' then
4845 begin // Была текстура
4846 Alpha := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_PANEL_ALPHA]]));
4847 Blending := NameToBool(vleObjectProperty.Values[_lc[I_PROP_PANEL_BLEND]]);
4848 end
4849 else // Не было
4850 begin
4851 Alpha := 0;
4852 Blending := False;
4853 end;
4855 // Новая текстура:
4856 TextureName := vleObjectProperty.Values[_lc[I_PROP_PANEL_TEX]];
4858 if TextureName <> '' then
4859 begin // Есть текстура
4860 // Обычная текстура:
4861 if not IsSpecialTexture(TextureName) then
4862 begin
4863 g_GetTextureSizeByName(TextureName,
4864 TextureWidth, TextureHeight);
4866 // Проверка кратности размеров панели:
4867 res := True;
4868 if TextureWidth <> 0 then
4869 if gPanels[SelectedObjects[_id].ID].Width mod TextureWidth <> 0 then
4870 begin
4871 ErrorMessageBox(Format(_lc[I_MSG_WRONG_TEXWIDTH],
4872 [TextureWidth]));
4873 Res := False;
4874 end;
4875 if Res and (TextureHeight <> 0) then
4876 if gPanels[SelectedObjects[_id].ID].Height mod TextureHeight <> 0 then
4877 begin
4878 ErrorMessageBox(Format(_lc[I_MSG_WRONG_TEXHEIGHT],
4879 [TextureHeight]));
4880 Res := False;
4881 end;
4883 if Res then
4884 begin
4885 if not g_GetTexture(TextureName, TextureID) then
4886 // Не удалось загрузить текстуру, рисуем NOTEXTURE
4887 if g_GetTexture('NOTEXTURE', NoTextureID) then
4888 begin
4889 TextureID := TEXTURE_SPECIAL_NOTEXTURE;
4890 g_GetTextureSizeByID(NoTextureID, NW, NH);
4891 TextureWidth := NW;
4892 TextureHeight := NH;
4893 end else
4894 begin
4895 TextureID := TEXTURE_SPECIAL_NONE;
4896 TextureWidth := 1;
4897 TextureHeight := 1;
4898 end;
4899 end
4900 else
4901 begin
4902 TextureName := '';
4903 TextureWidth := 1;
4904 TextureHeight := 1;
4905 TextureID := TEXTURE_SPECIAL_NONE;
4906 end;
4907 end
4908 else // Спец.текстура
4909 begin
4910 TextureHeight := 1;
4911 TextureWidth := 1;
4912 TextureID := SpecialTextureID(TextureName);
4913 end;
4914 end
4915 else // Нет текстуры
4916 begin
4917 TextureWidth := 1;
4918 TextureHeight := 1;
4919 TextureID := TEXTURE_SPECIAL_NONE;
4920 end;
4921 end
4922 else // Не может быть текстуры
4923 begin
4924 Alpha := 0;
4925 Blending := False;
4926 TextureName := '';
4927 TextureWidth := 1;
4928 TextureHeight := 1;
4929 TextureID := TEXTURE_SPECIAL_NONE;
4930 end;
4931 end;
4932 end;
4934 OBJECT_ITEM:
4935 begin
4936 with gItems[SelectedObjects[_id].ID] do
4937 begin
4938 X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
4939 Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
4940 OnlyDM := NameToBool(vleObjectProperty.Values[_lc[I_PROP_DM_ONLY]]);
4941 Fall := NameToBool(vleObjectProperty.Values[_lc[I_PROP_ITEM_FALLS]]);
4942 end;
4943 end;
4945 OBJECT_MONSTER:
4946 begin
4947 with gMonsters[SelectedObjects[_id].ID] do
4948 begin
4949 X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
4950 Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
4951 Direction := NameToDir(vleObjectProperty.Values[_lc[I_PROP_DIRECTION]]);
4952 end;
4953 end;
4955 OBJECT_AREA:
4956 begin
4957 with gAreas[SelectedObjects[_id].ID] do
4958 begin
4959 X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
4960 Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
4961 Direction := NameToDir(vleObjectProperty.Values[_lc[I_PROP_DIRECTION]]);
4962 end;
4963 end;
4965 OBJECT_TRIGGER:
4966 begin
4967 with gTriggers[SelectedObjects[_id].ID] do
4968 begin
4969 X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
4970 Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
4971 Width := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_WIDTH]]));
4972 Height := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_HEIGHT]]));
4973 Enabled := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_ENABLED]]);
4974 ActivateType := StrToActivate(vleObjectProperty.Values[_lc[I_PROP_TR_ACTIVATION]]);
4975 Key := StrToKey(vleObjectProperty.Values[_lc[I_PROP_TR_KEYS]]);
4977 case TriggerType of
4978 TRIGGER_EXIT:
4979 begin
4980 s := utf2win(vleObjectProperty.Values[_lc[I_PROP_TR_NEXT_MAP]]);
4981 FillByte(Data.MapName[0], 16, 0);
4982 if s <> '' then
4983 Move(s[1], Data.MapName[0], Min(Length(s), 16));
4984 end;
4986 TRIGGER_TEXTURE:
4987 begin
4988 Data.ActivateOnce := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_TEXTURE_ONCE]]);
4989 Data.AnimOnce := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_TEXTURE_ANIM_ONCE]]);
4990 end;
4992 TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF:
4993 begin
4994 Data.Wait := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EX_DELAY]], 0), 65535);
4995 Data.Count := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EX_COUNT]], 0), 65535);
4996 if Data.Count < 1 then
4997 Data.Count := 1;
4998 if TriggerType = TRIGGER_PRESS then
4999 Data.ExtRandom := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_EX_RANDOM]]);
5000 end;
5002 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR, TRIGGER_DOOR5,
5003 TRIGGER_CLOSETRAP, TRIGGER_TRAP, TRIGGER_LIFTUP, TRIGGER_LIFTDOWN,
5004 TRIGGER_LIFT:
5005 begin
5006 Data.NoSound := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SILENT]]);
5007 Data.d2d_doors := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_D2D]]);
5008 end;
5010 TRIGGER_TELEPORT:
5011 begin
5012 Data.d2d_teleport := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_D2D]]);
5013 Data.silent_teleport := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_TELEPORT_SILENT]]);
5014 Data.TlpDir := NameToDirAdv(vleObjectProperty.Values[_lc[I_PROP_TR_TELEPORT_DIR]]);
5015 end;
5017 TRIGGER_SOUND:
5018 begin
5019 s := utf2win(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_NAME]]);
5020 FillByte(Data.SoundName[0], 64, 0);
5021 if s <> '' then
5022 Move(s[1], Data.SoundName[0], Min(Length(s), 64));
5024 Data.Volume := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_VOLUME]], 0), 255);
5025 Data.Pan := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_PAN]], 0), 255);
5026 Data.PlayCount := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_COUNT]], 0), 255);
5027 Data.Local := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_LOCAL]]);
5028 Data.SoundSwitch := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_SWITCH]]);
5029 end;
5031 TRIGGER_SPAWNMONSTER:
5032 begin
5033 Data.MonType := StrToMonster(vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_TYPE]]);
5034 Data.MonDir := Byte(NameToDir(vleObjectProperty.Values[_lc[I_PROP_DIRECTION]]));
5035 Data.MonHealth := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_HEALTH]], 0), 1000000);
5036 if Data.MonHealth < 0 then
5037 Data.MonHealth := 0;
5038 Data.MonActive := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_ACTIVE]]);
5039 Data.MonCount := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_COUNT]], 0), 64);
5040 if Data.MonCount < 1 then
5041 Data.MonCount := 1;
5042 Data.MonEffect := StrToEffect(vleObjectProperty.Values[_lc[I_PROP_TR_FX_TYPE]]);
5043 Data.MonMax := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SPAWN_MAX]], 0), 65535);
5044 Data.MonDelay := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SPAWN_DELAY]], 0), 65535);
5045 Data.MonBehav := 0;
5046 if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_1] then
5047 Data.MonBehav := 1;
5048 if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_2] then
5049 Data.MonBehav := 2;
5050 if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_3] then
5051 Data.MonBehav := 3;
5052 if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_4] then
5053 Data.MonBehav := 4;
5054 if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_5] then
5055 Data.MonBehav := 5;
5056 end;
5058 TRIGGER_SPAWNITEM:
5059 begin
5060 Data.ItemType := StrToItem(vleObjectProperty.Values[_lc[I_PROP_TR_ITEM_TYPE]]);
5061 Data.ItemOnlyDM := NameToBool(vleObjectProperty.Values[_lc[I_PROP_DM_ONLY]]);
5062 Data.ItemFalls := NameToBool(vleObjectProperty.Values[_lc[I_PROP_ITEM_FALLS]]);
5063 Data.ItemCount := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_COUNT]], 0), 64);
5064 if Data.ItemCount < 1 then
5065 Data.ItemCount := 1;
5066 Data.ItemEffect := StrToEffect(vleObjectProperty.Values[_lc[I_PROP_TR_FX_TYPE]]);
5067 Data.ItemMax := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SPAWN_MAX]], 0), 65535);
5068 Data.ItemDelay := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SPAWN_DELAY]], 0), 65535);
5069 end;
5071 TRIGGER_MUSIC:
5072 begin
5073 s := utf2win(vleObjectProperty.Values[_lc[I_PROP_TR_MUSIC_NAME]]);
5074 FillByte(Data.MusicName[0], 64, 0);
5075 if s <> '' then
5076 Move(s[1], Data.MusicName[0], Min(Length(s), 64));
5078 if vleObjectProperty.Values[_lc[I_PROP_TR_MUSIC_ACT]] = _lc[I_PROP_TR_MUSIC_ON] then
5079 Data.MusicAction := 1
5080 else
5081 Data.MusicAction := 2;
5082 end;
5084 TRIGGER_PUSH:
5085 begin
5086 Data.PushAngle := Min(
5087 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_PUSH_ANGLE]], 0), 360);
5088 Data.PushForce := Min(
5089 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_PUSH_FORCE]], 0), 255);
5090 Data.ResetVel := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_PUSH_RESET]]);
5091 end;
5093 TRIGGER_SCORE:
5094 begin
5095 Data.ScoreAction := 0;
5096 if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_ACT]] = _lc[I_PROP_TR_SCORE_ACT_1] then
5097 Data.ScoreAction := 1
5098 else if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_ACT]] = _lc[I_PROP_TR_SCORE_ACT_2] then
5099 Data.ScoreAction := 2
5100 else if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_ACT]] = _lc[I_PROP_TR_SCORE_ACT_3] then
5101 Data.ScoreAction := 3;
5102 Data.ScoreCount := Min(Max(
5103 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_COUNT]], 0), 0), 255);
5104 Data.ScoreTeam := 0;
5105 if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_TEAM]] = _lc[I_PROP_TR_SCORE_TEAM_1] then
5106 Data.ScoreTeam := 1
5107 else if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_TEAM]] = _lc[I_PROP_TR_SCORE_TEAM_2] then
5108 Data.ScoreTeam := 2
5109 else if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_TEAM]] = _lc[I_PROP_TR_SCORE_TEAM_3] then
5110 Data.ScoreTeam := 3;
5111 Data.ScoreCon := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_CON]]);
5112 Data.ScoreMsg := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_MSG]]);
5113 end;
5115 TRIGGER_MESSAGE:
5116 begin
5117 Data.MessageKind := 0;
5118 if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_KIND]] = _lc[I_PROP_TR_MESSAGE_KIND_1] then
5119 Data.MessageKind := 1;
5121 Data.MessageSendTo := 0;
5122 if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_1] then
5123 Data.MessageSendTo := 1
5124 else if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_2] then
5125 Data.MessageSendTo := 2
5126 else if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_3] then
5127 Data.MessageSendTo := 3
5128 else if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_4] then
5129 Data.MessageSendTo := 4
5130 else if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_5] then
5131 Data.MessageSendTo := 5;
5133 s := utf2win(vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TEXT]]);
5134 FillByte(Data.MessageText[0], 100, 0);
5135 if s <> '' then
5136 Move(s[1], Data.MessageText[0], Min(Length(s), 100));
5138 Data.MessageTime := Min(Max(
5139 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TIME]], 0), 0), 65535);
5140 end;
5142 TRIGGER_DAMAGE:
5143 begin
5144 Data.DamageValue := Min(Max(
5145 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_DAMAGE_VALUE]], 0), 0), 65535);
5146 Data.DamageInterval := Min(Max(
5147 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_INTERVAL]], 0), 0), 65535);
5148 end;
5150 TRIGGER_HEALTH:
5151 begin
5152 Data.HealValue := Min(Max(
5153 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_HEALTH]], 0), 0), 65535);
5154 Data.HealInterval := Min(Max(
5155 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_INTERVAL]], 0), 0), 65535);
5156 Data.HealMax := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_HEALTH_MAX]]);
5157 Data.HealSilent := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SILENT]]);
5158 end;
5160 TRIGGER_SHOT:
5161 begin
5162 Data.ShotType := StrToShot(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TYPE]]);
5163 Data.ShotSound := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_SOUND]]);
5164 Data.ShotTarget := 0;
5165 if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_1] then
5166 Data.ShotTarget := 1
5167 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_2] then
5168 Data.ShotTarget := 2
5169 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_3] then
5170 Data.ShotTarget := 3
5171 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_4] then
5172 Data.ShotTarget := 4
5173 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_5] then
5174 Data.ShotTarget := 5
5175 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_6] then
5176 Data.ShotTarget := 6;
5177 Data.ShotIntSight := Min(Max(
5178 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_SIGHT]], 0), 0), 65535);
5179 Data.ShotAim := 0;
5180 if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_AIM]] = _lc[I_PROP_TR_SHOT_AIM_1] then
5181 Data.ShotAim := 1
5182 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_AIM]] = _lc[I_PROP_TR_SHOT_AIM_2] then
5183 Data.ShotAim := 2
5184 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_AIM]] = _lc[I_PROP_TR_SHOT_AIM_3] then
5185 Data.ShotAim := 3;
5186 Data.ShotAngle := Min(
5187 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_ANGLE]], 0), 360);
5188 Data.ShotWait := Min(Max(
5189 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EX_DELAY]], 0), 0), 65535);
5190 Data.ShotAccuracy := Min(Max(
5191 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_ACC]], 0), 0), 65535);
5192 Data.ShotAmmo := Min(Max(
5193 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_AMMO]], 0), 0), 65535);
5194 Data.ShotIntReload := Min(Max(
5195 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_RELOAD]], 0), 0), 65535);
5196 end;
5198 TRIGGER_EFFECT:
5199 begin
5200 Data.FXCount := Min(Max(
5201 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_COUNT]], 0), 0), 255);
5202 if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_TYPE]] = _lc[I_PROP_TR_EFFECT_PARTICLE] then
5203 begin
5204 Data.FXType := TRIGGER_EFFECT_PARTICLE;
5205 Data.FXSubType := TRIGGER_EFFECT_SLIQUID;
5206 if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_SLIQUID] then
5207 Data.FXSubType := TRIGGER_EFFECT_SLIQUID
5208 else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_LLIQUID] then
5209 Data.FXSubType := TRIGGER_EFFECT_LLIQUID
5210 else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_DLIQUID] then
5211 Data.FXSubType := TRIGGER_EFFECT_DLIQUID
5212 else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_BLOOD] then
5213 Data.FXSubType := TRIGGER_EFFECT_BLOOD
5214 else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_SPARK] then
5215 Data.FXSubType := TRIGGER_EFFECT_SPARK
5216 else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_BUBBLE] then
5217 Data.FXSubType := TRIGGER_EFFECT_BUBBLE;
5218 end else
5219 begin
5220 Data.FXType := TRIGGER_EFFECT_ANIMATION;
5221 Data.FXSubType := StrToEffect(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]]);
5222 end;
5223 a := Min(Max(
5224 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_COLOR]], 0), 0), $FFFFFF);
5225 Data.FXColorR := a and $FF;
5226 Data.FXColorG := (a shr 8) and $FF;
5227 Data.FXColorB := (a shr 16) and $FF;
5228 if NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_CENTER]]) then
5229 Data.FXPos := 0
5230 else
5231 Data.FXPos := 1;
5232 Data.FXWait := Min(Max(
5233 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EX_DELAY]], 0), 0), 65535);
5234 Data.FXVelX := Min(Max(
5235 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_VELX]], 0), -128), 127);
5236 Data.FXVelY := Min(Max(
5237 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_VELY]], 0), -128), 127);
5238 Data.FXSpreadL := Min(Max(
5239 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SPL]], 0), 0), 255);
5240 Data.FXSpreadR := Min(Max(
5241 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SPR]], 0), 0), 255);
5242 Data.FXSpreadU := Min(Max(
5243 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SPU]], 0), 0), 255);
5244 Data.FXSpreadD := Min(Max(
5245 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SPD]], 0), 0), 255);
5246 end;
5247 end;
5248 end;
5249 end;
5250 end;
5252 FillProperty();
5254 vleObjectProperty.Row := r;
5255 vleObjectProperty.Col := c;
5256 end;
5258 procedure TMainForm.bbRemoveTextureClick(Sender: TObject);
5259 var
5260 a, i: Integer;
5261 begin
5262 i := lbTextureList.ItemIndex;
5263 if i = -1 then
5264 Exit;
5266 if MessageBox(0, PChar(Format(_lc[I_MSG_DEL_TEXTURE_PROMT],
5267 [SelectedTexture()])),
5268 PChar(_lc[I_MSG_DEL_TEXTURE]),
5269 MB_ICONQUESTION or MB_YESNO or
5270 MB_DEFBUTTON1) <> idYes then
5271 Exit;
5273 if gPanels <> nil then
5274 for a := 0 to High(gPanels) do
5275 if (gPanels[a].PanelType <> 0) and
5276 (gPanels[a].TextureName = SelectedTexture()) then
5277 begin
5278 ErrorMessageBox(_lc[I_MSG_DEL_TEXTURE_CANT]);
5279 Exit;
5280 end;
5282 g_DeleteTexture(SelectedTexture());
5283 i := slInvalidTextures.IndexOf(lbTextureList.Items[i]);
5284 if i > -1 then
5285 slInvalidTextures.Delete(i);
5286 if lbTextureList.ItemIndex > -1 then
5287 lbTextureList.Items.Delete(lbTextureList.ItemIndex)
5288 end;
5290 procedure TMainForm.aNewMapExecute(Sender: TObject);
5291 begin
5292 if (MessageBox(0, PChar(_lc[I_MSG_CLEAR_MAP_PROMT]),
5293 PChar(_lc[I_MSG_CLEAR_MAP]),
5294 MB_ICONQUESTION or MB_YESNO or
5295 MB_DEFBUTTON1) = mrYes) then
5296 FullClear();
5297 end;
5299 procedure TMainForm.aUndoExecute(Sender: TObject);
5300 var
5301 a: Integer;
5302 begin
5303 if UndoBuffer = nil then
5304 Exit;
5305 if UndoBuffer[High(UndoBuffer)] = nil then
5306 Exit;
5308 for a := 0 to High(UndoBuffer[High(UndoBuffer)]) do
5309 with UndoBuffer[High(UndoBuffer)][a] do
5310 begin
5311 case UndoType of
5312 UNDO_DELETE_PANEL:
5313 begin
5314 AddPanel(Panel^);
5315 Panel := nil;
5316 end;
5317 UNDO_DELETE_ITEM: AddItem(Item);
5318 UNDO_DELETE_AREA: AddArea(Area);
5319 UNDO_DELETE_MONSTER: AddMonster(Monster);
5320 UNDO_DELETE_TRIGGER: AddTrigger(Trigger);
5321 UNDO_ADD_PANEL: RemoveObject(AddID, OBJECT_PANEL);
5322 UNDO_ADD_ITEM: RemoveObject(AddID, OBJECT_ITEM);
5323 UNDO_ADD_AREA: RemoveObject(AddID, OBJECT_AREA);
5324 UNDO_ADD_MONSTER: RemoveObject(AddID, OBJECT_MONSTER);
5325 UNDO_ADD_TRIGGER: RemoveObject(AddID, OBJECT_TRIGGER);
5326 end;
5327 end;
5329 SetLength(UndoBuffer, Length(UndoBuffer)-1);
5331 RemoveSelectFromObjects();
5333 miUndo.Enabled := UndoBuffer <> nil;
5334 end;
5337 procedure TMainForm.aCopyObjectExecute(Sender: TObject);
5338 var
5339 a, b: Integer;
5340 CopyBuffer: TCopyRecArray;
5341 str: String;
5342 ok: Boolean;
5344 function CB_Compare(I1, I2: TCopyRec): Integer;
5345 begin
5346 Result := Integer(I1.ObjectType) - Integer(I2.ObjectType);
5348 if Result = 0 then // Одного типа
5349 Result := Integer(I1.ID) - Integer(I2.ID);
5350 end;
5352 procedure QuickSortCopyBuffer(L, R: Integer);
5353 var
5354 I, J: Integer;
5355 P, T: TCopyRec;
5356 begin
5357 repeat
5358 I := L;
5359 J := R;
5360 P := CopyBuffer[(L + R) shr 1];
5362 repeat
5363 while CB_Compare(CopyBuffer[I], P) < 0 do
5364 Inc(I);
5365 while CB_Compare(CopyBuffer[J], P) > 0 do
5366 Dec(J);
5368 if I <= J then
5369 begin
5370 T := CopyBuffer[I];
5371 CopyBuffer[I] := CopyBuffer[J];
5372 CopyBuffer[J] := T;
5373 Inc(I);
5374 Dec(J);
5375 end;
5376 until I > J;
5378 if L < J then
5379 QuickSortCopyBuffer(L, J);
5381 L := I;
5382 until I >= R;
5383 end;
5385 begin
5386 if SelectedObjects = nil then
5387 Exit;
5389 b := -1;
5390 CopyBuffer := nil;
5392 // Копируем объекты:
5393 for a := 0 to High(SelectedObjects) do
5394 if SelectedObjects[a].Live then
5395 with SelectedObjects[a] do
5396 begin
5397 SetLength(CopyBuffer, Length(CopyBuffer)+1);
5398 b := High(CopyBuffer);
5399 CopyBuffer[b].ID := ID;
5400 CopyBuffer[b].Panel := nil;
5402 case ObjectType of
5403 OBJECT_PANEL:
5404 begin
5405 CopyBuffer[b].ObjectType := OBJECT_PANEL;
5406 New(CopyBuffer[b].Panel);
5407 CopyBuffer[b].Panel^ := gPanels[ID];
5408 end;
5410 OBJECT_ITEM:
5411 begin
5412 CopyBuffer[b].ObjectType := OBJECT_ITEM;
5413 CopyBuffer[b].Item := gItems[ID];
5414 end;
5416 OBJECT_MONSTER:
5417 begin
5418 CopyBuffer[b].ObjectType := OBJECT_MONSTER;
5419 CopyBuffer[b].Monster := gMonsters[ID];
5420 end;
5422 OBJECT_AREA:
5423 begin
5424 CopyBuffer[b].ObjectType := OBJECT_AREA;
5425 CopyBuffer[b].Area := gAreas[ID];
5426 end;
5428 OBJECT_TRIGGER:
5429 begin
5430 CopyBuffer[b].ObjectType := OBJECT_TRIGGER;
5431 CopyBuffer[b].Trigger := gTriggers[ID];
5432 end;
5433 end;
5434 end;
5436 // Сортировка по ID:
5437 if CopyBuffer <> nil then
5438 begin
5439 QuickSortCopyBuffer(0, b);
5440 end;
5442 // Пестановка ссылок триггеров:
5443 for a := 0 to Length(CopyBuffer)-1 do
5444 if CopyBuffer[a].ObjectType = OBJECT_TRIGGER then
5445 begin
5446 case CopyBuffer[a].Trigger.TriggerType of
5447 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
5448 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP,
5449 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
5450 if CopyBuffer[a].Trigger.Data.PanelID <> -1 then
5451 begin
5452 ok := False;
5454 for b := 0 to Length(CopyBuffer)-1 do
5455 if (CopyBuffer[b].ObjectType = OBJECT_PANEL) and
5456 (Integer(CopyBuffer[b].ID) = CopyBuffer[a].Trigger.Data.PanelID) then
5457 begin
5458 CopyBuffer[a].Trigger.Data.PanelID := b;
5459 ok := True;
5460 Break;
5461 end;
5463 // Этих панелей нет среди копируемых:
5464 if not ok then
5465 CopyBuffer[a].Trigger.Data.PanelID := -1;
5466 end;
5468 TRIGGER_PRESS, TRIGGER_ON,
5469 TRIGGER_OFF, TRIGGER_ONOFF:
5470 if CopyBuffer[a].Trigger.Data.MonsterID <> 0 then
5471 begin
5472 ok := False;
5474 for b := 0 to Length(CopyBuffer)-1 do
5475 if (CopyBuffer[b].ObjectType = OBJECT_MONSTER) and
5476 (Integer(CopyBuffer[b].ID) = CopyBuffer[a].Trigger.Data.MonsterID-1) then
5477 begin
5478 CopyBuffer[a].Trigger.Data.MonsterID := b+1;
5479 ok := True;
5480 Break;
5481 end;
5483 // Этих монстров нет среди копируемых:
5484 if not ok then
5485 CopyBuffer[a].Trigger.Data.MonsterID := 0;
5486 end;
5488 TRIGGER_SHOT:
5489 if CopyBuffer[a].Trigger.Data.ShotPanelID <> -1 then
5490 begin
5491 ok := False;
5493 for b := 0 to Length(CopyBuffer)-1 do
5494 if (CopyBuffer[b].ObjectType = OBJECT_PANEL) and
5495 (Integer(CopyBuffer[b].ID) = CopyBuffer[a].Trigger.Data.ShotPanelID) then
5496 begin
5497 CopyBuffer[a].Trigger.Data.ShotPanelID := b;
5498 ok := True;
5499 Break;
5500 end;
5502 // Этих панелей нет среди копируемых:
5503 if not ok then
5504 CopyBuffer[a].Trigger.Data.ShotPanelID := -1;
5505 end;
5506 end;
5508 if CopyBuffer[a].Trigger.TexturePanel <> -1 then
5509 begin
5510 ok := False;
5512 for b := 0 to Length(CopyBuffer)-1 do
5513 if (CopyBuffer[b].ObjectType = OBJECT_PANEL) and
5514 (Integer(CopyBuffer[b].ID) = CopyBuffer[a].Trigger.TexturePanel) then
5515 begin
5516 CopyBuffer[a].Trigger.TexturePanel := b;
5517 ok := True;
5518 Break;
5519 end;
5521 // Этих панелей нет среди копируемых:
5522 if not ok then
5523 CopyBuffer[a].Trigger.TexturePanel := -1;
5524 end;
5525 end;
5527 // В буфер обмена:
5528 str := CopyBufferToString(CopyBuffer);
5529 ClipBoard.AsText := str;
5531 for a := 0 to Length(CopyBuffer)-1 do
5532 if (CopyBuffer[a].ObjectType = OBJECT_PANEL) and
5533 (CopyBuffer[a].Panel <> nil) then
5534 Dispose(CopyBuffer[a].Panel);
5536 CopyBuffer := nil;
5537 end;
5539 procedure TMainForm.aPasteObjectExecute(Sender: TObject);
5540 var
5541 a, h: Integer;
5542 CopyBuffer: TCopyRecArray;
5543 res, rel: Boolean;
5544 swad, ssec, sres: String;
5545 NoTextureID: DWORD;
5546 pmin: TPoint;
5547 begin
5548 CopyBuffer := nil;
5549 NoTextureID := 0;
5550 pmin.X := High(pmin.X);
5551 pmin.Y := High(pmin.Y);
5553 StringToCopyBuffer(ClipBoard.AsText, CopyBuffer, pmin);
5554 rel := not(ssShift in GetKeyShiftState());
5556 if CopyBuffer = nil then
5557 Exit;
5559 RemoveSelectFromObjects();
5561 h := High(CopyBuffer);
5562 for a := 0 to h do
5563 with CopyBuffer[a] do
5564 begin
5565 case ObjectType of
5566 OBJECT_PANEL:
5567 if Panel <> nil then
5568 begin
5569 if rel then
5570 begin
5571 Panel^.X := Panel^.X - pmin.X - MapOffset.X + 32;
5572 Panel^.Y := Panel^.Y - pmin.Y - MapOffset.Y + 32;
5573 end;
5575 Panel^.TextureID := TEXTURE_SPECIAL_NONE;
5576 Panel^.TextureWidth := 1;
5577 Panel^.TextureHeight := 1;
5579 if (Panel^.PanelType = PANEL_LIFTUP) or
5580 (Panel^.PanelType = PANEL_LIFTDOWN) or
5581 (Panel^.PanelType = PANEL_LIFTLEFT) or
5582 (Panel^.PanelType = PANEL_LIFTRIGHT) or
5583 (Panel^.PanelType = PANEL_BLOCKMON) or
5584 (Panel^.TextureName = '') then
5585 begin // Нет или не может быть текстуры:
5586 end
5587 else // Есть текстура:
5588 begin
5589 // Обычная текстура:
5590 if not IsSpecialTexture(Panel^.TextureName) then
5591 begin
5592 res := g_GetTexture(Panel^.TextureName, Panel^.TextureID);
5594 if not res then
5595 begin
5596 g_ProcessResourceStr(Panel^.TextureName, swad, ssec, sres);
5597 AddTexture(swad, ssec, sres, True);
5598 res := g_GetTexture(Panel^.TextureName, Panel^.TextureID);
5599 end;
5601 if res then
5602 g_GetTextureSizeByName(Panel^.TextureName,
5603 Panel^.TextureWidth, Panel^.TextureHeight)
5604 else
5605 if g_GetTexture('NOTEXTURE', NoTextureID) then
5606 begin
5607 Panel^.TextureID := TEXTURE_SPECIAL_NOTEXTURE;
5608 g_GetTextureSizeByID(NoTextureID, Panel^.TextureWidth, Panel^.TextureHeight);
5609 end;
5610 end
5611 else // Спец.текстура:
5612 begin
5613 Panel^.TextureID := SpecialTextureID(Panel^.TextureName);
5614 with MainForm.lbTextureList.Items do
5615 if IndexOf(Panel^.TextureName) = -1 then
5616 Add(Panel^.TextureName);
5617 end;
5618 end;
5620 ID := AddPanel(Panel^);
5621 Dispose(Panel);
5622 Undo_Add(OBJECT_PANEL, ID, a > 0);
5623 SelectObject(OBJECT_PANEL, ID, True);
5624 end;
5626 OBJECT_ITEM:
5627 begin
5628 if rel then
5629 begin
5630 Item.X := Item.X - pmin.X - MapOffset.X + 32;
5631 Item.Y := Item.Y - pmin.Y - MapOffset.Y + 32;
5632 end;
5634 ID := AddItem(Item);
5635 Undo_Add(OBJECT_ITEM, ID, a > 0);
5636 SelectObject(OBJECT_ITEM, ID, True);
5637 end;
5639 OBJECT_MONSTER:
5640 begin
5641 if rel then
5642 begin
5643 Monster.X := Monster.X - pmin.X - MapOffset.X + 32;
5644 Monster.Y := Monster.Y - pmin.Y - MapOffset.Y + 32;
5645 end;
5647 ID := AddMonster(Monster);
5648 Undo_Add(OBJECT_MONSTER, ID, a > 0);
5649 SelectObject(OBJECT_MONSTER, ID, True);
5650 end;
5652 OBJECT_AREA:
5653 begin
5654 if rel then
5655 begin
5656 Area.X := Area.X - pmin.X - MapOffset.X + 32;
5657 Area.Y := Area.Y - pmin.Y - MapOffset.Y + 32;
5658 end;
5660 ID := AddArea(Area);
5661 Undo_Add(OBJECT_AREA, ID, a > 0);
5662 SelectObject(OBJECT_AREA, ID, True);
5663 end;
5665 OBJECT_TRIGGER:
5666 begin
5667 if rel then
5668 with Trigger do
5669 begin
5670 X := X - pmin.X - MapOffset.X + 32;
5671 Y := Y - pmin.Y - MapOffset.Y + 32;
5673 case TriggerType of
5674 TRIGGER_TELEPORT:
5675 begin
5676 Data.TargetPoint.X :=
5677 Data.TargetPoint.X - pmin.X - MapOffset.X + 32;
5678 Data.TargetPoint.Y :=
5679 Data.TargetPoint.Y - pmin.Y - MapOffset.Y + 32;
5680 end;
5681 TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF:
5682 begin
5683 Data.tX := Data.tX - pmin.X - MapOffset.X + 32;
5684 Data.tY := Data.tY - pmin.Y - MapOffset.Y + 32;
5685 end;
5686 TRIGGER_SPAWNMONSTER:
5687 begin
5688 Data.MonPos.X :=
5689 Data.MonPos.X - pmin.X - MapOffset.X + 32;
5690 Data.MonPos.Y :=
5691 Data.MonPos.Y - pmin.Y - MapOffset.Y + 32;
5692 end;
5693 TRIGGER_SPAWNITEM:
5694 begin
5695 Data.ItemPos.X :=
5696 Data.ItemPos.X - pmin.X - MapOffset.X + 32;
5697 Data.ItemPos.Y :=
5698 Data.ItemPos.Y - pmin.Y - MapOffset.Y + 32;
5699 end;
5700 TRIGGER_SHOT:
5701 begin
5702 Data.ShotPos.X :=
5703 Data.ShotPos.X - pmin.X - MapOffset.X + 32;
5704 Data.ShotPos.Y :=
5705 Data.ShotPos.Y - pmin.Y - MapOffset.Y + 32;
5706 end;
5707 end;
5708 end;
5710 ID := AddTrigger(Trigger);
5711 Undo_Add(OBJECT_TRIGGER, ID, a > 0);
5712 SelectObject(OBJECT_TRIGGER, ID, True);
5713 end;
5714 end;
5715 end;
5717 // Переставляем ссылки триггеров:
5718 for a := 0 to High(CopyBuffer) do
5719 if CopyBuffer[a].ObjectType = OBJECT_TRIGGER then
5720 begin
5721 case CopyBuffer[a].Trigger.TriggerType of
5722 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
5723 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP,
5724 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
5725 if CopyBuffer[a].Trigger.Data.PanelID <> -1 then
5726 gTriggers[CopyBuffer[a].ID].Data.PanelID :=
5727 CopyBuffer[CopyBuffer[a].Trigger.Data.PanelID].ID;
5729 TRIGGER_PRESS, TRIGGER_ON,
5730 TRIGGER_OFF, TRIGGER_ONOFF:
5731 if CopyBuffer[a].Trigger.Data.MonsterID <> 0 then
5732 gTriggers[CopyBuffer[a].ID].Data.MonsterID :=
5733 CopyBuffer[CopyBuffer[a].Trigger.Data.MonsterID-1].ID+1;
5735 TRIGGER_SHOT:
5736 if CopyBuffer[a].Trigger.Data.ShotPanelID <> -1 then
5737 gTriggers[CopyBuffer[a].ID].Data.ShotPanelID :=
5738 CopyBuffer[CopyBuffer[a].Trigger.Data.ShotPanelID].ID;
5739 end;
5741 if CopyBuffer[a].Trigger.TexturePanel <> -1 then
5742 gTriggers[CopyBuffer[a].ID].TexturePanel :=
5743 CopyBuffer[CopyBuffer[a].Trigger.TexturePanel].ID;
5744 end;
5746 CopyBuffer := nil;
5748 if h = 0 then
5749 FillProperty();
5750 end;
5752 procedure TMainForm.aCutObjectExecute(Sender: TObject);
5753 begin
5754 miCopy.Click();
5755 DeleteSelectedObjects();
5756 end;
5758 procedure TMainForm.vleObjectPropertyEditButtonClick(Sender: TObject);
5759 var
5760 Key, FileName: String;
5761 b: Byte;
5762 begin
5763 Key := vleObjectProperty.Keys[vleObjectProperty.Row];
5765 if Key = _lc[I_PROP_PANEL_TYPE] then
5766 begin
5767 with ChooseTypeForm, vleObjectProperty do
5768 begin // Выбор типа панели:
5769 Caption := _lc[I_PROP_PANEL_TYPE];
5770 lbTypeSelect.Items.Clear();
5772 for b := 0 to High(PANELNAMES) do
5773 begin
5774 lbTypeSelect.Items.Add(PANELNAMES[b]);
5775 if Values[Key] = PANELNAMES[b] then
5776 lbTypeSelect.ItemIndex := b;
5777 end;
5779 if ShowModal() = mrOK then
5780 begin
5781 b := lbTypeSelect.ItemIndex;
5782 Values[Key] := PANELNAMES[b];
5783 vleObjectPropertyApply(Sender);
5784 end;
5785 end
5786 end
5787 else if Key = _lc[I_PROP_TR_TELEPORT_TO] then
5788 SelectFlag := SELECTFLAG_TELEPORT
5789 else if Key = _lc[I_PROP_TR_SPAWN_TO] then
5790 SelectFlag := SELECTFLAG_SPAWNPOINT
5791 else if (Key = _lc[I_PROP_TR_DOOR_PANEL]) or
5792 (Key = _lc[I_PROP_TR_TRAP_PANEL]) then
5793 SelectFlag := SELECTFLAG_DOOR
5794 else if Key = _lc[I_PROP_TR_TEXTURE_PANEL] then
5795 begin
5796 DrawPressRect := False;
5797 SelectFlag := SELECTFLAG_TEXTURE;
5798 end
5799 else if Key = _lc[I_PROP_TR_SHOT_PANEL] then
5800 SelectFlag := SELECTFLAG_SHOTPANEL
5801 else if Key = _lc[I_PROP_TR_LIFT_PANEL] then
5802 SelectFlag := SELECTFLAG_LIFT
5803 else if key = _lc[I_PROP_TR_EX_MONSTER] then
5804 SelectFlag := SELECTFLAG_MONSTER
5805 else if Key = _lc[I_PROP_TR_EX_AREA] then
5806 begin
5807 SelectFlag := SELECTFLAG_NONE;
5808 DrawPressRect := True;
5809 end
5810 else if Key = _lc[I_PROP_TR_NEXT_MAP] then
5811 begin // Выбор следующей карты:
5812 g_ProcessResourceStr(OpenedMap, @FileName, nil, nil);
5813 SelectMapForm.Caption := _lc[I_CAP_SELECT];
5814 SelectMapForm.GetMaps(FileName);
5816 if SelectMapForm.ShowModal() = mrOK then
5817 begin
5818 vleObjectProperty.Values[Key] := SelectMapForm.lbMapList.Items[SelectMapForm.lbMapList.ItemIndex];
5819 vleObjectPropertyApply(Sender);
5820 end;
5821 end
5822 else if (Key = _lc[I_PROP_TR_SOUND_NAME]) or
5823 (Key = _lc[I_PROP_TR_MUSIC_NAME]) then
5824 begin // Выбор файла звука/музыки:
5825 AddSoundForm.OKFunction := nil;
5826 AddSoundForm.lbResourcesList.MultiSelect := False;
5827 AddSoundForm.SetResource := vleObjectProperty.Values[Key];
5829 if (AddSoundForm.ShowModal() = mrOk) then
5830 begin
5831 vleObjectProperty.Values[Key] := AddSoundForm.ResourceName;
5832 vleObjectPropertyApply(Sender);
5833 end;
5834 end
5835 else if Key = _lc[I_PROP_TR_ACTIVATION] then
5836 with ActivationTypeForm, vleObjectProperty do
5837 begin // Выбор типов активации:
5838 cbPlayerCollide.Checked := Pos('PC', Values[Key]) > 0;
5839 cbMonsterCollide.Checked := Pos('MC', Values[Key]) > 0;
5840 cbPlayerPress.Checked := Pos('PP', Values[Key]) > 0;
5841 cbMonsterPress.Checked := Pos('MP', Values[Key]) > 0;
5842 cbShot.Checked := Pos('SH', Values[Key]) > 0;
5843 cbNoMonster.Checked := Pos('NM', Values[Key]) > 0;
5845 if ShowModal() = mrOK then
5846 begin
5847 b := 0;
5848 if cbPlayerCollide.Checked then
5849 b := ACTIVATE_PLAYERCOLLIDE;
5850 if cbMonsterCollide.Checked then
5851 b := b or ACTIVATE_MONSTERCOLLIDE;
5852 if cbPlayerPress.Checked then
5853 b := b or ACTIVATE_PLAYERPRESS;
5854 if cbMonsterPress.Checked then
5855 b := b or ACTIVATE_MONSTERPRESS;
5856 if cbShot.Checked then
5857 b := b or ACTIVATE_SHOT;
5858 if cbNoMonster.Checked then
5859 b := b or ACTIVATE_NOMONSTER;
5861 Values[Key] := ActivateToStr(b);
5862 vleObjectPropertyApply(Sender);
5863 end;
5864 end
5865 else if Key = _lc[I_PROP_TR_KEYS] then
5866 with KeysForm, vleObjectProperty do
5867 begin // Выбор необходимых ключей:
5868 cbRedKey.Checked := Pos('RK', Values[Key]) > 0;
5869 cbGreenKey.Checked := Pos('GK', Values[Key]) > 0;
5870 cbBlueKey.Checked := Pos('BK', Values[Key]) > 0;
5871 cbRedTeam.Checked := Pos('RT', Values[Key]) > 0;
5872 cbBlueTeam.Checked := Pos('BT', Values[Key]) > 0;
5874 if ShowModal() = mrOK then
5875 begin
5876 b := 0;
5877 if cbRedKey.Checked then
5878 b := KEY_RED;
5879 if cbGreenKey.Checked then
5880 b := b or KEY_GREEN;
5881 if cbBlueKey.Checked then
5882 b := b or KEY_BLUE;
5883 if cbRedTeam.Checked then
5884 b := b or KEY_REDTEAM;
5885 if cbBlueTeam.Checked then
5886 b := b or KEY_BLUETEAM;
5888 Values[Key] := KeyToStr(b);
5889 vleObjectPropertyApply(Sender);
5890 end;
5891 end
5892 else if Key = _lc[I_PROP_TR_FX_TYPE] then
5893 with ChooseTypeForm, vleObjectProperty do
5894 begin // Выбор типа эффекта:
5895 Caption := _lc[I_CAP_FX_TYPE];
5896 lbTypeSelect.Items.Clear();
5898 for b := EFFECT_NONE to EFFECT_FIRE do
5899 lbTypeSelect.Items.Add(EffectToStr(b));
5901 lbTypeSelect.ItemIndex := StrToEffect(Values[Key]);
5903 if ShowModal() = mrOK then
5904 begin
5905 b := lbTypeSelect.ItemIndex;
5906 Values[Key] := EffectToStr(b);
5907 vleObjectPropertyApply(Sender);
5908 end;
5909 end
5910 else if Key = _lc[I_PROP_TR_MONSTER_TYPE] then
5911 with ChooseTypeForm, vleObjectProperty do
5912 begin // Выбор типа монстра:
5913 Caption := _lc[I_CAP_MONSTER_TYPE];
5914 lbTypeSelect.Items.Clear();
5916 for b := MONSTER_DEMON to MONSTER_MAN do
5917 lbTypeSelect.Items.Add(MonsterToStr(b));
5919 lbTypeSelect.ItemIndex := StrToMonster(Values[Key]) - MONSTER_DEMON;
5921 if ShowModal() = mrOK then
5922 begin
5923 b := lbTypeSelect.ItemIndex + MONSTER_DEMON;
5924 Values[Key] := MonsterToStr(b);
5925 vleObjectPropertyApply(Sender);
5926 end;
5927 end
5928 else if Key = _lc[I_PROP_TR_ITEM_TYPE] then
5929 with ChooseTypeForm, vleObjectProperty do
5930 begin // Выбор типа предмета:
5931 Caption := _lc[I_CAP_ITEM_TYPE];
5932 lbTypeSelect.Items.Clear();
5934 for b := ITEM_MEDKIT_SMALL to ITEM_KEY_BLUE do
5935 lbTypeSelect.Items.Add(ItemToStr(b));
5936 lbTypeSelect.Items.Add(ItemToStr(ITEM_BOTTLE));
5937 lbTypeSelect.Items.Add(ItemToStr(ITEM_HELMET));
5938 lbTypeSelect.Items.Add(ItemToStr(ITEM_JETPACK));
5939 lbTypeSelect.Items.Add(ItemToStr(ITEM_INVIS));
5940 lbTypeSelect.Items.Add(ItemToStr(ITEM_WEAPON_FLAMETHROWER));
5941 lbTypeSelect.Items.Add(ItemToStr(ITEM_AMMO_FUELCAN));
5943 b := StrToItem(Values[Key]);
5944 if b >= ITEM_BOTTLE then
5945 b := b - 2;
5946 lbTypeSelect.ItemIndex := b - ITEM_MEDKIT_SMALL;
5948 if ShowModal() = mrOK then
5949 begin
5950 b := lbTypeSelect.ItemIndex + ITEM_MEDKIT_SMALL;
5951 if b >= ITEM_WEAPON_KASTET then
5952 b := b + 2;
5953 Values[Key] := ItemToStr(b);
5954 vleObjectPropertyApply(Sender);
5955 end;
5956 end
5957 else if Key = _lc[I_PROP_TR_SHOT_TYPE] then
5958 with ChooseTypeForm, vleObjectProperty do
5959 begin // Выбор типа предмета:
5960 Caption := _lc[I_PROP_TR_SHOT_TYPE];
5961 lbTypeSelect.Items.Clear();
5963 for b := TRIGGER_SHOT_PISTOL to TRIGGER_SHOT_MAX do
5964 lbTypeSelect.Items.Add(ShotToStr(b));
5966 lbTypeSelect.ItemIndex := StrToShot(Values[Key]);
5968 if ShowModal() = mrOK then
5969 begin
5970 b := lbTypeSelect.ItemIndex;
5971 Values[Key] := ShotToStr(b);
5972 vleObjectPropertyApply(Sender);
5973 end;
5974 end
5975 else if Key = _lc[I_PROP_TR_EFFECT_TYPE] then
5976 with ChooseTypeForm, vleObjectProperty do
5977 begin // Выбор типа эффекта:
5978 Caption := _lc[I_CAP_FX_TYPE];
5979 lbTypeSelect.Items.Clear();
5981 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_PARTICLE]);
5982 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_ANIMATION]);
5983 if Values[Key] = _lc[I_PROP_TR_EFFECT_ANIMATION] then
5984 lbTypeSelect.ItemIndex := 1
5985 else
5986 lbTypeSelect.ItemIndex := 0;
5988 if ShowModal() = mrOK then
5989 begin
5990 b := lbTypeSelect.ItemIndex;
5991 if b = 0 then
5992 Values[Key] := _lc[I_PROP_TR_EFFECT_PARTICLE]
5993 else
5994 Values[Key] := _lc[I_PROP_TR_EFFECT_ANIMATION];
5995 vleObjectPropertyApply(Sender);
5996 end;
5997 end
5998 else if Key = _lc[I_PROP_TR_EFFECT_SUBTYPE] then
5999 with ChooseTypeForm, vleObjectProperty do
6000 begin // Выбор подтипа эффекта:
6001 Caption := _lc[I_CAP_FX_TYPE];
6002 lbTypeSelect.Items.Clear();
6004 if Values[_lc[I_PROP_TR_EFFECT_TYPE]] = _lc[I_PROP_TR_EFFECT_ANIMATION] then
6005 begin
6006 for b := EFFECT_TELEPORT to EFFECT_FIRE do
6007 lbTypeSelect.Items.Add(EffectToStr(b));
6009 lbTypeSelect.ItemIndex := StrToEffect(Values[Key]) - 1;
6010 end else
6011 begin
6012 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_SLIQUID]);
6013 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_LLIQUID]);
6014 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_DLIQUID]);
6015 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_BLOOD]);
6016 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_SPARK]);
6017 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_BUBBLE]);
6018 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_SLIQUID;
6019 if Values[Key] = _lc[I_PROP_TR_EFFECT_LLIQUID] then
6020 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_LLIQUID;
6021 if Values[Key] = _lc[I_PROP_TR_EFFECT_DLIQUID] then
6022 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_DLIQUID;
6023 if Values[Key] = _lc[I_PROP_TR_EFFECT_BLOOD] then
6024 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_BLOOD;
6025 if Values[Key] = _lc[I_PROP_TR_EFFECT_SPARK] then
6026 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_SPARK;
6027 if Values[Key] = _lc[I_PROP_TR_EFFECT_BUBBLE] then
6028 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_BUBBLE;
6029 end;
6031 if ShowModal() = mrOK then
6032 begin
6033 b := lbTypeSelect.ItemIndex;
6035 if Values[_lc[I_PROP_TR_EFFECT_TYPE]] = _lc[I_PROP_TR_EFFECT_ANIMATION] then
6036 Values[Key] := EffectToStr(b + 1)
6037 else begin
6038 Values[Key] := _lc[I_PROP_TR_EFFECT_SLIQUID];
6039 if b = TRIGGER_EFFECT_LLIQUID then
6040 Values[Key] := _lc[I_PROP_TR_EFFECT_LLIQUID];
6041 if b = TRIGGER_EFFECT_DLIQUID then
6042 Values[Key] := _lc[I_PROP_TR_EFFECT_DLIQUID];
6043 if b = TRIGGER_EFFECT_BLOOD then
6044 Values[Key] := _lc[I_PROP_TR_EFFECT_BLOOD];
6045 if b = TRIGGER_EFFECT_SPARK then
6046 Values[Key] := _lc[I_PROP_TR_EFFECT_SPARK];
6047 if b = TRIGGER_EFFECT_BUBBLE then
6048 Values[Key] := _lc[I_PROP_TR_EFFECT_BUBBLE];
6049 end;
6051 vleObjectPropertyApply(Sender);
6052 end;
6053 end
6054 else if Key = _lc[I_PROP_TR_EFFECT_COLOR] then
6055 with vleObjectProperty do
6056 begin // Выбор цвета эффекта:
6057 ColorDialog.Color := StrToIntDef(Values[Key], 0);
6058 if ColorDialog.Execute then
6059 begin
6060 Values[Key] := IntToStr(ColorDialog.Color);
6061 vleObjectPropertyApply(Sender);
6062 end;
6063 end
6064 else if Key = _lc[I_PROP_PANEL_TEX] then
6065 begin // Смена текстуры:
6066 vleObjectProperty.Values[Key] := SelectedTexture();
6067 vleObjectPropertyApply(Sender);
6068 end;
6069 end;
6071 procedure TMainForm.vleObjectPropertyApply(Sender: TObject);
6072 begin
6073 // hack to prevent empty ID in list
6074 RenderPanel.SetFocus();
6075 bApplyProperty.Click();
6076 vleObjectProperty.SetFocus();
6077 end;
6079 procedure TMainForm.aSaveMapExecute(Sender: TObject);
6080 var
6081 FileName, Section, Res: String;
6082 begin
6083 if OpenedMap = '' then
6084 begin
6085 aSaveMapAsExecute(nil);
6086 Exit;
6087 end;
6089 g_ProcessResourceStr(OpenedMap, FileName, Section, Res);
6091 SaveMap(FileName+':\'+Res);
6092 end;
6094 procedure TMainForm.aOpenMapExecute(Sender: TObject);
6095 begin
6096 OpenDialog.Filter := _lc[I_FILE_FILTER_ALL];
6098 if OpenDialog.Execute() then
6099 begin
6100 OpenMapFile(OpenDialog.FileName);
6101 OpenDialog.InitialDir := ExtractFileDir(OpenDialog.FileName);
6102 end;
6103 end;
6105 procedure TMainForm.OpenMapFile(FileName: String);
6106 begin
6107 if (Pos('.ini', LowerCase(ExtractFileName(FileName))) > 0) then
6108 begin // INI карты:
6109 FullClear();
6111 pLoadProgress.Left := (RenderPanel.Width div 2)-(pLoadProgress.Width div 2);
6112 pLoadProgress.Top := (RenderPanel.Height div 2)-(pLoadProgress.Height div 2);
6113 pLoadProgress.Show();
6115 OpenedMap := '';
6116 OpenedWAD := '';
6118 LoadMapOld(FileName);
6120 MainForm.Caption := Format('%s - %s', [FormCaption, ExtractFileName(FileName)]);
6122 pLoadProgress.Hide();
6123 MainForm.FormResize(Self);
6124 end
6125 else // Карты из WAD:
6126 begin
6127 OpenMap(FileName, '');
6128 end;
6129 end;
6131 procedure TMainForm.FormActivate(Sender: TObject);
6132 var
6133 lang: Integer;
6134 config: TConfig;
6135 begin
6136 MainForm.ActiveControl := RenderPanel;
6138 // Язык:
6139 if gLanguage = '' then
6140 begin
6141 lang := SelectLanguageForm.ShowModal();
6142 case lang of
6143 1: gLanguage := LANGUAGE_ENGLISH;
6144 else gLanguage := LANGUAGE_RUSSIAN;
6145 end;
6147 config := TConfig.CreateFile(EditorDir+'Editor.cfg');
6148 config.WriteStr('Editor', 'Language', gLanguage);
6149 config.SaveFile(EditorDir+'Editor.cfg');
6150 config.Free();
6151 end;
6153 //e_WriteLog('Read language file', MSG_NOTIFY);
6154 //g_Language_Load(EditorDir+'\data\'+gLanguage+LANGUAGE_FILE_NAME);
6155 g_Language_Set(gLanguage);
6156 end;
6158 procedure TMainForm.aDeleteMap(Sender: TObject);
6159 var
6160 res: Integer;
6161 FileName: String;
6162 MapName: String;
6163 begin
6164 OpenDialog.Filter := _lc[I_FILE_FILTER_WAD];
6166 if not OpenDialog.Execute() then
6167 Exit;
6169 FileName := OpenDialog.FileName;
6170 SelectMapForm.Caption := _lc[I_CAP_REMOVE];
6171 SelectMapForm.lbMapList.Items.Clear();
6172 SelectMapForm.GetMaps(FileName);
6174 if SelectMapForm.ShowModal() <> mrOK then
6175 Exit;
6177 MapName := SelectMapForm.lbMapList.Items[SelectMapForm.lbMapList.ItemIndex];
6178 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
6179 Exit;
6181 g_DeleteResource(FileName, '', utf2win(MapName), res);
6182 if res <> 0 then
6183 begin
6184 MessageBox(0, PChar('Cant delete map res=' + IntToStr(res)), PChar('Map not deleted!'), MB_ICONINFORMATION or MB_OK or MB_DEFBUTTON1);
6185 Exit
6186 end;
6188 MessageBox(
6189 0,
6190 PChar(Format(_lc[I_MSG_MAP_DELETED_PROMT], [MapName])),
6191 PChar(_lc[I_MSG_MAP_DELETED]),
6192 MB_ICONINFORMATION or MB_OK or MB_DEFBUTTON1
6193 );
6195 // Удалили текущую карту - сохранять по старому ее нельзя:
6196 if OpenedMap = (FileName + ':\' + MapName) then
6197 begin
6198 OpenedMap := '';
6199 OpenedWAD := '';
6200 MainForm.Caption := FormCaption
6201 end
6202 end;
6204 procedure TMainForm.vleObjectPropertyKeyDown(Sender: TObject;
6205 var Key: Word; Shift: TShiftState);
6206 begin
6207 if Key = VK_RETURN then
6208 vleObjectPropertyApply(Sender);
6209 end;
6211 procedure MovePanel(var ID: DWORD; MoveType: Byte);
6212 var
6213 _id, a: Integer;
6214 tmp: TPanel;
6215 begin
6216 if (ID = 0) and (MoveType = 0) then
6217 Exit;
6218 if (ID = DWORD(High(gPanels))) and (MoveType <> 0) then
6219 Exit;
6220 if (ID > DWORD(High(gPanels))) then
6221 Exit;
6223 _id := Integer(ID);
6225 if MoveType = 0 then // to Back
6226 begin
6227 if gTriggers <> nil then
6228 for a := 0 to High(gTriggers) do
6229 with gTriggers[a] do
6230 begin
6231 if TriggerType = TRIGGER_NONE then
6232 Continue;
6234 if TexturePanel = _id then
6235 TexturePanel := 0
6236 else
6237 if (TexturePanel >= 0) and (TexturePanel < _id) then
6238 Inc(TexturePanel);
6240 case TriggerType of
6241 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
6242 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP,
6243 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
6244 if Data.PanelID = _id then
6245 Data.PanelID := 0
6246 else
6247 if (Data.PanelID >= 0) and (Data.PanelID < _id) then
6248 Inc(Data.PanelID);
6250 TRIGGER_SHOT:
6251 if Data.ShotPanelID = _id then
6252 Data.ShotPanelID := 0
6253 else
6254 if (Data.ShotPanelID >= 0) and (Data.ShotPanelID < _id) then
6255 Inc(Data.ShotPanelID);
6256 end;
6257 end;
6259 tmp := gPanels[_id];
6261 for a := _id downto 1 do
6262 gPanels[a] := gPanels[a-1];
6264 gPanels[0] := tmp;
6266 ID := 0;
6267 end
6268 else // to Front
6269 begin
6270 if gTriggers <> nil then
6271 for a := 0 to High(gTriggers) do
6272 with gTriggers[a] do
6273 begin
6274 if TriggerType = TRIGGER_NONE then
6275 Continue;
6277 if TexturePanel = _id then
6278 TexturePanel := High(gPanels)
6279 else
6280 if TexturePanel > _id then
6281 Dec(TexturePanel);
6283 case TriggerType of
6284 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
6285 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP,
6286 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
6287 if Data.PanelID = _id then
6288 Data.PanelID := High(gPanels)
6289 else
6290 if Data.PanelID > _id then
6291 Dec(Data.PanelID);
6293 TRIGGER_SHOT:
6294 if Data.ShotPanelID = _id then
6295 Data.ShotPanelID := High(gPanels)
6296 else
6297 if Data.ShotPanelID > _id then
6298 Dec(Data.ShotPanelID);
6299 end;
6300 end;
6302 tmp := gPanels[_id];
6304 for a := _id to High(gPanels)-1 do
6305 gPanels[a] := gPanels[a+1];
6307 gPanels[High(gPanels)] := tmp;
6309 ID := High(gPanels);
6310 end;
6311 end;
6313 procedure TMainForm.aMoveToBack(Sender: TObject);
6314 var
6315 a: Integer;
6316 begin
6317 if SelectedObjects = nil then
6318 Exit;
6320 for a := 0 to High(SelectedObjects) do
6321 with SelectedObjects[a] do
6322 if Live and (ObjectType = OBJECT_PANEL) then
6323 begin
6324 SelectedObjects[0] := SelectedObjects[a];
6325 SetLength(SelectedObjects, 1);
6326 MovePanel(ID, 0);
6327 FillProperty();
6328 Break;
6329 end;
6330 end;
6332 procedure TMainForm.aMoveToFore(Sender: TObject);
6333 var
6334 a: Integer;
6335 begin
6336 if SelectedObjects = nil then
6337 Exit;
6339 for a := 0 to High(SelectedObjects) do
6340 with SelectedObjects[a] do
6341 if Live and (ObjectType = OBJECT_PANEL) then
6342 begin
6343 SelectedObjects[0] := SelectedObjects[a];
6344 SetLength(SelectedObjects, 1);
6345 MovePanel(ID, 1);
6346 FillProperty();
6347 Break;
6348 end;
6349 end;
6351 procedure TMainForm.aSaveMapAsExecute(Sender: TObject);
6352 var
6353 idx: Integer;
6354 begin
6355 SaveDialog.Filter := _lc[I_FILE_FILTER_WAD];
6357 if not SaveDialog.Execute() then
6358 Exit;
6360 SaveMapForm.GetMaps(SaveDialog.FileName, True);
6362 if SaveMapForm.ShowModal() <> mrOK then
6363 Exit;
6365 SaveDialog.InitialDir := ExtractFileDir(SaveDialog.FileName);
6366 OpenedMap := SaveDialog.FileName+':\'+SaveMapForm.eMapName.Text;
6367 OpenedWAD := SaveDialog.FileName;
6369 idx := RecentFiles.IndexOf(OpenedMap);
6370 // Такая карта уже недавно открывалась:
6371 if idx >= 0 then
6372 RecentFiles.Delete(idx);
6373 RecentFiles.Insert(0, OpenedMap);
6374 RefreshRecentMenu;
6376 SaveMap(OpenedMap);
6378 gMapInfo.FileName := SaveDialog.FileName;
6379 gMapInfo.MapName := SaveMapForm.eMapName.Text;
6380 UpdateCaption(gMapInfo.Name, ExtractFileName(gMapInfo.FileName), gMapInfo.MapName);
6381 end;
6383 procedure TMainForm.aSelectAllExecute(Sender: TObject);
6384 var
6385 a: Integer;
6386 begin
6387 RemoveSelectFromObjects();
6389 case pcObjects.ActivePageIndex+1 of
6390 OBJECT_PANEL:
6391 if gPanels <> nil then
6392 for a := 0 to High(gPanels) do
6393 if gPanels[a].PanelType <> PANEL_NONE then
6394 SelectObject(OBJECT_PANEL, a, True);
6395 OBJECT_ITEM:
6396 if gItems <> nil then
6397 for a := 0 to High(gItems) do
6398 if gItems[a].ItemType <> ITEM_NONE then
6399 SelectObject(OBJECT_ITEM, a, True);
6400 OBJECT_MONSTER:
6401 if gMonsters <> nil then
6402 for a := 0 to High(gMonsters) do
6403 if gMonsters[a].MonsterType <> MONSTER_NONE then
6404 SelectObject(OBJECT_MONSTER, a, True);
6405 OBJECT_AREA:
6406 if gAreas <> nil then
6407 for a := 0 to High(gAreas) do
6408 if gAreas[a].AreaType <> AREA_NONE then
6409 SelectObject(OBJECT_AREA, a, True);
6410 OBJECT_TRIGGER:
6411 if gTriggers <> nil then
6412 for a := 0 to High(gTriggers) do
6413 if gTriggers[a].TriggerType <> TRIGGER_NONE then
6414 SelectObject(OBJECT_TRIGGER, a, True);
6415 end;
6417 RecountSelectedObjects();
6418 end;
6420 procedure TMainForm.tbGridOnClick(Sender: TObject);
6421 begin
6422 DotEnable := not DotEnable;
6423 (Sender as TToolButton).Down := DotEnable;
6424 end;
6426 procedure TMainForm.OnIdle(Sender: TObject; var Done: Boolean);
6427 begin
6428 // FIXME: this is a shitty hack
6429 if not gDataLoaded then
6430 begin
6431 e_WriteLog('Init OpenGL', MSG_NOTIFY);
6432 e_InitGL();
6433 e_WriteLog('Loading data', MSG_NOTIFY);
6434 LoadStdFont('STDTXT', 'STDFONT', gEditorFont);
6435 e_WriteLog('Loading more data', MSG_NOTIFY);
6436 LoadData();
6437 e_WriteLog('Loading even more data', MSG_NOTIFY);
6438 gDataLoaded := True;
6439 MainForm.FormResize(nil);
6440 end;
6441 Draw();
6442 end;
6444 procedure TMainForm.miMapPreviewClick(Sender: TObject);
6445 begin
6446 if PreviewMode = 2 then
6447 Exit;
6449 if PreviewMode = 0 then
6450 begin
6451 Splitter2.Visible := False;
6452 Splitter1.Visible := False;
6453 StatusBar.Visible := False;
6454 PanelObjs.Visible := False;
6455 PanelProps.Visible := False;
6456 MainToolBar.Visible := False;
6457 sbHorizontal.Visible := False;
6458 sbVertical.Visible := False;
6459 end
6460 else
6461 begin
6462 StatusBar.Visible := True;
6463 PanelObjs.Visible := True;
6464 PanelProps.Visible := True;
6465 Splitter2.Visible := True;
6466 Splitter1.Visible := True;
6467 MainToolBar.Visible := True;
6468 sbHorizontal.Visible := True;
6469 sbVertical.Visible := True;
6470 end;
6472 PreviewMode := PreviewMode xor 1;
6473 (Sender as TMenuItem).Checked := PreviewMode > 0;
6475 FormResize(Self);
6476 end;
6478 procedure TMainForm.miLayer1Click(Sender: TObject);
6479 begin
6480 SwitchLayer(LAYER_BACK);
6481 end;
6483 procedure TMainForm.miLayer2Click(Sender: TObject);
6484 begin
6485 SwitchLayer(LAYER_WALLS);
6486 end;
6488 procedure TMainForm.miLayer3Click(Sender: TObject);
6489 begin
6490 SwitchLayer(LAYER_FOREGROUND);
6491 end;
6493 procedure TMainForm.miLayer4Click(Sender: TObject);
6494 begin
6495 SwitchLayer(LAYER_STEPS);
6496 end;
6498 procedure TMainForm.miLayer5Click(Sender: TObject);
6499 begin
6500 SwitchLayer(LAYER_WATER);
6501 end;
6503 procedure TMainForm.miLayer6Click(Sender: TObject);
6504 begin
6505 SwitchLayer(LAYER_ITEMS);
6506 end;
6508 procedure TMainForm.miLayer7Click(Sender: TObject);
6509 begin
6510 SwitchLayer(LAYER_MONSTERS);
6511 end;
6513 procedure TMainForm.miLayer8Click(Sender: TObject);
6514 begin
6515 SwitchLayer(LAYER_AREAS);
6516 end;
6518 procedure TMainForm.miLayer9Click(Sender: TObject);
6519 begin
6520 SwitchLayer(LAYER_TRIGGERS);
6521 end;
6523 procedure TMainForm.tbShowClick(Sender: TObject);
6524 var
6525 a: Integer;
6526 b: Boolean;
6527 begin
6528 b := True;
6529 for a := 0 to High(LayerEnabled) do
6530 b := b and LayerEnabled[a];
6532 b := not b;
6534 ShowLayer(LAYER_BACK, b);
6535 ShowLayer(LAYER_WALLS, b);
6536 ShowLayer(LAYER_FOREGROUND, b);
6537 ShowLayer(LAYER_STEPS, b);
6538 ShowLayer(LAYER_WATER, b);
6539 ShowLayer(LAYER_ITEMS, b);
6540 ShowLayer(LAYER_MONSTERS, b);
6541 ShowLayer(LAYER_AREAS, b);
6542 ShowLayer(LAYER_TRIGGERS, b);
6543 end;
6545 procedure TMainForm.miMiniMapClick(Sender: TObject);
6546 begin
6547 SwitchMap();
6548 end;
6550 procedure TMainForm.miSwitchGridClick(Sender: TObject);
6551 begin
6552 if DotStep = DotStepOne then
6553 DotStep := DotStepTwo
6554 else
6555 DotStep := DotStepOne;
6557 MousePos.X := (MousePos.X div DotStep) * DotStep;
6558 MousePos.Y := (MousePos.Y div DotStep) * DotStep;
6559 end;
6561 procedure TMainForm.miShowEdgesClick(Sender: TObject);
6562 begin
6563 ShowEdges();
6564 end;
6566 procedure TMainForm.miSnapToGridClick(Sender: TObject);
6567 begin
6568 SnapToGrid := not SnapToGrid;
6570 MousePos.X := (MousePos.X div DotStep) * DotStep;
6571 MousePos.Y := (MousePos.Y div DotStep) * DotStep;
6573 miSnapToGrid.Checked := SnapToGrid;
6574 end;
6576 procedure TMainForm.minexttabClick(Sender: TObject);
6577 begin
6578 if pcObjects.ActivePageIndex < pcObjects.PageCount-1 then
6579 pcObjects.ActivePageIndex := pcObjects.ActivePageIndex+1
6580 else
6581 pcObjects.ActivePageIndex := 0;
6582 end;
6584 procedure TMainForm.miSaveMiniMapClick(Sender: TObject);
6585 begin
6586 SaveMiniMapForm.ShowModal();
6587 end;
6589 procedure TMainForm.bClearTextureClick(Sender: TObject);
6590 begin
6591 lbTextureList.ItemIndex := -1;
6592 lTextureWidth.Caption := '';
6593 lTextureHeight.Caption := '';
6594 end;
6596 procedure TMainForm.miPackMapClick(Sender: TObject);
6597 begin
6598 PackMapForm.ShowModal();
6599 end;
6601 procedure TMainForm.miMapTestSettingsClick(Sender: TObject);
6602 begin
6603 MapTestForm.ShowModal();
6604 end;
6606 procedure TMainForm.miTestMapClick(Sender: TObject);
6607 var
6608 cmd, mapWAD, mapToRun, tempWAD: String;
6609 opt: LongWord;
6610 time: Integer;
6611 proc: TProcessUTF8;
6612 res: Boolean;
6613 begin
6614 mapToRun := '';
6615 if OpenedMap <> '' then
6616 begin
6617 // Указываем текущую карту для теста:
6618 g_ProcessResourceStr(OpenedMap, @mapWAD, nil, @mapToRun);
6619 mapToRun := mapWAD + ':\' + mapToRun;
6620 mapToRun := ExtractRelativePath(ExtractFilePath(TestD2dExe) + 'maps/', mapToRun);
6621 end;
6622 // Сохраняем временную карту:
6623 time := 0;
6624 repeat
6625 mapWAD := ExtractFilePath(TestD2dExe) + Format('maps/temp%.4d.wad', [time]);
6626 Inc(time);
6627 until not FileExists(mapWAD);
6628 tempWAD := mapWAD + ':\' + TEST_MAP_NAME;
6629 SaveMap(tempWAD);
6631 tempWAD := ExtractRelativePath(ExtractFilePath(TestD2dExe) + 'maps/', tempWAD);
6632 // Если карта не была открыта, указываем временную в качестве текущей:
6633 if mapToRun = '' then
6634 mapToRun := tempWAD;
6636 // Опции игры:
6637 opt := 32 + 64;
6638 if TestOptionsTwoPlayers then
6639 opt := opt + 1;
6640 if TestOptionsTeamDamage then
6641 opt := opt + 2;
6642 if TestOptionsAllowExit then
6643 opt := opt + 4;
6644 if TestOptionsWeaponStay then
6645 opt := opt + 8;
6646 if TestOptionsMonstersDM then
6647 opt := opt + 16;
6649 // Составляем командную строку:
6650 cmd := '-map "' + mapToRun + '"';
6651 cmd := cmd + ' -testmap "' + tempWAD + '"';
6652 cmd := cmd + ' -gm ' + TestGameMode;
6653 cmd := cmd + ' -limt ' + TestLimTime;
6654 cmd := cmd + ' -lims ' + TestLimScore;
6655 cmd := cmd + ' -opt ' + IntToStr(opt);
6657 if TestMapOnce then
6658 cmd := cmd + ' --close';
6660 cmd := cmd + ' --debug';
6662 // Запускаем:
6663 proc := TProcessUTF8.Create(nil);
6664 proc.Executable := TestD2dExe;
6665 proc.Parameters.Add(cmd);
6666 res := True;
6667 try
6668 proc.Execute();
6669 except
6670 res := False;
6671 end;
6672 if res then
6673 begin
6674 Application.Minimize();
6675 proc.WaitOnExit();
6676 end;
6677 if (not res) or (proc.ExitCode < 0) then
6678 begin
6679 MessageBox(0, 'FIXME',
6680 PChar(_lc[I_MSG_EXEC_ERROR]),
6681 MB_OK or MB_ICONERROR);
6682 end;
6683 proc.Free();
6685 SysUtils.DeleteFile(mapWAD);
6686 Application.Restore();
6687 end;
6689 procedure TMainForm.sbVerticalScroll(Sender: TObject;
6690 ScrollCode: TScrollCode; var ScrollPos: Integer);
6691 begin
6692 MapOffset.Y := -Normalize16(sbVertical.Position);
6693 end;
6695 procedure TMainForm.sbHorizontalScroll(Sender: TObject;
6696 ScrollCode: TScrollCode; var ScrollPos: Integer);
6697 begin
6698 MapOffset.X := -Normalize16(sbHorizontal.Position);
6699 end;
6701 procedure TMainForm.miOpenWadMapClick(Sender: TObject);
6702 begin
6703 if OpenedWAD <> '' then
6704 begin
6705 OpenMap(OpenedWAD, '');
6706 end;
6707 end;
6709 procedure TMainForm.selectall1Click(Sender: TObject);
6710 var
6711 a: Integer;
6712 begin
6713 RemoveSelectFromObjects();
6715 if gPanels <> nil then
6716 for a := 0 to High(gPanels) do
6717 if gPanels[a].PanelType <> PANEL_NONE then
6718 SelectObject(OBJECT_PANEL, a, True);
6720 if gItems <> nil then
6721 for a := 0 to High(gItems) do
6722 if gItems[a].ItemType <> ITEM_NONE then
6723 SelectObject(OBJECT_ITEM, a, True);
6725 if gMonsters <> nil then
6726 for a := 0 to High(gMonsters) do
6727 if gMonsters[a].MonsterType <> MONSTER_NONE then
6728 SelectObject(OBJECT_MONSTER, a, True);
6730 if gAreas <> nil then
6731 for a := 0 to High(gAreas) do
6732 if gAreas[a].AreaType <> AREA_NONE then
6733 SelectObject(OBJECT_AREA, a, True);
6735 if gTriggers <> nil then
6736 for a := 0 to High(gTriggers) do
6737 if gTriggers[a].TriggerType <> TRIGGER_NONE then
6738 SelectObject(OBJECT_TRIGGER, a, True);
6740 RecountSelectedObjects();
6741 end;
6743 procedure TMainForm.Splitter1CanResize(Sender: TObject;
6744 var NewSize: Integer; var Accept: Boolean);
6745 begin
6746 Accept := (NewSize > 140);
6747 end;
6749 procedure TMainForm.Splitter2CanResize(Sender: TObject;
6750 var NewSize: Integer; var Accept: Boolean);
6751 begin
6752 Accept := (NewSize > 110);
6753 end;
6755 procedure TMainForm.vleObjectPropertyEnter(Sender: TObject);
6756 begin
6757 EditingProperties := True;
6758 end;
6760 procedure TMainForm.vleObjectPropertyExit(Sender: TObject);
6761 begin
6762 EditingProperties := False;
6763 end;
6765 procedure TMainForm.FormKeyUp(Sender: TObject; var Key: Word;
6766 Shift: TShiftState);
6767 begin
6768 // Объекты передвигались:
6769 if MainForm.ActiveControl = RenderPanel then
6770 begin
6771 if (Key = VK_NUMPAD4) or
6772 (Key = VK_NUMPAD6) or
6773 (Key = VK_NUMPAD8) or
6774 (Key = VK_NUMPAD5) or
6775 (Key = Ord('V')) then
6776 FillProperty();
6777 end;
6778 // Быстрое превью карты:
6779 if Key = Ord('E') then
6780 begin
6781 if PreviewMode = 2 then
6782 PreviewMode := 0;
6783 end;
6784 RenderPanelMouseMove(Sender, Shift, RenderMousePos().X, RenderMousePos().Y);
6785 end;
6787 end.