Merge default. This branch is up-to-date and code is working. qmlfrontend
authorunc0rr
Sun, 17 Dec 2017 00:09:24 +0100
branchqmlfrontend
changeset 12855 1b2b84315d27
parent 11843 01f88c3b7b66 (current diff)
parent 12854 28cb18c5e712 (diff)
child 12856 95d903b976d0
Merge default. This branch is up-to-date and code is working.
.hgignore
CMakeLists.txt
INSTALL
QTfrontend/net/tcpBase.cpp
QTfrontend/res/btnForts.png
QTfrontend/res/btnForts@2x.png
QTfrontend/res/campaign/A_Classic_Fairytale/journey.png
QTfrontend/res/campaign/A_Classic_Fairytale/shadow.png
QTfrontend/util/platform/Xfire Game SDK.url
QTfrontend/util/platform/xfire.cpp
QTfrontend/util/platform/xfire.h
QTfrontend/util/platform/xfire_license.txt
QTfrontend/util/platform/xfiregameclient.cpp
QTfrontend/util/platform/xfiregameclient.h
gameServer/OfficialServer/checker.hs
hedgewars/CMakeLists.txt
hedgewars/SDLh.pas
hedgewars/hwengine.pas
hedgewars/uIO.pas
hedgewars/uInputHandler.pas
hedgewars/uLocale.pas
hedgewars/uMisc.pas
hedgewars/uPhysFSLayer.pas
hedgewars/uRender.pas
hedgewars/uTypes.pas
hedgewars/uUtils.pas
hedgewars/uVariables.pas
misc/loc_gen.txt
project_files/hedgewars.kdevelop
qmlFrontend/hwengine.cpp
share/hedgewars/Data/Graphics/AmmoMenu/Ammos.png
share/hedgewars/Data/Graphics/AmmoMenu/Ammos_bw.png
share/hedgewars/Data/Graphics/Missions/Training/Basic_Training_-_Sniper_Rifle.png
share/hedgewars/Data/Graphics/Missions/Training/Basic_Training_-_Sniper_Rifle@2x.png
share/hedgewars/Data/Graphics/Missions/Training/Challenge_-_Speed_Shoppa_-_Hedgelove@2x.png
share/hedgewars/Data/Graphics/Missions/Training/Challenge_-_Speed_Shoppa_-_Ropes@2x.png
share/hedgewars/Data/Graphics/Missions/Training/Challenge_-_Speed_Shoppa_-_ShoppaKing@2x.png
share/hedgewars/Data/Graphics/Missions/Training/ClimbHome.png
share/hedgewars/Data/Graphics/Missions/Training/ClimbHome@2x.png
share/hedgewars/Data/Graphics/Missions/Training/Target_Practice_-_Bazooka_easy@2x.png
share/hedgewars/Data/Graphics/Missions/Training/Target_Practice_-_Bazooka_hard@2x.png
share/hedgewars/Data/Graphics/Missions/Training/Target_Practice_-_Cluster_Bomb@2x.png
share/hedgewars/Data/Graphics/Missions/Training/Target_Practice_-_Grenade_easy@2x.png
share/hedgewars/Data/Graphics/Missions/Training/Target_Practice_-_Grenade_hard@2x.png
share/hedgewars/Data/Graphics/Missions/Training/Target_Practice_-_Homing_Bee@2x.png
share/hedgewars/Data/Graphics/Missions/Training/Target_Practice_-_Shotgun@2x.png
share/hedgewars/Data/Graphics/Missions/Training/User_Mission_-_Bamboo_Thicket.png
share/hedgewars/Data/Graphics/Missions/Training/User_Mission_-_Bamboo_Thicket@2x.png
share/hedgewars/Data/Graphics/Missions/Training/User_Mission_-_Dangerous_Ducklings.png
share/hedgewars/Data/Graphics/Missions/Training/User_Mission_-_Dangerous_Ducklings@2x.png
share/hedgewars/Data/Graphics/Missions/Training/User_Mission_-_Diver.png
share/hedgewars/Data/Graphics/Missions/Training/User_Mission_-_Diver@2x.png
share/hedgewars/Data/Graphics/Missions/Training/User_Mission_-_Newton_and_the_Hammock.png
share/hedgewars/Data/Graphics/Missions/Training/User_Mission_-_Newton_and_the_Hammock@2x.png
share/hedgewars/Data/Graphics/Missions/Training/User_Mission_-_Nobody_Laugh.png
share/hedgewars/Data/Graphics/Missions/Training/User_Mission_-_Nobody_Laugh@2x.png
share/hedgewars/Data/Graphics/Missions/Training/User_Mission_-_RCPlane_Challenge.png
share/hedgewars/Data/Graphics/Missions/Training/User_Mission_-_RCPlane_Challenge@2x.png
share/hedgewars/Data/Graphics/Missions/Training/User_Mission_-_Rope_Knock_Challenge.png
share/hedgewars/Data/Graphics/Missions/Training/User_Mission_-_Rope_Knock_Challenge@2x.png
share/hedgewars/Data/Graphics/Missions/Training/User_Mission_-_Spooky_Tree.png
share/hedgewars/Data/Graphics/Missions/Training/User_Mission_-_Spooky_Tree@2x.png
share/hedgewars/Data/Graphics/Missions/Training/User_Mission_-_Teamwork.png
share/hedgewars/Data/Graphics/Missions/Training/User_Mission_-_Teamwork@2x.png
share/hedgewars/Data/Graphics/Missions/Training/User_Mission_-_That_Sinking_Feeling.png
share/hedgewars/Data/Graphics/Missions/Training/User_Mission_-_That_Sinking_Feeling@2x.png
share/hedgewars/Data/Graphics/Missions/Training/User_Mission_-_The_Great_Escape.png
share/hedgewars/Data/Graphics/Missions/Training/User_Mission_-_The_Great_Escape@2x.png
share/hedgewars/Data/Graphics/Missions/Training/portal@2x.png
share/hedgewars/Data/Locale/CMakeLists.txt
share/hedgewars/Data/Missions/Training/Basic_Training_-_Sniper_Rifle.lua
share/hedgewars/Data/Missions/Training/Challenge_-_Speed_Shoppa_-_Hedgelove.lua
share/hedgewars/Data/Missions/Training/Challenge_-_Speed_Shoppa_-_Ropes.lua
share/hedgewars/Data/Missions/Training/Challenge_-_Speed_Shoppa_-_ShoppaKing.lua
share/hedgewars/Data/Missions/Training/ClimbHome.lua
share/hedgewars/Data/Missions/Training/Target_Practice_-_Bazooka_easy.lua
share/hedgewars/Data/Missions/Training/Target_Practice_-_Bazooka_hard.lua
share/hedgewars/Data/Missions/Training/Target_Practice_-_Cluster_Bomb.lua
share/hedgewars/Data/Missions/Training/Target_Practice_-_Grenade_easy.lua
share/hedgewars/Data/Missions/Training/Target_Practice_-_Grenade_hard.lua
share/hedgewars/Data/Missions/Training/Target_Practice_-_Homing_Bee.lua
share/hedgewars/Data/Missions/Training/Target_Practice_-_Shotgun.lua
share/hedgewars/Data/Missions/Training/User_Mission_-_Bamboo_Thicket.lua
share/hedgewars/Data/Missions/Training/User_Mission_-_Dangerous_Ducklings.lua
share/hedgewars/Data/Missions/Training/User_Mission_-_Diver.lua
share/hedgewars/Data/Missions/Training/User_Mission_-_Newton_and_the_Hammock.lua
share/hedgewars/Data/Missions/Training/User_Mission_-_Nobody_Laugh.lua
share/hedgewars/Data/Missions/Training/User_Mission_-_RCPlane_Challenge.lua
share/hedgewars/Data/Missions/Training/User_Mission_-_Rope_Knock_Challenge.lua
share/hedgewars/Data/Missions/Training/User_Mission_-_Spooky_Tree.lua
share/hedgewars/Data/Missions/Training/User_Mission_-_Teamwork.lua
share/hedgewars/Data/Missions/Training/User_Mission_-_That_Sinking_Feeling.lua
share/hedgewars/Data/Missions/Training/User_Mission_-_The_Great_Escape.lua
share/hedgewars/Data/Missions/Training/portal.lua
share/hedgewars/Data/Names/Cowboy.cfg
share/hedgewars/Data/Names/Glasses.cfg
share/hedgewars/Data/Names/Hat.cfg
share/hedgewars/Data/Names/MegaHogX.cfg
share/hedgewars/Data/Names/NoHat.cfg
share/hedgewars/Data/Names/RobinHood.cfg
share/hedgewars/Data/Names/Santa.cfg
share/hedgewars/Data/Names/Sunglasses.cfg
share/hedgewars/Data/Names/beefeater.cfg
share/hedgewars/Data/Names/brainslug.txt
share/hedgewars/Data/Names/cap_blue.cfg
share/hedgewars/Data/Names/cap_green.cfg
share/hedgewars/Data/Names/cap_red.cfg
share/hedgewars/Data/Names/cap_yellow.cfg
share/hedgewars/Data/Names/cowboy.txt
share/hedgewars/Data/Names/cyborg1.cfg
share/hedgewars/Data/Names/hair_blue.cfg
share/hedgewars/Data/Names/hair_green.cfg
share/hedgewars/Data/Names/hair_grey.cfg
share/hedgewars/Data/Names/hair_orange.cfg
share/hedgewars/Data/Names/hair_pink.cfg
share/hedgewars/Data/Names/hair_purple.cfg
share/hedgewars/Data/Names/hair_red.cfg
share/hedgewars/Data/Names/hair_yellow.cfg
share/hedgewars/Data/Names/indian.txt
share/hedgewars/Data/Names/mv_Venom.cfg
share/hedgewars/Data/Names/ntd_Kirby.cfg
share/hedgewars/Data/Names/royalguard.cfg
share/hedgewars/Data/Names/sf_ryu.cfg
share/hedgewars/Data/Names/ushanka.cfg
share/hedgewars/Data/Names/zoo_Bunny.cfg
share/hedgewars/Data/Themes/Beach/SprayObject4.png
share/hedgewars/Data/Themes/Beach/horizont-lowres.png
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.gitignore	Sun Dec 17 00:09:24 2017 +0100
@@ -0,0 +1,83 @@
+CMakeCache.txt
+CMakeFiles
+moc_*.cxx
+qrc_*.cxx
+*.o
+*.a
+*.qm
+Makefile
+bin
+*.hi
+*.ppu
+*.*~
+*.core
+hedgewars.pro.user
+config.inc
+cmake_install.cmake
+QTfrontend/hwconsts.cpp
+QTfrontend/servermessages.h
+CPackConfig.cmake
+CPackSourceConfig.cmake
+tools/cmake_uninstall.cmake
+install_manifest.txt
+.DS_Store
+*.swp
+*.orig
+*.diff
+vittorio.*
+project_files/HedgewarsMobile/Data/
+project_files/HedgewarsMobile/Build/
+gameServer/dist/
+misc/liblua/Xcode/build/
+misc/libphysfs/Xcode/build/
+misc/libphyslayer/Xcode/build/
+moc_*.cxx_parameters
+relre:^release\/
+*.log
+*.cmd
+*.diff
+*.patch
+*.orig
+*.bak
+*.rej
+project_files/hwc/*.c
+project_files/hwc/*.h
+project_files/Android-build/SDL-android-project/jni/**
+project_files/Android-build/SDL-android-project/obj
+project_files/Android-build/SDL-android-project/libs/armeabi*
+project_files/Android-build/SDL-android-project/bin
+project_files/Android-build/SDL-android-project/gen
+project_files/Android-build/SDL-android-project/local.properties
+project_files/Android-build/SDL-android-project/project.properties
+project_files/Android-build/SDL-android-project/default.properties
+project_files/Android-build/SDL-android-project/proguard.cfg
+project_files/Android-build/SDL-android-project/.*
+project_files/Android-build/out
+project_files/Android-build/Makefile.android
+hedgewars-build-desktop-Qt*
+hedgewars-build-desktop-Qt*
+*.depends
+tools/build_windows_koda.bat
+share/hedgewars/Data/misc/hwengine.desktop
+*.exe
+_CPack_Packages/
+version_info.txt
+*.tar.*
+*.or
+*.res
+Hedgewars.app/*
+tools/CreateMacBundle.cmake
+share/Info.plist
+CTestTestfile.cmake
+arch.c
+*.swp
+*~.nib
+*.pbxuser
+*.perspective
+*.perspectivev3
+*.project.xcworkspace
+*.xcuserdata
+xcuserdata
+*.mode1v3
+*.mode2v3
+Testing/*
--- a/.hgignore	Thu Aug 11 23:05:14 2016 +0300
+++ b/.hgignore	Sun Dec 17 00:09:24 2017 +0100
@@ -1,83 +1,89 @@
-glob:CMakeCache.txt
-glob:CMakeFiles
-glob:moc_*.cxx
-glob:qrc_*.cxx
-glob:*.o
-glob:*.a
-glob:*.qm
-glob:Makefile
-glob:bin
-glob:*.hi
-glob:*.ppu
-glob:*.*~
-glob:*.core
-glob:hedgewars.pro.user
-glob:config.inc
-glob:cmake_install.cmake
-glob:QTfrontend/hwconsts.cpp
-glob:QTfrontend/servermessages.h
-glob:CPackConfig.cmake
-glob:CPackSourceConfig.cmake
-glob:tools/cmake_uninstall.cmake
-glob:install_manifest.txt
-glob:.DS_Store
-glob:*.swp
-glob:*.orig
-glob:vittorio.*
-glob:project_files/HedgewarsMobile/Data/
-glob:project_files/HedgewarsMobile/Build/
-glob:gameServer/dist/
-glob:misc/liblua/Xcode/build/
-glob:misc/libphysfs/Xcode/build/
-glob:misc/libphyslayer/Xcode/build/
-glob:moc_*.cxx_parameters
-relre:^release\/
-glob:*.log
-glob:*.cmd
-glob:*.patch
-glob:*.orig
-glob:*.bak
-glob:*.rej
-glob:project_files/hwc/*.c
-glob:project_files/hwc/*.h
-glob:project_files/Android-build/SDL-android-project/jni/**
-glob:project_files/Android-build/SDL-android-project/obj
-glob:project_files/Android-build/SDL-android-project/libs/armeabi*
-glob:project_files/Android-build/SDL-android-project/bin
-glob:project_files/Android-build/SDL-android-project/gen
-glob:project_files/Android-build/SDL-android-project/local.properties
-glob:project_files/Android-build/SDL-android-project/project.properties
-glob:project_files/Android-build/SDL-android-project/default.properties
-glob:project_files/Android-build/SDL-android-project/proguard.cfg
-glob:project_files/Android-build/SDL-android-project/.*
-glob:project_files/Android-build/out
-glob:project_files/Android-build/Makefile.android
-glob:hedgewars-build-desktop-Qt*
-glob:*.depends
-glob:tools/build_windows_koda.bat
-glob:share/hedgewars/Data/misc/hwengine.desktop
-glob:*.exe
-glob:_CPack_Packages/
-glob:version_info.txt
-glob:*.tar.*
-glob:*.or
-glob:*.res
-glob:build-*
-glob:hedgewars-build-*
-glob:*.pro.user
-glob:Hedgewars.app/*
-glob:tools/CreateMacBundle.cmake
-glob:share/Info.plist
-glob:CTestTestfile.cmake
-glob:arch.c
-glob:*.swp
-glob:*~.nib
-glob:*.pbxuser
-glob:*.perspective
-glob:*.perspectivev3
-glob:*.project.xcworkspace
-glob:*.xcuserdata
-glob:xcuserdata
-glob:*.mode1v3
-glob:*.mode2v3
+syntax: regexp
+^release\/
 
+syntax: glob
+.git
+CMakeCache.txt
+CMakeFiles
+moc_*.cxx
+qrc_*.cxx
+*.o
+*.a
+*.qm
+Makefile
+bin
+*.hi
+*.ppu
+*.*~
+*.core
+hedgewars.pro.user
+config.inc
+cmake_install.cmake
+QTfrontend/hwconsts.cpp
+QTfrontend/servermessages.h
+CPackConfig.cmake
+CPackSourceConfig.cmake
+tools/cmake_uninstall.cmake
+install_manifest.txt
+.DS_Store
+*.swp
+*.orig
+vittorio.*
+project_files/HedgewarsMobile/Data/
+project_files/HedgewarsMobile/Build/
+gameServer/dist/
+misc/liblua/Xcode/build/
+misc/libphysfs/Xcode/build/
+misc/libphyslayer/Xcode/build/
+moc_*.cxx_parameters
+*.log
+*.cmd
+*.patch
+*.orig
+*.bak
+*.rej
+project_files/hwc/*.c
+project_files/hwc/*.h
+project_files/Android-build/SDL-android-project/jni/**
+project_files/Android-build/SDL-android-project/obj
+project_files/Android-build/SDL-android-project/libs/armeabi*
+project_files/Android-build/SDL-android-project/bin
+project_files/Android-build/SDL-android-project/gen
+project_files/Android-build/SDL-android-project/local.properties
+project_files/Android-build/SDL-android-project/project.properties
+project_files/Android-build/SDL-android-project/default.properties
+project_files/Android-build/SDL-android-project/proguard.cfg
+project_files/Android-build/SDL-android-project/.*
+project_files/Android-build/out
+project_files/Android-build/Makefile.android
+hedgewars-build-desktop-Qt*
+hedgewars-build-desktop-Qt*
+*.depends
+tools/build_windows_koda.bat
+share/hedgewars/Data/misc/hwengine.desktop
+*.exe
+_CPack_Packages/
+version_info.txt
+*.tar.*
+*.or
+*.res
+Hedgewars.app/*
+tools/CreateMacBundle.cmake
+share/Info.plist
+CTestTestfile.cmake
+arch.c
+*.swp
+*~.nib
+*.pbxuser
+*.perspective
+*.perspectivev3
+*.project.xcworkspace
+*.xcuserdata
+xcuserdata
+*.mode1v3
+*.mode2v3
+gameServer2/target
+gameServer2/Cargo.lock
+gameServer2/gameServer2.iml
+.idea
+Testing/
--- a/.hgtags	Thu Aug 11 23:05:14 2016 +0300
+++ b/.hgtags	Sun Dec 17 00:09:24 2017 +0100
@@ -75,3 +75,5 @@
 0000000000000000000000000000000000000000 fab746a3597e
 d9622394ec9c2974a84b9b4d9e6c0ac26c4060ff 0.9.22-RC
 0000000000000000000000000000000000000000 0.9.22-RC
+8cc070640fd1f4affb3c5dd5652b4d75a075c200 0.9.23-alpha
+8610462e3d336e112bffcd7c1530d271242216f1 0.9.23-release
--- a/.travis.yml	Thu Aug 11 23:05:14 2016 +0300
+++ b/.travis.yml	Sun Dec 17 00:09:24 2017 +0100
@@ -1,3 +1,5 @@
+sudo: required
+dist: trusty
 language: c
 sudo: true
 os:
@@ -12,6 +14,11 @@
   - gcc
   - clang
 
+matrix:
+  exclude:
+    - os: osx
+      compiler: gcc
+
 env:
   - BUILD_ARGS="-DCMAKE_BUILD_TYPE=Release"
   - BUILD_ARGS="-DCMAKE_BUILD_TYPE=Debug"
@@ -59,9 +66,12 @@
 
 install: |
   if [ "$TRAVIS_OS_NAME" == "linux" ]; then
-    sudo apt-get install debhelper cmake dpkg-dev libqt4-dev qt4-qmake libphysfs-dev libsdl2-dev libsdl2-ttf-dev libsdl2-mixer-dev libsdl2-image-dev libsdl2-net-dev bzip2 ghc libghc-mtl-dev libghc-parsec3-dev libghc-vector-dev libghc-zlib-dev libghc-random-dev libghc-stm-dev libghc-network-dev libghc-dataenc-dev libghc-hslogger-dev libghc-utf8-string-dev libghc-sha-dev libghc-entropy-dev liblua5.1-0-dev imagemagick fpc fp-compiler fp-units-misc libpng-dev fp-units-gfx libavcodec-dev libavformat-dev libglew1.6-dev
+    sudo apt-get install -y debhelper cmake dpkg-dev libqt4-dev qt4-qmake libphysfs-dev libsdl2-dev libsdl2-ttf-dev libsdl2-mixer-dev libsdl2-image-dev libsdl2-net-dev bzip2 ghc libghc-mtl-dev libghc-parsec3-dev libghc-vector-dev libghc-zlib-dev libghc-random-dev libghc-stm-dev libghc-network-dev libghc-sandi-dev libghc-hslogger-dev libghc-utf8-string-dev libghc-sha-dev libghc-entropy-dev libghc-regex-tdfa-dev liblua5.1-0-dev imagemagick fpc fp-compiler fp-units-misc libpng-dev fp-units-gfx libavcodec-dev libavformat-dev libglew1.6-dev
   elif [ "$TRAVIS_OS_NAME" == "osx" ]; then
-    brew install fpc glew qt physfs lua51 sdl2 sdl2_image sdl2_net sdl2_ttf ffmpeg ghc cabal-install
+    brew tap cartr/qt4
+    brew tap-pin cartr/qt4
+    brew install qt@4
+    brew install fpc glew physfs lua51 sdl2 sdl2_image sdl2_net sdl2_ttf ffmpeg ghc cabal-install
     brew install sdl2_mixer --with-libvorbis
     # use cabal install haskell deps, pas2c ones are covered by server
     if [[ "$BUILD_ARGS" != *"NOSERVER"* ]]; then
@@ -76,8 +86,8 @@
     export BUILD_ARGS="$BUILD_ARGS -DNOAUTOUPDATE=1"
   elif [ "$TRAVIS_OS_NAME" == "ios" ]; then
     # FPC 3.0.0 required for using FPC 3.0.1 which contains rtl for ios
-    sudo bash tools/dmg_pkg_install.sh ftp://freepascal.stack.nl/pub/fpc/dist/3.0.0/i386-macosx/fpc-3.0.0.intel-macosx.dmg
-    sudo bash tools/dmg_pkg_install.sh ftp://freepascal.stack.nl/pub/fpc/dist/3.0.0/i386-macosx/fpc-3.0.1.intel-macosx.cross.ios.dmg
+    sudo bash tools/dmg_pkg_install.sh ftp://freepascal.stack.nl/pub/mirrors/fpc/dist/3.0.0/i386-macosx/fpc-3.0.0.intel-macosx.dmg
+    sudo bash tools/dmg_pkg_install.sh ftp://freepascal.stack.nl/pub/mirrors/fpc/dist/3.0.0/i386-macosx/fpc-3.0.1.intel-macosx.cross.ios.dmg
   fi
 
 before_script: |
--- a/CMakeLists.txt	Thu Aug 11 23:05:14 2016 +0300
+++ b/CMakeLists.txt	Sun Dec 17 00:09:24 2017 +0100
@@ -1,5 +1,6 @@
 project(hedgewars)
 
+
 #initialise cmake environment
 cmake_minimum_required(VERSION 2.6.4)
 foreach(hwpolicy CMP0003 CMP0012 CMP0017 CMP0018)
@@ -79,8 +80,8 @@
 #versioning
 set(CPACK_PACKAGE_VERSION_MAJOR 0)
 set(CPACK_PACKAGE_VERSION_MINOR 9)
-set(CPACK_PACKAGE_VERSION_PATCH 23)
-set(HEDGEWARS_PROTO_VER 52)
+set(CPACK_PACKAGE_VERSION_PATCH 24)
+set(HEDGEWARS_PROTO_VER 54)
 set(HEDGEWARS_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
 include(${CMAKE_MODULE_PATH}/revinfo.cmake)
 
--- a/CREDITS	Thu Aug 11 23:05:14 2016 +0300
+++ b/CREDITS	Sun Dec 17 00:09:24 2017 +0100
@@ -1,36 +1,63 @@
-EXTENDED CREDITS LIST
+=============================
+=== EXTENDED CREDITS LIST ===
+=============================
+
+IF NOT OTHERWISE SPECIFIED, ALL OTHER CONTENT IS PROPERTY OF Andrey Korotaev <unC0Rr@gmail.com>.
+IF NO LICENSE IS SPECIFIED, THE LICENSE IS THE SAME AS MENTIONED IN README.md.
+
+Note: The asterisk is a placeholder which stands for any sequence of characters.
 
 ==========
 = FONTS
 ==========
 - see Fonts_LICENSE.txt
 
+=================
+= FRONTEND IMAGES
+=================
+(File name suffixes are omitted)
+
+- Tango Project and Wuzzy -> audio, home (CC0)
+- abustany and Wuzzy -> Videos (CC0)
+- Juliane Krug and Wuzzy -> Palette (CC0)
+- raseone and Wuzzy -> folder (CC0)
+
 ==========
 = FORTS
 ==========
 - Carlos Vives -> Tank (2010)
 - Dragonfly -> EvilChicken (2010)
 - Randy Broda -> SteelTower (2013)
+- Jon Dum and Wuzzy -> Snail (2017)
+- Maciej Mroziński (a.k.a. alzen) and Wuzzy -> Lonely_Island (2017)
+- Guillaume Englert and Wuzzy -> Olympic (2017)
 
 ==========
 = HATS
 ==========
-- Robinator -> Terminator (2010)
-- shingo666 -> Samus (2010)
+- Robinator -> Terminator_Glasses (2010)
+- shingo666 -> ntd_Samus (2010)
 - MeinCookie95 -> InfernalHorns (2010), Mummy (2010), war_* (2010-2011)
 - thuban -> Elvis (2010)
 - Miphica -> Disguise (2010)
-- Blayde -> Deer (2010), Moose (2010)
+- Blayde -> zoo_Deer (2010), zoo_Moose (2010)
 - hillis -> AkuAku (2010)
-- Lortinak -> OldMan (2010), ShortHair (2010)
-- chujoii -> BrainSlug (2010), Dragon (2010), Ladle (2010), Laminaria (2010), Pantsu (2010), Pig (2010), Plunger (2010), SauceBoat (2010), ShaggyYeti (2010), SleepWalker (2010), SunWukong (2010), Teapot (2010), Teacup (2010), Zombi (2010)
-- Randy Broda -> Cyclops (2011), Soldier (2011)
-- Wohlstand -> PoliceGirl [based on policecap and sm_daisy] (2014)
+- Lortinak -> OldMan (2010), ShortHair_* (2010)
+- chujoii -> scif_BrainSlug (2010), scif_BrainSlug2 (2010), Dragon (2010), dish_Ladle (2010), Laminaria (2010), Pantsu (2010), zoo_Pig (2010), Plunger (2010), dish_SauceBoatSilver (2010), ShaggyYeti (2010), Sleepwalker (2010), SunWukong (2010), dish_Teapot (2010), dish_Teacup (2010), Zombi (2010)
+- Randy Broda -> cyclops (2011), TeamSoldier (2011)
+- Zav -> zoo_octopus (2009)
+- Star and Moon -> bishop (2011)
+- Gimo -> leprechaun [based on tophats] (2011)
+- Terrington_Snyde -> pirate_eyepatch (2013), jester (2013)
+- Wohlstand -> policegirl [based on policecap and sm_daisy] (2014)
+- TheMadCharles -> barrelhider (CC BY 3.0) (2015)
 
 ==========
 = GRAVESTONES
 ==========
-- Randy Broda -> Dragonball (2012)
+- Randy Broda -> dragonball (2012)
+- CheezeMonkey -> pi (2011)
+- rosenholz -> Whisky (2013)
 
 ==========
 = MAPS
@@ -49,6 +76,7 @@
 - Jonatan Nilsson <jonatanfan@gmail.com> -> Pirate theme, EarthRise (former City) theme, Oriental theme, Snow theme)
 - yd - http://opengameart.org/users/yd -> "oriented", used as Olympics SD theme
 - Kevin MacLeod - http://incompetech.com/ -> "hitman", used as basis for preliminary default SD theme
+- Valentin Kraevskiy (alias alfadur) -> Jungle theme, Fruit theme
 
 ==========
 = THEMES
@@ -66,6 +94,12 @@
 - Stephen Alexander <ArmagonNo1@gmail.com>
 
 ==========
+= MISSIONS
+==========
+- Arkhnen -> Teamwork 2 (2012)
+- Wuzzy -> Big Armory (2016)
+
+==========
 = SOUNDS
 ==========
 - Mine impact sound from http://www.freesound.org/people/adcbicycle/sounds/13947/
@@ -77,9 +111,28 @@
      http://www.freesound.org/people/Jovica/sounds/38317/
 - Cleaver impact sound remixed from
      http://www.freesound.org/people/sethlind/sounds/265021/
-- Extra Time sound originally by uair01 (CC-BY), remixed from
+- Extra Time sound originally by uair01 (CC-BY 3.0), remixed from
      http://www.freesound.org/people/uair01/sounds/65291/
-- Air mine impact sound by Wuzzy (WTFPL), based on
+- Air mine impact sound by Wuzzy (CC-0), based on
      http://www.freesound.org/people/batchku/sounds/10479/
+- Rubber duck sounds are in the Public Domain.
+- Countdown sounds by Wuzzy (CC-0)
+- Laser Sight sound originally from drzhn (CC-0), remixed from
+     https://www.freesound.org/people/drzhnn/sounds/199938/
+- Flying Saucer boost sound originally by Jagadamba (CC-BY 3.0), remixed from
+     https://www.freesound.org/people/Jagadamba/sounds/257057/
+- Blowtorch sound originally by rombard (CC-0), remixed from
+     https://www.freesound.org/people/rombart/sounds/197800/
+- Portable Portal Device color switching sound by Wuzzy (CC-0)
+- Portable Portal Device shot sound originally by bubaproducer (CC-BY 3.0), remixed from
+     https://www.freesound.org/people/bubaproducer/sounds/151026/ 
+- Portal opening sound by Wuzzy (CC-0)
+- Invulnerable sound: remix based on a sound by pepingrillin (CC-0)
+     https://www.freesound.org/people/pepingrillin/sounds/252079/
 
-ALL OTHER CONTENT IS PROPERTY OF Andrey Korotaev <unC0Rr@gmail.com> UNLESS OTHERWISE SPECIFIED
+======================
+= LICENSE REFERENCES =
+======================
+
+- CC-BY 3.0: https://creativecommons.org/licenses/by/3.0/
+- CC-0: https://creativecommons.org/publicdomain/zero/1.0/
--- a/ChangeLog.txt	Thu Aug 11 23:05:14 2016 +0300
+++ b/ChangeLog.txt	Sun Dec 17 00:09:24 2017 +0100
@@ -1,61 +1,403 @@
 + features
 * bugfixes
 
-0.9.22 -> 0.9.23
+====================== 0.9.23 ======================
+HIGHLIGHTS:
+ + Battalion style
+ + Fort mode is now a map type instead of a scheme setting
+ + Fort mode now works with more than 2 teams
+ + New weapon: rubber duck
+ + New theme, map, 3 forts, 3 missions, some hats and graves
+ + WxW style allows you to select one of many wall sets
+ + Complete HedgeEditor overhaul
+ + Greatly improved script parameter support for many styles
+ + Improves stats screen of most styles and missions
+ + Various improvements for almost all styles
+ + AI hedgehogs can now use Bee, Vamprism, and Time Box
+ + Campaign page now shows your progress
+ + Improved turn timer
+ + Improved randomization options in team and multiplayer pages
+ + Improved theme customization support
+ + Various Lua API additions
+ * Fix cursor often jumping around after clicking
+ * A huge amount of bugfixes for both campaigns, the missions and styles
+ * Video recording functionality is restored
+
 Content:
- + New hat: "tf_scout" (this time for real)
+ + New game-style/mode: Battalion (see https://hedgewars.org/wiki/Battalion )
+ + New theme: Beach
+ + New theme music for Jungle and Fruit themes
+ + Change SD theme music for Halloween and Hoggywood (old tracks)
+ + Completely new Cheese map; replaces the old one
+ + New forts: Lonely_Island, Octopus, Olympic, Snail
+ + Many new random hedgehog and team names
+ + Add hats: barrelhider, bishop, jester, leprechaun, pirate_eyepatch, tf_scout, zoo_octopus
+ + Add hair-less variants of old hats: beefeaterhat, lambdahat, nursehat, pirate_bandana, pirate_hat, poke_ash_hat, RamboClean, sf_vega_hat, sf_guile_hat, simple_red, simple_yellow, simple_green, thugclean
+ * Remove hat: tf_scount (this was a duplicate of tf_demoman)
+ * Add graves: Clover, Old_Apple, pi, Simple_reversed, TV, Whisky, Ying_and_Yang
+ * Redo flags: cm_pentagram, cm_soviet, armenia, ireland, nepal, suisse, sweden, turkey
 
-Game engine:
+Game engine (weapons):
+ + New weapon: rubber duck
+ + Freezer can now freeze sticky mines (they get disabled and fall into the water)
+ + Keep rope / parachute / flying saucer selected when destroyed and secondary ammo selected
+ * Gameplay fix: Hammer damage is now rounded down. This means it will cause NO DAMAGE to a hedgehog with less than 3 hp.
+ * Fixed air strikes drops being off-center
+ * Fixed hedgehogs getting hurt while firing deagle / sniper rifle bullet in certain situations
+ * Fixed mine, sticky mine, seduction, resurrector not working correctly across wrap world edge
+ * Fixed teleportation being able to teleport in land if you clicked across the wrap or bounce world edge
+ * Fixed turn not ending when sticky mine was trapped on rubberband
+ * Rope is now destroyed when attempting to shoot it through wrap or bouncy world edge
+ * Fixed possible to move rope angle below 0° while having secondary weapon selected
+ * Fixed molotov cocktails bouncing vertically off rubber
+ * Fixed sniper rifle disabling laser sight utility after using
+ * Fixed RC planes being able to collect frozen crates
+ * Fixed cake taking over 200 seconds to explode when its stuck and can't move
+ * Fixed Birdy descending into water when hog took damage or died before it got picked up
+ * Fixed player being able to switch to dying hog
+ * Various other fixes
+
+Game engine (gameplay):
+ + Fort Mode will now work with more than 2 teams
+ + Divided Teams mode will now work with more than 2 teams (Hint: you probably want to set world edges to "wrap" in such games)
+ + Frozen hedgehogs can no longer be poisoned
+ + AI hedgehogs can now use Bee, Vampirism and Time Box
  + Improved hedgehog spawns on maps that lack land mass or free space
- + Highlander mode displays game scheme specifics (mines timer, etc.) in ESC info
- + AI hedgehogs can now use Bee and Vampirism
- + Divided Teams mode will now work with more than 2 teams (Hint: you probably want to set world edges to "wrap" in such games)
- + Fort Mode will now work with more than 2 teams
- + Added "Forts" to map type selection. This makes the mode easier selectable/discoverable. Also the slider can be used to adjust the distance between forts.
- + Render graves behind everything else, so that they can't hide mines etc.
+ + Hogs no longer spawn on icy terrain
+ + Temporarily suspend Heavy Wind mode while turn timer is not running
+ + Engine supports now really gigantic maps
+ * Fixed cursor often jumping back to screen center when putting target location while moving cursor
+ * Fixed team getting infinite ammo when stockpiling >= 100 ammo (max. finite ammo is now limited to 99)
+ * Fixed failure to collect crate across wrap world edge
+ * Remove buggy “/finish” chat command
+ * Fix key controls not working in ammo menu: ammo menu, placement, camera/cursor movement keys
+ * Various other fixes
+
+Game engine (graphics, sounds and texts):
+ + Show indicator symbols at bottom right while extra damage or low gravity are active
+ + Color coding for the turn timer: green = ready timer, yellow = turn in progress, red = retreat timer, gray = timer paused
+ + Play countdown sounds at 1-4 seconds turn time
  + Several new sound effects for weapons and utilities
- + Small visual effects enhancements
- + Briefly show theme and music authors in chat at start of game
- * Fixed air-strikes drops being off-center
- * Gameplay fix: Hammer damage is now rounded down. This means it will cause NO DAMAGE to a hedgehog with less than 3 hp.
- * Fixed screenshots being too bright if taken in quick succession
+ + More ticker messages: Hog gets sick, king died, hog was resurrected, hog time travels (and returns), timeout, kamikaze
+ + Small visual effects enhancements: Baseball bat, dynamite and more
+ + Render graves behind everything else, so that they can't hide mines etc.
  * Video recording functionality is restored
- * Fixed bee not being affected by wrap world edge while still being thrown
- * Fixed turn not ending when sticky mine was trapped on rubberband
- * Fixed hedgehog-voices missing a response type (Justyouwait/"You're gonna pay for that") on some platforms (e.g. Linux)
- * Fixed SD-flakes of themes not working if regular flakes were disabled
- * Fixed RC planes being able to collect frozen crates
+ * Fixed screenshots being too bright if taken in quick succession
+ * Fixed hedgehog voices missing a response type (Justyouwait/"You're gonna pay for that") on some platforms (e.g. GNU/Linux)
+ * Fixed SD flakes of themes not working if regular flakes were disabled
  * Fixed Seduction's "Yoohoo!" sound not playing
- * Fixed Hedgehogs getting hurt while firing deagle / sniper rifle bullet in certains situations
- * Various other fixes
+ * Fixed hedgehogs saying “Missed” when drowning enemy without dealing damage
+ * Fixed enemy saying "Missed” when giving poison without direct damage
+ * Fixed hedgehogs not saying “Stupid” and not displaying announcer message for inflicting self-harm
+ * Fixed incorrect time box tooltip when in Sudden Death
+ * Fixed short sound effect breakdown right after using a time box
+ * Fixed sticky mine sound sometimes playing when shooting portable portal device when a sticky mine is placed on terrain
+ * Fixed hedgehog holding nothing in hand when napalm or piano strike got selected
+ * Fixed excessive water splashes sometimes caused by mines
+
+Highlander:
+ + Show collected weapons after kill and play sound
+ + Mission panel now shows all game modifiers (e.g. mines time, vampirism, etc.)
+ + Loyal Highlander (optional): With “loyal=true” in script param, you only get weapons for enemy kills (clan kills don't count)
+ * Removed "Freezer"/IceGun from the default Highlander weaponset
 
 Construction Mode:
  + Added script parameter support:
   + initialenergy: Amount of energy at start
   + energyperround: New energy per round
-  + maxenergy: Maximum allowed
+  + maxenergy: Maximum allowed energy
+  + cratesperround: Maximum placable crates per round
+ + Completely reworked all in-game texts and descriptions
+ * Fix rubber being placable inside land
+ * Fix invalid girder placement costing energy
+ * Special tools like structure placer now have their own proper descriptions (instead of Air Attack description, etc.)
  * Costs for weapon and utility crates were all equal
+ * Remove airplane cursor
+ * Fix Lua errors when hog goes to time travel while any filter is in map
  * Many other fixes and tweaks
 
-Missions and Game Styles:
- + Added Basic Flying Saucer Training
+Racer and TechRacer:
+ + Allow to only place 2 waypoints in Racer
+ + Allow to remove Racer waypoints with precise key
+ + New script parameters for Racer:
+  + rounds: Number of rounds to play
+  + waypointradius: Size of waypoints
+  + maxwaypoints: Maximum allowed number of waypoints
+ + Show correct ranking and times in stats screen of Racer and TechRacer
+ * Fix description and icon of waypoint placement tool in Racer
+ * Remove airplane cursor in Racer
+ * Fixed waypoint message in TechRacer and Racer overwriting current weapon selection message
+ * Fixed TechRacer not recording finish if time was >= 100s
+
+WxW:
+ + Support for multiple sets of walls per map
+ + Add optional “Crate Before Attack” rule
+ + Add optional “All But Last” rule
+ + Add optional “Kill The Leader” rule
+ + Script parameter support (see Lua file comment for documentation)
+ + Possible to set max. number of weapons in game (script parameter only)
+ + Menu can be disabled (with script parameter “menu=false”) for insant game start
+ + Possible to set number of crates per turn
+ + Ropes, ShoppaKing, ShoppaHell and ShoppaNeon can now be played with the classic left and right walls
+ + Allows almost all game modifiers to be changed, the only exception is crate probabilities
+ + New wall sets for Ropes, ShoppaNeon, ShoppaDesert, ShoppaWild, ShoppaKing and ShoppaHell.
+ + Basic support for a bunch of Shoppa maps
+ + Fully functional even without a map border
+ + More sound effects
+ + More helpful mission display after configuration has been accepted
+ + Hide “Surf Before Crate” setting if surfing is disabled for this map, or the bottom is active and water never rises
+ + Hide walls setting if script does not provide walls for map yet
+ + Freeze crates at turn start if Walls Before Crate or Surf Before Crate is enabled (they unfreeze if you met requirements)
+ + Allow toggling the radar with Switch Hog key while roping or rope selected
+ * No smoke when hog is near near a WxW wall but walls need not to be touched
+ * Fix other player being able to change the menu config in the short period before the first turn
+
+Tumbler:
+ + Script parameter support:
+  + spawnbarrels: New barrels per turn
+  + spawnmines: New mines per turn
+  + ammoflamer: Initial Flamer fuel
+  + ammobarrel: Initial Barrel Launcher ammo
+  + ammomine: Initial Mine Deployer ammo
+  + minetimerplaced: Mine timer (ms) of mines dropped from Mine Deployer
+  + bonustime: Bonus time (s) in utility crates
+  + bonusflames: Bonus Flamer fuel in ammo crates
+  + chanceammo: Per-turn % chance of an ammo crate drop
+  + chancetime: Per-turn % chance of an utility crate (extra time) drop
+ + Alternative weapon selection with slot keys (F1, F2, F3)
+ + Add mine/barrel launch sounds
+ + Add countdown sounds
+ + Rewrote mission description and captions
+ + Sound and message when trying to fire empty weapon
+ * Permanently disable some game modifiers which won't work together with this
+
+Space Invasion:
+ + Show actual scores in stats screen, and a proper graph
+ + Show a couple of “awards” (snarky comments) in stats screen
+ + Remove bonuses “Boom!”, “BOOM!” and “BOOM!! BOOM!! BOOM!!” for balancing reasons
+ + Script parameter support:
+  + rounds: Number of rounds
+  + shield: Initial shield
+  + barrels: Initial barrel ammo
+  + pings: Available radar pings
+  + timebonus: Time bonus for red drones
+  + barrelbonus: Ammo bonus for green invaders
+  + shieldbonus: Shield bonus for purple invaders
+  + forcetheme: Set to “true” to use the selected theme instead of EarthRise
+ + Complete rewrite of almost all messages and the mission panel
+ + More event messages
+ + Show current score in HUD (white number)
+ + Stop overwriting most game scheme’s parameters
+ + Disable weapon scheme
+ + More sounds: Empty ammo, countdown, throw, kamikaze, radar ping, explosion
+ * Fix explosion being drawn twice when colliding with invader
+
+HedgeEditor:
+ + Dud mine placement mode
+ + Allow to select frames in sprite placement mode
+ + New placable sprite: sprTargetBee
+ + Complete rewrite of all help texts
+ + Allow to add and subtract health
+ + Add more convenient start values (e.g. for health)
+ + Allow to set timer of sticky mines
+ + Health crates can now have 0 health
+ + Hog and team names (from identity modes) are now translatable
+ + Show health/timer above health crates, barrels, mines, sticky mines and air mines
+ + Allow to toggle health/timer display with Precise+3
+ + Allow to toggle main help at any time with Precise+1
+ * Add proper description and name for the gear placement tool (no more fake air attack)
+ * Fix many issues with exported files
+ * Fix placement mode being changable when gear placement tool is not selected
+ * Make land gun spawn in utility crates instead of weapon crates
+ * Stop aggressively showing the mission panel after any button press
+ * Fix placement modes sometimes showing “nil” in caption
+ * Fix girder sprite being displayed at top left for no reason
+ * Ammo names are not hardcoded anymore (no more double work for translators)
+ * Fix many missing or poor-quality texts for translation
+ * Fix error when trying to set ShoppaBalance rank without anything selected
+ * Don't show misleading circle when placing girder/rubber
+ * Disable timer keys 2-4 in rubber placement mode
+ * Fix incorrect weapon crate preview of air attack, drill strike and napalm
+
+Other styles and schemes:
+ + The Specialists: Saints get low gravity
+ + Capture The Flag: Setting number of captures with script parameter “captures=<number>”
+ + Mutant: Show appropriate ranking and graph in stats screen
+ + Shoppa: Don't place air mines
+ * Capture the Flag: Fix flag of first team spawning at second hog instead of first
+ * Gravity: Using the low gravity *utility* had no effect. Now it halves the base gravity of the style
+ * Disable Sudden Death for good in Shoppa game scheme, some game styles and mission maps
+
+A Classic Fairytale:
+ + Mission 4: Add infinite skip
+ + Mission 5: Spare traitor's life with Skip instead of Precise
+ + Mission 6: Add alternate dialogues when killing cyborgs before collecting the crates
+ + Mission 6: Give hero only a portal gun at the final portal seqment, remove the large amount of crate drops
+ + All missions: Clarify mine timers
+ * Mission 1: Leap of faith: Hog was able to walk to the right and get stuck
+ * Mission 1: Leap of faith: Teleport player back to mole when failing
+ * Mission 2: Fix crash when trying to open ammo menu in opening sequence
+ * Mission 2: Fix game sometimes getting stuck after walking back to Leaks A Lot
+ * Mission 2: Fix breakages when heroes died before a new sequence, or together with enemies
+ * Mission 2: Remove restart option when cooperating with cyborg; it messed up things too much
+ * Mission 3: Fix various Lua errors when playing with 2 hogs and one of them dies
+ * Mission 3: Fix broken end sequence after killing cyborg or princess
+ * Mission 3: Fix broken sequence of princess being caged
+ * Mission 3: All girder crates now have 3 girders each
+ * Mission 5: Fix crash when skipping animation while the cyborg talks before the 3rd wave of cannibals starts
+ * Mission 5: Make sure the player can only play with one hog after the cyborg imprisoned the other natives
+ * Mission 5: Fix final animation being stuck if cyborg's way to the left is blocked
+ * Mission 6: Block off left cave entrance to stop player to just rope all the way around
+ * Mission 6: Fix mines not being able to get triggered in first turn
+ * Mission 8: Fix Lua error message at the very beginning and error spam in intro sequence
+ * Mission 10: Fix mission becoming unplayable when all hogs except the traitor died
+ * All missions: Add missing texts for translation
+ * All missions: Fix incorrect crate types
+ * All missions: Rewrite mission texts to state missions more clearly
+ * Fix swapped mission preview images of missions 2 and 3
+
+A Space Adventure:
+ + Side missions save and show your personal best successes (e.g. fastest finish in Hard Flying)
+ + Spacetrip: Show 2 flowers over fully completed planets (with side missions)
+ + All missions: Add skip where it doesn't hurt
+ + All missions: Clarify mine timers
+ + All missions: Improve displaying behaviour of mission panel
+ + All missions: Change team colors
+ + Side missions: Remove or shorten intro sequences
+ + Side missions: Generous ready time to give more time to read the mission panel
+ + Getting to the device: Put device part in a real crate, improve some dialogues
+ + Final mission: Add outro sequence instead of instantly quitting
+ + Bad timing: Improve messaging and choice dialog
+ * Spacetrip: Fix various bugs and logic flaws in the initial mission
+ * A frozen adventure: Fix bazooka and excess freezers (>6) not retained over checkpoints
+ * A frozen adventure: Fix and improve poorly written messages
+ * Getting to the device: Add real crate and correct message for collecting device part
+ * Getting to the device: Remove checkpoints. There was a good chance for these missions to become unwinnable
+ * Searching in the dust: Remove checkpoints. See above.
+ * Searching in the dust: Fix Hog Solo dropping straight down when roping near smuggler
+ * Searching in the dust: Fix incorrect messages after collecting device part
+ * Precise flying: Fix victory not being recognized, also wait for flames to settle before losing
+ * Hard Flying: Fix ending in a Lua error
+ * The First Stop: Fix stats screen showing teams twice
+ * Fruit planet: Fix “Precise shooting” disappearing directly after completing “Bad timing”
+ * Fruit planet: Fix “Getting to the device” not visible when landing on fruit planet with first main mission completed only
+ * Killing The Specialists: Fix killing hog with Deagle gave you chance to use another weapon in same turn
+ * Fix weird behaviour when walking right before the first animation in most missions
+ * Fix a couple of texts being untranslatable
+ * Fix a variety of minor logic flaws in the story
+ * Fix typos
+ * All missions: Fix incorrect crate types
+
+Missions:
+ + New scenario: Teamwork 2
+ + New scenario: Big Armory
+ + New training: Basic Flying Saucer Training
  + Rope-Knocking Challenge was improved (now awards score based on kills and time; taunts for knocking out hedgehogs)
+ + Rewrote some help texts in basic rope training
+ + Graphical effect (black bars) while in cut scenes
+ + Change description and icon for baseball bat in Knockball mission map
+ + Sniper rifle target practice: Dynamite blows up quicker, can also skip with precise key
+ * Fixed mistakes and bad wording of strings in several missions, scripts and campaigns
+ * TrophyRace: Fix hedgehogs not being eliminated anymore after one hog skipped or ran out of time
  * Portal Mind Challenge was cleaned up and reworked (especially less awful wording)
- * Fixed TechRacer not recording finish if time was >= 100s
  * Fixed Target Practice missions getting stuck when a target dropped into water
- * Fixed mistakes and bad wording of strings in several missions, scripts and campaigns
+ * Climb Home: Fix game getting stuck when a player reached home in multiplayer
+ * Climb Home: Fix Lua error messages and broken stats screen
+ * Sniper rifle target practice: Fix targets spawning twice in dynamite scenes
+ * Sniper rifle target practice: Fix auto-camera generally behaving weird
 
 Frontend:
- + Menu screens got few new icons and other tweaks, e.g. larger dropdown lists for easier access
- + Clicking on "New" in weapon scheme editor now creates empty weapon scheme instead of default
+ + Campaign screen shows which campaigns and missions you've completed so far
+ + Training screen now has 3 mission categories: Training (tutorials), Challenge (get a high score), Scenario (complete a task)
+ + Replaced the Fort Mode game modifier by adding "Forts" to the map type selection. This makes the mode easier selectable/discoverable. Also the slider can be used to adjust the distance between forts.
+ + Menu screens got few new icons and many other tweaks, e.g. larger dropdown lists for easier access
+ + Additional button for just randomizing theme that will not change your selected map
+ + Randomizing map/theme in online mode will not include DLC content
+ + New teams start with a random grave and fort
+ + Hedgewars creates 4 human teams and 2 computer teams on its first launch
+ + Allow to randomize hog names, hats, team name, flag, grave, voice and fort separately
+ + “Random team” button is now able to randomly select from all available hats
+ + Creating new game/weapon schemes guarantees unique names
+ + Custom maps and styles are now marked with an icon instead of an asterisk
+ + Mark custom forts in team editor
+ + Room host can delegate room control to other player by rightclick
+ + Switch from HTTP to HTTPS where possible
+ * Fix flag being selectable for computer players although it had no effect
+ * Campaign screen does no longer show AI-controlled teams
+ * Campaign names and campaign mission names can now be translated
+ * Creating randomized teams now randomizes (almost) every aspect
+ * Fixed mostly broken descriptions for multiplayer mission maps
+ * Clicking on "New" in weapon scheme editor now creates empty weapon scheme instead of default
+ * Fix language names in language list being always in English
+ * Prevent starting game with >48 hogs (because engine doesn't support it yet)
+ * Fix the key for toggling team bars being incorrectly described
+ * Fix caption of stats screen showing only one winner if multiple teams have won
+ * Remove broken “Play again” button appearing in stats page after an online game
+ * Weapons scheme editor: When leaving, it no longer flickers and the selection is not reset to Default
+ * Team editor: Fix old team being retained when renaming a team
+ * Team editor: Automatically rename team when leaving team editor page with an already used team name
+ * Fix broken cancel button in the login window
+
+Content Creation:
+ + Theme objects can now have more than 1 in-land rect specified. You can specify the amount in theme.cfg by adding another number (and a comma) before the first rect
+ + Theme objects can now be placed on water (by setting first in-land rectangle to 0,0,0,0)
+ + Themes can now use flakes with negative falling speed (rising flakes)
+ + Themes can now contain custom sound files: splash.ogg Droplet1.ogg Droplet2.ogg Droplet3.ogg skip.ogg
+ + Themes can now have mirrored clouds and flakes: CloudsL.png, SDCloudsL.png, FlakeL.png, SDFlakeL.png
+ + Water in themes supports custom animation and flow speed with water-animation and sd-water-animation in theme.cfg
+ + Simplified hat format for unanimated hats; a single 32×32 image is enough. For clan hats, use size 64×32, with the color overlay at the right
+ + Ammos.png and Ammos_bw.png in HWPs are now overlayed over the base images; use transparent icons to keep them unchanged from the original
+ + Custom Sudden Death background tint for themes with sd-tint
+ * Default water color was black instead of blue
 
-Lua-API:
+Translations:
+ + Complete translations: German, Polish
+ + Major translation updates: Scottish Gaelic, Italian
+ + Loading screen can now be translated
+ + A few window titles can be translated
+ + Campaign names and campaign mission names can be translated
+ + A Classic Fairytale, missions 8 and 10 can now be translated
+ * Built-in texts from Qt (e.g. “cut”, “paste”, “copy”) in frontend weren't translated
+ * Remove text from mission images to make them language-neutral
+ * Fix English-only language/country names in language selection
+ * Fix very, very broken mission map descriptions
+
+Lua API:
  + New call: SetCinematicMode(enable) -- e.g. for cutscenes etc.
+ + New call: GetAmmoName(ammoType [, ignoreOverwrite]) -- returns the localized name for the specified ammoType
+ + New call: GetVisualGearType(vgUid) -- returns the visual gear type
+ + New call: SetAmmoTexts(ammoType, name, caption, description) -- Overwrite displayed name and description of an ammo type
+ + New call: SetAmmoDescriptionAppendix(ammoType, descAppend) -- Append a custom text to the description of an ammo type without overwriting it
+ + New call: GetHogFort(gearUid) -- Returns the name of the fort of the hog's team
+ + New call: PlaceRubber(x, y, frameIdx) -- Places a rubber
+ + New call: SendGameResultOff() -- Disable the game automatically setting a game result in the stats screen
+ + New call: SendRankingStatsOff() -- Disable the game automatically filling the team rankings in the stats screen
+ + New call: SendAchievementsStatsOff() -- Disable the game automatically populating the bullet point list in the “Details” section on the stats screen
+ + New call: GetTeamStats(teamname) -- Returns a table of team stats
+ + New call: EndTurn([noTaunts]) -- Ends the current turn
+ + New hook: onVisualGearAdd(vgUid) -- called when a visual gear is added
+ + New hook: onVisualGearDelete(vgUid) -- called when a visual gear is deleted
+ + New hook: onUsedAmmo(ammoType) -- called when ammo has been finished using (e.g. after both shotgun shots)
+ + New variable: AirMinesNum -- Number of air mines being placed on a medium-sized map
+ + New variable: WorldEdge -- World edge type (weNone, weWrap, weBounce, weSea)
+ + New variable: AmmoTypeMax -- Maximum ammo type ID (useful to iterate through all ammo types, starting by 0)
+ + New variable: ReadyTimeLeft -- Remaining ready time, 0 if turn in progress. Can be set in onNewTurn
+ + Locale library: loc_noop -- Mark string for translation but don't translate it
+ + Animate library: AnimInit([startAnimating]) -- New parameter startAnimating: if true, will start game in cinematic mode with most controls disabled. Must play an animation after that
+ + Animate library: AnimSetInputMask(extraInputMask) -- Set input mask in a manner comptible with the Animate library
+ + Animate library: AnimMove(gear, dir, posx, posy, [maxMoveTime]) -- new optional parameter maxMoveTime. If hog did not reach its destination within maxMoveTime milliseconds, animation stops and hog is just teleported there
+ + Gear values: “Boom” -- used to modify explosion size and/or damage for most gears
+ + 8 overridable custom sprites/sounds: sprCustom1-sprCustom8, sndCustom1-sndCustom8
+ * Fixed call: HideHog(gear) -- Fix crash when gear is invalid. Returns true on success or false otherwise
+ * Fixed call: SwitchHog(gear) -- Fix new hog being unable to open ammo menu
+ * Removed call: SetAmmoStore -- Old undocumented function of questional use, has never been used
+ * Fixed variable: Goals -- Fix Goals text being cut off at ca. 255 characters
+ * Fix huge numbers having sign errors on 64-bit architectures
 
-0.9.21 -> 0.9.22
+====================== 0.9.22 ======================
  + New Weapon / Map object: AirMine (floating mine that will follow nearby hedgehogs)
  + Extensive changes to TechRacer: Variable terrain types, enhanced parameters, hwmap interpreter, fuel limiter, etc. 
- + HedgeEditor - create missions/etc. in-game! see http://hedgewars.org/HedgeEditor
+ + HedgeEditor - create missions/etc. in-game! see https://hedgewars.org/HedgeEditor
  + Map previews can now take script parameters into account and preview waypoints in TechRacer
  + Added a couple new flags
  + Various tweaks to the interface and in-game chat
@@ -84,7 +426,7 @@
  * Previously missing gear states are now available (gstSubmersible, gstFrozen and gstNoGravity)
  * Fixed OnHogAttack giving the incorrect AmmoType (amNothing) under certain conditions
 
-0.9.20 -> 0.9.21:
+====================== 0.9.21 ======================
  + New type of randomly generated maps: Perlin Maps.
  + Old Random generated maps are more diverse now.
  + Slider for adjusting land generation detail.
@@ -148,7 +490,7 @@
  * Fixes:
       gfResetHealth is now a available like the other GameFlags
 
-0.9.19 -> 0.9.20:
+====================== 0.9.20 ======================
  + New campaign, A Space Adventure!
  + Password protected rooms
  + Shapes on drawn maps (ellipses, rectangles)  - constrain dimensions with ctrl, as with straight line tool.
@@ -177,7 +519,7 @@
  * Fixed context menu/cursor in text areas
  * Many bugfixes. Keypad enter in chat, hog sliding freezing game, team name flaws in Windows, localisation of tips, crasher in slots with no weapons, frontend holiday css.
 
-0.9.18 -> 0.9.19:
+====================== 0.9.19 ======================
  + New Freezer weapon - freezes terrain, water, hedgehogs, mines, cases, explosives
  + Saucer can aim weapons and fire underwater
  + Main graphical user interface overhaul
@@ -212,7 +554,7 @@
  * ParseCommand should be safe to use in Lua now, at any time
  * Fixes to many weapons. Mudball, blowtorch, explosives, cluster bomb spread, portal.
 
-0.9.17 -> 0.9.18:
+====================== 0.9.18 ======================
 
  + 'A Classic Fairytale' Campaign
  + Video recorder (requires ffmpeg/libav)
@@ -241,7 +583,7 @@
  * Fix drill strike bug when drill's timer gets ridiculously high value instead of explosion
  * Fix some crashes, freezes and memory leaks in frontend and engine
 
-0.9.16 -> 0.9.17:
+====================== 0.9.17 ======================
  + New theme, Cave
  + New voicepack, Hillbilly
  + More attractive mission screen with previews
@@ -274,7 +616,7 @@
  * Many frontend bugfixes, code cleanup. Crash in game abort, flake clipping, invalid state on room close
  * Many other engine bugfixes.  SDL event crasher, timebox crasher, birdy hang, desync on quits, crash in birdy eggshell, hammer + vamp + invuln, clouds on Deep Space theme, etc
 
-0.9.15 -> 0.9.16:
+====================== 0.9.16 ======================
  + In-game chat now supports backspace-repeat and Escape to close the text input area
  + Team status bars shrunk/made translucent if they take up a significant portion of the screen
  + Background music change on sudden death mode
@@ -338,7 +680,7 @@
  * Fix invisible icons in popup menus
  * Various fixes and adjustments
 
-0.9.14 -> 0.9.15:
+====================== 0.9.15 ======================
  + Ability to create, save and load hand drawn maps
  + New maps: Capture the Flag (Blizzard) Map
  + New themes: Christmas
@@ -365,7 +707,7 @@
  + Variable rope length in scheme
  + Allow hog speech when not your turn
 
-0.9.13 -> 0.9.14:
+====================== 0.9.14 ======================
  + New audio tracks
  + New forts: EvilChicken, Tank
  + New game modes: AI Survival Mode, Per Hedgehog Ammo, Reset Health, Reset Weapons, Unlimited Attacks
@@ -403,7 +745,7 @@
  * Fixed bug that allowed charging a weapon while on rope, leading to frozen timer
  * Various bug fixes
 
-0.9.12 -> 0.9.13:
+====================== 0.9.13 ======================
  + Speed optimizations
  + New weapon: Birdy (carries your hog and lets you throw poisonous eggs at your foes)
  + Hats are visible while using rope and blowtorch
@@ -464,7 +806,7 @@
  + PowerPC architecture supported
  * Reduced memory footprint and leakage
 
-0.9.11 -> 0.9.12:
+====================== 0.9.12 ======================
  + Zoom
  + New weapons: flying saucer, molotov cocktail
  + More sounds
@@ -482,7 +824,7 @@
  * Fix rope bugs
  * Fix bugs in weapon selection code
 
-0.9.10 -> 0.9.11:
+====================== 0.9.11 ======================
  + Speech bubbles
  + Many new hats, new graves
  + New taunts
@@ -502,7 +844,7 @@
  * Fix crash in parachute/rope if drowning with active girder/teleport
  * Fix rope disappearing bug
 
-0.9.9 -> 0.9.10:
+====================== 0.9.10 ======================
  + Many new hats, maps, themes, updates on existing ones
  + Remove small pixels left by fire
  + Double possible land dimensions, allow up to 48 hedgehogs in game
@@ -527,7 +869,7 @@
  * Fix bug with not working toggles 'rectrict joins' and 'restrict team adding'
  + Fix engine slowdown when trying to switch ammo while firing bazooka
 
-0.9.8 -> 0.9.9:
+====================== 0.9.9 ======================
  + Voicepacks
  + Teams health graphic on statistics page
  + Colorize join/quit messages in chat
@@ -542,7 +884,7 @@
  * Fix autogenerated demos/saves filenames problems
  * Fix engine freeze when switching hedgehog in certain conditions
 
-0.9.7 -> 0.9.8:
+====================== 0.9.8 ======================
  + Many net server fixes
  + Lobby on net server
  + Napalm weapon
@@ -558,7 +900,7 @@
  * Fix a bug leading to engine silent crash when using whip, bat or firepunch (and probably flame)
  * Limit chat history to 250 entries to avoid DoS attack with its use
 
-0.9.6 -> 0.9.7:
+====================== 0.9.7 ======================
  + Completely redesign the frontend, no longer looks like an ugly program launcher
  + New art
  + Add fullscreen mode to frontend
@@ -582,7 +924,7 @@
  * Fixed grenade sound
  * AI uses the mortar better
 
-0.9.5 -> 0.9.6:
+====================== 0.9.6 ======================
  + New Cake weapon
  + New maps: EarthRise, Bamboo, Bath, BambooPlinko
  + New theme EarthRise
@@ -593,7 +935,7 @@
  * Fix clouds shaking up
  * Repair screenshots capturing
 
-0.9.4 -> 0.9.5:
+====================== 0.9.5 ======================
  + Taunts
  + Exit confirmation dialog
  + Sudden death
@@ -603,7 +945,7 @@
  + More impressive exposions
  * Fix bad sprite when you jump and get hit
 
-0.9.3 -> 0.9.4:
+====================== 0.9.4 ======================
  + In game chat is now implemented, chat (and taunt!) your buddies during network play
  + Mortar, whip and Kamikaze weapon additions
  + Two new themes, desert island and city
@@ -617,7 +959,7 @@
  + Lots of new graphics
  * Many network/gameplay bug fixes
 
-0.9.2 -> 0.9.3:
+====================== 0.9.3 ======================
  + Switch to OpenGL rendering
  + Massive graphics update
  + New animations, weapon sprites
@@ -633,7 +975,7 @@
  * Fix hedgehog moving direction after been shot by shotgun
  * Fix bug with handling keys while it is enemy's turn
 
-0.9 -> 0.9.2:
+====================== 0.9.2 ======================
 
  + Add registration of net game in web
  + Introduce weapons sets support
--- a/INSTALL	Thu Aug 11 23:05:14 2016 +0300
+++ b/INSTALL	Sun Dec 17 00:09:24 2017 +0100
@@ -1,47 +1,1 @@
-To compile and install you need:
- - CMake >= 2.6.0
- - FreePascal >= 2.2.4
- - Qt >= 4.7.0
- - SDL >= 2.0
- - SDL_net >= 2.0
- - SDL_mixer >= 2.0
- - SDL_image >= 2.0
- - SDL_ttf >= 2.0
- - Lua = 5.1.0
- - Physfs >= 2.0.0
-For server:
- - Glasgow Haskell Compiler >= 6.10
- - dataenc package
- - hslogger package
-For videorecording:
- - FFmpeg or LibAV
-For compressed screenshots:
- - libpng
-
-Lua will be automatically built if not found.
-
-PhysFS will internally built unless -DPHYSFS_SYSTEM=on is passed to cmake
-(also allows to set PHYSFS_LIBRARY and PHYSFS_INCLUDE_DIR if needed).
-
-1. Configure:
-$ cmake .
-or
-$ cmake -DCMAKE_BUILD_TYPE="Release" -DCMAKE_INSTALL_PREFIX="install_prefix" \
--DDATA_INSTALL_DIR="data_dir" -DNOSERVER=1 .
-
-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
-
-3. Install:
-# make install
-
-
-That's all! Enjoy!
-
+INSTALL.md
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/INSTALL.md	Sun Dec 17 00:09:24 2017 +0100
@@ -0,0 +1,203 @@
+Building and installing Hedgewars
+=================================
+
+This file explains to you how to build/compile Hedgewars and how to install it.
+
+See also: <https://hedgewars.org/kb/BuildingHedgewars>
+
+Dependencies
+------------
+
+### Core dependencies
+
+To compile and install Hedgewars, you need at least:
+
+- A C++ compiler (e.g. GCC)
+- CMake >= 2.6.0
+- A make program (e.g. GNU Make)
+- Free Pascal Compiler (FPC) >= 2.2.4
+- Qt = 4.7.0
+- SDL >= 2.0
+- SDL\_net >= 2.0
+- SDL\_mixer >= 2.0
+- SDL\_image >= 2.0
+- SDL\_ttf >= 2.0
+
+### Optional dependencies
+
+For some additional features, you can optionally install these dependencies:
+
+- For Hedgewars:
+    - PhysFS >= 2.0.0 (recommended)
+    - Lua = 5.1.0 (recommended)
+- For PNG screenshots:
+    - libpng >= 1.2 (recommended)
+- For video recording:
+    - FFmpeg or Libav
+- For the Hedgewars Server:
+    - GHC >= 6.10
+    - Various Haskell packages (see below)
+
+PhysFS will be internally built if `-DPHYSFS_SYSTEM=OFF` is passed to `cmake`
+(also allows to set `PHYSFS_LIBRARY` and `PHYSFS_INCLUDE_DIR` if needed).
+
+Lua will be automatically built if not found.
+
+### Hedgewars Server dependencies
+
+The Hedgewars Server is an **optional** separate application.
+It provides the online lobby and allows players to create rooms.
+You will also be able to launch the server from the frontend
+(network play → local network → start server).
+
+**Most players do not need this!**
+
+To compile it, you need:
+
+- Glasgow Haskell Compiler (GHC) >= 6.10
+- These Haskell packages:
+    - `containers`
+    - `vector`
+    - `bytestring`
+    - `network` >= 2.3
+    - `random`
+    - `time`
+    - `mtl` >= 2
+    - `sandi`
+    - `hslogger`
+    - `process`
+    - `deepseq`
+    - `utf8-string`
+    - `SHA`
+    - `entropy`
+    - `zlib` >= 0.5.3 and < 0.6
+    - `regex-tdfa`
+
+
+Building
+--------
+
+### Summary
+
+To build and install Hedgewars, obtain all dependencies, then run:
+
+   $ cmake .
+   $ make
+   # make install
+
+### Step 1: Configure
+
+For a default install with all dependencis, use this command:
+
+    $ cmake .
+
+To build with a custom install directory, instead run:
+
+    $ cmake -DCMAKE_INSTALL_PREFIX="<install_prefix>" .
+
+(Replace `<install_prefix>` with the directoy in which you
+want Hedgewars to be installed.)
+
+Add the `-DNOSERVER=ON` switch if you do not want to build
+the server.
+
+#### CMake options
+
+For more detailed build settings, change some CMake options.
+Run `ccmake` for an interactive way to edit them.
+
+Important CMake options:
+
+- `CMAKE_INSTALL_PREFIX`: Installation directory
+- `NOSERVER`: Set to `ON` to *not* build the server
+- `NOVIDEOREC`: Set to `ON` to *not* build the video recorder
+- `SYSTEM_PHYSFS`: Set to `OFF` to use Hedgewars-bundled PhysFS
+
+### Step 2: Make
+
+Run:
+
+    $ make
+
+This creates the following files:
+
+- `bin/hedgewars`: Hedgewars
+- `bin/hwengine`: Game engine, can be used to play demos and saved games
+- `bin/hedgewars-server`: Hedgewars Server (optional)
+
+### Step 3: Installation
+
+To install Hedgewars to the install directory run:
+
+    # make install
+
+That's all! Enjoy!
+
+Troubleshooting
+---------------
+
+### Qt is installed but it can't be found
+
+If this happens, set the following CMake option:
+
+    QT_QMAKE_EXECUTABLE="<path_to_qmake>"
+
+(Replace `<path_to_qmake>` with the path to the `qmake` application.)
+
+If this didn't work, make sure you have the correct Qt version
+(see above).
+
+### Hedgewars compiles successfully, but games instantly crash the map preview fails
+
+This is likely to be a problem with PhysFS. Try to build Hedgewars
+with the Hedgewars-bundled PhysFS by setting the CMake option
+`SYSTEM_PHYSFS=OFF`, then try to run `make` again.
+
+If the _bundled_ PhysFS fails, too, this is likely to be a bug in
+Hedgewars, please report at <https://issues.hedgewars.org/>.
+
+### Broken/missing Haskell dependencies
+
+First, try to obtain the missing Haskell packages and make sure GHC
+is up-to date, then try again. Read the error messages carefully
+to figure out missing package names.
+
+If everything fails and you don't need the server, set the CMake
+option `NOSERVER=ON` so the server isn't built at all.
+
+### Error messages related to libavcodec / libavformat
+
+Update Libav or FFmpeg (whatever is present on your system) to
+the latest version or install one of them if you haven't already.
+Then try to build again.
+
+If this still doesn't work and you give up, set the CMake option
+`NOVIDEOREC=ON`, but then the video recording functionality will
+not be available.
+
+### Error messages related to Lua, “undefined reference to `lua_tonumber'”, and so on
+If you get error messages like these:
+
+* /home/username/hw/hedgewars//uScript.pas:226: undefined reference to `lua_tonumber'
+* /home/username/hw/hedgewars/CMakeFiles/hwengine.dir/uScript.o: In function `LUATOVISUALGEARTYPEORD':
+
+There might be something wrong with your Lua installation. Try to install Lua 5.1.
+If this doesn't work, or you don't want to install Lua 5.1, try to build Hedgewars
+with the bundled Lua version.
+
+To build with the bundled Lua version, adding the CMake option `SYSTEM_LUA=OFF`, then
+repeat the building process.
+
+### Cleaning up
+
+In case you want to start over and start with a clean build,
+run `make clean`, then go back to step 2.
+
+If things got seriously out of hand, you may want to reset
+*everything* (even your configuration). If you use the
+Mercural repository, you can run `hg purge --all`. Proceed with
+step 1.
+
+### Still can't build Hedgewars?
+
+Visit us in the forums or IRC (see `README.md`) and ask for help.
--- a/QTfrontend/CMakeLists.txt	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/CMakeLists.txt	Sun Dec 17 00:09:24 2017 +0100
@@ -21,9 +21,9 @@
 endif()
 
 find_package(SDL2 REQUIRED)
-find_package(SDL2_mixer REQUIRED) #audio in SDLInteraction
+find_package(SDL2_mixer 2 REQUIRED) #audio in SDLInteraction
 include_directories(${SDL2_INCLUDE_DIR})
-include_directories(${SDL2MIXER_INCLUDE_DIR})
+include_directories(${SDL2_MIXER_INCLUDE_DIRS})
 
 if(LIBAV_FOUND)
     add_definitions(-DVIDEOREC -D__STDC_CONSTANT_MACROS)
@@ -103,11 +103,6 @@
     ${CMAKE_CURRENT_BINARY_DIR}/hwconsts.cpp
     )
 
-#xfire integration
-if(WIN32)
-    list(APPEND hwfr_src util/platform/xfire.cpp util/platform/xfiregameclient.cpp)
-endif(WIN32)
-
 if(MINGW)
     # resource compilation for mingw
     add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/hedgewars_rc.o
@@ -208,7 +203,7 @@
 
 list(APPEND HW_LINK_LIBS
     ${SDL2_LIBRARY}
-    ${SDL2MIXER_LIBRARY}
+    ${SDL2_MIXER_LIBRARIES}
     )
     
 if(WIN32 AND NOT UNIX)
--- a/QTfrontend/binds.cpp	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/binds.cpp	Sun Dec 17 00:09:24 2017 +0100
@@ -66,7 +66,8 @@
     {"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:")},
     {"+speedup",  "s",          QT_TRANSLATE_NOOP("binds", "speed up replay"),         NULL, QT_TRANSLATE_NOOP("binds (descriptions)", "Demo replay:")},
-    {"rotmask",   "delete",     QT_TRANSLATE_NOOP("binds", "hedgehog info"), NULL, QT_TRANSLATE_NOOP("binds (descriptions)", "Toggle labels above hedgehogs:")},
+    //: This refers to the team info bars (name/flag/health) of all teams. These are shown at the bottom center of the screen
+    {"rotmask",   "delete",     QT_TRANSLATE_NOOP("binds", "toggle team bars"), NULL, QT_TRANSLATE_NOOP("binds (descriptions)", "Heads-up display:")},
 #ifdef VIDEOREC
     {"record",    "r",          QT_TRANSLATE_NOOP("binds", "record"),          NULL, QT_TRANSLATE_NOOP("binds (descriptions)", "Record video:")}
 #endif
--- a/QTfrontend/campaign.cpp	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/campaign.cpp	Sun Dec 17 00:09:24 2017 +0100
@@ -23,68 +23,128 @@
 #include <QObject>
 #include <QLocale>
 
-QList<MissionInfo> getCampMissionList(QString & campaignName, QString & teamName)
+QSettings* getCampTeamFile(QString & campaignName, QString & teamName)
 {
-    QList<MissionInfo> missionInfoList;
-    QSettings teamfile(cfgdir->absolutePath() + "/Teams/" + teamName + ".hwt", QSettings::IniFormat, 0);
-    teamfile.setIniCodec("UTF-8");
-
+    QSettings* teamfile = new QSettings(cfgdir->absolutePath() + "/Teams/" + teamName + ".hwt", QSettings::IniFormat, 0);
+    teamfile->setIniCodec("UTF-8");
     // if entry not found check if there is written without _
     // if then is found rename it to use _
     QString spaceCampName = campaignName;
     spaceCampName = spaceCampName.replace(QString("_"),QString(" "));
-    if (!teamfile.childGroups().contains("Campaign " + campaignName) and
-            teamfile.childGroups().contains("Campaign " + spaceCampName)){
-        teamfile.beginGroup("Campaign " + spaceCampName);
-        QStringList keys = teamfile.childKeys();
-        teamfile.endGroup();
+    if (!teamfile->childGroups().contains("Campaign " + campaignName) and
+            teamfile->childGroups().contains("Campaign " + spaceCampName)){
+        teamfile->beginGroup("Campaign " + spaceCampName);
+        QStringList keys = teamfile->childKeys();
+        teamfile->endGroup();
         for (int i=0;i<keys.size();i++) {
-            QVariant value = teamfile.value("Campaign " + spaceCampName + "/" + keys[i]);
-            teamfile.setValue("Campaign " + campaignName + "/" + keys[i], value);
+            QVariant value = teamfile->value("Campaign " + spaceCampName + "/" + keys[i]);
+            teamfile->setValue("Campaign " + campaignName + "/" + keys[i], value);
         }
-        teamfile.remove("Campaign " + spaceCampName);
+        teamfile->remove("Campaign " + spaceCampName);
     }
 
-    int progress = teamfile.value("Campaign " + campaignName + "/Progress", 0).toInt();
-    int unlockedMissions = teamfile.value("Campaign " + campaignName + "/UnlockedMissions", 0).toInt();
+    return teamfile;
+}
+
+/**
+    Returns true if the specified mission has been completed
+    campaignName: Name of the campaign in question
+    missionInList: QComboBox index of the mission as selected in the mission widget
+    teamName: Name of the playing team
+*/
+bool isMissionWon(QString & campaignName, int missionInList, QString & teamName)
+{
+    QSettings* teamfile = getCampTeamFile(campaignName, teamName);
+    int progress = teamfile->value("Campaign " + campaignName + "/Progress", 0).toInt();
+    int unlockedMissions = teamfile->value("Campaign " + campaignName + "/UnlockedMissions", 0).toInt();
+    if(progress>0 and unlockedMissions==0)
+    {
+        QSettings campfile("physfs://Missions/Campaign/" + campaignName + "/campaign.ini", QSettings::IniFormat, 0);
+        campfile.setIniCodec("UTF-8");
+        int totalMissions = campfile.value("MissionNum", 1).toInt();
+        return (progress > (progress - missionInList)) || (progress >= totalMissions);
+    }
+    else if(unlockedMissions>0)
+    {
+        int fileMissionId = missionInList + 1;
+        int actualMissionId = teamfile->value(QString("Campaign %1/Mission%2").arg(campaignName, QString::number(fileMissionId)), false).toInt();
+        return teamfile->value(QString("Campaign %1/Mission%2Won").arg(campaignName, QString::number(actualMissionId)), false).toBool();
+    }
+    else
+        return false;
+}
+
+/** Returns true if the campaign has been won by the team */
+bool isCampWon(QString & campaignName, QString & teamName)
+{
+    QSettings* teamfile = getCampTeamFile(campaignName, teamName);
+    bool won = teamfile->value("Campaign " + campaignName + "/Won", false).toBool();
+    return won;
+}
+
+QSettings* getCampMetaInfo()
+{
+    DataManager & dataMgr = DataManager::instance();
+    // get locale
+    QSettings settings(dataMgr.settingsFileName(),
+    QSettings::IniFormat);
+    QString loc = settings.value("misc/locale", "").toString();
+    if (loc.isEmpty())
+        loc = QLocale::system().name();
+    QString campaignDescFile = QString("physfs://Locale/campaigns_" + loc + ".txt");
+    // if file is non-existant try with language only
+    if (!QFile::exists(campaignDescFile))
+    campaignDescFile = QString("physfs://Locale/campaigns_" + loc.remove(QRegExp("_.*$")) + ".txt");
+
+    // fallback if file for current locale is non-existant
+    if (!QFile::exists(campaignDescFile))
+        campaignDescFile = QString("physfs://Locale/campaigns_en.txt");
+
+    QSettings* m_info = new QSettings(campaignDescFile, QSettings::IniFormat, 0);
+    m_info->setIniCodec("UTF-8");
+
+    return m_info;
+}
+
+/** Returns the localized campaign name */
+QString getRealCampName(const QString & campaignName)
+{
+    QString campaignNameSpaces = QString(campaignName).replace(QString("_"), QString(" "));
+    return getCampMetaInfo()->value(campaignName+".name", campaignNameSpaces).toString();
+}
+
+QList<MissionInfo> getCampMissionList(QString & campaignName, QString & teamName)
+{
+    QList<MissionInfo> missionInfoList;
+    QSettings* teamfile = getCampTeamFile(campaignName, teamName);
+
+    int progress = teamfile->value("Campaign " + campaignName + "/Progress", 0).toInt();
+    int unlockedMissions = teamfile->value("Campaign " + campaignName + "/UnlockedMissions", 0).toInt();
 
     QSettings campfile("physfs://Missions/Campaign/" + campaignName + "/campaign.ini", QSettings::IniFormat, 0);
     campfile.setIniCodec("UTF-8");
 
-    DataManager & dataMgr = DataManager::instance();
-        // get locale
-        QSettings settings(dataMgr.settingsFileName(),
-                           QSettings::IniFormat);
-        QString loc = settings.value("misc/locale", "").toString();
-        if (loc.isEmpty())
-            loc = QLocale::system().name();
-        QString campaignDescFile = QString("physfs://Locale/campaigns_" + loc + ".txt");
-        // if file is non-existant try with language only
-        if (!QFile::exists(campaignDescFile))
-            campaignDescFile = QString("physfs://Locale/campaigns_" + loc.remove(QRegExp("_.*$")) + ".txt");
-
-        // fallback if file for current locale is non-existant
-        if (!QFile::exists(campaignDescFile))
-            campaignDescFile = QString("physfs://Locale/campaigns_en.txt");
-
-        QSettings m_info(campaignDescFile, QSettings::IniFormat, 0);
-        m_info.setIniCodec("UTF-8");
+    QSettings* m_info = getCampMetaInfo();
 
     if(progress>=0 and unlockedMissions==0)
     {
         for(unsigned int i=progress+1;i>0;i--)
         {
             MissionInfo missionInfo;
-            missionInfo.name = campfile.value(QString("Mission %1/Name").arg(i)).toString();
             QString script = campfile.value(QString("Mission %1/Script").arg(i)).toString();
-            missionInfo.script = script;
-            missionInfo.description = m_info.value(campaignName+"-"+ script.replace(QString(".lua"),QString("")) + ".desc",
+            if(!script.isNull()) {
+                missionInfo.script = script;
+                missionInfo.name = campfile.value(QString("Mission %1/Name").arg(i)).toString();
+                QString scriptPrefix = campaignName+"-"+ script.replace(QString(".lua"),QString(""));
+                missionInfo.realName = m_info->value(scriptPrefix+".name", missionInfo.name).toString();
+                missionInfo.description = m_info->value(scriptPrefix + ".desc",
                                             QObject::tr("No description available")).toString();
-            QString image = campfile.value(QString("Mission %1/Script").arg(i)).toString().replace(QString(".lua"),QString(".png"));
-            missionInfo.image = ":/res/campaign/"+campaignName+"/"+image;
-            if (!QFile::exists(missionInfo.image))
-                missionInfo.image = ":/res/CampaignDefault.png";
-            missionInfoList.append(missionInfo);
+                QString image = campfile.value(QString("Mission %1/Script").arg(i)).toString().replace(QString(".lua"),QString(".png"));
+                missionInfo.image = ":/res/campaign/"+campaignName+"/"+image;
+                if (!QFile::exists(missionInfo.image))
+                    missionInfo.image = ":/res/CampaignDefault.png";
+                missionInfoList.append(missionInfo);
+            }
         }
     }
     else if(unlockedMissions>0)
@@ -92,12 +152,14 @@
         for(int i=1;i<=unlockedMissions;i++)
         {
             QString missionNum = QString("%1").arg(i);
-            int missionNumber = teamfile.value("Campaign " + campaignName + "/Mission"+missionNum, -1).toInt();
+            int missionNumber = teamfile->value("Campaign " + campaignName + "/Mission"+missionNum, -1).toInt();
             MissionInfo missionInfo;
-            missionInfo.name = campfile.value(QString("Mission %1/Name").arg(missionNumber)).toString();
             QString script = campfile.value(QString("Mission %1/Script").arg(missionNumber)).toString();
             missionInfo.script = script;
-            missionInfo.description = m_info.value(campaignName+"-"+ script.replace(QString(".lua"),QString("")) + ".desc",
+            missionInfo.name = campfile.value(QString("Mission %1/Name").arg(missionNumber)).toString();
+            QString scriptPrefix = campaignName+"-"+ script.replace(QString(".lua"),QString(""));
+            missionInfo.realName = m_info->value(scriptPrefix+".name", missionInfo.name).toString();
+            missionInfo.description = m_info->value(scriptPrefix + ".desc",
                                             QObject::tr("No description available")).toString();
             QString image = campfile.value(QString("Mission %1/Script").arg(missionNumber)).toString().replace(QString(".lua"),QString(".png"));
             missionInfo.image = ":/res/campaign/"+campaignName+"/"+image;
--- a/QTfrontend/campaign.h	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/campaign.h	Sun Dec 17 00:09:24 2017 +0100
@@ -20,16 +20,24 @@
 #define CAMPAIGN_H
 
 #include <QString>
+#include <QSettings>
 
 class MissionInfo
 {
     public:
         QString name;
+        QString realName;
         QString description;
         QString script;
         QString image;
 };
 
+
+QSettings* getCampTeamFile(QString & campaignName, QString & teamName);
+QSettings* getCampMetaInfo();
+bool isCampWon(QString & campaignName, QString & teamName);
+bool isMissionWon(QString & campaignName, int missionInList, QString & teamName);
+QString getRealCampName(const QString & campaignName);
 QList<MissionInfo> getCampMissionList(QString & campaignName, QString & teamName);
 
 #endif
--- a/QTfrontend/game.cpp	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/game.cpp	Sun Dec 17 00:09:24 2017 +0100
@@ -44,6 +44,7 @@
 // last game info
 QList<QVariant> lastGameStartArgs = QList<QVariant>();
 GameType lastGameType = gtNone;
+QString lastTrainingSubFolder = NULL;
 GameCFGWidget * lastGameCfg = NULL;
 QString lastGameAmmo = NULL;
 TeamSelWidget * lastGameTeamSel = NULL;
@@ -153,7 +154,8 @@
     team1.setDifficulty(0);
     team1.setColor(0);
     team1.setNumHedgehogs(4);
-    HWNamegen::teamRandomNames(team1,true);
+    HWNamegen::teamRandomEverything(team1);
+    team1.setVoicepack("Default");
     HWProto::addStringListToBuffer(teamscfg,
                                    team1.teamGameConfig(100));
 
@@ -162,8 +164,9 @@
     team2.setColor(1);
     team2.setNumHedgehogs(4);
     do
-        HWNamegen::teamRandomNames(team2,true);
+        HWNamegen::teamRandomEverything(team2);
     while(!team2.name().compare(team1.name()) || !team2.hedgehog(0).Hat.compare(team1.hedgehog(0).Hat));
+    team2.setVoicepack("Default");
     HWProto::addStringListToBuffer(teamscfg,
                                    team2.teamGameConfig(100));
 
@@ -383,6 +386,8 @@
     arguments << "--user-prefix";
     arguments << cfgdir->absolutePath();
     arguments << "--locale";
+    // TODO: Don't bother translators with this nonsense and detect this file automatically.
+    //: IMPORTANT: This text has a special meaning, do not translate it directly. This is the file name of translation files for the game engine, found in Data/Locale/. Usually, you replace “en” with the ISO-639-1 language code of your language.
     arguments << tr("en.txt");
     arguments << "--frame-interval";
     arguments << QString::number(config->timerInterval());
@@ -430,6 +435,7 @@
 void HWGame::PlayDemo(const QString & demofilename, bool isSave)
 {
     gameType = isSave ? gtSave : gtDemo;
+    lastGameType = gameType;
     QFile demofile(demofilename);
     if (!demofile.open(QIODevice::ReadOnly))
     {
@@ -448,6 +454,9 @@
 
 void HWGame::StartNet()
 {
+    lastGameStartArgs.clear();
+    lastGameType = gtNet;
+
     gameType = gtNet;
     demo.clear();
     Start(false);
@@ -476,14 +485,16 @@
     SetGameState(gsStarted);
 }
 
-void HWGame::StartTraining(const QString & file)
+void HWGame::StartTraining(const QString & file, const QString & subFolder)
 {
     lastGameStartArgs.clear();
     lastGameStartArgs.append(file);
     lastGameType = gtTraining;
+    lastTrainingSubFolder = subFolder;
 
     gameType = gtTraining;
-    training = "Missions/Training/" + file + ".lua";
+
+    training = "Missions/" + subFolder + "/" + file + ".lua";
     demo.clear();
     Start(false);
     SetGameState(gsStarted);
--- a/QTfrontend/game.h	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/game.h	Sun Dec 17 00:09:24 2017 +0100
@@ -64,6 +64,7 @@
 // last game info
 extern QList<QVariant> lastGameStartArgs;
 extern GameType lastGameType;
+extern QString lastTrainingSubFolder;
 extern GameCFGWidget * lastGameCfg;
 extern QString lastGameAmmo;
 extern TeamSelWidget * lastGameTeamSel;
@@ -79,7 +80,7 @@
         void StartLocal();
         void StartQuick();
         void StartNet();
-        void StartTraining(const QString & file);
+        void StartTraining(const QString & file, const QString & subFolder);
         void StartCampaign(const QString & camp, const QString & campScript, const QString & campTeam);
         void abort();
         GameState gameState;
--- a/QTfrontend/gameuiconfig.cpp	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/gameuiconfig.cpp	Sun Dec 17 00:09:24 2017 +0100
@@ -183,10 +183,9 @@
     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) );
+    int framerateBoxIndex = Form->ui.pageOptions->framerateBox->findData(value("videorec/framerate", rec_Framerate()).toUInt());
+    if(framerateBoxIndex != -1)
+        Form->ui.pageOptions->framerateBox->setCurrentIndex(framerateBoxIndex);
     Form->ui.pageOptions->bitrateBox->setValue(value("videorec/bitrate", rec_Bitrate()).toUInt());
     bool useGameRes = value("videorec/usegameres",Form->ui.pageOptions->checkUseGameRes->isChecked()).toBool();
     if (useGameRes)
@@ -625,10 +624,7 @@
 
 int GameUIConfig::rec_Framerate()
 {
-    // remove the "fps" label
-    QString fpsText = Form->ui.pageOptions->framerateBox->currentText();
-    QStringList fpsList = fpsText.split(" ");
-    return fpsList.first().toInt();
+    return Form->ui.pageOptions->framerateBox->itemData(Form->ui.pageOptions->framerateBox->currentIndex()).toInt();
 }
 
 int GameUIConfig::rec_Bitrate()
--- a/QTfrontend/hedgewars.qrc	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/hedgewars.qrc	Sun Dec 17 00:09:24 2017 +0100
@@ -1,6 +1,6 @@
 <RCC>
     <qresource prefix="/">
-        <file alias="Ammos.png">../share/hedgewars/Data/Graphics/AmmoMenu/Ammos.png</file>
+        <file alias="Ammos.png">../share/hedgewars/Data/Graphics/AmmoMenu/Ammos_base.png</file>
         <file>res/css/qt.css</file>
         <file>res/css/chat.css</file>
         <file>res/css/christmas.css</file>
@@ -85,12 +85,20 @@
         <file>res/delete.png</file>
         <file>res/checked.png</file>
         <file>res/unchecked.png</file>
+        <file>res/missionFinished.png</file>
+        <file>res/missionFinishedSelected.png</file>
+        <file>res/dlcMarker.png</file>
+        <file>res/dlcMarkerSelected.png</file>
         <file>res/graphicsicon.png</file>
+        <file>res/frontendicon.png</file>
+        <file>res/folder.png</file>
         <file>res/miscicon.png</file>
         <file>res/Load.png</file>
         <file>res/Save.png</file>
         <file>res/Record.png</file>
         <file>res/Videos.png</file>
+        <file>res/Palette.png</file>
+        <file>res/schemeicon.png</file>
         <file>res/weaponsicon.png</file>
         <file>res/teamicon.png</file>
         <file>res/panelbg.png</file>
@@ -101,7 +109,6 @@
         <file>res/PlaySound.png</file>
         <file>res/hh_small.png</file>
         <file>res/btnDisabled.png</file>
-        <file>res/btnForts@2x.png</file>
         <file>res/btnBorder@2x.png</file>
         <file>res/btnInvulnerable@2x.png</file>
         <file>res/btnLaserSight@2x.png</file>
@@ -127,6 +134,7 @@
         <file>res/btnTagTeam@2x.png</file>
         <file>res/btnBottomBorder@2x.png</file>
         <file>res/iconBox.png</file>
+        <file>res/iconInitHealth.png</file>
         <file>res/iconHealth.png</file>
         <file>res/iconHealthPercent.png</file>
         <file>res/iconSuddenDeath.png</file>
@@ -148,6 +156,7 @@
         <file>res/iconScript.png</file>
         <file>res/dice.png</file>
         <file>res/Star.png</file>
+        <file>res/home.png</file>
         <file>res/inverse-corner-bl.png</file>
         <file>res/Flake.png</file>
         <file>res/Egg.png</file>
--- a/QTfrontend/hwconsts.cpp.in	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/hwconsts.cpp.in	Sun Dec 17 00:09:24 2017 +0100
@@ -72,12 +72,15 @@
         << qMakePair(QString("Highlander"), QString(
             AMMOLINE_HIGHLANDER_QT AMMOLINE_HIGHLANDER_PROB
             AMMOLINE_HIGHLANDER_DELAY AMMOLINE_HIGHLANDER_CRATE ))
-		<< qMakePair(QString("Construction Mode"),   QString(
+        << qMakePair(QString("Construction Mode"),   QString(
             AMMOLINE_CONSTRUCTION_QT AMMOLINE_CONSTRUCTION_PROB
             AMMOLINE_CONSTRUCTION_DELAY AMMOLINE_CONSTRUCTION_CRATE ))
-		<< qMakePair(QString("Shoppa Pro"), QString(
+        << qMakePair(QString("Shoppa Pro"), QString(
             AMMOLINE_SHOPPAPRO_QT AMMOLINE_SHOPPAPRO_PROB
             AMMOLINE_SHOPPAPRO_DELAY AMMOLINE_SHOPPAPRO_CRATE ))
+        << qMakePair(QString("HedgeEditor"), QString(
+            AMMOLINE_HEDGEEDITOR_QT AMMOLINE_HEDGEEDITOR_PROB
+            AMMOLINE_HEDGEEDITOR_DELAY AMMOLINE_HEDGEEDITOR_CRATE ))
         ;
 
 unsigned int colors[] = HW_TEAMCOLOR_ARRAY;
--- a/QTfrontend/hwconsts.h	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/hwconsts.h	Sun Dec 17 00:09:24 2017 +0100
@@ -73,7 +73,7 @@
 #define HEDGEHOGS_PER_TEAM 8
 
 
-// see http://en.wikipedia.org/wiki/List_of_colors
+// see https://en.wikipedia.org/wiki/List_of_colors
 /*define HW_TEAMCOLOR_ARRAY  {0xff007fff, /. azure          ./ \
                               0xffdd0000, /. classic red    ./ \
                               0xff3e9321, /. classic green  ./ \
--- a/QTfrontend/hwform.cpp	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/hwform.cpp	Sun Dec 17 00:09:24 2017 +0100
@@ -46,6 +46,8 @@
 #include <QPropertyAnimation>
 #include <QSettings>
 #include <QSortFilterProxyModel>
+#include <QIcon>
+#include <QImage>
 
 #if (QT_VERSION >= 0x040600)
 #include <QGraphicsEffect>
@@ -90,7 +92,6 @@
 #include "input_password.h"
 #include "ammoSchemeModel.h"
 #include "bgwidget.h"
-#include "xfire.h"
 #include "drawmapwidget.h"
 #include "mouseoverfilter.h"
 #include "roomslistmodel.h"
@@ -129,6 +130,8 @@
 bool frontendEffects = true;
 QString playerHash;
 
+QIcon finishedIcon;
+QIcon notFinishedIcon;
 GameUIConfig* HWForm::config = NULL;
 
 HWForm::HWForm(QWidget *parent, QString styleSheet)
@@ -142,10 +145,19 @@
     // set music track
     SDLInteraction::instance().setMusicTrack("/Music/main_theme.ogg");
 
-#ifdef USE_XFIRE
-    xfire_init();
-#endif
     this->setStyleSheet(styleSheet);
+
+
+    QIcon * hwIcon = new QIcon();
+    hwIcon->addFile(":/res/hh_small.png");
+    //hwIcon->addFile(":/res/hh25x25.png");
+    // crop-workaround for the fact that hh25x25.png is actually 25x35
+    QPixmap pm(":/res/hh25x25.png");
+    hwIcon->addPixmap(pm.copy(0,(pm.height()-25)/2,25,25));
+    hwIcon->addFile(":/res/teamicon.png");
+    hwIcon->addFile(":/res/teamicon2.png");
+
+    this->setWindowIcon(*hwIcon);
     ui.setupUi(this);
     setMinimumSize(760, 580);
     //setFocusPolicy(Qt::StrongFocus);
@@ -157,6 +169,15 @@
     frontendEffects = config->value("frontend/effects", true).toBool();
     playerHash = QString(QCryptographicHash::hash(config->value("net/nick",tr("Guest")+QString("%1").arg(rand())).toString().toUtf8(), QCryptographicHash::Md5).toHex());
 
+    // Icons for finished missions
+    finishedIcon.addFile(":/res/missionFinished.png", QSize(), QIcon::Normal, QIcon::On);
+    finishedIcon.addFile(":/res/missionFinishedSelected.png", QSize(), QIcon::Selected, QIcon::On);
+
+    // A transparent icon, used to nicely align the unfinished missions with the finished ones
+    QPixmap emptySpace = QPixmap(15, 15);
+    emptySpace.fill(QColor(0, 0, 0, 0));
+    notFinishedIcon = QIcon(emptySpace);
+
     ui.pageRoomsList->setSettings(config);
     ui.pageNetGame->setSettings(config);
     ui.pageNetGame->chatWidget->setSettings(config);
@@ -198,6 +219,7 @@
     UpdateTeamsLists();
     InitCampaignPage();
     UpdateCampaignPage(0);
+    UpdateCampaignPageTeam(0);
     UpdateCampaignPageMission(0);
     UpdateWeapons();
 
@@ -243,7 +265,7 @@
             ui.pageMultiplayer->BtnStartMPGame, SLOT(setEnabled(bool)));
     connect(ui.pageMultiplayer, SIGNAL(SetupClicked()), this, SLOT(IntermediateSetup()));
     connect(ui.pageMultiplayer->gameCFG, SIGNAL(goToSchemes(int)), this, SLOT(GoToScheme(int)));
-    connect(ui.pageMultiplayer->gameCFG, SIGNAL(goToWeapons(int)), this, SLOT(GoToSelectWeaponSet(int)));
+    connect(ui.pageMultiplayer->gameCFG, SIGNAL(goToWeapons(int)), this, SLOT(GoToWeapons(int)));
     connect(ui.pageMultiplayer->gameCFG, SIGNAL(goToDrawMap()), pageSwitchMapper, SLOT(map()));
     pageSwitchMapper->setMapping(ui.pageMultiplayer->gameCFG, ID_PAGE_DRAWMAP);
 
@@ -257,14 +279,13 @@
     connect(ui.pageOptions, SIGNAL(goBack()), config, SLOT(SaveOptions()));
     connect(ui.pageOptions->BtnAssociateFiles, SIGNAL(clicked()), this, SLOT(AssociateFiles()));
 
-    connect(ui.pageOptions->WeaponEdit, SIGNAL(clicked()), this, SLOT(GoToSelectWeapon()));
-    connect(ui.pageOptions->WeaponNew, SIGNAL(clicked()), this, SLOT(GoToSelectNewWeapon()));
+    connect(ui.pageOptions->WeaponEdit, SIGNAL(clicked()), this, SLOT(GoToEditWeapons()));
+    connect(ui.pageOptions->WeaponNew, SIGNAL(clicked()), this, SLOT(GoToNewWeapons()));
     connect(ui.pageOptions->WeaponDelete, SIGNAL(clicked()), this, SLOT(DeleteWeaponSet()));
     connect(ui.pageOptions->SchemeEdit, SIGNAL(clicked()), this, SLOT(GoToEditScheme()));
     connect(ui.pageOptions->SchemeNew, SIGNAL(clicked()), this, SLOT(GoToNewScheme()));
     connect(ui.pageOptions->SchemeDelete, SIGNAL(clicked()), this, SLOT(DeleteScheme()));
     connect(ui.pageOptions->CBFrontendEffects, SIGNAL(toggled(bool)), this, SLOT(onFrontendEffects(bool)) );
-    connect(ui.pageSelectWeapon->pWeapons, SIGNAL(weaponsChanged()), this, SLOT(UpdateWeapons()));
 
     connect(ui.pageNet->BtnSpecifyServer, SIGNAL(clicked()), this, SLOT(NetConnect()));
     connect(ui.pageNet->BtnNetSvrStart, SIGNAL(clicked()), pageSwitchMapper, SLOT(map()));
@@ -278,7 +299,7 @@
             ui.pageNetGame->BtnStart, SLOT(setEnabled(bool)));
     connect(ui.pageNetGame, SIGNAL(SetupClicked()), this, SLOT(IntermediateSetup()));
     connect(ui.pageNetGame->pGameCFG, SIGNAL(goToSchemes(int)), this, SLOT(GoToScheme(int)));
-    connect(ui.pageNetGame->pGameCFG, SIGNAL(goToWeapons(int)), this, SLOT(GoToSelectWeaponSet(int)));
+    connect(ui.pageNetGame->pGameCFG, SIGNAL(goToWeapons(int)), this, SLOT(GoToWeapons(int)));
     connect(ui.pageNetGame->pGameCFG, SIGNAL(goToDrawMap()), pageSwitchMapper, SLOT(map()));
     pageSwitchMapper->setMapping(ui.pageNetGame->pGameCFG, ID_PAGE_DRAWMAP);
 
@@ -303,21 +324,23 @@
     connect(ui.pageSinglePlayer->BtnLoad, SIGNAL(clicked()), this, SLOT(GoToSaves()));
     connect(ui.pageSinglePlayer->BtnDemos, SIGNAL(clicked()), this, SLOT(GoToDemos()));
 
-    connect(ui.pageTraining, SIGNAL(startMission(const QString&)), this, SLOT(startTraining(const QString&)));
+    connect(ui.pageTraining, SIGNAL(startMission(const QString&, const QString&)), this, SLOT(startTraining(const QString&, const QString&)));
 
     connect(ui.pageCampaign->BtnStartCampaign, SIGNAL(clicked()), this, SLOT(StartCampaign()));
     connect(ui.pageCampaign->btnPreview, SIGNAL(clicked()), this, SLOT(StartCampaign()));
     connect(ui.pageCampaign->CBTeam, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateCampaignPage(int)));
+    connect(ui.pageCampaign->CBTeam, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateCampaignPageTeam(int)));
     connect(ui.pageCampaign->CBCampaign, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateCampaignPage(int)));
     connect(ui.pageCampaign->CBMission, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateCampaignPageMission(int)));
 
-    connect(ui.pageSelectWeapon->BtnDelete, SIGNAL(clicked()),
-            ui.pageSelectWeapon->pWeapons, SLOT(deleteWeaponsName())); // executed first
-    connect(ui.pageSelectWeapon->pWeapons, SIGNAL(weaponsDeleted()),
-            this, SLOT(UpdateWeapons())); // executed second
-    //connect(ui.pageSelectWeapon->pWeapons, SIGNAL(weaponsDeleted()),
-    //    this, SLOT(GoBack())); // executed third
-
+    connect(ui.pageSelectWeapon->pWeapons, SIGNAL(weaponsDeleted(QString)),
+             this, SLOT(DeleteWeapons(QString)));
+    connect(ui.pageSelectWeapon->pWeapons, SIGNAL(weaponsAdded(QString, QString)),
+             this, SLOT(AddWeapons(QString, QString)));
+    connect(ui.pageSelectWeapon->pWeapons, SIGNAL(weaponsEdited(QString, QString, QString)),
+             this, SLOT(EditWeapons(QString, QString, QString)));
+    connect(ui.pageSelectWeapon->pWeapons, SIGNAL(weaponsEdited(QString, QString, QString)),
+             ui.pageNetGame->pGameCFG, SLOT(resendAmmoData()));
 
     connect(ui.pageMain->BtnNetLocal, SIGNAL(clicked()), this, SLOT(GoToNet()));
     connect(ui.pageMain->BtnNetOfficial, SIGNAL(clicked()), this, SLOT(NetConnectOfficialServer()));
@@ -359,56 +382,13 @@
     GoBack();
 }
 
-#ifdef USE_XFIRE
-void HWForm::updateXfire(void)
-{
-    if(hwnet && (hwnet->clientState() != HWNewNet::Disconnected))
-    {
-        xfire_setvalue(XFIRE_SERVER, !hwnet->getHost().compare(QString("%1:%2").arg(NETGAME_DEFAULT_SERVER).arg(NETGAME_DEFAULT_PORT)) ? "Official server" : hwnet->getHost().toAscii());
-        switch(hwnet->clientState())
-        {
-            case HWNewNet::Connecting: // Connecting
-            case HWNewNet::Connected:
-                xfire_setvalue(XFIRE_STATUS, "Connecting");
-                xfire_setvalue(XFIRE_NICKNAME, "-");
-                xfire_setvalue(XFIRE_ROOM, "-");
-            case HWNewNet::InLobby: // In lobby
-                xfire_setvalue(XFIRE_STATUS, "Online");
-                xfire_setvalue(XFIRE_NICKNAME, hwnet->getNick().toAscii());
-                xfire_setvalue(XFIRE_ROOM, "In game lobby");
-                break;
-            case HWNewNet::InRoom: // In room
-                xfire_setvalue(XFIRE_STATUS, "Online");
-                xfire_setvalue(XFIRE_NICKNAME, hwnet->getNick().toAscii());
-                xfire_setvalue(XFIRE_ROOM, (hwnet->getRoom() + " (waiting for players)").toAscii());
-                break;
-            case HWNewNet::InGame: // In game
-                xfire_setvalue(XFIRE_STATUS, "Online");
-                xfire_setvalue(XFIRE_NICKNAME, hwnet->getNick().toAscii());
-                xfire_setvalue(XFIRE_ROOM, (hwnet->getRoom() + " (playing or spectating)").toAscii());
-                break;
-            default:
-                break;
-        }
-    }
-    else
-    {
-        xfire_setvalue(XFIRE_STATUS, "Offline");
-        xfire_setvalue(XFIRE_NICKNAME, "-");
-        xfire_setvalue(XFIRE_ROOM, "-");
-        xfire_setvalue(XFIRE_SERVER, "-");
-    }
-    xfire_update();
-}
-#endif
-
 void HWForm::onFrontendFullscreen(bool value)
 {
     if (value)
         setWindowState(windowState() | Qt::WindowFullScreen);
     else
     {
-        setWindowState(windowState() & static_cast<int>(!Qt::WindowFullScreen));
+        setWindowState(windowState() & ~Qt::WindowFullScreen);
     }
 }
 
@@ -431,6 +411,7 @@
 
 void HWForm::CustomizePalettes()
 {
+    // Scroll bar widget palette
     QList<QScrollBar *> allSBars = findChildren<QScrollBar *>();
     QPalette pal = palette();
     pal.setColor(QPalette::WindowText, QColor(0xff, 0xcc, 0x00));
@@ -440,6 +421,11 @@
 
     for (int i = 0; i < allSBars.size(); ++i)
         allSBars.at(i)->setPalette(pal);
+
+    // Set default hyperlink color
+    QPalette appPal = qApp->palette();
+    appPal.setColor(QPalette::Link, QColor(0xff, 0xff, 0x6e));
+    qApp->setPalette(appPal);
 }
 
 void HWForm::UpdateWeapons()
@@ -467,53 +453,155 @@
     }
 }
 
+void HWForm::AddWeapons(QString weaponsName, QString ammo)
+{
+    QVector<QComboBox*> combos;
+    combos.push_back(ui.pageOptions->WeaponsName);
+    combos.push_back(ui.pageMultiplayer->gameCFG->WeaponsName);
+    combos.push_back(ui.pageNetGame->pGameCFG->WeaponsName);
+    combos.push_back(ui.pageSelectWeapon->selectWeaponSet);
+
+    QStringList names = ui.pageSelectWeapon->pWeapons->getWeaponNames();
+
+    for(QVector<QComboBox*>::iterator it = combos.begin(); it != combos.end(); ++it)
+    {
+        (*it)->addItem(weaponsName, QVariant(ammo));
+    }
+    ui.pageSelectWeapon->selectWeaponSet->setCurrentIndex(ui.pageSelectWeapon->selectWeaponSet->count()-1);
+}
+
+void HWForm::DeleteWeapons(QString weaponsName)
+{
+    QVector<QComboBox*> combos;
+    combos.push_back(ui.pageOptions->WeaponsName);
+    combos.push_back(ui.pageMultiplayer->gameCFG->WeaponsName);
+    combos.push_back(ui.pageNetGame->pGameCFG->WeaponsName);
+    combos.push_back(ui.pageSelectWeapon->selectWeaponSet);
+
+    QStringList names = ui.pageSelectWeapon->pWeapons->getWeaponNames();
+
+    for(QVector<QComboBox*>::iterator it = combos.begin(); it != combos.end(); ++it)
+    {
+        int pos = (*it)->findText(weaponsName);
+        if (pos != -1)
+        {
+            (*it)->removeItem(pos);
+        }
+    }
+    ui.pageSelectWeapon->pWeapons->deletionDone();
+}
+
+void HWForm::EditWeapons(QString oldWeaponsName, QString newWeaponsName, QString ammo)
+{
+    QVector<QComboBox*> combos;
+    combos.push_back(ui.pageOptions->WeaponsName);
+    combos.push_back(ui.pageMultiplayer->gameCFG->WeaponsName);
+    combos.push_back(ui.pageNetGame->pGameCFG->WeaponsName);
+    combos.push_back(ui.pageSelectWeapon->selectWeaponSet);
+
+    QStringList names = ui.pageSelectWeapon->pWeapons->getWeaponNames();
+
+    for(QVector<QComboBox*>::iterator it = combos.begin(); it != combos.end(); ++it)
+    {
+        int pos = (*it)->findText(oldWeaponsName);
+        (*it)->setItemText(pos, newWeaponsName);
+        (*it)->setItemData(pos, ammo);
+    }
+}
+
 void HWForm::UpdateTeamsLists()
 {
     QStringList teamslist = config->GetTeamsList();
 
     if(teamslist.empty())
     {
-        QString currentNickName = config->value("net/nick",tr("Guest")+QString("%1").arg(rand())).toString().toUtf8();
+        QString currentNickName = config->value("net/nick",tr("Guest")+QString("%1").arg(rand())).toString();
         QString teamName;
+        int firstHumanTeam = 1;
+        int lastHumanTeam = 2;
 
+        // Default team
         if (currentNickName.isEmpty())
         {
-            teamName = tr("DefaultTeam");
+            teamName = tr("Team 1");
+            firstHumanTeam++;
         }
         else
         {
             teamName = tr("%1's Team").arg(currentNickName);
+            lastHumanTeam--;
         }
 
         HWTeam defaultTeam(teamName);
+        // Randomize fort and grave for greater variety by default.
+        // But we exclude DLC graves and forts to not have desyncing teams by default
+        // TODO: Remove DLC filtering when it isn't neccessary anymore
+        HWNamegen::teamRandomGrave(defaultTeam, false);
+        HWNamegen::teamRandomFort(defaultTeam, false);
         defaultTeam.saveToFile();
         teamslist.push_back(teamName);
+
+        // Add additional default teams
+
+        // More human teams to allow local multiplayer instantly
+        for(int i=firstHumanTeam; i<=lastHumanTeam; i++)
+        {
+            //: Default team name
+            teamName = tr("Team %1").arg(i);
+            HWTeam numberTeam(teamName);
+            HWNamegen::teamRandomGrave(numberTeam, false);
+            HWNamegen::teamRandomFort(numberTeam, false);
+            numberTeam.saveToFile();
+            teamslist.push_back(teamName);
+        }
+        // Add 2 default CPU teams
+        for(int i=1; i<=5; i=i+2)
+        {
+            //: Default computer team name
+            teamName = tr("Computer %1").arg(i);
+            HWTeam numberTeam(teamName);
+            HWNamegen::teamRandomGrave(numberTeam, false);
+            HWNamegen::teamRandomFort(numberTeam, false);
+            numberTeam.setDifficulty(6-i);
+            numberTeam.saveToFile();
+            teamslist.push_back(teamName);
+        }
     }
 
     ui.pageOptions->CBTeamName->clear();
     ui.pageOptions->CBTeamName->addItems(teamslist);
     ui.pageCampaign->CBTeam->clear();
-    ui.pageCampaign->CBTeam->addItems(teamslist);
+    /* Only show human teams in campaign page */
+    for(int i=0; i<teamslist.length(); i++)
+    {
+        HWTeam testTeam = HWTeam(teamslist[i]);
+        testTeam.loadFromFile();
+        if(testTeam.difficulty() == 0)
+        {
+            ui.pageCampaign->CBTeam->addItem(teamslist[i]);
+        }
+    }
 }
 
-void HWForm::GoToSelectNewWeapon()
+void HWForm::GoToNewWeapons()
 {
     ui.pageSelectWeapon->pWeapons->newWeaponsName();
     GoToPage(ID_PAGE_SELECTWEAPON);
 }
 
-void HWForm::GoToSelectWeapon()
+void HWForm::GoToEditWeapons()
 {
     ui.pageSelectWeapon->selectWeaponSet->setCurrentIndex(ui.pageOptions->WeaponsName->currentIndex());
     GoToPage(ID_PAGE_SELECTWEAPON);
 }
 
-void HWForm::GoToSelectWeaponSet(int index)
+void HWForm::GoToWeapons(int index)
 {
     ui.pageSelectWeapon->selectWeaponSet->setCurrentIndex(index);
     GoToPage(ID_PAGE_SELECTWEAPON);
 }
 
+
 void HWForm::GoToSaves()
 {
     ui.pagePlayDemo->FillFromDir(PagePlayDemo::RT_Save);
@@ -594,10 +682,6 @@
 
 void HWForm::OnPageShown(quint8 id, quint8 lastid)
 {
-#ifdef USE_XFIRE
-    updateXfire();
-#endif
-
 #ifdef QT_DEBUG
     qDebug("Leaving %s, entering %s", qPrintable(stringifyPageId(lastid)), qPrintable(stringifyPageId(id)));
 #endif
@@ -954,7 +1038,16 @@
 
 void HWForm::NewTeam()
 {
-    ui.pageEditTeam->createTeam(QLineEdit::tr("unnamed"), playerHash);
+    QString teamName = QLineEdit::tr("unnamed");
+    QStringList teamslist = config->GetTeamsList();
+    if(teamslist.contains(teamName))
+    {
+        //name already used -> look for an appropriate name:
+        int i=2;
+        while(teamslist.contains(teamName = QLineEdit::tr("unnamed (%1)").arg(i++)));
+    }
+
+    ui.pageEditTeam->createTeam(teamName, playerHash);
     UpdateTeamsLists();
     GoToPage(ID_PAGE_SETUP_TEAM);
 }
@@ -1205,7 +1298,7 @@
     {
         case ID_PAGE_INGAME:
             MessageDialog::ShowErrorMessage(errmsg, this);
-            // no break
+            /* fallthrough */
         case ID_PAGE_NETGAME:
             ui.pageNetGame->displayError(errmsg);
             break;
@@ -1300,6 +1393,8 @@
 // chat widget actions
     connect(ui.pageNetGame->chatWidget, SIGNAL(kick(const QString&)),
             hwnet, SLOT(kickPlayer(const QString&)));
+    connect(ui.pageNetGame->chatWidget, SIGNAL(delegate(const QString&)),
+            hwnet, SLOT(delegateToPlayer(const QString&)));
     connect(ui.pageNetGame->chatWidget, SIGNAL(ban(const QString&)),
             hwnet, SLOT(banPlayer(const QString&)));
     connect(ui.pageNetGame->chatWidget, SIGNAL(info(const QString&)),
@@ -1433,11 +1528,11 @@
                 pwDialog->lePassword->setFocus();
             }
 
-            //if dialog close, create an error message
+            //if dialog aborted, return failure
             if (pwDialog->exec() != QDialog::Accepted) {
                 delete pwDialog;
                 GoBack();
-                break;
+                return 1;
             }
 
             //set nick and pass from the dialog
@@ -1607,6 +1702,14 @@
 
 void HWForm::StartMPGame()
 {
+    int numHogs = ui.pageMultiplayer->teamsSelect->getNumHedgehogs();
+    /* Don't allow to start game with >48 hogs.
+    TODO: Remove this as soon the engine supports more hogs. */
+    if(numHogs > 48)
+    {
+        MessageDialog::ShowErrorMessage(QMessageBox::tr("Sorry, Hedgewars can't be played with more than 48 hedgehogs. Please try again with fewer hedgehogs.\n\nCurrent number of hedgehogs: %1").arg(numHogs), this);
+        return;
+    }
     QString ammo;
     ammo = ui.pageMultiplayer->gameCFG->WeaponsName->itemData(
                ui.pageMultiplayer->gameCFG->WeaponsName->currentIndex()
@@ -1721,17 +1824,17 @@
     ui.pageVideos->startEncoding(record);
 }
 
-void HWForm::startTraining(const QString & scriptName)
+void HWForm::startTraining(const QString & scriptName, const QString & subFolder)
 {
     CreateGame(0, 0, 0);
 
-    game->StartTraining(scriptName);
+    game->StartTraining(scriptName, subFolder);
 }
 
 void HWForm::StartCampaign()
 {
     CreateGame(0, 0, 0);
-    QString camp = ui.pageCampaign->CBCampaign->currentText().replace(QString(" "),QString("_"));
+    QString camp = ui.pageCampaign->CBCampaign->itemData(ui.pageCampaign->CBCampaign->currentIndex()).toString();
     QString miss = campaignMissionInfo[ui.pageCampaign->CBMission->currentIndex()].script;
     QString campTeam = ui.pageCampaign->CBTeam->currentText();
     game->StartCampaign(camp, miss, campTeam);
@@ -1762,11 +1865,8 @@
 
 void HWForm::closeEvent(QCloseEvent *event)
 {
-#ifdef USE_XFIRE
-    xfire_free();
-#endif
     config->SaveOptions();
-#if VIDEOREC
+#ifdef VIDEOREC
     config->SaveVideosOptions();
 #endif
     event->accept();
@@ -1893,9 +1993,12 @@
                               );
 
     unsigned int n = entries.count();
+
     for(unsigned int i = 0; i < n; i++)
     {
-        ui.pageCampaign->CBCampaign->addItem(QString(entries[i]).replace(QString("_"),QString(" ")), QString(entries[i]).replace(QString("_"),QString(" ")));
+        const QString & campaignName = entries[i];
+        QString tName = team.name();
+        ui.pageCampaign->CBCampaign->addItem(getRealCampName(campaignName), campaignName);
     }
 }
 
@@ -1903,7 +2006,7 @@
 {
     Q_UNUSED(index);
     HWTeam team(ui.pageCampaign->CBTeam->currentText());
-    QString campaignName = ui.pageCampaign->CBCampaign->currentText().replace(QString(" "),QString("_"));
+    QString campaignName = ui.pageCampaign->CBCampaign->itemData(ui.pageCampaign->CBCampaign->currentIndex()).toString();
     QString tName = team.name();
 
     campaignMissionInfo = getCampMissionList(campaignName,tName);
@@ -1911,14 +2014,42 @@
 
     for(int i=0;i<campaignMissionInfo.size();i++)
     {
-        ui.pageCampaign->CBMission->addItem(QString(campaignMissionInfo[i].name), QString(campaignMissionInfo[i].name));
+        ui.pageCampaign->CBMission->addItem(QString(campaignMissionInfo[i].realName), QString(campaignMissionInfo[i].name));
+        if(isMissionWon(campaignName, i, tName))
+            ui.pageCampaign->CBMission->setItemIcon(i, finishedIcon);
+        else
+            ui.pageCampaign->CBMission->setItemIcon(i, notFinishedIcon);
+    }
+}
+
+void HWForm::UpdateCampaignPageTeam(int index)
+{
+    Q_UNUSED(index);
+    HWTeam team(ui.pageCampaign->CBTeam->currentText());
+    QString tName = team.name();
+
+    QStringList entries = DataManager::instance().entryList(
+                                  "Missions/Campaign",
+                                  QDir::Dirs,
+                                  QStringList("[^\\.]*")
+                              );
+
+    unsigned int n = entries.count();
+
+    for(unsigned int i = 0; i < n; i++)
+    {
+        QString campaignName = QString(entries[i]).replace(QString(" "),QString("_"));
+        if(isCampWon(campaignName, tName))
+            ui.pageCampaign->CBCampaign->setItemIcon(i, finishedIcon);
+        else
+            ui.pageCampaign->CBCampaign->setItemIcon(i, notFinishedIcon);
     }
 }
 
 void HWForm::UpdateCampaignPageMission(int index)
 {
     // update thumbnail and description
-    QString campaignName = ui.pageCampaign->CBCampaign->currentText().replace(QString(" "),QString("_"));
+    QString campaignName = ui.pageCampaign->CBCampaign->itemData(ui.pageCampaign->CBCampaign->currentIndex()).toString();
     // when campaign changes the UpdateCampaignPageMission is triggered with wrong values
     // this will cause segfault. This check prevents illegal memory reads
     if(index > -1 && index < campaignMissionInfo.count()) {
@@ -1936,12 +2067,20 @@
     UpdateCampaignPage(0);
     for(int i=0;i<ui.pageCampaign->CBMission->count();i++)
     {
-        if (ui.pageCampaign->CBMission->itemText(i)==missionTitle)
+        if (ui.pageCampaign->CBMission->itemData(i)==missionTitle)
         {
             ui.pageCampaign->CBMission->setCurrentIndex(i);
             break;
         }
     }
+    int i = ui.pageCampaign->CBCampaign->currentIndex();
+    QString campaignName = ui.pageCampaign->CBCampaign->itemData(i).toString();
+    HWTeam team(ui.pageCampaign->CBTeam->currentText());
+    QString tName = team.name();
+    if(isCampWon(campaignName, tName))
+        ui.pageCampaign->CBCampaign->setItemIcon(i, finishedIcon);
+    else
+        ui.pageCampaign->CBCampaign->setItemIcon(i, notFinishedIcon);
 }
 
 // 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]
@@ -2079,7 +2218,7 @@
 
     switch(lastGameType) {
     case gtTraining:
-        game->StartTraining(lastGameStartArgs.at(0).toString());
+        game->StartTraining(lastGameStartArgs.at(0).toString(), lastTrainingSubFolder);
         break;
     case gtQLocal:
         game->StartQuick();
@@ -2113,11 +2252,27 @@
 {
     QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
 
-    if (reply && (reply->error() == QNetworkReply::NoError)) {
-        FeedbackDialog dialog(this);
-        dialog.exec();
-    } else
-        MessageDialog::ShowErrorMessage(tr("This page requires an internet connection."), this);
+    if (reply) {
+        switch (reply->error()) {
+            case QNetworkReply::NoError:
+                {
+                    FeedbackDialog dialog(this);
+                    dialog.exec();
+                }
+                break;
+            case QNetworkReply::UnknownNetworkError:
+                MessageDialog::ShowFatalMessage(
+                    tr("Unknown network error (possibly missing SSL library)."), this);
+                break;
+            default:
+                MessageDialog::ShowFatalMessage(
+                    QString(tr("This feature requires an Internet connection, but you don't appear to be online (error code: %1).")).arg(reply->error()), this);
+                break;
+        }
+    }
+    else {
+        MessageDialog::ShowFatalMessage(tr("Internal error: Reply object is invalid."), this);
+    }
 }
 
 void HWForm::startGame()
--- a/QTfrontend/hwform.h	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/hwform.h	Sun Dec 17 00:09:24 2017 +0100
@@ -62,7 +62,6 @@
         HWForm(QWidget *parent = 0, QString styleSheet = "");
         Ui_HWForm ui;
         static GameUIConfig * config;
-        void updateXfire();
         void exit();
         void setButtonDescription(QString desc);
         void backDescription();
@@ -75,9 +74,9 @@
         void GoToSaves();
         void GoToDemos();
         void GoToNet();
-        void GoToSelectWeapon();
-        void GoToSelectWeaponSet(int index);
-        void GoToSelectNewWeapon();
+        void GoToEditWeapons();
+        void GoToNewWeapons();
+        void GoToWeapons(int index);
         void GoToScheme(int index);
         void GoToEditScheme();
         void GoToNewScheme();
@@ -96,7 +95,7 @@
         void DeleteWeaponSet();
         void SimpleGame();
         void PlayDemo();
-        void startTraining(const QString&);
+        void startTraining(const QString&, const QString&);
         void StartCampaign();
         void NetConnect();
         void NetConnectServer(const QString & host, quint16 port);
@@ -124,10 +123,14 @@
         void GetRecord(RecordType type, const QByteArray & record);
         void CreateNetGame();
         void UpdateWeapons();
+        void DeleteWeapons(QString weaponsName);
+        void AddWeapons(QString weaponsName, QString ammo);
+        void EditWeapons(QString oldWeaponsName, QString newWeaponsName, QString ammo);
         void onFrontendFullscreen(bool value);
         void onFrontendEffects(bool value);
         void Music(bool checked);
         void UpdateCampaignPage(int index);
+        void UpdateCampaignPageTeam(int index);
         void UpdateCampaignPageProgress(int index);
         void UpdateCampaignPageMission(int index);
         void InitCampaignPage();
--- a/QTfrontend/main.cpp	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/main.cpp	Sun Dec 17 00:09:24 2017 +0100
@@ -44,6 +44,11 @@
 #include <Shlobj.h>
 #elif defined __APPLE__
 #include "CocoaInitializer.h"
+
+#endif
+
+#ifdef Q_OS_WIN
+#include <QSplashScreen>
 #endif
 
 // Program resources
@@ -162,9 +167,8 @@
     HWApplication app(argc, argv);
     app.setAttribute(Qt::AA_DontShowIconsInMenus,false);
 
-    // file engine and splash. to be initialized later
+    // file engine, to be initialized later
     engine = NULL;
-    QLabel *splash = NULL;
 
     // parse arguments
 
@@ -241,17 +245,13 @@
 
     // end of parameter parsing
 
-#if defined Q_OS_WIN
-    QPixmap pixmap(":res/splash.png");
-    splash = new QLabel(0, Qt::FramelessWindowHint|Qt::WindowStaysOnTopHint);
-    splash->setAttribute(Qt::WA_TranslucentBackground);
-    const QRect deskSize = HWApplication::desktop()->screenGeometry(-1);
-    QPoint splashCenter = QPoint( (deskSize.width() - pixmap.width())/2,
-                                  (deskSize.height() - pixmap.height())/2 );
-    splash->move(splashCenter);
-    splash->setPixmap(pixmap);
-    splash->show();
+
+#ifdef Q_OS_WIN
+    QPixmap pixmap(":/res/splash.png");
+    QSplashScreen splash(pixmap);
+    splash.show();
 #endif
+
     app.setStyle(new QPlastiqueStyle());
 
     QDateTime now = QDateTime::currentDateTime();
@@ -346,7 +346,8 @@
     }
 
 #ifdef _WIN32
-    // Win32 registry setup (used for xfire detection etc. - don't set it if we're running in "portable" mode with a custom config dir)
+    // Win32 registry setup (used for external software detection etc.
+    // don't set it if running in "portable" mode with a custom config dir)
     if(!custom_config)
     {
         QSettings registry_hklm("HKEY_LOCAL_MACHINE", QSettings::NativeFormat);
@@ -392,9 +393,11 @@
     qWarning("Starting Hedgewars %s-r%d (%s)", qPrintable(*cVersionString), cRevisionString->toInt(), qPrintable(*cHashString));
 
     app.form = new HWForm(NULL, style);
+#ifdef Q_OS_WIN
+    splash.finish(app.form);
+#endif
     app.form->show();
-    if(splash)
-        splash->close();
+
     if (app.urlString)
         app.fakeEvent();
     return app.exec();
--- a/QTfrontend/model/GameStyleModel.cpp	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/model/GameStyleModel.cpp	Sun Dec 17 00:09:24 2017 +0100
@@ -32,11 +32,18 @@
 {
     beginResetModel();
 
+    QIcon dlcIcon;
+    dlcIcon.addFile(":/res/dlcMarker.png", QSize(), QIcon::Normal, QIcon::On);
+    dlcIcon.addFile(":/res/dlcMarkerSelected.png", QSize(), QIcon::Selected, QIcon::On);
+    QPixmap emptySpace = QPixmap(7, 15);
+    emptySpace.fill(QColor(0, 0, 0, 0));
+    QIcon notDlcIcon = QIcon(emptySpace);
+
     // empty list, so that we can (re)fill it
     QStandardItemModel::clear();
 
     QList<QStandardItem * > items;
-    items.append(new QStandardItem("Normal"));
+    items.append(new QStandardItem(notDlcIcon, "Normal"));
 
     // define a separator item
     QStandardItem * separator = new QStandardItem("---");
@@ -82,7 +89,11 @@
         QString scriptPath = PHYSFS_getRealDir(QString("Scripts/Multiplayer/%1.lua").arg(script).toLocal8Bit().data());
         bool isDLC = !scriptPath.startsWith(datadir->absolutePath());
 
-        QStandardItem * item = new QStandardItem((isDLC ? "*" : "") + name);
+        QStandardItem * item;
+        if (isDLC)
+            item = new QStandardItem(dlcIcon, name);
+        else
+            item = new QStandardItem(notDlcIcon, name);
 
         item->setData(script, ScriptRole);
         item->setData(scheme, SchemeRole);
--- a/QTfrontend/model/MapModel.cpp	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/model/MapModel.cpp	Sun Dec 17 00:09:24 2017 +0100
@@ -80,6 +80,14 @@
     //QList<QStandardItem *> missionMaps;
     QList<QStandardItem *> mapList;
 
+
+    QIcon dlcIcon;
+    dlcIcon.addFile(":/res/dlcMarker.png", QSize(), QIcon::Normal, QIcon::On);
+    dlcIcon.addFile(":/res/dlcMarkerSelected.png", QSize(), QIcon::Selected, QIcon::On);
+    QPixmap emptySpace = QPixmap(7, 15);
+    emptySpace.fill(QColor(0, 0, 0, 0));
+    QIcon notDlcIcon = QIcon(emptySpace);
+
     // add mission/static maps to lists
     foreach (QString map, maps)
     {
@@ -119,10 +127,22 @@
             // load description (if applicable)
             if (isMission)
             {
-                QString locale = HWApplication::keyboardInputLocale().name();
+                // get locale
+                QSettings settings(datamgr.settingsFileName(), QSettings::IniFormat);
+                QString locale = settings.value("misc/locale", "").toString();
+                if (locale.isEmpty())
+                    locale = QLocale::system().name();
 
                 QSettings descSettings(QString("physfs://Maps/%1/desc.txt").arg(map), QSettings::IniFormat);
-                desc = descSettings.value(locale, QString()).toString().replace("|", "\n").replace("\\,", ",");
+                descSettings.setIniCodec("UTF-8");
+                desc = descSettings.value(locale, QString()).toString();
+                // If not found, try with lanague-only code
+                if (desc.isEmpty())
+                {
+                    QString localeSimple = locale.remove(QRegExp("_.*$"));
+                    desc = descSettings.value(localeSimple, QString()).toString();
+                }
+                desc = desc.replace("_n", "\n").replace("_c", ",").replace("__", "_");
             }
 
             // detect if map is dlc
@@ -151,9 +171,15 @@
             // caption
             caption = map;
 
+            QIcon icon;
+            if (dlc)
+                icon = dlcIcon;
+            else
+                icon = notDlcIcon;
+
             // we know everything there is about the map, let's get am item for it
             QStandardItem * item = MapModel::infoToItem(
-                QIcon(), caption, type, map, theme, limit, scheme, weapons, desc, dlc);
+                icon, caption, type, map, theme, limit, scheme, weapons, desc, dlc);
 
             // append item to the list
             mapList.append(item);
@@ -213,7 +239,7 @@
     QString desc,
     bool dlc)
 {
-    QStandardItem * item = new QStandardItem(icon, (dlc ? "*" : "") + caption);
+    QStandardItem * item = new QStandardItem(icon, caption);
     MapInfo mapInfo;
     QVariant qvar(QVariant::UserType);
 
--- a/QTfrontend/model/ammoSchemeModel.cpp	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/model/ammoSchemeModel.cpp	Sun Dec 17 00:09:24 2017 +0100
@@ -81,11 +81,11 @@
                          << "Minefield"
                          << "Barrel Mayhem"
                          << "Tunnel Hogs"
-                         << "Fort Mode"
                          << "Timeless"
                          << "Thinking with Portals"
                          << "King Mode"
-						 << "Construction Mode"
+                         << "Construction Mode"
+                         << "HedgeEditor"
                          ;
 
     numberOfDefaultSchemes = predefSchemesNames.size();
@@ -222,11 +222,11 @@
             << QVariant(0)             // mines number   32
             << QVariant(0)             // mine dud pct   33
             << QVariant(0)             // explosives     34
-            << QVariant(8)             // air mines      35
+            << QVariant(0)             // air mines      35
             << QVariant(0)             // health case pct 36
             << QVariant(25)            // health case amt 37
-            << QVariant(47)            // water rise amt 38
-            << QVariant(5)             // health dec amt 39
+            << QVariant(0)             // water rise amt 38
+            << QVariant(0)             // health dec amt 39
             << QVariant(100)           // rope modfier   40
             << QVariant(100)           // get away time  41
             << QVariant(0)             // world edge     42
@@ -425,57 +425,9 @@
             << QVariant()              // scriptparam    43
             ;
 
-    QList<QVariant> forts;
-    forts
-            << predefSchemesNames[7]   // name           0
-            << QVariant(true)          // fortsmode      1
-            << QVariant(true)          // team divide    2
-            << QVariant(false)         // solid land     3
-            << QVariant(false)         // border         4
-            << QVariant(false)         // low gravity    5
-            << QVariant(false)         // laser sight    6
-            << QVariant(false)         // invulnerable   7
-            << QVariant(false)         // reset health   8
-            << QVariant(false)         // vampiric       9
-            << QVariant(false)         // karma          10
-            << QVariant(false)         // artillery      11
-            << QVariant(true)          // random order   12
-            << QVariant(false)         // king           13
-            << QVariant(false)         // place hog      14
-            << QVariant(false)         // shared ammo    15
-            << QVariant(false)         // disable girders 16
-            << QVariant(false)         // disable land objects 17
-            << QVariant(false)         // AI survival    18
-            << QVariant(false)         // inf. attack    19
-            << QVariant(false)         // reset weps     20
-            << QVariant(false)         // per hog ammo   21
-            << QVariant(false)         // no wind        22
-            << QVariant(false)         // more wind      23
-            << QVariant(false)         // tag team       24
-            << QVariant(false)         // bottom border  25
-            << QVariant(100)           // damage modfier 26
-            << QVariant(45)            // turn time      27
-            << QVariant(100)           // init health    28
-            << QVariant(15)            // sudden death   29
-            << QVariant(5)             // case prob      30
-            << QVariant(3)             // mines time     31
-            << QVariant(0)             // mines number   32
-            << QVariant(0)             // mine dud pct   33
-            << QVariant(0)             // explosives     34
-            << QVariant(0)             // air mines      35
-            << QVariant(35)            // health case pct 36
-            << QVariant(25)            // health case amt 37
-            << QVariant(47)            // water rise amt 38
-            << QVariant(5)             // health dec amt 39
-            << QVariant(100)           // rope modfier   40
-            << QVariant(100)           // get away time  41
-            << QVariant(0)             // world edge     42
-            << QVariant()              // scriptparam    43
-            ;
-
     QList<QVariant> timeless;
     timeless
-            << predefSchemesNames[8]   // name           0
+            << predefSchemesNames[7]   // name           0
             << QVariant(false)         // fortsmode      1
             << QVariant(false)         // team divide    2
             << QVariant(false)         // solid land     3
@@ -523,7 +475,7 @@
 
     QList<QVariant> thinkingportals;
     thinkingportals
-            << predefSchemesNames[9]   // name           0
+            << predefSchemesNames[8]   // name           0
             << QVariant(false)         // fortsmode      1
             << QVariant(false)         // team divide    2
             << QVariant(false)         // solid land     3
@@ -571,7 +523,7 @@
 
     QList<QVariant> kingmode;
     kingmode
-            << predefSchemesNames[10]  // name           0
+            << predefSchemesNames[9]  // name           0
             << QVariant(false)         // fortsmode      1
             << QVariant(false)         // team divide    2
             << QVariant(false)         // solid land     3
@@ -619,7 +571,7 @@
 
 	QList<QVariant> construction;
     construction
-            << predefSchemesNames[11]  // name           0
+            << predefSchemesNames[10]  // name           0
             << QVariant(false)         // fortsmode      1
             << QVariant(false)         // team divide    2
             << QVariant(false)         // solid land     3
@@ -664,6 +616,56 @@
             << QVariant(0)             // world edge     42
             << QVariant()              // scriptparam    43
             ;
+
+	QList<QVariant> hedgeeditor;
+    hedgeeditor
+            << predefSchemesNames[11]  // name           0
+            << QVariant(false)         // fortsmode      1
+            << QVariant(false)         // team divide    2
+            << QVariant(false)         // solid land     3
+            << QVariant(false)         // border         4
+            << QVariant(false)         // low gravity    5
+            << QVariant(false)         // laser sight    6
+            << QVariant(false)         // invulnerable   7
+            << QVariant(false)         // reset health   8
+            << QVariant(false)         // vampiric       9
+            << QVariant(false)         // karma          10
+            << QVariant(false)         // artillery      11
+            << QVariant(false)         // random order   12
+            << QVariant(false)         // king           13
+            << QVariant(false)         // place hog      14
+            << QVariant(false)         // shared ammo    15
+            << QVariant(false)         // disable girders 16
+            << QVariant(false)         // disable land objects 17
+            << QVariant(false)         // AI survival    18
+            << QVariant(false)         // inf. attack    19
+            << QVariant(false)         // reset weps     20
+            << QVariant(true)          // per hog ammo   21
+            << QVariant(false)         // no wind        22
+            << QVariant(false)         // more wind      23
+            << QVariant(false)         // tag team       24
+            << QVariant(false)         // bottom border  25
+            << QVariant(100)           // damage modfier 26
+            << QVariant(9999)          // turn time      27
+            << QVariant(100)           // init health    28
+            << QVariant(50)            // sudden death   29
+            << QVariant(5)             // case prob      30
+            << QVariant(3)             // mines time     31
+            << QVariant(0)             // mines number   32
+            << QVariant(0)             // mine dud pct   33
+            << QVariant(0)             // explosives     34
+            << QVariant(0)             // air mines      35
+            << QVariant(35)            // health case pct 36
+            << QVariant(25)            // health case amt 37
+            << QVariant(0)            // water rise amt 38
+            << QVariant(0)             // health dec amt 39
+            << QVariant(100)           // rope modfier   40
+            << QVariant(100)           // get away time  41
+            << QVariant(0)             // world edge     42
+            << QVariant()              // scriptparam    43
+            ;
+			
+ 
 			
     schemes.append(defaultScheme);
     schemes.append(proMode);
@@ -672,11 +674,11 @@
     schemes.append(minefield);
     schemes.append(barrelmayhem);
     schemes.append(tunnelhogs);
-    schemes.append(forts);
     schemes.append(timeless);
     schemes.append(thinkingportals);
     schemes.append(kingmode);
-	schemes.append(construction);
+    schemes.append(construction);
+    schemes.append(hedgeeditor);
 
 
     int size = fileConfig.beginReadArray("schemes");
@@ -722,6 +724,18 @@
         return defaultScheme.size();
 }
 
+bool AmmoSchemeModel::hasScheme(QString name)
+{
+    for(int i=0; i<schemes.size(); i++)
+    {
+        if(schemes[i][0] == name)
+        {
+            return true;
+        }
+    }
+    return false;
+}
+
 Qt::ItemFlags AmmoSchemeModel::flags(const QModelIndex & index) const
 {
     Q_UNUSED(index);
@@ -755,13 +769,29 @@
     if (row == -1)
     {
         QList<QVariant> newScheme = defaultScheme;
-        newScheme[0] = QVariant(tr("New"));
+
+        QString newName = tr("New");
+        if(hasScheme(newName))
+        {
+            //name already used -> look for an appropriate name:
+            int i=2;
+            while(hasScheme(newName = tr("New (%1)").arg(i++))) ;
+        }
+        newScheme[0] = QVariant(newName);
         schemes.insert(schemes.size(), newScheme);
     }
     else
     {
         QList<QVariant> newScheme = schemes[row];
-        newScheme[0] = QVariant(tr("Copy of %1").arg(newScheme[0].toString()));
+        QString oldName = newScheme[0].toString();
+        QString newName = tr("Copy of %1").arg(oldName);
+        if(hasScheme(newName))
+        {
+            //name already used -> look for an appropriate name:
+            int i=2;
+            while(hasScheme(newName = tr("Copy of %1 (%2)").arg(oldName).arg(i++)));
+        }
+        newScheme[0] = QVariant(newName);
         schemes.insert(schemes.size(), newScheme);
     }
 
--- a/QTfrontend/model/ammoSchemeModel.h	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/model/ammoSchemeModel.h	Sun Dec 17 00:09:24 2017 +0100
@@ -34,6 +34,7 @@
         QVariant headerData(int section, Qt::Orientation orientation, int role) const;
         int rowCount(const QModelIndex & parent) const;
         int columnCount(const QModelIndex & parent) const;
+        bool hasScheme(QString name);
         Qt::ItemFlags flags(const QModelIndex & index) const;
         bool setData(const QModelIndex & index, const QVariant & value, int role = Qt::EditRole);
         bool insertRows(int row, int count, const QModelIndex & parent = QModelIndex());
--- a/QTfrontend/model/roomslistmodel.cpp	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/model/roomslistmodel.cpp	Sun Dec 17 00:09:24 2017 +0100
@@ -32,17 +32,18 @@
     QAbstractTableModel(parent),
     c_nColumns(9)
 {
-    m_headerData =
-    QStringList()
-     << tr("In progress")
-     << tr("Room Name")
-     << tr("C")
-     << tr("T")
-     << tr("Owner")
-     << tr("Map")
-     << tr("Script")
-     << tr("Rules")
-     << tr("Weapons");
+    m_headerData = QStringList();
+    m_headerData << tr("In progress");
+    m_headerData << tr("Room Name");
+    //: Caption of the column for the number of connected clients in the list of rooms
+    m_headerData << tr("C");
+    //: Caption of the column for the number of teams in the list of rooms
+    m_headerData << tr("T");
+    m_headerData << tr("Owner");
+    m_headerData << tr("Map");
+    m_headerData << tr("Script");
+    m_headerData << tr("Rules");
+    m_headerData << tr("Weapons");
 
     m_staticMapModel = DataManager::instance().staticMapModel();
     m_missionMapModel = DataManager::instance().missionMapModel();
--- a/QTfrontend/net/newnetclient.cpp	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/net/newnetclient.cpp	Sun Dec 17 00:09:24 2017 +0100
@@ -1012,6 +1012,11 @@
     RawSendNet(QString("KICK%1%2").arg(delimiter).arg(nick));
 }
 
+void HWNewNet::delegateToPlayer(const QString & nick)
+{
+    RawSendNet(QString("DELEGATE%1%2").arg(delimiter).arg(nick));
+}
+
 void HWNewNet::infoPlayer(const QString & nick)
 {
     RawSendNet(QString("INFO%1%2").arg(delimiter).arg(nick));
--- a/QTfrontend/net/newnetclient.h	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/net/newnetclient.h	Sun Dec 17 00:09:24 2017 +0100
@@ -167,6 +167,7 @@
         void gameFinished(bool correcly);
         void banPlayer(const QString &);
         void kickPlayer(const QString &);
+        void delegateToPlayer(const QString &);
         void infoPlayer(const QString &);
         void followPlayer(const QString &);
         void consoleCommand(const QString &);
--- a/QTfrontend/net/tcpBase.cpp	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/net/tcpBase.cpp	Sun Dec 17 00:09:24 2017 +0100
@@ -188,7 +188,6 @@
 
 void TCPBase::ClientDisconnect()
 {
-    disconnect(IPCSocket, SIGNAL(readyRead()), this, SLOT(ClientRead()));
     onClientDisconnect();
 
     if(!simultaneousRun())
@@ -200,8 +199,11 @@
         emit isReadyNow();
     }
 
-    IPCSocket->deleteLater();
-    IPCSocket = NULL;
+    if(IPCSocket) {
+      disconnect(IPCSocket, SIGNAL(readyRead()), this, SLOT(ClientRead()));
+      IPCSocket->deleteLater();
+      IPCSocket = NULL;
+    }
 
     deleteLater();
 }
@@ -224,7 +226,8 @@
 {
     Q_UNUSED(exitStatus);
 
-    ClientDisconnect();
+    if(!m_connected)
+      ClientDisconnect();
 
     // show error message if there was an error that was not an engine's
     // fatal error - because that one already sent a info via IPC
@@ -240,16 +243,6 @@
             .arg("Feedback"));
 
     }
-
-    // cleanup up
-    if (IPCSocket)
-    {
-        IPCSocket->close();
-        IPCSocket->deleteLater();
-    }
-
-    // plot suicide
-    deleteLater();
 }
 
 void TCPBase::tcpServerReady()
Binary file QTfrontend/res/Multiplayer.png has changed
Binary file QTfrontend/res/NetworkPlay.png has changed
Binary file QTfrontend/res/Palette.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/res/Palette.svg	Sun Dec 17 00:09:24 2017 +0100
@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   height="48"
+   width="48"
+   version="1.1"
+   viewBox="0 0 45 45"
+   id="svg20305">
+  <defs
+     id="defs20307" />
+  <g
+     transform="matrix(0.59479444,0.10227643,-0.10227643,0.59479444,1.7060659,-7.8021394)"
+     id="g21200">
+    <path
+       d="M 56.964,9.6436 C 52.703,6.7734 45.988,6.4849 43.088,10.98 39.455,16.782 39.651,24.598 34.789,29.67 28.82,36.548 19.661,39.993 14.663,47.835 11.227,52.538 8.856,59.176 11.79,65.011 c 3.235,6.347 10.016,9.623 16.219,12.145 9.557,3.543 20.641,2.117 28.235,-4.201 C 66.569,65.055 73.162,52.531 74.223,39.264 74.44,32.316 72.524,25.071 68.406,19.231 65.15,15.43 61.352,12.023 56.964,9.6436 Z"
+       style="fill:#d19153;fill-opacity:1;fill-rule:evenodd;stroke:#482e18;stroke-width:2.63609332;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="path20328" />
+    <path
+       d="M 60.902589,13.329601 C 59.467882,12.218236 57.953793,11.215297 56.360321,10.352053 52.235298,7.573447 45.734587,7.2941543 42.927132,11.646096 c -3.516095,5.616846 -3.324414,13.183421 -8.032226,18.094531 -5.778517,6.657541 -14.646201,9.992605 -19.484705,17.585318 -3.32635,4.551949 -5.6242038,10.978117 -2.783253,16.625942 3.130797,6.145422 9.697337,9.316878 15.702386,11.757428 9.252016,3.429936 19.983272,2.05041 27.334931,-4.065969 9.995508,-7.647895 16.378112,-19.772228 17.405253,-32.614882 0.210075,-6.726276 -1.646717,-13.742009 -5.632336,-19.395643 -1.971027,-2.299209 -4.143416,-4.4503 -6.534593,-6.30322 z m -1.314663,0.85579 c 1.879058,1.446323 3.656468,3.027211 5.252844,4.793003 4.09598,4.831727 6.092178,11.179479 6.199635,17.324901 C 70.84582,47.946489 65.493261,58.975915 57.218046,66.589927 51.850967,72.150623 43.857465,74.993898 35.973357,74.09648 31.296524,73.490457 26.762968,71.669484 22.638914,69.255072 18.98535,67.122375 15.365669,63.916067 14.488582,59.595492 13.78575,55.124861 15.735478,50.84204 18.26122,47.441147 23.365947,40.622904 31.318789,36.865755 37.027605,30.660311 c 3.675829,-3.908171 4.755247,-9.423367 6.617849,-14.352872 0.819002,-2.368911 1.811292,-5.134738 4.381565,-5.99924 3.290531,-1.1281127 6.845351,0.547937 9.648933,2.473465 0.645714,0.454032 1.286589,0.921619 1.911974,1.403727 z"
+       style="fill:#ae7172;fill-opacity:0.29375;fill-rule:evenodd;stroke-width:0.96808791"
+       id="path21001" />
+    <path
+       d="m 59.890436,13.51037 c -2.769,-2.281 -6.034,-4.2953004 -9.634,-4.3409004 -2.539,-0.1368 -5.058,1.0949004 -6.226,3.3489004 -2.324,3.56 -3.122,7.903 -5.03,11.692 -1.975,4.42 -5.23,8.091 -8.992,11.018 -5.134,4.507 -10.717,8.659 -14.747,14.271 -2.26,3.452 -3.404,7.855 -2.527,12.089 0.8,3.333 3.241,6.044 5.923,8.083 2.203,-1.463 3.734,-3.698 5.635,-5.494 6.587,-6.966 10.155872,-14.523982 18.364872,-19.509982 7.886,-4.97 20.231128,-7.533018 28.993128,-10.807018 -0.806,-7.945 -5.148,-15.63 -11.76,-20.35 z"
+       style="fill:#ffffff;fill-opacity:0.1360634;fill-rule:evenodd"
+       id="path20961" />
+    <g
+       transform="matrix(1.1189191,0,0,1.1189191,23.244443,-19.439177)"
+       id="g4540">
+      <path
+         id="path21032"
+         style="fill:#4980c1;fill-opacity:0.90620871;fill-rule:evenodd"
+         d="M 25.813,60.121 C 36.546,59.159 37.102,68.399 30.81,71.094 18.041,72.25 18.411,63.202 25.813,60.121 Z" />
+      <path
+         id="path21033"
+         style="fill:#000000;fill-opacity:0.44253636;fill-rule:evenodd"
+         d="m 25.872,60.229 c -7.403,3.081 -7.765,12.138 5.004,10.983 6.292,-2.695 5.729,-11.945 -5.004,-10.983 z m 2.253,0.566 c 2.504,-0.233 6.524,2.046 5.221,5.575 -1.895,4.928 -7.369,3.498 -10.772,2.047 -2.983,-2.758 0.482,-7.077 3.183,-7.546 0.788,10e-4 1.582,-0.159 2.368,-0.076 z" />
+      <path
+         id="path21034"
+         style="fill:#ffffff;fill-opacity:0.13342142;fill-rule:evenodd"
+         d="m 23.897,62.344 c -2.172,1.282 -3.454,5.485 -0.508,6.68 4.33,1.123 5.495,-2.816 4.711,-7.9 -1.585,-0.334 -2.845,0.287 -4.203,1.22 z" />
+    </g>
+    <g
+       transform="matrix(1.0747502,0,0,1.0747502,10.652197,-28.766215)"
+       id="g4535">
+      <path
+         id="path21030"
+         style="fill:#20bf00;fill-opacity:0.8982827;fill-rule:evenodd"
+         d="M 43.927,57.271 C 55.041,56.326 55.615,65.395 49.101,68.04 35.879,69.174 36.263,60.294 43.927,57.271 Z" />
+      <path
+         id="path21031"
+         style="fill:#000000;fill-opacity:0.44253636;fill-rule:evenodd"
+         d="m 43.988,57.377 c -7.665,3.023 -8.04,11.912 5.181,10.779 6.515,-2.646 5.932,-11.724 -5.181,-10.779 z m 2.333,0.555 c 2.593,-0.229 6.755,2.008 5.406,5.471 -1.963,4.837 -7.63,3.434 -11.154,2.009 -3.088,-2.706 0.5,-6.945 3.296,-7.405 0.816,0.001 1.639,-0.156 2.452,-0.075 z" />
+      <path
+         id="path21040"
+         style="fill:#ffffff;fill-opacity:0.13333333;fill-rule:evenodd"
+         d="m 42.226,59.205 c -2.249,1.258 -3.577,5.383 -0.526,6.556 4.483,1.103 5.689,-2.764 4.877,-7.754 -1.641,-0.327 -2.945,0.282 -4.351,1.198 z" />
+    </g>
+    <g
+       transform="matrix(1.1403571,0,0,1.1403571,-25.702664,8.2163177)"
+       id="g4530">
+      <path
+         id="path21028"
+         style="fill:#ff0204;fill-opacity:0.90356673;fill-rule:evenodd"
+         d="m 55.349,46.446 c 11.722,-0.846 12.328,7.279 5.457,9.649 -13.945,1.016 -13.541,-6.94 -5.457,-9.649 z" />
+      <path
+         id="path21029"
+         style="fill:#000000;fill-opacity:0.44253636;fill-rule:evenodd"
+         d="m 55.413,46.541 c -8.084,2.709 -8.48,10.673 5.465,9.657 6.871,-2.37 6.257,-10.503 -5.465,-9.657 z m 2.461,0.497 c 2.735,-0.205 7.125,1.799 5.702,4.903 -2.07,4.333 -8.048,3.076 -11.765,1.799 -3.256,-2.425 0.528,-6.222 3.477,-6.635 0.861,0.001 1.728,-0.139 2.586,-0.067 z" />
+      <path
+         id="path21041"
+         style="fill:#ffffff;fill-opacity:0.13474241;fill-rule:evenodd"
+         d="m 53.417,48.109 c -2.372,1.127 -3.773,4.823 -0.555,5.874 4.728,0.988 6,-2.476 5.144,-6.947 -1.731,-0.293 -3.107,0.253 -4.589,1.073 z" />
+    </g>
+    <g
+       transform="matrix(1.0747502,0,0,1.0747502,6.4639824,-44.660848)"
+       id="g4535-3">
+      <path
+         id="path21030-6"
+         style="fill:#ffff04;fill-opacity:0.8982827;fill-rule:evenodd"
+         d="M 43.927,57.271 C 55.041,56.326 55.615,65.395 49.101,68.04 35.879,69.174 36.263,60.294 43.927,57.271 Z" />
+      <path
+         id="path21031-7"
+         style="fill:#000000;fill-opacity:0.44253636;fill-rule:evenodd"
+         d="m 43.988,57.377 c -7.665,3.023 -8.04,11.912 5.181,10.779 6.515,-2.646 5.932,-11.724 -5.181,-10.779 z m 2.333,0.555 c 2.593,-0.229 6.755,2.008 5.406,5.471 -1.963,4.837 -7.63,3.434 -11.154,2.009 -3.088,-2.706 0.5,-6.945 3.296,-7.405 0.816,0.001 1.639,-0.156 2.452,-0.075 z" />
+      <path
+         id="path21040-5"
+         style="fill:#ffffff;fill-opacity:0.13333333;fill-rule:evenodd"
+         d="m 42.226,59.205 c -2.249,1.258 -3.577,5.383 -0.526,6.556 4.483,1.103 5.689,-2.764 4.877,-7.754 -1.641,-0.327 -2.945,0.282 -4.351,1.198 z" />
+    </g>
+  </g>
+  <metadata
+     id="metadata34">
+    <rdf:RDF>
+      <cc:Work>
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <cc:license
+           rdf:resource="http://creativecommons.org/publicdomain/zero/1.0/" />
+        <dc:publisher>
+          <cc:Agent
+             rdf:about="http://openclipart.org/">
+            <dc:title>Openclipart</dc:title>
+          </cc:Agent>
+        </dc:publisher>
+        <dc:title></dc:title>
+      </cc:Work>
+      <cc:License
+         rdf:about="http://creativecommons.org/publicdomain/zero/1.0/">
+        <cc:permits
+           rdf:resource="http://creativecommons.org/ns#Reproduction" />
+        <cc:permits
+           rdf:resource="http://creativecommons.org/ns#Distribution" />
+        <cc:permits
+           rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
+      </cc:License>
+    </rdf:RDF>
+  </metadata>
+</svg>
Binary file QTfrontend/res/PlaySound.png has changed
Binary file QTfrontend/res/SimpleGame.png has changed
Binary file QTfrontend/res/StatsMedal1@2x.png has changed
Binary file QTfrontend/res/StatsMedal2@2x.png has changed
Binary file QTfrontend/res/StatsMedal3@2x.png has changed
Binary file QTfrontend/res/StatsMedal4@2x.png has changed
Binary file QTfrontend/res/Videos.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/res/Videos.svg	Sun Dec 17 00:09:24 2017 +0100
@@ -0,0 +1,429 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   height="60"
+   width="65"
+   version="1.1"
+   viewBox="0 0 60.937497 56.249997"
+   id="svg6485">
+  <defs
+     id="defs6487">
+    <mask
+       maskUnits="userSpaceOnUse"
+       id="mask7717">
+      <ellipse
+         ry="2.8315151"
+         rx="5.2363634"
+         cy="14.235151"
+         cx="22.070303"
+         transform="translate(0.080953,-0.87907)"
+         style="color:#000000;fill:#ffffff;stroke:#2e3436;stroke-width:0.1;stroke-linecap:round;stroke-linejoin:round"
+         id="path7719" />
+    </mask>
+    <mask
+       maskUnits="userSpaceOnUse"
+       id="mask7722">
+      <ellipse
+         ry="3.1418183"
+         rx="6.7490907"
+         cy="23.621819"
+         cx="18.385454"
+         transform="translate(0,-0.72567)"
+         style="color:#000000;fill:#ffffff;stroke:#2e3436;stroke-width:0.1;stroke-linecap:round;stroke-linejoin:round"
+         id="path7724" />
+    </mask>
+    <mask
+       maskUnits="userSpaceOnUse"
+       id="mask7727">
+      <ellipse
+         ry="3.6848485"
+         rx="6.671515"
+         cy="30.603636"
+         cx="35.607273"
+         transform="translate(-0.38286,-0.74272)"
+         style="color:#000000;fill:#ffffff;stroke:#2e3436;stroke-width:0.1;stroke-linecap:round;stroke-linejoin:round"
+         id="path7729" />
+    </mask>
+    <mask
+       maskUnits="userSpaceOnUse"
+       id="mask7773">
+      <ellipse
+         ry="2.8315151"
+         rx="5.4690909"
+         cy="15.321212"
+         cx="39.292122"
+         transform="translate(0.094565,-0.86907)"
+         style="color:#000000;fill:#ffffff;stroke:#2e3436;stroke-width:0.1;stroke-linecap:round;stroke-linejoin:round"
+         id="path7775" />
+    </mask>
+    <mask
+       maskUnits="userSpaceOnUse"
+       id="mask7827">
+      <ellipse
+         ry="3.1418183"
+         rx="5.7406058"
+         cy="24.397575"
+         cx="47.476364"
+         transform="translate(0.25051,-0.85916)"
+         style="color:#000000;fill:#ffffff;stroke:#2e3436;stroke-width:0.1;stroke-linecap:round;stroke-linejoin:round"
+         id="path7829" />
+    </mask>
+    <mask
+       maskUnits="userSpaceOnUse"
+       id="mask7939">
+      <ellipse
+         ry="4.848485"
+         rx="7.8351517"
+         cy="22.070303"
+         cx="33.202423"
+         transform="matrix(1.0447,-0.040661,5.9508e-4,1.0272,-2.1399,-0.37839)"
+         style="color:#000000;fill:#ffffff;stroke:#2e3436;stroke-width:0.096532;stroke-linecap:round;stroke-linejoin:round"
+         id="path7941" />
+    </mask>
+  </defs>
+  <g
+     transform="translate(0,-996.11)"
+     id="layer1">
+    <g
+       transform="matrix(0.87890619,0,0,0.87890619,2.0022216,123.44712)"
+       id="g7943">
+      <g
+         style="fill:#696969;fill-opacity:1"
+         id="g7317">
+        <ellipse
+           ry="11.597576"
+           rx="22.690908"
+           cy="35.878788"
+           cx="29.517576"
+           transform="matrix(0.97483,0.21459,-0.13084,1.1068,5.7428,974.61)"
+           style="color:#000000;fill:#696969;fill-opacity:1;stroke:#2e3436;stroke-width:0.89727014;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
+           id="path7082" />
+        <ellipse
+           ry="12.924329"
+           rx="22.498264"
+           cy="993.45416"
+           cx="149.30586"
+           transform="matrix(0.9762987,0.21642745,-0.116583,0.99318095,0,0)"
+           style="color:#000000;fill:#696969;fill-opacity:1;stroke:#2e3436;stroke-width:0.47653565;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
+           id="path7084" />
+      </g>
+      <g
+         id="g7403">
+        <path
+           transform="translate(0,988.36)"
+           d="m 8.9212,24.747 c 0,0 -0.54303,3.103 1.4739,6.2836 2.017,3.1806 4.2667,7.2921 13.576,9.9297 9.3091,2.6376 11.249,2.2737 13.421,2.1883 2.0514,-0.0807 6.8015,0.34661 8.6109,0.83716 1.3629,0.36951 2.4048,0.46545 2.56,1.5515 0.15515,1.0861 -2.1721,1.0861 -4.0339,2.2497 -1.8618,1.1636 -2.7152,3.103 -3.4909,5.3527 -0.77576,2.2497 -1.2412,3.1806 -0.46546,4.3442 0.77576,1.1636 3.2582,3.6461 5.5855,4.577 2.3273,0.93091 4.8873,1.0861 4.8873,1.0861 l 0.93091,-4.1115 c 0,0 -3.0255,-0.15515 -5.9733,-2.0945 -2.9479,-1.9394 -2.9479,-3.103 -2.9479,-3.6461 0,-0.54303 1.3188,-1.2412 2.7927,-1.8618 1.4739,-0.62061 2.7152,-0.15515 3.1806,-2.0945 0.46545,-1.9394 1.3188,-5.0424 1.1636,-6.5164 -0.15515,-1.4739 -1.0861,-2.2497 -2.8703,-3.0255 -1.7842,-0.77576 -3.5685,-1.1636 -5.5855,-1.1636 -2.017,0 -9.1539,0.54303 -14.817,-1.3188 -5.663,-1.8618 -13.343,-6.9042 -14.972,-8.7661 -1.6291,-1.8618 -2.4533,-2.8024 -3.0255,-3.8012 z"
+           style="fill:#0d0d0d;stroke:#2e3436;stroke-width:0.1"
+           id="path7086" />
+        <g
+           id="g7299">
+          <path
+             transform="translate(0,988.36)"
+             style="fill:#b8bab6;fill-opacity:1;stroke:#2e3436;stroke-width:0.1"
+             d="m 9.3091,25.792 c 0,0 0.11284,2.7152 1.2313,4.6085 0.79896,1.3524 2.1594,3.2779 2.1594,3.2779 l 1.0292,-2.9559 c 0,0 -0.74332,-0.44383 -2.2379,-1.7852 -1.329,-1.192 -1.7552,-2.573 -2.1819,-3.145 z"
+             id="path7088" />
+          <path
+             transform="translate(0,988.36)"
+             style="fill:#b8bab6;fill-opacity:1;stroke:#2e3436;stroke-width:0.1"
+             d="m 14.322,31.102 -1.1124,3.1329 1.9519,1.7111 1.1246,-3.0643 -1.9641,-1.7798 z"
+             id="path7090" />
+          <path
+             transform="translate(0,988.36)"
+             style="color:#000000;fill:#b8bab6;fill-opacity:1;stroke:#2e3436;stroke-width:0.1"
+             d="m 16.799,33.321 2.2506,1.3394 -1.2221,3.1085 -2.15,-1.3836 z"
+             id="path7105" />
+          <path
+             transform="translate(0,988.36)"
+             style="color:#000000;fill:#b8bab6;fill-opacity:1;stroke:#2e3436;stroke-width:0.1"
+             d="m 19.764,35.067 2.7016,0.92628 -1.0957,3.3768 -2.7412,-1.2616 1.1353,-3.0414 z"
+             id="path7115" />
+          <path
+             transform="translate(0,988.36)"
+             style="color:#000000;fill:#b8bab6;fill-opacity:1;stroke:#2e3436;stroke-width:0.1"
+             d="m 23.197,36.154 2.9851,1.1717 -1.0409,3.3107 -3.0688,-0.99123 1.1247,-3.4911 z"
+             id="path7125" />
+          <path
+             transform="translate(0,988.36)"
+             style="color:#000000;fill:#b8bab6;fill-opacity:1;stroke:#2e3436;stroke-width:0.1"
+             d="m 26.789,37.528 3.364,0.91127 -0.74336,3.2969 -3.5187,-0.89329 0.89804,-3.3149 z"
+             id="path7135" />
+          <path
+             d="m 30.741,1027 c 0,0 0.83773,0.2345 1.8099,0.399 0.97696,0.1653 1.5599,0.2114 1.5599,0.2114 l -0.54788,3.266 c 0,0 -1.2398,-0.1292 -1.8178,-0.2196 -0.6997,-0.1096 -1.6303,-0.3289 -1.6303,-0.3289 L 30.74116,1027 Z"
+             style="color:#000000;fill:#b8bab6;fill-opacity:1;stroke:#2e3436;stroke-width:0.1"
+             id="path7145" />
+          <path
+             d="m 34.668,1027.6 3.1031,0.04 -0.38398,3.2892 c 0,0 -1.0709,0.078 -1.6064,0.07 -0.53547,-0.01 -1.6064,-0.1174 -1.6064,-0.1174 l 0.49369,-3.1566 v -4e-4 -0.1248 z"
+             style="color:#000000;fill:#b8bab6;fill-opacity:1;stroke:#2e3436;stroke-width:0.1"
+             id="path7155" />
+          <path
+             transform="translate(0,988.36)"
+             style="color:#000000;fill:#b8bab6;fill-opacity:1;stroke:#2e3436;stroke-width:0.1"
+             d="m 38.508,39.309 c 0,0 1.0839,-0.0079 1.6102,-0.0118 0.52632,-0.0039 1.5165,0.08195 1.5165,0.08195 l -0.33677,3.376 c 0,0 -1.0397,-0.06527 -1.5595,-0.06666 -0.51984,-0.0014 -1.5595,-0.03541 -1.5595,-0.03541 l 0.32912,-3.3441 z"
+             id="path7165" />
+          <path
+             transform="translate(0,988.36)"
+             style="color:#000000;fill:#b8bab6;fill-opacity:1;stroke:#2e3436;stroke-width:0.1"
+             d="m 42.387,39.356 c 0,0 1.1647,0.18539 1.7002,0.24684 0.53547,0.06145 1.6377,0.4656 1.6377,0.4656 l -0.41523,3.3072 c 0,0 -1.0971,-0.19326 -1.6456,-0.27427 -0.54854,-0.08101 -1.6456,-0.21177 -1.6456,-0.21177 l 0.36869,-3.5336 z"
+             id="path7175" />
+          <path
+             transform="translate(0,988.36)"
+             style="color:#000000;fill:#b8bab6;fill-opacity:1;stroke:#2e3436;stroke-width:0.1"
+             d="m 46.54,40.319 c 0,0 1.3102,0.24436 2.1553,0.87834 0.46644,0.34992 0.86936,0.98671 0.86936,0.98671 l -0.72906,3.0559 c 0,0 -0.19742,-0.62169 -0.84776,-0.98738 -0.94715,-0.53258 -1.9103,-0.64229 -1.9103,-0.64229 l 0.46244,-3.2913 z"
+             id="path7185" />
+          <path
+             transform="translate(0,988.36)"
+             style="color:#000000;fill:#b8bab6;fill-opacity:1;stroke:#2e3436;stroke-width:0.1"
+             d="m 48.217,46.94 -0.63532,3.3308 -1.8109,0.65061 0.29156,-2.9864 2.1546,-0.99502 z"
+             id="path7195" />
+          <path
+             transform="translate(0,988.36)"
+             style="color:#000000;fill:#b8bab6;fill-opacity:1;stroke:#2e3436;stroke-width:0.1"
+             d="m 45.271,48.257 -0.34508,3.001 c 0,0 -0.54854,0.28956 -1.0422,0.56384 -0.49369,0.27427 -0.87767,0.65825 -0.87767,0.65825 0,0 -0.21942,-2.1393 0.6034,-2.9621 0.82282,-0.82282 1.4422,-1.261 1.6616,-1.261 z"
+             id="path7205" />
+          <path
+             transform="translate(0,988.36)"
+             style="color:#000000;fill:#b8bab6;fill-opacity:1;stroke:#2e3436;stroke-width:0.1"
+             d="m 41.619,52.253 c 0,0 0.18019,0.83079 0.45446,1.5988 0.27427,0.76796 0.83653,1.7691 0.83653,1.7691 0,0 -0.35655,0.63082 -0.64454,1.4811 -0.2663,0.78622 -0.24685,1.5085 -0.24685,1.5085 l -1.4262,-2.0708 c -0.26224,-0.38075 -0.15543,-1.0238 0.23504,-2.139 0.43884,-1.2533 0.68186,-1.9831 0.79156,-2.1476 z"
+             id="path7215" />
+          <path
+             transform="translate(0,988.36)"
+             style="color:#000000;fill:#b8bab6;fill-opacity:1;stroke:#2e3436;stroke-width:0.1"
+             d="m 43.499,56.142 c 0,0 0.67197,0.61711 1.4399,1.1382 0.67018,0.45477 1.5908,0.95995 1.5908,0.95995 0,0 -0.23313,0.71311 -0.34284,1.6456 -0.10971,0.93252 -4e-6,1.5359 -4e-6,1.5359 0,0 -1.0011,-0.39769 -2.0159,-1.0559 -0.98489,-0.63884 -1.4948,-1.1794 -1.4948,-1.1794 0,0 0.05485,-0.72682 0.27427,-1.5496 0.21942,-0.82282 0.31043,-0.99478 0.54854,-1.4948 z"
+             id="path7225" />
+          <path
+             transform="translate(0,988.36)"
+             style="color:#000000;fill:#b8bab6;fill-opacity:1;stroke:#2e3436;stroke-width:0.1"
+             d="m 47.284,58.501 c 0,0 0.98738,0.5074 2.0296,0.78167 1.04222,0.27427 1.7828,0.37027 1.7828,0.37027 l -0.61711,2.8799 c 0,0 -0.8091,-0.02742 -1.8513,-0.3017 -1.0422,-0.27427 -1.6731,-0.58968 -1.6731,-0.58968 0,0 -0.05486,-0.71311 0.05485,-1.5359 0.10971,-0.82282 0.21942,-1.6045 0.27427,-1.6045 z"
+             id="path7235" />
+        </g>
+      </g>
+      <g
+         id="g7395">
+        <ellipse
+           ry="13.847273"
+           rx="23.893333"
+           cy="23.699394"
+           cx="32.349091"
+           transform="matrix(0.99607,0.21408,-0.23368,0.91252,5.355,985.07)"
+           style="color:#000000;fill:#252525;fill-opacity:1;stroke:#2e3436;stroke-width:0.10212;stroke-linecap:round;stroke-linejoin:round"
+           id="path7023" />
+        <ellipse
+           ry="13.847273"
+           rx="23.893333"
+           cy="23.699394"
+           cx="32.349091"
+           transform="matrix(0.99607,0.22193,-0.23368,0.94595,5.355,982.83)"
+           style="color:#000000;fill:#777777;fill-opacity:1;stroke:#2e3436;stroke-width:0.75880688;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
+           id="path6511" />
+        <path
+           id="path5212"
+           d="m 24.931228,998.67067 c -3.693249,0.0504 -8.325703,0.75734 -11.460392,2.84023 -2.767808,1.1472 -5.0260178,4.2352 -4.9550522,6.9186 -0.8622461,2.7318 1.6174552,6.0019 3.2439022,7.7227 1.415809,1.7613 4.487185,3.5199 5.349339,4.4524 -2.712855,-2.914 -6.620033,-7.3622 -6.392064,-11.7583 3.073346,-9.24059 16.32269,-9.04513 23.845326,-8.2727 2.150157,0.3425 5.784107,0.9322 5.561495,0.7222 -1.407774,-1.32779 -8.571778,-2.20705 -9.37691,-2.41764 -2.456388,-0.23845 -3.355563,-0.0779 -5.815644,-0.20749 z"
+           style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:0.14398941;fill-rule:evenodd;stroke:none;stroke-width:0.94210398px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+        <path
+           transform="matrix(0.93749995,0,0,0.93749995,-0.14475,992.8965)"
+           id="path5208"
+           d="m 37.837891,7.6816406 c 0.01062,0.00888 0.02542,0.018447 0.02539,0.017578 -5.2e-5,0 0.01451,0.021109 0.02539,0.037109 -0.01114,-0.013442 -0.02958,-0.031998 -0.05078,-0.054687 z"
+           style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+        <path
+           transform="matrix(0.93749995,0,0,0.93749995,-0.14475,992.8965)"
+           id="path5204"
+           d="m 12.1875,16.662109 c -2.78e-4,0.0013 2.88e-4,0.0025 0,0.0039 l 0.0039,-0.0059 c -9.84e-4,8.29e-4 -0.0028,0.0011 -0.0039,0.002 z"
+           style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+        <path
+           transform="matrix(0.93749995,0,0,0.93749995,-0.14475,992.8965)"
+           id="path5202"
+           d="m 12.191406,16.660156 c 1.38e-4,2.33e-4 0.0018,0.0035 0.002,0.0039 0.0017,-0.0033 0.0022,-0.0045 0.0039,-0.0078 z"
+           style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+        <path
+           transform="matrix(0.93749995,0,0,0.93749995,-0.14475,992.8965)"
+           id="path5200"
+           d="m 35.568359,8.0722656 c 0.01739,0.010667 0.03924,0.012359 0.04297,0.011719 h -0.0078 c -0.017,0 -0.01779,0.010667 -0.03516,0 z"
+           style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+        <path
+           transform="matrix(0.93749995,0,0,0.93749995,-0.14475,992.8965)"
+           id="path5198"
+           d="m 36.173828,8.6367188 c 0.04406,0.0576 0.07491,0.1020779 0.107422,0.1445312 -0.0076,-0.010667 -0.0096,-0.011358 -0.01758,-0.015625 -0.02868,-0.0288 -0.08646,-0.116301 -0.08594,-0.1152344 4e-5,0 -0.0034,-0.011539 -0.0039,-0.013672 z"
+           style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+        <path
+           transform="matrix(0.93749995,0,0,0.93749995,-0.14475,992.8965)"
+           id="path5196"
+           d="m 34.833984,8.7675781 c -0.0079,0.040533 -0.01273,0.06815 -0.01758,0.09375 5.42e-4,-0.016 3.9e-5,-0.039063 0,-0.039063 -5.4e-5,3.2e-4 0.01147,-0.031221 0.01758,-0.054687 z"
+           style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+        <path
+           transform="matrix(0.93749995,0,0,0.93749995,-0.14475,992.8965)"
+           id="path5194"
+           d="m 35.808594,8.8867188 c 5.31e-4,0.00243 0.002,0.00977 0.002,0.00977 10e-7,0 -0.0017,0.00977 -0.002,0.00977 2.95e-4,-0.010667 -2.26e-4,-0.012065 0,-0.019531 z"
+           style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+        <path
+           transform="matrix(0.93749995,0,0,0.93749995,-0.14475,992.8965)"
+           id="path5186"
+           d="m 12.208984,16.640625 c -0.0016,0 -0.0039,0.0047 -0.0059,0.0078 10e-4,-0.0011 0.0052,-0.003 0.0059,-0.0039 z"
+           style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+        <path
+           transform="matrix(0.93749995,0,0,0.93749995,-0.14475,992.8965)"
+           id="path5184"
+           d="m 17.400391,21.962891 c 0.02655,0.01813 0.03111,0.02288 0.05664,0.04102 -0.0173,-0.01067 -0.04316,-0.02255 -0.04297,-0.02148 7.9e-5,1.07e-4 -0.01039,-0.01526 -0.01367,-0.01953 z"
+           style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+        <path
+           id="path5212-3"
+           d="m 38.488504,1026.2161 c 3.798454,-0.051 8.616165,-0.4665 11.840147,-2.5697 2.846651,-1.1583 5.292859,-4.3587 5.219872,-7.0681 0.886808,-2.7583 -1.745978,-6.4311 -3.418756,-8.1686 -1.392806,-1.7605 -3.993652,-3.2529 -5.501718,-4.3721 1.812007,2.747 4.063702,4.2428 5.714102,6.6066 2.401086,3.439 3.855769,8.2138 -2.966126,11.3807 -5.167089,2.7452 -10.724794,3.3128 -16.107728,2.7343 -4.548402,-0.4889 -8.995606,-1.8904 -12.73615,-2.5248 1.075781,1.4088 11.053996,3.5212 11.902177,3.739 2.52636,0.2408 3.524022,0.1118 6.05418,0.2427 z"
+           style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#000000;fill-opacity:0.14398941;fill-rule:evenodd;stroke:none;stroke-width:0.96005654px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+      </g>
+      <ellipse
+         transform="matrix(1.0287,0,0,1.2829,-0.56611,982.26)"
+         ry="3.1418183"
+         rx="6.7490907"
+         cy="23.621819"
+         cx="18.385454"
+         style="color:#000000;fill:#494949;fill-opacity:1;stroke:#2e3436;stroke-width:0.087049;stroke-linecap:round;stroke-linejoin:round"
+         id="path7025" />
+      <ellipse
+         ry="3.6848485"
+         rx="6.671515"
+         cy="30.603636"
+         cx="35.607273"
+         transform="matrix(0.96574,0.42197,-0.39338,1.0359,13.453,973.36)"
+         style="color:#000000;fill:#494949;fill-opacity:1;stroke:#2e3436;stroke-width:0.092592;stroke-linecap:round;stroke-linejoin:round"
+         id="path7031" />
+      <ellipse
+         ry="3.1418183"
+         rx="5.7406058"
+         cy="24.397575"
+         cx="47.476364"
+         transform="matrix(1.0238,0.29254,-0.33353,0.89797,6.9686,978.17)"
+         style="color:#000000;fill:#494949;fill-opacity:1;stroke:#2e3436;stroke-width:0.099165;stroke-linecap:round;stroke-linejoin:round"
+         id="path7037" />
+      <ellipse
+         ry="4.848485"
+         rx="7.8351517"
+         cy="22.070303"
+         cx="33.202423"
+         transform="matrix(0.44315,0.11256,-0.1318,0.37847,21.087,998.3)"
+         style="color:#000000;fill:#494949;fill-opacity:1;stroke:#2e3436;stroke-width:0.23405001;stroke-linecap:round;stroke-linejoin:round"
+         id="path7043" />
+      <ellipse
+         ry="2.8315151"
+         rx="5.2363634"
+         cy="14.235151"
+         cx="22.070303"
+         transform="matrix(1.0155,0.16626,-0.17122,0.98608,2.3277,985.2)"
+         style="color:#000000;fill:#494949;fill-opacity:1;stroke:#2e3436;stroke-width:0.09854;stroke-linecap:round;stroke-linejoin:round"
+         id="path7068" />
+      <ellipse
+         ry="2.8315151"
+         rx="5.4690909"
+         cy="15.321212"
+         cx="39.292122"
+         transform="matrix(1.0137,0.24551,-0.24675,1.0087,2.6196,979.24)"
+         style="color:#000000;fill:#494949;fill-opacity:1;stroke:#2e3436;stroke-width:0.096087;stroke-linecap:round;stroke-linejoin:round"
+         id="path7074" />
+      <g
+         style="fill:#111111;fill-opacity:1"
+         id="g5141">
+        <ellipse
+           id="path7027"
+           style="color:#000000;fill:#111111;fill-opacity:1;stroke:#2e3436;stroke-width:0.087049;stroke-linecap:round;stroke-linejoin:round"
+           mask="url(#mask7722)"
+           transform="matrix(1.0287,0,0,1.2829,-0.56611,983.19)"
+           cx="18.385454"
+           cy="23.621819"
+           rx="6.7490907"
+           ry="3.1418183" />
+        <ellipse
+           id="path7033"
+           style="color:#000000;fill:#111111;fill-opacity:1;stroke:#2e3436;stroke-width:0.092592;stroke-linecap:round;stroke-linejoin:round"
+           mask="url(#mask7727)"
+           transform="matrix(0.96574,0.42197,-0.39338,1.0359,13.53,974.29)"
+           cx="35.607273"
+           cy="30.603636"
+           rx="6.671515"
+           ry="3.6848485" />
+        <ellipse
+           id="path7039"
+           style="color:#000000;fill:#111111;fill-opacity:1;stroke:#2e3436;stroke-width:0.099165;stroke-linecap:round;stroke-linejoin:round"
+           mask="url(#mask7827)"
+           transform="matrix(1.0238,0.29254,-0.33353,0.89797,6.4255,978.86)"
+           cx="47.476364"
+           cy="24.397575"
+           rx="5.7406058"
+           ry="3.1418183" />
+        <ellipse
+           id="path7045"
+           style="color:#000000;fill:#111111;fill-opacity:1;stroke:#2e3436;stroke-width:0.24246;stroke-linecap:round;stroke-linejoin:round"
+           mask="url(#mask7939)"
+           transform="matrix(0.4192,0.12208,-0.12854,0.36836,21.936,998.7)"
+           cx="33.202423"
+           cy="22.070303"
+           rx="7.8351517"
+           ry="4.848485" />
+        <ellipse
+           id="path7070"
+           style="color:#000000;fill:#111111;fill-opacity:1;stroke:#2e3436;stroke-width:0.09854;stroke-linecap:round;stroke-linejoin:round"
+           mask="url(#mask7717)"
+           transform="matrix(1.0155,0.16626,-0.17122,0.98608,2.095,986.05)"
+           cx="22.070303"
+           cy="14.235151"
+           rx="5.2363634"
+           ry="2.8315151" />
+        <ellipse
+           id="path7076"
+           style="color:#000000;fill:#111111;fill-opacity:1;stroke:#2e3436;stroke-width:0.096087;stroke-linecap:round;stroke-linejoin:round"
+           mask="url(#mask7773)"
+           transform="matrix(1.0137,0.24551,-0.24675,1.0087,2.3093,980.1)"
+           cx="39.292122"
+           cy="15.321212"
+           rx="5.4690909"
+           ry="2.8315151" />
+      </g>
+    </g>
+  </g>
+  <metadata
+     id="metadata4644">
+    <rdf:RDF>
+      <cc:Work>
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <cc:license
+           rdf:resource="http://creativecommons.org/publicdomain/zero/1.0/" />
+        <dc:publisher>
+          <cc:Agent
+             rdf:about="http://openclipart.org/">
+            <dc:title>Openclipart</dc:title>
+          </cc:Agent>
+        </dc:publisher>
+        <dc:title></dc:title>
+        <dc:date>2010-02-12T23:23:34</dc:date>
+        <dc:description>A movie reel, seen in perspective</dc:description>
+        <dc:source>https://openclipart.org/detail/29273/movie-reel-by-abustany</dc:source>
+        <dc:creator>
+          <cc:Agent>
+            <dc:title>abustany</dc:title>
+          </cc:Agent>
+        </dc:creator>
+        <dc:subject>
+          <rdf:Bag>
+            <rdf:li>cinema</rdf:li>
+            <rdf:li>colour</rdf:li>
+            <rdf:li>film</rdf:li>
+            <rdf:li>movie</rdf:li>
+            <rdf:li>reel</rdf:li>
+            <rdf:li>video</rdf:li>
+          </rdf:Bag>
+        </dc:subject>
+      </cc:Work>
+      <cc:License
+         rdf:about="http://creativecommons.org/publicdomain/zero/1.0/">
+        <cc:permits
+           rdf:resource="http://creativecommons.org/ns#Reproduction" />
+        <cc:permits
+           rdf:resource="http://creativecommons.org/ns#Distribution" />
+        <cc:permits
+           rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
+      </cc:License>
+    </rdf:RDF>
+  </metadata>
+</svg>
Binary file QTfrontend/res/audio.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/res/audio.svg	Sun Dec 17 00:09:24 2017 +0100
@@ -0,0 +1,198 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   height="51.200001"
+   width="51.200001"
+   version="1.0"
+   viewBox="0 0 48 48"
+   id="svg2566">
+  <defs
+     id="defs2568">
+    <radialGradient
+       r="9.9204998"
+       gradientTransform="matrix(-0.12758,1.4161,-1.6301,-0.14685,17.488,15.561)"
+       cx="-1.0017"
+       cy="0.99004"
+       gradientUnits="userSpaceOnUse"
+       id="radialGradient3702">
+      <stop
+         offset="0"
+         style="stop-color:#eeeeec"
+         id="stop4022" />
+      <stop
+         offset="1"
+         style="stop-color:#555753"
+         id="stop3680" />
+    </radialGradient>
+  </defs>
+  <g
+     id="layer1">
+    <g
+       transform="matrix(1.2962,0,0,1.2962,-5.4212147,-7.1285265)"
+       id="g4090">
+      <ellipse
+         ry="6.3639612"
+         rx="3.6239223"
+         cy="24.665476"
+         cx="8.7504463"
+         transform="matrix(1.416,0,0,1.2586,-2.6676,-6.2007)"
+         style="color:#000000;fill:#aaaaa6;fill-opacity:1;stroke:#5d615f;stroke-width:0.57792002;stroke-linecap:round;stroke-linejoin:round"
+         id="path4076" />
+      <ellipse
+         ry="7.3471932"
+         rx="4.1838183"
+         cy="25.01948"
+         cx="10.473573"
+         style="color:#000000;fill:#c0c0be;fill-opacity:1;stroke-width:1.15450001"
+         id="path4060" />
+      <ellipse
+         ry="6.3639612"
+         rx="3.6239223"
+         cy="24.665476"
+         cx="8.7504463"
+         transform="matrix(1.0814,0,0,1.0814,1.2327,-1.8299)"
+         style="color:#000000;fill:#93958f"
+         id="path4058" />
+      <ellipse
+         ry="6.3639612"
+         rx="3.6239223"
+         cy="24.665476"
+         cx="8.7504463"
+         transform="matrix(1.1807,0,0,1.077,-0.60894,-1.7217)"
+         style="color:#000000;opacity:0.39560002;fill:none;stroke:#ffffff;stroke-width:0.68417001;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+         id="path3279" />
+    </g>
+    <path
+       d="M 9.4807,18.243 16.57,12.118 16.341,37.201 9.137,31.676 C 6.6165,29.614 6.1582,20.419 9.4807,18.243 Z"
+       style="color:#000000;fill:#9b9b8f;fill-rule:evenodd;stroke:#6f726f;stroke-linecap:round;fill-opacity:1;stroke-opacity:1"
+       id="path4542" />
+    <path
+       d="m 7.5384,21.987 4.0546,-3.039 -0.251,3.537 -3.9638,0.661 z"
+       style="color:#000000;fill:#ffffff;fill-rule:evenodd;fill-opacity:0.52972257"
+       id="path4544" />
+    <path
+       d="M 8.2035,30.371 12.644,33.94 12.087,31.512 7.6111,29.009 Z"
+       style="color:#000000;opacity:0.76923002;fill:#ffffff;fill-opacity:0.70671833"
+       id="path3672" />
+    <g
+       transform="matrix(1.0969,0,0,1.5093,-4.217,-12.118)"
+       id="g4006">
+      <path
+         d="M 23.75,14 C 21.81,14.049 20.013,14.683 18.5,15.688 18.133,15.264 17.604,15 17,15 c -0.034,0 -0.087,10e-4 -0.125,0 -0.028,0 -0.069,-0.003 -0.094,0 C 15.773,15.102 15,15.965 15,17 c 0,0.604 0.264,1.133 0.688,1.5 C 14.639,20.08 14,21.962 14,24 c 0,2.034 0.612,3.922 1.656,5.5 C 15.243,29.87 15,30.402 15,31 c 0,1.104 0.896,2 2,2 0.604,0 1.133,-0.264 1.5,-0.688 1.58,1.049 3.462,1.688 5.5,1.688 2.038,0 3.92,-0.639 5.5,-1.688 0.367,0.424 0.896,0.688 1.5,0.688 1.104,0 2,-0.896 2,-2 0,-0.604 -0.264,-1.133 -0.688,-1.5 C 33.361,27.92 34,26.038 34,24 34,21.962 33.361,20.08 32.312,18.5 32.736,18.133 33,17.604 33,17 c 0,-1.104 -0.896,-2 -2,-2 -0.034,0 -0.087,10e-4 -0.125,0 -0.028,0 -0.069,-0.003 -0.094,0 -0.504,0.051 -0.962,0.298 -1.281,0.656 -0.007,-0.004 -0.025,0.005 -0.031,0 C 27.895,14.62 26.025,14 24,14 c -0.086,0 -0.164,-0.002 -0.25,0 z"
+         style="color:#000000;fill:url(#radialGradient3702);fill-rule:evenodd;stroke:#475154;stroke-width:1.47669995;stroke-linecap:round;stroke-opacity:1"
+         id="path3726" />
+      <path
+         d="M 23.75,14 C 21.81,14.049 20.013,14.683 18.5,15.688 18.133,15.264 17.604,15 17,15 c -0.034,0 -0.087,10e-4 -0.125,0 -0.028,0 -0.069,-0.003 -0.094,0 C 15.773,15.102 15,15.965 15,17 c 0,0.604 0.264,1.133 0.688,1.5 C 14.639,20.08 14,21.962 14,24 c 0,2.034 0.612,3.922 1.656,5.5 C 15.243,29.87 15,30.402 15,31 c 0,1.104 0.896,2 2,2 0.604,0 1.133,-0.264 1.5,-0.688 1.58,1.049 3.462,1.688 5.5,1.688 2.038,0 3.92,-0.639 5.5,-1.688 0.367,0.424 0.896,0.688 1.5,0.688 1.104,0 2,-0.896 2,-2 0,-0.604 -0.264,-1.133 -0.688,-1.5 C 33.361,27.92 34,26.038 34,24 34,21.962 33.361,20.08 32.312,18.5 32.736,18.133 33,17.604 33,17 c 0,-1.104 -0.896,-2 -2,-2 -0.034,0 -0.087,10e-4 -0.125,0 -0.028,0 -0.069,-0.003 -0.094,0 -0.504,0.051 -0.962,0.298 -1.281,0.656 -0.007,-0.004 -0.025,0.005 -0.031,0 C 27.895,14.62 26.025,14 24,14 c -0.086,0 -0.164,-0.002 -0.25,0 z"
+         style="color:#000000;fill:#9c9c90;fill-rule:evenodd;fill-opacity:1"
+         id="path3507" />
+      <circle
+         r="9.375"
+         cy="9.375"
+         cx="9.375"
+         transform="matrix(0.84698,0,0,0.91142,16.71,15.45)"
+         style="color:#000000;fill:#313537;fill-rule:evenodd;stroke:#454d52;stroke-width:0.83832002;stroke-linecap:round;stroke-opacity:1;fill-opacity:1"
+         id="path3636" />
+      <ellipse
+         cy="24.097544"
+         cx="23.674191"
+         style="color:#000000;fill:#505558;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.52743274;stroke-linecap:round;stroke-opacity:1"
+         id="path3636-2"
+         rx="5.6859865"
+         ry="6.1185889" />
+      <ellipse
+         ry="3"
+         rx="3.4431562"
+         cy="24.0571"
+         cx="22.893705"
+         style="color:#000000;fill:#8b9396;fill-opacity:1;fill-rule:evenodd;stroke:#444444;stroke-width:0.70748819;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+         id="path3519" />
+      <circle
+         r="0.5"
+         cy="16.5"
+         cx="16.5"
+         transform="matrix(1.3125,0,0,1.3125,-4.6577,-5.0938)"
+         style="color:#000000;fill:#2e3436;fill-rule:evenodd"
+         id="path3718" />
+      <circle
+         r="0.5"
+         cy="16.5"
+         cx="16.5"
+         transform="translate(15.222,0.25)"
+         style="color:#000000;fill:#2e3436;fill-rule:evenodd"
+         id="path3720" />
+      <circle
+         r="0.5"
+         cy="16.5"
+         cx="16.5"
+         transform="translate(15.222,14.969)"
+         style="color:#000000;fill:#2e3436;fill-rule:evenodd"
+         id="path3722" />
+      <circle
+         r="0.5"
+         cy="16.5"
+         cx="16.5"
+         transform="matrix(1.375,0,0,1.375,-5.6889,8.8125)"
+         style="color:#000000;fill:#2e3436;fill-rule:evenodd"
+         id="path3724" />
+    </g>
+    <path
+       d="m 36.088,32.866 c 0.917,-2.165 1.481,-5.158 1.481,-8.438 0,-3.28 -0.564,-6.274 -1.481,-8.438"
+       style="color:#000000;fill:none;stroke:#3465a4;stroke-linecap:round;stroke-opacity:1"
+       id="path3488" />
+    <path
+       d="m 39.839,35.703 c 1.226,-2.893 1.979,-6.893 1.979,-11.275 0,-4.383 -0.753,-8.383 -1.979,-11.275"
+       style="color:#000000;fill:none;stroke:#3465a4;stroke-linecap:round;stroke-opacity:1;opacity:0.8"
+       id="path3494" />
+    <path
+       d="m 43.487,39.708 c 1.662,-3.92 2.682,-9.341 2.682,-15.28 0,-5.94 -1.02,-11.361 -2.682,-15.281"
+       style="color:#000000;fill:none;stroke:#3465a4;stroke-linecap:round;stroke-opacity:1;opacity:0.6"
+       id="path3496" />
+  </g>
+  <metadata
+     id="metadata7893">
+    <rdf:RDF>
+      <cc:Work>
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <cc:license
+           rdf:resource="http://creativecommons.org/publicdomain/zero/1.0/" />
+        <dc:publisher>
+          <cc:Agent
+             rdf:about="http://openclipart.org/">
+            <dc:title>Openclipart</dc:title>
+          </cc:Agent>
+        </dc:publisher>
+        <dc:title></dc:title>
+        <dc:date>2010-04-03T15:19:58</dc:date>
+        <dc:description>An icon from Tango Project. Since version 0.8.90 Tango Project icons are Public Domain.</dc:description>
+        <dc:source>https://openclipart.org/detail/36601/tango-audio-volume-high-by-warszawianka</dc:source>
+        <dc:creator>
+          <cc:Agent>
+            <dc:title>warszawianka</dc:title>
+          </cc:Agent>
+        </dc:creator>
+        <dc:subject>
+          <rdf:Bag>
+            <rdf:li>externalsource</rdf:li>
+            <rdf:li>icon</rdf:li>
+            <rdf:li>tango</rdf:li>
+          </rdf:Bag>
+        </dc:subject>
+      </cc:Work>
+      <cc:License
+         rdf:about="http://creativecommons.org/publicdomain/zero/1.0/">
+        <cc:permits
+           rdf:resource="http://creativecommons.org/ns#Reproduction" />
+        <cc:permits
+           rdf:resource="http://creativecommons.org/ns#Distribution" />
+        <cc:permits
+           rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
+      </cc:License>
+    </rdf:RDF>
+  </metadata>
+</svg>
Binary file QTfrontend/res/botlevels/net0.png has changed
Binary file QTfrontend/res/botlevels/net0.xcf has changed
Binary file QTfrontend/res/botlevels/net1.png has changed
Binary file QTfrontend/res/botlevels/net2.png has changed
Binary file QTfrontend/res/botlevels/net3.png has changed
Binary file QTfrontend/res/botlevels/net4.png has changed
Binary file QTfrontend/res/botlevels/net5.png has changed
Binary file QTfrontend/res/btnAISurvival.png has changed
Binary file QTfrontend/res/btnAISurvival.xcf has changed
Binary file QTfrontend/res/btnAISurvival@2x.png has changed
Binary file QTfrontend/res/btnAISurvival@2x.xcf has changed
Binary file QTfrontend/res/btnBorder.png has changed
Binary file QTfrontend/res/btnBorder@2x.png has changed
Binary file QTfrontend/res/btnBottomBorder.png has changed
Binary file QTfrontend/res/btnBottomBorder@2x.png has changed
Binary file QTfrontend/res/btnForts.png has changed
Binary file QTfrontend/res/btnForts@2x.png has changed
Binary file QTfrontend/res/btnLowGravity.png has changed
Binary file QTfrontend/res/btnLowGravity@2x.png has changed
Binary file QTfrontend/res/btnMoreWind.png has changed
Binary file QTfrontend/res/btnMoreWind@2x.png has changed
Binary file QTfrontend/res/btnNoWind.png has changed
Binary file QTfrontend/res/btnNoWind@2x.png has changed
Binary file QTfrontend/res/btnPlaceHog.png has changed
Binary file QTfrontend/res/btnPlaceHog@2x.png has changed
Binary file QTfrontend/res/btnRandomOrder@2x.png has changed
Binary file QTfrontend/res/campaign/A_Classic_Fairytale/epil.png has changed
Binary file QTfrontend/res/campaign/A_Classic_Fairytale/family.png has changed
Binary file QTfrontend/res/campaign/A_Classic_Fairytale/journey.png has changed
Binary file QTfrontend/res/campaign/A_Classic_Fairytale/shadow.png has changed
Binary file QTfrontend/res/campaign/A_Classic_Fairytale/united.png has changed
Binary file QTfrontend/res/campaign/A_Space_Adventure/cosmos.png has changed
Binary file QTfrontend/res/campaign/A_Space_Adventure/death01.png has changed
Binary file QTfrontend/res/campaign/A_Space_Adventure/death02.png has changed
Binary file QTfrontend/res/campaign/A_Space_Adventure/fruit03.png has changed
Binary file QTfrontend/res/campaign/A_Space_Adventure/ice01.png has changed
Binary file QTfrontend/res/campaign/A_Space_Adventure/ice02.png has changed
Binary file QTfrontend/res/campaign/A_Space_Adventure/moon02.png has changed
--- a/QTfrontend/res/css/qt.css	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/res/css/qt.css	Sun Dec 17 00:09:24 2017 +0100
@@ -94,6 +94,7 @@
 border-radius: 16px;
 background-color: rgba(13, 5, 68, 70%);
 padding: 6px;
+margin-top: 4px;
 }
 /*  Experimenting with PaintOnScreen and border-radius on IconedGroupBox children didn't work out well
 IconedGroupBox QComboBox, IconedGroupBox QPushButton, IconedGroupBox QLineEdit,
@@ -207,7 +208,6 @@
 subcontrol-position: top left;
 text-align: left;
 left: 15px;
-top: -4px;
 }
 
 QCheckBox::indicator:checked{
Binary file QTfrontend/res/dlcMarker.png has changed
Binary file QTfrontend/res/dlcMarkerSelected.png has changed
Binary file QTfrontend/res/folder.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/res/folder.svg	Sun Dec 17 00:09:24 2017 +0100
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   height="50"
+   width="50"
+   x="0px"
+   y="0px"
+   version="1.1"
+   viewBox="0 0 50 50"
+   xml:space="preserve"
+   enable-background="new 0 0 436.44 424.577"
+   id="Layer_1"
+   sodipodi:docname="folder.svg"
+   inkscape:version="0.92.2 5c3e80d, 2017-08-06"><sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1920"
+     inkscape:window-height="1024"
+     id="namedview841"
+     showgrid="false"
+     inkscape:zoom="5.9514821"
+     inkscape:cx="1.0474005"
+     inkscape:cy="13.907651"
+     inkscape:window-x="0"
+     inkscape:window-y="31"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="Layer_1" /><defs
+     id="defs4642"><linearGradient
+       id="XMLID_39_"
+       y2="35.569"
+       gradientUnits="userSpaceOnUse"
+       x2="64.388"
+       gradientTransform="matrix(0.3541,0,0,0.3541,1.6387,-0.083649)"
+       y1="65.124001"
+       x1="64.388"><stop
+         id="stop336"
+         style="stop-color:#FFFFFF"
+         offset="0" /><stop
+         id="stop338"
+         style="stop-color:#FF6200"
+         offset=".8539" /><stop
+         id="stop340"
+         style="stop-color:#F25D00"
+         offset="1" /><midPointStop
+         id="midPointStop335"
+         style="stop-color:#FFFFFF"
+         offset="0" /><midPointStop
+         id="midPointStop337"
+         style="stop-color:#FFFFFF"
+         offset="0.5" /><midPointStop
+         id="midPointStop339"
+         style="stop-color:#FF6200"
+         offset="0.8539" /><midPointStop
+         id="midPointStop341"
+         style="stop-color:#FF6200"
+         offset="0.5" /><midPointStop
+         id="midPointStop343"
+         style="stop-color:#F25D00"
+         offset="1" /></linearGradient></defs><g
+     id="g847"
+     transform="matrix(1.0116175,0,0,1.0116175,0.30267219,-16.376137)"><path
+       inkscape:connector-curvature="0"
+       style="fill:#ffcd65;fill-opacity:1;stroke:#573f07;stroke-width:1.60800004;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="path4633"
+       d="m 12.245913,21.938287 13.493661,1.673412 0.593465,0.219902 c 0.419165,0.659707 -0.131725,1.408563 0.04431,2.113114 6.206752,0.945958 12.389956,1.914073 18.707145,2.222259 0.197534,0.08774 0.330123,0.219903 0.373996,0.4183 -2.993155,9.551534 -6.319752,20.194618 -4.888713,30.780178 v 0.176462 L 10.294961,49.782 c -0.79179,0 0.730092,-21.845962 0.730092,-21.845962 0,0 0.560829,-4.016147 1.2214,-5.996671 z" /><path
+       inkscape:connector-curvature="0"
+       style="fill:#e69c00;fill-opacity:1;stroke:#573f07;stroke-width:1.60699999;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="path4626"
+       d="m 4.4414923,28.360111 c 0.8535257,-0.349575 1.9912027,0 2.8435477,0.1099 8.884298,1.903111 17.938164,3.380058 27.192128,4.211346 1.225338,0.284473 0.722676,1.356295 0.832147,2.319829 -0.415429,8.467581 0.605309,17.488135 4.827712,24.796553 C 30.224951,59.57955 21.566969,56.412947 12.618104,52.912683 10.626901,51.664677 8.155468,51.662009 7.301834,49.102181 5.305327,42.991787 3.3703287,36.69419 3.7174184,29.980683 3.7817524,29.257175 4.0924626,28.901908 4.4414923,28.360111 Z" /><path
+       inkscape:connector-curvature="0"
+       style="fill:#ffffff;fill-opacity:0.0658683;stroke-width:0.09016989"
+       id="path4626-3"
+       d="m 5.470299,29.027592 c 0.6827774,-0.168534 1.677426,0.405554 2.300462,0.304184 4.494948,1.405293 20.361778,3.073775 26.258636,4.297613 0.94405,0.260123 0.353089,1.381218 0.437431,2.262277 C 30.41684,51.353125 5.887201,50.561168 9.690875,50.69114 8.156772,49.549957 8.340958,49.672359 7.683284,47.331643 6.145095,41.744271 4.1423369,37.565988 4.4097487,31.427129 4.5294311,30.907471 4.4727612,29.639788 4.843561,29.278287 Z" /><path
+       inkscape:connector-curvature="0"
+       style="fill:#ffffff;fill-opacity:0.15269464;stroke-width:0.09016989"
+       id="path4626-3-6"
+       d="m 12.780516,22.800021 3.446446,0.479877 9.249617,1.235677 c 0,0 -0.04916,1.845739 0.142095,2.153875 -0.02325,0.0027 7.837117,0.937707 13.192741,1.859102 1.586251,0.14802 2.769599,0.257927 4.410709,0.411808 0.306221,0.05698 0.563199,0.01135 0.725934,0.06607 0.07464,0.0251 0.409834,-0.06188 0.458989,-0.02759 -0.08104,0.377335 -0.100333,0.618551 -0.243556,0.74789 -0.139681,0.123841 -0.325747,0.01989 -0.330256,0.06141 -0.02601,0.239522 -17.310065,-1.00348 -17.431742,-1.012038 -3.366442,-0.03162 -14.276281,-0.294142 -14.276281,-0.294142 0,0 -0.17888,0.07412 -0.20481,-0.139355 -0.08916,-0.73405 0.860114,-5.542584 0.860114,-5.542584 z" /></g><metadata
+     id="metadata4637"><rdf:RDF><cc:Work><dc:format>image/svg+xml</dc:format><dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><cc:license
+           rdf:resource="http://creativecommons.org/publicdomain/zero/1.0/" /><dc:publisher><cc:Agent
+             rdf:about="http://openclipart.org/"><dc:title>Openclipart</dc:title></cc:Agent></dc:publisher><dc:title></dc:title></cc:Work><cc:License
+         rdf:about="http://creativecommons.org/publicdomain/zero/1.0/"><cc:permits
+           rdf:resource="http://creativecommons.org/ns#Reproduction" /><cc:permits
+           rdf:resource="http://creativecommons.org/ns#Distribution" /><cc:permits
+           rdf:resource="http://creativecommons.org/ns#DerivativeWorks" /></cc:License></rdf:RDF></metadata></svg>
\ No newline at end of file
Binary file QTfrontend/res/frontendicon.png has changed
Binary file QTfrontend/res/home.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/res/home.svg	Sun Dec 17 00:09:24 2017 +0100
@@ -0,0 +1,201 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   id="svg2"
+   xml:space="preserve"
+   overflow="visible"
+   inkscape:export-ydpi="93.75"
+   viewBox="0 0 48 48"
+   inkscape:export-xdpi="93.75"
+   version="1.0"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   sodipodi:docname="home.svg"
+   inkscape:export-filename="/home/wuzzy/src/hedgewars/hg2/QTfrontend/res/home.png"
+   inkscape:version="0.92.1 r"
+   sodipodi:version="0.32"
+   enable-background="new 0 0 128 129.396"
+   width="51.200001"
+   height="51.200001"
+   style="overflow:visible"><defs
+     id="defs365"><linearGradient
+       id="XMLID_39_"
+       y2="35.569"
+       gradientUnits="userSpaceOnUse"
+       x2="64.388"
+       gradientTransform="matrix(0.3541,0,0,0.3541,1.6387,-0.083649)"
+       y1="65.124001"
+       x1="64.388"><stop
+         id="stop336"
+         style="stop-color:#FFFFFF"
+         offset="0" /><stop
+         id="stop338"
+         style="stop-color:#FF6200"
+         offset=".8539" /><stop
+         id="stop340"
+         style="stop-color:#F25D00"
+         offset="1" /><midPointStop
+         id="midPointStop335"
+         style="stop-color:#FFFFFF"
+         offset="0" /><midPointStop
+         id="midPointStop337"
+         style="stop-color:#FFFFFF"
+         offset="0.5" /><midPointStop
+         id="midPointStop339"
+         style="stop-color:#FF6200"
+         offset="0.8539" /><midPointStop
+         id="midPointStop341"
+         style="stop-color:#FF6200"
+         offset="0.5" /><midPointStop
+         id="midPointStop343"
+         style="stop-color:#F25D00"
+         offset="1" /></linearGradient><radialGradient
+       id="radialGradient2325"
+       gradientUnits="userSpaceOnUse"
+       cy="37.425999"
+       cx="20.444"
+       gradientTransform="matrix(1.1253,0,0,0.98274,-3.4287,0.73111)"
+       r="1.0821"
+       inkscape:collect="always"><stop
+         id="stop2321"
+         style="stop-color:#000000"
+         offset="0" /><stop
+         id="stop2323"
+         style="stop-color:#000000;stop-opacity:0"
+         offset="1" /></radialGradient></defs><sodipodi:namedview
+     id="base"
+     bordercolor="#666666"
+     inkscape:pageshadow="2"
+     inkscape:window-y="31"
+     pagecolor="#ffffff"
+     inkscape:showpageshadow="false"
+     inkscape:zoom="5.3063965"
+     inkscape:window-x="0"
+     stroke="#a40000"
+     borderopacity="0.21568627"
+     inkscape:current-layer="svg2"
+     inkscape:cx="15.947549"
+     inkscape:cy="61.117875"
+     inkscape:guide-bbox="true"
+     inkscape:window-width="1920"
+     showgrid="false"
+     inkscape:pageopacity="0.0"
+     inkscape:window-height="1024"
+     showguides="true"
+     fill="#555753"
+     inkscape:window-maximized="1" /><g
+     id="g7069"
+     transform="matrix(0.93589527,0,0,0.93589527,1.8266136,2.3833932)"><path
+       inkscape:connector-curvature="0"
+       d="m 21.62,8.1834 h 5.957 c 0.84,0 13.887,15.436 13.887,16.341 l -0.444,18.497 c 0,0.905 -0.676,1.634 -1.516,1.634 H 8.047 c -0.8398,0 -1.5158,-0.729 -1.5158,-1.634 l 0.0565,-18.497 c 0,-0.905 14.192,-16.341 15.032,-16.341 z"
+       style="color:#000000;fill:#ff81f7;fill-opacity:1;stroke:#000000;stroke-width:1.50659478;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       sodipodi:nodetypes="ccccccccc"
+       id="rect1512" /><path
+       inkscape:connector-curvature="0"
+       d="M 46.964,45.736 H 1.639 l -3e-4,-45.325 45.325,-3.2e-4 v 45.325 z"
+       style="fill:none"
+       id="path5" /><path
+       inkscape:connector-curvature="0"
+       d="m 21.809212,9.4056 h 5.482047 c 0.772022,0 12.817736,14.399 12.817736,15.244 l -0.342135,18.212 c 0,0.459 -0.140995,0.654 -0.504821,0.654 l -30.9469468,0.014 c -0.3637279,0 -0.576108,-0.08 -0.576108,-0.454 l 0.2123801,-18.426 c 0,-0.845 13.0859227,-15.244 13.8579457,-15.244 z"
+       style="color:#000000;opacity:0.31100003;fill:none;stroke:#ffffff;stroke-width:0.99296516"
+       sodipodi:nodetypes="ccccccccc"
+       id="path2357" /><path
+       inkscape:connector-curvature="0"
+       d="m 7.2075,27.943 -0.0542,2.595 18.368,-13.179 15.287,11.154 0.071,-0.311 -16.37,-15.904 z"
+       style="clip-rule:evenodd;opacity:0.2;fill:#575757;fill-opacity:0.47952444;fill-rule:evenodd"
+       sodipodi:nodetypes="cccccccc"
+       id="path23" /><path
+       inkscape:connector-curvature="0"
+       d="m 19.577,36.448 c 0.673,0 1.216,0.474 1.216,1.058 0,0.59 -0.543,1.069 -1.216,1.069 -0.672,0 -1.219,-0.479 -1.219,-1.069 0.001,-0.584 0.547,-1.058 1.219,-1.058 z"
+       style="clip-rule:evenodd;opacity:0.40909005;fill:url(#radialGradient2325);fill-rule:evenodd"
+       id="path2315" /><rect
+       style="opacity:1;fill:#e6ba64;fill-opacity:1;fill-rule:nonzero;stroke:#000003;stroke-width:1.27166378;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="rect7073"
+       width="11.291932"
+       height="14.464803"
+       x="11.353704"
+       y="30.095888" /><path
+       inkscape:connector-curvature="0"
+       d="m 19.462,35.932 c 0.673,0 1.217,0.475 1.217,1.059 0,0.59 -0.544,1.068 -1.217,1.068 -0.672,0 -1.218,-0.478 -1.218,-1.068 0,-0.584 0.546,-1.059 1.218,-1.059 z"
+       style="clip-rule:evenodd;fill:#d0af33;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.34406248;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="path217" /><path
+       inkscape:connector-curvature="0"
+       d="m 24.448,11.559 18.927,17.17 0.494,0.392 L 44.273,28.95 43.9,28.188 43.623,27.965 24.448,12.392 5.058,28.136 4.8206,28.28 4.6039,28.987 5.0373,29.116 5.4219,28.807 24.4479,11.559 Z"
+       style="fill:url(#XMLID_39_)"
+       sodipodi:nodetypes="ccccccccccccc"
+       id="path342" /><path
+       inkscape:connector-curvature="0"
+       d="m 24.33,2.2713 -21.882,18.102 -0.6243,7.166 1.9999,2.064 c 0,0 20.407,-17.157 20.624,-17.328 l 19.632,17.543 1.899,-2.324 -1.616,-7.111 -19.915,-18.216 -0.118,0.1043 z"
+       style="fill:#5195e9;fill-opacity:1;stroke:#170000;stroke-width:1.50659478;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       sodipodi:nodetypes="cccccccccc"
+       id="path362" /><path
+       inkscape:connector-curvature="0"
+       d="M 3.2473101,20.732415 2.5498,27.236 24.3688,8.98 24.406273,3.2299977 Z"
+       style="color:#000000;opacity:0.40909005;fill:#ffffff;fill-opacity:1"
+       sodipodi:nodetypes="cccccc"
+       id="path1536" /><path
+       inkscape:connector-curvature="0"
+       d="M 24.484,8.751 24.406273,3.2299977 43.840351,20.585783 45.404,27.325612 24.484,8.7509 Z"
+       style="color:#000000;opacity:0.13636002;fill:#000000;fill-opacity:1"
+       sodipodi:nodetypes="cccccc"
+       id="path2337" /><path
+       inkscape:connector-curvature="0"
+       d="m 26.946683,27.490623 h 9.210885 c 0.785575,0 1.417294,0.63172 1.417294,1.417294 l -0.0081,9.250622 c 0,0.785574 -0.607267,1.289931 -1.39284,1.289931 h -9.227188 c -0.784555,0 -1.417294,-0.63172 -1.417294,-1.417294 v -9.123259 c 0,-0.785574 0.632739,-1.417294 1.417294,-1.417294 z"
+       style="color:#000000;opacity:0.3181801;fill:none;stroke:#ffffff;stroke-width:1.01888192;stroke-miterlimit:4;stroke-dasharray:none"
+       sodipodi:nodetypes="ccccccccc"
+       id="rect2361" /><rect
+       x="26.507999"
+       y="28.514"
+       width="10.001"
+       height="9.9624996"
+       ry="0.38128"
+       rx="0.38128"
+       style="color:#000000;fill:#ffffff;fill-opacity:0.96169093;stroke:#050505;stroke-width:1.30382288;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="rect3263" /><rect
+       x="26.507999"
+       y="28.514"
+       width="1.9008306"
+       height="10.140061"
+       ry="0.19481476"
+       rx="0.19481476"
+       style="color:#000000;overflow:visible;fill:#000000;fill-opacity:0.10957181;stroke:none;stroke-width:0.66618741;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="rect3263-0" /><rect
+       x="28.408831"
+       y="28.514"
+       width="7.8143654"
+       height="1.8147584"
+       ry="0.19481476"
+       rx="0.19481476"
+       style="color:#000000;overflow:visible;fill:#000000;fill-opacity:0.10957181;stroke:none;stroke-width:0.66618741;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="rect3263-0-6" /></g><metadata
+     id="metadata6453"><rdf:RDF><cc:Work><dc:format>image/svg+xml</dc:format><dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><cc:license
+           rdf:resource="http://creativecommons.org/publicdomain/zero/1.0/" /><dc:publisher><cc:Agent
+             rdf:about="http://openclipart.org/"><dc:title>Openclipart</dc:title></cc:Agent></dc:publisher><dc:title></dc:title><dc:date>2010-03-10T10:25:42</dc:date><dc:description>Home icon from &lt;A href=&quot;http://tango.freedesktop.org/Tango_Desktop_Project&quot;&gt; Tango Project &lt;/A&gt; \n&lt;BR&gt;&lt;BR&gt;\nSince version 0.8.90 Tango Project icons are Public Domain: &lt;A href=&quot;http://tango.freedesktop.org/Frequently_Asked_Questions#Terms_of_Use.3F&quot;&gt; Tango Project FAQ &lt;/A&gt;</dc:description><dc:source>https://openclipart.org/detail/30805/tango-go-home-by-warszawianka</dc:source><dc:creator><cc:Agent><dc:title>warszawianka</dc:title></cc:Agent></dc:creator><dc:subject><rdf:Bag><rdf:li>architecture</rdf:li><rdf:li>building</rdf:li><rdf:li>externalsource</rdf:li><rdf:li>home</rdf:li><rdf:li>house</rdf:li><rdf:li>icon</rdf:li><rdf:li>tango</rdf:li></rdf:Bag></dc:subject></cc:Work><cc:License
+         rdf:about="http://creativecommons.org/publicdomain/zero/1.0/"><cc:permits
+           rdf:resource="http://creativecommons.org/ns#Reproduction" /><cc:permits
+           rdf:resource="http://creativecommons.org/ns#Distribution" /><cc:permits
+           rdf:resource="http://creativecommons.org/ns#DerivativeWorks" /></cc:License></rdf:RDF></metadata><rect
+     style="opacity:1;fill:#ffffff;fill-opacity:0.34886648;fill-rule:nonzero;stroke:none;stroke-width:1.20093751;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+     id="rect7090"
+     width="9.3733196"
+     height="1.0192808"
+     x="13.039264"
+     y="31.150461" /><rect
+     style="overflow:visible;opacity:1;fill:#ffffff;fill-opacity:0.34886648;fill-rule:nonzero;stroke:none;stroke-width:1.20093751;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+     id="rect7090-9"
+     width="0.92969835"
+     height="11.319164"
+     x="13.039264"
+     y="32.169743" /><rect
+     style="overflow:visible;opacity:1;fill:#000000;fill-opacity:0.11712844;fill-rule:nonzero;stroke:none;stroke-width:1.20093751;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+     id="rect7090-9-3"
+     width="0.64861304"
+     height="11.350396"
+     x="21.763969"
+     y="32.138512" /></svg>
\ No newline at end of file
--- a/QTfrontend/res/html/about.html	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/res/html/about.html	Sun Dec 17 00:09:24 2017 +0100
@@ -12,88 +12,94 @@
 <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>
-        Keybinds, feedback, maps and hats interfaces: Drew Gottlieb &lt;<a href="mailto:gottlieb.drew@gmail.com">gottlieb.drew@gmail.com</a>&gt;<br>
-        Login dialogs, frontend improvements: Ondrej Skopek &lt;<a href="mailto:skopekondrej@gmail.com">skopekondrej@gmail.com</a>&gt;<br>
-        Icegun weapon: Julia Struchenko &lt;<a href="mailto:urbertar@gmail.com">urbertar@gmail.com</a>&gt;<br>
-        iPhone/iPad ports: Anton Malmygin &lt;<a href="mailto:antonc27@mail.ru">antonc27@mail.ru</a>&gt;<br>
+        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 />
+        Keybinds, feedback, maps and hats interfaces: Drew Gottlieb &lt;<a href="mailto:gottlieb.drew@gmail.com">gottlieb.drew@gmail.com</a>&gt;<br />
+        Login dialogs, frontend improvements: Ondrej Skopek &lt;<a href="mailto:skopekondrej@gmail.com">skopekondrej@gmail.com</a>&gt;<br />
+        Icegun weapon: Julia Struchenko &lt;<a href="mailto:urbertar@gmail.com">urbertar@gmail.com</a>&gt;<br />
+        iPhone/iPad ports: Anton Malmygin &lt;<a href="mailto:antonc27@mail.ru">antonc27@mail.ru</a>&gt;<br />
+        Battalion style: Anachron &lt;<a href="mailto:Anachron14@gmx.de">Anachron14@gmx.de</a>&gt;<br />
+        Scripting, engine, frontend improvements, some missions: Wuzzy &lt;<a href="mailto:Wuzzy2@mail.ru">Wuzzy2@mail.ru</a>&gt;<br />
+        Theme customization improvements: KoBeWi<br />
+        Theme music, engine and frontend improvements, graphics: Valentin Kraevskiy <!--&lt;<a href="mailto:foo@bar.com">foo@bar.com</a>&gt;--><br />
         </p>
 
         <h2>Art:</h2>
             <p>John Dum &lt;<a href="mailto:fizzy@gmail.com">fizzy@gmail.com</a>&gt;
-            <br>
+            <br />
             Joshua Frese &lt;<a href="mailto:joshfrese@gmail.com">joshfrese@gmail.com</a>&gt;
-            <br>
+            <br />
             Stanko Tadić &lt;<a href="mailto:stanko@mfhinc.net">stanko@mfhinc.net</a>&gt;
-            <br>
+            <br />
             Julien Koesten &lt;<a href="mailto:julienkoesten@aol.com">julienkoesten@aol.com</a>&gt;
-            <br>
+            <br />
             Joshua O'Sullivan &lt;<a href="mailto:coheedftw@hotmail.co.uk">coheedftw@hotmail.co.uk</a>&gt;
-            <br>
+            <br />
             Nils Lück &lt;<a href="mailto:nils.luck.design@gmail.com">nils.luck.design@gmail.com</a>&gt;
-            <br>
+            <br />
             Guillaume Englert &lt;<a href="mailto:genglert@hybird.org">genglert@hybird.org</a>&gt;
-            <br>
+            <br />
+            <p>CopherNeue &lt;<a href="mailto:ppicondo.cvac@gmail.com">ppicondo.cvac@gmail.com</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>
+        <br />
         John Dum &lt;<a href="mailto:fizzy@gmail.com">fizzy@gmail.com</a>&gt;
-        <br>
+        <br />
         Jonatan Nilsson &lt;<a href="mailto:jonatanfan@gmail.com">jonatanfan@gmail.com</a>&gt;
-        <br>
+        <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;, Janne Uusitupa<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;, Matisumi<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;, Wuzzy &lt;<a href="mailto:almikes@aol.com">almikes@aol.com</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 &lt;<a href="mailto:m.bresciani@email.it">m.bresciani@email.it</a>&gt;, Gianfranco Costamagna &lt;<a href="mailto:costamagnagianfranco@yahoo.it">costamagnagianfranco@yahoo.it</a>&gt;<br>
-            Japanese: ADAM Etienne &lt;<a href="mailto:etienne.adam@gmail.com">etienne.adam@gmail.com</a>&gt;, Marco Bresciani &lt;<a href="mailto:m.bresciani@email.it">m.bresciani@email.it</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;, Vitaly Novichkov &lt;<a href="mailto:admin@wohlnet.ru">admin@wohlnet.ru</a>&gt;, Anton Malmygin &lt;<a href="mailto:antonc27@mail.ru">antonc27@mail.ru</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>
+            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;, Janne Uusitupa<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;, Matisumi<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;, Wuzzy &lt;<a href="mailto:Wuzzy2@mail.ru">Wuzzy2@mail.ru</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 &lt;<a href="mailto:m.bresciani@email.it">m.bresciani@email.it</a>&gt;, Gianfranco Costamagna &lt;<a href="mailto:costamagnagianfranco@yahoo.it">costamagnagianfranco@yahoo.it</a>&gt;, Enrico &lt;<a href="mailto:enricobe@hotmail.com">enricobe@hotmail.com</a>&gt;<br />
+            Japanese: ADAM Etienne &lt;<a href="mailto:etienne.adam@gmail.com">etienne.adam@gmail.com</a>&gt;, Marco Bresciani &lt;<a href="mailto:m.bresciani@email.it">m.bresciani@email.it</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, KoBeWi<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;, Vitaly Novichkov &lt;<a href="mailto:admin@wohlnet.ru">admin@wohlnet.ru</a>&gt;, Anton Malmygin &lt;<a href="mailto:antonc27@mail.ru">antonc27@mail.ru</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>
+        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>
Binary file QTfrontend/res/iconInitHealth.png has changed
Binary file QTfrontend/res/missionFinished.png has changed
Binary file QTfrontend/res/missionFinishedSelected.png has changed
Binary file QTfrontend/res/net.png has changed
Binary file QTfrontend/res/schemeicon.png has changed
--- a/QTfrontend/team.cpp	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/team.cpp	Sun Dec 17 00:09:24 2017 +0100
@@ -208,6 +208,14 @@
     return f.exists();
 }
 
+// Returns true if the team name has been changed but a file with the same team name already exists.
+// So if this team would be saved, another team file would be overwritten, which is generally not
+// desired.
+bool HWTeam::wouldOverwriteOtherFile()
+{
+    return (m_name != OldTeamName) && fileExists();
+}
+
 bool HWTeam::deleteFile()
 {
     if(m_isNetTeam)
--- a/QTfrontend/team.h	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/team.h	Sun Dec 17 00:09:24 2017 +0100
@@ -62,6 +62,7 @@
         bool deleteFile();
         bool saveToFile();
         bool fileExists();
+        bool wouldOverwriteOtherFile();
 
         // attribute getters
         unsigned int campaignProgress() const;
--- a/QTfrontend/ui/dialog/bandialog.cpp	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/ui/dialog/bandialog.cpp	Sun Dec 17 00:09:24 2017 +0100
@@ -85,7 +85,13 @@
 {
     if(leId->text().isEmpty())
     {
-        QMessageBox::warning(this, tr("Warning"), tr("Please, specify %1").arg(byIP() ? tr("IP") : tr("nickname")));
+        QString warning_text;
+        if (byIP())
+            warning_text = QString(tr("Please specify an IP address."));
+        else
+            warning_text = QString(tr("Please specify a nickname."));
+
+        QMessageBox::warning(this, tr("Warning"), warning_text);
         return;
     }
 
--- a/QTfrontend/ui/dialog/upload_video.cpp	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/ui/dialog/upload_video.cpp	Sun Dec 17 00:09:24 2017 +0100
@@ -57,7 +57,7 @@
         "<p>By clicking 'upload,' you certify that you own all rights to the content or that "
         "you are authorized by the owner to make the content publicly available on YouTube, "
         "and that it otherwise complies with the YouTube Terms of Service located at "
-        "<a href=\"http://www.youtube.com/t/terms\" style=\"color: white;\">http://www.youtube.com/t/terms</a>.</p>";
+        "<a href=\"https://www.youtube.com/t/terms\" style=\"color: white;\">https://www.youtube.com/t/terms</a>.</p>";
 
     // youtube doesn't understand this characters, even when they are properly escaped
     // (either with CDATA or with &lt or &gt)
--- a/QTfrontend/ui/page/AbstractPage.cpp	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/ui/page/AbstractPage.cpp	Sun Dec 17 00:09:24 2017 +0100
@@ -141,6 +141,13 @@
     return btn;
 }
 
+QPushButton* AbstractPage::addSoundlessButton(const QString & name, QGridLayout * grid, int row, int column, int rowSpan, int columnSpan, bool hasIcon, Qt::Alignment alignment)
+{
+    QPushButton * btn = formattedSoundlessButton(name, hasIcon);
+    grid->addWidget(btn, row, column, rowSpan, columnSpan, alignment);
+    return btn;
+}
+
 QPushButton* AbstractPage::addSoundlessButton(const QString & name, QBoxLayout * box, int where, bool hasIcon, Qt::Alignment alignment)
 {
     QPushButton* btn = formattedSoundlessButton(name, hasIcon);
--- a/QTfrontend/ui/page/AbstractPage.h	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/ui/page/AbstractPage.h	Sun Dec 17 00:09:24 2017 +0100
@@ -190,6 +190,7 @@
          * @return the button.
          */
         QPushButtonWithSound * addButton(const QString & name, QGridLayout * grid, int row, int column, int rowSpan = 1, int columnSpan = 1, bool hasIcon = false, Qt::Alignment alignment = 0);
+        QPushButton * addSoundlessButton(const QString & name, QGridLayout * grid, int row, int column, int rowSpan = 1, int columnSpan = 1, bool hasIcon = false, Qt::Alignment alignment = 0);
 
         /**
          * @brief Creates a default formatted button and adds it to a
--- a/QTfrontend/ui/page/pagecampaign.cpp	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/ui/page/pagecampaign.cpp	Sun Dec 17 00:09:24 2017 +0100
@@ -26,9 +26,10 @@
 QLayout * PageCampaign::bodyLayoutDefinition()
 {
     QGridLayout * pageLayout = new QGridLayout();
-    pageLayout->setColumnStretch(0, 1);
-    pageLayout->setColumnStretch(1, 2);
-    pageLayout->setColumnStretch(2, 1);
+    pageLayout->setColumnStretch(0, 5);
+    pageLayout->setColumnStretch(1, 1);
+    pageLayout->setColumnStretch(2, 9);
+    pageLayout->setColumnStretch(3, 5);
     pageLayout->setRowStretch(0, 1);
     pageLayout->setRowStretch(3, 1);
 
@@ -43,6 +44,7 @@
 
     // set this as default image first time page is created, this will change in hwform.cpp
     btnPreview = formattedButton(":/res/campaign/A_Classic_Fairytale/first_blood.png", true);
+    btnPreview->setWhatsThis(tr("Start fighting"));
     infoLayout->setAlignment(btnPreview, Qt::AlignHCenter | Qt::AlignVCenter);
 
     lbldescription = new QLabel(this);
@@ -52,6 +54,10 @@
     lbltitle = new QLabel();
     lbltitle->setAlignment(Qt::AlignHCenter | Qt::AlignBottom);
 
+    QLabel* lblteam = new QLabel(tr("Team"));
+    QLabel* lblcampaign = new QLabel(tr("Campaign"));
+    QLabel* lblmission = new QLabel(tr("Mission"));
+
     CBTeam = new QComboBox(this);
     CBMission = new QComboBox(this);
     CBCampaign = new QComboBox(this);
@@ -63,19 +69,41 @@
     infoLayout->addWidget(lbltitle,0,2,1,2);
     infoLayout->addWidget(lbldescription,1,2,1,2);
 
-    pageLayout->addLayout(infoLayout, 0, 0, 2, 3);
-    pageLayout->addWidget(CBTeam, 2, 1);
-    pageLayout->addWidget(CBCampaign, 3, 1);
-    pageLayout->addWidget(CBMission, 4, 1);
+    pageLayout->addLayout(infoLayout, 0, 0, 2, 4);
+    pageLayout->addWidget(lblteam, 2, 1);
+    pageLayout->addWidget(lblcampaign, 3, 1);
+    pageLayout->addWidget(lblmission, 4, 1);
+    pageLayout->addWidget(CBTeam, 2, 2);
+    pageLayout->addWidget(CBCampaign, 3, 2);
+    pageLayout->addWidget(CBMission, 4, 2);
 
-    BtnStartCampaign = new QPushButton(this);
-    BtnStartCampaign->setFont(*font14);
-    BtnStartCampaign->setText(QPushButton::tr("Go!"));
-    pageLayout->addWidget(BtnStartCampaign, 3, 2);
 
     return pageLayout;
 }
 
+QLayout * PageCampaign::footerLayoutDefinition()
+{
+    QHBoxLayout * footerLayout = new QHBoxLayout();
+
+    const QIcon& lp = QIcon(":/res/Start.png");
+    QSize sz = lp.actualSize(QSize(65535, 65535));
+    BtnStartCampaign = new QPushButton();
+    BtnStartCampaign->setWhatsThis(tr("Start fighting"));
+    BtnStartCampaign->setStyleSheet("padding: 5px 10px");
+    BtnStartCampaign->setText(QPushButton::tr("Start"));
+    BtnStartCampaign->setMinimumWidth(sz.width() + 60);
+    BtnStartCampaign->setIcon(lp);
+    BtnStartCampaign->setFixedHeight(50);
+    BtnStartCampaign->setIconSize(sz);
+    BtnStartCampaign->setFlat(true);
+    BtnStartCampaign->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+
+    footerLayout->addStretch();
+    footerLayout->addWidget(BtnStartCampaign);
+
+    return footerLayout;
+}
+
 PageCampaign::PageCampaign(QWidget* parent) : AbstractPage(parent)
 {
     initPage();
--- a/QTfrontend/ui/page/pagecampaign.h	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/ui/page/pagecampaign.h	Sun Dec 17 00:09:24 2017 +0100
@@ -38,6 +38,9 @@
 
     protected:
         QLayout * bodyLayoutDefinition();
+
+    private:
+        QLayout * footerLayoutDefinition();
 };
 
 #endif
--- a/QTfrontend/ui/page/pagedata.cpp	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/ui/page/pagedata.cpp	Sun Dec 17 00:09:24 2017 +0100
@@ -54,7 +54,14 @@
     QHBoxLayout * bottomLayout = new QHBoxLayout();
     bottomLayout->setStretch(0, 1);
 
-    pbOpenDir = addButton(tr("Open packages directory"), bottomLayout, 1, false, Qt::AlignBottom);
+    pbHome = addButton(":/res/home.png", bottomLayout, 1, true, Qt::AlignBottom);
+    pbHome->setMinimumHeight(50);
+    pbHome->setMinimumWidth(50);
+    pbHome->setWhatsThis(tr("Load the start page"));
+
+    pbOpenDir = addButton(":/res/folder.png", bottomLayout, 2, true, Qt::AlignBottom);
+    pbOpenDir->setStyleSheet("padding: 5px 10px");
+    pbOpenDir->setWhatsThis(tr("Open packages directory"));
     pbOpenDir->setMinimumHeight(50);
 
     bottomLayout->setStretch(2, 1);
@@ -67,6 +74,7 @@
     connect(web, SIGNAL(anchorClicked(QUrl)), this, SLOT(request(const QUrl&)));
     connect(this, SIGNAL(goBack()), this, SLOT(onPageLeave()));
     connect(pbOpenDir, SIGNAL(clicked()), this, SLOT(openPackagesDir()));
+    connect(pbHome, SIGNAL(clicked()), this, SLOT(fetchList()));
 }
 
 PageDataDownload::PageDataDownload(QWidget* parent) : AbstractPage(parent)
@@ -85,7 +93,12 @@
 void PageDataDownload::request(const QUrl &url)
 {
     QUrl finalUrl;
-    if(url.host().isEmpty())
+    if(url.isEmpty())
+    {
+        qWarning() << "Empty URL requested";
+        return;
+    }
+    else if(url.host().isEmpty())
         finalUrl = QUrl("https://www.hedgewars.org" + url.path());
     else
         finalUrl = url;
@@ -123,22 +136,34 @@
 void PageDataDownload::pageDownloaded()
 {
     QNetworkReply * reply = qobject_cast<QNetworkReply *>(sender());
+    const char *html =
+        "<center><h2>Hedgewars Downloadable Content</h2><br><br>"
+        "<h4><i>%1</i></h4></center>";
 
-    if (reply && (reply->error() == QNetworkReply::NoError)) {
-        QString html = QString::fromUtf8(reply->readAll());
-        int begin = html.indexOf("<!-- BEGIN -->");
-        int end = html.indexOf("<!-- END -->");
-        if(begin != -1 && begin < end)
+    if (reply) {
+        if (reply->error() == QNetworkReply::NoError)
         {
-            html.truncate(end);
-            html.remove(0, begin);
+            QString html = QString::fromUtf8(reply->readAll());
+                    int begin = html.indexOf("<!-- BEGIN -->");
+                    int end = html.indexOf("<!-- END -->");
+                    if(begin != -1 && begin < end)
+                    {
+                        html.truncate(end);
+                        html.remove(0, begin);
+                    }
+                    web->setHtml(html);
         }
-        web->setHtml(html);
-    } else
-        web->setHtml(QString(
-            "<center><h2>Hedgewars Downloadable Content</h2><br><br>"
-            "<p><i><h4>%1</i></h4></p></center>")
-            .arg(tr("This page requires an internet connection.")));
+        else
+        {
+            QString message = reply->error() == QNetworkReply::UnknownNetworkError ?
+                tr("Unknown network error (possibly missing SSL library).") :
+                QString(tr("This feature requires an Internet connection, but you don't appear to be online (error code: %1).")).arg(reply->error());
+            web->setHtml(QString(html).arg(message));
+        }
+    }
+    else {
+        web->setHtml(QString(html).arg(tr("Internal error: Reply object is invalid.")));
+    }
 }
 
 void PageDataDownload::fileDownloaded()
@@ -199,7 +224,6 @@
     request(QUrl("https://hedgewars.org/content.html"));
 }
 
-
 void PageDataDownload::onPageLeave()
 {
     if (m_contentDownloaded)
--- a/QTfrontend/ui/page/pagedata.h	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/ui/page/pagedata.h	Sun Dec 17 00:09:24 2017 +0100
@@ -48,6 +48,7 @@
         QHash<QNetworkReply*, QProgressBar *> progressBars;
         QVBoxLayout *progressBarsLayout;
         QPushButtonWithSound * pbOpenDir;
+        QPushButtonWithSound * pbHome;
 
         bool m_contentDownloaded; ///< true if something was downloaded since last page leave
 
--- a/QTfrontend/ui/page/pageeditteam.cpp	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/ui/page/pageeditteam.cpp	Sun Dec 17 00:09:24 2017 +0100
@@ -32,6 +32,7 @@
 #include "HWApplication.h"
 #include "keybinder.h"
 
+#include "physfs.h"
 #include "DataManager.h"
 #include "hatbutton.h"
 
@@ -77,20 +78,32 @@
         HHNameEdit[i]->setFixedHeight(36);
         HHNameEdit[i]->setWhatsThis(tr("This hedgehog's name"));
         HHNameEdit[i]->setStyleSheet("padding: 6px;");
-        GBHLayout->addWidget(HHNameEdit[i], i + 1, 1);
+        GBHLayout->addWidget(HHNameEdit[i], i + 1, 1, 1, 2);
 
-        btnRandomHogName[i] = addButton(":/res/dice.png", GBHLayout, i + 1, 3, 1, 1, true);
+        btnRandomHogName[i] = addButton(":/res/dice.png", GBHLayout, i + 1, 5, 1, 1, true);
         btnRandomHogName[i]->setFixedHeight(HHNameEdit[i]->height());
         btnRandomHogName[i]->setWhatsThis(tr("Randomize this hedgehog's name"));
     }
 
+    btnRandomHats = new QPushButton();
+    btnRandomHats->setText(tr("Random Hats"));
+    btnRandomHats->setStyleSheet("padding: 6px 10px;");
+    GBHLayout->addWidget(btnRandomHats, 9, 1, 1, 1, Qt::AlignCenter);
+    btnRandomHats->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+
+    btnRandomNames = new QPushButton();
+    btnRandomNames->setText(tr("Random Names"));
+    btnRandomNames->setStyleSheet("padding: 6px 10px;");
+    GBHLayout->addWidget(btnRandomNames, 9, 2, 1, 1, Qt::AlignCenter);
+    btnRandomNames->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+
+    vbox1->addWidget(GBoxHedgehogs);
+
     btnRandomTeam = new QPushButton();
     btnRandomTeam->setText(tr("Random Team"));
     btnRandomTeam->setStyleSheet("padding: 6px 10px;");
-    GBHLayout->addWidget(btnRandomTeam, 9, 0, 1, 4, Qt::AlignCenter);
     btnRandomTeam->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
-
-    vbox1->addWidget(GBoxHedgehogs);
+    vbox1->addWidget(btnRandomTeam, 0, Qt::AlignCenter);
 
     GBoxTeam = new QGroupBox(this);
     GBoxTeam->setTitle(QGroupBox::tr("Team Settings"));
@@ -114,10 +127,12 @@
 
     TeamNameEdit = new QLineEdit(GBoxTeam);
     TeamNameEdit->setMaxLength(64);
-    GBTLayout->addWidget(TeamNameEdit, 0, 1);
+    TeamNameEdit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+    GBTLayout->addWidget(TeamNameEdit, 0, 1, 1, 2);
     vbox2->addWidget(GBoxTeam);
 
     CBTeamLvl = new QComboBox(GBoxTeam);
+    CBTeamLvl->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
     CBTeamLvl->setIconSize(QSize(32, 32));
     CBTeamLvl->addItem(QIcon(":/res/botlevels/small0.png"), QComboBox::tr("Human"));
     for(int i = 5; i > 0; i--)
@@ -126,46 +141,97 @@
             QComboBox::tr("Computer (Level %1)").arg(i)
         );
     CBTeamLvl->setFixedHeight(38);
-    GBTLayout->addWidget(CBTeamLvl, 1, 1);
+    GBTLayout->addWidget(CBTeamLvl, 1, 1, 1, 2);
 
     CBGrave = new QComboBox(GBoxTeam);
+    CBGrave->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
     CBGrave->setMaxCount(65535);
     CBGrave->setMaxVisibleItems(20);
     CBGrave->setIconSize(QSize(32, 32));
     CBGrave->setFixedHeight(44);
-    GBTLayout->addWidget(CBGrave, 2, 1);
+    GBTLayout->addWidget(CBGrave, 2, 1, 1, 2);
 
+    // Player flags, combobox to select flag
     CBFlag = new QComboBox(GBoxTeam);
     CBFlag->setMaxCount(65535);
     CBFlag->setMaxVisibleItems(50);
     CBFlag->setIconSize(QSize(22, 15));
-    GBTLayout->addWidget(CBFlag, 3, 1);
+    CBFlag->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+    GBTLayout->addWidget(CBFlag, 3, 1, 1, 2);
+
+    // CPU level flag. Static image, only displayed when computer player is selected
+    QImage imgBotlevels = QImage("physfs://Graphics/botlevels.png");
+
+    int botlevelOffsets[5]= { 19, 14, 10, 6, 0 };   
+
+    for(int i=0; i<5; i++) {
+        QImage imgCPU = QImage("physfs://Graphics/Flags/cpu.png");
+        QPainter painter(&imgCPU);
+        painter.drawImage(botlevelOffsets[i], 0, imgBotlevels, botlevelOffsets[i]);
+
+        pixCPU[i] = QPixmap::fromImage(imgCPU);
+    }
+
+    QHBoxLayout* hboxCPU = new QHBoxLayout();
+    hboxCPU->setContentsMargins(0, 0, 0, 0);
+
+    hboxCPUWidget = new QWidget();
+    hboxCPUWidget->setLayout(hboxCPU);
 
-    QHBoxLayout * hbox = new QHBoxLayout();
+    CPUFlag = new QLabel();
+    CPUFlag->setPixmap(pixCPU[0]);
+    CPUFlag->setFixedHeight(38);
+
+    hboxCPU->addWidget(CPUFlag);
+
+    CPUFlagLabel = new QLabel("CPU");
+    CPUFlagLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+    hboxCPU->addWidget(CPUFlagLabel);
+
+    hboxCPUWidget->setHidden(true);
+    GBTLayout->addWidget(hboxCPUWidget, 3, 1, 1, 1);
+
+    btnRandomTeamName = addButton(":/res/dice.png", GBTLayout, 0, 3, 1, 1, true);
+    btnRandomTeamName->setWhatsThis(tr("Randomize the team name"));
+
+    btnRandomGrave = addButton(":/res/dice.png", GBTLayout, 2, 3, 1, 1, true);
+    btnRandomGrave->setWhatsThis(tr("Randomize the grave"));
+
+    btnRandomFlag = addButton(":/res/dice.png", GBTLayout, 3, 3, 1, 1, true);
+    btnRandomFlag->setWhatsThis(tr("Randomize the flag"));
+
     CBVoicepack = new QComboBox(GBoxTeam);
     CBVoicepack->setMaxVisibleItems(50);
+    CBVoicepack->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
 
-    hbox->addWidget(CBVoicepack, 100);
-    btnTestSound = addSoundlessButton(":/res/PlaySound.png", hbox, 1, true);
-    btnTestSound->setWhatsThis("Play a random example of this voice");
-    hbox->setStretchFactor(btnTestSound, 1);
+    GBTLayout->addWidget(CBVoicepack, 4, 1, 1, 1);
 
-    GBTLayout->addLayout(hbox, 4, 1);
+    btnTestSound = addSoundlessButton(":/res/PlaySound.png", GBTLayout, 4, 2, 1, 1, true);
+    btnTestSound->setWhatsThis(tr("Play a random example of this voice"));
+
+    btnRandomVoice = addButton(":/res/dice.png", GBTLayout, 4, 3, 1, 1, true);
+    btnRandomVoice->setWhatsThis(tr("Randomize the voice"));
 
     GBoxFort = new QGroupBox(this);
     GBoxFort->setTitle(QGroupBox::tr("Fort"));
     QGridLayout * GBFLayout = new QGridLayout(GBoxFort);
     CBFort = new QComboBox(GBoxFort);
+    CBFort->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
     CBFort->setMaxVisibleItems(25);
     CBFort->setMaxCount(65535);
+
     GBFLayout->addWidget(CBFort, 0, 0);
+
+    btnRandomFort = addButton(":/res/dice.png", GBFLayout, 0, 2, 1, 1, true);
+    btnRandomFort->setWhatsThis(tr("Randomize the fort"));
+
     FortPreview = new SquareLabel(GBoxFort);
     FortPreview->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
     FortPreview->setMinimumSize(128, 128);
     FortPreview->setPixmap(QPixmap());
     // perhaps due to handling its own paintevents, SquareLabel doesn't play nice with the stars
     //FortPreview->setAttribute(Qt::WA_PaintOnScreen, true);
-    GBFLayout->addWidget(FortPreview, 1, 0);
+    GBFLayout->addWidget(FortPreview, 1, 0, 1, 2);
     vbox2->addWidget(GBoxFort);
 
     vbox1->addStretch();
@@ -187,7 +253,7 @@
     signalMapper2 = new QSignalMapper(this);
 
     connect(signalMapper1, SIGNAL(mapped(int)), this, SLOT(fixHHname(int)));
-    connect(signalMapper2, SIGNAL(mapped(int)), this, SLOT(setRandomName(int)));
+    connect(signalMapper2, SIGNAL(mapped(int)), this, SLOT(setRandomHogName(int)));
 
     for(int i = 0; i < HEDGEHOGS_PER_TEAM; i++)
     {
@@ -198,11 +264,21 @@
         signalMapper2->setMapping(btnRandomHogName[i], i);
     }
 
-    connect(btnRandomTeam, SIGNAL(clicked()), this, SLOT(setRandomNames()));
+    connect(btnRandomTeam, SIGNAL(clicked()), this, SLOT(setRandomTeam()));
+    connect(btnRandomNames, SIGNAL(clicked()), this, SLOT(setRandomHogNames()));
+    connect(btnRandomHats, SIGNAL(clicked()), this, SLOT(setRandomHats()));
+
+    connect(CBTeamLvl, SIGNAL(currentIndexChanged(const int)), this, SLOT(CBTeamLvl_activated(const int)));
+
+    connect(btnRandomTeamName, SIGNAL(clicked()), this, SLOT(setRandomTeamName()));
+    connect(btnRandomGrave, SIGNAL(clicked()), this, SLOT(setRandomGrave()));
+    connect(btnRandomFlag, SIGNAL(clicked()), this, SLOT(setRandomFlag()));
+    connect(btnRandomVoice, SIGNAL(clicked()), this, SLOT(setRandomVoice()));
+    connect(btnRandomFort, SIGNAL(clicked()), this, SLOT(setRandomFort()));
 
     connect(btnTestSound, SIGNAL(clicked()), this, SLOT(testSound()));
 
-    connect(CBFort, SIGNAL(currentIndexChanged(const QString &)), this, SLOT(CBFort_activated(const QString &)));
+    connect(CBFort, SIGNAL(currentIndexChanged(const int)), this, SLOT(CBFort_activated(const int)));
 }
 
 PageEditTeam::PageEditTeam(QWidget* parent) :
@@ -236,11 +312,32 @@
 
     CBVoicepack->addItems(list);
 
+    QIcon dlcIcon;
+    dlcIcon.addFile(":/res/dlcMarker.png", QSize(), QIcon::Normal, QIcon::On);
+    dlcIcon.addFile(":/res/dlcMarkerSelected.png", QSize(), QIcon::Selected, QIcon::On);
+    QPixmap emptySpace = QPixmap(7, 15);
+    emptySpace.fill(QColor(0, 0, 0, 0));
+    QIcon notDlcIcon = QIcon(emptySpace);
 
     // forts
     list = dataMgr.entryList("Forts", QDir::Files, QStringList("*L.png"));
-    list.replaceInStrings(QRegExp("L\\.png$"), "");
-    CBFort->addItems(list);
+    foreach (QString file, list)
+    {
+        QString fortPath = PHYSFS_getRealDir(QString("Forts/%1").arg(file).toLocal8Bit().data());
+
+        QString fort = file.replace(QRegExp("L\\.png$"), "");
+
+        bool isDLC = !fortPath.startsWith(datadir->absolutePath());
+        if (isDLC)
+        {
+            CBFort->addItem(dlcIcon, fort, fort);
+        }
+        else
+        {
+            CBFort->addItem(notDlcIcon, fort, fort);
+        }
+
+    }
 
 
     // graves
@@ -314,10 +411,26 @@
         HHNameEdit[idx]->setText(QLineEdit::tr("hedgehog %1").arg(idx+1));
 }
 
-void PageEditTeam::CBFort_activated(const QString & fortname)
+void PageEditTeam::CBFort_activated(const int index)
+{
+    QString fortName = CBFort->itemData(index).toString();
+    QPixmap pix("physfs://Forts/" + fortName + "L.png");
+    FortPreview->setPixmap(pix);
+}
+
+void PageEditTeam::CBTeamLvl_activated(const int index)
 {
-    QPixmap pix("physfs://Forts/" + fortname + "L.png");
-    FortPreview->setPixmap(pix);
+    CBFlag->setHidden(index != 0);
+    btnRandomFlag->setHidden(index != 0);
+
+    if(index > 0) 
+    {
+        int cpuLevel = 6 - index;
+        CPUFlag->setPixmap(pixCPU[cpuLevel - 1]);
+        //: Name of a flag for computer-controlled enemies. %1 is replaced with the computer level
+        CPUFlagLabel->setText(tr("CPU %1").arg(cpuLevel));
+    }
+    hboxCPUWidget->setHidden(index == 0);
 }
 
 void PageEditTeam::testSound()
@@ -346,8 +459,16 @@
 {
     m_playerHash = playerHash;
     lazyLoad();
+    OldTeamName = name;
 
+    // Mostly create a default team, with 2 important exceptions:
     HWTeam newTeam(name);
+    // Randomize grave to make it less likely that default teams have equal graves (important for resurrector)
+    HWNamegen::teamRandomGrave(newTeam, false);
+    // Randomize fort for greater variety in fort mode with default teams
+    HWNamegen::teamRandomFort(newTeam, false);
+    // DLC forts and graves intentionally filtered out to prevent desyncs and missing grave error
+    // TODO: Remove DLC filter as soon it is not needed anymore
     loadTeam(newTeam);
 }
 
@@ -355,6 +476,7 @@
 {
     m_playerHash = playerHash;
     lazyLoad();
+    OldTeamName = name;
 
     HWTeam team(name);
     team.loadFromFile();
@@ -374,17 +496,66 @@
         HWTeam(name).deleteFile();
 }
 
-void PageEditTeam::setRandomNames()
+void PageEditTeam::setRandomTeam()
+{
+    HWTeam team = data();
+    HWNamegen::teamRandomEverything(team);
+    loadTeam(team);
+}
+
+void PageEditTeam::setRandomHogNames()
 {
     HWTeam team = data();
-    HWNamegen::teamRandomNames(team, true);
+    HWNamegen::teamRandomHogNames(team);
+    loadTeam(team);
+}
+
+void PageEditTeam::setRandomHats()
+{
+    HWTeam team = data();
+    HWNamegen::teamRandomHats(team);
+    loadTeam(team);
+}
+
+void PageEditTeam::setRandomHogName(int hh_index)
+{
+    HWTeam team = data();
+    HWNamegen::teamRandomHogName(team,hh_index);
     loadTeam(team);
 }
 
-void PageEditTeam::setRandomName(int hh_index)
+void PageEditTeam::setRandomTeamName()
+{
+    HWTeam team = data();
+    HWNamegen::teamRandomTeamName(team);
+    loadTeam(team);
+}
+
+void PageEditTeam::setRandomGrave()
 {
     HWTeam team = data();
-    HWNamegen::teamRandomName(team,hh_index);
+    HWNamegen::teamRandomGrave(team);
+    loadTeam(team);
+}
+
+void PageEditTeam::setRandomFlag()
+{
+    HWTeam team = data();
+    HWNamegen::teamRandomFlag(team);
+    loadTeam(team);
+}
+
+void PageEditTeam::setRandomVoice()
+{
+    HWTeam team = data();
+    HWNamegen::teamRandomVoice(team);
+    loadTeam(team);
+}
+
+void PageEditTeam::setRandomFort()
+{
+    HWTeam team = data();
+    HWNamegen::teamRandomFort(team);
     loadTeam(team);
 }
 
@@ -411,7 +582,7 @@
     CBGrave->setCurrentIndex(CBGrave->findText(team.grave()));
     CBFlag->setCurrentIndex(CBFlag->findData(team.flag()));
 
-    CBFort->setCurrentIndex(CBFort->findText(team.fort()));
+    CBFort->setCurrentIndex(CBFort->findData(team.fort()));
     CBVoicepack->setCurrentIndex(CBVoicepack->findText(team.voicepack()));
 
     QStandardItemModel * binds = DataManager::instance().bindsModel();
@@ -430,7 +601,8 @@
 
 HWTeam PageEditTeam::data()
 {
-    HWTeam team(TeamNameEdit->text());
+    HWTeam team(OldTeamName);
+    team.setName(TeamNameEdit->text());
     team.setDifficulty(CBTeamLvl->currentIndex());
 
     for(int i = 0; i < HEDGEHOGS_PER_TEAM; i++)
@@ -446,7 +618,7 @@
     }
 
     team.setGrave(CBGrave->currentText());
-    team.setFort(CBFort->currentText());
+    team.setFort(CBFort->itemData(CBFort->currentIndex()).toString());
     team.setVoicepack(CBVoicepack->currentText());
     team.setFlag(CBFlag->itemData(CBFlag->currentIndex()).toString());
 
@@ -461,7 +633,35 @@
 
 void PageEditTeam::saveTeam()
 {
-    data().saveToFile();
+    HWTeam team = data();
+    if(!team.wouldOverwriteOtherFile())
+    {
+        team.saveToFile();
+    }
+    else
+    {
+        // Name already used -> look for an appropriate name:
+        int i=2;
+        QString origName = team.name();
+        QString newName;
+        while(team.wouldOverwriteOtherFile())
+        {
+            newName = tr("%1 (%2)").arg(origName).arg(i++);
+            team.setName(newName);
+            if(i > 1000)
+                break;
+        }
+
+        QMessageBox teamNameFixedMsg(this);
+        teamNameFixedMsg.setIcon(QMessageBox::Warning);
+        teamNameFixedMsg.setWindowTitle(QMessageBox::tr("Teams - Name already taken"));
+        teamNameFixedMsg.setText(QMessageBox::tr("The team name '%1' is already taken, so your team has been renamed to '%2'.").arg(origName).arg(team.name()));
+        teamNameFixedMsg.setWindowModality(Qt::WindowModal);
+        teamNameFixedMsg.setStandardButtons(QMessageBox::Ok);
+        teamNameFixedMsg.exec();
+
+        team.saveToFile();
+    }
 }
 
 // When the "Use default for all binds" is pressed...
--- a/QTfrontend/ui/page/pageeditteam.h	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/ui/page/pageeditteam.h	Sun Dec 17 00:09:24 2017 +0100
@@ -43,7 +43,8 @@
         void deleteTeam(const QString & name);
 
     public slots:
-        void CBFort_activated(const QString & gravename);
+        void CBTeamLvl_activated(const int index);
+        void CBFort_activated(const int index);
 
     private:
         QTabWidget * tbw;
@@ -56,6 +57,10 @@
         SquareLabel *FortPreview;
         QComboBox *CBGrave;
         QComboBox *CBFlag;
+        QLabel *CPUFlag;
+        QLabel *CPUFlagLabel;
+        QWidget *hboxCPUWidget;
+        QPixmap pixCPU[5];
         QComboBox *CBTeamLvl;
         QComboBox *CBVoicepack;
         QGroupBox *GBoxBinds;
@@ -65,6 +70,7 @@
         HatButton * HHHats[HEDGEHOGS_PER_TEAM];
         HWTeam data();
         QString m_playerHash;
+        QString OldTeamName;
         KeyBinder * binder;
         bool m_loaded;
 
@@ -75,17 +81,33 @@
         void loadTeam(const HWTeam & team);
 
         // page 1
+        QPushButton * btnRandomTeam;
+        QPushButton * btnRandomNames;
+        QPushButton * btnRandomHats;
+
         QPushButton * btnRandomHogName[HEDGEHOGS_PER_TEAM];
-        QPushButton * btnRandomTeam;
+        QPushButton * btnRandomTeamName;
+        QPushButton * btnRandomGrave;
+        QPushButton * btnRandomFlag;
+        QPushButton * btnRandomVoice;
+        QPushButton * btnRandomFort;
         QPushButton * btnTestSound;
 
         void lazyLoad();
 
     private slots:
         void saveTeam();
-        void setRandomNames();
+        void setRandomTeam();
+        void setRandomHogNames();
+        void setRandomHats();
 
-        void setRandomName(int hh_index);
+        void setRandomTeamName();
+        void setRandomGrave();
+        void setRandomFlag();
+        void setRandomVoice();
+        void setRandomFort();
+
+        void setRandomHogName(int hh_index);
 
         /// Plays a random voice sound of the currently edited team.
         void testSound();
--- a/QTfrontend/ui/page/pagegamestats.cpp	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/ui/page/pagegamestats.cpp	Sun Dec 17 00:09:24 2017 +0100
@@ -148,6 +148,7 @@
     labelGameStats->setText("");
     healthPoints.clear();
     labelGameRank->setText("");
+    labelGameWin->setText("");
     playerPosition = 0;
     lastColor = 0;
 }
@@ -301,8 +302,10 @@
             QString message;
             QString killstring;
             if(kindOfPoints.compare("") == 0) {
+                //: Number of kills in stats screen, written after the team name
                 killstring = PageGameStats::tr("(%1 kill)", "", kills).arg(kills);
             } else {
+                //: For custom number of points in the stats screen, written after the team name. %1 is the number, %2 is the word. Example: “4 points”
                 killstring = PageGameStats::tr("(%1 %2)", "", kills).arg(kills).arg(kindOfPoints);
                 kindOfPoints = QString("");
             }
@@ -316,7 +319,7 @@
         {
             int i = info.indexOf(' ');
             int num = info.left(i).toInt();
-            QString message = "<p><img src=\":/res/StatsMostSelfDamage.png\"> " + PageGameStats::tr("<b>%1</b> thought it's good to shoot his own hedgehogs with <b>%2</b> pts.", "", num).arg(info.mid(i + 1)).arg(num) + "</p>";
+            QString message = "<p><img src=\":/res/StatsMostSelfDamage.png\"> " + PageGameStats::tr("<b>%1</b> thought it's good to shoot their own hedgehogs for <b>%2</b> pts.", "", num).arg(info.mid(i + 1)).arg(num) + "</p>";
             AddStatText(message);
             break;
         }
@@ -324,7 +327,7 @@
         {
             int i = info.indexOf(' ');
             int num = info.left(i).toInt();
-            QString message = "<p><img src=\":/res/StatsSelfKilled.png\"> " + PageGameStats::tr("<b>%1</b> killed <b>%2</b> of his own hedgehogs.", "", num).arg(info.mid(i + 1)).arg(num) + "</p>";
+            QString message = "<p><img src=\":/res/StatsSelfKilled.png\"> " + PageGameStats::tr("<b>%1</b> killed <b>%2</b> of their own hedgehogs.", "", num).arg(info.mid(i + 1)).arg(num) + "</p>";
             AddStatText(message);
             break;
         }
--- a/QTfrontend/ui/page/pageinfo.cpp	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/ui/page/pageinfo.cpp	Sun Dec 17 00:09:24 2017 +0100
@@ -41,7 +41,7 @@
 {
     QHBoxLayout * bottomLayout = new QHBoxLayout();
     bottomLayout->setContentsMargins(0,0,0,0);
-    BtnSnapshots = addButton(":/res/Star.png", bottomLayout, 0, true, Qt::AlignBottom);
+    BtnSnapshots = addButton(":/res/folder.png", bottomLayout, 0, true, Qt::AlignBottom);
     BtnSnapshots->setWhatsThis(tr("Open the snapshot folder"));
     BtnSnapshots->setMinimumSize(50,50);
     return bottomLayout;
--- a/QTfrontend/ui/page/pagemultiplayer.cpp	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/ui/page/pagemultiplayer.cpp	Sun Dec 17 00:09:24 2017 +0100
@@ -34,10 +34,12 @@
     QHBoxLayout * pageLayout = new QHBoxLayout();
 
     gameCFG = new GameCFGWidget(this);
-    pageLayout->addWidget(gameCFG, 3, Qt::AlignTop);
+    pageLayout->addWidget(gameCFG);
+    pageLayout->setAlignment(gameCFG, Qt::AlignTop);
 
     teamsSelect = new TeamSelWidget(this);
-    pageLayout->addWidget(teamsSelect, 2, Qt::AlignTop);
+    pageLayout->addWidget(teamsSelect);
+    teamsSelect->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
 
     return pageLayout;
 }
@@ -59,14 +61,14 @@
     const QIcon& lp = QIcon(":/res/Start.png");
     QSize sz = lp.actualSize(QSize(65535, 65535));
     BtnStartMPGame = new QPushButton();
+    BtnStartMPGame->setStyleSheet("padding: 5px 10px");
     BtnStartMPGame->setText(tr("Start"));
     BtnStartMPGame->setWhatsThis(tr("Start fighting (requires at least 2 teams)"));
-    BtnStartMPGame->setMinimumWidth(sz.width() + 60);
     BtnStartMPGame->setIcon(lp);
     BtnStartMPGame->setFixedHeight(50);
     BtnStartMPGame->setIconSize(sz);
     BtnStartMPGame->setFlat(true);
-    BtnStartMPGame->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+    BtnStartMPGame->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
 
     footerLayout->addStretch();
     footerLayout->addWidget(BtnStartMPGame, 0, Qt::AlignBottom);
--- a/QTfrontend/ui/page/pagenetgame.cpp	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/ui/page/pagenetgame.cpp	Sun Dec 17 00:09:24 2017 +0100
@@ -50,7 +50,7 @@
 
     leRoomName = new HistoryLineEdit(this, 10);
     leRoomName->setWhatsThis(tr("Room name"));
-    leRoomName->setMaxLength(60);
+    leRoomName->setMaxLength(40);
     leRoomName->setMinimumWidth(400);
     leRoomName->setMaximumWidth(600);
     leRoomName->setFixedHeight(30);
--- a/QTfrontend/ui/page/pagenetserver.cpp	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/ui/page/pagenetserver.cpp	Sun Dec 17 00:09:24 2017 +0100
@@ -83,7 +83,7 @@
     labelURL->setText(
               "<style type=\"text/css\"> a { color: #ffcc00; } </style>"
               "<div align=\"center\">"
-              "<a href=\"hedgewars.org/kb/HWPlaySchemeSyntax\">" +
+              "<a href=\"https://hedgewars.org/kb/HWPlaySchemeSyntax\">" +
               tr("Click here for details") +
               "</a></div>");
     labelURL->setOpenExternalLinks(true);
--- a/QTfrontend/ui/page/pageoptions.cpp	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/ui/page/pageoptions.cpp	Sun Dec 17 00:09:24 2017 +0100
@@ -32,6 +32,7 @@
 #include <QSlider>
 #include <QSignalMapper>
 #include <QColorDialog>
+#include <QMessageBox>
 #include <QStandardItemModel>
 #include <QDebug>
 
@@ -167,7 +168,7 @@
         }
 
         { // group: schemes
-            OptionGroupBox * groupSchemes = new OptionGroupBox(":/res/weaponsicon.png", tr("Schemes"), this);
+            OptionGroupBox * groupSchemes = new OptionGroupBox(":/res/schemeicon.png", tr("Schemes"), this);
             leftColumn->addWidget(groupSchemes);
 
             groupSchemes->layout()->setColumnStretch(0, 1);
@@ -275,7 +276,8 @@
             groupGame->layout()->addWidget(winResContainer, 2, 1);
 
             QLabel *winLabelX = new QLabel(groupGame);
-            winLabelX->setText("x"); // decorational x
+            //: Multiplication sign, to be used between two numbers. Note the “x” is only a dummy character, we recommend to use “×” if your language permits it
+            winLabelX->setText(tr("x"));
             winLabelX->setFixedWidth(40);
             winLabelX->setAlignment(Qt::AlignCenter);
 
@@ -310,10 +312,11 @@
             // Stereo spacing
 
             QLabel * lblStereo = new QLabel(groupGame);
-            lblStereo->setText(QLabel::tr("Stereo rendering"));
+            lblStereo->setText(QLabel::tr("Stereoscopy"));
             groupGame->layout()->addWidget(lblStereo, 4, 0);
 
             CBStereoMode = new QComboBox(groupGame);
+            CBStereoMode->setWhatsThis(QComboBox::tr("Stereoscopy creates an illusion of depth when you wear 3D glasses."));
             CBStereoMode->setMaxVisibleItems(50);
             CBStereoMode->addItem(QComboBox::tr("Disabled"));
             CBStereoMode->addItem(QComboBox::tr("Red/Cyan"));
@@ -406,7 +409,7 @@
         }
 
         { // group: frontend
-            OptionGroupBox * groupFrontend = new OptionGroupBox(":/res/graphicsicon.png", tr("Frontend"), this);
+            OptionGroupBox * groupFrontend = new OptionGroupBox(":/res/frontendicon.png", tr("Frontend"), this);
             rightColumn->addWidget(groupFrontend);
 
             // Fullscreen
@@ -419,11 +422,12 @@
 
             CBFrontendEffects = new QCheckBox(groupFrontend);
             CBFrontendEffects->setText(QCheckBox::tr("Visual effects"));
+            CBFrontendEffects->setWhatsThis(QCheckBox::tr("Enable visual effects such as animated menu transitions and falling stars"));
             groupFrontend->layout()->addWidget(CBFrontendEffects, 1, 0);
         }
 
         { // group: colors
-            OptionGroupBox * groupColors = new OptionGroupBox(":/res/lightbulb_on.png", tr("Custom colors"), this);
+            OptionGroupBox * groupColors = new OptionGroupBox(":/res/Palette.png", tr("Custom colors"), this);
             rightColumn->addWidget(groupColors);
 
             groupColors->layout()->setColumnStretch(0, 1);
@@ -626,12 +630,41 @@
             CBLanguage->setMaxVisibleItems(50);
             groupMisc->layout()->addWidget(CBLanguage, 0, 1);
             QStringList locs = DataManager::instance().entryList("Locale", QDir::Files, QStringList("hedgewars_*.qm"));
+            QStringList langnames;
             CBLanguage->addItem(QComboBox::tr("(System default)"), QString());
             for(int i = 0; i < locs.count(); i++)
             {
                 QString lname = locs[i].replace(QRegExp("hedgewars_(.*)\\.qm"), "\\1");
-                QLocale loc(lname);
-                CBLanguage->addItem(QLocale::languageToString(loc.language()) + " (" + QLocale::countryToString(loc.country()) + ")", lname);
+                QLocale loc = QLocale(lname);
+                QString entryName;
+                // If local identifier has underscore, it means the country has been specified
+                if(lname.contains("_"))
+                {
+                    // Append country name for disambiguation
+                    // FIXME: These brackets are hardcoded and can't be translated. Luckily, these are rarely used and work with most languages anyway
+                    entryName = loc.nativeLanguageName() + " (" + loc.nativeCountryName() + ")";
+                }
+                else
+                {
+                    // Usually, we just print the language name
+                    entryName = loc.nativeLanguageName();
+                }
+                // Fallback code, if language name is empty for some reason. This should normally not happen
+                if(entryName.isEmpty())
+                {
+                    if(lname == "gd")
+                    {
+                        /* Workaround for Qt4: nativeLanguageName does not return correct name for Scottish Gaelic (QTBUG-59929),
+                           so we have to add it ourselves :-/ */
+                        entryName = QString::fromUtf8("Gàidhlig");
+                    }
+                    else
+                    {
+                        // If all else fails, show error and the locale identifier
+                        entryName = tr("MISSING LANGUAGE NAME [%1]").arg(lname);
+                    }
+                }
+                CBLanguage->addItem(entryName, lname);
             }
 
             QLabel *restartNoticeLabel = new QLabel(groupMisc);
@@ -647,6 +680,7 @@
 
             CBNameWithDate = new QCheckBox(groupMisc);
             CBNameWithDate->setText(QCheckBox::tr("Append date and time to record file name"));
+            CBNameWithDate->setWhatsThis(QCheckBox::tr("If enabled, Hedgewars adds the date and time in the form \"YYYY-MM-DD_hh-mm\" for automatically created demos."));
             groupMisc->layout()->addWidget(CBNameWithDate, 3, 0, 1, 2);
 
             // Associate file extensions
@@ -674,7 +708,7 @@
             btnUpdateNow = new QPushButton(groupUpdates);
             connect(btnUpdateNow, SIGNAL(clicked()), this, SLOT(checkForUpdates()));
             btnUpdateNow->setWhatsThis(tr("Check for updates"));
-            btnUpdateNow->setText("Check now");
+            btnUpdateNow->setText(tr("Check now"));
             btnUpdateNow->setFixedSize(130, 30);
             groupUpdates->layout()->addWidget(btnUpdateNow, 0, 1);
         }
@@ -764,10 +798,10 @@
         widthEdit->setValidator(new QIntValidator(this));
         groupVideoRec->layout()->addWidget(widthEdit, 5, 1);
 
-        // x
+        // multiplication sign
 
         QLabel *labelX = new QLabel(groupVideoRec);
-        labelX->setText("X");
+        labelX->setText(tr("x"));
         groupVideoRec->layout()->addWidget(labelX, 5, 2);
 
         // height
@@ -789,17 +823,18 @@
         groupVideoRec->layout()->addWidget(labelFramerate, 6, 0);
 
         framerateBox = new QComboBox(groupVideoRec);
-        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);
+        framerateBox->addItem(QComboBox::tr("24 FPS"), 24);
+        framerateBox->addItem(QComboBox::tr("25 FPS"), 25);
+        framerateBox->addItem(QComboBox::tr("30 FPS"), 30);
+        framerateBox->addItem(QComboBox::tr("50 FPS"), 50);
+        framerateBox->addItem(QComboBox::tr("60 FPS"), 60);
         groupVideoRec->layout()->addWidget(framerateBox, 6, 1);
 
         // label for Bitrate
 
         QLabel *labelBitrate = new QLabel(groupVideoRec);
-        labelBitrate->setText(QLabel::tr("Bitrate (Kbps)"));
+        //: “Kibit/s” is the symbol for 1024 bits per second
+        labelBitrate->setText(QLabel::tr("Bitrate (Kibit/s)"));
         groupVideoRec->layout()->addWidget(labelBitrate, 6, 2);
 
         // bitrate
@@ -807,6 +842,7 @@
         bitrateBox = new QSpinBox(groupVideoRec);
         bitrateBox->setRange(100, 5000);
         bitrateBox->setSingleStep(100);
+        bitrateBox->setWhatsThis(QSpinBox::tr("Specify the bitrate of recorded videos as a multiple of 1024 bits per second"));
         groupVideoRec->layout()->addWidget(bitrateBox, 6, 3);
 
         // button 'set default options'
@@ -951,7 +987,10 @@
 
 void PageOptions::requestDeleteSelectedTeam()
 {
-    emit deleteTeamRequested(CBTeamName->currentText());
+    if(CBTeamName->count() > 1)
+        emit deleteTeamRequested(CBTeamName->currentText());
+    else
+        QMessageBox::warning(this, tr("Can't delete last team"), tr("You can't delete the last team!"));
 }
 
 void PageOptions::setTeamOptionsEnabled(bool enabled)
--- a/QTfrontend/ui/page/pageplayrecord.cpp	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/ui/page/pageplayrecord.cpp	Sun Dec 17 00:09:24 2017 +0100
@@ -62,7 +62,7 @@
     BtnPlayDemo = addButton(tr("Play demo"), bottomLayout, 0, false, Qt::AlignBottom);
     const QIcon& lp = QIcon(":/res/Start.png");
     QSize sz = lp.actualSize(QSize(65535, 65535));
-    BtnPlayDemo->setMinimumWidth(sz.width());
+    BtnPlayDemo->setStyleSheet("padding: 5px 10px");
     BtnPlayDemo->setIcon(lp);
     BtnPlayDemo->setFixedHeight(50);
     BtnPlayDemo->setIconSize(sz);
@@ -136,8 +136,8 @@
     {
         QMessageBox recordMsg(this);
         recordMsg.setIcon(QMessageBox::Warning);
-        recordMsg.setWindowTitle(QMessageBox::tr("Record Play - Error"));
-        recordMsg.setText(QMessageBox::tr("Please select record from the list"));
+        recordMsg.setWindowTitle(QMessageBox::tr("Error"));
+        recordMsg.setText(QMessageBox::tr("Please select a file from the list."));
         recordMsg.setWindowModality(Qt::WindowModal);
         recordMsg.exec();
         return ;
@@ -163,8 +163,8 @@
         {
             QMessageBox renameMsg(this);
             renameMsg.setIcon(QMessageBox::Warning);
-            renameMsg.setWindowTitle(QMessageBox::tr("Record Play - Error"));
-            renameMsg.setText(QMessageBox::tr("Cannot rename to ") + newfullname);
+            renameMsg.setWindowTitle(QMessageBox::tr("Error"));
+            renameMsg.setText(QMessageBox::tr("Cannot rename file to %1.").arg(newfullname));
             renameMsg.setWindowModality(Qt::WindowModal);
             renameMsg.exec();
         }
@@ -180,8 +180,8 @@
     {
         QMessageBox recordMsg(this);
         recordMsg.setIcon(QMessageBox::Warning);
-        recordMsg.setWindowTitle(QMessageBox::tr("Record Play - Error"));
-        recordMsg.setText(QMessageBox::tr("Please select record from the list"));
+        recordMsg.setWindowTitle(QMessageBox::tr("Error"));
+        recordMsg.setText(QMessageBox::tr("Please select a file from the list."));
         recordMsg.setWindowModality(Qt::WindowModal);
         recordMsg.exec();
         return ;
@@ -195,8 +195,8 @@
     {
         QMessageBox removeMsg(this);
         removeMsg.setIcon(QMessageBox::Warning);
-        removeMsg.setWindowTitle(QMessageBox::tr("Record Play - Error"));
-        removeMsg.setText(QMessageBox::tr("Cannot delete file ") + rfile.fileName());
+        removeMsg.setWindowTitle(QMessageBox::tr("Error"));
+        removeMsg.setText(QMessageBox::tr("Cannot delete file %1.").arg(rfile.fileName()));
         removeMsg.setWindowModality(Qt::WindowModal);
         removeMsg.exec();
     }
--- a/QTfrontend/ui/page/pageroomslist.cpp	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/ui/page/pageroomslist.cpp	Sun Dec 17 00:09:24 2017 +0100
@@ -176,6 +176,7 @@
 
     BtnAdmin = addButton(tr("Admin features"), bottomLayout, 0, false, Qt::AlignBottom);
     BtnAdmin->setMinimumSize(180, 50);
+    BtnAdmin->setStyleSheet("padding: 5px 10px");
     BtnAdmin->setWhatsThis(tr("Open server administration page"));
 
     return bottomLayout;
--- a/QTfrontend/ui/page/pagescheme.cpp	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/ui/page/pagescheme.cpp	Sun Dec 17 00:09:24 2017 +0100
@@ -68,25 +68,21 @@
     gbBasicSettings->setLayout(glBSLayout);
     // Left
 
-    TBW_mode_Forts = new ToggleButtonWidget(gbGameModes, ":/res/btnForts@2x.png");
-    TBW_mode_Forts->setWhatsThis(tr("Defend your fort and destroy the opponents, two team colours max!"));
-    glGMLayout->addWidget(TBW_mode_Forts,0,0,1,1);
-
     TBW_disablegirders = new ToggleButtonWidget(gbGameModes, ":/res/btnDisableGirders@2x.png");
     TBW_disablegirders->setWhatsThis(tr("Disable girders when generating random maps."));
-    glGMLayout->addWidget(TBW_disablegirders,0,1,1,1);
+    glGMLayout->addWidget(TBW_disablegirders,0,0,1,1);
 
     TBW_disablelandobjects = new ToggleButtonWidget(gbGameModes, ":/res/btnDisableLandObjects@2x.png");
     TBW_disablelandobjects->setWhatsThis(tr("Disable land objects when generating random maps."));
-    glGMLayout->addWidget(TBW_disablelandobjects,0,2,1,1);
+    glGMLayout->addWidget(TBW_disablelandobjects,0,1,1,1);
 
     TBW_border = new ToggleButtonWidget(gbGameModes, ":/res/btnBorder@2x.png");
     TBW_border->setWhatsThis(tr("Add an indestructible border around the terrain"));
-    glGMLayout->addWidget(TBW_border,0,3,1,1);
+    glGMLayout->addWidget(TBW_border,0,2,1,1);
 
     TBW_bottomborder = new ToggleButtonWidget(gbGameModes, ":/res/btnBottomBorder@2x.png");
     TBW_bottomborder->setWhatsThis(tr("Add an indestructible border along the bottom"));
-    glGMLayout->addWidget(TBW_bottomborder,0,4,1,1);
+    glGMLayout->addWidget(TBW_bottomborder,0,3,1,1);
 
     TBW_solid = new ToggleButtonWidget(gbGameModes, ":/res/btnSolid@2x.png");
     TBW_solid->setWhatsThis(tr("Land can not be destroyed!"));
@@ -232,11 +228,11 @@
     l = new QLabel(gbBasicSettings);
     l->setWhatsThis(wtInitHealth);
     l->setFixedSize(32,32);
-    l->setPixmap(QPixmap(":/res/iconHealth.png"));
+    l->setPixmap(QPixmap(":/res/iconInitHealth.png"));
     glBSLayout->addWidget(l,2,1,1,1);
     SB_InitHealth = new QSpinBox(gbBasicSettings);
     SB_InitHealth->setWhatsThis(wtInitHealth);
-    SB_InitHealth->setRange(50, 200);
+    SB_InitHealth->setRange(1, 1000);
     SB_InitHealth->setValue(100);
     SB_InitHealth->setSingleStep(25);
     glBSLayout->addWidget(SB_InitHealth,2,2,1,1);
@@ -287,7 +283,7 @@
     glBSLayout->addWidget(l,5,1,1,1);
     SB_HealthDecrease = new QSpinBox(gbBasicSettings);
     SB_HealthDecrease->setWhatsThis(wtHealthDecrease);
-    SB_HealthDecrease->setRange(0, 100);
+    SB_HealthDecrease->setRange(0, 1000);
     SB_HealthDecrease->setValue(5);
     SB_HealthDecrease->setSingleStep(1);
     glBSLayout->addWidget(SB_HealthDecrease,5,2,1,1);
@@ -354,7 +350,7 @@
     glBSLayout->addWidget(l,9,1,1,1);
     SB_CrateHealth = new QSpinBox(gbBasicSettings);
     SB_CrateHealth->setWhatsThis(wtCrateHealth);
-    SB_CrateHealth->setRange(0, 200);
+    SB_CrateHealth->setRange(0, 1000);
     SB_CrateHealth->setValue(25);
     SB_CrateHealth->setSingleStep(5);
     glBSLayout->addWidget(SB_CrateHealth,9,2,1,1);
@@ -503,7 +499,7 @@
     l->setText(QLabel::tr("Scheme Name:"));
 
     LE_name = new QLineEdit(this);
-    LE_name->setWhatsThis("Name of this scheme");
+    LE_name->setWhatsThis(tr("Name of this scheme"));
 
     gl->addWidget(LE_name,15,1,1,5);
     gl->addWidget(l,15,0,1,1);
@@ -550,7 +546,6 @@
     selectScheme->setModel(model);
 
     mapper->addMapping(LE_name, 0);
-    mapper->addMapping(TBW_mode_Forts, 1);
     mapper->addMapping(TBW_teamsDivide, 2);
     mapper->addMapping(TBW_solid, 3);
     mapper->addMapping(TBW_border, 4);
--- a/QTfrontend/ui/page/pagescheme.h	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/ui/page/pagescheme.h	Sun Dec 17 00:09:24 2017 +0100
@@ -51,7 +51,6 @@
 
     private:
         QDataWidgetMapper * mapper;
-        ToggleButtonWidget * TBW_mode_Forts;
         ToggleButtonWidget * TBW_teamsDivide;
         ToggleButtonWidget * TBW_solid;
         ToggleButtonWidget * TBW_border;
--- a/QTfrontend/ui/page/pageselectweapon.cpp	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/ui/page/pageselectweapon.cpp	Sun Dec 17 00:09:24 2017 +0100
@@ -30,6 +30,7 @@
     QGridLayout * pageLayout = new QGridLayout();
 
     pWeapons = new SelWeaponWidget(cAmmoNumber, this);
+    pWeapons->init();
     pageLayout->addWidget(pWeapons);
 
     return pageLayout;
@@ -59,11 +60,12 @@
 
 void PageSelectWeapon::connectSignals()
 {
+    connect(selectWeaponSet, SIGNAL(currentIndexChanged(const QString&)), pWeapons, SLOT(switchWeapons(const QString&)));
     connect(BtnDefault, SIGNAL(clicked()), pWeapons, SLOT(setDefault()));
     connect(this, SIGNAL(goBack()), pWeapons, SLOT(save()));
     connect(BtnNew, SIGNAL(clicked()), pWeapons, SLOT(newWeaponsName()));
     connect(BtnCopy, SIGNAL(clicked()), pWeapons, SLOT(copy()));
-    connect(selectWeaponSet, SIGNAL(currentIndexChanged(const QString&)), pWeapons, SLOT(setWeaponsName(const QString&)));
+    connect(BtnDelete, SIGNAL(clicked()), pWeapons, SLOT(deleteWeaponsName()));
 }
 
 PageSelectWeapon::PageSelectWeapon(QWidget* parent) :  AbstractPage(parent)
--- a/QTfrontend/ui/page/pagetraining.cpp	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/ui/page/pagetraining.cpp	Sun Dec 17 00:09:24 2017 +0100
@@ -73,14 +73,29 @@
     pageLayout->setAlignment(infoLayout, Qt::AlignLeft);
 
 
-    // mission list
-    lstMissions = new QListWidget(this);
-    lstMissions->setWhatsThis(tr("Pick the mission or training to play"));
-    pageLayout->addWidget(lstMissions, 1, 0, 1, 2); // span 2 columns
+    // tab widget containing all lists
+    tbw = new QTabWidget(this);
+    pageLayout->addWidget(tbw, 1, 0, 1, 2); // span 2 columns
+    // let's not make the tab widget use more space than needed
+    tbw->setFixedWidth(400);
+    pageLayout->setAlignment(tbw, Qt::AlignHCenter);
+    
+    tbw->setStyleSheet("QListWidget { border-style: none; padding-top: 6px; }");
 
-    // let's not make the list use more space than needed
-    lstMissions->setFixedWidth(400);
-    pageLayout->setAlignment(lstMissions, Qt::AlignHCenter);
+    // training/challenge/scenario lists
+    lstTrainings = new QListWidget(this);
+    lstTrainings ->setWhatsThis(tr("Pick the training to play"));
+
+    lstChallenges = new QListWidget(this);
+    lstChallenges ->setWhatsThis(tr("Pick the challenge to play"));
+
+    lstScenarios= new QListWidget(this);
+    lstScenarios->setWhatsThis(tr("Pick the scenario to play"));
+
+    tbw->addTab(lstTrainings, tr("Trainings"));
+    tbw->addTab(lstChallenges, tr("Challenges"));
+    tbw->addTab(lstScenarios, tr("Scenarios"));
+    tbw->setCurrentWidget(lstTrainings);
 
     return pageLayout;
 }
@@ -89,9 +104,18 @@
 {
     QBoxLayout * bottomLayout = new QVBoxLayout();
 
-    btnStart = formattedButton(QPushButton::tr("Go!"));
+    const QIcon& lp = QIcon(":/res/Start.png");
+    QSize sz = lp.actualSize(QSize(65535, 65535));
+    btnStart = new QPushButton();
+    btnStart->setStyleSheet("padding: 5px 10px");
+    btnStart->setText(QPushButton::tr("Start"));
     btnStart->setWhatsThis(tr("Start fighting"));
-    btnStart->setFixedWidth(140);
+    btnStart->setMinimumWidth(sz.width() + 60);
+    btnStart->setIcon(lp);
+    btnStart->setFixedHeight(50);
+    btnStart->setIconSize(sz);
+    btnStart->setFlat(true);
+    btnStart->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
 
     bottomLayout->addWidget(btnStart);
 
@@ -103,9 +127,20 @@
 
 void PageTraining::connectSignals()
 {
-    connect(lstMissions, SIGNAL(currentItemChanged(QListWidgetItem*, QListWidgetItem*)), this, SLOT(updateInfo()));
-    connect(lstMissions, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(updateInfo()));
-    connect(lstMissions, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(startSelected()));
+    connect(lstTrainings, SIGNAL(currentItemChanged(QListWidgetItem*, QListWidgetItem*)), this, SLOT(updateInfo()));
+    connect(lstTrainings, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(updateInfo()));
+    connect(lstTrainings, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(startSelected()));
+
+    connect(lstChallenges, SIGNAL(currentItemChanged(QListWidgetItem*, QListWidgetItem*)), this, SLOT(updateInfo()));
+    connect(lstChallenges, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(updateInfo()));
+    connect(lstChallenges, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(startSelected()));
+
+    connect(lstScenarios, SIGNAL(currentItemChanged(QListWidgetItem*, QListWidgetItem*)), this, SLOT(updateInfo()));
+    connect(lstScenarios, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(updateInfo()));
+    connect(lstScenarios, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(startSelected()));
+
+    connect(tbw, SIGNAL(currentChanged(int)), this, SLOT(updateInfo()));
+
     connect(btnPreview, SIGNAL(clicked()), this, SLOT(startSelected()));
     connect(btnStart, SIGNAL(clicked()), this, SLOT(startSelected()));
 }
@@ -140,79 +175,130 @@
     m_info = new QSettings(infoFile, QSettings::IniFormat, this);
     m_info->setIniCodec("UTF-8");
 
-
-    QStringList missionList = dataMgr.entryList(
-                                  "Missions/Training",
-                                  QDir::Files, QStringList("*.lua")).
-                              replaceInStrings(QRegExp("\\.lua$"), "");
-
-    // scripts to lost - TODO: model?
-    foreach (const QString & mission, missionList)
-    {
-        QListWidgetItem * item = new QListWidgetItem(mission);
+    QStringList m_list;
+    QListWidget * m_widget;
+    QString subFolder;
 
-        // fallback name: replace underscores in mission name with spaces
-        QString name = item->text().replace("_", " ");
-
-        // see if we can get a prettier/translated name
-        name = m_info->value(mission + ".name", name).toString();
+    for(int i=1; i<=3; i++) {
+        switch(i) {
+            case 1:
+                subFolder = "Training";
+                m_widget = lstTrainings;
+                break;
+            case 2:
+                subFolder = "Challenge";
+                m_widget = lstChallenges;
+                break;
+            case 3:
+                subFolder = "Scenario";
+                m_widget = lstScenarios;
+                break;
+        }
+        m_list = dataMgr.entryList(
+                    "Missions/" + subFolder,
+                    QDir::Files, QStringList("*.lua")).
+               replaceInStrings(QRegExp("\\.lua$"), "");
 
-        item->setText(name);
+        // scripts to load - TODO: model?
+        foreach (const QString & m_id, m_list)
+        {
+            QListWidgetItem * item = new QListWidgetItem(m_id);
+
+            // fallback name: replace underscores in mission name with spaces
+            QString name = item->text().replace("_", " ");
 
-        // store original name in data
-        item->setData(Qt::UserRole, mission);
+            // see if we can get a prettier/translated name
+            name = m_info->value(m_id + ".name", name).toString();
+
+            item->setText(name);
 
-        lstMissions->addItem(item);
+            // store original name in data
+            item->setData(Qt::UserRole, m_id);
+
+            m_widget->addItem(item);
+        }
     }
 
     updateInfo();
 
     // pre-select first mission
-    if (lstMissions->count() > 0)
-        lstMissions->setCurrentRow(0);
+    if (lstTrainings->count() > 0)
+        lstTrainings->setCurrentRow(0);
+
+    if (lstChallenges->count() > 0)
+        lstChallenges->setCurrentRow(0);
+
+    if (lstScenarios->count() > 0)
+        lstScenarios->setCurrentRow(0);
 }
 
+QString PageTraining::getSubFolderOfSelected()
+{
+    QString subFolder;
+    if (tbw->currentWidget() == lstTrainings) {
+        subFolder = "Training";
+    } else if (tbw->currentWidget() == lstChallenges) {
+        subFolder = "Challenge";
+    } else if (tbw->currentWidget() == lstScenarios) {
+        subFolder = "Scenario";
+    } else {
+        subFolder = "Training";
+    }
+    return subFolder;
+}
 
 void PageTraining::startSelected()
 {
-    QListWidgetItem * curItem = lstMissions->currentItem();
+    QListWidget *list;
+    list = (QListWidget*) tbw->currentWidget();
+    QListWidgetItem * curItem = list->currentItem();
 
     if (curItem != NULL)
-        emit startMission(curItem->data(Qt::UserRole).toString());
+        emit startMission(curItem->data(Qt::UserRole).toString(), getSubFolderOfSelected());
 }
 
 
 void PageTraining::updateInfo()
 {
-    if (lstMissions->currentItem())
+    if (tbw->currentWidget())
     {
-        // TODO also use .pngs in userdata folder
-        QString thumbFile =     "physfs://Graphics/Missions/Training/" +
-                                lstMissions->currentItem()->data(Qt::UserRole).toString() +
-                                "@2x.png";
+        QString subFolder;
+        QListWidget *list;
+        subFolder = getSubFolderOfSelected();
+        list = (QListWidget*) tbw->currentWidget();
+        if (list->currentItem())
+        {
+            // TODO also use .pngs in userdata folder
+            QString thumbFile =     "physfs://Graphics/Missions/" +
+                                    subFolder + "/" +
+                                    list->currentItem()->data(Qt::UserRole).toString() +
+                                    "@2x.png";
 
-        if (QFile::exists(thumbFile))
-            btnPreview->setIcon(QIcon(thumbFile));
-        else
-            btnPreview->setIcon(QIcon(":/res/Trainings.png"));
-
-        QString realName = lstMissions->currentItem()->data(
-                               Qt::UserRole).toString();
+            if (QFile::exists(thumbFile))
+                btnPreview->setIcon(QIcon(thumbFile));
+            else
+                btnPreview->setIcon(QIcon(":/res/Trainings.png"));
 
-        QString caption = m_info->value(realName + ".name",
-                                        lstMissions->currentItem()->text()).toString();
+            btnPreview->setWhatsThis(tr("Start fighting"));
+
+            QString realName = list->currentItem()->data(
+                                    Qt::UserRole).toString();
 
-        QString description = m_info->value(realName + ".desc",
-                                            tr("No description available")).toString();
+            QString caption = m_info->value(realName + ".name",
+                                            list->currentItem()->text()).toString();
+
+            QString description = m_info->value(realName + ".desc",
+                                                tr("No description available")).toString();
 
-        lblCaption->setText("<h2>" + caption +"</h2>");
-        lblDescription->setText(description);
-    }
-    else
-    {
-        btnPreview->setIcon(QIcon(":/res/Trainings.png"));
-        lblCaption->setText(tr("Select a mission!"));
-        // TODO better text and tr()
-        lblDescription->setText("");
+            lblCaption->setText("<h2>" + caption +"</h2>");
+            lblDescription->setText(description);
+        }
+        else
+        {
+            btnPreview->setIcon(QIcon(":/res/Trainings.png"));
+            lblCaption->setText(tr("Select a mission!"));
+            // TODO better text and tr()
+            lblDescription->setText("");
+        }
     }
 }
--- a/QTfrontend/ui/page/pagetraining.h	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/ui/page/pagetraining.h	Sun Dec 17 00:09:24 2017 +0100
@@ -30,7 +30,7 @@
 
 
     signals:
-        void startMission(const QString & scriptName);
+        void startMission(const QString & scriptName, const QString & subFolder);
 
 
     protected:
@@ -44,8 +44,12 @@
         QPushButton * btnStart;
         QLabel * lblCaption;
         QLabel * lblDescription;
-        QListWidget * lstMissions;
+        QTabWidget * tbw;
+        QListWidget * lstTrainings;
+        QListWidget * lstChallenges;
+        QListWidget * lstScenarios;
         QSettings * m_info;
+        QString getSubFolderOfSelected();
 
 
     private slots:
--- a/QTfrontend/ui/page/pagevideos.cpp	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/ui/page/pagevideos.cpp	Sun Dec 17 00:09:24 2017 +0100
@@ -77,7 +77,7 @@
         QString name;
         QString prefix; // original filename without extension
         QString desc;   // description (duration, resolution, etc...)
-        QString uploadUrl; // http://youtu.be/???????
+        QString uploadUrl; // https://youtu.be/???????
         HWRecorder    * pRecorder; // non NULL if file is being encoded
         QNetworkReply * pUploading; // non NULL if file is being uploaded
         bool seen; // used when updating directory
@@ -114,7 +114,7 @@
     // list of videos
     {
         IconedGroupBox* pTableGroup = new IconedGroupBox(this);
-        pTableGroup->setIcon(QIcon(":/res/graphicsicon.png")); // FIXME
+        pTableGroup->setIcon(QIcon(":/res/Videos.png"));
         pTableGroup->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
         pTableGroup->setTitle(QGroupBox::tr("Videos"));
 
@@ -151,7 +151,7 @@
     // description
     {
         IconedGroupBox* pDescGroup = new IconedGroupBox(this);
-        pDescGroup->setIcon(QIcon(":/res/graphicsicon.png")); // FIXME
+        pDescGroup->setIcon(QIcon(":/res/miscicon.png"));
         pDescGroup->setTitle(QGroupBox::tr("Description"));
 
         QVBoxLayout* pDescLayout = new QVBoxLayout(pDescGroup);
@@ -194,7 +194,7 @@
         pBottomDescLayout->addWidget(btnDelete);
         btnToYouTube = new QPushButton(QPushButton::tr("Upload to YouTube"), pDescGroup);
         btnToYouTube->setEnabled(false);
-        btnToYouTube->setWhatsThis(QPushButton::tr("Upload this video to your Youtube account"));
+        btnToYouTube->setWhatsThis(QPushButton::tr("Upload this video to your YouTube account"));
         pBottomDescLayout->addWidget(btnToYouTube);
 
         pDescLayout->addWidget(labelThumbnail, 0);
@@ -823,7 +823,7 @@
 
     if (!videoid.isEmpty())
     {
-        item->uploadUrl = "http://youtu.be/" + videoid;
+        item->uploadUrl = "https://youtu.be/" + videoid;
         updateDescription();
 
         // save url in file
--- a/QTfrontend/ui/widget/MinesTimeSpinBox.h	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/ui/widget/MinesTimeSpinBox.h	Sun Dec 17 00:09:24 2017 +0100
@@ -44,7 +44,7 @@
 
     protected:
         /**
-         * Returns it's value localized.
+         * Returns its value localized.
          * @param value integer value to be representing as string.
          * @return string representation
          */
--- a/QTfrontend/ui/widget/about.cpp	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/ui/widget/about.cpp	Sun Dec 17 00:09:24 2017 +0100
@@ -71,15 +71,18 @@
     QLabel *lbl1 = new QLabel(this);
     lbl1->setOpenExternalLinks(true);
     lbl1->setText(
-        "<style type=\"text/css\">"
-        "a { color: #ffcc00; }"
-//            "a:hover { color: yellow; }"
-        "</style>"
-        "<div align=\"center\"><h1>Hedgewars " + *cVersionString + "</h1>"
-        "<h3>" + QLabel::tr("Revision") + " " + *cRevisionString + " (" + *cHashString + ")</h3>"
-        "<p><a href=\"https://www.hedgewars.org/\">https://www.hedgewars.org/</a></p>" +
-        QLabel::tr("This program is distributed under the %1").arg("<a \
-        href=\"http://www.gnu.org/licenses/gpl-2.0.html\">GNU GPL v2</a>") +
+        //: %1 contains Hedgewars' version number
+        "<div align=\"center\"><h1>"+QString(tr("Hedgewars %1")).arg(*cVersionString) + "</h1>"
+        //: “Revision” stands for a revision in Mercurial, a distributed version control system. %1 is the revision, %2 is the hexadecimal hash.
+        "<h3>" + QString(tr("Revision %1 (%2)")).arg(*cRevisionString, *cHashString) + "</h3>"
+        //: %1 is replaced by the URL of Hedgewars.
+        "<p>" + QString(tr("Visit our homepage: %1"))
+        .arg("<a href=\"https://www.hedgewars.org/\">https://www.hedgewars.org/</a>") + "</p>" +
+        //: %1 is the name of a license
+        tr("This program is distributed under the %1.")
+	.arg("<a href=\"https://www.gnu.org/licenses/gpl-2.0.html\">"+
+        //: Short for “GNU General Public License version 2”
+        tr("GNU GPL v2")+"</a>") +
         "</div>"
     );
     lbl1->setWordWrap(true);
@@ -93,10 +96,12 @@
 
     /* Library information */
 
-    QString libinfo = "<style type=text/css>a:link { color: #FFFF6E; }</style>";
+    //: For the version numbers of Hedgewars' software dependencies
+    QString libinfo = QString(tr("Dependency versions:") + QString("<br>"));
 
 #ifdef __GNUC__
-    libinfo.append(QString("<a href=\"http://gcc.gnu.org\">GCC</a> %1<br>").arg(__VERSION__));
+    libinfo.append(QString(tr("<a href=\"https://gcc.gnu.org\">GCC</a>: %1")).arg(__VERSION__));
+    libinfo.append(QString("<br>"));
 #else
     libinfo.append(QString(tr("Unknown Compiler")).arg(__VERSION__) + QString("<br>"));
 #endif
@@ -105,83 +110,93 @@
     SDL_version sdl_version;
     SDL_GetVersion(&sdl_version);
     sdl_ver = &sdl_version;
-    libinfo.append(QString("<a href=\"http://www.libsdl.org/\">SDL2</a> version: %1.%2.%3<br>")
+    libinfo.append(QString(tr("<a href=\"https://www.libsdl.org/\">SDL2</a>: %1.%2.%3"))
         .arg(sdl_ver->major)
         .arg(sdl_ver->minor)
         .arg(sdl_ver->patch));
+    libinfo.append(QString("<br>"));
 
     const SDL_version *sdlmixer_ver = Mix_Linked_Version();
-    libinfo.append(QString("<a href=\"http://www.libsdl.org/\">SDL2_mixer</a> version: %1.%2.%3<br>")
+    libinfo.append(QString(tr("<a href=\"https://www.libsdl.org/\">SDL2_mixer</a>: %1.%2.%3"))
         .arg(sdlmixer_ver->major)
         .arg(sdlmixer_ver->minor)
         .arg(sdlmixer_ver->patch));
+    libinfo.append(QString("<br>"));
 
     // the remaining sdl modules used only in engine, so instead of needlessly linking them here
     // we dynamically call the function returning the linked version
-    void *sdlnet_handle = SDL_LoadObject(sopath("SDL_net"));
+    void *sdlnet_handle = SDL_LoadObject(sopath("SDL2_net"));
     if (sdlnet_handle != NULL) {
         SDL_version *(*sdlnet_ver_get)(void) = NULL;
         sdlnet_ver_get = (SDL_version *(*)(void)) SDL_LoadFunction(sdlnet_handle, "SDLNet_Linked_Version");
         if (sdlnet_ver_get != NULL) {
             SDL_version *sdlnet_ver = sdlnet_ver_get();
-            libinfo.append(QString("<a href=\"http://www.libsdl.org/\">SDL_net</a> version: %1.%2.%3<br>")
+            libinfo.append(QString(tr("<a href=\"https://www.libsdl.org/\">SDL2_net</a>: %1.%2.%3"))
                 .arg(sdlnet_ver->major)
                 .arg(sdlnet_ver->minor)
                 .arg(sdlnet_ver->patch));
+            libinfo.append(QString("<br>"));
         }
         SDL_UnloadObject(sdlnet_handle);
     }
 
-    void *sdlimage_handle = SDL_LoadObject(sopath("SDL_image"));
+    void *sdlimage_handle = SDL_LoadObject(sopath("SDL2_image"));
     if (sdlimage_handle != NULL) {
         SDL_version *(*sdlimage_ver_get)(void) = NULL;
         sdlimage_ver_get = (SDL_version *(*)(void)) SDL_LoadFunction(sdlimage_handle, "IMG_Linked_Version");
         if (sdlimage_ver_get != NULL) {
             SDL_version *sdlimage_ver = sdlimage_ver_get();
-            libinfo.append(QString("<a href=\"http://www.libsdl.org/\">SDL_image</a> version: %1.%2.%3<br>")
+            libinfo.append(QString(tr("<a href=\"https://www.libsdl.org/\">SDL2_image</a>: %1.%2.%3"))
                 .arg(sdlimage_ver->major)
                 .arg(sdlimage_ver->minor)
                 .arg(sdlimage_ver->patch));
+            libinfo.append(QString("<br>"));
         }
-        SDL_UnloadObject(sdlnet_handle);
+        SDL_UnloadObject(sdlimage_handle);
     }
 
-    void *sdlttf_handle = SDL_LoadObject(sopath("SDL_ttf"));
+    void *sdlttf_handle = SDL_LoadObject(sopath("SDL2_ttf"));
     if (sdlttf_handle != NULL) {
         SDL_version *(*sdlttf_ver_get)(void) = NULL;
         sdlttf_ver_get = (SDL_version *(*)(void)) SDL_LoadFunction(sdlttf_handle, "TTF_Linked_Version");
         if (sdlttf_ver_get != NULL) {
             SDL_version *sdlttf_ver = sdlttf_ver_get();
-            libinfo.append(QString("<a href=\"http://www.libsdl.org/\">SDL_ttf</a> version: %1.%2.%3<br>")
+            libinfo.append(QString(tr("<a href=\"https://www.libsdl.org/\">SDL2_ttf</a>: %1.%2.%3"))
                 .arg(sdlttf_ver->major)
                 .arg(sdlttf_ver->minor)
                 .arg(sdlttf_ver->patch));
+            libinfo.append(QString("<br>"));
         }
-        SDL_UnloadObject(sdlnet_handle);
+        SDL_UnloadObject(sdlttf_handle);
     }
 
 
-    libinfo.append(QString("<a href=\"http://qt-project.org/\">Qt</a> version: %1<br>").arg(QT_VERSION_STR));
+    libinfo.append(QString(tr("<a href=\"https://www.qt.io/developers/\">Qt</a>: %1")).arg(QT_VERSION_STR));
+    libinfo.append(QString("<br>"));
 
 #ifdef VIDEOREC
-    libinfo.append(QString("<a href=\"http://libav.org\">libavcodec</a> version: %1.%2.%3<br>")
+    libinfo.append(QString(tr("<a href=\"https://libav.org\">libavcodec</a>: %1.%2.%3"))
         .arg(LIBAVCODEC_VERSION_MAJOR)
         .arg(LIBAVCODEC_VERSION_MINOR)
         .arg(LIBAVCODEC_VERSION_MICRO));
-    libinfo.append(QString("<a href=\"http://libav.org\">libavformat</a> version: %1.%2.%3<br>")
+    libinfo.append(QString("<br>"));
+    libinfo.append(QString(tr("<a href=\"https://libav.org\">libavformat</a>: %1.%2.%3"))
         .arg(LIBAVFORMAT_VERSION_MAJOR)
         .arg(LIBAVFORMAT_VERSION_MINOR)
         .arg(LIBAVFORMAT_VERSION_MICRO));
-    libinfo.append(QString("<a href=\"http://libav.org\">libavutil</a> version: %1.%2.%3<br>")
+    libinfo.append(QString("<br>"));
+    libinfo.append(QString(tr("<a href=\"https://libav.org\">libavutil</a>: %1.%2.%3"))
         .arg(LIBAVUTIL_VERSION_MAJOR)
         .arg(LIBAVUTIL_VERSION_MINOR)
         .arg(LIBAVUTIL_VERSION_MICRO));
+    libinfo.append(QString("<br>"));
 #endif
 
-    libinfo.append(QString("<a href=\"http://icculus.org/physfs/\">PhysFS</a> version: %1.%2.%3<br>")
+    libinfo.append(QString(tr("<a href=\"https://icculus.org/physfs/\">PhysFS</a>: %1.%2.%3"))
         .arg(PHYSFS_VER_MAJOR)
         .arg(PHYSFS_VER_MINOR)
         .arg(PHYSFS_VER_PATCH));
+    libinfo.append(QString("<br>"));
 
     // TODO: how to add Lua information?
 
--- a/QTfrontend/ui/widget/chatwidget.cpp	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/ui/widget/chatwidget.cpp	Sun Dec 17 00:09:24 2017 +0100
@@ -270,6 +270,10 @@
     acBan->setIcon(QIcon(":/res/ban.png"));
     acBan->setData(QVariant(true));
     connect(acBan, SIGNAL(triggered(bool)), this, SLOT(onBan()));
+    acDelegate = new QAction(QAction::tr("Delegate room control"), chatNicks);
+    acDelegate->setIcon(QIcon(":/res/chat/roomadmin.png"));
+    acDelegate->setData(QVariant(true));
+    connect(acDelegate, SIGNAL(triggered(bool)), this, SLOT(onDelegate()));
     acFollow = new QAction(QAction::tr("Follow"), chatNicks);
     acFollow->setIcon(QIcon(":/res/follow.png"));
     acFollow->setData(QVariant(false));
@@ -624,6 +628,14 @@
         emit ban(mil[0].data().toString());
 }
 
+void HWChatWidget::onDelegate()
+{
+    QModelIndexList mil = chatNicks->selectionModel()->selectedRows();
+
+    if(mil.size())
+        emit delegate(mil[0].data().toString());
+}
+
 void HWChatWidget::onInfo()
 {
     QModelIndexList mil = chatNicks->selectionModel()->selectedRows();
@@ -732,6 +744,7 @@
 {
     chatNicks->removeAction(acKick);
     //chatNicks->removeAction(acBan);
+    chatNicks->removeAction(acDelegate);
 
     m_isAdmin = b;
 
@@ -739,6 +752,7 @@
     {
         chatNicks->insertAction(0, acKick);
         //chatNicks->insertAction(0, acBan);
+        chatNicks->insertAction(acFriend, acDelegate);
     }
 }
 
@@ -931,6 +945,7 @@
     {
         acKick->setVisible(!isSelf && isOnline);
         acBan->setVisible(!isSelf);
+        acDelegate->setVisible(!isSelf && players->isFlagSet(m_userNick, PlayersListModel::InRoom));
     }
 
     m_nicksMenu->clear();
--- a/QTfrontend/ui/widget/chatwidget.h	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/ui/widget/chatwidget.h	Sun Dec 17 00:09:24 2017 +0100
@@ -128,6 +128,7 @@
         void chatLine(const QString& str);
         void kick(const QString & str);
         void ban(const QString & str);
+        void delegate(const QString & str);
         void info(const QString & str);
         void follow(const QString &);
         void nickCountUpdate(int cnt);
@@ -144,6 +145,7 @@
         QAction * acInfo;
         QAction * acKick;
         QAction * acBan;
+        QAction * acDelegate;
         QAction * acFollow;
         QAction * acIgnore;
         QAction * acFriend;
@@ -163,6 +165,7 @@
         void returnPressed();
         void onBan();
         void onKick();
+        void onDelegate();
         void onInfo();
         void onFollow();
         void onIgnore();
--- a/QTfrontend/ui/widget/feedbackdialog.cpp	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/ui/widget/feedbackdialog.cpp	Sun Dec 17 00:09:24 2017 +0100
@@ -156,8 +156,9 @@
     captchaLayoutWidget->setLayout(captchaLayout);
     feedbackLayout->addWidget(captchaLayoutWidget, 3, 1, 1, 2);
 
-    // TODO: Set green arrow icon for send button (:/res/Start.png)
     BtnSend = new QPushButton(tr("Send Feedback"));
+    BtnSend->setStyleSheet("qproperty-icon: url(:/res/Start.png);");
+
     feedbackLayout->addWidget(BtnSend, 3, 3);
     BtnSend->setFixedHeight(40);
     connect(BtnSend, SIGNAL(clicked()), this, SLOT(SendFeedback()));
--- a/QTfrontend/ui/widget/gamecfgwidget.cpp	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/ui/widget/gamecfgwidget.cpp	Sun Dec 17 00:09:24 2017 +0100
@@ -333,6 +333,8 @@
     bcfg << QString("e$mapgen %1").arg(mapgen).toUtf8();
     if(!schemeData(43).isNull())
         bcfg << QString("e$scriptparam %1").arg(schemeData(43).toString()).toUtf8();
+    else
+        bcfg << QString("e$scriptparam ").toUtf8();
 
 
     switch (mapgen)
@@ -695,6 +697,11 @@
     schemeChanged(GameSchemes->currentIndex());
 }
 
+void GameCFGWidget::resendAmmoData()
+{
+    ammoChanged(WeaponsName->currentIndex());
+}
+
 void GameCFGWidget::onDrawnMapChanged(const QByteArray & data)
 {
     emit paramChanged("DRAWNMAP", QStringList(qCompress(data, 9).toBase64()));
--- a/QTfrontend/ui/widget/gamecfgwidget.h	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/ui/widget/gamecfgwidget.h	Sun Dec 17 00:09:24 2017 +0100
@@ -55,6 +55,7 @@
         void setParam(const QString & param, const QStringList & value);
         void fullNetConfig();
         void resendSchemeData();
+        void resendAmmoData();
         void setMaster(bool master);
         void setTabbed(bool tabbed);
 
--- a/QTfrontend/ui/widget/hedgehogerWidget.cpp	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/ui/widget/hedgehogerWidget.cpp	Sun Dec 17 00:09:24 2017 +0100
@@ -83,7 +83,7 @@
 {
     Q_UNUSED(event);
 
-    if (this->width() >= 11 * numItems + 26)
+    if ((this->width() >= 11 * numItems + 26) || (numItems == 1))
         ItemNum::paintEvent(event);
     else
     {
--- a/QTfrontend/ui/widget/keybinder.cpp	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/ui/widget/keybinder.cpp	Sun Dec 17 00:09:24 2017 +0100
@@ -60,6 +60,7 @@
     {
         QPushButton * btnResetAll = new QPushButton(resetButtonText);
         catListContainer->addWidget(btnResetAll);
+        btnResetAll->setStyleSheet("padding: 5px 10px");
         btnResetAll->setFixedHeight(40);
         catListContainer->setStretch(1, 0);
         catListContainer->setSpacing(10);
@@ -241,13 +242,12 @@
 {
     QComboBox * box = bindCellComboBoxMappings->value(item);
     QTableWidget * table = item->tableWidget();
-    QFrame * frame = box->findChild<QFrame*>();
 
+    box->move(
+        table->horizontalHeader()->sectionSize(0),
+        (table->verticalHeader()->defaultSectionSize() * (item->row() + 1)) - (box->height()) + 1
+    );
     box->showPopup();
-    frame->move(
-        frame->x() + table->horizontalHeader()->sectionSize(0),
-        frame->y() + (table->verticalHeader()->defaultSectionSize() * item->row())
-    );
 }
 
 // When a new row in a bind table is *selected*, this clears selection in any other table
--- a/QTfrontend/ui/widget/mapContainer.cpp	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/ui/widget/mapContainer.cpp	Sun Dec 17 00:09:24 2017 +0100
@@ -253,7 +253,7 @@
     bottomLeftLayout->addStretch(1);
 
     /* Theme chooser */
-    QHBoxLayout * themeHBox = new QHBoxLayout(this);
+    QHBoxLayout * themeHBox = new QHBoxLayout();
 
     btnRandTheme = new QPushButton();
     btnRandTheme->setWhatsThis(tr("Randomize the theme"));
@@ -262,7 +262,7 @@
     btnRandTheme->setFixedHeight(30);
     btnRandTheme->setFixedWidth(30);
     connect(btnRandTheme, SIGNAL(clicked()), this, SLOT(setRandomTheme()));
-    m_childWidgets << btnTheme;
+    m_childWidgets << btnRandTheme;
     themeHBox->addWidget(btnRandTheme, 0);
 
     btnTheme = new QPushButton(this);
--- a/QTfrontend/ui/widget/roomnameprompt.cpp	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/ui/widget/roomnameprompt.cpp	Sun Dec 17 00:09:24 2017 +0100
@@ -48,7 +48,8 @@
     // Input box
     leRoomName = new QLineEdit(this);
     leRoomName->setText(roomName);
-    leRoomName->setMaxLength(59); // It didn't like 60 :(
+    //leRoomName->setMaxLength(59); // It didn't like 60 :(
+    leRoomName->setMaxLength(40);
     leRoomName->setStyleSheet("QLineEdit { padding: 3px; }");
     leRoomName->selectAll();
     dialogLayout->addWidget(leRoomName);
--- a/QTfrontend/ui/widget/selectWeapon.cpp	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/ui/widget/selectWeapon.cpp	Sun Dec 17 00:09:24 2017 +0100
@@ -189,11 +189,19 @@
     setWeapons(*cDefaultAmmoStore);
 }
 
+//Save current weapons set.
 void SelWeaponWidget::save()
 {
+    //The save() function is called by ANY change of the combo box.
+    //If an entry is deleted, this code would just re-add the deleted
+    //item. We use isDeleted to check if we are currently deleting to
+    //prevent this.
+    if (isDeleting)
+        return;
     // TODO make this return if success or not, so that the page can react
     // properly and not goBack if saving failed
-    if (m_name->text() == "") return;
+    if (m_name->text() == "")
+        return;
 
     QString state1;
     QString state2;
@@ -218,12 +226,15 @@
 
     for(int i = 0; i < cDefaultAmmos.size(); i++)
     {
-        if (cDefaultAmmos[i].first.compare(m_name->text()) == 0)
+        // Don't allow same name as default weapon set, even case-insensitively.
+        // This prevents some problems with saving/loading.
+        if (cDefaultAmmos[i].first.toLower().compare(m_name->text().toLower()) == 0)
         {
             // don't show warning if no change
             if (cDefaultAmmos[i].second.compare(stateFull) == 0)
                 return;
 
+            m_name->setText(curWeaponsName);
             QMessageBox deniedMsg(this);
             deniedMsg.setIcon(QMessageBox::Warning);
             deniedMsg.setWindowTitle(QMessageBox::tr("Weapons - Warning"));
@@ -240,7 +251,7 @@
         wconf->remove(curWeaponsName);
     }
     wconf->setValue(m_name->text(), stateFull);
-    emit weaponsChanged();
+    emit weaponsEdited(curWeaponsName, m_name->text(), stateFull);
 }
 
 int SelWeaponWidget::operator [] (unsigned int weaponIndex) const
@@ -256,10 +267,11 @@
 
 void SelWeaponWidget::deleteWeaponsName()
 {
-    if (curWeaponsName == "") return;
+    QString delWeaponsName = curWeaponsName;
+    if (delWeaponsName == "") return;
 
     for(int i = 0; i < cDefaultAmmos.size(); i++)
-        if (!cDefaultAmmos[i].first.compare(m_name->text()))
+        if (!cDefaultAmmos[i].first.compare(delWeaponsName))
         {
             QMessageBox deniedMsg(this);
             deniedMsg.setIcon(QMessageBox::Warning);
@@ -273,19 +285,21 @@
     QMessageBox reallyDeleteMsg(this);
     reallyDeleteMsg.setIcon(QMessageBox::Question);
     reallyDeleteMsg.setWindowTitle(QMessageBox::tr("Weapons - Are you sure?"));
-    reallyDeleteMsg.setText(QMessageBox::tr("Do you really want to delete the weapon set '%1'?").arg(curWeaponsName));
+    reallyDeleteMsg.setText(QMessageBox::tr("Do you really want to delete the weapon set '%1'?").arg(delWeaponsName));
     reallyDeleteMsg.setWindowModality(Qt::WindowModal);
     reallyDeleteMsg.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
 
     if (reallyDeleteMsg.exec() == QMessageBox::Ok)
     {
-        wconf->remove(curWeaponsName);
-        emit weaponsDeleted();
+        isDeleting = true;
+        wconf->remove(delWeaponsName);
+        emit weaponsDeleted(delWeaponsName);
     }
 }
 
 void SelWeaponWidget::newWeaponsName()
 {
+    save();
     QString newName = tr("New");
     if(wconf->contains(newName))
     {
@@ -294,6 +308,8 @@
         while(wconf->contains(newName = tr("New (%1)").arg(i++))) ;
     }
     setWeaponsName(newName);
+    wconf->setValue(newName, *cEmptyAmmoStore);
+    emit weaponsAdded(newName, *cEmptyAmmoStore);
 }
 
 void SelWeaponWidget::setWeaponsName(const QString& name)
@@ -312,6 +328,13 @@
     }
 }
 
+void SelWeaponWidget::switchWeapons(const QString& name)
+{
+    // Rescue old weapons set, then select new one
+    save();
+    setWeaponsName(name);
+}
+
 QStringList SelWeaponWidget::getWeaponNames() const
 {
     return wconf->allKeys();
@@ -319,6 +342,7 @@
 
 void SelWeaponWidget::copy()
 {
+    save();
     if(wconf->contains(curWeaponsName))
     {
         QString ammo = getWeaponsString(curWeaponsName);
@@ -327,10 +351,12 @@
         {
             //name already used -> look for an appropriate name:
             int i=2;
-            while(wconf->contains(newName = tr("Copy of %1 (%2)").arg(curWeaponsName, i++)));
+            while(wconf->contains(newName = tr("Copy of %1 (%2)").arg(curWeaponsName).arg(i++)));
         }
         setWeaponsName(newName);
         setWeapons(ammo);
+        wconf->setValue(newName, ammo);
+        emit weaponsAdded(newName, ammo);
     }
 }
 
@@ -352,3 +378,13 @@
 
     return sl.join(QString());
 }
+
+void SelWeaponWidget::deletionDone()
+{
+    isDeleting = false;
+}
+
+void SelWeaponWidget::init()
+{
+    isDeleting = false;
+}
--- a/QTfrontend/ui/widget/selectWeapon.h	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/ui/widget/selectWeapon.h	Sun Dec 17 00:09:24 2017 +0100
@@ -52,24 +52,30 @@
         SelWeaponWidget(int numItems, QWidget* parent=0);
         QString getWeaponsString(const QString& name) const;
         QStringList getWeaponNames() const;
+        void deletionDone();
+        void init();
 
     public slots:
         void setDefault();
         void setWeapons(const QString& ammo);
         //sets the name of the current set
         void setWeaponsName(const QString& name);
+        void switchWeapons(const QString& name);
         void deleteWeaponsName();
         void newWeaponsName();
         void save();
         void copy();
 
     signals:
-        void weaponsChanged();
-        void weaponsDeleted();
+        void weaponsDeleted(QString weaponsName);
+        void weaponsAdded(QString weaponsName, QString ammo);
+        void weaponsEdited(QString oldWeaponsName, QString newWeaponsName, QString ammo);
 
     private:
         //the name of the current weapon set
         QString curWeaponsName;
+        //set to true while an entry is deleted. Used to avoid duplicate saving due to combobox change
+        bool isDeleting;
 
         QLineEdit* m_name;
 
--- a/QTfrontend/ui/widget/teamselect.cpp	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/ui/widget/teamselect.cpp	Sun Dec 17 00:09:24 2017 +0100
@@ -43,6 +43,12 @@
         blockSignals(false);
         connect(framePlaying->getTeamWidget(team), SIGNAL(teamColorChanged(const HWTeam&)),
                 this, SLOT(proxyTeamColorChanged(const HWTeam&)));
+
+        // Hide team notice if at least two teams.
+        if (curPlayingTeams.size() >= 2)
+        {
+            numTeamNotice->hide();
+        }
     }
     else
     {
@@ -133,6 +139,11 @@
         QObject::disconnect(framePlaying->getTeamWidget(*itPlay), SIGNAL(teamStatusChanged(HWTeam)));
         framePlaying->removeTeam(team);
         curPlayingTeams.erase(itPlay);
+        // Show team notice if less than two teams.
+        if (curPlayingTeams.size() < 2)
+        {
+            numTeamNotice->show();
+        }
     }
     else
     {
@@ -229,15 +240,17 @@
     emit setEnabledGameStart(curPlayingTeams.size()>1);
 }
 
-void TeamSelWidget::addScrArea(FrameTeams* pfteams, QColor color, int fixedHeight)
+void TeamSelWidget::addScrArea(FrameTeams* pfteams, QColor color, int minHeight, int maxHeight, bool setFrame)
 {
     VertScrArea* area = new VertScrArea(color);
     area->setWidget(pfteams);
-    mainLayout.addWidget(area, 30);
-    if (fixedHeight > 0)
+    mainLayout.addWidget(area);
+    if (minHeight > 0)
+        area->setMinimumHeight(minHeight);
+    if (maxHeight > 0)
+        area->setMaximumHeight(maxHeight);
+    if (setFrame)
     {
-        area->setMinimumHeight(fixedHeight);
-        area->setMaximumHeight(fixedHeight);
         area->setStyleSheet(
             "FrameTeams{"
             "border: solid;"
@@ -263,8 +276,8 @@
 
     QPalette p;
     p.setColor(QPalette::Window, QColor(0x00, 0x00, 0x00));
-    addScrArea(framePlaying, p.color(QPalette::Window).light(105), 150);
-    addScrArea(frameDontPlaying, p.color(QPalette::Window).dark(105), 0);
+    addScrArea(framePlaying, p.color(QPalette::Window).light(105), 161, 325, true);
+    addScrArea(frameDontPlaying, p.color(QPalette::Window).dark(105), 80, 0, false);
 
     this->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
     this->setMinimumWidth(200);
@@ -292,6 +305,8 @@
     foreach(HWTeam team, teamslist)
         addTeam(team);
 
+    numTeamNotice->show();
+
     repaint();
 }
 
@@ -310,6 +325,17 @@
     return m_curNotPlayingTeams;
 }
 
+unsigned short TeamSelWidget::getNumHedgehogs() const
+{
+    unsigned short numHogs = 0;
+    QList<HWTeam>::const_iterator team;
+    for(team = curPlayingTeams.begin(); team != curPlayingTeams.end(); ++team)
+    {
+        numHogs += (*team).numHedgehogs();
+    }
+    return numHogs;
+}
+
 void TeamSelWidget::pre_changeTeamStatus(const HWTeam & team)
 {
     //team.setColor(framePlaying->getNextColor());
--- a/QTfrontend/ui/widget/teamselect.h	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/ui/widget/teamselect.h	Sun Dec 17 00:09:24 2017 +0100
@@ -47,6 +47,7 @@
         bool isPlaying(const HWTeam &team) const;
         QList<HWTeam> getPlayingTeams() const;
         QList<HWTeam> getNotPlayingTeams() const;
+	unsigned short getNumHedgehogs() const;
         void setInteractivity(bool interactive);
 
     public slots:
@@ -69,7 +70,7 @@
         void proxyTeamColorChanged(const HWTeam& team);
 
     private:
-        void addScrArea(FrameTeams* pfteams, QColor color, int maxHeight);
+        void addScrArea(FrameTeams* pfteams, QColor color, int minHeight, int maxHeight, bool setFrame);
         FrameTeams* frameDontPlaying;
         FrameTeams* framePlaying;
 
--- a/QTfrontend/util/DataManager.cpp	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/util/DataManager.cpp	Sun Dec 17 00:09:24 2017 +0100
@@ -31,6 +31,7 @@
 #include "hwconsts.h"
 #include "HWApplication.h"
 #include "sdlkeys.h"
+#include "physfs.h"
 
 #include "DataManager.h"
 
@@ -61,7 +62,8 @@
 QStringList DataManager::entryList(
     const QString & subDirectory,
     QDir::Filters filters,
-    const QStringList & nameFilters
+    const QStringList & nameFilters,
+    bool withDLC
 ) const
 {
     QDir tmpDir(QString("physfs://%1").arg(subDirectory));
@@ -69,9 +71,13 @@
 
     // sort case-insensitive
     QMap<QString, QString> sortedFileNames;
+    QString absolutePath = datadir->absolutePath().toLocal8Bit().data();
     foreach ( QString fn, result)
     {
-        sortedFileNames.insert(fn.toLower(), fn);
+        // Filter out DLC entries if desired
+        QString realDir = PHYSFS_getRealDir(QString(subDirectory + "/" + fn).toLocal8Bit().data());
+        if(withDLC || realDir == absolutePath)
+            sortedFileNames.insert(fn.toLower(), fn);
     }
     result = sortedFileNames.values();
 
--- a/QTfrontend/util/DataManager.h	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/util/DataManager.h	Sun Dec 17 00:09:24 2017 +0100
@@ -37,7 +37,7 @@
 /**
  * @brief Offers access to the data files of hedgewars.
  *
- * @see <a href="http://en.wikipedia.org/wiki/Singleton_pattern">singleton pattern</a>
+ * @see <a href="https://en.wikipedia.org/wiki/Singleton_pattern">singleton pattern</a>
  *
  * @author sheepluva
  * @since 0.9.17
@@ -50,7 +50,7 @@
         /**
          * @brief Returns reference to the <i>singleton</i> instance of this class.
          *
-         * @see <a href="http://en.wikipedia.org/wiki/Singleton_pattern">singleton pattern</a>
+         * @see <a href="https://en.wikipedia.org/wiki/Singleton_pattern">singleton pattern</a>
          *
          * @return reference to the instance.
          */
@@ -66,7 +66,8 @@
          */
         QStringList entryList(const QString & subDirectory,
                               QDir::Filters filters = QDir::NoFilter,
-                              const QStringList & nameFilters = QStringList("*")
+                              const QStringList & nameFilters = QStringList("*"),
+                              bool withDLC = true
                              ) const;
 
         /**
@@ -141,7 +142,7 @@
          * Not to be used from outside the class,
          * use the static {@link DataManager::instance()} instead.
          *
-         * @see <a href="http://en.wikipedia.org/wiki/Singleton_pattern">singleton pattern</a>
+         * @see <a href="https://en.wikipedia.org/wiki/Singleton_pattern">singleton pattern</a>
          */
         DataManager();
 
--- a/QTfrontend/util/FileEngine.cpp	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/util/FileEngine.cpp	Sun Dec 17 00:09:24 2017 +0100
@@ -295,7 +295,11 @@
 
 QString FileEngine::errorString() const
 {
+#if PHYSFS_VER_MAJOR >= 3
+    return PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode());
+#else
     return PHYSFS_getLastError();
+#endif
 }
 
 bool FileEngine::supportsExtension(Extension extension) const
@@ -352,7 +356,12 @@
 
 QString FileEngineHandler::errorStr()
 {
-    QString s = QString::fromUtf8(PHYSFS_getLastError());
+    QString s;
+#if PHYSFS_VER_MAJOR >= 3
+    s = QString::fromUtf8(PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
+#else
+    s = QString::fromUtf8(PHYSFS_getLastError());
+#endif
     return s.isEmpty() ? "ok" : s;
 }
 
--- a/QTfrontend/util/LibavInteraction.cpp	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/util/LibavInteraction.cpp	Sun Dec 17 00:09:24 2017 +0100
@@ -18,7 +18,7 @@
 
 #include "LibavInteraction.h"
 
-#if VIDEOREC
+#ifdef VIDEOREC
 extern "C"
 {
 #include "libavcodec/avcodec.h"
@@ -291,7 +291,8 @@
         return "";
 
     int s = float(pContext->duration)/AV_TIME_BASE;
-    QString desc = tr("Duration: %1m %2s").arg(s/60).arg(s%60) + "\n";
+    //: Duration in minutes and seconds (SI units)
+    QString desc = tr("Duration: %1min %2s").arg(s/60).arg(s%60) + "\n";
     for (int i = 0; i < (int)pContext->nb_streams; i++)
     {
         AVStream* pStream = pContext->streams[i];
@@ -307,7 +308,7 @@
             if (pStream->avg_frame_rate.den)
             {
                 float fps = float(pStream->avg_frame_rate.num)/pStream->avg_frame_rate.den;
-                desc += QString(tr("%1 fps")).arg(fps, 0, 'f', 2) + ", ";
+                desc += QString(tr("%1 FPS")).arg(fps, 0, 'f', 2) + ", ";
             }
         }
         else if (pCodec->codec_type == AVMEDIA_TYPE_AUDIO)
--- a/QTfrontend/util/LibavInteraction.h	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/util/LibavInteraction.h	Sun Dec 17 00:09:24 2017 +0100
@@ -24,7 +24,7 @@
 /**
  * @brief Class for interacting with ffmpeg/libav libraries
  *
- * @see <a href="http://en.wikipedia.org/wiki/Singleton_pattern">singleton pattern</a>
+ * @see <a href="https://en.wikipedia.org/wiki/Singleton_pattern">singleton pattern</a>
  */
 class LibavInteraction : public QObject
 {
--- a/QTfrontend/util/SDLInteraction.h	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/util/SDLInteraction.h	Sun Dec 17 00:09:24 2017 +0100
@@ -41,7 +41,7 @@
 /**
  * @brief Class for interacting with SDL (used for music and keys)
  *
- * @see <a href="http://en.wikipedia.org/wiki/Singleton_pattern">singleton pattern</a>
+ * @see <a href="https://en.wikipedia.org/wiki/Singleton_pattern">singleton pattern</a>
  */
 class SDLInteraction
 {
@@ -53,7 +53,7 @@
          * Not to be used from outside the class,
          * use the static {@link DataManager::instance()} instead.
          *
-         * @see <a href="http://en.wikipedia.org/wiki/Singleton_pattern">singleton pattern</a>
+         * @see <a href="https://en.wikipedia.org/wiki/Singleton_pattern">singleton pattern</a>
          */
         SDLInteraction();
 
@@ -73,7 +73,7 @@
         /**
          * @brief Returns reference to the <i>singleton</i> instance of this class.
          *
-         * @see <a href="http://en.wikipedia.org/wiki/Singleton_pattern">singleton pattern</a>
+         * @see <a href="https://en.wikipedia.org/wiki/Singleton_pattern">singleton pattern</a>
          *
          * @return reference to the instance.
          */
--- a/QTfrontend/util/namegen.cpp	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/util/namegen.cpp	Sun Dec 17 00:09:24 2017 +0100
@@ -18,6 +18,7 @@
  */
 
 #include <QFile>
+#include <QFileInfo>
 #include <QTextStream>
 #include <QStringList>
 #include <QLineEdit>
@@ -33,8 +34,34 @@
 QList<QStringList> HWNamegen::TypesHatnames;
 bool HWNamegen::typesAvailable = false;
 
+void HWNamegen::teamRandomTeamName(HWTeam & team)
+{
+    QString newName = getRandomTeamName(-1);
+    if(!newName.isNull())
+        team.setName(newName);
+}
 
-void HWNamegen::teamRandomNames(HWTeam & team, const bool changeteamname)
+void HWNamegen::teamRandomFlag(HWTeam & team, bool withDLC)
+{
+    team.setFlag(getRandomFlag(withDLC));
+}
+
+void HWNamegen::teamRandomVoice(HWTeam & team, bool withDLC)
+{
+    team.setVoicepack(getRandomVoice(withDLC));
+}
+
+void HWNamegen::teamRandomGrave(HWTeam & team, bool withDLC)
+{
+    team.setGrave(getRandomGrave(withDLC));
+}
+
+void HWNamegen::teamRandomFort(HWTeam & team, bool withDLC)
+{
+    team.setFort(getRandomFort(withDLC));
+}
+
+void HWNamegen::teamRandomEverything(HWTeam & team)
 {
     // load types if not already loaded
     if (!typesAvailable)
@@ -48,34 +75,53 @@
     // the hat will influence which names the hogs get
     int kind = (rand()%(TypesHatnames.size()));
 
-    // pick team name based on hat
-    if (changeteamname)
-    {
-        if (TypesTeamnames[kind].size() > 0)
-            team.setName(TypesTeamnames[kind][rand()%(TypesTeamnames[kind].size())]);
-
-        team.setGrave(getRandomGrave());
-        team.setFort(getRandomFort());
-        team.setVoicepack("Default");
-    }
+    team.setGrave(getRandomGrave());
+    team.setFort(getRandomFort());
+    team.setFlag(getRandomFlag());
+    team.setVoicepack(getRandomVoice());
 
     QStringList dicts;
     QStringList dict;
 
-    if ((TypesHatnames[kind].size()) <= 0)
-    {
-        dicts = dictsForHat(team.hedgehog(0).Hat);
-        dict  = dictContents(dicts[rand()%(dicts.size())]);
-    }
+    // Randomness mode:
+    // 0: Themed hats (from types.ini)
+    // 1: Equal hats for all
+    // 2: Random hat for each hedgehog
+    int r = rand() % 10;
+    int randomMode;
+    if (r <= 4)		// 0-4 (50%)
+       randomMode = 0;
+    else if (r <= 8)	// 5-8 (40%)
+       randomMode = 1;
+    else		// 9   (10%)
+       randomMode = 2;
 
+    // Generate random hats
     for(int i = 0; i < HEDGEHOGS_PER_TEAM; i++)
     {
-        if ((TypesHatnames[kind].size()) > 0)
+        HWHog hh = team.hedgehog(i);
+
+        if (randomMode == 0)
+        {
+            hh.Hat = TypesHatnames[kind][rand()%(TypesHatnames[kind].size())];
+        }
+        else if (randomMode == 1)
         {
-            HWHog hh = team.hedgehog(i);
-            hh.Hat = TypesHatnames[kind][rand()%(TypesHatnames[kind].size())];
-            team.setHedgehog(i,hh);
+            if (i == 0)
+            {
+                hh.Hat = getRandomHat();
+            }
+            else
+            {
+                hh.Hat = team.hedgehog(i-1).Hat;
+            }
         }
+        else if (randomMode == 2)
+        {
+            hh.Hat = getRandomHat();
+        }
+
+        team.setHedgehog(i,hh);
 
         // there is a chance that this hog has the same hat as the previous one
         // let's reuse the hat-specific dict in this case
@@ -86,21 +132,83 @@
         }
 
         // give each hedgehog a random name
-        HWNamegen::teamRandomName(team,i,dict);
+        HWNamegen::teamRandomHogName(team,i,dict);
     }
 
+    // If using themed hats, use themed team name.
+    // Otherwise, only use “generic” team names from the first team
+    // in types.txt.
+    if (randomMode == 0)
+        team.setName(getRandomTeamName(kind));
+    else
+        team.setName(getRandomTeamName(0));
+
 }
 
-void HWNamegen::teamRandomName(HWTeam & team, const int HedgehogNumber)
+// Set random hats for entire team
+void HWNamegen::teamRandomHats(HWTeam & team, bool withDLC)
+{
+    // 50% chance that all hogs are set to the same hat.
+    // 50% chance that each hog gets a random head individually.
+
+    bool sameHogs = (rand()%2) == 0;
+    for(int i = 0; i < HEDGEHOGS_PER_TEAM; i++)
+    {
+        HWHog hh = team.hedgehog(i);
+        if (sameHogs and i > 0)
+            hh.Hat = team.hedgehog(i-1).Hat;
+        else
+            hh.Hat = getRandomHat(withDLC);
+        team.setHedgehog(i, hh);
+    }
+}
+
+void HWNamegen::teamRandomHat(HWTeam & team, const int HedgehogNumber, bool withDLC)
+{
+    HWHog hh = team.hedgehog(HedgehogNumber);
+
+    hh.Hat = getRandomHat(withDLC);
+
+    team.setHedgehog(HedgehogNumber, hh);
+}
+
+void HWNamegen::teamRandomHat(HWTeam & team, const int HedgehogNumber, const QStringList & dict)
+{
+    HWHog hh = team.hedgehog(HedgehogNumber);
+
+    hh.Name = dict[rand()%(dict.size())];
+
+    team.setHedgehog(HedgehogNumber, hh);
+}
+
+void HWNamegen::teamRandomHogNames(HWTeam & team)
+{
+    QStringList dicts, dict;
+    for(int i = 0; i < HEDGEHOGS_PER_TEAM; i++)
+    {
+        // there is a chance that this hog has the same hat as the previous one
+        // let's reuse the hat-specific dict in this case
+        if ((i == 0) || (team.hedgehog(i).Hat != team.hedgehog(i-1).Hat))
+        {
+            dicts = dictsForHat(team.hedgehog(i).Hat);
+            dict  = dictContents(dicts[rand()%(dicts.size())]);
+        }
+
+        // give each hedgehog a random name
+        HWNamegen::teamRandomHogName(team,i,dict);
+    }
+}
+
+void HWNamegen::teamRandomHogName(HWTeam & team, const int HedgehogNumber)
 {
     QStringList dicts = dictsForHat(team.hedgehog(HedgehogNumber).Hat);
 
     QStringList dict = dictContents(dicts[rand()%(dicts.size())]);
 
-    teamRandomName(team, HedgehogNumber, dict);
+    teamRandomHogName(team, HedgehogNumber, dict);
 }
 
-void HWNamegen::teamRandomName(HWTeam & team, const int HedgehogNumber, const QStringList & dict)
+void HWNamegen::teamRandomHogName(HWTeam & team, const int HedgehogNumber, const QStringList & dict)
 {
     QStringList namesDict = dict;
 
@@ -151,22 +259,32 @@
 {
     QStringList list;
 
-    // find .cfg to load the dicts from
-    QFile file(QString("physfs://Names/%1.cfg").arg(hatname));
+    // Find and check .cfg to load the dicts from
+    QString path = QString("physfs://Names/%1.cfg").arg(hatname);
+    QFileInfo check_file(path);
 
-    if (file.open(QIODevice::ReadOnly | QIODevice::Text))
+    // Note: The .cfg file is optional; a fallback mechanism is in place (see below)
+
+    // Check if file exists to prevent PhysFS from complaining in console so much
+    if (check_file.exists() && check_file.isFile())
     {
-        QTextStream in(&file);
-        QString line;
-        do
+        QFile file(path);
+
+        if (file.open(QIODevice::ReadOnly | QIODevice::Text))
         {
-            line = in.readLine();
+            QTextStream in(&file);
+            QString line;
+            do
+            {
+                line = in.readLine();
 
-            if(!line.isEmpty())
-                list.append(line);
-        } while (!line.isNull());
+                if(!line.isEmpty())
+                    list.append(line);
+            } while (!line.isNull());
+        }
     }
 
+    // Use Data/Names/generic.cfg by default
     if (list.size() == 0)
         list.append(QString("generic"));
 
@@ -231,9 +349,54 @@
     return typesAvailable;
 }
 
+/* Generates a random team name.
+kind: Use to select a team name out of a group (types.ini).
+Use a negative value if you don't care.
+This function may return a null QString on error(this should never happen). */
+QString HWNamegen::getRandomTeamName(int kind)
+{
+    // load types if not already loaded
+    if (!typesAvailable)
+        if (!loadTypes())
+            return QString(); // abort if loading failed
 
+    // abort if there are no hat types
+    if (TypesHatnames.size() <= 0)
+        return QString();
+
+    if(kind < 0)
+        kind = (rand()%(TypesHatnames.size()));
+
+    if (TypesTeamnames[kind].size() > 0)
+        return TypesTeamnames[kind][rand()%(TypesTeamnames[kind].size())];
+    else
+        return QString();
+}
 
-QString HWNamegen::getRandomGrave()
+QString HWNamegen::getRandomHat(bool withDLC)
+{
+    QStringList Hats;
+
+    // list all available hats
+    Hats.append(DataManager::instance().entryList(
+                      "Graphics/Hats",
+                      QDir::Files,
+                      QStringList("*.png"),
+                      withDLC
+                  ).replaceInStrings(QRegExp("\\.png$"), "")
+                 );
+
+    if(Hats.size()==0)
+    {
+        // TODO do some serious error handling
+        return "Error";
+    }
+
+    // pick a random hat
+    return Hats[rand()%(Hats.size())];
+}
+
+QString HWNamegen::getRandomGrave(bool withDLC)
 {
     QStringList Graves;
 
@@ -241,7 +404,8 @@
     Graves.append(DataManager::instance().entryList(
                       "Graphics/Graves",
                       QDir::Files,
-                      QStringList("*.png")
+                      QStringList("*.png"),
+                      withDLC
                   ).replaceInStrings(QRegExp("\\.png$"), "")
                  );
 
@@ -255,7 +419,33 @@
     return Graves[rand()%(Graves.size())];
 }
 
-QString HWNamegen::getRandomFort()
+QString HWNamegen::getRandomFlag(bool withDLC)
+{
+    QStringList Flags;
+
+    //list all available flags
+    Flags.append(DataManager::instance().entryList(
+                      "Graphics/Flags",
+                      QDir::Files,
+                      QStringList("*.png"),
+                      withDLC
+                  ).replaceInStrings(QRegExp("\\.png$"), "")
+                 );
+    //remove internal flags
+    Flags.removeAll("cpu");
+    Flags.removeAll("cpu_plain");
+
+    if(Flags.size()==0)
+    {
+        // TODO do some serious error handling
+        return "Error";
+    }
+
+    //pick a random flag
+    return Flags[rand()%(Flags.size())];
+}
+
+QString HWNamegen::getRandomFort(bool withDLC)
 {
     QStringList Forts;
 
@@ -263,7 +453,8 @@
     Forts.append(DataManager::instance().entryList(
                      "Forts",
                      QDir::Files,
-                     QStringList("*L.png")
+                     QStringList("*L.png"),
+                     withDLC
                  ).replaceInStrings(QRegExp("L\\.png$"), "")
                 );
 
@@ -276,3 +467,24 @@
     //pick a random fort
     return Forts[rand()%(Forts.size())];
 }
+
+QString HWNamegen::getRandomVoice(bool withDLC)
+{
+    QStringList Voices;
+
+    //list all available voices 
+    Voices.append(DataManager::instance().entryList(
+                     "Sounds/voices",
+                     QDir::Dirs | QDir::NoDotAndDotDot,
+                     QStringList("*"),
+                     withDLC));
+
+    if(Voices.size()==0)
+    {
+        // TODO do some serious error handling
+        return "Error";
+    }
+
+    //pick a random voice
+    return Voices[rand()%(Voices.size())];
+}
--- a/QTfrontend/util/namegen.h	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/util/namegen.h	Sun Dec 17 00:09:24 2017 +0100
@@ -28,13 +28,27 @@
 class HWNamegen
 {
     public:
-
-        static void teamRandomName(HWTeam & team, const int HedgehogNumber);
-        static void teamRandomNames(HWTeam & team, const bool changeteamname);
+        static void teamRandomTeamName(HWTeam & team);
+        static void teamRandomGrave(HWTeam & team, bool withDLC = true);
+        static void teamRandomFort(HWTeam & team, bool withDLC = true);
+        static void teamRandomFlag(HWTeam & team, bool withDLC = true);
+        static void teamRandomVoice(HWTeam & team, bool withDLC = true);
+        static void teamRandomHats(HWTeam & team, bool withDLC = true);
+        static void teamRandomHat(HWTeam & team, const int HedgehogNumber, bool withDLC = true);
+        static void teamRandomHogNames(HWTeam & team);
+        static void teamRandomHogName(HWTeam & team, const int HedgehogNumber);
+        static void teamRandomEverything(HWTeam & team);
 
     private:
         HWNamegen();
 
+        static QString getRandomTeamName(int kind);
+        static QString getRandomHat(bool withDLC = true);
+        static QString getRandomGrave(bool withDLC = true);
+        static QString getRandomFort(bool withDLC = true);
+        static QString getRandomFlag(bool withDLC = true);
+        static QString getRandomVoice(bool withDLC = true);
+
         static QList<QStringList> TypesTeamnames;
         static QList<QStringList> TypesHatnames;
         static bool typesAvailable;
@@ -43,9 +57,8 @@
         static QStringList dictContents(const QString filename);
         static QStringList dictsForHat(const QString hatname);
 
-        static QString getRandomGrave();
-        static QString getRandomFort();
-        static void teamRandomName(HWTeam & team, const int HedgehogNumber, const QStringList & dict);
+        static void teamRandomHat(HWTeam & team, const int HedgehogNumber, const QStringList & dict);
+        static void teamRandomHogName(HWTeam & team, const int HedgehogNumber, const QStringList & dict);
 };
 
 
--- a/QTfrontend/util/platform/CocoaInitializer.h	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/util/platform/CocoaInitializer.h	Sun Dec 17 00:09:24 2017 +0100
@@ -16,7 +16,7 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
-// see original example here http://el-tramo.be/blog/mixing-cocoa-and-qt
+// see original example here https://el-tramo.be/blog/mixing-cocoa-and-qt
 
 #ifndef COCOAINITIALIZER_H
 #define COCOAINITIALIZER_H
--- a/QTfrontend/util/platform/CocoaInitializer.mm	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/util/platform/CocoaInitializer.mm	Sun Dec 17 00:09:24 2017 +0100
@@ -16,7 +16,7 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
-// see original example here http://el-tramo.be/blog/mixing-cocoa-and-qt
+// see original example here https://el-tramo.be/blog/mixing-cocoa-and-qt
 
 #include "CocoaInitializer.h"
 
--- a/QTfrontend/util/platform/SparkleAutoUpdater.mm	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/util/platform/SparkleAutoUpdater.mm	Sun Dec 17 00:09:24 2017 +0100
@@ -16,7 +16,7 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
-// see original example here http://el-tramo.be/blog/mixing-cocoa-and-qt
+// see original example here https://el-tramo.be/blog/mixing-cocoa-and-qt
 
 #include "SparkleAutoUpdater.h"
 
--- a/QTfrontend/util/platform/Xfire Game SDK.url	Thu Aug 11 23:05:14 2016 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,5 +0,0 @@
-[{000214A0-0000-0000-C000-000000000046}]
-Prop3=19,2
-[InternetShortcut]
-URL=http://www.xfire.com/cms/xf_game_sdk
-IDList=
--- a/QTfrontend/util/platform/xfire.cpp	Thu Aug 11 23:05:14 2016 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,85 +0,0 @@
-/*
- * Hedgewars, a free turn based strategy game
- * Copyright (c) 2004-2015 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- */
-
-#include <string>
-#include <cstring>
-#include <stdio.h>
-
-#include "xfire.h"
-#include "xfiregameclient.h"
-
-#ifdef USE_XFIRE
-// use_xfire: stores if xfire is loaded and functions should do something at all
-bool use_xfire = false;
-char *keys[XFIRE_KEY_COUNT];
-char *values[XFIRE_KEY_COUNT];
-
-// xfire_init(): used to initialize all variables and set their default values
-void xfire_init(void)
-{
-    if(use_xfire)
-        return;
-    use_xfire = XfireIsLoaded() == 1;
-
-    if(!use_xfire)
-        return;
-
-    for(int i = 0; i < XFIRE_KEY_COUNT; i++)
-    {
-        keys[i] = new char[256];
-        values[i] = new char[256];
-        strcpy(keys[i], "");
-        strcpy(values[i], "");
-    }
-
-    strcpy(keys[XFIRE_NICKNAME], "Nickname");
-    strcpy(keys[XFIRE_ROOM], "Room");
-    strcpy(keys[XFIRE_SERVER], "Server");
-    strcpy(keys[XFIRE_STATUS], "Status");
-    xfire_update();
-}
-
-// xfire_free(): used to free up ressources used etc.
-void xfire_free(void)
-{
-    if(!use_xfire)
-        return;
-
-    for(int i = 0; i < XFIRE_KEY_COUNT; i++)
-    {
-        delete [] keys[i];
-        delete [] values[i];
-    }
-}
-
-// xfire_setvalue(): set a specific value
-void xfire_setvalue(const XFIRE_KEYS status, const char *value)
-{
-    if(!use_xfire || strlen(value) > 255)
-        return;
-    strcpy(values[status], value);
-}
-
-// xfire_update(): submits current values to the xfire app
-void xfire_update(void)
-{
-    if(!use_xfire)
-        return;
-    XfireSetCustomGameDataA(XFIRE_KEY_COUNT, (const char**)keys, (const char**)values);
-}
-#endif // USE_XFIRE
--- a/QTfrontend/util/platform/xfire.h	Thu Aug 11 23:05:14 2016 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +0,0 @@
-/*
- * Hedgewars, a free turn based strategy game
- * Copyright (c) 2004-2015 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- */
-
-#ifndef XFIRE_H
-#define XFIRE_H
-
-
-#ifdef USE_XFIRE
-enum XFIRE_KEYS
-{
-    XFIRE_STATUS = 0,
-    XFIRE_NICKNAME,
-    XFIRE_SERVER,
-    XFIRE_ROOM,
-    XFIRE_KEY_COUNT,
-};
-
-void xfire_init(void);
-void xfire_free(void);
-void xfire_setvalue(const XFIRE_KEYS status, const char *value);
-void xfire_update(void);
-#endif
-
-#endif // XFIRE_H
--- a/QTfrontend/util/platform/xfire_license.txt	Thu Aug 11 23:05:14 2016 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,103 +0,0 @@
-Terms and Conditions
-AGREEMENT BETWEEN USER AND XFIRE INC.
-This is a legal agreement between you and Xfire Inc. ("Xfire") with respect to your access and use of the Xfire Service, which may also include Xfire software, content and related documentation and information (collectively, the "Service"). You must accept without modification all of the terms, conditions, and notices contained in these Terms of Use in order to access and/or use the Service (collectively, the "Terms of Use" or "Agreement"). If you do not accept these Terms of Use in their entirety, you may not access or use the Service.
-
-Portions of the Service may be governed by posted guidelines, rules, or other terms and conditions. All such guidelines, rules, terms and conditions are hereby incorporated by reference into these Terms of Use. In the event of a conflict between such other guidelines, rules, terms and conditions and these Terms of Use, the Terms of Use shall control, except that the Xfire Service Privacy Policy, referenced below, supersedes any conflicting language in these Terms of Use and/or any other guidelines, rules, terms and conditions published in connection with the Service with respect to the subject matter covered by such privacy policy.
-
-MODIFICATION OF THESE TERMS OF USE; UPDATES
-Xfire may change the Terms of Use at any time and such changes shall be effective immediately. You are responsible for regularly reviewing the Terms of Use. The most recent version of the Terms of Use can be found at http://www.xfire.com/xf/terms.php. Your continued use of the Service affirms your agreement to the Terms of Use and any changes.
-
-Xfire is not obligated to provide updates or improvements to the Service. However, if Xfire, in its sole discretion, updates or improves the Service, these Terms of Use shall apply to such updates and improvements unless expressly noted otherwise.
-
-CLIENT SOFTWARE USE LIMITATION
-YOU MAY ONLY USE XFIRE CLIENT SOFTWARE OR AUTHORIZED THIRD-PARTY SOFTWARE TO ACCESS AND/OR USE THE SERVICE. You may not use any software or services in conjunction with the Xfire software or authorized third-party software which modifies or reroutes, or attempts to modify or reroute, the Service. You may not authorize any third party to access and/or use the Service on your behalf using any automated process such as a BOT, a spider or periodic caching of information stored by the Xfire Service on your behalf without a separate written agreement with Xfire. You may not use any software or hardware that reduces the number of users directly accessing or using the Service (sometimes called 'multiplexing' or 'pooling' software or hardware).
-
-You may not modify, copy, distribute, transmit, display, perform, reproduce, publish, license, create derivative works from, transfer, or sell any information, software, products or services that are part of the Service except as expressly provided in these Terms of Use.
-
-NO UNLAWFUL OR PROHIBITED USE; RESPONSIBILITY FOR YOUR ACCOUNT
-As a condition of your use of the Service, you will not use the Service for any purpose that is unlawful or prohibited by these Terms of Use. You may not use the Service in any manner that could damage, disable, overburden, or impair the Service or interfere with any other party's use and enjoyment of it. You may not attempt to gain unauthorized access to any account, computer systems or networks associated with the Service or to otherwise interfere with or disrupt any accounts, computer systems or networks connected to the Service. You may not obtain or attempt to obtain any materials or information through any means not intentionally made available or provided for through the Service. You may not use access to the Service to obtain information necessary for you to design, develop or update unauthorized software that you use or provide to others to use to access the Service. You may not charge others to use the Service either directly or indirectly without the express written agreement of Xfire.
-Subject to these Terms of Use, you may use the Service within your commercial organization, but you may not use the Service to advertise or offer to buy or sell any goods or services, or to run a business or commercial entity without the express written agreement of Xfire.
-You agree to use the Service only to send, receive, and transfer appropriate messages and material. By way of example, and not as a limitation, you agree that when using the Service, you will not:
-
-
- Use the Service in connection with surveys, contests, pyramid schemes, chain letters, junk email, spamming or any duplicative, bulk or unsolicited messages (commercial or otherwise).
-
- Defame, abuse, harass, stalk, threaten or otherwise violate the legal rights (such as rights of privacy and publicity) of others.
-
- Create a false identity for the purpose of misleading others.
-
- Publish, transfer, distribute or disseminate any inappropriate, profane, defamatory, obscene, indecent or unlawful topic, name, material or information.
-
- Transfer, stream, or otherwise make available, files or other material that contain images, photographs, software or other material protected by intellectual property laws, including, by way of example, and not as limitation, copyright or trademark laws (or by rights of privacy or publicity) unless you own or control the rights thereto or have received all necessary consents to do the same.
-
- Use any material or information, including images or photographs, which is made available through the Service in any manner that infringes any copyright, trademark, patent, trade secret, or other proprietary right of any party.
-
- Transfer, stream or otherwise make available, files or other material that contain viruses, Trojan horses, worms, time bombs, cancelbots, corrupted files, or any other similar software or programs that may damage the operation of another's computer or property of another.
-
- Download any file or other material transferred by another user of the Service that you know, or reasonably should know, cannot be legally distributed in such manner.
-
- Use, download or otherwise copy, or provide (whether or not for a fee) to a person or entity any directory of users of the Service or other user or usage information or any portion thereof.
-
- Falsify or delete any author attributions, legal or other proper notices or proprietary designations or labels of the origin or source of software or other material contained in a file that is transferred.
-
- Violate any code of conduct or other guidelines which may be applicable to the Service.
-
- Use any portion of the Service to harvest or otherwise collect information about others, including e-mail addresses.
-
-Xfire reserves the right at all times to monitor communications on the Service and disclose any information Xfire deems necessary to (i) ensure your compliance with this Agreement; (ii) satisfy any applicable law, regulation or legal process; or (iii) protect the rights, property, and interests of Xfire, its employees or the public. Xfire also reserves the right to edit, refuse to transfer or to remove any information or materials, in whole or in part, in Xfire's sole discretion.
-
-Always use caution when giving out any personally identifiable information about yourself or your children in the Service. Xfire does not control or endorse the content, messages or information exchanged by means of the Service and, therefore, Xfire specifically disclaims any liability with regard to the Service and any actions resulting from your participation in the Service.
-
-You are responsible for all activities that occur in your Service account. You agree to notify Xfire immediately of any unauthorized use of your account or breach in security known to you related to the Service.
-
-
-PRIVACY
-See the Xfire Service Privacy Statement at http://www.xfire.com/xf/privacy.php for disclosures relating to the collection and use of your information.
-
-
-INTERACTION WITH THIRD PARTY SITES AND SERVICES
-The Service may allow you to interact with third-party Web sites and Web services ("Link(s)"). The Links are not under the control of Xfire and Xfire is not responsible for the contents of any Links, including without limitation any link contained in a Link, or any changes or updates to a Link. Xfire is not responsible for any form of transmission received from any Link, nor is Xfire responsible if the Link is not working appropriately. Xfire is providing these Links to you only as a convenience, and the inclusion of any Link does not imply endorsement by Xfire of the Link or any association with its operators. You are responsible for viewing and abiding by any privacy statements and terms of use posted in connection with the Links.
-
-You are solely responsible for any dealings with third parties (including advertisers) who support the Service, including the delivery of and payment for goods and services.
-
-TERMS OF USE FOR SERVICE-ENABLED PROPERTIES
-For the terms and conditions governing your use of any Xfire or authorized third party Web site or service that enables you to use the Service other than the Service itself ("Service-Enabled Properties"), please refer to the applicable Terms of Use for such Service-Enabled Properties.
-
-SOFTWARE AND CONTENT AVAILABLE ON THE SERVICE
-All Xfire content and software (if any) that is made available to view and/or download in connection with the Service ("Software") is owned by and is the copyrighted work of Xfire and/or its suppliers and is licensed, not sold. Your use of the Software is governed by the terms of the license agreement, if any, which accompanies or is included with the Software ("License Agreement"). You may not install or use any Software that is accompanied by or includes a License Agreement unless you first agree to the License Agreement terms. For any Software not accompanied by a license agreement, Xfire hereby grants to you, the user, a non-exclusive, revocable, personal, non-transferable license to use the Software solely in connection with the Service in accordance with these Terms of Use. You may not lend, lease, rent or sublicense the Software or any aspect of the Service.
-
-You will not disassemble, decompile, or reverse engineer the Software. All Software is protected by copyright laws and international treaty provisions. Any unauthorized reproduction or redistribution of the Software is expressly prohibited by law, and may result in severe civil and criminal penalties. WITHOUT LIMITING THE FOREGOING, COPYING OR REPRODUCTION OF THE SOFTWARE TO ANY OTHER SERVER OR LOCATION FOR FURTHER REPRODUCTION OR REDISTRIBUTION IS EXPRESSLY PROHIBITED. THE SOFTWARE IS WARRANTED, IF AT ALL, ONLY ACCORDING TO THE TERMS OF THE LICENSE AGREEMENT. You acknowledge that the Software, and any accompanying documentation and/or technical information, is subject to applicable export control laws and regulations of the U.S.A. You agree not to export or re-export the Software, directly or indirectly, to any countries that are subject to U.S.A. export restrictions.
-
-Your license to use the Software with the Service terminates when you terminate your use of the Service. Your license to use the Software with the Service may also terminate if Xfire, in its sole discretion, modifies the Service to no longer support such Software.
-
-NO WARRANTIES; LIABILITY DISCLAIMER; EXCLUSIVE REMEDY
-XFIRE PROVIDES THE SERVICE AND THE SOFTWARE "AS IS," "WITH ALL FAULTS" AND "AS AVAILABLE," AND THE ENTIRE RISK AS TO SATISFACTORY QUALITY, PERFORMANCE, ACCURACY, AND EFFORT IS WITH YOU. XFIRE, ITS AFFILIATES, ITS RESELLERS, DISTRIBUTORS, SERVICE PROVIDERS AND/OR SUPPLIERS (COLLECTIVELY, THE "XFIRE PARTIES") MAKE NO WARRANTIES. THE XFIRE PARTIES DISCLAIM ANY AND ALL WARRANTIES, EXPRESS, STATUTORY AND IMPLIED, INCLUDING WITHOUT LIMITATION (1) WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, WORKMANLIKE EFFORT, ACCURACY, TITLE, QUIET ENJOYMENT, NO ENCUMBRANCES, NO LIENS AND NON-INFRINGEMENT, (2) WARRANTIES ARISING THROUGH COURSE OF DEALING OR USAGE OF TRADE, AND (3) WARRANTIES THAT ACCESS TO OR USE OF THE SERVICE WILL BE UNINTERRUPTED OR ERROR-FREE. THERE ARE NO WARRANTIES THAT EXTEND BEYOND THE FACE OF THIS AGREEMENT. XFIRE MAY CHANGE THE SERVICE OR THE FEATURES IN ANY WAY, AND AT ANY TIME AND FOR ANY REASON.
-
-IN NO EVENT SHALL ANY OF THE XFIRE PARTIES BE LIABLE FOR ANY DIRECT, INDIRECT, CONSEQUENTIAL, SPECIAL, INCIDENTAL, OR PUNITIVE DAMAGES ARISING OUT OF, BASED ON, OR RESULTING FROM THIS AGREEMENT OR YOUR USE OF THE SERVICE, INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF USE, DATA OR PROFITS, WITH THE DELAY OR INABILITY TO USE THE SERVICE, THE PROVISION OF OR FAILURE TO PROVIDE SUPPORT SERVICES, OR FOR ANY INFORMATION, SOFTWARE, PRODUCTS, OR SERVICES OBTAINED THROUGH THE SERVICE, OR OTHERWISE ARISING OUT OF THE USE OF THE SERVICE, WHETHER BASED ON CONTRACT, TORT, NEGLIGENCE, STRICT LIABILITY OR OTHERWISE, EVEN IF XFIREOR ANY OF ITS SUPPLIERS HAS BEEN ADVISED OF THE POSSIBILITY OF DAMAGES. BECAUSE SOME STATES/JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES, THE ABOVE LIMITATION MAY NOT APPLY TO YOU.
-
-IF YOU ARE DISSATISFIED WITH ANY PORTION OF THE SERVICE, OR WITH ANY OF THESE TERMS OF USE, YOUR SOLE AND EXCLUSIVE REMEDY IS TO DISCONTINUE USING THE SERVICE.
-
-INDEMNITY
-You agree to indemnify and hold Xfire, its officers, and employees, harmless from any claim or demand, including reasonable attorneys' fees, made by any third party due to or arising out of your use of the Services, the violation of these Terms of Use by you, or the infringement by you, or other user of the Services using your computer or identity, of any intellectual property or other right of any person or entity.
-
-CUSTOMER SUPPORT
-Xfire may, but is not required to, provide you with customer support ("Support"). Unless you have entered into a separate written support agreement with Xfire with respect to the Service, Xfire may terminate any Support it provides at any time in its sole discretion.
-
-Authorized third-party software that uses the Service is not supported by Xfire and you should contact the provider of such software for support, if any.
-
-TERMINATION/ACCESS RESTRICTION
-Unless you, or a third party on your behalf, have entered into a separate written agreement with Xfire that modifies these Terms of Use, Xfire reserves the right, in its sole discretion, to terminate your access to and use of the Service or any portion thereof at any time, without notice. Also, unless you or a third party on your behalf have entered into a separate agreement with Xfire, Xfire may terminate or suspend your access to the Service for inactivity, which is defined as failing to log onto the Service for an extended period of time, as determined by Xfire.
-ELECTRONIC NOTICES
-You consent to Xfire providing you any information regarding the Service in electronic form. Xfire may provide such information to you via e-mail at the e-mail address you specified when you registered for the Service, by instant message to your account, or by access to a Xfire web site. As long as you access and use the Service, you will have the necessary software and hardware to receive such notices. If you do not consent to receive any notices electronically, you must discontinue your use of the Service.
-
-GENERAL
-If you reside in the United States, claims for enforcement, breach or violation of duties or rights under these Terms of Use are governed by the laws of the State of California, without reference to conflict of laws principles. All other claims, including, without limitation, claims under or for violation of state consumer protection laws, unfair competition laws, and in tort, are governed by the laws of your state of residence in the United States. If you reside outside of the United States, these Terms of Use are governed by the laws of the State of California, without reference to conflict of laws principles. You hereby irrevocably consent to the exclusive jurisdiction and venue of courts in San Mateo County, California, U.S.A. in all disputes arising out of or relating to the use of the Service.
-
-YOU AND XFIRE AGREE THAT ANY CAUSE OF ACTION ARISING OUT OF OR RELATED TO THE SERVICE MUST COMMENCE WITHIN ONE (1) YEAR AFTER THE CAUSE OF ACTION ACCRUES. OTHERWISE, SUCH CAUSE OF ACTION IS PERMANENTLY BARRED.
-
-Xfire may have patents, patent applications, trademarks, copyrights, or other intellectual property rights covering subject matter in any Web pages that are part of the Service. Except as expressly provided in these Terms of Use, the furnishing of such Web pages to you does not give you any license to these patents, trademarks, copyrights, or other intellectual property. Any rights not expressly granted herein are reserved.
-
-June 2004
-
-
-
--- a/QTfrontend/util/platform/xfiregameclient.cpp	Thu Aug 11 23:05:14 2016 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,121 +0,0 @@
-/* This file is NOT open source. See "license.txt" to read the full license provided with the Xfire SDK. */
-
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#include <tlhelp32.h>
-
-#include "xfiregameclient.h"
-
-static HMODULE g_toucan_dll = NULL;
-static void HelperInit();
-static HMODULE HelperGetToucanDLL();
-
-typedef int (*XfireSetCustomGameDataAFunction)(int , const char **, const char **);
-typedef int (*XfireSetCustomGameDataWFunction)(int , const wchar_t **, const wchar_t **);
-typedef int (*XfireSetCustomGameDataUTF8Function)(int , const char **, const char **);
-
-static XfireSetCustomGameDataAFunction ptr_XfireSetCustomGameDataA = NULL;
-static XfireSetCustomGameDataWFunction ptr_XfireSetCustomGameDataW = NULL;
-static XfireSetCustomGameDataUTF8Function ptr_XfireSetCustomGameDataUTF8 = NULL;
-
-/* make sure we are going to call the ANSI version */
-#ifdef MODULEENTRY32
-#undef MODULEENTRY32
-#endif
-
-#ifdef Module32First
-#undef Module32First
-#endif
-
-#ifdef Module32Next
-#undef Module32Next
-#endif
-
-
-int XfireIsLoaded()
-{
-    HelperInit();
-    if (ptr_XfireSetCustomGameDataA &&
-        ptr_XfireSetCustomGameDataW &&
-        ptr_XfireSetCustomGameDataUTF8)
-        return 1;
-    return 0;
-}
-
-int XfireSetCustomGameDataA(int num_keys, const char **keys, const char **values)
-{
-    HelperInit();
-    if (ptr_XfireSetCustomGameDataA)
-        return ptr_XfireSetCustomGameDataA(num_keys, keys, values);
-    return 1;
-}
-
-int XfireSetCustomGameDataW(int num_keys, const wchar_t **keys, const wchar_t **values)
-{
-    HelperInit();
-    if (ptr_XfireSetCustomGameDataW)
-        return ptr_XfireSetCustomGameDataW(num_keys, keys, values);
-    return 1;
-}
-
-int XfireSetCustomGameDataUTF8(int num_keys, const char **keys, const char **values)
-{
-    HelperInit();
-    if (ptr_XfireSetCustomGameDataUTF8)
-        return ptr_XfireSetCustomGameDataUTF8(num_keys, keys, values);
-    return 1;
-}
-
-/* ------------------------------------------------------------------------- */
-static void HelperInit()
-{
-    if (!ptr_XfireSetCustomGameDataA ||
-        !ptr_XfireSetCustomGameDataW ||
-        !ptr_XfireSetCustomGameDataUTF8)
-    {
-        HMODULE toucan_dll = HelperGetToucanDLL();
-        if (toucan_dll)
-        {
-            ptr_XfireSetCustomGameDataA = (XfireSetCustomGameDataAFunction)::GetProcAddress(toucan_dll, "ToucanSendGameClientDataA_V1");
-            ptr_XfireSetCustomGameDataW = (XfireSetCustomGameDataWFunction)::GetProcAddress(toucan_dll, "ToucanSendGameClientDataW_V1");
-            ptr_XfireSetCustomGameDataUTF8 = (XfireSetCustomGameDataUTF8Function)::GetProcAddress(toucan_dll, "ToucanSendGameClientDataUTF8_V1");
-        }
-    }
-}
-
-
-static HMODULE HelperGetToucanDLL()
-{
-    if (g_toucan_dll)
-        return g_toucan_dll;
-
-    /*
-    ** We need to enumerate the DLLs loaded to find toucan dll.
-    ** This is done because the toucan dll changes with each update.
-    ** The toucan dll has the following format. "xfire_toucan_{BUILD_NUMBER}.dll"
-    ** We simply try to find a dll w/ the prefix "xfire_toucan"
-    */
-    HANDLE snapshot_handle = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId());
-    if (snapshot_handle != INVALID_HANDLE_VALUE)
-    {
-        MODULEENTRY32 module_entry;
-        module_entry.dwSize = sizeof(MODULEENTRY32);
-
-        BOOL result = Module32First(snapshot_handle, &module_entry);
-        char module_name[] = "xfire_toucan";
-        DWORD module_name_len = sizeof(module_name)-1;
-        while (result)
-        {
-            if (CompareStringA(LOCALE_USER_DEFAULT, NORM_IGNORECASE, module_entry.szModule, module_name_len, module_name, module_name_len) == CSTR_EQUAL)
-            {
-                g_toucan_dll = module_entry.hModule;
-                break;
-            }
-            result = Module32Next(snapshot_handle, &module_entry);
-        }
-
-        CloseHandle(snapshot_handle);
-    }
-
-    return g_toucan_dll;
-}
--- a/QTfrontend/util/platform/xfiregameclient.h	Thu Aug 11 23:05:14 2016 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-/* This file is NOT open source. See "license.txt" to read the full license provided with the Xfire SDK. */
-
-#ifndef __XFIREGAMECLIENT_H__
-#define __XFIREGAMECLIENT_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
-**  XfireIsLoaded()
-**
-**  returns 1 if application can talk to Xfire, 0 otherwise
-*/
-int XfireIsLoaded();
-
-/*
-**  XfireSetCustomGameDataA()
-**
-**  ANSI version to tell xfire of custom game data
-*/
-int XfireSetCustomGameDataA(int num_keys, const char **keys, const char **values);
-
-/*
-**  XfireSetCustomGameDataA()
-**
-**  UNICODE version to tell xfire of custom game data
-*/
-int XfireSetCustomGameDataW(int num_keys, const wchar_t **keys, const wchar_t **values);
-
-/*
-**  XfireSetCustomGameDataUTF8()
-**
-**  UTF8 version to tell xfire of custom game data
-*/
-int XfireSetCustomGameDataUTF8(int num_keys, const char **keys, const char **values);
-
-#ifdef UNICODE
-#define XfireSetCustomGameData XfireSetCustomGameDataW
-#else
-#define XfireSetCustomGameData XfireSetCustomGameDataA
-#endif
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __XFIREGAMECLIENT_H__ */
--- a/QTfrontend/weapons.h	Thu Aug 11 23:05:14 2016 +0300
+++ b/QTfrontend/weapons.h	Sun Dec 17 00:09:24 2017 +0100
@@ -16,10 +16,10 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
-#define AMMOLINE_EMPTY_QT       "000000900000000000000000000000000000000000000000000000000"
-#define AMMOLINE_EMPTY_PROB     "000000000000000000000000000000000000000000000000000000000"
-#define AMMOLINE_EMPTY_DELAY    "000000000000000000000000000000000000000000000000000000000"
-#define AMMOLINE_EMPTY_CRATE    "131111031211111112311411111111111111121111111111111111111"
+#define AMMOLINE_EMPTY_QT       "0000009000000000000000000000000000000000000000000000000000"
+#define AMMOLINE_EMPTY_PROB     "0000000000000000000000000000000000000000000000000000000000"
+#define AMMOLINE_EMPTY_DELAY    "0000000000000000000000000000000000000000000000000000000000"
+#define AMMOLINE_EMPTY_CRATE    "1311110312111111123114111111111111111211111111111111111111"
 
 /*
  AmmoType lookup table (use monospace font / cursor movements)
@@ -81,63 +81,64 @@
  amKnife-------------------------------------------------------------------------------|
  amRubber-------------------------------------------------------------------------------|
  amAirMine-------------------------------------------------------------------------------|
+ amDuck-----------------------------------------------------------------------------------|
 */
-#define AMMOLINE_DEFAULT_QT     "939192942219912103223511100120000000021110010101111100010"
-#define AMMOLINE_DEFAULT_PROB   "040504054160065554655446477657666666615551010111541111111"
-#define AMMOLINE_DEFAULT_DELAY  "000000000000020550000004000700400000000022000000060002000"
-#define AMMOLINE_DEFAULT_CRATE  "131111031211111112311411111111111111121111110111111111111"
+#define AMMOLINE_DEFAULT_QT     "9391929422199121032235111001200000000211100101011111000102"
+#define AMMOLINE_DEFAULT_PROB   "0405040541600655546554464776576666666155510101115411111114"
+#define AMMOLINE_DEFAULT_DELAY  "0000000000000205500000040007004000000000220000000600020000"
+#define AMMOLINE_DEFAULT_CRATE  "1311110312111111123114111111111111111211111111111111111111"
 
-#define AMMOLINE_CRAZY_QT       "999999999999999999299999999999999929999999990999999299919"
-#define AMMOLINE_CRAZY_PROB     "111111011111111111111111111111111111111111110111111111111"
-#define AMMOLINE_CRAZY_DELAY    "000000000000000000000000000000000000000000000000000000000"
-#define AMMOLINE_CRAZY_CRATE    "131111031211111112311411111111111111121111010111111111111"
+#define AMMOLINE_CRAZY_QT       "9999999999999999992999999999999999299999999999999992999199"
+#define AMMOLINE_CRAZY_PROB     "1111110111111111111111111111111111111111111111111111111111"
+#define AMMOLINE_CRAZY_DELAY    "0000000000000000000000000000000000000000000000000000000000"
+#define AMMOLINE_CRAZY_CRATE    "1311110312111111123114111111111111111211111111111111111111"
 
-#define AMMOLINE_PROMODE_QT     "909000900000000000000900000000000000000000000000000000000"
-#define AMMOLINE_PROMODE_PROB   "000000000000000000000000000000000000000000000000000000000"
-#define AMMOLINE_PROMODE_DELAY  "000000000000020550000004000700400000000020000000000002000"
-#define AMMOLINE_PROMODE_CRATE  "111111011111111111111111111111111111111110010111111111111"
+#define AMMOLINE_PROMODE_QT     "9090009000000000000009000000000000000000000000000000000000"
+#define AMMOLINE_PROMODE_PROB   "0000000000000000000000000000000000000000000000000000000000"
+#define AMMOLINE_PROMODE_DELAY  "0000000000000205500000040007004000000000200000000000020000"
+#define AMMOLINE_PROMODE_CRATE  "1111110111111111111111111111111111111111111111111111111111"
 
-#define AMMOLINE_SHOPPA_QT      "000000990000000000000000000000000000000000000000000000000"
-#define AMMOLINE_SHOPPA_PROB    "444441004424440221011212122242200000000200040001001100101"
-#define AMMOLINE_SHOPPA_DELAY   "000000000000000000000000000000000000000000000000000000000"
-#define AMMOLINE_SHOPPA_CRATE   "111111011111111111111111111111111111111110110111111111101"
+#define AMMOLINE_SHOPPA_QT      "0000009900000000000000000000000000000000000000000000000000"
+#define AMMOLINE_SHOPPA_PROB    "4444410044244402210112121222422000000002000400010011001011"
+#define AMMOLINE_SHOPPA_DELAY   "0000000000000000000000000000000000000000000000000000000000"
+#define AMMOLINE_SHOPPA_CRATE   "1111110111111111111111111111111111111111111111111111111111"
 
-#define AMMOLINE_CLEAN_QT       "101000900001000001100000000000000000000000000000100000000"
-#define AMMOLINE_CLEAN_PROB     "040504054160065554655446477657666666615551010111541112111"
-#define AMMOLINE_CLEAN_DELAY    "000000000000000000000000000000000000000000000000000002000"
-#define AMMOLINE_CLEAN_CRATE    "131111031211111112311411111111111111121111110111111111111"
+#define AMMOLINE_CLEAN_QT       "1010009000010000011000000000000000000000000000001000000000"
+#define AMMOLINE_CLEAN_PROB     "0405040541600655546554464776576666666155510101115411121114"
+#define AMMOLINE_CLEAN_DELAY    "0000000000000000000000000000000000000000000000000000020000"
+#define AMMOLINE_CLEAN_CRATE    "1311110312111111123114111111111111111211111111111111111111"
 
-#define AMMOLINE_MINES_QT       "000000990009000000030000000000000000000000000000000000000"
-#define AMMOLINE_MINES_PROB     "000000000000000000000000000000000000000000000000000000000"
-#define AMMOLINE_MINES_DELAY    "000000000000020550000004000700400000000020000000060002000"
-#define AMMOLINE_MINES_CRATE    "111111011111111111111111111111111111111111110111111111111"
+#define AMMOLINE_MINES_QT       "0000009900090000000300000000000000000000000000000000000000"
+#define AMMOLINE_MINES_PROB     "0000000000000000000000000000000000000000000000000000000000"
+#define AMMOLINE_MINES_DELAY    "0000000000000205500000040007004000000000200000000600020000"
+#define AMMOLINE_MINES_CRATE    "1111110111111111111111111111111111111111111111111111111111"
 
-#define AMMOLINE_PORTALS_QT     "900000900200000000210000000000000011000009000000000000000"
-#define AMMOLINE_PORTALS_PROB   "040504054160065554655446477657666666615551010111541112111"
-#define AMMOLINE_PORTALS_DELAY  "000000000000020550000004000700400000000020000000060002000"
-#define AMMOLINE_PORTALS_CRATE  "131111031211111112311411111111111111121111110111111111111"
+#define AMMOLINE_PORTALS_QT     "9000009002000000002100000000000000110000090000000000000000"
+#define AMMOLINE_PORTALS_PROB   "0405040541600655546554464776576666666155510101115411121112"
+#define AMMOLINE_PORTALS_DELAY  "0000000000000205500000040007004000000000200000000600020000"
+#define AMMOLINE_PORTALS_CRATE  "1311110312111111123114111111111111111211111111111111111111"
 
-#define AMMOLINE_ONEEVERY_QT    "111111911111111111111111111111111111111111111111111111111"
-#define AMMOLINE_ONEEVERY_PROB  "111111011111111111111111111111111111111111111111111111111"
-#define AMMOLINE_ONEEVERY_DELAY "000000000000000000000000000000000000000000000000000000000"
-#define AMMOLINE_ONEEVERY_CRATE "111111011111111111111111111111111111111111111111111111111"
+#define AMMOLINE_ONEEVERY_QT    "1111119111111111111111111111111111111111111111111111111111"
+#define AMMOLINE_ONEEVERY_PROB  "1111110111111111111111111111111111111111111111111111111111"
+#define AMMOLINE_ONEEVERY_DELAY "0000000000000000000000000000000000000000000000000000000000"
+#define AMMOLINE_ONEEVERY_CRATE "1111110111111111111111111111111111111111111111111111111111"
 
-#define AMMOLINE_HIGHLANDER_QT    "111111911111111111110191111111111001011111011110110011010"
-#define AMMOLINE_HIGHLANDER_PROB  "000000000000000000000000000000000000000000000000000000000"
-#define AMMOLINE_HIGHLANDER_DELAY "000000000000000000000000000000000000000000000000000000000"
-#define AMMOLINE_HIGHLANDER_CRATE "000000000000000000000000000000000000000000000000000000000"
+#define AMMOLINE_HIGHLANDER_QT    "1111119111111111111101911111111110010111110111100100101111"
+#define AMMOLINE_HIGHLANDER_PROB  "0000000000000000000000000000000000000000000000000000000000"
+#define AMMOLINE_HIGHLANDER_DELAY "0000000000000000000000000000000000000000000000000000000000"
+#define AMMOLINE_HIGHLANDER_CRATE "0000000000000000000000000000000000000000000000000000000000"
 
-#define AMMOLINE_CONSTRUCTION_QT    "110001900000001001000000000000000000000000000000000000000"
-#define AMMOLINE_CONSTRUCTION_PROB  "111111011111111111111111111111111111111111111111111111110"
-#define AMMOLINE_CONSTRUCTION_DELAY "000000000000000000000000000000000000000000000000000000000"
-#define AMMOLINE_CONSTRUCTION_CRATE "111111011111111111111111111111111111111111111111111111110"
+#define AMMOLINE_CONSTRUCTION_QT    "1100019000000010010000000000000000000000000000000000000000"
+#define AMMOLINE_CONSTRUCTION_PROB  "1111110111111111111111111111111111111111111111111111111111"
+#define AMMOLINE_CONSTRUCTION_DELAY "0000000000000000000000000000000000000000000000000000000000"
+#define AMMOLINE_CONSTRUCTION_CRATE "1111110111111111111111111111111111111111111111111111111111"
 
-#define AMMOLINE_SHOPPAPRO_QT      "000000990000000000000000000000000000000000000000000000000"
-#define AMMOLINE_SHOPPAPRO_PROB    "444440004404440000000000000040000000000000000000000000000"
-#define AMMOLINE_SHOPPAPRO_DELAY   "000000000000000000000000000000000000000000000000000000000"
-#define AMMOLINE_SHOPPAPRO_CRATE   "111111011111111111111111111111111111111110110111111112110"
+#define AMMOLINE_SHOPPAPRO_QT      "0000009900000000000000000000000000000000000000000000000000"
+#define AMMOLINE_SHOPPAPRO_PROB    "4444400044044400000000000000400000000000000000000000000000"
+#define AMMOLINE_SHOPPAPRO_DELAY   "0000000000000000000000000000000000000000000000000000000000"
+#define AMMOLINE_SHOPPAPRO_CRATE   "1111110111111111111111111111111111111111111111111111121111"
 
-
-//When adding new weapons also insert one element in cDefaultAmmos list (hwconsts.cpp.in)
-
-
+#define AMMOLINE_HEDGEEDITOR_QT    "0000009000000000000000000000000000000000000000000000000000"
+#define AMMOLINE_HEDGEEDITOR_PROB  "0000000000000000000000000000000000000000000000000000000000"
+#define AMMOLINE_HEDGEEDITOR_DELAY "0000000000000000000000000000000000000000000000000000000000"
+#define AMMOLINE_HEDGEEDITOR_CRATE "1111110111111111111111111111111111111111111111111111111111"
--- a/README.md	Thu Aug 11 23:05:14 2016 +0300
+++ b/README.md	Sun Dec 17 00:09:24 2017 +0100
@@ -1,48 +1,125 @@
-Hedgewars - a turn based strategy game.
-=======================================
+Hedgewars - a turn-based strategy game
+======================================
+
+Description
+-----------
+This is the funniest and most addictive game you'll ever play—hilarious fun
+that you can enjoy anywhere, anytime. **Hedgewars** is a **turn-based strategy
+game** but the real buzz is from watching the **devastation caused by those
+pesky hedgehogs** with those fantastic weapons—sneaky little blighters with a
+bad attitude!
+
+Each player controls a **team of up to 8 hedgehogs**. During the course of
+the game, players take turns with one of their hedgehogs. They then use
+whatever tools and weapons are available to **attack and kill the opponents'
+hedgehogs**, thereby winning the game. Hedgehogs may move around the terrain
+in a variety of ways, normally by walking and jumping but also by using
+particular tools such as the rope or parachute, to move to otherwise
+inaccessible areas. Each **turn is time-limited** to ensure that players do
+not hold up the game with excessive thinking or moving.
+
+A large **variety of tools and weapons** are available for players during
+the game. Hedgewars features the standard artillery-genre classics (such as
+grenade, cluster bomb, bazooka, shotgun), but also boasts a host of other
+weapons quite unique to it alone.
+
+Most weapons, when used, cause **explosions that deform the terrain**,
+removing circular chunks. Hedgehogs can die by drowning, being thrown off
+either side of the arena, or when their health is reduced to zero.
+
+Getting started
+---------------
+For complete beginners we recommend to start with the the first 2 or 3
+missions of the campaign “A Classic Fairytale” in the singleplayer menu.
+It explains the basic controls and gameplay.
+
+Note that Hedgewars doesn't have a *complete* tutorial yet, but it is
+planned to create one in future versions.
+
+In-depth information about the game can be found online:
+
+* <https://hedgewars.org/start>: Getting Started
+* <https://hedgewars.org/wiki.html>: Hedgewars Wiki
+
+Default controls (excerpt)
+--------------------------
+The most important default controls are:
+
+* Cursor keys: Walk and aim
+* Mouse: Move camera
+* Right mouse button: Open ammo menu
+* Left mouse button: Select target or weapon
+* Space bar: Shoot
+* Left shift: Precise
+* Left shift + Up/Down: Precise aiming
+* Enter: Jump
+* Backspace: High jump
+* Backspace ×2: Backjump
+* Tab: Switch hedgehog (after activating the utility)
+* 1-5: Set weapon timer
+* F1-F10: Weapon shortcuts
+* P: Pause (also shows mission panel)
+* Esc: Quit with prompt (also shows mission panel)
+* T: Chat
+
+For the full list, go to the Hedgewars settings. Also read the weapon tooltips
+for weapon-specific controls.
+
+### Special controls
+
+These are lesser-known controls of Hedgewars, they are based on your
+configured controls:
+
+* Confirm: Team chat (if not confirming quit)
+* Hold down Precise: Prevent slipping on ice
+* Precise + Left/Right: Turn around
+* Precise + Toggle team bars: Change hedgehog tabs
+* Precise + Toggle team bars + Switch: Toggle HUD
+* Precise + Screenshot: Save current map + mask in Screenshot directory
+
+Installation instructions
+-------------------------
+See the `INSTALL.md` file.
+
+Or see our wiki at <https://hedgewars.org/kb/BuildingHedgewars>.
+
+Source code
+-----------
+Our main repository is located at <https://hg.hedgewars.org/hedgewars/> using
+Mercurial as DVCS. A Git repository is also available (mirrored daily)
+at <https://github.com/hedgewars/hw>.
 
 [![Build Status](https://travis-ci.org/hedgewars/hw.svg)](https://travis-ci.org/hedgewars/hw)
 
-Copyright 2004-2015 Andrey Korotaev <unC0Rr@gmail.com> and others.
-See QTfrontend/res/html/about.html and CREDITS for a complete list of authors.
-
-Licence:
---------
-Source code is distributed under the terms of the GNU General Public Licence
-version 2; images and sounds are distributed under the terms of the GNU Free
-Documentation Licence version 1.2. See the COPYING file for the full text of
-the licenses.
-
-Instructions:
--------------
-See our wiki at: http://hedgewars.org/kb/BuildingHedgewars
-
-You can find an outline of the necessary dependencies in the INSTALL file.
-
-Source code:
-------------
-Our main repository is located at http://hg.hedgewars.org/hedgewars/ using
-Mercurial as DVCS. A Git repository is also available (mirrored daily)
-at https://github.com/hedgewars/hw
-
-Contribute:
------------
+Contribute
+----------
 If you see a bug or have any suggestion please use the official bug tracker at
-http://hedgewars.org/bugs or the integrated feedback
-button.
+<https://hedgewars.org/bugs> or the integrated feedback button.
 
 If you want to help or get to know the sources better you can do that with some
-easy tasks from http://hedgewars.org/kb/TODO. We also have an
-extended API in LUA to customize your adventures in our wiki at
-http://hedgewars.org/kb/LuaAPI.
+easy tasks from <https://hedgewars.org/kb/TODO>. We also have an extensive API
+in Lua to customize your adventures. See our wiki at
+<https://hedgewars.org/kb/LuaAPI>.
 
 If you know your way through the code feel free to send a patch or open a pull
-request. The best LUA scripts get released in the official DLC page and later
+request. The best Lua scripts get released in the official DLC page and later
 integrated in the next version.
 
-Contact:
---------
+Licence and credits
+-------------------
+This game is free software (“free” as in “freedom”). Source code is
+distributed under the terms of the GNU General Public Licence version 2;
+images and sounds are distributed under the terms of the GNU Free Documentation
+Licence version 1.2. See the `COPYING` file for the full text of the licenses.
+
+Copyright 2004-2015 Andrey Korotaev <unC0Rr@gmail.com> and others.
+See `QTfrontend/res/html/about.html` and `CREDITS` for a more complete list of
+authors.
+
+Contact
+-------
+* Homepage        - https://hedgewars.org/
 * IRC channel     - irc://irc.freenode.net/hedgewars
-* community forum - http://www.hedgewars.org/forum
-* mailing list    - https://mail.gna.org/listinfo/hedgewars-dev
+* Community forum - https://hedgewars.org/forum
+* Mailing list    - https://mail.gna.org/listinfo/hedgewars-dev
 
--- a/cmake_modules/CheckHaskellModuleExists.cmake	Thu Aug 11 23:05:14 2016 +0300
+++ b/cmake_modules/CheckHaskellModuleExists.cmake	Sun Dec 17 00:09:24 2017 +0100
@@ -22,12 +22,15 @@
         endforeach()
     endif()
 
-    set(PARAMETERS "")
+    #set(PARAMETERS "")
 
     execute_process(COMMAND ${GHC_EXECUTABLE}
                     "-DMODULE=${MODULE}"
                     "-DFUNCTION=${FUNCTION}"
                     "-DPARAMETERS=${PARAMETERS}"
+                    -hide-all-packages
+                    -package ${LIBRARY}
+                    -package base
                     -cpp
                     -c "${CMAKE_MODULE_PATH}/checkModule.hs"
                     RESULT_VARIABLE COMMAND_RESULT
--- a/cmake_modules/FindLua.cmake	Thu Aug 11 23:05:14 2016 +0300
+++ b/cmake_modules/FindLua.cmake	Sun Dec 17 00:09:24 2017 +0100
@@ -18,7 +18,7 @@
 find_path(LUA_INCLUDE_DIR lua.h
                           PATHS /usr/include /usr/local/include /usr/pkg/include
                           PATH_SUFFIXES lua5.1 lua51 lua-5.1)
-find_library(LUA_LIBRARY NAMES lua51 lua5.1 lua-5.1 lua
+find_library(LUA_LIBRARY NAMES liblua lua51 lua5.1 lua-5.1 lua
                          PATHS /lib /usr/lib /usr/local/lib /usr/pkg/lib)
 
 find_package_handle_standard_args(Lua DEFAULT_MSG LUA_LIBRARY LUA_INCLUDE_DIR)
--- a/cmake_modules/FindSDL2_image.cmake	Thu Aug 11 23:05:14 2016 +0300
+++ b/cmake_modules/FindSDL2_image.cmake	Sun Dec 17 00:09:24 2017 +0100
@@ -55,13 +55,13 @@
   PATH_SUFFIXES lib
 )
 
-if(SDL2_IMAGE_INCLUDE_DIR AND EXISTS "${SDL2_IMAGE_INCLUDE_DIR}/SDL2_image.h")
-  file(STRINGS "${SDL2_IMAGE_INCLUDE_DIR}/SDL2_image.h" SDL2_IMAGE_VERSION_MAJOR_LINE REGEX "^#define[ \t]+SDL2_IMAGE_MAJOR_VERSION[ \t]+[0-9]+$")
-  file(STRINGS "${SDL2_IMAGE_INCLUDE_DIR}/SDL2_image.h" SDL2_IMAGE_VERSION_MINOR_LINE REGEX "^#define[ \t]+SDL2_IMAGE_MINOR_VERSION[ \t]+[0-9]+$")
-  file(STRINGS "${SDL2_IMAGE_INCLUDE_DIR}/SDL2_image.h" SDL2_IMAGE_VERSION_PATCH_LINE REGEX "^#define[ \t]+SDL2_IMAGE_PATCHLEVEL[ \t]+[0-9]+$")
-  string(REGEX REPLACE "^#define[ \t]+SDL2_IMAGE_MAJOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_IMAGE_VERSION_MAJOR "${SDL2_IMAGE_VERSION_MAJOR_LINE}")
-  string(REGEX REPLACE "^#define[ \t]+SDL2_IMAGE_MINOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_IMAGE_VERSION_MINOR "${SDL2_IMAGE_VERSION_MINOR_LINE}")
-  string(REGEX REPLACE "^#define[ \t]+SDL2_IMAGE_PATCHLEVEL[ \t]+([0-9]+)$" "\\1" SDL2_IMAGE_VERSION_PATCH "${SDL2_IMAGE_VERSION_PATCH_LINE}")
+if(SDL2_IMAGE_INCLUDE_DIR AND EXISTS "${SDL2_IMAGE_INCLUDE_DIR}/SDL_image.h")
+  file(STRINGS "${SDL2_IMAGE_INCLUDE_DIR}/SDL_image.h" SDL2_IMAGE_VERSION_MAJOR_LINE REGEX "^#define[ \t]+SDL_IMAGE_MAJOR_VERSION[ \t]+[0-9]+$")
+  file(STRINGS "${SDL2_IMAGE_INCLUDE_DIR}/SDL_image.h" SDL2_IMAGE_VERSION_MINOR_LINE REGEX "^#define[ \t]+SDL_IMAGE_MINOR_VERSION[ \t]+[0-9]+$")
+  file(STRINGS "${SDL2_IMAGE_INCLUDE_DIR}/SDL_image.h" SDL2_IMAGE_VERSION_PATCH_LINE REGEX "^#define[ \t]+SDL_IMAGE_PATCHLEVEL[ \t]+[0-9]+$")
+  string(REGEX REPLACE "^#define[ \t]+SDL_IMAGE_MAJOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_IMAGE_VERSION_MAJOR "${SDL2_IMAGE_VERSION_MAJOR_LINE}")
+  string(REGEX REPLACE "^#define[ \t]+SDL_IMAGE_MINOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_IMAGE_VERSION_MINOR "${SDL2_IMAGE_VERSION_MINOR_LINE}")
+  string(REGEX REPLACE "^#define[ \t]+SDL_IMAGE_PATCHLEVEL[ \t]+([0-9]+)$" "\\1" SDL2_IMAGE_VERSION_PATCH "${SDL2_IMAGE_VERSION_PATCH_LINE}")
   set(SDL2_IMAGE_VERSION_STRING ${SDL2_IMAGE_VERSION_MAJOR}.${SDL2_IMAGE_VERSION_MINOR}.${SDL2_IMAGE_VERSION_PATCH})
   unset(SDL2_IMAGE_VERSION_MAJOR_LINE)
   unset(SDL2_IMAGE_VERSION_MINOR_LINE)
@@ -87,8 +87,8 @@
                                   VERSION_VAR SDL2_IMAGE_VERSION_STRING)
 
 # for backward compatiblity
-set(SDL2IMAGE_LIBRARY ${SDL2_IMAGE_LIBRARIES})
-set(SDL2IMAGE_INCLUDE_DIR ${SDL2_IMAGE_INCLUDE_DIRS})
-set(SDL2IMAGE_FOUND ${SDL2_IMAGE_FOUND})
+set(SDLIMAGE_LIBRARY ${SDL2_IMAGE_LIBRARIES})
+set(SDLIMAGE_INCLUDE_DIR ${SDL2_IMAGE_INCLUDE_DIRS})
+set(SDLIMAGE_FOUND ${SDL2_IMAGE_FOUND})
 
 mark_as_advanced(SDL2_IMAGE_LIBRARY SDL2_IMAGE_INCLUDE_DIR)
--- a/cmake_modules/FindSDL2_mixer.cmake	Thu Aug 11 23:05:14 2016 +0300
+++ b/cmake_modules/FindSDL2_mixer.cmake	Sun Dec 17 00:09:24 2017 +0100
@@ -33,8 +33,7 @@
 #  License text for the above reference.)
 
 if(NOT SDL2_MIXER_INCLUDE_DIR AND SDL2MIXER_INCLUDE_DIR)
-  set(SDL2_MIXER_INCLUDE_DIR ${SDL2MIXER_INCLUDE_DIR} CACHE PATH "directory cache
-entry initialized from old variable name")
+  set(SDL2_MIXER_INCLUDE_DIR ${SDL2MIXER_INCLUDE_DIR} CACHE PATH "directory cache entry initialized from old variable name")
 endif()
 find_path(SDL2_MIXER_INCLUDE_DIR SDL_mixer.h
   HINTS
@@ -55,13 +54,13 @@
   PATH_SUFFIXES lib
 )
 
-if(SDL2_MIXER_INCLUDE_DIR AND EXISTS "${SDL2_MIXER_INCLUDE_DIR}/SDL2_mixer.h")
-  file(STRINGS "${SDL2_MIXER_INCLUDE_DIR}/SDL2_mixer.h" SDL2_MIXER_VERSION_MAJOR_LINE REGEX "^#define[ \t]+SDL2_MIXER_MAJOR_VERSION[ \t]+[0-9]+$")
-  file(STRINGS "${SDL2_MIXER_INCLUDE_DIR}/SDL2_mixer.h" SDL2_MIXER_VERSION_MINOR_LINE REGEX "^#define[ \t]+SDL2_MIXER_MINOR_VERSION[ \t]+[0-9]+$")
-  file(STRINGS "${SDL2_MIXER_INCLUDE_DIR}/SDL2_mixer.h" SDL2_MIXER_VERSION_PATCH_LINE REGEX "^#define[ \t]+SDL2_MIXER_PATCHLEVEL[ \t]+[0-9]+$")
-  string(REGEX REPLACE "^#define[ \t]+SDL2_MIXER_MAJOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_MIXER_VERSION_MAJOR "${SDL2_MIXER_VERSION_MAJOR_LINE}")
-  string(REGEX REPLACE "^#define[ \t]+SDL2_MIXER_MINOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_MIXER_VERSION_MINOR "${SDL2_MIXER_VERSION_MINOR_LINE}")
-  string(REGEX REPLACE "^#define[ \t]+SDL2_MIXER_PATCHLEVEL[ \t]+([0-9]+)$" "\\1" SDL2_MIXER_VERSION_PATCH "${SDL2_MIXER_VERSION_PATCH_LINE}")
+if(SDL2_MIXER_INCLUDE_DIR AND EXISTS "${SDL2_MIXER_INCLUDE_DIR}/SDL_mixer.h")
+  file(STRINGS "${SDL2_MIXER_INCLUDE_DIR}/SDL_mixer.h" SDL2_MIXER_VERSION_MAJOR_LINE REGEX "^#define[ \t]+SDL_MIXER_MAJOR_VERSION[ \t]+[0-9]+$")
+  file(STRINGS "${SDL2_MIXER_INCLUDE_DIR}/SDL_mixer.h" SDL2_MIXER_VERSION_MINOR_LINE REGEX "^#define[ \t]+SDL_MIXER_MINOR_VERSION[ \t]+[0-9]+$")
+  file(STRINGS "${SDL2_MIXER_INCLUDE_DIR}/SDL_mixer.h" SDL2_MIXER_VERSION_PATCH_LINE REGEX "^#define[ \t]+SDL_MIXER_PATCHLEVEL[ \t]+[0-9]+$")
+  string(REGEX REPLACE "^#define[ \t]+SDL_MIXER_MAJOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_MIXER_VERSION_MAJOR "${SDL2_MIXER_VERSION_MAJOR_LINE}")
+  string(REGEX REPLACE "^#define[ \t]+SDL_MIXER_MINOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_MIXER_VERSION_MINOR "${SDL2_MIXER_VERSION_MINOR_LINE}")
+  string(REGEX REPLACE "^#define[ \t]+SDL_MIXER_PATCHLEVEL[ \t]+([0-9]+)$" "\\1" SDL2_MIXER_VERSION_PATCH "${SDL2_MIXER_VERSION_PATCH_LINE}")
   set(SDL2_MIXER_VERSION_STRING ${SDL2_MIXER_VERSION_MAJOR}.${SDL2_MIXER_VERSION_MINOR}.${SDL2_MIXER_VERSION_PATCH})
   unset(SDL2_MIXER_VERSION_MAJOR_LINE)
   unset(SDL2_MIXER_VERSION_MINOR_LINE)
@@ -87,8 +86,8 @@
                                   VERSION_VAR SDL2_MIXER_VERSION_STRING)
 
 # for backward compatiblity
-set(SDL2MIXER_LIBRARY ${SDL2_MIXER_LIBRARIES})
-set(SDL2MIXER_INCLUDE_DIR ${SDL2_MIXER_INCLUDE_DIRS})
-set(SDL2MIXER_FOUND ${SDL2_MIXER_FOUND})
+set(SDLMIXER_LIBRARY ${SDL2_MIXER_LIBRARIES})
+set(SDLMIXER_INCLUDE_DIR ${SDL2_MIXER_INCLUDE_DIRS})
+set(SDLMIXER_FOUND ${SDL2_MIXER_FOUND})
 
 mark_as_advanced(SDL2_MIXER_LIBRARY SDL2_MIXER_INCLUDE_DIR)
--- a/cmake_modules/FindSDL2_net.cmake	Thu Aug 11 23:05:14 2016 +0300
+++ b/cmake_modules/FindSDL2_net.cmake	Sun Dec 17 00:09:24 2017 +0100
@@ -55,13 +55,13 @@
   PATH_SUFFIXES lib
 )
 
-if(SDL2_NET_INCLUDE_DIR AND EXISTS "${SDL2_NET_INCLUDE_DIR}/SDL2_net.h")
-  file(STRINGS "${SDL2_NET_INCLUDE_DIR}/SDL2_net.h" SDL2_NET_VERSION_MAJOR_LINE REGEX "^#define[ \t]+SDL2_NET_MAJOR_VERSION[ \t]+[0-9]+$")
-  file(STRINGS "${SDL2_NET_INCLUDE_DIR}/SDL2_net.h" SDL2_NET_VERSION_MINOR_LINE REGEX "^#define[ \t]+SDL2_NET_MINOR_VERSION[ \t]+[0-9]+$")
-  file(STRINGS "${SDL2_NET_INCLUDE_DIR}/SDL2_net.h" SDL2_NET_VERSION_PATCH_LINE REGEX "^#define[ \t]+SDL2_NET_PATCHLEVEL[ \t]+[0-9]+$")
-  string(REGEX REPLACE "^#define[ \t]+SDL2_NET_MAJOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_NET_VERSION_MAJOR "${SDL2_NET_VERSION_MAJOR_LINE}")
-  string(REGEX REPLACE "^#define[ \t]+SDL2_NET_MINOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_NET_VERSION_MINOR "${SDL2_NET_VERSION_MINOR_LINE}")
-  string(REGEX REPLACE "^#define[ \t]+SDL2_NET_PATCHLEVEL[ \t]+([0-9]+)$" "\\1" SDL2_NET_VERSION_PATCH "${SDL2_NET_VERSION_PATCH_LINE}")
+if(SDL2_NET_INCLUDE_DIR AND EXISTS "${SDL2_NET_INCLUDE_DIR}/SDL_net.h")
+  file(STRINGS "${SDL2_NET_INCLUDE_DIR}/SDL_net.h" SDL2_NET_VERSION_MAJOR_LINE REGEX "^#define[ \t]+SDL_NET_MAJOR_VERSION[ \t]+[0-9]+$")
+  file(STRINGS "${SDL2_NET_INCLUDE_DIR}/SDL_net.h" SDL2_NET_VERSION_MINOR_LINE REGEX "^#define[ \t]+SDL_NET_MINOR_VERSION[ \t]+[0-9]+$")
+  file(STRINGS "${SDL2_NET_INCLUDE_DIR}/SDL_net.h" SDL2_NET_VERSION_PATCH_LINE REGEX "^#define[ \t]+SDL_NET_PATCHLEVEL[ \t]+[0-9]+$")
+  string(REGEX REPLACE "^#define[ \t]+SDL_NET_MAJOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_NET_VERSION_MAJOR "${SDL2_NET_VERSION_MAJOR_LINE}")
+  string(REGEX REPLACE "^#define[ \t]+SDL_NET_MINOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_NET_VERSION_MINOR "${SDL2_NET_VERSION_MINOR_LINE}")
+  string(REGEX REPLACE "^#define[ \t]+SDL_NET_PATCHLEVEL[ \t]+([0-9]+)$" "\\1" SDL2_NET_VERSION_PATCH "${SDL2_NET_VERSION_PATCH_LINE}")
   set(SDL2_NET_VERSION_STRING ${SDL2_NET_VERSION_MAJOR}.${SDL2_NET_VERSION_MINOR}.${SDL2_NET_VERSION_PATCH})
   unset(SDL2_NET_VERSION_MAJOR_LINE)
   unset(SDL2_NET_VERSION_MINOR_LINE)
@@ -87,8 +87,8 @@
                                   VERSION_VAR SDL2_NET_VERSION_STRING)
 
 # for backward compatiblity
-set(SDL2NET_LIBRARY ${SDL2_NET_LIBRARIES})
-set(SDL2NET_INCLUDE_DIR ${SDL2_NET_INCLUDE_DIRS})
-set(SDL2NET_FOUND ${SDL2_NET_FOUND})
+set(SDLNET_LIBRARY ${SDL2_NET_LIBRARIES})
+set(SDLNET_INCLUDE_DIR ${SDL2_NET_INCLUDE_DIRS})
+set(SDLNET_FOUND ${SDL2_NET_FOUND})
 
 mark_as_advanced(SDL2_NET_LIBRARY SDL2_NET_INCLUDE_DIR)
--- a/cmake_modules/FindSDL2_ttf.cmake	Thu Aug 11 23:05:14 2016 +0300
+++ b/cmake_modules/FindSDL2_ttf.cmake	Sun Dec 17 00:09:24 2017 +0100
@@ -55,13 +55,13 @@
   PATH_SUFFIXES lib
 )
 
-if(SDL2_TTF_INCLUDE_DIR AND EXISTS "${SDL2_TTF_INCLUDE_DIR}/SDL2_ttf.h")
-  file(STRINGS "${SDL2_TTF_INCLUDE_DIR}/SDL2_ttf.h" SDL2_TTF_VERSION_MAJOR_LINE REGEX "^#define[ \t]+SDL2_TTF_MAJOR_VERSION[ \t]+[0-9]+$")
-  file(STRINGS "${SDL2_TTF_INCLUDE_DIR}/SDL2_ttf.h" SDL2_TTF_VERSION_MINOR_LINE REGEX "^#define[ \t]+SDL2_TTF_MINOR_VERSION[ \t]+[0-9]+$")
-  file(STRINGS "${SDL2_TTF_INCLUDE_DIR}/SDL2_ttf.h" SDL2_TTF_VERSION_PATCH_LINE REGEX "^#define[ \t]+SDL2_TTF_PATCHLEVEL[ \t]+[0-9]+$")
-  string(REGEX REPLACE "^#define[ \t]+SDL2_TTF_MAJOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_TTF_VERSION_MAJOR "${SDL2_TTF_VERSION_MAJOR_LINE}")
-  string(REGEX REPLACE "^#define[ \t]+SDL2_TTF_MINOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_TTF_VERSION_MINOR "${SDL2_TTF_VERSION_MINOR_LINE}")
-  string(REGEX REPLACE "^#define[ \t]+SDL2_TTF_PATCHLEVEL[ \t]+([0-9]+)$" "\\1" SDL2_TTF_VERSION_PATCH "${SDL2_TTF_VERSION_PATCH_LINE}")
+if(SDL2_TTF_INCLUDE_DIR AND EXISTS "${SDL2_TTF_INCLUDE_DIR}/SDL_ttf.h")
+  file(STRINGS "${SDL2_TTF_INCLUDE_DIR}/SDL_ttf.h" SDL2_TTF_VERSION_MAJOR_LINE REGEX "^#define[ \t]+SDL_TTF_MAJOR_VERSION[ \t]+[0-9]+$")
+  file(STRINGS "${SDL2_TTF_INCLUDE_DIR}/SDL_ttf.h" SDL2_TTF_VERSION_MINOR_LINE REGEX "^#define[ \t]+SDL_TTF_MINOR_VERSION[ \t]+[0-9]+$")
+  file(STRINGS "${SDL2_TTF_INCLUDE_DIR}/SDL_ttf.h" SDL2_TTF_VERSION_PATCH_LINE REGEX "^#define[ \t]+SDL_TTF_PATCHLEVEL[ \t]+[0-9]+$")
+  string(REGEX REPLACE "^#define[ \t]+SDL_TTF_MAJOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_TTF_VERSION_MAJOR "${SDL2_TTF_VERSION_MAJOR_LINE}")
+  string(REGEX REPLACE "^#define[ \t]+SDL_TTF_MINOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_TTF_VERSION_MINOR "${SDL2_TTF_VERSION_MINOR_LINE}")
+  string(REGEX REPLACE "^#define[ \t]+SDL_TTF_PATCHLEVEL[ \t]+([0-9]+)$" "\\1" SDL2_TTF_VERSION_PATCH "${SDL2_TTF_VERSION_PATCH_LINE}")
   set(SDL2_TTF_VERSION_STRING ${SDL2_TTF_VERSION_MAJOR}.${SDL2_TTF_VERSION_MINOR}.${SDL2_TTF_VERSION_PATCH})
   unset(SDL2_TTF_VERSION_MAJOR_LINE)
   unset(SDL2_TTF_VERSION_MINOR_LINE)
@@ -87,8 +87,8 @@
                                   VERSION_VAR SDL2_TTF_VERSION_STRING)
 
 # for backward compatiblity
-set(SDL2TTF_LIBRARY ${SDL2_TTF_LIBRARIES})
-set(SDL2TTF_INCLUDE_DIR ${SDL2_TTF_INCLUDE_DIRS})
-set(SDL2TTF_FOUND ${SDL2_TTF_FOUND})
+set(SDLTTF_LIBRARY ${SDL2_TTF_LIBRARIES})
+set(SDLTTF_INCLUDE_DIR ${SDL2_TTF_INCLUDE_DIRS})
+set(SDLTTF_FOUND ${SDL2_TTF_FOUND})
 
 mark_as_advanced(SDL2_TTF_LIBRARY SDL2_TTF_INCLUDE_DIR)
--- a/cmake_modules/checkModule.hs	Thu Aug 11 23:05:14 2016 +0300
+++ b/cmake_modules/checkModule.hs	Sun Dec 17 00:09:24 2017 +0100
@@ -1,3 +1,4 @@
+{-# LANGUAGE ImpredicativeTypes #-}
 module Main where
 
 import qualified MODULE as M
--- a/cmake_modules/cpackvars.cmake	Thu Aug 11 23:05:14 2016 +0300
+++ b/cmake_modules/cpackvars.cmake	Sun Dec 17 00:09:24 2017 +0100
@@ -81,6 +81,8 @@
     "[dD]ebug$"
     "[rR]elease$"
     "CPack"
+    "CTestTestfile.cmake"
+    "gameServer2"
     "cmake_install\\\\.cmake$"
     "cmake_uninstall\\\\.cmake$"
     "CMakeCache\\\\.txt$"
--- a/gameServer/Actions.hs	Thu Aug 11 23:05:14 2016 +0300
+++ b/gameServer/Actions.hs	Sun Dec 17 00:09:24 2017 +0100
@@ -40,6 +40,9 @@
 import Network.Socket
 import System.Random
 import qualified Data.Traversable as DT
+import Text.Regex.Base
+import qualified Text.Regex.TDFA as TDFA
+import qualified Text.Regex.TDFA.ByteString as TDFAB
 -----------------------------
 #if defined(OFFICIAL_SERVER)
 import OfficialServer.GameReplayStore
@@ -512,12 +515,12 @@
     rnc <- gets roomsClients
     clientNick <- client's nick
     clProto <- client's clientProto
-    isAuthenticated <- liftM (not . B.null) $ client's webPassword
+    isAuthenticated <- client's isRegistered
     isAdmin <- client's isAdministrator
     isContr <- client's isContributor
     loggedInClients <- liftM (Prelude.filter isVisible) $! allClientsS
     let (lobbyNicks, clientsChans) = unzip . L.map (nick &&& sendChan) $ loggedInClients
-    let authenticatedNicks = L.map nick . L.filter (not . B.null . webPassword) $ loggedInClients
+    let authenticatedNicks = L.map nick . L.filter isRegistered $ loggedInClients
     let adminsNicks = L.map nick . L.filter isAdministrator $ loggedInClients
     let contrNicks = L.map nick . L.filter isContributor $ loggedInClients
     inRoomNicks <- io $
@@ -528,8 +531,8 @@
 
     roomsInfoList <- io $ do
         rooms <- roomsM rnc
-        mapM (\r -> (if isNothing $ masterID r then return "" else client'sM rnc nick (fromJust $ masterID r))
-            >>= \cn -> return $ roomInfo clProto cn r)
+        mapM (\r -> (mapM (client'sM rnc id) $ masterID r)
+            >>= \cn -> return $ roomInfo clProto (maybeNick cn) r)
             $ filter (\r -> (roomProto r == clProto)) rooms
 
     mapM_ processAction . concat $ [
@@ -658,9 +661,13 @@
     where
         checkNotExpired testTime (BanByIP _ _ time) = testTime `diffUTCTime` time <= 0
         checkNotExpired testTime (BanByNick _ _ time) = testTime `diffUTCTime` time <= 0
-        checkBan True ip _ (BanByIP bip _ _) = bip `B.isPrefixOf` ip
-        checkBan False _ n (BanByNick bn _ _) = caseInsensitiveCompare bn n
+        checkBan True ip _ (BanByIP bip _ _) = isMatch bip ip
+        checkBan False _ n (BanByNick bn _ _) = isMatch bn n
         checkBan _ _ _ _ = False
+        isMatch :: B.ByteString -> B.ByteString -> Bool
+        isMatch rexp src = (==) (Just True) $ mrexp rexp >>= flip matchM src
+        mrexp :: B.ByteString -> Maybe TDFAB.Regex
+        mrexp = makeRegexOptsM TDFA.defaultCompOpt{TDFA.caseSensitive = False} TDFA.defaultExecOpt
         getBanReason (BanByIP _ msg _) = msg
         getBanReason (BanByNick _ msg _) = msg
 
--- a/gameServer/CMakeLists.txt	Thu Aug 11 23:05:14 2016 +0300
+++ b/gameServer/CMakeLists.txt	Sun Dec 17 00:09:24 2017 +0100
@@ -12,7 +12,7 @@
 check_haskell_module_exists("Network.BSD" getHostName 0 network)
 check_haskell_module_exists("Data.Time" getCurrentTime 0 time)
 check_haskell_module_exists("Control.Monad.State" fix 1 mtl)
-check_haskell_module_exists("Codec.Binary.Base64" encode 1 dataenc)
+check_haskell_module_exists("Codec.Binary.Base64" encode 1 sandi)
 check_haskell_module_exists("System.Log.Logger" warningM 1 hslogger)
 check_haskell_module_exists("System.Process" createProcess 3 process)
 check_haskell_module_exists("Data.ByteString.Lazy.UTF8" decode 1 utf8-string)
@@ -20,6 +20,7 @@
 check_haskell_module_exists("System.Entropy" openHandle 0 entropy)
 check_haskell_module_exists("Codec.Compression.Zlib" decompress 1 zlib)
 check_haskell_module_exists("System.Random" getStdGen 0 random)
+check_haskell_module_exists("Text.Regex.TDFA.ByteString" execute 2 regex-tdfa)
 
 # this one needs type signatures to work
 # check_haskell_module_exists("Control.DeepSeq" deepseq 2 deepseq)
--- a/gameServer/CoreTypes.hs	Thu Aug 11 23:05:14 2016 +0300
+++ b/gameServer/CoreTypes.hs	Sun Dec 17 00:09:24 2017 +0100
@@ -311,8 +311,8 @@
         True
         False
         "<h2><p align=center><a href=\"http://www.hedgewars.org/\">http://www.hedgewars.org/</a></p></h2>"
-        "<font color=yellow><h3 align=center>Hedgewars 0.9.22 is out! Please update.</h3><p align=center><a href=http://hedgewars.org/download.html>Download page here</a></font>"
-        51 -- latestReleaseVersion
+        "<font color=yellow><h3 align=center>Hedgewars 0.9.23 is out! Please update.</h3><p align=center><a href=http://hedgewars.org/download.html>Download page here</a></font>"
+        53 -- latestReleaseVersion
         41 -- earliestCompatibleVersion
         46631
         ""
--- a/gameServer/EngineInteraction.hs	Thu Aug 11 23:05:14 2016 +0300
+++ b/gameServer/EngineInteraction.hs	Sun Dec 17 00:09:24 2017 +0100
@@ -44,26 +44,20 @@
 import Utils
 
 #if defined(OFFICIAL_SERVER)
-{-
-    this is snippet from http://stackoverflow.com/questions/10043102/how-to-catch-the-decompress-ioerror
-    because standard 'catch' doesn't seem to catch decompression errors for some reason
--}
 import qualified Codec.Compression.Zlib.Internal as ZI
 import qualified Codec.Compression.Zlib as Z
 
-decompressWithoutExceptions :: BL.ByteString -> Either String BL.ByteString
-decompressWithoutExceptions = finalise
-                            . ZI.foldDecompressStream cons nil err
-                            . ZI.decompressWithErrors ZI.zlibFormat ZI.defaultDecompressParams
-  where err _ msg = Left msg
-        nil = Right []
-        cons chunk = right (chunk :)
-        finalise = right BL.fromChunks
-{- end snippet  -}
+decompressWithoutExceptions :: BL.ByteString -> BL.ByteString
+decompressWithoutExceptions = BL.fromChunks . ZI.foldDecompressStreamWithInput chunk end err decomp
+    where
+        decomp = ZI.decompressST ZI.zlibFormat ZI.defaultDecompressParams
+        chunk = (:)
+        end _ = []
+        err = const $ [BW.empty]
 #endif
 
 toEngineMsg :: B.ByteString -> B.ByteString
-toEngineMsg msg = B.pack $ Base64.encode (fromIntegral (BW.length msg) : BW.unpack msg)
+toEngineMsg msg = Base64.encode (fromIntegral (BW.length msg) `BW.cons` msg)
 
 
 {-fromEngineMsg :: B.ByteString -> Maybe B.ByteString
@@ -85,15 +79,15 @@
 checkNetCmd :: [Word8] -> B.ByteString -> (B.ByteString, B.ByteString, Maybe (Maybe B.ByteString))
 checkNetCmd teamsIndexes msg = check decoded
     where
-        decoded = liftM (splitMessages . BW.pack) $ Base64.decode $ B.unpack msg
-        check Nothing = (B.empty, B.empty, Nothing)
-        check (Just msgs) = let (a, b) = (filter isLegal msgs, filter isNonEmpty a) in (encode a, encode b, lft a)
-        encode = B.pack . Base64.encode . BW.unpack . B.concat
+        decoded = liftM splitMessages $ Base64.decode msg
+        check (Left _) = (B.empty, B.empty, Nothing)
+        check (Right msgs) = let (a, b) = (filter isLegal msgs, filter isNonEmpty a) in (encode a, encode b, lft a)
+        encode = Base64.encode . B.concat
         isLegal m = (B.length m > 1) && (flip Set.member legalMessages . B.head . B.tail $ m) && not (isMalformed (B.head m) (B.tail m))
         lft = foldr l Nothing
         l m n = let m' = B.head $ B.tail m; tst = flip Set.member in
                       if not $ tst timedMessages m' then n
-                        else if '+' /= m' then Just Nothing else Just . Just . B.pack . Base64.encode . BW.unpack $ m
+                        else if '+' /= m' then Just Nothing else Just . Just . Base64.encode $ m
         isNonEmpty = (/=) '+' . B.head . B.tail
         legalMessages = Set.fromList $ "M#+LlRrUuDdZzAaSjJ,NpPwtgfhbc12345" ++ slotMessages
         slotMessages = "\128\129\130\131\132\133\134\135\136\137\138"
@@ -187,13 +181,10 @@
         by200 m = Just $ L.splitAt 200 m
 
 unpackDrawnMap :: B.ByteString -> BL.ByteString
-unpackDrawnMap = either (const BL.empty) id
-        . decompressWithoutExceptions
-        . BL.pack
-        . L.drop 4
-        . fromMaybe []
+unpackDrawnMap = either
+        (const BL.empty) 
+        (decompressWithoutExceptions . BL.pack . drop 4 . BW.unpack)
         . Base64.decode
-        . B.unpack
 
 compressWithLength :: BL.ByteString -> BL.ByteString
 compressWithLength b = BL.drop 8 . encode . runPut $ do
@@ -201,9 +192,8 @@
     mapM_ putWord8 $ BW.unpack $ BL.toStrict $ Z.compress b
 
 packDrawnMap :: BL.ByteString -> B.ByteString
-packDrawnMap = B.pack
-    . Base64.encode
-    . BW.unpack
+packDrawnMap =
+      Base64.encode
     . BL.toStrict
     . compressWithLength
 
--- a/gameServer/HWProtoCore.hs	Thu Aug 11 23:05:14 2016 +0300
+++ b/gameServer/HWProtoCore.hs	Sun Dec 17 00:09:24 2017 +0100
@@ -40,7 +40,7 @@
 
 handleCmd ("QUIT" : xs) = return [ByeClient msg]
     where
-        msg = if not $ null xs then head xs else loc "bye"
+        msg = if not $ null xs then "User quit: " `B.append` (head xs) else loc "bye"
 
 
 handleCmd ["PONG"] = do
--- a/gameServer/HWProtoInRoomState.hs	Thu Aug 11 23:05:14 2016 +0300
+++ b/gameServer/HWProtoInRoomState.hs	Sun Dec 17 00:09:24 2017 +0100
@@ -111,7 +111,6 @@
         clChan <- thisClientChans
         othChans <- roomOthersChans
         roomChans <- roomClientsChans
-        let isRegistered = (<) 0 . B.length . webPassword $ cl
         teamColor <-
             if clientProto cl < 42 then
                 return color
@@ -123,7 +122,7 @@
                     minimum [hhnum $ head roomTeams, canAddNumber roomTeams]
                 else
                     defaultHedgehogsNumber rm
-        let newTeam = clNick `seq` TeamInfo clNick tName teamColor grave fort voicepack flag isRegistered dif hhNum (hhsList hhsInfo)
+        let newTeam = clNick `seq` TeamInfo clNick tName teamColor grave fort voicepack flag (isRegistered cl) dif hhNum (hhsList hhsInfo)
         return $
             if not . null . drop (teamsNumberLimit rm - 1) $ roomTeams then
                 [Warning $ loc "too many teams"]
--- a/gameServer/HWProtoLobbyState.hs	Thu Aug 11 23:05:14 2016 +0300
+++ b/gameServer/HWProtoLobbyState.hs	Sun Dec 17 00:09:24 2017 +0100
@@ -83,7 +83,7 @@
     let chans = map sendChan (cl : jRoomClients)
     let isBanned = host cl `elem` roomBansList jRoom
     let clTeams =
-            if (clientProto cl >= 48) && (isJust $ gameInfo jRoom) then
+            if (clientProto cl >= 48) && (isJust $ gameInfo jRoom) && isRegistered cl then
                 filter (\t -> teamowner t == nick cl) . teamsAtStart . fromJust $ gameInfo jRoom 
                 else
                 []
@@ -95,7 +95,7 @@
             [Warning $ loc "Room version incompatible to your hedgewars version"]
             else if isRestrictedJoins jRoom && not (hasSuperPower cl) then
             [Warning $ loc "Joining restricted"]
-            else if isRegisteredOnly jRoom && (B.null . webPassword $ cl) && not (isAdministrator cl) then
+            else if isRegisteredOnly jRoom && (not $ isRegistered cl) && not (isAdministrator cl) then
             [Warning $ loc "Registered users only"]
             else if isBanned then
             [Warning $ loc "You are banned in this room"]
--- a/gameServer/NetRoutines.hs	Thu Aug 11 23:05:14 2016 +0300
+++ b/gameServer/NetRoutines.hs	Sun Dec 17 00:09:24 2017 +0100
@@ -25,11 +25,8 @@
 import Control.Monad
 import Data.Unique
 import qualified Codec.Binary.Base64 as Base64
-import qualified Data.ByteString as BW
-import qualified Data.ByteString.Char8 as B
 import qualified Control.Exception as E
 import System.Entropy
-import Data.Either
 -----------------------------
 import CoreTypes
 import Utils
@@ -48,7 +45,7 @@
         sendChan' <- newChan
 
         uid <- newUnique
-        salt <- liftM (B.pack . Base64.encode . BW.unpack) $ hGetEntropy ch 18
+        salt <- liftM Base64.encode $ hGetEntropy ch 18
 
         let newClient =
                 (ClientInfo
--- a/gameServer/OfficialServer/checker.hs	Thu Aug 11 23:05:14 2016 +0300
+++ b/gameServer/OfficialServer/checker.hs	Sun Dec 17 00:09:24 2017 +0100
@@ -37,6 +37,7 @@
 import qualified Codec.Binary.Base64 as Base64
 import System.Process
 import Data.Maybe
+import Data.Either
 import qualified Data.List as L
 #if !defined(mingw32_HOST_OS)
 import System.Posix
@@ -54,7 +55,7 @@
     deriving Show
 
 serverAddress = "netserver.hedgewars.org"