DEADSOFTWARE

Main: Add Ctrl+Alt switch for object range selection
[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 end;
272 const
273 LAYER_BACK = 0;
274 LAYER_WALLS = 1;
275 LAYER_FOREGROUND = 2;
276 LAYER_STEPS = 3;
277 LAYER_WATER = 4;
278 LAYER_ITEMS = 5;
279 LAYER_MONSTERS = 6;
280 LAYER_AREAS = 7;
281 LAYER_TRIGGERS = 8;
283 TEST_MAP_NAME = '$$$_TEST_$$$';
284 LANGUAGE_FILE_NAME = '_Editor.txt';
286 var
287 MainForm: TMainForm;
288 EditorDir: String;
289 OpenedMap: String;
290 OpenedWAD: String;
292 DotColor: TColor;
293 DotEnable: Boolean;
294 DotStep: Byte;
295 DotStepOne, DotStepTwo: Byte;
296 DotSize: Byte;
297 DrawTexturePanel: Boolean;
298 DrawPanelSize: Boolean;
299 BackColor: TColor;
300 PreviewColor: TColor;
301 UseCheckerboard: Boolean;
302 Scale: Byte;
303 RecentCount: Integer;
304 RecentFiles: TStringList;
305 slInvalidTextures: TStringList;
307 TestGameMode: String;
308 TestLimTime: String;
309 TestLimScore: String;
310 TestOptionsTwoPlayers: Boolean;
311 TestOptionsTeamDamage: Boolean;
312 TestOptionsAllowExit: Boolean;
313 TestOptionsWeaponStay: Boolean;
314 TestOptionsMonstersDM: Boolean;
315 TestD2dExe: String;
316 TestMapOnce: Boolean;
318 LayerEnabled: Array [LAYER_BACK..LAYER_TRIGGERS] of Boolean =
319 (True, True, True, True, True, True, True, True, True);
320 PreviewMode: Byte = 0;
321 gLanguage: String;
323 FormCaption: String;
326 procedure OpenMap(FileName: String; mapN: String);
327 function AddTexture(aWAD, aSection, aTex: String; silent: Boolean): Boolean;
328 procedure RemoveSelectFromObjects();
329 procedure ChangeShownProperty(Name: String; NewValue: String);
331 implementation
333 uses
334 f_options, e_graphics, e_log, GL, Math,
335 f_mapoptions, g_basic, f_about, f_mapoptimization,
336 f_mapcheck, f_addresource_texture, g_textures,
337 f_activationtype, f_keys,
338 MAPREADER, f_selectmap, f_savemap, WADEDITOR, WADSTRUCT, MAPDEF,
339 g_map, f_saveminimap, f_addresource, CONFIG, f_packmap,
340 f_addresource_sound, f_maptest, f_choosetype,
341 g_language, f_selectlang, ClipBrd;
343 const
344 UNDO_DELETE_PANEL = 1;
345 UNDO_DELETE_ITEM = 2;
346 UNDO_DELETE_AREA = 3;
347 UNDO_DELETE_MONSTER = 4;
348 UNDO_DELETE_TRIGGER = 5;
349 UNDO_ADD_PANEL = 6;
350 UNDO_ADD_ITEM = 7;
351 UNDO_ADD_AREA = 8;
352 UNDO_ADD_MONSTER = 9;
353 UNDO_ADD_TRIGGER = 10;
354 UNDO_MOVE_PANEL = 11;
355 UNDO_MOVE_ITEM = 12;
356 UNDO_MOVE_AREA = 13;
357 UNDO_MOVE_MONSTER = 14;
358 UNDO_MOVE_TRIGGER = 15;
359 UNDO_RESIZE_PANEL = 16;
360 UNDO_RESIZE_TRIGGER = 17;
362 MOUSEACTION_NONE = 0;
363 MOUSEACTION_DRAWPANEL = 1;
364 MOUSEACTION_DRAWTRIGGER = 2;
365 MOUSEACTION_MOVEOBJ = 3;
366 MOUSEACTION_RESIZE = 4;
367 MOUSEACTION_MOVEMAP = 5;
368 MOUSEACTION_DRAWPRESS = 6;
369 MOUSEACTION_NOACTION = 7;
371 RESIZETYPE_NONE = 0;
372 RESIZETYPE_VERTICAL = 1;
373 RESIZETYPE_HORIZONTAL = 2;
375 RESIZEDIR_NONE = 0;
376 RESIZEDIR_DOWN = 1;
377 RESIZEDIR_UP = 2;
378 RESIZEDIR_RIGHT = 3;
379 RESIZEDIR_LEFT = 4;
381 SELECTFLAG_NONE = 0;
382 SELECTFLAG_TELEPORT = 1;
383 SELECTFLAG_DOOR = 2;
384 SELECTFLAG_TEXTURE = 3;
385 SELECTFLAG_LIFT = 4;
386 SELECTFLAG_MONSTER = 5;
387 SELECTFLAG_SPAWNPOINT = 6;
388 SELECTFLAG_SHOTPANEL = 7;
389 SELECTFLAG_SELECTED = 8;
391 RECENT_FILES_MENU_START = 12;
393 CLIPBOARD_SIG = 'DF:ED';
395 type
396 TUndoRec = record
397 UndoType: Byte;
398 case Byte of
399 UNDO_DELETE_PANEL: (Panel: ^TPanel);
400 UNDO_DELETE_ITEM: (Item: TItem);
401 UNDO_DELETE_AREA: (Area: TArea);
402 UNDO_DELETE_MONSTER: (Monster: TMonster);
403 UNDO_DELETE_TRIGGER: (Trigger: TTrigger);
404 UNDO_ADD_PANEL,
405 UNDO_ADD_ITEM,
406 UNDO_ADD_AREA,
407 UNDO_ADD_MONSTER,
408 UNDO_ADD_TRIGGER: (AddID: DWORD);
409 UNDO_MOVE_PANEL,
410 UNDO_MOVE_ITEM,
411 UNDO_MOVE_AREA,
412 UNDO_MOVE_MONSTER,
413 UNDO_MOVE_TRIGGER: (MoveID: DWORD; dX, dY: Integer);
414 UNDO_RESIZE_PANEL,
415 UNDO_RESIZE_TRIGGER: (ResizeID: DWORD; dW, dH: Integer);
416 end;
418 TCopyRec = record
419 ObjectType: Byte;
420 ID: Cardinal;
421 case Byte of
422 OBJECT_PANEL: (Panel: ^TPanel);
423 OBJECT_ITEM: (Item: TItem);
424 OBJECT_AREA: (Area: TArea);
425 OBJECT_MONSTER: (Monster: TMonster);
426 OBJECT_TRIGGER: (Trigger: TTrigger);
427 end;
429 TCopyRecArray = Array of TCopyRec;
431 var
432 gEditorFont: DWORD;
433 gDataLoaded: Boolean = False;
434 ShowMap: Boolean = False;
435 DrawRect: PRect = nil;
436 SnapToGrid: Boolean = True;
438 MousePos: Types.TPoint;
439 LastMovePoint: Types.TPoint;
440 MouseLDown: Boolean;
441 MouseRDown: Boolean;
442 MouseLDownPos: Types.TPoint;
443 MouseRDownPos: Types.TPoint;
444 WASDOffset: 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();
743 // Отображаем свойства если выделен только один объект:
744 if SelectedObjectCount() <> 1 then
745 Exit;
747 _id := GetFirstSelected();
748 if not SelectedObjects[_id].Live then
749 Exit;
751 with MainForm.vleObjectProperty do
752 with ItemProps[InsertRow(_lc[I_PROP_ID], IntToStr(SelectedObjects[_id].ID), True)] do
753 begin
754 EditStyle := esSimple;
755 ReadOnly := True;
756 end;
758 case SelectedObjects[0].ObjectType of
759 OBJECT_PANEL:
760 begin
761 with MainForm.vleObjectProperty,
762 gPanels[SelectedObjects[_id].ID] do
763 begin
764 with ItemProps[InsertRow(_lc[I_PROP_X], IntToStr(X), True)] do
765 begin
766 EditStyle := esSimple;
767 MaxLength := 5;
768 end;
770 with ItemProps[InsertRow(_lc[I_PROP_Y], IntToStr(Y), True)] do
771 begin
772 EditStyle := esSimple;
773 MaxLength := 5;
774 end;
776 with ItemProps[InsertRow(_lc[I_PROP_WIDTH], IntToStr(Width), True)] do
777 begin
778 EditStyle := esSimple;
779 MaxLength := 5;
780 end;
782 with ItemProps[InsertRow(_lc[I_PROP_HEIGHT], IntToStr(Height), True)] do
783 begin
784 EditStyle := esSimple;
785 MaxLength := 5;
786 end;
788 with ItemProps[InsertRow(_lc[I_PROP_PANEL_TYPE], GetPanelName(PanelType), True)] do
789 begin
790 EditStyle := esEllipsis;
791 ReadOnly := True;
792 end;
794 if IsTexturedPanel(PanelType) then
795 begin // Может быть текстура
796 with ItemProps[InsertRow(_lc[I_PROP_PANEL_TEX], TextureName, True)] do
797 begin
798 EditStyle := esEllipsis;
799 ReadOnly := True;
800 end;
802 if TextureName <> '' then
803 begin // Есть текстура
804 with ItemProps[InsertRow(_lc[I_PROP_PANEL_ALPHA], IntToStr(Alpha), True)] do
805 begin
806 EditStyle := esSimple;
807 MaxLength := 3;
808 end;
810 with ItemProps[InsertRow(_lc[I_PROP_PANEL_BLEND], BoolNames[Blending], True)] do
811 begin
812 EditStyle := esPickList;
813 ReadOnly := True;
814 end;
815 end;
816 end;
817 end;
818 end;
820 OBJECT_ITEM:
821 begin
822 with MainForm.vleObjectProperty,
823 gItems[SelectedObjects[_id].ID] do
824 begin
825 with ItemProps[InsertRow(_lc[I_PROP_X], IntToStr(X), True)] do
826 begin
827 EditStyle := esSimple;
828 MaxLength := 5;
829 end;
831 with ItemProps[InsertRow(_lc[I_PROP_Y], IntToStr(Y), True)] do
832 begin
833 EditStyle := esSimple;
834 MaxLength := 5;
835 end;
837 with ItemProps[InsertRow(_lc[I_PROP_DM_ONLY], BoolNames[OnlyDM], True)] do
838 begin
839 EditStyle := esPickList;
840 ReadOnly := True;
841 end;
843 with ItemProps[InsertRow(_lc[I_PROP_ITEM_FALLS], BoolNames[Fall], True)] do
844 begin
845 EditStyle := esPickList;
846 ReadOnly := True;
847 end;
848 end;
849 end;
851 OBJECT_MONSTER:
852 begin
853 with MainForm.vleObjectProperty,
854 gMonsters[SelectedObjects[_id].ID] do
855 begin
856 with ItemProps[InsertRow(_lc[I_PROP_X], IntToStr(X), True)] do
857 begin
858 EditStyle := esSimple;
859 MaxLength := 5;
860 end;
862 with ItemProps[InsertRow(_lc[I_PROP_Y], IntToStr(Y), True)] do
863 begin
864 EditStyle := esSimple;
865 MaxLength := 5;
866 end;
868 with ItemProps[InsertRow(_lc[I_PROP_DIRECTION], DirNames[Direction], True)] do
869 begin
870 EditStyle := esPickList;
871 ReadOnly := True;
872 end;
873 end;
874 end;
876 OBJECT_AREA:
877 begin
878 with MainForm.vleObjectProperty,
879 gAreas[SelectedObjects[_id].ID] do
880 begin
881 with ItemProps[InsertRow(_lc[I_PROP_X], IntToStr(X), True)] do
882 begin
883 EditStyle := esSimple;
884 MaxLength := 5;
885 end;
887 with ItemProps[InsertRow(_lc[I_PROP_Y], IntToStr(Y), True)] do
888 begin
889 EditStyle := esSimple;
890 MaxLength := 5;
891 end;
893 with ItemProps[InsertRow(_lc[I_PROP_DIRECTION], DirNames[Direction], True)] do
894 begin
895 EditStyle := esPickList;
896 ReadOnly := True;
897 end;
898 end;
899 end;
901 OBJECT_TRIGGER:
902 begin
903 with MainForm.vleObjectProperty,
904 gTriggers[SelectedObjects[_id].ID] do
905 begin
906 with ItemProps[InsertRow(_lc[I_PROP_TR_TYPE], GetTriggerName(TriggerType), True)] do
907 begin
908 EditStyle := esSimple;
909 ReadOnly := True;
910 end;
912 with ItemProps[InsertRow(_lc[I_PROP_X], IntToStr(X), True)] do
913 begin
914 EditStyle := esSimple;
915 MaxLength := 5;
916 end;
918 with ItemProps[InsertRow(_lc[I_PROP_Y], IntToStr(Y), True)] do
919 begin
920 EditStyle := esSimple;
921 MaxLength := 5;
922 end;
924 with ItemProps[InsertRow(_lc[I_PROP_WIDTH], IntToStr(Width), True)] do
925 begin
926 EditStyle := esSimple;
927 MaxLength := 5;
928 end;
930 with ItemProps[InsertRow(_lc[I_PROP_HEIGHT], IntToStr(Height), True)] do
931 begin
932 EditStyle := esSimple;
933 MaxLength := 5;
934 end;
936 with ItemProps[InsertRow(_lc[I_PROP_TR_ENABLED], BoolNames[Enabled], True)] do
937 begin
938 EditStyle := esPickList;
939 ReadOnly := True;
940 end;
942 with ItemProps[InsertRow(_lc[I_PROP_TR_TEXTURE_PANEL], IntToStr(TexturePanel), True)] do
943 begin
944 EditStyle := esEllipsis;
945 ReadOnly := True;
946 end;
948 with ItemProps[InsertRow(_lc[I_PROP_TR_ACTIVATION], ActivateToStr(ActivateType), True)] do
949 begin
950 EditStyle := esEllipsis;
951 ReadOnly := True;
952 end;
954 with ItemProps[InsertRow(_lc[I_PROP_TR_KEYS], KeyToStr(Key), True)] do
955 begin
956 EditStyle := esEllipsis;
957 ReadOnly := True;
958 end;
960 case TriggerType of
961 TRIGGER_EXIT:
962 begin
963 str := win2utf(Data.MapName);
964 with ItemProps[InsertRow(_lc[I_PROP_TR_NEXT_MAP], str, True)] do
965 begin
966 EditStyle := esEllipsis;
967 ReadOnly := True;
968 end;
969 end;
971 TRIGGER_TELEPORT:
972 begin
973 with ItemProps[InsertRow(_lc[I_PROP_TR_TELEPORT_TO], Format('(%d:%d)', [Data.TargetPoint.X, Data.TargetPoint.Y]), True)] do
974 begin
975 EditStyle := esEllipsis;
976 ReadOnly := True;
977 end;
979 with ItemProps[InsertRow(_lc[I_PROP_TR_D2D], BoolNames[Data.d2d_teleport], True)] do
980 begin
981 EditStyle := esPickList;
982 ReadOnly := True;
983 end;
985 with ItemProps[InsertRow(_lc[I_PROP_TR_TELEPORT_SILENT], BoolNames[Data.silent_teleport], True)] do
986 begin
987 EditStyle := esPickList;
988 ReadOnly := True;
989 end;
991 with ItemProps[InsertRow(_lc[I_PROP_TR_TELEPORT_DIR], DirNamesAdv[Data.TlpDir], True)] do
992 begin
993 EditStyle := esPickList;
994 ReadOnly := True;
995 end;
996 end;
998 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR,
999 TRIGGER_DOOR, TRIGGER_DOOR5:
1000 begin
1001 with ItemProps[InsertRow(_lc[I_PROP_TR_DOOR_PANEL], IntToStr(Data.PanelID), True)] do
1002 begin
1003 EditStyle := esEllipsis;
1004 ReadOnly := True;
1005 end;
1007 with ItemProps[InsertRow(_lc[I_PROP_TR_SILENT], BoolNames[Data.NoSound], True)] do
1008 begin
1009 EditStyle := esPickList;
1010 ReadOnly := True;
1011 end;
1013 with ItemProps[InsertRow(_lc[I_PROP_TR_D2D], BoolNames[Data.d2d_doors], True)] do
1014 begin
1015 EditStyle := esPickList;
1016 ReadOnly := True;
1017 end;
1018 end;
1020 TRIGGER_CLOSETRAP, TRIGGER_TRAP:
1021 begin
1022 with ItemProps[InsertRow(_lc[I_PROP_TR_TRAP_PANEL], IntToStr(Data.PanelID), True)] do
1023 begin
1024 EditStyle := esEllipsis;
1025 ReadOnly := True;
1026 end;
1028 with ItemProps[InsertRow(_lc[I_PROP_TR_SILENT], BoolNames[Data.NoSound], True)] do
1029 begin
1030 EditStyle := esPickList;
1031 ReadOnly := True;
1032 end;
1034 with ItemProps[InsertRow(_lc[I_PROP_TR_D2D], BoolNames[Data.d2d_doors], True)] do
1035 begin
1036 EditStyle := esPickList;
1037 ReadOnly := True;
1038 end;
1039 end;
1041 TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF,
1042 TRIGGER_ONOFF:
1043 begin
1044 with ItemProps[InsertRow(_lc[I_PROP_TR_EX_AREA],
1045 Format('(%d:%d %d:%d)', [Data.tX, Data.tY, Data.tWidth, Data.tHeight]), True)] do
1046 begin
1047 EditStyle := esEllipsis;
1048 ReadOnly := True;
1049 end;
1051 with ItemProps[InsertRow(_lc[I_PROP_TR_EX_DELAY], IntToStr(Data.Wait), True)] do
1052 begin
1053 EditStyle := esSimple;
1054 MaxLength := 5;
1055 end;
1057 with ItemProps[InsertRow(_lc[I_PROP_TR_EX_COUNT], IntToStr(Data.Count), True)] do
1058 begin
1059 EditStyle := esSimple;
1060 MaxLength := 5;
1061 end;
1063 with ItemProps[InsertRow(_lc[I_PROP_TR_EX_MONSTER], IntToStr(Data.MonsterID-1), True)] do
1064 begin
1065 EditStyle := esEllipsis;
1066 ReadOnly := True;
1067 end;
1069 if TriggerType = TRIGGER_PRESS then
1070 with ItemProps[InsertRow(_lc[I_PROP_TR_EX_RANDOM], BoolNames[Data.ExtRandom], True)] do
1071 begin
1072 EditStyle := esPickList;
1073 ReadOnly := True;
1074 end;
1075 end;
1077 TRIGGER_SECRET:
1080 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
1081 begin
1082 with ItemProps[InsertRow(_lc[I_PROP_TR_LIFT_PANEL], IntToStr(Data.PanelID), True)] do
1083 begin
1084 EditStyle := esEllipsis;
1085 ReadOnly := True;
1086 end;
1088 with ItemProps[InsertRow(_lc[I_PROP_TR_SILENT], BoolNames[Data.NoSound], True)] do
1089 begin
1090 EditStyle := esPickList;
1091 ReadOnly := True;
1092 end;
1094 with ItemProps[InsertRow(_lc[I_PROP_TR_D2D], BoolNames[Data.d2d_doors], True)] do
1095 begin
1096 EditStyle := esPickList;
1097 ReadOnly := True;
1098 end;
1099 end;
1101 TRIGGER_TEXTURE:
1102 begin
1103 with ItemProps[InsertRow(_lc[I_PROP_TR_TEXTURE_ONCE], BoolNames[Data.ActivateOnce], True)] do
1104 begin
1105 EditStyle := esPickList;
1106 ReadOnly := True;
1107 end;
1109 with ItemProps[InsertRow(_lc[I_PROP_TR_TEXTURE_ANIM_ONCE], BoolNames[Data.AnimOnce], True)] do
1110 begin
1111 EditStyle := esPickList;
1112 ReadOnly := True;
1113 end;
1114 end;
1116 TRIGGER_SOUND:
1117 begin
1118 str := win2utf(Data.SoundName);
1119 with ItemProps[InsertRow(_lc[I_PROP_TR_SOUND_NAME], str, True)] do
1120 begin
1121 EditStyle := esEllipsis;
1122 ReadOnly := True;
1123 end;
1125 with ItemProps[InsertRow(_lc[I_PROP_TR_SOUND_VOLUME], IntToStr(Data.Volume), True)] do
1126 begin
1127 EditStyle := esSimple;
1128 MaxLength := 3;
1129 end;
1131 with ItemProps[InsertRow(_lc[I_PROP_TR_SOUND_PAN], IntToStr(Data.Pan), True)] do
1132 begin
1133 EditStyle := esSimple;
1134 MaxLength := 3;
1135 end;
1137 with ItemProps[InsertRow(_lc[I_PROP_TR_SOUND_COUNT], IntToStr(Data.PlayCount), True)] do
1138 begin
1139 EditStyle := esSimple;
1140 MaxLength := 3;
1141 end;
1143 with ItemProps[InsertRow(_lc[I_PROP_TR_SOUND_LOCAL], BoolNames[Data.Local], True)] do
1144 begin
1145 EditStyle := esPickList;
1146 ReadOnly := True;
1147 end;
1149 with ItemProps[InsertRow(_lc[I_PROP_TR_SOUND_SWITCH], BoolNames[Data.SoundSwitch], True)] do
1150 begin
1151 EditStyle := esPickList;
1152 ReadOnly := True;
1153 end;
1154 end;
1156 TRIGGER_SPAWNMONSTER:
1157 begin
1158 with ItemProps[InsertRow(_lc[I_PROP_TR_MONSTER_TYPE], MonsterToStr(Data.MonType), True)] do
1159 begin
1160 EditStyle := esEllipsis;
1161 ReadOnly := True;
1162 end;
1164 with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_TO],
1165 Format('(%d:%d)', [Data.MonPos.X, Data.MonPos.Y]), True)] do
1166 begin
1167 EditStyle := esEllipsis;
1168 ReadOnly := True;
1169 end;
1171 with ItemProps[InsertRow(_lc[I_PROP_DIRECTION], DirNames[TDirection(Data.MonDir)], True)] do
1172 begin
1173 EditStyle := esPickList;
1174 ReadOnly := True;
1175 end;
1177 with ItemProps[InsertRow(_lc[I_PROP_TR_HEALTH], IntToStr(Data.MonHealth), True)] do
1178 begin
1179 EditStyle := esSimple;
1180 MaxLength := 5;
1181 end;
1183 with ItemProps[InsertRow(_lc[I_PROP_TR_MONSTER_ACTIVE], BoolNames[Data.MonActive], True)] do
1184 begin
1185 EditStyle := esPickList;
1186 ReadOnly := True;
1187 end;
1189 with ItemProps[InsertRow(_lc[I_PROP_TR_COUNT], IntToStr(Data.MonCount), True)] do
1190 begin
1191 EditStyle := esSimple;
1192 MaxLength := 5;
1193 end;
1195 with ItemProps[InsertRow(_lc[I_PROP_TR_FX_TYPE], EffectToStr(Data.MonEffect), True)] do
1196 begin
1197 EditStyle := esEllipsis;
1198 ReadOnly := True;
1199 end;
1201 with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_MAX], IntToStr(Data.MonMax), True)] do
1202 begin
1203 EditStyle := esSimple;
1204 MaxLength := 5;
1205 end;
1207 with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_DELAY], IntToStr(Data.MonDelay), True)] do
1208 begin
1209 EditStyle := esSimple;
1210 MaxLength := 5;
1211 end;
1213 case Data.MonBehav of
1214 1: str := _lc[I_PROP_TR_MONSTER_BEHAVIOUR_1];
1215 2: str := _lc[I_PROP_TR_MONSTER_BEHAVIOUR_2];
1216 3: str := _lc[I_PROP_TR_MONSTER_BEHAVIOUR_3];
1217 4: str := _lc[I_PROP_TR_MONSTER_BEHAVIOUR_4];
1218 5: str := _lc[I_PROP_TR_MONSTER_BEHAVIOUR_5];
1219 else str := _lc[I_PROP_TR_MONSTER_BEHAVIOUR_0];
1220 end;
1221 with ItemProps[InsertRow(_lc[I_PROP_TR_MONSTER_BEHAVIOUR], str, True)] do
1222 begin
1223 EditStyle := esPickList;
1224 ReadOnly := True;
1225 end;
1226 end;
1228 TRIGGER_SPAWNITEM:
1229 begin
1230 with ItemProps[InsertRow(_lc[I_PROP_TR_ITEM_TYPE], ItemToStr(Data.ItemType), True)] do
1231 begin
1232 EditStyle := esEllipsis;
1233 ReadOnly := True;
1234 end;
1236 with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_TO],
1237 Format('(%d:%d)', [Data.ItemPos.X, Data.ItemPos.Y]), True)] do
1238 begin
1239 EditStyle := esEllipsis;
1240 ReadOnly := True;
1241 end;
1243 with ItemProps[InsertRow(_lc[I_PROP_DM_ONLY], BoolNames[Data.ItemOnlyDM], True)] do
1244 begin
1245 EditStyle := esPickList;
1246 ReadOnly := True;
1247 end;
1249 with ItemProps[InsertRow(_lc[I_PROP_ITEM_FALLS], BoolNames[Data.ItemFalls], True)] do
1250 begin
1251 EditStyle := esPickList;
1252 ReadOnly := True;
1253 end;
1255 with ItemProps[InsertRow(_lc[I_PROP_TR_COUNT], IntToStr(Data.ItemCount), True)] do
1256 begin
1257 EditStyle := esSimple;
1258 MaxLength := 5;
1259 end;
1261 with ItemProps[InsertRow(_lc[I_PROP_TR_FX_TYPE], EffectToStr(Data.ItemEffect), True)] do
1262 begin
1263 EditStyle := esEllipsis;
1264 ReadOnly := True;
1265 end;
1267 with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_MAX], IntToStr(Data.ItemMax), True)] do
1268 begin
1269 EditStyle := esSimple;
1270 MaxLength := 5;
1271 end;
1273 with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_DELAY], IntToStr(Data.ItemDelay), True)] do
1274 begin
1275 EditStyle := esSimple;
1276 MaxLength := 5;
1277 end;
1278 end;
1280 TRIGGER_MUSIC:
1281 begin
1282 str := win2utf(Data.MusicName);
1283 with ItemProps[InsertRow(_lc[I_PROP_TR_MUSIC_NAME], str, True)] do
1284 begin
1285 EditStyle := esEllipsis;
1286 ReadOnly := True;
1287 end;
1289 if Data.MusicAction = 1 then
1290 str := _lc[I_PROP_TR_MUSIC_ON]
1291 else
1292 str := _lc[I_PROP_TR_MUSIC_OFF];
1294 with ItemProps[InsertRow(_lc[I_PROP_TR_MUSIC_ACT], str, True)] do
1295 begin
1296 EditStyle := esPickList;
1297 ReadOnly := True;
1298 end;
1299 end;
1301 TRIGGER_PUSH:
1302 begin
1303 with ItemProps[InsertRow(_lc[I_PROP_TR_PUSH_ANGLE], IntToStr(Data.PushAngle), True)] do
1304 begin
1305 EditStyle := esSimple;
1306 MaxLength := 4;
1307 end;
1308 with ItemProps[InsertRow(_lc[I_PROP_TR_PUSH_FORCE], IntToStr(Data.PushForce), True)] do
1309 begin
1310 EditStyle := esSimple;
1311 MaxLength := 4;
1312 end;
1313 with ItemProps[InsertRow(_lc[I_PROP_TR_PUSH_RESET], BoolNames[Data.ResetVel], True)] do
1314 begin
1315 EditStyle := esPickList;
1316 ReadOnly := True;
1317 end;
1318 end;
1320 TRIGGER_SCORE:
1321 begin
1322 case Data.ScoreAction of
1323 1: str := _lc[I_PROP_TR_SCORE_ACT_1];
1324 2: str := _lc[I_PROP_TR_SCORE_ACT_2];
1325 3: str := _lc[I_PROP_TR_SCORE_ACT_3];
1326 else str := _lc[I_PROP_TR_SCORE_ACT_0];
1327 end;
1328 with ItemProps[InsertRow(_lc[I_PROP_TR_SCORE_ACT], str, True)] do
1329 begin
1330 EditStyle := esPickList;
1331 ReadOnly := True;
1332 end;
1333 with ItemProps[InsertRow(_lc[I_PROP_TR_COUNT], IntToStr(Data.ScoreCount), True)] do
1334 begin
1335 EditStyle := esSimple;
1336 MaxLength := 3;
1337 end;
1338 case Data.ScoreTeam of
1339 1: str := _lc[I_PROP_TR_SCORE_TEAM_1];
1340 2: str := _lc[I_PROP_TR_SCORE_TEAM_2];
1341 3: str := _lc[I_PROP_TR_SCORE_TEAM_3];
1342 else str := _lc[I_PROP_TR_SCORE_TEAM_0];
1343 end;
1344 with ItemProps[InsertRow(_lc[I_PROP_TR_SCORE_TEAM], str, True)] do
1345 begin
1346 EditStyle := esPickList;
1347 ReadOnly := True;
1348 end;
1349 with ItemProps[InsertRow(_lc[I_PROP_TR_SCORE_CON], BoolNames[Data.ScoreCon], True)] do
1350 begin
1351 EditStyle := esPickList;
1352 ReadOnly := True;
1353 end;
1354 with ItemProps[InsertRow(_lc[I_PROP_TR_SCORE_MSG], BoolNames[Data.ScoreMsg], True)] do
1355 begin
1356 EditStyle := esPickList;
1357 ReadOnly := True;
1358 end;
1359 end;
1361 TRIGGER_MESSAGE:
1362 begin
1363 case Data.MessageKind of
1364 1: str := _lc[I_PROP_TR_MESSAGE_KIND_1];
1365 else str := _lc[I_PROP_TR_MESSAGE_KIND_0];
1366 end;
1367 with ItemProps[InsertRow(_lc[I_PROP_TR_MESSAGE_KIND], str, True)] do
1368 begin
1369 EditStyle := esPickList;
1370 ReadOnly := True;
1371 end;
1372 case Data.MessageSendTo of
1373 1: str := _lc[I_PROP_TR_MESSAGE_TO_1];
1374 2: str := _lc[I_PROP_TR_MESSAGE_TO_2];
1375 3: str := _lc[I_PROP_TR_MESSAGE_TO_3];
1376 4: str := _lc[I_PROP_TR_MESSAGE_TO_4];
1377 5: str := _lc[I_PROP_TR_MESSAGE_TO_5];
1378 else str := _lc[I_PROP_TR_MESSAGE_TO_0];
1379 end;
1380 with ItemProps[InsertRow(_lc[I_PROP_TR_MESSAGE_TO], str, True)] do
1381 begin
1382 EditStyle := esPickList;
1383 ReadOnly := True;
1384 end;
1385 str := win2utf(Data.MessageText);
1386 with ItemProps[InsertRow(_lc[I_PROP_TR_MESSAGE_TEXT], str, True)] do
1387 begin
1388 EditStyle := esSimple;
1389 MaxLength := 100;
1390 end;
1391 with ItemProps[InsertRow(_lc[I_PROP_TR_MESSAGE_TIME], IntToStr(Data.MessageTime), True)] do
1392 begin
1393 EditStyle := esSimple;
1394 MaxLength := 5;
1395 end;
1396 end;
1398 TRIGGER_DAMAGE:
1399 begin
1400 with ItemProps[InsertRow(_lc[I_PROP_TR_DAMAGE_VALUE], IntToStr(Data.DamageValue), True)] do
1401 begin
1402 EditStyle := esSimple;
1403 MaxLength := 5;
1404 end;
1405 with ItemProps[InsertRow(_lc[I_PROP_TR_INTERVAL], IntToStr(Data.DamageInterval), True)] do
1406 begin
1407 EditStyle := esSimple;
1408 MaxLength := 5;
1409 end;
1410 end;
1412 TRIGGER_HEALTH:
1413 begin
1414 with ItemProps[InsertRow(_lc[I_PROP_TR_HEALTH], IntToStr(Data.HealValue), True)] do
1415 begin
1416 EditStyle := esSimple;
1417 MaxLength := 5;
1418 end;
1419 with ItemProps[InsertRow(_lc[I_PROP_TR_INTERVAL], IntToStr(Data.HealInterval), True)] do
1420 begin
1421 EditStyle := esSimple;
1422 MaxLength := 5;
1423 end;
1424 with ItemProps[InsertRow(_lc[I_PROP_TR_HEALTH_MAX], BoolNames[Data.HealMax], True)] do
1425 begin
1426 EditStyle := esPickList;
1427 ReadOnly := True;
1428 end;
1429 with ItemProps[InsertRow(_lc[I_PROP_TR_SILENT], BoolNames[Data.HealSilent], True)] do
1430 begin
1431 EditStyle := esPickList;
1432 ReadOnly := True;
1433 end;
1434 end;
1436 TRIGGER_SHOT:
1437 begin
1438 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_TYPE], ShotToStr(Data.ShotType), True)] do
1439 begin
1440 EditStyle := esEllipsis;
1441 ReadOnly := True;
1442 end;
1444 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_SOUND], BoolNames[Data.ShotSound], True)] do
1445 begin
1446 EditStyle := esPickList;
1447 ReadOnly := True;
1448 end;
1450 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_PANEL], IntToStr(Data.ShotPanelID), True)] do
1451 begin
1452 EditStyle := esEllipsis;
1453 ReadOnly := True;
1454 end;
1456 case Data.ShotTarget of
1457 1: str := _lc[I_PROP_TR_SHOT_TO_1];
1458 2: str := _lc[I_PROP_TR_SHOT_TO_2];
1459 3: str := _lc[I_PROP_TR_SHOT_TO_3];
1460 4: str := _lc[I_PROP_TR_SHOT_TO_4];
1461 5: str := _lc[I_PROP_TR_SHOT_TO_5];
1462 6: str := _lc[I_PROP_TR_SHOT_TO_6];
1463 else str := _lc[I_PROP_TR_SHOT_TO_0];
1464 end;
1465 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_TO], str, True)] do
1466 begin
1467 EditStyle := esPickList;
1468 ReadOnly := True;
1469 end;
1471 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_SIGHT], IntToStr(Data.ShotIntSight), True)] do
1472 begin
1473 EditStyle := esSimple;
1474 MaxLength := 3;
1475 end;
1477 case Data.ShotAim of
1478 1: str := _lc[I_PROP_TR_SHOT_AIM_1];
1479 2: str := _lc[I_PROP_TR_SHOT_AIM_2];
1480 3: str := _lc[I_PROP_TR_SHOT_AIM_3];
1481 else str := _lc[I_PROP_TR_SHOT_AIM_0];
1482 end;
1483 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_AIM], str, True)-1] do
1484 begin
1485 EditStyle := esPickList;
1486 ReadOnly := True;
1487 end;
1489 with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_TO],
1490 Format('(%d:%d)', [Data.ShotPos.X, Data.ShotPos.Y]), True)] do
1491 begin
1492 EditStyle := esEllipsis;
1493 ReadOnly := True;
1494 end;
1496 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_ANGLE], IntToStr(Data.ShotAngle), True)] do
1497 begin
1498 EditStyle := esSimple;
1499 MaxLength := 4;
1500 end;
1502 with ItemProps[InsertRow(_lc[I_PROP_TR_EX_DELAY], IntToStr(Data.ShotWait), True)] do
1503 begin
1504 EditStyle := esSimple;
1505 MaxLength := 5;
1506 end;
1508 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_ACC], IntToStr(Data.ShotAccuracy), True)] do
1509 begin
1510 EditStyle := esSimple;
1511 MaxLength := 5;
1512 end;
1514 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_AMMO], IntToStr(Data.ShotAmmo), True)] do
1515 begin
1516 EditStyle := esSimple;
1517 MaxLength := 5;
1518 end;
1520 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_RELOAD], IntToStr(Data.ShotIntReload), True)] do
1521 begin
1522 EditStyle := esSimple;
1523 MaxLength := 4;
1524 end;
1525 end;
1527 TRIGGER_EFFECT:
1528 begin
1529 with ItemProps[InsertRow(_lc[I_PROP_TR_COUNT], IntToStr(Data.FXCount), True)] do
1530 begin
1531 EditStyle := esSimple;
1532 MaxLength := 3;
1533 end;
1535 if Data.FXType = 0 then
1536 str := _lc[I_PROP_TR_EFFECT_PARTICLE]
1537 else
1538 str := _lc[I_PROP_TR_EFFECT_ANIMATION];
1539 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_TYPE], str, True)] do
1540 begin
1541 EditStyle := esEllipsis;
1542 ReadOnly := True;
1543 end;
1545 str := '';
1546 if Data.FXType = 0 then
1547 case Data.FXSubType of
1548 TRIGGER_EFFECT_SLIQUID:
1549 str := _lc[I_PROP_TR_EFFECT_SLIQUID];
1550 TRIGGER_EFFECT_LLIQUID:
1551 str := _lc[I_PROP_TR_EFFECT_LLIQUID];
1552 TRIGGER_EFFECT_DLIQUID:
1553 str := _lc[I_PROP_TR_EFFECT_DLIQUID];
1554 TRIGGER_EFFECT_BLOOD:
1555 str := _lc[I_PROP_TR_EFFECT_BLOOD];
1556 TRIGGER_EFFECT_SPARK:
1557 str := _lc[I_PROP_TR_EFFECT_SPARK];
1558 TRIGGER_EFFECT_BUBBLE:
1559 str := _lc[I_PROP_TR_EFFECT_BUBBLE];
1560 end;
1561 if Data.FXType = 1 then
1562 begin
1563 if (Data.FXSubType = 0) or (Data.FXSubType > EFFECT_FIRE) then
1564 Data.FXSubType := EFFECT_TELEPORT;
1565 str := EffectToStr(Data.FXSubType);
1566 end;
1567 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_SUBTYPE], str, True)] do
1568 begin
1569 EditStyle := esEllipsis;
1570 ReadOnly := True;
1571 end;
1573 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_COLOR], IntToStr(Data.FXColorR or (Data.FXColorG shl 8) or (Data.FXColorB shl 16)), True)] do
1574 begin
1575 EditStyle := esEllipsis;
1576 ReadOnly := True;
1577 end;
1579 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_CENTER], BoolNames[Data.FXPos = 0], True)] do
1580 begin
1581 EditStyle := esPickList;
1582 ReadOnly := True;
1583 end;
1585 with ItemProps[InsertRow(_lc[I_PROP_TR_EX_DELAY], IntToStr(Data.FXWait), True)] do
1586 begin
1587 EditStyle := esSimple;
1588 MaxLength := 5;
1589 end;
1591 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_VELX], IntToStr(Data.FXVelX), True)] do
1592 begin
1593 EditStyle := esSimple;
1594 MaxLength := 4;
1595 end;
1597 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_VELY], IntToStr(Data.FXVelY), True)] do
1598 begin
1599 EditStyle := esSimple;
1600 MaxLength := 4;
1601 end;
1603 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_SPL], IntToStr(Data.FXSpreadL), True)] do
1604 begin
1605 EditStyle := esSimple;
1606 MaxLength := 3;
1607 end;
1609 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_SPR], IntToStr(Data.FXSpreadR), True)] do
1610 begin
1611 EditStyle := esSimple;
1612 MaxLength := 3;
1613 end;
1615 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_SPU], IntToStr(Data.FXSpreadU), True)] do
1616 begin
1617 EditStyle := esSimple;
1618 MaxLength := 3;
1619 end;
1621 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_SPD], IntToStr(Data.FXSpreadD), True)] do
1622 begin
1623 EditStyle := esSimple;
1624 MaxLength := 3;
1625 end;
1626 end;
1627 end; //case TriggerType
1628 end;
1629 end; // OBJECT_TRIGGER:
1630 end;
1631 end;
1633 procedure ChangeShownProperty(Name: String; NewValue: String);
1634 var
1635 row: Integer;
1636 begin
1637 if SelectedObjectCount() <> 1 then
1638 Exit;
1639 if not SelectedObjects[GetFirstSelected()].Live then
1640 Exit;
1642 // Есть ли такой ключ:
1643 if MainForm.vleObjectProperty.FindRow(Name, row) then
1644 begin
1645 MainForm.vleObjectProperty.Values[Name] := NewValue;
1646 end;
1647 end;
1649 procedure SelectObject(fObjectType: Byte; fID: DWORD; Multi: Boolean);
1650 var
1651 a: Integer;
1652 b: Boolean;
1653 begin
1654 if Multi then
1655 begin
1656 b := False;
1658 // Уже выделен - убираем:
1659 if SelectedObjects <> nil then
1660 for a := 0 to High(SelectedObjects) do
1661 with SelectedObjects[a] do
1662 if Live and (ID = fID) and
1663 (ObjectType = fObjectType) then
1664 begin
1665 Live := False;
1666 b := True;
1667 end;
1669 if b then
1670 Exit;
1672 SetLength(SelectedObjects, Length(SelectedObjects)+1);
1674 with SelectedObjects[High(SelectedObjects)] do
1675 begin
1676 ObjectType := fObjectType;
1677 ID := fID;
1678 Live := True;
1679 end;
1680 end
1681 else // not Multi
1682 begin
1683 SetLength(SelectedObjects, 1);
1685 with SelectedObjects[0] do
1686 begin
1687 ObjectType := fObjectType;
1688 ID := fID;
1689 Live := True;
1690 end;
1691 end;
1693 MainForm.miCopy.Enabled := True;
1694 MainForm.miCut.Enabled := True;
1696 if fObjectType = OBJECT_PANEL then
1697 begin
1698 MainForm.miToFore.Enabled := True;
1699 MainForm.miToBack.Enabled := True;
1700 end;
1701 end;
1703 procedure RemoveSelectFromObjects();
1704 begin
1705 SelectedObjects := nil;
1706 DrawPressRect := False;
1707 MouseLDown := False;
1708 MouseRDown := False;
1709 MouseAction := MOUSEACTION_NONE;
1710 SelectFlag := SELECTFLAG_NONE;
1711 ResizeType := RESIZETYPE_NONE;
1712 ResizeDirection := RESIZEDIR_NONE;
1714 MainForm.vleObjectProperty.Strings.Clear();
1716 MainForm.miCopy.Enabled := False;
1717 MainForm.miCut.Enabled := False;
1718 MainForm.miToFore.Enabled := False;
1719 MainForm.miToBack.Enabled := False;
1720 end;
1722 procedure DeleteSelectedObjects();
1723 var
1724 i, a, ii: Integer;
1725 b: Boolean;
1726 begin
1727 if SelectedObjects = nil then
1728 Exit;
1730 b := False;
1731 i := 0;
1733 for a := 0 to High(SelectedObjects) do
1734 with SelectedObjects[a] do
1735 if Live then
1736 begin
1737 if not b then
1738 begin
1739 SetLength(UndoBuffer, Length(UndoBuffer)+1);
1740 i := High(UndoBuffer);
1741 b := True;
1742 end;
1744 SetLength(UndoBuffer[i], Length(UndoBuffer[i])+1);
1745 ii := High(UndoBuffer[i]);
1747 case ObjectType of
1748 OBJECT_PANEL:
1749 begin
1750 UndoBuffer[i, ii].UndoType := UNDO_DELETE_PANEL;
1751 New(UndoBuffer[i, ii].Panel);
1752 UndoBuffer[i, ii].Panel^ := gPanels[ID];
1753 end;
1754 OBJECT_ITEM:
1755 begin
1756 UndoBuffer[i, ii].UndoType := UNDO_DELETE_ITEM;
1757 UndoBuffer[i, ii].Item := gItems[ID];
1758 end;
1759 OBJECT_AREA:
1760 begin
1761 UndoBuffer[i, ii].UndoType := UNDO_DELETE_AREA;
1762 UndoBuffer[i, ii].Area := gAreas[ID];
1763 end;
1764 OBJECT_TRIGGER:
1765 begin
1766 UndoBuffer[i, ii].UndoType := UNDO_DELETE_TRIGGER;
1767 UndoBuffer[i, ii].Trigger := gTriggers[ID];
1768 end;
1769 end;
1771 RemoveObject(ID, ObjectType);
1772 end;
1774 RemoveSelectFromObjects();
1776 MainForm.miUndo.Enabled := UndoBuffer <> nil;
1777 end;
1779 procedure Undo_Add(ObjectType: Byte; ID: DWORD; Group: Boolean = False);
1780 var
1781 i, ii: Integer;
1782 begin
1783 if (not Group) or (Length(UndoBuffer) = 0) then
1784 SetLength(UndoBuffer, Length(UndoBuffer)+1);
1785 SetLength(UndoBuffer[High(UndoBuffer)], Length(UndoBuffer[High(UndoBuffer)])+1);
1786 i := High(UndoBuffer);
1787 ii := High(UndoBuffer[i]);
1789 case ObjectType of
1790 OBJECT_PANEL:
1791 UndoBuffer[i, ii].UndoType := UNDO_ADD_PANEL;
1792 OBJECT_ITEM:
1793 UndoBuffer[i, ii].UndoType := UNDO_ADD_ITEM;
1794 OBJECT_MONSTER:
1795 UndoBuffer[i, ii].UndoType := UNDO_ADD_MONSTER;
1796 OBJECT_AREA:
1797 UndoBuffer[i, ii].UndoType := UNDO_ADD_AREA;
1798 OBJECT_TRIGGER:
1799 UndoBuffer[i, ii].UndoType := UNDO_ADD_TRIGGER;
1800 end;
1802 UndoBuffer[i, ii].AddID := ID;
1804 MainForm.miUndo.Enabled := UndoBuffer <> nil;
1805 end;
1807 procedure FullClear();
1808 begin
1809 RemoveSelectFromObjects();
1810 ClearMap();
1811 LoadSky(gMapInfo.SkyName);
1812 UndoBuffer := nil;
1813 slInvalidTextures.Clear();
1814 MapCheckForm.lbErrorList.Clear();
1815 MapCheckForm.mErrorDescription.Clear();
1817 MainForm.miUndo.Enabled := False;
1818 MainForm.sbHorizontal.Position := 0;
1819 MainForm.sbVertical.Position := 0;
1820 MainForm.FormResize(nil);
1821 MainForm.Caption := FormCaption;
1822 OpenedMap := '';
1823 OpenedWAD := '';
1824 end;
1826 procedure ErrorMessageBox(str: String);
1827 begin
1828 MessageBox(0, PChar(str), PChar(_lc[I_MSG_ERROR]),
1829 MB_ICONINFORMATION or MB_OK or MB_DEFBUTTON1);
1830 end;
1832 function CheckProperty(): Boolean;
1833 var
1834 _id: Integer;
1835 begin
1836 Result := False;
1838 _id := GetFirstSelected();
1840 if SelectedObjects[_id].ObjectType = OBJECT_PANEL then
1841 with gPanels[SelectedObjects[_id].ID] do
1842 begin
1843 if TextureWidth <> 0 then
1844 if StrToIntDef(MainForm.vleObjectProperty.Values[_lc[I_PROP_WIDTH]], 1) mod TextureWidth <> 0 then
1845 begin
1846 ErrorMessageBox(Format(_lc[I_MSG_WRONG_TEXWIDTH],
1847 [TextureWidth]));
1848 Exit;
1849 end;
1851 if TextureHeight <> 0 then
1852 if StrToIntDef(Trim(MainForm.vleObjectProperty.Values[_lc[I_PROP_HEIGHT]]), 1) mod TextureHeight <> 0 then
1853 begin
1854 ErrorMessageBox(Format(_lc[I_MSG_WRONG_TEXHEIGHT],
1855 [TextureHeight]));
1856 Exit;
1857 end;
1859 if IsTexturedPanel(PanelType) and (TextureName <> '') then
1860 if not (StrToIntDef(MainForm.vleObjectProperty.Values[_lc[I_PROP_PANEL_ALPHA]], -1) in [0..255]) then
1861 begin
1862 ErrorMessageBox(_lc[I_MSG_WRONG_ALPHA]);
1863 Exit;
1864 end;
1865 end;
1867 if SelectedObjects[_id].ObjectType in [OBJECT_PANEL, OBJECT_TRIGGER] then
1868 if (StrToIntDef(MainForm.vleObjectProperty.Values[_lc[I_PROP_WIDTH]], 0) <= 0) or
1869 (StrToIntDef(MainForm.vleObjectProperty.Values[_lc[I_PROP_HEIGHT]], 0) <= 0) then
1870 begin
1871 ErrorMessageBox(_lc[I_MSG_WRONG_SIZE]);
1872 Exit;
1873 end;
1875 if (Trim(MainForm.vleObjectProperty.Values[_lc[I_PROP_X]]) = '') or
1876 (Trim(MainForm.vleObjectProperty.Values[_lc[I_PROP_Y]]) = '') then
1877 begin
1878 ErrorMessageBox(_lc[I_MSG_WRONG_XY]);
1879 Exit;
1880 end;
1882 Result := True;
1883 end;
1885 procedure SelectTexture(ID: Integer);
1886 begin
1887 MainForm.lbTextureList.ItemIndex := ID;
1888 MainForm.lbTextureListClick(nil);
1889 end;
1891 function AddTexture(aWAD, aSection, aTex: String; silent: Boolean): Boolean;
1892 var
1893 a, FrameLen: Integer;
1894 ok: Boolean;
1895 FileName: String;
1896 ResourceName: String;
1897 FullResourceName: String;
1898 SectionName: String;
1899 Data: Pointer;
1900 Width, Height: Word;
1901 fn: String;
1902 begin
1903 Data := nil;
1904 FrameLen := 0;
1905 Width := 0;
1906 Height := 0;
1908 if aSection = '..' then
1909 SectionName := ''
1910 else
1911 SectionName := aSection;
1913 if aWAD = '' then
1914 aWAD := _lc[I_WAD_SPECIAL_MAP];
1916 if aWAD = _lc[I_WAD_SPECIAL_MAP] then
1917 begin // Файл карты
1918 g_ProcessResourceStr(OpenedMap, @fn, nil, nil);
1919 //FileName := EditorDir+'maps\'+ExtractFileName(fn);
1920 FileName := fn;
1921 ResourceName := ':'+SectionName+'\'+aTex;
1922 end
1923 else
1924 if aWAD = _lc[I_WAD_SPECIAL_TEXS] then
1925 begin // Спец. текстуры
1926 FileName := '';
1927 ResourceName := aTex;
1928 end
1929 else
1930 begin // Внешний WAD
1931 FileName := EditorDir+'wads/'+aWAD;
1932 ResourceName := aWAD+':'+SectionName+'\'+aTex;
1933 end;
1935 ok := True;
1937 // Есть ли уже такая текстура:
1938 for a := 0 to MainForm.lbTextureList.Items.Count-1 do
1939 if ResourceName = MainForm.lbTextureList.Items[a] then
1940 begin
1941 if not silent then
1942 ErrorMessageBox(Format(_lc[I_MSG_TEXTURE_ALREADY],
1943 [ResourceName]));
1944 ok := False;
1945 end;
1947 // Название ресурса <= 64 символов:
1948 if Length(ResourceName) > 64 then
1949 begin
1950 if not silent then
1951 ErrorMessageBox(Format(_lc[I_MSG_RES_NAME_64],
1952 [ResourceName]));
1953 ok := False;
1954 end;
1956 if ok then
1957 begin
1958 a := -1;
1959 if aWAD = _lc[I_WAD_SPECIAL_TEXS] then
1960 begin
1961 a := MainForm.lbTextureList.Items.Add(ResourceName);
1962 if not silent then
1963 SelectTexture(a);
1964 Result := True;
1965 Exit;
1966 end;
1968 FullResourceName := FileName+':'+SectionName+'\'+aTex;
1970 if IsAnim(FullResourceName) then
1971 begin // Аним. текстура
1972 GetFrame(FullResourceName, Data, FrameLen, Width, Height);
1974 if not g_CreateTextureMemorySize(Data, FrameLen, ResourceName, 0, 0, Width, Height, 1) then
1975 ok := False;
1976 a := MainForm.lbTextureList.Items.Add(ResourceName);
1977 end
1978 else // Обычная текстура
1979 begin
1980 if not g_CreateTextureWAD(ResourceName, FullResourceName) then
1981 ok := False;
1982 a := MainForm.lbTextureList.Items.Add(ResourceName);
1983 end;
1984 if (not ok) and (slInvalidTextures.IndexOf(ResourceName) = -1) then
1985 begin
1986 slInvalidTextures.Add(ResourceName);
1987 ok := True;
1988 end;
1989 if (a > -1) and (not silent) then
1990 SelectTexture(a);
1991 end;
1993 Result := ok;
1994 end;
1996 procedure UpdateCaption(sMap, sFile, sRes: String);
1997 begin
1998 with MainForm do
1999 if (sFile = '') and (sRes = '') and (sMap = '') then
2000 Caption := FormCaption
2001 else
2002 if sMap = '' then
2003 Caption := Format('%s - %s:%s', [FormCaption, sFile, sRes])
2004 else
2005 if (sFile <> '') and (sRes <> '') then
2006 Caption := Format('%s - %s (%s:%s)', [FormCaption, sMap, sFile, sRes])
2007 else
2008 Caption := Format('%s - %s', [FormCaption, sMap]);
2009 end;
2011 procedure OpenMap(FileName: String; mapN: String);
2012 var
2013 MapName: String;
2014 idx: Integer;
2015 begin
2016 SelectMapForm.Caption := _lc[I_CAP_OPEN];
2017 SelectMapForm.GetMaps(FileName);
2019 if (FileName = OpenedWAD) and
2020 (OpenedMap <> '') then
2021 begin
2022 MapName := OpenedMap;
2023 while (Pos(':\', MapName) > 0) do
2024 Delete(MapName, 1, Pos(':\', MapName) + 1);
2026 idx := SelectMapForm.lbMapList.Items.IndexOf(MapName);
2027 SelectMapForm.lbMapList.ItemIndex := idx;
2028 end
2029 else
2030 if SelectMapForm.lbMapList.Count > 0 then
2031 SelectMapForm.lbMapList.ItemIndex := 0
2032 else
2033 SelectMapForm.lbMapList.ItemIndex := -1;
2035 if mapN = '' then
2036 idx := -1
2037 else
2038 idx := SelectMapForm.lbMapList.Items.IndexOf(mapN);
2040 if idx < 0 then
2041 begin
2042 if (SelectMapForm.ShowModal() = mrOK) and
2043 (SelectMapForm.lbMapList.ItemIndex <> -1) then
2044 idx := SelectMapForm.lbMapList.ItemIndex
2045 else
2046 Exit;
2047 end;
2049 MapName := SelectMapForm.lbMapList.Items[idx];
2051 with MainForm do
2052 begin
2053 FullClear();
2055 pLoadProgress.Left := (RenderPanel.Width div 2)-(pLoadProgress.Width div 2);
2056 pLoadProgress.Top := (RenderPanel.Height div 2)-(pLoadProgress.Height div 2);
2057 pLoadProgress.Show();
2059 OpenedMap := FileName+':\'+MapName;
2060 OpenedWAD := FileName;
2062 idx := RecentFiles.IndexOf(OpenedMap);
2063 // Такая карта уже недавно открывалась:
2064 if idx >= 0 then
2065 RecentFiles.Delete(idx);
2066 RecentFiles.Insert(0, OpenedMap);
2067 RefreshRecentMenu();
2069 LoadMap(OpenedMap);
2071 pLoadProgress.Hide();
2072 FormResize(nil);
2074 lbTextureList.Sorted := True;
2075 lbTextureList.Sorted := False;
2077 UpdateCaption(gMapInfo.Name, ExtractFileName(FileName), MapName);
2078 end;
2079 end;
2081 procedure MoveSelectedObjects(Wall, alt: Boolean; dx, dy: Integer);
2082 var
2083 okX, okY: Boolean;
2084 a: Integer;
2085 begin
2086 if SelectedObjects = nil then
2087 Exit;
2089 okX := True;
2090 okY := True;
2092 if Wall then
2093 for a := 0 to High(SelectedObjects) do
2094 if SelectedObjects[a].Live then
2095 begin
2096 if ObjectCollideLevel(SelectedObjects[a].ID, SelectedObjects[a].ObjectType, dx, 0) then
2097 okX := False;
2099 if ObjectCollideLevel(SelectedObjects[a].ID, SelectedObjects[a].ObjectType, 0, dy) then
2100 okY := False;
2102 if (not okX) or (not okY) then
2103 Break;
2104 end;
2106 if okX or okY then
2107 begin
2108 for a := 0 to High(SelectedObjects) do
2109 if SelectedObjects[a].Live then
2110 begin
2111 if okX then
2112 MoveObject(SelectedObjects[a].ObjectType, SelectedObjects[a].ID, dx, 0);
2114 if okY then
2115 MoveObject(SelectedObjects[a].ObjectType, SelectedObjects[a].ID, 0, dy);
2117 if alt and (SelectedObjects[a].ObjectType = OBJECT_TRIGGER) then
2118 begin
2119 if gTriggers[SelectedObjects[a].ID].TriggerType in [TRIGGER_PRESS,
2120 TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF] then
2121 begin // Двигаем зону Расширителя
2122 if okX then
2123 gTriggers[SelectedObjects[a].ID].Data.tX := gTriggers[SelectedObjects[a].ID].Data.tX+dx;
2124 if okY then
2125 gTriggers[SelectedObjects[a].ID].Data.tY := gTriggers[SelectedObjects[a].ID].Data.tY+dy;
2126 end;
2128 if gTriggers[SelectedObjects[a].ID].TriggerType in [TRIGGER_TELEPORT] then
2129 begin // Двигаем точку назначения Телепорта
2130 if okX then
2131 gTriggers[SelectedObjects[a].ID].Data.TargetPoint.X := gTriggers[SelectedObjects[a].ID].Data.TargetPoint.X+dx;
2132 if okY then
2133 gTriggers[SelectedObjects[a].ID].Data.TargetPoint.Y := gTriggers[SelectedObjects[a].ID].Data.TargetPoint.Y+dy;
2134 end;
2136 if gTriggers[SelectedObjects[a].ID].TriggerType in [TRIGGER_SPAWNMONSTER] then
2137 begin // Двигаем точку создания монстра
2138 if okX then
2139 gTriggers[SelectedObjects[a].ID].Data.MonPos.X := gTriggers[SelectedObjects[a].ID].Data.MonPos.X+dx;
2140 if okY then
2141 gTriggers[SelectedObjects[a].ID].Data.MonPos.Y := gTriggers[SelectedObjects[a].ID].Data.MonPos.Y+dy;
2142 end;
2144 if gTriggers[SelectedObjects[a].ID].TriggerType in [TRIGGER_SPAWNITEM] then
2145 begin // Двигаем точку создания предмета
2146 if okX then
2147 gTriggers[SelectedObjects[a].ID].Data.ItemPos.X := gTriggers[SelectedObjects[a].ID].Data.ItemPos.X+dx;
2148 if okY then
2149 gTriggers[SelectedObjects[a].ID].Data.ItemPos.Y := gTriggers[SelectedObjects[a].ID].Data.ItemPos.Y+dy;
2150 end;
2152 if gTriggers[SelectedObjects[a].ID].TriggerType in [TRIGGER_SHOT] then
2153 begin // Двигаем точку создания выстрела
2154 if okX then
2155 gTriggers[SelectedObjects[a].ID].Data.ShotPos.X := gTriggers[SelectedObjects[a].ID].Data.ShotPos.X+dx;
2156 if okY then
2157 gTriggers[SelectedObjects[a].ID].Data.ShotPos.Y := gTriggers[SelectedObjects[a].ID].Data.ShotPos.Y+dy;
2158 end;
2159 end;
2160 end;
2162 LastMovePoint := MousePos;
2163 end;
2164 end;
2166 procedure ShowLayer(Layer: Byte; show: Boolean);
2167 begin
2168 LayerEnabled[Layer] := show;
2170 case Layer of
2171 LAYER_BACK:
2172 begin
2173 MainForm.miLayer1.Checked := show;
2174 MainForm.miLayerP1.Checked := show;
2175 end;
2176 LAYER_WALLS:
2177 begin
2178 MainForm.miLayer2.Checked := show;
2179 MainForm.miLayerP2.Checked := show;
2180 end;
2181 LAYER_FOREGROUND:
2182 begin
2183 MainForm.miLayer3.Checked := show;
2184 MainForm.miLayerP3.Checked := show;
2185 end;
2186 LAYER_STEPS:
2187 begin
2188 MainForm.miLayer4.Checked := show;
2189 MainForm.miLayerP4.Checked := show;
2190 end;
2191 LAYER_WATER:
2192 begin
2193 MainForm.miLayer5.Checked := show;
2194 MainForm.miLayerP5.Checked := show;
2195 end;
2196 LAYER_ITEMS:
2197 begin
2198 MainForm.miLayer6.Checked := show;
2199 MainForm.miLayerP6.Checked := show;
2200 end;
2201 LAYER_MONSTERS:
2202 begin
2203 MainForm.miLayer7.Checked := show;
2204 MainForm.miLayerP7.Checked := show;
2205 end;
2206 LAYER_AREAS:
2207 begin
2208 MainForm.miLayer8.Checked := show;
2209 MainForm.miLayerP8.Checked := show;
2210 end;
2211 LAYER_TRIGGERS:
2212 begin
2213 MainForm.miLayer9.Checked := show;
2214 MainForm.miLayerP9.Checked := show;
2215 end;
2216 end;
2218 RemoveSelectFromObjects();
2219 end;
2221 procedure SwitchLayer(Layer: Byte);
2222 begin
2223 ShowLayer(Layer, not LayerEnabled[Layer]);
2224 end;
2226 procedure SwitchMap();
2227 begin
2228 ShowMap := not ShowMap;
2229 MainForm.tbShowMap.Down := ShowMap;
2230 end;
2232 procedure ShowEdges();
2233 begin
2234 if drEdge[3] < 255 then
2235 drEdge[3] := 255
2236 else
2237 drEdge[3] := gAlphaEdge;
2238 end;
2240 function SelectedTexture(): String;
2241 begin
2242 if MainForm.lbTextureList.ItemIndex <> -1 then
2243 Result := MainForm.lbTextureList.Items[MainForm.lbTextureList.ItemIndex]
2244 else
2245 Result := '';
2246 end;
2248 function IsSpecialTextureSel(): Boolean;
2249 begin
2250 Result := (MainForm.lbTextureList.ItemIndex <> -1) and
2251 IsSpecialTexture(MainForm.lbTextureList.Items[MainForm.lbTextureList.ItemIndex]);
2252 end;
2254 function CopyBufferToString(var CopyBuf: TCopyRecArray): String;
2255 var
2256 i, j: Integer;
2257 Res: String;
2259 procedure AddInt(x: Integer);
2260 begin
2261 Res := Res + IntToStr(x) + ' ';
2262 end;
2264 begin
2265 Result := '';
2267 if Length(CopyBuf) = 0 then
2268 Exit;
2270 Res := CLIPBOARD_SIG + ' ';
2272 for i := 0 to High(CopyBuf) do
2273 begin
2274 if (CopyBuf[i].ObjectType = OBJECT_PANEL) and
2275 (CopyBuf[i].Panel = nil) then
2276 Continue;
2278 // Тип объекта:
2279 AddInt(CopyBuf[i].ObjectType);
2280 Res := Res + '; ';
2282 // Свойства объекта:
2283 case CopyBuf[i].ObjectType of
2284 OBJECT_PANEL:
2285 with CopyBuf[i].Panel^ do
2286 begin
2287 AddInt(PanelType);
2288 AddInt(X);
2289 AddInt(Y);
2290 AddInt(Width);
2291 AddInt(Height);
2292 Res := Res + '"' + TextureName + '" ';
2293 AddInt(Alpha);
2294 AddInt(IfThen(Blending, 1, 0));
2295 end;
2297 OBJECT_ITEM:
2298 with CopyBuf[i].Item do
2299 begin
2300 AddInt(ItemType);
2301 AddInt(X);
2302 AddInt(Y);
2303 AddInt(IfThen(OnlyDM, 1, 0));
2304 AddInt(IfThen(Fall, 1, 0));
2305 end;
2307 OBJECT_MONSTER:
2308 with CopyBuf[i].Monster do
2309 begin
2310 AddInt(MonsterType);
2311 AddInt(X);
2312 AddInt(Y);
2313 AddInt(IfThen(Direction = D_LEFT, 1, 0));
2314 end;
2316 OBJECT_AREA:
2317 with CopyBuf[i].Area do
2318 begin
2319 AddInt(AreaType);
2320 AddInt(X);
2321 AddInt(Y);
2322 AddInt(IfThen(Direction = D_LEFT, 1, 0));
2323 end;
2325 OBJECT_TRIGGER:
2326 with CopyBuf[i].Trigger do
2327 begin
2328 AddInt(TriggerType);
2329 AddInt(X);
2330 AddInt(Y);
2331 AddInt(Width);
2332 AddInt(Height);
2333 AddInt(ActivateType);
2334 AddInt(Key);
2335 AddInt(IfThen(Enabled, 1, 0));
2336 AddInt(TexturePanel);
2338 for j := 0 to 127 do
2339 AddInt(Data.Default[j]);
2340 end;
2341 end;
2342 end;
2344 Result := Res;
2345 end;
2347 procedure StringToCopyBuffer(Str: String; var CopyBuf: TCopyRecArray;
2348 var pmin: TPoint);
2349 var
2350 i, j, t: Integer;
2352 function GetNext(): String;
2353 var
2354 p: Integer;
2356 begin
2357 if Str[1] = '"' then
2358 begin
2359 Delete(Str, 1, 1);
2360 p := Pos('"', Str);
2362 if p = 0 then
2363 begin
2364 Result := Str;
2365 Str := '';
2366 end
2367 else
2368 begin
2369 Result := Copy(Str, 1, p-1);
2370 Delete(Str, 1, p);
2371 Str := Trim(Str);
2372 end;
2373 end
2374 else
2375 begin
2376 p := Pos(' ', Str);
2378 if p = 0 then
2379 begin
2380 Result := Str;
2381 Str := '';
2382 end
2383 else
2384 begin
2385 Result := Copy(Str, 1, p-1);
2386 Delete(Str, 1, p);
2387 Str := Trim(Str);
2388 end;
2389 end;
2390 end;
2392 begin
2393 Str := Trim(Str);
2395 if GetNext() <> CLIPBOARD_SIG then
2396 Exit;
2398 while Str <> '' do
2399 begin
2400 // Тип объекта:
2401 t := StrToIntDef(GetNext(), 0);
2403 if (t < OBJECT_PANEL) or (t > OBJECT_TRIGGER) or
2404 (GetNext() <> ';') then
2405 begin // Что-то не то => пропускаем:
2406 t := Pos(';', Str);
2407 Delete(Str, 1, t);
2408 Str := Trim(Str);
2410 Continue;
2411 end;
2413 i := Length(CopyBuf);
2414 SetLength(CopyBuf, i + 1);
2416 CopyBuf[i].ObjectType := t;
2417 CopyBuf[i].Panel := nil;
2419 // Свойства объекта:
2420 case t of
2421 OBJECT_PANEL:
2422 begin
2423 New(CopyBuf[i].Panel);
2425 with CopyBuf[i].Panel^ do
2426 begin
2427 PanelType := StrToIntDef(GetNext(), PANEL_WALL);
2428 X := StrToIntDef(GetNext(), 0);
2429 Y := StrToIntDef(GetNext(), 0);
2430 pmin.X := Min(X, pmin.X);
2431 pmin.Y := Min(Y, pmin.Y);
2432 Width := StrToIntDef(GetNext(), 16);
2433 Height := StrToIntDef(GetNext(), 16);
2434 TextureName := GetNext();
2435 Alpha := StrToIntDef(GetNext(), 0);
2436 Blending := (GetNext() = '1');
2437 end;
2438 end;
2440 OBJECT_ITEM:
2441 with CopyBuf[i].Item do
2442 begin
2443 ItemType := StrToIntDef(GetNext(), ITEM_MEDKIT_SMALL);
2444 X := StrToIntDef(GetNext(), 0);
2445 Y := StrToIntDef(GetNext(), 0);
2446 pmin.X := Min(X, pmin.X);
2447 pmin.Y := Min(Y, pmin.Y);
2448 OnlyDM := (GetNext() = '1');
2449 Fall := (GetNext() = '1');
2450 end;
2452 OBJECT_MONSTER:
2453 with CopyBuf[i].Monster do
2454 begin
2455 MonsterType := StrToIntDef(GetNext(), MONSTER_DEMON);
2456 X := StrToIntDef(GetNext(), 0);
2457 Y := StrToIntDef(GetNext(), 0);
2458 pmin.X := Min(X, pmin.X);
2459 pmin.Y := Min(Y, pmin.Y);
2461 if GetNext() = '1' then
2462 Direction := D_LEFT
2463 else
2464 Direction := D_RIGHT;
2465 end;
2467 OBJECT_AREA:
2468 with CopyBuf[i].Area do
2469 begin
2470 AreaType := StrToIntDef(GetNext(), AREA_PLAYERPOINT1);
2471 X := StrToIntDef(GetNext(), 0);
2472 Y := StrToIntDef(GetNext(), 0);
2473 pmin.X := Min(X, pmin.X);
2474 pmin.Y := Min(Y, pmin.Y);
2475 if GetNext() = '1' then
2476 Direction := D_LEFT
2477 else
2478 Direction := D_RIGHT;
2479 end;
2481 OBJECT_TRIGGER:
2482 with CopyBuf[i].Trigger do
2483 begin
2484 TriggerType := StrToIntDef(GetNext(), TRIGGER_EXIT);
2485 X := StrToIntDef(GetNext(), 0);
2486 Y := StrToIntDef(GetNext(), 0);
2487 pmin.X := Min(X, pmin.X);
2488 pmin.Y := Min(Y, pmin.Y);
2489 Width := StrToIntDef(GetNext(), 16);
2490 Height := StrToIntDef(GetNext(), 16);
2491 ActivateType := StrToIntDef(GetNext(), 0);
2492 Key := StrToIntDef(GetNext(), 0);
2493 Enabled := (GetNext() = '1');
2494 TexturePanel := StrToIntDef(GetNext(), 0);
2496 for j := 0 to 127 do
2497 Data.Default[j] := StrToIntDef(GetNext(), 0);
2499 case TriggerType of
2500 TRIGGER_TELEPORT:
2501 begin
2502 pmin.X := Min(Data.TargetPoint.X, pmin.X);
2503 pmin.Y := Min(Data.TargetPoint.Y, pmin.Y);
2504 end;
2505 TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF:
2506 begin
2507 pmin.X := Min(Data.tX, pmin.X);
2508 pmin.Y := Min(Data.tY, pmin.Y);
2509 end;
2510 TRIGGER_SPAWNMONSTER:
2511 begin
2512 pmin.X := Min(Data.MonPos.X, pmin.X);
2513 pmin.Y := Min(Data.MonPos.Y, pmin.Y);
2514 end;
2515 TRIGGER_SPAWNITEM:
2516 begin
2517 pmin.X := Min(Data.ItemPos.X, pmin.X);
2518 pmin.Y := Min(Data.ItemPos.Y, pmin.Y);
2519 end;
2520 TRIGGER_SHOT:
2521 begin
2522 pmin.X := Min(Data.ShotPos.X, pmin.X);
2523 pmin.Y := Min(Data.ShotPos.Y, pmin.Y);
2524 end;
2525 end;
2526 end;
2527 end;
2528 end;
2529 end;
2531 //----------------------------------------
2532 //Закончились вспомогательные процедуры
2533 //----------------------------------------
2535 procedure TMainForm.RefreshRecentMenu();
2536 var
2537 i: Integer;
2538 MI: TMenuItem;
2539 begin
2540 // Лишние запомненные карты:
2541 while RecentFiles.Count > RecentCount do
2542 RecentFiles.Delete(RecentFiles.Count-1);
2544 // Лишние строки меню:
2545 while MainMenu.Items[0].Count > RECENT_FILES_MENU_START do
2546 MainMenu.Items[0].Delete(MainMenu.Items[0].Count-1);
2548 // Отделение списка карт от строки "Выход":
2549 if RecentFiles.Count > 0 then
2550 begin
2551 MI := TMenuItem.Create(MainMenu.Items[0]);
2552 MI.Caption := '-';
2553 MainMenu.Items[0].Add(MI);
2554 end;
2556 // Добавление в меню списка запомненных карт:
2557 for i := 0 to RecentFiles.Count-1 do
2558 begin
2559 MI := TMenuItem.Create(MainMenu.Items[0]);
2560 MI.Caption := IntToStr(i+1) + ' ' + RecentFiles[i];
2561 MI.OnClick := aRecentFileExecute;
2562 MainMenu.Items[0].Add(MI);
2563 end;
2564 end;
2566 procedure TMainForm.aRecentFileExecute(Sender: TObject);
2567 var
2568 n, pw: Integer;
2569 s, fn: String;
2570 b: Boolean;
2571 begin
2572 s := LowerCase((Sender as TMenuItem).Caption);
2573 Delete(s, Pos('&', s), 1);
2574 s := Trim(Copy(s, 1, 2));
2575 n := StrToIntDef(s, 0) - 1;
2577 if (n < 0) or (n >= RecentFiles.Count) then
2578 Exit;
2580 s := RecentFiles[n];
2581 pw := Pos('.wad:\', LowerCase(s));
2582 b := False;
2584 if pw > 0 then
2585 begin // Map name included
2586 fn := Copy(s, 1, pw + 3);
2587 Delete(s, 1, pw + 5);
2588 if (FileExists(fn)) then
2589 begin
2590 OpenMap(fn, s);
2591 b := True;
2592 end;
2593 end
2594 else // Only wad name
2595 if (FileExists(s)) then
2596 begin
2597 OpenMap(s, '');
2598 b := True;
2599 end;
2601 if (not b) and (MessageBox(0, PChar(_lc[I_MSG_DEL_RECENT_PROMT]),
2602 PChar(_lc[I_MSG_DEL_RECENT]), MB_ICONQUESTION or MB_YESNO) = idYes) then
2603 begin
2604 RecentFiles.Delete(n);
2605 RefreshRecentMenu();
2606 end;
2607 end;
2609 procedure TMainForm.aEditorOptionsExecute(Sender: TObject);
2610 begin
2611 OptionsForm.ShowModal();
2612 end;
2614 procedure LoadStdFont(cfgres, texture: string; var FontID: DWORD);
2615 var
2616 cwdt, chgt: Byte;
2617 spc: ShortInt;
2618 ID: DWORD;
2619 wad: TWADEditor_1;
2620 cfgdata: Pointer;
2621 cfglen: Integer;
2622 config: TConfig;
2623 begin
2624 cfgdata := nil;
2625 cfglen := 0;
2626 ID := 0;
2628 wad := TWADEditor_1.Create;
2629 if wad.ReadFile(EditorDir+'data/Game.wad') then
2630 wad.GetResource('FONTS', cfgres, cfgdata, cfglen);
2631 wad.Free();
2633 if cfglen <> 0 then
2634 begin
2635 if not g_CreateTextureWAD('FONT_STD', EditorDir+'data/Game.wad:FONTS\'+texture) then
2636 e_WriteLog('ERROR ERROR ERROR', MSG_WARNING);
2638 config := TConfig.CreateMem(cfgdata, cfglen);
2639 cwdt := Min(Max(config.ReadInt('FontMap', 'CharWidth', 0), 0), 255);
2640 chgt := Min(Max(config.ReadInt('FontMap', 'CharHeight', 0), 0), 255);
2641 spc := Min(Max(config.ReadInt('FontMap', 'Kerning', 0), -128), 127);
2643 if g_GetTexture('FONT_STD', ID) then
2644 e_TextureFontBuild(ID, FontID, cwdt, chgt, spc-2);
2646 config.Free();
2647 end
2648 else
2649 e_WriteLog('Could not load FONT_STD', MSG_WARNING);
2651 if cfglen <> 0 then FreeMem(cfgdata);
2652 end;
2654 procedure TMainForm.FormCreate(Sender: TObject);
2655 var
2656 config: TConfig;
2657 i: Integer;
2658 s: String;
2659 begin
2660 Randomize();
2662 EditorDir := ExtractFilePath(Application.ExeName);
2664 e_InitLog(EditorDir+'Editor.log', WM_NEWFILE);
2666 slInvalidTextures := TStringList.Create;
2668 ShowLayer(LAYER_BACK, True);
2669 ShowLayer(LAYER_WALLS, True);
2670 ShowLayer(LAYER_FOREGROUND, True);
2671 ShowLayer(LAYER_STEPS, True);
2672 ShowLayer(LAYER_WATER, True);
2673 ShowLayer(LAYER_ITEMS, True);
2674 ShowLayer(LAYER_MONSTERS, True);
2675 ShowLayer(LAYER_AREAS, True);
2676 ShowLayer(LAYER_TRIGGERS, True);
2678 ClearMap();
2680 FormCaption := MainForm.Caption;
2681 OpenedMap := '';
2682 OpenedWAD := '';
2684 config := TConfig.CreateFile(EditorDir+'Editor.cfg');
2686 if config.ReadInt('Editor', 'XPos', -1) = -1 then
2687 Position := poDesktopCenter
2688 else begin
2689 Left := config.ReadInt('Editor', 'XPos', Left);
2690 Top := config.ReadInt('Editor', 'YPos', Top);
2691 Width := config.ReadInt('Editor', 'Width', Width);
2692 Height := config.ReadInt('Editor', 'Height', Height);
2693 end;
2694 if config.ReadBool('Editor', 'Maximize', False) then
2695 WindowState := wsMaximized;
2696 ShowMap := config.ReadBool('Editor', 'Minimap', False);
2697 PanelProps.Width := config.ReadInt('Editor', 'PanelProps', PanelProps.ClientWidth);
2698 Splitter1.Left := PanelProps.Left;
2699 PanelObjs.Height := config.ReadInt('Editor', 'PanelObjs', PanelObjs.ClientHeight);
2700 Splitter2.Top := PanelObjs.Top;
2701 StatusBar.Top := PanelObjs.BoundsRect.Bottom;
2702 DotEnable := config.ReadBool('Editor', 'DotEnable', True);
2703 DotColor := config.ReadInt('Editor', 'DotColor', $FFFFFF);
2704 DotStepOne := config.ReadInt('Editor', 'DotStepOne', 16);
2705 DotStepTwo := config.ReadInt('Editor', 'DotStepTwo', 8);
2706 DotStep := config.ReadInt('Editor', 'DotStep', DotStepOne);
2707 DrawTexturePanel := config.ReadBool('Editor', 'DrawTexturePanel', True);
2708 DrawPanelSize := config.ReadBool('Editor', 'DrawPanelSize', True);
2709 BackColor := config.ReadInt('Editor', 'BackColor', $7F6040);
2710 PreviewColor := config.ReadInt('Editor', 'PreviewColor', $00FF00);
2711 UseCheckerboard := config.ReadBool('Editor', 'UseCheckerboard', True);
2712 gColorEdge := config.ReadInt('Editor', 'EdgeColor', COLOR_EDGE);
2713 gAlphaEdge := config.ReadInt('Editor', 'EdgeAlpha', ALPHA_EDGE);
2714 if gAlphaEdge = 255 then
2715 gAlphaEdge := ALPHA_EDGE;
2716 drEdge[0] := GetRValue(gColorEdge);
2717 drEdge[1] := GetGValue(gColorEdge);
2718 drEdge[2] := GetBValue(gColorEdge);
2719 if not config.ReadBool('Editor', 'EdgeShow', True) then
2720 drEdge[3] := 255
2721 else
2722 drEdge[3] := gAlphaEdge;
2723 gAlphaTriggerLine := config.ReadInt('Editor', 'LineAlpha', ALPHA_LINE);
2724 if gAlphaTriggerLine = 255 then
2725 gAlphaTriggerLine := ALPHA_LINE;
2726 gAlphaTriggerArea := config.ReadInt('Editor', 'TriggerAlpha', ALPHA_AREA);
2727 if gAlphaTriggerArea = 255 then
2728 gAlphaTriggerArea := ALPHA_AREA;
2729 gAlphaMonsterRect := config.ReadInt('Editor', 'MonsterRectAlpha', 0);
2730 gAlphaAreaRect := config.ReadInt('Editor', 'AreaRectAlpha', 0);
2731 if config.ReadInt('Editor', 'Scale', 0) = 1 then
2732 Scale := 2
2733 else
2734 Scale := 1;
2735 if config.ReadInt('Editor', 'DotSize', 0) = 1 then
2736 DotSize := 2
2737 else
2738 DotSize := 1;
2739 OpenDialog.InitialDir := config.ReadStr('Editor', 'LastOpenDir', EditorDir);
2740 SaveDialog.InitialDir := config.ReadStr('Editor', 'LastSaveDir', EditorDir);
2742 s := config.ReadStr('Editor', 'Language', '');
2743 gLanguage := s;
2745 RecentCount := config.ReadInt('Editor', 'RecentCount', 5);
2746 if RecentCount > 10 then
2747 RecentCount := 10;
2748 if RecentCount < 2 then
2749 RecentCount := 2;
2751 RecentFiles := TStringList.Create();
2752 for i := 0 to RecentCount-1 do
2753 begin
2754 s := config.ReadStr('RecentFiles', IntToStr(i+1), '');
2755 if s <> '' then
2756 RecentFiles.Add(s);
2757 end;
2758 RefreshRecentMenu();
2760 config.Free();
2762 tbShowMap.Down := ShowMap;
2763 tbGridOn.Down := DotEnable;
2764 pcObjects.ActivePageIndex := 0;
2765 Application.Title := _lc[I_EDITOR_TITLE];
2767 Application.OnIdle := OnIdle;
2768 end;
2770 procedure PrintBlack(X, Y: Integer; Text: string; FontID: DWORD);
2771 begin
2772 // NOTE: all the font printing routines assume CP1251
2773 e_TextureFontPrintEx(X, Y, Text, FontID, 0, 0, 0, 1.0);
2774 end;
2776 procedure TMainForm.Draw();
2777 var
2778 x, y: Integer;
2779 a, b: Integer;
2780 ID, PID: DWORD;
2781 Width, Height: Word;
2782 Rect: TRectWH;
2783 ObjCount: Word;
2784 aX, aY, aX2, aY2, XX, ScaleSz: Integer;
2785 begin
2786 ID := 0;
2787 PID := 0;
2788 Width := 0;
2789 Height := 0;
2791 e_BeginRender();
2793 e_Clear(GL_COLOR_BUFFER_BIT,
2794 GetRValue(BackColor)/255,
2795 GetGValue(BackColor)/255,
2796 GetBValue(BackColor)/255);
2798 DrawMap();
2800 ObjCount := SelectedObjectCount();
2802 // Обводим выделенные объекты красной рамкой:
2803 if ObjCount > 0 then
2804 begin
2805 for a := 0 to High(SelectedObjects) do
2806 if SelectedObjects[a].Live then
2807 begin
2808 Rect := ObjectGetRect(SelectedObjects[a].ObjectType, SelectedObjects[a].ID);
2810 with Rect do
2811 begin
2812 e_DrawQuad(X+MapOffset.X, Y+MapOffset.Y,
2813 X+MapOffset.X+Width-1, Y+MapOffset.Y+Height-1,
2814 255, 0, 0);
2816 // Рисуем точки изменения размеров:
2817 if (ObjCount = 1) and
2818 (SelectedObjects[GetFirstSelected].ObjectType in [OBJECT_PANEL, OBJECT_TRIGGER]) then
2819 begin
2820 e_DrawPoint(5, X+MapOffset.X, Y+MapOffset.Y+(Height div 2), 255, 255, 255);
2821 e_DrawPoint(5, X+MapOffset.X+Width-1, Y+MapOffset.Y+(Height div 2), 255, 255, 255);
2822 e_DrawPoint(5, X+MapOffset.X+(Width div 2), Y+MapOffset.Y, 255, 255, 255);
2823 e_DrawPoint(5, X+MapOffset.X+(Width div 2), Y+MapOffset.Y+Height-1, 255, 255, 255);
2825 e_DrawPoint(3, X+MapOffset.X, Y+MapOffset.Y+(Height div 2), 255, 0, 0);
2826 e_DrawPoint(3, X+MapOffset.X+Width-1, Y+MapOffset.Y+(Height div 2), 255, 0, 0);
2827 e_DrawPoint(3, X+MapOffset.X+(Width div 2), Y+MapOffset.Y, 255, 0, 0);
2828 e_DrawPoint(3, X+MapOffset.X+(Width div 2), Y+MapOffset.Y+Height-1, 255, 0, 0);
2829 end;
2830 end;
2831 end;
2832 end;
2834 // Рисуем сетку:
2835 if DotEnable and (PreviewMode = 0) then
2836 begin
2837 if DotSize = 2 then
2838 a := -1
2839 else
2840 a := 0;
2842 for x := 0 to (RenderPanel.Width div DotStep) do
2843 for y := 0 to (RenderPanel.Height div DotStep) do
2844 e_DrawPoint(DotSize, x*DotStep + a, y*DotStep + a,
2845 GetRValue(DotColor),
2846 GetGValue(DotColor),
2847 GetBValue(DotColor));
2848 end;
2850 // Превью текстуры:
2851 if (lbTextureList.ItemIndex <> -1) and (cbPreview.Checked) and
2852 (not IsSpecialTextureSel()) and (PreviewMode = 0) then
2853 begin
2854 if not g_GetTexture(SelectedTexture(), ID) then
2855 g_GetTexture('NOTEXTURE', ID);
2856 g_GetTextureSizeByID(ID, Width, Height);
2857 if UseCheckerboard then
2858 begin
2859 if g_GetTexture('PREVIEW', PID) then
2860 e_DrawFill(PID, RenderPanel.Width-Width, RenderPanel.Height-Height, Width div 16 + 1, Height div 16 + 1, 0, True, False);
2861 end else
2862 e_DrawFillQuad(RenderPanel.Width-Width-2, RenderPanel.Height-Height-2,
2863 RenderPanel.Width-1, RenderPanel.Height-1,
2864 GetRValue(PreviewColor), GetGValue(PreviewColor), GetBValue(PreviewColor), 0);
2865 e_Draw(ID, RenderPanel.Width-Width, RenderPanel.Height-Height, 0, True, False);
2866 end;
2868 // Подсказка при выборе точки Телепорта:
2869 if SelectFlag = SELECTFLAG_TELEPORT then
2870 begin
2871 with gTriggers[SelectedObjects[GetFirstSelected()].ID] do
2872 if Data.d2d_teleport then
2873 e_DrawLine(2, MousePos.X-16, MousePos.Y-1,
2874 MousePos.X+16, MousePos.Y-1,
2875 0, 0, 255)
2876 else
2877 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+AreaSize[AREA_DMPOINT].Width-1,
2878 MousePos.Y+AreaSize[AREA_DMPOINT].Height-1, 255, 255, 255);
2880 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 192, 192, 192, 127);
2881 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 255, 255, 255);
2882 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_TELEPORT], gEditorFont);
2883 end;
2885 // Подсказка при выборе точки появления:
2886 if SelectFlag = SELECTFLAG_SPAWNPOINT then
2887 begin
2888 e_DrawLine(2, MousePos.X-16, MousePos.Y-1,
2889 MousePos.X+16, MousePos.Y-1,
2890 0, 0, 255);
2891 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 192, 192, 192, 127);
2892 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 255, 255, 255);
2893 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_SPAWN], gEditorFont);
2894 end;
2896 // Подсказка при выборе панели двери:
2897 if SelectFlag = SELECTFLAG_DOOR then
2898 begin
2899 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 192, 192, 192, 127);
2900 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 255, 255, 255);
2901 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_PANEL_DOOR], gEditorFont);
2902 end;
2904 // Подсказка при выборе панели с текстурой:
2905 if SelectFlag = SELECTFLAG_TEXTURE then
2906 begin
2907 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+196, MousePos.Y+18, 192, 192, 192, 127);
2908 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+196, MousePos.Y+18, 255, 255, 255);
2909 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_PANEL_TEXTURE], gEditorFont);
2910 end;
2912 // Подсказка при выборе панели индикации выстрела:
2913 if SelectFlag = SELECTFLAG_SHOTPANEL then
2914 begin
2915 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+316, MousePos.Y+18, 192, 192, 192, 127);
2916 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+316, MousePos.Y+18, 255, 255, 255);
2917 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_PANEL_SHOT], gEditorFont);
2918 end;
2920 // Подсказка при выборе панели лифта:
2921 if SelectFlag = SELECTFLAG_LIFT then
2922 begin
2923 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 192, 192, 192, 127);
2924 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 255, 255, 255);
2925 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_PANEL_LIFT], gEditorFont);
2926 end;
2928 // Подсказка при выборе монстра:
2929 if SelectFlag = SELECTFLAG_MONSTER then
2930 begin
2931 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+120, MousePos.Y+18, 192, 192, 192, 127);
2932 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+120, MousePos.Y+18, 255, 255, 255);
2933 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_MONSTER], gEditorFont);
2934 end;
2936 // Подсказка при выборе области воздействия:
2937 if DrawPressRect then
2938 begin
2939 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+204, MousePos.Y+18, 192, 192, 192, 127);
2940 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+204, MousePos.Y+18, 255, 255, 255);
2941 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_EXT_AREA], gEditorFont);
2942 end;
2944 // Рисуем текстуры, если чертим панель:
2945 if (MouseAction = MOUSEACTION_DRAWPANEL) and (DrawTexturePanel) and
2946 (lbTextureList.ItemIndex <> -1) and (DrawRect <> nil) and
2947 (lbPanelType.ItemIndex in [0..8]) and not IsSpecialTextureSel() then
2948 begin
2949 if not g_GetTexture(SelectedTexture(), ID) then
2950 g_GetTexture('NOTEXTURE', ID);
2951 g_GetTextureSizeByID(ID, Width, Height);
2952 with DrawRect^ do
2953 if (Abs(Right-Left) >= Width) and (Abs(Bottom-Top) >= Height) then
2954 e_DrawFill(ID, Min(Left, Right), Min(Top, Bottom), Abs(Right-Left) div Width,
2955 Abs(Bottom-Top) div Height, 64, True, False);
2956 end;
2958 // Прямоугольник выделения:
2959 if DrawRect <> nil then
2960 with DrawRect^ do
2961 e_DrawQuad(Left, Top, Right-1, Bottom-1, 255, 255, 255);
2963 // Чертим мышью панель/триггер или меняем мышью их размер:
2964 if (((MouseAction in [MOUSEACTION_DRAWPANEL, MOUSEACTION_DRAWTRIGGER]) and
2965 not(ssCtrl in GetKeyShiftState())) or (MouseAction = MOUSEACTION_RESIZE)) and
2966 (DrawPanelSize) then
2967 begin
2968 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+88, MousePos.Y+33, 192, 192, 192, 127);
2969 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+88, MousePos.Y+33, 255, 255, 255);
2971 if MouseAction in [MOUSEACTION_DRAWPANEL, MOUSEACTION_DRAWTRIGGER] then
2972 begin // Чертим новый
2973 PrintBlack(MousePos.X+2, MousePos.Y+2, Format(_glc[I_HINT_WIDTH],
2974 [Abs(MousePos.X-MouseLDownPos.X)]), gEditorFont);
2975 PrintBlack(MousePos.X+2, MousePos.Y+16, Format(_glc[I_HINT_HEIGHT],
2976 [Abs(MousePos.Y-MouseLDownPos.Y)]), gEditorFont);
2977 end
2978 else // Растягиваем существующий
2979 if SelectedObjects[GetFirstSelected].ObjectType in [OBJECT_PANEL, OBJECT_TRIGGER] then
2980 begin
2981 if SelectedObjects[GetFirstSelected].ObjectType = OBJECT_PANEL then
2982 begin
2983 Width := gPanels[SelectedObjects[GetFirstSelected].ID].Width;
2984 Height := gPanels[SelectedObjects[GetFirstSelected].ID].Height;
2985 end
2986 else
2987 begin
2988 Width := gTriggers[SelectedObjects[GetFirstSelected].ID].Width;
2989 Height := gTriggers[SelectedObjects[GetFirstSelected].ID].Height;
2990 end;
2992 PrintBlack(MousePos.X+2, MousePos.Y+2, Format(_glc[I_HINT_WIDTH], [Width]),
2993 gEditorFont);
2994 PrintBlack(MousePos.X+2, MousePos.Y+16, Format(_glc[I_HINT_HEIGHT], [Height]),
2995 gEditorFont);
2996 end;
2997 end;
2999 // Ближайшая к курсору мыши точка на сетке:
3000 e_DrawPoint(3, MousePos.X, MousePos.Y, 0, 0, 255);
3002 // Мини-карта:
3003 if ShowMap then
3004 begin
3005 // Сколько пикселов карты в 1 пикселе мини-карты:
3006 ScaleSz := 16 div Scale;
3007 // Размеры мини-карты:
3008 aX := max(gMapInfo.Width div ScaleSz, 1);
3009 aY := max(gMapInfo.Height div ScaleSz, 1);
3010 // X-координата на RenderPanel нулевой x-координаты карты:
3011 XX := RenderPanel.Width - aX - 1;
3012 // Рамка карты:
3013 e_DrawFillQuad(XX-1, 0, RenderPanel.Width-1, aY+1, 0, 0, 0, 0);
3014 e_DrawQuad(XX-1, 0, RenderPanel.Width-1, aY+1, 197, 197, 197);
3016 if gPanels <> nil then
3017 begin
3018 // Рисуем панели:
3019 for a := 0 to High(gPanels) do
3020 with gPanels[a] do
3021 if PanelType <> 0 then
3022 begin
3023 // Левый верхний угол:
3024 aX := XX + (X div ScaleSz);
3025 aY := 1 + (Y div ScaleSz);
3026 // Размеры:
3027 aX2 := max(Width div ScaleSz, 1);
3028 aY2 := max(Height div ScaleSz, 1);
3029 // Правый нижний угол:
3030 aX2 := aX + aX2 - 1;
3031 aY2 := aY + aY2 - 1;
3033 case PanelType of
3034 PANEL_WALL: e_DrawFillQuad(aX, aY, aX2, aY2, 208, 208, 208, 0);
3035 PANEL_WATER: e_DrawFillQuad(aX, aY, aX2, aY2, 0, 0, 192, 0);
3036 PANEL_ACID1: e_DrawFillQuad(aX, aY, aX2, aY2, 0, 176, 0, 0);
3037 PANEL_ACID2: e_DrawFillQuad(aX, aY, aX2, aY2, 176, 0, 0, 0);
3038 PANEL_STEP: e_DrawFillQuad(aX, aY, aX2, aY2, 128, 128, 128, 0);
3039 PANEL_LIFTUP: e_DrawFillQuad(aX, aY, aX2, aY2, 116, 72, 36, 0);
3040 PANEL_LIFTDOWN: e_DrawFillQuad(aX, aY, aX2, aY2, 116, 124, 96, 0);
3041 PANEL_LIFTLEFT: e_DrawFillQuad(aX, aY, aX2, aY2, 200, 80, 4, 0);
3042 PANEL_LIFTRIGHT: e_DrawFillQuad(aX, aY, aX2, aY2, 252, 140, 56, 0);
3043 PANEL_OPENDOOR: e_DrawFillQuad(aX, aY, aX2, aY2, 100, 220, 92, 0);
3044 PANEL_CLOSEDOOR: e_DrawFillQuad(aX, aY, aX2, aY2, 212, 184, 64, 0);
3045 PANEL_BLOCKMON: e_DrawFillQuad(aX, aY, aX2, aY2, 192, 0, 192, 0);
3046 end;
3047 end;
3049 // Рисуем красным выделенные панели:
3050 if SelectedObjects <> nil then
3051 for b := 0 to High(SelectedObjects) do
3052 with SelectedObjects[b] do
3053 if Live and (ObjectType = OBJECT_PANEL) then
3054 with gPanels[SelectedObjects[b].ID] do
3055 if PanelType and not(PANEL_BACK or PANEL_FORE) <> 0 then
3056 begin
3057 // Левый верхний угол:
3058 aX := XX + (X div ScaleSz);
3059 aY := 1 + (Y div ScaleSz);
3060 // Размеры:
3061 aX2 := max(Width div ScaleSz, 1);
3062 aY2 := max(Height div ScaleSz, 1);
3063 // Правый нижний угол:
3064 aX2 := aX + aX2 - 1;
3065 aY2 := aY + aY2 - 1;
3067 e_DrawFillQuad(aX, aY, aX2, aY2, 255, 0, 0, 0)
3068 end;
3069 end;
3071 if (gMapInfo.Width > RenderPanel.Width) or
3072 (gMapInfo.Height > RenderPanel.Height) then
3073 begin
3074 // Окно, показывающее текущее положение экрана на карте:
3075 // Размеры окна:
3076 x := max(min(RenderPanel.Width, gMapInfo.Width) div ScaleSz, 1);
3077 y := max(min(RenderPanel.Height, gMapInfo.Height) div ScaleSz, 1);
3078 // Левый верхний угол:
3079 aX := XX + ((-MapOffset.X) div ScaleSz);
3080 aY := 1 + ((-MapOffset.Y) div ScaleSz);
3081 // Правый нижний угол:
3082 aX2 := aX + x - 1;
3083 aY2 := aY + y - 1;
3085 e_DrawFillQuad(aX, aY, aX2, aY2, 127, 192, 127, 127, B_BLEND);
3086 e_DrawQuad(aX, aY, aX2, aY2, 255, 0, 0);
3087 end;
3088 end; // Мини-карта
3090 e_EndRender();
3091 RenderPanel.SwapBuffers();
3092 end;
3094 procedure TMainForm.FormResize(Sender: TObject);
3095 begin
3096 e_SetViewPort(0, 0, RenderPanel.Width, RenderPanel.Height);
3098 if gMapInfo.Width >= RenderPanel.Width then
3099 sbHorizontal.Max := Normalize16(gMapInfo.Width-RenderPanel.Width+16)
3100 else
3101 sbHorizontal.Max := 0;
3103 if gMapInfo.Height >= RenderPanel.Height then
3104 sbVertical.Max := Normalize16(gMapInfo.Height-RenderPanel.Height+16)
3105 else
3106 sbVertical.Max := 0;
3108 MapOffset.X := -Normalize16(sbHorizontal.Position);
3109 MapOffset.Y := -Normalize16(sbVertical.Position);
3110 end;
3112 procedure SelectNextObject(X, Y: Integer; ObjectType: Byte; ID: DWORD);
3113 var
3114 j, j_max: Integer;
3115 res: Boolean;
3116 begin
3117 j_max := 0; // shut up compiler
3118 case ObjectType of
3119 OBJECT_PANEL:
3120 begin
3121 res := (gPanels <> nil) and
3122 PanelInShownLayer(gPanels[ID].PanelType) and
3123 g_CollidePoint(X, Y, gPanels[ID].X, gPanels[ID].Y,
3124 gPanels[ID].Width,
3125 gPanels[ID].Height);
3126 j_max := Length(gPanels) - 1;
3127 end;
3129 OBJECT_ITEM:
3130 begin
3131 res := (gItems <> nil) and
3132 LayerEnabled[LAYER_ITEMS] and
3133 g_CollidePoint(X, Y, gItems[ID].X, gItems[ID].Y,
3134 ItemSize[gItems[ID].ItemType][0],
3135 ItemSize[gItems[ID].ItemType][1]);
3136 j_max := Length(gItems) - 1;
3137 end;
3139 OBJECT_MONSTER:
3140 begin
3141 res := (gMonsters <> nil) and
3142 LayerEnabled[LAYER_MONSTERS] and
3143 g_CollidePoint(X, Y, gMonsters[ID].X, gMonsters[ID].Y,
3144 MonsterSize[gMonsters[ID].MonsterType].Width,
3145 MonsterSize[gMonsters[ID].MonsterType].Height);
3146 j_max := Length(gMonsters) - 1;
3147 end;
3149 OBJECT_AREA:
3150 begin
3151 res := (gAreas <> nil) and
3152 LayerEnabled[LAYER_AREAS] and
3153 g_CollidePoint(X, Y, gAreas[ID].X, gAreas[ID].Y,
3154 AreaSize[gAreas[ID].AreaType].Width,
3155 AreaSize[gAreas[ID].AreaType].Height);
3156 j_max := Length(gAreas) - 1;
3157 end;
3159 OBJECT_TRIGGER:
3160 begin
3161 res := (gTriggers <> nil) and
3162 LayerEnabled[LAYER_TRIGGERS] and
3163 g_CollidePoint(X, Y, gTriggers[ID].X, gTriggers[ID].Y,
3164 gTriggers[ID].Width,
3165 gTriggers[ID].Height);
3166 j_max := Length(gTriggers) - 1;
3167 end;
3169 else
3170 res := False;
3171 end;
3173 if not res then
3174 Exit;
3176 // Перебор ID: от ID-1 до 0; потом от High до ID+1:
3177 j := ID;
3179 while True do
3180 begin
3181 Dec(j);
3183 if j < 0 then
3184 j := j_max;
3185 if j = Integer(ID) then
3186 Break;
3188 case ObjectType of
3189 OBJECT_PANEL:
3190 res := PanelInShownLayer(gPanels[j].PanelType) and
3191 g_CollidePoint(X, Y, gPanels[j].X, gPanels[j].Y,
3192 gPanels[j].Width,
3193 gPanels[j].Height);
3194 OBJECT_ITEM:
3195 res := (gItems[j].ItemType <> ITEM_NONE) and
3196 g_CollidePoint(X, Y, gItems[j].X, gItems[j].Y,
3197 ItemSize[gItems[j].ItemType][0],
3198 ItemSize[gItems[j].ItemType][1]);
3199 OBJECT_MONSTER:
3200 res := (gMonsters[j].MonsterType <> MONSTER_NONE) and
3201 g_CollidePoint(X, Y, gMonsters[j].X, gMonsters[j].Y,
3202 MonsterSize[gMonsters[j].MonsterType].Width,
3203 MonsterSize[gMonsters[j].MonsterType].Height);
3204 OBJECT_AREA:
3205 res := (gAreas[j].AreaType <> AREA_NONE) and
3206 g_CollidePoint(X, Y, gAreas[j].X, gAreas[j].Y,
3207 AreaSize[gAreas[j].AreaType].Width,
3208 AreaSize[gAreas[j].AreaType].Height);
3209 OBJECT_TRIGGER:
3210 res := (gTriggers[j].TriggerType <> TRIGGER_NONE) and
3211 g_CollidePoint(X, Y, gTriggers[j].X, gTriggers[j].Y,
3212 gTriggers[j].Width,
3213 gTriggers[j].Height);
3214 else
3215 res := False;
3216 end;
3218 if res then
3219 begin
3220 SetLength(SelectedObjects, 1);
3222 SelectedObjects[0].ObjectType := ObjectType;
3223 SelectedObjects[0].ID := j;
3224 SelectedObjects[0].Live := True;
3226 FillProperty();
3227 Break;
3228 end;
3229 end;
3230 end;
3232 procedure TMainForm.RenderPanelMouseDown(Sender: TObject;
3233 Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
3234 var
3235 i: Integer;
3236 Rect: TRectWH;
3237 c1, c2, c3, c4: Boolean;
3238 item: TItem;
3239 area: TArea;
3240 monster: TMonster;
3241 IDArray: DWArray;
3242 begin
3243 MainForm.ActiveControl := RenderPanel;
3244 RenderPanel.SetFocus();
3246 RenderPanelMouseMove(RenderPanel, Shift, X, Y);
3248 if Button = mbLeft then // Left Mouse Button
3249 begin
3250 // Двигаем карту с помощью мыши и мини-карты:
3251 if ShowMap and
3252 g_CollidePoint(X, Y,
3253 RenderPanel.Width-max(gMapInfo.Width div (16 div Scale), 1)-1,
3254 1,
3255 max(gMapInfo.Width div (16 div Scale), 1),
3256 max(gMapInfo.Height div (16 div Scale), 1) ) then
3257 begin
3258 MoveMap(X, Y);
3259 MouseAction := MOUSEACTION_MOVEMAP;
3260 end
3261 else // Ставим предмет/монстра/область:
3262 if (pcObjects.ActivePageIndex in [1, 2, 3]) and
3263 (not (ssShift in Shift)) then
3264 begin
3265 case pcObjects.ActivePageIndex of
3266 1:
3267 if lbItemList.ItemIndex = -1 then
3268 ErrorMessageBox(_lc[I_MSG_CHOOSE_ITEM])
3269 else
3270 begin
3271 item.ItemType := lbItemList.ItemIndex + ITEM_MEDKIT_SMALL;
3272 if item.ItemType >= ITEM_WEAPON_KASTET then
3273 item.ItemType := item.ItemType + 2;
3274 item.X := MousePos.X-MapOffset.X;
3275 item.Y := MousePos.Y-MapOffset.Y;
3277 if not (ssCtrl in Shift) then
3278 begin
3279 item.X := item.X - (ItemSize[item.ItemType][0] div 2);
3280 item.Y := item.Y - ItemSize[item.ItemType][1];
3281 end;
3283 item.OnlyDM := cbOnlyDM.Checked;
3284 item.Fall := cbFall.Checked;
3285 Undo_Add(OBJECT_ITEM, AddItem(item));
3286 end;
3287 2:
3288 if lbMonsterList.ItemIndex = -1 then
3289 ErrorMessageBox(_lc[I_MSG_CHOOSE_MONSTER])
3290 else
3291 begin
3292 monster.MonsterType := lbMonsterList.ItemIndex + MONSTER_DEMON;
3293 monster.X := MousePos.X-MapOffset.X;
3294 monster.Y := MousePos.Y-MapOffset.Y;
3296 if not (ssCtrl in Shift) then
3297 begin
3298 monster.X := monster.X - (MonsterSize[monster.MonsterType].Width div 2);
3299 monster.Y := monster.Y - MonsterSize[monster.MonsterType].Height;
3300 end;
3302 if rbMonsterLeft.Checked then
3303 monster.Direction := D_LEFT
3304 else
3305 monster.Direction := D_RIGHT;
3306 Undo_Add(OBJECT_MONSTER, AddMonster(monster));
3307 end;
3308 3:
3309 if lbAreasList.ItemIndex = -1 then
3310 ErrorMessageBox(_lc[I_MSG_CHOOSE_AREA])
3311 else
3312 if (lbAreasList.ItemIndex + 1) <> AREA_DOMFLAG then
3313 begin
3314 area.AreaType := lbAreasList.ItemIndex + AREA_PLAYERPOINT1;
3315 area.X := MousePos.X-MapOffset.X;
3316 area.Y := MousePos.Y-MapOffset.Y;
3318 if not (ssCtrl in Shift) then
3319 begin
3320 area.X := area.X - (AreaSize[area.AreaType].Width div 2);
3321 area.Y := area.Y - AreaSize[area.AreaType].Height;
3322 end;
3324 if rbAreaLeft.Checked then
3325 area.Direction := D_LEFT
3326 else
3327 area.Direction := D_RIGHT;
3328 Undo_Add(OBJECT_AREA, AddArea(area));
3329 end;
3330 end;
3331 end
3332 else
3333 begin
3334 i := GetFirstSelected();
3336 // Выбираем объект под текущим:
3337 if (SelectedObjects <> nil) and
3338 (ssShift in Shift) and (i >= 0) and
3339 (SelectedObjects[i].Live) then
3340 begin
3341 if SelectedObjectCount() = 1 then
3342 SelectNextObject(X-MapOffset.X, Y-MapOffset.Y,
3343 SelectedObjects[i].ObjectType,
3344 SelectedObjects[i].ID);
3345 end
3346 else
3347 begin
3348 // Рисуем область триггера "Расширитель":
3349 if DrawPressRect and (i >= 0) and
3350 (SelectedObjects[i].ObjectType = OBJECT_TRIGGER) and
3351 (gTriggers[SelectedObjects[i].ID].TriggerType in
3352 [TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF]) then
3353 MouseAction := MOUSEACTION_DRAWPRESS
3354 else // Рисуем панель:
3355 if pcObjects.ActivePageIndex = 0 then
3356 begin
3357 if (lbPanelType.ItemIndex >= 0) then
3358 MouseAction := MOUSEACTION_DRAWPANEL
3359 end
3360 else // Рисуем триггер:
3361 if (lbTriggersList.ItemIndex >= 0) then
3362 begin
3363 MouseAction := MOUSEACTION_DRAWTRIGGER;
3364 end;
3365 end;
3366 end;
3367 end; // if Button = mbLeft
3369 if Button = mbRight then // Right Mouse Button
3370 begin
3371 // Клик по мини-карте:
3372 if ShowMap and
3373 g_CollidePoint(X, Y,
3374 RenderPanel.Width-max(gMapInfo.Width div (16 div Scale), 1)-1,
3375 1,
3376 max(gMapInfo.Width div (16 div Scale), 1),
3377 max(gMapInfo.Height div (16 div Scale), 1) ) then
3378 begin
3379 MouseAction := MOUSEACTION_NOACTION;
3380 end
3381 else // Нужно что-то выбрать мышью:
3382 if SelectFlag <> SELECTFLAG_NONE then
3383 begin
3384 case SelectFlag of
3385 SELECTFLAG_TELEPORT:
3386 // Точку назначения телепортации:
3387 with gTriggers[SelectedObjects[
3388 GetFirstSelected() ].ID].Data.TargetPoint do
3389 begin
3390 X := MousePos.X-MapOffset.X;
3391 Y := MousePos.Y-MapOffset.Y;
3392 end;
3394 SELECTFLAG_SPAWNPOINT:
3395 // Точку создания монстра:
3396 with gTriggers[SelectedObjects[GetFirstSelected()].ID] do
3397 if TriggerType = TRIGGER_SPAWNMONSTER then
3398 begin
3399 Data.MonPos.X := MousePos.X-MapOffset.X;
3400 Data.MonPos.Y := MousePos.Y-MapOffset.Y;
3401 end
3402 else if TriggerType = TRIGGER_SPAWNITEM then
3403 begin // Точка создания предмета:
3404 Data.ItemPos.X := MousePos.X-MapOffset.X;
3405 Data.ItemPos.Y := MousePos.Y-MapOffset.Y;
3406 end
3407 else if TriggerType = TRIGGER_SHOT then
3408 begin // Точка создания выстрела:
3409 Data.ShotPos.X := MousePos.X-MapOffset.X;
3410 Data.ShotPos.Y := MousePos.Y-MapOffset.Y;
3411 end;
3413 SELECTFLAG_DOOR:
3414 // Дверь:
3415 begin
3416 IDArray := ObjectInRect(X-MapOffset.X,
3417 Y-MapOffset.Y,
3418 2, 2, OBJECT_PANEL, True);
3419 if IDArray <> nil then
3420 begin
3421 for i := 0 to High(IDArray) do
3422 if (gPanels[IDArray[i]].PanelType = PANEL_OPENDOOR) or
3423 (gPanels[IDArray[i]].PanelType = PANEL_CLOSEDOOR) then
3424 begin
3425 gTriggers[SelectedObjects[
3426 GetFirstSelected() ].ID].Data.PanelID := IDArray[i];
3427 Break;
3428 end;
3429 end
3430 else
3431 gTriggers[SelectedObjects[
3432 GetFirstSelected() ].ID].Data.PanelID := -1;
3433 end;
3435 SELECTFLAG_TEXTURE:
3436 // Панель с текстурой:
3437 begin
3438 IDArray := ObjectInRect(X-MapOffset.X,
3439 Y-MapOffset.Y,
3440 2, 2, OBJECT_PANEL, True);
3441 if IDArray <> nil then
3442 begin
3443 for i := 0 to High(IDArray) do
3444 if ((gPanels[IDArray[i]].PanelType in
3445 [PANEL_WALL, PANEL_BACK, PANEL_FORE,
3446 PANEL_WATER, PANEL_ACID1, PANEL_ACID2,
3447 PANEL_STEP]) or
3448 (gPanels[IDArray[i]].PanelType = PANEL_OPENDOOR) or
3449 (gPanels[IDArray[i]].PanelType = PANEL_CLOSEDOOR)) and
3450 (gPanels[IDArray[i]].TextureName <> '') then
3451 begin
3452 gTriggers[SelectedObjects[
3453 GetFirstSelected() ].ID].TexturePanel := IDArray[i];
3454 Break;
3455 end;
3456 end
3457 else
3458 gTriggers[SelectedObjects[
3459 GetFirstSelected() ].ID].TexturePanel := -1;
3460 end;
3462 SELECTFLAG_LIFT:
3463 // Лифт:
3464 begin
3465 IDArray := ObjectInRect(X-MapOffset.X,
3466 Y-MapOffset.Y,
3467 2, 2, OBJECT_PANEL, True);
3468 if IDArray <> nil then
3469 begin
3470 for i := 0 to High(IDArray) do
3471 if (gPanels[IDArray[i]].PanelType = PANEL_LIFTUP) or
3472 (gPanels[IDArray[i]].PanelType = PANEL_LIFTDOWN) or
3473 (gPanels[IDArray[i]].PanelType = PANEL_LIFTLEFT) or
3474 (gPanels[IDArray[i]].PanelType = PANEL_LIFTRIGHT) then
3475 begin
3476 gTriggers[SelectedObjects[
3477 GetFirstSelected() ].ID].Data.PanelID := IDArray[i];
3478 Break;
3479 end;
3480 end
3481 else
3482 gTriggers[SelectedObjects[
3483 GetFirstSelected() ].ID].Data.PanelID := -1;
3484 end;
3486 SELECTFLAG_MONSTER:
3487 // Монстра:
3488 begin
3489 IDArray := ObjectInRect(X-MapOffset.X,
3490 Y-MapOffset.Y,
3491 2, 2, OBJECT_MONSTER, False);
3492 if IDArray <> nil then
3493 gTriggers[SelectedObjects[
3494 GetFirstSelected() ].ID].Data.MonsterID := IDArray[0]+1
3495 else
3496 gTriggers[SelectedObjects[
3497 GetFirstSelected() ].ID].Data.MonsterID := 0;
3498 end;
3500 SELECTFLAG_SHOTPANEL:
3501 // Панель индикации выстрела:
3502 begin
3503 if gTriggers[SelectedObjects[
3504 GetFirstSelected() ].ID].TriggerType = TRIGGER_SHOT then
3505 begin
3506 IDArray := ObjectInRect(X-MapOffset.X,
3507 Y-MapOffset.Y,
3508 2, 2, OBJECT_PANEL, True);
3509 if IDArray <> nil then
3510 begin
3511 for i := 0 to High(IDArray) do
3512 if ((gPanels[IDArray[i]].PanelType in
3513 [PANEL_WALL, PANEL_BACK, PANEL_FORE,
3514 PANEL_WATER, PANEL_ACID1, PANEL_ACID2,
3515 PANEL_STEP]) or
3516 (gPanels[IDArray[i]].PanelType = PANEL_OPENDOOR) or
3517 (gPanels[IDArray[i]].PanelType = PANEL_CLOSEDOOR)) and
3518 (gPanels[IDArray[i]].TextureName <> '') then
3519 begin
3520 gTriggers[SelectedObjects[
3521 GetFirstSelected() ].ID].Data.ShotPanelID := IDArray[i];
3522 Break;
3523 end;
3524 end
3525 else
3526 gTriggers[SelectedObjects[
3527 GetFirstSelected() ].ID].Data.ShotPanelID := -1;
3528 end;
3529 end;
3530 end;
3532 SelectFlag := SELECTFLAG_SELECTED;
3533 end
3534 else // if SelectFlag <> SELECTFLAG_NONE...
3535 begin
3536 // Что уже выбрано и не нажат Ctrl:
3537 if (SelectedObjects <> nil) and
3538 (not (ssCtrl in Shift)) then
3539 for i := 0 to High(SelectedObjects) do
3540 with SelectedObjects[i] do
3541 if Live then
3542 begin
3543 if (ObjectType in [OBJECT_PANEL, OBJECT_TRIGGER]) and
3544 (SelectedObjectCount() = 1) then
3545 begin
3546 Rect := ObjectGetRect(ObjectType, ID);
3548 c1 := g_Collide(X-MapOffset.X-1, Y-MapOffset.Y-1, 2, 2,
3549 Rect.X-2, Rect.Y+(Rect.Height div 2)-2, 4, 4);
3550 c2 := g_Collide(X-MapOffset.X-1, Y-MapOffset.Y-1, 2, 2,
3551 Rect.X+Rect.Width-3, Rect.Y+(Rect.Height div 2)-2, 4, 4);
3552 c3 := g_Collide(X-MapOffset.X-1, Y-MapOffset.Y-1, 2, 2,
3553 Rect.X+(Rect.Width div 2)-2, Rect.Y-2, 4, 4);
3554 c4 := g_Collide(X-MapOffset.X-1, Y-MapOffset.Y-1, 2, 2,
3555 Rect.X+(Rect.Width div 2)-2, Rect.Y+Rect.Height-3, 4, 4);
3557 // Меняем размер панели или триггера:
3558 if c1 or c2 or c3 or c4 then
3559 begin
3560 MouseAction := MOUSEACTION_RESIZE;
3561 LastMovePoint := MousePos;
3563 if c1 or c2 then
3564 begin // Шире/уже
3565 ResizeType := RESIZETYPE_HORIZONTAL;
3566 if c1 then
3567 ResizeDirection := RESIZEDIR_LEFT
3568 else
3569 ResizeDirection := RESIZEDIR_RIGHT;
3570 RenderPanel.Cursor := crSizeWE;
3571 end
3572 else
3573 begin // Выше/ниже
3574 ResizeType := RESIZETYPE_VERTICAL;
3575 if c3 then
3576 ResizeDirection := RESIZEDIR_UP
3577 else
3578 ResizeDirection := RESIZEDIR_DOWN;
3579 RenderPanel.Cursor := crSizeNS;
3580 end;
3582 Break;
3583 end;
3584 end;
3586 // Перемещаем панель или триггер:
3587 if ObjectCollide(ObjectType, ID,
3588 X-MapOffset.X-1,
3589 Y-MapOffset.Y-1, 2, 2) then
3590 begin
3591 MouseAction := MOUSEACTION_MOVEOBJ;
3592 LastMovePoint := MousePos;
3594 Break;
3595 end;
3596 end;
3597 end;
3598 end; // if Button = mbRight
3600 MouseRDown := Button = mbRight;
3601 if MouseRDown then
3602 MouseRDownPos := MousePos;
3604 MouseLDown := Button = mbLeft;
3605 if MouseLDown then
3606 MouseLDownPos := MousePos;
3607 end;
3609 procedure TMainForm.RenderPanelMouseUp(Sender: TObject;
3610 Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
3611 var
3612 panel: TPanel;
3613 trigger: TTrigger;
3614 rRect: TRectWH;
3615 rSelectRect: Boolean;
3616 wWidth, wHeight: Word;
3617 TextureID: DWORD;
3619 procedure SelectObjects(ObjectType: Byte);
3620 var
3621 i: Integer;
3622 IDArray: DWArray;
3623 begin
3624 IDArray := ObjectInRect(rRect.X, rRect.Y,
3625 rRect.Width, rRect.Height,
3626 ObjectType, rSelectRect);
3628 if IDArray <> nil then
3629 for i := 0 to High(IDArray) do
3630 SelectObject(ObjectType, IDArray[i], (ssCtrl in Shift) or rSelectRect);
3631 end;
3632 begin
3633 if Button = mbLeft then
3634 MouseLDown := False;
3635 if Button = mbRight then
3636 MouseRDown := False;
3638 DrawRect := nil;
3639 ResizeType := RESIZETYPE_NONE;
3640 TextureID := 0;
3642 if Button = mbLeft then // Left Mouse Button
3643 begin
3644 if MouseAction <> MOUSEACTION_NONE then
3645 begin // Было действие мышью
3646 // Мышь сдвинулась во время удержания клавиши,
3647 // либо активирован режим быстрого рисования:
3648 if ((MousePos.X <> MouseLDownPos.X) and
3649 (MousePos.Y <> MouseLDownPos.Y)) or
3650 ((MouseAction in [MOUSEACTION_DRAWPANEL, MOUSEACTION_DRAWTRIGGER]) and
3651 (ssCtrl in Shift)) then
3652 case MouseAction of
3653 // Рисовали панель:
3654 MOUSEACTION_DRAWPANEL:
3655 begin
3656 // Фон или передний план без текстуры - ошибка:
3657 if (lbPanelType.ItemIndex in [1, 2]) and
3658 (lbTextureList.ItemIndex = -1) then
3659 ErrorMessageBox(_lc[I_MSG_CHOOSE_TEXTURE])
3660 else // Назначаем параметры панели:
3661 begin
3662 case lbPanelType.ItemIndex of
3663 0: Panel.PanelType := PANEL_WALL;
3664 1: Panel.PanelType := PANEL_BACK;
3665 2: Panel.PanelType := PANEL_FORE;
3666 3: Panel.PanelType := PANEL_OPENDOOR;
3667 4: Panel.PanelType := PANEL_CLOSEDOOR;
3668 5: Panel.PanelType := PANEL_STEP;
3669 6: Panel.PanelType := PANEL_WATER;
3670 7: Panel.PanelType := PANEL_ACID1;
3671 8: Panel.PanelType := PANEL_ACID2;
3672 9: Panel.PanelType := PANEL_LIFTUP;
3673 10: Panel.PanelType := PANEL_LIFTDOWN;
3674 11: Panel.PanelType := PANEL_LIFTLEFT;
3675 12: Panel.PanelType := PANEL_LIFTRIGHT;
3676 13: Panel.PanelType := PANEL_BLOCKMON;
3677 end;
3679 Panel.X := Min(MousePos.X-MapOffset.X, MouseLDownPos.X-MapOffset.X);
3680 Panel.Y := Min(MousePos.Y-MapOffset.Y, MouseLDownPos.Y-MapOffset.Y);
3681 if ssCtrl in Shift then
3682 begin
3683 wWidth := DotStep;
3684 wHeight := DotStep;
3685 if (lbTextureList.ItemIndex <> -1) and
3686 (not IsSpecialTextureSel()) then
3687 begin
3688 if not g_GetTexture(SelectedTexture(), TextureID) then
3689 g_GetTexture('NOTEXTURE', TextureID);
3690 g_GetTextureSizeByID(TextureID, wWidth, wHeight);
3691 end;
3692 Panel.Width := wWidth;
3693 Panel.Height := wHeight;
3694 end
3695 else
3696 begin
3697 Panel.Width := Abs(MousePos.X-MouseLDownPos.X);
3698 Panel.Height := Abs(MousePos.Y-MouseLDownPos.Y);
3699 end;
3701 // Лифты, блокМон или отсутствие текстуры - пустая текстура:
3702 if (lbPanelType.ItemIndex in [9, 10, 11, 12, 13]) or
3703 (lbTextureList.ItemIndex = -1) then
3704 begin
3705 Panel.TextureHeight := 1;
3706 Panel.TextureWidth := 1;
3707 Panel.TextureName := '';
3708 Panel.TextureID := TEXTURE_SPECIAL_NONE;
3709 end
3710 else // Есть текстура:
3711 begin
3712 Panel.TextureName := SelectedTexture();
3714 // Обычная текстура:
3715 if not IsSpecialTextureSel() then
3716 begin
3717 g_GetTextureSizeByName(Panel.TextureName,
3718 Panel.TextureWidth, Panel.TextureHeight);
3719 g_GetTexture(Panel.TextureName, Panel.TextureID);
3720 end
3721 else // Спец.текстура:
3722 begin
3723 Panel.TextureHeight := 1;
3724 Panel.TextureWidth := 1;
3725 Panel.TextureID := SpecialTextureID(SelectedTexture());
3726 end;
3727 end;
3729 Panel.Alpha := 0;
3730 Panel.Blending := False;
3732 Undo_Add(OBJECT_PANEL, AddPanel(Panel));
3733 end;
3734 end;
3736 // Рисовали триггер:
3737 MOUSEACTION_DRAWTRIGGER:
3738 begin
3739 trigger.X := Min(MousePos.X-MapOffset.X, MouseLDownPos.X-MapOffset.X);
3740 trigger.Y := Min(MousePos.Y-MapOffset.Y, MouseLDownPos.Y-MapOffset.Y);
3741 if ssCtrl in Shift then
3742 begin
3743 wWidth := DotStep;
3744 wHeight := DotStep;
3745 trigger.Width := wWidth;
3746 trigger.Height := wHeight;
3747 end
3748 else
3749 begin
3750 trigger.Width := Abs(MousePos.X-MouseLDownPos.X);
3751 trigger.Height := Abs(MousePos.Y-MouseLDownPos.Y);
3752 end;
3754 trigger.Enabled := True;
3755 trigger.TriggerType := lbTriggersList.ItemIndex+1;
3756 trigger.TexturePanel := -1;
3758 // Типы активации:
3759 trigger.ActivateType := 0;
3761 if clbActivationType.Checked[0] then
3762 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_PLAYERCOLLIDE;
3763 if clbActivationType.Checked[1] then
3764 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_MONSTERCOLLIDE;
3765 if clbActivationType.Checked[2] then
3766 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_PLAYERPRESS;
3767 if clbActivationType.Checked[3] then
3768 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_MONSTERPRESS;
3769 if clbActivationType.Checked[4] then
3770 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_SHOT;
3771 if clbActivationType.Checked[5] then
3772 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_NOMONSTER;
3774 // Необходимые для активации ключи:
3775 trigger.Key := 0;
3777 if clbKeys.Checked[0] then
3778 trigger.Key := Trigger.Key or KEY_RED;
3779 if clbKeys.Checked[1] then
3780 trigger.Key := Trigger.Key or KEY_GREEN;
3781 if clbKeys.Checked[2] then
3782 trigger.Key := Trigger.Key or KEY_BLUE;
3783 if clbKeys.Checked[3] then
3784 trigger.Key := Trigger.Key or KEY_REDTEAM;
3785 if clbKeys.Checked[4] then
3786 trigger.Key := Trigger.Key or KEY_BLUETEAM;
3788 // Параметры триггера:
3789 FillByte(trigger.Data.Default[0], 128, 0);
3791 case trigger.TriggerType of
3792 // Переключаемая панель:
3793 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
3794 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP,
3795 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
3796 begin
3797 Trigger.Data.PanelID := -1;
3798 end;
3800 // Телепортация:
3801 TRIGGER_TELEPORT:
3802 begin
3803 trigger.Data.TargetPoint.X := trigger.X-64;
3804 trigger.Data.TargetPoint.Y := trigger.Y-64;
3805 trigger.Data.d2d_teleport := True;
3806 trigger.Data.TlpDir := 0;
3807 end;
3809 // Изменение других триггеров:
3810 TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF,
3811 TRIGGER_ONOFF:
3812 begin
3813 trigger.Data.Count := 1;
3814 end;
3816 // Звук:
3817 TRIGGER_SOUND:
3818 begin
3819 trigger.Data.Volume := 255;
3820 trigger.Data.Pan := 127;
3821 trigger.Data.PlayCount := 1;
3822 trigger.Data.Local := True;
3823 trigger.Data.SoundSwitch := False;
3824 end;
3826 // Музыка:
3827 TRIGGER_MUSIC:
3828 begin
3829 trigger.Data.MusicAction := 1;
3830 end;
3832 // Создание монстра:
3833 TRIGGER_SPAWNMONSTER:
3834 begin
3835 trigger.Data.MonType := MONSTER_ZOMBY;
3836 trigger.Data.MonPos.X := trigger.X-64;
3837 trigger.Data.MonPos.Y := trigger.Y-64;
3838 trigger.Data.MonHealth := 0;
3839 trigger.Data.MonActive := False;
3840 trigger.Data.MonCount := 1;
3841 end;
3843 // Создание предмета:
3844 TRIGGER_SPAWNITEM:
3845 begin
3846 trigger.Data.ItemType := ITEM_AMMO_BULLETS;
3847 trigger.Data.ItemPos.X := trigger.X-64;
3848 trigger.Data.ItemPos.Y := trigger.Y-64;
3849 trigger.Data.ItemOnlyDM := False;
3850 trigger.Data.ItemFalls := False;
3851 trigger.Data.ItemCount := 1;
3852 trigger.Data.ItemMax := 0;
3853 trigger.Data.ItemDelay := 0;
3854 end;
3856 // Ускорение:
3857 TRIGGER_PUSH:
3858 begin
3859 trigger.Data.PushAngle := 90;
3860 trigger.Data.PushForce := 10;
3861 trigger.Data.ResetVel := True;
3862 end;
3864 TRIGGER_SCORE:
3865 begin
3866 trigger.Data.ScoreCount := 1;
3867 trigger.Data.ScoreCon := True;
3868 trigger.Data.ScoreMsg := True;
3869 end;
3871 TRIGGER_MESSAGE:
3872 begin
3873 trigger.Data.MessageKind := 0;
3874 trigger.Data.MessageSendTo := 0;
3875 trigger.Data.MessageText := '';
3876 trigger.Data.MessageTime := 144;
3877 end;
3879 TRIGGER_DAMAGE:
3880 begin
3881 trigger.Data.DamageValue := 5;
3882 trigger.Data.DamageInterval := 12;
3883 end;
3885 TRIGGER_HEALTH:
3886 begin
3887 trigger.Data.HealValue := 5;
3888 trigger.Data.HealInterval := 36;
3889 end;
3891 TRIGGER_SHOT:
3892 begin
3893 trigger.Data.ShotType := TRIGGER_SHOT_BULLET;
3894 trigger.Data.ShotSound := True;
3895 trigger.Data.ShotPanelID := -1;
3896 trigger.Data.ShotTarget := 0;
3897 trigger.Data.ShotIntSight := 0;
3898 trigger.Data.ShotAim := TRIGGER_SHOT_AIM_DEFAULT;
3899 trigger.Data.ShotPos.X := trigger.X-64;
3900 trigger.Data.ShotPos.Y := trigger.Y-64;
3901 trigger.Data.ShotAngle := 0;
3902 trigger.Data.ShotWait := 18;
3903 trigger.Data.ShotAccuracy := 0;
3904 trigger.Data.ShotAmmo := 0;
3905 trigger.Data.ShotIntReload := 0;
3906 end;
3908 TRIGGER_EFFECT:
3909 begin
3910 trigger.Data.FXCount := 1;
3911 trigger.Data.FXType := TRIGGER_EFFECT_PARTICLE;
3912 trigger.Data.FXSubType := TRIGGER_EFFECT_SLIQUID;
3913 trigger.Data.FXColorR := 0;
3914 trigger.Data.FXColorG := 0;
3915 trigger.Data.FXColorB := 255;
3916 trigger.Data.FXPos := TRIGGER_EFFECT_POS_CENTER;
3917 trigger.Data.FXWait := 1;
3918 trigger.Data.FXVelX := 0;
3919 trigger.Data.FXVelY := -20;
3920 trigger.Data.FXSpreadL := 5;
3921 trigger.Data.FXSpreadR := 5;
3922 trigger.Data.FXSpreadU := 4;
3923 trigger.Data.FXSpreadD := 0;
3924 end;
3925 end;
3927 Undo_Add(OBJECT_TRIGGER, AddTrigger(trigger));
3928 end;
3930 // Рисовали область триггера "Расширитель":
3931 MOUSEACTION_DRAWPRESS:
3932 with gTriggers[SelectedObjects[GetFirstSelected].ID] do
3933 begin
3934 Data.tX := Min(MousePos.X-MapOffset.X, MouseLDownPos.X-MapOffset.X);
3935 Data.tY := Min(MousePos.Y-MapOffset.Y, MouseLDownPos.Y-MapOffset.Y);
3936 Data.tWidth := Abs(MousePos.X-MouseLDownPos.X);
3937 Data.tHeight := Abs(MousePos.Y-MouseLDownPos.Y);
3939 DrawPressRect := False;
3940 end;
3941 end;
3943 MouseAction := MOUSEACTION_NONE;
3944 end;
3945 end // if Button = mbLeft...
3946 else // Right Mouse Button:
3947 begin
3948 if MouseAction = MOUSEACTION_NOACTION then
3949 begin
3950 MouseAction := MOUSEACTION_NONE;
3951 Exit;
3952 end;
3954 // Объект передвинут или изменен в размере:
3955 if MouseAction in [MOUSEACTION_MOVEOBJ, MOUSEACTION_RESIZE] then
3956 begin
3957 MouseAction := MOUSEACTION_NONE;
3958 FillProperty();
3959 Exit;
3960 end;
3962 // Еще не все выбрали:
3963 if SelectFlag <> SELECTFLAG_NONE then
3964 begin
3965 if SelectFlag = SELECTFLAG_SELECTED then
3966 SelectFlag := SELECTFLAG_NONE;
3967 FillProperty();
3968 Exit;
3969 end;
3971 // Мышь сдвинулась во время удержания клавиши:
3972 if (MousePos.X <> MouseRDownPos.X) and
3973 (MousePos.Y <> MouseRDownPos.Y) then
3974 begin
3975 rSelectRect := True;
3977 rRect.X := Min(MousePos.X, MouseRDownPos.X)-MapOffset.X;
3978 rRect.Y := Min(MousePos.Y, MouseRDownPos.Y)-MapOffset.Y;
3979 rRect.Width := Abs(MousePos.X-MouseRDownPos.X);
3980 rRect.Height := Abs(MousePos.Y-MouseRDownPos.Y);
3981 end
3982 else // Мышь не сдвинулась - нет прямоугольника:
3983 begin
3984 rSelectRect := False;
3986 rRect.X := X-MapOffset.X-1;
3987 rRect.Y := Y-MapOffset.Y-1;
3988 rRect.Width := 2;
3989 rRect.Height := 2;
3990 end;
3992 // Если зажат Ctrl - выделять еще, иначе только один выделенный объект:
3993 if not (ssCtrl in Shift) then
3994 RemoveSelectFromObjects();
3996 // Выделяем всё в выбранном прямоугольнике:
3997 if (ssCtrl in Shift) and (ssAlt in Shift) then
3998 begin
3999 SelectObjects(OBJECT_PANEL);
4000 SelectObjects(OBJECT_ITEM);
4001 SelectObjects(OBJECT_MONSTER);
4002 SelectObjects(OBJECT_AREA);
4003 SelectObjects(OBJECT_TRIGGER);
4004 end
4005 else
4006 SelectObjects(pcObjects.ActivePageIndex+1);
4008 FillProperty();
4009 end;
4010 end;
4012 procedure TMainForm.RenderPanelPaint(Sender: TObject);
4013 begin
4014 Draw();
4015 end;
4017 function TMainForm.RenderMousePos(): Types.TPoint;
4018 begin
4019 Result := RenderPanel.ScreenToClient(Mouse.CursorPos);
4020 end;
4022 procedure TMainForm.RenderPanelMouseMove(Sender: TObject;
4023 Shift: TShiftState; X, Y: Integer);
4024 var
4025 sX, sY: Integer;
4026 dWidth, dHeight: Integer;
4027 _id: Integer;
4028 TextureID: DWORD;
4029 wWidth, wHeight: Word;
4030 begin
4031 _id := GetFirstSelected();
4032 TextureID := 0;
4034 // Рисуем панель с текстурой, сетка - размеры текстуры:
4035 if (MouseAction = MOUSEACTION_DRAWPANEL) and
4036 (lbPanelType.ItemIndex in [0..8]) and
4037 (lbTextureList.ItemIndex <> -1) and
4038 (not IsSpecialTextureSel()) then
4039 begin
4040 sX := StrToIntDef(lTextureWidth.Caption, DotStep);
4041 sY := StrToIntDef(lTextureHeight.Caption, DotStep);
4042 end
4043 else
4044 // Меняем размер панели с текстурой, сетка - размеры текстуры:
4045 if (MouseAction = MOUSEACTION_RESIZE) and
4046 ( (SelectedObjects[_id].ObjectType = OBJECT_PANEL) and
4047 IsTexturedPanel(gPanels[SelectedObjects[_id].ID].PanelType) and
4048 (gPanels[SelectedObjects[_id].ID].TextureName <> '') and
4049 (not IsSpecialTexture(gPanels[SelectedObjects[_id].ID].TextureName)) ) then
4050 begin
4051 sX := gPanels[SelectedObjects[_id].ID].TextureWidth;
4052 sY := gPanels[SelectedObjects[_id].ID].TextureHeight;
4053 end
4054 else
4055 // Выравнивание по сетке:
4056 if SnapToGrid then
4057 begin
4058 sX := DotStep;
4059 sY := DotStep;
4060 end
4061 else // Нет выравнивания по сетке:
4062 begin
4063 sX := 1;
4064 sY := 1;
4065 end;
4067 // Новая позиция мыши:
4068 if MouseLDown then
4069 begin // Зажата левая кнопка мыши
4070 MousePos.X := (Round((X-MouseLDownPos.X)/sX)*sX)+MouseLDownPos.X;
4071 MousePos.Y := (Round((Y-MouseLDownPos.Y)/sY)*sY)+MouseLDownPos.Y;
4072 end
4073 else
4074 if MouseRDown then
4075 begin // Зажата правая кнопка мыши
4076 MousePos.X := (Round((X-MouseRDownPos.X)/sX)*sX)+MouseRDownPos.X;
4077 MousePos.Y := (Round((Y-MouseRDownPos.Y)/sY)*sY)+MouseRDownPos.Y;
4078 end
4079 else
4080 begin // Кнопки мыши не зажаты
4081 MousePos.X := (Round(X/sX)*sX);
4082 MousePos.Y := (Round(Y/sY)*sY);
4083 end;
4085 // Изменение размера закончилось - ставим обычный курсор:
4086 if ResizeType = RESIZETYPE_NONE then
4087 RenderPanel.Cursor := crDefault;
4089 // Зажата только правая кнопка мыши:
4090 if (not MouseLDown) and (MouseRDown) then
4091 begin
4092 // Рисуем прямоугольник выделения:
4093 if MouseAction = MOUSEACTION_NONE then
4094 begin
4095 if DrawRect = nil then
4096 New(DrawRect);
4097 DrawRect.Top := MouseRDownPos.y;
4098 DrawRect.Left := MouseRDownPos.x;
4099 DrawRect.Bottom := MousePos.y;
4100 DrawRect.Right := MousePos.x;
4101 end
4102 else
4103 // Двигаем выделенные объекты:
4104 if MouseAction = MOUSEACTION_MOVEOBJ then
4105 begin
4106 MoveSelectedObjects(ssShift in Shift, ssCtrl in Shift,
4107 MousePos.X-LastMovePoint.X+WASDOffset.X,
4108 MousePos.Y-LastMovePoint.Y+WASDOffset.Y);
4109 WASDOffset.X := 0;
4110 WASDOffset.Y := 0;
4111 end
4112 else
4113 // Меняем размер выделенного объекта:
4114 if MouseAction = MOUSEACTION_RESIZE then
4115 begin
4116 if (SelectedObjectCount = 1) and
4117 (SelectedObjects[GetFirstSelected].Live) then
4118 begin
4119 dWidth := MousePos.X-LastMovePoint.X+WASDOffset.X;
4120 dHeight := MousePos.Y-LastMovePoint.Y+WASDOffset.Y;
4121 WASDOffset.X := 0;
4122 WASDOffset.Y := 0;
4124 case ResizeType of
4125 RESIZETYPE_VERTICAL: dWidth := 0;
4126 RESIZETYPE_HORIZONTAL: dHeight := 0;
4127 end;
4129 case ResizeDirection of
4130 RESIZEDIR_UP: dHeight := -dHeight;
4131 RESIZEDIR_LEFT: dWidth := -dWidth;
4132 end;
4134 ResizeObject(SelectedObjects[GetFirstSelected].ObjectType,
4135 SelectedObjects[GetFirstSelected].ID,
4136 dWidth, dHeight, ResizeDirection);
4138 LastMovePoint := MousePos;
4139 end;
4140 end;
4141 end;
4143 // Зажата только левая кнопка мыши:
4144 if (not MouseRDown) and (MouseLDown) then
4145 begin
4146 // Рисуем прямоугольник планирования панели:
4147 if MouseAction in [MOUSEACTION_DRAWPANEL,
4148 MOUSEACTION_DRAWTRIGGER,
4149 MOUSEACTION_DRAWPRESS] then
4150 begin
4151 if DrawRect = nil then
4152 New(DrawRect);
4153 if ssCtrl in Shift then
4154 begin
4155 wWidth := DotStep;
4156 wHeight := DotStep;
4157 if (lbTextureList.ItemIndex <> -1) and (not IsSpecialTextureSel()) and
4158 (MouseAction = MOUSEACTION_DRAWPANEL) then
4159 begin
4160 if not g_GetTexture(SelectedTexture(), TextureID) then
4161 g_GetTexture('NOTEXTURE', TextureID);
4162 g_GetTextureSizeByID(TextureID, wWidth, wHeight);
4163 end;
4164 DrawRect.Top := MouseLDownPos.y;
4165 DrawRect.Left := MouseLDownPos.x;
4166 DrawRect.Bottom := DrawRect.Top + wHeight;
4167 DrawRect.Right := DrawRect.Left + wWidth;
4168 end
4169 else
4170 begin
4171 DrawRect.Top := MouseLDownPos.y;
4172 DrawRect.Left := MouseLDownPos.x;
4173 DrawRect.Bottom := MousePos.y;
4174 DrawRect.Right := MousePos.x;
4175 end;
4176 end
4177 else // Двигаем карту:
4178 if MouseAction = MOUSEACTION_MOVEMAP then
4179 begin
4180 MoveMap(X, Y);
4181 end;
4182 end;
4184 // Клавиши мыши не зажаты:
4185 if (not MouseRDown) and (not MouseLDown) then
4186 DrawRect := nil;
4188 // Строка состояния - координаты мыши:
4189 StatusBar.Panels[1].Text := Format('(%d:%d)',
4190 [MousePos.X-MapOffset.X, MousePos.Y-MapOffset.Y]);
4191 end;
4193 procedure TMainForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
4194 begin
4195 CanClose := MessageBox(0, PChar(_lc[I_MSG_EXIT_PROMT]),
4196 PChar(_lc[I_MSG_EXIT]),
4197 MB_ICONQUESTION or MB_YESNO or
4198 MB_DEFBUTTON1) = idYes;
4199 end;
4201 procedure TMainForm.aExitExecute(Sender: TObject);
4202 begin
4203 Close();
4204 end;
4206 procedure TMainForm.FormDestroy(Sender: TObject);
4207 var
4208 config: TConfig;
4209 i: Integer;
4210 begin
4211 config := TConfig.CreateFile(EditorDir+'Editor.cfg');
4213 if WindowState <> wsMaximized then
4214 begin
4215 config.WriteInt('Editor', 'XPos', Left);
4216 config.WriteInt('Editor', 'YPos', Top);
4217 config.WriteInt('Editor', 'Width', Width);
4218 config.WriteInt('Editor', 'Height', Height);
4219 end
4220 else
4221 begin
4222 config.WriteInt('Editor', 'XPos', RestoredLeft);
4223 config.WriteInt('Editor', 'YPos', RestoredTop);
4224 config.WriteInt('Editor', 'Width', RestoredWidth);
4225 config.WriteInt('Editor', 'Height', RestoredHeight);
4226 end;
4227 config.WriteBool('Editor', 'Maximize', WindowState = wsMaximized);
4228 config.WriteBool('Editor', 'Minimap', ShowMap);
4229 config.WriteInt('Editor', 'PanelProps', PanelProps.ClientWidth);
4230 config.WriteInt('Editor', 'PanelObjs', PanelObjs.ClientHeight);
4231 config.WriteBool('Editor', 'DotEnable', DotEnable);
4232 config.WriteInt('Editor', 'DotStep', DotStep);
4233 config.WriteStr('Editor', 'LastOpenDir', OpenDialog.InitialDir);
4234 config.WriteStr('Editor', 'LastSaveDir', SaveDialog.InitialDir);
4235 config.WriteBool('Editor', 'EdgeShow', drEdge[3] < 255);
4236 config.WriteInt('Editor', 'EdgeColor', gColorEdge);
4237 config.WriteInt('Editor', 'EdgeAlpha', gAlphaEdge);
4238 config.WriteInt('Editor', 'LineAlpha', gAlphaTriggerLine);
4239 config.WriteInt('Editor', 'TriggerAlpha', gAlphaTriggerArea);
4240 config.WriteInt('Editor', 'MonsterRectAlpha', gAlphaMonsterRect);
4241 config.WriteInt('Editor', 'AreaRectAlpha', gAlphaAreaRect);
4243 for i := 0 to RecentCount-1 do
4244 if i < RecentFiles.Count then
4245 config.WriteStr('RecentFiles', IntToStr(i+1), RecentFiles[i])
4246 else
4247 config.WriteStr('RecentFiles', IntToStr(i+1), '');
4248 RecentFiles.Free();
4250 config.SaveFile(EditorDir+'Editor.cfg');
4251 config.Free();
4253 slInvalidTextures.Free;
4254 end;
4256 procedure TMainForm.FormDropFiles(Sender: TObject;
4257 const FileNames: array of String);
4258 begin
4259 if Length(FileNames) <> 1 then
4260 Exit;
4262 OpenMapFile(FileNames[0]);
4263 end;
4265 procedure TMainForm.RenderPanelResize(Sender: TObject);
4266 begin
4267 if MainForm.Visible then
4268 MainForm.Resize();
4269 end;
4271 procedure TMainForm.Splitter1Moved(Sender: TObject);
4272 begin
4273 FormResize(Sender);
4274 end;
4276 procedure TMainForm.aMapOptionsExecute(Sender: TObject);
4277 var
4278 ResName: String;
4279 begin
4280 MapOptionsForm.ShowModal();
4282 ResName := OpenedMap;
4283 while (Pos(':\', ResName) > 0) do
4284 Delete(ResName, 1, Pos(':\', ResName) + 1);
4286 UpdateCaption(gMapInfo.Name, ExtractFileName(OpenedWAD), ResName);
4287 end;
4289 procedure TMainForm.aAboutExecute(Sender: TObject);
4290 begin
4291 AboutForm.ShowModal();
4292 end;
4294 procedure TMainForm.FormKeyDown(Sender: TObject; var Key: Word;
4295 Shift: TShiftState);
4296 var
4297 dx, dy, i: Integer;
4298 FileName: String;
4299 begin
4300 if (not EditingProperties) then
4301 begin
4302 if Key = Ord('1') then
4303 SwitchLayer(LAYER_BACK);
4304 if Key = Ord('2') then
4305 SwitchLayer(LAYER_WALLS);
4306 if Key = Ord('3') then
4307 SwitchLayer(LAYER_FOREGROUND);
4308 if Key = Ord('4') then
4309 SwitchLayer(LAYER_STEPS);
4310 if Key = Ord('5') then
4311 SwitchLayer(LAYER_WATER);
4312 if Key = Ord('6') then
4313 SwitchLayer(LAYER_ITEMS);
4314 if Key = Ord('7') then
4315 SwitchLayer(LAYER_MONSTERS);
4316 if Key = Ord('8') then
4317 SwitchLayer(LAYER_AREAS);
4318 if Key = Ord('9') then
4319 SwitchLayer(LAYER_TRIGGERS);
4320 if Key = Ord('0') then
4321 tbShowClick(tbShow);
4323 if Key = Ord('V') then
4324 begin // Поворот монстров и областей:
4325 if (SelectedObjects <> nil) then
4326 begin
4327 for i := 0 to High(SelectedObjects) do
4328 if (SelectedObjects[i].Live) then
4329 begin
4330 if (SelectedObjects[i].ObjectType = OBJECT_MONSTER) then
4331 begin
4332 g_ChangeDir(gMonsters[SelectedObjects[i].ID].Direction);
4333 end
4334 else
4335 if (SelectedObjects[i].ObjectType = OBJECT_AREA) then
4336 begin
4337 g_ChangeDir(gAreas[SelectedObjects[i].ID].Direction);
4338 end;
4339 end;
4340 end
4341 else
4342 begin
4343 if pcObjects.ActivePage = tsMonsters then
4344 begin
4345 if rbMonsterLeft.Checked then
4346 rbMonsterRight.Checked := True
4347 else
4348 rbMonsterLeft.Checked := True;
4349 end;
4350 if pcObjects.ActivePage = tsAreas then
4351 begin
4352 if rbAreaLeft.Checked then
4353 rbAreaRight.Checked := True
4354 else
4355 rbAreaLeft.Checked := True;
4356 end;
4357 end;
4358 end;
4360 if not (ssCtrl in Shift) then
4361 begin
4362 // Быстрое превью карты:
4363 if Key = Ord('E') then
4364 begin
4365 if PreviewMode = 0 then
4366 PreviewMode := 2;
4367 end;
4369 // Вертикальный скролл карты:
4370 with sbVertical do
4371 begin
4372 if Key = Ord('W') then
4373 begin
4374 if (MouseLDown or MouseRDown) and (Position >= DotStep) then
4375 begin
4376 Dec(WASDOffset.Y, DotStep);
4377 RenderPanelMouseMove(Sender, Shift, RenderMousePos().X, RenderMousePos().Y);
4378 end;
4379 Position := IfThen(Position > DotStep, Position-DotStep, 0);
4380 MapOffset.Y := -Round(Position/16) * 16;
4381 end;
4383 if Key = Ord('S') then
4384 begin
4385 if (MouseLDown or MouseRDown) and (Position+DotStep <= Max) then
4386 begin
4387 Inc(WASDOffset.Y, DotStep);
4388 RenderPanelMouseMove(Sender, Shift, RenderMousePos().X, RenderMousePos().Y);
4389 end;
4390 Position := IfThen(Position+DotStep < Max, Position+DotStep, Max);
4391 MapOffset.Y := -Round(Position/16) * 16;
4392 end;
4393 end;
4395 // Горизонтальный скролл карты:
4396 with sbHorizontal do
4397 begin
4398 if Key = Ord('A') then
4399 begin
4400 if (MouseLDown or MouseRDown) and (Position >= DotStep) then
4401 begin
4402 Dec(WASDOffset.X, DotStep);
4403 RenderPanelMouseMove(Sender, Shift, RenderMousePos().X, RenderMousePos().Y);
4404 end;
4405 Position := IfThen(Position > DotStep, Position-DotStep, 0);
4406 MapOffset.X := -Round(Position/16) * 16;
4407 end;
4409 if Key = Ord('D') then
4410 begin
4411 if (MouseLDown or MouseRDown) and (Position+DotStep <= Max) then
4412 begin
4413 Inc(WASDOffset.X, DotStep);
4414 RenderPanelMouseMove(Sender, Shift, RenderMousePos().X, RenderMousePos().Y);
4415 end;
4416 Position := IfThen(Position+DotStep < Max, Position+DotStep, Max);
4417 MapOffset.X := -Round(Position/16) * 16;
4418 end;
4419 end;
4420 end
4421 else // ssCtrl in Shift
4422 begin
4423 if ssShift in Shift then
4424 begin
4425 // Вставка по абсолютному смещению:
4426 if Key = Ord('V') then
4427 aPasteObjectExecute(Sender);
4428 end;
4429 RenderPanelMouseMove(Sender, Shift, RenderMousePos().X, RenderMousePos().Y);
4430 end;
4431 end;
4433 // Удалить выделенные объекты:
4434 if (Key = VK_DELETE) and (SelectedObjects <> nil) and
4435 RenderPanel.Focused() then
4436 DeleteSelectedObjects();
4438 // Снять выделение:
4439 if (Key = VK_ESCAPE) and (SelectedObjects <> nil) then
4440 RemoveSelectFromObjects();
4442 // Передвинуть объекты:
4443 if MainForm.ActiveControl = RenderPanel then
4444 begin
4445 dx := 0;
4446 dy := 0;
4448 if Key = VK_NUMPAD4 then
4449 dx := IfThen(ssAlt in Shift, -1, -DotStep);
4450 if Key = VK_NUMPAD6 then
4451 dx := IfThen(ssAlt in Shift, 1, DotStep);
4452 if Key = VK_NUMPAD8 then
4453 dy := IfThen(ssAlt in Shift, -1, -DotStep);
4454 if Key = VK_NUMPAD5 then
4455 dy := IfThen(ssAlt in Shift, 1, DotStep);
4457 if (dx <> 0) or (dy <> 0) then
4458 begin
4459 MoveSelectedObjects(ssShift in Shift, ssCtrl in Shift, dx, dy);
4460 Key := 0;
4461 end;
4462 end;
4464 if ssCtrl in Shift then
4465 begin
4466 // Выбор панели с текстурой для триггера
4467 if Key = Ord('T') then
4468 begin
4469 DrawPressRect := False;
4470 if SelectFlag = SELECTFLAG_TEXTURE then
4471 begin
4472 SelectFlag := SELECTFLAG_NONE;
4473 Exit;
4474 end;
4475 vleObjectProperty.FindRow(_lc[I_PROP_TR_TEXTURE_PANEL], i);
4476 if i > 0 then
4477 SelectFlag := SELECTFLAG_TEXTURE;
4478 end;
4480 if Key = Ord('D') then
4481 begin
4482 SelectFlag := SELECTFLAG_NONE;
4483 if DrawPressRect then
4484 begin
4485 DrawPressRect := False;
4486 Exit;
4487 end;
4488 i := -1;
4490 // Выбор области воздействия, в зависимости от типа триггера
4491 vleObjectProperty.FindRow(_lc[I_PROP_TR_EX_AREA], i);
4492 if i > 0 then
4493 begin
4494 DrawPressRect := True;
4495 Exit;
4496 end;
4497 vleObjectProperty.FindRow(_lc[I_PROP_TR_DOOR_PANEL], i);
4498 if i <= 0 then
4499 vleObjectProperty.FindRow(_lc[I_PROP_TR_TRAP_PANEL], i);
4500 if i > 0 then
4501 begin
4502 SelectFlag := SELECTFLAG_DOOR;
4503 Exit;
4504 end;
4505 vleObjectProperty.FindRow(_lc[I_PROP_TR_LIFT_PANEL], i);
4506 if i > 0 then
4507 begin
4508 SelectFlag := SELECTFLAG_LIFT;
4509 Exit;
4510 end;
4511 vleObjectProperty.FindRow(_lc[I_PROP_TR_TELEPORT_TO], i);
4512 if i > 0 then
4513 begin
4514 SelectFlag := SELECTFLAG_TELEPORT;
4515 Exit;
4516 end;
4517 vleObjectProperty.FindRow(_lc[I_PROP_TR_SPAWN_TO], i);
4518 if i > 0 then
4519 begin
4520 SelectFlag := SELECTFLAG_SPAWNPOINT;
4521 Exit;
4522 end;
4524 // Выбор основного параметра, в зависимости от типа триггера
4525 vleObjectProperty.FindRow(_lc[I_PROP_TR_NEXT_MAP], i);
4526 if i > 0 then
4527 begin
4528 g_ProcessResourceStr(OpenedMap, @FileName, nil, nil);
4529 SelectMapForm.Caption := _lc[I_CAP_SELECT];
4530 SelectMapForm.GetMaps(FileName);
4532 if SelectMapForm.ShowModal() = mrOK then
4533 begin
4534 vleObjectProperty.Cells[1, i] := SelectMapForm.lbMapList.Items[SelectMapForm.lbMapList.ItemIndex];
4535 bApplyProperty.Click();
4536 end;
4537 Exit;
4538 end;
4539 vleObjectProperty.FindRow(_lc[I_PROP_TR_SOUND_NAME], i);
4540 if i <= 0 then
4541 vleObjectProperty.FindRow(_lc[I_PROP_TR_MUSIC_NAME], i);
4542 if i > 0 then
4543 begin
4544 AddSoundForm.OKFunction := nil;
4545 AddSoundForm.lbResourcesList.MultiSelect := False;
4546 AddSoundForm.SetResource := vleObjectProperty.Cells[1, i];
4548 if (AddSoundForm.ShowModal() = mrOk) then
4549 begin
4550 vleObjectProperty.Cells[1, i] := AddSoundForm.ResourceName;
4551 bApplyProperty.Click();
4552 end;
4553 Exit;
4554 end;
4555 vleObjectProperty.FindRow(_lc[I_PROP_TR_PUSH_ANGLE], i);
4556 if i <= 0 then
4557 vleObjectProperty.FindRow(_lc[I_PROP_TR_MESSAGE_TEXT], i);
4558 if i > 0 then
4559 begin
4560 vleObjectProperty.Row := i;
4561 vleObjectProperty.SetFocus();
4562 Exit;
4563 end;
4564 end;
4565 end;
4566 end;
4568 procedure TMainForm.aOptimizeExecute(Sender: TObject);
4569 begin
4570 RemoveSelectFromObjects();
4571 MapOptimizationForm.ShowModal();
4572 end;
4574 procedure TMainForm.aCheckMapExecute(Sender: TObject);
4575 begin
4576 MapCheckForm.ShowModal();
4577 end;
4579 procedure TMainForm.bbAddTextureClick(Sender: TObject);
4580 begin
4581 AddTextureForm.lbResourcesList.MultiSelect := True;
4582 AddTextureForm.ShowModal();
4583 end;
4585 procedure TMainForm.lbTextureListClick(Sender: TObject);
4586 var
4587 TextureID: DWORD;
4588 TextureWidth, TextureHeight: Word;
4589 begin
4590 TextureID := 0;
4591 TextureWidth := 0;
4592 TextureHeight := 0;
4593 if (lbTextureList.ItemIndex <> -1) and
4594 (not IsSpecialTextureSel()) then
4595 begin
4596 if g_GetTexture(SelectedTexture(), TextureID) then
4597 begin
4598 g_GetTextureSizeByID(TextureID, TextureWidth, TextureHeight);
4600 lTextureWidth.Caption := IntToStr(TextureWidth);
4601 lTextureHeight.Caption := IntToStr(TextureHeight);
4602 end else
4603 begin
4604 lTextureWidth.Caption := _lc[I_NOT_ACCESSIBLE];
4605 lTextureHeight.Caption := _lc[I_NOT_ACCESSIBLE];
4606 end;
4607 end
4608 else
4609 begin
4610 lTextureWidth.Caption := '';
4611 lTextureHeight.Caption := '';
4612 end;
4613 end;
4615 procedure TMainForm.lbTextureListDrawItem(Control: TWinControl; Index: Integer;
4616 ARect: TRect; State: TOwnerDrawState);
4617 begin
4618 with Control as TListBox do
4619 begin
4620 if LCLType.odSelected in State then
4621 begin
4622 Canvas.Brush.Color := clHighlight;
4623 Canvas.Font.Color := clHighlightText;
4624 end else
4625 if (Items <> nil) and (Index >= 0) then
4626 if slInvalidTextures.IndexOf(Items[Index]) > -1 then
4627 begin
4628 Canvas.Brush.Color := clRed;
4629 Canvas.Font.Color := clWhite;
4630 end;
4631 Canvas.FillRect(ARect);
4632 Canvas.TextRect(ARect, ARect.Left, ARect.Top, Items[Index]);
4633 end;
4634 end;
4636 procedure TMainForm.miReopenMapClick(Sender: TObject);
4637 var
4638 FileName, Resource: String;
4639 begin
4640 if OpenedMap = '' then
4641 Exit;
4643 if MessageBox(0, PChar(_lc[I_MSG_REOPEN_MAP_PROMT]),
4644 PChar(_lc[I_MENU_FILE_REOPEN]), MB_ICONQUESTION or MB_YESNO) <> idYes then
4645 Exit;
4647 g_ProcessResourceStr(OpenedMap, @FileName, nil, @Resource);
4648 OpenMap(FileName, Resource);
4649 end;
4651 procedure TMainForm.vleObjectPropertyGetPickList(Sender: TObject;
4652 const KeyName: String; Values: TStrings);
4653 begin
4654 if vleObjectProperty.ItemProps[KeyName].EditStyle = esPickList then
4655 begin
4656 if KeyName = _lc[I_PROP_DIRECTION] then
4657 begin
4658 Values.Add(DirNames[D_LEFT]);
4659 Values.Add(DirNames[D_RIGHT]);
4660 end
4661 else if KeyName = _lc[I_PROP_TR_TELEPORT_DIR] then
4662 begin
4663 Values.Add(DirNamesAdv[0]);
4664 Values.Add(DirNamesAdv[1]);
4665 Values.Add(DirNamesAdv[2]);
4666 Values.Add(DirNamesAdv[3]);
4667 end
4668 else if KeyName = _lc[I_PROP_TR_MUSIC_ACT] then
4669 begin
4670 Values.Add(_lc[I_PROP_TR_MUSIC_ON]);
4671 Values.Add(_lc[I_PROP_TR_MUSIC_OFF]);
4672 end
4673 else if KeyName = _lc[I_PROP_TR_MONSTER_BEHAVIOUR] then
4674 begin
4675 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_0]);
4676 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_1]);
4677 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_2]);
4678 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_3]);
4679 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_4]);
4680 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_5]);
4681 end
4682 else if KeyName = _lc[I_PROP_TR_SCORE_ACT] then
4683 begin
4684 Values.Add(_lc[I_PROP_TR_SCORE_ACT_0]);
4685 Values.Add(_lc[I_PROP_TR_SCORE_ACT_1]);
4686 Values.Add(_lc[I_PROP_TR_SCORE_ACT_2]);
4687 Values.Add(_lc[I_PROP_TR_SCORE_ACT_3]);
4688 end
4689 else if KeyName = _lc[I_PROP_TR_SCORE_TEAM] then
4690 begin
4691 Values.Add(_lc[I_PROP_TR_SCORE_TEAM_0]);
4692 Values.Add(_lc[I_PROP_TR_SCORE_TEAM_1]);
4693 Values.Add(_lc[I_PROP_TR_SCORE_TEAM_2]);
4694 Values.Add(_lc[I_PROP_TR_SCORE_TEAM_3]);
4695 end
4696 else if KeyName = _lc[I_PROP_TR_MESSAGE_KIND] then
4697 begin
4698 Values.Add(_lc[I_PROP_TR_MESSAGE_KIND_0]);
4699 Values.Add(_lc[I_PROP_TR_MESSAGE_KIND_1]);
4700 end
4701 else if KeyName = _lc[I_PROP_TR_MESSAGE_TO] then
4702 begin
4703 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_0]);
4704 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_1]);
4705 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_2]);
4706 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_3]);
4707 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_4]);
4708 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_5]);
4709 end
4710 else if KeyName = _lc[I_PROP_TR_SHOT_TO] then
4711 begin
4712 Values.Add(_lc[I_PROP_TR_SHOT_TO_0]);
4713 Values.Add(_lc[I_PROP_TR_SHOT_TO_1]);
4714 Values.Add(_lc[I_PROP_TR_SHOT_TO_2]);
4715 Values.Add(_lc[I_PROP_TR_SHOT_TO_3]);
4716 Values.Add(_lc[I_PROP_TR_SHOT_TO_4]);
4717 Values.Add(_lc[I_PROP_TR_SHOT_TO_5]);
4718 Values.Add(_lc[I_PROP_TR_SHOT_TO_6]);
4719 end
4720 else if KeyName = _lc[I_PROP_TR_SHOT_AIM] then
4721 begin
4722 Values.Add(_lc[I_PROP_TR_SHOT_AIM_0]);
4723 Values.Add(_lc[I_PROP_TR_SHOT_AIM_1]);
4724 Values.Add(_lc[I_PROP_TR_SHOT_AIM_2]);
4725 Values.Add(_lc[I_PROP_TR_SHOT_AIM_3]);
4726 end
4727 else if (KeyName = _lc[I_PROP_PANEL_BLEND]) or
4728 (KeyName = _lc[I_PROP_DM_ONLY]) or
4729 (KeyName = _lc[I_PROP_ITEM_FALLS]) or
4730 (KeyName = _lc[I_PROP_TR_ENABLED]) or
4731 (KeyName = _lc[I_PROP_TR_D2D]) or
4732 (KeyName = _lc[I_PROP_TR_SILENT]) or
4733 (KeyName = _lc[I_PROP_TR_TELEPORT_SILENT]) or
4734 (KeyName = _lc[I_PROP_TR_EX_RANDOM]) or
4735 (KeyName = _lc[I_PROP_TR_TEXTURE_ONCE]) or
4736 (KeyName = _lc[I_PROP_TR_TEXTURE_ANIM_ONCE]) or
4737 (KeyName = _lc[I_PROP_TR_SOUND_LOCAL]) or
4738 (KeyName = _lc[I_PROP_TR_SOUND_SWITCH]) or
4739 (KeyName = _lc[I_PROP_TR_MONSTER_ACTIVE]) or
4740 (KeyName = _lc[I_PROP_TR_PUSH_RESET]) or
4741 (KeyName = _lc[I_PROP_TR_SCORE_CON]) or
4742 (KeyName = _lc[I_PROP_TR_SCORE_MSG]) or
4743 (KeyName = _lc[I_PROP_TR_HEALTH_MAX]) or
4744 (KeyName = _lc[I_PROP_TR_SHOT_SOUND]) or
4745 (KeyName = _lc[I_PROP_TR_EFFECT_CENTER]) then
4746 begin
4747 Values.Add(BoolNames[True]);
4748 Values.Add(BoolNames[False]);
4749 end;
4750 end;
4751 end;
4753 procedure TMainForm.bApplyPropertyClick(Sender: TObject);
4754 var
4755 _id, a, r, c: Integer;
4756 s: String;
4757 res: Boolean;
4758 NoTextureID: DWORD;
4759 NW, NH: Word;
4760 begin
4761 NoTextureID := 0;
4762 NW := 0;
4763 NH := 0;
4765 if SelectedObjectCount() <> 1 then
4766 Exit;
4767 if not SelectedObjects[GetFirstSelected()].Live then
4768 Exit;
4770 try
4771 if not CheckProperty() then
4772 Exit;
4773 except
4774 Exit;
4775 end;
4777 _id := GetFirstSelected();
4779 r := vleObjectProperty.Row;
4780 c := vleObjectProperty.Col;
4782 case SelectedObjects[_id].ObjectType of
4783 OBJECT_PANEL:
4784 begin
4785 with gPanels[SelectedObjects[_id].ID] do
4786 begin
4787 X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
4788 Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
4789 Width := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_WIDTH]]));
4790 Height := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_HEIGHT]]));
4792 PanelType := GetPanelType(vleObjectProperty.Values[_lc[I_PROP_PANEL_TYPE]]);
4794 // Сброс ссылки на триггеры смены текстуры:
4795 if not WordBool(PanelType and (PANEL_WALL or PANEL_FORE or PANEL_BACK)) then
4796 if gTriggers <> nil then
4797 for a := 0 to High(gTriggers) do
4798 begin
4799 if (gTriggers[a].TriggerType <> 0) and
4800 (gTriggers[a].TexturePanel = Integer(SelectedObjects[_id].ID)) then
4801 gTriggers[a].TexturePanel := -1;
4802 if (gTriggers[a].TriggerType = TRIGGER_SHOT) and
4803 (gTriggers[a].Data.ShotPanelID = Integer(SelectedObjects[_id].ID)) then
4804 gTriggers[a].Data.ShotPanelID := -1;
4805 end;
4807 // Сброс ссылки на триггеры лифта:
4808 if not WordBool(PanelType and (PANEL_LIFTUP or PANEL_LIFTDOWN or PANEL_LIFTLEFT or PANEL_LIFTRIGHT)) then
4809 if gTriggers <> nil then
4810 for a := 0 to High(gTriggers) do
4811 if (gTriggers[a].TriggerType in [TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT]) and
4812 (gTriggers[a].Data.PanelID = Integer(SelectedObjects[_id].ID)) then
4813 gTriggers[a].Data.PanelID := -1;
4815 // Сброс ссылки на триггеры двери:
4816 if not WordBool(PanelType and (PANEL_OPENDOOR or PANEL_CLOSEDOOR)) then
4817 if gTriggers <> nil then
4818 for a := 0 to High(gTriggers) do
4819 if (gTriggers[a].TriggerType in [TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
4820 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP]) and
4821 (gTriggers[a].Data.PanelID = Integer(SelectedObjects[_id].ID)) then
4822 gTriggers[a].Data.PanelID := -1;
4824 if IsTexturedPanel(PanelType) then
4825 begin // Может быть текстура
4826 if TextureName <> '' then
4827 begin // Была текстура
4828 Alpha := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_PANEL_ALPHA]]));
4829 Blending := NameToBool(vleObjectProperty.Values[_lc[I_PROP_PANEL_BLEND]]);
4830 end
4831 else // Не было
4832 begin
4833 Alpha := 0;
4834 Blending := False;
4835 end;
4837 // Новая текстура:
4838 TextureName := vleObjectProperty.Values[_lc[I_PROP_PANEL_TEX]];
4840 if TextureName <> '' then
4841 begin // Есть текстура
4842 // Обычная текстура:
4843 if not IsSpecialTexture(TextureName) then
4844 begin
4845 g_GetTextureSizeByName(TextureName,
4846 TextureWidth, TextureHeight);
4848 // Проверка кратности размеров панели:
4849 res := True;
4850 if TextureWidth <> 0 then
4851 if gPanels[SelectedObjects[_id].ID].Width mod TextureWidth <> 0 then
4852 begin
4853 ErrorMessageBox(Format(_lc[I_MSG_WRONG_TEXWIDTH],
4854 [TextureWidth]));
4855 Res := False;
4856 end;
4857 if Res and (TextureHeight <> 0) then
4858 if gPanels[SelectedObjects[_id].ID].Height mod TextureHeight <> 0 then
4859 begin
4860 ErrorMessageBox(Format(_lc[I_MSG_WRONG_TEXHEIGHT],
4861 [TextureHeight]));
4862 Res := False;
4863 end;
4865 if Res then
4866 begin
4867 if not g_GetTexture(TextureName, TextureID) then
4868 // Не удалось загрузить текстуру, рисуем NOTEXTURE
4869 if g_GetTexture('NOTEXTURE', NoTextureID) then
4870 begin
4871 TextureID := TEXTURE_SPECIAL_NOTEXTURE;
4872 g_GetTextureSizeByID(NoTextureID, NW, NH);
4873 TextureWidth := NW;
4874 TextureHeight := NH;
4875 end else
4876 begin
4877 TextureID := TEXTURE_SPECIAL_NONE;
4878 TextureWidth := 1;
4879 TextureHeight := 1;
4880 end;
4881 end
4882 else
4883 begin
4884 TextureName := '';
4885 TextureWidth := 1;
4886 TextureHeight := 1;
4887 TextureID := TEXTURE_SPECIAL_NONE;
4888 end;
4889 end
4890 else // Спец.текстура
4891 begin
4892 TextureHeight := 1;
4893 TextureWidth := 1;
4894 TextureID := SpecialTextureID(TextureName);
4895 end;
4896 end
4897 else // Нет текстуры
4898 begin
4899 TextureWidth := 1;
4900 TextureHeight := 1;
4901 TextureID := TEXTURE_SPECIAL_NONE;
4902 end;
4903 end
4904 else // Не может быть текстуры
4905 begin
4906 Alpha := 0;
4907 Blending := False;
4908 TextureName := '';
4909 TextureWidth := 1;
4910 TextureHeight := 1;
4911 TextureID := TEXTURE_SPECIAL_NONE;
4912 end;
4913 end;
4914 end;
4916 OBJECT_ITEM:
4917 begin
4918 with gItems[SelectedObjects[_id].ID] do
4919 begin
4920 X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
4921 Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
4922 OnlyDM := NameToBool(vleObjectProperty.Values[_lc[I_PROP_DM_ONLY]]);
4923 Fall := NameToBool(vleObjectProperty.Values[_lc[I_PROP_ITEM_FALLS]]);
4924 end;
4925 end;
4927 OBJECT_MONSTER:
4928 begin
4929 with gMonsters[SelectedObjects[_id].ID] do
4930 begin
4931 X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
4932 Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
4933 Direction := NameToDir(vleObjectProperty.Values[_lc[I_PROP_DIRECTION]]);
4934 end;
4935 end;
4937 OBJECT_AREA:
4938 begin
4939 with gAreas[SelectedObjects[_id].ID] do
4940 begin
4941 X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
4942 Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
4943 Direction := NameToDir(vleObjectProperty.Values[_lc[I_PROP_DIRECTION]]);
4944 end;
4945 end;
4947 OBJECT_TRIGGER:
4948 begin
4949 with gTriggers[SelectedObjects[_id].ID] do
4950 begin
4951 X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
4952 Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
4953 Width := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_WIDTH]]));
4954 Height := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_HEIGHT]]));
4955 Enabled := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_ENABLED]]);
4956 ActivateType := StrToActivate(vleObjectProperty.Values[_lc[I_PROP_TR_ACTIVATION]]);
4957 Key := StrToKey(vleObjectProperty.Values[_lc[I_PROP_TR_KEYS]]);
4959 case TriggerType of
4960 TRIGGER_EXIT:
4961 begin
4962 s := utf2win(vleObjectProperty.Values[_lc[I_PROP_TR_NEXT_MAP]]);
4963 FillByte(Data.MapName[0], 16, 0);
4964 if s <> '' then
4965 Move(s[1], Data.MapName[0], Min(Length(s), 16));
4966 end;
4968 TRIGGER_TEXTURE:
4969 begin
4970 Data.ActivateOnce := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_TEXTURE_ONCE]]);
4971 Data.AnimOnce := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_TEXTURE_ANIM_ONCE]]);
4972 end;
4974 TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF:
4975 begin
4976 Data.Wait := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EX_DELAY]], 0), 65535);
4977 Data.Count := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EX_COUNT]], 0), 65535);
4978 if Data.Count < 1 then
4979 Data.Count := 1;
4980 if TriggerType = TRIGGER_PRESS then
4981 Data.ExtRandom := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_EX_RANDOM]]);
4982 end;
4984 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR, TRIGGER_DOOR5,
4985 TRIGGER_CLOSETRAP, TRIGGER_TRAP, TRIGGER_LIFTUP, TRIGGER_LIFTDOWN,
4986 TRIGGER_LIFT:
4987 begin
4988 Data.NoSound := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SILENT]]);
4989 Data.d2d_doors := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_D2D]]);
4990 end;
4992 TRIGGER_TELEPORT:
4993 begin
4994 Data.d2d_teleport := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_D2D]]);
4995 Data.silent_teleport := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_TELEPORT_SILENT]]);
4996 Data.TlpDir := NameToDirAdv(vleObjectProperty.Values[_lc[I_PROP_TR_TELEPORT_DIR]]);
4997 end;
4999 TRIGGER_SOUND:
5000 begin
5001 s := utf2win(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_NAME]]);
5002 FillByte(Data.SoundName[0], 64, 0);
5003 if s <> '' then
5004 Move(s[1], Data.SoundName[0], Min(Length(s), 64));
5006 Data.Volume := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_VOLUME]], 0), 255);
5007 Data.Pan := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_PAN]], 0), 255);
5008 Data.PlayCount := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_COUNT]], 0), 255);
5009 Data.Local := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_LOCAL]]);
5010 Data.SoundSwitch := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_SWITCH]]);
5011 end;
5013 TRIGGER_SPAWNMONSTER:
5014 begin
5015 Data.MonType := StrToMonster(vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_TYPE]]);
5016 Data.MonDir := Byte(NameToDir(vleObjectProperty.Values[_lc[I_PROP_DIRECTION]]));
5017 Data.MonHealth := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_HEALTH]], 0), 1000000);
5018 if Data.MonHealth < 0 then
5019 Data.MonHealth := 0;
5020 Data.MonActive := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_ACTIVE]]);
5021 Data.MonCount := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_COUNT]], 0), 64);
5022 if Data.MonCount < 1 then
5023 Data.MonCount := 1;
5024 Data.MonEffect := StrToEffect(vleObjectProperty.Values[_lc[I_PROP_TR_FX_TYPE]]);
5025 Data.MonMax := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SPAWN_MAX]], 0), 65535);
5026 Data.MonDelay := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SPAWN_DELAY]], 0), 65535);
5027 Data.MonBehav := 0;
5028 if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_1] then
5029 Data.MonBehav := 1;
5030 if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_2] then
5031 Data.MonBehav := 2;
5032 if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_3] then
5033 Data.MonBehav := 3;
5034 if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_4] then
5035 Data.MonBehav := 4;
5036 if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_5] then
5037 Data.MonBehav := 5;
5038 end;
5040 TRIGGER_SPAWNITEM:
5041 begin
5042 Data.ItemType := StrToItem(vleObjectProperty.Values[_lc[I_PROP_TR_ITEM_TYPE]]);
5043 Data.ItemOnlyDM := NameToBool(vleObjectProperty.Values[_lc[I_PROP_DM_ONLY]]);
5044 Data.ItemFalls := NameToBool(vleObjectProperty.Values[_lc[I_PROP_ITEM_FALLS]]);
5045 Data.ItemCount := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_COUNT]], 0), 64);
5046 if Data.ItemCount < 1 then
5047 Data.ItemCount := 1;
5048 Data.ItemEffect := StrToEffect(vleObjectProperty.Values[_lc[I_PROP_TR_FX_TYPE]]);
5049 Data.ItemMax := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SPAWN_MAX]], 0), 65535);
5050 Data.ItemDelay := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SPAWN_DELAY]], 0), 65535);
5051 end;
5053 TRIGGER_MUSIC:
5054 begin
5055 s := utf2win(vleObjectProperty.Values[_lc[I_PROP_TR_MUSIC_NAME]]);
5056 FillByte(Data.MusicName[0], 64, 0);
5057 if s <> '' then
5058 Move(s[1], Data.MusicName[0], Min(Length(s), 64));
5060 if vleObjectProperty.Values[_lc[I_PROP_TR_MUSIC_ACT]] = _lc[I_PROP_TR_MUSIC_ON] then
5061 Data.MusicAction := 1
5062 else
5063 Data.MusicAction := 2;
5064 end;
5066 TRIGGER_PUSH:
5067 begin
5068 Data.PushAngle := Min(
5069 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_PUSH_ANGLE]], 0), 360);
5070 Data.PushForce := Min(
5071 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_PUSH_FORCE]], 0), 255);
5072 Data.ResetVel := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_PUSH_RESET]]);
5073 end;
5075 TRIGGER_SCORE:
5076 begin
5077 Data.ScoreAction := 0;
5078 if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_ACT]] = _lc[I_PROP_TR_SCORE_ACT_1] then
5079 Data.ScoreAction := 1
5080 else if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_ACT]] = _lc[I_PROP_TR_SCORE_ACT_2] then
5081 Data.ScoreAction := 2
5082 else if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_ACT]] = _lc[I_PROP_TR_SCORE_ACT_3] then
5083 Data.ScoreAction := 3;
5084 Data.ScoreCount := Min(Max(
5085 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_COUNT]], 0), 0), 255);
5086 Data.ScoreTeam := 0;
5087 if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_TEAM]] = _lc[I_PROP_TR_SCORE_TEAM_1] then
5088 Data.ScoreTeam := 1
5089 else if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_TEAM]] = _lc[I_PROP_TR_SCORE_TEAM_2] then
5090 Data.ScoreTeam := 2
5091 else if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_TEAM]] = _lc[I_PROP_TR_SCORE_TEAM_3] then
5092 Data.ScoreTeam := 3;
5093 Data.ScoreCon := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_CON]]);
5094 Data.ScoreMsg := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_MSG]]);
5095 end;
5097 TRIGGER_MESSAGE:
5098 begin
5099 Data.MessageKind := 0;
5100 if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_KIND]] = _lc[I_PROP_TR_MESSAGE_KIND_1] then
5101 Data.MessageKind := 1;
5103 Data.MessageSendTo := 0;
5104 if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_1] then
5105 Data.MessageSendTo := 1
5106 else if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_2] then
5107 Data.MessageSendTo := 2
5108 else if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_3] then
5109 Data.MessageSendTo := 3
5110 else if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_4] then
5111 Data.MessageSendTo := 4
5112 else if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_5] then
5113 Data.MessageSendTo := 5;
5115 s := utf2win(vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TEXT]]);
5116 FillByte(Data.MessageText[0], 100, 0);
5117 if s <> '' then
5118 Move(s[1], Data.MessageText[0], Min(Length(s), 100));
5120 Data.MessageTime := Min(Max(
5121 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TIME]], 0), 0), 65535);
5122 end;
5124 TRIGGER_DAMAGE:
5125 begin
5126 Data.DamageValue := Min(Max(
5127 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_DAMAGE_VALUE]], 0), 0), 65535);
5128 Data.DamageInterval := Min(Max(
5129 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_INTERVAL]], 0), 0), 65535);
5130 end;
5132 TRIGGER_HEALTH:
5133 begin
5134 Data.HealValue := Min(Max(
5135 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_HEALTH]], 0), 0), 65535);
5136 Data.HealInterval := Min(Max(
5137 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_INTERVAL]], 0), 0), 65535);
5138 Data.HealMax := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_HEALTH_MAX]]);
5139 Data.HealSilent := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SILENT]]);
5140 end;
5142 TRIGGER_SHOT:
5143 begin
5144 Data.ShotType := StrToShot(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TYPE]]);
5145 Data.ShotSound := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_SOUND]]);
5146 Data.ShotTarget := 0;
5147 if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_1] then
5148 Data.ShotTarget := 1
5149 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_2] then
5150 Data.ShotTarget := 2
5151 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_3] then
5152 Data.ShotTarget := 3
5153 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_4] then
5154 Data.ShotTarget := 4
5155 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_5] then
5156 Data.ShotTarget := 5
5157 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_6] then
5158 Data.ShotTarget := 6;
5159 Data.ShotIntSight := Min(Max(
5160 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_SIGHT]], 0), 0), 65535);
5161 Data.ShotAim := 0;
5162 if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_AIM]] = _lc[I_PROP_TR_SHOT_AIM_1] then
5163 Data.ShotAim := 1
5164 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_AIM]] = _lc[I_PROP_TR_SHOT_AIM_2] then
5165 Data.ShotAim := 2
5166 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_AIM]] = _lc[I_PROP_TR_SHOT_AIM_3] then
5167 Data.ShotAim := 3;
5168 Data.ShotAngle := Min(
5169 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_ANGLE]], 0), 360);
5170 Data.ShotWait := Min(Max(
5171 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EX_DELAY]], 0), 0), 65535);
5172 Data.ShotAccuracy := Min(Max(
5173 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_ACC]], 0), 0), 65535);
5174 Data.ShotAmmo := Min(Max(
5175 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_AMMO]], 0), 0), 65535);
5176 Data.ShotIntReload := Min(Max(
5177 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_RELOAD]], 0), 0), 65535);
5178 end;
5180 TRIGGER_EFFECT:
5181 begin
5182 Data.FXCount := Min(Max(
5183 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_COUNT]], 0), 0), 255);
5184 if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_TYPE]] = _lc[I_PROP_TR_EFFECT_PARTICLE] then
5185 begin
5186 Data.FXType := TRIGGER_EFFECT_PARTICLE;
5187 Data.FXSubType := TRIGGER_EFFECT_SLIQUID;
5188 if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_SLIQUID] then
5189 Data.FXSubType := TRIGGER_EFFECT_SLIQUID
5190 else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_LLIQUID] then
5191 Data.FXSubType := TRIGGER_EFFECT_LLIQUID
5192 else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_DLIQUID] then
5193 Data.FXSubType := TRIGGER_EFFECT_DLIQUID
5194 else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_BLOOD] then
5195 Data.FXSubType := TRIGGER_EFFECT_BLOOD
5196 else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_SPARK] then
5197 Data.FXSubType := TRIGGER_EFFECT_SPARK
5198 else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_BUBBLE] then
5199 Data.FXSubType := TRIGGER_EFFECT_BUBBLE;
5200 end else
5201 begin
5202 Data.FXType := TRIGGER_EFFECT_ANIMATION;
5203 Data.FXSubType := StrToEffect(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]]);
5204 end;
5205 a := Min(Max(
5206 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_COLOR]], 0), 0), $FFFFFF);
5207 Data.FXColorR := a and $FF;
5208 Data.FXColorG := (a shr 8) and $FF;
5209 Data.FXColorB := (a shr 16) and $FF;
5210 if NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_CENTER]]) then
5211 Data.FXPos := 0
5212 else
5213 Data.FXPos := 1;
5214 Data.FXWait := Min(Max(
5215 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EX_DELAY]], 0), 0), 65535);
5216 Data.FXVelX := Min(Max(
5217 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_VELX]], 0), -128), 127);
5218 Data.FXVelY := Min(Max(
5219 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_VELY]], 0), -128), 127);
5220 Data.FXSpreadL := Min(Max(
5221 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SPL]], 0), 0), 255);
5222 Data.FXSpreadR := Min(Max(
5223 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SPR]], 0), 0), 255);
5224 Data.FXSpreadU := Min(Max(
5225 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SPU]], 0), 0), 255);
5226 Data.FXSpreadD := Min(Max(
5227 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SPD]], 0), 0), 255);
5228 end;
5229 end;
5230 end;
5231 end;
5232 end;
5234 FillProperty();
5236 vleObjectProperty.Row := r;
5237 vleObjectProperty.Col := c;
5238 end;
5240 procedure TMainForm.bbRemoveTextureClick(Sender: TObject);
5241 var
5242 a, i: Integer;
5243 begin
5244 i := lbTextureList.ItemIndex;
5245 if i = -1 then
5246 Exit;
5248 if MessageBox(0, PChar(Format(_lc[I_MSG_DEL_TEXTURE_PROMT],
5249 [SelectedTexture()])),
5250 PChar(_lc[I_MSG_DEL_TEXTURE]),
5251 MB_ICONQUESTION or MB_YESNO or
5252 MB_DEFBUTTON1) <> idYes then
5253 Exit;
5255 if gPanels <> nil then
5256 for a := 0 to High(gPanels) do
5257 if (gPanels[a].PanelType <> 0) and
5258 (gPanels[a].TextureName = SelectedTexture()) then
5259 begin
5260 ErrorMessageBox(_lc[I_MSG_DEL_TEXTURE_CANT]);
5261 Exit;
5262 end;
5264 g_DeleteTexture(SelectedTexture());
5265 i := slInvalidTextures.IndexOf(lbTextureList.Items[i]);
5266 if i > -1 then
5267 slInvalidTextures.Delete(i);
5268 if lbTextureList.ItemIndex > -1 then
5269 lbTextureList.Items.Delete(lbTextureList.ItemIndex)
5270 end;
5272 procedure TMainForm.aNewMapExecute(Sender: TObject);
5273 begin
5274 if (MessageBox(0, PChar(_lc[I_MSG_CLEAR_MAP_PROMT]),
5275 PChar(_lc[I_MSG_CLEAR_MAP]),
5276 MB_ICONQUESTION or MB_YESNO or
5277 MB_DEFBUTTON1) = mrYes) then
5278 FullClear();
5279 end;
5281 procedure TMainForm.aUndoExecute(Sender: TObject);
5282 var
5283 a: Integer;
5284 begin
5285 if UndoBuffer = nil then
5286 Exit;
5287 if UndoBuffer[High(UndoBuffer)] = nil then
5288 Exit;
5290 for a := 0 to High(UndoBuffer[High(UndoBuffer)]) do
5291 with UndoBuffer[High(UndoBuffer)][a] do
5292 begin
5293 case UndoType of
5294 UNDO_DELETE_PANEL:
5295 begin
5296 AddPanel(Panel^);
5297 Panel := nil;
5298 end;
5299 UNDO_DELETE_ITEM: AddItem(Item);
5300 UNDO_DELETE_AREA: AddArea(Area);
5301 UNDO_DELETE_MONSTER: AddMonster(Monster);
5302 UNDO_DELETE_TRIGGER: AddTrigger(Trigger);
5303 UNDO_ADD_PANEL: RemoveObject(AddID, OBJECT_PANEL);
5304 UNDO_ADD_ITEM: RemoveObject(AddID, OBJECT_ITEM);
5305 UNDO_ADD_AREA: RemoveObject(AddID, OBJECT_AREA);
5306 UNDO_ADD_MONSTER: RemoveObject(AddID, OBJECT_MONSTER);
5307 UNDO_ADD_TRIGGER: RemoveObject(AddID, OBJECT_TRIGGER);
5308 end;
5309 end;
5311 SetLength(UndoBuffer, Length(UndoBuffer)-1);
5313 RemoveSelectFromObjects();
5315 miUndo.Enabled := UndoBuffer <> nil;
5316 end;
5319 procedure TMainForm.aCopyObjectExecute(Sender: TObject);
5320 var
5321 a, b: Integer;
5322 CopyBuffer: TCopyRecArray;
5323 str: String;
5324 ok: Boolean;
5326 function CB_Compare(I1, I2: TCopyRec): Integer;
5327 begin
5328 Result := Integer(I1.ObjectType) - Integer(I2.ObjectType);
5330 if Result = 0 then // Одного типа
5331 Result := Integer(I1.ID) - Integer(I2.ID);
5332 end;
5334 procedure QuickSortCopyBuffer(L, R: Integer);
5335 var
5336 I, J: Integer;
5337 P, T: TCopyRec;
5338 begin
5339 repeat
5340 I := L;
5341 J := R;
5342 P := CopyBuffer[(L + R) shr 1];
5344 repeat
5345 while CB_Compare(CopyBuffer[I], P) < 0 do
5346 Inc(I);
5347 while CB_Compare(CopyBuffer[J], P) > 0 do
5348 Dec(J);
5350 if I <= J then
5351 begin
5352 T := CopyBuffer[I];
5353 CopyBuffer[I] := CopyBuffer[J];
5354 CopyBuffer[J] := T;
5355 Inc(I);
5356 Dec(J);
5357 end;
5358 until I > J;
5360 if L < J then
5361 QuickSortCopyBuffer(L, J);
5363 L := I;
5364 until I >= R;
5365 end;
5367 begin
5368 if SelectedObjects = nil then
5369 Exit;
5371 b := -1;
5372 CopyBuffer := nil;
5374 // Копируем объекты:
5375 for a := 0 to High(SelectedObjects) do
5376 if SelectedObjects[a].Live then
5377 with SelectedObjects[a] do
5378 begin
5379 SetLength(CopyBuffer, Length(CopyBuffer)+1);
5380 b := High(CopyBuffer);
5381 CopyBuffer[b].ID := ID;
5382 CopyBuffer[b].Panel := nil;
5384 case ObjectType of
5385 OBJECT_PANEL:
5386 begin
5387 CopyBuffer[b].ObjectType := OBJECT_PANEL;
5388 New(CopyBuffer[b].Panel);
5389 CopyBuffer[b].Panel^ := gPanels[ID];
5390 end;
5392 OBJECT_ITEM:
5393 begin
5394 CopyBuffer[b].ObjectType := OBJECT_ITEM;
5395 CopyBuffer[b].Item := gItems[ID];
5396 end;
5398 OBJECT_MONSTER:
5399 begin
5400 CopyBuffer[b].ObjectType := OBJECT_MONSTER;
5401 CopyBuffer[b].Monster := gMonsters[ID];
5402 end;
5404 OBJECT_AREA:
5405 begin
5406 CopyBuffer[b].ObjectType := OBJECT_AREA;
5407 CopyBuffer[b].Area := gAreas[ID];
5408 end;
5410 OBJECT_TRIGGER:
5411 begin
5412 CopyBuffer[b].ObjectType := OBJECT_TRIGGER;
5413 CopyBuffer[b].Trigger := gTriggers[ID];
5414 end;
5415 end;
5416 end;
5418 // Сортировка по ID:
5419 if CopyBuffer <> nil then
5420 begin
5421 QuickSortCopyBuffer(0, b);
5422 end;
5424 // Пестановка ссылок триггеров:
5425 for a := 0 to Length(CopyBuffer)-1 do
5426 if CopyBuffer[a].ObjectType = OBJECT_TRIGGER then
5427 begin
5428 case CopyBuffer[a].Trigger.TriggerType of
5429 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
5430 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP,
5431 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
5432 if CopyBuffer[a].Trigger.Data.PanelID <> -1 then
5433 begin
5434 ok := False;
5436 for b := 0 to Length(CopyBuffer)-1 do
5437 if (CopyBuffer[b].ObjectType = OBJECT_PANEL) and
5438 (Integer(CopyBuffer[b].ID) = CopyBuffer[a].Trigger.Data.PanelID) then
5439 begin
5440 CopyBuffer[a].Trigger.Data.PanelID := b;
5441 ok := True;
5442 Break;
5443 end;
5445 // Этих панелей нет среди копируемых:
5446 if not ok then
5447 CopyBuffer[a].Trigger.Data.PanelID := -1;
5448 end;
5450 TRIGGER_PRESS, TRIGGER_ON,
5451 TRIGGER_OFF, TRIGGER_ONOFF:
5452 if CopyBuffer[a].Trigger.Data.MonsterID <> 0 then
5453 begin
5454 ok := False;
5456 for b := 0 to Length(CopyBuffer)-1 do
5457 if (CopyBuffer[b].ObjectType = OBJECT_MONSTER) and
5458 (Integer(CopyBuffer[b].ID) = CopyBuffer[a].Trigger.Data.MonsterID-1) then
5459 begin
5460 CopyBuffer[a].Trigger.Data.MonsterID := b+1;
5461 ok := True;
5462 Break;
5463 end;
5465 // Этих монстров нет среди копируемых:
5466 if not ok then
5467 CopyBuffer[a].Trigger.Data.MonsterID := 0;
5468 end;
5470 TRIGGER_SHOT:
5471 if CopyBuffer[a].Trigger.Data.ShotPanelID <> -1 then
5472 begin
5473 ok := False;
5475 for b := 0 to Length(CopyBuffer)-1 do
5476 if (CopyBuffer[b].ObjectType = OBJECT_PANEL) and
5477 (Integer(CopyBuffer[b].ID) = CopyBuffer[a].Trigger.Data.ShotPanelID) then
5478 begin
5479 CopyBuffer[a].Trigger.Data.ShotPanelID := b;
5480 ok := True;
5481 Break;
5482 end;
5484 // Этих панелей нет среди копируемых:
5485 if not ok then
5486 CopyBuffer[a].Trigger.Data.ShotPanelID := -1;
5487 end;
5488 end;
5490 if CopyBuffer[a].Trigger.TexturePanel <> -1 then
5491 begin
5492 ok := False;
5494 for b := 0 to Length(CopyBuffer)-1 do
5495 if (CopyBuffer[b].ObjectType = OBJECT_PANEL) and
5496 (Integer(CopyBuffer[b].ID) = CopyBuffer[a].Trigger.TexturePanel) then
5497 begin
5498 CopyBuffer[a].Trigger.TexturePanel := b;
5499 ok := True;
5500 Break;
5501 end;
5503 // Этих панелей нет среди копируемых:
5504 if not ok then
5505 CopyBuffer[a].Trigger.TexturePanel := -1;
5506 end;
5507 end;
5509 // В буфер обмена:
5510 str := CopyBufferToString(CopyBuffer);
5511 ClipBoard.AsText := str;
5513 for a := 0 to Length(CopyBuffer)-1 do
5514 if (CopyBuffer[a].ObjectType = OBJECT_PANEL) and
5515 (CopyBuffer[a].Panel <> nil) then
5516 Dispose(CopyBuffer[a].Panel);
5518 CopyBuffer := nil;
5519 end;
5521 procedure TMainForm.aPasteObjectExecute(Sender: TObject);
5522 var
5523 a, h: Integer;
5524 CopyBuffer: TCopyRecArray;
5525 res, rel: Boolean;
5526 swad, ssec, sres: String;
5527 NoTextureID: DWORD;
5528 pmin: TPoint;
5529 begin
5530 CopyBuffer := nil;
5531 NoTextureID := 0;
5532 pmin.X := High(pmin.X);
5533 pmin.Y := High(pmin.Y);
5535 StringToCopyBuffer(ClipBoard.AsText, CopyBuffer, pmin);
5536 rel := not(ssShift in GetKeyShiftState());
5538 if CopyBuffer = nil then
5539 Exit;
5541 RemoveSelectFromObjects();
5543 h := High(CopyBuffer);
5544 for a := 0 to h do
5545 with CopyBuffer[a] do
5546 begin
5547 case ObjectType of
5548 OBJECT_PANEL:
5549 if Panel <> nil then
5550 begin
5551 if rel then
5552 begin
5553 Panel^.X := Panel^.X - pmin.X - MapOffset.X + 32;
5554 Panel^.Y := Panel^.Y - pmin.Y - MapOffset.Y + 32;
5555 end;
5557 Panel^.TextureID := TEXTURE_SPECIAL_NONE;
5558 Panel^.TextureWidth := 1;
5559 Panel^.TextureHeight := 1;
5561 if (Panel^.PanelType = PANEL_LIFTUP) or
5562 (Panel^.PanelType = PANEL_LIFTDOWN) or
5563 (Panel^.PanelType = PANEL_LIFTLEFT) or
5564 (Panel^.PanelType = PANEL_LIFTRIGHT) or
5565 (Panel^.PanelType = PANEL_BLOCKMON) or
5566 (Panel^.TextureName = '') then
5567 begin // Нет или не может быть текстуры:
5568 end
5569 else // Есть текстура:
5570 begin
5571 // Обычная текстура:
5572 if not IsSpecialTexture(Panel^.TextureName) then
5573 begin
5574 res := g_GetTexture(Panel^.TextureName, Panel^.TextureID);
5576 if not res then
5577 begin
5578 g_ProcessResourceStr(Panel^.TextureName, swad, ssec, sres);
5579 AddTexture(swad, ssec, sres, True);
5580 res := g_GetTexture(Panel^.TextureName, Panel^.TextureID);
5581 end;
5583 if res then
5584 g_GetTextureSizeByName(Panel^.TextureName,
5585 Panel^.TextureWidth, Panel^.TextureHeight)
5586 else
5587 if g_GetTexture('NOTEXTURE', NoTextureID) then
5588 begin
5589 Panel^.TextureID := TEXTURE_SPECIAL_NOTEXTURE;
5590 g_GetTextureSizeByID(NoTextureID, Panel^.TextureWidth, Panel^.TextureHeight);
5591 end;
5592 end
5593 else // Спец.текстура:
5594 begin
5595 Panel^.TextureID := SpecialTextureID(Panel^.TextureName);
5596 with MainForm.lbTextureList.Items do
5597 if IndexOf(Panel^.TextureName) = -1 then
5598 Add(Panel^.TextureName);
5599 end;
5600 end;
5602 ID := AddPanel(Panel^);
5603 Dispose(Panel);
5604 Undo_Add(OBJECT_PANEL, ID, a > 0);
5605 SelectObject(OBJECT_PANEL, ID, True);
5606 end;
5608 OBJECT_ITEM:
5609 begin
5610 if rel then
5611 begin
5612 Item.X := Item.X - pmin.X - MapOffset.X + 32;
5613 Item.Y := Item.Y - pmin.Y - MapOffset.Y + 32;
5614 end;
5616 ID := AddItem(Item);
5617 Undo_Add(OBJECT_ITEM, ID, a > 0);
5618 SelectObject(OBJECT_ITEM, ID, True);
5619 end;
5621 OBJECT_MONSTER:
5622 begin
5623 if rel then
5624 begin
5625 Monster.X := Monster.X - pmin.X - MapOffset.X + 32;
5626 Monster.Y := Monster.Y - pmin.Y - MapOffset.Y + 32;
5627 end;
5629 ID := AddMonster(Monster);
5630 Undo_Add(OBJECT_MONSTER, ID, a > 0);
5631 SelectObject(OBJECT_MONSTER, ID, True);
5632 end;
5634 OBJECT_AREA:
5635 begin
5636 if rel then
5637 begin
5638 Area.X := Area.X - pmin.X - MapOffset.X + 32;
5639 Area.Y := Area.Y - pmin.Y - MapOffset.Y + 32;
5640 end;
5642 ID := AddArea(Area);
5643 Undo_Add(OBJECT_AREA, ID, a > 0);
5644 SelectObject(OBJECT_AREA, ID, True);
5645 end;
5647 OBJECT_TRIGGER:
5648 begin
5649 if rel then
5650 with Trigger do
5651 begin
5652 X := X - pmin.X - MapOffset.X + 32;
5653 Y := Y - pmin.Y - MapOffset.Y + 32;
5655 case TriggerType of
5656 TRIGGER_TELEPORT:
5657 begin
5658 Data.TargetPoint.X :=
5659 Data.TargetPoint.X - pmin.X - MapOffset.X + 32;
5660 Data.TargetPoint.Y :=
5661 Data.TargetPoint.Y - pmin.Y - MapOffset.Y + 32;
5662 end;
5663 TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF:
5664 begin
5665 Data.tX := Data.tX - pmin.X - MapOffset.X + 32;
5666 Data.tY := Data.tY - pmin.Y - MapOffset.Y + 32;
5667 end;
5668 TRIGGER_SPAWNMONSTER:
5669 begin
5670 Data.MonPos.X :=
5671 Data.MonPos.X - pmin.X - MapOffset.X + 32;
5672 Data.MonPos.Y :=
5673 Data.MonPos.Y - pmin.Y - MapOffset.Y + 32;
5674 end;
5675 TRIGGER_SPAWNITEM:
5676 begin
5677 Data.ItemPos.X :=
5678 Data.ItemPos.X - pmin.X - MapOffset.X + 32;
5679 Data.ItemPos.Y :=
5680 Data.ItemPos.Y - pmin.Y - MapOffset.Y + 32;
5681 end;
5682 TRIGGER_SHOT:
5683 begin
5684 Data.ShotPos.X :=
5685 Data.ShotPos.X - pmin.X - MapOffset.X + 32;
5686 Data.ShotPos.Y :=
5687 Data.ShotPos.Y - pmin.Y - MapOffset.Y + 32;
5688 end;
5689 end;
5690 end;
5692 ID := AddTrigger(Trigger);
5693 Undo_Add(OBJECT_TRIGGER, ID, a > 0);
5694 SelectObject(OBJECT_TRIGGER, ID, True);
5695 end;
5696 end;
5697 end;
5699 // Переставляем ссылки триггеров:
5700 for a := 0 to High(CopyBuffer) do
5701 if CopyBuffer[a].ObjectType = OBJECT_TRIGGER then
5702 begin
5703 case CopyBuffer[a].Trigger.TriggerType of
5704 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
5705 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP,
5706 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
5707 if CopyBuffer[a].Trigger.Data.PanelID <> -1 then
5708 gTriggers[CopyBuffer[a].ID].Data.PanelID :=
5709 CopyBuffer[CopyBuffer[a].Trigger.Data.PanelID].ID;
5711 TRIGGER_PRESS, TRIGGER_ON,
5712 TRIGGER_OFF, TRIGGER_ONOFF:
5713 if CopyBuffer[a].Trigger.Data.MonsterID <> 0 then
5714 gTriggers[CopyBuffer[a].ID].Data.MonsterID :=
5715 CopyBuffer[CopyBuffer[a].Trigger.Data.MonsterID-1].ID+1;
5717 TRIGGER_SHOT:
5718 if CopyBuffer[a].Trigger.Data.ShotPanelID <> -1 then
5719 gTriggers[CopyBuffer[a].ID].Data.ShotPanelID :=
5720 CopyBuffer[CopyBuffer[a].Trigger.Data.ShotPanelID].ID;
5721 end;
5723 if CopyBuffer[a].Trigger.TexturePanel <> -1 then
5724 gTriggers[CopyBuffer[a].ID].TexturePanel :=
5725 CopyBuffer[CopyBuffer[a].Trigger.TexturePanel].ID;
5726 end;
5728 CopyBuffer := nil;
5730 if h = 0 then
5731 FillProperty();
5732 end;
5734 procedure TMainForm.aCutObjectExecute(Sender: TObject);
5735 begin
5736 miCopy.Click();
5737 DeleteSelectedObjects();
5738 end;
5740 procedure TMainForm.vleObjectPropertyEditButtonClick(Sender: TObject);
5741 var
5742 Key, FileName: String;
5743 b: Byte;
5744 begin
5745 Key := vleObjectProperty.Keys[vleObjectProperty.Row];
5747 if Key = _lc[I_PROP_PANEL_TYPE] then
5748 begin
5749 with ChooseTypeForm, vleObjectProperty do
5750 begin // Выбор типа панели:
5751 Caption := _lc[I_PROP_PANEL_TYPE];
5752 lbTypeSelect.Items.Clear();
5754 for b := 0 to High(PANELNAMES) do
5755 begin
5756 lbTypeSelect.Items.Add(PANELNAMES[b]);
5757 if Values[Key] = PANELNAMES[b] then
5758 lbTypeSelect.ItemIndex := b;
5759 end;
5761 if ShowModal() = mrOK then
5762 begin
5763 b := lbTypeSelect.ItemIndex;
5764 Values[Key] := PANELNAMES[b];
5765 vleObjectPropertyApply(Sender);
5766 end;
5767 end
5768 end
5769 else if Key = _lc[I_PROP_TR_TELEPORT_TO] then
5770 SelectFlag := SELECTFLAG_TELEPORT
5771 else if Key = _lc[I_PROP_TR_SPAWN_TO] then
5772 SelectFlag := SELECTFLAG_SPAWNPOINT
5773 else if (Key = _lc[I_PROP_TR_DOOR_PANEL]) or
5774 (Key = _lc[I_PROP_TR_TRAP_PANEL]) then
5775 SelectFlag := SELECTFLAG_DOOR
5776 else if Key = _lc[I_PROP_TR_TEXTURE_PANEL] then
5777 begin
5778 DrawPressRect := False;
5779 SelectFlag := SELECTFLAG_TEXTURE;
5780 end
5781 else if Key = _lc[I_PROP_TR_SHOT_PANEL] then
5782 SelectFlag := SELECTFLAG_SHOTPANEL
5783 else if Key = _lc[I_PROP_TR_LIFT_PANEL] then
5784 SelectFlag := SELECTFLAG_LIFT
5785 else if key = _lc[I_PROP_TR_EX_MONSTER] then
5786 SelectFlag := SELECTFLAG_MONSTER
5787 else if Key = _lc[I_PROP_TR_EX_AREA] then
5788 begin
5789 SelectFlag := SELECTFLAG_NONE;
5790 DrawPressRect := True;
5791 end
5792 else if Key = _lc[I_PROP_TR_NEXT_MAP] then
5793 begin // Выбор следующей карты:
5794 g_ProcessResourceStr(OpenedMap, @FileName, nil, nil);
5795 SelectMapForm.Caption := _lc[I_CAP_SELECT];
5796 SelectMapForm.GetMaps(FileName);
5798 if SelectMapForm.ShowModal() = mrOK then
5799 begin
5800 vleObjectProperty.Values[Key] := SelectMapForm.lbMapList.Items[SelectMapForm.lbMapList.ItemIndex];
5801 vleObjectPropertyApply(Sender);
5802 end;
5803 end
5804 else if (Key = _lc[I_PROP_TR_SOUND_NAME]) or
5805 (Key = _lc[I_PROP_TR_MUSIC_NAME]) then
5806 begin // Выбор файла звука/музыки:
5807 AddSoundForm.OKFunction := nil;
5808 AddSoundForm.lbResourcesList.MultiSelect := False;
5809 AddSoundForm.SetResource := vleObjectProperty.Values[Key];
5811 if (AddSoundForm.ShowModal() = mrOk) then
5812 begin
5813 vleObjectProperty.Values[Key] := AddSoundForm.ResourceName;
5814 vleObjectPropertyApply(Sender);
5815 end;
5816 end
5817 else if Key = _lc[I_PROP_TR_ACTIVATION] then
5818 with ActivationTypeForm, vleObjectProperty do
5819 begin // Выбор типов активации:
5820 cbPlayerCollide.Checked := Pos('PC', Values[Key]) > 0;
5821 cbMonsterCollide.Checked := Pos('MC', Values[Key]) > 0;
5822 cbPlayerPress.Checked := Pos('PP', Values[Key]) > 0;
5823 cbMonsterPress.Checked := Pos('MP', Values[Key]) > 0;
5824 cbShot.Checked := Pos('SH', Values[Key]) > 0;
5825 cbNoMonster.Checked := Pos('NM', Values[Key]) > 0;
5827 if ShowModal() = mrOK then
5828 begin
5829 b := 0;
5830 if cbPlayerCollide.Checked then
5831 b := ACTIVATE_PLAYERCOLLIDE;
5832 if cbMonsterCollide.Checked then
5833 b := b or ACTIVATE_MONSTERCOLLIDE;
5834 if cbPlayerPress.Checked then
5835 b := b or ACTIVATE_PLAYERPRESS;
5836 if cbMonsterPress.Checked then
5837 b := b or ACTIVATE_MONSTERPRESS;
5838 if cbShot.Checked then
5839 b := b or ACTIVATE_SHOT;
5840 if cbNoMonster.Checked then
5841 b := b or ACTIVATE_NOMONSTER;
5843 Values[Key] := ActivateToStr(b);
5844 vleObjectPropertyApply(Sender);
5845 end;
5846 end
5847 else if Key = _lc[I_PROP_TR_KEYS] then
5848 with KeysForm, vleObjectProperty do
5849 begin // Выбор необходимых ключей:
5850 cbRedKey.Checked := Pos('RK', Values[Key]) > 0;
5851 cbGreenKey.Checked := Pos('GK', Values[Key]) > 0;
5852 cbBlueKey.Checked := Pos('BK', Values[Key]) > 0;
5853 cbRedTeam.Checked := Pos('RT', Values[Key]) > 0;
5854 cbBlueTeam.Checked := Pos('BT', Values[Key]) > 0;
5856 if ShowModal() = mrOK then
5857 begin
5858 b := 0;
5859 if cbRedKey.Checked then
5860 b := KEY_RED;
5861 if cbGreenKey.Checked then
5862 b := b or KEY_GREEN;
5863 if cbBlueKey.Checked then
5864 b := b or KEY_BLUE;
5865 if cbRedTeam.Checked then
5866 b := b or KEY_REDTEAM;
5867 if cbBlueTeam.Checked then
5868 b := b or KEY_BLUETEAM;
5870 Values[Key] := KeyToStr(b);
5871 vleObjectPropertyApply(Sender);
5872 end;
5873 end
5874 else if Key = _lc[I_PROP_TR_FX_TYPE] then
5875 with ChooseTypeForm, vleObjectProperty do
5876 begin // Выбор типа эффекта:
5877 Caption := _lc[I_CAP_FX_TYPE];
5878 lbTypeSelect.Items.Clear();
5880 for b := EFFECT_NONE to EFFECT_FIRE do
5881 lbTypeSelect.Items.Add(EffectToStr(b));
5883 lbTypeSelect.ItemIndex := StrToEffect(Values[Key]);
5885 if ShowModal() = mrOK then
5886 begin
5887 b := lbTypeSelect.ItemIndex;
5888 Values[Key] := EffectToStr(b);
5889 vleObjectPropertyApply(Sender);
5890 end;
5891 end
5892 else if Key = _lc[I_PROP_TR_MONSTER_TYPE] then
5893 with ChooseTypeForm, vleObjectProperty do
5894 begin // Выбор типа монстра:
5895 Caption := _lc[I_CAP_MONSTER_TYPE];
5896 lbTypeSelect.Items.Clear();
5898 for b := MONSTER_DEMON to MONSTER_MAN do
5899 lbTypeSelect.Items.Add(MonsterToStr(b));
5901 lbTypeSelect.ItemIndex := StrToMonster(Values[Key]) - MONSTER_DEMON;
5903 if ShowModal() = mrOK then
5904 begin
5905 b := lbTypeSelect.ItemIndex + MONSTER_DEMON;
5906 Values[Key] := MonsterToStr(b);
5907 vleObjectPropertyApply(Sender);
5908 end;
5909 end
5910 else if Key = _lc[I_PROP_TR_ITEM_TYPE] then
5911 with ChooseTypeForm, vleObjectProperty do
5912 begin // Выбор типа предмета:
5913 Caption := _lc[I_CAP_ITEM_TYPE];
5914 lbTypeSelect.Items.Clear();
5916 for b := ITEM_MEDKIT_SMALL to ITEM_KEY_BLUE do
5917 lbTypeSelect.Items.Add(ItemToStr(b));
5918 lbTypeSelect.Items.Add(ItemToStr(ITEM_BOTTLE));
5919 lbTypeSelect.Items.Add(ItemToStr(ITEM_HELMET));
5920 lbTypeSelect.Items.Add(ItemToStr(ITEM_JETPACK));
5921 lbTypeSelect.Items.Add(ItemToStr(ITEM_INVIS));
5922 lbTypeSelect.Items.Add(ItemToStr(ITEM_WEAPON_FLAMETHROWER));
5923 lbTypeSelect.Items.Add(ItemToStr(ITEM_AMMO_FUELCAN));
5925 b := StrToItem(Values[Key]);
5926 if b >= ITEM_BOTTLE then
5927 b := b - 2;
5928 lbTypeSelect.ItemIndex := b - ITEM_MEDKIT_SMALL;
5930 if ShowModal() = mrOK then
5931 begin
5932 b := lbTypeSelect.ItemIndex + ITEM_MEDKIT_SMALL;
5933 if b >= ITEM_WEAPON_KASTET then
5934 b := b + 2;
5935 Values[Key] := ItemToStr(b);
5936 vleObjectPropertyApply(Sender);
5937 end;
5938 end
5939 else if Key = _lc[I_PROP_TR_SHOT_TYPE] then
5940 with ChooseTypeForm, vleObjectProperty do
5941 begin // Выбор типа предмета:
5942 Caption := _lc[I_PROP_TR_SHOT_TYPE];
5943 lbTypeSelect.Items.Clear();
5945 for b := TRIGGER_SHOT_PISTOL to TRIGGER_SHOT_MAX do
5946 lbTypeSelect.Items.Add(ShotToStr(b));
5948 lbTypeSelect.ItemIndex := StrToShot(Values[Key]);
5950 if ShowModal() = mrOK then
5951 begin
5952 b := lbTypeSelect.ItemIndex;
5953 Values[Key] := ShotToStr(b);
5954 vleObjectPropertyApply(Sender);
5955 end;
5956 end
5957 else if Key = _lc[I_PROP_TR_EFFECT_TYPE] then
5958 with ChooseTypeForm, vleObjectProperty do
5959 begin // Выбор типа эффекта:
5960 Caption := _lc[I_CAP_FX_TYPE];
5961 lbTypeSelect.Items.Clear();
5963 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_PARTICLE]);
5964 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_ANIMATION]);
5965 if Values[Key] = _lc[I_PROP_TR_EFFECT_ANIMATION] then
5966 lbTypeSelect.ItemIndex := 1
5967 else
5968 lbTypeSelect.ItemIndex := 0;
5970 if ShowModal() = mrOK then
5971 begin
5972 b := lbTypeSelect.ItemIndex;
5973 if b = 0 then
5974 Values[Key] := _lc[I_PROP_TR_EFFECT_PARTICLE]
5975 else
5976 Values[Key] := _lc[I_PROP_TR_EFFECT_ANIMATION];
5977 vleObjectPropertyApply(Sender);
5978 end;
5979 end
5980 else if Key = _lc[I_PROP_TR_EFFECT_SUBTYPE] then
5981 with ChooseTypeForm, vleObjectProperty do
5982 begin // Выбор подтипа эффекта:
5983 Caption := _lc[I_CAP_FX_TYPE];
5984 lbTypeSelect.Items.Clear();
5986 if Values[_lc[I_PROP_TR_EFFECT_TYPE]] = _lc[I_PROP_TR_EFFECT_ANIMATION] then
5987 begin
5988 for b := EFFECT_TELEPORT to EFFECT_FIRE do
5989 lbTypeSelect.Items.Add(EffectToStr(b));
5991 lbTypeSelect.ItemIndex := StrToEffect(Values[Key]) - 1;
5992 end else
5993 begin
5994 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_SLIQUID]);
5995 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_LLIQUID]);
5996 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_DLIQUID]);
5997 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_BLOOD]);
5998 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_SPARK]);
5999 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_BUBBLE]);
6000 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_SLIQUID;
6001 if Values[Key] = _lc[I_PROP_TR_EFFECT_LLIQUID] then
6002 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_LLIQUID;
6003 if Values[Key] = _lc[I_PROP_TR_EFFECT_DLIQUID] then
6004 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_DLIQUID;
6005 if Values[Key] = _lc[I_PROP_TR_EFFECT_BLOOD] then
6006 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_BLOOD;
6007 if Values[Key] = _lc[I_PROP_TR_EFFECT_SPARK] then
6008 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_SPARK;
6009 if Values[Key] = _lc[I_PROP_TR_EFFECT_BUBBLE] then
6010 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_BUBBLE;
6011 end;
6013 if ShowModal() = mrOK then
6014 begin
6015 b := lbTypeSelect.ItemIndex;
6017 if Values[_lc[I_PROP_TR_EFFECT_TYPE]] = _lc[I_PROP_TR_EFFECT_ANIMATION] then
6018 Values[Key] := EffectToStr(b + 1)
6019 else begin
6020 Values[Key] := _lc[I_PROP_TR_EFFECT_SLIQUID];
6021 if b = TRIGGER_EFFECT_LLIQUID then
6022 Values[Key] := _lc[I_PROP_TR_EFFECT_LLIQUID];
6023 if b = TRIGGER_EFFECT_DLIQUID then
6024 Values[Key] := _lc[I_PROP_TR_EFFECT_DLIQUID];
6025 if b = TRIGGER_EFFECT_BLOOD then
6026 Values[Key] := _lc[I_PROP_TR_EFFECT_BLOOD];
6027 if b = TRIGGER_EFFECT_SPARK then
6028 Values[Key] := _lc[I_PROP_TR_EFFECT_SPARK];
6029 if b = TRIGGER_EFFECT_BUBBLE then
6030 Values[Key] := _lc[I_PROP_TR_EFFECT_BUBBLE];
6031 end;
6033 vleObjectPropertyApply(Sender);
6034 end;
6035 end
6036 else if Key = _lc[I_PROP_TR_EFFECT_COLOR] then
6037 with vleObjectProperty do
6038 begin // Выбор цвета эффекта:
6039 ColorDialog.Color := StrToIntDef(Values[Key], 0);
6040 if ColorDialog.Execute then
6041 begin
6042 Values[Key] := IntToStr(ColorDialog.Color);
6043 vleObjectPropertyApply(Sender);
6044 end;
6045 end
6046 else if Key = _lc[I_PROP_PANEL_TEX] then
6047 begin // Смена текстуры:
6048 vleObjectProperty.Values[Key] := SelectedTexture();
6049 vleObjectPropertyApply(Sender);
6050 end;
6051 end;
6053 procedure TMainForm.vleObjectPropertyApply(Sender: TObject);
6054 begin
6055 // hack to prevent empty ID in list
6056 RenderPanel.SetFocus();
6057 bApplyProperty.Click();
6058 vleObjectProperty.SetFocus();
6059 end;
6061 procedure TMainForm.aSaveMapExecute(Sender: TObject);
6062 var
6063 FileName, Section, Res: String;
6064 begin
6065 if OpenedMap = '' then
6066 begin
6067 aSaveMapAsExecute(nil);
6068 Exit;
6069 end;
6071 g_ProcessResourceStr(OpenedMap, FileName, Section, Res);
6073 SaveMap(FileName+':\'+Res);
6074 end;
6076 procedure TMainForm.aOpenMapExecute(Sender: TObject);
6077 begin
6078 OpenDialog.Filter := _lc[I_FILE_FILTER_ALL];
6080 if OpenDialog.Execute() then
6081 begin
6082 OpenMapFile(OpenDialog.FileName);
6083 OpenDialog.InitialDir := ExtractFileDir(OpenDialog.FileName);
6084 end;
6085 end;
6087 procedure TMainForm.OpenMapFile(FileName: String);
6088 begin
6089 if (Pos('.ini', LowerCase(ExtractFileName(FileName))) > 0) then
6090 begin // INI карты:
6091 FullClear();
6093 pLoadProgress.Left := (RenderPanel.Width div 2)-(pLoadProgress.Width div 2);
6094 pLoadProgress.Top := (RenderPanel.Height div 2)-(pLoadProgress.Height div 2);
6095 pLoadProgress.Show();
6097 OpenedMap := '';
6098 OpenedWAD := '';
6100 LoadMapOld(FileName);
6102 MainForm.Caption := Format('%s - %s', [FormCaption, ExtractFileName(FileName)]);
6104 pLoadProgress.Hide();
6105 MainForm.FormResize(Self);
6106 end
6107 else // Карты из WAD:
6108 begin
6109 OpenMap(FileName, '');
6110 end;
6111 end;
6113 procedure TMainForm.FormActivate(Sender: TObject);
6114 var
6115 lang: Integer;
6116 config: TConfig;
6117 begin
6118 MainForm.ActiveControl := RenderPanel;
6120 // Язык:
6121 if gLanguage = '' then
6122 begin
6123 lang := SelectLanguageForm.ShowModal();
6124 case lang of
6125 1: gLanguage := LANGUAGE_ENGLISH;
6126 else gLanguage := LANGUAGE_RUSSIAN;
6127 end;
6129 config := TConfig.CreateFile(EditorDir+'Editor.cfg');
6130 config.WriteStr('Editor', 'Language', gLanguage);
6131 config.SaveFile(EditorDir+'Editor.cfg');
6132 config.Free();
6133 end;
6135 //e_WriteLog('Read language file', MSG_NOTIFY);
6136 //g_Language_Load(EditorDir+'\data\'+gLanguage+LANGUAGE_FILE_NAME);
6137 g_Language_Set(gLanguage);
6138 end;
6140 procedure TMainForm.aDeleteMap(Sender: TObject);
6141 var
6142 WAD: TWADEditor_1;
6143 MapList: SArray;
6144 MapName: Char16;
6145 a: Integer;
6146 str: String;
6147 begin
6148 OpenDialog.Filter := _lc[I_FILE_FILTER_WAD];
6150 if not OpenDialog.Execute() then
6151 Exit;
6153 WAD := TWADEditor_1.Create();
6155 if not WAD.ReadFile(OpenDialog.FileName) then
6156 begin
6157 WAD.Free();
6158 Exit;
6159 end;
6161 WAD.CreateImage();
6163 MapList := WAD.GetResourcesList('');
6165 SelectMapForm.Caption := _lc[I_CAP_REMOVE];
6166 SelectMapForm.lbMapList.Items.Clear();
6168 if MapList <> nil then
6169 for a := 0 to High(MapList) do
6170 SelectMapForm.lbMapList.Items.Add(win2utf(MapList[a]));
6172 if (SelectMapForm.ShowModal() = mrOK) then
6173 begin
6174 str := SelectMapForm.lbMapList.Items[SelectMapForm.lbMapList.ItemIndex];
6175 MapName := '';
6176 Move(str[1], MapName[0], Min(16, Length(str)));
6178 if MessageBox(0, PChar(Format(_lc[I_MSG_DELETE_MAP_PROMT],
6179 [MapName, OpenDialog.FileName])),
6180 PChar(_lc[I_MSG_DELETE_MAP]),
6181 MB_ICONQUESTION or MB_YESNO or
6182 MB_DEFBUTTON2) <> mrYes then
6183 Exit;
6185 WAD.RemoveResource('', utf2win(MapName));
6187 MessageBox(0, PChar(Format(_lc[I_MSG_MAP_DELETED_PROMT],
6188 [MapName])),
6189 PChar(_lc[I_MSG_MAP_DELETED]),
6190 MB_ICONINFORMATION or MB_OK or
6191 MB_DEFBUTTON1);
6193 WAD.SaveTo(OpenDialog.FileName);
6195 // Удалили текущую карту - сохранять по старому ее нельзя:
6196 if OpenedMap = (OpenDialog.FileName+':\'+MapName) then
6197 begin
6198 OpenedMap := '';
6199 OpenedWAD := '';
6200 MainForm.Caption := FormCaption;
6201 end;
6202 end;
6204 WAD.Free();
6205 end;
6207 procedure TMainForm.vleObjectPropertyKeyDown(Sender: TObject;
6208 var Key: Word; Shift: TShiftState);
6209 begin
6210 if Key = VK_RETURN then
6211 vleObjectPropertyApply(Sender);
6212 end;
6214 procedure MovePanel(var ID: DWORD; MoveType: Byte);
6215 var
6216 _id, a: Integer;
6217 tmp: TPanel;
6218 begin
6219 if (ID = 0) and (MoveType = 0) then
6220 Exit;
6221 if (ID = DWORD(High(gPanels))) and (MoveType <> 0) then
6222 Exit;
6223 if (ID > DWORD(High(gPanels))) then
6224 Exit;
6226 _id := Integer(ID);
6228 if MoveType = 0 then // to Back
6229 begin
6230 if gTriggers <> nil then
6231 for a := 0 to High(gTriggers) do
6232 with gTriggers[a] do
6233 begin
6234 if TriggerType = TRIGGER_NONE then
6235 Continue;
6237 if TexturePanel = _id then
6238 TexturePanel := 0
6239 else
6240 if (TexturePanel >= 0) and (TexturePanel < _id) then
6241 Inc(TexturePanel);
6243 case TriggerType of
6244 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
6245 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP,
6246 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
6247 if Data.PanelID = _id then
6248 Data.PanelID := 0
6249 else
6250 if (Data.PanelID >= 0) and (Data.PanelID < _id) then
6251 Inc(Data.PanelID);
6253 TRIGGER_SHOT:
6254 if Data.ShotPanelID = _id then
6255 Data.ShotPanelID := 0
6256 else
6257 if (Data.ShotPanelID >= 0) and (Data.ShotPanelID < _id) then
6258 Inc(Data.ShotPanelID);
6259 end;
6260 end;
6262 tmp := gPanels[_id];
6264 for a := _id downto 1 do
6265 gPanels[a] := gPanels[a-1];
6267 gPanels[0] := tmp;
6269 ID := 0;
6270 end
6271 else // to Front
6272 begin
6273 if gTriggers <> nil then
6274 for a := 0 to High(gTriggers) do
6275 with gTriggers[a] do
6276 begin
6277 if TriggerType = TRIGGER_NONE then
6278 Continue;
6280 if TexturePanel = _id then
6281 TexturePanel := High(gPanels)
6282 else
6283 if TexturePanel > _id then
6284 Dec(TexturePanel);
6286 case TriggerType of
6287 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
6288 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP,
6289 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
6290 if Data.PanelID = _id then
6291 Data.PanelID := High(gPanels)
6292 else
6293 if Data.PanelID > _id then
6294 Dec(Data.PanelID);
6296 TRIGGER_SHOT:
6297 if Data.ShotPanelID = _id then
6298 Data.ShotPanelID := High(gPanels)
6299 else
6300 if Data.ShotPanelID > _id then
6301 Dec(Data.ShotPanelID);
6302 end;
6303 end;
6305 tmp := gPanels[_id];
6307 for a := _id to High(gPanels)-1 do
6308 gPanels[a] := gPanels[a+1];
6310 gPanels[High(gPanels)] := tmp;
6312 ID := High(gPanels);
6313 end;
6314 end;
6316 procedure TMainForm.aMoveToBack(Sender: TObject);
6317 var
6318 a: Integer;
6319 begin
6320 if SelectedObjects = nil then
6321 Exit;
6323 for a := 0 to High(SelectedObjects) do
6324 with SelectedObjects[a] do
6325 if Live and (ObjectType = OBJECT_PANEL) then
6326 begin
6327 SelectedObjects[0] := SelectedObjects[a];
6328 SetLength(SelectedObjects, 1);
6329 MovePanel(ID, 0);
6330 FillProperty();
6331 Break;
6332 end;
6333 end;
6335 procedure TMainForm.aMoveToFore(Sender: TObject);
6336 var
6337 a: Integer;
6338 begin
6339 if SelectedObjects = nil then
6340 Exit;
6342 for a := 0 to High(SelectedObjects) do
6343 with SelectedObjects[a] do
6344 if Live and (ObjectType = OBJECT_PANEL) then
6345 begin
6346 SelectedObjects[0] := SelectedObjects[a];
6347 SetLength(SelectedObjects, 1);
6348 MovePanel(ID, 1);
6349 FillProperty();
6350 Break;
6351 end;
6352 end;
6354 procedure TMainForm.aSaveMapAsExecute(Sender: TObject);
6355 var
6356 idx: Integer;
6357 begin
6358 SaveDialog.Filter := _lc[I_FILE_FILTER_WAD];
6360 if not SaveDialog.Execute() then
6361 Exit;
6363 SaveMapForm.GetMaps(SaveDialog.FileName, True);
6365 if SaveMapForm.ShowModal() <> mrOK then
6366 Exit;
6368 SaveDialog.InitialDir := ExtractFileDir(SaveDialog.FileName);
6369 OpenedMap := SaveDialog.FileName+':\'+SaveMapForm.eMapName.Text;
6370 OpenedWAD := SaveDialog.FileName;
6372 idx := RecentFiles.IndexOf(OpenedMap);
6373 // Такая карта уже недавно открывалась:
6374 if idx >= 0 then
6375 RecentFiles.Delete(idx);
6376 RecentFiles.Insert(0, OpenedMap);
6377 RefreshRecentMenu;
6379 SaveMap(OpenedMap);
6381 gMapInfo.FileName := SaveDialog.FileName;
6382 gMapInfo.MapName := SaveMapForm.eMapName.Text;
6383 UpdateCaption(gMapInfo.Name, ExtractFileName(gMapInfo.FileName), gMapInfo.MapName);
6384 end;
6386 procedure TMainForm.aSelectAllExecute(Sender: TObject);
6387 var
6388 a: Integer;
6389 begin
6390 RemoveSelectFromObjects();
6392 case pcObjects.ActivePageIndex+1 of
6393 OBJECT_PANEL:
6394 if gPanels <> nil then
6395 for a := 0 to High(gPanels) do
6396 if gPanels[a].PanelType <> PANEL_NONE then
6397 SelectObject(OBJECT_PANEL, a, True);
6398 OBJECT_ITEM:
6399 if gItems <> nil then
6400 for a := 0 to High(gItems) do
6401 if gItems[a].ItemType <> ITEM_NONE then
6402 SelectObject(OBJECT_ITEM, a, True);
6403 OBJECT_MONSTER:
6404 if gMonsters <> nil then
6405 for a := 0 to High(gMonsters) do
6406 if gMonsters[a].MonsterType <> MONSTER_NONE then
6407 SelectObject(OBJECT_MONSTER, a, True);
6408 OBJECT_AREA:
6409 if gAreas <> nil then
6410 for a := 0 to High(gAreas) do
6411 if gAreas[a].AreaType <> AREA_NONE then
6412 SelectObject(OBJECT_AREA, a, True);
6413 OBJECT_TRIGGER:
6414 if gTriggers <> nil then
6415 for a := 0 to High(gTriggers) do
6416 if gTriggers[a].TriggerType <> TRIGGER_NONE then
6417 SelectObject(OBJECT_TRIGGER, a, True);
6418 end;
6419 end;
6421 procedure TMainForm.tbGridOnClick(Sender: TObject);
6422 begin
6423 DotEnable := not DotEnable;
6424 (Sender as TToolButton).Down := DotEnable;
6425 end;
6427 procedure TMainForm.OnIdle(Sender: TObject; var Done: Boolean);
6428 begin
6429 // FIXME: this is a shitty hack
6430 if not gDataLoaded then
6431 begin
6432 e_WriteLog('Init OpenGL', MSG_NOTIFY);
6433 e_InitGL();
6434 e_WriteLog('Loading data', MSG_NOTIFY);
6435 LoadStdFont('STDTXT', 'STDFONT', gEditorFont);
6436 e_WriteLog('Loading more data', MSG_NOTIFY);
6437 LoadData();
6438 e_WriteLog('Loading even more data', MSG_NOTIFY);
6439 gDataLoaded := True;
6440 MainForm.FormResize(nil);
6441 end;
6442 Draw();
6443 end;
6445 procedure TMainForm.miMapPreviewClick(Sender: TObject);
6446 begin
6447 if PreviewMode = 2 then
6448 Exit;
6450 if PreviewMode = 0 then
6451 begin
6452 Splitter2.Visible := False;
6453 Splitter1.Visible := False;
6454 StatusBar.Visible := False;
6455 PanelObjs.Visible := False;
6456 PanelProps.Visible := False;
6457 MainToolBar.Visible := False;
6458 sbHorizontal.Visible := False;
6459 sbVertical.Visible := False;
6460 end
6461 else
6462 begin
6463 StatusBar.Visible := True;
6464 PanelObjs.Visible := True;
6465 PanelProps.Visible := True;
6466 Splitter2.Visible := True;
6467 Splitter1.Visible := True;
6468 MainToolBar.Visible := True;
6469 sbHorizontal.Visible := True;
6470 sbVertical.Visible := True;
6471 end;
6473 PreviewMode := PreviewMode xor 1;
6474 (Sender as TMenuItem).Checked := PreviewMode > 0;
6476 FormResize(Self);
6477 end;
6479 procedure TMainForm.miLayer1Click(Sender: TObject);
6480 begin
6481 SwitchLayer(LAYER_BACK);
6482 end;
6484 procedure TMainForm.miLayer2Click(Sender: TObject);
6485 begin
6486 SwitchLayer(LAYER_WALLS);
6487 end;
6489 procedure TMainForm.miLayer3Click(Sender: TObject);
6490 begin
6491 SwitchLayer(LAYER_FOREGROUND);
6492 end;
6494 procedure TMainForm.miLayer4Click(Sender: TObject);
6495 begin
6496 SwitchLayer(LAYER_STEPS);
6497 end;
6499 procedure TMainForm.miLayer5Click(Sender: TObject);
6500 begin
6501 SwitchLayer(LAYER_WATER);
6502 end;
6504 procedure TMainForm.miLayer6Click(Sender: TObject);
6505 begin
6506 SwitchLayer(LAYER_ITEMS);
6507 end;
6509 procedure TMainForm.miLayer7Click(Sender: TObject);
6510 begin
6511 SwitchLayer(LAYER_MONSTERS);
6512 end;
6514 procedure TMainForm.miLayer8Click(Sender: TObject);
6515 begin
6516 SwitchLayer(LAYER_AREAS);
6517 end;
6519 procedure TMainForm.miLayer9Click(Sender: TObject);
6520 begin
6521 SwitchLayer(LAYER_TRIGGERS);
6522 end;
6524 procedure TMainForm.tbShowClick(Sender: TObject);
6525 var
6526 a: Integer;
6527 b: Boolean;
6528 begin
6529 b := True;
6530 for a := 0 to High(LayerEnabled) do
6531 b := b and LayerEnabled[a];
6533 b := not b;
6535 ShowLayer(LAYER_BACK, b);
6536 ShowLayer(LAYER_WALLS, b);
6537 ShowLayer(LAYER_FOREGROUND, b);
6538 ShowLayer(LAYER_STEPS, b);
6539 ShowLayer(LAYER_WATER, b);
6540 ShowLayer(LAYER_ITEMS, b);
6541 ShowLayer(LAYER_MONSTERS, b);
6542 ShowLayer(LAYER_AREAS, b);
6543 ShowLayer(LAYER_TRIGGERS, b);
6544 end;
6546 procedure TMainForm.miMiniMapClick(Sender: TObject);
6547 begin
6548 SwitchMap();
6549 end;
6551 procedure TMainForm.miSwitchGridClick(Sender: TObject);
6552 begin
6553 if DotStep = DotStepOne then
6554 DotStep := DotStepTwo
6555 else
6556 DotStep := DotStepOne;
6558 MousePos.X := (MousePos.X div DotStep) * DotStep;
6559 MousePos.Y := (MousePos.Y div DotStep) * DotStep;
6560 end;
6562 procedure TMainForm.miShowEdgesClick(Sender: TObject);
6563 begin
6564 ShowEdges();
6565 end;
6567 procedure TMainForm.miSnapToGridClick(Sender: TObject);
6568 begin
6569 SnapToGrid := not SnapToGrid;
6571 MousePos.X := (MousePos.X div DotStep) * DotStep;
6572 MousePos.Y := (MousePos.Y div DotStep) * DotStep;
6574 miSnapToGrid.Checked := SnapToGrid;
6575 end;
6577 procedure TMainForm.minexttabClick(Sender: TObject);
6578 begin
6579 if pcObjects.ActivePageIndex < pcObjects.PageCount-1 then
6580 pcObjects.ActivePageIndex := pcObjects.ActivePageIndex+1
6581 else
6582 pcObjects.ActivePageIndex := 0;
6583 end;
6585 procedure TMainForm.miSaveMiniMapClick(Sender: TObject);
6586 begin
6587 SaveMiniMapForm.ShowModal();
6588 end;
6590 procedure TMainForm.bClearTextureClick(Sender: TObject);
6591 begin
6592 lbTextureList.ItemIndex := -1;
6593 lTextureWidth.Caption := '';
6594 lTextureHeight.Caption := '';
6595 end;
6597 procedure TMainForm.miPackMapClick(Sender: TObject);
6598 begin
6599 PackMapForm.ShowModal();
6600 end;
6602 procedure TMainForm.miMapTestSettingsClick(Sender: TObject);
6603 begin
6604 MapTestForm.ShowModal();
6605 end;
6607 procedure TMainForm.miTestMapClick(Sender: TObject);
6608 var
6609 cmd, mapWAD, mapToRun, tempWAD: String;
6610 opt: LongWord;
6611 time: Integer;
6612 proc: TProcessUTF8;
6613 res: Boolean;
6614 begin
6615 mapToRun := '';
6616 if OpenedMap <> '' then
6617 begin
6618 // Указываем текущую карту для теста:
6619 g_ProcessResourceStr(OpenedMap, @mapWAD, nil, @mapToRun);
6620 mapToRun := mapWAD + ':\' + mapToRun;
6621 mapToRun := ExtractRelativePath(ExtractFilePath(TestD2dExe) + 'maps/', mapToRun);
6622 end;
6623 // Сохраняем временную карту:
6624 time := 0;
6625 repeat
6626 mapWAD := ExtractFilePath(TestD2dExe) + Format('maps/temp%.4d.wad', [time]);
6627 Inc(time);
6628 until not FileExists(mapWAD);
6629 tempWAD := mapWAD + ':\' + TEST_MAP_NAME;
6630 SaveMap(tempWAD);
6632 tempWAD := ExtractRelativePath(ExtractFilePath(TestD2dExe) + 'maps/', tempWAD);
6633 // Если карта не была открыта, указываем временную в качестве текущей:
6634 if mapToRun = '' then
6635 mapToRun := tempWAD;
6637 // Опции игры:
6638 opt := 32 + 64;
6639 if TestOptionsTwoPlayers then
6640 opt := opt + 1;
6641 if TestOptionsTeamDamage then
6642 opt := opt + 2;
6643 if TestOptionsAllowExit then
6644 opt := opt + 4;
6645 if TestOptionsWeaponStay then
6646 opt := opt + 8;
6647 if TestOptionsMonstersDM then
6648 opt := opt + 16;
6650 // Составляем командную строку:
6651 cmd := '-map "' + mapToRun + '"';
6652 cmd := cmd + ' -testmap "' + tempWAD + '"';
6653 cmd := cmd + ' -gm ' + TestGameMode;
6654 cmd := cmd + ' -limt ' + TestLimTime;
6655 cmd := cmd + ' -lims ' + TestLimScore;
6656 cmd := cmd + ' -opt ' + IntToStr(opt);
6658 if TestMapOnce then
6659 cmd := cmd + ' --close';
6661 cmd := cmd + ' --debug';
6663 // Запускаем:
6664 proc := TProcessUTF8.Create(nil);
6665 proc.Executable := TestD2dExe;
6666 proc.Parameters.Add(cmd);
6667 res := True;
6668 try
6669 proc.Execute();
6670 except
6671 res := False;
6672 end;
6673 if res then
6674 begin
6675 Application.Minimize();
6676 proc.WaitOnExit();
6677 end;
6678 if (not res) or (proc.ExitCode < 0) then
6679 begin
6680 MessageBox(0, 'FIXME',
6681 PChar(_lc[I_MSG_EXEC_ERROR]),
6682 MB_OK or MB_ICONERROR);
6683 end;
6684 proc.Free();
6686 SysUtils.DeleteFile(mapWAD);
6687 Application.Restore();
6688 end;
6690 procedure TMainForm.sbVerticalScroll(Sender: TObject;
6691 ScrollCode: TScrollCode; var ScrollPos: Integer);
6692 begin
6693 MapOffset.Y := -Normalize16(sbVertical.Position);
6694 end;
6696 procedure TMainForm.sbHorizontalScroll(Sender: TObject;
6697 ScrollCode: TScrollCode; var ScrollPos: Integer);
6698 begin
6699 MapOffset.X := -Normalize16(sbHorizontal.Position);
6700 end;
6702 procedure TMainForm.miOpenWadMapClick(Sender: TObject);
6703 begin
6704 if OpenedWAD <> '' then
6705 begin
6706 OpenMap(OpenedWAD, '');
6707 end;
6708 end;
6710 procedure TMainForm.selectall1Click(Sender: TObject);
6711 var
6712 a: Integer;
6713 begin
6714 RemoveSelectFromObjects();
6716 if gPanels <> nil then
6717 for a := 0 to High(gPanels) do
6718 if gPanels[a].PanelType <> PANEL_NONE then
6719 SelectObject(OBJECT_PANEL, a, True);
6721 if gItems <> nil then
6722 for a := 0 to High(gItems) do
6723 if gItems[a].ItemType <> ITEM_NONE then
6724 SelectObject(OBJECT_ITEM, a, True);
6726 if gMonsters <> nil then
6727 for a := 0 to High(gMonsters) do
6728 if gMonsters[a].MonsterType <> MONSTER_NONE then
6729 SelectObject(OBJECT_MONSTER, a, True);
6731 if gAreas <> nil then
6732 for a := 0 to High(gAreas) do
6733 if gAreas[a].AreaType <> AREA_NONE then
6734 SelectObject(OBJECT_AREA, a, True);
6736 if gTriggers <> nil then
6737 for a := 0 to High(gTriggers) do
6738 if gTriggers[a].TriggerType <> TRIGGER_NONE then
6739 SelectObject(OBJECT_TRIGGER, a, True);
6740 end;
6742 procedure TMainForm.Splitter1CanResize(Sender: TObject;
6743 var NewSize: Integer; var Accept: Boolean);
6744 begin
6745 Accept := (NewSize > 140);
6746 end;
6748 procedure TMainForm.Splitter2CanResize(Sender: TObject;
6749 var NewSize: Integer; var Accept: Boolean);
6750 begin
6751 Accept := (NewSize > 110);
6752 end;
6754 procedure TMainForm.vleObjectPropertyEnter(Sender: TObject);
6755 begin
6756 EditingProperties := True;
6757 end;
6759 procedure TMainForm.vleObjectPropertyExit(Sender: TObject);
6760 begin
6761 EditingProperties := False;
6762 end;
6764 procedure TMainForm.FormKeyUp(Sender: TObject; var Key: Word;
6765 Shift: TShiftState);
6766 begin
6767 // Объекты передвигались:
6768 if MainForm.ActiveControl = RenderPanel then
6769 begin
6770 if (Key = VK_NUMPAD4) or
6771 (Key = VK_NUMPAD6) or
6772 (Key = VK_NUMPAD8) or
6773 (Key = VK_NUMPAD5) or
6774 (Key = Ord('V')) then
6775 FillProperty();
6776 end;
6777 // Быстрое превью карты:
6778 if Key = Ord('E') then
6779 begin
6780 if PreviewMode = 2 then
6781 PreviewMode := 0;
6782 end;
6783 RenderPanelMouseMove(Sender, Shift, RenderMousePos().X, RenderMousePos().Y);
6784 end;
6786 end.