update branch with default webgl
authorkoda
Tue, 25 Dec 2012 04:45:22 +0100
branchwebgl
changeset 8330 aaefa587e277
parent 8116 d24257910f8d (current diff)
parent 8328 03684c667664 (diff)
child 8332 9333216f2054
update branch with default
.hgignore
CMakeLists.txt
QTfrontend/CMakeLists.txt
QTfrontend/game.cpp
QTfrontend/gameuiconfig.cpp
QTfrontend/gameuiconfig.h
QTfrontend/hwform.cpp
QTfrontend/hwform.h
QTfrontend/net/newnetclient.cpp
QTfrontend/net/newnetclient.h
QTfrontend/net/recorder.cpp
QTfrontend/ui/dialog/bandialog.h
QTfrontend/ui/dialog/input_password.cpp
QTfrontend/ui/page/pagefeedback.cpp
QTfrontend/ui/page/pagefeedback.h
QTfrontend/ui/page/pagemain.cpp
QTfrontend/ui/page/pagenettype.cpp
QTfrontend/ui/page/pagenettype.h
QTfrontend/ui/page/pagevideos.cpp
QTfrontend/ui/widget/about.cpp
QTfrontend/util/FileEngine.cpp
README_WINDOWS
bin/CMakeLists.txt
gameServer/Actions.hs
gameServer/CMakeLists.txt
gameServer/HWProtoInRoomState.hs
hedgewars/ArgParsers.inc
hedgewars/CMakeLists.txt
hedgewars/GSHandlers.inc
hedgewars/VGSHandlers.inc
hedgewars/hwengine.pas
hedgewars/options.inc
hedgewars/uAIAmmoTests.pas
hedgewars/uChat.pas
hedgewars/uCommandHandlers.pas
hedgewars/uConsts.pas
hedgewars/uCursor.pas
hedgewars/uGame.pas
hedgewars/uGears.pas
hedgewars/uGearsHedgehog.pas
hedgewars/uGearsList.pas
hedgewars/uGearsRender.pas
hedgewars/uGearsUtils.pas
hedgewars/uIO.pas
hedgewars/uInputHandler.pas
hedgewars/uLand.pas
hedgewars/uLandObjects.pas
hedgewars/uLandOutline.pas
hedgewars/uLocale.pas
hedgewars/uMobile.pas
hedgewars/uPhysFSLayer.pas
hedgewars/uRender.pas
hedgewars/uScript.pas
hedgewars/uSound.pas
hedgewars/uStore.pas
hedgewars/uTeams.pas
hedgewars/uTouch.pas
hedgewars/uTypes.pas
hedgewars/uUtils.pas
hedgewars/uVariables.pas
hedgewars/uVisualGears.pas
hedgewars/uWorld.pas
misc/liblua/CMakeLists.txt
misc/libopenalbridge/CMakeLists.txt
misc/physfs/CMakeLists.txt
project_files/Android-build/CMakeLists.txt
project_files/frontlib/hwconsts.h
project_files/frontlib/md5/md5.h
project_files/frontlib/model/gamesetup.h
project_files/frontlib/model/map.h
project_files/frontlib/model/mapcfg.h
project_files/frontlib/model/room.h
project_files/frontlib/model/team.h
project_files/frontlib/net/netconn.h
project_files/frontlib/net/netconn_internal.h
share/CMakeLists.txt
share/hedgewars/Data/Graphics/AmmoMenu/Ammos@2x.png
share/hedgewars/Data/Graphics/AmmoMenu/Ammos_bw@2x.png
share/hedgewars/Data/Graphics/AmmoMenu/BorderHorizontal.png
share/hedgewars/Data/Graphics/AmmoMenu/BorderVertical.png
share/hedgewars/Data/Graphics/AmmoMenu/CMakeLists.txt
share/hedgewars/Data/Locale/en.txt
tools/pas2c/PascalPreprocessor.hs
--- a/.hgignore	Sun Dec 02 00:03:16 2012 +0100
+++ b/.hgignore	Tue Dec 25 04:45:22 2012 +0100
@@ -30,6 +30,7 @@
 glob:misc/liblua/Xcode/build/
 glob:misc/libfreetype/Xcode/build/
 glob:misc/libfreetype/Xcode-iOS/build/
+glob:misc/physfs/Xcode/build/
 glob:moc_*.cxx_parameters
 relre:^release\/
 glob:*.log
@@ -57,4 +58,5 @@
 glob:hedgewars-build-desktop-Qt_4_7_4_for_Desktop_-_MinGW_4_4__Qt_SDK__Release
 glob:*.depends
 glob:tools/build_windows_koda.bat
+glob:share/hedgewars/Data/misc/hwengine.desktop
 
--- a/CMakeLists.txt	Sun Dec 02 00:03:16 2012 +0100
+++ b/CMakeLists.txt	Tue Dec 25 04:45:22 2012 +0100
@@ -1,19 +1,20 @@
 project(hedgewars)
 
 #initialise cmake environment
-cmake_minimum_required(VERSION 2.6.0 FATAL_ERROR)
-cmake_policy(VERSION 2.6)
-FOREACH(hwpolicy CMP0003 CMP0012 CMP0017)
-    IF(POLICY ${hwpolicy})
-        CMAKE_POLICY(SET ${hwpolicy} NEW)
-    ENDIF()
-ENDFOREACH()
+cmake_minimum_required(VERSION 2.6.0)
+foreach(hwpolicy CMP0003 CMP0012 CMP0017)
+    if(POLICY ${hwpolicy})
+        cmake_policy(SET ${hwpolicy} NEW)
+    endif()
+endforeach()
 #use available modules, fallback to ours if not present (CMP0017 helps)
 set(CMAKE_MODULE_PATH "${CMAKE_ROOT}/Modules" "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules")
 
-#set some default values
-option(NOREVISION "Build Hedgewars without revision information" OFF)
 
+#usually this is set at release time
+option(NOREVISION "Build Hedgewars without revision information [default: off]" OFF)
+
+#set other default values
 option(NOSERVER "Disable gameServer build [default: auto]" OFF)
 option(NOPNG "Disable screenshoot compression [default: auto]" OFF)
 option(NOVIDEOREC "Disable video recording [default: auto]" OFF)
@@ -25,39 +26,40 @@
 
 option(ANDROID "Enable Android build [default: off]" OFF)
 option(NOAUTOUPDATE "Disable OS X Sparkle update checking" OFF)
-option(CROSSAPPLE "Enable OSX when not on OSX [default: off]" OFF)
 option(MINIMAL_FLAGS "Respect system flags as much as possible [default: off]" OFF)
+set(FPFLAGS "" CACHE STRING "Additional Freepascal flags" FORCE)
+set(GHFLAGS "" CACHE STRING "Additional Haskell flags" FORCE)
 
 
 #detect Mercurial revision (if present)
-IF(NOT NOREVISION)
+if(NOT NOREVISION)
     set(default_build_type "DEBUG")
     set(version_suffix "-development_version")
     set(HW_DEV true)
-    FIND_PROGRAM(HGCOMMAND hg)
-    IF(HGCOMMAND AND (EXISTS ${CMAKE_SOURCE_DIR}/.hg))
+    find_program(HGCOMMAND hg)
+    if(HGCOMMAND AND (EXISTS ${CMAKE_SOURCE_DIR}/.hg))
         execute_process(COMMAND ${HGCOMMAND} identify -in
                         WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
                         OUTPUT_VARIABLE internal_version
                         ERROR_QUIET
                     )
         #check local repo status
-        STRING(REGEX REPLACE "[^+]" "" HGCHANGED ${internal_version})
+        string(REGEX REPLACE "[^+]" "" HGCHANGED ${internal_version})
 
-        STRING(REGEX REPLACE "[0-9a-zA-Z]+(.*) ([0-9]+)(.*)" "\\2" revision_number ${internal_version})
-        STRING(REGEX REPLACE "([0-9a-zA-Z]+)(.*) [0-9]+(.*)" "\\1" revision_hash ${internal_version})
+        string(REGEX REPLACE "[0-9a-zA-Z]+(.*) ([0-9]+)(.*)" "\\2" revision_number ${internal_version})
+        string(REGEX REPLACE "([0-9a-zA-Z]+)(.*) [0-9]+(.*)" "\\1" revision_hash ${internal_version})
 
-        MESSAGE(STATUS "Building revision ${revision_number} from hash ${revision_hash} ${HGCHANGED}")
-        IF(HGCHANGED)
+        message(STATUS "Building revision ${revision_number} from hash ${revision_hash} ${HGCHANGED}")
+        if(HGCHANGED)
             MESSAGE(WARNING "Notice: you have uncommitted changes in your repository")
-        ENDIF()
+        endif()
         set(version_suffix "-${revision_number}${HGCHANGED}")
-    ENDIF()
-ELSE(NOT NOREVISION)
+    endif()
+else(NOT NOREVISION)
     set(default_build_type "RELEASE")
     set(HWDEV false)
-    MESSAGE(STATUS "Building distributable version")
-ENDIF(NOT NOREVISION)
+    message(STATUS "Building distributable version")
+endif(NOT NOREVISION)
 
 
 #versioning
@@ -79,19 +81,35 @@
 endif()
 
 
-#bundle .app setup
-if(APPLE OR CROSSAPPLE)
-    #paths for creating the bundle
-    set(bundle_name Hedgewars.app)
-    set(frameworks_dir ${bundle_name}/Contents/Frameworks/)
-    set(CMAKE_INSTALL_PREFIX ${bundle_name}/Contents/MacOS/)
-    set(DATA_INSTALL_DIR "../Resources/")
-    set(target_dir ".")
-    set(minimum_macosx_version "10.6")
+set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
+set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
+
+if(UNIX AND NOT APPLE)
+    set(target_binary_install_dir "bin")
+    set(target_library_install_dir "lib")
+    if(DEFINED DATA_INSTALL_DIR)
+        set(SHAREPATH "${DATA_INSTALL_DIR}")
+    else()
+        set(SHAREPATH "share/hedgewars/")
+    endif()
 else()
-    set(target_dir "bin")
+    set(target_binary_install_dir "./")
+
+    if(APPLE)
+        set(CMAKE_INSTALL_PREFIX "Hedgewars.app/Contents/MacOS/")
+        set(SHAREPATH "../Resources/")
+        set(target_library_install_dir "../Frameworks/")
+    else()
+        if(WIN32)
+            set(target_library_install_dir "./")
+            set(SHAREPATH "./")
+            set(CMAKE_PREFIX_PATH "${CMAKE_SOURCE_DIR}/misc/winutils/")
+            link_directories("${EXECUTABLE_OUTPUT_PATH}" "${CMAKE_SOURCE_DIR}/misc/winutils/bin")
+        endif(WIN32)
+    endif()
 endif()
 
+
 if(APPLE)
     set(CMAKE_FIND_FRAMEWORK "FIRST")
 
@@ -120,12 +138,12 @@
     endif()
 
     #lower systems don't have enough processing power anyway
-    if (minimum_macosx_version LESS "10.4")
+    if (minimum_macosx_version VERSION_LESS "10.4")
         message(FATAL_ERROR "Hedgewars is not supported on Mac OS X pre-10.4")
     endif()
 
     #workaround for http://playcontrol.net/ewing/jibberjabber/big_behind-the-scenes_chang.html#SDL_mixer (Update 2)
-    if(current_macosx_version MATCHES "10.4")
+    if(current_macosx_version VERSION_EQUAL "10.4")
         find_package(SDL_mixer REQUIRED)
         set(DYLIB_SMPEG "-dylib_file @loader_path/Frameworks/smpeg.framework/Versions/A/smpeg:${SDLMIXER_LIBRARY}/Versions/A/Frameworks/smpeg.framework/Versions/A/smpeg")
         set(DYLIB_MIKMOD "-dylib_file @loader_path/Frameworks/mikmod.framework/Versions/A/mikmod:${SDLMIXER_LIBRARY}/Versions/A/Frameworks/mikmod.framework/Versions/A/mikmod")
@@ -135,7 +153,7 @@
 
     #CMAKE_OSX_ARCHITECTURES and CMAKE_OSX_SYSROOT need to be set for universal binary and correct linking
     if(NOT CMAKE_OSX_ARCHITECTURES)
-        if(current_macosx_version LESS "10.6")
+        if(current_macosx_version VERSION_LESS "10.6")
             if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "powerpc*")
                 set(CMAKE_OSX_ARCHITECTURES "ppc7400")
             else()
@@ -148,8 +166,8 @@
 
     #CMAKE_OSX_SYSROOT is set at the system version we are supposed to build on
     #we need to provide the correct one when host and target differ
-    if(NOT ${minimum_macosx_version} MATCHES ${current_macosx_version})
-        if(minimum_macosx_version MATCHES "10.4")
+    if(NOT ${minimum_macosx_version} VERSION_EQUAL ${current_macosx_version})
+        if(minimum_macosx_version VERSION_EQUAL "10.4")
             set(CMAKE_OSX_SYSROOT "/Developer/SDKs/MacOSX10.4u.sdk/")
             set(CMAKE_C_COMPILER "gcc-4.0")
             set(CMAKE_CXX_COMPILER "g++-4.0")
@@ -164,8 +182,10 @@
     #set deployment target
     set(pascal_flags "-k-macosx_version_min" "-k${minimum_macosx_version}" "-XR${CMAKE_OSX_SYSROOT}" ${pascal_flags})
 
-    message(STATUS "Build system: Mac OS X ${current_macosx_version} with C compiler: ${CMAKE_C_COMPILER}")
-    message(STATUS "Target system: Mac OS X ${minimum_macosx_version} for architecture(s): ${CMAKE_OSX_ARCHITECTURES}")
+    #silly libav that always brings in VideoDecoderAcceleration, avaible only from 10.6.3
+    if(NOT NOVIDEOREC AND ${minimum_macosx_version} VERSION_LESS "10.6")
+        set(WARNING "Video recording support before OS X 10.6 is experimental")
+    endif()
 endif(APPLE)
 
 
@@ -173,7 +193,7 @@
 if (CMAKE_BUILD_TYPE)
     string (TOUPPER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE)
     if ( NOT( (CMAKE_BUILD_TYPE MATCHES "RELEASE") OR (CMAKE_BUILD_TYPE MATCHES "DEBUG") ) )
-        set (CMAKE_BUILD_TYPE ${default_build_type} CACHE STRING "Only 'Debug' or 'Release' options are allowed." FORCE)
+        set (CMAKE_BUILD_TYPE ${default_build_type} CACHE STRING "Choose the build type, options are: Debug Release." FORCE)
         message (STATUS "Unknown build type, using default (${default_build_type})")
     endif ()
 else (CMAKE_BUILD_TYPE)
@@ -198,45 +218,39 @@
 
 #parse additional parameters
 if(FPFLAGS OR GHFLAGS)
-    math(EXPR cmake_version "${CMAKE_MAJOR_VERSION}*10000 + ${CMAKE_MINOR_VERSION}*100 + ${CMAKE_PATCH_VERSION}")
-    if(cmake_version LESS "020800")
-        message(STATUS "FPFLAGS and GHFLAGS are available only when using CMake >= 2.8")
+    set(cmake_version "${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION}")
+    if(cmake_version VERSION_LESS "2.8")
+        message(WARNING "FPFLAGS and GHFLAGS are available only when using CMake >= 2.8")
     else()
         separate_arguments(fpflags_parsed UNIX_COMMAND ${FPFLAGS})
         separate_arguments(ghflags_parsed UNIX_COMMAND ${GHFLAGS})
     endif()
 endif()
 
-set(pascal_flags ${fpflags_parsed} "-vm4079,4080,4081" "-B" "-FE../bin" "-Cs2000000" "-vewnq" "-dDEBUGFILE" ${pascal_flags})
+set(pascal_flags ${fpflags_parsed}              # user flags
+                 "-vm4079,4080,4081"            # fpc output format
+                 "-B"                           # compile all units
+                 "-FE${PROJECT_BINARY_DIR}/bin" # fpc output directory
+                 "-Fl${PROJECT_BINARY_DIR}/bin" # fpc linking directory
+                 "-Cs2000000"                   # stack size
+                 "-vewnq"                       # fpc output verbosity
+                 "-dDEBUGFILE"                  # macro for engine output
+                 ${pascal_flags}                # adding to list
+                 )
 set(haskell_flags "-O2" ${ghflags_parsed} ${haskell_flags})
 
 #get BUILD_TYPE and enable/disable optimisation
+message(STATUS "Using ${CMAKE_BUILD_TYPE} configuration")
 if(CMAKE_BUILD_TYPE MATCHES "DEBUG")
-    message(STATUS "Building Debug flavour")
     set(pascal_flags "-O-" "-g" "-gl" "-gv" ${pascal_flags})
     set(haskell_flags "-Wall" "-debug" "-dcore-lint" "-fno-warn-unused-do-bind" ${haskell_flags})
 else()
-    message(STATUS "Building Release flavour")
 #    set(pascal_flags "-O3" "-OpPENTIUM4" "-CfSSE3" "-Xs" "-Si" ${pascal_flags})
-    set(pascal_flags "-Os" "-Ooregvar" "-Xs" "-Si" ${pascal_flags})
+    set(pascal_flags "-Os" "-Xs" "-Si" ${pascal_flags})
     set(haskell_flags "-w" "-fno-warn-unused-do-bind" ${haskell_flags})
 endif()
 
 
-#finish setting paths
-if(DEFINED DATA_INSTALL_DIR)
-    set(SHAREPATH ${DATA_INSTALL_DIR}/hedgewars/)
-else()
-    set(SHAREPATH share/hedgewars/)
-endif()
-set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
-set(LIBRARY_OUTPUT_PATH ${EXECUTABLE_OUTPUT_PATH})
-if(WIN32)
-    set(CMAKE_PREFIX_PATH "${CMAKE_SOURCE_DIR}/misc/winutils/")
-    link_directories("${EXECUTABLE_OUTPUT_PATH}" "${CMAKE_SOURCE_DIR}/misc/winutils/bin")
-endif(WIN32)
-
-
 #Haskell compiler discovery (for server and engine in c)
 if((NOT NOSERVER) OR NOPASCAL)
     if(GHC)
@@ -277,8 +291,12 @@
 endif()
 
 
-#physfs library
+#physfs library (static on unix, dll on win32)
 add_subdirectory(misc/physfs)
+if(NOT WIN32)
+    set(pascal_flags "-k${LIBRARY_OUTPUT_PATH}/libphysfs.a" ${pascal_flags})
+endif()
+
 
 #frontend library
 add_subdirectory(project_files/frontlib)
@@ -331,6 +349,7 @@
     set(CPACK_NSIS_URL_INFO_ABOUT "http://www.hedgewars.org/")
     set(CPACK_NSIS_CONTACT "unC0Rr@gmail.com")
     set(CPACK_NSIS_MODIFY_PATH OFF)
+    set(CPACK_NSIS_EXECUTABLES_DIRECTORY "${target_binary_install_dir}")
     set(CPACK_GENERATOR "ZIP;NSIS")
     set(CPACK_PACKAGE_INSTALL_REGISTRY_KEY "hedgewars")
 else(WIN32 AND NOT UNIX)
--- a/INSTALL	Sun Dec 02 00:03:16 2012 +0100
+++ b/INSTALL	Tue Dec 25 04:45:22 2012 +0100
@@ -1,13 +1,14 @@
 To compile and install you need:
- - Qt >= 4.5
- - FreePascal >= 2.2.4
+ - CMake >= 2.6.0
+ - FreePascal >= 2.2.0
+ - Qt >= 4.5.0
  - SDL >= 1.2.5
  - SDL_net >= 1.2.5
  - SDL_mixer >= 1.2
  - SDL_image >= 1.2
  - SDL_ttf >= 2.0
- - CMake >= 2.6.0
  - Lua >= 5.1.0
+ - Physfs >= 2.1
 For server:
  - Glasgow Haskell Compiler >= 6.10
  - bytestring-show package
@@ -16,6 +17,11 @@
 For videorecording:
  - FFmpeg or LibAV
  - GLUT (when SDL < 2)
+For compressed screenshots:
+ - libpng
+
+Lua will be automatically built if not found.
+
 
 1. Configure:
 $ cmake .
@@ -23,8 +29,12 @@
 $ cmake -DCMAKE_BUILD_TYPE="Release" -DCMAKE_INSTALL_PREFIX="install_prefix" \
 -DDATA_INSTALL_DIR="data_dir" -DNOSERVER=1 .
 
-add -DNOSERVER=0 to compile net server; if you have Qt installed but it is
-not found you can set it up with -DQT_QMAKE_EXECUTABLE="path_to_qmake"
+Add -DNOSERVER=0 to compile net server (remember to check out the additional
+dependencies with the hedgewars-server.cabal configuration file. If you have
+Qt installed but it is not found, you can set it up with
+-DQT_QMAKE_EXECUTABLE="path_to_qmake".
+To get a glimpse of the main configuration options, you may use this command
+`cat CMakeLists.txt | grep option`
 
 2. Compile:
 $ make
@@ -34,3 +44,4 @@
 
 
 That's all! Enjoy!
+
--- a/QTfrontend/AutoUpdater.h	Sun Dec 02 00:03:16 2012 +0100
+++ b/QTfrontend/AutoUpdater.h	Tue Dec 25 04:45:22 2012 +0100
@@ -11,6 +11,7 @@
         virtual ~AutoUpdater();
 
         virtual void checkForUpdates() = 0;
+        virtual void checkForUpdatesNow() = 0;
 };
 
 #endif
--- a/QTfrontend/CMakeLists.txt	Sun Dec 02 00:03:16 2012 +0100
+++ b/QTfrontend/CMakeLists.txt	Tue Dec 25 04:45:22 2012 +0100
@@ -11,15 +11,16 @@
 set(QT_USE_QTMAIN TRUE)
 
 find_package(Qt4 REQUIRED)
-if (NOT CROSSAPPLE)
-    include(${QT_USE_FILE})
-endif()
+include(${QT_USE_FILE})
 
 find_package(SDL REQUIRED)       #video in SDLInteraction
 find_package(SDL_mixer REQUIRED) #audio in SDLInteraction
 find_package(SDL_net REQUIRED)   #network frontlib
 if(NOT NOVIDEOREC)
     find_package(FFMPEG)
+    if(${FFMPEG_FOUND})
+        add_definitions(-DVIDEOREC -D__STDC_CONSTANT_MACROS)
+    endif()
 endif()
 
 include_directories(.)
@@ -35,30 +36,24 @@
 include_directories(${FFMPEG_INCLUDE_DIR})
 include_directories(${CMAKE_SOURCE_DIR}/misc/physfs/src)
 include_directories(${CMAKE_SOURCE_DIR}/misc/physfs/extras)
-include_directories(${CMAKE_SOURCE_DIR}/project_files/frontlib)
 if(UNIX)
     # HACK: in freebsd cannot find iconv.h included via SDL.h
     include_directories("/usr/local/include")
 endif(UNIX)
 
-
-if(WIN32 AND NOT UNIX)
-    set(HEDGEWARS_BINDIR ".")
-    set(HEDGEWARS_DATADIR "../share/")
-    add_definitions(-DUSE_XFIRE)
+#directory for resources, relative to the one above on certain platforms/configurations
+if(DEFINED DATA_INSTALL_DIR OR WIN32 OR APPLE)
+    set(HEDGEWARS_DATADIR ${SHAREPATH})
 else()
-    set(HEDGEWARS_BINDIR ${CMAKE_INSTALL_PREFIX})
-    if(DEFINED DATA_INSTALL_DIR)
-        set(HEDGEWARS_DATADIR ${DATA_INSTALL_DIR})
-    else()
-        set(HEDGEWARS_DATADIR ${CMAKE_INSTALL_PREFIX}/share/)
-    endif()
-    #only the cocoa version of qt supports building 64 bit apps
-    if(APPLE AND (CMAKE_OSX_ARCHITECTURES MATCHES "x86_64*") AND (NOT QT_MAC_USE_COCOA))
-        message(FATAL_ERROR "Building the 64 bit version of Hedgewars *requires* the Cocoa variant of QT on Mac OS X")
-    endif()
+    set(HEDGEWARS_DATADIR ${CMAKE_INSTALL_PREFIX}/${SHAREPATH}/)
 endif()
 
+#only the cocoa version of qt supports building 64 bit apps
+if(APPLE AND (CMAKE_OSX_ARCHITECTURES MATCHES "x86_64*") AND (NOT QT_MAC_USE_COCOA))
+    message(FATAL_ERROR "Building the 64 bit version of Hedgewars *requires* the Cocoa variant of QT on Mac OS X")
+endif()
+#endif()
+
 configure_file(${CMAKE_CURRENT_SOURCE_DIR}/hwconsts.cpp.in ${CMAKE_CURRENT_BINARY_DIR}/hwconsts.cpp)
 
 file(GLOB NetCpp net/*.cpp)
@@ -66,10 +61,6 @@
 file(GLOB_RECURSE UIcpp ui/*.cpp)
 file(GLOB UtilCpp util/*.cpp)
 
-if(${FFMPEG_FOUND})
-    add_definitions(-DVIDEOREC -D__STDC_CONSTANT_MACROS)
-endif()
-
 set(hwfr_src
     ${ModelCpp}
     ${NetCpp}
@@ -97,9 +88,9 @@
 if(MINGW)
     # resource compilation for mingw
     add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/hedgewars_rc.o
-    COMMAND windres -I ${CMAKE_CURRENT_SOURCE_DIR}
-    -i ${CMAKE_CURRENT_SOURCE_DIR}/hedgewars.rc
-    -o ${CMAKE_CURRENT_BINARY_DIR}/hedgewars_rc.o)
+                       COMMAND windres -I ${CMAKE_CURRENT_SOURCE_DIR}
+                               -i ${CMAKE_CURRENT_SOURCE_DIR}/hedgewars.rc
+                               -o ${CMAKE_CURRENT_BINARY_DIR}/hedgewars_rc.o)
     set(hwfr_src ${hwfr_src} ${CMAKE_CURRENT_BINARY_DIR}/hedgewars_rc.o)
 else(MINGW)
     set(hwfr_src ${hwfr_src} hedgewars.rc)
@@ -138,15 +129,26 @@
 
 set(hwfr_rez hedgewars.qrc)
 
+if(${BUILD_ENGINE_LIBRARY})
+    add_definitions(-DHWLIBRARY=1)
+    set(hwlibname "${EXECUTABLE_OUTPUT_PATH}/${CMAKE_SHARED_LIBRARY_PREFIX}hwengine${CMAKE_SHARED_LIBRARY_SUFFIX}")
+    set(HW_LINK_LIBS ${hwlibname} ${HW_LINK_LIBS})
+endif()
+
 qt4_add_resources(hwfr_rez_src ${hwfr_rez})
 
 qt4_wrap_cpp(hwfr_moc_srcs ${hwfr_moc_hdrs})
 
 
-if(APPLE OR CROSSAPPLE)
-    set(hwfr_src ${hwfr_src} InstallController.cpp CocoaInitializer.mm M3Panel.mm M3InstallController.m NSWorkspace_RBAdditions.m)
-    set(HW_LINK_LIBS IOKit ${HW_LINK_LIBS})
-
+if(APPLE)
+    find_library(iokit_framework NAMES IOKit)
+    set(HW_LINK_LIBS ${iokit_framework} ${HW_LINK_LIBS})
+    set(hwfr_src ${hwfr_src} CocoaInitializer.mm
+                             InstallController.cpp
+                             M3Panel.mm
+                             M3InstallController.m
+                             NSWorkspace_RBAdditions.m
+                             )
     if(NOT NOAUTOUPDATE)
         find_package(Sparkle)
         if(SPARKLE_FOUND)
@@ -157,28 +159,33 @@
     endif()
 endif()
 
-if(LIBENGINE)
+#when debugging, always prompt a console to see fronted messages
+#TODO: check it doesn't interfere on UNIX
+if(CMAKE_BUILD_TYPE MATCHES "RELEASE")
+    set(console_access "WIN32")
+endif(CMAKE_BUILD_TYPE MATCHES "RELEASE")
+if(${LIBENGINE})
     add_definitions(-DHWLIBRARY)
     set(HW_LINK_LIBS hwengine ${HW_LINK_LIBS})
     link_directories(${EXECUTABLE_OUTPUT_PATH})
 endif()
 
-
-add_executable(hedgewars WIN32
+add_executable(hedgewars ${console_access}
     ${hwfr_src}
     ${hwfr_moc_srcs}
     ${hwfr_hdrs}
     ${hwfr_rez_src}
     )
 
+if((UNIX AND NOT APPLE) AND ${LIBENGINE})
+    set_target_properties(hedgewars PROPERTIES LINK_FLAGS "-Wl,-rpath,${CMAKE_INSTALL_PREFIX}/${target_library_install_dir}")
+endif()
 
 set(HW_LINK_LIBS
     physfs
-    frontlib
     ${QT_LIBRARIES}
     ${SDL_LIBRARY}
     ${SDLMIXER_LIBRARY}
-    ${SDLNET_LIBRARY}
     ${FFMPEG_LIBRARIES}
     ${HW_LINK_LIBS}
     )
@@ -197,13 +204,8 @@
         )
 endif()
 
-
-if (CROSSAPPLE)
-
-else()
-    target_link_libraries(hedgewars ${HW_LINK_LIBS})
-endif()
+target_link_libraries(hedgewars ${HW_LINK_LIBS})
 
 
-install(PROGRAMS "${EXECUTABLE_OUTPUT_PATH}/hedgewars${CMAKE_EXECUTABLE_SUFFIX}" DESTINATION ${target_dir})
+install(PROGRAMS "${EXECUTABLE_OUTPUT_PATH}/hedgewars${CMAKE_EXECUTABLE_SUFFIX}" DESTINATION ${target_binary_install_dir})
 
--- a/QTfrontend/binds.cpp	Sun Dec 02 00:03:16 2012 +0100
+++ b/QTfrontend/binds.cpp	Tue Dec 25 04:45:22 2012 +0100
@@ -66,5 +66,7 @@
     {"fullscr",   "f12",        QT_TRANSLATE_NOOP("binds", "change mode"),     NULL, QT_TRANSLATE_NOOP("binds (descriptions)", "Toggle fullscreen mode:")},
     {"capture",   "c",          QT_TRANSLATE_NOOP("binds", "capture"),         NULL, QT_TRANSLATE_NOOP("binds (descriptions)", "Take a screenshot:")},
     {"rotmask",   "delete",     QT_TRANSLATE_NOOP("binds", "hedgehogs\ninfo"), NULL, QT_TRANSLATE_NOOP("binds (descriptions)", "Toggle labels above hedgehogs:")},
+#ifdef VIDEOREC
     {"record",    "r",          QT_TRANSLATE_NOOP("binds", "record"),          NULL, QT_TRANSLATE_NOOP("binds (descriptions)", "Record video:")}
+#endif
 };
--- a/QTfrontend/binds.h	Sun Dec 02 00:03:16 2012 +0100
+++ b/QTfrontend/binds.h	Tue Dec 25 04:45:22 2012 +0100
@@ -21,7 +21,11 @@
 
 #include <QString>
 
+#ifdef VIDEOREC
 #define BINDS_NUMBER 46
+#else
+#define BINDS_NUMBER 45
+#endif
 
 struct BindAction
 {
--- a/QTfrontend/game.cpp	Sun Dec 02 00:03:16 2012 +0100
+++ b/QTfrontend/game.cpp	Tue Dec 25 04:45:22 2012 +0100
@@ -56,7 +56,7 @@
     switch (gameType)
     {
         case gtDemo:
-            // for video recording we need demo anyway 
+            // for video recording we need demo anyway
             emit HaveRecord(rtNeither, demo);
             break;
         case gtNet:
@@ -314,23 +314,43 @@
 {
     QStringList arguments;
     QRect resolution = config->vid_Resolution();
-    arguments << cfgdir->absolutePath();
-    arguments << QString::number(resolution.width());
-    arguments << QString::number(resolution.height());
-    arguments << QString::number(config->bitDepth()); // bpp
+    QString nick = config->netNick().toUtf8().toBase64();
+
+    arguments << "--internal"; //Must be passed as first argument
+    arguments << "--port";
     arguments << QString("%1").arg(ipc_port);
-    arguments << (config->vid_Fullscreen() ? "1" : "0");
-    arguments << (config->isSoundEnabled() ? "1" : "0");
-    arguments << (config->isMusicEnabled() ? "1" : "0");
-    arguments << QString::number(config->volume()); // sound volume
-    arguments << QString::number(config->timerInterval());
+    arguments << "--prefix";
     arguments << datadir->absolutePath();
-    arguments << (config->isShowFPSEnabled() ? "1" : "0");
-    arguments << (config->isAltDamageEnabled() ? "1" : "0");
-    arguments << config->netNick().toUtf8().toBase64();
+    arguments << "--user-prefix";
+    arguments << cfgdir->absolutePath();
+    arguments << "--locale";
+    arguments << tr("en.txt");
+    arguments << "--frame-interval";
+    arguments << QString::number(config->timerInterval());
+    arguments << "--volume";
+    arguments << QString::number(config->volume());
+    arguments << "--width";
+    arguments << QString::number(resolution.width());
+    arguments << "--height";
+    arguments << QString::number(resolution.height());
+    arguments << "--raw-quality";
     arguments << QString::number(config->translateQuality());
+    arguments << "--stereo";
     arguments << QString::number(config->stereoMode());
-    arguments << tr("en.txt");
+    if (config->vid_Fullscreen())
+        arguments << "--fullscreen";
+    if (config->isShowFPSEnabled())
+        arguments << "--showfps";
+    if (config->isAltDamageEnabled())
+        arguments << "--altdmg";
+    if (!config->isSoundEnabled())
+        arguments << "--nosound";
+    if (!config->isMusicEnabled())
+        arguments << "--nomusic";
+    if (!nick.isEmpty()) {
+        arguments << "--nick";
+        arguments << nick;
+    }
 
     return arguments;
 }
--- a/QTfrontend/gameuiconfig.cpp	Sun Dec 02 00:03:16 2012 +0100
+++ b/QTfrontend/gameuiconfig.cpp	Tue Dec 25 04:45:22 2012 +0100
@@ -44,17 +44,21 @@
 
 
 GameUIConfig::GameUIConfig(HWForm * FormWidgets, const QString & fileName)
-    : QSettings(fileName, QSettings::IniFormat)
+    : QSettings(fileName, QSettings::IniFormat, FormWidgets)
 {
     Form = FormWidgets;
 
-    connect(Form->ui.pageOptions->CBEnableFrontendMusic, SIGNAL(toggled(bool)), Form, SLOT(Music(bool)));
+    setIniCodec("UTF-8");
+
+    connect(Form->ui.pageOptions->CBFrontendMusic, SIGNAL(toggled(bool)), Form, SLOT(Music(bool)));
 
     //Form->resize(value("frontend/width", 640).toUInt(), value("frontend/height", 450).toUInt());
     resizeToConfigValues();
 
     reloadValues();
+#ifdef VIDEOREC
     reloadVideosValues();
+#endif
 }
 
 void GameUIConfig::reloadValues(void)
@@ -77,11 +81,11 @@
 
     Form->ui.pageOptions->SLQuality->setValue(value("video/quality", 5).toUInt());
     Form->ui.pageOptions->CBStereoMode->setCurrentIndex(value("video/stereo", 0).toUInt());
-    Form->ui.pageOptions->CBEnableFrontendSound->setChecked(value("frontend/effects", true).toBool());
-    Form->ui.pageOptions->CBEnableSound->setChecked(value("audio/sound", true).toBool());
-    Form->ui.pageOptions->CBEnableFrontendSound->setChecked(value("frontend/sound", true).toBool());
-    Form->ui.pageOptions->CBEnableMusic->setChecked(value("audio/music", true).toBool());
-    Form->ui.pageOptions->CBEnableFrontendMusic->setChecked(value("frontend/music", true).toBool());
+    Form->ui.pageOptions->CBFrontendEffects->setChecked(value("frontend/effects", true).toBool());
+    Form->ui.pageOptions->CBSound->setChecked(value("audio/sound", true).toBool());
+    Form->ui.pageOptions->CBFrontendSound->setChecked(value("frontend/sound", true).toBool());
+    Form->ui.pageOptions->CBMusic->setChecked(value("audio/music", true).toBool());
+    Form->ui.pageOptions->CBFrontendMusic->setChecked(value("frontend/music", true).toBool());
     Form->ui.pageOptions->volumeBox->setValue(value("audio/volume", 100).toUInt());
 
     QString netNick = value("net/nick", "").toString();
@@ -92,11 +96,13 @@
     Form->ui.pageOptions->editNetPassword->installEventFilter(this);
 
     int passLength = value("net/passwordlength", 0).toInt();
-    setNetPasswordLength(passLength);
-    if (savePwd == false) {
-        Form->ui.pageOptions->editNetPassword->setEnabled(savePwd);
+    if (!savePwd) {
+        Form->ui.pageOptions->editNetPassword->setEnabled(false);
         Form->ui.pageOptions->editNetPassword->setText("");
-        setNetPasswordLength(0);        
+        setNetPasswordLength(0);
+    } else
+    {
+        setNetPasswordLength(passLength);
     }
 
     delete netHost;
@@ -124,10 +130,6 @@
     Form->ui.pageOptions->leProxyLogin->setText(value("proxy/login", "").toString());
     Form->ui.pageOptions->leProxyPassword->setText(value("proxy/password", "").toString());
 
-    depth = HWApplication::desktop()->depth();
-    if (depth < 16) depth = 16;
-    else if (depth > 16) depth = 32;
-
     { // load colors
         QStandardItemModel * model = DataManager::instance().colorsModel();
         for(int i = model->rowCount() - 1; i >= 0; --i)
@@ -137,26 +139,34 @@
 
 void GameUIConfig::reloadVideosValues(void)
 {
-    Form->ui.pageVideos->framerateBox->setValue(value("videorec/fps",25).toUInt());
-    Form->ui.pageVideos->bitrateBox->setValue(value("videorec/bitrate",400).toUInt());
-    bool useGameRes = value("videorec/usegameres",true).toBool();
+    // one pass with default values
+    Form->ui.pageOptions->setDefaultOptions();
+
+    // then load user configuration
+    Form->ui.pageOptions->framerateBox->setCurrentIndex(
+            Form->ui.pageOptions->framerateBox->findData(
+                        value("videorec/framerate", rec_Framerate()).toString() + " fps",
+                    Qt::MatchExactly) );
+    Form->ui.pageOptions->bitrateBox->setValue(value("videorec/bitrate", rec_Bitrate()).toUInt());
+    bool useGameRes = value("videorec/usegameres",Form->ui.pageOptions->checkUseGameRes->isChecked()).toBool();
     if (useGameRes)
     {
         QRect res = vid_Resolution();
-        Form->ui.pageVideos->widthEdit->setText(QString::number(res.width()));
-        Form->ui.pageVideos->heightEdit->setText(QString::number(res.height()));
+        Form->ui.pageOptions->widthEdit->setText(QString::number(res.width()));
+        Form->ui.pageOptions->heightEdit->setText(QString::number(res.height()));
     }
     else
     {
-        Form->ui.pageVideos->widthEdit->setText(value("videorec/width","800").toString());
-        Form->ui.pageVideos->heightEdit->setText(value("videorec/height","600").toString());
+        Form->ui.pageOptions->widthEdit->setText(value("videorec/width","800").toString());
+        Form->ui.pageOptions->heightEdit->setText(value("videorec/height","600").toString());
     }
-    Form->ui.pageVideos->checkUseGameRes->setChecked(useGameRes);
-    Form->ui.pageVideos->checkRecordAudio->setChecked(value("videorec/audio",true).toBool());
-    if (!Form->ui.pageVideos->tryCodecs(value("videorec/format","no").toString(),
+    Form->ui.pageOptions->checkUseGameRes->setChecked(useGameRes);
+    Form->ui.pageOptions->checkRecordAudio->setChecked(
+            value("videorec/audio",Form->ui.pageOptions->checkRecordAudio->isChecked()).toBool() );
+    if (!Form->ui.pageOptions->tryCodecs(value("videorec/format","no").toString(),
                                         value("videorec/videocodec","no").toString(),
                                         value("videorec/audiocodec","no").toString()))
-        Form->ui.pageVideos->setDefaultCodecs();
+        Form->ui.pageOptions->setDefaultCodecs();
 }
 
 QStringList GameUIConfig::GetTeamsList()
@@ -175,7 +185,16 @@
 
 void GameUIConfig::resizeToConfigValues()
 {
-    Form->resize(value("frontend/width", 800).toUInt(), value("frontend/height", 600).toUInt());
+    // fill 2/3 of the screen desktop
+    const QRect deskSize = QApplication::desktop()->screenGeometry(-1);
+    Form->resize(value("frontend/width", qMin(qMax(deskSize.width()*2/3,800),deskSize.width())).toUInt(),
+                 value("frontend/height", qMin(qMax(deskSize.height()*2/3,600),deskSize.height())).toUInt());
+
+    // move the window to the center of the screen
+    QPoint center = QApplication::desktop()->availableGeometry(-1).center();
+    center.setX(center.x() - (Form->width()/2));
+    center.setY(center.y() - (Form->height()/2));
+    Form->move(center);
 }
 
 void GameUIConfig::SaveOptions()
@@ -210,11 +229,13 @@
     setValue("audio/volume", Form->ui.pageOptions->volumeBox->value());
 
     setValue("net/nick", netNick());
-    if (netPasswordIsValid() && Form->ui.pageOptions->CBSavePassword->isChecked())
-    {
-        setValue("net/passwordhash", netPasswordHash());
-        setValue("net/passwordlength", netPasswordLength());
+    if (netPasswordIsValid() && Form->ui.pageOptions->CBSavePassword->isChecked()) {
+    setPasswordHash(netPasswordHash());
     }
+    else if(!Form->ui.pageOptions->CBSavePassword->isChecked()) {
+        clearPasswordHash();
+    }
+
     setValue("net/savepassword", Form->ui.pageOptions->CBSavePassword->isChecked());
     setValue("net/ip", *netHost);
     setValue("net/port", netPort);
@@ -268,7 +289,7 @@
             setValue(QString("colors/color%1").arg(i), model->item(i)->data());
     }
 
-    Form->gameSettings->sync();
+    sync();
 }
 
 void GameUIConfig::SaveVideosOptions()
@@ -277,14 +298,20 @@
     setValue("videorec/format", AVFormat());
     setValue("videorec/videocodec", videoCodec());
     setValue("videorec/audiocodec", audioCodec());
-    setValue("videorec/fps", rec_Framerate());
+    setValue("videorec/framerate", rec_Framerate());
     setValue("videorec/bitrate", rec_Bitrate());
     setValue("videorec/width", res.width());
     setValue("videorec/height", res.height());
-    setValue("videorec/usegameres", Form->ui.pageVideos->checkUseGameRes->isChecked());
+    setValue("videorec/usegameres", Form->ui.pageOptions->checkUseGameRes->isChecked());
     setValue("videorec/audio", recordAudio());
 
-    Form->gameSettings->sync();
+    sync();
+}
+
+void GameUIConfig::setValue(const QString &key, const QVariant &value)
+{
+    //qDebug() << "[settings]" << key << value;
+    QSettings::setValue(key, value);
 }
 
 QString GameUIConfig::language()
@@ -370,20 +397,20 @@
 
 bool GameUIConfig::isSoundEnabled()
 {
-    return Form->ui.pageOptions->CBEnableSound->isChecked();
+    return Form->ui.pageOptions->CBSound->isChecked();
 }
 bool GameUIConfig::isFrontendSoundEnabled()
 {
-    return Form->ui.pageOptions->CBEnableFrontendSound->isChecked();
+    return Form->ui.pageOptions->CBFrontendSound->isChecked();
 }
 
 bool GameUIConfig::isMusicEnabled()
 {
-    return Form->ui.pageOptions->CBEnableMusic->isChecked();
+    return Form->ui.pageOptions->CBMusic->isChecked();
 }
 bool GameUIConfig::isFrontendMusicEnabled()
 {
-    return Form->ui.pageOptions->CBEnableFrontendMusic->isChecked();
+    return Form->ui.pageOptions->CBFrontendMusic->isChecked();
 }
 
 bool GameUIConfig::isShowFPSEnabled()
@@ -418,11 +445,6 @@
     return 35 - Form->ui.pageOptions->fpsedit->value();
 }
 
-quint8 GameUIConfig::bitDepth()
-{
-    return depth;
-}
-
 QString GameUIConfig::netNick()
 {
     return Form->ui.pageOptions->editNetNick->text();
@@ -445,7 +467,41 @@
 
 bool GameUIConfig::netPasswordIsValid()
 {
-    return (netPasswordLength() == 0 || Form->ui.pageOptions->editNetPassword->text() != QString(netPasswordLength(), '\0'));
+    return (netPasswordLength() == 0 || Form->ui.pageOptions->editNetPassword->text() != QString(netPasswordLength(), '*'));
+}
+
+void GameUIConfig::clearPasswordHash()
+{
+    setValue("net/passwordhash", QString());
+    setValue("net/passwordlength", 0);
+    setValue("net/savepassword", false); //changes the savepassword value to false in order to not let the user save an empty password in PAGE_SETUP
+    reloadValues(); //reloads the values of PAGE_SETUP
+}
+
+void GameUIConfig::setPasswordHash(const QString & passwordhash)
+{
+    setValue("net/passwordhash", passwordhash);
+    setValue("net/passwordlength", passwordhash.size()/4);
+    setNetPasswordLength(passwordhash.size()/4);  //the hash.size() is divided by 4 let PAGE_SETUP use a reasonable number of stars to display the PW
+}
+
+QString GameUIConfig::passwordHash()
+{
+    return value("net/passwordhash").toString();
+}
+
+void GameUIConfig::clearTempHash()
+{
+    setTempHash(QString());
+}
+
+void GameUIConfig::setTempHash(const QString & temphash)
+{
+    this->temphash = temphash;
+}
+
+QString GameUIConfig::tempHash() {
+    return this->temphash;
 }
 
 // When hedgewars launches, the password field is set with null characters. If the user tries to edit the field and there are such characters, then clear the field
@@ -470,7 +526,7 @@
 {
     if (passwordLength > 0)
     {
-        Form->ui.pageOptions->editNetPassword->setText(QString(passwordLength, '\0'));
+        Form->ui.pageOptions->editNetPassword->setText(QString(passwordLength, '*'));
     }
     else
     {
@@ -485,40 +541,43 @@
 
 QString GameUIConfig::AVFormat()
 {
-    return Form->ui.pageVideos->format();
+    return Form->ui.pageOptions->format();
 }
 
 QString GameUIConfig::videoCodec()
 {
-    return Form->ui.pageVideos->videoCodec();
+    return Form->ui.pageOptions->videoCodec();
 }
 
 QString GameUIConfig::audioCodec()
 {
-    return Form->ui.pageVideos->audioCodec();
+    return Form->ui.pageOptions->audioCodec();
 }
 
 QRect GameUIConfig::rec_Resolution()
 {
-    if (Form->ui.pageVideos->checkUseGameRes->isChecked())
+    if (Form->ui.pageOptions->checkUseGameRes->isChecked())
         return vid_Resolution();
     QRect res(0,0,0,0);
-    res.setWidth(Form->ui.pageVideos->widthEdit->text().toUInt());
-    res.setHeight(Form->ui.pageVideos->heightEdit->text().toUInt());
+    res.setWidth(Form->ui.pageOptions->widthEdit->text().toUInt());
+    res.setHeight(Form->ui.pageOptions->heightEdit->text().toUInt());
     return res;
 }
 
 int GameUIConfig::rec_Framerate()
 {
-    return Form->ui.pageVideos->framerateBox->value();
+    // remove the "fps" label
+    QString fpsText = Form->ui.pageOptions->framerateBox->currentText();
+    QStringList fpsList = fpsText.split(" ");
+    return fpsList.first().toInt();
 }
 
 int GameUIConfig::rec_Bitrate()
 {
-    return Form->ui.pageVideos->bitrateBox->value();
+    return Form->ui.pageOptions->bitrateBox->value();
 }
 
 bool GameUIConfig::recordAudio()
 {
-    return Form->ui.pageVideos->checkRecordAudio->isChecked();
+    return Form->ui.pageOptions->checkRecordAudio->isChecked();
 }
--- a/QTfrontend/gameuiconfig.h	Sun Dec 02 00:03:16 2012 +0100
+++ b/QTfrontend/gameuiconfig.h	Tue Dec 25 04:45:22 2012 +0100
@@ -48,16 +48,22 @@
         bool appendDateTimeToRecordName();
         quint8 volume();
         quint8 timerInterval();
-        quint8 bitDepth();
         QString netNick();
         QByteArray netPasswordHash();
         int netPasswordLength();
+        void clearPasswordHash();
+        void setPasswordHash(const QString & passwordhash);
+        QString passwordHash();
+        void clearTempHash();
+        void setTempHash(const QString & temphash);
+        QString tempHash();
         void setNetPasswordLength(int passwordLength);
         bool isReducedQuality() const;
         bool isFrontendEffects() const;
         bool isFrontendFullscreen() const;
         void resizeToConfigValues();
         quint32 stereoMode() const;
+        void setValue(const QString & key, const QVariant & value);
 
         QString AVFormat();
         QString videoCodec();
@@ -85,7 +91,7 @@
     private:
         bool netPasswordIsValid();
         bool eventFilter(QObject *object, QEvent *event);
-        quint8 depth;
+    QString temphash;
 };
 
 #endif
--- a/QTfrontend/hedgewars.qrc	Sun Dec 02 00:03:16 2012 +0100
+++ b/QTfrontend/hedgewars.qrc	Tue Dec 25 04:45:22 2012 +0100
@@ -44,6 +44,7 @@
         <file>res/HedgewarsTitle.png</file>
         <file>res/LocalPlay.png</file>
         <file>res/NetworkPlay.png</file>
+        <file>res/NetworkPlayDisabled.png</file>
         <file>res/Settings.png</file>
         <file>res/dropdown.png</file>
         <file>res/new.png</file>
@@ -145,5 +146,6 @@
         <file>res/chat/serveradmin_gray.png</file>
         <file>res/chat/lamp_off.png</file>
         <file>res/chat/ingame.png</file>
+	<file>res/html/about.html</file>
     </qresource>
 </RCC>
--- a/QTfrontend/hwconsts.cpp.in	Sun Dec 02 00:03:16 2012 +0100
+++ b/QTfrontend/hwconsts.cpp.in	Tue Dec 25 04:45:22 2012 +0100
@@ -22,10 +22,9 @@
 
 QString * cProtoVer = new QString("${HEDGEWARS_PROTO_VER}");
 QString * cDataDir = new QString("${HEDGEWARS_DATADIR}");
-QString * cConfigDir = new QString("");
 QString * cVersionString = new QString("${HEDGEWARS_VERSION}");
 
-QDir * bindir = new QDir("${HEDGEWARS_BINDIR}");
+QDir * bindir = new QDir();
 QDir * cfgdir = new QDir();
 QDir * datadir = new QDir();
 
--- a/QTfrontend/hwconsts.h	Sun Dec 02 00:03:16 2012 +0100
+++ b/QTfrontend/hwconsts.h	Tue Dec 25 04:45:22 2012 +0100
@@ -26,7 +26,6 @@
 extern QString * cProtoVer;
 extern QString * cVersionString;
 extern QString * cDataDir;
-extern QString * cConfigDir;
 
 extern QDir * bindir;
 extern QDir * cfgdir;
@@ -63,40 +62,40 @@
 
 #define HEDGEHOGS_PER_TEAM           8
 
-#define AMMOLINE_DEFAULT_QT     "93919294221991210322351110012010000002111101010111110101"
-#define AMMOLINE_DEFAULT_PROB   "04050405416006555465544647765766666661555101011154110101"
-#define AMMOLINE_DEFAULT_DELAY  "00000000000002055000000400070040000000002200000006000000"
-#define AMMOLINE_DEFAULT_CRATE  "13111103121111111231141111111111111112111111011111110101"
+#define AMMOLINE_DEFAULT_QT     "9391929422199121032235111001201000000211110101011111101"
+#define AMMOLINE_DEFAULT_PROB   "0405040541600655546554464776576666666155510101115411101"
+#define AMMOLINE_DEFAULT_DELAY  "0000000000000205500000040007004000000000220000000600000"
+#define AMMOLINE_DEFAULT_CRATE  "1311110312111111123114111111111111111211111101111111101"
 
-#define AMMOLINE_CRAZY_QT       "99999999999999999929999999999999992999999999099999920909"
-#define AMMOLINE_CRAZY_PROB     "11111101111111111111111111111111111111111111011111110101"
-#define AMMOLINE_CRAZY_DELAY    "00000000000000000000000000000000000000000000000000000000"
-#define AMMOLINE_CRAZY_CRATE    "13111103121111111231141111111111111112111101011111110101"
+#define AMMOLINE_CRAZY_QT       "9999999999999999992999999999999999299999999909999992909"
+#define AMMOLINE_CRAZY_PROB     "1111110111111111111111111111111111111111111101111111101"
+#define AMMOLINE_CRAZY_DELAY    "0000000000000000000000000000000000000000000000000000000"
+#define AMMOLINE_CRAZY_CRATE    "1311110312111111123114111111111111111211110101111111101"
 
-#define AMMOLINE_PROMODE_QT     "90900090000000000000090000000000000000000000000000000000"
-#define AMMOLINE_PROMODE_PROB   "00000000000000000000000000000000000000000000000000000000"
-#define AMMOLINE_PROMODE_DELAY  "00000000000002055000000400070040000000002000000000000002"
-#define AMMOLINE_PROMODE_CRATE  "11111111111111111111111111111111111111111001011111110101"
+#define AMMOLINE_PROMODE_QT     "9090009000000000000009000000000000000000000000000000000"
+#define AMMOLINE_PROMODE_PROB   "0000000000000000000000000000000000000000000000000000000"
+#define AMMOLINE_PROMODE_DELAY  "0000000000000205500000040007004000000000200000000000002"
+#define AMMOLINE_PROMODE_CRATE  "1111111111111111111111111111111111111111100101111111101"
 
-#define AMMOLINE_SHOPPA_QT      "00000099000000000000000000000000000000000000000000000000"
-#define AMMOLINE_SHOPPA_PROB    "44444100442444022101121212224220000000020004000100110001"
-#define AMMOLINE_SHOPPA_DELAY   "00000000000000000000000000000000000000000000000000000000"
-#define AMMOLINE_SHOPPA_CRATE   "11111111111111111111111111111111111111111011011111110001"
+#define AMMOLINE_SHOPPA_QT      "0000009900000000000000000000000000000000000000000000000"
+#define AMMOLINE_SHOPPA_PROB    "4444410044244402210112121222422000000002000400010011001"
+#define AMMOLINE_SHOPPA_DELAY   "0000000000000000000000000000000000000000000000000000000"
+#define AMMOLINE_SHOPPA_CRATE   "1111111111111111111111111111111111111111101101111111001"
 
-#define AMMOLINE_CLEAN_QT       "10100090000100000110000000000000000000000000000010000000"
-#define AMMOLINE_CLEAN_PROB     "04050405416006555465544647765766666661555101011154110101"
-#define AMMOLINE_CLEAN_DELAY    "00000000000000000000000000000000000000000000000000000000"
-#define AMMOLINE_CLEAN_CRATE    "13111103121111111231141111111111111112111111011111110101"
+#define AMMOLINE_CLEAN_QT       "1010009000010000011000000000000000000000000000001000000"
+#define AMMOLINE_CLEAN_PROB     "0405040541600655546554464776576666666155510101115411101"
+#define AMMOLINE_CLEAN_DELAY    "0000000000000000000000000000000000000000000000000000000"
+#define AMMOLINE_CLEAN_CRATE    "1311110312111111123114111111111111111211111101111111101"
 
-#define AMMOLINE_MINES_QT       "00000099000900000003000000000000000000000000000000000000"
-#define AMMOLINE_MINES_PROB     "00000000000000000000000000000000000000000000000000000000"
-#define AMMOLINE_MINES_DELAY    "00000000000002055000000400070040000000002000000006000000"
-#define AMMOLINE_MINES_CRATE    "11111111111111111111111111111111111111111111011111110101"
+#define AMMOLINE_MINES_QT       "0000009900090000000300000000000000000000000000000000000"
+#define AMMOLINE_MINES_PROB     "0000000000000000000000000000000000000000000000000000000"
+#define AMMOLINE_MINES_DELAY    "0000000000000205500000040007004000000000200000000600000"
+#define AMMOLINE_MINES_CRATE    "1111111111111111111111111111111111111111111101111111101"
 
-#define AMMOLINE_PORTALS_QT     "90000090020000000021000000000000001100000900000000000000"
-#define AMMOLINE_PORTALS_PROB   "04050405416006555465544647765766666661555101011154110101"
-#define AMMOLINE_PORTALS_DELAY  "00000000000002055000000400070040000000002000000006000000"
-#define AMMOLINE_PORTALS_CRATE  "13111103121111111231141111111111111112111111011111110101"
+#define AMMOLINE_PORTALS_QT     "9000009002000000002100000000000000110000090000000000000"
+#define AMMOLINE_PORTALS_PROB   "0405040541600655546554464776576666666155510101115411101"
+#define AMMOLINE_PORTALS_DELAY  "0000000000000205500000040007004000000000200000000600000"
+#define AMMOLINE_PORTALS_CRATE  "1311110312111111123114111111111111111211111101111111101"
 
 //Different seasons; assigned to season (int)
 #define SEASON_NONE 0
--- a/QTfrontend/hwform.cpp	Sun Dec 02 00:03:16 2012 +0100
+++ b/QTfrontend/hwform.cpp	Tue Dec 25 04:45:22 2012 +0100
@@ -39,6 +39,8 @@
 #include <QSignalMapper>
 #include <QShortcut>
 #include <QDesktopServices>
+#include <QDesktopWidget>
+#include <QApplication>
 #include <QInputDialog>
 #include <QPropertyAnimation>
 #include <QSettings>
@@ -73,7 +75,6 @@
 #include "pagefeedback.h"
 #include "pagenetserver.h"
 #include "pagedrawmap.h"
-#include "pagenettype.h"
 #include "pagegamestats.h"
 #include "pageplayrecord.h"
 #include "pagedata.h"
@@ -96,6 +97,19 @@
 #include "playerslistmodel.h"
 
 #include "DataManager.h"
+#include "AutoUpdater.h"
+
+#ifdef Q_WS_WIN
+#define WINVER 0x0500
+#include <windows.h>
+#else
+#include <unistd.h>
+#include <sys/types.h>
+#endif
+
+#ifdef Q_WS_MAC
+#include <sys/sysctl.h>
+#endif
 
 #ifdef __APPLE__
 #include "M3Panel.h"
@@ -111,7 +125,6 @@
 QString playerHash;
 
 GameUIConfig* HWForm::config = NULL;
-QSettings* HWForm::gameSettings = NULL;
 
 HWForm::HWForm(QWidget *parent, QString styleSheet)
     : QMainWindow(parent)
@@ -127,10 +140,6 @@
 #ifdef USE_XFIRE
     xfire_init();
 #endif
-    gameSettings = new QSettings(cfgdir->absolutePath() + "/hedgewars.ini", QSettings::IniFormat);
-    frontendEffects = gameSettings->value("frontend/effects", true).toBool();
-    playerHash = QString(QCryptographicHash::hash(gameSettings->value("net/nick","").toString().toUtf8(), QCryptographicHash::Md5).toHex());
-
     this->setStyleSheet(styleSheet);
     ui.setupUi(this);
     setMinimumSize(760, 580);
@@ -139,21 +148,38 @@
 
     ui.pageOptions->CBResolution->addItems(SDLInteraction::instance().getResolutions());
 
-    config = new GameUIConfig(this, cfgdir->absolutePath() + "/hedgewars.ini");
+    config = new GameUIConfig(this, "physfs://hedgewars.ini");
+    frontendEffects = config->value("frontend/effects", true).toBool();
+    playerHash = QString(QCryptographicHash::hash(config->value("net/nick","").toString().toUtf8(), QCryptographicHash::Md5).toHex());
+
+    ui.pageRoomsList->setSettings(config);
+    ui.pageNetGame->chatWidget->setSettings(config);
+    ui.pageRoomsList->chatWidget->setSettings(config);
+#ifdef VIDEOREC
+    ui.pageVideos->init(config);
+    ui.pageOptions->setConfig(config);
+#endif
 
-    ui.pageVideos->init(config);
+#ifdef __APPLE__
+    AutoUpdater* updater = NULL;
+    if (config->isAutoUpdateEnabled())
+    {
+#ifdef __APPLE__
+#ifdef SPARKLE_ENABLED
+        updater = new SparkleAutoUpdater();
+#endif
+#endif
+        if (updater)
+        {
+            updater->checkForUpdates();
+            delete updater;
+        }
+    }
+#endif
 
 #ifdef __APPLE__
     panel = new M3Panel;
 
-#ifdef SPARKLE_ENABLED
-    AutoUpdater* updater;
-
-    updater = new SparkleAutoUpdater();
-    if (updater && config->isAutoUpdateEnabled())
-        updater->checkForUpdates();
-#endif
-
     QShortcut *hideFrontend = new QShortcut(QKeySequence("Ctrl+M"), this);
     connect (hideFrontend, SIGNAL(activated()), this, SLOT(showMinimized()));
 #else
@@ -190,9 +216,6 @@
     connect(ui.pageMain->BtnFeedback, SIGNAL(clicked()), pageSwitchMapper, SLOT(map()));
     pageSwitchMapper->setMapping(ui.pageMain->BtnFeedback, ID_PAGE_FEEDBACK);
 
-    connect(ui.pageMain->BtnNet, SIGNAL(clicked()), pageSwitchMapper, SLOT(map()));
-    pageSwitchMapper->setMapping(ui.pageMain->BtnNet, ID_PAGE_NETTYPE);
-
     connect(ui.pageMain->BtnInfo, SIGNAL(clicked()), pageSwitchMapper, SLOT(map()));
     pageSwitchMapper->setMapping(ui.pageMain->BtnInfo, ID_PAGE_INFO);
 
@@ -291,8 +314,8 @@
     //    this, SLOT(GoBack())); // executed third
 
 
-    connect(ui.pageNetType->BtnLAN, SIGNAL(clicked()), this, SLOT(GoToNet()));
-    connect(ui.pageNetType->BtnOfficialServer, SIGNAL(clicked()), this, SLOT(NetConnectOfficialServer()));
+    connect(ui.pageMain->BtnNetLocal, SIGNAL(clicked()), this, SLOT(GoToNet()));
+    connect(ui.pageMain->BtnNetOfficial, SIGNAL(clicked()), this, SLOT(NetConnectOfficialServer()));
 
     connect(ui.pageConnecting, SIGNAL(cancelConnection()), this, SLOT(GoBack()));
 
@@ -439,23 +462,27 @@
     }
 }
 
-void HWForm::UpdateTeamsLists(const QStringList* editable_teams)
+void HWForm::UpdateTeamsLists()
 {
-    QStringList teamslist;
-    if(editable_teams)
-    {
-        teamslist =* editable_teams;
-    }
-    else
-    {
-        teamslist = config->GetTeamsList();
-    }
+    QStringList teamslist = config->GetTeamsList();
 
     if(teamslist.empty())
     {
-        HWTeam defaultTeam(tr("DefaultTeam"));
+        QString currentNickName = config->value("net/nick","").toString().toUtf8();
+        QString teamName;
+
+        if (currentNickName.isEmpty())
+        {
+            teamName = tr("DefaultTeam");
+        }
+        else
+        {
+            teamName = tr("%1's Team").arg(currentNickName);
+        }
+
+        HWTeam defaultTeam(teamName);
         defaultTeam.saveToFile();
-        teamslist.push_back(tr("DefaultTeam"));
+        teamslist.push_back(teamName);
     }
 
     ui.pageOptions->CBTeamName->clear();
@@ -531,6 +558,67 @@
 #ifdef USE_XFIRE
     updateXfire();
 #endif
+
+    QString openPrefix = "Debug:   (PAGE_OPENED: ";
+    QString openSuffix = ")";
+    QString closePrefix = "Debug:   (PAGE_LEFT: ";
+    QString closeSuffix = ")";
+
+    switch (lastid) { //Print the id of the page we're leaving
+      case ID_PAGE_SETUP_TEAM : qDebug("%sPAGE_SETUP_TEAM%s", qPrintable(closePrefix), qPrintable(closeSuffix));    break;
+      case ID_PAGE_SETUP :      qDebug("%sPAGE_SETUP%s", qPrintable(closePrefix), qPrintable(closeSuffix));     break;
+      case ID_PAGE_MULTIPLAYER :    qDebug("%sPAGE_MULTIPLAYER%s", qPrintable(closePrefix), qPrintable(closeSuffix));   break;
+      case ID_PAGE_DEMOS :      qDebug("%sPAGE_DEMOS%s", qPrintable(closePrefix), qPrintable(closeSuffix));     break;
+      case ID_PAGE_NET :        qDebug("%sPAGE_NET%s", qPrintable(closePrefix), qPrintable(closeSuffix));       break;
+      case ID_PAGE_NETGAME :        qDebug("%sPAGE_NETGAME%s", qPrintable(closePrefix), qPrintable(closeSuffix));       break;
+      case ID_PAGE_INFO :       qDebug("%sPAGE_INFO%s", qPrintable(closePrefix), qPrintable(closeSuffix));      break;
+      case ID_PAGE_MAIN :       qDebug("%sPAGE_MAIN%s", qPrintable(closePrefix), qPrintable(closeSuffix));      break;
+      case ID_PAGE_GAMESTATS :      qDebug("%sPAGE_GAMESTATS%s", qPrintable(closePrefix), qPrintable(closeSuffix));     break;
+      case ID_PAGE_SINGLEPLAYER :   qDebug("%sPAGE_SINGLEPLAYER%s", qPrintable(closePrefix), qPrintable(closeSuffix));  break;
+      case ID_PAGE_TRAINING :       qDebug("%sPAGE_TRAINING%s", qPrintable(closePrefix), qPrintable(closeSuffix));      break;
+      case ID_PAGE_SELECTWEAPON :   qDebug("%sPAGE_SELECTWEAPON%s", qPrintable(closePrefix), qPrintable(closeSuffix));  break;
+      case ID_PAGE_NETSERVER :      qDebug("%sPAGE_NETSERVER%s", qPrintable(closePrefix), qPrintable(closeSuffix));     break;
+      case ID_PAGE_INGAME :     qDebug("%sPAGE_INGAME%s", qPrintable(closePrefix), qPrintable(closeSuffix));        break;
+      case ID_PAGE_ROOMSLIST :      qDebug("%sPAGE_ROOMSLIST%s", qPrintable(closePrefix), qPrintable(closeSuffix));     break;
+      case ID_PAGE_CONNECTING : qDebug("%sPAGE_CONNECTING%s", qPrintable(closePrefix), qPrintable(closeSuffix));    break;
+      case ID_PAGE_SCHEME :     qDebug("%sPAGE_SCHEME%s", qPrintable(closePrefix), qPrintable(closeSuffix));        break;
+      case ID_PAGE_ADMIN :      qDebug("%sPAGE_ADMIN%s", qPrintable(closePrefix), qPrintable(closeSuffix));     break;
+      case ID_PAGE_CAMPAIGN :       qDebug("%sPAGE_CAMPAIGN%s", qPrintable(closePrefix), qPrintable(closeSuffix));      break;
+      case ID_PAGE_DRAWMAP :        qDebug("%sPAGE_DRAWMAP%s", qPrintable(closePrefix), qPrintable(closeSuffix));       break;
+      case ID_PAGE_DATADOWNLOAD :   qDebug("%sPAGE_DATADOWNLOAD%s", qPrintable(closePrefix), qPrintable(closeSuffix));  break;
+      case ID_PAGE_FEEDBACK :       qDebug("%sPAGE_FEEDBACK%s", qPrintable(closePrefix), qPrintable(closeSuffix));      break;
+      case ID_PAGE_VIDEOS :     qDebug("%sPAGE_VIDEOS%s", qPrintable(closePrefix), qPrintable(closeSuffix));        break;
+      case MAX_PAGE :           qDebug("%sMAX_PAGE%s", qPrintable(closePrefix), qPrintable(closeSuffix));       break;
+      default :         qDebug("%sUNKNOWN PAGE%s", qPrintable(closePrefix), qPrintable(closeSuffix));       break;
+    } //end switch(lastid)
+    switch (id) { //Print the id of the opened page
+      case ID_PAGE_SETUP_TEAM : qDebug("%sPAGE_SETUP_TEAM%s", qPrintable(openPrefix), qPrintable(openSuffix));      break;
+      case ID_PAGE_SETUP :      qDebug("%sPAGE_SETUP%s", qPrintable(openPrefix), qPrintable(openSuffix));       break;
+      case ID_PAGE_MULTIPLAYER :    qDebug("%sPAGE_MULTIPLAYER%s", qPrintable(openPrefix), qPrintable(openSuffix));     break;
+      case ID_PAGE_DEMOS :      qDebug("%sPAGE_DEMOS%s", qPrintable(openPrefix), qPrintable(openSuffix));       break;
+      case ID_PAGE_NET :        qDebug("%sPAGE_NET%s", qPrintable(openPrefix), qPrintable(openSuffix));         break;
+      case ID_PAGE_NETGAME :        qDebug("%sPAGE_NETGAME%s", qPrintable(openPrefix), qPrintable(openSuffix));     break;
+      case ID_PAGE_INFO :       qDebug("%sPAGE_INFO%s", qPrintable(openPrefix), qPrintable(openSuffix));        break;
+      case ID_PAGE_MAIN :       qDebug("%sPAGE_MAIN%s", qPrintable(openPrefix), qPrintable(openSuffix));        break;
+      case ID_PAGE_GAMESTATS :      qDebug("%sPAGE_GAMESTATS%s", qPrintable(openPrefix), qPrintable(openSuffix));       break;
+      case ID_PAGE_SINGLEPLAYER :   qDebug("%sPAGE_SINGLEPLAYER%s", qPrintable(openPrefix), qPrintable(openSuffix));    break;
+      case ID_PAGE_TRAINING :       qDebug("%sPAGE_TRAINING%s", qPrintable(openPrefix), qPrintable(openSuffix));        break;
+      case ID_PAGE_SELECTWEAPON :   qDebug("%sPAGE_SELECTWEAPON%s", qPrintable(openPrefix), qPrintable(openSuffix));    break;
+      case ID_PAGE_NETSERVER :      qDebug("%sPAGE_NETSERVER%s", qPrintable(openPrefix), qPrintable(openSuffix));       break;
+      case ID_PAGE_INGAME :     qDebug("%sPAGE_INGAME%s", qPrintable(openPrefix), qPrintable(openSuffix));      break;
+      case ID_PAGE_ROOMSLIST :      qDebug("%sPAGE_ROOMSLIST%s", qPrintable(openPrefix), qPrintable(openSuffix));       break;
+      case ID_PAGE_CONNECTING : qDebug("%sPAGE_CONNECTING%s", qPrintable(openPrefix), qPrintable(openSuffix));      break;
+      case ID_PAGE_SCHEME :     qDebug("%sPAGE_SCHEME%s", qPrintable(openPrefix), qPrintable(openSuffix));      break;
+      case ID_PAGE_ADMIN :      qDebug("%sPAGE_ADMIN%s", qPrintable(openPrefix), qPrintable(openSuffix));       break;
+      case ID_PAGE_CAMPAIGN :       qDebug("%sPAGE_CAMPAIGN%s", qPrintable(openPrefix), qPrintable(openSuffix));        break;
+      case ID_PAGE_DRAWMAP :        qDebug("%sPAGE_DRAWMAP%s", qPrintable(openPrefix), qPrintable(openSuffix));     break;
+      case ID_PAGE_DATADOWNLOAD :   qDebug("%sPAGE_DATADOWNLOAD%s", qPrintable(openPrefix), qPrintable(openSuffix));    break;
+      case ID_PAGE_FEEDBACK :       qDebug("%sPAGE_FEEDBACK%s", qPrintable(openPrefix), qPrintable(openSuffix));        break;
+      case ID_PAGE_VIDEOS :     qDebug("%sPAGE_VIDEOS%s", qPrintable(openPrefix), qPrintable(openSuffix));      break;
+      case MAX_PAGE :           qDebug("%sMAX_PAGE%s", qPrintable(openPrefix), qPrintable(openSuffix));         break;
+      default :         qDebug("%sUNKNOWN PAGE%s", qPrintable(openPrefix), qPrintable(openSuffix));     break;
+    } //end switch(id)
+
     if (id == ID_PAGE_DATADOWNLOAD)
     {
         ui.pageDataDownload->fetchList();
@@ -612,14 +700,9 @@
         ui.pageOptions->setTeamOptionsEnabled(true);
     }
 
-    if (id == ID_PAGE_SETUP)
+    if (id == ID_PAGE_FEEDBACK)
     {
-        config->reloadValues();
-    }
-
-    if (id == ID_PAGE_VIDEOS )
-    {
-        config->reloadVideosValues();
+        ui.pageFeedback->LoadCaptchaImage();
     }
 }
 
@@ -636,8 +719,8 @@
 
    /* if (id == ID_PAGE_DRAWMAP || id == ID_PAGE_GAMESTATS)
         stopAnim = true;
-	This were disabled due to broken flake animations.  I believe the more general problems w/ opacity that forced its disable makes blocking these
-	unnecessary.
+    This were disabled due to broken flake animations.  I believe the more general problems w/ opacity that forced its disable makes blocking these
+    unnecessary.
    */
 
 #if (QT_VERSION >= 0x040600)
@@ -695,8 +778,8 @@
         animationOldSlide->start(QAbstractAnimation::DeleteWhenStopped);
         animationNewSlide->start(QAbstractAnimation::DeleteWhenStopped);
 
-    	/* this is for the situation when the animation below is interrupted by a new animation.  For some reason, finished is not being fired */ 	
-    	for(int i=0;i<MAX_PAGE;i++) if (i!=id && i!=lastid) ui.Pages->widget(i)->hide();
+        /* this is for the situation when the animation below is interrupted by a new animation.  For some reason, finished is not being fired */
+        for(int i=0;i<MAX_PAGE;i++) if (i!=id && i!=lastid) ui.Pages->widget(i)->hide();
     }
 #endif
 }
@@ -965,37 +1048,78 @@
 
 void HWForm::NetPassword(const QString & nick)
 {
-    int passLength = config->value("net/passwordlength", 0).toInt();
-    QString hash = config->value("net/passwordhash", "").toString();
+    //Get hashes
+    QString hash =  config->passwordHash();
+    QString temphash =  config->tempHash();
+
+    //Check them
 
-    // If the password is blank, ask the user to enter one in
-    if (passLength == 0)
-    {
-        HWPasswordDialog * hpd = new HWPasswordDialog(this, tr("Your nickname %1 is\nregistered on Hedgewars.org\nPlease provide your password below\nor pick another nickname in game config:").arg(nick));
-        hpd->cbSave->setChecked(config->value("net/savepassword", true).toBool());
-        if (hpd->exec() != QDialog::Accepted)
-        {
-            ForcedDisconnect(tr("No password supplied."));
-            delete hpd;
-            return;
-        }
-
-        QString password = hpd->lePassword->text();
-        hash = QCryptographicHash::hash(password.toUtf8(), QCryptographicHash::Md5).toHex();
-
-        bool save = hpd->cbSave->isChecked();
-        config->setValue("net/savepassword", save);
-        if (save) // user wants to save password
-        {
-            config->setValue("net/passwordhash", hash);
-            config->setValue("net/passwordlength", password.size());
-            config->setNetPasswordLength(password.size());
-        }
-
-        delete hpd;
+    if (temphash.isEmpty() && hash.isEmpty()) { //If the user enters a registered nick with no password, sends a bogus hash
+        hwnet->SendPasswordHash("THISISNOHASH");
+    }
+    else if (temphash.isEmpty()) { //Send saved hash as default
+        hwnet->SendPasswordHash(hash);
+    }
+    else { //Send the hash
+        hwnet->SendPasswordHash(temphash);
     }
 
-    hwnet->SendPasswordHash(hash);
+    //Remove temporary hash from config
+    config->clearTempHash();
+}
+
+void HWForm::NetNickRegistered(const QString & nick)
+{
+    //Get hashes
+    QString hash =  config->passwordHash();
+    QString temphash =  config->tempHash();
+
+    if (hash.isEmpty()) {
+        if (temphash.isEmpty()) { //If the user enters a registered nick with no password
+            QString suppliedpass;
+            while (suppliedpass.isEmpty()) {
+                QInputDialog nickRegedDialog(this);
+                nickRegedDialog.setWindowModality(Qt::WindowModal);
+                nickRegedDialog.setInputMode(QInputDialog::TextInput);
+                nickRegedDialog.setWindowTitle(tr("Hedgewars - Nick registered"));
+                nickRegedDialog.setLabelText(tr("This nick is registered, and you haven't specified a password.\n\nIf this nick isn't yours, please register your own nick at www.hedgewars.org\n\nPassword:"));
+                nickRegedDialog.setTextEchoMode(QLineEdit::Password);
+                nickRegedDialog.exec();
+
+                suppliedpass = nickRegedDialog.textValue();
+
+                if (nickRegedDialog.result() == QDialog::Rejected) {
+                    config->clearPasswordHash();
+                    config->clearTempHash();
+                    GoBack();
+                    return;
+                }
+                temphash = QCryptographicHash::hash(suppliedpass.toUtf8(), QCryptographicHash::Md5).toHex();
+                config->setTempHash(temphash);
+            }
+        }
+    }
+    NetPassword(nick);
+}
+
+void HWForm::NetNickNotRegistered(const QString & nick)
+{
+    QMessageBox noRegMsg(this);
+    noRegMsg.setIcon(QMessageBox::Information);
+    noRegMsg.setWindowTitle(QMessageBox::tr("Hedgewars - Nick not registered"));
+    noRegMsg.setWindowModality(Qt::WindowModal);
+    noRegMsg.setText(tr("Your nickname is not registered.\nTo prevent someone else from using it,\nplease register it at www.hedgewars.org"));
+
+    if (!config->passwordHash().isEmpty())
+    {
+        config->clearPasswordHash();
+        noRegMsg.setText(noRegMsg.text()+tr("\n\nYour password wasn't saved either."));
+    }
+    if (!config->tempHash().isEmpty())
+    {
+        config->clearTempHash();
+    }
+    noRegMsg.exec();
 }
 
 void HWForm::NetNickTaken(const QString & nick)
@@ -1005,7 +1129,12 @@
 
     if (!ok || newNick.isEmpty())
     {
-        ForcedDisconnect(tr("No nickname supplied."));
+        //ForcedDisconnect(tr("No nickname supplied."));
+    bool retry = RetryDialog(tr("Hedgewars - Empty nickname"), tr("No nickname supplied."));
+    GoBack();
+        if (retry) {
+           NetConnectOfficialServer();
+        }
         return;
     }
 
@@ -1020,8 +1149,39 @@
 void HWForm::NetAuthFailed()
 {
     // Set the password blank if case the user tries to join and enter his password again
-    config->setValue("net/passwordlength", 0);
-    config->setNetPasswordLength(0);
+    config->clearTempHash();
+
+    //Try to login again
+    bool retry = RetryDialog(tr("Hedgewars - Wrong password"), tr("You entered a wrong password."));
+    GoBack();
+
+    config->clearPasswordHash();
+    config->clearTempHash();
+    if (retry) {
+       NetConnectOfficialServer();
+    }
+}
+
+bool HWForm::RetryDialog(const QString & title, const QString & label)
+{
+    QMessageBox retryMsg(this);
+    retryMsg.setIcon(QMessageBox::Warning);
+    retryMsg.setWindowTitle(title);
+    retryMsg.setText(label);
+    retryMsg.setWindowModality(Qt::WindowModal);
+
+    retryMsg.addButton(QMessageBox::Cancel);
+
+    QPushButton *retryButton = retryMsg.addButton(QMessageBox::Ok);
+    retryButton->setText(tr("Try Again"));
+    retryButton->setFocus();
+
+    retryMsg.exec();
+
+    if (retryMsg.clickedButton() == retryButton) {
+       return true;
+    }
+    return false;
 }
 
 void HWForm::NetTeamAccepted(const QString & team)
@@ -1074,13 +1234,14 @@
     connect(hwnet, SIGNAL(AddNetTeam(const HWTeam&)), this, SLOT(AddNetTeam(const HWTeam&)), Qt::QueuedConnection);
     connect(hwnet, SIGNAL(RemoveNetTeam(const HWTeam&)), this, SLOT(RemoveNetTeam(const HWTeam&)), Qt::QueuedConnection);
     connect(hwnet, SIGNAL(TeamAccepted(const QString&)), this, SLOT(NetTeamAccepted(const QString&)), Qt::QueuedConnection);
-    connect(hwnet, SIGNAL(AskForPassword(const QString&)), this, SLOT(NetPassword(const QString&)), Qt::QueuedConnection);
+    connect(hwnet, SIGNAL(NickRegistered(const QString&)), this, SLOT(NetNickRegistered(const QString&)), Qt::QueuedConnection);
+    connect(hwnet, SIGNAL(NickNotRegistered(const QString&)), this, SLOT(NetNickNotRegistered(const QString&)), Qt::QueuedConnection);
     connect(hwnet, SIGNAL(NickTaken(const QString&)), this, SLOT(NetNickTaken(const QString&)), Qt::QueuedConnection);
     connect(hwnet, SIGNAL(AuthFailed()), this, SLOT(NetAuthFailed()), Qt::QueuedConnection);
     //connect(ui.pageNetGame->BtnBack, SIGNAL(clicked()), hwnet, SLOT(partRoom()));
 
     ui.pageRoomsList->chatWidget->setUsersModel(hwnet->lobbyPlayersModel());
-    ui.pageNetGame->pChatWidget->setUsersModel(hwnet->roomPlayersModel());
+    ui.pageNetGame->chatWidget->setUsersModel(hwnet->roomPlayersModel());
 
 // rooms list page stuff
     ui.pageRoomsList->setModel(hwnet->roomsListModel());
@@ -1109,26 +1270,26 @@
 
 // net page stuff
     connect(hwnet, SIGNAL(chatStringFromNet(const QString&)),
-            ui.pageNetGame->pChatWidget, SLOT(onChatString(const QString&)), Qt::QueuedConnection);
+            ui.pageNetGame->chatWidget, SLOT(onChatString(const QString&)), Qt::QueuedConnection);
 
     connect(hwnet, SIGNAL(chatStringFromMe(const QString&)),
-            ui.pageNetGame->pChatWidget, SLOT(onChatString(const QString&)), Qt::QueuedConnection);
+            ui.pageNetGame->chatWidget, SLOT(onChatString(const QString&)), Qt::QueuedConnection);
     connect(hwnet, SIGNAL(roomMaster(bool)),
-            ui.pageNetGame->pChatWidget, SLOT(adminAccess(bool)), Qt::QueuedConnection);
-    connect(ui.pageNetGame->pChatWidget, SIGNAL(chatLine(const QString&)),
+            ui.pageNetGame->chatWidget, SLOT(adminAccess(bool)), Qt::QueuedConnection);
+    connect(ui.pageNetGame->chatWidget, SIGNAL(chatLine(const QString&)),
             hwnet, SLOT(chatLineToNet(const QString&)));
     connect(ui.pageNetGame->BtnGo, SIGNAL(clicked()), hwnet, SLOT(ToggleReady()));
     connect(hwnet, SIGNAL(setMyReadyStatus(bool)),
             ui.pageNetGame, SLOT(setReadyStatus(bool)), Qt::QueuedConnection);
 
 // chat widget actions
-    connect(ui.pageNetGame->pChatWidget, SIGNAL(kick(const QString&)),
+    connect(ui.pageNetGame->chatWidget, SIGNAL(kick(const QString&)),
             hwnet, SLOT(kickPlayer(const QString&)));
-    connect(ui.pageNetGame->pChatWidget, SIGNAL(ban(const QString&)),
+    connect(ui.pageNetGame->chatWidget, SIGNAL(ban(const QString&)),
             hwnet, SLOT(banPlayer(const QString&)));
-    connect(ui.pageNetGame->pChatWidget, SIGNAL(info(const QString&)),
+    connect(ui.pageNetGame->chatWidget, SIGNAL(info(const QString&)),
             hwnet, SLOT(infoPlayer(const QString&)));
-    connect(ui.pageNetGame->pChatWidget, SIGNAL(follow(const QString&)),
+    connect(ui.pageNetGame->chatWidget, SIGNAL(follow(const QString&)),
             hwnet, SLOT(followPlayer(const QString&)));
     connect(ui.pageRoomsList->chatWidget, SIGNAL(kick(const QString&)),
             hwnet, SLOT(kickPlayer(const QString&)));
@@ -1151,9 +1312,9 @@
 
 // nick list stuff
     connect(hwnet, SIGNAL(nickAdded(const QString&, bool)),
-            ui.pageNetGame->pChatWidget, SLOT(nickAdded(const QString&, bool)), Qt::QueuedConnection);
+            ui.pageNetGame->chatWidget, SLOT(nickAdded(const QString&, bool)), Qt::QueuedConnection);
     connect(hwnet, SIGNAL(nickRemoved(const QString&)),
-            ui.pageNetGame->pChatWidget, SLOT(nickRemoved(const QString&)), Qt::QueuedConnection);
+            ui.pageNetGame->chatWidget, SLOT(nickRemoved(const QString&)), Qt::QueuedConnection);
     connect(hwnet, SIGNAL(nickAddedLobby(const QString&, bool)),
             ui.pageRoomsList->chatWidget, SLOT(nickAdded(const QString&, bool)), Qt::QueuedConnection);
     connect(hwnet, SIGNAL(nickRemovedLobby(const QString&)),
@@ -1176,11 +1337,16 @@
     connect(hwnet, SIGNAL(serverMessageNew(const QString&)), ui.pageAdmin, SLOT(serverMessageNew(const QString &)));
     connect(hwnet, SIGNAL(serverMessageOld(const QString&)), ui.pageAdmin, SLOT(serverMessageOld(const QString &)));
     connect(hwnet, SIGNAL(latestProtocolVar(int)), ui.pageAdmin, SLOT(protocol(int)));
+    connect(hwnet, SIGNAL(bansList(const QStringList &)), ui.pageAdmin, SLOT(setBansList(const QStringList &)));
     connect(ui.pageAdmin, SIGNAL(setServerMessageNew(const QString&)), hwnet, SLOT(setServerMessageNew(const QString &)));
     connect(ui.pageAdmin, SIGNAL(setServerMessageOld(const QString&)), hwnet, SLOT(setServerMessageOld(const QString &)));
     connect(ui.pageAdmin, SIGNAL(setProtocol(int)), hwnet, SLOT(setLatestProtocolVar(int)));
     connect(ui.pageAdmin, SIGNAL(askServerVars()), hwnet, SLOT(askServerVars()));
     connect(ui.pageAdmin, SIGNAL(clearAccountsCache()), hwnet, SLOT(clearAccountsCache()));
+    connect(ui.pageAdmin, SIGNAL(bansListRequest()), hwnet, SLOT(getBanList()));
+    connect(ui.pageAdmin, SIGNAL(removeBan(QString)), hwnet, SLOT(removeBan(QString)));
+    connect(ui.pageAdmin, SIGNAL(banIP(QString,QString,int)), hwnet, SLOT(banIP(QString,QString,int)));
+    connect(ui.pageAdmin, SIGNAL(banNick(QString,QString,int)), hwnet, SLOT(banNick(QString,QString,int)));
 
 // disconnect
     connect(hwnet, SIGNAL(disconnected(const QString&)), this, SLOT(ForcedDisconnect(const QString&)), Qt::QueuedConnection);
@@ -1190,23 +1356,95 @@
     connect(ui.pageNetGame->pGameCFG, SIGNAL(paramChanged(const QString &, const QStringList &)), hwnet, SLOT(onParamChanged(const QString &, const QStringList &)));
     connect(hwnet, SIGNAL(configAsked()), ui.pageNetGame->pGameCFG, SLOT(fullNetConfig()));
 
-    while (nick.isEmpty())
-    {
-        nick = QInputDialog::getText(this,
-                                     QObject::tr("Nickname"),
-                                     QObject::tr("Please enter your nickname"),
-                                     QLineEdit::Normal,
-                                     QDir::home().dirName());
-        config->setValue("net/nick",nick);
+//nick and pass stuff
+
+    //remove temppasswordhash just in case
+    config->clearTempHash();
+
+    //initialize
+    QString hash = config->passwordHash();
+    QString temphash = config->tempHash();
+    QString nickname = config->value("net/nick", "").toString();
+    QString password;
+
+    if (nickname.isEmpty() || hash.isEmpty()) { //if something from login is missing, start dialog loop
+
+        while (nickname.isEmpty() || (hash.isEmpty() && temphash.isEmpty())) //while a nickname, or both hashes are missing
+        {
+        //open dialog
+            HWPasswordDialog * pwDialog = new HWPasswordDialog(this);
+            pwDialog->cbSave->setChecked(config->value("net/savepassword", true).toBool());
+
+        //if nickname is present, put it into the field
+        if (!nickname.isEmpty()) {
+            pwDialog->leNickname->setText(nickname);
+            pwDialog->lePassword->setFocus();
+        }
+
+        //if dialog close, create an error message
+        if (pwDialog->exec() != QDialog::Accepted) {
+            delete pwDialog;
+            GoBack();
+            return;
+        }
+
+        //set nick and pass from the dialog
+        nickname = pwDialog->leNickname->text();
+        password = pwDialog->lePassword->text();
+
+        //check the nickname variable
+        if (nickname.isEmpty()) {
+            int retry = RetryDialog(tr("Hedgewars - Empty nickname"), tr("No nickname supplied."));
+            GoBack();
+            delete pwDialog;
+            if (retry) {
+                NetConnectOfficialServer();
+            }
+            return;
+        }
+
+        if (!password.isEmpty()) {
+            //calculate temphash and set it into config
+            temphash = QCryptographicHash::hash(password.toUtf8(), QCryptographicHash::Md5).toHex();
+            config->setTempHash(temphash);
+
+            //if user wants to save password
+            bool save = pwDialog->cbSave->isChecked();
+            config->setValue("net/savepassword", save);
+            if (save) // user wants to save password
+            {
+                config->setPasswordHash(temphash);
+            }
+        }
+        else {
+            delete pwDialog;
+            config->setValue("net/nick", nickname);
+            config->updNetNick();
+            config->clearPasswordHash();
+            break;
+        }
+
+        delete pwDialog;
+
+        //update nickname
+        config->setValue("net/nick", nickname);
         config->updNetNick();
+
+        //and all the variables
+        hash = config->passwordHash();
+        temphash = config->tempHash();
+        nickname = config->value("net/nick", "").toString();
+        }
     }
 
-    ui.pageRoomsList->setUser(nick);
-    ui.pageNetGame->setUser(nick);
+    ui.pageRoomsList->setUser(nickname);
+    ui.pageNetGame->setUser(nickname);
 
-    hwnet->Connect(hostName, port, nick);
+    hwnet->Connect(hostName, port, nickname);
 }
 
+
+
 void HWForm::NetConnect()
 {
     HWHostPortDialog * hpd = new HWHostPortDialog(this);
@@ -1271,6 +1509,20 @@
 
 void HWForm::ForcedDisconnect(const QString & reason)
 {
+    if (reason == "Reconnected too fast") { //TODO: this is a hack, which should be remade
+        bool retry = RetryDialog(tr("Hedgewars - Connection error"), tr("You reconnected too fast.\nPlease wait a few seconds and try again."));
+        if (retry) {
+            NetConnectOfficialServer();
+        }
+        else {
+            while (ui.Pages->currentIndex() != ID_PAGE_NET
+                && ui.Pages->currentIndex() != ID_PAGE_MAIN)
+            {
+                GoBack();
+            }
+        }
+        return;
+    }
     if (pnetserver)
         return; // we have server - let it care of all things
     if (hwnet)
@@ -1280,7 +1532,6 @@
     }
 
     while (ui.Pages->currentIndex() != ID_PAGE_NET
-        && ui.Pages->currentIndex() != ID_PAGE_NETTYPE
         && ui.Pages->currentIndex() != ID_PAGE_MAIN)
     {
         GoBack();
@@ -1294,7 +1545,7 @@
 
 void HWForm::NetGameEnter()
 {
-    ui.pageNetGame->pChatWidget->clear();
+    ui.pageNetGame->chatWidget->clear();
     GoToPage(ID_PAGE_NETGAME);
 }
 
@@ -1345,7 +1596,7 @@
             //setVisible(true);
             setFocusPolicy(Qt::StrongFocus);
             if (id == ID_PAGE_INGAME) GoBack();
-            Music(ui.pageOptions->CBEnableFrontendMusic->isChecked());
+            Music(ui.pageOptions->CBFrontendMusic->isChecked());
             if (wBackground) wBackground->startAnimation();
             GoToPage(ID_PAGE_GAMESTATS);
             if (hwnet && (!game || !game->netSuspend)) hwnet->gameFinished(true);
@@ -1363,7 +1614,7 @@
                      (gameState == gsInterrupted || gameState == gsStopped || gameState == gsDestroyed || gameState == gsHalted)))
             {
                 if (id == ID_PAGE_INGAME) GoBack();
-                Music(ui.pageOptions->CBEnableFrontendMusic->isChecked());
+                Music(ui.pageOptions->CBFrontendMusic->isChecked());
                 if (wBackground) wBackground->startAnimation();
                 if (hwnet) hwnet->gameFinished(false);
             }
@@ -1480,7 +1731,9 @@
     xfire_free();
 #endif
     config->SaveOptions();
+#if VIDEOREC
     config->SaveVideosOptions();
+#endif
     event->accept();
 }
 
@@ -1632,19 +1885,28 @@
 // used for --set-everything [screen width] [screen height] [color dept] [volume] [enable music] [enable sounds] [language file] [full screen] [show FPS] [alternate damage] [timer value] [reduced quality]
 QString HWForm::getDemoArguments()
 {
+
+    QString prefix = datadir->absolutePath();
+    QString userPrefix = cfgdir->absolutePath();
+#ifdef Q_WS_WIN
+    prefix = prefix.replace("/","\\");
+    userPrefix = userPrefix.replace("/","\\");
+#endif
+
     QRect resolution = config->vid_Resolution();
-    return QString(QString::number(resolution.width()) + " "
-                   + QString::number(resolution.height()) + " "
-                   + QString::number(config->bitDepth()) + " " // bpp
-                   + QString::number(config->volume()) + " " // sound volume
-                   + (config->isMusicEnabled() ? "1" : "0") + " "
-                   + (config->isSoundEnabled() ? "1" : "0") + " "
-                   + config->language() + ".txt "
-                   + (config->vid_Fullscreen() ? "1" : "0") + " "
-                   + (config->isShowFPSEnabled() ? "1" : "0") + " "
-                   + (config->isAltDamageEnabled() ? "1" : "0") + " "
-                   + QString::number(config->timerInterval()) + " "
-                   + QString::number(config->translateQuality()));
+    return QString("--prefix " + prefix
+                   + " --user-prefix " + userPrefix
+                   + " --width " + QString::number(resolution.width())
+                   + " --height " + QString::number(resolution.height())
+                   + " --volume " + QString::number(config->volume())
+                   + (config->isMusicEnabled() ? "" : " --nomusic")
+                   + (config->isSoundEnabled() ? "" : " --nosound")
+                   + " --locale " + config->language() + ".txt"
+                   + (config->vid_Fullscreen() ? " --fullscreen" : "")
+                   + (config->isShowFPSEnabled() ? " --showfps" : "")
+                   + (config->isAltDamageEnabled() ? " --altdmg" : "")
+                   + " --frame-interval " + QString::number(config->timerInterval())
+                   + " --raw-quality " + QString::number(config->translateQuality()));
 }
 
 void HWForm::AssociateFiles()
@@ -1659,8 +1921,8 @@
     registry_hkcr.setValue("Hedgewars.Save/Default", tr("Hedgewars Save File", "File Types"));
     registry_hkcr.setValue("Hedgewars.Demo/DefaultIcon/Default", "\"" + bindir->absolutePath().replace("/", "\\") + "\\hwdfile.ico\",0");
     registry_hkcr.setValue("Hedgewars.Save/DefaultIcon/Default", "\"" + bindir->absolutePath().replace("/", "\\") + "\\hwsfile.ico\",0");
-    registry_hkcr.setValue("Hedgewars.Demo/Shell/Open/Command/Default", "\"" + bindir->absolutePath().replace("/", "\\") + "\\hwengine.exe\" \"" + cfgdir->absolutePath().replace("/","\\") + "\" \"" + datadir->absolutePath().replace("/", "\\") + "\" \"%1\" --set-everything "+arguments);
-    registry_hkcr.setValue("Hedgewars.Save/Shell/Open/Command/Default", "\"" + bindir->absolutePath().replace("/", "\\") + "\\hwengine.exe\" \"" + cfgdir->absolutePath().replace("/","\\") + "\" \"" + datadir->absolutePath().replace("/", "\\") + "\" \"%1\" --set-everything "+arguments);
+    registry_hkcr.setValue("Hedgewars.Demo/Shell/Open/Command/Default", "\"" + bindir->absolutePath().replace("/", "\\") + "\\hwengine.exe\" \"%1\" "+arguments);
+    registry_hkcr.setValue("Hedgewars.Save/Shell/Open/Command/Default", "\"" + bindir->absolutePath().replace("/", "\\") + "\\hwengine.exe\" \"%1\" "+arguments);
 #elif defined __APPLE__
     // only useful when other apps have taken precedence over our file extensions and you want to reset it
     system("defaults write com.apple.LaunchServices LSHandlers -array-add '<dict><key>LSHandlerContentTag</key><string>hwd</string><key>LSHandlerContentTagClass</key><string>public.filename-extension</string><key>LSHandlerRoleAll</key><string>org.hedgewars.desktop</string></dict>'");
@@ -1681,7 +1943,7 @@
     if (success) success = system("xdg-mime default hwengine.desktop application/x-hedgewars-demo")==0;
     if (success) success = system("xdg-mime default hwengine.desktop application/x-hedgewars-save")==0;
     // hack to add user's settings to hwengine. might be better at this point to read in the file, append it, and write it out to its new home.  This assumes no spaces in the data dir path
-    if (success) success = system(("sed -i 's/^\\(Exec=.*\\) \\([^ ]* %f\\)/\\1 "+cfgdir->absolutePath().replace(" ","\\\\ ").replace("/","\\/")+" \\2 --set-everything "+arguments+"/' "+QDir::home().absolutePath()+"/.local/share/applications/hwengine.desktop").toLocal8Bit().constData())==0;
+    if (success) success = system(("sed -i 's/^\\(Exec=.*\\) \\([^ ]* %f\\)/\\1 \\2 "+arguments+"/' "+QDir::home().absolutePath()+"/.local/share/applications/hwengine.desktop").toLocal8Bit().constData())==0;
 #endif
     if (success)
     {
@@ -1726,105 +1988,74 @@
 
 void HWForm::SendFeedback()
 {
-    //Create Xml representation of google code issue first
-    if (!CreateIssueXml())
+    // Get form data
+
+    QString summary = ui.pageFeedback->summary->text();
+    QString description = ui.pageFeedback->description->toPlainText();
+    QString email = ui.pageFeedback->email->text();
+    QString captchaCode = ui.pageFeedback->captcha_code->text();
+    QString captchaID = QString::number(ui.pageFeedback->captchaID);
+    QString version = "HedgewarsFoundation-Hedgewars-" + (cVersionString?(*cVersionString):QString(""));
+
+    if (summary.isEmpty() || description.isEmpty())
     {
-        ShowErrorMessage(QMessageBox::tr("Please fill out all fields"));
+        ShowErrorMessage(QMessageBox::tr("Please fill out all fields. Email is optional."));
         return;
     }
 
-    //Google login using fake account (feedback.hedgewars@gmail.com)
+    // Submit issue to PHP script
+
+    QByteArray body;
+    body.append("captcha=");
+    body.append(captchaID);
+    body.append("&code=");
+    body.append(captchaCode);
+    body.append("&version=");
+    body.append(QUrl::toPercentEncoding(version));
+    body.append("&title=");
+    body.append(QUrl::toPercentEncoding(summary));
+    body.append("&body=");
+    body.append(QUrl::toPercentEncoding(description));
+    body.append("&email=");
+    body.append(QUrl::toPercentEncoding(email));
+    if (ui.pageFeedback->CheckSendSpecs->isChecked())
+    {
+        body.append("&specs=");
+        body.append(QUrl::toPercentEncoding(ui.pageFeedback->specs));
+    }
+
     nam = new QNetworkAccessManager(this);
     connect(nam, SIGNAL(finished(QNetworkReply*)),
             this, SLOT(finishedSlot(QNetworkReply*)));
 
-    QUrl url(QString("https://www.google.com/accounts/ClientLogin?"
-                     "accountType=GOOGLE&Email=feedback.hedgewars@gmail.com&Passwd=hwfeedback&service=code&source=HedgewarsFoundation-Hedgewars-")
-                    + (cVersionString?(*cVersionString):QString("")));
-    nam->get(QNetworkRequest(url));
-
-}
-
-bool HWForm::CreateIssueXml()
-{
-    QString summary = ui.pageFeedback->summary->text();
-    QString description = ui.pageFeedback->description->toPlainText();
+    QNetworkRequest header(QUrl("http://hedgewars.org/feedback/?submit"));
+    header.setRawHeader("Content-Length", QString::number(body.size()).toAscii());
 
-    //Check if all necessary information is entered
-    if (summary.isEmpty() || description.isEmpty())
-        return false;
-
-    issueXml =
-        "<?xml version='1.0' encoding='UTF-8'?>"
-        "<entry xmlns='http://www.w3.org/2005/Atom' xmlns:issues='http://code.google.com/p/hedgewars/issues/list'>"
-        "<title>";
-    issueXml.append(summary);
-    issueXml.append("</title><content type='html'>");
-    issueXml.append(description);
-    issueXml.append("</content><author><name>feedback.hedgewars</name></author></entry>");
-
-    return true;
+    nam->post(header, body);
 }
 
 void HWForm::finishedSlot(QNetworkReply* reply)
 {
     if (reply && reply->error() == QNetworkReply::NoError)
     {
-        QByteArray array = reply->readAll();
-        QString str(array);
-
-        if (authToken.length() != 0)
-        {
-
             QMessageBox infoMsg(this);
             infoMsg.setIcon(QMessageBox::Information);
             infoMsg.setWindowTitle(QMessageBox::tr("Hedgewars - Success"));
-            infoMsg.setText(QMessageBox::tr("Successfully posted the issue on hedgewars.googlecode.com"));
+            infoMsg.setText(reply->readAll());
             infoMsg.setWindowModality(Qt::WindowModal);
             infoMsg.exec();
 
             ui.pageFeedback->summary->clear();
+            ui.pageFeedback->email->clear();
             ui.pageFeedback->description->clear();
-            authToken = "";
-            return;
-        }
-
-        if (!getAuthToken(str))
-        {
-            ShowErrorMessage(QMessageBox::tr("Error during authentication at google.com"));
-            return;
-        }
+            ui.pageFeedback->LoadCaptchaImage();
 
-        QByteArray body(issueXml.toUtf8());
-        QNetworkRequest header(QUrl("https://code.google.com/feeds/issues/p/hedgewars/issues/full"));
-        header.setRawHeader("Content-Length", QString::number(issueXml.length()).toAscii());
-        header.setRawHeader("Content-Type", "application/atom+xml");
-        header.setRawHeader("Authorization", QString("GoogleLogin auth=%1").arg(authToken).toUtf8());
-        nam->post(header, body);
-
+            return;
     }
-    else if (authToken.length() == 0)
-        ShowErrorMessage(QMessageBox::tr("Error during authentication at google.com"));
     else
     {
-        ShowErrorMessage(QMessageBox::tr("Error reporting the issue, please try again later (or visit hedgewars.googlecode.com directly)"));
-        authToken = "";
+        ShowErrorMessage(QString("Error: ") + reply->readAll());
+        ui.pageFeedback->LoadCaptchaImage();
     }
-
 }
 
-bool HWForm::getAuthToken(QString str)
-{
-    QRegExp ex("Auth=(.+)");
-
-    if (-1 == ex.indexIn(str))
-        return false;
-
-    authToken = ex.cap(1);
-    authToken.remove(QChar('\n'));
-
-    return true;
-}
-
-
-
--- a/QTfrontend/hwform.h	Sun Dec 02 00:03:16 2012 +0100
+++ b/QTfrontend/hwform.h	Tue Dec 25 04:45:22 2012 +0100
@@ -61,7 +61,6 @@
         HWForm(QWidget *parent = 0, QString styleSheet = "");
         Ui_HWForm ui;
         static GameUIConfig * config;
-        static QSettings * gameSettings; // Same file GameUIConfig points to but without the baggage.  Needs sync() calls if you want to get GameUIConfig changes though
         void updateXfire();
         void PlayDemoQuick(const QString & demofilename);
         void exit();
@@ -106,8 +105,11 @@
         void NetWarning(const QString & wrnmsg);
         void NetGameEnter();
         void NetPassword(const QString & nick);
+        void NetNickRegistered(const QString & nick);
+        void NetNickNotRegistered(const QString & nick);
         void NetNickTaken(const QString & nick);
         void NetAuthFailed();
+    bool RetryDialog(const QString & title, const QString & label);
         void NetTeamAccepted(const QString& team);
         void AddNetTeam(const HWTeam& team);
         void RemoveNetTeam(const HWTeam& team);
@@ -126,13 +128,8 @@
         void InitCampaignPage();
         //Starts the transmission process for the feedback
         void SendFeedback();
-        //Make a xml representation of the issue to be created
-        bool CreateIssueXml();
-        //Called the first time when receiving authorization token from google,
-        //second time when receiving the response after posting the issue
+        //Called after submitting new feedback
         void finishedSlot(QNetworkReply* reply);
-        //Filter the auth token from the reply from google
-        bool getAuthToken(QString str);
 
         void NetGameChangeStatus(bool isMaster);
         void NetGameMaster();
@@ -146,7 +143,7 @@
 
     private:
         void _NetConnect(const QString & hostName, quint16 port, QString nick);
-        void UpdateTeamsLists(const QStringList* editable_teams=0);
+        void UpdateTeamsLists();
         void CreateGame(GameCFGWidget * gamecfg, TeamSelWidget* pTeamSelWidget, QString ammo);
         void closeEvent(QCloseEvent *event);
         void CustomizePalettes();
@@ -173,13 +170,12 @@
             ID_PAGE_CONNECTING     ,
             ID_PAGE_SCHEME         ,
             ID_PAGE_ADMIN          ,
-            ID_PAGE_NETTYPE        ,
             ID_PAGE_CAMPAIGN       ,
             ID_PAGE_DRAWMAP        ,
             ID_PAGE_DATADOWNLOAD   ,
-            ID_PAGE_FEEDBACK	   ,
-            ID_PAGE_VIDEOS,
-	    MAX_PAGE
+            ID_PAGE_FEEDBACK       ,
+            ID_PAGE_VIDEOS     ,
+            MAX_PAGE
         };
         QPointer<HWGame> game;
         QPointer<HWNetServer> pnetserver;
@@ -194,8 +190,6 @@
         QSignalMapper * pageSwitchMapper;
         QByteArray m_lastDemo;
         QNetworkAccessManager * nam;
-        QString issueXml;
-        QString authToken;
 
         QPropertyAnimation *animationNewSlide;
         QPropertyAnimation *animationOldSlide;
--- a/QTfrontend/main.cpp	Sun Dec 02 00:03:16 2012 +0100
+++ b/QTfrontend/main.cpp	Tue Dec 25 04:45:22 2012 +0100
@@ -35,8 +35,6 @@
 #include "DataManager.h"
 #include "FileEngine.h"
 
-#include "frontlib.h"
-
 #ifdef _WIN32
 #include <Shlobj.h>
 #endif
@@ -90,9 +88,9 @@
 
 bool checkForDir(const QString & dir)
 {
-    QDir tmpdir;
-    if (!tmpdir.exists(dir))
-        if (!tmpdir.mkdir(dir))
+    QDir tmpdir(dir);
+    if (!tmpdir.exists())
+        if (!tmpdir.mkpath(dir))
         {
             QMessageBox directoryMsg(QApplication::activeWindow());
             directoryMsg.setIcon(QMessageBox::Warning);
@@ -105,14 +103,41 @@
     return true;
 }
 
+bool checkForFile(const QString & file)
+{
+    QFile tmpfile(file);
+    if (!tmpfile.exists())
+        return tmpfile.open(QFile::WriteOnly);
+    else
+        return true;
+}
+
+#ifdef __APPLE__
+static CocoaInitializer *cocoaInit = NULL;
+// Function to be called at end of program's termination on OS X to release
+// the NSAutoReleasePool contained within the CocoaInitializer.
+void releaseCocoaPool(void)
+{
+    if (cocoaInit != NULL)
+    {
+        delete cocoaInit;
+        cocoaInit = NULL;
+    }
+}
+#endif
+
 int main(int argc, char *argv[])
 {
+#ifdef __APPLE__
+    // This creates the autoreleasepool that prevents leaking, and destroys it only on exit
+    cocoaInit = new CocoaInitializer();
+    atexit(releaseCocoaPool);
+#endif
+
     HWApplication app(argc, argv);
 
     FileEngineHandler engine(argv[0]);
 
-    flib_init();
-
     app.setAttribute(Qt::AA_DontShowIconsInMenus,false);
 
     QStringList arguments = app.arguments();
@@ -150,9 +175,14 @@
     if(parsedArgs.contains("config-dir"))
     {
         QFileInfo f(parsedArgs["config-dir"]);
-        *cConfigDir = f.absoluteFilePath();
+        cfgdir->setPath(f.absoluteFilePath());
         custom_config = true;
     }
+    else
+    {
+        cfgdir->setPath(QDir::homePath());
+        custom_config = false;
+    }
 
     app.setStyle(new QPlastiqueStyle());
 
@@ -164,14 +194,11 @@
 
     qRegisterMetaType<HWTeam>("HWTeam");
 
-    bindir->cd("bin"); // workaround over NSIS installer
+    // workaround over NSIS installer which modifies the install path
+    //bindir->cd("./");
+    bindir->cd(QCoreApplication::applicationDirPath());
 
-    if(cConfigDir->length() == 0)
-        cfgdir->setPath(cfgdir->homePath());
-    else
-        cfgdir->setPath(*cConfigDir);
-
-    if(cConfigDir->length() == 0)
+    if(custom_config == false)
     {
 #ifdef __APPLE__
         checkForDir(cfgdir->absolutePath() + "/Library/Application Support/Hedgewars");
@@ -212,14 +239,14 @@
 
     datadir->cd(bindir->absolutePath());
     datadir->cd(*cDataDir);
-    if(!datadir->cd("hedgewars/Data"))
+    if(!datadir->cd("Data"))
     {
         QMessageBox missingMsg(QApplication::activeWindow());
         missingMsg.setIcon(QMessageBox::Critical);
         missingMsg.setWindowTitle(QMessageBox::tr("Main - Error"));
         missingMsg.setText(QMessageBox::tr("Failed to open data directory:\n%1\n\n"
                                            "Please check your installation!").
-                                            arg(datadir->absolutePath()+"/hedgewars/Data"));
+                                            arg(datadir->absolutePath()+"/Data"));
         missingMsg.setWindowModality(Qt::WindowModal);
         missingMsg.exec();
         return 1;
@@ -228,13 +255,15 @@
     // setup PhysFS
     engine.mount(datadir->absolutePath());
     engine.mount(cfgdir->absolutePath() + "/Data");
-    engine.mount(cfgdir->absolutePath(), "/config");
+    engine.mount(cfgdir->absolutePath());
     engine.setWriteDir(cfgdir->absolutePath());
     engine.mountPacks();
 
+    checkForFile("physfs://hedgewars.ini");
+
     QTranslator Translator;
     {
-        QSettings settings("physfs://config/hedgewars.ini", QSettings::IniFormat);
+        QSettings settings("physfs://hedgewars.ini", QSettings::IniFormat);
         QString cc = settings.value("misc/locale", QString()).toString();
         if(cc.isEmpty())
             cc = QLocale::system().name();
@@ -254,10 +283,6 @@
         registry_hklm.setValue("Software/Hedgewars/Path", bindir->absolutePath().replace("/", "\\"));
     }
 #endif
-#ifdef __APPLE__
-    // this creates the autoreleasepool that prevents leaking
-    CocoaInitializer initializer;
-#endif
 
     QString style = "";
     QString fname;
@@ -294,9 +319,5 @@
 
     app.form = new HWForm(NULL, style);
     app.form->show();
-    int r = app.exec();
-
-    flib_quit();
-
-    return r;
+    return app.exec();
 }
--- a/QTfrontend/net/hwmap.cpp	Sun Dec 02 00:03:16 2012 +0100
+++ b/QTfrontend/net/hwmap.cpp	Tue Dec 25 04:45:22 2012 +0100
@@ -47,9 +47,12 @@
 QStringList HWMap::getArguments()
 {
     QStringList arguments;
-    arguments << cfgdir->absolutePath();
+    arguments << "--internal";
+    arguments << "--port";
     arguments << QString("%1").arg(ipc_port);
-    arguments << "landpreview";
+    arguments << "--user-prefix";
+    arguments << cfgdir->absolutePath();
+    arguments << "--landpreview";
     return arguments;
 }
 
--- a/QTfrontend/net/newnetclient.cpp	Sun Dec 02 00:03:16 2012 +0100
+++ b/QTfrontend/net/newnetclient.cpp	Tue Dec 25 04:45:22 2012 +0100
@@ -241,6 +241,7 @@
     {
         mynick = lst[1];
         m_playersModel->setNickname(mynick);
+        m_nick_registered = false;
         return ;
     }
 
@@ -304,6 +305,10 @@
         QStringList tmp = lst;
         tmp.removeFirst();
         m_roomsListModel->setRoomsList(tmp);
+        if (m_nick_registered == false)
+        {
+            emit NickNotRegistered(mynick);
+        }
         return;
     }
 
@@ -364,6 +369,14 @@
         return;
     }
 
+    if (lst[0] == "BANLIST")
+    {
+        QStringList tmp = lst;
+        tmp.removeFirst();
+        emit bansList(tmp);
+        return;
+    }
+
     if (lst[0] == "CLIENT_FLAGS")
     {
         if(lst.size() < 3 || lst[1].size() < 2)
@@ -530,7 +543,8 @@
 
     if (lst[0] == "ASKPASSWORD")
     {
-        emit AskForPassword(mynick);
+        emit NickRegistered(mynick);
+        m_nick_registered = true;
         return;
     }
 
@@ -565,6 +579,10 @@
         if (lst[1] == "Authentication failed")
         {
             emit AuthFailed();
+        m_game_connected = false;
+        Disconnect();
+        //omitted 'emit disconnected()', we don't want the error message
+        return;
         }
         m_game_connected = false;
         Disconnect();
@@ -621,6 +639,12 @@
             return;
         }
 
+        if (lst[0] == "ROUND_FINISHED")
+        {
+            emit FromNet(QByteArray("\x01o"));
+            return;
+        }
+
         if (lst[0] == "ADD_TEAM")
         {
             if(lst.size() != 24)
@@ -863,6 +887,26 @@
     RawSendNet(QString("BAN%1%2").arg(delimeter).arg(nick));
 }
 
+void HWNewNet::banIP(const QString & ip, const QString & reason, int seconds)
+{
+    RawSendNet(QString("BANIP%1%2%1%3%1%4").arg(delimeter).arg(ip).arg(reason).arg(seconds));
+}
+
+void HWNewNet::banNick(const QString & nick, const QString & reason, int seconds)
+{
+    RawSendNet(QString("BANNICK%1%2%1%3%1%4").arg(delimeter).arg(nick).arg(reason).arg(seconds));
+}
+
+void HWNewNet::getBanList()
+{
+    RawSendNet(QByteArray("BANLIST"));
+}
+
+void HWNewNet::removeBan(const QString & b)
+{
+    RawSendNet(QString("UNBAN%1%2").arg(delimeter).arg(b));
+}
+
 void HWNewNet::kickPlayer(const QString & nick)
 {
     RawSendNet(QString("KICK%1%2").arg(delimeter).arg(nick));
--- a/QTfrontend/net/newnetclient.h	Sun Dec 02 00:03:16 2012 +0100
+++ b/QTfrontend/net/newnetclient.h	Tue Dec 25 04:45:22 2012 +0100
@@ -69,6 +69,7 @@
         QTcpSocket NetSocket;
         QString seed;
         bool m_game_connected;
+        bool m_nick_registered;
         RoomsListModel * m_roomsListModel;
         PlayersListModel * m_playersModel;
         QSortFilterProxyModel * m_lobbyPlayersModel;
@@ -90,7 +91,8 @@
         void disconnected(const QString & reason);
         void Error(const QString & errmsg);
         void Warning(const QString & wrnmsg);
-        void AskForPassword(const QString & nick);
+        void NickRegistered(const QString & nick);
+        void NickNotRegistered(const QString & nick);
         void NickTaken(const QString & nick);
         void AuthFailed();
         void EnteredGame();
@@ -123,6 +125,7 @@
         void serverMessageNew(const QString &);
         void serverMessageOld(const QString &);
         void latestProtocolVar(int);
+        void bansList(const QStringList &);
 
         void setMyReadyStatus(bool isReady);
 
@@ -157,6 +160,10 @@
         void toggleRestrictTeamAdds();
         void partRoom();
         void clearAccountsCache();
+        void getBanList();
+        void removeBan(const QString &);
+        void banIP(const QString & ip, const QString & reason, int seconds);
+        void banNick(const QString & nick, const QString & reason, int seconds);
 
     private slots:
         void ClientRead();
--- a/QTfrontend/net/recorder.cpp	Sun Dec 02 00:03:16 2012 +0100
+++ b/QTfrontend/net/recorder.cpp	Tue Dec 25 04:45:22 2012 +0100
@@ -99,29 +99,44 @@
 {
     QStringList arguments;
     QRect resolution = config->rec_Resolution();
-    arguments << cfgdir->absolutePath();
-    arguments << QString::number(resolution.width());
-    arguments << QString::number(resolution.height());
-    arguments << "32"; // bpp
+    QString nick = config->netNick().toUtf8().toBase64();
+
+    arguments << "--internal";
+    arguments << "--port";
     arguments << QString("%1").arg(ipc_port);
-    arguments << "0"; // fullscreen
-    arguments << "0"; // sound
-    arguments << "0"; // music
-    arguments << "0"; // sound volume
+    arguments << "--prefix";
+    arguments << datadir->absolutePath();
+    arguments << "--user-prefix";
+    arguments << cfgdir->absolutePath();
+    arguments << "--locale";
+    arguments << HWGame::tr("en.txt");
+    arguments << "--frame-interval";
     arguments << QString::number(config->timerInterval());
-    arguments << datadir->absolutePath();
-    arguments << "0"; // fps
-    arguments << (config->isAltDamageEnabled() ? "1" : "0");
-    arguments << config->netNick().toUtf8().toBase64();
+    arguments << "--width";
+    arguments << QString::number(resolution.width());
+    arguments << "--height";
+    arguments << QString::number(resolution.height());
+    arguments << "--nosound";
+    arguments << "--raw-quality";
     arguments << QString::number(config->translateQuality());
+    arguments << "--stereo";
     arguments << QString::number(config->stereoMode());
-    arguments << HWGame::tr("en.txt");
-    arguments << QString::number(config->rec_Framerate()); // framerate numerator
-    arguments << "1";  // framerate denominator
+    arguments << "--nomusic";
+    arguments << "--volume";
+    arguments << "0";
+    if (config->isAltDamageEnabled())
+        arguments << "--altdmg";
+    if (!nick.isEmpty()) {
+        arguments << "--nick";
+        arguments << nick;
+    }
+    arguments << "--recorder";
+    arguments << QString::number(config->rec_Framerate()); //cVideoFramerateNum
+    arguments << "1"; //cVideoFramerateDen
     arguments << prefix;
     arguments << config->AVFormat();
     arguments << config->videoCodec();
-// Could use a field to use quality instead. maybe quality could override bitrate - or just pass (and set) both. 
+// Could use a field to use quality instead. maybe quality could override bitrate - or just pass (and set) both.
 // The library does support using both at once after all.
     arguments << QString::number(config->rec_Bitrate()*1024);
     arguments << (config->recordAudio() ? config->audioCodec() : "no");
--- a/QTfrontend/net/tcpBase.cpp	Sun Dec 02 00:03:16 2012 +0100
+++ b/QTfrontend/net/tcpBase.cpp	Tue Dec 25 04:45:22 2012 +0100
@@ -29,31 +29,39 @@
 
 #ifdef HWLIBRARY
 extern "C" void Game(char**arguments);
+extern "C" void GenLandPreview(int port);
 
-//NOTE: most likely subclassing QThread is wrong
-class EngineThread : public QThread
+
+EngineInstance::EngineInstance(QObject *parent)
+    : QObject(parent)
 {
-protected:
-    void run();
-};
+    port = 0;
+}
 
-void EngineThread::run()
+EngineInstance::~EngineInstance()
+{
+}
+
+void EngineInstance::start()
 {
-    char *args[12];
-    args[0] = "1";      //cShowFPS
-    args[1] = "65000";  //ipcPort
-    args[2] = "1024";   //cScreenWidth
-    args[3] = "768";    //cScreenHeight
-    args[4] = "0";      //cReducedQuality
-    args[5] = "en.txt"; //cLocaleFName
-    args[6] = "koda";   //UserNick
-    args[7] = "1";      //SetSound
-    args[8] = "1";      //SetMusic
-    args[9] = "0";      //cAltDamage
-    args[10]= "../Resources/hedgewars/Data";   //cPathPrefix
-    args[11]= NULL;     //recordFileName
+#if 0
+    char *args[11];
+    args[0] = "65000";  //ipcPort
+    args[1] = "1024";   //cScreenWidth
+    args[2] = "768";    //cScreenHeight
+    args[3] = "0";      //cReducedQuality
+    args[4] = "en.txt"; //cLocaleFName
+    args[5] = "koda";   //UserNick
+    args[6] = "1";      //SetSound
+    args[7] = "1";      //SetMusic
+    args[8] = "0";      //cAltDamage
+    args[9]= datadir->absolutePath().toAscii().data(); //cPathPrefix
+    args[10]= NULL;     //recordFileName
     Game(args);
+#endif
+    GenLandPreview(port);
 }
+
 #endif
 
 QList<TCPBase*> srvsList;
@@ -66,6 +74,7 @@
 
     if (IPCSocket)
         IPCSocket->deleteLater();
+
 }
 
 TCPBase::TCPBase(bool demoMode, QObject *parent) :
@@ -90,11 +99,8 @@
             exit(0); // FIXME - should be graceful exit here (lower Critical -> Warning above when implemented)
         }
     }
-#ifdef HWLIBRARY
-    ipc_port=65000; //HACK
-#else
+
     ipc_port=IPCServer->serverPort();
-#endif
 }
 
 void TCPBase::NewConnection()
@@ -118,8 +124,17 @@
     IPCSocket = 0;
 
 #ifdef HWLIBRARY
-    EngineThread engineThread;// = new EngineThread(this);
-    engineThread.start();
+    QThread *thread = new QThread;
+    EngineInstance *instance = new EngineInstance;
+    instance->port = IPCServer->serverPort();
+
+    instance->moveToThread(thread);
+
+    connect(thread, SIGNAL(started()), instance, SLOT(start(void)));
+    connect(instance, SIGNAL(finished()), thread, SLOT(quit()));
+    connect(instance, SIGNAL(finished()), instance, SLOT(deleteLater()));
+    connect(instance, SIGNAL(finished()), thread, SLOT(deleteLater()));
+    thread->start();
 #else
     QProcess * process;
     process = new QProcess();
--- a/QTfrontend/net/tcpBase.h	Sun Dec 02 00:03:16 2012 +0100
+++ b/QTfrontend/net/tcpBase.h	Tue Dec 25 04:45:22 2012 +0100
@@ -81,4 +81,21 @@
         void tcpServerReady();
 };
 
+#ifdef HWLIBRARY
+class EngineInstance : public QObject
+{
+    Q_OBJECT
+public:
+    EngineInstance(QObject *parent = 0);
+    ~EngineInstance();
+
+    int port;
+public slots:
+    void start(void);
+signals:
+    void finished(void);
+private:
+};
+#endif
+
 #endif // _TCPBASE_INCLUDED
Binary file QTfrontend/res/NetworkPlayDisabled.png has changed
--- a/QTfrontend/res/css/christmas.css	Sun Dec 02 00:03:16 2012 +0100
+++ b/QTfrontend/res/css/christmas.css	Tue Dec 25 04:45:22 2012 +0100
@@ -21,7 +21,7 @@
 background-image: url(":/res/BackgroundChristmas.png");
 background-position: bottom center;
 background-repeat: repeat-x;
-background-color: #141250;
+background-color: #0c0f28;
 }
 
 * {
--- a/QTfrontend/res/css/qt.css	Sun Dec 02 00:03:16 2012 +0100
+++ b/QTfrontend/res/css/qt.css	Tue Dec 25 04:45:22 2012 +0100
@@ -105,7 +105,6 @@
 outline: none;
 }
 
-
 QHeaderView {
 border-radius: 0;
 border-width: 0;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/res/html/about.html	Tue Dec 25 04:45:22 2012 +0100
@@ -0,0 +1,94 @@
+<!DOCTYPE HTML>
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
+<head>
+<title>Hedgewars - Authors</title>
+<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
+<style type="text/css">
+     { color: #ffcc00; }
+</style>
+</head>
+<body>
+	<h2>Developers:</h2>
+	<p>
+        Engine, frontend, net server: Andrey Korotaev &lt;<a href="mailto:unC0Rr@gmail.com">unC0Rr@gmail.com</a>&gt;<br>
+        Many frontend improvements: Igor Ulyanov &lt;<a href="mailto:disinbox@gmail.com">disinbox@gmail.com</a>&gt;<br>
+        Many engine and frontend improvements: Derek Pomery &lt;<a href="mailto:nemo@m8y.org">nemo@m8y.org</a>&gt;<br>
+        Drill rocket, Ballgun, RC Plane weapons: Martin Boze &lt;<a href="mailto:afffect@gmail.com">afffect@gmail.com</a>&gt;<br>
+        Mine number and time game settings: David A. Cuadrado &lt;<a href="mailto:krawek@gmail.com">krawek@gmail.com</a>&gt;<br>
+        Frontend improvements: Martin Minarik &lt;<a href="mailto:ttsmj@pokec.sk">ttsmj@pokec.sk</a>&gt;<br>
+        Frontend improvements: Kristian Lehmann &lt;<a href="mailto:email@thexception.net">email@thexception.net</a>&gt;<br>
+        Mac OS X/iPhone port, OpenGL-ES conversion: Vittorio Giovara &lt;<a href="mailto:vittorio.giovara@gmail.com">vittorio.giovara@gmail.com</a>&gt;<br>
+        Many engine and frontend improvements (and bugs): Richard Karolyi &lt;<a href="mailto:sheepluva@ercatec.net">sheepluva@ercatec.net</a>&gt;<br>
+        Gamepad and Lua integration: Mario Liebisch &lt;<a href="mailto:mario.liebisch@gmail.com">mario.liebisch@gmail.com</a>&gt;<br>
+        Many engine improvements and graphics: Carlos Vives &lt;<a href="mailto:mail@carlosvives.es">mail@carlosvives.es</a>&gt;<br>
+        Maze maps: Henning K&uuml;hn &lt;<a href="mailto:prg@cooco.de">prg@cooco.de</a>&gt;<br>
+        Engine and frontend improvements: Henrik Rostedt &lt;<a href="mailto:henrik.rostedt@gmail.com">henrik.rostedt@gmail.com</a>&gt;<br>
+        Lua game modes and missions: John Lambert &lt;<a href="mailto:redgrinner@gmail.com">redgrinner@gmail.com</a>&gt;<br>
+        Frontend improvements: Mayur Pawashe &lt;<a href="mailto:zorgiepoo@gmail.com">zorgiepoo@gmail.com</a>&gt;<br>
+        Android port: Richard Deurwaarder &lt;<a href="mailto:xeli@xelification.com">xeli@xelification.com</a>&gt;<br>
+        Android netplay, portability abstraction: Simeon Maxein &lt;<a href="mailto:smaxein@googlemail.com">smaxein@googlemail.com</a>&gt;<br>
+        WebGL port, some pas2c and GLES2 work: Meng Xiangyun &lt;<a href="mailto:xymengxy@gmail.com">xymengxy@gmail.com</a>&gt;<br>
+        Video recording: Stepan Podoskin &lt;<a href="mailto:stepik-777@mail.ru">stepik-777@mail.ru</a>&gt;<br>
+        Campaign support, first campaign: Szabolcs Orb&agrave;n &lt;<a href="mailto:szabibibi@gmail.com">szabibibi@gmail.com</a>&gt;<br>
+        </p>
+        
+        <h2>Art:</h2>
+            <p>John Dum &lt;<a href="mailto:fizzy@gmail.com">fizzy@gmail.com</a>&gt;
+            <br>
+            Joshua Frese &lt;<a href="mailto:joshfrese@gmail.com">joshfrese@gmail.com</a>&gt;
+            <br>
+            Stanko Tadić &lt;<a href="mailto:stanko@mfhinc.net">stanko@mfhinc.net</a>&gt;
+            <br>
+            Julien Koesten &lt;<a href="mailto:julienkoesten@aol.com">julienkoesten@aol.com</a>&gt;
+            <br>
+            Joshua O'Sullivan &lt;<a href="mailto:coheedftw@hotmail.co.uk">coheedftw@hotmail.co.uk</a>&gt;
+            <br>
+            Nils Lück &lt;<a href="mailto:nils.luck.design@gmail.com">nils.luck.design@gmail.com</a>&gt;
+            <br>
+            Guillaume Englert &lt;<a href="mailto:genglert@hybird.org">genglert@hybird.org</a>&gt;
+            <br>
+            Hats: Trey Perry &lt;<a href="mailto:tx.perry.j@gmail.com">tx.perry.j@gmail.com</a>&gt;
+            </p>
+        
+        <h2>Sounds:</h2>
+        <p>
+        Hedgehogs voice: Stephen Alexander &lt;<a href="mailto:ArmagonNo1@gmail.com">ArmagonNo1@gmail.com</a>&gt;
+        <br>
+        John Dum &lt;<a href="mailto:fizzy@gmail.com">fizzy@gmail.com</a>&gt;
+        <br>
+        Jonatan Nilsson &lt;<a href="mailto:jonatanfan@gmail.com">jonatanfan@gmail.com</a>&gt;
+        <br>
+        Daniel Martin &lt;<a href="mailto:elhombresinremedio@gmail.com">elhombresinremedio@gmail.com</a>&gt;
+        </p>
+
+        <h2>Translations:</h2><p>
+            Brazilian Portuguese: Romulo Fernandes Machado &lt;<a href="mailto:abra185@gmail.com">abra185@gmail.com</a>&gt;<br>
+            Bulgarian: Svetoslav Stefanov<br>
+            Czech: Petr Řezáček &lt;<a href="mailto:rezacek@gmail.com">rezacek@gmail.com</a>&gt;<br>
+            Chinese: Jie Luo &lt;<a href="mailto:lililjlj@gmail.com">lililjlj@gmail.com</a>&gt;<br>
+            English: Andrey Korotaev &lt;<a href="mailto:unC0Rr@gmail.com">unC0Rr@gmail.com</a>&gt;<br>
+            Finnish: Nina Kuisma &lt;<a href="mailto:ninnnu@gmail.com">ninnnu@gmail.com</a>&gt;<br>
+            French: Antoine Turmel &lt;<a href="mailto:geekshadow@gmail.com">geekshadow@gmail.com</a>&gt;, Clement Woitrain &lt;<a href="mailto:sphrixclement@gmail.com">sphrixclement@gmail.com</a>&gt;<br>
+            German: Peter Hüwe &lt;<a href="mailto:PeterHuewe@gmx.de">PeterHuewe@gmx.de</a>&gt;, Mario Liebisch &lt;<a href="mailto:mario.liebisch@gmail.com">mario.liebisch@gmail.com</a>&gt;, Richard Karolyi &lt;<a href="mailto:sheepluva@ercatec.net">sheepluva@ercatec.net</a>&gt;<br>
+            Greek: &lt;<a href="mailto:talos_kriti@yahoo.gr">talos_kriti@yahoo.gr</a>&gt;<br>
+            Italian: Luca Bonora &lt;<a href="mailto:bonora.luca@gmail.com">bonora.luca@gmail.com</a>&gt;, Marco Bresciani<br>
+            Japanese: ADAM Etienne &lt;<a href="mailto:etienne.adam@gmail.com">etienne.adam@gmail.com</a>&gt;<br>
+            Korean: Anthony Bellew &lt;<a href="mailto:anthonyreflected@gmail.com">anthonyreflected@gmail.com</a>&gt;<br>
+            Lithuanian: Lukas Urbonas &lt;<a href="mailto:lukasu08@gmail.com">lukasu08@gmail.com</a>&gt;<br>
+            Polish: Maciej Mroziński &lt;<a href="mailto:mynick2@o2.pl">mynick2@o2.pl</a>&gt;, Wojciech Latkowski &lt;<a href="mailto:magik17l@gmail.com">magik17l@gmail.com</a>&gt;, Piotr Mitana, Maciej Górny<br>
+            Portuguese: Fábio Canário &lt;<a href="mailto:inufabie@gmail.com">inufabie@gmail.com</a>&gt;<br>
+            Russian: Andrey Korotaev &lt;<a href="mailto:unC0Rr@gmail.com">unC0Rr@gmail.com</a>&gt;<br>
+            Slovak: Jose Riha<br>
+            Spanish: Carlos Vives &lt;<a href="mailto:mail@carlosvives.es">mail@carlosvives.es</a>&gt;<br>
+            Swedish: Niklas Grahn &lt;<a href="mailto:raewolusjoon@yaoo.com">raewolusjoon@yaoo.com</a>&gt;, Henrik Rostedt &lt;<a href="mailto:henrik.rostedt@gmail.com">henrik.rostedt@gmail.com</a>&gt;<br>
+            Ukrainian: Eugene V. Lyubimkin &lt;<a href="mailto:jackyf.devel@gmail.com">jackyf.devel@gmail.com</a>&gt;, Igor Paliychuk &lt;<a href="mailto:mansonigor@gmail.com">mansonigor@gmail.com</a>&gt;, Eugene Sakara &lt;<a href="mailto:eresid@gmail.com">eresid@gmail.com</a>&gt;
+            </p>
+
+        <h2>Special thanks:</h2><p>
+        Aleksey Andreev &lt;<a href="mailto:blaknayabr@gmail.com">blaknayabr@gmail.com</a>&gt;<br>
+        Aleksander Rudalev &lt;<a href="mailto:alexv@pomorsu.ru">alexv@pomorsu.ru</a>&gt;<br>
+        Natasha Korotaeva &lt;<a href="mailto:layout@pisem.net">layout@pisem.net</a>&gt;<br>
+        Adam Higerd (aka ahigerd at FreeNode)
+        </p>
+</body>
+</html>
--- a/QTfrontend/team.cpp	Sun Dec 02 00:03:16 2012 +0100
+++ b/QTfrontend/team.cpp	Tue Dec 25 04:45:22 2012 +0100
@@ -169,7 +169,7 @@
 
 bool HWTeam::loadFromFile()
 {
-    QSettings teamfile(QString("physfs://config/Teams/%1.hwt").arg(m_name), QSettings::IniFormat, 0);
+    QSettings teamfile(QString("physfs://Teams/%1.hwt").arg(m_name), QSettings::IniFormat, 0);
     teamfile.setIniCodec("UTF-8");
     m_name = teamfile.value("Team/Name", m_name).toString();
     m_grave = teamfile.value("Team/Grave", "Statue").toString();
@@ -202,7 +202,7 @@
 
 bool HWTeam::fileExists()
 {
-    QFile f(QString("physfs://config/Teams/%1.hwt").arg(m_name));
+    QFile f(QString("physfs://Teams/%1.hwt").arg(m_name));
     return f.exists();
 }
 
@@ -210,7 +210,7 @@
 {
     if(m_isNetTeam)
         return false;
-    QFile cfgfile(QString("physfs://config/Teams/%1.hwt").arg(m_name));
+    QFile cfgfile(QString("physfs://Teams/%1.hwt").arg(m_name));
     cfgfile.remove();
     return true;
 }
@@ -219,11 +219,12 @@
 {
     if (OldTeamName != m_name)
     {
-        QFile cfgfile(QString("physfs://config/Teams/%1.hwt").arg(OldTeamName));
+        QFile cfgfile(QString("physfs://Teams/%1.hwt").arg(OldTeamName));
         cfgfile.remove();
         OldTeamName = m_name;
     }
-    QSettings teamfile(QString("physfs://config/Teams/%1.hwt").arg(m_name), QSettings::IniFormat, 0);
+
+    QSettings teamfile(QString("physfs://Teams/%1.hwt").arg(m_name), QSettings::IniFormat, 0);
     teamfile.setIniCodec("UTF-8");
     teamfile.setValue("Team/Name", m_name);
     teamfile.setValue("Team/Grave", m_grave);
@@ -234,6 +235,7 @@
     teamfile.setValue("Team/Rounds", m_rounds);
     teamfile.setValue("Team/Wins", m_wins);
     teamfile.setValue("Team/CampaignProgress", m_campaignProgress);
+
     for(int i = 0; i < HEDGEHOGS_PER_TEAM; i++)
     {
         QString hh = QString("Hedgehog%1/").arg(i);
@@ -251,6 +253,7 @@
             teamfile.setValue(QString("Achievements/%1").arg(achievements[i][0]), AchievementProgress[i]);
         else
             break;
+
     return true;
 }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/ui/dialog/bandialog.cpp	Tue Dec 25 04:45:22 2012 +0100
@@ -0,0 +1,87 @@
+#include <QFormLayout>
+#include <QComboBox>
+#include <QRadioButton>
+#include <QLineEdit>
+#include <QLabel>
+#include <QPushButton>
+#include <QHBoxLayout>
+#include <QMessageBox>
+
+#include "bandialog.h"
+
+BanDialog::BanDialog(QWidget *parent) :
+    QDialog(parent)
+{
+    QFormLayout * formLayout = new QFormLayout(this);
+
+    rbIP = new QRadioButton(this);
+    rbIP->setChecked(true);
+    rbNick = new QRadioButton(this);
+    leId = new QLineEdit(this);
+    leReason = new QLineEdit(this);
+    cbTime = new QComboBox(this);
+
+    cbTime->addItem(tr("10 minutes"), 5 * 60);
+    cbTime->addItem(tr("30 minutes"), 10 * 60);
+    cbTime->addItem(tr("1 hour"), 60 * 60);
+    cbTime->addItem(tr("3 hours"), 3 * 60 * 60);
+    cbTime->addItem(tr("5 hours"), 5 * 60 * 60);
+    cbTime->addItem(tr("24 hours"), 24 * 60 * 60);
+    cbTime->addItem(tr("3 days"), 72 * 60 * 60);
+    cbTime->addItem(tr("7 days"), 168 * 60 * 60);
+    cbTime->addItem(tr("14 days"), 336 * 60 * 60);
+    cbTime->addItem(tr("permanent"), 3650 * 24 * 60 * 60);
+    cbTime->setCurrentIndex(0);
+
+    formLayout->addRow(tr("IP"), rbIP);
+    formLayout->addRow(tr("Nick"), rbNick);
+    formLayout->addRow(tr("IP/Nick"), leId);
+    formLayout->addRow(tr("Reason"), leReason);
+    formLayout->addRow(tr("Duration"), cbTime);
+
+    formLayout->setLabelAlignment(Qt::AlignRight);
+
+    QHBoxLayout * hbox = new QHBoxLayout();
+    formLayout->addRow(hbox);
+    QPushButton * btnOk = new QPushButton(tr("Ok"), this);
+    QPushButton * btnCancel = new QPushButton(tr("Cancel"), this);
+    hbox->addStretch();
+    hbox->addWidget(btnOk);
+    hbox->addWidget(btnCancel);
+
+    connect(btnOk, SIGNAL(clicked()), this, SLOT(okClicked()));
+    connect(btnCancel, SIGNAL(clicked()), this, SLOT(reject()));
+
+    this->setWindowModality(Qt::WindowModal);
+}
+
+bool BanDialog::byIP()
+{
+    return rbIP->isChecked();
+}
+
+int BanDialog::duration()
+{
+    return cbTime->itemData(cbTime->currentIndex()).toInt();
+}
+
+QString BanDialog::banId()
+{
+    return leId->text();
+}
+
+QString BanDialog::reason()
+{
+    return leReason->text().isEmpty() ? tr("you know why") : leReason->text();
+}
+
+void BanDialog::okClicked()
+{
+    if(leId->text().isEmpty())
+    {
+        QMessageBox::warning(this, tr("Warning"), tr("Please, specify %1").arg(byIP() ? tr("IP") : tr("nickname")));
+        return;
+    }
+
+    accept();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/ui/dialog/bandialog.h	Tue Dec 25 04:45:22 2012 +0100
@@ -0,0 +1,32 @@
+#ifndef BANDIALOG_H
+#define BANDIALOG_H
+
+#include <QDialog>
+
+class QComboBox;
+class QRadioButton;
+class QLineEdit;
+
+class BanDialog : public QDialog
+{
+    Q_OBJECT
+public:
+    explicit BanDialog(QWidget *parent = 0);
+
+    bool byIP();
+    int duration();
+    QString banId();
+    QString reason();
+
+private:
+    QRadioButton * rbIP;
+    QRadioButton * rbNick;
+    QLineEdit * leId;
+    QLineEdit * leReason;
+    QComboBox * cbTime;
+
+private slots:
+    void okClicked();
+};
+
+#endif // BANDIALOG_H
--- a/QTfrontend/ui/dialog/input_password.cpp	Sun Dec 02 00:03:16 2012 +0100
+++ b/QTfrontend/ui/dialog/input_password.cpp	Tue Dec 25 04:45:22 2012 +0100
@@ -25,28 +25,44 @@
 
 #include "input_password.h"
 
-HWPasswordDialog::HWPasswordDialog(QWidget* parent, const QString & label) : QDialog(parent)
+HWPasswordDialog::HWPasswordDialog(QWidget* parent) : QDialog(parent)
 {
-    setWindowTitle(tr("Password"));
+    setWindowTitle(tr("Login"));
+
+    QString titleLabelText = "To connect to the server, please log in.\n\nIf you don't have an account on www.hedgewars.org,\njust enter your nickname.";
+    QString nickLabelText = "Nickname:";
+    QString passLabelText = "Password:";
 
     QGridLayout * layout = new QGridLayout(this);
 
-    QLabel * lbLabel = new QLabel(this);
-    lbLabel->setText(label);
-    layout->addWidget(lbLabel, 0, 0);
+    QLabel * titleLabel = new QLabel(this);
+    titleLabel->setText(titleLabelText);
+    layout->addWidget(titleLabel, 0, 0);
+
+    QLabel * nickLabel = new QLabel(this);
+    nickLabel->setText(nickLabelText);
+    layout->addWidget(nickLabel, 1, 0);
+
+    leNickname = new QLineEdit(this);
+    leNickname->setEchoMode(QLineEdit::Normal);
+    layout->addWidget(leNickname, 2, 0);
+
+    QLabel * passLabel = new QLabel(this);
+    passLabel->setText(passLabelText);
+    layout->addWidget(passLabel, 3, 0);
 
     lePassword = new QLineEdit(this);
     lePassword->setEchoMode(QLineEdit::Password);
-    layout->addWidget(lePassword, 1, 0);
+    layout->addWidget(lePassword, 4, 0);
 
     cbSave = new QCheckBox(this);
     cbSave->setText(QCheckBox::tr("Save password"));
-    layout->addWidget(cbSave, 2, 0);
+    layout->addWidget(cbSave, 5, 0);
 
     QDialogButtonBox* dbbButtons = new QDialogButtonBox(this);
     QPushButton * pbOK = dbbButtons->addButton(QDialogButtonBox::Ok);
     QPushButton * pbCancel = dbbButtons->addButton(QDialogButtonBox::Cancel);
-    layout->addWidget(dbbButtons, 3, 0);
+    layout->addWidget(dbbButtons, 6, 0);
 
     connect(pbOK, SIGNAL(clicked()), this, SLOT(accept()));
     connect(pbCancel, SIGNAL(clicked()), this, SLOT(reject()));
--- a/QTfrontend/ui/dialog/input_password.h	Sun Dec 02 00:03:16 2012 +0100
+++ b/QTfrontend/ui/dialog/input_password.h	Tue Dec 25 04:45:22 2012 +0100
@@ -28,9 +28,10 @@
 {
         Q_OBJECT
     public:
-        HWPasswordDialog(QWidget* parent, const QString & label);
+        HWPasswordDialog(QWidget* parent);
 
         QLineEdit* lePassword;
+        QLineEdit* leNickname;
         QCheckBox* cbSave;
 };
 
--- a/QTfrontend/ui/mouseoverfilter.cpp	Sun Dec 02 00:03:16 2012 +0100
+++ b/QTfrontend/ui/mouseoverfilter.cpp	Tue Dec 25 04:45:22 2012 +0100
@@ -39,7 +39,7 @@
         QComboBox * droplist = dynamic_cast<QComboBox*>(dist);
         QSlider * slider = dynamic_cast<QSlider*>(dist);
         QTabWidget * tab = dynamic_cast<QTabWidget*>(dist);
-        if (HWForm::config->isFrontendSoundEnabled() && (button || textfield || checkbox || droplist || slider || tab))
+        if (button || textfield || checkbox || droplist || slider || tab)
         {
             SDLInteraction::instance().playSoundFile("/Sounds/steps.ogg");
         }
--- a/QTfrontend/ui/page/AbstractPage.cpp	Sun Dec 02 00:03:16 2012 +0100
+++ b/QTfrontend/ui/page/AbstractPage.cpp	Tue Dec 25 04:45:22 2012 +0100
@@ -41,8 +41,9 @@
     QGridLayout * pageLayout = new QGridLayout(this);
 
     // stretch grid space for body and footer
-    pageLayout->setColumnStretch(0,0);
-    pageLayout->setColumnStretch(1,1);
+    pageLayout->setColumnStretch(0,1);
+    pageLayout->setColumnStretch(1,2);
+    pageLayout->setColumnStretch(2,1);
     pageLayout->setRowStretch(0,1);
     pageLayout->setRowStretch(1,0);
 
--- a/QTfrontend/ui/page/pageadmin.cpp	Sun Dec 02 00:03:16 2012 +0100
+++ b/QTfrontend/ui/page/pageadmin.cpp	Tue Dec 25 04:45:22 2012 +0100
@@ -22,56 +22,98 @@
 #include <QSpinBox>
 #include <QPushButton>
 #include <QTextBrowser>
+#include <QTableWidget>
+#include <QHeaderView>
 
 #include "pageadmin.h"
 #include "chatwidget.h"
+#include "bandialog.h"
 
 QLayout * PageAdmin::bodyLayoutDefinition()
 {
-    QGridLayout * pageLayout = new QGridLayout();
-
-    // 0
-    pbAsk = addButton(tr("Fetch data"), pageLayout, 0, 0, 1, 3);
+    QVBoxLayout * pageLayout = new QVBoxLayout();
 
-    // 1
-    QLabel * lblSMN = new QLabel(this);
-    lblSMN->setText(tr("Server message for latest version:"));
-    pageLayout->addWidget(lblSMN, 1, 0);
+    QTabWidget * tabs = new QTabWidget(this);
+    pageLayout->addWidget(tabs);
+    QWidget * page1 = new QWidget(this);
+    QWidget * page2 = new QWidget(this);
+    tabs->addTab(page1, tr("General"));
+    tabs->addTab(page2, tr("Bans"));
+
+    // page 1
+    {
+        QGridLayout * tab1Layout = new QGridLayout(page1);
+
+        // 0
+        pbAsk = addButton(tr("Fetch data"), tab1Layout, 0, 0, 1, 3);
 
-    leServerMessageNew = new QLineEdit(this);
-    pageLayout->addWidget(leServerMessageNew, 1, 1);
+        // 1
+        QLabel * lblSMN = new QLabel(this);
+        lblSMN->setText(tr("Server message for latest version:"));
+        tab1Layout->addWidget(lblSMN, 1, 0);
+
+        leServerMessageNew = new QLineEdit(this);
+        tab1Layout->addWidget(leServerMessageNew, 1, 1);
 
-    // 2
-    QLabel * lblSMO = new QLabel(this);
-    lblSMO->setText(tr("Server message for previous versions:"));
-    pageLayout->addWidget(lblSMO, 2, 0);
+        // 2
+        QLabel * lblSMO = new QLabel(this);
+        lblSMO->setText(tr("Server message for previous versions:"));
+        tab1Layout->addWidget(lblSMO, 2, 0);
+
+        leServerMessageOld = new QLineEdit(this);
+        tab1Layout->addWidget(leServerMessageOld, 2, 1);
 
-    leServerMessageOld = new QLineEdit(this);
-    pageLayout->addWidget(leServerMessageOld, 2, 1);
+        // 3
+        QLabel * lblP = new QLabel(this);
+        lblP->setText(tr("Latest version protocol number:"));
+        tab1Layout->addWidget(lblP, 3, 0);
+
+        sbProtocol = new QSpinBox(this);
+        tab1Layout->addWidget(sbProtocol, 3, 1);
 
-    // 3
-    QLabel * lblP = new QLabel(this);
-    lblP->setText(tr("Latest version protocol number:"));
-    pageLayout->addWidget(lblP, 3, 0);
+        // 4
+        QLabel * lblPreview = new QLabel(this);
+        lblPreview->setText(tr("MOTD preview:"));
+        tab1Layout->addWidget(lblPreview, 4, 0);
 
-    sbProtocol = new QSpinBox(this);
-    pageLayout->addWidget(sbProtocol, 3, 1);
+        tb = new QTextBrowser(this);
+        tb->setOpenExternalLinks(true);
+        tb->document()->setDefaultStyleSheet(HWChatWidget::styleSheet());
+        tab1Layout->addWidget(tb, 4, 1, 1, 2);
+
+        // 5
+        pbClearAccountsCache = addButton(tr("Clear Accounts Cache"), tab1Layout, 5, 0);
+
+        // 6
+        pbSetSM = addButton(tr("Set data"), tab1Layout, 6, 0, 1, 3);
+    }
 
-    // 4
-    QLabel * lblPreview = new QLabel(this);
-    lblPreview->setText(tr("MOTD preview:"));
-    pageLayout->addWidget(lblPreview, 4, 0);
+    // page 2
+    {
+        QGridLayout * tab2Layout = new QGridLayout(page2);
+        twBans = new QTableWidget(this);
+        twBans->setColumnCount(3);
+        twBans->setHorizontalHeaderLabels(QStringList()
+                              << tr("IP/Nick")
+                              << tr("Expiration")
+                              << tr("Reason")
+                    );
+        twBans->horizontalHeader()->setResizeMode(2, QHeaderView::Stretch);
+        twBans->setEditTriggers(QAbstractItemView::NoEditTriggers);
+        twBans->setSelectionBehavior(QAbstractItemView::SelectRows);
+        twBans->setSelectionMode(QAbstractItemView::SingleSelection);
+        twBans->setAlternatingRowColors(true);
+        tab2Layout->addWidget(twBans, 0, 1, 4, 1);
 
-    tb = new QTextBrowser(this);
-    tb->setOpenExternalLinks(true);
-    tb->document()->setDefaultStyleSheet(HWChatWidget::styleSheet());
-    pageLayout->addWidget(tb, 4, 1, 1, 2);
+        QPushButton * btnRefresh = addButton(tr("Refresh"), tab2Layout, 0, 0);
+        QPushButton * btnAdd = addButton(tr("Add"), tab2Layout, 1, 0);
+        QPushButton * btnRemove = addButton(tr("Remove"), tab2Layout, 2, 0);
 
-    // 5
-    pbClearAccountsCache = addButton(tr("Clear Accounts Cache"), pageLayout, 5, 0);
-
-    // 6
-    pbSetSM = addButton(tr("Set data"), pageLayout, 6, 0, 1, 3);
+        connect(btnRefresh, SIGNAL(clicked()), this, SIGNAL(bansListRequest()));
+        connect(btnRefresh, SIGNAL(clicked()), this, SLOT(onRefreshClicked()));
+        connect(btnAdd, SIGNAL(clicked()), this, SLOT(onAddClicked()));
+        connect(btnRemove, SIGNAL(clicked()), this, SLOT(onRemoveClicked()));
+    }
 
     return pageLayout;
 }
@@ -106,7 +148,64 @@
 {
     leServerMessageOld->setText(str);
 }
+
 void PageAdmin::protocol(int proto)
 {
     sbProtocol->setValue(proto);
 }
+
+void PageAdmin::onAddClicked()
+{
+    BanDialog dialog(this);
+
+    if(dialog.exec())
+    {
+        if(dialog.byIP())
+        {
+            emit banIP(dialog.banId(), dialog.reason(), dialog.duration());
+        } else
+        {
+            emit banNick(dialog.banId(), dialog.reason(), dialog.duration());
+        }
+
+        emit bansListRequest();
+    }
+}
+
+void PageAdmin::onRemoveClicked()
+{
+    QList<QTableWidgetItem *> sel = twBans->selectedItems();
+
+    if(sel.size())
+    {
+        emit removeBan(twBans->item(sel[0]->row(), 0)->data(Qt::DisplayRole).toString());
+        emit bansListRequest();
+    }
+}
+
+void PageAdmin::setBansList(const QStringList & bans)
+{
+    if(bans.size() % 4)
+        return;
+
+    twBans->setRowCount(bans.size() / 4);
+
+    for(int i = 0; i < bans.size(); i += 4)
+    {
+        if(!twBans->item(i / 4, 0))
+        {
+            twBans->setItem(i / 4, 0, new QTableWidgetItem());
+            twBans->setItem(i / 4, 1, new QTableWidgetItem());
+            twBans->setItem(i / 4, 2, new QTableWidgetItem());
+        }
+
+        twBans->item(i / 4, 0)->setData(Qt::DisplayRole, bans[i + 1]);
+        twBans->item(i / 4, 1)->setData(Qt::DisplayRole, bans[i + 3]);
+        twBans->item(i / 4, 2)->setData(Qt::DisplayRole, bans[i + 2]);
+    }
+}
+
+void PageAdmin::onRefreshClicked()
+{
+    twBans->setRowCount(0);
+}
--- a/QTfrontend/ui/page/pageadmin.h	Sun Dec 02 00:03:16 2012 +0100
+++ b/QTfrontend/ui/page/pageadmin.h	Tue Dec 25 04:45:22 2012 +0100
@@ -21,6 +21,8 @@
 
 #include "AbstractPage.h"
 
+class QTableWidget;
+
 class PageAdmin : public AbstractPage
 {
         Q_OBJECT
@@ -32,6 +34,7 @@
         void serverMessageNew(const QString & str);
         void serverMessageOld(const QString & str);
         void protocol(int proto);
+        void setBansList(const QStringList & bans);
 
     signals:
         void setServerMessageNew(const QString & str);
@@ -39,6 +42,10 @@
         void setProtocol(int proto);
         void askServerVars();
         void clearAccountsCache();
+        void bansListRequest();
+        void removeBan(const QString &);
+        void banIP(const QString & ip, const QString & reason, int seconds);
+        void banNick(const QString & nick, const QString & reason, int seconds);
 
     protected:
         QLayout * bodyLayoutDefinition();
@@ -52,9 +59,13 @@
         QSpinBox * sbProtocol;
         QTextBrowser * tb;
         QPushButton * pbClearAccountsCache;
+        QTableWidget * twBans;
 
     private slots:
         void smChanged();
+        void onAddClicked();
+        void onRemoveClicked();
+        void onRefreshClicked();
 };
 
 #endif
--- a/QTfrontend/ui/page/pagefeedback.cpp	Sun Dec 02 00:03:16 2012 +0100
+++ b/QTfrontend/ui/page/pagefeedback.cpp	Tue Dec 25 04:45:22 2012 +0100
@@ -20,6 +20,32 @@
 #include <QLineEdit>
 #include <QTextBrowser>
 #include <QLabel>
+#include <QHttp>
+#include <QSysInfo>
+#include <QDebug>
+#include <QBuffer>
+#include <QApplication>
+#include <QDesktopWidget>
+#include <QNetworkReply>
+#include <QProcess>
+#include <QMessageBox>
+#include <QCheckBox>
+
+#include <string>
+
+#ifdef Q_WS_WIN
+#define WINVER 0x0500
+#include <windows.h>
+#else
+#include <unistd.h>
+#include <sys/types.h>
+#endif
+
+#ifdef Q_WS_MAC
+#include <sys/sysctl.h>
+#endif
+
+#include <stdint.h>
 
 #include "pagefeedback.h"
 #include "hwconsts.h"
@@ -28,55 +54,347 @@
 {
     QVBoxLayout * pageLayout = new QVBoxLayout();
     QHBoxLayout * summaryLayout = new QHBoxLayout();
+    QHBoxLayout * emailLayout = new QHBoxLayout();
+    QHBoxLayout * descriptionLayout = new QHBoxLayout();
+    QHBoxLayout * combinedTopLayout = new QHBoxLayout();
+    QHBoxLayout * systemLayout = new QHBoxLayout();
 
     info = new QLabel();
     info->setText(
         "<style type=\"text/css\">"
-        "a { color: #ffcc00; }"
+        "a { color: #fc0; }"
+        "b { color: #0df; }"
         "</style>"
-        "<div align=\"center\"><h1>Please give us a feedback!</h1>"
-        "<h3>We are always happy about suggestions, ideas or bug reports.<h3>"
-        "<h4>The feedback will be posted as a new issue on our Google Code page.<h4>"
+        "<div align=\"center\"><h1>Please give us feedback!</h1>"
+        "<h3>We are always happy about suggestions, ideas, or bug reports.<h3>"
+        "<h4>Your email address is optional, but we may want to contact you.<h4>"
         "</div>"
     );
     pageLayout->addWidget(info);
 
+    QVBoxLayout * summaryEmailLayout = new QVBoxLayout();
+
+    const int labelWidth = 90;
+
+    label_email = new QLabel();
+    label_email->setText(QLabel::tr("Your Email"));
+    label_email->setFixedWidth(labelWidth);
+    emailLayout->addWidget(label_email);
+    email = new QLineEdit();
+    emailLayout->addWidget(email);
+    summaryEmailLayout->addLayout(emailLayout);
+
     label_summary = new QLabel();
-    label_summary->setText(QLabel::tr("Summary   "));
+    label_summary->setText(QLabel::tr("Summary"));
+    label_summary->setFixedWidth(labelWidth);
     summaryLayout->addWidget(label_summary);
     summary = new QLineEdit();
     summaryLayout->addWidget(summary);
-    pageLayout->addLayout(summaryLayout);
+    summaryEmailLayout->addLayout(summaryLayout);
+
+    combinedTopLayout->addLayout(summaryEmailLayout);
+
+
+    CheckSendSpecs = new QCheckBox();
+    CheckSendSpecs->setText(QLabel::tr("Send system information"));
+    CheckSendSpecs->setChecked(true);
+    systemLayout->addWidget(CheckSendSpecs);
+    BtnViewInfo = addButton("View", systemLayout, 1, false);
+    BtnViewInfo->setFixedSize(60, 30);
+    connect(BtnViewInfo, SIGNAL(clicked()), this, SLOT(ShowSpecs()));
+    combinedTopLayout->addLayout(systemLayout);
+
+    combinedTopLayout->setStretch(0, 1);
+    combinedTopLayout->insertSpacing(1, 20);
+
+    pageLayout->addLayout(combinedTopLayout);
 
     label_description = new QLabel();
     label_description->setText(QLabel::tr("Description"));
-    pageLayout->addWidget(label_description, 0, Qt::AlignHCenter);
+    label_description->setFixedWidth(labelWidth);
+    descriptionLayout->addWidget(label_description, 0, Qt::AlignTop);
     description = new QTextBrowser();
     description->setReadOnly(false);
-    pageLayout->addWidget(description);
+    descriptionLayout->addWidget(description);
+    pageLayout->addLayout(descriptionLayout);
 
     return pageLayout;
 }
 
+QNetworkAccessManager * PageFeedback::GetNetManager()
+{
+    if (netManager) return netManager;
+    netManager = new QNetworkAccessManager(this);
+    connect(netManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(NetReply(QNetworkReply*)));
+    return netManager;
+}
+
+void PageFeedback::LoadCaptchaImage()
+{
+        QNetworkAccessManager *netManager = GetNetManager();
+        QUrl captchaURL("http://hedgewars.org/feedback/?gencaptcha");
+        QNetworkRequest req(captchaURL);
+        genCaptchaRequest = netManager->get(req);
+}
+
+void PageFeedback::NetReply(QNetworkReply *reply)
+{
+    if (reply == genCaptchaRequest)
+    {
+        if (reply->error() != QNetworkReply::NoError)
+        {
+            qDebug() << "Error generating captcha image: " << reply->errorString();
+            ShowErrorMessage(QMessageBox::tr("Failed to generate captcha"));
+            return;
+        }
+
+        bool okay;
+        QByteArray body = reply->readAll();
+        captchaID = QString(body).toInt(&okay);
+
+        if (!okay)
+        {
+            qDebug() << "Failed to get captcha ID: " << body;
+            ShowErrorMessage(QMessageBox::tr("Failed to generate captcha"));
+            return;
+        }
+
+        QString url = "http://hedgewars.org/feedback/?captcha&id=";
+        url += QString::number(captchaID);
+
+        QNetworkAccessManager *netManager = GetNetManager();
+        QUrl captchaURL(url);
+        QNetworkRequest req(captchaURL);
+        captchaImageRequest = netManager->get(req);
+    }
+    else if (reply == captchaImageRequest)
+    {
+        if (reply->error() != QNetworkReply::NoError)
+        {
+            qDebug() << "Error loading captcha image: " << reply->errorString();
+            ShowErrorMessage(QMessageBox::tr("Failed to download captcha"));
+            return;
+        }
+
+        QByteArray imageData = reply->readAll();
+        QPixmap pixmap;
+        pixmap.loadFromData(imageData);
+        label_captcha->setPixmap(pixmap);
+        captcha_code->setText("");
+    }
+}
+
 QLayout * PageFeedback::footerLayoutDefinition()
 {
     QHBoxLayout * bottomLayout = new QHBoxLayout();
+    QHBoxLayout * captchaLayout = new QHBoxLayout();
+    QVBoxLayout * captchaInputLayout = new QVBoxLayout();
 
-    bottomLayout->setStretch(0,1);
+    label_captcha = new QLabel();
+    label_captcha->setStyleSheet("border: 3px solid #ffcc00; border-radius: 4px");
+    label_captcha->setText("<div style='width: 200px; height: 100px;'>loading<br>captcha</div>");
+    captchaLayout->addWidget(label_captcha);
+
+    label_captcha_input = new QLabel();
+    label_captcha_input->setText(QLabel::tr("Type the security code:"));
+    captchaInputLayout->addWidget(label_captcha_input);
+    captchaInputLayout->setAlignment(label_captcha, Qt::AlignBottom);
+    captcha_code = new QLineEdit();
+    captcha_code->setFixedSize(165, 30);
+    captchaInputLayout->addWidget(captcha_code);
+    captchaInputLayout->setAlignment(captcha_code, Qt::AlignTop);
+    captchaLayout->addLayout(captchaInputLayout);
+    captchaLayout->setAlignment(captchaInputLayout, Qt::AlignLeft);
+
+    captchaLayout->insertSpacing(-1, 40);
+    bottomLayout->addLayout(captchaLayout);
+
     //TODO: create logo for send button
-    BtnSend = addButton("Send", bottomLayout, 0, false);
-    bottomLayout->insertStretch(0);
+    BtnSend = addButton("Send Feedback", bottomLayout, 0, false);
+    BtnSend->setFixedSize(120, 40);
+
+    bottomLayout->setStretchFactor(captchaLayout, 0);
+    bottomLayout->setStretchFactor(BtnSend, 1);
 
     return bottomLayout;
 }
 
+void PageFeedback::GenerateSpecs()
+{
+    // Gather some information about the system and embed it into the report
+    QDesktopWidget* screen = QApplication::desktop();
+    QString os_version = "Operating system: ";
+    QString qt_version = QString("Qt version: ") + QT_VERSION_STR + QString("\n");
+    QString total_ram = "Total RAM: ";
+    QString number_of_cores = "Number of cores: ";
+    QString compiler_bits = "Compiler architecture: ";
+    QString compiler_version = "Compiler version: ";
+    QString kernel_line = "Kernel: ";
+    QString screen_size = "Size of the screen(s): " +
+        QString::number(screen->width()) + "x" + QString::number(screen->height()) + "\n";
+    QString number_of_screens = "Number of screens: " + QString::number(screen->screenCount()) + "\n";
+    std::string processor_name = "Processor: ";
+
+    // platform specific code
+#ifdef Q_WS_MACX
+    number_of_cores += QString::number(sysconf(_SC_NPROCESSORS_ONLN)) + "\n";
+
+    uint64_t memsize;
+    size_t len = sizeof(memsize);
+    static int mib_s[2] = { CTL_HW, HW_MEMSIZE };
+    if (sysctl (mib_s, 2, &memsize, &len, NULL, 0) == 0)
+        total_ram += QString::number(memsize/1024/1024) + " MB\n";
+    else
+        total_ram += "Error getting total RAM information\n";
+
+    int mib[] = {CTL_KERN, KERN_OSRELEASE};
+    sysctl(mib, sizeof mib / sizeof(int), NULL, &len, NULL, 0);
+
+    char *kernelVersion = (char *)malloc(sizeof(char)*len);
+    sysctl(mib, sizeof mib / sizeof(int), kernelVersion, &len, NULL, 0);
+
+    QString kernelVersionStr = QString(kernelVersion);
+    free(kernelVersion);
+    int major_version = kernelVersionStr.split(".").first().toUInt() - 4;
+    int minor_version = kernelVersionStr.split(".").at(1).toUInt();
+    os_version += QString("Mac OS X 10.%1.%2").arg(major_version).arg(minor_version) + " ";
+
+    switch(major_version)
+    {
+        case 4:  os_version += "\"Tiger\"\n"; break;
+        case 5:  os_version += "\"Leopard\"\n"; break;
+        case 6:  os_version += "\"Snow Leopard\"\n"; break;
+        case 7:  os_version += "\"Lion\"\n"; break;
+        case 8:  os_version += "\"Mountain Lion\"\n"; break;
+        default: os_version += "\"Unknown version\"\n"; break;
+    }
+#endif
+#ifdef Q_WS_WIN
+    SYSTEM_INFO sysinfo;
+    GetSystemInfo(&sysinfo);
+    number_of_cores += QString::number(sysinfo.dwNumberOfProcessors) + "\n";
+    MEMORYSTATUSEX status;
+    status.dwLength = sizeof(status);
+    GlobalMemoryStatusEx(&status);
+    total_ram += QString::number(status.ullTotalPhys);
+
+    switch(QSysInfo::WinVersion())
+    {
+        case QSysInfo::WV_2000: os_version += "Windows 2000\n"; break;
+        case QSysInfo::WV_XP: os_version += "Windows XP\n"; break;
+        case QSysInfo::WV_VISTA: os_version += "Windows Vista\n"; break;
+        case QSysInfo::WV_WINDOWS7: os_version += "Windows 7\n"; break;
+        default: os_version += "Windows (Unknown version)\n"; break;
+    }
+    kernel_line += "Windows kernel\n";
+#endif
+#ifdef Q_WS_X11
+    number_of_cores += QString::number(sysconf(_SC_NPROCESSORS_ONLN)) + "\n";
+    long pages = sysconf(_SC_PHYS_PAGES),
+#ifndef Q_OS_FREEBSD
+         available_pages = sysconf(_SC_AVPHYS_PAGES),
+#else
+         available_pages = 0,
+#endif
+         page_size = sysconf(_SC_PAGE_SIZE);
+    total_ram += QString::number(pages * page_size) + "\n";
+    os_version += "GNU/Linux or BSD\n";
+#endif
+
+    // uname -a
+#if defined(Q_WS_X11) || defined(Q_WS_MACX)
+    QProcess *process = new QProcess();
+    QStringList arguments = QStringList("-a");
+    process->start("uname", arguments);
+    if (process->waitForFinished())
+        kernel_line += QString(process->readAll());
+    delete process;
+#endif
+
+    // cpu info
+    quint32 registers[4];
+    quint32 i;
+
+    i = 0x80000002;
+    asm volatile
+      ("cpuid" : "=a" (registers[0]), "=b" (registers[1]), "=c" (registers[2]), "=d" (registers[3])
+       : "a" (i), "c" (0));
+    processor_name += std::string((const char *)&registers[0], 4);
+    processor_name += std::string((const char *)&registers[1], 4);
+    processor_name += std::string((const char *)&registers[2], 4);
+    processor_name += std::string((const char *)&registers[3], 4);
+    i = 0x80000003;
+    asm volatile
+      ("cpuid" : "=a" (registers[0]), "=b" (registers[1]), "=c" (registers[2]), "=d" (registers[3])
+       : "a" (i), "c" (0));
+    processor_name += std::string((const char *)&registers[0], 4);
+    processor_name += std::string((const char *)&registers[1], 4);
+    processor_name += std::string((const char *)&registers[2], 4);
+    processor_name += std::string((const char *)&registers[3], 4);
+    i = 0x80000004;
+    asm volatile
+      ("cpuid" : "=a" (registers[0]), "=b" (registers[1]), "=c" (registers[2]), "=d" (registers[3])
+       : "a" (i), "c" (0));
+    processor_name += std::string((const char *)&registers[0], 4);
+    processor_name += std::string((const char *)&registers[1], 4);
+    processor_name += std::string((const char *)&registers[2], 4);
+    processor_name += std::string((const char *)&registers[3], 3);
+
+    // compiler
+#ifdef __GNUC__
+    compiler_version += "GCC " + QString(__VERSION__) + "\n";
+#else
+    compiler_version += "Unknown\n";
+#endif
+
+    if(sizeof(void*) == 4)
+        compiler_bits += "i386\n";
+    else if(sizeof(void*) == 8)
+        compiler_bits += "x86_64\n";
+
+    // concat system info
+    specs = qt_version
+        + os_version
+        + total_ram
+        + screen_size
+        + number_of_screens
+        + QString::fromStdString(processor_name + "\n")
+        + number_of_cores
+        + compiler_version
+        + compiler_bits
+        + kernel_line;
+}
+
 void PageFeedback::connectSignals()
 {
     //TODO
 }
 
+void PageFeedback::ShowErrorMessage(const QString & msg)
+{
+    QMessageBox msgMsg(this);
+    msgMsg.setIcon(QMessageBox::Warning);
+    msgMsg.setWindowTitle(QMessageBox::tr("Hedgewars - Error"));
+    msgMsg.setText(msg);
+    msgMsg.setWindowModality(Qt::WindowModal);
+    msgMsg.exec();
+}
+
+void PageFeedback::ShowSpecs()
+{
+    QMessageBox msgMsg(this);
+    msgMsg.setIcon(QMessageBox::Information);
+    msgMsg.setWindowTitle(QMessageBox::tr("System Information Preview"));
+    msgMsg.setText(specs);
+    msgMsg.setTextFormat(Qt::PlainText);
+    msgMsg.setWindowModality(Qt::WindowModal);
+    msgMsg.setStyleSheet("background: #0A0533;");
+    msgMsg.exec();
+}
+
 PageFeedback::PageFeedback(QWidget* parent) : AbstractPage(parent)
 {
     initPage();
-
+    netManager = NULL;
+    GenerateSpecs();
 }
--- a/QTfrontend/ui/page/pagefeedback.h	Sun Dec 02 00:03:16 2012 +0100
+++ b/QTfrontend/ui/page/pagefeedback.h	Tue Dec 25 04:45:22 2012 +0100
@@ -21,24 +21,50 @@
 
 #include "AbstractPage.h"
 
+class QNetworkReply;
+class QNetworkAccessManager;
+
 class PageFeedback : public AbstractPage
 {
         Q_OBJECT
 
     public:
         PageFeedback(QWidget * parent = 0);
+        void EmbedSystemInfo();
+        void LoadCaptchaImage();
 
         QPushButton * BtnSend;
+        QPushButton * BtnViewInfo;
+        QCheckBox * CheckSendSpecs;
         QLineEdit * summary;
         QTextBrowser * description;
         QLabel * info;
         QLabel * label_summary;
         QLabel * label_description;
+        QLabel * label_captcha;
+        QLabel * label_email;
+        QLabel * label_captcha_input;
+        QLineEdit * captcha_code;
+        QLineEdit * email;
+        int captchaID;
+        QString specs;
+
+    private slots:
+
+        virtual void NetReply(QNetworkReply*);
+        virtual void ShowSpecs();
 
     private:
+        void GenerateSpecs();
         QLayout * bodyLayoutDefinition();
         QLayout * footerLayoutDefinition();
+        QNetworkAccessManager * GetNetManager();
+        void ShowErrorMessage(const QString & msg);
         void connectSignals();
+
+        QNetworkAccessManager * netManager;
+        QNetworkReply * captchaImageRequest;
+        QNetworkReply * genCaptchaRequest;
 };
 
 #endif
--- a/QTfrontend/ui/page/pagemain.cpp	Sun Dec 02 00:03:16 2012 +0100
+++ b/QTfrontend/ui/page/pagemain.cpp	Tue Dec 25 04:45:22 2012 +0100
@@ -46,10 +46,35 @@
     BtnSinglePlayer->setWhatsThis(tr("Play a game on a single computer"));
     pageLayout->setAlignment(BtnSinglePlayer, Qt::AlignHCenter);
 
+    //BtnNet = addButton(":/res/NetworkPlay.png", (QBoxLayout*)netLayout, 1, true);
     BtnNet = addButton(":/res/NetworkPlay.png", pageLayout, 2, 2, 1, 2, true);
     BtnNet->setToolTip(tr("Network Game"));
     BtnNet->setWhatsThis(tr("Play a game across a network"));
     pageLayout->setAlignment(BtnNet, Qt::AlignHCenter);
+    connect(BtnNet, SIGNAL(clicked()), this, SLOT(toggleNetworkChoice()));
+
+    originalNetworkIcon = BtnNet->icon();
+    disabledNetworkIcon = QIcon(":/res/NetworkPlayDisabled.png");
+
+    //QWidget *netLayoutWidget = new QWidget();
+    QVBoxLayout *netLayout = new QVBoxLayout(BtnNet);
+    //pageLayout->addWidget(netLayoutWidget, 2, 2, 1, 2);
+    //netLayoutWidget->setStyleSheet("background: green;");
+    //netLayoutWidget->setFixedSize(314, 260);
+    netLayout->setSpacing(20);
+    netLayout->setAlignment(Qt::AlignHCenter);
+
+    BtnNetLocal = addButton("Play local network game", (QBoxLayout*)netLayout, 0, false);
+    BtnNetLocal->setToolTip(tr("Play a local network game"));
+    BtnNetLocal->setWhatsThis(tr("Play a game across a local area network"));
+    BtnNetLocal->setFixedSize(BtnNet->width() - 50, 60);
+    BtnNetLocal->setVisible(false);
+
+    BtnNetOfficial = addButton("Play official network game", (QBoxLayout*)netLayout, 0, false);
+    BtnNetOfficial->setToolTip(tr("Play a network game"));
+    BtnNetOfficial->setWhatsThis(tr("Play a game on an official server"));
+    BtnNetOfficial->setFixedSize(BtnNet->width() - 50, 60);
+    BtnNetOfficial->setVisible(false);
 
     // button order matters for overlapping (what's on top and what isn't)
     BtnInfo = addButton(":/res/HedgewarsTitle.png", pageLayout, 0, 0, 1, 4, true);
@@ -59,10 +84,12 @@
     pageLayout->setAlignment(BtnInfo, Qt::AlignHCenter);
 
     BtnFeedback = addButton("Feedback", pageLayout, 4, 0, 1, 4, false);
+    BtnFeedback->setFixedSize(86, 27);
     BtnFeedback->setWhatsThis(tr("Leave a feedback here reporting issues, suggesting features or just saying how you like Hedgewars"));
     pageLayout->setAlignment(BtnFeedback, Qt::AlignHCenter);
 
     BtnDataDownload = addButton(tr("Downloadable Content"), pageLayout, 5, 0, 1, 4, false);
+    BtnDataDownload->setFixedSize(176, 27);
     //BtnDataDownload->setToolTip(tr(Downloadable Content"));
     BtnDataDownload->setWhatsThis(tr("Access the user created content downloadable from our website"));
     pageLayout->setAlignment(BtnDataDownload, Qt::AlignHCenter);
@@ -115,7 +142,7 @@
     }
     else
     {
-        setDefautDescription(QLabel::tr("This development build is 'work in progress' and may not be compatible with other versions of the game. Some features might be broken or incomplete. Use at your own risk!"));
+        setDefautDescription(QLabel::tr("This development build is 'work in progress' and may not be compatible with other versions of the game, while some features might be broken or incomplete!"));
     }
 
 }
@@ -182,3 +209,12 @@
 
     return Tips[QTime(0, 0, 0).secsTo(QTime::currentTime()) % Tips.length()];
 }
+
+void PageMain::toggleNetworkChoice()
+{
+    bool visible = BtnNetLocal->isVisible();
+    BtnNetLocal->setVisible(!visible);
+    BtnNetOfficial->setVisible(!visible);
+    if (visible)    BtnNet->setIcon(originalNetworkIcon);
+    else            BtnNet->setIcon(disabledNetworkIcon);
+}
--- a/QTfrontend/ui/page/pagemain.h	Sun Dec 02 00:03:16 2012 +0100
+++ b/QTfrontend/ui/page/pagemain.h	Tue Dec 25 04:45:22 2012 +0100
@@ -21,15 +21,19 @@
 
 #include "AbstractPage.h"
 
+class QIcon;
+
 class PageMain : public AbstractPage
 {
-        Q_OBJECT
+    Q_OBJECT
 
     public:
         PageMain(QWidget * parent = 0);
 
         QPushButton * BtnSinglePlayer;
         QPushButton * BtnNet;
+        QPushButton * BtnNetLocal;
+        QPushButton * BtnNetOfficial;
         QPushButton * BtnSetup;
         QPushButton * BtnFeedback;
         QPushButton * BtnInfo;
@@ -41,8 +45,12 @@
         QLayout * bodyLayoutDefinition();
         QLayout * footerLayoutDefinition();
         void connectSignals();
+        QIcon originalNetworkIcon, disabledNetworkIcon;
 
         QString randomTip() const;
+
+    private slots:
+        void toggleNetworkChoice();
 };
 
 #endif
--- a/QTfrontend/ui/page/pagenetgame.cpp	Sun Dec 02 00:03:16 2012 +0100
+++ b/QTfrontend/ui/page/pagenetgame.cpp	Tue Dec 25 04:45:22 2012 +0100
@@ -37,10 +37,10 @@
     pageLayout->setColumnStretch(1, 50);
 
     // chatwidget
-    pChatWidget = new HWChatWidget(this, m_gameSettings, true);
-    pChatWidget->setShowFollow(false); // don't show follow in nicks' context menus
-    pChatWidget->setIgnoreListKick(true); // kick ignored players automatically
-    pageLayout->addWidget(pChatWidget, 2, 0, 1, 2);
+    chatWidget = new HWChatWidget(this, true);
+    chatWidget->setShowFollow(false); // don't show follow in nicks' context menus
+    chatWidget->setIgnoreListKick(true); // kick ignored players automatically
+    pageLayout->addWidget(chatWidget, 2, 0, 1, 2);
     pageLayout->setRowStretch(1, 100);
     pageLayout->setRowStretch(2, 100);
 
@@ -96,10 +96,8 @@
     connect(BtnUpdate, SIGNAL(clicked()), this, SLOT(onUpdateClick()));
 }
 
-PageNetGame::PageNetGame(QWidget* parent, QSettings * gameSettings) : AbstractPage(parent)
+PageNetGame::PageNetGame(QWidget* parent) : AbstractPage(parent)
 {
-    m_gameSettings = gameSettings;
-
     initPage();
 
     QMenu * menu = new QMenu(BtnMaster);
@@ -113,24 +111,23 @@
     menu->addAction(restrictTeamAdds);
 
     BtnMaster->setMenu(menu);
-
 }
 
 
 void PageNetGame::displayError(const QString & message)
 {
-    pChatWidget->displayError(message);
+    chatWidget->displayError(message);
 }
 
 
 void PageNetGame::displayNotice(const QString & message)
 {
-    pChatWidget->displayNotice(message);
+    chatWidget->displayNotice(message);
 }
 
 void PageNetGame::displayWarning(const QString & message)
 {
-    pChatWidget->displayWarning(message);
+    chatWidget->displayWarning(message);
 }
 
 
@@ -178,5 +175,5 @@
 
 void PageNetGame::setUser(const QString & nickname)
 {
-    pChatWidget->setUser(nickname);
+    chatWidget->setUser(nickname);
 }
--- a/QTfrontend/ui/page/pagenetgame.h	Sun Dec 02 00:03:16 2012 +0100
+++ b/QTfrontend/ui/page/pagenetgame.h	Tue Dec 25 04:45:22 2012 +0100
@@ -32,7 +32,7 @@
         Q_OBJECT
 
     public:
-        PageNetGame(QWidget* parent, QSettings * gameSettings);
+        PageNetGame(QWidget* parent);
 
         /**
          * Sets the room name to display.
@@ -52,7 +52,7 @@
         QAction * restrictJoins;
         QAction * restrictTeamAdds;
 
-        HWChatWidget* pChatWidget;
+        HWChatWidget* chatWidget;
 
         TeamSelWidget* pNetTeamsWidget;
         GameCFGWidget* pGameCFG;
@@ -72,8 +72,6 @@
         QLayout * footerLayoutDefinition();
         void connectSignals();
 
-        QSettings * m_gameSettings;
-
         HistoryLineEdit * leRoomName;
         QPushButton * btnSetup;
 };
--- a/QTfrontend/ui/page/pagenettype.cpp	Sun Dec 02 00:03:16 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-/*
- * Hedgewars, a free turn based strategy game
- * Copyright (c) 2004-2012 Andrey Korotaev <unC0Rr@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-
-#include <QGridLayout>
-#include <QPushButton>
-
-#include "pagenettype.h"
-
-
-QLayout * PageNetType::bodyLayoutDefinition()
-{
-    QGridLayout * pageLayout = new QGridLayout();
-    pageLayout->setRowStretch(0, 10);
-    pageLayout->setRowStretch(3, 10);
-
-    pageLayout->setColumnStretch(1, 10);
-    pageLayout->setColumnStretch(2, 20);
-    pageLayout->setColumnStretch(3, 10);
-
-    BtnLAN = addButton(tr("LAN game"), pageLayout, 1, 2);
-    BtnLAN->setWhatsThis(tr("Join or host your own game server in a Local Area Network."));
-    BtnOfficialServer = addButton(tr("Official server"), pageLayout, 2, 2);
-    BtnOfficialServer->setWhatsThis(tr("Join hundreds of players online!"));
-
-    // hack: temporary deactivated - requires server modifications that aren't backward compatible (yet)
-    //BtnOfficialServer->setEnabled(false);
-
-    return pageLayout;
-}
-
-PageNetType::PageNetType(QWidget* parent) : AbstractPage(parent)
-{
-    initPage();
-}
--- a/QTfrontend/ui/page/pagenettype.h	Sun Dec 02 00:03:16 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,38 +0,0 @@
-/*
- * Hedgewars, a free turn based strategy game
- * Copyright (c) 2004-2012 Andrey Korotaev <unC0Rr@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-
-#ifndef PAGE_NETTYPE_H
-#define PAGE_NETTYPE_H
-
-#include "AbstractPage.h"
-
-class PageNetType : public AbstractPage
-{
-        Q_OBJECT
-
-    public:
-        PageNetType(QWidget* parent = 0);
-
-        QPushButton * BtnLAN;
-        QPushButton * BtnOfficialServer;
-
-    protected:
-        QLayout * bodyLayoutDefinition();
-};
-
-#endif
--- a/QTfrontend/ui/page/pageoptions.cpp	Sun Dec 02 00:03:16 2012 +0100
+++ b/QTfrontend/ui/page/pageoptions.cpp	Tue Dec 25 04:45:22 2012 +0100
@@ -33,10 +33,19 @@
 #include <QStandardItemModel>
 
 #include "pageoptions.h"
+#include "gameuiconfig.h"
 #include "hwconsts.h"
 #include "fpsedit.h"
 #include "igbox.h"
 #include "DataManager.h"
+#include "LibavInteraction.h"
+#include "AutoUpdater.h"
+
+#ifdef __APPLE__
+#ifdef SPARKLE_ENABLED
+#include "SparkleAutoUpdater.h"
+#endif
+#endif
 
 // TODO cleanup
 QLayout * PageOptions::bodyLayoutDefinition()
@@ -50,6 +59,11 @@
     tabs->addTab(page1, tr("General"));
     tabs->addTab(page2, tr("Advanced"));
 
+#ifdef VIDEOREC
+    QWidget * page3 = new QWidget(this);
+    tabs->addTab(page3, tr("Video Recording"));
+#endif
+
     { // page 1
         QGridLayout * page1Layout = new QGridLayout(page1);
         //gbTBLayout->setMargin(0);
@@ -191,11 +205,7 @@
 
             // List of installed languages
             CBLanguage = new QComboBox(groupMisc);
-            QDir tmpdir;
-            tmpdir.cd(cfgdir->absolutePath());
-            tmpdir.cd("Data/Locale");
-            tmpdir.setFilter(QDir::Files);
-            QStringList locs = tmpdir.entryList(QStringList("hedgewars_*.qm"));
+            QStringList locs = DataManager::instance().entryList("Locale", QDir::Files, QStringList("hedgewars_*.qm"));
             CBLanguage->addItem(QComboBox::tr("(System default)"), QString(""));
             for(int i = 0; i < locs.count(); i++)
             {
@@ -203,17 +213,6 @@
                 CBLanguage->addItem(QLocale::languageToString(loc.language()) + " (" + QLocale::countryToString(loc.country()) + ")", loc.name());
             }
 
-            tmpdir.cd(datadir->absolutePath());
-            tmpdir.cd("Locale");
-            tmpdir.setFilter(QDir::Files);
-            QStringList tmplist = tmpdir.entryList(QStringList("hedgewars_*.qm"));
-            for(int i = 0; i < tmplist.count(); i++)
-            {
-                if (locs.contains(tmplist[i])) continue;
-                QLocale loc(tmplist[i].replace(QRegExp("hedgewars_(.*)\\.qm"), "\\1"));
-                CBLanguage->addItem(QLocale::languageToString(loc.language()) + " (" + QLocale::countryToString(loc.country()) + ")", loc.name());
-            }
-
             MiscLayout->addWidget(CBLanguage, 0, 1);
 
             // Label and field for net nick
@@ -239,7 +238,14 @@
     #ifdef SPARKLE_ENABLED
             CBAutoUpdate = new QCheckBox(groupMisc);
             CBAutoUpdate->setText(QCheckBox::tr("Check for updates at startup"));
-            MiscLayout->addWidget(CBAutoUpdate, 7, 0, 1, 3);
+            MiscLayout->addWidget(CBAutoUpdate, 7, 0, 1, 1);
+
+            btnUpdateNow = new QPushButton(groupMisc);
+            connect(btnUpdateNow, SIGNAL(clicked()), this, SLOT(checkForUpdates()));
+            btnUpdateNow->setToolTip(tr("Check for updates"));
+            btnUpdateNow->setText("Check now");
+            btnUpdateNow->setFixedSize(130, 30);
+            MiscLayout->addWidget(btnUpdateNow, 7, 1, 1, 1);
     #endif
     #endif
             page1Layout->addWidget(groupMisc, 2, 0);
@@ -253,25 +259,33 @@
             AGGroupBox->setTitle(QGroupBox::tr("Audio/Graphic options"));
 
             QVBoxLayout * GBAlayout = new QVBoxLayout(AGGroupBox);
+            QGridLayout * GBAfrontendlayout = new QGridLayout(0);
             QHBoxLayout * GBAreslayout = new QHBoxLayout(0);
             QHBoxLayout * GBAstereolayout = new QHBoxLayout(0);
             QHBoxLayout * GBAqualayout = new QHBoxLayout(0);
 
+            QLabel * frontend = new QLabel(AGGroupBox);
+            frontend->setText(QLabel::tr("Frontend"));
+            frontend->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+            GBAfrontendlayout->addWidget(frontend, 0, 0, 1, 2);
+
             CBFrontendFullscreen = new QCheckBox(AGGroupBox);
-            CBFrontendFullscreen->setText(QCheckBox::tr("Frontend fullscreen"));
-            GBAlayout->addWidget(CBFrontendFullscreen);
+            CBFrontendFullscreen->setText(QCheckBox::tr("Fullscreen"));
+            GBAfrontendlayout->addWidget(CBFrontendFullscreen, 1, 0);
 
             CBFrontendEffects = new QCheckBox(AGGroupBox);
-            CBFrontendEffects->setText(QCheckBox::tr("Frontend effects"));
-            GBAlayout->addWidget(CBFrontendEffects);
+            CBFrontendEffects->setText(QCheckBox::tr("Visual effects"));
+            GBAfrontendlayout->addWidget(CBFrontendEffects, 2, 0);
 
-            CBEnableFrontendSound = new QCheckBox(AGGroupBox);
-            CBEnableFrontendSound->setText(QCheckBox::tr("Enable frontend sounds"));
-            GBAlayout->addWidget(CBEnableFrontendSound);
+            CBFrontendSound = new QCheckBox(AGGroupBox);
+            CBFrontendSound->setText(QCheckBox::tr("Sound"));
+            GBAfrontendlayout->addWidget(CBFrontendSound, 1, 1);
 
-            CBEnableFrontendMusic = new QCheckBox(AGGroupBox);
-            CBEnableFrontendMusic->setText(QCheckBox::tr("Enable frontend music"));
-            GBAlayout->addWidget(CBEnableFrontendMusic);
+            CBFrontendMusic = new QCheckBox(AGGroupBox);
+            CBFrontendMusic->setText(QCheckBox::tr("Music"));
+            GBAfrontendlayout->addWidget(CBFrontendMusic, 2, 1);
+
+            GBAlayout->addLayout(GBAfrontendlayout);
 
             QFrame * hr = new QFrame(AGGroupBox);
             hr->setFrameStyle(QFrame::HLine);
@@ -345,13 +359,15 @@
             volumeBox->setSingleStep(5);
             GBAvollayout->addWidget(volumeBox, 0, 2);
 
-            CBEnableSound = new QCheckBox(AGGroupBox);
-            CBEnableSound->setText(QCheckBox::tr("Enable sound"));
-            GBAvollayout->addWidget(CBEnableSound, 1, 0, 1, 1);
+            CBSound = new QCheckBox(AGGroupBox);
+            CBSound->setText(QCheckBox::tr("Sound"));
+            CBSound->setWhatsThis(QCheckBox::tr("In-game sound effects"));
+            GBAvollayout->addWidget(CBSound, 1, 0);
 
-            CBEnableMusic = new QCheckBox(AGGroupBox);
-            CBEnableMusic->setText(QCheckBox::tr("Enable music"));
-            GBAvollayout->addWidget(CBEnableMusic, 1, 1, 1, 2);
+            CBMusic = new QCheckBox(AGGroupBox);
+            CBMusic->setText(QCheckBox::tr("Music"));
+            CBMusic->setWhatsThis(QCheckBox::tr("In-game music"));
+            GBAvollayout->addWidget(CBMusic, 1, 1, 1, 2);
 
             GBAvollayout->setSizeConstraint(QLayout::SetMinimumSize);
 
@@ -492,6 +508,121 @@
 
         page2Layout->addWidget(new QWidget(this), 2, 0);
     }
+#ifdef VIDEOREC
+    { // page 3
+        QGridLayout * page3Layout = new QGridLayout(page3);
+
+        IconedGroupBox* pOptionsGroup = new IconedGroupBox(this);
+        pOptionsGroup->setIcon(QIcon(":/res/Settings.png")); // FIXME
+        pOptionsGroup->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+        pOptionsGroup->setTitle(QGroupBox::tr("Video recording options"));
+        QGridLayout * pOptLayout = new QGridLayout(pOptionsGroup);
+
+        // label for format
+        QLabel *labelFormat = new QLabel(pOptionsGroup);
+        labelFormat->setText(QLabel::tr("Format"));
+        pOptLayout->addWidget(labelFormat, 0, 0);
+
+        // list of supported formats
+        comboAVFormats = new QComboBox(pOptionsGroup);
+        pOptLayout->addWidget(comboAVFormats, 0, 1, 1, 4);
+        LibavInteraction::instance().fillFormats(comboAVFormats);
+
+        // separator
+        QFrame * hr = new QFrame(pOptionsGroup);
+        hr->setFrameStyle(QFrame::HLine);
+        hr->setLineWidth(3);
+        hr->setFixedHeight(10);
+        pOptLayout->addWidget(hr, 1, 0, 1, 5);
+
+        // label for audio codec
+        QLabel *labelACodec = new QLabel(pOptionsGroup);
+        labelACodec->setText(QLabel::tr("Audio codec"));
+        pOptLayout->addWidget(labelACodec, 2, 0);
+
+        // list of supported audio codecs
+        comboAudioCodecs = new QComboBox(pOptionsGroup);
+        pOptLayout->addWidget(comboAudioCodecs, 2, 1, 1, 3);
+
+        // checkbox 'record audio'
+        checkRecordAudio = new QCheckBox(pOptionsGroup);
+        checkRecordAudio->setText(QCheckBox::tr("Record audio"));
+        pOptLayout->addWidget(checkRecordAudio, 2, 4);
+
+        // separator
+        hr = new QFrame(pOptionsGroup);
+        hr->setFrameStyle(QFrame::HLine);
+        hr->setLineWidth(3);
+        hr->setFixedHeight(10);
+        pOptLayout->addWidget(hr, 3, 0, 1, 5);
+
+        // label for video codec
+        QLabel *labelVCodec = new QLabel(pOptionsGroup);
+        labelVCodec->setText(QLabel::tr("Video codec"));
+        pOptLayout->addWidget(labelVCodec, 4, 0);
+
+        // list of supported video codecs
+        comboVideoCodecs = new QComboBox(pOptionsGroup);
+        pOptLayout->addWidget(comboVideoCodecs, 4, 1, 1, 4);
+
+        // label for resolution
+        QLabel *labelRes = new QLabel(pOptionsGroup);
+        labelRes->setText(QLabel::tr("Resolution"));
+        pOptLayout->addWidget(labelRes, 5, 0);
+
+        // width
+        widthEdit = new QLineEdit(pOptionsGroup);
+        widthEdit->setValidator(new QIntValidator(this));
+        pOptLayout->addWidget(widthEdit, 5, 1);
+
+        // x
+        QLabel *labelX = new QLabel(pOptionsGroup);
+        labelX->setText("X");
+        pOptLayout->addWidget(labelX, 5, 2);
+
+        // height
+        heightEdit = new QLineEdit(pOptionsGroup);
+        heightEdit->setValidator(new QIntValidator(pOptionsGroup));
+        pOptLayout->addWidget(heightEdit, 5, 3);
+
+        // checkbox 'use game resolution'
+        checkUseGameRes = new QCheckBox(pOptionsGroup);
+        checkUseGameRes->setText(QCheckBox::tr("Use game resolution"));
+        pOptLayout->addWidget(checkUseGameRes, 5, 4);
+
+        // label for framerate
+        QLabel *labelFramerate = new QLabel(pOptionsGroup);
+        labelFramerate->setText(QLabel::tr("Framerate"));
+        pOptLayout->addWidget(labelFramerate, 6, 0);
+
+        framerateBox = new QComboBox(pOptionsGroup);
+        framerateBox->addItem("24 fps", 24);
+        framerateBox->addItem("25 fps", 25);
+        framerateBox->addItem("30 fps", 30);
+        framerateBox->addItem("50 fps", 50);
+        framerateBox->addItem("60 fps", 60);
+        pOptLayout->addWidget(framerateBox, 6, 1);
+
+        // label for Bitrate
+        QLabel *labelBitrate = new QLabel(pOptionsGroup);
+        labelBitrate->setText(QLabel::tr("Bitrate (Kbps)"));
+        pOptLayout->addWidget(labelBitrate, 6, 2);
+
+        // bitrate
+        bitrateBox = new QSpinBox(pOptionsGroup);
+        bitrateBox->setRange(100, 5000);
+        bitrateBox->setSingleStep(100);
+        pOptLayout->addWidget(bitrateBox, 6, 3);
+
+        // button 'set default options'
+        btnDefaults = new QPushButton(pOptionsGroup);
+        btnDefaults->setText(QPushButton::tr("Set default options"));
+        btnDefaults->setWhatsThis(QPushButton::tr("Restore default coding parameters"));
+        pOptLayout->addWidget(btnDefaults, 7, 0, 1, 5);
+
+        page3Layout->addWidget(pOptionsGroup, 1, 0);
+    }
+#endif
 
     previousQuality = this->SLQuality->value();
     previousResolutionIndex = this->CBResolution->currentIndex();
@@ -507,6 +638,13 @@
 
 void PageOptions::connectSignals()
 {
+#ifdef VIDEOREC
+    connect(checkUseGameRes, SIGNAL(stateChanged(int)), this, SLOT(changeUseGameRes(int)));
+    connect(checkRecordAudio, SIGNAL(stateChanged(int)), this, SLOT(changeRecordAudio(int)));
+    connect(comboAVFormats, SIGNAL(currentIndexChanged(int)), this, SLOT(changeAVFormat(int)));
+    connect(btnDefaults, SIGNAL(clicked()), this, SLOT(setDefaultOptions()));
+#endif
+
     connect(SLQuality, SIGNAL(valueChanged(int)), this, SLOT(setQuality(int)));
     connect(CBResolution, SIGNAL(currentIndexChanged(int)), this, SLOT(setResolution(int)));
     connect(CBFullscreen, SIGNAL(stateChanged(int)), this, SLOT(setFullscreen(int)));
@@ -515,7 +653,7 @@
     connect(CBSavePassword, SIGNAL(stateChanged(int)), this, SLOT(savePwdChanged(int)));
 }
 
-PageOptions::PageOptions(QWidget* parent) : AbstractPage(parent)
+PageOptions::PageOptions(QWidget* parent) : AbstractPage(parent), config(0)
 {
     initPage();
 }
@@ -634,3 +772,145 @@
     leProxyLogin->setEnabled(b);
     leProxyPassword->setEnabled(b);
 }
+
+// Video Recording
+
+void PageOptions::setConfig(GameUIConfig * config)
+{
+    this->config = config;
+}
+
+// user changed file format, we need to update list of codecs
+void PageOptions::changeAVFormat(int index)
+{
+    // remember selected codecs
+    QString prevVCodec = videoCodec();
+    QString prevACodec = audioCodec();
+
+    // clear lists of codecs
+    comboVideoCodecs->clear();
+    comboAudioCodecs->clear();
+
+    // get list of codecs for specified format
+    LibavInteraction::instance().fillCodecs(comboAVFormats->itemData(index).toString(), comboVideoCodecs, comboAudioCodecs);
+
+    // disable audio if there is no audio codec
+    if (comboAudioCodecs->count() == 0)
+    {
+        checkRecordAudio->setChecked(false);
+        checkRecordAudio->setEnabled(false);
+    }
+    else
+        checkRecordAudio->setEnabled(true);
+
+    // restore selected codecs if possible
+    int iVCodec = comboVideoCodecs->findData(prevVCodec);
+    if (iVCodec != -1)
+        comboVideoCodecs->setCurrentIndex(iVCodec);
+    int iACodec = comboAudioCodecs->findData(prevACodec);
+    if (iACodec != -1)
+        comboAudioCodecs->setCurrentIndex(iACodec);
+}
+
+// user switched checkbox 'use game resolution'
+void PageOptions::changeUseGameRes(int state)
+{
+    if (state && config)
+    {
+        // set resolution to game resolution
+        QRect resolution = config->vid_Resolution();
+        widthEdit->setText(QString::number(resolution.width()));
+        heightEdit->setText(QString::number(resolution.height()));
+    }
+    widthEdit->setEnabled(!state);
+    heightEdit->setEnabled(!state);
+}
+
+// user switched checkbox 'record audio'
+void PageOptions::changeRecordAudio(int state)
+{
+    comboAudioCodecs->setEnabled(!!state);
+}
+
+void PageOptions::setDefaultCodecs()
+{
+    // VLC should be able to handle any of these configurations
+    // Quicktime X only opens the first one
+    // Windows Media Player TODO
+    if (tryCodecs("mp4", "libx264", "aac"))
+        return;
+    if (tryCodecs("mp4", "libx264", "libfaac"))
+        return;
+    if (tryCodecs("mp4", "libx264", "libmp3lame"))
+        return;
+    if (tryCodecs("mp4", "libx264", "mp2"))
+        return;
+    if (tryCodecs("avi", "libxvid", "libmp3lame"))
+        return;
+    if (tryCodecs("avi", "libxvid", "ac3_fixed"))
+        return;
+    if (tryCodecs("avi", "libxvid", "mp2"))
+        return;
+    if (tryCodecs("avi", "mpeg4", "libmp3lame"))
+        return;
+    if (tryCodecs("avi", "mpeg4", "ac3_fixed"))
+        return;
+    if (tryCodecs("avi", "mpeg4", "mp2"))
+        return;
+
+    // this shouldn't happen, just in case
+    if (tryCodecs("ogg", "libtheora", "libvorbis"))
+        return;
+    tryCodecs("ogg", "libtheora", "flac");
+}
+
+void PageOptions::setDefaultOptions()
+{
+    framerateBox->setCurrentIndex(2);
+    bitrateBox->setValue(1000);
+    checkRecordAudio->setChecked(true);
+    checkUseGameRes->setChecked(true);
+    setDefaultCodecs();
+}
+
+void PageOptions::checkForUpdates()
+{
+    AutoUpdater *updater = NULL;
+
+#ifdef __APPLE__
+#ifdef SPARKLE_ENABLED
+    updater = new SparkleAutoUpdater();
+#endif
+#endif
+
+    if (updater)
+    {
+        updater->checkForUpdatesNow();
+        delete updater;
+    }
+}
+
+bool PageOptions::tryCodecs(const QString & format, const QString & vcodec, const QString & acodec)
+{
+    // first we should change format
+    int iFormat = comboAVFormats->findData(format);
+    if (iFormat == -1)
+        return false;
+    comboAVFormats->setCurrentIndex(iFormat);
+    // format was changed, so lists of codecs were automatically updated to codecs supported by this format
+
+    // try to find video codec
+    int iVCodec = comboVideoCodecs->findData(vcodec);
+    if (iVCodec == -1)
+        return false;
+    comboVideoCodecs->setCurrentIndex(iVCodec);
+
+    // try to find audio codec
+    int iACodec = comboAudioCodecs->findData(acodec);
+    if (iACodec == -1 && checkRecordAudio->isChecked())
+        return false;
+    if (iACodec != -1)
+        comboAudioCodecs->setCurrentIndex(iACodec);
+
+    return true;
+}
--- a/QTfrontend/ui/page/pageoptions.h	Sun Dec 02 00:03:16 2012 +0100
+++ b/QTfrontend/ui/page/pageoptions.h	Tue Dec 25 04:45:22 2012 +0100
@@ -21,6 +21,7 @@
 
 #include "AbstractPage.h"
 
+class GameUIConfig;
 class FPSEdit;
 class IconedGroupBox;
 class QSignalMapper;
@@ -57,10 +58,10 @@
         IconedGroupBox *AGGroupBox;
         QComboBox *CBResolution;
         QComboBox *CBStereoMode;
-        QCheckBox *CBEnableSound;
-        QCheckBox *CBEnableFrontendSound;
-        QCheckBox *CBEnableMusic;
-        QCheckBox *CBEnableFrontendMusic;
+        QCheckBox *CBFrontendSound;
+        QCheckBox *CBFrontendMusic;
+        QCheckBox *CBSound;
+        QCheckBox *CBMusic;
         QCheckBox *CBFullscreen;
         QCheckBox *CBFrontendFullscreen;
         QCheckBox *CBShowFPS;
@@ -69,6 +70,7 @@
         QCheckBox *CBNameWithDate;
 #ifdef __APPLE__
         QCheckBox *CBAutoUpdate;
+        QPushButton *BtnUpdateNow;
 #endif
 
         FPSEdit *fpsedit;
@@ -84,6 +86,26 @@
         QLineEdit * leProxyLogin;
         QLineEdit * leProxyPassword;
 
+        QComboBox  *framerateBox;
+        QSpinBox  *bitrateBox;
+        QLineEdit *widthEdit;
+        QLineEdit *heightEdit;
+        QCheckBox *checkUseGameRes;
+        QCheckBox *checkRecordAudio;
+
+        QString format()
+        { return comboAVFormats->itemData(comboAVFormats->currentIndex()).toString(); }
+
+        QString videoCodec()
+        { return comboVideoCodecs->itemData(comboVideoCodecs->currentIndex()).toString(); }
+
+        QString audioCodec()
+        { return comboAudioCodecs->itemData(comboAudioCodecs->currentIndex()).toString(); }
+
+        void setDefaultCodecs();
+        bool tryCodecs(const QString & format, const QString & vcodec, const QString & acodec);
+        void setConfig(GameUIConfig * config);
+
         void setTeamOptionsEnabled(bool enabled);
 
     signals:
@@ -106,6 +128,13 @@
         QPushButton *BtnDeleteTeam;
         QList<QPushButton *> m_colorButtons;
 
+        QComboBox *comboAVFormats;
+        QComboBox *comboVideoCodecs;
+        QComboBox *comboAudioCodecs;
+        QPushButton *btnDefaults;
+        QPushButton *btnUpdateNow;
+        GameUIConfig * config;
+
     private slots:
         void forceFullscreen(int index);
         void setFullscreen(int state);
@@ -118,6 +147,13 @@
         void colorButtonClicked(int i);
         void onColorModelDataChanged(const QModelIndex & topLeft, const QModelIndex & bottomRight);
         void onProxyTypeChanged();
+        void changeAVFormat(int index);
+        void changeUseGameRes(int state);
+        void changeRecordAudio(int state);
+        void checkForUpdates();
+
+    public slots:
+        void setDefaultOptions();
 };
 
 #endif
--- a/QTfrontend/ui/page/pageroomslist.cpp	Sun Dec 02 00:03:16 2012 +0100
+++ b/QTfrontend/ui/page/pageroomslist.cpp	Tue Dec 25 04:45:22 2012 +0100
@@ -95,7 +95,7 @@
 
     pageLayout->addLayout(filterLayout, 4, 0, 1, 2);
 
-    chatWidget = new HWChatWidget(this, m_gameSettings, false);
+    chatWidget = new HWChatWidget(this, false);
     pageLayout->addWidget(chatWidget, 5, 0, 1, 3);
     pageLayout->setRowStretch(5, 350);
 
@@ -156,11 +156,9 @@
 }
 
 
-PageRoomsList::PageRoomsList(QWidget* parent, QSettings * gameSettings) :
+PageRoomsList::PageRoomsList(QWidget* parent) :
     AbstractPage(parent)
 {
-    m_gameSettings = gameSettings;
-
     roomsModel = NULL;
     stateFilteredModel = NULL;
     schemeFilteredModel = NULL;
@@ -612,13 +610,17 @@
             QString("*%1*").arg(CBWeapons->currentText()));
 }
 
+void PageRoomsList::setSettings(QSettings *settings)
+{
+    m_gameSettings = settings;
+}
 
 bool PageRoomsList::restoreHeaderState()
 {
     if (!m_gameSettings->contains("frontend/roomslist_header"))
         return false;
     return roomsList->horizontalHeader()->restoreState(QByteArray::fromBase64(
-        (m_gameSettings->value("frontend/roomslist_header").toString().toAscii())));
+        (m_gameSettings->value("frontend/roomslist_header").toByteArray())));
 }
 
 void PageRoomsList::saveHeaderState()
--- a/QTfrontend/ui/page/pageroomslist.h	Sun Dec 02 00:03:16 2012 +0100
+++ b/QTfrontend/ui/page/pageroomslist.h	Tue Dec 25 04:45:22 2012 +0100
@@ -32,10 +32,11 @@
         Q_OBJECT
 
     public:
-        PageRoomsList(QWidget* parent, QSettings * config);
+        PageRoomsList(QWidget* parent);
         void displayError(const QString & message);
         void displayNotice(const QString & message);
         void displayWarning(const QString & message);
+        void setSettings(QSettings * settings);
 
         QLineEdit * roomName;
         QLineEdit * searchText;
--- a/QTfrontend/ui/page/pagetraining.cpp	Sun Dec 02 00:03:16 2012 +0100
+++ b/QTfrontend/ui/page/pagetraining.cpp	Tue Dec 25 04:45:22 2012 +0100
@@ -118,7 +118,7 @@
     DataManager & dataMgr = DataManager::instance();
 
     // get locale
-    QSettings settings(cfgdir->absolutePath() + "/hedgewars.ini",
+    QSettings settings("physfs://hedgewars.ini",
                        QSettings::IniFormat);
 
     QString loc = settings.value("misc/locale", "").toString();
--- a/QTfrontend/ui/page/pagevideos.cpp	Sun Dec 02 00:03:16 2012 +0100
+++ b/QTfrontend/ui/page/pagevideos.cpp	Tue Dec 25 04:45:22 2012 +0100
@@ -109,119 +109,6 @@
     QGridLayout * pPageLayout = new QGridLayout();
     pPageLayout->setColumnStretch(0, 1);
     pPageLayout->setColumnStretch(1, 2);
-    pPageLayout->setRowStretch(0, 1);
-    pPageLayout->setRowStretch(1, 1);
-
-    // options
-    {
-        IconedGroupBox* pOptionsGroup = new IconedGroupBox(this);
-        pOptionsGroup->setIcon(QIcon(":/res/Settings.png")); // FIXME
-        pOptionsGroup->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
-        pOptionsGroup->setTitle(QGroupBox::tr("Video recording options"));
-        QGridLayout * pOptLayout = new QGridLayout(pOptionsGroup);
-
-        // label for format
-        QLabel *labelFormat = new QLabel(pOptionsGroup);
-        labelFormat->setText(QLabel::tr("Format"));
-        pOptLayout->addWidget(labelFormat, 0, 0);
-
-        // list of supported formats
-        comboAVFormats = new QComboBox(pOptionsGroup);
-        pOptLayout->addWidget(comboAVFormats, 0, 1, 1, 4);
-        LibavInteraction::instance().fillFormats(comboAVFormats);
-
-        // separator
-        QFrame * hr = new QFrame(pOptionsGroup);
-        hr->setFrameStyle(QFrame::HLine);
-        hr->setLineWidth(3);
-        hr->setFixedHeight(10);
-        pOptLayout->addWidget(hr, 1, 0, 1, 5);
-
-        // label for audio codec
-        QLabel *labelACodec = new QLabel(pOptionsGroup);
-        labelACodec->setText(QLabel::tr("Audio codec"));
-        pOptLayout->addWidget(labelACodec, 2, 0);
-
-        // list of supported audio codecs
-        comboAudioCodecs = new QComboBox(pOptionsGroup);
-        pOptLayout->addWidget(comboAudioCodecs, 2, 1, 1, 3);
-
-        // checkbox 'record audio'
-        checkRecordAudio = new QCheckBox(pOptionsGroup);
-        checkRecordAudio->setText(QCheckBox::tr("Record audio"));
-        pOptLayout->addWidget(checkRecordAudio, 2, 4);
-
-        // separator
-        hr = new QFrame(pOptionsGroup);
-        hr->setFrameStyle(QFrame::HLine);
-        hr->setLineWidth(3);
-        hr->setFixedHeight(10);
-        pOptLayout->addWidget(hr, 3, 0, 1, 5);
-
-        // label for video codec
-        QLabel *labelVCodec = new QLabel(pOptionsGroup);
-        labelVCodec->setText(QLabel::tr("Video codec"));
-        pOptLayout->addWidget(labelVCodec, 4, 0);
-
-        // list of supported video codecs
-        comboVideoCodecs = new QComboBox(pOptionsGroup);
-        pOptLayout->addWidget(comboVideoCodecs, 4, 1, 1, 4);
-
-        // label for resolution
-        QLabel *labelRes = new QLabel(pOptionsGroup);
-        labelRes->setText(QLabel::tr("Resolution"));
-        pOptLayout->addWidget(labelRes, 5, 0);
-
-        // width
-        widthEdit = new QLineEdit(pOptionsGroup);
-        widthEdit->setValidator(new QIntValidator(this));
-        pOptLayout->addWidget(widthEdit, 5, 1);
-
-        // x
-        QLabel *labelX = new QLabel(pOptionsGroup);
-        labelX->setText("X");
-        pOptLayout->addWidget(labelX, 5, 2);
-
-        // height
-        heightEdit = new QLineEdit(pOptionsGroup);
-        heightEdit->setValidator(new QIntValidator(pOptionsGroup));
-        pOptLayout->addWidget(heightEdit, 5, 3);
-
-        // checkbox 'use game resolution'
-        checkUseGameRes = new QCheckBox(pOptionsGroup);
-        checkUseGameRes->setText(QCheckBox::tr("Use game resolution"));
-        pOptLayout->addWidget(checkUseGameRes, 5, 4);
-
-        // label for framerate
-        QLabel *labelFramerate = new QLabel(pOptionsGroup);
-        labelFramerate->setText(QLabel::tr("Framerate"));
-        pOptLayout->addWidget(labelFramerate, 6, 0);
-
-        // framerate
-        framerateBox = new QSpinBox(pOptionsGroup);
-        framerateBox->setRange(1, 200);
-        framerateBox->setSingleStep(1);
-        pOptLayout->addWidget(framerateBox, 6, 1);
-
-        // label for Bitrate
-        QLabel *labelBitrate = new QLabel(pOptionsGroup);
-        labelBitrate->setText(QLabel::tr("Bitrate (Kbps)"));
-        pOptLayout->addWidget(labelBitrate, 6, 2);
-
-        // bitrate
-        bitrateBox = new QSpinBox(pOptionsGroup);
-        bitrateBox->setRange(100, 5000);
-        bitrateBox->setSingleStep(100);
-        pOptLayout->addWidget(bitrateBox, 6, 3);
-
-        // button 'set default options'
-        btnDefaults = new QPushButton(pOptionsGroup);
-        btnDefaults->setText(QPushButton::tr("Set default options"));
-        btnDefaults->setWhatsThis(QPushButton::tr("Restore default coding parameters"));
-        pOptLayout->addWidget(btnDefaults, 7, 0, 1, 5);
-
-        pPageLayout->addWidget(pOptionsGroup, 1, 0);
-    }
 
     // list of videos
     {
@@ -257,7 +144,7 @@
         box->addWidget(filesTable);
         box->addWidget(btnOpenDir);
 
-        pPageLayout->addWidget(pTableGroup, 0, 1, 2, 1);
+        pPageLayout->addWidget(pTableGroup, 0, 1);
     }
 
     // description
@@ -267,7 +154,6 @@
         pDescGroup->setTitle(QGroupBox::tr("Description"));
 
         QVBoxLayout* pDescLayout = new QVBoxLayout(pDescGroup);
-        QHBoxLayout* pTopDescLayout = new QHBoxLayout(0);    // picture and text
         QHBoxLayout* pBottomDescLayout = new QHBoxLayout(0); // buttons
 
         // label with thumbnail picture
@@ -282,18 +168,18 @@
                     "border-radius: 4px;"
                     "}" );
         clearThumbnail();
-        pTopDescLayout->addWidget(labelThumbnail, 2);
 
         // label with file description
         labelDesc = new QLabel(pDescGroup);
         labelDesc->setAlignment(Qt::AlignLeft | Qt::AlignTop);
         labelDesc->setTextInteractionFlags(Qt::TextSelectableByMouse |
-                                           Qt::TextSelectableByKeyboard	|
+                                           Qt::TextSelectableByKeyboard |
                                            Qt::LinksAccessibleByMouse |
                                            Qt::LinksAccessibleByKeyboard);
         labelDesc->setTextFormat(Qt::RichText);
         labelDesc->setOpenExternalLinks(true);
-        pTopDescLayout->addWidget(labelDesc, 1);
+        labelDesc->setMinimumSize(ThumbnailSize);
+        //pTopDescLayout->addWidget(labelDesc, 1);
 
         // buttons: play and delete
         btnPlay = new QPushButton(QPushButton::tr("Play"), pDescGroup);
@@ -310,7 +196,9 @@
         pBottomDescLayout->addWidget(btnToYouTube);
 
         pDescLayout->addStretch(1);
-        pDescLayout->addLayout(pTopDescLayout, 0);
+        pDescLayout->addWidget(labelThumbnail, 0);
+        pDescLayout->addStretch(1);
+        pDescLayout->addWidget(labelDesc, 0);
         pDescLayout->addStretch(1);
         pDescLayout->addLayout(pBottomDescLayout, 0);
 
@@ -327,10 +215,6 @@
 
 void PageVideos::connectSignals()
 {
-    connect(checkUseGameRes, SIGNAL(stateChanged(int)), this, SLOT(changeUseGameRes(int)));
-    connect(checkRecordAudio, SIGNAL(stateChanged(int)), this, SLOT(changeRecordAudio(int)));
-    connect(comboAVFormats, SIGNAL(currentIndexChanged(int)), this, SLOT(changeAVFormat(int)));
-    connect(btnDefaults, SIGNAL(clicked()), this, SLOT(setDefaultOptions()));
     connect(filesTable, SIGNAL(cellDoubleClicked(int, int)), this, SLOT(cellDoubleClicked(int, int)));
     connect(filesTable, SIGNAL(cellChanged(int,int)), this, SLOT(cellChanged(int, int)));
     connect(filesTable, SIGNAL(currentCellChanged(int,int,int,int)), this, SLOT(currentCellChanged()));
@@ -362,124 +246,6 @@
     startEncoding(); // this is for videos recorded from demos which were executed directly (without frontend)
 }
 
-// user changed file format, we need to update list of codecs
-void PageVideos::changeAVFormat(int index)
-{
-    // remember selected codecs
-    QString prevVCodec = videoCodec();
-    QString prevACodec = audioCodec();
-
-    // clear lists of codecs
-    comboVideoCodecs->clear();
-    comboAudioCodecs->clear();
-
-    // get list of codecs for specified format
-    LibavInteraction::instance().fillCodecs(comboAVFormats->itemData(index).toString(), comboVideoCodecs, comboAudioCodecs);
-
-    // disable audio if there is no audio codec
-    if (comboAudioCodecs->count() == 0)
-    {
-        checkRecordAudio->setChecked(false);
-        checkRecordAudio->setEnabled(false);
-    }
-    else
-        checkRecordAudio->setEnabled(true);
-
-    // restore selected codecs if possible
-    int iVCodec = comboVideoCodecs->findData(prevVCodec);
-    if (iVCodec != -1)
-        comboVideoCodecs->setCurrentIndex(iVCodec);
-    int iACodec = comboAudioCodecs->findData(prevACodec);
-    if (iACodec != -1)
-        comboAudioCodecs->setCurrentIndex(iACodec);
-}
-
-// user switched checkbox 'use game resolution'
-void PageVideos::changeUseGameRes(int state)
-{
-    if (state && config)
-    {
-        // set resolution to game resolution
-        QRect resolution = config->vid_Resolution();
-        widthEdit->setText(QString::number(resolution.width()));
-        heightEdit->setText(QString::number(resolution.height()));
-    }
-    widthEdit->setEnabled(!state);
-    heightEdit->setEnabled(!state);
-}
-
-// user switched checkbox 'record audio'
-void PageVideos::changeRecordAudio(int state)
-{
-    comboAudioCodecs->setEnabled(!!state);
-}
-
-void PageVideos::setDefaultCodecs()
-{
-    // VLC should be able to handle any of these configurations
-    // Quicktime X only opens the first one
-    // Windows Media Player TODO
-    if (tryCodecs("mp4", "libx264", "aac"))
-        return;
-    if (tryCodecs("mp4", "libx264", "libfaac"))
-        return;
-    if (tryCodecs("mp4", "libx264", "libmp3lame"))
-        return;
-    if (tryCodecs("mp4", "libx264", "mp2"))
-        return;
-    if (tryCodecs("avi", "libxvid", "libmp3lame"))
-        return;
-    if (tryCodecs("avi", "libxvid", "ac3_fixed"))
-        return;
-    if (tryCodecs("avi", "libxvid", "mp2"))
-        return;
-    if (tryCodecs("avi", "mpeg4", "libmp3lame"))
-        return;
-    if (tryCodecs("avi", "mpeg4", "ac3_fixed"))
-        return;
-    if (tryCodecs("avi", "mpeg4", "mp2"))
-        return;
-
-    // this shouldn't happen, just in case
-    if (tryCodecs("ogg", "libtheora", "libvorbis"))
-        return;
-    tryCodecs("ogg", "libtheora", "flac");
-}
-
-void PageVideos::setDefaultOptions()
-{
-    framerateBox->setValue(30);
-    bitrateBox->setValue(1000);
-    checkRecordAudio->setChecked(true);
-    checkUseGameRes->setChecked(true);
-    setDefaultCodecs();
-}
-
-bool PageVideos::tryCodecs(const QString & format, const QString & vcodec, const QString & acodec)
-{
-    // first we should change format
-    int iFormat = comboAVFormats->findData(format);
-    if (iFormat == -1)
-        return false;
-    comboAVFormats->setCurrentIndex(iFormat);
-    // format was changed, so lists of codecs were automatically updated to codecs supported by this format
-
-    // try to find video codec
-    int iVCodec = comboVideoCodecs->findData(vcodec);
-    if (iVCodec == -1)
-        return false;
-    comboVideoCodecs->setCurrentIndex(iVCodec);
-
-    // try to find audio codec
-    int iACodec = comboAudioCodecs->findData(acodec);
-    if (iACodec == -1 && checkRecordAudio->isChecked())
-        return false;
-    if (iACodec != -1)
-        comboAudioCodecs->setCurrentIndex(iACodec);
-
-    return true;
-}
-
 // get file size as string
 static QString FileSizeStr(const QString & path)
 {
@@ -1096,7 +862,7 @@
     int row = filesTable->currentRow();
     VideoItem * item = nameItem(row);
 
-    if (item->pUploading)
+    if (item->pUploading) //Act as 'cancel uploading' button
     {
         // ask user if (s)he is serious
         QMessageBox reallyStopMsg(this);
@@ -1108,9 +874,10 @@
 
         if (reallyStopMsg.exec() != QMessageBox::Ok)
             return;
-        item->pUploading->deleteLater();
+        item->pUploading->abort();
+        btnToYouTube->setText(QPushButton::tr("Upload to YouTube"));
         filesTable->setCellWidget(row, vcProgress, NULL); // remove progress bar
-        numUploads--;
+        //numUploads--;
         return;
     }
 
--- a/QTfrontend/ui/page/pagevideos.h	Sun Dec 02 00:03:16 2012 +0100
+++ b/QTfrontend/ui/page/pagevideos.h	Tue Dec 25 04:45:22 2012 +0100
@@ -36,24 +36,6 @@
     public:
         PageVideos(QWidget* parent = 0);
 
-        QSpinBox  *framerateBox;
-        QSpinBox  *bitrateBox;
-        QLineEdit *widthEdit;
-        QLineEdit *heightEdit;
-        QCheckBox *checkUseGameRes;
-        QCheckBox *checkRecordAudio;
-
-        QString format()
-        { return comboAVFormats->itemData(comboAVFormats->currentIndex()).toString(); }
-
-        QString videoCodec()
-        { return comboVideoCodecs->itemData(comboVideoCodecs->currentIndex()).toString(); }
-
-        QString audioCodec()
-        { return comboAudioCodecs->itemData(comboAudioCodecs->currentIndex()).toString(); }
-
-        void setDefaultCodecs();
-        bool tryCodecs(const QString & format, const QString & vcodec, const QString & acodec);
         void addRecorder(HWRecorder* pRecorder);
         bool tryQuit(HWForm *form);
         QString getVideosInProgress(); // get multi-line string with list of videos in progress
@@ -83,12 +65,6 @@
         GameUIConfig * config;
         QNetworkAccessManager* netManager;
 
-        // options group
-        QComboBox *comboAVFormats;
-        QComboBox *comboVideoCodecs;
-        QComboBox *comboAudioCodecs;
-        QPushButton *btnDefaults;
-
         // file list group
         QTableWidget *filesTable;
         QPushButton *btnOpenDir;
@@ -105,10 +81,6 @@
         int numRecorders, numUploads;
 
     private slots:
-        void changeAVFormat(int index);
-        void changeUseGameRes(int state);
-        void changeRecordAudio(int state);
-        void setDefaultOptions();
         void encodingFinished(bool success);
         void updateProgress(float value);
         void cellDoubleClicked(int row, int column);
--- a/QTfrontend/ui/widget/about.cpp	Sun Dec 02 00:03:16 2012 +0100
+++ b/QTfrontend/ui/widget/about.cpp	Tue Dec 25 04:45:22 2012 +0100
@@ -21,6 +21,10 @@
 #include <QList>
 #include <QUrl>
 #include <QRegExp>
+#include <QNetworkAccessManager>
+#include <QNetworkRequest>
+#include <QNetworkReply>
+#include <QDebug>
 #include "hwconsts.h"
 #include "SDLInteraction.h"
 
@@ -59,97 +63,9 @@
     mainLayout->addWidget(lbl1, 0, 1);
 
     lbl2 = new QTextBrowser(this);
-
     lbl2->setOpenExternalLinks(true);
-    lbl2->setText(
-        "<style type=\"text/css\">"
-        "a { color: #ffcc00; }"
-//            "a:hover { color: yellow; }"
-        "</style>" +
-        QString("<h2>") +
-        QLabel::tr("Developers:") +
-        "</h2><p>"
-        "Engine, frontend, net server: Andrey Korotaev &lt;<a href=\"mailto:unC0Rr@gmail.com\">unC0Rr@gmail.com</a>&gt;<br>"
-        "Many frontend improvements: Igor Ulyanov &lt;<a href=\"mailto:disinbox@gmail.com\">disinbox@gmail.com</a>&gt;<br>"
-        "Many engine and frontend improvements: Derek Pomery &lt;<a href=\"mailto:nemo@m8y.org\">nemo@m8y.org</a>&gt;<br>"
-        "Drill rocket, Ballgun, RC Plane weapons: Martin Boze &lt;<a href=\"mailto:afffect@gmail.com\">afffect@gmail.com</a>&gt;<br>"
-        "Mine number and time game settings: David A. Cuadrado &lt;<a href=\"mailto:krawek@gmail.com\">krawek@gmail.com</a>&gt;<br>"
-        "Frontend improvements: Martin Minarik &lt;<a href=\"mailto:ttsmj@pokec.sk\">ttsmj@pokec.sk</a>&gt;<br>"
-        "Frontend improvements: Kristian Lehmann &lt;<a href=\"mailto:email@thexception.net\">email@thexception.net</a>&gt;<br>"
-        "Mac OS X/iPhone port, OpenGL-ES conversion: Vittorio Giovara &lt;<a href=\"mailto:vittorio.giovara@gmail.com\">vittorio.giovara@gmail.com</a>&gt;<br>"
-        "Many engine and frontend improvements (and bugs): Richard Karolyi &lt;<a href=\"mailto:sheepluva@" "ercatec.net\">sheepluva@" "ercatec.net</a>&gt;<br>"
-        "Gamepad and Lua integration: Mario Liebisch &lt;<a href=\"mailto:mario.liebisch@gmail.com\">mario.liebisch@gmail.com</a>&gt;<br>"
-        "Many engine improvements and graphics: Carlos Vives &lt;<a href=\"mailto:mail@carlosvives.es\">mail@carlosvives.es</a>&gt;<br>"
-        "Maze maps: Henning K&uuml;hn &lt;<a href=\"mailto:prg@cooco.de\">prg@cooco.de</a>&gt;<br>"
-        "Engine and frontend improvements: Henrik Rostedt &lt;<a href=\"mailto:henrik.rostedt@gmail.com\">henrik.rostedt@gmail.com</a>&gt;<br>"
-        "Lua game modes and missions: John Lambert &lt;<a href=\"mailto:redgrinner@gmail.com\">redgrinner@gmail.com</a>&gt;<br>"
-        "Frontend improvements: Mayur Pawashe &lt;<a href=\"mailto:zorgiepoo@gmail.com\">zorgiepoo@gmail.com</a>&gt;<br>"
-        "Android port: Richard Deurwaarder &lt;<a href=\"mailto:xeli@xelification.com\">xeli@xelification.com</a>&gt;<br>"
-        "Android netplay, portability abstraction: Simeon Maxein &lt;<a href=\"mailto:smaxein@googlemail.com\">smaxein@googlemail.com</a>&gt;<br>"
-        "WebGL port, some pas2c and GLES2 work: Meng Xiangyun &lt;<a href=\"mailto:xymengxy@gmail.com\">xymengxy@gmail.com</a>&gt;<br>"
-        "Video recording: Stepan Podoskin &lt;<a href=\"mailto:stepik-777@mail.ru\">stepik-777@mail.ru</a>&gt;<br>"
-        "Campaign support, first campaign: Szabolcs Orb&agrave;n &lt;<a href=\"mailto:szabibibi@gmail.com\">szabibibi@gmail.com</a>&gt;<br>"
-        "</p><h2>" +
-
-        QLabel::tr("Art:") + "</h2>"
-        + QString::fromUtf8(
-            "<p>John Dum &lt;<a href=\"mailto:fizzy@gmail.com\">fizzy@gmail.com</a>&gt;"
-            "<br>"
-            "Joshua Frese &lt;<a href=\"mailto:joshfrese@gmail.com\">joshfrese@gmail.com</a>&gt;"
-            "<br>"
-            "Stanko Tadić &lt;<a href=\"mailto:stanko@mfhinc.net\">stanko@mfhinc.net</a>&gt;"
-            "<br>"
-            "Julien Koesten &lt;<a href=\"mailto:julienkoesten@aol.com\">julienkoesten@aol.com</a>&gt;"
-            "<br>"
-            "Joshua O'Sullivan &lt;<a href=\"mailto:coheedftw@hotmail.co.uk\">coheedftw@hotmail.co.uk</a>&gt;"
-            "<br>"
-            "Nils Lück &lt;<a href=\"mailto:nils.luck.design@gmail.com\">nils.luck.design@gmail.com</a>&gt;"
-            "<br>"
-            "Guillaume Englert &lt;<a href=\"mailto:genglert@hybird.org\">genglert@hybird.org</a>&gt;"
-            "<br>"
-            "Hats: Trey Perry &lt;<a href=\"mailto:tx.perry.j@gmail.com\">tx.perry.j@gmail.com</a>&gt;"
-            "</p><h2>") +
-        QLabel::tr("Sounds:") + "</h2>"
-        "Hedgehogs voice: Stephen Alexander &lt;<a href=\"mailto:ArmagonNo1@gmail.com\">ArmagonNo1@gmail.com</a>&gt;"
-        "<br>"
-        "John Dum &lt;<a href=\"mailto:fizzy@gmail.com\">fizzy@gmail.com</a>&gt;"
-        "<br>"
-        "Jonatan Nilsson &lt;<a href=\"mailto:jonatanfan@gmail.com\">jonatanfan@gmail.com</a>&gt;"
-        "<br>"
-        "Daniel Martin &lt;<a href=\"mailto:elhombresinremedio@gmail.com\">elhombresinremedio@gmail.com</a>&gt;"
-        "</p><h2>" +
-
-        QLabel::tr("Translations:") + "</h2><p>"
-        + QString::fromUtf8(
-            "Brazilian Portuguese: Romulo Fernandes Machado &lt;<a href=\"mailto:abra185@gmail.com\">abra185@gmail.com</a>&gt;<br>"
-            "Bulgarian: Svetoslav Stefanov<br>"
-            "Czech: Petr Řezáček &lt;<a href=\"mailto:rezacek@gmail.com\">rezacek@gmail.com</a>&gt;<br>"
-            "Chinese: Jie Luo &lt;<a href=\"mailto:lililjlj@gmail.com\">lililjlj@gmail.com</a>&gt;<br>"
-            "English: Andrey Korotaev &lt;<a href=\"mailto:unC0Rr@gmail.com\">unC0Rr@gmail.com</a>&gt;<br>"
-            "Finnish: Nina Kuisma &lt;<a href=\"mailto:ninnnu@gmail.com\">ninnnu@gmail.com</a>&gt;<br>"
-            "French: Antoine Turmel &lt;<a href=\"mailto:geekshadow@gmail.com\">geekshadow@gmail.com</a>&gt;, Clement Woitrain &lt;<a href=\"mailto:sphrixclement@gmail.com\">sphrixclement@gmail.com</a>&gt;<br>"
-            "German: Peter Hüwe &lt;<a href=\"mailto:PeterHuewe@gmx.de\">PeterHuewe@gmx.de</a>&gt;, Mario Liebisch &lt;<a href=\"mailto:mario.liebisch@gmail.com\">mario.liebisch@gmail.com</a>&gt;, Richard Karolyi &lt;<a href=\"mailto:sheepluva@" "ercatec.net\">sheepluva@" "ercatec.net</a>&gt;<br>"
-            "Greek: &lt;<a href=\"mailto:talos_kriti@yahoo.gr\">talos_kriti@yahoo.gr</a>&gt;<br>"
-            "Italian: Luca Bonora &lt;<a href=\"mailto:bonora.luca@gmail.com\">bonora.luca@gmail.com</a>&gt;, Marco Bresciani<br>"
-            "Japanese: ADAM Etienne &lt;<a href=\"mailto:etienne.adam@gmail.com\">etienne.adam@gmail.com</a>&gt;<br>"
-            "Korean: Anthony Bellew &lt;<a href=\"mailto:anthonyreflected@gmail.com\">anthonyreflected@gmail.com</a>&gt;<br>"
-            "Lithuanian: Lukas Urbonas &lt;<a href=\"mailto:lukasu08@gmail.com\">lukasu08@gmail.com</a>&gt;<br>"
-            "Polish: Maciej Mroziński &lt;<a href=\"mailto:mynick2@o2.pl\">mynick2@o2.pl</a>&gt;, Wojciech Latkowski &lt;<a href=\"mailto:magik17l@gmail.com\">magik17l@gmail.com</a>&gt;, Piotr Mitana, Maciej Górny<br>"
-            "Portuguese: Fábio Canário &lt;<a href=\"mailto:inufabie@gmail.com\">inufabie@gmail.com</a>&gt;<br>"
-            "Russian: Andrey Korotaev &lt;<a href=\"mailto:unC0Rr@gmail.com\">unC0Rr@gmail.com</a>&gt;<br>"
-            "Slovak: Jose Riha<br>"
-            "Spanish: Carlos Vives &lt;<a href=\"mailto:mail@carlosvives.es\">mail@carlosvives.es</a>&gt;<br>"
-            "Swedish: Niklas Grahn &lt;<a href=\"mailto:raewolusjoon@yaoo.com\">raewolusjoon@yaoo.com</a>&gt;, Henrik Rostedt &lt;<a href=\"mailto:henrik.rostedt@gmail.com\">henrik.rostedt@gmail.com</a>&gt;<br>"
-            "Ukrainian: Eugene V. Lyubimkin &lt;<a href=\"mailto:jackyf.devel@gmail.com\">jackyf.devel@gmail.com</a>&gt;, Igor Paliychuk &lt;<a href=\"mailto:mansonigor@gmail.com\">mansonigor@gmail.com</a>&gt;, Eugene Sakara &lt;<a href=\"mailto:eresid@gmail.com\">eresid@gmail.com</a>&gt;"
-            "</p><h2>") +
-
-        QLabel::tr("Special thanks:") + "</h2><p>"
-        "Aleksey Andreev &lt;<a href=\"mailto:blaknayabr@gmail.com\">blaknayabr@gmail.com</a>&gt;<br>"
-        "Aleksander Rudalev &lt;<a href=\"mailto:alexv@pomorsu.ru\">alexv@pomorsu.ru</a>&gt;<br>"
-        "Natasha Korotaeva &lt;<a href=\"mailto:layout@pisem.net\">layout@pisem.net</a>&gt;<br>"
-        "Adam Higerd (aka ahigerd at FreeNode)"
-        "</p>"
-    );
+    QUrl localpage = QUrl::fromLocalFile(":/res/html/about.html");
+    lbl2->setSource(localpage); //sets the source of the label from the file above
     mainLayout->addWidget(lbl2, 1, 1);
 
     setAcceptDrops(true);
--- a/QTfrontend/ui/widget/chatwidget.cpp	Sun Dec 02 00:03:16 2012 +0100
+++ b/QTfrontend/ui/widget/chatwidget.cpp	Tue Dec 25 04:45:22 2012 +0100
@@ -177,7 +177,7 @@
 }
 
 
-HWChatWidget::HWChatWidget(QWidget* parent, QSettings * gameSettings, bool notify) :
+HWChatWidget::HWChatWidget(QWidget* parent, bool notify) :
     QWidget(parent),
     mainLayout(this)
 {
@@ -187,7 +187,6 @@
     m_isAdmin = false;
     m_autoKickEnabled = false;
 
-    if(gameSettings->value("frontend/sound", true).toBool())
     {
         QStringList vpList =
              QStringList() << "Classic" << "Default" << "Mobster" << "Russian";
@@ -281,6 +280,10 @@
     clear();
 }
 
+void HWChatWidget::setSettings(QSettings * settings)
+{
+    gameSettings = settings;
+}
 
 void HWChatWidget::linkClicked(const QUrl & link)
 {
--- a/QTfrontend/ui/widget/chatwidget.h	Sun Dec 02 00:03:16 2012 +0100
+++ b/QTfrontend/ui/widget/chatwidget.h	Tue Dec 25 04:45:22 2012 +0100
@@ -54,7 +54,7 @@
         Q_OBJECT
 
     public:
-        HWChatWidget(QWidget* parent, QSettings * gameSettings, bool notify);
+        HWChatWidget(QWidget* parent, bool notify);
         void setIgnoreListKick(bool enabled); ///< automatically kick people on ignore list (if possible)
         void setShowFollow(bool enabled);
         static const QString & styleSheet();
@@ -63,6 +63,7 @@
         void displayWarning(const QString & message);
         void setUser(const QString & nickname);
         void setUsersModel(QAbstractItemModel * model);
+        void setSettings(QSettings * settings);
 
     protected:
         virtual void dragEnterEvent(QDragEnterEvent * event);
--- a/QTfrontend/ui/widget/qpushbuttonwithsound.cpp	Sun Dec 02 00:03:16 2012 +0100
+++ b/QTfrontend/ui/widget/qpushbuttonwithsound.cpp	Tue Dec 25 04:45:22 2012 +0100
@@ -33,7 +33,7 @@
 
 void QPushButtonWithSound::buttonClicked()
 {
-    if ( !isSoundEnabled || !HWForm::config->isFrontendSoundEnabled())
+    if ( !isSoundEnabled )
         return;
 
     if (this->isEnabled())
--- a/QTfrontend/ui/widget/teamselect.cpp	Sun Dec 02 00:03:16 2012 +0100
+++ b/QTfrontend/ui/widget/teamselect.cpp	Tue Dec 25 04:45:22 2012 +0100
@@ -59,6 +59,7 @@
                     this, SLOT(changeTeamStatus(HWTeam)));
         }
     }
+
     emit setEnabledGameStart(curPlayingTeams.size()>1);
 }
 
@@ -168,6 +169,12 @@
         m_curNotPlayingTeams.push_back(*itPlay);
         emit teamNotPlaying(*itPlay);
         curPlayingTeams.erase(itPlay);
+
+        // Show team notice if less than two teams.
+        if (curPlayingTeams.size() < 2)
+        {
+            numTeamNotice->show();
+        }
     }
     else
     {
@@ -179,6 +186,12 @@
         curPlayingTeams.push_back(*itDontPlay);
         if(!m_acceptOuter) emit teamWillPlay(*itDontPlay);
         m_curNotPlayingTeams.erase(itDontPlay);
+
+        // Hide team notice if at least two teams.
+        if (curPlayingTeams.size() >= 2)
+        {
+            numTeamNotice->hide();
+        }
     }
 
     FrameTeams* pRemoveTeams;
@@ -254,6 +267,10 @@
     framePlaying = new FrameTeams();
     frameDontPlaying = new FrameTeams();
 
+    // Add notice about number of required teams.
+    numTeamNotice = new QLabel("Two teams are required to play!");
+    mainLayout.addWidget(numTeamNotice);
+
     QPalette p;
     p.setColor(QPalette::Window, QColor(0x00, 0x00, 0x00));
     addScrArea(framePlaying, p.color(QPalette::Window).light(105), 250);
--- a/QTfrontend/ui/widget/teamselect.h	Sun Dec 02 00:03:16 2012 +0100
+++ b/QTfrontend/ui/widget/teamselect.h	Tue Dec 25 04:45:22 2012 +0100
@@ -20,6 +20,7 @@
 #ifndef _TEAM_SELECT_INCLUDED
 #define _TEAM_SELECT_INCLUDED
 
+#include <QLabel>
 #include <QGroupBox>
 #include <QVBoxLayout>
 #include <QColor>
@@ -74,6 +75,7 @@
         FrameTeams* framePlaying;
 
         QVBoxLayout mainLayout;
+        QLabel *numTeamNotice;
         bool m_acceptOuter;
 
         QList<HWTeam> curPlayingTeams;
--- a/QTfrontend/ui_hwform.cpp	Sun Dec 02 00:03:16 2012 +0100
+++ b/QTfrontend/ui_hwform.cpp	Tue Dec 25 04:45:22 2012 +0100
@@ -30,7 +30,6 @@
 #include "pagefeedback.h"
 #include "pageingame.h"
 #include "pagescheme.h"
-#include "pagenettype.h"
 #include "pageroomslist.h"
 #include "pageinfo.h"
 #include "pagenetgame.h"
@@ -60,7 +59,7 @@
     centralWidget = new QWidget(HWForm);
     centralWidget->setObjectName(QString::fromUtf8("centralWidget"));
 
-    SetupPages(centralWidget, HWForm);
+    SetupPages(centralWidget);
 
     HWForm->setCentralWidget(centralWidget);
 
@@ -74,7 +73,7 @@
     font14 = new QFont("MS Shell Dlg", 14);
 }
 
-void Ui_HWForm::SetupPages(QWidget *Parent, HWForm *HWForm)
+void Ui_HWForm::SetupPages(QWidget *Parent)
 {
     Pages = new QStackedLayout(Parent);
 
@@ -93,7 +92,7 @@
     pageNet = new PageNet();
     Pages->addWidget(pageNet);
 
-    pageNetGame = new PageNetGame(Parent, HWForm->gameSettings);
+    pageNetGame = new PageNetGame(Parent);
     Pages->addWidget(pageNetGame);
 
     pageInfo = new PageInfo();
@@ -120,7 +119,7 @@
     pageInGame = new PageInGame();
     Pages->addWidget(pageInGame);
 
-    pageRoomsList = new PageRoomsList(Parent, HWForm->gameSettings);
+    pageRoomsList = new PageRoomsList(Parent);
     Pages->addWidget(pageRoomsList);
 
     pageConnecting = new PageConnecting();
@@ -132,9 +131,6 @@
     pageAdmin = new PageAdmin();
     Pages->addWidget(pageAdmin);
 
-    pageNetType = new PageNetType();
-    Pages->addWidget(pageNetType);
-
     pageCampaign = new PageCampaign();
     Pages->addWidget(pageCampaign);
 
--- a/QTfrontend/ui_hwform.h	Sun Dec 02 00:03:16 2012 +0100
+++ b/QTfrontend/ui_hwform.h	Tue Dec 25 04:45:22 2012 +0100
@@ -41,7 +41,6 @@
 class PageConnecting;
 class PageScheme;
 class PageAdmin;
-class PageNetType;
 class PageDrawMap;
 class PageVideos;
 class QStackedLayout;
@@ -76,7 +75,6 @@
         PageConnecting *pageConnecting;
         PageScheme *pageScheme;
         PageAdmin *pageAdmin;
-        PageNetType *pageNetType;
         PageCampaign *pageCampaign;
         PageDrawMap *pageDrawMap;
         PageVideos *pageVideos;
@@ -86,7 +84,7 @@
 
         void setupUi(HWForm *HWForm);
         void SetupFonts();
-        void SetupPages(QWidget *Parent, HWForm *HWForm);
+        void SetupPages(QWidget *Parent);
 };
 
 #endif // UI_HWFORM_H
--- a/QTfrontend/util/FileEngine.cpp	Sun Dec 02 00:03:16 2012 +0100
+++ b/QTfrontend/util/FileEngine.cpp	Tue Dec 25 04:45:22 2012 +0100
@@ -1,322 +1,380 @@
-/* borrowed from https://github.com/skhaz/qt-physfs-wrapper
- * TODO: add copyright header, determine license
- */
-
-#include "hwpacksmounter.h"
-#include "FileEngine.h"
-
-
-const QString FileEngineHandler::scheme = "physfs:/";
-
-FileEngine::FileEngine(const QString& filename)
-: _handler(NULL)
-, _flags(0)
-{
-    setFileName(filename);
-}
-
-FileEngine::~FileEngine()
-{
-    close();
-}
-
-bool FileEngine::open(QIODevice::OpenMode openMode)
-{
-    close();
-
-    if (openMode & QIODevice::WriteOnly) {
-        _handler = PHYSFS_openWrite(_filename.toUtf8().constData());
-        _flags = QAbstractFileEngine::WriteOwnerPerm | QAbstractFileEngine::WriteUserPerm | QAbstractFileEngine::FileType;
-    }
-
-    else if (openMode & QIODevice::ReadOnly) {
-        _handler = PHYSFS_openRead(_filename.toUtf8().constData());
-    }
-
-    else if (openMode & QIODevice::Append) {
-        _handler = PHYSFS_openAppend(_filename.toUtf8().constData());
-    }
-
-    else {
-        qWarning("Bad file open mode: %d", (int)openMode);
-    }
-
-    if (!_handler) {
-        qWarning("Failed to open %s, reason: %s", _filename.toUtf8().constData(), PHYSFS_getLastError());
-        return false;
-    }
-
-    return true;
-}
-
-bool FileEngine::close()
-{
-    if (isOpened()) {
-        int result = PHYSFS_close(_handler);
-        _handler = NULL;
-        return result != 0;
-    }
-
-    return true;
-}
-
-bool FileEngine::flush()
-{
-    return PHYSFS_flush(_handler) != 0;
-}
-
-qint64 FileEngine::size() const
-{
-    return _size;
-}
-
-qint64 FileEngine::pos() const
-{
-    return PHYSFS_tell(_handler);
-}
-
-bool FileEngine::seek(qint64 pos)
-{
-    return PHYSFS_seek(_handler, pos) != 0;
-}
-
-bool FileEngine::isSequential() const
-{
-    return false;
-}
-
-bool FileEngine::remove()
-{
-    return PHYSFS_delete(_filename.toUtf8().constData()) != 0;
-}
-
-bool FileEngine::mkdir(const QString &dirName, bool createParentDirectories) const
-{
-    Q_UNUSED(createParentDirectories);
-    return PHYSFS_mkdir(dirName.toUtf8().constData()) != 0;
-}
-
-bool FileEngine::rmdir(const QString &dirName, bool recurseParentDirectories) const
-{
-    Q_UNUSED(recurseParentDirectories);
-    return PHYSFS_delete(dirName.toUtf8().constData()) != 0;
-}
-
-bool FileEngine::caseSensitive() const
-{
-    return true;
-}
-
-bool FileEngine::isRelativePath() const
-{
-    return true;
-}
-
-QAbstractFileEngineIterator * FileEngine::beginEntryList(QDir::Filters filters, const QStringList &filterNames)
-{
-    return new FileEngineIterator(filters, filterNames, entryList(filters, filterNames));
-}
-
-QStringList FileEngine::entryList(QDir::Filters filters, const QStringList &filterNames) const
-{
-    Q_UNUSED(filters);
-
-    QString file;
-    QStringList result;
-    char **files = PHYSFS_enumerateFiles(_filename.toUtf8().constData());
-
-    for (char **i = files; *i != NULL; i++) {
-        file = QString::fromUtf8(*i);
-
-        if (filterNames.isEmpty() || QDir::match(filterNames, file)) {
-            result << file;
-        }
-    }
-
-    PHYSFS_freeList(files);
-
-    return result;
-}
-
-QAbstractFileEngine::FileFlags FileEngine::fileFlags(FileFlags type) const
-{
-    return type & _flags;
-}
-
-QString FileEngine::fileName(FileName file) const
-{
-    switch(file)
-    {
-        case QAbstractFileEngine::AbsolutePathName:
-        {
-            QString s(PHYSFS_getWriteDir());
-            return s;
-        }
-        case QAbstractFileEngine::BaseName:
-        {
-            int l = _filename.lastIndexOf('/');
-            QString s = _filename.mid(l + 1);
-            return s;
-        }
-        case QAbstractFileEngine::DefaultName:
-        case QAbstractFileEngine::AbsoluteName:
-        default:
-        {
-            QString s = "physfs:/" + _filename;
-            return s;
-        }
-    }
-}
-
-QDateTime FileEngine::fileTime(FileTime time) const
-{
-
-    switch (time)
-    {
-        case QAbstractFileEngine::ModificationTime:
-        default:
-            return _datetime;
-            break;
-    };
-}
-
-void FileEngine::setFileName(const QString &file)
-{
-    if(file.startsWith(FileEngineHandler::scheme))
-        _filename = file.mid(FileEngineHandler::scheme.size());
-    else
-        _filename = file;
-
-    PHYSFS_Stat stat;
-    if (PHYSFS_stat(_filename.toUtf8().constData(), &stat) != 0) {
-        _size = stat.filesize;
-        _datetime = QDateTime::fromTime_t(stat.modtime);
-//        _flags |= QAbstractFileEngine::WriteUserPerm;
-        _flags |= QAbstractFileEngine::ReadUserPerm;
-        _flags |= QAbstractFileEngine::ExistsFlag;
-
-        switch (stat.filetype)
-        {
-            case PHYSFS_FILETYPE_REGULAR:
-                _flags |= QAbstractFileEngine::FileType;
-                break;
-
-            case PHYSFS_FILETYPE_DIRECTORY:
-                _flags |= QAbstractFileEngine::DirectoryType;
-                break;
-            case PHYSFS_FILETYPE_SYMLINK:
-                _flags |= QAbstractFileEngine::LinkType;
-                break;
-            default: ;
-        }
-    }
-}
-
-bool FileEngine::atEnd() const
-{
-    return PHYSFS_eof(_handler) != 0;
-}
-
-qint64 FileEngine::read(char *data, qint64 maxlen)
-{
-    return PHYSFS_readBytes(_handler, data, maxlen);
-}
-
-qint64 FileEngine::write(const char *data, qint64 len)
-{
-    return PHYSFS_writeBytes(_handler, data, len);
-}
-
-bool FileEngine::isOpened() const
-{
-    return _handler != NULL;
-}
-
-QFile::FileError FileEngine::error() const
-{
-    return QFile::UnspecifiedError;
-}
-
-QString FileEngine::errorString() const
-{
-    return PHYSFS_getLastError();
-}
-
-bool FileEngine::supportsExtension(Extension extension) const
-{
-    return extension == QAbstractFileEngine::AtEndExtension;
-}
-
-
-
-FileEngineHandler::FileEngineHandler(char *argv0)
-{
-    PHYSFS_init(argv0);
-}
-
-FileEngineHandler::~FileEngineHandler()
-{
-    PHYSFS_deinit();
-}
-
-QAbstractFileEngine* FileEngineHandler::create(const QString &filename) const
-{
-    if (filename.startsWith(scheme))
-        return new FileEngine(filename.mid(scheme.size()));
-    else
-        return NULL;
-}
-
-void FileEngineHandler::mount(const QString &path)
-{
-    PHYSFS_mount(path.toUtf8().constData(), NULL, 1);
-}
-
-void FileEngineHandler::mount(const QString & path, const QString & mountPoint)
-{
-    PHYSFS_mount(path.toUtf8().constData(), mountPoint.toUtf8().constData(), 1);
-}
-
-void FileEngineHandler::setWriteDir(const QString &path)
-{
-    PHYSFS_setWriteDir(path.toUtf8().constData());
-}
-
-void FileEngineHandler::mountPacks()
-{
-    hedgewarsMountPackages();
-}
-
-
-FileEngineIterator::FileEngineIterator(QDir::Filters filters, const QStringList &nameFilters, const QStringList &entries)
-    : QAbstractFileEngineIterator(filters, nameFilters)
-{
-    m_entries = entries;
-
-    /* heck.. docs are unclear on this
-     * QDirIterator puts iterator before first entry
-     * but QAbstractFileEngineIterator example puts iterator on first entry
-     * though QDirIterator approach seems to be the right one
-     */
-
-    m_index = -1;
-}
-
-bool FileEngineIterator::hasNext() const
-{
-    return m_index < m_entries.size() - 1;
-}
-
-QString FileEngineIterator::next()
-{
-   if (!hasNext())
-       return QString();
-
-   ++m_index;
-   return currentFilePath();
-}
-
-QString FileEngineIterator::currentFileName() const
-{
-    return m_entries.at(m_index);
-}
+/* borrowed from https://github.com/skhaz/qt-physfs-wrapper
+ * TODO: add copyright header, determine license
+ */
+
+#include "hwpacksmounter.h"
+#include "FileEngine.h"
+
+
+const QString FileEngineHandler::scheme = "physfs:/";
+
+FileEngine::FileEngine(const QString& filename)
+    : m_handle(NULL)
+    , m_size(0)
+    , m_flags(0)
+    , m_bufferSet(false)
+    , m_readWrite(false)
+{
+    setFileName(filename);
+}
+
+FileEngine::~FileEngine()
+{
+    close();
+}
+
+bool FileEngine::open(QIODevice::OpenMode openMode)
+{
+    close();
+
+    if ((openMode & QIODevice::ReadWrite) == QIODevice::ReadWrite) {
+        m_handle = PHYSFS_openAppend(m_fileName.toUtf8().constData());
+        if(m_handle)
+        {
+            m_readWrite = true;
+            seek(0);
+        }
+    }
+
+    else if (openMode & QIODevice::WriteOnly) {
+        m_handle = PHYSFS_openWrite(m_fileName.toUtf8().constData());
+        m_flags = QAbstractFileEngine::WriteOwnerPerm | QAbstractFileEngine::WriteUserPerm | QAbstractFileEngine::FileType;
+    }
+
+    else if (openMode & QIODevice::ReadOnly) {
+        m_handle = PHYSFS_openRead(m_fileName.toUtf8().constData());
+    }
+
+    else if (openMode & QIODevice::Append) {
+        m_handle = PHYSFS_openAppend(m_fileName.toUtf8().constData());
+    }
+
+    else {
+        qWarning("[PHYSFS] Bad file open mode: %d", (int)openMode);
+    }
+
+    if (!m_handle) {
+        qWarning("[PHYSFS] Failed to open %s, reason: %s", m_fileName.toUtf8().constData(), PHYSFS_getLastError());
+        return false;
+    }
+
+    return true;
+}
+
+bool FileEngine::close()
+{
+    if (isOpened()) {
+        int result = PHYSFS_close(m_handle);
+        m_handle = NULL;
+        return result != 0;
+    }
+
+    return true;
+}
+
+bool FileEngine::flush()
+{
+    return PHYSFS_flush(m_handle) != 0;
+}
+
+qint64 FileEngine::size() const
+{
+    return m_size;
+}
+
+qint64 FileEngine::pos() const
+{
+    return PHYSFS_tell(m_handle);
+}
+
+bool FileEngine::setSize(qint64 size)
+{
+    if(size == 0)
+    {
+        m_size = 0;
+        return open(QIODevice::WriteOnly);
+    }
+    else
+        return false;
+}
+
+bool FileEngine::seek(qint64 pos)
+{
+    bool ok = PHYSFS_seek(m_handle, pos) != 0;
+
+    return ok;
+}
+
+bool FileEngine::isSequential() const
+{
+    return false;
+}
+
+bool FileEngine::remove()
+{
+    return PHYSFS_delete(m_fileName.toUtf8().constData()) != 0;
+}
+
+bool FileEngine::mkdir(const QString &dirName, bool createParentDirectories) const
+{
+    Q_UNUSED(createParentDirectories);
+
+    return PHYSFS_mkdir(dirName.toUtf8().constData()) != 0;
+}
+
+bool FileEngine::rmdir(const QString &dirName, bool recurseParentDirectories) const
+{
+    Q_UNUSED(recurseParentDirectories);
+
+    return PHYSFS_delete(dirName.toUtf8().constData()) != 0;
+}
+
+bool FileEngine::caseSensitive() const
+{
+    return true;
+}
+
+bool FileEngine::isRelativePath() const
+{
+    return false;
+}
+
+QAbstractFileEngineIterator * FileEngine::beginEntryList(QDir::Filters filters, const QStringList &filterNames)
+{
+    return new FileEngineIterator(filters, filterNames, entryList(filters, filterNames));
+}
+
+QStringList FileEngine::entryList(QDir::Filters filters, const QStringList &filterNames) const
+{
+    Q_UNUSED(filters);
+
+    QString file;
+    QStringList result;
+    char **files = PHYSFS_enumerateFiles(m_fileName.toUtf8().constData());
+
+    for (char **i = files; *i != NULL; i++) {
+        file = QString::fromUtf8(*i);
+
+        if (filterNames.isEmpty() || QDir::match(filterNames, file)) {
+            result << file;
+        }
+    }
+
+    PHYSFS_freeList(files);
+
+    return result;
+}
+
+QAbstractFileEngine::FileFlags FileEngine::fileFlags(FileFlags type) const
+{
+    return type & m_flags;
+}
+
+QString FileEngine::fileName(FileName file) const
+{
+    switch(file)
+    {
+        case QAbstractFileEngine::AbsolutePathName:
+        {
+            QString s(PHYSFS_getWriteDir());
+            return s;
+        }
+        case QAbstractFileEngine::BaseName:
+        {
+            int l = m_fileName.lastIndexOf('/');
+            QString s = m_fileName.mid(l + 1);
+            return s;
+        }
+        case QAbstractFileEngine::DefaultName:
+        case QAbstractFileEngine::AbsoluteName:
+        default:
+        {
+            QString s = "physfs:/" + m_fileName;
+            return s;
+        }
+    }
+}
+
+QDateTime FileEngine::fileTime(FileTime time) const
+{
+    switch (time)
+    {
+        case QAbstractFileEngine::ModificationTime:
+        default:
+            return m_date;
+            break;
+    };
+}
+
+void FileEngine::setFileName(const QString &file)
+{
+    if(file.startsWith(FileEngineHandler::scheme))
+        m_fileName = file.mid(FileEngineHandler::scheme.size());
+    else
+        m_fileName = file;
+    PHYSFS_Stat stat;
+    if (PHYSFS_stat(m_fileName.toUtf8().constData(), &stat) != 0) {
+        m_size = stat.filesize;
+        m_date = QDateTime::fromTime_t(stat.modtime);
+//        m_flags |= QAbstractFileEngine::WriteOwnerPerm;
+        m_flags |= QAbstractFileEngine::ReadOwnerPerm;
+        m_flags |= QAbstractFileEngine::ReadUserPerm;
+        m_flags |= QAbstractFileEngine::ExistsFlag;
+        m_flags |= QAbstractFileEngine::LocalDiskFlag;
+
+        switch (stat.filetype)
+        {
+            case PHYSFS_FILETYPE_REGULAR:
+                m_flags |= QAbstractFileEngine::FileType;
+                break;
+            case PHYSFS_FILETYPE_DIRECTORY:
+                m_flags |= QAbstractFileEngine::DirectoryType;
+                break;
+            case PHYSFS_FILETYPE_SYMLINK:
+                m_flags |= QAbstractFileEngine::LinkType;
+                break;
+            default: ;
+        }
+    }
+}
+
+bool FileEngine::atEnd() const
+{
+    return PHYSFS_eof(m_handle) != 0;
+}
+
+qint64 FileEngine::read(char *data, qint64 maxlen)
+{
+    if(m_readWrite)
+    {
+        if(pos() == 0)
+            open(QIODevice::ReadOnly);
+        else
+            return -1;
+    }
+
+    qint64 len = PHYSFS_readBytes(m_handle, data, maxlen);
+    return len;
+}
+
+qint64 FileEngine::readLine(char *data, qint64 maxlen)
+{
+    if(!m_bufferSet)
+    {
+        PHYSFS_setBuffer(m_handle, 4096);
+        m_bufferSet = true;
+    }
+
+    qint64 bytesRead = 0;
+    while(PHYSFS_readBytes(m_handle, data, 1)
+          && maxlen
+          && (*data == '\n'))
+    {
+        ++data;
+        --maxlen;
+        ++bytesRead;
+    }
+
+    return bytesRead;
+}
+
+qint64 FileEngine::write(const char *data, qint64 len)
+{
+    return PHYSFS_writeBytes(m_handle, data, len);
+}
+
+bool FileEngine::isOpened() const
+{
+    return m_handle != NULL;
+}
+
+QFile::FileError FileEngine::error() const
+{
+    return QFile::UnspecifiedError;
+}
+
+QString FileEngine::errorString() const
+{
+    return PHYSFS_getLastError();
+}
+
+bool FileEngine::supportsExtension(Extension extension) const
+{
+    return
+            (extension == QAbstractFileEngine::AtEndExtension)
+            || (extension == QAbstractFileEngine::FastReadLineExtension)
+            ;
+}
+
+
+FileEngineHandler::FileEngineHandler(char *argv0)
+{
+    PHYSFS_init(argv0);
+}
+
+FileEngineHandler::~FileEngineHandler()
+{
+    PHYSFS_deinit();
+}
+
+QAbstractFileEngine* FileEngineHandler::create(const QString &filename) const
+{
+    if (filename.startsWith(scheme))
+        return new FileEngine(filename);
+    else
+        return NULL;
+}
+
+void FileEngineHandler::mount(const QString &path)
+{
+    PHYSFS_mount(path.toUtf8().constData(), NULL, 1);
+}
+
+void FileEngineHandler::mount(const QString & path, const QString & mountPoint)
+{
+    PHYSFS_mount(path.toUtf8().constData(), mountPoint.toUtf8().constData(), 1);
+}
+
+void FileEngineHandler::setWriteDir(const QString &path)
+{
+    PHYSFS_setWriteDir(path.toUtf8().constData());
+}
+
+void FileEngineHandler::mountPacks()
+{
+    hedgewarsMountPackages();
+}
+
+
+FileEngineIterator::FileEngineIterator(QDir::Filters filters, const QStringList &nameFilters, const QStringList &entries)
+    : QAbstractFileEngineIterator(filters, nameFilters)
+{
+    m_entries = entries;
+
+    /* heck.. docs are unclear on this
+     * QDirIterator puts iterator before first entry
+     * but QAbstractFileEngineIterator example puts iterator on first entry
+     * though QDirIterator approach seems to be the right one
+     */
+
+    m_index = -1;
+}
+
+bool FileEngineIterator::hasNext() const
+{
+    return m_index < m_entries.size() - 1;
+}
+
+QString FileEngineIterator::next()
+{
+   if (!hasNext())
+       return QString();
+
+   ++m_index;
+   return currentFilePath();
+}
+
+QString FileEngineIterator::currentFileName() const
+{
+    return m_entries.at(m_index);
+}
--- a/QTfrontend/util/FileEngine.h	Sun Dec 02 00:03:16 2012 +0100
+++ b/QTfrontend/util/FileEngine.h	Tue Dec 25 04:45:22 2012 +0100
@@ -22,6 +22,7 @@
         virtual bool flush();
         virtual qint64 size() const;
         virtual qint64 pos() const;
+        virtual bool setSize(qint64 size);
         virtual bool seek(qint64 pos);
         virtual bool isSequential() const;
         virtual bool remove();
@@ -38,6 +39,7 @@
         bool atEnd() const;
 
         virtual qint64 read(char *data, qint64 maxlen);
+        virtual qint64 readLine(char *data, qint64 maxlen);
         virtual qint64 write(const char *data, qint64 len);
 
         bool isOpened() const;
@@ -48,11 +50,13 @@
         virtual bool supportsExtension(Extension extension) const;
 
     private:
-        PHYSFS_file *_handler;
-        qint64 _size;
-        FileFlags _flags;
-        QString _filename;
-        QDateTime _datetime;
+        PHYSFS_file *m_handle;
+        qint64 m_size;
+        FileFlags m_flags;
+        QString m_fileName;
+        QDateTime m_date;
+        bool m_bufferSet;
+        bool m_readWrite;
 };
 
 class FileEngineHandler : public QAbstractFileEngineHandler
--- a/QTfrontend/util/SDLInteraction.cpp	Sun Dec 02 00:03:16 2012 +0100
+++ b/QTfrontend/util/SDLInteraction.cpp	Tue Dec 25 04:45:22 2012 +0100
@@ -25,9 +25,13 @@
 #include "SDL_mixer.h"
 
 #include "HWApplication.h"
+#include "hwform.h" /* you know, we could just put a config singleton lookup function in gameuiconfig or something... */
+#include "gameuiconfig.h"
 
 #include "SDLInteraction.h"
 
+#include "physfsrwops.h"
+
 extern char sdlkeys[1024][2][128];
 extern char xb360buttons[][128];
 extern char xb360dpad[128];
@@ -184,16 +188,18 @@
         return;
 
     SDL_Init(SDL_INIT_AUDIO);
-    Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 1024);
-    m_audioInitialized = true;
+    if(!Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 1024)) /* should we keep trying, or just turn off permanently? */
+        m_audioInitialized = true;
 }
 
 
 void SDLInteraction::playSoundFile(const QString & soundFile)
 {
+    if (!HWForm::config || !HWForm::config->isFrontendSoundEnabled()) return;
     SDLAudioInit();
+    if (!m_audioInitialized) return;
     if (!m_soundMap->contains(soundFile))
-        m_soundMap->insert(soundFile, Mix_LoadWAV(soundFile.toLocal8Bit().constData()));
+        m_soundMap->insert(soundFile, Mix_LoadWAV_RW(PHYSFSRWOPS_openRead(soundFile.toLocal8Bit().constData()), 1));
 
     //FIXME: this is a hack, but works as long as we have few concurrent playing sounds
     if (Mix_Playing(lastchannel) == false)
@@ -230,9 +236,10 @@
         return;
 
     SDLAudioInit();
+    if (!m_audioInitialized) return;
 
     if (m_music == NULL)
-        m_music = Mix_LoadMUS(m_musicTrack.toLocal8Bit().constData());
+        m_music = Mix_LoadMUS_RW(PHYSFSRWOPS_openRead(m_musicTrack.toLocal8Bit().constData()));
 
     Mix_VolumeMusic(MIX_MAX_VOLUME - 28);
     Mix_FadeInMusic(m_music, -1, 1750);
--- a/QTfrontend/util/namegen.cpp	Sun Dec 02 00:03:16 2012 +0100
+++ b/QTfrontend/util/namegen.cpp	Tue Dec 25 04:45:22 2012 +0100
@@ -125,22 +125,21 @@
     QStringList list;
 
     // find .txt to load the names from
-    QFile * file = new QFile(QString("physfs://Names/%1.txt").arg(filename));
+    QFile file(QString("physfs://Names/%1.txt").arg(filename));
 
-    if (file->exists() && file->open(QIODevice::ReadOnly | QIODevice::Text))
+    if (file.open(QIODevice::ReadOnly | QIODevice::Text))
     {
-        QTextStream in(file);
-        while (!in.atEnd())
+        QTextStream in(&file);
+        QString line;
+        do
         {
-            QString line = in.readLine();
+            line = in.readLine();
+
             if(!line.isEmpty())
                 list.append(line);
-        }
+        } while (!line.isNull());
     }
 
-    // this QFile isn't needed any further
-    delete file;
-
     if (list.size() == 0)
         list.append(filename);
 
@@ -153,22 +152,21 @@
     QStringList list;
 
     // find .cfg to load the dicts from
-    QFile * file = new QFile(QString("physfs://Names/%1.cfg").arg(hatname));
+    QFile file(QString("physfs://Names/%1.cfg").arg(hatname));
 
-    if (file->exists() && file->open(QIODevice::ReadOnly | QIODevice::Text))
+    if (file.open(QIODevice::ReadOnly | QIODevice::Text))
     {
-        QTextStream in(file);
-        while (!in.atEnd())
+        QTextStream in(&file);
+        QString line;
+        do
         {
-            QString line = in.readLine();
+            line = in.readLine();
+
             if(!line.isEmpty())
                 list.append(line);
-        }
+        } while (!line.isNull());
     }
 
-    // this QFile isn't needed any further
-    delete file;
-
     if (list.size() == 0)
         list.append(QString("generic"));
 
--- a/README	Sun Dec 02 00:03:16 2012 +0100
+++ b/README	Tue Dec 25 04:45:22 2012 +0100
@@ -5,3 +5,10 @@
 Source:
 Copyright 2004-2011 Andrey Korotaev <unC0Rr@gmail.com>
 Portions copyright 2006-2008 Igor Ulyanov aka Displacer <iulyanov@gmail.com>
+
+Instructions:
+depending on your system, consult our wiki at:
+- http://code.google.com/p/hedgewars/wiki/BuildingOnLinux
+- http://code.google.com/p/hedgewars/wiki/BuildingOnWindows
+- http://code.google.com/p/hedgewars/wiki/BuildingOnMac
+
--- a/README_WINDOWS	Sun Dec 02 00:03:16 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-For instructions, please visit: http://code.google.com/p/hedgewars/wiki/BuildingOnWindows
--- a/bin/CMakeLists.txt	Sun Dec 02 00:03:16 2012 +0100
+++ b/bin/CMakeLists.txt	Tue Dec 25 04:45:22 2012 +0100
@@ -1,9 +1,9 @@
 if(WIN32 AND NOT UNIX)
-	file(GLOB DLLs *.dll)
-	file(GLOB ICOs *.ico)
-	
-	install(FILES
-		${DLLs}
-		${ICOs}
-		DESTINATION bin)
+    file(GLOB DLLs *.dll)
+    file(GLOB ICOs *.ico)
+
+    install(FILES
+        ${DLLs}
+        ${ICOs}
+        DESTINATION ${target_library_install_dir})
 endif(WIN32 AND NOT UNIX)
--- a/cmake_modules/FindFFMPEG.cmake	Sun Dec 02 00:03:16 2012 +0100
+++ b/cmake_modules/FindFFMPEG.cmake	Tue Dec 25 04:45:22 2012 +0100
@@ -16,17 +16,23 @@
 #  BSD license.
 #
 
+set(FFMPEG_FOUND FALSE)
+
 if (FFMPEG_LIBRARIES AND FFMPEG_INCLUDE_DIR)
   # in cache already
   set(FFMPEG_FOUND TRUE)
 else (FFMPEG_LIBRARIES AND FFMPEG_INCLUDE_DIR)
+  # silence output option
+  if (FFMPEG_FIND_QUIETLY)
+    set(VERBOSITY "QUIET")
+  endif ()
   # use pkg-config to get the directories and then use these values
   # in the FIND_PATH() and FIND_LIBRARY() calls
   find_package(PkgConfig)
   if (PKG_CONFIG_FOUND)
-    pkg_check_modules(_FFMPEG_AVCODEC libavcodec)
-    pkg_check_modules(_FFMPEG_AVFORMAT libavformat)
-    pkg_check_modules(_FFMPEG_AVUTIL libavutil)
+    pkg_check_modules(_FFMPEG_AVCODEC libavcodec ${VERBOSITY})
+    pkg_check_modules(_FFMPEG_AVFORMAT libavformat ${VERBOSITY})
+    pkg_check_modules(_FFMPEG_AVUTIL libavutil ${VERBOSITY})
   endif (PKG_CONFIG_FOUND)
 
   find_path(FFMPEG_AVCODEC_INCLUDE_DIR
@@ -74,10 +80,6 @@
       ${FFMPEG_LIBAVFORMAT}
       ${FFMPEG_LIBAVUTIL}
     )
-    if (APPLE)
-      set(FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} "bz2" "-framework CoreVideo" "-framework VideoDecodeAcceleration")
-    endif(APPLE)
-
   endif (FFMPEG_FOUND)
 
   if (FFMPEG_FOUND)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cmake_modules/FindFreepascal.cmake	Tue Dec 25 04:45:22 2012 +0100
@@ -0,0 +1,37 @@
+# Load Freepascal
+if (FPC)
+    set(FPC_EXECUTABLE ${FPC})
+else()
+    find_program(FPC_EXECUTABLE
+        NAMES fpc
+        PATHS /opt/local/bin /usr/local/bin /usr/bin)
+endif()
+
+# Check Freepascal version
+if (FPC_EXECUTABLE)
+    exec_program(${FPC_EXECUTABLE} ARGS "-v" OUTPUT_VARIABLE FPC_VERSION_FULL)
+
+    string(REGEX MATCH "[0-9]+\\.[0-9]+" FPC_VERSION_LONG "${FPC_VERSION_FULL}")
+    string(REGEX REPLACE "([0-9]+\\.[0-9]+)" "\\1" FPC_VERSION "${FPC_VERSION_LONG}")
+    message(STATUS "Found Freepascal: ${FPC_EXECUTABLE} (version ${FPC_VERSION})")
+else()
+    message(FATAL_ERROR "Could NOT find Freepascal")
+endif()
+
+# Check for noexecstack flag support
+message(STATUS "Checking whether linker needs explicit noexecstack")
+set(NOEXECSTACK_FLAGS "-k-z" "-knoexecstack")
+file(WRITE ${EXECUTABLE_OUTPUT_PATH}/checkstack.pas "begin end.")
+
+execute_process(COMMAND ${FPC_EXECUTABLE} ${NOEXECSTACK_FLAGS} checkstack.pas
+    WORKING_DIRECTORY ${EXECUTABLE_OUTPUT_PATH}
+    RESULT_VARIABLE TEST_NOEXECSTACK
+    OUTPUT_QUIET ERROR_QUIET)
+
+if (TEST_NOEXECSTACK)
+    set(NOEXECSTACK_FLAGS "")
+    message(STATUS "Checking whether linker needs explicit noexecstack -- no")
+else(TEST_NOEXECSTACK)
+    message(STATUS "Checking whether linker needs explicit noexecstack -- yes")
+endif(TEST_NOEXECSTACK)
+
--- a/doc/protocol.txt	Sun Dec 02 00:03:16 2012 +0100
+++ b/doc/protocol.txt	Tue Dec 25 04:45:22 2012 +0100
@@ -1,34 +1,35 @@
-	'?'             ping?
-	'!'             pong!
-	'l','L'         срабатывание команд     -left, +left
-	'r','R'                                 -right, +right
-	'u','U'                                 -up, +up
-	'd','D'                                 -down, +down
-	'z', 'Z'                                -precise, +precise
-	'N'             срабатывание команды /nextturn
-	'S'                                  /switch
-	's' + <текст>   /say
-	'+'             пустой пакет для постоянности лага
-	'1'..'5'        /timer 1..5
-	chr(128+№)     /slot №
-	'w'             /setweap
-	'p'             /put
-	'j'             /ljump
-	'J'             /hjump
-	'E' + <текст>   сообщение об ошибке
-	','             /skip
-	'K'             вывести сообщение из KB
-	'Q'             выход через команду /quit
-	'q'             выход по причине окончания игры
-	't' + №        /taunt №
-	'F' + <team>    команда team вылетела в сетевой игре
+    '?'             ping?
+    '!'             pong!
+    'l','L'         срабатывание команд     -left, +left
+    'r','R'                                 -right, +right
+    'u','U'                                 -up, +up
+    'd','D'                                 -down, +down
+    'z', 'Z'                                -precise, +precise
+    'N'             срабатывание команды /nextturn
+    'S'                                  /switch
+    's' + <текст>   /say
+    '+'             пустой пакет для постоянности лага
+    '1'..'5'        /timer 1..5
+    chr(128+№)     /slot №
+    'w'             /setweap
+    'p'             /put
+    'j'             /ljump
+    'J'             /hjump
+    'E' + <текст>   сообщение об ошибке
+    ','             /skip
+    't' + №         /taunt №
 
 фронтенд клиенту:
-	'e' + <команда> выполнить "/<команда>"
-	'T' + {L,N,D}   тип игры (локальная, сетевая, просмотр демо)
-	'W' + <текст>   сообщение о нефатальной ошибке
+    'e' + <команда> выполнить "/<команда>"
+    'T' + {L,N,D}   тип игры (локальная, сетевая, просмотр демо)
+    'W' + <текст>   сообщение о нефатальной ошибке
+    'F' + <team>    команда team вылетела в сетевой игре
+    'o'             stop syncing, game over!
 
 Клиент фронтенду:
-	'C'             запрос текущего конфига игры
-	'q'             выход по причине окончания демки
-	'i'             статистика
+    'C'             запрос текущего конфига игры
+    'q'             выход по причине окончания демки
+    'i'             статистика
+    'K'             вывести сообщение из KB
+    'Q'             выход через команду /quit
+    'q'             выход по причине окончания игры
--- a/gameServer/Actions.hs	Sun Dec 02 00:03:16 2012 +0100
+++ b/gameServer/Actions.hs	Tue Dec 25 04:45:22 2012 +0100
@@ -52,9 +52,10 @@
     | KickRoomClient ClientIndex
     | BanClient NominalDiffTime B.ByteString ClientIndex
     | BanIP B.ByteString NominalDiffTime B.ByteString
+    | BanNick B.ByteString NominalDiffTime B.ByteString
     | BanList
     | Unban B.ByteString
-    | ChangeMaster
+    | ChangeMaster (Maybe ClientIndex)
     | RemoveClientTeams ClientIndex
     | ModifyClient (ClientInfo -> ClientInfo)
     | ModifyClient2 ClientIndex (ClientInfo -> ClientInfo)
@@ -73,7 +74,7 @@
     | RestartServer
     | AddNick2Bans B.ByteString B.ByteString UTCTime
     | AddIP2Bans B.ByteString B.ByteString UTCTime
-    | CheckBanned
+    | CheckBanned Bool
     | SaveReplay
 
 
@@ -154,7 +155,7 @@
 
     when loggedIn $ processAction $ AnswerClients clientsChans ["LOBBY:LEFT", clNick, msg]
 
-    mapM processAction
+    mapM_ processAction
         [
         AnswerClients [chan] ["BYE", msg]
         , ModifyClient (\c -> c{nick = "", logonPassed = False}) -- this will effectively hide client from others while he isn't deleted from list
@@ -234,7 +235,7 @@
 
     if master then
         if playersNum > 1 then
-            mapM_ processAction [ChangeMaster, NoticeMessage AdminLeft, RemoveClientTeams ci, AnswerClients chans ["LEFT", clNick, msg]]
+            mapM_ processAction [ChangeMaster Nothing, NoticeMessage AdminLeft, RemoveClientTeams ci, AnswerClients chans ["LEFT", clNick, msg]]
             else
             processAction RemoveRoom
         else
@@ -250,26 +251,27 @@
         moveClientToLobby rnc ci
 
 
-processAction ChangeMaster = do
+processAction (ChangeMaster delegateId)= do
     (Just ci) <- gets clientIndex
     proto <- client's clientProto
     ri <- clientRoomA
     rnc <- gets roomsClients
-    newMasterId <- liftM (last . filter (/= ci)) . io $ roomClientsIndicesM rnc ri
+    newMasterId <- liftM (\ids -> fromMaybe (last . filter (/= ci) $ ids) delegateId) . io $ roomClientsIndicesM rnc ri
     newMaster <- io $ client'sM rnc id newMasterId
     oldRoomName <- io $ room'sM rnc name ri
     oldMaster <- client's nick
+    kicked <- client's isKickedFromServer
     thisRoomChans <- liftM (map sendChan) $ roomClientsS ri
-    let newRoomName = if proto < 42 then nick newMaster else oldRoomName
+    let newRoomName = if (proto < 42) || kicked then nick newMaster else oldRoomName
     mapM_ processAction [
         ModifyRoom (\r -> r{masterID = newMasterId
                 , name = newRoomName
                 , isRestrictedJoins = False
                 , isRestrictedTeams = False
+                , isRegisteredOnly = False
                 , readyPlayers = if isReady newMaster then readyPlayers r else readyPlayers r + 1})
         , ModifyClient2 newMasterId (\c -> c{isMaster = True, isReady = True})
         , AnswerClients [sendChan newMaster] ["ROOM_CONTROL_ACCESS", "1"]
-        , AnswerClients thisRoomChans ["WARNING", "New room admin is " `B.append` nick newMaster]
         , AnswerClients thisRoomChans ["CLIENT_FLAGS", "-h", oldMaster]
         , AnswerClients thisRoomChans ["CLIENT_FLAGS", "+hr", nick newMaster]
         ]
@@ -361,6 +363,7 @@
             )
         : UnreadyRoomClients
         : SendUpdateOnThisRoom
+        : AnswerClients thisRoomChans ["ROUND_FINISHED"]
         : answerRemovedTeams
 
 
@@ -422,17 +425,14 @@
     haveSameNick <- liftM (not . null . tail . filter (\c -> caseInsensitiveCompare (nick c) n)) allClientsS
     if haveSameNick then
         if p < 38 then
-            mapM_ processAction [ByeClient "Nickname is already in use", removeNick]
+            processAction $ ByeClient "Nickname is already in use"
             else
-            mapM_ processAction [NoticeMessage NickAlreadyInUse, removeNick]
+            processAction $ NoticeMessage NickAlreadyInUse
         else
         do
         db <- gets (dbQueries . serverInfo)
         io $ writeChan db $ CheckAccount ci (hashUnique uid) n h
         return ()
-   where
-       removeNick = ModifyClient (\c -> c{nick = ""})
-
 
 processAction ClearAccountsCache = do
     dbq <- gets (dbQueries . serverInfo)
@@ -440,17 +440,25 @@
     return ()
 
 
-processAction (ProcessAccountInfo info) =
+processAction (ProcessAccountInfo info) = do
     case info of
         HasAccount passwd isAdmin -> do
-            chan <- client's sendChan
-            mapM_ processAction [AnswerClients [chan] ["ASKPASSWORD"], ModifyClient (\c -> c{webPassword = passwd, isAdministrator = isAdmin})]
-        Guest ->
-            processAction JoinLobby
+            b <- isBanned
+            when (not b) $ do
+                chan <- client's sendChan
+                mapM_ processAction [AnswerClients [chan] ["ASKPASSWORD"], ModifyClient (\c -> c{webPassword = passwd, isAdministrator = isAdmin})]
+        Guest -> do
+            b <- isBanned
+            when (not b) $
+                processAction JoinLobby
         Admin -> do
             mapM_ processAction [ModifyClient (\cl -> cl{isAdministrator = True}), JoinLobby]
             chan <- client's sendChan
             processAction $ AnswerClients [chan] ["ADMIN_ACCESS"]
+    where
+    isBanned = do
+        processAction $ CheckBanned False
+        liftM B.null $ client's nick
 
 
 processAction JoinLobby = do
@@ -479,8 +487,9 @@
     clHost <- client's host
     currentTime <- io getCurrentTime
     mapM_ processAction [
-        AddIP2Bans clHost "60 seconds cooldown after kick" (addUTCTime 60 currentTime),
-        ByeClient "Kicked"
+        AddIP2Bans clHost "60 seconds cooldown after kick" (addUTCTime 60 currentTime)
+        , ModifyClient (\c -> c{isKickedFromServer = True})
+        , ByeClient "Kicked"
         ]
 
 
@@ -494,24 +503,43 @@
         , KickClient banId
         ]
 
+
 processAction (BanIP ip seconds reason) = do
     currentTime <- io getCurrentTime
     let msg = B.concat ["Ban for ", B.pack . show $ seconds, " (", reason, ")"]
     processAction $
         AddIP2Bans ip msg (addUTCTime seconds currentTime)
 
+
+processAction (BanNick n seconds reason) = do
+    currentTime <- io getCurrentTime
+    let msg =
+            if seconds > 60 * 60 * 24 * 365 then
+                B.concat ["Permanent ban (", reason, ")"]
+                else
+                B.concat ["Ban for ", B.pack . show $ seconds, " (", reason, ")"]
+    processAction $
+        AddNick2Bans n msg (addUTCTime seconds currentTime)
+
+
 processAction BanList = do
+    time <- io $ getCurrentTime
     ch <- client's sendChan
-    b <- gets (B.pack . unlines . map show . bans . serverInfo)
+    b <- gets (B.intercalate "\n" . concatMap (ban2Str time) . bans . serverInfo)
     processAction $
         AnswerClients [ch] ["BANLIST", b]
+    where
+        ban2Str time (BanByIP b r t) = ["I", b, r, B.pack . show $ t `diffUTCTime` time]
+        ban2Str time (BanByNick b r t) = ["N", b, r, B.pack . show $ t `diffUTCTime` time]
+
 
 processAction (Unban entry) = do
-    processAction $ ModifyServerInfo (\s -> s{bans = filter f $ bans s})
+    processAction $ ModifyServerInfo (\s -> s{bans = filter (not . f) $ bans s})
     where
         f (BanByIP bip _ _) = bip == entry
         f (BanByNick bn _ _) = bn == entry
 
+
 processAction (KickRoomClient kickId) = do
     modify (\s -> s{clientIndex = Just kickId})
     ch <- client's sendChan
@@ -533,7 +561,7 @@
     mapM_ processAction
         [
             AnswerClients [sendChan cl] ["CONNECTED", "Hedgewars server http://www.hedgewars.org/", serverVersion]
-            , CheckBanned
+            , CheckBanned True
             , AddIP2Bans (host cl) "Reconnected too fast" (addUTCTime 10 $ connectTime cl)
         ]
 
@@ -547,21 +575,22 @@
     when (not $ ci `Set.member` rc)
         $ processAction $ ModifyServerInfo (\s -> s{bans = BanByIP ip reason expiring : bans s})
 
-processAction CheckBanned = do
+processAction (CheckBanned byIP) = do
     clTime <- client's connectTime
     clNick <- client's nick
     clHost <- client's host
     si <- gets serverInfo
     let validBans = filter (checkNotExpired clTime) $ bans si
-    let ban = L.find (checkBan clHost clNick) $ validBans
+    let ban = L.find (checkBan byIP clHost clNick) $ validBans
     mapM_ processAction $
         ModifyServerInfo (\s -> s{bans = validBans})
         : [ByeClient (getBanReason $ fromJust ban) | isJust ban]
     where
         checkNotExpired testTime (BanByIP _ _ time) = testTime `diffUTCTime` time <= 0
         checkNotExpired testTime (BanByNick _ _ time) = testTime `diffUTCTime` time <= 0
-        checkBan ip _ (BanByIP bip _ _) = bip `B.isPrefixOf` ip
-        checkBan _ n (BanByNick bn _ _) = bn == n
+        checkBan True ip _ (BanByIP bip _ _) = bip `B.isPrefixOf` ip
+        checkBan False _ n (BanByNick bn _ _) = caseInsensitiveCompare bn n
+        checkBan _ _ _ _ = False
         getBanReason (BanByIP _ msg _) = msg
         getBanReason (BanByNick _ msg _) = msg
 
--- a/gameServer/CMakeLists.txt	Sun Dec 02 00:03:16 2012 +0100
+++ b/gameServer/CMakeLists.txt	Tue Dec 25 04:45:22 2012 +0100
@@ -42,4 +42,4 @@
 
 add_custom_target(hedgewars-server ALL DEPENDS "${EXECUTABLE_OUTPUT_PATH}/hedgewars-server${CMAKE_EXECUTABLE_SUFFIX}")
 
-install(PROGRAMS "${EXECUTABLE_OUTPUT_PATH}/hedgewars-server${CMAKE_EXECUTABLE_SUFFIX}" DESTINATION ${target_dir})
+install(PROGRAMS "${EXECUTABLE_OUTPUT_PATH}/hedgewars-server${CMAKE_EXECUTABLE_SUFFIX}" DESTINATION ${target_binary_install_dir})
--- a/gameServer/CoreTypes.hs	Sun Dec 02 00:03:16 2012 +0100
+++ b/gameServer/CoreTypes.hs	Tue Dec 25 04:45:22 2012 +0100
@@ -36,6 +36,7 @@
         isReady :: !Bool,
         isInGame :: Bool,
         isAdministrator :: Bool,
+        isKickedFromServer :: Bool,
         clientClan :: Maybe B.ByteString,
         teamsInGame :: Word
     }
@@ -100,6 +101,7 @@
         readyPlayers :: !Int,
         isRestrictedJoins :: Bool,
         isRestrictedTeams :: Bool,
+        isRegisteredOnly :: Bool,
         roomBansList :: ![B.ByteString],
         mapParams :: Map.Map B.ByteString B.ByteString,
         params :: Map.Map B.ByteString [B.ByteString]
@@ -118,6 +120,7 @@
         0
         False
         False
+        False
         []
         (
             Map.fromList $ Prelude.zipWith (,)
--- a/gameServer/HWProtoInRoomState.hs	Sun Dec 02 00:03:16 2012 +0100
+++ b/gameServer/HWProtoInRoomState.hs	Tue Dec 25 04:45:22 2012 +0100
@@ -56,7 +56,7 @@
         roomChans <- roomClientsChans
         cl <- thisClient
         teamColor <-
-            if clientProto cl < 42 then 
+            if clientProto cl < 42 then
                 return color
                 else
                 liftM (head . (L.\\) (map B.singleton ['0'..]) . map teamcolor . teams) thisRoom
@@ -264,6 +264,14 @@
             [ModifyRoom (\r -> r{isRestrictedTeams = not $ isRestrictedTeams r})]
 
 
+handleCmd_inRoom ["TOGGLE_REGISTERED_ONLY"] = do
+    cl <- thisClient
+    return $
+        if not $ isMaster cl then
+            [ProtocolError "Not room master"]
+        else
+            [ModifyRoom (\r -> r{isRegisteredOnly = not $ isRegisteredOnly r})]
+
 handleCmd_inRoom ["ROOM_NAME", newName] = do
     cl <- thisClient
     rs <- allRoomInfos
@@ -293,6 +301,16 @@
         [KickRoomClient kickId | master && isJust maybeClientId && (kickId /= thisClientId) && sameRoom]
 
 
+handleCmd_inRoom ["DELEGATE", newAdmin] = do
+    (thisClientId, rnc) <- ask
+    maybeClientId <- clientByNick newAdmin
+    master <- liftM isMaster thisClient
+    let newAdminId = fromJust maybeClientId
+    let sameRoom = clientRoom rnc thisClientId == clientRoom rnc newAdminId
+    return
+        [ChangeMaster (Just newAdminId) | master && isJust maybeClientId && (newAdminId /= thisClientId) && sameRoom]
+
+
 handleCmd_inRoom ["TEAMCHAT", msg] = do
     cl <- thisClient
     chans <- roomSameClanChans
@@ -308,8 +326,8 @@
     let sameRoom = clientRoom rnc thisClientId == clientRoom rnc banId
     if master && isJust maybeClientId && (banId /= thisClientId) && sameRoom then
         return [
-                ModifyRoom (\r -> r{roomBansList = let h = host $ rnc `client` banId in h `deepseq` h : roomBansList r})
-              , KickRoomClient banId
+--                ModifyRoom (\r -> r{roomBansList = let h = host $ rnc `client` banId in h `deepseq` h : roomBansList r})
+                KickRoomClient banId
             ]
         else
         return []
--- a/gameServer/HWProtoLobbyState.hs	Sun Dec 02 00:03:16 2012 +0100
+++ b/gameServer/HWProtoLobbyState.hs	Tue Dec 25 04:45:22 2012 +0100
@@ -80,6 +80,8 @@
             [Warning "No such room"]
             else if isRestrictedJoins jRoom then
             [Warning "Joining restricted"]
+            else if isRegisteredOnly jRoom then
+            [Warning "Registered users only"]
             else if isBanned then
             [Warning "You are banned in this room"]
             else if roomPassword /= password jRoom then
@@ -89,20 +91,21 @@
                 MoveToRoom jRI
                 , AnswerClients [sendChan cl] $ "JOINED" : nicks
                 , AnswerClients chans ["CLIENT_FLAGS", "-r", nick cl]
-                , AnswerClients [sendChan cl] $ ["WARNING", "Room admin is " `B.append` ownerNick]
                 , AnswerClients [sendChan cl] $ ["CLIENT_FLAGS", "+h", ownerNick]
             ]
-            ++ map (readynessMessage cl) jRoomClients
+            ++ (if clientProto cl < 38 then map (readynessMessage cl) jRoomClients else [sendStateFlags cl jRoomClients])
             ++ answerFullConfig cl (mapParams jRoom) (params jRoom)
             ++ answerTeams cl jRoom
-            ++ watchRound cl jRoom
+            ++ watchRound cl jRoom chans
 
         where
-        readynessMessage cl c = AnswerClients [sendChan cl] $
-                if clientProto cl < 38 then
-                    [if isReady c then "READY" else "NOT_READY", nick c]
-                    else
-                    ["CLIENT_FLAGS", if isReady c then "+r" else "-r", nick c]
+        readynessMessage cl c = AnswerClients [sendChan cl] [if isReady c then "READY" else "NOT_READY", nick c]
+        sendStateFlags cl clients = AnswerClients [sendChan cl] . concat . intersperse [""] . filter (not . null) . concat $
+                [f "+r" ready, f "-r" unready, f "+g" ingame, f "-g" inroomlobby]
+            where
+            (ready, unready) = partition isReady clients
+            (ingame, inroomlobby) = partition isInGame clients
+            f fl lst = ["CLIENT_FLAGS" : fl : map nick lst | not $ null lst]
 
         toAnswer cl (paramName, paramStrs) = AnswerClients [sendChan cl] $ "CFG" : paramName : paramStrs
 
@@ -119,11 +122,13 @@
 
         answerTeams cl jRoom = let f = if isJust $ gameInfo jRoom then teamsAtStart . fromJust . gameInfo else teams in answerAllTeams cl $ f jRoom
 
-        watchRound cl jRoom = if isNothing $ gameInfo jRoom then
+        watchRound cl jRoom chans = if isNothing $ gameInfo jRoom then
                     []
                 else
-                    [AnswerClients [sendChan cl]  ["RUN_GAME"],
-                    AnswerClients [sendChan cl] $ "EM" : toEngineMsg "e$spectate 1" : Foldable.toList (roundMsgs . fromJust . gameInfo $ jRoom)]
+                    [AnswerClients [sendChan cl]  ["RUN_GAME"]
+                    , AnswerClients chans ["CLIENT_FLAGS", "+g", nick cl]
+                    , ModifyClient (\c -> c{isInGame = True})
+                    , AnswerClients [sendChan cl] $ "EM" : toEngineMsg "e$spectate 1" : Foldable.toList (roundMsgs . fromJust . gameInfo $ jRoom)]
 
 
 handleCmd_lobby ["JOIN_ROOM", roomName] =
@@ -150,16 +155,20 @@
     return [KickClient $ fromJust kickId | isAdministrator cl && isJust kickId && fromJust kickId /= ci]
 
 
-handleCmd_lobby ["BAN", banNick, reason] = do
+handleCmd_lobby ["BAN", banNick, reason, duration] = do
     (ci, _) <- ask
     cl <- thisClient
     banId <- clientByNick banNick
-    return [BanClient 60 reason (fromJust banId) | isAdministrator cl && isJust banId && fromJust banId /= ci]
+    return [BanClient (readInt_ duration) reason (fromJust banId) | isAdministrator cl && isJust banId && fromJust banId /= ci]
 
 handleCmd_lobby ["BANIP", ip, reason, duration] = do
     cl <- thisClient
     return [BanIP ip (readInt_ duration) reason | isAdministrator cl]
 
+handleCmd_lobby ["BANNICK", n, reason, duration] = do
+    cl <- thisClient
+    return [BanNick n (readInt_ duration) reason | isAdministrator cl]
+
 handleCmd_lobby ["BANLIST"] = do
     cl <- thisClient
     return [BanList | isAdministrator cl]
--- a/gameServer/NetRoutines.hs	Sun Dec 02 00:03:16 2012 +0100
+++ b/gameServer/NetRoutines.hs	Tue Dec 25 04:45:22 2012 +0100
@@ -41,6 +41,7 @@
                     False
                     False
                     False
+                    False
                     Nothing
                     0
                     )
--- a/hedgewars/ArgParsers.inc	Sun Dec 02 00:03:16 2012 +0100
+++ b/hedgewars/ArgParsers.inc	Tue Dec 25 04:45:22 2012 +0100
@@ -16,232 +16,319 @@
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
  *)
 
+procedure GciEasterEgg;
+begin
+    WriteLn(stdout, '                                                                ');
+    WriteLn(stdout, '      /\\\\\\\\\\\\        /\\\\\\\\\  /\\\\\\\\\\\             ');
+    WriteLn(stdout, '     /\\\//////////      /\\\////////  \/////\\\///             ');
+    WriteLn(stdout, '     /\\\               /\\\/               \/\\\               ');
+    WriteLn(stdout, '     \/\\\    /\\\\\\\  /\\\                 \/\\\              ');
+    WriteLn(stdout, '      \/\\\   \/////\\\ \/\\\                 \/\\\             ');
+    WriteLn(stdout, '       \/\\\       \/\\\ \//\\\                \/\\\            ');
+    WriteLn(stdout, '        \/\\\       \/\\\  \///\\\              \/\\\           ');
+    WriteLn(stdout, '         \/\\\\\\\\\\\\\/     \////\\\\\\\\\  /\\\\\\\\\\\      ');
+    WriteLn(stdout, '          \/////////////          \/////////  \///////////      ');
+    WriteLn(stdout, '                                                                ');
+    WriteLn(stdout, ' Command Line Parser Implementation by a Google Code-In Student ');
+    WriteLn(stdout, '             ASCII Art easter egg idea by @sheepluva            ');
+    WriteLn(stdout, '                                                                ');
+end;
 
-procedure internalStartGameWithParameters();
-var tmp: LongInt;
+procedure DisplayUsage;
 begin
-    UserPathPrefix:= ParamStr(1);
-    cScreenWidth:= StrToInt(ParamStr(2));
-    cScreenHeight:= StrToInt(ParamStr(3));
-    cBits:= StrToInt(ParamStr(4));
-    ipcPort:= StrToInt(ParamStr(5));
-    cFullScreen:= ParamStr(6) = '1';
-    SetSound(ParamStr(7) = '1');
-    SetMusic(ParamStr(8) = '1');
-    SetVolume(StrToInt(ParamStr(9)));
-    cTimerInterval:= StrToInt(ParamStr(10));
-    PathPrefix:= ParamStr(11);
-    cShowFPS:= ParamStr(12) = '1';
-    cAltDamage:= ParamStr(13) = '1';
-    UserNick:= DecodeBase64(ParamStr(14));
-    cReducedQuality:= StrToInt(ParamStr(15));
-    tmp:= StrToInt(ParamStr(16));
+    WriteLn(stdout, 'Usage: hwengine <path to replay file> [options]');
+    WriteLn(stdout, '');
+    WriteLn(stdout, 'where [options] can be any of the following:');
+    WriteLn(stdout, ' --prefix [path to folder]');
+    WriteLn(stdout, ' --user-prefix [path to folder]');
+    WriteLn(stdout, ' --locale [name of language file]');
+    WriteLn(stdout, ' --nick [string]');
+    WriteLn(stdout, ' --width [screen width in pixels]');
+    WriteLn(stdout, ' --height [screen height in pixels]');
+    WriteLn(stdout, ' --volume [sound level]');
+    WriteLn(stdout, ' --frame-interval [milliseconds]');
+    Writeln(stdout, ' --stereo [value]');
+    WriteLn(stdout, ' --raw-quality [flags]');
+    WriteLn(stdout, ' --low-quality');
+    WriteLn(stdout, ' --nomusic');
+    WriteLn(stdout, ' --nosound');
+    WriteLn(stdout, ' --fullscreen');
+    WriteLn(stdout, ' --showfps');
+    WriteLn(stdout, ' --altdmg');
+    WriteLn(stdout, ' --stats-only');
+    WriteLn(stdout, ' --help');
+    WriteLn(stdout, '');
+    WriteLn(stdout, 'For more detailed help and examples go to:');
+    WriteLn(stdout, 'http://code.google.com/p/hedgewars/wiki/CommandLineOptions');
+    GameType:= gmtSyntax;
+end;
+
+procedure setDepth(var paramIndex: LongInt);
+begin
+    WriteLn(stdout, 'WARNING: --depth is a deprecated command, which could be removed in a future version!');
+    WriteLn(stdout, '         This option no longer does anything, please consider removing it');
+    WriteLn(stdout, '');
+   inc(ParamIndex);
+end;
+
+procedure statsOnlyGame;
+begin
+    cOnlyStats:= true;
+    cReducedQuality:= $FFFFFFFF xor rqLowRes;
+    SetSound(false);
+    SetMusic(false);
+    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: String): String;
+begin
+    if isInternal then
+        parseNick:= DecodeBase64(nick)
+    else
+        parseNick:= nick;
+end;
+
+procedure setStereoMode(tmp: LongInt);
+begin
     GrayScale:= false;
-    if (tmp > 9) and (tmp < 16) then 
+{$IFDEF USE_S3D_RENDERING}
+    if (tmp > 9) and (tmp < 16) then
         begin
+        // set the gray anaglyph rendering
         GrayScale:= true;
         cStereoMode:= TStereoMode(max(0, min(ord(high(TStereoMode)), tmp-9)))
         end
-    else if tmp <= 9 then 
+    else if tmp <= 9 then
+        // set the fullcolor anaglyph
         cStereoMode:= TStereoMode(max(0, min(ord(high(TStereoMode)), tmp)))
-    else 
+    else
+        // any other mode
         cStereoMode:= TStereoMode(max(0, min(ord(high(TStereoMode)), tmp-6)));
-    cLocaleFName:= ParamStr(17);
+{$ELSE}
+    cStereoMode:= smNone;
+{$ENDIF}
+end;
+
+procedure startVideoRecording(var paramIndex: LongInt);
+begin
+{$IFDEF USE_VIDEO_RECORDING}
+    GameType:= gmtRecord;
+    inc(paramIndex);
+    cVideoFramerateNum:= StrToInt(ParamStr(paramIndex)); inc(paramIndex);
+    cVideoFramerateDen:= StrToInt(ParamStr(paramIndex)); inc(paramIndex);
+    RecPrefix:= ParamStr(paramIndex);                    inc(paramIndex);
+    cAVFormat:= ParamStr(paramIndex);                    inc(paramIndex);
+    cVideoCodec:= ParamStr(paramIndex);                  inc(paramIndex);
+    cVideoQuality:= StrToInt(ParamStr(paramIndex));      inc(paramIndex);
+    cAudioCodec:= ParamStr(paramIndex);                  inc(paramIndex);
+{$ENDIF}
+end;
+
+function getLongIntParameter(str:String; var paramIndex:LongInt; var wrongParameter:Boolean): LongInt;
+var tmpInt, c: LongInt;
+begin
+    inc(paramIndex);
+    val(str, tmpInt, c);
+    wrongParameter:= c <> 0;
+    if wrongParameter then
+        WriteLn(stderr, 'ERROR: '+ParamStr(paramIndex-1)+' expects a number, you passed "'+str+'"');
+    getLongIntParameter:= tmpInt;
+end;
+
+function getStringParameter(str:String; var paramIndex:LongInt; var wrongParameter:Boolean): String;
+begin
+    inc(paramIndex);
+    wrongParameter:= (str='') or (Copy(str,1,2) = '--');
+    if wrongParameter then
+         WriteLn(stderr, 'ERROR: '+ParamStr(paramIndex-1)+' expects a string, you passed "'+str+'"');
+    getStringParameter:= str;
 end;
 
-{$IFDEF USE_VIDEO_RECORDING}
-procedure internalStartVideoRecordingWithParameters();
+
+procedure parseClassicParameter(cmdArray: Array of String; size:LongInt; var paramIndex:LongInt); Forward;
+
+function parseParameter(cmd:String; arg:String; var paramIndex:LongInt): Boolean;
+const videoArray: Array [1..3] of String = ('--width','--height','--depth');
+      audioArray: Array [1..3] of String = ('--volume','--nomusic','--nosound');
+      otherArray: Array [1..3] of String = ('--locale','--fullscreen','--showfps');
+      mediaArray: Array [1..8] of String = ('--width','--height','--depth','--volume','--nomusic','--nosound','--locale','--fullscreen');
+      allArray: Array [1..12] of String = ('--width','--height','--depth','--volume','--nomusic','--nosound','--locale','--fullscreen','--showfps','--altdmg','--frame-interval','--low-quality');
+      reallyAll: array[0..28] of shortstring = (
+                '--prefix', '--user-prefix', '--locale', '--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',
+  {misc}        '--stats-only', '--gci', '--help');
+var cmdIndex: byte;
+begin
+    parseParameter:= false;
+    cmdIndex:= 0;
+
+    //NOTE: Any update to the list of parameters must be reflected in the case statement below, the reallyAll array above,
+    //      the the DisplayUsage() procedure, the HWForm::getDemoArguments() function, and the online wiki
+
+    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);
+        {--width}           3 : cScreenWidth   := getLongIntParameter(arg, paramIndex, parseParameter);
+        {--height}          4 : cScreenHeight  := getLongIntParameter(arg, paramIndex, parseParameter);
+        {--frame-interval}  5 : cTimerInterval := getLongIntParameter(arg, paramIndex, parseParameter);
+        {--volume}          6 : SetVolume       ( getLongIntParameter(arg, paramIndex, parseParameter) );
+        {--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}          16 : setDepth(paramIndex);
+        {--set-video}      17 : parseClassicParameter(videoArray,3,paramIndex);
+        {--set-audio}      18 : parseClassicParameter(audioArray,3,paramIndex);
+        {--set-other}      19 : parseClassicParameter(otherArray,3,paramIndex);
+        {--set-multimedia} 20 : parseClassicParameter(mediaArray,8,paramIndex);
+        {--set-everything} 21 : parseClassicParameter(allArray,12,paramIndex);
+        {"internal" options}
+        {--internal}       22 : {note it, but do nothing};
+        {--port}            23 : setIpcPort( getLongIntParameter(arg, paramIndex, parseParameter), parseParameter );
+        {--recorder}       24 : startVideoRecording(paramIndex);
+        {--landpreview}    25 : GameType := gmtLandPreview;
+        {anything else}
+        {--stats-only}     26 : statsOnlyGame();
+        {--gci}            27 : GciEasterEgg();
+        {--help}           28 : DisplayUsage();
+    else
+        begin
+        //Asusme the first "non parameter" is the replay file, anything else is invalid
+        if (recordFileName = '') and (Copy(cmd,1,2) <> '--') then
+            recordFileName := cmd
+        else
+            begin
+            WriteLn(stderr, '"'+cmd+'" is not a valid option');
+            parseParameter:= true;
+            end;
+        end;
+    end;
+end;
+
+procedure parseClassicParameter(cmdArray: Array of String; size:LongInt; var paramIndex:LongInt);
+var index, tmpInt: LongInt;
+    isBool, isValid: Boolean;
+    cmd, arg, newSyntax: String;
 begin
-    internalStartGameWithParameters();
-    GameType:= gmtRecord;
-    cVideoFramerateNum:= StrToInt(ParamStr(18));
-    cVideoFramerateDen:= StrToInt(ParamStr(19));
-    RecPrefix:= ParamStr(20);
-    cAVFormat:= ParamStr(21);
-    cVideoCodec:= ParamStr(22);
-    cVideoQuality:= StrToInt(ParamStr(23));
-    cAudioCodec:= ParamStr(24);
+    WriteLn(stdout, 'WARNING: you are using a deprecated command, which could be removed in a future version!');
+    WriteLn(stdout, '         Consider updating to the latest syntax, which is much more flexible!');
+    WriteLn(stdout, '         Run `hwegine --help` to learn it!');
+    WriteLn(stdout, '');
+
+    index:= 0;
+    tmpInt:= 1;
+    while (index < size) do
+        begin
+        inc(paramIndex);
+        cmd:= cmdArray[index];
+        arg:= ParamStr(paramIndex);
+        isValid:= (cmd<>'--depth');
+
+        // check if the parameter is a boolean one
+        isBool:= (cmd = '--nomusic') or (cmd = '--nosound') or (cmd = '--fullscreen') or (cmd = '--showfps') or (cmd = '--altdmg');
+        if isBool and (arg='0') then
+            isValid:= false;
+        if (cmd='--nomusic') or (cmd='--nosound') then
+            isValid:= not isValid;
+
+        if isValid then
+            begin
+            parseParameter(cmd, arg, tmpInt);
+            newSyntax += cmd + ' ';
+            if not isBool then
+                newSyntax += arg + ' ';
+            end;
+        inc(index);
+        end;
+
+    WriteLn(stdout, 'Attempted to automatically convert to the new syntax:');
+    WriteLn(stdout, newSyntax);
+    WriteLn(stdout, '');
+end;
+
+procedure parseCommandLine{$IFDEF HWLIBRARY}(argc: LongInt; argv: PPChar){$ENDIF};
+var paramIndex: LongInt;
+    paramTotal: LongInt;
+    wrongParameter: boolean;
+begin
+    paramIndex:= 1;
+    paramTotal:={$IFDEF HWLIBRARY}argc{$ELSE}ParamCount{$ENDIF};
+    wrongParameter:= false;
+    while (paramIndex <= paramTotal) do
+        begin
+        {$IFDEF HWLIBRARY}
+        wrongParameter:= parseParameter( argv[paramIndex], argv[paramIndex+1], paramIndex);
+        {$ELSE}
+        wrongParameter:= parseParameter( ParamStr(paramIndex), ParamStr(paramIndex+1), paramIndex);
+        {$ENDIF}
+        inc(paramIndex);
+        end;
+    if wrongParameter = true then
+        GameType:= gmtSyntax;
+end;
+
+{$IFNDEF HWLIBRARY}
+procedure GetParams;
+//var tmpInt: LongInt;
+begin
+    (*
+    tmpInt:=0;
+    while (tmpInt <= ParamCount) do
+        begin
+        WriteLn(stdout, inttostr(tmpInt) + ': ' + ParamStr(tmpInt));
+        inc(tmpInt);
+        end;
+    *)
+
+    isInternal:= (ParamStr(1) = '--internal');
+
+    UserPathPrefix := '.';
+    PathPrefix     := cDefaultPathPrefix;
+    recordFileName := '';
+    parseCommandLine();
+
+    if (isInternal) and (ParamCount<=1) then
+        begin
+        WriteLn(stderr, '--internal should not be manually used');
+        GameType := gmtSyntax;
+        end;
+
+    if (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 (GameType = gmtSyntax) then
+        WriteLn(stderr, 'Please use --help to see possible arguments and their usage');
+
+    (*
+    WriteLn(stdout,'PathPrefix:     ' + PathPrefix);
+    WriteLn(stdout,'UserPathPrefix: ' + UserPathPrefix);
+    *)
 end;
 {$ENDIF}
 
-procedure setVideo(screenWidth: LongInt; screenHeight: LongInt; bitsStr: LongInt);
-begin
-    cScreenWidth:= screenWidth;
-    cScreenHeight:= screenHeight;
-    cBits:= bitsStr
-end;
-
-procedure setVideoWithParameters(screenWidthParam: string; screenHeightParam: string; bitsParam: string);
-var screenWidthAsInt, screenHeightAsInt, bitsStrAsInt, c: LongInt;
-begin
-    val(screenWidthParam, screenWidthAsInt, c);
-    val(screenHeightParam, screenHeightAsInt, c);
-    val(bitsParam, bitsStrAsInt, c);
-    setVideo(screenWidthAsInt,screenHeightAsInt,bitsStrAsInt)
-end;
-
-procedure setOtherOptions(languageFile: string; fullScreen: boolean);
-begin
-    cLocaleFName:= languageFile;
-    cFullScreen:= fullScreen
-end;
-
-procedure setShowFPS(showFPS: boolean);
-begin
-    cShowFPS:= showFPS
-end;
-
-procedure setOtherOptionsWithParameters(languageFileParam: string; fullScreenParam: string; showFPSParam: string);
-var fullScreen, showFPS: boolean;
-begin
-    fullScreen:= fullScreenParam = '1';
-    showFPS:= showFPSParam = '1';
-    setOtherOptions(languageFileParam,fullScreen);
-    setShowFPS(showFPS)
-end;
-
-procedure setAudio(initialVolume: LongInt; musicEnabled: boolean; soundEnabled: boolean);
-begin
-    SetVolume(initialVolume);
-    SetMusic(musicEnabled);
-    SetSound(soundEnabled);
-end;
-
-procedure setAudioWithParameters(initialVolumeParam: string; musicEnabledParam: string; soundEnabledParam: string);
-var initialVolumeAsInt, c: LongInt;
-    musicEnabled, soundEnabled: boolean;
-begin
-    val(initialVolumeParam, initialVolumeAsInt, c);
-    musicEnabled:= musicEnabledParam = '1';
-    soundEnabled:= soundEnabledParam = '1';
-    setAudio(initialVolumeAsInt,musicEnabled, soundEnabled)
-end;
-
-procedure setMultimediaOptionsWithParameters(screenWidthParam, screenHeightParam, bitsParam: string;
-                                             initialVolumeParam, musicEnabledParam, soundEnabledParam: string;
-                                             languageFileParam, fullScreenParam: string);
-begin
-    setVideoWithParameters(screenWidthParam,screenHeightParam, bitsParam);
-    setAudioWithParameters(initialVolumeParam,musicEnabledParam,soundEnabledParam);
-    setOtherOptions(languageFileParam,fullScreenParam = '1')
-end;
-
-procedure setAltDamageTimerValueAndQuality(altDamage: boolean; timeIterval: LongInt; reducedQuality: boolean);
-begin
-    cAltDamage:= altDamage;
-    cTimerInterval:= timeIterval;
-    if (reducedQuality) then        //HACK
-        cReducedQuality:= $FFFFFFFF xor rqLowRes
-end;
-
-procedure setAllOptionsWithParameters(screenWidthParam:string; screenHeightParam:string; bitsParam:string;
-                                      initialVolumeParam:string; musicEnabledParam:string; soundEnabledParam:string;
-                                      languageFileParam:string; fullScreenParam:string; showFPSParam:string;
-                                      altDamageParam:string; timeItervalParam:string; reducedQualityParam: string);
-var showFPS, altDamage, reducedQuality: boolean;
-    timeIterval, c: LongInt;
-begin
-    setMultimediaOptionsWithParameters(screenWidthParam,screenHeightParam, bitsParam,
-                                       initialVolumeParam,musicEnabledParam,soundEnabledParam,
-                                       languageFileParam,fullScreenParam);
-    showFPS := showFPSParam = '1';
-    setShowFPS(showFPS);
-
-    altDamage:= altDamageParam = '1';
-    val(timeItervalParam, timeIterval, c);
-    reducedQuality:= reducedQualityParam = '1';
-    setAltDamageTimerValueAndQuality(altDamage,timeIterval,reducedQuality);
-end;
-
-procedure playReplayFileWithParameters();
-var paramIndex: LongInt;
-    wrongParameter: boolean;
-begin
-    UserPathPrefix:= ParamStr(1);
-    PathPrefix:= ParamStr(2);
-    recordFileName:= ParamStr(3);
-    paramIndex:= 4;
-    wrongParameter:= false;
-    while (paramIndex <= ParamCount) and (not wrongParameter) do
-        begin
-        if ParamStr(paramIndex) = '--set-video'  then
-//--set-video [screen width] [screen height] [color dept]
-            begin
-            if(ParamCount-paramIndex < 3) then
-                begin
-                wrongParameter:= true;
-                GameType:= gmtSyntax
-                end;
-            setVideoWithParameters(ParamStr(paramIndex+1), ParamStr(paramIndex+2), ParamStr(paramIndex+3));
-            paramIndex:= paramIndex + 4
-            end
-        else
-//--set-audio [volume] [enable music] [enable sounds]
-            if ParamStr(paramIndex) = '--set-audio'  then
-                begin
-                if(ParamCount-paramIndex < 3) then
-                    begin
-                    wrongParameter := true;
-                    GameType:= gmtSyntax
-                    end;
-                setAudioWithParameters(ParamStr(paramIndex+1),ParamStr(paramIndex+2), ParamStr(paramIndex+3));
-                paramIndex:= paramIndex + 4
-                end
-            else
-// --set-other [language file] [full screen] [show FPS]
-                if ParamStr(paramIndex) = '--set-other'  then
-                    begin
-                    if(ParamCount-paramIndex < 3) then
-                        begin
-                        wrongParameter:= true;
-                        GameType:= gmtSyntax
-                        end;
-                    setOtherOptionsWithParameters(ParamStr(paramIndex+1),ParamStr(paramIndex+2), ParamStr(paramIndex+3));
-                    paramIndex:= paramIndex + 4
-                    end
-                else
-//--set-multimedia [screen width] [screen height] [color dept] [volume] [enable music] [enable sounds] [language file] [full screen]
-                    if ParamStr(paramIndex) = '--set-multimedia'  then
-                        begin
-                        if ParamCount-paramIndex < 8  then
-                            begin
-                            wrongParameter:= true;
-                            GameType:= gmtSyntax
-                            end;
-                        setMultimediaOptionsWithParameters(ParamStr(paramIndex+1),ParamStr(paramIndex+2),ParamStr(paramIndex+3),
-                                                           ParamStr(paramIndex+4),ParamStr(paramIndex+5),ParamStr(paramIndex+6),
-                                                           ParamStr(paramIndex+7),ParamStr(paramIndex+8));
-                        paramIndex:= paramIndex + 9
-                        end
-                    else
-//--set-everything [screen width] [screen height] [color dept] [volume] [enable music] [enable sounds] [language file] [full screen] [show FPS] [alternate damage] [timer value] [reduced quality]
-                        if ParamStr(paramIndex) = '--set-everything'  then
-                            begin
-                            if ParamCount-paramIndex < 12  then
-                                begin
-                                wrongParameter:= true;
-                                GameType:= gmtSyntax
-                                end;
-                            setAllOptionsWithParameters(ParamStr(paramIndex+1),ParamStr(paramIndex+2),ParamStr(paramIndex+3),
-                                                        ParamStr(paramIndex+4),ParamStr(paramIndex+5),ParamStr(paramIndex+6),
-                                                        ParamStr(paramIndex+7),ParamStr(paramIndex+8),ParamStr(paramIndex+9),
-                                                        ParamStr(paramIndex+10),ParamStr(paramIndex+11),ParamStr(paramIndex+12));
-                            paramIndex:= paramIndex + 13
-                            end
-                        else
-                            if ParamStr(paramIndex) = '--stats-only'  then
-                                begin
-                                cOnlyStats:= true;
-                                SetSound(false);
-                                SetMusic(false);
-                                cReducedQuality:= $FFFFFFFF xor rqLowRes; // HACK
-                                paramIndex:= paramIndex + 1
-                                end
-                            else
-                                begin
-                                wrongParameter:= true;
-                                GameType:= gmtSyntax
-                                end
-    end
-end;
-
--- a/hedgewars/CMakeLists.txt	Sun Dec 02 00:03:16 2012 +0100
+++ b/hedgewars/CMakeLists.txt	Tue Dec 25 04:45:22 2012 +0100
@@ -6,11 +6,22 @@
 
 include(${CMAKE_SOURCE_DIR}/cmake_modules/FindSDL_Extras.cmake)
 
-configure_file(${CMAKE_SOURCE_DIR}/hedgewars/config.inc.in ${CMAKE_CURRENT_BINARY_DIR}/config.inc)
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.inc.in ${CMAKE_CURRENT_BINARY_DIR}/config.inc)
 
 #SOURCE AND PROGRAMS SECTION
-set(hwengine_project ${CMAKE_SOURCE_DIR}/hedgewars/hwengine.pas)
-set(engine_output_name "hwengine")
+if(${LIBENGINE})
+    set(engine_output_name "${CMAKE_SHARED_LIBRARY_PREFIX}hwengine${CMAKE_SHARED_LIBRARY_SUFFIX}")
+    set(hwengine_project ${CMAKE_CURRENT_SOURCE_DIR}/hwLibrary.pas)
+else()
+    set(engine_output_name "hwengine${CMAKE_EXECUTABLE_SUFFIX}")
+    set(hwengine_project ${CMAKE_CURRENT_SOURCE_DIR}/hwengine.pas)
+endif()
+
+if (APPLE)
+    set(required_fpc_version 2.6)
+else()
+    set(required_fpc_version 2.2)
+endif()
 
 set(engine_sources
     ${hwengine_project}
@@ -54,7 +65,6 @@
     uLocale.pas
     uMatrix.pas
     uMisc.pas
-    uMobile.pas
     uPhysFSLayer.pas
     uRandom.pas
     uRender.pas
@@ -81,9 +91,8 @@
     ${CMAKE_CURRENT_BINARY_DIR}/config.inc
     )
 
-if(LIBENGINE)
-    message(STATUS "Engine will be built as library (experimental)")
-    set(hwengine_project ${CMAKE_SOURCE_DIR}/hedgewars/hwLibrary.pas)
+if(${LIBENGINE})
+    message(WARNING "Engine will be built as library (experimental)")
     set(pascal_flags "-dHWLIBRARY" ${pascal_flags})
 
     # create position independent code, only required for x68_64 builds, similar to -fPIC
@@ -92,64 +101,22 @@
     endif(CMAKE_SIZEOF_VOID_P MATCHES "8")
 
     # due to compiler/linker issues on Max OS X 10.6 -k-no_order_inits is needed to avoid linking fail
-    if(APPLE AND current_macosx_version GREATER "10.5")
+    if(APPLE AND current_macosx_version VERSION_GREATER "10.5")
         set(pascal_flags "-k-no_order_inits" ${pascal_flags})
     endif()
-
-    if(APPLE)
-        set(engine_output_name "libhwengine.dylib")
-    endif (APPLE)
-endif(LIBENGINE)
+    set(destination_dir ${target_library_install_dir})
+else(${LIBENGINE})
+    set(destination_dir ${target_binary_install_dir})
+endif(${LIBENGINE})
 
 
-#PASCAL DETECTION SECTION
-IF(FPC)
-    set(fpc_executable ${FPC})
-ELSE()
-    find_program(fpc_executable fpc)
-ENDIF()
-
-message(STATUS "Check for working FPC compiler: ${fpc_executable}")
-execute_process(COMMAND ${fpc_executable} -iV OUTPUT_VARIABLE fpc_output ERROR_VARIABLE fpc_error)
-if(fpc_error)
-    message(STATUS "Check for working FPC compiler: ${fpc_executable} -- broken")
-else(fpc_error)
-    message(STATUS "Check for working FPC compiler: ${fpc_executable} -- works")
-endif(fpc_error)
+# Check Freepascal version
+find_package(Freepascal)
 
-string(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+" fpc_version "${fpc_output}")
-if(fpc_version)
-    string(REGEX REPLACE "([0-9]+)\\.[0-9]+\\.[0-9]+" "\\1" fpc_vers_major "${fpc_version}")
-    string(REGEX REPLACE "[0-9]+\\.([0-9]+)\\.[0-9]+" "\\1" fpc_vers_minor "${fpc_version}")
-    string(REGEX REPLACE "[0-9]+\\.[0-9]+\\.([0-9]+)" "\\1" fpc_vers_patch "${fpc_version}")
-    message(STATUS "Found Freepascal: ${fpc_executable} (version ${fpc_vers_major}.${fpc_vers_minor})")
-    math(EXPR fpc_version "${fpc_vers_major}*10000 + ${fpc_vers_minor}*100 + ${fpc_vers_patch}")
-
-    if(fpc_version LESS "020200")
-        message(FATAL_ERROR "Minimum required version of FreePascal is 2.2.0")
-    elseif(APPLE AND (fpc_version LESS "020600"))
-        message(FATAL_ERROR "Minimum required version of FreePascal is 2.6.0 on Mac OS X")
-    endif()
-else()
-    message(FATAL_ERROR "No FreePascal compiler found!")
+if (FPC_VERSION VERSION_LESS required_fpc_version)
+    message(FATAL_ERROR "Freepascal is too old, minimum version required is ${required_fpc_version}")
 endif()
 
-message(STATUS "Checking whether linker supports noexecstack flag")
-set(noexecstack_flags "-k-z" "-knoexecstack")
-file(WRITE ${EXECUTABLE_OUTPUT_PATH}/checkstack.pas "begin end.")
-
-execute_process(COMMAND ${fpc_executable} ${noexecstack_flags} checkstack.pas
-    WORKING_DIRECTORY ${EXECUTABLE_OUTPUT_PATH}
-    RESULT_VARIABLE testnoexecstack
-    OUTPUT_QUIET ERROR_QUIET
-    )
-
-if(${testnoexecstack})
-    set (noexecstack_flags "")
-    message(STATUS "Checking whether linker supports noexecstack flag -- no")
-else(${testnoexecstack})
-    message(STATUS "Checking whether linker supports noexecstack flag -- yes")
-endif(${testnoexecstack})
 
 #DEPENDECIES AND EXECUTABLES SECTION
 if(APPLE)
@@ -162,13 +129,13 @@
     endif()
 
     #on OSX we need to provide the SDL_main() function when building as executable
-    if(NOT LIBENGINE)
+    if(NOT ${LIBENGINE})
         #let's look for the installed sdlmain file; if it is not found, let's build our own
         find_package(SDL REQUIRED)
         #remove the ";-framework Cocoa" from the SDL_LIBRARY variable
-        string(REGEX REPLACE "(.*);-.*" "\\1" sdl_dir "${SDL_LIBRARY}")
+        string(REGEX REPLACE "(.*);-.*" "\\1" sdl_library_only "${SDL_LIBRARY}")
         #find libsdmain.a
-        find_file(SDLMAIN_LIB libSDLMain.a PATHS ${sdl_dir}/Resources/)
+        find_file(SDLMAIN_LIB libSDLMain.a PATHS ${sdl_library_only}/Resources/)
 
         if(SDLMAIN_LIB MATCHES "SDLMAIN_LIB-NOTFOUND")
             include_directories(${SDL_INCLUDE_DIR})
@@ -180,7 +147,6 @@
 
         set(pascal_flags "-k${SDLMAIN_LIB}" ${pascal_flags})
     endif()
-    set(pascal_flags "-k${LIBRARY_OUTPUT_PATH}/libphysfs.a" ${pascal_flags})
 endif(APPLE)
 
 if(NOT NOPNG)
@@ -199,9 +165,8 @@
 
 
 #this command is a workaround to some inlining issues present in older FreePascal versions and fixed in 2.6
-if(fpc_version LESS "020600")
+if(FPC_VERSION VERSION_LESS "2.6")
     #under some configurations CMAKE_BUILD_TOOL fails to pass on the jobserver, breaking parallel compilation
-    #TODO: check if this is needed on windows too
     if(UNIX)
         set(SAFE_BUILD_TOOL $(MAKE))
     else()
@@ -226,7 +191,7 @@
             # there are some problems with linking our avwrapper as static lib, so link it as shared
             add_library(avwrapper SHARED videorec/avwrapper.c)
             target_link_libraries(avwrapper ${FFMPEG_LIBRARIES})
-            install(PROGRAMS "${EXECUTABLE_OUTPUT_PATH}/${CMAKE_SHARED_LIBRARY_PREFIX}avwrapper${CMAKE_SHARED_LIBRARY_SUFFIX}" DESTINATION ${target_dir})
+            install(PROGRAMS "${EXECUTABLE_OUTPUT_PATH}/${CMAKE_SHARED_LIBRARY_PREFIX}avwrapper${CMAKE_SHARED_LIBRARY_SUFFIX}" DESTINATION ${target_library_install_dir})
         ELSE()
             add_library(avwrapper STATIC videorec/avwrapper.c)
             set(pascal_flags "-k${FFMPEG_LIBAVCODEC}" "-k${FFMPEG_LIBAVFORMAT}" "-k${FFMPEG_LIBAVUTIL}" ${pascal_flags})
@@ -238,29 +203,33 @@
     message(STATUS "Video recording disabled by user")
 endif()
 
-set(pascal_flags "-Fl${LIBRARY_OUTPUT_PATH}" ${pascal_flags})
 
-set(fpc_flags ${noexecstack_flags} ${pascal_flags} ${hwengine_project})
+set(fpc_flags ${NOEXECSTACK_FLAGS} ${pascal_flags} ${hwengine_project})
 
-IF(NOT APPLE)
+if(NOT APPLE)
     #here is the command for standard executables or for shared library
-    add_custom_command(OUTPUT "${EXECUTABLE_OUTPUT_PATH}/${engine_output_name}${CMAKE_EXECUTABLE_SUFFIX}"
-        COMMAND "${fpc_executable}"
-        ARGS ${fpc_flags}
+    add_custom_command(OUTPUT "${EXECUTABLE_OUTPUT_PATH}/${engine_output_name}"
+        COMMAND "${FPC_EXECUTABLE}"
+        ARGS ${fpc_flags} -o${engine_output_name}
         MAIN_DEPENDENCY ${hwengine_project}
         DEPENDS ${engine_sources}
         )
-ELSE()
+else()
     #these are the dependencies for building a universal binary on Mac OS X
     foreach (build_arch ${powerpc_build} ${i386_build} ${x86_64_build})
         set(lipo_args_list "${EXECUTABLE_OUTPUT_PATH}/hwengine.${build_arch}" ${lipo_args_list})
         add_custom_command(OUTPUT "${EXECUTABLE_OUTPUT_PATH}/hwengine.${build_arch}"
-            COMMAND "${fpc_executable}"
+            COMMAND "${FPC_EXECUTABLE}"
             ARGS ${fpc_flags} -ohwengine.${build_arch} -P${build_arch}
             MAIN_DEPENDENCY ${hwengine_project}
             DEPENDS ${engine_sources}
             )
         add_custom_target(hwengine.${build_arch} ALL DEPENDS "${EXECUTABLE_OUTPUT_PATH}/hwengine.${build_arch}")
+        add_custom_command(TARGET hwengine.${build_arch} POST_BUILD
+            COMMAND "install_name_tool"
+            ARGS -id @executable_path/../Frameworks/${engine_output_name}
+                ${EXECUTABLE_OUTPUT_PATH}/hwengine.${build_arch}
+            )
     endforeach()
 
     add_custom_command(OUTPUT "${EXECUTABLE_OUTPUT_PATH}/${engine_output_name}"
@@ -268,10 +237,10 @@
         ARGS ${lipo_args_list} -create -output ${EXECUTABLE_OUTPUT_PATH}/${engine_output_name}
         DEPENDS ${lipo_args_list}
         )
-ENDIF()
+endif()
 
 
-add_custom_target(${engine_output_name} ALL DEPENDS "${EXECUTABLE_OUTPUT_PATH}/${engine_output_name}${CMAKE_EXECUTABLE_SUFFIX}")
+add_custom_target(${engine_output_name} ALL DEPENDS "${EXECUTABLE_OUTPUT_PATH}/${engine_output_name}")
 
 #when system Lua is not found we need to compile it before engine
 if(NOT LUA_FOUND)
@@ -288,8 +257,8 @@
 endif()
 
 #this command is a workaround to some inlining issues present in older FreePascal versions and fixed in 2.6
-if((fpc_version LESS "020600") AND (NOVIDEOREC OR NOT ${FFMPEG_FOUND}))
+if((FPC_VERSION VERSION_LESS "2.6") AND (NOVIDEOREC OR NOT ${FFMPEG_FOUND}))
     add_dependencies(${engine_output_name} ENGINECLEAN)
 endif()
 
-install(PROGRAMS "${EXECUTABLE_OUTPUT_PATH}/${engine_output_name}${CMAKE_EXECUTABLE_SUFFIX}" DESTINATION ${target_dir})
+install(PROGRAMS "${EXECUTABLE_OUTPUT_PATH}/${engine_output_name}" DESTINATION ${destination_dir})
--- a/hedgewars/GSHandlers.inc	Sun Dec 02 00:03:16 2012 +0100
+++ b/hedgewars/GSHandlers.inc	Tue Dec 25 04:45:22 2012 +0100
@@ -53,7 +53,7 @@
         sX:= dX / steps;
         sY:= dY / steps;
         end
-        
+
     else
         begin
         sX:= dX;
@@ -75,7 +75,7 @@
 end;
 
 procedure makeHogsWorry(x, y: hwFloat; r: LongInt);
-var 
+var
     gi: PGear;
     d: LongInt;
 begin
@@ -89,7 +89,7 @@
                 begin
                 if (CurrentHedgehog^.Gear = gi) then
                     PlaySoundV(sndOops, gi^.Hedgehog^.Team^.voicepack)
-                    
+
                 else
                     begin
                     if (gi^.State and gstMoving) = 0 then
@@ -97,15 +97,15 @@
                         gi^.dX.isNegative:= X<gi^.X;
                         gi^.State := gi^.State or gstLoser;
                         end;
-                        
+
                     if d > r div 2 then
-                        PlaySoundV(sndNooo, gi^.Hedgehog^.Team^.voicepack) 
+                        PlaySoundV(sndNooo, gi^.Hedgehog^.Team^.voicepack)
                     else
                         PlaySoundV(sndUhOh, gi^.Hedgehog^.Team^.voicepack);
                     end;
                 end;
             end;
-            
+
         gi := gi^.NextGear
         end;
 end;
@@ -116,10 +116,10 @@
     DeleteCI(HH^.Gear);
     if FollowGear = HH^.Gear then
         FollowGear:= nil;
-        
+
     if lastGearByUID = HH^.Gear then
         lastGearByUID := nil;
-    
+
     HH^.Gear^.Message:= HH^.Gear^.Message or gmRemoveFromList;
     with HH^.Gear^ do
         begin
@@ -165,7 +165,7 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 procedure doStepFallingGear(Gear: PGear);
-var 
+var
     isFalling: boolean;
     //tmp: QWord;
     tdX, tdY: hwFloat;
@@ -220,16 +220,16 @@
         else if (Gear^.AdvBounce=1) and (TestCollisionYwithGear(Gear, 1) <> 0) then
             collV := 1;
         end
-    else 
+    else
         begin // Gear^.dY.isNegative is false
         land:= TestCollisionYwithGear(Gear, 1);
         if land <> 0 then
             begin
             collV := 1;
             isFalling := false;
-            if land and lfIce <> 0 then 
+            if land and lfIce <> 0 then
                 Gear^.dX := Gear^.dX * (_0_9 + Gear^.Friction * _0_1)
-            else 
+            else
                 Gear^.dX := Gear^.dX * Gear^.Friction;
 
             Gear^.dY := - Gear^.dY * Gear^.Elasticity;
@@ -252,7 +252,7 @@
         Gear^.State := Gear^.State or gstCollision
         end
     else if (Gear^.AdvBounce=1) and TestCollisionXwithGear(Gear, -hwSign(Gear^.dX)) then
-        collH := -hwSign(Gear^.dX); 
+        collH := -hwSign(Gear^.dX);
     //if Gear^.AdvBounce and (collV <>0) and (collH <> 0) and (hwSqr(tdX) + hwSqr(tdY) > _0_08) then
     if (Gear^.AdvBounce=1) and (collV <>0) and (collH <> 0) and ((collV=-1)
     or ((tdX.QWordValue + tdY.QWordValue) > _0_2.QWordValue)) then
@@ -285,18 +285,18 @@
     else
         Gear^.State := Gear^.State or gstMoving;
 
-    if (Gear^.nImpactSounds > 0) and 
+    if (Gear^.nImpactSounds > 0) and
         (Gear^.State and gstCollision <> 0) and
         (((Gear^.Kind <> gtMine) and (Gear^.Damage <> 0)) or (Gear^.State and gstMoving <> 0)) and
         (((Gear^.Radius < 3) and (Gear^.dY < -_0_1)) or
-            ((Gear^.Radius >= 3) and 
+            ((Gear^.Radius >= 3) and
                 ((Gear^.dX.QWordValue > _0_1.QWordValue) or (Gear^.dY.QWordValue > _0_1.QWordValue)))) then
         PlaySound(TSound(ord(Gear^.ImpactSound) + LongInt(GetRandom(Gear^.nImpactSounds))), true);
 end;
 
 ////////////////////////////////////////////////////////////////////////////////
 procedure doStepBomb(Gear: PGear);
-var 
+var
     i, x, y: LongInt;
     dX, dY: hwFloat;
     vg: PVisualGear;
@@ -307,7 +307,7 @@
 
     dec(Gear^.Timer);
     if Gear^.Timer = 1000 then // might need adjustments
-        case Gear^.Kind of 
+        case Gear^.Kind of
             gtGrenade: makeHogsWorry(Gear^.X, Gear^.Y, 50);
             gtClusterBomb: makeHogsWorry(Gear^.X, Gear^.Y, 20);
             gtWatermelon: makeHogsWorry(Gear^.X, Gear^.Y, 75);
@@ -331,10 +331,10 @@
 
     if Gear^.Timer = 0 then
         begin
-        case Gear^.Kind of 
+        case Gear^.Kind of
             gtGrenade: doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, Gear^.Hedgehog, EXPLAutoSound);
             gtBall: doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 40, Gear^.Hedgehog, EXPLAutoSound);
-            gtClusterBomb: 
+            gtClusterBomb:
                 begin
                 x := hwRound(Gear^.X);
                 y := hwRound(Gear^.Y);
@@ -346,7 +346,7 @@
                     FollowGear := AddGear(x, y, gtCluster, 0, dX, dY, 25)
                     end
                 end;
-            gtWatermelon: 
+            gtWatermelon:
                 begin
                 x := hwRound(Gear^.X);
                 y := hwRound(Gear^.Y);
@@ -359,7 +359,7 @@
                     FollowGear^.DirAngle := i * 60
                     end
                 end;
-            gtHellishBomb: 
+            gtHellishBomb:
                 begin
                 x := hwRound(Gear^.X);
                 y := hwRound(Gear^.Y);
@@ -375,7 +375,7 @@
                         AddGear(x, y, gtFlame, 0, dX, -dY, 0)
                         end
                     else
-                        begin 
+                        begin
                         AddGear(x, y, gtFlame, 0, dX, dY, 0);
                         AddGear(x, y, gtFlame, gstTmpFlag, dX, -dY, 0)
                         end;
@@ -415,7 +415,7 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 procedure doStepMolotov(Gear: PGear);
-var 
+var
     s: Longword;
     i, gX, gY: LongInt;
     dX, dY: hwFloat;
@@ -435,7 +435,7 @@
             i:= 130
         else
             i:= 50;
-            
+
         smoke:= AddVisualGear(hwRound(Gear^.X)-round(cos((Gear^.DirAngle+i) * pi / 180)*20), hwRound(Gear^.Y)-round(sin((Gear^.DirAngle+i) * pi / 180)*20), vgtSmoke);
         if smoke <> nil then
             smoke^.Scale:= 0.75;
@@ -694,10 +694,10 @@
                     end;
                 p:= @(p^[s^.pitch shr 2])
                 end;
-            
-            // Why is this here.  For one thing, there's no test on +1 being safe. 
+
+            // Why is this here.  For one thing, there's no test on +1 being safe.
             //Land[py, px+1]:= lfBasic;
-            
+
             if allpx then
                 UpdateLandTexture(xx, Pred(s^.h), yy, Pred(s^.w), true)
             else
@@ -762,7 +762,7 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 procedure doStepBeeWork(Gear: PGear);
-var 
+var
     t: hwFloat;
     gX,gY,i: LongInt;
     uw, nuw: boolean;
@@ -877,7 +877,7 @@
         Gear^.Hedgehog^.Gear^.Message:= Gear^.Hedgehog^.Gear^.Message and (not gmAttack);
         Gear^.Hedgehog^.Gear^.State:= Gear^.Hedgehog^.Gear^.State and (not gstAttacking);
         AttackBar:= 0;
-        
+
         Gear^.SoundChannel := LoopSound(sndBee);
         Gear^.Timer := 5000;
         // save initial speed in otherwise unused Friction variable
@@ -899,7 +899,7 @@
 end;
 
 procedure doStepShotgunShot(Gear: PGear);
-var 
+var
     i: LongWord;
     shell: PVisualGear;
 begin
@@ -975,7 +975,7 @@
 
         // Bullet trail
         VGear := AddVisualGear(hwRound(ox), hwRound(oy), vgtLineTrail);
-        
+
         if VGear <> nil then
             begin
             VGear^.X:= hwFloat2Float(ox);
@@ -998,7 +998,7 @@
 end;
 
 procedure doStepBulletWork(Gear: PGear);
-var 
+var
     i: LongInt;
     x, y: LongWord;
     oX, oY: hwFloat;
@@ -1014,7 +1014,7 @@
         Gear^.Y := Gear^.Y + Gear^.dY;
         x := hwRound(Gear^.X);
         y := hwRound(Gear^.Y);
-        
+
         if ((y and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0) and (Land[y, x] <> 0) then
             inc(Gear^.Damage);
         // let's interrupt before a collision to give portals a chance to catch the bullet
@@ -1036,7 +1036,7 @@
         else
             AmmoShove(Gear, Gear^.Timer, 20);
         CheckGearDrowning(Gear);
-        dec(i) 
+        dec(i)
     until (i = 0) or (Gear^.Damage > Gear^.Health) or ((Gear^.State and gstDrowning) <> 0);
 
     if Gear^.Damage > 0 then
@@ -1064,7 +1064,7 @@
                 cLaserSighting := false;
             if (Ammoz[Gear^.AmmoType].Ammo.NumPerTurn <= CurrentHedgehog^.MultiShootAttacks) and ((GameFlags and gfArtillery) = 0) then
                 cArtillery := false;
-        
+
         // Bullet Hit
             if (hwRound(Gear^.X) and LAND_WIDTH_MASK = 0) and (hwRound(Gear^.Y) and LAND_HEIGHT_MASK = 0) then
                 begin
@@ -1074,7 +1074,7 @@
                     VGear^.Angle := DxDy2Angle(-Gear^.dX, Gear^.dY);
                     end;
                 end;
-       
+
             spawnBulletTrail(Gear);
             Gear^.doStep := @doStepShotIdle
             end;
@@ -1090,7 +1090,7 @@
 end;
 
 procedure doStepSniperRifleShot(Gear: PGear);
-var 
+var
     HHGear: PGear;
     shell: PVisualGear;
 begin
@@ -1121,7 +1121,7 @@
         Gear^.dY := -AngleCos(HHGear^.Angle) * _0_5;
         PlaySound(sndGun);
         // add 3 initial steps to avoid problem with ammoshove related to calculation of radius + 1 radius as gear widths, and also just weird angles
-        Gear^.X := Gear^.X + Gear^.dX * 3;  
+        Gear^.X := Gear^.X + Gear^.dX * 3;
         Gear^.Y := Gear^.Y + Gear^.dY * 3;
         Gear^.doStep := @doStepBulletWork;
         end
@@ -1150,7 +1150,7 @@
 begin
 dec(Gear^.Timer);
 case Gear^.Kind of
-    gtATStartGame: 
+    gtATStartGame:
     begin
         AllInactive := false;
         if Gear^.Timer = 0 then
@@ -1158,7 +1158,7 @@
             AddCaption(trmsg[sidStartFight], cWhiteColor, capgrpGameState);
             end
     end;
-    gtATFinishGame: 
+    gtATFinishGame:
     begin
         AllInactive := false;
         if Gear^.Timer = 1000 then
@@ -1181,7 +1181,7 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 procedure doStepPickHammerWork(Gear: PGear);
-var 
+var
     i, ei, x, y: LongInt;
     HHGear: PGear;
 begin
@@ -1272,7 +1272,7 @@
 end;
 
 procedure doStepPickHammer(Gear: PGear);
-var 
+var
     i, y: LongInt;
     ar: TRangeArray;
     HHGear: PGear;
@@ -1299,11 +1299,11 @@
 end;
 
 ////////////////////////////////////////////////////////////////////////////////
-var 
+var
     BTPrevAngle, BTSteps: LongInt;
 
 procedure doStepBlowTorchWork(Gear: PGear);
-var 
+var
     HHGear: PGear;
     b: boolean;
     prevX: LongInt;
@@ -1312,7 +1312,7 @@
     dec(Gear^.Timer);
     if ((GameFlags and gfInfAttack) <> 0) and (TurnTimeLeft > 0) then
         dec(TurnTimeLeft);
-    
+
     HHGear := Gear^.Hedgehog^.Gear;
 
     HedgehogChAngle(HHGear);
@@ -1393,7 +1393,7 @@
 end;
 
 procedure doStepBlowTorch(Gear: PGear);
-var 
+var
     HHGear: PGear;
 begin
     BTPrevAngle := High(LongInt);
@@ -1433,7 +1433,7 @@
             inc(Gear^.Damage, hwRound(Gear^.dY * -_70))
         else if Gear^.dX.isNegative and (Gear^.dX < -_0_2) and TestCollisionXwithGear(Gear, -1) then
             inc(Gear^.Damage, hwRound(Gear^.dX * -_70));
-        
+
         if ((GameTicks and $FF) = 0) and (Gear^.Damage > random(30)) then
             begin
             vg:= AddVisualGear(hwRound(Gear^.X) - 4  + Random(8), hwRound(Gear^.Y) - 4 - Random(4), vgtSmoke);
@@ -1495,9 +1495,9 @@
 procedure doStepSMine(Gear: PGear);
 begin
     // TODO: do real calculation?
-    if TestCollisionXwithGear(Gear, 2) 
-    or (TestCollisionYwithGear(Gear, -2) <> 0) 
-    or TestCollisionXwithGear(Gear, -2) 
+    if TestCollisionXwithGear(Gear, 2)
+    or (TestCollisionYwithGear(Gear, -2) <> 0)
+    or TestCollisionXwithGear(Gear, -2)
     or (TestCollisionYwithGear(Gear, 2) <> 0) then
         begin
         if (not isZero(Gear^.dX)) or (not isZero(Gear^.dY)) then
@@ -1572,14 +1572,14 @@
 Try tweaking friction some more
 *)
 procedure doStepRollingBarrel(Gear: PGear);
-var 
+var
     i: LongInt;
     particle: PVisualGear;
 begin
     if (Gear^.dY.QWordValue = 0) and (Gear^.dY.QWordValue = 0) and (TestCollisionYwithGear(Gear, 1) = 0) then
         SetLittle(Gear^.dY);
     Gear^.State := Gear^.State or gstAnimation;
-    
+
     if ((Gear^.dX.QWordValue <> 0)
     or (Gear^.dY.QWordValue <> 0))  then
         begin
@@ -1598,10 +1598,10 @@
             end
         else if (not Gear^.dX.isNegative) and (Gear^.dX > _0_2) and TestCollisionXwithGear(Gear, 1) then
                 inc(Gear^.Damage, hwRound(Gear^.dX * _70))
-                
+
         else if Gear^.dY.isNegative and (Gear^.dY < -_0_2) and (TestCollisionYwithGear(Gear, -1) <> 0) then
                 inc(Gear^.Damage, hwRound(Gear^.dY * -_70))
-                
+
         else if Gear^.dX.isNegative and (Gear^.dX < -_0_2) and TestCollisionXwithGear(Gear, -1) then
                 inc(Gear^.Damage, hwRound(Gear^.dX * -_70));
 
@@ -1650,7 +1650,7 @@
 end;
 
 procedure doStepCase(Gear: PGear);
-var 
+var
     i, x, y: LongInt;
     k: TGearType;
     exBoom: boolean;
@@ -1691,7 +1691,7 @@
             exBoom := true;
         end
     else
-        begin 
+        begin
         if (Gear^.Pos <> posCaseHealth) and (GameTicks and $1FFF = 0) then // stir 'em up periodically
             begin
             gi := GearsList;
@@ -1728,12 +1728,12 @@
                 sparkles^.dX:= 0;
                 sparkles^.dY:= 0;
                 sparkles^.Angle:= 270;
-                if Gear^.Tag = 1 then 
+                if Gear^.Tag = 1 then
                     sparkles^.Tint:= $3744D7FF
                 else sparkles^.Tint:= $FAB22CFF
                 end;
             end;
-        if Gear^.Timer < 1000 then 
+        if Gear^.Timer < 1000 then
             begin
             AllInactive:= false;
             exit
@@ -1792,7 +1792,7 @@
             if Gear^.dY > _0_2 then
                 for i:= min(12, hwRound(Gear^.dY*_10)) downto 0 do
                     AddVisualGear(hwRound(Gear^.X) - 5 + Random(10), hwRound(Gear^.Y) + 12, vgtDust);
-                    
+
             Gear^.dY := - Gear^.dY * Gear^.Elasticity;
             if Gear^.dY > - _0_001 then
                 Gear^.dY := _0
@@ -1846,7 +1846,7 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 procedure doStepShover(Gear: PGear);
-var 
+var
     HHGear: PGear;
 begin
     HHGear := Gear^.Hedgehog^.Gear;
@@ -1862,7 +1862,7 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 procedure doStepWhip(Gear: PGear);
-var 
+var
     HHGear: PGear;
     i: LongInt;
 begin
@@ -1884,7 +1884,7 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 procedure doStepFlame(Gear: PGear);
-var 
+var
     gX,gY,i: LongInt;
     sticky: Boolean;
     vgt: PVisualGear;
@@ -1911,10 +1911,10 @@
 
         if Gear^.dX.QWordValue > _0_01.QWordValue then
             Gear^.dX := Gear^.dX * _0_995;
-            
+
         Gear^.dY := Gear^.dY + cGravity;
         // if sticky then Gear^.dY := Gear^.dY + cGravity;
-        
+
         if Gear^.dY.QWordValue > _0_2.QWordValue then
             Gear^.dY := Gear^.dY * _0_995;
 
@@ -1975,13 +1975,13 @@
                     Gear^.Radius := 1;
                     end
                 else if ((GameTicks and $3) = 3) then
-                    doMakeExplosion(gX, gY, 8, Gear^.Hedgehog, 0);//, EXPLNoDamage); 
+                    doMakeExplosion(gX, gY, 8, Gear^.Hedgehog, 0);//, EXPLNoDamage);
                 //DrawExplosion(gX, gY, 4);
-                
+
                 if ((GameTicks and $7) = 0) and (Random(2) = 0) then
                     for i:= Random(2) downto 0 do
                         AddVisualGear(gX - 3 + Random(6), gY - 2, vgtSmoke);
-                        
+
                 if Gear^.Health > 0 then
                     dec(Gear^.Health);
                 Gear^.Timer := 450 - Gear^.Tag * 8
@@ -2024,7 +2024,7 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 procedure doStepFirePunchWork(Gear: PGear);
-var 
+var
     HHGear: PGear;
 begin
     AllInactive := false;
@@ -2061,7 +2061,7 @@
 end;
 
 procedure doStepFirePunch(Gear: PGear);
-var 
+var
     HHGear: PGear;
 begin
     AllInactive := false;
@@ -2084,7 +2084,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 procedure doStepParachuteWork(Gear: PGear);
-var 
+var
     HHGear: PGear;
 begin
     HHGear := Gear^.Hedgehog^.Gear;
@@ -2113,13 +2113,13 @@
 
     if (Gear^.Message and gmLeft) <> 0 then
         HHGear^.X := HHGear^.X - cMaxWindSpeed * 80
-        
+
     else if (Gear^.Message and gmRight) <> 0 then
         HHGear^.X := HHGear^.X + cMaxWindSpeed * 80;
-        
+
     if (Gear^.Message and gmUp) <> 0 then
         HHGear^.Y := HHGear^.Y - cGravity * 40
-        
+
     else if (Gear^.Message and gmDown) <> 0 then
         HHGear^.Y := HHGear^.Y + cGravity * 40;
 
@@ -2132,7 +2132,7 @@
 end;
 
 procedure doStepParachute(Gear: PGear);
-var 
+var
     HHGear: PGear;
 begin
     HHGear := Gear^.Hedgehog^.Gear;
@@ -2159,7 +2159,7 @@
     if (Gear^.Health > 0) and (not (Gear^.X < Gear^.dX)) and (Gear^.X < Gear^.dX + cAirPlaneSpeed) then
         begin
         dec(Gear^.Health);
-            case Gear^.State of 
+            case Gear^.State of
                 0: FollowGear := AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtAirBomb, 0, cBombsSpeed * Gear^.Tag, _0, 0);
                 1: FollowGear := AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtMine,    0, cBombsSpeed * Gear^.Tag, _0, 0);
                 2: FollowGear := AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtNapalmBomb, 0, cBombsSpeed * Gear^.Tag, _0, 0);
@@ -2202,7 +2202,7 @@
 
     // calcs for Napalm Strike, so that it will hit the target (without wind at least :P)
     if (Gear^.State = 2) then
-        Gear^.dX := Gear^.dX - cBombsSpeed * Gear^.Tag * 900 
+        Gear^.dX := Gear^.dX - cBombsSpeed * Gear^.Tag * 900
     // calcs for regular falling gears
     else if (int2hwFloat(Gear^.Target.Y) - Gear^.Y > _0) then
             Gear^.dX := Gear^.dX - cBombsSpeed * hwSqrt((int2hwFloat(Gear^.Target.Y) - Gear^.Y) * 2 /
@@ -2224,7 +2224,9 @@
         begin
         doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 30, Gear^.Hedgehog, EXPLAutoSound);
         DeleteGear(Gear);
-        performRumble();
+        with mobileRecord do
+            if (performRumble <> nil) and (not fastUntilLag) then
+                performRumble(kSystemSoundID_Vibrate);
         exit
         end;
     if (GameTicks and $3F) = 0 then
@@ -2234,7 +2236,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 procedure doStepGirder(Gear: PGear);
-var 
+var
     HHGear: PGear;
     x, y, tx, ty: hwFloat;
 begin
@@ -2256,7 +2258,7 @@
         isCursorVisible := true;
         DeleteGear(Gear)
         end
-    else 
+    else
         begin
         PlaySound(sndPlaced);
         DeleteGear(Gear);
@@ -2269,7 +2271,7 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 procedure doStepTeleportAfter(Gear: PGear);
-var 
+var
     HHGear: PGear;
 begin
     HHGear := Gear^.Hedgehog^.Gear;
@@ -2303,7 +2305,7 @@
 end;
 
 procedure doStepTeleport(Gear: PGear);
-var 
+var
     HHGear: PGear;
 begin
     AllInactive := false;
@@ -2344,7 +2346,7 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 procedure doStepSwitcherWork(Gear: PGear);
-var 
+var
     HHGear: PGear;
     hedgehog: PHedgehog;
     State: Longword;
@@ -2382,7 +2384,7 @@
         until (CurrentTeam^.Hedgehogs[CurrentTeam^.CurrHedgehog].Gear <> nil) and (CurrentTeam^.Hedgehogs[CurrentTeam^.CurrHedgehog].Gear^.Damage = 0);
 
         SwitchCurrentHedgehog(@CurrentTeam^.Hedgehogs[CurrentTeam^.CurrHedgehog]);
-        AmmoMenuInvalidated:= true; 
+        AmmoMenuInvalidated:= true;
 
         HHGear := CurrentHedgehog^.Gear;
         HHGear^.State := State;
@@ -2396,7 +2398,7 @@
 end;
 
 procedure doStepSwitcher(Gear: PGear);
-var 
+var
     HHGear: PGear;
 begin
     Gear^.doStep := @doStepSwitcherWork;
@@ -2412,7 +2414,7 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 procedure doStepMortar(Gear: PGear);
-var 
+var
     dX, dY: hwFloat;
     i: LongInt;
     dxn, dyn: boolean;
@@ -2445,7 +2447,7 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 procedure doStepKamikazeWork(Gear: PGear);
-var 
+var
     i: LongWord;
     HHGear: PGear;
     sparkles: PVisualGear;
@@ -2480,7 +2482,7 @@
 
     i := 2;
     repeat
-        
+
         Gear^.X := Gear^.X + HHGear^.dX;
         Gear^.Y := Gear^.Y + HHGear^.dY;
         HHGear^.X := Gear^.X;
@@ -2563,7 +2565,7 @@
 end;
 
 procedure doStepKamikaze(Gear: PGear);
-var 
+var
     HHGear: PGear;
 begin
     AllInactive := false;
@@ -2584,7 +2586,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 const cakeh =   27;
-var 
+var
     CakePoints: array[0..Pred(cakeh)] of record
         x, y: hwFloat;
     end;
@@ -2604,7 +2606,7 @@
 end;
 
 procedure doStepCakeDown(Gear: PGear);
-var 
+var
     gi: PGear;
     dmg, dmgBase: LongInt;
     fX, fY, tdX, tdY: hwFloat;
@@ -2690,7 +2692,7 @@
 end;
 
 procedure doStepCakeUp(Gear: PGear);
-var 
+var
     i: Longword;
 begin
     AllInactive := false;
@@ -2730,7 +2732,7 @@
 end;
 
 procedure doStepCake(Gear: PGear);
-var 
+var
     HHGear: PGear;
 begin
     AllInactive := false;
@@ -2835,7 +2837,7 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 procedure doStepWaterUp(Gear: PGear);
-var 
+var
     i: LongWord;
 begin
     if (Gear^.Tag = 0)
@@ -2869,7 +2871,7 @@
 forward;
 
 procedure doStepDrillDrilling(Gear: PGear);
-var 
+var
     t: PGearArray;
     ox, oy: hwFloat;
 begin
@@ -2893,10 +2895,10 @@
 
     if GameTicks > Gear^.FlightTime then
         t := CheckGearsCollision(Gear)
-        
+
     else t := nil;
     //fixes drill not exploding when touching HH bug
-    
+
     if (Gear^.Timer = 0) or ((t <> nil) and (t^.Count <> 0))
     or ( ((Gear^.State and gsttmpFlag) = 0) and (TestCollisionYWithGear(Gear, hwSign(Gear^.dY)) = 0) and (not TestCollisionXWithGear(Gear, hwSign(Gear^.dX))))
 // CheckLandValue returns true if the type isn't matched
@@ -2911,7 +2913,7 @@
         DeleteGear(Gear);
         exit
         end
-        
+
     else if (TestCollisionYWithGear(Gear, hwSign(Gear^.dY)) = 0) and (not (TestCollisionXWithGear(Gear, hwSign(Gear^.dX)))) then
         begin
         StopSoundChan(Gear^.SoundChannel);
@@ -2923,7 +2925,7 @@
 end;
 
 procedure doStepDrill(Gear: PGear);
-var 
+var
     t: PGearArray;
     oldDx, oldDy: hwFloat;
     t2: hwFloat;
@@ -2947,7 +2949,7 @@
         Gear^.dX := oldDx;
         Gear^.dY := oldDy;
 
-        if GameTicks > Gear^.FlightTime then 
+        if GameTicks > Gear^.FlightTime then
             t := CheckGearsCollision(Gear)
         else
             t := nil;
@@ -2958,7 +2960,7 @@
             Gear^.dX := Gear^.dX * t2;
             Gear^.dY := Gear^.dY * t2;
             end
-            
+
         else if (t <> nil) then
             begin
             //explode right on contact with HH
@@ -2972,14 +2974,14 @@
 
         Gear^.SoundChannel := LoopSound(sndDrillRocket);
         Gear^.doStep := @doStepDrillDrilling;
-        
+
         if (Gear^.State and gsttmpFlag) <> 0 then
             gear^.RenderTimer:= true;
         if Gear^.Timer > 0 then dec(Gear^.Timer)
         end
     else if ((Gear^.State and gsttmpFlag) <> 0) and (Gear^.Tag <> 0) then
         begin
-        if Gear^.Timer > 0 then 
+        if Gear^.Timer > 0 then
             dec(Gear^.Timer)
         else
             begin
@@ -2991,7 +2993,7 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 procedure doStepBallgunWork(Gear: PGear);
-var 
+var
     HHGear, ball: PGear;
     rx, ry: hwFloat;
     gX, gY: LongInt;
@@ -3021,7 +3023,7 @@
 end;
 
 procedure doStepBallgun(Gear: PGear);
-var 
+var
     HHGear: PGear;
 begin
     HHGear := Gear^.Hedgehog^.Gear;
@@ -3034,7 +3036,7 @@
 procedure doStepRCPlaneWork(Gear: PGear);
 
 const cAngleSpeed =   3;
-var 
+var
     HHGear: PGear;
     i: LongInt;
     dX, dY: hwFloat;
@@ -3143,7 +3145,7 @@
             begin
             if TagTurnTimeLeft = 0 then
                 TagTurnTimeLeft:= TurnTimeLeft;
-                
+
             TurnTimeLeft:= 14 * 125;
             end;
 
@@ -3153,7 +3155,7 @@
 end;
 
 procedure doStepRCPlane(Gear: PGear);
-var 
+var
     HHGear: PGear;
 begin
     HHGear := Gear^.Hedgehog^.Gear;
@@ -3161,7 +3163,7 @@
     HHGear^.State := HHGear^.State or gstNotKickable;
     Gear^.Angle := HHGear^.Angle;
     Gear^.Tag := hwSign(HHGear^.dX);
-    
+
     if HHGear^.dX.isNegative then
         Gear^.Angle := 4096 - Gear^.Angle;
     Gear^.doStep := @doStepRCPlaneWork
@@ -3169,7 +3171,7 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 procedure doStepJetpackWork(Gear: PGear);
-var 
+var
     HHGear: PGear;
     fuel, i: LongInt;
     move: hwFloat;
@@ -3248,9 +3250,9 @@
 
     if Gear^.Health < 0 then
         Gear^.Health := 0;
-        
+
     i:= Gear^.Health div 20;
-    
+
     if (i <> Gear^.Damage) and ((GameTicks and $3F) = 0) then
         begin
         Gear^.Damage:= i;
@@ -3259,9 +3261,9 @@
         Gear^.Tex := RenderStringTex(trmsg[sidFuel] + ': ' + inttostr(i) + '%', cWhiteColor, fntSmall)
         end;
 
-    if HHGear^.Message and (gmAttack or gmUp or gmPrecise or gmLeft or gmRight) <> 0 then 
+    if HHGear^.Message and (gmAttack or gmUp or gmPrecise or gmLeft or gmRight) <> 0 then
         Gear^.State := Gear^.State and (not gsttmpFlag);
-        
+
     HHGear^.Message := HHGear^.Message and (not (gmUp or gmPrecise or gmLeft or gmRight));
     HHGear^.State := HHGear^.State or gstMoving;
 
@@ -3271,7 +3273,7 @@
     if (not isUnderWater) and hasBorder and ((HHGear^.X < _0)
     or (hwRound(HHGear^.X) > LAND_WIDTH)) then
         HHGear^.dY.isNegative:= false;
-        
+
     if ((Gear^.State and gsttmpFlag) = 0)
     or (HHGear^.dY < _0) then
         doStepHedgehogMoving(HHGear);
@@ -3303,7 +3305,7 @@
 end;
 
 procedure doStepJetpack(Gear: PGear);
-var 
+var
     HHGear: PGear;
 begin
     Gear^.Pos:= 0;
@@ -3316,7 +3318,7 @@
         begin
         State := State and (not gstAttacking);
         Message := Message and (not (gmAttack or gmUp or gmPrecise or gmLeft or gmRight));
-        
+
         if (dY < _0_1) and (dY > -_0_1) then
             begin
             Gear^.State := Gear^.State or gsttmpFlag;
@@ -3339,13 +3341,13 @@
 end;
 
 procedure doStepBirdyFly(Gear: PGear);
-var 
+var
     HHGear: PGear;
     fuel, i: LongInt;
     move: hwFloat;
 begin
     HHGear := Gear^.Hedgehog^.Gear;
-    if HHGear = nil then 
+    if HHGear = nil then
         begin
         DeleteGear(Gear);
         exit
@@ -3369,11 +3371,11 @@
         if (not HHGear^.dY.isNegative)
         or (HHGear^.Y > -_256) then
             HHGear^.dY := HHGear^.dY - move;
-            
+
         dec(Gear^.Health, fuel);
         Gear^.MsgParam := Gear^.MsgParam or gmUp;
         end;
-        
+
     if (HHGear^.Message and gmLeft) <> 0 then move.isNegative := true;
     if (HHGear^.Message and (gmLeft or gmRight)) <> 0 then
         begin
@@ -3384,7 +3386,7 @@
 
     if Gear^.Health < 0 then
         Gear^.Health := 0;
-        
+
     if ((GameTicks and $FF) = 0) and (Gear^.Health < 500) then
         for i:= ((500-Gear^.Health) div 250) downto 0 do
             AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtFeather);
@@ -3402,7 +3404,7 @@
 
     if HHGear^.Message and (gmUp or gmPrecise or gmLeft or gmRight) <> 0 then
         Gear^.State := Gear^.State and (not gsttmpFlag);
-        
+
     HHGear^.Message := HHGear^.Message and (not (gmUp or gmPrecise or gmLeft or gmRight));
     HHGear^.State := HHGear^.State or gstMoving;
 
@@ -3445,7 +3447,7 @@
 end;
 
 procedure doStepBirdyDescend(Gear: PGear);
-var 
+var
     HHGear: PGear;
 begin
     if Gear^.Timer > 0 then
@@ -3486,12 +3488,12 @@
 end;
 
 procedure doStepBirdy(Gear: PGear);
-var 
+var
     HHGear: PGear;
 begin
     gear^.State :=  gear^.State or gstAnimation and (not gstTmpFlag);
     Gear^.doStep := @doStepBirdyAppear;
-    
+
     if CurrentHedgehog = nil then
         begin
         DeleteGear(Gear);
@@ -3516,7 +3518,7 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 procedure doStepEggWork(Gear: PGear);
-var 
+var
     vg: PVisualGear;
     i: LongInt;
 begin
@@ -3559,18 +3561,18 @@
                 if (CurAmmoType = amPortalGun) then
                     begin
                     CurrentHedgehog^.Gear^.Message := CurrentHedgehog^.Gear^.Message and (not gmSwitch);
-                
+
                     CurWeapon:= GetCurAmmoEntry(CurrentHedgehog^);
                     if CurWeapon^.Pos <> 0 then
                         CurWeapon^.Pos := 0
-                        
+
                     else
                     CurWeapon^.Pos := 1;
                     end;
 end;
 
 procedure doStepPortal(Gear: PGear);
-var 
+var
     iterator, conPortal: PGear;
     s, r, nx, ny, ox, oy, poffs, noffs, pspeed, nspeed,
     resetx, resety, resetdx, resetdy: hwFloat;
@@ -3871,7 +3873,7 @@
             resetx.QWordValue:= 4294967296 * 35;
             resetdx.isNegative:= false;
             resetdx.QWordValue:= 4294967296 * 1152;
-    
+
             resetdy:=hwAbs(iterator^.dX*4);
             resetdy:= resetdy + hwPow(resetdy,3)/_6 + _3 * hwPow(resetdy,5) / _40 + _5 * hwPow(resetdy,7) / resety + resetx * hwPow(resetdy,9) / resetdx;
             iterator^.Angle:= hwRound(resetdy*_2048 / _PI);
@@ -3938,7 +3940,7 @@
 end;
 
 procedure doStepMovingPortal_real(Gear: PGear);
-var 
+var
     x, y, tx, ty: LongInt;
     s: hwFloat;
 begin
@@ -3952,7 +3954,7 @@
         begin
         Gear^.State := Gear^.State or gstCollision;
         Gear^.State := Gear^.State and (not gstMoving);
-        
+
         if (Land[y, x] and lfBouncy <> 0)
         or (not (CalcSlopeTangent(Gear, x, y, tx, ty, 255)))
         or (DistanceI(tx,ty) < _12) then // reject shots at too irregular terrain
@@ -3980,7 +3982,7 @@
         else
             loadNewPortalBall(Gear, true);
     end
-    
+
     else if (y > cWaterLine)
     or (y < -max(LAND_WIDTH,4096))
     or (x > 2*max(LAND_WIDTH,4096))
@@ -3992,13 +3994,13 @@
 begin
     doPortalColorSwitch();
     doStepPerPixel(Gear, @doStepMovingPortal_real, true);
-    if (Gear^.Timer < 1) 
+    if (Gear^.Timer < 1)
     or (Gear^.Hedgehog^.Team <> CurrentHedgehog^.Team) then
         deleteGear(Gear);
 end;
 
 procedure doStepPortalShot(newPortal: PGear);
-var 
+var
     iterator: PGear;
     s: hwFloat;
     CurWeapon: PAmmo;
@@ -4078,15 +4080,15 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 procedure doStepPiano(Gear: PGear);
-var 
+var
     r0, r1: LongInt;
     odY: hwFloat;
 begin
     AllInactive := false;
-    if (CurrentHedgehog <> nil) and (CurrentHedgehog^.Gear <> nil) and 
+    if (CurrentHedgehog <> nil) and (CurrentHedgehog^.Gear <> nil) and
         ((CurrentHedgehog^.Gear^.Message and gmSlot) <> 0) then
             begin
-                case CurrentHedgehog^.Gear^.MsgParam of 
+                case CurrentHedgehog^.Gear^.MsgParam of
                 0: PlaySound(sndPiano0);
                 1: PlaySound(sndPiano1);
                 2: PlaySound(sndPiano2);
@@ -4166,7 +4168,7 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 procedure doStepSineGunShotWork(Gear: PGear);
-var 
+var
     x, y, rX, rY, t, tmp, initHealth: LongInt;
     oX, oY, ldX, ldY, sdX, sdY, sine, lx, ly, amp: hwFloat;
     justCollided: boolean;
@@ -4261,7 +4263,7 @@
                     end;
 
                 if random(100) = 0 then
-                    AddVisualGear(x, y, vgtSmokeTrace); 
+                    AddVisualGear(x, y, vgtSmokeTrace);
                 end
                 else dec(Gear^.Health, 5); // if underwater get additional damage
             end;
@@ -4299,7 +4301,7 @@
 var
     HHGear: PGear;
 begin
-    PlaySound(sndSineGun); 
+    PlaySound(sndSineGun);
 
     // push the shooting Hedgehog back
     HHGear := CurrentHedgehog^.Gear;
@@ -4312,12 +4314,14 @@
     Gear^.dY.isNegative := not Gear^.dY.isNegative;
 
     Gear^.doStep := @doStepSineGunShotWork;
-    performRumble();
+    with mobileRecord do
+        if (performRumble <> nil) and (not fastUntilLag) then
+            performRumble(kSystemSoundID_Vibrate);
 end;
 
 ////////////////////////////////////////////////////////////////////////////////
 procedure doStepFlamethrowerWork(Gear: PGear);
-var 
+var
     HHGear, flame: PGear;
     rx, ry, speed: hwFloat;
     i, gX, gY: LongInt;
@@ -4327,7 +4331,7 @@
     HedgehogChAngle(HHGear);
     gX := hwRound(Gear^.X) + GetLaunchX(amBallgun, hwSign(HHGear^.dX), HHGear^.Angle);
     gY := hwRound(Gear^.Y) + GetLaunchY(amBallgun, HHGear^.Angle);
-    
+
     if (GameTicks and $FF) = 0 then
         begin
         if (HHGear^.Message and gmRight) <> 0 then
@@ -4341,11 +4345,11 @@
             begin
             if HHGear^.dX.isNegative and (Gear^.Tag > 5) then
                 dec(Gear^.Tag)
-            else if Gear^.Tag < 20 then 
+            else if Gear^.Tag < 20 then
                 inc(Gear^.Tag);
             end
         end;
-    
+
     dec(Gear^.Timer);
     if Gear^.Timer = 0 then
         begin
@@ -4355,12 +4359,12 @@
             rx := rndSign(getRandomf * _0_1);
             ry := rndSign(getRandomf * _0_1);
             speed := _0_5 * (_10 / Gear^.Tag);
-    
+
             flame:= AddGear(gx, gy, gtFlame, gstTmpFlag,
                     SignAs(AngleSin(HHGear^.Angle) * speed, HHGear^.dX) + rx,
                     AngleCos(HHGear^.Angle) * ( - speed) + ry, 0);
             flame^.CollisionMask:= $FF7F;
-            
+
             if (Gear^.Health mod 30) = 0 then
                 begin
                 flame:= AddGear(gx, gy, gtFlame, 0,
@@ -4391,7 +4395,7 @@
 end;
 
 procedure doStepFlamethrower(Gear: PGear);
-var 
+var
     HHGear: PGear;
 begin
     HHGear := Gear^.Hedgehog^.Gear;
@@ -4402,7 +4406,7 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 procedure doStepLandGunWork(Gear: PGear);
-var 
+var
     HHGear, land: PGear;
     rx, ry, speed: hwFloat;
     i, gX, gY: LongInt;
@@ -4412,7 +4416,7 @@
     HedgehogChAngle(HHGear);
     gX := hwRound(Gear^.X) + GetLaunchX(amBallgun, hwSign(HHGear^.dX), HHGear^.Angle);
     gY := hwRound(Gear^.Y) + GetLaunchY(amBallgun, HHGear^.Angle);
-    
+
     if (GameTicks and $FF) = 0 then
         begin
         if (HHGear^.Message and gmRight) <> 0 then
@@ -4430,7 +4434,7 @@
                 inc(Gear^.Tag);
             end
         end;
-    
+
     dec(Gear^.Timer);
     if Gear^.Timer = 0 then
         begin
@@ -4440,11 +4444,11 @@
         ry := rndSign(getRandomf * _0_1);
         speed := (_3 / Gear^.Tag);
 
-        land:= AddGear(gx, gy, gtFlake, gstTmpFlag, 
-                SignAs(AngleSin(HHGear^.Angle) * speed, HHGear^.dX) + rx, 
+        land:= AddGear(gx, gy, gtFlake, gstTmpFlag,
+                SignAs(AngleSin(HHGear^.Angle) * speed, HHGear^.dX) + rx,
                 AngleCos(HHGear^.Angle) * ( - speed) + ry, 0);
         land^.CollisionMask:= $FF7F;
-            
+
         Gear^.Timer:= Gear^.Tag
         end;
 
@@ -4468,7 +4472,7 @@
 end;
 
 procedure doStepLandGun(Gear: PGear);
-var 
+var
     HHGear: PGear;
 begin
     HHGear := Gear^.Hedgehog^.Gear;
@@ -4537,7 +4541,7 @@
 end;
 
 procedure doStepHammerHitWork(Gear: PGear);
-var 
+var
     i, j, ei: LongInt;
     HitGear: PGear;
 begin
@@ -4592,7 +4596,7 @@
 end;
 
 procedure doStepHammerHit(Gear: PGear);
-var 
+var
     i, y: LongInt;
     ar: TRangeArray;
     HHGear: PGear;
@@ -4643,7 +4647,7 @@
         begin
         if (GameTicks and $F) <> 0 then
         exit;
-        end 
+        end
     else if (GameTicks and $1FF) <> 0 then
         exit;
 
@@ -4680,8 +4684,8 @@
                 inc(graves[i]^.Health);
             end;
         end; -}
-        end 
-    else 
+        end
+    else
         begin
         // now really resurrect the hogs with the hp saved in the graves
         for i:= 0 to graves.size - 1 do
@@ -4729,8 +4733,8 @@
             graves.ar^[i]^.Health := 0;
             end;
         Gear^.doStep := @doStepResurrectorWork;
-        end 
-    else 
+        end
+    else
         begin
         StopSoundChan(Gear^.SoundChannel);
         Gear^.Timer := 250;
@@ -4750,7 +4754,7 @@
     begin
         doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 10, Gear^.Hedgehog, EXPLAutoSound);
         gX := hwRound(Gear^.X);
-        gY := hwRound(Gear^.Y); 
+        gY := hwRound(Gear^.Y);
         for i:= 0 to 10 do
         begin
             dX := AngleCos(i * 2) * ((_0_1*(i div 5))) * (GetRandomf + _1);
@@ -4778,7 +4782,7 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 procedure doStepStructure(Gear: PGear);
-var 
+var
     x, y: LongInt;
     HH: PHedgehog;
     t: PGear;
@@ -4795,7 +4799,7 @@
 
     dec(Gear^.Health, Gear^.Damage);
     Gear^.Damage:= 0;
-        
+
     if Gear^.Pos = 1 then
         begin
         AddGearCI(Gear);
@@ -4806,7 +4810,7 @@
             HideHog(HH);
         Gear^.Pos:= 2
         end;
-        
+
     if Gear^.Pos = 2 then
         begin
         if ((GameTicks mod 100) = 0) and (Gear^.Timer < 1000) then
@@ -4822,7 +4826,7 @@
         if Gear^.Tag <= TotalRounds then
             Gear^.Pos:= 3;
         end;
-        
+
     if Gear^.Pos = 3 then
         if Gear^.Timer < 1000 then
             begin
@@ -4840,7 +4844,7 @@
                 RestoreHog(HH);
             Gear^.Pos:= 4;
             end;
-        
+
     if Gear^.Pos = 4 then
         if ((GameTicks mod 1000) = 0) and ((GameFlags and gfInvulnerable) = 0) then
             begin
@@ -4852,12 +4856,12 @@
                 t:= t^.NextGear;
                 end;
             end;
-        
+
     if Gear^.Health <= 0 then
         begin
         if HH^.GearHidden <> nil then
             RestoreHog(HH);
-        
+
         x := hwRound(Gear^.X);
         y := hwRound(Gear^.Y);
 
@@ -4870,7 +4874,7 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 (*
- TARDIS needs 
+ TARDIS needs
  Warp in.  Pos = 1
  Pause.    Pos = 2
  Hide gear  (TARDIS hedgehog was nil)
@@ -4896,7 +4900,7 @@
             begin
             AfterAttack;
             if Gear = CurAmmoGear then CurAmmoGear := nil;
-            if (HH^.Gear^.Damage = 0) and  (HH^.Gear^.Health > 0) and 
+            if (HH^.Gear^.Damage = 0) and  (HH^.Gear^.Health > 0) and
             ((Gear^.State and (gstMoving or gstHHDeath or gstHHGone)) = 0) then
                 HideHog(HH)
             end
@@ -4916,7 +4920,7 @@
 if (Gear^.Pos = 1) and (GameTicks and $1F = 0) and (Gear^.Power < 255) then
     begin
     inc(Gear^.Power);
-    if (Gear^.Power = 172) and (HH^.Gear <> nil) and 
+    if (Gear^.Power = 172) and (HH^.Gear <> nil) and
         (HH^.Gear^.Damage = 0) and (HH^.Gear^.Health > 0) and
         ((HH^.Gear^.State and (gstMoving or gstHHDeath or gstHHGone)) = 0) then
             with HH^.Gear^ do
@@ -4957,7 +4961,7 @@
         begin
         if HH^.GearHidden <> nil then
             FindPlace(HH^.GearHidden, false, 0, LAND_WIDTH,true);
-            
+
         if HH^.GearHidden <> nil then
             begin
             Gear^.X:= HH^.GearHidden^.X;
@@ -5033,7 +5037,7 @@
 WIP. The ice gun will have the following effects.  It has been proposed by sheepluva that it take the appearance of a large freezer
 spewing ice cubes.  The cubes will be visual gears only.  The scatter from them and the impact snow dust should help hide imprecisions in things like the GearsNear effect.
 For now we assume a "ray" like a deagle projected out from the gun.
-All these effects assume the ray's angle is not changed and that the target type was unchanged over a number of ticks.  This is a simplifying assumption for "gun was applying freezing effect to the same target".  
+All these effects assume the ray's angle is not changed and that the target type was unchanged over a number of ticks.  This is a simplifying assumption for "gun was applying freezing effect to the same target".
   * When fired at water a layer of ice textured land is added above the water.
   * When fired at non-ice land (land and $FF00 and not lfIce) the land is overlaid with a thin layer of ice textured land around that point (say, 1 or 2px into land, 1px above). For attractiveness, a slope would probably be needed.
   * When fired at a hog (land and $00FF <> 0), while the hog is targetted, the hog's state is set to frozen.  As long as the gun is on the hog, a frozen hog sprite creeps up from the feet to the head.  If the effect is interrupted before reaching the top, the freezing state is cleared.
@@ -5073,8 +5077,8 @@
         HedgehogChAngle(HHGear);
         ndX:= SignAs(AngleSin(HHGear^.Angle), HHGear^.dX) * _4;
         ndY:= -AngleCos(HHGear^.Angle) * _4;
-        if (ndX <> dX) or (ndY <> dY) or 
-           ((Target.X <> NoPointX) and (Target.X and LAND_WIDTH_MASK = 0) and 
+        if (ndX <> dX) or (ndY <> dY) or
+           ((Target.X <> NoPointX) and (Target.X and LAND_WIDTH_MASK = 0) and
              (Target.Y and LAND_HEIGHT_MASK = 0) and ((Land[Target.Y, Target.X] = 0))) then
             begin
             dX:= ndX;
@@ -5088,8 +5092,8 @@
             iter := GearsList;
             while iter <> nil do
                 begin
-                if (iter^.Kind = gtHedgehog) and 
-                   (iter^.Hedgehog^.Effects[heFrozen] < 0) then 
+                if (iter^.Kind = gtHedgehog) and
+                   (iter^.Hedgehog^.Effects[heFrozen] < 0) then
                     iter^.Hedgehog^.Effects[heFrozen]:= 0;
                 iter:= iter^.NextGear
                 end *)
@@ -5211,7 +5215,7 @@
         DeleteGear(Gear)
         end;
     // ssssss he essssscaped
-    if (Gear^.Timer > 250) and ((HHGear = nil) or 
+    if (Gear^.Timer > 250) and ((HHGear = nil) or
             (((abs(HHGear^.X.Round-Gear^.X.Round) + abs(HHGear^.Y.Round-Gear^.Y.Round) + 2) >  180) and
             (Distance(HHGear^.X-Gear^.X,HHGear^.Y-Gear^.Y) > _180))) then
         begin
@@ -5222,7 +5226,7 @@
     end;
 
 // Search out a new target, as target seek time has expired, target is dead, target is out of range, or we did not have a target
-if (HHGear = nil) or (Gear^.Timer = 0) or 
+if (HHGear = nil) or (Gear^.Timer = 0) or
    (((abs(HHGear^.X.Round-Gear^.X.Round) + abs(HHGear^.Y.Round-Gear^.Y.Round) + 2) >  Gear^.Angle) and
         (Distance(HHGear^.X-Gear^.X,HHGear^.Y-Gear^.Y) > int2hwFloat(Gear^.Angle)))
     then
@@ -5339,7 +5343,7 @@
  This didn't end up getting used, but, who knows, might be reasonable for javellin or something
 // Make the knife initial angle based on the hog attack angle, or is that too hard?
 procedure doStepKnife(Gear: PGear);
-var t, 
+var t,
     gx, gy, ga,  // gear x,y,angle
     lx, ly, la, // land x,y,angle
     ox, oy, // x,y offset
@@ -5363,7 +5367,7 @@
         begin
         if CheckLandValue(gx, gy, $FF00) then
             begin
-            t:= Angle + hwRound((hwAbs(dX)+hwAbs(dY)) * _10); 
+            t:= Angle + hwRound((hwAbs(dX)+hwAbs(dY)) * _10);
 
             if t < 0 then inc(t, 4096)
             else if 4095 < t then dec(t, 4096);
@@ -5400,7 +5404,7 @@
                 4:  begin
                     ox:= 29; oy:=  8;
                      w:= 19;  h:= 19;
-                    tx:=  0; ty:= 17 
+                    tx:=  0; ty:= 17
                     end;
                 5:  begin
                     ox:= 29; oy:=  32;
@@ -5410,7 +5414,7 @@
                 6:  begin
                     ox:= 51; oy:=   3;
                      w:= 11;  h:=  23;
-                    tx:=  0; ty:=  22 
+                    tx:=  0; ty:=  22
                     end;
                 7:  begin
                     ox:= 51; oy:=  34;
@@ -5418,7 +5422,7 @@
                     tx:=  0; ty:=  23
                     end
                 end;
-                
+
             surf:= SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 32, RMask, GMask, BMask, AMask);
             copyToXYFromRect(SpritesData[sprKnife].Surface, surf, ox, oy, w, h, 0, 0);
             // try to make the knife hit point first
@@ -5440,7 +5444,7 @@
                 AddFileLog('la: '+inttostr(la)+' ga: '+inttostr(ga)+' Angle: '+inttostr(Angle))
                 end;
             case Angle div 1024 of
-                0:  begin 
+                0:  begin
                     flipSurface(surf, true);
                     flipSurface(surf, true);
                     BlitImageAndGenerateCollisionInfo(gx-(w-tx), gy-(h-ty), w, surf)
--- a/hedgewars/VGSHandlers.inc	Sun Dec 02 00:03:16 2012 +0100
+++ b/hedgewars/VGSHandlers.inc	Tue Dec 25 04:45:22 2012 +0100
@@ -60,8 +60,8 @@
     else
         if Angle < - 360 then
             Angle:= Angle + 360;
-    
-  
+
+
     if (round(X) >= cLeftScreenBorder)
     and (round(X) <= cRightScreenBorder)
     and (round(Y) - 75 <= LAND_HEIGHT)
@@ -644,10 +644,10 @@
 begin
 gX:= round(Gear^.X);
 gY:= round(Gear^.Y);
-for i:= 0 to 31 do 
+for i:= 0 to 31 do
     begin
     vg:= AddVisualGear(gX, gY, vgtFire);
-    if vg <> nil then 
+    if vg <> nil then
         begin
         vg^.State:= gstTmpFlag;
         inc(vg^.FrameTicks, vg^.FrameTicks)
@@ -688,10 +688,10 @@
 gX:= round(Gear^.X);
 gY:= round(Gear^.Y);
 AddVisualGear(gX, gY, vgtSmokeRing);
-for i:= 0 to 46 do 
+for i:= 0 to 46 do
     begin
     vg:= AddVisualGear(gX, gY, vgtFire);
-    if vg <> nil then 
+    if vg <> nil then
         begin
         vg^.State:= gstTmpFlag;
         inc(vg^.FrameTicks, vg^.FrameTicks)
@@ -704,7 +704,9 @@
 Gear^.doStep:= @doStepBigExplosionWork;
 if Steps > 1 then
     Gear^.doStep(Gear, Steps-1);
-performRumble();
+with mobileRecord do
+    if (performRumble <> nil) and (not fastUntilLag) then
+        performRumble(kSystemSoundID_Vibrate);
 end;
 
 procedure doStepChunk(Gear: PVisualGear; Steps: Longword);
@@ -766,7 +768,7 @@
 procedure doStepSmoothWindBar(Gear: PVisualGear; Steps: Longword);
 begin
 inc(Gear^.Timer, Steps);
-    
+
 while Gear^.Timer >= 10 do
     begin
     dec(Gear^.Timer, 10);
@@ -785,8 +787,8 @@
     cWindspeedf := cWindspeedf + Gear^.Angle*Steps;
     if cWindspeedf > Gear^.dAngle then cWindspeedf:= Gear^.dAngle;
     end;
-        
-if (WindBarWidth = Gear^.Tag) and (cWindspeedf = Gear^.dAngle)  then 
+
+if (WindBarWidth = Gear^.Tag) and (cWindspeedf = Gear^.dAngle)  then
     DeleteVisualGear(Gear)
 end;
 ////////////////////////////////////////////////////////////////////////////////
@@ -800,7 +802,7 @@
 else
     begin
     dec(Gear^.FrameTicks, Steps);
-    if (Gear^.FrameTicks < 501) and (Gear^.FrameTicks mod 5 = 0) then 
+    if (Gear^.FrameTicks < 501) and (Gear^.FrameTicks mod 5 = 0) then
         Gear^.Tint:= (Gear^.Tint and $FFFFFF00) or (((Gear^.Tint and $000000FF) * Gear^.FrameTicks) div 500)
     end
 end;
--- a/hedgewars/config.inc.in	Sun Dec 02 00:03:16 2012 +0100
+++ b/hedgewars/config.inc.in	Tue Dec 25 04:45:22 2012 +0100
@@ -24,3 +24,4 @@
 const cNetProtoVersion = ${HEDGEWARS_PROTO_VER};
       cVersionString = '${HEDGEWARS_VERSION}';
       cLuaLibrary = '${LUA_LIBRARY}';
+      cDefaultPathPrefix = '${CMAKE_INSTALL_PREFIX}/${SHAREPATH}/Data';
--- a/hedgewars/hwengine.pas	Sun Dec 02 00:03:16 2012 +0100
+++ b/hedgewars/hwengine.pas	Tue Dec 25 04:45:22 2012 +0100
@@ -29,21 +29,23 @@
 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, uLandTexture, uCollisions,
-     uAILandMarks, SysUtils, uTypes, uVariables, uCommands, uUtils, uCaptions, uDebug, uCommandHandlers,
-     uLandPainted, uFloat, uPhysFSLayer
+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
+     , SysUtils, uTypes, uVariables, uCommands, uUtils, uCaptions, uDebug, uCommandHandlers, uLandPainted
+     , uPhysFSLayer, uCursor
      {$IFDEF USE_VIDEO_RECORDING}, uVideoRec {$ENDIF}
      {$IFDEF USE_TOUCH_INTERFACE}, uTouch {$ENDIF}
      {$IFDEF ANDROID}, GLUnit{$ENDIF}
      {$IFDEF WEBGL}, uWeb{$ENDIF}
      ;
 
+var isInternal: Boolean;
+
 {$IFDEF HWLIBRARY}
 procedure preInitEverything();
 procedure initEverything(complete:boolean);
 procedure freeEverything(complete:boolean);
-procedure Game(gameArgs: PPChar); cdecl; export;
+procedure Game(argc: LongInt; argv: PPChar); cdecl; export;
 procedure GenLandPreview(port: Longint); cdecl; export;
 
 implementation
@@ -53,6 +55,8 @@
 procedure freeEverything(complete:boolean); forward;
 {$ENDIF}
 
+{$INCLUDE "ArgParsers.inc"}
+
 {$IFDEF WEBGL}
 procedure playFile(path: PChar); forward;
 function isEngineRunning():Integer; forward;
@@ -185,7 +189,7 @@
 {$ENDIF}
 
         SDL_PumpEvents();
- 
+
         while SDL_PeepEvents(@event, 1, SDL_GETEVENT, {$IFDEF SDL13}SDL_FIRSTEVENT, SDL_LASTEVENT{$ELSE}SDL_ALLEVENTS{$ENDIF}) > 0 do
         begin
             case event.type_ of
@@ -199,7 +203,7 @@
                 SDL_KEYUP:
                     if GameState <> gsChat then
                         ProcessKey(event.key);
-                    
+
                 SDL_WINDOWEVENT:
                     if event.window.event = SDL_WINDOWEVENT_SHOWN then
                     begin
@@ -225,13 +229,13 @@
                         cNewScreenHeight:= max(2 * (event.window.data2 div 2), cMinScreenHeight);
                         cScreenResizeDelay:= RealTicks + 500{$IFDEF IPHONEOS}div 2{$ENDIF};
                     end;
-                        
+
                 SDL_FINGERMOTION:
                     onTouchMotion(event.tfinger.x, event.tfinger.y,event.tfinger.dx, event.tfinger.dy, event.tfinger.fingerId);
-                
+
                 SDL_FINGERDOWN:
                     onTouchDown(event.tfinger.x, event.tfinger.y, event.tfinger.fingerId);
-                
+
                 SDL_FINGERUP:
                     onTouchUp(event.tfinger.x, event.tfinger.y, event.tfinger.fingerId);
 {$ELSE}
@@ -243,13 +247,19 @@
                 SDL_KEYUP:
                     if GameState <> gsChat then
                         ProcessKey(event.key);
-                    
+
                 SDL_MOUSEBUTTONDOWN:
-                    ProcessMouse(event.button, true);
-                    
+                    if GameState = gsConfirm then
+                    begin
+                        resetPosition();
+                        ParseCommand('quit', true);
+                    end
+                    else
+                        ProcessMouse(event.button, true);
+
                 SDL_MOUSEBUTTONUP:
-                    ProcessMouse(event.button, false); 
-                    
+                    ProcessMouse(event.button, false);
+
                 SDL_ACTIVEEVENT:
                     if (event.active.state and SDL_APPINPUTFOCUS) <> 0 then
                     begin
@@ -258,7 +268,7 @@
                         if prevFocusState xor cHasFocus then
                             onFocusStateChanged()
                     end;
-                        
+
                 SDL_VIDEORESIZE:
                 begin
                     // using lower values than cMinScreenWidth or cMinScreenHeight causes widget overlap and off-screen widget parts
@@ -354,7 +364,7 @@
 {$ENDIF}
 
 ///////////////////////////////////////////////////////////////////////////////
-procedure Game{$IFDEF HWLIBRARY}(gameArgs: PPChar); cdecl; export{$ENDIF};
+procedure Game{$IFDEF HWLIBRARY}(argc: LongInt; argv: PPChar); cdecl; export{$ENDIF};
 var p: TPathType;
     s: shortstring;
     i: LongInt;
@@ -365,24 +375,11 @@
 begin
 {$IFDEF HWLIBRARY}
     preInitEverything();
-    cShowFPS:= {$IFDEF DEBUGFILE}true{$ELSE}false{$ENDIF};
-    ipcPort:= StrToInt(gameArgs[0]);
-    cScreenWidth:= StrToInt(gameArgs[1]);
-    cScreenHeight:= StrToInt(gameArgs[2]);
-    cReducedQuality:= StrToInt(gameArgs[3]);
-    cLocaleFName:= gameArgs[4];
-    UserNick:= gameArgs[5];
-    SetSound(gameArgs[6] = '1');
-    SetMusic(gameArgs[7] = '1');
-    cAltDamage:= gameArgs[8] = '1';
-    PathPrefix:= gameArgs[9];
-    UserPathPrefix:= '../Documents';
-    recordFileName:= gameArgs[10];
+    parseCommandLine(argc, argv);
 {$ENDIF}
     initEverything(true);
+    WriteLnToConsole('Hedgewars ' + cVersionString + ' engine (network protocol: ' + inttostr(cNetProtoVersion) + ')');
 
-    WriteLnToConsole('Hedgewars ' + cVersionString + ' engine (network protocol: ' + inttostr(cNetProtoVersion) + ')');
-    
     for i:= 0 to ParamCount do
         AddFileLog(inttostr(i) + ': ' + ParamStr(i));
 
@@ -402,7 +399,7 @@
         InitOffscreenOpenGL()
     else
 {$ENDIF}
-        begin            
+        begin
         // show main window
         if cFullScreen then
             ParseCommand('fullscr 1', true)
@@ -460,7 +457,7 @@
         exit;
     end;
 {$ENDIF}
-	
+
 {$IFDEF WEBGL}
     l := generateResourceList();
     clear_filelist_hook();
@@ -592,60 +589,6 @@
 end;
 
 {$IFNDEF HWLIBRARY}
-///////////////////////////////////////////////////////////////////////////////
-procedure DisplayUsage;
-var i: LongInt;
-begin
-    WriteLn(stdout, 'Wrong argument format: correct configurations is');
-    WriteLn(stdout, '');
-    WriteLn(stdout, '  hwengine <path to user hedgewars folder> <path to global data folder> <path to replay file> [options]');
-    WriteLn(stdout, '');
-    WriteLn(stdout, 'where [options] must be specified either as:');
-    WriteLn(stdout, ' --set-video [screen width] [screen height] [color dept]');
-    WriteLn(stdout, ' --set-audio [volume] [enable music] [enable sounds]');
-    WriteLn(stdout, ' --set-other [language file] [full screen] [show FPS]');
-    WriteLn(stdout, ' --set-multimedia [screen width] [screen height] [color dept] [volume] [enable music] [enable sounds] [language file] [full screen]');
-    WriteLn(stdout, ' --set-everything [screen width] [screen height] [color dept] [volume] [enable music] [enable sounds] [language file] [full screen] [show FPS] [alternate damage] [timer value] [reduced quality]');
-    WriteLn(stdout, ' --stats-only');
-    WriteLn(stdout, '');
-    WriteLn(stdout, 'Read documentation online at http://code.google.com/p/hedgewars/wiki/CommandLineOptions for more information');
-    WriteLn(stdout, '');
-    Write(stdout, 'PARSED COMMAND: ');
-    
-    for i:=0 to ParamCount do
-        Write(stdout, ParamStr(i) + ' ');
-        
-    WriteLn(stdout, '');
-end;
-
-///////////////////////////////////////////////////////////////////////////////
-{$INCLUDE "ArgParsers.inc"}
-
-procedure GetParams;
-begin
-    if (ParamCount < 3) then
-        GameType:= gmtSyntax
-    else
-        if (ParamCount = 3) and (ParamStr(3) = 'landpreview') then
-            begin
-            ipcPort:= StrToInt(ParamStr(2));
-            GameType:= gmtLandPreview;
-            end
-        else
-            begin
-            if (ParamCount = 3) and (ParamStr(3) = '--stats-only') then
-                playReplayFileWithParameters()
-            else
-                if ParamCount = cDefaultParamNum then
-                    internalStartGameWithParameters()
-{$IFDEF USE_VIDEO_RECORDING}
-                else if ParamCount = cVideorecParamNum then
-                    internalStartVideoRecordingWithParameters()
-{$ENDIF}
-                else
-                    playReplayFileWithParameters();
-            end
-end;
 
 ///////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////// m a i n ///////////////////////////////////
@@ -667,9 +610,8 @@
 
     if GameType = gmtLandPreview then
         GenLandPreview()
-    else if GameType = gmtSyntax then
-        DisplayUsage()
-    else Game();
+    else if GameType <> gmtSyntax then
+        Game();
 
     // return 1 when engine is not called correctly
     {$IFDEF PAS2C}
--- a/hedgewars/options.inc	Sun Dec 02 00:03:16 2012 +0100
+++ b/hedgewars/options.inc	Tue Dec 25 04:45:22 2012 +0100
@@ -50,12 +50,12 @@
 
 {$IFDEF MOBILE}
     {$DEFINE HWLIBRARY}
-    {$DEFINE S3D_DISABLED}
     {$DEFINE GLunit:=gles11}
     {$DEFINE USE_LANDSCAPE_AMMOMENU}
     {$DEFINE USE_TOUCH_INTERFACE}
 {$ELSE}
     {$DEFINE USE_AM_NUMCOLUMN}
+    {$DEFINE USE_S3D_RENDERING}
 {$ENDIF}
 
 
--- a/hedgewars/uAIAmmoTests.pas	Sun Dec 02 00:03:16 2012 +0100
+++ b/hedgewars/uAIAmmoTests.pas	Tue Dec 25 04:45:22 2012 +0100
@@ -21,7 +21,7 @@
 unit uAIAmmoTests;
 interface
 uses SDLh, uConsts, uFloat, uTypes;
-const 
+const
     amtest_Rare     = $00000001; // check only several positions
     amtest_NoTarget = $00000002; // each pos, but no targetting
 
@@ -116,7 +116,7 @@
             (proc: nil;              flags: 0), // amDrillStrike
             (proc: nil;              flags: 0), // amSnowball
             (proc: nil;              flags: 0), // amTardis
-            (proc: nil;              flags: 0), // amStructure
+            //(proc: nil;              flags: 0), // amStructure
             (proc: nil;              flags: 0), // amLandGun
             (proc: nil;              flags: 0), // amIceGun
             (proc: nil;              flags: 0)  // amKnife
@@ -163,9 +163,9 @@
             dX:= dX + windSpeed;
             dY:= dY + cGravityf;
             dec(t)
-        until (((Me = CurrentHedgehog^.Gear) and TestColl(trunc(x), trunc(y), 5)) or 
+        until (((Me = CurrentHedgehog^.Gear) and TestColl(trunc(x), trunc(y), 5)) or
                ((Me <> CurrentHedgehog^.Gear) and TestCollExcludingMe(Me, trunc(x), trunc(y), 5))) or (t <= 0);
-        
+
         EX:= trunc(x);
         EY:= trunc(y);
         if Level = 1 then
@@ -222,9 +222,9 @@
                 dX:= dX + windSpeed;
                 dY:= dY + cGravityf;
                 dec(t)
-            until (((Me = CurrentHedgehog^.Gear) and TestColl(trunc(x), trunc(y), 5)) or 
+            until (((Me = CurrentHedgehog^.Gear) and TestColl(trunc(x), trunc(y), 5)) or
                    ((Me <> CurrentHedgehog^.Gear) and TestCollExcludingMe(Me, trunc(x), trunc(y), 5))) or (y > cWaterLine);
-            
+
             EX:= trunc(x);
             EY:= trunc(y);
             if Level = 1 then
@@ -281,7 +281,7 @@
             dX:= dX + windSpeed;
             dY:= dY + cGravityf;
             dec(t)
-        until (((Me = CurrentHedgehog^.Gear) and TestColl(trunc(x), trunc(y), 5)) or 
+        until (((Me = CurrentHedgehog^.Gear) and TestColl(trunc(x), trunc(y), 5)) or
                ((Me <> CurrentHedgehog^.Gear) and TestCollExcludingMe(Me, trunc(x), trunc(y), 5))) or (t <= 0);
         EX:= trunc(x);
         EY:= trunc(y);
@@ -333,7 +333,7 @@
             y:= y + dY;
             dY:= dY + cGravityf;
             dec(t)
-        until (((Me = CurrentHedgehog^.Gear) and TestColl(trunc(x), trunc(y), 6)) or 
+        until (((Me = CurrentHedgehog^.Gear) and TestColl(trunc(x), trunc(y), 6)) or
                ((Me <> CurrentHedgehog^.Gear) and TestCollExcludingMe(Me, trunc(x), trunc(y), 6))) or (t = 0);
         EX:= trunc(x);
         EY:= trunc(y);
@@ -341,7 +341,7 @@
             Score:= RateExplosion(Me, EX, EY, 97)  // average of 17 attempts, most good, but some failing spectacularly
         else
             Score:= BadTurn;
-                  
+
         if valueResult < Score then
             begin
             ap.Angle:= DxDy2AttackAnglef(Vx, Vy) + AIrndSign(random(Level));
@@ -377,7 +377,7 @@
     if not (r > 1) then
         begin
         x:= meX;
-        y:= meY; 
+        y:= meY;
         dY:= -Vy;
         t:= TestTime;
         repeat
@@ -385,15 +385,15 @@
             y:= y + dY;
             dY:= dY + cGravityf;
             dec(t)
-        until (((Me = CurrentHedgehog^.Gear) and TestColl(trunc(x), trunc(y), 5)) or 
+        until (((Me = CurrentHedgehog^.Gear) and TestColl(trunc(x), trunc(y), 5)) or
                ((Me <> CurrentHedgehog^.Gear) and TestCollExcludingMe(Me, trunc(x), trunc(y), 5))) or (t = 0);
     EX:= trunc(x);
     EY:= trunc(y);
-    if t < 50 then 
+    if t < 50 then
         if Level = 1 then
             Score:= RateExplosion(Me, EX, EY, 101, afTrackFall or afErasesLand)
         else Score:= RateExplosion(Me, EX, EY, 101)
-    else 
+    else
         Score:= BadTurn;
 
     if (valueResult < Score) and (Score > 0) then
@@ -445,13 +445,13 @@
         y:= y + dY;
         dY:= dY + cGravityf;
         dec(t)
-    until (((Me = CurrentHedgehog^.Gear) and TestColl(trunc(x), trunc(y), 5)) or 
+    until (((Me = CurrentHedgehog^.Gear) and TestColl(trunc(x), trunc(y), 5)) or
            ((Me <> CurrentHedgehog^.Gear) and TestCollExcludingMe(Me, trunc(x), trunc(y), 5))) or (t = 0);
     EX:= trunc(x);
     EY:= trunc(y);
-    if t < 50 then 
+    if t < 50 then
         Score:= RateExplosion(Me, EX, EY, 41)
-    else 
+    else
         Score:= BadTurn;
 
      if valueResult < Score then
@@ -498,16 +498,16 @@
             y:= y + dY;
             dY:= dY + cGravityf;
             dec(t)
-       until (((Me = CurrentHedgehog^.Gear) and TestColl(trunc(x), trunc(y), 6)) or 
+       until (((Me = CurrentHedgehog^.Gear) and TestColl(trunc(x), trunc(y), 6)) or
                ((Me <> CurrentHedgehog^.Gear) and TestCollExcludingMe(Me, trunc(x), trunc(y), 6))) or (t = 0);
-        
+
         EX:= trunc(x);
         EY:= trunc(y);
-        if t < 50 then 
+        if t < 50 then
             Score:= RateExplosion(Me, EX, EY, 200) + RateExplosion(Me, EX, EY + 120, 200)
-        else 
+        else
             Score:= BadTurn;
-            
+
         if valueResult < Score then
             begin
             ap.Angle:= DxDy2AttackAnglef(Vx, Vy) + AIrndSign(random(Level));
@@ -544,7 +544,7 @@
             else
                 Solve:= 0
     end;
-    
+
 function TestMortar(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
 //const tDelta = 24;
 var Vx, Vy: real;
@@ -579,7 +579,7 @@
         dY:= dY + cGravityf;
         EX:= trunc(x);
         EY:= trunc(y);
-    until (((Me = CurrentHedgehog^.Gear) and TestColl(EX, EY, 4)) or 
+    until (((Me = CurrentHedgehog^.Gear) and TestColl(EX, EY, 4)) or
            ((Me <> CurrentHedgehog^.Gear) and TestCollExcludingMe(Me, EX, EY, 4))) or (EY > cWaterLine);
 
     if (EY < cWaterLine) and (dY >= 0) then
@@ -633,16 +633,16 @@
     y:= y + vY;
     rx:= trunc(x);
     ry:= trunc(y);
-    if ((Me = CurrentHedgehog^.Gear) and TestColl(rx, ry, 2)) or 
+    if ((Me = CurrentHedgehog^.Gear) and TestColl(rx, ry, 2)) or
         ((Me <> CurrentHedgehog^.Gear) and TestCollExcludingMe(Me, rx, ry, 2)) then
     begin
         x:= x + vX * 8;
         y:= y + vY * 8;
         valueResult:= RateShotgun(Me, vX, vY, rx, ry);
-     
-        if valueResult = 0 then 
+
+        if valueResult = 0 then
             valueResult:= 1024 - Metric(Targ.X, Targ.Y, rx, ry) div 64
-        else 
+        else
             dec(valueResult, Level * 4000);
         // 27/20 is reuse bonus
         exit(valueResult * 27 div 20)
@@ -748,7 +748,7 @@
     fallDmg:= TraceShoveFall(Targ.X, Targ.Y, vX * 0.00166 * dmg, vY * 0.00166 * dmg);
     if fallDmg < 0 then
         TestSniperRifle:= BadTurn
-    else 
+    else
         TestSniperRifle:= Max(0, trunc((dmg + fallDmg) * dmgMod) * 1024)
     end
 else
@@ -787,13 +787,13 @@
                 , 32, 30, 115
                 , dx, -dy, trackFall);
         if (v1 > valueResult) or (v2 > valueResult) then
-            if (v2 > v1) 
+            if (v2 > v1)
                 or {don't encourage turning for no gain}((v2 = v1) and (not Me^.dX.isNegative)) then
                 begin
                 ap.Angle:= a;
                 valueResult:= v2
                 end
-            else 
+            else
                 begin
                 ap.Angle:= -a;
                 valueResult:= v1
@@ -801,7 +801,7 @@
 
         a:= a - 15 - random(cMaxAngle div 16)
         end;
-   
+
     if valueResult <= 0 then
         valueResult:= BadTurn;
 
@@ -847,18 +847,18 @@
             , 19, 30, 40
             , 0.45, -0.9, trackFall);
 
-    if (v2 > v1) 
+    if (v2 > v1)
         or {don't encourage turning for no gain}((v2 = v1) and (not Me^.dX.isNegative)) then
         begin
         ap.Angle:= 1;
         valueResult:= v2
         end
-    else 
+    else
         begin
         ap.Angle:= -1;
         valueResult:= v1
         end;
-    
+
     if valueResult <= 0 then
         valueResult:= BadTurn;
 
@@ -882,8 +882,8 @@
     y:= hwRound(Me^.Y);
 
     // check left direction
-    {first RateShove checks farthermost of two whip's AmmoShove attacks 
-    to encourage distant attacks (damaged hog is excluded from view of second 
+    {first RateShove checks farthermost of two whip's AmmoShove attacks
+    to encourage distant attacks (damaged hog is excluded from view of second
     RateShove call)}
     v1:= RateShove(x - 13, y
             , 30, 30, 25
@@ -901,18 +901,18 @@
             , 30, 30, 25
             , 1, -0.8, trackFall);
 
-    if (v2 > v1) 
+    if (v2 > v1)
         or {don't encourage turning for no gain}((v2 = v1) and (not Me^.dX.isNegative)) then
         begin
         ap.Angle:= 1;
         valueResult:= v2
         end
-    else 
+    else
         begin
         ap.Angle:= -1;
         valueResult:= v1
         end;
-    
+
     if valueResult <= 0 then
         valueResult:= BadTurn
     else
@@ -931,13 +931,13 @@
     ap.Time:= 0;
     ap.Power:= 1;
 
-    if Level = 1 then 
+    if Level = 1 then
         trackFall:= afTrackFall
     else if Level = 2 then
         trackFall:= 0
     else
         exit(BadTurn);
-        
+
     valueResult:= 0;
     v:= 0;
 
@@ -958,16 +958,16 @@
 
         ap.Angle:= DxDy2AttackAnglef(dx, -dy)
         end;
-    
+
     if dx >= 0 then cx:= 0.45 else cx:= -0.45;
 
     for i:= 0 to 512 div step - 2 do
         begin
-        valueResult:= valueResult + 
+        valueResult:= valueResult +
             RateShove(trunc(x), trunc(y)
                 , 30, 30, 25
                 , cx, -0.9, trackFall or afSetSkip);
-                
+
         x:= x + dx;
         y:= y + dy;
         end;
@@ -982,7 +982,7 @@
         for i:= 1 to 512 div step - 2 do
             begin
             y:= y + dy;
-            v:= v + 
+            v:= v +
                 RateShove(tx, trunc(y)
                     , 30, 30, 25
                     , -cx, -0.9, trackFall or afSetSkip);
@@ -1015,7 +1015,7 @@
 ap.Time:= 0;
 ap.Power:= 1;
 ap.Angle:= 0;
-         
+
 rate:= RateHammer(Me);
 if rate = 0 then
     rate:= BadTurn;
@@ -1106,7 +1106,7 @@
         if Me^.Health <= 100  then
             begin
             maxTop := Targ.Y - cHHRadius * 2;
-            
+
             while (not TestColl(Targ.X, maxTop, cHHRadius)) and (maxTop > topY + cHHRadius * 2 + 1) do
                 dec(maxTop, cHHRadius*2);
             if not TestColl(Targ.X, maxTop + cHHRadius, cHHRadius) then
@@ -1125,7 +1125,7 @@
             inc(failNum);
         until not TestColl(bonuses.ar[i].X, bonuses.ar[i].Y - cHHRadius - bonuses.ar[i].Radius, cHHRadius)
         or (failNum = bonuses.Count*2);
-        
+
         if failNum < bonuses.Count*2 then
             begin
             ap.AttackPutX := bonuses.ar[i].X;
@@ -1147,7 +1147,7 @@
     begin
     cakeStep(Gear);
     v:= RateExplosion(Me, hwRound(Gear^.X), hwRound(Gear^.Y), cakeDmg * 2, afTrackFall);
-    if v > ap.Power then 
+    if v > ap.Power then
         begin
         ap.ExplX:= hwRound(Gear^.X);
         ap.ExplY:= hwRound(Gear^.Y);
--- a/hedgewars/uChat.pas	Sun Dec 02 00:03:16 2012 +0100
+++ b/hedgewars/uChat.pas	Tue Dec 25 04:45:22 2012 +0100
@@ -41,6 +41,7 @@
     Width: LongInt;
     s: shortstring;
     end;
+    TChatCmd = (quit, pause, finish, fullscreen);
 
 var Strs: array[0 .. MaxStrIndex] of TChatLine;
     MStrs: array[0 .. MaxStrIndex] of shortstring;
@@ -52,15 +53,25 @@
     ChatReady: boolean;
     showAll: boolean;
 
-const colors: array[#0..#6] of TSDL_Color = (
-    (r:$FF; g:$FF; b:$FF; unused:$FF), // unused, feel free to take it for anything
-    (r:$FF; g:$FF; b:$FF; unused:$FF), // chat message [White]
-    (r:$FF; g:$00; b:$FF; unused:$FF), // action message [Purple]
-    (r:$90; g:$FF; b:$90; unused:$FF), // join/leave message [Lime]
-    (r:$FF; g:$FF; b:$A0; unused:$FF), // team message [Light Yellow]
-    (r:$FF; g:$00; b:$00; unused:$FF), // error messages [Red]
-    (r:$00; g:$FF; b:$FF; unused:$FF)  // input line [Light Blue]
-    );
+const
+    colors: array[#0..#6] of TSDL_Color = (
+            (r:$FF; g:$FF; b:$FF; unused:$FF), // unused, feel free to take it for anything
+            (r:$FF; g:$FF; b:$FF; unused:$FF), // chat message [White]
+            (r:$FF; g:$00; b:$FF; unused:$FF), // action message [Purple]
+            (r:$90; g:$FF; b:$90; unused:$FF), // join/leave message [Lime]
+            (r:$FF; g:$FF; b:$A0; unused:$FF), // team message [Light Yellow]
+            (r:$FF; g:$00; b:$00; unused:$FF), // error messages [Red]
+            (r:$00; g:$FF; b:$FF; unused:$FF)  // input line [Light Blue]
+            );
+    ChatCommandz: array [TChatCmd] of record
+            ChatCmd: string[31];
+            ProcedureCallChatCmd: string[31];
+            end = (
+            (ChatCmd: '/quit'; ProcedureCallChatCmd: 'halt'),
+            (ChatCmd: '/pause'; ProcedureCallChatCmd: 'pause'),
+            (ChatCmd: '/finish'; ProcedureCallChatCmd: 'finish'),
+            (ChatCmd: '/fullscreen'; ProcedureCallChatCmd: 'fullscr')
+            );
 
 procedure SetLine(var cl: TChatLine; str: shortstring; isInput: boolean);
 var strSurface, resSurface: PSDL_Surface;
@@ -181,7 +192,7 @@
         i:= MaxStrIndex
     else
         dec(i);
-        
+
     inc(cnt);
     inc(t)
     end;
@@ -197,6 +208,7 @@
 
 procedure AcceptChatString(s: shortstring);
 var i: TWave;
+    j: TChatCmd;
     c, t: LongInt;
     x: byte;
 begin
@@ -204,13 +216,13 @@
 x:= 0;
 if (s[1] = '"') and (s[Length(s)] = '"')
     then x:= 1
-    
+
 else if (s[1] = '''') and (s[Length(s)] = '''') then
     x:= 2
-    
+
 else if (s[1] = '-') and (s[Length(s)] = '-') then
     x:= 3;
-    
+
 if (not CurrentTeam^.ExtDriven) and (x <> 0) then
     for c:= 0 to Pred(TeamsCount) do
         if (TeamsArray[c] = CurrentTeam) then
@@ -267,6 +279,13 @@
             ParseCommand('/taunt ' + char(i), true);
             exit
             end;
+
+    for j:= Low(TChatCmd) to High(TChatCmd) do
+        if (s = ChatCommandz[j].ChatCmd) then
+            begin
+            ParseCommand(ChatCommandz[j].ProcedureCallChatCmd, true);
+            exit
+            end;
     end
     else
         ParseCommand('/say ' + s, true);
--- a/hedgewars/uCommandHandlers.pas	Sun Dec 02 00:03:16 2012 +0100
+++ b/hedgewars/uCommandHandlers.pas	Tue Dec 25 04:45:22 2012 +0100
@@ -30,11 +30,13 @@
      {$IFDEF USE_VIDEO_RECORDING}, uVideoRec {$ENDIF};
 
 var prevGState: TGameState = gsConfirm;
+    cTagsMasks : array[0..15] of byte = (7, 0, 0, 0, 15, 6, 4, 5, 0, 0, 0, 0, 0, 14, 12, 13);
+    cTagsMasksNoHealth: array[0..15] of byte = (3, 2, 11, 1, 0, 0, 0, 0, 0, 10, 0, 9, 0, 0, 0, 0);
 
 procedure chGenCmd(var s: shortstring);
 begin
 case s[1] of
-    'R': if ReadyTimeLeft > 1 then 
+    'R': if ReadyTimeLeft > 1 then
         begin
         ReadyTimeLeft:= 1;
         if not isExternalSource then
@@ -479,7 +481,7 @@
 with CurrentHedgehog^.Gear^ do
     begin
     Message:= Message or (gmSlot and InputMask);
-    MsgParam:= slot; 
+    MsgParam:= slot;
     ScriptCall('onSlot', MsgParam);
     end
 end;
@@ -516,7 +518,7 @@
 with CurrentHedgehog^.Gear^ do
     begin
     Message:= Message or (gmAnimate and InputMask);
-    MsgParam:= byte(s[1]) ; 
+    MsgParam:= byte(s[1]) ;
     ScriptCall('onTaunt', MsgParam);
     end
 end;
--- a/hedgewars/uConsts.pas	Sun Dec 02 00:03:16 2012 +0100
+++ b/hedgewars/uConsts.pas	Tue Dec 25 04:45:22 2012 +0100
@@ -27,8 +27,6 @@
 
 const
     sfMax = 1000;
-    cDefaultParamNum = 17;
-    cVideorecParamNum = cDefaultParamNum + 7;
 
     // message constants
     errmsgCreateSurface   = 'Error creating SDL surface';
@@ -92,7 +90,7 @@
 // lfObject and lfBasic are only to be different *graphically*  in all other ways they should be treated the same
     lfBasic          = $8000;  // white
     lfIndestructible = $4000;  // red
-    lfObject         = $2000;  
+    lfObject         = $2000;
     lfDamaged        = $1000;  //
     lfIce            = $0800;  // blue
     lfBouncy         = $0400;  // green
@@ -112,9 +110,7 @@
     GL_TEXTURE_PRIORITY = $8066;
     {$ENDIF}
 
-    cSendCursorPosTime  : LongWord = 50;
     cVisibleWater       : LongInt = 128;
-    cCursorEdgesDist    : LongInt = 100;
     cTeamHealthWidth    : LongInt = 128;
 
     cifRandomize = $00000001;
@@ -122,8 +118,6 @@
     cifMap       = $00000002; // either theme or map (or map+theme)
     cifAllInited = cifRandomize or cifTheme or cifMap;
 
-    cTransparentColor: Longword = $00000000;
-
     RGB_LUMINANCE_RED    = 0.212671;
     RGB_LUMINANCE_GREEN  = 0.715160;
     RGB_LUMINANCE_BLUE   = 0.072169;
@@ -131,18 +125,14 @@
     cMaxTeams        = 8;
     cMaxHHIndex      = 7;
     cMaxHHs          = 48;
-    cMaxSpawnPoints  = 1024;
 
     cMaxEdgePoints = 16384;
 
     cHHRadius = 9;
     cHHStepTicks = 29;
 
-    cUsualZ = 500;
-    cSmokeZ = 499;
     cHHZ = 1000;
     cCurrHHZ = Succ(cHHZ);
-    cOnHHZ = 2000;
 
     cBarrelHealth = 60;
     cShotgunRadius = 22;
@@ -152,18 +142,11 @@
     cKeyMaxIndex = 1600;
     cKbdMaxIndex = 65536;//need more room for the modifier keys
 
-    cHHFileName = 'Hedgehog';
-    cCHFileName = 'Crosshair';
-    cThemeCFGFilename = 'theme.cfg';
-
     cFontBorder = 2;
 
     // do not change this value
     cDefaultZoomLevel = 2.0;
 
-    cSendEmptyPacketTime = 1000;
-    trigTurns = $80000001;
-
     // game flags
     gfAny                = $FFFFFFFF;
     gfOneClanMode        = $00000001;           // used in trainings
@@ -242,11 +225,11 @@
 
     cMaxSlotIndex       = 9;
     cMaxSlotAmmoIndex   = 5;
-    
+
     // ai hints
     aihUsualProcessing    = $00000000;
     aihDoesntMatter       = $00000001;
-    
+
     // ammo properties
     ammoprop_Timerable    = $00000001;
     ammoprop_Power        = $00000002;
@@ -262,7 +245,7 @@
     ammoprop_Utility      = $00001000;
     ammoprop_Effect       = $00002000;
     ammoprop_SetBounce    = $00004000;
-    ammoprop_NeedUpDown   = $00008000;//Used by TouchInterface to show or hide up/down widgets 
+    ammoprop_NeedUpDown   = $00008000;//Used by TouchInterface to show or hide up/down widgets
     ammoprop_OscAim       = $00010000;
     ammoprop_NoMoveAfter  = $00020000;