DEADSOFTWARE

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