DEADSOFTWARE

field namefix: `FLive` -> `FAlive`; `live` -> `alive`
[d2df-sdl.git] / src / game / g_triggers.pas
index be680ecb8e9f7e4698e3d0648b135d4b737c3d54..2da3a1e8dcdb267c264d22ef5fbd916845927085 100644 (file)
@@ -27,7 +27,9 @@ type
     UID:     Word;
     TimeOut: Word;
   end;
+  PTrigger = ^TTrigger;
   TTrigger = record
+  public
     ID:               DWORD;
     ClientID:         DWORD;
     TriggerType:      Byte;
@@ -36,7 +38,7 @@ type
     Enabled:          Boolean;
     ActivateType:     Byte;
     Keys:             Byte;
-    TexturePanel:     Integer;
+    TexturePanelGUID: Integer;
     TexturePanelType: Word;
 
     TimeOut:          Word;
@@ -60,14 +62,21 @@ type
     ShotAmmoCount:    Word;
     ShotReloadTime:   Integer;
 
-    trigShotPanelId: Integer;
-    trigPanelId: Integer;
+    mapId: AnsiString; // trigger id, from map
+    mapIndex: Integer; // index in fields['trigger'], used in save/load
+    trigPanelGUID: Integer;
 
     //TrigData:             TTriggerData;
     trigData: TDynRecord; // triggerdata; owned by trigger
+
+  public
+    function trigCenter (): TDFPoint; inline;
+
+  public
+    property trigShotPanelGUID: Integer read trigPanelGUID write trigPanelGUID;
   end;
 
