DEADSOFTWARE

Main: Epic encoding and other bugs megafix!
[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: Boolean = False;
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.GetMaps(FileName);
2001 if (FileName = OpenedWAD) and
2002 (OpenedMap <> '') then
2003 begin
2004 MapName := OpenedMap;
2005 while (Pos(':\', MapName) > 0) do
2006 Delete(MapName, 1, Pos(':\', MapName) + 1);
2008 idx := SelectMapForm.lbMapList.Items.IndexOf(MapName);
2009 SelectMapForm.lbMapList.ItemIndex := idx;
2010 end
2011 else
2012 if SelectMapForm.lbMapList.Count > 0 then
2013 SelectMapForm.lbMapList.ItemIndex := 0
2014 else
2015 SelectMapForm.lbMapList.ItemIndex := -1;
2017 if mapN = '' then
2018 idx := -1
2019 else
2020 idx := SelectMapForm.lbMapList.Items.IndexOf(mapN);
2022 if idx < 0 then
2023 begin
2024 if (SelectMapForm.ShowModal() = mrOK) and
2025 (SelectMapForm.lbMapList.ItemIndex <> -1) then
2026 idx := SelectMapForm.lbMapList.ItemIndex
2027 else
2028 Exit;
2029 end;
2031 MapName := SelectMapForm.lbMapList.Items[idx];
2033 with MainForm do
2034 begin
2035 FullClear();
2037 pLoadProgress.Left := (RenderPanel.Width div 2)-(pLoadProgress.Width div 2);
2038 pLoadProgress.Top := (RenderPanel.Height div 2)-(pLoadProgress.Height div 2);
2039 pLoadProgress.Show();
2041 OpenedMap := FileName+':\'+MapName;
2042 OpenedWAD := FileName;
2044 idx := RecentFiles.IndexOf(OpenedMap);
2045 // Такая карта уже недавно открывалась:
2046 if idx >= 0 then
2047 RecentFiles.Delete(idx);
2048 RecentFiles.Insert(0, OpenedMap);
2049 RefreshRecentMenu();
2051 LoadMap(OpenedMap);
2053 pLoadProgress.Hide();
2054 FormResize(nil);
2056 lbTextureList.Sorted := True;
2057 lbTextureList.Sorted := False;
2059 UpdateCaption(gMapInfo.Name, ExtractFileName(FileName), MapName);
2060 end;
2061 end;
2063 procedure MoveSelectedObjects(Wall, alt: Boolean; dx, dy: Integer);
2064 var
2065 okX, okY: Boolean;
2066 a: Integer;
2067 begin
2068 if SelectedObjects = nil then
2069 Exit;
2071 okX := True;
2072 okY := True;
2074 if Wall then
2075 for a := 0 to High(SelectedObjects) do
2076 if SelectedObjects[a].Live then
2077 begin
2078 if ObjectCollideLevel(SelectedObjects[a].ID, SelectedObjects[a].ObjectType, dx, 0) then
2079 okX := False;
2081 if ObjectCollideLevel(SelectedObjects[a].ID, SelectedObjects[a].ObjectType, 0, dy) then
2082 okY := False;
2084 if (not okX) or (not okY) then
2085 Break;
2086 end;
2088 if okX or okY then
2089 begin
2090 for a := 0 to High(SelectedObjects) do
2091 if SelectedObjects[a].Live then
2092 begin
2093 if okX then
2094 MoveObject(SelectedObjects[a].ObjectType, SelectedObjects[a].ID, dx, 0);
2096 if okY then
2097 MoveObject(SelectedObjects[a].ObjectType, SelectedObjects[a].ID, 0, dy);
2099 if alt and (SelectedObjects[a].ObjectType = OBJECT_TRIGGER) then
2100 begin
2101 if gTriggers[SelectedObjects[a].ID].TriggerType in [TRIGGER_PRESS,
2102 TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF] then
2103 begin // Двигаем зону Расширителя
2104 if okX then
2105 gTriggers[SelectedObjects[a].ID].Data.tX := gTriggers[SelectedObjects[a].ID].Data.tX+dx;
2106 if okY then
2107 gTriggers[SelectedObjects[a].ID].Data.tY := gTriggers[SelectedObjects[a].ID].Data.tY+dy;
2108 end;
2110 if gTriggers[SelectedObjects[a].ID].TriggerType in [TRIGGER_TELEPORT] then
2111 begin // Двигаем точку назначения Телепорта
2112 if okX then
2113 gTriggers[SelectedObjects[a].ID].Data.TargetPoint.X := gTriggers[SelectedObjects[a].ID].Data.TargetPoint.X+dx;
2114 if okY then
2115 gTriggers[SelectedObjects[a].ID].Data.TargetPoint.Y := gTriggers[SelectedObjects[a].ID].Data.TargetPoint.Y+dy;
2116 end;
2118 if gTriggers[SelectedObjects[a].ID].TriggerType in [TRIGGER_SPAWNMONSTER] then
2119 begin // Двигаем точку создания монстра
2120 if okX then
2121 gTriggers[SelectedObjects[a].ID].Data.MonPos.X := gTriggers[SelectedObjects[a].ID].Data.MonPos.X+dx;
2122 if okY then
2123 gTriggers[SelectedObjects[a].ID].Data.MonPos.Y := gTriggers[SelectedObjects[a].ID].Data.MonPos.Y+dy;
2124 end;
2126 if gTriggers[SelectedObjects[a].ID].TriggerType in [TRIGGER_SPAWNITEM] then
2127 begin // Двигаем точку создания предмета
2128 if okX then
2129 gTriggers[SelectedObjects[a].ID].Data.ItemPos.X := gTriggers[SelectedObjects[a].ID].Data.ItemPos.X+dx;
2130 if okY then
2131 gTriggers[SelectedObjects[a].ID].Data.ItemPos.Y := gTriggers[SelectedObjects[a].ID].Data.ItemPos.Y+dy;
2132 end;
2134 if gTriggers[SelectedObjects[a].ID].TriggerType in [TRIGGER_SHOT] then
2135 begin // Двигаем точку создания выстрела
2136 if okX then
2137 gTriggers[SelectedObjects[a].ID].Data.ShotPos.X := gTriggers[SelectedObjects[a].ID].Data.ShotPos.X+dx;
2138 if okY then
2139 gTriggers[SelectedObjects[a].ID].Data.ShotPos.Y := gTriggers[SelectedObjects[a].ID].Data.ShotPos.Y+dy;
2140 end;
2141 end;
2142 end;
2144 LastMovePoint := MousePos;
2145 end;
2146 end;
2148 procedure ShowLayer(Layer: Byte; show: Boolean);
2149 begin
2150 LayerEnabled[Layer] := show;
2152 case Layer of
2153 LAYER_BACK:
2154 begin
2155 MainForm.miLayer1.Checked := show;
2156 MainForm.miLayerP1.Checked := show;
2157 end;
2158 LAYER_WALLS:
2159 begin
2160 MainForm.miLayer2.Checked := show;
2161 MainForm.miLayerP2.Checked := show;
2162 end;
2163 LAYER_FOREGROUND:
2164 begin
2165 MainForm.miLayer3.Checked := show;
2166 MainForm.miLayerP3.Checked := show;
2167 end;
2168 LAYER_STEPS:
2169 begin
2170 MainForm.miLayer4.Checked := show;
2171 MainForm.miLayerP4.Checked := show;
2172 end;
2173 LAYER_WATER:
2174 begin
2175 MainForm.miLayer5.Checked := show;
2176 MainForm.miLayerP5.Checked := show;
2177 end;
2178 LAYER_ITEMS:
2179 begin
2180 MainForm.miLayer6.Checked := show;
2181 MainForm.miLayerP6.Checked := show;
2182 end;
2183 LAYER_MONSTERS:
2184 begin
2185 MainForm.miLayer7.Checked := show;
2186 MainForm.miLayerP7.Checked := show;
2187 end;
2188 LAYER_AREAS:
2189 begin
2190 MainForm.miLayer8.Checked := show;
2191 MainForm.miLayerP8.Checked := show;
2192 end;
2193 LAYER_TRIGGERS:
2194 begin
2195 MainForm.miLayer9.Checked := show;
2196 MainForm.miLayerP9.Checked := show;
2197 end;
2198 end;
2200 RemoveSelectFromObjects();
2201 end;
2203 procedure SwitchLayer(Layer: Byte);
2204 begin
2205 ShowLayer(Layer, not LayerEnabled[Layer]);
2206 end;
2208 procedure SwitchMap();
2209 begin
2210 ShowMap := not ShowMap;
2211 MainForm.tbShowMap.Down := ShowMap;
2212 end;
2214 procedure ShowEdges();
2215 begin
2216 if drEdge[3] < 255 then
2217 drEdge[3] := 255
2218 else
2219 drEdge[3] := gAlphaEdge;
2220 end;
2222 function SelectedTexture(): String;
2223 begin
2224 if MainForm.lbTextureList.ItemIndex <> -1 then
2225 Result := MainForm.lbTextureList.Items[MainForm.lbTextureList.ItemIndex]
2226 else
2227 Result := '';
2228 end;
2230 function IsSpecialTextureSel(): Boolean;
2231 begin
2232 Result := (MainForm.lbTextureList.ItemIndex <> -1) and
2233 IsSpecialTexture(MainForm.lbTextureList.Items[MainForm.lbTextureList.ItemIndex]);
2234 end;
2236 function CopyBufferToString(var CopyBuf: TCopyRecArray): String;
2237 var
2238 i, j: Integer;
2239 Res: String;
2241 procedure AddInt(x: Integer);
2242 begin
2243 Res := Res + IntToStr(x) + ' ';
2244 end;
2246 begin
2247 Result := '';
2249 if Length(CopyBuf) = 0 then
2250 Exit;
2252 Res := CLIPBOARD_SIG + ' ';
2254 for i := 0 to High(CopyBuf) do
2255 begin
2256 if (CopyBuf[i].ObjectType = OBJECT_PANEL) and
2257 (CopyBuf[i].Panel = nil) then
2258 Continue;
2260 // Тип объекта:
2261 AddInt(CopyBuf[i].ObjectType);
2262 Res := Res + '; ';
2264 // Свойства объекта:
2265 case CopyBuf[i].ObjectType of
2266 OBJECT_PANEL:
2267 with CopyBuf[i].Panel^ do
2268 begin
2269 AddInt(PanelType);
2270 AddInt(X);
2271 AddInt(Y);
2272 AddInt(Width);
2273 AddInt(Height);
2274 Res := Res + '"' + TextureName + '" ';
2275 AddInt(Alpha);
2276 AddInt(IfThen(Blending, 1, 0));
2277 end;
2279 OBJECT_ITEM:
2280 with CopyBuf[i].Item do
2281 begin
2282 AddInt(ItemType);
2283 AddInt(X);
2284 AddInt(Y);
2285 AddInt(IfThen(OnlyDM, 1, 0));
2286 AddInt(IfThen(Fall, 1, 0));
2287 end;
2289 OBJECT_MONSTER:
2290 with CopyBuf[i].Monster do
2291 begin
2292 AddInt(MonsterType);
2293 AddInt(X);
2294 AddInt(Y);
2295 AddInt(IfThen(Direction = D_LEFT, 1, 0));
2296 end;
2298 OBJECT_AREA:
2299 with CopyBuf[i].Area do
2300 begin
2301 AddInt(AreaType);
2302 AddInt(X);
2303 AddInt(Y);
2304 AddInt(IfThen(Direction = D_LEFT, 1, 0));
2305 end;
2307 OBJECT_TRIGGER:
2308 with CopyBuf[i].Trigger do
2309 begin
2310 AddInt(TriggerType);
2311 AddInt(X);
2312 AddInt(Y);
2313 AddInt(Width);
2314 AddInt(Height);
2315 AddInt(ActivateType);
2316 AddInt(Key);
2317 AddInt(IfThen(Enabled, 1, 0));
2318 AddInt(TexturePanel);
2320 for j := 0 to 127 do
2321 AddInt(Data.Default[j]);
2322 end;
2323 end;
2324 end;
2326 Result := Res;
2327 end;
2329 procedure StringToCopyBuffer(Str: String; var CopyBuf: TCopyRecArray);
2330 var
2331 i, j, t: Integer;
2333 function GetNext(): String;
2334 var
2335 p: Integer;
2337 begin
2338 if Str[1] = '"' then
2339 begin
2340 Delete(Str, 1, 1);
2341 p := Pos('"', Str);
2343 if p = 0 then
2344 begin
2345 Result := Str;
2346 Str := '';
2347 end
2348 else
2349 begin
2350 Result := Copy(Str, 1, p-1);
2351 Delete(Str, 1, p);
2352 Str := Trim(Str);
2353 end;
2354 end
2355 else
2356 begin
2357 p := Pos(' ', Str);
2359 if p = 0 then
2360 begin
2361 Result := Str;
2362 Str := '';
2363 end
2364 else
2365 begin
2366 Result := Copy(Str, 1, p-1);
2367 Delete(Str, 1, p);
2368 Str := Trim(Str);
2369 end;
2370 end;
2371 end;
2373 begin
2374 Str := Trim(Str);
2376 if GetNext() <> CLIPBOARD_SIG then
2377 Exit;
2379 while Str <> '' do
2380 begin
2381 // Тип объекта:
2382 t := StrToIntDef(GetNext(), 0);
2384 if (t < OBJECT_PANEL) or (t > OBJECT_TRIGGER) or
2385 (GetNext() <> ';') then
2386 begin // Что-то не то => пропускаем:
2387 t := Pos(';', Str);
2388 Delete(Str, 1, t);
2389 Str := Trim(Str);
2391 Continue;
2392 end;
2394 i := Length(CopyBuf);
2395 SetLength(CopyBuf, i + 1);
2397 CopyBuf[i].ObjectType := t;
2398 CopyBuf[i].Panel := nil;
2400 // Свойства объекта:
2401 case t of
2402 OBJECT_PANEL:
2403 begin
2404 New(CopyBuf[i].Panel);
2406 with CopyBuf[i].Panel^ do
2407 begin
2408 PanelType := StrToIntDef(GetNext(), PANEL_WALL);
2409 X := StrToIntDef(GetNext(), 0);
2410 Y := StrToIntDef(GetNext(), 0);
2411 Width := StrToIntDef(GetNext(), 16);
2412 Height := StrToIntDef(GetNext(), 16);
2413 TextureName := GetNext();
2414 Alpha := StrToIntDef(GetNext(), 0);
2415 Blending := (GetNext() = '1');
2416 end;
2417 end;
2419 OBJECT_ITEM:
2420 with CopyBuf[i].Item do
2421 begin
2422 ItemType := StrToIntDef(GetNext(), ITEM_MEDKIT_SMALL);
2423 X := StrToIntDef(GetNext(), 0);
2424 Y := StrToIntDef(GetNext(), 0);
2425 OnlyDM := (GetNext() = '1');
2426 Fall := (GetNext() = '1');
2427 end;
2429 OBJECT_MONSTER:
2430 with CopyBuf[i].Monster do
2431 begin
2432 MonsterType := StrToIntDef(GetNext(), MONSTER_DEMON);
2433 X := StrToIntDef(GetNext(), 0);
2434 Y := StrToIntDef(GetNext(), 0);
2436 if GetNext() = '1' then
2437 Direction := D_LEFT
2438 else
2439 Direction := D_RIGHT;
2440 end;
2442 OBJECT_AREA:
2443 with CopyBuf[i].Area do
2444 begin
2445 AreaType := StrToIntDef(GetNext(), AREA_PLAYERPOINT1);
2446 X := StrToIntDef(GetNext(), 0);
2447 Y := StrToIntDef(GetNext(), 0);
2448 if GetNext() = '1' then
2449 Direction := D_LEFT
2450 else
2451 Direction := D_RIGHT;
2452 end;
2454 OBJECT_TRIGGER:
2455 with CopyBuf[i].Trigger do
2456 begin
2457 TriggerType := StrToIntDef(GetNext(), TRIGGER_EXIT);
2458 X := StrToIntDef(GetNext(), 0);
2459 Y := StrToIntDef(GetNext(), 0);
2460 Width := StrToIntDef(GetNext(), 16);
2461 Height := StrToIntDef(GetNext(), 16);
2462 ActivateType := StrToIntDef(GetNext(), 0);
2463 Key := StrToIntDef(GetNext(), 0);
2464 Enabled := (GetNext() = '1');
2465 TexturePanel := StrToIntDef(GetNext(), 0);
2467 for j := 0 to 127 do
2468 Data.Default[j] := StrToIntDef(GetNext(), 0);
2469 end;
2470 end;
2471 end;
2472 end;
2474 //----------------------------------------
2475 //Закончились вспомогательные процедуры
2476 //----------------------------------------
2478 procedure TMainForm.RefreshRecentMenu();
2479 var
2480 i: Integer;
2481 MI: TMenuItem;
2482 begin
2483 // Лишние запомненные карты:
2484 while RecentFiles.Count > RecentCount do
2485 RecentFiles.Delete(RecentFiles.Count-1);
2487 // Лишние строки меню:
2488 while MainMenu.Items[0].Count > RECENT_FILES_MENU_START do
2489 MainMenu.Items[0].Delete(MainMenu.Items[0].Count-1);
2491 // Отделение списка карт от строки "Выход":
2492 if RecentFiles.Count > 0 then
2493 begin
2494 MI := TMenuItem.Create(MainMenu.Items[0]);
2495 MI.Caption := '-';
2496 MainMenu.Items[0].Add(MI);
2497 end;
2499 // Добавление в меню списка запомненных карт:
2500 for i := 0 to RecentFiles.Count-1 do
2501 begin
2502 MI := TMenuItem.Create(MainMenu.Items[0]);
2503 MI.Caption := IntToStr(i+1) + ' ' + RecentFiles[i];
2504 MI.OnClick := aRecentFileExecute;
2505 MainMenu.Items[0].Add(MI);
2506 end;
2507 end;
2509 procedure TMainForm.aRecentFileExecute(Sender: TObject);
2510 var
2511 n, pw: Integer;
2512 s, fn: String;
2513 b: Boolean;
2514 begin
2515 s := LowerCase((Sender as TMenuItem).Caption);
2516 Delete(s, Pos('&', s), 1);
2517 s := Trim(Copy(s, 1, 2));
2518 n := StrToIntDef(s, 0) - 1;
2520 if (n < 0) or (n >= RecentFiles.Count) then
2521 Exit;
2523 s := RecentFiles[n];
2524 pw := Pos('.wad:\', LowerCase(s));
2525 b := False;
2527 if pw > 0 then
2528 begin // Map name included
2529 fn := Copy(s, 1, pw + 3);
2530 Delete(s, 1, pw + 5);
2531 if (FileExists(fn)) then
2532 begin
2533 OpenMap(fn, s);
2534 b := True;
2535 end;
2536 end
2537 else // Only wad name
2538 if (FileExists(s)) then
2539 begin
2540 OpenMap(s, '');
2541 b := True;
2542 end;
2544 if (not b) and (MessageBox(0, PChar(_lc[I_MSG_DEL_RECENT_PROMT]),
2545 PChar(_lc[I_MSG_DEL_RECENT]), MB_ICONQUESTION or MB_YESNO) = idYes) then
2546 begin
2547 RecentFiles.Delete(n);
2548 RefreshRecentMenu();
2549 end;
2550 end;
2552 procedure TMainForm.aEditorOptionsExecute(Sender: TObject);
2553 begin
2554 OptionsForm.ShowModal();
2555 end;
2557 procedure LoadStdFont(cfgres, texture: string; var FontID: DWORD);
2558 var
2559 cwdt, chgt: Byte;
2560 spc: ShortInt;
2561 ID: DWORD;
2562 wad: TWADEditor_1;
2563 cfgdata: Pointer;
2564 cfglen: Integer;
2565 config: TConfig;
2566 begin
2567 cfgdata := nil;
2568 cfglen := 0;
2569 ID := 0;
2571 wad := TWADEditor_1.Create;
2572 if wad.ReadFile(EditorDir+'data/Game.wad') then
2573 wad.GetResource('FONTS', cfgres, cfgdata, cfglen);
2574 wad.Free();
2576 if cfglen <> 0 then
2577 begin
2578 if not g_CreateTextureWAD('FONT_STD', EditorDir+'data/Game.wad:FONTS\'+texture) then
2579 e_WriteLog('ERROR ERROR ERROR', MSG_WARNING);
2581 config := TConfig.CreateMem(cfgdata, cfglen);
2582 cwdt := Min(Max(config.ReadInt('FontMap', 'CharWidth', 0), 0), 255);
2583 chgt := Min(Max(config.ReadInt('FontMap', 'CharHeight', 0), 0), 255);
2584 spc := Min(Max(config.ReadInt('FontMap', 'Kerning', 0), -128), 127);
2586 if g_GetTexture('FONT_STD', ID) then
2587 e_TextureFontBuild(ID, FontID, cwdt, chgt, spc-2);
2589 config.Free();
2590 end
2591 else
2592 e_WriteLog('Could not load FONT_STD', MSG_WARNING);
2594 if cfglen <> 0 then FreeMem(cfgdata);
2595 end;
2597 procedure TMainForm.FormCreate(Sender: TObject);
2598 var
2599 config: TConfig;
2600 i: Integer;
2601 s: String;
2602 begin
2603 Randomize();
2605 EditorDir := ExtractFilePath(Application.ExeName);
2607 e_InitLog(EditorDir+'Editor.log', WM_NEWFILE);
2609 slInvalidTextures := TStringList.Create;
2611 ShowLayer(LAYER_BACK, True);
2612 ShowLayer(LAYER_WALLS, True);
2613 ShowLayer(LAYER_FOREGROUND, True);
2614 ShowLayer(LAYER_STEPS, True);
2615 ShowLayer(LAYER_WATER, True);
2616 ShowLayer(LAYER_ITEMS, True);
2617 ShowLayer(LAYER_MONSTERS, True);
2618 ShowLayer(LAYER_AREAS, True);
2619 ShowLayer(LAYER_TRIGGERS, True);
2621 ClearMap();
2623 FormCaption := MainForm.Caption;
2624 OpenedMap := '';
2625 OpenedWAD := '';
2627 config := TConfig.CreateFile(EditorDir+'Editor.cfg');
2629 if config.ReadInt('Editor', 'XPos', -1) = -1 then
2630 Position := poDesktopCenter
2631 else begin
2632 Left := config.ReadInt('Editor', 'XPos', Left);
2633 Top := config.ReadInt('Editor', 'YPos', Top);
2634 Width := config.ReadInt('Editor', 'Width', Width);
2635 Height := config.ReadInt('Editor', 'Height', Height);
2636 end;
2637 if config.ReadBool('Editor', 'Maximize', False) then
2638 WindowState := wsMaximized;
2639 ShowMap := config.ReadBool('Editor', 'Minimap', False);
2640 PanelProps.Width := config.ReadInt('Editor', 'PanelProps', PanelProps.ClientWidth);
2641 Splitter1.Left := PanelProps.Left;
2642 PanelObjs.Height := config.ReadInt('Editor', 'PanelObjs', PanelObjs.ClientHeight);
2643 Splitter2.Top := PanelObjs.Top;
2644 StatusBar.Top := PanelObjs.BoundsRect.Bottom;
2645 DotEnable := config.ReadBool('Editor', 'DotEnable', True);
2646 DotColor := config.ReadInt('Editor', 'DotColor', $FFFFFF);
2647 DotStepOne := config.ReadInt('Editor', 'DotStepOne', 16);
2648 DotStepTwo := config.ReadInt('Editor', 'DotStepTwo', 8);
2649 DotStep := config.ReadInt('Editor', 'DotStep', DotStepOne);
2650 DrawTexturePanel := config.ReadBool('Editor', 'DrawTexturePanel', True);
2651 DrawPanelSize := config.ReadBool('Editor', 'DrawPanelSize', True);
2652 BackColor := config.ReadInt('Editor', 'BackColor', $7F6040);
2653 PreviewColor := config.ReadInt('Editor', 'PreviewColor', $00FF00);
2654 gColorEdge := config.ReadInt('Editor', 'EdgeColor', COLOR_EDGE);
2655 gAlphaEdge := config.ReadInt('Editor', 'EdgeAlpha', ALPHA_EDGE);
2656 if gAlphaEdge = 255 then
2657 gAlphaEdge := ALPHA_EDGE;
2658 drEdge[0] := GetRValue(gColorEdge);
2659 drEdge[1] := GetGValue(gColorEdge);
2660 drEdge[2] := GetBValue(gColorEdge);
2661 if not config.ReadBool('Editor', 'EdgeShow', True) then
2662 drEdge[3] := 255
2663 else
2664 drEdge[3] := gAlphaEdge;
2665 gAlphaTriggerLine := config.ReadInt('Editor', 'LineAlpha', ALPHA_LINE);
2666 if gAlphaTriggerLine = 255 then
2667 gAlphaTriggerLine := ALPHA_LINE;
2668 gAlphaTriggerArea := config.ReadInt('Editor', 'TriggerAlpha', ALPHA_AREA);
2669 if gAlphaTriggerArea = 255 then
2670 gAlphaTriggerArea := ALPHA_AREA;
2671 if config.ReadInt('Editor', 'Scale', 0) = 1 then
2672 Scale := 2
2673 else
2674 Scale := 1;
2675 if config.ReadInt('Editor', 'DotSize', 0) = 1 then
2676 DotSize := 2
2677 else
2678 DotSize := 1;
2679 OpenDialog.InitialDir := config.ReadStr('Editor', 'LastOpenDir', EditorDir);
2680 SaveDialog.InitialDir := config.ReadStr('Editor', 'LastSaveDir', EditorDir);
2682 s := config.ReadStr('Editor', 'Language', '');
2683 gLanguage := s;
2685 RecentCount := config.ReadInt('Editor', 'RecentCount', 5);
2686 if RecentCount > 10 then
2687 RecentCount := 10;
2688 if RecentCount < 2 then
2689 RecentCount := 2;
2691 RecentFiles := TStringList.Create();
2692 for i := 0 to RecentCount-1 do
2693 begin
2694 s := config.ReadStr('RecentFiles', IntToStr(i+1), '');
2695 if s <> '' then
2696 RecentFiles.Add(s);
2697 end;
2698 RefreshRecentMenu();
2700 config.Free();
2702 tbShowMap.Down := ShowMap;
2703 tbGridOn.Down := DotEnable;
2704 pcObjects.ActivePageIndex := 0;
2705 Application.Title := _lc[I_EDITOR_TITLE];
2707 Application.OnIdle := OnIdle;
2708 end;
2710 procedure PrintBlack(X, Y: Integer; Text: string; FontID: DWORD);
2711 begin
2712 // NOTE: all the font printing routines assume CP1251
2713 e_TextureFontPrintEx(X, Y, Text, FontID, 0, 0, 0, 1.0);
2714 end;
2716 procedure TMainForm.Draw();
2717 var
2718 x, y: Integer;
2719 a, b: Integer;
2720 ID, PID: DWORD;
2721 Width, Height: Word;
2722 Rect: TRectWH;
2723 ObjCount: Word;
2724 aX, aY, aX2, aY2, XX, ScaleSz: Integer;
2725 begin
2726 ID := 0;
2727 PID := 0;
2728 Width := 0;
2729 Height := 0;
2731 e_BeginRender();
2733 e_Clear(GL_COLOR_BUFFER_BIT,
2734 GetRValue(BackColor)/255,
2735 GetGValue(BackColor)/255,
2736 GetBValue(BackColor)/255);
2738 DrawMap();
2740 ObjCount := SelectedObjectCount();
2742 // Обводим выделенные объекты красной рамкой:
2743 if ObjCount > 0 then
2744 begin
2745 for a := 0 to High(SelectedObjects) do
2746 if SelectedObjects[a].Live then
2747 begin
2748 Rect := ObjectGetRect(SelectedObjects[a].ObjectType, SelectedObjects[a].ID);
2750 with Rect do
2751 begin
2752 e_DrawQuad(X+MapOffset.X, Y+MapOffset.Y,
2753 X+MapOffset.X+Width-1, Y+MapOffset.Y+Height-1,
2754 255, 0, 0);
2756 // Рисуем точки изменения размеров:
2757 if (ObjCount = 1) and
2758 (SelectedObjects[GetFirstSelected].ObjectType in [OBJECT_PANEL, OBJECT_TRIGGER]) then
2759 begin
2760 e_DrawPoint(5, X+MapOffset.X, Y+MapOffset.Y+(Height div 2), 255, 255, 255);
2761 e_DrawPoint(5, X+MapOffset.X+Width-1, Y+MapOffset.Y+(Height div 2), 255, 255, 255);
2762 e_DrawPoint(5, X+MapOffset.X+(Width div 2), Y+MapOffset.Y, 255, 255, 255);
2763 e_DrawPoint(5, X+MapOffset.X+(Width div 2), Y+MapOffset.Y+Height-1, 255, 255, 255);
2765 e_DrawPoint(3, X+MapOffset.X, Y+MapOffset.Y+(Height div 2), 255, 0, 0);
2766 e_DrawPoint(3, X+MapOffset.X+Width-1, Y+MapOffset.Y+(Height div 2), 255, 0, 0);
2767 e_DrawPoint(3, X+MapOffset.X+(Width div 2), Y+MapOffset.Y, 255, 0, 0);
2768 e_DrawPoint(3, X+MapOffset.X+(Width div 2), Y+MapOffset.Y+Height-1, 255, 0, 0);
2769 end;
2770 end;
2771 end;
2772 end;
2774 // Рисуем сетку:
2775 if DotEnable and (not PreviewMode) then
2776 begin
2777 if DotSize = 2 then
2778 a := -1
2779 else
2780 a := 0;
2782 for x := 0 to (RenderPanel.Width div DotStep) do
2783 for y := 0 to (RenderPanel.Height div DotStep) do
2784 e_DrawPoint(DotSize, x*DotStep + a, y*DotStep + a,
2785 GetRValue(DotColor),
2786 GetGValue(DotColor),
2787 GetBValue(DotColor));
2788 end;
2790 // Превью текстуры:
2791 if (lbTextureList.ItemIndex <> -1) and (cbPreview.Checked) and
2792 (not IsSpecialTextureSel()) and (not PreviewMode) then
2793 begin
2794 if not g_GetTexture(SelectedTexture(), ID) then
2795 g_GetTexture('NOTEXTURE', ID);
2796 g_GetTextureSizeByID(ID, Width, Height);
2797 if g_GetTexture('PREVIEW', PID) then
2798 e_DrawFill(PID, RenderPanel.Width-Width, RenderPanel.Height-Height, Width div 16 + 1, Height div 16 + 1, 0, True, False);
2799 e_Draw(ID, RenderPanel.Width-Width, RenderPanel.Height-Height, 0, True, False);
2800 end;
2802 // Подсказка при выборе точки Телепорта:
2803 if SelectFlag = SELECTFLAG_TELEPORT then
2804 begin
2805 with gTriggers[SelectedObjects[GetFirstSelected()].ID] do
2806 if Data.d2d_teleport then
2807 e_DrawLine(2, MousePos.X-16, MousePos.Y-1,
2808 MousePos.X+16, MousePos.Y-1,
2809 0, 0, 255)
2810 else
2811 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+AreaSize[AREA_DMPOINT].Width-1,
2812 MousePos.Y+AreaSize[AREA_DMPOINT].Height-1, 255, 255, 255);
2814 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 192, 192, 192, 127);
2815 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 255, 255, 255);
2816 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_TELEPORT], gEditorFont);
2817 end;
2819 // Подсказка при выборе точки появления:
2820 if SelectFlag = SELECTFLAG_SPAWNPOINT then
2821 begin
2822 e_DrawLine(2, MousePos.X-16, MousePos.Y-1,
2823 MousePos.X+16, MousePos.Y-1,
2824 0, 0, 255);
2825 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 192, 192, 192, 127);
2826 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 255, 255, 255);
2827 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_SPAWN], gEditorFont);
2828 end;
2830 // Подсказка при выборе панели двери:
2831 if SelectFlag = SELECTFLAG_DOOR then
2832 begin
2833 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 192, 192, 192, 127);
2834 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 255, 255, 255);
2835 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_PANEL_DOOR], gEditorFont);
2836 end;
2838 // Подсказка при выборе панели с текстурой:
2839 if SelectFlag = SELECTFLAG_TEXTURE then
2840 begin
2841 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+196, MousePos.Y+18, 192, 192, 192, 127);
2842 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+196, MousePos.Y+18, 255, 255, 255);
2843 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_PANEL_TEXTURE], gEditorFont);
2844 end;
2846 // Подсказка при выборе панели индикации выстрела:
2847 if SelectFlag = SELECTFLAG_SHOTPANEL then
2848 begin
2849 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+316, MousePos.Y+18, 192, 192, 192, 127);
2850 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+316, MousePos.Y+18, 255, 255, 255);
2851 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_PANEL_SHOT], gEditorFont);
2852 end;
2854 // Подсказка при выборе панели лифта:
2855 if SelectFlag = SELECTFLAG_LIFT then
2856 begin
2857 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 192, 192, 192, 127);
2858 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 255, 255, 255);
2859 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_PANEL_LIFT], gEditorFont);
2860 end;
2862 // Подсказка при выборе монстра:
2863 if SelectFlag = SELECTFLAG_MONSTER then
2864 begin
2865 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+120, MousePos.Y+18, 192, 192, 192, 127);
2866 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+120, MousePos.Y+18, 255, 255, 255);
2867 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_MONSTER], gEditorFont);
2868 end;
2870 // Подсказка при выборе области воздействия:
2871 if DrawPressRect then
2872 begin
2873 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+204, MousePos.Y+18, 192, 192, 192, 127);
2874 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+204, MousePos.Y+18, 255, 255, 255);
2875 PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_EXT_AREA], gEditorFont);
2876 end;
2878 // Рисуем текстуры, если чертим панель:
2879 if (MouseAction = MOUSEACTION_DRAWPANEL) and (DrawTexturePanel) and
2880 (lbTextureList.ItemIndex <> -1) and (DrawRect <> nil) and
2881 (lbPanelType.ItemIndex in [0..8]) and not IsSpecialTextureSel() then
2882 begin
2883 if not g_GetTexture(SelectedTexture(), ID) then
2884 g_GetTexture('NOTEXTURE', ID);
2885 g_GetTextureSizeByID(ID, Width, Height);
2886 with DrawRect^ do
2887 e_DrawFill(ID, Min(Left, Right), Min(Top, Bottom), Abs(Right-Left) div Width,
2888 Abs(Bottom-Top) div Height, 0, True, False);
2889 end;
2891 // Прямоугольник выделения:
2892 if DrawRect <> nil then
2893 with DrawRect^ do
2894 e_DrawQuad(Left, Top, Right-1, Bottom-1, 255, 255, 255);
2896 // Чертим мышью панель/триггер или меняем мышью их размер:
2897 if (MouseAction in [MOUSEACTION_DRAWPANEL, MOUSEACTION_DRAWTRIGGER, MOUSEACTION_RESIZE]) and
2898 (DrawPanelSize) then
2899 begin
2900 e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+88, MousePos.Y+33, 192, 192, 192, 127);
2901 e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+88, MousePos.Y+33, 255, 255, 255);
2903 if MouseAction in [MOUSEACTION_DRAWPANEL, MOUSEACTION_DRAWTRIGGER] then
2904 begin // Чертим новый
2905 PrintBlack(MousePos.X+2, MousePos.Y+2, Format(_glc[I_HINT_WIDTH],
2906 [Abs(MousePos.X-MouseLDownPos.X)]), gEditorFont);
2907 PrintBlack(MousePos.X+2, MousePos.Y+14, Format(_glc[I_HINT_HEIGHT],
2908 [Abs(MousePos.Y-MouseLDownPos.Y)]), gEditorFont);
2909 end
2910 else // Растягиваем существующий
2911 if SelectedObjects[GetFirstSelected].ObjectType in [OBJECT_PANEL, OBJECT_TRIGGER] then
2912 begin
2913 if SelectedObjects[GetFirstSelected].ObjectType = OBJECT_PANEL then
2914 begin
2915 Width := gPanels[SelectedObjects[GetFirstSelected].ID].Width;
2916 Height := gPanels[SelectedObjects[GetFirstSelected].ID].Height;
2917 end
2918 else
2919 begin
2920 Width := gTriggers[SelectedObjects[GetFirstSelected].ID].Width;
2921 Height := gTriggers[SelectedObjects[GetFirstSelected].ID].Height;
2922 end;
2924 PrintBlack(MousePos.X+2, MousePos.Y+2, Format(_glc[I_HINT_WIDTH], [Width]),
2925 gEditorFont);
2926 PrintBlack(MousePos.X+2, MousePos.Y+14, Format(_glc[I_HINT_HEIGHT], [Height]),
2927 gEditorFont);
2928 end;
2929 end;
2931 // Ближайшая к курсору мыши точка на сетке:
2932 e_DrawPoint(3, MousePos.X, MousePos.Y, 0, 0, 255);
2934 // Мини-карта:
2935 if ShowMap then
2936 begin
2937 // Сколько пикселов карты в 1 пикселе мини-карты:
2938 ScaleSz := 16 div Scale;
2939 // Размеры мини-карты:
2940 aX := max(gMapInfo.Width div ScaleSz, 1);
2941 aY := max(gMapInfo.Height div ScaleSz, 1);
2942 // X-координата на RenderPanel нулевой x-координаты карты:
2943 XX := RenderPanel.Width - aX - 1;
2944 // Рамка карты:
2945 e_DrawFillQuad(XX-1, 0, RenderPanel.Width-1, aY+1, 0, 0, 0, 0);
2946 e_DrawQuad(XX-1, 0, RenderPanel.Width-1, aY+1, 197, 197, 197);
2948 if gPanels <> nil then
2949 begin
2950 // Рисуем панели:
2951 for a := 0 to High(gPanels) do
2952 with gPanels[a] do
2953 if PanelType <> 0 then
2954 begin
2955 // Левый верхний угол:
2956 aX := XX + (X div ScaleSz);
2957 aY := 1 + (Y div ScaleSz);
2958 // Размеры:
2959 aX2 := max(Width div ScaleSz, 1);
2960 aY2 := max(Height div ScaleSz, 1);
2961 // Правый нижний угол:
2962 aX2 := aX + aX2 - 1;
2963 aY2 := aY + aY2 - 1;
2965 case PanelType of
2966 PANEL_WALL: e_DrawFillQuad(aX, aY, aX2, aY2, 208, 208, 208, 0);
2967 PANEL_WATER: e_DrawFillQuad(aX, aY, aX2, aY2, 0, 0, 192, 0);
2968 PANEL_ACID1: e_DrawFillQuad(aX, aY, aX2, aY2, 0, 176, 0, 0);
2969 PANEL_ACID2: e_DrawFillQuad(aX, aY, aX2, aY2, 176, 0, 0, 0);
2970 PANEL_STEP: e_DrawFillQuad(aX, aY, aX2, aY2, 128, 128, 128, 0);
2971 PANEL_LIFTUP: e_DrawFillQuad(aX, aY, aX2, aY2, 116, 72, 36, 0);
2972 PANEL_LIFTDOWN: e_DrawFillQuad(aX, aY, aX2, aY2, 116, 124, 96, 0);
2973 PANEL_LIFTLEFT: e_DrawFillQuad(aX, aY, aX2, aY2, 200, 80, 4, 0);
2974 PANEL_LIFTRIGHT: e_DrawFillQuad(aX, aY, aX2, aY2, 252, 140, 56, 0);
2975 PANEL_OPENDOOR: e_DrawFillQuad(aX, aY, aX2, aY2, 100, 220, 92, 0);
2976 PANEL_CLOSEDOOR: e_DrawFillQuad(aX, aY, aX2, aY2, 212, 184, 64, 0);
2977 PANEL_BLOCKMON: e_DrawFillQuad(aX, aY, aX2, aY2, 192, 0, 192, 0);
2978 end;
2979 end;
2981 // Рисуем красным выделенные панели:
2982 if SelectedObjects <> nil then
2983 for b := 0 to High(SelectedObjects) do
2984 with SelectedObjects[b] do
2985 if Live and (ObjectType = OBJECT_PANEL) then
2986 with gPanels[SelectedObjects[b].ID] do
2987 if PanelType and not(PANEL_BACK or PANEL_FORE) <> 0 then
2988 begin
2989 // Левый верхний угол:
2990 aX := XX + (X div ScaleSz);
2991 aY := 1 + (Y div ScaleSz);
2992 // Размеры:
2993 aX2 := max(Width div ScaleSz, 1);
2994 aY2 := max(Height div ScaleSz, 1);
2995 // Правый нижний угол:
2996 aX2 := aX + aX2 - 1;
2997 aY2 := aY + aY2 - 1;
2999 e_DrawFillQuad(aX, aY, aX2, aY2, 255, 0, 0, 0)
3000 end;
3001 end;
3003 if (gMapInfo.Width > RenderPanel.Width) or
3004 (gMapInfo.Height > RenderPanel.Height) then
3005 begin
3006 // Окно, показывающее текущее положение экрана на карте:
3007 // Размеры окна:
3008 x := max(min(RenderPanel.Width, gMapInfo.Width) div ScaleSz, 1);
3009 y := max(min(RenderPanel.Height, gMapInfo.Height) div ScaleSz, 1);
3010 // Левый верхний угол:
3011 aX := XX + ((-MapOffset.X) div ScaleSz);
3012 aY := 1 + ((-MapOffset.Y) div ScaleSz);
3013 // Правый нижний угол:
3014 aX2 := aX + x - 1;
3015 aY2 := aY + y - 1;
3017 e_DrawFillQuad(aX, aY, aX2, aY2, 127, 192, 127, 127, B_BLEND);
3018 e_DrawQuad(aX, aY, aX2, aY2, 255, 0, 0);
3019 end;
3020 end; // Мини-карта
3022 e_EndRender();
3023 RenderPanel.SwapBuffers();
3024 end;
3026 procedure TMainForm.FormResize(Sender: TObject);
3027 begin
3028 e_SetViewPort(0, 0, RenderPanel.Width, RenderPanel.Height);
3030 if gMapInfo.Width >= RenderPanel.Width then
3031 sbHorizontal.Max := Normalize16(gMapInfo.Width-RenderPanel.Width+16)
3032 else
3033 sbHorizontal.Max := 0;
3035 if gMapInfo.Height >= RenderPanel.Height then
3036 sbVertical.Max := Normalize16(gMapInfo.Height-RenderPanel.Height+16)
3037 else
3038 sbVertical.Max := 0;
3040 MapOffset.X := -Normalize16(sbHorizontal.Position);
3041 MapOffset.Y := -Normalize16(sbVertical.Position);
3042 end;
3044 procedure SelectNextObject(X, Y: Integer; ObjectType: Byte; ID: DWORD);
3045 var
3046 j, j_max: Integer;
3047 res: Boolean;
3048 begin
3049 j_max := 0; // shut up compiler
3050 case ObjectType of
3051 OBJECT_PANEL:
3052 begin
3053 res := (gPanels <> nil) and
3054 PanelInShownLayer(gPanels[ID].PanelType) and
3055 g_CollidePoint(X, Y, gPanels[ID].X, gPanels[ID].Y,
3056 gPanels[ID].Width,
3057 gPanels[ID].Height);
3058 j_max := Length(gPanels) - 1;
3059 end;
3061 OBJECT_ITEM:
3062 begin
3063 res := (gItems <> nil) and
3064 LayerEnabled[LAYER_ITEMS] and
3065 g_CollidePoint(X, Y, gItems[ID].X, gItems[ID].Y,
3066 ItemSize[gItems[ID].ItemType][0],
3067 ItemSize[gItems[ID].ItemType][1]);
3068 j_max := Length(gItems) - 1;
3069 end;
3071 OBJECT_MONSTER:
3072 begin
3073 res := (gMonsters <> nil) and
3074 LayerEnabled[LAYER_MONSTERS] and
3075 g_CollidePoint(X, Y, gMonsters[ID].X, gMonsters[ID].Y,
3076 MonsterSize[gMonsters[ID].MonsterType].Width,
3077 MonsterSize[gMonsters[ID].MonsterType].Height);
3078 j_max := Length(gMonsters) - 1;
3079 end;
3081 OBJECT_AREA:
3082 begin
3083 res := (gAreas <> nil) and
3084 LayerEnabled[LAYER_AREAS] and
3085 g_CollidePoint(X, Y, gAreas[ID].X, gAreas[ID].Y,
3086 AreaSize[gAreas[ID].AreaType].Width,
3087 AreaSize[gAreas[ID].AreaType].Height);
3088 j_max := Length(gAreas) - 1;
3089 end;
3091 OBJECT_TRIGGER:
3092 begin
3093 res := (gTriggers <> nil) and
3094 LayerEnabled[LAYER_TRIGGERS] and
3095 g_CollidePoint(X, Y, gTriggers[ID].X, gTriggers[ID].Y,
3096 gTriggers[ID].Width,
3097 gTriggers[ID].Height);
3098 j_max := Length(gTriggers) - 1;
3099 end;
3101 else
3102 res := False;
3103 end;
3105 if not res then
3106 Exit;
3108 // Перебор ID: от ID-1 до 0; потом от High до ID+1:
3109 j := ID;
3111 while True do
3112 begin
3113 Dec(j);
3115 if j < 0 then
3116 j := j_max;
3117 if j = Integer(ID) then
3118 Break;
3120 case ObjectType of
3121 OBJECT_PANEL:
3122 res := PanelInShownLayer(gPanels[j].PanelType) and
3123 g_CollidePoint(X, Y, gPanels[j].X, gPanels[j].Y,
3124 gPanels[j].Width,
3125 gPanels[j].Height);
3126 OBJECT_ITEM:
3127 res := (gItems[j].ItemType <> ITEM_NONE) and
3128 g_CollidePoint(X, Y, gItems[j].X, gItems[j].Y,
3129 ItemSize[gItems[j].ItemType][0],
3130 ItemSize[gItems[j].ItemType][1]);
3131 OBJECT_MONSTER:
3132 res := (gMonsters[j].MonsterType <> MONSTER_NONE) and
3133 g_CollidePoint(X, Y, gMonsters[j].X, gMonsters[j].Y,
3134 MonsterSize[gMonsters[j].MonsterType].Width,
3135 MonsterSize[gMonsters[j].MonsterType].Height);
3136 OBJECT_AREA:
3137 res := (gAreas[j].AreaType <> AREA_NONE) and
3138 g_CollidePoint(X, Y, gAreas[j].X, gAreas[j].Y,
3139 AreaSize[gAreas[j].AreaType].Width,
3140 AreaSize[gAreas[j].AreaType].Height);
3141 OBJECT_TRIGGER:
3142 res := (gTriggers[j].TriggerType <> TRIGGER_NONE) and
3143 g_CollidePoint(X, Y, gTriggers[j].X, gTriggers[j].Y,
3144 gTriggers[j].Width,
3145 gTriggers[j].Height);
3146 else
3147 res := False;
3148 end;
3150 if res then
3151 begin
3152 SetLength(SelectedObjects, 1);
3154 SelectedObjects[0].ObjectType := ObjectType;
3155 SelectedObjects[0].ID := j;
3156 SelectedObjects[0].Live := True;
3158 FillProperty();
3159 Break;
3160 end;
3161 end;
3162 end;
3164 procedure TMainForm.RenderPanelMouseDown(Sender: TObject;
3165 Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
3166 var
3167 i: Integer;
3168 Rect: TRectWH;
3169 c1, c2, c3, c4: Boolean;
3170 item: TItem;
3171 area: TArea;
3172 monster: TMonster;
3173 IDArray: DWArray;
3174 begin
3175 MainForm.ActiveControl := RenderPanel;
3176 RenderPanel.SetFocus();
3178 RenderPanelMouseMove(RenderPanel, Shift, X, Y);
3180 if Button = mbLeft then // Left Mouse Button
3181 begin
3182 // Двигаем карту с помощью мыши и мини-карты:
3183 if ShowMap and
3184 g_CollidePoint(X, Y,
3185 RenderPanel.Width-max(gMapInfo.Width div (16 div Scale), 1)-1,
3186 1,
3187 max(gMapInfo.Width div (16 div Scale), 1),
3188 max(gMapInfo.Height div (16 div Scale), 1) ) then
3189 begin
3190 MoveMap(X, Y);
3191 MouseAction := MOUSEACTION_MOVEMAP;
3192 end
3193 else // Ставим предмет/монстра/область:
3194 if (pcObjects.ActivePageIndex in [1, 2, 3]) and
3195 (not (ssShift in Shift)) then
3196 begin
3197 case pcObjects.ActivePageIndex of
3198 1:
3199 if lbItemList.ItemIndex = -1 then
3200 ErrorMessageBox(_lc[I_MSG_CHOOSE_ITEM])
3201 else
3202 begin
3203 item.ItemType := lbItemList.ItemIndex + ITEM_MEDKIT_SMALL;
3204 if item.ItemType >= ITEM_WEAPON_KASTET then
3205 item.ItemType := item.ItemType + 2;
3206 item.X := MousePos.X-MapOffset.X;
3207 item.Y := MousePos.Y-MapOffset.Y;
3209 if not (ssCtrl in Shift) then
3210 begin
3211 item.X := item.X - (ItemSize[item.ItemType][0] div 2);
3212 item.Y := item.Y - ItemSize[item.ItemType][1];
3213 end;
3215 item.OnlyDM := cbOnlyDM.Checked;
3216 item.Fall := cbFall.Checked;
3217 Undo_Add(OBJECT_ITEM, AddItem(item));
3218 end;
3219 2:
3220 if lbMonsterList.ItemIndex = -1 then
3221 ErrorMessageBox(_lc[I_MSG_CHOOSE_MONSTER])
3222 else
3223 begin
3224 monster.MonsterType := lbMonsterList.ItemIndex + MONSTER_DEMON;
3225 monster.X := MousePos.X-MapOffset.X;
3226 monster.Y := MousePos.Y-MapOffset.Y;
3228 if not (ssCtrl in Shift) then
3229 begin
3230 monster.X := monster.X - (MonsterSize[monster.MonsterType].Width div 2);
3231 monster.Y := monster.Y - MonsterSize[monster.MonsterType].Height;
3232 end;
3234 if rbMonsterLeft.Checked then
3235 monster.Direction := D_LEFT
3236 else
3237 monster.Direction := D_RIGHT;
3238 Undo_Add(OBJECT_MONSTER, AddMonster(monster));
3239 end;
3240 3:
3241 if lbAreasList.ItemIndex = -1 then
3242 ErrorMessageBox(_lc[I_MSG_CHOOSE_AREA])
3243 else
3244 if (lbAreasList.ItemIndex + 1) <> AREA_DOMFLAG then
3245 begin
3246 area.AreaType := lbAreasList.ItemIndex + AREA_PLAYERPOINT1;
3247 area.X := MousePos.X-MapOffset.X;
3248 area.Y := MousePos.Y-MapOffset.Y;
3250 if not (ssCtrl in Shift) then
3251 begin
3252 area.X := area.X - (AreaSize[area.AreaType].Width div 2);
3253 area.Y := area.Y - AreaSize[area.AreaType].Height;
3254 end;
3256 if rbAreaLeft.Checked then
3257 area.Direction := D_LEFT
3258 else
3259 area.Direction := D_RIGHT;
3260 Undo_Add(OBJECT_AREA, AddArea(area));
3261 end;
3262 end;
3263 end
3264 else
3265 begin
3266 i := GetFirstSelected();
3268 // Выбираем объект под текущим:
3269 if (SelectedObjects <> nil) and
3270 (ssShift in Shift) and (i >= 0) and
3271 (SelectedObjects[i].Live) then
3272 begin
3273 if SelectedObjectCount() = 1 then
3274 SelectNextObject(X-MapOffset.X, Y-MapOffset.Y,
3275 SelectedObjects[i].ObjectType,
3276 SelectedObjects[i].ID);
3277 end
3278 else
3279 begin
3280 // Рисуем область триггера "Расширитель":
3281 if DrawPressRect and (i >= 0) and
3282 (SelectedObjects[i].ObjectType = OBJECT_TRIGGER) and
3283 (gTriggers[SelectedObjects[i].ID].TriggerType in
3284 [TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF]) then
3285 MouseAction := MOUSEACTION_DRAWPRESS
3286 else // Рисуем панель:
3287 if pcObjects.ActivePageIndex = 0 then
3288 begin
3289 if (lbPanelType.ItemIndex >= 0) then
3290 MouseAction := MOUSEACTION_DRAWPANEL
3291 end
3292 else // Рисуем триггер:
3293 if (lbTriggersList.ItemIndex >= 0) then
3294 begin
3295 MouseAction := MOUSEACTION_DRAWTRIGGER;
3296 end;
3297 end;
3298 end;
3299 end; // if Button = mbLeft
3301 if Button = mbRight then // Right Mouse Button
3302 begin
3303 // Клик по мини-карте:
3304 if ShowMap and
3305 g_CollidePoint(X, Y,
3306 RenderPanel.Width-max(gMapInfo.Width div (16 div Scale), 1)-1,
3307 1,
3308 max(gMapInfo.Width div (16 div Scale), 1),
3309 max(gMapInfo.Height div (16 div Scale), 1) ) then
3310 begin
3311 MouseAction := MOUSEACTION_NOACTION;
3312 end
3313 else // Нужно что-то выбрать мышью:
3314 if SelectFlag <> SELECTFLAG_NONE then
3315 begin
3316 case SelectFlag of
3317 SELECTFLAG_TELEPORT:
3318 // Точку назначения телепортации:
3319 with gTriggers[SelectedObjects[
3320 GetFirstSelected() ].ID].Data.TargetPoint do
3321 begin
3322 X := MousePos.X-MapOffset.X;
3323 Y := MousePos.Y-MapOffset.Y;
3324 end;
3326 SELECTFLAG_SPAWNPOINT:
3327 // Точку создания монстра:
3328 with gTriggers[SelectedObjects[GetFirstSelected()].ID] do
3329 if TriggerType = TRIGGER_SPAWNMONSTER then
3330 begin
3331 Data.MonPos.X := MousePos.X-MapOffset.X;
3332 Data.MonPos.Y := MousePos.Y-MapOffset.Y;
3333 end
3334 else if TriggerType = TRIGGER_SPAWNITEM then
3335 begin // Точка создания предмета:
3336 Data.ItemPos.X := MousePos.X-MapOffset.X;
3337 Data.ItemPos.Y := MousePos.Y-MapOffset.Y;
3338 end
3339 else if TriggerType = TRIGGER_SHOT then
3340 begin // Точка создания выстрела:
3341 Data.ShotPos.X := MousePos.X-MapOffset.X;
3342 Data.ShotPos.Y := MousePos.Y-MapOffset.Y;
3343 end;
3345 SELECTFLAG_DOOR:
3346 // Дверь:
3347 begin
3348 IDArray := ObjectInRect(X-MapOffset.X,
3349 Y-MapOffset.Y,
3350 2, 2, OBJECT_PANEL, True);
3351 if IDArray <> nil then
3352 begin
3353 for i := 0 to High(IDArray) do
3354 if (gPanels[IDArray[i]].PanelType = PANEL_OPENDOOR) or
3355 (gPanels[IDArray[i]].PanelType = PANEL_CLOSEDOOR) then
3356 begin
3357 gTriggers[SelectedObjects[
3358 GetFirstSelected() ].ID].Data.PanelID := IDArray[i];
3359 Break;
3360 end;
3361 end
3362 else
3363 gTriggers[SelectedObjects[
3364 GetFirstSelected() ].ID].Data.PanelID := -1;
3365 end;
3367 SELECTFLAG_TEXTURE:
3368 // Панель с текстурой:
3369 begin
3370 IDArray := ObjectInRect(X-MapOffset.X,
3371 Y-MapOffset.Y,
3372 2, 2, OBJECT_PANEL, True);
3373 if IDArray <> nil then
3374 begin
3375 for i := 0 to High(IDArray) do
3376 if ((gPanels[IDArray[i]].PanelType in
3377 [PANEL_WALL, PANEL_BACK, PANEL_FORE,
3378 PANEL_WATER, PANEL_ACID1, PANEL_ACID2,
3379 PANEL_STEP]) or
3380 (gPanels[IDArray[i]].PanelType = PANEL_OPENDOOR) or
3381 (gPanels[IDArray[i]].PanelType = PANEL_CLOSEDOOR)) and
3382 (gPanels[IDArray[i]].TextureName <> '') then
3383 begin
3384 gTriggers[SelectedObjects[
3385 GetFirstSelected() ].ID].TexturePanel := IDArray[i];
3386 Break;
3387 end;
3388 end
3389 else
3390 gTriggers[SelectedObjects[
3391 GetFirstSelected() ].ID].TexturePanel := -1;
3392 end;
3394 SELECTFLAG_LIFT:
3395 // Лифт:
3396 begin
3397 IDArray := ObjectInRect(X-MapOffset.X,
3398 Y-MapOffset.Y,
3399 2, 2, OBJECT_PANEL, True);
3400 if IDArray <> nil then
3401 begin
3402 for i := 0 to High(IDArray) do
3403 if (gPanels[IDArray[i]].PanelType = PANEL_LIFTUP) or
3404 (gPanels[IDArray[i]].PanelType = PANEL_LIFTDOWN) or
3405 (gPanels[IDArray[i]].PanelType = PANEL_LIFTLEFT) or
3406 (gPanels[IDArray[i]].PanelType = PANEL_LIFTRIGHT) then
3407 begin
3408 gTriggers[SelectedObjects[
3409 GetFirstSelected() ].ID].Data.PanelID := IDArray[i];
3410 Break;
3411 end;
3412 end
3413 else
3414 gTriggers[SelectedObjects[
3415 GetFirstSelected() ].ID].Data.PanelID := -1;
3416 end;
3418 SELECTFLAG_MONSTER:
3419 // Монстра:
3420 begin
3421 IDArray := ObjectInRect(X-MapOffset.X,
3422 Y-MapOffset.Y,
3423 2, 2, OBJECT_MONSTER, False);
3424 if IDArray <> nil then
3425 gTriggers[SelectedObjects[
3426 GetFirstSelected() ].ID].Data.MonsterID := IDArray[0]+1
3427 else
3428 gTriggers[SelectedObjects[
3429 GetFirstSelected() ].ID].Data.MonsterID := 0;
3430 end;
3432 SELECTFLAG_SHOTPANEL:
3433 // Панель индикации выстрела:
3434 begin
3435 if gTriggers[SelectedObjects[
3436 GetFirstSelected() ].ID].TriggerType = TRIGGER_SHOT then
3437 begin
3438 IDArray := ObjectInRect(X-MapOffset.X,
3439 Y-MapOffset.Y,
3440 2, 2, OBJECT_PANEL, True);
3441 if IDArray <> nil then
3442 begin
3443 for i := 0 to High(IDArray) do
3444 if ((gPanels[IDArray[i]].PanelType in
3445 [PANEL_WALL, PANEL_BACK, PANEL_FORE,
3446 PANEL_WATER, PANEL_ACID1, PANEL_ACID2,
3447 PANEL_STEP]) or
3448 (gPanels[IDArray[i]].PanelType = PANEL_OPENDOOR) or
3449 (gPanels[IDArray[i]].PanelType = PANEL_CLOSEDOOR)) and
3450 (gPanels[IDArray[i]].TextureName <> '') then
3451 begin
3452 gTriggers[SelectedObjects[
3453 GetFirstSelected() ].ID].Data.ShotPanelID := IDArray[i];
3454 Break;
3455 end;
3456 end
3457 else
3458 gTriggers[SelectedObjects[
3459 GetFirstSelected() ].ID].Data.ShotPanelID := -1;
3460 end;
3461 end;
3462 end;
3464 SelectFlag := SELECTFLAG_SELECTED;
3465 end
3466 else // if SelectFlag <> SELECTFLAG_NONE...
3467 begin
3468 // Что уже выбрано и не нажат Ctrl:
3469 if (SelectedObjects <> nil) and
3470 (not (ssCtrl in Shift)) then
3471 for i := 0 to High(SelectedObjects) do
3472 with SelectedObjects[i] do
3473 if Live then
3474 begin
3475 if (ObjectType in [OBJECT_PANEL, OBJECT_TRIGGER]) and
3476 (SelectedObjectCount() = 1) then
3477 begin
3478 Rect := ObjectGetRect(ObjectType, ID);
3480 c1 := g_Collide(X-MapOffset.X-1, Y-MapOffset.Y-1, 2, 2,
3481 Rect.X-2, Rect.Y+(Rect.Height div 2)-2, 4, 4);
3482 c2 := g_Collide(X-MapOffset.X-1, Y-MapOffset.Y-1, 2, 2,
3483 Rect.X+Rect.Width-3, Rect.Y+(Rect.Height div 2)-2, 4, 4);
3484 c3 := g_Collide(X-MapOffset.X-1, Y-MapOffset.Y-1, 2, 2,
3485 Rect.X+(Rect.Width div 2)-2, Rect.Y-2, 4, 4);
3486 c4 := g_Collide(X-MapOffset.X-1, Y-MapOffset.Y-1, 2, 2,
3487 Rect.X+(Rect.Width div 2)-2, Rect.Y+Rect.Height-3, 4, 4);
3489 // Меняем размер панели или триггера:
3490 if c1 or c2 or c3 or c4 then
3491 begin
3492 MouseAction := MOUSEACTION_RESIZE;
3493 LastMovePoint := MousePos;
3495 if c1 or c2 then
3496 begin // Шире/уже
3497 ResizeType := RESIZETYPE_HORIZONTAL;
3498 if c1 then
3499 ResizeDirection := RESIZEDIR_LEFT
3500 else
3501 ResizeDirection := RESIZEDIR_RIGHT;
3502 RenderPanel.Cursor := crSizeWE;
3503 end
3504 else
3505 begin // Выше/ниже
3506 ResizeType := RESIZETYPE_VERTICAL;
3507 if c3 then
3508 ResizeDirection := RESIZEDIR_UP
3509 else
3510 ResizeDirection := RESIZEDIR_DOWN;
3511 RenderPanel.Cursor := crSizeNS;
3512 end;
3514 Break;
3515 end;
3516 end;
3518 // Перемещаем панель или триггер:
3519 if ObjectCollide(ObjectType, ID,
3520 X-MapOffset.X-1,
3521 Y-MapOffset.Y-1, 2, 2) then
3522 begin
3523 MouseAction := MOUSEACTION_MOVEOBJ;
3524 LastMovePoint := MousePos;
3526 Break;
3527 end;
3528 end;
3529 end;
3530 end; // if Button = mbRight
3532 MouseRDown := Button = mbRight;
3533 if MouseRDown then
3534 MouseRDownPos := MousePos;
3536 MouseLDown := Button = mbLeft;
3537 if MouseLDown then
3538 MouseLDownPos := MousePos;
3539 end;
3541 procedure TMainForm.RenderPanelMouseUp(Sender: TObject;
3542 Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
3543 var
3544 panel: TPanel;
3545 trigger: TTrigger;
3546 i: Integer;
3547 IDArray: DWArray;
3548 rRect: TRectWH;
3549 rSelectRect: Boolean;
3550 begin
3551 if Button = mbLeft then
3552 MouseLDown := False;
3553 if Button = mbRight then
3554 MouseRDown := False;
3556 DrawRect := nil;
3557 ResizeType := RESIZETYPE_NONE;
3559 if Button = mbLeft then // Left Mouse Button
3560 begin
3561 if MouseAction <> MOUSEACTION_NONE then
3562 begin // Было действие мышью
3563 // Мышь сдвинулась во время удержания клавиши:
3564 if (MousePos.X <> MouseLDownPos.X) and
3565 (MousePos.Y <> MouseLDownPos.Y) then
3566 case MouseAction of
3567 // Рисовали панель:
3568 MOUSEACTION_DRAWPANEL:
3569 begin
3570 // Фон или передний план без текстуры - ошибка:
3571 if (lbPanelType.ItemIndex in [1, 2]) and
3572 (lbTextureList.ItemIndex = -1) then
3573 ErrorMessageBox(_lc[I_MSG_CHOOSE_TEXTURE])
3574 else // Назначаем параметры панели:
3575 begin
3576 case lbPanelType.ItemIndex of
3577 0: Panel.PanelType := PANEL_WALL;
3578 1: Panel.PanelType := PANEL_BACK;
3579 2: Panel.PanelType := PANEL_FORE;
3580 3: Panel.PanelType := PANEL_OPENDOOR;
3581 4: Panel.PanelType := PANEL_CLOSEDOOR;
3582 5: Panel.PanelType := PANEL_STEP;
3583 6: Panel.PanelType := PANEL_WATER;
3584 7: Panel.PanelType := PANEL_ACID1;
3585 8: Panel.PanelType := PANEL_ACID2;
3586 9: Panel.PanelType := PANEL_LIFTUP;
3587 10: Panel.PanelType := PANEL_LIFTDOWN;
3588 11: Panel.PanelType := PANEL_LIFTLEFT;
3589 12: Panel.PanelType := PANEL_LIFTRIGHT;
3590 13: Panel.PanelType := PANEL_BLOCKMON;
3591 end;
3593 Panel.X := Min(MousePos.X-MapOffset.X, MouseLDownPos.X-MapOffset.X);
3594 Panel.Y := Min(MousePos.Y-MapOffset.Y, MouseLDownPos.Y-MapOffset.Y);
3595 Panel.Width := Abs(MousePos.X-MouseLDownPos.X);
3596 Panel.Height := Abs(MousePos.Y-MouseLDownPos.Y);
3598 // Лифты, блокМон или отсутствие текстуры - пустая текстура:
3599 if (lbPanelType.ItemIndex in [9, 10, 11, 12, 13]) or
3600 (lbTextureList.ItemIndex = -1) then
3601 begin
3602 Panel.TextureHeight := 1;
3603 Panel.TextureWidth := 1;
3604 Panel.TextureName := '';
3605 Panel.TextureID := TEXTURE_SPECIAL_NONE;
3606 end
3607 else // Есть текстура:
3608 begin
3609 Panel.TextureName := SelectedTexture();
3611 // Обычная текстура:
3612 if not IsSpecialTextureSel() then
3613 begin
3614 g_GetTextureSizeByName(Panel.TextureName,
3615 Panel.TextureWidth, Panel.TextureHeight);
3616 g_GetTexture(Panel.TextureName, Panel.TextureID);
3617 end
3618 else // Спец.текстура:
3619 begin
3620 Panel.TextureHeight := 1;
3621 Panel.TextureWidth := 1;
3622 Panel.TextureID := SpecialTextureID(SelectedTexture());
3623 end;
3624 end;
3626 Panel.Alpha := 0;
3627 Panel.Blending := False;
3629 Undo_Add(OBJECT_PANEL, AddPanel(Panel));
3630 end;
3631 end;
3633 // Рисовали триггер:
3634 MOUSEACTION_DRAWTRIGGER:
3635 begin
3636 trigger.X := Min(MousePos.X-MapOffset.X, MouseLDownPos.X-MapOffset.X);
3637 trigger.Y := Min(MousePos.Y-MapOffset.Y, MouseLDownPos.Y-MapOffset.Y);
3638 trigger.Width := Abs(MousePos.X-MouseLDownPos.X);
3639 trigger.Height := Abs(MousePos.Y-MouseLDownPos.Y);
3641 trigger.Enabled := True;
3642 trigger.TriggerType := lbTriggersList.ItemIndex+1;
3643 trigger.TexturePanel := -1;
3645 // Типы активации:
3646 trigger.ActivateType := 0;
3648 if clbActivationType.Checked[0] then
3649 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_PLAYERCOLLIDE;
3650 if clbActivationType.Checked[1] then
3651 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_MONSTERCOLLIDE;
3652 if clbActivationType.Checked[2] then
3653 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_PLAYERPRESS;
3654 if clbActivationType.Checked[3] then
3655 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_MONSTERPRESS;
3656 if clbActivationType.Checked[4] then
3657 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_SHOT;
3658 if clbActivationType.Checked[5] then
3659 trigger.ActivateType := Trigger.ActivateType or ACTIVATE_NOMONSTER;
3661 // Необходимые для активации ключи:
3662 trigger.Key := 0;
3664 if clbKeys.Checked[0] then
3665 trigger.Key := Trigger.Key or KEY_RED;
3666 if clbKeys.Checked[1] then
3667 trigger.Key := Trigger.Key or KEY_GREEN;
3668 if clbKeys.Checked[2] then
3669 trigger.Key := Trigger.Key or KEY_BLUE;
3670 if clbKeys.Checked[3] then
3671 trigger.Key := Trigger.Key or KEY_REDTEAM;
3672 if clbKeys.Checked[4] then
3673 trigger.Key := Trigger.Key or KEY_BLUETEAM;
3675 // Параметры триггера:
3676 FillByte(trigger.Data.Default[0], 128, 0);
3678 case trigger.TriggerType of
3679 // Переключаемая панель:
3680 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
3681 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP,
3682 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
3683 begin
3684 Trigger.Data.PanelID := -1;
3685 end;
3687 // Телепортация:
3688 TRIGGER_TELEPORT:
3689 begin
3690 trigger.Data.TargetPoint.X := trigger.X-64;
3691 trigger.Data.TargetPoint.Y := trigger.Y-64;
3692 trigger.Data.d2d_teleport := True;
3693 trigger.Data.TlpDir := 0;
3694 end;
3696 // Изменение других триггеров:
3697 TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF,
3698 TRIGGER_ONOFF:
3699 begin
3700 trigger.Data.Count := 1;
3701 end;
3703 // Звук:
3704 TRIGGER_SOUND:
3705 begin
3706 trigger.Data.Volume := 255;
3707 trigger.Data.Pan := 127;
3708 trigger.Data.PlayCount := 1;
3709 trigger.Data.Local := True;
3710 trigger.Data.SoundSwitch := False;
3711 end;
3713 // Музыка:
3714 TRIGGER_MUSIC:
3715 begin
3716 trigger.Data.MusicAction := 1;
3717 end;
3719 // Создание монстра:
3720 TRIGGER_SPAWNMONSTER:
3721 begin
3722 trigger.Data.MonType := MONSTER_ZOMBY;
3723 trigger.Data.MonPos.X := trigger.X-64;
3724 trigger.Data.MonPos.Y := trigger.Y-64;
3725 trigger.Data.MonHealth := 0;
3726 trigger.Data.MonActive := False;
3727 trigger.Data.MonCount := 1;
3728 end;
3730 // Создание предмета:
3731 TRIGGER_SPAWNITEM:
3732 begin
3733 trigger.Data.ItemType := ITEM_AMMO_BULLETS;
3734 trigger.Data.ItemPos.X := trigger.X-64;
3735 trigger.Data.ItemPos.Y := trigger.Y-64;
3736 trigger.Data.ItemOnlyDM := False;
3737 trigger.Data.ItemFalls := False;
3738 trigger.Data.ItemCount := 1;
3739 trigger.Data.ItemMax := 0;
3740 trigger.Data.ItemDelay := 0;
3741 end;
3743 // Ускорение:
3744 TRIGGER_PUSH:
3745 begin
3746 trigger.Data.PushAngle := 90;
3747 trigger.Data.PushForce := 10;
3748 trigger.Data.ResetVel := True;
3749 end;
3751 TRIGGER_SCORE:
3752 begin
3753 trigger.Data.ScoreCount := 1;
3754 trigger.Data.ScoreCon := True;
3755 trigger.Data.ScoreMsg := True;
3756 end;
3758 TRIGGER_MESSAGE:
3759 begin
3760 trigger.Data.MessageKind := 0;
3761 trigger.Data.MessageSendTo := 0;
3762 trigger.Data.MessageText := '';
3763 trigger.Data.MessageTime := 144;
3764 end;
3766 TRIGGER_DAMAGE:
3767 begin
3768 trigger.Data.DamageValue := 5;
3769 trigger.Data.DamageInterval := 12;
3770 end;
3772 TRIGGER_HEALTH:
3773 begin
3774 trigger.Data.HealValue := 5;
3775 trigger.Data.HealInterval := 36;
3776 end;
3778 TRIGGER_SHOT:
3779 begin
3780 trigger.Data.ShotType := TRIGGER_SHOT_BULLET;
3781 trigger.Data.ShotSound := True;
3782 trigger.Data.ShotPanelID := -1;
3783 trigger.Data.ShotTarget := 0;
3784 trigger.Data.ShotIntSight := 0;
3785 trigger.Data.ShotAim := TRIGGER_SHOT_AIM_DEFAULT;
3786 trigger.Data.ShotPos.X := trigger.X-64;
3787 trigger.Data.ShotPos.Y := trigger.Y-64;
3788 trigger.Data.ShotAngle := 0;
3789 trigger.Data.ShotWait := 18;
3790 trigger.Data.ShotAccuracy := 0;
3791 trigger.Data.ShotAmmo := 0;
3792 trigger.Data.ShotIntReload := 0;
3793 end;
3795 TRIGGER_EFFECT:
3796 begin
3797 trigger.Data.FXCount := 1;
3798 trigger.Data.FXType := TRIGGER_EFFECT_PARTICLE;
3799 trigger.Data.FXSubType := TRIGGER_EFFECT_SLIQUID;
3800 trigger.Data.FXColorR := 0;
3801 trigger.Data.FXColorG := 0;
3802 trigger.Data.FXColorB := 255;
3803 trigger.Data.FXPos := TRIGGER_EFFECT_POS_CENTER;
3804 trigger.Data.FXWait := 1;
3805 trigger.Data.FXVelX := 0;
3806 trigger.Data.FXVelY := -20;
3807 trigger.Data.FXSpreadL := 5;
3808 trigger.Data.FXSpreadR := 5;
3809 trigger.Data.FXSpreadU := 4;
3810 trigger.Data.FXSpreadD := 0;
3811 end;
3812 end;
3814 Undo_Add(OBJECT_TRIGGER, AddTrigger(trigger));
3815 end;
3817 // Рисовали область триггера "Расширитель":
3818 MOUSEACTION_DRAWPRESS:
3819 with gTriggers[SelectedObjects[GetFirstSelected].ID] do
3820 begin
3821 Data.tX := Min(MousePos.X-MapOffset.X, MouseLDownPos.X-MapOffset.X);
3822 Data.tY := Min(MousePos.Y-MapOffset.Y, MouseLDownPos.Y-MapOffset.Y);
3823 Data.tWidth := Abs(MousePos.X-MouseLDownPos.X);
3824 Data.tHeight := Abs(MousePos.Y-MouseLDownPos.Y);
3826 DrawPressRect := False;
3827 end;
3828 end;
3830 MouseAction := MOUSEACTION_NONE;
3831 end;
3832 end // if Button = mbLeft...
3833 else // Right Mouse Button:
3834 begin
3835 if MouseAction = MOUSEACTION_NOACTION then
3836 begin
3837 MouseAction := MOUSEACTION_NONE;
3838 Exit;
3839 end;
3841 // Объект передвинут или изменен в размере:
3842 if MouseAction in [MOUSEACTION_MOVEOBJ, MOUSEACTION_RESIZE] then
3843 begin
3844 MouseAction := MOUSEACTION_NONE;
3845 FillProperty();
3846 Exit;
3847 end;
3849 // Еще не все выбрали:
3850 if SelectFlag <> SELECTFLAG_NONE then
3851 begin
3852 if SelectFlag = SELECTFLAG_SELECTED then
3853 SelectFlag := SELECTFLAG_NONE;
3854 FillProperty();
3855 Exit;
3856 end;
3858 // Мышь сдвинулась во время удержания клавиши:
3859 if (MousePos.X <> MouseRDownPos.X) and
3860 (MousePos.Y <> MouseRDownPos.Y) then
3861 begin
3862 rSelectRect := True;
3864 rRect.X := Min(MousePos.X, MouseRDownPos.X)-MapOffset.X;
3865 rRect.Y := Min(MousePos.Y, MouseRDownPos.Y)-MapOffset.Y;
3866 rRect.Width := Abs(MousePos.X-MouseRDownPos.X);
3867 rRect.Height := Abs(MousePos.Y-MouseRDownPos.Y);
3868 end
3869 else // Мышь не сдвинулась - нет прямоугольника:
3870 begin
3871 rSelectRect := False;
3873 rRect.X := X-MapOffset.X-1;
3874 rRect.Y := Y-MapOffset.Y-1;
3875 rRect.Width := 2;
3876 rRect.Height := 2;
3877 end;
3879 // Если зажат Ctrl - выделять еще, иначе только один выделенный объект:
3880 if not (ssCtrl in Shift) then
3881 RemoveSelectFromObjects();
3883 // Выделяем всё в выбранном прямоугольнике:
3884 IDArray := ObjectInRect(rRect.X, rRect.Y,
3885 rRect.Width, rRect.Height,
3886 pcObjects.ActivePageIndex+1, rSelectRect);
3888 if IDArray <> nil then
3889 for i := 0 to High(IDArray) do
3890 SelectObject(pcObjects.ActivePageIndex+1, IDArray[i],
3891 (ssCtrl in Shift) or rSelectRect);
3893 FillProperty();
3894 end;
3895 end;
3897 procedure TMainForm.RenderPanelPaint(Sender: TObject);
3898 begin
3899 Draw();
3900 end;
3902 procedure TMainForm.RenderPanelMouseMove(Sender: TObject;
3903 Shift: TShiftState; X, Y: Integer);
3904 var
3905 sX, sY: Integer;
3906 dWidth, dHeight: Integer;
3907 _id: Integer;
3908 begin
3909 _id := GetFirstSelected();
3911 // Рисуем панель с текстурой, сетка - размеры текстуры:
3912 if (MouseAction = MOUSEACTION_DRAWPANEL) and
3913 (lbPanelType.ItemIndex in [0..8]) and
3914 (lbTextureList.ItemIndex <> -1) and
3915 (not IsSpecialTextureSel()) then
3916 begin
3917 sX := StrToIntDef(lTextureWidth.Caption, DotStep);
3918 sY := StrToIntDef(lTextureHeight.Caption, DotStep);
3919 end
3920 else
3921 // Меняем размер панели с текстурой, сетка - размеры текстуры:
3922 if (MouseAction = MOUSEACTION_RESIZE) and
3923 ( (SelectedObjects[_id].ObjectType = OBJECT_PANEL) and
3924 IsTexturedPanel(gPanels[SelectedObjects[_id].ID].PanelType) and
3925 (gPanels[SelectedObjects[_id].ID].TextureName <> '') and
3926 (not IsSpecialTexture(gPanels[SelectedObjects[_id].ID].TextureName)) ) then
3927 begin
3928 sX := gPanels[SelectedObjects[_id].ID].TextureWidth;
3929 sY := gPanels[SelectedObjects[_id].ID].TextureHeight;
3930 end
3931 else
3932 // Выравнивание по сетке:
3933 if SnapToGrid then
3934 begin
3935 sX := DotStep;
3936 sY := DotStep;
3937 end
3938 else // Нет выравнивания по сетке:
3939 begin
3940 sX := 1;
3941 sY := 1;
3942 end;
3944 // Новая позиция мыши:
3945 if MouseLDown then
3946 begin // Зажата левая кнопка мыши
3947 MousePos.X := (Round((X-MouseLDownPos.X)/sX)*sX)+MouseLDownPos.X;
3948 MousePos.Y := (Round((Y-MouseLDownPos.Y)/sY)*sY)+MouseLDownPos.Y;
3949 end
3950 else
3951 if MouseRDown then
3952 begin // Зажата правая кнопка мыши
3953 MousePos.X := (Round((X-MouseRDownPos.X)/sX)*sX)+MouseRDownPos.X;
3954 MousePos.Y := (Round((Y-MouseRDownPos.Y)/sY)*sY)+MouseRDownPos.Y;
3955 end
3956 else
3957 begin // Кнопки мыши не зажаты
3958 MousePos.X := (Round(X/sX)*sX);
3959 MousePos.Y := (Round(Y/sY)*sY);
3960 end;
3962 // Изменение размера закончилось - ставим обычный курсор:
3963 if ResizeType = RESIZETYPE_NONE then
3964 RenderPanel.Cursor := crDefault;
3966 // Зажата только правая кнопка мыши:
3967 if (not MouseLDown) and (MouseRDown) then
3968 begin
3969 // Рисуем прямоугольник выделения:
3970 if MouseAction = MOUSEACTION_NONE then
3971 begin
3972 if DrawRect = nil then
3973 New(DrawRect);
3974 DrawRect.Top := MouseRDownPos.y;
3975 DrawRect.Left := MouseRDownPos.x;
3976 DrawRect.Bottom := MousePos.y;
3977 DrawRect.Right := MousePos.x;
3978 end
3979 else
3980 // Двигаем выделенные объекты:
3981 if MouseAction = MOUSEACTION_MOVEOBJ then
3982 begin
3983 MoveSelectedObjects(ssShift in Shift, ssCtrl in Shift,
3984 MousePos.X-LastMovePoint.X,
3985 MousePos.Y-LastMovePoint.Y);
3986 end
3987 else
3988 // Меняем размер выделенного объекта:
3989 if MouseAction = MOUSEACTION_RESIZE then
3990 begin
3991 if (SelectedObjectCount = 1) and
3992 (SelectedObjects[GetFirstSelected].Live) then
3993 begin
3994 dWidth := MousePos.X-LastMovePoint.X;
3995 dHeight := MousePos.Y-LastMovePoint.Y;
3997 case ResizeType of
3998 RESIZETYPE_VERTICAL: dWidth := 0;
3999 RESIZETYPE_HORIZONTAL: dHeight := 0;
4000 end;
4002 case ResizeDirection of
4003 RESIZEDIR_UP: dHeight := -dHeight;
4004 RESIZEDIR_LEFT: dWidth := -dWidth;
4005 end;
4007 ResizeObject(SelectedObjects[GetFirstSelected].ObjectType,
4008 SelectedObjects[GetFirstSelected].ID,
4009 dWidth, dHeight, ResizeDirection);
4011 LastMovePoint := MousePos;
4012 end;
4013 end;
4014 end;
4016 // Зажата только левая кнопка мыши:
4017 if (not MouseRDown) and (MouseLDown) then
4018 begin
4019 // Рисуем прямоугольник планирования панели:
4020 if MouseAction in [MOUSEACTION_DRAWPANEL,
4021 MOUSEACTION_DRAWTRIGGER,
4022 MOUSEACTION_DRAWPRESS] then
4023 begin
4024 if DrawRect = nil then
4025 New(DrawRect);
4026 DrawRect.Top := MouseLDownPos.y;
4027 DrawRect.Left := MouseLDownPos.x;
4028 DrawRect.Bottom := MousePos.y;
4029 DrawRect.Right := MousePos.x;
4030 end
4031 else // Двигаем карту:
4032 if MouseAction = MOUSEACTION_MOVEMAP then
4033 begin
4034 MoveMap(X, Y);
4035 end;
4036 end;
4038 // Клавиши мыши не зажаты:
4039 if (not MouseRDown) and (not MouseLDown) then
4040 DrawRect := nil;
4042 // Строка состояния - координаты мыши:
4043 StatusBar.Panels[1].Text := Format('(%d:%d)',
4044 [MousePos.X-MapOffset.X, MousePos.Y-MapOffset.Y]);
4045 end;
4047 procedure TMainForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
4048 begin
4049 CanClose := MessageBox(0, PChar(_lc[I_MSG_EXIT_PROMT]),
4050 PChar(_lc[I_MSG_EXIT]),
4051 MB_ICONQUESTION or MB_YESNO or
4052 MB_DEFBUTTON1) = idYes;
4053 end;
4055 procedure TMainForm.aExitExecute(Sender: TObject);
4056 begin
4057 Close();
4058 end;
4060 procedure TMainForm.FormDestroy(Sender: TObject);
4061 var
4062 config: TConfig;
4063 i: Integer;
4064 begin
4065 config := TConfig.CreateFile(EditorDir+'Editor.cfg');
4067 if WindowState <> wsMaximized then
4068 begin
4069 config.WriteInt('Editor', 'XPos', Left);
4070 config.WriteInt('Editor', 'YPos', Top);
4071 config.WriteInt('Editor', 'Width', Width);
4072 config.WriteInt('Editor', 'Height', Height);
4073 end
4074 else
4075 begin
4076 config.WriteInt('Editor', 'XPos', RestoredLeft);
4077 config.WriteInt('Editor', 'YPos', RestoredTop);
4078 config.WriteInt('Editor', 'Width', RestoredWidth);
4079 config.WriteInt('Editor', 'Height', RestoredHeight);
4080 end;
4081 config.WriteBool('Editor', 'Maximize', WindowState = wsMaximized);
4082 config.WriteBool('Editor', 'Minimap', ShowMap);
4083 config.WriteInt('Editor', 'PanelProps', PanelProps.ClientWidth);
4084 config.WriteInt('Editor', 'PanelObjs', PanelObjs.ClientHeight);
4085 config.WriteBool('Editor', 'DotEnable', DotEnable);
4086 config.WriteInt('Editor', 'DotStep', DotStep);
4087 config.WriteStr('Editor', 'LastOpenDir', OpenDialog.InitialDir);
4088 config.WriteStr('Editor', 'LastSaveDir', SaveDialog.InitialDir);
4089 config.WriteBool('Editor', 'EdgeShow', drEdge[3] < 255);
4090 config.WriteInt('Editor', 'EdgeColor', gColorEdge);
4091 config.WriteInt('Editor', 'EdgeAlpha', gAlphaEdge);
4092 config.WriteInt('Editor', 'LineAlpha', gAlphaTriggerLine);
4093 config.WriteInt('Editor', 'TriggerAlpha', gAlphaTriggerArea);
4095 for i := 0 to RecentCount-1 do
4096 if i < RecentFiles.Count then
4097 config.WriteStr('RecentFiles', IntToStr(i+1), RecentFiles[i])
4098 else
4099 config.WriteStr('RecentFiles', IntToStr(i+1), '');
4100 RecentFiles.Free();
4102 config.SaveFile(EditorDir+'Editor.cfg');
4103 config.Free();
4105 slInvalidTextures.Free;
4106 end;
4108 procedure TMainForm.RenderPanelResize(Sender: TObject);
4109 begin
4110 if MainForm.Visible then
4111 MainForm.Resize();
4112 end;
4114 procedure TMainForm.Splitter1Moved(Sender: TObject);
4115 begin
4116 FormResize(Sender);
4117 end;
4119 procedure TMainForm.aMapOptionsExecute(Sender: TObject);
4120 var
4121 ResName: String;
4122 begin
4123 MapOptionsForm.ShowModal();
4125 ResName := OpenedMap;
4126 while (Pos(':\', ResName) > 0) do
4127 Delete(ResName, 1, Pos(':\', ResName) + 1);
4129 UpdateCaption(gMapInfo.Name, ExtractFileName(OpenedWAD), ResName);
4130 end;
4132 procedure TMainForm.aAboutExecute(Sender: TObject);
4133 begin
4134 AboutForm.ShowModal();
4135 end;
4137 procedure TMainForm.FormKeyDown(Sender: TObject; var Key: Word;
4138 Shift: TShiftState);
4139 var
4140 dx, dy, i: Integer;
4141 FileName: String;
4142 begin
4143 if (not EditingProperties) then
4144 begin
4145 if Key = Ord('1') then
4146 SwitchLayer(LAYER_BACK);
4147 if Key = Ord('2') then
4148 SwitchLayer(LAYER_WALLS);
4149 if Key = Ord('3') then
4150 SwitchLayer(LAYER_FOREGROUND);
4151 if Key = Ord('4') then
4152 SwitchLayer(LAYER_STEPS);
4153 if Key = Ord('5') then
4154 SwitchLayer(LAYER_WATER);
4155 if Key = Ord('6') then
4156 SwitchLayer(LAYER_ITEMS);
4157 if Key = Ord('7') then
4158 SwitchLayer(LAYER_MONSTERS);
4159 if Key = Ord('8') then
4160 SwitchLayer(LAYER_AREAS);
4161 if Key = Ord('9') then
4162 SwitchLayer(LAYER_TRIGGERS);
4163 if Key = Ord('0') then
4164 tbShowClick(tbShow);
4166 if Key = Ord('V') then
4167 begin // Поворот монстров и областей:
4168 if (SelectedObjects <> nil) then
4169 begin
4170 for i := 0 to High(SelectedObjects) do
4171 if (SelectedObjects[i].Live) then
4172 begin
4173 if (SelectedObjects[i].ObjectType = OBJECT_MONSTER) then
4174 begin
4175 g_ChangeDir(gMonsters[SelectedObjects[i].ID].Direction);
4176 end
4177 else
4178 if (SelectedObjects[i].ObjectType = OBJECT_AREA) then
4179 begin
4180 g_ChangeDir(gAreas[SelectedObjects[i].ID].Direction);
4181 end;
4182 end;
4183 end
4184 else
4185 begin
4186 if pcObjects.ActivePage = tsMonsters then
4187 begin
4188 if rbMonsterLeft.Checked then
4189 rbMonsterRight.Checked := True
4190 else
4191 rbMonsterLeft.Checked := True;
4192 end;
4193 if pcObjects.ActivePage = tsAreas then
4194 begin
4195 if rbAreaLeft.Checked then
4196 rbAreaRight.Checked := True
4197 else
4198 rbAreaLeft.Checked := True;
4199 end;
4200 end;
4201 end;
4203 if not (ssCtrl in Shift) then
4204 begin
4205 // Вертикальный скролл карты:
4206 with sbVertical do
4207 begin
4208 if Key = Ord('W') then
4209 begin
4210 Position := IfThen(Position > DotStep, Position-DotStep, 0);
4211 MapOffset.Y := -Round(Position/16) * 16;
4212 end;
4214 if Key = Ord('S') then
4215 begin
4216 Position := IfThen(Position+DotStep < Max, Position+DotStep, Max);
4217 MapOffset.Y := -Round(Position/16) * 16;
4218 end;
4219 end;
4221 // Горизонтальный скролл карты:
4222 with sbHorizontal do
4223 begin
4224 if Key = Ord('A') then
4225 begin
4226 Position := IfThen(Position > DotStep, Position-DotStep, 0);
4227 MapOffset.X := -Round(Position/16) * 16;
4228 end;
4230 if Key = Ord('D') then
4231 begin
4232 Position := IfThen(Position+DotStep < Max, Position+DotStep, Max);
4233 MapOffset.X := -Round(Position/16) * 16;
4234 end;
4235 end;
4236 end;
4237 end;
4239 // Удалить выделенные объекты:
4240 if (Key = VK_DELETE) and (SelectedObjects <> nil) and
4241 RenderPanel.Focused() then
4242 DeleteSelectedObjects();
4244 // Снять выделение:
4245 if (Key = VK_ESCAPE) and (SelectedObjects <> nil) then
4246 RemoveSelectFromObjects();
4248 // Передвинуть объекты:
4249 if MainForm.ActiveControl = RenderPanel then
4250 begin
4251 dx := 0;
4252 dy := 0;
4254 if Key = VK_NUMPAD4 then
4255 dx := IfThen(ssAlt in Shift, -1, -DotStep);
4256 if Key = VK_NUMPAD6 then
4257 dx := IfThen(ssAlt in Shift, 1, DotStep);
4258 if Key = VK_NUMPAD8 then
4259 dy := IfThen(ssAlt in Shift, -1, -DotStep);
4260 if Key = VK_NUMPAD5 then
4261 dy := IfThen(ssAlt in Shift, 1, DotStep);
4263 if (dx <> 0) or (dy <> 0) then
4264 begin
4265 MoveSelectedObjects(ssShift in Shift, ssCtrl in Shift, dx, dy);
4266 Key := 0;
4267 end;
4268 end;
4270 if ssCtrl in Shift then
4271 begin
4272 // Выбор панели с текстурой для триггера
4273 if Key = Ord('T') then
4274 begin
4275 DrawPressRect := False;
4276 if SelectFlag = SELECTFLAG_TEXTURE then
4277 begin
4278 SelectFlag := SELECTFLAG_NONE;
4279 Exit;
4280 end;
4281 vleObjectProperty.FindRow(_lc[I_PROP_TR_TEXTURE_PANEL], i);
4282 if i > 0 then
4283 SelectFlag := SELECTFLAG_TEXTURE;
4284 end;
4286 if Key = Ord('D') then
4287 begin
4288 SelectFlag := SELECTFLAG_NONE;
4289 if DrawPressRect then
4290 begin
4291 DrawPressRect := False;
4292 Exit;
4293 end;
4294 i := -1;
4296 // Выбор области воздействия, в зависимости от типа триггера
4297 vleObjectProperty.FindRow(_lc[I_PROP_TR_EX_AREA], i);
4298 if i > 0 then
4299 begin
4300 DrawPressRect := True;
4301 Exit;
4302 end;
4303 vleObjectProperty.FindRow(_lc[I_PROP_TR_DOOR_PANEL], i);
4304 if i <= 0 then
4305 vleObjectProperty.FindRow(_lc[I_PROP_TR_TRAP_PANEL], i);
4306 if i > 0 then
4307 begin
4308 SelectFlag := SELECTFLAG_DOOR;
4309 Exit;
4310 end;
4311 vleObjectProperty.FindRow(_lc[I_PROP_TR_LIFT_PANEL], i);
4312 if i > 0 then
4313 begin
4314 SelectFlag := SELECTFLAG_LIFT;
4315 Exit;
4316 end;
4317 vleObjectProperty.FindRow(_lc[I_PROP_TR_TELEPORT_TO], i);
4318 if i > 0 then
4319 begin
4320 SelectFlag := SELECTFLAG_TELEPORT;
4321 Exit;
4322 end;
4323 vleObjectProperty.FindRow(_lc[I_PROP_TR_SPAWN_TO], i);
4324 if i > 0 then
4325 begin
4326 SelectFlag := SELECTFLAG_SPAWNPOINT;
4327 Exit;
4328 end;
4330 // Выбор основного параметра, в зависимости от типа триггера
4331 vleObjectProperty.FindRow(_lc[I_PROP_TR_NEXT_MAP], i);
4332 if i > 0 then
4333 begin
4334 g_ProcessResourceStr(OpenedMap, @FileName, nil, nil);
4335 SelectMapForm.GetMaps(FileName);
4337 if SelectMapForm.ShowModal() = mrOK then
4338 begin
4339 vleObjectProperty.Cells[1, i] := SelectMapForm.lbMapList.Items[SelectMapForm.lbMapList.ItemIndex];
4340 bApplyProperty.Click();
4341 end;
4342 Exit;
4343 end;
4344 vleObjectProperty.FindRow(_lc[I_PROP_TR_SOUND_NAME], i);
4345 if i <= 0 then
4346 vleObjectProperty.FindRow(_lc[I_PROP_TR_MUSIC_NAME], i);
4347 if i > 0 then
4348 begin
4349 AddSoundForm.OKFunction := nil;
4350 AddSoundForm.lbResourcesList.MultiSelect := False;
4351 AddSoundForm.SetResource := vleObjectProperty.Cells[1, i];
4353 if (AddSoundForm.ShowModal() = mrOk) then
4354 begin
4355 vleObjectProperty.Cells[1, i] := AddSoundForm.ResourceName;
4356 bApplyProperty.Click();
4357 end;
4358 Exit;
4359 end;
4360 vleObjectProperty.FindRow(_lc[I_PROP_TR_PUSH_ANGLE], i);
4361 if i <= 0 then
4362 vleObjectProperty.FindRow(_lc[I_PROP_TR_MESSAGE_TEXT], i);
4363 if i > 0 then
4364 begin
4365 vleObjectProperty.Row := i;
4366 vleObjectProperty.SetFocus();
4367 Exit;
4368 end;
4369 end;
4370 end;
4371 end;
4373 procedure TMainForm.aOptimizeExecute(Sender: TObject);
4374 begin
4375 RemoveSelectFromObjects();
4376 MapOptimizationForm.ShowModal();
4377 end;
4379 procedure TMainForm.aCheckMapExecute(Sender: TObject);
4380 begin
4381 MapCheckForm.ShowModal();
4382 end;
4384 procedure TMainForm.bbAddTextureClick(Sender: TObject);
4385 begin
4386 AddTextureForm.lbResourcesList.MultiSelect := True;
4387 AddTextureForm.ShowModal();
4388 end;
4390 procedure TMainForm.lbTextureListClick(Sender: TObject);
4391 var
4392 TextureID: DWORD;
4393 TextureWidth, TextureHeight: Word;
4394 begin
4395 TextureID := 0;
4396 TextureWidth := 0;
4397 TextureHeight := 0;
4398 if (lbTextureList.ItemIndex <> -1) and
4399 (not IsSpecialTextureSel()) then
4400 begin
4401 if g_GetTexture(SelectedTexture(), TextureID) then
4402 begin
4403 g_GetTextureSizeByID(TextureID, TextureWidth, TextureHeight);
4405 lTextureWidth.Caption := IntToStr(TextureWidth);
4406 lTextureHeight.Caption := IntToStr(TextureHeight);
4407 end else
4408 begin
4409 lTextureWidth.Caption := _lc[I_NOT_ACCESSIBLE];
4410 lTextureHeight.Caption := _lc[I_NOT_ACCESSIBLE];
4411 end;
4412 end
4413 else
4414 begin
4415 lTextureWidth.Caption := '';
4416 lTextureHeight.Caption := '';
4417 end;
4418 end;
4420 procedure TMainForm.lbTextureListDrawItem(Control: TWinControl; Index: Integer;
4421 ARect: TRect; State: TOwnerDrawState);
4422 begin
4423 with Control as TListBox do
4424 begin
4425 if LCLType.odSelected in State then
4426 begin
4427 Canvas.Brush.Color := clHighlight;
4428 Canvas.Font.Color := clHighlightText;
4429 end else
4430 if (Items <> nil) and (Index >= 0) then
4431 if slInvalidTextures.IndexOf(Items[Index]) > -1 then
4432 begin
4433 Canvas.Brush.Color := clRed;
4434 Canvas.Font.Color := clWhite;
4435 end;
4436 Canvas.FillRect(ARect);
4437 Canvas.TextRect(ARect, ARect.Left, ARect.Top, Items[Index]);
4438 end;
4439 end;
4441 procedure TMainForm.vleObjectPropertyGetPickList(Sender: TObject;
4442 const KeyName: String; Values: TStrings);
4443 begin
4444 if vleObjectProperty.ItemProps[KeyName].EditStyle = esPickList then
4445 begin
4446 if KeyName = _lc[I_PROP_DIRECTION] then
4447 begin
4448 Values.Add(DirNames[D_LEFT]);
4449 Values.Add(DirNames[D_RIGHT]);
4450 end
4451 else if KeyName = _lc[I_PROP_TR_TELEPORT_DIR] then
4452 begin
4453 Values.Add(DirNamesAdv[0]);
4454 Values.Add(DirNamesAdv[1]);
4455 Values.Add(DirNamesAdv[2]);
4456 Values.Add(DirNamesAdv[3]);
4457 end
4458 else if KeyName = _lc[I_PROP_TR_MUSIC_ACT] then
4459 begin
4460 Values.Add(_lc[I_PROP_TR_MUSIC_ON]);
4461 Values.Add(_lc[I_PROP_TR_MUSIC_OFF]);
4462 end
4463 else if KeyName = _lc[I_PROP_TR_MONSTER_BEHAVIOUR] then
4464 begin
4465 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_0]);
4466 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_1]);
4467 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_2]);
4468 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_3]);
4469 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_4]);
4470 Values.Add(_lc[I_PROP_TR_MONSTER_BEHAVIOUR_5]);
4471 end
4472 else if KeyName = _lc[I_PROP_TR_SCORE_ACT] then
4473 begin
4474 Values.Add(_lc[I_PROP_TR_SCORE_ACT_0]);
4475 Values.Add(_lc[I_PROP_TR_SCORE_ACT_1]);
4476 Values.Add(_lc[I_PROP_TR_SCORE_ACT_2]);
4477 Values.Add(_lc[I_PROP_TR_SCORE_ACT_3]);
4478 end
4479 else if KeyName = _lc[I_PROP_TR_SCORE_TEAM] then
4480 begin
4481 Values.Add(_lc[I_PROP_TR_SCORE_TEAM_0]);
4482 Values.Add(_lc[I_PROP_TR_SCORE_TEAM_1]);
4483 Values.Add(_lc[I_PROP_TR_SCORE_TEAM_2]);
4484 Values.Add(_lc[I_PROP_TR_SCORE_TEAM_3]);
4485 end
4486 else if KeyName = _lc[I_PROP_TR_MESSAGE_KIND] then
4487 begin
4488 Values.Add(_lc[I_PROP_TR_MESSAGE_KIND_0]);
4489 Values.Add(_lc[I_PROP_TR_MESSAGE_KIND_1]);
4490 end
4491 else if KeyName = _lc[I_PROP_TR_MESSAGE_TO] then
4492 begin
4493 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_0]);
4494 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_1]);
4495 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_2]);
4496 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_3]);
4497 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_4]);
4498 Values.Add(_lc[I_PROP_TR_MESSAGE_TO_5]);
4499 end
4500 else if KeyName = _lc[I_PROP_TR_SHOT_TO] then
4501 begin
4502 Values.Add(_lc[I_PROP_TR_SHOT_TO_0]);
4503 Values.Add(_lc[I_PROP_TR_SHOT_TO_1]);
4504 Values.Add(_lc[I_PROP_TR_SHOT_TO_2]);
4505 Values.Add(_lc[I_PROP_TR_SHOT_TO_3]);
4506 Values.Add(_lc[I_PROP_TR_SHOT_TO_4]);
4507 Values.Add(_lc[I_PROP_TR_SHOT_TO_5]);
4508 Values.Add(_lc[I_PROP_TR_SHOT_TO_6]);
4509 end
4510 else if KeyName = _lc[I_PROP_TR_SHOT_AIM] then
4511 begin
4512 Values.Add(_lc[I_PROP_TR_SHOT_AIM_0]);
4513 Values.Add(_lc[I_PROP_TR_SHOT_AIM_1]);
4514 Values.Add(_lc[I_PROP_TR_SHOT_AIM_2]);
4515 Values.Add(_lc[I_PROP_TR_SHOT_AIM_3]);
4516 end
4517 else if (KeyName = _lc[I_PROP_PANEL_BLEND]) or
4518 (KeyName = _lc[I_PROP_DM_ONLY]) or
4519 (KeyName = _lc[I_PROP_ITEM_FALLS]) or
4520 (KeyName = _lc[I_PROP_TR_ENABLED]) or
4521 (KeyName = _lc[I_PROP_TR_D2D]) or
4522 (KeyName = _lc[I_PROP_TR_SILENT]) or
4523 (KeyName = _lc[I_PROP_TR_TELEPORT_SILENT]) or
4524 (KeyName = _lc[I_PROP_TR_EX_RANDOM]) or
4525 (KeyName = _lc[I_PROP_TR_TEXTURE_ONCE]) or
4526 (KeyName = _lc[I_PROP_TR_TEXTURE_ANIM_ONCE]) or
4527 (KeyName = _lc[I_PROP_TR_SOUND_LOCAL]) or
4528 (KeyName = _lc[I_PROP_TR_SOUND_SWITCH]) or
4529 (KeyName = _lc[I_PROP_TR_MONSTER_ACTIVE]) or
4530 (KeyName = _lc[I_PROP_TR_PUSH_RESET]) or
4531 (KeyName = _lc[I_PROP_TR_SCORE_CON]) or
4532 (KeyName = _lc[I_PROP_TR_SCORE_MSG]) or
4533 (KeyName = _lc[I_PROP_TR_HEALTH_MAX]) or
4534 (KeyName = _lc[I_PROP_TR_SHOT_SOUND]) or
4535 (KeyName = _lc[I_PROP_TR_EFFECT_CENTER]) then
4536 begin
4537 Values.Add(BoolNames[True]);
4538 Values.Add(BoolNames[False]);
4539 end;
4540 end;
4541 end;
4543 procedure TMainForm.bApplyPropertyClick(Sender: TObject);
4544 var
4545 _id, a, r, c: Integer;
4546 s: String;
4547 res: Boolean;
4548 NoTextureID: DWORD;
4549 NW, NH: Word;
4550 begin
4551 NoTextureID := 0;
4552 NW := 0;
4553 NH := 0;
4555 if SelectedObjectCount() <> 1 then
4556 Exit;
4557 if not SelectedObjects[GetFirstSelected()].Live then
4558 Exit;
4560 try
4561 if not CheckProperty() then
4562 Exit;
4563 except
4564 Exit;
4565 end;
4567 _id := GetFirstSelected();
4569 r := vleObjectProperty.Row;
4570 c := vleObjectProperty.Col;
4572 case SelectedObjects[_id].ObjectType of
4573 OBJECT_PANEL:
4574 begin
4575 with gPanels[SelectedObjects[_id].ID] do
4576 begin
4577 X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
4578 Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
4579 Width := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_WIDTH]]));
4580 Height := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_HEIGHT]]));
4582 PanelType := GetPanelType(vleObjectProperty.Values[_lc[I_PROP_PANEL_TYPE]]);
4584 // Сброс ссылки на триггеры смены текстуры:
4585 if not WordBool(PanelType and (PANEL_WALL or PANEL_FORE or PANEL_BACK)) then
4586 if gTriggers <> nil then
4587 for a := 0 to High(gTriggers) do
4588 begin
4589 if (gTriggers[a].TriggerType <> 0) and
4590 (gTriggers[a].TexturePanel = Integer(SelectedObjects[_id].ID)) then
4591 gTriggers[a].TexturePanel := -1;
4592 if (gTriggers[a].TriggerType = TRIGGER_SHOT) and
4593 (gTriggers[a].Data.ShotPanelID = Integer(SelectedObjects[_id].ID)) then
4594 gTriggers[a].Data.ShotPanelID := -1;
4595 end;
4597 // Сброс ссылки на триггеры лифта:
4598 if not WordBool(PanelType and (PANEL_LIFTUP or PANEL_LIFTDOWN or PANEL_LIFTLEFT or PANEL_LIFTRIGHT)) then
4599 if gTriggers <> nil then
4600 for a := 0 to High(gTriggers) do
4601 if (gTriggers[a].TriggerType in [TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT]) and
4602 (gTriggers[a].Data.PanelID = Integer(SelectedObjects[_id].ID)) then
4603 gTriggers[a].Data.PanelID := -1;
4605 // Сброс ссылки на триггеры двери:
4606 if not WordBool(PanelType and (PANEL_OPENDOOR or PANEL_CLOSEDOOR)) then
4607 if gTriggers <> nil then
4608 for a := 0 to High(gTriggers) do
4609 if (gTriggers[a].TriggerType in [TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
4610 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP]) and
4611 (gTriggers[a].Data.PanelID = Integer(SelectedObjects[_id].ID)) then
4612 gTriggers[a].Data.PanelID := -1;
4614 if IsTexturedPanel(PanelType) then
4615 begin // Может быть текстура
4616 if TextureName <> '' then
4617 begin // Была текстура
4618 Alpha := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_PANEL_ALPHA]]));
4619 Blending := NameToBool(vleObjectProperty.Values[_lc[I_PROP_PANEL_BLEND]]);
4620 end
4621 else // Не было
4622 begin
4623 Alpha := 0;
4624 Blending := False;
4625 end;
4627 // Новая текстура:
4628 TextureName := vleObjectProperty.Values[_lc[I_PROP_PANEL_TEX]];
4630 if TextureName <> '' then
4631 begin // Есть текстура
4632 // Обычная текстура:
4633 if not IsSpecialTexture(TextureName) then
4634 begin
4635 g_GetTextureSizeByName(TextureName,
4636 TextureWidth, TextureHeight);
4638 // Проверка кратности размеров панели:
4639 res := True;
4640 if TextureWidth <> 0 then
4641 if gPanels[SelectedObjects[_id].ID].Width mod TextureWidth <> 0 then
4642 begin
4643 ErrorMessageBox(Format(_lc[I_MSG_WRONG_TEXWIDTH],
4644 [TextureWidth]));
4645 Res := False;
4646 end;
4647 if Res and (TextureHeight <> 0) then
4648 if gPanels[SelectedObjects[_id].ID].Height mod TextureHeight <> 0 then
4649 begin
4650 ErrorMessageBox(Format(_lc[I_MSG_WRONG_TEXHEIGHT],
4651 [TextureHeight]));
4652 Res := False;
4653 end;
4655 if Res then
4656 begin
4657 if not g_GetTexture(TextureName, TextureID) then
4658 // Не удалось загрузить текстуру, рисуем NOTEXTURE
4659 if g_GetTexture('NOTEXTURE', NoTextureID) then
4660 begin
4661 TextureID := TEXTURE_SPECIAL_NOTEXTURE;
4662 g_GetTextureSizeByID(NoTextureID, NW, NH);
4663 TextureWidth := NW;
4664 TextureHeight := NH;
4665 end else
4666 begin
4667 TextureID := TEXTURE_SPECIAL_NONE;
4668 TextureWidth := 1;
4669 TextureHeight := 1;
4670 end;
4671 end
4672 else
4673 begin
4674 TextureName := '';
4675 TextureWidth := 1;
4676 TextureHeight := 1;
4677 TextureID := TEXTURE_SPECIAL_NONE;
4678 end;
4679 end
4680 else // Спец.текстура
4681 begin
4682 TextureHeight := 1;
4683 TextureWidth := 1;
4684 TextureID := SpecialTextureID(TextureName);
4685 end;
4686 end
4687 else // Нет текстуры
4688 begin
4689 TextureWidth := 1;
4690 TextureHeight := 1;
4691 TextureID := TEXTURE_SPECIAL_NONE;
4692 end;
4693 end
4694 else // Не может быть текстуры
4695 begin
4696 Alpha := 0;
4697 Blending := False;
4698 TextureName := '';
4699 TextureWidth := 1;
4700 TextureHeight := 1;
4701 TextureID := TEXTURE_SPECIAL_NONE;
4702 end;
4703 end;
4704 end;
4706 OBJECT_ITEM:
4707 begin
4708 with gItems[SelectedObjects[_id].ID] do
4709 begin
4710 X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
4711 Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
4712 OnlyDM := NameToBool(vleObjectProperty.Values[_lc[I_PROP_DM_ONLY]]);
4713 Fall := NameToBool(vleObjectProperty.Values[_lc[I_PROP_ITEM_FALLS]]);
4714 end;
4715 end;
4717 OBJECT_MONSTER:
4718 begin
4719 with gMonsters[SelectedObjects[_id].ID] do
4720 begin
4721 X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
4722 Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
4723 Direction := NameToDir(vleObjectProperty.Values[_lc[I_PROP_DIRECTION]]);
4724 end;
4725 end;
4727 OBJECT_AREA:
4728 begin
4729 with gAreas[SelectedObjects[_id].ID] do
4730 begin
4731 X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
4732 Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
4733 Direction := NameToDir(vleObjectProperty.Values[_lc[I_PROP_DIRECTION]]);
4734 end;
4735 end;
4737 OBJECT_TRIGGER:
4738 begin
4739 with gTriggers[SelectedObjects[_id].ID] do
4740 begin
4741 X := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_X]]));
4742 Y := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_Y]]));
4743 Width := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_WIDTH]]));
4744 Height := StrToInt(Trim(vleObjectProperty.Values[_lc[I_PROP_HEIGHT]]));
4745 Enabled := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_ENABLED]]);
4746 ActivateType := StrToActivate(vleObjectProperty.Values[_lc[I_PROP_TR_ACTIVATION]]);
4747 Key := StrToKey(vleObjectProperty.Values[_lc[I_PROP_TR_KEYS]]);
4749 case TriggerType of
4750 TRIGGER_EXIT:
4751 begin
4752 s := utf2win(vleObjectProperty.Values[_lc[I_PROP_TR_NEXT_MAP]]);
4753 FillByte(Data.MapName[0], 16, 0);
4754 if s <> '' then
4755 Move(s[1], Data.MapName[0], Min(Length(s), 16));
4756 end;
4758 TRIGGER_TEXTURE:
4759 begin
4760 Data.ActivateOnce := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_TEXTURE_ONCE]]);
4761 Data.AnimOnce := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_TEXTURE_ANIM_ONCE]]);
4762 end;
4764 TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF:
4765 begin
4766 Data.Wait := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EX_DELAY]], 0), 65535);
4767 Data.Count := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EX_COUNT]], 0), 65535);
4768 if Data.Count < 1 then
4769 Data.Count := 1;
4770 if TriggerType = TRIGGER_PRESS then
4771 Data.ExtRandom := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_EX_RANDOM]]);
4772 end;
4774 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR, TRIGGER_DOOR5,
4775 TRIGGER_CLOSETRAP, TRIGGER_TRAP, TRIGGER_LIFTUP, TRIGGER_LIFTDOWN,
4776 TRIGGER_LIFT:
4777 begin
4778 Data.NoSound := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SILENT]]);
4779 Data.d2d_doors := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_D2D]]);
4780 end;
4782 TRIGGER_TELEPORT:
4783 begin
4784 Data.d2d_teleport := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_D2D]]);
4785 Data.silent_teleport := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_TELEPORT_SILENT]]);
4786 Data.TlpDir := NameToDirAdv(vleObjectProperty.Values[_lc[I_PROP_TR_TELEPORT_DIR]]);
4787 end;
4789 TRIGGER_SOUND:
4790 begin
4791 s := utf2win(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_NAME]]);
4792 FillByte(Data.SoundName[0], 64, 0);
4793 if s <> '' then
4794 Move(s[1], Data.SoundName[0], Min(Length(s), 64));
4796 Data.Volume := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_VOLUME]], 0), 255);
4797 Data.Pan := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_PAN]], 0), 255);
4798 Data.PlayCount := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_COUNT]], 0), 255);
4799 Data.Local := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_LOCAL]]);
4800 Data.SoundSwitch := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_SWITCH]]);
4801 end;
4803 TRIGGER_SPAWNMONSTER:
4804 begin
4805 Data.MonType := StrToMonster(vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_TYPE]]);
4806 Data.MonDir := Byte(NameToDir(vleObjectProperty.Values[_lc[I_PROP_DIRECTION]]));
4807 Data.MonHealth := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_HEALTH]], 0), 1000000);
4808 if Data.MonHealth < 0 then
4809 Data.MonHealth := 0;
4810 Data.MonActive := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_ACTIVE]]);
4811 Data.MonCount := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_COUNT]], 0), 64);
4812 if Data.MonCount < 1 then
4813 Data.MonCount := 1;
4814 Data.MonEffect := StrToEffect(vleObjectProperty.Values[_lc[I_PROP_TR_FX_TYPE]]);
4815 Data.MonMax := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SPAWN_MAX]], 0), 65535);
4816 Data.MonDelay := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SPAWN_DELAY]], 0), 65535);
4817 Data.MonBehav := 0;
4818 if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_1] then
4819 Data.MonBehav := 1;
4820 if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_2] then
4821 Data.MonBehav := 2;
4822 if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_3] then
4823 Data.MonBehav := 3;
4824 if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_4] then
4825 Data.MonBehav := 4;
4826 if vleObjectProperty.Values[_lc[I_PROP_TR_MONSTER_BEHAVIOUR]] = _lc[I_PROP_TR_MONSTER_BEHAVIOUR_5] then
4827 Data.MonBehav := 5;
4828 end;
4830 TRIGGER_SPAWNITEM:
4831 begin
4832 Data.ItemType := StrToItem(vleObjectProperty.Values[_lc[I_PROP_TR_ITEM_TYPE]]);
4833 Data.ItemOnlyDM := NameToBool(vleObjectProperty.Values[_lc[I_PROP_DM_ONLY]]);
4834 Data.ItemFalls := NameToBool(vleObjectProperty.Values[_lc[I_PROP_ITEM_FALLS]]);
4835 Data.ItemCount := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_COUNT]], 0), 64);
4836 if Data.ItemCount < 1 then
4837 Data.ItemCount := 1;
4838 Data.ItemEffect := StrToEffect(vleObjectProperty.Values[_lc[I_PROP_TR_FX_TYPE]]);
4839 Data.ItemMax := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SPAWN_MAX]], 0), 65535);
4840 Data.ItemDelay := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SPAWN_DELAY]], 0), 65535);
4841 end;
4843 TRIGGER_MUSIC:
4844 begin
4845 s := utf2win(vleObjectProperty.Values[_lc[I_PROP_TR_MUSIC_NAME]]);
4846 FillByte(Data.MusicName[0], 64, 0);
4847 if s <> '' then
4848 Move(s[1], Data.MusicName[0], Min(Length(s), 64));
4850 if vleObjectProperty.Values[_lc[I_PROP_TR_MUSIC_ACT]] = _lc[I_PROP_TR_MUSIC_ON] then
4851 Data.MusicAction := 1
4852 else
4853 Data.MusicAction := 2;
4854 end;
4856 TRIGGER_PUSH:
4857 begin
4858 Data.PushAngle := Min(
4859 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_PUSH_ANGLE]], 0), 360);
4860 Data.PushForce := Min(
4861 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_PUSH_FORCE]], 0), 255);
4862 Data.ResetVel := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_PUSH_RESET]]);
4863 end;
4865 TRIGGER_SCORE:
4866 begin
4867 Data.ScoreAction := 0;
4868 if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_ACT]] = _lc[I_PROP_TR_SCORE_ACT_1] then
4869 Data.ScoreAction := 1
4870 else if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_ACT]] = _lc[I_PROP_TR_SCORE_ACT_2] then
4871 Data.ScoreAction := 2
4872 else if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_ACT]] = _lc[I_PROP_TR_SCORE_ACT_3] then
4873 Data.ScoreAction := 3;
4874 Data.ScoreCount := Min(Max(
4875 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_COUNT]], 0), 0), 255);
4876 Data.ScoreTeam := 0;
4877 if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_TEAM]] = _lc[I_PROP_TR_SCORE_TEAM_1] then
4878 Data.ScoreTeam := 1
4879 else if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_TEAM]] = _lc[I_PROP_TR_SCORE_TEAM_2] then
4880 Data.ScoreTeam := 2
4881 else if vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_TEAM]] = _lc[I_PROP_TR_SCORE_TEAM_3] then
4882 Data.ScoreTeam := 3;
4883 Data.ScoreCon := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_CON]]);
4884 Data.ScoreMsg := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SCORE_MSG]]);
4885 end;
4887 TRIGGER_MESSAGE:
4888 begin
4889 Data.MessageKind := 0;
4890 if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_KIND]] = _lc[I_PROP_TR_MESSAGE_KIND_1] then
4891 Data.MessageKind := 1;
4893 Data.MessageSendTo := 0;
4894 if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_1] then
4895 Data.MessageSendTo := 1
4896 else if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_2] then
4897 Data.MessageSendTo := 2
4898 else if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_3] then
4899 Data.MessageSendTo := 3
4900 else if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_4] then
4901 Data.MessageSendTo := 4
4902 else if vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TO]] = _lc[I_PROP_TR_MESSAGE_TO_5] then
4903 Data.MessageSendTo := 5;
4905 s := utf2win(vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TEXT]]);
4906 FillByte(Data.MessageText[0], 100, 0);
4907 if s <> '' then
4908 Move(s[1], Data.MessageText[0], Min(Length(s), 100));
4910 Data.MessageTime := Min(Max(
4911 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TIME]], 0), 0), 65535);
4912 end;
4914 TRIGGER_DAMAGE:
4915 begin
4916 Data.DamageValue := Min(Max(
4917 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_DAMAGE_VALUE]], 0), 0), 65535);
4918 Data.DamageInterval := Min(Max(
4919 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_INTERVAL]], 0), 0), 65535);
4920 end;
4922 TRIGGER_HEALTH:
4923 begin
4924 Data.HealValue := Min(Max(
4925 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_HEALTH]], 0), 0), 65535);
4926 Data.HealInterval := Min(Max(
4927 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_INTERVAL]], 0), 0), 65535);
4928 Data.HealMax := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_HEALTH_MAX]]);
4929 Data.HealSilent := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SILENT]]);
4930 end;
4932 TRIGGER_SHOT:
4933 begin
4934 Data.ShotType := StrToShot(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TYPE]]);
4935 Data.ShotSound := NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_SOUND]]);
4936 Data.ShotTarget := 0;
4937 if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_1] then
4938 Data.ShotTarget := 1
4939 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_2] then
4940 Data.ShotTarget := 2
4941 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_3] then
4942 Data.ShotTarget := 3
4943 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_4] then
4944 Data.ShotTarget := 4
4945 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_5] then
4946 Data.ShotTarget := 5
4947 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_TO]] = _lc[I_PROP_TR_SHOT_TO_6] then
4948 Data.ShotTarget := 6;
4949 Data.ShotIntSight := Min(Max(
4950 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_SIGHT]], 0), 0), 65535);
4951 Data.ShotAim := 0;
4952 if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_AIM]] = _lc[I_PROP_TR_SHOT_AIM_1] then
4953 Data.ShotAim := 1
4954 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_AIM]] = _lc[I_PROP_TR_SHOT_AIM_2] then
4955 Data.ShotAim := 2
4956 else if vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_AIM]] = _lc[I_PROP_TR_SHOT_AIM_3] then
4957 Data.ShotAim := 3;
4958 Data.ShotAngle := Min(
4959 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_ANGLE]], 0), 360);
4960 Data.ShotWait := Min(Max(
4961 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EX_DELAY]], 0), 0), 65535);
4962 Data.ShotAccuracy := Min(Max(
4963 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_ACC]], 0), 0), 65535);
4964 Data.ShotAmmo := Min(Max(
4965 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_AMMO]], 0), 0), 65535);
4966 Data.ShotIntReload := Min(Max(
4967 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SHOT_RELOAD]], 0), 0), 65535);
4968 end;
4970 TRIGGER_EFFECT:
4971 begin
4972 Data.FXCount := Min(Max(
4973 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_COUNT]], 0), 0), 255);
4974 if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_TYPE]] = _lc[I_PROP_TR_EFFECT_PARTICLE] then
4975 begin
4976 Data.FXType := TRIGGER_EFFECT_PARTICLE;
4977 Data.FXSubType := TRIGGER_EFFECT_SLIQUID;
4978 if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_SLIQUID] then
4979 Data.FXSubType := TRIGGER_EFFECT_SLIQUID
4980 else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_LLIQUID] then
4981 Data.FXSubType := TRIGGER_EFFECT_LLIQUID
4982 else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_DLIQUID] then
4983 Data.FXSubType := TRIGGER_EFFECT_DLIQUID
4984 else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_BLOOD] then
4985 Data.FXSubType := TRIGGER_EFFECT_BLOOD
4986 else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_SPARK] then
4987 Data.FXSubType := TRIGGER_EFFECT_SPARK
4988 else if vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]] = _lc[I_PROP_TR_EFFECT_BUBBLE] then
4989 Data.FXSubType := TRIGGER_EFFECT_BUBBLE;
4990 end else
4991 begin
4992 Data.FXType := TRIGGER_EFFECT_ANIMATION;
4993 Data.FXSubType := StrToEffect(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SUBTYPE]]);
4994 end;
4995 a := Min(Max(
4996 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_COLOR]], 0), 0), $FFFFFF);
4997 Data.FXColorR := a and $FF;
4998 Data.FXColorG := (a shr 8) and $FF;
4999 Data.FXColorB := (a shr 16) and $FF;
5000 if NameToBool(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_CENTER]]) then
5001 Data.FXPos := 0
5002 else
5003 Data.FXPos := 1;
5004 Data.FXWait := Min(Max(
5005 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EX_DELAY]], 0), 0), 65535);
5006 Data.FXVelX := Min(Max(
5007 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_VELX]], 0), -128), 127);
5008 Data.FXVelY := Min(Max(
5009 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_VELY]], 0), -128), 127);
5010 Data.FXSpreadL := Min(Max(
5011 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SPL]], 0), 0), 255);
5012 Data.FXSpreadR := Min(Max(
5013 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SPR]], 0), 0), 255);
5014 Data.FXSpreadU := Min(Max(
5015 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SPU]], 0), 0), 255);
5016 Data.FXSpreadD := Min(Max(
5017 StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_EFFECT_SPD]], 0), 0), 255);
5018 end;
5019 end;
5020 end;
5021 end;
5022 end;
5024 FillProperty();
5026 vleObjectProperty.Row := r;
5027 vleObjectProperty.Col := c;
5028 end;
5030 procedure TMainForm.bbRemoveTextureClick(Sender: TObject);
5031 var
5032 a, i: Integer;
5033 begin
5034 i := lbTextureList.ItemIndex;
5035 if i = -1 then
5036 Exit;
5038 if MessageBox(0, PChar(Format(_lc[I_MSG_DEL_TEXTURE_PROMT],
5039 [SelectedTexture()])),
5040 PChar(_lc[I_MSG_DEL_TEXTURE]),
5041 MB_ICONQUESTION or MB_YESNO or
5042 MB_DEFBUTTON1) <> idYes then
5043 Exit;
5045 if gPanels <> nil then
5046 for a := 0 to High(gPanels) do
5047 if (gPanels[a].PanelType <> 0) and
5048 (gPanels[a].TextureName = SelectedTexture()) then
5049 begin
5050 ErrorMessageBox(_lc[I_MSG_DEL_TEXTURE_CANT]);
5051 Exit;
5052 end;
5054 g_DeleteTexture(SelectedTexture());
5055 i := slInvalidTextures.IndexOf(lbTextureList.Items[i]);
5056 if i > -1 then
5057 slInvalidTextures.Delete(i);
5058 if lbTextureList.ItemIndex > -1 then
5059 lbTextureList.Items.Delete(lbTextureList.ItemIndex)
5060 end;
5062 procedure TMainForm.aNewMapExecute(Sender: TObject);
5063 begin
5064 if (MessageBox(0, PChar(_lc[I_MSG_CLEAR_MAP_PROMT]),
5065 PChar(_lc[I_MSG_CLEAR_MAP]),
5066 MB_ICONQUESTION or MB_YESNO or
5067 MB_DEFBUTTON1) = mrYes) then
5068 FullClear();
5069 end;
5071 procedure TMainForm.aUndoExecute(Sender: TObject);
5072 var
5073 a: Integer;
5074 begin
5075 if UndoBuffer = nil then
5076 Exit;
5077 if UndoBuffer[High(UndoBuffer)] = nil then
5078 Exit;
5080 for a := 0 to High(UndoBuffer[High(UndoBuffer)]) do
5081 with UndoBuffer[High(UndoBuffer)][a] do
5082 begin
5083 case UndoType of
5084 UNDO_DELETE_PANEL:
5085 begin
5086 AddPanel(Panel^);
5087 Panel := nil;
5088 end;
5089 UNDO_DELETE_ITEM: AddItem(Item);
5090 UNDO_DELETE_AREA: AddArea(Area);
5091 UNDO_DELETE_MONSTER: AddMonster(Monster);
5092 UNDO_DELETE_TRIGGER: AddTrigger(Trigger);
5093 UNDO_ADD_PANEL: RemoveObject(AddID, OBJECT_PANEL);
5094 UNDO_ADD_ITEM: RemoveObject(AddID, OBJECT_ITEM);
5095 UNDO_ADD_AREA: RemoveObject(AddID, OBJECT_AREA);
5096 UNDO_ADD_MONSTER: RemoveObject(AddID, OBJECT_MONSTER);
5097 UNDO_ADD_TRIGGER: RemoveObject(AddID, OBJECT_TRIGGER);
5098 end;
5099 end;
5101 SetLength(UndoBuffer, Length(UndoBuffer)-1);
5103 RemoveSelectFromObjects();
5105 miUndo.Enabled := UndoBuffer <> nil;
5106 end;
5109 procedure TMainForm.aCopyObjectExecute(Sender: TObject);
5110 var
5111 a, b: Integer;
5112 CopyBuffer: TCopyRecArray;
5113 str: String;
5114 ok: Boolean;
5116 function CB_Compare(I1, I2: TCopyRec): Integer;
5117 begin
5118 Result := Integer(I1.ObjectType) - Integer(I2.ObjectType);
5120 if Result = 0 then // Одного типа
5121 Result := Integer(I1.ID) - Integer(I2.ID);
5122 end;
5124 procedure QuickSortCopyBuffer(L, R: Integer);
5125 var
5126 I, J: Integer;
5127 P, T: TCopyRec;
5128 begin
5129 repeat
5130 I := L;
5131 J := R;
5132 P := CopyBuffer[(L + R) shr 1];
5134 repeat
5135 while CB_Compare(CopyBuffer[I], P) < 0 do
5136 Inc(I);
5137 while CB_Compare(CopyBuffer[J], P) > 0 do
5138 Dec(J);
5140 if I <= J then
5141 begin
5142 T := CopyBuffer[I];
5143 CopyBuffer[I] := CopyBuffer[J];
5144 CopyBuffer[J] := T;
5145 Inc(I);
5146 Dec(J);
5147 end;
5148 until I > J;
5150 if L < J then
5151 QuickSortCopyBuffer(L, J);
5153 L := I;
5154 until I >= R;
5155 end;
5157 begin
5158 if SelectedObjects = nil then
5159 Exit;
5161 b := -1;
5162 CopyBuffer := nil;
5164 // Копируем объекты:
5165 for a := 0 to High(SelectedObjects) do
5166 if SelectedObjects[a].Live then
5167 with SelectedObjects[a] do
5168 begin
5169 SetLength(CopyBuffer, Length(CopyBuffer)+1);
5170 b := High(CopyBuffer);
5171 CopyBuffer[b].ID := ID;
5172 CopyBuffer[b].Panel := nil;
5174 case ObjectType of
5175 OBJECT_PANEL:
5176 begin
5177 CopyBuffer[b].ObjectType := OBJECT_PANEL;
5178 New(CopyBuffer[b].Panel);
5179 CopyBuffer[b].Panel^ := gPanels[ID];
5180 end;
5182 OBJECT_ITEM:
5183 begin
5184 CopyBuffer[b].ObjectType := OBJECT_ITEM;
5185 CopyBuffer[b].Item := gItems[ID];
5186 end;
5188 OBJECT_MONSTER:
5189 begin
5190 CopyBuffer[b].ObjectType := OBJECT_MONSTER;
5191 CopyBuffer[b].Monster := gMonsters[ID];
5192 end;
5194 OBJECT_AREA:
5195 begin
5196 CopyBuffer[b].ObjectType := OBJECT_AREA;
5197 CopyBuffer[b].Area := gAreas[ID];
5198 end;
5200 OBJECT_TRIGGER:
5201 begin
5202 CopyBuffer[b].ObjectType := OBJECT_TRIGGER;
5203 CopyBuffer[b].Trigger := gTriggers[ID];
5204 end;
5205 end;
5206 end;
5208 // Сортировка по ID:
5209 if CopyBuffer <> nil then
5210 begin
5211 QuickSortCopyBuffer(0, b);
5212 end;
5214 // Пестановка ссылок триггеров:
5215 for a := 0 to Length(CopyBuffer)-1 do
5216 if CopyBuffer[a].ObjectType = OBJECT_TRIGGER then
5217 begin
5218 case CopyBuffer[a].Trigger.TriggerType of
5219 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
5220 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP,
5221 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
5222 if CopyBuffer[a].Trigger.Data.PanelID <> -1 then
5223 begin
5224 ok := False;
5226 for b := 0 to Length(CopyBuffer)-1 do
5227 if (CopyBuffer[b].ObjectType = OBJECT_PANEL) and
5228 (Integer(CopyBuffer[b].ID) = CopyBuffer[a].Trigger.Data.PanelID) then
5229 begin
5230 CopyBuffer[a].Trigger.Data.PanelID := b;
5231 ok := True;
5232 Break;
5233 end;
5235 // Этих панелей нет среди копируемых:
5236 if not ok then
5237 CopyBuffer[a].Trigger.Data.PanelID := -1;
5238 end;
5240 TRIGGER_PRESS, TRIGGER_ON,
5241 TRIGGER_OFF, TRIGGER_ONOFF:
5242 if CopyBuffer[a].Trigger.Data.MonsterID <> 0 then
5243 begin
5244 ok := False;
5246 for b := 0 to Length(CopyBuffer)-1 do
5247 if (CopyBuffer[b].ObjectType = OBJECT_MONSTER) and
5248 (Integer(CopyBuffer[b].ID) = CopyBuffer[a].Trigger.Data.MonsterID-1) then
5249 begin
5250 CopyBuffer[a].Trigger.Data.MonsterID := b+1;
5251 ok := True;
5252 Break;
5253 end;
5255 // Этих монстров нет среди копируемых:
5256 if not ok then
5257 CopyBuffer[a].Trigger.Data.MonsterID := 0;
5258 end;
5260 TRIGGER_SHOT:
5261 if CopyBuffer[a].Trigger.Data.ShotPanelID <> -1 then
5262 begin
5263 ok := False;
5265 for b := 0 to Length(CopyBuffer)-1 do
5266 if (CopyBuffer[b].ObjectType = OBJECT_PANEL) and
5267 (Integer(CopyBuffer[b].ID) = CopyBuffer[a].Trigger.Data.ShotPanelID) then
5268 begin
5269 CopyBuffer[a].Trigger.Data.ShotPanelID := b;
5270 ok := True;
5271 Break;
5272 end;
5274 // Этих панелей нет среди копируемых:
5275 if not ok then
5276 CopyBuffer[a].Trigger.Data.ShotPanelID := -1;
5277 end;
5278 end;
5280 if CopyBuffer[a].Trigger.TexturePanel <> -1 then
5281 begin
5282 ok := False;
5284 for b := 0 to Length(CopyBuffer)-1 do
5285 if (CopyBuffer[b].ObjectType = OBJECT_PANEL) and
5286 (Integer(CopyBuffer[b].ID) = CopyBuffer[a].Trigger.TexturePanel) then
5287 begin
5288 CopyBuffer[a].Trigger.TexturePanel := b;
5289 ok := True;
5290 Break;
5291 end;
5293 // Этих панелей нет среди копируемых:
5294 if not ok then
5295 CopyBuffer[a].Trigger.TexturePanel := -1;
5296 end;
5297 end;
5299 // В буфер обмена:
5300 str := CopyBufferToString(CopyBuffer);
5301 ClipBoard.AsText := str;
5303 for a := 0 to Length(CopyBuffer)-1 do
5304 if (CopyBuffer[a].ObjectType = OBJECT_PANEL) and
5305 (CopyBuffer[a].Panel <> nil) then
5306 Dispose(CopyBuffer[a].Panel);
5308 CopyBuffer := nil;
5309 end;
5311 procedure TMainForm.aPasteObjectExecute(Sender: TObject);
5312 var
5313 a, h: Integer;
5314 CopyBuffer: TCopyRecArray;
5315 res: Boolean;
5316 swad, ssec, sres: String;
5317 begin
5318 CopyBuffer := nil;
5320 StringToCopyBuffer(ClipBoard.AsText, CopyBuffer);
5322 if CopyBuffer = nil then
5323 Exit;
5325 RemoveSelectFromObjects();
5327 h := High(CopyBuffer);
5328 for a := 0 to h do
5329 with CopyBuffer[a] do
5330 begin
5331 case ObjectType of
5332 OBJECT_PANEL:
5333 if Panel <> nil then
5334 begin
5335 Panel^.X := Panel^.X + 16;
5336 Panel^.Y := Panel^.Y + 16;
5338 Panel^.TextureID := TEXTURE_SPECIAL_NONE;
5339 Panel^.TextureWidth := 1;
5340 Panel^.TextureHeight := 1;
5342 if (Panel^.PanelType = PANEL_LIFTUP) or
5343 (Panel^.PanelType = PANEL_LIFTDOWN) or
5344 (Panel^.PanelType = PANEL_LIFTLEFT) or
5345 (Panel^.PanelType = PANEL_LIFTRIGHT) or
5346 (Panel^.PanelType = PANEL_BLOCKMON) or
5347 (Panel^.TextureName = '') then
5348 begin // Нет или не может быть текстуры:
5349 end
5350 else // Есть текстура:
5351 begin
5352 // Обычная текстура:
5353 if not IsSpecialTexture(Panel^.TextureName) then
5354 begin
5355 res := g_GetTexture(Panel^.TextureName, Panel^.TextureID);
5357 if not res then
5358 begin
5359 g_ProcessResourceStr(Panel^.TextureName, swad, ssec, sres);
5360 AddTexture(swad, ssec, sres, True);
5361 res := g_GetTexture(Panel^.TextureName, Panel^.TextureID);
5362 end;
5364 if res then
5365 g_GetTextureSizeByName(Panel^.TextureName,
5366 Panel^.TextureWidth, Panel^.TextureHeight)
5367 else
5368 Panel^.TextureName := '';
5369 end
5370 else // Спец.текстура:
5371 begin
5372 Panel^.TextureID := SpecialTextureID(Panel^.TextureName);
5373 with MainForm.lbTextureList.Items do
5374 if IndexOf(Panel^.TextureName) = -1 then
5375 Add(Panel^.TextureName);
5376 end;
5377 end;
5379 ID := AddPanel(Panel^);
5380 Dispose(Panel);
5381 Undo_Add(OBJECT_PANEL, ID, a > 0);
5382 SelectObject(OBJECT_PANEL, ID, True);
5383 end;
5385 OBJECT_ITEM:
5386 begin
5387 Item.X := Item.X + 16;
5388 Item.Y := Item.Y + 16;
5390 ID := AddItem(Item);
5391 Undo_Add(OBJECT_ITEM, ID, a > 0);
5392 SelectObject(OBJECT_ITEM, ID, True);
5393 end;
5395 OBJECT_MONSTER:
5396 begin
5397 Monster.X := Monster.X + 16;
5398 Monster.Y := Monster.Y + 16;
5400 ID := AddMonster(Monster);
5401 Undo_Add(OBJECT_MONSTER, ID, a > 0);
5402 SelectObject(OBJECT_MONSTER, ID, True);
5403 end;
5405 OBJECT_AREA:
5406 begin
5407 Area.X := Area.X + 16;
5408 Area.Y := Area.Y + 16;
5410 ID := AddArea(Area);
5411 Undo_Add(OBJECT_AREA, ID, a > 0);
5412 SelectObject(OBJECT_AREA, ID, True);
5413 end;
5415 OBJECT_TRIGGER:
5416 begin
5417 Trigger.X := Trigger.X + 16;
5418 Trigger.Y := Trigger.Y + 16;
5420 ID := AddTrigger(Trigger);
5421 Undo_Add(OBJECT_TRIGGER, ID, a > 0);
5422 SelectObject(OBJECT_TRIGGER, ID, True);
5423 end;
5424 end;
5425 end;
5427 // Переставляем ссылки триггеров:
5428 for a := 0 to High(CopyBuffer) do
5429 if CopyBuffer[a].ObjectType = OBJECT_TRIGGER then
5430 begin
5431 case CopyBuffer[a].Trigger.TriggerType of
5432 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
5433 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP,
5434 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
5435 if CopyBuffer[a].Trigger.Data.PanelID <> -1 then
5436 gTriggers[CopyBuffer[a].ID].Data.PanelID :=
5437 CopyBuffer[CopyBuffer[a].Trigger.Data.PanelID].ID;
5439 TRIGGER_PRESS, TRIGGER_ON,
5440 TRIGGER_OFF, TRIGGER_ONOFF:
5441 if CopyBuffer[a].Trigger.Data.MonsterID <> 0 then
5442 gTriggers[CopyBuffer[a].ID].Data.MonsterID :=
5443 CopyBuffer[CopyBuffer[a].Trigger.Data.MonsterID-1].ID+1;
5445 TRIGGER_SHOT:
5446 if CopyBuffer[a].Trigger.Data.ShotPanelID <> -1 then
5447 gTriggers[CopyBuffer[a].ID].Data.ShotPanelID :=
5448 CopyBuffer[CopyBuffer[a].Trigger.Data.ShotPanelID].ID;
5449 end;
5451 if CopyBuffer[a].Trigger.TexturePanel <> -1 then
5452 gTriggers[CopyBuffer[a].ID].TexturePanel :=
5453 CopyBuffer[CopyBuffer[a].Trigger.TexturePanel].ID;
5454 end;
5456 CopyBuffer := nil;
5458 if h = 0 then
5459 FillProperty();
5460 end;
5462 procedure TMainForm.aCutObjectExecute(Sender: TObject);
5463 begin
5464 miCopy.Click();
5465 DeleteSelectedObjects();
5466 end;
5468 procedure TMainForm.vleObjectPropertyEditButtonClick(Sender: TObject);
5469 var
5470 Key, FileName: String;
5471 b: Byte;
5472 begin
5473 Key := vleObjectProperty.Keys[vleObjectProperty.Row];
5475 if Key = _lc[I_PROP_PANEL_TYPE] then
5476 begin
5477 with ChooseTypeForm, vleObjectProperty do
5478 begin // Выбор типа панели:
5479 Caption := _lc[I_PROP_PANEL_TYPE];
5480 lbTypeSelect.Items.Clear();
5482 for b := 0 to High(PANELNAMES) do
5483 begin
5484 lbTypeSelect.Items.Add(PANELNAMES[b]);
5485 if Values[Key] = PANELNAMES[b] then
5486 lbTypeSelect.ItemIndex := b;
5487 end;
5489 if ShowModal() = mrOK then
5490 begin
5491 b := lbTypeSelect.ItemIndex;
5492 Values[Key] := PANELNAMES[b];
5493 vleObjectPropertyApply(Sender);
5494 end;
5495 end
5496 end
5497 else if Key = _lc[I_PROP_TR_TELEPORT_TO] then
5498 SelectFlag := SELECTFLAG_TELEPORT
5499 else if Key = _lc[I_PROP_TR_SPAWN_TO] then
5500 SelectFlag := SELECTFLAG_SPAWNPOINT
5501 else if (Key = _lc[I_PROP_TR_DOOR_PANEL]) or
5502 (Key = _lc[I_PROP_TR_TRAP_PANEL]) then
5503 SelectFlag := SELECTFLAG_DOOR
5504 else if Key = _lc[I_PROP_TR_TEXTURE_PANEL] then
5505 begin
5506 DrawPressRect := False;
5507 SelectFlag := SELECTFLAG_TEXTURE;
5508 end
5509 else if Key = _lc[I_PROP_TR_SHOT_PANEL] then
5510 SelectFlag := SELECTFLAG_SHOTPANEL
5511 else if Key = _lc[I_PROP_TR_LIFT_PANEL] then
5512 SelectFlag := SELECTFLAG_LIFT
5513 else if key = _lc[I_PROP_TR_EX_MONSTER] then
5514 SelectFlag := SELECTFLAG_MONSTER
5515 else if Key = _lc[I_PROP_TR_EX_AREA] then
5516 begin
5517 SelectFlag := SELECTFLAG_NONE;
5518 DrawPressRect := True;
5519 end
5520 else if Key = _lc[I_PROP_TR_NEXT_MAP] then
5521 begin // Выбор следующей карты:
5522 g_ProcessResourceStr(OpenedMap, @FileName, nil, nil);
5523 SelectMapForm.GetMaps(FileName);
5525 if SelectMapForm.ShowModal() = mrOK then
5526 begin
5527 vleObjectProperty.Values[Key] := SelectMapForm.lbMapList.Items[SelectMapForm.lbMapList.ItemIndex];
5528 vleObjectPropertyApply(Sender);
5529 end;
5530 end
5531 else if (Key = _lc[I_PROP_TR_SOUND_NAME]) or
5532 (Key = _lc[I_PROP_TR_MUSIC_NAME]) then
5533 begin // Выбор файла звука/музыки:
5534 AddSoundForm.OKFunction := nil;
5535 AddSoundForm.lbResourcesList.MultiSelect := False;
5536 AddSoundForm.SetResource := vleObjectProperty.Values[Key];
5538 if (AddSoundForm.ShowModal() = mrOk) then
5539 begin
5540 vleObjectProperty.Values[Key] := AddSoundForm.ResourceName;
5541 vleObjectPropertyApply(Sender);
5542 end;
5543 end
5544 else if Key = _lc[I_PROP_TR_ACTIVATION] then
5545 with ActivationTypeForm, vleObjectProperty do
5546 begin // Выбор типов активации:
5547 cbPlayerCollide.Checked := Pos('PC', Values[Key]) > 0;
5548 cbMonsterCollide.Checked := Pos('MC', Values[Key]) > 0;
5549 cbPlayerPress.Checked := Pos('PP', Values[Key]) > 0;
5550 cbMonsterPress.Checked := Pos('MP', Values[Key]) > 0;
5551 cbShot.Checked := Pos('SH', Values[Key]) > 0;
5552 cbNoMonster.Checked := Pos('NM', Values[Key]) > 0;
5554 if ShowModal() = mrOK then
5555 begin
5556 b := 0;
5557 if cbPlayerCollide.Checked then
5558 b := ACTIVATE_PLAYERCOLLIDE;
5559 if cbMonsterCollide.Checked then
5560 b := b or ACTIVATE_MONSTERCOLLIDE;
5561 if cbPlayerPress.Checked then
5562 b := b or ACTIVATE_PLAYERPRESS;
5563 if cbMonsterPress.Checked then
5564 b := b or ACTIVATE_MONSTERPRESS;
5565 if cbShot.Checked then
5566 b := b or ACTIVATE_SHOT;
5567 if cbNoMonster.Checked then
5568 b := b or ACTIVATE_NOMONSTER;
5570 Values[Key] := ActivateToStr(b);
5571 vleObjectPropertyApply(Sender);
5572 end;
5573 end
5574 else if Key = _lc[I_PROP_TR_KEYS] then
5575 with KeysForm, vleObjectProperty do
5576 begin // Выбор необходимых ключей:
5577 cbRedKey.Checked := Pos('RK', Values[Key]) > 0;
5578 cbGreenKey.Checked := Pos('GK', Values[Key]) > 0;
5579 cbBlueKey.Checked := Pos('BK', Values[Key]) > 0;
5580 cbRedTeam.Checked := Pos('RT', Values[Key]) > 0;
5581 cbBlueTeam.Checked := Pos('BT', Values[Key]) > 0;
5583 if ShowModal() = mrOK then
5584 begin
5585 b := 0;
5586 if cbRedKey.Checked then
5587 b := KEY_RED;
5588 if cbGreenKey.Checked then
5589 b := b or KEY_GREEN;
5590 if cbBlueKey.Checked then
5591 b := b or KEY_BLUE;
5592 if cbRedTeam.Checked then
5593 b := b or KEY_REDTEAM;
5594 if cbBlueTeam.Checked then
5595 b := b or KEY_BLUETEAM;
5597 Values[Key] := KeyToStr(b);
5598 vleObjectPropertyApply(Sender);
5599 end;
5600 end
5601 else if Key = _lc[I_PROP_TR_FX_TYPE] then
5602 with ChooseTypeForm, vleObjectProperty do
5603 begin // Выбор типа эффекта:
5604 Caption := _lc[I_CAP_FX_TYPE];
5605 lbTypeSelect.Items.Clear();
5607 for b := EFFECT_NONE to EFFECT_FIRE do
5608 lbTypeSelect.Items.Add(EffectToStr(b));
5610 lbTypeSelect.ItemIndex := StrToEffect(Values[Key]);
5612 if ShowModal() = mrOK then
5613 begin
5614 b := lbTypeSelect.ItemIndex;
5615 Values[Key] := EffectToStr(b);
5616 vleObjectPropertyApply(Sender);
5617 end;
5618 end
5619 else if Key = _lc[I_PROP_TR_MONSTER_TYPE] then
5620 with ChooseTypeForm, vleObjectProperty do
5621 begin // Выбор типа монстра:
5622 Caption := _lc[I_CAP_MONSTER_TYPE];
5623 lbTypeSelect.Items.Clear();
5625 for b := MONSTER_DEMON to MONSTER_MAN do
5626 lbTypeSelect.Items.Add(MonsterToStr(b));
5628 lbTypeSelect.ItemIndex := StrToMonster(Values[Key]) - MONSTER_DEMON;
5630 if ShowModal() = mrOK then
5631 begin
5632 b := lbTypeSelect.ItemIndex + MONSTER_DEMON;
5633 Values[Key] := MonsterToStr(b);
5634 vleObjectPropertyApply(Sender);
5635 end;
5636 end
5637 else if Key = _lc[I_PROP_TR_ITEM_TYPE] then
5638 with ChooseTypeForm, vleObjectProperty do
5639 begin // Выбор типа предмета:
5640 Caption := _lc[I_CAP_ITEM_TYPE];
5641 lbTypeSelect.Items.Clear();
5643 for b := ITEM_MEDKIT_SMALL to ITEM_KEY_BLUE do
5644 lbTypeSelect.Items.Add(ItemToStr(b));
5645 lbTypeSelect.Items.Add(ItemToStr(ITEM_BOTTLE));
5646 lbTypeSelect.Items.Add(ItemToStr(ITEM_HELMET));
5647 lbTypeSelect.Items.Add(ItemToStr(ITEM_JETPACK));
5648 lbTypeSelect.Items.Add(ItemToStr(ITEM_INVIS));
5649 lbTypeSelect.Items.Add(ItemToStr(ITEM_WEAPON_FLAMETHROWER));
5650 lbTypeSelect.Items.Add(ItemToStr(ITEM_AMMO_FUELCAN));
5652 b := StrToItem(Values[Key]);
5653 if b >= ITEM_BOTTLE then
5654 b := b - 2;
5655 lbTypeSelect.ItemIndex := b - ITEM_MEDKIT_SMALL;
5657 if ShowModal() = mrOK then
5658 begin
5659 b := lbTypeSelect.ItemIndex + ITEM_MEDKIT_SMALL;
5660 if b >= ITEM_WEAPON_KASTET then
5661 b := b + 2;
5662 Values[Key] := ItemToStr(b);
5663 vleObjectPropertyApply(Sender);
5664 end;
5665 end
5666 else if Key = _lc[I_PROP_TR_SHOT_TYPE] then
5667 with ChooseTypeForm, vleObjectProperty do
5668 begin // Выбор типа предмета:
5669 Caption := _lc[I_PROP_TR_SHOT_TYPE];
5670 lbTypeSelect.Items.Clear();
5672 for b := TRIGGER_SHOT_PISTOL to TRIGGER_SHOT_MAX do
5673 lbTypeSelect.Items.Add(ShotToStr(b));
5675 lbTypeSelect.ItemIndex := StrToShot(Values[Key]);
5677 if ShowModal() = mrOK then
5678 begin
5679 b := lbTypeSelect.ItemIndex;
5680 Values[Key] := ShotToStr(b);
5681 vleObjectPropertyApply(Sender);
5682 end;
5683 end
5684 else if Key = _lc[I_PROP_TR_EFFECT_TYPE] then
5685 with ChooseTypeForm, vleObjectProperty do
5686 begin // Выбор типа эффекта:
5687 Caption := _lc[I_CAP_FX_TYPE];
5688 lbTypeSelect.Items.Clear();
5690 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_PARTICLE]);
5691 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_ANIMATION]);
5692 if Values[Key] = _lc[I_PROP_TR_EFFECT_ANIMATION] then
5693 lbTypeSelect.ItemIndex := 1
5694 else
5695 lbTypeSelect.ItemIndex := 0;
5697 if ShowModal() = mrOK then
5698 begin
5699 b := lbTypeSelect.ItemIndex;
5700 if b = 0 then
5701 Values[Key] := _lc[I_PROP_TR_EFFECT_PARTICLE]
5702 else
5703 Values[Key] := _lc[I_PROP_TR_EFFECT_ANIMATION];
5704 vleObjectPropertyApply(Sender);
5705 end;
5706 end
5707 else if Key = _lc[I_PROP_TR_EFFECT_SUBTYPE] then
5708 with ChooseTypeForm, vleObjectProperty do
5709 begin // Выбор подтипа эффекта:
5710 Caption := _lc[I_CAP_FX_TYPE];
5711 lbTypeSelect.Items.Clear();
5713 if Values[_lc[I_PROP_TR_EFFECT_TYPE]] = _lc[I_PROP_TR_EFFECT_ANIMATION] then
5714 begin
5715 for b := EFFECT_TELEPORT to EFFECT_FIRE do
5716 lbTypeSelect.Items.Add(EffectToStr(b));
5718 lbTypeSelect.ItemIndex := StrToEffect(Values[Key]) - 1;
5719 end else
5720 begin
5721 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_SLIQUID]);
5722 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_LLIQUID]);
5723 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_DLIQUID]);
5724 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_BLOOD]);
5725 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_SPARK]);
5726 lbTypeSelect.Items.Add(_lc[I_PROP_TR_EFFECT_BUBBLE]);
5727 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_SLIQUID;
5728 if Values[Key] = _lc[I_PROP_TR_EFFECT_LLIQUID] then
5729 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_LLIQUID;
5730 if Values[Key] = _lc[I_PROP_TR_EFFECT_DLIQUID] then
5731 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_DLIQUID;
5732 if Values[Key] = _lc[I_PROP_TR_EFFECT_BLOOD] then
5733 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_BLOOD;
5734 if Values[Key] = _lc[I_PROP_TR_EFFECT_SPARK] then
5735 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_SPARK;
5736 if Values[Key] = _lc[I_PROP_TR_EFFECT_BUBBLE] then
5737 lbTypeSelect.ItemIndex := TRIGGER_EFFECT_BUBBLE;
5738 end;
5740 if ShowModal() = mrOK then
5741 begin
5742 b := lbTypeSelect.ItemIndex;
5744 if Values[_lc[I_PROP_TR_EFFECT_TYPE]] = _lc[I_PROP_TR_EFFECT_ANIMATION] then
5745 Values[Key] := EffectToStr(b + 1)
5746 else begin
5747 Values[Key] := _lc[I_PROP_TR_EFFECT_SLIQUID];
5748 if b = TRIGGER_EFFECT_LLIQUID then
5749 Values[Key] := _lc[I_PROP_TR_EFFECT_LLIQUID];
5750 if b = TRIGGER_EFFECT_DLIQUID then
5751 Values[Key] := _lc[I_PROP_TR_EFFECT_DLIQUID];
5752 if b = TRIGGER_EFFECT_BLOOD then
5753 Values[Key] := _lc[I_PROP_TR_EFFECT_BLOOD];
5754 if b = TRIGGER_EFFECT_SPARK then
5755 Values[Key] := _lc[I_PROP_TR_EFFECT_SPARK];
5756 if b = TRIGGER_EFFECT_BUBBLE then
5757 Values[Key] := _lc[I_PROP_TR_EFFECT_BUBBLE];
5758 end;
5760 vleObjectPropertyApply(Sender);
5761 end;
5762 end
5763 else if Key = _lc[I_PROP_TR_EFFECT_COLOR] then
5764 with vleObjectProperty do
5765 begin // Выбор цвета эффекта:
5766 ColorDialog.Color := StrToIntDef(Values[Key], 0);
5767 if ColorDialog.Execute then
5768 begin
5769 Values[Key] := IntToStr(ColorDialog.Color);
5770 vleObjectPropertyApply(Sender);
5771 end;
5772 end
5773 else if Key = _lc[I_PROP_PANEL_TEX] then
5774 begin // Смена текстуры:
5775 vleObjectProperty.Values[Key] := SelectedTexture();
5776 vleObjectPropertyApply(Sender);
5777 end;
5778 end;
5780 procedure TMainForm.vleObjectPropertyApply(Sender: TObject);
5781 begin
5782 // hack to prevent empty ID in list
5783 RenderPanel.SetFocus();
5784 bApplyProperty.Click();
5785 vleObjectProperty.SetFocus();
5786 end;
5788 procedure TMainForm.aSaveMapExecute(Sender: TObject);
5789 var
5790 FileName, Section, Res: String;
5791 begin
5792 if OpenedMap = '' then
5793 begin
5794 aSaveMapAsExecute(nil);
5795 Exit;
5796 end;
5798 g_ProcessResourceStr(OpenedMap, FileName, Section, Res);
5800 SaveMap(FileName+':\'+Res);
5801 end;
5803 procedure TMainForm.aOpenMapExecute(Sender: TObject);
5804 begin
5805 OpenDialog.Filter := _lc[I_FILE_FILTER_ALL];
5807 if OpenDialog.Execute() then
5808 begin
5809 if (Pos('.ini', LowerCase(ExtractFileName(OpenDialog.FileName))) > 0) then
5810 begin // INI карты:
5811 FullClear();
5813 pLoadProgress.Left := (RenderPanel.Width div 2)-(pLoadProgress.Width div 2);
5814 pLoadProgress.Top := (RenderPanel.Height div 2)-(pLoadProgress.Height div 2);
5815 pLoadProgress.Show();
5817 OpenedMap := '';
5818 OpenedWAD := '';
5820 LoadMapOld(OpenDialog.FileName);
5822 MainForm.Caption := Format('%s - %s', [FormCaption, ExtractFileName(OpenDialog.FileName)]);
5824 pLoadProgress.Hide();
5825 MainForm.FormResize(Self);
5826 end
5827 else // Карты из WAD:
5828 begin
5829 OpenMap(OpenDialog.FileName, '');
5830 end;
5832 OpenDialog.InitialDir := ExtractFileDir(OpenDialog.FileName);
5833 end;
5834 end;
5836 procedure TMainForm.FormActivate(Sender: TObject);
5837 var
5838 lang: Integer;
5839 config: TConfig;
5840 begin
5841 MainForm.ActiveControl := RenderPanel;
5843 // Язык:
5844 if gLanguage = '' then
5845 begin
5846 lang := SelectLanguageForm.ShowModal();
5847 case lang of
5848 1: gLanguage := LANGUAGE_ENGLISH;
5849 else gLanguage := LANGUAGE_RUSSIAN;
5850 end;
5852 config := TConfig.CreateFile(EditorDir+'Editor.cfg');
5853 config.WriteStr('Editor', 'Language', gLanguage);
5854 config.SaveFile(EditorDir+'Editor.cfg');
5855 config.Free();
5856 end;
5858 //e_WriteLog('Read language file', MSG_NOTIFY);
5859 //g_Language_Load(EditorDir+'\data\'+gLanguage+LANGUAGE_FILE_NAME);
5860 g_Language_Set(gLanguage);
5861 end;
5863 procedure TMainForm.aDeleteMap(Sender: TObject);
5864 var
5865 WAD: TWADEditor_1;
5866 MapList: SArray;
5867 MapName: Char16;
5868 a: Integer;
5869 str: String;
5870 begin
5871 OpenDialog.Filter := _lc[I_FILE_FILTER_WAD];
5873 if not OpenDialog.Execute() then
5874 Exit;
5876 WAD := TWADEditor_1.Create();
5878 if not WAD.ReadFile(OpenDialog.FileName) then
5879 begin
5880 WAD.Free();
5881 Exit;
5882 end;
5884 WAD.CreateImage();
5886 MapList := WAD.GetResourcesList('');
5888 SelectMapForm.lbMapList.Items.Clear();
5890 if MapList <> nil then
5891 for a := 0 to High(MapList) do
5892 SelectMapForm.lbMapList.Items.Add(win2utf(MapList[a]));
5894 if (SelectMapForm.ShowModal() = mrOK) then
5895 begin
5896 str := SelectMapForm.lbMapList.Items[SelectMapForm.lbMapList.ItemIndex];
5897 MapName := '';
5898 Move(str[1], MapName[0], Min(16, Length(str)));
5900 if MessageBox(0, PChar(Format(_lc[I_MSG_DELETE_MAP_PROMT],
5901 [MapName, OpenDialog.FileName])),
5902 PChar(_lc[I_MSG_DELETE_MAP]),
5903 MB_ICONQUESTION or MB_YESNO or
5904 MB_DEFBUTTON2) <> mrYes then
5905 Exit;
5907 WAD.RemoveResource('', utf2win(MapName));
5909 MessageBox(0, PChar(Format(_lc[I_MSG_MAP_DELETED_PROMT],
5910 [MapName])),
5911 PChar(_lc[I_MSG_MAP_DELETED]),
5912 MB_ICONINFORMATION or MB_OK or
5913 MB_DEFBUTTON1);
5915 WAD.SaveTo(OpenDialog.FileName);
5917 // Удалили текущую карту - сохранять по старому ее нельзя:
5918 if OpenedMap = (OpenDialog.FileName+':\'+MapName) then
5919 begin
5920 OpenedMap := '';
5921 OpenedWAD := '';
5922 MainForm.Caption := FormCaption;
5923 end;
5924 end;
5926 WAD.Free();
5927 end;
5929 procedure TMainForm.vleObjectPropertyKeyDown(Sender: TObject;
5930 var Key: Word; Shift: TShiftState);
5931 begin
5932 if Key = VK_RETURN then
5933 vleObjectPropertyApply(Sender);
5934 end;
5936 procedure MovePanel(var ID: DWORD; MoveType: Byte);
5937 var
5938 _id, a: Integer;
5939 tmp: TPanel;
5940 begin
5941 if (ID = 0) and (MoveType = 0) then
5942 Exit;
5943 if (ID = DWORD(High(gPanels))) and (MoveType <> 0) then
5944 Exit;
5945 if (ID > DWORD(High(gPanels))) then
5946 Exit;
5948 _id := Integer(ID);
5950 if MoveType = 0 then // to Back
5951 begin
5952 if gTriggers <> nil then
5953 for a := 0 to High(gTriggers) do
5954 with gTriggers[a] do
5955 begin
5956 if TriggerType = TRIGGER_NONE then
5957 Continue;
5959 if TexturePanel = _id then
5960 TexturePanel := 0
5961 else
5962 if (TexturePanel >= 0) and (TexturePanel < _id) then
5963 Inc(TexturePanel);
5965 case TriggerType of
5966 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
5967 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP,
5968 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
5969 if Data.PanelID = _id then
5970 Data.PanelID := 0
5971 else
5972 if (Data.PanelID >= 0) and (Data.PanelID < _id) then
5973 Inc(Data.PanelID);
5975 TRIGGER_SHOT:
5976 if Data.ShotPanelID = _id then
5977 Data.ShotPanelID := 0
5978 else
5979 if (Data.ShotPanelID >= 0) and (Data.ShotPanelID < _id) then
5980 Inc(Data.ShotPanelID);
5981 end;
5982 end;
5984 tmp := gPanels[_id];
5986 for a := _id downto 1 do
5987 gPanels[a] := gPanels[a-1];
5989 gPanels[0] := tmp;
5991 ID := 0;
5992 end
5993 else // to Front
5994 begin
5995 if gTriggers <> nil then
5996 for a := 0 to High(gTriggers) do
5997 with gTriggers[a] do
5998 begin
5999 if TriggerType = TRIGGER_NONE then
6000 Continue;
6002 if TexturePanel = _id then
6003 TexturePanel := High(gPanels)
6004 else
6005 if TexturePanel > _id then
6006 Dec(TexturePanel);
6008 case TriggerType of
6009 TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR,
6010 TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP,
6011 TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT:
6012 if Data.PanelID = _id then
6013 Data.PanelID := High(gPanels)
6014 else
6015 if Data.PanelID > _id then
6016 Dec(Data.PanelID);
6018 TRIGGER_SHOT:
6019 if Data.ShotPanelID = _id then
6020 Data.ShotPanelID := High(gPanels)
6021 else
6022 if Data.ShotPanelID > _id then
6023 Dec(Data.ShotPanelID);
6024 end;
6025 end;
6027 tmp := gPanels[_id];
6029 for a := _id to High(gPanels)-1 do
6030 gPanels[a] := gPanels[a+1];
6032 gPanels[High(gPanels)] := tmp;
6034 ID := High(gPanels);
6035 end;
6036 end;
6038 procedure TMainForm.aMoveToBack(Sender: TObject);
6039 var
6040 a: Integer;
6041 begin
6042 if SelectedObjects = nil then
6043 Exit;
6045 for a := 0 to High(SelectedObjects) do
6046 with SelectedObjects[a] do
6047 if Live and (ObjectType = OBJECT_PANEL) then
6048 begin
6049 SelectedObjects[0] := SelectedObjects[a];
6050 SetLength(SelectedObjects, 1);
6051 MovePanel(ID, 0);
6052 FillProperty();
6053 Break;
6054 end;
6055 end;
6057 procedure TMainForm.aMoveToFore(Sender: TObject);
6058 var
6059 a: Integer;
6060 begin
6061 if SelectedObjects = nil then
6062 Exit;
6064 for a := 0 to High(SelectedObjects) do
6065 with SelectedObjects[a] do
6066 if Live and (ObjectType = OBJECT_PANEL) then
6067 begin
6068 SelectedObjects[0] := SelectedObjects[a];
6069 SetLength(SelectedObjects, 1);
6070 MovePanel(ID, 1);
6071 FillProperty();
6072 Break;
6073 end;
6074 end;
6076 procedure TMainForm.aSaveMapAsExecute(Sender: TObject);
6077 var
6078 idx: Integer;
6079 begin
6080 SaveDialog.Filter := _lc[I_FILE_FILTER_WAD];
6082 if not SaveDialog.Execute() then
6083 Exit;
6085 SaveMapForm.GetMaps(SaveDialog.FileName, True);
6087 if SaveMapForm.ShowModal() <> mrOK then
6088 Exit;
6090 SaveDialog.InitialDir := ExtractFileDir(SaveDialog.FileName);
6091 OpenedMap := SaveDialog.FileName+':\'+SaveMapForm.eMapName.Text;
6092 OpenedWAD := SaveDialog.FileName;
6094 idx := RecentFiles.IndexOf(OpenedMap);
6095 // Такая карта уже недавно открывалась:
6096 if idx >= 0 then
6097 RecentFiles.Delete(idx);
6098 RecentFiles.Insert(0, OpenedMap);
6099 RefreshRecentMenu;
6101 SaveMap(OpenedMap);
6103 gMapInfo.FileName := SaveDialog.FileName;
6104 gMapInfo.MapName := SaveMapForm.eMapName.Text;
6105 UpdateCaption(gMapInfo.Name, ExtractFileName(gMapInfo.FileName), gMapInfo.MapName);
6106 end;
6108 procedure TMainForm.aSelectAllExecute(Sender: TObject);
6109 var
6110 a: Integer;
6111 begin
6112 RemoveSelectFromObjects();
6114 case pcObjects.ActivePageIndex+1 of
6115 OBJECT_PANEL:
6116 if gPanels <> nil then
6117 for a := 0 to High(gPanels) do
6118 if gPanels[a].PanelType <> PANEL_NONE then
6119 SelectObject(OBJECT_PANEL, a, True);
6120 OBJECT_ITEM:
6121 if gItems <> nil then
6122 for a := 0 to High(gItems) do
6123 if gItems[a].ItemType <> ITEM_NONE then
6124 SelectObject(OBJECT_ITEM, a, True);
6125 OBJECT_MONSTER:
6126 if gMonsters <> nil then
6127 for a := 0 to High(gMonsters) do
6128 if gMonsters[a].MonsterType <> MONSTER_NONE then
6129 SelectObject(OBJECT_MONSTER, a, True);
6130 OBJECT_AREA:
6131 if gAreas <> nil then
6132 for a := 0 to High(gAreas) do
6133 if gAreas[a].AreaType <> AREA_NONE then
6134 SelectObject(OBJECT_AREA, a, True);
6135 OBJECT_TRIGGER:
6136 if gTriggers <> nil then
6137 for a := 0 to High(gTriggers) do
6138 if gTriggers[a].TriggerType <> TRIGGER_NONE then
6139 SelectObject(OBJECT_TRIGGER, a, True);
6140 end;
6141 end;
6143 procedure TMainForm.tbGridOnClick(Sender: TObject);
6144 begin
6145 DotEnable := not DotEnable;
6146 (Sender as TToolButton).Down := DotEnable;
6147 end;
6149 procedure TMainForm.OnIdle(Sender: TObject; var Done: Boolean);
6150 begin
6151 // FIXME: this is a shitty hack
6152 if not gDataLoaded then
6153 begin
6154 e_WriteLog('Init OpenGL', MSG_NOTIFY);
6155 e_InitGL();
6156 e_WriteLog('Loading data', MSG_NOTIFY);
6157 LoadStdFont('STDTXT', 'STDFONT', gEditorFont);
6158 e_WriteLog('Loading more data', MSG_NOTIFY);
6159 LoadData();
6160 e_WriteLog('Loading even more data', MSG_NOTIFY);
6161 gDataLoaded := True;
6162 MainForm.FormResize(nil);
6163 end;
6164 Draw();
6165 end;
6167 procedure TMainForm.miMapPreviewClick(Sender: TObject);
6168 begin
6169 if not PreviewMode then
6170 begin
6171 Splitter2.Visible := False;
6172 Splitter1.Visible := False;
6173 StatusBar.Visible := False;
6174 PanelObjs.Visible := False;
6175 PanelProps.Visible := False;
6176 MainToolBar.Visible := False;
6177 sbHorizontal.Visible := False;
6178 sbVertical.Visible := False;
6179 end
6180 else
6181 begin
6182 StatusBar.Visible := True;
6183 PanelObjs.Visible := True;
6184 PanelProps.Visible := True;
6185 Splitter2.Visible := True;
6186 Splitter1.Visible := True;
6187 MainToolBar.Visible := True;
6188 sbHorizontal.Visible := True;
6189 sbVertical.Visible := True;
6190 end;
6192 PreviewMode := not PreviewMode;
6193 (Sender as TMenuItem).Checked := PreviewMode;
6195 FormResize(Self);
6196 end;
6198 procedure TMainForm.miLayer1Click(Sender: TObject);
6199 begin
6200 SwitchLayer(LAYER_BACK);
6201 end;
6203 procedure TMainForm.miLayer2Click(Sender: TObject);
6204 begin
6205 SwitchLayer(LAYER_WALLS);
6206 end;
6208 procedure TMainForm.miLayer3Click(Sender: TObject);
6209 begin
6210 SwitchLayer(LAYER_FOREGROUND);
6211 end;
6213 procedure TMainForm.miLayer4Click(Sender: TObject);
6214 begin
6215 SwitchLayer(LAYER_STEPS);
6216 end;
6218 procedure TMainForm.miLayer5Click(Sender: TObject);
6219 begin
6220 SwitchLayer(LAYER_WATER);
6221 end;
6223 procedure TMainForm.miLayer6Click(Sender: TObject);
6224 begin
6225 SwitchLayer(LAYER_ITEMS);
6226 end;
6228 procedure TMainForm.miLayer7Click(Sender: TObject);
6229 begin
6230 SwitchLayer(LAYER_MONSTERS);
6231 end;
6233 procedure TMainForm.miLayer8Click(Sender: TObject);
6234 begin
6235 SwitchLayer(LAYER_AREAS);
6236 end;
6238 procedure TMainForm.miLayer9Click(Sender: TObject);
6239 begin
6240 SwitchLayer(LAYER_TRIGGERS);
6241 end;
6243 procedure TMainForm.tbShowClick(Sender: TObject);
6244 var
6245 a: Integer;
6246 b: Boolean;
6247 begin
6248 b := True;
6249 for a := 0 to High(LayerEnabled) do
6250 b := b and LayerEnabled[a];
6252 b := not b;
6254 ShowLayer(LAYER_BACK, b);
6255 ShowLayer(LAYER_WALLS, b);
6256 ShowLayer(LAYER_FOREGROUND, b);
6257 ShowLayer(LAYER_STEPS, b);
6258 ShowLayer(LAYER_WATER, b);
6259 ShowLayer(LAYER_ITEMS, b);
6260 ShowLayer(LAYER_MONSTERS, b);
6261 ShowLayer(LAYER_AREAS, b);
6262 ShowLayer(LAYER_TRIGGERS, b);
6263 end;
6265 procedure TMainForm.miMiniMapClick(Sender: TObject);
6266 begin
6267 SwitchMap();
6268 end;
6270 procedure TMainForm.miSwitchGridClick(Sender: TObject);
6271 begin
6272 if DotStep = DotStepOne then
6273 DotStep := DotStepTwo
6274 else
6275 DotStep := DotStepOne;
6277 MousePos.X := (MousePos.X div DotStep) * DotStep;
6278 MousePos.Y := (MousePos.Y div DotStep) * DotStep;
6279 end;
6281 procedure TMainForm.miShowEdgesClick(Sender: TObject);
6282 begin
6283 ShowEdges();
6284 end;
6286 procedure TMainForm.miSnapToGridClick(Sender: TObject);
6287 begin
6288 SnapToGrid := not SnapToGrid;
6290 MousePos.X := (MousePos.X div DotStep) * DotStep;
6291 MousePos.Y := (MousePos.Y div DotStep) * DotStep;
6293 miSnapToGrid.Checked := SnapToGrid;
6294 end;
6296 procedure TMainForm.minexttabClick(Sender: TObject);
6297 begin
6298 if pcObjects.ActivePageIndex < pcObjects.PageCount-1 then
6299 pcObjects.ActivePageIndex := pcObjects.ActivePageIndex+1
6300 else
6301 pcObjects.ActivePageIndex := 0;
6302 end;
6304 procedure TMainForm.miSaveMiniMapClick(Sender: TObject);
6305 begin
6306 SaveMiniMapForm.ShowModal();
6307 end;
6309 procedure TMainForm.bClearTextureClick(Sender: TObject);
6310 begin
6311 lbTextureList.ItemIndex := -1;
6312 lTextureWidth.Caption := '';
6313 lTextureHeight.Caption := '';
6314 end;
6316 procedure TMainForm.miPackMapClick(Sender: TObject);
6317 begin
6318 PackMapForm.ShowModal();
6319 end;
6321 procedure TMainForm.miMapTestSettingsClick(Sender: TObject);
6322 begin
6323 MapTestForm.ShowModal();
6324 end;
6326 procedure TMainForm.miTestMapClick(Sender: TObject);
6327 var
6328 cmd, mapWAD, mapToRun, tempWAD: String;
6329 opt: LongWord;
6330 time: Integer;
6331 proc: TProcessUTF8;
6332 res: Boolean;
6333 begin
6334 mapToRun := '';
6335 if OpenedMap <> '' then
6336 begin
6337 // Указываем текущую карту для теста:
6338 g_ProcessResourceStr(OpenedMap, @mapWAD, nil, @mapToRun);
6339 mapToRun := mapWAD + ':\' + mapToRun;
6340 mapToRun := ExtractRelativePath(ExtractFilePath(TestD2dExe) + 'maps/', mapToRun);
6341 end;
6342 // Сохраняем временную карту:
6343 time := 0;
6344 repeat
6345 mapWAD := ExtractFilePath(TestD2dExe) + Format('maps/temp%.4d.wad', [time]);
6346 Inc(time);
6347 until not FileExists(mapWAD);
6348 tempWAD := mapWAD + ':\' + TEST_MAP_NAME;
6349 SaveMap(tempWAD);
6351 tempWAD := ExtractRelativePath(ExtractFilePath(TestD2dExe) + 'maps/', tempWAD);
6352 // Если карта не была открыта, указываем временную в качестве текущей:
6353 if mapToRun = '' then
6354 mapToRun := tempWAD;
6356 // Опции игры:
6357 opt := 32 + 64;
6358 if TestOptionsTwoPlayers then
6359 opt := opt + 1;
6360 if TestOptionsTeamDamage then
6361 opt := opt + 2;
6362 if TestOptionsAllowExit then
6363 opt := opt + 4;
6364 if TestOptionsWeaponStay then
6365 opt := opt + 8;
6366 if TestOptionsMonstersDM then
6367 opt := opt + 16;
6369 // Составляем командную строку:
6370 cmd := '-map "' + mapToRun + '"';
6371 cmd := cmd + ' -testmap "' + tempWAD + '"';
6372 cmd := cmd + ' -gm ' + TestGameMode;
6373 cmd := cmd + ' -limt ' + TestLimTime;
6374 cmd := cmd + ' -lims ' + TestLimScore;
6375 cmd := cmd + ' -opt ' + IntToStr(opt);
6377 if TestMapOnce then
6378 cmd := cmd + ' --close';
6380 cmd := cmd + ' --debug';
6382 // Запускаем:
6383 proc := TProcessUTF8.Create(nil);
6384 proc.Executable := TestD2dExe;
6385 proc.Parameters.Add(cmd);
6386 res := True;
6387 try
6388 proc.Execute();
6389 except
6390 res := False;
6391 end;
6392 if res then
6393 begin
6394 Application.Minimize();
6395 proc.WaitOnExit();
6396 end;
6397 if (not res) or (proc.ExitCode < 0) then
6398 begin
6399 MessageBox(0, 'FIXME',
6400 PChar(_lc[I_MSG_EXEC_ERROR]),
6401 MB_OK or MB_ICONERROR);
6402 end;
6403 proc.Free();
6405 SysUtils.DeleteFile(mapWAD);
6406 Application.Restore();
6407 end;
6409 procedure TMainForm.sbVerticalScroll(Sender: TObject;
6410 ScrollCode: TScrollCode; var ScrollPos: Integer);
6411 begin
6412 MapOffset.Y := -Normalize16(sbVertical.Position);
6413 end;
6415 procedure TMainForm.sbHorizontalScroll(Sender: TObject;
6416 ScrollCode: TScrollCode; var ScrollPos: Integer);
6417 begin
6418 MapOffset.X := -Normalize16(sbHorizontal.Position);
6419 end;
6421 procedure TMainForm.miOpenWadMapClick(Sender: TObject);
6422 begin
6423 if OpenedWAD <> '' then
6424 begin
6425 OpenMap(OpenedWAD, '');
6426 end;
6427 end;
6429 procedure TMainForm.selectall1Click(Sender: TObject);
6430 var
6431 a: Integer;
6432 begin
6433 RemoveSelectFromObjects();
6435 if gPanels <> nil then
6436 for a := 0 to High(gPanels) do
6437 if gPanels[a].PanelType <> PANEL_NONE then
6438 SelectObject(OBJECT_PANEL, a, True);
6440 if gItems <> nil then
6441 for a := 0 to High(gItems) do
6442 if gItems[a].ItemType <> ITEM_NONE then
6443 SelectObject(OBJECT_ITEM, a, True);
6445 if gMonsters <> nil then
6446 for a := 0 to High(gMonsters) do
6447 if gMonsters[a].MonsterType <> MONSTER_NONE then
6448 SelectObject(OBJECT_MONSTER, a, True);
6450 if gAreas <> nil then
6451 for a := 0 to High(gAreas) do
6452 if gAreas[a].AreaType <> AREA_NONE then
6453 SelectObject(OBJECT_AREA, a, True);
6455 if gTriggers <> nil then
6456 for a := 0 to High(gTriggers) do
6457 if gTriggers[a].TriggerType <> TRIGGER_NONE then
6458 SelectObject(OBJECT_TRIGGER, a, True);
6459 end;
6461 procedure TMainForm.Splitter1CanResize(Sender: TObject;
6462 var NewSize: Integer; var Accept: Boolean);
6463 begin
6464 Accept := (NewSize > 140);
6465 end;
6467 procedure TMainForm.Splitter2CanResize(Sender: TObject;
6468 var NewSize: Integer; var Accept: Boolean);
6469 begin
6470 Accept := (NewSize > 110);
6471 end;
6473 procedure TMainForm.vleObjectPropertyEnter(Sender: TObject);
6474 begin
6475 EditingProperties := True;
6476 end;
6478 procedure TMainForm.vleObjectPropertyExit(Sender: TObject);
6479 begin
6480 EditingProperties := False;
6481 end;
6483 procedure TMainForm.FormKeyUp(Sender: TObject; var Key: Word;
6484 Shift: TShiftState);
6485 begin
6486 // Объекты передвигались:
6487 if MainForm.ActiveControl = RenderPanel then
6488 begin
6489 if (Key = VK_NUMPAD4) or
6490 (Key = VK_NUMPAD6) or
6491 (Key = VK_NUMPAD8) or
6492 (Key = VK_NUMPAD5) or
6493 (Key = Ord('V')) then
6494 FillProperty();
6495 end;
6496 end;
6498 end.