DEADSOFTWARE

no more old-styled map structured; sadly, most triggers aren't working; also, save...
authorKetmar Dark <ketmar@ketmar.no-ip.org>
Thu, 31 Aug 2017 19:28:08 +0000 (22:28 +0300)
committerKetmar Dark <ketmar@ketmar.no-ip.org>
Fri, 1 Sep 2017 00:33:55 +0000 (03:33 +0300)
13 files changed:
src/game/g_game.pas
src/game/g_gui.pas
src/game/g_main.pas
src/game/g_map.pas
src/game/g_netmsg.pas
src/game/g_panel.pas
src/game/g_triggers.pas
src/shared/MAPDEF.pas
src/shared/mapdef.inc
src/shared/mapdef_help.inc [new file with mode: 0644]
src/shared/mapdef_impl.inc [new file with mode: 0644]
src/shared/xdynrec.pas
src/tools/mapgen.dpr

index 03be57d86ec5c43e9f3007c5f3548dfeaa20e7ed..302b952af4b10f88b81c89e2537faf706921b2b9 100644 (file)
@@ -5198,7 +5198,8 @@ begin
             begin
               g_Console_Add('player left the map');
               gExitByTrigger := True;
-              g_Game_ExitLevel(gTriggers[a].Data.MapName);
+              //g_Game_ExitLevel(gTriggers[a].Data.MapName);
+              g_Game_ExitLevel(gTriggers[a].trigData.trigMapName);
               break;
             end;
           end;
@@ -6067,7 +6068,8 @@ begin
             if gTriggers[a].TriggerType = TRIGGER_EXIT then
             begin
               gExitByTrigger := True;
-              gNextMap := gTriggers[a].Data.MapName;
+              //gNextMap := gTriggers[a].Data.MapName;
+              gNextMap := gTriggers[a].trigData.trigMapName;
               Break;
             end;
         // Èùåì ñëåäóþùóþ êàðòó â WAD ôàéëå
@@ -6458,17 +6460,17 @@ begin
       with gTriggers[i] do
         if (TriggerType = TRIGGER_SOUND) and
            (Sound <> nil) and
-           (Data.Local) and
+           (trigData.trigLocal) and
            Sound.IsPlaying() then
         begin
           if ((gPlayer1 <> nil) and g_CollidePoint(gPlayer1.GameX, gPlayer1.GameY, X, Y, Width, Height)) or
              ((gPlayer2 <> nil) and g_CollidePoint(gPlayer2.GameX, gPlayer2.GameY, X, Y, Width, Height)) then
           begin
-            Sound.SetPan(0.5 - Data.Pan/255.0);
-            Sound.SetVolume(Data.Volume/255.0);
+            Sound.SetPan(0.5 - trigData.trigPan/255.0);
+            Sound.SetVolume(trigData.trigVolume/255.0);
           end
           else
-            Sound.SetCoords(X+(Width div 2), Y+(Height div 2), Data.Volume/255.0);
+            Sound.SetCoords(X+(Width div 2), Y+(Height div 2), trigData.trigVolume/255.0);
         end;
 end;
 
index 45b2364f8adba30e40aa89565fc3648bfd26e24a..d7735ab374d568a4e51cf47c543f1a2c458d7522 100644 (file)
@@ -2775,10 +2775,9 @@ end;
 procedure TGUIMapPreview.SetMap(Res: string);
 var
   WAD: TWADFile;
-  //MapReader: TMapReader_1;
-  panels: TPanelsRec1Array;
-  header: TMapHeaderRec_1;
-  a: Integer;
+  panlist: TDynField;
+  pan: TDynRecord;
+  //header: TMapHeaderRec_1;
   FileName: string;
   Data: Pointer;
   Len: Integer;
@@ -2815,48 +2814,36 @@ begin
     raise;
   end;
 
-  {
-  MapReader := TMapReader_1.Create();
-  if not MapReader.LoadMap(Data) then
-  begin
-    FreeMem(Data);
-    MapReader.Free();
-    FMapSize.X := 0;
-    FMapSize.Y := 0;
-    FScale := 0.0;
-    FMapData := nil;
-    Exit;
-  end;
-  }
-
   FreeMem(Data);
 
-  panels := GetPanels(map);
-  header := GetMapHeader(map);
+  panlist := map.field['panel'];
+  //header := GetMapHeader(map);
 
-  FMapSize.X := header.Width div 16;
-  FMapSize.Y := header.Height div 16;
+  FMapSize.X := map.Width div 16;
+  FMapSize.Y := map.Height div 16;
 
-  rX := Ceil(header.Width / (MAPPREVIEW_WIDTH*256.0));
-  rY := Ceil(header.Height / (MAPPREVIEW_HEIGHT*256.0));
+  rX := Ceil(map.Width / (MAPPREVIEW_WIDTH*256.0));
+  rY := Ceil(map.Height / (MAPPREVIEW_HEIGHT*256.0));
   FScale := max(rX, rY);
 
   FMapData := nil;
 
-  if panels <> nil then
-    for a := 0 to High(panels) do
-      if WordBool(panels[a].PanelType and (PANEL_WALL or PANEL_CLOSEDOOR or
+  if (panlist <> nil) then
+  begin
+    for pan in panlist do
+    begin
+      if (pan.PanelType and (PANEL_WALL or PANEL_CLOSEDOOR or
                                            PANEL_STEP or PANEL_WATER or
-                                           PANEL_ACID1 or PANEL_ACID2)) then
+                                           PANEL_ACID1 or PANEL_ACID2)) <> 0 then
       begin
         SetLength(FMapData, Length(FMapData)+1);
         with FMapData[High(FMapData)] do
         begin
-          X1 := panels[a].X div 16;
-          Y1 := panels[a].Y div 16;
+          X1 := pan.X div 16;
+          Y1 := pan.Y div 16;
 
-          X2 := (panels[a].X + panels[a].Width) div 16;
-          Y2 := (panels[a].Y + panels[a].Height) div 16;
+          X2 := (pan.X + pan.Width) div 16;
+          Y2 := (pan.Y + pan.Height) div 16;
 
           X1 := Trunc(X1/FScale + 0.5);
           Y1 := Trunc(Y1/FScale + 0.5);
@@ -2871,13 +2858,12 @@ begin
               Y2 := Y2 + 1;
           end;
 
-          PanelType := panels[a].PanelType;
+          PanelType := pan.PanelType;
+        end;
       end;
-   end;
-
-  panels := nil;
+    end;
+  end;
 
-  //MapReader.Free();
   map.Free();
 end;
 
index 1b131f14e7bec2d12111b4487525f4a7232c5916..06e5ace8c04ede683e71ac4445ba8e019cc8df49 100644 (file)
@@ -302,7 +302,8 @@ begin
         if gTriggers[a].TriggerType = TRIGGER_EXIT then
         begin
           gExitByTrigger := True;
-          g_Game_ExitLevel(gTriggers[a].Data.MapName);
+          //g_Game_ExitLevel(gTriggers[a].Data.MapName);
+          g_Game_ExitLevel(gTriggers[a].trigData.trigMapName);
           Break;
         end;
     goto Cheated;
index 66d4e5696cbd19a3df29ab2d413d5f044bab1a0b..1695460c162e06e3b8b36e9c0f3b6b629390cc4a 100644 (file)
@@ -201,6 +201,8 @@ var
   profMapCollision: TProfiler = nil; //WARNING: FOR DEBUGGING ONLY!
   gDrawPanelList: TBinaryHeapObj = nil; // binary heap of all walls we have to render, populated by `g_Map_CollectDrawPanels()`
 
+  gCurrentMap: TDynRecord = nil;
+
 
 function panelTypeToTag (panelType: Word): Integer; // returns GridTagXXX
 
@@ -219,7 +221,7 @@ uses
   GL, GLExt, g_weapons, g_game, g_sound, e_sound, CONFIG,
   g_options, g_triggers, g_player,
   Math, g_monsters, g_saveload, g_language, g_netmsg,
-  utils, sfs, xstreams,
+  utils, sfs, xstreams, hashtable,
   ImagingTypes, Imaging, ImagingUtility,
   ImagingGif, ImagingNetworkGraphics;
 
@@ -232,7 +234,6 @@ const
 var
   dfmapdef: TDynMapDef = nil;
 
-
 procedure loadMapDefinition ();
 var
   pr: TTextParser = nil;
@@ -734,7 +735,7 @@ begin
   PanelArray := nil;
 end;
 
-function CreatePanel(PanelRec: TPanelRec_1; AddTextures: TAddTextureArray;
+function CreatePanel(PanelRec: TDynRecord; AddTextures: TAddTextureArray;
                      CurTex: Integer; sav: Boolean): Integer;
 var
   len: Integer;
@@ -1107,7 +1108,7 @@ begin
   end;
 end;
 
-procedure CreateItem(Item: TItemRec_1);
+procedure CreateItem(Item: TDynRecord);
 begin
   if g_Game_IsClient then Exit;
 
@@ -1119,7 +1120,7 @@ begin
                  gGameSettings.GameMode in [GM_DM, GM_TDM, GM_CTF, GM_COOP]);
 end;
 
-procedure CreateArea(Area: TAreaRec_1);
+procedure CreateArea(Area: TDynRecord);
 var
   a: Integer;
   id: DWORD = 0;
@@ -1189,7 +1190,7 @@ begin
   end;
 end;
 
-procedure CreateTrigger(Trigger: TTriggerRec_1; fTexturePanel1Type, fTexturePanel2Type: Word);
+procedure CreateTrigger(Trigger: TDynRecord; atpanid, ashotpanid: Integer; fTexturePanel1Type, fTexturePanel2Type: Word);
 var
   _trigger: TTrigger;
 begin
@@ -1208,13 +1209,16 @@ begin
     TriggerType := Trigger.TriggerType;
     ActivateType := Trigger.ActivateType;
     Keys := Trigger.Keys;
-    Data.Default := Trigger.DATA;
+    trigPanelId := atpanid;
+    trigShotPanelId := ashotpanid;
+    //Data.Default := Trigger.DATA;
+    trigData := Trigger.trigRec.clone();
   end;
 
   g_Triggers_Create(_trigger);
 end;
 
-procedure CreateMonster(monster: TMonsterRec_1);
+procedure CreateMonster(monster: TDynRecord);
 var
   a: Integer;
   mon: TMonster;
@@ -1232,7 +1236,8 @@ begin
       begin
         if gTriggers[a].TriggerType in [TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF] then
         begin
-          if (gTriggers[a].Data.MonsterID-1) = mon.StartID then mon.AddTrigger(a);
+          //if (gTriggers[a].Data.MonsterID-1) = Integer(mon.StartID) then mon.AddTrigger(a);
+          if (gTriggers[a].trigData.trigMonsterId) = Integer(mon.StartID) then mon.AddTrigger(a);
         end;
       end;
     end;
@@ -1253,7 +1258,8 @@ procedure g_Map_ReAdd_DieTriggers();
     begin
       if gTriggers[a].TriggerType in [TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF] then
       begin
-        if (gTriggers[a].Data.MonsterID-1) = mon.StartID then mon.AddTrigger(a);
+        //if (gTriggers[a].Data.MonsterID-1) = Integer(mon.StartID) then mon.AddTrigger(a);
+        if (gTriggers[a].trigData.trigMonsterId) = Integer(mon.StartID) then mon.AddTrigger(a);
       end;
     end;
   end;
@@ -1283,28 +1289,44 @@ begin
 end;
 
 procedure generateExternalResourcesList({mapReader: TMapReader_1}map: TDynRecord);
-var
-  textures: TTexturesRec1Array;
-  mapHeader: TMapHeaderRec_1;
-  i: integer;
-  resFile: String = '';
+//var
+  //textures: TTexturesRec1Array;
+  //textures: TDynField;
+  //trec: TDynRecord;
+  //mapHeader: TMapHeaderRec_1;
+  //i: integer;
+  //resFile: String = '';
 begin
   if gExternalResources = nil then
     gExternalResources := TStringList.Create;
 
   gExternalResources.Clear;
+
+  (*
+  {
   textures := GetTextures(map);
   for i := 0 to High(textures) do
   begin
     addResToExternalResList(resFile);
   end;
+  }
+
+  textures := map['texture'];
+  if (textures <> nil) then
+  begin
+    for trec in textures do
+    begin
+      addResToExternalResList(resFile);
+    end;
+  end;
 
   textures := nil;
+  *)
 
-  mapHeader := GetMapHeader(map);
+  //mapHeader := GetMapHeader(map);
 
-  addResToExternalResList(mapHeader.MusicName);
-  addResToExternalResList(mapHeader.SkyName);
+  addResToExternalResList(map.MusicName);
+  addResToExternalResList(map.SkyName);
 end;
 
 
@@ -1424,45 +1446,66 @@ function g_Map_Load(Res: String): Boolean;
 const
   DefaultMusRes = 'Standart.wad:STDMUS\MUS1';
   DefaultSkyRes = 'Standart.wad:STDSKY\SKY0';
+type
+  PTRec = ^TTRec;
+  TTRec = record
+    //TexturePanel: Integer;
+    texPanIdx: Integer;
+    LiftPanelIdx: Integer;
+    DoorPanelIdx: Integer;
+    ShotPanelIdx: Integer;
+    trigrec: TDynRecord;
+    texPan: TDynRecord;
+    liftPan: TDynRecord;
+    doorPan: TDynRecord;
+    shotPan: TDynRecord;
+  end;
 var
   WAD: TWADFile;
   //MapReader: TMapReader_1;
   mapReader: TDynRecord = nil;
-  Header: TMapHeaderRec_1;
-  _textures: TTexturesRec1Array;
-  _texnummap: array of Integer; // `_textures` -> `Textures`
-  panels: TPanelsRec1Array;
-  items: TItemsRec1Array;
-  monsters: TMonsterRec1Array;
-  areas: TAreasRec1Array;
-  triggers: TTriggersRec1Array;
-  a, b, c, k: Integer;
+  //Header: TMapHeaderRec_1;
+  _textures: TDynField = nil; //TTexturesRec1Array; tagInt: texture index
+  //_texnummap: array of Integer = nil; // `_textures` -> `Textures`
+  panels: TDynField = nil; //TPanelsRec1Array;
+  items: TDynField = nil; //TItemsRec1Array;
+  monsters: TDynField = nil; //TMonsterRec1Array;
+  areas: TDynField = nil; //TAreasRec1Array;
+  triggers: TDynField = nil; //TTriggersRec1Array;
+  b, c, k: Integer;
   PanelID: DWORD;
   AddTextures: TAddTextureArray;
-  texture: TTextureRec_1;
-  TriggersTable: Array of record
-                           TexturePanel: Integer;
-                           LiftPanel: Integer;
-                           DoorPanel: Integer;
-                           ShotPanel: Integer;
-                          end;
+  //texture: TTextureRec_1;
+  TriggersTable: array of TTRec;
   FileName, mapResName, s, TexName: String;
   Data: Pointer;
   Len: Integer;
   ok, isAnim, trigRef: Boolean;
   CurTex, ntn: Integer;
+  rec, texrec: TDynRecord;
+  pttit: PTRec;
+  pannum, trignum, cnt: Integer;
+  // key: panel index; value: `TriggersTable` index
+  hashTextPan: THashIntInt = nil;
+  hashLiftPan: THashIntInt = nil;
+  hashDoorPan: THashIntInt = nil;
+  hashShotPan: THashIntInt = nil;
 begin
   mapGrid.Free();
   mapGrid := nil;
 
+  gCurrentMap.Free();
+  gCurrentMap := nil;
+
   Result := False;
   gMapInfo.Map := Res;
   TriggersTable := nil;
-  FillChar(texture, SizeOf(texture), 0);
+  mapReader := nil;
+  //FillChar(texture, SizeOf(texture), 0);
 
   sfsGCDisable(); // temporary disable removing of temporary volumes
   try
-  // Çàãðóçêà WAD:
+    // Çàãðóçêà WAD:
     FileName := g_ExtractWadName(Res);
     e_WriteLog('Loading map WAD: '+FileName, MSG_NOTIFY);
     g_Game_SetLoadingText(_lc[I_LOAD_WAD_FILE], 0, False);
@@ -1497,443 +1540,473 @@ begin
     e_LogWritefln('Loading map: %s', [mapResName], MSG_NOTIFY);
     g_Game_SetLoadingText(_lc[I_LOAD_MAP], 0, False);
 
-    {
-    if (PChar(Data)[0] = 'M') and (PChar(Data)[1] = 'A') and (PChar(Data)[2] = 'P') and (PByte(Data)[3] = 1) then
-    begin
-      // nothing
-    end
-    else
-    begin
-      e_LogWritefln('Loading text map: %s', [mapResName]);
-      loadMapDefinition();
-      if (dfmapdef = nil) then raise Exception.Create('internal map loader error');
-      //e_LogWritefln('***'#10'%s'#10'***', [dfmapdef.headerType.definition]);
-      wst := TSFSMemoryChunkStream.Create(Data, Len);
-      try
-        pr := TFileTextParser.Create(wst);
-        e_LogWritefln('parsing text map: %s', [mapResName]);
-        rec := dfmapdef.parseMap(pr);
-      except on e: Exception do
-        begin
-          if (pr <> nil) then e_LogWritefln('ERROR at (%s,%s): %s', [pr.line, pr.col, e.message])
-          else e_LogWritefln('ERROR: %s', [e.message]);
-          pr.Free();
-          wst.Free();
-          FreeMem(Data);
-          exit;
-        end;
-      end;
-      pr.Free();
-      //wst.Free(); // pr will do it
-      e_LogWritefln('writing text map to temporary bin storage...', []);
-      st := TMemoryStream.Create();
-      try
-        rec.writeBinTo(st);
-        Len := Integer(st.position);
-        st.position := 0;
-        FreeMem(Data);
-        GetMem(Data, Len);
-        st.ReadBuffer(Data^, Len);
-      except on e: Exception do
-        begin
-          rec.Free();
-          st.Free();
-          e_LogWritefln('ERROR: %s', [e.message]);
-          FreeMem(Data);
-          exit;
-        end;
-      end;
-      st.Free();
-    end;
-    }
     try
       mapReader := g_Map_ParseMap(Data, Len);
     except
       mapReader.Free();
       g_FatalError(Format(_lc[I_GAME_ERROR_MAP_LOAD], [Res]));
       FreeMem(Data);
-      MapReader.Free();
-      Exit;
-    end;
-
-    {
-    MapReader := TMapReader_1.Create();
-    if not MapReader.LoadMap(Data) then
-    begin
-      g_FatalError(Format(_lc[I_GAME_ERROR_MAP_LOAD], [Res]));
-      FreeMem(Data);
-      MapReader.Free();
       Exit;
     end;
-    }
 
     FreeMem(Data);
-    generateExternalResourcesList(MapReader);
-  // Çàãðóçêà òåêñòóð:
-    g_Game_SetLoadingText(_lc[I_LOAD_TEXTURES], 0, False);
-    _textures := GetTextures(mapReader);
-    _texnummap := nil;
 
-  // Çàãðóçêà îïèñàíèÿ êàðòû:
+    hashTextPan := hashNewIntInt();
+    hashLiftPan := hashNewIntInt();
+    hashDoorPan := hashNewIntInt();
+    hashShotPan := hashNewIntInt();
+
+    generateExternalResourcesList(MapReader);
+    //_textures := GetTextures(mapReader);
+    _textures := mapReader['texture'];
+    //_texnummap := nil;
+    // get all other lists here too
+    //panels := GetPanels(mapReader);
+    panels := mapReader['panel'];
+    //triggers := GetTriggers(mapReader);
+    triggers := mapReader['trigger'];
+    //items := GetItems(mapReader);
+    items := mapReader['item'];
+    //areas := GetAreas(mapReader);
+    areas := mapReader['area'];
+    //monsters := GetMonsters(mapReader);
+    monsters := mapReader['monster'];
+
+    // Çàãðóçêà îïèñàíèÿ êàðòû:
     e_WriteLog('  Reading map info...', MSG_NOTIFY);
     g_Game_SetLoadingText(_lc[I_LOAD_MAP_HEADER], 0, False);
-    Header := GetMapHeader(mapReader);
+    //Header := GetMapHeader(mapReader);
 
     with gMapInfo do
     begin
-      Name := Header.MapName;
-      Description := Header.MapDescription;
-      Author := Header.MapAuthor;
-      MusicName := Header.MusicName;
-      SkyName := Header.SkyName;
-      Height := Header.Height;
-      Width := Header.Width;
+      Name := mapReader.MapName;
+      Description := mapReader.MapDesc;
+      Author := mapReader.MapAuthor;
+      MusicName := mapReader.MusicName;
+      SkyName := mapReader.SkyName;
+      Height := mapReader.Height;
+      Width := mapReader.Width;
     end;
 
-  // Äîáàâëåíèå òåêñòóð â Textures[]:
-    if _textures <> nil then
+    // Çàãðóçêà òåêñòóð:
+    g_Game_SetLoadingText(_lc[I_LOAD_TEXTURES], 0, False);
+    // Äîáàâëåíèå òåêñòóð â Textures[]:
+    if (_textures <> nil) and (_textures.count > 0) then
     begin
       e_WriteLog('  Loading textures:', MSG_NOTIFY);
-      g_Game_SetLoadingText(_lc[I_LOAD_TEXTURES], High(_textures), False);
-      SetLength(_texnummap, length(_textures));
+      g_Game_SetLoadingText(_lc[I_LOAD_TEXTURES], _textures.count-1, False);
+      //SetLength(_texnummap, _textures.count);
 
-      for a := 0 to High(_textures) do
+      cnt := -1;
+      for rec in _textures do
       begin
-        SetLength(s, 64);
-        CopyMemory(@s[1], @_textures[a].Resource[0], 64);
-        for b := 1 to Length(s) do
-        begin
-          if s[b] = #0 then
-          begin
-            SetLength(s, b-1);
-            Break;
-          end;
-        end;
+        Inc(cnt);
+        s := rec.Resource;
         {$IF DEFINED(D2F_DEBUG_TXLOAD)}
-        e_WriteLog(Format('    Loading texture #%d: %s', [a, s]), MSG_NOTIFY);
+        e_WriteLog(Format('    Loading texture #%d: %s', [cnt, s]), MSG_NOTIFY);
         {$ENDIF}
         //if g_Map_IsSpecialTexture(s) then e_WriteLog('      SPECIAL!', MSG_NOTIFY);
-      // Àíèìèðîâàííàÿ òåêñòóðà:
-        if ByteBool(_textures[a].Anim) then
-          begin
-            ntn := CreateAnimTexture(_textures[a].Resource, FileName, True);
-            if ntn < 0 then
-            begin
-              g_SimpleError(Format(_lc[I_GAME_ERROR_TEXTURE_ANIM], [s]));
-              ntn := CreateNullTexture(_textures[a].Resource);
-            end;
-          end
-        else // Îáû÷íàÿ òåêñòóðà:
-          ntn := CreateTexture(_textures[a].Resource, FileName, True);
-          if ntn < 0 then
-          begin
-            g_SimpleError(Format(_lc[I_GAME_ERROR_TEXTURE_SIMPLE], [s]));
-            ntn := CreateNullTexture(_textures[a].Resource);
-          end;
+        if rec.Anim then
+        begin
+          // Àíèìèðîâàííàÿ òåêñòóðà
+          ntn := CreateAnimTexture(rec.Resource, FileName, True);
+          if (ntn < 0) then g_SimpleError(Format(_lc[I_GAME_ERROR_TEXTURE_ANIM], [s]));
+        end
+        else
+        begin
+          // Îáû÷íàÿ òåêñòóðà
+          ntn := CreateTexture(rec.Resource, FileName, True);
+          if (ntn < 0) then g_SimpleError(Format(_lc[I_GAME_ERROR_TEXTURE_SIMPLE], [s]));
+        end;
+        if (ntn < 0) then ntn := CreateNullTexture(rec.Resource);
 
-        _texnummap[a] := ntn; // fix texture number
+        //_texnummap[a] := ntn; // fix texture number
+        rec.tagInt := ntn;
         g_Game_StepLoading();
       end;
+
+      // set panel tagInt to texture index
+      if (panels <> nil) then
+      begin
+        for rec in panels do
+        begin
+          texrec := rec.TextureRec;
+          if (texrec = nil) then rec.tagInt := -1 else rec.tagInt := texrec.tagInt;
+        end;
+      end;
     end;
 
