DEADSOFTWARE

Main: Prompt to remove file from recent list
[d2df-editor.git] / src / editor / f_main.pas
1 unit f_main;
3 {$INCLUDE ../shared/a_modes.inc}
5 interface
7 uses
8 LCLIntf, LCLType, LMessages, SysUtils, Variants, Classes, Graphics,
9 Controls, Forms, Dialogs, ImgList, StdCtrls, Buttons,
10 ComCtrls, ValEdit, Types, ToolWin, Menus, ExtCtrls,
11 CheckLst, Grids, OpenGLContext, utils, UTF8Process;
13 type
15 { TMainForm }
17 TMainForm = class(TForm)
18 lLoad: TLabel;
19 // Главное меню:
20 MainMenu: TMainMenu;
21 // "Файл":
22 miMenuFile: TMenuItem;
23 miNewMap: TMenuItem;
24 miOpenMap: TMenuItem;
25 miSaveMap: TMenuItem;
26 miSaveMapAs: TMenuItem;
27 miOpenWadMap: TMenuItem;
28 miLine1: TMenuItem;
29 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 lbTextureListDrawItem(Control: TWinControl; Index: Integer;
211 ARect: TRect; State: TOwnerDrawState);
212 procedure RenderPanelMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
213 procedure RenderPanelMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
214 procedure RenderPanelMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
215 procedure RenderPanelPaint(Sender: TObject);
216 procedure RenderPanelResize(Sender: TObject);
217 procedure vleObjectPropertyEditButtonClick(Sender: TObject);
218 procedure vleObjectPropertyGetPickList(Sender: TObject; const KeyName: String; Values: TStrings);
219 procedure vleObjectPropertyKeyDown(Sender: TObject; var Key: Word;
220 Shift: TShiftState);
221 procedure tbGridOnClick(Sender: TObject);
222 procedure miMapPreviewClick(Sender: TObject);
223 procedure miLayer1Click(Sender: TObject);
224 procedure miLayer2Click(Sender: TObject);
225 procedure miLayer3Click(Sender: TObject);
226 procedure miLayer4Click(Sender: TObject);
227 procedure miLayer5Click(Sender: TObject);
228 procedure miLayer6Click(Sender: TObject);
229 procedure miLayer7Click(Sender: TObject);
230 procedure miLayer8Click(Sender: TObject);
231 procedure miLayer9Click(Sender: TObject);
232 procedure tbShowClick(Sender: TObject);
233 procedure miSnapToGridClick(Sender: TObject);
234 procedure miMiniMapClick(Sender: TObject);
235 procedure miSwitchGridClick(Sender: TObject);
236 procedure miShowEdgesClick(Sender: TObject);
237 procedure minexttabClick(Sender: TObject);
238 procedure miSaveMiniMapClick(Sender: TObject);
239 procedure bClearTextureClick(Sender: TObject);
240 procedure miPackMapClick(Sender: TObject);
241 procedure aRecentFileExecute(Sender: TObject);
242 procedure miMapTestSettingsClick(Sender: TObject);
243 procedure miTestMapClick(Sender: TObject);
244 procedure sbVerticalScroll(Sender: TObject; ScrollCode: TScrollCode;
245 var ScrollPos: Integer);
246 procedure sbHorizontalScroll(Sender: TObject; ScrollCode: TScrollCode;
247 var ScrollPos: Integer);
248 procedure miOpenWadMapClick(Sender: TObject);
249 procedure selectall1Click(Sender: TObject);
250 procedure Splitter1CanResize(Sender: TObject; var NewSize: Integer;
251 var Accept: Boolean);
252 procedure Splitter2CanResize(Sender: TObject; var NewSize: Integer;
253 var Accept: Boolean);
254 procedure vleObjectPropertyEnter(Sender: TObject);
255 procedure vleObjectPropertyExit(Sender: TObject);
256 procedure FormKeyUp(Sender: TObject; var Key: Word;
257 Shift: TShiftState);
258 private
259 procedure Draw();
260 procedure OnIdle(Sender: TObject; var Done: Boolean);
261 public
262 procedure RefreshRecentMenu();
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 case Data.ShotAim of
1465 1: str := _lc[I_PROP_TR_SHOT_AIM_1];
1466 2: str := _lc[I_PROP_TR_SHOT_AIM_2];
1467 3: str := _lc[I_PROP_TR_SHOT_AIM_3];
1468 else str := _lc[I_PROP_TR_SHOT_AIM_0];
1469 end;
1470 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_AIM], str, True)-1] do
1471 begin
1472 EditStyle := esPickList;
1473 ReadOnly := True;
1474 end;
1476 with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_TO],
1477 Format('(%d:%d)', [Data.ShotPos.X, Data.ShotPos.Y]), True)] do
1478 begin
1479 EditStyle := esEllipsis;
1480 ReadOnly := True;
1481 end;
1483 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_ANGLE], IntToStr(Data.ShotAngle), True)] do
1484 begin
1485 EditStyle := esSimple;
1486 MaxLength := 4;
1487 end;
1489 with ItemProps[InsertRow(_lc[I_PROP_TR_EX_DELAY], IntToStr(Data.ShotWait), True)] do
1490 begin
1491 EditStyle := esSimple;
1492 MaxLength := 5;
1493 end;
1495 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_ACC], IntToStr(Data.ShotAccuracy), True)] do
1496 begin
1497 EditStyle := esSimple;
1498 MaxLength := 5;
1499 end;
1501 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_AMMO], IntToStr(Data.ShotAmmo), True)] do
1502 begin
1503 EditStyle := esSimple;
1504 MaxLength := 5;
1505 end;
1507 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_RELOAD], IntToStr(Data.ShotIntReload), True)] do
1508 begin
1509 EditStyle := esSimple;
1510 MaxLength := 4;
1511 end;
1512 end;
1514 TRIGGER_EFFECT:
1515 begin
1516 with ItemProps[InsertRow(_lc[I_PROP_TR_COUNT], IntToStr(Data.FXCount), True)] do
1517 begin
1518 EditStyle := esSimple;
1519 MaxLength := 3;
1520 end;
1522 if Data.FXType = 0 then
1523 str := _lc[I_PROP_TR_EFFECT_PARTICLE]
1524 else
1525 str := _lc[I_PROP_TR_EFFECT_ANIMATION];
1526 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_TYPE], str, True)] do
1527 begin
1528 EditStyle := esEllipsis;
1529 ReadOnly := True;
1530 end;
1532 str := '';
1533 if Data.FXType = 0 then
1534 case Data.FXSubType of
1535 TRIGGER_EFFECT_SLIQUID:
1536 str := _lc[I_PROP_TR_EFFECT_SLIQUID];
1537 TRIGGER_EFFECT_LLIQUID:
1538 str := _lc[I_PROP_TR_EFFECT_LLIQUID];
1539 TRIGGER_EFFECT_DLIQUID:
1540 str := _lc[I_PROP_TR_EFFECT_DLIQUID];
1541 TRIGGER_EFFECT_BLOOD:
1542 str := _lc[I_PROP_TR_EFFECT_BLOOD];
1543 TRIGGER_EFFECT_SPARK:
1544 str := _lc[I_PROP_TR_EFFECT_SPARK];
1545 TRIGGER_EFFECT_BUBBLE:
1546 str := _lc[I_PROP_TR_EFFECT_BUBBLE];
1547 end;
1548 if Data.FXType = 1 then
1549 begin
1550 if (Data.FXSubType = 0) or (Data.FXSubType > EFFECT_FIRE) then
1551 Data.FXSubType := EFFECT_TELEPORT;
1552 str := EffectToStr(Data.FXSubType);
1553 end;
1554 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_SUBTYPE], str, True)] do
1555 begin
1556 EditStyle := esEllipsis;
1557 ReadOnly := True;
1558 end;
1560 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_COLOR], IntToStr(Data.FXColorR or (Data.FXColorG shl 8) or (Data.FXColorB shl 16)), True)] do
1561 begin
1562 EditStyle := esEllipsis;
1563 ReadOnly := True;
1564 end;
1566 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_CENTER], BoolNames[Data.FXPos = 0], True)] do
1567 begin
1568 EditStyle := esPickList;
1569 ReadOnly := True;
1570 end;
1572 with ItemProps[InsertRow(_lc[I_PROP_TR_EX_DELAY], IntToStr(Data.FXWait), True)] do
1573 begin
1574 EditStyle := esSimple;
1575 MaxLength := 5;
1576 end;
1578 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_VELX], IntToStr(Data.FXVelX), True)] do
1579 begin
1580 EditStyle := esSimple;
1581 MaxLength := 4;
1582 end;
1584 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_VELY], IntToStr(Data.FXVelY), True)] do
1585 begin
1586 EditStyle := esSimple;
1587 MaxLength := 4;
1588 end;
1590 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_SPL], IntToStr(Data.FXSpreadL), True)] do
1591 begin
1592 EditStyle := esSimple;
1593 MaxLength := 3;
1594 end;
1596 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_SPR], IntToStr(Data.FXSpreadR), True)] do
1597 begin
1598 EditStyle := esSimple;
1599 MaxLength := 3;
1600 end;
1602 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_SPU], IntToStr(Data.FXSpreadU), True)] do
1603 begin
1604 EditStyle := esSimple;
1605 MaxLength := 3;
1606 end;
1608 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_SPD], IntToStr(Data.FXSpreadD), True)] do
1609 begin
1610 EditStyle := esSimple;
1611 MaxLength := 3;
1612 end;
1613 end;
1614 end; //case TriggerType
1615 end;
1616 end; // OBJECT_TRIGGER:
1617 end;
1618 end;
1620 procedure ChangeShownProperty(Name: String; NewValue: String);
1621 var
1622 row: Integer;
1623 begin
1624 if SelectedObjectCount() <> 1 then
1625 Exit;
1626 if not SelectedObjects[GetFirstSelected()].Live then
1627 Exit;
1629 // Есть ли такой ключ:
1630 if MainForm.vleObjectProperty.FindRow(Name, row) then
1631 begin
1632 MainForm.vleObjectProperty.Values[Name] := NewValue;
1633 end;
1634 end;
1636 procedure SelectObject(fObjectType: Byte; fID: DWORD; Multi: Boolean);
1637 var
1638 a: Integer;
1639 b: Boolean;
1640 begin
1641 if Multi then
1642 begin
1643 b := False;
1645 // Уже выделен - убираем:
1646 if SelectedObjects <> nil then
1647 for a := 0 to High(SelectedObjects) do
1648 with SelectedObjects[a] do
1649 if Live and (ID = fID) and
1650 (ObjectType = fObjectType) then
1651 begin
1652 Live := False;
1653 b := True;
1654 end;
1656 if b then
1657 Exit;
1659 SetLength(SelectedObjects, Length(SelectedObjects)+1);
1661 with SelectedObjects[High(SelectedObjects)] do
1662 begin
1663 ObjectType := fObjectType;
1664 ID := fID;
1665 Live := True;
1666 end;
1667 end
1668 else // not Multi
1669 begin
1670 SetLength(SelectedObjects, 1);
1672 with SelectedObjects[0] do
1673 begin
1674 ObjectType := fObjectType;
1675 ID := fID;
1676 Live := True;
1677 end;
1678 end;
1680 MainForm.miCopy.Enabled := True;
1681 MainForm.miCut.Enabled := True;
1683 if fObjectType = OBJECT_PANEL then
1684 begin
1685 MainForm.miToFore.Enabled := True;
1686 MainForm.miToBack.Enabled := True;
1687 end;
1688 end;
1690 procedure RemoveSelectFromObjects();
1691 begin
1692 SelectedObjects := nil;
1693 DrawPressRect := False;
1694 MouseLDown := False;
1695 MouseRDown := False;
1696 MouseAction := MOUSEACTION_NONE;
1697 SelectFlag := SELECTFLAG_NONE;
1698 ResizeType := RESIZETYPE_NONE;
1699 ResizeDirection := RESIZEDIR_NONE;
1701 MainForm.vleObjectProperty.Strings.Clear();
1703 MainForm.miCopy.Enabled := False;
1704 MainForm.miCut.Enabled := False;
1705 MainForm.miToFore.Enabled := False;
1706 MainForm.miToBack.Enabled := False;
1707 end;
1709 procedure DeleteSelectedObjects();
1710 var
1711 i, a, ii: Integer;
1712 b: Boolean;
1713 begin
1714 if SelectedObjects = nil then
1715 Exit;
1717 b := False;
1718 i := 0;
1720 for a := 0 to High(SelectedObjects) do
1721 with SelectedObjects[a] do
1722 if Live then
1723 begin
1724 if not b then
1725 begin
1726 SetLength(UndoBuffer, Length(UndoBuffer)+1);
1727 i := High(UndoBuffer);
1728 b := True;
1729 end;
1731 SetLength(UndoBuffer[i], Length(UndoBuffer[i])+1);
1732 ii := High(UndoBuffer[i]);
1734 case ObjectType of
1735 OBJECT_PANEL:
1736 begin
1737 UndoBuffer[i, ii].UndoType := UNDO_DELETE_PANEL;
1738 New(UndoBuffer[i, ii].Panel);
1739 UndoBuffer[i, ii].Panel^ := gPanels[ID];
1740 end;
1741 OBJECT_ITEM:
1742 begin
1743 UndoBuffer[i, ii].UndoType := UNDO_DELETE_ITEM;
1744 UndoBuffer[i, ii].Item := gItems[ID];
1745 end;
1746 OBJECT_AREA:
1747 begin
1748 UndoBuffer[i, ii].UndoType := UNDO_DELETE_AREA;
1749 UndoBuffer[i, ii].Area := gAreas[ID];
1750 end;
1751 OBJECT_TRIGGER:
1752 begin
1753 UndoBuffer[i, ii].UndoType := UNDO_DELETE_TRIGGER;
1754 UndoBuffer[i, ii].Trigger := gTriggers[ID];
1755 end;
1756 end;
1758 RemoveObject(ID, ObjectType);
1759 end;
1761 RemoveSelectFromObjects();
1763 MainForm.miUndo.Enabled := UndoBuffer <> nil;
1764 end;
1766 procedure Undo_Add(ObjectType: Byte; ID: DWORD; Group: Boolean = False);
1767 var
1768 i, ii: Integer;
1769 begin
1770 if (not Group) or (Length(UndoBuffer) = 0) then
1771 SetLength(UndoBuffer, Length(UndoBuffer)+1);
1772 SetLength(UndoBuffer[High(UndoBuffer)], Length(UndoBuffer[High(UndoBuffer)])+1);
1773 i := High(UndoBuffer);
1774 ii := High(UndoBuffer[i]);
1776 case ObjectType of
1777 OBJECT_PANEL:
1778 UndoBuffer[i, ii].UndoType := UNDO_ADD_PANEL;
1779 OBJECT_ITEM:
1780 UndoBuffer[i, ii].UndoType := UNDO_ADD_ITEM;
1781 OBJECT_MONSTER:
1782 UndoBuffer[i, ii].UndoType := UNDO_ADD_MONSTER;
1783 OBJECT_AREA:
1784 UndoBuffer[i, ii].UndoType := UNDO_ADD_AREA;
1785 OBJECT_TRIGGER:
1786 UndoBuffer[i, ii].UndoType := UNDO_ADD_TRIGGER;
1787 end;
1789 UndoBuffer[i, ii].AddID := ID;
1791 MainForm.miUndo.Enabled := UndoBuffer <> nil;
1792 end;
1794 procedure FullClear();
1795 begin
1796 RemoveSelectFromObjects();
1797 ClearMap();
1798 LoadSky(gMapInfo.SkyName);
1799 UndoBuffer := nil;
1800 slInvalidTextures.Clear();
1801 MapCheckForm.lbErrorList.Clear();
1802 MapCheckForm.mErrorDescription.Clear();
1804 MainForm.miUndo.Enabled := False;
1805 MainForm.sbHorizontal.Position := 0;
1806 MainForm.sbVertical.Position := 0;
1807 MainForm.FormResize(nil);
1808 MainForm.Caption := FormCaption;
1809 OpenedMap := '';
1810 OpenedWAD := '';
1811 end;
1813 procedure ErrorMessageBox(str: String);
1814 begin
1815 MessageBox(0, PChar(str), PChar(_lc[I_MSG_ERROR]),
1816 MB_ICONINFORMATION or MB_OK or MB_DEFBUTTON1);
1817 end;
1819 function CheckProperty(): Boolean;
1820 var
1821 _id: Integer;
1822 begin
1823 Result := False;
1825 _id := GetFirstSelected();
1827 if SelectedObjects[_id].ObjectType = OBJECT_PANEL then
1828 with gPanels[SelectedObjects[_id].ID] do
1829 begin
1830 if TextureWidth <> 0 then
1831 if StrToIntDef(MainForm.vleObjectProperty.Values[_lc[I_PROP_WIDTH]], 1) mod TextureWidth <> 0 then
1832 begin
1833 ErrorMessageBox(Format(_lc[I_MSG_WRONG_TEXWIDTH],
1834 [TextureWidth]));
1835 Exit;
1836 end;
1838 if TextureHeight <> 0 then
1839 if StrToIntDef(Trim(MainForm.vleObjectProperty.Values[_lc[I_PROP_HEIGHT]]), 1) mod TextureHeight <> 0 then
1840 begin
1841 ErrorMessageBox(Format(_lc[I_MSG_WRONG_TEXHEIGHT],
1842 [TextureHeight]));
1843 Exit;
1844 end;
1846 if IsTexturedPanel(PanelType) and (TextureName <> '') then
1847 if not (StrToIntDef(MainForm.vleObjectProperty.Values[_lc[I_PROP_PANEL_ALPHA]], -1) in [0..255]) then
1848 begin
1849 ErrorMessageBox(_lc[I_MSG_WRONG_ALPHA]);
1850 Exit;
1851 end;
1852 end;
1854 if SelectedObjects[_id].ObjectType in [OBJECT_PANEL, OBJECT_TRIGGER] then
1855 if (StrToIntDef(MainForm.vleObjectProperty.Values[_lc[I_PROP_WIDTH]], 0) <= 0) or
1856 (StrToIntDef(MainForm.vleObjectProperty.Values[_lc[I_PROP_HEIGHT]], 0) <= 0) then
1857 begin
1858 ErrorMessageBox(_lc[I_MSG_WRONG_SIZE]);
1859 Exit;
1860 end;
1862 if (Trim(MainForm.vleObjectProperty.Values[_lc[I_PROP_X]]) = '') or
1863 (Trim(MainForm.vleObjectProperty.Values[_lc[I_PROP_Y]]) = '') then
1864 begin
1865 ErrorMessageBox(_lc[I_MSG_WRONG_XY]);
1866 Exit;
1867 end;
1869 Result := True;
1870 end;
1872 procedure SelectTexture(ID: Integer);
1873 begin
1874 MainForm.lbTextureList.ItemIndex := ID;
1875 MainForm.lbTextureListClick(nil);
1876 end;
1878 function AddTexture(aWAD, aSection, aTex: String; silent: Boolean): Boolean;
1879 var
1880 a, FrameLen: Integer;
1881 ok: Boolean;
1882 FileName: String;
1883 ResourceName: String;
1884 UResourceName: String;
1885 FullResourceName: String;
1886 SectionName: String;
1887 Data: Pointer;
1888 Width, Height: Word;
1889 fn: String;
1890 begin
1891 if aSection = '..' then
1892 SectionName := ''
1893 else
1894 SectionName := aSection;
1896 if aWAD = _lc[I_WAD_SPECIAL_MAP] then
1897 begin // Файл карты
1898 g_ProcessResourceStr(OpenedMap, @fn, nil, nil);
1899 //FileName := EditorDir+'maps\'+ExtractFileName(fn);
1900 FileName := fn;
1901 ResourceName := ':'+SectionName+'\'+aTex;
1902 end
1903 else
1904 if aWAD = _lc[I_WAD_SPECIAL_TEXS] then
1905 begin // Спец. текстуры
1906 FileName := '';
1907 ResourceName := aTex;
1908 end
1909 else
1910 begin // Внешний WAD
1911 FileName := EditorDir+'wads/'+aWAD;
1912 ResourceName := utf2win(aWAD)+':'+SectionName+'\'+aTex;
1913 end;
1915 ok := True;
1916 UResourceName := win2utf(ResourceName);
1918 // Есть ли уже такая текстура:
1919 for a := 0 to MainForm.lbTextureList.Items.Count-1 do
1920 if UResourceName = MainForm.lbTextureList.Items[a] then
1921 begin
1922 if not silent then
1923 ErrorMessageBox(Format(_lc[I_MSG_TEXTURE_ALREADY],
1924 [UResourceName]));
1925 ok := False;
1926 end;
1928 // Название ресурса <= 64 символов:
1929 if Length(ResourceName) > 64 then
1930 begin
1931 if not silent then
1932 ErrorMessageBox(Format(_lc[I_MSG_RES_NAME_64],
1933 [UResourceName]));
1934 ok := False;
1935 end;
1937 if ok then
1938 begin
1939 a := -1;
1940 if aWAD = _lc[I_WAD_SPECIAL_TEXS] then
1941 begin
1942 a := MainForm.lbTextureList.Items.Add(UResourceName);
1943 if not silent then
1944 SelectTexture(a);
1945 Result := True;
1946 Exit;
1947 end;
1949 FullResourceName := FileName+':'+SectionName+'\'+aTex;
1951 if IsAnim(FullResourceName) then
1952 begin // Аним. текстура
1953 GetFrame(FullResourceName, Data, FrameLen, Width, Height);
1955 if g_CreateTextureMemorySize(Data, FrameLen, ResourceName, 0, 0, Width, Height, 1) then
1956 a := MainForm.lbTextureList.Items.Add(UResourceName);
1957 end
1958 else // Обычная текстура
1959 begin
1960 if g_CreateTextureWAD(ResourceName, FullResourceName) then
1961 a := MainForm.lbTextureList.Items.Add(UResourceName);
1962 end;
1963 if (a > -1) and (not silent) then
1964 SelectTexture(a);
1965 end;
1967 Result := ok;
1968 end;
1970 procedure UpdateCaption(sMap, sFile, sRes: String);
1971 begin
1972 with MainForm do
1973 if (sFile = '') and (sRes = '') and (sMap = '') then
1974 Caption := FormCaption
1975 else
1976 if sMap = '' then
1977 Caption := Format('%s - %s:%s', [FormCaption, sFile, sRes])
1978 else
1979 if (sFile <> '') and (sRes <> '') then
1980 Caption := Format('%s - %s (%s:%s)', [FormCaption, sMap, sFile, sRes])
1981 else
1982 Caption := Format('%s - %s', [FormCaption, sMap]);
1983 end;
1985 procedure OpenMap(FileName: String; mapN: String);
1986 var
1987 MapName: String;
1988 idx: Integer;
1989 begin
1990 SelectMapForm.GetMaps(FileName);
1992 if (FileName = OpenedWAD) and
1993 (OpenedMap <> '') then
1994 begin
1995 MapName := OpenedMap;
1996 while (Pos(':\', MapName) > 0) do
1997 Delete(MapName, 1, Pos(':\', MapName) + 1);
1999 idx := SelectMapForm.lbMapList.Items.IndexOf(MapName);
2000 SelectMapForm.lbMapList.ItemIndex := idx;
2001 end
2002 else
2003 if SelectMapForm.lbMapList.Count > 0 then
2004 SelectMapForm.lbMapList.ItemIndex := 0
2005 else
2006 SelectMapForm.lbMapList.ItemIndex := -1;
2008 if mapN = '' then
2009 idx := -1
2010 else
2011 idx := SelectMapForm.lbMapList.Items.IndexOf(mapN);
2013 if idx < 0 then
2014 begin
2015 if (SelectMapForm.ShowModal() = mrOK) and
2016 (SelectMapForm.lbMapList.ItemIndex <> -1) then
2017 idx := SelectMapForm.lbMapList.ItemIndex
2018 else
2019 Exit;
2020 end;
2022 MapName := SelectMapForm.lbMapList.Items[idx];
2024 with MainForm do
2025 begin
2026 FullClear();
2028 pLoadProgress.Left := (RenderPanel.Width div 2)-(pLoadProgress.Width div 2);
2029 pLoadProgress.Top := (RenderPanel.Height div 2)-(pLoadProgress.Height div 2);
2030 pLoadProgress.Show();
2032 OpenedMap := FileName+':\'+MapName;
2033 OpenedWAD := FileName;
2035 idx := RecentFiles.IndexOf(OpenedMap);
2036 // Такая карта уже недавно открывалась:
2037 if idx >= 0 then
2038 RecentFiles.Delete(idx);
2039 RecentFiles.Insert(0, OpenedMap);
2040 RefreshRecentMenu();
2042 LoadMap(OpenedMap);
2044 pLoadProgress.Hide();
2045 FormResize(nil);
2047 lbTextureList.Sorted := True;
2048 lbTextureList.Sorted := False;
2050 UpdateCaption(win2utf(gMapInfo.Name), ExtractFileName(FileName), MapName);
2051 end;
2052 end;
2054 procedure MoveSelectedObjects(Wall, alt: Boolean; dx, dy: Integer);
2055 var
2056 okX, okY: Boolean;
2057 a: Integer;
2058 begin
2059 if SelectedObjects = nil then
2060 Exit;
2062 okX := True;
2063 okY := True;
2065 if Wall then
2066 for a := 0 to High(SelectedObjects) do
2067 if SelectedObjects[a].Live then
2068 begin
2069 if ObjectCollideLevel(SelectedObjects[a].ID, SelectedObjects[a].ObjectType, dx, 0) then
2070 okX := False;
2072 if ObjectCollideLevel(SelectedObjects[a].ID, SelectedObjects[a].ObjectType, 0, dy) then
2073 okY := False;
2075 if (not okX) or (not okY) then
2076 Break;
2077 end;
2079 if okX or okY then
2080 begin
2081 for a := 0 to High(SelectedObjects) do
2082 if SelectedObjects[a].Live then
2083 begin
2084 if okX then
2085 MoveObject(SelectedObjects[a].ObjectType, SelectedObjects[a].ID, dx, 0);
2087 if okY then
2088 MoveObject(SelectedObjects[a].ObjectType, SelectedObjects[a].ID, 0, dy);
2090 if alt and (SelectedObjects[a].ObjectType = OBJECT_TRIGGER) then
2091 begin
2092 if gTriggers[SelectedObjects[a].ID].TriggerType in [TRIGGER_PRESS,
2093 TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF] then
2094 begin // Двигаем зону Расширителя
2095 if okX then
2096 gTriggers[SelectedObjects[a].ID].Data.tX := gTriggers[SelectedObjects[a].ID].Data.tX+dx;
2097 if okY then
2098 gTriggers[SelectedObjects[a].ID].Data.tY := gTriggers[SelectedObjects[a].ID].Data.tY+dy;
2099 end;
2101 if gTriggers[SelectedObjects[a].ID].TriggerType in [TRIGGER_TELEPORT] then
2102 begin // Двигаем точку назначения Телепорта
2103 if okX then
2104 gTriggers[SelectedObjects[a].ID].Data.TargetPoint.X := gTriggers[SelectedObjects[a].ID].Data.TargetPoint.X+dx;
2105 if okY then
2106 gTriggers[SelectedObjects[a].ID].Data.TargetPoint.Y := gTriggers[SelectedObjects[a].ID].Data.TargetPoint.Y+dy;
2107 end;
2109 if gTriggers[SelectedObjects[a].ID].TriggerType in [TRIGGER_SPAWNMONSTER] then
2110 begin // Двигаем точку создания монстра
2111 if okX then
2112 gTriggers[SelectedObjects[a].ID].Data.MonPos.X := gTriggers[SelectedObjects[a].ID].Data.MonPos.X+dx;
2113 if okY then
2114 gTriggers[SelectedObjects[a].ID].Data.MonPos.Y := gTriggers[SelectedObjects[a].ID].Data.MonPos.Y+dy;
2115 end;
2117 if gTriggers[SelectedObjects[a].ID].TriggerType in [TRIGGER_SPAWNITEM] then
2118 begin // Двигаем точку создания предмета
2119 if okX then
2120 gTriggers[SelectedObjects[a].ID].Data.ItemPos.X := gTriggers[SelectedObjects[a].ID].Data.ItemPos.X+dx;
2121 if okY then
2122 gTriggers[SelectedObjects[a].ID].Data.ItemPos.Y := gTriggers[SelectedObjects[a].ID].Data.ItemPos.Y+dy;
2123 end;
2125 if gTriggers[SelectedObjects[a].ID].TriggerType in [TRIGGER_SHOT] then
2126 begin // Двигаем точку создания выстрела
2127 if okX then
2128 gTriggers[SelectedObjects[a].ID].Data.ShotPos.X := gTriggers[SelectedObjects[a].ID].Data.ShotPos.X+dx;
2129 if okY then
2130 gTriggers[SelectedObjects[a].ID].Data.ShotPos.Y := gTriggers[SelectedObjects[a].ID].Data.ShotPos.Y+dy;
2131 end;
2132 end;
2133 end;
2135 LastMovePoint := MousePos;
2136 end;
2137 end;
2139 procedure ShowLayer(Layer: Byte; show: Boolean);
2140 begin
2141 LayerEnabled[Layer] := show;
2143 case Layer of
2144 LAYER_BACK:
2145 begin
2146 MainForm.miLayer1.Checked := show;
2147 MainForm.miLayerP1.Checked := show;
2148 end;
2149 LAYER_WALLS:
2150 begin
2151 MainForm.miLayer2.Checked := show;
2152 MainForm.miLayerP2.Checked := show;
2153 end;
2154 LAYER_FOREGROUND:
2155 begin
2156 MainForm.miLayer3.Checked := show;
2157 MainForm.miLayerP3.Checked := show;
2158 end;
2159 LAYER_STEPS:
2160 begin
2161 MainForm.miLayer4.Checked := show;
2162 MainForm.miLayerP4.Checked := show;
2163 end;
2164 LAYER_WATER:
2165 begin
2166 MainForm.miLayer5.Checked := show;
2167 MainForm.miLayerP5.Checked := show;
2168 end;
2169 LAYER_ITEMS:
2170 begin
2171 MainForm.miLayer6.Checked := show;
2172 MainForm.miLayerP6.Checked := show;
2173 end;
2174 LAYER_MONSTERS:
2175 begin
2176 MainForm.miLayer7.Checked := show;
2177 MainForm.miLayerP7.Checked := show;
2178 end;
2179 LAYER_AREAS:
2180 begin
2181 MainForm.miLayer8.Checked := show;
2182 MainForm.miLayerP8.Checked := show;
2183 end;
2184 LAYER_TRIGGERS:
2185 begin
2186 MainForm.miLayer9.Checked := show;
2187 MainForm.miLayerP9.Checked := show;
2188 end;
2189 end;
2191 RemoveSelectFromObjects();
2192 end;
2194 procedure SwitchLayer(Layer: Byte);
2195 begin
2196 ShowLayer(Layer, not LayerEnabled[Layer]);
2197 end;
2199 procedure SwitchMap();
2200 begin
2201 ShowMap := not ShowMap;
2202 MainForm.tbShowMap.Down := ShowMap;
2203 end;
2205 procedure ShowEdges();
2206 begin
2207 if drEdge[3] < 255 then
2208 drEdge[3] := 255
2209 else
2210 drEdge[3] := gAlphaEdge;
2211 end;
2213 function SelectedTexture(): String;
2214 begin
2215 if MainForm.lbTextureList.ItemIndex <> -1 then
2216 Result := utf2win(MainForm.lbTextureList.Items[MainForm.lbTextureList.ItemIndex])
2217 else
2218 Result := '';
2219 end;
2221 function IsSpecialTextureSel(): Boolean;
2222 begin
2223 Result := (MainForm.lbTextureList.ItemIndex <> -1) and
2224 IsSpecialTexture(utf2win(MainForm.lbTextureList.Items[MainForm.lbTextureList.ItemIndex]));
2225 end;
2227 function CopyBufferToString(var CopyBuf: TCopyRecArray): String;
2228 var
2229 i, j: Integer;
2230 Res: String;
2232 procedure AddInt(x: Integer);
2233 begin
2234 Res := Res + IntToStr(x) + ' ';
2235 end;
2237 begin
2238 Result := '';
2240 if Length(CopyBuf) = 0 then
2241 Exit;
2243 Res := CLIPBOARD_SIG + ' ';
2245 for i := 0 to High(CopyBuf) do
2246 begin
2247 if (CopyBuf[i].ObjectType = OBJECT_PANEL) and
2248 (CopyBuf[i].Panel = nil) then
2249 Continue;
2251 // Тип объекта:
2252 AddInt(CopyBuf[i].ObjectType);
2253 Res := Res + '; ';
2255 // Свойства объекта:
2256 case CopyBuf[i].ObjectType of
2257 OBJECT_PANEL:
2258 with CopyBuf[i].Panel^ do
2259 begin
2260 AddInt(PanelType);
2261 AddInt(X);
2262 AddInt(Y);
2263 AddInt(Width);
2264 AddInt(Height);
2265 Res := Res + '"' + TextureName + '" ';
2266 AddInt(Alpha);
2267 AddInt(IfThen(Blending, 1, 0));
2268 end;
2270 OBJECT_ITEM:
2271 with CopyBuf[i].Item do
2272 begin
2273 AddInt(ItemType);
2274 AddInt(X);
2275 AddInt(Y);
2276 AddInt(IfThen(OnlyDM, 1, 0));
2277 AddInt(IfThen(Fall, 1, 0));
2278 end;
2280 OBJECT_MONSTER:
2281 with CopyBuf[i].Monster do
2282 begin
2283 AddInt(MonsterType);
2284 AddInt(X);
2285 AddInt(Y);
2286 AddInt(IfThen(Direction = D_LEFT, 1, 0));
2287 end;
2289 OBJECT_AREA:
2290 with CopyBuf[i].Area do
2291 begin
2292 AddInt(AreaType);
2293 AddInt(X);
2294 AddInt(Y);
2295 AddInt(IfThen(Direction = D_LEFT, 1, 0));
2296 end;
2298 OBJECT_TRIGGER:
2299 with CopyBuf[i].Trigger do
2300 begin
2301 AddInt(TriggerType);
2302 AddInt(X);
2303 AddInt(Y);
2304 AddInt(Width);
2305 AddInt(Height);
2306 AddInt(ActivateType);
2307 AddInt(Key);
2308 AddInt(IfThen(Enabled, 1, 0));
2309 AddInt(TexturePanel);
2311 for j := 0 to 127 do
2312 AddInt(Data.Default[j]);
2313 end;
2314 end;
2315 end;
2317 Result := Res;
2318 end;
2320 procedure StringToCopyBuffer(Str: String; var CopyBuf: TCopyRecArray);
2321 var
2322 i, j, t: Integer;
2324 function GetNext(): String;
2325 var
2326 p: Integer;
2328 begin
2329 if Str[1] = '"' then
2330 begin
2331 Delete(Str, 1, 1);
2332 p := Pos('"', Str);
2334 if p = 0 then
2335 begin
2336 Result := Str;
2337 Str := '';
2338 end
2339 else
2340 begin
2341 Result := Copy(Str, 1, p-1);
2342 Delete(Str, 1, p);
2343 Str := Trim(Str);
2344 end;
2345 end
2346 else
2347 begin
2348 p := Pos(' ', Str);
2350 if p = 0 then
2351 begin
2352 Result := Str;
2353 Str := '';
2354 end
2355 else
2356 begin
2357 Result := Copy(Str, 1, p-1);
2358 Delete(Str, 1, p);
2359 Str := Trim(Str);
2360 end;
2361 end;
2362 end;
2364 begin
2365 Str := Trim(Str);
2367 if GetNext() <> CLIPBOARD_SIG then
2368 Exit;
2370 while Str <> '' do
2371 begin
2372 // Тип объекта:
2373 t := StrToIntDef(GetNext(), 0);
2375 if (t < OBJECT_PANEL) or (t > OBJECT_TRIGGER) or
2376 (GetNext() <> ';') then
2377 begin // Что-то не то => пропускаем:
2378 t := Pos(';', Str);
2379 Delete(Str, 1, t);
2380 Str := Trim(Str);
2382 Continue;
2383 end;
2385 i := Length(CopyBuf);
2386 SetLength(CopyBuf, i + 1);
2388 CopyBuf[i].ObjectType := t;
2389 CopyBuf[i].Panel := nil;
2391 // Свойства объекта:
2392 case t of
2393 OBJECT_PANEL:
2394 begin
2395 New(CopyBuf[i].Panel);
2397 with CopyBuf[i].Panel^ do
2398 begin
2399 PanelType := StrToIntDef(GetNext(), PANEL_WALL);
2400 X := StrToIntDef(GetNext(), 0);
2401 Y := StrToIntDef(GetNext(), 0);
2402 Width := StrToIntDef(GetNext(), 16);
2403 Height := StrToIntDef(GetNext(), 16);
2404 TextureName := GetNext();
2405 Alpha := StrToIntDef(GetNext(), 0);
2406 Blending := (GetNext() = '1');
2407 end;
2408 end;
2410 OBJECT_ITEM:
2411 with CopyBuf[i].Item do
2412 begin
2413 ItemType := StrToIntDef(GetNext(), ITEM_MEDKIT_SMALL);
2414 X := StrToIntDef(GetNext(), 0);
2415 Y := StrToIntDef(GetNext(), 0);
2416 OnlyDM := (GetNext() = '1');
2417 Fall := (GetNext() = '1');
2418 end;
2420 OBJECT_MONSTER:
2421 with CopyBuf[i].Monster do
2422 begin
2423 MonsterType := StrToIntDef(GetNext(), MONSTER_DEMON);
2424 X := StrToIntDef(GetNext(), 0);
2425 Y := StrToIntDef(GetNext(), 0);
2427 if GetNext() = '1' then
2428 Direction := D_LEFT
2429 else
2430 Direction := D_RIGHT;
2431 end;
2433 OBJECT_AREA:
2434 with CopyBuf[i].Area do
2435 begin
2436 AreaType := StrToIntDef(GetNext(), AREA_PLAYERPOINT1);
2437 X := StrToIntDef(GetNext(), 0);
2438 Y := StrToIntDef(GetNext(), 0);
2439 if GetNext() = '1' then
2440 Direction := D_LEFT
2441 else
2442 Direction := D_RIGHT;
2443 end;
2445 OBJECT_TRIGGER:
2446 with CopyBuf[i].Trigger do
2447 begin
2448 TriggerType := StrToIntDef(GetNext(), TRIGGER_EXIT);
2449 X := StrToIntDef(GetNext(), 0);
2450 Y := StrToIntDef(GetNext(), 0);
2451 Width := StrToIntDef(GetNext(), 16);
2452 Height := StrToIntDef(GetNext(), 16);
2453 ActivateType := StrToIntDef(GetNext(), 0);
2454 Key := StrToIntDef(GetNext(), 0);
2455 Enabled := (GetNext() = '1');
2456 TexturePanel := StrToIntDef(GetNext(), 0);
2458 for j := 0 to 127 do
2459 Data.Default[j] := StrToIntDef(GetNext(), 0);
2460 end;
2461 end;
2462 end;
2463 end;
2465 //----------------------------------------
2466 //Закончились вспомогательные процедуры
2467 //----------------------------------------
2469 procedure TMainForm.RefreshRecentMenu();
2470 var
2471 i: Integer;
2472 MI: TMenuItem;
2473 begin
2474 // Лишние запомненные карты:
2475 while RecentFiles.Count > RecentCount do
2476 RecentFiles.Delete(RecentFiles.Count-1);
2478 // Лишние строки меню:
2479 while MainMenu.Items[0].Count > RECENT_FILES_MENU_START do
2480 MainMenu.Items[0].Delete(MainMenu.Items[0].Count-1);
2482 // Отделение списка карт от строки "Выход":
2483 if RecentFiles.Count > 0 then
2484 begin
2485 MI := TMenuItem.Create(MainMenu.Items[0]);
2486 MI.Caption := '-';
2487 MainMenu.Items[0].Add(MI);
2488 end;
2490 // Добавление в меню списка запомненных карт:
2491 for i := 0 to RecentFiles.Count-1 do
2492 begin
2493 MI := TMenuItem.Create(MainMenu.Items[0]);
2494 MI.Caption := IntToStr(i+1) + ' ' + RecentFiles[i];
2495 MI.OnClick := aRecentFileExecute;
2496 MainMenu.Items[0].Add(MI);
2497 end;
2498 end;
2500 procedure TMainForm.aRecentFileExecute(Sender: TObject);
2501 var
2502 n, pw: Integer;
2503 s, fn: String;
2504 b: Boolean;
2505 begin
2506 s := LowerCase((Sender as TMenuItem).Caption);
2507 Delete(s, Pos('&', s), 1);
2508 s := Trim(Copy(s, 1, 2));
2509 n := StrToIntDef(s, 0) - 1;
2511 if (n < 0) or (n >= RecentFiles.Count) then
2512 Exit;
2514 s := RecentFiles[n];
2515 pw := Pos('.wad:\', LowerCase(s));
2516 b := False;
2518 if pw > 0 then
2519 begin // Map name included
2520 fn := Copy(s, 1, pw + 3);
2521 Delete(s, 1, pw + 5);
2522 if (FileExists(fn)) then
2523 begin
2524 OpenMap(fn, s);
2525 b := True;
2526 end;
2527 end
2528 else // Only wad name
2529 if (FileExists(s)) then
2530 begin
2531 OpenMap(s, '');
2532 b := True;
2533 end;
2535 if (not b) and (MessageBox(0, PChar(_lc[I_MSG_DEL_RECENT_PROMT]),
2536 PChar(_lc[I_MSG_DEL_RECENT]), MB_ICONQUESTION or MB_YESNO) = idYes) then
2537 begin
2538 RecentFiles.Delete(n);
2539 RefreshRecentMenu();
2540 end;
2541 end;
2543 procedure TMainForm.aEditorOptionsExecute(Sender: TObject);
2544 begin
2545 OptionsForm.ShowModal();
2546 end;
2548 procedure LoadStdFont(cfgres, texture: string; var FontID: DWORD);
2549 var
2550 cwdt, chgt: Byte;
2551 spc: ShortInt;
2552 ID: DWORD;
2553 wad: TWADEditor_1;
2554 cfgdata: Pointer;
2555 cfglen: Integer;
2556 config: TConfig;
2557 begin
2558 cfglen := 0;
2560 wad := TWADEditor_1.Create;
2561 if wad.ReadFile(EditorDir+'data/Game.wad') then
2562 wad.GetResource('FONTS', cfgres, cfgdata, cfglen);
2563 wad.Free();
2565 if cfglen <> 0 then
2566 begin
2567 if not g_CreateTextureWAD('FONT_STD', EditorDir+'data/Game.wad:FONTS\'+texture) then
2568 e_WriteLog('ERROR ERROR ERROR', MSG_WARNING);
2570 config := TConfig.CreateMem(cfgdata, cfglen);
2571 cwdt := Min(Max(config.ReadInt('FontMap', 'CharWidth', 0), 0), 255);
2572 chgt := Min(Max(config.ReadInt('FontMap', 'CharHeight', 0), 0), 255);
2573 spc := Min(Max(config.ReadInt('FontMap', 'Kerning', 0), -128), 127);
2575 if g_GetTexture('FONT_STD', ID) then
2576 e_TextureFontBuild(ID, FontID, cwdt, chgt, spc-2);
2578 config.Free();
2579 end
2580 else
2581 e_WriteLog('Could not load FONT_STD', MSG_WARNING);
2583 if cfglen <> 0 then FreeMem(cfgdata);
2584 end;
2586 procedure TMainForm.FormCreate(Sender: TObject);
2587 var
2588 config: TConfig;
2589 i: Integer;
2590 s: String;
2591 begin
2592 Randomize();
2594 EditorDir := ExtractFilePath(Application.ExeName);
2596 e_InitLog(EditorDir+'Editor.log', WM_NEWFILE);
2598 slInvalidTextures := TStringList.Create;
2600 ShowLayer(LAYER_BACK, True);
2601 ShowLayer(LAYER_WALLS, True);
2602 ShowLayer(LAYER_FOREGROUND, True);
2603 ShowLayer(LAYER_STEPS, True);
2604 ShowLayer(LAYER_WATER, True);
2605 ShowLayer(LAYER_ITEMS, True);
2606 ShowLayer(LAYER_MONSTERS, True);
2607 ShowLayer(LAYER_AREAS, True);
2608 ShowLayer(LAYER_TRIGGERS, True);
2610 ClearMap();
2612 FormCaption := MainForm.Caption;
2613 OpenedMap := '';
2614 OpenedWAD := '';
2616 config := TConfig.CreateFile(EditorDir+'Editor.cfg');
2618 if config.ReadInt('Editor', 'XPos', -1) = -1 then
2619 Position := poDesktopCenter
2620 else begin
2621 Left := config.ReadInt('Editor', 'XPos', Left);
2622 Top := config.ReadInt('Editor', 'YPos', Top);
2623 Width := config.ReadInt('Editor', 'Width', Width);
2624 Height := config.ReadInt('Editor', 'Height', Height);
2625 end;
2626 if config.ReadBool('Editor', 'Maximize', False) then
2627 WindowState := wsMaximized;
2628 ShowMap := config.ReadBool('Editor', 'Minimap', False);
2629 PanelProps.Width := config.ReadInt('Editor', 'PanelProps', PanelProps.ClientWidth);
2630 Splitter1.Left := PanelProps.Left;
2631 PanelObjs.Height := config.ReadInt('Editor', 'PanelObjs', PanelObjs.ClientHeight);
2632 Splitter2.Top := PanelObjs.Top;
2633 StatusBar.Top := PanelObjs.BoundsRect.Bottom;
2634 DotEnable := config.ReadBool('Editor', 'DotEnable', True);
2635 DotColor := config.ReadInt('Editor', 'DotColor', $FFFFFF);
2636 DotStepOne := config.ReadInt('Editor', 'DotStepOne', 16);
2637 DotStepTwo := config.ReadInt('Editor', 'DotStepTwo', 8);
2638 DotStep := config.ReadInt('Editor', 'DotStep', DotStepOne);
2639 DrawTexturePanel := config.ReadBool('Editor', 'DrawTexturePanel', True);
2640 DrawPanelSize := config.ReadBool('Editor', 'DrawPanelSize', True);
2641 BackColor := config.ReadInt('Editor', 'BackColor', $7F6040);
2642 PreviewColor := config.ReadInt('Editor', 'PreviewColor', $00FF00);
2643 gColorEdge := config.ReadInt('Editor', 'EdgeColor', COLOR_EDGE);
2644 gAlphaEdge := config.ReadInt('Editor', 'EdgeAlpha', ALPHA_EDGE);
2645 if gAlphaEdge = 255 then
2646 gAlphaEdge := ALPHA_EDGE;
2647 drEdge[0] := GetRValue(gColorEdge);
2648 drEdge[1] := GetGValue(gColorEdge);
2649 drEdge[2] := GetBValue(gColorEdge);
2650 if not config.ReadBool('Editor', 'EdgeShow', True) then
2651 drEdge[3] := 255
2652 else
2653 drEdge[3] := gAlphaEdge;
2654 gAlphaTriggerLine := config.ReadInt('Editor', 'LineAlpha', ALPHA_LINE);
2655 if gAlphaTriggerLine = 255 then
2656 gAlphaTriggerLine := ALPHA_LINE;
2657 gAlphaTriggerArea := config.ReadInt('Editor', 'TriggerAlpha', ALPHA_AREA);
2658 if gAlphaTriggerArea = 255 then
2659 gAlphaTriggerArea := ALPHA_AREA;
2660 if config.ReadInt('Editor', 'Scale', 0) = 1 then
2661 Scale := 2
2662 else
2663 Scale := 1;
2664 if config.ReadInt('Editor', 'DotSize', 0) = 1 then
2665 DotSize := 2
2666 else
2667 DotSize := 1;
2668 OpenDialog.InitialDir := config.ReadStr('Editor', 'LastOpenDir', EditorDir);
2669 SaveDialog.InitialDir := config.ReadStr('Editor', 'LastSaveDir', EditorDir);
2671 s := config.ReadStr('Editor', 'Language', '');
2672 gLanguage := s;
2674 RecentCount := config.ReadInt('Editor', 'RecentCount', 5);
2675 if RecentCount > 10 then
2676 RecentCount := 10;
2677 if RecentCount < 2 then
2678 RecentCount := 2;
2680 RecentFiles := TStringList.Create();
2681 for i := 0 to RecentCount-1 do
2682 begin
2683 s := config.ReadStr('RecentFiles', IntToStr(i+1), '');
2684 if s <> '' then
2685 RecentFiles.Add(s);
2686 end;
2687 RefreshRecentMenu();
2689 config.Free();
2691 tbShowMap.Down := ShowMap;
2692 tbGridOn.Down := DotEnable;
2693 pcObjects.ActivePageIndex := 0;
2694 Application.Title := _lc[I_EDITOR_TITLE];
2696 Application.OnIdle := OnIdle;
2697 end;
2699 procedure PrintBlack(X, Y: Integer; Text: string; FontID: DWORD);
2700 begin
2701 // NOTE: all the font printing routines assume CP1251
2702 e_TextureFontPrintEx(X, Y, Text, FontID, 0, 0, 0, 1.0);
2703 end;
2705 procedure TMainForm.Draw();
2706 var
2707 x, y: Integer;
2708 a, b: Integer;
2709 ID, PID: DWORD;
2710 Width, Height: Word;
2711 Rect: TRectWH;
2712 ObjCount: Word;
2713 aX, aY, aX2, aY2, XX, ScaleSz: Integer;
2714 begin
2715 e_BeginRender();
2717 e_Clear(GL_COLOR_BUFFER_BIT,
2718 GetRValue(BackColor)/255,
2719 GetGValue(BackColor)/255,
2720 GetBValue(BackColor)/255);
2722 DrawMap();
2724 ObjCount := SelectedObjectCount();
2726 // Обводим выделенные объекты красной рамкой:
2727 if ObjCount > 0 then
2728 begin
2729 for a := 0 to High(SelectedObjects) do
2730 if SelectedObjects[a].Live then
2731 begin
2732 Rect := ObjectGetRect(SelectedObjects[a].ObjectType, SelectedObjects[a].ID);
2734 with Rect do
2735 begin
2736 e_DrawQuad(X+MapOffset.X, Y+MapOffset.Y,
2737 X+MapOffset.X+Width-1, Y+MapOffset.Y+Height-1,
2738 255, 0, 0);
2740 // Рисуем точки изменения размеров:
2741 if (ObjCount = 1) and
2742 (SelectedObjects[GetFirstSelected].ObjectType in [OBJECT_PANEL, OBJECT_TRIGGER]) then
2743 begin
2744 e_DrawPoint(5, X+MapOffset.X, Y+MapOffset.Y+(Height div 2), 255, 255, 255);
2745 e_DrawPoint(5, X+MapOffset.X+Width-1, Y+MapOffset.Y+(Height div 2), 255, 255, 255);
2746 e_DrawPoint(5, X+MapOffset.X+(Width div 2), Y+MapOffset.Y, 255, 255, 255);
2747 e_DrawPoint(5, X+MapOffset.X+(Width div 2), Y+MapOffset.Y+Height-1, 255, 255, 255);
2749 e_DrawPoint(3, X+MapOffset.X, Y+MapOffset.Y+(Height div 2), 255, 0, 0);
2750 e_DrawPoint(3, X+MapOffset.X+Width-1, Y+MapOffset.Y+(Height div 2), 255, 0, 0);
2751 e_DrawPoint(3, X+MapOffset.X+(Width div 2), Y+MapOffset.Y, 255, 0, 0);
2752 e_DrawPoint(3, X+MapOffset.X+(Width div 2), Y+MapOffset.Y+Height-1, 255, 0, 0);
2753 end;
2754 end;
2755 end;
2756 end;
2758 // Рисуем сетку:
2759 if DotEnable and (not PreviewMode) then
2760 begin
2761 if DotSize = 2 then
2762 a := -1
2763 else
2764 a := 0;
2766 for x := 0 to (RenderPanel.Width div DotStep) do
2767 for y := 0 to (RenderPanel.Height div DotStep) do
2768 e_DrawPoint(DotSize, x*DotStep + a, y*DotStep + a,
2769 GetRValue(DotColor),
2770 GetGValue(DotColor),
2771 GetBValue(DotColor));
2772 end;
2774 // Превью текстуры:
2775 if (lbTextureList.ItemIndex <> -1) and (cbPreview.Checked) and
2776 (not IsSpecialTextureSel()) and (not PreviewMode) then
2777 begin
2778 if not g_GetTexture(SelectedTexture(), ID) then
2779 g_GetTexture('NOTEXTURE', ID);
2780 g_GetTextureSizeByID(ID, Width, Height);
2781 if g_GetTexture('PREVIEW', PID) then
2782 e_DrawFill(PID, RenderPanel.Width-Width, RenderPanel.Height-Height, Width div 16 + 1, Height div 16 + 1, 0, True, False);
2783 e_Draw(ID, RenderPanel.Width-Width, RenderPanel.Height-Height, 0, True, False);
2784 end;
2786 // Подсказка при выборе точки Телепорта:
2787 if SelectFlag = SELECTFLAG_TELEPORT then
2788 begin
2789 with gTriggers[SelectedObjects[GetFirstSelected()].ID] do
2790 if Data.d2d_teleport then
2791 e_DrawLine(2, MousePos.X-16, MousePos.Y-1,
2792 MousePos.X+16, MousePos.Y-1,
2793 0, 0, 255)
2794 else
2795 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+AreaSize[AREA_DMPOINT].Width-1,
2796 MousePos.Y+AreaSize[AREA_DMPOINT].Height-1, 255, 255, 255);
2798 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 192, 192, 192, 127);
2799 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 255, 255, 255);
2800 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_TELEPORT], gEditorFont);
2801 end;
2803 // Подсказка при выборе точки появления:
2804 if SelectFlag = SELECTFLAG_SPAWNPOINT then
2805 begin
2806 e_DrawLine(2, MousePos.X-16, MousePos.Y-1,
2807 MousePos.X+16, MousePos.Y-1,
2808 0, 0, 255);
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_SPAWN], gEditorFont);
2812 end;
2814 // Подсказка при выборе панели двери:
2815 if SelectFlag = SELECTFLAG_DOOR then
2816 begin
2817 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 192, 192, 192, 127);
2818 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 255, 255, 255);
2819 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_PANEL_DOOR], gEditorFont);
2820 end;
2822 // Подсказка при выборе панели с текстурой:
2823 if SelectFlag = SELECTFLAG_TEXTURE then
2824 begin
2825 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+196, MousePos.Y+18, 192, 192, 192, 127);
2826 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+196, MousePos.Y+18, 255, 255, 255);
2827 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_PANEL_TEXTURE], gEditorFont);
2828 end;
2830 // Подсказка при выборе панели индикации выстрела:
2831 if SelectFlag = SELECTFLAG_SHOTPANEL then
2832 begin
2833 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+316, MousePos.Y+18, 192, 192, 192, 127);
2834 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+316, MousePos.Y+18, 255, 255, 255);
2835 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_PANEL_SHOT], gEditorFont);
2836 end;
2838 // Подсказка при выборе панели лифта:
2839 if SelectFlag = SELECTFLAG_LIFT then
2840 begin
2841 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 192, 192, 192, 127);
2842 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 255, 255, 255);
2843 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_PANEL_LIFT], gEditorFont);
2844 end;
2846 // Подсказка при выборе монстра:
2847 if SelectFlag = SELECTFLAG_MONSTER then
2848 begin
2849 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+120, MousePos.Y+18, 192, 192, 192, 127);
2850 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+120, MousePos.Y+18, 255, 255, 255);
2851 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_MONSTER], gEditorFont);
2852 end;
2854 // Подсказка при выборе области воздействия:
2855 if DrawPressRect then
2856 begin
2857 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+204, MousePos.Y+18, 192, 192, 192, 127);
2858 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+204, MousePos.Y+18, 255, 255, 255);
2859 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_EXT_AREA], gEditorFont);
2860 end;
2862 // Рисуем текстуры, если чертим панель:
2863 if (MouseAction = MOUSEACTION_DRAWPANEL) and (DrawTexturePanel) and
2864 (lbTextureList.ItemIndex <> -1) and (DrawRect <> nil) and
2865 (lbPanelType.ItemIndex in [0..8]) and not IsSpecialTextureSel() then
2866 begin
2867 if not g_GetTexture(SelectedTexture(), ID) then
2868 g_GetTexture('NOTEXTURE', ID);
2869 g_GetTextureSizeByID(ID, Width, Height);
2870 with DrawRect^ do
2871 e_DrawFill(ID, Min(Left, Right), Min(Top, Bottom), Abs(Right-Left) div Width,
2872 Abs(Bottom-Top) div Height, 0, True, False);
2873 end;
2875 // Прямоугольник выделения:
2876 if DrawRect <> nil then
2877 with DrawRect^ do
2878 e_DrawQuad(Left, Top, Right-1, Bottom-1, 255, 255, 255);
2880 // Чертим мышью панель/триггер или меняем мышью их размер:
2881 if (MouseAction in [MOUSEACTION_DRAWPANEL, MOUSEACTION_DRAWTRIGGER, MOUSEACTION_RESIZE]) and
2882 (DrawPanelSize) then
2883 begin
2884 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+88, MousePos.Y+33, 192, 192, 192, 127);
2885 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+88, MousePos.Y+33, 255, 255, 255);
2887 if MouseAction in [MOUSEACTION_DRAWPANEL, MOUSEACTION_DRAWTRIGGER] then
2888 begin // Чертим новый
2889 PrintBlack(MousePos.X+2, MousePos.Y+2, Format(_glc[I_HINT_WIDTH],
2890 [Abs(MousePos.X-MouseLDownPos.X)]), gEditorFont);
2891 PrintBlack(MousePos.X+2, MousePos.Y+14, Format(_glc[I_HINT_HEIGHT],
2892 [Abs(MousePos.Y-MouseLDownPos.Y)]), gEditorFont);
2893 end
2894 else // Растягиваем существующий
2895 if SelectedObjects[GetFirstSelected].ObjectType in [OBJECT_PANEL, OBJECT_TRIGGER] then
2896 begin
2897 if SelectedObjects[GetFirstSelected].ObjectType = OBJECT_PANEL then
2898 begin
2899 Width := gPanels[SelectedObjects[GetFirstSelected].ID].Width;
2900 Height := gPanels[SelectedObjects[GetFirstSelected].ID].Height;
2901 end
2902 else
2903 begin
2904 Width := gTriggers[SelectedObjects[GetFirstSelected].ID].Width;
2905 Height := gTriggers[SelectedObjects[GetFirstSelected].ID].Height;
2906 end;
2908 PrintBlack(MousePos.X+2, MousePos.Y+2, Format(_glc[I_HINT_WIDTH], [Width]),
2909 gEditorFont);
2910 PrintBlack(MousePos.X+2, MousePos.Y+14, Format(_glc[I_HINT_HEIGHT], [Height]),
2911 gEditorFont);
2912 end;
2913 end;
2915 // Ближайшая к курсору мыши точка на сетке:
2916 e_DrawPoint(3, MousePos.X, MousePos.Y, 0, 0, 255);
2918 // Мини-карта:
2919 if ShowMap then
2920 begin
2921 // Сколько пикселов карты в 1 пикселе мини-карты:
2922 ScaleSz := 16 div Scale;
2923 // Размеры мини-карты:
2924 aX := max(gMapInfo.Width div ScaleSz, 1);
2925 aY := max(gMapInfo.Height div ScaleSz, 1);
2926 // X-координата на RenderPanel нулевой x-координаты карты:
2927 XX := RenderPanel.Width - aX - 1;
2928 // Рамка карты:
2929 e_DrawFillQuad(XX-1, 0, RenderPanel.Width-1, aY+1, 0, 0, 0, 0);
2930 e_DrawQuad(XX-1, 0, RenderPanel.Width-1, aY+1, 197, 197, 197);
2932 if gPanels <> nil then
2933 begin
2934 // Рисуем панели:
2935 for a := 0 to High(gPanels) do
2936 with gPanels[a] do
2937 if PanelType <> 0 then
2938 begin
2939 // Левый верхний угол:
2940 aX := XX + (X div ScaleSz);
2941 aY := 1 + (Y div ScaleSz);
2942 // Размеры:
2943 aX2 := max(Width div ScaleSz, 1);
2944 aY2 := max(Height div ScaleSz, 1);
2945 // Правый нижний угол:
2946 aX2 := aX + aX2 - 1;
2947 aY2 := aY + aY2 - 1;
2949 case PanelType of
2950 PANEL_WALL: e_DrawFillQuad(aX, aY, aX2, aY2, 208, 208, 208, 0);
2951 PANEL_WATER: e_DrawFillQuad(aX, aY, aX2, aY2, 0, 0, 192, 0);
2952 PANEL_ACID1: e_DrawFillQuad(aX, aY, aX2, aY2, 0, 176, 0, 0);
2953 PANEL_ACID2: e_DrawFillQuad(aX, aY, aX2, aY2, 176, 0, 0, 0);
2954 PANEL_STEP: e_DrawFillQuad(aX, aY, aX2, aY2, 128, 128, 128, 0);
2955 PANEL_LIFTUP: e_DrawFillQuad(aX, aY, aX2, aY2, 116, 72, 36, 0);
2956 PANEL_LIFTDOWN: e_DrawFillQuad(aX, aY, aX2, aY2, 116, 124, 96, 0);
2957 PANEL_LIFTLEFT: e_DrawFillQuad(aX, aY, aX2, aY2, 200, 80, 4, 0);
2958 PANEL_LIFTRIGHT: e_DrawFillQuad(aX, aY, aX2, aY2, 252, 140, 56, 0);
2959 PANEL_OPENDOOR: e_DrawFillQuad(aX, aY, aX2, aY2, 100, 220, 92, 0);
2960 PANEL_CLOSEDOOR: e_DrawFillQuad(aX, aY, aX2, aY2, 212, 184, 64, 0);
2961 PANEL_BLOCKMON: e_DrawFillQuad(aX, aY, aX2, aY2, 192, 0, 192, 0);
2962 end;
2963 end;
2965 // Рисуем красным выделенные панели:
2966 if SelectedObjects <> nil then
2967 for b := 0 to High(SelectedObjects) do
2968 with SelectedObjects[b] do
2969 if Live and (ObjectType = OBJECT_PANEL) then
2970 with gPanels[SelectedObjects[b].ID] do
2971 if PanelType and not(PANEL_BACK or PANEL_FORE) <> 0 then
2972 begin
2973 // Левый верхний угол:
2974 aX := XX + (X div ScaleSz);
2975 aY := 1 + (Y div ScaleSz);
2976 // Размеры:
2977 aX2 := max(Width div ScaleSz, 1);
2978 aY2 := max(Height div ScaleSz, 1);
2979 // Правый нижний угол:
2980 aX2 := aX + aX2 - 1;
2981 aY2 := aY + aY2 - 1;
2983 e_DrawFillQuad(aX, aY, aX2, aY2, 255, 0, 0, 0)
2984 end;
2985 end;
2987 if (gMapInfo.Width > RenderPanel.Width) or
2988 (gMapInfo.Height > RenderPanel.Height) then
2989 begin
2990 // Окно, показывающее текущее положение экрана на карте:
2991 // Размеры окна:
2992 x := max(min(RenderPanel.Width, gMapInfo.Width) div ScaleSz, 1);
2993 y := max(min(RenderPanel.Height, gMapInfo.Height) div ScaleSz, 1);
2994 // Левый верхний угол:
2995 aX := XX + ((-MapOffset.X) div ScaleSz);
2996 aY := 1 + ((-MapOffset.Y) div ScaleSz);
2997 // Правый нижний угол:
2998 aX2 := aX + x - 1;
2999 aY2 := aY + y - 1;
3001 e_DrawFillQuad(aX, aY, aX2, aY2, 127, 192, 127, 127, B_BLEND);
3002 e_DrawQuad(aX, aY, aX2, aY2, 255, 0, 0);
3003 end;
3004 end; // Мини-карта
3006 e_EndRender();
3007 RenderPanel.SwapBuffers();
3008 end;
3010 procedure TMainForm.FormResize(Sender: TObject);
3011 begin
3012 e_SetViewPort(0, 0, RenderPanel.Width, RenderPanel.Height);
3014 if gMapInfo.Width >= RenderPanel.Width then
3015 sbHorizontal.Max := Normalize16(gMapInfo.Width-RenderPanel.Width+16)
3016 else
3017 sbHorizontal.Max := 0;
3019 if gMapInfo.Height >= RenderPanel.Height then
3020 sbVertical.Max := Normalize16(gMapInfo.Height-RenderPanel.Height+16)
3021 else
3022 sbVertical.Max := 0;
3024 MapOffset.X := -Normalize16(sbHorizontal.Position);
3025 MapOffset.Y := -Normalize16(sbVertical.Position);
3026 end;
3028 procedure SelectNextObject(X, Y: Integer; ObjectType: Byte; ID: DWORD);
3029 var
3030 j, j_max: Integer;
3031 res: Boolean;
3032 begin
3033 j_max := 0; // shut up compiler
3034 case ObjectType of
3035 OBJECT_PANEL:
3036 begin
3037 res := (gPanels <> nil) and
3038 PanelInShownLayer(gPanels[ID].PanelType) and
3039 g_CollidePoint(X, Y, gPanels[ID].X, gPanels[ID].Y,
3040 gPanels[ID].Width,
3041 gPanels[ID].Height);
3042 j_max := Length(gPanels) - 1;
3043 end;
3045 OBJECT_ITEM:
3046 begin
3047 res := (gItems <> nil) and
3048 LayerEnabled[LAYER_ITEMS] and
3049 g_CollidePoint(X, Y, gItems[ID].X, gItems[ID].Y,
3050 ItemSize[gItems[ID].ItemType][0],
3051 ItemSize[gItems[ID].ItemType][1]);
3052 j_max := Length(gItems) - 1;
3053 end;
3055 OBJECT_MONSTER:
3056 begin
3057 res := (gMonsters <> nil) and
3058 LayerEnabled[LAYER_MONSTERS] and
3059 g_CollidePoint(X, Y, gMonsters[ID].X, gMonsters[ID].Y,
3060 MonsterSize[gMonsters[ID].MonsterType].Width,
3061 MonsterSize[gMonsters[ID].MonsterType].Height);
3062 j_max := Length(gMonsters) - 1;
3063 end;
3065 OBJECT_AREA:
3066 begin
3067 res := (gAreas <> nil) and
3068 LayerEnabled[LAYER_AREAS] and
3069 g_CollidePoint(X, Y, gAreas[ID].X, gAreas[ID].Y,
3070 AreaSize[gAreas[ID].AreaType].Width,
3071 AreaSize[gAreas[ID].AreaType].Height);
3072 j_max := Length(gAreas) - 1;
3073 end;
3075 OBJECT_TRIGGER:
3076 begin
3077 res := (gTriggers <> nil) and
3078 LayerEnabled[LAYER_TRIGGERS] and
3079 g_CollidePoint(X, Y, gTriggers[ID].X, gTriggers[ID].Y,
3080 gTriggers[ID].Width,
3081 gTriggers[ID].Height);
3082 j_max := Length(gTriggers) - 1;
3083 end;
3085 else
3086 res := False;
3087 end;
3089 if not res then
3090 Exit;
3092 // Перебор ID: от ID-1 до 0; потом от High до ID+1:
3093 j := ID;
3095 while True do
3096 begin
3097 Dec(j);
3099 if j < 0 then
3100 j := j_max;
3101 if j = Integer(ID) then
3102 Break;
3104 case ObjectType of
3105 OBJECT_PANEL:
3106 res := PanelInShownLayer(gPanels[j].PanelType) and
3107 g_CollidePoint(X, Y, gPanels[j].X, gPanels[j].Y,
3108 gPanels[j].Width,
3109 gPanels[j].Height);
3110 OBJECT_ITEM:
3111 res := (gItems[j].ItemType <> ITEM_NONE) and
3112 g_CollidePoint(X, Y, gItems[j].X, gItems[j].Y,
3113 ItemSize[gItems[j].ItemType][0],
3114 ItemSize[gItems[j].ItemType][1]);
3115 OBJECT_MONSTER:
3116 res := (gMonsters[j].MonsterType <> MONSTER_NONE) and
3117 g_CollidePoint(X, Y, gMonsters[j].X, gMonsters[j].Y,
3118 MonsterSize[gMonsters[j].MonsterType].Width,
3119 MonsterSize[gMonsters[j].MonsterType].Height);
3120 OBJECT_AREA:
3121 res := (gAreas[j].AreaType <> AREA_NONE) and
3122 g_CollidePoint(X, Y, gAreas[j].X, gAreas[j].Y,
3123 AreaSize[gAreas[j].AreaType].Width,
3124 AreaSize[gAreas[j].AreaType].Height);
3125 OBJECT_TRIGGER:
3126 res := (gTriggers[j].TriggerType <> TRIGGER_NONE) and
3127 g_CollidePoint(X, Y, gTriggers[j].X, gTriggers[j].Y,
3128 gTriggers[j].Width,
3129 gTriggers[j].Height);
3130 else
3131 res := False;
3132 end;
3134 if res then
3135 begin
3136 SetLength(SelectedObjects, 1);
3138 SelectedObjects[0].ObjectType := ObjectType;
3139 SelectedObjects[0].ID := j;
3140 SelectedObjects[0].Live := True;
3142 FillProperty();
3143 Break;
3144 end;
3145 end;
3146 end;
3148 procedure TMainForm.RenderPanelMouseDown(Sender: TObject;
3149 Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
3150 var
3151 i: Integer;
3152 Rect: TRectWH;
3153 c1, c2, c3, c4: Boolean;
3154 item: TItem;
3155 area: TArea;
3156 monster: TMonster;
3157 IDArray: DWArray;
3158 begin
3159 MainForm.ActiveControl := RenderPanel;
3160 RenderPanel.SetFocus();
3162 RenderPanelMouseMove(RenderPanel, Shift, X, Y);
3164 if Button = mbLeft then // Left Mouse Button
3165 begin
3166 // Двигаем карту с помощью мыши и мини-карты:
3167 if ShowMap and
3168 g_CollidePoint(X, Y,
3169 RenderPanel.Width-max(gMapInfo.Width div (16 div Scale), 1)-1,
3170 1,
3171 max(gMapInfo.Width div (16 div Scale), 1),
3172 max(gMapInfo.Height div (16 div Scale), 1) ) then
3173 begin
3174 MoveMap(X, Y);
3175 MouseAction := MOUSEACTION_MOVEMAP;
3176 end
3177 else // Ставим предмет/монстра/область:
3178 if (pcObjects.ActivePageIndex in [1, 2, 3]) and
3179 (not (ssShift in Shift)) then
3180 begin
3181 case pcObjects.ActivePageIndex of
3182 1:
3183 if lbItemList.ItemIndex = -1 then
3184 ErrorMessageBox(_lc[I_MSG_CHOOSE_ITEM])
3185 else
3186 begin
3187 item.ItemType := lbItemList.ItemIndex + ITEM_MEDKIT_SMALL;
3188 if item.ItemType >= ITEM_WEAPON_KASTET then
3189 item.ItemType := item.ItemType + 2;
3190 item.X := MousePos.X-MapOffset.X;
3191 item.Y := MousePos.Y-MapOffset.Y;
3193 if not (ssCtrl in Shift) then
3194 begin
3195 item.X := item.X - (ItemSize[item.ItemType][0] div 2);
3196 item.Y := item.Y - ItemSize[item.ItemType][1];
3197 end;
3199 item.OnlyDM := cbOnlyDM.Checked;
3200 item.Fall := cbFall.Checked;
3201 Undo_Add(OBJECT_ITEM, AddItem(item));
3202 end;
3203 2:
3204 if lbMonsterList.ItemIndex = -1 then
3205 ErrorMessageBox(_lc[I_MSG_CHOOSE_MONSTER])
3206 else
3207 begin
3208 monster.MonsterType := lbMonsterList.ItemIndex + MONSTER_DEMON;
3209 monster.X := MousePos.X-MapOffset.X;
3210 monster.Y := MousePos.Y-MapOffset.Y;
3212 if not (ssCtrl in Shift) then
3213 begin
3214 monster.X := monster.X - (MonsterSize[monster.MonsterType].Width div 2);
3215 monster.Y := monster.Y - MonsterSize[monster.MonsterType].Height;
3216 end;
3218 if rbMonsterLeft.Checked then
3219 monster.Direction := D_LEFT
3220 else
3221 monster.Direction := D_RIGHT;
3222 Undo_Add(OBJECT_MONSTER, AddMonster(monster));
3223 end;
3224 3:
3225 if lbAreasList.ItemIndex = -1 then
3226 ErrorMessageBox(_lc[I_MSG_CHOOSE_AREA])
3227 else
3228 if (lbAreasList.ItemIndex + 1) <> AREA_DOMFLAG then
3229 begin
3230 area.AreaType := lbAreasList.ItemIndex + AREA_PLAYERPOINT1;
3231 area.X := MousePos.X-MapOffset.X;
3232 area.Y := MousePos.Y-MapOffset.Y;
3234 if not (ssCtrl in Shift) then
3235 begin
3236 area.X := area.X - (AreaSize[area.AreaType].Width div 2);
3237 area.Y := area.Y - AreaSize[area.AreaType].Height;
3238 end;
3240 if rbAreaLeft.Checked then
3241 area.Direction := D_LEFT
3242 else
3243 area.Direction := D_RIGHT;
3244 Undo_Add(OBJECT_AREA, AddArea(area));
3245 end;
3246 end;
3247 end
3248 else
3249 begin
3250 i := GetFirstSelected();
3252 // Выбираем объект под текущим:
3253 if (SelectedObjects <> nil) and
3254 (ssShift in Shift) and (i >= 0) and
3255 (SelectedObjects[i].Live) then
3256 begin
3257 if SelectedObjectCount() = 1 then
3258 SelectNextObject(X-MapOffset.X, Y-MapOffset.Y,
3259 SelectedObjects[i].ObjectType,
3260 SelectedObjects[i].ID);
3261 end
3262 else
3263 begin
3264 // Рисуем область триггера "Расширитель":
3265 if DrawPressRect and (i >= 0) and
3266 (SelectedObjects[i].ObjectType = OBJECT_TRIGGER) and
3267 (gTriggers[SelectedObjects[i].ID].TriggerType in
3268 [TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF]) then
3269 MouseAction := MOUSEACTION_DRAWPRESS
3270 else // Рисуем панель:
3271 if pcObjects.ActivePageIndex = 0 then
3272 begin
3273 if (lbPanelType.ItemIndex >= 0) then
3274 MouseAction := MOUSEACTION_DRAWPANEL
3275 end
3276 else // Рисуем триггер:
3277 if (lbTriggersList.ItemIndex >= 0) then
3278 begin
3279 MouseAction := MOUSEACTION_DRAWTRIGGER;
3280 end;
3281 end;
3282 end;
3283 end; // if Button = mbLeft
3285 if Button = mbRight then // Right Mouse Button
3286 begin
3287 // Клик по мини-карте:
3288 if ShowMap and
3289 g_CollidePoint(X, Y,
3290 RenderPanel.Width-max(gMapInfo.Width div (16 div Scale), 1)-1,
3291 1,
3292 max(gMapInfo.Width div (16 div Scale), 1),
3293 max(gMapInfo.Height div (16 div Scale), 1) ) then
3294 begin
3295 MouseAction := MOUSEACTION_NOACTION;
3296 end
3297 else // Нужно что-то выбрать мышью:
3298 if SelectFlag <> SELECTFLAG_NONE then
3299 begin
3300 case SelectFlag of
3301 SELECTFLAG_TELEPORT:
3302 // Точку назначения телепортации:
3303 with gTriggers[SelectedObjects[
3304 GetFirstSelected() ].ID].Data.TargetPoint do
3305 begin
3306 X := MousePos.X-MapOffset.X;
3307 Y := MousePos.Y-MapOffset.Y;
3308 end;
3310 SELECTFLAG_SPAWNPOINT:
3311 // Точку создания монстра:
3312 with gTriggers[SelectedObjects[GetFirstSelected()].ID] do
3313 if TriggerType = TRIGGER_SPAWNMONSTER then
3314 begin
3315 Data.MonPos.X := MousePos.X-MapOffset.X;
3316 Data.MonPos.Y := MousePos.Y-MapOffset.Y;
3317 end
3318 else if TriggerType = TRIGGER_SPAWNITEM then
3319 begin // Точка создания предмета:
3320 Data.ItemPos.X := MousePos.X-MapOffset.X;
3321 Data.ItemPos.Y := MousePos.Y-MapOffset.Y;
3322 end
3323 else if TriggerType = TRIGGER_SHOT then
3324 begin // Точка создания выстрела:
3325 Data.ShotPos.X := MousePos.X-MapOffset.X;
3326 Data.ShotPos.Y := MousePos.Y-MapOffset.Y;
3327 end;
3329 SELECTFLAG_DOOR:
3330 // Дверь:
3331 begin
3332 IDArray := ObjectInRect(X-MapOffset.X,
3333 Y-MapOffset.Y,
3334 2, 2, OBJECT_PANEL, True);
3335 if IDArray <> nil then
3336 begin
3337 for i := 0 to High(IDArray) do
3338 if (gPanels[IDArray[i]].PanelType = PANEL_OPENDOOR) or
3339 (gPanels[IDArray[i]].PanelType = PANEL_CLOSEDOOR) then
3340 begin
3341 gTriggers[SelectedObjects[
3342 GetFirstSelected() ].ID].Data.PanelID := IDArray[i];
3343 Break;
3344 end;
3345 end
3346 else
3347 gTriggers[SelectedObjects[
3348 GetFirstSelected() ].ID].Data.PanelID := -1;
3349 end;
3351 SELECTFLAG_TEXTURE:
3352 // Панель с текстурой:
3353 begin
3354 IDArray := ObjectInRect(X-MapOffset.X,
3355 Y-MapOffset.Y,
3356 2, 2, OBJECT_PANEL, True);
3357 if IDArray <> nil then
3358 begin
3359 for i := 0 to High(IDArray) do
3360 if ((gPanels[IDArray[i]].PanelType in
3361 [PANEL_WALL, PANEL_BACK, PANEL_FORE,
3362 PANEL_WATER, PANEL_ACID1, PANEL_ACID2,
3363 PANEL_STEP]) or
3364 (gPanels[IDArray[i]].PanelType = PANEL_OPENDOOR) or
3365 (gPanels[IDArray[i]].PanelType = PANEL_CLOSEDOOR)) and
3366 (gPanels[IDArray[i]].TextureName <> '') then
3367 begin
3368 gTriggers[SelectedObjects[
3369 GetFirstSelected() ].ID].TexturePanel := IDArray[i];
3370 Break;
3371 end;
3372 end
3373 else
3374 gTriggers[SelectedObjects[
3375 GetFirstSelected() ].ID].TexturePanel := -1;
3376 end;
3378 SELECTFLAG_LIFT:
3379 // Лифт:
3380 begin
3381 IDArray := ObjectInRect(X-MapOffset.X,
3382 Y-MapOffset.Y,
3383 2, 2, OBJECT_PANEL, True);
3384 if IDArray <> nil then
3385 begin
3386 for i := 0 to High(IDArray) do
3387 if (gPanels[IDArray[i]].PanelType = PANEL_LIFTUP) or
3388 (gPanels[IDArray[i]].PanelType = PANEL_LIFTDOWN) or
3389 (gPanels[IDArray[i]].PanelType = PANEL_LIFTLEFT) or
3390 (gPanels[IDArray[i]].PanelType = PANEL_LIFTRIGHT) then
3391 begin
3392 gTriggers[SelectedObjects[
3393 GetFirstSelected() ].ID].Data.PanelID := IDArray[i];
3394 Break;
3395 end;
3396 end
3397 else
3398 gTriggers[SelectedObjects[
3399 GetFirstSelected() ].ID].Data.PanelID := -1;
3400 end;
3402 SELECTFLAG_MONSTER:
3403 // Монстра:
3404 begin
3405 IDArray := ObjectInRect(X-MapOffset.X,
3406 Y-MapOffset.Y,
3407 2, 2, OBJECT_MONSTER, False);
3408 if IDArray <> nil then
3409 gTriggers[SelectedObjects[
3410 GetFirstSelected() ].ID].Data.MonsterID := IDArray[0]+1
3411 else
3412 gTriggers[SelectedObjects[
3413 GetFirstSelected() ].ID].Data.MonsterID := 0;
3414 end;
3416 SELECTFLAG_SHOTPANEL:
3417 // Панель индикации выстрела:
3418 begin
3419 if gTriggers[SelectedObjects[
3420 GetFirstSelected() ].ID].TriggerType = TRIGGER_SHOT then
3421 begin
3422 IDArray := ObjectInRect(X-MapOffset.X,
3423 Y-MapOffset.Y,
3424 2, 2, OBJECT_PANEL, True);
3425 if IDArray <> nil then
3426 begin
3427 for i := 0 to High(IDArray) do
3428 if ((gPanels[IDArray[i]].PanelType in
3429 [PANEL_WALL, PANEL_BACK, PANEL_FORE,
3430 PANEL_WATER, PANEL_ACID1, PANEL_ACID2,
3431 PANEL_STEP]) or
3432 (gPanels[IDArray[i]].PanelType = PANEL_OPENDOOR) or
3433 (gPanels[IDArray[i]].PanelType = PANEL_CLOSEDOOR)) and
3434 (gPanels[IDArray[i]].TextureName <> '') then
3435 begin
3436 gTriggers[SelectedObjects[
3437 GetFirstSelected() ].ID].Data.ShotPanelID := IDArray[i];
3438 Break;
3439 end;
3440 end
3441 else
3442 gTriggers[SelectedObjects[
3443 GetFirstSelected() ].ID].Data.ShotPanelID := -1;
3444 end;
3445 end;
3446 end;
3448 SelectFlag := SELECTFLAG_SELECTED;
3449 end
3450 else // if SelectFlag <> SELECTFLAG_NONE...
3451 begin
3452 // Что уже выбрано и не нажат Ctrl:
3453 if (SelectedObjects <> nil) and
3454 (not (ssCtrl in Shift)) then
3455 for i := 0 to High(SelectedObjects) do
3456 with SelectedObjects[i] do
3457 if Live then
3458 begin
3459 if (ObjectType in [OBJECT_PANEL, OBJECT_TRIGGER]) and
3460 (SelectedObjectCount() = 1) then
3461 begin
3462 Rect := ObjectGetRect(ObjectType, ID);
3464 c1 := g_Collide(X-MapOffset.X-1, Y-MapOffset.Y-1, 2, 2,
3465 Rect.X-2, Rect.Y+(Rect.Height div 2)-2, 4, 4);
3466 c2 := g_Collide(X-MapOffset.X-1, Y-MapOffset.Y-1, 2, 2,
3467 Rect.X+Rect.Width-3, Rect.Y+(Rect.Height div 2)-2, 4, 4);
3468 c3 := g_Collide(X-MapOffset.X-1, Y-MapOffset.Y-1, 2, 2,
3469 Rect.X+(Rect.Width div 2)-2, Rect.Y-2, 4, 4);
3470 c4 := g_Collide(X-MapOffset.X-1, Y-MapOffset.Y-1, 2, 2,
3471 Rect.X+(Rect.Width div 2)-2, Rect.Y+Rect.Height-3, 4, 4);
3473 // Меняем размер панели или триггера:
3474 if c1 or c2 or c3 or c4 then
3475 begin
3476 MouseAction := MOUSEACTION_RESIZE;
3477 LastMovePoint := MousePos;
3479 if c1 or c2 then
3480 begin // Шире/уже
3481 ResizeType := RESIZETYPE_HORIZONTAL;
3482 if c1 then
3483 ResizeDirection := RESIZEDIR_LEFT
3484 else
3485 ResizeDirection := RESIZEDIR_RIGHT;
3486 RenderPanel.Cursor := crSizeWE;
3487 end
3488 else
3489 begin // Выше/ниже
3490 ResizeType := RESIZETYPE_VERTICAL;
3491 if c3 then
3492 ResizeDirection := RESIZEDIR_UP
3493 else
3494 ResizeDirection := RESIZEDIR_DOWN;
3495 RenderPanel.Cursor := crSizeNS;
3496 end;
3498 Break;
3499 end;
3500 end;
3502 // Перемещаем панель или триггер:
3503 if ObjectCollide(ObjectType, ID,
3504 X-MapOffset.X-1,
3505 Y-MapOffset.Y-1, 2, 2) then
3506 begin
3507 MouseAction := MOUSEACTION_MOVEOBJ;
3508 LastMovePoint := MousePos;
3510 Break;
3511 end;
3512 end;
3513 end;
3514 end; // if Button = mbRight
3516 MouseRDown := Button = mbRight;
3517 if MouseRDown then
3518 MouseRDownPos := MousePos;
3520 MouseLDown := Button = mbLeft;
3521 if MouseLDown then
3522 MouseLDownPos := MousePos;
3523 end;
3525 procedure TMainForm.RenderPanelMouseUp(Sender: TObject;
3526 Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
3527 var
3528 panel: TPanel;
3529 trigger: TTrigger;
3530 i: Integer;
3531 IDArray: DWArray;
3532 rRect: TRectWH;
3533 rSelectRect: Boolean;
3534 begin
3535 if Button = mbLeft then
3536 MouseLDown := False;
3537 if Button = mbRight then
3538 MouseRDown := False;
3540 DrawRect := nil;
3541 ResizeType := RESIZETYPE_NONE;
3543 if Button = mbLeft then // Left Mouse Button
3544 begin
3545 if MouseAction <> MOUSEACTION_NONE then
3546 begin // Было действие мышью
3547 // Мышь сдвинулась во время удержания клавиши:
3548 if (MousePos.X <> MouseLDownPos.X) and
3549 (MousePos.Y <> MouseLDownPos.Y) then
3550 case MouseAction of
3551 // Рисовали панель:
3552 MOUSEACTION_DRAWPANEL:
3553 begin
3554 // Фон или передний план без текстуры - ошибка:
3555 if (lbPanelType.ItemIndex in [1, 2]) and
3556 (lbTextureList.ItemIndex = -1) then
3557 ErrorMessageBox(_lc[I_MSG_CHOOSE_TEXTURE])
3558 else // Назначаем параметры панели:
3559 begin
3560 case lbPanelType.ItemIndex of
3561 0: Panel.PanelType := PANEL_WALL;
3562 1: Panel.PanelType := PANEL_BACK;
3563 2: Panel.PanelType := PANEL_FORE;
3564 3: Panel.PanelType := PANEL_OPENDOOR;
3565 4: Panel.PanelType := PANEL_CLOSEDOOR;
3566 5: Panel.PanelType := PANEL_STEP;
3567 6: Panel.PanelType := PANEL_WATER;
3568 7: Panel.PanelType := PANEL_ACID1;
3569 8: Panel.PanelType := PANEL_ACID2;
3570 9: Panel.PanelType := PANEL_LIFTUP;
3571 10: Panel.PanelType := PANEL_LIFTDOWN;
3572 11: Panel.PanelType := PANEL_LIFTLEFT;
3573 12: Panel.PanelType := PANEL_LIFTRIGHT;
3574 13: Panel.PanelType := PANEL_BLOCKMON;
3575 end;
3577 Panel.X := Min(MousePos.X-MapOffset.X, MouseLDownPos.X-MapOffset.X);
3578 Panel.Y := Min(MousePos.Y-MapOffset.Y, MouseLDownPos.Y-MapOffset.Y);
3579 Panel.Width := Abs(MousePos.X-MouseLDownPos.X);
3580 Panel.Height := Abs(MousePos.Y-MouseLDownPos.Y);
3582 // Лифты, блокМон или отсутствие текстуры - пустая текстура:
3583 if (lbPanelType.ItemIndex in [9, 10, 11, 12, 13]) or
3584 (lbTextureList.ItemIndex = -1) then
3585 begin
3586 Panel.TextureHeight := 1;
3587 Panel.TextureWidth := 1;
3588 Panel.TextureName := '';
3589 Panel.TextureID := TEXTURE_SPECIAL_NONE;
3590 end
3591 else // Есть текстура:
3592 begin
3593 Panel.TextureName := SelectedTexture();
3595 // Обычная текстура:
3596 if not IsSpecialTextureSel() then
3597 begin
3598 g_GetTextureSizeByName(Panel.TextureName,
3599 Panel.TextureWidth, Panel.TextureHeight);
3600 g_GetTexture(Panel.TextureName, Panel.TextureID);
3601 end
3602 else // Спец.текстура:
3603 begin
3604 Panel.TextureHeight := 1;
3605 Panel.TextureWidth := 1;
3606 Panel.TextureID := SpecialTextureID(SelectedTexture());
3607 end;
3608 end;
3610 Panel.Alpha := 0;
3611 Panel.Blending := False;
3613 Undo_Add(OBJECT_PANEL, AddPanel(Panel));
3614 end;
3615 end;
3617 // Рисовали триггер:
3618 MOUSEACTION_DRAWTRIGGER:
3619 begin
3620 trigger.X := Min(MousePos.X-MapOffset.X, MouseLDownPos.X-MapOffset.X);
3621 trigger.Y := Min(MousePos.Y-MapOffset.Y, MouseLDownPos.Y-MapOffset.Y);
3622 trigger.Width := Abs(MousePos.X-MouseLDownPos.X);
3623 trigger.Height := Abs(MousePos.Y-MouseLDownPos.Y);
3625 trigger.Enabled := True;
3626 trigger.TriggerType := lbTriggersList.ItemIndex+1;
3627 trigger.TexturePanel := -1;
3629 // Типы активации:
3630 trigger.ActivateType := 0;
3632 if clbActivationType.Checked[0] then
3633 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_PLAYERCOLLIDE;
3634 if clbActivationType.Checked[1] then
3635 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_MONSTERCOLLIDE;
3636 if clbActivationType.Checked[2] then
3637 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_PLAYERPRESS;
3638 if clbActivationType.Checked[3] then
3639 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_MONSTERPRESS;
3640 if clbActivationType.Checked[4] then
3641 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_SHOT;
3642 if clbActivationType.Checked[5] then
3643 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_NOMONSTER;
3645 // Необходимые для активации ключи:
3646 trigger.Key := 0;
3648 if clbKeys.Checked[0] then
3649 trigger.Key := Trigger.Key or KEY_RED;
3650 if clbKeys.Checked[1] then
3651 trigger.Key := Trigger.Key or KEY_GREEN;
3652 if clbKeys.Checked[2] then
3653 trigger.Key := Trigger.Key or KEY_BLUE;
3654 if clbKeys.Checked[3] then
3655 trigger.Key := Trigger.Key or KEY_REDTEAM;
3656 if clbKeys.Checked[4] then
3657 trigger.Key := Trigger.Key or KEY_BLUETEAM;
3659 // Параметры триггера:
3660 FillByte(trigger.Data.Default[0], 128, 0);
3662 case trigger.TriggerType of
3663 // Переключаемая панель:
3664 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
3665 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP,
3666 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
3667 begin
3668 Trigger.Data.PanelID := -1;
3669 end;
3671 // Телепортация:
3672 TRIGGER_TELEPORT:
3673 begin
3674 trigger.Data.TargetPoint.X := trigger.X-64;
3675 trigger.Data.TargetPoint.Y := trigger.Y-64;
3676 trigger.Data.d2d_teleport := True;
3677 trigger.Data.TlpDir := 0;
3678 end;
3680 // Изменение других триггеров:
3681 TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF,
3682 TRIGGER_ONOFF:
3683 begin
3684 trigger.Data.Count := 1;
3685 end;
3687 // Звук:
3688 TRIGGER_SOUND:
3689 begin
3690 trigger.Data.Volume := 255;
3691 trigger.Data.Pan := 127;
3692 trigger.Data.PlayCount := 1;
3693 trigger.Data.Local := True;
3694 trigger.Data.SoundSwitch := False;
3695 end;
3697 // Музыка:
3698 TRIGGER_MUSIC:
3699 begin
3700 trigger.Data.MusicAction := 1;
3701 end;
3703 // Создание монстра:
3704 TRIGGER_SPAWNMONSTER:
3705 begin
3706 trigger.Data.MonType := MONSTER_ZOMBY;
3707 trigger.Data.MonPos.X := trigger.X-64;
3708 trigger.Data.MonPos.Y := trigger.Y-64;
3709 trigger.Data.MonHealth := 0;
3710 trigger.Data.MonActive := False;
3711 trigger.Data.MonCount := 1;
3712 end;
3714 // Создание предмета:
3715 TRIGGER_SPAWNITEM:
3716 begin
3717 trigger.Data.ItemType := ITEM_AMMO_BULLETS;
3718 trigger.Data.ItemPos.X := trigger.X-64;
3719 trigger.Data.ItemPos.Y := trigger.Y-64;
3720 trigger.Data.ItemOnlyDM := False;
3721 trigger.Data.ItemFalls := False;
3722 trigger.Data.ItemCount := 1;
3723 trigger.Data.ItemMax := 0;
3724 trigger.Data.ItemDelay := 0;
3725 end;
3727 // Ускорение:
3728 TRIGGER_PUSH:
3729 begin
3730 trigger.Data.PushAngle := 90;
3731 trigger.Data.PushForce := 10;
3732 trigger.Data.ResetVel := True;
3733 end;
3735 TRIGGER_SCORE:
3736 begin
3737 trigger.Data.ScoreCount := 1;
3738 trigger.Data.ScoreCon := True;
3739 trigger.Data.ScoreMsg := True;
3740 end;
3742 TRIGGER_MESSAGE:
3743 begin
3744 trigger.Data.MessageKind := 0;
3745 trigger.Data.MessageSendTo := 0;
3746 trigger.Data.MessageText := '';
3747 trigger.Data.MessageTime := 144;
3748 end;
3750 TRIGGER_DAMAGE:
3751 begin
3752 trigger.Data.DamageValue := 5;
3753 trigger.Data.DamageInterval := 12;
3754 end;
3756 TRIGGER_HEALTH:
3757 begin
3758 trigger.Data.HealValue := 5;
3759 trigger.Data.HealInterval := 36;
3760 end;
3762 TRIGGER_SHOT:
3763 begin
3764 trigger.Data.ShotType := TRIGGER_SHOT_BULLET;
3765 trigger.Data.ShotSound := True;
3766 trigger.Data.ShotPanelID := -1;
3767 trigger.Data.ShotTarget := 0;
3768 trigger.Data.ShotIntSight := 0;
3769 trigger.Data.ShotAim := TRIGGER_SHOT_AIM_DEFAULT;
3770 trigger.Data.ShotPos.X := trigger.X-64;
3771 trigger.Data.ShotPos.Y := trigger.Y-64;
3772 trigger.Data.ShotAngle := 0;
3773 trigger.Data.ShotWait := 18;
3774 trigger.Data.ShotAccuracy := 0;
3775 trigger.Data.ShotAmmo := 0;
3776 trigger.Data.ShotIntReload := 0;
3777 end;
3779 TRIGGER_EFFECT:
3780 begin
3781 trigger.Data.FXCount := 1;
3782 trigger.Data.FXType := TRIGGER_EFFECT_PARTICLE;
3783 trigger.Data.FXSubType := TRIGGER_EFFECT_SLIQUID;
3784 trigger.Data.FXColorR := 0;
3785 trigger.Data.FXColorG := 0;
3786 trigger.Data.FXColorB := 255;
3787 trigger.Data.FXPos := TRIGGER_EFFECT_POS_CENTER;
3788 trigger.Data.FXWait := 1;
3789 trigger.Data.FXVelX := 0;
3790 trigger.Data.FXVelY := -20;
3791 trigger.Data.FXSpreadL := 5;
3792 trigger.Data.FXSpreadR := 5;
3793 trigger.Data.FXSpreadU := 4;
3794 trigger.Data.FXSpreadD := 0;
3795 end;
3796 end;
3798 Undo_Add(OBJECT_TRIGGER, AddTrigger(trigger));
3799 end;
3801 // Рисовали область триггера "Расширитель":
3802 MOUSEACTION_DRAWPRESS:
3803 with gTriggers[SelectedObjects[GetFirstSelected].ID] do
3804 begin
3805 Data.tX := Min(MousePos.X-MapOffset.X, MouseLDownPos.X-MapOffset.X);
3806 Data.tY := Min(MousePos.Y-MapOffset.Y, MouseLDownPos.Y-MapOffset.Y);
3807 Data.tWidth := Abs(MousePos.X-MouseLDownPos.X);
3808 Data.tHeight := Abs(MousePos.Y-MouseLDownPos.Y);
3810 DrawPressRect := False;
3811 end;
3812 end;
3814 MouseAction := MOUSEACTION_NONE;
3815 end;
3816 end // if Button = mbLeft...
3817 else // Right Mouse Button:
3818 begin
3819 if MouseAction = MOUSEACTION_NOACTION then
3820 begin
3821 MouseAction := MOUSEACTION_NONE;
3822 Exit;
3823 end;
3825 // Объект передвинут или изменен в размере:
3826 if MouseAction in [MOUSEACTION_MOVEOBJ, MOUSEACTION_RESIZE] then
3827 begin
3828 MouseAction := MOUSEACTION_NONE;
3829 FillProperty();
3830 Exit;
3831 end;
3833 // Еще не все выбрали:
3834 if SelectFlag <> SELECTFLAG_NONE then
3835 begin
3836 if SelectFlag = SELECTFLAG_SELECTED then
3837 SelectFlag := SELECTFLAG_NONE;
3838 FillProperty();
3839 Exit;
3840 end;
3842 // Мышь сдвинулась во время удержания клавиши:
3843 if (MousePos.X <> MouseRDownPos.X) and
3844 (MousePos.Y <> MouseRDownPos.Y) then
3845 begin
3846 rSelectRect := True;
3848 rRect.X := Min(MousePos.X, MouseRDownPos.X)-MapOffset.X;
3849 rRect.Y := Min(MousePos.Y, MouseRDownPos.Y)-MapOffset.Y;
3850 rRect.Width := Abs(MousePos.X-MouseRDownPos.X);
3851 rRect.Height := Abs(MousePos.Y-MouseRDownPos.Y);
3852 end
3853 else // Мышь не сдвинулась - нет прямоугольника:
3854 begin
3855 rSelectRect := False;
3857 rRect.X := X-MapOffset.X-1;
3858 rRect.Y := Y-MapOffset.Y-1;
3859 rRect.Width := 2;
3860 rRect.Height := 2;
3861 end;
3863 // Если зажат Ctrl - выделять еще, иначе только один выделенный объект:
3864 if not (ssCtrl in Shift) then
3865 RemoveSelectFromObjects();
3867 // Выделяем всё в выбранном прямоугольнике:
3868 IDArray := ObjectInRect(rRect.X, rRect.Y,
3869 rRect.Width, rRect.Height,
3870 pcObjects.ActivePageIndex+1, rSelectRect);
3872 if IDArray <> nil then
3873 for i := 0 to High(IDArray) do
3874 SelectObject(pcObjects.ActivePageIndex+1, IDArray[i],
3875 (ssCtrl in Shift) or rSelectRect);
3877 FillProperty();
3878 end;
3879 end;
3881 procedure TMainForm.RenderPanelPaint(Sender: TObject);
3882 begin
3883 Draw();
3884 end;
3886 procedure TMainForm.RenderPanelMouseMove(Sender: TObject;
3887 Shift: TShiftState; X, Y: Integer);
3888 var
3889 sX, sY: Integer;
3890 dWidth, dHeight: Integer;
3891 _id: Integer;
3892 begin
3893 _id := GetFirstSelected();
3895 // Рисуем панель с текстурой, сетка - размеры текстуры:
3896 if (MouseAction = MOUSEACTION_DRAWPANEL) and
3897 (lbPanelType.ItemIndex in [0..8]) and
3898 (lbTextureList.ItemIndex <> -1) and
3899 (not IsSpecialTextureSel()) then
3900 begin
3901 sX := StrToIntDef(lTextureWidth.Caption, DotStep);
3902 sY := StrToIntDef(lTextureHeight.Caption, DotStep);
3903 end
3904 else
3905 // Меняем размер панели с текстурой, сетка - размеры текстуры:
3906 if (MouseAction = MOUSEACTION_RESIZE) and
3907 ( (SelectedObjects[_id].ObjectType = OBJECT_PANEL) and
3908 IsTexturedPanel(gPanels[SelectedObjects[_id].ID].PanelType) and
3909 (gPanels[SelectedObjects[_id].ID].TextureName <> '') and
3910 (not IsSpecialTexture(gPanels[SelectedObjects[_id].ID].TextureName)) ) then
3911 begin
3912 sX := gPanels[SelectedObjects[_id].ID].TextureWidth;
3913 sY := gPanels[SelectedObjects[_id].ID].TextureHeight;
3914 end
3915 else
3916 // Выравнивание по сетке:
3917 if SnapToGrid then
3918 begin
3919 sX := DotStep;
3920 sY := DotStep;
3921 end
3922 else // Нет выравнивания по сетке:
3923 begin
3924 sX := 1;
3925 sY := 1;
3926 end;
3928 // Новая позиция мыши:
3929 if MouseLDown then
3930 begin // Зажата левая кнопка мыши
3931 MousePos.X := (Round((X-MouseLDownPos.X)/sX)*sX)+MouseLDownPos.X;
3932 MousePos.Y := (Round((Y-MouseLDownPos.Y)/sY)*sY)+MouseLDownPos.Y;
3933 end
3934 else
3935 if MouseRDown then
3936 begin // Зажата правая кнопка мыши
3937 MousePos.X := (Round((X-MouseRDownPos.X)/sX)*sX)+MouseRDownPos.X;
3938 MousePos.Y := (Round((Y-MouseRDownPos.Y)/sY)*sY)+MouseRDownPos.Y;
3939 end
3940 else
3941 begin // Кнопки мыши не зажаты
3942 MousePos.X := (Round(X/sX)*sX);
3943 MousePos.Y := (Round(Y/sY)*sY);
3944 end;
3946 // Изменение размера закончилось - ставим обычный курсор:
3947 if ResizeType = RESIZETYPE_NONE then
3948 RenderPanel.Cursor := crDefault;
3950 // Зажата только правая кнопка мыши:
3951 if (not MouseLDown) and (MouseRDown) then
3952 begin
3953 // Рисуем прямоугольник выделения:
3954 if MouseAction = MOUSEACTION_NONE then
3955 begin
3956 if DrawRect = nil then
3957 New(DrawRect);
3958 DrawRect.Top := MouseRDownPos.y;
3959 DrawRect.Left := MouseRDownPos.x;
3960 DrawRect.Bottom := MousePos.y;
3961 DrawRect.Right := MousePos.x;
3962 end
3963 else
3964 // Двигаем выделенные объекты:
3965 if MouseAction = MOUSEACTION_MOVEOBJ then
3966 begin
3967 MoveSelectedObjects(ssShift in Shift, ssCtrl in Shift,
3968 MousePos.X-LastMovePoint.X,
3969 MousePos.Y-LastMovePoint.Y);
3970 end
3971 else
3972 // Меняем размер выделенного объекта:
3973 if MouseAction = MOUSEACTION_RESIZE then
3974 begin
3975 if (SelectedObjectCount = 1) and
3976 (SelectedObjects[GetFirstSelected].Live) then
3977 begin
3978 dWidth := MousePos.X-LastMovePoint.X;
3979 dHeight := MousePos.Y-LastMovePoint.Y;
3981 case ResizeType of
3982 RESIZETYPE_VERTICAL: dWidth := 0;
3983 RESIZETYPE_HORIZONTAL: dHeight := 0;
3984 end;
3986 case ResizeDirection of
3987 RESIZEDIR_UP: dHeight := -dHeight;
3988 RESIZEDIR_LEFT: dWidth := -dWidth;
3989 end;
3991 ResizeObject(SelectedObjects[GetFirstSelected].ObjectType,
3992 SelectedObjects[GetFirstSelected].ID,
3993 dWidth, dHeight, ResizeDirection);
3995 LastMovePoint := MousePos;
3996 end;
3997 end;
3998 end;
4000 // Зажата только левая кнопка мыши:
4001 if (not MouseRDown) and (MouseLDown) then
4002 begin
4003 // Рисуем прямоугольник планирования панели:
4004 if MouseAction in [MOUSEACTION_DRAWPANEL,
4005 MOUSEACTION_DRAWTRIGGER,
4006 MOUSEACTION_DRAWPRESS] then
4007 begin
4008 if DrawRect = nil then
4009 New(DrawRect);
4010 DrawRect.Top := MouseLDownPos.y;
4011 DrawRect.Left := MouseLDownPos.x;
4012 DrawRect.Bottom := MousePos.y;
4013 DrawRect.Right := MousePos.x;
4014 end
4015 else // Двигаем карту:
4016 if MouseAction = MOUSEACTION_MOVEMAP then
4017 begin
4018 MoveMap(X, Y);
4019 end;
4020 end;
4022 // Клавиши мыши не зажаты:
4023 if (not MouseRDown) and (not MouseLDown) then
4024 DrawRect := nil;
4026 // Строка состояния - координаты мыши:
4027 StatusBar.Panels[1].Text := Format('(%d:%d)',
4028 [MousePos.X-MapOffset.X, MousePos.Y-MapOffset.Y]);
4029 end;
4031 procedure TMainForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
4032 begin
4033 CanClose := MessageBox(0, PChar(_lc[I_MSG_EXIT_PROMT]),
4034 PChar(_lc[I_MSG_EXIT]),
4035 MB_ICONQUESTION or MB_YESNO or
4036 MB_DEFBUTTON1) = idYes;
4037 end;
4039 procedure TMainForm.aExitExecute(Sender: TObject);
4040 begin
4041 Close();
4042 end;
4044 procedure TMainForm.FormDestroy(Sender: TObject);
4045 var
4046 config: TConfig;
4047 i: Integer;
4048 begin
4049 config := TConfig.CreateFile(EditorDir+'Editor.cfg');
4051 if WindowState <> wsMaximized then
4052 begin
4053 config.WriteInt('Editor', 'XPos', Left);
4054 config.WriteInt('Editor', 'YPos', Top);
4055 config.WriteInt('Editor', 'Width', Width);
4056 config.WriteInt('Editor', 'Height', Height);
4057 end
4058 else
4059 begin
4060 config.WriteInt('Editor', 'XPos', RestoredLeft);
4061 config.WriteInt('Editor', 'YPos', RestoredTop);
4062 config.WriteInt('Editor', 'Width', RestoredWidth);
4063 config.WriteInt('Editor', 'Height', RestoredHeight);
4064 end;
4065 config.WriteBool('Editor', 'Maximize', WindowState = wsMaximized);
4066 config.WriteBool('Editor', 'Minimap', ShowMap);
4067 config.WriteInt('Editor', 'PanelProps', PanelProps.ClientWidth);
4068 config.WriteInt('Editor', 'PanelObjs', PanelObjs.ClientHeight);
4069 config.WriteBool('Editor', 'DotEnable', DotEnable);
4070 config.WriteInt('Editor', 'DotStep', DotStep);
4071 config.WriteStr('Editor', 'LastOpenDir', OpenDialog.InitialDir);
4072 config.WriteStr('Editor', 'LastSaveDir', SaveDialog.InitialDir);
4073 config.WriteBool('Editor', 'EdgeShow', drEdge[3] < 255);
4074 config.WriteInt('Editor', 'EdgeColor', gColorEdge);
4075 config.WriteInt('Editor', 'EdgeAlpha', gAlphaEdge);
4076 config.WriteInt('Editor', 'LineAlpha', gAlphaTriggerLine);
4077 config.WriteInt('Editor', 'TriggerAlpha', gAlphaTriggerArea);
4079 for i := 0 to RecentCount-1 do
4080 if i < RecentFiles.Count then
4081 config.WriteStr('RecentFiles', IntToStr(i+1), RecentFiles[i])
4082 else
4083 config.WriteStr('RecentFiles', IntToStr(i+1), '');
4084 RecentFiles.Free();
4086 config.SaveFile(EditorDir+'Editor.cfg');
4087 config.Free();
4089 slInvalidTextures.Free;
4090 end;
4092 procedure TMainForm.RenderPanelResize(Sender: TObject);
4093 begin
4094 if MainForm.Visible then
4095 MainForm.Resize();
4096 end;
4098 procedure TMainForm.aMapOptionsExecute(Sender: TObject);
4099 var
4100 ResName: String;
4101 begin
4102 MapOptionsForm.ShowModal();
4104 ResName := OpenedMap;
4105 while (Pos(':\', ResName) > 0) do
4106 Delete(ResName, 1, Pos(':\', ResName) + 1);
4108 UpdateCaption(win2utf(gMapInfo.Name), ExtractFileName(OpenedWAD), ResName);
4109 end;
4111 procedure TMainForm.aAboutExecute(Sender: TObject);
4112 begin
4113 AboutForm.ShowModal();
4114 end;
4116 procedure TMainForm.FormKeyDown(Sender: TObject; var Key: Word;
4117 Shift: TShiftState);
4118 var
4119 dx, dy, i: Integer;
4120 FileName: String;
4121 begin
4122 if (not EditingProperties) then
4123 begin
4124 if Key = Ord('1') then
4125 SwitchLayer(LAYER_BACK);
4126 if Key = Ord('2') then
4127 SwitchLayer(LAYER_WALLS);
4128 if Key = Ord('3') then
4129 SwitchLayer(LAYER_FOREGROUND);
4130 if Key = Ord('4') then
4131 SwitchLayer(LAYER_STEPS);
4132 if Key = Ord('5') then
4133 SwitchLayer(LAYER_WATER);
4134 if Key = Ord('6') then
4135 SwitchLayer(LAYER_ITEMS);
4136 if Key = Ord('7') then
4137 SwitchLayer(LAYER_MONSTERS);
4138 if Key = Ord('8') then
4139 SwitchLayer(LAYER_AREAS);
4140 if Key = Ord('9') then
4141 SwitchLayer(LAYER_TRIGGERS);
4142 if Key = Ord('0') then
4143 tbShowClick(tbShow);
4145 if Key = Ord('V') then
4146 begin // Поворот монстров и областей:
4147 if (SelectedObjects <> nil) then
4148 begin
4149 for i := 0 to High(SelectedObjects) do
4150 if (SelectedObjects[i].Live) then
4151 begin
4152 if (SelectedObjects[i].ObjectType = OBJECT_MONSTER) then
4153 begin
4154 g_ChangeDir(gMonsters[SelectedObjects[i].ID].Direction);
4155 end
4156 else
4157 if (SelectedObjects[i].ObjectType = OBJECT_AREA) then
4158 begin
4159 g_ChangeDir(gAreas[SelectedObjects[i].ID].Direction);
4160 end;
4161 end;
4162 end
4163 else
4164 begin
4165 if pcObjects.ActivePage = tsMonsters then
4166 begin
4167 if rbMonsterLeft.Checked then
4168 rbMonsterRight.Checked := True
4169 else
4170 rbMonsterLeft.Checked := True;
4171 end;
4172 if pcObjects.ActivePage = tsAreas then
4173 begin
4174 if rbAreaLeft.Checked then
4175 rbAreaRight.Checked := True
4176 else
4177 rbAreaLeft.Checked := True;
4178 end;
4179 end;
4180 end;
4182 if not (ssCtrl in Shift) then
4183 begin
4184 // Вертикальный скролл карты:
4185 with sbVertical do
4186 begin
4187 if Key = Ord('W') then
4188 begin
4189 Position := IfThen(Position > DotStep, Position-DotStep, 0);
4190 MapOffset.Y := -Round(Position/16) * 16;
4191 end;
4193 if Key = Ord('S') then
4194 begin
4195 Position := IfThen(Position+DotStep < Max, Position+DotStep, Max);
4196 MapOffset.Y := -Round(Position/16) * 16;
4197 end;
4198 end;
4200 // Горизонтальный скролл карты:
4201 with sbHorizontal do
4202 begin
4203 if Key = Ord('A') then
4204 begin
4205 Position := IfThen(Position > DotStep, Position-DotStep, 0);
4206 MapOffset.X := -Round(Position/16) * 16;
4207 end;
4209 if Key = Ord('D') then
4210 begin
4211 Position := IfThen(Position+DotStep < Max, Position+DotStep, Max);
4212 MapOffset.X := -Round(Position/16) * 16;
4213 end;
4214 end;
4215 end;
4216 end;
4218 // Удалить выделенные объекты:
4219 if (Key = VK_DELETE) and (SelectedObjects <> nil) and
4220 RenderPanel.Focused() then
4221 DeleteSelectedObjects();
4223 // Снять выделение:
4224 if (Key = VK_ESCAPE) and (SelectedObjects <> nil) then
4225 RemoveSelectFromObjects();
4227 // Передвинуть объекты:
4228 if MainForm.ActiveControl = RenderPanel then
4229 begin
4230 dx := 0;
4231 dy := 0;
4233 if Key = VK_NUMPAD4 then
4234 dx := IfThen(ssAlt in Shift, -1, -DotStep);
4235 if Key = VK_NUMPAD6 then
4236 dx := IfThen(ssAlt in Shift, 1, DotStep);
4237 if Key = VK_NUMPAD8 then
4238 dy := IfThen(ssAlt in Shift, -1, -DotStep);
4239 if Key = VK_NUMPAD5 then
4240 dy := IfThen(ssAlt in Shift, 1, DotStep);
4242 if (dx <> 0) or (dy <> 0) then
4243 begin
4244 MoveSelectedObjects(ssShift in Shift, ssCtrl in Shift, dx, dy);
4245 Key := 0;
4246 end;
4247 end;
4249 if ssCtrl in Shift then
4250 begin
4251 // Выбор панели с текстурой для триггера
4252 if Key = Ord('T') then
4253 begin
4254 DrawPressRect := False;
4255 if SelectFlag = SELECTFLAG_TEXTURE then
4256 begin
4257 SelectFlag := SELECTFLAG_NONE;
4258 Exit;
4259 end;
4260 vleObjectProperty.FindRow(_lc[I_PROP_TR_TEXTURE_PANEL], i);
4261 if i > 0 then
4262 SelectFlag := SELECTFLAG_TEXTURE;
4263 end;
4265 if Key = Ord('D') then
4266 begin
4267 SelectFlag := SELECTFLAG_NONE;
4268 if DrawPressRect then
4269 begin
4270 DrawPressRect := False;
4271 Exit;
4272 end;
4274 // Выбор области воздействия, в зависимости от типа триггера
4275 vleObjectProperty.FindRow(_lc[I_PROP_TR_EX_AREA], i);
4276 if i > 0 then
4277 begin
4278 DrawPressRect := True;
4279 Exit;
4280 end;
4281 vleObjectProperty.FindRow(_lc[I_PROP_TR_DOOR_PANEL], i);
4282 if i <= 0 then
4283 vleObjectProperty.FindRow(_lc[I_PROP_TR_TRAP_PANEL], i);
4284 if i > 0 then
4285 begin
4286 SelectFlag := SELECTFLAG_DOOR;
4287 Exit;
4288 end;
4289 vleObjectProperty.FindRow(_lc[I_PROP_TR_LIFT_PANEL], i);
4290 if i > 0 then
4291 begin
4292 SelectFlag := SELECTFLAG_LIFT;
4293 Exit;
4294 end;
4295 vleObjectProperty.FindRow(_lc[I_PROP_TR_TELEPORT_TO], i);
4296 if i > 0 then
4297 begin
4298 SelectFlag := SELECTFLAG_TELEPORT;
4299 Exit;
4300 end;
4301 vleObjectProperty.FindRow(_lc[I_PROP_TR_SPAWN_TO], i);
4302 if i > 0 then
4303 begin
4304 SelectFlag := SELECTFLAG_SPAWNPOINT;
4305 Exit;
4306 end;
4308 // Выбор основного параметра, в зависимости от типа триггера
4309 vleObjectProperty.FindRow(_lc[I_PROP_TR_NEXT_MAP], i);
4310 if i > 0 then
4311 begin
4312 g_ProcessResourceStr(OpenedMap, @FileName, nil, nil);
4313 SelectMapForm.GetMaps(FileName);
4315 if SelectMapForm.ShowModal() = mrOK then
4316 begin
4317 vleObjectProperty.Cells[1, i] := SelectMapForm.lbMapList.Items[SelectMapForm.lbMapList.ItemIndex];
4318 bApplyProperty.Click();
4319 end;
4320 Exit;
4321 end;
4322 vleObjectProperty.FindRow(_lc[I_PROP_TR_SOUND_NAME], i);
4323 if i <= 0 then
4324 vleObjectProperty.FindRow(_lc[I_PROP_TR_MUSIC_NAME], i);
4325 if i > 0 then
4326 begin
4327 AddSoundForm.OKFunction := nil;
4328 AddSoundForm.lbResourcesList.MultiSelect := False;
4329 AddSoundForm.SetResource := utf2win(vleObjectProperty.Cells[1, i]);
4331 if (AddSoundForm.ShowModal() = mrOk) then
4332 begin
4333 vleObjectProperty.Cells[1, i] := win2utf(AddSoundForm.ResourceName);
4334 bApplyProperty.Click();
4335 end;
4336 Exit;
4337 end;
4338 vleObjectProperty.FindRow(_lc[I_PROP_TR_PUSH_ANGLE], i);
4339 if i <= 0 then
4340 vleObjectProperty.FindRow(_lc[I_PROP_TR_MESSAGE_TEXT], i);
4341 if i > 0 then
4342 begin
4343 vleObjectProperty.Row := i;
4344 vleObjectProperty.SetFocus();
4345 Exit;
4346 end;
4347 end;
4348 end;
4349 end;
4351 procedure TMainForm.aOptimizeExecute(Sender: TObject);
4352 begin
4353 RemoveSelectFromObjects();
4354 MapOptimizationForm.ShowModal();
4355 end;
4357 procedure TMainForm.aCheckMapExecute(Sender: TObject);
4358 begin
4359 MapCheckForm.ShowModal();
4360 end;
4362 procedure TMainForm.bbAddTextureClick(Sender: TObject);
4363 begin
4364 AddTextureForm.lbResourcesList.MultiSelect := True;
4365 AddTextureForm.ShowModal();
4366 end;
4368 procedure TMainForm.lbTextureListClick(Sender: TObject);
4369 var
4370 TextureID: DWORD;
4371 TextureWidth, TextureHeight: Word;
4372 begin
4373 if (lbTextureList.ItemIndex <> -1) and
4374 (not IsSpecialTextureSel()) then
4375 begin
4376 if g_GetTexture(SelectedTexture(), TextureID) then
4377 begin
4378 g_GetTextureSizeByID(TextureID, TextureWidth, TextureHeight);
4380 lTextureWidth.Caption := IntToStr(TextureWidth);
4381 lTextureHeight.Caption := IntToStr(TextureHeight);
4382 end else
4383 begin
4384 lTextureWidth.Caption := _lc[I_NOT_ACCESSIBLE];
4385 lTextureHeight.Caption := _lc[I_NOT_ACCESSIBLE];
4386 end;
4387 end
4388 else
4389 begin
4390 lTextureWidth.Caption := '';
4391 lTextureHeight.Caption := '';
4392 end;
4393 end;
4395 procedure TMainForm.lbTextureListDrawItem(Control: TWinControl; Index: Integer;
4396 ARect: TRect; State: TOwnerDrawState);
4397 begin
4398 with Control as TListBox do
4399 begin
4400 if LCLType.odSelected in State then
4401 begin
4402 Canvas.Brush.Color := clHighlight;
4403 Canvas.Font.Color := clHighlightText;
4404 end else
4405 if (Items <> nil) and (Index >= 0) then
4406 if slInvalidTextures.IndexOf(Items[Index]) > -1 then
4407 begin
4408 Canvas.Brush.Color := clRed;
4409 Canvas.Font.Color := clWhite;
4410 end;
4411 Canvas.FillRect(ARect);
4412 Canvas.TextRect(ARect, ARect.Left, ARect.Top, Items[Index]);
4413 end;
4414 end;
4416 procedure TMainForm.vleObjectPropertyGetPickList(Sender: TObject;
4417 const KeyName: String; Values: TStrings);
4418 begin
4419 if vleObjectProperty.ItemProps[KeyName].EditStyle = esPickList then
4420 begin
4421 if KeyName = _lc[I_PROP_DIRECTION] then
4422 begin
4423 Values.Add(DirNames[D_LEFT]);
4424 Values.Add(DirNames[D_RIGHT]);
4425 end
4426 else if KeyName = _lc[I_PROP_TR_TELEPORT_DIR] then
4427 begin
4428 Values.Add(DirNamesAdv[0]);
4429 Values.Add(DirNamesAdv[1]);
4430 Values.Add(DirNamesAdv[2]);
4431 Values.Add(DirNamesAdv[3]);
4432 end
4433 else if KeyName = _lc[I_PROP_TR_MUSIC_ACT] then
4434 begin
4435 Values.Add(_lc[I_PROP_TR_MUSIC_ON]);
4436 Values.Add(_lc[I_PROP_TR_MUSIC_OFF]);
4437 end
4438 else if KeyName = _lc[I_PROP_TR_MONSTER_BEHAVIOUR] then
4439 begin
4440 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_0]);
4441 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_1]);
4442 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_2]);
4443 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_3]);
4444 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_4]);
4445 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_5]);
4446 end
4447 else if KeyName = _lc[I_PROP_TR_SCORE_ACT] then
4448 begin
4449 Values.Add(_lc[I_PROP_TR_SCORE_ACT_0]);
4450 Values.Add(_lc[I_PROP_TR_SCORE_ACT_1]);
4451 Values.Add(_lc[I_PROP_TR_SCORE_ACT_2]);
4452 Values.Add(_lc[I_PROP_TR_SCORE_ACT_3]);
4453 end
4454 else if KeyName = _lc[I_PROP_TR_SCORE_TEAM] then
4455 begin
4456 Values.Add(_lc[I_PROP_TR_SCORE_TEAM_0]);
4457 Values.Add(_lc[I_PROP_TR_SCORE_TEAM_1]);
4458 Values.Add(_lc[I_PROP_TR_SCORE_TEAM_2]);
4459 Values.Add(_lc[I_PROP_TR_SCORE_TEAM_3]);
4460 end
4461 else if KeyName = _lc[I_PROP_TR_MESSAGE_KIND] then
4462 begin
4463 Values.Add(_lc[I_PROP_TR_MESSAGE_KIND_0]);
4464 Values.Add(_lc[I_PROP_TR_MESSAGE_KIND_1]);
4465 end
4466 else if KeyName = _lc[I_PROP_TR_MESSAGE_TO] then
4467 begin
4468 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_0]);
4469 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_1]);
4470 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_2]);
4471 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_3]);
4472 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_4]);
4473 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_5]);
4474 end
4475 else if KeyName = _lc[I_PROP_TR_SHOT_TO] then
4476 begin
4477 Values.Add(_lc[I_PROP_TR_SHOT_TO_0]);
4478 Values.Add(_lc[I_PROP_TR_SHOT_TO_1]);
4479 Values.Add(_lc[I_PROP_TR_SHOT_TO_2]);
4480 Values.Add(_lc[I_PROP_TR_SHOT_TO_3]);
4481 Values.Add(_lc[I_PROP_TR_SHOT_TO_4]);
4482 Values.Add(_lc[I_PROP_TR_SHOT_TO_5]);
4483 Values.Add(_lc[I_PROP_TR_SHOT_TO_6]);
4484 end
4485 else if KeyName = _lc[I_PROP_TR_SHOT_AIM] then
4486 begin
4487 Values.Add(_lc[I_PROP_TR_SHOT_AIM_0]);
4488 Values.Add(_lc[I_PROP_TR_SHOT_AIM_1]);
4489 Values.Add(_lc[I_PROP_TR_SHOT_AIM_2]);
4490 Values.Add(_lc[I_PROP_TR_SHOT_AIM_3]);
4491 end
4492 else if (KeyName = _lc[I_PROP_PANEL_BLEND]) or
4493 (KeyName = _lc[I_PROP_DM_ONLY]) or
4494 (KeyName = _lc[I_PROP_ITEM_FALLS]) or
4495 (KeyName = _lc[I_PROP_TR_ENABLED]) or
4496 (KeyName = _lc[I_PROP_TR_D2D]) or
4497 (KeyName = _lc[I_PROP_TR_SILENT]) or
4498 (KeyName = _lc[I_PROP_TR_TELEPORT_SILENT]) or
4499 (KeyName = _lc[I_PROP_TR_EX_RANDOM]) or
4500 (KeyName = _lc[I_PROP_TR_TEXTURE_ONCE]) or
4501 (KeyName = _lc[I_PROP_TR_TEXTURE_ANIM_ONCE]) or
4502 (KeyName = _lc[I_PROP_TR_SOUND_LOCAL]) or
4503 (KeyName = _lc[I_PROP_TR_SOUND_SWITCH]) or
4504 (KeyName = _lc[I_PROP_TR_MONSTER_ACTIVE]) or
4505 (KeyName = _lc[I_PROP_TR_PUSH_RESET]) or
4506 (KeyName = _lc[I_PROP_TR_SCORE_CON]) or
4507 (KeyName = _lc[I_PROP_TR_SCORE_MSG]) or
4508 (KeyName = _lc[I_PROP_TR_HEALTH_MAX]) or
4509 (KeyName = _lc[I_PROP_TR_SHOT_SOUND]) or
4510 (KeyName = _lc[I_PROP_TR_EFFECT_CENTER]) then
4511 begin
4512 Values.Add(BoolNames[True]);
4513 Values.Add(BoolNames[False]);
4514 end;
4515 end;
4516 end;
4518 procedure TMainForm.bApplyPropertyClick(Sender: TObject);
4519 var
4520 _id, a, r, c: Integer;
4521 s: String;
4522 res: Boolean;
4523 NoTextureID: DWORD;
4524 NW, NH: Word;
4525 begin
4526 if SelectedObjectCount() <> 1 then
4527 Exit;
4528 if not SelectedObjects[GetFirstSelected()].Live then
4529 Exit;
4531 try
4532 if not CheckProperty() then
4533 Exit;
4534 except
4535 Exit;
4536 end;
4538 _id := GetFirstSelected();
4540 r := vleObjectProperty.Row;
4541 c := vleObjectProperty.Col;
4543 case SelectedObjects[_id].ObjectType of
4544 OBJECT_PANEL:
4545 begin
4546 with gPanels[SelectedObjects[_id].ID] do
4547 begin
4548 X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
4549 Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
4550 Width := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_WIDTH]]));
4551 Height := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_HEIGHT]]));
4553 PanelType := GetPanelType(vleObjectProperty.Values[_lc[I_PROP_PANEL_TYPE]]);
4555 // Сброс ссылки на триггеры смены текстуры:
4556 if not WordBool(PanelType and (PANEL_WALL or PANEL_FORE or PANEL_BACK)) then
4557 if gTriggers <> nil then
4558 for a := 0 to High(gTriggers) do
4559 begin
4560 if (gTriggers[a].TriggerType <> 0) and
4561 (gTriggers[a].TexturePanel = Integer(SelectedObjects[_id].ID)) then
4562 gTriggers[a].TexturePanel := -1;
4563 if (gTriggers[a].TriggerType = TRIGGER_SHOT) and
4564 (gTriggers[a].Data.ShotPanelID = Integer(SelectedObjects[_id].ID)) then
4565 gTriggers[a].Data.ShotPanelID := -1;
4566 end;
4568 // Сброс ссылки на триггеры лифта:
4569 if not WordBool(PanelType and (PANEL_LIFTUP or PANEL_LIFTDOWN or PANEL_LIFTLEFT or PANEL_LIFTRIGHT)) then
4570 if gTriggers <> nil then
4571 for a := 0 to High(gTriggers) do
4572 if (gTriggers[a].TriggerType in [TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT]) and
4573 (gTriggers[a].Data.PanelID = Integer(SelectedObjects[_id].ID)) then
4574 gTriggers[a].Data.PanelID := -1;
4576 // Сброс ссылки на триггеры двери:
4577 if not WordBool(PanelType and (PANEL_OPENDOOR or PANEL_CLOSEDOOR)) then
4578 if gTriggers <> nil then
4579 for a := 0 to High(gTriggers) do
4580 if (gTriggers[a].TriggerType in [TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
4581 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP]) and
4582 (gTriggers[a].Data.PanelID = Integer(SelectedObjects[_id].ID)) then
4583 gTriggers[a].Data.PanelID := -1;
4585 if IsTexturedPanel(PanelType) then
4586 begin // Может быть текстура
4587 if TextureName <> '' then
4588 begin // Была текстура
4589 Alpha := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_PANEL_ALPHA]]));
4590 Blending := NameToBool(vleObjectProperty.Values[_lc[I_PROP_PANEL_BLEND]]);
4591 end
4592 else // Не было
4593 begin
4594 Alpha := 0;
4595 Blending := False;
4596 end;
4598 // Новая текстура:
4599 TextureName := vleObjectProperty.Values[_lc[I_PROP_PANEL_TEX]];
4601 if TextureName <> '' then
4602 begin // Есть текстура
4603 // Обычная текстура:
4604 if not IsSpecialTexture(TextureName) then
4605 begin
4606 g_GetTextureSizeByName(TextureName,
4607 TextureWidth, TextureHeight);
4609 // Проверка кратности размеров панели:
4610 res := True;
4611 if TextureWidth <> 0 then
4612 if gPanels[SelectedObjects[_id].ID].Width mod TextureWidth <> 0 then
4613 begin
4614 ErrorMessageBox(Format(_lc[I_MSG_WRONG_TEXWIDTH],
4615 [TextureWidth]));
4616 Res := False;
4617 end;
4618 if Res and (TextureHeight <> 0) then
4619 if gPanels[SelectedObjects[_id].ID].Height mod TextureHeight <> 0 then
4620 begin
4621 ErrorMessageBox(Format(_lc[I_MSG_WRONG_TEXHEIGHT],
4622 [TextureHeight]));
4623 Res := False;
4624 end;
4626 if Res then
4627 begin
4628 if not g_GetTexture(TextureName, TextureID) then
4629 // Не удалось загрузить текстуру, рисуем NOTEXTURE
4630 if g_GetTexture('NOTEXTURE', NoTextureID) then
4631 begin
4632 TextureID := TEXTURE_SPECIAL_NOTEXTURE;
4633 g_GetTextureSizeByID(NoTextureID, NW, NH);
4634 TextureWidth := NW;
4635 TextureHeight := NH;
4636 end else
4637 begin
4638 TextureID := TEXTURE_SPECIAL_NONE;
4639 TextureWidth := 1;
4640 TextureHeight := 1;
4641 end;
4642 end
4643 else
4644 begin
4645 TextureName := '';
4646 TextureWidth := 1;
4647 TextureHeight := 1;
4648 TextureID := TEXTURE_SPECIAL_NONE;
4649 end;
4650 end
4651 else // Спец.текстура
4652 begin
4653 TextureHeight := 1;
4654 TextureWidth := 1;
4655 TextureID := SpecialTextureID(TextureName);
4656 end;
4657 end
4658 else // Нет текстуры
4659 begin
4660 TextureWidth := 1;
4661 TextureHeight := 1;
4662 TextureID := TEXTURE_SPECIAL_NONE;
4663 end;
4664 end
4665 else // Не может быть текстуры
4666 begin
4667 Alpha := 0;
4668 Blending := False;
4669 TextureName := '';
4670 TextureWidth := 1;
4671 TextureHeight := 1;
4672 TextureID := TEXTURE_SPECIAL_NONE;
4673 end;
4674 end;
4675 end;
4677 OBJECT_ITEM:
4678 begin
4679 with gItems[SelectedObjects[_id].ID] do
4680 begin
4681 X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
4682 Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
4683 OnlyDM := NameToBool(vleObjectProperty.Values[_lc[I_PROP_DM_ONLY]]);
4684 Fall := NameToBool(vleObjectProperty.Values[_lc[I_PROP_ITEM_FALLS]]);
4685 end;
4686 end;
4688 OBJECT_MONSTER:
4689 begin
4690 with gMonsters[SelectedObjects[_id].ID] do
4691 begin
4692 X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
4693 Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
4694 Direction := NameToDir(vleObjectProperty.Values[_lc[I_PROP_DIRECTION]]);
4695 end;
4696 end;
4698 OBJECT_AREA:
4699 begin
4700 with gAreas[SelectedObjects[_id].ID] do
4701 begin
4702 X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
4703 Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
4704 Direction := NameToDir(vleObjectProperty.Values[_lc[I_PROP_DIRECTION]]);
4705 end;
4706 end;
4708 OBJECT_TRIGGER:
4709 begin
4710 with gTriggers[SelectedObjects[_id].ID] do
4711 begin
4712 X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
4713 Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
4714 Width := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_WIDTH]]));
4715 Height := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_HEIGHT]]));
4716 Enabled := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_ENABLED]]);
4717 ActivateType := StrToActivate(vleObjectProperty.Values[_lc[I_PROP_TR_ACTIVATION]]);
4718 Key := StrToKey(vleObjectProperty.Values[_lc[I_PROP_TR_KEYS]]);
4720 case TriggerType of
4721 TRIGGER_EXIT:
4722 begin
4723 s := vleObjectProperty.Values[_lc[I_PROP_TR_NEXT_MAP]];
4724 FillByte(Data.MapName[0], 16, 0);
4725 if s <> '' then
4726 Move(Data.MapName[0], s[1], Min(Length(s), 16));
4727 end;
4729 TRIGGER_TEXTURE:
4730 begin
4731 Data.ActivateOnce := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_TEXTURE_ONCE]]);
4732 Data.AnimOnce := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_TEXTURE_ANIM_ONCE]]);
4733 end;
4735 TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF:
4736 begin
4737 Data.Wait := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EX_DELAY]], 0), 65535);
4738 Data.Count := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EX_COUNT]], 0), 65535);
4739 if Data.Count < 1 then
4740 Data.Count := 1;
4741 if TriggerType = TRIGGER_PRESS then
4742 Data.ExtRandom := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_EX_RANDOM]]);
4743 end;
4745 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR, TRIGGER_DOOR5,
4746 TRIGGER_CLOSETRAP, TRIGGER_TRAP, TRIGGER_LIFTUP, TRIGGER_LIFTDOWN,
4747 TRIGGER_LIFT:
4748 begin
4749 Data.NoSound := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SILENT]]);
4750 Data.d2d_doors := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_D2D]]);
4751 end;
4753 TRIGGER_TELEPORT:
4754 begin
4755 Data.d2d_teleport := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_D2D]]);
4756 Data.silent_teleport := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_TELEPORT_SILENT]]);
4757 Data.TlpDir := NameToDirAdv(vleObjectProperty.Values[_lc[I_PROP_TR_TELEPORT_DIR]]);
4758 end;
4760 TRIGGER_SOUND:
4761 begin
4762 s := vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_NAME]];
4763 FillByte(Data.SoundName[0], 64, 0);
4764 if s <> '' then
4765 Move(Data.SoundName[0], s[1], Min(Length(s), 64));
4767 Data.Volume := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_VOLUME]], 0), 255);
4768 Data.Pan := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_PAN]], 0), 255);
4769 Data.PlayCount := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_COUNT]], 0), 255);
4770 Data.Local := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_LOCAL]]);
4771 Data.SoundSwitch := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_SWITCH]]);
4772 end;
4774 TRIGGER_SPAWNMONSTER:
4775 begin
4776 Data.MonType := StrToMonster(vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_TYPE]]);
4777 Data.MonDir := Byte(NameToDir(vleObjectProperty.Values[_lc[I_PROP_DIRECTION]]));
4778 Data.MonHealth := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_HEALTH]], 0), 1000000);
4779 if Data.MonHealth < 0 then
4780 Data.MonHealth := 0;
4781 Data.MonActive := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_ACTIVE]]);
4782 Data.MonCount := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_COUNT]], 0), 64);
4783 if Data.MonCount < 1 then
4784 Data.MonCount := 1;
4785 Data.MonEffect := StrToEffect(vleObjectProperty.Values[_lc[I_PROP_TR_FX_TYPE]]);
4786 Data.MonMax := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SPAWN_MAX]], 0), 65535);
4787 Data.MonDelay := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SPAWN_DELAY]], 0), 65535);
4788 Data.MonBehav := 0;
4789 if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_1] then
4790 Data.MonBehav := 1;
4791 if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_2] then
4792 Data.MonBehav := 2;
4793 if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_3] then
4794 Data.MonBehav := 3;
4795 if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_4] then
4796 Data.MonBehav := 4;
4797 if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_5] then
4798 Data.MonBehav := 5;
4799 end;
4801 TRIGGER_SPAWNITEM:
4802 begin
4803 Data.ItemType := StrToItem(vleObjectProperty.Values[_lc[I_PROP_TR_ITEM_TYPE]]);
4804 Data.ItemOnlyDM := NameToBool(vleObjectProperty.Values[_lc[I_PROP_DM_ONLY]]);
4805 Data.ItemFalls := NameToBool(vleObjectProperty.Values[_lc[I_PROP_ITEM_FALLS]]);
4806 Data.ItemCount := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_COUNT]], 0), 64);
4807 if Data.ItemCount < 1 then
4808 Data.ItemCount := 1;
4809 Data.ItemEffect := StrToEffect(vleObjectProperty.Values[_lc[I_PROP_TR_FX_TYPE]]);
4810 Data.ItemMax := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SPAWN_MAX]], 0), 65535);
4811 Data.ItemDelay := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SPAWN_DELAY]], 0), 65535);
4812 end;
4814 TRIGGER_MUSIC:
4815 begin
4816 s := vleObjectProperty.Values[_lc[I_PROP_TR_MUSIC_NAME]];
4817 FillByte(Data.MusicName[0], 64, 0);
4818 if s <> '' then
4819 Move(Data.MusicName[0], s[1], Min(Length(s), 64));
4821 if vleObjectProperty.Values[_lc[I_PROP_TR_MUSIC_ACT]] = _lc[I_PROP_TR_MUSIC_ON] then
4822 Data.MusicAction := 1
4823 else
4824 Data.MusicAction := 2;
4825 end;
4827 TRIGGER_PUSH:
4828 begin
4829 Data.PushAngle := Min(
4830 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_PUSH_ANGLE]], 0), 360);
4831 Data.PushForce := Min(
4832 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_PUSH_FORCE]], 0), 255);
4833 Data.ResetVel := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_PUSH_RESET]]);
4834 end;
4836 TRIGGER_SCORE:
4837 begin
4838 Data.ScoreAction := 0;
4839 if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_ACT]] = _lc[I_PROP_TR_SCORE_ACT_1] then
4840 Data.ScoreAction := 1
4841 else if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_ACT]] = _lc[I_PROP_TR_SCORE_ACT_2] then
4842 Data.ScoreAction := 2
4843 else if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_ACT]] = _lc[I_PROP_TR_SCORE_ACT_3] then
4844 Data.ScoreAction := 3;
4845 Data.ScoreCount := Min(Max(
4846 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_COUNT]], 0), 0), 255);
4847 Data.ScoreTeam := 0;
4848 if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_TEAM]] = _lc[I_PROP_TR_SCORE_TEAM_1] then
4849 Data.ScoreTeam := 1
4850 else if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_TEAM]] = _lc[I_PROP_TR_SCORE_TEAM_2] then
4851 Data.ScoreTeam := 2
4852 else if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_TEAM]] = _lc[I_PROP_TR_SCORE_TEAM_3] then
4853 Data.ScoreTeam := 3;
4854 Data.ScoreCon := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_CON]]);
4855 Data.ScoreMsg := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_MSG]]);
4856 end;
4858 TRIGGER_MESSAGE:
4859 begin
4860 Data.MessageKind := 0;
4861 if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_KIND]] = _lc[I_PROP_TR_MESSAGE_KIND_1] then
4862 Data.MessageKind := 1;
4864 Data.MessageSendTo := 0;
4865 if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_1] then
4866 Data.MessageSendTo := 1
4867 else if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_2] then
4868 Data.MessageSendTo := 2
4869 else if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_3] then
4870 Data.MessageSendTo := 3
4871 else if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_4] then
4872 Data.MessageSendTo := 4
4873 else if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_5] then
4874 Data.MessageSendTo := 5;
4876 s := vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TEXT]];
4877 FillByte(Data.MessageText[0], 100, 0);
4878 if s <> '' then
4879 Move(Data.MessageText[0], s[1], Min(Length(s), 100));
4881 Data.MessageTime := Min(Max(
4882 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TIME]], 0), 0), 65535);
4883 end;
4885 TRIGGER_DAMAGE:
4886 begin
4887 Data.DamageValue := Min(Max(
4888 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_DAMAGE_VALUE]], 0), 0), 65535);
4889 Data.DamageInterval := Min(Max(
4890 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_INTERVAL]], 0), 0), 65535);
4891 end;
4893 TRIGGER_HEALTH:
4894 begin
4895 Data.HealValue := Min(Max(
4896 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_HEALTH]], 0), 0), 65535);
4897 Data.HealInterval := Min(Max(
4898 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_INTERVAL]], 0), 0), 65535);
4899 Data.HealMax := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_HEALTH_MAX]]);
4900 Data.HealSilent := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SILENT]]);
4901 end;
4903 TRIGGER_SHOT:
4904 begin
4905 Data.ShotType := StrToShot(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TYPE]]);
4906 Data.ShotSound := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_SOUND]]);
4907 Data.ShotTarget := 0;
4908 if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_1] then
4909 Data.ShotTarget := 1
4910 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_2] then
4911 Data.ShotTarget := 2
4912 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_3] then
4913 Data.ShotTarget := 3
4914 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_4] then
4915 Data.ShotTarget := 4
4916 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_5] then
4917 Data.ShotTarget := 5
4918 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_6] then
4919 Data.ShotTarget := 6;
4920 Data.ShotIntSight := Min(Max(
4921 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_SIGHT]], 0), 0), 65535);
4922 Data.ShotAim := 0;
4923 if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_AIM]] = _lc[I_PROP_TR_SHOT_AIM_1] then
4924 Data.ShotAim := 1
4925 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_AIM]] = _lc[I_PROP_TR_SHOT_AIM_2] then
4926 Data.ShotAim := 2
4927 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_AIM]] = _lc[I_PROP_TR_SHOT_AIM_3] then
4928 Data.ShotAim := 3;
4929 Data.ShotAngle := Min(
4930 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_ANGLE]], 0), 360);
4931 Data.ShotWait := Min(Max(
4932 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EX_DELAY]], 0), 0), 65535);
4933 Data.ShotAccuracy := Min(Max(
4934 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_ACC]], 0), 0), 65535);
4935 Data.ShotAmmo := Min(Max(
4936 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_AMMO]], 0), 0), 65535);
4937 Data.ShotIntReload := Min(Max(
4938 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_RELOAD]], 0), 0), 65535);
4939 end;
4941 TRIGGER_EFFECT:
4942 begin
4943 Data.FXCount := Min(Max(
4944 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_COUNT]], 0), 0), 255);
4945 if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_TYPE]] = _lc[I_PROP_TR_EFFECT_PARTICLE] then
4946 begin
4947 Data.FXType := TRIGGER_EFFECT_PARTICLE;
4948 Data.FXSubType := TRIGGER_EFFECT_SLIQUID;
4949 if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_SLIQUID] then
4950 Data.FXSubType := TRIGGER_EFFECT_SLIQUID
4951 else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_LLIQUID] then
4952 Data.FXSubType := TRIGGER_EFFECT_LLIQUID
4953 else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_DLIQUID] then
4954 Data.FXSubType := TRIGGER_EFFECT_DLIQUID
4955 else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_BLOOD] then
4956 Data.FXSubType := TRIGGER_EFFECT_BLOOD
4957 else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_SPARK] then
4958 Data.FXSubType := TRIGGER_EFFECT_SPARK
4959 else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_BUBBLE] then
4960 Data.FXSubType := TRIGGER_EFFECT_BUBBLE;
4961 end else
4962 begin
4963 Data.FXType := TRIGGER_EFFECT_ANIMATION;
4964 Data.FXSubType := StrToEffect(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]]);
4965 end;
4966 a := Min(Max(
4967 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_COLOR]], 0), 0), $FFFFFF);
4968 Data.FXColorR := a and $FF;
4969 Data.FXColorG := (a shr 8) and $FF;
4970 Data.FXColorB := (a shr 16) and $FF;
4971 if NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_CENTER]]) then
4972 Data.FXPos := 0
4973 else
4974 Data.FXPos := 1;
4975 Data.FXWait := Min(Max(
4976 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EX_DELAY]], 0), 0), 65535);
4977 Data.FXVelX := Min(Max(
4978 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_VELX]], 0), -128), 127);
4979 Data.FXVelY := Min(Max(
4980 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_VELY]], 0), -128), 127);
4981 Data.FXSpreadL := Min(Max(
4982 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SPL]], 0), 0), 255);
4983 Data.FXSpreadR := Min(Max(
4984 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SPR]], 0), 0), 255);
4985 Data.FXSpreadU := Min(Max(
4986 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SPU]], 0), 0), 255);
4987 Data.FXSpreadD := Min(Max(
4988 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SPD]], 0), 0), 255);
4989 end;
4990 end;
4991 end;
4992 end;
4993 end;
4995 FillProperty();
4997 vleObjectProperty.Row := r;
4998 vleObjectProperty.Col := c;
4999 end;
5001 procedure TMainForm.bbRemoveTextureClick(Sender: TObject);
5002 var
5003 a, i: Integer;
5004 begin
5005 i := lbTextureList.ItemIndex;
5006 if i = -1 then
5007 Exit;
5009 if MessageBox(0, PChar(Format(_lc[I_MSG_DEL_TEXTURE_PROMT],
5010 [SelectedTexture()])),
5011 PChar(_lc[I_MSG_DEL_TEXTURE]),
5012 MB_ICONQUESTION or MB_YESNO or
5013 MB_DEFBUTTON1) <> idYes then
5014 Exit;
5016 if gPanels <> nil then
5017 for a := 0 to High(gPanels) do
5018 if (gPanels[a].PanelType <> 0) and
5019 (gPanels[a].TextureName = SelectedTexture()) then
5020 begin
5021 ErrorMessageBox(_lc[I_MSG_DEL_TEXTURE_CANT]);
5022 Exit;
5023 end;
5025 g_DeleteTexture(SelectedTexture());
5026 i := slInvalidTextures.IndexOf(lbTextureList.Items[i]);
5027 if i > -1 then
5028 slInvalidTextures.Delete(i);
5029 if lbTextureList.ItemIndex > -1 then
5030 lbTextureList.Items.Delete(lbTextureList.ItemIndex)
5031 end;
5033 procedure TMainForm.aNewMapExecute(Sender: TObject);
5034 begin
5035 if (MessageBox(0, PChar(_lc[I_MSG_CLEAR_MAP_PROMT]),
5036 PChar(_lc[I_MSG_CLEAR_MAP]),
5037 MB_ICONQUESTION or MB_YESNO or
5038 MB_DEFBUTTON1) = mrYes) then
5039 FullClear();
5040 end;
5042 procedure TMainForm.aUndoExecute(Sender: TObject);
5043 var
5044 a: Integer;
5045 begin
5046 if UndoBuffer = nil then
5047 Exit;
5048 if UndoBuffer[High(UndoBuffer)] = nil then
5049 Exit;
5051 for a := 0 to High(UndoBuffer[High(UndoBuffer)]) do
5052 with UndoBuffer[High(UndoBuffer)][a] do
5053 begin
5054 case UndoType of
5055 UNDO_DELETE_PANEL:
5056 begin
5057 AddPanel(Panel^);
5058 Panel := nil;
5059 end;
5060 UNDO_DELETE_ITEM: AddItem(Item);
5061 UNDO_DELETE_AREA: AddArea(Area);
5062 UNDO_DELETE_MONSTER: AddMonster(Monster);
5063 UNDO_DELETE_TRIGGER: AddTrigger(Trigger);
5064 UNDO_ADD_PANEL: RemoveObject(AddID, OBJECT_PANEL);
5065 UNDO_ADD_ITEM: RemoveObject(AddID, OBJECT_ITEM);
5066 UNDO_ADD_AREA: RemoveObject(AddID, OBJECT_AREA);
5067 UNDO_ADD_MONSTER: RemoveObject(AddID, OBJECT_MONSTER);
5068 UNDO_ADD_TRIGGER: RemoveObject(AddID, OBJECT_TRIGGER);
5069 end;
5070 end;
5072 SetLength(UndoBuffer, Length(UndoBuffer)-1);
5074 RemoveSelectFromObjects();
5076 miUndo.Enabled := UndoBuffer <> nil;
5077 end;
5080 procedure TMainForm.aCopyObjectExecute(Sender: TObject);
5081 var
5082 a, b: Integer;
5083 CopyBuffer: TCopyRecArray;
5084 str: String;
5085 ok: Boolean;
5087 function CB_Compare(I1, I2: TCopyRec): Integer;
5088 begin
5089 Result := Integer(I1.ObjectType) - Integer(I2.ObjectType);
5091 if Result = 0 then // Одного типа
5092 Result := Integer(I1.ID) - Integer(I2.ID);
5093 end;
5095 procedure QuickSortCopyBuffer(L, R: Integer);
5096 var
5097 I, J: Integer;
5098 P, T: TCopyRec;
5099 begin
5100 repeat
5101 I := L;
5102 J := R;
5103 P := CopyBuffer[(L + R) shr 1];
5105 repeat
5106 while CB_Compare(CopyBuffer[I], P) < 0 do
5107 Inc(I);
5108 while CB_Compare(CopyBuffer[J], P) > 0 do
5109 Dec(J);
5111 if I <= J then
5112 begin
5113 T := CopyBuffer[I];
5114 CopyBuffer[I] := CopyBuffer[J];
5115 CopyBuffer[J] := T;
5116 Inc(I);
5117 Dec(J);
5118 end;
5119 until I > J;
5121 if L < J then
5122 QuickSortCopyBuffer(L, J);
5124 L := I;
5125 until I >= R;
5126 end;
5128 begin
5129 if SelectedObjects = nil then
5130 Exit;
5132 b := -1;
5133 CopyBuffer := nil;
5135 // Копируем объекты:
5136 for a := 0 to High(SelectedObjects) do
5137 if SelectedObjects[a].Live then
5138 with SelectedObjects[a] do
5139 begin
5140 SetLength(CopyBuffer, Length(CopyBuffer)+1);
5141 b := High(CopyBuffer);
5142 CopyBuffer[b].ID := ID;
5143 CopyBuffer[b].Panel := nil;
5145 case ObjectType of
5146 OBJECT_PANEL:
5147 begin
5148 CopyBuffer[b].ObjectType := OBJECT_PANEL;
5149 New(CopyBuffer[b].Panel);
5150 CopyBuffer[b].Panel^ := gPanels[ID];
5151 end;
5153 OBJECT_ITEM:
5154 begin
5155 CopyBuffer[b].ObjectType := OBJECT_ITEM;
5156 CopyBuffer[b].Item := gItems[ID];
5157 end;
5159 OBJECT_MONSTER:
5160 begin
5161 CopyBuffer[b].ObjectType := OBJECT_MONSTER;
5162 CopyBuffer[b].Monster := gMonsters[ID];
5163 end;
5165 OBJECT_AREA:
5166 begin
5167 CopyBuffer[b].ObjectType := OBJECT_AREA;
5168 CopyBuffer[b].Area := gAreas[ID];
5169 end;
5171 OBJECT_TRIGGER:
5172 begin
5173 CopyBuffer[b].ObjectType := OBJECT_TRIGGER;
5174 CopyBuffer[b].Trigger := gTriggers[ID];
5175 end;
5176 end;
5177 end;
5179 // Сортировка по ID:
5180 if CopyBuffer <> nil then
5181 begin
5182 QuickSortCopyBuffer(0, b);
5183 end;
5185 // Пестановка ссылок триггеров:
5186 for a := 0 to Length(CopyBuffer)-1 do
5187 if CopyBuffer[a].ObjectType = OBJECT_TRIGGER then
5188 begin
5189 case CopyBuffer[a].Trigger.TriggerType of
5190 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
5191 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP,
5192 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
5193 if CopyBuffer[a].Trigger.Data.PanelID <> -1 then
5194 begin
5195 ok := False;
5197 for b := 0 to Length(CopyBuffer)-1 do
5198 if (CopyBuffer[b].ObjectType = OBJECT_PANEL) and
5199 (Integer(CopyBuffer[b].ID) = CopyBuffer[a].Trigger.Data.PanelID) then
5200 begin
5201 CopyBuffer[a].Trigger.Data.PanelID := b;
5202 ok := True;
5203 Break;
5204 end;
5206 // Этих панелей нет среди копируемых:
5207 if not ok then
5208 CopyBuffer[a].Trigger.Data.PanelID := -1;
5209 end;
5211 TRIGGER_PRESS, TRIGGER_ON,
5212 TRIGGER_OFF, TRIGGER_ONOFF:
5213 if CopyBuffer[a].Trigger.Data.MonsterID <> 0 then
5214 begin
5215 ok := False;
5217 for b := 0 to Length(CopyBuffer)-1 do
5218 if (CopyBuffer[b].ObjectType = OBJECT_MONSTER) and
5219 (Integer(CopyBuffer[b].ID) = CopyBuffer[a].Trigger.Data.MonsterID-1) then
5220 begin
5221 CopyBuffer[a].Trigger.Data.MonsterID := b+1;
5222 ok := True;
5223 Break;
5224 end;
5226 // Этих монстров нет среди копируемых:
5227 if not ok then
5228 CopyBuffer[a].Trigger.Data.MonsterID := 0;
5229 end;
5231 TRIGGER_SHOT:
5232 if CopyBuffer[a].Trigger.Data.ShotPanelID <> -1 then
5233 begin
5234 ok := False;
5236 for b := 0 to Length(CopyBuffer)-1 do
5237 if (CopyBuffer[b].ObjectType = OBJECT_PANEL) and
5238 (Integer(CopyBuffer[b].ID) = CopyBuffer[a].Trigger.Data.ShotPanelID) then
5239 begin
5240 CopyBuffer[a].Trigger.Data.ShotPanelID := b;
5241 ok := True;
5242 Break;
5243 end;
5245 // Этих панелей нет среди копируемых:
5246 if not ok then
5247 CopyBuffer[a].Trigger.Data.ShotPanelID := -1;
5248 end;
5249 end;
5251 if CopyBuffer[a].Trigger.TexturePanel <> -1 then
5252 begin
5253 ok := False;
5255 for b := 0 to Length(CopyBuffer)-1 do
5256 if (CopyBuffer[b].ObjectType = OBJECT_PANEL) and
5257 (Integer(CopyBuffer[b].ID) = CopyBuffer[a].Trigger.TexturePanel) then
5258 begin
5259 CopyBuffer[a].Trigger.TexturePanel := b;
5260 ok := True;
5261 Break;
5262 end;
5264 // Этих панелей нет среди копируемых:
5265 if not ok then
5266 CopyBuffer[a].Trigger.TexturePanel := -1;
5267 end;
5268 end;
5270 // В буфер обмена:
5271 str := CopyBufferToString(CopyBuffer);
5272 ClipBoard.AsText := str;
5274 for a := 0 to Length(CopyBuffer)-1 do
5275 if (CopyBuffer[a].ObjectType = OBJECT_PANEL) and
5276 (CopyBuffer[a].Panel <> nil) then
5277 Dispose(CopyBuffer[a].Panel);
5279 CopyBuffer := nil;
5280 end;
5282 procedure TMainForm.aPasteObjectExecute(Sender: TObject);
5283 var
5284 a, h: Integer;
5285 CopyBuffer: TCopyRecArray;
5286 res: Boolean;
5287 swad, ssec, sres: String;
5288 begin
5289 CopyBuffer := nil;
5291 StringToCopyBuffer(ClipBoard.AsText, CopyBuffer);
5293 if CopyBuffer = nil then
5294 Exit;
5296 RemoveSelectFromObjects();
5298 h := High(CopyBuffer);
5299 for a := 0 to h do
5300 with CopyBuffer[a] do
5301 begin
5302 case ObjectType of
5303 OBJECT_PANEL:
5304 if Panel <> nil then
5305 begin
5306 Panel^.X := Panel^.X + 16;
5307 Panel^.Y := Panel^.Y + 16;
5309 Panel^.TextureID := TEXTURE_SPECIAL_NONE;
5310 Panel^.TextureWidth := 1;
5311 Panel^.TextureHeight := 1;
5313 if (Panel^.PanelType = PANEL_LIFTUP) or
5314 (Panel^.PanelType = PANEL_LIFTDOWN) or
5315 (Panel^.PanelType = PANEL_LIFTLEFT) or
5316 (Panel^.PanelType = PANEL_LIFTRIGHT) or
5317 (Panel^.PanelType = PANEL_BLOCKMON) or
5318 (Panel^.TextureName = '') then
5319 begin // Нет или не может быть текстуры:
5320 end
5321 else // Есть текстура:
5322 begin
5323 // Обычная текстура:
5324 if not IsSpecialTexture(Panel^.TextureName) then
5325 begin
5326 res := g_GetTexture(Panel^.TextureName, Panel^.TextureID);
5328 if not res then
5329 begin
5330 g_ProcessResourceStr(Panel^.TextureName, swad, ssec, sres);
5331 AddTexture(swad, ssec, sres, True);
5332 res := g_GetTexture(Panel^.TextureName, Panel^.TextureID);
5333 end;
5335 if res then
5336 g_GetTextureSizeByName(Panel^.TextureName,
5337 Panel^.TextureWidth, Panel^.TextureHeight)
5338 else
5339 Panel^.TextureName := '';
5340 end
5341 else // Спец.текстура:
5342 begin
5343 Panel^.TextureID := SpecialTextureID(Panel^.TextureName);
5344 with MainForm.lbTextureList.Items do
5345 if IndexOf(win2utf(Panel^.TextureName)) = -1 then
5346 Add(win2utf(Panel^.TextureName));
5347 end;
5348 end;
5350 ID := AddPanel(Panel^);
5351 Dispose(Panel);
5352 Undo_Add(OBJECT_PANEL, ID, a > 0);
5353 SelectObject(OBJECT_PANEL, ID, True);
5354 end;
5356 OBJECT_ITEM:
5357 begin
5358 Item.X := Item.X + 16;
5359 Item.Y := Item.Y + 16;
5361 ID := AddItem(Item);
5362 Undo_Add(OBJECT_ITEM, ID, a > 0);
5363 SelectObject(OBJECT_ITEM, ID, True);
5364 end;
5366 OBJECT_MONSTER:
5367 begin
5368 Monster.X := Monster.X + 16;
5369 Monster.Y := Monster.Y + 16;
5371 ID := AddMonster(Monster);
5372 Undo_Add(OBJECT_MONSTER, ID, a > 0);
5373 SelectObject(OBJECT_MONSTER, ID, True);
5374 end;
5376 OBJECT_AREA:
5377 begin
5378 Area.X := Area.X + 16;
5379 Area.Y := Area.Y + 16;
5381 ID := AddArea(Area);
5382 Undo_Add(OBJECT_AREA, ID, a > 0);
5383 SelectObject(OBJECT_AREA, ID, True);
5384 end;
5386 OBJECT_TRIGGER:
5387 begin
5388 Trigger.X := Trigger.X + 16;
5389 Trigger.Y := Trigger.Y + 16;
5391 ID := AddTrigger(Trigger);
5392 Undo_Add(OBJECT_TRIGGER, ID, a > 0);
5393 SelectObject(OBJECT_TRIGGER, ID, True);
5394 end;
5395 end;
5396 end;
5398 // Переставляем ссылки триггеров:
5399 for a := 0 to High(CopyBuffer) do
5400 if CopyBuffer[a].ObjectType = OBJECT_TRIGGER then
5401 begin
5402 case CopyBuffer[a].Trigger.TriggerType of
5403 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
5404 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP,
5405 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
5406 if CopyBuffer[a].Trigger.Data.PanelID <> -1 then
5407 gTriggers[CopyBuffer[a].ID].Data.PanelID :=
5408 CopyBuffer[CopyBuffer[a].Trigger.Data.PanelID].ID;
5410 TRIGGER_PRESS, TRIGGER_ON,
5411 TRIGGER_OFF, TRIGGER_ONOFF:
5412 if CopyBuffer[a].Trigger.Data.MonsterID <> 0 then
5413 gTriggers[CopyBuffer[a].ID].Data.MonsterID :=
5414 CopyBuffer[CopyBuffer[a].Trigger.Data.MonsterID-1].ID+1;
5416 TRIGGER_SHOT:
5417 if CopyBuffer[a].Trigger.Data.ShotPanelID <> -1 then
5418 gTriggers[CopyBuffer[a].ID].Data.ShotPanelID :=
5419 CopyBuffer[CopyBuffer[a].Trigger.Data.ShotPanelID].ID;
5420 end;
5422 if CopyBuffer[a].Trigger.TexturePanel <> -1 then
5423 gTriggers[CopyBuffer[a].ID].TexturePanel :=
5424 CopyBuffer[CopyBuffer[a].Trigger.TexturePanel].ID;
5425 end;
5427 CopyBuffer := nil;
5429 if h = 0 then
5430 FillProperty();
5431 end;
5433 procedure TMainForm.aCutObjectExecute(Sender: TObject);
5434 begin
5435 miCopy.Click();
5436 DeleteSelectedObjects();
5437 end;
5439 procedure TMainForm.vleObjectPropertyEditButtonClick(Sender: TObject);
5440 var
5441 Key, FileName: String;
5442 b: Byte;
5443 begin
5444 Key := vleObjectProperty.Keys[vleObjectProperty.Row];
5446 if Key = _lc[I_PROP_PANEL_TYPE] then
5447 begin
5448 with ChooseTypeForm, vleObjectProperty do
5449 begin // Выбор типа панели:
5450 Caption := _lc[I_PROP_PANEL_TYPE];
5451 lbTypeSelect.Items.Clear();
5453 for b := 0 to High(PANELNAMES) do
5454 begin
5455 lbTypeSelect.Items.Add(PANELNAMES[b]);
5456 if Values[Key] = PANELNAMES[b] then
5457 lbTypeSelect.ItemIndex := b;
5458 end;
5460 if ShowModal() = mrOK then
5461 begin
5462 b := lbTypeSelect.ItemIndex;
5463 Values[Key] := PANELNAMES[b];
5464 bApplyProperty.Click();
5465 end;
5466 end
5467 end
5468 else if Key = _lc[I_PROP_TR_TELEPORT_TO] then
5469 SelectFlag := SELECTFLAG_TELEPORT
5470 else if Key = _lc[I_PROP_TR_SPAWN_TO] then
5471 SelectFlag := SELECTFLAG_SPAWNPOINT
5472 else if (Key = _lc[I_PROP_TR_DOOR_PANEL]) or
5473 (Key = _lc[I_PROP_TR_TRAP_PANEL]) then
5474 SelectFlag := SELECTFLAG_DOOR
5475 else if Key = _lc[I_PROP_TR_TEXTURE_PANEL] then
5476 begin
5477 DrawPressRect := False;
5478 SelectFlag := SELECTFLAG_TEXTURE;
5479 end
5480 else if Key = _lc[I_PROP_TR_SHOT_PANEL] then
5481 SelectFlag := SELECTFLAG_SHOTPANEL
5482 else if Key = _lc[I_PROP_TR_LIFT_PANEL] then
5483 SelectFlag := SELECTFLAG_LIFT
5484 else if key = _lc[I_PROP_TR_EX_MONSTER] then
5485 SelectFlag := SELECTFLAG_MONSTER
5486 else if Key = _lc[I_PROP_TR_EX_AREA] then
5487 begin
5488 SelectFlag := SELECTFLAG_NONE;
5489 DrawPressRect := True;
5490 end
5491 else if Key = _lc[I_PROP_TR_NEXT_MAP] then
5492 begin // Выбор следующей карты:
5493 g_ProcessResourceStr(OpenedMap, @FileName, nil, nil);
5494 SelectMapForm.GetMaps(FileName);
5496 if SelectMapForm.ShowModal() = mrOK then
5497 begin
5498 vleObjectProperty.Values[Key] := SelectMapForm.lbMapList.Items[SelectMapForm.lbMapList.ItemIndex];
5499 bApplyProperty.Click();
5500 end;
5501 end
5502 else if (Key = _lc[I_PROP_TR_SOUND_NAME]) or
5503 (Key = _lc[I_PROP_TR_MUSIC_NAME]) then
5504 begin // Выбор файла звука/музыки:
5505 AddSoundForm.OKFunction := nil;
5506 AddSoundForm.lbResourcesList.MultiSelect := False;
5507 AddSoundForm.SetResource := utf2win(vleObjectProperty.Values[Key]);
5509 if (AddSoundForm.ShowModal() = mrOk) then
5510 begin
5511 vleObjectProperty.Values[Key] := utf2win(AddSoundForm.ResourceName);
5512 bApplyProperty.Click();
5513 end;
5514 end
5515 else if Key = _lc[I_PROP_TR_ACTIVATION] then
5516 with ActivationTypeForm, vleObjectProperty do
5517 begin // Выбор типов активации:
5518 cbPlayerCollide.Checked := Pos('PC', Values[Key]) > 0;
5519 cbMonsterCollide.Checked := Pos('MC', Values[Key]) > 0;
5520 cbPlayerPress.Checked := Pos('PP', Values[Key]) > 0;
5521 cbMonsterPress.Checked := Pos('MP', Values[Key]) > 0;
5522 cbShot.Checked := Pos('SH', Values[Key]) > 0;
5523 cbNoMonster.Checked := Pos('NM', Values[Key]) > 0;
5525 if ShowModal() = mrOK then
5526 begin
5527 b := 0;
5528 if cbPlayerCollide.Checked then
5529 b := ACTIVATE_PLAYERCOLLIDE;
5530 if cbMonsterCollide.Checked then
5531 b := b or ACTIVATE_MONSTERCOLLIDE;
5532 if cbPlayerPress.Checked then
5533 b := b or ACTIVATE_PLAYERPRESS;
5534 if cbMonsterPress.Checked then
5535 b := b or ACTIVATE_MONSTERPRESS;
5536 if cbShot.Checked then
5537 b := b or ACTIVATE_SHOT;
5538 if cbNoMonster.Checked then
5539 b := b or ACTIVATE_NOMONSTER;
5541 Values[Key] := ActivateToStr(b);
5542 bApplyProperty.Click();
5543 end;
5544 end
5545 else if Key = _lc[I_PROP_TR_KEYS] then
5546 with KeysForm, vleObjectProperty do
5547 begin // Выбор необходимых ключей:
5548 cbRedKey.Checked := Pos('RK', Values[Key]) > 0;
5549 cbGreenKey.Checked := Pos('GK', Values[Key]) > 0;
5550 cbBlueKey.Checked := Pos('BK', Values[Key]) > 0;
5551 cbRedTeam.Checked := Pos('RT', Values[Key]) > 0;
5552 cbBlueTeam.Checked := Pos('BT', Values[Key]) > 0;
5554 if ShowModal() = mrOK then
5555 begin
5556 b := 0;
5557 if cbRedKey.Checked then
5558 b := KEY_RED;
5559 if cbGreenKey.Checked then
5560 b := b or KEY_GREEN;
5561 if cbBlueKey.Checked then
5562 b := b or KEY_BLUE;
5563 if cbRedTeam.Checked then
5564 b := b or KEY_REDTEAM;
5565 if cbBlueTeam.Checked then
5566 b := b or KEY_BLUETEAM;
5568 Values[Key] := KeyToStr(b);
5569 bApplyProperty.Click();
5570 end;
5571 end
5572 else if Key = _lc[I_PROP_TR_FX_TYPE] then
5573 with ChooseTypeForm, vleObjectProperty do
5574 begin // Выбор типа эффекта:
5575 Caption := _lc[I_CAP_FX_TYPE];
5576 lbTypeSelect.Items.Clear();
5578 for b := EFFECT_NONE to EFFECT_FIRE do
5579 lbTypeSelect.Items.Add(EffectToStr(b));
5581 lbTypeSelect.ItemIndex := StrToEffect(Values[Key]);
5583 if ShowModal() = mrOK then
5584 begin
5585 b := lbTypeSelect.ItemIndex;
5586 Values[Key] := EffectToStr(b);
5587 bApplyProperty.Click();
5588 end;
5589 end
5590 else if Key = _lc[I_PROP_TR_MONSTER_TYPE] then
5591 with ChooseTypeForm, vleObjectProperty do
5592 begin // Выбор типа монстра:
5593 Caption := _lc[I_CAP_MONSTER_TYPE];
5594 lbTypeSelect.Items.Clear();
5596 for b := MONSTER_DEMON to MONSTER_MAN do
5597 lbTypeSelect.Items.Add(MonsterToStr(b));
5599 lbTypeSelect.ItemIndex := StrToMonster(Values[Key]) - MONSTER_DEMON;
5601 if ShowModal() = mrOK then
5602 begin
5603 b := lbTypeSelect.ItemIndex + MONSTER_DEMON;
5604 Values[Key] := MonsterToStr(b);
5605 bApplyProperty.Click();
5606 end;
5607 end
5608 else if Key = _lc[I_PROP_TR_ITEM_TYPE] then
5609 with ChooseTypeForm, vleObjectProperty do
5610 begin // Выбор типа предмета:
5611 Caption := _lc[I_CAP_ITEM_TYPE];
5612 lbTypeSelect.Items.Clear();
5614 for b := ITEM_MEDKIT_SMALL to ITEM_KEY_BLUE do
5615 lbTypeSelect.Items.Add(ItemToStr(b));
5616 lbTypeSelect.Items.Add(ItemToStr(ITEM_BOTTLE));
5617 lbTypeSelect.Items.Add(ItemToStr(ITEM_HELMET));
5618 lbTypeSelect.Items.Add(ItemToStr(ITEM_JETPACK));
5619 lbTypeSelect.Items.Add(ItemToStr(ITEM_INVIS));
5620 lbTypeSelect.Items.Add(ItemToStr(ITEM_WEAPON_FLAMETHROWER));
5621 lbTypeSelect.Items.Add(ItemToStr(ITEM_AMMO_FUELCAN));
5623 b := StrToItem(Values[Key]);
5624 if b >= ITEM_BOTTLE then
5625 b := b - 2;
5626 lbTypeSelect.ItemIndex := b - ITEM_MEDKIT_SMALL;
5628 if ShowModal() = mrOK then
5629 begin
5630 b := lbTypeSelect.ItemIndex + ITEM_MEDKIT_SMALL;
5631 if b >= ITEM_WEAPON_KASTET then
5632 b := b + 2;
5633 Values[Key] := ItemToStr(b);
5634 bApplyProperty.Click();
5635 end;
5636 end
5637 else if Key = _lc[I_PROP_TR_SHOT_TYPE] then
5638 with ChooseTypeForm, vleObjectProperty do
5639 begin // Выбор типа предмета:
5640 Caption := _lc[I_PROP_TR_SHOT_TYPE];
5641 lbTypeSelect.Items.Clear();
5643 for b := TRIGGER_SHOT_PISTOL to TRIGGER_SHOT_MAX do
5644 lbTypeSelect.Items.Add(ShotToStr(b));
5646 lbTypeSelect.ItemIndex := StrToShot(Values[Key]);
5648 if ShowModal() = mrOK then
5649 begin
5650 b := lbTypeSelect.ItemIndex;
5651 Values[Key] := ShotToStr(b);
5652 bApplyProperty.Click();
5653 end;
5654 end
5655 else if Key = _lc[I_PROP_TR_EFFECT_TYPE] then
5656 with ChooseTypeForm, vleObjectProperty do
5657 begin // Выбор типа эффекта:
5658 Caption := _lc[I_CAP_FX_TYPE];
5659 lbTypeSelect.Items.Clear();
5661 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_PARTICLE]);
5662 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_ANIMATION]);
5663 if Values[Key] = _lc[I_PROP_TR_EFFECT_ANIMATION] then
5664 lbTypeSelect.ItemIndex := 1
5665 else
5666 lbTypeSelect.ItemIndex := 0;
5668 if ShowModal() = mrOK then
5669 begin
5670 b := lbTypeSelect.ItemIndex;
5671 if b = 0 then
5672 Values[Key] := _lc[I_PROP_TR_EFFECT_PARTICLE]
5673 else
5674 Values[Key] := _lc[I_PROP_TR_EFFECT_ANIMATION];
5675 bApplyProperty.Click();
5676 end;
5677 end
5678 else if Key = _lc[I_PROP_TR_EFFECT_SUBTYPE] then
5679 with ChooseTypeForm, vleObjectProperty do
5680 begin // Выбор подтипа эффекта:
5681 Caption := _lc[I_CAP_FX_TYPE];
5682 lbTypeSelect.Items.Clear();
5684 if Values[_lc[I_PROP_TR_EFFECT_TYPE]] = _lc[I_PROP_TR_EFFECT_ANIMATION] then
5685 begin
5686 for b := EFFECT_TELEPORT to EFFECT_FIRE do
5687 lbTypeSelect.Items.Add(EffectToStr(b));
5689 lbTypeSelect.ItemIndex := StrToEffect(Values[Key]) - 1;
5690 end else
5691 begin
5692 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_SLIQUID]);
5693 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_LLIQUID]);
5694 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_DLIQUID]);
5695 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_BLOOD]);
5696 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_SPARK]);
5697 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_BUBBLE]);
5698 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_SLIQUID;
5699 if Values[Key] = _lc[I_PROP_TR_EFFECT_LLIQUID] then
5700 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_LLIQUID;
5701 if Values[Key] = _lc[I_PROP_TR_EFFECT_DLIQUID] then
5702 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_DLIQUID;
5703 if Values[Key] = _lc[I_PROP_TR_EFFECT_BLOOD] then
5704 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_BLOOD;
5705 if Values[Key] = _lc[I_PROP_TR_EFFECT_SPARK] then
5706 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_SPARK;
5707 if Values[Key] = _lc[I_PROP_TR_EFFECT_BUBBLE] then
5708 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_BUBBLE;
5709 end;
5711 if ShowModal() = mrOK then
5712 begin
5713 b := lbTypeSelect.ItemIndex;
5715 if Values[_lc[I_PROP_TR_EFFECT_TYPE]] = _lc[I_PROP_TR_EFFECT_ANIMATION] then
5716 Values[Key] := EffectToStr(b + 1)
5717 else begin
5718 Values[Key] := _lc[I_PROP_TR_EFFECT_SLIQUID];
5719 if b = TRIGGER_EFFECT_LLIQUID then
5720 Values[Key] := _lc[I_PROP_TR_EFFECT_LLIQUID];
5721 if b = TRIGGER_EFFECT_DLIQUID then
5722 Values[Key] := _lc[I_PROP_TR_EFFECT_DLIQUID];
5723 if b = TRIGGER_EFFECT_BLOOD then
5724 Values[Key] := _lc[I_PROP_TR_EFFECT_BLOOD];
5725 if b = TRIGGER_EFFECT_SPARK then
5726 Values[Key] := _lc[I_PROP_TR_EFFECT_SPARK];
5727 if b = TRIGGER_EFFECT_BUBBLE then
5728 Values[Key] := _lc[I_PROP_TR_EFFECT_BUBBLE];
5729 end;
5731 bApplyProperty.Click();
5732 end;
5733 end
5734 else if Key = _lc[I_PROP_TR_EFFECT_COLOR] then
5735 with vleObjectProperty do
5736 begin // Выбор цвета эффекта:
5737 ColorDialog.Color := StrToIntDef(Values[Key], 0);
5738 if ColorDialog.Execute then
5739 begin
5740 Values[Key] := IntToStr(ColorDialog.Color);
5741 bApplyProperty.Click();
5742 end;
5743 end
5744 else if Key = _lc[I_PROP_PANEL_TEX] then
5745 begin // Смена текстуры:
5746 vleObjectProperty.Values[Key] := SelectedTexture();
5747 bApplyProperty.Click();
5748 end;
5749 end;
5751 procedure TMainForm.aSaveMapExecute(Sender: TObject);
5752 var
5753 FileName, Section, Res: String;
5754 begin
5755 if OpenedMap = '' then
5756 begin
5757 aSaveMapAsExecute(nil);
5758 Exit;
5759 end;
5761 g_ProcessResourceStr(OpenedMap, FileName, Section, Res);
5763 SaveMap(FileName+':\'+Res);
5764 end;
5766 procedure TMainForm.aOpenMapExecute(Sender: TObject);
5767 begin
5768 OpenDialog.Filter := _lc[I_FILE_FILTER_ALL];
5770 if OpenDialog.Execute() then
5771 begin
5772 if (Pos('.ini', LowerCase(ExtractFileName(OpenDialog.FileName))) > 0) then
5773 begin // INI карты:
5774 FullClear();
5776 pLoadProgress.Left := (RenderPanel.Width div 2)-(pLoadProgress.Width div 2);
5777 pLoadProgress.Top := (RenderPanel.Height div 2)-(pLoadProgress.Height div 2);
5778 pLoadProgress.Show();
5780 OpenedMap := '';
5781 OpenedWAD := '';
5783 LoadMapOld(OpenDialog.FileName);
5785 MainForm.Caption := Format('%s - %s', [FormCaption, ExtractFileName(OpenDialog.FileName)]);
5787 pLoadProgress.Hide();
5788 MainForm.FormResize(Self);
5789 end
5790 else // Карты из WAD:
5791 begin
5792 OpenMap(OpenDialog.FileName, '');
5793 end;
5795 OpenDialog.InitialDir := ExtractFileDir(OpenDialog.FileName);
5796 end;
5797 end;
5799 procedure TMainForm.FormActivate(Sender: TObject);
5800 var
5801 lang: Integer;
5802 config: TConfig;
5803 begin
5804 MainForm.ActiveControl := RenderPanel;
5806 // Язык:
5807 if gLanguage = '' then
5808 begin
5809 lang := SelectLanguageForm.ShowModal();
5810 case lang of
5811 1: gLanguage := LANGUAGE_ENGLISH;
5812 else gLanguage := LANGUAGE_RUSSIAN;
5813 end;
5815 config := TConfig.CreateFile(EditorDir+'Editor.cfg');
5816 config.WriteStr('Editor', 'Language', gLanguage);
5817 config.SaveFile(EditorDir+'Editor.cfg');
5818 config.Free();
5819 end;
5821 //e_WriteLog('Read language file', MSG_NOTIFY);
5822 //g_Language_Load(EditorDir+'\data\'+gLanguage+LANGUAGE_FILE_NAME);
5823 g_Language_Set(gLanguage);
5824 end;
5826 procedure TMainForm.aDeleteMap(Sender: TObject);
5827 var
5828 WAD: TWADEditor_1;
5829 MapList: SArray;
5830 MapName: Char16;
5831 a: Integer;
5832 str: String;
5833 begin
5834 OpenDialog.Filter := _lc[I_FILE_FILTER_WAD];
5836 if not OpenDialog.Execute() then
5837 Exit;
5839 WAD := TWADEditor_1.Create();
5841 if not WAD.ReadFile(OpenDialog.FileName) then
5842 begin
5843 WAD.Free();
5844 Exit;
5845 end;
5847 WAD.CreateImage();
5849 MapList := WAD.GetResourcesList('');
5851 SelectMapForm.lbMapList.Items.Clear();
5853 if MapList <> nil then
5854 for a := 0 to High(MapList) do
5855 SelectMapForm.lbMapList.Items.Add(MapList[a]);
5857 if (SelectMapForm.ShowModal() = mrOK) then
5858 begin
5859 str := SelectMapForm.lbMapList.Items[SelectMapForm.lbMapList.ItemIndex];
5860 MapName := '';
5861 Move(MapName[0], str[1], Min(16, Length(str)));
5863 if MessageBox(0, PChar(Format(_lc[I_MSG_DELETE_MAP_PROMT],
5864 [MapName, OpenDialog.FileName])),
5865 PChar(_lc[I_MSG_DELETE_MAP]),
5866 MB_ICONQUESTION or MB_YESNO or
5867 MB_DEFBUTTON2) <> mrYes then
5868 Exit;
5870 WAD.RemoveResource('', MapName);
5872 MessageBox(0, PChar(Format(_lc[I_MSG_MAP_DELETED_PROMT],
5873 [MapName])),
5874 PChar(_lc[I_MSG_MAP_DELETED]),
5875 MB_ICONINFORMATION or MB_OK or
5876 MB_DEFBUTTON1);
5878 WAD.SaveTo(OpenDialog.FileName);
5880 // Удалили текущую карту - сохранять по старому ее нельзя:
5881 if OpenedMap = (OpenDialog.FileName+':\'+MapName) then
5882 begin
5883 OpenedMap := '';
5884 OpenedWAD := '';
5885 MainForm.Caption := FormCaption;
5886 end;
5887 end;
5889 WAD.Free();
5890 end;
5892 procedure TMainForm.vleObjectPropertyKeyDown(Sender: TObject;
5893 var Key: Word; Shift: TShiftState);
5894 begin
5895 if Key = VK_RETURN then
5896 bApplyProperty.Click();
5897 end;
5899 procedure MovePanel(var ID: DWORD; MoveType: Byte);
5900 var
5901 _id, a: Integer;
5902 tmp: TPanel;
5903 begin
5904 if (ID = 0) and (MoveType = 0) then
5905 Exit;
5906 if (ID = DWORD(High(gPanels))) and (MoveType <> 0) then
5907 Exit;
5908 if (ID > DWORD(High(gPanels))) then
5909 Exit;
5911 _id := Integer(ID);
5913 if MoveType = 0 then // to Back
5914 begin
5915 if gTriggers <> nil then
5916 for a := 0 to High(gTriggers) do
5917 with gTriggers[a] do
5918 begin
5919 if TriggerType = TRIGGER_NONE then
5920 Continue;
5922 if TexturePanel = _id then
5923 TexturePanel := 0
5924 else
5925 if (TexturePanel >= 0) and (TexturePanel < _id) then
5926 Inc(TexturePanel);
5928 case TriggerType of
5929 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
5930 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP,
5931 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
5932 if Data.PanelID = _id then
5933 Data.PanelID := 0
5934 else
5935 if (Data.PanelID >= 0) and (Data.PanelID < _id) then
5936 Inc(Data.PanelID);
5938 TRIGGER_SHOT:
5939 if Data.ShotPanelID = _id then
5940 Data.ShotPanelID := 0
5941 else
5942 if (Data.ShotPanelID >= 0) and (Data.ShotPanelID < _id) then
5943 Inc(Data.ShotPanelID);
5944 end;
5945 end;
5947 tmp := gPanels[_id];
5949 for a := _id downto 1 do
5950 gPanels[a] := gPanels[a-1];
5952 gPanels[0] := tmp;
5954 ID := 0;
5955 end
5956 else // to Front
5957 begin
5958 if gTriggers <> nil then
5959 for a := 0 to High(gTriggers) do
5960 with gTriggers[a] do
5961 begin
5962 if TriggerType = TRIGGER_NONE then
5963 Continue;
5965 if TexturePanel = _id then
5966 TexturePanel := High(gPanels)
5967 else
5968 if TexturePanel > _id then
5969 Dec(TexturePanel);
5971 case TriggerType of
5972 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
5973 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP,
5974 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
5975 if Data.PanelID = _id then
5976 Data.PanelID := High(gPanels)
5977 else
5978 if Data.PanelID > _id then
5979 Dec(Data.PanelID);
5981 TRIGGER_SHOT:
5982 if Data.ShotPanelID = _id then
5983 Data.ShotPanelID := High(gPanels)
5984 else
5985 if Data.ShotPanelID > _id then
5986 Dec(Data.ShotPanelID);
5987 end;
5988 end;
5990 tmp := gPanels[_id];
5992 for a := _id to High(gPanels)-1 do
5993 gPanels[a] := gPanels[a+1];
5995 gPanels[High(gPanels)] := tmp;
5997 ID := High(gPanels);
5998 end;
5999 end;
6001 procedure TMainForm.aMoveToBack(Sender: TObject);
6002 var
6003 a: Integer;
6004 begin
6005 if SelectedObjects = nil then
6006 Exit;
6008 for a := 0 to High(SelectedObjects) do
6009 with SelectedObjects[a] do
6010 if Live and (ObjectType = OBJECT_PANEL) then
6011 begin
6012 SelectedObjects[0] := SelectedObjects[a];
6013 SetLength(SelectedObjects, 1);
6014 MovePanel(ID, 0);
6015 FillProperty();
6016 Break;
6017 end;
6018 end;
6020 procedure TMainForm.aMoveToFore(Sender: TObject);
6021 var
6022 a: Integer;
6023 begin
6024 if SelectedObjects = nil then
6025 Exit;
6027 for a := 0 to High(SelectedObjects) do
6028 with SelectedObjects[a] do
6029 if Live and (ObjectType = OBJECT_PANEL) then
6030 begin
6031 SelectedObjects[0] := SelectedObjects[a];
6032 SetLength(SelectedObjects, 1);
6033 MovePanel(ID, 1);
6034 FillProperty();
6035 Break;
6036 end;
6037 end;
6039 procedure TMainForm.aSaveMapAsExecute(Sender: TObject);
6040 var
6041 idx: Integer;
6042 begin
6043 SaveDialog.Filter := _lc[I_FILE_FILTER_WAD];
6045 if not SaveDialog.Execute() then
6046 Exit;
6048 SaveMapForm.GetMaps(SaveDialog.FileName, True);
6050 if SaveMapForm.ShowModal() <> mrOK then
6051 Exit;
6053 SaveDialog.InitialDir := ExtractFileDir(SaveDialog.FileName);
6054 OpenedMap := SaveDialog.FileName+':\'+SaveMapForm.eMapName.Text;
6055 OpenedWAD := SaveDialog.FileName;
6057 idx := RecentFiles.IndexOf(OpenedMap);
6058 // Такая карта уже недавно открывалась:
6059 if idx >= 0 then
6060 RecentFiles.Delete(idx);
6061 RecentFiles.Insert(0, OpenedMap);
6062 RefreshRecentMenu;
6064 SaveMap(OpenedMap);
6066 gMapInfo.FileName := SaveDialog.FileName;
6067 gMapInfo.MapName := SaveMapForm.eMapName.Text;
6068 UpdateCaption(win2utf(gMapInfo.Name), ExtractFileName(gMapInfo.FileName), gMapInfo.MapName);
6069 end;
6071 procedure TMainForm.aSelectAllExecute(Sender: TObject);
6072 var
6073 a: Integer;
6074 begin
6075 RemoveSelectFromObjects();
6077 case pcObjects.ActivePageIndex+1 of
6078 OBJECT_PANEL:
6079 if gPanels <> nil then
6080 for a := 0 to High(gPanels) do
6081 if gPanels[a].PanelType <> PANEL_NONE then
6082 SelectObject(OBJECT_PANEL, a, True);
6083 OBJECT_ITEM:
6084 if gItems <> nil then
6085 for a := 0 to High(gItems) do
6086 if gItems[a].ItemType <> ITEM_NONE then
6087 SelectObject(OBJECT_ITEM, a, True);
6088 OBJECT_MONSTER:
6089 if gMonsters <> nil then
6090 for a := 0 to High(gMonsters) do
6091 if gMonsters[a].MonsterType <> MONSTER_NONE then
6092 SelectObject(OBJECT_MONSTER, a, True);
6093 OBJECT_AREA:
6094 if gAreas <> nil then
6095 for a := 0 to High(gAreas) do
6096 if gAreas[a].AreaType <> AREA_NONE then
6097 SelectObject(OBJECT_AREA, a, True);
6098 OBJECT_TRIGGER:
6099 if gTriggers <> nil then
6100 for a := 0 to High(gTriggers) do
6101 if gTriggers[a].TriggerType <> TRIGGER_NONE then
6102 SelectObject(OBJECT_TRIGGER, a, True);
6103 end;
6104 end;
6106 procedure TMainForm.tbGridOnClick(Sender: TObject);
6107 begin
6108 DotEnable := not DotEnable;
6109 (Sender as TToolButton).Down := DotEnable;
6110 end;
6112 procedure TMainForm.OnIdle(Sender: TObject; var Done: Boolean);
6113 begin
6114 // FIXME: this is a shitty hack
6115 if not gDataLoaded then
6116 begin
6117 e_WriteLog('Init OpenGL', MSG_NOTIFY);
6118 e_InitGL();
6119 e_WriteLog('Loading data', MSG_NOTIFY);
6120 LoadStdFont('STDTXT', 'STDFONT', gEditorFont);
6121 e_WriteLog('Loading more data', MSG_NOTIFY);
6122 LoadData();
6123 e_WriteLog('Loading even more data', MSG_NOTIFY);
6124 gDataLoaded := True;
6125 MainForm.FormResize(nil);
6126 end;
6127 Draw();
6128 end;
6130 procedure TMainForm.miMapPreviewClick(Sender: TObject);
6131 begin
6132 if not PreviewMode then
6133 begin
6134 Splitter2.Visible := False;
6135 Splitter1.Visible := False;
6136 StatusBar.Visible := False;
6137 PanelObjs.Visible := False;
6138 PanelProps.Visible := False;
6139 MainToolBar.Visible := False;
6140 sbHorizontal.Visible := False;
6141 sbVertical.Visible := False;
6142 end
6143 else
6144 begin
6145 StatusBar.Visible := True;
6146 PanelObjs.Visible := True;
6147 PanelProps.Visible := True;
6148 Splitter2.Visible := True;
6149 Splitter1.Visible := True;
6150 MainToolBar.Visible := True;
6151 sbHorizontal.Visible := True;
6152 sbVertical.Visible := True;
6153 end;
6155 PreviewMode := not PreviewMode;
6156 (Sender as TMenuItem).Checked := PreviewMode;
6158 FormResize(Self);
6159 end;
6161 procedure TMainForm.miLayer1Click(Sender: TObject);
6162 begin
6163 SwitchLayer(LAYER_BACK);
6164 end;
6166 procedure TMainForm.miLayer2Click(Sender: TObject);
6167 begin
6168 SwitchLayer(LAYER_WALLS);
6169 end;
6171 procedure TMainForm.miLayer3Click(Sender: TObject);
6172 begin
6173 SwitchLayer(LAYER_FOREGROUND);
6174 end;
6176 procedure TMainForm.miLayer4Click(Sender: TObject);
6177 begin
6178 SwitchLayer(LAYER_STEPS);
6179 end;
6181 procedure TMainForm.miLayer5Click(Sender: TObject);
6182 begin
6183 SwitchLayer(LAYER_WATER);
6184 end;
6186 procedure TMainForm.miLayer6Click(Sender: TObject);
6187 begin
6188 SwitchLayer(LAYER_ITEMS);
6189 end;
6191 procedure TMainForm.miLayer7Click(Sender: TObject);
6192 begin
6193 SwitchLayer(LAYER_MONSTERS);
6194 end;
6196 procedure TMainForm.miLayer8Click(Sender: TObject);
6197 begin
6198 SwitchLayer(LAYER_AREAS);
6199 end;
6201 procedure TMainForm.miLayer9Click(Sender: TObject);
6202 begin
6203 SwitchLayer(LAYER_TRIGGERS);
6204 end;
6206 procedure TMainForm.tbShowClick(Sender: TObject);
6207 var
6208 a: Integer;
6209 b: Boolean;
6210 begin
6211 b := True;
6212 for a := 0 to High(LayerEnabled) do
6213 b := b and LayerEnabled[a];
6215 b := not b;
6217 ShowLayer(LAYER_BACK, b);
6218 ShowLayer(LAYER_WALLS, b);
6219 ShowLayer(LAYER_FOREGROUND, b);
6220 ShowLayer(LAYER_STEPS, b);
6221 ShowLayer(LAYER_WATER, b);
6222 ShowLayer(LAYER_ITEMS, b);
6223 ShowLayer(LAYER_MONSTERS, b);
6224 ShowLayer(LAYER_AREAS, b);
6225 ShowLayer(LAYER_TRIGGERS, b);
6226 end;
6228 procedure TMainForm.miMiniMapClick(Sender: TObject);
6229 begin
6230 SwitchMap();
6231 end;
6233 procedure TMainForm.miSwitchGridClick(Sender: TObject);
6234 begin
6235 if DotStep = DotStepOne then
6236 DotStep := DotStepTwo
6237 else
6238 DotStep := DotStepOne;
6240 MousePos.X := (MousePos.X div DotStep) * DotStep;
6241 MousePos.Y := (MousePos.Y div DotStep) * DotStep;
6242 end;
6244 procedure TMainForm.miShowEdgesClick(Sender: TObject);
6245 begin
6246 ShowEdges();
6247 end;
6249 procedure TMainForm.miSnapToGridClick(Sender: TObject);
6250 begin
6251 SnapToGrid := not SnapToGrid;
6253 MousePos.X := (MousePos.X div DotStep) * DotStep;
6254 MousePos.Y := (MousePos.Y div DotStep) * DotStep;
6256 miSnapToGrid.Checked := SnapToGrid;
6257 end;
6259 procedure TMainForm.minexttabClick(Sender: TObject);
6260 begin
6261 if pcObjects.ActivePageIndex < pcObjects.PageCount-1 then
6262 pcObjects.ActivePageIndex := pcObjects.ActivePageIndex+1
6263 else
6264 pcObjects.ActivePageIndex := 0;
6265 end;
6267 procedure TMainForm.miSaveMiniMapClick(Sender: TObject);
6268 begin
6269 SaveMiniMapForm.ShowModal();
6270 end;
6272 procedure TMainForm.bClearTextureClick(Sender: TObject);
6273 begin
6274 lbTextureList.ItemIndex := -1;
6275 lTextureWidth.Caption := '';
6276 lTextureHeight.Caption := '';
6277 end;
6279 procedure TMainForm.miPackMapClick(Sender: TObject);
6280 begin
6281 PackMapForm.ShowModal();
6282 end;
6284 procedure TMainForm.miMapTestSettingsClick(Sender: TObject);
6285 begin
6286 MapTestForm.ShowModal();
6287 end;
6289 procedure TMainForm.miTestMapClick(Sender: TObject);
6290 var
6291 cmd, mapWAD, mapToRun, tempWAD: String;
6292 opt: LongWord;
6293 time: Integer;
6294 proc: TProcessUTF8;
6295 res: Boolean;
6296 begin
6297 mapToRun := '';
6298 if OpenedMap <> '' then
6299 begin
6300 // Указываем текущую карту для теста:
6301 g_ProcessResourceStr(OpenedMap, @mapWAD, nil, @mapToRun);
6302 mapToRun := mapWAD + ':\' + mapToRun;
6303 mapToRun := ExtractRelativePath(ExtractFilePath(TestD2dExe) + 'maps/', mapToRun);
6304 end;
6305 // Сохраняем временную карту:
6306 time := 0;
6307 repeat
6308 mapWAD := ExtractFilePath(TestD2dExe) + Format('maps/temp%.4d.wad', [time]);
6309 Inc(time);
6310 until not FileExists(mapWAD);
6311 tempWAD := mapWAD + ':\' + TEST_MAP_NAME;
6312 SaveMap(tempWAD);
6314 tempWAD := ExtractRelativePath(ExtractFilePath(TestD2dExe) + 'maps/', tempWAD);
6315 // Если карта не была открыта, указываем временную в качестве текущей:
6316 if mapToRun = '' then
6317 mapToRun := tempWAD;
6319 // Опции игры:
6320 opt := 32 + 64;
6321 if TestOptionsTwoPlayers then
6322 opt := opt + 1;
6323 if TestOptionsTeamDamage then
6324 opt := opt + 2;
6325 if TestOptionsAllowExit then
6326 opt := opt + 4;
6327 if TestOptionsWeaponStay then
6328 opt := opt + 8;
6329 if TestOptionsMonstersDM then
6330 opt := opt + 16;
6332 // Составляем командную строку:
6333 cmd := '-map "' + mapToRun + '"';
6334 cmd := cmd + ' -testmap "' + tempWAD + '"';
6335 cmd := cmd + ' -gm ' + TestGameMode;
6336 cmd := cmd + ' -limt ' + TestLimTime;
6337 cmd := cmd + ' -lims ' + TestLimScore;
6338 cmd := cmd + ' -opt ' + IntToStr(opt);
6340 if TestMapOnce then
6341 cmd := cmd + ' --close';
6343 cmd := cmd + ' --debug';
6345 // Запускаем:
6346 proc := TProcessUTF8.Create(nil);
6347 proc.Executable := TestD2dExe;
6348 proc.Parameters.Add(cmd);
6349 res := True;
6350 try
6351 proc.Execute();
6352 except
6353 res := False;
6354 end;
6355 if res then
6356 begin
6357 Application.Minimize();
6358 proc.WaitOnExit();
6359 end;
6360 if (not res) or (proc.ExitCode < 0) then
6361 begin
6362 MessageBox(0, 'FIXME',
6363 PChar(_lc[I_MSG_EXEC_ERROR]),
6364 MB_OK or MB_ICONERROR);
6365 end;
6366 proc.Free();
6368 SysUtils.DeleteFile(mapWAD);
6369 Application.Restore();
6370 end;
6372 procedure TMainForm.sbVerticalScroll(Sender: TObject;
6373 ScrollCode: TScrollCode; var ScrollPos: Integer);
6374 begin
6375 MapOffset.Y := -Normalize16(sbVertical.Position);
6376 end;
6378 procedure TMainForm.sbHorizontalScroll(Sender: TObject;
6379 ScrollCode: TScrollCode; var ScrollPos: Integer);
6380 begin
6381 MapOffset.X := -Normalize16(sbHorizontal.Position);
6382 end;
6384 procedure TMainForm.miOpenWadMapClick(Sender: TObject);
6385 begin
6386 if OpenedWAD <> '' then
6387 begin
6388 OpenMap(OpenedWAD, '');
6389 end;
6390 end;
6392 procedure TMainForm.selectall1Click(Sender: TObject);
6393 var
6394 a: Integer;
6395 begin
6396 RemoveSelectFromObjects();
6398 if gPanels <> nil then
6399 for a := 0 to High(gPanels) do
6400 if gPanels[a].PanelType <> PANEL_NONE then
6401 SelectObject(OBJECT_PANEL, a, True);
6403 if gItems <> nil then
6404 for a := 0 to High(gItems) do
6405 if gItems[a].ItemType <> ITEM_NONE then
6406 SelectObject(OBJECT_ITEM, a, True);
6408 if gMonsters <> nil then
6409 for a := 0 to High(gMonsters) do
6410 if gMonsters[a].MonsterType <> MONSTER_NONE then
6411 SelectObject(OBJECT_MONSTER, a, True);
6413 if gAreas <> nil then
6414 for a := 0 to High(gAreas) do
6415 if gAreas[a].AreaType <> AREA_NONE then
6416 SelectObject(OBJECT_AREA, a, True);
6418 if gTriggers <> nil then
6419 for a := 0 to High(gTriggers) do
6420 if gTriggers[a].TriggerType <> TRIGGER_NONE then
6421 SelectObject(OBJECT_TRIGGER, a, True);
6422 end;
6424 procedure TMainForm.Splitter1CanResize(Sender: TObject;
6425 var NewSize: Integer; var Accept: Boolean);
6426 begin
6427 Accept := (NewSize > 140);
6428 end;
6430 procedure TMainForm.Splitter2CanResize(Sender: TObject;
6431 var NewSize: Integer; var Accept: Boolean);
6432 begin
6433 Accept := (NewSize > 110);
6434 end;
6436 procedure TMainForm.vleObjectPropertyEnter(Sender: TObject);
6437 begin
6438 EditingProperties := True;
6439 end;
6441 procedure TMainForm.vleObjectPropertyExit(Sender: TObject);
6442 begin
6443 EditingProperties := False;
6444 end;
6446 procedure TMainForm.FormKeyUp(Sender: TObject; var Key: Word;
6447 Shift: TShiftState);
6448 begin
6449 // Объекты передвигались:
6450 if MainForm.ActiveControl = RenderPanel then
6451 begin
6452 if (Key = VK_NUMPAD4) or
6453 (Key = VK_NUMPAD6) or
6454 (Key = VK_NUMPAD8) or
6455 (Key = VK_NUMPAD5) or
6456 (Key = Ord('V')) then
6457 FillProperty();
6458 end;
6459 end;
6461 end.