-function g_Triggers_Create(Trigger: TTrigger): DWORD;
+function g_Triggers_Create(Trigger: TTrigger; forceInternalIndex: Integer=-1): DWORD;
 procedure g_Triggers_Update();
 procedure g_Triggers_Press(ID: DWORD; ActivateType: Byte; ActivateUID: Word = 0);
 function g_Triggers_PressR(X, Y: Integer; Width, Height: Word; UID: Word;
@@ -80,18 +89,6 @@ procedure g_Triggers_Free();
 procedure g_Triggers_SaveState(var Mem: TBinMemoryWriter);
 procedure g_Triggers_LoadState(var Mem: TBinMemoryReader);
 
-function tr_Message(MKind: Integer; MText: string; MSendTo: Integer; MTime: Integer; ActivateUID: Integer): Boolean;
-
-function tr_CloseDoor(PanelID: Integer; NoSound: Boolean; d2d: Boolean): Boolean;
-function tr_OpenDoor(PanelID: Integer; NoSound: Boolean; d2d: Boolean): Boolean;
-procedure tr_CloseTrap(PanelID: Integer; NoSound: Boolean; d2d: Boolean);
-function tr_SetLift(PanelID: Integer; d: Integer; NoSound: Boolean; d2d: Boolean): Boolean;
-
-function tr_Teleport(ActivateUID: Integer; TX, TY: Integer; TDir: Integer; Silent: Boolean; D2D: Boolean): Boolean;
-function tr_Push(ActivateUID: Integer; VX, VY: Integer; ResetVel: Boolean): Boolean;
-
-procedure tr_MakeEffect(X, Y, VX, VY: Integer; T, ST, CR, CG, CB: Byte; Silent, Send: Boolean);
-function tr_SpawnShot(ShotType: Integer; wx, wy, dx, dy: Integer; ShotSound: Boolean; ShotTarget: Word): Integer;
 
 var
   gTriggerClientID: Integer = 0;
@@ -99,121 +96,139 @@ var
   gSecretsCount: Integer = 0;
   gMonstersSpawned: array of LongInt = nil;
 
+
 implementation
 
 uses
-  g_player, g_map, Math, g_gfx, g_game, g_textures,
+  Math,
+  g_player, g_map, g_panel, g_gfx, g_game, g_textures,
   g_console, g_monsters, g_items, g_phys, g_weapons,
   wadreader, g_main, SysUtils, e_log, g_language,
-  g_options, g_net, g_netmsg, utils;
+  g_options, g_net, g_netmsg, utils, xparser;
 
 const
-  TRIGGER_SIGNATURE = $52475254; // 'TRGR'
+  TRIGGER_SIGNATURE = $58475254; // 'TRGX'
   TRAP_DAMAGE = 1000;
 
-function FindTrigger(): DWORD;
+
+function TTrigger.trigCenter (): TDFPoint; inline;
+begin
+  result := TDFPoint.Create(x+width div 2, y+height div 2);
+end;
+
+
+function FindTrigger (): DWORD;
 var
   i: Integer;
 begin
-  if gTriggers <> nil then
-    for i := 0 to High(gTriggers) do
-      if gTriggers[i].TriggerType = TRIGGER_NONE then
-      begin
-        Result := i;
-        Exit;
-      end;
+  for i := 0 to High(gTriggers) do
+  begin
+    if gTriggers[i].TriggerType = TRIGGER_NONE then begin result := i; exit; end;
+  end;
 
-  if gTriggers = nil then
+  if (gTriggers = nil) then
   begin
     SetLength(gTriggers, 8);
-    Result := 0;
+    result := 0;
   end
   else
   begin
-    Result := High(gTriggers) + 1;
-    SetLength(gTriggers, Length(gTriggers) + 8);
+    result := Length(gTriggers);
+    SetLength(gTriggers, result+8);
+    for i := result to High(gTriggers) do gTriggers[i].TriggerType := TRIGGER_NONE;
   end;
 end;
 
-function tr_CloseDoor(PanelID: Integer; NoSound: Boolean; d2d: Boolean): Boolean;
+
+function tr_CloseDoor (PanelGUID: Integer; NoSound: Boolean; d2d: Boolean): Boolean;
 var
   a, b, c: Integer;
+  pan: TPanel;
+  PanelID: Integer;
 begin
-  Result := False;
-
-  if PanelID = -1 then Exit;
+  result := false;
+  pan := g_Map_PanelByGUID(PanelGUID);
+  if (pan = nil) or not pan.isGWall then exit; //!FIXME!TRIGANY!
+  PanelID := pan.arrIdx;
 
   if not d2d then
   begin
     with gWalls[PanelID] do
     begin
-      if g_CollidePlayer(X, Y, Width, Height) or
-         g_Mons_IsAnyAliveAt(X, Y, Width, Height) then Exit;
-
+      if g_CollidePlayer(X, Y, Width, Height) or g_Mons_IsAnyAliveAt(X, Y, Width, Height) then Exit;
       if not Enabled then
       begin
         if not NoSound then
         begin
           g_Sound_PlayExAt('SOUND_GAME_DOORCLOSE', X, Y);
-          if g_Game_IsServer and g_Game_IsNet then
-            MH_SEND_Sound(X, Y, 'SOUND_GAME_DOORCLOSE');
+          if g_Game_IsServer and g_Game_IsNet then MH_SEND_Sound(X, Y, 'SOUND_GAME_DOORCLOSE');
         end;
-        g_Map_EnableWall(PanelID);
-        Result := True;
+        g_Map_EnableWallGUID(PanelGUID);
+        result := true;
       end;
     end;
   end
   else
   begin
-    if gDoorMap = nil then Exit;
+    if (gDoorMap = nil) then exit;
 
     c := -1;
     for a := 0 to High(gDoorMap) do
     begin
       for b := 0 to High(gDoorMap[a]) do
+      begin
         if gDoorMap[a, b] = DWORD(PanelID) then
         begin
           c := a;
-          Break;
+          break;
         end;
-
-      if c <> -1 then Break;
+      end;
+      if (c <> -1) then break;
     end;
-    if c = -1 then Exit;
+    if (c = -1) then exit;
 
     for b := 0 to High(gDoorMap[c]) do
+    begin
       with gWalls[gDoorMap[c, b]] do
       begin
-        if g_CollidePlayer(X, Y, Width, Height) or
-          g_Mons_IsAnyAliveAt(X, Y, Width, Height) then Exit;
+        if g_CollidePlayer(X, Y, Width, Height) or g_Mons_IsAnyAliveAt(X, Y, Width, Height) then exit;
       end;
+    end;
 
     if not NoSound then
+    begin
       for b := 0 to High(gDoorMap[c]) do
+      begin
         if not gWalls[gDoorMap[c, b]].Enabled then
         begin
           with gWalls[PanelID] do
           begin
             g_Sound_PlayExAt('SOUND_GAME_DOORCLOSE', X, Y);
-            if g_Game_IsServer and g_Game_IsNet then
-              MH_SEND_Sound(X, Y, 'SOUND_GAME_DOORCLOSE');
+            if g_Game_IsServer and g_Game_IsNet then MH_SEND_Sound(X, Y, 'SOUND_GAME_DOORCLOSE');
           end;
-          Break;
+          break;
         end;
+      end;
+    end;
 
     for b := 0 to High(gDoorMap[c]) do
+    begin
       if not gWalls[gDoorMap[c, b]].Enabled then
       begin
-        g_Map_EnableWall(gDoorMap[c, b]);
-        Result := True;
+        g_Map_EnableWall_XXX(gDoorMap[c, b]);
+        result := true;
       end;
+    end;
   end;
 end;
 
-procedure tr_CloseTrap(PanelID: Integer; NoSound: Boolean; d2d: Boolean);
+
+procedure tr_CloseTrap (PanelGUID: Integer; NoSound: Boolean; d2d: Boolean);
 var
   a, b, c: Integer;
   wx, wy, wh, ww: Integer;
+  pan: TPanel;
+  PanelID: Integer;
 
   function monsDamage (mon: TMonster): Boolean;
   begin
@@ -222,7 +237,19 @@ var
   end;
 
 begin
-  if PanelID = -1 then Exit;
+  pan := g_Map_PanelByGUID(PanelGUID);
+  {
+  if (pan = nil) then
+  begin
+    e_LogWritefln('tr_CloseTrap: pguid=%s; NO PANEL!', [PanelGUID], MSG_WARNING);
+  end
+  else
+  begin
+    e_LogWritefln('tr_CloseTrap: pguid=%s; isGWall=%s; arrIdx=%s', [PanelGUID, pan.isGWall, pan.arrIdx]);
+  end;
+  }
+  if (pan = nil) or not pan.isGWall then exit; //!FIXME!TRIGANY!
+  PanelID := pan.arrIdx;
 
   if not d2d then
   begin
@@ -231,8 +258,7 @@ begin
       if (not NoSound) and (not Enabled) then
       begin
         g_Sound_PlayExAt('SOUND_GAME_SWITCH1', X, Y);
-        if g_Game_IsServer and g_Game_IsNet then
-          MH_SEND_Sound(X, Y, 'SOUND_GAME_SWITCH1');
+        if g_Game_IsServer and g_Game_IsNet then MH_SEND_Sound(X, Y, 'SOUND_GAME_SWITCH1');
       end;
     end;
 
@@ -244,20 +270,25 @@ begin
     with gWalls[PanelID] do
     begin
       if gPlayers <> nil then
+      begin
         for a := 0 to High(gPlayers) do
-          if (gPlayers[a] <> nil) and gPlayers[a].Live and
-              gPlayers[a].Collide(X, Y, Width, Height) then
+        begin
+          if (gPlayers[a] <> nil) and gPlayers[a].alive and gPlayers[a].Collide(X, Y, Width, Height) then
+          begin
             gPlayers[a].Damage(TRAP_DAMAGE, 0, 0, 0, HIT_TRAP);
+          end;
+        end;
+      end;
 
       //g_Mons_ForEach(monsDamage);
       g_Mons_ForEachAliveAt(wx, wy, ww, wh, monsDamage);
 
-      if not Enabled then g_Map_EnableWall(PanelID);
+      if not Enabled then g_Map_EnableWallGUID(PanelGUID);
     end;
   end
   else
   begin
-    if gDoorMap = nil then Exit;
+    if (gDoorMap = nil) then exit;
 
     c := -1;
     for a := 0 to High(gDoorMap) do
@@ -267,13 +298,12 @@ begin
         if gDoorMap[a, b] = DWORD(PanelID) then
         begin
           c := a;
-          Break;
+          break;
         end;
       end;
-
-      if c <> -1 then Break;
+      if (c <> -1) then break;
     end;
-    if c = -1 then Exit;
+    if (c = -1) then exit;
 
     if not NoSound then
     begin
@@ -301,143 +331,166 @@ begin
       with gWalls[gDoorMap[c, b]] do
       begin
         if gPlayers <> nil then
+        begin
           for a := 0 to High(gPlayers) do
-            if (gPlayers[a] <> nil) and gPlayers[a].Live and
-            gPlayers[a].Collide(X, Y, Width, Height) then
+          begin
+            if (gPlayers[a] <> nil) and gPlayers[a].alive and gPlayers[a].Collide(X, Y, Width, Height) then
+            begin
               gPlayers[a].Damage(TRAP_DAMAGE, 0, 0, 0, HIT_TRAP);
+            end;
+          end;
+        end;
 
         //g_Mons_ForEach(monsDamage);
         g_Mons_ForEachAliveAt(wx, wy, ww, wh, monsDamage);
         (*
         if gMonsters <> nil then
           for a := 0 to High(gMonsters) do
-            if (gMonsters[a] <> nil) and gMonsters[a].Live and
+            if (gMonsters[a] <> nil) and gMonsters[a].alive and
             g_Obj_Collide(X, Y, Width, Height, @gMonsters[a].Obj) then
               gMonsters[a].Damage(TRAP_DAMAGE, 0, 0, 0, HIT_TRAP);
         *)
 
-        if not Enabled then g_Map_EnableWall(gDoorMap[c, b]);
+        if not Enabled then g_Map_EnableWall_XXX(gDoorMap[c, b]);
       end;
     end;
   end;
 end;
 
-function tr_OpenDoor(PanelID: Integer; NoSound: Boolean; d2d: Boolean): Boolean;
+
+function tr_OpenDoor (PanelGUID: Integer; NoSound: Boolean; d2d: Boolean): Boolean;
 var
   a, b, c: Integer;
+  pan: TPanel;
+  PanelID: Integer;
 begin
-  Result := False;
-
-  if PanelID = -1 then Exit;
+  result := false;
+  pan := g_Map_PanelByGUID(PanelGUID);
+  if (pan = nil) or not pan.isGWall then exit; //!FIXME!TRIGANY!
+  PanelID := pan.arrIdx;
 
   if not d2d then
   begin
     with gWalls[PanelID] do
+    begin
       if Enabled then
       begin
         if not NoSound then
         begin
           g_Sound_PlayExAt('SOUND_GAME_DOOROPEN', X, Y);
-          if g_Game_IsServer and g_Game_IsNet then
-            MH_SEND_Sound(X, Y, 'SOUND_GAME_DOOROPEN');
+          if g_Game_IsServer and g_Game_IsNet then MH_SEND_Sound(X, Y, 'SOUND_GAME_DOOROPEN');
         end;
-        g_Map_DisableWall(PanelID);
-        Result := True;
+        g_Map_DisableWallGUID(PanelGUID);
+        result := true;
       end;
+    end
   end
   else
   begin
-    if gDoorMap = nil then Exit;
+    if (gDoorMap = nil) then exit;
 
     c := -1;
     for a := 0 to High(gDoorMap) do
     begin
       for b := 0 to High(gDoorMap[a]) do
+      begin
         if gDoorMap[a, b] = DWORD(PanelID) then
         begin
           c := a;
-          Break;
+          break;
         end;
-
-      if c <> -1 then Break;
+      end;
+      if (c <> -1) then break;
     end;
-    if c = -1 then Exit;
+    if (c = -1) then exit;
 
     if not NoSound then
+    begin
       for b := 0 to High(gDoorMap[c]) do
+      begin
         if gWalls[gDoorMap[c, b]].Enabled then
         begin
           with gWalls[PanelID] do
           begin
             g_Sound_PlayExAt('SOUND_GAME_DOOROPEN', X, Y);
-            if g_Game_IsServer and g_Game_IsNet then
-              MH_SEND_Sound(X, Y, 'SOUND_GAME_DOOROPEN');
+            if g_Game_IsServer and g_Game_IsNet then MH_SEND_Sound(X, Y, 'SOUND_GAME_DOOROPEN');
           end;
-          Break;
+          break;
         end;
+      end;
+    end;
 
     for b := 0 to High(gDoorMap[c]) do
+    begin
       if gWalls[gDoorMap[c, b]].Enabled then
       begin
-        g_Map_DisableWall(gDoorMap[c, b]);
-        Result := True;
+        g_Map_DisableWall_XXX(gDoorMap[c, b]);
+        result := true;
       end;
+    end;
   end;
 end;
 
-function tr_SetLift(PanelID: Integer; d: Integer; NoSound: Boolean; d2d: Boolean): Boolean;
+
+function tr_SetLift (PanelGUID: Integer; d: Integer; NoSound: Boolean; d2d: Boolean): Boolean;
 var
-  a, b, c, t: Integer;
+  a, b, c: Integer;
+  t: Integer = 0;
+  pan: TPanel;
+  PanelID: Integer;
 begin
-  t := 0;
-  Result := False;
-
-  if PanelID = -1 then Exit;
+  result := false;
+  pan := g_Map_PanelByGUID(PanelGUID);
+  if (pan = nil) or not pan.isGLift then exit; //!FIXME!TRIGANY!
+  PanelID := pan.arrIdx;
 
-  if (gLifts[PanelID].PanelType = PANEL_LIFTUP) or
-     (gLifts[PanelID].PanelType = PANEL_LIFTDOWN) then
+  if (gLifts[PanelID].PanelType = PANEL_LIFTUP) or (gLifts[PanelID].PanelType = PANEL_LIFTDOWN) then
+  begin
     case d of
       0: t := 0;
       1: t := 1;
       else t := IfThen(gLifts[PanelID].LiftType = 1, 0, 1);
     end
-  else if (gLifts[PanelID].PanelType = PANEL_LIFTLEFT) or
-          (gLifts[PanelID].PanelType = PANEL_LIFTRIGHT) then
+  end
+  else if (gLifts[PanelID].PanelType = PANEL_LIFTLEFT) or (gLifts[PanelID].PanelType = PANEL_LIFTRIGHT) then
+  begin
     case d of
       0: t := 2;
       1: t := 3;
       else t := IfThen(gLifts[PanelID].LiftType = 2, 3, 2);
     end;
+  end;
 
   if not d2d then
   begin
     with gLifts[PanelID] do
-      if LiftType <> t then
+    begin
+      if (LiftType <> t) then
       begin
-        g_Map_SetLift(PanelID, t);
-
-        {if not NoSound then
-          g_Sound_PlayExAt('SOUND_GAME_SWITCH0', X, Y);}
-        Result := True;
+        g_Map_SetLiftGUID(PanelGUID, t); //???
+        //if not NoSound then g_Sound_PlayExAt('SOUND_GAME_SWITCH0', X, Y);
+        result := true;
       end;
+    end;
   end
   else // Êàê â D2d
   begin
-    if gLiftMap = nil then Exit;
+    if (gLiftMap = nil) then exit;
 
     c := -1;
     for a := 0 to High(gLiftMap) do
     begin
       for b := 0 to High(gLiftMap[a]) do
-        if gLiftMap[a, b] = DWORD(PanelID) then
+      begin
+        if (gLiftMap[a, b] = DWORD(PanelID)) then
         begin
           c := a;
-          Break;
+          break;
         end;
-
-      if c <> -1 then Break;
+      end;
+      if (c <> -1) then break;
     end;
-    if c = -1 then Exit;
+    if (c = -1) then exit;
 
     {if not NoSound then
       for b := 0 to High(gLiftMap[c]) do
@@ -449,27 +502,32 @@ begin
         end;}
 
     for b := 0 to High(gLiftMap[c]) do
+    begin
       with gLifts[gLiftMap[c, b]] do
-        if LiftType <> t then
+      begin
+        if (LiftType <> t) then
         begin
-          g_Map_SetLift(gLiftMap[c, b], t);
-
-          Result := True;
+          g_Map_SetLift_XXX(gLiftMap[c, b], t);
+          result := true;
         end;
+      end;
+    end;
   end;
 end;
 
-function tr_SpawnShot(ShotType: Integer; wx, wy, dx, dy: Integer; ShotSound: Boolean; ShotTarget: Word): Integer;
+
+function tr_SpawnShot (ShotType: Integer; wx, wy, dx, dy: Integer; ShotSound: Boolean; ShotTarget: Word): Integer;
 var
   snd: string;
   Projectile: Boolean;
   TextureID: DWORD;
   Anim: TAnimation;
 begin
-  Result := -1;
+  result := -1;
   TextureID := DWORD(-1);
   snd := 'SOUND_WEAPON_FIREROCKET';
-  Projectile := True;
+  Projectile := true;
+
   case ShotType of
     TRIGGER_SHOT_PISTOL:
       begin
@@ -479,8 +537,7 @@ begin
         if ShotSound then
         begin
           g_Player_CreateShell(wx, wy, 0, -2, SHELL_BULLET);
-          if g_Game_IsNet then
-            MH_SEND_Effect(wx, wy, 0, NET_GFX_SHELL1);
+          if g_Game_IsNet then MH_SEND_Effect(wx, wy, 0, NET_GFX_SHELL1);
         end;
       end;
 
@@ -493,8 +550,7 @@ begin
         if ShotSound then
         begin
           g_Player_CreateShell(wx, wy, 0, -2, SHELL_BULLET);
-          if g_Game_IsNet then
-            MH_SEND_Effect(wx, wy, 0, NET_GFX_SHELL1);
+          if g_Game_IsNet then MH_SEND_Effect(wx, wy, 0, NET_GFX_SHELL1);
         end;
       end;
 
@@ -506,8 +562,7 @@ begin
         if ShotSound then
         begin
           g_Player_CreateShell(wx, wy, 0, -2, SHELL_SHELL);
-          if g_Game_IsNet then
-            MH_SEND_Effect(wx, wy, 0, NET_GFX_SHELL2);
+          if g_Game_IsNet then MH_SEND_Effect(wx, wy, 0, NET_GFX_SHELL2);
         end;
       end;
 
@@ -520,8 +575,7 @@ begin
         begin
           g_Player_CreateShell(wx, wy, 0, -2, SHELL_SHELL);
           g_Player_CreateShell(wx, wy, 0, -2, SHELL_SHELL);
-          if g_Game_IsNet then
-            MH_SEND_Effect(wx, wy, 0, NET_GFX_SHELL3);
+          if g_Game_IsNet then MH_SEND_Effect(wx, wy, 0, NET_GFX_SHELL3);
         end;
       end;
 
@@ -611,125 +665,118 @@ begin
   end;
 
   if g_Game_IsNet and g_Game_IsServer then
+  begin
     case ShotType of
-      TRIGGER_SHOT_EXPL:
-        MH_SEND_Effect(wx, wy, Byte(ShotSound), NET_GFX_EXPLODE);
-      TRIGGER_SHOT_BFGEXPL:
-        MH_SEND_Effect(wx, wy, Byte(ShotSound), NET_GFX_BFGEXPL);
+      TRIGGER_SHOT_EXPL: MH_SEND_Effect(wx, wy, Byte(ShotSound), NET_GFX_EXPLODE);
+      TRIGGER_SHOT_BFGEXPL: MH_SEND_Effect(wx, wy, Byte(ShotSound), NET_GFX_BFGEXPL);
       else
       begin
-        if Projectile then
-          MH_SEND_CreateShot(LastShotID);
-        if ShotSound then
-          MH_SEND_Sound(wx, wy, snd);
+        if Projectile then MH_SEND_CreateShot(LastShotID);
+        if ShotSound then MH_SEND_Sound(wx, wy, snd);
       end;
     end;
+  end;
 
-  if ShotSound then
-    g_Sound_PlayExAt(snd, wx, wy);
+  if ShotSound then g_Sound_PlayExAt(snd, wx, wy);
 
-  if Projectile then
-    Result := LastShotID;
+  if Projectile then Result := LastShotID;
 end;
 
-procedure MakeShot(var Trigger: TTrigger; wx, wy, dx, dy: Integer; TargetUID: Word);
+
+procedure MakeShot (var Trigger: TTrigger; wx, wy, dx, dy: Integer; TargetUID: Word);
 begin
   with Trigger do
-    if (trigData.trigShotAmmo = 0) or
-       ((trigData.trigShotAmmo > 0) and (ShotAmmoCount > 0)) then
+  begin
+    if (trigData.trigShotAmmo = 0) or ((trigData.trigShotAmmo > 0) and (ShotAmmoCount > 0)) then
     begin
-      if (trigShotPanelID <> -1) and (ShotPanelTime = 0) then
+      if (trigShotPanelGUID <> -1) and (ShotPanelTime = 0) then
       begin
-        g_Map_SwitchTexture(ShotPanelType, trigShotPanelID);
+        g_Map_SwitchTextureGUID(ShotPanelType, trigShotPanelGUID);
         ShotPanelTime := 4; // òèêîâ íà âñïûøêó âûñòðåëà
       end;
 
-      if trigData.trigShotIntSight > 0 then
-        ShotSightTimeout := 180; // ~= 5 ñåêóíä
+      if (trigData.trigShotIntSight > 0) then ShotSightTimeout := 180; // ~= 5 ñåêóíä
 
-      if ShotAmmoCount > 0 then Dec(ShotAmmoCount);
+      if (ShotAmmoCount > 0) then Dec(ShotAmmoCount);
 
-      dx := dx + Random(trigData.trigShotAccuracy) - Random(trigData.trigShotAccuracy);
-      dy := dy + Random(trigData.trigShotAccuracy) - Random(trigData.trigShotAccuracy);
+      dx += Random(trigData.trigShotAccuracy)-Random(trigData.trigShotAccuracy);
+      dy += Random(trigData.trigShotAccuracy)-Random(trigData.trigShotAccuracy);
 
       tr_SpawnShot(trigData.trigShotType, wx, wy, dx, dy, trigData.trigShotSound, TargetUID);
     end
     else
+    begin
       if (trigData.trigShotIntReload > 0) and (ShotReloadTime = 0) then
+      begin
         ShotReloadTime := trigData.trigShotIntReload; // òèêîâ íà ïåðåçàðÿäêó ïóøêè
+      end;
+    end;
+  end;
 end;
 
-procedure tr_MakeEffect(X, Y, VX, VY: Integer; T, ST, CR, CG, CB: Byte; Silent, Send: Boolean);
+
+procedure tr_MakeEffect (X, Y, VX, VY: Integer; T, ST, CR, CG, CB: Byte; Silent, Send: Boolean);
 var
   FramesID: DWORD;
   Anim: TAnimation;
 begin
   if T = TRIGGER_EFFECT_PARTICLE then
+  begin
     case ST of
       TRIGGER_EFFECT_SLIQUID:
       begin
-        if (CR = 255) and (CG = 0) and (CB = 0) then
-          g_GFX_SimpleWater(X, Y, 1, VX, VY, 1, 0, 0, 0)
-        else if (CR = 0) and (CG = 255) and (CB = 0) then
-          g_GFX_SimpleWater(X, Y, 1, VX, VY, 2, 0, 0, 0)
-        else if (CR = 0) and (CG = 0) and (CB = 255) then
-          g_GFX_SimpleWater(X, Y, 1, VX, VY, 3, 0, 0, 0)
-        else
-          g_GFX_SimpleWater(X, Y, 1, VX, VY, 0, 0, 0, 0);
+             if (CR = 255) and (CG = 0) and (CB = 0) then g_GFX_SimpleWater(X, Y, 1, VX, VY, 1, 0, 0, 0)
+        else if (CR = 0) and (CG = 255) and (CB = 0) then g_GFX_SimpleWater(X, Y, 1, VX, VY, 2, 0, 0, 0)
+        else if (CR = 0) and (CG = 0) and (CB = 255) then g_GFX_SimpleWater(X, Y, 1, VX, VY, 3, 0, 0, 0)
+        else g_GFX_SimpleWater(X, Y, 1, VX, VY, 0, 0, 0, 0);
       end;
-      TRIGGER_EFFECT_LLIQUID:
-        g_GFX_SimpleWater(X, Y, 1, VX, VY, 4, CR, CG, CB);
-      TRIGGER_EFFECT_DLIQUID:
-        g_GFX_SimpleWater(X, Y, 1, VX, VY, 5, CR, CG, CB);
-      TRIGGER_EFFECT_BLOOD:
-        g_GFX_Blood(X, Y, 1, VX, VY, 0, 0, CR, CG, CB);
-      TRIGGER_EFFECT_SPARK:
-        g_GFX_Spark(X, Y, 1, GetAngle2(VX, VY), 0, 0);
-      TRIGGER_EFFECT_BUBBLE:
-        g_GFX_Bubbles(X, Y, 1, 0, 0);
+      TRIGGER_EFFECT_LLIQUID: g_GFX_SimpleWater(X, Y, 1, VX, VY, 4, CR, CG, CB);
+      TRIGGER_EFFECT_DLIQUID: g_GFX_SimpleWater(X, Y, 1, VX, VY, 5, CR, CG, CB);
+      TRIGGER_EFFECT_BLOOD: g_GFX_Blood(X, Y, 1, VX, VY, 0, 0, CR, CG, CB);
+      TRIGGER_EFFECT_SPARK: g_GFX_Spark(X, Y, 1, GetAngle2(VX, VY), 0, 0);
+      TRIGGER_EFFECT_BUBBLE: g_GFX_Bubbles(X, Y, 1, 0, 0);
     end;
+  end;
+
   if T = TRIGGER_EFFECT_ANIMATION then
+  begin
     case ST of
       EFFECT_TELEPORT: begin
         if g_Frames_Get(FramesID, 'FRAMES_TELEPORT') then
         begin
           Anim := TAnimation.Create(FramesID, False, 3);
-          if not Silent then
-            g_Sound_PlayExAt('SOUND_GAME_TELEPORT', X, Y);
+          if not Silent then g_Sound_PlayExAt('SOUND_GAME_TELEPORT', X, Y);
           g_GFX_OnceAnim(X-32, Y-32, Anim);
           Anim.Free();
         end;
-        if Send and g_Game_IsServer and g_Game_IsNet then
-          MH_SEND_Effect(X, Y, Byte(not Silent), NET_GFX_TELE);
+        if Send and g_Game_IsServer and g_Game_IsNet then MH_SEND_Effect(X, Y, Byte(not Silent), NET_GFX_TELE);
       end;
       EFFECT_RESPAWN: begin
         if g_Frames_Get(FramesID, 'FRAMES_ITEM_RESPAWN') then
         begin
           Anim := TAnimation.Create(FramesID, False, 4);
-          if not Silent then
-            g_Sound_PlayExAt('SOUND_ITEM_RESPAWNITEM', X, Y);
+          if not Silent then g_Sound_PlayExAt('SOUND_ITEM_RESPAWNITEM', X, Y);
           g_GFX_OnceAnim(X-16, Y-16, Anim);
           Anim.Free();
         end;
-        if Send and g_Game_IsServer and g_Game_IsNet then
-          MH_SEND_Effect(X-16, Y-16, Byte(not Silent), NET_GFX_RESPAWN);
+        if Send and g_Game_IsServer and g_Game_IsNet then MH_SEND_Effect(X-16, Y-16, Byte(not Silent), NET_GFX_RESPAWN);
       end;
       EFFECT_FIRE: begin
         if g_Frames_Get(FramesID, 'FRAMES_FIRE') then
         begin
           Anim := TAnimation.Create(FramesID, False, 4);
-          if not Silent then
-            g_Sound_PlayExAt('SOUND_FIRE', X, Y);
+          if not Silent then g_Sound_PlayExAt('SOUND_FIRE', X, Y);
           g_GFX_OnceAnim(X-32, Y-128, Anim);
           Anim.Free();
         end;
-        if Send and g_Game_IsServer and g_Game_IsNet then
-          MH_SEND_Effect(X-32, Y-128, Byte(not Silent), NET_GFX_FIRE);
+        if Send and g_Game_IsServer and g_Game_IsNet then MH_SEND_Effect(X-32, Y-128, Byte(not Silent), NET_GFX_FIRE);
       end;
     end;
+  end;
 end;
 
-function tr_Teleport(ActivateUID: Integer; TX, TY: Integer; TDir: Integer; Silent: Boolean; D2D: Boolean): Boolean;
+
+function tr_Teleport (ActivateUID: Integer; TX, TY: Integer; TDir: Integer; Silent: Boolean; D2D: Boolean): Boolean;
 var
   p: TPlayer;
   m: TMonster;
@@ -740,56 +787,45 @@ begin
     UID_PLAYER:
       begin
         p := g_Player_Get(ActivateUID);
-        if p = nil then
-          Exit;
-
+        if p = nil then Exit;
         if D2D then
-          begin
-            if p.TeleportTo(TX-(p.Obj.Rect.Width div 2),
-                            TY-p.Obj.Rect.Height,
-                            Silent,
-                            TDir) then
-              Result := True;
-          end
+        begin
+          if p.TeleportTo(TX-(p.Obj.Rect.Width div 2), TY-p.Obj.Rect.Height, Silent, TDir) then result := true;
+        end
         else
-          if p.TeleportTo(TX, TY, Silent, TDir) then
-            Result := True;
+        begin
+          if p.TeleportTo(TX, TY, Silent, TDir) then result := true;
+        end;
       end;
-
     UID_MONSTER:
       begin
         m := g_Monsters_ByUID(ActivateUID);
-        if m = nil then
-          Exit;
-
+        if m = nil then Exit;
         if D2D then
-          begin
-            if m.TeleportTo(TX-(m.Obj.Rect.Width div 2),
-                            TY-m.Obj.Rect.Height,
-                            Silent,
-                            TDir) then
-              Result := True;
-          end
+        begin
+          if m.TeleportTo(TX-(m.Obj.Rect.Width div 2), TY-m.Obj.Rect.Height, Silent, TDir) then result := true;
+        end
         else
-          if m.TeleportTo(TX, TY, Silent, TDir) then
-            Result := True;
+        begin
+          if m.TeleportTo(TX, TY, Silent, TDir) then result := true;
+        end;
       end;
   end;
 end;
 
-function tr_Push(ActivateUID: Integer; VX, VY: Integer; ResetVel: Boolean): Boolean;
+
+function tr_Push (ActivateUID: Integer; VX, VY: Integer; ResetVel: Boolean): Boolean;
 var
   p: TPlayer;
   m: TMonster;
 begin
-  Result := True;
-  if (ActivateUID < 0) or (ActivateUID > $FFFF) then Exit;
+  result := true;
+  if (ActivateUID < 0) or (ActivateUID > $FFFF) then exit;
   case g_GetUIDType(ActivateUID) of
     UID_PLAYER:
       begin
         p := g_Player_Get(ActivateUID);
-        if p = nil then
-          Exit;
+        if p = nil then Exit;
 
         if ResetVel then
         begin
@@ -805,8 +841,7 @@ begin
     UID_MONSTER:
       begin
         m := g_Monsters_ByUID(ActivateUID);
-        if m = nil then
-          Exit;
+        if m = nil then Exit;
 
         if ResetVel then
         begin
@@ -821,7 +856,8 @@ begin
   end;
 end;
 
-function tr_Message(MKind: Integer; MText: string; MSendTo: Integer; MTime: Integer; ActivateUID: Integer): Boolean;
+
+function tr_Message (MKind: Integer; MText: string; MSendTo: Integer; MTime: Integer; ActivateUID: Integer): Boolean;
 var
   msg: string;
   p: TPlayer;
@@ -837,19 +873,17 @@ begin
         begin
           if g_Game_IsWatchedPlayer(ActivateUID) then
           begin
-            if MKind = 0 then
-              g_Console_Add(msg, True)
-            else if MKind = 1 then
-              g_Game_Message(msg, MTime);
+                 if MKind = 0 then g_Console_Add(msg, True)
+            else if MKind = 1 then g_Game_Message(msg, MTime);
           end
           else
           begin
             p := g_Player_Get(ActivateUID);
             if g_Game_IsNet and (p.FClientID >= 0) then
-              if MKind = 0 then
-                MH_SEND_Chat(msg, NET_CHAT_SYSTEM, p.FClientID)
-              else if MKind = 1 then
-                MH_SEND_GameEvent(NET_EV_BIGTEXT, MTime, msg, p.FClientID);
+            begin
+                   if MKind = 0 then MH_SEND_Chat(msg, NET_CHAT_SYSTEM, p.FClientID)
+              else if MKind = 1 then MH_SEND_GameEvent(NET_EV_BIGTEXT, MTime, msg, p.FClientID);
+            end;
           end;
         end;
       end;
@@ -860,19 +894,21 @@ begin
         begin
           p := g_Player_Get(ActivateUID);
           if g_Game_IsWatchedTeam(p.Team) then
-            if MKind = 0 then
-              g_Console_Add(msg, True)
-            else if MKind = 1 then
-              g_Game_Message(msg, MTime);
+          begin
+                 if MKind = 0 then g_Console_Add(msg, True)
+            else if MKind = 1 then g_Game_Message(msg, MTime);
+          end;
 
           if g_Game_IsNet then
           begin
             for i := Low(gPlayers) to High(gPlayers) do
+            begin
               if (gPlayers[i].Team = p.Team) and (gPlayers[i].FClientID >= 0) then
-                if MKind = 0 then
-                  MH_SEND_Chat(msg, NET_CHAT_SYSTEM, gPlayers[i].FClientID)
-                else if MKind = 1 then
-                  MH_SEND_GameEvent(NET_EV_BIGTEXT, MTime, msg, gPlayers[i].FClientID);
+              begin
+                     if MKind = 0 then MH_SEND_Chat(msg, NET_CHAT_SYSTEM, gPlayers[i].FClientID)
+                else if MKind = 1 then MH_SEND_GameEvent(NET_EV_BIGTEXT, MTime, msg, gPlayers[i].FClientID);
+              end;
+            end;
           end;
         end;
       end;
@@ -883,19 +919,21 @@ begin
         begin
           p := g_Player_Get(ActivateUID);
           if g_Game_IsWatchedTeam(p.Team) then
-            if MKind = 0 then
-              g_Console_Add(msg, True)
-            else if MKind = 1 then
-              g_Game_Message(msg, MTime);
+          begin
+                 if MKind = 0 then g_Console_Add(msg, True)
+            else if MKind = 1 then g_Game_Message(msg, MTime);
+          end;
 
           if g_Game_IsNet then
           begin
             for i := Low(gPlayers) to High(gPlayers) do
+            begin
               if (gPlayers[i].Team <> p.Team) and (gPlayers[i].FClientID >= 0) then
-                if MKind = 0 then
-                  MH_SEND_Chat(msg, NET_CHAT_SYSTEM, gPlayers[i].FClientID)
-                else if MKind = 1 then
-                  MH_SEND_GameEvent(NET_EV_BIGTEXT, MTime, msg, gPlayers[i].FClientID);
+              begin
+                     if MKind = 0 then MH_SEND_Chat(msg, NET_CHAT_SYSTEM, gPlayers[i].FClientID)
+                else if MKind = 1 then MH_SEND_GameEvent(NET_EV_BIGTEXT, MTime, msg, gPlayers[i].FClientID);
+              end;
+            end;
           end;
         end;
       end;
@@ -903,81 +941,84 @@ begin
     3: // red team
       begin
         if g_Game_IsWatchedTeam(TEAM_RED) then
-          if MKind = 0 then
-            g_Console_Add(msg, True)
-          else if MKind = 1 then
-            g_Game_Message(msg, MTime);
+        begin
+               if MKind = 0 then g_Console_Add(msg, True)
+          else if MKind = 1 then g_Game_Message(msg, MTime);
+        end;
 
         if g_Game_IsNet then
         begin
           for i := Low(gPlayers) to High(gPlayers) do
+          begin
             if (gPlayers[i].Team = TEAM_RED) and (gPlayers[i].FClientID >= 0) then
-              if MKind = 0 then
-                MH_SEND_Chat(msg, NET_CHAT_SYSTEM, gPlayers[i].FClientID)
-              else if MKind = 1 then
-                MH_SEND_GameEvent(NET_EV_BIGTEXT, MTime, msg, gPlayers[i].FClientID);
+            begin
+                   if MKind = 0 then MH_SEND_Chat(msg, NET_CHAT_SYSTEM, gPlayers[i].FClientID)
+              else if MKind = 1 then MH_SEND_GameEvent(NET_EV_BIGTEXT, MTime, msg, gPlayers[i].FClientID);
+            end;
+          end;
         end;
       end;
 
     4: // blue team
       begin
         if g_Game_IsWatchedTeam(TEAM_BLUE) then
-          if MKind = 0 then
-            g_Console_Add(msg, True)
-          else if MKind = 1 then
-            g_Game_Message(msg, MTime);
+        begin
+               if MKind = 0 then g_Console_Add(msg, True)
+          else if MKind = 1 then g_Game_Message(msg, MTime);
+        end;
 
         if g_Game_IsNet then
         begin
           for i := Low(gPlayers) to High(gPlayers) do
+          begin
             if (gPlayers[i].Team = TEAM_BLUE) and (gPlayers[i].FClientID >= 0) then
-              if MKind = 0 then
-                MH_SEND_Chat(msg, NET_CHAT_SYSTEM, gPlayers[i].FClientID)
-              else if MKind = 1 then
-                MH_SEND_GameEvent(NET_EV_BIGTEXT, MTime, msg, gPlayers[i].FClientID);
+            begin
+                   if MKind = 0 then MH_SEND_Chat(msg, NET_CHAT_SYSTEM, gPlayers[i].FClientID)
+              else if MKind = 1 then MH_SEND_GameEvent(NET_EV_BIGTEXT, MTime, msg, gPlayers[i].FClientID);
+            end;
+          end;
         end;
       end;
 
     5: // everyone
       begin
-        if MKind = 0 then
-          g_Console_Add(msg, True)
-        else if MKind = 1 then
-          g_Game_Message(msg, MTime);
+             if MKind = 0 then g_Console_Add(msg, True)
+        else if MKind = 1 then g_Game_Message(msg, MTime);
 
         if g_Game_IsNet then
         begin
-          if MKind = 0 then
-            MH_SEND_Chat(msg, NET_CHAT_SYSTEM)
-          else if MKind = 1 then
-            MH_SEND_GameEvent(NET_EV_BIGTEXT, MTime, msg);
+               if MKind = 0 then MH_SEND_Chat(msg, NET_CHAT_SYSTEM)
+          else if MKind = 1 then MH_SEND_GameEvent(NET_EV_BIGTEXT, MTime, msg);
         end;
       end;
   end;
 end;
 
-function tr_ShotAimCheck(var Trigger: TTrigger; Obj: PObj): Boolean;
+
+function tr_ShotAimCheck (var Trigger: TTrigger; Obj: PObj): Boolean;
 begin
   result := false;
   with Trigger do
   begin
-    if TriggerType <> TRIGGER_SHOT then
-      Exit;
-    Result := (trigData.trigShotAim and TRIGGER_SHOT_AIM_ALLMAP > 0)
+    if TriggerType <> TRIGGER_SHOT then Exit;
+    result := (trigData.trigShotAim and TRIGGER_SHOT_AIM_ALLMAP > 0)
               or g_Obj_Collide(X, Y, Width, Height, Obj);
-    if Result and (trigData.trigShotAim and TRIGGER_SHOT_AIM_TRACE > 0) then
-      Result := g_TraceVector(trigData.trigShotPos.X,
-                              trigData.trigShotPos.Y,
+    if result and (trigData.trigShotAim and TRIGGER_SHOT_AIM_TRACE > 0) then
+    begin
+      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;
   end;
 end;
 
-function ActivateTrigger(var Trigger: TTrigger; actType: Byte): Boolean;
+
+function ActivateTrigger (var Trigger: TTrigger; actType: Byte): Boolean;
 var
   animonce: Boolean;
   p: TPlayer;
   m: TMonster;
+  pan: TPanel;
   idx, k, wx, wy, xd, yd: Integer;
   iid: LongWord;
   coolDown: Boolean;
@@ -992,7 +1033,7 @@ var
   function monsShotTarget (mon: TMonster): Boolean;
   begin
     result := false; // don't stop
-    if mon.Live and tr_ShotAimCheck(Trigger, @(mon.Obj)) then
+    if mon.alive and tr_ShotAimCheck(Trigger, @(mon.Obj)) then
     begin
       xd := mon.GameX + mon.Obj.Rect.Width div 2;
       yd := mon.GameY + mon.Obj.Rect.Height div 2;
@@ -1004,7 +1045,7 @@ var
   function monsShotTargetMonPlr (mon: TMonster): Boolean;
   begin
     result := false; // don't stop
-    if mon.Live and tr_ShotAimCheck(Trigger, @(mon.Obj)) then
+    if mon.alive and tr_ShotAimCheck(Trigger, @(mon.Obj)) then
     begin
       xd := mon.GameX + mon.Obj.Rect.Width div 2;
       yd := mon.GameY + mon.Obj.Rect.Height div 2;
@@ -1016,7 +1057,7 @@ var
   function monShotTargetPlrMon (mon: TMonster): Boolean;
   begin
     result := false; // don't stop
-    if mon.Live and tr_ShotAimCheck(Trigger, @(mon.Obj)) then
+    if mon.alive and tr_ShotAimCheck(Trigger, @(mon.Obj)) then
     begin
       xd := mon.GameX + mon.Obj.Rect.Width div 2;
       yd := mon.GameY + mon.Obj.Rect.Height div 2;
@@ -1026,16 +1067,12 @@ var
   end;
 
 begin
-  Result := False;
-  if g_Game_IsClient then
-    Exit;
+  result := false;
+  if g_Game_IsClient then exit;
 
-  if not Trigger.Enabled then
-    Exit;
-  if (Trigger.TimeOut <> 0) and (actType <> ACTIVATE_CUSTOM) then
-    Exit;
-  if gLMSRespawn = LMS_RESPAWN_WARMUP then
-    Exit;
+  if not Trigger.Enabled then exit;
+  if (Trigger.TimeOut <> 0) and (actType <> ACTIVATE_CUSTOM) then exit;
+  if gLMSRespawn = LMS_RESPAWN_WARMUP then exit;
 
   animonce := False;
 
@@ -1067,38 +1104,38 @@ begin
 
       TRIGGER_OPENDOOR:
         begin
-          Result := tr_OpenDoor(trigPanelID, trigData.trigNoSound, trigData.trigd2d_doors);
+          Result := tr_OpenDoor(trigPanelGUID, trigData.trigNoSound, trigData.trigd2d_doors);
           TimeOut := 0;
         end;
 
       TRIGGER_CLOSEDOOR:
         begin
-          Result := tr_CloseDoor(trigPanelID, trigData.trigNoSound, trigData.trigd2d_doors);
+          Result := tr_CloseDoor(trigPanelGUID, trigData.trigNoSound, trigData.trigd2d_doors);
           TimeOut := 0;
         end;
 
       TRIGGER_DOOR, TRIGGER_DOOR5:
         begin
-          if trigPanelID <> -1 then
+          pan := g_Map_PanelByGUID(trigPanelGUID);
+          if (pan <> nil) and pan.isGWall then
           begin
-            if gWalls[trigPanelID].Enabled then
-              begin
-                Result := tr_OpenDoor(trigPanelID, trigData.trigNoSound, trigData.trigd2d_doors);
-
-                if TriggerType = TRIGGER_DOOR5 then
-                  DoorTime := 180;
-              end
+            if gWalls[{trigPanelID}pan.arrIdx].Enabled then
+            begin
+              result := tr_OpenDoor(trigPanelGUID, trigData.trigNoSound, trigData.trigd2d_doors);
+              if (TriggerType = TRIGGER_DOOR5) then DoorTime := 180;
+            end
             else
-              Result := tr_CloseDoor(trigPanelID, trigData.trigNoSound, trigData.trigd2d_doors);
+            begin
+              result := tr_CloseDoor(trigPanelGUID, trigData.trigNoSound, trigData.trigd2d_doors);
+            end;
 
-            if Result then
-              TimeOut := 18;
+            if result then TimeOut := 18;
           end;
         end;
 
       TRIGGER_CLOSETRAP, TRIGGER_TRAP:
         begin
-          tr_CloseTrap(trigPanelID, trigData.trigNoSound, trigData.trigd2d_doors);
+          tr_CloseTrap(trigPanelGUID, trigData.trigNoSound, trigData.trigd2d_doors);
 
           if TriggerType = TRIGGER_TRAP then
             begin
@@ -1116,15 +1153,9 @@ begin
 
       TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF:
         begin
-          PressCount := PressCount + 1;
-
-          if PressTime = -1 then
-            PressTime := trigData.trigWait;
-
-          if coolDown then
-            TimeOut := 18
-          else
-            TimeOut := 0;
+          PressCount += 1;
+          if PressTime = -1 then PressTime := trigData.trigWait;
+          if coolDown then TimeOut := 18 else TimeOut := 0;
           Result := True;
         end;
 
@@ -1143,7 +1174,7 @@ begin
 
       TRIGGER_LIFTUP:
         begin
-          Result := tr_SetLift(trigPanelID, 0, trigData.trigNoSound, trigData.trigd2d_doors);
+          Result := tr_SetLift(trigPanelGUID, 0, trigData.trigNoSound, trigData.trigd2d_doors);
           TimeOut := 0;
 
           if (not trigData.trigNoSound) and Result then begin
@@ -1159,7 +1190,7 @@ begin
 
       TRIGGER_LIFTDOWN:
         begin
-          Result := tr_SetLift(trigPanelID, 1, trigData.trigNoSound, trigData.trigd2d_doors);
+          Result := tr_SetLift(trigPanelGUID, 1, trigData.trigNoSound, trigData.trigd2d_doors);
           TimeOut := 0;
 
           if (not trigData.trigNoSound) and Result then begin
@@ -1175,7 +1206,7 @@ begin
 
       TRIGGER_LIFT:
         begin
-          Result := tr_SetLift(trigPanelID, 3, trigData.trigNoSound, trigData.trigd2d_doors);
+          Result := tr_SetLift(trigPanelGUID, 3, trigData.trigNoSound, trigData.trigd2d_doors);
 
           if Result then
           begin
@@ -1195,7 +1226,7 @@ begin
 
       TRIGGER_TEXTURE:
         begin
-          if ByteBool(trigData.trigActivateOnce) then
+          if trigData.trigActivateOnce then
             begin
               Enabled := False;
               TriggerType := TRIGGER_NONE;
@@ -1819,7 +1850,7 @@ begin
 
       TRIGGER_MESSAGE:
         begin
-          Result := tr_Message(trigData.trigMessageKind, trigData.trigMessageText, 
+          Result := tr_Message(trigData.trigMessageKind, trigData.trigMessageText,
                                trigData.trigMessageSendTo, trigData.trigMessageTime,
                                ActivateUID);
           TimeOut := 18;
@@ -1939,7 +1970,7 @@ begin
             TRIGGER_SHOT_TARGET_PLR: // players
               if gPlayers <> nil then
                 for idx := Low(gPlayers) to High(gPlayers) do
-                  if (gPlayers[idx] <> nil) and gPlayers[idx].Live and
+                  if (gPlayers[idx] <> nil) and gPlayers[idx].alive and
                      tr_ShotAimCheck(Trigger, @(gPlayers[idx].Obj)) then
                   begin
                     xd := gPlayers[idx].GameX + PLAYER_RECT_CX;
@@ -1951,7 +1982,7 @@ begin
             TRIGGER_SHOT_TARGET_RED: // red team
               if gPlayers <> nil then
                 for idx := Low(gPlayers) to High(gPlayers) do
-                  if (gPlayers[idx] <> nil) and gPlayers[idx].Live and
+                  if (gPlayers[idx] <> nil) and gPlayers[idx].alive and
                      (gPlayers[idx].Team = TEAM_RED) and
                      tr_ShotAimCheck(Trigger, @(gPlayers[idx].Obj)) then
                   begin
@@ -1964,7 +1995,7 @@ begin
             TRIGGER_SHOT_TARGET_BLUE: // blue team
               if gPlayers <> nil then
                 for idx := Low(gPlayers) to High(gPlayers) do
-                  if (gPlayers[idx] <> nil) and gPlayers[idx].Live and
+                  if (gPlayers[idx] <> nil) and gPlayers[idx].alive and
                      (gPlayers[idx].Team = TEAM_BLUE) and
                      tr_ShotAimCheck(Trigger, @(gPlayers[idx].Obj)) then
                   begin
@@ -1981,7 +2012,7 @@ begin
 
               if (TargetUID = 0) and (gPlayers <> nil) then
                 for idx := Low(gPlayers) to High(gPlayers) do
-                  if (gPlayers[idx] <> nil) and gPlayers[idx].Live and
+                  if (gPlayers[idx] <> nil) and gPlayers[idx].alive and
                      tr_ShotAimCheck(Trigger, @(gPlayers[idx].Obj)) then
                   begin
                     xd := gPlayers[idx].GameX + PLAYER_RECT_CX;
@@ -1995,7 +2026,7 @@ begin
             begin
               if gPlayers <> nil then
                 for idx := Low(gPlayers) to High(gPlayers) do
-                  if (gPlayers[idx] <> nil) and gPlayers[idx].Live and
+                  if (gPlayers[idx] <> nil) and gPlayers[idx].alive and
                      tr_ShotAimCheck(Trigger, @(gPlayers[idx].Obj)) then
                   begin
                     xd := gPlayers[idx].GameX + PLAYER_RECT_CX;
@@ -2077,14 +2108,41 @@ begin
     end;
   end;
 
-  if Result and (Trigger.TexturePanel <> -1) then
-    g_Map_SwitchTexture(Trigger.TexturePanelType, Trigger.TexturePanel, IfThen(animonce, 2, 1));
+  if Result {and (Trigger.TexturePanel <> -1)} then
+  begin
+    g_Map_SwitchTextureGUID(Trigger.TexturePanelType, Trigger.TexturePanelGUID, IfThen(animonce, 2, 1));
+  end;
 end;
 
-function g_Triggers_Create(Trigger: TTrigger): DWORD;
+
+function g_Triggers_CreateWithMapIndex (Trigger: TTrigger; arridx, mapidx: Integer): DWORD;
+var
+  triggers: TDynField;
+begin
+  triggers := gCurrentMap['trigger'];
+  if (triggers = nil) then raise Exception.Create('LOAD: map has no triggers');
+  if (mapidx < 0) or (mapidx >= triggers.count) then raise Exception.Create('LOAD: invalid map trigger index');
+  Trigger.trigData := triggers.item[mapidx];
+  if (Trigger.trigData = nil) then raise Exception.Create('LOAD: internal error in trigger loader');
+  Trigger.mapId := Trigger.trigData.id;
+  Trigger.mapIndex := mapidx;
+  if (Trigger.trigData.trigRec <> nil) then
+  begin
+    Trigger.trigData := Trigger.trigData.trigRec.clone({Trigger.trigData.headerRec}nil);
+  end
+  else
+  begin
+    Trigger.trigData := nil;
+  end;
+  result := g_Triggers_Create(Trigger, arridx);
+end;
+
+
+function g_Triggers_Create(Trigger: TTrigger; forceInternalIndex: Integer=-1): DWORD;
 var
   find_id: DWORD;
-  fn, mapw: String;
+  fn, mapw: AnsiString;
+  f, olen: Integer;
 begin
 // Íå ñîçäàâàòü âûõîä, åñëè èãðà áåç âûõîäà:
   if (Trigger.TriggerType = TRIGGER_EXIT) and
@@ -2101,9 +2159,37 @@ begin
   if Trigger.TriggerType = TRIGGER_SECRET then
     gSecretsCount := gSecretsCount + 1;
 
-  find_id := FindTrigger();
+  if (forceInternalIndex < 0) then
+  begin
+    find_id := FindTrigger();
+  end
+  else
+  begin
+    olen := Length(gTriggers);
+    if (forceInternalIndex >= olen) then
+    begin
+      SetLength(gTriggers, forceInternalIndex+1);
+      for f := olen to High(gTriggers) do gTriggers[f].TriggerType := TRIGGER_NONE;
+    end;
+    find_id := DWORD(forceInternalIndex);
+  end;
   gTriggers[find_id] := Trigger;
 
+  //e_LogWritefln('created trigger with map index %s, findid=%s (%s)', [Trigger.mapIndex, find_id, Trigger.mapId]);
+
+  {
+  writeln('trigger #', find_id, ': pos=(', Trigger.x, ',', Trigger.y, ')-(', Trigger.width, 'x', Trigger.height, ')',
+    '; TexturePanel=', Trigger.TexturePanel,
+    '; TexturePanelType=', Trigger.TexturePanelType,
+    '; ShotPanelType=', Trigger.ShotPanelType,
+    '; TriggerType=', Trigger.TriggerType,
+    '; ActivateType=', Trigger.ActivateType,
+    '; Keys=', Trigger.Keys,
+    '; trigPanelId=', Trigger.trigPanelId,
+    '; trigShotPanelId=', Trigger.trigShotPanelId
+    );
+  }
+
   with gTriggers[find_id] do
   begin
     ID := find_id;
@@ -2225,6 +2311,7 @@ var
 
 var
   mon: TMonster;
+  pan: TPanel;
 begin
   if (tgMonsList = nil) then tgMonsList := TSimpleMonsterList.Create();
 
@@ -2237,120 +2324,135 @@ begin
     // Åñòü òðèããåð:
       if TriggerType <> TRIGGER_NONE then
       begin
-      // Óìåíüøàåì âðåìÿ äî çàêðûòèÿ äâåðè (îòêðûòèÿ ëîâóøêè):
-        if DoorTime > 0 then
-          DoorTime := DoorTime - 1;
-      // Óìåíüøàåì âðåìÿ îæèäàíèÿ ïîñëå íàæàòèÿ:
-        if PressTime > 0 then
-          PressTime := PressTime - 1;
-      // Ïðîâåðÿåì èãðîêîâ è ìîíñòðîâ, êîòîðûõ ðàíåå çàïîìíèëè:
+        // Óìåíüøàåì âðåìÿ äî çàêðûòèÿ äâåðè (îòêðûòèÿ ëîâóøêè)
+        if DoorTime > 0 then DoorTime := DoorTime - 1;
+        // Óìåíüøàåì âðåìÿ îæèäàíèÿ ïîñëå íàæàòèÿ
+        if PressTime > 0 then PressTime := PressTime - 1;
+        // Ïðîâåðÿåì èãðîêîâ è ìîíñòðîâ, êîòîðûõ ðàíåå çàïîìíèëè:
         if (TriggerType = TRIGGER_DAMAGE) or (TriggerType = TRIGGER_HEALTH) then
+        begin
           for b := 0 to High(Activators) do
           begin
             // Óìåíüøàåì âðåìÿ äî ïîâòîðíîãî âîçäåéñòâèÿ:
             if Activators[b].TimeOut > 0 then
-              Dec(Activators[b].TimeOut)
+            begin
+              Dec(Activators[b].TimeOut);
+            end
             else
-              Continue;
+            begin
+              continue;
+            end;
             // Ñ÷èòàåì, ÷òî îáúåêò ïîêèíóë çîíó äåéñòâèÿ òðèããåðà
-            if (trigData.trigDamageInterval = 0) and (Activators[b].TimeOut < 65530) then
-              Activators[b].TimeOut := 0;
+            if (trigData.trigDamageInterval = 0) and (Activators[b].TimeOut < 65530) then Activators[b].TimeOut := 0;
           end;
+        end;
 
-      // Îáðàáàòûâàåì ñïàâíåðû:
+        // Îáðàáàòûâàåì ñïàâíåðû
         if Enabled and AutoSpawn then
+        begin
           if SpawnCooldown = 0 then
           begin
-            // Åñëè ïðèøëî âðåìÿ, ñïàâíèì ìîíñòðà:
+            // Åñëè ïðèøëî âðåìÿ, ñïàâíèì ìîíñòðà
             if (TriggerType = TRIGGER_SPAWNMONSTER) and (trigData.trigMonDelay > 0)  then
             begin
               ActivateUID := 0;
               ActivateTrigger(gTriggers[a], ACTIVATE_CUSTOM);
             end;
-            // Åñëè ïðèøëî âðåìÿ, ñïàâíèì ïðåäìåò:
+            // Åñëè ïðèøëî âðåìÿ, ñïàâíèì ïðåäìåò
             if (TriggerType = TRIGGER_SPAWNITEM) and (trigData.trigItemDelay > 0) then
             begin
               ActivateUID := 0;
               ActivateTrigger(gTriggers[a], ACTIVATE_CUSTOM);
             end;
-          end else // Óìåíüøàåì âðåìÿ îæèäàíèÿ:
+          end
+          else
+          begin
+            // Óìåíüøàåì âðåìÿ îæèäàíèÿ
             Dec(SpawnCooldown);
+          end;
+        end;
 
-      // Îáðàáàòûâàåì ñîáûòèÿ òðèããåðà "Òóðåëü":
+        // Îáðàáàòûâàåì ñîáûòèÿ òðèããåðà "Òóðåëü"
         if TriggerType = TRIGGER_SHOT then
         begin
           if ShotPanelTime > 0 then
           begin
             Dec(ShotPanelTime);
-            if ShotPanelTime = 0 then
-              g_Map_SwitchTexture(ShotPanelType, trigShotPanelID);
+            if ShotPanelTime = 0 then g_Map_SwitchTextureGUID(ShotPanelType, trigShotPanelGUID);
           end;
           if ShotSightTime > 0 then
           begin
             Dec(ShotSightTime);
-            if ShotSightTime = 0 then
-              ShotSightTarget := ShotSightTargetN;
+            if ShotSightTime = 0 then ShotSightTarget := ShotSightTargetN;
           end;
           if ShotSightTimeout > 0 then
           begin
             Dec(ShotSightTimeout);
-            if ShotSightTimeout = 0 then
-              ShotSightTarget := 0;
+            if ShotSightTimeout = 0 then ShotSightTarget := 0;
           end;
           if ShotReloadTime > 0 then
           begin
             Dec(ShotReloadTime);
-            if ShotReloadTime = 0 then
-              ShotAmmoCount := trigData.trigShotAmmo;
+            if ShotReloadTime = 0 then ShotAmmoCount := trigData.trigShotAmmo;
           end;
         end;
 
-      // Òðèããåð "Çâóê" óæå îòûãðàë, åñëè íóæíî åùå - ïåðåçàïóñêàåì:
+        // Òðèããåð "Çâóê" óæå îòûãðàë, åñëè íóæíî åùå - ïåðåçàïóñêàåì
         if Enabled and (TriggerType = TRIGGER_SOUND) and (Sound <> nil) then
+        begin
           if (SoundPlayCount > 0) and (not Sound.IsPlaying()) then
           begin
-            if trigData.trigPlayCount > 0 then // Åñëè 0 - èãðàåì çâóê áåñêîíå÷íî
-              SoundPlayCount := SoundPlayCount - 1;
+            if trigData.trigPlayCount > 0 then SoundPlayCount -= 1; // Åñëè 0 - èãðàåì çâóê áåñêîíå÷íî
             if trigData.trigLocal then
-              Sound.PlayVolumeAt(X+(Width div 2), Y+(Height div 2), trigData.trigVolume/255.0)
+            begin
+              Sound.PlayVolumeAt(X+(Width div 2), Y+(Height div 2), trigData.trigVolume/255.0);
+            end
             else
+            begin
               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 Sound.IsPlaying() and g_Game_IsNet and g_Game_IsServer then MH_SEND_TriggerSound(gTriggers[a]);
           end;
+        end;
 
-      // Òðèããåð "Ëîâóøêà" - ïîðà îòêðûâàòü:
-        if (TriggerType = TRIGGER_TRAP) and (DoorTime = 0) and (trigPanelID <> -1) then
+        // Òðèããåð "Ëîâóøêà" - ïîðà îòêðûâàòü
+        if (TriggerType = TRIGGER_TRAP) and (DoorTime = 0) and (g_Map_PanelByGUID(trigPanelGUID) <> nil) then
         begin
-          tr_OpenDoor(trigPanelID, trigData.trigNoSound, trigData.trigd2d_doors);
+          tr_OpenDoor(trigPanelGUID, trigData.trigNoSound, trigData.trigd2d_doors);
           DoorTime := -1;
         end;
 
-      // Òðèããåð "Äâåðü 5 ñåê" - ïîðà çàêðûâàòü:
-        if (TriggerType = TRIGGER_DOOR5) and (DoorTime = 0) and (trigPanelID <> -1) then
+        // Òðèããåð "Äâåðü 5 ñåê" - ïîðà çàêðûâàòü
+        if (TriggerType = TRIGGER_DOOR5) and (DoorTime = 0) and (g_Map_PanelByGUID(trigPanelGUID) <> nil) then
         begin
-        // Óæå çàêðûòà:
-          if gWalls[trigPanelID].Enabled then
-            DoorTime := -1
-          else // Ïîêà îòêðûòà - çàêðûâàåì
-            if tr_CloseDoor(trigPanelID, trigData.trigNoSound, trigData.trigd2d_doors) then
+          pan := g_Map_PanelByGUID(trigPanelGUID);
+          if (pan <> nil) and pan.isGWall then
+          begin
+            // Óæå çàêðûòà
+            if {gWalls[trigPanelID].Enabled} pan.Enabled then
+            begin
               DoorTime := -1;
+            end
+            else
+            begin
+              // Ïîêà îòêðûòà - çàêðûâàåì
+              if tr_CloseDoor(trigPanelGUID, trigData.trigNoSound, trigData.trigd2d_doors) then DoorTime := -1;
+            end;
+          end;
         end;
 
       // Òðèããåð - ðàñøèðèòåëü èëè ïåðåêëþ÷àòåëü, è ïðîøëà çàäåðæêà, è íàæàëè íóæíîå ÷èñëî ðàç:
         if (TriggerType in [TRIGGER_PRESS, TRIGGER_ON, TRIGGER_OFF, TRIGGER_ONOFF]) and
            (PressTime = 0) and (PressCount >= trigData.trigCount) then
         begin
-        // Ñáðàñûâàåì çàäåðæêó àêòèâàöèè:
+          // Ñáðàñûâàåì çàäåðæêó àêòèâàöèè:
           PressTime := -1;
-        // Ñáðàñûâàåì ñ÷åò÷èê íàæàòèé:
-          if trigData.trigCount > 0 then
-            PressCount := PressCount - trigData.trigCount
-          else
-            PressCount := 0;
+          // Ñáðàñûâàåì ñ÷åò÷èê íàæàòèé:
+          if trigData.trigCount > 0 then PressCount -= trigData.trigCount else PressCount := 0;
 
-        // Îïðåäåëÿåì èçìåíÿåìûå èì òðèããåðû:
+          // Îïðåäåëÿåì èçìåíÿåìûå èì òðèããåðû:
           for b := 0 to High(gTriggers) do
+          begin
             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 (trigData.trigWait > 0)) then
@@ -2361,7 +2463,22 @@ begin
                 Affected[High(Affected)] := b;
               end;
             end;
-        // Âûáèðàåì îäèí èç òðèããåðîâ äëÿ ðàñøèðèòåëÿ, åñëè âêëþ÷åí ðàíäîì:
+          end;
+
+          //HACK!
+          // if we have panelid, assume that it will switch the moving platform
+          pan := g_Map_PanelByGUID(trigPanelGUID);
+          if (pan <> nil) then
+          begin
+            case TriggerType of
+              TRIGGER_PRESS: pan.movingActive := true; // what to do here?
+              TRIGGER_ON: pan.movingActive := true;
+              TRIGGER_OFF: pan.movingActive := false;
+              TRIGGER_ONOFF: pan.movingActive := not pan.movingActive;
+            end;
+          end;
+
+          // Âûáèðàåì îäèí èç òðèããåðîâ äëÿ ðàñøèðèòåëÿ, åñëè âêëþ÷åí ðàíäîì:
           if (TriggerType = TRIGGER_PRESS) and trigData.trigExtRandom then
           begin
             if (Length(Affected) > 0) then
@@ -2372,6 +2489,7 @@ begin
             end;
           end
           else // Â ïðîòèâíîì ñëó÷àå ðàáîòàåì êàê îáû÷íî:
+          begin
             for i := 0 to High(Affected) do
             begin
               b := Affected[i];
@@ -2410,6 +2528,7 @@ begin
                   end;
               end;
             end;
+          end;
           SetLength(Affected, 0);
         end;
 
@@ -2432,7 +2551,7 @@ begin
               if gPlayers[b] <> nil then
                 with gPlayers[b] do
                 // Æèâ, åñòü íóæíûå êëþ÷è è îí ðÿäîì:
-                  if Live and ((gTriggers[a].Keys and GetKeys) = gTriggers[a].Keys) and
+                  if alive and ((gTriggers[a].Keys and GetKeys) = gTriggers[a].Keys) and
                      Collide(X, Y, Width, Height) then
                   begin
                     gTriggers[a].ActivateUID := UID;
@@ -2627,15 +2746,19 @@ begin
 
   b := False;
   for a := 0 to High(gTriggers) do
+  begin
     with gTriggers[a] do
+    begin
       if (TriggerType = TRIGGER_OPENDOOR) or
          (TriggerType = TRIGGER_DOOR5) or
          (TriggerType = TRIGGER_DOOR) then
       begin
-        tr_OpenDoor(trigPanelID, True, trigData.trigd2d_doors);
+        tr_OpenDoor(trigPanelGUID, True, trigData.trigd2d_doors);
         if TriggerType = TRIGGER_DOOR5 then DoorTime := 180;
         b := True;
       end;
+    end;
+  end;
 
   if b then g_Sound_PlayEx('SOUND_GAME_DOOROPEN');
 end;
@@ -2653,7 +2776,6 @@ var
 begin
   for a := 0 to High(gTriggers) do
   begin
-    gTriggers[a].trigData.Free();
     if (gTriggers[a].TriggerType = TRIGGER_SOUND) then
     begin
       if g_Sound_Exists(gTriggers[a].trigData.trigSoundName) then
@@ -2666,6 +2788,7 @@ begin
     begin
       SetLength(gTriggers[a].Activators, 0);
     end;
+    gTriggers[a].trigData.Free();
   end;
 
   gTriggers := nil;
@@ -2679,31 +2802,30 @@ var
   dw: DWORD;
   sg: Single;
   b: Boolean;
-  //p: Pointer;
 begin
-// Ñ÷èòàåì êîëè÷åñòâî ñóùåñòâóþùèõ òðèããåðîâ:
-  count := 0;
-  if gTriggers <> nil then
-    for i := 0 to High(gTriggers) do
-      count := count + 1;
+  // Ñ÷èòàåì êîëè÷åñòâî ñóùåñòâóþùèõ òðèããåðîâ
+  count := Length(gTriggers);
 
   Mem := TBinMemoryWriter.Create((count+1) * 200);
 
-// Êîëè÷åñòâî òðèããåðîâ:
+  // Êîëè÷åñòâî òðèããåðîâ:
   Mem.WriteInt(count);
 
-  if count = 0 then
-    Exit;
+  //e_LogWritefln('saving %s triggers (count=%s)', [Length(gTriggers), count]);
+
+  if count = 0 then exit;
 
   for i := 0 to High(gTriggers) do
   begin
   // Ñèãíàòóðà òðèããåðà:
-    dw := TRIGGER_SIGNATURE; // 'TRGR'
+    dw := TRIGGER_SIGNATURE; // 'TRGX'
     Mem.WriteDWORD(dw);
   // Òèï òðèããåðà:
     Mem.WriteByte(gTriggers[i].TriggerType);
-  // Ñïåöèàëüíûå äàííûå òðèããåðà:
-  //!!!FIXME!!!
+    if (gTriggers[i].TriggerType = TRIGGER_NONE) then continue; // empty one
+  // Ñïåöèàëüíûå äàííûå òðèããåðà: äà â æîïó, ïîòîì èç êàðòû îïÿòü âûòàùèì; ñîõðàíèì òîëüêî èíäåêñ
+    //e_LogWritefln('=== trigger #%s saved ===', [gTriggers[i].mapIndex]);
+    Mem.WriteInt(gTriggers[i].mapIndex);
     //p := @gTriggers[i].Data;
     //Mem.WriteMemory(p, SizeOf(TTriggerData));
   // Êîîðäèíàòû ëåâîãî âåðõíåãî óãëà:
@@ -2719,9 +2841,11 @@ begin
   // Êëþ÷è, íåîáõîäèìûå äëÿ àêòèâàöèè:
     Mem.WriteByte(gTriggers[i].Keys);
   // ID ïàíåëè, òåêñòóðà êîòîðîé èçìåíèòñÿ:
-    Mem.WriteInt(gTriggers[i].TexturePanel);
+    Mem.WriteInt(gTriggers[i].TexturePanelGUID);
   // Òèï ýòîé ïàíåëè:
     Mem.WriteWord(gTriggers[i].TexturePanelType);
+  // Âíóòðåííèé íîìåð äðóãîé ïàíåëè (ïî ñ÷àñòëèâîé ñëó÷àéíîñòè îí áóäåò ñîâïàäàòü ñ òåì, ÷òî ñîçäàíî ïðè çàãðóçêå êàðòû)
+    Mem.WriteInt(gTriggers[i].trigPanelGUID);
   // Âðåìÿ äî âîçìîæíîñòè àêòèâàöèè:
     Mem.WriteWord(gTriggers[i].TimeOut);
   // UID òîãî, êòî àêòèâèðîâàë ýòîò òðèããåð:
@@ -2782,6 +2906,8 @@ var
   b: Boolean;
   //p: Pointer;
   Trig: TTrigger;
+  mapIndex: Integer;
+  //tw: TStrTextWriter;
 begin
   if Mem = nil then
     Exit;
@@ -2791,20 +2917,21 @@ begin
 // Êîëè÷åñòâî òðèããåðîâ:
   Mem.ReadInt(count);
 
-  if count = 0 then
-    Exit;
+  if (count = 0) then exit;
 
   for a := 0 to count-1 do
   begin
   // Ñèãíàòóðà òðèããåðà:
     Mem.ReadDWORD(dw);
-    if dw <> TRIGGER_SIGNATURE then // 'TRGR'
+    if (dw <> TRIGGER_SIGNATURE) then // 'TRGX'
     begin
       raise EBinSizeError.Create('g_Triggers_LoadState: Wrong Trigger Signature');
     end;
   // Òèï òðèããåðà:
     Mem.ReadByte(Trig.TriggerType);
-  // Ñïåöèàëüíûå äàííûå òðèããåðà:
+  // Ñïåöèàëüíûå äàííûå òðèããåðà: èíäåêñ â gCurrentMap.field['triggers']
+    if (Trig.TriggerType = TRIGGER_NONE) then continue; // empty one
+    Mem.ReadInt(mapIndex);
   //!!!FIXME!!!
     {
     Mem.ReadMemory(p, dw);
@@ -2815,7 +2942,19 @@ begin
     Trig.Data := TTriggerData(p^);
     }
   // Ñîçäàåì òðèããåð:
-    i := g_Triggers_Create(Trig);
+    i := g_Triggers_CreateWithMapIndex(Trig, a, mapIndex);
+    {
+    if (gTriggers[i].trigData <> nil) then
+    begin
+      tw := TStrTextWriter.Create();
+      try
+        gTriggers[i].trigData.writeTo(tw);
+        e_LogWritefln('=== trigger #%s loaded ==='#10'%s'#10'---', [mapIndex, tw.str]);
+      finally
+        tw.Free();
+      end;
+    end;
+    }
   // Êîîðäèíàòû ëåâîãî âåðõíåãî óãëà:
     Mem.ReadInt(gTriggers[i].X);
     Mem.ReadInt(gTriggers[i].Y);
@@ -2829,9 +2968,11 @@ begin
   // Êëþ÷è, íåîáõîäèìûå äëÿ àêòèâàöèè:
     Mem.ReadByte(gTriggers[i].Keys);
   // ID ïàíåëè, òåêñòóðà êîòîðîé èçìåíèòñÿ:
-    Mem.ReadInt(gTriggers[i].TexturePanel);
+    Mem.ReadInt(gTriggers[i].TexturePanelGUID);
   // Òèï ýòîé ïàíåëè:
     Mem.ReadWord(gTriggers[i].TexturePanelType);
+  // Âíóòðåííèé íîìåð äðóãîé ïàíåëè (ïî ñ÷àñòëèâîé ñëó÷àéíîñòè îí áóäåò ñîâïàäàòü ñ òåì, ÷òî ñîçäàíî ïðè çàãðóçêå êàðòû)
+    Mem.ReadInt(gTriggers[i].trigPanelGUID);
   // Âðåìÿ äî âîçìîæíîñòè àêòèâàöèè:
     Mem.ReadWord(gTriggers[i].TimeOut);
   // UID òîãî, êòî àêòèâèðîâàë ýòîò òðèããåð: