DEADSOFTWARE

some accessors to publish more properties
[d2df-sdl.git] / src / game / g_panel.pas
index c13693e7b0bc3aa3cefd820bfdd433fb35446973..d104593da3eeb95a875366263c08c5c78b2554f7 100644 (file)
  * You should have received a copy of the GNU General Public License
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  *)
-{$MODE DELPHI}
+{$INCLUDE ../shared/a_modes.inc}
+{$M+}
 unit g_panel;
 
 interface
 
 uses
-  MAPSTRUCT, BinEditor, g_textures;
+  MAPDEF, BinEditor, g_textures, xdynrec;
 
 type
   TAddTextureArray = Array of
@@ -30,6 +31,9 @@ type
 
   TPanel = Class (TObject)
   private
+    const
+  private
+    mGUID: Integer; // will be assigned in "g_map.pas"
     FTextureWidth:    Word;
     FTextureHeight:   Word;
     FAlpha:           Byte;
@@ -41,26 +45,59 @@ type
                             True:  (AnTex: TAnimation);
                         end;
 
+    mMovingSpeed: TDFPoint;
+    mMovingStart: TDFPoint;
+    mMovingEnd: TDFPoint;
+    mMovingActive: Boolean;
+
+  private
+    function getx1 (): Integer; inline;
+    function gety1 (): Integer; inline;
+    function getvisvalid (): Boolean; inline;
+
+    function getMovingSpeedX (): Integer; inline;
+    procedure setMovingSpeedX (v: Integer); inline;
+    function getMovingSpeedY (): Integer; inline;
+    procedure setMovingSpeedY (v: Integer); inline;
+
+    function getMovingStartX (): Integer; inline;
+    procedure setMovingStartX (v: Integer); inline;
+    function getMovingStartY (): Integer; inline;
+    procedure setMovingStartY (v: Integer); inline;
+
+    function getMovingEndX (): Integer; inline;
+    procedure setMovingEndX (v: Integer); inline;
+    function getMovingEndY (): Integer; inline;
+    procedure setMovingEndY (v: Integer); inline;
+
   public
     FCurTexture:      Integer; // Íîìåð òåêóùåé òåêñòóðû
     FCurFrame:        Integer;
     FCurFrameCount:   Byte;
-    X, Y:             Integer;
-    Width, Height:    Word;
-    PanelType:        Word;
-    SaveIt:           Boolean; // Ñîõðàíÿòü ïðè SaveState?
-    Enabled:          Boolean;
-    Door:             Boolean;
-    LiftType:         Byte;
-    LastAnimLoop:     Byte;
-
-    constructor Create(PanelRec: TPanelRec_1;
+    FX, FY:           Integer;
+    FWidth, FHeight:  Word;
+    FPanelType:       Word;
+    FSaveIt:          Boolean; // Ñîõðàíÿòü ïðè SaveState?
+    FEnabled:         Boolean;
+    FDoor:            Boolean;
+    FMoved:           Boolean;
+    FLiftType:        Byte;
+    FLastAnimLoop:    Byte;
+    // sorry, there fields are public to allow setting 'em in g_map; this should be fixed later
+    // for now, PLEASE, don't modify 'em, or all hell will break loose
+    arrIdx:           Integer; // index in one of internal arrays; sorry
+    tag:              Integer; // used in coldets and such; sorry; see g_map.GridTagXXX
+    proxyId:          Integer; // proxy id in map grid (DO NOT USE!)
+    mapId:            AnsiString; // taken directly from map file; dunno why it is here
+
+    constructor Create(PanelRec: TDynRecord;
                        AddTextures: TAddTextureArray;
                        CurTex: Integer;
-                       var Textures: TLevelTextureArray);
+                       var Textures: TLevelTextureArray; aguid: Integer);
     destructor  Destroy(); override;
 
     procedure   Draw();
