--- a/.hgignore Sat Jan 03 00:30:30 2015 +0300
+++ b/.hgignore Sat Jan 03 23:46:26 2015 +0300
@@ -65,3 +65,6 @@
glob:*.tar.*
glob:*.or
glob:*.res
+glob:build-*
+glob:hedgewars-build-*
+glob:*.pro.user
--- a/CMakeLists.txt Sat Jan 03 00:30:30 2015 +0300
+++ b/CMakeLists.txt Sat Jan 03 23:46:26 2015 +0300
@@ -27,7 +27,7 @@
option(LUA_SYSTEM "Use system lua (on)" ON)
endif()
-option(BUILD_ENGINE_LIBRARY "Enable hwengine library (off)" OFF)
+set(BUILD_ENGINE_LIBRARY ON)
option(ANDROID "Enable Android build (off)" OFF)
option(MINIMAL_FLAGS "Respect system flags as much as possible (off)" OFF)
--- a/QTfrontend/net/tcpBase.cpp Sat Jan 03 00:30:30 2015 +0300
+++ b/QTfrontend/net/tcpBase.cpp Sat Jan 03 23:46:26 2015 +0300
@@ -111,8 +111,6 @@
m_connected(false),
IPCSocket(0)
{
- process = 0;
-
if(!IPCServer)
{
IPCServer = new QTcpServer(0);
--- a/hedgewars/ArgParsers.pas Sat Jan 03 00:30:30 2015 +0300
+++ b/hedgewars/ArgParsers.pas Sat Jan 03 23:46:26 2015 +0300
@@ -121,17 +121,6 @@
SetVolume(0);
end;
-procedure setIpcPort(port: LongInt; var wrongParameter:Boolean);
-begin
- if isInternal then
- ipcPort := port
- else
- begin
- WriteLn(stderr, 'ERROR: use of --port is not allowed');
- wrongParameter := true;
- end
-end;
-
function parseNick(nick: shortstring): shortstring;
begin
if isInternal then
@@ -215,12 +204,12 @@
otherarray: array [0..2] of string = ('--locale','--fullscreen','--showfps');
mediaarray: array [0..9] of string = ('--fullscreen-width', '--fullscreen-height', '--width', '--height', '--depth', '--volume','--nomusic','--nosound','--locale','--fullscreen');
allarray: array [0..17] of string = ('--fullscreen-width','--fullscreen-height', '--width', '--height', '--depth','--volume','--nomusic','--nosound','--locale','--fullscreen','--showfps','--altdmg','--frame-interval','--low-quality','--no-teamtag','--no-hogtag','--no-healthtag','--translucent-tags');
- reallyAll: array[0..35] of shortstring = (
- '--prefix', '--user-prefix', '--locale', '--fullscreen-width', '--fullscreen-height', '--width',
+ reallyAll: array[0..32] of shortstring = (
+ '--locale', '--fullscreen-width', '--fullscreen-height', '--width',
'--height', '--frame-interval', '--volume','--nomusic', '--nosound',
'--fullscreen', '--showfps', '--altdmg', '--low-quality', '--raw-quality', '--stereo', '--nick',
{deprecated} '--depth', '--set-video', '--set-audio', '--set-other', '--set-multimedia', '--set-everything',
- {internal} '--internal', '--port', '--recorder', '--landpreview',
+ {internal} '--internal', '--recorder', '--landpreview',
{misc} '--stats-only', '--gci', '--help','--no-teamtag','--no-hogtag','--no-healthtag','--translucent-tags','--lua-test');
var cmdIndex: byte;
begin
@@ -232,45 +221,42 @@
while (cmdIndex <= High(reallyAll)) and (cmd <> reallyAll[cmdIndex]) do inc(cmdIndex);
case cmdIndex of
- {--prefix} 0 : PathPrefix := getstringParameter (arg, paramIndex, parseParameter);
- {--user-prefix} 1 : UserPathPrefix := getstringParameter (arg, paramIndex, parseParameter);
- {--locale} 2 : cLocaleFName := getstringParameter (arg, paramIndex, parseParameter);
- {--fullscreen-width} 3 : cFullscreenWidth := max(getLongIntParameter(arg, paramIndex, parseParameter), cMinScreenWidth);
- {--fullscreen-height} 4 : cFullscreenHeight := max(getLongIntParameter(arg, paramIndex, parseParameter), cMinScreenHeight);
- {--width} 5 : cWindowedWidth := max(2 * (getLongIntParameter(arg, paramIndex, parseParameter) div 2), cMinScreenWidth);
- {--height} 6 : cWindowedHeight := max(2 * (getLongIntParameter(arg, paramIndex, parseParameter) div 2), cMinScreenHeight);
- {--frame-interval} 7 : cTimerInterval := getLongIntParameter(arg, paramIndex, parseParameter);
- {--volume} 8 : SetVolume ( max(getLongIntParameter(arg, paramIndex, parseParameter), 0) );
- {--nomusic} 9 : SetMusic ( false );
- {--nosound} 10 : SetSound ( false );
- {--fullscreen} 11 : cFullScreen := true;
- {--showfps} 12 : cShowFPS := true;
- {--altdmg} 13 : cAltDamage := true;
- {--low-quality} 14 : cReducedQuality := $FFFFFFFF xor rqLowRes;
- {--raw-quality} 15 : cReducedQuality := getLongIntParameter(arg, paramIndex, parseParameter);
- {--stereo} 16 : setStereoMode ( getLongIntParameter(arg, paramIndex, parseParameter) );
- {--nick} 17 : UserNick := parseNick( getstringParameter(arg, paramIndex, parseParameter) );
+ {--locale} 0 : cLocaleFName := getstringParameter (arg, paramIndex, parseParameter);
+ {--fullscreen-width} 1 : cFullscreenWidth := max(getLongIntParameter(arg, paramIndex, parseParameter), cMinScreenWidth);
+ {--fullscreen-height} 2 : cFullscreenHeight := max(getLongIntParameter(arg, paramIndex, parseParameter), cMinScreenHeight);
+ {--width} 3 : cWindowedWidth := max(2 * (getLongIntParameter(arg, paramIndex, parseParameter) div 2), cMinScreenWidth);
+ {--height} 4 : cWindowedHeight := max(2 * (getLongIntParameter(arg, paramIndex, parseParameter) div 2), cMinScreenHeight);
+ {--frame-interval} 5 : cTimerInterval := getLongIntParameter(arg, paramIndex, parseParameter);
+ {--volume} 6 : SetVolume ( max(getLongIntParameter(arg, paramIndex, parseParameter), 0) );
+ {--nomusic} 7 : SetMusic ( false );
+ {--nosound} 8 : SetSound ( false );
+ {--fullscreen} 9 : cFullScreen := true;
+ {--showfps} 10 : cShowFPS := true;
+ {--altdmg} 11 : cAltDamage := true;
+ {--low-quality} 12 : cReducedQuality := $FFFFFFFF xor rqLowRes;
+ {--raw-quality} 13 : cReducedQuality := getLongIntParameter(arg, paramIndex, parseParameter);
+ {--stereo} 14 : setStereoMode ( getLongIntParameter(arg, paramIndex, parseParameter) );
+ {--nick} 15 : UserNick := parseNick( getstringParameter(arg, paramIndex, parseParameter) );
{deprecated options}
- {--depth} 18 : setDepth(paramIndex);
- {--set-video} 19 : parseClassicParameter(videoarray,5,paramIndex);
- {--set-audio} 20 : parseClassicParameter(audioarray,3,paramIndex);
- {--set-other} 21 : parseClassicParameter(otherarray,3,paramIndex);
- {--set-multimedia} 22 : parseClassicParameter(mediaarray,10,paramIndex);
- {--set-everything} 23 : parseClassicParameter(allarray,14,paramIndex);
+ {--depth} 16 : setDepth(paramIndex);
+ {--set-video} 17 : parseClassicParameter(videoarray,5,paramIndex);
+ {--set-audio} 18 : parseClassicParameter(audioarray,3,paramIndex);
+ {--set-other} 19 : parseClassicParameter(otherarray,3,paramIndex);
+ {--set-multimedia} 20 : parseClassicParameter(mediaarray,10,paramIndex);
+ {--set-everything} 21 : parseClassicParameter(allarray,14,paramIndex);
{"internal" options}
- {--internal} 24 : {$IFDEF HWLIBRARY}isInternal:= true{$ENDIF};
- {--port} 25 : setIpcPort( getLongIntParameter(arg, paramIndex, parseParameter), parseParameter );
- {--recorder} 26 : startVideoRecording(paramIndex);
- {--landpreview} 27 : GameType := gmtLandPreview;
+ {--internal} 22 : {$IFDEF HWLIBRARY}isInternal:= true{$ENDIF};
+ {--recorder} 23 : startVideoRecording(paramIndex);
+ {--landpreview} 24 : GameType := gmtLandPreview;
{anything else}
- {--stats-only} 28 : statsOnlyGame();
- {--gci} 29 : GciEasterEgg();
- {--help} 30 : DisplayUsage();
- {--no-teamtag} 31 : cTagsMask := cTagsMask and (not htTeamName);
- {--no-hogtag} 32 : cTagsMask := cTagsMask and (not htName);
- {--no-healthtag} 33 : cTagsMask := cTagsMask and (not htHealth);
- {--translucent-tags} 34 : cTagsMask := cTagsMask or htTransparent;
- {--lua-test} 35 : begin cTestLua := true; SetSound(false); cScriptName := getstringParameter(arg, paramIndex, parseParameter); WriteLn(stdout, 'Lua test file specified: ' + cScriptName);end;
+ {--stats-only} 25 : statsOnlyGame();
+ {--gci} 26 : GciEasterEgg();
+ {--help} 27 : DisplayUsage();
+ {--no-teamtag} 28 : cTagsMask := cTagsMask and (not htTeamName);
+ {--no-hogtag} 29 : cTagsMask := cTagsMask and (not htName);
+ {--no-healthtag} 30 : cTagsMask := cTagsMask and (not htHealth);
+ {--translucent-tags} 31 : cTagsMask := cTagsMask or htTransparent;
+ {--lua-test} 32: begin cTestLua := true; SetSound(false); cScriptName := getstringParameter(arg, paramIndex, parseParameter); WriteLn(stdout, 'Lua test file specified: ' + cScriptName);end;
else
begin
//Assume the first "non parameter" is the replay file, anything else is invalid
@@ -332,12 +318,12 @@
paramTotal: LongInt;
index, nextIndex: LongInt;
wrongParameter: boolean;
-//var tmpInt: LongInt;
+var tmpInt: LongInt;
begin
paramIndex:= 1;
paramTotal:= ParamCount; //-1 because pascal enumeration is inclusive
- (*
+
WriteLn(stdout, 'total parameters: ' + inttostr(paramTotal));
tmpInt:= 0;
while (tmpInt <= paramTotal) do
@@ -345,7 +331,7 @@
WriteLn(stdout, inttostr(tmpInt) + ': ' + {$IFDEF HWLIBRARY}argv[tmpInt]{$ELSE}paramCount(tmpInt){$ENDIF});
inc(tmpInt);
end;
- *)
+
wrongParameter:= false;
while (paramIndex <= paramTotal) do
begin
@@ -362,26 +348,29 @@
procedure GetParams;
begin
- isInternal:= (ParamStr(1) = '--internal');
-
- UserPathPrefix := _S'.';
- PathPrefix := cDefaultPathPrefix;
- recordFileName := '';
- parseCommandLine();
-
- if (isInternal) and (ParamCount<=1) then
+ if ParamCount > 0 then
begin
- WriteLn(stderr, '--internal should not be manually used');
- GameType := gmtSyntax;
- end;
+ isInternal:= (ParamStr(1) = '--internal');
+
+ recordFileName := '';
+ parseCommandLine();
+
+ if (isInternal) and (ParamCount<=1) then
+ begin
+ WriteLn(stderr, '--internal should not be manually used');
+ GameType := gmtSyntax;
+ end;
- if (not cTestLua) and (not isInternal) and (recordFileName = '') then
- begin
- WriteLn(stderr, 'You must specify a replay file');
- GameType := gmtSyntax;
- end
- else if (recordFileName <> '') then
- WriteLn(stdout, 'Attempting to play demo file "' + recordFilename + '"');
+ if (not cTestLua) and (not isInternal) and (recordFileName = '') then
+ begin
+ WriteLn(stderr, 'You must specify a replay file');
+ GameType := gmtSyntax;
+ end
+ else if (recordFileName <> '') then
+ WriteLn(stdout, 'Attempting to play demo file "' + recordFilename + '"');
+ end
+ else
+ GameType:= gmtSyntax;
if (GameType = gmtSyntax) then
WriteLn(stderr, 'Please use --help to see possible arguments and their usage');
--- a/hedgewars/CMakeLists.txt Sat Jan 03 00:30:30 2015 +0300
+++ b/hedgewars/CMakeLists.txt Sat Jan 03 23:46:26 2015 +0300
@@ -100,6 +100,15 @@
uGearsUtils.pas
uTeams.pas
+ uFLData.pas
+ uFLGameConfig.pas
+ uFLIPC.pas
+ uFLScripts.pas
+ uFLSchemes.pas
+ uFLTeams.pas
+ uFLTypes.pas
+ uFLUtils.pas
+
#these interact with everything, so compile last
uScript.pas
)
--- a/hedgewars/SDLh.pas Sat Jan 03 00:30:30 2015 +0300
+++ b/hedgewars/SDLh.pas Sat Jan 03 23:46:26 2015 +0300
@@ -842,6 +842,8 @@
PSDL_Thread = Pointer;
PSDL_mutex = Pointer;
+ PSDL_sem = Pointer;
+ PSDL_cond = Pointer;
TSDL_GLattr = (
SDL_GL_RED_SIZE,
@@ -1064,6 +1066,23 @@
function SDL_LockMutex(mutex: PSDL_mutex): LongInt; cdecl; external SDLLibName {$IFNDEF SDL2}name 'SDL_mutexP'{$ENDIF};
function SDL_UnlockMutex(mutex: PSDL_mutex): LongInt; cdecl; external SDLLibName {$IFNDEF SDL2}name 'SDL_mutexV'{$ENDIF};
+function SDL_CreateCond: PSDL_cond; cdecl; external SDLLibName;
+procedure SDL_DestroyCond(cond: PSDL_cond); cdecl; external SDLLibName;
+function SDL_CondSignal(cond: PSDL_cond): LongInt; cdecl; external SDLLibName;
+function SDL_CondBroadcast(cond: PSDL_cond): LongInt; cdecl; external SDLLibName;
+function SDL_CondWait(cond: PSDL_cond; mut: PSDL_mutex): LongInt; cdecl; external SDLLibName;
+function SDL_CondWaitTimeout(cond: PSDL_cond; mut: PSDL_mutex; ms: Longword): LongInt; cdecl; external SDLLibName;
+
+
+function SDL_CreateSemaphore(initial_value: Longword): PSDL_sem; cdecl; external SDLLibName;
+procedure SDL_DestroySemaphore(sem: PSDL_sem); cdecl; external SDLLibName;
+function SDL_SemWait(sem: PSDL_sem): LongInt; cdecl; external SDLLibName;
+function SDL_SemTryWait(sem: PSDL_sem): LongInt; cdecl; external SDLLibName;
+function SDL_SemWaitTimeout(sem: PSDL_sem; ms: Longword): LongInt; cdecl; external SDLLibName;
+function SDL_SemPost(sem: PSDL_sem): LongInt; cdecl; external SDLLibName;
+function SDL_SemValue(sem: PSDL_sem): Longword; cdecl; external SDLLibName;
+
+
function SDL_GL_SetAttribute(attr: TSDL_GLattr; value: LongInt): LongInt; cdecl; external SDLLibName;
procedure SDL_GL_SwapBuffers; cdecl; external SDLLibName;
--- a/hedgewars/hwLibrary.pas Sat Jan 03 00:30:30 2015 +0300
+++ b/hedgewars/hwLibrary.pas Sat Jan 03 23:46:26 2015 +0300
@@ -29,65 +29,93 @@
Library hwLibrary;
-uses hwengine, uTypes, uConsts, uVariables, uSound, uCommands, uUtils,
- uLocale{$IFDEF ANDROID}, jni{$ENDIF};
+uses hwengine
+ , uTypes
+ , uConsts
+ , uVariables
+ , uSound
+ , uCommands
+ , uUtils
+ , uLocale
+ {$IFDEF ANDROID}, jni{$ENDIF}
+ , uFLTypes
+ , uFLGameConfig
+ , uFLIPC
+ , uPhysFSLayer
+ , uFLData
+ , uFLTeams
+ , uFLScripts
+ , uFLSchemes
+ ;
{$INCLUDE "config.inc"}
// retrieve protocol information
-procedure HW_versionInfo(netProto: PLongInt; versionStr: PPChar); cdecl; export;
+procedure HW_versionInfo(netProto: PLongInt; versionStr: PPChar); cdecl;
begin
netProto^:= cNetProtoVersion;
versionStr^:= cVersionString;
end;
-function HW_versionString: PChar; cdecl; export;
+function HW_versionString: PChar; cdecl;
begin
exit(cVersionString + '-r' + cRevisionString + ' (' + cHashString + ')');
end;
// equivalent to esc+y; when closeFrontend = true the game exits after memory cleanup
-procedure HW_terminate(closeFrontend: boolean); cdecl; export;
+procedure HW_terminate(closeFrontend: boolean); cdecl;
begin
closeFrontend:= closeFrontend; // avoid hint
ParseCommand('forcequit', true);
end;
-function HW_getWeaponNameByIndex(whichone: LongInt): PChar; cdecl; export;
+function HW_getWeaponNameByIndex(whichone: LongInt): PChar; cdecl;
begin
HW_getWeaponNameByIndex:= (str2pchar(trammo[Ammoz[TAmmoType(whichone+1)].NameId]));
end;
-(*function HW_getWeaponCaptionByIndex(whichone: LongInt): PChar; cdecl; export;
+(*function HW_getWeaponCaptionByIndex(whichone: LongInt): PChar; cdecl;
begin
HW_getWeaponCaptionByIndex:= (str2pchar(trammoc[Ammoz[TAmmoType(whichone+1)].NameId]));
end;
-function HW_getWeaponDescriptionByIndex(whichone: LongInt): PChar; cdecl; export;
+function HW_getWeaponDescriptionByIndex(whichone: LongInt): PChar; cdecl;
begin
HW_getWeaponDescriptionByIndex:= (str2pchar(trammod[Ammoz[TAmmoType(whichone+1)].NameId]));
end;*)
-function HW_getNumberOfWeapons: LongInt; cdecl; export;
+function HW_getNumberOfWeapons: LongInt; cdecl;
begin
HW_getNumberOfWeapons:= ord(high(TAmmoType));
end;
-function HW_getMaxNumberOfHogs: LongInt; cdecl; export;
+function HW_getMaxNumberOfHogs: LongInt; cdecl;
begin
HW_getMaxNumberOfHogs:= cMaxHHIndex + 1;
end;
-function HW_getMaxNumberOfTeams: LongInt; cdecl; export;
+function HW_getMaxNumberOfTeams: LongInt; cdecl;
begin
HW_getMaxNumberOfTeams:= cMaxTeams;
end;
-procedure HW_memoryWarningCallback; cdecl; export;
+procedure HW_memoryWarningCallback; cdecl;
begin
ReleaseSound(false);
end;
+procedure flibInit(localPrefix, userPrefix: PChar); cdecl;
+begin
+ initIPC;
+ uPhysFSLayer.initModule(localPrefix, userPrefix);
+end;
+
+procedure flibFree; cdecl;
+begin
+ uPhysFSLayer.freemodule;
+ freeIPC;
+end;
+
{$IFDEF ANDROID}
function JNI_HW_versionInfoNet(env: PJNIEnv; obj: JObject):JInt;cdecl;
begin
@@ -119,6 +147,28 @@
Game;
{$ELSE}
exports
+ runQuickGame,
+ runLocalGame,
+ getPreview,
+ registerGUIMessagesCallback,
+ flibInit,
+ flibFree,
+ resetGameConfig,
+ setSeed,
+ getSeed,
+ setTheme,
+ setScript,
+ getThemesList,
+ freeThemesList,
+ getThemeIcon,
+ getScriptsList,
+ getSchemesList,
+ getTeamsList,
+ tryAddTeam,
+ tryRemoveTeam,
+ changeTeamColor,
+
+ // dunno what these are
RunEngine,
LoadLocaleWrapper,
HW_versionInfo,
--- a/hedgewars/hwengine.pas Sat Jan 03 00:30:30 2015 +0300
+++ b/hedgewars/hwengine.pas Sat Jan 03 23:46:26 2015 +0300
@@ -22,12 +22,8 @@
{$R res/hwengine.rc}
{$ENDIF}
-{$IFDEF HWLIBRARY}
unit hwengine;
interface
-{$ELSE}
-program hwengine;
-{$ENDIF}
uses SDLh, uMisc, uConsole, uGame, uConsts, uLand, uAmmos, uVisualGears, uGears, uStore, uWorld, uInputHandler
, uSound, uScript, uTeams, uStats, uIO, uLocale, uChat, uAI, uAIMisc, uAILandMarks, uLandTexture, uCollisions
@@ -38,19 +34,12 @@
{$IFDEF ANDROID}, GLUnit{$ENDIF}
;
-{$IFDEF HWLIBRARY}
-procedure RunEngine(argc: LongInt; argv: PPChar); cdecl; export;
-
+function RunEngine(argc: LongInt; argv: PPChar): Longint; cdecl; export;
procedure preInitEverything();
procedure initEverything(complete:boolean);
procedure freeEverything(complete:boolean);
implementation
-{$ELSE}
-procedure preInitEverything(); forward;
-procedure initEverything(complete:boolean); forward;
-procedure freeEverything(complete:boolean); forward;
-{$ENDIF}
///////////////////////////////////////////////////////////////////////////////
function DoTimer(Lag: LongInt): boolean;
@@ -343,8 +332,8 @@
initEverything(true);
WriteLnToConsole('Hedgewars engine ' + cVersionString + '-r' + cRevisionString +
' (' + cHashString + ') with protocol #' + inttostr(cNetProtoVersion));
- AddFileLog('Prefix: "' + shortstring(PathPrefix) +'"');
- AddFileLog('UserPrefix: "' + shortstring(UserPathPrefix) +'"');
+ //AddFileLog('Prefix: "' + shortstring(PathPrefix) +'"');
+ //AddFileLog('UserPrefix: "' + shortstring(UserPathPrefix) +'"');
for i:= 0 to ParamCount do
AddFileLog(inttostr(i) + ': ' + ParamStr(i));
@@ -406,7 +395,6 @@
begin
if recordFileName = '' then
begin
- InitIPC;
SendIPCAndWaitReply(_S'C'); // ask for game config
end
else
@@ -465,8 +453,8 @@
uLand.initModule; // computes land
uLandPainted.initModule; // computes drawn land
uIO.initModule; // sets up sockets
- uPhysFSLayer.initModule;
uScript.initModule;
+ uTeams.initModule; // clear CurrentTeam variable
if complete then
begin
@@ -490,7 +478,6 @@
uStats.initModule;
uStore.initModule;
uRender.initModule;
- uTeams.initModule;
uVisualGears.initModule;
uVisualGearsHandlers.initModule;
uWorld.initModule;
@@ -534,7 +521,6 @@
uCommands.freeModule;
uVariables.freeModule;
uUtils.freeModule; // closes debug file
- uPhysFSLayer.freeModule;
uScript.freeModule;
end;
@@ -544,7 +530,6 @@
begin
initEverything(false);
- InitIPC;
IPCWaitPongEvent;
TryDo(InitStepsFlags = cifRandomize, 'Some parameters not set (flags = ' + inttostr(InitStepsFlags) + ')', true);
@@ -557,18 +542,21 @@
freeEverything(false);
end;
-{$IFDEF HWLIBRARY}
-procedure RunEngine(argc: LongInt; argv: PPChar); cdecl; export;
+function EngineThread(p: pointer): Longint; cdecl; export;
+begin
+ if GameType = gmtLandPreview then
+ GenLandPreview()
+ else Game();
+
+ EngineThread:= 0
+end;
+
+
+function RunEngine(argc: LongInt; argv: PPChar): Longint; cdecl; export;
begin
operatingsystem_parameter_argc:= argc;
operatingsystem_parameter_argv:= argv;
-{$ELSE}
-begin
-{$ENDIF}
-///////////////////////////////////////////////////////////////////////////////
-/////////////////////////////////// m a i n ///////////////////////////////////
-///////////////////////////////////////////////////////////////////////////////
{$IFDEF PAS2C}
// workaround for pascal's ParamStr and ParamCount
init(argc, argv);
@@ -577,36 +565,13 @@
GetParams();
- if GameType = gmtLandPreview then
- GenLandPreview()
- else if GameType <> gmtSyntax then
- Game();
-
- // return 1 when engine is not called correctly
if GameType = gmtSyntax then
- {$IFDEF PAS2C}
- exit(HaltUsageError);
- {$ELSE}
- halt(HaltUsageError);
- {$ENDIF}
-
- if cTestLua then
- begin
- WriteLnToConsole(errmsgLuaTestTerm);
- {$IFDEF PAS2C}
- exit(HaltTestUnexpected);
- {$ELSE}
- halt(HaltTestUnexpected);
- {$ENDIF}
- end;
-
- {$IFDEF PAS2C}
- exit(HaltNoError);
- {$ELSE}
- halt(HaltNoError);
- {$ENDIF}
-{$IFDEF HWLIBRARY}
+ RunEngine:= HaltUsageError
+ else
+ begin
+ SDL_CreateThread(@EngineThread{$IFDEF SDL2}, 'engine'{$ENDIF}, nil);
+ RunEngine:= 0
+ end
end;
-{$ENDIF}
end.
--- a/hedgewars/uDebug.pas Sat Jan 03 00:30:30 2015 +0300
+++ b/hedgewars/uDebug.pas Sat Jan 03 23:46:26 2015 +0300
@@ -33,12 +33,7 @@
begin
WriteLnToConsole(Msg);
if isFatalError then
- begin
ParseCommand('fatal ' + lastConsoleline, true);
- // hint for the 'coverity' source analyzer
- // this halt is never actually reached because ParseCommands will halt first
- halt(HaltFatalError);
- end;
end;
procedure TryDo(Assert: boolean; Msg: shortstring; isFatal: boolean);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hedgewars/uFLData.pas Sat Jan 03 23:46:26 2015 +0300
@@ -0,0 +1,85 @@
+unit uFLData;
+interface
+
+function getThemesList: PPChar; cdecl;
+procedure freeThemesList(list: PPChar); cdecl;
+function getThemeIcon(themeName: PChar; buffer: PChar; buflen: Longword): Longword; cdecl;
+
+const colorsSet: array[0..8] of shortstring = (
+ '16712196'
+ , '4817089'
+ , '1959610'
+ , '11878895'
+ , '10526880'
+ , '2146048'
+ , '16681742'
+ , '6239749'
+ , '16776961');
+
+implementation
+uses uPhysFSLayer;
+
+function getThemesList: PPChar; cdecl;
+var list, res, tmp: PPChar;
+ i, size: Longword;
+begin
+ list:= pfsEnumerateFiles('Themes');
+ size:= 0;
+ tmp:= list;
+ while tmp^ <> nil do
+ begin
+ inc(size);
+ inc(tmp)
+ end;
+
+ res:= GetMem((3 + size) * sizeof(PChar));
+ res^:= PChar(list);
+ inc(res);
+ res^:= PChar(res + size + 2);
+ inc(res);
+
+ getThemesList:= res;
+
+ for i:= 1 to size do
+ begin
+ if pfsExists('/Themes/' + shortstring(list^) + '/icon.png') then
+ begin
+ res^:= list^;
+ inc(res)
+ end;
+
+ inc(list)
+ end;
+
+ res^:= nil
+end;
+
+procedure freeThemesList(list: PPChar); cdecl;
+var listEnd: PPChar;
+begin
+ dec(list);
+ listEnd:= PPChar(list^);
+ dec(list);
+
+ pfsFreeList(PPChar(list^));
+ freeMem(list, (listEnd - list) * sizeof(PChar))
+end;
+
+function getThemeIcon(themeName: PChar; buffer: PChar; buflen: Longword): Longword; cdecl;
+var s: shortstring;
+ f: PFSFile;
+begin
+ s:= '/Themes/' + shortstring(themeName) + '/icon@2x.png';
+
+ f:= pfsOpenRead(s);
+
+ if f = nil then
+ getThemeIcon:= 0
+ else
+ begin
+ getThemeIcon:= pfsBlockRead(f, buffer, buflen);
+ pfsClose(f)
+ end;
+end;
+
+end.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hedgewars/uFLGameConfig.pas Sat Jan 03 23:46:26 2015 +0300
@@ -0,0 +1,326 @@
+unit uFLGameConfig;
+interface
+uses uFLTypes;
+
+procedure resetGameConfig; cdecl;
+procedure runQuickGame; cdecl;
+procedure runLocalGame; cdecl;
+procedure getPreview; cdecl;
+
+procedure registerGUIMessagesCallback(p: pointer; f: TGUICallback); cdecl;
+
+procedure setSeed(seed: PChar); cdecl;
+function getSeed: PChar; cdecl;
+procedure setTheme(themeName: PChar); cdecl;
+procedure setScript(scriptName: PChar); cdecl;
+
+procedure tryAddTeam(teamName: PChar); cdecl;
+procedure tryRemoveTeam(teamName: PChar); cdecl;
+procedure changeTeamColor(teamName: PChar; dir: LongInt); cdecl;
+
+implementation
+uses uFLIPC, hwengine, uFLUtils, uFLTeams, uFLData;
+
+var guiCallbackPointer: pointer;
+ guiCallbackFunction: TGUICallback;
+
+const
+ MAXCONFIGS = 5;
+ MAXARGS = 32;
+
+type
+ TGameConfig = record
+ seed: shortstring;
+ theme: shortstring;
+ script: shortstring;
+ mapgen: Longint;
+ gameType: TGameType;
+ teams: array[0..7] of TTeam;
+ arguments: array[0..Pred(MAXARGS)] of shortstring;
+ argv: array[0..Pred(MAXARGS)] of PChar;
+ argumentsNumber: Longword;
+ end;
+ PGameConfig = ^TGameConfig;
+
+var
+ currentConfig: TGameConfig;
+
+
+procedure sendConfig(config: PGameConfig);
+var i: Longword;
+begin
+with config^ do
+begin
+ case gameType of
+ gtPreview: begin
+ if script <> '' then
+ ipcToEngine('escript ' + script);
+ ipcToEngine('eseed ' + seed);
+ ipcToEngine('e$mapgen ' + intToStr(mapgen));
+ end;
+ gtLocal: begin
+ if script <> '' then
+ ipcToEngine('escript ' + script);
+ ipcToEngine('eseed ' + seed);
+ ipcToEngine('e$mapgen ' + intToStr(mapgen));
+ ipcToEngine('e$theme ' + theme);
+
+ i:= 0;
+ while (i < 8) and (teams[i].hogsNumber > 0) do
+ begin
+ ipcToEngine('eammloadt 93919294221991210322351110012000000002111001010111110001');
+ ipcToEngine('eammprob 04050405416006555465544647765766666661555101011154111111');
+ ipcToEngine('eammdelay 00000000000002055000000400070040000000002200000006000200');
+ ipcToEngine('eammreinf 13111103121111111231141111111111111112111111011111111111');
+ ipcToEngine('eammstore');
+ sendTeamConfig(teams[i]);
+ inc(i)
+ end;
+ end;
+ end;
+
+ ipcToEngine('!');
+end;
+end;
+
+procedure queueExecution;
+var pConfig: PGameConfig;
+ i: Longword;
+begin
+ new(pConfig);
+ pConfig^:= currentConfig;
+
+ with pConfig^ do
+ for i:= 0 to Pred(MAXARGS) do
+ begin
+ if arguments[i][0] = #255 then
+ arguments[i][255]:= #0
+ else
+ arguments[i][byte(arguments[i][0]) + 1]:= #0;
+ argv[i]:= @arguments[i][1]
+ end;
+
+ RunEngine(pConfig^.argumentsNumber, @pConfig^.argv);
+
+ sendConfig(pConfig)
+end;
+
+procedure resetGameConfig; cdecl;
+var i: Longword;
+begin
+ with currentConfig do
+ begin
+ for i:= 0 to 7 do
+ teams[i].hogsNumber:= 0
+ end
+end;
+
+procedure setSeed(seed: PChar); cdecl;
+begin
+ currentConfig.seed:= seed
+end;
+
+
+function getSeed: PChar; cdecl;
+begin
+ getSeed:= str2PChar(currentConfig.seed)
+end;
+
+function getUnusedColor: Longword;
+var i, c: Longword;
+ fColorMatched: boolean;
+begin
+ c:= 0;
+ i:= 0;
+ repeat
+ repeat
+ fColorMatched:= (currentConfig.teams[i].hogsNumber > 0) and (currentConfig.teams[i].color = c);
+ inc(i)
+ until (i >= 8) or (currentConfig.teams[i].hogsNumber = 0) or fColorMatched;
+
+ if fColorMatched then
+ begin
+ i:= 0;
+ inc(c)
+ end;
+ until not fColorMatched;
+
+ getUnusedColor:= c
+end;
+
+procedure runQuickGame; cdecl;
+begin
+ with currentConfig do
+ begin
+ gameType:= gtLocal;
+ arguments[0]:= '';
+ arguments[1]:= '--internal';
+ arguments[2]:= '--nomusic';
+ argumentsNumber:= 3;
+
+ teams[0]:= createRandomTeam;
+ teams[0].color:= 0;
+ teams[1]:= createRandomTeam;
+ teams[1].color:= 1;
+ teams[1].botLevel:= 1;
+
+ queueExecution;
+ end;
+end;
+
+
+procedure getPreview; cdecl;
+begin
+ with currentConfig do
+ begin
+ gameType:= gtPreview;
+ arguments[0]:= '';
+ arguments[1]:= '--internal';
+ arguments[2]:= '--landpreview';
+ argumentsNumber:= 3;
+
+ queueExecution;
+ end;
+end;
+
+procedure runLocalGame; cdecl;
+begin
+ with currentConfig do
+ begin
+ gameType:= gtLocal;
+ arguments[0]:= '';
+ arguments[1]:= '--internal';
+ arguments[2]:= '--nomusic';
+ argumentsNumber:= 3;
+
+ queueExecution;
+ end;
+end;
+
+
+procedure engineMessageCallback(p: pointer; msg: PChar; len: Longword);
+begin
+ if len = 128 * 256 then guiCallbackFunction(guiCallbackPointer, mtPreview, msg, len)
+end;
+
+procedure registerGUIMessagesCallback(p: pointer; f: TGUICallback); cdecl;
+begin
+ guiCallbackPointer:= p;
+ guiCallbackFunction:= f;
+
+ registerIPCCallback(nil, @engineMessageCallback)
+end;
+
+
+procedure tryAddTeam(teamName: PChar); cdecl;
+var msg: ansistring;
+ i, hn, hedgehogsNumber: Longword;
+ team: PTeam;
+ c: Longword;
+begin
+ with currentConfig do
+ begin
+ hedgehogsNumber:= 0;
+ i:= 0;
+
+ while (i < 8) and (teams[i].hogsNumber > 0) do
+ begin
+ inc(i);
+ inc(hedgehogsNumber, teams[i].hogsNumber)
+ end;
+
+ // no free space for a team or reached hogs number maximum
+ if (i > 7) or (hedgehogsNumber >= 48) then exit;
+
+ team:= teamByName(teamName);
+ if team = nil then exit;
+
+ c:= getUnusedColor;
+
+ teams[i]:= team^;
+
+ if i = 0 then hn:= 4 else hn:= teams[i - 1].hogsNumber;
+ if hn > 48 - hedgehogsNumber then hn:= 48 - hedgehogsNumber;
+ teams[i].hogsNumber:= hn;
+
+ teams[i].color:= c;
+
+ msg:= '0' + #10 + teamName;
+ guiCallbackFunction(guiCallbackPointer, mtAddPlayingTeam, @msg[1], length(msg));
+
+ msg:= teamName + #10 + colorsSet[teams[i].color];
+ guiCallbackFunction(guiCallbackPointer, mtTeamColor, @msg[1], length(msg));
+
+ msg:= teamName;
+ guiCallbackFunction(guiCallbackPointer, mtRemoveTeam, @msg[1], length(msg))
+ end
+end;
+
+
+procedure tryRemoveTeam(teamName: PChar); cdecl;
+var msg: ansistring;
+ i: Longword;
+ tn: shortstring;
+begin
+ with currentConfig do
+ begin
+ i:= 0;
+ tn:= teamName;
+ while (i < 8) and (teams[i].teamName <> tn) do
+ inc(i);
+
+ // team not found???
+ if (i > 7) then exit;
+
+ while (i < 7) and (teams[i + 1].hogsNumber > 0) do
+ begin
+ teams[i]:= teams[i + 1];
+ inc(i)
+ end;
+
+ teams[i].hogsNumber:= 0
+ end;
+
+ msg:= teamName;
+
+ guiCallbackFunction(guiCallbackPointer, mtRemovePlayingTeam, @msg[1], length(msg));
+ guiCallbackFunction(guiCallbackPointer, mtAddTeam, @msg[1], length(msg))
+end;
+
+
+procedure changeTeamColor(teamName: PChar; dir: LongInt); cdecl;
+var i, dc: Longword;
+ tn: shortstring;
+ msg: ansistring;
+begin
+ with currentConfig do
+ begin
+ i:= 0;
+ tn:= teamName;
+ while (i < 8) and (teams[i].teamName <> tn) do
+ inc(i);
+ // team not found???
+ if (i > 7) then exit;
+
+ if dir >= 0 then dc:= 1 else dc:= 8;
+ teams[i].color:= (teams[i].color + dc) mod 9;
+
+ msg:= tn + #10 + colorsSet[teams[i].color];
+ guiCallbackFunction(guiCallbackPointer, mtTeamColor, @msg[1], length(msg))
+ end
+end;
+
+procedure setTheme(themeName: PChar); cdecl;
+begin
+ currentConfig.theme:= themeName
+end;
+
+procedure setScript(scriptName: PChar); cdecl;
+begin
+ if scriptName <> 'Normal' then
+ currentConfig.script:= '/Scripts/Multiplayer/' + scriptName + '.lua'
+ else
+ currentConfig.script:= ''
+end;
+
+end.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hedgewars/uFLIPC.pas Sat Jan 03 23:46:26 2015 +0300
@@ -0,0 +1,166 @@
+unit uFLIPC;
+interface
+uses SDLh, uFLTypes;
+
+var msgFrontend, msgEngine: TIPCMessage;
+ mutFrontend, mutEngine: PSDL_mutex;
+ condFrontend, condEngine: PSDL_cond;
+
+procedure initIPC;
+procedure freeIPC;
+
+procedure ipcToEngine(s: shortstring);
+//function ipcReadFromEngine: shortstring;
+//function ipcCheckFromEngine: boolean;
+
+procedure ipcToFrontend(s: shortstring);
+procedure ipcToFrontendRaw(p: pointer; len: Longword);
+function ipcReadFromFrontend: shortstring;
+function ipcCheckFromFrontend: boolean;
+
+procedure registerIPCCallback(p: pointer; f: TIPCCallback);
+
+implementation
+
+var callbackPointer: pointer;
+ callbackFunction: TIPCCallback;
+ callbackListenerThread: PSDL_Thread;
+
+procedure ipcSend(var s: TIPCMessage; var msg: TIPCMessage; mut: PSDL_mutex; cond: PSDL_cond);
+begin
+ SDL_LockMutex(mut);
+
+ while (msg.str[0] > #0) or (msg.buf <> nil) do
+ SDL_CondWait(cond, mut);
+
+ msg:= s;
+ SDL_CondSignal(cond);
+ SDL_UnlockMutex(mut);
+end;
+
+function ipcRead(var msg: TIPCMessage; mut: PSDL_mutex; cond: PSDL_cond): TIPCMessage;
+var tmp: pointer;
+begin
+ SDL_LockMutex(mut);
+ while (msg.str[0] = #0) and (msg.buf = nil) do
+ SDL_CondWait(cond, mut);
+
+ if msg.buf <> nil then
+ begin
+ tmp:= msg.buf;
+ msg.buf:= GetMem(msg.len);
+ Move(tmp^, msg.buf^, msg.len);
+ FreeMem(tmp, msg.len)
+ end;
+
+ ipcRead:= msg;
+
+ msg.str[0]:= #0;
+ msg.buf:= nil;
+
+ SDL_CondSignal(cond);
+ SDL_UnlockMutex(mut)
+end;
+
+function ipcCheck(var msg: TIPCMessage; mut: PSDL_mutex): boolean;
+begin
+ SDL_LockMutex(mut);
+ ipcCheck:= (msg.str[0] > #0) or (msg.buf <> nil);
+ SDL_UnlockMutex(mut)
+end;
+
+procedure ipcToEngine(s: shortstring);
+var msg: TIPCMessage;
+begin
+ msg.str:= s;
+ msg.buf:= nil;
+ ipcSend(msg, msgEngine, mutEngine, condEngine)
+end;
+
+procedure ipcToFrontend(s: shortstring);
+var msg: TIPCMessage;
+begin
+ msg.str:= s;
+ msg.buf:= nil;
+ ipcSend(msg, msgFrontend, mutFrontend, condFrontend)
+end;
+
+procedure ipcToFrontendRaw(p: pointer; len: Longword);
+var msg: TIPCMessage;
+begin
+ msg.str[0]:= #0;
+ msg.len:= len;
+ msg.buf:= GetMem(len);
+ Move(p^, msg.buf^, len);
+ ipcSend(msg, msgFrontend, mutFrontend, condFrontend)
+end;
+
+function ipcReadFromEngine: TIPCMessage;
+begin
+ ipcReadFromEngine:= ipcRead(msgFrontend, mutFrontend, condFrontend)
+end;
+
+function ipcReadFromFrontend: shortstring;
+begin
+ ipcReadFromFrontend:= ipcRead(msgEngine, mutEngine, condEngine).str
+end;
+
+function ipcCheckFromEngine: boolean;
+begin
+ ipcCheckFromEngine:= ipcCheck(msgFrontend, mutFrontend)
+end;
+
+function ipcCheckFromFrontend: boolean;
+begin
+ ipcCheckFromFrontend:= ipcCheck(msgEngine, mutEngine)
+end;
+
+function listener(p: pointer): Longint; cdecl; export;
+var msg: TIPCMessage;
+begin
+ listener:= 0;
+ repeat
+ msg:= ipcReadFromEngine();
+ if msg.buf = nil then
+ callbackFunction(callbackPointer, @msg.str[1], byte(msg.str[0]))
+ else
+ begin
+ callbackFunction(callbackPointer, msg.buf, msg.len);
+ FreeMem(msg.buf, msg.len)
+ end
+ until false
+end;
+
+procedure registerIPCCallback(p: pointer; f: TIPCCallback);
+begin
+ callbackPointer:= p;
+ callbackFunction:= f;
+ callbackListenerThread:= SDL_CreateThread(@listener{$IFDEF SDL2}, 'ipcListener'{$ENDIF}, nil);
+end;
+
+procedure initIPC;
+begin
+ msgFrontend.str:= '';
+ msgFrontend.buf:= nil;
+ msgEngine.str:= '';
+ msgEngine.buf:= nil;
+
+ callbackPointer:= nil;
+ callbackListenerThread:= nil;
+
+ mutFrontend:= SDL_CreateMutex;
+ mutEngine:= SDL_CreateMutex;
+ condFrontend:= SDL_CreateCond;
+ condEngine:= SDL_CreateCond;
+end;
+
+procedure freeIPC;
+begin
+ SDL_KillThread(callbackListenerThread);
+ SDL_DestroyMutex(mutFrontend);
+ SDL_DestroyMutex(mutEngine);
+ SDL_DestroyCond(condFrontend);
+ SDL_DestroyCond(condEngine);
+end;
+
+end.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hedgewars/uFLSchemes.pas Sat Jan 03 23:46:26 2015 +0300
@@ -0,0 +1,155 @@
+unit uFLSchemes;
+interface
+uses uFLTypes;
+
+function getSchemesList: PPChar; cdecl;
+procedure freeSchemesList;
+
+implementation
+uses uFLUtils, uFLIPC, uPhysFSLayer, uFLData;
+
+const MAX_SCHEME_NAMES = 64;
+type
+ TScheme = record
+ schemeName: shortstring;
+ end;
+ PScheme = ^TScheme;
+ TSchemeArray = array [0..0] of TScheme;
+ PSchemeArray = ^TSchemeArray;
+var
+ schemesList: PScheme;
+ schemesNumber: LongInt;
+ listOfSchemeNames: array[0..MAX_SCHEME_NAMES] of PChar;
+
+procedure loadSchemes;
+var f: PFSFile;
+ scheme: PScheme;
+ schemes: PSchemeArray;
+ s: shortstring;
+ l, i: Longword;
+begin
+ f:= pfsOpenRead('/Config/schemes.ini');
+ schemesNumber:= 0;
+
+ if f <> nil then
+ begin
+ while (not pfsEOF(f)) and (schemesNumber = 0) do
+ begin
+ pfsReadLn(f, s);
+
+ if copy(s, 1, 5) = 'size=' then
+ schemesNumber:= strToInt(midStr(s, 6));
+ end;
+
+ //inc(schemesNumber); // add some default schemes
+
+ schemesList:= GetMem(sizeof(schemesList^) * (schemesNumber + 1));
+ schemes:= PSchemeArray(schemesList);
+
+ while (not pfsEOF(f)) do
+ begin
+ pfsReadLn(f, s);
+
+ i:= 1;
+ while(i <= length(s)) and (s[i] <> '\') do inc(i);
+
+ if i < length(s) then
+ begin
+ l:= strToInt(copy(s, 1, i - 1));
+
+ if (l < schemesNumber) and (l > 0) then
+ begin
+ scheme:= @schemes^[l - 1];
+
+ if copy(s, i + 1, 5) = 'name=' then
+ scheme^. schemeName:= midStr(s, i + 6);
+ end;
+ end;
+ end;
+
+ pfsClose(f)
+ end;
+{
+name=AI TEST
+fortsmode=false
+divteams=false
+solidland=false
+border=false
+lowgrav=false
+laser=false
+invulnerability=false
+mines=true
+damagefactor=100
+turntime=40
+health=100
+suddendeath=0
+caseprobability=5
+vampiric=false
+karma=false
+artillery=false
+minestime=0
+landadds=4
+randomorder=true
+king=false
+placehog=false
+sharedammo=false
+disablegirders=false
+minedudpct=100
+explosives=40
+disablelandobjects=true
+aisurvival=true
+resethealth=false
+infattack=true
+resetweps=true
+perhogammo=false
+minesnum=0
+healthprobability=100
+healthcaseamount=50
+waterrise=0
+healthdecrease=0
+disablewind=false
+morewind=false
+ropepct=100
+tagteam=false
+getawaytime=100
+bottomborder=false
+worldedge=1
+scriptparam=@Invalid()
+}
+end;
+
+
+function getSchemesList: PPChar; cdecl;
+var i, t, l: Longword;
+ scheme: PScheme;
+begin
+ if schemesList = nil then
+ loadSchemes;
+
+ t:= schemesNumber;
+ if t >= MAX_SCHEME_NAMES then
+ t:= MAX_SCHEME_NAMES;
+
+ scheme:= schemesList;
+ for i:= 0 to Pred(t) do
+ begin
+ l:= length(scheme^.schemeName);
+ if l >= 255 then l:= 254;
+ scheme^.schemeName[l + 1]:= #0;
+ listOfSchemeNames[i]:= @scheme^.schemeName[1];
+ inc(scheme)
+ end;
+
+ listOfSchemeNames[t]:= nil;
+
+ getSchemesList:= listOfSchemeNames
+end;
+
+
+procedure freeSchemesList;
+begin
+ if schemesList <> nil then
+ FreeMem(schemesList, sizeof(schemesList^) * schemesNumber)
+end;
+
+end.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hedgewars/uFLScripts.pas Sat Jan 03 23:46:26 2015 +0300
@@ -0,0 +1,129 @@
+unit uFLScripts;
+interface
+uses uFLTypes;
+
+function getScriptsList: PPChar; cdecl;
+procedure freeScriptsList;
+
+implementation
+uses uFLUtils, uFLIPC, uPhysFSLayer, uFLData;
+
+const MAX_SCRIPT_NAMES = 64;
+type
+ TScript = record
+ scriptName: shortstring;
+ description: shortstring;
+ gameScheme, weapons: shortstring;
+ end;
+ PScript = ^TScript;
+var
+ scriptsList: PScript;
+ scriptsNumber: Longword;
+ listOfScriptNames: array[0..MAX_SCRIPT_NAMES] of PChar;
+
+procedure loadScript(var script: TScript; scriptName, fileName: shortstring);
+var f: PFSFile;
+begin
+ underScore2Space(scriptName);
+ script.scriptName:= scriptName;
+ script.description:= scriptName + ' script description';
+
+ f:= pfsOpenRead(copy(fileName, 1, length(fileName) - 4) + '.txt');
+
+ script.gameScheme:= '';
+ script.weapons:= '';
+
+ if f <> nil then
+ begin
+ if not pfsEOF(f) then
+ begin
+ pfsReadLn(f, script.gameScheme);
+
+ if not pfsEOF(f) then
+ pfsReadLn(f, script.weapons);
+ end;
+
+ pfsClose(f)
+ end
+end;
+
+procedure loadScripts;
+var filesList, tmp: PPChar;
+ script: PScript;
+ s: shortstring;
+ l: Longword;
+begin
+ filesList:= pfsEnumerateFiles('/Scripts/Multiplayer');
+ scriptsNumber:= 1;
+
+ tmp:= filesList;
+ while tmp^ <> nil do
+ begin
+ s:= shortstring(tmp^);
+ writeln(stderr, '> ', s);
+ l:= length(s);
+ if (l > 4) and (copy(s, l - 3, 4) = '.lua') then inc(scriptsNumber);
+ inc(tmp)
+ end;
+
+ scriptsList:= GetMem(sizeof(scriptsList^) * (scriptsNumber + 1));
+
+ script:= scriptsList;
+
+ // add 'normal' script
+ script^.scriptName:= 'Normal';
+ script^.description:= 'Normal gameplay';
+ inc(script);
+
+ // fill the rest from *.lua list
+ tmp:= filesList;
+ while tmp^ <> nil do
+ begin
+ s:= shortstring(tmp^);
+ l:= length(s);
+ if (l > 4) and (copy(s, l - 3, 4) = '.lua') then
+ begin
+ loadScript(script^, copy(s, 1, l - 4), '/Config/Scripts/' + s);
+ inc(script)
+ end;
+ inc(tmp)
+ end;
+
+ pfsFreeList(filesList)
+end;
+
+
+function getScriptsList: PPChar; cdecl;
+var i, t, l: Longword;
+ script: PScript;
+begin
+ if scriptsList = nil then
+ loadScripts;
+
+ t:= scriptsNumber;
+ if t >= MAX_SCRIPT_NAMES then
+ t:= MAX_SCRIPT_NAMES;
+
+ script:= scriptsList;
+ for i:= 0 to Pred(t) do
+ begin
+ l:= length(script^.scriptName);
+ if l >= 255 then l:= 254;
+ script^.scriptName[l + 1]:= #0;
+ listOfScriptNames[i]:= @script^.scriptName[1];
+ inc(script)
+ end;
+
+ listOfScriptNames[t]:= nil;
+
+ getScriptsList:= listOfScriptNames
+end;
+
+
+procedure freeScriptsList;
+begin
+ if scriptsList <> nil then
+ FreeMem(scriptsList, sizeof(scriptsList^) * scriptsNumber)
+end;
+
+end.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hedgewars/uFLTeams.pas Sat Jan 03 23:46:26 2015 +0300
@@ -0,0 +1,182 @@
+unit uFLTeams;
+interface
+uses uFLTypes;
+
+function createRandomTeam: TTeam;
+procedure sendTeamConfig(var team: TTeam);
+
+function getTeamsList: PPChar; cdecl;
+procedure freeTeamsList;
+
+function teamByName(s: shortstring): PTeam;
+
+implementation
+uses uFLUtils, uFLIPC, uPhysFSLayer, uFLData;
+
+const MAX_TEAM_NAMES = 128;
+var
+ teamsList: PTeam;
+ teamsNumber: Longword;
+ listOfTeamNames: array[0..MAX_TEAM_NAMES] of PChar;
+
+
+function createRandomTeam: TTeam;
+var t: TTeam;
+ i: Longword;
+begin
+ with t do
+ begin
+ teamName:= 'team' + inttostr(random(100));
+
+ for i:= 0 to 7 do
+ with hedgehogs[i] do
+ begin
+ name:= 'hedgehog ' + inttostr(i);
+ hat:= 'NoHat'
+ end;
+
+ botLevel:= 0;
+ hogsNumber:= 4
+ end;
+ createRandomTeam:= t
+end;
+
+
+procedure sendTeamConfig(var team: TTeam);
+var i: Longword;
+begin
+ with team do
+ begin
+ ipcToEngine('eaddteam <hash> ' + colorsSet[color] + ' ' + teamName);
+ for i:= 0 to Pred(hogsNumber) do
+ begin
+ ipcToEngine('eaddhh ' + inttostr(botLevel) + ' 100 hog');// + hedgehogs[i].name);
+ //ipcToEngine('ehat ' + hedgehogs[i].hat);
+ end;
+ end
+end;
+
+
+procedure loadTeam(var team: TTeam; fileName: shortstring);
+var f: PFSFile;
+ section: LongInt;
+ l: shortstring;
+begin
+ section:= -1;
+ f:= pfsOpenRead(fileName);
+
+ while (not pfsEOF(f)) do
+ begin
+ pfsReadLn(f, l);
+
+ if l = '' then
+ else if l = '[Team]' then
+ section:= 0
+ else if l[1] = '[' then
+ section:= -1
+ else if section = 0 then
+ begin // [Team]
+ if copy(l, 1, 5) = 'Name=' then
+ team.teamName:= midStr(l, 6)
+ else if copy(l, 1, 6) = 'Grave=' then
+ team.graveName:= midStr(l, 7)
+ else if copy(l, 1, 5) = 'Fort=' then
+ team.fortName:= midStr(l, 6)
+ else if copy(l, 1, 5) = 'Flag=' then
+ team.flag:= midStr(l, 6)
+ end;
+ // TODO: load hedgehogs and other stuff
+ team.botLevel:= 1
+ end;
+
+ pfsClose(f)
+end;
+
+
+procedure loadTeams;
+var filesList, tmp: PPChar;
+ team: PTeam;
+ s: shortstring;
+ l: Longword;
+begin
+ filesList:= pfsEnumerateFiles('/Config/Teams');
+ teamsNumber:= 0;
+
+ tmp:= filesList;
+ while tmp^ <> nil do
+ begin
+ s:= shortstring(tmp^);
+ l:= length(s);
+ if (l > 4) and (copy(s, l - 3, 4) = '.hwt') then inc(teamsNumber);
+ inc(tmp)
+ end;
+
+ // TODO: no teams at all?
+ teamsList:= GetMem(sizeof(teamsList^) * teamsNumber);
+
+ team:= teamsList;
+ tmp:= filesList;
+ while tmp^ <> nil do
+ begin
+ s:= shortstring(tmp^);
+ l:= length(s);
+ if (l > 4) and (copy(s, l - 3, 4) = '.hwt') then
+ begin
+ loadTeam(team^, '/Config/Teams/' + s);
+ inc(team)
+ end;
+ inc(tmp)
+ end;
+
+ pfsFreeList(filesList)
+end;
+
+
+function getTeamsList: PPChar; cdecl;
+var i, t, l: Longword;
+ team: PTeam;
+begin
+ if teamsList = nil then
+ loadTeams;
+
+ t:= teamsNumber;
+ if t >= MAX_TEAM_NAMES then
+ t:= MAX_TEAM_NAMES;
+
+ team:= teamsList;
+ for i:= 0 to Pred(t) do
+ begin
+ l:= length(team^.teamName);
+ if l >= 255 then l:= 254;
+ team^.teamName[l + 1]:= #0;
+ listOfTeamNames[i]:= @team^.teamName[1];
+ inc(team)
+ end;
+
+ listOfTeamNames[t]:= nil;
+
+ getTeamsList:= listOfTeamNames
+end;
+
+function teamByName(s: shortstring): PTeam;
+var i: Longword;
+ team: PTeam;
+begin
+ team:= teamsList;
+ i:= 0;
+ while (i < teamsNumber) and (team^.teamName <> s) do
+ begin
+ inc(team);
+ inc(i)
+ end;
+
+ if i < teamsNumber then teamByName:= team else teamByName:= nil
+end;
+
+procedure freeTeamsList;
+begin
+ if teamsList <> nil then
+ FreeMem(teamsList, sizeof(teamsList^) * teamsNumber)
+end;
+
+end.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hedgewars/uFLTypes.pas Sat Jan 03 23:46:26 2015 +0300
@@ -0,0 +1,38 @@
+unit uFLTypes;
+interface
+
+type
+ TMessageType = (mtPreview, mtAddPlayingTeam, mtRemovePlayingTeam, mtAddTeam, mtRemoveTeam
+ , mtTeamColor);
+
+ TIPCMessage = record
+ str: shortstring;
+ len: Longword;
+ buf: Pointer
+ end;
+
+ TIPCCallback = procedure (p: pointer; msg: PChar; len: Longword);
+ TGUICallback = procedure (p: pointer; msgType: TMessageType; msg: PChar; len: Longword); cdecl;
+
+ TGameType = (gtPreview, gtLocal);
+ THedgehog = record
+ name: shortstring;
+ hat: shortstring;
+ end;
+ TTeam = record
+ teamName: shortstring;
+ flag: shortstring;
+ graveName: shortstring;
+ fortName: shortstring;
+ owner: shortstring;
+ color: Longword;
+ extDriven: boolean;
+ botLevel: Longword;
+ hedgehogs: array[0..7] of THedgehog;
+ hogsNumber: Longword;
+ end;
+ PTeam = ^TTeam;
+
+implementation
+
+end.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hedgewars/uFLUtils.pas Sat Jan 03 23:46:26 2015 +0300
@@ -0,0 +1,48 @@
+unit uFLUtils;
+interface
+
+function str2PChar(const s: shortstring): PChar;
+function intToStr(n: LongInt): shortstring;
+function strToInt(s: shortstring): LongInt;
+function midStr(s: shortstring; pos: byte): shortstring;
+procedure underScore2Space(var s: shortstring);
+
+implementation
+
+var
+ str2PCharBuffer: array[0..255] of char;
+
+function str2PChar(const s: shortstring): PChar;
+var i: Integer;
+begin
+ for i:= 1 to Length(s) do
+ begin
+ str2PCharBuffer[i - 1] := s[i];
+ end;
+ str2PCharBuffer[Length(s)]:= #0;
+ str2PChar:= @(str2PCharBuffer[0]);
+end;
+
+function intToStr(n: LongInt): shortstring;
+begin
+ str(n, intToStr)
+end;
+
+function strToInt(s: shortstring): LongInt;
+begin
+val(s, strToInt);
+end;
+
+function midStr(s: shortstring; pos: byte): shortstring;
+begin
+ midStr:= copy(s, pos, length(s) - pos + 1)
+end;
+
+procedure underScore2Space(var s: shortstring);
+var i: LongInt;
+begin
+ for i:= length(s) downto 1 do
+ if s[i] = '_' then s[i]:= ' '
+end;
+
+end.
--- a/hedgewars/uIO.pas Sat Jan 03 00:30:30 2015 +0300
+++ b/hedgewars/uIO.pas Sat Jan 03 23:46:26 2015 +0300
@@ -25,7 +25,6 @@
procedure initModule;
procedure freeModule;
-procedure InitIPC;
procedure SendIPC(s: shortstring);
procedure SendIPCXY(cmd: char; X, Y: LongInt);
procedure SendIPCRaw(p: pointer; len: Longword);
@@ -39,7 +38,7 @@
procedure doPut(putX, putY: LongInt; fromAI: boolean);
implementation
-uses uConsole, uConsts, uVariables, uCommands, uUtils, uDebug;
+uses uConsole, uConsts, uVariables, uCommands, uUtils, uDebug, uFLIPC;
const
cSendEmptyPacketTime = 1000;
@@ -55,11 +54,9 @@
2: (str: shortstring);
end;
-var IPCSock: PTCPSocket;
- fds: PSDLNet_SocketSet;
+var
isPonged: boolean;
- SocketString: shortstring;
-
+
headcmd: PCmd;
lastcmd: PCmd;
@@ -101,23 +98,6 @@
dispose(tmp)
end;
-procedure InitIPC;
-var ipaddr: TIPAddress;
-begin
- WriteToConsole('Init SDL_Net... ');
- SDLTry(SDLNet_Init = 0, true);
- fds:= SDLNet_AllocSocketSet(1);
- SDLTry(fds <> nil, true);
- WriteLnToConsole(msgOK);
- WriteToConsole('Establishing IPC connection to tcp 127.0.0.1:' + IntToStr(ipcPort) + ' ');
- {$HINTS OFF}
- SDLTry(SDLNet_ResolveHost(ipaddr, PChar('127.0.0.1'), ipcPort) = 0, true);
- {$HINTS ON}
- IPCSock:= SDLNet_TCP_Open(ipaddr);
- SDLTry(IPCSock <> nil, true);
- WriteLnToConsole(msgOK)
-end;
-
procedure ParseChatCommand(command: shortstring; message: shortstring;
messageStartIndex: Byte);
var
@@ -176,31 +156,9 @@
end;
procedure IPCCheckSock;
-var i: LongInt;
- s: shortstring;
begin
- if IPCSock = nil then
- exit;
-
- fds^.numsockets:= 0;
- SDLNet_AddSocket(fds, IPCSock);
-
- while SDLNet_CheckSockets(fds, 0) > 0 do
- begin
- i:= SDLNet_TCP_Recv(IPCSock, @s[1], 255 - Length(SocketString));
- if i > 0 then
- begin
- s[0]:= char(i);
- SocketString:= SocketString + s;
- while (Length(SocketString) > 1) and (Length(SocketString) > byte(SocketString[1])) do
- begin
- ParseIPCCommand(copy(SocketString, 2, byte(SocketString[1])));
- Delete(SocketString, 1, Succ(byte(SocketString[1])))
- end
- end
- else
- OutError('IPC connection lost', true)
- end;
+ while ipcCheckFromFrontend() do
+ ParseIPCCommand(ipcReadFromFrontend())
end;
procedure LoadRecordFromFile(fileName: shortstring);
@@ -260,18 +218,11 @@
procedure flushBuffer();
begin
- if IPCSock <> nil then
- begin
- SDLNet_TCP_Send(IPCSock, @sendBuffer.buf, sendBuffer.count);
- flushDelayTicks:= 0;
- sendBuffer.count:= 0
- end
+
end;
procedure SendIPC(s: shortstring);
begin
-if IPCSock <> nil then
- begin
if s[0] > #251 then
s[0]:= #251;
@@ -280,37 +231,22 @@
AddFileLog('[IPC out] '+ sanitizeCharForLog(s[1]));
inc(s[0], 2);
- if isSyncedCommand(s[1]) then
- begin
- if sendBuffer.count + byte(s[0]) >= cSendBufferSize then
- flushBuffer();
-
- Move(s, sendBuffer.buf[sendBuffer.count], byte(s[0]) + 1);
- inc(sendBuffer.count, byte(s[0]) + 1);
-
- if (s[1] = 'N') or (s[1] = '#') then
- flushBuffer();
- end else
- SDLNet_TCP_Send(IPCSock, @s, Succ(byte(s[0])))
- end
+ ipcToFrontend(s)
end;
procedure SendIPCRaw(p: pointer; len: Longword);
begin
-if IPCSock <> nil then
- begin
- SDLNet_TCP_Send(IPCSock, p, len)
- end
+ ipcToFrontendRaw(p, len)
end;
procedure SendIPCXY(cmd: char; X, Y: LongInt);
var s: shortstring;
begin
-s[0]:= #9;
-s[1]:= cmd;
-SDLNet_Write32(X, @s[2]);
-SDLNet_Write32(Y, @s[6]);
-SendIPC(s)
+ s[0]:= #9;
+ s[1]:= cmd;
+ SDLNet_Write32(X, @s[2]);
+ SDLNet_Write32(Y, @s[6]);
+ SendIPC(s)
end;
procedure IPCWaitPongEvent;
@@ -440,13 +376,13 @@
procedure chFatalError(var s: shortstring);
begin
SendIPC('E' + s);
- // TODO: should we try to clean more stuff here?
+{ // TODO: should we try to clean more stuff here?
SDL_Quit;
if IPCSock <> nil then
halt(HaltFatalError)
else
- halt(HaltFatalErrorNoIPC);
+ halt(HaltFatalErrorNoIPC);}
end;
procedure doPut(putX, putY: LongInt; fromAI: boolean);
@@ -498,12 +434,9 @@
begin
RegisterVariable('fatal', @chFatalError, true );
- IPCSock:= nil;
-
headcmd:= nil;
lastcmd:= nil;
isPonged:= false;
- SocketString:= '';
hiTicks:= 0;
flushDelayTicks:= 0;
@@ -513,10 +446,6 @@
procedure freeModule;
begin
while headcmd <> nil do RemoveCmd;
- SDLNet_FreeSocketSet(fds);
- SDLNet_TCP_Close(IPCSock);
- SDLNet_Quit();
-
end;
end.
--- a/hedgewars/uInputHandler.pas Sat Jan 03 00:30:30 2015 +0300
+++ b/hedgewars/uInputHandler.pas Sat Jan 03 23:46:26 2015 +0300
@@ -331,7 +331,7 @@
for i:= 1 to 10 do DefaultBinds[KeyNameToCode('f'+IntToStr(i))]:= 'slot '+char(i+48);
for i:= 1 to 5 do DefaultBinds[KeyNameToCode(IntToStr(i))]:= 'timer '+IntToStr(i);
-loadBinds('dbind', cPathz[ptData] + '/settings.ini');
+loadBinds('dbind', cPathz[ptConfig] + '/settings.ini');
end;
procedure SetBinds(var binds: TBinds);
--- a/hedgewars/uMisc.pas Sat Jan 03 00:30:30 2015 +0300
+++ b/hedgewars/uMisc.pas Sat Jan 03 23:46:26 2015 +0300
@@ -283,11 +283,12 @@
// allocate and fill structure that will be passed to new thread
New(image); // will be disposed in SaveScreenshot()
-if dump = 2 then
+{if dump = 2 then
image^.filename:= shortstring(UserPathPrefix) + filename + '_landpixels' + ext
else if dump = 1 then
image^.filename:= shortstring(UserPathPrefix) + filename + '_land' + ext
-else image^.filename:= shortstring(UserPathPrefix) + filename + ext;
+else image^.filename:= shortstring(UserPathPrefix) + filename + ext;}
+image^.filename:= filename + ext;
if dump <> 0 then
begin
--- a/hedgewars/uPhysFSLayer.pas Sat Jan 03 00:30:30 2015 +0300
+++ b/hedgewars/uPhysFSLayer.pas Sat Jan 03 23:46:26 2015 +0300
@@ -13,7 +13,7 @@
{$linklib physlayer}
{$ENDIF}
-procedure initModule;
+procedure initModule(localPrefix, userPrefix: PChar);
procedure freeModule;
type PFSFile = pointer;
@@ -28,6 +28,8 @@
procedure pfsReadLnA(f: PFSFile; var s: ansistring);
function pfsBlockRead(f: PFSFile; buf: pointer; size: Int64): Int64;
function pfsEOF(f: PFSFile): boolean;
+function pfsEnumerateFiles(dir: shortstring): PPChar;
+procedure pfsFreeList(list: PPChar);
function pfsExists(fname: shortstring): boolean;
@@ -51,6 +53,8 @@
function PHYSFS_close(f: PFSFile): LongBool; cdecl; external PhysfsLibName;
function PHYSFS_exists(fname: PChar): LongBool; cdecl; external PhysfsLibName;
function PHYSFS_getLastError(): PChar; cdecl; external PhysfsLibName;
+function PHYSFS_enumerateFiles(dir: PChar): PPChar; cdecl; external PhysfsLibName;
+procedure PHYSFS_freeList(list: PPChar); cdecl; external PhysfsLibName;
{$ELSE}
function PHYSFS_readBytes(f: PFSFile; buffer: pointer; len: Int64): Int64;
begin
@@ -88,6 +92,15 @@
exit(PHYSFS_exists(Str2PChar(fname)))
end;
+function pfsEnumerateFiles(dir: shortstring): PPChar;
+begin
+ exit(PHYSFS_enumerateFiles(Str2PChar(dir)))
+end;
+
+procedure pfsFreeList(list: PPChar);
+begin
+ PHYSFS_freeList(list)
+end;
procedure pfsReadLn(f: PFSFile; var s: shortstring);
var c: char;
@@ -138,9 +151,9 @@
procedure pfsMount(path: ansistring; mountpoint: PChar);
begin
if PHYSFS_mount(PChar(path), mountpoint, false) then
- AddFileLog('[PhysFS] mount ' + shortstring(path) + ' at ' + shortstring(mountpoint) + ' : ok')
+ //AddFileLog('[PhysFS] mount ' + shortstring(path) + ' at ' + shortstring(mountpoint) + ' : ok')
else
- AddFileLog('[PhysFS] mount ' + shortstring(path) + ' at ' + shortstring(mountpoint) + ' : FAILED ("' + shortstring(PHYSFS_getLastError()) + '")');
+ //AddFileLog('[PhysFS] mount ' + shortstring(path) + ' at ' + shortstring(mountpoint) + ' : FAILED ("' + shortstring(PHYSFS_getLastError()) + '")');
end;
procedure pfsMountAtRoot(path: ansistring);
@@ -148,20 +161,16 @@
pfsMount(path, PChar(_S'/'));
end;
-procedure initModule;
+procedure initModule(localPrefix, userPrefix: PChar);
var i: LongInt;
cPhysfsId: shortstring;
fp: PChar;
begin
-{$IFDEF HWLIBRARY}
//TODO: http://icculus.org/pipermail/physfs/2011-August/001006.html
cPhysfsId:= GetCurrentDir() + {$IFDEF DARWIN}{$IFNDEF IPHONEOS}'/Hedgewars.app/Contents/MacOS/' + {$ENDIF}{$ENDIF} ' hedgewars';
-{$ELSE}
- cPhysfsId:= ParamStr(0);
-{$ENDIF}
i:= PHYSFS_init(Str2PChar(cPhysfsId));
- AddFileLog('[PhysFS] init: ' + inttostr(i));
+ //AddFileLog('[PhysFS] init: ' + inttostr(i));
// mount system fonts paths first
for i:= low(cFontsPaths) to high(cFontsPaths) do
@@ -171,14 +180,12 @@
pfsMount(ansistring(fp), PChar('/Fonts'));
end;
- pfsMountAtRoot(PathPrefix);
- pfsMountAtRoot(UserPathPrefix + ansistring('/Data'));
+ pfsMountAtRoot(localPrefix);
+ pfsMountAtRoot(userPrefix + ansistring('/Data'));
+ pfsMount(userPrefix, PChar('/Config'));
hedgewarsMountPackages;
- // need access to teams and frontend configs (for bindings)
- pfsMountAtRoot(UserPathPrefix);
-
if cTestLua then
begin
pfsMountAtRoot(ansistring(ExtractFileDir(cScriptName)));
--- a/hedgewars/uRender.pas Sat Jan 03 00:30:30 2015 +0300
+++ b/hedgewars/uRender.pas Sat Jan 03 23:46:26 2015 +0300
@@ -101,8 +101,7 @@
implementation
uses {$IFNDEF PAS2C} StrUtils, {$ENDIF}SysUtils, uVariables, uUtils, uConsts
- {$IFDEF GL2}, uMatrix, uConsole{$ENDIF}
- {$IF NOT DEFINED(SDL2) AND DEFINED(USE_VIDEO_RECORDING)}, glut {$ENDIF};
+ {$IFDEF GL2}, uMatrix, uConsole{$ENDIF};
{$IFDEF USE_TOUCH_INTERFACE}
const
--- a/hedgewars/uTypes.pas Sat Jan 03 00:30:30 2015 +0300
+++ b/hedgewars/uTypes.pas Sat Jan 03 23:46:26 2015 +0300
@@ -45,7 +45,7 @@
TPathType = (ptNone, ptData, ptGraphics, ptThemes, ptCurrTheme, ptTeams, ptMaps,
ptMapCurrent, ptDemos, ptSounds, ptGraves, ptFonts, ptForts, ptLocale,
ptAmmoMenu, ptHedgehog, ptVoices, ptHats, ptFlags, ptMissionMaps,
- ptSuddenDeath, ptButtons, ptShaders);
+ ptSuddenDeath, ptButtons, ptShaders, ptConfig);
// Available sprites for displaying stuff
TSprite = (sprWater, sprCloud, sprBomb, sprBigDigit, sprFrame,
--- a/hedgewars/uUtils.pas Sat Jan 03 00:30:30 2015 +0300
+++ b/hedgewars/uUtils.pas Sat Jan 03 23:46:26 2015 +0300
@@ -329,7 +329,7 @@
function Str2PChar(const s: shortstring): PChar;
-var i :Integer ;
+var i: Integer;
begin
for i:= 1 to Length(s) do
begin
@@ -547,7 +547,7 @@
{$ENDIF}
{$I-}
rwfailed:= false;
- if (length(UserPathPrefix) > 0) then
+ (*if (length(UserPathPrefix) > 0) then
begin
{$IFNDEF PAS2C}
// create directory if it doesn't exist
@@ -567,10 +567,10 @@
inc(i)
end;
end;
-
+ *)
{$IFNDEF PAS2C}
// if everything fails, write to stderr
- if (length(UserPathPrefix) = 0) or (rwfailed) then
+ //if (length(UserPathPrefix) = 0) or (rwfailed) then
logFile:= stderr;
{$ENDIF}
{$I+}
--- a/hedgewars/uVariables.pas Sat Jan 03 00:30:30 2015 +0300
+++ b/hedgewars/uVariables.pas Sat Jan 03 23:46:26 2015 +0300
@@ -36,14 +36,11 @@
cNewScreenWidth : LongInt;
cNewScreenHeight : LongInt;
cScreenResizeDelay : LongWord;
- ipcPort : Word;
AprilOne : boolean;
cFullScreen : boolean;
cLocaleFName : shortstring;
cLocale : shortstring;
cTimerInterval : LongInt;
- PathPrefix : ansistring;
- UserPathPrefix : ansistring;
cShowFPS : boolean;
cFlattenFlakes : boolean;
cFlattenClouds : boolean;
@@ -251,11 +248,11 @@
// these consts are here because they would cause circular dependencies in uConsts/uTypes
cPathz: array[TPathType] of shortstring = (
'', // ptNone
- '//', // ptData
+ '/', // ptData
'/Graphics', // ptGraphics
'/Themes', // ptThemes
'/Themes/Bamboo', // ptCurrTheme
- '/Teams', // ptTeams
+ '/Config/Teams', // ptTeams
'/Maps', // ptMaps
'', // ptMapCurrent
'/Demos', // ptDemos
@@ -272,7 +269,8 @@
'/Missions/Maps', // ptMissionMaps
'/Graphics/SuddenDeath', // ptSuddenDeath
'/Graphics/Buttons', // ptButton
- '/Shaders' // ptShaders
+ '/Shaders', // ptShaders
+ '/Config' // ptConfig
);
var
@@ -2428,13 +2426,10 @@
cLocaleFName := 'en.txt';
cFullScreen := false;
- UserPathPrefix := '';
- ipcPort := 0;
recordFileName := '';
UserNick := '';
cStereoMode := smNone;
GrayScale := false;
- PathPrefix := './';
GameType := gmtLocal;
cOnlyStats := False;
cScriptName := '';
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qmlFrontend/flib.h Sat Jan 03 23:46:26 2015 +0300
@@ -0,0 +1,59 @@
+#ifndef FLIB_H
+#define FLIB_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum MessageType {
+ MSG_PREVIEW
+ , MSG_ADDPLAYINGTEAM
+ , MSG_REMOVEPLAYINGTEAM
+ , MSG_ADDTEAM
+ , MSG_REMOVETEAM
+ , MSG_TEAMCOLOR
+};
+
+typedef union string255_
+ {
+ struct {
+ unsigned char s[256];
+ };
+ struct {
+ unsigned char len;
+ unsigned char str[255];
+ };
+ } string255;
+
+typedef void RunEngine_t(int argc, const char ** argv);
+typedef void registerGUIMessagesCallback_t(void * context, void (*)(void * context, MessageType mt, const char * msg, uint32_t len));
+typedef void getPreview_t();
+typedef void runQuickGame_t();
+typedef void runLocalGame_t();
+typedef void resetGameConfig_t();
+typedef void setSeed_t(const char * seed);
+typedef char *getSeed_t();
+typedef void setTheme_t(const char * themeName);
+typedef void setScript_t(const char * scriptName);
+typedef void flibInit_t(const char * localPrefix, const char * userPrefix);
+typedef void flibFree_t();
+
+typedef char **getThemesList_t();
+typedef void freeThemesList_t(char **list);
+typedef uint32_t getThemeIcon_t(char * theme, char * buffer, uint32_t size);
+
+typedef char **getScriptsList_t();
+typedef char **getSchemesList_t();
+
+typedef char **getTeamsList_t();
+typedef void tryAddTeam_t(const char * teamName);
+typedef void tryRemoveTeam_t(const char * teamName);
+typedef void changeTeamColor_t(const char * teamName, int32_t dir);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // FLIB_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qmlFrontend/hwengine.cpp Sat Jan 03 23:46:26 2015 +0300
@@ -0,0 +1,235 @@
+#include <QLibrary>
+#include <QtQml>
+#include <QDebug>
+#include <QPainter>
+#include <QUuid>
+
+#include "hwengine.h"
+#include "previewimageprovider.h"
+#include "themeiconprovider.h"
+
+extern "C" {
+ RunEngine_t *flibRunEngine;
+ registerGUIMessagesCallback_t *flibRegisterGUIMessagesCallback;
+ setSeed_t *flibSetSeed;
+ getSeed_t *flibGetSeed;
+ setTheme_t *flibSetTheme;
+ setScript_t *flibSetScript;
+ getPreview_t *flibGetPreview;
+ runQuickGame_t *flibRunQuickGame;
+ runLocalGame_t *flibRunLocalGame;
+ flibInit_t *flibInit;
+ flibFree_t *flibFree;
+ resetGameConfig_t * flibResetGameConfig;
+ getThemesList_t *flibGetThemesList;
+ freeThemesList_t *flibFreeThemesList;
+ getThemeIcon_t *flibGetThemeIcon;
+ getScriptsList_t *flibGetScriptsList;
+ getSchemesList_t *flibGetSchemesList;
+ getTeamsList_t *flibGetTeamsList;
+ tryAddTeam_t * flibTryAddTeam;
+ tryRemoveTeam_t * flibTryRemoveTeam;
+ changeTeamColor_t * flibChangeTeamColor;
+}
+
+Q_DECLARE_METATYPE(MessageType);
+
+HWEngine::HWEngine(QQmlEngine *engine, QObject *parent) :
+ QObject(parent),
+ m_engine(engine)
+{
+ qRegisterMetaType<MessageType>("MessageType");
+
+ QLibrary hwlib("./libhwengine.so");
+
+ if(!hwlib.load())
+ qWarning() << "Engine library not found" << hwlib.errorString();
+
+ flibRunEngine = (RunEngine_t*) hwlib.resolve("RunEngine");
+ flibRegisterGUIMessagesCallback = (registerGUIMessagesCallback_t*) hwlib.resolve("registerGUIMessagesCallback");
+ flibGetSeed = (getSeed_t*) hwlib.resolve("getSeed");
+ flibGetPreview = (getPreview_t*) hwlib.resolve("getPreview");
+ flibRunQuickGame = (runQuickGame_t*) hwlib.resolve("runQuickGame");
+ flibRunLocalGame = (runLocalGame_t*) hwlib.resolve("runLocalGame");
+ flibInit = (flibInit_t*) hwlib.resolve("flibInit");
+ flibFree = (flibFree_t*) hwlib.resolve("flibFree");
+
+ flibSetSeed = (setSeed_t*) hwlib.resolve("setSeed");
+ flibSetTheme = (setTheme_t*) hwlib.resolve("setTheme");
+ flibSetScript = (setScript_t*) hwlib.resolve("setScript");
+
+ flibGetThemesList = (getThemesList_t*) hwlib.resolve("getThemesList");
+ flibFreeThemesList = (freeThemesList_t*) hwlib.resolve("freeThemesList");
+ flibGetThemeIcon = (getThemeIcon_t*) hwlib.resolve("getThemeIcon");
+
+ flibGetScriptsList = (getScriptsList_t*) hwlib.resolve("getScriptsList");
+ flibGetSchemesList = (getSchemesList_t*) hwlib.resolve("getSchemesList");
+
+ flibResetGameConfig = (resetGameConfig_t*) hwlib.resolve("resetGameConfig");
+ flibGetTeamsList = (getTeamsList_t*) hwlib.resolve("getTeamsList");
+ flibTryAddTeam = (tryAddTeam_t*) hwlib.resolve("tryAddTeam");
+ flibTryRemoveTeam = (tryRemoveTeam_t*) hwlib.resolve("tryRemoveTeam");
+ flibChangeTeamColor = (changeTeamColor_t*) hwlib.resolve("changeTeamColor");
+
+ flibInit("/usr/home/unC0Rr/Sources/Hedgewars/Hedgewars-GC/share/hedgewars/Data", "/usr/home/unC0Rr/.hedgewars");
+ flibRegisterGUIMessagesCallback(this, &guiMessagesCallback);
+
+ ThemeIconProvider * themeIcon = (ThemeIconProvider *)m_engine->imageProvider(QLatin1String("theme"));
+ themeIcon->setFileContentsFunction(flibGetThemeIcon);
+
+ fillModels();
+}
+
+HWEngine::~HWEngine()
+{
+ flibFree();
+}
+
+void HWEngine::getPreview()
+{
+ flibSetSeed(QUuid::createUuid().toString().toLatin1());
+ flibGetPreview();
+}
+
+void HWEngine::runQuickGame()
+{
+ flibSetSeed(QUuid::createUuid().toString().toLatin1());
+ flibRunQuickGame();
+}
+
+void HWEngine::runLocalGame()
+{
+ flibRunLocalGame();
+}
+
+
+static QObject *hwengine_singletontype_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
+{
+ Q_UNUSED(scriptEngine)
+
+ HWEngine *hwengine = new HWEngine(engine);
+ return hwengine;
+}
+
+void HWEngine::exposeToQML()
+{
+ qDebug("HWEngine::exposeToQML");
+ qmlRegisterSingletonType<HWEngine>("Hedgewars.Engine", 1, 0, "HWEngine", hwengine_singletontype_provider);
+}
+
+
+void HWEngine::guiMessagesCallback(void *context, MessageType mt, const char * msg, uint32_t len)
+{
+ HWEngine * obj = (HWEngine *)context;
+ QByteArray b = QByteArray(msg, len);
+
+ qDebug() << "FLIPC in" << b.size() << b;
+
+ QMetaObject::invokeMethod(obj, "engineMessageHandler", Qt::QueuedConnection, Q_ARG(MessageType, mt), Q_ARG(QByteArray, b));
+}
+
+void HWEngine::engineMessageHandler(MessageType mt, const QByteArray &msg)
+{
+ switch(mt)
+ {
+ case MSG_PREVIEW: {
+ PreviewImageProvider * preview = (PreviewImageProvider *)m_engine->imageProvider(QLatin1String("preview"));
+ preview->setPixmap(msg);
+ emit previewImageChanged();
+ break;
+ }
+ case MSG_ADDPLAYINGTEAM: {
+ QStringList l = QString::fromUtf8(msg).split('\n');
+ emit playingTeamAdded(l[1], l[0].toInt(), true);
+ break;
+ }
+ case MSG_REMOVEPLAYINGTEAM: {
+ emit playingTeamRemoved(msg);
+ break;
+ }
+ case MSG_ADDTEAM: {
+ emit localTeamAdded(msg, 0);
+ break;
+ }
+ case MSG_REMOVETEAM: {
+ emit localTeamRemoved(msg);
+ break;
+ }
+ case MSG_TEAMCOLOR: {
+ QStringList l = QString::fromUtf8(msg).split('\n');
+ emit teamColorChanged(l[0], QColor::fromRgba(l[1].toInt()).name());
+ break;
+ }
+ }
+}
+
+QString HWEngine::currentSeed()
+{
+ return QString::fromLatin1(flibGetSeed());
+}
+
+void HWEngine::fillModels()
+{
+ QStringList resultModel;
+
+ char ** themes = flibGetThemesList();
+ for (char **i = themes; *i != NULL; i++)
+ resultModel << QString::fromUtf8(*i);
+ flibFreeThemesList(themes);
+
+ m_engine->rootContext()->setContextProperty("themesModel", QVariant::fromValue(resultModel));
+
+ // scripts model
+ resultModel.clear();
+ for (char **i = flibGetScriptsList(); *i != NULL; i++)
+ resultModel << QString::fromUtf8(*i);
+
+ m_engine->rootContext()->setContextProperty("scriptsModel", QVariant::fromValue(resultModel));
+
+ // schemes model
+ resultModel.clear();
+ for (char **i = flibGetSchemesList(); *i != NULL; i++)
+ resultModel << QString::fromUtf8(*i);
+
+ m_engine->rootContext()->setContextProperty("schemesModel", QVariant::fromValue(resultModel));
+}
+
+void HWEngine::getTeamsList()
+{
+ char ** teams = flibGetTeamsList();
+ for (char **i = teams; *i != NULL; i++) {
+ QString team = QString::fromUtf8(*i);
+
+ emit localTeamAdded(team, 0);
+ }
+}
+
+void HWEngine::tryAddTeam(const QString &teamName)
+{
+ flibTryAddTeam(teamName.toUtf8().constData());
+}
+
+void HWEngine::tryRemoveTeam(const QString &teamName)
+{
+ flibTryRemoveTeam(teamName.toUtf8().constData());
+}
+
+void HWEngine::resetGameConfig()
+{
+ flibResetGameConfig();
+}
+
+void HWEngine::changeTeamColor(const QString &teamName, int dir)
+{
+ flibChangeTeamColor(teamName.toUtf8().constData(), dir);
+}
+
+void HWEngine::setTheme(const QString &theme)
+{
+ flibSetTheme(theme.toUtf8().constData());
+}
+
+void HWEngine::setScript(const QString &script)
+{
+ flibSetScript(script.toUtf8().constData());
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qmlFrontend/hwengine.h Sat Jan 03 23:46:26 2015 +0300
@@ -0,0 +1,58 @@
+#ifndef HWENGINE_H
+#define HWENGINE_H
+
+#include <QObject>
+#include <QByteArray>
+#include <QVector>
+#include <QPixmap>
+
+#include "flib.h"
+
+class QQmlEngine;
+
+class HWEngine : public QObject
+{
+ Q_OBJECT
+public:
+ explicit HWEngine(QQmlEngine * engine, QObject *parent = 0);
+ ~HWEngine();
+
+ static void exposeToQML();
+ Q_INVOKABLE void getPreview();
+ Q_INVOKABLE void runQuickGame();
+ Q_INVOKABLE void runLocalGame();
+ Q_INVOKABLE QString currentSeed();
+ Q_INVOKABLE void getTeamsList();
+ Q_INVOKABLE void resetGameConfig();
+
+ Q_INVOKABLE void setTheme(const QString & theme);
+ Q_INVOKABLE void setScript(const QString & script);
+
+ Q_INVOKABLE void tryAddTeam(const QString & teamName);
+ Q_INVOKABLE void tryRemoveTeam(const QString & teamName);
+ Q_INVOKABLE void changeTeamColor(const QString & teamName, int dir);
+
+signals:
+ void previewImageChanged();
+ void localTeamAdded(const QString & teamName, int aiLevel);
+ void localTeamRemoved(const QString & teamName);
+
+ void playingTeamAdded(const QString & teamName, int aiLevel, bool isLocal);
+ void playingTeamRemoved(const QString & teamName);
+
+ void teamColorChanged(const QString & teamName, const QString & colorValue);
+
+public slots:
+
+private:
+ QQmlEngine * m_engine;
+
+ static void guiMessagesCallback(void * context, MessageType mt, const char * msg, uint32_t len);
+ void fillModels();
+
+private slots:
+ void engineMessageHandler(MessageType mt, const QByteArray &msg);
+};
+
+#endif // HWENGINE_H
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qmlFrontend/main.cpp Sat Jan 03 23:46:26 2015 +0300
@@ -0,0 +1,25 @@
+#include <QtGui/QGuiApplication>
+#include <QQmlEngine>
+
+#include "qtquick2applicationviewer/qtquick2applicationviewer.h"
+#include "hwengine.h"
+#include "previewimageprovider.h"
+#include "themeiconprovider.h"
+
+
+int main(int argc, char *argv[])
+{
+ QGuiApplication app(argc, argv);
+
+ HWEngine::exposeToQML();
+
+ QtQuick2ApplicationViewer viewer;
+
+ viewer.engine()->addImageProvider(QLatin1String("preview"), new PreviewImageProvider());
+ viewer.engine()->addImageProvider(QLatin1String("theme"), new ThemeIconProvider());
+
+ viewer.setMainQmlFile(QStringLiteral("qml/qmlFrontend/main.qml"));
+ viewer.showExpanded();
+
+ return app.exec();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qmlFrontend/previewimageprovider.cpp Sat Jan 03 23:46:26 2015 +0300
@@ -0,0 +1,36 @@
+#include "previewimageprovider.h"
+
+PreviewImageProvider::PreviewImageProvider()
+ : QQuickImageProvider(QQuickImageProvider::Pixmap)
+{
+}
+
+QPixmap PreviewImageProvider::requestPixmap(const QString &id, QSize *size, const QSize &requestedSize)
+{
+ Q_UNUSED(id);
+ Q_UNUSED(requestedSize);
+
+ if (size)
+ *size = m_px.size();
+
+ return m_px;
+}
+
+void PreviewImageProvider::setPixmap(const QByteArray &px)
+{
+ QVector<QRgb> colorTable;
+ colorTable.resize(256);
+ for(int i = 0; i < 256; ++i)
+ colorTable[i] = qRgba(255, 255, 0, i);
+
+ const quint8 *buf = (const quint8*) px.constData();
+ QImage im(buf, 256, 128, QImage::Format_Indexed8);
+ im.setColorTable(colorTable);
+
+ m_px = QPixmap::fromImage(im, Qt::ColorOnly);
+ //QPixmap pxres(px.size());
+ //QPainter p(&pxres);
+
+ //p.fillRect(pxres.rect(), linearGrad);
+ //p.drawPixmap(0, 0, px);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qmlFrontend/previewimageprovider.h Sat Jan 03 23:46:26 2015 +0300
@@ -0,0 +1,21 @@
+#ifndef PREVIEWIMAGEPROVIDER_H
+#define PREVIEWIMAGEPROVIDER_H
+
+#include <QQuickImageProvider>
+#include <QPixmap>
+#include <QSize>
+
+class PreviewImageProvider : public QQuickImageProvider
+{
+public:
+ PreviewImageProvider();
+
+ QPixmap requestPixmap(const QString &id, QSize *size, const QSize &requestedSize);
+
+ void setPixmap(const QByteArray & px);
+
+private:
+ QPixmap m_px;
+};
+
+#endif // PREVIEWIMAGEPROVIDER_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qmlFrontend/qml/qmlFrontend/First.qml Sat Jan 03 23:46:26 2015 +0300
@@ -0,0 +1,29 @@
+import QtQuick 2.0
+
+Rectangle {
+ HWButton {
+ id: btnLocalGame
+ x: 8
+ y: 80
+ width: 166
+ height: 166
+
+ onClicked: pages.currentPage = "LocalGame"
+ }
+
+ HWButton {
+ id: btnNetwork
+ x: 192
+ y: 80
+ width: 166
+ height: 166
+ }
+
+ HWButton {
+ id: btnAbout
+ x: 100
+ y: 16
+ width: 200
+ height: 50
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qmlFrontend/qml/qmlFrontend/GameConfig.qml Sat Jan 03 23:46:26 2015 +0300
@@ -0,0 +1,266 @@
+import QtQuick 2.0
+import Hedgewars.Engine 1.0
+
+
+Rectangle {
+ HWButton {
+ id: btnPreview
+ x: 50
+ y: 16
+ width: 256
+ height: 128
+
+ onClicked: HWEngine.getPreview()
+
+ Connections {
+ target: HWEngine
+ onPreviewImageChanged: previewImage.source = "image://preview/" + HWEngine.currentSeed()
+ }
+
+ Image {
+ id: previewImage
+ x: 0
+ y: 0
+ width: 256
+ height: 128
+ cache: false
+ }
+ }
+
+ HWButton {
+ id: btnRunGame
+ x: 600
+ y: 440
+ width: 32
+ height: 32
+
+ onClicked: HWEngine.runLocalGame()
+ }
+
+ HWComboBox {
+ id: cbTheme
+ x: 50
+ y: 160
+ width: 256
+ height: 64
+
+ model: themesModel
+ delegate: Rectangle {
+ height: 25
+ width: 100
+ color: "transparent"
+
+ property alias itemIconSource: themeIcon.source
+ property alias itemText: themeName.text
+
+ Row {
+ Image {id: themeIcon; width: height; height: parent.height; source: "image://theme/" + modelData}
+ Text {id: themeName; text: modelData }
+ }
+
+ MouseArea {
+ z: 1
+ anchors.fill: parent
+ onClicked: {
+ cbTheme.currentIndex = index
+ HWEngine.setTheme(themeName.text)
+ }
+ }
+ }
+ }
+
+ HWComboBox {
+ id: cbScript
+ x: 50
+ y: 256
+ width: 256
+ height: 64
+
+ model: scriptsModel
+ delegate: Rectangle {
+ height: 25
+ width: 100
+ color: "transparent"
+
+ property string itemIconSource: ""
+ property alias itemText: scriptName.text
+
+ Row {
+ //Image {id: themeIcon; width: height; height: parent.height; source: "image://theme/" + modelData}
+ Text {id: scriptName; text: modelData }
+ }
+
+ MouseArea {
+ z: 1
+ anchors.fill: parent
+ onClicked: {
+ cbScript.currentIndex = index
+ HWEngine.setScript(scriptName.text)
+ }
+ }
+ }
+ }
+
+ HWComboBox {
+ id: cbScheme
+ x: 50
+ y: 336
+ width: 256
+ height: 64
+
+ model: schemesModel
+ delegate: Rectangle {
+ height: 25
+ width: 100
+ color: "transparent"
+
+ property string itemIconSource: ""
+ property alias itemText: schemeName.text
+
+ Row {
+ //Image {id: themeIcon; width: height; height: parent.height; source: "image://theme/" + modelData}
+ Text {id: schemeName; text: modelData }
+ }
+
+ MouseArea {
+ z: 1
+ anchors.fill: parent
+ onClicked: {
+ cbScheme.currentIndex = index
+ //HWEngine.setScheme(schemeName.text)
+ }
+ }
+ }
+ }
+
+
+ ListView {
+ id: playingTeamsList
+ x: 440
+ y: 16
+ width: 100
+ height: 192
+ highlight: Rectangle { color: "#eaea00"; radius: 4 }
+ focus: true
+ clip: true
+
+ model: ListModel {
+ id: playingTeamsModel
+ }
+
+ delegate: Rectangle {
+ id: teamDelegate
+ height: 24
+ width: parent.width
+ radius: 8
+ border.width: 2
+ border.color: "#eaea00"
+
+ Row {
+ Rectangle {
+ height: 20
+ width: height
+ color: teamColor
+ border.width: 2
+ border.color: "#eaea00"
+
+ MouseArea {
+ z: 1
+ anchors.fill: parent
+ acceptedButtons: Qt.LeftButton | Qt.RightButton
+ onClicked: {
+ if (mouse.button === Qt.LeftButton)
+ HWEngine.changeTeamColor(name, 1)
+ else if (mouse.button === Qt.RightButton)
+ HWEngine.changeTeamColor(name, -1)
+ }
+ onWheel: HWEngine.changeTeamColor(name, -wheel.angleDelta.y)
+ }
+ }
+
+ Text { text: name
+ MouseArea {
+ z: 1
+ anchors.fill: parent
+ onClicked: HWEngine.tryRemoveTeam(name)
+ }
+ }
+ }
+
+
+ }
+
+ Connections {
+ target: HWEngine
+ onPlayingTeamAdded: playingTeamsModel.append({
+ "aiLevel": aiLevel
+ , "name": teamName
+ , "local": isLocal
+ , "teamColor": "#000000"
+ })
+ onPlayingTeamRemoved: {
+ var i = playingTeamsModel.count - 1;
+ while ((i >= 0) && (playingTeamsModel.get(i).name !== teamName)) --i
+
+ if(i >= 0) playingTeamsModel.remove(i, 1)
+ }
+ onTeamColorChanged: {
+ var i = playingTeamsModel.count - 1;
+ while ((i >= 0) && (playingTeamsModel.get(i).name !== teamName)) --i
+
+ if(i >= 0) playingTeamsModel.setProperty(i, "teamColor", colorValue)
+ }
+ }
+ }
+
+ ListView {
+ id: localTeamsList
+ x: 440
+ y: 224
+ width: 100
+ height: 192
+ highlight: Rectangle { color: "#eaea00"; radius: 4 }
+ focus: true
+ clip: true
+
+ model: ListModel {
+ id: localTeamsModel
+ }
+
+ delegate: Rectangle {
+ id: localTeamDelegate
+ height: 24
+ width: parent.width
+ radius: 8
+ border.width: 2
+ border.color: "#eaea00"
+
+ Row {
+ Text { text: name }
+ }
+
+ MouseArea {
+ z: 1
+ anchors.fill: parent
+ onClicked: HWEngine.tryAddTeam(name)
+ }
+ }
+
+ Connections {
+ target: HWEngine
+ onLocalTeamAdded: localTeamsModel.append({"aiLevel": aiLevel, "name": teamName})
+ onLocalTeamRemoved: {
+ var i = localTeamsModel.count - 1;
+ while ((i >= 0) && (localTeamsModel.get(i).name !== teamName)) --i
+
+ if(i >= 0) localTeamsModel.remove(i, 1)
+ }
+ }
+ }
+
+ Component.onCompleted: {
+ HWEngine.resetGameConfig()
+ HWEngine.getTeamsList()
+ HWEngine.getPreview()
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qmlFrontend/qml/qmlFrontend/HWButton.qml Sat Jan 03 23:46:26 2015 +0300
@@ -0,0 +1,42 @@
+import QtQuick 2.0
+
+Rectangle {
+ id: hwbutton
+ width: 360
+ height: 360
+ color: "#15193a"
+ radius: 8
+ border.width: 4
+ opacity: 1
+
+ signal clicked()
+
+ Behavior on border.color {
+ ColorAnimation {}
+ }
+
+ MouseArea {
+ id: mousearea
+ anchors.fill: parent
+ hoverEnabled: true
+ onClicked: parent.clicked()
+ }
+
+ states: [
+ State {
+ when: mousearea.containsMouse
+
+ PropertyChanges {
+ target: hwbutton
+ border.color: "#eaea00"
+ }
+ }
+ , State {
+ when: !mousearea.containsMouse
+
+ PropertyChanges {
+ target: hwbutton
+ border.color: "#ea761d"
+ }
+ }]
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qmlFrontend/qml/qmlFrontend/HWComboBox.qml Sat Jan 03 23:46:26 2015 +0300
@@ -0,0 +1,57 @@
+import QtQuick 2.0
+import QtQuick.Window 2.1
+
+HWButton {
+ property alias model: itemsList.model
+ property alias delegate: itemsList.delegate
+ property alias currentIndex: itemsList.currentIndex
+
+ Window {
+ id: selection
+ visibility: Window.Hidden
+ modality: Qt.WindowModal
+ flags: Qt.Dialog
+
+ ListView {
+ id: itemsList
+ x: 0
+ y: 64
+ anchors.fill: parent
+ anchors.bottomMargin: 32
+ highlight: Rectangle { color: "#eaea00"; radius: 4 }
+ focus: true
+
+ onCurrentItemChanged: {
+ cbIcon.source = currentItem.itemIconSource
+ cbText.text = currentItem.itemText
+ }
+ }
+
+ HWButton {
+ x: parent.width - 32
+ y: parent.height - 32
+ width: 32
+ height: 32
+
+ onClicked: selection.visibility = Window.Hidden;
+ }
+ }
+
+ Row {
+ anchors.fill: parent
+ anchors.margins: 4
+
+ Image {
+ id: cbIcon
+ width: height
+ height: parent.height
+ }
+
+ Text {
+ id: cbText
+ height: parent.height
+ }
+ }
+
+ onClicked: selection.visibility = Window.Windowed
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qmlFrontend/qml/qmlFrontend/LocalGame.qml Sat Jan 03 23:46:26 2015 +0300
@@ -0,0 +1,24 @@
+import QtQuick 2.0
+import Hedgewars.Engine 1.0
+
+Rectangle {
+ HWButton {
+ id: btnQuickGame
+ x: 8
+ y: 66
+ width: 150
+ height: 150
+
+ onClicked: HWEngine.runQuickGame()
+ }
+
+ HWButton {
+ id: btnMultiplayer
+ x: 192
+ y: 66
+ width: 150
+ height: 150
+
+ onClicked: pages.currentPage = "GameConfig"
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qmlFrontend/qml/qmlFrontend/main.qml Sat Jan 03 23:46:26 2015 +0300
@@ -0,0 +1,35 @@
+import QtQuick 2.0
+
+Rectangle {
+ id: pages
+ width: 800
+ height: 600
+
+ property variant pagesList : [
+ "First"
+ , "LocalGame"
+ , "GameConfig"
+ ];
+
+ property string currentPage : "First";
+
+ Repeater {
+ model: pagesList;
+
+ delegate: Loader {
+ active: false
+ asynchronous: true
+ anchors.fill: parent
+ visible: (currentPage === modelData)
+ source: "%1.qml".arg(modelData)
+ onVisibleChanged: loadIfNotLoaded();
+ Component.onCompleted: loadIfNotLoaded();
+
+ function loadIfNotLoaded ()
+ {
+ if (visible && !active)
+ active = true;
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qmlFrontend/qmlFrontend.pro Sat Jan 03 23:46:26 2015 +0300
@@ -0,0 +1,41 @@
+# Add more folders to ship with the application, here
+folder_01.source = qml/qmlFrontend
+folder_01.target = qml
+DEPLOYMENTFOLDERS = folder_01
+
+# Additional import path used to resolve QML modules in Creator's code model
+QML_IMPORT_PATH =
+
+# If your application uses the Qt Mobility libraries, uncomment the following
+# lines and add the respective components to the MOBILITY variable.
+# CONFIG += mobility
+# MOBILITY +=
+
+# The .cpp file which was generated for your project. Feel free to hack it.
+SOURCES += main.cpp \
+ hwengine.cpp \
+ previewimageprovider.cpp \
+ themeiconprovider.cpp
+
+# Installation path
+# target.path =
+
+# Please do not modify the following two lines. Required for deployment.
+include(qtquick2applicationviewer/qtquick2applicationviewer.pri)
+qtcAddDeployment()
+
+HEADERS += \
+ qtquick2applicationviewer/qtquick2applicationviewer.h \
+ hwengine.h \
+ flib.h \
+ previewimageprovider.h \
+ themeiconprovider.h
+
+OTHER_FILES += \
+ qtquick2applicationviewer/qtquick2applicationviewer.pri \
+ qml/qmlFrontend/HWButton.qml \
+ qml/qmlFrontend/main.qml \
+ qml/qmlFrontend/LocalGame.qml \
+ qml/qmlFrontend/GameConfig.qml \
+ qml/qmlFrontend/First.qml \
+ qml/qmlFrontend/HWComboBox.qml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qmlFrontend/qtquick2applicationviewer/qtquick2applicationviewer.cpp Sat Jan 03 23:46:26 2015 +0300
@@ -0,0 +1,81 @@
+// checksum 0x4f6f version 0x90005
+/*
+ This file was generated by the Qt Quick 2 Application wizard of Qt Creator.
+ QtQuick2ApplicationViewer is a convenience class containing mobile device specific
+ code such as screen orientation handling. Also QML paths and debugging are
+ handled here.
+ It is recommended not to modify this file, since newer versions of Qt Creator
+ may offer an updated version of it.
+*/
+
+#include "qtquick2applicationviewer.h"
+
+#include <QtCore/QCoreApplication>
+#include <QtCore/QDir>
+#include <QtQml/QQmlEngine>
+
+class QtQuick2ApplicationViewerPrivate
+{
+ QString mainQmlFile;
+ friend class QtQuick2ApplicationViewer;
+ static QString adjustPath(const QString &path);
+};
+
+QString QtQuick2ApplicationViewerPrivate::adjustPath(const QString &path)
+{
+#if defined(Q_OS_MAC)
+ if (!QDir::isAbsolutePath(path))
+ return QString::fromLatin1("%1/../Resources/%2")
+ .arg(QCoreApplication::applicationDirPath(), path);
+#elif defined(Q_OS_BLACKBERRY)
+ if (!QDir::isAbsolutePath(path))
+ return QString::fromLatin1("app/native/%1").arg(path);
+#elif !defined(Q_OS_ANDROID)
+ QString pathInInstallDir =
+ QString::fromLatin1("%1/../%2").arg(QCoreApplication::applicationDirPath(), path);
+ if (QFileInfo(pathInInstallDir).exists())
+ return pathInInstallDir;
+ pathInInstallDir =
+ QString::fromLatin1("%1/%2").arg(QCoreApplication::applicationDirPath(), path);
+ if (QFileInfo(pathInInstallDir).exists())
+ return pathInInstallDir;
+#endif
+ return path;
+}
+
+QtQuick2ApplicationViewer::QtQuick2ApplicationViewer(QWindow *parent)
+ : QQuickView(parent)
+ , d(new QtQuick2ApplicationViewerPrivate())
+{
+ connect(engine(), SIGNAL(quit()), SLOT(close()));
+ setResizeMode(QQuickView::SizeRootObjectToView);
+}
+
+QtQuick2ApplicationViewer::~QtQuick2ApplicationViewer()
+{
+ delete d;
+}
+
+void QtQuick2ApplicationViewer::setMainQmlFile(const QString &file)
+{
+ d->mainQmlFile = QtQuick2ApplicationViewerPrivate::adjustPath(file);
+#ifdef Q_OS_ANDROID
+ setSource(QUrl(QLatin1String("assets:/")+d->mainQmlFile));
+#else
+ setSource(QUrl::fromLocalFile(d->mainQmlFile));
+#endif
+}
+
+void QtQuick2ApplicationViewer::addImportPath(const QString &path)
+{
+ engine()->addImportPath(QtQuick2ApplicationViewerPrivate::adjustPath(path));
+}
+
+void QtQuick2ApplicationViewer::showExpanded()
+{
+#if defined(Q_WS_SIMULATOR) || defined(Q_OS_QNX)
+ showFullScreen();
+#else
+ show();
+#endif
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qmlFrontend/qtquick2applicationviewer/qtquick2applicationviewer.h Sat Jan 03 23:46:26 2015 +0300
@@ -0,0 +1,33 @@
+// checksum 0xfde6 version 0x90005
+/*
+ This file was generated by the Qt Quick 2 Application wizard of Qt Creator.
+ QtQuick2ApplicationViewer is a convenience class containing mobile device specific
+ code such as screen orientation handling. Also QML paths and debugging are
+ handled here.
+ It is recommended not to modify this file, since newer versions of Qt Creator
+ may offer an updated version of it.
+*/
+
+#ifndef QTQUICK2APPLICATIONVIEWER_H
+#define QTQUICK2APPLICATIONVIEWER_H
+
+#include <QtQuick/QQuickView>
+
+class QtQuick2ApplicationViewer : public QQuickView
+{
+ Q_OBJECT
+
+public:
+ explicit QtQuick2ApplicationViewer(QWindow *parent = 0);
+ virtual ~QtQuick2ApplicationViewer();
+
+ void setMainQmlFile(const QString &file);
+ void addImportPath(const QString &path);
+
+ void showExpanded();
+
+private:
+ class QtQuick2ApplicationViewerPrivate *d;
+};
+
+#endif // QTQUICK2APPLICATIONVIEWER_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qmlFrontend/qtquick2applicationviewer/qtquick2applicationviewer.pri Sat Jan 03 23:46:26 2015 +0300
@@ -0,0 +1,180 @@
+# checksum 0x7b0d version 0x90005
+# This file was generated by the Qt Quick 2 Application wizard of Qt Creator.
+# The code below adds the QtQuick2ApplicationViewer to the project and handles
+# the activation of QML debugging.
+# It is recommended not to modify this file, since newer versions of Qt Creator
+# may offer an updated version of it.
+
+QT += qml quick
+
+SOURCES += $$PWD/qtquick2applicationviewer.cpp
+HEADERS += $$PWD/qtquick2applicationviewer.h
+INCLUDEPATH += $$PWD
+# This file was generated by an application wizard of Qt Creator.
+# The code below handles deployment to Android and Maemo, aswell as copying
+# of the application data to shadow build directories on desktop.
+# It is recommended not to modify this file, since newer versions of Qt Creator
+# may offer an updated version of it.
+
+defineTest(qtcAddDeployment) {
+for(deploymentfolder, DEPLOYMENTFOLDERS) {
+ item = item$${deploymentfolder}
+ greaterThan(QT_MAJOR_VERSION, 4) {
+ itemsources = $${item}.files
+ } else {
+ itemsources = $${item}.sources
+ }
+ $$itemsources = $$eval($${deploymentfolder}.source)
+ itempath = $${item}.path
+ $$itempath= $$eval($${deploymentfolder}.target)
+ export($$itemsources)
+ export($$itempath)
+ DEPLOYMENT += $$item
+}
+
+MAINPROFILEPWD = $$PWD
+
+android-no-sdk {
+ for(deploymentfolder, DEPLOYMENTFOLDERS) {
+ item = item$${deploymentfolder}
+ itemfiles = $${item}.files
+ $$itemfiles = $$eval($${deploymentfolder}.source)
+ itempath = $${item}.path
+ $$itempath = /data/user/qt/$$eval($${deploymentfolder}.target)
+ export($$itemfiles)
+ export($$itempath)
+ INSTALLS += $$item
+ }
+
+ target.path = /data/user/qt
+
+ export(target.path)
+ INSTALLS += target
+} else:android {
+ for(deploymentfolder, DEPLOYMENTFOLDERS) {
+ item = item$${deploymentfolder}
+ itemfiles = $${item}.files
+ $$itemfiles = $$eval($${deploymentfolder}.source)
+ itempath = $${item}.path
+ $$itempath = /assets/$$eval($${deploymentfolder}.target)
+ export($$itemfiles)
+ export($$itempath)
+ INSTALLS += $$item
+ }
+
+ x86 {
+ target.path = /libs/x86
+ } else: armeabi-v7a {
+ target.path = /libs/armeabi-v7a
+ } else {
+ target.path = /libs/armeabi
+ }
+
+ export(target.path)
+ INSTALLS += target
+} else:win32 {
+ copyCommand =
+ for(deploymentfolder, DEPLOYMENTFOLDERS) {
+ source = $$MAINPROFILEPWD/$$eval($${deploymentfolder}.source)
+ source = $$replace(source, /, \\)
+ sourcePathSegments = $$split(source, \\)
+ target = $$OUT_PWD/$$eval($${deploymentfolder}.target)/$$last(sourcePathSegments)
+ target = $$replace(target, /, \\)
+ target ~= s,\\\\\\.?\\\\,\\,
+ !isEqual(source,$$target) {
+ !isEmpty(copyCommand):copyCommand += &&
+ isEqual(QMAKE_DIR_SEP, \\) {
+ copyCommand += $(COPY_DIR) \"$$source\" \"$$target\"
+ } else {
+ source = $$replace(source, \\\\, /)
+ target = $$OUT_PWD/$$eval($${deploymentfolder}.target)
+ target = $$replace(target, \\\\, /)
+ copyCommand += test -d \"$$target\" || mkdir -p \"$$target\" && cp -r \"$$source\" \"$$target\"
+ }
+ }
+ }
+ !isEmpty(copyCommand) {
+ copyCommand = @echo Copying application data... && $$copyCommand
+ copydeploymentfolders.commands = $$copyCommand
+ first.depends = $(first) copydeploymentfolders
+ export(first.depends)
+ export(copydeploymentfolders.commands)
+ QMAKE_EXTRA_TARGETS += first copydeploymentfolders
+ }
+} else:unix {
+ maemo5 {
+ desktopfile.files = $${TARGET}.desktop
+ desktopfile.path = /usr/share/applications/hildon
+ icon.files = $${TARGET}64.png
+ icon.path = /usr/share/icons/hicolor/64x64/apps
+ } else:!isEmpty(MEEGO_VERSION_MAJOR) {
+ desktopfile.files = $${TARGET}_harmattan.desktop
+ desktopfile.path = /usr/share/applications
+ icon.files = $${TARGET}80.png
+ icon.path = /usr/share/icons/hicolor/80x80/apps
+ } else { # Assumed to be a Desktop Unix
+ copyCommand =
+ for(deploymentfolder, DEPLOYMENTFOLDERS) {
+ source = $$MAINPROFILEPWD/$$eval($${deploymentfolder}.source)
+ source = $$replace(source, \\\\, /)
+ macx {
+ target = $$OUT_PWD/$${TARGET}.app/Contents/Resources/$$eval($${deploymentfolder}.target)
+ } else {
+ target = $$OUT_PWD/$$eval($${deploymentfolder}.target)
+ }
+ target = $$replace(target, \\\\, /)
+ sourcePathSegments = $$split(source, /)
+ targetFullPath = $$target/$$last(sourcePathSegments)
+ targetFullPath ~= s,/\\.?/,/,
+ !isEqual(source,$$targetFullPath) {
+ !isEmpty(copyCommand):copyCommand += &&
+ copyCommand += $(MKDIR) \"$$target\"
+ copyCommand += && $(COPY_DIR) \"$$source\" \"$$target\"
+ }
+ }
+ !isEmpty(copyCommand) {
+ copyCommand = @echo Copying application data... && $$copyCommand
+ copydeploymentfolders.commands = $$copyCommand
+ first.depends = $(first) copydeploymentfolders
+ export(first.depends)
+ export(copydeploymentfolders.commands)
+ QMAKE_EXTRA_TARGETS += first copydeploymentfolders
+ }
+ }
+ !isEmpty(target.path) {
+ installPrefix = $${target.path}
+ } else {
+ installPrefix = /opt/$${TARGET}
+ }
+ for(deploymentfolder, DEPLOYMENTFOLDERS) {
+ item = item$${deploymentfolder}
+ itemfiles = $${item}.files
+ $$itemfiles = $$eval($${deploymentfolder}.source)
+ itempath = $${item}.path
+ $$itempath = $${installPrefix}/$$eval($${deploymentfolder}.target)
+ export($$itemfiles)
+ export($$itempath)
+ INSTALLS += $$item
+ }
+
+ !isEmpty(desktopfile.path) {
+ export(icon.files)
+ export(icon.path)
+ export(desktopfile.files)
+ export(desktopfile.path)
+ INSTALLS += icon desktopfile
+ }
+
+ isEmpty(target.path) {
+ target.path = $${installPrefix}/bin
+ export(target.path)
+ }
+ INSTALLS += target
+}
+
+export (ICON)
+export (INSTALLS)
+export (DEPLOYMENT)
+export (LIBS)
+export (QMAKE_EXTRA_TARGETS)
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qmlFrontend/themeiconprovider.cpp Sat Jan 03 23:46:26 2015 +0300
@@ -0,0 +1,38 @@
+#include <QByteArray>
+#include <QDebug>
+
+#include "themeiconprovider.h"
+#include "flib.h"
+
+ThemeIconProvider::ThemeIconProvider()
+ : QQuickImageProvider(QQuickImageProvider::Image)
+{
+ getThemeIcon = 0;
+}
+
+void ThemeIconProvider::setFileContentsFunction(getThemeIcon_t *f)
+{
+ getThemeIcon = f;
+}
+
+QImage ThemeIconProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize)
+{
+ Q_UNUSED(requestedSize);
+
+ if(!getThemeIcon)
+ return QImage();
+
+ QByteArray buf;
+ buf.resize(65536);
+
+ char * bufptr = buf.data();
+ uint32_t fileSize = getThemeIcon(id.toUtf8().data(), bufptr, buf.size());
+ buf.truncate(fileSize);
+ qDebug() << "ThemeIconProvider file size = " << fileSize;
+
+ QImage img = QImage::fromData(buf);
+
+ if (size)
+ *size = img.size();
+ return img;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qmlFrontend/themeiconprovider.h Sat Jan 03 23:46:26 2015 +0300
@@ -0,0 +1,21 @@
+#ifndef THEMEICONPROVIDER_H
+#define THEMEICONPROVIDER_H
+
+#include <QQuickImageProvider>
+#include <QImage>
+
+#include "flib.h"
+
+class ThemeIconProvider : public QQuickImageProvider
+{
+public:
+ ThemeIconProvider();
+
+ void setFileContentsFunction(getThemeIcon_t *f);
+
+ QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize);
+private:
+ getThemeIcon_t *getThemeIcon;
+};
+
+#endif // THEMEICONPROVIDER_H