DEADSOFTWARE

8158c03344f380660a7de069841ce8357aedb984
[d2df-editor.git] / src / editor / f_main.pas
1 unit f_main;
3 {$INCLUDE ../shared/a_modes.inc}
5 interface
7 uses
8 LCLIntf, LCLType, SysUtils, Variants, Classes, Graphics,
9 Controls, Forms, Dialogs, StdCtrls, Buttons,
10 ComCtrls, ValEdit, Types, Menus, ExtCtrls,
11 CheckLst, Grids, OpenGLContext, utils, UTF8Process;
13 type
15 { TMainForm }
17 TMainForm = class(TForm)
18 lLoad: TLabel;
19 // Главное меню:
20 MainMenu: TMainMenu;
21 // "Файл":
22 miMenuFile: TMenuItem;
23 miNewMap: TMenuItem;
24 miOpenMap: TMenuItem;
25 miSaveMap: TMenuItem;
26 miSaveMapAs: TMenuItem;
27 miOpenWadMap: TMenuItem;
28 miLine1: TMenuItem;
29 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 Splitter1Moved(Sender: TObject);
218 procedure vleObjectPropertyEditButtonClick(Sender: TObject);
219 procedure vleObjectPropertyApply(Sender: TObject);
220 procedure vleObjectPropertyGetPickList(Sender: TObject; const KeyName: String; Values: TStrings);
221 procedure vleObjectPropertyKeyDown(Sender: TObject; var Key: Word;
222 Shift: TShiftState);
223 procedure tbGridOnClick(Sender: TObject);
224 procedure miMapPreviewClick(Sender: TObject);
225 procedure miLayer1Click(Sender: TObject);
226 procedure miLayer2Click(Sender: TObject);
227 procedure miLayer3Click(Sender: TObject);
228 procedure miLayer4Click(Sender: TObject);
229 procedure miLayer5Click(Sender: TObject);
230 procedure miLayer6Click(Sender: TObject);
231 procedure miLayer7Click(Sender: TObject);
232 procedure miLayer8Click(Sender: TObject);
233 procedure miLayer9Click(Sender: TObject);
234 procedure tbShowClick(Sender: TObject);
235 procedure miSnapToGridClick(Sender: TObject);
236 procedure miMiniMapClick(Sender: TObject);
237 procedure miSwitchGridClick(Sender: TObject);
238 procedure miShowEdgesClick(Sender: TObject);
239 procedure minexttabClick(Sender: TObject);
240 procedure miSaveMiniMapClick(Sender: TObject);
241 procedure bClearTextureClick(Sender: TObject);
242 procedure miPackMapClick(Sender: TObject);
243 procedure aRecentFileExecute(Sender: TObject);
244 procedure miMapTestSettingsClick(Sender: TObject);
245 procedure miTestMapClick(Sender: TObject);
246 procedure sbVerticalScroll(Sender: TObject; ScrollCode: TScrollCode;
247 var ScrollPos: Integer);
248 procedure sbHorizontalScroll(Sender: TObject; ScrollCode: TScrollCode;
249 var ScrollPos: Integer);
250 procedure miOpenWadMapClick(Sender: TObject);
251 procedure selectall1Click(Sender: TObject);
252 procedure Splitter1CanResize(Sender: TObject; var NewSize: Integer;
253 var Accept: Boolean);
254 procedure Splitter2CanResize(Sender: TObject; var NewSize: Integer;
255 var Accept: Boolean);
256 procedure vleObjectPropertyEnter(Sender: TObject);
257 procedure vleObjectPropertyExit(Sender: TObject);
258 procedure FormKeyUp(Sender: TObject; var Key: Word;
259 Shift: TShiftState);
260 private
261 procedure Draw();
262 procedure OnIdle(Sender: TObject; var Done: Boolean);
263 public
264 procedure RefreshRecentMenu();
265 end;
267 const
268 LAYER_BACK = 0;
269 LAYER_WALLS = 1;
270 LAYER_FOREGROUND = 2;
271 LAYER_STEPS = 3;
272 LAYER_WATER = 4;
273 LAYER_ITEMS = 5;
274 LAYER_MONSTERS = 6;
275 LAYER_AREAS = 7;
276 LAYER_TRIGGERS = 8;
278 TEST_MAP_NAME = '$$$_TEST_$$$';
279 LANGUAGE_FILE_NAME = '_Editor.txt';
281 var
282 MainForm: TMainForm;
283 EditorDir: String;
284 OpenedMap: String;
285 OpenedWAD: String;
287 DotColor: TColor;
288 DotEnable: Boolean;
289 DotStep: Byte;
290 DotStepOne, DotStepTwo: Byte;
291 DotSize: Byte;
292 DrawTexturePanel: Boolean;
293 DrawPanelSize: Boolean;
294 BackColor: TColor;
295 PreviewColor: TColor;
296 Scale: Byte;
297 RecentCount: Integer;
298 RecentFiles: TStringList;
299 slInvalidTextures: TStringList;
301 TestGameMode: String;
302 TestLimTime: String;
303 TestLimScore: String;
304 TestOptionsTwoPlayers: Boolean;
305 TestOptionsTeamDamage: Boolean;
306 TestOptionsAllowExit: Boolean;
307 TestOptionsWeaponStay: Boolean;
308 TestOptionsMonstersDM: Boolean;
309 TestD2dExe: String;
310 TestMapOnce: Boolean;
312 LayerEnabled: Array [LAYER_BACK..LAYER_TRIGGERS] of Boolean =
313 (True, True, True, True, True, True, True, True, True);
314 PreviewMode: Byte = 0;
315 gLanguage: String;
317 FormCaption: String;
320 procedure OpenMap(FileName: String; mapN: String);
321 function AddTexture(aWAD, aSection, aTex: String; silent: Boolean): Boolean;
322 procedure RemoveSelectFromObjects();
323 procedure ChangeShownProperty(Name: String; NewValue: String);
325 implementation
327 uses
328 f_options, e_graphics, e_log, GL, Math,
329 f_mapoptions, g_basic, f_about, f_mapoptimization,
330 f_mapcheck, f_addresource_texture, g_textures,
331 f_activationtype, f_keys,
332 MAPREADER, f_selectmap, f_savemap, WADEDITOR, WADSTRUCT, MAPDEF,
333 g_map, f_saveminimap, f_addresource, CONFIG, f_packmap,
334 f_addresource_sound, f_maptest, f_choosetype,
335 g_language, f_selectlang, ClipBrd;
337 const
338 UNDO_DELETE_PANEL = 1;
339 UNDO_DELETE_ITEM = 2;
340 UNDO_DELETE_AREA = 3;
341 UNDO_DELETE_MONSTER = 4;
342 UNDO_DELETE_TRIGGER = 5;
343 UNDO_ADD_PANEL = 6;
344 UNDO_ADD_ITEM = 7;
345 UNDO_ADD_AREA = 8;
346 UNDO_ADD_MONSTER = 9;
347 UNDO_ADD_TRIGGER = 10;
348 UNDO_MOVE_PANEL = 11;
349 UNDO_MOVE_ITEM = 12;
350 UNDO_MOVE_AREA = 13;
351 UNDO_MOVE_MONSTER = 14;
352 UNDO_MOVE_TRIGGER = 15;
353 UNDO_RESIZE_PANEL = 16;
354 UNDO_RESIZE_TRIGGER = 17;
356 MOUSEACTION_NONE = 0;
357 MOUSEACTION_DRAWPANEL = 1;
358 MOUSEACTION_DRAWTRIGGER = 2;
359 MOUSEACTION_MOVEOBJ = 3;
360 MOUSEACTION_RESIZE = 4;
361 MOUSEACTION_MOVEMAP = 5;
362 MOUSEACTION_DRAWPRESS = 6;
363 MOUSEACTION_NOACTION = 7;
365 RESIZETYPE_NONE = 0;
366 RESIZETYPE_VERTICAL = 1;
367 RESIZETYPE_HORIZONTAL = 2;
369 RESIZEDIR_NONE = 0;
370 RESIZEDIR_DOWN = 1;
371 RESIZEDIR_UP = 2;
372 RESIZEDIR_RIGHT = 3;
373 RESIZEDIR_LEFT = 4;
375 SELECTFLAG_NONE = 0;
376 SELECTFLAG_TELEPORT = 1;
377 SELECTFLAG_DOOR = 2;
378 SELECTFLAG_TEXTURE = 3;
379 SELECTFLAG_LIFT = 4;
380 SELECTFLAG_MONSTER = 5;
381 SELECTFLAG_SPAWNPOINT = 6;
382 SELECTFLAG_SHOTPANEL = 7;
383 SELECTFLAG_SELECTED = 8;
385 RECENT_FILES_MENU_START = 11;
387 CLIPBOARD_SIG = 'DF:ED';
389 type
390 TUndoRec = record
391 UndoType: Byte;
392 case Byte of
393 UNDO_DELETE_PANEL: (Panel: ^TPanel);
394 UNDO_DELETE_ITEM: (Item: TItem);
395 UNDO_DELETE_AREA: (Area: TArea);
396 UNDO_DELETE_MONSTER: (Monster: TMonster);
397 UNDO_DELETE_TRIGGER: (Trigger: TTrigger);
398 UNDO_ADD_PANEL,
399 UNDO_ADD_ITEM,
400 UNDO_ADD_AREA,
401 UNDO_ADD_MONSTER,
402 UNDO_ADD_TRIGGER: (AddID: DWORD);
403 UNDO_MOVE_PANEL,
404 UNDO_MOVE_ITEM,
405 UNDO_MOVE_AREA,
406 UNDO_MOVE_MONSTER,
407 UNDO_MOVE_TRIGGER: (MoveID: DWORD; dX, dY: Integer);
408 UNDO_RESIZE_PANEL,
409 UNDO_RESIZE_TRIGGER: (ResizeID: DWORD; dW, dH: Integer);
410 end;
412 TCopyRec = record
413 ObjectType: Byte;
414 ID: Cardinal;
415 case Byte of
416 OBJECT_PANEL: (Panel: ^TPanel);
417 OBJECT_ITEM: (Item: TItem);
418 OBJECT_AREA: (Area: TArea);
419 OBJECT_MONSTER: (Monster: TMonster);
420 OBJECT_TRIGGER: (Trigger: TTrigger);
421 end;
423 TCopyRecArray = Array of TCopyRec;
425 var
426 gEditorFont: DWORD;
427 gDataLoaded: Boolean = False;
428 ShowMap: Boolean = False;
429 DrawRect: PRect = nil;
430 SnapToGrid: Boolean = True;
432 MousePos: Types.TPoint;
433 LastMovePoint: Types.TPoint;
434 MouseLDown: Boolean;
435 MouseRDown: Boolean;
436 MouseLDownPos: Types.TPoint;
437 MouseRDownPos: Types.TPoint;
439 SelectFlag: Byte = SELECTFLAG_NONE;
440 MouseAction: Byte = MOUSEACTION_NONE;
441 ResizeType: Byte = RESIZETYPE_NONE;
442 ResizeDirection: Byte = RESIZEDIR_NONE;
444 DrawPressRect: Boolean = False;
445 EditingProperties: Boolean = False;
447 UndoBuffer: Array of Array of TUndoRec = nil;
450 {$R *.lfm}
452 //----------------------------------------
453 //Далее идут вспомогательные процедуры
454 //----------------------------------------
456 function NameToBool(Name: String): Boolean;
457 begin
458 if Name = BoolNames[True] then
459 Result := True
460 else
461 Result := False;
462 end;
464 function NameToDir(Name: String): TDirection;
465 begin
466 if Name = DirNames[D_LEFT] then
467 Result := D_LEFT
468 else
469 Result := D_RIGHT;
470 end;
472 function NameToDirAdv(Name: String): Byte;
473 begin
474 if Name = DirNamesAdv[1] then
475 Result := 1
476 else
477 if Name = DirNamesAdv[2] then
478 Result := 2
479 else
480 if Name = DirNamesAdv[3] then
481 Result := 3
482 else
483 Result := 0;
484 end;
486 function ActivateToStr(ActivateType: Byte): String;
487 begin
488 Result := '';
490 if ByteBool(ACTIVATE_PLAYERCOLLIDE and ActivateType) then
491 Result := Result + '+PC';
492 if ByteBool(ACTIVATE_MONSTERCOLLIDE and ActivateType) then
493 Result := Result + '+MC';
494 if ByteBool(ACTIVATE_PLAYERPRESS and ActivateType) then
495 Result := Result + '+PP';
496 if ByteBool(ACTIVATE_MONSTERPRESS and ActivateType) then
497 Result := Result + '+MP';
498 if ByteBool(ACTIVATE_SHOT and ActivateType) then
499 Result := Result + '+SH';
500 if ByteBool(ACTIVATE_NOMONSTER and ActivateType) then
501 Result := Result + '+NM';
503 if (Result <> '') and (Result[1] = '+') then
504 Delete(Result, 1, 1);
505 end;
507 function StrToActivate(Str: String): Byte;
508 begin
509 Result := 0;
511 if Pos('PC', Str) > 0 then
512 Result := ACTIVATE_PLAYERCOLLIDE;
513 if Pos('MC', Str) > 0 then
514 Result := Result or ACTIVATE_MONSTERCOLLIDE;
515 if Pos('PP', Str) > 0 then
516 Result := Result or ACTIVATE_PLAYERPRESS;
517 if Pos('MP', Str) > 0 then
518 Result := Result or ACTIVATE_MONSTERPRESS;
519 if Pos('SH', Str) > 0 then
520 Result := Result or ACTIVATE_SHOT;
521 if Pos('NM', Str) > 0 then
522 Result := Result or ACTIVATE_NOMONSTER;
523 end;
525 function KeyToStr(Key: Byte): String;
526 begin
527 Result := '';
529 if ByteBool(KEY_RED and Key) then
530 Result := Result + '+RK';
531 if ByteBool(KEY_GREEN and Key) then
532 Result := Result + '+GK';
533 if ByteBool(KEY_BLUE and Key) then
534 Result := Result + '+BK';
535 if ByteBool(KEY_REDTEAM and Key) then
536 Result := Result + '+RT';
537 if ByteBool(KEY_BLUETEAM and Key) then
538 Result := Result + '+BT';
540 if (Result <> '') and (Result[1] = '+') then
541 Delete(Result, 1, 1);
542 end;
544 function StrToKey(Str: String): Byte;
545 begin
546 Result := 0;
548 if Pos('RK', Str) > 0 then
549 Result := KEY_RED;
550 if Pos('GK', Str) > 0 then
551 Result := Result or KEY_GREEN;
552 if Pos('BK', Str) > 0 then
553 Result := Result or KEY_BLUE;
554 if Pos('RT', Str) > 0 then
555 Result := Result or KEY_REDTEAM;
556 if Pos('BT', Str) > 0 then
557 Result := Result or KEY_BLUETEAM;
558 end;
560 function EffectToStr(Effect: Byte): String;
561 begin
562 if Effect in [EFFECT_TELEPORT..EFFECT_FIRE] then
563 Result := EffectNames[Effect]
564 else
565 Result := EffectNames[EFFECT_NONE];
566 end;
568 function StrToEffect(Str: String): Byte;
569 var
570 i: Integer;
571 begin
572 Result := EFFECT_NONE;
573 for i := EFFECT_TELEPORT to EFFECT_FIRE do
574 if EffectNames[i] = Str then
575 begin
576 Result := i;
577 Exit;
578 end;
579 end;
581 function MonsterToStr(MonType: Byte): String;
582 begin
583 if MonType in [MONSTER_DEMON..MONSTER_MAN] then
584 Result := MonsterNames[MonType]
585 else
586 Result := MonsterNames[MONSTER_ZOMBY];
587 end;
589 function StrToMonster(Str: String): Byte;
590 var
591 i: Integer;
592 begin
593 Result := MONSTER_ZOMBY;
594 for i := MONSTER_DEMON to MONSTER_MAN do
595 if MonsterNames[i] = Str then
596 begin
597 Result := i;
598 Exit;
599 end;
600 end;
602 function ItemToStr(ItemType: Byte): String;
603 begin
604 if ItemType in [ITEM_MEDKIT_SMALL..ITEM_MAX] then
605 Result := ItemNames[ItemType]
606 else
607 Result := ItemNames[ITEM_AMMO_BULLETS];
608 end;
610 function StrToItem(Str: String): Byte;
611 var
612 i: Integer;
613 begin
614 Result := ITEM_AMMO_BULLETS;
615 for i := ITEM_MEDKIT_SMALL to ITEM_MAX do
616 if ItemNames[i] = Str then
617 begin
618 Result := i;
619 Exit;
620 end;
621 end;
623 function ShotToStr(ShotType: Byte): String;
624 begin
625 if ShotType in [TRIGGER_SHOT_PISTOL..TRIGGER_SHOT_MAX] then
626 Result := ShotNames[ShotType]
627 else
628 Result := ShotNames[TRIGGER_SHOT_PISTOL];
629 end;
631 function StrToShot(Str: String): Byte;
632 var
633 i: Integer;
634 begin
635 Result := TRIGGER_SHOT_PISTOL;
636 for i := TRIGGER_SHOT_PISTOL to TRIGGER_SHOT_MAX do
637 if ShotNames[i] = Str then
638 begin
639 Result := i;
640 Exit;
641 end;
642 end;
644 function SelectedObjectCount(): Word;
645 var
646 a: Integer;
647 begin
648 Result := 0;
650 if SelectedObjects = nil then
651 Exit;
653 for a := 0 to High(SelectedObjects) do
654 if SelectedObjects[a].Live then
655 Result := Result + 1;
656 end;
658 function GetFirstSelected(): Integer;
659 var
660 a: Integer;
661 begin
662 Result := -1;
664 if SelectedObjects = nil then
665 Exit;
667 for a := 0 to High(SelectedObjects) do
668 if SelectedObjects[a].Live then
669 begin
670 Result := a;
671 Exit;
672 end;
673 end;
675 function Normalize16(x: Integer): Integer;
676 begin
677 Result := (x div 16) * 16;
678 end;
680 procedure MoveMap(X, Y: Integer);
681 var
682 rx, ry, ScaleSz: Integer;
683 begin
684 with MainForm.RenderPanel do
685 begin
686 ScaleSz := 16 div Scale;
687 // Размер видимой части карты:
688 rx := min(Normalize16(Width), Normalize16(gMapInfo.Width)) div 2;
689 ry := min(Normalize16(Height), Normalize16(gMapInfo.Height)) div 2;
690 // Место клика на мини-карте:
691 MapOffset.X := X - (Width-max(gMapInfo.Width div ScaleSz, 1)-1);
692 MapOffset.Y := Y - 1;
693 // Это же место на "большой" карте:
694 MapOffset.X := MapOffset.X * ScaleSz;
695 MapOffset.Y := MapOffset.Y * ScaleSz;
696 // Левый верхний угол новой видимой части карты:
697 MapOffset.X := MapOffset.X - rx;
698 MapOffset.Y := MapOffset.Y - ry;
699 // Выход за границы:
700 if MapOffset.X < 0 then
701 MapOffset.X := 0;
702 if MapOffset.Y < 0 then
703 MapOffset.Y := 0;
704 if MapOffset.X > MainForm.sbHorizontal.Max then
705 MapOffset.X := MainForm.sbHorizontal.Max;
706 if MapOffset.Y > MainForm.sbVertical.Max then
707 MapOffset.Y := MainForm.sbVertical.Max;
708 // Кратно 16:
709 MapOffset.X := Normalize16(MapOffset.X);
710 MapOffset.Y := Normalize16(MapOffset.Y);
711 end;
713 MainForm.sbHorizontal.Position := MapOffset.X;
714 MainForm.sbVertical.Position := MapOffset.Y;
716 MapOffset.X := -MapOffset.X;
717 MapOffset.Y := -MapOffset.Y;
719 MainForm.Resize();
720 end;
722 function IsTexturedPanel(PanelType: Word): Boolean;
723 begin
724 Result := WordBool(PanelType and (PANEL_WALL or PANEL_BACK or PANEL_FORE or
725 PANEL_STEP or PANEL_OPENDOOR or PANEL_CLOSEDOOR or
726 PANEL_WATER or PANEL_ACID1 or PANEL_ACID2));
727 end;
729 procedure FillProperty();
730 var
731 _id: DWORD;
732 str: String;
733 begin
734 MainForm.vleObjectProperty.Strings.Clear();
736 // Отображаем свойства если выделен только один объект:
737 if SelectedObjectCount() <> 1 then
738 Exit;
740 _id := GetFirstSelected();
741 if not SelectedObjects[_id].Live then
742 Exit;
744 with MainForm.vleObjectProperty do
745 with ItemProps[InsertRow(_lc[I_PROP_ID], IntToStr(SelectedObjects[_id].ID), True)] do
746 begin
747 EditStyle := esSimple;
748 ReadOnly := True;
749 end;
751 case SelectedObjects[0].ObjectType of
752 OBJECT_PANEL:
753 begin
754 with MainForm.vleObjectProperty,
755 gPanels[SelectedObjects[_id].ID] do
756 begin
757 with ItemProps[InsertRow(_lc[I_PROP_X], IntToStr(X), True)] do
758 begin
759 EditStyle := esSimple;
760 MaxLength := 5;
761 end;
763 with ItemProps[InsertRow(_lc[I_PROP_Y], IntToStr(Y), True)] do
764 begin
765 EditStyle := esSimple;
766 MaxLength := 5;
767 end;
769 with ItemProps[InsertRow(_lc[I_PROP_WIDTH], IntToStr(Width), True)] do
770 begin
771 EditStyle := esSimple;
772 MaxLength := 5;
773 end;
775 with ItemProps[InsertRow(_lc[I_PROP_HEIGHT], IntToStr(Height), True)] do
776 begin
777 EditStyle := esSimple;
778 MaxLength := 5;
779 end;
781 with ItemProps[InsertRow(_lc[I_PROP_PANEL_TYPE], GetPanelName(PanelType), True)] do
782 begin
783 EditStyle := esEllipsis;
784 ReadOnly := True;
785 end;
787 if IsTexturedPanel(PanelType) then
788 begin // Может быть текстура
789 with ItemProps[InsertRow(_lc[I_PROP_PANEL_TEX], TextureName, True)] do
790 begin
791 EditStyle := esEllipsis;
792 ReadOnly := True;
793 end;
795 if TextureName <> '' then
796 begin // Есть текстура
797 with ItemProps[InsertRow(_lc[I_PROP_PANEL_ALPHA], IntToStr(Alpha), True)] do
798 begin
799 EditStyle := esSimple;
800 MaxLength := 3;
801 end;
803 with ItemProps[InsertRow(_lc[I_PROP_PANEL_BLEND], BoolNames[Blending], True)] do
804 begin
805 EditStyle := esPickList;
806 ReadOnly := True;
807 end;
808 end;
809 end;
810 end;
811 end;
813 OBJECT_ITEM:
814 begin
815 with MainForm.vleObjectProperty,
816 gItems[SelectedObjects[_id].ID] do
817 begin
818 with ItemProps[InsertRow(_lc[I_PROP_X], IntToStr(X), True)] do
819 begin
820 EditStyle := esSimple;
821 MaxLength := 5;
822 end;
824 with ItemProps[InsertRow(_lc[I_PROP_Y], IntToStr(Y), True)] do
825 begin
826 EditStyle := esSimple;
827 MaxLength := 5;
828 end;
830 with ItemProps[InsertRow(_lc[I_PROP_DM_ONLY], BoolNames[OnlyDM], True)] do
831 begin
832 EditStyle := esPickList;
833 ReadOnly := True;
834 end;
836 with ItemProps[InsertRow(_lc[I_PROP_ITEM_FALLS], BoolNames[Fall], True)] do
837 begin
838 EditStyle := esPickList;
839 ReadOnly := True;
840 end;
841 end;
842 end;
844 OBJECT_MONSTER:
845 begin
846 with MainForm.vleObjectProperty,
847 gMonsters[SelectedObjects[_id].ID] do
848 begin
849 with ItemProps[InsertRow(_lc[I_PROP_X], IntToStr(X), True)] do
850 begin
851 EditStyle := esSimple;
852 MaxLength := 5;
853 end;
855 with ItemProps[InsertRow(_lc[I_PROP_Y], IntToStr(Y), True)] do
856 begin
857 EditStyle := esSimple;
858 MaxLength := 5;
859 end;
861 with ItemProps[InsertRow(_lc[I_PROP_DIRECTION], DirNames[Direction], True)] do
862 begin
863 EditStyle := esPickList;
864 ReadOnly := True;
865 end;
866 end;
867 end;
869 OBJECT_AREA:
870 begin
871 with MainForm.vleObjectProperty,
872 gAreas[SelectedObjects[_id].ID] do
873 begin
874 with ItemProps[InsertRow(_lc[I_PROP_X], IntToStr(X), True)] do
875 begin
876 EditStyle := esSimple;
877 MaxLength := 5;
878 end;
880 with ItemProps[InsertRow(_lc[I_PROP_Y], IntToStr(Y), True)] do
881 begin
882 EditStyle := esSimple;
883 MaxLength := 5;
884 end;
886 with ItemProps[InsertRow(_lc[I_PROP_DIRECTION], DirNames[Direction], True)] do
887 begin
888 EditStyle := esPickList;
889 ReadOnly := True;
890 end;
891 end;
892 end;
894 OBJECT_TRIGGER:
895 begin
896 with MainForm.vleObjectProperty,
897 gTriggers[SelectedObjects[_id].ID] do
898 begin
899 with ItemProps[InsertRow(_lc[I_PROP_TR_TYPE], GetTriggerName(TriggerType), True)] do
900 begin
901 EditStyle := esSimple;
902 ReadOnly := True;
903 end;
905 with ItemProps[InsertRow(_lc[I_PROP_X], IntToStr(X), True)] do
906 begin
907 EditStyle := esSimple;
908 MaxLength := 5;
909 end;
911 with ItemProps[InsertRow(_lc[I_PROP_Y], IntToStr(Y), True)] do
912 begin
913 EditStyle := esSimple;
914 MaxLength := 5;
915 end;
917 with ItemProps[InsertRow(_lc[I_PROP_WIDTH], IntToStr(Width), True)] do
918 begin
919 EditStyle := esSimple;
920 MaxLength := 5;
921 end;
923 with ItemProps[InsertRow(_lc[I_PROP_HEIGHT], IntToStr(Height), True)] do
924 begin
925 EditStyle := esSimple;
926 MaxLength := 5;
927 end;
929 with ItemProps[InsertRow(_lc[I_PROP_TR_ENABLED], BoolNames[Enabled], True)] do
930 begin
931 EditStyle := esPickList;
932 ReadOnly := True;
933 end;
935 with ItemProps[InsertRow(_lc[I_PROP_TR_TEXTURE_PANEL], IntToStr(TexturePanel), True)] do
936 begin
937 EditStyle := esEllipsis;
938 ReadOnly := True;
939 end;
941 with ItemProps[InsertRow(_lc[I_PROP_TR_ACTIVATION], ActivateToStr(ActivateType), True)] do
942 begin
943 EditStyle := esEllipsis;
944 ReadOnly := True;
945 end;
947 with ItemProps[InsertRow(_lc[I_PROP_TR_KEYS], KeyToStr(Key), True)] do
948 begin
949 EditStyle := esEllipsis;
950 ReadOnly := True;
951 end;
953 case TriggerType of
954 TRIGGER_EXIT:
955 begin
956 str := win2utf(Data.MapName);
957 with ItemProps[InsertRow(_lc[I_PROP_TR_NEXT_MAP], str, True)] do
958 begin
959 EditStyle := esEllipsis;
960 ReadOnly := True;
961 end;
962 end;
964 TRIGGER_TELEPORT:
965 begin
966 with ItemProps[InsertRow(_lc[I_PROP_TR_TELEPORT_TO], Format('(%d:%d)', [Data.TargetPoint.X, Data.TargetPoint.Y]), True)] do
967 begin
968 EditStyle := esEllipsis;
969 ReadOnly := True;
970 end;
972 with ItemProps[InsertRow(_lc[I_PROP_TR_D2D], BoolNames[Data.d2d_teleport], True)] do
973 begin
974 EditStyle := esPickList;
975 ReadOnly := True;
976 end;
978 with ItemProps[InsertRow(_lc[I_PROP_TR_TELEPORT_SILENT], BoolNames[Data.silent_teleport], True)] do
979 begin
980 EditStyle := esPickList;
981 ReadOnly := True;
982 end;
984 with ItemProps[InsertRow(_lc[I_PROP_TR_TELEPORT_DIR], DirNamesAdv[Data.TlpDir], True)] do
985 begin
986 EditStyle := esPickList;
987 ReadOnly := True;
988 end;
989 end;
991 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR,
992 TRIGGER_DOOR, TRIGGER_DOOR5:
993 begin
994 with ItemProps[InsertRow(_lc[I_PROP_TR_DOOR_PANEL], IntToStr(Data.PanelID), True)] do
995 begin
996 EditStyle := esEllipsis;
997 ReadOnly := True;
998 end;
1000 with ItemProps[InsertRow(_lc[I_PROP_TR_SILENT], BoolNames[Data.NoSound], True)] do
1001 begin
1002 EditStyle := esPickList;
1003 ReadOnly := True;
1004 end;
1006 with ItemProps[InsertRow(_lc[I_PROP_TR_D2D], BoolNames[Data.d2d_doors], True)] do
1007 begin
1008 EditStyle := esPickList;
1009 ReadOnly := True;
1010 end;
1011 end;
1013 TRIGGER_CLOSETRAP, TRIGGER_TRAP:
1014 begin
1015 with ItemProps[InsertRow(_lc[I_PROP_TR_TRAP_PANEL], IntToStr(Data.PanelID), True)] do
1016 begin
1017 EditStyle := esEllipsis;
1018 ReadOnly := True;
1019 end;
1021 with ItemProps[InsertRow(_lc[I_PROP_TR_SILENT], BoolNames[Data.NoSound], True)] do
1022 begin
1023 EditStyle := esPickList;
1024 ReadOnly := True;
1025 end;
1027 with ItemProps[InsertRow(_lc[I_PROP_TR_D2D], BoolNames[Data.d2d_doors], True)] do
1028 begin
1029 EditStyle := esPickList;
1030 ReadOnly := True;
1031 end;
1032 end;
1034 TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF,
1035 TRIGGER_ONOFF:
1036 begin
1037 with ItemProps[InsertRow(_lc[I_PROP_TR_EX_AREA],
1038 Format('(%d:%d %d:%d)', [Data.tX, Data.tY, Data.tWidth, Data.tHeight]), True)] do
1039 begin
1040 EditStyle := esEllipsis;
1041 ReadOnly := True;
1042 end;
1044 with ItemProps[InsertRow(_lc[I_PROP_TR_EX_DELAY], IntToStr(Data.Wait), True)] do
1045 begin
1046 EditStyle := esSimple;
1047 MaxLength := 5;
1048 end;
1050 with ItemProps[InsertRow(_lc[I_PROP_TR_EX_COUNT], IntToStr(Data.Count), True)] do
1051 begin
1052 EditStyle := esSimple;
1053 MaxLength := 5;
1054 end;
1056 with ItemProps[InsertRow(_lc[I_PROP_TR_EX_MONSTER], IntToStr(Data.MonsterID-1), True)] do
1057 begin
1058 EditStyle := esEllipsis;
1059 ReadOnly := True;
1060 end;
1062 if TriggerType = TRIGGER_PRESS then
1063 with ItemProps[InsertRow(_lc[I_PROP_TR_EX_RANDOM], BoolNames[Data.ExtRandom], True)] do
1064 begin
1065 EditStyle := esPickList;
1066 ReadOnly := True;
1067 end;
1068 end;
1070 TRIGGER_SECRET:
1073 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
1074 begin
1075 with ItemProps[InsertRow(_lc[I_PROP_TR_LIFT_PANEL], IntToStr(Data.PanelID), True)] do
1076 begin
1077 EditStyle := esEllipsis;
1078 ReadOnly := True;
1079 end;
1081 with ItemProps[InsertRow(_lc[I_PROP_TR_SILENT], BoolNames[Data.NoSound], True)] do
1082 begin
1083 EditStyle := esPickList;
1084 ReadOnly := True;
1085 end;
1087 with ItemProps[InsertRow(_lc[I_PROP_TR_D2D], BoolNames[Data.d2d_doors], True)] do
1088 begin
1089 EditStyle := esPickList;
1090 ReadOnly := True;
1091 end;
1092 end;
1094 TRIGGER_TEXTURE:
1095 begin
1096 with ItemProps[InsertRow(_lc[I_PROP_TR_TEXTURE_ONCE], BoolNames[Data.ActivateOnce], True)] do
1097 begin
1098 EditStyle := esPickList;
1099 ReadOnly := True;
1100 end;
1102 with ItemProps[InsertRow(_lc[I_PROP_TR_TEXTURE_ANIM_ONCE], BoolNames[Data.AnimOnce], True)] do
1103 begin
1104 EditStyle := esPickList;
1105 ReadOnly := True;
1106 end;
1107 end;
1109 TRIGGER_SOUND:
1110 begin
1111 str := win2utf(Data.SoundName);
1112 with ItemProps[InsertRow(_lc[I_PROP_TR_SOUND_NAME], str, True)] do
1113 begin
1114 EditStyle := esEllipsis;
1115 ReadOnly := True;
1116 end;
1118 with ItemProps[InsertRow(_lc[I_PROP_TR_SOUND_VOLUME], IntToStr(Data.Volume), True)] do
1119 begin
1120 EditStyle := esSimple;
1121 MaxLength := 3;
1122 end;
1124 with ItemProps[InsertRow(_lc[I_PROP_TR_SOUND_PAN], IntToStr(Data.Pan), True)] do
1125 begin
1126 EditStyle := esSimple;
1127 MaxLength := 3;
1128 end;
1130 with ItemProps[InsertRow(_lc[I_PROP_TR_SOUND_COUNT], IntToStr(Data.PlayCount), True)] do
1131 begin
1132 EditStyle := esSimple;
1133 MaxLength := 3;
1134 end;
1136 with ItemProps[InsertRow(_lc[I_PROP_TR_SOUND_LOCAL], BoolNames[Data.Local], True)] do
1137 begin
1138 EditStyle := esPickList;
1139 ReadOnly := True;
1140 end;
1142 with ItemProps[InsertRow(_lc[I_PROP_TR_SOUND_SWITCH], BoolNames[Data.SoundSwitch], True)] do
1143 begin
1144 EditStyle := esPickList;
1145 ReadOnly := True;
1146 end;
1147 end;
1149 TRIGGER_SPAWNMONSTER:
1150 begin
1151 with ItemProps[InsertRow(_lc[I_PROP_TR_MONSTER_TYPE], MonsterToStr(Data.MonType), True)] do
1152 begin
1153 EditStyle := esEllipsis;
1154 ReadOnly := True;
1155 end;
1157 with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_TO],
1158 Format('(%d:%d)', [Data.MonPos.X, Data.MonPos.Y]), True)] do
1159 begin
1160 EditStyle := esEllipsis;
1161 ReadOnly := True;
1162 end;
1164 with ItemProps[InsertRow(_lc[I_PROP_DIRECTION], DirNames[TDirection(Data.MonDir)], True)] do
1165 begin
1166 EditStyle := esPickList;
1167 ReadOnly := True;
1168 end;
1170 with ItemProps[InsertRow(_lc[I_PROP_TR_HEALTH], IntToStr(Data.MonHealth), True)] do
1171 begin
1172 EditStyle := esSimple;
1173 MaxLength := 5;
1174 end;
1176 with ItemProps[InsertRow(_lc[I_PROP_TR_MONSTER_ACTIVE], BoolNames[Data.MonActive], True)] do
1177 begin
1178 EditStyle := esPickList;
1179 ReadOnly := True;
1180 end;
1182 with ItemProps[InsertRow(_lc[I_PROP_TR_COUNT], IntToStr(Data.MonCount), True)] do
1183 begin
1184 EditStyle := esSimple;
1185 MaxLength := 5;
1186 end;
1188 with ItemProps[InsertRow(_lc[I_PROP_TR_FX_TYPE], EffectToStr(Data.MonEffect), True)] do
1189 begin
1190 EditStyle := esEllipsis;
1191 ReadOnly := True;
1192 end;
1194 with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_MAX], IntToStr(Data.MonMax), True)] do
1195 begin
1196 EditStyle := esSimple;
1197 MaxLength := 5;
1198 end;
1200 with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_DELAY], IntToStr(Data.MonDelay), True)] do
1201 begin
1202 EditStyle := esSimple;
1203 MaxLength := 5;
1204 end;
1206 case Data.MonBehav of
1207 1: str := _lc[I_PROP_TR_MONSTER_BEHAVIOUR_1];
1208 2: str := _lc[I_PROP_TR_MONSTER_BEHAVIOUR_2];
1209 3: str := _lc[I_PROP_TR_MONSTER_BEHAVIOUR_3];
1210 4: str := _lc[I_PROP_TR_MONSTER_BEHAVIOUR_4];
1211 5: str := _lc[I_PROP_TR_MONSTER_BEHAVIOUR_5];
1212 else str := _lc[I_PROP_TR_MONSTER_BEHAVIOUR_0];
1213 end;
1214 with ItemProps[InsertRow(_lc[I_PROP_TR_MONSTER_BEHAVIOUR], str, True)] do
1215 begin
1216 EditStyle := esPickList;
1217 ReadOnly := True;
1218 end;
1219 end;
1221 TRIGGER_SPAWNITEM:
1222 begin
1223 with ItemProps[InsertRow(_lc[I_PROP_TR_ITEM_TYPE], ItemToStr(Data.ItemType), True)] do
1224 begin
1225 EditStyle := esEllipsis;
1226 ReadOnly := True;
1227 end;
1229 with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_TO],
1230 Format('(%d:%d)', [Data.ItemPos.X, Data.ItemPos.Y]), True)] do
1231 begin
1232 EditStyle := esEllipsis;
1233 ReadOnly := True;
1234 end;
1236 with ItemProps[InsertRow(_lc[I_PROP_DM_ONLY], BoolNames[Data.ItemOnlyDM], True)] do
1237 begin
1238 EditStyle := esPickList;
1239 ReadOnly := True;
1240 end;
1242 with ItemProps[InsertRow(_lc[I_PROP_ITEM_FALLS], BoolNames[Data.ItemFalls], True)] do
1243 begin
1244 EditStyle := esPickList;
1245 ReadOnly := True;
1246 end;
1248 with ItemProps[InsertRow(_lc[I_PROP_TR_COUNT], IntToStr(Data.ItemCount), True)] do
1249 begin
1250 EditStyle := esSimple;
1251 MaxLength := 5;
1252 end;
1254 with ItemProps[InsertRow(_lc[I_PROP_TR_FX_TYPE], EffectToStr(Data.ItemEffect), True)] do
1255 begin
1256 EditStyle := esEllipsis;
1257 ReadOnly := True;
1258 end;
1260 with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_MAX], IntToStr(Data.ItemMax), True)] do
1261 begin
1262 EditStyle := esSimple;
1263 MaxLength := 5;
1264 end;
1266 with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_DELAY], IntToStr(Data.ItemDelay), True)] do
1267 begin
1268 EditStyle := esSimple;
1269 MaxLength := 5;
1270 end;
1271 end;
1273 TRIGGER_MUSIC:
1274 begin
1275 str := win2utf(Data.MusicName);
1276 with ItemProps[InsertRow(_lc[I_PROP_TR_MUSIC_NAME], str, True)] do
1277 begin
1278 EditStyle := esEllipsis;
1279 ReadOnly := True;
1280 end;
1282 if Data.MusicAction = 1 then
1283 str := _lc[I_PROP_TR_MUSIC_ON]
1284 else
1285 str := _lc[I_PROP_TR_MUSIC_OFF];
1287 with ItemProps[InsertRow(_lc[I_PROP_TR_MUSIC_ACT], str, True)] do
1288 begin
1289 EditStyle := esPickList;
1290 ReadOnly := True;
1291 end;
1292 end;
1294 TRIGGER_PUSH:
1295 begin
1296 with ItemProps[InsertRow(_lc[I_PROP_TR_PUSH_ANGLE], IntToStr(Data.PushAngle), True)] do
1297 begin
1298 EditStyle := esSimple;
1299 MaxLength := 4;
1300 end;
1301 with ItemProps[InsertRow(_lc[I_PROP_TR_PUSH_FORCE], IntToStr(Data.PushForce), True)] do
1302 begin
1303 EditStyle := esSimple;
1304 MaxLength := 4;
1305 end;
1306 with ItemProps[InsertRow(_lc[I_PROP_TR_PUSH_RESET], BoolNames[Data.ResetVel], True)] do
1307 begin
1308 EditStyle := esPickList;
1309 ReadOnly := True;
1310 end;
1311 end;
1313 TRIGGER_SCORE:
1314 begin
1315 case Data.ScoreAction of
1316 1: str := _lc[I_PROP_TR_SCORE_ACT_1];
1317 2: str := _lc[I_PROP_TR_SCORE_ACT_2];
1318 3: str := _lc[I_PROP_TR_SCORE_ACT_3];
1319 else str := _lc[I_PROP_TR_SCORE_ACT_0];
1320 end;
1321 with ItemProps[InsertRow(_lc[I_PROP_TR_SCORE_ACT], str, True)] do
1322 begin
1323 EditStyle := esPickList;
1324 ReadOnly := True;
1325 end;
1326 with ItemProps[InsertRow(_lc[I_PROP_TR_COUNT], IntToStr(Data.ScoreCount), True)] do
1327 begin
1328 EditStyle := esSimple;
1329 MaxLength := 3;
1330 end;
1331 case Data.ScoreTeam of
1332 1: str := _lc[I_PROP_TR_SCORE_TEAM_1];
1333 2: str := _lc[I_PROP_TR_SCORE_TEAM_2];
1334 3: str := _lc[I_PROP_TR_SCORE_TEAM_3];
1335 else str := _lc[I_PROP_TR_SCORE_TEAM_0];
1336 end;
1337 with ItemProps[InsertRow(_lc[I_PROP_TR_SCORE_TEAM], str, True)] do
1338 begin
1339 EditStyle := esPickList;
1340 ReadOnly := True;
1341 end;
1342 with ItemProps[InsertRow(_lc[I_PROP_TR_SCORE_CON], BoolNames[Data.ScoreCon], True)] do
1343 begin
1344 EditStyle := esPickList;
1345 ReadOnly := True;
1346 end;
1347 with ItemProps[InsertRow(_lc[I_PROP_TR_SCORE_MSG], BoolNames[Data.ScoreMsg], True)] do
1348 begin
1349 EditStyle := esPickList;
1350 ReadOnly := True;
1351 end;
1352 end;
1354 TRIGGER_MESSAGE:
1355 begin
1356 case Data.MessageKind of
1357 1: str := _lc[I_PROP_TR_MESSAGE_KIND_1];
1358 else str := _lc[I_PROP_TR_MESSAGE_KIND_0];
1359 end;
1360 with ItemProps[InsertRow(_lc[I_PROP_TR_MESSAGE_KIND], str, True)] do
1361 begin
1362 EditStyle := esPickList;
1363 ReadOnly := True;
1364 end;
1365 case Data.MessageSendTo of
1366 1: str := _lc[I_PROP_TR_MESSAGE_TO_1];
1367 2: str := _lc[I_PROP_TR_MESSAGE_TO_2];
1368 3: str := _lc[I_PROP_TR_MESSAGE_TO_3];
1369 4: str := _lc[I_PROP_TR_MESSAGE_TO_4];
1370 5: str := _lc[I_PROP_TR_MESSAGE_TO_5];
1371 else str := _lc[I_PROP_TR_MESSAGE_TO_0];
1372 end;
1373 with ItemProps[InsertRow(_lc[I_PROP_TR_MESSAGE_TO], str, True)] do
1374 begin
1375 EditStyle := esPickList;
1376 ReadOnly := True;
1377 end;
1378 str := win2utf(Data.MessageText);
1379 with ItemProps[InsertRow(_lc[I_PROP_TR_MESSAGE_TEXT], str, True)] do
1380 begin
1381 EditStyle := esSimple;
1382 MaxLength := 100;
1383 end;
1384 with ItemProps[InsertRow(_lc[I_PROP_TR_MESSAGE_TIME], IntToStr(Data.MessageTime), True)] do
1385 begin
1386 EditStyle := esSimple;
1387 MaxLength := 5;
1388 end;
1389 end;
1391 TRIGGER_DAMAGE:
1392 begin
1393 with ItemProps[InsertRow(_lc[I_PROP_TR_DAMAGE_VALUE], IntToStr(Data.DamageValue), True)] do
1394 begin
1395 EditStyle := esSimple;
1396 MaxLength := 5;
1397 end;
1398 with ItemProps[InsertRow(_lc[I_PROP_TR_INTERVAL], IntToStr(Data.DamageInterval), True)] do
1399 begin
1400 EditStyle := esSimple;
1401 MaxLength := 5;
1402 end;
1403 end;
1405 TRIGGER_HEALTH:
1406 begin
1407 with ItemProps[InsertRow(_lc[I_PROP_TR_HEALTH], IntToStr(Data.HealValue), True)] do
1408 begin
1409 EditStyle := esSimple;
1410 MaxLength := 5;
1411 end;
1412 with ItemProps[InsertRow(_lc[I_PROP_TR_INTERVAL], IntToStr(Data.HealInterval), True)] do
1413 begin
1414 EditStyle := esSimple;
1415 MaxLength := 5;
1416 end;
1417 with ItemProps[InsertRow(_lc[I_PROP_TR_HEALTH_MAX], BoolNames[Data.HealMax], True)] do
1418 begin
1419 EditStyle := esPickList;
1420 ReadOnly := True;
1421 end;
1422 with ItemProps[InsertRow(_lc[I_PROP_TR_SILENT], BoolNames[Data.HealSilent], True)] do
1423 begin
1424 EditStyle := esPickList;
1425 ReadOnly := True;
1426 end;
1427 end;
1429 TRIGGER_SHOT:
1430 begin
1431 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_TYPE], ShotToStr(Data.ShotType), True)] do
1432 begin
1433 EditStyle := esEllipsis;
1434 ReadOnly := True;
1435 end;
1437 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_SOUND], BoolNames[Data.ShotSound], True)] do
1438 begin
1439 EditStyle := esPickList;
1440 ReadOnly := True;
1441 end;
1443 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_PANEL], IntToStr(Data.ShotPanelID), True)] do
1444 begin
1445 EditStyle := esEllipsis;
1446 ReadOnly := True;
1447 end;
1449 case Data.ShotTarget of
1450 1: str := _lc[I_PROP_TR_SHOT_TO_1];
1451 2: str := _lc[I_PROP_TR_SHOT_TO_2];
1452 3: str := _lc[I_PROP_TR_SHOT_TO_3];
1453 4: str := _lc[I_PROP_TR_SHOT_TO_4];
1454 5: str := _lc[I_PROP_TR_SHOT_TO_5];
1455 6: str := _lc[I_PROP_TR_SHOT_TO_6];
1456 else str := _lc[I_PROP_TR_SHOT_TO_0];
1457 end;
1458 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_TO], str, True)] do
1459 begin
1460 EditStyle := esPickList;
1461 ReadOnly := True;
1462 end;
1464 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_SIGHT], IntToStr(Data.ShotIntSight), True)] do
1465 begin
1466 EditStyle := esSimple;
1467 MaxLength := 3;
1468 end;
1470 case Data.ShotAim of
1471 1: str := _lc[I_PROP_TR_SHOT_AIM_1];
1472 2: str := _lc[I_PROP_TR_SHOT_AIM_2];
1473 3: str := _lc[I_PROP_TR_SHOT_AIM_3];
1474 else str := _lc[I_PROP_TR_SHOT_AIM_0];
1475 end;
1476 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_AIM], str, True)-1] do
1477 begin
1478 EditStyle := esPickList;
1479 ReadOnly := True;
1480 end;
1482 with ItemProps[InsertRow(_lc[I_PROP_TR_SPAWN_TO],
1483 Format('(%d:%d)', [Data.ShotPos.X, Data.ShotPos.Y]), True)] do
1484 begin
1485 EditStyle := esEllipsis;
1486 ReadOnly := True;
1487 end;
1489 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_ANGLE], IntToStr(Data.ShotAngle), True)] do
1490 begin
1491 EditStyle := esSimple;
1492 MaxLength := 4;
1493 end;
1495 with ItemProps[InsertRow(_lc[I_PROP_TR_EX_DELAY], IntToStr(Data.ShotWait), True)] do
1496 begin
1497 EditStyle := esSimple;
1498 MaxLength := 5;
1499 end;
1501 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_ACC], IntToStr(Data.ShotAccuracy), True)] do
1502 begin
1503 EditStyle := esSimple;
1504 MaxLength := 5;
1505 end;
1507 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_AMMO], IntToStr(Data.ShotAmmo), True)] do
1508 begin
1509 EditStyle := esSimple;
1510 MaxLength := 5;
1511 end;
1513 with ItemProps[InsertRow(_lc[I_PROP_TR_SHOT_RELOAD], IntToStr(Data.ShotIntReload), True)] do
1514 begin
1515 EditStyle := esSimple;
1516 MaxLength := 4;
1517 end;
1518 end;
1520 TRIGGER_EFFECT:
1521 begin
1522 with ItemProps[InsertRow(_lc[I_PROP_TR_COUNT], IntToStr(Data.FXCount), True)] do
1523 begin
1524 EditStyle := esSimple;
1525 MaxLength := 3;
1526 end;
1528 if Data.FXType = 0 then
1529 str := _lc[I_PROP_TR_EFFECT_PARTICLE]
1530 else
1531 str := _lc[I_PROP_TR_EFFECT_ANIMATION];
1532 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_TYPE], str, True)] do
1533 begin
1534 EditStyle := esEllipsis;
1535 ReadOnly := True;
1536 end;
1538 str := '';
1539 if Data.FXType = 0 then
1540 case Data.FXSubType of
1541 TRIGGER_EFFECT_SLIQUID:
1542 str := _lc[I_PROP_TR_EFFECT_SLIQUID];
1543 TRIGGER_EFFECT_LLIQUID:
1544 str := _lc[I_PROP_TR_EFFECT_LLIQUID];
1545 TRIGGER_EFFECT_DLIQUID:
1546 str := _lc[I_PROP_TR_EFFECT_DLIQUID];
1547 TRIGGER_EFFECT_BLOOD:
1548 str := _lc[I_PROP_TR_EFFECT_BLOOD];
1549 TRIGGER_EFFECT_SPARK:
1550 str := _lc[I_PROP_TR_EFFECT_SPARK];
1551 TRIGGER_EFFECT_BUBBLE:
1552 str := _lc[I_PROP_TR_EFFECT_BUBBLE];
1553 end;
1554 if Data.FXType = 1 then
1555 begin
1556 if (Data.FXSubType = 0) or (Data.FXSubType > EFFECT_FIRE) then
1557 Data.FXSubType := EFFECT_TELEPORT;
1558 str := EffectToStr(Data.FXSubType);
1559 end;
1560 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_SUBTYPE], str, True)] do
1561 begin
1562 EditStyle := esEllipsis;
1563 ReadOnly := True;
1564 end;
1566 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_COLOR], IntToStr(Data.FXColorR or (Data.FXColorG shl 8) or (Data.FXColorB shl 16)), True)] do
1567 begin
1568 EditStyle := esEllipsis;
1569 ReadOnly := True;
1570 end;
1572 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_CENTER], BoolNames[Data.FXPos = 0], True)] do
1573 begin
1574 EditStyle := esPickList;
1575 ReadOnly := True;
1576 end;
1578 with ItemProps[InsertRow(_lc[I_PROP_TR_EX_DELAY], IntToStr(Data.FXWait), True)] do
1579 begin
1580 EditStyle := esSimple;
1581 MaxLength := 5;
1582 end;
1584 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_VELX], IntToStr(Data.FXVelX), True)] do
1585 begin
1586 EditStyle := esSimple;
1587 MaxLength := 4;
1588 end;
1590 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_VELY], IntToStr(Data.FXVelY), True)] do
1591 begin
1592 EditStyle := esSimple;
1593 MaxLength := 4;
1594 end;
1596 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_SPL], IntToStr(Data.FXSpreadL), True)] do
1597 begin
1598 EditStyle := esSimple;
1599 MaxLength := 3;
1600 end;
1602 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_SPR], IntToStr(Data.FXSpreadR), True)] do
1603 begin
1604 EditStyle := esSimple;
1605 MaxLength := 3;
1606 end;
1608 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_SPU], IntToStr(Data.FXSpreadU), True)] do
1609 begin
1610 EditStyle := esSimple;
1611 MaxLength := 3;
1612 end;
1614 with ItemProps[InsertRow(_lc[I_PROP_TR_EFFECT_SPD], IntToStr(Data.FXSpreadD), True)] do
1615 begin
1616 EditStyle := esSimple;
1617 MaxLength := 3;
1618 end;
1619 end;
1620 end; //case TriggerType
1621 end;
1622 end; // OBJECT_TRIGGER:
1623 end;
1624 end;
1626 procedure ChangeShownProperty(Name: String; NewValue: String);
1627 var
1628 row: Integer;
1629 begin
1630 if SelectedObjectCount() <> 1 then
1631 Exit;
1632 if not SelectedObjects[GetFirstSelected()].Live then
1633 Exit;
1635 // Есть ли такой ключ:
1636 if MainForm.vleObjectProperty.FindRow(Name, row) then
1637 begin
1638 MainForm.vleObjectProperty.Values[Name] := NewValue;
1639 end;
1640 end;
1642 procedure SelectObject(fObjectType: Byte; fID: DWORD; Multi: Boolean);
1643 var
1644 a: Integer;
1645 b: Boolean;
1646 begin
1647 if Multi then
1648 begin
1649 b := False;
1651 // Уже выделен - убираем:
1652 if SelectedObjects <> nil then
1653 for a := 0 to High(SelectedObjects) do
1654 with SelectedObjects[a] do
1655 if Live and (ID = fID) and
1656 (ObjectType = fObjectType) then
1657 begin
1658 Live := False;
1659 b := True;
1660 end;
1662 if b then
1663 Exit;
1665 SetLength(SelectedObjects, Length(SelectedObjects)+1);
1667 with SelectedObjects[High(SelectedObjects)] do
1668 begin
1669 ObjectType := fObjectType;
1670 ID := fID;
1671 Live := True;
1672 end;
1673 end
1674 else // not Multi
1675 begin
1676 SetLength(SelectedObjects, 1);
1678 with SelectedObjects[0] do
1679 begin
1680 ObjectType := fObjectType;
1681 ID := fID;
1682 Live := True;
1683 end;
1684 end;
1686 MainForm.miCopy.Enabled := True;
1687 MainForm.miCut.Enabled := True;
1689 if fObjectType = OBJECT_PANEL then
1690 begin
1691 MainForm.miToFore.Enabled := True;
1692 MainForm.miToBack.Enabled := True;
1693 end;
1694 end;
1696 procedure RemoveSelectFromObjects();
1697 begin
1698 SelectedObjects := nil;
1699 DrawPressRect := False;
1700 MouseLDown := False;
1701 MouseRDown := False;
1702 MouseAction := MOUSEACTION_NONE;
1703 SelectFlag := SELECTFLAG_NONE;
1704 ResizeType := RESIZETYPE_NONE;
1705 ResizeDirection := RESIZEDIR_NONE;
1707 MainForm.vleObjectProperty.Strings.Clear();
1709 MainForm.miCopy.Enabled := False;
1710 MainForm.miCut.Enabled := False;
1711 MainForm.miToFore.Enabled := False;
1712 MainForm.miToBack.Enabled := False;
1713 end;
1715 procedure DeleteSelectedObjects();
1716 var
1717 i, a, ii: Integer;
1718 b: Boolean;
1719 begin
1720 if SelectedObjects = nil then
1721 Exit;
1723 b := False;
1724 i := 0;
1726 for a := 0 to High(SelectedObjects) do
1727 with SelectedObjects[a] do
1728 if Live then
1729 begin
1730 if not b then
1731 begin
1732 SetLength(UndoBuffer, Length(UndoBuffer)+1);
1733 i := High(UndoBuffer);
1734 b := True;
1735 end;
1737 SetLength(UndoBuffer[i], Length(UndoBuffer[i])+1);
1738 ii := High(UndoBuffer[i]);
1740 case ObjectType of
1741 OBJECT_PANEL:
1742 begin
1743 UndoBuffer[i, ii].UndoType := UNDO_DELETE_PANEL;
1744 New(UndoBuffer[i, ii].Panel);
1745 UndoBuffer[i, ii].Panel^ := gPanels[ID];
1746 end;
1747 OBJECT_ITEM:
1748 begin
1749 UndoBuffer[i, ii].UndoType := UNDO_DELETE_ITEM;
1750 UndoBuffer[i, ii].Item := gItems[ID];
1751 end;
1752 OBJECT_AREA:
1753 begin
1754 UndoBuffer[i, ii].UndoType := UNDO_DELETE_AREA;
1755 UndoBuffer[i, ii].Area := gAreas[ID];
1756 end;
1757 OBJECT_TRIGGER:
1758 begin
1759 UndoBuffer[i, ii].UndoType := UNDO_DELETE_TRIGGER;
1760 UndoBuffer[i, ii].Trigger := gTriggers[ID];
1761 end;
1762 end;
1764 RemoveObject(ID, ObjectType);
1765 end;
1767 RemoveSelectFromObjects();
1769 MainForm.miUndo.Enabled := UndoBuffer <> nil;
1770 end;
1772 procedure Undo_Add(ObjectType: Byte; ID: DWORD; Group: Boolean = False);
1773 var
1774 i, ii: Integer;
1775 begin
1776 if (not Group) or (Length(UndoBuffer) = 0) then
1777 SetLength(UndoBuffer, Length(UndoBuffer)+1);
1778 SetLength(UndoBuffer[High(UndoBuffer)], Length(UndoBuffer[High(UndoBuffer)])+1);
1779 i := High(UndoBuffer);
1780 ii := High(UndoBuffer[i]);
1782 case ObjectType of
1783 OBJECT_PANEL:
1784 UndoBuffer[i, ii].UndoType := UNDO_ADD_PANEL;
1785 OBJECT_ITEM:
1786 UndoBuffer[i, ii].UndoType := UNDO_ADD_ITEM;
1787 OBJECT_MONSTER:
1788 UndoBuffer[i, ii].UndoType := UNDO_ADD_MONSTER;
1789 OBJECT_AREA:
1790 UndoBuffer[i, ii].UndoType := UNDO_ADD_AREA;
1791 OBJECT_TRIGGER:
1792 UndoBuffer[i, ii].UndoType := UNDO_ADD_TRIGGER;
1793 end;
1795 UndoBuffer[i, ii].AddID := ID;
1797 MainForm.miUndo.Enabled := UndoBuffer <> nil;
1798 end;
1800 procedure FullClear();
1801 begin
1802 RemoveSelectFromObjects();
1803 ClearMap();
1804 LoadSky(gMapInfo.SkyName);
1805 UndoBuffer := nil;
1806 slInvalidTextures.Clear();
1807 MapCheckForm.lbErrorList.Clear();
1808 MapCheckForm.mErrorDescription.Clear();
1810 MainForm.miUndo.Enabled := False;
1811 MainForm.sbHorizontal.Position := 0;
1812 MainForm.sbVertical.Position := 0;
1813 MainForm.FormResize(nil);
1814 MainForm.Caption := FormCaption;
1815 OpenedMap := '';
1816 OpenedWAD := '';
1817 end;
1819 procedure ErrorMessageBox(str: String);
1820 begin
1821 MessageBox(0, PChar(str), PChar(_lc[I_MSG_ERROR]),
1822 MB_ICONINFORMATION or MB_OK or MB_DEFBUTTON1);
1823 end;
1825 function CheckProperty(): Boolean;
1826 var
1827 _id: Integer;
1828 begin
1829 Result := False;
1831 _id := GetFirstSelected();
1833 if SelectedObjects[_id].ObjectType = OBJECT_PANEL then
1834 with gPanels[SelectedObjects[_id].ID] do
1835 begin
1836 if TextureWidth <> 0 then
1837 if StrToIntDef(MainForm.vleObjectProperty.Values[_lc[I_PROP_WIDTH]], 1) mod TextureWidth <> 0 then
1838 begin
1839 ErrorMessageBox(Format(_lc[I_MSG_WRONG_TEXWIDTH],
1840 [TextureWidth]));
1841 Exit;
1842 end;
1844 if TextureHeight <> 0 then
1845 if StrToIntDef(Trim(MainForm.vleObjectProperty.Values[_lc[I_PROP_HEIGHT]]), 1) mod TextureHeight <> 0 then
1846 begin
1847 ErrorMessageBox(Format(_lc[I_MSG_WRONG_TEXHEIGHT],
1848 [TextureHeight]));
1849 Exit;
1850 end;
1852 if IsTexturedPanel(PanelType) and (TextureName <> '') then
1853 if not (StrToIntDef(MainForm.vleObjectProperty.Values[_lc[I_PROP_PANEL_ALPHA]], -1) in [0..255]) then
1854 begin
1855 ErrorMessageBox(_lc[I_MSG_WRONG_ALPHA]);
1856 Exit;
1857 end;
1858 end;
1860 if SelectedObjects[_id].ObjectType in [OBJECT_PANEL, OBJECT_TRIGGER] then
1861 if (StrToIntDef(MainForm.vleObjectProperty.Values[_lc[I_PROP_WIDTH]], 0) <= 0) or
1862 (StrToIntDef(MainForm.vleObjectProperty.Values[_lc[I_PROP_HEIGHT]], 0) <= 0) then
1863 begin
1864 ErrorMessageBox(_lc[I_MSG_WRONG_SIZE]);
1865 Exit;
1866 end;
1868 if (Trim(MainForm.vleObjectProperty.Values[_lc[I_PROP_X]]) = '') or
1869 (Trim(MainForm.vleObjectProperty.Values[_lc[I_PROP_Y]]) = '') then
1870 begin
1871 ErrorMessageBox(_lc[I_MSG_WRONG_XY]);
1872 Exit;
1873 end;
1875 Result := True;
1876 end;
1878 procedure SelectTexture(ID: Integer);
1879 begin
1880 MainForm.lbTextureList.ItemIndex := ID;
1881 MainForm.lbTextureListClick(nil);
1882 end;
1884 function AddTexture(aWAD, aSection, aTex: String; silent: Boolean): Boolean;
1885 var
1886 a, FrameLen: Integer;
1887 ok: Boolean;
1888 FileName: String;
1889 ResourceName: String;
1890 FullResourceName: String;
1891 SectionName: String;
1892 Data: Pointer;
1893 Width, Height: Word;
1894 fn: String;
1895 begin
1896 Data := nil;
1897 FrameLen := 0;
1898 Width := 0;
1899 Height := 0;
1901 if aSection = '..' then
1902 SectionName := ''
1903 else
1904 SectionName := aSection;
1906 if aWAD = _lc[I_WAD_SPECIAL_MAP] then
1907 begin // Файл карты
1908 g_ProcessResourceStr(OpenedMap, @fn, nil, nil);
1909 //FileName := EditorDir+'maps\'+ExtractFileName(fn);
1910 FileName := fn;
1911 ResourceName := ':'+SectionName+'\'+aTex;
1912 end
1913 else
1914 if aWAD = _lc[I_WAD_SPECIAL_TEXS] then
1915 begin // Спец. текстуры
1916 FileName := '';
1917 ResourceName := aTex;
1918 end
1919 else
1920 begin // Внешний WAD
1921 FileName := EditorDir+'wads/'+aWAD;
1922 ResourceName := aWAD+':'+SectionName+'\'+aTex;
1923 end;
1925 ok := True;
1927 // Есть ли уже такая текстура:
1928 for a := 0 to MainForm.lbTextureList.Items.Count-1 do
1929 if ResourceName = MainForm.lbTextureList.Items[a] then
1930 begin
1931 if not silent then
1932 ErrorMessageBox(Format(_lc[I_MSG_TEXTURE_ALREADY],
1933 [ResourceName]));
1934 ok := False;
1935 end;
1937 // Название ресурса <= 64 символов:
1938 if Length(ResourceName) > 64 then
1939 begin
1940 if not silent then
1941 ErrorMessageBox(Format(_lc[I_MSG_RES_NAME_64],
1942 [ResourceName]));
1943 ok := False;
1944 end;
1946 if ok then
1947 begin
1948 a := -1;
1949 if aWAD = _lc[I_WAD_SPECIAL_TEXS] then
1950 begin
1951 a := MainForm.lbTextureList.Items.Add(ResourceName);
1952 if not silent then
1953 SelectTexture(a);
1954 Result := True;
1955 Exit;
1956 end;
1958 FullResourceName := FileName+':'+SectionName+'\'+aTex;
1960 if IsAnim(FullResourceName) then
1961 begin // Аним. текстура
1962 GetFrame(FullResourceName, Data, FrameLen, Width, Height);
1964 if g_CreateTextureMemorySize(Data, FrameLen, ResourceName, 0, 0, Width, Height, 1) then
1965 a := MainForm.lbTextureList.Items.Add(ResourceName);
1966 end
1967 else // Обычная текстура
1968 begin
1969 if g_CreateTextureWAD(ResourceName, FullResourceName) then
1970 a := MainForm.lbTextureList.Items.Add(ResourceName);
1971 end;
1972 if (a > -1) and (not silent) then
1973 SelectTexture(a);
1974 end;
1976 Result := ok;
1977 end;
1979 procedure UpdateCaption(sMap, sFile, sRes: String);
1980 begin
1981 with MainForm do
1982 if (sFile = '') and (sRes = '') and (sMap = '') then
1983 Caption := FormCaption
1984 else
1985 if sMap = '' then
1986 Caption := Format('%s - %s:%s', [FormCaption, sFile, sRes])
1987 else
1988 if (sFile <> '') and (sRes <> '') then
1989 Caption := Format('%s - %s (%s:%s)', [FormCaption, sMap, sFile, sRes])
1990 else
1991 Caption := Format('%s - %s', [FormCaption, sMap]);
1992 end;
1994 procedure OpenMap(FileName: String; mapN: String);
1995 var
1996 MapName: String;
1997 idx: Integer;
1998 begin
1999 SelectMapForm.Caption := _lc[I_CAP_OPEN];
2000 SelectMapForm.GetMaps(FileName);
2002 if (FileName = OpenedWAD) and
2003 (OpenedMap <> '') then
2004 begin
2005 MapName := OpenedMap;
2006 while (Pos(':\', MapName) > 0) do
2007 Delete(MapName, 1, Pos(':\', MapName) + 1);
2009 idx := SelectMapForm.lbMapList.Items.IndexOf(MapName);
2010 SelectMapForm.lbMapList.ItemIndex := idx;
2011 end
2012 else
2013 if SelectMapForm.lbMapList.Count > 0 then
2014 SelectMapForm.lbMapList.ItemIndex := 0
2015 else
2016 SelectMapForm.lbMapList.ItemIndex := -1;
2018 if mapN = '' then
2019 idx := -1
2020 else
2021 idx := SelectMapForm.lbMapList.Items.IndexOf(mapN);
2023 if idx < 0 then
2024 begin
2025 if (SelectMapForm.ShowModal() = mrOK) and
2026 (SelectMapForm.lbMapList.ItemIndex <> -1) then
2027 idx := SelectMapForm.lbMapList.ItemIndex
2028 else
2029 Exit;
2030 end;
2032 MapName := SelectMapForm.lbMapList.Items[idx];
2034 with MainForm do
2035 begin
2036 FullClear();
2038 pLoadProgress.Left := (RenderPanel.Width div 2)-(pLoadProgress.Width div 2);
2039 pLoadProgress.Top := (RenderPanel.Height div 2)-(pLoadProgress.Height div 2);
2040 pLoadProgress.Show();
2042 OpenedMap := FileName+':\'+MapName;
2043 OpenedWAD := FileName;
2045 idx := RecentFiles.IndexOf(OpenedMap);
2046 // Такая карта уже недавно открывалась:
2047 if idx >= 0 then
2048 RecentFiles.Delete(idx);
2049 RecentFiles.Insert(0, OpenedMap);
2050 RefreshRecentMenu();
2052 LoadMap(OpenedMap);
2054 pLoadProgress.Hide();
2055 FormResize(nil);
2057 lbTextureList.Sorted := True;
2058 lbTextureList.Sorted := False;
2060 UpdateCaption(gMapInfo.Name, ExtractFileName(FileName), MapName);
2061 end;
2062 end;
2064 procedure MoveSelectedObjects(Wall, alt: Boolean; dx, dy: Integer);
2065 var
2066 okX, okY: Boolean;
2067 a: Integer;
2068 begin
2069 if SelectedObjects = nil then
2070 Exit;
2072 okX := True;
2073 okY := True;
2075 if Wall then
2076 for a := 0 to High(SelectedObjects) do
2077 if SelectedObjects[a].Live then
2078 begin
2079 if ObjectCollideLevel(SelectedObjects[a].ID, SelectedObjects[a].ObjectType, dx, 0) then
2080 okX := False;
2082 if ObjectCollideLevel(SelectedObjects[a].ID, SelectedObjects[a].ObjectType, 0, dy) then
2083 okY := False;
2085 if (not okX) or (not okY) then
2086 Break;
2087 end;
2089 if okX or okY then
2090 begin
2091 for a := 0 to High(SelectedObjects) do
2092 if SelectedObjects[a].Live then
2093 begin
2094 if okX then
2095 MoveObject(SelectedObjects[a].ObjectType, SelectedObjects[a].ID, dx, 0);
2097 if okY then
2098 MoveObject(SelectedObjects[a].ObjectType, SelectedObjects[a].ID, 0, dy);
2100 if alt and (SelectedObjects[a].ObjectType = OBJECT_TRIGGER) then
2101 begin
2102 if gTriggers[SelectedObjects[a].ID].TriggerType in [TRIGGER_PRESS,
2103 TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF] then
2104 begin // Двигаем зону Расширителя
2105 if okX then
2106 gTriggers[SelectedObjects[a].ID].Data.tX := gTriggers[SelectedObjects[a].ID].Data.tX+dx;
2107 if okY then
2108 gTriggers[SelectedObjects[a].ID].Data.tY := gTriggers[SelectedObjects[a].ID].Data.tY+dy;
2109 end;
2111 if gTriggers[SelectedObjects[a].ID].TriggerType in [TRIGGER_TELEPORT] then
2112 begin // Двигаем точку назначения Телепорта
2113 if okX then
2114 gTriggers[SelectedObjects[a].ID].Data.TargetPoint.X := gTriggers[SelectedObjects[a].ID].Data.TargetPoint.X+dx;
2115 if okY then
2116 gTriggers[SelectedObjects[a].ID].Data.TargetPoint.Y := gTriggers[SelectedObjects[a].ID].Data.TargetPoint.Y+dy;
2117 end;
2119 if gTriggers[SelectedObjects[a].ID].TriggerType in [TRIGGER_SPAWNMONSTER] then
2120 begin // Двигаем точку создания монстра
2121 if okX then
2122 gTriggers[SelectedObjects[a].ID].Data.MonPos.X := gTriggers[SelectedObjects[a].ID].Data.MonPos.X+dx;
2123 if okY then
2124 gTriggers[SelectedObjects[a].ID].Data.MonPos.Y := gTriggers[SelectedObjects[a].ID].Data.MonPos.Y+dy;
2125 end;
2127 if gTriggers[SelectedObjects[a].ID].TriggerType in [TRIGGER_SPAWNITEM] then
2128 begin // Двигаем точку создания предмета
2129 if okX then
2130 gTriggers[SelectedObjects[a].ID].Data.ItemPos.X := gTriggers[SelectedObjects[a].ID].Data.ItemPos.X+dx;
2131 if okY then
2132 gTriggers[SelectedObjects[a].ID].Data.ItemPos.Y := gTriggers[SelectedObjects[a].ID].Data.ItemPos.Y+dy;
2133 end;
2135 if gTriggers[SelectedObjects[a].ID].TriggerType in [TRIGGER_SHOT] then
2136 begin // Двигаем точку создания выстрела
2137 if okX then
2138 gTriggers[SelectedObjects[a].ID].Data.ShotPos.X := gTriggers[SelectedObjects[a].ID].Data.ShotPos.X+dx;
2139 if okY then
2140 gTriggers[SelectedObjects[a].ID].Data.ShotPos.Y := gTriggers[SelectedObjects[a].ID].Data.ShotPos.Y+dy;
2141 end;
2142 end;
2143 end;
2145 LastMovePoint := MousePos;
2146 end;
2147 end;
2149 procedure ShowLayer(Layer: Byte; show: Boolean);
2150 begin
2151 LayerEnabled[Layer] := show;
2153 case Layer of
2154 LAYER_BACK:
2155 begin
2156 MainForm.miLayer1.Checked := show;
2157 MainForm.miLayerP1.Checked := show;
2158 end;
2159 LAYER_WALLS:
2160 begin
2161 MainForm.miLayer2.Checked := show;
2162 MainForm.miLayerP2.Checked := show;
2163 end;
2164 LAYER_FOREGROUND:
2165 begin
2166 MainForm.miLayer3.Checked := show;
2167 MainForm.miLayerP3.Checked := show;
2168 end;
2169 LAYER_STEPS:
2170 begin
2171 MainForm.miLayer4.Checked := show;
2172 MainForm.miLayerP4.Checked := show;
2173 end;
2174 LAYER_WATER:
2175 begin
2176 MainForm.miLayer5.Checked := show;
2177 MainForm.miLayerP5.Checked := show;
2178 end;
2179 LAYER_ITEMS:
2180 begin
2181 MainForm.miLayer6.Checked := show;
2182 MainForm.miLayerP6.Checked := show;
2183 end;
2184 LAYER_MONSTERS:
2185 begin
2186 MainForm.miLayer7.Checked := show;
2187 MainForm.miLayerP7.Checked := show;
2188 end;
2189 LAYER_AREAS:
2190 begin
2191 MainForm.miLayer8.Checked := show;
2192 MainForm.miLayerP8.Checked := show;
2193 end;
2194 LAYER_TRIGGERS:
2195 begin
2196 MainForm.miLayer9.Checked := show;
2197 MainForm.miLayerP9.Checked := show;
2198 end;
2199 end;
2201 RemoveSelectFromObjects();
2202 end;
2204 procedure SwitchLayer(Layer: Byte);
2205 begin
2206 ShowLayer(Layer, not LayerEnabled[Layer]);
2207 end;
2209 procedure SwitchMap();
2210 begin
2211 ShowMap := not ShowMap;
2212 MainForm.tbShowMap.Down := ShowMap;
2213 end;
2215 procedure ShowEdges();
2216 begin
2217 if drEdge[3] < 255 then
2218 drEdge[3] := 255
2219 else
2220 drEdge[3] := gAlphaEdge;
2221 end;
2223 function SelectedTexture(): String;
2224 begin
2225 if MainForm.lbTextureList.ItemIndex <> -1 then
2226 Result := MainForm.lbTextureList.Items[MainForm.lbTextureList.ItemIndex]
2227 else
2228 Result := '';
2229 end;
2231 function IsSpecialTextureSel(): Boolean;
2232 begin
2233 Result := (MainForm.lbTextureList.ItemIndex <> -1) and
2234 IsSpecialTexture(MainForm.lbTextureList.Items[MainForm.lbTextureList.ItemIndex]);
2235 end;
2237 function CopyBufferToString(var CopyBuf: TCopyRecArray): String;
2238 var
2239 i, j: Integer;
2240 Res: String;
2242 procedure AddInt(x: Integer);
2243 begin
2244 Res := Res + IntToStr(x) + ' ';
2245 end;
2247 begin
2248 Result := '';
2250 if Length(CopyBuf) = 0 then
2251 Exit;
2253 Res := CLIPBOARD_SIG + ' ';
2255 for i := 0 to High(CopyBuf) do
2256 begin
2257 if (CopyBuf[i].ObjectType = OBJECT_PANEL) and
2258 (CopyBuf[i].Panel = nil) then
2259 Continue;
2261 // Тип объекта:
2262 AddInt(CopyBuf[i].ObjectType);
2263 Res := Res + '; ';
2265 // Свойства объекта:
2266 case CopyBuf[i].ObjectType of
2267 OBJECT_PANEL:
2268 with CopyBuf[i].Panel^ do
2269 begin
2270 AddInt(PanelType);
2271 AddInt(X);
2272 AddInt(Y);
2273 AddInt(Width);
2274 AddInt(Height);
2275 Res := Res + '"' + TextureName + '" ';
2276 AddInt(Alpha);
2277 AddInt(IfThen(Blending, 1, 0));
2278 end;
2280 OBJECT_ITEM:
2281 with CopyBuf[i].Item do
2282 begin
2283 AddInt(ItemType);
2284 AddInt(X);
2285 AddInt(Y);
2286 AddInt(IfThen(OnlyDM, 1, 0));
2287 AddInt(IfThen(Fall, 1, 0));
2288 end;
2290 OBJECT_MONSTER:
2291 with CopyBuf[i].Monster do
2292 begin
2293 AddInt(MonsterType);
2294 AddInt(X);
2295 AddInt(Y);
2296 AddInt(IfThen(Direction = D_LEFT, 1, 0));
2297 end;
2299 OBJECT_AREA:
2300 with CopyBuf[i].Area do
2301 begin
2302 AddInt(AreaType);
2303 AddInt(X);
2304 AddInt(Y);
2305 AddInt(IfThen(Direction = D_LEFT, 1, 0));
2306 end;
2308 OBJECT_TRIGGER:
2309 with CopyBuf[i].Trigger do
2310 begin
2311 AddInt(TriggerType);
2312 AddInt(X);
2313 AddInt(Y);
2314 AddInt(Width);
2315 AddInt(Height);
2316 AddInt(ActivateType);
2317 AddInt(Key);
2318 AddInt(IfThen(Enabled, 1, 0));
2319 AddInt(TexturePanel);
2321 for j := 0 to 127 do
2322 AddInt(Data.Default[j]);
2323 end;
2324 end;
2325 end;
2327 Result := Res;
2328 end;
2330 procedure StringToCopyBuffer(Str: String; var CopyBuf: TCopyRecArray);
2331 var
2332 i, j, t: Integer;
2334 function GetNext(): String;
2335 var
2336 p: Integer;
2338 begin
2339 if Str[1] = '"' then
2340 begin
2341 Delete(Str, 1, 1);
2342 p := Pos('"', Str);
2344 if p = 0 then
2345 begin
2346 Result := Str;
2347 Str := '';
2348 end
2349 else
2350 begin
2351 Result := Copy(Str, 1, p-1);
2352 Delete(Str, 1, p);
2353 Str := Trim(Str);
2354 end;
2355 end
2356 else
2357 begin
2358 p := Pos(' ', Str);
2360 if p = 0 then
2361 begin
2362 Result := Str;
2363 Str := '';
2364 end
2365 else
2366 begin
2367 Result := Copy(Str, 1, p-1);
2368 Delete(Str, 1, p);
2369 Str := Trim(Str);
2370 end;
2371 end;
2372 end;
2374 begin
2375 Str := Trim(Str);
2377 if GetNext() <> CLIPBOARD_SIG then
2378 Exit;
2380 while Str <> '' do
2381 begin
2382 // Тип объекта:
2383 t := StrToIntDef(GetNext(), 0);
2385 if (t < OBJECT_PANEL) or (t > OBJECT_TRIGGER) or
2386 (GetNext() <> ';') then
2387 begin // Что-то не то => пропускаем:
2388 t := Pos(';', Str);
2389 Delete(Str, 1, t);
2390 Str := Trim(Str);
2392 Continue;
2393 end;
2395 i := Length(CopyBuf);
2396 SetLength(CopyBuf, i + 1);
2398 CopyBuf[i].ObjectType := t;
2399 CopyBuf[i].Panel := nil;
2401 // Свойства объекта:
2402 case t of
2403 OBJECT_PANEL:
2404 begin
2405 New(CopyBuf[i].Panel);
2407 with CopyBuf[i].Panel^ do
2408 begin
2409 PanelType := StrToIntDef(GetNext(), PANEL_WALL);
2410 X := StrToIntDef(GetNext(), 0);
2411 Y := StrToIntDef(GetNext(), 0);
2412 Width := StrToIntDef(GetNext(), 16);
2413 Height := StrToIntDef(GetNext(), 16);
2414 TextureName := GetNext();
2415 Alpha := StrToIntDef(GetNext(), 0);
2416 Blending := (GetNext() = '1');
2417 end;
2418 end;
2420 OBJECT_ITEM:
2421 with CopyBuf[i].Item do
2422 begin
2423 ItemType := StrToIntDef(GetNext(), ITEM_MEDKIT_SMALL);
2424 X := StrToIntDef(GetNext(), 0);
2425 Y := StrToIntDef(GetNext(), 0);
2426 OnlyDM := (GetNext() = '1');
2427 Fall := (GetNext() = '1');
2428 end;
2430 OBJECT_MONSTER:
2431 with CopyBuf[i].Monster do
2432 begin
2433 MonsterType := StrToIntDef(GetNext(), MONSTER_DEMON);
2434 X := StrToIntDef(GetNext(), 0);
2435 Y := StrToIntDef(GetNext(), 0);
2437 if GetNext() = '1' then
2438 Direction := D_LEFT
2439 else
2440 Direction := D_RIGHT;
2441 end;
2443 OBJECT_AREA:
2444 with CopyBuf[i].Area do
2445 begin
2446 AreaType := StrToIntDef(GetNext(), AREA_PLAYERPOINT1);
2447 X := StrToIntDef(GetNext(), 0);
2448 Y := StrToIntDef(GetNext(), 0);
2449 if GetNext() = '1' then
2450 Direction := D_LEFT
2451 else
2452 Direction := D_RIGHT;
2453 end;
2455 OBJECT_TRIGGER:
2456 with CopyBuf[i].Trigger do
2457 begin
2458 TriggerType := StrToIntDef(GetNext(), TRIGGER_EXIT);
2459 X := StrToIntDef(GetNext(), 0);
2460 Y := StrToIntDef(GetNext(), 0);
2461 Width := StrToIntDef(GetNext(), 16);
2462 Height := StrToIntDef(GetNext(), 16);
2463 ActivateType := StrToIntDef(GetNext(), 0);
2464 Key := StrToIntDef(GetNext(), 0);
2465 Enabled := (GetNext() = '1');
2466 TexturePanel := StrToIntDef(GetNext(), 0);
2468 for j := 0 to 127 do
2469 Data.Default[j] := StrToIntDef(GetNext(), 0);
2470 end;
2471 end;
2472 end;
2473 end;
2475 //----------------------------------------
2476 //Закончились вспомогательные процедуры
2477 //----------------------------------------
2479 procedure TMainForm.RefreshRecentMenu();
2480 var
2481 i: Integer;
2482 MI: TMenuItem;
2483 begin
2484 // Лишние запомненные карты:
2485 while RecentFiles.Count > RecentCount do
2486 RecentFiles.Delete(RecentFiles.Count-1);
2488 // Лишние строки меню:
2489 while MainMenu.Items[0].Count > RECENT_FILES_MENU_START do
2490 MainMenu.Items[0].Delete(MainMenu.Items[0].Count-1);
2492 // Отделение списка карт от строки "Выход":
2493 if RecentFiles.Count > 0 then
2494 begin
2495 MI := TMenuItem.Create(MainMenu.Items[0]);
2496 MI.Caption := '-';
2497 MainMenu.Items[0].Add(MI);
2498 end;
2500 // Добавление в меню списка запомненных карт:
2501 for i := 0 to RecentFiles.Count-1 do
2502 begin
2503 MI := TMenuItem.Create(MainMenu.Items[0]);
2504 MI.Caption := IntToStr(i+1) + ' ' + RecentFiles[i];
2505 MI.OnClick := aRecentFileExecute;
2506 MainMenu.Items[0].Add(MI);
2507 end;
2508 end;
2510 procedure TMainForm.aRecentFileExecute(Sender: TObject);
2511 var
2512 n, pw: Integer;
2513 s, fn: String;
2514 b: Boolean;
2515 begin
2516 s := LowerCase((Sender as TMenuItem).Caption);
2517 Delete(s, Pos('&', s), 1);
2518 s := Trim(Copy(s, 1, 2));
2519 n := StrToIntDef(s, 0) - 1;
2521 if (n < 0) or (n >= RecentFiles.Count) then
2522 Exit;
2524 s := RecentFiles[n];
2525 pw := Pos('.wad:\', LowerCase(s));
2526 b := False;
2528 if pw > 0 then
2529 begin // Map name included
2530 fn := Copy(s, 1, pw + 3);
2531 Delete(s, 1, pw + 5);
2532 if (FileExists(fn)) then
2533 begin
2534 OpenMap(fn, s);
2535 b := True;
2536 end;
2537 end
2538 else // Only wad name
2539 if (FileExists(s)) then
2540 begin
2541 OpenMap(s, '');
2542 b := True;
2543 end;
2545 if (not b) and (MessageBox(0, PChar(_lc[I_MSG_DEL_RECENT_PROMT]),
2546 PChar(_lc[I_MSG_DEL_RECENT]), MB_ICONQUESTION or MB_YESNO) = idYes) then
2547 begin
2548 RecentFiles.Delete(n);
2549 RefreshRecentMenu();
2550 end;
2551 end;
2553 procedure TMainForm.aEditorOptionsExecute(Sender: TObject);
2554 begin
2555 OptionsForm.ShowModal();
2556 end;
2558 procedure LoadStdFont(cfgres, texture: string; var FontID: DWORD);
2559 var
2560 cwdt, chgt: Byte;
2561 spc: ShortInt;
2562 ID: DWORD;
2563 wad: TWADEditor_1;
2564 cfgdata: Pointer;
2565 cfglen: Integer;
2566 config: TConfig;
2567 begin
2568 cfgdata := nil;
2569 cfglen := 0;
2570 ID := 0;
2572 wad := TWADEditor_1.Create;
2573 if wad.ReadFile(EditorDir+'data/Game.wad') then
2574 wad.GetResource('FONTS', cfgres, cfgdata, cfglen);
2575 wad.Free();
2577 if cfglen <> 0 then
2578 begin
2579 if not g_CreateTextureWAD('FONT_STD', EditorDir+'data/Game.wad:FONTS\'+texture) then
2580 e_WriteLog('ERROR ERROR ERROR', MSG_WARNING);
2582 config := TConfig.CreateMem(cfgdata, cfglen);
2583 cwdt := Min(Max(config.ReadInt('FontMap', 'CharWidth', 0), 0), 255);
2584 chgt := Min(Max(config.ReadInt('FontMap', 'CharHeight', 0), 0), 255);
2585 spc := Min(Max(config.ReadInt('FontMap', 'Kerning', 0), -128), 127);
2587 if g_GetTexture('FONT_STD', ID) then
2588 e_TextureFontBuild(ID, FontID, cwdt, chgt, spc-2);
2590 config.Free();
2591 end
2592 else
2593 e_WriteLog('Could not load FONT_STD', MSG_WARNING);
2595 if cfglen <> 0 then FreeMem(cfgdata);
2596 end;
2598 procedure TMainForm.FormCreate(Sender: TObject);
2599 var
2600 config: TConfig;
2601 i: Integer;
2602 s: String;
2603 begin
2604 Randomize();
2606 EditorDir := ExtractFilePath(Application.ExeName);
2608 e_InitLog(EditorDir+'Editor.log', WM_NEWFILE);
2610 slInvalidTextures := TStringList.Create;
2612 ShowLayer(LAYER_BACK, True);
2613 ShowLayer(LAYER_WALLS, True);
2614 ShowLayer(LAYER_FOREGROUND, True);
2615 ShowLayer(LAYER_STEPS, True);
2616 ShowLayer(LAYER_WATER, True);
2617 ShowLayer(LAYER_ITEMS, True);
2618 ShowLayer(LAYER_MONSTERS, True);
2619 ShowLayer(LAYER_AREAS, True);
2620 ShowLayer(LAYER_TRIGGERS, True);
2622 ClearMap();
2624 FormCaption := MainForm.Caption;
2625 OpenedMap := '';
2626 OpenedWAD := '';
2628 config := TConfig.CreateFile(EditorDir+'Editor.cfg');
2630 if config.ReadInt('Editor', 'XPos', -1) = -1 then
2631 Position := poDesktopCenter
2632 else begin
2633 Left := config.ReadInt('Editor', 'XPos', Left);
2634 Top := config.ReadInt('Editor', 'YPos', Top);
2635 Width := config.ReadInt('Editor', 'Width', Width);
2636 Height := config.ReadInt('Editor', 'Height', Height);
2637 end;
2638 if config.ReadBool('Editor', 'Maximize', False) then
2639 WindowState := wsMaximized;
2640 ShowMap := config.ReadBool('Editor', 'Minimap', False);
2641 PanelProps.Width := config.ReadInt('Editor', 'PanelProps', PanelProps.ClientWidth);
2642 Splitter1.Left := PanelProps.Left;
2643 PanelObjs.Height := config.ReadInt('Editor', 'PanelObjs', PanelObjs.ClientHeight);
2644 Splitter2.Top := PanelObjs.Top;
2645 StatusBar.Top := PanelObjs.BoundsRect.Bottom;
2646 DotEnable := config.ReadBool('Editor', 'DotEnable', True);
2647 DotColor := config.ReadInt('Editor', 'DotColor', $FFFFFF);
2648 DotStepOne := config.ReadInt('Editor', 'DotStepOne', 16);
2649 DotStepTwo := config.ReadInt('Editor', 'DotStepTwo', 8);
2650 DotStep := config.ReadInt('Editor', 'DotStep', DotStepOne);
2651 DrawTexturePanel := config.ReadBool('Editor', 'DrawTexturePanel', True);
2652 DrawPanelSize := config.ReadBool('Editor', 'DrawPanelSize', True);
2653 BackColor := config.ReadInt('Editor', 'BackColor', $7F6040);
2654 PreviewColor := config.ReadInt('Editor', 'PreviewColor', $00FF00);
2655 gColorEdge := config.ReadInt('Editor', 'EdgeColor', COLOR_EDGE);
2656 gAlphaEdge := config.ReadInt('Editor', 'EdgeAlpha', ALPHA_EDGE);
2657 if gAlphaEdge = 255 then
2658 gAlphaEdge := ALPHA_EDGE;
2659 drEdge[0] := GetRValue(gColorEdge);
2660 drEdge[1] := GetGValue(gColorEdge);
2661 drEdge[2] := GetBValue(gColorEdge);
2662 if not config.ReadBool('Editor', 'EdgeShow', True) then
2663 drEdge[3] := 255
2664 else
2665 drEdge[3] := gAlphaEdge;
2666 gAlphaTriggerLine := config.ReadInt('Editor', 'LineAlpha', ALPHA_LINE);
2667 if gAlphaTriggerLine = 255 then
2668 gAlphaTriggerLine := ALPHA_LINE;
2669 gAlphaTriggerArea := config.ReadInt('Editor', 'TriggerAlpha', ALPHA_AREA);
2670 if gAlphaTriggerArea = 255 then
2671 gAlphaTriggerArea := ALPHA_AREA;
2672 if config.ReadInt('Editor', 'Scale', 0) = 1 then
2673 Scale := 2
2674 else
2675 Scale := 1;
2676 if config.ReadInt('Editor', 'DotSize', 0) = 1 then
2677 DotSize := 2
2678 else
2679 DotSize := 1;
2680 OpenDialog.InitialDir := config.ReadStr('Editor', 'LastOpenDir', EditorDir);
2681 SaveDialog.InitialDir := config.ReadStr('Editor', 'LastSaveDir', EditorDir);
2683 s := config.ReadStr('Editor', 'Language', '');
2684 gLanguage := s;
2686 RecentCount := config.ReadInt('Editor', 'RecentCount', 5);
2687 if RecentCount > 10 then
2688 RecentCount := 10;
2689 if RecentCount < 2 then
2690 RecentCount := 2;
2692 RecentFiles := TStringList.Create();
2693 for i := 0 to RecentCount-1 do
2694 begin
2695 s := config.ReadStr('RecentFiles', IntToStr(i+1), '');
2696 if s <> '' then
2697 RecentFiles.Add(s);
2698 end;
2699 RefreshRecentMenu();
2701 config.Free();
2703 tbShowMap.Down := ShowMap;
2704 tbGridOn.Down := DotEnable;
2705 pcObjects.ActivePageIndex := 0;
2706 Application.Title := _lc[I_EDITOR_TITLE];
2708 Application.OnIdle := OnIdle;
2709 end;
2711 procedure PrintBlack(X, Y: Integer; Text: string; FontID: DWORD);
2712 begin
2713 // NOTE: all the font printing routines assume CP1251
2714 e_TextureFontPrintEx(X, Y, Text, FontID, 0, 0, 0, 1.0);
2715 end;
2717 procedure TMainForm.Draw();
2718 var
2719 x, y: Integer;
2720 a, b: Integer;
2721 ID, PID: DWORD;
2722 Width, Height: Word;
2723 Rect: TRectWH;
2724 ObjCount: Word;
2725 aX, aY, aX2, aY2, XX, ScaleSz: Integer;
2726 begin
2727 ID := 0;
2728 PID := 0;
2729 Width := 0;
2730 Height := 0;
2732 e_BeginRender();
2734 e_Clear(GL_COLOR_BUFFER_BIT,
2735 GetRValue(BackColor)/255,
2736 GetGValue(BackColor)/255,
2737 GetBValue(BackColor)/255);
2739 DrawMap();
2741 ObjCount := SelectedObjectCount();
2743 // Обводим выделенные объекты красной рамкой:
2744 if ObjCount > 0 then
2745 begin
2746 for a := 0 to High(SelectedObjects) do
2747 if SelectedObjects[a].Live then
2748 begin
2749 Rect := ObjectGetRect(SelectedObjects[a].ObjectType, SelectedObjects[a].ID);
2751 with Rect do
2752 begin
2753 e_DrawQuad(X+MapOffset.X, Y+MapOffset.Y,
2754 X+MapOffset.X+Width-1, Y+MapOffset.Y+Height-1,
2755 255, 0, 0);
2757 // Рисуем точки изменения размеров:
2758 if (ObjCount = 1) and
2759 (SelectedObjects[GetFirstSelected].ObjectType in [OBJECT_PANEL, OBJECT_TRIGGER]) then
2760 begin
2761 e_DrawPoint(5, X+MapOffset.X, Y+MapOffset.Y+(Height div 2), 255, 255, 255);
2762 e_DrawPoint(5, X+MapOffset.X+Width-1, Y+MapOffset.Y+(Height div 2), 255, 255, 255);
2763 e_DrawPoint(5, X+MapOffset.X+(Width div 2), Y+MapOffset.Y, 255, 255, 255);
2764 e_DrawPoint(5, X+MapOffset.X+(Width div 2), Y+MapOffset.Y+Height-1, 255, 255, 255);
2766 e_DrawPoint(3, X+MapOffset.X, Y+MapOffset.Y+(Height div 2), 255, 0, 0);
2767 e_DrawPoint(3, X+MapOffset.X+Width-1, Y+MapOffset.Y+(Height div 2), 255, 0, 0);
2768 e_DrawPoint(3, X+MapOffset.X+(Width div 2), Y+MapOffset.Y, 255, 0, 0);
2769 e_DrawPoint(3, X+MapOffset.X+(Width div 2), Y+MapOffset.Y+Height-1, 255, 0, 0);
2770 end;
2771 end;
2772 end;
2773 end;
2775 // Рисуем сетку:
2776 if DotEnable and (PreviewMode = 0) then
2777 begin
2778 if DotSize = 2 then
2779 a := -1
2780 else
2781 a := 0;
2783 for x := 0 to (RenderPanel.Width div DotStep) do
2784 for y := 0 to (RenderPanel.Height div DotStep) do
2785 e_DrawPoint(DotSize, x*DotStep + a, y*DotStep + a,
2786 GetRValue(DotColor),
2787 GetGValue(DotColor),
2788 GetBValue(DotColor));
2789 end;
2791 // Превью текстуры:
2792 if (lbTextureList.ItemIndex <> -1) and (cbPreview.Checked) and
2793 (not IsSpecialTextureSel()) and (PreviewMode = 0) then
2794 begin
2795 if not g_GetTexture(SelectedTexture(), ID) then
2796 g_GetTexture('NOTEXTURE', ID);
2797 g_GetTextureSizeByID(ID, Width, Height);
2798 if g_GetTexture('PREVIEW', PID) then
2799 e_DrawFill(PID, RenderPanel.Width-Width, RenderPanel.Height-Height, Width div 16 + 1, Height div 16 + 1, 0, True, False);
2800 e_Draw(ID, RenderPanel.Width-Width, RenderPanel.Height-Height, 0, True, False);
2801 end;
2803 // Подсказка при выборе точки Телепорта:
2804 if SelectFlag = SELECTFLAG_TELEPORT then
2805 begin
2806 with gTriggers[SelectedObjects[GetFirstSelected()].ID] do
2807 if Data.d2d_teleport then
2808 e_DrawLine(2, MousePos.X-16, MousePos.Y-1,
2809 MousePos.X+16, MousePos.Y-1,
2810 0, 0, 255)
2811 else
2812 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+AreaSize[AREA_DMPOINT].Width-1,
2813 MousePos.Y+AreaSize[AREA_DMPOINT].Height-1, 255, 255, 255);
2815 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 192, 192, 192, 127);
2816 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 255, 255, 255);
2817 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_TELEPORT], gEditorFont);
2818 end;
2820 // Подсказка при выборе точки появления:
2821 if SelectFlag = SELECTFLAG_SPAWNPOINT then
2822 begin
2823 e_DrawLine(2, MousePos.X-16, MousePos.Y-1,
2824 MousePos.X+16, MousePos.Y-1,
2825 0, 0, 255);
2826 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 192, 192, 192, 127);
2827 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 255, 255, 255);
2828 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_SPAWN], gEditorFont);
2829 end;
2831 // Подсказка при выборе панели двери:
2832 if SelectFlag = SELECTFLAG_DOOR then
2833 begin
2834 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 192, 192, 192, 127);
2835 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 255, 255, 255);
2836 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_PANEL_DOOR], gEditorFont);
2837 end;
2839 // Подсказка при выборе панели с текстурой:
2840 if SelectFlag = SELECTFLAG_TEXTURE then
2841 begin
2842 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+196, MousePos.Y+18, 192, 192, 192, 127);
2843 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+196, MousePos.Y+18, 255, 255, 255);
2844 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_PANEL_TEXTURE], gEditorFont);
2845 end;
2847 // Подсказка при выборе панели индикации выстрела:
2848 if SelectFlag = SELECTFLAG_SHOTPANEL then
2849 begin
2850 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+316, MousePos.Y+18, 192, 192, 192, 127);
2851 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+316, MousePos.Y+18, 255, 255, 255);
2852 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_PANEL_SHOT], gEditorFont);
2853 end;
2855 // Подсказка при выборе панели лифта:
2856 if SelectFlag = SELECTFLAG_LIFT then
2857 begin
2858 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 192, 192, 192, 127);
2859 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 255, 255, 255);
2860 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_PANEL_LIFT], gEditorFont);
2861 end;
2863 // Подсказка при выборе монстра:
2864 if SelectFlag = SELECTFLAG_MONSTER then
2865 begin
2866 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+120, MousePos.Y+18, 192, 192, 192, 127);
2867 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+120, MousePos.Y+18, 255, 255, 255);
2868 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_MONSTER], gEditorFont);
2869 end;
2871 // Подсказка при выборе области воздействия:
2872 if DrawPressRect then
2873 begin
2874 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+204, MousePos.Y+18, 192, 192, 192, 127);
2875 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+204, MousePos.Y+18, 255, 255, 255);
2876 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_EXT_AREA], gEditorFont);
2877 end;
2879 // Рисуем текстуры, если чертим панель:
2880 if (MouseAction = MOUSEACTION_DRAWPANEL) and (DrawTexturePanel) and
2881 (lbTextureList.ItemIndex <> -1) and (DrawRect <> nil) and
2882 (lbPanelType.ItemIndex in [0..8]) and not IsSpecialTextureSel() then
2883 begin
2884 if not g_GetTexture(SelectedTexture(), ID) then
2885 g_GetTexture('NOTEXTURE', ID);
2886 g_GetTextureSizeByID(ID, Width, Height);
2887 with DrawRect^ do
2888 e_DrawFill(ID, Min(Left, Right), Min(Top, Bottom), Abs(Right-Left) div Width,
2889 Abs(Bottom-Top) div Height, 0, True, False);
2890 end;
2892 // Прямоугольник выделения:
2893 if DrawRect <> nil then
2894 with DrawRect^ do
2895 e_DrawQuad(Left, Top, Right-1, Bottom-1, 255, 255, 255);
2897 // Чертим мышью панель/триггер или меняем мышью их размер:
2898 if (MouseAction in [MOUSEACTION_DRAWPANEL, MOUSEACTION_DRAWTRIGGER, MOUSEACTION_RESIZE]) and
2899 (DrawPanelSize) then
2900 begin
2901 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+88, MousePos.Y+33, 192, 192, 192, 127);
2902 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+88, MousePos.Y+33, 255, 255, 255);
2904 if MouseAction in [MOUSEACTION_DRAWPANEL, MOUSEACTION_DRAWTRIGGER] then
2905 begin // Чертим новый
2906 PrintBlack(MousePos.X+2, MousePos.Y+2, Format(_glc[I_HINT_WIDTH],
2907 [Abs(MousePos.X-MouseLDownPos.X)]), gEditorFont);
2908 PrintBlack(MousePos.X+2, MousePos.Y+14, Format(_glc[I_HINT_HEIGHT],
2909 [Abs(MousePos.Y-MouseLDownPos.Y)]), gEditorFont);
2910 end
2911 else // Растягиваем существующий
2912 if SelectedObjects[GetFirstSelected].ObjectType in [OBJECT_PANEL, OBJECT_TRIGGER] then
2913 begin
2914 if SelectedObjects[GetFirstSelected].ObjectType = OBJECT_PANEL then
2915 begin
2916 Width := gPanels[SelectedObjects[GetFirstSelected].ID].Width;
2917 Height := gPanels[SelectedObjects[GetFirstSelected].ID].Height;
2918 end
2919 else
2920 begin
2921 Width := gTriggers[SelectedObjects[GetFirstSelected].ID].Width;
2922 Height := gTriggers[SelectedObjects[GetFirstSelected].ID].Height;
2923 end;
2925 PrintBlack(MousePos.X+2, MousePos.Y+2, Format(_glc[I_HINT_WIDTH], [Width]),
2926 gEditorFont);
2927 PrintBlack(MousePos.X+2, MousePos.Y+14, Format(_glc[I_HINT_HEIGHT], [Height]),
2928 gEditorFont);
2929 end;
2930 end;
2932 // Ближайшая к курсору мыши точка на сетке:
2933 e_DrawPoint(3, MousePos.X, MousePos.Y, 0, 0, 255);
2935 // Мини-карта:
2936 if ShowMap then
2937 begin
2938 // Сколько пикселов карты в 1 пикселе мини-карты:
2939 ScaleSz := 16 div Scale;
2940 // Размеры мини-карты:
2941 aX := max(gMapInfo.Width div ScaleSz, 1);
2942 aY := max(gMapInfo.Height div ScaleSz, 1);
2943 // X-координата на RenderPanel нулевой x-координаты карты:
2944 XX := RenderPanel.Width - aX - 1;
2945 // Рамка карты:
2946 e_DrawFillQuad(XX-1, 0, RenderPanel.Width-1, aY+1, 0, 0, 0, 0);
2947 e_DrawQuad(XX-1, 0, RenderPanel.Width-1, aY+1, 197, 197, 197);
2949 if gPanels <> nil then
2950 begin
2951 // Рисуем панели:
2952 for a := 0 to High(gPanels) do
2953 with gPanels[a] do
2954 if PanelType <> 0 then
2955 begin
2956 // Левый верхний угол:
2957 aX := XX + (X div ScaleSz);
2958 aY := 1 + (Y div ScaleSz);
2959 // Размеры:
2960 aX2 := max(Width div ScaleSz, 1);
2961 aY2 := max(Height div ScaleSz, 1);
2962 // Правый нижний угол:
2963 aX2 := aX + aX2 - 1;
2964 aY2 := aY + aY2 - 1;
2966 case PanelType of
2967 PANEL_WALL: e_DrawFillQuad(aX, aY, aX2, aY2, 208, 208, 208, 0);
2968 PANEL_WATER: e_DrawFillQuad(aX, aY, aX2, aY2, 0, 0, 192, 0);
2969 PANEL_ACID1: e_DrawFillQuad(aX, aY, aX2, aY2, 0, 176, 0, 0);
2970 PANEL_ACID2: e_DrawFillQuad(aX, aY, aX2, aY2, 176, 0, 0, 0);
2971 PANEL_STEP: e_DrawFillQuad(aX, aY, aX2, aY2, 128, 128, 128, 0);
2972 PANEL_LIFTUP: e_DrawFillQuad(aX, aY, aX2, aY2, 116, 72, 36, 0);
2973 PANEL_LIFTDOWN: e_DrawFillQuad(aX, aY, aX2, aY2, 116, 124, 96, 0);
2974 PANEL_LIFTLEFT: e_DrawFillQuad(aX, aY, aX2, aY2, 200, 80, 4, 0);
2975 PANEL_LIFTRIGHT: e_DrawFillQuad(aX, aY, aX2, aY2, 252, 140, 56, 0);
2976 PANEL_OPENDOOR: e_DrawFillQuad(aX, aY, aX2, aY2, 100, 220, 92, 0);
2977 PANEL_CLOSEDOOR: e_DrawFillQuad(aX, aY, aX2, aY2, 212, 184, 64, 0);
2978 PANEL_BLOCKMON: e_DrawFillQuad(aX, aY, aX2, aY2, 192, 0, 192, 0);
2979 end;
2980 end;
2982 // Рисуем красным выделенные панели:
2983 if SelectedObjects <> nil then
2984 for b := 0 to High(SelectedObjects) do
2985 with SelectedObjects[b] do
2986 if Live and (ObjectType = OBJECT_PANEL) then
2987 with gPanels[SelectedObjects[b].ID] do
2988 if PanelType and not(PANEL_BACK or PANEL_FORE) <> 0 then
2989 begin
2990 // Левый верхний угол:
2991 aX := XX + (X div ScaleSz);
2992 aY := 1 + (Y div ScaleSz);
2993 // Размеры:
2994 aX2 := max(Width div ScaleSz, 1);
2995 aY2 := max(Height div ScaleSz, 1);
2996 // Правый нижний угол:
2997 aX2 := aX + aX2 - 1;
2998 aY2 := aY + aY2 - 1;
3000 e_DrawFillQuad(aX, aY, aX2, aY2, 255, 0, 0, 0)
3001 end;
3002 end;
3004 if (gMapInfo.Width > RenderPanel.Width) or
3005 (gMapInfo.Height > RenderPanel.Height) then
3006 begin
3007 // Окно, показывающее текущее положение экрана на карте:
3008 // Размеры окна:
3009 x := max(min(RenderPanel.Width, gMapInfo.Width) div ScaleSz, 1);
3010 y := max(min(RenderPanel.Height, gMapInfo.Height) div ScaleSz, 1);
3011 // Левый верхний угол:
3012 aX := XX + ((-MapOffset.X) div ScaleSz);
3013 aY := 1 + ((-MapOffset.Y) div ScaleSz);
3014 // Правый нижний угол:
3015 aX2 := aX + x - 1;
3016 aY2 := aY + y - 1;
3018 e_DrawFillQuad(aX, aY, aX2, aY2, 127, 192, 127, 127, B_BLEND);
3019 e_DrawQuad(aX, aY, aX2, aY2, 255, 0, 0);
3020 end;
3021 end; // Мини-карта
3023 e_EndRender();
3024 RenderPanel.SwapBuffers();
3025 end;
3027 procedure TMainForm.FormResize(Sender: TObject);
3028 begin
3029 e_SetViewPort(0, 0, RenderPanel.Width, RenderPanel.Height);
3031 if gMapInfo.Width >= RenderPanel.Width then
3032 sbHorizontal.Max := Normalize16(gMapInfo.Width-RenderPanel.Width+16)
3033 else
3034 sbHorizontal.Max := 0;
3036 if gMapInfo.Height >= RenderPanel.Height then
3037 sbVertical.Max := Normalize16(gMapInfo.Height-RenderPanel.Height+16)
3038 else
3039 sbVertical.Max := 0;
3041 MapOffset.X := -Normalize16(sbHorizontal.Position);
3042 MapOffset.Y := -Normalize16(sbVertical.Position);
3043 end;
3045 procedure SelectNextObject(X, Y: Integer; ObjectType: Byte; ID: DWORD);
3046 var
3047 j, j_max: Integer;
3048 res: Boolean;
3049 begin
3050 j_max := 0; // shut up compiler
3051 case ObjectType of
3052 OBJECT_PANEL:
3053 begin
3054 res := (gPanels <> nil) and
3055 PanelInShownLayer(gPanels[ID].PanelType) and
3056 g_CollidePoint(X, Y, gPanels[ID].X, gPanels[ID].Y,
3057 gPanels[ID].Width,
3058 gPanels[ID].Height);
3059 j_max := Length(gPanels) - 1;
3060 end;
3062 OBJECT_ITEM:
3063 begin
3064 res := (gItems <> nil) and
3065 LayerEnabled[LAYER_ITEMS] and
3066 g_CollidePoint(X, Y, gItems[ID].X, gItems[ID].Y,
3067 ItemSize[gItems[ID].ItemType][0],
3068 ItemSize[gItems[ID].ItemType][1]);
3069 j_max := Length(gItems) - 1;
3070 end;
3072 OBJECT_MONSTER:
3073 begin
3074 res := (gMonsters <> nil) and
3075 LayerEnabled[LAYER_MONSTERS] and
3076 g_CollidePoint(X, Y, gMonsters[ID].X, gMonsters[ID].Y,
3077 MonsterSize[gMonsters[ID].MonsterType].Width,
3078 MonsterSize[gMonsters[ID].MonsterType].Height);
3079 j_max := Length(gMonsters) - 1;
3080 end;
3082 OBJECT_AREA:
3083 begin
3084 res := (gAreas <> nil) and
3085 LayerEnabled[LAYER_AREAS] and
3086 g_CollidePoint(X, Y, gAreas[ID].X, gAreas[ID].Y,
3087 AreaSize[gAreas[ID].AreaType].Width,
3088 AreaSize[gAreas[ID].AreaType].Height);
3089 j_max := Length(gAreas) - 1;
3090 end;
3092 OBJECT_TRIGGER:
3093 begin
3094 res := (gTriggers <> nil) and
3095 LayerEnabled[LAYER_TRIGGERS] and
3096 g_CollidePoint(X, Y, gTriggers[ID].X, gTriggers[ID].Y,
3097 gTriggers[ID].Width,
3098 gTriggers[ID].Height);
3099 j_max := Length(gTriggers) - 1;
3100 end;
3102 else
3103 res := False;
3104 end;
3106 if not res then
3107 Exit;
3109 // Перебор ID: от ID-1 до 0; потом от High до ID+1:
3110 j := ID;
3112 while True do
3113 begin
3114 Dec(j);
3116 if j < 0 then
3117 j := j_max;
3118 if j = Integer(ID) then
3119 Break;
3121 case ObjectType of
3122 OBJECT_PANEL:
3123 res := PanelInShownLayer(gPanels[j].PanelType) and
3124 g_CollidePoint(X, Y, gPanels[j].X, gPanels[j].Y,
3125 gPanels[j].Width,
3126 gPanels[j].Height);
3127 OBJECT_ITEM:
3128 res := (gItems[j].ItemType <> ITEM_NONE) and
3129 g_CollidePoint(X, Y, gItems[j].X, gItems[j].Y,
3130 ItemSize[gItems[j].ItemType][0],
3131 ItemSize[gItems[j].ItemType][1]);
3132 OBJECT_MONSTER:
3133 res := (gMonsters[j].MonsterType <> MONSTER_NONE) and
3134 g_CollidePoint(X, Y, gMonsters[j].X, gMonsters[j].Y,
3135 MonsterSize[gMonsters[j].MonsterType].Width,
3136 MonsterSize[gMonsters[j].MonsterType].Height);
3137 OBJECT_AREA:
3138 res := (gAreas[j].AreaType <> AREA_NONE) and
3139 g_CollidePoint(X, Y, gAreas[j].X, gAreas[j].Y,
3140 AreaSize[gAreas[j].AreaType].Width,
3141 AreaSize[gAreas[j].AreaType].Height);
3142 OBJECT_TRIGGER:
3143 res := (gTriggers[j].TriggerType <> TRIGGER_NONE) and
3144 g_CollidePoint(X, Y, gTriggers[j].X, gTriggers[j].Y,
3145 gTriggers[j].Width,
3146 gTriggers[j].Height);
3147 else
3148 res := False;
3149 end;
3151 if res then
3152 begin
3153 SetLength(SelectedObjects, 1);
3155 SelectedObjects[0].ObjectType := ObjectType;
3156 SelectedObjects[0].ID := j;
3157 SelectedObjects[0].Live := True;
3159 FillProperty();
3160 Break;
3161 end;
3162 end;
3163 end;
3165 procedure TMainForm.RenderPanelMouseDown(Sender: TObject;
3166 Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
3167 var
3168 i: Integer;
3169 Rect: TRectWH;
3170 c1, c2, c3, c4: Boolean;
3171 item: TItem;
3172 area: TArea;
3173 monster: TMonster;
3174 IDArray: DWArray;
3175 begin
3176 MainForm.ActiveControl := RenderPanel;
3177 RenderPanel.SetFocus();
3179 RenderPanelMouseMove(RenderPanel, Shift, X, Y);
3181 if Button = mbLeft then // Left Mouse Button
3182 begin
3183 // Двигаем карту с помощью мыши и мини-карты:
3184 if ShowMap and
3185 g_CollidePoint(X, Y,
3186 RenderPanel.Width-max(gMapInfo.Width div (16 div Scale), 1)-1,
3187 1,
3188 max(gMapInfo.Width div (16 div Scale), 1),
3189 max(gMapInfo.Height div (16 div Scale), 1) ) then
3190 begin
3191 MoveMap(X, Y);
3192 MouseAction := MOUSEACTION_MOVEMAP;
3193 end
3194 else // Ставим предмет/монстра/область:
3195 if (pcObjects.ActivePageIndex in [1, 2, 3]) and
3196 (not (ssShift in Shift)) then
3197 begin
3198 case pcObjects.ActivePageIndex of
3199 1:
3200 if lbItemList.ItemIndex = -1 then
3201 ErrorMessageBox(_lc[I_MSG_CHOOSE_ITEM])
3202 else
3203 begin
3204 item.ItemType := lbItemList.ItemIndex + ITEM_MEDKIT_SMALL;
3205 if item.ItemType >= ITEM_WEAPON_KASTET then
3206 item.ItemType := item.ItemType + 2;
3207 item.X := MousePos.X-MapOffset.X;
3208 item.Y := MousePos.Y-MapOffset.Y;
3210 if not (ssCtrl in Shift) then
3211 begin
3212 item.X := item.X - (ItemSize[item.ItemType][0] div 2);
3213 item.Y := item.Y - ItemSize[item.ItemType][1];
3214 end;
3216 item.OnlyDM := cbOnlyDM.Checked;
3217 item.Fall := cbFall.Checked;
3218 Undo_Add(OBJECT_ITEM, AddItem(item));
3219 end;
3220 2:
3221 if lbMonsterList.ItemIndex = -1 then
3222 ErrorMessageBox(_lc[I_MSG_CHOOSE_MONSTER])
3223 else
3224 begin
3225 monster.MonsterType := lbMonsterList.ItemIndex + MONSTER_DEMON;
3226 monster.X := MousePos.X-MapOffset.X;
3227 monster.Y := MousePos.Y-MapOffset.Y;
3229 if not (ssCtrl in Shift) then
3230 begin
3231 monster.X := monster.X - (MonsterSize[monster.MonsterType].Width div 2);
3232 monster.Y := monster.Y - MonsterSize[monster.MonsterType].Height;
3233 end;
3235 if rbMonsterLeft.Checked then
3236 monster.Direction := D_LEFT
3237 else
3238 monster.Direction := D_RIGHT;
3239 Undo_Add(OBJECT_MONSTER, AddMonster(monster));
3240 end;
3241 3:
3242 if lbAreasList.ItemIndex = -1 then
3243 ErrorMessageBox(_lc[I_MSG_CHOOSE_AREA])
3244 else
3245 if (lbAreasList.ItemIndex + 1) <> AREA_DOMFLAG then
3246 begin
3247 area.AreaType := lbAreasList.ItemIndex + AREA_PLAYERPOINT1;
3248 area.X := MousePos.X-MapOffset.X;
3249 area.Y := MousePos.Y-MapOffset.Y;
3251 if not (ssCtrl in Shift) then
3252 begin
3253 area.X := area.X - (AreaSize[area.AreaType].Width div 2);
3254 area.Y := area.Y - AreaSize[area.AreaType].Height;
3255 end;
3257 if rbAreaLeft.Checked then
3258 area.Direction := D_LEFT
3259 else
3260 area.Direction := D_RIGHT;
3261 Undo_Add(OBJECT_AREA, AddArea(area));
3262 end;
3263 end;
3264 end
3265 else
3266 begin
3267 i := GetFirstSelected();
3269 // Выбираем объект под текущим:
3270 if (SelectedObjects <> nil) and
3271 (ssShift in Shift) and (i >= 0) and
3272 (SelectedObjects[i].Live) then
3273 begin
3274 if SelectedObjectCount() = 1 then
3275 SelectNextObject(X-MapOffset.X, Y-MapOffset.Y,
3276 SelectedObjects[i].ObjectType,
3277 SelectedObjects[i].ID);
3278 end
3279 else
3280 begin
3281 // Рисуем область триггера "Расширитель":
3282 if DrawPressRect and (i >= 0) and
3283 (SelectedObjects[i].ObjectType = OBJECT_TRIGGER) and
3284 (gTriggers[SelectedObjects[i].ID].TriggerType in
3285 [TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF]) then
3286 MouseAction := MOUSEACTION_DRAWPRESS
3287 else // Рисуем панель:
3288 if pcObjects.ActivePageIndex = 0 then
3289 begin
3290 if (lbPanelType.ItemIndex >= 0) then
3291 MouseAction := MOUSEACTION_DRAWPANEL
3292 end
3293 else // Рисуем триггер:
3294 if (lbTriggersList.ItemIndex >= 0) then
3295 begin
3296 MouseAction := MOUSEACTION_DRAWTRIGGER;
3297 end;
3298 end;
3299 end;
3300 end; // if Button = mbLeft
3302 if Button = mbRight then // Right Mouse Button
3303 begin
3304 // Клик по мини-карте:
3305 if ShowMap and
3306 g_CollidePoint(X, Y,
3307 RenderPanel.Width-max(gMapInfo.Width div (16 div Scale), 1)-1,
3308 1,
3309 max(gMapInfo.Width div (16 div Scale), 1),
3310 max(gMapInfo.Height div (16 div Scale), 1) ) then
3311 begin
3312 MouseAction := MOUSEACTION_NOACTION;
3313 end
3314 else // Нужно что-то выбрать мышью:
3315 if SelectFlag <> SELECTFLAG_NONE then
3316 begin
3317 case SelectFlag of
3318 SELECTFLAG_TELEPORT:
3319 // Точку назначения телепортации:
3320 with gTriggers[SelectedObjects[
3321 GetFirstSelected() ].ID].Data.TargetPoint do
3322 begin
3323 X := MousePos.X-MapOffset.X;
3324 Y := MousePos.Y-MapOffset.Y;
3325 end;
3327 SELECTFLAG_SPAWNPOINT:
3328 // Точку создания монстра:
3329 with gTriggers[SelectedObjects[GetFirstSelected()].ID] do
3330 if TriggerType = TRIGGER_SPAWNMONSTER then
3331 begin
3332 Data.MonPos.X := MousePos.X-MapOffset.X;
3333 Data.MonPos.Y := MousePos.Y-MapOffset.Y;
3334 end
3335 else if TriggerType = TRIGGER_SPAWNITEM then
3336 begin // Точка создания предмета:
3337 Data.ItemPos.X := MousePos.X-MapOffset.X;
3338 Data.ItemPos.Y := MousePos.Y-MapOffset.Y;
3339 end
3340 else if TriggerType = TRIGGER_SHOT then
3341 begin // Точка создания выстрела:
3342 Data.ShotPos.X := MousePos.X-MapOffset.X;
3343 Data.ShotPos.Y := MousePos.Y-MapOffset.Y;
3344 end;
3346 SELECTFLAG_DOOR:
3347 // Дверь:
3348 begin
3349 IDArray := ObjectInRect(X-MapOffset.X,
3350 Y-MapOffset.Y,
3351 2, 2, OBJECT_PANEL, True);
3352 if IDArray <> nil then
3353 begin
3354 for i := 0 to High(IDArray) do
3355 if (gPanels[IDArray[i]].PanelType = PANEL_OPENDOOR) or
3356 (gPanels[IDArray[i]].PanelType = PANEL_CLOSEDOOR) then
3357 begin
3358 gTriggers[SelectedObjects[
3359 GetFirstSelected() ].ID].Data.PanelID := IDArray[i];
3360 Break;
3361 end;
3362 end
3363 else
3364 gTriggers[SelectedObjects[
3365 GetFirstSelected() ].ID].Data.PanelID := -1;
3366 end;
3368 SELECTFLAG_TEXTURE:
3369 // Панель с текстурой:
3370 begin
3371 IDArray := ObjectInRect(X-MapOffset.X,
3372 Y-MapOffset.Y,
3373 2, 2, OBJECT_PANEL, True);
3374 if IDArray <> nil then
3375 begin
3376 for i := 0 to High(IDArray) do
3377 if ((gPanels[IDArray[i]].PanelType in
3378 [PANEL_WALL, PANEL_BACK, PANEL_FORE,
3379 PANEL_WATER, PANEL_ACID1, PANEL_ACID2,
3380 PANEL_STEP]) or
3381 (gPanels[IDArray[i]].PanelType = PANEL_OPENDOOR) or
3382 (gPanels[IDArray[i]].PanelType = PANEL_CLOSEDOOR)) and
3383 (gPanels[IDArray[i]].TextureName <> '') then
3384 begin
3385 gTriggers[SelectedObjects[
3386 GetFirstSelected() ].ID].TexturePanel := IDArray[i];
3387 Break;
3388 end;
3389 end
3390 else
3391 gTriggers[SelectedObjects[
3392 GetFirstSelected() ].ID].TexturePanel := -1;
3393 end;
3395 SELECTFLAG_LIFT:
3396 // Лифт:
3397 begin
3398 IDArray := ObjectInRect(X-MapOffset.X,
3399 Y-MapOffset.Y,
3400 2, 2, OBJECT_PANEL, True);
3401 if IDArray <> nil then
3402 begin
3403 for i := 0 to High(IDArray) do
3404 if (gPanels[IDArray[i]].PanelType = PANEL_LIFTUP) or
3405 (gPanels[IDArray[i]].PanelType = PANEL_LIFTDOWN) or
3406 (gPanels[IDArray[i]].PanelType = PANEL_LIFTLEFT) or
3407 (gPanels[IDArray[i]].PanelType = PANEL_LIFTRIGHT) then
3408 begin
3409 gTriggers[SelectedObjects[
3410 GetFirstSelected() ].ID].Data.PanelID := IDArray[i];
3411 Break;
3412 end;
3413 end
3414 else
3415 gTriggers[SelectedObjects[
3416 GetFirstSelected() ].ID].Data.PanelID := -1;
3417 end;
3419 SELECTFLAG_MONSTER:
3420 // Монстра:
3421 begin
3422 IDArray := ObjectInRect(X-MapOffset.X,
3423 Y-MapOffset.Y,
3424 2, 2, OBJECT_MONSTER, False);
3425 if IDArray <> nil then
3426 gTriggers[SelectedObjects[
3427 GetFirstSelected() ].ID].Data.MonsterID := IDArray[0]+1
3428 else
3429 gTriggers[SelectedObjects[
3430 GetFirstSelected() ].ID].Data.MonsterID := 0;
3431 end;
3433 SELECTFLAG_SHOTPANEL:
3434 // Панель индикации выстрела:
3435 begin
3436 if gTriggers[SelectedObjects[
3437 GetFirstSelected() ].ID].TriggerType = TRIGGER_SHOT then
3438 begin
3439 IDArray := ObjectInRect(X-MapOffset.X,
3440 Y-MapOffset.Y,
3441 2, 2, OBJECT_PANEL, True);
3442 if IDArray <> nil then
3443 begin
3444 for i := 0 to High(IDArray) do
3445 if ((gPanels[IDArray[i]].PanelType in
3446 [PANEL_WALL, PANEL_BACK, PANEL_FORE,
3447 PANEL_WATER, PANEL_ACID1, PANEL_ACID2,
3448 PANEL_STEP]) or
3449 (gPanels[IDArray[i]].PanelType = PANEL_OPENDOOR) or
3450 (gPanels[IDArray[i]].PanelType = PANEL_CLOSEDOOR)) and
3451 (gPanels[IDArray[i]].TextureName <> '') then
3452 begin
3453 gTriggers[SelectedObjects[
3454 GetFirstSelected() ].ID].Data.ShotPanelID := IDArray[i];
3455 Break;
3456 end;
3457 end
3458 else
3459 gTriggers[SelectedObjects[
3460 GetFirstSelected() ].ID].Data.ShotPanelID := -1;
3461 end;
3462 end;
3463 end;
3465 SelectFlag := SELECTFLAG_SELECTED;
3466 end
3467 else // if SelectFlag <> SELECTFLAG_NONE...
3468 begin
3469 // Что уже выбрано и не нажат Ctrl:
3470 if (SelectedObjects <> nil) and
3471 (not (ssCtrl in Shift)) then
3472 for i := 0 to High(SelectedObjects) do
3473 with SelectedObjects[i] do
3474 if Live then
3475 begin
3476 if (ObjectType in [OBJECT_PANEL, OBJECT_TRIGGER]) and
3477 (SelectedObjectCount() = 1) then
3478 begin
3479 Rect := ObjectGetRect(ObjectType, ID);
3481 c1 := g_Collide(X-MapOffset.X-1, Y-MapOffset.Y-1, 2, 2,
3482 Rect.X-2, Rect.Y+(Rect.Height div 2)-2, 4, 4);
3483 c2 := g_Collide(X-MapOffset.X-1, Y-MapOffset.Y-1, 2, 2,
3484 Rect.X+Rect.Width-3, Rect.Y+(Rect.Height div 2)-2, 4, 4);
3485 c3 := g_Collide(X-MapOffset.X-1, Y-MapOffset.Y-1, 2, 2,
3486 Rect.X+(Rect.Width div 2)-2, Rect.Y-2, 4, 4);
3487 c4 := g_Collide(X-MapOffset.X-1, Y-MapOffset.Y-1, 2, 2,
3488 Rect.X+(Rect.Width div 2)-2, Rect.Y+Rect.Height-3, 4, 4);
3490 // Меняем размер панели или триггера:
3491 if c1 or c2 or c3 or c4 then
3492 begin
3493 MouseAction := MOUSEACTION_RESIZE;
3494 LastMovePoint := MousePos;
3496 if c1 or c2 then
3497 begin // Шире/уже
3498 ResizeType := RESIZETYPE_HORIZONTAL;
3499 if c1 then
3500 ResizeDirection := RESIZEDIR_LEFT
3501 else
3502 ResizeDirection := RESIZEDIR_RIGHT;
3503 RenderPanel.Cursor := crSizeWE;
3504 end
3505 else
3506 begin // Выше/ниже
3507 ResizeType := RESIZETYPE_VERTICAL;
3508 if c3 then
3509 ResizeDirection := RESIZEDIR_UP
3510 else
3511 ResizeDirection := RESIZEDIR_DOWN;
3512 RenderPanel.Cursor := crSizeNS;
3513 end;
3515 Break;
3516 end;
3517 end;
3519 // Перемещаем панель или триггер:
3520 if ObjectCollide(ObjectType, ID,
3521 X-MapOffset.X-1,
3522 Y-MapOffset.Y-1, 2, 2) then
3523 begin
3524 MouseAction := MOUSEACTION_MOVEOBJ;
3525 LastMovePoint := MousePos;
3527 Break;
3528 end;
3529 end;
3530 end;
3531 end; // if Button = mbRight
3533 MouseRDown := Button = mbRight;
3534 if MouseRDown then
3535 MouseRDownPos := MousePos;
3537 MouseLDown := Button = mbLeft;
3538 if MouseLDown then
3539 MouseLDownPos := MousePos;
3540 end;
3542 procedure TMainForm.RenderPanelMouseUp(Sender: TObject;
3543 Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
3544 var
3545 panel: TPanel;
3546 trigger: TTrigger;
3547 i: Integer;
3548 IDArray: DWArray;
3549 rRect: TRectWH;
3550 rSelectRect: Boolean;
3551 begin
3552 if Button = mbLeft then
3553 MouseLDown := False;
3554 if Button = mbRight then
3555 MouseRDown := False;
3557 DrawRect := nil;
3558 ResizeType := RESIZETYPE_NONE;
3560 if Button = mbLeft then // Left Mouse Button
3561 begin
3562 if MouseAction <> MOUSEACTION_NONE then
3563 begin // Было действие мышью
3564 // Мышь сдвинулась во время удержания клавиши:
3565 if (MousePos.X <> MouseLDownPos.X) and
3566 (MousePos.Y <> MouseLDownPos.Y) then
3567 case MouseAction of
3568 // Рисовали панель:
3569 MOUSEACTION_DRAWPANEL:
3570 begin
3571 // Фон или передний план без текстуры - ошибка:
3572 if (lbPanelType.ItemIndex in [1, 2]) and
3573 (lbTextureList.ItemIndex = -1) then
3574 ErrorMessageBox(_lc[I_MSG_CHOOSE_TEXTURE])
3575 else // Назначаем параметры панели:
3576 begin
3577 case lbPanelType.ItemIndex of
3578 0: Panel.PanelType := PANEL_WALL;
3579 1: Panel.PanelType := PANEL_BACK;
3580 2: Panel.PanelType := PANEL_FORE;
3581 3: Panel.PanelType := PANEL_OPENDOOR;
3582 4: Panel.PanelType := PANEL_CLOSEDOOR;
3583 5: Panel.PanelType := PANEL_STEP;
3584 6: Panel.PanelType := PANEL_WATER;
3585 7: Panel.PanelType := PANEL_ACID1;
3586 8: Panel.PanelType := PANEL_ACID2;
3587 9: Panel.PanelType := PANEL_LIFTUP;
3588 10: Panel.PanelType := PANEL_LIFTDOWN;
3589 11: Panel.PanelType := PANEL_LIFTLEFT;
3590 12: Panel.PanelType := PANEL_LIFTRIGHT;
3591 13: Panel.PanelType := PANEL_BLOCKMON;
3592 end;
3594 Panel.X := Min(MousePos.X-MapOffset.X, MouseLDownPos.X-MapOffset.X);
3595 Panel.Y := Min(MousePos.Y-MapOffset.Y, MouseLDownPos.Y-MapOffset.Y);
3596 Panel.Width := Abs(MousePos.X-MouseLDownPos.X);
3597 Panel.Height := Abs(MousePos.Y-MouseLDownPos.Y);
3599 // Лифты, блокМон или отсутствие текстуры - пустая текстура:
3600 if (lbPanelType.ItemIndex in [9, 10, 11, 12, 13]) or
3601 (lbTextureList.ItemIndex = -1) then
3602 begin
3603 Panel.TextureHeight := 1;
3604 Panel.TextureWidth := 1;
3605 Panel.TextureName := '';
3606 Panel.TextureID := TEXTURE_SPECIAL_NONE;
3607 end
3608 else // Есть текстура:
3609 begin
3610 Panel.TextureName := SelectedTexture();
3612 // Обычная текстура:
3613 if not IsSpecialTextureSel() then
3614 begin
3615 g_GetTextureSizeByName(Panel.TextureName,
3616 Panel.TextureWidth, Panel.TextureHeight);
3617 g_GetTexture(Panel.TextureName, Panel.TextureID);
3618 end
3619 else // Спец.текстура:
3620 begin
3621 Panel.TextureHeight := 1;
3622 Panel.TextureWidth := 1;
3623 Panel.TextureID := SpecialTextureID(SelectedTexture());
3624 end;
3625 end;
3627 Panel.Alpha := 0;
3628 Panel.Blending := False;
3630 Undo_Add(OBJECT_PANEL, AddPanel(Panel));
3631 end;
3632 end;
3634 // Рисовали триггер:
3635 MOUSEACTION_DRAWTRIGGER:
3636 begin
3637 trigger.X := Min(MousePos.X-MapOffset.X, MouseLDownPos.X-MapOffset.X);
3638 trigger.Y := Min(MousePos.Y-MapOffset.Y, MouseLDownPos.Y-MapOffset.Y);
3639 trigger.Width := Abs(MousePos.X-MouseLDownPos.X);
3640 trigger.Height := Abs(MousePos.Y-MouseLDownPos.Y);
3642 trigger.Enabled := True;
3643 trigger.TriggerType := lbTriggersList.ItemIndex+1;
3644 trigger.TexturePanel := -1;
3646 // Типы активации:
3647 trigger.ActivateType := 0;
3649 if clbActivationType.Checked[0] then
3650 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_PLAYERCOLLIDE;
3651 if clbActivationType.Checked[1] then
3652 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_MONSTERCOLLIDE;
3653 if clbActivationType.Checked[2] then
3654 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_PLAYERPRESS;
3655 if clbActivationType.Checked[3] then
3656 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_MONSTERPRESS;
3657 if clbActivationType.Checked[4] then
3658 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_SHOT;
3659 if clbActivationType.Checked[5] then
3660 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_NOMONSTER;
3662 // Необходимые для активации ключи:
3663 trigger.Key := 0;
3665 if clbKeys.Checked[0] then
3666 trigger.Key := Trigger.Key or KEY_RED;
3667 if clbKeys.Checked[1] then
3668 trigger.Key := Trigger.Key or KEY_GREEN;
3669 if clbKeys.Checked[2] then
3670 trigger.Key := Trigger.Key or KEY_BLUE;
3671 if clbKeys.Checked[3] then
3672 trigger.Key := Trigger.Key or KEY_REDTEAM;
3673 if clbKeys.Checked[4] then
3674 trigger.Key := Trigger.Key or KEY_BLUETEAM;
3676 // Параметры триггера:
3677 FillByte(trigger.Data.Default[0], 128, 0);
3679 case trigger.TriggerType of
3680 // Переключаемая панель:
3681 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
3682 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP,
3683 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
3684 begin
3685 Trigger.Data.PanelID := -1;
3686 end;
3688 // Телепортация:
3689 TRIGGER_TELEPORT:
3690 begin
3691 trigger.Data.TargetPoint.X := trigger.X-64;
3692 trigger.Data.TargetPoint.Y := trigger.Y-64;
3693 trigger.Data.d2d_teleport := True;
3694 trigger.Data.TlpDir := 0;
3695 end;
3697 // Изменение других триггеров:
3698 TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF,
3699 TRIGGER_ONOFF:
3700 begin
3701 trigger.Data.Count := 1;
3702 end;
3704 // Звук:
3705 TRIGGER_SOUND:
3706 begin
3707 trigger.Data.Volume := 255;
3708 trigger.Data.Pan := 127;
3709 trigger.Data.PlayCount := 1;
3710 trigger.Data.Local := True;
3711 trigger.Data.SoundSwitch := False;
3712 end;
3714 // Музыка:
3715 TRIGGER_MUSIC:
3716 begin
3717 trigger.Data.MusicAction := 1;
3718 end;
3720 // Создание монстра:
3721 TRIGGER_SPAWNMONSTER:
3722 begin
3723 trigger.Data.MonType := MONSTER_ZOMBY;
3724 trigger.Data.MonPos.X := trigger.X-64;
3725 trigger.Data.MonPos.Y := trigger.Y-64;
3726 trigger.Data.MonHealth := 0;
3727 trigger.Data.MonActive := False;
3728 trigger.Data.MonCount := 1;
3729 end;
3731 // Создание предмета:
3732 TRIGGER_SPAWNITEM:
3733 begin
3734 trigger.Data.ItemType := ITEM_AMMO_BULLETS;
3735 trigger.Data.ItemPos.X := trigger.X-64;
3736 trigger.Data.ItemPos.Y := trigger.Y-64;
3737 trigger.Data.ItemOnlyDM := False;
3738 trigger.Data.ItemFalls := False;
3739 trigger.Data.ItemCount := 1;
3740 trigger.Data.ItemMax := 0;
3741 trigger.Data.ItemDelay := 0;
3742 end;
3744 // Ускорение:
3745 TRIGGER_PUSH:
3746 begin
3747 trigger.Data.PushAngle := 90;
3748 trigger.Data.PushForce := 10;
3749 trigger.Data.ResetVel := True;
3750 end;
3752 TRIGGER_SCORE:
3753 begin
3754 trigger.Data.ScoreCount := 1;
3755 trigger.Data.ScoreCon := True;
3756 trigger.Data.ScoreMsg := True;
3757 end;
3759 TRIGGER_MESSAGE:
3760 begin
3761 trigger.Data.MessageKind := 0;
3762 trigger.Data.MessageSendTo := 0;
3763 trigger.Data.MessageText := '';
3764 trigger.Data.MessageTime := 144;
3765 end;
3767 TRIGGER_DAMAGE:
3768 begin
3769 trigger.Data.DamageValue := 5;
3770 trigger.Data.DamageInterval := 12;
3771 end;
3773 TRIGGER_HEALTH:
3774 begin
3775 trigger.Data.HealValue := 5;
3776 trigger.Data.HealInterval := 36;
3777 end;
3779 TRIGGER_SHOT:
3780 begin
3781 trigger.Data.ShotType := TRIGGER_SHOT_BULLET;
3782 trigger.Data.ShotSound := True;
3783 trigger.Data.ShotPanelID := -1;
3784 trigger.Data.ShotTarget := 0;
3785 trigger.Data.ShotIntSight := 0;
3786 trigger.Data.ShotAim := TRIGGER_SHOT_AIM_DEFAULT;
3787 trigger.Data.ShotPos.X := trigger.X-64;
3788 trigger.Data.ShotPos.Y := trigger.Y-64;
3789 trigger.Data.ShotAngle := 0;
3790 trigger.Data.ShotWait := 18;
3791 trigger.Data.ShotAccuracy := 0;
3792 trigger.Data.ShotAmmo := 0;
3793 trigger.Data.ShotIntReload := 0;
3794 end;
3796 TRIGGER_EFFECT:
3797 begin
3798 trigger.Data.FXCount := 1;
3799 trigger.Data.FXType := TRIGGER_EFFECT_PARTICLE;
3800 trigger.Data.FXSubType := TRIGGER_EFFECT_SLIQUID;
3801 trigger.Data.FXColorR := 0;
3802 trigger.Data.FXColorG := 0;
3803 trigger.Data.FXColorB := 255;
3804 trigger.Data.FXPos := TRIGGER_EFFECT_POS_CENTER;
3805 trigger.Data.FXWait := 1;
3806 trigger.Data.FXVelX := 0;
3807 trigger.Data.FXVelY := -20;
3808 trigger.Data.FXSpreadL := 5;
3809 trigger.Data.FXSpreadR := 5;
3810 trigger.Data.FXSpreadU := 4;
3811 trigger.Data.FXSpreadD := 0;
3812 end;
3813 end;
3815 Undo_Add(OBJECT_TRIGGER, AddTrigger(trigger));
3816 end;
3818 // Рисовали область триггера "Расширитель":
3819 MOUSEACTION_DRAWPRESS:
3820 with gTriggers[SelectedObjects[GetFirstSelected].ID] do
3821 begin
3822 Data.tX := Min(MousePos.X-MapOffset.X, MouseLDownPos.X-MapOffset.X);
3823 Data.tY := Min(MousePos.Y-MapOffset.Y, MouseLDownPos.Y-MapOffset.Y);
3824 Data.tWidth := Abs(MousePos.X-MouseLDownPos.X);
3825 Data.tHeight := Abs(MousePos.Y-MouseLDownPos.Y);
3827 DrawPressRect := False;
3828 end;
3829 end;
3831 MouseAction := MOUSEACTION_NONE;
3832 end;
3833 end // if Button = mbLeft...
3834 else // Right Mouse Button:
3835 begin
3836 if MouseAction = MOUSEACTION_NOACTION then
3837 begin
3838 MouseAction := MOUSEACTION_NONE;
3839 Exit;
3840 end;
3842 // Объект передвинут или изменен в размере:
3843 if MouseAction in [MOUSEACTION_MOVEOBJ, MOUSEACTION_RESIZE] then
3844 begin
3845 MouseAction := MOUSEACTION_NONE;
3846 FillProperty();
3847 Exit;
3848 end;
3850 // Еще не все выбрали:
3851 if SelectFlag <> SELECTFLAG_NONE then
3852 begin
3853 if SelectFlag = SELECTFLAG_SELECTED then
3854 SelectFlag := SELECTFLAG_NONE;
3855 FillProperty();
3856 Exit;
3857 end;
3859 // Мышь сдвинулась во время удержания клавиши:
3860 if (MousePos.X <> MouseRDownPos.X) and
3861 (MousePos.Y <> MouseRDownPos.Y) then
3862 begin
3863 rSelectRect := True;
3865 rRect.X := Min(MousePos.X, MouseRDownPos.X)-MapOffset.X;
3866 rRect.Y := Min(MousePos.Y, MouseRDownPos.Y)-MapOffset.Y;
3867 rRect.Width := Abs(MousePos.X-MouseRDownPos.X);
3868 rRect.Height := Abs(MousePos.Y-MouseRDownPos.Y);
3869 end
3870 else // Мышь не сдвинулась - нет прямоугольника:
3871 begin
3872 rSelectRect := False;
3874 rRect.X := X-MapOffset.X-1;
3875 rRect.Y := Y-MapOffset.Y-1;
3876 rRect.Width := 2;
3877 rRect.Height := 2;
3878 end;
3880 // Если зажат Ctrl - выделять еще, иначе только один выделенный объект:
3881 if not (ssCtrl in Shift) then
3882 RemoveSelectFromObjects();
3884 // Выделяем всё в выбранном прямоугольнике:
3885 IDArray := ObjectInRect(rRect.X, rRect.Y,
3886 rRect.Width, rRect.Height,
3887 pcObjects.ActivePageIndex+1, rSelectRect);
3889 if IDArray <> nil then
3890 for i := 0 to High(IDArray) do
3891 SelectObject(pcObjects.ActivePageIndex+1, IDArray[i],
3892 (ssCtrl in Shift) or rSelectRect);
3894 FillProperty();
3895 end;
3896 end;
3898 procedure TMainForm.RenderPanelPaint(Sender: TObject);
3899 begin
3900 Draw();
3901 end;
3903 procedure TMainForm.RenderPanelMouseMove(Sender: TObject;
3904 Shift: TShiftState; X, Y: Integer);
3905 var
3906 sX, sY: Integer;
3907 dWidth, dHeight: Integer;
3908 _id: Integer;
3909 begin
3910 _id := GetFirstSelected();
3912 // Рисуем панель с текстурой, сетка - размеры текстуры:
3913 if (MouseAction = MOUSEACTION_DRAWPANEL) and
3914 (lbPanelType.ItemIndex in [0..8]) and
3915 (lbTextureList.ItemIndex <> -1) and
3916 (not IsSpecialTextureSel()) then
3917 begin
3918 sX := StrToIntDef(lTextureWidth.Caption, DotStep);
3919 sY := StrToIntDef(lTextureHeight.Caption, DotStep);
3920 end
3921 else
3922 // Меняем размер панели с текстурой, сетка - размеры текстуры:
3923 if (MouseAction = MOUSEACTION_RESIZE) and
3924 ( (SelectedObjects[_id].ObjectType = OBJECT_PANEL) and
3925 IsTexturedPanel(gPanels[SelectedObjects[_id].ID].PanelType) and
3926 (gPanels[SelectedObjects[_id].ID].TextureName <> '') and
3927 (not IsSpecialTexture(gPanels[SelectedObjects[_id].ID].TextureName)) ) then
3928 begin
3929 sX := gPanels[SelectedObjects[_id].ID].TextureWidth;
3930 sY := gPanels[SelectedObjects[_id].ID].TextureHeight;
3931 end
3932 else
3933 // Выравнивание по сетке:
3934 if SnapToGrid then
3935 begin
3936 sX := DotStep;
3937 sY := DotStep;
3938 end
3939 else // Нет выравнивания по сетке:
3940 begin
3941 sX := 1;
3942 sY := 1;
3943 end;
3945 // Новая позиция мыши:
3946 if MouseLDown then
3947 begin // Зажата левая кнопка мыши
3948 MousePos.X := (Round((X-MouseLDownPos.X)/sX)*sX)+MouseLDownPos.X;
3949 MousePos.Y := (Round((Y-MouseLDownPos.Y)/sY)*sY)+MouseLDownPos.Y;
3950 end
3951 else
3952 if MouseRDown then
3953 begin // Зажата правая кнопка мыши
3954 MousePos.X := (Round((X-MouseRDownPos.X)/sX)*sX)+MouseRDownPos.X;
3955 MousePos.Y := (Round((Y-MouseRDownPos.Y)/sY)*sY)+MouseRDownPos.Y;
3956 end
3957 else
3958 begin // Кнопки мыши не зажаты
3959 MousePos.X := (Round(X/sX)*sX);
3960 MousePos.Y := (Round(Y/sY)*sY);
3961 end;
3963 // Изменение размера закончилось - ставим обычный курсор:
3964 if ResizeType = RESIZETYPE_NONE then
3965 RenderPanel.Cursor := crDefault;
3967 // Зажата только правая кнопка мыши:
3968 if (not MouseLDown) and (MouseRDown) then
3969 begin
3970 // Рисуем прямоугольник выделения:
3971 if MouseAction = MOUSEACTION_NONE then
3972 begin
3973 if DrawRect = nil then
3974 New(DrawRect);
3975 DrawRect.Top := MouseRDownPos.y;
3976 DrawRect.Left := MouseRDownPos.x;
3977 DrawRect.Bottom := MousePos.y;
3978 DrawRect.Right := MousePos.x;
3979 end
3980 else
3981 // Двигаем выделенные объекты:
3982 if MouseAction = MOUSEACTION_MOVEOBJ then
3983 begin
3984 MoveSelectedObjects(ssShift in Shift, ssCtrl in Shift,
3985 MousePos.X-LastMovePoint.X,
3986 MousePos.Y-LastMovePoint.Y);
3987 end
3988 else
3989 // Меняем размер выделенного объекта:
3990 if MouseAction = MOUSEACTION_RESIZE then
3991 begin
3992 if (SelectedObjectCount = 1) and
3993 (SelectedObjects[GetFirstSelected].Live) then
3994 begin
3995 dWidth := MousePos.X-LastMovePoint.X;
3996 dHeight := MousePos.Y-LastMovePoint.Y;
3998 case ResizeType of
3999 RESIZETYPE_VERTICAL: dWidth := 0;
4000 RESIZETYPE_HORIZONTAL: dHeight := 0;
4001 end;
4003 case ResizeDirection of
4004 RESIZEDIR_UP: dHeight := -dHeight;
4005 RESIZEDIR_LEFT: dWidth := -dWidth;
4006 end;
4008 ResizeObject(SelectedObjects[GetFirstSelected].ObjectType,
4009 SelectedObjects[GetFirstSelected].ID,
4010 dWidth, dHeight, ResizeDirection);
4012 LastMovePoint := MousePos;
4013 end;
4014 end;
4015 end;
4017 // Зажата только левая кнопка мыши:
4018 if (not MouseRDown) and (MouseLDown) then
4019 begin
4020 // Рисуем прямоугольник планирования панели:
4021 if MouseAction in [MOUSEACTION_DRAWPANEL,
4022 MOUSEACTION_DRAWTRIGGER,
4023 MOUSEACTION_DRAWPRESS] then
4024 begin
4025 if DrawRect = nil then
4026 New(DrawRect);
4027 DrawRect.Top := MouseLDownPos.y;
4028 DrawRect.Left := MouseLDownPos.x;
4029 DrawRect.Bottom := MousePos.y;
4030 DrawRect.Right := MousePos.x;
4031 end
4032 else // Двигаем карту:
4033 if MouseAction = MOUSEACTION_MOVEMAP then
4034 begin
4035 MoveMap(X, Y);
4036 end;
4037 end;
4039 // Клавиши мыши не зажаты:
4040 if (not MouseRDown) and (not MouseLDown) then
4041 DrawRect := nil;
4043 // Строка состояния - координаты мыши:
4044 StatusBar.Panels[1].Text := Format('(%d:%d)',
4045 [MousePos.X-MapOffset.X, MousePos.Y-MapOffset.Y]);
4046 end;
4048 procedure TMainForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
4049 begin
4050 CanClose := MessageBox(0, PChar(_lc[I_MSG_EXIT_PROMT]),
4051 PChar(_lc[I_MSG_EXIT]),
4052 MB_ICONQUESTION or MB_YESNO or
4053 MB_DEFBUTTON1) = idYes;
4054 end;
4056 procedure TMainForm.aExitExecute(Sender: TObject);
4057 begin
4058 Close();
4059 end;
4061 procedure TMainForm.FormDestroy(Sender: TObject);
4062 var
4063 config: TConfig;
4064 i: Integer;
4065 begin
4066 config := TConfig.CreateFile(EditorDir+'Editor.cfg');
4068 if WindowState <> wsMaximized then
4069 begin
4070 config.WriteInt('Editor', 'XPos', Left);
4071 config.WriteInt('Editor', 'YPos', Top);
4072 config.WriteInt('Editor', 'Width', Width);
4073 config.WriteInt('Editor', 'Height', Height);
4074 end
4075 else
4076 begin
4077 config.WriteInt('Editor', 'XPos', RestoredLeft);
4078 config.WriteInt('Editor', 'YPos', RestoredTop);
4079 config.WriteInt('Editor', 'Width', RestoredWidth);
4080 config.WriteInt('Editor', 'Height', RestoredHeight);
4081 end;
4082 config.WriteBool('Editor', 'Maximize', WindowState = wsMaximized);
4083 config.WriteBool('Editor', 'Minimap', ShowMap);
4084 config.WriteInt('Editor', 'PanelProps', PanelProps.ClientWidth);
4085 config.WriteInt('Editor', 'PanelObjs', PanelObjs.ClientHeight);
4086 config.WriteBool('Editor', 'DotEnable', DotEnable);
4087 config.WriteInt('Editor', 'DotStep', DotStep);
4088 config.WriteStr('Editor', 'LastOpenDir', OpenDialog.InitialDir);
4089 config.WriteStr('Editor', 'LastSaveDir', SaveDialog.InitialDir);
4090 config.WriteBool('Editor', 'EdgeShow', drEdge[3] < 255);
4091 config.WriteInt('Editor', 'EdgeColor', gColorEdge);
4092 config.WriteInt('Editor', 'EdgeAlpha', gAlphaEdge);
4093 config.WriteInt('Editor', 'LineAlpha', gAlphaTriggerLine);
4094 config.WriteInt('Editor', 'TriggerAlpha', gAlphaTriggerArea);
4096 for i := 0 to RecentCount-1 do
4097 if i < RecentFiles.Count then
4098 config.WriteStr('RecentFiles', IntToStr(i+1), RecentFiles[i])
4099 else
4100 config.WriteStr('RecentFiles', IntToStr(i+1), '');
4101 RecentFiles.Free();
4103 config.SaveFile(EditorDir+'Editor.cfg');
4104 config.Free();
4106 slInvalidTextures.Free;
4107 end;
4109 procedure TMainForm.RenderPanelResize(Sender: TObject);
4110 begin
4111 if MainForm.Visible then
4112 MainForm.Resize();
4113 end;
4115 procedure TMainForm.Splitter1Moved(Sender: TObject);
4116 begin
4117 FormResize(Sender);
4118 end;
4120 procedure TMainForm.aMapOptionsExecute(Sender: TObject);
4121 var
4122 ResName: String;
4123 begin
4124 MapOptionsForm.ShowModal();
4126 ResName := OpenedMap;
4127 while (Pos(':\', ResName) > 0) do
4128 Delete(ResName, 1, Pos(':\', ResName) + 1);
4130 UpdateCaption(gMapInfo.Name, ExtractFileName(OpenedWAD), ResName);
4131 end;
4133 procedure TMainForm.aAboutExecute(Sender: TObject);
4134 begin
4135 AboutForm.ShowModal();
4136 end;
4138 procedure TMainForm.FormKeyDown(Sender: TObject; var Key: Word;
4139 Shift: TShiftState);
4140 var
4141 dx, dy, i: Integer;
4142 FileName: String;
4143 begin
4144 if (not EditingProperties) then
4145 begin
4146 if Key = Ord('1') then
4147 SwitchLayer(LAYER_BACK);
4148 if Key = Ord('2') then
4149 SwitchLayer(LAYER_WALLS);
4150 if Key = Ord('3') then
4151 SwitchLayer(LAYER_FOREGROUND);
4152 if Key = Ord('4') then
4153 SwitchLayer(LAYER_STEPS);
4154 if Key = Ord('5') then
4155 SwitchLayer(LAYER_WATER);
4156 if Key = Ord('6') then
4157 SwitchLayer(LAYER_ITEMS);
4158 if Key = Ord('7') then
4159 SwitchLayer(LAYER_MONSTERS);
4160 if Key = Ord('8') then
4161 SwitchLayer(LAYER_AREAS);
4162 if Key = Ord('9') then
4163 SwitchLayer(LAYER_TRIGGERS);
4164 if Key = Ord('0') then
4165 tbShowClick(tbShow);
4167 if Key = Ord('V') then
4168 begin // Поворот монстров и областей:
4169 if (SelectedObjects <> nil) then
4170 begin
4171 for i := 0 to High(SelectedObjects) do
4172 if (SelectedObjects[i].Live) then
4173 begin
4174 if (SelectedObjects[i].ObjectType = OBJECT_MONSTER) then
4175 begin
4176 g_ChangeDir(gMonsters[SelectedObjects[i].ID].Direction);
4177 end
4178 else
4179 if (SelectedObjects[i].ObjectType = OBJECT_AREA) then
4180 begin
4181 g_ChangeDir(gAreas[SelectedObjects[i].ID].Direction);
4182 end;
4183 end;
4184 end
4185 else
4186 begin
4187 if pcObjects.ActivePage = tsMonsters then
4188 begin
4189 if rbMonsterLeft.Checked then
4190 rbMonsterRight.Checked := True
4191 else
4192 rbMonsterLeft.Checked := True;
4193 end;
4194 if pcObjects.ActivePage = tsAreas then
4195 begin
4196 if rbAreaLeft.Checked then
4197 rbAreaRight.Checked := True
4198 else
4199 rbAreaLeft.Checked := True;
4200 end;
4201 end;
4202 end;
4204 if not (ssCtrl in Shift) then
4205 begin
4206 // Быстрое превью карты:
4207 if Key = Ord('E') then
4208 begin
4209 if PreviewMode = 0 then
4210 PreviewMode := 2;
4211 end;
4213 // Вертикальный скролл карты:
4214 with sbVertical do
4215 begin
4216 if Key = Ord('W') then
4217 begin
4218 Position := IfThen(Position > DotStep, Position-DotStep, 0);
4219 MapOffset.Y := -Round(Position/16) * 16;
4220 end;
4222 if Key = Ord('S') then
4223 begin
4224 Position := IfThen(Position+DotStep < Max, Position+DotStep, Max);
4225 MapOffset.Y := -Round(Position/16) * 16;
4226 end;
4227 end;
4229 // Горизонтальный скролл карты:
4230 with sbHorizontal do
4231 begin
4232 if Key = Ord('A') then
4233 begin
4234 Position := IfThen(Position > DotStep, Position-DotStep, 0);
4235 MapOffset.X := -Round(Position/16) * 16;
4236 end;
4238 if Key = Ord('D') then
4239 begin
4240 Position := IfThen(Position+DotStep < Max, Position+DotStep, Max);
4241 MapOffset.X := -Round(Position/16) * 16;
4242 end;
4243 end;
4244 end;
4245 end;
4247 // Удалить выделенные объекты:
4248 if (Key = VK_DELETE) and (SelectedObjects <> nil) and
4249 RenderPanel.Focused() then
4250 DeleteSelectedObjects();
4252 // Снять выделение:
4253 if (Key = VK_ESCAPE) and (SelectedObjects <> nil) then
4254 RemoveSelectFromObjects();
4256 // Передвинуть объекты:
4257 if MainForm.ActiveControl = RenderPanel then
4258 begin
4259 dx := 0;
4260 dy := 0;
4262 if Key = VK_NUMPAD4 then
4263 dx := IfThen(ssAlt in Shift, -1, -DotStep);
4264 if Key = VK_NUMPAD6 then
4265 dx := IfThen(ssAlt in Shift, 1, DotStep);
4266 if Key = VK_NUMPAD8 then
4267 dy := IfThen(ssAlt in Shift, -1, -DotStep);
4268 if Key = VK_NUMPAD5 then
4269 dy := IfThen(ssAlt in Shift, 1, DotStep);
4271 if (dx <> 0) or (dy <> 0) then
4272 begin
4273 MoveSelectedObjects(ssShift in Shift, ssCtrl in Shift, dx, dy);
4274 Key := 0;
4275 end;
4276 end;
4278 if ssCtrl in Shift then
4279 begin
4280 // Выбор панели с текстурой для триггера
4281 if Key = Ord('T') then
4282 begin
4283 DrawPressRect := False;
4284 if SelectFlag = SELECTFLAG_TEXTURE then
4285 begin
4286 SelectFlag := SELECTFLAG_NONE;
4287 Exit;
4288 end;
4289 vleObjectProperty.FindRow(_lc[I_PROP_TR_TEXTURE_PANEL], i);
4290 if i > 0 then
4291 SelectFlag := SELECTFLAG_TEXTURE;
4292 end;
4294 if Key = Ord('D') then
4295 begin
4296 SelectFlag := SELECTFLAG_NONE;
4297 if DrawPressRect then
4298 begin
4299 DrawPressRect := False;
4300 Exit;
4301 end;
4302 i := -1;
4304 // Выбор области воздействия, в зависимости от типа триггера
4305 vleObjectProperty.FindRow(_lc[I_PROP_TR_EX_AREA], i);
4306 if i > 0 then
4307 begin
4308 DrawPressRect := True;
4309 Exit;
4310 end;
4311 vleObjectProperty.FindRow(_lc[I_PROP_TR_DOOR_PANEL], i);
4312 if i <= 0 then
4313 vleObjectProperty.FindRow(_lc[I_PROP_TR_TRAP_PANEL], i);
4314 if i > 0 then
4315 begin
4316 SelectFlag := SELECTFLAG_DOOR;
4317 Exit;
4318 end;
4319 vleObjectProperty.FindRow(_lc[I_PROP_TR_LIFT_PANEL], i);
4320 if i > 0 then
4321 begin
4322 SelectFlag := SELECTFLAG_LIFT;
4323 Exit;
4324 end;
4325 vleObjectProperty.FindRow(_lc[I_PROP_TR_TELEPORT_TO], i);
4326 if i > 0 then
4327 begin
4328 SelectFlag := SELECTFLAG_TELEPORT;
4329 Exit;
4330 end;
4331 vleObjectProperty.FindRow(_lc[I_PROP_TR_SPAWN_TO], i);
4332 if i > 0 then
4333 begin
4334 SelectFlag := SELECTFLAG_SPAWNPOINT;
4335 Exit;
4336 end;
4338 // Выбор основного параметра, в зависимости от типа триггера
4339 vleObjectProperty.FindRow(_lc[I_PROP_TR_NEXT_MAP], i);
4340 if i > 0 then
4341 begin
4342 g_ProcessResourceStr(OpenedMap, @FileName, nil, nil);
4343 SelectMapForm.Caption := _lc[I_CAP_SELECT];
4344 SelectMapForm.GetMaps(FileName);
4346 if SelectMapForm.ShowModal() = mrOK then
4347 begin
4348 vleObjectProperty.Cells[1, i] := SelectMapForm.lbMapList.Items[SelectMapForm.lbMapList.ItemIndex];
4349 bApplyProperty.Click();
4350 end;
4351 Exit;
4352 end;
4353 vleObjectProperty.FindRow(_lc[I_PROP_TR_SOUND_NAME], i);
4354 if i <= 0 then
4355 vleObjectProperty.FindRow(_lc[I_PROP_TR_MUSIC_NAME], i);
4356 if i > 0 then
4357 begin
4358 AddSoundForm.OKFunction := nil;
4359 AddSoundForm.lbResourcesList.MultiSelect := False;
4360 AddSoundForm.SetResource := vleObjectProperty.Cells[1, i];
4362 if (AddSoundForm.ShowModal() = mrOk) then
4363 begin
4364 vleObjectProperty.Cells[1, i] := AddSoundForm.ResourceName;
4365 bApplyProperty.Click();
4366 end;
4367 Exit;
4368 end;
4369 vleObjectProperty.FindRow(_lc[I_PROP_TR_PUSH_ANGLE], i);
4370 if i <= 0 then
4371 vleObjectProperty.FindRow(_lc[I_PROP_TR_MESSAGE_TEXT], i);
4372 if i > 0 then
4373 begin
4374 vleObjectProperty.Row := i;
4375 vleObjectProperty.SetFocus();
4376 Exit;
4377 end;
4378 end;
4379 end;
4380 end;
4382 procedure TMainForm.aOptimizeExecute(Sender: TObject);
4383 begin
4384 RemoveSelectFromObjects();
4385 MapOptimizationForm.ShowModal();
4386 end;
4388 procedure TMainForm.aCheckMapExecute(Sender: TObject);
4389 begin
4390 MapCheckForm.ShowModal();
4391 end;
4393 procedure TMainForm.bbAddTextureClick(Sender: TObject);
4394 begin
4395 AddTextureForm.lbResourcesList.MultiSelect := True;
4396 AddTextureForm.ShowModal();
4397 end;
4399 procedure TMainForm.lbTextureListClick(Sender: TObject);
4400 var
4401 TextureID: DWORD;
4402 TextureWidth, TextureHeight: Word;
4403 begin
4404 TextureID := 0;
4405 TextureWidth := 0;
4406 TextureHeight := 0;
4407 if (lbTextureList.ItemIndex <> -1) and
4408 (not IsSpecialTextureSel()) then
4409 begin
4410 if g_GetTexture(SelectedTexture(), TextureID) then
4411 begin
4412 g_GetTextureSizeByID(TextureID, TextureWidth, TextureHeight);
4414 lTextureWidth.Caption := IntToStr(TextureWidth);
4415 lTextureHeight.Caption := IntToStr(TextureHeight);
4416 end else
4417 begin
4418 lTextureWidth.Caption := _lc[I_NOT_ACCESSIBLE];
4419 lTextureHeight.Caption := _lc[I_NOT_ACCESSIBLE];
4420 end;
4421 end
4422 else
4423 begin
4424 lTextureWidth.Caption := '';
4425 lTextureHeight.Caption := '';
4426 end;
4427 end;
4429 procedure TMainForm.lbTextureListDrawItem(Control: TWinControl; Index: Integer;
4430 ARect: TRect; State: TOwnerDrawState);
4431 begin
4432 with Control as TListBox do
4433 begin
4434 if LCLType.odSelected in State then
4435 begin
4436 Canvas.Brush.Color := clHighlight;
4437 Canvas.Font.Color := clHighlightText;
4438 end else
4439 if (Items <> nil) and (Index >= 0) then
4440 if slInvalidTextures.IndexOf(Items[Index]) > -1 then
4441 begin
4442 Canvas.Brush.Color := clRed;
4443 Canvas.Font.Color := clWhite;
4444 end;
4445 Canvas.FillRect(ARect);
4446 Canvas.TextRect(ARect, ARect.Left, ARect.Top, Items[Index]);
4447 end;
4448 end;
4450 procedure TMainForm.vleObjectPropertyGetPickList(Sender: TObject;
4451 const KeyName: String; Values: TStrings);
4452 begin
4453 if vleObjectProperty.ItemProps[KeyName].EditStyle = esPickList then
4454 begin
4455 if KeyName = _lc[I_PROP_DIRECTION] then
4456 begin
4457 Values.Add(DirNames[D_LEFT]);
4458 Values.Add(DirNames[D_RIGHT]);
4459 end
4460 else if KeyName = _lc[I_PROP_TR_TELEPORT_DIR] then
4461 begin
4462 Values.Add(DirNamesAdv[0]);
4463 Values.Add(DirNamesAdv[1]);
4464 Values.Add(DirNamesAdv[2]);
4465 Values.Add(DirNamesAdv[3]);
4466 end
4467 else if KeyName = _lc[I_PROP_TR_MUSIC_ACT] then
4468 begin
4469 Values.Add(_lc[I_PROP_TR_MUSIC_ON]);
4470 Values.Add(_lc[I_PROP_TR_MUSIC_OFF]);
4471 end
4472 else if KeyName = _lc[I_PROP_TR_MONSTER_BEHAVIOUR] then
4473 begin
4474 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_0]);
4475 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_1]);
4476 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_2]);
4477 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_3]);
4478 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_4]);
4479 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_5]);
4480 end
4481 else if KeyName = _lc[I_PROP_TR_SCORE_ACT] then
4482 begin
4483 Values.Add(_lc[I_PROP_TR_SCORE_ACT_0]);
4484 Values.Add(_lc[I_PROP_TR_SCORE_ACT_1]);
4485 Values.Add(_lc[I_PROP_TR_SCORE_ACT_2]);
4486 Values.Add(_lc[I_PROP_TR_SCORE_ACT_3]);
4487 end
4488 else if KeyName = _lc[I_PROP_TR_SCORE_TEAM] then
4489 begin
4490 Values.Add(_lc[I_PROP_TR_SCORE_TEAM_0]);
4491 Values.Add(_lc[I_PROP_TR_SCORE_TEAM_1]);
4492 Values.Add(_lc[I_PROP_TR_SCORE_TEAM_2]);
4493 Values.Add(_lc[I_PROP_TR_SCORE_TEAM_3]);
4494 end
4495 else if KeyName = _lc[I_PROP_TR_MESSAGE_KIND] then
4496 begin
4497 Values.Add(_lc[I_PROP_TR_MESSAGE_KIND_0]);
4498 Values.Add(_lc[I_PROP_TR_MESSAGE_KIND_1]);
4499 end
4500 else if KeyName = _lc[I_PROP_TR_MESSAGE_TO] then
4501 begin
4502 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_0]);
4503 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_1]);
4504 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_2]);
4505 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_3]);
4506 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_4]);
4507 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_5]);
4508 end
4509 else if KeyName = _lc[I_PROP_TR_SHOT_TO] then
4510 begin
4511 Values.Add(_lc[I_PROP_TR_SHOT_TO_0]);
4512 Values.Add(_lc[I_PROP_TR_SHOT_TO_1]);
4513 Values.Add(_lc[I_PROP_TR_SHOT_TO_2]);
4514 Values.Add(_lc[I_PROP_TR_SHOT_TO_3]);
4515 Values.Add(_lc[I_PROP_TR_SHOT_TO_4]);
4516 Values.Add(_lc[I_PROP_TR_SHOT_TO_5]);
4517 Values.Add(_lc[I_PROP_TR_SHOT_TO_6]);
4518 end
4519 else if KeyName = _lc[I_PROP_TR_SHOT_AIM] then
4520 begin
4521 Values.Add(_lc[I_PROP_TR_SHOT_AIM_0]);
4522 Values.Add(_lc[I_PROP_TR_SHOT_AIM_1]);
4523 Values.Add(_lc[I_PROP_TR_SHOT_AIM_2]);
4524 Values.Add(_lc[I_PROP_TR_SHOT_AIM_3]);
4525 end
4526 else if (KeyName = _lc[I_PROP_PANEL_BLEND]) or
4527 (KeyName = _lc[I_PROP_DM_ONLY]) or
4528 (KeyName = _lc[I_PROP_ITEM_FALLS]) or
4529 (KeyName = _lc[I_PROP_TR_ENABLED]) or
4530 (KeyName = _lc[I_PROP_TR_D2D]) or
4531 (KeyName = _lc[I_PROP_TR_SILENT]) or
4532 (KeyName = _lc[I_PROP_TR_TELEPORT_SILENT]) or
4533 (KeyName = _lc[I_PROP_TR_EX_RANDOM]) or
4534 (KeyName = _lc[I_PROP_TR_TEXTURE_ONCE]) or
4535 (KeyName = _lc[I_PROP_TR_TEXTURE_ANIM_ONCE]) or
4536 (KeyName = _lc[I_PROP_TR_SOUND_LOCAL]) or
4537 (KeyName = _lc[I_PROP_TR_SOUND_SWITCH]) or
4538 (KeyName = _lc[I_PROP_TR_MONSTER_ACTIVE]) or
4539 (KeyName = _lc[I_PROP_TR_PUSH_RESET]) or
4540 (KeyName = _lc[I_PROP_TR_SCORE_CON]) or
4541 (KeyName = _lc[I_PROP_TR_SCORE_MSG]) or
4542 (KeyName = _lc[I_PROP_TR_HEALTH_MAX]) or
4543 (KeyName = _lc[I_PROP_TR_SHOT_SOUND]) or
4544 (KeyName = _lc[I_PROP_TR_EFFECT_CENTER]) then
4545 begin
4546 Values.Add(BoolNames[True]);
4547 Values.Add(BoolNames[False]);
4548 end;
4549 end;
4550 end;
4552 procedure TMainForm.bApplyPropertyClick(Sender: TObject);
4553 var
4554 _id, a, r, c: Integer;
4555 s: String;
4556 res: Boolean;
4557 NoTextureID: DWORD;
4558 NW, NH: Word;
4559 begin
4560 NoTextureID := 0;
4561 NW := 0;
4562 NH := 0;
4564 if SelectedObjectCount() <> 1 then
4565 Exit;
4566 if not SelectedObjects[GetFirstSelected()].Live then
4567 Exit;
4569 try
4570 if not CheckProperty() then
4571 Exit;
4572 except
4573 Exit;
4574 end;
4576 _id := GetFirstSelected();
4578 r := vleObjectProperty.Row;
4579 c := vleObjectProperty.Col;
4581 case SelectedObjects[_id].ObjectType of
4582 OBJECT_PANEL:
4583 begin
4584 with gPanels[SelectedObjects[_id].ID] do
4585 begin
4586 X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
4587 Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
4588 Width := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_WIDTH]]));
4589 Height := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_HEIGHT]]));
4591 PanelType := GetPanelType(vleObjectProperty.Values[_lc[I_PROP_PANEL_TYPE]]);
4593 // Сброс ссылки на триггеры смены текстуры:
4594 if not WordBool(PanelType and (PANEL_WALL or PANEL_FORE or PANEL_BACK)) then
4595 if gTriggers <> nil then
4596 for a := 0 to High(gTriggers) do
4597 begin
4598 if (gTriggers[a].TriggerType <> 0) and
4599 (gTriggers[a].TexturePanel = Integer(SelectedObjects[_id].ID)) then
4600 gTriggers[a].TexturePanel := -1;
4601 if (gTriggers[a].TriggerType = TRIGGER_SHOT) and
4602 (gTriggers[a].Data.ShotPanelID = Integer(SelectedObjects[_id].ID)) then
4603 gTriggers[a].Data.ShotPanelID := -1;
4604 end;
4606 // Сброс ссылки на триггеры лифта:
4607 if not WordBool(PanelType and (PANEL_LIFTUP or PANEL_LIFTDOWN or PANEL_LIFTLEFT or PANEL_LIFTRIGHT)) then
4608 if gTriggers <> nil then
4609 for a := 0 to High(gTriggers) do
4610 if (gTriggers[a].TriggerType in [TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT]) and
4611 (gTriggers[a].Data.PanelID = Integer(SelectedObjects[_id].ID)) then
4612 gTriggers[a].Data.PanelID := -1;
4614 // Сброс ссылки на триггеры двери:
4615 if not WordBool(PanelType and (PANEL_OPENDOOR or PANEL_CLOSEDOOR)) then
4616 if gTriggers <> nil then
4617 for a := 0 to High(gTriggers) do
4618 if (gTriggers[a].TriggerType in [TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
4619 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP]) and
4620 (gTriggers[a].Data.PanelID = Integer(SelectedObjects[_id].ID)) then
4621 gTriggers[a].Data.PanelID := -1;
4623 if IsTexturedPanel(PanelType) then
4624 begin // Может быть текстура
4625 if TextureName <> '' then
4626 begin // Была текстура
4627 Alpha := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_PANEL_ALPHA]]));
4628 Blending := NameToBool(vleObjectProperty.Values[_lc[I_PROP_PANEL_BLEND]]);
4629 end
4630 else // Не было
4631 begin
4632 Alpha := 0;
4633 Blending := False;
4634 end;
4636 // Новая текстура:
4637 TextureName := vleObjectProperty.Values[_lc[I_PROP_PANEL_TEX]];
4639 if TextureName <> '' then
4640 begin // Есть текстура
4641 // Обычная текстура:
4642 if not IsSpecialTexture(TextureName) then
4643 begin
4644 g_GetTextureSizeByName(TextureName,
4645 TextureWidth, TextureHeight);
4647 // Проверка кратности размеров панели:
4648 res := True;
4649 if TextureWidth <> 0 then
4650 if gPanels[SelectedObjects[_id].ID].Width mod TextureWidth <> 0 then
4651 begin
4652 ErrorMessageBox(Format(_lc[I_MSG_WRONG_TEXWIDTH],
4653 [TextureWidth]));
4654 Res := False;
4655 end;
4656 if Res and (TextureHeight <> 0) then
4657 if gPanels[SelectedObjects[_id].ID].Height mod TextureHeight <> 0 then
4658 begin
4659 ErrorMessageBox(Format(_lc[I_MSG_WRONG_TEXHEIGHT],
4660 [TextureHeight]));
4661 Res := False;
4662 end;
4664 if Res then
4665 begin
4666 if not g_GetTexture(TextureName, TextureID) then
4667 // Не удалось загрузить текстуру, рисуем NOTEXTURE
4668 if g_GetTexture('NOTEXTURE', NoTextureID) then
4669 begin
4670 TextureID := TEXTURE_SPECIAL_NOTEXTURE;
4671 g_GetTextureSizeByID(NoTextureID, NW, NH);
4672 TextureWidth := NW;
4673 TextureHeight := NH;
4674 end else
4675 begin
4676 TextureID := TEXTURE_SPECIAL_NONE;
4677 TextureWidth := 1;
4678 TextureHeight := 1;
4679 end;
4680 end
4681 else
4682 begin
4683 TextureName := '';
4684 TextureWidth := 1;
4685 TextureHeight := 1;
4686 TextureID := TEXTURE_SPECIAL_NONE;
4687 end;
4688 end
4689 else // Спец.текстура
4690 begin
4691 TextureHeight := 1;
4692 TextureWidth := 1;
4693 TextureID := SpecialTextureID(TextureName);
4694 end;
4695 end
4696 else // Нет текстуры
4697 begin
4698 TextureWidth := 1;
4699 TextureHeight := 1;
4700 TextureID := TEXTURE_SPECIAL_NONE;
4701 end;
4702 end
4703 else // Не может быть текстуры
4704 begin
4705 Alpha := 0;
4706 Blending := False;
4707 TextureName := '';
4708 TextureWidth := 1;
4709 TextureHeight := 1;
4710 TextureID := TEXTURE_SPECIAL_NONE;
4711 end;
4712 end;
4713 end;
4715 OBJECT_ITEM:
4716 begin
4717 with gItems[SelectedObjects[_id].ID] do
4718 begin
4719 X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
4720 Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
4721 OnlyDM := NameToBool(vleObjectProperty.Values[_lc[I_PROP_DM_ONLY]]);
4722 Fall := NameToBool(vleObjectProperty.Values[_lc[I_PROP_ITEM_FALLS]]);
4723 end;
4724 end;
4726 OBJECT_MONSTER:
4727 begin
4728 with gMonsters[SelectedObjects[_id].ID] do
4729 begin
4730 X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
4731 Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
4732 Direction := NameToDir(vleObjectProperty.Values[_lc[I_PROP_DIRECTION]]);
4733 end;
4734 end;
4736 OBJECT_AREA:
4737 begin
4738 with gAreas[SelectedObjects[_id].ID] do
4739 begin
4740 X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
4741 Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
4742 Direction := NameToDir(vleObjectProperty.Values[_lc[I_PROP_DIRECTION]]);
4743 end;
4744 end;
4746 OBJECT_TRIGGER:
4747 begin
4748 with gTriggers[SelectedObjects[_id].ID] do
4749 begin
4750 X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
4751 Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
4752 Width := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_WIDTH]]));
4753 Height := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_HEIGHT]]));
4754 Enabled := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_ENABLED]]);
4755 ActivateType := StrToActivate(vleObjectProperty.Values[_lc[I_PROP_TR_ACTIVATION]]);
4756 Key := StrToKey(vleObjectProperty.Values[_lc[I_PROP_TR_KEYS]]);
4758 case TriggerType of
4759 TRIGGER_EXIT:
4760 begin
4761 s := utf2win(vleObjectProperty.Values[_lc[I_PROP_TR_NEXT_MAP]]);
4762 FillByte(Data.MapName[0], 16, 0);
4763 if s <> '' then
4764 Move(s[1], Data.MapName[0], Min(Length(s), 16));
4765 end;
4767 TRIGGER_TEXTURE:
4768 begin
4769 Data.ActivateOnce := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_TEXTURE_ONCE]]);
4770 Data.AnimOnce := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_TEXTURE_ANIM_ONCE]]);
4771 end;
4773 TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF:
4774 begin
4775 Data.Wait := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EX_DELAY]], 0), 65535);
4776 Data.Count := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EX_COUNT]], 0), 65535);
4777 if Data.Count < 1 then
4778 Data.Count := 1;
4779 if TriggerType = TRIGGER_PRESS then
4780 Data.ExtRandom := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_EX_RANDOM]]);
4781 end;
4783 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR, TRIGGER_DOOR5,
4784 TRIGGER_CLOSETRAP, TRIGGER_TRAP, TRIGGER_LIFTUP, TRIGGER_LIFTDOWN,
4785 TRIGGER_LIFT:
4786 begin
4787 Data.NoSound := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SILENT]]);
4788 Data.d2d_doors := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_D2D]]);
4789 end;
4791 TRIGGER_TELEPORT:
4792 begin
4793 Data.d2d_teleport := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_D2D]]);
4794 Data.silent_teleport := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_TELEPORT_SILENT]]);
4795 Data.TlpDir := NameToDirAdv(vleObjectProperty.Values[_lc[I_PROP_TR_TELEPORT_DIR]]);
4796 end;
4798 TRIGGER_SOUND:
4799 begin
4800 s := utf2win(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_NAME]]);
4801 FillByte(Data.SoundName[0], 64, 0);
4802 if s <> '' then
4803 Move(s[1], Data.SoundName[0], Min(Length(s), 64));
4805 Data.Volume := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_VOLUME]], 0), 255);
4806 Data.Pan := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_PAN]], 0), 255);
4807 Data.PlayCount := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_COUNT]], 0), 255);
4808 Data.Local := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_LOCAL]]);
4809 Data.SoundSwitch := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_SWITCH]]);
4810 end;
4812 TRIGGER_SPAWNMONSTER:
4813 begin
4814 Data.MonType := StrToMonster(vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_TYPE]]);
4815 Data.MonDir := Byte(NameToDir(vleObjectProperty.Values[_lc[I_PROP_DIRECTION]]));
4816 Data.MonHealth := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_HEALTH]], 0), 1000000);
4817 if Data.MonHealth < 0 then
4818 Data.MonHealth := 0;
4819 Data.MonActive := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_ACTIVE]]);
4820 Data.MonCount := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_COUNT]], 0), 64);
4821 if Data.MonCount < 1 then
4822 Data.MonCount := 1;
4823 Data.MonEffect := StrToEffect(vleObjectProperty.Values[_lc[I_PROP_TR_FX_TYPE]]);
4824 Data.MonMax := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SPAWN_MAX]], 0), 65535);
4825 Data.MonDelay := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SPAWN_DELAY]], 0), 65535);
4826 Data.MonBehav := 0;
4827 if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_1] then
4828 Data.MonBehav := 1;
4829 if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_2] then
4830 Data.MonBehav := 2;
4831 if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_3] then
4832 Data.MonBehav := 3;
4833 if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_4] then
4834 Data.MonBehav := 4;
4835 if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_5] then
4836 Data.MonBehav := 5;
4837 end;
4839 TRIGGER_SPAWNITEM:
4840 begin
4841 Data.ItemType := StrToItem(vleObjectProperty.Values[_lc[I_PROP_TR_ITEM_TYPE]]);
4842 Data.ItemOnlyDM := NameToBool(vleObjectProperty.Values[_lc[I_PROP_DM_ONLY]]);
4843 Data.ItemFalls := NameToBool(vleObjectProperty.Values[_lc[I_PROP_ITEM_FALLS]]);
4844 Data.ItemCount := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_COUNT]], 0), 64);
4845 if Data.ItemCount < 1 then
4846 Data.ItemCount := 1;
4847 Data.ItemEffect := StrToEffect(vleObjectProperty.Values[_lc[I_PROP_TR_FX_TYPE]]);
4848 Data.ItemMax := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SPAWN_MAX]], 0), 65535);
4849 Data.ItemDelay := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SPAWN_DELAY]], 0), 65535);
4850 end;
4852 TRIGGER_MUSIC:
4853 begin
4854 s := utf2win(vleObjectProperty.Values[_lc[I_PROP_TR_MUSIC_NAME]]);
4855 FillByte(Data.MusicName[0], 64, 0);
4856 if s <> '' then
4857 Move(s[1], Data.MusicName[0], Min(Length(s), 64));
4859 if vleObjectProperty.Values[_lc[I_PROP_TR_MUSIC_ACT]] = _lc[I_PROP_TR_MUSIC_ON] then
4860 Data.MusicAction := 1
4861 else
4862 Data.MusicAction := 2;
4863 end;
4865 TRIGGER_PUSH:
4866 begin
4867 Data.PushAngle := Min(
4868 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_PUSH_ANGLE]], 0), 360);
4869 Data.PushForce := Min(
4870 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_PUSH_FORCE]], 0), 255);
4871 Data.ResetVel := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_PUSH_RESET]]);
4872 end;
4874 TRIGGER_SCORE:
4875 begin
4876 Data.ScoreAction := 0;
4877 if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_ACT]] = _lc[I_PROP_TR_SCORE_ACT_1] then
4878 Data.ScoreAction := 1
4879 else if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_ACT]] = _lc[I_PROP_TR_SCORE_ACT_2] then
4880 Data.ScoreAction := 2
4881 else if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_ACT]] = _lc[I_PROP_TR_SCORE_ACT_3] then
4882 Data.ScoreAction := 3;
4883 Data.ScoreCount := Min(Max(
4884 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_COUNT]], 0), 0), 255);
4885 Data.ScoreTeam := 0;
4886 if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_TEAM]] = _lc[I_PROP_TR_SCORE_TEAM_1] then
4887 Data.ScoreTeam := 1
4888 else if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_TEAM]] = _lc[I_PROP_TR_SCORE_TEAM_2] then
4889 Data.ScoreTeam := 2
4890 else if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_TEAM]] = _lc[I_PROP_TR_SCORE_TEAM_3] then
4891 Data.ScoreTeam := 3;
4892 Data.ScoreCon := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_CON]]);
4893 Data.ScoreMsg := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_MSG]]);
4894 end;
4896 TRIGGER_MESSAGE:
4897 begin
4898 Data.MessageKind := 0;
4899 if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_KIND]] = _lc[I_PROP_TR_MESSAGE_KIND_1] then
4900 Data.MessageKind := 1;
4902 Data.MessageSendTo := 0;
4903 if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_1] then
4904 Data.MessageSendTo := 1
4905 else if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_2] then
4906 Data.MessageSendTo := 2
4907 else if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_3] then
4908 Data.MessageSendTo := 3
4909 else if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_4] then
4910 Data.MessageSendTo := 4
4911 else if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_5] then
4912 Data.MessageSendTo := 5;
4914 s := utf2win(vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TEXT]]);
4915 FillByte(Data.MessageText[0], 100, 0);
4916 if s <> '' then
4917 Move(s[1], Data.MessageText[0], Min(Length(s), 100));
4919 Data.MessageTime := Min(Max(
4920 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TIME]], 0), 0), 65535);
4921 end;
4923 TRIGGER_DAMAGE:
4924 begin
4925 Data.DamageValue := Min(Max(
4926 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_DAMAGE_VALUE]], 0), 0), 65535);
4927 Data.DamageInterval := Min(Max(
4928 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_INTERVAL]], 0), 0), 65535);
4929 end;
4931 TRIGGER_HEALTH:
4932 begin
4933 Data.HealValue := Min(Max(
4934 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_HEALTH]], 0), 0), 65535);
4935 Data.HealInterval := Min(Max(
4936 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_INTERVAL]], 0), 0), 65535);
4937 Data.HealMax := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_HEALTH_MAX]]);
4938 Data.HealSilent := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SILENT]]);
4939 end;
4941 TRIGGER_SHOT:
4942 begin
4943 Data.ShotType := StrToShot(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TYPE]]);
4944 Data.ShotSound := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_SOUND]]);
4945 Data.ShotTarget := 0;
4946 if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_1] then
4947 Data.ShotTarget := 1
4948 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_2] then
4949 Data.ShotTarget := 2
4950 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_3] then
4951 Data.ShotTarget := 3
4952 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_4] then
4953 Data.ShotTarget := 4
4954 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_5] then
4955 Data.ShotTarget := 5
4956 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_6] then
4957 Data.ShotTarget := 6;
4958 Data.ShotIntSight := Min(Max(
4959 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_SIGHT]], 0), 0), 65535);
4960 Data.ShotAim := 0;
4961 if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_AIM]] = _lc[I_PROP_TR_SHOT_AIM_1] then
4962 Data.ShotAim := 1
4963 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_AIM]] = _lc[I_PROP_TR_SHOT_AIM_2] then
4964 Data.ShotAim := 2
4965 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_AIM]] = _lc[I_PROP_TR_SHOT_AIM_3] then
4966 Data.ShotAim := 3;
4967 Data.ShotAngle := Min(
4968 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_ANGLE]], 0), 360);
4969 Data.ShotWait := Min(Max(
4970 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EX_DELAY]], 0), 0), 65535);
4971 Data.ShotAccuracy := Min(Max(
4972 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_ACC]], 0), 0), 65535);
4973 Data.ShotAmmo := Min(Max(
4974 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_AMMO]], 0), 0), 65535);
4975 Data.ShotIntReload := Min(Max(
4976 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_RELOAD]], 0), 0), 65535);
4977 end;
4979 TRIGGER_EFFECT:
4980 begin
4981 Data.FXCount := Min(Max(
4982 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_COUNT]], 0), 0), 255);
4983 if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_TYPE]] = _lc[I_PROP_TR_EFFECT_PARTICLE] then
4984 begin
4985 Data.FXType := TRIGGER_EFFECT_PARTICLE;
4986 Data.FXSubType := TRIGGER_EFFECT_SLIQUID;
4987 if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_SLIQUID] then
4988 Data.FXSubType := TRIGGER_EFFECT_SLIQUID
4989 else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_LLIQUID] then
4990 Data.FXSubType := TRIGGER_EFFECT_LLIQUID
4991 else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_DLIQUID] then
4992 Data.FXSubType := TRIGGER_EFFECT_DLIQUID
4993 else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_BLOOD] then
4994 Data.FXSubType := TRIGGER_EFFECT_BLOOD
4995 else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_SPARK] then
4996 Data.FXSubType := TRIGGER_EFFECT_SPARK
4997 else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_BUBBLE] then
4998 Data.FXSubType := TRIGGER_EFFECT_BUBBLE;
4999 end else
5000 begin
5001 Data.FXType := TRIGGER_EFFECT_ANIMATION;
5002 Data.FXSubType := StrToEffect(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]]);
5003 end;
5004 a := Min(Max(
5005 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_COLOR]], 0), 0), $FFFFFF);
5006 Data.FXColorR := a and $FF;
5007 Data.FXColorG := (a shr 8) and $FF;
5008 Data.FXColorB := (a shr 16) and $FF;
5009 if NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_CENTER]]) then
5010 Data.FXPos := 0
5011 else
5012 Data.FXPos := 1;
5013 Data.FXWait := Min(Max(
5014 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EX_DELAY]], 0), 0), 65535);
5015 Data.FXVelX := Min(Max(
5016 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_VELX]], 0), -128), 127);
5017 Data.FXVelY := Min(Max(
5018 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_VELY]], 0), -128), 127);
5019 Data.FXSpreadL := Min(Max(
5020 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SPL]], 0), 0), 255);
5021 Data.FXSpreadR := Min(Max(
5022 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SPR]], 0), 0), 255);
5023 Data.FXSpreadU := Min(Max(
5024 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SPU]], 0), 0), 255);
5025 Data.FXSpreadD := Min(Max(
5026 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SPD]], 0), 0), 255);
5027 end;
5028 end;
5029 end;
5030 end;
5031 end;
5033 FillProperty();
5035 vleObjectProperty.Row := r;
5036 vleObjectProperty.Col := c;
5037 end;
5039 procedure TMainForm.bbRemoveTextureClick(Sender: TObject);
5040 var
5041 a, i: Integer;
5042 begin
5043 i := lbTextureList.ItemIndex;
5044 if i = -1 then
5045 Exit;
5047 if MessageBox(0, PChar(Format(_lc[I_MSG_DEL_TEXTURE_PROMT],
5048 [SelectedTexture()])),
5049 PChar(_lc[I_MSG_DEL_TEXTURE]),
5050 MB_ICONQUESTION or MB_YESNO or
5051 MB_DEFBUTTON1) <> idYes then
5052 Exit;
5054 if gPanels <> nil then
5055 for a := 0 to High(gPanels) do
5056 if (gPanels[a].PanelType <> 0) and
5057 (gPanels[a].TextureName = SelectedTexture()) then
5058 begin
5059 ErrorMessageBox(_lc[I_MSG_DEL_TEXTURE_CANT]);
5060 Exit;
5061 end;
5063 g_DeleteTexture(SelectedTexture());
5064 i := slInvalidTextures.IndexOf(lbTextureList.Items[i]);
5065 if i > -1 then
5066 slInvalidTextures.Delete(i);
5067 if lbTextureList.ItemIndex > -1 then
5068 lbTextureList.Items.Delete(lbTextureList.ItemIndex)
5069 end;
5071 procedure TMainForm.aNewMapExecute(Sender: TObject);
5072 begin
5073 if (MessageBox(0, PChar(_lc[I_MSG_CLEAR_MAP_PROMT]),
5074 PChar(_lc[I_MSG_CLEAR_MAP]),
5075 MB_ICONQUESTION or MB_YESNO or
5076 MB_DEFBUTTON1) = mrYes) then
5077 FullClear();
5078 end;
5080 procedure TMainForm.aUndoExecute(Sender: TObject);
5081 var
5082 a: Integer;
5083 begin
5084 if UndoBuffer = nil then
5085 Exit;
5086 if UndoBuffer[High(UndoBuffer)] = nil then
5087 Exit;
5089 for a := 0 to High(UndoBuffer[High(UndoBuffer)]) do
5090 with UndoBuffer[High(UndoBuffer)][a] do
5091 begin
5092 case UndoType of
5093 UNDO_DELETE_PANEL:
5094 begin
5095 AddPanel(Panel^);
5096 Panel := nil;
5097 end;
5098 UNDO_DELETE_ITEM: AddItem(Item);
5099 UNDO_DELETE_AREA: AddArea(Area);
5100 UNDO_DELETE_MONSTER: AddMonster(Monster);
5101 UNDO_DELETE_TRIGGER: AddTrigger(Trigger);
5102 UNDO_ADD_PANEL: RemoveObject(AddID, OBJECT_PANEL);
5103 UNDO_ADD_ITEM: RemoveObject(AddID, OBJECT_ITEM);
5104 UNDO_ADD_AREA: RemoveObject(AddID, OBJECT_AREA);
5105 UNDO_ADD_MONSTER: RemoveObject(AddID, OBJECT_MONSTER);
5106 UNDO_ADD_TRIGGER: RemoveObject(AddID, OBJECT_TRIGGER);
5107 end;
5108 end;
5110 SetLength(UndoBuffer, Length(UndoBuffer)-1);
5112 RemoveSelectFromObjects();
5114 miUndo.Enabled := UndoBuffer <> nil;
5115 end;
5118 procedure TMainForm.aCopyObjectExecute(Sender: TObject);
5119 var
5120 a, b: Integer;
5121 CopyBuffer: TCopyRecArray;
5122 str: String;
5123 ok: Boolean;
5125 function CB_Compare(I1, I2: TCopyRec): Integer;
5126 begin
5127 Result := Integer(I1.ObjectType) - Integer(I2.ObjectType);
5129 if Result = 0 then // Одного типа
5130 Result := Integer(I1.ID) - Integer(I2.ID);
5131 end;
5133 procedure QuickSortCopyBuffer(L, R: Integer);
5134 var
5135 I, J: Integer;
5136 P, T: TCopyRec;
5137 begin
5138 repeat
5139 I := L;
5140 J := R;
5141 P := CopyBuffer[(L + R) shr 1];
5143 repeat
5144 while CB_Compare(CopyBuffer[I], P) < 0 do
5145 Inc(I);
5146 while CB_Compare(CopyBuffer[J], P) > 0 do
5147 Dec(J);
5149 if I <= J then
5150 begin
5151 T := CopyBuffer[I];
5152 CopyBuffer[I] := CopyBuffer[J];
5153 CopyBuffer[J] := T;
5154 Inc(I);
5155 Dec(J);
5156 end;
5157 until I > J;
5159 if L < J then
5160 QuickSortCopyBuffer(L, J);
5162 L := I;
5163 until I >= R;
5164 end;
5166 begin
5167 if SelectedObjects = nil then
5168 Exit;
5170 b := -1;
5171 CopyBuffer := nil;
5173 // Копируем объекты:
5174 for a := 0 to High(SelectedObjects) do
5175 if SelectedObjects[a].Live then
5176 with SelectedObjects[a] do
5177 begin
5178 SetLength(CopyBuffer, Length(CopyBuffer)+1);
5179 b := High(CopyBuffer);
5180 CopyBuffer[b].ID := ID;
5181 CopyBuffer[b].Panel := nil;
5183 case ObjectType of
5184 OBJECT_PANEL:
5185 begin
5186 CopyBuffer[b].ObjectType := OBJECT_PANEL;
5187 New(CopyBuffer[b].Panel);
5188 CopyBuffer[b].Panel^ := gPanels[ID];
5189 end;
5191 OBJECT_ITEM:
5192 begin
5193 CopyBuffer[b].ObjectType := OBJECT_ITEM;
5194 CopyBuffer[b].Item := gItems[ID];
5195 end;
5197 OBJECT_MONSTER:
5198 begin
5199 CopyBuffer[b].ObjectType := OBJECT_MONSTER;
5200 CopyBuffer[b].Monster := gMonsters[ID];
5201 end;
5203 OBJECT_AREA:
5204 begin
5205 CopyBuffer[b].ObjectType := OBJECT_AREA;
5206 CopyBuffer[b].Area := gAreas[ID];
5207 end;
5209 OBJECT_TRIGGER:
5210 begin
5211 CopyBuffer[b].ObjectType := OBJECT_TRIGGER;
5212 CopyBuffer[b].Trigger := gTriggers[ID];
5213 end;
5214 end;
5215 end;
5217 // Сортировка по ID:
5218 if CopyBuffer <> nil then
5219 begin
5220 QuickSortCopyBuffer(0, b);
5221 end;
5223 // Пестановка ссылок триггеров:
5224 for a := 0 to Length(CopyBuffer)-1 do
5225 if CopyBuffer[a].ObjectType = OBJECT_TRIGGER then
5226 begin
5227 case CopyBuffer[a].Trigger.TriggerType of
5228 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
5229 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP,
5230 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
5231 if CopyBuffer[a].Trigger.Data.PanelID <> -1 then
5232 begin
5233 ok := False;
5235 for b := 0 to Length(CopyBuffer)-1 do
5236 if (CopyBuffer[b].ObjectType = OBJECT_PANEL) and
5237 (Integer(CopyBuffer[b].ID) = CopyBuffer[a].Trigger.Data.PanelID) then
5238 begin
5239 CopyBuffer[a].Trigger.Data.PanelID := b;
5240 ok := True;
5241 Break;
5242 end;
5244 // Этих панелей нет среди копируемых:
5245 if not ok then
5246 CopyBuffer[a].Trigger.Data.PanelID := -1;
5247 end;
5249 TRIGGER_PRESS, TRIGGER_ON,
5250 TRIGGER_OFF, TRIGGER_ONOFF:
5251 if CopyBuffer[a].Trigger.Data.MonsterID <> 0 then
5252 begin
5253 ok := False;
5255 for b := 0 to Length(CopyBuffer)-1 do
5256 if (CopyBuffer[b].ObjectType = OBJECT_MONSTER) and
5257 (Integer(CopyBuffer[b].ID) = CopyBuffer[a].Trigger.Data.MonsterID-1) then
5258 begin
5259 CopyBuffer[a].Trigger.Data.MonsterID := b+1;
5260 ok := True;
5261 Break;
5262 end;
5264 // Этих монстров нет среди копируемых:
5265 if not ok then
5266 CopyBuffer[a].Trigger.Data.MonsterID := 0;
5267 end;
5269 TRIGGER_SHOT:
5270 if CopyBuffer[a].Trigger.Data.ShotPanelID <> -1 then
5271 begin
5272 ok := False;
5274 for b := 0 to Length(CopyBuffer)-1 do
5275 if (CopyBuffer[b].ObjectType = OBJECT_PANEL) and
5276 (Integer(CopyBuffer[b].ID) = CopyBuffer[a].Trigger.Data.ShotPanelID) then
5277 begin
5278 CopyBuffer[a].Trigger.Data.ShotPanelID := b;
5279 ok := True;
5280 Break;
5281 end;
5283 // Этих панелей нет среди копируемых:
5284 if not ok then
5285 CopyBuffer[a].Trigger.Data.ShotPanelID := -1;
5286 end;
5287 end;
5289 if CopyBuffer[a].Trigger.TexturePanel <> -1 then
5290 begin
5291 ok := False;
5293 for b := 0 to Length(CopyBuffer)-1 do
5294 if (CopyBuffer[b].ObjectType = OBJECT_PANEL) and
5295 (Integer(CopyBuffer[b].ID) = CopyBuffer[a].Trigger.TexturePanel) then
5296 begin
5297 CopyBuffer[a].Trigger.TexturePanel := b;
5298 ok := True;
5299 Break;
5300 end;
5302 // Этих панелей нет среди копируемых:
5303 if not ok then
5304 CopyBuffer[a].Trigger.TexturePanel := -1;
5305 end;
5306 end;
5308 // В буфер обмена:
5309 str := CopyBufferToString(CopyBuffer);
5310 ClipBoard.AsText := str;
5312 for a := 0 to Length(CopyBuffer)-1 do
5313 if (CopyBuffer[a].ObjectType = OBJECT_PANEL) and
5314 (CopyBuffer[a].Panel <> nil) then
5315 Dispose(CopyBuffer[a].Panel);
5317 CopyBuffer := nil;
5318 end;
5320 procedure TMainForm.aPasteObjectExecute(Sender: TObject);
5321 var
5322 a, h: Integer;
5323 CopyBuffer: TCopyRecArray;
5324 res: Boolean;
5325 swad, ssec, sres: String;
5326 begin
5327 CopyBuffer := nil;
5329 StringToCopyBuffer(ClipBoard.AsText, CopyBuffer);
5331 if CopyBuffer = nil then
5332 Exit;
5334 RemoveSelectFromObjects();
5336 h := High(CopyBuffer);
5337 for a := 0 to h do
5338 with CopyBuffer[a] do
5339 begin
5340 case ObjectType of
5341 OBJECT_PANEL:
5342 if Panel <> nil then
5343 begin
5344 Panel^.X := Panel^.X + 16;
5345 Panel^.Y := Panel^.Y + 16;
5347 Panel^.TextureID := TEXTURE_SPECIAL_NONE;
5348 Panel^.TextureWidth := 1;
5349 Panel^.TextureHeight := 1;
5351 if (Panel^.PanelType = PANEL_LIFTUP) or
5352 (Panel^.PanelType = PANEL_LIFTDOWN) or
5353 (Panel^.PanelType = PANEL_LIFTLEFT) or
5354 (Panel^.PanelType = PANEL_LIFTRIGHT) or
5355 (Panel^.PanelType = PANEL_BLOCKMON) or
5356 (Panel^.TextureName = '') then
5357 begin // Нет или не может быть текстуры:
5358 end
5359 else // Есть текстура:
5360 begin
5361 // Обычная текстура:
5362 if not IsSpecialTexture(Panel^.TextureName) then
5363 begin
5364 res := g_GetTexture(Panel^.TextureName, Panel^.TextureID);
5366 if not res then
5367 begin
5368 g_ProcessResourceStr(Panel^.TextureName, swad, ssec, sres);
5369 AddTexture(swad, ssec, sres, True);
5370 res := g_GetTexture(Panel^.TextureName, Panel^.TextureID);
5371 end;
5373 if res then
5374 g_GetTextureSizeByName(Panel^.TextureName,
5375 Panel^.TextureWidth, Panel^.TextureHeight)
5376 else
5377 Panel^.TextureName := '';
5378 end
5379 else // Спец.текстура:
5380 begin
5381 Panel^.TextureID := SpecialTextureID(Panel^.TextureName);
5382 with MainForm.lbTextureList.Items do
5383 if IndexOf(Panel^.TextureName) = -1 then
5384 Add(Panel^.TextureName);
5385 end;
5386 end;
5388 ID := AddPanel(Panel^);
5389 Dispose(Panel);
5390 Undo_Add(OBJECT_PANEL, ID, a > 0);
5391 SelectObject(OBJECT_PANEL, ID, True);
5392 end;
5394 OBJECT_ITEM:
5395 begin
5396 Item.X := Item.X + 16;
5397 Item.Y := Item.Y + 16;
5399 ID := AddItem(Item);
5400 Undo_Add(OBJECT_ITEM, ID, a > 0);
5401 SelectObject(OBJECT_ITEM, ID, True);
5402 end;
5404 OBJECT_MONSTER:
5405 begin
5406 Monster.X := Monster.X + 16;
5407 Monster.Y := Monster.Y + 16;
5409 ID := AddMonster(Monster);
5410 Undo_Add(OBJECT_MONSTER, ID, a > 0);
5411 SelectObject(OBJECT_MONSTER, ID, True);
5412 end;
5414 OBJECT_AREA:
5415 begin
5416 Area.X := Area.X + 16;
5417 Area.Y := Area.Y + 16;
5419 ID := AddArea(Area);
5420 Undo_Add(OBJECT_AREA, ID, a > 0);
5421 SelectObject(OBJECT_AREA, ID, True);
5422 end;
5424 OBJECT_TRIGGER:
5425 begin
5426 Trigger.X := Trigger.X + 16;
5427 Trigger.Y := Trigger.Y + 16;
5429 ID := AddTrigger(Trigger);
5430 Undo_Add(OBJECT_TRIGGER, ID, a > 0);
5431 SelectObject(OBJECT_TRIGGER, ID, True);
5432 end;
5433 end;
5434 end;
5436 // Переставляем ссылки триггеров:
5437 for a := 0 to High(CopyBuffer) do
5438 if CopyBuffer[a].ObjectType = OBJECT_TRIGGER then
5439 begin
5440 case CopyBuffer[a].Trigger.TriggerType of
5441 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
5442 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP,
5443 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
5444 if CopyBuffer[a].Trigger.Data.PanelID <> -1 then
5445 gTriggers[CopyBuffer[a].ID].Data.PanelID :=
5446 CopyBuffer[CopyBuffer[a].Trigger.Data.PanelID].ID;
5448 TRIGGER_PRESS, TRIGGER_ON,
5449 TRIGGER_OFF, TRIGGER_ONOFF:
5450 if CopyBuffer[a].Trigger.Data.MonsterID <> 0 then
5451 gTriggers[CopyBuffer[a].ID].Data.MonsterID :=
5452 CopyBuffer[CopyBuffer[a].Trigger.Data.MonsterID-1].ID+1;
5454 TRIGGER_SHOT:
5455 if CopyBuffer[a].Trigger.Data.ShotPanelID <> -1 then
5456 gTriggers[CopyBuffer[a].ID].Data.ShotPanelID :=
5457 CopyBuffer[CopyBuffer[a].Trigger.Data.ShotPanelID].ID;
5458 end;
5460 if CopyBuffer[a].Trigger.TexturePanel <> -1 then
5461 gTriggers[CopyBuffer[a].ID].TexturePanel :=
5462 CopyBuffer[CopyBuffer[a].Trigger.TexturePanel].ID;
5463 end;
5465 CopyBuffer := nil;
5467 if h = 0 then
5468 FillProperty();
5469 end;
5471 procedure TMainForm.aCutObjectExecute(Sender: TObject);
5472 begin
5473 miCopy.Click();
5474 DeleteSelectedObjects();
5475 end;
5477 procedure TMainForm.vleObjectPropertyEditButtonClick(Sender: TObject);
5478 var
5479 Key, FileName: String;
5480 b: Byte;
5481 begin
5482 Key := vleObjectProperty.Keys[vleObjectProperty.Row];
5484 if Key = _lc[I_PROP_PANEL_TYPE] then
5485 begin
5486 with ChooseTypeForm, vleObjectProperty do
5487 begin // Выбор типа панели:
5488 Caption := _lc[I_PROP_PANEL_TYPE];
5489 lbTypeSelect.Items.Clear();
5491 for b := 0 to High(PANELNAMES) do
5492 begin
5493 lbTypeSelect.Items.Add(PANELNAMES[b]);
5494 if Values[Key] = PANELNAMES[b] then
5495 lbTypeSelect.ItemIndex := b;
5496 end;
5498 if ShowModal() = mrOK then
5499 begin
5500 b := lbTypeSelect.ItemIndex;
5501 Values[Key] := PANELNAMES[b];
5502 vleObjectPropertyApply(Sender);
5503 end;
5504 end
5505 end
5506 else if Key = _lc[I_PROP_TR_TELEPORT_TO] then
5507 SelectFlag := SELECTFLAG_TELEPORT
5508 else if Key = _lc[I_PROP_TR_SPAWN_TO] then
5509 SelectFlag := SELECTFLAG_SPAWNPOINT
5510 else if (Key = _lc[I_PROP_TR_DOOR_PANEL]) or
5511 (Key = _lc[I_PROP_TR_TRAP_PANEL]) then
5512 SelectFlag := SELECTFLAG_DOOR
5513 else if Key = _lc[I_PROP_TR_TEXTURE_PANEL] then
5514 begin
5515 DrawPressRect := False;
5516 SelectFlag := SELECTFLAG_TEXTURE;
5517 end
5518 else if Key = _lc[I_PROP_TR_SHOT_PANEL] then
5519 SelectFlag := SELECTFLAG_SHOTPANEL
5520 else if Key = _lc[I_PROP_TR_LIFT_PANEL] then
5521 SelectFlag := SELECTFLAG_LIFT
5522 else if key = _lc[I_PROP_TR_EX_MONSTER] then
5523 SelectFlag := SELECTFLAG_MONSTER
5524 else if Key = _lc[I_PROP_TR_EX_AREA] then
5525 begin
5526 SelectFlag := SELECTFLAG_NONE;
5527 DrawPressRect := True;
5528 end
5529 else if Key = _lc[I_PROP_TR_NEXT_MAP] then
5530 begin // Выбор следующей карты:
5531 g_ProcessResourceStr(OpenedMap, @FileName, nil, nil);
5532 SelectMapForm.Caption := _lc[I_CAP_SELECT];
5533 SelectMapForm.GetMaps(FileName);
5535 if SelectMapForm.ShowModal() = mrOK then
5536 begin
5537 vleObjectProperty.Values[Key] := SelectMapForm.lbMapList.Items[SelectMapForm.lbMapList.ItemIndex];
5538 vleObjectPropertyApply(Sender);
5539 end;
5540 end
5541 else if (Key = _lc[I_PROP_TR_SOUND_NAME]) or
5542 (Key = _lc[I_PROP_TR_MUSIC_NAME]) then
5543 begin // Выбор файла звука/музыки:
5544 AddSoundForm.OKFunction := nil;
5545 AddSoundForm.lbResourcesList.MultiSelect := False;
5546 AddSoundForm.SetResource := vleObjectProperty.Values[Key];
5548 if (AddSoundForm.ShowModal() = mrOk) then
5549 begin
5550 vleObjectProperty.Values[Key] := AddSoundForm.ResourceName;
5551 vleObjectPropertyApply(Sender);
5552 end;
5553 end
5554 else if Key = _lc[I_PROP_TR_ACTIVATION] then
5555 with ActivationTypeForm, vleObjectProperty do
5556 begin // Выбор типов активации:
5557 cbPlayerCollide.Checked := Pos('PC', Values[Key]) > 0;
5558 cbMonsterCollide.Checked := Pos('MC', Values[Key]) > 0;
5559 cbPlayerPress.Checked := Pos('PP', Values[Key]) > 0;
5560 cbMonsterPress.Checked := Pos('MP', Values[Key]) > 0;
5561 cbShot.Checked := Pos('SH', Values[Key]) > 0;
5562 cbNoMonster.Checked := Pos('NM', Values[Key]) > 0;
5564 if ShowModal() = mrOK then
5565 begin
5566 b := 0;
5567 if cbPlayerCollide.Checked then
5568 b := ACTIVATE_PLAYERCOLLIDE;
5569 if cbMonsterCollide.Checked then
5570 b := b or ACTIVATE_MONSTERCOLLIDE;
5571 if cbPlayerPress.Checked then
5572 b := b or ACTIVATE_PLAYERPRESS;
5573 if cbMonsterPress.Checked then
5574 b := b or ACTIVATE_MONSTERPRESS;
5575 if cbShot.Checked then
5576 b := b or ACTIVATE_SHOT;
5577 if cbNoMonster.Checked then
5578 b := b or ACTIVATE_NOMONSTER;
5580 Values[Key] := ActivateToStr(b);
5581 vleObjectPropertyApply(Sender);
5582 end;
5583 end
5584 else if Key = _lc[I_PROP_TR_KEYS] then
5585 with KeysForm, vleObjectProperty do
5586 begin // Выбор необходимых ключей:
5587 cbRedKey.Checked := Pos('RK', Values[Key]) > 0;
5588 cbGreenKey.Checked := Pos('GK', Values[Key]) > 0;
5589 cbBlueKey.Checked := Pos('BK', Values[Key]) > 0;
5590 cbRedTeam.Checked := Pos('RT', Values[Key]) > 0;
5591 cbBlueTeam.Checked := Pos('BT', Values[Key]) > 0;
5593 if ShowModal() = mrOK then
5594 begin
5595 b := 0;
5596 if cbRedKey.Checked then
5597 b := KEY_RED;
5598 if cbGreenKey.Checked then
5599 b := b or KEY_GREEN;
5600 if cbBlueKey.Checked then
5601 b := b or KEY_BLUE;
5602 if cbRedTeam.Checked then
5603 b := b or KEY_REDTEAM;
5604 if cbBlueTeam.Checked then
5605 b := b or KEY_BLUETEAM;
5607 Values[Key] := KeyToStr(b);
5608 vleObjectPropertyApply(Sender);
5609 end;
5610 end
5611 else if Key = _lc[I_PROP_TR_FX_TYPE] then
5612 with ChooseTypeForm, vleObjectProperty do
5613 begin // Выбор типа эффекта:
5614 Caption := _lc[I_CAP_FX_TYPE];
5615 lbTypeSelect.Items.Clear();
5617 for b := EFFECT_NONE to EFFECT_FIRE do
5618 lbTypeSelect.Items.Add(EffectToStr(b));
5620 lbTypeSelect.ItemIndex := StrToEffect(Values[Key]);
5622 if ShowModal() = mrOK then
5623 begin
5624 b := lbTypeSelect.ItemIndex;
5625 Values[Key] := EffectToStr(b);
5626 vleObjectPropertyApply(Sender);
5627 end;
5628 end
5629 else if Key = _lc[I_PROP_TR_MONSTER_TYPE] then
5630 with ChooseTypeForm, vleObjectProperty do
5631 begin // Выбор типа монстра:
5632 Caption := _lc[I_CAP_MONSTER_TYPE];
5633 lbTypeSelect.Items.Clear();
5635 for b := MONSTER_DEMON to MONSTER_MAN do
5636 lbTypeSelect.Items.Add(MonsterToStr(b));
5638 lbTypeSelect.ItemIndex := StrToMonster(Values[Key]) - MONSTER_DEMON;
5640 if ShowModal() = mrOK then
5641 begin
5642 b := lbTypeSelect.ItemIndex + MONSTER_DEMON;
5643 Values[Key] := MonsterToStr(b);
5644 vleObjectPropertyApply(Sender);
5645 end;
5646 end
5647 else if Key = _lc[I_PROP_TR_ITEM_TYPE] then
5648 with ChooseTypeForm, vleObjectProperty do
5649 begin // Выбор типа предмета:
5650 Caption := _lc[I_CAP_ITEM_TYPE];
5651 lbTypeSelect.Items.Clear();
5653 for b := ITEM_MEDKIT_SMALL to ITEM_KEY_BLUE do
5654 lbTypeSelect.Items.Add(ItemToStr(b));
5655 lbTypeSelect.Items.Add(ItemToStr(ITEM_BOTTLE));
5656 lbTypeSelect.Items.Add(ItemToStr(ITEM_HELMET));
5657 lbTypeSelect.Items.Add(ItemToStr(ITEM_JETPACK));
5658 lbTypeSelect.Items.Add(ItemToStr(ITEM_INVIS));
5659 lbTypeSelect.Items.Add(ItemToStr(ITEM_WEAPON_FLAMETHROWER));
5660 lbTypeSelect.Items.Add(ItemToStr(ITEM_AMMO_FUELCAN));
5662 b := StrToItem(Values[Key]);
5663 if b >= ITEM_BOTTLE then
5664 b := b - 2;
5665 lbTypeSelect.ItemIndex := b - ITEM_MEDKIT_SMALL;
5667 if ShowModal() = mrOK then
5668 begin
5669 b := lbTypeSelect.ItemIndex + ITEM_MEDKIT_SMALL;
5670 if b >= ITEM_WEAPON_KASTET then
5671 b := b + 2;
5672 Values[Key] := ItemToStr(b);
5673 vleObjectPropertyApply(Sender);
5674 end;
5675 end
5676 else if Key = _lc[I_PROP_TR_SHOT_TYPE] then
5677 with ChooseTypeForm, vleObjectProperty do
5678 begin // Выбор типа предмета:
5679 Caption := _lc[I_PROP_TR_SHOT_TYPE];
5680 lbTypeSelect.Items.Clear();
5682 for b := TRIGGER_SHOT_PISTOL to TRIGGER_SHOT_MAX do
5683 lbTypeSelect.Items.Add(ShotToStr(b));
5685 lbTypeSelect.ItemIndex := StrToShot(Values[Key]);
5687 if ShowModal() = mrOK then
5688 begin
5689 b := lbTypeSelect.ItemIndex;
5690 Values[Key] := ShotToStr(b);
5691 vleObjectPropertyApply(Sender);
5692 end;
5693 end
5694 else if Key = _lc[I_PROP_TR_EFFECT_TYPE] then
5695 with ChooseTypeForm, vleObjectProperty do
5696 begin // Выбор типа эффекта:
5697 Caption := _lc[I_CAP_FX_TYPE];
5698 lbTypeSelect.Items.Clear();
5700 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_PARTICLE]);
5701 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_ANIMATION]);
5702 if Values[Key] = _lc[I_PROP_TR_EFFECT_ANIMATION] then
5703 lbTypeSelect.ItemIndex := 1
5704 else
5705 lbTypeSelect.ItemIndex := 0;
5707 if ShowModal() = mrOK then
5708 begin
5709 b := lbTypeSelect.ItemIndex;
5710 if b = 0 then
5711 Values[Key] := _lc[I_PROP_TR_EFFECT_PARTICLE]
5712 else
5713 Values[Key] := _lc[I_PROP_TR_EFFECT_ANIMATION];
5714 vleObjectPropertyApply(Sender);
5715 end;
5716 end
5717 else if Key = _lc[I_PROP_TR_EFFECT_SUBTYPE] then
5718 with ChooseTypeForm, vleObjectProperty do
5719 begin // Выбор подтипа эффекта:
5720 Caption := _lc[I_CAP_FX_TYPE];
5721 lbTypeSelect.Items.Clear();
5723 if Values[_lc[I_PROP_TR_EFFECT_TYPE]] = _lc[I_PROP_TR_EFFECT_ANIMATION] then
5724 begin
5725 for b := EFFECT_TELEPORT to EFFECT_FIRE do
5726 lbTypeSelect.Items.Add(EffectToStr(b));
5728 lbTypeSelect.ItemIndex := StrToEffect(Values[Key]) - 1;
5729 end else
5730 begin
5731 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_SLIQUID]);
5732 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_LLIQUID]);
5733 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_DLIQUID]);
5734 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_BLOOD]);
5735 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_SPARK]);
5736 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_BUBBLE]);
5737 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_SLIQUID;
5738 if Values[Key] = _lc[I_PROP_TR_EFFECT_LLIQUID] then
5739 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_LLIQUID;
5740 if Values[Key] = _lc[I_PROP_TR_EFFECT_DLIQUID] then
5741 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_DLIQUID;
5742 if Values[Key] = _lc[I_PROP_TR_EFFECT_BLOOD] then
5743 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_BLOOD;
5744 if Values[Key] = _lc[I_PROP_TR_EFFECT_SPARK] then
5745 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_SPARK;
5746 if Values[Key] = _lc[I_PROP_TR_EFFECT_BUBBLE] then
5747 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_BUBBLE;
5748 end;
5750 if ShowModal() = mrOK then
5751 begin
5752 b := lbTypeSelect.ItemIndex;
5754 if Values[_lc[I_PROP_TR_EFFECT_TYPE]] = _lc[I_PROP_TR_EFFECT_ANIMATION] then
5755 Values[Key] := EffectToStr(b + 1)
5756 else begin
5757 Values[Key] := _lc[I_PROP_TR_EFFECT_SLIQUID];
5758 if b = TRIGGER_EFFECT_LLIQUID then
5759 Values[Key] := _lc[I_PROP_TR_EFFECT_LLIQUID];
5760 if b = TRIGGER_EFFECT_DLIQUID then
5761 Values[Key] := _lc[I_PROP_TR_EFFECT_DLIQUID];
5762 if b = TRIGGER_EFFECT_BLOOD then
5763 Values[Key] := _lc[I_PROP_TR_EFFECT_BLOOD];
5764 if b = TRIGGER_EFFECT_SPARK then
5765 Values[Key] := _lc[I_PROP_TR_EFFECT_SPARK];
5766 if b = TRIGGER_EFFECT_BUBBLE then
5767 Values[Key] := _lc[I_PROP_TR_EFFECT_BUBBLE];
5768 end;
5770 vleObjectPropertyApply(Sender);
5771 end;
5772 end
5773 else if Key = _lc[I_PROP_TR_EFFECT_COLOR] then
5774 with vleObjectProperty do
5775 begin // Выбор цвета эффекта:
5776 ColorDialog.Color := StrToIntDef(Values[Key], 0);
5777 if ColorDialog.Execute then
5778 begin
5779 Values[Key] := IntToStr(ColorDialog.Color);
5780 vleObjectPropertyApply(Sender);
5781 end;
5782 end
5783 else if Key = _lc[I_PROP_PANEL_TEX] then
5784 begin // Смена текстуры:
5785 vleObjectProperty.Values[Key] := SelectedTexture();
5786 vleObjectPropertyApply(Sender);
5787 end;
5788 end;
5790 procedure TMainForm.vleObjectPropertyApply(Sender: TObject);
5791 begin
5792 // hack to prevent empty ID in list
5793 RenderPanel.SetFocus();
5794 bApplyProperty.Click();
5795 vleObjectProperty.SetFocus();
5796 end;
5798 procedure TMainForm.aSaveMapExecute(Sender: TObject);
5799 var
5800 FileName, Section, Res: String;
5801 begin
5802 if OpenedMap = '' then
5803 begin
5804 aSaveMapAsExecute(nil);
5805 Exit;
5806 end;
5808 g_ProcessResourceStr(OpenedMap, FileName, Section, Res);
5810 SaveMap(FileName+':\'+Res);
5811 end;
5813 procedure TMainForm.aOpenMapExecute(Sender: TObject);
5814 begin
5815 OpenDialog.Filter := _lc[I_FILE_FILTER_ALL];
5817 if OpenDialog.Execute() then
5818 begin
5819 if (Pos('.ini', LowerCase(ExtractFileName(OpenDialog.FileName))) > 0) then
5820 begin // INI карты:
5821 FullClear();
5823 pLoadProgress.Left := (RenderPanel.Width div 2)-(pLoadProgress.Width div 2);
5824 pLoadProgress.Top := (RenderPanel.Height div 2)-(pLoadProgress.Height div 2);
5825 pLoadProgress.Show();
5827 OpenedMap := '';
5828 OpenedWAD := '';
5830 LoadMapOld(OpenDialog.FileName);
5832 MainForm.Caption := Format('%s - %s', [FormCaption, ExtractFileName(OpenDialog.FileName)]);
5834 pLoadProgress.Hide();
5835 MainForm.FormResize(Self);
5836 end
5837 else // Карты из WAD:
5838 begin
5839 OpenMap(OpenDialog.FileName, '');
5840 end;
5842 OpenDialog.InitialDir := ExtractFileDir(OpenDialog.FileName);
5843 end;
5844 end;
5846 procedure TMainForm.FormActivate(Sender: TObject);
5847 var
5848 lang: Integer;
5849 config: TConfig;
5850 begin
5851 MainForm.ActiveControl := RenderPanel;
5853 // Язык:
5854 if gLanguage = '' then
5855 begin
5856 lang := SelectLanguageForm.ShowModal();
5857 case lang of
5858 1: gLanguage := LANGUAGE_ENGLISH;
5859 else gLanguage := LANGUAGE_RUSSIAN;
5860 end;
5862 config := TConfig.CreateFile(EditorDir+'Editor.cfg');
5863 config.WriteStr('Editor', 'Language', gLanguage);
5864 config.SaveFile(EditorDir+'Editor.cfg');
5865 config.Free();
5866 end;
5868 //e_WriteLog('Read language file', MSG_NOTIFY);
5869 //g_Language_Load(EditorDir+'\data\'+gLanguage+LANGUAGE_FILE_NAME);
5870 g_Language_Set(gLanguage);
5871 end;
5873 procedure TMainForm.aDeleteMap(Sender: TObject);
5874 var
5875 WAD: TWADEditor_1;
5876 MapList: SArray;
5877 MapName: Char16;
5878 a: Integer;
5879 str: String;
5880 begin
5881 OpenDialog.Filter := _lc[I_FILE_FILTER_WAD];
5883 if not OpenDialog.Execute() then
5884 Exit;
5886 WAD := TWADEditor_1.Create();
5888 if not WAD.ReadFile(OpenDialog.FileName) then
5889 begin
5890 WAD.Free();
5891 Exit;
5892 end;
5894 WAD.CreateImage();
5896 MapList := WAD.GetResourcesList('');
5898 SelectMapForm.Caption := _lc[I_CAP_REMOVE];
5899 SelectMapForm.lbMapList.Items.Clear();
5901 if MapList <> nil then
5902 for a := 0 to High(MapList) do
5903 SelectMapForm.lbMapList.Items.Add(win2utf(MapList[a]));
5905 if (SelectMapForm.ShowModal() = mrOK) then
5906 begin
5907 str := SelectMapForm.lbMapList.Items[SelectMapForm.lbMapList.ItemIndex];
5908 MapName := '';
5909 Move(str[1], MapName[0], Min(16, Length(str)));
5911 if MessageBox(0, PChar(Format(_lc[I_MSG_DELETE_MAP_PROMT],
5912 [MapName, OpenDialog.FileName])),
5913 PChar(_lc[I_MSG_DELETE_MAP]),
5914 MB_ICONQUESTION or MB_YESNO or
5915 MB_DEFBUTTON2) <> mrYes then
5916 Exit;
5918 WAD.RemoveResource('', utf2win(MapName));
5920 MessageBox(0, PChar(Format(_lc[I_MSG_MAP_DELETED_PROMT],
5921 [MapName])),
5922 PChar(_lc[I_MSG_MAP_DELETED]),
5923 MB_ICONINFORMATION or MB_OK or
5924 MB_DEFBUTTON1);
5926 WAD.SaveTo(OpenDialog.FileName);
5928 // Удалили текущую карту - сохранять по старому ее нельзя:
5929 if OpenedMap = (OpenDialog.FileName+':\'+MapName) then
5930 begin
5931 OpenedMap := '';
5932 OpenedWAD := '';
5933 MainForm.Caption := FormCaption;
5934 end;
5935 end;
5937 WAD.Free();
5938 end;
5940 procedure TMainForm.vleObjectPropertyKeyDown(Sender: TObject;
5941 var Key: Word; Shift: TShiftState);
5942 begin
5943 if Key = VK_RETURN then
5944 vleObjectPropertyApply(Sender);
5945 end;
5947 procedure MovePanel(var ID: DWORD; MoveType: Byte);
5948 var
5949 _id, a: Integer;
5950 tmp: TPanel;
5951 begin
5952 if (ID = 0) and (MoveType = 0) then
5953 Exit;
5954 if (ID = DWORD(High(gPanels))) and (MoveType <> 0) then
5955 Exit;
5956 if (ID > DWORD(High(gPanels))) then
5957 Exit;
5959 _id := Integer(ID);
5961 if MoveType = 0 then // to Back
5962 begin
5963 if gTriggers <> nil then
5964 for a := 0 to High(gTriggers) do
5965 with gTriggers[a] do
5966 begin
5967 if TriggerType = TRIGGER_NONE then
5968 Continue;
5970 if TexturePanel = _id then
5971 TexturePanel := 0
5972 else
5973 if (TexturePanel >= 0) and (TexturePanel < _id) then
5974 Inc(TexturePanel);
5976 case TriggerType of
5977 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
5978 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP,
5979 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
5980 if Data.PanelID = _id then
5981 Data.PanelID := 0
5982 else
5983 if (Data.PanelID >= 0) and (Data.PanelID < _id) then
5984 Inc(Data.PanelID);
5986 TRIGGER_SHOT:
5987 if Data.ShotPanelID = _id then
5988 Data.ShotPanelID := 0
5989 else
5990 if (Data.ShotPanelID >= 0) and (Data.ShotPanelID < _id) then
5991 Inc(Data.ShotPanelID);
5992 end;
5993 end;
5995 tmp := gPanels[_id];
5997 for a := _id downto 1 do
5998 gPanels[a] := gPanels[a-1];
6000 gPanels[0] := tmp;
6002 ID := 0;
6003 end
6004 else // to Front
6005 begin
6006 if gTriggers <> nil then
6007 for a := 0 to High(gTriggers) do
6008 with gTriggers[a] do
6009 begin
6010 if TriggerType = TRIGGER_NONE then
6011 Continue;
6013 if TexturePanel = _id then
6014 TexturePanel := High(gPanels)
6015 else
6016 if TexturePanel > _id then
6017 Dec(TexturePanel);
6019 case TriggerType of
6020 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
6021 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP,
6022 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
6023 if Data.PanelID = _id then
6024 Data.PanelID := High(gPanels)
6025 else
6026 if Data.PanelID > _id then
6027 Dec(Data.PanelID);
6029 TRIGGER_SHOT:
6030 if Data.ShotPanelID = _id then
6031 Data.ShotPanelID := High(gPanels)
6032 else
6033 if Data.ShotPanelID > _id then
6034 Dec(Data.ShotPanelID);
6035 end;
6036 end;
6038 tmp := gPanels[_id];
6040 for a := _id to High(gPanels)-1 do
6041 gPanels[a] := gPanels[a+1];
6043 gPanels[High(gPanels)] := tmp;
6045 ID := High(gPanels);
6046 end;
6047 end;
6049 procedure TMainForm.aMoveToBack(Sender: TObject);
6050 var
6051 a: Integer;
6052 begin
6053 if SelectedObjects = nil then
6054 Exit;
6056 for a := 0 to High(SelectedObjects) do
6057 with SelectedObjects[a] do
6058 if Live and (ObjectType = OBJECT_PANEL) then
6059 begin
6060 SelectedObjects[0] := SelectedObjects[a];
6061 SetLength(SelectedObjects, 1);
6062 MovePanel(ID, 0);
6063 FillProperty();
6064 Break;
6065 end;
6066 end;
6068 procedure TMainForm.aMoveToFore(Sender: TObject);
6069 var
6070 a: Integer;
6071 begin
6072 if SelectedObjects = nil then
6073 Exit;
6075 for a := 0 to High(SelectedObjects) do
6076 with SelectedObjects[a] do
6077 if Live and (ObjectType = OBJECT_PANEL) then
6078 begin
6079 SelectedObjects[0] := SelectedObjects[a];
6080 SetLength(SelectedObjects, 1);
6081 MovePanel(ID, 1);
6082 FillProperty();
6083 Break;
6084 end;
6085 end;
6087 procedure TMainForm.aSaveMapAsExecute(Sender: TObject);
6088 var
6089 idx: Integer;
6090 begin
6091 SaveDialog.Filter := _lc[I_FILE_FILTER_WAD];
6093 if not SaveDialog.Execute() then
6094 Exit;
6096 SaveMapForm.GetMaps(SaveDialog.FileName, True);
6098 if SaveMapForm.ShowModal() <> mrOK then
6099 Exit;
6101 SaveDialog.InitialDir := ExtractFileDir(SaveDialog.FileName);
6102 OpenedMap := SaveDialog.FileName+':\'+SaveMapForm.eMapName.Text;
6103 OpenedWAD := SaveDialog.FileName;
6105 idx := RecentFiles.IndexOf(OpenedMap);
6106 // Такая карта уже недавно открывалась:
6107 if idx >= 0 then
6108 RecentFiles.Delete(idx);
6109 RecentFiles.Insert(0, OpenedMap);
6110 RefreshRecentMenu;
6112 SaveMap(OpenedMap);
6114 gMapInfo.FileName := SaveDialog.FileName;
6115 gMapInfo.MapName := SaveMapForm.eMapName.Text;
6116 UpdateCaption(gMapInfo.Name, ExtractFileName(gMapInfo.FileName), gMapInfo.MapName);
6117 end;
6119 procedure TMainForm.aSelectAllExecute(Sender: TObject);
6120 var
6121 a: Integer;
6122 begin
6123 RemoveSelectFromObjects();
6125 case pcObjects.ActivePageIndex+1 of
6126 OBJECT_PANEL:
6127 if gPanels <> nil then
6128 for a := 0 to High(gPanels) do
6129 if gPanels[a].PanelType <> PANEL_NONE then
6130 SelectObject(OBJECT_PANEL, a, True);
6131 OBJECT_ITEM:
6132 if gItems <> nil then
6133 for a := 0 to High(gItems) do
6134 if gItems[a].ItemType <> ITEM_NONE then
6135 SelectObject(OBJECT_ITEM, a, True);
6136 OBJECT_MONSTER:
6137 if gMonsters <> nil then
6138 for a := 0 to High(gMonsters) do
6139 if gMonsters[a].MonsterType <> MONSTER_NONE then
6140 SelectObject(OBJECT_MONSTER, a, True);
6141 OBJECT_AREA:
6142 if gAreas <> nil then
6143 for a := 0 to High(gAreas) do
6144 if gAreas[a].AreaType <> AREA_NONE then
6145 SelectObject(OBJECT_AREA, a, True);
6146 OBJECT_TRIGGER:
6147 if gTriggers <> nil then
6148 for a := 0 to High(gTriggers) do
6149 if gTriggers[a].TriggerType <> TRIGGER_NONE then
6150 SelectObject(OBJECT_TRIGGER, a, True);
6151 end;
6152 end;
6154 procedure TMainForm.tbGridOnClick(Sender: TObject);
6155 begin
6156 DotEnable := not DotEnable;
6157 (Sender as TToolButton).Down := DotEnable;
6158 end;
6160 procedure TMainForm.OnIdle(Sender: TObject; var Done: Boolean);
6161 begin
6162 // FIXME: this is a shitty hack
6163 if not gDataLoaded then
6164 begin
6165 e_WriteLog('Init OpenGL', MSG_NOTIFY);
6166 e_InitGL();
6167 e_WriteLog('Loading data', MSG_NOTIFY);
6168 LoadStdFont('STDTXT', 'STDFONT', gEditorFont);
6169 e_WriteLog('Loading more data', MSG_NOTIFY);
6170 LoadData();
6171 e_WriteLog('Loading even more data', MSG_NOTIFY);
6172 gDataLoaded := True;
6173 MainForm.FormResize(nil);
6174 end;
6175 Draw();
6176 end;
6178 procedure TMainForm.miMapPreviewClick(Sender: TObject);
6179 begin
6180 if PreviewMode = 2 then
6181 Exit;
6183 if PreviewMode = 0 then
6184 begin
6185 Splitter2.Visible := False;
6186 Splitter1.Visible := False;
6187 StatusBar.Visible := False;
6188 PanelObjs.Visible := False;
6189 PanelProps.Visible := False;
6190 MainToolBar.Visible := False;
6191 sbHorizontal.Visible := False;
6192 sbVertical.Visible := False;
6193 end
6194 else
6195 begin
6196 StatusBar.Visible := True;
6197 PanelObjs.Visible := True;
6198 PanelProps.Visible := True;
6199 Splitter2.Visible := True;
6200 Splitter1.Visible := True;
6201 MainToolBar.Visible := True;
6202 sbHorizontal.Visible := True;
6203 sbVertical.Visible := True;
6204 end;
6206 PreviewMode := PreviewMode xor 1;
6207 (Sender as TMenuItem).Checked := PreviewMode > 0;
6209 FormResize(Self);
6210 end;
6212 procedure TMainForm.miLayer1Click(Sender: TObject);
6213 begin
6214 SwitchLayer(LAYER_BACK);
6215 end;
6217 procedure TMainForm.miLayer2Click(Sender: TObject);
6218 begin
6219 SwitchLayer(LAYER_WALLS);
6220 end;
6222 procedure TMainForm.miLayer3Click(Sender: TObject);
6223 begin
6224 SwitchLayer(LAYER_FOREGROUND);
6225 end;
6227 procedure TMainForm.miLayer4Click(Sender: TObject);
6228 begin
6229 SwitchLayer(LAYER_STEPS);
6230 end;
6232 procedure TMainForm.miLayer5Click(Sender: TObject);
6233 begin
6234 SwitchLayer(LAYER_WATER);
6235 end;
6237 procedure TMainForm.miLayer6Click(Sender: TObject);
6238 begin
6239 SwitchLayer(LAYER_ITEMS);
6240 end;
6242 procedure TMainForm.miLayer7Click(Sender: TObject);
6243 begin
6244 SwitchLayer(LAYER_MONSTERS);
6245 end;
6247 procedure TMainForm.miLayer8Click(Sender: TObject);
6248 begin
6249 SwitchLayer(LAYER_AREAS);
6250 end;
6252 procedure TMainForm.miLayer9Click(Sender: TObject);
6253 begin
6254 SwitchLayer(LAYER_TRIGGERS);
6255 end;
6257 procedure TMainForm.tbShowClick(Sender: TObject);
6258 var
6259 a: Integer;
6260 b: Boolean;
6261 begin
6262 b := True;
6263 for a := 0 to High(LayerEnabled) do
6264 b := b and LayerEnabled[a];
6266 b := not b;
6268 ShowLayer(LAYER_BACK, b);
6269 ShowLayer(LAYER_WALLS, b);
6270 ShowLayer(LAYER_FOREGROUND, b);
6271 ShowLayer(LAYER_STEPS, b);
6272 ShowLayer(LAYER_WATER, b);
6273 ShowLayer(LAYER_ITEMS, b);
6274 ShowLayer(LAYER_MONSTERS, b);
6275 ShowLayer(LAYER_AREAS, b);
6276 ShowLayer(LAYER_TRIGGERS, b);
6277 end;
6279 procedure TMainForm.miMiniMapClick(Sender: TObject);
6280 begin
6281 SwitchMap();
6282 end;
6284 procedure TMainForm.miSwitchGridClick(Sender: TObject);
6285 begin
6286 if DotStep = DotStepOne then
6287 DotStep := DotStepTwo
6288 else
6289 DotStep := DotStepOne;
6291 MousePos.X := (MousePos.X div DotStep) * DotStep;
6292 MousePos.Y := (MousePos.Y div DotStep) * DotStep;
6293 end;
6295 procedure TMainForm.miShowEdgesClick(Sender: TObject);
6296 begin
6297 ShowEdges();
6298 end;
6300 procedure TMainForm.miSnapToGridClick(Sender: TObject);
6301 begin
6302 SnapToGrid := not SnapToGrid;
6304 MousePos.X := (MousePos.X div DotStep) * DotStep;
6305 MousePos.Y := (MousePos.Y div DotStep) * DotStep;
6307 miSnapToGrid.Checked := SnapToGrid;
6308 end;
6310 procedure TMainForm.minexttabClick(Sender: TObject);
6311 begin
6312 if pcObjects.ActivePageIndex < pcObjects.PageCount-1 then
6313 pcObjects.ActivePageIndex := pcObjects.ActivePageIndex+1
6314 else
6315 pcObjects.ActivePageIndex := 0;
6316 end;
6318 procedure TMainForm.miSaveMiniMapClick(Sender: TObject);
6319 begin
6320 SaveMiniMapForm.ShowModal();
6321 end;
6323 procedure TMainForm.bClearTextureClick(Sender: TObject);
6324 begin
6325 lbTextureList.ItemIndex := -1;
6326 lTextureWidth.Caption := '';
6327 lTextureHeight.Caption := '';
6328 end;
6330 procedure TMainForm.miPackMapClick(Sender: TObject);
6331 begin
6332 PackMapForm.ShowModal();
6333 end;
6335 procedure TMainForm.miMapTestSettingsClick(Sender: TObject);
6336 begin
6337 MapTestForm.ShowModal();
6338 end;
6340 procedure TMainForm.miTestMapClick(Sender: TObject);
6341 var
6342 cmd, mapWAD, mapToRun, tempWAD: String;
6343 opt: LongWord;
6344 time: Integer;
6345 proc: TProcessUTF8;
6346 res: Boolean;
6347 begin
6348 mapToRun := '';
6349 if OpenedMap <> '' then
6350 begin
6351 // Указываем текущую карту для теста:
6352 g_ProcessResourceStr(OpenedMap, @mapWAD, nil, @mapToRun);
6353 mapToRun := mapWAD + ':\' + mapToRun;
6354 mapToRun := ExtractRelativePath(ExtractFilePath(TestD2dExe) + 'maps/', mapToRun);
6355 end;
6356 // Сохраняем временную карту:
6357 time := 0;
6358 repeat
6359 mapWAD := ExtractFilePath(TestD2dExe) + Format('maps/temp%.4d.wad', [time]);
6360 Inc(time);
6361 until not FileExists(mapWAD);
6362 tempWAD := mapWAD + ':\' + TEST_MAP_NAME;
6363 SaveMap(tempWAD);
6365 tempWAD := ExtractRelativePath(ExtractFilePath(TestD2dExe) + 'maps/', tempWAD);
6366 // Если карта не была открыта, указываем временную в качестве текущей:
6367 if mapToRun = '' then
6368 mapToRun := tempWAD;
6370 // Опции игры:
6371 opt := 32 + 64;
6372 if TestOptionsTwoPlayers then
6373 opt := opt + 1;
6374 if TestOptionsTeamDamage then
6375 opt := opt + 2;
6376 if TestOptionsAllowExit then
6377 opt := opt + 4;
6378 if TestOptionsWeaponStay then
6379 opt := opt + 8;
6380 if TestOptionsMonstersDM then
6381 opt := opt + 16;
6383 // Составляем командную строку:
6384 cmd := '-map "' + mapToRun + '"';
6385 cmd := cmd + ' -testmap "' + tempWAD + '"';
6386 cmd := cmd + ' -gm ' + TestGameMode;
6387 cmd := cmd + ' -limt ' + TestLimTime;
6388 cmd := cmd + ' -lims ' + TestLimScore;
6389 cmd := cmd + ' -opt ' + IntToStr(opt);
6391 if TestMapOnce then
6392 cmd := cmd + ' --close';
6394 cmd := cmd + ' --debug';
6396 // Запускаем:
6397 proc := TProcessUTF8.Create(nil);
6398 proc.Executable := TestD2dExe;
6399 proc.Parameters.Add(cmd);
6400 res := True;
6401 try
6402 proc.Execute();
6403 except
6404 res := False;
6405 end;
6406 if res then
6407 begin
6408 Application.Minimize();
6409 proc.WaitOnExit();
6410 end;
6411 if (not res) or (proc.ExitCode < 0) then
6412 begin
6413 MessageBox(0, 'FIXME',
6414 PChar(_lc[I_MSG_EXEC_ERROR]),
6415 MB_OK or MB_ICONERROR);
6416 end;
6417 proc.Free();
6419 SysUtils.DeleteFile(mapWAD);
6420 Application.Restore();
6421 end;
6423 procedure TMainForm.sbVerticalScroll(Sender: TObject;
6424 ScrollCode: TScrollCode; var ScrollPos: Integer);
6425 begin
6426 MapOffset.Y := -Normalize16(sbVertical.Position);
6427 end;
6429 procedure TMainForm.sbHorizontalScroll(Sender: TObject;
6430 ScrollCode: TScrollCode; var ScrollPos: Integer);
6431 begin
6432 MapOffset.X := -Normalize16(sbHorizontal.Position);
6433 end;
6435 procedure TMainForm.miOpenWadMapClick(Sender: TObject);
6436 begin
6437 if OpenedWAD <> '' then
6438 begin
6439 OpenMap(OpenedWAD, '');
6440 end;
6441 end;
6443 procedure TMainForm.selectall1Click(Sender: TObject);
6444 var
6445 a: Integer;
6446 begin
6447 RemoveSelectFromObjects();
6449 if gPanels <> nil then
6450 for a := 0 to High(gPanels) do
6451 if gPanels[a].PanelType <> PANEL_NONE then
6452 SelectObject(OBJECT_PANEL, a, True);
6454 if gItems <> nil then
6455 for a := 0 to High(gItems) do
6456 if gItems[a].ItemType <> ITEM_NONE then
6457 SelectObject(OBJECT_ITEM, a, True);
6459 if gMonsters <> nil then
6460 for a := 0 to High(gMonsters) do
6461 if gMonsters[a].MonsterType <> MONSTER_NONE then
6462 SelectObject(OBJECT_MONSTER, a, True);
6464 if gAreas <> nil then
6465 for a := 0 to High(gAreas) do
6466 if gAreas[a].AreaType <> AREA_NONE then
6467 SelectObject(OBJECT_AREA, a, True);
6469 if gTriggers <> nil then
6470 for a := 0 to High(gTriggers) do
6471 if gTriggers[a].TriggerType <> TRIGGER_NONE then
6472 SelectObject(OBJECT_TRIGGER, a, True);
6473 end;
6475 procedure TMainForm.Splitter1CanResize(Sender: TObject;
6476 var NewSize: Integer; var Accept: Boolean);
6477 begin
6478 Accept := (NewSize > 140);
6479 end;
6481 procedure TMainForm.Splitter2CanResize(Sender: TObject;
6482 var NewSize: Integer; var Accept: Boolean);
6483 begin
6484 Accept := (NewSize > 110);
6485 end;
6487 procedure TMainForm.vleObjectPropertyEnter(Sender: TObject);
6488 begin
6489 EditingProperties := True;
6490 end;
6492 procedure TMainForm.vleObjectPropertyExit(Sender: TObject);
6493 begin
6494 EditingProperties := False;
6495 end;
6497 procedure TMainForm.FormKeyUp(Sender: TObject; var Key: Word;
6498 Shift: TShiftState);
6499 begin
6500 // Объекты передвигались:
6501 if MainForm.ActiveControl = RenderPanel then
6502 begin
6503 if (Key = VK_NUMPAD4) or
6504 (Key = VK_NUMPAD6) or
6505 (Key = VK_NUMPAD8) or
6506 (Key = VK_NUMPAD5) or
6507 (Key = Ord('V')) then
6508 FillProperty();
6509 end;
6510 // Быстрое превью карты:
6511 if Key = Ord('E') then
6512 begin
6513 if PreviewMode = 2 then
6514 PreviewMode := 0;
6515 end;
6516 end;
6518 end.