diff --git a/src/game/g_main.pas b/src/game/g_main.pas
index 16085cead25ca40398edda2a2a43bb8a4b6f51e6..af95f90039433fabd4834b40f6b977878b65234c 100644 (file)
--- a/src/game/g_main.pas
+++ b/src/game/g_main.pas
procedure CharPress (C: AnsiChar);
var
- {--- TO REMOVE ---}
- //GameDir: string;
- {-----------------}
-
{--- Read-only dirs ---}
GameWAD: string;
DataDirs: SSArray;
CacheDirs: SSArray;
ConfigDirs: SSArray;
ScreenshotDirs: SSArray;
+ StatsDirs: SSArray;
MapDownloadDirs: SSArray;
WadDownloadDirs: SSArray;
+ GameWADName: string = 'GAME';
+
implementation
uses
{$IFDEF LINUX}
BaseUnix,
{$ENDIF}
+{$IFDEF DARWIN}
+ MacOSAll, CocoaAll,
+{$ENDIF}
{$IFDEF USE_SDL2}
SDL2,
{$ENDIF}
var
charbuff: packed array [0..15] of AnsiChar;
binPath: AnsiString = '';
- forceCurrentDir: Boolean = false;
-
+ forceBinDir: Boolean;
function GetBinaryPath (): AnsiString;
{$IFDEF LINUX}
e_LogWriteln(' ' + dir);
end;
+{$IFDEF DARWIN}
+ function NSStringToAnsiString (s: NSString): AnsiString;
+ var i: Integer;
+ begin
+ result := '';
+ for i := 0 to s.length - 1 do
+ result := result + AnsiChar(s.characterAtIndex(i));
+ end;
+
+ function GetBundlePath (): AnsiString;
+ var pathRef: CFURLRef; pathCFStr: CFStringRef; pathStr: ShortString;
+ begin
+ pathRef := CFBundleCopyBundleURL(CFBundleGetMainBundle());
+ pathCFStr := CFURLCopyFileSystemPath(pathRef, kCFURLPOSIXPathStyle);
+ CFStringGetPascalString(pathCFStr, @pathStr, 255, CFStringGetSystemEncoding());
+ CFRelease(pathRef);
+ CFRelease(pathCFStr);
+ Result := pathStr;
+ end;
+{$ENDIF}
+
procedure InitPath;
var i: Integer; rwdir, rodir: AnsiString; rwdirs, rodirs: SSArray;
- //first: Boolean = true;
- procedure xput (s: AnsiString);
- {
- var
- f: TextFile;
+ procedure AddDir (var dirs: SSArray; append: AnsiString);
begin
- AssignFile(f, 'zzz.log');
- if (first) then
- begin
- Rewrite(f);
- first := false;
- end
- else
- begin
- Append(f);
- end;
- writeln(f, s);
- CloseFile(f);
+ SetLength(dirs, Length(dirs) + 1);
+ dirs[High(dirs)] := ExpandFileName(append)
end;
- }
+
+ function IsSep (ch: Char): Boolean;
begin
+ {$IFDEF WINDOWS}
+ result := (ch = '/') or (ch = '\');
+ {$ELSE}
+ result := (ch = '/');
+ {$ENDIF}
end;
- procedure AddPath (var arr: SSArray; str: AnsiString; usecwd: Boolean=true);
- var
- ss: ShortString;
+ function OptimizePath (dir: AnsiString): AnsiString;
+ var i, len: Integer; s: AnsiString;
begin
- if (length(str) = 0) then exit;
- //writeln('NEW PATH(0): ['+str+']');
- if (forceCurrentDir or usecwd) then
- begin
- str := fixSlashes(ExpandFileName(str));
- end
- else
+ i := 1; len := Length(dir); s := '';
+ while i <= len do
begin
- str := fixSlashes(str);
- if (not isAbsolutePath(str)) then str := binPath+str;
- while (length(str) > 0) do
+ if IsSep(dir[i]) then
begin
- if (isRootPath(str)) then exit;
- if (str[length(str)] = '/') then begin Delete(str, length(str), 1); continue; end;
- if (length(str) >= 2) and (Copy(str, length(str)-1, 2) = '/.') then begin Delete(str, length(str)-1, 2); continue; end;
- break;
- end;
- end;
- if (length(str) = 0) then exit;
- if (length(str) > 255) then
- begin
- xput('path too long: ['+str+']');
- raise Exception.Create(Format('path "%s" too long', [str]));
+ s := s + DirectorySeparator;
+ Inc(i);
+ while (i <= len) and IsSep(dir[i]) do Inc(i);
+ if (i <= len) and (dir[i] = '.') then
+ begin
+ if (i = len) or IsSep(dir[i + 1]) then
+ begin
+ Inc(i)
+ end
+ else if (i + 1 <= len) and (dir[i + 1] = '.') then
+ begin
+ if (i + 1 = len) or IsSep(dir[i + 2]) then
+ begin
+ s := e_UpperDir(s);
+ Inc(i, 2)
+ end
+ end
+ end
+ end
+ else
+ begin
+ s := s + dir[i];
+ Inc(i)
+ end
end;
- for ss in arr do
+ result := s
+ end;
+
+ procedure OptimizeDirs (var dirs: SSArray);
+ var i, j, k: Integer;
+ begin
+ for i := 0 to High(dirs) do
+ dirs[i] := OptimizePath(dirs[i]);
+ // deduplicate
+ i := High(dirs);
+ while i >= 0 do
begin
- //writeln('<<<', ss, '>>> : [', str, ']');
- if (ss = str) then exit;
- end;
- SetLength(arr, Length(arr)+1);
- //arr[High(arr)] := ExpandFileName(str);
- arr[High(arr)] := str;
- //writeln('NEW PATH(1): ['+str+']');
+ j := 0;
+ while j < i do
+ begin
+ if dirs[j] = dirs[i] then
+ begin
+ for k := j + 1 to High(dirs) do
+ dirs[k - 1] := dirs[k];
+ Dec(i);
+ SetLength(dirs, High(dirs))
+ end
+ else
+ begin
+ Inc(j)
+ end
+ end;
+ Dec(i)
+ end
end;
procedure AddDef (var dirs: SSArray; base: SSArray; append: AnsiString);
begin
if Length(dirs) = 0 then
for s in base do
- AddPath(dirs, e_CatPath(s, append), false)
- end;
-
- procedure AddDir (var dirs: SSArray; append: AnsiString);
- begin
- SetLength(dirs, Length(dirs) + 1);
- dirs[High(dirs)] := append
+ AddDir(dirs, e_CatPath(s, append));
+ OptimizeDirs(dirs)
end;
function GetDefaultRODirs (): SSArray;
- {$IFDEF UNIX}
+ {$IF DEFINED(UNIX) AND NOT DEFINED(DARWIN) AND NOT DEFINED(ANDROID)}
var home: AnsiString;
{$ENDIF}
- begin
- {$IFDEF USE_SDL2}
- AddDir(result, SDL_GetBasePath());
- AddDir(result, SDL_GetPrefPath('', 'doom2df'));
+ {$IFDEF WINDOWS}
+ var appdata: AnsiString;
{$ENDIF}
- {$IFDEF UNIX}
- AddDir(result, '/usr/share/doom2df');
- AddDir(result, '/usr/local/share/doom2df');
- home := GetEnvironmentVariable('HOME');
- if home <> '' then
- AddDir(result, e_CatPath(home, '.doom2df'));
+ {$IFDEF DARWIN}
+ var bundle, s: AnsiString; dirArr: NSArray; i: Integer;
{$ENDIF}
- {$IF DEFINED(ANDROID) AND DEFINED(USE_SDL2)}
- AddDir(result, SDL_AndroidGetInternalStoragePath());
- if SDL_AndroidGetExternalStorageState() <> 0 then
- AddDir(result, SDL_AndroidGetExternalStoragePath());
+ begin
+ result := nil;
+ {$IFDEF DARWIN}
+ bundle := GetBundlePath();
+ if ExtractFileExt(bundle) <> '.app' then
+ AddDir(result, binpath);
+ {$ELSE}
+ AddDir(result, binPath);
{$ENDIF}
- AddDir(result, '.');
+ if forceBinDir = false then
+ begin
+ {$IFDEF USE_SDL2}
+ AddDir(result, SDL_GetBasePath());
+ AddDir(result, SDL_GetPrefPath('', 'doom2df'));
+ {$ENDIF}
+ {$IFDEF WINDOWS}
+ appdata := GetEnvironmentVariable('APPDATA') + '\doom2df';
+ if appdata <> '' then
+ AddDir(result, appdata);
+ {$ENDIF}
+ {$IF DEFINED(UNIX) AND NOT DEFINED(DARWIN) AND NOT DEFINED(ANDROID)}
+ AddDir(result, '/usr/share/doom2df');
+ AddDir(result, '/usr/local/share/doom2df');
+ home := GetEnvironmentVariable('HOME');
+ if home <> '' then
+ AddDir(result, e_CatPath(home, '.doom2df'));
+ {$ENDIF}
+ {$IFDEF DARWIN}
+ bundle := GetBundlePath();
+ if bundle <> '' then
+ AddDir(result, e_CatPath(bundle, 'Contents/Resources'));
+ dirArr := NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, true);
+ for i := 0 to dirArr.count - 1 do
+ begin
+ s := NSStringToAnsiString(dirArr.objectAtIndex(i));
+ AddDir(result, e_CatPath(s, 'Doom 2D Forever'))
+ end;
+ {$ENDIF}
+ {$IF DEFINED(ANDROID) AND DEFINED(USE_SDL2)}
+ AddDir(result, SDL_AndroidGetInternalStoragePath());
+ if SDL_AndroidGetExternalStorageState() <> 0 then
+ AddDir(result, SDL_AndroidGetExternalStoragePath());
+ {$ENDIF}
+ end
end;
function GetDefaultRWDirs (): SSArray;
- {$IFDEF UNIX}
+ {$IF DEFINED(UNIX) AND NOT DEFINED(DARWIN) AND NOT DEFINED(ANDROID)}
var home: AnsiString;
{$ENDIF}
- begin
- {$IF DEFINED(USE_SDL2)}
- AddDir(result, SDL_GetPrefPath('', 'doom2df'));
+ {$IFDEF WINDOWS}
+ var appdata: AnsiString;
{$ENDIF}
- {$IFDEF UNIX}
- home := GetEnvironmentVariable('HOME');
- if home <> '' then
- AddDir(result, e_CatPath(home, '.doom2df'));
+ {$IFDEF DARWIN}
+ var bundle, s: AnsiString; dirArr: NSArray; i: Integer;
{$ENDIF}
- {$IF DEFINED(ANDROID) AND DEFINED(USE_SDL2)}
- if SDL_AndroidGetExternalStorageState() <> 0 then
- AddDir(result, SDL_AndroidGetExternalStoragePath());
+ begin
+ result := nil;
+ {$IFDEF DARWIN}
+ bundle := GetBundlePath();
+ if ExtractFileExt(bundle) <> '.app' then
+ AddDir(result, binPath);
+ {$ELSE}
+ AddDir(result, binPath);
{$ENDIF}
- AddDir(result, '.');
+ if forceBinDir = false then
+ begin
+ {$IFDEF USE_SDL2}
+ AddDir(result, SDL_GetPrefPath('', 'doom2df'));
+ {$ENDIF}
+ {$IFDEF WINDOWS}
+ appdata := GetEnvironmentVariable('APPDATA') + '\doom2df';
+ if appdata <> '' then
+ AddDir(result, appdata);
+ {$ENDIF}
+ {$IF DEFINED(UNIX) AND NOT DEFINED(DARWIN) AND NOT DEFINED(ANDROID)}
+ home := GetEnvironmentVariable('HOME');
+ if home <> '' then
+ AddDir(result, e_CatPath(home, '.doom2df'));
+ {$ENDIF}
+ {$IFDEF DARWIN}
+ dirArr := NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, true);
+ for i := 0 to dirArr.count - 1 do
+ begin
+ s := NSStringToAnsiString(dirArr.objectAtIndex(i));
+ AddDir(result, e_CatPath(s, 'Doom 2D Forever'))
+ end;
+ {$ENDIF}
+ {$IF DEFINED(ANDROID) AND DEFINED(USE_SDL2)}
+ if SDL_AndroidGetExternalStorageState() <> 0 then
+ AddDir(result, SDL_AndroidGetExternalStoragePath());
+ {$ENDIF}
+ end
end;
begin
- //GetDir(0, GameDir);
+ forceBinDir := false;
binPath := GetBinaryPath();
- xput('binPath=['+binPath+']');
-
- for i := 1 to ParamCount do
- begin
- if (ParamStr(i) = '--cwd') then
- begin
- forceCurrentDir := true;
- break
- end
- end;
i := 1;
while i < ParamCount do
begin
case ParamStr(i) of
+ '--like-windoze': forceBinDir := true;
'--rw-dir':
begin
Inc(i);
rwdir := ParamStr(i);
(* RW *)
- AddPath(LogDirs, e_CatPath(rwdir, ''));
- AddPath(SaveDirs, e_CatPath(rwdir, 'data'));
- AddPath(CacheDirs, e_CatPath(rwdir, 'data/cache'));
- AddPath(ConfigDirs, e_CatPath(rwdir, ''));
- AddPath(MapDownloadDirs, e_CatPath(rwdir, 'maps/downloads'));
- AddPath(WadDownloadDirs, e_CatPath(rwdir, 'wads/downloads'));
- AddPath(ScreenshotDirs, e_CatPath(rwdir, 'screenshots'));
+ AddDir(LogDirs, e_CatPath(rwdir, ''));
+ AddDir(SaveDirs, e_CatPath(rwdir, 'data'));
+ AddDir(CacheDirs, e_CatPath(rwdir, 'data/cache'));
+ AddDir(ConfigDirs, e_CatPath(rwdir, ''));
+ AddDir(MapDownloadDirs, e_CatPath(rwdir, 'maps/downloads'));
+ AddDir(WadDownloadDirs, e_CatPath(rwdir, 'wads/downloads'));
+ AddDir(ScreenshotDirs, e_CatPath(rwdir, 'screenshots'));
+ AddDir(StatsDirs, e_CatPath(rwdir, 'stats'));
(* RO *)
- AddPath(DataDirs, e_CatPath(rwdir, 'data'));
- AddPath(ModelDirs, e_CatPath(rwdir, 'data/models'));
- AddPath(MegawadDirs, e_CatPath(rwdir, 'maps/megawads'));
- AddPath(MapDirs, e_CatPath(rwdir, 'maps'));
- AddPath(WadDirs, e_CatPath(rwdir, 'wads'));
+ AddDir(DataDirs, e_CatPath(rwdir, 'data'));
+ AddDir(ModelDirs, e_CatPath(rwdir, 'data/models'));
+ AddDir(MegawadDirs, e_CatPath(rwdir, 'maps/megawads'));
+ AddDir(MapDirs, e_CatPath(rwdir, 'maps'));
+ AddDir(WadDirs, e_CatPath(rwdir, 'wads'));
end;
'--ro-dir':
begin
Inc(i);
rodir := ParamStr(i);
(* RO *)
- AddPath(DataDirs, e_CatPath(rodir, 'data'));
- AddPath(ModelDirs, e_CatPath(rodir, 'data/models'));
- AddPath(MegawadDirs, e_CatPath(rodir, 'maps/megawads'));
- AddPath(MapDirs, e_CatPath(rodir, 'maps'));
- AddPath(WadDirs, e_CatPath(rodir, 'wads'));
+ AddDir(DataDirs, e_CatPath(rodir, 'data'));
+ AddDir(ModelDirs, e_CatPath(rodir, 'data/models'));
+ AddDir(MegawadDirs, e_CatPath(rodir, 'maps/megawads'));
+ AddDir(MapDirs, e_CatPath(rodir, 'maps'));
+ AddDir(WadDirs, e_CatPath(rodir, 'wads'));
+ end;
+ '--game-wad':
+ begin
+ Inc(i);
+ GameWADName := ParamStr(i);
+ end;
+ '--config':
+ begin
+ Inc(i);
+ gConfigScript := ParamStr(i);
end;
end;
Inc(i)
end;
+ // prefer bin dir if it writable and contains game.wad
+ if forceBinDir = false then
+ begin
+ if findDiskWad(binPath + 'data' + '/' + GameWADName) <> '' then
+ if e_CanCreateFilesAt(binPath) then
+ forceBinDir := true
+ end;
+
(* RO *)
rodirs := GetDefaultRODirs();
AddDef(DataDirs, rodirs, 'data');
AddDef(MapDownloadDirs, rwdirs, 'maps/downloads');
AddDef(WadDownloadDirs, rwdirs, 'wads/downloads');
AddDef(ScreenshotDirs, rwdirs, 'screenshots');
+ AddDef(StatsDirs, rwdirs, 'stats');
for i := 0 to High(MapDirs) do
- AddPath(AllMapDirs, MapDirs[i]);
+ AddDir(AllMapDirs, MapDirs[i]);
for i := 0 to High(MegawadDirs) do
- AddPath(AllMapDirs, MegawadDirs[i]);
+ AddDir(AllMapDirs, MegawadDirs[i]);
+ OptimizeDirs(AllMapDirs);
if LogFileName = '' then
begin
{$ENDIF}
end
end;
-
- xput('binPath=['+binPath+']');
+
+ // HACK: ensure the screenshots folder also has a stats subfolder in it
+ rwdir := e_GetWriteableDir(ScreenshotDirs, false);
+ if rwdir <> '' then CreateDir(rwdir + '/stats');
end;
procedure InitPrep;
{$ENDIF}
for i := 1 to ParamCount do
begin
- if (ParamStr(i) = '--con-stdout') then
- begin
- conbufDumpToStdOut := true;
- break
+ case ParamStr(i) of
+ '--con-stdout': conbufDumpToStdOut := true;
+ '--no-fbo': glRenderToFBO := false;
end
end;
e_InitWritelnDriver();
e_WriteLog('Doom 2D: Forever version ' + GAME_VERSION + ' proto ' + IntToStr(NET_PROTOCOL_VER), TMsgType.Notify);
e_WriteLog('Build date: ' + GAME_BUILDDATE + ' ' + GAME_BUILDTIME, TMsgType.Notify);
+ e_WriteLog('Build hash: ' + g_GetBuildHash(), TMsgType.Notify);
+ e_WriteLog('Build by: ' + g_GetBuilderName(), TMsgType.Notify);
+ e_LogWritefln('Force bin dir: %s', [forceBinDir], TMsgType.Notify);
e_LogWritefln('BINARY PATH: [%s]', [binPath], TMsgType.Notify);
PrintDirs('DataDirs', DataDirs);
PrintDirs('CacheDirs', CacheDirs);
PrintDirs('ConfigDirs', ConfigDirs);
PrintDirs('ScreenshotDirs', ScreenshotDirs);
+ PrintDirs('StatsDirs', StatsDirs);
PrintDirs('MapDownloadDirs', MapDownloadDirs);
PrintDirs('WadDownloadDirs', WadDownloadDirs);
- GameWAD := e_FindWad(DataDirs, 'GAME');
+ GameWAD := e_FindWad(DataDirs, GameWADName);
if GameWad = '' then
begin
- e_WriteLog('GAME.WAD not installed?', TMsgType.Fatal);
- {$IFDEF USE_SDL2}
- SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, 'Doom 2D Forever', 'GAME.WAD not installed?', nil);
+ e_WriteLog('WAD ' + GameWADName + ' not found in data directories.', TMsgType.Fatal);
+ {$IF DEFINED(USE_SDL2) AND NOT DEFINED(HEADLESS)}
+ if forceBinDir = false then
+ SDL_ShowSimpleMessageBox(
+ SDL_MESSAGEBOX_ERROR,
+ 'Doom 2D Forever',
+ PChar('WAD ' + GameWADName + ' not found in data directories.'),
+ nil
+ );
{$ENDIF}
+ e_DeinitLog;
Halt(1);
end;
{$IFDEF ENABLE_HOLMES}
var flexloaded: Boolean;
{$ENDIF}
- var s: AnsiString;
begin
InitPath;
InitPrep;
e_InitInput;
sys_Init;
- s := CONFIG_FILENAME;
- if e_FindResource(ConfigDirs, s) = true then
- begin
- g_Options_Read(s)
- end
- else
- begin
- g_Options_SetDefault;
- g_Options_SetDefaultVideo
- end;
- if sys_SetDisplayMode(gScreenWidth, gScreenHeight, gBPP, gFullScreen) = False then
+ g_Options_SetDefault;
+ g_Options_SetDefaultVideo;
+ g_Console_SysInit;
+ if sys_SetDisplayMode(gRC_Width, gRC_Height, gBPP, gRC_FullScreen, gRC_Maximized) = False then
raise Exception.Create('Failed to set videomode on startup.');
- g_Console_SysInit;
e_WriteLog(gLanguage, TMsgType.Notify);
g_Language_Set(gLanguage);
if assigned(oglDeinitCB) then oglDeinitCB;
{$ENDIF}
+ g_Console_WriteGameConfig;
sys_Final;
end;
procedure Update ();
begin
+ // remember old mobj positions, prepare for update
+ g_Game_PreUpdate();
+ // server: receive client commands for new frame
+ // client: receive game state changes from server
+ if (NetMode = NET_SERVER) then g_Net_Host_Update()
+ else if (NetMode = NET_CLIENT) then g_Net_Client_Update();
+ // think
g_Game_Update();
+ // server: send any accumulated outgoing data to clients
+ if NetMode = NET_SERVER then g_Net_Flush();
end;