+    procedure   DrawShadowVolume(lightX: Integer; lightY: Integer; radius: Integer);
     procedure   Update();
     procedure   SetFrame(Frame: Integer; Count: Byte);
     procedure   NextTexture(AnimLoop: Byte = 0);
@@ -70,6 +107,62 @@ type
 
     procedure   SaveState(var Mem: TBinMemoryWriter);
     procedure   LoadState(var Mem: TBinMemoryReader);
+
+    procedure positionChanged (); inline;
+
+    function getIsGBack (): Boolean; inline; // gRenderBackgrounds
+    function getIsGStep (): Boolean; inline; // gSteps
+    function getIsGWall (): Boolean; inline; // gWalls
+    function getIsGAcid1 (): Boolean; inline; // gAcid1
+    function getIsGAcid2 (): Boolean; inline; // gAcid2
+    function getIsGWater (): Boolean; inline; // gWater
+    function getIsGFore (): Boolean; inline; // gRenderForegrounds
+    function getIsGLift (): Boolean; inline; // gLifts
+    function getIsGBlockMon (): Boolean; inline; // gBlockMon
+
+  public
+    property visvalid: Boolean read getvisvalid; // panel is "visvalid" when it's width and height are positive
+
+  published
+    property guid: Integer read mGUID; // will be assigned in "g_map.pas"
+    property x0: Integer read FX;
+    property y0: Integer read FY;
+    property x1: Integer read getx1; // inclusive!
+    property y1: Integer read gety1; // inclusive!
+    property x: Integer read FX write FX;
+    property y: Integer read FY write FY;
+    property width: Word read FWidth write FWidth;
+    property height: Word read FHeight write FHeight;
+    property panelType: Word read FPanelType write FPanelType;
+    property saveIt: Boolean read FSaveIt write FSaveIt; // Ñîõðàíÿòü ïðè SaveState?
+    property enabled: Boolean read FEnabled write FEnabled; // Ñîõðàíÿòü ïðè SaveState?
+    property door: Boolean read FDoor write FDoor; // Ñîõðàíÿòü ïðè SaveState?
+    property moved: Boolean read FMoved write FMoved; // Ñîõðàíÿòü ïðè SaveState?
+    property liftType: Byte read FLiftType write FLiftType; // Ñîõðàíÿòü ïðè SaveState?
+    property lastAnimLoop: Byte read FLastAnimLoop write FLastAnimLoop; // Ñîõðàíÿòü ïðè SaveState?
+
+    property movingSpeedX: Integer read getMovingSpeedX write setMovingSpeedX;
+    property movingSpeedY: Integer read getMovingSpeedY write setMovingSpeedY;
+    property movingStartX: Integer read getMovingStartX write setMovingStartX;
+    property movingStartY: Integer read getMovingStartY write setMovingStartY;
+    property movingEndX: Integer read getMovingEndX write setMovingEndX;
+    property movingEndY: Integer read getMovingEndY write setMovingEndY;
+    property movingActive: Boolean read mMovingActive write mMovingActive;
+
+    property isGBack: Boolean read getIsGBack;
+    property isGStep: Boolean read getIsGStep;
+    property isGWall: Boolean read getIsGWall;
+    property isGAcid1: Boolean read getIsGAcid1;
+    property isGAcid2: Boolean read getIsGAcid2;
+    property isGWater: Boolean read getIsGWater;
+    property isGFore: Boolean read getIsGFore;
+    property isGLift: Boolean read getIsGLift;
+    property isGBlockMon: Boolean read getIsGBlockMon;
+
+  public
+    property movingSpeed: TDFPoint read mMovingSpeed write mMovingSpeed;
+    property movingStart: TDFPoint read mMovingStart write mMovingStart;
+    property movingEnd: TDFPoint read mMovingEnd write mMovingEnd;
   end;
 
   TPanelArray = Array of TPanel;
@@ -77,18 +170,18 @@ type
 implementation
 
 uses
-  SysUtils, g_basic, g_map, MAPDEF, g_game, e_graphics,
-  g_console, g_language, e_log;
+  SysUtils, g_basic, g_map, g_game, g_gfx, e_graphics,
+  g_console, g_language, g_monsters, g_player, e_log, GL;
 
 const
   PANEL_SIGNATURE = $4C4E4150; // 'PANL'
 
 { T P a n e l : }
 
-constructor TPanel.Create(PanelRec: TPanelRec_1;
+constructor TPanel.Create(PanelRec: TDynRecord;
                           AddTextures: TAddTextureArray;
                           CurTex: Integer;
-                          var Textures: TLevelTextureArray);
+                          var Textures: TLevelTextureArray; aguid: Integer);
 var
   i: Integer;
 begin
@@ -101,6 +194,15 @@ begin
   FCurFrame := 0;
   FCurFrameCount := 0;
   LastAnimLoop := 0;
+  Moved := False;
+
+  mapId := PanelRec.id;
+  mGUID := aguid;
+
+  mMovingSpeed := PanelRec.moveSpeed;
+  mMovingStart := PanelRec.moveStart;
+  mMovingEnd := PanelRec.moveEnd;
+  mMovingActive := PanelRec['move_active'].varvalue;
 
 // Òèï ïàíåëè:
   PanelType := PanelRec.PanelType;
@@ -169,11 +271,11 @@ begin
 
     case PanelRec.PanelType of
       PANEL_WATER:
-        FTextureIDs[0].Tex := TEXTURE_SPECIAL_WATER;
+        FTextureIDs[0].Tex := LongWord(TEXTURE_SPECIAL_WATER);
       PANEL_ACID1:
-        FTextureIDs[0].Tex := TEXTURE_SPECIAL_ACID1;
+        FTextureIDs[0].Tex := LongWord(TEXTURE_SPECIAL_ACID1);
       PANEL_ACID2:
-        FTextureIDs[0].Tex := TEXTURE_SPECIAL_ACID2;
+        FTextureIDs[0].Tex := LongWord(TEXTURE_SPECIAL_ACID2);
     end;
 
     FCurTexture := 0;
@@ -242,16 +344,44 @@ begin
   Inherited;
 end;
 
+function TPanel.getx1 (): Integer; inline; begin result := X+Width-1; end;
+function TPanel.gety1 (): Integer; inline; begin result := Y+Height-1; end;
+function TPanel.getvisvalid (): Boolean; inline; begin result := (Width > 0) and (Height > 0); end;
+
+function TPanel.getMovingSpeedX (): Integer; inline; begin result := mMovingSpeed.X; end;
+procedure TPanel.setMovingSpeedX (v: Integer); inline; begin mMovingSpeed.X := v; end;
+function TPanel.getMovingSpeedY (): Integer; inline; begin result := mMovingSpeed.Y; end;
+procedure TPanel.setMovingSpeedY (v: Integer); inline; begin mMovingSpeed.Y := v; end;
+
+function TPanel.getMovingStartX (): Integer; inline; begin result := mMovingStart.X; end;
+procedure TPanel.setMovingStartX (v: Integer); inline; begin mMovingStart.X := v; end;
+function TPanel.getMovingStartY (): Integer; inline; begin result := mMovingStart.Y; end;
+procedure TPanel.setMovingStartY (v: Integer); inline; begin mMovingStart.Y := v; end;
+
+function TPanel.getMovingEndX (): Integer; inline; begin result := mMovingEnd.X; end;
+procedure TPanel.setMovingEndX (v: Integer); inline; begin mMovingEnd.X := v; end;
+function TPanel.getMovingEndY (): Integer; inline; begin result := mMovingEnd.Y; end;
+procedure TPanel.setMovingEndY (v: Integer); inline; begin mMovingEnd.Y := v; end;
+
+function TPanel.getIsGBack (): Boolean; inline; begin result := ((tag and GridTagBack) <> 0); end;
+function TPanel.getIsGStep (): Boolean; inline; begin result := ((tag and GridTagStep) <> 0); end;
+function TPanel.getIsGWall (): Boolean; inline; begin result := ((tag and (GridTagWall or GridTagDoor)) <> 0); end;
+function TPanel.getIsGAcid1 (): Boolean; inline; begin result := ((tag and GridTagAcid1) <> 0); end;
+function TPanel.getIsGAcid2 (): Boolean; inline; begin result := ((tag and GridTagAcid2) <> 0); end;
+function TPanel.getIsGWater (): Boolean; inline; begin result := ((tag and GridTagWater) <> 0); end;
+function TPanel.getIsGFore (): Boolean; inline; begin result := ((tag and GridTagFore) <> 0); end;
+function TPanel.getIsGLift (): Boolean; inline; begin result := ((tag and GridTagLift) <> 0); end;
+function TPanel.getIsGBlockMon (): Boolean; inline; begin result := ((tag and GridTagBlockMon) <> 0); end;
+
 procedure TPanel.Draw();
 var
   xx, yy: Integer;
   NoTextureID: DWORD;
   NW, NH: Word;
 begin
