DEADSOFTWARE

FPC3.2.0 compat patch by deaddoomer
[d2df-sdl.git] / src / shared / MAPDEF.pas
index 15203525aaa81bfdbda94270df10e0e77541961a..5316d010f6a7875df557254d7ea4df71b3d35136 100644 (file)
@@ -1,9 +1,8 @@
-(* Copyright (C)  DooM 2D:Forever Developers
+(* Copyright (C)  Doom 2D: Forever Developers
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
+ * the Free Software Foundation, version 3 of the License ONLY.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * 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 a_modes.inc}
+{$M+}
 unit MAPDEF;
 
-{
------------------------------------
-MAPDEF.PAS ÂÅÐÑÈß ÎÒ 22.03.09
-
-Ïîääåðæêà êàðò âåðñèè 1
------------------------------------
-}
-
 interface
 
 uses
-  MAPSTRUCT;
+  xdynrec;
+
 
 const
-  PANEL_NONE      = 0;
-  PANEL_WALL      = 1;
-  PANEL_BACK      = 2;
-  PANEL_FORE      = 4;
-  PANEL_WATER     = 8;
-  PANEL_ACID1     = 16;
-  PANEL_ACID2     = 32;
-  PANEL_STEP      = 64;
-  PANEL_LIFTUP    = 128;
-  PANEL_LIFTDOWN  = 256;
-  PANEL_OPENDOOR  = 512;
-  PANEL_CLOSEDOOR = 1024;
-  PANEL_BLOCKMON  = 2048;
-  PANEL_LIFTLEFT  = 4096;
-  PANEL_LIFTRIGHT = 8192;
-
-  PANEL_FLAG_BLENDING      = 1;
-  PANEL_FLAG_HIDE          = 2;
-  PANEL_FLAG_WATERTEXTURES = 4;
-
-  EFFECT_NONE     = 0;
-  EFFECT_TELEPORT = 1;
-  EFFECT_RESPAWN  = 2;
-  EFFECT_FIRE     = 3;
-
-  ITEM_NONE                  = 0;
-  ITEM_MEDKIT_SMALL          = 1;
-  ITEM_MEDKIT_LARGE          = 2;
-  ITEM_MEDKIT_BLACK          = 3;
-  ITEM_ARMOR_GREEN           = 4;
-  ITEM_ARMOR_BLUE            = 5;
-  ITEM_SPHERE_BLUE           = 6;
-  ITEM_SPHERE_WHITE          = 7;
-  ITEM_SUIT                  = 8;
-  ITEM_OXYGEN                = 9;
-  ITEM_INVUL                 = 10;
-  ITEM_WEAPON_SAW            = 11;
-  ITEM_WEAPON_SHOTGUN1       = 12;
-  ITEM_WEAPON_SHOTGUN2       = 13;
-  ITEM_WEAPON_CHAINGUN       = 14;
-  ITEM_WEAPON_ROCKETLAUNCHER = 15;
-  ITEM_WEAPON_PLASMA         = 16;
-  ITEM_WEAPON_BFG            = 17;
-  ITEM_WEAPON_SUPERPULEMET   = 18;
-  ITEM_AMMO_BULLETS          = 19;
-  ITEM_AMMO_BULLETS_BOX      = 20;
-  ITEM_AMMO_SHELLS           = 21;
-  ITEM_AMMO_SHELLS_BOX       = 22;
-  ITEM_AMMO_ROCKET           = 23;
-  ITEM_AMMO_ROCKET_BOX       = 24;
-  ITEM_AMMO_CELL             = 25;
-  ITEM_AMMO_CELL_BIG         = 26;
-  ITEM_AMMO_BACKPACK         = 27;
-  ITEM_KEY_RED               = 28;
-  ITEM_KEY_GREEN             = 29;
-  ITEM_KEY_BLUE              = 30;
-  ITEM_WEAPON_KASTET         = 31;
-  ITEM_WEAPON_PISTOL         = 32;
-  ITEM_BOTTLE                = 33;
-  ITEM_HELMET                = 34;
-  ITEM_JETPACK               = 35;
-  ITEM_INVIS                 = 36;
-
-  ITEM_MAX                   = 36; // store the last item's id in here
-                                   // use this in for loops
-
-  ITEM_OPTION_ONLYDM = 1;
-  ITEM_OPTION_FALL   = 2;
-
-  AREA_NONE          = 0;
-  AREA_PLAYERPOINT1  = 1;
-  AREA_PLAYERPOINT2  = 2;
-  AREA_DMPOINT       = 3;
-  AREA_REDFLAG       = 4;
-  AREA_BLUEFLAG      = 5;
-  AREA_DOMFLAG       = 6;
-  AREA_REDTEAMPOINT  = 7;
-  AREA_BLUETEAMPOINT = 8;
-
-  MONSTER_NONE   = 0;
-  MONSTER_DEMON  = 1;
-  MONSTER_IMP    = 2;
-  MONSTER_ZOMBY  = 3;
-  MONSTER_SERG   = 4;
-  MONSTER_CYBER  = 5;
-  MONSTER_CGUN   = 6;
-  MONSTER_BARON  = 7;
-  MONSTER_KNIGHT = 8;
-  MONSTER_CACO   = 9;
-  MONSTER_SOUL   = 10;
-  MONSTER_PAIN   = 11;
-  MONSTER_SPIDER = 12;
-  MONSTER_BSP    = 13;
-  MONSTER_MANCUB = 14;
-  MONSTER_SKEL   = 15;
-  MONSTER_VILE   = 16;
-  MONSTER_FISH   = 17;
-  MONSTER_BARREL = 18;
-  MONSTER_ROBO   = 19;
-  MONSTER_MAN    = 20;
-
-  TRIGGER_NONE            = 0;
-  TRIGGER_EXIT            = 1;
-  TRIGGER_TELEPORT        = 2;
-  TRIGGER_OPENDOOR        = 3;
-  TRIGGER_CLOSEDOOR       = 4;
-  TRIGGER_DOOR            = 5;
-  TRIGGER_DOOR5           = 6;
-  TRIGGER_CLOSETRAP       = 7;
-  TRIGGER_TRAP            = 8;
-  TRIGGER_PRESS           = 9;
-  TRIGGER_SECRET          = 10;
-  TRIGGER_LIFTUP          = 11;
-  TRIGGER_LIFTDOWN        = 12;
-  TRIGGER_LIFT            = 13;
-  TRIGGER_TEXTURE         = 14;
-  TRIGGER_ON              = 15;
-  TRIGGER_OFF             = 16;
-  TRIGGER_ONOFF           = 17;
-  TRIGGER_SOUND           = 18;
-  TRIGGER_SPAWNMONSTER    = 19;
-  TRIGGER_SPAWNITEM       = 20;
-  TRIGGER_MUSIC           = 21;
-  TRIGGER_PUSH            = 22;
-  TRIGGER_SCORE           = 23;
-  TRIGGER_MESSAGE         = 24;
-  TRIGGER_DAMAGE          = 25;
-  TRIGGER_HEALTH          = 26;
-  TRIGGER_SHOT            = 27;
-  TRIGGER_EFFECT          = 28;
-  TRIGGER_SCRIPT          = 29;
-  TRIGGER_MAX             = 29;
-
-  TRIGGER_SHOT_PISTOL  = 0;
-  TRIGGER_SHOT_BULLET  = 1;
-  TRIGGER_SHOT_SHOTGUN = 2;
-  TRIGGER_SHOT_SSG     = 3;
-  TRIGGER_SHOT_IMP     = 4;
-  TRIGGER_SHOT_PLASMA  = 5;
-  TRIGGER_SHOT_SPIDER  = 6;
-  TRIGGER_SHOT_CACO    = 7;
-  TRIGGER_SHOT_BARON   = 8;
-  TRIGGER_SHOT_MANCUB  = 9;
-  TRIGGER_SHOT_REV     = 10;
-  TRIGGER_SHOT_ROCKET  = 11;
-  TRIGGER_SHOT_BFG     = 12;
-  TRIGGER_SHOT_EXPL    = 13;
-  TRIGGER_SHOT_BFGEXPL = 14;
-  TRIGGER_SHOT_MAX     = 14;
-
-  TRIGGER_SHOT_TARGET_NONE   = 0;
-  TRIGGER_SHOT_TARGET_MON    = 1;
-  TRIGGER_SHOT_TARGET_PLR    = 2;
-  TRIGGER_SHOT_TARGET_RED    = 3;
-  TRIGGER_SHOT_TARGET_BLUE   = 4;
-  TRIGGER_SHOT_TARGET_MONPLR = 5;
-  TRIGGER_SHOT_TARGET_PLRMON = 6;
-
-  TRIGGER_SHOT_AIM_DEFAULT   = 0;
-  TRIGGER_SHOT_AIM_ALLMAP    = 1;
-  TRIGGER_SHOT_AIM_TRACE     = 2;
-  TRIGGER_SHOT_AIM_TRACEALL  = 3;
-
-  TRIGGER_EFFECT_PARTICLE  = 0;
-  TRIGGER_EFFECT_ANIMATION = 1;
-
-  TRIGGER_EFFECT_SLIQUID = 0;
-  TRIGGER_EFFECT_LLIQUID = 1;
-  TRIGGER_EFFECT_DLIQUID = 2;
-  TRIGGER_EFFECT_BLOOD   = 3;
-  TRIGGER_EFFECT_SPARK   = 4;
-  TRIGGER_EFFECT_BUBBLE  = 5;
-  TRIGGER_EFFECT_MAX     = 5;
-
-  TRIGGER_EFFECT_POS_CENTER = 0;
-  TRIGGER_EFFECT_POS_AREA   = 1;
-
-  ACTIVATE_PLAYERCOLLIDE  = 1;
-  ACTIVATE_MONSTERCOLLIDE = 2;
-  ACTIVATE_PLAYERPRESS    = 4;
-  ACTIVATE_MONSTERPRESS   = 8;
-  ACTIVATE_SHOT           = 16;
-  ACTIVATE_NOMONSTER      = 32;
-  ACTIVATE_CUSTOM         = 255;
-
-  KEY_RED      = 1;
-  KEY_GREEN    = 2;
-  KEY_BLUE     = 4;
-  KEY_REDTEAM  = 8;
-  KEY_BLUETEAM = 16;
+  MAP_SIGNATURE = 'MAP';
 
+
+const
   TEXTURE_NAME_WATER = '_water_0';
   TEXTURE_NAME_ACID1 = '_water_1';
   TEXTURE_NAME_ACID2 = '_water_2';
 
-  TEXTURE_SPECIAL_WATER = DWORD(-1);
-  TEXTURE_SPECIAL_ACID1 = DWORD(-2);
-  TEXTURE_SPECIAL_ACID2 = DWORD(-3);
-  TEXTURE_NONE = DWORD(-4);
 
 type
-  TPoint = packed record
+  TDFPoint = packed record
+  public
     X, Y: LongInt;
+
+  public
+    constructor Create (ax, ay: LongInt);
+
+    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;
 
-  TTriggerData = record
-    case Byte of
-      0: (Default: Byte128);
-      TRIGGER_EXIT:         (MapName: Char16);
-      TRIGGER_TELEPORT:     (TargetPoint: TPoint;
-                             d2d_teleport: Boolean;
-                             silent_teleport: Boolean;
-                             TlpDir: Byte);
-      TRIGGER_OPENDOOR,
-      TRIGGER_CLOSEDOOR,
-      TRIGGER_DOOR,
-      TRIGGER_DOOR5,
-      TRIGGER_CLOSETRAP,
-      TRIGGER_TRAP,
-      TRIGGER_LIFTUP,
-      TRIGGER_LIFTDOWN,
-      TRIGGER_LIFT:         (PanelID: Integer;
-                             NoSound: Boolean;
-                             d2d_doors: Boolean);
-      TRIGGER_PRESS,
-      TRIGGER_ON,
-      TRIGGER_OFF,
-      TRIGGER_ONOFF:        (tX, tY: Integer;
-                             tWidth, tHeight: Word;
-                             Wait: Word;
-                             Count: Word;
-                             MonsterID: Integer;
-                             ExtRandom: Boolean);
-      TRIGGER_SECRET:       ();
-      TRIGGER_TEXTURE:      (ActivateOnce: Boolean;
-                             AnimOnce: Boolean);
-      TRIGGER_SOUND:        (SoundName: Char64;
-                             Volume: Byte;
-                             Pan: Byte;
-                             Local: Boolean;
-                             PlayCount: Byte;
-                             SoundSwitch: Boolean);
-      TRIGGER_SPAWNMONSTER: (MonPos: TPoint;
-                             MonType: Byte;
-                             MonHealth: Integer;
-                             MonDir: Byte;
-                             MonActive: Boolean;
-                             MonCount: Integer;
-                             MonEffect: Byte;
-                             MonMax: Word;
-                             MonDelay: Word;
-                             MonBehav: Byte);
-      TRIGGER_SPAWNITEM:    (ItemPos: TPoint;
-                             ItemType: Byte;
-                             ItemFalls: Boolean;
-                             ItemOnlyDM: Boolean;
-                             ItemCount: Integer;
-                             ItemEffect: Byte;
-                             ItemMax: Word;
-                             ItemDelay: Word);
-      TRIGGER_MUSIC:        (MusicName: Char64;
-                             MusicAction: Byte);
-      TRIGGER_PUSH:         (PushAngle: Word;
-                             PushForce: Byte;
-                             ResetVel: Boolean);
-      TRIGGER_SCORE:        (ScoreAction: Byte;
-                             ScoreCount: Byte;
-                             ScoreTeam: Byte;
-                             ScoreCon,
-                             ScoreMsg: Boolean);
-      TRIGGER_MESSAGE:      (MessageKind: Byte;
-                             MessageSendTo: Byte;
-                             MessageText: Char100;
-                             MessageTime: Word);
-      TRIGGER_DAMAGE:       (DamageValue: Word;
-                             DamageInterval: Word);
-      TRIGGER_HEALTH:       (HealValue: Word;
-                             HealInterval: Word;
-                             HealMax: Boolean;
-                             HealSilent: Boolean);
-      TRIGGER_SHOT:         (ShotPos: TPoint;
-                             ShotType: Byte;
-                             ShotTarget: Byte;
-                             ShotSound: Boolean;
-                             ShotAim: Byte;
-                             ShotPanelID: Integer;
-                             ShotIntSight: Word;
-                             ShotAngle: Word;
-                             ShotWait: Word;
-                             ShotAccuracy: Word;
-                             ShotAmmo: Word;
-                             ShotIntReload: Word);
-      TRIGGER_EFFECT:       (FXCount: Byte;
-                             FXType: Byte;
-                             FXSubType: Byte;
-                             FXColorR: Byte;
-                             FXColorG: Byte;
-                             FXColorB: Byte;
-                             FXPos: Byte;
-                             FXWait: Word;
-                             FXVelX: ShortInt;
-                             FXVelY: ShortInt;
-                             FXSpreadL: Byte;
-                             FXSpreadR: Byte;
-                             FXSpreadU: Byte;
-                             FXSpreadD: Byte);
-      TRIGGER_SCRIPT:       (SCRProc: Char64;
-                             SCRArg: Integer);
+  TDFColor = packed record
+  public
+    r, g, b, a: Byte; // a: 0 is transparent, 255 is opaque
+
+  public
+    constructor Create (ar, ag, ab: LongInt; aa: LongInt=0);
+
+    function isTransparent (): Boolean; inline;
+    function isOpaque (): Boolean; inline;
+    function isBlack (): Boolean; inline;
+    function isWhite (): Boolean; inline;
   end;
 
-{$INCLUDE mapstructsizes.inc}
+{$INCLUDE mapdef.inc}
+
+// various helpers to access map structures
+type
+  TDynFieldHelper = class helper for TDynField
+  public
+    function getRGBA (): TDFColor; inline;
+    procedure setRGBA (const v: TDFColor); inline;
+
+  public
+    property rgba: TDFColor read getRGBA write setRGBA; // for `TColor`
+  end;
+
+  TDynRecordHelper = class helper for TDynRecord
+  private
+    function getFieldWithType (const aname: AnsiString; atype: TDynField.TType): TDynField; inline;
+
+    function getPanelByIdx (idx: Integer): TDynRecord; inline;
+
+    function getTexturePanel (): Integer; inline;
+    function getTexturePanelRec (): TDynRecord; inline;
+
+    function getPanelIndex (pan: TDynRecord): Integer;
+
+    function getPointField (const aname: AnsiString): TDFPoint; inline;
+    function getSizeField (const aname: AnsiString): TDFSize; inline;
+
+  public
+    function panelCount (): Integer; inline;
+
+    // header
+    function mapName (): AnsiString; inline;
+    function mapAuthor (): AnsiString; inline;
+    function mapDesc (): AnsiString; inline;
+    function musicName (): AnsiString; inline;
+    function skyName (): AnsiString; inline;
+
+    // panel
+    function X (): Integer; inline;
+    function Y (): Integer; inline;
+    function Width (): Word; inline;
+    function Height (): Word; inline;
+    function TextureNum (): Word; inline;
+    function TextureRec (): TDynRecord; inline;
+    function PanelType (): Word; inline;
+    function Alpha (): Byte; inline;
+    function Flags (): Byte; inline;
+
+    function moveSpeed (): TDFPoint; inline;
+    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;
+
+    // item
+    function ItemType (): Byte; inline;
+    function Options (): Byte; inline;
+
+    // monster
+    function MonsterType (): Byte; inline; // type, ubyte
+    function Direction (): Byte; inline; // direction, ubyte
+
+    // area
+    function AreaType (): Byte; inline; // type, ubyte
+    //function Direction (): Byte; inline; // direction, ubyte
+
+    // trigger
+    function trigRec (): TDynRecord; {inline;}
+    function Enabled (): Boolean; inline; // enabled, bool
+    function TriggerType (): Byte; inline; // type, ubyte
+    function ActivateType (): Byte; inline; // activatetype, ubyte
+    function Keys (): Byte; inline; // keys, ubyte
+    //function DATA (): Byte128; inline; // triggerdata, trigdata[128]; // the only special nested structure
+
+    {$INCLUDE mapdef_help.inc}
+    function trigMonsterId (): Integer; inline;
+    function trigPanelId (): Integer; inline; // panel index in list
+    function trigPanelRec (): TDynRecord; inline;
+
+  private
+    // user fields
+    function getUserPanelId (): Integer; inline;
+    procedure setUserPanelId (v: Integer); inline;
+
+    function getUserTrigRef (): Boolean; inline;
+    procedure setUserTrigRef (v: Boolean); inline;
+
+  public
+    property panel[idx: Integer]: TDynRecord read getPanelByIdx;
+    property panelIndex[pan: TDynRecord]: Integer read getPanelIndex;
+    // triggers
+    property tgPanelId: Integer read trigPanelId;
+    property tgPanelRec: TDynRecord read trigPanelRec;
+    property TexturePanelId: Integer read getTexturePanel; // texturepanel, int
+    property TexturePanelRec: TDynRecord read getTexturePanelRec;
+    // user fields
+    property userPanelId: Integer read getUserPanelId write setUserPanelId;
+    property userPanelTrigRef: Boolean read getUserTrigRef write setUserTrigRef;
+  end;
 
 implementation
 
-uses SysUtils;
+uses
+  SysUtils, {e_log,} utils, xparser, xstreams;
+
+
+// ////////////////////////////////////////////////////////////////////////// //
+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;
+
+constructor TDFColor.Create (ar, ag, ab: LongInt; aa: LongInt=0);
+begin
+  if (ar < 0) then r := 0 else if (ar > 255) then r := 255 else r := Byte(ar);
+  if (ag < 0) then g := 0 else if (ag > 255) then g := 255 else g := Byte(ag);
+  if (ab < 0) then b := 0 else if (ab > 255) then b := 255 else b := Byte(ab);
+  if (aa < 0) then a := 0 else if (aa > 255) then a := 255 else a := Byte(aa);
+end;
+function TDFColor.isTransparent (): Boolean; inline; begin result := (a = 0); end;
+function TDFColor.isOpaque (): Boolean; inline; begin result := (a = 255); end;
+function TDFColor.isBlack (): Boolean; inline; begin result := (r = 0) and (g = 0) and (b = 0); end;
+function TDFColor.isWhite (): Boolean; inline; begin result := (r = 255) and (g = 255) and (b = 255); end;
+
+
+// ////////////////////////////////////////////////////////////////////////// //
+function TDynFieldHelper.getRGBA (): TDFColor; inline; begin result := TDFColor.Create(red, green, blue, alpha); end;
+procedure TDynFieldHelper.setRGBA (const v: TDFColor); inline; begin red := v.r; green := v.g; blue := v.b; alpha := v.a; end;
+
+
+// ////////////////////////////////////////////////////////////////////////// //
+function TDynRecordHelper.getUserPanelId (): Integer; inline;
+var
+  fld: TDynField;
+begin
+  fld := field['userPanelId'];
+  //if (fld = nil) or (fld.baseType <> TDynField.TType.TInt) then result := -1 else result := fld.ival;
+  if (fld = nil) then result := -1 else result := Integer(fld.value);
+end;
+
+
+procedure TDynRecordHelper.setUserPanelId (v: Integer); inline;
+begin
+  user['userPanelId'] := v;
+end;
+
+
+function TDynRecordHelper.getUserTrigRef (): Boolean; inline;
+var
+  fld: TDynField;
+begin
+  fld := field['userPanelTrigRef'];
+  if (fld = nil) then result := false else result := Boolean(fld.value);
+  //if (fld = nil) or (fld.baseType <> TDynField.TType.TBool) then result := false else result := (fld.ival <> 0);
+end;
+
+
+procedure TDynRecordHelper.setUserTrigRef (v: Boolean); inline;
+begin
+  user['userPanelTrigRef'] := v;
+end;
+
+
+// ////////////////////////////////////////////////////////////////////////// //
+function TDynRecordHelper.moveSpeed (): TDFPoint; inline; begin result := getPointField('move_speed'); end;
+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;
+begin
+  result := field[aname];
+  if (result = nil) then raise Exception.Create(Format('field ''%s'' not found in record ''%s'' of type ''%s''', [aname, typeName, id]));
+  if (result.baseType <> atype) then raise Exception.Create(Format('field ''%s'' in record ''%s'' of type ''%s'' has invalid data type', [aname, typeName, id]));
+end;
+
+
+function TDynRecordHelper.getPointField (const aname: AnsiString): TDFPoint; 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, typeName, id]));
+  if (fld.baseType <> fld.TType.TPoint) then raise Exception.Create(Format('field ''%s'' in record ''%s'' of type ''%s'' has invalid data type', [aname, typeName, id]));
+  result := TDFPoint.Create(fld.ival, fld.ival2);
+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, typeName, id]));
+  if (fld.baseType <> fld.TType.TSize) and (fld.baseType <> fld.TType.TPoint) then raise Exception.Create(Format('field ''%s'' in record ''%s'' of type ''%s'' has invalid data type', [aname, typeName, id]));
+  result := TDFSize.Create(fld.ival, fld.ival2);
+end;
+
+
+function TDynRecordHelper.getPanelByIdx (idx: Integer): TDynRecord; inline;
+var
+  fld: TDynField;
+begin
+  fld := headerRec['panel'];
+  if (fld <> nil) then result := fld.itemAt[idx] else result := nil;
+end;
+
+
+function TDynRecordHelper.getPanelIndex (pan: TDynRecord): Integer;
+var
+  fld: TDynField;
+  f: Integer;
+begin
+  result := -1;
+  if (pan <> nil) then
+  begin
+    fld := headerRec['panel'];
+    if (fld <> nil) then
+    begin
+      for f := 0 to fld.count-1 do if (fld.itemAt[f] = pan) then begin result := f; exit; end;
+    end;
+  end;
+end;
+
+
+function TDynRecordHelper.panelCount (): Integer; inline;
+var
+  fld: TDynField;
+begin
+  fld := headerRec['panel'];
+  if (fld <> nil) then result := fld.count else result := 0;
+end;
+
+
+function TDynRecordHelper.TextureNum (): Word; inline;
+var
+  idx: Integer;
+  fld: TDynField;
+begin
+  fld := getFieldWithType('texture', TDynField.TType.TUShort);
+  idx := fld.recrefIndex;
+  if (idx < 0) then result := Word(TEXTURE_NONE) else result := Word(idx);
+end;
+
+
+// ////////////////////////////////////////////////////////////////////////// //
+// trigger
+function TDynRecordHelper.trigRec (): TDynRecord; {inline;}
+var
+  fld: TDynField;
+begin
+  fld := getFieldWithType('triggerdata', TDynField.TType.TTrigData);
+  if (fld <> nil) then result := fld.recref else result := nil;
+end;
+
+function TDynRecordHelper.trigMonsterId (): Integer; inline;
+var
+  fld: TDynField;
+begin
+  result := -1;
+  fld := field['monsterid'];
+  if (fld = nil) then exit;
+  if (fld.baseType <> TDynField.TType.TInt) then exit;
+  if (fld.recref = nil) then exit;
+  result := fld.recrefIndex;
+end;
+
+function TDynRecordHelper.trigPanelRec (): TDynRecord; inline;
+var
+  fld: TDynField;
+begin
+  result := nil;
+  fld := field['panelid'];
+  if (fld = nil) then exit;
+  if (fld.baseType <> TDynField.TType.TInt) then exit;
+  result := fld.recref;
+  if (result <> nil) and (result.typeName <> 'panel') then result := nil;
+end;
+
+// panel index in list
+function TDynRecordHelper.trigPanelId (): Integer; inline;
+var
+  fld: TDynField;
+begin
+  result := -1;
+  fld := field['panelid'];
+  if (fld = nil) then exit;
+  if (fld.baseType <> TDynField.TType.TInt) then exit;
+  if (fld.recref = nil) then exit;
+  if (fld.recref.typeName <> 'panel') then exit;
+  result := fld.recrefIndex;
+end;
+
+function TDynRecordHelper.getTexturePanelRec (): TDynRecord;
+var
+  fld: TDynField;
+begin
+  result := nil;
+  fld := field['texture_panel'];
+  if (fld = nil) then exit;
+  if (fld.baseType <> TDynField.TType.TInt) then exit;
+  result := fld.recref;
+  if (result <> nil) and (result.typeName <> 'panel') then result := nil;
+end;
+
+function TDynRecordHelper.getTexturePanel (): Integer;
+var
+  fld: TDynField;
+begin
+  result := -1;
+  fld := field['texture_panel'];
+  if (fld = nil) then exit;
+  if (fld.baseType <> TDynField.TType.TInt) then exit;
+  if (fld.recref = nil) then exit;
+  if (fld.recref.typeName <> 'panel') then exit;
+  result := fld.recrefIndex;
+end;
+
+
+// ////////////////////////////////////////////////////////////////////////// //
+function TDynRecordHelper.mapName (): AnsiString; inline; begin result := utf2win(getFieldWithType('name', TDynField.TType.TChar).sval); end;
+function TDynRecordHelper.mapAuthor (): AnsiString; inline; begin result := utf2win(getFieldWithType('author', TDynField.TType.TChar).sval); end;
+function TDynRecordHelper.mapDesc (): AnsiString; inline; begin result := utf2win(getFieldWithType('description', TDynField.TType.TChar).sval); end;
+function TDynRecordHelper.musicName (): AnsiString; inline; begin result := utf2win(getFieldWithType('music', TDynField.TType.TChar).sval); end;
+function TDynRecordHelper.skyName (): AnsiString; inline; begin result := utf2win(getFieldWithType('sky', TDynField.TType.TChar).sval); end;
+function TDynRecordHelper.X (): Integer; inline; begin result := getFieldWithType('position', TDynField.TType.TPoint).ival; end;
+function TDynRecordHelper.Y (): Integer; inline; begin result := getFieldWithType('position', TDynField.TType.TPoint).ival2; end;
+function TDynRecordHelper.Width (): Word; inline; begin result := Word(getFieldWithType('size', TDynField.TType.TSize).ival); end;
+function TDynRecordHelper.Height (): Word; inline; begin result := Word(getFieldWithType('size', TDynField.TType.TSize).ival2); end;
+function TDynRecordHelper.PanelType (): Word; inline; begin result := Word(getFieldWithType('type', TDynField.TType.TUShort).ival); end;
+function TDynRecordHelper.TextureRec (): TDynRecord; inline; begin result := getFieldWithType('texture', TDynField.TType.TUShort).recref; end;
+function TDynRecordHelper.Alpha (): Byte; inline; begin result := Byte(getFieldWithType('alpha', TDynField.TType.TUByte).ival); end;
+function TDynRecordHelper.Flags (): Byte; inline; begin result := Byte(getFieldWithType('flags', TDynField.TType.TUByte).ival); end;
+function TDynRecordHelper.Resource (): AnsiString; inline; begin result := utf2win(getFieldWithType('path', TDynField.TType.TChar).sval); end;
+function TDynRecordHelper.Anim (): Boolean; inline; begin result := (getFieldWithType('animated', TDynField.TType.TBool).ival <> 0); end;
+function TDynRecordHelper.ItemType (): Byte; inline; begin result := Byte(getFieldWithType('type', TDynField.TType.TUByte).ival); end;
+function TDynRecordHelper.Options (): Byte; inline; begin result := Byte(getFieldWithType('options', TDynField.TType.TUByte).ival); end;
+function TDynRecordHelper.MonsterType (): Byte; inline; begin result := Byte(getFieldWithType('type', TDynField.TType.TUByte).ival); end;
+function TDynRecordHelper.Direction (): Byte; inline; begin result := Byte(getFieldWithType('direction', TDynField.TType.TUByte).ival); end;
+function TDynRecordHelper.AreaType (): Byte; inline; begin result := Byte(getFieldWithType('type', TDynField.TType.TUByte).ival); end;
+function TDynRecordHelper.Enabled (): Boolean; inline; begin result := (getFieldWithType('enabled', TDynField.TType.TBool).ival <> 0); end;
+function TDynRecordHelper.TriggerType (): Byte; inline; begin result := Byte(getFieldWithType('type', TDynField.TType.TUByte).ival); end;
+function TDynRecordHelper.ActivateType (): Byte; inline; begin result := Byte(getFieldWithType('activate_type', TDynField.TType.TUByte).ival); end;
+function TDynRecordHelper.Keys (): Byte; inline; begin result := Byte(getFieldWithType('keys', TDynField.TType.TUByte).ival); end;
+
+{$INCLUDE mapdef_impl.inc}
 
-{$INCLUDE mapstructio.inc}
 
 end.