-  // Çàãðóçêà òðèããåðîâ:
+    // Çàãðóçêà òðèããåðîâ
     gTriggerClientID := 0;
     e_WriteLog('  Loading triggers...', MSG_NOTIFY);
     g_Game_SetLoadingText(_lc[I_LOAD_TRIGGERS], 0, False);
-    triggers := GetTriggers(mapReader);
 
-  // Çàãðóçêà ïàíåëåé:
+    // Çàãðóçêà ïàíåëåé
     e_WriteLog('  Loading panels...', MSG_NOTIFY);
     g_Game_SetLoadingText(_lc[I_LOAD_PANELS], 0, False);
-    panels := GetPanels(mapReader);
 
     // check texture numbers for panels
-    for a := 0 to High(panels) do
+    if (panels <> nil) and (panels.count > 0) then
     begin
-      if panels[a].TextureNum > High(_textures) then
+      for rec in panels do
       begin
-        e_WriteLog('error loading map: invalid texture index for panel', MSG_FATALERROR);
-        result := false;
-        exit;
+        if (rec.tagInt < 0) then
+        begin
+          e_WriteLog('error loading map: invalid texture index for panel', MSG_FATALERROR);
+          result := false;
+          exit;
+        end;
       end;
-      panels[a].TextureNum := _texnummap[panels[a].TextureNum];
     end;
 
-  // Ñîçäàíèå òàáëèöû òðèããåðîâ (ñîîòâåòñòâèå ïàíåëåé òðèããåðàì):
-    if triggers <> nil then
+    // Ñîçäàíèå òàáëèöû òðèããåðîâ (ñîîòâåòñòâèå ïàíåëåé òðèããåðàì)
+    if (triggers <> nil) and (triggers.count > 0) then
     begin
       e_WriteLog('  Setting up trigger table...', MSG_NOTIFY);
-      SetLength(TriggersTable, Length(triggers));
-      g_Game_SetLoadingText(_lc[I_LOAD_TRIGGERS_TABLE], High(TriggersTable), False);
+      //SetLength(TriggersTable, triggers.count);
+      g_Game_SetLoadingText(_lc[I_LOAD_TRIGGERS_TABLE], triggers.count-1, False);
 
-      for a := 0 to High(TriggersTable) do
+      for rec in triggers do
       begin
-      // Ñìåíà òåêñòóðû (âîçìîæíî, êíîïêè):
-        TriggersTable[a].TexturePanel := triggers[a].TexturePanel;
-      // Ëèôòû:
-        if triggers[a].TriggerType in [TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT] then
-          TriggersTable[a].LiftPanel := TTriggerData(triggers[a].DATA).PanelID
-        else
-          TriggersTable[a].LiftPanel := -1;
-      // Äâåðè:
-        if triggers[a].TriggerType in [TRIGGER_OPENDOOR,
-            TRIGGER_CLOSEDOOR, TRIGGER_DOOR, TRIGGER_DOOR5,
-            TRIGGER_CLOSETRAP, TRIGGER_TRAP] then
-          TriggersTable[a].DoorPanel := TTriggerData(triggers[a].DATA).PanelID
-        else
-          TriggersTable[a].DoorPanel := -1;
-      // Òóðåëü:
-        if triggers[a].TriggerType = TRIGGER_SHOT then
-          TriggersTable[a].ShotPanel := TTriggerData(triggers[a].DATA).ShotPanelID
-        else
-          TriggersTable[a].ShotPanel := -1;
+        SetLength(TriggersTable, Length(TriggersTable)+1);
+        pttit := @TriggersTable[High(TriggersTable)];
+        pttit.trigrec := rec;
+        pttit.texPan := mapReader.panel[rec.TexturePanel];
+        pttit.liftPan := nil;
+        pttit.doorPan := nil;
+        pttit.shotPan := nil;
+        pttit.texPanIdx := -1;
+        pttit.LiftPanelIdx := -1;
+        pttit.DoorPanelIdx := -1;
+        pttit.ShotPanelIdx := -1;
+        // Ñìåíà òåêñòóðû (âîçìîæíî, êíîïêè)
+        //if (rec.TexturePanel >= 0) and (pttit.texPan = nil) then e_WriteLog('error loading map: invalid texture panel index for trigger', MSG_WARNING);
+        // Ëèôòû
+        if rec.TriggerType in [TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT] then
+        begin
+          //pttit.LiftPanel := TTriggerData(rec.DATA).PanelID
+          pttit.liftPan := mapReader.panel[rec.trigRec.tgPanelID];
+          //if (rec.trigRec.trigPanelID >= 0) and (pttit.liftPan = nil) then e_WriteLog('error loading map: invalid lift panel index for trigger', MSG_WARNING);
+        end;
+        // Äâåðè
+        if rec.TriggerType in [TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR, TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP] then
+        begin
+          //pttit.DoorPanel := TTriggerData(rec.DATA).PanelID
+          pttit.doorPan := mapReader.panel[rec.trigRec.tgPanelID];
+        end;
+        // Òóðåëü
+        if (rec.TriggerType = TRIGGER_SHOT) then
+        begin
+          //pttit.ShotPanel := TTriggerData(rec.DATA).ShotPanelID
+          pttit.shotPan := mapReader.panel[rec.trigRec.tgShotPanelID];
+        end;
+
+        // update hashes
+        if (pttit.texPan <> nil) then hashTextPan.put(rec.TexturePanel, High(TriggersTable));
+        if (pttit.liftPan <> nil) then hashLiftPan.put(rec.trigRec.tgPanelID, High(TriggersTable));
+        if (pttit.doorPan <> nil) then hashDoorPan.put(rec.trigRec.tgPanelID, High(TriggersTable));
+        if (pttit.shotPan <> nil) then hashShotPan.put(rec.trigRec.tgShotPanelID, High(TriggersTable));
 
         g_Game_StepLoading();
       end;
     end;
 
-  // Ñîçäàåì ïàíåëè:
-    if panels <> nil then
+    // Ñîçäàåì ïàíåëè
+    if (panels <> nil) and (panels.count > 0) then
     begin
       e_WriteLog('  Setting up trigger links...', MSG_NOTIFY);
-      g_Game_SetLoadingText(_lc[I_LOAD_LINK_TRIGGERS], High(panels), False);
+      g_Game_SetLoadingText(_lc[I_LOAD_LINK_TRIGGERS], panels.count-1, False);
 
-      for a := 0 to High(panels) do
+      pannum := -1;
+      for rec in panels do
       begin
+        Inc(pannum);
+        texrec := nil;
         SetLength(AddTextures, 0);
         trigRef := False;
         CurTex := -1;
-        if _textures <> nil then
-          begin
-            texture := _textures[panels[a].TextureNum];
-            ok := True;
-          end
-        else
-          ok := False;
+        ok := false;
+
+        if (_textures <> nil) then
+        begin
+          texrec := rec.TextureRec;
+          ok := (texrec <> nil);
+        end;
 
         if ok then
         begin
-        // Ñìîòðèì, ññûëàþòñÿ ëè íà ýòó ïàíåëü òðèããåðû.
-        // Åñëè äà - òî íàäî ñîçäàòü åùå òåêñòóð:
-          ok := False;
+          // Ñìîòðèì, ññûëàþòñÿ ëè íà ýòó ïàíåëü òðèããåðû.
+          // Åñëè äà - òî íàäî ñîçäàòü åùå òåêñòóð
+          ok := false;
           if (TriggersTable <> nil) and (_textures <> nil) then
+          begin
             for b := 0 to High(TriggersTable) do
-              if (TriggersTable[b].TexturePanel = a)
-              or (TriggersTable[b].ShotPanel = a) then
+            begin
+              if (TriggersTable[b].texPan = rec) or (TriggersTable[b].shotPan = rec) then
               begin
                 trigRef := True;
                 ok := True;
-                Break;
+                break;
               end;
+            end;
+          end;
         end;
 
         if ok then
-        begin // Åñòü ññûëêè òðèããåðîâ íà ýòó ïàíåëü
-          SetLength(s, 64);
-          CopyMemory(@s[1], @texture.Resource[0], 64);
-        // Èçìåðÿåì äëèíó:
-          Len := Length(s);
-          for c := Len downto 1 do
-            if s[c] <> #0 then
-            begin
-              Len := c;
-              Break;
-            end;
-          SetLength(s, Len);
+        begin
+          // Åñòü ññûëêè òðèããåðîâ íà ýòó ïàíåëü
+          s := texrec.Resource;
 
-        // Ñïåö-òåêñòóðû çàïðåùåíû:
+          // Ñïåö-òåêñòóðû çàïðåùåíû
           if g_Map_IsSpecialTexture(s) then
-            ok := False
+          begin
+            ok := false
+          end
           else
-        // Îïðåäåëÿåì íàëè÷èå è ïîëîæåíèå öèôð â êîíöå ñòðîêè:
+          begin
+            // Îïðåäåëÿåì íàëè÷èå è ïîëîæåíèå öèôð â êîíöå ñòðîêè
             ok := g_Texture_NumNameFindStart(s);
+          end;
 
-        // Åñëè ok, çíà÷èò åñòü öèôðû â êîíöå.
-        // Çàãðóæàåì òåêñòóðû ñ îñòàëüíûìè #:
+          // Åñëè ok, çíà÷èò åñòü öèôðû â êîíöå.
+          // Çàãðóæàåì òåêñòóðû ñ îñòàëüíûìè #
           if ok then
           begin
             k := NNF_NAME_BEFORE;
-          // Öèêë ïî èçìåíåíèþ èìåíè òåêñòóðû:
-            while ok or (k = NNF_NAME_BEFORE) or
-                  (k = NNF_NAME_EQUALS) do
+            // Öèêë ïî èçìåíåíèþ èìåíè òåêñòóðû
+            while ok or (k = NNF_NAME_BEFORE) or (k = NNF_NAME_EQUALS) do
             begin
               k := g_Texture_NumNameFindNext(TexName);
 
-              if (k = NNF_NAME_BEFORE) or
-                 (k = NNF_NAME_AFTER) then
+              if (k = NNF_NAME_BEFORE) or (k = NNF_NAME_AFTER) then
+              begin
+                // Ïðîáóåì äîáàâèòü íîâóþ òåêñòóðó
+                if texrec.Anim then
                 begin
-                // Ïðîáóåì äîáàâèòü íîâóþ òåêñòóðó:
-                  if ByteBool(texture.Anim) then
-                    begin // Íà÷àëüíàÿ - àíèìèðîâàííàÿ, èùåì àíèìèðîâàííóþ
-                      isAnim := True;
-                      ok := CreateAnimTexture(TexName, FileName, False) >= 0;
-                      if not ok then
-                      begin // Íåò àíèìèðîâàííîé, èùåì îáû÷íóþ
-                        isAnim := False;
-                        ok := CreateTexture(TexName, FileName, False) >= 0;
-                      end;
-                    end
-                  else
-                    begin // Íà÷àëüíàÿ - îáû÷íàÿ, èùåì îáû÷íóþ
-                      isAnim := False;
-                      ok := CreateTexture(TexName, FileName, False) >= 0;
-                      if not ok then
-                      begin // Íåò îáû÷íîé, èùåì àíèìèðîâàííóþ
-                        isAnim := True;
-                        ok := CreateAnimTexture(TexName, FileName, False) >= 0;
-                      end;
-                    end;
-
-                // Îíà ñóùåñòâóåò. Çàíîñèì åå ID â ñïèñîê ïàíåëè:
-                  if ok then
+                  // Íà÷àëüíàÿ - àíèìèðîâàííàÿ, èùåì àíèìèðîâàííóþ
+                  isAnim := True;
+                  ok := CreateAnimTexture(TexName, FileName, False) >= 0;
+                  if not ok then
                   begin
-                    for c := 0 to High(Textures) do
-                      if Textures[c].TextureName = TexName then
-                      begin
-                        SetLength(AddTextures, Length(AddTextures)+1);
-                        AddTextures[High(AddTextures)].Texture := c;
-                        AddTextures[High(AddTextures)].Anim := isAnim;
-                        Break;
-                      end;
+                    // Íåò àíèìèðîâàííîé, èùåì îáû÷íóþ
+                    isAnim := False;
+                    ok := CreateTexture(TexName, FileName, False) >= 0;
                   end;
                 end
+                else
+                begin
+                  // Íà÷àëüíàÿ - îáû÷íàÿ, èùåì îáû÷íóþ
+                  isAnim := False;
+                  ok := CreateTexture(TexName, FileName, False) >= 0;
+                  if not ok then
+                  begin
+                    // Íåò îáû÷íîé, èùåì àíèìèðîâàííóþ
+                    isAnim := True;
+                    ok := CreateAnimTexture(TexName, FileName, False) >= 0;
+                  end;
+                end;
+
+                // Îíà ñóùåñòâóåò. Çàíîñèì åå ID â ñïèñîê ïàíåëè
+                if ok then
+                begin
+                  for c := 0 to High(Textures) do
+                  begin
+                    if (Textures[c].TextureName = TexName) then
+                    begin
+                      SetLength(AddTextures, Length(AddTextures)+1);
+                      AddTextures[High(AddTextures)].Texture := c;
+                      AddTextures[High(AddTextures)].Anim := isAnim;
+                      break;
+                    end;
+                  end;
+                end;
+              end
               else
+              begin
                 if k = NNF_NAME_EQUALS then
-                  begin
-                  // Çàíîñèì òåêóùóþ òåêñòóðó íà ñâîå ìåñòî:
-                    SetLength(AddTextures, Length(AddTextures)+1);
-                    AddTextures[High(AddTextures)].Texture := panels[a].TextureNum;
-                    AddTextures[High(AddTextures)].Anim := ByteBool(texture.Anim);
-                    CurTex := High(AddTextures);
-                    ok := True;
-                  end
+                begin
+                  // Çàíîñèì òåêóùóþ òåêñòóðó íà ñâîå ìåñòî
+                  SetLength(AddTextures, Length(AddTextures)+1);
+                  //AddTextures[High(AddTextures)].Texture := _texnummap[rec.TextureNum]; //panels[a].TextureNum;
+                  AddTextures[High(AddTextures)].Texture := rec.tagInt; //panels[a].TextureNum;
+                  AddTextures[High(AddTextures)].Anim := texrec.Anim;
+                  CurTex := High(AddTextures);
+                  ok := true;
+                end
                 else // NNF_NO_NAME
-                  ok := False;
+                begin
+                  ok := false;
+                end;
+              end;
             end; // while ok...
 
-            ok := True;
+            ok := true;
           end; // if ok - åñòü ñìåæíûå òåêñòóðû
         end; // if ok - ññûëàþòñÿ òðèããåðû
 
         if not ok then
         begin
-        // Çàíîñèì òîëüêî òåêóùóþ òåêñòóðó:
+          // Çàíîñèì òîëüêî òåêóùóþ òåêñòóðó
           SetLength(AddTextures, 1);
-          AddTextures[0].Texture := panels[a].TextureNum;
-          AddTextures[0].Anim := ByteBool(texture.Anim);
+          AddTextures[0].Texture := rec.tagInt; //panels[a].TextureNum;
+          AddTextures[0].Anim := false;
+          if (texrec <> nil) then AddTextures[0].Anim := texrec.Anim;
           CurTex := 0;
         end;
 
         //e_WriteLog(Format('panel #%d: TextureNum=%d; ht=%d; ht1=%d; atl=%d', [a, panels[a].TextureNum, High(_textures), High(Textures), High(AddTextures)]), MSG_NOTIFY);
 
-      // Ñîçäàåì ïàíåëü è çàïîìèíàåì åå íîìåð:
-        PanelID := CreatePanel(panels[a], AddTextures, CurTex, trigRef);
+        // Ñîçäàåì ïàíåëü è çàïîìèíàåì åå íîìåð
+        PanelID := CreatePanel(rec, AddTextures, CurTex, trigRef);
+        //e_LogWritefln('panel #%s of type %s got id #%s', [pannum, rec.PanelType, PanelID]);
 
-      // Åñëè èñïîëüçóåòñÿ â òðèããåðàõ, òî ñòàâèì òî÷íûé ID:
-        if TriggersTable <> nil then
+        // Åñëè èñïîëüçóåòñÿ â òðèããåðàõ, òî ñòàâèì òî÷íûé ID
+        if hashTextPan.get(pannum, b) then TriggersTable[b].texPanIdx := PanelID;
+        if hashLiftPan.get(pannum, b) then TriggersTable[b].LiftPanelIdx := PanelID;
+        if hashDoorPan.get(pannum, b) then TriggersTable[b].DoorPanelIdx := PanelID;
+        if hashShotPan.get(pannum, b) then TriggersTable[b].ShotPanelIdx := PanelID;
+
+        (*
+        if (TriggersTable <> nil) then
+        begin
           for b := 0 to High(TriggersTable) do
           begin
-          // Òðèããåð äâåðè/ëèôòà:
-            if (TriggersTable[b].LiftPanel = a) or
-               (TriggersTable[b].DoorPanel = a) then
-              TTriggerData(triggers[b].DATA).PanelID := PanelID;
-          // Òðèããåð ñìåíû òåêñòóðû:
-            if TriggersTable[b].TexturePanel = a then
-              triggers[b].TexturePanel := PanelID;
-          // Òðèããåð "Òóðåëü":
-            if TriggersTable[b].ShotPanel = a then
-              TTriggerData(triggers[b].DATA).ShotPanelID := PanelID;
+            if (TriggersTable[b].texPan = rec) then TriggersTable[b].texPanIdx := PanelID;
+            if (TriggersTable[b].liftPan = rec) then TriggersTable[b].LiftPanelIdx := PanelID;
+            if (TriggersTable[b].doorPan = rec) then TriggersTable[b].DoorPanelIdx := PanelID;
+            if (TriggersTable[b].shotPan = rec) then TriggersTable[b].ShotPanelIdx := PanelID;
+            {
+            // Òðèããåð äâåðè/ëèôòà
+            if (TriggersTable[b].LiftPanel = pannum) or
+               (TriggersTable[b].DoorPanel = pannum) then
+              //TTriggerData(TriggersTable[b].trigrec.DATA).PanelID := PanelID;
+              TriggersTable[b].trigrec.trigRec.trigPanelID := PanelID;
+            // Òðèããåð ñìåíû òåêñòóðû
+            if TriggersTable[b].texPanIdx = pannum then
+              TriggersTable[b].trigrec.TexturePanel := PanelID;
+            // Òðèããåð "Òóðåëü"
+            if TriggersTable[b].ShotPanel = pannum then
+              TriggersTable[b].trigrec.trigRec.trigShotPanelID := PanelID;
+            }
           end;
+        end;
+        *)
 
         g_Game_StepLoading();
       end;
     end;
 
+    (*
+    begin
+      for b := 0 to High(TriggersTable) do
+      begin
+        // Òðèããåð äâåðè/ëèôòà
+        if (TriggersTable[b].texPan <> nil) then e_LogWritefln('trigger #%s: textPan=%s; panidx=%s', [b, TriggersTable[b].texPanIdx, mapReader.panelIndex[TriggersTable[b].texPan]]);
+        if (TriggersTable[b].liftPan <> nil) then e_LogWritefln('trigger #%s: liftPan=%s; panidx=%s', [b, TriggersTable[b].LiftPanelIdx, mapReader.panelIndex[TriggersTable[b].liftPan]]);
+        if (TriggersTable[b].doorPan <> nil) then e_LogWritefln('trigger #%s: doorPan=%s; panidx=%s', [b, TriggersTable[b].DoorPanelIdx, mapReader.panelIndex[TriggersTable[b].doorPan]]);
+        if (TriggersTable[b].shotPan <> nil) then e_LogWritefln('trigger #%s: shotPan=%s; panidx=%s', [b, TriggersTable[b].ShotPanelIdx, mapReader.panelIndex[TriggersTable[b].shotPan]]);
+      end;
+    end;
+    *)
+
     // create map grid, init other grids (for monsters, for example)
     e_WriteLog('Creating map grid', MSG_NOTIFY);
     mapCreateGrid();
 
-  // Åñëè íå LoadState, òî ñîçäàåì òðèããåðû:
-    if (triggers <> nil) and not gLoadGameMode then
+    // Åñëè íå LoadState, òî ñîçäàåì òðèããåðû
+    if (triggers <> nil) and (panels <> nil) and (not gLoadGameMode) then
     begin
-      e_LogWritefln('  Creating triggers (%d)...', [Length(triggers)]);
+      e_LogWritefln('  Creating triggers (%d)...', [triggers.count]);
       g_Game_SetLoadingText(_lc[I_LOAD_CREATE_TRIGGERS], 0, False);
-    // Óêàçûâàåì òèï ïàíåëè, åñëè åñòü:
-      for a := 0 to High(triggers) do
+      // Óêàçûâàåì òèï ïàíåëè, åñëè åñòü
+      trignum := -1;
+      for rec in triggers do
       begin
-        if (triggers[a].TexturePanel <> -1) then
+        Inc(trignum);
+        if (TriggersTable[trignum].texPan <> nil) then b := TriggersTable[trignum].texPan.PanelType else b := 0;
+        if (TriggersTable[trignum].shotPan <> nil) then c := TriggersTable[trignum].shotPan.PanelType else c := 0;
+        (*
+        if (rec.TexturePanel <> -1) then
         begin
-          if (TriggersTable[a].TexturePanel < 0) or (TriggersTable[a].TexturePanel > High(panels)) then
+          {
+          if (TriggersTable[trignum].TexturePanel < 0) or (TriggersTable[trignum].TexturePanel >= panels.count) then
           begin
             e_WriteLog('error loading map: invalid panel index for trigger', MSG_FATALERROR);
             result := false;
             exit;
           end;
-          b := panels[TriggersTable[a].TexturePanel].PanelType;
+          }
+          //b := panels[TriggersTable[a].TexturePanel].PanelType;
+          //b := mapReader.panel[TriggersTable[trignum].texPanIdx].PanelType;
+          assert(TriggersTable[trignum].texPanIdx >= 0);
+          b := TriggersTable[trignum].texPanIdx;
         end
         else
         begin
           b := 0;
         end;
-        if (triggers[a].TriggerType = TRIGGER_SHOT) and (TTriggerData(triggers[a].DATA).ShotPanelID <> -1) then
+        e_LogWritefln('trigger #%s: type=%s; texPanIdx=%s; b=%s', [trignum, rec.TriggerType, TriggersTable[trignum].texPanIdx, b]);
+        if (rec.TriggerType = TRIGGER_SHOT) then e_LogWritefln('  SHOT: shotpanidx=%s', [rec.trigRec.trigShotPanelID]);
+        if (rec.TriggerType = TRIGGER_SHOT) and {(rec.trigRec.trigShotPanelID <> -1)} (TriggersTable[trignum].shotPan <> nil) then
         begin
-          c := panels[TriggersTable[a].ShotPanel].PanelType
+          //c := panels[TriggersTable[a].ShotPanel].PanelType;
+          //c := mapReader.panel[TriggersTable[trignum].ShotPanel].PanelType;
+          assert(TriggersTable[trignum].ShotPanelIdx >= 0);
+          c := TriggersTable[trignum].ShotPanelIdx;
         end
         else
         begin
           c := 0;
         end;
-        CreateTrigger(triggers[a], b, c);
+        *)
+        //e_LogWritefln('creating trigger #%s; texpantype=%s; shotpantype=%s (%d,%d)', [trignum, b, c, TriggersTable[trignum].texPanIdx, TriggersTable[trignum].ShotPanelIdx]);
+        CreateTrigger(rec, TriggersTable[trignum].texPanIdx, TriggersTable[trignum].ShotPanelIdx, Word(b), Word(c));
       end;
     end;
 
-  // Çàãðóçêà ïðåäìåòîâ:
+    // Çàãðóçêà ïðåäìåòîâ
     e_WriteLog('  Loading items...', MSG_NOTIFY);
     g_Game_SetLoadingText(_lc[I_LOAD_ITEMS], 0, False);
-    items := GetItems(mapReader);
 
-  // Åñëè íå LoadState, òî ñîçäàåì ïðåäìåòû:
+    // Åñëè íå LoadState, òî ñîçäàåì ïðåäìåòû
     if (items <> nil) and not gLoadGameMode then
     begin
       e_WriteLog('  Spawning items...', MSG_NOTIFY);
       g_Game_SetLoadingText(_lc[I_LOAD_CREATE_ITEMS], 0, False);
-      for a := 0 to High(items) do
-        CreateItem(Items[a]);
+      for rec in items do CreateItem(rec);
     end;
 
