1 (* Copyright (C) DooM 2D:Forever Developers
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 {$INCLUDE a_modes.inc}
27 MAP_SIGNATURE
= 'MAP';
31 TEXTURE_NAME_WATER
= '_water_0';
32 TEXTURE_NAME_ACID1
= '_water_1';
33 TEXTURE_NAME_ACID2
= '_water_2';
37 TDFPoint
= packed record
42 constructor Create (ax
, ay
: LongInt);
44 function isZero (): Boolean; inline;
47 TDFSize
= packed record
52 constructor Create (aw
, ah
: LongInt);
54 function isZero (): Boolean; inline;
55 function isValid (): Boolean; inline;
58 TDFColor
= packed record
60 r
, g
, b
, a
: Byte; // a: 0 is transparent, 255 is opaque
63 constructor Create (ar
, ag
, ab
: LongInt; aa
: LongInt=0);
65 function isTransparent (): Boolean; inline;
66 function isOpaque (): Boolean; inline;
71 // various helpers to access map structures
73 TDynFieldHelper
= class helper
for TDynField
75 function getRGBA (): TDFColor
; inline;
76 procedure setRGBA (const v
: TDFColor
); inline;
79 property rgba
: TDFColor read getRGBA write setRGBA
; // for `TColor`
82 TDynRecordHelper
= class helper
for TDynRecord
84 function getFieldWithType (const aname
: AnsiString; atype
: TDynField
.TType
): TDynField
; inline;
86 function getPanelByIdx (idx
: Integer): TDynRecord
; inline;
88 function getTexturePanel (): Integer; inline;
89 function getTexturePanelRec (): TDynRecord
; inline;
91 function getPanelIndex (pan
: TDynRecord
): Integer;
93 function getPointField (const aname
: AnsiString): TDFPoint
; inline;
94 function getSizeField (const aname
: AnsiString): TDFSize
; inline;
97 function panelCount (): Integer; inline;
100 function mapName (): AnsiString; inline;
101 function mapAuthor (): AnsiString; inline;
102 function mapDesc (): AnsiString; inline;
103 function musicName (): AnsiString; inline;
104 function skyName (): AnsiString; inline;
107 function X (): Integer; inline;
108 function Y (): Integer; inline;
109 function Width (): Word; inline;
110 function Height (): Word; inline;
111 function TextureNum (): Word; inline;
112 function TextureRec (): TDynRecord
; inline;
113 function PanelType (): Word; inline;
114 function Alpha (): Byte; inline;
115 function Flags (): Byte; inline;
117 function moveSpeed (): TDFPoint
; inline;
118 function moveStart (): TDFPoint
; inline;
119 function moveEnd (): TDFPoint
; inline;
121 function moveOnce (): Boolean; inline;
123 function sizeSpeed (): TDFSize
; inline;
124 function sizeEnd (): TDFSize
; inline;
126 function endPosTrig (): Integer; inline;
127 function endSizeTrig (): Integer; inline;
130 function Resource (): AnsiString; inline;
131 function Anim (): Boolean; inline;
134 function ItemType (): Byte; inline;
135 function Options (): Byte; inline;
138 function MonsterType (): Byte; inline; // type, ubyte
139 function Direction (): Byte; inline; // direction, ubyte
142 function AreaType (): Byte; inline; // type, ubyte
143 //function Direction (): Byte; inline; // direction, ubyte
146 function trigRec (): TDynRecord
; inline;
147 function Enabled (): Boolean; inline; // enabled, bool
148 function TriggerType (): Byte; inline; // type, ubyte
149 function ActivateType (): Byte; inline; // activatetype, ubyte
150 function Keys (): Byte; inline; // keys, ubyte
151 //function DATA (): Byte128; inline; // triggerdata, trigdata[128]; // the only special nested structure
153 {$INCLUDE mapdef_help.inc}
154 function trigMonsterId (): Integer; inline;
155 function trigPanelId (): Integer; inline; // panel index in list
156 function trigPanelRec (): TDynRecord
; inline;
160 function getUserPanelId (): Integer; inline;
161 procedure setUserPanelId (v
: Integer); inline;
163 function getUserTrigRef (): Boolean; inline;
164 procedure setUserTrigRef (v
: Boolean); inline;
167 property panel
[idx
: Integer]: TDynRecord read getPanelByIdx
;
168 property panelIndex
[pan
: TDynRecord
]: Integer read getPanelIndex
;
170 property tgPanelId
: Integer read trigPanelId
;
171 property tgPanelRec
: TDynRecord read trigPanelRec
;
172 property TexturePanelId
: Integer read getTexturePanel
; // texturepanel, int
173 property TexturePanelRec
: TDynRecord read getTexturePanelRec
;
175 property userPanelId
: Integer read getUserPanelId write setUserPanelId
;
176 property userPanelTrigRef
: Boolean read getUserTrigRef write setUserTrigRef
;
182 SysUtils
, {e_log,} utils
, xparser
, xstreams
;
185 // ////////////////////////////////////////////////////////////////////////// //
186 constructor TDFPoint
.Create (ax
, ay
: LongInt); begin X
:= ax
; Y
:= ay
; end;
187 function TDFPoint
.isZero (): Boolean; inline; begin result
:= (X
= 0) and (Y
= 0); end;
190 constructor TDFSize
.Create (aw
, ah
: LongInt); begin w
:= aw
; h
:= ah
; end;
191 function TDFSize
.isZero (): Boolean; inline; begin result
:= (w
= 0) and (h
= 0); end;
192 function TDFSize
.isValid (): Boolean; inline; begin result
:= (w
> 0) and (h
> 0); end;
194 constructor TDFColor
.Create (ar
, ag
, ab
: LongInt; aa
: LongInt=0);
196 if (ar
< 0) then r
:= 0 else if (ar
> 255) then r
:= 255 else r
:= Byte(ar
);
197 if (ag
< 0) then g
:= 0 else if (ag
> 255) then g
:= 255 else g
:= Byte(ag
);
198 if (ab
< 0) then b
:= 0 else if (ab
> 255) then b
:= 255 else b
:= Byte(ab
);
199 if (aa
< 0) then a
:= 0 else if (aa
> 255) then a
:= 255 else a
:= Byte(aa
);
201 function TDFColor
.isTransparent (): Boolean; inline; begin result
:= (a
= 0); end;
202 function TDFColor
.isOpaque (): Boolean; inline; begin result
:= (a
= 255); end;
205 // ////////////////////////////////////////////////////////////////////////// //
206 function TDynFieldHelper
.getRGBA (): TDFColor
; inline; begin result
:= TDFColor
.Create(red
, green
, blue
, alpha
); end;
207 procedure TDynFieldHelper
.setRGBA (const v
: TDFColor
); inline; begin red
:= v
.r
; green
:= v
.g
; blue
:= v
.b
; alpha
:= v
.a
; end;
210 // ////////////////////////////////////////////////////////////////////////// //
211 function TDynRecordHelper
.getUserPanelId (): Integer; inline;
215 fld
:= field
['userPanelId'];
216 //if (fld = nil) or (fld.baseType <> TDynField.TType.TInt) then result := -1 else result := fld.ival;
217 if (fld
= nil) then result
:= -1 else result
:= Integer(fld
.value
);
221 procedure TDynRecordHelper
.setUserPanelId (v
: Integer); inline;
223 user
['userPanelId'] := v
;
227 function TDynRecordHelper
.getUserTrigRef (): Boolean; inline;
231 fld
:= field
['userPanelTrigRef'];
232 if (fld
= nil) then result
:= false else result
:= Boolean(fld
.value
);
233 //if (fld = nil) or (fld.baseType <> TDynField.TType.TBool) then result := false else result := (fld.ival <> 0);
237 procedure TDynRecordHelper
.setUserTrigRef (v
: Boolean); inline;
239 user
['userPanelTrigRef'] := v
;
243 // ////////////////////////////////////////////////////////////////////////// //
244 function TDynRecordHelper
.moveSpeed (): TDFPoint
; inline; begin result
:= getPointField('move_speed'); end;
245 function TDynRecordHelper
.moveStart (): TDFPoint
; inline; begin result
:= getPointField('move_start'); end;
246 function TDynRecordHelper
.moveEnd (): TDFPoint
; inline; begin result
:= getPointField('move_end'); end;
248 function TDynRecordHelper
.sizeSpeed (): TDFSize
; inline; begin result
:= getSizeField('size_speed'); end;
249 function TDynRecordHelper
.sizeEnd (): TDFSize
; inline; begin result
:= getSizeField('size_end'); end;
251 function TDynRecordHelper
.moveOnce (): Boolean; inline; begin result
:= (getFieldWithType('move_once', TDynField
.TType
.TBool
).ival
<> 0); end;
254 function TDynRecordHelper
.endPosTrig (): Integer; inline;
258 fld
:= getFieldWithType('end_pos_trigger', TDynField
.TType
.TInt
);
259 result
:= fld
.recrefIndex
;
262 function TDynRecordHelper
.endSizeTrig (): Integer; inline;
266 fld
:= getFieldWithType('end_size_trigger', TDynField
.TType
.TInt
);
267 result
:= fld
.recrefIndex
;
271 // ////////////////////////////////////////////////////////////////////////// //
272 function TDynRecordHelper
.getFieldWithType (const aname
: AnsiString; atype
: TDynField
.TType
): TDynField
; inline;
274 result
:= field
[aname
];
275 if (result
= nil) then raise Exception
.Create(Format('field ''%s'' not found in record ''%s'' of type ''%s''', [aname
, typeName
, id
]));
276 if (result
.baseType
<> atype
) then raise Exception
.Create(Format('field ''%s'' in record ''%s'' of type ''%s'' has invalid data type', [aname
, typeName
, id
]));
280 function TDynRecordHelper
.getPointField (const aname
: AnsiString): TDFPoint
; inline;
285 if (fld
= nil) then raise Exception
.Create(Format('field ''%s'' not found in record ''%s'' of type ''%s''', [aname
, typeName
, id
]));
286 if (fld
.baseType
<> TPoint
) then raise Exception
.Create(Format('field ''%s'' in record ''%s'' of type ''%s'' has invalid data type', [aname
, typeName
, id
]));
287 result
:= TDFPoint
.Create(fld
.ival
, fld
.ival2
);
291 function TDynRecordHelper
.getSizeField (const aname
: AnsiString): TDFSize
; inline;
296 if (fld
= nil) then raise Exception
.Create(Format('field ''%s'' not found in record ''%s'' of type ''%s''', [aname
, typeName
, id
]));
297 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
, typeName
, id
]));
298 result
:= TDFSize
.Create(fld
.ival
, fld
.ival2
);
302 function TDynRecordHelper
.getPanelByIdx (idx
: Integer): TDynRecord
; inline;
306 fld
:= headerRec
['panel'];
307 if (fld
<> nil) then result
:= fld
.itemAt
[idx
] else result
:= nil;
311 function TDynRecordHelper
.getPanelIndex (pan
: TDynRecord
): Integer;
319 fld
:= headerRec
['panel'];
322 for f
:= 0 to fld
.count
-1 do if (fld
.itemAt
[f
] = pan
) then begin result
:= f
; exit
; end;
328 function TDynRecordHelper
.panelCount (): Integer; inline;
332 fld
:= headerRec
['panel'];
333 if (fld
<> nil) then result
:= fld
.count
else result
:= 0;
337 function TDynRecordHelper
.TextureNum (): Word; inline;
342 fld
:= getFieldWithType('texture', TDynField
.TType
.TUShort
);
343 idx
:= fld
.recrefIndex
;
344 if (idx
< 0) then result
:= Word(TEXTURE_NONE
) else result
:= Word(idx
);
348 // ////////////////////////////////////////////////////////////////////////// //
350 function TDynRecordHelper
.trigRec (): TDynRecord
; inline;
354 fld
:= getFieldWithType('triggerdata', TDynField
.TType
.TTrigData
);
355 if (fld
<> nil) then result
:= fld
.recref
else result
:= nil;
358 function TDynRecordHelper
.trigMonsterId (): Integer; inline;
363 fld
:= field
['monsterid'];
364 if (fld
= nil) then exit
;
365 if (fld
.baseType
<> TDynField
.TType
.TInt
) then exit
;
366 if (fld
.recref
= nil) then exit
;
367 result
:= fld
.recrefIndex
;
370 function TDynRecordHelper
.trigPanelRec (): TDynRecord
; inline;
375 fld
:= field
['panelid'];
376 if (fld
= nil) then exit
;
377 if (fld
.baseType
<> TDynField
.TType
.TInt
) then exit
;
378 result
:= fld
.recref
;
379 if (result
<> nil) and (result
.typeName
<> 'panel') then result
:= nil;
382 // panel index in list
383 function TDynRecordHelper
.trigPanelId (): Integer; inline;
388 fld
:= field
['panelid'];
389 if (fld
= nil) then exit
;
390 if (fld
.baseType
<> TDynField
.TType
.TInt
) then exit
;
391 if (fld
.recref
= nil) then exit
;
392 if (fld
.recref
.typeName
<> 'panel') then exit
;
393 result
:= fld
.recrefIndex
;
396 function TDynRecordHelper
.getTexturePanelRec (): TDynRecord
;
401 fld
:= field
['texture_panel'];
402 if (fld
= nil) then exit
;
403 if (fld
.baseType
<> TDynField
.TType
.TInt
) then exit
;
404 result
:= fld
.recref
;
405 if (result
<> nil) and (result
.typeName
<> 'panel') then result
:= nil;
408 function TDynRecordHelper
.getTexturePanel (): Integer;
413 fld
:= field
['texture_panel'];
414 if (fld
= nil) then exit
;
415 if (fld
.baseType
<> TDynField
.TType
.TInt
) then exit
;
416 if (fld
.recref
= nil) then exit
;
417 if (fld
.recref
.typeName
<> 'panel') then exit
;
418 result
:= fld
.recrefIndex
;
422 // ////////////////////////////////////////////////////////////////////////// //
423 function TDynRecordHelper
.mapName (): AnsiString; inline; begin result
:= utf2win(getFieldWithType('name', TDynField
.TType
.TChar
).sval
); end;
424 function TDynRecordHelper
.mapAuthor (): AnsiString; inline; begin result
:= utf2win(getFieldWithType('author', TDynField
.TType
.TChar
).sval
); end;
425 function TDynRecordHelper
.mapDesc (): AnsiString; inline; begin result
:= utf2win(getFieldWithType('description', TDynField
.TType
.TChar
).sval
); end;
426 function TDynRecordHelper
.musicName (): AnsiString; inline; begin result
:= utf2win(getFieldWithType('music', TDynField
.TType
.TChar
).sval
); end;
427 function TDynRecordHelper
.skyName (): AnsiString; inline; begin result
:= utf2win(getFieldWithType('sky', TDynField
.TType
.TChar
).sval
); end;
428 function TDynRecordHelper
.X (): Integer; inline; begin result
:= getFieldWithType('position', TDynField
.TType
.TPoint
).ival
; end;
429 function TDynRecordHelper
.Y (): Integer; inline; begin result
:= getFieldWithType('position', TDynField
.TType
.TPoint
).ival2
; end;
430 function TDynRecordHelper
.Width (): Word; inline; begin result
:= Word(getFieldWithType('size', TDynField
.TType
.TSize
).ival
); end;
431 function TDynRecordHelper
.Height (): Word; inline; begin result
:= Word(getFieldWithType('size', TDynField
.TType
.TSize
).ival2
); end;
432 function TDynRecordHelper
.PanelType (): Word; inline; begin result
:= Word(getFieldWithType('type', TDynField
.TType
.TUShort
).ival
); end;
433 function TDynRecordHelper
.TextureRec (): TDynRecord
; inline; begin result
:= getFieldWithType('texture', TDynField
.TType
.TUShort
).recref
; end;
434 function TDynRecordHelper
.Alpha (): Byte; inline; begin result
:= Byte(getFieldWithType('alpha', TDynField
.TType
.TUByte
).ival
); end;
435 function TDynRecordHelper
.Flags (): Byte; inline; begin result
:= Byte(getFieldWithType('flags', TDynField
.TType
.TUByte
).ival
); end;
436 function TDynRecordHelper
.Resource (): AnsiString; inline; begin result
:= utf2win(getFieldWithType('path', TDynField
.TType
.TChar
).sval
); end;
437 function TDynRecordHelper
.Anim (): Boolean; inline; begin result
:= (getFieldWithType('animated', TDynField
.TType
.TBool
).ival
<> 0); end;
438 function TDynRecordHelper
.ItemType (): Byte; inline; begin result
:= Byte(getFieldWithType('type', TDynField
.TType
.TUByte
).ival
); end;
439 function TDynRecordHelper
.Options (): Byte; inline; begin result
:= Byte(getFieldWithType('options', TDynField
.TType
.TUByte
).ival
); end;
440 function TDynRecordHelper
.MonsterType (): Byte; inline; begin result
:= Byte(getFieldWithType('type', TDynField
.TType
.TUByte
).ival
); end;
441 function TDynRecordHelper
.Direction (): Byte; inline; begin result
:= Byte(getFieldWithType('direction', TDynField
.TType
.TUByte
).ival
); end;
442 function TDynRecordHelper
.AreaType (): Byte; inline; begin result
:= Byte(getFieldWithType('type', TDynField
.TType
.TUByte
).ival
); end;
443 function TDynRecordHelper
.Enabled (): Boolean; inline; begin result
:= (getFieldWithType('enabled', TDynField
.TType
.TBool
).ival
<> 0); end;
444 function TDynRecordHelper
.TriggerType (): Byte; inline; begin result
:= Byte(getFieldWithType('type', TDynField
.TType
.TUByte
).ival
); end;
445 function TDynRecordHelper
.ActivateType (): Byte; inline; begin result
:= Byte(getFieldWithType('activate_type', TDynField
.TType
.TUByte
).ival
); end;
446 function TDynRecordHelper
.Keys (): Byte; inline; begin result
:= Byte(getFieldWithType('keys', TDynField
.TType
.TUByte
).ival
); end;
448 {$INCLUDE mapdef_impl.inc}