-  if Enabled and (FCurTexture >= 0) and
+  if {Enabled and} (FCurTexture >= 0) and
      (Width > 0) and (Height > 0) and (FAlpha < 255) and
-     g_Collide(X, Y, Width, Height,
-               sX, sY, sWidth, sHeight) then
+     ((g_dbg_scale <> 1.0) or g_Collide(X, Y, Width, Height, sX, sY, sWidth, sHeight)) then
   begin
     if FTextureIDs[FCurTexture].Anim then
       begin // Àíèìèðîâàííàÿ òåêñòóðà
@@ -267,16 +397,16 @@ begin
     else
       begin // Îáû÷íàÿ òåêñòóðà
         case FTextureIDs[FCurTexture].Tex of
-          TEXTURE_SPECIAL_WATER:
+          LongWord(TEXTURE_SPECIAL_WATER):
             e_DrawFillQuad(X, Y, X+Width-1, Y+Height-1,
                            0, 0, 255, 0, B_FILTER);
-          TEXTURE_SPECIAL_ACID1:
+          LongWord(TEXTURE_SPECIAL_ACID1):
             e_DrawFillQuad(X, Y, X+Width-1, Y+Height-1,
                            0, 128, 0, 0, B_FILTER);
-          TEXTURE_SPECIAL_ACID2:
+          LongWord(TEXTURE_SPECIAL_ACID2):
             e_DrawFillQuad(X, Y, X+Width-1, Y+Height-1,
                            128, 0, 0, 0, B_FILTER);
-          TEXTURE_NONE:
+          LongWord(TEXTURE_NONE):
             if g_Texture_Get('NOTEXTURE', NoTextureID) then
             begin
               e_GetTextureSize(NoTextureID, @NW, @NH);
@@ -306,7 +436,153 @@ begin
   end;
 end;
 
