DEADSOFTWARE

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