summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: ee55194)
raw | patch | inline | side by side (parent: ee55194)
author | Ketmar Dark <ketmar@ketmar.no-ip.org> | |
Tue, 29 Aug 2017 21:53:09 +0000 (00:53 +0300) | ||
committer | Ketmar Dark <ketmar@ketmar.no-ip.org> | |
Tue, 29 Aug 2017 21:53:42 +0000 (00:53 +0300) |
diff --git a/src/engine/e_log.pas b/src/engine/e_log.pas
index aba6e0d99d3f794b3de7f85dbf69d99de4c32a57..afc638cac7be82a9d7af6a0f1eb764811adf4eb8 100644 (file)
--- a/src/engine/e_log.pas
+++ b/src/engine/e_log.pas
while (len > 0) do
begin
if (len > 255) then slen := 255 else slen := Integer(len);
- Move(b^, ss[1], len);
+ Move(b^, ss[1], slen);
ss[0] := AnsiChar(slen);
write(ss);
b += slen;
while (len > 0) do
begin
slen := 0;
- while (slen < len) and (slen < 255) and (b[slen] <> 13) and (b[slen] <> 10) do Inc(slen);
+ while (slen < len) and (b[slen] <> 13) and (b[slen] <> 10) do Inc(slen);
+ if (slen > 255) then slen := 255;
// print string
if (slen > 0) then
begin
if xlogWantSpace then begin write(xlogFile, ' '); xlogWantSpace := false; end;
- Move(b^, ss[1], len);
+ Move(b^, ss[1], slen);
ss[0] := AnsiChar(slen);
write(xlogFile, ss);
b += slen;
// process newline
if (len > 0) and ((b[0] = 13) or (b[0] = 10)) then
begin
- if (len > 1) and (b[0] = 13) and (b[1] = 10) then
- begin
- len -= 2;
- b += 2;
- end
- else
- begin
- len -= 1;
- b += 1;
- end;
+ if (b[0] = 13) then begin len -= 1; b += 1; end;
+ if (len > 0) and (b[0] = 10) then begin len -= 1; b += 1; end;
xlogLastWasEOL := false;
writeln(xlogFile, '');
write(xlogFile, xlogPrefix);
diff --git a/src/game/Doom2DF.dpr b/src/game/Doom2DF.dpr
index e5ecf92df9006496a1f5577aa5657d1826efdbbb..bfd07a5b8f15c1a6668a003710606823d283b118 100644 (file)
--- a/src/game/Doom2DF.dpr
+++ b/src/game/Doom2DF.dpr
hashtable in '../shared/hashtable.pas',
idpool in '../shared/idpool.pas',
xparser in '../shared/xparser.pas',
+ xdynrec in '../shared/xdynrec.pas',
BinEditor in '../shared/BinEditor.pas',
envvars in '../shared/envvars.pas',
g_panel in 'g_panel.pas',
diff --git a/src/game/g_map.pas b/src/game/g_map.pas
index 4f86e9b0d3f14ddc3f21e097756080f4996e2e12..4bb340d1026a97f86893f6843e0f0f3dfb93a61a 100644 (file)
--- a/src/game/g_map.pas
+++ b/src/game/g_map.pas
GL, GLExt, g_weapons, g_game, g_sound, e_sound, CONFIG,
g_options, MAPREADER, g_triggers, g_player, MAPDEF,
Math, g_monsters, g_saveload, g_language, g_netmsg,
- utils, sfs,
+ utils, sfs, xparser, xdynrec, xstreams,
ImagingTypes, Imaging, ImagingUtility,
ImagingGif, ImagingNetworkGraphics;
FLAG_SIGNATURE = $47414C46; // 'FLAG'
+{$IF DEFINED(D2D_NEW_MAP_READER)}
+var
+ dfmapdef: TDynMapDef = nil;
+
+
+procedure loadMapDefinition ();
+var
+ pr: TTextParser = nil;
+ st: TStream = nil;
+ WAD: TWADFile = nil;
+begin
+ if (dfmapdef <> nil) then exit;
+ try
+ e_LogWritefln('parsing "mapdef.txt"...', []);
+ st := openDiskFileRO(DataDir+'mapdef.txt');
+ except
+ st := nil;
+ e_LogWritefln('local "%smapdef.txt" not found', [DataDir]);
+ end;
+ if (st = nil) then
+ begin
+ WAD := TWADFile.Create();
+ if not WAD.ReadFile(GameWAD) then raise Exception.Create('cannot load "game.wad"');
+ st := WAD.openFileStream('mapdef.txt');
+ end;
+
+ if (st = nil) then raise Exception.Create('cannot open "mapdef.txt"');
+ pr := TFileTextParser.Create(st);
+
+ try
+ dfmapdef := TDynMapDef.Create(pr);
+ except on e: Exception do
+ raise Exception.Create(Format('ERROR in "mapdef.txt" at (%s,%s): %s', [pr.line, pr.col, e.message]));
+ end;
+
+ st.Free();
+ WAD.Free();
+end;
+{$ENDIF}
+
+
function panelTypeToTag (panelType: Word): Integer;
begin
case panelType of
Len: Integer;
ok, isAnim, trigRef: Boolean;
CurTex, ntn: Integer;
-
+ {$IF DEFINED(D2D_NEW_MAP_READER)}
+ pr: TTextParser = nil;
+ st: TStream = nil;
+ wst: TSFSMemoryChunkStream = nil;
+ rec: TDynRecord;
+ {$ENDIF}
begin
mapGrid.Free();
mapGrid := nil;
- //mapTree.Free();
- //mapTree := nil;
Result := False;
gMapInfo.Map := Res;
WAD.Free();
Exit;
end;
+
//k8: why loader ignores path here?
mapResName := g_ExtractFileName(Res);
if not WAD.GetMapResource(mapResName, Data, Len) then
WAD.Free();
- // Çàãðóçêà êàðòû:
- e_WriteLog('Loading map: '+mapResName, MSG_NOTIFY);
+ if (Len < 4) then
+ begin
+ e_LogWritefln('invalid map file: ''%s''', [mapResName]);
+ FreeMem(Data);
+ exit;
+ end;
+
+ // Çàãðóçêà êàðòû:
+ e_LogWritefln('Loading map: %s', [mapResName], MSG_NOTIFY);
g_Game_SetLoadingText(_lc[I_LOAD_MAP], 0, False);
+
+ {$IF DEFINED(D2D_NEW_MAP_READER)}
+ if (PChar(Data)[0] = 'M') and (PChar(Data)[1] = 'A') and (PChar(Data)[2] = 'P') and (PByte(Data)[3] = 1) then
+ begin
+ // nothing
+ end
+ else
+ begin
+ e_LogWritefln('Loading text map: %s', [mapResName]);
+ loadMapDefinition();
+ if (dfmapdef = nil) then raise Exception.Create('internal map loader error');
+ //e_LogWritefln('***'#10'%s'#10'***', [dfmapdef.headerType.definition]);
+ wst := TSFSMemoryChunkStream.Create(Data, Len);
+ try
+ pr := TFileTextParser.Create(wst);
+ e_LogWritefln('parsing text map: %s', [mapResName]);
+ rec := dfmapdef.parseMap(pr);
+ except on e: Exception do
+ begin
+ if (pr <> nil) then e_LogWritefln('ERROR at (%s,%s): %s', [pr.line, pr.col, e.message])
+ else e_LogWritefln('ERROR: %s', [e.message]);
+ pr.Free();
+ wst.Free();
+ FreeMem(Data);
+ exit;
+ end;
+ end;
+ pr.Free();
+ //wst.Free(); // pr will do it
+ e_LogWritefln('writing text map to temporary bin storage...', []);
+ st := TMemoryStream.Create();
+ try
+ rec.writeBinTo(st);
+ Len := Integer(st.position);
+ st.position := 0;
+ FreeMem(Data);
+ GetMem(Data, Len);
+ st.ReadBuffer(Data^, Len);
+ except on e: Exception do
+ begin
+ rec.Free();
+ st.Free();
+ e_LogWritefln('ERROR: %s', [e.message]);
+ FreeMem(Data);
+ exit;
+ end;
+ end;
+ st.Free();
+ end;
+ {$ENDIF}
+
MapReader := TMapReader_1.Create();
if not MapReader.LoadMap(Data) then
begin
dplClear();
//tagmask := panelTypeToTag(PanelType);
-
- {if gdbg_map_use_tree_draw then
- begin
- mapTree.aabbQuery(x0, y0, wdt, hgt, checker, (GridTagBack or GridTagStep or GridTagWall or GridTagDoor or GridTagAcid1 or GridTagAcid2 or GridTagWater or GridTagFore));
- end
- else}
- begin
- mapGrid.forEachInAABB(x0, y0, wdt, hgt, checker, GridDrawableMask);
- end;
+ mapGrid.forEachInAABB(x0, y0, wdt, hgt, checker, GridDrawableMask);
// list will be rendered in `g_game.DrawPlayer()`
end;
@@ -2105,14 +2200,7 @@ procedure g_Map_DrawPanelShadowVolumes(lightX: Integer; lightY: Integer; radius:
end;
begin
- {if gdbg_map_use_tree_draw then
- begin
- mapTree.aabbQuery(lightX-radius, lightY-radius, radius*2, radius*2, checker, (GridTagWall or GridTagDoor));
- end
- else}
- begin
- mapGrid.forEachInAABB(lightX-radius, lightY-radius, radius*2, radius*2, checker, (GridTagWall or GridTagDoor));
- end;
+ mapGrid.forEachInAABB(lightX-radius, lightY-radius, radius*2, radius*2, checker, (GridTagWall or GridTagDoor));
end;
if (profMapCollision <> nil) then profMapCollision.sectionBeginAccum('*solids');
if gdbg_map_use_accel_coldet then
begin
- {if gdbg_map_use_tree_coldet then
+ if (Width = 1) and (Height = 1) then
begin
- //e_WriteLog(Format('coldet query: x=%d; y=%d; w=%d; h=%d', [X, Y, Width, Height]), MSG_NOTIFY);
- result := (mapTree.aabbQuery(X, Y, Width, Height, checker, tagmask) <> nil);
- if (gdbg_map_dump_coldet_tree_queries) and (mapTree.nodesVisited <> 0) then
+ if ((tagmask and SlowMask) <> 0) then
+ begin
+ // slow
+ result := (mapGrid.forEachAtPoint(X, Y, checker, tagmask) <> nil);
+ end
+ else
begin
- //e_WriteLog(Format('map collision: %d nodes visited (%d deep)', [mapTree.nodesVisited, mapTree.nodesDeepVisited]), MSG_NOTIFY);
- g_Console_Add(Format('map collision: %d nodes visited (%d deep)', [mapTree.nodesVisited, mapTree.nodesDeepVisited]));
+ // fast
+ result := (mapGrid.forEachAtPoint(X, Y, nil, tagmask) <> nil);
end;
end
- else}
+ else
begin
- if (Width = 1) and (Height = 1) then
+ if ((tagmask and SlowMask) <> 0) then
begin
- if ((tagmask and SlowMask) <> 0) then
- begin
- // slow
- result := (mapGrid.forEachAtPoint(X, Y, checker, tagmask) <> nil);
- end
- else
- begin
- // fast
- result := (mapGrid.forEachAtPoint(X, Y, nil, tagmask) <> nil);
- end;
+ // slow
+ result := (mapGrid.forEachInAABB(X, Y, Width, Height, checker, tagmask) <> nil);
end
else
begin
- if ((tagmask and SlowMask) <> 0) then
- begin
- // slow
- result := (mapGrid.forEachInAABB(X, Y, Width, Height, checker, tagmask) <> nil);
- end
- else
- begin
- // fast
- result := (mapGrid.forEachInAABB(X, Y, Width, Height, nil, tagmask) <> nil);
- end;
+ // fast
+ result := (mapGrid.forEachInAABB(X, Y, Width, Height, nil, tagmask) <> nil);
end;
end;
end
if gdbg_map_use_accel_coldet then
begin
texid := TEXTURE_NONE;
- {if gdbg_map_use_tree_coldet then
+ if (Width = 1) and (Height = 1) then
begin
- mapTree.aabbQuery(X, Y, Width, Height, checker, (GridTagWater or GridTagAcid1 or GridTagAcid2));
+ mapGrid.forEachAtPoint(X, Y, checker, (GridTagWater or GridTagAcid1 or GridTagAcid2));
end
- else}
+ else
begin
- if (Width = 1) and (Height = 1) then
- begin
- mapGrid.forEachAtPoint(X, Y, checker, (GridTagWater or GridTagAcid1 or GridTagAcid2));
- end
- else
- begin
- mapGrid.forEachInAABB(X, Y, Width, Height, checker, (GridTagWater or GridTagAcid1 or GridTagAcid2));
- end;
+ mapGrid.forEachInAABB(X, Y, Width, Height, checker, (GridTagWater or GridTagAcid1 or GridTagAcid2));
end;
result := texid;
end
diff --git a/src/shared/a_modes.inc b/src/shared/a_modes.inc
index a0ea22057a20fde14b3d03f2a2de5dcf87937d7b..2834ce096081b14bcbdaba59c75d61a91587a233 100644 (file)
--- a/src/shared/a_modes.inc
+++ b/src/shared/a_modes.inc
{$WARNINGS ON}
{$NOTES ON}
+// include support for text maps
+{$DEFINE D2D_NEW_MAP_READER}
{$IFDEF MSWINDOWS}
{$IFNDEF WINDOWS}
diff --git a/src/shared/mapdef.txt b/src/shared/mapdef.txt
index 4e172871d6a9368ea2db43eef0a4b411e9030dc1..d93b48d58bf87449d3b2b8356176eb8f26dee0a3 100644 (file)
--- a/src/shared/mapdef.txt
+++ b/src/shared/mapdef.txt
enum DirType {
DIR_LEFT, // 0
DIR_RIGHT, // 1
+ DIR_SOMETHING2, // 2
}
// triggers
diff --git a/src/shared/utils.pas b/src/shared/utils.pas
index d73d25766e0734e972f0cf5a8a099d099d2a586e..9e136495bc8792dc661c3e4fa254ee58d24974a6 100644 (file)
--- a/src/shared/utils.pas
+++ b/src/shared/utils.pas
while (len > 0) do
begin
if (len > 255) then slen := 255 else slen := Integer(len);
- Move(b^, ss[1], len);
+ Move(b^, ss[1], slen);
ss[0] := AnsiChar(slen);
result += ss;
b += slen;
index df0de0fc591a48ffe3d16ce7f68ba412fd781b85..3830af240f6f924519c5704f81f1dc9683ab0dc5 100644 (file)
--- a/src/shared/wadreader.pas
+++ b/src/shared/wadreader.pas
interface
uses
- sfs, xstreams;
+ sfs, xstreams, Classes;
type
function GetMapResource (name: AnsiString; var pData: Pointer; var Len: Integer): Boolean;
function GetMapResources (): SArray;
+ // returns `nil` if file wasn't found
+ function openFileStream (name: AnsiString): TStream;
+
property isOpen: Boolean read getIsOpen;
end;
implementation
uses
- SysUtils, Classes{, BinEditor}, e_log{, g_options}, utils, MAPSTRUCT;
+ SysUtils, e_log, utils, MAPSTRUCT;
function findDiskWad (fname: AnsiString): AnsiString;
fFileName := '';
end;
+
+//FIXME: detect text maps properly here
function TWADFile.isMapResource (idx: Integer): Boolean;
var
sign: packed array [0..2] of Char;
- fs: TStream;
+ fs: TStream = nil;
begin
result := false;
if not isOpen or (fIter = nil) then exit;
if (idx < 0) or (idx >= fIter.Count) then exit;
- fs := nil;
try
fs := fIter.volume.OpenFileByIndex(idx);
fs.readBuffer(sign, 3);
result := (sign = MAP_SIGNATURE);
+ if not result then result := (sign[0] = 'm') and (sign[1] = 'a') and (sign[2] = 'p');
except
if fs <> nil then fs.Free();
exit;
fs.Free();
end;
+
+// returns `nil` if file wasn't found
+function TWADFile.openFileStream (name: AnsiString): TStream;
+var
+ f: Integer;
+ fi: TSFSFileInfo;
+begin
+ result := nil;
+ // backwards, due to possible similar names and such
+ for f := fIter.Count-1 downto 0 do
+ begin
+ fi := fIter.Files[f];
+ if fi = nil then continue;
+ if StrEquCI1251(fi.name, name) then
+ begin
+ try
+ result := fIter.volume.OpenFileByIndex(f);
+ except
+ result := nil;
+ end;
+ if (result <> nil) then exit;
+ end;
+ end;
+end;
+
+
function removeExt (s: AnsiString): AnsiString;
var
i: Integer;
result := s;
end;
+
function TWADFile.GetResourceEx (name: AnsiString; wantMap: Boolean; var pData: Pointer; var Len: Integer): Boolean;
var
f, lastSlash: Integer;
fs: TStream;
fpp: Pointer;
rpath, rname: AnsiString;
- sign: array [0..2] of Char;
+ sign: packed array [0..2] of Char;
goodMap: Boolean;
begin
Result := False;
if wantMap then
begin
goodMap := false;
- //e_WriteLog(Format('DFWAD: checking for good map in wad [%s], file [%s] (#%d)', [fFileName, fi.fname, f]), MSG_NOTIFY);
+ {$IF DEFINED(D2D_NEW_MAP_READER_DBG)}
+ e_LogWritefln('DFWAD: checking for good map in wad [%s], file [%s] (#%d)', [fFileName, fi.fname, f]);
+ {$ENDIF}
try
fs.readBuffer(sign, 3);
goodMap := (sign = MAP_SIGNATURE);
- {
+ if not goodMap then goodMap := (sign[0] = 'm') and (sign[1] = 'a') and (sign[2] = 'p');
+ {$IF DEFINED(D2D_NEW_MAP_READER_DBG)}
if goodMap then
- e_WriteLog(Format(' GOOD map in wad [%s], file [%s] (#%d)', [fFileName, fi.fname, f]), MSG_NOTIFY)
+ e_LogWritefln(' GOOD map in wad [%s], file [%s] (#%d)', [fFileName, fi.fname, f])
else
- e_WriteLog(Format(' BAD map in wad [%s], file [%s] (#%d)', [fFileName, fi.fname, f]), MSG_NOTIFY);
- }
+ e_LogWritefln(' BAD map in wad [%s], file [%s] (#%d)', [fFileName, fi.fname, f]);
+ {$ENDIF}
except
end;
if not goodMap then
begin
- //e_WriteLog(Format(' not a map in wad [%s], file [%s] (#%d)', [fFileName, fi.fname, f]), MSG_NOTIFY);
+ {$IF DEFINED(D2D_NEW_MAP_READER_DBG)}
+ e_LogWritefln(' not a map in wad [%s], file [%s] (#%d)', [fFileName, fi.fname, f]);
+ {$ENDIF}
fs.Free();
continue;
end;
fi := fIter.Files[f];
if fi = nil then continue;
if length(fi.name) = 0 then continue;
- //e_WriteLog(Format('DFWAD: checking for map in wad [%s], file [%s] (#%d)', [fFileName, fi.fname, f]), MSG_NOTIFY);
+ {$IF DEFINED(D2D_NEW_MAP_READER)}
+ //e_LogWritefln('DFWAD: checking for map in wad [%s], file [%s] (#%d)', [fFileName, fi.fname, f]);
+ {$ENDIF}
if isMapResource(f) then
begin
s := removeExt(fi.name);
diff --git a/src/shared/xdynrec.pas b/src/shared/xdynrec.pas
index c6897578d7d6334e3f9f71f964e64753013b6338..3a31a9663c9c96ef3e0bd3d3ba2d5c8603dc679f 100644 (file)
--- a/src/shared/xdynrec.pas
+++ b/src/shared/xdynrec.pas
property internal: Boolean read mInternal write mInternal;
property ival: Integer read mIVal;
property sval: AnsiString read mSVal;
- //property list: TDynRecordArray read mRVal write mRVal;
- property maxdim: Integer read mMaxDim; // for fixed-size arrays
- property binOfs: Integer read mBinOfs; // offset in binary; <0 - none
- property recOfs: Integer read mRecOfs; // offset in record; <0 - none
property hasDefault: Boolean read mHasDefault;
property defsval: AnsiString read mDefSVal;
property ebs: TEBS read mEBS;
es: TDynEBS = nil;
tfld: TDynField;
tk: AnsiString;
+ edim: AnsiChar;
begin
// if this field should contain struct, convert type and parse struct
case mEBS of
TType.TPoint,
TType.TSize:
begin
- pr.expectDelim('(');
+ if pr.eatDelim('[') then edim := ']' else begin pr.expectDelim('('); edim := ')'; end;
mIVal := pr.expectInt();
if (mType = TType.TSize) then
begin
if (mIVal2 < 0) or (mIVal2 > 32767) then raise Exception.Create(Format('invalid %s value for field ''%s''', [getTypeName(mType), mName]));
end;
mDefined := true;
- pr.expectDelim(')');
+ pr.expectDelim(edim);
pr.expectTT(pr.TTSemi);
exit;
end;
diff --git a/src/shared/xparser.pas b/src/shared/xparser.pas
index d8b600dbc1d6340a0a16c9b8017dfde7bd9f401a..d0f0d3af202bef33b10715f495e13db098ce7dd3 100644 (file)
--- a/src/shared/xparser.pas
+++ b/src/shared/xparser.pas
// ////////////////////////////////////////////////////////////////////////// //
type
TFileTextParser = class(TTextParser)
+ private
+ const BufSize = 65536;
+
private
mFile: TStream;
+ mBuffer: PChar;
+ mBufLen: Integer;
+ mBufPos: Integer;
protected
procedure loadNextChar (); override; // loads next char into mNextChar; #0 means 'eof'
// ////////////////////////////////////////////////////////////////////////// //
constructor TFileTextParser.Create (const fname: AnsiString; loadToken: Boolean=true);
begin
+ mBuffer := nil;
mFile := openDiskFileRO(fname);
+ GetMem(mBuffer, BufSize);
+ mBufPos := 0;
+ mBufLen := mFile.Read(mBuffer^, BufSize);
+ if (mBufLen < 0) then raise Exception.Create('TFileTextParser: read error');
inherited Create(loadToken);
end;
begin
if (st = nil) then raise Exception.Create('cannot create parser for nil stream');
mFile := st;
+ GetMem(mBuffer, BufSize);
+ mBufPos := 0;
+ mBufLen := mFile.Read(mBuffer^, BufSize);
+ if (mBufLen < 0) then raise Exception.Create('TFileTextParser: read error');
inherited Create(loadToken);
end;
destructor TFileTextParser.Destroy ();
begin
+ if (mBuffer <> nil) then FreeMem(mBuffer);
mFile.Free();
inherited;
end;
procedure TFileTextParser.loadNextChar ();
-var
- rd: Integer;
begin
- rd := mFile.Read(mNextChar, 1);
- if (rd = 0) then begin mNextChar := #0; exit; end;
+ if (mBufLen = 0) then begin mNextChar := #0; exit; end;
+ if (mBufPos >= mBufLen) then
+ begin
+ mBufLen := mFile.Read(mBuffer^, BufSize);
+ if (mBufLen < 0) then raise Exception.Create('TFileTextParser: read error');
+ if (mBufLen = 0) then begin mNextChar := #0; exit; end;
+ mBufPos := 0;
+ end;
+ assert(mBufPos < mBufLen);
+ mNextChar := mBuffer[mBufPos];
+ Inc(mBufPos);
if (mNextChar = #0) then mNextChar := ' ';
end;