+procedure TPanel.DrawShadowVolume(lightX: Integer; lightY: Integer; radius: Integer);
+  procedure extrude (x: Integer; y: Integer);
+  begin
+    glVertex2i(x+(x-lightX)*500, y+(y-lightY)*500);
+    //e_WriteLog(Format('  : (%d,%d)', [x+(x-lightX)*300, y+(y-lightY)*300]), MSG_WARNING);
+  end;
+
+  procedure drawLine (x0: Integer; y0: Integer; x1: Integer; y1: Integer);
+  begin
+    // does this side facing the light?
+    if ((x1-x0)*(lightY-y0)-(lightX-x0)*(y1-y0) >= 0) then exit;
+    //e_WriteLog(Format('lightpan: (%d,%d)-(%d,%d)', [x0, y0, x1, y1]), MSG_WARNING);
+    // this edge is facing the light, extrude and draw it
+    glVertex2i(x0, y0);
+    glVertex2i(x1, y1);
+    extrude(x1, y1);
+    extrude(x0, y0);
+  end;
+
+begin
+  if radius < 4 then exit;
+  if Enabled and (FCurTexture >= 0) and (Width > 0) and (Height > 0) and (FAlpha < 255) and g_Collide(X, Y, Width, Height, sX, sY, sWidth, sHeight) then
+  begin
+    if not FTextureIDs[FCurTexture].Anim then
+    begin
+      case FTextureIDs[FCurTexture].Tex of
+        LongWord(TEXTURE_SPECIAL_WATER): exit;
+        LongWord(TEXTURE_SPECIAL_ACID1): exit;
+        LongWord(TEXTURE_SPECIAL_ACID2): exit;
+        LongWord(TEXTURE_NONE): exit;
+      end;
+    end;
+    if (X+Width < lightX-radius) then exit;
+    if (Y+Height < lightY-radius) then exit;
+    if (X > lightX+radius) then exit;
+    if (Y > lightY+radius) then exit;
+    //e_DrawFill(FTextureIDs[FCurTexture].Tex, X, Y, Width div FTextureWidth, Height div FTextureHeight, FAlpha, True, FBlending);
+
+    glBegin(GL_QUADS);
+      drawLine(x,       y,        x+width, y); // top
+      drawLine(x+width, y,        x+width, y+height); // right
+      drawLine(x+width, y+height, x,       y+height); // bottom
+      drawLine(x,       y+height, x,       y); // left
+    glEnd();
+  end;
+end;
+
+
+procedure TPanel.positionChanged (); inline;
+var
+  px, py, pw, ph: Integer;
+begin
+  if (proxyId >= 0) then
+  begin
+    monsGrid.getBodyDims(proxyId, px, py, pw, ph);
+    if (px <> x) or (py <> y) or (pw <> Width) or (ph <> Height) then
+    begin
+      g_Mark(px, py, pw, ph, MARK_WALL, false);
+      if (pw <> Width) or (ph <> Height) then mapGrid.moveResizeBody(proxyId, X, Y, Width, Height)
+      else mapGrid.moveBody(proxyId, X, Y);
+      g_Mark(X, Y, Width, Height, MARK_WALL);
+    end;
+  end;
+end;
+
+
+var
+  monMoveList: array of TMonster = nil;
+  monMoveListUsed: Integer = 0;
+
 procedure TPanel.Update();
+var
+  nx, ny: Integer;
+  f: Integer;
+
+  function doPush (px, py, pw, ph: Integer; out dx, dy: Integer): Boolean;
+  begin
+    result := g_Collide(px, py, pw, ph, nx, ny, Width, Height);
+    if result then
+    begin
+      // need to push
+           if (mMovingSpeed.X < 0) then dx := nx-(px+pw)
+      else if (mMovingSpeed.X > 0) then dx := (nx+Width)-px
+      else dx := 0;
+           if (mMovingSpeed.Y < 0) then dy := ny-(py+ph)
+      else if (mMovingSpeed.Y > 0) then dy := (ny+Height)-py
+      else dy := 0;
+    end
+    else
+    begin
+      dx := 0;
+      dy := 0;
+    end;
+  end;
+
+  function monMove (mon: TMonster): Boolean;
+  begin
+    result := false; // don't stop
+    //mon.GameX := mon.GameX+mMovingSpeed.X;
+    //mon.GameY := mon.GameY+mMovingSpeed.Y;
+    mon.setPosition(mon.GameX+mMovingSpeed.X, mon.GameY+mMovingSpeed.Y, false); // we can't call `positionChanged()` in grid callback
+    if (monMoveListUsed >= Length(monMoveList)) then SetLength(monMoveList, monMoveListUsed+64);
+    monMoveList[monMoveListUsed] := mon;
+    Inc(monMoveListUsed);
+  end;
+
+  function monPush (mon: TMonster): Boolean;
+  var
+    px, py, pw, ph, dx, dy: Integer;
+  begin
+    result := false; // don't stop
+    mon.getMapBox(px, py, pw, ph);
+    if doPush(px, py, pw, ph, dx, dy) then
+    begin
+      //mon.GameX := mon.GameX+dx;
+      //mon.GameY := mon.GameY+dy;
+      mon.setPosition(mon.GameX+dx, mon.GameY+dy, false); // we can't call `positionChanged()` in grid callback
+      if (monMoveListUsed >= Length(monMoveList)) then SetLength(monMoveList, monMoveListUsed+64);
+      monMoveList[monMoveListUsed] := mon;
+      Inc(monMoveListUsed);
+    end;
+  end;
+
+  procedure plrMove (plr: TPlayer);
+  var
+    px, py, pw, ph, dx, dy: Integer;
+  begin
+    if (plr = nil) then exit;
+    plr.getMapBox(px, py, pw, ph);
+    if (py+ph <> Y) then
+    begin
+      // push player
+      if doPush(px, py, pw, ph, dx, dy) then
+      begin
+        plr.GameX := plr.GameX+dx;
+        plr.GameY := plr.GameY+dy;
+        plr.positionChanged();
+      end;
+      exit;
+    end;
+    if (px+pw <= X) then exit;
+    if (px >= X+Width) then exit;
+    plr.GameX := plr.GameX+mMovingSpeed.X;
+    plr.GameY := plr.GameY+mMovingSpeed.Y;
+    plr.positionChanged();
+  end;
+
 begin
   if Enabled and (FCurTexture >= 0) and
     (FTextureIDs[FCurTexture].Anim) and