-  // Çàãðóçêà îáëàñòåé:
+    // Çàãðóçêà îáëàñòåé
     e_WriteLog('  Loading areas...', MSG_NOTIFY);
     g_Game_SetLoadingText(_lc[I_LOAD_AREAS], 0, False);
-    areas := GetAreas(mapReader);
 
-  // Åñëè íå LoadState, òî ñîçäàåì îáëàñòè:
+    // Åñëè íå LoadState, òî ñîçäàåì îáëàñòè
     if areas <> nil then
     begin
       e_WriteLog('  Creating areas...', MSG_NOTIFY);
       g_Game_SetLoadingText(_lc[I_LOAD_CREATE_AREAS], 0, False);
-      for a := 0 to High(areas) do
-        CreateArea(areas[a]);
+      for rec in areas do CreateArea(rec);
     end;
 
-  // Çàãðóçêà ìîíñòðîâ:
+    // Çàãðóçêà ìîíñòðîâ
     e_WriteLog('  Loading monsters...', MSG_NOTIFY);
     g_Game_SetLoadingText(_lc[I_LOAD_MONSTERS], 0, False);
-    monsters := GetMonsters(mapReader);
 
     gTotalMonsters := 0;
 
-  // Åñëè íå LoadState, òî ñîçäàåì ìîíñòðîâ:
+    // Åñëè íå LoadState, òî ñîçäàåì ìîíñòðîâ
     if (monsters <> nil) and not gLoadGameMode then
     begin
       e_WriteLog('  Spawning monsters...', MSG_NOTIFY);
       g_Game_SetLoadingText(_lc[I_LOAD_CREATE_MONSTERS], 0, False);
-      for a := 0 to High(monsters) do
-        CreateMonster(monsters[a]);
+      for rec in monsters do CreateMonster(rec);
     end;
 
-    MapReader.Free();
+    //MapReader.Free();
+    gCurrentMap := mapReader;
+    mapReader := nil;
 
-  // Çàãðóçêà íåáà:
+    // Çàãðóçêà íåáà
     if gMapInfo.SkyName <> '' then
     begin
       e_WriteLog('  Loading sky: ' + gMapInfo.SkyName, MSG_NOTIFY);
@@ -1956,7 +2029,7 @@ begin
         g_FatalError(Format(_lc[I_GAME_ERROR_SKY], [s]));
     end;
 
-  // Çàãðóçêà ìóçûêè:
+    // Çàãðóçêà ìóçûêè
     ok := False;
     if gMapInfo.MusicName <> '' then
     begin
@@ -1978,7 +2051,7 @@ begin
         g_FatalError(Format(_lc[I_GAME_ERROR_MUSIC], [s]));
     end;
 
-  // Îñòàëüíûå óñòàíâêè:
+    // Îñòàëüíûå óñòàíâêè
     CreateDoorMap();
     CreateLiftMap();
 
@@ -1986,11 +2059,10 @@ begin
     g_Weapon_Init();
     g_Monsters_Init();
 
-  // Åñëè íå LoadState, òî ñîçäàåì êàðòó ñòîëêíîâåíèé:
-    if not gLoadGameMode then
-      g_GFX_Init();
+    // Åñëè íå LoadState, òî ñîçäàåì êàðòó ñòîëêíîâåíèé:
+    if not gLoadGameMode then g_GFX_Init();
 
-  // Ñáðîñ ëîêàëüíûõ ìàññèâîâ:
+    // Ñáðîñ ëîêàëüíûõ ìàññèâîâ:
     _textures := nil;
     panels := nil;
     items := nil;
@@ -1999,16 +2071,23 @@ begin
     TriggersTable := nil;
     AddTextures := nil;
 
-  // Âêëþ÷àåì ìóçûêó, åñëè ýòî íå çàãðóçêà:
+    // Âêëþ÷àåì ìóçûêó, åñëè ýòî íå çàãðóçêà:
     if ok and (not gLoadGameMode) then
-      begin
-        gMusic.SetByName(gMapInfo.MusicName);
-        gMusic.Play();
-      end
+    begin
+      gMusic.SetByName(gMapInfo.MusicName);
+      gMusic.Play();
+    end
     else
+    begin
       gMusic.SetByName('');
+    end;
   finally
     sfsGCEnable(); // enable releasing unused volumes
+    mapReader.Free();
+    hashTextPan.Free();
+    hashLiftPan.Free();
+    hashDoorPan.Free();
+    hashShotPan.Free();
   end;
 
   e_WriteLog('Done loading map.', MSG_NOTIFY);
@@ -2019,7 +2098,7 @@ function g_Map_GetMapInfo(Res: String): TMapInfo;
 var
   WAD: TWADFile;
   MapReader: TDynRecord;
-  Header: TMapHeaderRec_1;
+  //Header: TMapHeaderRec_1;
   FileName: String;
   Data: Pointer;
   Len: Integer;
@@ -2068,26 +2147,31 @@ begin
   FreeMem(Data);
   //MapReader.Free();
 
-  if (mapReader <> nil) then Header := GetMapHeader(mapReader) else FillChar(Header, sizeof(Header), 0);
-  MapReader.Free();
+  //if (mapReader <> nil) then Header := GetMapHeader(mapReader) else FillChar(Header, sizeof(Header), 0);
+  //MapReader.Free();
 
-  if (Header.Width > 0) and (Header.Height > 0) then
+  if (mapReader.Width > 0) and (mapReader.Height > 0) then
   begin
-    Result.Name := Header.MapName;
-    Result.Description := Header.MapDescription;
+    Result.Name := mapReader.MapName;
+    Result.Description := mapReader.MapDesc;
+    Result.Map := Res;
+    Result.Author := mapReader.MapAuthor;
+    Result.Height := mapReader.Height;
+    Result.Width := mapReader.Width;
   end
   else
   begin
     g_Console_Add(Format(_lc[I_GAME_ERROR_MAP_LOAD], [Res]), True);
-    ZeroMemory(@Header, SizeOf(Header));
+    //ZeroMemory(@Header, SizeOf(Header));
     Result.Name := _lc[I_GAME_ERROR_MAP_SELECT];
     Result.Description := _lc[I_GAME_ERROR_MAP_SELECT];
+    Result.Map := Res;
+    Result.Author := '';
+    Result.Height := 0;
+    Result.Width := 0;
   end;
 
-  Result.Map := Res;
-  Result.Author := Header.MapAuthor;
-  Result.Height := Header.Height;
-  Result.Width := Header.Width;
+  mapReader.Free();
 end;
 
 function g_Map_GetMapsList(WADName: string): SArray;
index 936141adbc58ee1d33acae7c7708b42ef064dcfe..f77bdcadd97dbafa8ea20c15c44e4f473ce80806 100644 (file)
@@ -2517,10 +2517,10 @@ begin
         begin
           if SPlaying then
           begin
-            if Data.Local then
-              Sound.PlayVolumeAt(X+(Width div 2), Y+(Height div 2), Data.Volume/255.0)
+            if trigData.trigLocal then
+              Sound.PlayVolumeAt(X+(Width div 2), Y+(Height div 2), trigData.trigVolume/255.0)
             else
-              Sound.PlayPanVolume((Data.Pan-127.0)/128.0, Data.Volume/255.0);
+              Sound.PlayPanVolume((trigData.trigPan-127.0)/128.0, trigData.trigVolume/255.0);
             Sound.SetPosition(SPos);
           end
           else
index c46cf8c456d1f591698f72dc96593132c17680e0..5eec8e780a546456cf85a75a25c04b6160b08b62 100644 (file)
@@ -19,7 +19,7 @@ unit g_panel;
 interface
 
 uses
-  MAPDEF, BinEditor, g_textures;
+  MAPDEF, BinEditor, g_textures, xdynrec;
 
 type
   TAddTextureArray = Array of
@@ -63,7 +63,7 @@ type
     tag:              Integer; // used in coldets and such; sorry
     proxyId:          Integer; // proxy id in map grid (DO NOT USE!)
 
