--- a/.hgignore Thu Sep 03 11:51:08 2015 -0400
+++ b/.hgignore Thu Sep 03 20:59:48 2015 +0300
@@ -55,7 +55,6 @@
glob:project_files/Android-build/out
glob:project_files/Android-build/Makefile.android
glob:hedgewars-build-desktop-Qt*
-glob:hedgewars-build-desktop-Qt*
glob:*.depends
glob:tools/build_windows_koda.bat
glob:share/hedgewars/Data/misc/hwengine.desktop
@@ -65,8 +64,12 @@
glob:*.tar.*
glob:*.or
glob:*.res
+glob:build-*
+glob:hedgewars-build-*
+glob:*.pro.user
glob:Hedgewars.app/*
glob:tools/CreateMacBundle.cmake
glob:share/Info.plist
glob:CTestTestfile.cmake
glob:arch.c
+
--- a/CMakeLists.txt Thu Sep 03 11:51:08 2015 -0400
+++ b/CMakeLists.txt Thu Sep 03 20:59:48 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)
@@ -225,7 +225,7 @@
add_subdirectory(project_files/Android-build)
else(ANDROID)
add_subdirectory(bin)
- add_subdirectory(QTfrontend)
+ add_subdirectory(qmlFrontend)
add_subdirectory(share)
add_subdirectory(tools)
endif(ANDROID)
--- a/QTfrontend/net/tcpBase.cpp Thu Sep 03 11:51:08 2015 -0400
+++ b/QTfrontend/net/tcpBase.cpp Thu Sep 03 20:59:48 2015 +0300
@@ -111,8 +111,6 @@
m_connected(false),
IPCSocket(0)
{
- process = 0;
-
if(!IPCServer)
{
IPCServer = new QTcpServer(0);
--- a/hedgewars/ArgParsers.pas Thu Sep 03 11:51:08 2015 -0400
+++ b/hedgewars/ArgParsers.pas Thu Sep 03 20:59:48 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 Thu Sep 03 11:51:08 2015 -0400
+++ b/hedgewars/CMakeLists.txt Thu Sep 03 20:59:48 2015 +0300
@@ -104,6 +104,20 @@
uGearsUtils.pas
uTeams.pas
+ uFLAmmo.pas
+ uFLData.pas
+ uFLGameConfig.pas
+ uFLIPC.pas
+ uFLNet.pas
+ uFLNetProtocol.pas
+ uFLNetTypes.pas
+ uFLScripts.pas
+ uFLSchemes.pas
+ uFLTeams.pas
+ uFLTypes.pas
+ uFLUICallback.pas
+ uFLUtils.pas
+
#these interact with everything, so compile last
uScript.pas
)
--- a/hedgewars/SDLh.pas Thu Sep 03 11:51:08 2015 -0400
+++ b/hedgewars/SDLh.pas Thu Sep 03 20:59:48 2015 +0300
@@ -832,6 +832,8 @@
PSDL_Thread = Pointer;
PSDL_mutex = Pointer;
+ PSDL_sem = Pointer;
+ PSDL_cond = Pointer;
TSDL_GLattr = (
SDL_GL_RED_SIZE,
@@ -1054,6 +1056,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 Thu Sep 03 11:51:08 2015 -0400
+++ b/hedgewars/hwLibrary.pas Thu Sep 03 20:59:48 2015 +0300
@@ -29,65 +29,99 @@
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
+ , uFLAmmo
+ , uFLNet
+ , uFLNetProtocol
+ , uFLUICallback
+ ;
{$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);
+ uFLNet.initModule;
+end;
+
+procedure flibFree; cdecl;
+begin
+ uFLNet.freeModule;
+ uPhysFSLayer.freemodule;
+ freeIPC;
+end;
+
{$IFDEF ANDROID}
function JNI_HW_versionInfoNet(env: PJNIEnv; obj: JObject):JInt;cdecl;
begin
@@ -119,6 +153,35 @@
Game;
{$ELSE}
exports
+ runQuickGame,
+ runLocalGame,
+ getPreview,
+ registerUIMessagesCallback,
+ flibInit,
+ flibFree,
+ //game config
+ resetGameConfig,
+ setSeed,
+ getSeed,
+ setTheme,
+ setScript,
+ setScheme,
+ setAmmo,
+ getThemesList,
+ freeThemesList,
+ getThemeIcon,
+ getScriptsList,
+ getSchemesList,
+ getAmmosList,
+ getTeamsList,
+ tryAddTeam,
+ tryRemoveTeam,
+ changeTeamColor,
+ // network
+ connectOfficialServer,
+ passNetData,
+
+ // dunno what these are
RunEngine,
LoadLocaleWrapper,
HW_versionInfo,
--- a/hedgewars/hwengine.pas Thu Sep 03 11:51:08 2015 -0400
+++ b/hedgewars/hwengine.pas Thu Sep 03 20:59:48 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;
@@ -344,8 +333,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));
@@ -407,7 +396,6 @@
begin
if recordFileName = '' then
begin
- InitIPC;
SendIPCAndWaitReply(_S'C'); // ask for game config
end
else
@@ -466,8 +454,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
@@ -491,7 +479,6 @@
uStats.initModule;
uStore.initModule;
uRender.initModule;
- uTeams.initModule;
uVisualGears.initModule;
uVisualGearsHandlers.initModule;
uWorld.initModule;
@@ -535,7 +522,6 @@
uCommands.freeModule;
uVariables.freeModule;
uUtils.freeModule; // closes debug file
- uPhysFSLayer.freeModule;
uScript.freeModule;
end;
@@ -545,7 +531,6 @@
begin
initEverything(false);
- InitIPC;
IPCWaitPongEvent;
TryDo(InitStepsFlags = cifRandomize, 'Some parameters not set (flags = ' + inttostr(InitStepsFlags) + ')', true);
@@ -558,18 +543,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);
@@ -578,36 +566,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 Thu Sep 03 11:51:08 2015 -0400
+++ b/hedgewars/uDebug.pas Thu Sep 03 20:59:48 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/uFLAmmo.pas Thu Sep 03 20:59:48 2015 +0300
@@ -0,0 +1,135 @@
+unit uFLAmmo;
+interface
+uses uFLTypes;
+
+function getAmmosList: PPChar; cdecl;
+procedure freeAmmosList;
+
+function ammoByName(s: shortstring): PAmmo;
+procedure sendAmmoConfig(var ammo: TAmmo);
+
+implementation
+uses uFLUtils, uFLIPC, uPhysFSLayer, uFLData;
+
+const MAX_AMMO_NAMES = 64;
+type
+ TAmmoArray = array [0..0] of TAmmo;
+ PAmmoArray = ^TAmmoArray;
+var
+ ammoList: PAmmo;
+ ammoNumber: LongInt;
+ listOfAmmoNames: array[0..MAX_AMMO_NAMES] of PChar;
+
+procedure loadAmmo;
+var f: PFSFile;
+ ammo: PAmmo;
+ ammos: PAmmoArray;
+ s: ansistring;
+ i: Longword;
+begin
+ f:= pfsOpenRead('/Config/weapons.ini');
+ ammoNumber:= 0;
+
+ if f <> nil then
+ begin
+ while (not pfsEOF(f)) do
+ begin
+ pfsReadLnA(f, s);
+
+ if (length(s) > 0) and (s[1] <> '[') then
+ inc(ammoNumber);
+ end;
+
+ //inc(ammoNumber); // add some default ammo
+
+ ammoList:= GetMem(sizeof(ammoList^) * (ammoNumber + 1));
+ ammo:= PAmmo(ammoList);
+ pfsSeek(f, 0);
+
+ while (not pfsEOF(f)) do
+ begin
+ pfsReadLnA(f, s);
+
+ i:= 1;
+ while(i <= length(s)) and (s[i] <> '=') do inc(i);
+
+ if i < length(s) then
+ begin
+ ammo^.ammoName:= copy(s, 1, i - 1);
+ delete(s, 1, i);
+ // TODO: split into 4 shortstrings
+ i:= length(s) div 4;
+ ammo^.a:= copy(s, 1, i);
+ ammo^.b:= copy(s, i + 1, i);
+ ammo^.c:= copy(s, i * 2 + 1, i);
+ ammo^.d:= copy(s, i * 3 + 1, i);
+ inc(ammo)
+ end;
+ end;
+
+ pfsClose(f)
+ end;
+end;
+
+
+function getAmmosList: PPChar; cdecl;
+var i, t, l: Longword;
+ ammo: PAmmo;
+begin
+ if ammoList = nil then
+ loadAmmo;
+
+ t:= ammoNumber;
+ if t >= MAX_AMMO_NAMES then
+ t:= MAX_AMMO_NAMES;
+
+ ammo:= ammoList;
+ for i:= 0 to Pred(t) do
+ begin
+ l:= length(ammo^.ammoName);
+ if l >= 255 then l:= 254;
+ ammo^.ammoName[l + 1]:= #0;
+ listOfAmmoNames[i]:= @ammo^.ammoName[1];
+ inc(ammo)
+ end;
+
+ listOfAmmoNames[t]:= nil;
+
+ getAmmosList:= listOfAmmoNames
+end;
+
+function ammoByName(s: shortstring): PAmmo;
+var i: Longword;
+ ammo: PAmmo;
+begin
+ ammo:= ammoList;
+ i:= 0;
+ while (i < ammoNumber) and (ammo^.ammoName <> s) do
+ begin
+ inc(ammo);
+ inc(i)
+ end;
+
+ if i < ammoNumber then ammoByName:= ammo else ammoByName:= nil
+end;
+
+procedure freeAmmosList;
+begin
+ if ammoList <> nil then
+ FreeMem(ammoList, sizeof(ammoList^) * (ammoNumber + 1))
+end;
+
+
+procedure sendAmmoConfig(var ammo: TAmmo);
+var i: Longword;
+begin
+ with ammo do
+ begin
+ ipcToEngine('eammloadt ' + ammo.a);
+ ipcToEngine('eammprob ' + ammo.b);
+ ipcToEngine('eammdelay ' + ammo.c);
+ ipcToEngine('eammreinf ' + ammo.d);
+ end
+end;
+
+end.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hedgewars/uFLData.pas Thu Sep 03 20:59:48 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 Thu Sep 03 20:59:48 2015 +0300
@@ -0,0 +1,327 @@
+unit uFLGameConfig;
+interface
+uses uFLTypes;
+
+procedure resetGameConfig; cdecl;
+procedure runQuickGame; cdecl;
+procedure runLocalGame; cdecl;
+procedure getPreview; cdecl;
+
+procedure setSeed(seed: PChar); cdecl;
+function getSeed: PChar; cdecl;
+procedure setTheme(themeName: PChar); cdecl;
+procedure setScript(scriptName: PChar); cdecl;
+procedure setScheme(schemeName: PChar); cdecl;
+procedure setAmmo(ammoName: 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, uFLSChemes, uFLAmmo, uFLUICallback;
+
+const
+ MAXCONFIGS = 5;
+ MAXARGS = 32;
+
+type
+ TGameConfig = record
+ seed: shortstring;
+ theme: shortstring;
+ script: shortstring;
+ scheme: TScheme;
+ ammo: TAmmo;
+ 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);
+
+ sendSchemeConfig(scheme);
+
+ i:= 0;
+ while (i < 8) and (teams[i].hogsNumber > 0) do
+ begin
+ sendAmmoConfig(config^.ammo);
+ 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 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;
+ sendUI(mtAddPlayingTeam, @msg[1], length(msg));
+
+ msg:= teamName + #10 + colorsSet[teams[i].color];
+ sendUI(mtTeamColor, @msg[1], length(msg));
+
+ msg:= teamName;
+ sendUI(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;
+
+ sendUI(mtRemovePlayingTeam, @msg[1], length(msg));
+ sendUI(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];
+ sendUI(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;
+
+procedure setScheme(schemeName: PChar); cdecl;
+var scheme: PScheme;
+begin
+ scheme:= schemeByName(schemeName);
+
+ if scheme <> nil then
+ currentConfig.scheme:= scheme^
+end;
+
+procedure setAmmo(ammoName: PChar); cdecl;
+var ammo: PAmmo;
+begin
+ ammo:= ammoByName(ammoName);
+
+ if ammo <> nil then
+ currentConfig.ammo:= ammo^
+end;
+
+end.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hedgewars/uFLIPC.pas Thu Sep 03 20:59:48 2015 +0300
@@ -0,0 +1,237 @@
+unit uFLIPC;
+interface
+uses SDLh, uFLTypes;
+
+var msgFrontend, msgEngine, msgNet: TIPCMessage;
+ mutFrontend, mutEngine, mutNet: PSDL_mutex;
+ condFrontend, condEngine, condNet: PSDL_cond;
+
+procedure initIPC;
+procedure freeIPC;
+
+procedure ipcToEngine(s: shortstring);
+procedure ipcToEngineRaw(p: pointer; len: Longword);
+//function ipcReadFromEngine: shortstring;
+//function ipcCheckFromEngine: boolean;
+
+procedure ipcToNet(s: shortstring);
+procedure ipcToNetRaw(p: pointer; len: Longword);
+
+procedure ipcToFrontend(s: shortstring);
+procedure ipcToFrontendRaw(p: pointer; len: Longword);
+function ipcReadFromFrontend: shortstring;
+function ipcCheckFromFrontend: boolean;
+
+procedure registerIPCCallback(p: pointer; f: TIPCCallback);
+procedure registerNetCallback(p: pointer; f: TIPCCallback);
+
+implementation
+
+var callbackPointerF: pointer;
+ callbackFunctionF: TIPCCallback;
+ callbackListenerThreadF: PSDL_Thread;
+ callbackPointerN: pointer;
+ callbackFunctionN: TIPCCallback;
+ callbackListenerThreadN: 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 ipcToNet(s: shortstring);
+var msg: TIPCMessage;
+begin
+ msg.str:= s;
+ msg.buf:= nil;
+ ipcSend(msg, msgNet, mutNet, condNet)
+end;
+
+procedure ipcToEngineRaw(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, msgEngine, mutEngine, condEngine)
+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;
+
+procedure ipcToNetRaw(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, msgNet, mutNet, condNet)
+end;
+
+function ipcReadFromEngine: TIPCMessage;
+begin
+ ipcReadFromEngine:= ipcRead(msgFrontend, mutFrontend, condFrontend)
+end;
+
+function ipcReadFromFrontend: shortstring;
+begin
+ ipcReadFromFrontend:= ipcRead(msgEngine, mutEngine, condEngine).str
+end;
+
+function ipcReadToNet: TIPCMessage;
+begin
+ ipcReadToNet:= ipcRead(msgNet, mutNet, condNet)
+end;
+
+function ipcCheckFromEngine: boolean;
+begin
+ ipcCheckFromEngine:= ipcCheck(msgFrontend, mutFrontend)
+end;
+
+function ipcCheckFromFrontend: boolean;
+begin
+ ipcCheckFromFrontend:= ipcCheck(msgEngine, mutEngine)
+end;
+
+function engineListener(p: pointer): Longint; cdecl; export;
+var msg: TIPCMessage;
+begin
+ engineListener:= 0;
+ repeat
+ msg:= ipcReadFromEngine();
+ if msg.buf = nil then
+ callbackFunctionF(callbackPointerF, @msg.str[1], byte(msg.str[0]))
+ else
+ begin
+ callbackFunctionF(callbackPointerF, msg.buf, msg.len);
+ FreeMem(msg.buf, msg.len)
+ end
+ until false
+end;
+
+function netListener(p: pointer): Longint; cdecl; export;
+var msg: TIPCMessage;
+begin
+ netListener:= 0;
+ repeat
+ msg:= ipcReadToNet();
+ if msg.buf = nil then
+ callbackFunctionN(callbackPointerN, @msg.str[1], byte(msg.str[0]))
+ else
+ begin
+ callbackFunctionN(callbackPointerN, msg.buf, msg.len);
+ FreeMem(msg.buf, msg.len)
+ end
+ until false
+end;
+
+procedure registerIPCCallback(p: pointer; f: TIPCCallback);
+begin
+ callbackPointerF:= p;
+ callbackFunctionF:= f;
+ callbackListenerThreadF:= SDL_CreateThread(@engineListener{$IFDEF SDL2}, 'engineListener'{$ENDIF}, nil);
+end;
+
+procedure registerNetCallback(p: pointer; f: TIPCCallback);
+begin
+ callbackPointerN:= p;
+ callbackFunctionN:= f;
+ callbackListenerThreadN:= SDL_CreateThread(@netListener{$IFDEF SDL2}, 'netListener'{$ENDIF}, nil);
+end;
+
+procedure initIPC;
+begin
+ msgFrontend.str:= '';
+ msgFrontend.buf:= nil;
+ msgEngine.str:= '';
+ msgEngine.buf:= nil;
+ msgNet.str:= '';
+ msgNet.buf:= nil;
+
+ callbackPointerF:= nil;
+ callbackListenerThreadF:= nil;
+
+ mutFrontend:= SDL_CreateMutex;
+ mutEngine:= SDL_CreateMutex;
+ mutNet:= SDL_CreateMutex;
+ condFrontend:= SDL_CreateCond;
+ condEngine:= SDL_CreateCond;
+ condNet:= SDL_CreateCond;
+end;
+
+procedure freeIPC;
+begin
+ SDL_KillThread(callbackListenerThreadF);
+ SDL_KillThread(callbackListenerThreadN);
+ SDL_DestroyMutex(mutFrontend);
+ SDL_DestroyMutex(mutEngine);
+ SDL_DestroyMutex(mutNet);
+ SDL_DestroyCond(condFrontend);
+ SDL_DestroyCond(condEngine);
+ SDL_DestroyCond(condNet);
+end;
+
+end.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hedgewars/uFLNet.pas Thu Sep 03 20:59:48 2015 +0300
@@ -0,0 +1,295 @@
+unit uFLNet;
+interface
+
+procedure connectOfficialServer;
+
+procedure initModule;
+procedure freeModule;
+
+implementation
+uses SDLh, uFLIPC, uFLTypes, uFLUICallback, uFLNetTypes;
+
+const endCmd: string = #10 + #10;
+
+function getNextChar: char; forward;
+function getCurrChar: char; forward;
+procedure sendNet(s: shortstring); forward;
+
+type
+ TNetState = (netDisconnected, netConnecting, netLoggedIn);
+ TParserState = record
+ cmd: TCmdType;
+ l: LongInt;
+ netState: TNetState;
+ buf: shortstring;
+ bufpos: byte;
+ end;
+ PHandler = procedure;
+
+var state: TParserState;
+
+// generated stuff here
+const letters: array[0..206] of char = ('A', 'S', 'K', 'P', 'A', 'S', 'S', 'W', 'O', 'R', 'D', #10, 'B', 'A', 'N', 'L', 'I', 'S', 'T', #10, 'Y', 'E', #10, 'C', 'H', 'A', 'T', #10, 'L', 'I', 'E', 'N', 'T', '_', 'F', 'L', 'A', 'G', 'S', #10, 'O', 'N', 'N', 'E', 'C', 'T', 'E', 'D', #10, 'E', 'M', #10, 'H', 'H', '_', 'N', 'U', 'M', #10, 'I', 'N', 'F', 'O', #10, 'J', 'O', 'I', 'N', 'E', 'D', #10, 'I', 'N', 'G', #10, 'K', 'I', 'C', 'K', 'E', 'D', #10, 'L', 'E', 'F', 'T', #10, 'O', 'B', 'B', 'Y', ':', 'J', 'O', 'I', 'N', 'E', 'D', #10, 'L', 'E', 'F', 'T', #10, 'N', 'I', 'C', 'K', #10, 'O', 'T', 'I', 'C', 'E', #10, 'P', 'I', 'N', 'G', #10, 'R', 'O', 'T', 'O', #10, 'R', 'O', 'O', 'M', 'S', #10, 'U', 'N', 'D', '_', 'F', 'I', 'N', 'I', 'S', 'H', 'E', 'D', #10, 'U', 'N', '_', 'G', 'A', 'M', 'E', #10, 'S', 'E', 'R', 'V', 'E', 'R', '_', 'A', 'U', 'T', 'H', #10, 'M', 'E', 'S', 'S', 'A', 'G', 'E', #10, 'V', 'A', 'R', 'S', #10, 'T', 'E', 'A', 'M', '_', 'A', 'C', 'C', 'E', 'P', 'T', 'E', 'D', #10, 'C', 'O', 'L', 'O', 'R', #10, 'W', 'A', 'R', 'N', 'I', 'N', 'G', #10, #0, #10);
+
+const commands: array[0..206] of integer = (12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -38, 11, 7, 0, 0, 0, 0, 0, -37, 0, 0, -36, 26, 4, 0, 0, -35, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -34, 0, 0, 0, 0, 0, 0, 0, 0, -33, 3, 0, -32, 7, 0, 0, 0, 0, 0, -31, 5, 0, 0, 0, -30, 11, 0, 0, 0, 3, 0, -29, 0, 0, 0, -28, 7, 0, 0, 0, 0, 0, -27, 22, 4, 0, 0, -26, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, -25, 0, 0, 0, 0, -24, 11, 4, 0, 0, -23, 0, 0, 0, 0, 0, -22, 10, 4, 0, 0, -21, 0, 0, 0, 0, -20, 27, 18, 4, 0, 0, -19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -18, 0, 0, 0, 0, 0, 0, 0, -17, 25, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, -16, 8, 0, 0, 0, 0, 0, 0, -15, 0, 0, 0, 0, -14, 20, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, -13, 0, 0, 0, 0, 0, -12, 8, 0, 0, 0, 0, 0, 0, -11, 0, -10);
+
+procedure handler_ASKPASSWORD;
+begin
+end;
+
+procedure handler_BANLIST;
+begin
+end;
+
+procedure handler_BYE;
+begin
+end;
+
+procedure handler_CHAT;
+begin
+end;
+
+procedure handler_CLIENT_FLAGS;
+begin
+end;
+
+procedure handler_CONNECTED;
+var data: TCmdConnectedData;
+begin
+ sendUI(mtNetData, nil, 0);
+end;
+
+procedure handler_EM;
+begin
+end;
+
+procedure handler_HH_NUM;
+begin
+end;
+
+procedure handler_INFO;
+begin
+end;
+
+procedure handler_JOINED;
+begin
+end;
+
+procedure handler_JOINING;
+begin
+end;
+
+procedure handler_KICKED;
+begin
+end;
+
+procedure handler_LEFT;
+begin
+end;
+
+procedure handler_LOBBY_JOINED;
+begin
+end;
+
+procedure handler_LOBBY_LEFT;
+begin
+end;
+
+procedure handler_NICK;
+begin
+end;
+
+procedure handler_NOTICE;
+begin
+end;
+
+procedure handler_PING;
+begin
+ sendNet('PONG')
+end;
+
+procedure handler_PROTO;
+begin
+end;
+
+procedure handler_ROOMS;
+begin
+end;
+
+procedure handler_ROUND_FINISHED;
+begin
+end;
+
+procedure handler_RUN_GAME;
+begin
+end;
+
+procedure handler_SERVER_AUTH;
+begin
+end;
+
+procedure handler_SERVER_MESSAGE;
+begin
+end;
+
+procedure handler_SERVER_VARS;
+begin
+end;
+
+procedure handler_TEAM_ACCEPTED;
+begin
+end;
+
+procedure handler_TEAM_COLOR;
+begin
+end;
+
+procedure handler_WARNING;
+begin
+end;
+
+procedure handler___UNKNOWN__;
+begin
+ writeln('[NET] Unknown cmd');
+end;
+
+const handlers: array[0..28] of PHandler = (@handler___UNKNOWN__, @handler_WARNING, @handler_TEAM_COLOR, @handler_TEAM_ACCEPTED, @handler_SERVER_VARS, @handler_SERVER_MESSAGE, @handler_SERVER_AUTH, @handler_RUN_GAME, @handler_ROUND_FINISHED, @handler_ROOMS, @handler_PROTO, @handler_PING, @handler_NOTICE, @handler_NICK, @handler_LOBBY_LEFT, @handler_LOBBY_JOINED, @handler_LEFT, @handler_KICKED, @handler_JOINING, @handler_JOINED, @handler_INFO, @handler_HH_NUM, @handler_EM, @handler_CONNECTED, @handler_CLIENT_FLAGS, @handler_CHAT, @handler_BYE, @handler_BANLIST, @handler_ASKPASSWORD);
+
+
+// end of generated stuff
+procedure handleTail;
+var cnt: Longint;
+ c: char;
+begin
+ state.l:= 0;
+
+ c:= getCurrChar;
+ repeat
+ if c = #10 then cnt:= 0 else cnt:= 1;
+ repeat
+ c:= getNextChar;
+ inc(cnt)
+ until (c = #0) or (c = #10);
+ until (c = #0) or (cnt = 1)
+end;
+
+var sock: PTCPSocket;
+ netReaderThread: PSDL_Thread;
+
+function getCurrChar: char;
+begin
+ getCurrChar:= state.buf[state.bufpos]
+end;
+
+function getNextChar: char;
+var r: byte;
+begin
+ if state.bufpos < byte(state.buf[0]) then
+ begin
+ inc(state.bufpos);
+ end else
+ begin
+ r:= SDLNet_TCP_Recv(sock, @state.buf[1], 255);
+ if r > 0 then
+ begin
+ state.bufpos:= 1;
+ state.buf[0]:= char(r);
+ end else
+ begin
+ state.bufpos:= 0;
+ state.buf[0]:= #0;
+ end
+ end;
+
+ getNextChar:= state.buf[state.bufpos];
+end;
+
+function netWriter(sock: PTCPSocket): LongInt; cdecl; export;
+begin
+ netWriter:= 0;
+end;
+
+function netReader(data: pointer): LongInt; cdecl; export;
+var c: char;
+ ipaddr: TIPAddress;
+begin
+ netReader:= 0;
+
+ if SDLNet_ResolveHost(ipaddr, PChar('netserver.hedgewars.org'), 46631) = 0 then
+ sock:= SDLNet_TCP_Open(ipaddr);
+
+ SDL_CreateThread(@netWriter{$IFDEF SDL2}, 'netWriter'{$ENDIF}, sock);
+
+ repeat
+ c:= getNextChar;
+ //writeln('>>>>> ', c, ' [', letters[state.l], '] ', commands[state.l]);
+ if c = #0 then
+ state.netState:= netDisconnected
+ else
+ begin
+ while (letters[state.l] <> c) and (commands[state.l] > 0) do
+ inc(state.l, commands[state.l]);
+
+ if c = letters[state.l] then
+ if commands[state.l] < 0 then
+ begin
+ state.cmd:= TCmdType(-10 - commands[state.l]);
+ writeln('[NET] ', state.cmd);
+ handlers[-10 - commands[state.l]]();
+ handleTail()
+ end
+ else
+ inc(state.l)
+ else
+ begin
+ handler___UNKNOWN__();
+ handleTail()
+ end
+ end
+ until state.netState = netDisconnected;
+
+ sock:= nil;
+
+ writeln('[NET] netReader: disconnected');
+end;
+
+procedure sendNet(s: shortstring);
+begin
+ writeln('[NET] Send: ', s);
+ ipcToNet(s + endCmd);
+end;
+
+procedure netSendCallback(p: pointer; msg: PChar; len: Longword);
+begin
+ // W A R N I N G: totally thread-unsafe due to use of sock variable
+ SDLNet_TCP_Send(sock, msg, len);
+end;
+
+procedure connectOfficialServer;
+begin
+ if sock <> nil then
+ exit;
+
+ state.bufpos:= 0;
+ state.buf:= '';
+
+ state.l:= 0;
+ state.netState:= netConnecting;
+
+ netReaderThread:= SDL_CreateThread(@netReader{$IFDEF SDL2}, 'netReader'{$ENDIF}, nil);
+end;
+
+procedure initModule;
+begin
+ sock:= nil;
+
+ SDLNet_Init;
+
+ registerNetCallback(nil, @netSendCallback);
+end;
+
+procedure freeModule;
+begin
+end;
+
+end.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hedgewars/uFLNetProtocol.pas Thu Sep 03 20:59:48 2015 +0300
@@ -0,0 +1,14 @@
+unit uFLNetProtocol;
+interface
+
+procedure passNetData(p: pointer); cdecl;
+
+implementation
+uses uFLNetTypes;
+
+procedure passNetData(p: pointer); cdecl;
+begin
+
+end;
+
+end.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hedgewars/uFLNetTypes.pas Thu Sep 03 20:59:48 2015 +0300
@@ -0,0 +1,16 @@
+unit uFLNetTypes;
+interface
+
+type TCmdType = (cmd___UNKNOWN__, cmd_WARNING, cmd_TEAM_COLOR, cmd_TEAM_ACCEPTED, cmd_SERVER_VARS, cmd_SERVER_MESSAGE, cmd_SERVER_AUTH, cmd_RUN_GAME, cmd_ROUND_FINISHED, cmd_ROOMS, cmd_PROTO, cmd_PING, cmd_NOTICE, cmd_NICK, cmd_LOBBY_LEFT, cmd_LOBBY_JOINED, cmd_LEFT, cmd_KICKED, cmd_JOINING, cmd_JOINED, cmd_INFO, cmd_HH_NUM, cmd_EM, cmd_CONNECTED, cmd_CLIENT_FLAGS, cmd_CHAT, cmd_BYE, cmd_BANLIST, cmd_ASKPASSWORD);
+ TCmdConnectedData = record
+ cmd: TCmdType;
+ protocolNumber: Longword
+ end;
+ TCmdData = record
+ case byte of
+ 0: (cmdConnected: TCmdConnectedData)
+ end;
+
+implementation
+
+end.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hedgewars/uFLSchemes.pas Thu Sep 03 20:59:48 2015 +0300
@@ -0,0 +1,202 @@
+unit uFLSchemes;
+interface
+uses uFLTypes;
+
+function getSchemesList: PPChar; cdecl;
+procedure freeSchemesList;
+
+function schemeByName(s: shortstring): PScheme;
+procedure sendSchemeConfig(var scheme: TScheme);
+
+implementation
+uses uFLUtils, uFLIPC, uPhysFSLayer, uFLData;
+
+const MAX_SCHEME_NAMES = 64;
+type
+ TSchemeArray = array [0..0] of TScheme;
+ PSchemeArray = ^TSchemeArray;
+var
+ schemesList: PScheme;
+ schemesNumber: LongInt;
+ listOfSchemeNames: array[0..MAX_SCHEME_NAMES] of PChar;
+ tmpScheme: TScheme;
+
+const ints: array[0 .. 16] of record
+ name: shortstring;
+ param: ^LongInt;
+ end = (
+ (name: 'damagefactor'; param: @tmpScheme.damagefactor)
+ , (name: 'turntime'; param: @tmpScheme.turntime)
+ , (name: 'health'; param: @tmpScheme.health)
+ , (name: 'suddendeath'; param: @tmpScheme.suddendeath)
+ , (name: 'caseprobability'; param: @tmpScheme.caseprobability)
+ , (name: 'minestime'; param: @tmpScheme.minestime)
+ , (name: 'landadds'; param: @tmpScheme.landadds)
+ , (name: 'minedudpct'; param: @tmpScheme.minedudpct)
+ , (name: 'explosives'; param: @tmpScheme.explosives)
+ , (name: 'minesnum'; param: @tmpScheme.minesnum)
+ , (name: 'healthprobability'; param: @tmpScheme.healthprobability)
+ , (name: 'healthcaseamount'; param: @tmpScheme.healthcaseamount)
+ , (name: 'waterrise'; param: @tmpScheme.waterrise)
+ , (name: 'healthdecrease'; param: @tmpScheme.healthdecrease)
+ , (name: 'ropepct'; param: @tmpScheme.ropepct)
+ , (name: 'getawaytime'; param: @tmpScheme.getawaytime)
+ , (name: 'worldedge'; param: @tmpScheme.worldedge)
+ );
+const bools: array[0 .. 19] of record
+ name: shortstring;
+ param: ^boolean;
+ end = (
+ (name: 'fortsmode'; param: @tmpScheme.fortsmode)
+ , (name: 'divteams'; param: @tmpScheme.divteams)
+ , (name: 'solidland'; param: @tmpScheme.solidland)
+ , (name: 'border'; param: @tmpScheme.border)
+ , (name: 'lowgrav'; param: @tmpScheme.lowgrav)
+ , (name: 'laser'; param: @tmpScheme.laser)
+ , (name: 'invulnerability'; param: @tmpScheme.invulnerability)
+ , (name: 'mines'; param: @tmpScheme.mines)
+ , (name: 'vampiric'; param: @tmpScheme.vampiric)
+ , (name: 'karma'; param: @tmpScheme.karma)
+ , (name: 'artillery'; param: @tmpScheme.artillery)
+ , (name: 'randomorder'; param: @tmpScheme.randomorder)
+ , (name: 'king'; param: @tmpScheme.king)
+ , (name: 'placehog'; param: @tmpScheme.placehog)
+ , (name: 'sharedammo'; param: @tmpScheme.sharedammo)
+ , (name: 'disablegirders'; param: @tmpScheme.disablegirders)
+ , (name: 'disablewind'; param: @tmpScheme.disablewind)
+ , (name: 'morewind'; param: @tmpScheme.morewind)
+ , (name: 'tagteam'; param: @tmpScheme.tagteam)
+ , (name: 'bottomborder'; param: @tmpScheme.bottomborder)
+ );
+
+
+procedure loadSchemes;
+var f: PFSFile;
+ scheme: PScheme;
+ schemes: PSchemeArray;
+ s: shortstring;
+ l, i, ii: Longword;
+ isFound: boolean;
+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));
+ delete(s, 1, i);
+
+ if (l <= schemesNumber) and (l > 0) then
+ begin
+ if copy(s, 1, 5) = 'name=' then
+ schemes^[l - 1].schemeName:= midStr(s, 6)
+ else if copy(s, 1, 12) = 'scriptparam=' then
+ schemes^[l - 1].scriptparam:= midStr(s, 13) else
+ begin
+ ii:= 0;
+ repeat
+ isFound:= readInt(ints[ii].name, s, PLongInt(ints[ii].param - @tmpScheme + @schemes^[l - 1])^);
+ inc(ii)
+ until isFound or (ii > High(ints));
+
+ if not isFound then
+ begin
+ ii:= 0;
+ repeat
+ isFound:= readBool(bools[ii].name, s, PBoolean(bools[ii].param - @tmpScheme + @schemes^[l - 1])^);
+ inc(ii)
+ until isFound or (ii > High(bools));
+ end;
+ end;
+ end;
+ end;
+ end;
+
+ pfsClose(f)
+ end;
+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;
+
+function schemeByName(s: shortstring): PScheme;
+var i: Longword;
+ scheme: PScheme;
+begin
+ scheme:= schemesList;
+ i:= 0;
+ while (i < schemesNumber) and (scheme^.schemeName <> s) do
+ begin
+ inc(scheme);
+ inc(i)
+ end;
+
+ if i < schemesNumber then schemeByName:= scheme else schemeByName:= nil
+end;
+
+procedure freeSchemesList;
+begin
+ if schemesList <> nil then
+ FreeMem(schemesList, sizeof(schemesList^) * (schemesNumber + 1))
+end;
+
+
+procedure sendSchemeConfig(var scheme: TScheme);
+var i: Longword;
+begin
+ with scheme do
+ begin
+ if scheme.turntime <> 45 then
+ ipcToEngine('e$turntime ' + inttostr(scheme.turntime * 1000));
+ if scheme.minesnum <> 4 then
+ ipcToEngine('e$minesnum ' + inttostr(scheme.minesnum));
+ end
+end;
+
+end.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hedgewars/uFLScripts.pas Thu Sep 03 20:59:48 2015 +0300
@@ -0,0 +1,128 @@
+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^);
+ 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 Thu Sep 03 20:59:48 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 Thu Sep 03 20:59:48 2015 +0300
@@ -0,0 +1,86 @@
+unit uFLTypes;
+interface
+
+type
+ TMessageType = (mtPreview, mtAddPlayingTeam, mtRemovePlayingTeam, mtAddTeam, mtRemoveTeam
+ , mtTeamColor, mtNetData);
+
+ TIPCMessage = record
+ str: shortstring;
+ len: Longword;
+ buf: Pointer
+ end;
+
+ TIPCCallback = procedure (p: pointer; msg: PChar; len: Longword);
+ TUICallback = 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;
+
+ TScheme = record
+ schemeName
+ , scriptparam : shortstring;
+ fortsmode
+ , divteams
+ , solidland
+ , border
+ , lowgrav
+ , laser
+ , invulnerability
+ , mines
+ , vampiric
+ , karma
+ , artillery
+ , randomorder
+ , king
+ , placehog
+ , sharedammo
+ , disablegirders
+ , disablewind
+ , morewind
+ , tagteam
+ , bottomborder: boolean;
+ damagefactor
+ , turntime
+ , health
+ , suddendeath
+ , caseprobability
+ , minestime
+ , landadds
+ , minedudpct
+ , explosives
+ , minesnum
+ , healthprobability
+ , healthcaseamount
+ , waterrise
+ , healthdecrease
+ , ropepct
+ , getawaytime
+ , worldedge: LongInt
+ end;
+ PScheme = ^TScheme;
+ TAmmo = record
+ ammoName: shortstring;
+ a, b, c, d: shortstring;
+ end;
+ PAmmo = ^TAmmo;
+
+implementation
+
+end.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hedgewars/uFLUICallback.pas Thu Sep 03 20:59:48 2015 +0300
@@ -0,0 +1,32 @@
+unit uFLUICallback;
+interface
+uses uFLTypes;
+
+procedure registerUIMessagesCallback(p: pointer; f: TUICallback); cdecl;
+procedure sendUI(msgType: TMessageType; msg: PChar; len: Longword);
+
+implementation
+uses uFLIPC;
+
+var uiCallbackPointer: pointer;
+ uiCallbackFunction: TUICallback;
+
+procedure engineMessageCallback(p: pointer; msg: PChar; len: Longword);
+begin
+ if len = 128 * 256 then uiCallbackFunction(uiCallbackPointer, mtPreview, msg, len)
+end;
+
+procedure registerUIMessagesCallback(p: pointer; f: TUICallback); cdecl;
+begin
+ uiCallbackPointer:= p;
+ uiCallbackFunction:= f;
+
+ registerIPCCallback(nil, @engineMessageCallback)
+end;
+
+procedure sendUI(msgType: TMessageType; msg: PChar; len: Longword);
+begin
+ uiCallbackFunction(uiCallbackPointer, msgType, msg, len)
+end;
+
+end.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hedgewars/uFLUtils.pas Thu Sep 03 20:59:48 2015 +0300
@@ -0,0 +1,80 @@
+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);
+function readInt(name, input: shortstring; var value: LongInt): boolean;
+function readBool(name, input: shortstring; var value: boolean): boolean;
+
+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;
+
+function readInt(name, input: shortstring; var value: LongInt): boolean;
+var l: LongInt;
+begin
+ name:= name + '=';
+ l:= length(name);
+
+ if copy(input, 1, l) = name then
+ begin
+ value:= strToInt(midStr(input, l + 1));
+ readInt:= true
+ end
+ else
+ readInt:= false
+end;
+
+function readBool(name, input: shortstring; var value: boolean): boolean;
+var l: LongInt;
+begin
+ name:= name + '=';
+ l:= length(name);
+
+ if copy(input, 1, l) = name then
+ begin
+ value:= (length(input) > l) and (input[l + 1] <> 'f');
+ readBool:= true
+ end
+ else
+ readBool:= false
+end;
+
+end.
--- a/hedgewars/uIO.pas Thu Sep 03 11:51:08 2015 -0400
+++ b/hedgewars/uIO.pas Thu Sep 03 20:59:48 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
@@ -177,31 +157,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);
@@ -261,18 +219,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;
@@ -281,37 +232,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;
@@ -445,13 +381,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);
@@ -503,12 +439,9 @@
begin
RegisterVariable('fatal', @chFatalError, true );
- IPCSock:= nil;
-
headcmd:= nil;
lastcmd:= nil;
isPonged:= false;
- SocketString:= '';
hiTicks:= 0;
flushDelayTicks:= 0;
@@ -518,10 +451,6 @@
procedure freeModule;
begin
while headcmd <> nil do RemoveCmd;
- SDLNet_FreeSocketSet(fds);
- SDLNet_TCP_Close(IPCSock);
- SDLNet_Quit();
-
end;
end.
--- a/hedgewars/uInputHandler.pas Thu Sep 03 11:51:08 2015 -0400
+++ b/hedgewars/uInputHandler.pas Thu Sep 03 20:59:48 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 Thu Sep 03 11:51:08 2015 -0400
+++ b/hedgewars/uMisc.pas Thu Sep 03 20:59:48 2015 +0300
@@ -284,11 +284,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 Thu Sep 03 11:51:08 2015 -0400
+++ b/hedgewars/uPhysFSLayer.pas Thu Sep 03 20:59:48 2015 +0300
@@ -13,7 +13,7 @@
{$linklib physlayer}
{$ENDIF}
-procedure initModule;
+procedure initModule(localPrefix, userPrefix: PChar);
procedure freeModule;
type PFSFile = pointer;
@@ -23,11 +23,14 @@
function pfsOpenRead(fname: shortstring): PFSFile;
function pfsClose(f: PFSFile): boolean;
+function pfsSeek(f: PFSFile; pos: QWord): boolean;
procedure pfsReadLn(f: PFSFile; var s: shortstring);
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;
@@ -48,9 +51,12 @@
function PHYSFS_openRead(fname: PChar): PFSFile; cdecl; external PhysfsLibName;
function PHYSFS_eof(f: PFSFile): LongBool; cdecl; external PhysfsLibName;
function PHYSFS_readBytes(f: PFSFile; buffer: pointer; len: Int64): Int64; cdecl; external PhysfsLibName;
+function PHYSFS_seek(f: PFSFile; pos: QWord): LongBool; cdecl; external PhysfsLibName;
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
@@ -83,11 +89,25 @@
exit(PHYSFS_close(f))
end;
+function pfsSeek(f: PFSFile; pos: QWord): boolean;
+begin
+ exit(PHYSFS_seek(f, 0));
+end;
+
function pfsExists(fname: shortstring): boolean;
begin
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 +158,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 +168,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 +187,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 Thu Sep 03 11:51:08 2015 -0400
+++ b/hedgewars/uRender.pas Thu Sep 03 20:59:48 2015 +0300
@@ -104,8 +104,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 Thu Sep 03 11:51:08 2015 -0400
+++ b/hedgewars/uTypes.pas Thu Sep 03 20:59:48 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 Thu Sep 03 11:51:08 2015 -0400
+++ b/hedgewars/uUtils.pas Thu Sep 03 20:59:48 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 Thu Sep 03 11:51:08 2015 -0400
+++ b/hedgewars/uVariables.pas Thu Sep 03 20:59:48 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;
@@ -261,11 +258,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
@@ -282,7 +279,8 @@
'/Missions/Maps', // ptMissionMaps
'/Graphics/SuddenDeath', // ptSuddenDeath
'/Graphics/Buttons', // ptButton
- '/Shaders' // ptShaders
+ '/Shaders', // ptShaders
+ '/Config' // ptConfig
);
var
@@ -2465,13 +2463,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/misc/OfficialChallenges/racer_#17.hwmap Thu Sep 03 20:59:48 2015 +0300
@@ -0,0 +1,1 @@
+AAAA4Xic43vHWMfAc4SFi4FrB5DFrsEiy8DCyriegTGGRYeBIYldlIGfkX02A/di9qIO7sWsrxhARMf/K0AWLy9bUwffXiDBEst2qPP/b3bRzQwO7FIXGO3YpUAGmC0GGrVlMbsui9JiEPcSkLgDMn7LJRZWpkwGoIT6JSDxn4HvCWPvZq7NjHWbQc64wX2FSYmB7yVj8w0+VqZ0Bp6TLAybgY5kvcFzhOk0AwMDu+gmkNMuMFYC3ceSw3bhApM7u0AXgwgjbyvDJwZ9Bj5p9tBW/nvsoQwAuyw7Aw==
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qmlFrontend/CMakeLists.txt Thu Sep 03 20:59:48 2015 +0300
@@ -0,0 +1,26 @@
+cmake_minimum_required(VERSION 2.8.11)
+
+project(hedgewars)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+set(CMAKE_AUTOMOC ON)
+
+find_package(OpenGL)
+
+find_package(Qt5 COMPONENTS Core Qml Quick Gui)
+
+qt5_add_resources(qresources qmlFrontend.qrc)
+
+add_executable(hedgewars WIN32
+ main
+ hwengine
+ previewimageprovider
+ themeiconprovider
+ qtquick2applicationviewer/qtquick2applicationviewer
+ flib.h
+ ${qresources}
+ )
+
+include_directories(${OPENGL_INCLUDE_DIR})
+
+target_link_libraries(hedgewars Qt5::Core Qt5::Gui Qt5::Quick Qt5::Qml)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qmlFrontend/flib.h Thu Sep 03 20:59:48 2015 +0300
@@ -0,0 +1,66 @@
+#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
+ , MSG_NETDATA
+};
+
+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 registerUIMessagesCallback_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 setScheme_t(const char * schemeName);
+typedef void setAmmo_t(const char * ammoName);
+typedef void flibInit_t(const char * localPrefix, const char * userPrefix);
+typedef void flibFree_t();
+typedef void passNetData_t(const char * data);
+
+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 **getAmmosList_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);
+
+typedef void connectOfficialServer_t();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // FLIB_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qmlFrontend/hwengine.cpp Thu Sep 03 20:59:48 2015 +0300
@@ -0,0 +1,272 @@
+#include <QLibrary>
+#include <QtQml>
+#include <QDebug>
+#include <QPainter>
+#include <QUuid>
+
+#include "hwengine.h"
+#include "previewimageprovider.h"
+#include "themeiconprovider.h"
+
+extern "C" {
+ RunEngine_t *flibRunEngine;
+ registerUIMessagesCallback_t *flibRegisterUIMessagesCallback;
+ setSeed_t *flibSetSeed;
+ getSeed_t *flibGetSeed;
+ setTheme_t *flibSetTheme;
+ setScript_t *flibSetScript;
+ setScheme_t *flibSetScheme;
+ setAmmo_t *flibSetAmmo;
+ 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;
+ getAmmosList_t *flibGetAmmosList;
+ getTeamsList_t *flibGetTeamsList;
+ tryAddTeam_t * flibTryAddTeam;
+ tryRemoveTeam_t * flibTryRemoveTeam;
+ changeTeamColor_t * flibChangeTeamColor;
+
+ connectOfficialServer_t * flibConnectOfficialServer;
+ passNetData_t * flibPassNetData;
+}
+
+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");
+ flibRegisterUIMessagesCallback = (registerUIMessagesCallback_t*) hwlib.resolve("registerUIMessagesCallback");
+ 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");
+ flibSetScheme = (setScheme_t*) hwlib.resolve("setScheme");
+ flibSetAmmo = (setAmmo_t*) hwlib.resolve("setAmmo");
+
+ 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");
+ flibGetAmmosList = (getAmmosList_t*) hwlib.resolve("getAmmosList");
+
+ 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");
+
+ flibConnectOfficialServer = (connectOfficialServer_t*) hwlib.resolve("connectOfficialServer");
+ flibPassNetData = (passNetData_t*) hwlib.resolve("passNetData");
+
+ flibInit("/usr/home/unC0Rr/Sources/Hedgewars/Hedgewars-GC/share/hedgewars/Data", "/usr/home/unC0Rr/.hedgewars");
+ flibRegisterUIMessagesCallback(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;
+ }
+ case MSG_NETDATA: {
+ flibPassNetData(msg.constData());
+ }
+ }
+}
+
+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));
+
+ // ammos model
+ resultModel.clear();
+ for (char **i = flibGetAmmosList(); *i != NULL; i++)
+ resultModel << QString::fromUtf8(*i);
+
+ m_engine->rootContext()->setContextProperty("ammosModel", 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::connect(const QString &host, quint16 port)
+{
+ flibConnectOfficialServer();
+}
+
+void HWEngine::setTheme(const QString &theme)
+{
+ flibSetTheme(theme.toUtf8().constData());
+}
+
+void HWEngine::setScript(const QString &script)
+{
+ flibSetScript(script.toUtf8().constData());
+}
+
+void HWEngine::setScheme(const QString &scheme)
+{
+ flibSetScheme(scheme.toUtf8().constData());
+}
+
+void HWEngine::setAmmo(const QString &ammo)
+{
+ flibSetAmmo(ammo.toUtf8().constData());
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qmlFrontend/hwengine.h Thu Sep 03 20:59:48 2015 +0300
@@ -0,0 +1,62 @@
+#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 setScheme(const QString & scheme);
+ Q_INVOKABLE void setAmmo(const QString & ammo);
+
+ Q_INVOKABLE void tryAddTeam(const QString & teamName);
+ Q_INVOKABLE void tryRemoveTeam(const QString & teamName);
+ Q_INVOKABLE void changeTeamColor(const QString & teamName, int dir);
+
+ Q_INVOKABLE void connect(const QString & host, quint16 port);
+
+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 Thu Sep 03 20:59:48 2015 +0300
@@ -0,0 +1,27 @@
+#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();
+
+ Q_INIT_RESOURCE(qmlFrontend);
+
+ QtQuick2ApplicationViewer viewer;
+
+ viewer.engine()->addImageProvider(QLatin1String("preview"), new PreviewImageProvider());
+ viewer.engine()->addImageProvider(QLatin1String("theme"), new ThemeIconProvider());
+
+ viewer.setSource(QUrl("qrc:/qml/qmlFrontend/main.qml"));
+ viewer.showExpanded();
+
+ return app.exec();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qmlFrontend/previewimageprovider.cpp Thu Sep 03 20:59:48 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 Thu Sep 03 20:59:48 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/Connect.qml Thu Sep 03 20:59:48 2015 +0300
@@ -0,0 +1,14 @@
+import QtQuick 2.0
+import Hedgewars.Engine 1.0
+
+Rectangle {
+ HWButton {
+ id: btnNetConnect
+ x: 80
+ y: 80
+ width: 256
+ height: 128
+
+ onClicked: HWEngine.connect("netserver.hedgewars.org", 46631);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qmlFrontend/qml/qmlFrontend/First.qml Thu Sep 03 20:59:48 2015 +0300
@@ -0,0 +1,31 @@
+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
+
+ onClicked: pages.currentPage = "Connect"
+ }
+
+ 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 Thu Sep 03 20:59:48 2015 +0300
@@ -0,0 +1,298 @@
+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)
+ }
+ }
+ }
+ }
+
+
+ HWComboBox {
+ id: cbAmmo
+ x: 50
+ y: 416
+ width: 256
+ height: 64
+
+ model: ammosModel
+ delegate: Rectangle {
+ height: 25
+ width: 100
+ color: "transparent"
+
+ property string itemIconSource: ""
+ property alias itemText: ammoName.text
+
+ Row {
+ //Image {id: themeIcon; width: height; height: parent.height; source: "image://theme/" + modelData}
+ Text {id: ammoName; text: modelData }
+ }
+
+ MouseArea {
+ z: 1
+ anchors.fill: parent
+ onClicked: {
+ cbAmmo.currentIndex = index
+ HWEngine.setAmmo(ammoName.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 Thu Sep 03 20:59:48 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 Thu Sep 03 20:59:48 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 Thu Sep 03 20:59:48 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 Thu Sep 03 20:59:48 2015 +0300
@@ -0,0 +1,36 @@
+import QtQuick 2.0
+
+Rectangle {
+ id: pages
+ width: 800
+ height: 600
+
+ property variant pagesList : [
+ "First"
+ , "LocalGame"
+ , "GameConfig"
+ , "Connect"
+ ];
+
+ 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.qrc Thu Sep 03 20:59:48 2015 +0300
@@ -0,0 +1,11 @@
+<RCC>
+ <qresource prefix="/">
+ <file>qml/qmlFrontend/First.qml</file>
+ <file>qml/qmlFrontend/GameConfig.qml</file>
+ <file>qml/qmlFrontend/HWButton.qml</file>
+ <file>qml/qmlFrontend/HWComboBox.qml</file>
+ <file>qml/qmlFrontend/LocalGame.qml</file>
+ <file>qml/qmlFrontend/main.qml</file>
+ <file>qml/qmlFrontend/Connect.qml</file>
+ </qresource>
+</RCC>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qmlFrontend/qtquick2applicationviewer/qtquick2applicationviewer.cpp Thu Sep 03 20:59:48 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 Thu Sep 03 20:59:48 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 Thu Sep 03 20:59:48 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 Thu Sep 03 20:59:48 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 Thu Sep 03 20:59:48 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
--- a/share/hedgewars/Data/Scripts/OfficialChallenges.lua Thu Sep 03 11:51:08 2015 -0400
+++ b/share/hedgewars/Data/Scripts/OfficialChallenges.lua Thu Sep 03 20:59:48 2015 +0300
@@ -36,6 +36,8 @@
return("Racer Challenge #6")
elseif LandDigest == "M256715557Scripts/Multiplayer/Racer.lua" then
return("Racer Challenge #15")
+ elseif LandDigest == "M-1389184823Scripts/Multiplayer/Racer.lua" then
+ return("Racer Challenge #17")
end
end
end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/protocolParser.hs Thu Sep 03 20:59:48 2015 +0300
@@ -0,0 +1,167 @@
+module Main where
+
+import Text.PrettyPrint.HughesPJ
+import qualified Data.MultiMap as MM
+import Data.Maybe
+import Data.List
+import Data.Char
+import qualified Data.Set as Set
+
+data HWProtocol = Command String [CmdParam]
+
+instance Ord HWProtocol where
+ (Command a _) `compare` (Command b _) = a `compare` b
+instance Eq HWProtocol where
+ (Command a _) == (Command b _) = a == b
+
+data CmdParam = Skip
+ | SS
+ | LS
+ | IntP
+ | Many [CmdParam]
+data ClientStates = NotConnected
+ | JustConnected
+ | ServerAuth
+ | Lobby
+
+data ParseTree = PTPrefix String [ParseTree]
+ | PTCommand String HWProtocol
+
+cmd = Command
+cmd1 s p = Command s [p]
+cmd2 s p1 p2 = Command s [p1, p2]
+
+cmdParams2str (Command _ p) = "TCmdParam" ++ concatMap f p
+ where
+ f Skip = ""
+ f SS = "S"
+ f LS = "L"
+ f IntP = "i"
+ f (Many p) = ""
+
+cmdParams2handlerType (Command _ p) = "handler_" ++ concatMap f p
+ where
+ f Skip = "_"
+ f SS = "S"
+ f LS = "L"
+ f IntP = "i"
+ f (Many p) = 'M' : concatMap f p
+
+cmdParams2record cmd@(Command _ p) = renderStyle style{lineLength = 80} $
+ text "type " <> text (cmdParams2str cmd)
+ <> text " = record" $+$ nest 4 (
+ vcat (map (uncurry f) $ zip [1..] $ filter isRendered p)
+ $+$ text "end;")
+ where
+ isRendered Skip = False
+ isRendered (Many _) = False
+ isRendered _ = True
+ f n Skip = empty
+ f n SS = text "str" <> int n <> text ": shortstring;"
+ f n LS = text "str" <> int n <> text ": longstring;"
+ f n IntP = text "param" <> int n <> text ": LongInt;"
+ f _ (Many _) = empty
+
+commandsDescription = [
+ cmd "CONNECTED" [Skip, IntP]
+ , cmd1 "NICK" SS
+ , cmd1 "PROTO" IntP
+ , cmd1 "ASKPASSWORD" SS
+ , cmd1 "SERVER_AUTH" SS
+ , cmd1 "JOINING" SS
+ , cmd1 "TEAM_ACCEPTED" SS
+ , cmd1 "HH_NUM" $ Many [SS]
+ , cmd1 "TEAM_COLOR" $ Many [SS]
+ , cmd1 "TEAM_ACCEPTED" SS
+ , cmd1 "BANLIST" $ Many [SS]
+ , cmd1 "JOINED" $ Many [SS]
+ , cmd1 "LOBBY:JOINED" $ Many [SS]
+ , cmd2 "LOBBY:LEFT" SS LS
+ , cmd2 "CLIENT_FLAGS" SS $ Many [SS]
+ , cmd2 "LEFT" SS $ Many [SS]
+ , cmd1 "SERVER_MESSAGE" LS
+ , cmd1 "ERROR" LS
+ , cmd1 "NOTICE" LS
+ , cmd1 "WARNING" LS
+ , cmd1 "EM" $ Many [LS]
+ , cmd1 "PING" $ Many [SS]
+ , cmd2 "CHAT" SS LS
+ , cmd2 "SERVER_VARS" SS LS
+ , cmd2 "BYE" SS LS
+ , cmd1 "INFO" $ Many [SS]
+ , cmd1 "ROOMS" $ Many [SS]
+ , cmd "KICKED" []
+ , cmd "RUN_GAME" []
+ , cmd "ROUND_FINISHED" []
+ ]
+
+unknowncmd = PTPrefix "$" [PTCommand "$" $ Command "__UNKNOWN__" [Many [SS]]]
+
+groupByFirstChar :: [ParseTree] -> [(Char, [ParseTree])]
+groupByFirstChar = MM.assocs . MM.fromList . map breakCmd
+ where
+ breakCmd (PTCommand (c:cs) params) = (c, PTCommand cs params)
+
+makePT cmd@(Command n p) = PTCommand n cmd
+
+buildParseTree cmds = [PTPrefix "!" $ (bpt $ map makePT cmds) ++ [unknowncmd]]
+bpt cmds = if not . null $ fst emptyNamed then cmdLeaf emptyNamed else subtree
+ where
+ emptyNamed = partition (\(_, (PTCommand n _:_)) -> null n) assocs
+ assocs = groupByFirstChar cmds
+ subtree = map buildsub assocs
+ buildsub (c, cmds) = let st = bpt cmds in if null $ drop 1 st then maybeMerge c st else PTPrefix [c] st
+ maybeMerge c cmd@[PTCommand {}] = PTPrefix [c] cmd
+ maybeMerge c cmd@[PTPrefix s ss] = PTPrefix (c:s) ss
+ cmdLeaf ([(c, (hwc:_))], assocs2) = (PTPrefix [c] [hwc]) : map buildsub assocs2
+
+dumpTree = vcat . map dt
+ where
+ dt (PTPrefix s st) = text s $$ (nest 1 $ vcat $ map dt st)
+ dt _ = empty
+
+pas2 = buildSwitch $ buildParseTree commandsDescription
+ where
+ buildSwitch cmds = text "case getNextChar of" $$ (nest 4 . vcat $ map buildCase cmds) $$ elsePart
+ buildCase (PTCommand {}) = text "#10: <call cmd handler>;"
+ buildCase (PTPrefix (s:ss) cmds) = quotes (char s) <> text ": " <> consumePrefix ss (buildSwitch cmds)
+ consumePrefix "" = id
+ consumePrefix str = (text "consume" <> (parens . quotes $ text str) <> semi $$)
+ zeroChar = text "#0: state:= pstDisconnected;"
+ elsePart = text "else <unknown cmd> end;"
+
+renderArrays (letters, commands, handlers) = vcat $ punctuate (char '\n') [cmds, l, s, bodies, c, structs]
+ where
+ maybeQuotes "$" = text "#0"
+ maybeQuotes s = if null $ tail s then quotes $ text s else text s
+ l = text "const letters: array[0.." <> (int $ length letters - 1) <> text "] of char = "
+ <> parens (hsep . punctuate comma $ map maybeQuotes letters) <> semi
+ s = text "const commands: array[0.." <> (int $ length commands - 1) <> text "] of integer = "
+ <> parens (hsep . punctuate comma $ map text commands) <> semi
+ c = text "const handlers: array[0.." <> (int $ length fixedNames - 1) <> text "] of PHandler = "
+ <> parens (hsep . punctuate comma $ map (text . (:) '@') handlerTypes) <> semi
+ handlerTypes = map cmdParams2handlerType . reverse $ sort commandsDescription
+ fixedNames = map fixName handlers
+ fixName = map fixChar
+ fixChar c | isLetter c = c
+ | otherwise = '_'
+ bodies = vcat $ punctuate (char '\n') $ map handlerBody fixedNames
+ handlerBody n = text "procedure handler_" <> text n <> semi
+ $+$ text "begin"
+ $+$ text "end" <> semi
+ cmds = text "type TCmdType = " <> parens (hsep $ punctuate comma $ map ((<>) (text "cmd_") . text) $ reverse fixedNames) <> semi
+ structs = vcat (map text . Set.toList . Set.fromList $ map cmdParams2record commandsDescription)
+
+pas = renderArrays $ buildTables $ buildParseTree commandsDescription
+ where
+ buildTables cmds = let (_, _, _, t1, t2, t3) = foldr walk (0, [0], -10, [], [], [[]]) cmds in (tail t1, tail t2, concat t3)
+ walk (PTCommand _ (Command n params)) (lc, s:sh, pc, tbl1, tbl2, (t3:tbl3)) =
+ (lc, 1:sh, pc - 1, "#10":tbl1, show pc:tbl2, (n:t3):tbl3)
+ walk (PTPrefix prefix cmds) l = lvldown $ foldr fpf (foldr walk (lvlup l) cmds) prefix
+ lvlup (lc, sh, pc, tbl1, tbl2, tbl3) = (lc, 0:sh, pc, tbl1, tbl2, []:tbl3)
+ lvldown (lc, s1:s2:sh, pc, tbl1, t:tbl2, t31:t32:tbl3) = (lc, s1+s2:sh, pc, tbl1, (if null t32 then "0" else show s1):tbl2, (t31 ++ t32):tbl3)
+ fpf c (lc, s:sh, pc, tbl1, tbl2, tbl3) = (lc + 1, s+1:sh, pc, [c]:tbl1, "0":tbl2, tbl3)
+
+main =
+ putStrLn $ renderStyle style{lineLength = 80} $ pas
+ --putStrLn $ renderStyle style{lineLength = 80} $ dumpTree $ buildParseTree commandsDescription