@@ -317,6 +593,33 @@ begin
     FCurFrame := FTextureIDs[FCurTexture].AnTex.CurrentFrame;
     FCurFrameCount := FTextureIDs[FCurTexture].AnTex.CurrentCounter;
   end;
+
+  if mMovingActive and (not mMovingSpeed.isZero) then
+  begin
+    monMoveListUsed := 0;
+    nx := X+mMovingSpeed.X;
+    ny := Y+mMovingSpeed.Y;
+    // move monsters on lifts
+    g_Mons_ForEachAt(X, Y-1, Width, 1, monMove);
+    // push monsters
+    g_Mons_ForEachAt(nx, ny, Width, Height, monPush);
+    // move and push players
+    for f := 0 to High(gPlayers) do plrMove(gPlayers[f]);
+    // reverse moving direction, if necessary
+         if (mMovingSpeed.X < 0) and (nx <= mMovingStart.X) then mMovingSpeed.X := -mMovingSpeed.X
+    else if (mMovingSpeed.X > 0) and (nx >= mMovingEnd.X) then mMovingSpeed.X := -mMovingSpeed.X;
+         if (mMovingSpeed.Y < 0) and (ny <= mMovingStart.Y) then mMovingSpeed.Y := -mMovingSpeed.Y
+    else if (mMovingSpeed.Y > 0) and (ny >= mMovingEnd.Y) then mMovingSpeed.Y := -mMovingSpeed.Y;
+    // awake particles
+    //g_Mark(X, Y, Width, Height, MARK_WALL, false);
+    X := nx;
+    Y := ny;
+    //g_Mark(nx, ny, Width, Height, MARK_WALL);
+    // fix grid
+    positionChanged();
+    // notify moved monsters about their movement
+    for f := 0 to monMoveListUsed-1 do monMoveList[f].positionChanged();
+  end;
 end;
 
 procedure TPanel.SetFrame(Frame: Integer; Count: Byte);
@@ -429,7 +732,7 @@ end;
 
 function TPanel.GetTextureID(): DWORD;
 begin
-  Result := TEXTURE_NONE;
+  Result := LongWord(TEXTURE_NONE);
 
   if (FCurTexture >= 0) then
   begin
@@ -455,18 +758,21 @@ var
   sig: DWORD;
   anim: Boolean;
 begin
-  if (not SaveIt) or (Mem = nil) then
-    Exit;
+  if (Mem = nil) then exit;
+  //if not SaveIt then exit;
 
 // Ñèãíàòóðà ïàíåëè:
   sig := PANEL_SIGNATURE; // 'PANL'
   Mem.WriteDWORD(sig);
 // Îòêðûòà/çàêðûòà, åñëè äâåðü:
