DEADSOFTWARE

xdynrec: TColor type (rgb, and optional a)
[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 end;
69 {$INCLUDE mapdef.inc}
71 // various helpers to access map structures
72 type
73 TDynFieldHelper = class helper for TDynField
74 public
75 function getRGBA (): TDFColor; inline;
76 procedure setRGBA (const v: TDFColor); inline;
78 public
79 property rgba: TDFColor read getRGBA write setRGBA; // for `TColor`
80 end;
82 TDynRecordHelper = class helper for TDynRecord
83 private
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;
96 public
97 function panelCount (): Integer; inline;
99 // header
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;
106 // panel
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;
129 // texture
130 function Resource (): AnsiString; inline;
131 function Anim (): Boolean; inline;
133 // item
134 function ItemType (): Byte; inline;
135 function Options (): Byte; inline;
137 // monster
138 function MonsterType (): Byte; inline; // type, ubyte
139 function Direction (): Byte; inline; // direction, ubyte
141 // area
142 function AreaType (): Byte; inline; // type, ubyte
143 //function Direction (): Byte; inline; // direction, ubyte
145 // trigger
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;
158 private
159 // user fields
160 function getUserPanelId (): Integer; inline;
161 procedure setUserPanelId (v: Integer); inline;
163 function getUserTrigRef (): Boolean; inline;
164 procedure setUserTrigRef (v: Boolean); inline;
166 public
167 property panel[idx: Integer]: TDynRecord read getPanelByIdx;
168 property panelIndex[pan: TDynRecord]: Integer read getPanelIndex;
169 // triggers
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;
174 // user fields
175 property userPanelId: Integer read getUserPanelId write setUserPanelId;
176 property userPanelTrigRef: Boolean read getUserTrigRef write setUserTrigRef;
177 end;
179 implementation
181 uses
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);
195 begin
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);
200 end;
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;
212 var
213 fld: TDynField;
214 begin
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);
218 end;
221 procedure TDynRecordHelper.setUserPanelId (v: Integer); inline;
222 begin
223 user['userPanelId'] := v;
224 end;
227 function TDynRecordHelper.getUserTrigRef (): Boolean; inline;
228 var
229 fld: TDynField;
230 begin
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);
234 end;
237 procedure TDynRecordHelper.setUserTrigRef (v: Boolean); inline;
238 begin
239 user['userPanelTrigRef'] := v;
240 end;
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;
255 var
256 fld: TDynField;
257 begin
258 fld := getFieldWithType('end_pos_trigger', TDynField.TType.TInt);
259 result := fld.recrefIndex;
260 end;
262 function TDynRecordHelper.endSizeTrig (): Integer; inline;
263 var
264 fld: TDynField;
265 begin
266 fld := getFieldWithType('end_size_trigger', TDynField.TType.TInt);
267 result := fld.recrefIndex;
268 end;
271 // ////////////////////////////////////////////////////////////////////////// //
272 function TDynRecordHelper.getFieldWithType (const aname: AnsiString; atype: TDynField.TType): TDynField; inline;
273 begin
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]));
277 end;
280 function TDynRecordHelper.getPointField (const aname: AnsiString): TDFPoint; inline;
281 var
282 fld: TDynField;
283 begin
284 fld := field[aname];
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);
288 end;
291 function TDynRecordHelper.getSizeField (const aname: AnsiString): TDFSize; inline;
292 var
293 fld: TDynField;
294 begin
295 fld := field[aname];
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);
299 end;
302 function TDynRecordHelper.getPanelByIdx (idx: Integer): TDynRecord; inline;
303 var
304 fld: TDynField;
305 begin
306 fld := headerRec['panel'];
307 if (fld <> nil) then result := fld.itemAt[idx] else result := nil;
308 end;
311 function TDynRecordHelper.getPanelIndex (pan: TDynRecord): Integer;
312 var
313 fld: TDynField;
314 f: Integer;
315 begin
316 result := -1;
317 if (pan <> nil) then
318 begin
319 fld := headerRec['panel'];
320 if (fld <> nil) then
321 begin
322 for f := 0 to fld.count-1 do if (fld.itemAt[f] = pan) then begin result := f; exit; end;
323 end;
324 end;
325 end;
328 function TDynRecordHelper.panelCount (): Integer; inline;
329 var
330 fld: TDynField;
331 begin
332 fld := headerRec['panel'];
333 if (fld <> nil) then result := fld.count else result := 0;
334 end;
337 function TDynRecordHelper.TextureNum (): Word; inline;
338 var
339 idx: Integer;
340 fld: TDynField;
341 begin
342 fld := getFieldWithType('texture', TDynField.TType.TUShort);
343 idx := fld.recrefIndex;
344 if (idx < 0) then result := Word(TEXTURE_NONE) else result := Word(idx);
345 end;
348 // ////////////////////////////////////////////////////////////////////////// //
349 // trigger
350 function TDynRecordHelper.trigRec (): TDynRecord; inline;
351 var
352 fld: TDynField;
353 begin
354 fld := getFieldWithType('triggerdata', TDynField.TType.TTrigData);
355 if (fld <> nil) then result := fld.recref else result := nil;
356 end;
358 function TDynRecordHelper.trigMonsterId (): Integer; inline;
359 var
360 fld: TDynField;
361 begin
362 result := -1;
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;
368 end;
370 function TDynRecordHelper.trigPanelRec (): TDynRecord; inline;
371 var
372 fld: TDynField;
373 begin
374 result := nil;
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;
380 end;
382 // panel index in list
383 function TDynRecordHelper.trigPanelId (): Integer; inline;
384 var
385 fld: TDynField;
386 begin
387 result := -1;
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;
394 end;
396 function TDynRecordHelper.getTexturePanelRec (): TDynRecord;
397 var
398 fld: TDynField;
399 begin
400 result := nil;
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;
406 end;
408 function TDynRecordHelper.getTexturePanel (): Integer;
409 var
410 fld: TDynField;
411 begin
412 result := -1;
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;
419 end;
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}
451 end.