1 {$INCLUDE ../shared/a_modes.inc}
9 SDL in '../lib/sdl/sdl.pas',
12 SDL2 in '../lib/sdl2/sdl2.pas',
14 mempool in '../shared/mempool.pas',
15 xstreams in '../shared/xstreams.pas',
16 xparser in '../shared/xparser.pas',
17 xdynrec in '../shared/xdynrec.pas',
18 xprofiler in '../shared/xprofiler.pas',
19 utils in '../shared/utils.pas',
20 hashtable in '../shared/hashtable.pas',
21 conbuf in '../shared/conbuf.pas',
22 e_log in '../engine/e_log.pas';
25 // ////////////////////////////////////////////////////////////////////////// //
27 THashStrFld = specialize THashBase<AnsiString, TDynField, THashKeyStr>;
30 // ////////////////////////////////////////////////////////////////////////// //
35 // ////////////////////////////////////////////////////////////////////////// //
36 procedure genTrigCacheVars (const fname: AnsiString);
39 tidx, fidx, nidx: Integer;
43 fldknown: THashStrFld = nil; // key: palias; value: prev field
45 AssignFile(fo, fname);
46 {$I+}Rewrite(fo);{$I-}
48 fldknown := THashStrFld.Create();
50 write(fo, '// trigger cache'#10);
51 for tidx := 0 to dfmapdef.trigTypeCount-1 do
55 trec := dfmapdef.trigTypeAt[tidx];
56 for nidx := 0 to trec.forTrigCount-1 do
58 write(fo, '//', trec.forTrigAt[nidx], #10);
61 for fidx := 0 to trec.count-1 do
63 fld := trec.fieldAt[fidx];
64 if fld.internal then continue;
66 if (fld.name = 'panelid') or (fld.name = 'monsterid') then
68 //writeln('skipping <', fld.name, '>');
71 palias := fld.palias(true);
72 // don't write duplicate fields
73 if fldknown.has(toLowerCase1251(palias)) then continue;
74 fldknown.put(toLowerCase1251(palias), fld);
75 // write field definition
77 TDynField.TType.TBool: write(fo, 'tgc', palias, ': Boolean;'#10);
78 TDynField.TType.TChar: write(fo, 'tgc', palias, ': AnsiString;'#10);
79 TDynField.TType.TByte: write(fo, 'tgc', palias, ': SmallInt;'#10);
80 TDynField.TType.TUByte: write(fo, 'tgc', palias, ': Byte;'#10);
81 TDynField.TType.TShort: write(fo, 'tgc', palias, ': ShortInt;'#10);
82 TDynField.TType.TUShort: write(fo, 'tgc', palias, ': Word;'#10);
83 TDynField.TType.TInt: write(fo, 'tgc', palias, ': LongInt;'#10);
84 TDynField.TType.TUInt: write(fo, 'tgc', palias, ': LongWord;'#10);
85 TDynField.TType.TString: write(fo, 'tgc', palias, ': AnsiString;'#10);
86 TDynField.TType.TPoint:
88 if fld.hasTPrefix then
90 write(fo, 'tgcTX: LongInt;'#10);
91 write(fo, 'tgcTY: LongInt;'#10);
93 else if fld.separatePasFields then
95 write(fo, 'tgcX: LongInt;'#10);
96 write(fo, 'tgcY: LongInt;'#10);
100 write(fo, 'tgc', palias, ': TDFPoint;'#10);
103 TDynField.TType.TSize:
105 if fld.hasTPrefix then
107 write(fo, 'tgcTWidth: LongInt;'#10);
108 write(fo, 'tgcTHeight: LongInt;'#10);
110 else if fld.separatePasFields then
112 write(fo, 'tgcWidth: LongInt;'#10);
113 write(fo, 'tgcHeight: LongInt;'#10);
117 write(fo, 'tgc', palias, ': TDFSize;'#10);
120 TDynField.TType.TList:
121 raise Exception.Create('no lists in triggers, pelase');
122 TDynField.TType.TTrigData:
123 raise Exception.Create('no triggers in triggers, pelase');
133 // ////////////////////////////////////////////////////////////////////////// //
134 procedure genTrigLoadCache (const fname: AnsiString);
137 tidx, fidx, nidx: Integer;
143 AssignFile(fo, fname);
144 {$I+}Rewrite(fo);{$I-}
146 write(fo, '// trigger cache loader'#10);
147 write(fo, '// set `TriggerType` in `tgt` before calling this'#10);
148 write(fo, 'procedure trigUpdateCacheData (var tgt: TTrigger; tdata: TDynRecord);'#10);
149 write(fo, 'begin'#10);
150 write(fo, ' case tgt.TriggerType of'#10);
151 for tidx := 0 to dfmapdef.trigTypeCount-1 do
156 trec := dfmapdef.trigTypeAt[tidx];
157 for nidx := 0 to trec.forTrigCount-1 do
159 if needComma then write(fo, ','#10' ') else needComma := true;
160 write(fo, trec.forTrigAt[nidx]);
163 write(fo, ' begin'#10);
165 for fidx := 0 to trec.count-1 do
167 fld := trec.fieldAt[fidx];
168 if fld.internal then continue;
170 if (fld.name = 'panelid') or (fld.name = 'monsterid') then
172 //writeln('skipping <', fld.name, '>');
175 palias := fld.palias(true);
176 // write field definition
178 TDynField.TType.TBool,
179 TDynField.TType.TChar,
180 TDynField.TType.TByte,
181 TDynField.TType.TUByte,
182 TDynField.TType.TShort,
183 TDynField.TType.TUShort,
184 TDynField.TType.TInt,
185 TDynField.TType.TUInt,
186 TDynField.TType.TString:
187 write(fo, ' tgt.tgc', palias, ' := tdata.trig', palias, ';'#10);
188 TDynField.TType.TPoint:
190 if fld.hasTPrefix then
192 write(fo, ' tgt.tgcTX := tdata.trigTX;'#10);
193 write(fo, ' tgt.tgcTY := tdata.trigTY;'#10);
195 else if fld.separatePasFields then
197 write(fo, ' tgt.tgcX := tdata.trigX;'#10);
198 write(fo, ' tgt.tgcY := tdata.trigY;'#10);
202 write(fo, ' tgt.tgc', palias, ' := tdata.trig', palias, ';'#10);
205 TDynField.TType.TSize:
207 if fld.hasTPrefix then
209 write(fo, ' tgt.tgcTWidth := tdata.trigTWidth;'#10);
210 write(fo, ' tgt.tgcTHeight := tdata.trigTHeight;'#10);
212 else if fld.separatePasFields then
214 write(fo, ' tgt.tgcWidth := tdata.trigWidth;'#10);
215 write(fo, ' tgt.tgcHeight := tdata.trigHeight;'#10);
219 write(fo, ' tgt.tgc', palias, ' := tdata.trig', palias, ';'#10);
222 TDynField.TType.TList:
223 raise Exception.Create('no lists in triggers, pelase');
224 TDynField.TType.TTrigData:
225 raise Exception.Create('no triggers in triggers, pelase');
228 write(fo, ' end;'#10);
230 write(fo, ' end;'#10);
231 write(fo, 'end;'#10);
237 // ////////////////////////////////////////////////////////////////////////// //
240 fo, fohlp, foimpl: TextFile;
245 tidx, nidx, fidx: Integer;
250 fldknown: THashStrFld = nil; // key: palias; value: prev field
253 fldknown := THashStrFld.Create();
254 //writeln(getFilenamePath(ParamStr(0)), '|');
256 e_InitWritelnDriver();
257 conbufDumpToStdOut := true;
258 conbufConPrefix := false;
260 writeln('parsing "mapdef.txt"...');
262 st := openDiskFileRO('mapdef.txt');
263 writeln('found: local mapdef');
268 writeln(filenameConcat(getFilenamePath(ParamStr(0)), '../mapdef/mapdef.txt'), '|');
269 st := openDiskFileRO(filenameConcat(getFilenamePath(ParamStr(0)), '../mapdef/mapdef.txt'));
270 writeln('found: system mapdef');
272 writeln('FATAL: mapdef not found!');
275 writeln('parsing "mapdef.txt"...');
276 pr := TFileTextParser.Create(st, false); // don't own
278 dfmapdef := TDynMapDef.Create(pr);
280 on e: TDynParseException do
282 writeln('ERROR at (', e.tokLine, ',', e.tokCol, '): ', e.message);
287 writeln('ERROR: ', e.message);
293 writeln('writing "mapdef.inc"...');
294 AssignFile(fo, 'mapdef.inc');
295 {$I+}Rewrite(fo);{$I-}
297 AssignFile(fohlp, 'mapdef_help.inc');
298 {$I+}Rewrite(fohlp);{$I-}
300 AssignFile(foimpl, 'mapdef_impl.inc');
301 {$I+}Rewrite(foimpl);{$I-}
303 write(fo, '// *** WARNING! ***'#10);
304 write(fo, '// regenerate this part directly from "mapdef.txt" with ''mapgen'', NEVER manually change anything here!'#10#10#10);
305 write(fo, dfmapdef.pasdefconst);
307 write(fohlp, '// *** WARNING! ***'#10);
308 write(fohlp, '// regenerate this part directly from "mapdef.txt" with ''mapgen'', NEVER manually change anything here!'#10#10);
310 // generate trigger helpers
311 write(foimpl, #10#10'// ////////////////////////////////////////////////////////////////////////// //'#10);
312 write(foimpl, '// trigger helpers'#10);
313 for tidx := 0 to dfmapdef.trigTypeCount-1 do
316 write(foimpl, #10'// ');
317 write(fohlp, #10'// ');
319 trec := dfmapdef.trigTypeAt[tidx];
320 for nidx := 0 to trec.forTrigCount-1 do
322 if needComma then write(fohlp, ', ');
323 if needComma then write(foimpl, ', ') else needComma := true;
324 write(fohlp, trec.forTrigAt[nidx]);
325 write(foimpl, trec.forTrigAt[nidx]);
330 for fidx := 0 to trec.count-1 do
332 fld := trec.fieldAt[fidx];
333 if fld.internal then continue;
334 //if (fld.binOfs < 0) then continue;
336 if (fld.name = 'panelid') or (fld.name = 'monsterid') then
338 writeln('skipping <', fld.name, '>');
341 palias := fld.palias(true);
342 // check for known aliases
343 //writeln('<', palias, '> : <', toLowerCase1251(palias), '>');
345 if fldknown.get(toLowerCase1251(palias), knownfld) then
347 if (fld.name <> knownfld.name) then raise Exception.Create(formatstrf('field ''%s'' of record ''%s'' conflicts with other field ''%s''', [fld.name, trec.typeName, knownfld.name]));
348 if (fld.baseType <> knownfld.baseType) then raise Exception.Create(formatstrf('field ''%s'' of record ''%s'' conflicts with other field ''%s'' by type', [fld.name, trec.typeName, knownfld.name]));
349 writeln('skipped duplicate field ''', fld.name, '''');
352 fldknown.put(toLowerCase1251(palias), fld);
354 if (fld.baseType <> TDynField.TType.TPoint) and (fld.baseType <> TDynField.TType.TSize) then
356 write(foimpl, 'function TDynRecordHelper.trig', palias, ' (): ');
357 write(fohlp, 'function trig', palias, ' (): ');
360 TDynField.TType.TBool:
362 write(fohlp, 'Boolean; inline;'#10);
363 write(foimpl, 'Boolean; inline; begin result := (getFieldWithType(''', fld.name, ''', TDynField.TType.TBool).ival ');
364 if fld.negbool then write(foimpl, '=') else write(foimpl, '<>');
365 write(foimpl, ' 0); end;'#10);
367 TDynField.TType.TChar:
369 write(fohlp, 'AnsiString; inline;'#10);
370 write(foimpl, 'AnsiString; inline; begin result := utf2win(getFieldWithType(''', fld.name, ''', TDynField.TType.TChar).sval); end;'#10);
372 TDynField.TType.TByte:
374 write(fohlp, 'SmallInt; inline;'#10);
375 write(foimpl, 'SmallInt; inline; begin result := ShortInt(getFieldWithType(''', fld.name, ''', TDynField.TType.TByte).ival); end;'#10);
377 TDynField.TType.TUByte:
379 write(fohlp, 'Byte; inline;'#10);
380 write(foimpl, 'Byte; inline; begin result := Byte(getFieldWithType(''', fld.name, ''', TDynField.TType.TUByte).ival); end;'#10);
382 TDynField.TType.TShort:
384 write(fohlp, 'ShortInt; inline;'#10);
385 write(foimpl, 'ShortInt; inline; begin result := SmallInt(getFieldWithType(''', fld.name, ''', TDynField.TType.TShort).ival); end;'#10);
387 TDynField.TType.TUShort:
389 write(fohlp, 'Word; inline;'#10);
390 write(foimpl, 'Word; inline; begin result := Word(getFieldWithType(''', fld.name, ''', TDynField.TType.TUShort).ival); end;'#10);
392 TDynField.TType.TInt:
394 write(fohlp, 'LongInt; inline;'#10);
395 write(foimpl, 'LongInt; inline; begin result := LongInt(getFieldWithType(''', fld.name, ''', TDynField.TType.TInt).ival); end;'#10);
397 TDynField.TType.TUInt:
399 write(fohlp, 'LongWord; inline;'#10);
400 write(foimpl, 'LongWord; inline; begin result := LongWord(getFieldWithType(''', fld.name, ''', TDynField.TType.TUInt).ival); end;'#10);
402 TDynField.TType.TString:
404 write(fohlp, 'AnsiString; inline;'#10);
405 write(foimpl, 'AnsiString; inline; begin result := utf2win(getFieldWithType(''', fld.name, ''', TDynField.TType.TString).sval); end;'#10);
407 TDynField.TType.TPoint:
409 if fld.hasTPrefix or fld.separatePasFields then
411 write(fohlp, 'function trig'); if fld.hasTPrefix then write(fohlp, 'T'); write(fohlp, 'X (): LongInt; inline;'#10);
412 write(fohlp, 'function trig'); if fld.hasTPrefix then write(fohlp, 'T'); write(fohlp, 'Y (): LongInt; inline;'#10);
414 write(foimpl, 'function TDynRecordHelper.trig');
415 if fld.hasTPrefix then write(foimpl, 'T');
416 write(foimpl, 'X (): LongInt; inline; begin result := LongInt(getFieldWithType(''', fld.name, ''', TDynField.TType.TPoint).ival); end;'#10);
418 write(foimpl, 'function TDynRecordHelper.trig');
419 if fld.hasTPrefix then write(foimpl, 'T');
420 write(foimpl, 'Y (): LongInt; inline; begin result := LongInt(getFieldWithType(''', fld.name, ''', TDynField.TType.TPoint).ival2); end;'#10);
424 write(fohlp, 'function trig', palias, ' (): TDFPoint; inline;'#10);
425 write(foimpl, 'function TDynRecordHelper.trig', palias, ' (): TDFPoint; inline; begin result := getPointField(''', fld.name, '''); end;'#10);
428 TDynField.TType.TSize:
430 if fld.hasTPrefix or fld.separatePasFields then
432 write(fohlp, 'function trig'); if fld.hasTPrefix then write(fohlp, 'T'); write(fohlp, 'Width (): Word; inline;'#10);
433 write(fohlp, 'function trig'); if fld.hasTPrefix then write(fohlp, 'T'); write(fohlp, 'Height (): Word; inline;'#10);
435 write(foimpl, 'function TDynRecordHelper.trig');
436 if fld.hasTPrefix then write(foimpl, 'T');
437 write(foimpl, 'Width (): Word; inline; begin result := Word(getFieldWithType(''', fld.name, ''', TDynField.TType.TSize).ival); end;'#10);
439 write(foimpl, 'function TDynRecordHelper.trig');
440 if fld.hasTPrefix then write(foimpl, 'T');
441 write(foimpl, 'Height (): Word; inline; begin result := Word(getFieldWithType(''', fld.name, ''', TDynField.TType.TSize).ival2); end;'#10);
445 //raise Exception.Create('no non-separate sizes in triggers, pelase');
446 write(fohlp, 'function trig', palias, ' (): TDFSize; inline;'#10);
447 write(foimpl, 'function TDynRecordHelper.trig', palias, ' (): TDFSize; inline; begin result := getSizeField(''', fld.name, '''); end;'#10);
450 TDynField.TType.TList:
451 raise Exception.Create('no lists in triggers, pelase');
452 TDynField.TType.TTrigData:
453 raise Exception.Create('no triggers in triggers, pelase');
458 genTrigCacheVars('mapdef_tgc_def.inc');
459 genTrigLoadCache('mapdef_tgc_impl.inc');
461 //st := openDiskFileRO('mapdef.txt');
463 write(fo, #10#10'const defaultMapDef: AnsiString = ''''+'#10' ');
467 if (st.Read(ch, 1) <> 1) then break;
468 s := formatstrf('#%d', [Byte(ch)]);
469 if (wdt+Length(s) > 78) then begin wdt := 2; write(fo, '+'#10' '); end;