-  Mem.WriteBoolean(Enabled);
+  Mem.WriteBoolean(FEnabled);
 // Íàïðàâëåíèå ëèôòà, åñëè ëèôò:
-  Mem.WriteByte(LiftType);
+  Mem.WriteByte(FLiftType);
 // Íîìåð òåêóùåé òåêñòóðû:
   Mem.WriteInt(FCurTexture);
+// Êîîðäû
+  Mem.WriteInt(FX);
+  Mem.WriteInt(FY);
 // Àíèìèðîâàííàÿ ëè òåêóùàÿ òåêñòóðà:
   if (FCurTexture >= 0) and (FTextureIDs[FCurTexture].Anim) then
     begin
@@ -480,15 +786,24 @@ begin
 // Åñëè äà - ñîõðàíÿåì àíèìàöèþ:
   if anim then
     FTextureIDs[FCurTexture].AnTex.SaveState(Mem);
+  // moving platform state
+  Mem.WriteInt(mMovingSpeed.X);
+  Mem.WriteInt(mMovingSpeed.Y);
+  Mem.WriteInt(mMovingStart.X);
+  Mem.WriteInt(mMovingStart.Y);
+  Mem.WriteInt(mMovingEnd.X);
+  Mem.WriteInt(mMovingEnd.Y);
+  Mem.WriteBoolean(mMovingActive);
 end;
 
 procedure TPanel.LoadState(var Mem: TBinMemoryReader);
 var
   sig: DWORD;
   anim: Boolean;
+  //ox, oy: Integer;
 begin
-  if (not SaveIt) or (Mem = nil) then
-    Exit;
+  if (Mem = nil) then exit;
+  //if not SaveIt then exit;
 
 // Ñèãíàòóðà ïàíåëè:
   Mem.ReadDWORD(sig);
@@ -497,11 +812,17 @@ begin
     raise EBinSizeError.Create('TPanel.LoadState: Wrong Panel Signature');
   end;
 // Îòêðûòà/çàêðûòà, åñëè äâåðü:
-  Mem.ReadBoolean(Enabled);
+  Mem.ReadBoolean(FEnabled);
 // Íàïðàâëåíèå ëèôòà, åñëè ëèôò:
-  Mem.ReadByte(LiftType);
+  Mem.ReadByte(FLiftType);
 // Íîìåð òåêóùåé òåêñòóðû:
   Mem.ReadInt(FCurTexture);
+// Êîîðäû
+  //ox := FX;
+  //oy := FY;
+  Mem.ReadInt(FX);
+  Mem.ReadInt(FY);
+  //e_LogWritefln('panel %s(%s): old=(%s,%s); new=(%s,%s); delta=(%s,%s)', [arrIdx, proxyId, ox, oy, FX, FY, FX-ox, FY-oy]);
 // Àíèìèðîâàííàÿ ëè òåêóùàÿ òåêñòóðà:
   Mem.ReadBoolean(anim);
 // Åñëè äà - çàãðóæàåì àíèìàöèþ:
@@ -513,6 +834,17 @@ begin
            'TPanel.LoadState: No animation object');
     FTextureIDs[FCurTexture].AnTex.LoadState(Mem);
   end;
+  // moving platform state
+  Mem.ReadInt(mMovingSpeed.X);
+  Mem.ReadInt(mMovingSpeed.Y);
+  Mem.ReadInt(mMovingStart.X);
+  Mem.ReadInt(mMovingStart.Y);
+  Mem.ReadInt(mMovingEnd.X);
+  Mem.ReadInt(mMovingEnd.Y);
+  Mem.ReadBoolean(mMovingActive);
+
+  positionChanged();
+  //mapGrid.proxyEnabled[proxyId] := FEnabled; // done in g_map.pas
 end;
 
 end.