DEADSOFTWARE

cc63613f5377e05f9e461fd576f1400ff1cc6ed2
[d2df-sdl.git] / src / shared / MAPDEF.pas
1 (* Copyright (C) Doom 2D: Forever Developers
2 *
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.
7 *
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.
12 *
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/>.
15 *)
16 {$INCLUDE a_modes.inc}
17 {$M+}
18 unit MAPDEF;
20 interface
22 uses
23 xdynrec;
26 const
27 MAP_SIGNATURE = 'MAP';
30 const
31 TEXTURE_NAME_WATER = '_water_0';
32 TEXTURE_NAME_ACID1 = '_water_1';
33 TEXTURE_NAME_ACID2 = '_water_2';
36 type
37 TDFPoint = packed record
38 public
39 X, Y: LongInt;
41 public
42 constructor Create (ax, ay: LongInt);
44 function isZero (): Boolean; inline;
45 end;
47 TDFSize = packed record
48 public
49 w, h: LongInt;
51 public
52 constructor Create (aw, ah: LongInt);
54 function isZero (): Boolean; inline;
55 function isValid (): Boolean; inline;
56 end;
58 TDFColor = packed record
59 public
60 r, g, b, a: Byte; // a: 0 is transparent, 255 is opaque
62 public
63 constructor Create (ar, ag, ab: LongInt; aa: LongInt=0);
65 function isTransparent (): Boolean; inline;
66 function isOpaque (): Boolean; inline;
67 function isBlack (): Boolean; inline;
68 function isWhite (): Boolean; inline;
69 end;
71 {$INCLUDE mapdef.inc}
73 // various helpers to access map structures
74 type
75 TDynFieldHelper = class helper for TDynField
76 public
77 function getRGBA (): TDFColor; inline;
78 procedure setRGBA (const v: TDFColor); inline;
80 public
81 property rgba: TDFColor read getRGBA write setRGBA; // for `TColor`
82 end;
84 TDynRecordHelper = class helper for TDynRecord
85 private
86 function getFieldWithType (const aname: AnsiString; atype: TDynField.TType): TDynField; inline;
88 function getPanelByIdx (idx: Integer): TDynRecord; inline;
90 function getTexturePanel (): Integer; inline;
91 function getTexturePanelRec (): TDynRecord; inline;
93 function getPanelIndex (pan: TDynRecord): Integer;
95 function getPointField (const aname: AnsiString): TDFPoint; inline;
96 function getSizeField (const aname: AnsiString): TDFSize; inline;
98 public
99 function panelCount (): Integer; inline;
101 // header
102 function mapName (): AnsiString; inline;
103 function mapAuthor (): AnsiString; inline;
104 function mapDesc (): AnsiString; inline;
105 function musicName (): AnsiString; inline;
106 function skyName (): AnsiString; inline;
108 // panel
109 function X (): Integer; inline;
110 function Y (): Integer; inline;
111 function Width (): Word; inline;
112 function Height (): Word; inline;
113 function TextureNum (): Word; inline;
114 function TextureRec (): TDynRecord; inline;
115 function PanelType (): Word; inline;
116 function Alpha (): Byte; inline;
117 function Flags (): Byte; inline;
119 function moveSpeed (): TDFPoint; inline;
120 function moveStart (): TDFPoint; inline;
121 function moveEnd (): TDFPoint; inline;
123 function moveOnce (): Boolean; inline;
125 function sizeSpeed (): TDFSize; inline;
126 function sizeEnd (): TDFSize; inline;
128 function endPosTrig (): Integer; inline;
129 function endSizeTrig (): Integer; inline;
131 // texture
132 function Resource (): AnsiString; inline;
133 function Anim (): Boolean; inline;
135 // item
136 function ItemType (): Byte; inline;
137 function Options (): Byte; inline;
139 // monster
140 function MonsterType (): Byte; inline; // type, ubyte
141 function Direction (): Byte; inline; // direction, ubyte
143 // area
144 function AreaType (): Byte; inline; // type, ubyte
145 //function Direction (): Byte; inline; // direction, ubyte
147 // trigger
148 function trigRec (): TDynRecord; inline;
149 function Enabled (): Boolean; inline; // enabled, bool
150 function TriggerType (): Byte; inline; // type, ubyte
151 function ActivateType (): Byte; inline; // activatetype, ubyte
152 function Keys (): Byte; inline; // keys, ubyte
153 //function DATA (): Byte128; inline; // triggerdata, trigdata[128]; // the only special nested structure
155 {$INCLUDE mapdef_help.inc}
156 function trigMonsterId (): Integer; inline;
157 function trigPanelId (): Integer; inline; // panel index in list
158 function trigPanelRec (): TDynRecord; inline;
160 private
161 // user fields
162 function getUserPanelId (): Integer; inline;
163 procedure setUserPanelId (v: Integer); inline;
165 function getUserTrigRef (): Boolean; inline;
166 procedure setUserTrigRef (v: Boolean); inline;
168 public
169 property panel[idx: Integer]: TDynRecord read getPanelByIdx;
170 property panelIndex[pan: TDynRecord]: Integer read getPanelIndex;
171 // triggers
172 property tgPanelId: Integer read trigPanelId;
173 property tgPanelRec: TDynRecord read trigPanelRec;
174 property TexturePanelId: Integer read getTexturePanel; // texturepanel, int
175 property TexturePanelRec: TDynRecord read getTexturePanelRec;
176 // user fields
177 property userPanelId: Integer read getUserPanelId write setUserPanelId;
178 property userPanelTrigRef: Boolean read getUserTrigRef write setUserTrigRef;
179 end;
181 implementation
183 uses
184 SysUtils, {e_log,} utils, xparser, xstreams;
187 // ////////////////////////////////////////////////////////////////////////// //
188 constructor TDFPoint.Create (ax, ay: LongInt); begin X := ax; Y := ay; end;
189 function TDFPoint.isZero (): Boolean; inline; begin result := (X = 0) and (Y = 0); end;
192 constructor TDFSize.Create (aw, ah: LongInt); begin w := aw; h := ah; end;
193 function TDFSize.isZero (): Boolean; inline; begin result := (w = 0) and (h = 0); end;
194 function TDFSize.isValid (): Boolean; inline; begin result := (w > 0) and (h > 0); end;
196 constructor TDFColor.Create (ar, ag, ab: LongInt; aa: LongInt=0);
197 begin
198 if (ar < 0) then r := 0 else if (ar > 255) then r := 255 else r := Byte(ar);
199 if (ag < 0) then g := 0 else if (ag > 255) then g := 255 else g := Byte(ag);
200 if (ab < 0) then b := 0 else if (ab > 255) then b := 255 else b := Byte(ab);
201 if (aa < 0) then a := 0 else if (aa > 255) then a := 255 else a := Byte(aa);
202 end;
203 function TDFColor.isTransparent (): Boolean; inline; begin result := (a = 0); end;
204 function TDFColor.isOpaque (): Boolean; inline; begin result := (a = 255); end;
205 function TDFColor.isBlack (): Boolean; inline; begin result := (r = 0) and (g = 0) and (b = 0); end;
206 function TDFColor.isWhite (): Boolean; inline; begin result := (r = 255) and (g = 255) and (b = 255); end;
209 // ////////////////////////////////////////////////////////////////////////// //
210 function TDynFieldHelper.getRGBA (): TDFColor; inline; begin result := TDFColor.Create(red, green, blue, alpha); end;
211 procedure TDynFieldHelper.setRGBA (const v: TDFColor); inline; begin red := v.r; green := v.g; blue := v.b; alpha := v.a; end;
214 // ////////////////////////////////////////////////////////////////////////// //
215 function TDynRecordHelper.getUserPanelId (): Integer; inline;
216 var
217 fld: TDynField;
218 begin
219 fld := field['userPanelId'];
220 //if (fld = nil) or (fld.baseType <> TDynField.TType.TInt) then result := -1 else result := fld.ival;
221 if (fld = nil) then result := -1 else result := Integer(fld.value);
222 end;
225 procedure TDynRecordHelper.setUserPanelId (v: Integer); inline;
226 begin
227 user['userPanelId'] := v;
228 end;
231 function TDynRecordHelper.getUserTrigRef (): Boolean; inline;
232 var
233 fld: TDynField;
234 begin
235 fld := field['userPanelTrigRef'];
236 if (fld = nil) then result := false else result := Boolean(fld.value);
237 //if (fld = nil) or (fld.baseType <> TDynField.TType.TBool) then result := false else result := (fld.ival <> 0);
238 end;
241 procedure TDynRecordHelper.setUserTrigRef (v: Boolean); inline;
242 begin
243 user['userPanelTrigRef'] := v;
244 end;
247 // ////////////////////////////////////////////////////////////////////////// //
248 function TDynRecordHelper.moveSpeed (): TDFPoint; inline; begin result := getPointField('move_speed'); end;
249 function TDynRecordHelper.moveStart (): TDFPoint; inline; begin result := getPointField('move_start'); end;
250 function TDynRecordHelper.moveEnd (): TDFPoint; inline; begin result := getPointField('move_end'); end;
252 function TDynRecordHelper.sizeSpeed (): TDFSize; inline; begin result := getSizeField('size_speed'); end;
253 function TDynRecordHelper.sizeEnd (): TDFSize; inline; begin result := getSizeField('size_end'); end;
255 function TDynRecordHelper.moveOnce (): Boolean; inline; begin result := (getFieldWithType('move_once', TDynField.TType.TBool).ival <> 0); end;
258 function TDynRecordHelper.endPosTrig (): Integer; inline;
259 var
260 fld: TDynField;
261 begin
262 fld := getFieldWithType('end_pos_trigger', TDynField.TType.TInt);
263 result := fld.recrefIndex;
264 end;
266 function TDynRecordHelper.endSizeTrig (): Integer; inline;
267 var
268 fld: TDynField;
269 begin
270 fld := getFieldWithType('end_size_trigger', TDynField.TType.TInt);
271 result := fld.recrefIndex;
272 end;
275 // ////////////////////////////////////////////////////////////////////////// //
276 function TDynRecordHelper.getFieldWithType (const aname: AnsiString; atype: TDynField.TType): TDynField; inline;
277 begin
278 result := field[aname];
279 if (result = nil) then raise Exception.Create(Format('field ''%s'' not found in record ''%s'' of type ''%s''', [aname, typeName, id]));
280 if (result.baseType <> atype) then raise Exception.Create(Format('field ''%s'' in record ''%s'' of type ''%s'' has invalid data type', [aname, typeName, id]));
281 end;
284 function TDynRecordHelper.getPointField (const aname: AnsiString): TDFPoint; inline;
285 var
286 fld: TDynField;
287 begin
288 fld := field[aname];
289 if (fld = nil) then raise Exception.Create(Format('field ''%s'' not found in record ''%s'' of type ''%s''', [aname, typeName, id]));
290 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]));
291 result := TDFPoint.Create(fld.ival, fld.ival2);
292 end;
295 function TDynRecordHelper.getSizeField (const aname: AnsiString): TDFSize; inline;
296 var
297 fld: TDynField;
298 begin
299 fld := field[aname];
300 if (fld = nil) then raise Exception.Create(Format('field ''%s'' not found in record ''%s'' of type ''%s''', [aname, typeName, id]));
301 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]));
302 result := TDFSize.Create(fld.ival, fld.ival2);
303 end;
306 function TDynRecordHelper.getPanelByIdx (idx: Integer): TDynRecord; inline;
307 var
308 fld: TDynField;
309 begin
310 fld := headerRec['panel'];
311 if (fld <> nil) then result := fld.itemAt[idx] else result := nil;
312 end;
315 function TDynRecordHelper.getPanelIndex (pan: TDynRecord): Integer;
316 var
317 fld: TDynField;
318 f: Integer;
319 begin
320 result := -1;
321 if (pan <> nil) then
322 begin
323 fld := headerRec['panel'];
324 if (fld <> nil) then
325 begin
326 for f := 0 to fld.count-1 do if (fld.itemAt[f] = pan) then begin result := f; exit; end;
327 end;
328 end;
329 end;
332 function TDynRecordHelper.panelCount (): Integer; inline;
333 var
334 fld: TDynField;
335 begin
336 fld := headerRec['panel'];
337 if (fld <> nil) then result := fld.count else result := 0;
338 end;
341 function TDynRecordHelper.TextureNum (): Word; inline;
342 var
343 idx: Integer;
344 fld: TDynField;
345 begin
346 fld := getFieldWithType('texture', TDynField.TType.TUShort);
347 idx := fld.recrefIndex;
348 if (idx < 0) then result := Word(TEXTURE_NONE) else result := Word(idx);
349 end;
352 // ////////////////////////////////////////////////////////////////////////// //
353 // trigger
354 function TDynRecordHelper.trigRec (): TDynRecord; inline;
355 var
356 fld: TDynField;
357 begin
358 fld := getFieldWithType('triggerdata', TDynField.TType.TTrigData);
359 if (fld <> nil) then result := fld.recref else result := nil;
360 end;
362 function TDynRecordHelper.trigMonsterId (): Integer; inline;
363 var
364 fld: TDynField;
365 begin
366 result := -1;
367 fld := field['monsterid'];
368 if (fld = nil) then exit;
369 if (fld.baseType <> TDynField.TType.TInt) then exit;
370 if (fld.recref = nil) then exit;
371 result := fld.recrefIndex;
372 end;
374 function TDynRecordHelper.trigPanelRec (): TDynRecord; inline;
375 var
376 fld: TDynField;
377 begin
378 result := nil;
379 fld := field['panelid'];
380 if (fld = nil) then exit;
381 if (fld.baseType <> TDynField.TType.TInt) then exit;
382 result := fld.recref;
383 if (result <> nil) and (result.typeName <> 'panel') then result := nil;
384 end;
386 // panel index in list
387 function TDynRecordHelper.trigPanelId (): Integer; inline;
388 var
389 fld: TDynField;
390 begin
391 result := -1;
392 fld := field['panelid'];
393 if (fld = nil) then exit;
394 if (fld.baseType <> TDynField.TType.TInt) then exit;
395 if (fld.recref = nil) then exit;
396 if (fld.recref.typeName <> 'panel') then exit;
397 result := fld.recrefIndex;
398 end;
400 function TDynRecordHelper.getTexturePanelRec (): TDynRecord;
401 var
402 fld: TDynField;
403 begin
404 result := nil;
405 fld := field['texture_panel'];
406 if (fld = nil) then exit;
407 if (fld.baseType <> TDynField.TType.TInt) then exit;
408 result := fld.recref;
409 if (result <> nil) and (result.typeName <> 'panel') then result := nil;
410 end;
412 function TDynRecordHelper.getTexturePanel (): Integer;
413 var
414 fld: TDynField;
415 begin
416 result := -1;
417 fld := field['texture_panel'];
418 if (fld = nil) then exit;
419 if (fld.baseType <> TDynField.TType.TInt) then exit;
420 if (fld.recref = nil) then exit;
421 if (fld.recref.typeName <> 'panel') then exit;
422 result := fld.recrefIndex;
423 end;
426 // ////////////////////////////////////////////////////////////////////////// //
427 function TDynRecordHelper.mapName (): AnsiString; inline; begin result := utf2win(getFieldWithType('name', TDynField.TType.TChar).sval); end;
428 function TDynRecordHelper.mapAuthor (): AnsiString; inline; begin result := utf2win(getFieldWithType('author', TDynField.TType.TChar).sval); end;
429 function TDynRecordHelper.mapDesc (): AnsiString; inline; begin result := utf2win(getFieldWithType('description', TDynField.TType.TChar).sval); end;
430 function TDynRecordHelper.musicName (): AnsiString; inline; begin result := utf2win(getFieldWithType('music', TDynField.TType.TChar).sval); end;
431 function TDynRecordHelper.skyName (): AnsiString; inline; begin result := utf2win(getFieldWithType('sky', TDynField.TType.TChar).sval); end;
432 function TDynRecordHelper.X (): Integer; inline; begin result := getFieldWithType('position', TDynField.TType.TPoint).ival; end;
433 function TDynRecordHelper.Y (): Integer; inline; begin result := getFieldWithType('position', TDynField.TType.TPoint).ival2; end;
434 function TDynRecordHelper.Width (): Word; inline; begin result := Word(getFieldWithType('size', TDynField.TType.TSize).ival); end;
435 function TDynRecordHelper.Height (): Word; inline; begin result := Word(getFieldWithType('size', TDynField.TType.TSize).ival2); end;
436 function TDynRecordHelper.PanelType (): Word; inline; begin result := Word(getFieldWithType('type', TDynField.TType.TUShort).ival); end;
437 function TDynRecordHelper.TextureRec (): TDynRecord; inline; begin result := getFieldWithType('texture', TDynField.TType.TUShort).recref; end;
438 function TDynRecordHelper.Alpha (): Byte; inline; begin result := Byte(getFieldWithType('alpha', TDynField.TType.TUByte).ival); end;
439 function TDynRecordHelper.Flags (): Byte; inline; begin result := Byte(getFieldWithType('flags', TDynField.TType.TUByte).ival); end;
440 function TDynRecordHelper.Resource (): AnsiString; inline; begin result := utf2win(getFieldWithType('path', TDynField.TType.TChar).sval); end;
441 function TDynRecordHelper.Anim (): Boolean; inline; begin result := (getFieldWithType('animated', TDynField.TType.TBool).ival <> 0); end;
442 function TDynRecordHelper.ItemType (): Byte; inline; begin result := Byte(getFieldWithType('type', TDynField.TType.TUByte).ival); end;
443 function TDynRecordHelper.Options (): Byte; inline; begin result := Byte(getFieldWithType('options', TDynField.TType.TUByte).ival); end;
444 function TDynRecordHelper.MonsterType (): Byte; inline; begin result := Byte(getFieldWithType('type', TDynField.TType.TUByte).ival); end;
445 function TDynRecordHelper.Direction (): Byte; inline; begin result := Byte(getFieldWithType('direction', TDynField.TType.TUByte).ival); end;
446 function TDynRecordHelper.AreaType (): Byte; inline; begin result := Byte(getFieldWithType('type', TDynField.TType.TUByte).ival); end;
447 function TDynRecordHelper.Enabled (): Boolean; inline; begin result := (getFieldWithType('enabled', TDynField.TType.TBool).ival <> 0); end;
448 function TDynRecordHelper.TriggerType (): Byte; inline; begin result := Byte(getFieldWithType('type', TDynField.TType.TUByte).ival); end;
449 function TDynRecordHelper.ActivateType (): Byte; inline; begin result := Byte(getFieldWithType('activate_type', TDynField.TType.TUByte).ival); end;
450 function TDynRecordHelper.Keys (): Byte; inline; begin result := Byte(getFieldWithType('keys', TDynField.TType.TUByte).ival); end;
452 {$INCLUDE mapdef_impl.inc}
455 end.