DEADSOFTWARE

d3193006eebd27184d3b0bc384de61a50d60962e
[d2df-editor.git] / src / editor / f_main.pas
1 unit f_main;
3 {$MODE Delphi}
5 interface
7 uses
8 LCLIntf, LCLType, LMessages, SysUtils, Variants, Classes, Graphics,
9 Controls, Forms, Dialogs, ImgList, StdCtrls, Buttons,
10 ComCtrls, ValEdit, Types, ToolWin, Menus, ExtCtrls,
11 CheckLst, Grids;
13 type
14 TMainForm = class(TForm)
15 // Главное меню:
16 MainMenu: TMainMenu;
17 // "Файл":
18 miMenuFile: TMenuItem;
19 miNewMap: TMenuItem;
20 miOpenMap: TMenuItem;
21 miSaveMap: TMenuItem;
22 miSaveMapAs: TMenuItem;
23 miOpenWadMap: TMenuItem;
24 miLine1: TMenuItem;
25 miSaveMiniMap: TMenuItem;
26 miDeleteMap: TMenuItem;
27 miPackMap: TMenuItem;
28 miLine2: TMenuItem;
29 miExit: TMenuItem;
30 // "Правка":
31 miMenuEdit: TMenuItem;
32 miUndo: TMenuItem;
33 miLine3: TMenuItem;
34 miCopy: TMenuItem;
35 miCut: TMenuItem;
36 miPaste: TMenuItem;
37 miLine4: TMenuItem;
38 miSelectAll: TMenuItem;
39 miLine5: TMenuItem;
40 miToFore: TMenuItem;
41 miToBack: TMenuItem;
42 // "Инструменты":
43 miMenuTools: TMenuItem;
44 miSnapToGrid: TMenuItem;
45 miMiniMap: TMenuItem;
46 miSwitchGrid: TMenuItem;
47 miShowEdges: TMenuItem;
48 miLayers: TMenuItem;
49 miLayer1: TMenuItem;
50 miLayer2: TMenuItem;
51 miLayer3: TMenuItem;
52 miLayer4: TMenuItem;
53 miLayer5: TMenuItem;
54 miLayer6: TMenuItem;
55 miLayer7: TMenuItem;
56 miLayer8: TMenuItem;
57 miLayer9: TMenuItem;
58 // "Сервис":
59 miMenuService: TMenuItem;
60 miCheckMap: TMenuItem;
61 miOptimmization: TMenuItem;
62 miMapPreview: TMenuItem;
63 miTestMap: TMenuItem;
64 // "Настройка":
65 miMenuSettings: TMenuItem;
66 miMapOptions: TMenuItem;
67 miLine6: TMenuItem;
68 miOptions: TMenuItem;
69 miLine7: TMenuItem;
70 miMapTestSettings: TMenuItem;
71 // "Справка":
72 miMenuHelp: TMenuItem;
73 miAbout: TMenuItem;
74 // Скрытый пункт меню для Ctrl+Tab:
75 miHidden1: TMenuItem;
76 minexttab: TMenuItem;
78 // Панель инструментов:
79 MainToolBar: TToolBar;
80 tbNewMap: TToolButton;
81 tbOpenMap: TToolButton;
82 tbSaveMap: TToolButton;
83 tbOpenWadMap: TToolButton;
84 tbLine1: TToolButton;
85 tbShowMap: TToolButton;
86 tbLine2: TToolButton;
87 tbShow: TToolButton;
88 tbLine3: TToolButton;
89 tbGridOn: TToolButton;
90 tbGrid: TToolButton;
91 tbLine4: TToolButton;
92 tbTestMap: TToolButton;
93 // Всплывающее меню для кнопки слоев:
94 pmShow: TPopupMenu;
95 miLayerP1: TMenuItem;
96 miLayerP2: TMenuItem;
97 miLayerP3: TMenuItem;
98 miLayerP4: TMenuItem;
99 miLayerP5: TMenuItem;
100 miLayerP6: TMenuItem;
101 miLayerP7: TMenuItem;
102 miLayerP8: TMenuItem;
103 miLayerP9: TMenuItem;
104 // Всплывающее меню для кнопки теста карты:
105 pmMapTest: TPopupMenu;
106 miMapTestPMSet: TMenuItem;
108 // Панель карты:
109 PanelMap: TPanel;
110 // Панель отображения карты:
111 RenderPanel: TPanel;
112 // Панель загрузки:
113 pLoadProgress: TPanel;
114 lLoad: TLabel;
115 pbLoad: TProgressBar;
116 // Полосы прокрутки:
117 sbHorizontal: TScrollBar;
118 sbVertical: TScrollBar;
120 // Панель свойств:
121 PanelProps: TPanel;
122 // Панель применения свойств:
123 PanelPropApply: TPanel;
124 bApplyProperty: TButton;
125 // Редактор свойств объектов:
126 vleObjectProperty: TValueListEditor;
128 // Панель объектов - вкладки:
129 PanelObjs: TPanel;
130 pcObjects: TPageControl;
131 // Вкладка "Панели":
132 tsPanels: TTabSheet;
133 lbTextureList: TListBox;
134 // Панель настройки текстур:
135 PanelTextures: TPanel;
136 LabelTxW: TLabel;
137 lTextureWidth: TLabel;
138 LabelTxH: TLabel;
139 lTextureHeight: TLabel;
140 cbPreview: TCheckBox;
141 bbAddTexture: TBitBtn;
142 bbRemoveTexture: TBitBtn;
143 bClearTexture: TButton;
144 // Панель типов панелей:
145 PanelPanelType: TPanel;
146 lbPanelType: TListBox;
147 // Вкладка "Предметы":
148 tsItems: TTabSheet;
149 lbItemList: TListBox;
150 cbOnlyDM: TCheckBox;
151 cbFall: TCheckBox;
152 // Вкладка "Монстры":
153 tsMonsters: TTabSheet;
154 lbMonsterList: TListBox;
155 rbMonsterLeft: TRadioButton;
156 rbMonsterRight: TRadioButton;
157 // Вкладка "Области":
158 tsAreas: TTabSheet;
159 lbAreasList: TListBox;
160 rbAreaLeft: TRadioButton;
161 rbAreaRight: TRadioButton;
162 // Вкладка "Триггеры":
163 tsTriggers: TTabSheet;
164 lbTriggersList: TListBox;
165 clbActivationType: TCheckListBox;
166 clbKeys: TCheckListBox;
168 // Остальные панели
169 Splitter1: TSplitter;
170 Splitter2: TSplitter;
171 StatusBar: TStatusBar;
173 // Специальные объекты:
174 ImageList: TImageList;
175 ilToolbar: TImageList;
176 OpenDialog: TOpenDialog;
177 SaveDialog: TSaveDialog;
178 selectall1: TMenuItem;
179 ColorDialog: TColorDialog;
181 procedure aAboutExecute(Sender: TObject);
182 procedure aCheckMapExecute(Sender: TObject);
183 procedure aMoveToFore(Sender: TObject);
184 procedure aMoveToBack(Sender: TObject);
185 procedure aCopyObjectExecute(Sender: TObject);
186 procedure aCutObjectExecute(Sender: TObject);
187 procedure aEditorOptionsExecute(Sender: TObject);
188 procedure aExitExecute(Sender: TObject);
189 procedure aMapOptionsExecute(Sender: TObject);
190 procedure aNewMapExecute(Sender: TObject);
191 procedure aOpenMapExecute(Sender: TObject);
192 procedure aOptimizeExecute(Sender: TObject);
193 procedure aPasteObjectExecute(Sender: TObject);
194 procedure aSelectAllExecute(Sender: TObject);
195 procedure aSaveMapExecute(Sender: TObject);
196 procedure aSaveMapAsExecute(Sender: TObject);
197 procedure aUndoExecute(Sender: TObject);
198 procedure aDeleteMap(Sender: TObject);
199 procedure bApplyPropertyClick(Sender: TObject);
200 procedure bbAddTextureClick(Sender: TObject);
201 procedure bbRemoveTextureClick(Sender: TObject);
202 procedure FormActivate(Sender: TObject);
203 procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
204 procedure FormCreate(Sender: TObject);
205 procedure FormDestroy(Sender: TObject);
206 procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
207 procedure FormResize(Sender: TObject);
208 procedure lbTextureListClick(Sender: TObject);
209 procedure RenderPanelMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
210 procedure RenderPanelMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
211 procedure RenderPanelMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
212 procedure RenderPanelResize(Sender: TObject);
213 procedure vleObjectPropertyEditButtonClick(Sender: TObject);
214 procedure vleObjectPropertyGetPickList(Sender: TObject; const KeyName: String; Values: TStrings);
215 procedure vleObjectPropertyKeyDown(Sender: TObject; var Key: Word;
216 Shift: TShiftState);
217 procedure tbGridOnClick(Sender: TObject);
218 procedure miMapPreviewClick(Sender: TObject);
219 procedure miLayer1Click(Sender: TObject);
220 procedure miLayer2Click(Sender: TObject);
221 procedure miLayer3Click(Sender: TObject);
222 procedure miLayer4Click(Sender: TObject);
223 procedure miLayer5Click(Sender: TObject);
224 procedure miLayer6Click(Sender: TObject);
225 procedure miLayer7Click(Sender: TObject);
226 procedure miLayer8Click(Sender: TObject);
227 procedure miLayer9Click(Sender: TObject);
228 procedure tbShowClick(Sender: TObject);
229 procedure miSnapToGridClick(Sender: TObject);
230 procedure miMiniMapClick(Sender: TObject);
231 procedure miSwitchGridClick(Sender: TObject);
232 procedure miShowEdgesClick(Sender: TObject);
233 procedure minexttabClick(Sender: TObject);
234 procedure miSaveMiniMapClick(Sender: TObject);
235 procedure bClearTextureClick(Sender: TObject);
236 procedure miPackMapClick(Sender: TObject);
237 procedure aRecentFileExecute(Sender: TObject);
238 procedure miMapTestSettingsClick(Sender: TObject);
239 procedure miTestMapClick(Sender: TObject);
240 procedure sbVerticalScroll(Sender: TObject; ScrollCode: TScrollCode;
241 var ScrollPos: Integer);
242 procedure sbHorizontalScroll(Sender: TObject; ScrollCode: TScrollCode;
243 var ScrollPos: Integer);
244 procedure miOpenWadMapClick(Sender: TObject);
245 procedure selectall1Click(Sender: TObject);
246 procedure Splitter1CanResize(Sender: TObject; var NewSize: Integer;
247 var Accept: Boolean);
248 procedure Splitter2CanResize(Sender: TObject; var NewSize: Integer;
249 var Accept: Boolean);
250 procedure vleObjectPropertyEnter(Sender: TObject);
251 procedure vleObjectPropertyExit(Sender: TObject);
252 procedure FormKeyUp(Sender: TObject; var Key: Word;
253 Shift: TShiftState);
254 private
255 procedure Draw();
256 procedure OnIdle(Sender: TObject; var Done: Boolean);
257 public
258 procedure RefreshRecentMenu();
259 { procedure lbTextureListDrawItem(Control: TWinControl; Index: Integer;
260 Rect: TRect; State: TOwnerDrawState); }
261 end;
263 const
264 LAYER_BACK = 0;
265 LAYER_WALLS = 1;
266 LAYER_FOREGROUND = 2;
267 LAYER_STEPS = 3;
268 LAYER_WATER = 4;
269 LAYER_ITEMS = 5;
270 LAYER_MONSTERS = 6;
271 LAYER_AREAS = 7;
272 LAYER_TRIGGERS = 8;
274 TEST_MAP_NAME = '$$$_TEST_$$$';
275 LANGUAGE_FILE_NAME = '_Editor.txt';
277 var
278 MainForm: TMainForm;
279 EditorDir: String;
280 OpenedMap: String;
281 OpenedWAD: String;
283 DotColor: TColor;
284 DotEnable: Boolean;
285 DotStep: Byte;
286 DotStepOne, DotStepTwo: Byte;
287 DotSize: Byte;
288 DrawTexturePanel: Boolean;
289 DrawPanelSize: Boolean;
290 BackColor: TColor;
291 PreviewColor: TColor;
292 Scale: Byte;
293 RecentCount: Integer;
294 RecentFiles: TStringList;
295 slInvalidTextures: TStringList;
297 TestGameMode: String;
298 TestLimTime: String;
299 TestLimScore: String;
300 TestOptionsTwoPlayers: Boolean;
301 TestOptionsTeamDamage: Boolean;
302 TestOptionsAllowExit: Boolean;
303 TestOptionsWeaponStay: Boolean;
304 TestOptionsMonstersDM: Boolean;
305 TestD2dExe: String;
306 TestMapOnce: Boolean;
308 LayerEnabled: Array [LAYER_BACK..LAYER_TRIGGERS] of Boolean =
309 (True, True, True, True, True, True, True, True, True);
310 PreviewMode: Boolean = False;
311 gLanguage: String;
313 FormCaption: String;
316 procedure OpenMap(FileName: String; mapN: String);
317 function AddTexture(aWAD, aSection, aTex: String; silent: Boolean): Boolean;
318 procedure RemoveSelectFromObjects();
319 procedure ChangeShownProperty(Name: String; NewValue: String);
321 implementation
323 uses
324 f_options, e_graphics, e_log, dglOpenGL, Math,
325 f_mapoptions, g_basic, f_about, f_mapoptimization,
326 f_mapcheck, f_addresource_texture, g_textures,
327 f_activationtype, f_keys, MAPWRITER, MAPSTRUCT,
328 MAPREADER, f_selectmap, f_savemap, WADEDITOR, MAPDEF,
329 g_map, f_saveminimap, f_addresource, CONFIG, f_packmap,
330 f_addresource_sound, f_maptest, f_choosetype,
331 g_language, f_selectlang, ClipBrd, Windows;
333 const
334 UNDO_DELETE_PANEL = 1;
335 UNDO_DELETE_ITEM = 2;
336 UNDO_DELETE_AREA = 3;
337 UNDO_DELETE_MONSTER = 4;
338 UNDO_DELETE_TRIGGER = 5;
339 UNDO_ADD_PANEL = 6;
340 UNDO_ADD_ITEM = 7;
341 UNDO_ADD_AREA = 8;
342 UNDO_ADD_MONSTER = 9;
343 UNDO_ADD_TRIGGER = 10;
344 UNDO_MOVE_PANEL = 11;
345 UNDO_MOVE_ITEM = 12;
346 UNDO_MOVE_AREA = 13;
347 UNDO_MOVE_MONSTER = 14;
348 UNDO_MOVE_TRIGGER = 15;
349 UNDO_RESIZE_PANEL = 16;
350 UNDO_RESIZE_TRIGGER = 17;
352 MOUSEACTION_NONE = 0;
353 MOUSEACTION_DRAWPANEL = 1;
354 MOUSEACTION_DRAWTRIGGER = 2;
355 MOUSEACTION_MOVEOBJ = 3;
356 MOUSEACTION_RESIZE = 4;
357 MOUSEACTION_MOVEMAP = 5;
358 MOUSEACTION_DRAWPRESS = 6;
359 MOUSEACTION_NOACTION = 7;
361 RESIZETYPE_NONE = 0;
362 RESIZETYPE_VERTICAL = 1;
363 RESIZETYPE_HORIZONTAL = 2;
365 RESIZEDIR_NONE = 0;
366 RESIZEDIR_DOWN = 1;
367 RESIZEDIR_UP = 2;
368 RESIZEDIR_RIGHT = 3;
369 RESIZEDIR_LEFT = 4;
371 SELECTFLAG_NONE = 0;
372 SELECTFLAG_TELEPORT = 1;
373 SELECTFLAG_DOOR = 2;
374 SELECTFLAG_TEXTURE = 3;
375 SELECTFLAG_LIFT = 4;
376 SELECTFLAG_MONSTER = 5;
377 SELECTFLAG_SPAWNPOINT = 6;
378 SELECTFLAG_SHOTPANEL = 7;
379 SELECTFLAG_SELECTED = 8;
381 RECENT_FILES_MENU_START = 11;
383 CLIPBOARD_SIG = 'DF:ED';
385 type
386 TUndoRec = record
387 UndoType: Byte;
388 case Byte of
389 UNDO_DELETE_PANEL: (Panel: ^TPanel);
390 UNDO_DELETE_ITEM: (Item: TItem);
391 UNDO_DELETE_AREA: (Area: TArea);
392 UNDO_DELETE_MONSTER: (Monster: TMonster);
393 UNDO_DELETE_TRIGGER: (Trigger: TTrigger);
394 UNDO_ADD_PANEL,
395 UNDO_ADD_ITEM,
396 UNDO_ADD_AREA,
397 UNDO_ADD_MONSTER,
398 UNDO_ADD_TRIGGER: (AddID: DWORD);
399 UNDO_MOVE_PANEL,
400 UNDO_MOVE_ITEM,
401 UNDO_MOVE_AREA,
402 UNDO_MOVE_MONSTER,
403 UNDO_MOVE_TRIGGER: (MoveID: DWORD; dX, dY: Integer);
404 UNDO_RESIZE_PANEL,
405 UNDO_RESIZE_TRIGGER: (ResizeID: DWORD; dW, dH: Integer);
406 end;
408 TCopyRec = record
409 ObjectType: Byte;
410 ID: Cardinal;
411 case Byte of
412 OBJECT_PANEL: (Panel: ^TPanel);
413 OBJECT_ITEM: (Item: TItem);
414 OBJECT_AREA: (Area: TArea);
415 OBJECT_MONSTER: (Monster: TMonster);
416 OBJECT_TRIGGER: (Trigger: TTrigger);
417 end;
419 TCopyRecArray = Array of TCopyRec;
421 var
422 hDC: THandle;
423 hRC: THandle;
424 gEditorFont: DWORD;
425 ShowMap: Boolean = False;
426 DrawRect: PRect = nil;
427 SnapToGrid: Boolean = True;
429 MousePos: Types.TPoint;
430 LastMovePoint: Types.TPoint;
431 MouseLDown: Boolean;
432 MouseRDown: Boolean;
433 MouseLDownPos: Types.TPoint;
434 MouseRDownPos: Types.TPoint;
436 SelectFlag: Byte = SELECTFLAG_NONE;
437 MouseAction: Byte = MOUSEACTION_NONE;
438 ResizeType: Byte = RESIZETYPE_NONE;
439 ResizeDirection: Byte = RESIZEDIR_NONE;
441 DrawPressRect: Boolean = False;
442 EditingProperties: Boolean = False;
444 UndoBuffer: Array of Array of TUndoRec = nil;
447 {$R *.lfm}
449 //----------------------------------------
450 //Далее идут вспомогательные процедуры
451 //----------------------------------------
453 function NameToBool(Name: String): Boolean;
454 begin
455 if Name = BoolNames[True] then
456 Result := True
457 else
458 Result := False;
459 end;
461 function NameToDir(Name: String): TDirection;
462 begin
463 if Name = DirNames[D_LEFT] then
464 Result := D_LEFT
465 else
466 Result := D_RIGHT;
467 end;
469 function NameToDirAdv(Name: String): Byte;
470 begin
471 if Name = DirNamesAdv[1] then
472 Result := 1
473 else
474 if Name = DirNamesAdv[2] then
475 Result := 2
476 else
477 if Name = DirNamesAdv[3] then
478 Result := 3
479 else
480 Result := 0;
481 end;
483 function ActivateToStr(ActivateType: Byte): String;
484 begin
485 Result := '';
487 if ByteBool(ACTIVATE_PLAYERCOLLIDE and ActivateType) then
488 Result := Result + '+PC';
489 if ByteBool(ACTIVATE_MONSTERCOLLIDE and ActivateType) then
490 Result := Result + '+MC';
491 if ByteBool(ACTIVATE_PLAYERPRESS and ActivateType) then
492 Result := Result + '+PP';
493 if ByteBool(ACTIVATE_MONSTERPRESS and ActivateType) then
494 Result := Result + '+MP';
495 if ByteBool(ACTIVATE_SHOT and ActivateType) then
496 Result := Result + '+SH';
497 if ByteBool(ACTIVATE_NOMONSTER and ActivateType) then
498 Result := Result + '+NM';
500 if (Result <> '') and (Result[1] = '+') then
501 Delete(Result, 1, 1);
502 end;
504 function StrToActivate(Str: String): Byte;
505 begin
506 Result := 0;
508 if Pos('PC', Str) > 0 then
509 Result := ACTIVATE_PLAYERCOLLIDE;
510 if Pos('MC', Str) > 0 then
511 Result := Result or ACTIVATE_MONSTERCOLLIDE;
512 if Pos('PP', Str) > 0 then
513 Result := Result or ACTIVATE_PLAYERPRESS;
514 if Pos('MP', Str) > 0 then
515 Result := Result or ACTIVATE_MONSTERPRESS;
516 if Pos('SH', Str) > 0 then
517 Result := Result or ACTIVATE_SHOT;
518 if Pos('NM', Str) > 0 then
519 Result := Result or ACTIVATE_NOMONSTER;
520 end;
522 function KeyToStr(Key: Byte): String;
523 begin
524 Result := '';
526 if ByteBool(KEY_RED and Key) then
527 Result := Result + '+RK';
528 if ByteBool(KEY_GREEN and Key) then
529 Result := Result + '+GK';
530 if ByteBool(KEY_BLUE and Key) then
531 Result := Result + '+BK';
532 if ByteBool(KEY_REDTEAM and Key) then
533 Result := Result + '+RT';
534 if ByteBool(KEY_BLUETEAM and Key) then
535 Result := Result + '+BT';
537 if (Result <> '') and (Result[1] = '+') then
538 Delete(Result, 1, 1);
539 end;
541 function StrToKey(Str: String): Byte;
542 begin
543 Result := 0;
545 if Pos('RK', Str) > 0 then
546 Result := KEY_RED;
547 if Pos('GK', Str) > 0 then
548 Result := Result or KEY_GREEN;
549 if Pos('BK', Str) > 0 then
550 Result := Result or KEY_BLUE;
551 if Pos('RT', Str) > 0 then
552 Result := Result or KEY_REDTEAM;
553 if Pos('BT', Str) > 0 then
554 Result := Result or KEY_BLUETEAM;
555 end;
557 function EffectToStr(Effect: Byte): String;
558 begin
559 if Effect in [EFFECT_TELEPORT..EFFECT_FIRE] then
560 Result := EffectNames[Effect]
561 else
562 Result := EffectNames[EFFECT_NONE];
563 end;
565 function StrToEffect(Str: String): Byte;
566 var
567 i: Integer;
568 begin
569 Result := EFFECT_NONE;
570 for i := EFFECT_TELEPORT to EFFECT_FIRE do
571 if EffectNames[i] = Str then
572 begin
573 Result := i;
574 Exit;
575 end;
576 end;
578 function MonsterToStr(MonType: Byte): String;
579 begin
580 if MonType in [MONSTER_DEMON..MONSTER_MAN] then
581 Result := MonsterNames[MonType]
582 else
583 Result := MonsterNames[MONSTER_ZOMBY];
584 end;
586 function StrToMonster(Str: String): Byte;
587 var
588 i: Integer;
589 begin
590 Result := MONSTER_ZOMBY;
591 for i := MONSTER_DEMON to MONSTER_MAN do
592 if MonsterNames[i] = Str then
593 begin
594 Result := i;
595 Exit;
596 end;
597 end;
599 function ItemToStr(ItemType: Byte): String;
600 begin
601 if ItemType in [ITEM_MEDKIT_SMALL..ITEM_MAX] then
602 Result := ItemNames[ItemType]
603 else
604 Result := ItemNames[ITEM_AMMO_BULLETS];
605 end;
607 function StrToItem(Str: String): Byte;
608 var
609 i: Integer;
610 begin
611 Result := ITEM_AMMO_BULLETS;
612 for i := ITEM_MEDKIT_SMALL to ITEM_MAX do
613 if ItemNames[i] = Str then
614 begin
615 Result := i;
616 Exit;
617 end;
618 end;
620 function ShotToStr(ShotType: Byte): String;
621 begin
622 if ShotType in [TRIGGER_SHOT_PISTOL..TRIGGER_SHOT_MAX] then
623 Result := ShotNames[ShotType]
624 else
625 Result := ShotNames[TRIGGER_SHOT_PISTOL];
626 end;
628 function StrToShot(Str: String): Byte;
629 var
630 i: Integer;
631 begin
632 Result := TRIGGER_SHOT_PISTOL;
633 for i := TRIGGER_SHOT_PISTOL to TRIGGER_SHOT_MAX do
634 if ShotNames[i] = Str then
635 begin
636 Result := i;
637 Exit;
638 end;
639 end;
641 function SelectedObjectCount(): Word;
642 var
643 a: Integer;
644 begin
645 Result := 0;
647 if SelectedObjects = nil then
648 Exit;
650 for a := 0 to High(SelectedObjects) do
651 if SelectedObjects[a].Live then
652 Result := Result + 1;
653 end;
655 function GetFirstSelected(): Integer;
656 var
657 a: Integer;
658 begin
659 Result := -1;
661 if SelectedObjects = nil then
662 Exit;
664 for a := 0 to High(SelectedObjects) do
665 if SelectedObjects[a].Live then
666 begin
667 Result := a;
668 Exit;
669 end;
670 end;
672 function Normalize16(x: Integer): Integer;
673 begin
674 Result := (x div 16) * 16;
675 end;
677 procedure MoveMap(X, Y: Integer);
678 var
679 rx, ry, ScaleSz: Integer;
680 begin
681 with MainForm.RenderPanel do
682 begin
683 ScaleSz := 16 div Scale;
684 // Размер видимой части карты:
685 rx := min(Normalize16(Width), Normalize16(gMapInfo.Width)) div 2;
686 ry := min(Normalize16(Height), Normalize16(gMapInfo.Height)) div 2;
687 // Место клика на мини-карте:
688 MapOffset.X := X - (Width-max(gMapInfo.Width div ScaleSz, 1)-1);
689 MapOffset.Y := Y - 1;
690 // Это же место на "большой" карте:
691 MapOffset.X := MapOffset.X * ScaleSz;
692 MapOffset.Y := MapOffset.Y * ScaleSz;
693 // Левый верхний угол новой видимой части карты:
694 MapOffset.X := MapOffset.X - rx;
695 MapOffset.Y := MapOffset.Y - ry;
696 // Выход за границы:
697 if MapOffset.X < 0 then
698 MapOffset.X := 0;
699 if MapOffset.Y < 0 then
700 MapOffset.Y := 0;
701 if MapOffset.X > MainForm.sbHorizontal.Max then
702 MapOffset.X := MainForm.sbHorizontal.Max;
703 if MapOffset.Y > MainForm.sbVertical.Max then
704 MapOffset.Y := MainForm.sbVertical.Max;
705 // Кратно 16:
706 MapOffset.X := Normalize16(MapOffset.X);
707 MapOffset.Y := Normalize16(MapOffset.Y);
708 end;
710 MainForm.sbHorizontal.Position := MapOffset.X;
711 MainForm.sbVertical.Position := MapOffset.Y;
713 MapOffset.X := -MapOffset.X;
714 MapOffset.Y := -MapOffset.Y;
716 MainForm.Resize();
717 end;
719 function IsTexturedPanel(PanelType: Word): Boolean;
720 begin
721 Result := WordBool(PanelType and (PANEL_WALL or PANEL_BACK or PANEL_FORE or
722 PANEL_STEP or PANEL_OPENDOOR or PANEL_CLOSEDOOR or
723 PANEL_WATER or PANEL_ACID1 or PANEL_ACID2));
724 end;
726 procedure FillProperty();
727 var
728 _id: DWORD;
729 str: String;
730 begin
731 MainForm.vleObjectProperty.Strings.Clear();
733 // Отображаем свойства если выделен только один объект:
734 if SelectedObjectCount() <> 1 then
735 Exit;
737 _id := GetFirstSelected();
738 if not SelectedObjects[_id].Live then
739 Exit;
741 with MainForm.vleObjectProperty do
742 with ItemProps[InsertRow(_lc[I_PROP_ID], IntToStr(SelectedObjects[_id].ID), True)] do
743 begin
744 EditStyle := esSimple;
745 ReadOnly := True;
746 end;
748 case SelectedObjects[0].ObjectType of
749 OBJECT_PANEL:
750 begin
751 with MainForm.vleObjectProperty,
752 gPanels[SelectedObjects[_id].ID] do
753 begin
754 with ItemProps[InsertRow(_lc[I_PROP_X], IntToStr(X), True)] do
755 begin
756 EditStyle := esSimple;
757 MaxLength := 5;
758 end;
760 with ItemProps[InsertRow(_lc[I_PROP_Y], IntToStr(Y), True)] do
761 begin
762 EditStyle := esSimple;
763 MaxLength := 5;
764 end;
766 with ItemProps[InsertRow(_lc[I_PROP_WIDTH], IntToStr(Width), True)] do
767 begin
768 EditStyle := esSimple;
769 MaxLength := 5;
770 end;
772 with ItemProps[InsertRow(_lc[I_PROP_HEIGHT], IntToStr(Height), True)] do
773 begin
774 EditStyle := esSimple;
775 MaxLength := 5;
776 end;
778 with ItemProps[InsertRow(_lc[I_PROP_PANEL_TYPE], GetPanelName(PanelType), True)] do
779 begin
780 EditStyle := esEllipsis;
781 ReadOnly := True;
782 end;
784 if IsTexturedPanel(PanelType) then
785 begin // Может быть текстура
786 with ItemProps[InsertRow(_lc[I_PROP_PANEL_TEX], TextureName, True)] do
787 begin
788 EditStyle := esEllipsis;
789 ReadOnly := True;
790 end;
792 if TextureName <> '' then
793 begin // Есть текстура
794 with ItemProps[InsertRow(_lc[I_PROP_PANEL_ALPHA], IntToStr(Alpha), True)] do
795 begin
796 EditStyle := esSimple;
797 MaxLength := 3;
798 end;
800 with ItemProps[InsertRow(_lc[I_PROP_PANEL_BLEND], BoolNames[Blending], True)] do
801 begin
802 EditStyle := esPickList;
803 ReadOnly := True;
804 end;
805 end;
806 end;
807 end;
808 end;
810 OBJECT_ITEM:
811 begin
812 with MainForm.vleObjectProperty,
813 gItems[SelectedObjects[_id].ID] do
814 begin
815 with ItemProps[InsertRow(_lc[I_PROP_X], IntToStr(X), True)] do
816 begin
817 EditStyle := esSimple;
818 MaxLength := 5;
819 end;
821 with ItemProps[InsertRow(_lc[I_PROP_Y], IntToStr(Y), True)] do
822 begin
823 EditStyle := esSimple;
824 MaxLength := 5;
825 end;
827 with ItemProps[InsertRow(_lc[I_PROP_DM_ONLY], BoolNames[OnlyDM], True)] do
828 begin
829 EditStyle := esPickList;
830 ReadOnly := True;
831 end;
833 with ItemProps[InsertRow(_lc[I_PROP_ITEM_FALLS], BoolNames[Fall], True)] do
834 begin
835 EditStyle := esPickList;
836 ReadOnly := True;
837 end;
838 end;
839 end;
841 OBJECT_MONSTER:
842 begin
843 with MainForm.vleObjectProperty,
844 gMonsters[SelectedObjects[_id].ID] do
845 begin
846 with ItemProps[InsertRow(_lc[I_PROP_X], IntToStr(X), True)] do
847 begin
848 EditStyle := esSimple;
849 MaxLength := 5;
850 end;
852 with ItemProps[InsertRow(_lc[I_PROP_Y], IntToStr(Y), True)] do
853 begin
854 EditStyle := esSimple;
855 MaxLength := 5;
856 end;
858 with ItemProps[InsertRow(_lc[I_PROP_DIRECTION], DirNames[Direction], True)] do
859 begin
860 EditStyle := esPickList;
861 ReadOnly := True;
862 end;
863 end;
864 end;
866 OBJECT_AREA:
867 begin
868 with MainForm.vleObjectProperty,
869 gAreas[SelectedObjects[_id].ID] do
870 begin
871 with ItemProps[InsertRow(_lc[I_PROP_X], IntToStr(X), True)] do
872 begin
873 EditStyle := esSimple;
874 MaxLength := 5;
875 end;
877 with ItemProps[InsertRow(_lc[I_PROP_Y], IntToStr(Y), True)] do
878 begin
879 EditStyle := esSimple;
880 MaxLength := 5;
881 end;
883 with ItemProps[InsertRow(_lc[I_PROP_DIRECTION], DirNames[Direction], True)] do
884 begin
885 EditStyle := esPickList;
886 ReadOnly := True;
887 end;
888 end;
889 end;
891 OBJECT_TRIGGER:
892 begin
893 with MainForm.vleObjectProperty,
894 gTriggers[SelectedObjects[_id].ID] do
895 begin
896 with ItemProps[InsertRow(_lc[I_PROP_TR_TYPE], GetTriggerName(TriggerType), True)] do
897 begin
898 EditStyle := esSimple;
899 ReadOnly := True;
900 end;
902 with ItemProps[InsertRow(_lc[I_PROP_X], IntToStr(X), True)] do
903 begin
904 EditStyle := esSimple;
905 MaxLength := 5;
906 end;
908 with ItemProps[InsertRow(_lc[I_PROP_Y], IntToStr(Y), True)] do
909 begin
910 EditStyle := esSimple;
911 MaxLength := 5;
912 end;
914 with ItemProps[InsertRow(_lc[I_PROP_WIDTH], IntToStr(Width), True)] do
915 begin
916 EditStyle := esSimple;
917 MaxLength := 5;
918 end;
920 with ItemProps[InsertRow(_lc[I_PROP_HEIGHT], IntToStr(Height), True)] do
921 begin
922 EditStyle := esSimple;
923 MaxLength := 5;
924 end;
926 with ItemProps[InsertRow(_lc[I_PROP_TR_ENABLED], BoolNames[Enabled], True)] do
927 begin
928 EditStyle := esPickList;
929 ReadOnly := True;
930 end;
932 with ItemProps[InsertRow(_lc[I_PROP_TR_TEXTURE_PANEL], IntToStr(TexturePanel), True)] do
933 begin
934 EditStyle := esEllipsis;
935 ReadOnly := True;
936 end;
938 with ItemProps[InsertRow(_lc[I_PROP_TR_ACTIVATION], ActivateToStr(ActivateType), True)] do
939 begin
940 EditStyle := esEllipsis;
941 ReadOnly := True;
942 end;
944 with ItemProps[InsertRow(_lc[I_PROP_TR_KEYS], KeyToStr(Key), True)] do
945 begin
946 EditStyle := esEllipsis;
947 ReadOnly := True;
948 end;
950 case TriggerType of
951 TRIGGER_EXIT:
952 begin
953 with ItemProps[InsertRow(_lc[I_PROP_TR_NEXT_MAP], Data.MapName, True)] do
954 begin
955 EditStyle := esEllipsis;
956 ReadOnly := True;
957 end;
958 end;
960 TRIGGER_TELEPORT:
961 begin
962 with ItemProps[InsertRow(_lc[I_PROP_TR_TELEPORT_TO], Format('(%d:%d)', [Data.TargetPoint.X, Data.TargetPoint.Y]), True)] do
963 begin
964 EditStyle := esEllipsis;
965 ReadOnly := True;
966 end;
968 with ItemProps[InsertRow(_lc[I_PROP_TR_D2D], BoolNames[Data.d2d_teleport], True)] do
969 begin
970 EditStyle := esPickList;
971 ReadOnly := True;
972 end;
974 with ItemProps[InsertRow(_lc[I_PROP_TR_TELEPORT_SILENT], BoolNames[Data.silent_teleport], True)] do
975 begin
976 EditStyle := esPickList;
977 ReadOnly := True;
978 end;
980 with ItemProps[InsertRow(_lc[I_PROP_TR_TELEPORT_DIR], DirNamesAdv[Data.TlpDir], True)] do
981 begin
982 EditStyle := esPickList;
983 ReadOnly := True;
984 end;
985 end;
987 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR,
988 TRIGGER_DOOR, TRIGGER_DOOR5:
989 begin
990 with ItemProps[InsertRow(_lc[I_PROP_TR_DOOR_PANEL], IntToStr(Data.PanelID), True)] do
991 begin
992 EditStyle := esEllipsis;
993 ReadOnly := True;
994 end;
996 with ItemProps[InsertRow(_lc[I_PROP_TR_SILENT], BoolNames[Data.NoSound], True)] do
997 begin
998 EditStyle := esPickList;
999 ReadOnly := True;
1000 end;
1002 with ItemProps[InsertRow(_lc[I_PROP_TR_D2D], BoolNames[Data.d2d_doors], True)] do
1003 begin
1004 EditStyle := esPickList;
1005 ReadOnly := True;
1006 end;
1007 end;
1009 TRIGGER_CLOSETRAP, TRIGGER_TRAP:
1010 begin
1011 with ItemProps[InsertRow(_lc[I_PROP_TR_TRAP_PANEL], IntToStr(Data.PanelID), True)] do
1012 begin
1013 EditStyle := esEllipsis;
1014 ReadOnly := True;
1015 end;
1017 with ItemProps[InsertRow(_lc[I_PROP_TR_SILENT], BoolNames[Data.NoSound], True)] do
1018 begin
1019 EditStyle := esPickList;
1020 ReadOnly := True;
1021 end;
1023 with ItemProps[InsertRow(_lc[I_PROP_TR_D2D], BoolNames[Data.d2d_doors], True)] do
1024 begin
1025 EditStyle := esPickList;
1026 ReadOnly := True;
1027 end;
1028 end;
1030 TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF,
1031 TRIGGER_ONOFF:
1032 begin
1033 with ItemProps[InsertRow(_lc[I_PROP_TR_EX_AREA],
1034 Format('(%d:%d %d:%d)', [Data.tX, Data.tY, Data.tWidth, Data.tHeight]), True)] do
1035 begin
1036 EditStyle := esEllipsis;
1037 ReadOnly := True;
1038 end;
1040 with ItemProps[InsertRow(_lc[I_PROP_TR_EX_DELAY], IntToStr(Data.Wait), True)] do
1041 begin
1042 EditStyle := esSimple;
1043 MaxLength := 5;
1044 end;
1046 with ItemProps[InsertRow(_lc[I_PROP_TR_EX_COUNT], IntToStr(Data.Count), True)] do
1047 begin
1048 EditStyle := esSimple;
1049 MaxLength := 5;
1050 end;
1052 with ItemProps[InsertRow(_lc[I_PROP_TR_EX_MONSTER], IntToStr(Data.MonsterID-1), True)] do
1053 begin
1054 EditStyle := esEllipsis;
1055 ReadOnly := True;
1056 end;
1058 if TriggerType = TRIGGER_PRESS then
1059 with ItemProps[InsertRow(_lc[I_PROP_TR_EX_RANDOM], BoolNames[Data.ExtRandom], True)] do
1060 begin
1061 EditStyle := esPickList;
1062 ReadOnly := True;
1063 end;
1064 end;
1066 TRIGGER_SECRET:
1069 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
1070 begin
1071 with ItemProps[InsertRow(_lc[I_PROP_TR_LIFT_PANEL], IntToStr(Data.PanelID), True)] do
1072 begin
1073 EditStyle := esEllipsis;
1074 ReadOnly := True;
1075 end;
1077 with ItemProps[InsertRow(_lc[I_PROP_TR_SILENT], BoolNames[Data.NoSound], True)] do
1078 begin
1079 EditStyle := esPickList;
1080 ReadOnly := True;
1081 end;
1083 with ItemProps[InsertRow(_lc[I_PROP_TR_D2D], BoolNames[Data.d2d_doors], True)] do
1084 begin
1085 EditStyle := esPickList;
1086 ReadOnly := True;
1087 end;
1088 end;
1090 TRIGGER_TEXTURE:
1091 begin
1092 with ItemProps[InsertRow(_lc[I_PROP_TR_TEXTURE_ONCE], BoolNames[Data.ActivateOnce], True)] do
1093 begin
1094 EditStyle := esPickList;
1095 ReadOnly := True;
1096 end;
1098 with ItemProps[InsertRow(_lc[I_PROP_TR_TEXTURE_ANIM_ONCE], BoolNames[Data.AnimOnce], True)] do
1099 begin
1100 EditStyle := esPickList;
1101 ReadOnly := True;
1102 end;
1103 end;
1105 TRIGGER_SOUND:
1106 begin
1107 with ItemProps[InsertRow(_lc[I_PROP_TR_SOUND_NAME], Data.SoundName, True)] do
1108 begin
1109 EditStyle := esEllipsis;
1110 ReadOnly := True;
1111 end;
1113 with ItemProps[InsertRow(_lc[I_PROP_TR_SOUND_VOLUME], IntToStr(Data.Volume), True)] do
1114 begin
1115 EditStyle := esSimple;
1116 MaxLength := 3;
1117 end;
1119 with ItemProps[InsertRow(_lc[I_PROP_TR_SOUND_PAN], IntToStr(Data.Pan), True)] do
1120 begin
1121 EditStyle := esSimple;
1122 MaxLength := 3;
1123 end;
1125 with ItemProps[InsertRow(_lc[I_PROP_TR_SOUND_COUNT], IntToStr(Data.PlayCount), True)] do
1126 begin
1127 EditStyle := esSimple;
1128 MaxLength := 3;
1129 end;
1131 with ItemProps[InsertRow(_lc[I_PROP_TR_SOUND_LOCAL], BoolNames[Data.Local], True)] do
1132 begin
1133 EditStyle := esPickList;
1134 ReadOnly := True;
1135 end;
1137 with ItemProps[InsertRow(_lc[I_PROP_TR_SOUND_SWITCH], BoolNames[Data.SoundSwitch], True)] do
1138 begin
1139 EditStyle := esPickList;
1140 ReadOnly := True;
1141 end;
1142 end;
1144 TRIGGER_SPAWNMONSTER:
1145 begin
1146 with ItemProps[InsertRow(_lc[I_PROP_TR_MONSTER_TYPE], MonsterToStr(Data.MonType), True)] do
1147 begin
1148 EditStyle := esEllipsis;
1149 ReadOnly := True;
1150 end;
1152 with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_TO],
1153 Format('(%d:%d)', [Data.MonPos.X, Data.MonPos.Y]), True)] do
1154 begin
1155 EditStyle := esEllipsis;
1156 ReadOnly := True;
1157 end;
1159 with ItemProps[InsertRow(_lc[I_PROP_DIRECTION], DirNames[TDirection(Data.MonDir)], True)] do
1160 begin
1161 EditStyle := esPickList;
1162 ReadOnly := True;
1163 end;
1165 with ItemProps[InsertRow(_lc[I_PROP_TR_HEALTH], IntToStr(Data.MonHealth), True)] do
1166 begin
1167 EditStyle := esSimple;
1168 MaxLength := 5;
1169 end;
1171 with ItemProps[InsertRow(_lc[I_PROP_TR_MONSTER_ACTIVE], BoolNames[Data.MonActive], True)] do
1172 begin
1173 EditStyle := esPickList;
1174 ReadOnly := True;
1175 end;
1177 with ItemProps[InsertRow(_lc[I_PROP_TR_COUNT], IntToStr(Data.MonCount), True)] do
1178 begin
1179 EditStyle := esSimple;
1180 MaxLength := 5;
1181 end;
1183 with ItemProps[InsertRow(_lc[I_PROP_TR_FX_TYPE], EffectToStr(Data.MonEffect), True)] do
1184 begin
1185 EditStyle := esEllipsis;
1186 ReadOnly := True;
1187 end;
1189 with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_MAX], IntToStr(Data.MonMax), True)] do
1190 begin
1191 EditStyle := esSimple;
1192 MaxLength := 5;
1193 end;
1195 with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_DELAY], IntToStr(Data.MonDelay), True)] do
1196 begin
1197 EditStyle := esSimple;
1198 MaxLength := 5;
1199 end;
1201 case Data.MonBehav of
1202 1: str := _lc[I_PROP_TR_MONSTER_BEHAVIOUR_1];
1203 2: str := _lc[I_PROP_TR_MONSTER_BEHAVIOUR_2];
1204 3: str := _lc[I_PROP_TR_MONSTER_BEHAVIOUR_3];
1205 4: str := _lc[I_PROP_TR_MONSTER_BEHAVIOUR_4];
1206 5: str := _lc[I_PROP_TR_MONSTER_BEHAVIOUR_5];
1207 else str := _lc[I_PROP_TR_MONSTER_BEHAVIOUR_0];
1208 end;
1209 with ItemProps[InsertRow(_lc[I_PROP_TR_MONSTER_BEHAVIOUR], str, True)] do
1210 begin
1211 EditStyle := esPickList;
1212 ReadOnly := True;
1213 end;
1214 end;
1216 TRIGGER_SPAWNITEM:
1217 begin
1218 with ItemProps[InsertRow(_lc[I_PROP_TR_ITEM_TYPE], ItemToStr(Data.ItemType), True)] do
1219 begin
1220 EditStyle := esEllipsis;
1221 ReadOnly := True;
1222 end;
1224 with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_TO],
1225 Format('(%d:%d)', [Data.ItemPos.X, Data.ItemPos.Y]), True)] do
1226 begin
1227 EditStyle := esEllipsis;
1228 ReadOnly := True;
1229 end;
1231 with ItemProps[InsertRow(_lc[I_PROP_DM_ONLY], BoolNames[Data.ItemOnlyDM], True)] do
1232 begin
1233 EditStyle := esPickList;
1234 ReadOnly := True;
1235 end;
1237 with ItemProps[InsertRow(_lc[I_PROP_ITEM_FALLS], BoolNames[Data.ItemFalls], True)] do
1238 begin
1239 EditStyle := esPickList;
1240 ReadOnly := True;
1241 end;
1243 with ItemProps[InsertRow(_lc[I_PROP_TR_COUNT], IntToStr(Data.ItemCount), True)] do
1244 begin
1245 EditStyle := esSimple;
1246 MaxLength := 5;
1247 end;
1249 with ItemProps[InsertRow(_lc[I_PROP_TR_FX_TYPE], EffectToStr(Data.ItemEffect), True)] do
1250 begin
1251 EditStyle := esEllipsis;
1252 ReadOnly := True;
1253 end;
1255 with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_MAX], IntToStr(Data.ItemMax), True)] do
1256 begin
1257 EditStyle := esSimple;
1258 MaxLength := 5;
1259 end;
1261 with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_DELAY], IntToStr(Data.ItemDelay), True)] do
1262 begin
1263 EditStyle := esSimple;
1264 MaxLength := 5;
1265 end;
1266 end;
1268 TRIGGER_MUSIC:
1269 begin
1270 with ItemProps[InsertRow(_lc[I_PROP_TR_MUSIC_NAME], Data.MusicName, True)] do
1271 begin
1272 EditStyle := esEllipsis;
1273 ReadOnly := True;
1274 end;
1276 if Data.MusicAction = 1 then
1277 str := _lc[I_PROP_TR_MUSIC_ON]
1278 else
1279 str := _lc[I_PROP_TR_MUSIC_OFF];
1281 with ItemProps[InsertRow(_lc[I_PROP_TR_MUSIC_ACT], str, True)] do
1282 begin
1283 EditStyle := esPickList;
1284 ReadOnly := True;
1285 end;
1286 end;
1288 TRIGGER_PUSH:
1289 begin
1290 with ItemProps[InsertRow(_lc[I_PROP_TR_PUSH_ANGLE], IntToStr(Data.PushAngle), True)] do
1291 begin
1292 EditStyle := esSimple;
1293 MaxLength := 4;
1294 end;
1295 with ItemProps[InsertRow(_lc[I_PROP_TR_PUSH_FORCE], IntToStr(Data.PushForce), True)] do
1296 begin
1297 EditStyle := esSimple;
1298 MaxLength := 4;
1299 end;
1300 with ItemProps[InsertRow(_lc[I_PROP_TR_PUSH_RESET], BoolNames[Data.ResetVel], True)] do
1301 begin
1302 EditStyle := esPickList;
1303 ReadOnly := True;
1304 end;
1305 end;
1307 TRIGGER_SCORE:
1308 begin
1309 case Data.ScoreAction of
1310 1: str := _lc[I_PROP_TR_SCORE_ACT_1];
1311 2: str := _lc[I_PROP_TR_SCORE_ACT_2];
1312 3: str := _lc[I_PROP_TR_SCORE_ACT_3];
1313 else str := _lc[I_PROP_TR_SCORE_ACT_0];
1314 end;
1315 with ItemProps[InsertRow(_lc[I_PROP_TR_SCORE_ACT], str, True)] do
1316 begin
1317 EditStyle := esPickList;
1318 ReadOnly := True;
1319 end;
1320 with ItemProps[InsertRow(_lc[I_PROP_TR_COUNT], IntToStr(Data.ScoreCount), True)] do
1321 begin
1322 EditStyle := esSimple;
1323 MaxLength := 3;
1324 end;
1325 case Data.ScoreTeam of
1326 1: str := _lc[I_PROP_TR_SCORE_TEAM_1];
1327 2: str := _lc[I_PROP_TR_SCORE_TEAM_2];
1328 3: str := _lc[I_PROP_TR_SCORE_TEAM_3];
1329 else str := _lc[I_PROP_TR_SCORE_TEAM_0];
1330 end;
1331 with ItemProps[InsertRow(_lc[I_PROP_TR_SCORE_TEAM], str, True)] do
1332 begin
1333 EditStyle := esPickList;
1334 ReadOnly := True;
1335 end;
1336 with ItemProps[InsertRow(_lc[I_PROP_TR_SCORE_CON], BoolNames[Data.ScoreCon], True)] do
1337 begin
1338 EditStyle := esPickList;
1339 ReadOnly := True;
1340 end;
1341 with ItemProps[InsertRow(_lc[I_PROP_TR_SCORE_MSG], BoolNames[Data.ScoreMsg], True)] do
1342 begin
1343 EditStyle := esPickList;
1344 ReadOnly := True;
1345 end;
1346 end;
1348 TRIGGER_MESSAGE:
1349 begin
1350 case Data.MessageKind of
1351 1: str := _lc[I_PROP_TR_MESSAGE_KIND_1];
1352 else str := _lc[I_PROP_TR_MESSAGE_KIND_0];
1353 end;
1354 with ItemProps[InsertRow(_lc[I_PROP_TR_MESSAGE_KIND], str, True)] do
1355 begin
1356 EditStyle := esPickList;
1357 ReadOnly := True;
1358 end;
1359 case Data.MessageSendTo of
1360 1: str := _lc[I_PROP_TR_MESSAGE_TO_1];
1361 2: str := _lc[I_PROP_TR_MESSAGE_TO_2];
1362 3: str := _lc[I_PROP_TR_MESSAGE_TO_3];
1363 4: str := _lc[I_PROP_TR_MESSAGE_TO_4];
1364 5: str := _lc[I_PROP_TR_MESSAGE_TO_5];
1365 else str := _lc[I_PROP_TR_MESSAGE_TO_0];
1366 end;
1367 with ItemProps[InsertRow(_lc[I_PROP_TR_MESSAGE_TO], str, True)] do
1368 begin
1369 EditStyle := esPickList;
1370 ReadOnly := True;
1371 end;
1372 with ItemProps[InsertRow(_lc[I_PROP_TR_MESSAGE_TEXT], Data.MessageText, True)] do
1373 begin
1374 EditStyle := esSimple;
1375 MaxLength := 100;
1376 end;
1377 with ItemProps[InsertRow(_lc[I_PROP_TR_MESSAGE_TIME], IntToStr(Data.MessageTime), True)] do
1378 begin
1379 EditStyle := esSimple;
1380 MaxLength := 5;
1381 end;
1382 end;
1384 TRIGGER_DAMAGE:
1385 begin
1386 with ItemProps[InsertRow(_lc[I_PROP_TR_DAMAGE_VALUE], IntToStr(Data.DamageValue), True)] do
1387 begin
1388 EditStyle := esSimple;
1389 MaxLength := 5;
1390 end;
1391 with ItemProps[InsertRow(_lc[I_PROP_TR_INTERVAL], IntToStr(Data.DamageInterval), True)] do
1392 begin
1393 EditStyle := esSimple;
1394 MaxLength := 5;
1395 end;
1396 end;
1398 TRIGGER_HEALTH:
1399 begin
1400 with ItemProps[InsertRow(_lc[I_PROP_TR_HEALTH], IntToStr(Data.HealValue), True)] do
1401 begin
1402 EditStyle := esSimple;
1403 MaxLength := 5;
1404 end;
1405 with ItemProps[InsertRow(_lc[I_PROP_TR_INTERVAL], IntToStr(Data.HealInterval), True)] do
1406 begin
1407 EditStyle := esSimple;
1408 MaxLength := 5;
1409 end;
1410 with ItemProps[InsertRow(_lc[I_PROP_TR_HEALTH_MAX], BoolNames[Data.HealMax], True)] do
1411 begin
1412 EditStyle := esPickList;
1413 ReadOnly := True;
1414 end;
1415 with ItemProps[InsertRow(_lc[I_PROP_TR_SILENT], BoolNames[Data.HealSilent], True)] do
1416 begin
1417 EditStyle := esPickList;
1418 ReadOnly := True;
1419 end;
1420 end;
1422 TRIGGER_SHOT:
1423 begin
1424 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_TYPE], ShotToStr(Data.ShotType), True)] do
1425 begin
1426 EditStyle := esEllipsis;
1427 ReadOnly := True;
1428 end;
1430 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_SOUND], BoolNames[Data.ShotSound], True)] do
1431 begin
1432 EditStyle := esPickList;
1433 ReadOnly := True;
1434 end;
1436 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_PANEL], IntToStr(Data.ShotPanelID), True)] do
1437 begin
1438 EditStyle := esEllipsis;
1439 ReadOnly := True;
1440 end;
1442 case Data.ShotTarget of
1443 1: str := _lc[I_PROP_TR_SHOT_TO_1];
1444 2: str := _lc[I_PROP_TR_SHOT_TO_2];
1445 3: str := _lc[I_PROP_TR_SHOT_TO_3];
1446 4: str := _lc[I_PROP_TR_SHOT_TO_4];
1447 5: str := _lc[I_PROP_TR_SHOT_TO_5];
1448 6: str := _lc[I_PROP_TR_SHOT_TO_6];
1449 else str := _lc[I_PROP_TR_SHOT_TO_0];
1450 end;
1451 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_TO], str, True)] do
1452 begin
1453 EditStyle := esPickList;
1454 ReadOnly := True;
1455 end;
1457 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_SIGHT], IntToStr(Data.ShotIntSight), True)] do
1458 begin
1459 EditStyle := esSimple;
1460 MaxLength := 3;
1461 end;
1463 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_ALLMAP], BoolNames[Data.ShotAllMap], True)] do
1464 begin
1465 EditStyle := esPickList;
1466 ReadOnly := True;
1467 end;
1469 with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_TO],
1470 Format('(%d:%d)', [Data.ShotPos.X, Data.ShotPos.Y]), True)] do
1471 begin
1472 EditStyle := esEllipsis;
1473 ReadOnly := True;
1474 end;
1476 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_ANGLE], IntToStr(Data.ShotAngle), True)] do
1477 begin
1478 EditStyle := esSimple;
1479 MaxLength := 4;
1480 end;
1482 with ItemProps[InsertRow(_lc[I_PROP_TR_EX_DELAY], IntToStr(Data.ShotWait), True)] do
1483 begin
1484 EditStyle := esSimple;
1485 MaxLength := 5;
1486 end;
1488 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_ACC], IntToStr(Data.ShotAccuracy), True)] do
1489 begin
1490 EditStyle := esSimple;
1491 MaxLength := 5;
1492 end;
1494 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_AMMO], IntToStr(Data.ShotAmmo), True)] do
1495 begin
1496 EditStyle := esSimple;
1497 MaxLength := 5;
1498 end;
1500 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_RELOAD], IntToStr(Data.ShotIntReload), True)] do
1501 begin
1502 EditStyle := esSimple;
1503 MaxLength := 4;
1504 end;
1505 end;
1507 TRIGGER_EFFECT:
1508 begin
1509 with ItemProps[InsertRow(_lc[I_PROP_TR_COUNT], IntToStr(Data.FXCount), True)] do
1510 begin
1511 EditStyle := esSimple;
1512 MaxLength := 3;
1513 end;
1515 if Data.FXType = 0 then
1516 str := _lc[I_PROP_TR_EFFECT_PARTICLE]
1517 else
1518 str := _lc[I_PROP_TR_EFFECT_ANIMATION];
1519 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_TYPE], str, True)] do
1520 begin
1521 EditStyle := esEllipsis;
1522 ReadOnly := True;
1523 end;
1525 str := '';
1526 if Data.FXType = 0 then
1527 case Data.FXSubType of
1528 TRIGGER_EFFECT_SLIQUID:
1529 str := _lc[I_PROP_TR_EFFECT_SLIQUID];
1530 TRIGGER_EFFECT_LLIQUID:
1531 str := _lc[I_PROP_TR_EFFECT_LLIQUID];
1532 TRIGGER_EFFECT_DLIQUID:
1533 str := _lc[I_PROP_TR_EFFECT_DLIQUID];
1534 TRIGGER_EFFECT_BLOOD:
1535 str := _lc[I_PROP_TR_EFFECT_BLOOD];
1536 TRIGGER_EFFECT_SPARK:
1537 str := _lc[I_PROP_TR_EFFECT_SPARK];
1538 TRIGGER_EFFECT_BUBBLE:
1539 str := _lc[I_PROP_TR_EFFECT_BUBBLE];
1540 end;
1541 if Data.FXType = 1 then
1542 begin
1543 if (Data.FXSubType = 0) or (Data.FXSubType > EFFECT_FIRE) then
1544 Data.FXSubType := EFFECT_TELEPORT;
1545 str := EffectToStr(Data.FXSubType);
1546 end;
1547 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_SUBTYPE], str, True)] do
1548 begin
1549 EditStyle := esEllipsis;
1550 ReadOnly := True;
1551 end;
1553 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_COLOR], IntToStr(Data.FXColorR or (Data.FXColorG shl 8) or (Data.FXColorB shl 16)), True)] do
1554 begin
1555 EditStyle := esEllipsis;
1556 ReadOnly := True;
1557 end;
1559 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_CENTER], BoolNames[Data.FXPos = 0], True)] do
1560 begin
1561 EditStyle := esPickList;
1562 ReadOnly := True;
1563 end;
1565 with ItemProps[InsertRow(_lc[I_PROP_TR_EX_DELAY], IntToStr(Data.FXWait), True)] do
1566 begin
1567 EditStyle := esSimple;
1568 MaxLength := 5;
1569 end;
1571 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_VELX], IntToStr(Data.FXVelX), True)] do
1572 begin
1573 EditStyle := esSimple;
1574 MaxLength := 4;
1575 end;
1577 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_VELY], IntToStr(Data.FXVelY), True)] do
1578 begin
1579 EditStyle := esSimple;
1580 MaxLength := 4;
1581 end;
1583 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_SPL], IntToStr(Data.FXSpreadL), True)] do
1584 begin
1585 EditStyle := esSimple;
1586 MaxLength := 3;
1587 end;
1589 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_SPR], IntToStr(Data.FXSpreadR), True)] do
1590 begin
1591 EditStyle := esSimple;
1592 MaxLength := 3;
1593 end;
1595 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_SPU], IntToStr(Data.FXSpreadU), True)] do
1596 begin
1597 EditStyle := esSimple;
1598 MaxLength := 3;
1599 end;
1601 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_SPD], IntToStr(Data.FXSpreadD), True)] do
1602 begin
1603 EditStyle := esSimple;
1604 MaxLength := 3;
1605 end;
1606 end;
1607 end; //case TriggerType
1608 end;
1609 end; // OBJECT_TRIGGER:
1610 end;
1611 end;
1613 procedure ChangeShownProperty(Name: String; NewValue: String);
1614 var
1615 row: Integer;
1616 begin
1617 if SelectedObjectCount() <> 1 then
1618 Exit;
1619 if not SelectedObjects[GetFirstSelected()].Live then
1620 Exit;
1622 // Есть ли такой ключ:
1623 if MainForm.vleObjectProperty.FindRow(Name, row) then
1624 begin
1625 MainForm.vleObjectProperty.Values[Name] := NewValue;
1626 end;
1627 end;
1629 procedure SelectObject(fObjectType: Byte; fID: DWORD; Multi: Boolean);
1630 var
1631 a: Integer;
1632 b: Boolean;
1633 begin
1634 if Multi then
1635 begin
1636 b := False;
1638 // Уже выделен - убираем:
1639 if SelectedObjects <> nil then
1640 for a := 0 to High(SelectedObjects) do
1641 with SelectedObjects[a] do
1642 if Live and (ID = fID) and
1643 (ObjectType = fObjectType) then
1644 begin
1645 Live := False;
1646 b := True;
1647 end;
1649 if b then
1650 Exit;
1652 SetLength(SelectedObjects, Length(SelectedObjects)+1);
1654 with SelectedObjects[High(SelectedObjects)] do
1655 begin
1656 ObjectType := fObjectType;
1657 ID := fID;
1658 Live := True;
1659 end;
1660 end
1661 else // not Multi
1662 begin
1663 SetLength(SelectedObjects, 1);
1665 with SelectedObjects[0] do
1666 begin
1667 ObjectType := fObjectType;
1668 ID := fID;
1669 Live := True;
1670 end;
1671 end;
1673 MainForm.miCopy.Enabled := True;
1674 MainForm.miCut.Enabled := True;
1676 if fObjectType = OBJECT_PANEL then
1677 begin
1678 MainForm.miToFore.Enabled := True;
1679 MainForm.miToBack.Enabled := True;
1680 end;
1681 end;
1683 procedure RemoveSelectFromObjects();
1684 begin
1685 SelectedObjects := nil;
1686 DrawPressRect := False;
1687 MouseLDown := False;
1688 MouseRDown := False;
1689 MouseAction := MOUSEACTION_NONE;
1690 SelectFlag := SELECTFLAG_NONE;
1691 ResizeType := RESIZETYPE_NONE;
1692 ResizeDirection := RESIZEDIR_NONE;
1694 MainForm.vleObjectProperty.Strings.Clear();
1696 MainForm.miCopy.Enabled := False;
1697 MainForm.miCut.Enabled := False;
1698 MainForm.miToFore.Enabled := False;
1699 MainForm.miToBack.Enabled := False;
1700 end;
1702 procedure DeleteSelectedObjects();
1703 var
1704 i, a, ii: Integer;
1705 b: Boolean;
1706 begin
1707 if SelectedObjects = nil then
1708 Exit;
1710 b := False;
1711 i := 0;
1713 for a := 0 to High(SelectedObjects) do
1714 with SelectedObjects[a] do
1715 if Live then
1716 begin
1717 if not b then
1718 begin
1719 SetLength(UndoBuffer, Length(UndoBuffer)+1);
1720 i := High(UndoBuffer);
1721 b := True;
1722 end;
1724 SetLength(UndoBuffer[i], Length(UndoBuffer[i])+1);
1725 ii := High(UndoBuffer[i]);
1727 case ObjectType of
1728 OBJECT_PANEL:
1729 begin
1730 UndoBuffer[i, ii].UndoType := UNDO_DELETE_PANEL;
1731 New(UndoBuffer[i, ii].Panel);
1732 UndoBuffer[i, ii].Panel^ := gPanels[ID];
1733 end;
1734 OBJECT_ITEM:
1735 begin
1736 UndoBuffer[i, ii].UndoType := UNDO_DELETE_ITEM;
1737 UndoBuffer[i, ii].Item := gItems[ID];
1738 end;
1739 OBJECT_AREA:
1740 begin
1741 UndoBuffer[i, ii].UndoType := UNDO_DELETE_AREA;
1742 UndoBuffer[i, ii].Area := gAreas[ID];
1743 end;
1744 OBJECT_TRIGGER:
1745 begin
1746 UndoBuffer[i, ii].UndoType := UNDO_DELETE_TRIGGER;
1747 UndoBuffer[i, ii].Trigger := gTriggers[ID];
1748 end;
1749 end;
1751 RemoveObject(ID, ObjectType);
1752 end;
1754 RemoveSelectFromObjects();
1756 MainForm.miUndo.Enabled := UndoBuffer <> nil;
1757 end;
1759 procedure Undo_Add(ObjectType: Byte; ID: DWORD; Group: Boolean = False);
1760 var
1761 i, ii: Integer;
1762 begin
1763 if (not Group) or (Length(UndoBuffer) = 0) then
1764 SetLength(UndoBuffer, Length(UndoBuffer)+1);
1765 SetLength(UndoBuffer[High(UndoBuffer)], Length(UndoBuffer[High(UndoBuffer)])+1);
1766 i := High(UndoBuffer);
1767 ii := High(UndoBuffer[i]);
1769 case ObjectType of
1770 OBJECT_PANEL:
1771 UndoBuffer[i, ii].UndoType := UNDO_ADD_PANEL;
1772 OBJECT_ITEM:
1773 UndoBuffer[i, ii].UndoType := UNDO_ADD_ITEM;
1774 OBJECT_MONSTER:
1775 UndoBuffer[i, ii].UndoType := UNDO_ADD_MONSTER;
1776 OBJECT_AREA:
1777 UndoBuffer[i, ii].UndoType := UNDO_ADD_AREA;
1778 OBJECT_TRIGGER:
1779 UndoBuffer[i, ii].UndoType := UNDO_ADD_TRIGGER;
1780 end;
1782 UndoBuffer[i, ii].AddID := ID;
1784 MainForm.miUndo.Enabled := UndoBuffer <> nil;
1785 end;
1787 procedure FullClear();
1788 begin
1789 RemoveSelectFromObjects();
1790 ClearMap();
1791 UndoBuffer := nil;
1792 slInvalidTextures.Clear();
1793 MapCheckForm.lbErrorList.Clear();
1794 MapCheckForm.mErrorDescription.Clear();
1796 MainForm.miUndo.Enabled := False;
1797 MainForm.sbHorizontal.Position := 0;
1798 MainForm.sbVertical.Position := 0;
1799 MainForm.FormResize(nil);
1800 MainForm.Caption := FormCaption;
1801 OpenedMap := '';
1802 OpenedWAD := '';
1803 end;
1805 procedure ErrorMessageBox(str: String);
1806 begin
1807 MessageBox(0, PChar(str), PChar(_lc[I_MSG_ERROR]),
1808 MB_ICONINFORMATION or MB_OK or MB_DEFBUTTON1);
1809 end;
1811 function CheckProperty(): Boolean;
1812 var
1813 _id: Integer;
1814 begin
1815 Result := False;
1817 _id := GetFirstSelected();
1819 if SelectedObjects[_id].ObjectType = OBJECT_PANEL then
1820 with gPanels[SelectedObjects[_id].ID] do
1821 begin
1822 if TextureWidth <> 0 then
1823 if StrToIntDef(MainForm.vleObjectProperty.Values[_lc[I_PROP_WIDTH]], 1) mod TextureWidth <> 0 then
1824 begin
1825 ErrorMessageBox(Format(_lc[I_MSG_WRONG_TEXWIDTH],
1826 [TextureWidth]));
1827 Exit;
1828 end;
1830 if TextureHeight <> 0 then
1831 if StrToIntDef(Trim(MainForm.vleObjectProperty.Values[_lc[I_PROP_HEIGHT]]), 1) mod TextureHeight <> 0 then
1832 begin
1833 ErrorMessageBox(Format(_lc[I_MSG_WRONG_TEXHEIGHT],
1834 [TextureHeight]));
1835 Exit;
1836 end;
1838 if IsTexturedPanel(PanelType) and (TextureName <> '') then
1839 if not (StrToIntDef(MainForm.vleObjectProperty.Values[_lc[I_PROP_PANEL_ALPHA]], -1) in [0..255]) then
1840 begin
1841 ErrorMessageBox(_lc[I_MSG_WRONG_ALPHA]);
1842 Exit;
1843 end;
1844 end;
1846 if SelectedObjects[_id].ObjectType in [OBJECT_PANEL, OBJECT_TRIGGER] then
1847 if (StrToIntDef(MainForm.vleObjectProperty.Values[_lc[I_PROP_WIDTH]], 0) <= 0) or
1848 (StrToIntDef(MainForm.vleObjectProperty.Values[_lc[I_PROP_HEIGHT]], 0) <= 0) then
1849 begin
1850 ErrorMessageBox(_lc[I_MSG_WRONG_SIZE]);
1851 Exit;
1852 end;
1854 if (Trim(MainForm.vleObjectProperty.Values[_lc[I_PROP_X]]) = '') or
1855 (Trim(MainForm.vleObjectProperty.Values[_lc[I_PROP_Y]]) = '') then
1856 begin
1857 ErrorMessageBox(_lc[I_MSG_WRONG_XY]);
1858 Exit;
1859 end;
1861 Result := True;
1862 end;
1864 procedure SelectTexture(ID: Integer);
1865 begin
1866 MainForm.lbTextureList.ItemIndex := ID;
1867 MainForm.lbTextureListClick(nil);
1868 end;
1870 function AddTexture(aWAD, aSection, aTex: String; silent: Boolean): Boolean;
1871 var
1872 a: Integer;
1873 ok: Boolean;
1874 FileName: String;
1875 ResourceName: String;
1876 FullResourceName: String;
1877 SectionName: String;
1878 Data: Pointer;
1879 Width, Height: Word;
1880 fn: String;
1881 begin
1882 if aSection = '..' then
1883 SectionName := ''
1884 else
1885 SectionName := aSection;
1887 if aWAD = _lc[I_WAD_SPECIAL_MAP] then
1888 begin // Файл карты
1889 g_ProcessResourceStr(OpenedMap, @fn, nil, nil);
1890 //FileName := EditorDir+'maps\'+ExtractFileName(fn);
1891 FileName := fn;
1892 ResourceName := ':'+SectionName+'\'+aTex;
1893 end
1894 else
1895 if aWAD = _lc[I_WAD_SPECIAL_TEXS] then
1896 begin // Спец. текстуры
1897 FileName := '';
1898 ResourceName := aTex;
1899 end
1900 else
1901 begin // Внешний WAD
1902 FileName := EditorDir+'wads\'+aWAD;
1903 ResourceName := aWAD+':'+SectionName+'\'+aTex;
1904 end;
1906 ok := True;
1908 // Есть ли уже такая текстура:
1909 for a := 0 to MainForm.lbTextureList.Items.Count-1 do
1910 if ResourceName = MainForm.lbTextureList.Items[a] then
1911 begin
1912 if not silent then
1913 ErrorMessageBox(Format(_lc[I_MSG_TEXTURE_ALREADY],
1914 [ResourceName]));
1915 ok := False;
1916 end;
1918 // Название ресурса <= 64 символов:
1919 if Length(ResourceName) > 64 then
1920 begin
1921 if not silent then
1922 ErrorMessageBox(Format(_lc[I_MSG_RES_NAME_64],
1923 [ResourceName]));
1924 ok := False;
1925 end;
1927 if ok then
1928 begin
1929 a := -1;
1930 if aWAD = _lc[I_WAD_SPECIAL_TEXS] then
1931 begin
1932 a := MainForm.lbTextureList.Items.Add(ResourceName);
1933 if not silent then
1934 SelectTexture(a);
1935 Result := True;
1936 Exit;
1937 end;
1939 FullResourceName := FileName+':'+SectionName+'\'+aTex;
1941 if IsAnim(FullResourceName) then
1942 begin // Аним. текстура
1943 GetFrame(FullResourceName, Data, Width, Height);
1945 if g_CreateTextureMemorySize(Data, ResourceName, 0, 0, Width, Height, 1) then
1946 a := MainForm.lbTextureList.Items.Add(ResourceName);
1947 end
1948 else // Обычная текстура
1949 begin
1950 if g_CreateTextureWAD(ResourceName, FullResourceName) then
1951 a := MainForm.lbTextureList.Items.Add(ResourceName);
1952 end;
1953 if (a > -1) and (not silent) then
1954 SelectTexture(a);
1955 end;
1957 Result := ok;
1958 end;
1960 procedure UpdateCaption(sMap, sFile, sRes: String);
1961 begin
1962 with MainForm do
1963 if (sFile = '') and (sRes = '') and (sMap = '') then
1964 Caption := FormCaption
1965 else
1966 if sMap = '' then
1967 Caption := Format('%s - %s:%s', [FormCaption, sFile, sRes])
1968 else
1969 if (sFile <> '') and (sRes <> '') then
1970 Caption := Format('%s - %s (%s:%s)', [FormCaption, sMap, sFile, sRes])
1971 else
1972 Caption := Format('%s - %s', [FormCaption, sMap]);
1973 end;
1975 procedure OpenMap(FileName: String; mapN: String);
1976 var
1977 MapName: String;
1978 idx: Integer;
1979 begin
1980 SelectMapForm.GetMaps(FileName);
1982 if (FileName = OpenedWAD) and
1983 (OpenedMap <> '') then
1984 begin
1985 MapName := OpenedMap;
1986 while (Pos(':\', MapName) > 0) do
1987 Delete(MapName, 1, Pos(':\', MapName) + 1);
1989 idx := SelectMapForm.lbMapList.Items.IndexOf(MapName);
1990 SelectMapForm.lbMapList.ItemIndex := idx;
1991 end
1992 else
1993 if SelectMapForm.lbMapList.Count > 0 then
1994 SelectMapForm.lbMapList.ItemIndex := 0
1995 else
1996 SelectMapForm.lbMapList.ItemIndex := -1;
1998 if mapN = '' then
1999 idx := -1
2000 else
2001 idx := SelectMapForm.lbMapList.Items.IndexOf(mapN);
2003 if idx < 0 then
2004 begin
2005 if (SelectMapForm.ShowModal() = mrOK) and
2006 (SelectMapForm.lbMapList.ItemIndex <> -1) then
2007 idx := SelectMapForm.lbMapList.ItemIndex
2008 else
2009 Exit;
2010 end;
2012 MapName := SelectMapForm.lbMapList.Items[idx];
2014 with MainForm do
2015 begin
2016 FullClear();
2018 pLoadProgress.Left := (RenderPanel.Width div 2)-(pLoadProgress.Width div 2);
2019 pLoadProgress.Top := (RenderPanel.Height div 2)-(pLoadProgress.Height div 2);
2020 pLoadProgress.Show();
2022 OpenedMap := FileName+':\'+MapName;
2023 OpenedWAD := FileName;
2025 idx := RecentFiles.IndexOf(OpenedMap);
2026 // Такая карта уже недавно открывалась:
2027 if idx >= 0 then
2028 RecentFiles.Delete(idx);
2029 RecentFiles.Insert(0, OpenedMap);
2030 RefreshRecentMenu();
2032 LoadMap(OpenedMap);
2034 pLoadProgress.Hide();
2035 FormResize(nil);
2037 lbTextureList.Sorted := True;
2038 lbTextureList.Sorted := False;
2040 UpdateCaption(gMapInfo.Name, ExtractFileName(FileName), MapName);
2041 end;
2042 end;
2044 procedure MoveSelectedObjects(Wall, alt: Boolean; dx, dy: Integer);
2045 var
2046 okX, okY: Boolean;
2047 a: Integer;
2048 begin
2049 if SelectedObjects = nil then
2050 Exit;
2052 okX := True;
2053 okY := True;
2055 if Wall then
2056 for a := 0 to High(SelectedObjects) do
2057 if SelectedObjects[a].Live then
2058 begin
2059 if ObjectCollideLevel(SelectedObjects[a].ID, SelectedObjects[a].ObjectType, dx, 0) then
2060 okX := False;
2062 if ObjectCollideLevel(SelectedObjects[a].ID, SelectedObjects[a].ObjectType, 0, dy) then
2063 okY := False;
2065 if (not okX) or (not okY) then
2066 Break;
2067 end;
2069 if okX or okY then
2070 begin
2071 for a := 0 to High(SelectedObjects) do
2072 if SelectedObjects[a].Live then
2073 begin
2074 if okX then
2075 MoveObject(SelectedObjects[a].ObjectType, SelectedObjects[a].ID, dx, 0);
2077 if okY then
2078 MoveObject(SelectedObjects[a].ObjectType, SelectedObjects[a].ID, 0, dy);
2080 if alt and (SelectedObjects[a].ObjectType = OBJECT_TRIGGER) then
2081 begin
2082 if gTriggers[SelectedObjects[a].ID].TriggerType in [TRIGGER_PRESS,
2083 TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF] then
2084 begin // Двигаем зону Расширителя
2085 if okX then
2086 gTriggers[SelectedObjects[a].ID].Data.tX := gTriggers[SelectedObjects[a].ID].Data.tX+dx;
2087 if okY then
2088 gTriggers[SelectedObjects[a].ID].Data.tY := gTriggers[SelectedObjects[a].ID].Data.tY+dy;
2089 end;
2091 if gTriggers[SelectedObjects[a].ID].TriggerType in [TRIGGER_TELEPORT] then
2092 begin // Двигаем точку назначения Телепорта
2093 if okX then
2094 gTriggers[SelectedObjects[a].ID].Data.TargetPoint.X := gTriggers[SelectedObjects[a].ID].Data.TargetPoint.X+dx;
2095 if okY then
2096 gTriggers[SelectedObjects[a].ID].Data.TargetPoint.Y := gTriggers[SelectedObjects[a].ID].Data.TargetPoint.Y+dy;
2097 end;
2099 if gTriggers[SelectedObjects[a].ID].TriggerType in [TRIGGER_SPAWNMONSTER] then
2100 begin // Двигаем точку создания монстра
2101 if okX then
2102 gTriggers[SelectedObjects[a].ID].Data.MonPos.X := gTriggers[SelectedObjects[a].ID].Data.MonPos.X+dx;
2103 if okY then
2104 gTriggers[SelectedObjects[a].ID].Data.MonPos.Y := gTriggers[SelectedObjects[a].ID].Data.MonPos.Y+dy;
2105 end;
2107 if gTriggers[SelectedObjects[a].ID].TriggerType in [TRIGGER_SPAWNITEM] then
2108 begin // Двигаем точку создания предмета
2109 if okX then
2110 gTriggers[SelectedObjects[a].ID].Data.ItemPos.X := gTriggers[SelectedObjects[a].ID].Data.ItemPos.X+dx;
2111 if okY then
2112 gTriggers[SelectedObjects[a].ID].Data.ItemPos.Y := gTriggers[SelectedObjects[a].ID].Data.ItemPos.Y+dy;
2113 end;
2115 if gTriggers[SelectedObjects[a].ID].TriggerType in [TRIGGER_SHOT] then
2116 begin // Двигаем точку создания выстрела
2117 if okX then
2118 gTriggers[SelectedObjects[a].ID].Data.ShotPos.X := gTriggers[SelectedObjects[a].ID].Data.ShotPos.X+dx;
2119 if okY then
2120 gTriggers[SelectedObjects[a].ID].Data.ShotPos.Y := gTriggers[SelectedObjects[a].ID].Data.ShotPos.Y+dy;
2121 end;
2122 end;
2123 end;
2125 LastMovePoint := MousePos;
2126 end;
2127 end;
2129 procedure ShowLayer(Layer: Byte; show: Boolean);
2130 begin
2131 LayerEnabled[Layer] := show;
2133 case Layer of
2134 LAYER_BACK:
2135 begin
2136 MainForm.miLayer1.Checked := show;
2137 MainForm.miLayerP1.Checked := show;
2138 end;
2139 LAYER_WALLS:
2140 begin
2141 MainForm.miLayer2.Checked := show;
2142 MainForm.miLayerP2.Checked := show;
2143 end;
2144 LAYER_FOREGROUND:
2145 begin
2146 MainForm.miLayer3.Checked := show;
2147 MainForm.miLayerP3.Checked := show;
2148 end;
2149 LAYER_STEPS:
2150 begin
2151 MainForm.miLayer4.Checked := show;
2152 MainForm.miLayerP4.Checked := show;
2153 end;
2154 LAYER_WATER:
2155 begin
2156 MainForm.miLayer5.Checked := show;
2157 MainForm.miLayerP5.Checked := show;
2158 end;
2159 LAYER_ITEMS:
2160 begin
2161 MainForm.miLayer6.Checked := show;
2162 MainForm.miLayerP6.Checked := show;
2163 end;
2164 LAYER_MONSTERS:
2165 begin
2166 MainForm.miLayer7.Checked := show;
2167 MainForm.miLayerP7.Checked := show;
2168 end;
2169 LAYER_AREAS:
2170 begin
2171 MainForm.miLayer8.Checked := show;
2172 MainForm.miLayerP8.Checked := show;
2173 end;
2174 LAYER_TRIGGERS:
2175 begin
2176 MainForm.miLayer9.Checked := show;
2177 MainForm.miLayerP9.Checked := show;
2178 end;
2179 end;
2181 RemoveSelectFromObjects();
2182 end;
2184 procedure SwitchLayer(Layer: Byte);
2185 begin
2186 ShowLayer(Layer, not LayerEnabled[Layer]);
2187 end;
2189 procedure SwitchMap();
2190 begin
2191 ShowMap := not ShowMap;
2192 MainForm.tbShowMap.Down := ShowMap;
2193 end;
2195 procedure ShowEdges();
2196 begin
2197 if drEdge[3] < 255 then
2198 drEdge[3] := 255
2199 else
2200 drEdge[3] := gAlphaEdge;
2201 end;
2203 function SelectedTexture(): String;
2204 begin
2205 if MainForm.lbTextureList.ItemIndex <> -1 then
2206 Result := MainForm.lbTextureList.Items[MainForm.lbTextureList.ItemIndex]
2207 else
2208 Result := '';
2209 end;
2211 function IsSpecialTextureSel(): Boolean;
2212 begin
2213 Result := (MainForm.lbTextureList.ItemIndex <> -1) and
2214 IsSpecialTexture(MainForm.lbTextureList.Items[MainForm.lbTextureList.ItemIndex]);
2215 end;
2217 function CopyBufferToString(var CopyBuf: TCopyRecArray): String;
2218 var
2219 i, j: Integer;
2220 Res: String;
2222 procedure AddInt(x: Integer);
2223 begin
2224 Res := Res + IntToStr(x) + ' ';
2225 end;
2227 begin
2228 Result := '';
2230 if Length(CopyBuf) = 0 then
2231 Exit;
2233 Res := CLIPBOARD_SIG + ' ';
2235 for i := 0 to High(CopyBuf) do
2236 begin
2237 if (CopyBuf[i].ObjectType = OBJECT_PANEL) and
2238 (CopyBuf[i].Panel = nil) then
2239 Continue;
2241 // Тип объекта:
2242 AddInt(CopyBuf[i].ObjectType);
2243 Res := Res + '; ';
2245 // Свойства объекта:
2246 case CopyBuf[i].ObjectType of
2247 OBJECT_PANEL:
2248 with CopyBuf[i].Panel^ do
2249 begin
2250 AddInt(PanelType);
2251 AddInt(X);
2252 AddInt(Y);
2253 AddInt(Width);
2254 AddInt(Height);
2255 Res := Res + '"' + TextureName + '" ';
2256 AddInt(Alpha);
2257 AddInt(IfThen(Blending, 1, 0));
2258 end;
2260 OBJECT_ITEM:
2261 with CopyBuf[i].Item do
2262 begin
2263 AddInt(ItemType);
2264 AddInt(X);
2265 AddInt(Y);
2266 AddInt(IfThen(OnlyDM, 1, 0));
2267 AddInt(IfThen(Fall, 1, 0));
2268 end;
2270 OBJECT_MONSTER:
2271 with CopyBuf[i].Monster do
2272 begin
2273 AddInt(MonsterType);
2274 AddInt(X);
2275 AddInt(Y);
2276 AddInt(IfThen(Direction = D_LEFT, 1, 0));
2277 end;
2279 OBJECT_AREA:
2280 with CopyBuf[i].Area do
2281 begin
2282 AddInt(AreaType);
2283 AddInt(X);
2284 AddInt(Y);
2285 AddInt(IfThen(Direction = D_LEFT, 1, 0));
2286 end;
2288 OBJECT_TRIGGER:
2289 with CopyBuf[i].Trigger do
2290 begin
2291 AddInt(TriggerType);
2292 AddInt(X);
2293 AddInt(Y);
2294 AddInt(Width);
2295 AddInt(Height);
2296 AddInt(ActivateType);
2297 AddInt(Key);
2298 AddInt(IfThen(Enabled, 1, 0));
2299 AddInt(TexturePanel);
2301 for j := 0 to 127 do
2302 AddInt(Data.Default[j]);
2303 end;
2304 end;
2305 end;
2307 Result := Res;
2308 end;
2310 procedure StringToCopyBuffer(Str: String; var CopyBuf: TCopyRecArray);
2311 var
2312 i, j, t: Integer;
2314 function GetNext(): String;
2315 var
2316 p: Integer;
2318 begin
2319 if Str[1] = '"' then
2320 begin
2321 Delete(Str, 1, 1);
2322 p := Pos('"', Str);
2324 if p = 0 then
2325 begin
2326 Result := Str;
2327 Str := '';
2328 end
2329 else
2330 begin
2331 Result := Copy(Str, 1, p-1);
2332 Delete(Str, 1, p);
2333 Str := Trim(Str);
2334 end;
2335 end
2336 else
2337 begin
2338 p := Pos(' ', Str);
2340 if p = 0 then
2341 begin
2342 Result := Str;
2343 Str := '';
2344 end
2345 else
2346 begin
2347 Result := Copy(Str, 1, p-1);
2348 Delete(Str, 1, p);
2349 Str := Trim(Str);
2350 end;
2351 end;
2352 end;
2354 begin
2355 Str := Trim(Str);
2357 if GetNext() <> CLIPBOARD_SIG then
2358 Exit;
2360 while Str <> '' do
2361 begin
2362 // Тип объекта:
2363 t := StrToIntDef(GetNext(), 0);
2365 if (t < OBJECT_PANEL) or (t > OBJECT_TRIGGER) or
2366 (GetNext() <> ';') then
2367 begin // Что-то не то => пропускаем:
2368 t := Pos(';', Str);
2369 Delete(Str, 1, t);
2370 Str := Trim(Str);
2372 Continue;
2373 end;
2375 i := Length(CopyBuf);
2376 SetLength(CopyBuf, i + 1);
2378 CopyBuf[i].ObjectType := t;
2379 CopyBuf[i].Panel := nil;
2381 // Свойства объекта:
2382 case t of
2383 OBJECT_PANEL:
2384 begin
2385 New(CopyBuf[i].Panel);
2387 with CopyBuf[i].Panel^ do
2388 begin
2389 PanelType := StrToIntDef(GetNext(), PANEL_WALL);
2390 X := StrToIntDef(GetNext(), 0);
2391 Y := StrToIntDef(GetNext(), 0);
2392 Width := StrToIntDef(GetNext(), 16);
2393 Height := StrToIntDef(GetNext(), 16);
2394 TextureName := GetNext();
2395 Alpha := StrToIntDef(GetNext(), 0);
2396 Blending := (GetNext() = '1');
2397 end;
2398 end;
2400 OBJECT_ITEM:
2401 with CopyBuf[i].Item do
2402 begin
2403 ItemType := StrToIntDef(GetNext(), ITEM_MEDKIT_SMALL);
2404 X := StrToIntDef(GetNext(), 0);
2405 Y := StrToIntDef(GetNext(), 0);
2406 OnlyDM := (GetNext() = '1');
2407 Fall := (GetNext() = '1');
2408 end;
2410 OBJECT_MONSTER:
2411 with CopyBuf[i].Monster do
2412 begin
2413 MonsterType := StrToIntDef(GetNext(), MONSTER_DEMON);
2414 X := StrToIntDef(GetNext(), 0);
2415 Y := StrToIntDef(GetNext(), 0);
2417 if GetNext() = '1' then
2418 Direction := D_LEFT
2419 else
2420 Direction := D_RIGHT;
2421 end;
2423 OBJECT_AREA:
2424 with CopyBuf[i].Area do
2425 begin
2426 AreaType := StrToIntDef(GetNext(), AREA_PLAYERPOINT1);
2427 X := StrToIntDef(GetNext(), 0);
2428 Y := StrToIntDef(GetNext(), 0);
2429 if GetNext() = '1' then
2430 Direction := D_LEFT
2431 else
2432 Direction := D_RIGHT;
2433 end;
2435 OBJECT_TRIGGER:
2436 with CopyBuf[i].Trigger do
2437 begin
2438 TriggerType := StrToIntDef(GetNext(), TRIGGER_EXIT);
2439 X := StrToIntDef(GetNext(), 0);
2440 Y := StrToIntDef(GetNext(), 0);
2441 Width := StrToIntDef(GetNext(), 16);
2442 Height := StrToIntDef(GetNext(), 16);
2443 ActivateType := StrToIntDef(GetNext(), 0);
2444 Key := StrToIntDef(GetNext(), 0);
2445 Enabled := (GetNext() = '1');
2446 TexturePanel := StrToIntDef(GetNext(), 0);
2448 for j := 0 to 127 do
2449 Data.Default[j] := StrToIntDef(GetNext(), 0);
2450 end;
2451 end;
2452 end;
2453 end;
2455 //----------------------------------------
2456 //Закончились вспомогательные процедуры
2457 //----------------------------------------
2459 procedure TMainForm.RefreshRecentMenu();
2460 var
2461 i: Integer;
2462 MI: TMenuItem;
2463 begin
2464 // Лишние запомненные карты:
2465 while RecentFiles.Count > RecentCount do
2466 RecentFiles.Delete(RecentFiles.Count-1);
2468 // Лишние строки меню:
2469 while MainMenu.Items[0].Count > RECENT_FILES_MENU_START do
2470 MainMenu.Items[0].Delete(MainMenu.Items[0].Count-1);
2472 // Отделение списка карт от строки "Выход":
2473 if RecentFiles.Count > 0 then
2474 begin
2475 MI := TMenuItem.Create(MainMenu.Items[0]);
2476 MI.Caption := '-';
2477 MainMenu.Items[0].Add(MI);
2478 end;
2480 // Добавление в меню списка запомненных карт:
2481 for i := 0 to RecentFiles.Count-1 do
2482 begin
2483 MI := TMenuItem.Create(MainMenu.Items[0]);
2484 MI.Caption := IntToStr(i+1) + ' ' + RecentFiles[i];
2485 MI.OnClick := aRecentFileExecute;
2486 MainMenu.Items[0].Add(MI);
2487 end;
2488 end;
2490 procedure TMainForm.aRecentFileExecute(Sender: TObject);
2491 var
2492 n, pw: Integer;
2493 s, fn: String;
2494 begin
2495 s := LowerCase((Sender as TMenuItem).Caption);
2496 Delete(s, Pos('&', s), 1);
2497 s := Trim(Copy(s, 1, 2));
2498 n := StrToIntDef(s, 0) - 1;
2500 if (n < 0) or (n >= RecentFiles.Count) then
2501 Exit;
2503 s := RecentFiles[n];
2504 pw := Pos('.wad:\', LowerCase(s));
2506 if pw > 0 then
2507 begin // Map name included
2508 fn := Copy(s, 1, pw + 3);
2509 Delete(s, 1, pw + 5);
2510 if (FileExists(fn)) then
2511 OpenMap(fn, s);
2512 end
2513 else // Only wad name
2514 if (FileExists(s)) then
2515 OpenMap(s, '');
2516 end;
2518 procedure TMainForm.aEditorOptionsExecute(Sender: TObject);
2519 begin
2520 OptionsForm.ShowModal();
2521 end;
2523 procedure TMainForm.FormCreate(Sender: TObject);
2524 var
2525 PixelFormat: GLuint;
2526 pfd: TPIXELFORMATDESCRIPTOR;
2527 config: TConfig;
2528 i: Integer;
2529 s: String;
2530 begin
2531 Randomize();
2533 EditorDir := ExtractFilePath(Application.ExeName);
2535 e_InitLog(EditorDir+'Editor.log', WM_NEWFILE);
2537 e_WriteLog('Init OpenGL', MSG_NOTIFY);
2539 InitOpenGL();
2540 hDC := GetDC(RenderPanel.Handle);
2542 FillChar(pfd, SizeOf(pfd), 0);
2543 with pfd do
2544 begin
2545 nSize := SizeOf(pfd);
2546 nVersion := 1;
2547 dwFlags := PFD_DRAW_TO_WINDOW or PFD_SUPPORT_OPENGL or PFD_DOUBLEBUFFER;
2548 dwLayerMask := PFD_MAIN_PLANE;
2549 iPixelType := PFD_TYPE_RGBA;
2550 cColorBits := 24;
2551 cDepthBits := 32;
2552 iLayerType := PFD_MAIN_PLANE;
2553 end;
2554 PixelFormat := ChoosePixelFormat (hDC, @pfd);
2555 SetPixelFormat(hDC, PixelFormat, @pfd);
2557 hRC := wglCreateContext(hDC);
2558 ActivateRenderingContext(hDC, hRC);
2560 e_InitGL(False);
2562 gEditorFont := e_SimpleFontCreate('Arial Cyr', 12, FW_BOLD, hDC);
2564 slInvalidTextures := TStringList.Create;
2566 e_WriteLog('Loading data', MSG_NOTIFY);
2567 LoadData();
2569 ShowLayer(LAYER_BACK, True);
2570 ShowLayer(LAYER_WALLS, True);
2571 ShowLayer(LAYER_FOREGROUND, True);
2572 ShowLayer(LAYER_STEPS, True);
2573 ShowLayer(LAYER_WATER, True);
2574 ShowLayer(LAYER_ITEMS, True);
2575 ShowLayer(LAYER_MONSTERS, True);
2576 ShowLayer(LAYER_AREAS, True);
2577 ShowLayer(LAYER_TRIGGERS, True);
2579 ClearMap();
2581 FormCaption := MainForm.Caption;
2582 OpenedMap := '';
2583 OpenedWAD := '';
2585 config := TConfig.CreateFile(EditorDir+'\Editor.cfg');
2587 if config.ReadBool('Editor', 'Maximize', False) then
2588 WindowState := wsMaximized;
2589 ShowMap := config.ReadBool('Editor', 'Minimap', False);
2590 PanelProps.Width := config.ReadInt('Editor', 'PanelProps', PanelProps.ClientWidth);
2591 Splitter1.Left := PanelProps.Left;
2592 PanelObjs.Height := config.ReadInt('Editor', 'PanelObjs', PanelObjs.ClientHeight);
2593 Splitter2.Top := PanelObjs.Top;
2594 StatusBar.Top := PanelObjs.BoundsRect.Bottom;
2595 DotEnable := config.ReadBool('Editor', 'DotEnable', True);
2596 DotColor := config.ReadInt('Editor', 'DotColor', $FFFFFF);
2597 DotStepOne := config.ReadInt('Editor', 'DotStepOne', 16);
2598 DotStepTwo := config.ReadInt('Editor', 'DotStepTwo', 8);
2599 DotStep := config.ReadInt('Editor', 'DotStep', DotStepOne);
2600 DrawTexturePanel := config.ReadBool('Editor', 'DrawTexturePanel', True);
2601 DrawPanelSize := config.ReadBool('Editor', 'DrawPanelSize', True);
2602 BackColor := config.ReadInt('Editor', 'BackColor', $7F6040);
2603 PreviewColor := config.ReadInt('Editor', 'PreviewColor', $00FF00);
2604 gColorEdge := config.ReadInt('Editor', 'EdgeColor', COLOR_EDGE);
2605 gAlphaEdge := config.ReadInt('Editor', 'EdgeAlpha', ALPHA_EDGE);
2606 if gAlphaEdge = 255 then
2607 gAlphaEdge := ALPHA_EDGE;
2608 drEdge[0] := GetRValue(gColorEdge);
2609 drEdge[1] := GetGValue(gColorEdge);
2610 drEdge[2] := GetBValue(gColorEdge);
2611 if not config.ReadBool('Editor', 'EdgeShow', True) then
2612 drEdge[3] := 255
2613 else
2614 drEdge[3] := gAlphaEdge;
2615 gAlphaTriggerLine := config.ReadInt('Editor', 'LineAlpha', ALPHA_LINE);
2616 if gAlphaTriggerLine = 255 then
2617 gAlphaTriggerLine := ALPHA_LINE;
2618 gAlphaTriggerArea := config.ReadInt('Editor', 'TriggerAlpha', ALPHA_AREA);
2619 if gAlphaTriggerArea = 255 then
2620 gAlphaTriggerArea := ALPHA_AREA;
2621 if config.ReadInt('Editor', 'Scale', 0) = 1 then
2622 Scale := 2
2623 else
2624 Scale := 1;
2625 if config.ReadInt('Editor', 'DotSize', 0) = 1 then
2626 DotSize := 2
2627 else
2628 DotSize := 1;
2629 OpenDialog.InitialDir := config.ReadStr('Editor', 'LastOpenDir', EditorDir);
2630 SaveDialog.InitialDir := config.ReadStr('Editor', 'LastSaveDir', EditorDir);
2632 s := config.ReadStr('Editor', 'Language', '');
2633 gLanguage := s;
2635 RecentCount := config.ReadInt('Editor', 'RecentCount', 5);
2636 if RecentCount > 10 then
2637 RecentCount := 10;
2638 if RecentCount < 2 then
2639 RecentCount := 2;
2641 RecentFiles := TStringList.Create();
2642 for i := 0 to RecentCount-1 do
2643 begin
2644 s := config.ReadStr('RecentFiles', IntToStr(i+1), '');
2645 if s <> '' then
2646 RecentFiles.Add(s);
2647 end;
2648 RefreshRecentMenu();
2650 config.Free();
2652 tbShowMap.Down := ShowMap;
2653 tbGridOn.Down := DotEnable;
2654 pcObjects.ActivePageIndex := 0;
2655 Application.Title := _lc[I_EDITOR_TITLE];
2657 Application.OnIdle := OnIdle;
2658 end;
2660 procedure TMainForm.Draw();
2661 var
2662 ps: TPaintStruct;
2663 x, y: Integer;
2664 a, b: Integer;
2665 ID: DWORD;
2666 Width, Height: Word;
2667 Rect: TRectWH;
2668 ObjCount: Word;
2669 aX, aY, aX2, aY2, XX, ScaleSz: Integer;
2670 begin
2671 BeginPaint(Handle, ps);
2672 e_BeginRender();
2674 e_Clear(GL_COLOR_BUFFER_BIT,
2675 GetRValue(BackColor)/255,
2676 GetGValue(BackColor)/255,
2677 GetBValue(BackColor)/255);
2679 DrawMap();
2681 ObjCount := SelectedObjectCount();
2683 // Обводим выделенные объекты красной рамкой:
2684 if ObjCount > 0 then
2685 begin
2686 for a := 0 to High(SelectedObjects) do
2687 if SelectedObjects[a].Live then
2688 begin
2689 Rect := ObjectGetRect(SelectedObjects[a].ObjectType, SelectedObjects[a].ID);
2691 with Rect do
2692 begin
2693 e_DrawQuad(X+MapOffset.X, Y+MapOffset.Y,
2694 X+MapOffset.X+Width-1, Y+MapOffset.Y+Height-1,
2695 255, 0, 0);
2697 // Рисуем точки изменения размеров:
2698 if (ObjCount = 1) and
2699 (SelectedObjects[GetFirstSelected].ObjectType in [OBJECT_PANEL, OBJECT_TRIGGER]) then
2700 begin
2701 e_DrawPoint(5, X+MapOffset.X, Y+MapOffset.Y+(Height div 2), 255, 255, 255);
2702 e_DrawPoint(5, X+MapOffset.X+Width-1, Y+MapOffset.Y+(Height div 2), 255, 255, 255);
2703 e_DrawPoint(5, X+MapOffset.X+(Width div 2), Y+MapOffset.Y, 255, 255, 255);
2704 e_DrawPoint(5, X+MapOffset.X+(Width div 2), Y+MapOffset.Y+Height-1, 255, 255, 255);
2706 e_DrawPoint(3, X+MapOffset.X, Y+MapOffset.Y+(Height div 2), 255, 0, 0);
2707 e_DrawPoint(3, X+MapOffset.X+Width-1, Y+MapOffset.Y+(Height div 2), 255, 0, 0);
2708 e_DrawPoint(3, X+MapOffset.X+(Width div 2), Y+MapOffset.Y, 255, 0, 0);
2709 e_DrawPoint(3, X+MapOffset.X+(Width div 2), Y+MapOffset.Y+Height-1, 255, 0, 0);
2710 end;
2711 end;
2712 end;
2713 end;
2715 // Рисуем сетку:
2716 if DotEnable and (not PreviewMode) then
2717 begin
2718 if DotSize = 2 then
2719 a := -1
2720 else
2721 a := 0;
2723 for x := 0 to (RenderPanel.Width div DotStep) do
2724 for y := 0 to (RenderPanel.Height div DotStep) do
2725 e_DrawPoint(DotSize, x*DotStep + a, y*DotStep + a,
2726 GetRValue(DotColor),
2727 GetGValue(DotColor),
2728 GetBValue(DotColor));
2729 end;
2731 // Превью текстуры:
2732 if (lbTextureList.ItemIndex <> -1) and (cbPreview.Checked) and
2733 (not IsSpecialTextureSel()) and (not PreviewMode) then
2734 begin
2735 if not g_GetTexture(SelectedTexture(), ID) then
2736 g_GetTexture('NOTEXTURE', ID);
2737 g_GetTextureSizeByID(ID, Width, Height);
2738 e_DrawFillQuad(RenderPanel.Width-Width-2, RenderPanel.Height-Height-2,
2739 RenderPanel.Width-1, RenderPanel.Height-1,
2740 GetRValue(PreviewColor), GetGValue(PreviewColor), GetBValue(PreviewColor), 0);
2741 e_Draw(ID, RenderPanel.Width-Width-1, RenderPanel.Height-Height-1, 0, True, False);
2742 end;
2744 // Подсказка при выборе точки Телепорта:
2745 if SelectFlag = SELECTFLAG_TELEPORT then
2746 begin
2747 with gTriggers[SelectedObjects[GetFirstSelected()].ID] do
2748 if Data.d2d_teleport then
2749 e_DrawLine(2, MousePos.X-16, MousePos.Y-1,
2750 MousePos.X+16, MousePos.Y-1,
2751 0, 0, 255)
2752 else
2753 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+AreaSize[AREA_DMPOINT].Width-1,
2754 MousePos.Y+AreaSize[AREA_DMPOINT].Height-1, 255, 255, 255);
2756 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 192, 192, 192, 127);
2757 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 255, 255, 255);
2758 e_SimpleFontPrint(MousePos.X+8, MousePos.Y+14, PChar(_lc[I_HINT_TELEPORT]), gEditorFont, 0, 0, 0);
2759 end;
2761 // Подсказка при выборе точки появления:
2762 if SelectFlag = SELECTFLAG_SPAWNPOINT then
2763 begin
2764 e_DrawLine(2, MousePos.X-16, MousePos.Y-1,
2765 MousePos.X+16, MousePos.Y-1,
2766 0, 0, 255);
2767 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 192, 192, 192, 127);
2768 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 255, 255, 255);
2769 e_SimpleFontPrint(MousePos.X+8, MousePos.Y+14, PChar(_lc[I_HINT_SPAWN]), gEditorFont, 0, 0, 0);
2770 end;
2772 // Подсказка при выборе панели двери:
2773 if SelectFlag = SELECTFLAG_DOOR then
2774 begin
2775 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 192, 192, 192, 127);
2776 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 255, 255, 255);
2777 e_SimpleFontPrint(MousePos.X+8, MousePos.Y+14, PChar(_lc[I_HINT_PANEL_DOOR]), gEditorFont, 0, 0, 0);
2778 end;
2780 // Подсказка при выборе панели с текстурой:
2781 if SelectFlag = SELECTFLAG_TEXTURE then
2782 begin
2783 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+196, MousePos.Y+18, 192, 192, 192, 127);
2784 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+196, MousePos.Y+18, 255, 255, 255);
2785 e_SimpleFontPrint(MousePos.X+8, MousePos.Y+14, PChar(_lc[I_HINT_PANEL_TEXTURE]), gEditorFont, 0, 0, 0);
2786 end;
2788 // Подсказка при выборе панели индикации выстрела:
2789 if SelectFlag = SELECTFLAG_SHOTPANEL then
2790 begin
2791 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+316, MousePos.Y+18, 192, 192, 192, 127);
2792 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+316, MousePos.Y+18, 255, 255, 255);
2793 e_SimpleFontPrint(MousePos.X+8, MousePos.Y+14, PChar(_lc[I_HINT_PANEL_SHOT]), gEditorFont, 0, 0, 0);
2794 end;
2796 // Подсказка при выборе панели лифта:
2797 if SelectFlag = SELECTFLAG_LIFT then
2798 begin
2799 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 192, 192, 192, 127);
2800 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 255, 255, 255);
2801 e_SimpleFontPrint(MousePos.X+8, MousePos.Y+14, PChar(_lc[I_HINT_PANEL_LIFT]), gEditorFont, 0, 0, 0);
2802 end;
2804 // Подсказка при выборе монстра:
2805 if SelectFlag = SELECTFLAG_MONSTER then
2806 begin
2807 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+120, MousePos.Y+18, 192, 192, 192, 127);
2808 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+120, MousePos.Y+18, 255, 255, 255);
2809 e_SimpleFontPrint(MousePos.X+8, MousePos.Y+14, PChar(_lc[I_HINT_MONSTER]), gEditorFont, 0, 0, 0);
2810 end;
2812 // Подсказка при выборе области воздействия:
2813 if DrawPressRect then
2814 begin
2815 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+204, MousePos.Y+18, 192, 192, 192, 127);
2816 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+204, MousePos.Y+18, 255, 255, 255);
2817 e_SimpleFontPrint(MousePos.X+8, MousePos.Y+14, PChar(_lc[I_HINT_EXT_AREA]), gEditorFont, 0, 0, 0);
2818 end;
2820 // Рисуем текстуры, если чертим панель:
2821 if (MouseAction = MOUSEACTION_DRAWPANEL) and (DrawTexturePanel) and
2822 (lbTextureList.ItemIndex <> -1) and (DrawRect <> nil) and
2823 (lbPanelType.ItemIndex in [0..8]) and not IsSpecialTextureSel() then
2824 begin
2825 if not g_GetTexture(SelectedTexture(), ID) then
2826 g_GetTexture('NOTEXTURE', ID);
2827 g_GetTextureSizeByID(ID, Width, Height);
2828 with DrawRect^ do
2829 e_DrawFill(ID, Min(Left, Right), Min(Top, Bottom), Abs(Right-Left) div Width,
2830 Abs(Bottom-Top) div Height, 0, True, False);
2831 end;
2833 // Прямоугольник выделения:
2834 if DrawRect <> nil then
2835 with DrawRect^ do
2836 e_DrawQuad(Left, Top, Right-1, Bottom-1, 255, 255, 255);
2838 // Чертим мышью панель/триггер или меняем мышью их размер:
2839 if (MouseAction in [MOUSEACTION_DRAWPANEL, MOUSEACTION_DRAWTRIGGER, MOUSEACTION_RESIZE]) and
2840 (DrawPanelSize) then
2841 begin
2842 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+88, MousePos.Y+33, 192, 192, 192, 127);
2843 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+88, MousePos.Y+33, 255, 255, 255);
2845 if MouseAction in [MOUSEACTION_DRAWPANEL, MOUSEACTION_DRAWTRIGGER] then
2846 begin // Чертим новый
2847 e_SimpleFontPrint(MousePos.X+8, MousePos.Y+14, PChar(Format(_lc[I_HINT_WIDTH],
2848 [Abs(MousePos.X-MouseLDownPos.X)])), gEditorFont, 0, 0, 0);
2849 e_SimpleFontPrint(MousePos.X+8, MousePos.Y+28, PChar(Format(_lc[I_HINT_HEIGHT],
2850 [Abs(MousePos.Y-MouseLDownPos.Y)])), gEditorFont, 0, 0, 0);
2851 end
2852 else // Растягиваем существующий
2853 if SelectedObjects[GetFirstSelected].ObjectType in [OBJECT_PANEL, OBJECT_TRIGGER] then
2854 begin
2855 if SelectedObjects[GetFirstSelected].ObjectType = OBJECT_PANEL then
2856 begin
2857 Width := gPanels[SelectedObjects[GetFirstSelected].ID].Width;
2858 Height := gPanels[SelectedObjects[GetFirstSelected].ID].Height;
2859 end
2860 else
2861 begin
2862 Width := gTriggers[SelectedObjects[GetFirstSelected].ID].Width;
2863 Height := gTriggers[SelectedObjects[GetFirstSelected].ID].Height;
2864 end;
2866 e_SimpleFontPrint(MousePos.X+8, MousePos.Y+14, PChar(Format(_lc[I_HINT_WIDTH], [Width])),
2867 gEditorFont, 0, 0, 0);
2868 e_SimpleFontPrint(MousePos.X+8, MousePos.Y+28, PChar(Format(_lc[I_HINT_HEIGHT], [Height])),
2869 gEditorFont, 0, 0, 0);
2870 end;
2871 end;
2873 // Ближайшая к курсору мыши точка на сетке:
2874 e_DrawPoint(3, MousePos.X, MousePos.Y, 0, 0, 255);
2876 // Мини-карта:
2877 if ShowMap then
2878 begin
2879 // Сколько пикселов карты в 1 пикселе мини-карты:
2880 ScaleSz := 16 div Scale;
2881 // Размеры мини-карты:
2882 aX := max(gMapInfo.Width div ScaleSz, 1);
2883 aY := max(gMapInfo.Height div ScaleSz, 1);
2884 // X-координата на RenderPanel нулевой x-координаты карты:
2885 XX := RenderPanel.Width - aX - 1;
2886 // Рамка карты:
2887 e_DrawFillQuad(XX-1, 0, RenderPanel.Width-1, aY+1, 0, 0, 0, 0);
2888 e_DrawQuad(XX-1, 0, RenderPanel.Width-1, aY+1, 197, 197, 197);
2890 if gPanels <> nil then
2891 begin
2892 // Рисуем панели:
2893 for a := 0 to High(gPanels) do
2894 with gPanels[a] do
2895 if PanelType <> 0 then
2896 begin
2897 // Левый верхний угол:
2898 aX := XX + (X div ScaleSz);
2899 aY := 1 + (Y div ScaleSz);
2900 // Размеры:
2901 aX2 := max(Width div ScaleSz, 1);
2902 aY2 := max(Height div ScaleSz, 1);
2903 // Правый нижний угол:
2904 aX2 := aX + aX2 - 1;
2905 aY2 := aY + aY2 - 1;
2907 case PanelType of
2908 PANEL_WALL: e_DrawFillQuad(aX, aY, aX2, aY2, 208, 208, 208, 0);
2909 PANEL_WATER: e_DrawFillQuad(aX, aY, aX2, aY2, 0, 0, 192, 0);
2910 PANEL_ACID1: e_DrawFillQuad(aX, aY, aX2, aY2, 0, 176, 0, 0);
2911 PANEL_ACID2: e_DrawFillQuad(aX, aY, aX2, aY2, 176, 0, 0, 0);
2912 PANEL_STEP: e_DrawFillQuad(aX, aY, aX2, aY2, 128, 128, 128, 0);
2913 PANEL_LIFTUP: e_DrawFillQuad(aX, aY, aX2, aY2, 116, 72, 36, 0);
2914 PANEL_LIFTDOWN: e_DrawFillQuad(aX, aY, aX2, aY2, 116, 124, 96, 0);
2915 PANEL_LIFTLEFT: e_DrawFillQuad(aX, aY, aX2, aY2, 200, 80, 4, 0);
2916 PANEL_LIFTRIGHT: e_DrawFillQuad(aX, aY, aX2, aY2, 252, 140, 56, 0);
2917 PANEL_OPENDOOR: e_DrawFillQuad(aX, aY, aX2, aY2, 100, 220, 92, 0);
2918 PANEL_CLOSEDOOR: e_DrawFillQuad(aX, aY, aX2, aY2, 212, 184, 64, 0);
2919 PANEL_BLOCKMON: e_DrawFillQuad(aX, aY, aX2, aY2, 192, 0, 192, 0);
2920 end;
2921 end;
2923 // Рисуем красным выделенные панели:
2924 if SelectedObjects <> nil then
2925 for b := 0 to High(SelectedObjects) do
2926 with SelectedObjects[b] do
2927 if Live and (ObjectType = OBJECT_PANEL) then
2928 with gPanels[SelectedObjects[b].ID] do
2929 if PanelType and not(PANEL_BACK or PANEL_FORE) <> 0 then
2930 begin
2931 // Левый верхний угол:
2932 aX := XX + (X div ScaleSz);
2933 aY := 1 + (Y div ScaleSz);
2934 // Размеры:
2935 aX2 := max(Width div ScaleSz, 1);
2936 aY2 := max(Height div ScaleSz, 1);
2937 // Правый нижний угол:
2938 aX2 := aX + aX2 - 1;
2939 aY2 := aY + aY2 - 1;
2941 e_DrawFillQuad(aX, aY, aX2, aY2, 255, 0, 0, 0)
2942 end;
2943 end;
2945 if (gMapInfo.Width > RenderPanel.Width) or
2946 (gMapInfo.Height > RenderPanel.Height) then
2947 begin
2948 // Окно, показывающее текущее положение экрана на карте:
2949 // Размеры окна:
2950 x := max(min(RenderPanel.Width, gMapInfo.Width) div ScaleSz, 1);
2951 y := max(min(RenderPanel.Height, gMapInfo.Height) div ScaleSz, 1);
2952 // Левый верхний угол:
2953 aX := XX + ((-MapOffset.X) div ScaleSz);
2954 aY := 1 + ((-MapOffset.Y) div ScaleSz);
2955 // Правый нижний угол:
2956 aX2 := aX + x - 1;
2957 aY2 := aY + y - 1;
2959 e_DrawFillQuad(aX, aY, aX2, aY2, 127, 192, 127, 127, B_BLEND);
2960 e_DrawQuad(aX, aY, aX2, aY2, 255, 0, 0);
2961 end;
2962 end; // Мини-карта
2964 e_EndRender();
2965 SwapBuffers(hDC);
2966 EndPaint(Handle, ps);
2967 end;
2969 procedure TMainForm.FormResize(Sender: TObject);
2970 begin
2971 e_SetViewPort(0, 0, RenderPanel.Width, RenderPanel.Height);
2973 if gMapInfo.Width >= RenderPanel.Width then
2974 sbHorizontal.Max := Normalize16(gMapInfo.Width-RenderPanel.Width+16)
2975 else
2976 sbHorizontal.Max := 0;
2978 if gMapInfo.Height >= RenderPanel.Height then
2979 sbVertical.Max := Normalize16(gMapInfo.Height-RenderPanel.Height+16)
2980 else
2981 sbVertical.Max := 0;
2983 MapOffset.X := -Normalize16(sbHorizontal.Position);
2984 MapOffset.Y := -Normalize16(sbVertical.Position);
2985 end;
2987 procedure SelectNextObject(X, Y: Integer; ObjectType: Byte; ID: DWORD);
2988 var
2989 j, j_max: Integer;
2990 res: Boolean;
2991 begin
2992 j_max := 0; // shut up compiler
2993 case ObjectType of
2994 OBJECT_PANEL:
2995 begin
2996 res := (gPanels <> nil) and
2997 PanelInShownLayer(gPanels[ID].PanelType) and
2998 g_CollidePoint(X, Y, gPanels[ID].X, gPanels[ID].Y,
2999 gPanels[ID].Width,
3000 gPanels[ID].Height);
3001 j_max := Length(gPanels) - 1;
3002 end;
3004 OBJECT_ITEM:
3005 begin
3006 res := (gItems <> nil) and
3007 LayerEnabled[LAYER_ITEMS] and
3008 g_CollidePoint(X, Y, gItems[ID].X, gItems[ID].Y,
3009 ItemSize[gItems[ID].ItemType][0],
3010 ItemSize[gItems[ID].ItemType][1]);
3011 j_max := Length(gItems) - 1;
3012 end;
3014 OBJECT_MONSTER:
3015 begin
3016 res := (gMonsters <> nil) and
3017 LayerEnabled[LAYER_MONSTERS] and
3018 g_CollidePoint(X, Y, gMonsters[ID].X, gMonsters[ID].Y,
3019 MonsterSize[gMonsters[ID].MonsterType].Width,
3020 MonsterSize[gMonsters[ID].MonsterType].Height);
3021 j_max := Length(gMonsters) - 1;
3022 end;
3024 OBJECT_AREA:
3025 begin
3026 res := (gAreas <> nil) and
3027 LayerEnabled[LAYER_AREAS] and
3028 g_CollidePoint(X, Y, gAreas[ID].X, gAreas[ID].Y,
3029 AreaSize[gAreas[ID].AreaType].Width,
3030 AreaSize[gAreas[ID].AreaType].Height);
3031 j_max := Length(gAreas) - 1;
3032 end;
3034 OBJECT_TRIGGER:
3035 begin
3036 res := (gTriggers <> nil) and
3037 LayerEnabled[LAYER_TRIGGERS] and
3038 g_CollidePoint(X, Y, gTriggers[ID].X, gTriggers[ID].Y,
3039 gTriggers[ID].Width,
3040 gTriggers[ID].Height);
3041 j_max := Length(gTriggers) - 1;
3042 end;
3044 else
3045 res := False;
3046 end;
3048 if not res then
3049 Exit;
3051 // Перебор ID: от ID-1 до 0; потом от High до ID+1:
3052 j := ID;
3054 while True do
3055 begin
3056 Dec(j);
3058 if j < 0 then
3059 j := j_max;
3060 if j = Integer(ID) then
3061 Break;
3063 case ObjectType of
3064 OBJECT_PANEL:
3065 res := PanelInShownLayer(gPanels[j].PanelType) and
3066 g_CollidePoint(X, Y, gPanels[j].X, gPanels[j].Y,
3067 gPanels[j].Width,
3068 gPanels[j].Height);
3069 OBJECT_ITEM:
3070 res := (gItems[j].ItemType <> ITEM_NONE) and
3071 g_CollidePoint(X, Y, gItems[j].X, gItems[j].Y,
3072 ItemSize[gItems[j].ItemType][0],
3073 ItemSize[gItems[j].ItemType][1]);
3074 OBJECT_MONSTER:
3075 res := (gMonsters[j].MonsterType <> MONSTER_NONE) and
3076 g_CollidePoint(X, Y, gMonsters[j].X, gMonsters[j].Y,
3077 MonsterSize[gMonsters[j].MonsterType].Width,
3078 MonsterSize[gMonsters[j].MonsterType].Height);
3079 OBJECT_AREA:
3080 res := (gAreas[j].AreaType <> AREA_NONE) and
3081 g_CollidePoint(X, Y, gAreas[j].X, gAreas[j].Y,
3082 AreaSize[gAreas[j].AreaType].Width,
3083 AreaSize[gAreas[j].AreaType].Height);
3084 OBJECT_TRIGGER:
3085 res := (gTriggers[j].TriggerType <> TRIGGER_NONE) and
3086 g_CollidePoint(X, Y, gTriggers[j].X, gTriggers[j].Y,
3087 gTriggers[j].Width,
3088 gTriggers[j].Height);
3089 else
3090 res := False;
3091 end;
3093 if res then
3094 begin
3095 SetLength(SelectedObjects, 1);
3097 SelectedObjects[0].ObjectType := ObjectType;
3098 SelectedObjects[0].ID := j;
3099 SelectedObjects[0].Live := True;
3101 FillProperty();
3102 Break;
3103 end;
3104 end;
3105 end;
3107 procedure TMainForm.RenderPanelMouseDown(Sender: TObject;
3108 Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
3109 var
3110 i: Integer;
3111 Rect: TRectWH;
3112 c1, c2, c3, c4: Boolean;
3113 item: TItem;
3114 area: TArea;
3115 monster: TMonster;
3116 IDArray: DWArray;
3117 begin
3118 MainForm.ActiveControl := RenderPanel;
3119 RenderPanel.SetFocus();
3121 RenderPanelMouseMove(RenderPanel, Shift, X, Y);
3123 if Button = mbLeft then // Left Mouse Button
3124 begin
3125 // Двигаем карту с помощью мыши и мини-карты:
3126 if ShowMap and
3127 g_CollidePoint(X, Y,
3128 RenderPanel.Width-max(gMapInfo.Width div (16 div Scale), 1)-1,
3129 1,
3130 max(gMapInfo.Width div (16 div Scale), 1),
3131 max(gMapInfo.Height div (16 div Scale), 1) ) then
3132 begin
3133 MoveMap(X, Y);
3134 MouseAction := MOUSEACTION_MOVEMAP;
3135 end
3136 else // Ставим предмет/монстра/область:
3137 if (pcObjects.ActivePageIndex in [1, 2, 3]) and
3138 (not (ssShift in Shift)) then
3139 begin
3140 case pcObjects.ActivePageIndex of
3141 1:
3142 if lbItemList.ItemIndex = -1 then
3143 ErrorMessageBox(_lc[I_MSG_CHOOSE_ITEM])
3144 else
3145 begin
3146 item.ItemType := lbItemList.ItemIndex + ITEM_MEDKIT_SMALL;
3147 if item.ItemType >= ITEM_WEAPON_KASTET then
3148 item.ItemType := item.ItemType + 2;
3149 item.X := MousePos.X-MapOffset.X;
3150 item.Y := MousePos.Y-MapOffset.Y;
3152 if not (ssCtrl in Shift) then
3153 begin
3154 item.X := item.X - (ItemSize[item.ItemType][0] div 2);
3155 item.Y := item.Y - ItemSize[item.ItemType][1];
3156 end;
3158 item.OnlyDM := cbOnlyDM.Checked;
3159 item.Fall := cbFall.Checked;
3160 Undo_Add(OBJECT_ITEM, AddItem(item));
3161 end;
3162 2:
3163 if lbMonsterList.ItemIndex = -1 then
3164 ErrorMessageBox(_lc[I_MSG_CHOOSE_MONSTER])
3165 else
3166 begin
3167 monster.MonsterType := lbMonsterList.ItemIndex + MONSTER_DEMON;
3168 monster.X := MousePos.X-MapOffset.X;
3169 monster.Y := MousePos.Y-MapOffset.Y;
3171 if not (ssCtrl in Shift) then
3172 begin
3173 monster.X := monster.X - (MonsterSize[monster.MonsterType].Width div 2);
3174 monster.Y := monster.Y - MonsterSize[monster.MonsterType].Height;
3175 end;
3177 if rbMonsterLeft.Checked then
3178 monster.Direction := D_LEFT
3179 else
3180 monster.Direction := D_RIGHT;
3181 Undo_Add(OBJECT_MONSTER, AddMonster(monster));
3182 end;
3183 3:
3184 if lbAreasList.ItemIndex = -1 then
3185 ErrorMessageBox(_lc[I_MSG_CHOOSE_AREA])
3186 else
3187 if (lbAreasList.ItemIndex + 1) <> AREA_DOMFLAG then
3188 begin
3189 area.AreaType := lbAreasList.ItemIndex + AREA_PLAYERPOINT1;
3190 area.X := MousePos.X-MapOffset.X;
3191 area.Y := MousePos.Y-MapOffset.Y;
3193 if not (ssCtrl in Shift) then
3194 begin
3195 area.X := area.X - (AreaSize[area.AreaType].Width div 2);
3196 area.Y := area.Y - AreaSize[area.AreaType].Height;
3197 end;
3199 if rbAreaLeft.Checked then
3200 area.Direction := D_LEFT
3201 else
3202 area.Direction := D_RIGHT;
3203 Undo_Add(OBJECT_AREA, AddArea(area));
3204 end;
3205 end;
3206 end
3207 else
3208 begin
3209 i := GetFirstSelected();
3211 // Выбираем объект под текущим:
3212 if (SelectedObjects <> nil) and
3213 (ssShift in Shift) and (i >= 0) and
3214 (SelectedObjects[i].Live) then
3215 begin
3216 if SelectedObjectCount() = 1 then
3217 SelectNextObject(X-MapOffset.X, Y-MapOffset.Y,
3218 SelectedObjects[i].ObjectType,
3219 SelectedObjects[i].ID);
3220 end
3221 else
3222 begin
3223 // Рисуем область триггера "Расширитель":
3224 if DrawPressRect and (i >= 0) and
3225 (SelectedObjects[i].ObjectType = OBJECT_TRIGGER) and
3226 (gTriggers[SelectedObjects[i].ID].TriggerType in
3227 [TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF]) then
3228 MouseAction := MOUSEACTION_DRAWPRESS
3229 else // Рисуем панель:
3230 if pcObjects.ActivePageIndex = 0 then
3231 begin
3232 if (lbPanelType.ItemIndex >= 0) then
3233 MouseAction := MOUSEACTION_DRAWPANEL
3234 end
3235 else // Рисуем триггер:
3236 if (lbTriggersList.ItemIndex >= 0) then
3237 begin
3238 MouseAction := MOUSEACTION_DRAWTRIGGER;
3239 end;
3240 end;
3241 end;
3242 end; // if Button = mbLeft
3244 if Button = mbRight then // Right 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 MouseAction := MOUSEACTION_NOACTION;
3255 end
3256 else // Нужно что-то выбрать мышью:
3257 if SelectFlag <> SELECTFLAG_NONE then
3258 begin
3259 case SelectFlag of
3260 SELECTFLAG_TELEPORT:
3261 // Точку назначения телепортации:
3262 with gTriggers[SelectedObjects[
3263 GetFirstSelected() ].ID].Data.TargetPoint do
3264 begin
3265 X := MousePos.X-MapOffset.X;
3266 Y := MousePos.Y-MapOffset.Y;
3267 end;
3269 SELECTFLAG_SPAWNPOINT:
3270 // Точку создания монстра:
3271 with gTriggers[SelectedObjects[GetFirstSelected()].ID] do
3272 if TriggerType = TRIGGER_SPAWNMONSTER then
3273 begin
3274 Data.MonPos.X := MousePos.X-MapOffset.X;
3275 Data.MonPos.Y := MousePos.Y-MapOffset.Y;
3276 end
3277 else if TriggerType = TRIGGER_SPAWNITEM then
3278 begin // Точка создания предмета:
3279 Data.ItemPos.X := MousePos.X-MapOffset.X;
3280 Data.ItemPos.Y := MousePos.Y-MapOffset.Y;
3281 end
3282 else if TriggerType = TRIGGER_SHOT then
3283 begin // Точка создания выстрела:
3284 Data.ShotPos.X := MousePos.X-MapOffset.X;
3285 Data.ShotPos.Y := MousePos.Y-MapOffset.Y;
3286 end;
3288 SELECTFLAG_DOOR:
3289 // Дверь:
3290 begin
3291 IDArray := ObjectInRect(X-MapOffset.X,
3292 Y-MapOffset.Y,
3293 2, 2, OBJECT_PANEL, True);
3294 if IDArray <> nil then
3295 begin
3296 for i := 0 to High(IDArray) do
3297 if (gPanels[IDArray[i]].PanelType = PANEL_OPENDOOR) or
3298 (gPanels[IDArray[i]].PanelType = PANEL_CLOSEDOOR) then
3299 begin
3300 gTriggers[SelectedObjects[
3301 GetFirstSelected() ].ID].Data.PanelID := IDArray[i];
3302 Break;
3303 end;
3304 end
3305 else
3306 gTriggers[SelectedObjects[
3307 GetFirstSelected() ].ID].Data.PanelID := -1;
3308 end;
3310 SELECTFLAG_TEXTURE:
3311 // Панель с текстурой:
3312 begin
3313 IDArray := ObjectInRect(X-MapOffset.X,
3314 Y-MapOffset.Y,
3315 2, 2, OBJECT_PANEL, True);
3316 if IDArray <> nil then
3317 begin
3318 for i := 0 to High(IDArray) do
3319 if ((gPanels[IDArray[i]].PanelType in
3320 [PANEL_WALL, PANEL_BACK, PANEL_FORE,
3321 PANEL_WATER, PANEL_ACID1, PANEL_ACID2,
3322 PANEL_STEP]) or
3323 (gPanels[IDArray[i]].PanelType = PANEL_OPENDOOR) or
3324 (gPanels[IDArray[i]].PanelType = PANEL_CLOSEDOOR)) and
3325 (gPanels[IDArray[i]].TextureName <> '') then
3326 begin
3327 gTriggers[SelectedObjects[
3328 GetFirstSelected() ].ID].TexturePanel := IDArray[i];
3329 Break;
3330 end;
3331 end
3332 else
3333 gTriggers[SelectedObjects[
3334 GetFirstSelected() ].ID].TexturePanel := -1;
3335 end;
3337 SELECTFLAG_LIFT:
3338 // Лифт:
3339 begin
3340 IDArray := ObjectInRect(X-MapOffset.X,
3341 Y-MapOffset.Y,
3342 2, 2, OBJECT_PANEL, True);
3343 if IDArray <> nil then
3344 begin
3345 for i := 0 to High(IDArray) do
3346 if (gPanels[IDArray[i]].PanelType = PANEL_LIFTUP) or
3347 (gPanels[IDArray[i]].PanelType = PANEL_LIFTDOWN) or
3348 (gPanels[IDArray[i]].PanelType = PANEL_LIFTLEFT) or
3349 (gPanels[IDArray[i]].PanelType = PANEL_LIFTRIGHT) then
3350 begin
3351 gTriggers[SelectedObjects[
3352 GetFirstSelected() ].ID].Data.PanelID := IDArray[i];
3353 Break;
3354 end;
3355 end
3356 else
3357 gTriggers[SelectedObjects[
3358 GetFirstSelected() ].ID].Data.PanelID := -1;
3359 end;
3361 SELECTFLAG_MONSTER:
3362 // Монстра:
3363 begin
3364 IDArray := ObjectInRect(X-MapOffset.X,
3365 Y-MapOffset.Y,
3366 2, 2, OBJECT_MONSTER, False);
3367 if IDArray <> nil then
3368 gTriggers[SelectedObjects[
3369 GetFirstSelected() ].ID].Data.MonsterID := IDArray[0]+1
3370 else
3371 gTriggers[SelectedObjects[
3372 GetFirstSelected() ].ID].Data.MonsterID := 0;
3373 end;
3375 SELECTFLAG_SHOTPANEL:
3376 // Панель индикации выстрела:
3377 begin
3378 if gTriggers[SelectedObjects[
3379 GetFirstSelected() ].ID].TriggerType = TRIGGER_SHOT then
3380 begin
3381 IDArray := ObjectInRect(X-MapOffset.X,
3382 Y-MapOffset.Y,
3383 2, 2, OBJECT_PANEL, True);
3384 if IDArray <> nil then
3385 begin
3386 for i := 0 to High(IDArray) do
3387 if ((gPanels[IDArray[i]].PanelType in
3388 [PANEL_WALL, PANEL_BACK, PANEL_FORE,
3389 PANEL_WATER, PANEL_ACID1, PANEL_ACID2,
3390 PANEL_STEP]) or
3391 (gPanels[IDArray[i]].PanelType = PANEL_OPENDOOR) or
3392 (gPanels[IDArray[i]].PanelType = PANEL_CLOSEDOOR)) and
3393 (gPanels[IDArray[i]].TextureName <> '') then
3394 begin
3395 gTriggers[SelectedObjects[
3396 GetFirstSelected() ].ID].Data.ShotPanelID := IDArray[i];
3397 Break;
3398 end;
3399 end
3400 else
3401 gTriggers[SelectedObjects[
3402 GetFirstSelected() ].ID].Data.ShotPanelID := -1;
3403 end;
3404 end;
3405 end;
3407 SelectFlag := SELECTFLAG_SELECTED;
3408 end
3409 else // if SelectFlag <> SELECTFLAG_NONE...
3410 begin
3411 // Что уже выбрано и не нажат Ctrl:
3412 if (SelectedObjects <> nil) and
3413 (not (ssCtrl in Shift)) then
3414 for i := 0 to High(SelectedObjects) do
3415 with SelectedObjects[i] do
3416 if Live then
3417 begin
3418 if (ObjectType in [OBJECT_PANEL, OBJECT_TRIGGER]) and
3419 (SelectedObjectCount() = 1) then
3420 begin
3421 Rect := ObjectGetRect(ObjectType, ID);
3423 c1 := g_Collide(X-MapOffset.X-1, Y-MapOffset.Y-1, 2, 2,
3424 Rect.X-2, Rect.Y+(Rect.Height div 2)-2, 4, 4);
3425 c2 := g_Collide(X-MapOffset.X-1, Y-MapOffset.Y-1, 2, 2,
3426 Rect.X+Rect.Width-3, Rect.Y+(Rect.Height div 2)-2, 4, 4);
3427 c3 := g_Collide(X-MapOffset.X-1, Y-MapOffset.Y-1, 2, 2,
3428 Rect.X+(Rect.Width div 2)-2, Rect.Y-2, 4, 4);
3429 c4 := g_Collide(X-MapOffset.X-1, Y-MapOffset.Y-1, 2, 2,
3430 Rect.X+(Rect.Width div 2)-2, Rect.Y+Rect.Height-3, 4, 4);
3432 // Меняем размер панели или триггера:
3433 if c1 or c2 or c3 or c4 then
3434 begin
3435 MouseAction := MOUSEACTION_RESIZE;
3436 LastMovePoint := MousePos;
3438 if c1 or c2 then
3439 begin // Шире/уже
3440 ResizeType := RESIZETYPE_HORIZONTAL;
3441 if c1 then
3442 ResizeDirection := RESIZEDIR_LEFT
3443 else
3444 ResizeDirection := RESIZEDIR_RIGHT;
3445 RenderPanel.Cursor := crSizeWE;
3446 end
3447 else
3448 begin // Выше/ниже
3449 ResizeType := RESIZETYPE_VERTICAL;
3450 if c3 then
3451 ResizeDirection := RESIZEDIR_UP
3452 else
3453 ResizeDirection := RESIZEDIR_DOWN;
3454 RenderPanel.Cursor := crSizeNS;
3455 end;
3457 Break;
3458 end;
3459 end;
3461 // Перемещаем панель или триггер:
3462 if ObjectCollide(ObjectType, ID,
3463 X-MapOffset.X-1,
3464 Y-MapOffset.Y-1, 2, 2) then
3465 begin
3466 MouseAction := MOUSEACTION_MOVEOBJ;
3467 LastMovePoint := MousePos;
3469 Break;
3470 end;
3471 end;
3472 end;
3473 end; // if Button = mbRight
3475 MouseRDown := Button = mbRight;
3476 if MouseRDown then
3477 MouseRDownPos := MousePos;
3479 MouseLDown := Button = mbLeft;
3480 if MouseLDown then
3481 MouseLDownPos := MousePos;
3482 end;
3484 procedure TMainForm.RenderPanelMouseUp(Sender: TObject;
3485 Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
3486 var
3487 panel: TPanel;
3488 trigger: TTrigger;
3489 i: Integer;
3490 IDArray: DWArray;
3491 rRect: TRectWH;
3492 rSelectRect: Boolean;
3493 begin
3494 if Button = mbLeft then
3495 MouseLDown := False;
3496 if Button = mbRight then
3497 MouseRDown := False;
3499 DrawRect := nil;
3500 ResizeType := RESIZETYPE_NONE;
3502 if Button = mbLeft then // Left Mouse Button
3503 begin
3504 if MouseAction <> MOUSEACTION_NONE then
3505 begin // Было действие мышью
3506 // Мышь сдвинулась во время удержания клавиши:
3507 if (MousePos.X <> MouseLDownPos.X) and
3508 (MousePos.Y <> MouseLDownPos.Y) then
3509 case MouseAction of
3510 // Рисовали панель:
3511 MOUSEACTION_DRAWPANEL:
3512 begin
3513 // Фон или передний план без текстуры - ошибка:
3514 if (lbPanelType.ItemIndex in [1, 2]) and
3515 (lbTextureList.ItemIndex = -1) then
3516 ErrorMessageBox(_lc[I_MSG_CHOOSE_TEXTURE])
3517 else // Назначаем параметры панели:
3518 begin
3519 case lbPanelType.ItemIndex of
3520 0: Panel.PanelType := PANEL_WALL;
3521 1: Panel.PanelType := PANEL_BACK;
3522 2: Panel.PanelType := PANEL_FORE;
3523 3: Panel.PanelType := PANEL_OPENDOOR;
3524 4: Panel.PanelType := PANEL_CLOSEDOOR;
3525 5: Panel.PanelType := PANEL_STEP;
3526 6: Panel.PanelType := PANEL_WATER;
3527 7: Panel.PanelType := PANEL_ACID1;
3528 8: Panel.PanelType := PANEL_ACID2;
3529 9: Panel.PanelType := PANEL_LIFTUP;
3530 10: Panel.PanelType := PANEL_LIFTDOWN;
3531 11: Panel.PanelType := PANEL_LIFTLEFT;
3532 12: Panel.PanelType := PANEL_LIFTRIGHT;
3533 13: Panel.PanelType := PANEL_BLOCKMON;
3534 end;
3536 Panel.X := Min(MousePos.X-MapOffset.X, MouseLDownPos.X-MapOffset.X);
3537 Panel.Y := Min(MousePos.Y-MapOffset.Y, MouseLDownPos.Y-MapOffset.Y);
3538 Panel.Width := Abs(MousePos.X-MouseLDownPos.X);
3539 Panel.Height := Abs(MousePos.Y-MouseLDownPos.Y);
3541 // Лифты, блокМон или отсутствие текстуры - пустая текстура:
3542 if (lbPanelType.ItemIndex in [9, 10, 11, 12, 13]) or
3543 (lbTextureList.ItemIndex = -1) then
3544 begin
3545 Panel.TextureHeight := 1;
3546 Panel.TextureWidth := 1;
3547 Panel.TextureName := '';
3548 Panel.TextureID := TEXTURE_SPECIAL_NONE;
3549 end
3550 else // Есть текстура:
3551 begin
3552 Panel.TextureName := SelectedTexture();
3554 // Обычная текстура:
3555 if not IsSpecialTextureSel() then
3556 begin
3557 g_GetTextureSizeByName(Panel.TextureName,
3558 Panel.TextureWidth, Panel.TextureHeight);
3559 g_GetTexture(Panel.TextureName, Panel.TextureID);
3560 end
3561 else // Спец.текстура:
3562 begin
3563 Panel.TextureHeight := 1;
3564 Panel.TextureWidth := 1;
3565 Panel.TextureID := SpecialTextureID(SelectedTexture());
3566 end;
3567 end;
3569 Panel.Alpha := 0;
3570 Panel.Blending := False;
3572 Undo_Add(OBJECT_PANEL, AddPanel(Panel));
3573 end;
3574 end;
3576 // Рисовали триггер:
3577 MOUSEACTION_DRAWTRIGGER:
3578 begin
3579 trigger.X := Min(MousePos.X-MapOffset.X, MouseLDownPos.X-MapOffset.X);
3580 trigger.Y := Min(MousePos.Y-MapOffset.Y, MouseLDownPos.Y-MapOffset.Y);
3581 trigger.Width := Abs(MousePos.X-MouseLDownPos.X);
3582 trigger.Height := Abs(MousePos.Y-MouseLDownPos.Y);
3584 trigger.Enabled := True;
3585 trigger.TriggerType := lbTriggersList.ItemIndex+1;
3586 trigger.TexturePanel := -1;
3588 // Типы активации:
3589 trigger.ActivateType := 0;
3591 if clbActivationType.Checked[0] then
3592 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_PLAYERCOLLIDE;
3593 if clbActivationType.Checked[1] then
3594 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_MONSTERCOLLIDE;
3595 if clbActivationType.Checked[2] then
3596 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_PLAYERPRESS;
3597 if clbActivationType.Checked[3] then
3598 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_MONSTERPRESS;
3599 if clbActivationType.Checked[4] then
3600 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_SHOT;
3601 if clbActivationType.Checked[5] then
3602 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_NOMONSTER;
3604 // Необходимые для активации ключи:
3605 trigger.Key := 0;
3607 if clbKeys.Checked[0] then
3608 trigger.Key := Trigger.Key or KEY_RED;
3609 if clbKeys.Checked[1] then
3610 trigger.Key := Trigger.Key or KEY_GREEN;
3611 if clbKeys.Checked[2] then
3612 trigger.Key := Trigger.Key or KEY_BLUE;
3613 if clbKeys.Checked[3] then
3614 trigger.Key := Trigger.Key or KEY_REDTEAM;
3615 if clbKeys.Checked[4] then
3616 trigger.Key := Trigger.Key or KEY_BLUETEAM;
3618 // Параметры триггера:
3619 ZeroMemory(@trigger.Data.Default[0], 128);
3621 case trigger.TriggerType of
3622 // Переключаемая панель:
3623 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
3624 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP,
3625 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
3626 begin
3627 Trigger.Data.PanelID := -1;
3628 end;
3630 // Телепортация:
3631 TRIGGER_TELEPORT:
3632 begin
3633 trigger.Data.TargetPoint.X := trigger.X-64;
3634 trigger.Data.TargetPoint.Y := trigger.Y-64;
3635 trigger.Data.d2d_teleport := True;
3636 trigger.Data.TlpDir := 0;
3637 end;
3639 // Изменение других триггеров:
3640 TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF,
3641 TRIGGER_ONOFF:
3642 begin
3643 trigger.Data.Count := 1;
3644 end;
3646 // Звук:
3647 TRIGGER_SOUND:
3648 begin
3649 trigger.Data.Volume := 255;
3650 trigger.Data.Pan := 127;
3651 trigger.Data.PlayCount := 1;
3652 trigger.Data.Local := True;
3653 trigger.Data.SoundSwitch := False;
3654 end;
3656 // Музыка:
3657 TRIGGER_MUSIC:
3658 begin
3659 trigger.Data.MusicAction := 1;
3660 end;
3662 // Создание монстра:
3663 TRIGGER_SPAWNMONSTER:
3664 begin
3665 trigger.Data.MonType := MONSTER_ZOMBY;
3666 trigger.Data.MonPos.X := trigger.X-64;
3667 trigger.Data.MonPos.Y := trigger.Y-64;
3668 trigger.Data.MonHealth := 0;
3669 trigger.Data.MonActive := False;
3670 trigger.Data.MonCount := 1;
3671 end;
3673 // Создание предмета:
3674 TRIGGER_SPAWNITEM:
3675 begin
3676 trigger.Data.ItemType := ITEM_AMMO_BULLETS;
3677 trigger.Data.ItemPos.X := trigger.X-64;
3678 trigger.Data.ItemPos.Y := trigger.Y-64;
3679 trigger.Data.ItemOnlyDM := False;
3680 trigger.Data.ItemFalls := False;
3681 trigger.Data.ItemCount := 1;
3682 trigger.Data.ItemMax := 0;
3683 trigger.Data.ItemDelay := 0;
3684 end;
3686 // Ускорение:
3687 TRIGGER_PUSH:
3688 begin
3689 trigger.Data.PushAngle := 90;
3690 trigger.Data.PushForce := 10;
3691 trigger.Data.ResetVel := True;
3692 end;
3694 TRIGGER_SCORE:
3695 begin
3696 trigger.Data.ScoreCount := 1;
3697 trigger.Data.ScoreCon := True;
3698 trigger.Data.ScoreMsg := True;
3699 end;
3701 TRIGGER_MESSAGE:
3702 begin
3703 trigger.Data.MessageKind := 0;
3704 trigger.Data.MessageSendTo := 0;
3705 trigger.Data.MessageText := '';
3706 trigger.Data.MessageTime := 144;
3707 end;
3709 TRIGGER_DAMAGE:
3710 begin
3711 trigger.Data.DamageValue := 5;
3712 trigger.Data.DamageInterval := 12;
3713 end;
3715 TRIGGER_HEALTH:
3716 begin
3717 trigger.Data.HealValue := 5;
3718 trigger.Data.HealInterval := 36;
3719 end;
3721 TRIGGER_SHOT:
3722 begin
3723 trigger.Data.ShotType := TRIGGER_SHOT_BULLET;
3724 trigger.Data.ShotSound := True;
3725 trigger.Data.ShotPanelID := -1;
3726 trigger.Data.ShotTarget := 0;
3727 trigger.Data.ShotIntSight := 0;
3728 trigger.Data.ShotAllMap := False;
3729 trigger.Data.ShotPos.X := trigger.X-64;
3730 trigger.Data.ShotPos.Y := trigger.Y-64;
3731 trigger.Data.ShotAngle := 0;
3732 trigger.Data.ShotWait := 18;
3733 trigger.Data.ShotAccuracy := 0;
3734 trigger.Data.ShotAmmo := 0;
3735 trigger.Data.ShotIntReload := 0;
3736 end;
3738 TRIGGER_EFFECT:
3739 begin
3740 trigger.Data.FXCount := 1;
3741 trigger.Data.FXType := TRIGGER_EFFECT_PARTICLE;
3742 trigger.Data.FXSubType := TRIGGER_EFFECT_SLIQUID;
3743 trigger.Data.FXColorR := 0;
3744 trigger.Data.FXColorG := 0;
3745 trigger.Data.FXColorB := 255;
3746 trigger.Data.FXPos := TRIGGER_EFFECT_POS_CENTER;
3747 trigger.Data.FXWait := 1;
3748 trigger.Data.FXVelX := 0;
3749 trigger.Data.FXVelY := -20;
3750 trigger.Data.FXSpreadL := 5;
3751 trigger.Data.FXSpreadR := 5;
3752 trigger.Data.FXSpreadU := 4;
3753 trigger.Data.FXSpreadD := 0;
3754 end;
3755 end;
3757 Undo_Add(OBJECT_TRIGGER, AddTrigger(trigger));
3758 end;
3760 // Рисовали область триггера "Расширитель":
3761 MOUSEACTION_DRAWPRESS:
3762 with gTriggers[SelectedObjects[GetFirstSelected].ID] do
3763 begin
3764 Data.tX := Min(MousePos.X-MapOffset.X, MouseLDownPos.X-MapOffset.X);
3765 Data.tY := Min(MousePos.Y-MapOffset.Y, MouseLDownPos.Y-MapOffset.Y);
3766 Data.tWidth := Abs(MousePos.X-MouseLDownPos.X);
3767 Data.tHeight := Abs(MousePos.Y-MouseLDownPos.Y);
3769 DrawPressRect := False;
3770 end;
3771 end;
3773 MouseAction := MOUSEACTION_NONE;
3774 end;
3775 end // if Button = mbLeft...
3776 else // Right Mouse Button:
3777 begin
3778 if MouseAction = MOUSEACTION_NOACTION then
3779 begin
3780 MouseAction := MOUSEACTION_NONE;
3781 Exit;
3782 end;
3784 // Объект передвинут или изменен в размере:
3785 if MouseAction in [MOUSEACTION_MOVEOBJ, MOUSEACTION_RESIZE] then
3786 begin
3787 MouseAction := MOUSEACTION_NONE;
3788 FillProperty();
3789 Exit;
3790 end;
3792 // Еще не все выбрали:
3793 if SelectFlag <> SELECTFLAG_NONE then
3794 begin
3795 if SelectFlag = SELECTFLAG_SELECTED then
3796 SelectFlag := SELECTFLAG_NONE;
3797 FillProperty();
3798 Exit;
3799 end;
3801 // Мышь сдвинулась во время удержания клавиши:
3802 if (MousePos.X <> MouseRDownPos.X) and
3803 (MousePos.Y <> MouseRDownPos.Y) then
3804 begin
3805 rSelectRect := True;
3807 rRect.X := Min(MousePos.X, MouseRDownPos.X)-MapOffset.X;
3808 rRect.Y := Min(MousePos.Y, MouseRDownPos.Y)-MapOffset.Y;
3809 rRect.Width := Abs(MousePos.X-MouseRDownPos.X);
3810 rRect.Height := Abs(MousePos.Y-MouseRDownPos.Y);
3811 end
3812 else // Мышь не сдвинулась - нет прямоугольника:
3813 begin
3814 rSelectRect := False;
3816 rRect.X := X-MapOffset.X-1;
3817 rRect.Y := Y-MapOffset.Y-1;
3818 rRect.Width := 2;
3819 rRect.Height := 2;
3820 end;
3822 // Если зажат Ctrl - выделять еще, иначе только один выделенный объект:
3823 if not (ssCtrl in Shift) then
3824 RemoveSelectFromObjects();
3826 // Выделяем всё в выбранном прямоугольнике:
3827 IDArray := ObjectInRect(rRect.X, rRect.Y,
3828 rRect.Width, rRect.Height,
3829 pcObjects.ActivePageIndex+1, rSelectRect);
3831 if IDArray <> nil then
3832 for i := 0 to High(IDArray) do
3833 SelectObject(pcObjects.ActivePageIndex+1, IDArray[i],
3834 (ssCtrl in Shift) or rSelectRect);
3836 FillProperty();
3837 end;
3838 end;
3840 procedure TMainForm.RenderPanelMouseMove(Sender: TObject;
3841 Shift: TShiftState; X, Y: Integer);
3842 var
3843 sX, sY: Integer;
3844 dWidth, dHeight: Integer;
3845 _id: Integer;
3846 begin
3847 _id := GetFirstSelected();
3849 // Рисуем панель с текстурой, сетка - размеры текстуры:
3850 if (MouseAction = MOUSEACTION_DRAWPANEL) and
3851 (lbPanelType.ItemIndex in [0..8]) and
3852 (lbTextureList.ItemIndex <> -1) and
3853 (not IsSpecialTextureSel()) then
3854 begin
3855 sX := StrToIntDef(lTextureWidth.Caption, DotStep);
3856 sY := StrToIntDef(lTextureHeight.Caption, DotStep);
3857 end
3858 else
3859 // Меняем размер панели с текстурой, сетка - размеры текстуры:
3860 if (MouseAction = MOUSEACTION_RESIZE) and
3861 ( (SelectedObjects[_id].ObjectType = OBJECT_PANEL) and
3862 IsTexturedPanel(gPanels[SelectedObjects[_id].ID].PanelType) and
3863 (gPanels[SelectedObjects[_id].ID].TextureName <> '') and
3864 (not IsSpecialTexture(gPanels[SelectedObjects[_id].ID].TextureName)) ) then
3865 begin
3866 sX := gPanels[SelectedObjects[_id].ID].TextureWidth;
3867 sY := gPanels[SelectedObjects[_id].ID].TextureHeight;
3868 end
3869 else
3870 // Выравнивание по сетке:
3871 if SnapToGrid then
3872 begin
3873 sX := DotStep;
3874 sY := DotStep;
3875 end
3876 else // Нет выравнивания по сетке:
3877 begin
3878 sX := 1;
3879 sY := 1;
3880 end;
3882 // Новая позиция мыши:
3883 if MouseLDown then
3884 begin // Зажата левая кнопка мыши
3885 MousePos.X := (Round((X-MouseLDownPos.X)/sX)*sX)+MouseLDownPos.X;
3886 MousePos.Y := (Round((Y-MouseLDownPos.Y)/sY)*sY)+MouseLDownPos.Y;
3887 end
3888 else
3889 if MouseRDown then
3890 begin // Зажата правая кнопка мыши
3891 MousePos.X := (Round((X-MouseRDownPos.X)/sX)*sX)+MouseRDownPos.X;
3892 MousePos.Y := (Round((Y-MouseRDownPos.Y)/sY)*sY)+MouseRDownPos.Y;
3893 end
3894 else
3895 begin // Кнопки мыши не зажаты
3896 MousePos.X := (Round(X/sX)*sX);
3897 MousePos.Y := (Round(Y/sY)*sY);
3898 end;
3900 // Изменение размера закончилось - ставим обычный курсор:
3901 if ResizeType = RESIZETYPE_NONE then
3902 RenderPanel.Cursor := crDefault;
3904 // Зажата только правая кнопка мыши:
3905 if (not MouseLDown) and (MouseRDown) then
3906 begin
3907 // Рисуем прямоугольник выделения:
3908 if MouseAction = MOUSEACTION_NONE then
3909 begin
3910 if DrawRect = nil then
3911 New(DrawRect);
3912 DrawRect.TopLeft := MouseRDownPos;
3913 DrawRect.BottomRight := MousePos;
3914 end
3915 else
3916 // Двигаем выделенные объекты:
3917 if MouseAction = MOUSEACTION_MOVEOBJ then
3918 begin
3919 MoveSelectedObjects(ssShift in Shift, ssCtrl in Shift,
3920 MousePos.X-LastMovePoint.X,
3921 MousePos.Y-LastMovePoint.Y);
3922 end
3923 else
3924 // Меняем размер выделенного объекта:
3925 if MouseAction = MOUSEACTION_RESIZE then
3926 begin
3927 if (SelectedObjectCount = 1) and
3928 (SelectedObjects[GetFirstSelected].Live) then
3929 begin
3930 dWidth := MousePos.X-LastMovePoint.X;
3931 dHeight := MousePos.Y-LastMovePoint.Y;
3933 case ResizeType of
3934 RESIZETYPE_VERTICAL: dWidth := 0;
3935 RESIZETYPE_HORIZONTAL: dHeight := 0;
3936 end;
3938 case ResizeDirection of
3939 RESIZEDIR_UP: dHeight := -dHeight;
3940 RESIZEDIR_LEFT: dWidth := -dWidth;
3941 end;
3943 ResizeObject(SelectedObjects[GetFirstSelected].ObjectType,
3944 SelectedObjects[GetFirstSelected].ID,
3945 dWidth, dHeight, ResizeDirection);
3947 LastMovePoint := MousePos;
3948 end;
3949 end;
3950 end;
3952 // Зажата только левая кнопка мыши:
3953 if (not MouseRDown) and (MouseLDown) then
3954 begin
3955 // Рисуем прямоугольник планирования панели:
3956 if MouseAction in [MOUSEACTION_DRAWPANEL,
3957 MOUSEACTION_DRAWTRIGGER,
3958 MOUSEACTION_DRAWPRESS] then
3959 begin
3960 if DrawRect = nil then
3961 New(DrawRect);
3962 DrawRect.TopLeft := MouseLDownPos;
3963 DrawRect.BottomRight := MousePos;
3964 end
3965 else // Двигаем карту:
3966 if MouseAction = MOUSEACTION_MOVEMAP then
3967 begin
3968 MoveMap(X, Y);
3969 end;
3970 end;
3972 // Клавиши мыши не зажаты:
3973 if (not MouseRDown) and (not MouseLDown) then
3974 DrawRect := nil;
3976 // Строка состояния - координаты мыши:
3977 StatusBar.Panels[1].Text := Format('(%d:%d)',
3978 [MousePos.X-MapOffset.X, MousePos.Y-MapOffset.Y]);
3979 end;
3981 procedure TMainForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
3982 begin
3983 CanClose := MessageBox(0, PChar(_lc[I_MSG_EXIT_PROMT]),
3984 PChar(_lc[I_MSG_EXIT]),
3985 MB_ICONQUESTION or MB_YESNO or
3986 MB_TASKMODAL or MB_DEFBUTTON1) = idYes;
3987 end;
3989 procedure TMainForm.aExitExecute(Sender: TObject);
3990 begin
3991 Close();
3992 end;
3994 procedure TMainForm.FormDestroy(Sender: TObject);
3995 var
3996 config: TConfig;
3997 i: Integer;
3998 begin
3999 config := TConfig.CreateFile(EditorDir+'\Editor.cfg');
4001 config.WriteBool('Editor', 'Maximize', WindowState = wsMaximized);
4002 config.WriteBool('Editor', 'Minimap', ShowMap);
4003 config.WriteInt('Editor', 'PanelProps', PanelProps.ClientWidth);
4004 config.WriteInt('Editor', 'PanelObjs', PanelObjs.ClientHeight);
4005 config.WriteBool('Editor', 'DotEnable', DotEnable);
4006 config.WriteInt('Editor', 'DotStep', DotStep);
4007 config.WriteStr('Editor', 'LastOpenDir', OpenDialog.InitialDir);
4008 config.WriteStr('Editor', 'LastSaveDir', SaveDialog.InitialDir);
4009 config.WriteBool('Editor', 'EdgeShow', drEdge[3] < 255);
4010 config.WriteInt('Editor', 'EdgeColor', gColorEdge);
4011 config.WriteInt('Editor', 'EdgeAlpha', gAlphaEdge);
4012 config.WriteInt('Editor', 'LineAlpha', gAlphaTriggerLine);
4013 config.WriteInt('Editor', 'TriggerAlpha', gAlphaTriggerArea);
4015 for i := 0 to RecentCount-1 do
4016 if i < RecentFiles.Count then
4017 config.WriteStr('RecentFiles', IntToStr(i+1), RecentFiles[i])
4018 else
4019 config.WriteStr('RecentFiles', IntToStr(i+1), '');
4020 RecentFiles.Free();
4022 config.SaveFile(EditorDir+'\Editor.cfg');
4023 config.Free();
4025 slInvalidTextures.Free;
4027 wglDeleteContext(hRC);
4028 end;
4030 procedure TMainForm.RenderPanelResize(Sender: TObject);
4031 begin
4032 if MainForm.Visible then
4033 MainForm.Resize();
4034 end;
4036 procedure TMainForm.aMapOptionsExecute(Sender: TObject);
4037 var
4038 ResName: String;
4039 begin
4040 MapOptionsForm.ShowModal();
4042 ResName := OpenedMap;
4043 while (Pos(':\', ResName) > 0) do
4044 Delete(ResName, 1, Pos(':\', ResName) + 1);
4046 UpdateCaption(gMapInfo.Name, ExtractFileName(OpenedWAD), ResName);
4047 end;
4049 procedure TMainForm.aAboutExecute(Sender: TObject);
4050 begin
4051 AboutForm.ShowModal();
4052 end;
4054 procedure TMainForm.FormKeyDown(Sender: TObject; var Key: Word;
4055 Shift: TShiftState);
4056 var
4057 dx, dy, i: Integer;
4058 FileName: String;
4059 begin
4060 if (not EditingProperties) then
4061 begin
4062 if Key = Ord('1') then
4063 SwitchLayer(LAYER_BACK);
4064 if Key = Ord('2') then
4065 SwitchLayer(LAYER_WALLS);
4066 if Key = Ord('3') then
4067 SwitchLayer(LAYER_FOREGROUND);
4068 if Key = Ord('4') then
4069 SwitchLayer(LAYER_STEPS);
4070 if Key = Ord('5') then
4071 SwitchLayer(LAYER_WATER);
4072 if Key = Ord('6') then
4073 SwitchLayer(LAYER_ITEMS);
4074 if Key = Ord('7') then
4075 SwitchLayer(LAYER_MONSTERS);
4076 if Key = Ord('8') then
4077 SwitchLayer(LAYER_AREAS);
4078 if Key = Ord('9') then
4079 SwitchLayer(LAYER_TRIGGERS);
4080 if Key = Ord('0') then
4081 tbShowClick(tbShow);
4083 if Key = Ord('V') then
4084 begin // Поворот монстров и областей:
4085 if (SelectedObjects <> nil) then
4086 begin
4087 for i := 0 to High(SelectedObjects) do
4088 if (SelectedObjects[i].Live) then
4089 begin
4090 if (SelectedObjects[i].ObjectType = OBJECT_MONSTER) then
4091 begin
4092 g_ChangeDir(gMonsters[SelectedObjects[i].ID].Direction);
4093 end
4094 else
4095 if (SelectedObjects[i].ObjectType = OBJECT_AREA) then
4096 begin
4097 g_ChangeDir(gAreas[SelectedObjects[i].ID].Direction);
4098 end;
4099 end;
4100 end
4101 else
4102 begin
4103 if pcObjects.ActivePage = tsMonsters then
4104 begin
4105 if rbMonsterLeft.Checked then
4106 rbMonsterRight.Checked := True
4107 else
4108 rbMonsterLeft.Checked := True;
4109 end;
4110 if pcObjects.ActivePage = tsAreas then
4111 begin
4112 if rbAreaLeft.Checked then
4113 rbAreaRight.Checked := True
4114 else
4115 rbAreaLeft.Checked := True;
4116 end;
4117 end;
4118 end;
4120 if not (ssCtrl in Shift) then
4121 begin
4122 // Вертикальный скролл карты:
4123 with sbVertical do
4124 begin
4125 if Key = Ord('W') then
4126 begin
4127 Position := IfThen(Position > DotStep, Position-DotStep, 0);
4128 MapOffset.Y := -Round(Position/16) * 16;
4129 end;
4131 if Key = Ord('S') then
4132 begin
4133 Position := IfThen(Position+DotStep < Max, Position+DotStep, Max);
4134 MapOffset.Y := -Round(Position/16) * 16;
4135 end;
4136 end;
4138 // Горизонтальный скролл карты:
4139 with sbHorizontal do
4140 begin
4141 if Key = Ord('A') then
4142 begin
4143 Position := IfThen(Position > DotStep, Position-DotStep, 0);
4144 MapOffset.X := -Round(Position/16) * 16;
4145 end;
4147 if Key = Ord('D') then
4148 begin
4149 Position := IfThen(Position+DotStep < Max, Position+DotStep, Max);
4150 MapOffset.X := -Round(Position/16) * 16;
4151 end;
4152 end;
4153 end;
4154 end;
4156 // Удалить выделенные объекты:
4157 if (Key = VK_DELETE) and (SelectedObjects <> nil) and
4158 RenderPanel.Focused() then
4159 DeleteSelectedObjects();
4161 // Снять выделение:
4162 if (Key = VK_ESCAPE) and (SelectedObjects <> nil) then
4163 RemoveSelectFromObjects();
4165 // Передвинуть объекты:
4166 if MainForm.ActiveControl = RenderPanel then
4167 begin
4168 dx := 0;
4169 dy := 0;
4171 if Key = VK_NUMPAD4 then
4172 dx := IfThen(ssAlt in Shift, -1, -DotStep);
4173 if Key = VK_NUMPAD6 then
4174 dx := IfThen(ssAlt in Shift, 1, DotStep);
4175 if Key = VK_NUMPAD8 then
4176 dy := IfThen(ssAlt in Shift, -1, -DotStep);
4177 if Key = VK_NUMPAD5 then
4178 dy := IfThen(ssAlt in Shift, 1, DotStep);
4180 if (dx <> 0) or (dy <> 0) then
4181 begin
4182 MoveSelectedObjects(ssShift in Shift, ssCtrl in Shift, dx, dy);
4183 Key := 0;
4184 end;
4185 end;
4187 if ssCtrl in Shift then
4188 begin
4189 // Выбор панели с текстурой для триггера
4190 if Key = Ord('T') then
4191 begin
4192 DrawPressRect := False;
4193 if SelectFlag = SELECTFLAG_TEXTURE then
4194 begin
4195 SelectFlag := SELECTFLAG_NONE;
4196 Exit;
4197 end;
4198 vleObjectProperty.FindRow(_lc[I_PROP_TR_TEXTURE_PANEL], i);
4199 if i > 0 then
4200 SelectFlag := SELECTFLAG_TEXTURE;
4201 end;
4203 if Key = Ord('D') then
4204 begin
4205 SelectFlag := SELECTFLAG_NONE;
4206 if DrawPressRect then
4207 begin
4208 DrawPressRect := False;
4209 Exit;
4210 end;
4212 // Выбор области воздействия, в зависимости от типа триггера
4213 vleObjectProperty.FindRow(_lc[I_PROP_TR_EX_AREA], i);
4214 if i > 0 then
4215 begin
4216 DrawPressRect := True;
4217 Exit;
4218 end;
4219 vleObjectProperty.FindRow(_lc[I_PROP_TR_DOOR_PANEL], i);
4220 if i <= 0 then
4221 vleObjectProperty.FindRow(_lc[I_PROP_TR_TRAP_PANEL], i);
4222 if i > 0 then
4223 begin
4224 SelectFlag := SELECTFLAG_DOOR;
4225 Exit;
4226 end;
4227 vleObjectProperty.FindRow(_lc[I_PROP_TR_LIFT_PANEL], i);
4228 if i > 0 then
4229 begin
4230 SelectFlag := SELECTFLAG_LIFT;
4231 Exit;
4232 end;
4233 vleObjectProperty.FindRow(_lc[I_PROP_TR_TELEPORT_TO], i);
4234 if i > 0 then
4235 begin
4236 SelectFlag := SELECTFLAG_TELEPORT;
4237 Exit;
4238 end;
4239 vleObjectProperty.FindRow(_lc[I_PROP_TR_SPAWN_TO], i);
4240 if i > 0 then
4241 begin
4242 SelectFlag := SELECTFLAG_SPAWNPOINT;
4243 Exit;
4244 end;
4246 // Выбор основного параметра, в зависимости от типа триггера
4247 vleObjectProperty.FindRow(_lc[I_PROP_TR_NEXT_MAP], i);
4248 if i > 0 then
4249 begin
4250 g_ProcessResourceStr(OpenedMap, @FileName, nil, nil);
4251 SelectMapForm.GetMaps(FileName);
4253 if SelectMapForm.ShowModal() = mrOK then
4254 begin
4255 vleObjectProperty.Cells[1, i] := SelectMapForm.lbMapList.Items[SelectMapForm.lbMapList.ItemIndex];
4256 bApplyProperty.Click();
4257 end;
4258 Exit;
4259 end;
4260 vleObjectProperty.FindRow(_lc[I_PROP_TR_SOUND_NAME], i);
4261 if i <= 0 then
4262 vleObjectProperty.FindRow(_lc[I_PROP_TR_MUSIC_NAME], i);
4263 if i > 0 then
4264 begin
4265 AddSoundForm.OKFunction := nil;
4266 AddSoundForm.lbResourcesList.MultiSelect := False;
4267 AddSoundForm.SetResource := vleObjectProperty.Cells[1, i];
4269 if (AddSoundForm.ShowModal() = mrOk) then
4270 begin
4271 vleObjectProperty.Cells[1, i] := AddSoundForm.ResourceName;
4272 bApplyProperty.Click();
4273 end;
4274 Exit;
4275 end;
4276 vleObjectProperty.FindRow(_lc[I_PROP_TR_PUSH_ANGLE], i);
4277 if i <= 0 then
4278 vleObjectProperty.FindRow(_lc[I_PROP_TR_MESSAGE_TEXT], i);
4279 if i > 0 then
4280 begin
4281 vleObjectProperty.Row := i;
4282 vleObjectProperty.SetFocus();
4283 Exit;
4284 end;
4285 end;
4286 end;
4287 end;
4289 procedure TMainForm.aOptimizeExecute(Sender: TObject);
4290 begin
4291 RemoveSelectFromObjects();
4292 MapOptimizationForm.ShowModal();
4293 end;
4295 procedure TMainForm.aCheckMapExecute(Sender: TObject);
4296 begin
4297 MapCheckForm.ShowModal();
4298 end;
4300 procedure TMainForm.bbAddTextureClick(Sender: TObject);
4301 begin
4302 AddTextureForm.lbResourcesList.MultiSelect := True;
4303 AddTextureForm.ShowModal();
4304 end;
4306 procedure TMainForm.lbTextureListClick(Sender: TObject);
4307 var
4308 TextureID: DWORD;
4309 TextureWidth, TextureHeight: Word;
4310 begin
4311 if (lbTextureList.ItemIndex <> -1) and
4312 (not IsSpecialTextureSel()) then
4313 begin
4314 if g_GetTexture(SelectedTexture(), TextureID) then
4315 begin
4316 g_GetTextureSizeByID(TextureID, TextureWidth, TextureHeight);
4318 lTextureWidth.Caption := IntToStr(TextureWidth);
4319 lTextureHeight.Caption := IntToStr(TextureHeight);
4320 end else
4321 begin
4322 lTextureWidth.Caption := _lc[I_NOT_ACCESSIBLE];
4323 lTextureHeight.Caption := _lc[I_NOT_ACCESSIBLE];
4324 end;
4325 end
4326 else
4327 begin
4328 lTextureWidth.Caption := '';
4329 lTextureHeight.Caption := '';
4330 end;
4331 end;
4333 procedure TMainForm.vleObjectPropertyGetPickList(Sender: TObject;
4334 const KeyName: String; Values: TStrings);
4335 begin
4336 if vleObjectProperty.ItemProps[KeyName].EditStyle = esPickList then
4337 begin
4338 if KeyName = _lc[I_PROP_DIRECTION] then
4339 begin
4340 Values.Add(DirNames[D_LEFT]);
4341 Values.Add(DirNames[D_RIGHT]);
4342 end
4343 else if KeyName = _lc[I_PROP_TR_TELEPORT_DIR] then
4344 begin
4345 Values.Add(DirNamesAdv[0]);
4346 Values.Add(DirNamesAdv[1]);
4347 Values.Add(DirNamesAdv[2]);
4348 Values.Add(DirNamesAdv[3]);
4349 end
4350 else if KeyName = _lc[I_PROP_TR_MUSIC_ACT] then
4351 begin
4352 Values.Add(_lc[I_PROP_TR_MUSIC_ON]);
4353 Values.Add(_lc[I_PROP_TR_MUSIC_OFF]);
4354 end
4355 else if KeyName = _lc[I_PROP_TR_MONSTER_BEHAVIOUR] then
4356 begin
4357 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_0]);
4358 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_1]);
4359 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_2]);
4360 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_3]);
4361 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_4]);
4362 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_5]);
4363 end
4364 else if KeyName = _lc[I_PROP_TR_SCORE_ACT] then
4365 begin
4366 Values.Add(_lc[I_PROP_TR_SCORE_ACT_0]);
4367 Values.Add(_lc[I_PROP_TR_SCORE_ACT_1]);
4368 Values.Add(_lc[I_PROP_TR_SCORE_ACT_2]);
4369 Values.Add(_lc[I_PROP_TR_SCORE_ACT_3]);
4370 end
4371 else if KeyName = _lc[I_PROP_TR_SCORE_TEAM] then
4372 begin
4373 Values.Add(_lc[I_PROP_TR_SCORE_TEAM_0]);
4374 Values.Add(_lc[I_PROP_TR_SCORE_TEAM_1]);
4375 Values.Add(_lc[I_PROP_TR_SCORE_TEAM_2]);
4376 Values.Add(_lc[I_PROP_TR_SCORE_TEAM_3]);
4377 end
4378 else if KeyName = _lc[I_PROP_TR_MESSAGE_KIND] then
4379 begin
4380 Values.Add(_lc[I_PROP_TR_MESSAGE_KIND_0]);
4381 Values.Add(_lc[I_PROP_TR_MESSAGE_KIND_1]);
4382 end
4383 else if KeyName = _lc[I_PROP_TR_MESSAGE_TO] then
4384 begin
4385 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_0]);
4386 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_1]);
4387 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_2]);
4388 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_3]);
4389 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_4]);
4390 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_5]);
4391 end
4392 else if KeyName = _lc[I_PROP_TR_SHOT_TO] then
4393 begin
4394 Values.Add(_lc[I_PROP_TR_SHOT_TO_0]);
4395 Values.Add(_lc[I_PROP_TR_SHOT_TO_1]);
4396 Values.Add(_lc[I_PROP_TR_SHOT_TO_2]);
4397 Values.Add(_lc[I_PROP_TR_SHOT_TO_3]);
4398 Values.Add(_lc[I_PROP_TR_SHOT_TO_4]);
4399 Values.Add(_lc[I_PROP_TR_SHOT_TO_5]);
4400 Values.Add(_lc[I_PROP_TR_SHOT_TO_6]);
4401 end
4402 else if (KeyName = _lc[I_PROP_PANEL_BLEND]) or
4403 (KeyName = _lc[I_PROP_DM_ONLY]) or
4404 (KeyName = _lc[I_PROP_ITEM_FALLS]) or
4405 (KeyName = _lc[I_PROP_TR_ENABLED]) or
4406 (KeyName = _lc[I_PROP_TR_D2D]) or
4407 (KeyName = _lc[I_PROP_TR_SILENT]) or
4408 (KeyName = _lc[I_PROP_TR_TELEPORT_SILENT]) or
4409 (KeyName = _lc[I_PROP_TR_EX_RANDOM]) or
4410 (KeyName = _lc[I_PROP_TR_TEXTURE_ONCE]) or
4411 (KeyName = _lc[I_PROP_TR_TEXTURE_ANIM_ONCE]) or
4412 (KeyName = _lc[I_PROP_TR_SOUND_LOCAL]) or
4413 (KeyName = _lc[I_PROP_TR_SOUND_SWITCH]) or
4414 (KeyName = _lc[I_PROP_TR_MONSTER_ACTIVE]) or
4415 (KeyName = _lc[I_PROP_TR_PUSH_RESET]) or
4416 (KeyName = _lc[I_PROP_TR_SCORE_CON]) or
4417 (KeyName = _lc[I_PROP_TR_SCORE_MSG]) or
4418 (KeyName = _lc[I_PROP_TR_HEALTH_MAX]) or
4419 (KeyName = _lc[I_PROP_TR_SHOT_ALLMAP]) or
4420 (KeyName = _lc[I_PROP_TR_SHOT_SOUND]) or
4421 (KeyName = _lc[I_PROP_TR_EFFECT_CENTER]) then
4422 begin
4423 Values.Add(BoolNames[True]);
4424 Values.Add(BoolNames[False]);
4425 end;
4426 end;
4427 end;
4429 procedure TMainForm.bApplyPropertyClick(Sender: TObject);
4430 var
4431 _id, a, r, c: Integer;
4432 s: String;
4433 res: Boolean;
4434 NoTextureID: DWORD;
4435 NW, NH: Word;
4436 begin
4437 if SelectedObjectCount() <> 1 then
4438 Exit;
4439 if not SelectedObjects[GetFirstSelected()].Live then
4440 Exit;
4442 try
4443 if not CheckProperty() then
4444 Exit;
4445 except
4446 Exit;
4447 end;
4449 _id := GetFirstSelected();
4451 r := vleObjectProperty.Row;
4452 c := vleObjectProperty.Col;
4454 case SelectedObjects[_id].ObjectType of
4455 OBJECT_PANEL:
4456 begin
4457 with gPanels[SelectedObjects[_id].ID] do
4458 begin
4459 X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
4460 Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
4461 Width := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_WIDTH]]));
4462 Height := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_HEIGHT]]));
4464 PanelType := GetPanelType(vleObjectProperty.Values[_lc[I_PROP_PANEL_TYPE]]);
4466 // Сброс ссылки на триггеры смены текстуры:
4467 if not WordBool(PanelType and (PANEL_WALL or PANEL_FORE or PANEL_BACK)) then
4468 if gTriggers <> nil then
4469 for a := 0 to High(gTriggers) do
4470 begin
4471 if (gTriggers[a].TriggerType <> 0) and
4472 (gTriggers[a].TexturePanel = Integer(SelectedObjects[_id].ID)) then
4473 gTriggers[a].TexturePanel := -1;
4474 if (gTriggers[a].TriggerType = TRIGGER_SHOT) and
4475 (gTriggers[a].Data.ShotPanelID = Integer(SelectedObjects[_id].ID)) then
4476 gTriggers[a].Data.ShotPanelID := -1;
4477 end;
4479 // Сброс ссылки на триггеры лифта:
4480 if not WordBool(PanelType and (PANEL_LIFTUP or PANEL_LIFTDOWN or PANEL_LIFTLEFT or PANEL_LIFTRIGHT)) then
4481 if gTriggers <> nil then
4482 for a := 0 to High(gTriggers) do
4483 if (gTriggers[a].TriggerType in [TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT]) and
4484 (gTriggers[a].Data.PanelID = Integer(SelectedObjects[_id].ID)) then
4485 gTriggers[a].Data.PanelID := -1;
4487 // Сброс ссылки на триггеры двери:
4488 if not WordBool(PanelType and (PANEL_OPENDOOR or PANEL_CLOSEDOOR)) then
4489 if gTriggers <> nil then
4490 for a := 0 to High(gTriggers) do
4491 if (gTriggers[a].TriggerType in [TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
4492 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP]) and
4493 (gTriggers[a].Data.PanelID = Integer(SelectedObjects[_id].ID)) then
4494 gTriggers[a].Data.PanelID := -1;
4496 if IsTexturedPanel(PanelType) then
4497 begin // Может быть текстура
4498 if TextureName <> '' then
4499 begin // Была текстура
4500 Alpha := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_PANEL_ALPHA]]));
4501 Blending := NameToBool(vleObjectProperty.Values[_lc[I_PROP_PANEL_BLEND]]);
4502 end
4503 else // Не было
4504 begin
4505 Alpha := 0;
4506 Blending := False;
4507 end;
4509 // Новая текстура:
4510 TextureName := vleObjectProperty.Values[_lc[I_PROP_PANEL_TEX]];
4512 if TextureName <> '' then
4513 begin // Есть текстура
4514 // Обычная текстура:
4515 if not IsSpecialTexture(TextureName) then
4516 begin
4517 g_GetTextureSizeByName(TextureName,
4518 TextureWidth, TextureHeight);
4520 // Проверка кратности размеров панели:
4521 res := True;
4522 if TextureWidth <> 0 then
4523 if gPanels[SelectedObjects[_id].ID].Width mod TextureWidth <> 0 then
4524 begin
4525 ErrorMessageBox(Format(_lc[I_MSG_WRONG_TEXWIDTH],
4526 [TextureWidth]));
4527 Res := False;
4528 end;
4529 if Res and (TextureHeight <> 0) then
4530 if gPanels[SelectedObjects[_id].ID].Height mod TextureHeight <> 0 then
4531 begin
4532 ErrorMessageBox(Format(_lc[I_MSG_WRONG_TEXHEIGHT],
4533 [TextureHeight]));
4534 Res := False;
4535 end;
4537 if Res then
4538 begin
4539 if not g_GetTexture(TextureName, TextureID) then
4540 // Не удалось загрузить текстуру, рисуем NOTEXTURE
4541 if g_GetTexture('NOTEXTURE', NoTextureID) then
4542 begin
4543 TextureID := TEXTURE_SPECIAL_NOTEXTURE;
4544 g_GetTextureSizeByID(NoTextureID, NW, NH);
4545 TextureWidth := NW;
4546 TextureHeight := NH;
4547 end else
4548 begin
4549 TextureID := TEXTURE_SPECIAL_NONE;
4550 TextureWidth := 1;
4551 TextureHeight := 1;
4552 end;
4553 end
4554 else
4555 begin
4556 TextureName := '';
4557 TextureWidth := 1;
4558 TextureHeight := 1;
4559 TextureID := TEXTURE_SPECIAL_NONE;
4560 end;
4561 end
4562 else // Спец.текстура
4563 begin
4564 TextureHeight := 1;
4565 TextureWidth := 1;
4566 TextureID := SpecialTextureID(TextureName);
4567 end;
4568 end
4569 else // Нет текстуры
4570 begin
4571 TextureWidth := 1;
4572 TextureHeight := 1;
4573 TextureID := TEXTURE_SPECIAL_NONE;
4574 end;
4575 end
4576 else // Не может быть текстуры
4577 begin
4578 Alpha := 0;
4579 Blending := False;
4580 TextureName := '';
4581 TextureWidth := 1;
4582 TextureHeight := 1;
4583 TextureID := TEXTURE_SPECIAL_NONE;
4584 end;
4585 end;
4586 end;
4588 OBJECT_ITEM:
4589 begin
4590 with gItems[SelectedObjects[_id].ID] do
4591 begin
4592 X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
4593 Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
4594 OnlyDM := NameToBool(vleObjectProperty.Values[_lc[I_PROP_DM_ONLY]]);
4595 Fall := NameToBool(vleObjectProperty.Values[_lc[I_PROP_ITEM_FALLS]]);
4596 end;
4597 end;
4599 OBJECT_MONSTER:
4600 begin
4601 with gMonsters[SelectedObjects[_id].ID] do
4602 begin
4603 X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
4604 Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
4605 Direction := NameToDir(vleObjectProperty.Values[_lc[I_PROP_DIRECTION]]);
4606 end;
4607 end;
4609 OBJECT_AREA:
4610 begin
4611 with gAreas[SelectedObjects[_id].ID] do
4612 begin
4613 X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
4614 Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
4615 Direction := NameToDir(vleObjectProperty.Values[_lc[I_PROP_DIRECTION]]);
4616 end;
4617 end;
4619 OBJECT_TRIGGER:
4620 begin
4621 with gTriggers[SelectedObjects[_id].ID] do
4622 begin
4623 X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
4624 Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
4625 Width := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_WIDTH]]));
4626 Height := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_HEIGHT]]));
4627 Enabled := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_ENABLED]]);
4628 ActivateType := StrToActivate(vleObjectProperty.Values[_lc[I_PROP_TR_ACTIVATION]]);
4629 Key := StrToKey(vleObjectProperty.Values[_lc[I_PROP_TR_KEYS]]);
4631 case TriggerType of
4632 TRIGGER_EXIT:
4633 begin
4634 s := vleObjectProperty.Values[_lc[I_PROP_TR_NEXT_MAP]];
4635 ZeroMemory(@Data.MapName[0], 16);
4636 if s <> '' then
4637 CopyMemory(@Data.MapName[0], @s[1], Min(Length(s), 16));
4638 end;
4640 TRIGGER_TEXTURE:
4641 begin
4642 Data.ActivateOnce := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_TEXTURE_ONCE]]);
4643 Data.AnimOnce := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_TEXTURE_ANIM_ONCE]]);
4644 end;
4646 TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF:
4647 begin
4648 Data.Wait := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EX_DELAY]], 0), 65535);
4649 Data.Count := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EX_COUNT]], 0), 65535);
4650 if Data.Count < 1 then
4651 Data.Count := 1;
4652 if TriggerType = TRIGGER_PRESS then
4653 Data.ExtRandom := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_EX_RANDOM]]);
4654 end;
4656 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR, TRIGGER_DOOR5,
4657 TRIGGER_CLOSETRAP, TRIGGER_TRAP, TRIGGER_LIFTUP, TRIGGER_LIFTDOWN,
4658 TRIGGER_LIFT:
4659 begin
4660 Data.NoSound := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SILENT]]);
4661 Data.d2d_doors := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_D2D]]);
4662 end;
4664 TRIGGER_TELEPORT:
4665 begin
4666 Data.d2d_teleport := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_D2D]]);
4667 Data.silent_teleport := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_TELEPORT_SILENT]]);
4668 Data.TlpDir := NameToDirAdv(vleObjectProperty.Values[_lc[I_PROP_TR_TELEPORT_DIR]]);
4669 end;
4671 TRIGGER_SOUND:
4672 begin
4673 s := vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_NAME]];
4674 ZeroMemory(@Data.SoundName[0], 64);
4675 if s <> '' then
4676 CopyMemory(@Data.SoundName[0], @s[1], Min(Length(s), 64));
4678 Data.Volume := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_VOLUME]], 0), 255);
4679 Data.Pan := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_PAN]], 0), 255);
4680 Data.PlayCount := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_COUNT]], 0), 255);
4681 Data.Local := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_LOCAL]]);
4682 Data.SoundSwitch := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_SWITCH]]);
4683 end;
4685 TRIGGER_SPAWNMONSTER:
4686 begin
4687 Data.MonType := StrToMonster(vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_TYPE]]);
4688 Data.MonDir := Byte(NameToDir(vleObjectProperty.Values[_lc[I_PROP_DIRECTION]]));
4689 Data.MonHealth := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_HEALTH]], 0), 1000000);
4690 if Data.MonHealth < 0 then
4691 Data.MonHealth := 0;
4692 Data.MonActive := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_ACTIVE]]);
4693 Data.MonCount := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_COUNT]], 0), 64);
4694 if Data.MonCount < 1 then
4695 Data.MonCount := 1;
4696 Data.MonEffect := StrToEffect(vleObjectProperty.Values[_lc[I_PROP_TR_FX_TYPE]]);
4697 Data.MonMax := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SPAWN_MAX]], 0), 65535);
4698 Data.MonDelay := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SPAWN_DELAY]], 0), 65535);
4699 Data.MonBehav := 0;
4700 if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_1] then
4701 Data.MonBehav := 1;
4702 if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_2] then
4703 Data.MonBehav := 2;
4704 if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_3] then
4705 Data.MonBehav := 3;
4706 if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_4] then
4707 Data.MonBehav := 4;
4708 if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_5] then
4709 Data.MonBehav := 5;
4710 end;
4712 TRIGGER_SPAWNITEM:
4713 begin
4714 Data.ItemType := StrToItem(vleObjectProperty.Values[_lc[I_PROP_TR_ITEM_TYPE]]);
4715 Data.ItemOnlyDM := NameToBool(vleObjectProperty.Values[_lc[I_PROP_DM_ONLY]]);
4716 Data.ItemFalls := NameToBool(vleObjectProperty.Values[_lc[I_PROP_ITEM_FALLS]]);
4717 Data.ItemCount := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_COUNT]], 0), 64);
4718 if Data.ItemCount < 1 then
4719 Data.ItemCount := 1;
4720 Data.ItemEffect := StrToEffect(vleObjectProperty.Values[_lc[I_PROP_TR_FX_TYPE]]);
4721 Data.ItemMax := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SPAWN_MAX]], 0), 65535);
4722 Data.ItemDelay := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SPAWN_DELAY]], 0), 65535);
4723 end;
4725 TRIGGER_MUSIC:
4726 begin
4727 s := vleObjectProperty.Values[_lc[I_PROP_TR_MUSIC_NAME]];
4728 ZeroMemory(@Data.MusicName[0], 64);
4729 if s <> '' then
4730 CopyMemory(@Data.MusicName[0], @s[1], Min(Length(s), 64));
4732 if vleObjectProperty.Values[_lc[I_PROP_TR_MUSIC_ACT]] = _lc[I_PROP_TR_MUSIC_ON] then
4733 Data.MusicAction := 1
4734 else
4735 Data.MusicAction := 2;
4736 end;
4738 TRIGGER_PUSH:
4739 begin
4740 Data.PushAngle := Min(
4741 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_PUSH_ANGLE]], 0), 360);
4742 Data.PushForce := Min(
4743 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_PUSH_FORCE]], 0), 255);
4744 Data.ResetVel := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_PUSH_RESET]]);
4745 end;
4747 TRIGGER_SCORE:
4748 begin
4749 Data.ScoreAction := 0;
4750 if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_ACT]] = _lc[I_PROP_TR_SCORE_ACT_1] then
4751 Data.ScoreAction := 1
4752 else if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_ACT]] = _lc[I_PROP_TR_SCORE_ACT_2] then
4753 Data.ScoreAction := 2
4754 else if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_ACT]] = _lc[I_PROP_TR_SCORE_ACT_3] then
4755 Data.ScoreAction := 3;
4756 Data.ScoreCount := Min(Max(
4757 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_COUNT]], 0), 0), 255);
4758 Data.ScoreTeam := 0;
4759 if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_TEAM]] = _lc[I_PROP_TR_SCORE_TEAM_1] then
4760 Data.ScoreTeam := 1
4761 else if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_TEAM]] = _lc[I_PROP_TR_SCORE_TEAM_2] then
4762 Data.ScoreTeam := 2
4763 else if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_TEAM]] = _lc[I_PROP_TR_SCORE_TEAM_3] then
4764 Data.ScoreTeam := 3;
4765 Data.ScoreCon := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_CON]]);
4766 Data.ScoreMsg := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_MSG]]);
4767 end;
4769 TRIGGER_MESSAGE:
4770 begin
4771 Data.MessageKind := 0;
4772 if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_KIND]] = _lc[I_PROP_TR_MESSAGE_KIND_1] then
4773 Data.MessageKind := 1;
4775 Data.MessageSendTo := 0;
4776 if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_1] then
4777 Data.MessageSendTo := 1
4778 else if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_2] then
4779 Data.MessageSendTo := 2
4780 else if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_3] then
4781 Data.MessageSendTo := 3
4782 else if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_4] then
4783 Data.MessageSendTo := 4
4784 else if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_5] then
4785 Data.MessageSendTo := 5;
4787 s := vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TEXT]];
4788 ZeroMemory(@Data.MessageText[0], 100);
4789 if s <> '' then
4790 CopyMemory(@Data.MessageText[0], @s[1], Min(Length(s), 100));
4792 Data.MessageTime := Min(Max(
4793 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TIME]], 0), 0), 65535);
4794 end;
4796 TRIGGER_DAMAGE:
4797 begin
4798 Data.DamageValue := Min(Max(
4799 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_DAMAGE_VALUE]], 0), 0), 65535);
4800 Data.DamageInterval := Min(Max(
4801 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_INTERVAL]], 0), 0), 65535);
4802 end;
4804 TRIGGER_HEALTH:
4805 begin
4806 Data.HealValue := Min(Max(
4807 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_HEALTH]], 0), 0), 65535);
4808 Data.HealInterval := Min(Max(
4809 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_INTERVAL]], 0), 0), 65535);
4810 Data.HealMax := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_HEALTH_MAX]]);
4811 Data.HealSilent := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SILENT]]);
4812 end;
4814 TRIGGER_SHOT:
4815 begin
4816 Data.ShotType := StrToShot(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TYPE]]);
4817 Data.ShotSound := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_SOUND]]);
4818 Data.ShotTarget := 0;
4819 if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_1] then
4820 Data.ShotTarget := 1
4821 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_2] then
4822 Data.ShotTarget := 2
4823 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_3] then
4824 Data.ShotTarget := 3
4825 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_4] then
4826 Data.ShotTarget := 4
4827 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_5] then
4828 Data.ShotTarget := 5
4829 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_6] then
4830 Data.ShotTarget := 6;
4831 Data.ShotIntSight := Min(Max(
4832 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_SIGHT]], 0), 0), 65535);
4833 Data.ShotAllMap := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_ALLMAP]]);
4834 Data.ShotAngle := Min(
4835 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_ANGLE]], 0), 360);
4836 Data.ShotWait := Min(Max(
4837 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EX_DELAY]], 0), 0), 65535);
4838 Data.ShotAccuracy := Min(Max(
4839 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_ACC]], 0), 0), 65535);
4840 Data.ShotAmmo := Min(Max(
4841 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_AMMO]], 0), 0), 65535);
4842 Data.ShotIntReload := Min(Max(
4843 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_RELOAD]], 0), 0), 65535);
4844 end;
4846 TRIGGER_EFFECT:
4847 begin
4848 Data.FXCount := Min(Max(
4849 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_COUNT]], 0), 0), 255);
4850 if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_TYPE]] = _lc[I_PROP_TR_EFFECT_PARTICLE] then
4851 begin
4852 Data.FXType := TRIGGER_EFFECT_PARTICLE;
4853 Data.FXSubType := TRIGGER_EFFECT_SLIQUID;
4854 if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_SLIQUID] then
4855 Data.FXSubType := TRIGGER_EFFECT_SLIQUID
4856 else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_LLIQUID] then
4857 Data.FXSubType := TRIGGER_EFFECT_LLIQUID
4858 else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_DLIQUID] then
4859 Data.FXSubType := TRIGGER_EFFECT_DLIQUID
4860 else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_BLOOD] then
4861 Data.FXSubType := TRIGGER_EFFECT_BLOOD
4862 else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_SPARK] then
4863 Data.FXSubType := TRIGGER_EFFECT_SPARK
4864 else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_BUBBLE] then
4865 Data.FXSubType := TRIGGER_EFFECT_BUBBLE;
4866 end else
4867 begin
4868 Data.FXType := TRIGGER_EFFECT_ANIMATION;
4869 Data.FXSubType := StrToEffect(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]]);
4870 end;
4871 a := Min(Max(
4872 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_COLOR]], 0), 0), $FFFFFF);
4873 Data.FXColorR := a and $FF;
4874 Data.FXColorG := (a shr 8) and $FF;
4875 Data.FXColorB := (a shr 16) and $FF;
4876 if NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_CENTER]]) then
4877 Data.FXPos := 0
4878 else
4879 Data.FXPos := 1;
4880 Data.FXWait := Min(Max(
4881 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EX_DELAY]], 0), 0), 65535);
4882 Data.FXVelX := Min(Max(
4883 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_VELX]], 0), -128), 127);
4884 Data.FXVelY := Min(Max(
4885 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_VELY]], 0), -128), 127);
4886 Data.FXSpreadL := Min(Max(
4887 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SPL]], 0), 0), 255);
4888 Data.FXSpreadR := Min(Max(
4889 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SPR]], 0), 0), 255);
4890 Data.FXSpreadU := Min(Max(
4891 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SPU]], 0), 0), 255);
4892 Data.FXSpreadD := Min(Max(
4893 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SPD]], 0), 0), 255);
4894 end;
4895 end;
4896 end;
4897 end;
4898 end;
4900 FillProperty();
4902 vleObjectProperty.Row := r;
4903 vleObjectProperty.Col := c;
4904 end;
4906 procedure TMainForm.bbRemoveTextureClick(Sender: TObject);
4907 var
4908 a, i: Integer;
4909 begin
4910 i := lbTextureList.ItemIndex;
4911 if i = -1 then
4912 Exit;
4914 if MessageBox(0, PChar(Format(_lc[I_MSG_DEL_TEXTURE_PROMT],
4915 [SelectedTexture()])),
4916 PChar(_lc[I_MSG_DEL_TEXTURE]),
4917 MB_ICONQUESTION or MB_YESNO or
4918 MB_TASKMODAL or MB_DEFBUTTON1) <> idYes then
4919 Exit;
4921 if gPanels <> nil then
4922 for a := 0 to High(gPanels) do
4923 if (gPanels[a].PanelType <> 0) and
4924 (gPanels[a].TextureName = SelectedTexture()) then
4925 begin
4926 ErrorMessageBox(_lc[I_MSG_DEL_TEXTURE_CANT]);
4927 Exit;
4928 end;
4930 g_DeleteTexture(SelectedTexture());
4931 i := slInvalidTextures.IndexOf(lbTextureList.Items[i]);
4932 if i > -1 then
4933 slInvalidTextures.Delete(i);
4934 if lbTextureList.ItemIndex > -1 then
4935 lbTextureList.Items.Delete(lbTextureList.ItemIndex)
4936 end;
4938 procedure TMainForm.aNewMapExecute(Sender: TObject);
4939 begin
4940 if (MessageBox(0, PChar(_lc[I_MSG_CLEAR_MAP_PROMT]),
4941 PChar(_lc[I_MSG_CLEAR_MAP]),
4942 MB_ICONQUESTION or MB_YESNO or
4943 MB_TASKMODAL or MB_DEFBUTTON1) = mrYes) then
4944 FullClear();
4945 end;
4947 procedure TMainForm.aUndoExecute(Sender: TObject);
4948 var
4949 a: Integer;
4950 begin
4951 if UndoBuffer = nil then
4952 Exit;
4953 if UndoBuffer[High(UndoBuffer)] = nil then
4954 Exit;
4956 for a := 0 to High(UndoBuffer[High(UndoBuffer)]) do
4957 with UndoBuffer[High(UndoBuffer)][a] do
4958 begin
4959 case UndoType of
4960 UNDO_DELETE_PANEL:
4961 begin
4962 AddPanel(Panel^);
4963 Panel := nil;
4964 end;
4965 UNDO_DELETE_ITEM: AddItem(Item);
4966 UNDO_DELETE_AREA: AddArea(Area);
4967 UNDO_DELETE_MONSTER: AddMonster(Monster);
4968 UNDO_DELETE_TRIGGER: AddTrigger(Trigger);
4969 UNDO_ADD_PANEL: RemoveObject(AddID, OBJECT_PANEL);
4970 UNDO_ADD_ITEM: RemoveObject(AddID, OBJECT_ITEM);
4971 UNDO_ADD_AREA: RemoveObject(AddID, OBJECT_AREA);
4972 UNDO_ADD_MONSTER: RemoveObject(AddID, OBJECT_MONSTER);
4973 UNDO_ADD_TRIGGER: RemoveObject(AddID, OBJECT_TRIGGER);
4974 end;
4975 end;
4977 SetLength(UndoBuffer, Length(UndoBuffer)-1);
4979 RemoveSelectFromObjects();
4981 miUndo.Enabled := UndoBuffer <> nil;
4982 end;
4985 procedure TMainForm.aCopyObjectExecute(Sender: TObject);
4986 var
4987 a, b: Integer;
4988 CopyBuffer: TCopyRecArray;
4989 str: String;
4990 ok: Boolean;
4992 function CB_Compare(I1, I2: TCopyRec): Integer;
4993 begin
4994 Result := Integer(I1.ObjectType) - Integer(I2.ObjectType);
4996 if Result = 0 then // Одного типа
4997 Result := Integer(I1.ID) - Integer(I2.ID);
4998 end;
5000 procedure QuickSortCopyBuffer(L, R: Integer);
5001 var
5002 I, J: Integer;
5003 P, T: TCopyRec;
5004 begin
5005 repeat
5006 I := L;
5007 J := R;
5008 P := CopyBuffer[(L + R) shr 1];
5010 repeat
5011 while CB_Compare(CopyBuffer[I], P) < 0 do
5012 Inc(I);
5013 while CB_Compare(CopyBuffer[J], P) > 0 do
5014 Dec(J);
5016 if I <= J then
5017 begin
5018 T := CopyBuffer[I];
5019 CopyBuffer[I] := CopyBuffer[J];
5020 CopyBuffer[J] := T;
5021 Inc(I);
5022 Dec(J);
5023 end;
5024 until I > J;
5026 if L < J then
5027 QuickSortCopyBuffer(L, J);
5029 L := I;
5030 until I >= R;
5031 end;
5033 begin
5034 if SelectedObjects = nil then
5035 Exit;
5037 b := -1;
5038 CopyBuffer := nil;
5040 // Копируем объекты:
5041 for a := 0 to High(SelectedObjects) do
5042 if SelectedObjects[a].Live then
5043 with SelectedObjects[a] do
5044 begin
5045 SetLength(CopyBuffer, Length(CopyBuffer)+1);
5046 b := High(CopyBuffer);
5047 CopyBuffer[b].ID := ID;
5048 CopyBuffer[b].Panel := nil;
5050 case ObjectType of
5051 OBJECT_PANEL:
5052 begin
5053 CopyBuffer[b].ObjectType := OBJECT_PANEL;
5054 New(CopyBuffer[b].Panel);
5055 CopyBuffer[b].Panel^ := gPanels[ID];
5056 end;
5058 OBJECT_ITEM:
5059 begin
5060 CopyBuffer[b].ObjectType := OBJECT_ITEM;
5061 CopyBuffer[b].Item := gItems[ID];
5062 end;
5064 OBJECT_MONSTER:
5065 begin
5066 CopyBuffer[b].ObjectType := OBJECT_MONSTER;
5067 CopyBuffer[b].Monster := gMonsters[ID];
5068 end;
5070 OBJECT_AREA:
5071 begin
5072 CopyBuffer[b].ObjectType := OBJECT_AREA;
5073 CopyBuffer[b].Area := gAreas[ID];
5074 end;
5076 OBJECT_TRIGGER:
5077 begin
5078 CopyBuffer[b].ObjectType := OBJECT_TRIGGER;
5079 CopyBuffer[b].Trigger := gTriggers[ID];
5080 end;
5081 end;
5082 end;
5084 // Сортировка по ID:
5085 if CopyBuffer <> nil then
5086 begin
5087 QuickSortCopyBuffer(0, b);
5088 end;
5090 // Пестановка ссылок триггеров:
5091 for a := 0 to Length(CopyBuffer)-1 do
5092 if CopyBuffer[a].ObjectType = OBJECT_TRIGGER then
5093 begin
5094 case CopyBuffer[a].Trigger.TriggerType of
5095 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
5096 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP,
5097 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
5098 if CopyBuffer[a].Trigger.Data.PanelID <> -1 then
5099 begin
5100 ok := False;
5102 for b := 0 to Length(CopyBuffer)-1 do
5103 if (CopyBuffer[b].ObjectType = OBJECT_PANEL) and
5104 (Integer(CopyBuffer[b].ID) = CopyBuffer[a].Trigger.Data.PanelID) then
5105 begin
5106 CopyBuffer[a].Trigger.Data.PanelID := b;
5107 ok := True;
5108 Break;
5109 end;
5111 // Этих панелей нет среди копируемых:
5112 if not ok then
5113 CopyBuffer[a].Trigger.Data.PanelID := -1;
5114 end;
5116 TRIGGER_PRESS, TRIGGER_ON,
5117 TRIGGER_OFF, TRIGGER_ONOFF:
5118 if CopyBuffer[a].Trigger.Data.MonsterID <> 0 then
5119 begin
5120 ok := False;
5122 for b := 0 to Length(CopyBuffer)-1 do
5123 if (CopyBuffer[b].ObjectType = OBJECT_MONSTER) and
5124 (Integer(CopyBuffer[b].ID) = CopyBuffer[a].Trigger.Data.MonsterID-1) then
5125 begin
5126 CopyBuffer[a].Trigger.Data.MonsterID := b+1;
5127 ok := True;
5128 Break;
5129 end;
5131 // Этих монстров нет среди копируемых:
5132 if not ok then
5133 CopyBuffer[a].Trigger.Data.MonsterID := 0;
5134 end;
5136 TRIGGER_SHOT:
5137 if CopyBuffer[a].Trigger.Data.ShotPanelID <> -1 then
5138 begin
5139 ok := False;
5141 for b := 0 to Length(CopyBuffer)-1 do
5142 if (CopyBuffer[b].ObjectType = OBJECT_PANEL) and
5143 (Integer(CopyBuffer[b].ID) = CopyBuffer[a].Trigger.Data.ShotPanelID) then
5144 begin
5145 CopyBuffer[a].Trigger.Data.ShotPanelID := b;
5146 ok := True;
5147 Break;
5148 end;
5150 // Этих панелей нет среди копируемых:
5151 if not ok then
5152 CopyBuffer[a].Trigger.Data.ShotPanelID := -1;
5153 end;
5154 end;
5156 if CopyBuffer[a].Trigger.TexturePanel <> -1 then
5157 begin
5158 ok := False;
5160 for b := 0 to Length(CopyBuffer)-1 do
5161 if (CopyBuffer[b].ObjectType = OBJECT_PANEL) and
5162 (Integer(CopyBuffer[b].ID) = CopyBuffer[a].Trigger.TexturePanel) then
5163 begin
5164 CopyBuffer[a].Trigger.TexturePanel := b;
5165 ok := True;
5166 Break;
5167 end;
5169 // Этих панелей нет среди копируемых:
5170 if not ok then
5171 CopyBuffer[a].Trigger.TexturePanel := -1;
5172 end;
5173 end;
5175 // В буфер обмена:
5176 str := CopyBufferToString(CopyBuffer);
5177 ClipBoard.AsText := str;
5179 for a := 0 to Length(CopyBuffer)-1 do
5180 if (CopyBuffer[a].ObjectType = OBJECT_PANEL) and
5181 (CopyBuffer[a].Panel <> nil) then
5182 Dispose(CopyBuffer[a].Panel);
5184 CopyBuffer := nil;
5185 end;
5187 procedure TMainForm.aPasteObjectExecute(Sender: TObject);
5188 var
5189 a, h: Integer;
5190 CopyBuffer: TCopyRecArray;
5191 res: Boolean;
5192 swad, ssec, sres: String;
5193 begin
5194 CopyBuffer := nil;
5196 StringToCopyBuffer(ClipBoard.AsText, CopyBuffer);
5198 if CopyBuffer = nil then
5199 Exit;
5201 RemoveSelectFromObjects();
5203 h := High(CopyBuffer);
5204 for a := 0 to h do
5205 with CopyBuffer[a] do
5206 begin
5207 case ObjectType of
5208 OBJECT_PANEL:
5209 if Panel <> nil then
5210 begin
5211 Panel^.X := Panel^.X + 16;
5212 Panel^.Y := Panel^.Y + 16;
5214 Panel^.TextureID := TEXTURE_SPECIAL_NONE;
5215 Panel^.TextureWidth := 1;
5216 Panel^.TextureHeight := 1;
5218 if (Panel^.PanelType = PANEL_LIFTUP) or
5219 (Panel^.PanelType = PANEL_LIFTDOWN) or
5220 (Panel^.PanelType = PANEL_LIFTLEFT) or
5221 (Panel^.PanelType = PANEL_LIFTRIGHT) or
5222 (Panel^.PanelType = PANEL_BLOCKMON) or
5223 (Panel^.TextureName = '') then
5224 begin // Нет или не может быть текстуры:
5225 end
5226 else // Есть текстура:
5227 begin
5228 // Обычная текстура:
5229 if not IsSpecialTexture(Panel^.TextureName) then
5230 begin
5231 res := g_GetTexture(Panel^.TextureName, Panel^.TextureID);
5233 if not res then
5234 begin
5235 g_ProcessResourceStr(Panel^.TextureName, swad, ssec, sres);
5236 AddTexture(swad, ssec, sres, True);
5237 res := g_GetTexture(Panel^.TextureName, Panel^.TextureID);
5238 end;
5240 if res then
5241 g_GetTextureSizeByName(Panel^.TextureName,
5242 Panel^.TextureWidth, Panel^.TextureHeight)
5243 else
5244 Panel^.TextureName := '';
5245 end
5246 else // Спец.текстура:
5247 begin
5248 Panel^.TextureID := SpecialTextureID(Panel^.TextureName);
5249 with MainForm.lbTextureList.Items do
5250 if IndexOf(Panel^.TextureName) = -1 then
5251 Add(Panel^.TextureName);
5252 end;
5253 end;
5255 ID := AddPanel(Panel^);
5256 Dispose(Panel);
5257 Undo_Add(OBJECT_PANEL, ID, a > 0);
5258 SelectObject(OBJECT_PANEL, ID, True);
5259 end;
5261 OBJECT_ITEM:
5262 begin
5263 Item.X := Item.X + 16;
5264 Item.Y := Item.Y + 16;
5266 ID := AddItem(Item);
5267 Undo_Add(OBJECT_ITEM, ID, a > 0);
5268 SelectObject(OBJECT_ITEM, ID, True);
5269 end;
5271 OBJECT_MONSTER:
5272 begin
5273 Monster.X := Monster.X + 16;
5274 Monster.Y := Monster.Y + 16;
5276 ID := AddMonster(Monster);
5277 Undo_Add(OBJECT_MONSTER, ID, a > 0);
5278 SelectObject(OBJECT_MONSTER, ID, True);
5279 end;
5281 OBJECT_AREA:
5282 begin
5283 Area.X := Area.X + 16;
5284 Area.Y := Area.Y + 16;
5286 ID := AddArea(Area);
5287 Undo_Add(OBJECT_AREA, ID, a > 0);
5288 SelectObject(OBJECT_AREA, ID, True);
5289 end;
5291 OBJECT_TRIGGER:
5292 begin
5293 Trigger.X := Trigger.X + 16;
5294 Trigger.Y := Trigger.Y + 16;
5296 ID := AddTrigger(Trigger);
5297 Undo_Add(OBJECT_TRIGGER, ID, a > 0);
5298 SelectObject(OBJECT_TRIGGER, ID, True);
5299 end;
5300 end;
5301 end;
5303 // Переставляем ссылки триггеров:
5304 for a := 0 to High(CopyBuffer) do
5305 if CopyBuffer[a].ObjectType = OBJECT_TRIGGER then
5306 begin
5307 case CopyBuffer[a].Trigger.TriggerType of
5308 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
5309 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP,
5310 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
5311 if CopyBuffer[a].Trigger.Data.PanelID <> -1 then
5312 gTriggers[CopyBuffer[a].ID].Data.PanelID :=
5313 CopyBuffer[CopyBuffer[a].Trigger.Data.PanelID].ID;
5315 TRIGGER_PRESS, TRIGGER_ON,
5316 TRIGGER_OFF, TRIGGER_ONOFF:
5317 if CopyBuffer[a].Trigger.Data.MonsterID <> 0 then
5318 gTriggers[CopyBuffer[a].ID].Data.MonsterID :=
5319 CopyBuffer[CopyBuffer[a].Trigger.Data.MonsterID-1].ID+1;
5321 TRIGGER_SHOT:
5322 if CopyBuffer[a].Trigger.Data.ShotPanelID <> -1 then
5323 gTriggers[CopyBuffer[a].ID].Data.ShotPanelID :=
5324 CopyBuffer[CopyBuffer[a].Trigger.Data.ShotPanelID].ID;
5325 end;
5327 if CopyBuffer[a].Trigger.TexturePanel <> -1 then
5328 gTriggers[CopyBuffer[a].ID].TexturePanel :=
5329 CopyBuffer[CopyBuffer[a].Trigger.TexturePanel].ID;
5330 end;
5332 CopyBuffer := nil;
5334 if h = 0 then
5335 FillProperty();
5336 end;
5338 procedure TMainForm.aCutObjectExecute(Sender: TObject);
5339 begin
5340 miCopy.Click();
5341 DeleteSelectedObjects();
5342 end;
5344 procedure TMainForm.vleObjectPropertyEditButtonClick(Sender: TObject);
5345 var
5346 Key, FileName: String;
5347 b: Byte;
5348 begin
5349 Key := vleObjectProperty.Keys[vleObjectProperty.Row];
5351 if Key = _lc[I_PROP_PANEL_TYPE] then
5352 begin
5353 with ChooseTypeForm, vleObjectProperty do
5354 begin // Выбор типа панели:
5355 Caption := _lc[I_PROP_PANEL_TYPE];
5356 lbTypeSelect.Items.Clear();
5358 for b := 0 to High(PANELNAMES) do
5359 begin
5360 lbTypeSelect.Items.Add(PANELNAMES[b]);
5361 if Values[Key] = PANELNAMES[b] then
5362 lbTypeSelect.ItemIndex := b;
5363 end;
5365 if ShowModal() = mrOK then
5366 begin
5367 b := lbTypeSelect.ItemIndex;
5368 Values[Key] := PANELNAMES[b];
5369 bApplyProperty.Click();
5370 end;
5371 end
5372 end
5373 else if Key = _lc[I_PROP_TR_TELEPORT_TO] then
5374 SelectFlag := SELECTFLAG_TELEPORT
5375 else if Key = _lc[I_PROP_TR_SPAWN_TO] then
5376 SelectFlag := SELECTFLAG_SPAWNPOINT
5377 else if (Key = _lc[I_PROP_TR_DOOR_PANEL]) or
5378 (Key = _lc[I_PROP_TR_TRAP_PANEL]) then
5379 SelectFlag := SELECTFLAG_DOOR
5380 else if Key = _lc[I_PROP_TR_TEXTURE_PANEL] then
5381 begin
5382 DrawPressRect := False;
5383 SelectFlag := SELECTFLAG_TEXTURE;
5384 end
5385 else if Key = _lc[I_PROP_TR_SHOT_PANEL] then
5386 SelectFlag := SELECTFLAG_SHOTPANEL
5387 else if Key = _lc[I_PROP_TR_LIFT_PANEL] then
5388 SelectFlag := SELECTFLAG_LIFT
5389 else if key = _lc[I_PROP_TR_EX_MONSTER] then
5390 SelectFlag := SELECTFLAG_MONSTER
5391 else if Key = _lc[I_PROP_TR_EX_AREA] then
5392 begin
5393 SelectFlag := SELECTFLAG_NONE;
5394 DrawPressRect := True;
5395 end
5396 else if Key = _lc[I_PROP_TR_NEXT_MAP] then
5397 begin // Выбор следующей карты:
5398 g_ProcessResourceStr(OpenedMap, @FileName, nil, nil);
5399 SelectMapForm.GetMaps(FileName);
5401 if SelectMapForm.ShowModal() = mrOK then
5402 begin
5403 vleObjectProperty.Values[Key] := SelectMapForm.lbMapList.Items[SelectMapForm.lbMapList.ItemIndex];
5404 bApplyProperty.Click();
5405 end;
5406 end
5407 else if (Key = _lc[I_PROP_TR_SOUND_NAME]) or
5408 (Key = _lc[I_PROP_TR_MUSIC_NAME]) then
5409 begin // Выбор файла звука/музыки:
5410 AddSoundForm.OKFunction := nil;
5411 AddSoundForm.lbResourcesList.MultiSelect := False;
5412 AddSoundForm.SetResource := vleObjectProperty.Values[Key];
5414 if (AddSoundForm.ShowModal() = mrOk) then
5415 begin
5416 vleObjectProperty.Values[Key] := AddSoundForm.ResourceName;
5417 bApplyProperty.Click();
5418 end;
5419 end
5420 else if Key = _lc[I_PROP_TR_ACTIVATION] then
5421 with ActivationTypeForm, vleObjectProperty do
5422 begin // Выбор типов активации:
5423 cbPlayerCollide.Checked := Pos('PC', Values[Key]) > 0;
5424 cbMonsterCollide.Checked := Pos('MC', Values[Key]) > 0;
5425 cbPlayerPress.Checked := Pos('PP', Values[Key]) > 0;
5426 cbMonsterPress.Checked := Pos('MP', Values[Key]) > 0;
5427 cbShot.Checked := Pos('SH', Values[Key]) > 0;
5428 cbNoMonster.Checked := Pos('NM', Values[Key]) > 0;
5430 if ShowModal() = mrOK then
5431 begin
5432 b := 0;
5433 if cbPlayerCollide.Checked then
5434 b := ACTIVATE_PLAYERCOLLIDE;
5435 if cbMonsterCollide.Checked then
5436 b := b or ACTIVATE_MONSTERCOLLIDE;
5437 if cbPlayerPress.Checked then
5438 b := b or ACTIVATE_PLAYERPRESS;
5439 if cbMonsterPress.Checked then
5440 b := b or ACTIVATE_MONSTERPRESS;
5441 if cbShot.Checked then
5442 b := b or ACTIVATE_SHOT;
5443 if cbNoMonster.Checked then
5444 b := b or ACTIVATE_NOMONSTER;
5446 Values[Key] := ActivateToStr(b);
5447 bApplyProperty.Click();
5448 end;
5449 end
5450 else if Key = _lc[I_PROP_TR_KEYS] then
5451 with KeysForm, vleObjectProperty do
5452 begin // Выбор необходимых ключей:
5453 cbRedKey.Checked := Pos('RK', Values[Key]) > 0;
5454 cbGreenKey.Checked := Pos('GK', Values[Key]) > 0;
5455 cbBlueKey.Checked := Pos('BK', Values[Key]) > 0;
5456 cbRedTeam.Checked := Pos('RT', Values[Key]) > 0;
5457 cbBlueTeam.Checked := Pos('BT', Values[Key]) > 0;
5459 if ShowModal() = mrOK then
5460 begin
5461 b := 0;
5462 if cbRedKey.Checked then
5463 b := KEY_RED;
5464 if cbGreenKey.Checked then
5465 b := b or KEY_GREEN;
5466 if cbBlueKey.Checked then
5467 b := b or KEY_BLUE;
5468 if cbRedTeam.Checked then
5469 b := b or KEY_REDTEAM;
5470 if cbBlueTeam.Checked then
5471 b := b or KEY_BLUETEAM;
5473 Values[Key] := KeyToStr(b);
5474 bApplyProperty.Click();
5475 end;
5476 end
5477 else if Key = _lc[I_PROP_TR_FX_TYPE] then
5478 with ChooseTypeForm, vleObjectProperty do
5479 begin // Выбор типа эффекта:
5480 Caption := _lc[I_CAP_FX_TYPE];
5481 lbTypeSelect.Items.Clear();
5483 for b := EFFECT_NONE to EFFECT_FIRE do
5484 lbTypeSelect.Items.Add(EffectToStr(b));
5486 lbTypeSelect.ItemIndex := StrToEffect(Values[Key]);
5488 if ShowModal() = mrOK then
5489 begin
5490 b := lbTypeSelect.ItemIndex;
5491 Values[Key] := EffectToStr(b);
5492 bApplyProperty.Click();
5493 end;
5494 end
5495 else if Key = _lc[I_PROP_TR_MONSTER_TYPE] then
5496 with ChooseTypeForm, vleObjectProperty do
5497 begin // Выбор типа монстра:
5498 Caption := _lc[I_CAP_MONSTER_TYPE];
5499 lbTypeSelect.Items.Clear();
5501 for b := MONSTER_DEMON to MONSTER_MAN do
5502 lbTypeSelect.Items.Add(MonsterToStr(b));
5504 lbTypeSelect.ItemIndex := StrToMonster(Values[Key]) - MONSTER_DEMON;
5506 if ShowModal() = mrOK then
5507 begin
5508 b := lbTypeSelect.ItemIndex + MONSTER_DEMON;
5509 Values[Key] := MonsterToStr(b);
5510 bApplyProperty.Click();
5511 end;
5512 end
5513 else if Key = _lc[I_PROP_TR_ITEM_TYPE] then
5514 with ChooseTypeForm, vleObjectProperty do
5515 begin // Выбор типа предмета:
5516 Caption := _lc[I_CAP_ITEM_TYPE];
5517 lbTypeSelect.Items.Clear();
5519 for b := ITEM_MEDKIT_SMALL to ITEM_KEY_BLUE do
5520 lbTypeSelect.Items.Add(ItemToStr(b));
5521 lbTypeSelect.Items.Add(ItemToStr(ITEM_BOTTLE));
5522 lbTypeSelect.Items.Add(ItemToStr(ITEM_HELMET));
5523 lbTypeSelect.Items.Add(ItemToStr(ITEM_JETPACK));
5524 lbTypeSelect.Items.Add(ItemToStr(ITEM_INVIS));
5526 b := StrToItem(Values[Key]);
5527 if b >= ITEM_BOTTLE then
5528 b := b - 2;
5529 lbTypeSelect.ItemIndex := b - ITEM_MEDKIT_SMALL;
5531 if ShowModal() = mrOK then
5532 begin
5533 b := lbTypeSelect.ItemIndex + ITEM_MEDKIT_SMALL;
5534 if b >= ITEM_WEAPON_KASTET then
5535 b := b + 2;
5536 Values[Key] := ItemToStr(b);
5537 bApplyProperty.Click();
5538 end;
5539 end
5540 else if Key = _lc[I_PROP_TR_SHOT_TYPE] then
5541 with ChooseTypeForm, vleObjectProperty do
5542 begin // Выбор типа предмета:
5543 Caption := _lc[I_PROP_TR_SHOT_TYPE];
5544 lbTypeSelect.Items.Clear();
5546 for b := TRIGGER_SHOT_PISTOL to TRIGGER_SHOT_MAX do
5547 lbTypeSelect.Items.Add(ShotToStr(b));
5549 lbTypeSelect.ItemIndex := StrToShot(Values[Key]);
5551 if ShowModal() = mrOK then
5552 begin
5553 b := lbTypeSelect.ItemIndex;
5554 Values[Key] := ShotToStr(b);
5555 bApplyProperty.Click();
5556 end;
5557 end
5558 else if Key = _lc[I_PROP_TR_EFFECT_TYPE] then
5559 with ChooseTypeForm, vleObjectProperty do
5560 begin // Выбор типа эффекта:
5561 Caption := _lc[I_CAP_FX_TYPE];
5562 lbTypeSelect.Items.Clear();
5564 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_PARTICLE]);
5565 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_ANIMATION]);
5566 if Values[Key] = _lc[I_PROP_TR_EFFECT_ANIMATION] then
5567 lbTypeSelect.ItemIndex := 1
5568 else
5569 lbTypeSelect.ItemIndex := 0;
5571 if ShowModal() = mrOK then
5572 begin
5573 b := lbTypeSelect.ItemIndex;
5574 if b = 0 then
5575 Values[Key] := _lc[I_PROP_TR_EFFECT_PARTICLE]
5576 else
5577 Values[Key] := _lc[I_PROP_TR_EFFECT_ANIMATION];
5578 bApplyProperty.Click();
5579 end;
5580 end
5581 else if Key = _lc[I_PROP_TR_EFFECT_SUBTYPE] then
5582 with ChooseTypeForm, vleObjectProperty do
5583 begin // Выбор подтипа эффекта:
5584 Caption := _lc[I_CAP_FX_TYPE];
5585 lbTypeSelect.Items.Clear();
5587 if Values[_lc[I_PROP_TR_EFFECT_TYPE]] = _lc[I_PROP_TR_EFFECT_ANIMATION] then
5588 begin
5589 for b := EFFECT_TELEPORT to EFFECT_FIRE do
5590 lbTypeSelect.Items.Add(EffectToStr(b));
5592 lbTypeSelect.ItemIndex := StrToEffect(Values[Key]) - 1;
5593 end else
5594 begin
5595 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_SLIQUID]);
5596 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_LLIQUID]);
5597 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_DLIQUID]);
5598 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_BLOOD]);
5599 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_SPARK]);
5600 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_BUBBLE]);
5601 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_SLIQUID;
5602 if Values[Key] = _lc[I_PROP_TR_EFFECT_LLIQUID] then
5603 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_LLIQUID;
5604 if Values[Key] = _lc[I_PROP_TR_EFFECT_DLIQUID] then
5605 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_DLIQUID;
5606 if Values[Key] = _lc[I_PROP_TR_EFFECT_BLOOD] then
5607 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_BLOOD;
5608 if Values[Key] = _lc[I_PROP_TR_EFFECT_SPARK] then
5609 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_SPARK;
5610 if Values[Key] = _lc[I_PROP_TR_EFFECT_BUBBLE] then
5611 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_BUBBLE;
5612 end;
5614 if ShowModal() = mrOK then
5615 begin
5616 b := lbTypeSelect.ItemIndex;
5618 if Values[_lc[I_PROP_TR_EFFECT_TYPE]] = _lc[I_PROP_TR_EFFECT_ANIMATION] then
5619 Values[Key] := EffectToStr(b + 1)
5620 else begin
5621 Values[Key] := _lc[I_PROP_TR_EFFECT_SLIQUID];
5622 if b = TRIGGER_EFFECT_LLIQUID then
5623 Values[Key] := _lc[I_PROP_TR_EFFECT_LLIQUID];
5624 if b = TRIGGER_EFFECT_DLIQUID then
5625 Values[Key] := _lc[I_PROP_TR_EFFECT_DLIQUID];
5626 if b = TRIGGER_EFFECT_BLOOD then
5627 Values[Key] := _lc[I_PROP_TR_EFFECT_BLOOD];
5628 if b = TRIGGER_EFFECT_SPARK then
5629 Values[Key] := _lc[I_PROP_TR_EFFECT_SPARK];
5630 if b = TRIGGER_EFFECT_BUBBLE then
5631 Values[Key] := _lc[I_PROP_TR_EFFECT_BUBBLE];
5632 end;
5634 bApplyProperty.Click();
5635 end;
5636 end
5637 else if Key = _lc[I_PROP_TR_EFFECT_COLOR] then
5638 with vleObjectProperty do
5639 begin // Выбор цвета эффекта:
5640 ColorDialog.Color := StrToIntDef(Values[Key], 0);
5641 if ColorDialog.Execute then
5642 begin
5643 Values[Key] := IntToStr(ColorDialog.Color);
5644 bApplyProperty.Click();
5645 end;
5646 end
5647 else if Key = _lc[I_PROP_PANEL_TEX] then
5648 begin // Смена текстуры:
5649 vleObjectProperty.Values[Key] := SelectedTexture();
5650 bApplyProperty.Click();
5651 end;
5652 end;
5654 procedure TMainForm.aSaveMapExecute(Sender: TObject);
5655 var
5656 FileName, Section, Res: String;
5657 begin
5658 if OpenedMap = '' then
5659 begin
5660 aSaveMapAsExecute(nil);
5661 Exit;
5662 end;
5664 g_ProcessResourceStr(OpenedMap, FileName, Section, Res);
5666 SaveMap(FileName+':\'+Res);
5667 end;
5669 procedure TMainForm.aOpenMapExecute(Sender: TObject);
5670 begin
5671 OpenDialog.Filter := _lc[I_FILE_FILTER_ALL];
5673 if OpenDialog.Execute() then
5674 begin
5675 if (Pos('.ini', LowerCase(ExtractFileName(OpenDialog.FileName))) > 0) then
5676 begin // INI карты:
5677 FullClear();
5679 pLoadProgress.Left := (RenderPanel.Width div 2)-(pLoadProgress.Width div 2);
5680 pLoadProgress.Top := (RenderPanel.Height div 2)-(pLoadProgress.Height div 2);
5681 pLoadProgress.Show();
5683 OpenedMap := '';
5684 OpenedWAD := '';
5686 LoadMapOld(OpenDialog.FileName);
5688 MainForm.Caption := Format('%s - %s', [FormCaption, ExtractFileName(OpenDialog.FileName)]);
5690 pLoadProgress.Hide();
5691 MainForm.FormResize(Self);
5692 end
5693 else // Карты из WAD:
5694 begin
5695 OpenMap(OpenDialog.FileName, '');
5696 end;
5698 OpenDialog.InitialDir := ExtractFileDir(OpenDialog.FileName);
5699 end;
5700 end;
5702 procedure TMainForm.FormActivate(Sender: TObject);
5703 var
5704 lang: Integer;
5705 config: TConfig;
5706 begin
5707 MainForm.ActiveControl := RenderPanel;
5709 // Язык:
5710 if gLanguage = '' then
5711 begin
5712 lang := SelectLanguageForm.ShowModal();
5713 case lang of
5714 1: gLanguage := LANGUAGE_ENGLISH;
5715 else gLanguage := LANGUAGE_RUSSIAN;
5716 end;
5718 config := TConfig.CreateFile(EditorDir+'\Editor.cfg');
5719 config.WriteStr('Editor', 'Language', gLanguage);
5720 config.SaveFile(EditorDir+'\Editor.cfg');
5721 config.Free();
5722 end;
5724 //e_WriteLog('Read language file', MSG_NOTIFY);
5725 //g_Language_Load(EditorDir+'\data\'+gLanguage+LANGUAGE_FILE_NAME);
5726 g_Language_Set(gLanguage);
5727 end;
5729 procedure TMainForm.aDeleteMap(Sender: TObject);
5730 var
5731 WAD: TWADEditor_1;
5732 MapList: SArray;
5733 MapName: Char16;
5734 a: Integer;
5735 str: String;
5736 begin
5737 OpenDialog.Filter := _lc[I_FILE_FILTER_WAD];
5739 if not OpenDialog.Execute() then
5740 Exit;
5742 WAD := TWADEditor_1.Create();
5744 if not WAD.ReadFile(OpenDialog.FileName) then
5745 begin
5746 WAD.Free();
5747 Exit;
5748 end;
5750 WAD.CreateImage();
5752 MapList := WAD.GetResourcesList('');
5754 SelectMapForm.lbMapList.Items.Clear();
5756 if MapList <> nil then
5757 for a := 0 to High(MapList) do
5758 SelectMapForm.lbMapList.Items.Add(MapList[a]);
5760 if (SelectMapForm.ShowModal() = mrOK) then
5761 begin
5762 str := SelectMapForm.lbMapList.Items[SelectMapForm.lbMapList.ItemIndex];
5763 MapName := '';
5764 CopyMemory(@MapName[0], @str[1], Min(16, Length(str)));
5766 if MessageBox(0, PChar(Format(_lc[I_MSG_DELETE_MAP_PROMT],
5767 [MapName, OpenDialog.FileName])),
5768 PChar(_lc[I_MSG_DELETE_MAP]),
5769 MB_ICONQUESTION or MB_YESNO or
5770 MB_TASKMODAL or MB_DEFBUTTON2) <> mrYes then
5771 Exit;
5773 WAD.RemoveResource('', MapName);
5775 MessageBox(0, PChar(Format(_lc[I_MSG_MAP_DELETED_PROMT],
5776 [MapName])),
5777 PChar(_lc[I_MSG_MAP_DELETED]),
5778 MB_ICONINFORMATION or MB_OK or
5779 MB_TASKMODAL or MB_DEFBUTTON1);
5781 WAD.SaveTo(OpenDialog.FileName);
5783 // Удалили текущую карту - сохранять по старому ее нельзя:
5784 if OpenedMap = (OpenDialog.FileName+':\'+MapName) then
5785 begin
5786 OpenedMap := '';
5787 OpenedWAD := '';
5788 MainForm.Caption := FormCaption;
5789 end;
5790 end;
5792 WAD.Free();
5793 end;
5795 procedure TMainForm.vleObjectPropertyKeyDown(Sender: TObject;
5796 var Key: Word; Shift: TShiftState);
5797 begin
5798 if Key = VK_RETURN then
5799 bApplyProperty.Click();
5800 end;
5802 procedure MovePanel(var ID: DWORD; MoveType: Byte);
5803 var
5804 _id, a: Integer;
5805 tmp: TPanel;
5806 begin
5807 if (ID = 0) and (MoveType = 0) then
5808 Exit;
5809 if (ID = DWORD(High(gPanels))) and (MoveType <> 0) then
5810 Exit;
5811 if (ID > DWORD(High(gPanels))) then
5812 Exit;
5814 _id := Integer(ID);
5816 if MoveType = 0 then // to Back
5817 begin
5818 if gTriggers <> nil then
5819 for a := 0 to High(gTriggers) do
5820 with gTriggers[a] do
5821 begin
5822 if TriggerType = TRIGGER_NONE then
5823 Continue;
5825 if TexturePanel = _id then
5826 TexturePanel := 0
5827 else
5828 if (TexturePanel >= 0) and (TexturePanel < _id) then
5829 Inc(TexturePanel);
5831 case TriggerType of
5832 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
5833 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP,
5834 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
5835 if Data.PanelID = _id then
5836 Data.PanelID := 0
5837 else
5838 if (Data.PanelID >= 0) and (Data.PanelID < _id) then
5839 Inc(Data.PanelID);
5841 TRIGGER_SHOT:
5842 if Data.ShotPanelID = _id then
5843 Data.ShotPanelID := 0
5844 else
5845 if (Data.ShotPanelID >= 0) and (Data.ShotPanelID < _id) then
5846 Inc(Data.ShotPanelID);
5847 end;
5848 end;
5850 tmp := gPanels[_id];
5852 for a := _id downto 1 do
5853 gPanels[a] := gPanels[a-1];
5855 gPanels[0] := tmp;
5857 ID := 0;
5858 end
5859 else // to Front
5860 begin
5861 if gTriggers <> nil then
5862 for a := 0 to High(gTriggers) do
5863 with gTriggers[a] do
5864 begin
5865 if TriggerType = TRIGGER_NONE then
5866 Continue;
5868 if TexturePanel = _id then
5869 TexturePanel := High(gPanels)
5870 else
5871 if TexturePanel > _id then
5872 Dec(TexturePanel);
5874 case TriggerType of
5875 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
5876 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP,
5877 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
5878 if Data.PanelID = _id then
5879 Data.PanelID := High(gPanels)
5880 else
5881 if Data.PanelID > _id then
5882 Dec(Data.PanelID);
5884 TRIGGER_SHOT:
5885 if Data.ShotPanelID = _id then
5886 Data.ShotPanelID := High(gPanels)
5887 else
5888 if Data.ShotPanelID > _id then
5889 Dec(Data.ShotPanelID);
5890 end;
5891 end;
5893 tmp := gPanels[_id];
5895 for a := _id to High(gPanels)-1 do
5896 gPanels[a] := gPanels[a+1];
5898 gPanels[High(gPanels)] := tmp;
5900 ID := High(gPanels);
5901 end;
5902 end;
5904 procedure TMainForm.aMoveToBack(Sender: TObject);
5905 var
5906 a: Integer;
5907 begin
5908 if SelectedObjects = nil then
5909 Exit;
5911 for a := 0 to High(SelectedObjects) do
5912 with SelectedObjects[a] do
5913 if Live and (ObjectType = OBJECT_PANEL) then
5914 begin
5915 SelectedObjects[0] := SelectedObjects[a];
5916 SetLength(SelectedObjects, 1);
5917 MovePanel(ID, 0);
5918 FillProperty();
5919 Break;
5920 end;
5921 end;
5923 procedure TMainForm.aMoveToFore(Sender: TObject);
5924 var
5925 a: Integer;
5926 begin
5927 if SelectedObjects = nil then
5928 Exit;
5930 for a := 0 to High(SelectedObjects) do
5931 with SelectedObjects[a] do
5932 if Live and (ObjectType = OBJECT_PANEL) then
5933 begin
5934 SelectedObjects[0] := SelectedObjects[a];
5935 SetLength(SelectedObjects, 1);
5936 MovePanel(ID, 1);
5937 FillProperty();
5938 Break;
5939 end;
5940 end;
5942 procedure TMainForm.aSaveMapAsExecute(Sender: TObject);
5943 var
5944 idx: Integer;
5945 begin
5946 SaveDialog.Filter := _lc[I_FILE_FILTER_WAD];
5948 if not SaveDialog.Execute() then
5949 Exit;
5951 SaveMapForm.GetMaps(SaveDialog.FileName, True);
5953 if SaveMapForm.ShowModal() <> mrOK then
5954 Exit;
5956 SaveDialog.InitialDir := ExtractFileDir(SaveDialog.FileName);
5957 OpenedMap := SaveDialog.FileName+':\'+SaveMapForm.eMapName.Text;
5958 OpenedWAD := SaveDialog.FileName;
5960 idx := RecentFiles.IndexOf(OpenedMap);
5961 // Такая карта уже недавно открывалась:
5962 if idx >= 0 then
5963 RecentFiles.Delete(idx);
5964 RecentFiles.Insert(0, OpenedMap);
5965 RefreshRecentMenu;
5967 SaveMap(OpenedMap);
5969 gMapInfo.FileName := SaveDialog.FileName;
5970 gMapInfo.MapName := SaveMapForm.eMapName.Text;
5971 UpdateCaption(gMapInfo.Name, ExtractFileName(gMapInfo.FileName), gMapInfo.MapName);
5972 end;
5974 procedure TMainForm.aSelectAllExecute(Sender: TObject);
5975 var
5976 a: Integer;
5977 begin
5978 RemoveSelectFromObjects();
5980 case pcObjects.ActivePageIndex+1 of
5981 OBJECT_PANEL:
5982 if gPanels <> nil then
5983 for a := 0 to High(gPanels) do
5984 if gPanels[a].PanelType <> PANEL_NONE then
5985 SelectObject(OBJECT_PANEL, a, True);
5986 OBJECT_ITEM:
5987 if gItems <> nil then
5988 for a := 0 to High(gItems) do
5989 if gItems[a].ItemType <> ITEM_NONE then
5990 SelectObject(OBJECT_ITEM, a, True);
5991 OBJECT_MONSTER:
5992 if gMonsters <> nil then
5993 for a := 0 to High(gMonsters) do
5994 if gMonsters[a].MonsterType <> MONSTER_NONE then
5995 SelectObject(OBJECT_MONSTER, a, True);
5996 OBJECT_AREA:
5997 if gAreas <> nil then
5998 for a := 0 to High(gAreas) do
5999 if gAreas[a].AreaType <> AREA_NONE then
6000 SelectObject(OBJECT_AREA, a, True);
6001 OBJECT_TRIGGER:
6002 if gTriggers <> nil then
6003 for a := 0 to High(gTriggers) do
6004 if gTriggers[a].TriggerType <> TRIGGER_NONE then
6005 SelectObject(OBJECT_TRIGGER, a, True);
6006 end;
6007 end;
6009 procedure TMainForm.tbGridOnClick(Sender: TObject);
6010 begin
6011 DotEnable := not DotEnable;
6012 (Sender as TToolButton).Down := DotEnable;
6013 end;
6015 procedure TMainForm.OnIdle(Sender: TObject; var Done: Boolean);
6016 begin
6017 Draw();
6018 end;
6020 procedure TMainForm.miMapPreviewClick(Sender: TObject);
6021 begin
6022 if not PreviewMode then
6023 begin
6024 Splitter2.Visible := False;
6025 Splitter1.Visible := False;
6026 StatusBar.Visible := False;
6027 PanelObjs.Visible := False;
6028 PanelProps.Visible := False;
6029 MainToolBar.Visible := False;
6030 sbHorizontal.Visible := False;
6031 sbVertical.Visible := False;
6032 end
6033 else
6034 begin
6035 StatusBar.Visible := True;
6036 PanelObjs.Visible := True;
6037 PanelProps.Visible := True;
6038 Splitter2.Visible := True;
6039 Splitter1.Visible := True;
6040 MainToolBar.Visible := True;
6041 sbHorizontal.Visible := True;
6042 sbVertical.Visible := True;
6043 end;
6045 PreviewMode := not PreviewMode;
6046 (Sender as TMenuItem).Checked := PreviewMode;
6047 end;
6049 procedure TMainForm.miLayer1Click(Sender: TObject);
6050 begin
6051 SwitchLayer(LAYER_BACK);
6052 end;
6054 procedure TMainForm.miLayer2Click(Sender: TObject);
6055 begin
6056 SwitchLayer(LAYER_WALLS);
6057 end;
6059 procedure TMainForm.miLayer3Click(Sender: TObject);
6060 begin
6061 SwitchLayer(LAYER_FOREGROUND);
6062 end;
6064 procedure TMainForm.miLayer4Click(Sender: TObject);
6065 begin
6066 SwitchLayer(LAYER_STEPS);
6067 end;
6069 procedure TMainForm.miLayer5Click(Sender: TObject);
6070 begin
6071 SwitchLayer(LAYER_WATER);
6072 end;
6074 procedure TMainForm.miLayer6Click(Sender: TObject);
6075 begin
6076 SwitchLayer(LAYER_ITEMS);
6077 end;
6079 procedure TMainForm.miLayer7Click(Sender: TObject);
6080 begin
6081 SwitchLayer(LAYER_MONSTERS);
6082 end;
6084 procedure TMainForm.miLayer8Click(Sender: TObject);
6085 begin
6086 SwitchLayer(LAYER_AREAS);
6087 end;
6089 procedure TMainForm.miLayer9Click(Sender: TObject);
6090 begin
6091 SwitchLayer(LAYER_TRIGGERS);
6092 end;
6094 procedure TMainForm.tbShowClick(Sender: TObject);
6095 var
6096 a: Integer;
6097 b: Boolean;
6098 begin
6099 b := True;
6100 for a := 0 to High(LayerEnabled) do
6101 b := b and LayerEnabled[a];
6103 b := not b;
6105 ShowLayer(LAYER_BACK, b);
6106 ShowLayer(LAYER_WALLS, b);
6107 ShowLayer(LAYER_FOREGROUND, b);
6108 ShowLayer(LAYER_STEPS, b);
6109 ShowLayer(LAYER_WATER, b);
6110 ShowLayer(LAYER_ITEMS, b);
6111 ShowLayer(LAYER_MONSTERS, b);
6112 ShowLayer(LAYER_AREAS, b);
6113 ShowLayer(LAYER_TRIGGERS, b);
6114 end;
6116 procedure TMainForm.miMiniMapClick(Sender: TObject);
6117 begin
6118 SwitchMap();
6119 end;
6121 procedure TMainForm.miSwitchGridClick(Sender: TObject);
6122 begin
6123 if DotStep = DotStepOne then
6124 DotStep := DotStepTwo
6125 else
6126 DotStep := DotStepOne;
6128 MousePos.X := (MousePos.X div DotStep) * DotStep;
6129 MousePos.Y := (MousePos.Y div DotStep) * DotStep;
6130 end;
6132 procedure TMainForm.miShowEdgesClick(Sender: TObject);
6133 begin
6134 ShowEdges();
6135 end;
6137 procedure TMainForm.miSnapToGridClick(Sender: TObject);
6138 begin
6139 SnapToGrid := not SnapToGrid;
6141 MousePos.X := (MousePos.X div DotStep) * DotStep;
6142 MousePos.Y := (MousePos.Y div DotStep) * DotStep;
6144 miSnapToGrid.Checked := SnapToGrid;
6145 end;
6147 procedure TMainForm.minexttabClick(Sender: TObject);
6148 begin
6149 if pcObjects.ActivePageIndex < pcObjects.PageCount-1 then
6150 pcObjects.ActivePageIndex := pcObjects.ActivePageIndex+1
6151 else
6152 pcObjects.ActivePageIndex := 0;
6153 end;
6155 procedure TMainForm.miSaveMiniMapClick(Sender: TObject);
6156 begin
6157 SaveMiniMapForm.ShowModal();
6158 end;
6160 procedure TMainForm.bClearTextureClick(Sender: TObject);
6161 begin
6162 lbTextureList.ItemIndex := -1;
6163 lTextureWidth.Caption := '';
6164 lTextureHeight.Caption := '';
6165 end;
6167 procedure TMainForm.miPackMapClick(Sender: TObject);
6168 begin
6169 PackMapForm.ShowModal();
6170 end;
6172 procedure TMainForm.miMapTestSettingsClick(Sender: TObject);
6173 begin
6174 MapTestForm.ShowModal();
6175 end;
6177 procedure TMainForm.miTestMapClick(Sender: TObject);
6178 var
6179 cmd, mapWAD, mapToRun: String;
6180 opt: LongWord;
6181 time: Integer;
6182 lpMsgBuf: PChar;
6183 begin
6184 // Сохраняем временную карту:
6185 time := 0;
6186 repeat
6187 mapWAD := ExtractFilePath(TestD2dExe) + Format('maps\temp%.4d.wad', [time]);
6188 Inc(time);
6189 until not FileExists(mapWAD);
6190 mapToRun := mapWAD + ':\' + TEST_MAP_NAME;
6191 SaveMap(mapToRun);
6193 mapToRun := ExtractRelativePath(ExtractFilePath(TestD2dExe) + 'maps\', mapToRun);
6195 // Опции игры:
6196 opt := 32 + 64;
6197 if TestOptionsTwoPlayers then
6198 opt := opt + 1;
6199 if TestOptionsTeamDamage then
6200 opt := opt + 2;
6201 if TestOptionsAllowExit then
6202 opt := opt + 4;
6203 if TestOptionsWeaponStay then
6204 opt := opt + 8;
6205 if TestOptionsMonstersDM then
6206 opt := opt + 16;
6208 // Составляем командную строку:
6209 cmd := ' -map "' + mapToRun + '"';
6210 cmd := cmd + ' -gm ' + TestGameMode;
6211 cmd := cmd + ' -limt ' + TestLimTime;
6212 cmd := cmd + ' -lims ' + TestLimScore;
6213 cmd := cmd + ' -opt ' + IntToStr(opt);
6215 if TestMapOnce then
6216 cmd := cmd + ' --close';
6218 cmd := cmd + ' --debug';
6219 cmd := cmd + ' --tempdelete';
6221 // Запускаем:
6222 Application.Minimize();
6223 if ExecuteProcess(TestD2dExe, cmd) < 0 then
6224 begin
6225 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER or FORMAT_MESSAGE_FROM_SYSTEM,
6226 nil, GetLastError(), LANG_SYSTEM_DEFAULT,
6227 @lpMsgBuf, 0, nil);
6228 MessageBox(0, lpMsgBuf,
6229 PChar(_lc[I_MSG_EXEC_ERROR]),
6230 MB_OK or MB_ICONERROR);
6231 end;
6233 SysUtils.DeleteFile(mapWAD);
6234 Application.Restore();
6235 end;
6237 procedure TMainForm.sbVerticalScroll(Sender: TObject;
6238 ScrollCode: TScrollCode; var ScrollPos: Integer);
6239 begin
6240 MapOffset.Y := -Normalize16(sbVertical.Position);
6241 end;
6243 procedure TMainForm.sbHorizontalScroll(Sender: TObject;
6244 ScrollCode: TScrollCode; var ScrollPos: Integer);
6245 begin
6246 MapOffset.X := -Normalize16(sbHorizontal.Position);
6247 end;
6249 procedure TMainForm.miOpenWadMapClick(Sender: TObject);
6250 begin
6251 if OpenedWAD <> '' then
6252 begin
6253 OpenMap(OpenedWAD, '');
6254 end;
6255 end;
6257 procedure TMainForm.selectall1Click(Sender: TObject);
6258 var
6259 a: Integer;
6260 begin
6261 RemoveSelectFromObjects();
6263 if gPanels <> nil then
6264 for a := 0 to High(gPanels) do
6265 if gPanels[a].PanelType <> PANEL_NONE then
6266 SelectObject(OBJECT_PANEL, a, True);
6268 if gItems <> nil then
6269 for a := 0 to High(gItems) do
6270 if gItems[a].ItemType <> ITEM_NONE then
6271 SelectObject(OBJECT_ITEM, a, True);
6273 if gMonsters <> nil then
6274 for a := 0 to High(gMonsters) do
6275 if gMonsters[a].MonsterType <> MONSTER_NONE then
6276 SelectObject(OBJECT_MONSTER, a, True);
6278 if gAreas <> nil then
6279 for a := 0 to High(gAreas) do
6280 if gAreas[a].AreaType <> AREA_NONE then
6281 SelectObject(OBJECT_AREA, a, True);
6283 if gTriggers <> nil then
6284 for a := 0 to High(gTriggers) do
6285 if gTriggers[a].TriggerType <> TRIGGER_NONE then
6286 SelectObject(OBJECT_TRIGGER, a, True);
6287 end;
6289 procedure TMainForm.Splitter1CanResize(Sender: TObject;
6290 var NewSize: Integer; var Accept: Boolean);
6291 begin
6292 Accept := (NewSize > 140);
6293 end;
6295 procedure TMainForm.Splitter2CanResize(Sender: TObject;
6296 var NewSize: Integer; var Accept: Boolean);
6297 begin
6298 Accept := (NewSize > 110);
6299 end;
6301 procedure TMainForm.vleObjectPropertyEnter(Sender: TObject);
6302 begin
6303 EditingProperties := True;
6304 end;
6306 procedure TMainForm.vleObjectPropertyExit(Sender: TObject);
6307 begin
6308 EditingProperties := False;
6309 end;
6311 procedure TMainForm.FormKeyUp(Sender: TObject; var Key: Word;
6312 Shift: TShiftState);
6313 begin
6314 // Объекты передвигались:
6315 if MainForm.ActiveControl = RenderPanel then
6316 begin
6317 if (Key = VK_NUMPAD4) or
6318 (Key = VK_NUMPAD6) or
6319 (Key = VK_NUMPAD8) or
6320 (Key = VK_NUMPAD5) or
6321 (Key = Ord('V')) then
6322 FillProperty();
6323 end;
6324 end;
6327 procedure TMainForm.lbTextureListDrawItem(Control: TWinControl; Index: Integer;
6328 Rect: TRect; State: LCLType.TOwnerDrawState);
6329 begin
6330 with Control as TListBox do
6331 begin
6332 if LCLType.odSelected in State then
6333 begin
6334 Canvas.Brush.Color := clHighlight;
6335 Canvas.Font.Color := clHighlightText;
6336 end else
6337 if (Items <> nil) and (Index >= 0) then
6338 if slInvalidTextures.IndexOf(Items[Index]) > -1 then
6339 begin
6340 Canvas.Brush.Color := clRed;
6341 Canvas.Font.Color := clWhite;
6342 end;
6343 Canvas.FillRect(Rect);
6344 Canvas.TextRect(Rect, Rect.Left, Rect.Top, Items[Index]);
6345 end;
6346 end;
6348 end.