-    constructor Create(PanelRec: TPanelRec_1;
+    constructor Create(PanelRec: TDynRecord;
                        AddTextures: TAddTextureArray;
                        CurTex: Integer;
                        var Textures: TLevelTextureArray);
@@ -102,7 +102,7 @@ const
 
 { T P a n e l : }
 
-constructor TPanel.Create(PanelRec: TPanelRec_1;
+constructor TPanel.Create(PanelRec: TDynRecord;
                           AddTextures: TAddTextureArray;
                           CurTex: Integer;
                           var Textures: TLevelTextureArray);
index c327fdb55c2afcd0257ec015562191cdcc0aade1..be680ecb8e9f7e4698e3d0648b135d4b737c3d54 100644 (file)
@@ -20,7 +20,7 @@ interface
 
 uses
   MAPDEF, e_graphics, g_basic, g_sound,
-  BinEditor;
+  BinEditor, xdynrec;
 
 type
   TActivator = record
@@ -60,7 +60,11 @@ type
     ShotAmmoCount:    Word;
     ShotReloadTime:   Integer;
 
-    Data:             TTriggerData;
+    trigShotPanelId: Integer;
+    trigPanelId: Integer;
+
+    //TrigData:             TTriggerData;
+    trigData: TDynRecord; // triggerdata; owned by trigger
   end;
 
 function g_Triggers_Create(Trigger: TTrigger): DWORD;
@@ -631,28 +635,28 @@ end;
 procedure MakeShot(var Trigger: TTrigger; wx, wy, dx, dy: Integer; TargetUID: Word);
 begin
   with Trigger do
-    if (Data.ShotAmmo = 0) or
-       ((Data.ShotAmmo > 0) and (ShotAmmoCount > 0)) then
+    if (trigData.trigShotAmmo = 0) or
+       ((trigData.trigShotAmmo > 0) and (ShotAmmoCount > 0)) then
     begin
-      if (Data.ShotPanelID <> -1) and (ShotPanelTime = 0) then
+      if (trigShotPanelID <> -1) and (ShotPanelTime = 0) then
       begin
-        g_Map_SwitchTexture(ShotPanelType, Data.ShotPanelID);
+        g_Map_SwitchTexture(ShotPanelType, trigShotPanelID);
         ShotPanelTime := 4; // òèêîâ íà âñïûøêó âûñòðåëà
       end;
 
-      if Data.ShotIntSight > 0 then
+      if trigData.trigShotIntSight > 0 then
         ShotSightTimeout := 180; // ~= 5 ñåêóíä
 
       if ShotAmmoCount > 0 then Dec(ShotAmmoCount);
 
-      dx := dx + Random(Data.ShotAccuracy) - Random(Data.ShotAccuracy);
-      dy := dy + Random(Data.ShotAccuracy) - Random(Data.ShotAccuracy);
+      dx := dx + Random(trigData.trigShotAccuracy) - Random(trigData.trigShotAccuracy);
+      dy := dy + Random(trigData.trigShotAccuracy) - Random(trigData.trigShotAccuracy);
 
-      tr_SpawnShot(Data.ShotType, wx, wy, dx, dy, Data.ShotSound, TargetUID);
+      tr_SpawnShot(trigData.trigShotType, wx, wy, dx, dy, trigData.trigShotSound, TargetUID);
     end
     else
-      if (Data.ShotIntReload > 0) and (ShotReloadTime = 0) then
-        ShotReloadTime := Data.ShotIntReload; // òèêîâ íà ïåðåçàðÿäêó ïóøêè
+      if (trigData.trigShotIntReload > 0) and (ShotReloadTime = 0) then
+        ShotReloadTime := trigData.trigShotIntReload; // òèêîâ íà ïåðåçàðÿäêó ïóøêè
 end;
 
 procedure tr_MakeEffect(X, Y, VX, VY: Integer; T, ST, CR, CG, CB: Byte; Silent, Send: Boolean);
@@ -959,11 +963,11 @@ begin
   begin
     if TriggerType <> TRIGGER_SHOT then
       Exit;
-    Result := (Data.ShotAim and TRIGGER_SHOT_AIM_ALLMAP > 0)
+    Result := (trigData.trigShotAim and TRIGGER_SHOT_AIM_ALLMAP > 0)
               or g_Obj_Collide(X, Y, Width, Height, Obj);
-    if Result and (Data.ShotAim and TRIGGER_SHOT_AIM_TRACE > 0) then
-      Result := g_TraceVector(Data.ShotPos.X,
-                              Data.ShotPos.Y,
+    if Result and (trigData.trigShotAim and TRIGGER_SHOT_AIM_TRACE > 0) then
+      Result := g_TraceVector(trigData.trigShotPos.X,
+                              trigData.trigShotPos.Y,
                               Obj^.X + Obj^.Rect.X + (Obj^.Rect.Width div 2),
                               Obj^.Y + Obj^.Rect.Y + (Obj^.Rect.Height div 2));
   end;
@@ -1045,7 +1049,7 @@ begin
           g_Sound_PlayEx('SOUND_GAME_SWITCH0');
           if g_Game_IsNet then MH_SEND_Sound(X, Y, 'SOUND_GAME_SWITCH0');
           gExitByTrigger := True;
-          g_Game_ExitLevel(Data.MapName);
+          g_Game_ExitLevel(trigData.trigMapName);
           TimeOut := 18;
           Result := True;
 
@@ -1055,37 +1059,37 @@ begin
       TRIGGER_TELEPORT:
         begin
           Result := tr_Teleport(ActivateUID,
-                                Data.TargetPoint.X, Data.TargetPoint.Y,
-                                Data.TlpDir, Data.silent_teleport,
-                                Data.d2d_teleport);
+                                trigData.trigTargetPoint.X, trigData.trigTargetPoint.Y,
+                                trigData.trigTlpDir, trigData.trigsilent_teleport,
+                                trigData.trigd2d_teleport);
           TimeOut := 0;
         end;
 
       TRIGGER_OPENDOOR:
         begin
-          Result := tr_OpenDoor(Data.PanelID, Data.NoSound, Data.d2d_doors);
+          Result := tr_OpenDoor(trigPanelID, trigData.trigNoSound, trigData.trigd2d_doors);
           TimeOut := 0;
         end;
 
       TRIGGER_CLOSEDOOR:
         begin
-          Result := tr_CloseDoor(Data.PanelID, Data.NoSound, Data.d2d_doors);
+          Result := tr_CloseDoor(trigPanelID, trigData.trigNoSound, trigData.trigd2d_doors);
           TimeOut := 0;
         end;
 
       TRIGGER_DOOR, TRIGGER_DOOR5:
         begin
-          if Data.PanelID <> -1 then
+          if trigPanelID <> -1 then
           begin
-            if gWalls[Data.PanelID].Enabled then
+            if gWalls[trigPanelID].Enabled then
               begin
-                Result := tr_OpenDoor(Data.PanelID, Data.NoSound, Data.d2d_doors);
+                Result := tr_OpenDoor(trigPanelID, trigData.trigNoSound, trigData.trigd2d_doors);
 
                 if TriggerType = TRIGGER_DOOR5 then
                   DoorTime := 180;
               end
             else
-              Result := tr_CloseDoor(Data.PanelID, Data.NoSound, Data.d2d_doors);
+              Result := tr_CloseDoor(trigPanelID, trigData.trigNoSound, trigData.trigd2d_doors);
 
             if Result then
               TimeOut := 18;
@@ -1094,7 +1098,7 @@ begin
 
       TRIGGER_CLOSETRAP, TRIGGER_TRAP:
         begin
-          tr_CloseTrap(Data.PanelID, Data.NoSound, Data.d2d_doors);
+          tr_CloseTrap(trigPanelID, trigData.trigNoSound, trigData.trigd2d_doors);
 
           if TriggerType = TRIGGER_TRAP then
             begin
@@ -1115,7 +1119,7 @@ begin
           PressCount := PressCount + 1;
 
           if PressTime = -1 then
-            PressTime := Data.Wait;
+            PressTime := trigData.trigWait;
 
           if coolDown then
             TimeOut := 18
@@ -1139,10 +1143,10 @@ begin
 
       TRIGGER_LIFTUP:
         begin
-          Result := tr_SetLift(Data.PanelID, 0, Data.NoSound, Data.d2d_doors);
+          Result := tr_SetLift(trigPanelID, 0, trigData.trigNoSound, trigData.trigd2d_doors);
           TimeOut := 0;
 
-          if (not Data.NoSound) and Result then begin
+          if (not trigData.trigNoSound) and Result then begin
             g_Sound_PlayExAt('SOUND_GAME_SWITCH0',
                              X + (Width div 2),
                              Y + (Height div 2));
@@ -1155,10 +1159,10 @@ begin
 
       TRIGGER_LIFTDOWN:
         begin
-          Result := tr_SetLift(Data.PanelID, 1, Data.NoSound, Data.d2d_doors);
+          Result := tr_SetLift(trigPanelID, 1, trigData.trigNoSound, trigData.trigd2d_doors);
           TimeOut := 0;
 
-          if (not Data.NoSound) and Result then begin
+          if (not trigData.trigNoSound) and Result then begin
             g_Sound_PlayExAt('SOUND_GAME_SWITCH0',
                              X + (Width div 2),
                              Y + (Height div 2));
@@ -1171,13 +1175,13 @@ begin
 
       TRIGGER_LIFT:
         begin
-          Result := tr_SetLift(Data.PanelID, 3, Data.NoSound, Data.d2d_doors);
+          Result := tr_SetLift(trigPanelID, 3, trigData.trigNoSound, trigData.trigd2d_doors);
 
           if Result then
           begin
             TimeOut := 18;
 
-            if (not Data.NoSound) and Result then begin
+            if (not trigData.trigNoSound) and Result then begin
               g_Sound_PlayExAt('SOUND_GAME_SWITCH0',
                                X + (Width div 2),
                                Y + (Height div 2));
@@ -1191,7 +1195,7 @@ begin
 
       TRIGGER_TEXTURE:
         begin
-          if ByteBool(Data.ActivateOnce) then
+          if ByteBool(trigData.trigActivateOnce) then
             begin
               Enabled := False;
               TriggerType := TRIGGER_NONE;
@@ -1202,7 +1206,7 @@ begin
             else
               TimeOut := 0;
 
-          animonce := Data.AnimOnce;
+          animonce := trigData.trigAnimOnce;
           Result := True;
         end;
 
@@ -1210,17 +1214,17 @@ begin
         begin
           if Sound <> nil then
           begin
-            if Data.SoundSwitch and Sound.IsPlaying() then
+            if trigData.trigSoundSwitch and Sound.IsPlaying() then
               begin // Íóæíî âûêëþ÷èòü, åñëè èãðàë
                 Sound.Stop();
                 SoundPlayCount := 0;
                 Result := True;
               end
             else // (not Data.SoundSwitch) or (not Sound.IsPlaying())
-              if (Data.PlayCount > 0) or (not Sound.IsPlaying()) then
+              if (trigData.trigPlayCount > 0) or (not Sound.IsPlaying()) then
                 begin
-                  if Data.PlayCount > 0 then
-                    SoundPlayCount := Data.PlayCount
+                  if trigData.trigPlayCount > 0 then
+                    SoundPlayCount := trigData.trigPlayCount
                   else // 0 - èãðàåì áåñêîíå÷íî
                     SoundPlayCount := 1;
                   Result := True;
@@ -1230,10 +1234,10 @@ begin
         end;
 
       TRIGGER_SPAWNMONSTER:
-        if (Data.MonType in [MONSTER_DEMON..MONSTER_MAN]) then
+        if (trigData.trigMonType in [MONSTER_DEMON..MONSTER_MAN]) then
         begin
           Result := False;
-          if (Data.MonDelay > 0) and (actType <> ACTIVATE_CUSTOM) then
+          if (trigData.trigMonDelay > 0) and (actType <> ACTIVATE_CUSTOM) then
           begin
             AutoSpawn := not AutoSpawn;
             SpawnCooldown := 0;
@@ -1241,34 +1245,34 @@ begin
             Result := True;
           end;
 
-          if ((Data.MonDelay = 0) and (actType <> ACTIVATE_CUSTOM))
-          or ((Data.MonDelay > 0) and (actType = ACTIVATE_CUSTOM)) then
-            for k := 1 to Data.MonCount do
+          if ((trigData.trigMonDelay = 0) and (actType <> ACTIVATE_CUSTOM))
+          or ((trigData.trigMonDelay > 0) and (actType = ACTIVATE_CUSTOM)) then
+            for k := 1 to trigData.trigMonCount do
             begin
-              if (actType = ACTIVATE_CUSTOM) and (Data.MonDelay > 0) then
-                SpawnCooldown := Data.MonDelay;
-              if (Data.MonMax > 0) and (SpawnedCount >= Data.MonMax) then
+              if (actType = ACTIVATE_CUSTOM) and (trigData.trigMonDelay > 0) then
+                SpawnCooldown := trigData.trigMonDelay;
+              if (trigData.trigMonMax > 0) and (SpawnedCount >= trigData.trigMonMax) then
                 Break;
 
-              mon := g_Monsters_Create(Data.MonType,
-                     Data.MonPos.X, Data.MonPos.Y,
-                     TDirection(Data.MonDir), True);
+              mon := g_Monsters_Create(trigData.trigMonType,
+                     trigData.trigMonPos.X, trigData.trigMonPos.Y,
+                     TDirection(trigData.trigMonDir), True);
 
               Result := True;
 
             // Çäîðîâüå:
-              if (Data.MonHealth > 0) then
-                mon.SetHealth(Data.MonHealth);
+              if (trigData.trigMonHealth > 0) then
+                mon.SetHealth(trigData.trigMonHealth);
             // Óñòàíàâëèâàåì ïîâåäåíèå:
-              mon.MonsterBehaviour := Data.MonBehav;
+              mon.MonsterBehaviour := trigData.trigMonBehav;
               mon.FNoRespawn := True;
               if g_Game_IsNet then
                 MH_SEND_MonsterSpawn(mon.UID);
             // Èäåì èñêàòü öåëü, åñëè íàäî:
-              if Data.MonActive then
+              if trigData.trigMonActive then
                 mon.WakeUp();
 
-              if Data.MonType <> MONSTER_BARREL then Inc(gTotalMonsters);
+              if trigData.trigMonType <> MONSTER_BARREL then Inc(gTotalMonsters);
 
               if g_Game_IsNet then
               begin
@@ -1276,18 +1280,18 @@ begin
                 gMonstersSpawned[High(gMonstersSpawned)] := mon.UID;
               end;
 
-              if Data.MonMax > 0 then
+              if trigData.trigMonMax > 0 then
               begin
                 mon.SpawnTrigger := ID;
                 Inc(SpawnedCount);
               end;
 
-              case Data.MonEffect of
+              case trigData.trigMonEffect of
                 EFFECT_TELEPORT: begin
                   if g_Frames_Get(FramesID, 'FRAMES_TELEPORT') then
                   begin
                     Anim := TAnimation.Create(FramesID, False, 3);
-                    g_Sound_PlayExAt('SOUND_GAME_TELEPORT', Data.MonPos.X, Data.MonPos.Y);
+                    g_Sound_PlayExAt('SOUND_GAME_TELEPORT', trigData.trigMonPos.X, trigData.trigMonPos.Y);
                     g_GFX_OnceAnim(mon.Obj.X+mon.Obj.Rect.X+(mon.Obj.Rect.Width div 2)-32,
                                    mon.Obj.Y+mon.Obj.Rect.Y+(mon.Obj.Rect.Height div 2)-32, Anim);
                     Anim.Free();
@@ -1301,7 +1305,7 @@ begin
                   if g_Frames_Get(FramesID, 'FRAMES_ITEM_RESPAWN') then
                   begin
                     Anim := TAnimation.Create(FramesID, False, 4);
-                    g_Sound_PlayExAt('SOUND_ITEM_RESPAWNITEM', Data.MonPos.X, Data.MonPos.Y);
+                    g_Sound_PlayExAt('SOUND_ITEM_RESPAWNITEM', trigData.trigMonPos.X, trigData.trigMonPos.Y);
                     g_GFX_OnceAnim(mon.Obj.X+mon.Obj.Rect.X+(mon.Obj.Rect.Width div 2)-16,
                                    mon.Obj.Y+mon.Obj.Rect.Y+(mon.Obj.Rect.Height div 2)-16, Anim);
                     Anim.Free();
@@ -1315,7 +1319,7 @@ begin
                   if g_Frames_Get(FramesID, 'FRAMES_FIRE') then
                   begin
                     Anim := TAnimation.Create(FramesID, False, 4);
-                    g_Sound_PlayExAt('SOUND_FIRE', Data.MonPos.X, Data.MonPos.Y);
+                    g_Sound_PlayExAt('SOUND_FIRE', trigData.trigMonPos.X, trigData.trigMonPos.Y);
                     g_GFX_OnceAnim(mon.Obj.X+mon.Obj.Rect.X+(mon.Obj.Rect.Width div 2)-32,
                                    mon.Obj.Y+mon.Obj.Rect.Y+mon.Obj.Rect.Height-128, Anim);
                     Anim.Free();
@@ -1343,10 +1347,10 @@ begin
         end;
 
       TRIGGER_SPAWNITEM:
-        if (Data.ItemType in [ITEM_MEDKIT_SMALL..ITEM_MAX]) then
+        if (trigData.trigItemType in [ITEM_MEDKIT_SMALL..ITEM_MAX]) then
         begin
           Result := False;
-          if (Data.ItemDelay > 0) and (actType <> ACTIVATE_CUSTOM) then
+          if (trigData.trigItemDelay > 0) and (actType <> ACTIVATE_CUSTOM) then
           begin
             AutoSpawn := not AutoSpawn;
             SpawnCooldown := 0;
@@ -1354,36 +1358,36 @@ begin
             Result := True;
           end;
 
-          if ((Data.ItemDelay = 0) and (actType <> ACTIVATE_CUSTOM))
-          or ((Data.ItemDelay > 0) and (actType = ACTIVATE_CUSTOM)) then
-            if (not Data.ItemOnlyDM) or
+          if ((trigData.trigItemDelay = 0) and (actType <> ACTIVATE_CUSTOM))
+          or ((trigData.trigItemDelay > 0) and (actType = ACTIVATE_CUSTOM)) then
+            if (not trigData.trigItemOnlyDM) or
                (gGameSettings.GameMode in [GM_DM, GM_TDM, GM_CTF]) then
-              for k := 1 to Data.ItemCount do
+              for k := 1 to trigData.trigItemCount do
               begin
-                if (actType = ACTIVATE_CUSTOM) and (Data.ItemDelay > 0) then
-                  SpawnCooldown := Data.ItemDelay;
-                if (Data.ItemMax > 0) and (SpawnedCount >= Data.ItemMax) then
+                if (actType = ACTIVATE_CUSTOM) and (trigData.trigItemDelay > 0) then
+                  SpawnCooldown := trigData.trigItemDelay;
+                if (trigData.trigItemMax > 0) and (SpawnedCount >= trigData.trigItemMax) then
                   Break;
 
-                iid := g_Items_Create(Data.ItemPos.X, Data.ItemPos.Y,
-                  Data.ItemType, Data.ItemFalls, False, True);
+                iid := g_Items_Create(trigData.trigItemPos.X, trigData.trigItemPos.Y,
+                  trigData.trigItemType, trigData.trigItemFalls, False, True);
 
                 Result := True;
 
-                if Data.ItemMax > 0 then
+                if trigData.trigItemMax > 0 then
                 begin
                   it := g_Items_ByIdx(iid);
                   it.SpawnTrigger := ID;
                   Inc(SpawnedCount);
                 end;
 
-                case Data.ItemEffect of
+                case trigData.trigItemEffect of
                   EFFECT_TELEPORT: begin
                     it := g_Items_ByIdx(iid);
                     if g_Frames_Get(FramesID, 'FRAMES_TELEPORT') then
                     begin
                       Anim := TAnimation.Create(FramesID, False, 3);
-                      g_Sound_PlayExAt('SOUND_GAME_TELEPORT', Data.ItemPos.X, Data.ItemPos.Y);
+                      g_Sound_PlayExAt('SOUND_GAME_TELEPORT', trigData.trigItemPos.X, trigData.trigItemPos.Y);
                       g_GFX_OnceAnim(it.Obj.X+it.Obj.Rect.X+(it.Obj.Rect.Width div 2)-32,
                                      it.Obj.Y+it.Obj.Rect.Y+(it.Obj.Rect.Height div 2)-32, Anim);
                       Anim.Free();
@@ -1398,7 +1402,7 @@ begin
                     if g_Frames_Get(FramesID, 'FRAMES_ITEM_RESPAWN') then
                     begin
                       Anim := TAnimation.Create(FramesID, False, 4);
-                      g_Sound_PlayExAt('SOUND_ITEM_RESPAWNITEM', Data.ItemPos.X, Data.ItemPos.Y);
+                      g_Sound_PlayExAt('SOUND_ITEM_RESPAWNITEM', trigData.trigItemPos.X, trigData.trigItemPos.Y);
                       g_GFX_OnceAnim(it.Obj.X+it.Obj.Rect.X+(it.Obj.Rect.Width div 2)-16,
                                      it.Obj.Y+it.Obj.Rect.Y+(it.Obj.Rect.Height div 2)-16, Anim);
                       Anim.Free();
@@ -1413,7 +1417,7 @@ begin
                     if g_Frames_Get(FramesID, 'FRAMES_FIRE') then
                     begin
                       Anim := TAnimation.Create(FramesID, False, 4);
-                      g_Sound_PlayExAt('SOUND_FIRE', Data.ItemPos.X, Data.ItemPos.Y);
+                      g_Sound_PlayExAt('SOUND_FIRE', trigData.trigItemPos.X, trigData.trigItemPos.Y);
                       g_GFX_OnceAnim(it.Obj.X+it.Obj.Rect.X+(it.Obj.Rect.Width div 2)-32,
                                      it.Obj.Y+it.Obj.Rect.Y+it.Obj.Rect.Height-128, Anim);
                       Anim.Free();
@@ -1441,14 +1445,14 @@ begin
       TRIGGER_MUSIC:
         begin
         // Ìåíÿåì ìóçûêó, åñëè åñòü íà ÷òî:
-          if (Trigger.Data.MusicName <> '') then
+          if (Trigger.trigData.trigMusicName <> '') then
           begin
-            gMusic.SetByName(Trigger.Data.MusicName);
+            gMusic.SetByName(Trigger.trigData.trigMusicName);
             gMusic.SpecPause := True;
             gMusic.Play();
           end;
 
-          if Trigger.Data.MusicAction = 1 then
+          if Trigger.trigData.trigMusicAction = 1 then
             begin // Âêëþ÷èòü
               if gMusic.SpecPause then // Áûëà íà ïàóçå => èãðàòü
                 gMusic.SpecPause := False
@@ -1471,11 +1475,11 @@ begin
 
       TRIGGER_PUSH:
         begin
-          pAngle := -DegToRad(Data.PushAngle);
+          pAngle := -DegToRad(trigData.trigPushAngle);
           Result := tr_Push(ActivateUID,
-                            Floor(Cos(pAngle)*Data.PushForce),
-                            Floor(Sin(pAngle)*Data.PushForce),
-                            Data.ResetVel);
+                            Floor(Cos(pAngle)*trigData.trigPushForce),
+                            Floor(Sin(pAngle)*trigData.trigPushForce),
+                            trigData.trigResetVel);
           TimeOut := 0;
         end;
 
@@ -1483,106 +1487,106 @@ begin
         begin
           Result := False;
           // Ïðèáàâèòü èëè îòíÿòü î÷êî
-          if (Data.ScoreAction in [0..1]) and (Data.ScoreCount > 0) then
+          if (trigData.trigScoreAction in [0..1]) and (trigData.trigScoreCount > 0) then
           begin
             // Ñâîåé èëè ÷óæîé êîìàíäå
-            if (Data.ScoreTeam in [0..1]) and (g_GetUIDType(ActivateUID) = UID_PLAYER) then
+            if (trigData.trigScoreTeam in [0..1]) and (g_GetUIDType(ActivateUID) = UID_PLAYER) then
             begin
               p := g_Player_Get(ActivateUID);
-              if ((Data.ScoreAction = 0) and (Data.ScoreTeam = 0) and (p.Team = TEAM_RED))
-              or ((Data.ScoreAction = 0) and (Data.ScoreTeam = 1) and (p.Team = TEAM_BLUE)) then
+              if ((trigData.trigScoreAction = 0) and (trigData.trigScoreTeam = 0) and (p.Team = TEAM_RED))
+              or ((trigData.trigScoreAction = 0) and (trigData.trigScoreTeam = 1) and (p.Team = TEAM_BLUE)) then
               begin
-                Inc(gTeamStat[TEAM_RED].Goals, Data.ScoreCount); // Red Scores
+                Inc(gTeamStat[TEAM_RED].Goals, trigData.trigScoreCount); // Red Scores
 
-                if Data.ScoreCon then
-                  if Data.ScoreTeam = 0 then
+                if trigData.trigScoreCon then
+                  if trigData.trigScoreTeam = 0 then
                   begin
-                    g_Console_Add(Format(_lc[I_PLAYER_SCORE_ADD_OWN], [p.Name, Data.ScoreCount, _lc[I_PLAYER_SCORE_TO_RED]]), True);
+                    g_Console_Add(Format(_lc[I_PLAYER_SCORE_ADD_OWN], [p.Name, trigData.trigScoreCount, _lc[I_PLAYER_SCORE_TO_RED]]), True);
                     if g_Game_IsServer and g_Game_IsNet then
-                      MH_SEND_GameEvent(NET_EV_SCORE, p.UID or (Data.ScoreCount shl 16), '+r');
+                      MH_SEND_GameEvent(NET_EV_SCORE, p.UID or (trigData.trigScoreCount shl 16), '+r');
                   end else
                   begin
-                    g_Console_Add(Format(_lc[I_PLAYER_SCORE_ADD_ENEMY], [p.Name, Data.ScoreCount, _lc[I_PLAYER_SCORE_TO_RED]]), True);
+                    g_Console_Add(Format(_lc[I_PLAYER_SCORE_ADD_ENEMY], [p.Name, trigData.trigScoreCount, _lc[I_PLAYER_SCORE_TO_RED]]), True);
                     if g_Game_IsServer and g_Game_IsNet then
-                      MH_SEND_GameEvent(NET_EV_SCORE, p.UID or (Data.ScoreCount shl 16), '+re');
+                      MH_SEND_GameEvent(NET_EV_SCORE, p.UID or (trigData.trigScoreCount shl 16), '+re');
                   end;
 
-                if Data.ScoreMsg then
+                if trigData.trigScoreMsg then
                 begin
                   g_Game_Message(Format(_lc[I_MESSAGE_SCORE_ADD], [AnsiUpperCase(_lc[I_GAME_TEAM_RED])]), 108);
                   if g_Game_IsServer and g_Game_IsNet then
                     MH_SEND_GameEvent(NET_EV_SCORE_MSG, TEAM_RED);
                 end;
               end;
-              if ((Data.ScoreAction = 1) and (Data.ScoreTeam = 0) and (p.Team = TEAM_RED))
-              or ((Data.ScoreAction = 1) and (Data.ScoreTeam = 1) and (p.Team = TEAM_BLUE)) then
+              if ((trigData.trigScoreAction = 1) and (trigData.trigScoreTeam = 0) and (p.Team = TEAM_RED))
+              or ((trigData.trigScoreAction = 1) and (trigData.trigScoreTeam = 1) and (p.Team = TEAM_BLUE)) then
               begin
-                Dec(gTeamStat[TEAM_RED].Goals, Data.ScoreCount); // Red Fouls
+                Dec(gTeamStat[TEAM_RED].Goals, trigData.trigScoreCount); // Red Fouls
 
-                if Data.ScoreCon then
-                  if Data.ScoreTeam = 0 then
+                if trigData.trigScoreCon then
+                  if trigData.trigScoreTeam = 0 then
                   begin
-                    g_Console_Add(Format(_lc[I_PLAYER_SCORE_SUB_OWN], [p.Name, Data.ScoreCount, _lc[I_PLAYER_SCORE_TO_RED]]), True);
+                    g_Console_Add(Format(_lc[I_PLAYER_SCORE_SUB_OWN], [p.Name, trigData.trigScoreCount, _lc[I_PLAYER_SCORE_TO_RED]]), True);
                     if g_Game_IsServer and g_Game_IsNet then
-                      MH_SEND_GameEvent(NET_EV_SCORE, p.UID or (Data.ScoreCount shl 16), '-r');
+                      MH_SEND_GameEvent(NET_EV_SCORE, p.UID or (trigData.trigScoreCount shl 16), '-r');
                   end else
                   begin
-                    g_Console_Add(Format(_lc[I_PLAYER_SCORE_SUB_ENEMY], [p.Name, Data.ScoreCount, _lc[I_PLAYER_SCORE_TO_RED]]), True);
+                    g_Console_Add(Format(_lc[I_PLAYER_SCORE_SUB_ENEMY], [p.Name, trigData.trigScoreCount, _lc[I_PLAYER_SCORE_TO_RED]]), True);
                     if g_Game_IsServer and g_Game_IsNet then
-                      MH_SEND_GameEvent(NET_EV_SCORE, p.UID or (Data.ScoreCount shl 16), '-re');
+                      MH_SEND_GameEvent(NET_EV_SCORE, p.UID or (trigData.trigScoreCount shl 16), '-re');
                   end;
 
-                if Data.ScoreMsg then
+                if trigData.trigScoreMsg then
                 begin
                   g_Game_Message(Format(_lc[I_MESSAGE_SCORE_SUB], [AnsiUpperCase(_lc[I_GAME_TEAM_RED])]), 108);
                   if g_Game_IsServer and g_Game_IsNet then
                     MH_SEND_GameEvent(NET_EV_SCORE_MSG, -TEAM_RED);
                 end;
               end;
-              if ((Data.ScoreAction = 0) and (Data.ScoreTeam = 0) and (p.Team = TEAM_BLUE))
-              or ((Data.ScoreAction = 0) and (Data.ScoreTeam = 1) and (p.Team = TEAM_RED)) then
+              if ((trigData.trigScoreAction = 0) and (trigData.trigScoreTeam = 0) and (p.Team = TEAM_BLUE))
+              or ((trigData.trigScoreAction = 0) and (trigData.trigScoreTeam = 1) and (p.Team = TEAM_RED)) then
               begin
-                Inc(gTeamStat[TEAM_BLUE].Goals, Data.ScoreCount); // Blue Scores
+                Inc(gTeamStat[TEAM_BLUE].Goals, trigData.trigScoreCount); // Blue Scores
 
-                if Data.ScoreCon then
-                  if Data.ScoreTeam = 0 then
+                if trigData.trigScoreCon then
+                  if trigData.trigScoreTeam = 0 then
                   begin
-                    g_Console_Add(Format(_lc[I_PLAYER_SCORE_ADD_OWN], [p.Name, Data.ScoreCount, _lc[I_PLAYER_SCORE_TO_BLUE]]), True);
+                    g_Console_Add(Format(_lc[I_PLAYER_SCORE_ADD_OWN], [p.Name, trigData.trigScoreCount, _lc[I_PLAYER_SCORE_TO_BLUE]]), True);
                     if g_Game_IsServer and g_Game_IsNet then
-                      MH_SEND_GameEvent(NET_EV_SCORE, p.UID or (Data.ScoreCount shl 16), '+b');
+                      MH_SEND_GameEvent(NET_EV_SCORE, p.UID or (trigData.trigScoreCount shl 16), '+b');
                   end else
                   begin
-                    g_Console_Add(Format(_lc[I_PLAYER_SCORE_ADD_ENEMY], [p.Name, Data.ScoreCount, _lc[I_PLAYER_SCORE_TO_BLUE]]), True);
+                    g_Console_Add(Format(_lc[I_PLAYER_SCORE_ADD_ENEMY], [p.Name, trigData.trigScoreCount, _lc[I_PLAYER_SCORE_TO_BLUE]]), True);
                     if g_Game_IsServer and g_Game_IsNet then
-                      MH_SEND_GameEvent(NET_EV_SCORE, p.UID or (Data.ScoreCount shl 16), '+be');
+                      MH_SEND_GameEvent(NET_EV_SCORE, p.UID or (trigData.trigScoreCount shl 16), '+be');
                   end;
 
-                if Data.ScoreMsg then
+                if trigData.trigScoreMsg then
                 begin
                   g_Game_Message(Format(_lc[I_MESSAGE_SCORE_ADD], [AnsiUpperCase(_lc[I_GAME_TEAM_BLUE])]), 108);
                   if g_Game_IsServer and g_Game_IsNet then
                     MH_SEND_GameEvent(NET_EV_SCORE_MSG, TEAM_BLUE);
                 end;
               end;
-              if ((Data.ScoreAction = 1) and (Data.ScoreTeam = 0) and (p.Team = TEAM_BLUE))
-              or ((Data.ScoreAction = 1) and (Data.ScoreTeam = 1) and (p.Team = TEAM_RED)) then
+              if ((trigData.trigScoreAction = 1) and (trigData.trigScoreTeam = 0) and (p.Team = TEAM_BLUE))
+              or ((trigData.trigScoreAction = 1) and (trigData.trigScoreTeam = 1) and (p.Team = TEAM_RED)) then
               begin
-                Dec(gTeamStat[TEAM_BLUE].Goals, Data.ScoreCount); // Blue Fouls
+                Dec(gTeamStat[TEAM_BLUE].Goals, trigData.trigScoreCount); // Blue Fouls
 
-                if Data.ScoreCon then
-                  if Data.ScoreTeam = 0 then
+                if trigData.trigScoreCon then
+                  if trigData.trigScoreTeam = 0 then
                   begin
-                    g_Console_Add(Format(_lc[I_PLAYER_SCORE_SUB_OWN], [p.Name, Data.ScoreCount, _lc[I_PLAYER_SCORE_TO_BLUE]]), True);
+                    g_Console_Add(Format(_lc[I_PLAYER_SCORE_SUB_OWN], [p.Name, trigData.trigScoreCount, _lc[I_PLAYER_SCORE_TO_BLUE]]), True);
                     if g_Game_IsServer and g_Game_IsNet then
-                      MH_SEND_GameEvent(NET_EV_SCORE, p.UID or (Data.ScoreCount shl 16), '-b');
+                      MH_SEND_GameEvent(NET_EV_SCORE, p.UID or (trigData.trigScoreCount shl 16), '-b');
                   end else
                   begin
-                    g_Console_Add(Format(_lc[I_PLAYER_SCORE_SUB_ENEMY], [p.Name, Data.ScoreCount, _lc[I_PLAYER_SCORE_TO_BLUE]]), True);
+                    g_Console_Add(Format(_lc[I_PLAYER_SCORE_SUB_ENEMY], [p.Name, trigData.trigScoreCount, _lc[I_PLAYER_SCORE_TO_BLUE]]), True);
                     if g_Game_IsServer and g_Game_IsNet then
-                      MH_SEND_GameEvent(NET_EV_SCORE, p.UID or (Data.ScoreCount shl 16), '-be');
+                      MH_SEND_GameEvent(NET_EV_SCORE, p.UID or (trigData.trigScoreCount shl 16), '-be');
                   end;
 
-                if Data.ScoreMsg then
+                if trigData.trigScoreMsg then
                 begin
                   g_Game_Message(Format(_lc[I_MESSAGE_SCORE_SUB], [AnsiUpperCase(_lc[I_GAME_TEAM_BLUE])]), 108);
                   if g_Game_IsServer and g_Game_IsNet then
@@ -1592,74 +1596,74 @@ begin
               Result := (p.Team = TEAM_RED) or (p.Team = TEAM_BLUE);
             end;
             // Êàêîé-òî êîíêðåòíîé êîìàíäå
-            if Data.ScoreTeam in [2..3] then
+            if trigData.trigScoreTeam in [2..3] then
             begin
-              if (Data.ScoreAction = 0) and (Data.ScoreTeam = 2) then
+              if (trigData.trigScoreAction = 0) and (trigData.trigScoreTeam = 2) then
               begin
-                Inc(gTeamStat[TEAM_RED].Goals, Data.ScoreCount); // Red Scores
+                Inc(gTeamStat[TEAM_RED].Goals, trigData.trigScoreCount); // Red Scores
 
-                if Data.ScoreCon then
+                if trigData.trigScoreCon then
                 begin
-                  g_Console_Add(Format(_lc[I_PLAYER_SCORE_ADD_TEAM], [_lc[I_PLAYER_SCORE_RED], Data.ScoreCount]), True);
+                  g_Console_Add(Format(_lc[I_PLAYER_SCORE_ADD_TEAM], [_lc[I_PLAYER_SCORE_RED], trigData.trigScoreCount]), True);
                   if g_Game_IsServer and g_Game_IsNet then
-                    MH_SEND_GameEvent(NET_EV_SCORE, Data.ScoreCount shl 16, '+tr');
+                    MH_SEND_GameEvent(NET_EV_SCORE, trigData.trigScoreCount shl 16, '+tr');
                 end;
 
-                if Data.ScoreMsg then
+                if trigData.trigScoreMsg then
                 begin
                   g_Game_Message(Format(_lc[I_MESSAGE_SCORE_ADD], [AnsiUpperCase(_lc[I_GAME_TEAM_RED])]), 108);
                   if g_Game_IsServer and g_Game_IsNet then
                     MH_SEND_GameEvent(NET_EV_SCORE_MSG, TEAM_RED);
                 end;
               end;
-              if (Data.ScoreAction = 1) and (Data.ScoreTeam = 2) then
+              if (trigData.trigScoreAction = 1) and (trigData.trigScoreTeam = 2) then
               begin
-                Dec(gTeamStat[TEAM_RED].Goals, Data.ScoreCount); // Red Fouls
+                Dec(gTeamStat[TEAM_RED].Goals, trigData.trigScoreCount); // Red Fouls
 
-                if Data.ScoreCon then
+                if trigData.trigScoreCon then
                 begin
-                  g_Console_Add(Format(_lc[I_PLAYER_SCORE_SUB_TEAM], [_lc[I_PLAYER_SCORE_RED], Data.ScoreCount]), True);
+                  g_Console_Add(Format(_lc[I_PLAYER_SCORE_SUB_TEAM], [_lc[I_PLAYER_SCORE_RED], trigData.trigScoreCount]), True);
                   if g_Game_IsServer and g_Game_IsNet then
-                    MH_SEND_GameEvent(NET_EV_SCORE, Data.ScoreCount shl 16, '-tr');
+                    MH_SEND_GameEvent(NET_EV_SCORE, trigData.trigScoreCount shl 16, '-tr');
                 end;
 
-                if Data.ScoreMsg then
+                if trigData.trigScoreMsg then
                 begin
                   g_Game_Message(Format(_lc[I_MESSAGE_SCORE_SUB], [AnsiUpperCase(_lc[I_GAME_TEAM_RED])]), 108);
                   if g_Game_IsServer and g_Game_IsNet then
                     MH_SEND_GameEvent(NET_EV_SCORE_MSG, -TEAM_RED);
                 end;
               end;
-              if (Data.ScoreAction = 0) and (Data.ScoreTeam = 3) then
+              if (trigData.trigScoreAction = 0) and (trigData.trigScoreTeam = 3) then
               begin
-                Inc(gTeamStat[TEAM_BLUE].Goals, Data.ScoreCount); // Blue Scores
+                Inc(gTeamStat[TEAM_BLUE].Goals, trigData.trigScoreCount); // Blue Scores
 
-                if Data.ScoreCon then
+                if trigData.trigScoreCon then
                 begin
-                  g_Console_Add(Format(_lc[I_PLAYER_SCORE_ADD_TEAM], [_lc[I_PLAYER_SCORE_BLUE], Data.ScoreCount]), True);
+                  g_Console_Add(Format(_lc[I_PLAYER_SCORE_ADD_TEAM], [_lc[I_PLAYER_SCORE_BLUE], trigData.trigScoreCount]), True);
                   if g_Game_IsServer and g_Game_IsNet then
-                    MH_SEND_GameEvent(NET_EV_SCORE, Data.ScoreCount shl 16, '+tb');
+                    MH_SEND_GameEvent(NET_EV_SCORE, trigData.trigScoreCount shl 16, '+tb');
                 end;
 
-                if Data.ScoreMsg then
+                if trigData.trigScoreMsg then
                 begin
                   g_Game_Message(Format(_lc[I_MESSAGE_SCORE_ADD], [AnsiUpperCase(_lc[I_GAME_TEAM_BLUE])]), 108);
                   if g_Game_IsServer and g_Game_IsNet then
                     MH_SEND_GameEvent(NET_EV_SCORE_MSG, TEAM_BLUE);
                 end;
               end;
-              if (Data.ScoreAction = 1) and (Data.ScoreTeam = 3) then
+              if (trigData.trigScoreAction = 1) and (trigData.trigScoreTeam = 3) then
               begin
-                Dec(gTeamStat[TEAM_BLUE].Goals, Data.ScoreCount); // Blue Fouls
+                Dec(gTeamStat[TEAM_BLUE].Goals, trigData.trigScoreCount); // Blue Fouls
 
-                if Data.ScoreCon then
+                if trigData.trigScoreCon then
                 begin
-                  g_Console_Add(Format(_lc[I_PLAYER_SCORE_SUB_TEAM], [_lc[I_PLAYER_SCORE_BLUE], Data.ScoreCount]), True);
+                  g_Console_Add(Format(_lc[I_PLAYER_SCORE_SUB_TEAM], [_lc[I_PLAYER_SCORE_BLUE], trigData.trigScoreCount]), True);
                   if g_Game_IsServer and g_Game_IsNet then
-                    MH_SEND_GameEvent(NET_EV_SCORE, Data.ScoreCount shl 16, '-tb');
+                    MH_SEND_GameEvent(NET_EV_SCORE, trigData.trigScoreCount shl 16, '-tb');
                 end;
 
-                if Data.ScoreMsg then
+                if trigData.trigScoreMsg then
                 begin
                   g_Game_Message(Format(_lc[I_MESSAGE_SCORE_SUB], [AnsiUpperCase(_lc[I_GAME_TEAM_BLUE])]), 108);
                   if g_Game_IsServer and g_Game_IsNet then
@@ -1670,20 +1674,20 @@ begin
             end;
           end;
           // Âûèãðûø
-          if (Data.ScoreAction = 2) and (gGameSettings.GoalLimit > 0) then
+          if (trigData.trigScoreAction = 2) and (gGameSettings.GoalLimit > 0) then
           begin
             // Ñâîåé èëè ÷óæîé êîìàíäû
-            if (Data.ScoreTeam in [0..1]) and (g_GetUIDType(ActivateUID) = UID_PLAYER) then
+            if (trigData.trigScoreTeam in [0..1]) and (g_GetUIDType(ActivateUID) = UID_PLAYER) then
             begin
               p := g_Player_Get(ActivateUID);
-              if ((Data.ScoreTeam = 0) and (p.Team = TEAM_RED)) // Red Wins
-              or ((Data.ScoreTeam = 1) and (p.Team = TEAM_BLUE)) then
+              if ((trigData.trigScoreTeam = 0) and (p.Team = TEAM_RED)) // Red Wins
+              or ((trigData.trigScoreTeam = 1) and (p.Team = TEAM_BLUE)) then
                 if gTeamStat[TEAM_RED].Goals < SmallInt(gGameSettings.GoalLimit) then
                 begin
                   gTeamStat[TEAM_RED].Goals := gGameSettings.GoalLimit;
 
-                  if Data.ScoreCon then
-                    if Data.ScoreTeam = 0 then
+                  if trigData.trigScoreCon then
+                    if trigData.trigScoreTeam = 0 then
                     begin
                       g_Console_Add(Format(_lc[I_PLAYER_SCORE_WIN_OWN], [p.Name, _lc[I_PLAYER_SCORE_TO_RED]]), True);
                       if g_Game_IsServer and g_Game_IsNet then
@@ -1697,14 +1701,14 @@ begin
 
                   Result := True;
                 end;
-              if ((Data.ScoreTeam = 0) and (p.Team = TEAM_BLUE)) // Blue Wins
-              or ((Data.ScoreTeam = 1) and (p.Team = TEAM_RED)) then
+              if ((trigData.trigScoreTeam = 0) and (p.Team = TEAM_BLUE)) // Blue Wins
+              or ((trigData.trigScoreTeam = 1) and (p.Team = TEAM_RED)) then
                 if gTeamStat[TEAM_BLUE].Goals < SmallInt(gGameSettings.GoalLimit) then
                 begin
                   gTeamStat[TEAM_BLUE].Goals := gGameSettings.GoalLimit;
 
-                  if Data.ScoreCon then
-                    if Data.ScoreTeam = 0 then
+                  if trigData.trigScoreCon then
+                    if trigData.trigScoreTeam = 0 then
                     begin
                       g_Console_Add(Format(_lc[I_PLAYER_SCORE_WIN_OWN], [p.Name, _lc[I_PLAYER_SCORE_TO_BLUE]]), True);
                       if g_Game_IsServer and g_Game_IsNet then
@@ -1720,15 +1724,15 @@ begin
                 end;
             end;
             // Êàêîé-òî êîíêðåòíîé êîìàíäû
-            if Data.ScoreTeam in [2..3] then
+            if trigData.trigScoreTeam in [2..3] then
             begin
-              if Data.ScoreTeam = 2 then // Red Wins
+              if trigData.trigScoreTeam = 2 then // Red Wins
                 if gTeamStat[TEAM_RED].Goals < SmallInt(gGameSettings.GoalLimit) then
                 begin
                   gTeamStat[TEAM_RED].Goals := gGameSettings.GoalLimit;
                   Result := True;
                 end;
-              if Data.ScoreTeam = 3 then // Blue Wins
+              if trigData.trigScoreTeam = 3 then // Blue Wins
                 if gTeamStat[TEAM_BLUE].Goals < SmallInt(gGameSettings.GoalLimit) then
                 begin
                   gTeamStat[TEAM_BLUE].Goals := gGameSettings.GoalLimit;
@@ -1737,20 +1741,20 @@ begin
             end;
           end;
           // Ïðîèãðûø
-          if (Data.ScoreAction = 3) and (gGameSettings.GoalLimit > 0) then
+          if (trigData.trigScoreAction = 3) and (gGameSettings.GoalLimit > 0) then
           begin
             // Ñâîåé èëè ÷óæîé êîìàíäû
-            if (Data.ScoreTeam in [0..1]) and (g_GetUIDType(ActivateUID) = UID_PLAYER) then
+            if (trigData.trigScoreTeam in [0..1]) and (g_GetUIDType(ActivateUID) = UID_PLAYER) then
             begin
               p := g_Player_Get(ActivateUID);
-              if ((Data.ScoreTeam = 0) and (p.Team = TEAM_BLUE)) // Red Wins
-              or ((Data.ScoreTeam = 1) and (p.Team = TEAM_RED)) then
+              if ((trigData.trigScoreTeam = 0) and (p.Team = TEAM_BLUE)) // Red Wins
+              or ((trigData.trigScoreTeam = 1) and (p.Team = TEAM_RED)) then
                 if gTeamStat[TEAM_RED].Goals < SmallInt(gGameSettings.GoalLimit) then
                 begin
                   gTeamStat[TEAM_RED].Goals := gGameSettings.GoalLimit;
 
-                  if Data.ScoreCon then
-                    if Data.ScoreTeam = 0 then
+                  if trigData.trigScoreCon then
+                    if trigData.trigScoreTeam = 0 then
                     begin
                       g_Console_Add(Format(_lc[I_PLAYER_SCORE_WIN_ENEMY], [p.Name, _lc[I_PLAYER_SCORE_TO_RED]]), True);
                       if g_Game_IsServer and g_Game_IsNet then
@@ -1764,14 +1768,14 @@ begin
 
                   Result := True;
                 end;
-              if ((Data.ScoreTeam = 0) and (p.Team = TEAM_RED)) // Blue Wins
-              or ((Data.ScoreTeam = 1) and (p.Team = TEAM_BLUE)) then
+              if ((trigData.trigScoreTeam = 0) and (p.Team = TEAM_RED)) // Blue Wins
+              or ((trigData.trigScoreTeam = 1) and (p.Team = TEAM_BLUE)) then
                 if gTeamStat[TEAM_BLUE].Goals < SmallInt(gGameSettings.GoalLimit) then
                 begin
                   gTeamStat[TEAM_BLUE].Goals := gGameSettings.GoalLimit;
 
-                  if Data.ScoreCon then
-                    if Data.ScoreTeam = 0 then
+                  if trigData.trigScoreCon then
+                    if trigData.trigScoreTeam = 0 then
                     begin
                       g_Console_Add(Format(_lc[I_PLAYER_SCORE_WIN_ENEMY], [p.Name, _lc[I_PLAYER_SCORE_TO_BLUE]]), True);
                       if g_Game_IsServer and g_Game_IsNet then
@@ -1787,15 +1791,15 @@ begin
                 end;
             end;
             // Êàêîé-òî êîíêðåòíîé êîìàíäû
-            if Data.ScoreTeam in [2..3] then
+            if trigData.trigScoreTeam in [2..3] then
             begin
-              if Data.ScoreTeam = 3 then // Red Wins
+              if trigData.trigScoreTeam = 3 then // Red Wins
                 if gTeamStat[TEAM_RED].Goals < SmallInt(gGameSettings.GoalLimit) then
                 begin
                   gTeamStat[TEAM_RED].Goals := gGameSettings.GoalLimit;
                   Result := True;
                 end;
-              if Data.ScoreTeam = 2 then // Blue Wins
+              if trigData.trigScoreTeam = 2 then // Blue Wins
                 if gTeamStat[TEAM_BLUE].Goals < SmallInt(gGameSettings.GoalLimit) then
                 begin
                   gTeamStat[TEAM_BLUE].Goals := gGameSettings.GoalLimit;
@@ -1815,8 +1819,8 @@ begin
 
       TRIGGER_MESSAGE:
         begin
-          Result := tr_Message(Data.MessageKind, Data.MessageText, 
-                               Data.MessageSendTo, Data.MessageTime,
+          Result := tr_Message(trigData.trigMessageKind, trigData.trigMessageText, 
+                               trigData.trigMessageSendTo, trigData.trigMessageTime,
                                ActivateUID);
           TimeOut := 18;
         end;
@@ -1847,7 +1851,7 @@ begin
               end else
               begin // Óæå âèäåëè åãî
                 // Åñëè èíòåðâàë îòêëþ÷¸í, íî îí âñ¸ åù¸ â çîíå ïîðàæåíèÿ, äà¸ì åìó âðåìÿ
-                if (Data.DamageInterval = 0) and (Activators[k].TimeOut > 0) then
+                if (trigData.trigDamageInterval = 0) and (Activators[k].TimeOut > 0) then
                   Activators[k].TimeOut := 65535;
                 // Òàéìàóò ïðîø¸ë - ðàáîòàåì
                 Result := Activators[k].TimeOut = 0;
@@ -1864,12 +1868,12 @@ begin
                       Exit;
 
                     // Íàíîñèì óðîí èãðîêó
-                    if (TriggerType = TRIGGER_DAMAGE) and (Data.DamageValue > 0) then
-                      p.Damage(Data.DamageValue, 0, 0, 0, HIT_SOME);
+                    if (TriggerType = TRIGGER_DAMAGE) and (trigData.trigDamageValue > 0) then
+                      p.Damage(trigData.trigDamageValue, 0, 0, 0, HIT_SOME);
 
                     // Ëå÷èì èãðîêà
-                    if (TriggerType = TRIGGER_HEALTH) and (Data.HealValue > 0) then
-                      if p.Heal(Data.HealValue, not Data.HealMax) and (not Data.HealSilent) then
+                    if (TriggerType = TRIGGER_HEALTH) and (trigData.trigHealValue > 0) then
+                      if p.Heal(trigData.trigHealValue, not trigData.trigHealMax) and (not trigData.trigHealSilent) then
                       begin
                         g_Sound_PlayExAt('SOUND_ITEM_GETITEM', p.Obj.X, p.Obj.Y);
                         if g_Game_IsServer and g_Game_IsNet then
@@ -1884,12 +1888,12 @@ begin
                       Exit;
 
                     // Íàíîñèì óðîí ìîíñòðó
-                    if (TriggerType = TRIGGER_DAMAGE) and (Data.DamageValue > 0) then
-                      m.Damage(Data.DamageValue, 0, 0, 0, HIT_SOME);
+                    if (TriggerType = TRIGGER_DAMAGE) and (trigData.trigDamageValue > 0) then
+                      m.Damage(trigData.trigDamageValue, 0, 0, 0, HIT_SOME);
 
                     // Ëå÷èì ìîíñòðà
-                    if (TriggerType = TRIGGER_HEALTH) and (Data.HealValue > 0) then
-                      if m.Heal(Data.HealValue) and (not Data.HealSilent) then
+                    if (TriggerType = TRIGGER_HEALTH) and (trigData.trigHealValue > 0) then
+                      if m.Heal(trigData.trigHealValue) and (not trigData.trigHealSilent) then
                       begin
                         g_Sound_PlayExAt('SOUND_ITEM_GETITEM', m.Obj.X, m.Obj.Y);
                         if g_Game_IsServer and g_Game_IsNet then
@@ -1899,9 +1903,9 @@ begin
               end;
               // Íàçíà÷àåì âðåìÿ ñëåäóþùåãî âîçäåéñòâèÿ
               if TriggerType = TRIGGER_DAMAGE then
-                idx := Data.DamageInterval
+                idx := trigData.trigDamageInterval
               else
-                idx := Data.HealInterval;
+                idx := trigData.trigHealInterval;
               if coolDown then
                 if idx > 0 then
                   Activators[k].TimeOut := idx
@@ -1918,16 +1922,16 @@ begin
             Exit;
 
           // put this at the beginning so it doesn't trigger itself
-          TimeOut := Data.ShotWait + 1;
+          TimeOut := trigData.trigShotWait + 1;
 
-          wx := Data.ShotPos.X;
-          wy := Data.ShotPos.Y;
-          pAngle := -DegToRad(Data.ShotAngle);
+          wx := trigData.trigShotPos.X;
+          wy := trigData.trigShotPos.Y;
+          pAngle := -DegToRad(trigData.trigShotAngle);
           xd := wx + Round(Cos(pAngle) * 32.0);
           yd := wy + Round(Sin(pAngle) * 32.0);
           TargetUID := 0;
 
-          case Data.ShotTarget of
+          case trigData.trigShotTarget of
             TRIGGER_SHOT_TARGET_MON: // monsters
               //TODO: accelerate this!
               g_Mons_ForEachAlive(monsShotTarget);
@@ -2007,25 +2011,25 @@ begin
             end;
 
             else begin
-              if (Data.ShotTarget <> TRIGGER_SHOT_TARGET_NONE) or
-                 (Data.ShotType <> TRIGGER_SHOT_REV) then
+              if (trigData.trigShotTarget <> TRIGGER_SHOT_TARGET_NONE) or
+                 (trigData.trigShotType <> TRIGGER_SHOT_REV) then
                 TargetUID := ActivateUID;
             end;
           end;
 
-          if (Data.ShotTarget = TRIGGER_SHOT_TARGET_NONE) or (TargetUID > 0) or
-            ((Data.ShotTarget > TRIGGER_SHOT_TARGET_NONE) and (TargetUID = 0)) then
+          if (trigData.trigShotTarget = TRIGGER_SHOT_TARGET_NONE) or (TargetUID > 0) or
+            ((trigData.trigShotTarget > TRIGGER_SHOT_TARGET_NONE) and (TargetUID = 0)) then
           begin
             Result := True;
-            if (Data.ShotIntSight = 0) or
-               (Data.ShotTarget = TRIGGER_SHOT_TARGET_NONE) or
+            if (trigData.trigShotIntSight = 0) or
+               (trigData.trigShotTarget = TRIGGER_SHOT_TARGET_NONE) or
                (TargetUID = ShotSightTarget) then
               MakeShot(Trigger, wx, wy, xd, yd, TargetUID)
             else
             begin
-              ShotSightTime := Data.ShotIntSight;
+              ShotSightTime := trigData.trigShotIntSight;
               ShotSightTargetN := TargetUID;
-              if Data.ShotType = TRIGGER_SHOT_BFG then
+              if trigData.trigShotType = TRIGGER_SHOT_BFG then
               begin
                 g_Sound_PlayExAt('SOUND_WEAPON_STARTFIREBFG', wx, wy);
                 if g_Game_IsNet and g_Game_IsServer then
@@ -2037,11 +2041,11 @@ begin
 
       TRIGGER_EFFECT:
         begin
-          idx := Data.FXCount;
+          idx := trigData.trigFXCount;
 
           while idx > 0 do
           begin
-            case Data.FXPos of
+            case trigData.trigFXPos of
               TRIGGER_EFFECT_POS_CENTER:
               begin
                 wx := X + Width div 2;
@@ -2057,18 +2061,18 @@ begin
                 wy := Y + Height div 2;
               end;
             end;
-            xd := Data.FXVelX;
-            yd := Data.FXVelY;
-            if Data.FXSpreadL > 0 then xd := xd - Random(Data.FXSpreadL + 1);
-            if Data.FXSpreadR > 0 then xd := xd + Random(Data.FXSpreadR + 1);
-            if Data.FXSpreadU > 0 then yd := yd - Random(Data.FXSpreadU + 1);
-            if Data.FXSpreadD > 0 then yd := yd + Random(Data.FXSpreadD + 1);
+            xd := trigData.trigFXVelX;
+            yd := trigData.trigFXVelY;
+            if trigData.trigFXSpreadL > 0 then xd := xd - Random(trigData.trigFXSpreadL + 1);
+            if trigData.trigFXSpreadR > 0 then xd := xd + Random(trigData.trigFXSpreadR + 1);
+            if trigData.trigFXSpreadU > 0 then yd := yd - Random(trigData.trigFXSpreadU + 1);
+            if trigData.trigFXSpreadD > 0 then yd := yd + Random(trigData.trigFXSpreadD + 1);
             tr_MakeEffect(wx, wy, xd, yd,
-                       Data.FXType, Data.FXSubType,
-                       Data.FXColorR, Data.FXColorG, Data.FXColorB, True, False);
+                       trigData.trigFXType, trigData.trigFXSubType,
+                       trigData.trigFXColorR, trigData.trigFXColorG, trigData.trigFXColorB, True, False);
             Dec(idx);
           end;
-          TimeOut := Data.FXWait;
+          TimeOut := trigData.trigFXWait;
         end;
     end;
   end;
@@ -2127,30 +2131,30 @@ begin
 
 // Çàãðóæàåì çâóê, åñëè ýòî òðèããåð "Çâóê":
   if (Trigger.TriggerType = TRIGGER_SOUND) and
-     (Trigger.Data.SoundName <> '') then
+     (Trigger.trigData.trigSoundName <> '') then
   begin
   // Åùå íåò òàêîãî çâóêà:
-    if not g_Sound_Exists(Trigger.Data.SoundName) then
+    if not g_Sound_Exists(Trigger.trigData.trigSoundName) then
     begin
-      fn := g_ExtractWadName(Trigger.Data.SoundName);
+      fn := g_ExtractWadName(Trigger.trigData.trigSoundName);
 
       if fn = '' then
         begin // Çâóê â ôàéëå ñ êàðòîé
           mapw := g_ExtractWadName(gMapInfo.Map);
-          fn := mapw+':'+g_ExtractFilePathName(Trigger.Data.SoundName);
+          fn := mapw+':'+g_ExtractFilePathName(Trigger.trigData.trigSoundName);
         end
       else // Çâóê â îòäåëüíîì ôàéëå
-        fn := GameDir + '/wads/' + Trigger.Data.SoundName;
+        fn := GameDir + '/wads/' + Trigger.trigData.trigSoundName;
 
-      if not g_Sound_CreateWADEx(Trigger.Data.SoundName, fn) then
-        g_FatalError(Format(_lc[I_GAME_ERROR_TR_SOUND], [fn, Trigger.Data.SoundName]));
+      if not g_Sound_CreateWADEx(Trigger.trigData.trigSoundName, fn) then
+        g_FatalError(Format(_lc[I_GAME_ERROR_TR_SOUND], [fn, Trigger.trigData.trigSoundName]));
     end;
 
   // Ñîçäàåì îáúåêò çâóêà:
     with gTriggers[find_id] do
     begin
       Sound := TPlayableSound.Create();
-      if not Sound.SetByName(Trigger.Data.SoundName) then
+      if not Sound.SetByName(Trigger.trigData.trigSoundName) then
       begin
         Sound.Free();
         Sound := nil;
@@ -2160,23 +2164,23 @@ begin
 
 // Çàãðóæàåì ìóçûêó, åñëè ýòî òðèããåð "Ìóçûêà":
   if (Trigger.TriggerType = TRIGGER_MUSIC) and
-     (Trigger.Data.MusicName <> '') then
+     (Trigger.trigData.trigMusicName <> '') then
   begin
   // Åùå íåò òàêîé ìóçûêè:
-    if not g_Sound_Exists(Trigger.Data.MusicName) then
+    if not g_Sound_Exists(Trigger.trigData.trigMusicName) then
     begin
-      fn := g_ExtractWadName(Trigger.Data.MusicName);
+      fn := g_ExtractWadName(Trigger.trigData.trigMusicName);
 
       if fn = '' then
         begin // Ìóçûêà â ôàéëå ñ êàðòîé
           mapw := g_ExtractWadName(gMapInfo.Map);
-          fn := mapw+':'+g_ExtractFilePathName(Trigger.Data.MusicName);
+          fn := mapw+':'+g_ExtractFilePathName(Trigger.trigData.trigMusicName);
         end
       else // Ìóçûêà â ôàéëå ñ êàðòîé
-        fn := GameDir+'/wads/'+Trigger.Data.MusicName;
+        fn := GameDir+'/wads/'+Trigger.trigData.trigMusicName;
 
-      if not g_Sound_CreateWADEx(Trigger.Data.MusicName, fn, True) then
-        g_FatalError(Format(_lc[I_GAME_ERROR_TR_SOUND], [fn, Trigger.Data.MusicName]));
+      if not g_Sound_CreateWADEx(Trigger.trigData.trigMusicName, fn, True) then
+        g_FatalError(Format(_lc[I_GAME_ERROR_TR_SOUND], [fn, Trigger.trigData.trigMusicName]));
     end;
   end;
 
@@ -2189,7 +2193,7 @@ begin
       ShotSightTimeout := 0;
       ShotSightTarget := 0;
       ShotSightTargetN := 0;
-      ShotAmmoCount := Trigger.Data.ShotAmmo;
+      ShotAmmoCount := Trigger.trigData.trigShotAmmo;
       ShotReloadTime := 0;
     end;
 
@@ -2249,7 +2253,7 @@ begin
             else
               Continue;
             // Ñ÷èòàåì, ÷òî îáúåêò ïîêèíóë çîíó äåéñòâèÿ òðèããåðà
-            if (Data.DamageInterval = 0) and (Activators[b].TimeOut < 65530) then
+            if (trigData.trigDamageInterval = 0) and (Activators[b].TimeOut < 65530) then
               Activators[b].TimeOut := 0;
           end;
 
@@ -2258,13 +2262,13 @@ begin
           if SpawnCooldown = 0 then
           begin
             // Åñëè ïðèøëî âðåìÿ, ñïàâíèì ìîíñòðà:
-            if (TriggerType = TRIGGER_SPAWNMONSTER) and (Data.MonDelay > 0)  then
+            if (TriggerType = TRIGGER_SPAWNMONSTER) and (trigData.trigMonDelay > 0)  then
             begin
               ActivateUID := 0;
               ActivateTrigger(gTriggers[a], ACTIVATE_CUSTOM);
             end;
             // Åñëè ïðèøëî âðåìÿ, ñïàâíèì ïðåäìåò:
-            if (TriggerType = TRIGGER_SPAWNITEM) and (Data.ItemDelay > 0) then
+            if (TriggerType = TRIGGER_SPAWNITEM) and (trigData.trigItemDelay > 0) then
             begin
               ActivateUID := 0;
               ActivateTrigger(gTriggers[a], ACTIVATE_CUSTOM);
@@ -2279,7 +2283,7 @@ begin
           begin
             Dec(ShotPanelTime);
             if ShotPanelTime = 0 then
-              g_Map_SwitchTexture(ShotPanelType, Data.ShotPanelID);
+              g_Map_SwitchTexture(ShotPanelType, trigShotPanelID);
           end;
           if ShotSightTime > 0 then
           begin
@@ -2297,7 +2301,7 @@ begin
           begin
             Dec(ShotReloadTime);
             if ShotReloadTime = 0 then
-              ShotAmmoCount := Data.ShotAmmo;
+              ShotAmmoCount := trigData.trigShotAmmo;
           end;
         end;
 
@@ -2305,60 +2309,60 @@ begin
         if Enabled and (TriggerType = TRIGGER_SOUND) and (Sound <> nil) then
           if (SoundPlayCount > 0) and (not Sound.IsPlaying()) then
           begin
-            if Data.PlayCount > 0 then // Åñëè 0 - èãðàåì çâóê áåñêîíå÷íî
+            if trigData.trigPlayCount > 0 then // Åñëè 0 - èãðàåì çâóê áåñêîíå÷íî
               SoundPlayCount := SoundPlayCount - 1;
-            if Data.Local then
-              Sound.PlayVolumeAt(X+(Width div 2), Y+(Height div 2), Data.Volume/255.0)
+            if trigData.trigLocal then
+              Sound.PlayVolumeAt(X+(Width div 2), Y+(Height div 2), trigData.trigVolume/255.0)
             else
-              Sound.PlayPanVolume((Data.Pan-127.0)/128.0, Data.Volume/255.0);
+              Sound.PlayPanVolume((trigData.trigPan-127.0)/128.0, trigData.trigVolume/255.0);
             if Sound.IsPlaying() and g_Game_IsNet and g_Game_IsServer then
               MH_SEND_TriggerSound(gTriggers[a]);
           end;
 
       // Òðèããåð "Ëîâóøêà" - ïîðà îòêðûâàòü:
-        if (TriggerType = TRIGGER_TRAP) and (DoorTime = 0) and (Data.PanelID <> -1) then
+        if (TriggerType = TRIGGER_TRAP) and (DoorTime = 0) and (trigPanelID <> -1) then
         begin
-          tr_OpenDoor(Data.PanelID, Data.NoSound, Data.d2d_doors);
+          tr_OpenDoor(trigPanelID, trigData.trigNoSound, trigData.trigd2d_doors);
           DoorTime := -1;
         end;
 
       // Òðèããåð "Äâåðü 5 ñåê" - ïîðà çàêðûâàòü:
-        if (TriggerType = TRIGGER_DOOR5) and (DoorTime = 0) and (Data.PanelID <> -1) then
+        if (TriggerType = TRIGGER_DOOR5) and (DoorTime = 0) and (trigPanelID <> -1) then
         begin
         // Óæå çàêðûòà:
-          if gWalls[Data.PanelID].Enabled then
+          if gWalls[trigPanelID].Enabled then
             DoorTime := -1
           else // Ïîêà îòêðûòà - çàêðûâàåì
-            if tr_CloseDoor(Data.PanelID, Data.NoSound, Data.d2d_doors) then
+            if tr_CloseDoor(trigPanelID, trigData.trigNoSound, trigData.trigd2d_doors) then
               DoorTime := -1;
         end;
 
       // Òðèããåð - ðàñøèðèòåëü èëè ïåðåêëþ÷àòåëü, è ïðîøëà çàäåðæêà, è íàæàëè íóæíîå ÷èñëî ðàç:
         if (TriggerType in [TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF]) and
-           (PressTime = 0) and (PressCount >= Data.Count) then
+           (PressTime = 0) and (PressCount >= trigData.trigCount) then
         begin
         // Ñáðàñûâàåì çàäåðæêó àêòèâàöèè:
           PressTime := -1;
         // Ñáðàñûâàåì ñ÷åò÷èê íàæàòèé:
-          if Data.Count > 0 then
-            PressCount := PressCount - Data.Count
+          if trigData.trigCount > 0 then
+            PressCount := PressCount - trigData.trigCount
           else
             PressCount := 0;
 
         // Îïðåäåëÿåì èçìåíÿåìûå èì òðèããåðû:
           for b := 0 to High(gTriggers) do
-            if g_Collide(Data.tX, Data.tY, Data.tWidth, Data.tHeight, gTriggers[b].X, gTriggers[b].Y,
+            if g_Collide(trigData.trigtX, trigData.trigtY, trigData.trigtWidth, trigData.trigtHeight, gTriggers[b].X, gTriggers[b].Y,
                gTriggers[b].Width, gTriggers[b].Height) and
-               ((b <> a) or (Data.Wait > 0)) then
+               ((b <> a) or (trigData.trigWait > 0)) then
             begin // Can be self-activated, if there is Data.Wait
-              if (not Data.ExtRandom) or gTriggers[b].Enabled then
+              if (not trigData.trigExtRandom) or gTriggers[b].Enabled then
               begin
                 SetLength(Affected, Length(Affected) + 1);
                 Affected[High(Affected)] := b;
               end;
             end;
         // Âûáèðàåì îäèí èç òðèããåðîâ äëÿ ðàñøèðèòåëÿ, åñëè âêëþ÷åí ðàíäîì:
-          if (TriggerType = TRIGGER_PRESS) and Data.ExtRandom then
+          if (TriggerType = TRIGGER_PRESS) and trigData.trigExtRandom then
           begin
             if (Length(Affected) > 0) then
             begin
@@ -2628,7 +2632,7 @@ begin
          (TriggerType = TRIGGER_DOOR5) or
          (TriggerType = TRIGGER_DOOR) then
       begin
-        tr_OpenDoor(Data.PanelID, True, Data.d2d_doors);
+        tr_OpenDoor(trigPanelID, True, trigData.trigd2d_doors);
         if TriggerType = TRIGGER_DOOR5 then DoorTime := 180;
         b := True;
       end;
@@ -2647,19 +2651,22 @@ procedure g_Triggers_Free();
 var
   a: Integer;
 begin
-  if gTriggers <> nil then
-    for a := 0 to High(gTriggers) do
+  for a := 0 to High(gTriggers) do
+  begin
+    gTriggers[a].trigData.Free();
+    if (gTriggers[a].TriggerType = TRIGGER_SOUND) then
     begin
-      if gTriggers[a].TriggerType = TRIGGER_SOUND then
+      if g_Sound_Exists(gTriggers[a].trigData.trigSoundName) then
       begin
-        if g_Sound_Exists(gTriggers[a].Data.SoundName) then
-          g_Sound_Delete(gTriggers[a].Data.SoundName);
-
-        gTriggers[a].Sound.Free();
+        g_Sound_Delete(gTriggers[a].trigData.trigSoundName);
       end;
-      if gTriggers[a].Activators <> nil then
-        SetLength(gTriggers[a].Activators, 0);
+      gTriggers[a].Sound.Free();
     end;
+    if (gTriggers[a].Activators <> nil) then
+    begin
+      SetLength(gTriggers[a].Activators, 0);
+    end;
+  end;
 
   gTriggers := nil;
   gSecretsCount := 0;
@@ -2672,7 +2679,7 @@ var
   dw: DWORD;
   sg: Single;
   b: Boolean;
-  p: Pointer;
+  //p: Pointer;
 begin
 // Ñ÷èòàåì êîëè÷åñòâî ñóùåñòâóþùèõ òðèããåðîâ:
   count := 0;
@@ -2696,8 +2703,9 @@ begin
   // Òèï òðèããåðà:
     Mem.WriteByte(gTriggers[i].TriggerType);
   // Ñïåöèàëüíûå äàííûå òðèããåðà:
-    p := @gTriggers[i].Data;
-    Mem.WriteMemory(p, SizeOf(TTriggerData));
+  //!!!FIXME!!!
+    //p := @gTriggers[i].Data;
+    //Mem.WriteMemory(p, SizeOf(TTriggerData));
   // Êîîðäèíàòû ëåâîãî âåðõíåãî óãëà:
     Mem.WriteInt(gTriggers[i].X);
     Mem.WriteInt(gTriggers[i].Y);
@@ -2772,7 +2780,7 @@ var
   dw: DWORD;
   vol, pan: Single;
   b: Boolean;
-  p: Pointer;
+  //p: Pointer;
   Trig: TTrigger;
 begin
   if Mem = nil then
@@ -2797,12 +2805,15 @@ begin
   // Òèï òðèããåðà:
     Mem.ReadByte(Trig.TriggerType);
   // Ñïåöèàëüíûå äàííûå òðèããåðà:
+  //!!!FIXME!!!
+    {
     Mem.ReadMemory(p, dw);
     if dw <> SizeOf(TTriggerData) then
     begin
       raise EBinSizeError.Create('g_Triggers_LoadState: Wrong TriggerData Size');
     end;
     Trig.Data := TTriggerData(p^);
+    }
   // Ñîçäàåì òðèããåð:
     i := g_Triggers_Create(Trig);
   // Êîîðäèíàòû ëåâîãî âåðõíåãî óãëà:
index 37f9f0091ced2a3c9f117838fa1fceb42ebd3849..a7137162c81c5be25db278bc34b11462913c11a9 100644 (file)
 {$M+}
 unit MAPDEF;
 
-{
------------------------------------
-MAPDEF.PAS ÂÅÐÑÈß ÎÒ 22.03.09
-
-Ïîääåðæêà êàðò âåðñèè 1
------------------------------------
-}
-
 interface
 
 uses
@@ -43,7 +35,11 @@ const
 
 type
   TDFPoint = packed record
+  public
     X, Y: LongInt;
+
+  public
+    constructor Create (ax, ay: LongInt);
   end;
 
   Char16     = packed array[0..15] of Char;
@@ -55,221 +51,207 @@ type
 
 {$INCLUDE mapdef.inc}
 
+// various helpers to access map structures
 type
-  TTexturesRec1Array = array of TTextureRec_1;
-  TPanelsRec1Array = array of TPanelRec_1;
-  TItemsRec1Array = array of TItemRec_1;
-  TMonsterRec1Array = array of TMonsterRec_1;
-  TAreasRec1Array = array of TAreaRec_1;
-  TTriggersRec1Array = array of TTriggerRec_1;
+  TDynRecordHelper = class helper for TDynRecord
+  private
+    function getFieldWithType (const aname: AnsiString; atype: TDynField.TType): TDynField; inline;
+
+    function getPanelByIdx (idx: Integer): TDynRecord; inline;
+
+    function getPanelId (): Integer; inline;
+    //procedure setPanelId (v: Integer); inline;
+
+    function getTexturePanel (): Integer; inline;
+    //procedure setTexturePanel (v: Integer); inline;
+
+    function getPanelIndex (pan: TDynRecord): Integer;
+
+    function getPointField (const aname: AnsiString): TDFPoint; inline;
+
+  public
+    function panelCount (): Integer; inline;
+
+    // header
+    function mapName (): AnsiString; inline;
+    function mapAuthor (): AnsiString; inline;
+    function mapDesc (): AnsiString; inline;
+    function musicName (): AnsiString; inline;
+    function skyName (): AnsiString; inline;
+
+    // panel
+    function X (): Integer; inline;
+    function Y (): Integer; inline;
+    function Width (): Word; inline;
+    function Height (): Word; inline;
+    function TextureNum (): Word; inline;
+    function TextureRec (): TDynRecord; inline;
+    function PanelType (): Word; inline;
+    function Alpha (): Byte; inline;
+    function Flags (): Byte; inline;
+
+    // texture
+    function Resource (): AnsiString; inline;
+    function Anim (): Boolean; inline;
+
+    // item
+    function ItemType (): Byte; inline;
+    function Options (): Byte; inline;
+
+    // monster
+    function MonsterType (): Byte; inline; // type, ubyte
+    function Direction (): Byte; inline; // direction, ubyte
+
+    // area
+    function AreaType (): Byte; inline; // type, ubyte
+    //function Direction (): Byte; inline; // direction, ubyte
+
+    // trigger
+    function trigRec (): TDynRecord; inline;
+    function Enabled (): Boolean; inline; // enabled, bool
+    function TriggerType (): Byte; inline; // type, ubyte
+    function ActivateType (): Byte; inline; // activatetype, ubyte
+    function Keys (): Byte; inline; // keys, ubyte
+    //function DATA (): Byte128; inline; // triggerdata, trigdata[128]; // the only special nested structure
+
+    {$INCLUDE mapdef_help.inc}
+    function trigMonsterId (): Integer; inline;
+
+  public
+    property panel[idx: Integer]: TDynRecord read getPanelByIdx;
+    property panelIndex[pan: TDynRecord]: Integer read getPanelIndex;
+    // triggers
+    property tgPanelID: Integer read getPanelId {write setPanelId};
+    property tgShotPanelID: Integer read getPanelId {write setPanelId};
+    property TexturePanel: Integer read getTexturePanel {write setTexturePanel}; // texturepanel, int
+  end;
 
+implementation
 
-function GetMapHeader (rec: TDynRecord): TMapHeaderRec_1;
-function GetTextures (rec: TDynRecord): TTexturesRec1Array;
-function GetPanels (rec: TDynRecord): TPanelsRec1Array;
-function GetItems (rec: TDynRecord): TItemsRec1Array;
-function GetAreas (rec: TDynRecord): TAreasRec1Array;
-function GetMonsters (rec: TDynRecord): TMonsterRec1Array;
-function GetTriggers (rec: TDynRecord): TTriggersRec1Array;
+uses
+  SysUtils, {e_log,} utils, xparser, xstreams;
 
 
-implementation
+// ////////////////////////////////////////////////////////////////////////// //
+constructor TDFPoint.Create (ax, ay: LongInt); begin X := ax; Y := ay; end;
 
-uses
-  {e_log,} xparser, xstreams;
+
+// ////////////////////////////////////////////////////////////////////////// //
+function TDynRecordHelper.getFieldWithType (const aname: AnsiString; atype: TDynField.TType): TDynField; inline;
+begin
+  result := field[aname];
+  if (result = nil) then raise Exception.Create(Format('field ''%s'' not found in record ''%s'' of type ''%s''', [aname, name, id]));
+  if (result.baseType <> atype) then raise Exception.Create(Format('field ''%s'' in record ''%s'' of type ''%s'' has invalid data type', [aname, name, id]));
+end;
 
 
-function GetMapHeader (rec: TDynRecord): TMapHeaderRec_1;
+function TDynRecordHelper.getPointField (const aname: AnsiString): TDFPoint; inline;
 var
-  ws: TSFSMemoryChunkStream = nil;
+  fld: TDynField;
 begin
-  FillChar(result, sizeof(result), 0);
-  if (rec = nil) then exit;
-  try
-    ws := TSFSMemoryChunkStream.Create(@result, sizeof(result));
-    rec.writeBinTo(ws, -1, true); // only fields
-  except // sorry
-    FillChar(result, sizeof(result), 0);
-  end;
-  ws.Free();
+  fld := field[aname];
+  if (fld = nil) then raise Exception.Create(Format('field ''%s'' not found in record ''%s'' of type ''%s''', [aname, name, id]));
+  if (fld.baseType <> TPoint) then raise Exception.Create(Format('field ''%s'' in record ''%s'' of type ''%s'' has invalid data type', [aname, name, id]));
+  result := TDFPoint.Create(fld.ival, fld.ival2);
 end;
 
 
-function GetTextures (rec: TDynRecord): TTexturesRec1Array;
+function TDynRecordHelper.getPanelByIdx (idx: Integer): TDynRecord; inline;
 var
-  ws: TSFSMemoryChunkStream = nil;
   fld: TDynField;
-  f: Integer;
 begin
-  result := nil;
-  fld := rec.field['texture'];
-  if (fld = nil) or (fld.baseType <> fld.TType.TList) or (fld.count = 0) then exit;
-  ws := TSFSMemoryChunkStream.Create(nil, 0);
-  try
-    SetLength(result, fld.count);
-    for f := 0 to fld.count-1 do
-    begin
-      FillChar(result[f], sizeof(result[f]), 0);
-      ws.setup(@result[f], sizeof(result[f]));
-      fld.item[f].writeBinTo(ws, -1, true); // only fields
-    end;
-  except
-    result := nil;
-  end;
-  ws.Free();
+  fld := headerRec['panel'];
+  if (fld <> nil) then result := fld.item[idx] else result := nil;
 end;
 
 
-function GetPanels (rec: TDynRecord): TPanelsRec1Array;
+function TDynRecordHelper.getPanelIndex (pan: TDynRecord): Integer;
 var
-  ws: TSFSMemoryChunkStream = nil;
   fld: TDynField;
   f: Integer;
 begin
-  result := nil;
-  fld := rec.field['panel'];
-  if (fld = nil) or (fld.baseType <> fld.TType.TList) or (fld.count = 0) then exit;
-  ws := TSFSMemoryChunkStream.Create(nil, 0);
-  try
-    SetLength(result, fld.count);
-    for f := 0 to fld.count-1 do
+  result := -1;
+  if (pan <> nil) then
+  begin
+    fld := headerRec['panel'];
+    if (fld <> nil) then
     begin
-      FillChar(result[f], sizeof(result[f]), 0);
-      ws.setup(@result[f], sizeof(result[f]));
-      fld.item[f].writeBinTo(ws, -1, true); // only fields
+      for f := 0 to fld.count-1 do if (fld.item[f] = pan) then begin result := f; exit; end;
     end;
-  except
-    result := nil;
   end;
-  ws.Free();
 end;
 
 
-function GetItems (rec: TDynRecord): TItemsRec1Array;
+function TDynRecordHelper.panelCount (): Integer; inline;
 var
-  ws: TSFSMemoryChunkStream = nil;
   fld: TDynField;
-  f: Integer;
 begin
-  result := nil;
-  fld := rec.field['item'];
-  if (fld = nil) or (fld.baseType <> fld.TType.TList) or (fld.count = 0) then exit;
-  ws := TSFSMemoryChunkStream.Create(nil, 0);
-  try
-    SetLength(result, fld.count);
-    for f := 0 to fld.count-1 do
-    begin
-      FillChar(result[f], sizeof(result[f]), 0);
-      ws.setup(@result[f], sizeof(result[f]));
-      fld.item[f].writeBinTo(ws, -1, true); // only fields
-    end;
-  except
-    result := nil;
-  end;
-  ws.Free();
+  fld := headerRec['panel'];
+  if (fld <> nil) then result := fld.count else result := 0;
 end;
 
 
-function GetAreas (rec: TDynRecord): TAreasRec1Array;
+function TDynRecordHelper.TextureNum (): Word; inline;
 var
-  ws: TSFSMemoryChunkStream = nil;
+  idx: Integer;
   fld: TDynField;
-  f: Integer;
 begin
-  result := nil;
-  fld := rec.field['area'];
-  if (fld = nil) or (fld.baseType <> fld.TType.TList) or (fld.count = 0) then exit;
-  ws := TSFSMemoryChunkStream.Create(nil, 0);
-  try
-    SetLength(result, fld.count);
-    for f := 0 to fld.count-1 do
-    begin
-      FillChar(result[f], sizeof(result[f]), 0);
-      ws.setup(@result[f], sizeof(result[f]));
-      fld.item[f].writeBinTo(ws, -1, true); // only fields
-    end;
-  except
-    result := nil;
-  end;
-  ws.Free();
+  fld := getFieldWithType('texture', TDynField.TType.TUShort);
+  idx := fld.recrefIndex;
+  if (idx < 0) then result := Word(TEXTURE_NONE) else result := Word(idx);
 end;
 
 
-function GetMonsters (rec: TDynRecord): TMonsterRec1Array;
+// ////////////////////////////////////////////////////////////////////////// //
+// trigger
+function TDynRecordHelper.trigRec (): TDynRecord; inline;
 var
-  ws: TSFSMemoryChunkStream = nil;
   fld: TDynField;
-  f: Integer;
 begin
-  result := nil;
-  fld := rec.field['monster'];
-  if (fld = nil) or (fld.baseType <> fld.TType.TList) or (fld.count = 0) then exit;
-  ws := TSFSMemoryChunkStream.Create(nil, 0);
-  try
-    SetLength(result, fld.count);
-    for f := 0 to fld.count-1 do
-    begin
-      FillChar(result[f], sizeof(result[f]), 0);
-      ws.setup(@result[f], sizeof(result[f]));
-      fld.item[f].writeBinTo(ws, -1, true); // only fields
-    end;
-  except
-    result := nil;
-  end;
-  ws.Free();
+  fld := getFieldWithType('triggerdata', TDynField.TType.TTrigData);
+  if (fld <> nil) then result := fld.recref else result := nil;
 end;
 
 
-function GetTriggers (rec: TDynRecord): TTriggersRec1Array;
+function TDynRecordHelper.trigMonsterId (): Integer; inline;
 var
-  ws: TSFSMemoryChunkStream = nil;
   fld: TDynField;
-  f: Integer;
-  //wr: TTextWriter;
-  //fo: File;
 begin
-  result := nil;
-  fld := rec.field['trigger'];
-  if (fld = nil) or (fld.baseType <> fld.TType.TList) or (fld.count = 0) then exit;
-  ws := TSFSMemoryChunkStream.Create(nil, 0);
-  try
-    //wr := TFileTextWriter.Create('z00.txt');
-    SetLength(result, fld.count);
-    for f := 0 to fld.count-1 do
-    begin
-      FillChar(result[f], sizeof(result[f]), 0);
-      //e_LogWritefln(': trigger #%s; TexturePanel=%s', [f, result[f].TexturePanel]);
-      ws.setup(@result[f], sizeof(result[f]));
-      fld.item[f].writeBinTo(ws, -1, true); // only fields
-      {
-      e_LogWritefln(': trigger #%s; X=%s; Y=%s; Width=%s; Height=%s; Enabled=%s; TexturePanel=%s; TriggerType=%s; ActivateType=%s; Keys=%s', [f,
-       result[f].X,
-       result[f].Y,
-       result[f].Width,
-       result[f].Height,
-       result[f].Enabled,
-       result[f].TexturePanel,
-       result[f].TriggerType,
-       result[f].ActivateType,
-       result[f].Keys
-       ]);
-      //e_LogWritefln('***'#10'%s'#10'***', [);
-      fld.item[f].writeTo(wr);
-      if (f = 0) then
-      begin
-        AssignFile(fo, 'z00.bin');
-        Rewrite(fo, 1);
-        BlockWrite(fo, result[f], sizeof(result[f]));
-        CloseFile(fo);
-      end;
-      }
-    end;
-    //wr.Free();
-  except
-    result := nil;
-  end;
-  ws.Free();
+  fld := getFieldWithType('monsterid', TDynField.TType.TInt);
+  result := fld.recrefIndex;
 end;
 
 
+// ////////////////////////////////////////////////////////////////////////// //
+function TDynRecordHelper.mapName (): AnsiString; inline; begin result := utf2win(getFieldWithType('name', TDynField.TType.TChar).sval); end;
+function TDynRecordHelper.mapAuthor (): AnsiString; inline; begin result := utf2win(getFieldWithType('author', TDynField.TType.TChar).sval); end;
+function TDynRecordHelper.mapDesc (): AnsiString; inline; begin result := utf2win(getFieldWithType('description', TDynField.TType.TChar).sval); end;
+function TDynRecordHelper.musicName (): AnsiString; inline; begin result := utf2win(getFieldWithType('music', TDynField.TType.TChar).sval); end;
+function TDynRecordHelper.skyName (): AnsiString; inline; begin result := utf2win(getFieldWithType('sky', TDynField.TType.TChar).sval); end;
+function TDynRecordHelper.X (): Integer; inline; begin result := getFieldWithType('position', TDynField.TType.TPoint).ival; end;
+function TDynRecordHelper.Y (): Integer; inline; begin result := getFieldWithType('position', TDynField.TType.TPoint).ival2; end;
+function TDynRecordHelper.Width (): Word; inline; begin result := Word(getFieldWithType('size', TDynField.TType.TSize).ival); end;
+function TDynRecordHelper.Height (): Word; inline; begin result := Word(getFieldWithType('size', TDynField.TType.TSize).ival2); end;
+function TDynRecordHelper.PanelType (): Word; inline; begin result := Word(getFieldWithType('type', TDynField.TType.TUShort).ival); end;
+function TDynRecordHelper.TextureRec (): TDynRecord; inline; begin result := getFieldWithType('texture', TDynField.TType.TUShort).recref; end;
+function TDynRecordHelper.Alpha (): Byte; inline; begin result := Byte(getFieldWithType('alpha', TDynField.TType.TUByte).ival); end;
+function TDynRecordHelper.Flags (): Byte; inline; begin result := Byte(getFieldWithType('flags', TDynField.TType.TUByte).ival); end;
+function TDynRecordHelper.Resource (): AnsiString; inline; begin result := utf2win(getFieldWithType('path', TDynField.TType.TChar).sval); end;
+function TDynRecordHelper.Anim (): Boolean; inline; begin result := (getFieldWithType('animated', TDynField.TType.TBool).ival <> 0); end;
+function TDynRecordHelper.ItemType (): Byte; inline; begin result := Byte(getFieldWithType('type', TDynField.TType.TUByte).ival); end;
+function TDynRecordHelper.Options (): Byte; inline; begin result := Byte(getFieldWithType('options', TDynField.TType.TUByte).ival); end;
+function TDynRecordHelper.MonsterType (): Byte; inline; begin result := Byte(getFieldWithType('type', TDynField.TType.TUByte).ival); end;
+function TDynRecordHelper.Direction (): Byte; inline; begin result := Byte(getFieldWithType('direction', TDynField.TType.TUByte).ival); end;
+function TDynRecordHelper.AreaType (): Byte; inline; begin result := Byte(getFieldWithType('type', TDynField.TType.TUByte).ival); end;
+function TDynRecordHelper.Enabled (): Boolean; inline; begin result := (getFieldWithType('enabled', TDynField.TType.TBool).ival <> 0); end;
+function TDynRecordHelper.TriggerType (): Byte; inline; begin result := Byte(getFieldWithType('type', TDynField.TType.TUByte).ival); end;
+function TDynRecordHelper.ActivateType (): Byte; inline; begin result := Byte(getFieldWithType('activatetype', TDynField.TType.TUByte).ival); end;
+function TDynRecordHelper.Keys (): Byte; inline; begin result := Byte(getFieldWithType('keys', TDynField.TType.TUByte).ival); end;
+
+function TDynRecordHelper.getPanelId (): Integer; inline; begin result := getFieldWithType('panelid', TDynField.TType.TInt).recrefIndex; end;
+function TDynRecordHelper.getTexturePanel (): Integer; begin result := getFieldWithType('texturepanel', TDynField.TType.TInt).recrefIndex; end;
+
+{$INCLUDE mapdef_impl.inc}
+
+
 end.
index 3ebc917df62bd7c01617fe03fc7932d17c409995..d744d9394d7e6ba0ea5cfeb9a0f14bb58ad24049 100644 (file)
@@ -246,192 +246,6 @@ const
   KEY_BLUETEAM = 16;
 
 
-// ////////////////////////////////////////////////////////////////////////// //
-// records
-type
-  TMapHeaderRec_1 = packed record
-    MapName: Char32;
-    MapAuthor: Char32;
-    MapDescription: Char256;
-    MusicName: Char64;
-    SkyName: Char64;
-    Width, Height: Word;
-  end;
-
-  TTextureRec_1 = packed record
-    Resource: Char64;
-    Anim: Boolean;
-  end;
-
-  TPanelRec_1 = packed record
-    X, Y: Integer;
-    Width, Height: Word;
-    TextureNum: Word;
-    PanelType: Word;
-    Alpha: Byte;
-    Flags: Byte;
-  end;
-
-  TItemRec_1 = packed record
-    X, Y: Integer;
-    ItemType: Byte;
-    Options: Byte;
-  end;
-
-  TMonsterRec_1 = packed record
-    X, Y: Integer;
-    MonsterType: Byte;
-    Direction: Byte;
-  end;
-
-  TAreaRec_1 = packed record
-    X, Y: Integer;
-    AreaType: Byte;
-    Direction: Byte;
-  end;
-
-  TTriggerRec_1 = packed record
-    X, Y: Integer;
-    Width, Height: Word;
-    Enabled: Boolean;
-    TexturePanel: LongInt;
-    TriggerType: Byte;
-    ActivateType: Byte;
-    Keys: Byte;
-    DATA: Byte128;
-  end;
-
-
-
-// ////////////////////////////////////////////////////////////////////////// //
-// triggerdata
-type
-  TTriggerData = record
-    case Byte of
-      0: (Default: Byte128);
-      TRIGGER_EXIT: (
-        MapName: Char16;
-      );
-      TRIGGER_TELEPORT: (
-        TargetPoint: TDFPoint;
-        d2d_teleport: Boolean;
-        silent_teleport: Boolean;
-        TlpDir: Byte;
-      );
-      TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR, TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP, TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT: (
-        PanelID: LongInt;
-        NoSound: Boolean;
-        d2d_doors: Boolean;
-      );
-      TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF: (
-        tX, tY: Integer;
-        tWidth, tHeight: Word;
-        Wait: Word;
-        Count: Word;
-        MonsterID: LongInt;
-        ExtRandom: Boolean;
-      );
-      TRIGGER_SECRET: (
-      );
-      TRIGGER_TEXTURE: (
-        ActivateOnce: Boolean;
-        AnimOnce: Boolean;
-      );
-      TRIGGER_SOUND: (
-        SoundName: Char64;
-        Volume: Byte;
-        Pan: Byte;
-        Local: Boolean;
-        PlayCount: Byte;
-        SoundSwitch: Boolean;
-      );
-      TRIGGER_SPAWNMONSTER: (
-        MonPos: TDFPoint;
-        MonType: Byte;
-        MonHealth: LongInt;
-        MonDir: Byte;
-        MonActive: Boolean;
-        MonCount: LongInt;
-        MonEffect: Byte;
-        MonMax: Word;
-        MonDelay: Word;
-        MonBehav: Byte;
-      );
-      TRIGGER_SPAWNITEM: (
-        ItemPos: TDFPoint;
-        ItemType: Byte;
-        ItemFalls: Boolean;
-        ItemOnlyDM: Boolean;
-        ItemCount: LongInt;
-        ItemEffect: Byte;
-        ItemMax: Word;
-        ItemDelay: Word;
-      );
-      TRIGGER_MUSIC: (
-        MusicName: Char64;
-        MusicAction: Byte;
-      );
-      TRIGGER_PUSH: (
-        PushAngle: Word;
-        PushForce: Byte;
-        ResetVel: Boolean;
-      );
-      TRIGGER_SCORE: (
-        ScoreAction: Byte;
-        ScoreCount: Byte;
-        ScoreTeam: Byte;
-        ScoreCon: Boolean;
-        ScoreMsg: Boolean;
-      );
-      TRIGGER_MESSAGE: (
-        MessageKind: Byte;
-        MessageSendTo: Byte;
-        MessageText: Char100;
-        MessageTime: Word;
-      );
-      TRIGGER_DAMAGE: (
-        DamageValue: Word;
-        DamageInterval: Word;
-      );
-      TRIGGER_HEALTH: (
-        HealValue: Word;
-        HealInterval: Word;
-        HealMax: Boolean;
-        HealSilent: Boolean;
-      );
-      TRIGGER_SHOT: (
-        ShotPos: TDFPoint;
-        ShotType: Byte;
-        ShotTarget: Byte;
-        ShotSound: Boolean;
-        ShotAim: ShortInt;
-        ShotPanelID: LongInt;
-        ShotIntSight: Word;
-        ShotAngle: Word;
-        ShotWait: Word;
-        ShotAccuracy: Word;
-        ShotAmmo: Word;
-        ShotIntReload: Word;
-      );
-      TRIGGER_EFFECT: (
-        FXCount: Byte;
-        FXType: Byte;
-        FXSubType: Byte;
-        FXColorR: Byte;
-        FXColorG: Byte;
-        FXColorB: Byte;
-        FXPos: Byte;
-        FXWait: Word;
-        FXVelX: ShortInt;
-        FXVelY: ShortInt;
-        FXSpreadL: Byte;
-        FXSpreadR: Byte;
-        FXSpreadU: Byte;
-        FXSpreadD: Byte;
-      );
-  end;
-
-
 const defaultMapDef: AnsiString = ''+
   #47#47#32#121#101#115#44#32#116#104#105#115#32#102#105#108#101#32#115#101+
   #114#118#101#115#32#98#111#116#104#32#97#115#32#102#111#114#109#97#116#32+
diff --git a/src/shared/mapdef_help.inc b/src/shared/mapdef_help.inc
new file mode 100644 (file)
index 0000000..efd7623
--- /dev/null
@@ -0,0 +1,88 @@
+// *** WARNING! ***
+//   regenerate this part directly from "mapdef.txt" with 'mapgen', NEVER manually change anything here!
+
+function trigMapName (): AnsiString; inline;
+function trigTargetPoint (): TDFPoint; inline;
+function trigd2d_teleport (): Boolean; inline;
+function trigsilent_teleport (): Boolean; inline;
+function trigTlpDir (): Byte; inline;
+function trigNoSound (): Boolean; inline;
+function trigd2d_doors (): Boolean; inline;
+function trigTX (): LongInt; inline;
+function trigTY (): LongInt; inline;
+function trigTWidth (): Word; inline;
+function trigTHeight (): Word; inline;
+function trigWait (): Word; inline;
+function trigCount (): Word; inline;
+function trigExtRandom (): Boolean; inline;
+function trigActivateOnce (): Boolean; inline;
+function trigAnimOnce (): Boolean; inline;
+function trigSoundName (): AnsiString; inline;
+function trigVolume (): Byte; inline;
+function trigPan (): Byte; inline;
+function trigLocal (): Boolean; inline;
+function trigPlayCount (): Byte; inline;
+function trigSoundSwitch (): Boolean; inline;
+function trigMonPos (): TDFPoint; inline;
+function trigMonType (): Byte; inline;
+function trigMonHealth (): LongInt; inline;
+function trigMonDir (): Byte; inline;
+function trigMonActive (): Boolean; inline;
+function trigMonCount (): LongInt; inline;
+function trigMonEffect (): Byte; inline;
+function trigMonMax (): Word; inline;
+function trigMonDelay (): Word; inline;
+function trigMonBehav (): Byte; inline;
+function trigItemPos (): TDFPoint; inline;
+function trigItemType (): Byte; inline;
+function trigItemFalls (): Boolean; inline;
+function trigItemOnlyDM (): Boolean; inline;
+function trigItemCount (): LongInt; inline;
+function trigItemEffect (): Byte; inline;
+function trigItemMax (): Word; inline;
+function trigItemDelay (): Word; inline;
+function trigMusicName (): AnsiString; inline;
+function trigMusicAction (): Byte; inline;
+function trigPushAngle (): Word; inline;
+function trigPushForce (): Byte; inline;
+function trigResetVel (): Boolean; inline;
+function trigScoreAction (): Byte; inline;
+function trigScoreCount (): Byte; inline;
+function trigScoreTeam (): Byte; inline;
+function trigScoreCon (): Boolean; inline;
+function trigScoreMsg (): Boolean; inline;
+function trigMessageKind (): Byte; inline;
+function trigMessageSendTo (): Byte; inline;
+function trigMessageText (): AnsiString; inline;
+function trigMessageTime (): Word; inline;
+function trigDamageValue (): Word; inline;
+function trigDamageInterval (): Word; inline;
+function trigHealValue (): Word; inline;
+function trigHealInterval (): Word; inline;
+function trigHealMax (): Boolean; inline;
+function trigHealSilent (): Boolean; inline;
+function trigShotPos (): TDFPoint; inline;
+function trigShotType (): Byte; inline;
+function trigShotTarget (): Byte; inline;
+function trigShotSound (): Boolean; inline;
+function trigShotAim (): SmallInt; inline;
+function trigShotIntSight (): Word; inline;
+function trigShotAngle (): Word; inline;
+function trigShotWait (): Word; inline;
+function trigShotAccuracy (): Word; inline;
+function trigShotAmmo (): Word; inline;
+function trigShotIntReload (): Word; inline;
+function trigFXCount (): Byte; inline;
+function trigFXType (): Byte; inline;
+function trigFXSubType (): Byte; inline;
+function trigFXColorR (): Byte; inline;
+function trigFXColorG (): Byte; inline;
+function trigFXColorB (): Byte; inline;
+function trigFXPos (): Byte; inline;
+function trigFXWait (): Word; inline;
+function trigFXVelX (): SmallInt; inline;
+function trigFXVelY (): SmallInt; inline;
+function trigFXSpreadL (): Byte; inline;
+function trigFXSpreadR (): Byte; inline;
+function trigFXSpreadU (): Byte; inline;
+function trigFXSpreadD (): Byte; inline;
diff --git a/src/shared/mapdef_impl.inc b/src/shared/mapdef_impl.inc
new file mode 100644 (file)
index 0000000..f491dbf
--- /dev/null
@@ -0,0 +1,123 @@
+
+
+// ////////////////////////////////////////////////////////////////////////// //
+// trigger helpers
+
+// TRIGGER_EXIT
+function TDynRecordHelper.trigMapName (): AnsiString; inline; begin result := utf2win(getFieldWithType('map', TDynField.TType.TChar).sval); end;
+
+// TRIGGER_TELEPORT
+function TDynRecordHelper.trigTargetPoint (): TDFPoint; inline; begin result := getPointField('target'); end;
+function TDynRecordHelper.trigd2d_teleport (): Boolean; inline; begin result := (getFieldWithType('d2d', TDynField.TType.TBool).ival <> 0); end;
+function TDynRecordHelper.trigsilent_teleport (): Boolean; inline; begin result := (getFieldWithType('silent', TDynField.TType.TBool).ival <> 0); end;
+function TDynRecordHelper.trigTlpDir (): Byte; inline; begin result := Byte(getFieldWithType('direction', TDynField.TType.TUByte).ival); end;
+
+// TRIGGER_OPENDOOR, TRIGGER_CLOSEDOOR, TRIGGER_DOOR, TRIGGER_DOOR5, TRIGGER_CLOSETRAP, TRIGGER_TRAP, TRIGGER_LIFTUP, TRIGGER_LIFTDOWN, TRIGGER_LIFT
+function TDynRecordHelper.trigNoSound (): Boolean; inline; begin result := (getFieldWithType('silent', TDynField.TType.TBool).ival <> 0); end;
+function TDynRecordHelper.trigd2d_doors (): Boolean; inline; begin result := (getFieldWithType('d2d', TDynField.TType.TBool).ival <> 0); end;
+
+// TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF
+function TDynRecordHelper.trigTX (): LongInt; inline; begin result := LongInt(getFieldWithType('position', TDynField.TType.TPoint).ival); end;
+function TDynRecordHelper.trigTY (): LongInt; inline; begin result := LongInt(getFieldWithType('position', TDynField.TType.TPoint).ival2); end;
+function TDynRecordHelper.trigTWidth (): Word; inline; begin result := Word(getFieldWithType('size', TDynField.TType.TSize).ival); end;
+function TDynRecordHelper.trigTHeight (): Word; inline; begin result := Word(getFieldWithType('size', TDynField.TType.TSize).ival2); end;
+function TDynRecordHelper.trigWait (): Word; inline; begin result := Word(getFieldWithType('wait', TDynField.TType.TUShort).ival); end;
+function TDynRecordHelper.trigCount (): Word; inline; begin result := Word(getFieldWithType('count', TDynField.TType.TUShort).ival); end;
+function TDynRecordHelper.trigExtRandom (): Boolean; inline; begin result := (getFieldWithType('extrandom', TDynField.TType.TBool).ival <> 0); end;
+
+// TRIGGER_SECRET
+
+// TRIGGER_TEXTURE
+function TDynRecordHelper.trigActivateOnce (): Boolean; inline; begin result := (getFieldWithType('activateonce', TDynField.TType.TBool).ival <> 0); end;
+function TDynRecordHelper.trigAnimOnce (): Boolean; inline; begin result := (getFieldWithType('animateonce', TDynField.TType.TBool).ival <> 0); end;
+
+// TRIGGER_SOUND
+function TDynRecordHelper.trigSoundName (): AnsiString; inline; begin result := utf2win(getFieldWithType('soundname', TDynField.TType.TChar).sval); end;
+function TDynRecordHelper.trigVolume (): Byte; inline; begin result := Byte(getFieldWithType('volume', TDynField.TType.TUByte).ival); end;
+function TDynRecordHelper.trigPan (): Byte; inline; begin result := Byte(getFieldWithType('pan', TDynField.TType.TUByte).ival); end;
+function TDynRecordHelper.trigLocal (): Boolean; inline; begin result := (getFieldWithType('local', TDynField.TType.TBool).ival <> 0); end;
+function TDynRecordHelper.trigPlayCount (): Byte; inline; begin result := Byte(getFieldWithType('playcount', TDynField.TType.TUByte).ival); end;
+function TDynRecordHelper.trigSoundSwitch (): Boolean; inline; begin result := (getFieldWithType('soundswitch', TDynField.TType.TBool).ival <> 0); end;
+
+// TRIGGER_SPAWNMONSTER
+function TDynRecordHelper.trigMonPos (): TDFPoint; inline; begin result := getPointField('position'); end;
+function TDynRecordHelper.trigMonType (): Byte; inline; begin result := Byte(getFieldWithType('type', TDynField.TType.TUByte).ival); end;
+function TDynRecordHelper.trigMonHealth (): LongInt; inline; begin result := LongInt(getFieldWithType('health', TDynField.TType.TInt).ival); end;
+function TDynRecordHelper.trigMonDir (): Byte; inline; begin result := Byte(getFieldWithType('direction', TDynField.TType.TUByte).ival); end;
+function TDynRecordHelper.trigMonActive (): Boolean; inline; begin result := (getFieldWithType('active', TDynField.TType.TBool).ival <> 0); end;
+function TDynRecordHelper.trigMonCount (): LongInt; inline; begin result := LongInt(getFieldWithType('count', TDynField.TType.TInt).ival); end;
+function TDynRecordHelper.trigMonEffect (): Byte; inline; begin result := Byte(getFieldWithType('effect', TDynField.TType.TUByte).ival); end;
+function TDynRecordHelper.trigMonMax (): Word; inline; begin result := Word(getFieldWithType('max', TDynField.TType.TUShort).ival); end;
+function TDynRecordHelper.trigMonDelay (): Word; inline; begin result := Word(getFieldWithType('delay', TDynField.TType.TUShort).ival); end;
+function TDynRecordHelper.trigMonBehav (): Byte; inline; begin result := Byte(getFieldWithType('behaviour', TDynField.TType.TUByte).ival); end;
+
+// TRIGGER_SPAWNITEM
+function TDynRecordHelper.trigItemPos (): TDFPoint; inline; begin result := getPointField('position'); end;
+function TDynRecordHelper.trigItemType (): Byte; inline; begin result := Byte(getFieldWithType('type', TDynField.TType.TUByte).ival); end;
+function TDynRecordHelper.trigItemFalls (): Boolean; inline; begin result := (getFieldWithType('gravity', TDynField.TType.TBool).ival <> 0); end;
+function TDynRecordHelper.trigItemOnlyDM (): Boolean; inline; begin result := (getFieldWithType('dmonly', TDynField.TType.TBool).ival <> 0); end;
+function TDynRecordHelper.trigItemCount (): LongInt; inline; begin result := LongInt(getFieldWithType('count', TDynField.TType.TInt).ival); end;
+function TDynRecordHelper.trigItemEffect (): Byte; inline; begin result := Byte(getFieldWithType('effect', TDynField.TType.TUByte).ival); end;
+function TDynRecordHelper.trigItemMax (): Word; inline; begin result := Word(getFieldWithType('max', TDynField.TType.TUShort).ival); end;
+function TDynRecordHelper.trigItemDelay (): Word; inline; begin result := Word(getFieldWithType('delay', TDynField.TType.TUShort).ival); end;
+
+// TRIGGER_MUSIC
+function TDynRecordHelper.trigMusicName (): AnsiString; inline; begin result := utf2win(getFieldWithType('name', TDynField.TType.TChar).sval); end;
+function TDynRecordHelper.trigMusicAction (): Byte; inline; begin result := Byte(getFieldWithType('action', TDynField.TType.TUByte).ival); end;
+
+// TRIGGER_PUSH
+function TDynRecordHelper.trigPushAngle (): Word; inline; begin result := Word(getFieldWithType('angle', TDynField.TType.TUShort).ival); end;
+function TDynRecordHelper.trigPushForce (): Byte; inline; begin result := Byte(getFieldWithType('force', TDynField.TType.TUByte).ival); end;
+function TDynRecordHelper.trigResetVel (): Boolean; inline; begin result := (getFieldWithType('resetvelocity', TDynField.TType.TBool).ival <> 0); end;
+
+// TRIGGER_SCORE
+function TDynRecordHelper.trigScoreAction (): Byte; inline; begin result := Byte(getFieldWithType('action', TDynField.TType.TUByte).ival); end;
+function TDynRecordHelper.trigScoreCount (): Byte; inline; begin result := Byte(getFieldWithType('count', TDynField.TType.TUByte).ival); end;
+function TDynRecordHelper.trigScoreTeam (): Byte; inline; begin result := Byte(getFieldWithType('team', TDynField.TType.TUByte).ival); end;
+function TDynRecordHelper.trigScoreCon (): Boolean; inline; begin result := (getFieldWithType('console', TDynField.TType.TBool).ival <> 0); end;
+function TDynRecordHelper.trigScoreMsg (): Boolean; inline; begin result := (getFieldWithType('message', TDynField.TType.TBool).ival <> 0); end;
+
+// TRIGGER_MESSAGE
+function TDynRecordHelper.trigMessageKind (): Byte; inline; begin result := Byte(getFieldWithType('kind', TDynField.TType.TUByte).ival); end;
+function TDynRecordHelper.trigMessageSendTo (): Byte; inline; begin result := Byte(getFieldWithType('sendto', TDynField.TType.TUByte).ival); end;
+function TDynRecordHelper.trigMessageText (): AnsiString; inline; begin result := utf2win(getFieldWithType('text', TDynField.TType.TChar).sval); end;
+function TDynRecordHelper.trigMessageTime (): Word; inline; begin result := Word(getFieldWithType('time', TDynField.TType.TUShort).ival); end;
+
+// TRIGGER_DAMAGE
+function TDynRecordHelper.trigDamageValue (): Word; inline; begin result := Word(getFieldWithType('amount', TDynField.TType.TUShort).ival); end;
+function TDynRecordHelper.trigDamageInterval (): Word; inline; begin result := Word(getFieldWithType('interval', TDynField.TType.TUShort).ival); end;
+
+// TRIGGER_HEALTH
+function TDynRecordHelper.trigHealValue (): Word; inline; begin result := Word(getFieldWithType('amount', TDynField.TType.TUShort).ival); end;
+function TDynRecordHelper.trigHealInterval (): Word; inline; begin result := Word(getFieldWithType('interval', TDynField.TType.TUShort).ival); end;
+function TDynRecordHelper.trigHealMax (): Boolean; inline; begin result := (getFieldWithType('max', TDynField.TType.TBool).ival <> 0); end;
+function TDynRecordHelper.trigHealSilent (): Boolean; inline; begin result := (getFieldWithType('silent', TDynField.TType.TBool).ival <> 0); end;
+
+// TRIGGER_SHOT
+function TDynRecordHelper.trigShotPos (): TDFPoint; inline; begin result := getPointField('position'); end;
+function TDynRecordHelper.trigShotType (): Byte; inline; begin result := Byte(getFieldWithType('type', TDynField.TType.TUByte).ival); end;
+function TDynRecordHelper.trigShotTarget (): Byte; inline; begin result := Byte(getFieldWithType('target', TDynField.TType.TUByte).ival); end;
+function TDynRecordHelper.trigShotSound (): Boolean; inline; begin result := (getFieldWithType('silent', TDynField.TType.TBool).ival = 0); end;
+function TDynRecordHelper.trigShotAim (): SmallInt; inline; begin result := ShortInt(getFieldWithType('aim', TDynField.TType.TByte).ival); end;
+function TDynRecordHelper.trigShotIntSight (): Word; inline; begin result := Word(getFieldWithType('sight', TDynField.TType.TUShort).ival); end;
+function TDynRecordHelper.trigShotAngle (): Word; inline; begin result := Word(getFieldWithType('angle', TDynField.TType.TUShort).ival); end;
+function TDynRecordHelper.trigShotWait (): Word; inline; begin result := Word(getFieldWithType('wait', TDynField.TType.TUShort).ival); end;
+function TDynRecordHelper.trigShotAccuracy (): Word; inline; begin result := Word(getFieldWithType('accuracy', TDynField.TType.TUShort).ival); end;
+function TDynRecordHelper.trigShotAmmo (): Word; inline; begin result := Word(getFieldWithType('ammo', TDynField.TType.TUShort).ival); end;
+function TDynRecordHelper.trigShotIntReload (): Word; inline; begin result := Word(getFieldWithType('reload', TDynField.TType.TUShort).ival); end;
+
+// TRIGGER_EFFECT
+function TDynRecordHelper.trigFXCount (): Byte; inline; begin result := Byte(getFieldWithType('count', TDynField.TType.TUByte).ival); end;
+function TDynRecordHelper.trigFXType (): Byte; inline; begin result := Byte(getFieldWithType('type', TDynField.TType.TUByte).ival); end;
+function TDynRecordHelper.trigFXSubType (): Byte; inline; begin result := Byte(getFieldWithType('subtype', TDynField.TType.TUByte).ival); end;
+function TDynRecordHelper.trigFXColorR (): Byte; inline; begin result := Byte(getFieldWithType('colorr', TDynField.TType.TUByte).ival); end;
+function TDynRecordHelper.trigFXColorG (): Byte; inline; begin result := Byte(getFieldWithType('colorg', TDynField.TType.TUByte).ival); end;
+function TDynRecordHelper.trigFXColorB (): Byte; inline; begin result := Byte(getFieldWithType('colorb', TDynField.TType.TUByte).ival); end;
+function TDynRecordHelper.trigFXPos (): Byte; inline; begin result := Byte(getFieldWithType('position', TDynField.TType.TUByte).ival); end;
+function TDynRecordHelper.trigFXWait (): Word; inline; begin result := Word(getFieldWithType('wait', TDynField.TType.TUShort).ival); end;
+function TDynRecordHelper.trigFXVelX (): SmallInt; inline; begin result := ShortInt(getFieldWithType('velx', TDynField.TType.TByte).ival); end;
+function TDynRecordHelper.trigFXVelY (): SmallInt; inline; begin result := ShortInt(getFieldWithType('vely', TDynField.TType.TByte).ival); end;
+function TDynRecordHelper.trigFXSpreadL (): Byte; inline; begin result := Byte(getFieldWithType('spreadl', TDynField.TType.TUByte).ival); end;
+function TDynRecordHelper.trigFXSpreadR (): Byte; inline; begin result := Byte(getFieldWithType('spreadr', TDynField.TType.TUByte).ival); end;
+function TDynRecordHelper.trigFXSpreadU (): Byte; inline; begin result := Byte(getFieldWithType('spreadu', TDynField.TType.TUByte).ival); end;
+function TDynRecordHelper.trigFXSpreadD (): Byte; inline; begin result := Byte(getFieldWithType('spreadd', TDynField.TType.TUByte).ival); end;
index 37d27dfca414f09c812edf9af38aa0ed6c9a31be..8ebac36188754ef6349bbb7bbc5147a1a0ccfe7a 100644 (file)
@@ -63,7 +63,6 @@ type
     mRecRef: TDynRecord; // for TEBS.TRec
     mMaxDim: Integer; // for byte and char arrays; <0: not an array; 0: impossible value
     mBinOfs: Integer; // offset in binary; <0 - none
-    mRecOfs: Integer; // offset in record; <0 - none
     mSepPosSize: Boolean; // for points and sizes, use separate fields
     mAsT: Boolean; // for points and sizes, use separate fields, names starts with `t`
     mDefined: Boolean;
@@ -85,6 +84,10 @@ type
     // for binary parser
     mRecRefId: AnsiString;
 
+    // for userdata
+    mTagInt: Integer;
+    mTagPtr: Pointer;
+
   private
     procedure cleanup ();
 
@@ -98,10 +101,27 @@ type
     function getListItem (idx: Integer): TDynRecord; inline; overload;
     function getListItem (const aname: AnsiString): TDynRecord; inline; overload;
 
+    function getRecRefIndex (): Integer;
+
+    procedure setIVal (v: Integer); inline;
+
   protected
     // returns `true` for duplicate record id
     function addListItem (rec: TDynRecord): Boolean; inline;
 
+  public
+    type
+      TListEnumerator = record
+      private
+        mList: TDynRecList;
+        mCurIdx: Integer;
+      public
+        constructor Create (alist: TDynRecList);
+        function MoveNext (): Boolean; inline;
+        function getCurrent (): TDynRecord; inline;
+        property Current: TDynRecord read getCurrent;
+      end;
+
   public
     constructor Create (const aname: AnsiString; atype: TType);
     constructor Create (pr: TTextParser);
@@ -125,28 +145,35 @@ type
 
     procedure setValue (const s: AnsiString);
 
+    function GetEnumerator (): TListEnumerator;
+
   public
     property pasname: AnsiString read mPasName;
     property name: AnsiString read mName;
     property baseType: TType read mType;
+    property negbool: Boolean read mNegBool;
     property defined: Boolean read mDefined write mDefined;
     property internal: Boolean read mInternal write mInternal;
-    property ival: Integer read mIVal;
+    property hasTPrefix: Boolean read mAsT;
+    property separatePasFields: Boolean read mSepPosSize;
+    property binOfs: Integer read mBinOfs;
+    property ival: Integer read mIVal write setIVal;
+    property ival2: Integer read mIVal2;
     property sval: AnsiString read mSVal;
     property hasDefault: Boolean read mHasDefault;
     property defsval: AnsiString read mDefSVal;
     property ebs: TEBS read mEBS;
     property ebstype: TObject read mEBSType;
     property ebstypename: AnsiString read mEBSTypeName; // enum/bitset name
+    property recref: TDynRecord read mRecRef write mRecRef; //FIXME: writing is a hack!
+    property recrefIndex: Integer read getRecRefIndex; // search for this record in header; -1: not found
     // for lists
     property count: Integer read getListCount;
     property item[idx: Integer]: TDynRecord read getListItem;
     property items[const aname: AnsiString]: TDynRecord read getListItem; default; // alas, FPC 3+ lost property overloading feature
-
-    property x: Integer read mIVal;
-    property w: Integer read mIVal;
-    property y: Integer read mIVal2;
-    property h: Integer read mIVal2;
+    // userdata
+    property tagInt: Integer read mTagInt write mTagInt;
+    property tagPtr: Pointer read mTagPtr write mTagPtr;
   end;
 
 
@@ -167,16 +194,25 @@ type
     mBinBlock: Integer; // -1: none
     mHeaderRec: TDynRecord; // for "value" records this is header record with data, for "type" records this is header type record
 
+    // for userdata
+    mTagInt: Integer;
+    mTagPtr: Pointer;
+
   private
     procedure parseDef (pr: TTextParser); // parse definition
 
     function findByName (const aname: AnsiString): Integer; inline;
     function hasByName (const aname: AnsiString): Boolean; inline;
     function getFieldByName (const aname: AnsiString): TDynField; inline;
+    function getFieldAt (idx: Integer): TDynField; inline;
+    function getCount (): Integer; inline;
 
     function getIsTrigData (): Boolean; inline;
     function getIsForTrig (const aname: AnsiString): Boolean; inline;
 
+    function getForTrigCount (): Integer; inline;
+    function getForTrigAt (idx: Integer): AnsiString; inline;
+
   protected
     function findRecordByTypeId (const atypename, aid: AnsiString): TDynRecord;
     function findRecordNumByType (const atypename: AnsiString; rc: TDynRecord): Integer;
@@ -216,11 +252,18 @@ type
     property size: Integer read mSize; // size in bytes
     //property fields: TDynFieldList read mFields;
     property has[const aname: AnsiString]: Boolean read hasByName;
-    property field[const aname: AnsiString]: TDynField read getFieldByName;
+    property count: Integer read getCount;
+    property field[const aname: AnsiString]: TDynField read getFieldByName; default;
+    property fieldAt[idx: Integer]: TDynField read getFieldAt;
     property isTrigData: Boolean read getIsTrigData;
     property isForTrig[const aname: AnsiString]: Boolean read getIsForTrig;
-    property headerType: TDynRecord read mHeaderRec;
+    property forTrigCount: Integer read getForTrigCount;
+    property forTrigAt[idx: Integer]: AnsiString read getForTrigAt;
+    property headerRec: TDynRecord read mHeaderRec;
     property isHeader: Boolean read mHeader;
+    // userdata
+    property tagInt: Integer read mTagInt write mTagInt;
+    property tagPtr: Pointer read mTagPtr write mTagPtr;
   end;
 
   TDynEBS = class
@@ -271,6 +314,9 @@ type
 
     function getHeaderRecType (): TDynRecord; inline;
 
+    function getTrigTypeCount (): Integer; inline;
+    function getTrigTypeAt (idx: Integer): TDynRecord; inline;
+
   public
     constructor Create (pr: TTextParser); // parses data definition
     destructor Destroy (); override;
@@ -280,6 +326,7 @@ type
     function findEBSType (const aname: AnsiString): TDynEBS;
 
     function pasdef (): AnsiString;
+    function pasdefconst (): AnsiString;
 
     // creates new header record
     function parseMap (pr: TTextParser): TDynRecord;
@@ -289,6 +336,8 @@ type
 
   public
     property headerType: TDynRecord read getHeaderRecType;
+    property trigTypeCount: Integer read getTrigTypeCount;
+    property trigType[idx: Integer]: TDynRecord read getTrigTypeAt;
   end;
 
 
@@ -308,6 +357,33 @@ uses
 function StrEqu (const a, b: AnsiString): Boolean; inline; begin result := (a = b); end;
 
 
+// ////////////////////////////////////////////////////////////////////////// //
+constructor TDynField.TListEnumerator.Create (alist: TDynRecList);
+begin
+  mList := alist;
+  mCurIdx := -1;
+end;
+
+
+function TDynField.TListEnumerator.MoveNext (): Boolean; inline;
+begin
+  Inc(mCurIdx);
+  result := (mList <> nil) and (mCurIdx < mList.count);
+end;
+
+
+function TDynField.TListEnumerator.getCurrent (): TDynRecord; inline;
+begin
+  result := mList[mCurIdx];
+end;
+
+
+function TDynField.GetEnumerator (): TListEnumerator;
+begin
+  result := TListEnumerator.Create(mRVal);
+end;
+
+
 // ////////////////////////////////////////////////////////////////////////// //
 constructor TDynField.Create (const aname: AnsiString; atype: TType);
 begin
@@ -353,7 +429,6 @@ begin
   mRecRef := nil;
   mMaxDim := -1;
   mBinOfs := -1;
-  mRecOfs := -1;
   mSepPosSize := false;
   mAsT := false;
   mHasDefault := false;
@@ -372,6 +447,8 @@ begin
   mAsMonsterId := false;
   mNegBool := false;
   mRecRefId := '';
+  mTagInt := 0;
+  mTagPtr := nil;
 end;
 
 
@@ -397,7 +474,6 @@ begin
   result.mRecRef := mRecRef;
   result.mMaxDim := mMaxDim;
   result.mBinOfs := mBinOfs;
-  result.mRecOfs := mRecOfs;
   result.mSepPosSize := mSepPosSize;
   result.mAsT := mAsT;
   result.mDefined := mDefined;
@@ -416,6 +492,16 @@ begin
   result.mEBSTypeName := mEBSTypeName;
   result.mEBSType := mEBSType;
   result.mRecRefId := mRecRefId;
+  result.mTagInt := mTagInt;
+  result.mTagPtr := mTagPtr;
+end;
+
+
+procedure TDynField.setIVal (v: Integer); inline;
+begin
+  //FIXME: check type
+  mIVal := v;
+  mDefined := true;
 end;
 
 
@@ -590,7 +676,7 @@ begin
   result := mPasName+' is '+quoteStr(mName)+' type ';
   result += getTypeName(mType);
   if (mMaxDim >= 0) then result += Format('[%d]', [mMaxDim]);
-  if (mRecOfs >= 0) then result += Format(' offset %d', [mRecOfs]);
+  if (mBinOfs >= 0) then result += Format(' offset %d', [mBinOfs]);
   case mEBS of
     TEBS.TNone: begin end;
     TEBS.TRec: result += ' '+mEBSTypeName;
@@ -814,7 +900,6 @@ begin
   self.mAsMonsterId := asmonid;
   self.mMaxDim := lmaxdim;
   self.mBinOfs := fldofs;
-  self.mRecOfs := fldofs;
   self.mSepPosSize := (asxy or aswh);
   self.mAsT := ast;
   self.mOmitDef := omitdef;
@@ -822,6 +907,13 @@ begin
 end;
 
 
+function TDynField.getRecRefIndex (): Integer;
+begin
+  if (mRecRef = nil) then begin result := -1; exit; end;
+  result := mOwner.findRecordNumByType(mEBSTypeName, mRecRef);
+end;
+
+
 procedure TDynField.writeBinTo (st: TStream);
 var
   s: AnsiString;
@@ -1122,6 +1214,7 @@ begin
   raise Exception.Create(Format('cannot parse field ''%s'' yet', [mName]));
 end;
 
+
 procedure TDynField.parseBinValue (st: TStream);
 var
   rec, rc: TDynRecord;
@@ -1564,6 +1657,8 @@ begin
   mHeader := false;
   mHeaderRec := nil;
   mBinBlock := -1;
+  mTagInt := 0;
+  mTagPtr := nil;
   parseDef(pr);
 end;
 
@@ -1579,6 +1674,8 @@ begin
   mTrigTypes := nil;
   mHeader := false;
   mHeaderRec := nil;
+  mTagInt := 0;
+  mTagPtr := nil;
 end;
 
 
@@ -1593,6 +1690,8 @@ begin
   {$ENDIF}
   mTrigTypes := nil;
   mHeaderRec := nil;
+  mTagInt := 0;
+  mTagPtr := nil;
   inherited;
 end;
 
@@ -1652,6 +1751,18 @@ begin
 end;
 
 
+function TDynRecord.getFieldAt (idx: Integer): TDynField; inline;
+begin
+  if (idx >= 0) and (idx < mFields.count) then result := mFields[idx] else result := nil;
+end;
+
+
+function TDynRecord.getCount (): Integer; inline;
+begin
+  result := mFields.count;
+end;
+
+
 function TDynRecord.getIsTrigData (): Boolean; inline;
 begin
   result := (Length(mTrigTypes) > 0);
@@ -1668,6 +1779,18 @@ begin
 end;
 
 
+function TDynRecord.getForTrigCount (): Integer; inline;
+begin
+  result := Length(mTrigTypes);
+end;
+
+
+function TDynRecord.getForTrigAt (idx: Integer): AnsiString; inline;
+begin
+  if (idx >= 0) and (idx < Length(mTrigTypes)) then result := mTrigTypes[idx] else result := '';
+end;
+
+
 function TDynRecord.clone (): TDynRecord;
 var
   fld: TDynField;
@@ -1689,6 +1812,8 @@ begin
   result.mHeader := mHeader;
   result.mBinBlock := mBinBlock;
   result.mHeaderRec := mHeaderRec;
+  result.mTagInt := mTagInt;
+  result.mTagPtr := mTagPtr;
 end;
 
 
@@ -2815,4 +2940,19 @@ begin
 end;
 
 
+function TDynMapDef.pasdefconst (): AnsiString;
+var
+  ebs: TDynEBS;
+begin
+  result := '';
+  result += '// ////////////////////////////////////////////////////////////////////////// //'#10;
+  result += '// enums and bitsets'#10;
+  for ebs in ebsTypes do result += #10+ebs.pasdef();
+end;
+
+
+function TDynMapDef.getTrigTypeCount (): Integer; inline; begin result := trigTypes.count; end;
+function TDynMapDef.getTrigTypeAt (idx: Integer): TDynRecord; inline; begin if (idx >= 0) and (idx < trigTypes.count) then result := trigTypes[idx] else result := nil; end;
+
+
 end.
index 9a98f712be4e676662a34514530cdf60997f14ff..c53aa4eb9ee22b74608b8e0d873f53c3d7df9db3 100644 (file)
@@ -19,11 +19,15 @@ uses
 var
   pr: TTextParser;
   dfmapdef: TDynMapDef;
-  fo: TextFile;
+  fo, fohlp, foimpl: TextFile;
   st: TStream = nil;
   ch: AnsiChar;
   wdt: Integer;
   s: AnsiString;
+  tidx, nidx, fidx: Integer;
+  needComma: Boolean;
+  trec: TDynRecord;
+  fld: TDynField;
 begin
   //writeln(getFilenamePath(ParamStr(0)), '|');
 
@@ -60,9 +64,156 @@ begin
   writeln('writing "mapdef.inc"...');
   AssignFile(fo, 'mapdef.inc');
   Rewrite(fo);
+
+  AssignFile(fohlp, 'mapdef_help.inc');
+  Rewrite(fohlp);
+
+  AssignFile(foimpl, 'mapdef_impl.inc');
+  Rewrite(foimpl);
+
   write(fo, '// *** WARNING! ***'#10);
   write(fo, '//   regenerate this part directly from "mapdef.txt" with ''mapgen'', NEVER manually change anything here!'#10#10#10);
-  write(fo, dfmapdef.pasdef);
+  write(fo, dfmapdef.pasdefconst);
+
+  write(fohlp, '// *** WARNING! ***'#10);
+  write(fohlp, '//   regenerate this part directly from "mapdef.txt" with ''mapgen'', NEVER manually change anything here!'#10#10);
+
+  // generate trigger helpers
+{
+function TDynRecordHelper.trigTargetPoint (): TDFPoint; inline; begin result := getPointField('target'); end;
+function TDynRecordHelper.trigD2DTeleport (): Boolean; inline; begin result := (getFieldWithType('d2d', TDynField.TType.TBool).ival <> 0); end;
+function TDynRecordHelper.trigSilentTeleport (): Boolean; inline; begin result := (getFieldWithType('silent', TDynField.TType.TBool).ival <> 0); end;
+function TDynRecordHelper.trigTlpDir (): Byte; inline; begin result := Byte(getFieldWithType('direction', TDynField.TType.TUByte).ival); end;
+}
+
+  write(foimpl, #10#10'// ////////////////////////////////////////////////////////////////////////// //'#10);
+  write(foimpl, '// trigger helpers'#10);
+  for tidx := 0 to dfmapdef.trigTypeCount-1 do
+  begin
+    // header comment
+    write(foimpl, #10'// ');
+    needComma := false;
+    trec := dfmapdef.trigType[tidx];
+    for nidx := 0 to trec.forTrigCount-1 do
+    begin
+      if needComma then write(foimpl, ', ') else needComma := true;
+      write(foimpl, trec.forTrigAt[nidx]);
+    end;
+    write(foimpl, #10);
+    // fields
+    for fidx := 0 to trec.count-1 do
+    begin
+      fld := trec.fieldAt[fidx];
+      if fld.internal then continue;
+      if (fld.binOfs < 0) then continue;
+      // HACK!
+      if (fld.name = 'panelid') or (fld.name = 'monsterid') then
+      begin
+        writeln('skipping ', fld.pasname, ' <', fld.name, '>');
+        continue;
+      end;
+      if (fld.baseType <> TDynField.TType.TPoint) and (fld.baseType <> TDynField.TType.TSize) then
+      begin
+        write(foimpl, 'function TDynRecordHelper.trig', fld.pasname, ' (): ');
+        write(fohlp, 'function trig', fld.pasname, ' (): ');
+      end;
+      case fld.baseType of
+        TDynField.TType.TBool:
+          begin
+            write(fohlp, 'Boolean; inline;'#10);
+            write(foimpl, 'Boolean; inline; begin result := (getFieldWithType(''', fld.name, ''', TDynField.TType.TBool).ival ');
+            if fld.negbool then write(foimpl, '=') else write(foimpl, '<>');
+            write(foimpl, ' 0); end;'#10);
+          end;
+        TDynField.TType.TChar:
+          begin
+            write(fohlp, 'AnsiString; inline;'#10);
+            write(foimpl, 'AnsiString; inline; begin result := utf2win(getFieldWithType(''', fld.name, ''', TDynField.TType.TChar).sval); end;'#10);
+          end;
+        TDynField.TType.TByte:
+          begin
+            write(fohlp, 'SmallInt; inline;'#10);
+            write(foimpl, 'SmallInt; inline; begin result := ShortInt(getFieldWithType(''', fld.name, ''', TDynField.TType.TByte).ival); end;'#10);
+          end;
+        TDynField.TType.TUByte:
+          begin
+            write(fohlp, 'Byte; inline;'#10);
+            write(foimpl, 'Byte; inline; begin result := Byte(getFieldWithType(''', fld.name, ''', TDynField.TType.TUByte).ival); end;'#10);
+          end;
+        TDynField.TType.TShort:
+          begin
+            write(fohlp, 'ShortInt; inline;'#10);
+            write(foimpl, 'ShortInt; inline; begin result := SmallInt(getFieldWithType(''', fld.name, ''', TDynField.TType.TShort).ival); end;'#10);
+          end;
+        TDynField.TType.TUShort:
+          begin
+            write(fohlp, 'Word; inline;'#10);
+            write(foimpl, 'Word; inline; begin result := Word(getFieldWithType(''', fld.name, ''', TDynField.TType.TUShort).ival); end;'#10);
+          end;
+        TDynField.TType.TInt:
+          begin
+            write(fohlp, 'LongInt; inline;'#10);
+            write(foimpl, 'LongInt; inline; begin result := LongInt(getFieldWithType(''', fld.name, ''', TDynField.TType.TInt).ival); end;'#10);
+          end;
+        TDynField.TType.TUInt:
+          begin
+            write(fohlp, 'LongWord; inline;'#10);
+            write(foimpl, 'LongWord; inline; begin result := LongWord(getFieldWithType(''', fld.name, ''', TDynField.TType.TUInt).ival); end;'#10);
+          end;
+        TDynField.TType.TString:
+          begin
+            write(fohlp, 'AnsiString; inline;'#10);
+            write(foimpl, 'AnsiString; inline; begin result := utf2win(getFieldWithType(''', fld.name, ''', TDynField.TType.TChar).sval); end;'#10);
+          end;
+        TDynField.TType.TPoint:
+          begin
+            if fld.hasTPrefix or fld.separatePasFields then
+            begin
+              write(fohlp, 'function trig'); if fld.hasTPrefix then write(fohlp, 'T'); write(fohlp, 'X (): LongInt; inline;'#10);
+              write(fohlp, 'function trig'); if fld.hasTPrefix then write(fohlp, 'T'); write(fohlp, 'Y (): LongInt; inline;'#10);
+              // [T]X
+              write(foimpl, 'function TDynRecordHelper.trig');
+              if fld.hasTPrefix then write(foimpl, 'T');
+              write(foimpl, 'X (): LongInt; inline; begin result := LongInt(getFieldWithType(''', fld.name, ''', TDynField.TType.TPoint).ival); end;'#10);
+              // [T]Y
+              write(foimpl, 'function TDynRecordHelper.trig');
+              if fld.hasTPrefix then write(foimpl, 'T');
+              write(foimpl, 'Y (): LongInt; inline; begin result := LongInt(getFieldWithType(''', fld.name, ''', TDynField.TType.TPoint).ival2); end;'#10);
+            end
+            else
+            begin
+              write(fohlp, 'function trig', fld.pasname, ' (): TDFPoint; inline;'#10);
+              write(foimpl, 'function TDynRecordHelper.trig', fld.pasname, ' (): TDFPoint; inline; begin result := getPointField(''', fld.name, '''); end;'#10);
+            end;
+          end;
+        TDynField.TType.TSize:
+          begin
+            if fld.hasTPrefix or fld.separatePasFields then
+            begin
+              write(fohlp, 'function trig'); if fld.hasTPrefix then write(fohlp, 'T'); write(fohlp, 'Width (): Word; inline;'#10);
+              write(fohlp, 'function trig'); if fld.hasTPrefix then write(fohlp, 'T'); write(fohlp, 'Height (): Word; inline;'#10);
+              // [T]X
+              write(foimpl, 'function TDynRecordHelper.trig');
+              if fld.hasTPrefix then write(foimpl, 'T');
+              write(foimpl, 'Width (): Word; inline; begin result := Word(getFieldWithType(''', fld.name, ''', TDynField.TType.TSize).ival); end;'#10);
+              // [T]Y
+              write(foimpl, 'function TDynRecordHelper.trig');
+              if fld.hasTPrefix then write(foimpl, 'T');
+              write(foimpl, 'Height (): Word; inline; begin result := Word(getFieldWithType(''', fld.name, ''', TDynField.TType.TSize).ival2); end;'#10);
+            end
+            else
+            begin
+              raise Exception.Create('no non-separate sizes in triggers, pelase');
+            end;
+          end;
+        TDynField.TType.TList:
+          raise Exception.Create('no lists in triggers, pelase');
+        TDynField.TType.TTrigData:
+          raise Exception.Create('no triggers in triggers, pelase');
+      end;
+    end;
+  end;
+
 
   //st := openDiskFileRO('mapdef.txt');
   st.position := 0;
@@ -79,4 +230,6 @@ begin
   write(fo, #10';');
 
   CloseFile(fo);
+  CloseFile(fohlp);
+  CloseFile(foimpl);
 end.