DEADSOFTWARE

mplat fixes
authorKetmar Dark <ketmar@ketmar.no-ip.org>
Tue, 5 Sep 2017 01:48:59 +0000 (04:48 +0300)
committerKetmar Dark <ketmar@ketmar.no-ip.org>
Tue, 5 Sep 2017 01:49:09 +0000 (04:49 +0300)
src/game/g_game.pas
src/game/g_map.pas
src/game/g_panel.pas
src/game/g_triggers.pas
src/game/g_window.pas
src/mapdef/mapdef.txt
src/shared/MAPDEF.pas
src/shared/mapdef.inc
src/shared/xdynrec.pas

index 58abd6ef2ef281d0b7ee2b0d471708ff8ced7143..c83fb8e455e06decf3ce5a07a13f94a8aa06a33c 100644 (file)
@@ -794,7 +794,7 @@ begin
 
   {$IF DEFINED(D2F_DEBUG)}
   if gPlayer1 <> nil then gPlayer1.NoTarget := True;
-  gAimLine := true;
+  gAimLine := g_dbg_aimline_on;
   {$ENDIF}
 end;
 
index bbf39cb5efb7bad44613c76d9352e0cb2655b37b..101c3c544d06658454afb94777d730c333832545 100644 (file)
@@ -1293,10 +1293,11 @@ begin
   end;
 end;
 
-procedure CreateTrigger (amapIdx: Integer; Trigger: TDynRecord; atpanid, atrigpanid: Integer; fTexturePanel1Type, fTexturePanel2Type: Word);
+function CreateTrigger (amapIdx: Integer; Trigger: TDynRecord; atpanid, atrigpanid: Integer; fTexturePanel1Type, fTexturePanel2Type: Word): Integer;
 var
   _trigger: TTrigger;
 begin
+  result := -1;
   if g_Game_IsClient and not (Trigger.TriggerType in [TRIGGER_SOUND, TRIGGER_MUSIC]) then Exit;
 
   with _trigger do
@@ -1332,7 +1333,7 @@ begin
     end;
   end;
 
-  g_Triggers_Create(_trigger);
+  result := Integer(g_Triggers_Create(_trigger));
 end;
 
 procedure CreateMonster(monster: TDynRecord);
@@ -1577,6 +1578,8 @@ type
   PTRec = ^TTRec;
   TTRec = record
     //TexturePanel: Integer;
+    tnum: Integer;
+    id: Integer;
     texPanIdx: Integer;
     LiftPanelIdx: Integer;
     DoorPanelIdx: Integer;
@@ -1613,6 +1616,7 @@ var
   stt: UInt64;
   moveSpeed{, moveStart, moveEnd}: TDFPoint;
   //moveActive: Boolean;
+  pan: TPanel;
 begin
   mapGrid.Free();
   mapGrid := nil;
@@ -2057,7 +2061,21 @@ begin
         else if (TriggersTable[trignum].MPlatPanelIdx <> -1) then tgpid := TriggersTable[trignum].MPlatPanelIdx
         else tgpid := -1;
         //e_LogWritefln('creating trigger #%s; texpantype=%s; shotpantype=%s (%d,%d)', [trignum, b, c, TriggersTable[trignum].texPanIdx, TriggersTable[trignum].ShotPanelIdx]);
-        CreateTrigger(trignum, rec, TriggersTable[trignum].texPanIdx, tgpid, Word(b), Word(c));
+        TriggersTable[trignum].tnum := trignum;
+        TriggersTable[trignum].id := CreateTrigger(trignum, rec, TriggersTable[trignum].texPanIdx, tgpid, Word(b), Word(c));
+      end;
+    end;
+
+    //FIXME: use hashtable!
+    for pan in panByGUID do
+    begin
+      if (pan.endPosTrigId >= 0) and (pan.endPosTrigId < Length(TriggersTable)) then
+      begin
+        pan.endPosTrigId := TriggersTable[pan.endPosTrigId].id;
+      end;
+      if (pan.endSizeTrigId >= 0) and (pan.endSizeTrigId < Length(TriggersTable)) then
+      begin
+        pan.endSizeTrigId := TriggersTable[pan.endSizeTrigId].id;
       end;
     end;
 
index 7ea056dc25f97fef599dfaa48539367915558137..2f54116f98da1fcf96782ba70d2035e2e335553d 100644 (file)
@@ -49,6 +49,13 @@ type
     mMovingStart: TDFPoint;
     mMovingEnd: TDFPoint;
     mMovingActive: Boolean;
+    mMoveOnce: Boolean;
+
+    mSizeSpeed: TDFSize;
+    mSizeEnd: TDFSize;
+
+    mEndPosTrig: Integer;
+    mEndSizeTrig: Integer;
 
   private
     function getx1 (): Integer; inline;
@@ -148,6 +155,7 @@ type
     property movingEndX: Integer read getMovingEndX write setMovingEndX;
     property movingEndY: Integer read getMovingEndY write setMovingEndY;
     property movingActive: Boolean read mMovingActive write mMovingActive;
+    property moveOnce: Boolean read mMoveOnce write mMoveOnce;
 
     property isGBack: Boolean read getIsGBack;
     property isGStep: Boolean read getIsGStep;
@@ -163,6 +171,9 @@ type
     property movingSpeed: TDFPoint read mMovingSpeed write mMovingSpeed;
     property movingStart: TDFPoint read mMovingStart write mMovingStart;
     property movingEnd: TDFPoint read mMovingEnd write mMovingEnd;
+
+    property endPosTrigId: Integer read mEndPosTrig write mEndPosTrig;
+    property endSizeTrigId: Integer read mEndSizeTrig write mEndSizeTrig;
   end;
 
   TPanelArray = Array of TPanel;
@@ -175,7 +186,7 @@ var
 implementation
 
 uses
-  SysUtils, g_basic, g_map, g_game, g_gfx, e_graphics, g_weapons,
+  SysUtils, g_basic, g_map, g_game, g_gfx, e_graphics, g_weapons, g_triggers,
   g_console, g_language, g_monsters, g_player, g_grid, e_log, GL, utils;
 
 const
@@ -208,6 +219,13 @@ begin
   mMovingStart := PanelRec.moveStart;
   mMovingEnd := PanelRec.moveEnd;
   mMovingActive := PanelRec['move_active'].varvalue;
+  mMoveOnce := PanelRec.moveOnce;
+
+  mSizeSpeed := PanelRec.sizeSpeed;
+  mSizeEnd := PanelRec.sizeEnd;
+
+  mEndPosTrig := PanelRec.endPosTrig;
+  mEndSizeTrig := PanelRec.endSizeTrig;
 
 // Òèï ïàíåëè:
   PanelType := PanelRec.PanelType;
@@ -503,9 +521,17 @@ begin
         [arrIdx, mGUID, proxyId, px, py, pw, ph, x, y, width, height]);
       }
       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);
+      if (Width < 1) or (Height < 1) then
+      begin
+        mapGrid.proxyEnabled[proxyId] := false;
+      end
+      else
+      begin
+        mapGrid.proxyEnabled[proxyId] := Enabled;
+        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;
 end;
@@ -530,6 +556,7 @@ var
     pdx, pdy: Integer;
     pan: TPanel;
     trtag: Integer;
+    hedge: Integer;
   begin
     squash := false;
     tex := px;
@@ -546,10 +573,12 @@ var
       begin
         //e_LogWritefln('entity on the platform; tracing=(%s,%s); endpoint=(%s,%s); mustbe=(%s,%s)', [px, py, tex, tey, px+pdx, py+pdy]);
         // if we cannot move, only walls should squash the entity
+        {
         if ((tag and (GridTagWall or GridTagDoor)) <> 0) then
         begin
           if (tex = px) and (tey = py) then squash := true;
         end;
+        }
       end;
     end
     else
@@ -563,7 +592,7 @@ var
         e_LogWritefln('entity is embedded: plr=(%s,%s)-(%s,%s); mpl=(%s,%s)-(%s,%s)', [px, py, px+pw-1, py+ph-1, ox, oy, ox+mpw-1, oy+mph-1]);
       end;
       }
-      if sweepAABB(ox, oy, mpw, mph, pdx, pdy, px, py, pw, ph, @u0, nil, @u1) then
+      if sweepAABB(ox, oy, mpw, mph, pdx, pdy, px, py, pw, ph, @u0, @hedge, @u1) then
       begin
         //e_LogWritefln('T: platsweep; u0=%s; u1=%s; hedge=%s; sweepAABB(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)', [u0, u1, hedge, ox, oy, mpw, mph, pdx, pdy, px-1, py-1, pw+2, ph+2]);
         // yes, platform hits the entity, push the entity in the direction of the platform
@@ -580,26 +609,28 @@ var
           pan := mapGrid.traceBox(tex, tey, px, py, pw, ph, pdx, pdy, nil, trtag);
           //e_LogWritefln('  tracebox: te=(%s,%s)', [tex, tey]);
           // if we cannot move, only walls should squash the entity
+          {
           if ((tag and (GridTagWall or GridTagDoor)) <> 0) then
           begin
             if (pan <> nil) and (tex = px) and (tey = py) then squash := true;
           end;
+          }
         end;
       end
       else
       begin
         // no collistion, but may be embedded
         //e_LogWritefln('F: platsweep; u0=%s; u1=%s; sweepAABB(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)', [u0, u1, ox, oy, mpw, mph, pdx, pdy, px-1, py-1, pw+2, ph+2]);
-        squash := (u1 >= 0.0);
+        //squash := (u1 >= 0.0);
       end;
     end;
     dx := tex-px;
     dy := tey-py;
     result := (dx <> 0) or (dy <> 0);
-    if result and (not squash) and ((tag and (GridTagWall or GridTagDoor)) <> 0) then
+    if (not squash) and ((tag and (GridTagWall or GridTagDoor)) <> 0) then
     begin
       squash := g_Collide(tex, tey, pw, ph, nx, ny, mpw, mph); // still in platform?
-      if not squash then squash := g_Map_CollidePanel(tex, tey, pw, ph, (PANEL_WALL or PANEL_OPENDOOR or PANEL_CLOSEDOOR));
+      //if not squash then squash := g_Map_CollidePanel(tex, tey, pw, ph, (PANEL_WALL or PANEL_OPENDOOR or PANEL_CLOSEDOOR));
     end;
   end;
 
@@ -622,6 +653,8 @@ var
   mon: TMonster;
   mpfrid: LongWord;
   ontop: Boolean;
+  actMoveTrig: Boolean;
+  actSizeTrig: Boolean;
 begin
   if (not Enabled) or (Width < 1) or (Height < 1) then exit;
 
@@ -635,8 +668,14 @@ begin
     FCurFrameCount := FTextureIDs[FCurTexture].AnTex.CurrentCounter;
   end;
 
+  if not g_dbgpan_mplat_active then exit;
+
+  if not mMovingActive then exit;
+  if mMovingSpeed.isZero and mSizeSpeed.isZero then exit;
+
+  //TODO: write wall size change processing
+
   // moving platform?
-  if mMovingActive and (not mMovingSpeed.isZero) and g_dbgpan_mplat_active then
   begin
     (*
      * collect all monsters and players (aka entities) along the possible platform path
@@ -672,104 +711,149 @@ begin
     cw := cx1-cx0+1;
     ch := cy1-cy0+1;
 
-    // temporarily turn off this panel, so it won't interfere with collision checks
-    mapGrid.proxyEnabled[proxyId] := false;
-
-    // process players
-    for f := 0 to High(gPlayers) do
+    // process "obstacle" panels
+    if ((tag and GridTagObstacle) <> 0) then
     begin
-      plr := gPlayers[f];
-      if (plr = nil) or (not plr.alive) then continue;
-      plr.getMapBox(px, py, pw, ph);
-      if not g_Collide(px, py, pw, ph, cx0, cy0, cw, ch) then continue;
-      if tryMPlatMove(px, py, pw, ph, pdx, pdy, squash) then
+      // temporarily turn off this panel, so it won't interfere with collision checks
+      mapGrid.proxyEnabled[proxyId] := false;
+
+      // process players
+      for f := 0 to High(gPlayers) do
       begin
-        // set new position
-        plr.moveBy(pdx, pdy); // this will call `positionChanged()` for us
+        plr := gPlayers[f];
+        if (plr = nil) or (not plr.alive) then continue;
+        plr.getMapBox(px, py, pw, ph);
+        if not g_Collide(px, py, pw, ph, cx0, cy0, cw, ch) then continue;
+        if tryMPlatMove(px, py, pw, ph, pdx, pdy, squash) then
+        begin
+          // set new position
+          plr.moveBy(pdx, pdy); // this will call `positionChanged()` for us
+        end;
         // squash player, if necessary
         if squash then plr.Damage(15000, 0, 0, 0, HIT_TRAP);
       end;
-    end;
 
-    // process gibs
-    for f := 0 to High(gGibs) do
-    begin
-      gib := @gGibs[f];
-      if not gib.alive then continue;
-      gib.getMapBox(px, py, pw, ph);
-      if not g_Collide(px, py, pw, ph, cx0, cy0, cw, ch) then continue;
-      if tryMPlatMove(px, py, pw, ph, pdx, pdy, squash, @ontop) then
+      // process gibs
+      for f := 0 to High(gGibs) do
       begin
-        // set new position
-        gib.moveBy(pdx, pdy); // this will call `positionChanged()` for us
-        {
-        if ontop then
+        gib := @gGibs[f];
+        if not gib.alive then continue;
+        gib.getMapBox(px, py, pw, ph);
+        if not g_Collide(px, py, pw, ph, cx0, cy0, cw, ch) then continue;
+        if tryMPlatMove(px, py, pw, ph, pdx, pdy, squash, @ontop) then
         begin
-          gib.Obj.Vel.X += pdx;
-          gib.Obj.Vel.Y += pdy;
+          // set new position
+          gib.moveBy(pdx, pdy); // this will call `positionChanged()` for us
+          {
+          if ontop then
+          begin
+            gib.Obj.Vel.X += pdx;
+            gib.Obj.Vel.Y += pdy;
+          end;
+          }
         end;
-        }
       end;
-    end;
 
-    // move and push corpses
-    for f := 0 to High(gCorpses) do
-    begin
-      cor := gCorpses[f];
-      if (cor = nil) then continue;
-      cor.getMapBox(px, py, pw, ph);
-      if not g_Collide(px, py, pw, ph, cx0, cy0, cw, ch) then continue;
-      if tryMPlatMove(px, py, pw, ph, pdx, pdy, squash, @ontop) then
+      // move and push corpses
+      for f := 0 to High(gCorpses) do
       begin
-        // set new position
-        cor.moveBy(pdx, pdy); // this will call `positionChanged()` for us
-        {
-        if ontop then
+        cor := gCorpses[f];
+        if (cor = nil) then continue;
+        cor.getMapBox(px, py, pw, ph);
+        if not g_Collide(px, py, pw, ph, cx0, cy0, cw, ch) then continue;
+        if tryMPlatMove(px, py, pw, ph, pdx, pdy, squash, @ontop) then
         begin
-          cor.ObjPtr.Vel.X += pdx;
-          cor.ObjPtr.Vel.Y += pdy;
+          // set new position
+          cor.moveBy(pdx, pdy); // this will call `positionChanged()` for us
+          {
+          if ontop then
+          begin
+            cor.ObjPtr.Vel.X += pdx;
+            cor.ObjPtr.Vel.Y += pdy;
+          end;
+          }
         end;
-        }
       end;
-    end;
 
-    // collect monsters
-    monCheckListUsed := 0;
-    g_Mons_ForEachAt(cx0, cy0, cw, ch, monCollect);
+      // collect monsters
+      monCheckListUsed := 0;
+      g_Mons_ForEachAt(cx0, cy0, cw, ch, monCollect);
 
-    // process collected monsters
-    if (monCheckListUsed > 0) then
-    begin
-      mpfrid := g_Mons_getNewMPlatFrameId();
-      for f := 0 to monCheckListUsed do
+      // process collected monsters
+      if (monCheckListUsed > 0) then
       begin
-        mon := monCheckList[f];
-        if (mon = nil) or (not mon.alive) or (mon.mplatCheckFrameId = mpfrid) then continue;
-        mon.mplatCheckFrameId := mpfrid;
-        mon.getMapBox(px, py, pw, ph);
-        //if not g_Collide(px, py, pw, ph, cx0, cy0, cw, ch) then continue;
-        if tryMPlatMove(px, py, pw, ph, pdx, pdy, squash) then
+        mpfrid := g_Mons_getNewMPlatFrameId();
+        for f := 0 to monCheckListUsed do
         begin
-          // set new position
-          mon.moveBy(pdx, pdy); // this will call `positionChanged()` for us
+          mon := monCheckList[f];
+          if (mon = nil) or (not mon.alive) or (mon.mplatCheckFrameId = mpfrid) then continue;
+          mon.mplatCheckFrameId := mpfrid;
+          mon.getMapBox(px, py, pw, ph);
+          //if not g_Collide(px, py, pw, ph, cx0, cy0, cw, ch) then continue;
+          if tryMPlatMove(px, py, pw, ph, pdx, pdy, squash) then
+          begin
+            // set new position
+            mon.moveBy(pdx, pdy); // this will call `positionChanged()` for us
+          end;
           // squash player, if necessary
           if squash then mon.Damage(15000, 0, 0, 0, HIT_TRAP);
         end;
       end;
+
+      // restore panel state
+      mapGrid.proxyEnabled[proxyId] := true;
     end;
 
-    // restore panel state
-    mapGrid.proxyEnabled[proxyId] := true;
-    // and really move it
+    // move panel
     X := nx;
     Y := ny;
+    FWidth += mSizeSpeed.w;
+    FHeight += mSizeSpeed.h;
     positionChanged();
 
+    actMoveTrig := false;
+    actSizeTrig := false;
+
+    {
+    if not mSizeSpeed.isZero then
+    begin
+      e_LogWritefln('ss: size_speed=(%s,%s); size=(%s,%s); move_speed=(%s,%s); oy=%s; ny=%s; etp:%s; ets:%s', [mSizeSpeed.w, mSizeSpeed.h, FWidth, FHeight, mMovingSpeed.X, mMovingSpeed.Y, oy, ny, mEndPosTrig, mEndSizeTrig]);
+    end;
+    }
+
     // 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;
+    if ((mMovingSpeed.X < 0) and (nx <= mMovingStart.X)) or ((mMovingSpeed.X > 0) and (nx >= mMovingEnd.X)) then
+    begin
+      if mMoveOnce then mMovingActive := false else mMovingSpeed.X := -mMovingSpeed.X;
+      actMoveTrig := true;
+    end;
+
+    if ((mMovingSpeed.Y < 0) and (ny <= mMovingStart.Y)) or ((mMovingSpeed.Y > 0) and (ny >= mMovingEnd.Y)) then
+    begin
+      if mMoveOnce then mMovingActive := false else mMovingSpeed.Y := -mMovingSpeed.Y;
+      actMoveTrig := true;
+    end;
+
+    // check "size stop"
+    if not mSizeSpeed.isZero and (Width = mSizeEnd.w) and (Height = mSizeEnd.h) then
+    begin
+      mSizeSpeed.w := 0;
+      mSizeSpeed.h := 0;
+      actSizeTrig := true;
+      if (Width < 1) or (Height < 1) then mMovingActive := false; //HACK!
+      //e_LogWritefln('FUUUUUUUUUUUUUU', []);
+    end;
+
+
+    if actMoveTrig then
+    begin
+      g_Triggers_Press(mEndPosTrig, ACTIVATE_CUSTOM);
+    end;
+
+    if actSizeTrig then
+    begin
+      g_Triggers_Press(mEndSizeTrig, ACTIVATE_CUSTOM);
+    end;
   end;
 end;
 
index 2da3a1e8dcdb267c264d22ef5fbd916845927085..97648af9e91d01cbbf3bdec3123aa363864d80fc 100644 (file)
@@ -2608,6 +2608,7 @@ end;
 
 procedure g_Triggers_Press(ID: DWORD; ActivateType: Byte; ActivateUID: Word = 0);
 begin
+  if (ID >= Length(gTriggers)) then exit;
   gTriggers[ID].ActivateUID := ActivateUID;
   ActivateTrigger(gTriggers[ID], ActivateType);
 end;
index e77934cbb8892120c7fa6e93b5dbf7ececb619c1..0cf15d68e7496a62fe4389700811d9bd2dec47b1 100644 (file)
@@ -40,6 +40,7 @@ var
   gwin_dump_extensions: Boolean = false;
   gwin_has_stencil: Boolean = false;
   gwin_k8_enable_light_experiments: Boolean = false;
+  g_dbg_aimline_on: Boolean = false;
 
 
 implementation
@@ -872,6 +873,10 @@ begin
     if arg = '--no-particle-phys' then gpart_dbg_phys_enabled := false;
     if arg = '--no-particle-physics' then gpart_dbg_phys_enabled := false;
 
+    {$IF DEFINED(D2F_DEBUG)}
+    if arg = '--aimline' then g_dbg_aimline_on := false;
+    {$ENDIF}
+
     if arg = '--holmes' then begin g_holmes_enabled := true; g_Game_SetDebugMode(); end;
     if (arg = '--holmes-ui-scale') or (arg = '-holmes-ui-scale') then
     begin
index 4a27ccfa1b675d8820166afd52c231f3ef7325b1..591eadbc4ec71a5754428347ccd1940cda449d15 100644 (file)
@@ -54,9 +54,14 @@ TPanelRec_1 is "panel" size 18 bytes binblock 2 {
   Flags is "flags" type ubyte offset 17 bitset PanelFlag default PANEL_FLAG_NONE omitdefault;
   // moving platform options, not in binary
   MoveSpeed is "move_speed" type point default (0 0) omitdefault;
+  SizeSpeed is "size_speed" type point default (0 0) omitdefault; // alas, `size` cannot be negative
   MoveStart is "move_start" type point default (0 0) omitdefault;
   MoveEnd is "move_end" type point default (0 0) omitdefault;
+  SizeEnd is "size_end" type size default (0 0) omitdefault;
   MoveActive is "move_active" type bool default false omitdefault;
+  MoveOnce is "move_once" type bool default false omitdefault;
+  EndPosTrigger is "end_pos_trigger" type int trigger default null omitdefault;
+  EndSizeTrigger is "end_size_trigger" type int trigger default null omitdefault;
   // not in binary
   //Id is "id" type string default "" omitdefault;
   // internals
index ad160252dcc5877460d99f413785999aa8df791f..2e7ec96e8310ed7c6aa719e8729e5828068246ea 100644 (file)
@@ -44,6 +44,17 @@ type
     function isZero (): Boolean; inline;
   end;
 
+  TDFSize = packed record
+  public
+    w, h: LongInt;
+
+  public
+    constructor Create (aw, ah: LongInt);
+
+    function isZero (): Boolean; inline;
+    function isValid (): Boolean; inline;
+  end;
+
   Char16     = packed array[0..15] of Char;
   Char32     = packed array[0..31] of Char;
   Char64     = packed array[0..63] of Char;
@@ -70,6 +81,7 @@ type
     function getPanelIndex (pan: TDynRecord): Integer;
 
     function getPointField (const aname: AnsiString): TDFPoint; inline;
+    function getSizeField (const aname: AnsiString): TDFSize; inline;
 
   public
     function panelCount (): Integer; inline;
@@ -96,6 +108,14 @@ type
     function moveStart (): TDFPoint; inline;
     function moveEnd (): TDFPoint; inline;
 
+    function moveOnce (): Boolean; inline;
+
+    function sizeSpeed (): TDFSize; inline;
+    function sizeEnd (): TDFSize; inline;
+
+    function endPosTrig (): Integer; inline;
+    function endSizeTrig (): Integer; inline;
+
     // texture
     function Resource (): AnsiString; inline;
     function Anim (): Boolean; inline;
@@ -155,6 +175,11 @@ constructor TDFPoint.Create (ax, ay: LongInt); begin X := ax; Y := ay; end;
 function TDFPoint.isZero (): Boolean; inline; begin result := (X = 0) and (Y = 0); end;
 
 
+constructor TDFSize.Create (aw, ah: LongInt); begin w := aw; h := ah; end;
+function TDFSize.isZero (): Boolean; inline; begin result := (w = 0) and (h = 0); end;
+function TDFSize.isValid (): Boolean; inline; begin result := (w > 0) and (h > 0); end;
+
+
 // ////////////////////////////////////////////////////////////////////////// //
 function TDynRecordHelper.getUserPanelId (): Integer; inline;
 var
@@ -193,6 +218,28 @@ function TDynRecordHelper.moveSpeed (): TDFPoint; inline; begin result := getPoi
 function TDynRecordHelper.moveStart (): TDFPoint; inline; begin result := getPointField('move_start'); end;
 function TDynRecordHelper.moveEnd (): TDFPoint; inline; begin result := getPointField('move_end'); end;
 
+function TDynRecordHelper.sizeSpeed (): TDFSize; inline; begin result := getSizeField('size_speed'); end;
+function TDynRecordHelper.sizeEnd (): TDFSize; inline; begin result := getSizeField('size_end'); end;
+
+function TDynRecordHelper.moveOnce (): Boolean; inline; begin result := (getFieldWithType('move_once', TDynField.TType.TBool).ival <> 0); end;
+
+
+function TDynRecordHelper.endPosTrig (): Integer; inline;
+var
+  fld: TDynField;
+begin
+  fld := getFieldWithType('end_pos_trigger', TDynField.TType.TInt);
+  result := fld.recrefIndex;
+end;
+
+function TDynRecordHelper.endSizeTrig (): Integer; inline;
+var
+  fld: TDynField;
+begin
+  fld := getFieldWithType('end_size_trigger', TDynField.TType.TInt);
+  result := fld.recrefIndex;
+end;
+
 
 // ////////////////////////////////////////////////////////////////////////// //
 function TDynRecordHelper.getFieldWithType (const aname: AnsiString; atype: TDynField.TType): TDynField; inline;
@@ -214,6 +261,17 @@ begin
 end;
 
 
+function TDynRecordHelper.getSizeField (const aname: AnsiString): TDFSize; inline;
+var
+  fld: TDynField;
+begin
+  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 <> TSize) and (fld.baseType <> TPoint) then raise Exception.Create(Format('field ''%s'' in record ''%s'' of type ''%s'' has invalid data type', [aname, name, id]));
+  result := TDFSize.Create(fld.ival, fld.ival2);
+end;
+
+
 function TDynRecordHelper.getPanelByIdx (idx: Integer): TDynRecord; inline;
 var
   fld: TDynField;
index b74ebfc9dcb93ab110655d97cd365a27c2e75a36..c4ab9848657502190c5eb86bd968c83c52efcde6 100644 (file)
@@ -379,28 +379,47 @@ const defaultMapDef: AnsiString = ''+
   #10#32#32#77#111#118#101#83#112#101#101#100#32#105#115#32#34#109#111#118#101+
   #95#115#112#101#101#100#34#32#116#121#112#101#32#112#111#105#110#116#32#100+
   #101#102#97#117#108#116#32#40#48#32#48#41#32#111#109#105#116#100#101#102#97+
-  #117#108#116#59#10#32#32#77#111#118#101#83#116#97#114#116#32#105#115#32#34+
-  #109#111#118#101#95#115#116#97#114#116#34#32#116#121#112#101#32#112#111#105+
+  #117#108#116#59#10#32#32#83#105#122#101#83#112#101#101#100#32#105#115#32#34+
+  #115#105#122#101#95#115#112#101#101#100#34#32#116#121#112#101#32#112#111#105+
   #110#116#32#100#101#102#97#117#108#116#32#40#48#32#48#41#32#111#109#105#116+
-  #100#101#102#97#117#108#116#59#10#32#32#77#111#118#101#69#110#100#32#105#115+
-  #32#34#109#111#118#101#95#101#110#100#34#32#116#121#112#101#32#112#111#105+
-  #110#116#32#100#101#102#97#117#108#116#32#40#48#32#48#41#32#111#109#105#116+
-  #100#101#102#97#117#108#116#59#10#32#32#77#111#118#101#65#99#116#105#118#101+
-  #32#105#115#32#34#109#111#118#101#95#97#99#116#105#118#101#34#32#116#121#112+
-  #101#32#98#111#111#108#32#100#101#102#97#117#108#116#32#102#97#108#115#101+
-  #32#111#109#105#116#100#101#102#97#117#108#116#59#10#32#32#47#47#32#110#111+
-  #116#32#105#110#32#98#105#110#97#114#121#10#32#32#47#47#73#100#32#105#115#32+
-  #34#105#100#34#32#116#121#112#101#32#115#116#114#105#110#103#32#100#101#102+
-  #97#117#108#116#32#34#34#32#111#109#105#116#100#101#102#97#117#108#116#59#10+
-  #32#32#47#47#32#105#110#116#101#114#110#97#108#115#10#32#32#80#97#110#73#100+
-  #120#32#105#115#32#34#112#97#110#105#100#120#34#32#116#121#112#101#32#117+
-  #105#110#116#32#105#110#116#101#114#110#97#108#59#10#125#10#10#84#73#116#101+
-  #109#82#101#99#95#49#32#105#115#32#34#105#116#101#109#34#32#115#105#122#101+
-  #32#49#48#32#98#121#116#101#115#32#98#105#110#98#108#111#99#107#32#51#32#123+
-  #10#32#32#47#47#88#32#105#115#32#34#120#34#32#116#121#112#101#32#105#110#116+
-  #32#111#102#102#115#101#116#32#48#59#10#32#32#47#47#89#32#105#115#32#34#121+
-  #34#32#116#121#112#101#32#105#110#116#32#111#102#102#115#101#116#32#52#59#10+
-  #32#32#80#111#115#32#105#115#32#34#112#111#115#105#116#105#111#110#34#32#116+
+  #100#101#102#97#117#108#116#59#32#47#47#32#97#108#97#115#44#32#96#115#105+
+  #122#101#96#32#99#97#110#110#111#116#32#98#101#32#110#101#103#97#116#105#118+
+  #101#10#32#32#77#111#118#101#83#116#97#114#116#32#105#115#32#34#109#111#118+
+  #101#95#115#116#97#114#116#34#32#116#121#112#101#32#112#111#105#110#116#32+
+  #100#101#102#97#117#108#116#32#40#48#32#48#41#32#111#109#105#116#100#101#102+
+  #97#117#108#116#59#10#32#32#77#111#118#101#69#110#100#32#105#115#32#34#109+
+  #111#118#101#95#101#110#100#34#32#116#121#112#101#32#112#111#105#110#116#32+
+  #100#101#102#97#117#108#116#32#40#48#32#48#41#32#111#109#105#116#100#101#102+
+  #97#117#108#116#59#10#32#32#83#105#122#101#69#110#100#32#105#115#32#34#115+
+  #105#122#101#95#101#110#100#34#32#116#121#112#101#32#115#105#122#101#32#100+
+  #101#102#97#117#108#116#32#40#48#32#48#41#32#111#109#105#116#100#101#102#97+
+  #117#108#116#59#10#32#32#77#111#118#101#65#99#116#105#118#101#32#105#115#32+
+  #34#109#111#118#101#95#97#99#116#105#118#101#34#32#116#121#112#101#32#98#111+
+  #111#108#32#100#101#102#97#117#108#116#32#102#97#108#115#101#32#111#109#105+
+  #116#100#101#102#97#117#108#116#59#10#32#32#77#111#118#101#79#110#99#101#32+
+  #105#115#32#34#109#111#118#101#95#111#110#99#101#34#32#116#121#112#101#32#98+
+  #111#111#108#32#100#101#102#97#117#108#116#32#102#97#108#115#101#32#111#109+
+  #105#116#100#101#102#97#117#108#116#59#10#32#32#69#110#100#80#111#115#84#114+
+  #105#103#103#101#114#32#105#115#32#34#101#110#100#95#112#111#115#95#116#114+
+  #105#103#103#101#114#34#32#116#121#112#101#32#105#110#116#32#116#114#105#103+
+  #103#101#114#32#100#101#102#97#117#108#116#32#110#117#108#108#32#111#109#105+
+  #116#100#101#102#97#117#108#116#59#10#32#32#69#110#100#83#105#122#101#84#114+
+  #105#103#103#101#114#32#105#115#32#34#101#110#100#95#115#105#122#101#95#116+
+  #114#105#103#103#101#114#34#32#116#121#112#101#32#105#110#116#32#116#114#105+
+  #103#103#101#114#32#100#101#102#97#117#108#116#32#110#117#108#108#32#111#109+
+  #105#116#100#101#102#97#117#108#116#59#10#32#32#47#47#32#110#111#116#32#105+
+  #110#32#98#105#110#97#114#121#10#32#32#47#47#73#100#32#105#115#32#34#105#100+
+  #34#32#116#121#112#101#32#115#116#114#105#110#103#32#100#101#102#97#117#108+
+  #116#32#34#34#32#111#109#105#116#100#101#102#97#117#108#116#59#10#32#32#47+
+  #47#32#105#110#116#101#114#110#97#108#115#10#32#32#80#97#110#73#100#120#32+
+  #105#115#32#34#112#97#110#105#100#120#34#32#116#121#112#101#32#117#105#110+
+  #116#32#105#110#116#101#114#110#97#108#59#10#125#10#10#84#73#116#101#109#82+
+  #101#99#95#49#32#105#115#32#34#105#116#101#109#34#32#115#105#122#101#32#49+
+  #48#32#98#121#116#101#115#32#98#105#110#98#108#111#99#107#32#51#32#123#10#32+
+  #32#47#47#88#32#105#115#32#34#120#34#32#116#121#112#101#32#105#110#116#32+
+  #111#102#102#115#101#116#32#48#59#10#32#32#47#47#89#32#105#115#32#34#121#34+
+  #32#116#121#112#101#32#105#110#116#32#111#102#102#115#101#116#32#52#59#10#32+
+  #32#80#111#115#32#105#115#32#34#112#111#115#105#116#105#111#110#34#32#116+
   #121#112#101#32#112#111#105#110#116#32#111#102#102#115#101#116#32#48#32#97+
   #115#32#120#121#59#10#32#32#73#116#101#109#84#121#112#101#32#105#115#32#34+
   #116#121#112#101#34#32#116#121#112#101#32#117#98#121#116#101#32#111#102#102+
index d82867e7d504dd34ad0d1a152a9ffe7a872069d6..15040f8acc1d0dfa984a40de623192043617c9a9 100644 (file)
@@ -1647,9 +1647,17 @@ begin
           else
           begin
             rec := mOwner.findRecordByTypeId(mEBSTypeName, pr.tokStr);
-            if (rec = nil) then raise Exception.Create(Format('record ''%s'' (%s) value for field ''%s'' not found', [pr.tokStr, mEBSTypeName, mName]));
+            if (rec = nil) then
+            begin
+              //raise Exception.Create(Format('record ''%s'' (%s) value for field ''%s'' not found', [pr.tokStr, mEBSTypeName, mName]));
+              mRecRefId := pr.tokStr;
+            end
+            else
+            begin
+              mRecRef := rec;
+              mRecRefId := '';
+            end;
             pr.expectId();
-            mRecRef := rec;
           end;
           mDefined := true;
           pr.expectTT(pr.TTSemi);
@@ -2634,6 +2642,40 @@ var
   {$IF DEFINED(D2D_DYNREC_PROFILER)}
   stt, stall: UInt64;
   {$ENDIF}
+
+  procedure linkNames (rec: TDynRecord);
+  var
+    fld: TDynField;
+    rt: TDynRecord;
+  begin
+    //writeln('*** rec: ', rec.mName, '.', rec.mId, ' (', rec.mFields.count, ')');
+    for fld in rec.mFields do
+    begin
+      if (fld.mType = TDynField.TType.TTrigData) then
+      begin
+        if (fld.mRecRef <> nil) then linkNames(fld.mRecRef);
+        continue;
+      end;
+      if (Length(fld.mRecRefId) = 0) then continue;
+      assert(fld.mEBSType <> nil);
+      rt := findRecordByTypeId(fld.mEBSTypeName, fld.mRecRefId);
+      if (rt = nil) then
+      begin
+        e_LogWritefln('record of type ''%s'' with id ''%s'' links to inexistant record of type ''%s'' with id ''%s''', [rec.mName, rec.mId, fld.mEBSTypeName, fld.mRecRefId], MSG_WARNING);
+        //raise Exception.Create(Format('record of type ''%s'' with id ''%s'' links to inexistant record of type ''%s'' with id ''%s''', [rec.mName, rec.mId, fld.mEBSTypeName, fld.mRecRefId]));
+      end;
+      //writeln(' ', rec.mName, '.', rec.mId, ':', fld.mName, ' -> ', rt.mName, '.', rt.mId, ' (', fld.mEBSTypeName, '.', fld.mRecRefId, ')');
+      fld.mRecRefId := '';
+      fld.mRecRef := rt;
+      fld.mDefined := true;
+    end;
+    for fld in rec.mFields do
+    begin
+      //writeln('  ', fld.mName);
+      fld.fixDefaultValue(); // just in case
+    end;
+  end;
+
 begin
   if (mOwner = nil) then raise Exception.Create(Format('can''t parse record ''%s'' value without owner', [mName]));
 
@@ -2724,6 +2766,17 @@ begin
     raise Exception.Create(Format('unknown field ''%s'' in record ''%s''', [pr.tokStr, mName]));
   end;
   pr.expectTT(pr.TTEnd);
+
+  if mHeader then
+  begin
+    // link fields
+    for fld in mFields do
+    begin
+      if (fld.mType <> TDynField.TType.TList) then continue;
+      for rec in fld.mRVal do linkNames(rec);
+    end;
+  end;
+
   // fix field defaults
   {$IF DEFINED(D2D_DYNREC_PROFILER)}stt := curTimeMicro();{$ENDIF}
   for fld in mFields do fld.fixDefaultValue();
@@ -3115,7 +3168,7 @@ begin
     result := res;
     res := nil;
   finally
-    res.Free();
+    //TMP:segfaults! res.Free();
   end;
 end;