update branch with latest head, most likely breaking water color in stereo mode experimental3D
authorkoda
Wed, 27 Oct 2010 14:02:20 +0200
branchexperimental3D
changeset 4004 b1c2c2f6fc5e
parent 3698 793386610068 (current diff)
parent 4002 3e173ac63849 (diff)
child 4006 45b63c2a694f
update branch with latest head, most likely breaking water color in stereo mode
QTfrontend/CMakeLists.txt
QTfrontend/game.cpp
QTfrontend/gameuiconfig.cpp
QTfrontend/gameuiconfig.h
QTfrontend/pages.cpp
QTfrontend/pages.h
hedgewars/ArgParsers.inc
hedgewars/hwengine.pas
hedgewars/uConsts.pas
hedgewars/uMisc.pas
hedgewars/uSHA.pas
hedgewars/uStore.pas
hedgewars/uWorld.pas
project_files/HedgewarsMobile/Classes/DetailViewController.h
project_files/HedgewarsMobile/Classes/DetailViewController.m
project_files/HedgewarsMobile/Resources/Frontend-iPad/background-lobby.png
project_files/HedgewarsMobile/Resources/Frontend-iPad/bluebox.png
project_files/HedgewarsMobile/Resources/Frontend-iPad/toolbarBackground.png
project_files/HedgewarsMobile/Resources/Overlay/joyPush.png
share/hedgewars/Data/Forts/BarrelhouseL.png
share/hedgewars/Data/Forts/BarrelhouseR.png
share/hedgewars/Data/Forts/IslandL.png
share/hedgewars/Data/Forts/IslandR.png
share/hedgewars/Data/Graphics/Flags/pirate.png
share/hedgewars/Data/Graphics/Hats/Pumpkin Hat.png
share/hedgewars/Data/Locale/hedgewars_bg.qm
share/hedgewars/Data/Locale/hedgewars_cs.qm
share/hedgewars/Data/Locale/hedgewars_de.qm
share/hedgewars/Data/Locale/hedgewars_en.qm
share/hedgewars/Data/Locale/hedgewars_es.qm
share/hedgewars/Data/Locale/hedgewars_fi.qm
share/hedgewars/Data/Locale/hedgewars_fr.qm
share/hedgewars/Data/Locale/hedgewars_it.qm
share/hedgewars/Data/Locale/hedgewars_ja.qm
share/hedgewars/Data/Locale/hedgewars_pl.qm
share/hedgewars/Data/Locale/hedgewars_pt_BR.qm
share/hedgewars/Data/Locale/hedgewars_pt_PT.qm
share/hedgewars/Data/Locale/hedgewars_ru.qm
share/hedgewars/Data/Locale/hedgewars_sk.qm
share/hedgewars/Data/Locale/hedgewars_sv.qm
share/hedgewars/Data/Locale/hedgewars_tr_TR.qm
share/hedgewars/Data/Locale/hedgewars_uk.qm
share/hedgewars/Data/Locale/hedgewars_zh_CN.qm
share/hedgewars/Data/Locale/hedgewars_zh_TW.qm
share/hedgewars/Data/Themes/Art/Thumbs.db
--- a/.hgignore	Thu Aug 26 23:59:18 2010 +0200
+++ b/.hgignore	Wed Oct 27 14:02:20 2010 +0200
@@ -1,24 +1,34 @@
-glob:CMakeCache.txt
-glob:CMakeFiles
-glob:moc_*.cxx
-glob:qrc_*.cxx
-glob:*.o
-glob:Makefile
-glob:bin
-glob:*.hi
-glob:*.*~
-glob:*.core
-glob:hedgewars/config.inc
-glob:cmake_install.cmake
-glob:QTfrontend/hwconsts.cpp
-glob:CPackConfig.cmake
-glob:CPackSourceConfig.cmake
-glob:tools/cmake_uninstall.cmake
-glob:install_manifest.txt
-glob:.DS_Store
-glob:*.swp
-glob:*.orig
-glob:*.diff
-glob:project_files/HedgewarsMobile/Data/
-glob:project_files/HedgewarsMobile/build/
-glob:project_files/HedgewarsMobile/Hedgewars.xcodeproj/vittorio.*
+glob:CMakeCache.txt
+glob:CMakeFiles
+glob:moc_*.cxx
+glob:qrc_*.cxx
+glob:*.o
+glob:Makefile
+glob:bin
+glob:*.hi
+glob:*.*~
+glob:*.core
+glob:hedgewars/config.inc
+glob:cmake_install.cmake
+glob:QTfrontend/hwconsts.cpp
+glob:CPackConfig.cmake
+glob:CPackSourceConfig.cmake
+glob:tools/cmake_uninstall.cmake
+glob:install_manifest.txt
+glob:.DS_Store
+glob:*.swp
+glob:*.orig
+glob:*.diff
+glob:project_files/HedgewarsMobile/Data/
+glob:project_files/HedgewarsMobile/build/
+glob:project_files/HedgewarsMobile/audio/
+glob:project_files/HedgewarsMobile/Hedgewars.xcodeproj/vittorio.*
+glob:moc_*.cxx_parameters
+relre:^release\/
+glob:*.log
+glob:*.cmd
+glob:*.diff
+glob:*.patch
+glob:*.orig
+glob:*.bak
+glob:*.rej
--- a/.hgtags	Thu Aug 26 23:59:18 2010 +0200
+++ b/.hgtags	Wed Oct 27 14:02:20 2010 +0200
@@ -11,3 +11,14 @@
 bb56f0682655b18f229be97085a409e3c76f578e hedgewars-0.8.1
 fee68e3a303998fdfcc69f74775dc84a36f587fb 0.9.9
 fee68e3a303998fdfcc69f74775dc84a36f587fb 0.9.9.1
+fd6c20cd90e33fa5e4f03e1c1f220b3eb14d169a Hedgewars-iOS-1.0
+fd6c20cd90e33fa5e4f03e1c1f220b3eb14d169a Hedgewars-iOS-1.0
+0000000000000000000000000000000000000000 Hedgewars-iOS-1.0
+0000000000000000000000000000000000000000 Hedgewars-iOS-1.0
+81db3c85784b4f35c7ff1ef9a5d64f5bdd383f08 Hedgewars-iOS-1.0
+296ec09490d92a74619aa8595df1bbcfd0dff4e5 Hedgewars-iOS-1.0.1
+296ec09490d92a74619aa8595df1bbcfd0dff4e5 Hedgewars-iOS-1.0.1
+0000000000000000000000000000000000000000 Hedgewars-iOS-1.0.1
+0000000000000000000000000000000000000000 Hedgewars-iOS-1.0.1
+3620607258cdc1213dce20cb6ad7872f6b8085e0 Hedgewars-iOS-1.0.1
+adffb668f06e265b45d1e4aedc283e6f4e5ba7e8 Hedgewars-iOS-1.1
--- a/CMakeLists.txt	Thu Aug 26 23:59:18 2010 +0200
+++ b/CMakeLists.txt	Wed Oct 27 14:02:20 2010 +0200
@@ -11,10 +11,10 @@
 set(version_suffix "-dev") #UNSET THIS VARIABLE AT RELEASE TIME
 IF(version_suffix MATCHES "-dev")
 	set(HW_DEV true)
-	IF (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.hg) 
+	IF (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.hg)
 		FIND_PROGRAM(HGCOMMAND hg)
 		IF(HGCOMMAND)
-			exec_program(${HGCOMMAND} 
+			exec_program(${HGCOMMAND}
 				     ARGS identify -in ${CMAKE_CURRENT_SOURCE_DIR}
 				     OUTPUT_VARIABLE version_suffix
 				     )
@@ -55,16 +55,16 @@
 
 if(APPLE)
 	set(CMAKE_FIND_FRAMEWORK "FIRST")
-	
+
 	#paths for creating the bundle
 	set(bundle_name Hedgewars.app)
-	set(CMAKE_INSTALL_PREFIX ${bundle_name}/Contents/MacOS/) 
+	set(CMAKE_INSTALL_PREFIX ${bundle_name}/Contents/MacOS/)
 	set(DATA_INSTALL_DIR "../Resources/")
 	set(target_dir ".")
-	
+
 	#what system are we building for
 	set(minimum_macosx $ENV{MACOSX_DEPLOYMENT_TARGET})
-	
+
 	#detect on which system are we
 	EXEC_PROGRAM("/usr/bin/sw_vers" OUTPUT_VARIABLE MACOSX_VERSION_TMP)
 	STRING(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+" MACOSX_VERSION_TMP "${MACOSX_VERSION_TMP}")
@@ -97,9 +97,9 @@
 		if(current_macosx_version MATCHES "10.6")
 			set(CMAKE_OSX_ARCHITECTURES "x86_64")
 		endif()
-	ENDIF()	
+	ENDIF()
 
-	message(STATUS "Target system: Mac OS X ${minimum_macosx} ${CMAKE_OSX_ARCHITECTURES}")	
+	message(STATUS "Target system: Mac OS X ${minimum_macosx} ${CMAKE_OSX_ARCHITECTURES}")
 
 	if(minimum_macosx MATCHES "10.4")
 		set(CMAKE_OSX_SYSROOT "/Developer/SDKs/MacOSX10.4u.sdk/")
@@ -132,10 +132,10 @@
 endif (NOT CMAKE_BUILD_TYPE)
 
 if(CMAKE_BUILD_TYPE MATCHES RELEASE OR CMAKE_BUILD_TYPE MATCHES "Release")
-	message(STATUS "Building Release")	
+	message(STATUS "Building Release")
 	set(Optz true)
 else()
-	message(STATUS "Building Debug")	
+	message(STATUS "Building Debug")
 	#set(CMAKE_VERBOSE_MAKEFILE true)
 	set(Optz false)
 endif()
@@ -205,7 +205,7 @@
 set(CPACK_PACKAGE_INSTALL_DIRECTORY "Hedgewars ${HEDGEWARS_VERSION}")
 
 if(WIN32 AND NOT UNIX)
-	set(CPACK_NSIS_DISPLAY_NAME ${CPACK_PACKAGE_DESCRIPTION_SUMMARY}) 
+	set(CPACK_NSIS_DISPLAY_NAME "Hedgewars")
 	set(CPACK_NSIS_HELP_LINK "http://www.hedgewars.org/")
 	set(CPACK_NSIS_URL_INFO_ABOUT "http://www.hedgewars.org/")
 	set(CPACK_NSIS_CONTACT "unC0Rr@gmail.com")
--- a/QTfrontend/CMakeLists.txt	Thu Aug 26 23:59:18 2010 +0200
+++ b/QTfrontend/CMakeLists.txt	Wed Oct 27 14:02:20 2010 +0200
@@ -183,7 +183,7 @@
 	)
 
 
-set(	HW_LINK_LIBS 
+set(	HW_LINK_LIBS
 	${QT_LIBRARIES}
 	${SDL_LIBRARY}
 	${SDLMIXER_LIBRARY}
@@ -195,7 +195,7 @@
 		set(HW_LINK_LIBS ${HW_LINK_LIBS} SDL)
 	endif()
 
-	set(	HW_LINK_LIBS 
+	set(	HW_LINK_LIBS
 		${HW_LINK_LIBS}
 		ole32
 		oleaut32
--- a/QTfrontend/CocoaInitializer.mm	Thu Aug 26 23:59:18 2010 +0200
+++ b/QTfrontend/CocoaInitializer.mm	Wed Oct 27 14:02:20 2010 +0200
@@ -8,7 +8,7 @@
 #include <Cocoa/Cocoa.h>
 #include <QtDebug>
 
-class CocoaInitializer::Private 
+class CocoaInitializer::Private
 {
 	public:
 		NSAutoreleasePool* autoReleasePool_;
--- a/QTfrontend/InstallController.cpp	Thu Aug 26 23:59:18 2010 +0200
+++ b/QTfrontend/InstallController.cpp	Wed Oct 27 14:02:20 2010 +0200
@@ -1,6 +1,6 @@
 /*
  *  InstallController.cpp
- *  
+ *
  *
  *  Created by Vittorio on 28/09/09.
  *  Copyright 2009 __MyCompanyName__. All rights reserved.
--- a/QTfrontend/InstallController.h	Thu Aug 26 23:59:18 2010 +0200
+++ b/QTfrontend/InstallController.h	Wed Oct 27 14:02:20 2010 +0200
@@ -1,6 +1,6 @@
 /*
  *  InstallController.h
- *  
+ *
  *
  *  Created by Vittorio on 28/09/09.
  *  Copyright 2009 __MyCompanyName__. All rights reserved.
@@ -14,8 +14,8 @@
         {
     public:
         virtual ~InstallController();
-                
+
         virtual void showInstallController() = 0;
         };
 
-#endif
\ No newline at end of file
+#endif
--- a/QTfrontend/M3InstallController.h	Thu Aug 26 23:59:18 2010 +0200
+++ b/QTfrontend/M3InstallController.h	Wed Oct 27 14:02:20 2010 +0200
@@ -1,10 +1,10 @@
 /*****************************************************************
  M3InstallController.m
- 
+
  Created by Martin Pilkington on 02/06/2007.
- 
+
  Copyright (c) 2006-2009 M Cubed Software
- 
+
  Permission is hereby granted, free of charge, to any person
  obtaining a copy of this software and associated documentation
  files (the "Software"), to deal in the Software without
@@ -13,10 +13,10 @@
  copies of the Software, and to permit persons to whom the
  Software is furnished to do so, subject to the following
  conditions:
- 
+
  The above copyright notice and this permission notice shall be
  included in all copies or substantial portions of the Software.
- 
+
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
@@ -25,7 +25,7 @@
  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  OTHER DEALINGS IN THE SOFTWARE.
- 
+
  *****************************************************************/
 
 #import <Cocoa/Cocoa.h>
--- a/QTfrontend/M3InstallController.m	Thu Aug 26 23:59:18 2010 +0200
+++ b/QTfrontend/M3InstallController.m	Wed Oct 27 14:02:20 2010 +0200
@@ -1,10 +1,10 @@
 /*****************************************************************
  M3InstallController.m
- 
+
  Created by Martin Pilkington on 02/06/2007.
- 
+
  Copyright (c) 2006-2009 M Cubed Software
- 
+
  Permission is hereby granted, free of charge, to any person
  obtaining a copy of this software and associated documentation
  files (the "Software"), to deal in the Software without
@@ -13,10 +13,10 @@
  copies of the Software, and to permit persons to whom the
  Software is furnished to do so, subject to the following
  conditions:
- 
+
  The above copyright notice and this permission notice shall be
  included in all copies or substantial portions of the Software.
- 
+
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
@@ -25,7 +25,7 @@
  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  OTHER DEALINGS IN THE SOFTWARE.
- 
+
  *****************************************************************/
 
 #import "M3InstallController.h"
@@ -40,7 +40,7 @@
 		NSString *appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"];
 		NSString *title = [NSString stringWithFormat:NSLocalizedString(@"%@ is currently running from a disk image", @"AppName is currently running from a disk image"), appName];
 		NSString *body = [NSString stringWithFormat:NSLocalizedString(@"Would you like to install %@ in your applications folder before quitting?", @"Would you like to install App Name in your applications folder before quitting?"), appName];
-		alert = [[NSAlert alertWithMessageText:title 
+		alert = [[NSAlert alertWithMessageText:title
 								 defaultButton:NSLocalizedString(@"Install", @"Install")
 							   alternateButton:NSLocalizedString(@"Don't Install", @"Don't Install")
 								   otherButton:nil
@@ -67,16 +67,16 @@
 	NSString *appsPath = [[NSString stringWithString:@"/Applications"] stringByAppendingPathComponent:[[[NSBundle mainBundle] bundlePath] lastPathComponent]];
 	NSString *userAppsPath = [[[NSString stringWithString:@"~/Applications"] stringByAppendingPathComponent:[[[NSBundle mainBundle] bundlePath] lastPathComponent]] stringByExpandingTildeInPath];
 	NSString *appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"];
-	
+
 	//Delete the app that is installed
 	if ([[NSFileManager defaultManager] fileExistsAtPath:appsPath]) {
 		[[NSFileManager defaultManager] removeFileAtPath:appsPath handler:nil];
 	}
 	//Delete the app that is installed
-	if ([[NSFileManager defaultManager] copyPath:[[NSBundle mainBundle] bundlePath] toPath:appsPath 
+	if ([[NSFileManager defaultManager] copyPath:[[NSBundle mainBundle] bundlePath] toPath:appsPath
 										  handler:nil]) {
-		NSRunAlertPanel([NSString stringWithFormat:NSLocalizedString(@"%@ installed successfully", @"App Name installed successfully"), appName], 
-						[NSString stringWithFormat:NSLocalizedString(@"%@ was installed in /Applications", @"App Name was installed in /Applications"), appName], 
+		NSRunAlertPanel([NSString stringWithFormat:NSLocalizedString(@"%@ installed successfully", @"App Name installed successfully"), appName],
+						[NSString stringWithFormat:NSLocalizedString(@"%@ was installed in /Applications", @"App Name was installed in /Applications"), appName],
 						NSLocalizedString(@"Quit", @"Quit"), nil, nil);
 	} else {
 		if ([[NSFileManager defaultManager] fileExistsAtPath:userAppsPath]) {
@@ -84,11 +84,11 @@
 		}
 		if ([[NSFileManager defaultManager] copyPath:[[NSBundle mainBundle] bundlePath] toPath:userAppsPath
 												handler:nil]) {
-		NSRunAlertPanel([NSString stringWithFormat:NSLocalizedString(@"%@ installed successfully", @"AppName installed successfully"), appName], 
-				[NSString stringWithFormat:NSLocalizedString(@"%@ was installed in %@", @"App Name was installed in %@"), appName, [[NSString stringWithString:@"~/Applications"] stringByExpandingTildeInPath]], 
+		NSRunAlertPanel([NSString stringWithFormat:NSLocalizedString(@"%@ installed successfully", @"AppName installed successfully"), appName],
+				[NSString stringWithFormat:NSLocalizedString(@"%@ was installed in %@", @"App Name was installed in %@"), appName, [[NSString stringWithString:@"~/Applications"] stringByExpandingTildeInPath]],
 						NSLocalizedString(@"Quit", @"Quit"), nil, nil);
 		} else {
-			NSRunAlertPanel([NSString stringWithFormat:NSLocalizedString(@"Could not install %@", @"Could not install App Name"), appName], 
+			NSRunAlertPanel([NSString stringWithFormat:NSLocalizedString(@"Could not install %@", @"Could not install App Name"), appName],
 							NSLocalizedString(@"An error occurred when installing", @"An error occurred when installing"), NSLocalizedString(@"Quit", @"Quit"), nil, nil);
 		}
 	}
--- a/QTfrontend/M3Panel.h	Thu Aug 26 23:59:18 2010 +0200
+++ b/QTfrontend/M3Panel.h	Wed Oct 27 14:02:20 2010 +0200
@@ -1,6 +1,6 @@
 /*
  *  M3Panel.h
- *  
+ *
  *
  *  Created by Vittorio on 28/09/09.
  *  Copyright 2009 __MyCompanyName__. All rights reserved.
@@ -17,9 +17,9 @@
     public:
         M3Panel(void);
         ~M3Panel();
-                
+
         void showInstallController();
-                
+
     private:
         class Private;
         Private* c;
--- a/QTfrontend/M3Panel.mm	Thu Aug 26 23:59:18 2010 +0200
+++ b/QTfrontend/M3Panel.mm	Wed Oct 27 14:02:20 2010 +0200
@@ -1,6 +1,6 @@
 /*
  *  M3Panel.cpp
- *  
+ *
  *
  *  Created by Vittorio on 28/09/09.
  *  Copyright 2009 __MyCompanyName__. All rights reserved.
@@ -21,10 +21,10 @@
 M3Panel::M3Panel(void)
 {
 	c = new Private;
-        
+
 	c->install = [[M3InstallController alloc] init];
 	[c->install retain];
-        
+
 }
 
 M3Panel::~M3Panel()
--- a/QTfrontend/NSWorkspace_RBAdditions.m	Thu Aug 26 23:59:18 2010 +0200
+++ b/QTfrontend/NSWorkspace_RBAdditions.m	Wed Oct 27 14:02:20 2010 +0200
@@ -107,7 +107,7 @@
 			}
 			NSString* cls = [(NSString*)IOObjectCopyClass(nextParent) autorelease];
 			if (![cls isEqualToString:@"IOPCIDevice"]) {
-			
+
 // Uncomment the following line to have the device tree dumped to the console.
 //				NSLog(@"=================================> %@:%@\n",cls,props);
 
@@ -207,7 +207,7 @@
 			}
 		}
 		//Don't need this for disk images, gets around warnings for some deprecated functions
-		
+
 		/* else {
 // For a network volume, get the volume reference number and use to get the server URL.
 			FSRef ref;
--- a/QTfrontend/SDLs.cpp	Thu Aug 26 23:59:18 2010 +0200
+++ b/QTfrontend/SDLs.cpp	Wed Oct 27 14:02:20 2010 +0200
@@ -35,7 +35,7 @@
 {
 
     SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK);
-    
+
     musicInitialized = 0;
     music = NULL;
     if(SDL_NumJoysticks())
@@ -86,7 +86,7 @@
     for(int jid = 0; jid < SDL_NumJoysticks(); jid++)
     {
         SDL_Joystick* joy = SDL_JoystickOpen(jid);
-        
+
         // Retrieve the game controller's name and strip "Controller (...)" that's added by some drivers (English only)
         QString joyname = QString(SDL_JoystickName(jid)).replace(QRegExp("^Controller \\((.*)\\)$"), "\\1");
 
@@ -102,7 +102,7 @@
         {
             // Again store the part of the string not changing for multiple uses
             QString axis = prefix + QApplication::translate("binds (keys)", "Axis") + QString(" %1 ").arg(aid + 1);
-            
+
             // Entry for "Axis Up"
             sprintf(sdlkeys[i][0], "j%da%du", jid, aid);
             sprintf(sdlkeys[i++][1], "%s", ((isxb && aid < 5) ? (prefix + QApplication::translate("binds (keys)", xbox360axes[aid * 2])) : axis + QApplication::translate("binds (keys)", "(Up)")).toStdString().c_str());
@@ -119,33 +119,33 @@
             QString hat = prefix + (isxb ? (QApplication::translate("binds (keys)", xb360dpad) + QString(" ")) : QApplication::translate("binds (keys)", "Hat") + QString(" %1 ").arg(hid + 1));
 
             // Entry for "Hat Up"
-            sprintf(sdlkeys[i][0], "j%dh%du", jid, hid);            
+            sprintf(sdlkeys[i][0], "j%dh%du", jid, hid);
             sprintf(sdlkeys[i++][1], "%s", (hat + QApplication::translate("binds (keys)", "(Up)")).toStdString().c_str());
 
             // Entry for "Hat Down"
-            sprintf(sdlkeys[i][0], "j%dh%dd", jid, hid);            
+            sprintf(sdlkeys[i][0], "j%dh%dd", jid, hid);
             sprintf(sdlkeys[i++][1], "%s", (hat + QApplication::translate("binds (keys)", "(Down)")).toStdString().c_str());
 
             // Entry for "Hat Left"
-            sprintf(sdlkeys[i][0], "j%dh%dl", jid, hid);            
+            sprintf(sdlkeys[i][0], "j%dh%dl", jid, hid);
             sprintf(sdlkeys[i++][1], "%s", (hat + QApplication::translate("binds (keys)", "(Left)")).toStdString().c_str());
 
             // Entry for "Hat Right"
-            sprintf(sdlkeys[i][0], "j%dh%dr", jid, hid);            
+            sprintf(sdlkeys[i][0], "j%dh%dr", jid, hid);
             sprintf(sdlkeys[i++][1], "%s", (hat + QApplication::translate("binds (keys)", "(Right)")).toStdString().c_str());
         }
-        
+
         // Register entries for all buttons of this joystick/gamepad
         for(int bid = 0; bid < SDL_JoystickNumButtons(joy) && i < 1022; bid++)
         {
             // Buttons
-            sprintf(sdlkeys[i][0], "j%db%d", jid, bid);         
+            sprintf(sdlkeys[i][0], "j%db%d", jid, bid);
             sprintf(sdlkeys[i++][1], "%s", (prefix + ((isxb && bid < 10) ? (QApplication::translate("binds (keys)", xb360buttons[bid]) + QString(" ")) : QApplication::translate("binds (keys)", "Button") + QString(" %1").arg(bid + 1))).toStdString().c_str());
         }
         // Close the game controller as we no longer need it
         SDL_JoystickClose(joy);
     }
-    
+
     // Terminate the list
     sdlkeys[i][0][0] = '\0';
     sdlkeys[i][1][0] = '\0';
@@ -167,7 +167,7 @@
 
     if (music == NULL) {
         music = Mix_LoadMUS((datadir->absolutePath() + "/Music/main theme.ogg").toLocal8Bit().constData());
-    
+
     }
     Mix_VolumeMusic(MIX_MAX_VOLUME - 28);
     Mix_FadeInMusic(music, -1, 1750);
--- a/QTfrontend/SDLs.h	Thu Aug 26 23:59:18 2010 +0200
+++ b/QTfrontend/SDLs.h	Wed Oct 27 14:02:20 2010 +0200
@@ -32,7 +32,7 @@
 
 private:
     Mix_Music *music;
-    int musicInitialized;   
+    int musicInitialized;
 
 public:
     SDLInteraction();
@@ -41,7 +41,7 @@
     void addGameControllerKeys() const;
     void StartMusic();
     void StopMusic();
-    void SDLMusicInit();    
+    void SDLMusicInit();
 };
 
 
--- a/QTfrontend/about.cpp	Thu Aug 26 23:59:18 2010 +0200
+++ b/QTfrontend/about.cpp	Wed Oct 27 14:02:20 2010 +0200
@@ -90,7 +90,7 @@
             "<br>"
             "Julien Koesten &lt;<a href=\"mailto:julienkoesten@aol.com\">julienkoesten@aol.com</a>&gt;"
             "<br>"
-            "Joshua O'Sullivan &lt;<a href=\"mailto:battysausage@hotmail.co.uk\">battysausage@hotmail.co.uk</a>&gt;"
+            "Joshua O'Sullivan &lt;<a href=\"mailto:coheedftw@hotmail.co.uk\">coheedftw@hotmail.co.uk</a>&gt;"
             "<br>"
             "Nils Lück &lt;<a href=\"mailto:nils.luck.design@gmail.com\">nils.luck.design@gmail.com</a>&gt;"
             "<br>"
@@ -118,7 +118,7 @@
             "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;<br>"
             "Italian: Luca Bonora &lt;<a href=\"mailto:bonora.luca@gmail.com\">bonora.luca@gmail.com</a>&gt;<br>"
             "Japanese: ADAM Etienne &lt;<a href=\"mailto:etienne.adam@gmail.com\">etienne.adam@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\">magikmagik17l@gmail.com</a>&gt;, Maciej Górny<br>"
+            "Polish: Maciej Mroziński &lt;<a href=\"mailto:mynick2@o2.pl\">mynick2@o2.pl</a>&gt;, Wojciech Latkowski &lt;<a href=\"mailto:magik17l@gmail.com\">magik17l@gmail.com</a>&gt;, Piotr Mitana, Maciej Górny<br>"
             "Portuguese: Fábio Canário &lt;<a href=\"mailto:inufabie@gmail.com\">inufabie@gmail.com</a>&gt;<br>"
             "Russian: Andrey Korotaev &lt;<a href=\"mailto:unC0Rr@gmail.com\">unC0Rr@gmail.com</a>&gt;<br>"
             "Slovak: Jose Riha<br>"
--- a/QTfrontend/achievements.cpp	Thu Aug 26 23:59:18 2010 +0200
+++ b/QTfrontend/achievements.cpp	Wed Oct 27 14:02:20 2010 +0200
@@ -33,5 +33,5 @@
     {"skipping", QT_TRANSLATE_NOOP("achievements", "Skipped"),              QT_TRANSLATE_NOOP("achievements", "Let a single hog skip over the surface of the water for at least 5 times."),                   "skipped",    "1", "hidden"},
     {"cgunman",  QT_TRANSLATE_NOOP("achievements", "Crazy Gunman"),         QT_TRANSLATE_NOOP("achievements", "Eliminate 3 hogs with a single shot of the sniper rifle."),                                    "cgunman",    "1", ""},
     */
-    {0, 0, 0, 0, 0, 0} // "terminator" line
+    { {0, 0, 0, 0, 0, 0} } // "terminator" line
 };
--- a/QTfrontend/ammoSchemeModel.cpp	Thu Aug 26 23:59:18 2010 +0200
+++ b/QTfrontend/ammoSchemeModel.cpp	Wed Oct 27 14:02:20 2010 +0200
@@ -41,15 +41,19 @@
         << QVariant(false)         // shared ammo    15
         << QVariant(false)         //disable girders 16
         << QVariant(false)         // disable land objects 17
-        << QVariant(100)           // damage modfier 18
-        << QVariant(45)            // turn time      19
-        << QVariant(100)           // init health    20
-        << QVariant(15)            // sudden death   21
-        << QVariant(5)             // case prob      22
-        << QVariant(3)             //  mines time    23
-        << QVariant(4)             //  landadds      24
-        << QVariant(0)             // mine dud pct   25
-        << QVariant(2)             // explosives     26
+        << QVariant(false)         // AI survival    18
+        << QVariant(false)         // inf. attack    19
+        << QVariant(false)         // reset weps     20
+        << QVariant(false)         // per hog ammo   21
+        << QVariant(100)           // damage modfier 22
+        << QVariant(45)            // turn time      23
+        << QVariant(100)           // init health    24
+        << QVariant(15)            // sudden death   25
+        << QVariant(5)             // case prob      26
+        << QVariant(3)             //  mines time    27
+        << QVariant(4)             //  landadds      28
+        << QVariant(0)             // mine dud pct   29
+        << QVariant(2)             // explosives     30
         ;
 
 AmmoSchemeModel::AmmoSchemeModel(QObject* parent, const QString & fileName) :
@@ -87,15 +91,19 @@
         << "sharedammo"       // 15
         << "disablegirders"   // 16
         << "disablelandobjects" // 17
-        << "damagefactor"     // 18
-        << "turntime"         // 19
-        << "health"           // 20
-        << "suddendeath"      // 21
-        << "caseprobability"  // 22
-        << "minestime"        // 23
-        << "landadds"         // 24
-        << "minedudpct"       // 25
-        << "explosives"       // 26
+        << "aisurvival"       // 18
+        << "infattack"        // 19
+        << "resetweps"        // 20
+        << "perhogammo"       // 21
+        << "damagefactor"     // 22
+        << "turntime"         // 23
+        << "health"           // 24
+        << "suddendeath"      // 25
+        << "caseprobability"  // 26
+        << "minestime"        // 27
+        << "landadds"         // 28
+        << "minedudpct"       // 29
+        << "explosives"       // 30
         ;
 
     QList<QVariant> proMode;
@@ -118,15 +126,19 @@
         << QVariant(true)          // shared ammo    15
         << QVariant(false)         //disable girders 16
         << QVariant(false)         // disable land objects 17
-        << QVariant(100)           // damage modfier 18
-        << QVariant(15)            // turn time      19
-        << QVariant(100)           // init health    20
-        << QVariant(15)            // sudden death   21
-        << QVariant(0)             // case prob      22
-        << QVariant(3)             //  mines time    23
-        << QVariant(4)             //  landadds      24
-        << QVariant(0)             // mine dud pct   25
-        << QVariant(2)             // explosives     26
+        << QVariant(false)         // AI survival    18
+        << QVariant(false)         // inf. attack    19
+        << QVariant(false)         // reset weps     20
+        << QVariant(false)         // per hog ammo   21
+        << QVariant(100)           // damage modfier 22
+        << QVariant(15)            // turn time      23
+        << QVariant(100)           // init health    24
+        << QVariant(15)            // sudden death   25
+        << QVariant(0)             // case prob      26
+        << QVariant(3)             //  mines time    27
+        << QVariant(4)             //  landadds      28
+        << QVariant(0)             // mine dud pct   29
+        << QVariant(2)             // explosives     30
         ;
 
     QList<QVariant> shoppa;
@@ -149,15 +161,19 @@
         << QVariant(true)          // shared ammo    15
         << QVariant(true)          //disable girders 16
         << QVariant(false)         // disable land objects 17
-        << QVariant(100)           // damage modfier 18
-        << QVariant(30)            // turn time      19
-        << QVariant(100)           // init health    20
-        << QVariant(50)            // sudden death   21
-        << QVariant(1)             // case prob      22
-        << QVariant(3)             //  mines time    23
-        << QVariant(4)             //  landadds      24
-        << QVariant(0)             // mine dud pct   25
-        << QVariant(0)             // explosives     26
+        << QVariant(false)         // AI survival    18
+        << QVariant(false)         // inf. attack    19
+        << QVariant(false)         // reset weps     20
+        << QVariant(false)         // per hog ammo   21
+        << QVariant(100)           // damage modfier 22
+        << QVariant(30)            // turn time      23
+        << QVariant(100)           // init health    24
+        << QVariant(50)            // sudden death   25
+        << QVariant(1)             // case prob      26
+        << QVariant(3)             //  mines time    27
+        << QVariant(4)             //  landadds      28
+        << QVariant(0)             // mine dud pct   29
+        << QVariant(0)             // explosives     30
         ;
 
     QList<QVariant> basketball;
@@ -180,15 +196,19 @@
         << QVariant(true)          // shared ammo    15
         << QVariant(true)          //disable girders 16
         << QVariant(false)         // disable land objects 17
-        << QVariant(100)           // damage modfier 18
-        << QVariant(30)            // turn time      19
-        << QVariant(100)           // init health    20
-        << QVariant(15)            // sudden death   21
-        << QVariant(0)             // case prob      22
-        << QVariant(3)             //  mines time    23
-        << QVariant(4)             //  landadds      24
-        << QVariant(0)             // mine dud pct   25
-        << QVariant(0)             // explosives     26
+        << QVariant(false)         // AI survival    18
+        << QVariant(false)         // inf. attack    19
+        << QVariant(false)         // reset weps     20
+        << QVariant(false)         // per hog ammo   21
+        << QVariant(100)           // damage modfier 22
+        << QVariant(30)            // turn time      23
+        << QVariant(100)           // init health    24
+        << QVariant(15)            // sudden death   25
+        << QVariant(0)             // case prob      26
+        << QVariant(3)             //  mines time    27
+        << QVariant(4)             //  landadds      28
+        << QVariant(0)             // mine dud pct   29
+        << QVariant(0)             // explosives     30
         ;
 
     QList<QVariant> minefield;
@@ -211,15 +231,19 @@
         << QVariant(true)          // shared ammo    15
         << QVariant(true)          //disable girders 16
         << QVariant(false)         // disable land objects 17
-        << QVariant(150)           // damage modfier 18
-        << QVariant(30)            // turn time      19
-        << QVariant(50)            // init health    20
-        << QVariant(15)            // sudden death   21
-        << QVariant(0)             // case prob      22
-        << QVariant(0)             //  mines time    23
-        << QVariant(80)            //  landadds      24
-        << QVariant(0)             // mine dud pct   25
-        << QVariant(0)             // explosives     26
+        << QVariant(false)         // AI survival    18
+        << QVariant(false)         // inf. attack    19
+        << QVariant(false)         // reset weps     20
+        << QVariant(false)         // per hog ammo   21
+        << QVariant(150)           // damage modfier 22
+        << QVariant(30)            // turn time      23
+        << QVariant(50)            // init health    24
+        << QVariant(15)            // sudden death   25
+        << QVariant(0)             // case prob      26
+        << QVariant(0)             //  mines time    27
+        << QVariant(80)            //  landadds      28
+        << QVariant(0)             // mine dud pct   29
+        << QVariant(0)             // explosives     30
         ;
 
     QList<QVariant> barrelmayhem;
@@ -242,15 +266,19 @@
         << QVariant(true)          // shared ammo    15
         << QVariant(false)         //disable girders 16
         << QVariant(false)         // disable land objects 17
-        << QVariant(100)           // damage modfier 18
-        << QVariant(30)            // turn time      19
-        << QVariant(100)           // init health    20
-        << QVariant(15)            // sudden death   21
-        << QVariant(0)             // case prob      22
-        << QVariant(0)             // mines time     23
-        << QVariant(0)             // landadds       24
-        << QVariant(0)             // mine dud pct   25
-        << QVariant(80)            // explosives     26
+        << QVariant(false)         // AI survival    18
+        << QVariant(false)         // inf. attack    19
+        << QVariant(false)         // reset weps     20
+        << QVariant(false)         // per hog ammo   21
+        << QVariant(100)           // damage modfier 22
+        << QVariant(30)            // turn time      23
+        << QVariant(100)           // init health    24
+        << QVariant(15)            // sudden death   25
+        << QVariant(0)             // case prob      26
+        << QVariant(0)             // mines time     27
+        << QVariant(0)             // landadds       28
+        << QVariant(0)             // mine dud pct   29
+        << QVariant(80)            // explosives     30
         ;
 
     QList<QVariant> tunnelhogs;
@@ -273,15 +301,19 @@
         << QVariant(true)          // shared ammo    15
         << QVariant(true)          //disable girders 16
         << QVariant(true)          // disable land objects 17
-        << QVariant(100)           // damage modfier 18
-        << QVariant(30)            // turn time      19
-        << QVariant(100)           // init health    20
-        << QVariant(15)            // sudden death   21
-        << QVariant(5)             // case prob      22
-        << QVariant(3)             // mines time     23
-        << QVariant(10)            // landadds       24
-        << QVariant(10)            // mine dud pct   25
-        << QVariant(10)            // explosives     26
+        << QVariant(false)         // AI survival    18
+        << QVariant(false)         // inf. attack    19
+        << QVariant(false)         // reset weps     20
+        << QVariant(false)         // per hog ammo   21
+        << QVariant(100)           // damage modfier 22
+        << QVariant(30)            // turn time      23
+        << QVariant(100)           // init health    24
+        << QVariant(15)            // sudden death   25
+        << QVariant(5)             // case prob      26
+        << QVariant(3)             // mines time     27
+        << QVariant(10)            // landadds       28
+        << QVariant(10)            // mine dud pct   29
+        << QVariant(10)            // explosives     30
         ;
 
     schemes.append(defaultScheme);
--- a/QTfrontend/chatwidget.cpp	Thu Aug 26 23:59:18 2010 +0200
+++ b/QTfrontend/chatwidget.cpp	Wed Oct 27 14:02:20 2010 +0200
@@ -54,14 +54,14 @@
     mainLayout.setSpacing(1);
     mainLayout.setMargin(1);
     mainLayout.setSizeConstraint(QLayout::SetMinimumSize);
-    mainLayout.setColumnStretch(0, 75);
-    mainLayout.setColumnStretch(1, 25);
+    mainLayout.setColumnStretch(0, 76);
+    mainLayout.setColumnStretch(1, 24);
 
     chatEditLine = new QLineEdit(this);
     chatEditLine->setMaxLength(300);
     connect(chatEditLine, SIGNAL(returnPressed()), this, SLOT(returnPressed()));
 
-    mainLayout.addWidget(chatEditLine, 1, 0, 1, 2);
+    mainLayout.addWidget(chatEditLine, 1, 0);
 
     chatText = new QTextBrowser(this);
     chatText->setMinimumHeight(20);
@@ -81,7 +81,7 @@
     connect(chatNicks, SIGNAL(currentRowChanged(int)),
         this, SLOT(chatNickSelected(int)));
 
-    mainLayout.addWidget(chatNicks, 0, 1);
+    mainLayout.addWidget(chatNicks, 0, 1, -1, 1);
 
     acInfo = new QAction(QAction::tr("Info"), chatNicks);
     acInfo->setIcon(QIcon(":/res/info.png"));
@@ -106,7 +106,7 @@
     chatNicks->insertAction(0, acFollow);
     chatNicks->insertAction(0, acIgnore);
     chatNicks->insertAction(0, acFriend);
-    
+
     showReady = false;
 }
 
@@ -151,17 +151,17 @@
 
     if(ignoreList.contains(nick, Qt::CaseInsensitive))
     {
-        item->setIcon(QIcon(showReady ? (item->data(Qt::UserRole).toBool() ? ":/res/chat_ignore_on" : ":/res/chat_ignore_off") : ":/res/chat_ignore.png"));
+        item->setIcon(QIcon(showReady ? (item->data(Qt::UserRole).toBool() ? ":/res/chat_ignore_on.png" : ":/res/chat_ignore_off.png") : ":/res/chat_ignore.png"));
         item->setForeground(Qt::gray);
     }
     else if(friendsList.contains(nick, Qt::CaseInsensitive))
     {
-        item->setIcon(QIcon(showReady ? (item->data(Qt::UserRole).toBool() ? ":/res/chat_friend_on" : ":/res/chat_friend_off") : ":/res/chat_friend.png"));
+        item->setIcon(QIcon(showReady ? (item->data(Qt::UserRole).toBool() ? ":/res/chat_friend_on.png" : ":/res/chat_friend_off.png") : ":/res/chat_friend.png"));
         item->setForeground(Qt::green);
     }
     else
     {
-        item->setIcon(QIcon(showReady ? (item->data(Qt::UserRole).toBool() ? ":/res/chat_default_on" : ":/res/chat_default_off") : ":/res/chat_default.png"));
+        item->setIcon(QIcon(showReady ? (item->data(Qt::UserRole).toBool() ? ":/res/chat_default_on.png" : ":/res/chat_default_off.png") : ":/res/chat_default.png"));
         item->setForeground(QBrush(QColor(0xff, 0xcc, 0x00)));
     }
 }
@@ -209,7 +209,7 @@
 
     QString color("");
     bool isFriend = friendsList.contains(parts[0], Qt::CaseInsensitive);
-    
+
     if (str.startsWith("\x03"))
         color = QString("#c0c0c0");
     else if (str.startsWith("\x02"))
--- a/QTfrontend/frameTeam.cpp	Thu Aug 26 23:59:18 2010 +0200
+++ b/QTfrontend/frameTeam.cpp	Wed Oct 27 14:02:20 2010 +0200
@@ -35,12 +35,9 @@
     mainLayout.setSpacing(1);
     mainLayout.setContentsMargins(4, 4, 4, 4);
 
-    availableColors.push_back(*color1);
-    availableColors.push_back(*color2);
-    availableColors.push_back(*color3);
-    availableColors.push_back(*color4);
-    availableColors.push_back(*color5);
-    availableColors.push_back(*color6);
+    int i = 0;
+    while(colors[i])
+        availableColors.push_back(*colors[i++]);
 
     resetColors();
 }
@@ -57,7 +54,7 @@
 
 void FrameTeams::resetColors()
 {
-  currentColor=availableColors.begin();
+  currentColor=availableColors.end() - 1; // ensure next color is the first one
 }
 
 QColor FrameTeams::getNextColor() const
--- a/QTfrontend/game.cpp	Thu Aug 26 23:59:18 2010 +0200
+++ b/QTfrontend/game.cpp	Wed Oct 27 14:02:20 2010 +0200
@@ -30,7 +30,7 @@
 
 #include <QTextStream>
 
-QString training; // TODO: Cleaner solution?
+QString training, campaign; // TODO: Cleaner solution?
 
 HWGame::HWGame(GameUIConfig * config, GameCFGWidget * gamecfg, QString ammo, TeamSelWidget* pTeamSelWidget) :
   TCPBase(true),
@@ -84,13 +84,13 @@
         QList<HWTeam> teams = m_pTeamSelWidget->getPlayingTeams();
         for(QList<HWTeam>::iterator it = teams.begin(); it != teams.end(); ++it)
         {
-            HWProto::addStringListToBuffer(buf,
-                (*it).TeamGameConfig(gamecfg->getInitHealth()));
             HWProto::addStringToBuffer(buf, QString("eammloadt %1").arg(ammostr.mid(0, cAmmoNumber)));
             HWProto::addStringToBuffer(buf, QString("eammprob %1").arg(ammostr.mid(cAmmoNumber, cAmmoNumber)));
             HWProto::addStringToBuffer(buf, QString("eammdelay %1").arg(ammostr.mid(2 * cAmmoNumber, cAmmoNumber)));
             HWProto::addStringToBuffer(buf, QString("eammreinf %1").arg(ammostr.mid(3 * cAmmoNumber, cAmmoNumber)));
             HWProto::addStringToBuffer(buf, QString("eammstore"));
+            HWProto::addStringListToBuffer(buf,
+                (*it).TeamGameConfig(gamecfg->getInitHealth()));
         }
     }
     RawSendIPC(buf);
@@ -115,7 +115,7 @@
     HWTeam * team1;
     team1 = new HWTeam;
     team1->difficulty = 0;
-    team1->teamColor = *color1;
+    team1->teamColor = *colors[0];
     team1->numHedgehogs = 4;
     namegen.TeamRandomNames(team1,TRUE);
     HWProto::addStringListToBuffer(teamscfg,
@@ -124,7 +124,7 @@
     HWTeam * team2;
     team2 = new HWTeam;
     team2->difficulty = 4;
-    team2->teamColor = *color2;
+    team2->teamColor = *colors[1];
     team2->numHedgehogs = 4;
 	do
         namegen.TeamRandomNames(team2,TRUE);
@@ -146,11 +146,21 @@
     QByteArray traincfg;
     HWProto::addStringToBuffer(traincfg, "TL");
 
-    HWProto::addStringToBuffer(traincfg, "escript " + datadir->absolutePath() + "/Missions/Training/" + training + ".lua");
+    HWProto::addStringToBuffer(traincfg, "escript " + training);
 
     RawSendIPC(traincfg);
 }
 
+void HWGame::SendCampaignConfig()
+{
+    QByteArray campaigncfg;
+    HWProto::addStringToBuffer(campaigncfg, "TL");
+
+    HWProto::addStringToBuffer(campaigncfg, "escript " + campaign);
+
+    RawSendIPC(campaigncfg);
+}
+
 void HWGame::SendNetConfig()
 {
     commonConfig();
@@ -182,6 +192,10 @@
                     SendTrainingConfig();
                     break;
                 }
+                case gtCampaign: {
+                    SendCampaignConfig();
+                    break;
+                }
             }
             break;
         }
@@ -277,18 +291,17 @@
     arguments << QString("%1").arg(ipc_port);
     arguments << (config->vid_Fullscreen() ? "1" : "0");
     arguments << (config->isSoundEnabled() ? "1" : "0");
-    arguments << "0"; //(config->isSoundHardware() ? "1" : "0");
-    arguments << "0"; //(config->isWeaponTooltip() ? "1" : "0");
-    arguments << tr("en.txt");
+    arguments << (config->isMusicEnabled() ? "1" : "0");
     arguments << QString::number(config->volume()); // sound volume
     arguments << QString::number(config->timerInterval());
     arguments << datadir->absolutePath();
     arguments << (config->isShowFPSEnabled() ? "1" : "0");
     arguments << (config->isAltDamageEnabled() ? "1" : "0");
     arguments << config->netNick().toUtf8().toBase64();
-    arguments << (config->isMusicEnabled() ? "1" : "0");
     arguments << QString::number(config->translateQuality());
     arguments << QString::number(config->stereoMode());
+    arguments << tr("en.txt");
+
     return arguments;
 }
 
@@ -345,7 +358,16 @@
 void HWGame::StartTraining(const QString & file)
 {
     gameType = gtTraining;
-    training = file;
+    training = "Missions/Training/" + file + ".lua";
+    demo.clear();
+    Start();
+    SetGameState(gsStarted);
+}
+
+void HWGame::StartCampaign(const QString & file)
+{
+    gameType = gtCampaign;
+    campaign = "Missions/Campaign/" + file + ".lua";
     demo.clear();
     Start();
     SetGameState(gsStarted);
--- a/QTfrontend/game.h	Thu Aug 26 23:59:18 2010 +0200
+++ b/QTfrontend/game.h	Wed Oct 27 14:02:20 2010 +0200
@@ -51,6 +51,7 @@
     void StartQuick();
     void StartNet();
     void StartTraining(const QString & file);
+    void StartCampaign(const QString & file);
 
  protected:
     virtual QStringList setArguments();
@@ -76,7 +77,8 @@
         gtQLocal   = 2,
         gtDemo     = 3,
         gtNet      = 4,
-        gtTraining = 5
+        gtTraining = 5,
+        gtCampaign = 6,
     };
     char msgbuf[MAXMSGCHARS];
     QString teams[5];
@@ -93,6 +95,7 @@
     void SendQuickConfig();
     void SendNetConfig();
     void SendTrainingConfig();
+    void SendCampaignConfig();
     void ParseMessage(const QByteArray & msg);
     void SetGameState(GameState state);
 };
--- a/QTfrontend/gamecfgwidget.cpp	Thu Aug 26 23:59:18 2010 +0200
+++ b/QTfrontend/gamecfgwidget.cpp	Wed Oct 27 14:02:20 2010 +0200
@@ -101,46 +101,54 @@
     quint32 result = 0;
 
     if (schemeData(1).toBool())
-        result |= 0x01;
+        result |= 0x00001000;
     if (schemeData(2).toBool())
-        result |= 0x10;
+        result |= 0x00000010;
     if (schemeData(3).toBool())
-        result |= 0x04;
+        result |= 0x00000004;
     if (schemeData(4).toBool())
-        result |= 0x08;
+        result |= 0x00000008;
     if (schemeData(5).toBool())
-        result |= 0x20;
+        result |= 0x00000020;
     if (schemeData(6).toBool())
-        result |= 0x40;
+        result |= 0x00000040;
     if (schemeData(7).toBool())
-        result |= 0x80;
+        result |= 0x00000080;
     if (schemeData(8).toBool())
-        result |= 0x100;
+        result |= 0x00000100;
     if (schemeData(9).toBool())
-        result |= 0x200;
+        result |= 0x00000200;
     if (schemeData(10).toBool())
-        result |= 0x400;
+        result |= 0x00000400;
     if (schemeData(11).toBool())
-        result |= 0x800;
+        result |= 0x00000800;
     if (schemeData(12).toBool())
-        result |= 0x2000;
+        result |= 0x00002000;
     if (schemeData(13).toBool())
-        result |= 0x4000;
+        result |= 0x00004000;
     if (schemeData(14).toBool())
-        result |= 0x8000;
+        result |= 0x00008000;
     if (schemeData(15).toBool())
-        result |= 0x10000;
+        result |= 0x00010000;
     if (schemeData(16).toBool())
-        result |= 0x20000;
+        result |= 0x00020000;
     if (schemeData(17).toBool())
-        result |= 0x80000;
+        result |= 0x00040000;
+    if (schemeData(18).toBool())
+        result |= 0x00080000;
+    if (schemeData(19).toBool())
+        result |= 0x00100000;
+    if (schemeData(20).toBool())
+        result |= 0x00200000;
+    if (schemeData(21).toBool())
+        result |= 0x00400000;
 
     return result;
 }
 
 quint32 GameCFGWidget::getInitHealth() const
 {
-    return schemeData(20).toInt();
+    return schemeData(24).toInt();
 }
 
 QStringList GameCFGWidget::getFullConfig() const
@@ -148,14 +156,14 @@
     QStringList sl;
     sl.append("eseed " + pMapContainer->getCurrentSeed());
     sl.append(QString("e$gmflags %1").arg(getGameFlags()));
-    sl.append(QString("e$damagepct %1").arg(schemeData(18).toInt()));
-    sl.append(QString("e$turntime %1").arg(schemeData(19).toInt() * 1000));
-    sl.append(QString("e$minestime %1").arg(schemeData(23).toInt() * 1000));
-    sl.append(QString("e$landadds %1").arg(schemeData(24).toInt()));
-    sl.append(QString("e$sd_turns %1").arg(schemeData(21).toInt()));
-    sl.append(QString("e$casefreq %1").arg(schemeData(22).toInt()));
-    sl.append(QString("e$minedudpct %1").arg(schemeData(25).toInt()));
-    sl.append(QString("e$explosives %1").arg(schemeData(26).toInt()));
+    sl.append(QString("e$damagepct %1").arg(schemeData(22).toInt()));
+    sl.append(QString("e$turntime %1").arg(schemeData(23).toInt() * 1000));
+    sl.append(QString("e$minestime %1").arg(schemeData(27).toInt() * 1000));
+    sl.append(QString("e$landadds %1").arg(schemeData(28).toInt()));
+    sl.append(QString("e$sd_turns %1").arg(schemeData(25).toInt()));
+    sl.append(QString("e$casefreq %1").arg(schemeData(26).toInt()));
+    sl.append(QString("e$minedudpct %1").arg(schemeData(29).toInt()));
+    sl.append(QString("e$explosives %1").arg(schemeData(30).toInt()));
     sl.append(QString("e$template_filter %1").arg(pMapContainer->getTemplateFilter()));
     sl.append(QString("e$mapgen %1").arg(pMapContainer->get_mapgen()));
     sl.append(QString("e$maze_size %1").arg(pMapContainer->get_maze_size()));
@@ -165,8 +173,7 @@
     {
         sl.append("emap " + currentMap);
         if(pMapContainer->getCurrentIsMission())
-            sl.append(QString("escript %1/Maps/%2/map.lua")
-                .arg(datadir->absolutePath())
+            sl.append(QString("escript Maps/%1/map.lua")
                 .arg(currentMap));
     }
     sl.append("etheme " + pMapContainer->getCurrentTheme());
--- a/QTfrontend/gameuiconfig.cpp	Thu Aug 26 23:59:18 2010 +0200
+++ b/QTfrontend/gameuiconfig.cpp	Wed Oct 27 14:02:20 2010 +0200
@@ -94,10 +94,10 @@
 {
     QDir teamdir;
     teamdir.cd(cfgdir->absolutePath() + "/Teams");
-    QStringList teamslist = teamdir.entryList(QStringList("*.ini"));
+    QStringList teamslist = teamdir.entryList(QStringList("*.hwt"));
     QStringList cleanedList;
     for (QStringList::Iterator it = teamslist.begin(); it != teamslist.end(); ++it ) {
-            QString tmpTeamStr=(*it).replace(QRegExp("^(.*)\\.ini$"), "\\1");
+            QString tmpTeamStr=(*it).replace(QRegExp("^(.*)\\.hwt$"), "\\1");
             cleanedList.push_back(tmpTeamStr);
     }
     return cleanedList;
@@ -180,7 +180,7 @@
 quint32 GameUIConfig::translateQuality()
 {
     quint32 rqNone = 0x00000000;  // don't reduce quality
-    quint32 rqLowRes = 0x00000001;  // use half land array
+    //quint32 rqLowRes = 0x00000001;  // use half land array
     quint32 rqBlurryLand = 0x00000002;  // downscaled terrain
     quint32 rqNoBackground = 0x00000004;  // don't draw background
     quint32 rqSimpleRope = 0x00000008;  // avoid drawing rope
--- a/QTfrontend/hedgehogerWidget.cpp	Thu Aug 26 23:59:18 2010 +0200
+++ b/QTfrontend/hedgehogerWidget.cpp	Wed Oct 27 14:02:20 2010 +0200
@@ -23,34 +23,36 @@
 CHedgehogerWidget::CHedgehogerWidget(const QImage& im, QWidget * parent) :
     ItemNum(im, parent, 1)
 {
-  if(parent) {
+  // TODO: maxHedgehogsPerGame doesn't reset properly and won't match map limits for now
+  /*if(parent) {
     pOurFrameTeams = dynamic_cast<FrameTeams*>(parent->parentWidget());
   }
   if(pOurFrameTeams->overallHedgehogs + 4 > pOurFrameTeams->maxHedgehogsPerGame) {
     numItems = pOurFrameTeams->maxHedgehogsPerGame - pOurFrameTeams->overallHedgehogs;
   } else numItems = 4;
-  pOurFrameTeams->overallHedgehogs += numItems;
+  pOurFrameTeams->overallHedgehogs += numItems;*/
 }
 
 void CHedgehogerWidget::incItems()
 {
-  if (pOurFrameTeams->overallHedgehogs < pOurFrameTeams->maxHedgehogsPerGame) {
+  //if (pOurFrameTeams->overallHedgehogs < pOurFrameTeams->maxHedgehogsPerGame) {
     numItems++;
-    pOurFrameTeams->overallHedgehogs++;
+    //pOurFrameTeams->overallHedgehogs++;
     emit hedgehogsNumChanged();
-  }
+  //}
 }
 
 void CHedgehogerWidget::decItems()
 {
   numItems--;
-  pOurFrameTeams->overallHedgehogs--;
+  //pOurFrameTeams->overallHedgehogs--;
   emit hedgehogsNumChanged();
 }
 
 CHedgehogerWidget::~CHedgehogerWidget()
 {
-  pOurFrameTeams->overallHedgehogs-=numItems;
+  // TODO: not called?
+  //pOurFrameTeams->overallHedgehogs-=numItems;
 }
 
 void CHedgehogerWidget::setNonInteractive()
@@ -60,9 +62,10 @@
 
 void CHedgehogerWidget::setHHNum(unsigned int num)
 {
-  unsigned int diff = num - numItems;
+  /*unsigned int diff = num - numItems;
   numItems += diff;
-  pOurFrameTeams->overallHedgehogs += diff;
+  pOurFrameTeams->overallHedgehogs += diff;*/
+  numItems = num;
   repaint();
 }
 
--- a/QTfrontend/hedgewars.qrc	Thu Aug 26 23:59:18 2010 +0200
+++ b/QTfrontend/hedgewars.qrc	Wed Oct 27 14:02:20 2010 +0200
@@ -66,6 +66,10 @@
     <file>res/btnSharedAmmo.png</file>
     <file>res/btnDisableGirders.png</file>
     <file>res/btnDisableLandObjects.png</file>
+    <file>res/btnAISurvival.png</file>
+    <file>res/btnInfAttack.png</file>
+    <file>res/btnResetWeps.png</file>
+    <file>res/btnPerHogAmmo.png</file>
     <file>res/iconBox.png</file>
     <file>res/iconHealth.png</file>
     <file>res/iconSuddenDeath.png</file>
@@ -95,5 +99,23 @@
     <file>res/follow.png</file>
     <file>res/info.png</file>
     <file>res/kick.png</file>
+    <file>res/StatsMedal1.png</file>
+    <file>res/StatsMedal2.png</file>
+    <file>res/StatsMedal3.png</file>
+    <file>res/StatsMedal4.png</file>
+    <file>res/StatsR.png</file>
+    <file>res/StatsH.png</file>
+    <file>res/StatsD.png</file>
+    <file>res/StatsBestKiller.png</file>
+    <file>res/StatsBestShot.png</file>
+    <file>res/StatsHedgehogsKilled.png</file>
+    <file>res/StatsMostSelfDamage.png</file>
+    <file>res/StatsSelfKilled.png</file>
+    <file>res/StatsSkipped.png</file>
+    <file>res/mapRandom.png</file>
+    <file>res/mapMaze.png</file>
+    <file>res/mapMissing.png</file>
+    <file>res/mapCustom.png</file>
+    <file>res/mapMission.png</file>
 </qresource>
 </RCC>
--- a/QTfrontend/hwconsts.cpp.in	Thu Aug 26 23:59:18 2010 +0200
+++ b/QTfrontend/hwconsts.cpp.in	Wed Oct 27 14:02:20 2010 +0200
@@ -30,50 +30,65 @@
 QStringList * Themes;
 QStringList * mapList;
 
+bool custom_config = false;
+bool custom_data = false;
+
+int cMaxTeams = 6;
+
 QString * cDefaultAmmoStore = new QString(
-        "9391929422199121032235111001201000000211110111"
-        "0405040541600655546554464776576666666155510111"
-        "0000000000000205500000040007004000000000200000"
-        "1311110312111111123114111111111111111211111111"
-		);
+        "9391929422199121032235111001201000000211110101011"
+        "0405040541600655546554464776576666666155510101117"
+        "0000000000000205500000040007004000000000200000000"
+        "1311110312111111123114111111111111111211111101111"
+        );
 int cAmmoNumber = cDefaultAmmoStore->size() / 4;
 
 QList< QPair<QString, QString> > cDefaultAmmos =
-	QList< QPair<QString, QString> >()
-	<< qMakePair(QString("Default"), *cDefaultAmmoStore)
-	<< qMakePair(QString("Crazy"),     QString(
-        "9999999999999999992999999999999999299999999999" // TODO: Remove Piano's unlimited uses!
-        "1111110111111111111111111111111111111111111111"
-        "0000000000000000000000000000000000000000000000"
-        "1311110312111111123114111111111111111211110101"))
-	<< qMakePair(QString("Pro mode"),  QString(
-        "9090009000000000000009000000000000000000000900"
-        "0000000000000000000000000000000000000000000000"
-        "0000000000000205500000040007004000000000200000"
-        "1111111111111111111111111111111111111111100111"))
-	<< qMakePair(QString("Shoppa"),    QString(
-        "0000009900000000000000000000000000000000000000"
-        "4444410044244402210112121222422000000002000400"
-        "0000000000000000000000000000000000000000000000"
-        "1111111111111111111111111111111111111111101111"))
-	<< qMakePair(QString("Basketball"),QString(
-		"0000009000000900000000000000000000000000000000"
-		"0000000000000000000000000000000000000000000000"
-		"0000000000000005500000040007004000000000200000"
-		"1111111111111111111111111111111111111111111111"))
-	<< qMakePair(QString("Minefield"), QString(
-		"0000009900090000000300000000000000000000000000"
-		"0000000000000000000000000000000000000000000000"
-		"0000000000000205500000040007004000000000200000"
-		"1111111111111111111111111111111111111111111111"))
-	;
+        QList< QPair<QString, QString> >()
+        << qMakePair(QString("Default"), *cDefaultAmmoStore)
+        << qMakePair(QString("Crazy"),     QString(
+        // TODO: Remove Piano's unlimited uses!
+        "9999999999999999992999999999999999299999999909999"
+        "1111110111111111111111111111111111111111111101111"
+        "0000000000000000000000000000000000000000000000000"
+        "1311110312111111123114111111111111111211110101111"
+        ))
+        << qMakePair(QString("Pro mode"),  QString(
+        "9090009000000000000009000000000000000000000000000"
+        "0000000000000000000000000000000000000000000000000"
+        "0000000000000205500000040007004000000000200000000"
+        "1111111111111111111111111111111111111111100101111"
+        ))
+        << qMakePair(QString("Shoppa"),    QString(
+        "0000009900000000000000000000000000000000000000000"
+        "4444410044244402210112121222422000000002000400010"
+        "0000000000000000000000000000000000000000000000000"
+        "1111111111111111111111111111111111111111101101111"
+        ))
+        << qMakePair(QString("Basketball"),QString(
+        "0000009000000900000000000000000000000000000000000"
+        "0000000000000000000000000000000000000000000000000"
+        "0000000000000005500000040007004000000000200000000"
+        "1111111111111111111111111111111111111111111101111"
+        ))
+        << qMakePair(QString("Minefield"), QString(
+        "0000009900090000000300000000000000000000000000000"
+        "0000000000000000000000000000000000000000000000000"
+        "0000000000000205500000040007004000000000200000000"
+        "1111111111111111111111111111111111111111111101111"
+        ));
 
-QColor * color1 = new QColor(221,   0,   0);
-QColor * color2 = new QColor( 67, 118, 233);
-QColor * color3 = new QColor( 62, 147,  33);
-QColor * color4 = new QColor(162,  61, 187);
-QColor * color5 = new QColor(255, 147,  41);
-QColor * color6 = new QColor(115, 115, 115);
+QColor *colors[] = {
+                    new QColor(221,   0,   0), // classic red
+                    new QColor( 67, 118, 233), // classic blue
+                    new QColor( 62, 147,  33), // classic green
+                    new QColor(162,  61, 187), // classic purple
+                    new QColor(255, 147,  41), // classic orange
+                    new QColor(115, 115, 115), // classic gray
+                    new QColor(187, 162,  61), // gold
+                    new QColor( 61, 162, 187), // cyan
+                    // add new colors here
+                    0};
 
 QString * netHost = new QString();
 quint16 netPort = 46631;
--- a/QTfrontend/hwconsts.h	Thu Aug 26 23:59:18 2010 +0200
+++ b/QTfrontend/hwconsts.h	Wed Oct 27 14:02:20 2010 +0200
@@ -31,6 +31,11 @@
 extern QDir * cfgdir;
 extern QDir * datadir;
 
+extern bool custom_config;
+extern bool custom_data;
+
+extern int cMaxTeams;
+
 extern QStringList * Themes;
 extern QStringList * mapList;
 
@@ -38,12 +43,7 @@
 extern int cAmmoNumber;
 extern QList< QPair<QString, QString> > cDefaultAmmos;
 
-extern QColor * color1;
-extern QColor * color2;
-extern QColor * color3;
-extern QColor * color4;
-extern QColor * color5;
-extern QColor * color6;
+extern QColor *colors[];
 
 extern QString * netHost;
 extern quint16 netPort;
--- a/QTfrontend/hwform.cpp	Thu Aug 26 23:59:18 2010 +0200
+++ b/QTfrontend/hwform.cpp	Wed Oct 27 14:02:20 2010 +0200
@@ -83,9 +83,9 @@
 
     ui.setupUi(this);
     setMinimumSize(760, 580);
-
+    setFocusPolicy(Qt::StrongFocus);
     CustomizePalettes();
-    
+
     ui.pageOptions->CBResolution->addItems(sdli.getResolutions());
 
     config = new GameUIConfig(this, cfgdir->absolutePath() + "/hedgewars.ini");
@@ -93,17 +93,18 @@
     namegen = new HWNamegen();
 
 #ifdef __APPLE__
-        panel = new M3Panel;
+    panel = new M3Panel;
 #ifdef SPARKLE_ENABLED
-        AutoUpdater* updater;
-        CocoaInitializer initializer;
-        updater = new SparkleAutoUpdater(SPARKLE_APPCAST_URL);
-    if(updater && config->isAutoUpdateEnabled())
-            updater->checkForUpdates();
-#endif        
+    AutoUpdater* updater;
+    CocoaInitializer initializer;
+    updater = new SparkleAutoUpdater(SPARKLE_APPCAST_URL);
+    if (updater && config->isAutoUpdateEnabled())
+        updater->checkForUpdates();
+#endif
 #endif
 
     UpdateTeamsLists();
+    UpdateCampaignPage(0);
     UpdateWeapons();
 
     connect(config, SIGNAL(frontendFullscreen(bool)), this, SLOT(onFrontendFullscreen(bool)));
@@ -140,6 +141,9 @@
     connect(ui.pageOptions->BtnDeleteTeam, SIGNAL(clicked()), this, SLOT(DeleteTeam()));
     connect(ui.pageOptions->BtnSaveOptions, SIGNAL(clicked()), config, SLOT(SaveOptions()));
     connect(ui.pageOptions->BtnSaveOptions, SIGNAL(clicked()), this, SLOT(GoBack()));
+#ifdef _WIN32
+    connect(ui.pageOptions->BtnAssociateFiles, SIGNAL(clicked()), this, SLOT(AssociateFiles()));
+#endif
 
     connect(ui.pageOptions->WeaponEdit, SIGNAL(clicked()), this, SLOT(GoToSelectWeapon()));
     connect(ui.pageOptions->WeaponsButt, SIGNAL(clicked()), this, SLOT(GoToSelectNewWeapon()));
@@ -171,6 +175,7 @@
 
     connect(ui.pageSinglePlayer->BtnSimpleGamePage, SIGNAL(clicked()), this, SLOT(SimpleGame()));
     connect(ui.pageSinglePlayer->BtnTrainPage, SIGNAL(clicked()), this, SLOT(GoToTraining()));
+    connect(ui.pageSinglePlayer->BtnCampaignPage, SIGNAL(clicked()), this, SLOT(GoToCampaign()));
     connect(ui.pageSinglePlayer->BtnMultiplayer, SIGNAL(clicked()), this, SLOT(GoToMultiplayer()));
     connect(ui.pageSinglePlayer->BtnLoad, SIGNAL(clicked()), this, SLOT(GoToSaves()));
     connect(ui.pageSinglePlayer->BtnDemos, SIGNAL(clicked()), this, SLOT(GoToDemos()));
@@ -179,6 +184,10 @@
     connect(ui.pageTraining->BtnStartTrain, SIGNAL(clicked()), this, SLOT(StartTraining()));
     connect(ui.pageTraining->BtnBack, SIGNAL(clicked()), this, SLOT(GoBack()));
 
+    connect(ui.pageCampaign->BtnStartCampaign, SIGNAL(clicked()), this, SLOT(StartCampaign()));
+    connect(ui.pageCampaign->BtnBack, SIGNAL(clicked()), this, SLOT(GoBack()));
+    connect(ui.pageCampaign->CBTeam, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateCampaignPage(int)));
+
     connect(ui.pageSelectWeapon->BtnBack, SIGNAL(clicked()), this, SLOT(GoBack()));
 
     connect(ui.pageSelectWeapon->BtnDelete, SIGNAL(clicked()),
@@ -265,6 +274,12 @@
   }
 }
 
+void HWForm::keyReleaseEvent(QKeyEvent *event)
+{
+  if (event->key() == Qt::Key_Escape /*|| event->key() == Qt::Key_Backspace*/ )
+    this->GoBack();
+}
+
 void HWForm::CustomizePalettes()
 {
     QList<QScrollBar *> allSBars = findChildren<QScrollBar *>();
@@ -310,13 +325,15 @@
     }
 
     if(teamslist.empty()) {
-        HWTeam defaultTeam("DefaultTeam");
+        HWTeam defaultTeam(tr("DefaultTeam"));
         defaultTeam.SaveToFile();
-        teamslist.push_back("DefaultTeam");
+        teamslist.push_back(tr("DefaultTeam"));
     }
 
     ui.pageOptions->CBTeamName->clear();
     ui.pageOptions->CBTeamName->addItems(teamslist);
+    ui.pageCampaign->CBTeam->clear();
+    ui.pageCampaign->CBTeam->addItems(teamslist);
 }
 
 void HWForm::GoToMain()
@@ -334,6 +351,11 @@
     GoToPage(ID_PAGE_TRAINING);
 }
 
+void HWForm::GoToCampaign()
+{
+    GoToPage(ID_PAGE_CAMPAIGN);
+}
+
 void HWForm::GoToSetup()
 {
     GoToPage(ID_PAGE_SETUP);
@@ -513,11 +535,11 @@
 {
     if (eggTimer.elapsed() < 3000){
 #ifdef __APPLE__
-                panel->showInstallController();
+        panel->showInstallController();
 #endif
         close();
     }
-        else
+    else
     {
         QPushButton * btn = findChild<QPushButton *>("imageButt");
         if (btn)
@@ -543,7 +565,8 @@
     for(QList<HWTeam>::iterator it = teams.begin(); it != teams.end(); ++it) {
         tmnames += it->TeamName;
     }
-    UpdateTeamsLists(&tmnames); // FIXME: still need more work if teamname is updated while configuring
+    //UpdateTeamsLists(&tmnames); // FIXME: still need more work if teamname is updated while configuring
+    UpdateTeamsLists();
 
     GoToPage(ID_PAGE_SETUP);
 }
@@ -961,7 +984,14 @@
 {
     CreateGame(0, 0, 0);
 
-    game->StartTraining(ui.pageTraining->CBSelect->currentText());
+    game->StartTraining(ui.pageTraining->CBSelect->itemData(ui.pageTraining->CBSelect->currentIndex()).toString());
+}
+
+void HWForm::StartCampaign()
+{
+    CreateGame(0, 0, 0);
+
+    game->StartCampaign(ui.pageCampaign->CBSelect->itemData(ui.pageCampaign->CBSelect->currentIndex()).toString());
 }
 
 void HWForm::CreateNetGame()
@@ -1074,3 +1104,33 @@
         wBackground->move(0, 0);
     }
 }
+
+void HWForm::UpdateCampaignPage(int index)
+{
+    HWTeam team(ui.pageCampaign->CBTeam->currentText());
+    ui.pageCampaign->CBSelect->clear();
+
+    QDir tmpdir;
+    tmpdir.cd(datadir->absolutePath());
+    tmpdir.cd("Missions/Campaign");
+    tmpdir.setFilter(QDir::Files);
+    QStringList entries = tmpdir.entryList(QStringList("*#*.lua"));
+    //entries.sort();
+    for(int i = 0; (i < entries.count()) && (i <= team.CampaignProgress); i++)
+        ui.pageCampaign->CBSelect->addItem(QString(entries[i]).replace(QRegExp("^(\\d+)#(.+)\\.lua"), QComboBox::tr("Mission") + " \\1: \\2"), QString(entries[i]).replace(QRegExp("^(.*)\\.lua"), "\\1"));
+}
+
+void HWForm::AssociateFiles()
+{
+    QSettings registry_hkcr("HKEY_CLASSES_ROOT", QSettings::NativeFormat);
+    registry_hkcr.setValue(".hwd/Default", "Hedgewars.Demo");
+    registry_hkcr.setValue(".hws/Default", "Hedgewars.Save");
+    registry_hkcr.setValue("Hedgewars.Demo/Default", tr("Hedgewars Demo File", "File Types"));
+    registry_hkcr.setValue("Hedgewars.Save/Default", tr("Hedgewars Save File", "File Types"));
+    registry_hkcr.setValue("Hedgewars.Demo/DefaultIcon/Default", "\"" + bindir->absolutePath().replace("/", "\\") + "\\hwdfile.ico\",0");
+    registry_hkcr.setValue("Hedgewars.Save/DefaultIcon/Default", "\"" + bindir->absolutePath().replace("/", "\\") + "\\hwsfile.ico\",0");
+    registry_hkcr.setValue("Hedgewars.Demo/Shell/Open/Command/Default", "\"" + bindir->absolutePath().replace("/", "\\") + "\\hwengine.exe\" \"" + datadir->absolutePath().replace("/", "\\") + "\" \"%1\"");
+    registry_hkcr.setValue("Hedgewars.Save/Shell/Open/Command/Default", "\"" + bindir->absolutePath().replace("/", "\\") + "\\hwengine.exe\" \"" + datadir->absolutePath().replace("/", "\\") + "\" \"%1\"");
+    QMessageBox::information(0, "", QMessageBox::tr("All file associations have been set."));
+}
+
--- a/QTfrontend/hwform.h	Thu Aug 26 23:59:18 2010 +0200
+++ b/QTfrontend/hwform.h	Wed Oct 27 14:02:20 2010 +0200
@@ -69,6 +69,7 @@
     void GoToNetType();
     void GoToInfo();
     void GoToTraining();
+    void GoToCampaign();
     void GoToSelectWeapon();
     void GoToSelectWeaponSet(const QString & name);
     void GoToSelectNewWeapon();
@@ -77,6 +78,7 @@
     void GoToAdmin();
     void GoToPage(quint8 id);
     void GoBack();
+    void AssociateFiles();
     void btnExitPressed();
     void btnExitClicked();
     void IntermediateSetup();
@@ -90,6 +92,7 @@
     void SimpleGame();
     void PlayDemo();
     void StartTraining();
+    void StartCampaign();
     void NetConnect();
     void NetConnectServer(const QString & host, quint16 port);
     void NetConnectOfficialServer();
@@ -107,6 +110,7 @@
     void UpdateWeapons();
     void onFrontendFullscreen(bool value);
     void Music(bool checked);
+    void UpdateCampaignPage(int index);
 
     void NetGameChangeStatus(bool isMaster);
     void NetGameMaster();
@@ -123,7 +127,8 @@
     void closeEvent(QCloseEvent *event);
     void CustomizePalettes();
     void resizeEvent(QResizeEvent * event);
-
+    void keyReleaseEvent(QKeyEvent *event);
+    
     enum PageIDs {
         ID_PAGE_SETUP_TEAM      =  0,
         ID_PAGE_SETUP           =  1,
@@ -143,7 +148,8 @@
         ID_PAGE_CONNECTING      = 15,
         ID_PAGE_SCHEME          = 16,
         ID_PAGE_ADMIN           = 17,
-        ID_PAGE_NETTYPE         = 18
+        ID_PAGE_NETTYPE         = 18,
+        ID_PAGE_CAMPAIGN        = 19
         };
     HWGame * game;
     HWNetServer* pnetserver;
@@ -155,11 +161,11 @@
     QStack<quint8> PagesStack;
     QTime eggTimer;
     BGWidget * wBackground;
-        
+
 #ifdef __APPLE__
         InstallController * panel;
 #endif
-        
+
     void OnPageShown(quint8 id, quint8 lastid=0);
 };
 
--- a/QTfrontend/main.cpp	Thu Aug 26 23:59:18 2010 +0200
+++ b/QTfrontend/main.cpp	Wed Oct 27 14:02:20 2010 +0200
@@ -47,7 +47,7 @@
     return true;
 }
 
-int main(int argc, char *argv[]) {        
+int main(int argc, char *argv[]) {
     QApplication app(argc, argv);
 
     QStringList arguments = app.arguments();
@@ -73,11 +73,13 @@
             qWarning() << "WARNING: Cannot open DATA_PATH=" << f.absoluteFilePath();
         }
         *cDataDir = f.absoluteFilePath();
+        custom_data = true;
     }
 
     if(parsedArgs.contains("config-dir")) {
         QFileInfo f(parsedArgs["config-dir"]);
         *cConfigDir = f.absoluteFilePath();
+        custom_config = true;
     }
 
     app.setStyle(new QPlastiqueStyle);
@@ -180,6 +182,7 @@
             "}"
             "QTableView {"
                 "alternate-background-color: #2f213a;"
+                "gridline-color: transparent;"
             "}"
 
             "QTabBar::tab {"
@@ -294,6 +297,18 @@
             "SquareLabel, ItemNum {"
                 "background-color: #000000;"
             "}"
+            "QSlider::groove::horizontal {"
+                "height: 2px;"
+                "margin: 2px 0px;"
+                "background-color: #ffcc00;"
+            "}"
+            "QSlider::handle::horizontal {"
+                "border: 0px;"
+                "margin: -2px 0px;"
+                "border-radius: 3px;"
+                "background-color: #ffcc00;"
+                "width: 8px;"
+            "}"
             )
         );
 
@@ -307,62 +322,53 @@
     if(cConfigDir->length() == 0)
     {
 #ifdef __APPLE__
-        if (checkForDir(cfgdir->absolutePath() + "/Library/Application Support/Hedgewars"))
-        {
-            checkForDir(cfgdir->absolutePath() + "/Library/Application Support/Hedgewars/Demos");
-            checkForDir(cfgdir->absolutePath() + "/Library/Application Support/Hedgewars/Saves");
-            checkForDir(cfgdir->absolutePath() + "/Library/Application Support/Hedgewars/Screenshots");
-            checkForDir(cfgdir->absolutePath() + "/Library/Application Support/Hedgewars/Teams");
-        }
+        checkForDir(cfgdir->absolutePath() + "/Library/Application Support/Hedgewars");
         cfgdir->cd("Library/Application Support/Hedgewars");
 #elif defined _WIN32
         char path[1024];
         if(!SHGetFolderPathA(0, CSIDL_PERSONAL, NULL, 0, path))
         {
             cfgdir->cd(path);
-            if (checkForDir(cfgdir->absolutePath() + "/Hedgewars"))
-            {
-                checkForDir(cfgdir->absolutePath() + "/Hedgewars/Demos");
-                checkForDir(cfgdir->absolutePath() + "/Hedgewars/Saves");
-                checkForDir(cfgdir->absolutePath() + "/Hedgewars/Screenshots");
-                checkForDir(cfgdir->absolutePath() + "/Hedgewars/Teams");
-            }
+            checkForDir(cfgdir->absolutePath() + "/Hedgewars");
             cfgdir->cd("Hedgewars");
         }
-        else
+        else // couldn't retrieve documents folder? almost impossible, but in case fall back to classic path
         {
-            if (checkForDir(cfgdir->absolutePath() + "/.hedgewars"))
-            {
-                checkForDir(cfgdir->absolutePath() + "/.hedgewars/Demos");
-                checkForDir(cfgdir->absolutePath() + "/.hedgewars/Saves");
-                checkForDir(cfgdir->absolutePath() + "/.hedgewars/Screenshots");
-                checkForDir(cfgdir->absolutePath() + "/.hedgewars/Teams");
-            }
+            checkForDir(cfgdir->absolutePath() + "/.hedgewars");
             cfgdir->cd(".hedgewars");
         }
 #else
-        if (checkForDir(cfgdir->absolutePath() + "/.hedgewars"))
-        {
-            checkForDir(cfgdir->absolutePath() + "/.hedgewars/Demos");
-            checkForDir(cfgdir->absolutePath() + "/.hedgewars/Saves");
-            checkForDir(cfgdir->absolutePath() + "/.hedgewars/Screenshots");
-            checkForDir(cfgdir->absolutePath() + "/.hedgewars/Teams");
-        }
+        checkForDir(cfgdir->absolutePath() + "/.hedgewars");
         cfgdir->cd(".hedgewars");
 #endif
     }
-    else
+
+    if (checkForDir(cfgdir->absolutePath()))
     {
-        if (checkForDir(cfgdir->absolutePath()))
-        {
-            checkForDir(cfgdir->absolutePath() + "/Demos");
-            checkForDir(cfgdir->absolutePath() + "/Saves");
-            checkForDir(cfgdir->absolutePath() + "/Screenshots");
-            checkForDir(cfgdir->absolutePath() + "/Teams");
-        }
+        // alternative loading/lookup paths
+        // TODO: Uncomment paths as they're implemented
+        checkForDir(cfgdir->absolutePath() + "/Data");
+        //checkForDir(cfgdir->absolutePath() + "/Data/Forts");
+        //checkForDir(cfgdir->absolutePath() + "/Data/Graphics");
+        //checkForDir(cfgdir->absolutePath() + "/Data/Graphics/Flags");
+        //checkForDir(cfgdir->absolutePath() + "/Data/Graphics/Graves");
+        //checkForDir(cfgdir->absolutePath() + "/Data/Graphics/Hats");
+        //checkForDir(cfgdir->absolutePath() + "/Data/Maps");
+        //checkForDir(cfgdir->absolutePath() + "/Data/Missions");
+        //checkForDir(cfgdir->absolutePath() + "/Data/Missions/Campaign");
+        //checkForDir(cfgdir->absolutePath() + "/Data/Missions/Training");
+        //checkForDir(cfgdir->absolutePath() + "/Data/Sounds");
+        //checkForDir(cfgdir->absolutePath() + "/Data/Sounds/voices");
+        //checkForDir(cfgdir->absolutePath() + "/Data/Themes");
+
+        // config/save paths
+        checkForDir(cfgdir->absolutePath() + "/Demos");
+        checkForDir(cfgdir->absolutePath() + "/Saves");
+        checkForDir(cfgdir->absolutePath() + "/Screenshots");
+        checkForDir(cfgdir->absolutePath() + "/Teams");
+        checkForDir(cfgdir->absolutePath() + "/Logs");
     }
 
-
     datadir->cd(bindir->absolutePath());
     datadir->cd(*cDataDir);
     if(!datadir->cd("hedgewars/Data")) {
@@ -406,12 +412,11 @@
 
     // Win32 registry setup (used for xfire detection etc. - don't set it if we're running in "portable" mode with a custom config dir)
 #ifdef _WIN32
-    if(cConfigDir->length() == 0)
+    if(!custom_config)
     {
-        QSettings registry(QSettings::NativeFormat, QSettings::UserScope, "Hedgewars Project", "Hedgewars");
-        QFileInfo f(argv[0]);
-        registry.setValue("file", f.absoluteFilePath());
-        registry.setValue("path", f.absolutePath());
+        QSettings registry_hklm("HKEY_LOCAL_MACHINE", QSettings::NativeFormat);
+        registry_hklm.setValue("Software/Hedgewars/Frontend", bindir->absolutePath().replace("/", "\\") + "\\hedgewars.exe");
+        registry_hklm.setValue("Software/Hedgewars/Path", bindir->absolutePath().replace("/", "\\"));
     }
 #endif
 
--- a/QTfrontend/mapContainer.cpp	Thu Aug 26 23:59:18 2010 +0200
+++ b/QTfrontend/mapContainer.cpp	Wed Oct 27 14:02:20 2010 +0200
@@ -56,16 +56,18 @@
     imageButt->setFlat(true);
     imageButt->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);//QSizePolicy::Minimum, QSizePolicy::Minimum);
     mainLayout.addWidget(imageButt, 0, 0, 1, 2);
-    connect(imageButt, SIGNAL(clicked()), this, SLOT(setRandomSeed()));
-    connect(imageButt, SIGNAL(clicked()), this, SLOT(setRandomTheme()));
+    //connect(imageButt, SIGNAL(clicked()), this, SLOT(setRandomSeed()));
+    //connect(imageButt, SIGNAL(clicked()), this, SLOT(setRandomTheme()));
+    connect(imageButt, SIGNAL(clicked()), this, SLOT(setRandomMap()));
 
     chooseMap = new QComboBox(this);
     chooseMap->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
-    chooseMap->addItem(QComboBox::tr("generated map..."));
-    chooseMap->addItem(QComboBox::tr("generated maze..."));
+    chooseMap->addItem(QIcon(":/res/mapRandom.png"), QComboBox::tr("generated map..."));
+    chooseMap->addItem(QIcon(":/res/mapMaze.png"), QComboBox::tr("generated maze..."));
     chooseMap->insertSeparator(chooseMap->count()); // separator between generators and missions
 
     int missionindex = chooseMap->count();
+    numMissions = 0;
     for (int i = 0; i < mapList->size(); ++i) {
         QString map = (*mapList)[i];
         QFile mapCfgFile(
@@ -92,9 +94,12 @@
                 mapInfo.push_back(18);
             mapInfo.push_back(mapLuaFile.exists());
             if(mapLuaFile.exists())
-                chooseMap->insertItem(missionindex++, QComboBox::tr("Mission") + ": " + map, mapInfo);
+            {
+                chooseMap->insertItem(missionindex++, QIcon(":/res/mapMission.png"), QComboBox::tr("Mission") + ": " + map, mapInfo);
+                numMissions++;
+            }
             else
-                chooseMap->addItem(map, mapInfo);
+                chooseMap->addItem(QIcon(":/res/mapCustom.png"), map, mapInfo);
             mapCfgFile.close();
         }
     }
@@ -149,11 +154,12 @@
     gbTLayout->setSpacing(0);
     lwThemes = new QListWidget(this);
     lwThemes->setMinimumHeight(30);
-    lwThemes->setFixedWidth(120);
+    lwThemes->setFixedWidth(140);
     for (int i = 0; i < Themes->size(); ++i) {
         QListWidgetItem * lwi = new QListWidgetItem();
         lwi->setText(Themes->at(i));
-        lwi->setTextAlignment(Qt::AlignHCenter);
+        lwi->setIcon(QIcon(QString("%1/Themes/%2/icon.png").arg(datadir->absolutePath()).arg(Themes->at(i))));
+        //lwi->setTextAlignment(Qt::AlignHCenter);
         lwThemes->addItem(lwi);
     }
     connect(lwThemes, SIGNAL(currentRowChanged(int)), this, SLOT(themeSelected(int)));
@@ -167,7 +173,7 @@
             "border-color: transparent;"
             "background-color: #0d0544;"
             "color: #ffcc00;"
-            "font: bold 14px;"
+            "font: bold 13px;"
             "}"
         )
     );
@@ -389,6 +395,36 @@
     if(items.size())
         lwThemes->setCurrentItem(items.at(0));
 }
+#include <QMessageBox>
+void HWMapContainer::setRandomMap()
+{
+    switch(chooseMap->currentIndex())
+    {
+    case MAPGEN_REGULAR:
+    case MAPGEN_MAZE:
+        setRandomSeed();
+        setRandomTheme();
+        break;
+    default:
+        if(chooseMap->currentIndex() < numMissions + 3)
+            setRandomMission();
+        else
+            setRandomStatic();
+        break;
+    }
+}
+
+void HWMapContainer::setRandomStatic()
+{
+    chooseMap->setCurrentIndex(4 + numMissions + rand() % (chooseMap->count() - 4 - numMissions));
+    m_seed = QUuid::createUuid().toString();
+}
+
+void HWMapContainer::setRandomMission()
+{
+    chooseMap->setCurrentIndex(3 + rand() % numMissions);
+    m_seed = QUuid::createUuid().toString();
+}
 
 void HWMapContainer::setRandomSeed()
 {
--- a/QTfrontend/mapContainer.h	Thu Aug 26 23:59:18 2010 +0200
+++ b/QTfrontend/mapContainer.h	Wed Oct 27 14:02:20 2010 +0200
@@ -72,6 +72,9 @@
   void mapChanged(int index);
   void setRandomSeed();
   void setRandomTheme();
+  void setRandomMap();
+  void setRandomStatic();
+  void setRandomMission();
   void themeSelected(int currentRow);
   void addInfoToPreview(QPixmap image);
   void templateFilterChanged(int filter);
@@ -95,6 +98,7 @@
   QLabel *maze_size_label;
   QComboBox *maze_size_selection;
   MapGenerator mapgen;
+  int numMissions;
   int maze_size;
 
   void loadMap(int index);
--- a/QTfrontend/newnetclient.cpp	Thu Aug 26 23:59:18 2010 +0200
+++ b/QTfrontend/newnetclient.cpp	Wed Oct 27 14:02:20 2010 +0200
@@ -305,7 +305,7 @@
             if(tmp[0] == "MOTD_NEW") emit serverMessageNew(tmp[1]);
             else if(tmp[0] == "MOTD_OLD") emit serverMessageOld(tmp[1]);
             else if(tmp[0] == "LATEST_PROTO") emit latestProtocolVar(tmp[1].toInt());
-                
+
             tmp.removeFirst();
             tmp.removeFirst();
         }
@@ -472,13 +472,13 @@
         int passLength = config->value("net/passwordlength", 0).toInt();
         QString hash = config->value("net/passwordhash", "").toString();
         QString password = QInputDialog::getText(0, tr("Password"), tr("Your nickname %1 is\nregistered on Hedgewars.org\nPlease provide your password below\nor pick another nickname in game config:").arg(mynick), QLineEdit::Password, passLength==0?NULL:QString(passLength,'\0'), &ok);
-        
+
         if (!ok) {
             Disconnect();
             emit Disconnected();
             return;
         }
-        
+
         if (!passLength || password!=QString(passLength, '\0')) {
             hash = QCryptographicHash::hash(password.toLatin1(), QCryptographicHash::Md5).toHex();
             config->setValue("net/passwordhash", hash);
@@ -750,5 +750,5 @@
 
 void HWNewNet::askServerVars()
 {
-    RawSendNet(QString("GET_SERVER_VAR"));    
+    RawSendNet(QString("GET_SERVER_VAR"));
 }
--- a/QTfrontend/newnetclient.h	Thu Aug 26 23:59:18 2010 +0200
+++ b/QTfrontend/newnetclient.h	Wed Oct 27 14:02:20 2010 +0200
@@ -48,7 +48,7 @@
   QString getNick();
   QString getRoom();
   QString getHost();
-  
+
  private:
   GameUIConfig* config;
   GameCFGWidget* m_pGameCFGWidget;
--- a/QTfrontend/pages.cpp	Thu Aug 26 23:59:18 2010 +0200
+++ b/QTfrontend/pages.cpp	Wed Oct 27 14:02:20 2010 +0200
@@ -92,39 +92,69 @@
     mainNote = new QLabel(this);
     mainNote->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
     mainNote->setWordWrap(true);
+    mainNote->setOpenExternalLinks(true);
 
-    QStringList Tips;
-    Tips << tr("Simply pick the same color as a friend to play together as a team. Each of you will still control his or her own hedgehogs but they'll win or lose together.", "Tips");
-    Tips << tr("Some weapons might do only low damage but they can be a lot more devastating in the right situation. Try to use the Desert Eagle to knock multiple hedgehogs into the water.", "Tips");
-    Tips << tr("If you're unsure what to do and don't want to waste ammo, skip one round. But don't let too much time pass as there will be Sudden Death!", "Tips");
-    Tips << tr("Want to save ropse? Release the rope in mid air and then shoot again. As long as you don't touch the ground you'll reuse your rope without wasting ammo!", "Tips");
-    Tips << tr("If you'd like to keep others from using your preferred nickname on the official server, register an account at http://www.hedgewars.org/.", "Tips");
-    Tips << tr("You're bored of default gameplay? Try one of the missions - they'll offer different gameplay depending on the one you picked.", "Tips");
-    Tips << tr("By default the game will always record the last game played as a demo. Select 'Local Game' and pick the 'Demos' button on the lower right corner to play or manage them.", "Tips");
-    Tips << tr("Hedgewars is Open Source and Freeware we create in our spare time. If you've got problems, ask on our forums but please don't expect 24/7 support!", "Tips");
-    Tips << tr("Hedgewars is Open Source and Freeware we create in our spare time. If you like it, help us with a small donation or contribute your own work!", "Tips");
-    Tips << tr("Hedgewars is Open Source and Freeware we create in our spare time. Share it with your family and friends as you like!", "Tips");
-    Tips << tr("From time to time there will be official tournaments. Upcoming events will be announced at http://www.hedgewars.org/ some days in advance.", "Tips");
-    Tips << tr("Hedgewars is available in many languages. If the translation in your language seems to be missing or outdated, feel free to contact us!", "Tips");
-    Tips << tr("Hedgewars can be run on lots of different operating systems including Microsoft Windows, Mac OS X and Linux.", "Tips");
-    Tips << tr("Always remember you're able to set up your own games in local and network/online play. You're not restricted to the 'Simple Game' option.", "Tips");
-    Tips << tr("Connect one or more gamepads before launching the game to be able to assign their controls to your teams.", "Tips");
-    Tips << tr("Create an account on http://www.hedgewars.org/ to keep others from using your most favourite nickname while playing on the official server.", "Tips");
-    Tips << tr("While playing you should give yourself a short break at least once an hour.", "Tips");
-    Tips << tr("If your graphics card isn't able to provide hardware accelerated OpenGL, try to enable the low quality mode to improve performance.", "Tips");
-    Tips << tr("We're open to suggestions and constructive feedback. If you don't like something or got a great idea, let us know!", "Tips");
-    Tips << tr("Especially while playing online be polite and always remember there might be some minors playing with or against you as well!", "Tips");
-    Tips << tr("Special game modes such as 'Vampirism' or 'Karma' allow you to develop completely new tactics. Try them in a custom game!", "Tips");
-    Tips << tr("The Windows version of Hedgewars supports Xfire. Make sure to add Hedgwars to its game list so your friends can see you playing.", "Tips");
-    Tips << tr("You should never install Hedgewars on computers you don't own (school, university, work, etc.). Please ask the responsible person instead!", "Tips");
-    Tips << tr("Hedgewars can be perfect for short games during breaks. Just ensure you don't add too many hedgehogs or use an huge map. Reducing time and health might help as well.", "Tips");
-    Tips << tr("No hedgehogs were harmed in making this game.", "Tips");
-    
-
-    if(isDevBuild)
+    if(!isDevBuild)
+    {
+        QStringList Tips;
+        Tips << tr("Simply pick the same color as a friend to play together as a team. Each of you will still control his or her own hedgehogs but they'll win or lose together.", "Tips");
+        Tips << tr("Some weapons might do only low damage but they can be a lot more devastating in the right situation. Try to use the Desert Eagle to knock multiple hedgehogs into the water.", "Tips");
+        Tips << tr("If you're unsure what to do and don't want to waste ammo, skip one round. But don't let too much time pass as there will be Sudden Death!", "Tips");
+        Tips << tr("Want to save ropse? Release the rope in mid air and then shoot again. As long as you don't touch the ground you'll reuse your rope without wasting ammo!", "Tips");
+        Tips << tr("If you'd like to keep others from using your preferred nickname on the official server, register an account at http://www.hedgewars.org/.", "Tips");
+        Tips << tr("You're bored of default gameplay? Try one of the missions - they'll offer different gameplay depending on the one you picked.", "Tips");
+        Tips << tr("By default the game will always record the last game played as a demo. Select 'Local Game' and pick the 'Demos' button on the lower right corner to play or manage them.", "Tips");
+        Tips << tr("Hedgewars is Open Source and Freeware we create in our spare time. If you've got problems, ask on our forums but please don't expect 24/7 support!", "Tips");
+        Tips << tr("Hedgewars is Open Source and Freeware we create in our spare time. If you like it, help us with a small donation or contribute your own work!", "Tips");
+        Tips << tr("Hedgewars is Open Source and Freeware we create in our spare time. Share it with your family and friends as you like!", "Tips");
+        Tips << tr("Hedgewars is Open Source and Freeware we create in our spare time. If someone sold you the game, you should try get a refund!", "Tips");
+        Tips << tr("From time to time there will be official tournaments. Upcoming events will be announced at http://www.hedgewars.org/ some days in advance.", "Tips");
+        Tips << tr("Hedgewars is available in many languages. If the translation in your language seems to be missing or outdated, feel free to contact us!", "Tips");
+        Tips << tr("Hedgewars can be run on lots of different operating systems including Microsoft Windows, Mac OS X and Linux.", "Tips");
+        Tips << tr("Always remember you're able to set up your own games in local and network/online play. You're not restricted to the 'Simple Game' option.", "Tips");
+        Tips << tr("Connect one or more gamepads before starting the game to be able to assign their controls to your teams.", "Tips");
+        Tips << tr("Create an account on %1 to keep others from using your most favourite nickname while playing on the official server.", "Tips").arg("<a href=\"http://www.hedgewars.org/\">http://www.hedgewars.org/</a>");
+        Tips << tr("While playing you should give yourself a short break at least once an hour.", "Tips");
+        Tips << tr("If your graphics card isn't able to provide hardware accelerated OpenGL, try to enable the low quality mode to improve performance.", "Tips");
+        Tips << tr("If your graphics card isn't able to provide hardware accelerated OpenGL, try to update the associated drivers.", "Tips");
+        Tips << tr("We're open to suggestions and constructive feedback. If you don't like something or got a great idea, let us know!", "Tips");
+        Tips << tr("Especially while playing online be polite and always remember there might be some minors playing with or against you as well!", "Tips");
+        Tips << tr("Special game modes such as 'Vampirism' or 'Karma' allow you to develop completely new tactics. Try them in a custom game!", "Tips");
+        Tips << tr("The Windows version of Hedgewars supports Xfire. Make sure to add Hedgwars to its game list so your friends can see you playing.", "Tips");
+        Tips << tr("You should never install Hedgewars on computers you don't own (school, university, work, etc.). Please ask the responsible person instead!", "Tips");
+        Tips << tr("Hedgewars can be perfect for short games during breaks. Just ensure you don't add too many hedgehogs or use an huge map. Reducing time and health might help as well.", "Tips");
+        Tips << tr("No hedgehogs were harmed in making this game.", "Tips");
+        Tips << tr("There are three different jumps available. Tap [high jump] twice to do a very high/backwards jump.", "Tips");
+        Tips << tr("Afraid of falling off a cliff? Hold down [precise] to turn [left] or [right] without actually moving.", "Tips");
+        Tips << tr("Some weapons require special strategies or just lots of training, so don't give up on a particular tool if you miss an enemy once.", "Tips");
+        Tips << tr("Most weapons won't work once they touch the water. The Homing Bee as well as the Cake are exceptions to this.", "Tips");
+        Tips << tr("The Old Limbuger only causes a small explosion. However the wind affected smelly cloud can poison lots of hogs at once.", "Tips");
+        Tips << tr("The Piano Strike is the most damaging air strike. You'll lose the hedgehog performing it, so there's a huge downside as well.", "Tips");
+        Tips << tr("The Homing Bee can be tricky to use. It's turn radius depends on it's velocity, so try to not use full power.", "Tips");
+        Tips << tr("Sticky Mines are a perfect tool to create small chain reactions knocking enemy hedgehogs into dire situations ... or water.", "Tips");
+        Tips << tr("The Hammer is most effective when used on bridges or girders. Hit hogs will just break through the ground.", "Tips");
+        Tips << tr("If you're stuck behind an enemy hedgehog, use the Hammer to free yourself without getting damaged by an explosion.", "Tips");
+        Tips << tr("The Cake's maximum walking distance depends on the ground it has to pass. Use [attack] to detonate it early.", "Tips");
+        Tips << tr("The Flame Thrower is a weapon but it can be used for tunnel digging as well.", "Tips");
+        Tips << tr("Use the Incinerating Grenade to temporary keep hedgehogs from passing terrain such as tunnels or platforms.", "Tips");
+        Tips << tr("Want to know who's behind the game? Click on the Hedgewars logo in the main menu to see the credits.", "Tips");
+        Tips << tr("Like Hedgewars? Become a fan on %1 or join our group at %2. You could follow us on %3 as well!", "Tips").arg("<a href=\"http://www.facebook.com/Hedgewars\">Facebook</a>").arg("<a href=\"http://steamcommunity.com/groups/hedgewars\">Steam Community</a>").arg("<a href=\"http://twitter.com/hedgewars\">Twitter</a>");
+        Tips << tr("Feel free to draw your own graves, hats, flags or even maps and themes! But note that you'll have to share them somewhere to use them online.", "Tips");
+        Tips << tr("Really want to wear a specific hat? Donate to us and receive an exclusive hat of your choice!", "Tips");
+        // The following tip will require links to app store entries first.
+        //Tips << tr("Want to play Hedgewars any time? Grab the Mobile version for %1 and %2.", "Tips").arg("").arg("");
+        Tips << tr("Keep your video card drivers up to date to avoid issues playing the game.", "Tips");
+        //Tips << tr("", "Tips");
+#ifdef _WIN32
+        Tips << tr("You can find your Hedgewars configuration files under \"My Documents\\Hedgewars\". Create backups or take the files with you, but don't edit them by hand.", "Tips");
+        Tips << tr("You're able to associate Hedgewars related files (savegames and demo recordings) with the game to launch them right from your favorite file or internet browser.", "Tips");
+#else
+        Tips << tr("You can find your Hedgewars configuration files under \"Hedgewars\" in your home directory. Create backups or take the files with you, but don't edit them by hand.", "Tips");
+#endif
+        mainNote->setText(QLabel::tr("Tip: ") + Tips[QTime(0, 0, 0).secsTo(QTime::currentTime()) % Tips.length()]);
+    }
+    else
         mainNote->setText(QLabel::tr("This development build is 'work in progress' and may not be compatible with other versions of the game. Some features might be broken or incomplete. Use at your own risk!"));
-    else
-        mainNote->setText(QLabel::tr("Tip: ") + Tips[QTime(0, 0, 0).secsTo(QTime::currentTime()) % Tips.length()]);
 
     pageLayout->addWidget(mainNote, 4, 1, 1, 2);
 
@@ -301,12 +331,33 @@
     tmpdir.cd(datadir->absolutePath());
     tmpdir.cd("Graphics/Flags");
     list = tmpdir.entryList(QStringList("*.png"));
+    
+    // add the default flag
+    CBFlag->addItem(QIcon(QPixmap(datadir->absolutePath() + "/Graphics/Flags/hedgewars.png").copy(0, 0, 22, 15)), "Hedgewars", "hedgewars");
+
+    CBFlag->insertSeparator(CBFlag->count());
+    // add all country flags
     for (QStringList::Iterator it = list.begin(); it != list.end(); ++it )
     {
         QPixmap pix(datadir->absolutePath() + "/Graphics/Flags/" + *it);
         QIcon icon(pix.copy(0, 0, 22, 15));
-        if(it->compare("cpu.png")) // skip cpu flag
-            CBFlag->addItem(icon, (*it).replace(QRegExp("^(.*)\\.png"), "\\1"));
+        if(it->compare("cpu.png") && it->compare("hedgewars.png") && (it->indexOf("cm_") == -1)) // skip cpu and hedgewars flags as well as all community flags
+        {
+            QString flag = (*it).replace(QRegExp("^(.*)\\.png"), "\\1");
+            CBFlag->addItem(icon, QString(flag).replace("_", " "), flag);
+        }
+    }
+    CBFlag->insertSeparator(CBFlag->count());
+    // add all community flags
+    for (QStringList::Iterator it = list.begin(); it != list.end(); ++it )
+    {
+        QPixmap pix(datadir->absolutePath() + "/Graphics/Flags/" + *it);
+        QIcon icon(pix.copy(0, 0, 22, 15));
+        if(it->indexOf("cm_") > -1) // skip non community flags this time
+        {
+            QString flag = (*it).replace(QRegExp("^(.*)\\.png"), "\\1");
+            CBFlag->addItem(icon, QString(flag).replace("cm_", QComboBox::tr("Community") + ": "), flag);
+        }
     }
 
     vbox1->addStretch();
@@ -560,7 +611,12 @@
             CBAutoUpdate->setText(QCheckBox::tr("Check for updates at startup"));
             MiscLayout->addWidget(CBAutoUpdate, 4, 0, 1, 2);
 #endif
-
+#ifdef _WIN32
+            BtnAssociateFiles = new QPushButton(groupMisc);
+            BtnAssociateFiles->setText(QPushButton::tr("Associate file extensions"));
+            BtnAssociateFiles->setEnabled(!custom_data && !custom_config);
+            MiscLayout->addWidget(BtnAssociateFiles, 4, 0, 1, 2);
+#endif
             gbTBLayout->addWidget(groupMisc, 2, 0);
         }
 
@@ -613,6 +669,7 @@
 
             QLabel * quality = new QLabel(AGGroupBox);
             quality->setText(QLabel::tr("Quality"));
+            quality->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
             GBAqualayout->addWidget(quality);
             
             SLQuality = new QSlider(Qt::Horizontal, AGGroupBox);
@@ -622,7 +679,6 @@
             SLQuality->setFixedWidth(150);
             GBAqualayout->addWidget(SLQuality);
             GBAlayout->addLayout(GBAqualayout);
-
             QLabel * stereo = new QLabel(AGGroupBox);
             stereo->setText(QLabel::tr("Stereo rendering"));
             GBAstereolayout->addWidget(stereo);
@@ -962,7 +1018,10 @@
     topLine->addStretch();
 
 
-    BtnTrainPage = addButton(":/res/Trainings.png", middleLine, 0, true);
+    BtnCampaignPage = addButton(":/res/SimpleGame.png", middleLine, 0, true);
+    BtnCampaignPage->setToolTip(tr("Campaign Mode (...). IN DEVELOPMENT"));
+
+    BtnTrainPage = addButton(":/res/Trainings.png", middleLine, 1, true);
     BtnTrainPage->setToolTip(tr("Training Mode (Practice your skills in a range of training missions). IN DEVELOPMENT"));
 
     BtnBack = addButton(":/res/Exit.png", bottomLine, 0, true);
@@ -993,6 +1052,8 @@
     tmpdir.cd("Missions/Training");
     tmpdir.setFilter(QDir::Files);
     CBSelect->addItems(tmpdir.entryList(QStringList("*.lua")).replaceInStrings(QRegExp("^(.*)\\.lua"), "\\1"));
+    for(int i = 0; i < CBSelect->count(); i++)
+        CBSelect->setItemData(i, CBSelect->itemText(i));
 
     pageLayout->addWidget(CBSelect, 1, 1);
     
@@ -1004,6 +1065,29 @@
     BtnBack = addButton(":/res/Exit.png", pageLayout, 3, 0, true);
 }
 
+PageCampaign::PageCampaign(QWidget* parent) : AbstractPage(parent)
+{
+    QGridLayout * pageLayout = new QGridLayout(this);
+    pageLayout->setColumnStretch(0, 1);
+    pageLayout->setColumnStretch(1, 2);
+    pageLayout->setColumnStretch(2, 1);
+    pageLayout->setRowStretch(0, 1);
+    pageLayout->setRowStretch(3, 1);
+
+    CBSelect = new QComboBox(this);
+    CBTeam = new QComboBox(this);
+
+    pageLayout->addWidget(CBTeam, 1, 1);
+    pageLayout->addWidget(CBSelect, 2, 1);
+    
+    BtnStartCampaign = new QPushButton(this);
+    BtnStartCampaign->setFont(*font14);
+    BtnStartCampaign->setText(QPushButton::tr("Go!"));
+    pageLayout->addWidget(BtnStartCampaign, 2, 2);
+
+    BtnBack = addButton(":/res/Exit.png", pageLayout, 4, 0, true);
+}
+
 PageSelectWeapon::PageSelectWeapon(QWidget* parent) :
   AbstractPage(parent)
 {
@@ -1050,24 +1134,85 @@
     roomsList->verticalHeader()->setVisible(false);
     roomsList->horizontalHeader()->setResizeMode(QHeaderView::Interactive);
     roomsList->setAlternatingRowColors(true);
+    roomsList->setShowGrid(false);
+    roomsList->setSelectionMode(QAbstractItemView::SingleSelection);
     pageLayout->addWidget(roomsList, 1, 0, 3, 1);
     pageLayout->setRowStretch(2, 100);
+    
+    QHBoxLayout * filterLayout = new QHBoxLayout();
+    
+    QLabel * stateLabel = new QLabel(this);
+    stateLabel->setText(tr("State:"));
+    CBState = new QComboBox(this);
+    CBState->addItem(QComboBox::tr("Any"));
+    CBState->addItem(QComboBox::tr("In lobby"));
+    CBState->addItem(QComboBox::tr("In progress"));
+    filterLayout->addWidget(stateLabel);
+    filterLayout->addWidget(CBState);
+    filterLayout->addSpacing(30);
+    
+    QLabel * ruleLabel = new QLabel(this);
+    ruleLabel->setText(tr("Rules:"));
+    CBRules = new QComboBox(this);
+    CBRules->addItem(QComboBox::tr("Any"));
+    CBRules->addItem(QComboBox::tr("Default"));
+    CBRules->addItem(QComboBox::tr("Pro mode"));
+    CBRules->addItem(QComboBox::tr("Shoppa"));
+    CBRules->addItem(QComboBox::tr("Basketball"));
+    CBRules->addItem(QComboBox::tr("Minefield"));
+    CBRules->addItem(QComboBox::tr("Barrel mayhem"));
+    CBRules->addItem(QComboBox::tr("Tunnel hogs"));
+    filterLayout->addWidget(ruleLabel);
+    filterLayout->addWidget(CBRules);
+    filterLayout->addSpacing(30);
+    
+    QLabel * weaponLabel = new QLabel(this);
+    weaponLabel->setText(tr("Weapons:"));
+    CBWeapons = new QComboBox(this);
+    CBWeapons->addItem(QComboBox::tr("Any"));
+    CBWeapons->addItem(QComboBox::tr("Basketball"));
+    CBWeapons->addItem(QComboBox::tr("Crazy"));
+    CBWeapons->addItem(QComboBox::tr("Default"));
+    CBWeapons->addItem(QComboBox::tr("Minefield"));
+    CBWeapons->addItem(QComboBox::tr("Pro mode"));
+    CBWeapons->addItem(QComboBox::tr("Shoppa"));
+    filterLayout->addWidget(weaponLabel);
+    filterLayout->addWidget(CBWeapons);
+    filterLayout->addSpacing(30);
+
+    QLabel * searchLabel = new QLabel(this);
+    searchLabel->setText(tr("Search:"));
+    searchText = new QLineEdit(this);
+    searchText->setMaxLength(60);
+    filterLayout->addWidget(searchLabel);
+    filterLayout->addWidget(searchText);
+
+    pageLayout->addLayout(filterLayout, 4, 0);
 
     chatWidget = new HWChatWidget(this, gameSettings, sdli, false);
-    pageLayout->addWidget(chatWidget, 4, 0, 1, 2);
-    pageLayout->setRowStretch(4, 350);
+    pageLayout->addWidget(chatWidget, 5, 0, 1, 2);
+    pageLayout->setRowStretch(5, 350);
 
     BtnCreate = addButton(tr("Create"), pageLayout, 0, 1);
     BtnJoin = addButton(tr("Join"), pageLayout, 1, 1);
     BtnRefresh = addButton(tr("Refresh"), pageLayout, 3, 1);
+    BtnClear = addButton(tr("Clear"), pageLayout, 4, 1);
 
-    BtnBack = addButton(":/res/Exit.png", pageLayout, 5, 0, true);
-    BtnAdmin = addButton(tr("Admin features"), pageLayout, 5, 1);
+    BtnBack = addButton(":/res/Exit.png", pageLayout, 6, 0, true);
+    BtnAdmin = addButton(tr("Admin features"), pageLayout, 6, 1);
 
     connect(BtnCreate, SIGNAL(clicked()), this, SLOT(onCreateClick()));
     connect(BtnJoin, SIGNAL(clicked()), this, SLOT(onJoinClick()));
     connect(BtnRefresh, SIGNAL(clicked()), this, SLOT(onRefreshClick()));
+    connect(BtnClear, SIGNAL(clicked()), this, SLOT(onClearClick()));
     connect(roomsList, SIGNAL(doubleClicked (const QModelIndex &)), this, SLOT(onJoinClick()));
+    connect(CBState, SIGNAL(currentIndexChanged (int)), this, SLOT(onRefreshClick()));
+    connect(CBRules, SIGNAL(currentIndexChanged (int)), this, SLOT(onRefreshClick()));
+    connect(CBWeapons, SIGNAL(currentIndexChanged (int)), this, SLOT(onRefreshClick()));
+    connect(searchText, SIGNAL(textChanged (const QString &)), this, SLOT(onRefreshClick()));
+    connect(this, SIGNAL(askJoinConfirmation (const QString &)), this, SLOT(onJoinConfirmation(const QString &)), Qt::QueuedConnection);
+    
+    gameInLobby = false;
 }
 
 void PageRoomsList::setAdmin(bool flag)
@@ -1077,6 +1222,18 @@
 
 void PageRoomsList::setRoomsList(const QStringList & list)
 {
+    QBrush red(QColor(255, 0, 0));
+    QBrush orange(QColor(127, 127, 0));
+    QBrush yellow(QColor(255, 255, 0));
+    QBrush green(QColor(0, 255, 0));
+
+    listFromServer = list;
+    
+    QString selection = "";
+    
+    if(QTableWidgetItem *item = roomsList->item(roomsList->currentRow(), 0))
+        selection = item->text();
+    
     roomsList->clear();
     roomsList->setColumnCount(7);
     roomsList->setHorizontalHeaderLabels(
@@ -1102,12 +1259,46 @@
     // set resize modes
 //  roomsList->horizontalHeader()->setResizeMode(QHeaderView::Interactive);
 
+    bool gameCanBeJoined = true;
+
     if (list.size() % 8)
         return;
 
     roomsList->setRowCount(list.size() / 8);
     for(int i = 0, r = 0; i < list.size(); i += 8, r++)
     {
+        // if we are joining a game
+        // TODO: Should NOT be done here
+        if (gameInLobby) {
+            if (gameInLobbyName == list[i + 1]) {
+                gameCanBeJoined = list[i].compare("True");
+            }
+        }
+        
+        // check filter settings
+        #define NO_FILTER_MATCH roomsList->setRowCount(roomsList->rowCount() - 1); --r; continue
+        
+        if (list[i].compare("True") && CBState->currentIndex() == 2) { NO_FILTER_MATCH; }
+        if (list[i].compare("False") && CBState->currentIndex() == 1) { NO_FILTER_MATCH; }
+        if (CBRules->currentIndex() != 0 && list[i + 6].compare(CBRules->currentText())) { NO_FILTER_MATCH; }
+        if (CBWeapons->currentIndex() != 0 && list[i + 7].compare(CBWeapons->currentText())) { NO_FILTER_MATCH; }
+        bool found = list[i + 1].contains(searchText->text(), Qt::CaseInsensitive);
+        if (!found) {
+            for (int a = 4; a <= 7; ++a) {
+                QString compString = list[i + a];
+                if (a == 5 && compString == "+rnd+") {
+                    compString = "Random Map";
+                } else if (a == 5 && compString == "+maze+") {
+                    compString = "Random Maze";
+                }
+                if (compString.contains(searchText->text(), Qt::CaseInsensitive)) {
+                    found = true;
+                    break;
+                }
+            }
+        }
+        if (!searchText->text().isEmpty() && !found) { NO_FILTER_MATCH; }
+        
         QTableWidgetItem * item;
         item = new QTableWidgetItem(list[i + 1]); // room name
         item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
@@ -1136,6 +1327,9 @@
         item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
         item->setTextAlignment(Qt::AlignCenter);
         item->setToolTip(tr("There are %1 teams participating in this room.", "", list[i + 3].toInt()).arg(list[i + 3]));
+        //Should we highlight "full" games? Might get misinterpreted
+        //if(list[i + 3].toInt() >= cMaxTeams)
+        //    item->setForeground(red);
         roomsList->setItem(r, 2, item);
 
         item = new QTableWidgetItem(list[i + 4].left(15)); // name of host
@@ -1144,9 +1338,15 @@
         roomsList->setItem(r, 3, item);
 
         if(list[i + 5] == "+rnd+")
+        {
             item = new QTableWidgetItem(tr("Random Map")); // selected map (is randomized)
+            item->setIcon(QIcon(":/res/mapRandom.png"));
+        }
         else if (list[i+5] == "+maze+")
+        {
             item = new QTableWidgetItem(tr("Random Maze"));
+            item->setIcon(QIcon(":/res/mapMaze.png"));
+        }
         else
         {
             item = new QTableWidgetItem(list[i + 5]); // selected map
@@ -1154,7 +1354,15 @@
             // check to see if we've got this map
             // not perfect but a start
             if(!mapList->contains(list[i + 5]))
-                item->setForeground(QBrush(QColor(255, 0, 0)));
+            {
+                item->setForeground(red);
+                item->setIcon(QIcon(":/res/mapMissing.png"));
+            }
+            else
+            {
+                // todo: mission icon?
+                item->setIcon(QIcon(":/res/mapCustom.png"));
+            }
         }
         
         item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
@@ -1171,14 +1379,27 @@
         item->setToolTip(tr("The Weapon Scheme defines available weapons and their ammunition count."));
         roomsList->setItem(r, 6, item);
 
+        if(!list[i + 1].compare(selection) && !selection.isEmpty())
+            roomsList->selectionModel()->setCurrentIndex(roomsList->model()->index(r, 0), QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows);
     }
-   roomsList->horizontalHeader()->setResizeMode(0, QHeaderView::Stretch);
-   roomsList->horizontalHeader()->setResizeMode(1, QHeaderView::ResizeToContents);
-   roomsList->horizontalHeader()->setResizeMode(2, QHeaderView::ResizeToContents);
-   roomsList->horizontalHeader()->setResizeMode(3, QHeaderView::ResizeToContents);
-   roomsList->horizontalHeader()->setResizeMode(4, QHeaderView::ResizeToContents);
-   roomsList->horizontalHeader()->setResizeMode(5, QHeaderView::ResizeToContents);
-   roomsList->horizontalHeader()->setResizeMode(6, QHeaderView::ResizeToContents);
+
+    roomsList->horizontalHeader()->setResizeMode(0, QHeaderView::Stretch);
+    roomsList->horizontalHeader()->setResizeMode(1, QHeaderView::ResizeToContents);
+    roomsList->horizontalHeader()->setResizeMode(2, QHeaderView::ResizeToContents);
+    roomsList->horizontalHeader()->setResizeMode(3, QHeaderView::ResizeToContents);
+    roomsList->horizontalHeader()->setResizeMode(4, QHeaderView::ResizeToContents);
+    roomsList->horizontalHeader()->setResizeMode(5, QHeaderView::ResizeToContents);
+    roomsList->horizontalHeader()->setResizeMode(6, QHeaderView::ResizeToContents);
+
+    // TODO: Should NOT be done here
+    if (gameInLobby) {
+        gameInLobby = false;
+        if (gameCanBeJoined) {
+            emit askForJoinRoom(gameInLobbyName);
+        } else {
+            emit askJoinConfirmation(gameInLobbyName);
+        }
+    }
 
 //  roomsList->resizeColumnsToContents();
 }
@@ -1203,9 +1424,22 @@
                 tr("Error"),
                 tr("Please select room from the list"),
                 tr("OK"));
-        return ;
+        return;
     }
-    emit askForJoinRoom(curritem->data(Qt::DisplayRole).toString());
+
+    for (int i = 0; i < listFromServer.size(); i += 8) {
+        if (listFromServer[i + 1] == curritem->data(Qt::DisplayRole).toString()) {
+            gameInLobby = listFromServer[i].compare("True");
+            break;
+        }
+    }
+    
+    if (gameInLobby) {
+        gameInLobbyName = curritem->data(Qt::DisplayRole).toString();
+        emit askForRoomList();
+    } else {
+        emit askForJoinRoom(curritem->data(Qt::DisplayRole).toString());
+    }
 }
 
 void PageRoomsList::onRefreshClick()
@@ -1213,6 +1447,24 @@
     emit askForRoomList();
 }
 
+void PageRoomsList::onClearClick()
+{
+    CBState->setCurrentIndex(0);
+    CBRules->setCurrentIndex(0);
+    CBWeapons->setCurrentIndex(0);
+    searchText->clear();
+}
+
+void PageRoomsList::onJoinConfirmation(const QString & room)
+{
+    if (QMessageBox::warning(this,
+        tr("Warning"),
+        tr("The game you are trying to join has started.\nDo you still want to join the room?"),
+        QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes)
+    {
+        emit askForJoinRoom(room);
+    }
+}
 
 PageConnecting::PageConnecting(QWidget* parent) :
     AbstractPage(parent)
@@ -1277,55 +1529,71 @@
 
     TBW_lowGravity = new ToggleButtonWidget(gbGameModes, ":/res/btnLowGravity.png");
     TBW_lowGravity->setToolTip("<b>" + ToggleButtonWidget::tr("Low Gravity") + "</b>:<br />" + tr("Lower gravity"));
-    glGMLayout->addWidget(TBW_lowGravity,1,0,1,1);
+    glGMLayout->addWidget(TBW_lowGravity,0,4,1,1);
 
     TBW_laserSight = new ToggleButtonWidget(gbGameModes, ":/res/btnLaserSight.png");
     TBW_laserSight->setToolTip("<b>" + ToggleButtonWidget::tr("Laser Sight") + "</b>:<br />" + tr("Assisted aiming with laser sight"));
-    glGMLayout->addWidget(TBW_laserSight,1,1,1,1);
+    glGMLayout->addWidget(TBW_laserSight,1,0,1,1);
 
     TBW_invulnerable = new ToggleButtonWidget(gbGameModes, ":/res/btnInvulnerable.png");
     TBW_invulnerable->setToolTip("<b>" + ToggleButtonWidget::tr("Invulnerable") + "</b>:<br />" + tr("All hogs have a personal forcefield"));
-    glGMLayout->addWidget(TBW_invulnerable,1,2,1,1);
+    glGMLayout->addWidget(TBW_invulnerable,1,1,1,1);
 
     TBW_mines = new ToggleButtonWidget(gbGameModes, ":/res/btnMines.png");
     TBW_mines->setToolTip("<b>" + ToggleButtonWidget::tr("Add Mines") + "</b>:<br />" + tr("Enable random mines"));
-    glGMLayout->addWidget(TBW_mines,1,3,1,1);
+    glGMLayout->addWidget(TBW_mines,1,2,1,1);
 
     TBW_vampiric = new ToggleButtonWidget(gbGameModes, ":/res/btnVampiric.png");
     TBW_vampiric->setToolTip("<b>" + ToggleButtonWidget::tr("Vampirism") + "</b>:<br />" + tr("Gain 80% of the damage you do back in health"));
-    glGMLayout->addWidget(TBW_vampiric,2,0,1,1);
+    glGMLayout->addWidget(TBW_vampiric,1,3,1,1);
 
     TBW_karma = new ToggleButtonWidget(gbGameModes, ":/res/btnKarma.png");
     TBW_karma->setToolTip("<b>" + ToggleButtonWidget::tr("Karma") + "</b>:<br />" + tr("Share your opponents pain, share their damage"));
-    glGMLayout->addWidget(TBW_karma,2,1,1,1);
+    glGMLayout->addWidget(TBW_karma,1,4,1,1);
 
     TBW_artillery = new ToggleButtonWidget(gbGameModes, ":/res/btnArtillery.png");
     TBW_artillery->setToolTip("<b>" + ToggleButtonWidget::tr("Artillery") + "</b>:<br />" + tr("Your hogs are unable to move, put your artillery skills to the test"));
-    glGMLayout->addWidget(TBW_artillery,2,2,1,1);
+    glGMLayout->addWidget(TBW_artillery,2,0,1,1);
 
     TBW_randomorder = new ToggleButtonWidget(gbGameModes, ":/res/btnRandomOrder.png");
     TBW_randomorder->setToolTip("<b>" + ToggleButtonWidget::tr("Random Order") + "</b>:<br />" + tr("Order of play is random instead of in room order."));
-    glGMLayout->addWidget(TBW_randomorder,2,3,1,1);
+    glGMLayout->addWidget(TBW_randomorder,2,1,1,1);
 
     TBW_king = new ToggleButtonWidget(gbGameModes, ":/res/btnKing.png");
     TBW_king->setToolTip("<b>" + ToggleButtonWidget::tr("King") + "</b>:<br />" + tr("Play with a King. If he dies, your side dies."));
-    glGMLayout->addWidget(TBW_king,3,0,1,1);
+    glGMLayout->addWidget(TBW_king,2,2,1,1);
 
     TBW_placehog = new ToggleButtonWidget(gbGameModes, ":/res/btnPlaceHog.png");
     TBW_placehog->setToolTip("<b>" + ToggleButtonWidget::tr("Place Hedgehogs") + "</b>:<br />" + tr("Take turns placing your hedgehogs before the start of play."));
-    glGMLayout->addWidget(TBW_placehog,3,1,1,1);
+    glGMLayout->addWidget(TBW_placehog,2,3,1,1);
 
     TBW_sharedammo = new ToggleButtonWidget(gbGameModes, ":/res/btnSharedAmmo.png");
     TBW_sharedammo->setToolTip("<b>" + ToggleButtonWidget::tr("Clan Shares Ammo") + "</b>:<br />" + tr("Ammo is shared between all teams that share a colour."));
-    glGMLayout->addWidget(TBW_sharedammo,3,2,1,1);
+    glGMLayout->addWidget(TBW_sharedammo,2,4,1,1);
 
     TBW_disablegirders = new ToggleButtonWidget(gbGameModes, ":/res/btnDisableGirders.png");
     TBW_disablegirders->setToolTip("<b>" + ToggleButtonWidget::tr("Disable Girders") + "</b>:<br />" + tr("Disable girders when generating random maps."));
-    glGMLayout->addWidget(TBW_disablegirders,3,3,1,1);
+    glGMLayout->addWidget(TBW_disablegirders,3,0,1,1);
 
     TBW_disablelandobjects = new ToggleButtonWidget(gbGameModes, ":/res/btnDisableLandObjects.png");
     TBW_disablelandobjects->setToolTip("<b>" + ToggleButtonWidget::tr("Disable Land Objects") + "</b>:<br />" + tr("Disable land objects when generating random maps."));
-    glGMLayout->addWidget(TBW_disablelandobjects,4,0,1,1);
+    glGMLayout->addWidget(TBW_disablelandobjects,3,1,1,1);
+
+    TBW_aisurvival = new ToggleButtonWidget(gbGameModes, ":/res/btnAISurvival.png");
+    TBW_aisurvival->setToolTip("<b>" + ToggleButtonWidget::tr("AI Survival Mode") + "</b>:<br />" + tr("AI respawns on death."));
+    glGMLayout->addWidget(TBW_aisurvival,3,2,1,1);
+
+    TBW_infattack = new ToggleButtonWidget(gbGameModes, ":/res/btnInfAttack.png");
+    TBW_infattack->setToolTip("<b>" + ToggleButtonWidget::tr("Unlimited Attacks") + "</b>:<br />" + tr("Attacking does not end your turn."));
+    glGMLayout->addWidget(TBW_infattack,3,3,1,1);
+
+    TBW_resetweps = new ToggleButtonWidget(gbGameModes, ":/res/btnResetWeps.png");
+    TBW_resetweps->setToolTip("<b>" + ToggleButtonWidget::tr("Reset Weapons") + "</b>:<br />" + tr("Weapons are reset to starting values each turn."));
+    glGMLayout->addWidget(TBW_resetweps,3,4,1,1);
+
+    TBW_perhogammo = new ToggleButtonWidget(gbGameModes, ":/res/btnPerHogAmmo.png");
+    TBW_perhogammo->setToolTip("<b>" + ToggleButtonWidget::tr("Per Hedgehog Ammo") + "</b>:<br />" + tr("Each hedgehog has its own ammo. It does not share with the team."));
+    glGMLayout->addWidget(TBW_perhogammo,4,0,1,1);
 
     // Right
     QLabel * l;
@@ -1355,7 +1623,7 @@
     glBSLayout->addWidget(l,1,1,1,1);
 
     SB_TurnTime = new QSpinBox(gbBasicSettings);
-    SB_TurnTime->setRange(1, 99);
+    SB_TurnTime->setRange(1, 9999);
     SB_TurnTime->setValue(45);
     SB_TurnTime->setSingleStep(15);
     glBSLayout->addWidget(SB_TurnTime,1,2,1,1);
@@ -1510,15 +1778,19 @@
     mapper->addMapping(TBW_sharedammo, 15);
     mapper->addMapping(TBW_disablegirders, 16);
     mapper->addMapping(TBW_disablelandobjects, 17);
-    mapper->addMapping(SB_DamageModifier, 18);
-    mapper->addMapping(SB_TurnTime, 19);
-    mapper->addMapping(SB_InitHealth, 20);
-    mapper->addMapping(SB_SuddenDeath, 21);
-    mapper->addMapping(SB_CaseProb, 22);
-    mapper->addMapping(SB_MinesTime, 23);
-    mapper->addMapping(SB_Mines, 24);
-    mapper->addMapping(SB_MineDuds, 25);
-    mapper->addMapping(SB_Explosives, 26);
+    mapper->addMapping(TBW_aisurvival, 18);
+    mapper->addMapping(TBW_infattack, 19);
+    mapper->addMapping(TBW_resetweps, 20);
+    mapper->addMapping(TBW_perhogammo, 21);
+    mapper->addMapping(SB_DamageModifier, 22);
+    mapper->addMapping(SB_TurnTime, 23);
+    mapper->addMapping(SB_InitHealth, 24);
+    mapper->addMapping(SB_SuddenDeath, 25);
+    mapper->addMapping(SB_CaseProb, 26);
+    mapper->addMapping(SB_MinesTime, 27);
+    mapper->addMapping(SB_Mines, 28);
+    mapper->addMapping(SB_MineDuds, 29);
+    mapper->addMapping(SB_Explosives, 30);
 
     mapper->toFirst();
 }
--- a/QTfrontend/pages.h	Thu Aug 26 23:59:18 2010 +0200
+++ b/QTfrontend/pages.h	Wed Oct 27 14:02:20 2010 +0200
@@ -70,6 +70,7 @@
  protected:
   AbstractPage(QWidget* parent = 0) {
     font14 = new QFont("MS Shell Dlg", 14);
+    setFocusPolicy(Qt::StrongFocus);
   }
   virtual ~AbstractPage() {};
 
@@ -216,6 +217,7 @@
     QPushButton *BtnNewTeam;
     QPushButton *BtnEditTeam;
     QPushButton *BtnDeleteTeam;
+    QPushButton *BtnAssociateFiles;
     QLabel *LblNoEditTeam;
     QComboBox *CBTeamName;
     IconedGroupBox *AGGroupBox;
@@ -340,6 +342,7 @@
 
     QPushButton *BtnSimpleGamePage;
     QPushButton *BtnTrainPage;
+    QPushButton *BtnCampaignPage;
     QPushButton *BtnMultiplayer;
     QPushButton *BtnLoad;
     QPushButton *BtnDemos;
@@ -359,6 +362,19 @@
     QComboBox   *CBSelect;
 };
 
+class PageCampaign : public AbstractPage
+{
+    Q_OBJECT
+
+public:
+    PageCampaign(QWidget* parent = 0);
+
+    QPushButton *BtnStartCampaign;
+    QPushButton *BtnBack;
+    QComboBox   *CBSelect;
+    QComboBox   *CBTeam;
+};
+
 class PageSelectWeapon : public AbstractPage
 {
     Q_OBJECT
@@ -389,14 +405,24 @@
     PageRoomsList(QWidget* parent, QSettings * config, SDLInteraction * sdli);
 
     QLineEdit * roomName;
+    QLineEdit * searchText;
     QTableWidget * roomsList;
     QPushButton * BtnBack;
     QPushButton * BtnCreate;
     QPushButton * BtnJoin;
     QPushButton * BtnRefresh;
     QPushButton * BtnAdmin;
+    QPushButton * BtnClear;
+    QComboBox * CBState;
+    QComboBox * CBRules;
+    QComboBox * CBWeapons;
     HWChatWidget * chatWidget;
 
+private:
+    bool gameInLobby;
+    QString gameInLobbyName;
+    QStringList listFromServer;
+
 public slots:
     void setRoomsList(const QStringList & list);
     void setAdmin(bool);
@@ -405,11 +431,14 @@
     void onCreateClick();
     void onJoinClick();
     void onRefreshClick();
+    void onClearClick();
+    void onJoinConfirmation(const QString &);
 
 signals:
     void askForCreateRoom(const QString &);
     void askForJoinRoom(const QString &);
     void askForRoomList();
+    void askJoinConfirmation(const QString &);
 };
 
 class PageConnecting : public AbstractPage
@@ -453,6 +482,10 @@
     ToggleButtonWidget * TBW_sharedammo;
     ToggleButtonWidget * TBW_disablegirders;
     ToggleButtonWidget * TBW_disablelandobjects;
+    ToggleButtonWidget * TBW_aisurvival;
+    ToggleButtonWidget * TBW_infattack;
+    ToggleButtonWidget * TBW_resetweps;
+    ToggleButtonWidget * TBW_perhogammo;
 
     QSpinBox * SB_DamageModifier;
     QSpinBox * SB_TurnTime;
Binary file QTfrontend/res/StatsBestKiller.png has changed
Binary file QTfrontend/res/StatsBestShot.png has changed
Binary file QTfrontend/res/StatsD.png has changed
Binary file QTfrontend/res/StatsH.png has changed
Binary file QTfrontend/res/StatsHedgehogsKilled.png has changed
Binary file QTfrontend/res/StatsMedal1.png has changed
Binary file QTfrontend/res/StatsMedal2.png has changed
Binary file QTfrontend/res/StatsMedal3.png has changed
Binary file QTfrontend/res/StatsMedal4.png has changed
Binary file QTfrontend/res/StatsMostSelfDamage.png has changed
Binary file QTfrontend/res/StatsR.png has changed
Binary file QTfrontend/res/StatsSelfKilled.png has changed
Binary file QTfrontend/res/StatsSkipped.png has changed
Binary file QTfrontend/res/btnAISurvival.png has changed
Binary file QTfrontend/res/btnInfAttack.png has changed
Binary file QTfrontend/res/btnPerHogAmmo.png has changed
Binary file QTfrontend/res/btnResetWeps.png has changed
Binary file QTfrontend/res/mapCustom.png has changed
Binary file QTfrontend/res/mapMaze.png has changed
Binary file QTfrontend/res/mapMissing.png has changed
Binary file QTfrontend/res/mapMission.png has changed
Binary file QTfrontend/res/mapRandom.png has changed
--- a/QTfrontend/sdlkeys.h	Thu Aug 26 23:59:18 2010 +0200
+++ b/QTfrontend/sdlkeys.h	Wed Oct 27 14:02:20 2010 +0200
@@ -39,7 +39,7 @@
     {")", ")"},
     {"*", "*"},
     {"+", "+"},
-    {", ", ", "},
+    {",", ","},
     {"-", "-"},
     {".", "."},
     {"/", "/"},
--- a/QTfrontend/selectWeapon.cpp	Thu Aug 26 23:59:18 2010 +0200
+++ b/QTfrontend/selectWeapon.cpp	Wed Oct 27 14:02:20 2010 +0200
@@ -131,11 +131,11 @@
         SelWeaponItem * pwi = new SelWeaponItem(false, i, currentState[numItems + i].digitValue(), QImage(":/res/ammopicbox.png"), this);
         weaponItems[i].append(pwi);
         p2Layout->addWidget(pwi, j, k % 4);
-        
+
         SelWeaponItem * dwi = new SelWeaponItem(false, i, currentState[numItems*2 + i].digitValue(), QImage(":/res/ammopicdelay.png"), this);
         weaponItems[i].append(dwi);
         p3Layout->addWidget(dwi, j, k % 4);
-        
+
         SelWeaponItem * awi = new SelWeaponItem(false, i, currentState[numItems*3 + i].digitValue(), QImage(":/res/ammopic.png"), this);
         weaponItems[i].append(awi);
         p4Layout->addWidget(awi, j, k % 4);
--- a/QTfrontend/statsPage.cpp	Thu Aug 26 23:59:18 2010 +0200
+++ b/QTfrontend/statsPage.cpp	Wed Oct 27 14:02:20 2010 +0200
@@ -19,7 +19,8 @@
 #include <QLabel>
 #include <QGridLayout>
 #include <QGraphicsScene>
-
+#include <QGroupBox>
+#include <QSizePolicy>
 #include "statsPage.h"
 #include "team.h"
 
@@ -36,20 +37,59 @@
 PageGameStats::PageGameStats(QWidget* parent) : AbstractPage(parent)
 {
     QGridLayout * pageLayout = new QGridLayout(this);
+    pageLayout->setSpacing(20);
     pageLayout->setColumnStretch(0, 1);
     pageLayout->setColumnStretch(1, 1);
-    pageLayout->setColumnStretch(2, 1);
+
+    BtnBack = addButton(":/res/Exit.png", pageLayout, 3, 0, true);
+    BtnBack->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
 
-    BtnBack = addButton(":/res/Exit.png", pageLayout, 2, 0, true);
+    QGroupBox * gb = new QGroupBox(this);
+    QVBoxLayout * gbl = new QVBoxLayout;
 
+    // details
     labelGameStats = new QLabel(this);
+    QLabel * l = new QLabel(this);
+    l->setTextFormat(Qt::RichText);
+    l->setText("<h1><img src=\":/res/StatsD.png\"> " + PageGameStats::tr("Details") + "</h1>");
+    l->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
     labelGameStats->setTextFormat(Qt::RichText);
-    pageLayout->addWidget(labelGameStats, 0, 0, 1, 3);
-
-    graphic = new FitGraphicsView(this);
+    labelGameStats->setAlignment(Qt::AlignTop);
+    gbl->addWidget(l);
+    gbl->addWidget(labelGameStats);
+    gb->setLayout(gbl);
+    pageLayout->addWidget(gb, 1, 1);
+    
+    // graph
+    graphic = new FitGraphicsView(gb);
+    l = new QLabel(this);
+    l->setTextFormat(Qt::RichText);
+    l->setText("<br><h1><img src=\":/res/StatsH.png\"> " + PageGameStats::tr("Health graph") + "</h1>");
+    l->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+    gbl->addWidget(l);
+    gbl->addWidget(graphic);
     graphic->scale(1.0, -1.0);
     graphic->setBackgroundBrush(QBrush(Qt::black));
-    pageLayout->addWidget(graphic, 1, 0, 1, 3);
+    
+    labelGameWin = new QLabel(this);
+    labelGameWin->setTextFormat(Qt::RichText);
+    pageLayout->addWidget(labelGameWin, 0, 0, 1, 2);
+
+    // ranking box
+    gb = new QGroupBox(this);
+    gbl = new QVBoxLayout;
+    labelGameRank = new QLabel(gb);
+    l = new QLabel(this);
+    l->setTextFormat(Qt::RichText);
+    l->setText("<h1><img src=\":/res/StatsR.png\"> " + PageGameStats::tr("Ranking") + "</h1>");
+    l->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+    gbl->addWidget(l);
+    gbl->addWidget(labelGameRank);
+    gb->setLayout(gbl);
+
+    labelGameRank->setTextFormat(Qt::RichText);
+    labelGameRank->setAlignment(Qt::AlignTop);
+    pageLayout->addWidget(gb, 1, 0);
 }
 
 void PageGameStats::AddStatText(const QString & msg)
@@ -61,6 +101,9 @@
 {
     labelGameStats->setText("");
     healthPoints.clear();
+    labelGameRank->setText("");
+    playerPosition = 0;
+    lastColor = 0;
 }
 
 void PageGameStats::renderStats()
@@ -93,27 +136,25 @@
 {
     switch(type) {
         case 'r' : {
-            AddStatText(QString("<h1 align=\"center\">%1</h1>").arg(info));
+            labelGameWin->setText(QString("<h1 align=\"center\">%1</h1>").arg(info));
             break;
         }
         case 'D' : {
             int i = info.indexOf(' ');
-            QString message = PageGameStats::tr("<p>The best shot award was won by <b>%1</b> with <b>%2</b> pts.</p>")
-                    .arg(info.mid(i + 1), info.left(i));
+            QString message = "<p><img src=\":/res/StatsBestShot.png\"> " + PageGameStats::tr("The best shot award was won by <b>%1</b> with <b>%2</b> pts.").arg(info.mid(i + 1), info.left(i)) + "</p>";
             AddStatText(message);
             break;
         }
         case 'k' : {
             int i = info.indexOf(' ');
             int num = info.left(i).toInt();
-            QString message = PageGameStats::tr("<p>The best killer is <b>%1</b> with <b>%2</b> kills in a turn.</p>", "", num)
-                    .arg(info.mid(i + 1), info.left(i));
+            QString message = "<p><img src=\":/res/StatsBestKiller.png\"> " + PageGameStats::tr("The best killer is <b>%1</b> with <b>%2</b> kills in a turn.", "", num).arg(info.mid(i + 1), info.left(i)) + "</p>";
             AddStatText(message);
             break;
         }
         case 'K' : {
             int num = info.toInt();
-            QString message = PageGameStats::tr("<p>A total of <b>%1</b> hedgehog(s) were killed during this round.</p>", "", num).arg(num);
+            QString message = "<p><img src=\":/res/StatsHedgehogsKilled.png\"> " +  PageGameStats::tr("A total of <b>%1</b> hedgehog(s) were killed during this round.", "", num).arg(num) + "</p>";
             AddStatText(message);
             break;
         }
@@ -136,6 +177,75 @@
                     team.Wins++; // should draws count as wins?
                 //team.SaveToFile(); // don't save yet
             }
+	    break;
         }
+	
+        case 'P' : {
+            int i = info.indexOf(' ');
+	    playerPosition++;
+	    QString color = info.left(i);
+	    quint32 c = color.toInt();
+	    QColor clanColor = QColor(qRgb((c >> 16) & 255, (c >> 8) & 255, c & 255));
+
+	    QString playerinfo = info.mid(i + 1);
+	    
+	    i = playerinfo.indexOf(' ');
+
+	    QString kills = playerinfo.left(i);
+	    QString playername = playerinfo.mid(i + 1);
+	    QString image;
+
+            if (lastColor == c && playerPosition <= 2) playerPosition = 1;
+	    lastColor = c;
+
+	    switch (playerPosition)
+	    {
+	    	case 1:
+			image = "<img src=\":/res/StatsMedal1.png\">";
+			break;
+		case 2:
+			image = "<img src=\":/res/StatsMedal2.png\">";
+			break;
+		case 3:
+			image = "<img src=\":/res/StatsMedal3.png\">";
+			break;
+		default:
+			image = "<img src=\":/res/StatsMedal4.png\">";
+			break;
+	    }
+
+            QString message;
+	    QString killstring;
+	    if (kills.toInt() == 1)
+	    {
+	    	killstring = PageGameStats::tr("(%1 kill)").arg(kills);
+	    } else {
+	    	killstring = PageGameStats::tr("(%1 kills)").arg(kills);
+            }
+	    
+	    message = QString("<p><h2>%1 %2. <font color=\"%4\">%3</font> ").arg(image, QString::number(playerPosition), playername, clanColor.name()) + killstring + "</h2></p>";
+            
+	    labelGameRank->setText(labelGameRank->text() + message);
+            break;
+	}
+        case 's' : {
+            int i = info.indexOf(' ');
+            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.").arg(info.mid(i + 1), info.left(i)) + "</p>";
+            AddStatText(message);
+            break;
+        }
+        case 'S' : {
+            int i = info.indexOf(' ');
+            QString message = "<p><img src=\":/res/StatsSelfKilled.png\"> " + PageGameStats::tr("<b>%1</b> killed <b>%2</b> of his own hedgehogs.").arg(info.mid(i + 1), info.left(i)) + "</p>"; 
+            AddStatText(message);
+            break;
+        }
+        case 'B' : {
+            int i = info.indexOf(' ');
+            QString message = "<p><img src=\":/res/StatsSkipped.png\"> " + PageGameStats::tr("<b>%1</b> was scared and skipped turn <b>%2</b> times.").arg(info.mid(i + 1), info.left(i)) + "</p>";
+            AddStatText(message);
+            break;
+        }
+
     }
 }
--- a/QTfrontend/statsPage.h	Thu Aug 26 23:59:18 2010 +0200
+++ b/QTfrontend/statsPage.h	Wed Oct 27 14:02:20 2010 +0200
@@ -44,6 +44,8 @@
 
     QPushButton *BtnBack;
     QLabel *labelGameStats;
+    QLabel *labelGameWin;
+    QLabel *labelGameRank;
     FitGraphicsView * graphic;
 
 public slots:
@@ -55,6 +57,8 @@
     void AddStatText(const QString & msg);
 
     QMap<quint32, QVector<quint32> > healthPoints;
+    unsigned int playerPosition;
+    quint32 lastColor;
 };
 
 #endif // STATSPAGE_H
--- a/QTfrontend/tcpBase.cpp	Thu Aug 26 23:59:18 2010 +0200
+++ b/QTfrontend/tcpBase.cpp	Wed Oct 27 14:02:20 2010 +0200
@@ -72,7 +72,7 @@
   process = new QProcess;
   connect(process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(StartProcessError(QProcess::ProcessError)));
   QStringList arguments=setArguments();
-  
+
   // redirect everything written on stdout/stderr
   if(isDevBuild)
     process->setProcessChannelMode(QProcess::ForwardedChannels);
--- a/QTfrontend/team.cpp	Thu Aug 26 23:59:18 2010 +0200
+++ b/QTfrontend/team.cpp	Wed Oct 27 14:02:20 2010 +0200
@@ -52,6 +52,7 @@
     }
     Rounds = 0;
     Wins = 0;
+    CampaignProgress = 0;
 }
 
 HWTeam::HWTeam(const QStringList& strLst) :
@@ -73,10 +74,11 @@
         Hedgehogs[i].Hat=strLst[i * 2 + 8];
 // Somehow claymore managed an empty hat.  Until we figure out how, this should avoid a repeat
 // Checking net teams is probably pointless, but can't hurt.
-        if (Hedgehogs[i].Hat.length() == 0) Hedgehogs[i].Hat = "NoHat"; 
+        if (Hedgehogs[i].Hat.isEmpty()) Hedgehogs[i].Hat = "NoHat";
     }
     Rounds = 0;
     Wins = 0;
+    CampaignProgress = 0;
 }
 
 HWTeam::HWTeam() :
@@ -103,12 +105,13 @@
     }
     Rounds = 0;
     Wins = 0;
+    CampaignProgress = 0;
 }
 
 
 bool HWTeam::LoadFromFile()
 {
-    QSettings teamfile(cfgdir->absolutePath() + "/Teams/" + TeamName + ".ini", QSettings::IniFormat, 0);
+    QSettings teamfile(cfgdir->absolutePath() + "/Teams/" + TeamName + ".hwt", QSettings::IniFormat, 0);
     teamfile.setIniCodec("UTF-8");
     TeamName = teamfile.value("Team/Name", TeamName).toString();
     Grave = teamfile.value("Team/Grave", "Statue").toString();
@@ -118,6 +121,7 @@
     difficulty = teamfile.value("Team/Difficulty", 0).toInt();
     Rounds = teamfile.value("Team/Rounds", 0).toInt();
     Wins = teamfile.value("Team/Wins", 0).toInt();
+    CampaignProgress = teamfile.value("Team/CampaignProgress", 0).toInt();
     for(int i = 0; i < 8; i++)
     {
         QString hh = QString("Hedgehog%1/").arg(i);
@@ -140,7 +144,7 @@
 
 bool HWTeam::FileExists()
 {
-    QFile f(cfgdir->absolutePath() + "/Teams/" + TeamName + ".ini");
+    QFile f(cfgdir->absolutePath() + "/Teams/" + TeamName + ".hwt");
     return f.exists();
 }
 
@@ -148,7 +152,7 @@
 {
     if(m_isNetTeam)
         return false;
-    QFile cfgfile(cfgdir->absolutePath() + "/Teams/" + TeamName + ".ini");
+    QFile cfgfile(cfgdir->absolutePath() + "/Teams/" + TeamName + ".hwt");
     cfgfile.remove();
     return true;
 }
@@ -157,11 +161,11 @@
 {
     if (OldTeamName != TeamName)
     {
-        QFile cfgfile(cfgdir->absolutePath() + "/Teams/" + OldTeamName + ".ini");
+        QFile cfgfile(cfgdir->absolutePath() + "/Teams/" + OldTeamName + ".hwt");
         cfgfile.remove();
         OldTeamName = TeamName;
     }
-    QSettings teamfile(cfgdir->absolutePath() + "/Teams/" + TeamName + ".ini", QSettings::IniFormat, 0);
+    QSettings teamfile(cfgdir->absolutePath() + "/Teams/" + TeamName + ".hwt", QSettings::IniFormat, 0);
     teamfile.setIniCodec("UTF-8");
     teamfile.setValue("Team/Name", TeamName);
     teamfile.setValue("Team/Grave", Grave);
@@ -171,6 +175,7 @@
     teamfile.setValue("Team/Difficulty", difficulty);
     teamfile.setValue("Team/Rounds", Rounds);
     teamfile.setValue("Team/Wins", Wins);
+    teamfile.setValue("Team/CampaignProgress", CampaignProgress);
     for(int i = 0; i < 8; i++)
     {
         QString hh = QString("Hedgehog%1/").arg(i);
@@ -204,7 +209,7 @@
             hwform->ui.pageEditTeam->HHHats[i]->setCurrentIndex(hwform->ui.pageEditTeam->HHHats[i]->findData(Hedgehogs[i].Hat, Qt::DisplayRole));
     }
     hwform->ui.pageEditTeam->CBGrave->setCurrentIndex(hwform->ui.pageEditTeam->CBGrave->findText(Grave));
-    hwform->ui.pageEditTeam->CBFlag->setCurrentIndex(hwform->ui.pageEditTeam->CBFlag->findText(Flag));
+    hwform->ui.pageEditTeam->CBFlag->setCurrentIndex(hwform->ui.pageEditTeam->CBFlag->findData(Flag));
 
     hwform->ui.pageEditTeam->CBFort->setCurrentIndex(hwform->ui.pageEditTeam->CBFort->findText(Fort));
     hwform->ui.pageEditTeam->CBVoicepack->setCurrentIndex(hwform->ui.pageEditTeam->CBVoicepack->findText(Voicepack));
@@ -232,7 +237,7 @@
     Grave = hwform->ui.pageEditTeam->CBGrave->currentText();
     Fort = hwform->ui.pageEditTeam->CBFort->currentText();
     Voicepack = hwform->ui.pageEditTeam->CBVoicepack->currentText();
-    Flag = hwform->ui.pageEditTeam->CBFlag->currentText();
+    Flag = hwform->ui.pageEditTeam->CBFlag->itemData(hwform->ui.pageEditTeam->CBFlag->currentIndex()).toString();
     for(int i = 0; i < BINDS_NUMBER; i++)
     {
         binds[i].strbind = hwform->ui.pageEditTeam->CBBind[i]->itemData(hwform->ui.pageEditTeam->CBBind[i]->currentIndex()).toString();
--- a/QTfrontend/team.h	Thu Aug 26 23:59:18 2010 +0200
+++ b/QTfrontend/team.h	Wed Oct 27 14:02:20 2010 +0200
@@ -56,6 +56,7 @@
         QString Owner;
         int Rounds;
         int Wins;
+        int CampaignProgress;
         HWHog Hedgehogs[8];
         unsigned int AchievementProgress[MAX_ACHIEVEMENTS];
         unsigned int difficulty;
--- a/QTfrontend/teamselhelper.cpp	Thu Aug 26 23:59:18 2010 +0200
+++ b/QTfrontend/teamselhelper.cpp	Wed Oct 27 14:02:20 2010 +0200
@@ -75,6 +75,7 @@
 
         phhoger = new CHedgehogerWidget(QImage(":/res/hh25x25.png"), this);
         connect(phhoger, SIGNAL(hedgehogsNumChanged()), this, SLOT(hhNumChanged()));
+        phhoger->setHHNum(team.numHedgehogs);
         mainLayout.addWidget(phhoger);
     } else {
     }
--- a/QTfrontend/ui_hwform.cpp	Thu Aug 26 23:59:18 2010 +0200
+++ b/QTfrontend/ui_hwform.cpp	Wed Oct 27 14:02:20 2010 +0200
@@ -113,4 +113,7 @@
 
     pageNetType = new PageNetType();
     Pages->addWidget(pageNetType);
+
+    pageCampaign = new PageCampaign();
+    Pages->addWidget(pageCampaign);
 }
--- a/QTfrontend/ui_hwform.h	Thu Aug 26 23:59:18 2010 +0200
+++ b/QTfrontend/ui_hwform.h	Wed Oct 27 14:02:20 2010 +0200
@@ -32,6 +32,7 @@
 class PageGameStats;
 class PageSinglePlayer;
 class PageTraining;
+class PageCampaign;
 class PageSelectWeapon;
 class PageInGame;
 class PageRoomsList;
@@ -70,6 +71,7 @@
     PageScheme *pageScheme;
     PageAdmin *pageAdmin;
     PageNetType *pageNetType;
+    PageCampaign *pageCampaign;
 
     QStackedLayout *Pages;
     QFont *font14;
--- a/QTfrontend/xfire.cpp	Thu Aug 26 23:59:18 2010 +0200
+++ b/QTfrontend/xfire.cpp	Wed Oct 27 14:02:20 2010 +0200
@@ -1,6 +1,6 @@
 /*
  * Hedgewars Xfire integration
- * Copyright (c) 2010 Mario Liebisch <mario.liebisch AT googlemail.com>
+ * Copyright (c) 2010 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
@@ -34,10 +34,10 @@
     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];
@@ -45,7 +45,7 @@
         strcpy(keys[i], "");
         strcpy(values[i], "");
     }
-    
+
     strcpy(keys[XFIRE_NICKNAME], "Nickname");
     strcpy(keys[XFIRE_ROOM], "Room");
     strcpy(keys[XFIRE_SERVER], "Server");
@@ -58,7 +58,7 @@
 {
     if(!use_xfire)
         return;
-    
+
     for(int i = 0; i < XFIRE_KEY_COUNT; i++)
     {
         delete [] keys[i];
--- a/QTfrontend/xfire.h	Thu Aug 26 23:59:18 2010 +0200
+++ b/QTfrontend/xfire.h	Wed Oct 27 14:02:20 2010 +0200
@@ -1,6 +1,6 @@
 /*
  * Hedgewars Xfire integration
- * Copyright (c) 2010 Mario Liebisch <mario.liebisch AT googlemail.com>
+ * Copyright (c) 2010 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
Binary file bin/hwdfile.ico has changed
Binary file bin/hwsfile.ico has changed
--- a/gameServer/Actions.hs	Thu Aug 26 23:59:18 2010 +0200
+++ b/gameServer/Actions.hs	Wed Oct 27 14:02:20 2010 +0200
@@ -11,7 +11,7 @@
 import Data.Time
 import Data.Maybe
 import Control.Monad.Reader
-import Control.Monad.State
+import Control.Monad.State.Strict
 import qualified Data.ByteString.Char8 as B
 -----------------------------
 import CoreTypes
@@ -57,9 +57,7 @@
 
 
 processAction (AnswerClients chans msg) = do
-    liftIO (putStr $ "AnswerClients... " ++ (show $ length chans) ++ " (" ++ (show msg) ++")")
-    liftIO $ map (flip seq ()) chans `seq` mapM_ (flip writeChan msg) chans
-    liftIO (putStrLn "done")
+    liftIO $ map (flip seq ()) chans `seq` map (flip seq ()) msg `seq` mapM_ (flip writeChan msg) chans
 
 
 processAction SendServerMessage = do
@@ -100,30 +98,35 @@
     (Just ci) <- gets clientIndex
     rnc <- gets roomsClients
     ri <- clientRoomA
-    when (ri /= lobbyId) $ do
-        processAction $ MoveToLobby ("quit: " `B.append` msg)
-        return ()
 
     chan <- client's sendChan
     ready <- client's isReady
 
+    when (ri /= lobbyId) $ do
+        processAction $ MoveToLobby ("quit: " `B.append` msg)
+        liftIO $ modifyRoom rnc (\r -> r{
+                        --playersIDs = IntSet.delete ci (playersIDs r)
+                        playersIn = (playersIn r) - 1,
+                        readyPlayers = if ready then readyPlayers r - 1 else readyPlayers r
+                        }) ri
+        return ()
+
     liftIO $ do
         infoM "Clients" (show ci ++ " quits: " ++ (B.unpack msg))
 
         --mapM_ (processAction (ci, serverInfo, rnc)) $ answerOthersQuit ++ answerInformRoom
-        modifyRoom rnc (\r -> r{
-                        --playersIDs = IntSet.delete ci (playersIDs r)
-                        playersIn = (playersIn r) - 1,
-                        readyPlayers = if ready then readyPlayers r - 1 else readyPlayers r
-                        }) ri
 
     processAction $ AnswerClients [chan] ["BYE", msg]
-    modify (\s -> s{removedClients = ci `Set.insert` removedClients s})
+
+    s <- get
+    put $! s{removedClients = ci `Set.insert` removedClients s}
 
 processAction (DeleteClient ci) = do
     rnc <- gets roomsClients
     liftIO $ removeClient rnc ci
-    modify (\s -> s{removedClients = ci `Set.delete` removedClients s})
+
+    s <- get
+    put $! s{removedClients = ci `Set.delete` removedClients s}
 
 {-
     where
@@ -258,7 +261,7 @@
 
     processAction $ MoveToRoom rId
 
-    chans <- liftM (map sendChan) $ roomClientsS lobbyId
+    chans <- liftM (map sendChan) $! roomClientsS lobbyId
 
     mapM_ processAction [
         AnswerClients chans ["ROOM", "ADD", roomName]
@@ -401,7 +404,7 @@
     liftIO $ do
         ci <- addClient rnc client
         forkIO $ clientRecvLoop (clientSocket client) (coreChan si) ci
-        forkIO $ clientSendLoop (clientSocket client) (coreChan si) (sendChan client) ci
+        forkIO $ clientSendLoop (clientSocket client) (sendChan client) ci
 
         infoM "Clients" (show ci ++ ": New client. Time: " ++ show (connectTime client))
 
--- a/gameServer/ClientIO.hs	Thu Aug 26 23:59:18 2010 +0200
+++ b/gameServer/ClientIO.hs	Wed Oct 27 14:02:20 2010 +0200
@@ -57,8 +57,8 @@
 
 
 
-clientSendLoop :: Socket -> Chan CoreMessage -> Chan [B.ByteString] -> ClientIndex -> IO()
-clientSendLoop s coreChan chan ci = do
+clientSendLoop :: Socket -> Chan [B.ByteString] -> ClientIndex -> IO ()
+clientSendLoop s chan ci = do
     answer <- readChan chan
     Exception.handle
         (\(e :: Exception.IOException) -> when (not $ isQuit answer) $ sendQuit e) $ do
@@ -67,7 +67,7 @@
     if (isQuit answer) then
         Exception.handle (\(_ :: Exception.IOException) -> putStrLn "error on sClose") $ sClose s
         else
-        clientSendLoop s coreChan chan ci
+        clientSendLoop s chan ci
 
     where
         --sendQuit e = writeChan coreChan $ ClientMessage (ci, ["QUIT", B.pack $ show e])
--- a/gameServer/CoreTypes.hs	Thu Aug 26 23:59:18 2010 +0200
+++ b/gameServer/CoreTypes.hs	Wed Oct 27 14:02:20 2010 +0200
@@ -31,7 +31,7 @@
         roomID :: RoomIndex,
         pingsQueue :: !Word,
         isMaster :: Bool,
-        isReady :: Bool,
+        isReady :: !Bool,
         isAdministrator :: Bool,
         clientClan :: B.ByteString,
         teamsInGame :: Word
@@ -78,7 +78,6 @@
         gameinprogress :: Bool,
         playersIn :: !Int,
         readyPlayers :: !Int,
-        playersIDs :: IntSet.IntSet,
         isRestrictedJoins :: Bool,
         isRestrictedTeams :: Bool,
         roundMsgs :: Seq B.ByteString,
@@ -88,8 +87,7 @@
     }
 
 instance Show RoomInfo where
-    show ri = ", players ids: " ++ show (IntSet.size $ playersIDs ri)
-            ++ ", players: " ++ show (playersIn ri)
+    show ri = ", players: " ++ show (playersIn ri)
             ++ ", ready: " ++ show (readyPlayers ri)
             ++ ", teams: " ++ show (teams ri)
 
@@ -104,7 +102,6 @@
         False
         0
         0
-        IntSet.empty
         False
         False
         Data.Sequence.empty
--- a/gameServer/OfficialServer/extdbinterface.hs	Thu Aug 26 23:59:18 2010 +0200
+++ b/gameServer/OfficialServer/extdbinterface.hs	Wed Oct 27 14:02:20 2010 +0200
@@ -1,4 +1,4 @@
-{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE ScopedTypeVariables, OverloadedStrings #-}
 
 module Main where
 
@@ -26,7 +26,7 @@
     case q of
         CheckAccount clUid clNick _ -> do
                 statement <- prepare dbConn dbQueryAccount
-                execute statement [SqlString $ clNick]
+                execute statement [SqlByteString $ clNick]
                 passAndRole <- fetchRow statement
                 finish statement
                 let response = 
@@ -47,7 +47,7 @@
 
 
 dbConnectionLoop mySQLConnectionInfo =
-    Control.Exception.handle (\(_ :: IOException) -> return ()) $ handleSqlError $
+    Control.Exception.handle (\(e :: IOException) -> hPutStrLn stderr $ show e) $ handleSqlError $
         bracket
             (connectMySQL mySQLConnectionInfo)
             (disconnect)
--- a/gameServer/RoomsAndClients.hs	Thu Aug 26 23:59:18 2010 +0200
+++ b/gameServer/RoomsAndClients.hs	Wed Oct 27 14:02:20 2010 +0200
@@ -1,193 +1,196 @@
-module RoomsAndClients(
-    RoomIndex(),
-    ClientIndex(),
-    MRoomsAndClients(),
-    IRoomsAndClients(),
-    newRoomsAndClients,
-    addRoom,
-    addClient,
-    removeRoom,
-    removeClient,
-    modifyRoom,
-    modifyClient,
-    lobbyId,
-    moveClientToLobby,
-    moveClientToRoom,
-    clientRoom,
-    clientRoomM,
-    client,
-    room,
-    client'sM,
-    room'sM,
-    allClientsM,
-    clientsM,
-    roomClientsM,
-    roomClientsIndicesM,
-    withRoomsAndClients,
-    allRooms,
-    allClients,
-    clientRoom,
-    showRooms,
-    roomClients
-    ) where
-
-
-import Store
-import Control.Monad
-
-
-data Room r = Room {
-    roomClients' :: [ClientIndex],
-    room' :: r
-    }
-
-
-data Client c = Client {
-    clientRoom' :: RoomIndex,
-    client' :: c
-    }
-
-
-newtype RoomIndex = RoomIndex ElemIndex
-    deriving (Eq)
-newtype ClientIndex = ClientIndex ElemIndex
-    deriving (Eq, Show, Read, Ord)
-
-instance Show RoomIndex where
-    show (RoomIndex i) = 'r' : show i
-
-unRoomIndex :: RoomIndex -> ElemIndex
-unRoomIndex (RoomIndex r) = r
-
-unClientIndex :: ClientIndex -> ElemIndex
-unClientIndex (ClientIndex c) = c
-
-
-newtype MRoomsAndClients r c = MRoomsAndClients (MStore (Room r), MStore (Client c))
-newtype IRoomsAndClients r c = IRoomsAndClients (IStore (Room r), IStore (Client c))
-
-
-lobbyId :: RoomIndex
-lobbyId = RoomIndex firstIndex
-
-
-newRoomsAndClients :: r -> IO (MRoomsAndClients r c)
-newRoomsAndClients r = do
-    rooms <- newStore
-    clients <- newStore
-    let rnc = MRoomsAndClients (rooms, clients)
-    ri <- addRoom rnc r
-    when (ri /= lobbyId) $ error "Empty struct inserts not at firstIndex index"
-    return rnc
-
-
-roomAddClient :: ClientIndex -> Room r -> Room r
-roomAddClient cl room = room{roomClients' = cl : roomClients' room}
-
-roomRemoveClient :: ClientIndex -> Room r -> Room r
-roomRemoveClient cl room = room{roomClients' = filter (/= cl) $ roomClients' room}
-
-
-addRoom :: MRoomsAndClients r c -> r -> IO RoomIndex
-addRoom (MRoomsAndClients (rooms, _)) room = do
-    i <- addElem rooms (Room  [] room)
-    return $ RoomIndex i
-
-
-addClient :: MRoomsAndClients r c -> c -> IO ClientIndex
-addClient (MRoomsAndClients (rooms, clients)) client = do
-    i <- addElem clients (Client lobbyId client)
-    modifyElem rooms (roomAddClient (ClientIndex i)) (unRoomIndex lobbyId)
-    return $ ClientIndex i
-
-removeRoom :: MRoomsAndClients r c -> RoomIndex -> IO ()
-removeRoom rnc@(MRoomsAndClients (rooms, _)) room@(RoomIndex ri) 
-    | room == lobbyId = error "Cannot delete lobby"
-    | otherwise = do
-        clIds <- liftM roomClients' $ readElem rooms ri
-        forM_ clIds (moveClientToLobby rnc)
-        removeElem rooms ri
-
-
-removeClient :: MRoomsAndClients r c -> ClientIndex -> IO ()
-removeClient (MRoomsAndClients (rooms, clients)) cl@(ClientIndex ci) = do
-    RoomIndex ri <- liftM clientRoom' $ readElem clients ci
-    modifyElem rooms (roomRemoveClient cl) ri
-    removeElem clients ci
-
-
-modifyRoom :: MRoomsAndClients r c -> (r -> r) -> RoomIndex -> IO ()
-modifyRoom (MRoomsAndClients (rooms, _)) f (RoomIndex ri) = modifyElem rooms (\r -> r{room' = f $ room' r}) ri
-
-modifyClient :: MRoomsAndClients r c -> (c -> c) -> ClientIndex -> IO ()
-modifyClient (MRoomsAndClients (_, clients)) f (ClientIndex ci) = modifyElem clients (\c -> c{client' = f $ client' c}) ci
-
-moveClientInRooms :: MRoomsAndClients r c -> RoomIndex -> RoomIndex -> ClientIndex -> IO ()
-moveClientInRooms (MRoomsAndClients (rooms, clients)) (RoomIndex riFrom) rt@(RoomIndex riTo) cl@(ClientIndex ci) = do
-    modifyElem rooms (roomRemoveClient cl) riFrom
-    modifyElem rooms (roomAddClient cl) riTo
-    modifyElem clients (\c -> c{clientRoom' = rt}) ci
-
-
-moveClientToLobby :: MRoomsAndClients r c -> ClientIndex -> IO ()
-moveClientToLobby rnc ci = do
-    room <- clientRoomM rnc ci
-    moveClientInRooms rnc room lobbyId ci
-
-
-moveClientToRoom :: MRoomsAndClients r c -> RoomIndex -> ClientIndex -> IO ()
-moveClientToRoom rnc ri ci = moveClientInRooms rnc lobbyId ri ci
-
-
-clientRoomM :: MRoomsAndClients r c -> ClientIndex -> IO RoomIndex
-clientRoomM (MRoomsAndClients (_, clients)) (ClientIndex ci) = liftM clientRoom' (clients `readElem` ci)
-
-client'sM :: MRoomsAndClients r c -> (c -> a) -> ClientIndex -> IO a
-client'sM (MRoomsAndClients (_, clients)) f (ClientIndex ci) = liftM (f . client') (clients `readElem` ci)
-
-room'sM :: MRoomsAndClients r c -> (r -> a) -> RoomIndex -> IO a
-room'sM (MRoomsAndClients (rooms, _)) f (RoomIndex ri) = liftM (f . room') (rooms `readElem` ri)
-
-allClientsM :: MRoomsAndClients r c -> IO [ClientIndex]
-allClientsM (MRoomsAndClients (_, clients)) = liftM (map ClientIndex) $ indicesM clients
-
-clientsM :: MRoomsAndClients r c -> IO [c]
-clientsM (MRoomsAndClients (_, clients)) = indicesM clients >>= mapM (\ci -> liftM client' $ readElem clients ci)
-
-roomClientsIndicesM :: MRoomsAndClients r c -> RoomIndex -> IO [ClientIndex]
-roomClientsIndicesM (MRoomsAndClients (rooms, clients)) (RoomIndex ri) = liftM roomClients' (rooms `readElem` ri)
-
-roomClientsM :: MRoomsAndClients r c -> RoomIndex -> IO [c]
-roomClientsM (MRoomsAndClients (rooms, clients)) (RoomIndex ri) = liftM roomClients' (rooms `readElem` ri) >>= mapM (\(ClientIndex ci) -> liftM client' $ readElem clients ci)
-
-withRoomsAndClients :: MRoomsAndClients r c -> (IRoomsAndClients r c -> a) -> IO a
-withRoomsAndClients (MRoomsAndClients (rooms, clients)) f =
-    withIStore2 rooms clients (\r c -> f $ IRoomsAndClients (r, c))
-
-----------------------------------------
------------ IRoomsAndClients -----------
-
-showRooms :: (Show r, Show c) => IRoomsAndClients r c -> String
-showRooms rnc@(IRoomsAndClients (rooms, clients)) = concatMap showRoom (allRooms rnc)
-    where
-    showRoom r = unlines $ ((show r) ++ ": " ++ (show $ room' $ rooms ! (unRoomIndex r))) : (map showClient (roomClients' $ rooms ! (unRoomIndex r)))
-    showClient c = "    " ++ (show c) ++ ": " ++ (show $ client' $ clients ! (unClientIndex c))
-
-
-allRooms :: IRoomsAndClients r c -> [RoomIndex]
-allRooms (IRoomsAndClients (rooms, _)) = map RoomIndex $ indices rooms
-
-allClients :: IRoomsAndClients r c -> [ClientIndex]
-allClients (IRoomsAndClients (_, clients)) = map ClientIndex $ indices clients
-
-clientRoom :: IRoomsAndClients r c -> ClientIndex -> RoomIndex
-clientRoom (IRoomsAndClients (_, clients)) (ClientIndex ci) = clientRoom' (clients ! ci)
-
-client :: IRoomsAndClients r c -> ClientIndex -> c
-client (IRoomsAndClients (_, clients)) (ClientIndex ci) = client' (clients ! ci)
-
-room :: IRoomsAndClients r c -> RoomIndex -> r
-room (IRoomsAndClients (rooms, _)) (RoomIndex ri) = room' (rooms ! ri)
-
-roomClients :: IRoomsAndClients r c -> RoomIndex -> [ClientIndex]
-roomClients (IRoomsAndClients (rooms, _)) (RoomIndex ri) = roomClients' $ (rooms ! ri)
+module RoomsAndClients(
+    RoomIndex(),
+    ClientIndex(),
+    MRoomsAndClients(),
+    IRoomsAndClients(),
+    newRoomsAndClients,
+    addRoom,
+    addClient,
+    removeRoom,
+    removeClient,
+    modifyRoom,
+    modifyClient,
+    lobbyId,
+    moveClientToLobby,
+    moveClientToRoom,
+    clientRoomM,
+    clientExists,
+    client,
+    room,
+    client'sM,
+    room'sM,
+    allClientsM,
+    clientsM,
+    roomClientsM,
+    roomClientsIndicesM,
+    withRoomsAndClients,
+    allRooms,
+    allClients,
+    clientRoom,
+    showRooms,
+    roomClients
+    ) where
+
+
+import Store
+import Control.Monad
+
+
+data Room r = Room {
+    roomClients' :: [ClientIndex],
+    room' :: r
+    }
+
+
+data Client c = Client {
+    clientRoom' :: RoomIndex,
+    client' :: c
+    }
+
+
+newtype RoomIndex = RoomIndex ElemIndex
+    deriving (Eq)
+newtype ClientIndex = ClientIndex ElemIndex
+    deriving (Eq, Show, Read, Ord)
+
+instance Show RoomIndex where
+    show (RoomIndex i) = 'r' : show i
+
+unRoomIndex :: RoomIndex -> ElemIndex
+unRoomIndex (RoomIndex r) = r
+
+unClientIndex :: ClientIndex -> ElemIndex
+unClientIndex (ClientIndex c) = c
+
+
+newtype MRoomsAndClients r c = MRoomsAndClients (MStore (Room r), MStore (Client c))
+newtype IRoomsAndClients r c = IRoomsAndClients (IStore (Room r), IStore (Client c))
+
+
+lobbyId :: RoomIndex
+lobbyId = RoomIndex firstIndex
+
+
+newRoomsAndClients :: r -> IO (MRoomsAndClients r c)
+newRoomsAndClients r = do
+    rooms <- newStore
+    clients <- newStore
+    let rnc = MRoomsAndClients (rooms, clients)
+    ri <- addRoom rnc r
+    when (ri /= lobbyId) $ error "Empty struct inserts not at firstIndex index"
+    return rnc
+
+
+roomAddClient :: ClientIndex -> Room r -> Room r
+roomAddClient cl room = let cls = cl : roomClients' room; nr = room{roomClients' = cls} in cls `seq` nr `seq` nr
+
+roomRemoveClient :: ClientIndex -> Room r -> Room r
+roomRemoveClient cl room = let cls = filter (/= cl) $ roomClients' room; nr = room{roomClients' = cls} in cls `seq` nr `seq` nr
+
+
+addRoom :: MRoomsAndClients r c -> r -> IO RoomIndex
+addRoom (MRoomsAndClients (rooms, _)) room = do
+    i <- addElem rooms (Room  [] room)
+    return $ RoomIndex i
+
+
+addClient :: MRoomsAndClients r c -> c -> IO ClientIndex
+addClient (MRoomsAndClients (rooms, clients)) client = do
+    i <- addElem clients (Client lobbyId client)
+    modifyElem rooms (roomAddClient (ClientIndex i)) (unRoomIndex lobbyId)
+    return $ ClientIndex i
+
+removeRoom :: MRoomsAndClients r c -> RoomIndex -> IO ()
+removeRoom rnc@(MRoomsAndClients (rooms, _)) room@(RoomIndex ri) 
+    | room == lobbyId = error "Cannot delete lobby"
+    | otherwise = do
+        clIds <- liftM roomClients' $ readElem rooms ri
+        forM_ clIds (moveClientToLobby rnc)
+        removeElem rooms ri
+
+
+removeClient :: MRoomsAndClients r c -> ClientIndex -> IO ()
+removeClient (MRoomsAndClients (rooms, clients)) cl@(ClientIndex ci) = do
+    RoomIndex ri <- liftM clientRoom' $ readElem clients ci
+    modifyElem rooms (roomRemoveClient cl) ri
+    removeElem clients ci
+
+
+modifyRoom :: MRoomsAndClients r c -> (r -> r) -> RoomIndex -> IO ()
+modifyRoom (MRoomsAndClients (rooms, _)) f (RoomIndex ri) = modifyElem rooms (\r -> r{room' = f $ room' r}) ri
+
+modifyClient :: MRoomsAndClients r c -> (c -> c) -> ClientIndex -> IO ()
+modifyClient (MRoomsAndClients (_, clients)) f (ClientIndex ci) = modifyElem clients (\c -> c{client' = f $ client' c}) ci
+
+moveClientInRooms :: MRoomsAndClients r c -> RoomIndex -> RoomIndex -> ClientIndex -> IO ()
+moveClientInRooms (MRoomsAndClients (rooms, clients)) (RoomIndex riFrom) rt@(RoomIndex riTo) cl@(ClientIndex ci) = do
+    modifyElem rooms (roomRemoveClient cl) riFrom
+    modifyElem rooms (roomAddClient cl) riTo
+    modifyElem clients (\c -> c{clientRoom' = rt}) ci
+
+
+moveClientToLobby :: MRoomsAndClients r c -> ClientIndex -> IO ()
+moveClientToLobby rnc ci = do
+    room <- clientRoomM rnc ci
+    moveClientInRooms rnc room lobbyId ci
+
+
+moveClientToRoom :: MRoomsAndClients r c -> RoomIndex -> ClientIndex -> IO ()
+moveClientToRoom rnc ri ci = moveClientInRooms rnc lobbyId ri ci
+
+
+clientExists :: MRoomsAndClients r c -> ClientIndex -> IO Bool
+clientExists (MRoomsAndClients (_, clients)) (ClientIndex ci) = elemExists clients ci
+
+clientRoomM :: MRoomsAndClients r c -> ClientIndex -> IO RoomIndex
+clientRoomM (MRoomsAndClients (_, clients)) (ClientIndex ci) = liftM clientRoom' (clients `readElem` ci)
+
+client'sM :: MRoomsAndClients r c -> (c -> a) -> ClientIndex -> IO a
+client'sM (MRoomsAndClients (_, clients)) f (ClientIndex ci) = liftM (f . client') (clients `readElem` ci)
+
+room'sM :: MRoomsAndClients r c -> (r -> a) -> RoomIndex -> IO a
+room'sM (MRoomsAndClients (rooms, _)) f (RoomIndex ri) = liftM (f . room') (rooms `readElem` ri)
+
+allClientsM :: MRoomsAndClients r c -> IO [ClientIndex]
+allClientsM (MRoomsAndClients (_, clients)) = liftM (map ClientIndex) $ indicesM clients
+
+clientsM :: MRoomsAndClients r c -> IO [c]
+clientsM (MRoomsAndClients (_, clients)) = indicesM clients >>= mapM (\ci -> liftM client' $ readElem clients ci)
+
+roomClientsIndicesM :: MRoomsAndClients r c -> RoomIndex -> IO [ClientIndex]
+roomClientsIndicesM (MRoomsAndClients (rooms, clients)) (RoomIndex ri) = liftM roomClients' (rooms `readElem` ri)
+
+roomClientsM :: MRoomsAndClients r c -> RoomIndex -> IO [c]
+roomClientsM (MRoomsAndClients (rooms, clients)) (RoomIndex ri) = liftM roomClients' (rooms `readElem` ri) >>= mapM (\(ClientIndex ci) -> liftM client' $ readElem clients ci)
+
+withRoomsAndClients :: MRoomsAndClients r c -> (IRoomsAndClients r c -> a) -> IO a
+withRoomsAndClients (MRoomsAndClients (rooms, clients)) f =
+    withIStore2 rooms clients (\r c -> f $ IRoomsAndClients (r, c))
+
+----------------------------------------
+----------- IRoomsAndClients -----------
+
+showRooms :: (Show r, Show c) => IRoomsAndClients r c -> String
+showRooms rnc@(IRoomsAndClients (rooms, clients)) = concatMap showRoom (allRooms rnc)
+    where
+    showRoom r = unlines $ ((show r) ++ ": " ++ (show $ room' $ rooms ! (unRoomIndex r))) : (map showClient (roomClients' $ rooms ! (unRoomIndex r)))
+    showClient c = "    " ++ (show c) ++ ": " ++ (show $ client' $ clients ! (unClientIndex c))
+
+
+allRooms :: IRoomsAndClients r c -> [RoomIndex]
+allRooms (IRoomsAndClients (rooms, _)) = map RoomIndex $ indices rooms
+
+allClients :: IRoomsAndClients r c -> [ClientIndex]
+allClients (IRoomsAndClients (_, clients)) = map ClientIndex $ indices clients
+
+clientRoom :: IRoomsAndClients r c -> ClientIndex -> RoomIndex
+clientRoom (IRoomsAndClients (_, clients)) (ClientIndex ci) = clientRoom' (clients ! ci)
+
+client :: IRoomsAndClients r c -> ClientIndex -> c
+client (IRoomsAndClients (_, clients)) (ClientIndex ci) = client' (clients ! ci)
+
+room :: IRoomsAndClients r c -> RoomIndex -> r
+room (IRoomsAndClients (rooms, _)) (RoomIndex ri) = room' (rooms ! ri)
+
+roomClients :: IRoomsAndClients r c -> RoomIndex -> [ClientIndex]
+roomClients (IRoomsAndClients (rooms, _)) (RoomIndex ri) = roomClients' $ (rooms ! ri)
--- a/gameServer/ServerCore.hs	Thu Aug 26 23:59:18 2010 +0200
+++ b/gameServer/ServerCore.hs	Wed Oct 27 14:02:20 2010 +0200
@@ -7,7 +7,7 @@
 import qualified Data.IntMap as IntMap
 import System.Log.Logger
 import Control.Monad.Reader
-import Control.Monad.State
+import Control.Monad.State.Strict
 import Data.Set as Set
 import qualified Data.ByteString.Char8 as B
 --------------------------------------
@@ -19,7 +19,7 @@
 import ServerState
 
 
-timerLoop :: Int -> Chan CoreMessage -> IO()
+timerLoop :: Int -> Chan CoreMessage -> IO ()
 timerLoop tick messagesChan = threadDelay (30 * 10^6) >> writeChan messagesChan (TimerAction tick) >> timerLoop (tick + 1) messagesChan
 
 
@@ -32,10 +32,11 @@
 
 mainLoop :: StateT ServerState IO ()
 mainLoop = forever $ do
+    get >>= \s -> put $! s
+
     si <- gets serverInfo
     r <- liftIO $ readChan $ coreChan si
 
-    liftIO $ putStrLn $ "Core msg: " ++ show r
     case r of
         Accept ci -> processAction (AddClient ci)
 
@@ -44,7 +45,8 @@
 
             removed <- gets removedClients
             when (not $ ci `Set.member` removed) $ do
-                modify (\as -> as{clientIndex = Just ci})
+                as <- get
+                put $! as{clientIndex = Just ci}
                 reactCmd cmd
 
         Remove ci -> do
@@ -57,13 +59,14 @@
                 --return (serverInfo, rnc)
 
         ClientAccountInfo (ci, info) -> do
-            --should instead check ci exists and has same nick/hostname
-            --removed <- gets removedClients
-            --when (not $ ci `Set.member` removed) $ do
-            --    modify (\as -> as{clientIndex = Just ci})
-            --    processAction (ProcessAccountInfo info)
-            return ()
-            
+            rnc <- gets roomsClients
+            exists <- liftIO $ clientExists rnc ci
+            when (exists) $ do
+                as <- get
+                put $! as{clientIndex = Just ci}
+                processAction (ProcessAccountInfo info)
+                return ()
+
         TimerAction tick ->
                 mapM_ processAction $
                     PingAll : [StatsAction | even tick]
--- a/gameServer/ServerState.hs	Thu Aug 26 23:59:18 2010 +0200
+++ b/gameServer/ServerState.hs	Wed Oct 27 14:02:20 2010 +0200
@@ -8,17 +8,17 @@
     roomClientsS
     ) where
 
-import Control.Monad.State
+import Control.Monad.State.Strict
 import Data.Set as Set
 ----------------------
 import RoomsAndClients
 import CoreTypes
 
 data ServerState = ServerState {
-        clientIndex :: Maybe ClientIndex,
-        serverInfo :: ServerInfo,
-        removedClients :: Set.Set ClientIndex,
-        roomsClients :: MRnC
+        clientIndex :: !(Maybe ClientIndex),
+        serverInfo :: !ServerInfo,
+        removedClients :: !(Set.Set ClientIndex),
+        roomsClients :: !MRnC
     }
 
 
--- a/gameServer/Store.hs	Thu Aug 26 23:59:18 2010 +0200
+++ b/gameServer/Store.hs	Wed Oct 27 14:02:20 2010 +0200
@@ -1,128 +1,145 @@
-module Store(
-    ElemIndex(),
-    MStore(),
-    IStore(),
-    newStore,
-    addElem,
-    removeElem,
-    readElem,
-    writeElem,
-    modifyElem,
-    firstIndex,
-    indicesM,
-    withIStore,
-    withIStore2,
-    (!),
-    indices
-    ) where
-
-import qualified Data.Array.IArray as IA
-import qualified Data.Array.IO as IOA
-import qualified Data.IntSet as IntSet
-import Data.IORef
-import Control.Monad
-
-
-newtype ElemIndex = ElemIndex Int
-    deriving (Eq, Show, Read, Ord)
-newtype MStore e = MStore (IORef (IntSet.IntSet, IntSet.IntSet, IOA.IOArray Int e))
-newtype IStore e = IStore (IntSet.IntSet, IA.Array Int e)
-
-
-firstIndex :: ElemIndex
-firstIndex = ElemIndex 0
-
--- MStore code
-initialSize :: Int
-initialSize = 10
-
-
-growFunc :: Int -> Int
-growFunc a = a * 3 `div` 2
-
-
-newStore :: IO (MStore e)
-newStore = do
-    newar <- IOA.newArray_ (0, initialSize - 1)
-    new <- newIORef (IntSet.empty, IntSet.fromAscList [0..initialSize - 1], newar)
-    return (MStore new)
-
-
-growStore :: MStore e -> IO ()
-growStore (MStore ref) = do
-    (busyElems, freeElems, arr) <- readIORef ref
-    (_, m') <- IOA.getBounds arr
-    let newM' = growFunc (m' + 1) - 1
-    newArr <- IOA.newArray_ (0, newM')
-    sequence_ [IOA.readArray arr i >>= IOA.writeArray newArr i | i <- [0..m']]
-    writeIORef ref (busyElems, freeElems `IntSet.union` (IntSet.fromAscList [m'+1..newM']), newArr)
-
-
-growIfNeeded :: MStore e -> IO ()
-growIfNeeded m@(MStore ref) = do
-    (_, freeElems, _) <- readIORef ref
-    when (IntSet.null freeElems) $ growStore m
-
-
-addElem :: MStore e -> e -> IO ElemIndex
-addElem m@(MStore ref) element = do
-    growIfNeeded m
-    (busyElems, freeElems, arr) <- readIORef ref
-    let (n, freeElems') = IntSet.deleteFindMin freeElems
-    IOA.writeArray arr n element
-    writeIORef ref (IntSet.insert n busyElems, freeElems', arr)
-    return $ ElemIndex n
-
-
-removeElem :: MStore e -> ElemIndex -> IO ()
-removeElem (MStore ref) (ElemIndex n) = do
-    (busyElems, freeElems, arr) <- readIORef ref
-    IOA.writeArray arr n (error $ "Store: no element " ++ show n)
-    writeIORef ref (IntSet.delete n busyElems, IntSet.insert n freeElems, arr)
-
-
-readElem :: MStore e -> ElemIndex -> IO e
-readElem (MStore ref) (ElemIndex n) = readIORef ref >>= \(_, _, arr) -> IOA.readArray arr n
-
-
-writeElem :: MStore e -> ElemIndex -> e -> IO ()
-writeElem (MStore ref) (ElemIndex n) el = readIORef ref >>= \(_, _, arr) -> IOA.writeArray arr n el
-
-
-modifyElem :: MStore e -> (e -> e) -> ElemIndex -> IO ()
-modifyElem (MStore ref) f (ElemIndex n) = do
-    (_, _, arr) <- readIORef ref
-    IOA.readArray arr n >>= (IOA.writeArray arr n) . f
-
-
-indicesM :: MStore e -> IO [ElemIndex]
-indicesM (MStore ref) = do
-    (busy, _, _) <- readIORef ref
-    return $ map ElemIndex $ IntSet.toList busy
-
-
--- A way to use see MStore elements in pure code via IStore
-m2i :: MStore e -> IO (IStore e)
-m2i (MStore ref) = do
-    (a, _, c') <- readIORef ref 
-    c <- IOA.freeze c'
-    return $ IStore (a, c)
-
-
-withIStore :: MStore e -> (IStore e -> a) -> IO a
-withIStore m f = liftM f (m2i m)
-
-
-withIStore2 :: MStore e1 -> MStore e2 -> (IStore e1 -> IStore e2 -> a) -> IO a
-withIStore2 m1 m2 f = do
-    i1 <- m2i m1
-    i2 <- m2i m2
-    return $ f i1 i2
-
-
--- IStore code
-(!) :: IStore e -> ElemIndex -> e
-(!) (IStore (_, arr)) (ElemIndex i) = (IA.!) arr i
-
-indices :: IStore e -> [ElemIndex]
-indices (IStore (busy, _)) = map ElemIndex $ IntSet.toList busy
+module Store(
+    ElemIndex(),
+    MStore(),
+    IStore(),
+    newStore,
+    addElem,
+    removeElem,
+    readElem,
+    writeElem,
+    modifyElem,
+    elemExists,
+    firstIndex,
+    indicesM,
+    withIStore,
+    withIStore2,
+    (!),
+    indices
+    ) where
+
+import qualified Data.Array.IArray as IA
+import qualified Data.Array.IO as IOA
+import qualified Data.IntSet as IntSet
+import Data.IORef
+import Control.Monad
+
+
+newtype ElemIndex = ElemIndex Int
+    deriving (Eq, Show, Read, Ord)
+newtype MStore e = MStore (IORef (IntSet.IntSet, IntSet.IntSet, IOA.IOArray Int e))
+newtype IStore e = IStore (IntSet.IntSet, IA.Array Int e)
+
+
+firstIndex :: ElemIndex
+firstIndex = ElemIndex 0
+
+-- MStore code
+initialSize :: Int
+initialSize = 10
+
+
+growFunc :: Int -> Int
+growFunc a = a * 3 `div` 2
+
+
+newStore :: IO (MStore e)
+newStore = do
+    newar <- IOA.newArray_ (0, initialSize - 1)
+    new <- newIORef (IntSet.empty, IntSet.fromAscList [0..initialSize - 1], newar)
+    return (MStore new)
+
+
+growStore :: MStore e -> IO ()
+growStore (MStore ref) = do
+    (busyElems, freeElems, arr) <- readIORef ref
+    (_, m') <- IOA.getBounds arr
+    let newM' = growFunc (m' + 1) - 1
+    newArr <- IOA.newArray_ (0, newM')
+    sequence_ [IOA.readArray arr i >>= IOA.writeArray newArr i | i <- [0..m']]
+    writeIORef ref (busyElems, freeElems `IntSet.union` (IntSet.fromAscList [m'+1..newM']), newArr)
+
+
+growIfNeeded :: MStore e -> IO ()
+growIfNeeded m@(MStore ref) = do
+    (_, freeElems, _) <- readIORef ref
+    when (IntSet.null freeElems) $ growStore m
+
+
+addElem :: MStore e -> e -> IO ElemIndex
+addElem m@(MStore ref) element = do
+    growIfNeeded m
+    (busyElems, freeElems, arr) <- readIORef ref
+    let (n, freeElems') = IntSet.deleteFindMin freeElems
+    IOA.writeArray arr n element
+    writeIORef ref (IntSet.insert n busyElems, freeElems', arr)
+    return $ ElemIndex n
+
+
+removeElem :: MStore e -> ElemIndex -> IO ()
+removeElem (MStore ref) (ElemIndex n) = do
+    (busyElems, freeElems, arr) <- readIORef ref
+    IOA.writeArray arr n (error $ "Store: no element " ++ show n)
+    writeIORef ref (IntSet.delete n busyElems, IntSet.insert n freeElems, arr)
+
+
+readElem :: MStore e -> ElemIndex -> IO e
+readElem (MStore ref) (ElemIndex n) = readIORef ref >>= \(_, _, arr) -> IOA.readArray arr n
+
+
+writeElem :: MStore e -> ElemIndex -> e -> IO ()
+writeElem (MStore ref) (ElemIndex n) el = readIORef ref >>= \(_, _, arr) -> IOA.writeArray arr n el
+
+
+modifyElem :: MStore e -> (e -> e) -> ElemIndex -> IO ()
+modifyElem (MStore ref) f (ElemIndex n) = do
+    (_, _, arr) <- readIORef ref
+    IOA.readArray arr n >>= IOA.writeArray arr n . f
+
+elemExists :: MStore e -> ElemIndex -> IO Bool
+elemExists (MStore ref) (ElemIndex n) = do
+    (_, free, _) <- readIORef ref
+    return $ n `IntSet.notMember` free
+
+indicesM :: MStore e -> IO [ElemIndex]
+indicesM (MStore ref) = do
+    (busy, _, _) <- readIORef ref
+    return $ map ElemIndex $ IntSet.toList busy
+
+
+-- A way to see MStore elements in pure code via IStore
+m2i :: MStore e -> IO (IStore e)
+m2i (MStore ref) = do
+    (a, _, c') <- readIORef ref
+    c <- IOA.unsafeFreeze c'
+    return $ IStore (a, c)
+
+i2m :: (MStore e) -> IStore e -> IO ()
+i2m (MStore ref) (IStore (_, arr)) = do
+    (b, e, _) <- readIORef ref
+    a <- IOA.unsafeThaw arr
+    writeIORef ref (b, e, a)
+
+withIStore :: MStore e -> (IStore e -> a) -> IO a
+withIStore m f = do
+    i <- m2i m
+    let res = f i
+    res `seq` i2m m i
+    return res
+
+
+withIStore2 :: MStore e1 -> MStore e2 -> (IStore e1 -> IStore e2 -> a) -> IO a
+withIStore2 m1 m2 f = do
+    i1 <- m2i m1
+    i2 <- m2i m2
+    let res = f i1 i2
+    res `seq` i2m m1 i1
+    i2m m2 i2
+    return res
+
+
+-- IStore code
+(!) :: IStore e -> ElemIndex -> e
+(!) (IStore (_, arr)) (ElemIndex i) = (IA.!) arr i
+
+indices :: IStore e -> [ElemIndex]
+indices (IStore (busy, _)) = map ElemIndex $ IntSet.toList busy
--- a/gameServer/hedgewars-server.hs	Thu Aug 26 23:59:18 2010 +0200
+++ b/gameServer/hedgewars-server.hs	Wed Oct 27 14:02:20 2010 +0200
@@ -21,7 +21,7 @@
 setupLoggers :: IO ()
 setupLoggers =
     updateGlobalLogger "Clients"
-        (setLevel DEBUG)
+        (setLevel INFO)
 
 main :: IO ()
 main = withSocketsDo $ do
--- a/gameServer/stresstest.hs	Thu Aug 26 23:59:18 2010 +0200
+++ b/gameServer/stresstest.hs	Wed Oct 27 14:02:20 2010 +0200
@@ -19,7 +19,7 @@
 session3 nick room = ["NICK", nick, "", "PROTO", "32", "", "LIST", "", "JOIN_ROON", room, "", "CHAT", "room 2", "", "QUIT", "quit", ""]
 
 emulateSession sock s = do
-    mapM_ (\x -> hPutStrLn sock x >> hFlush sock >> randomRIO (300000::Int, 590000) >>= threadDelay) s
+    mapM_ (\x -> hPutStrLn sock x >> hFlush sock >> randomRIO (30000::Int, 59000) >>= threadDelay) s
     hFlush sock
     threadDelay 225000
 
@@ -40,7 +40,7 @@
     putStrLn "Finish"
 
 forks = forever $ do
-    delay <- randomRIO (300000::Int, 590000)
+    delay <- randomRIO (30000::Int, 59000)
     threadDelay delay
     forkIO testing
 
--- a/gameServer/stresstest2.hs	Thu Aug 26 23:59:18 2010 +0200
+++ b/gameServer/stresstest2.hs	Wed Oct 27 14:02:20 2010 +0200
@@ -6,7 +6,7 @@
 import System.IO
 import Control.Concurrent
 import Network
-import Control.Exception
+import Control.OldException
 import Control.Monad
 import System.Random
 
@@ -14,22 +14,28 @@
 import System.Posix
 #endif
 
-testing = Control.Exception.handle print $ do
-    delay <- randomRIO (100::Int, 300)
-    threadDelay delay
+session1 nick room = ["NICK", nick, "", "PROTO", "32", ""]
+
+
+
+testing = Control.OldException.handle print $ do
+    putStrLn "Start"
     sock <- connectTo "127.0.0.1" (PortNumber 46631)
-    hClose sock
 
-forks i = do
-    delay <- randomRIO (50::Int, 190)
-    if i `mod` 10 == 0 then putStr (show i) else putStr "."
-    hFlush stdout
-    threadDelay delay
-    forkIO testing
-    forks (i + 1)
+    num1 <- randomRIO (70000::Int, 70100)
+    num2 <- randomRIO (0::Int, 2)
+    num3 <- randomRIO (0::Int, 5)
+    let nick1 = 'n' : show num1
+    let room1 = 'r' : show num2
+    mapM_ (\x -> hPutStrLn sock x >> hFlush sock >> randomRIO (300::Int, 590) >>= threadDelay) $ session1 nick1 room1
+    mapM_ (\x -> hPutStrLn sock x >> hFlush sock) $ concatMap (\x -> ["CHAT_MSG", show x, ""]) [1..]
+    hClose sock
+    putStrLn "Finish"
+
+forks = testing
 
 main = withSocketsDo $ do
 #if !defined(mingw32_HOST_OS)
     installHandler sigPIPE Ignore Nothing;
 #endif
-    forks 1
+    forks
--- a/gameServer/stresstest3.hs	Thu Aug 26 23:59:18 2010 +0200
+++ b/gameServer/stresstest3.hs	Wed Oct 27 14:02:20 2010 +0200
@@ -44,7 +44,7 @@
 
 emulateSession :: StateT SState IO ()
 emulateSession = do
-    n <- io $ randomRIO (100000::Int, 100000)
+    n <- io $ randomRIO (100000::Int, 100100)
     waitPacket "CONNECTED"
     sendPacket ["NICK", "test" ++ (show n)]
     waitPacket "NICK"
@@ -52,6 +52,7 @@
     waitPacket "PROTO"
     b <- waitPacket "LOBBY:JOINED"
     --io $ print b
+    sendPacket ["QUIT", "BYE"]
     return ()
 
 testing = Control.OldException.handle print $ do
@@ -62,7 +63,7 @@
     putStr "-"
     hFlush stdout
 
-forks = forever $ do
+forks = forM_ [1..100] $ const $ do
     delay <- randomRIO (10000::Int, 30000)
     threadDelay delay
     forkIO testing
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hedgewars/ArgParsers.inc	Wed Oct 27 14:02:20 2010 +0200
@@ -0,0 +1,202 @@
+
+procedure internalSetGameTypeLandPreviewFromParameters();
+begin
+    val(ParamStr(2), ipcPort);
+    GameType:= gmtLandPreview;
+    if ParamStr(3) <> 'landpreview' then
+        GameType:= gmtSyntax
+end;
+
+procedure internalStartGameWithParameters();
+var tmp: LongInt;
+begin
+    val(ParamStr(2), cScreenWidth);
+    val(ParamStr(3), cScreenHeight);
+    val(ParamStr(4), cBits);
+    val(ParamStr(5), ipcPort);
+    cFullScreen:= ParamStr(6) = '1';
+    isSoundEnabled:= ParamStr(7) = '1';
+    isMusicEnabled:= ParamStr(8) = '1';
+    val(ParamStr(9), cInitVolume);
+    val(ParamStr(10), cTimerInterval);
+    PathPrefix:= ParamStr(11);
+    cShowFPS:= ParamStr(12) = '1';
+    cAltDamage:= ParamStr(13) = '1';
+    UserNick:= DecodeBase64(ParamStr(14));
+    val(ParamStr(15), cReducedQuality);
+    val(ParamStr(16), tmp);
+    cStereoMode:= TStereoMode(max(0, min(ord(high(TStereoMode)), tmp)));
+    cLocaleFName:= ParamStr(17);
+end;
+
+procedure setVideo(screenWidth: LongInt; screenHeight: LongInt; bitsStr: LongInt);
+begin
+    cScreenWidth:= screenWidth;
+    cScreenHeight:= screenHeight;
+    cBits:= bitsStr
+end;
+
+procedure setVideoWithParameters(screenWidthParam: string; screenHeightParam: string; bitsParam: string);
+var screenWidthAsInt, screenHeightAsInt, bitsStrAsInt: LongInt;
+begin
+    val(screenWidthParam, screenWidthAsInt);
+    val(screenHeightParam, screenHeightAsInt);
+    val(bitsParam, bitsStrAsInt);
+    setVideo(screenWidthAsInt,screenHeightAsInt,bitsStrAsInt)
+end;
+
+procedure setOtherOptions(languageFile: string; fullScreen: boolean);
+begin
+    cLocaleFName:= languageFile;
+    cFullScreen:= fullScreen
+end;
+
+procedure setShowFPS(showFPS: boolean);
+begin
+    cShowFPS:= showFPS
+end;
+
+procedure setOtherOptionsWithParameters(languageFileParam: string; fullScreenParam: string; showFPSParam: string);
+var fullScreen, showFPS: boolean;
+begin
+    fullScreen:= fullScreenParam = '1';
+    showFPS:= showFPSParam = '1';
+    setOtherOptions(languageFileParam,fullScreen);
+    setShowFPS(showFPS)
+end;
+
+procedure setAudio(initialVolume: LongInt; musicEnabled: boolean; soundEnabled: boolean);
+begin
+    cInitVolume:= initialVolume;
+    isMusicEnabled:= musicEnabled;
+    isSoundEnabled:= soundEnabled
+end;
+
+procedure setAudioWithParameters(initialVolumeParam: string; musicEnabledParam: string; soundEnabledParam: string);
+var initialVolumeAsInt: LongInt;
+    musicEnabled, soundEnabled: boolean;
+begin
+    val(initialVolumeParam, initialVolumeAsInt);
+    musicEnabled:= musicEnabledParam = '1';
+    soundEnabled:= soundEnabledParam = '1';
+    setAudio(initialVolumeAsInt,musicEnabled, soundEnabled)
+end;
+
+procedure setMultimediaOptionsWithParameters(screenWidthParam, screenHeightParam, bitsParam: string;
+                                             initialVolumeParam, musicEnabledParam, soundEnabledParam: string;
+                                             languageFileParam, fullScreenParam: string);
+begin
+    setVideoWithParameters(screenWidthParam,screenHeightParam, bitsParam);
+    setAudioWithParameters(initialVolumeParam,musicEnabledParam,soundEnabledParam);
+    setOtherOptions(languageFileParam,fullScreenParam = '1')
+end;
+
+procedure setAltDamageTimerValueAndQuality(altDamage: boolean; timeIterval: LongInt; reducedQuality: boolean);
+begin
+    cAltDamage:= altDamage;
+    cTimerInterval:= timeIterval;
+    if (reducedQuality) then        //HACK
+        cReducedQuality:= $FFFFFFFF xor rqLowRes
+end;
+
+procedure setAllOptionsWithParameters(screenWidthParam:string; screenHeightParam:string; bitsParam:string;
+                                      initialVolumeParam:string; musicEnabledParam:string; soundEnabledParam:string;
+                                      languageFileParam:string; fullScreenParam:string; showFPSParam:string;
+                                      altDamageParam:string; timeItervalParam:string; reducedQualityParam: string);
+var showFPS, altDamage, reducedQuality: boolean;
+    timeIterval: LongInt;
+begin
+    setMultimediaOptionsWithParameters(screenWidthParam,screenHeightParam, bitsParam,
+                                       initialVolumeParam,musicEnabledParam,soundEnabledParam,
+                                       languageFileParam,fullScreenParam);
+    showFPS := showFPSParam = '1';
+    setShowFPS(showFPS);
+
+    altDamage:= altDamageParam = '1';
+    val(timeItervalParam, timeIterval);
+    reducedQuality:= reducedQualityParam = '1';
+    setAltDamageTimerValueAndQuality(altDamage,timeIterval,reducedQuality);
+end;
+
+procedure playReplayFileWithParameters();
+var paramIndex: LongInt;
+    wrongParameter: boolean;
+begin
+    PathPrefix:= ParamStr(1);
+    recordFileName:= ParamStr(2);
+    paramIndex:= 3;
+    wrongParameter:= false;
+    while (paramIndex <= ParamCount) and not wrongParameter do
+        begin
+        if ParamStr(paramIndex) = '--set-video'  then
+//--set-video [screen width] [screen height] [color dept]
+            begin
+            if(ParamCount-paramIndex < 3) then
+                begin
+                wrongParameter:= true;
+                GameType:= gmtSyntax
+                end;
+            setVideoWithParameters(ParamStr(paramIndex+1), ParamStr(paramIndex+2), ParamStr(paramIndex+3));
+            paramIndex:= paramIndex + 4
+            end
+        else
+//--set-audio [volume] [enable music] [enable sounds]
+            if ParamStr(paramIndex) = '--set-audio'  then
+                begin
+                if(ParamCount-paramIndex < 3) then
+                    begin
+                    wrongParameter := true;
+                    GameType:= gmtSyntax
+                    end;
+                setAudioWithParameters(ParamStr(paramIndex+1),ParamStr(paramIndex+2), ParamStr(paramIndex+3));
+                paramIndex:= paramIndex + 4
+                end
+            else
+// --set-other [language file] [full screen] [show FPS]
+                if ParamStr(paramIndex) = '--set-other'  then
+                    begin
+                    if(ParamCount-paramIndex < 3) then
+                        begin
+                        wrongParameter:= true;
+                        GameType:= gmtSyntax
+                        end;
+                    setOtherOptionsWithParameters(ParamStr(paramIndex+1),ParamStr(paramIndex+2), ParamStr(paramIndex+3));
+                    paramIndex:= paramIndex + 4
+                    end
+                else
+//--set-multimedia [screen width] [screen height] [color dept] [volume] [enable music] [enable sounds] [language file] [full screen]
+                    if ParamStr(paramIndex) = '--set-multimedia'  then
+                        begin
+                        if ParamCount-paramIndex < 8  then
+                            begin
+                            wrongParameter:= true;
+                            GameType:= gmtSyntax
+                            end;
+                        setMultimediaOptionsWithParameters(ParamStr(paramIndex+1),ParamStr(paramIndex+2),ParamStr(paramIndex+3),
+                                                           ParamStr(paramIndex+4),ParamStr(paramIndex+5),ParamStr(paramIndex+6),
+                                                           ParamStr(paramIndex+7),ParamStr(paramIndex+8));
+                        paramIndex:= paramIndex + 9
+                        end
+                    else
+//--set-everything [screen width] [screen height] [color dept] [volume] [enable music] [enable sounds] [language file] [full screen] [show FPS] [alternate damage] [timer value] [reduced quality]
+                        if ParamStr(paramIndex) = '--set-everything'  then
+                            begin
+                            if ParamCount-paramIndex < 12  then
+                                begin
+                                wrongParameter:= true;
+                                GameType:= gmtSyntax
+                                end;
+                            setAllOptionsWithParameters(ParamStr(paramIndex+1),ParamStr(paramIndex+2),ParamStr(paramIndex+3),
+                                                        ParamStr(paramIndex+4),ParamStr(paramIndex+5),ParamStr(paramIndex+6),
+                                                        ParamStr(paramIndex+7),ParamStr(paramIndex+8),ParamStr(paramIndex+9),
+                                                        ParamStr(paramIndex+10),ParamStr(paramIndex+11),ParamStr(paramIndex+12));
+                            paramIndex:= paramIndex + 13
+                            end
+                        else
+                            begin
+                            wrongParameter:= true;
+                            GameType:= gmtSyntax
+                            end
+    end
+end;
+
--- a/hedgewars/CCHandlers.inc	Thu Aug 26 23:59:18 2010 +0200
+++ b/hedgewars/CCHandlers.inc	Wed Oct 27 14:02:20 2010 +0200
@@ -162,6 +162,11 @@
     TryDo(Gear^.Health > 0, 'Invalid hedgehog health', true);
     PHedgehog(Gear^.Hedgehog)^.Team:= CurrentTeam;
     if (GameFlags and gfSharedAmmo) <> 0 then CurrentHedgehog^.AmmoStore:= Clan^.ClanIndex
+    else if (GameFlags and gfPerHogAmmo) <> 0 then
+        begin
+        AddAmmoStore;
+        CurrentHedgehog^.AmmoStore:= StoreCnt - 1
+        end
     else CurrentHedgehog^.AmmoStore:= TeamsCount - 1;
     CurrentHedgehog^.Gear:= Gear;
     CurrentHedgehog^.Name:= id;
@@ -290,10 +295,11 @@
 begin
 s:= s; // avoid compiler hint
 if CheckNoTeamOrHH or isPaused then exit;
+if not CurrentTeam^.ExtDriven then SendIPC('L');
+if ReadyTimeLeft > 1 then ReadyTimeLeft:= 1;
 bShowFinger:= false;
-if not CurrentTeam^.ExtDriven then SendIPC('L');
 with CurrentHedgehog^.Gear^ do
-    Message:= Message or gm_Left
+    Message:= Message or gmLeft
 end;
 
 procedure chLeft_m(var s: shortstring);
@@ -302,17 +308,18 @@
 if CheckNoTeamOrHH then exit;
 if not CurrentTeam^.ExtDriven then SendIPC('l');
 with CurrentHedgehog^.Gear^ do
-    Message:= Message and not gm_Left
+    Message:= Message and not gmLeft
 end;
 
 procedure chRight_p(var s: shortstring);
 begin
 s:= s; // avoid compiler hint
 if CheckNoTeamOrHH or isPaused then exit;
+if not CurrentTeam^.ExtDriven then SendIPC('R');
+if ReadyTimeLeft > 1 then ReadyTimeLeft:= 1;
 bShowFinger:= false;
-if not CurrentTeam^.ExtDriven then SendIPC('R');
 with CurrentHedgehog^.Gear^ do
-    Message:= Message or gm_Right
+    Message:= Message or gmRight
 end;
 
 procedure chRight_m(var s: shortstring);
@@ -321,17 +328,18 @@
 if CheckNoTeamOrHH then exit;
 if not CurrentTeam^.ExtDriven then SendIPC('r');
 with CurrentHedgehog^.Gear^ do
-    Message:= Message and not gm_Right
+    Message:= Message and not gmRight
 end;
 
 procedure chUp_p(var s: shortstring);
 begin
 s:= s; // avoid compiler hint
 if CheckNoTeamOrHH or isPaused then exit;
+if not CurrentTeam^.ExtDriven then SendIPC('U');
+if ReadyTimeLeft > 1 then ReadyTimeLeft:= 1;
 bShowFinger:= false;
-if not CurrentTeam^.ExtDriven then SendIPC('U');
 with CurrentHedgehog^.Gear^ do
-    Message:= Message or gm_Up
+    Message:= Message or gmUp
 end;
 
 procedure chUp_m(var s: shortstring);
@@ -340,17 +348,18 @@
 if CheckNoTeamOrHH then exit;
 if not CurrentTeam^.ExtDriven then SendIPC('u');
 with CurrentHedgehog^.Gear^ do
-    Message:= Message and not gm_Up
+    Message:= Message and not gmUp
 end;
 
 procedure chDown_p(var s: shortstring);
 begin
 s:= s; // avoid compiler hint
 if CheckNoTeamOrHH or isPaused then exit;
+if not CurrentTeam^.ExtDriven then SendIPC('D');
+if ReadyTimeLeft > 1 then ReadyTimeLeft:= 1;
 bShowFinger:= false;
-if not CurrentTeam^.ExtDriven then SendIPC('D');
 with CurrentHedgehog^.Gear^ do
-    Message:= Message or gm_Down
+    Message:= Message or gmDown
 end;
 
 procedure chDown_m(var s: shortstring);
@@ -359,17 +368,18 @@
 if CheckNoTeamOrHH then exit;
 if not CurrentTeam^.ExtDriven then SendIPC('d');
 with CurrentHedgehog^.Gear^ do
-    Message:= Message and not gm_Down
+    Message:= Message and not gmDown
 end;
 
 procedure chPrecise_p(var s: shortstring);
 begin
 s:= s; // avoid compiler hint
 if CheckNoTeamOrHH or isPaused then exit;
+if not CurrentTeam^.ExtDriven then SendIPC('Z');
+if ReadyTimeLeft > 1 then ReadyTimeLeft:= 1;
 bShowFinger:= false;
-if not CurrentTeam^.ExtDriven then SendIPC('Z');
 with CurrentHedgehog^.Gear^ do
-    Message:= Message or gm_Precise
+    Message:= Message or gmPrecise
 end;
 
 procedure chPrecise_m(var s: shortstring);
@@ -378,33 +388,36 @@
 if CheckNoTeamOrHH then exit;
 if not CurrentTeam^.ExtDriven then SendIPC('z');
 with CurrentHedgehog^.Gear^ do
-    Message:= Message and not gm_Precise
+    Message:= Message and not gmPrecise
 end;
 
 procedure chLJump(var s: shortstring);
 begin
 s:= s; // avoid compiler hint
 if CheckNoTeamOrHH or isPaused then exit;
+if not CurrentTeam^.ExtDriven then SendIPC('j');
+if ReadyTimeLeft > 1 then ReadyTimeLeft:= 1;
 bShowFinger:= false;
-if not CurrentTeam^.ExtDriven then SendIPC('j');
 with CurrentHedgehog^.Gear^ do
-    Message:= Message or gm_LJump
+    Message:= Message or gmLJump
 end;
 
 procedure chHJump(var s: shortstring);
 begin
 s:= s; // avoid compiler hint
 if CheckNoTeamOrHH or isPaused then exit;
+if not CurrentTeam^.ExtDriven then SendIPC('J');
+if ReadyTimeLeft > 1 then ReadyTimeLeft:= 1;
 bShowFinger:= false;
-if not CurrentTeam^.ExtDriven then SendIPC('J');
 with CurrentHedgehog^.Gear^ do
-    Message:= Message or gm_HJump
+    Message:= Message or gmHJump
 end;
 
 procedure chAttack_p(var s: shortstring);
 begin
 s:= s; // avoid compiler hint
 if CheckNoTeamOrHH or isPaused then exit;
+if ReadyTimeLeft > 1 then ReadyTimeLeft:= 1;
 bShowFinger:= false;
 with CurrentHedgehog^.Gear^ do
     begin
@@ -413,7 +426,7 @@
         begin
         FollowGear:= CurrentHedgehog^.Gear;
         if not CurrentTeam^.ExtDriven then SendIPC('A');
-        Message:= Message or gm_Attack
+        Message:= Message or gmAttack
         end
     end
 end;
@@ -425,8 +438,8 @@
 with CurrentHedgehog^.Gear^ do
     begin
     if not CurrentTeam^.ExtDriven and
-        ((Message and gm_Attack) <> 0) then SendIPC('a');
-    Message:= Message and not gm_Attack
+        ((Message and gmAttack) <> 0) then SendIPC('a');
+    Message:= Message and not gmAttack
     end
 end;
 
@@ -435,8 +448,10 @@
 s:= s; // avoid compiler hint
 if CheckNoTeamOrHH or isPaused then exit;
 if not CurrentTeam^.ExtDriven then SendIPC('S');
+if ReadyTimeLeft > 1 then ReadyTimeLeft:= 1;
+bShowFinger:= false;
 with CurrentHedgehog^.Gear^ do
-    Message:= Message or gm_Switch
+    Message:= Message or gmSwitch
 end;
 
 procedure chNextTurn(var s: shortstring);
@@ -448,9 +463,7 @@
 {$IFDEF DEBUGFILE}
     AddFileLog('Doing SwitchHedgehog: time '+inttostr(GameTicks));
 {$ENDIF}
-{$IFDEF IPHONEOS}
-    clearView();
-{$ENDIF}
+    perfExt_NewTurnBeginning();
 end;
 
 procedure chSay(var s: shortstring);
@@ -477,12 +490,13 @@
 procedure chTimer(var s: shortstring);
 begin
 if (s[0] <> #1) or (s[1] < '1') or (s[1] > '5') or CheckNoTeamOrHH then exit;
-bShowFinger:= false;
 
 if not CurrentTeam^.ExtDriven then SendIPC(s);
+if ReadyTimeLeft > 1 then ReadyTimeLeft:= 1;
+bShowFinger:= false;
 with CurrentHedgehog^.Gear^ do
     begin
-    Message:= Message or gm_Timer;
+    Message:= Message or gmTimer;
     MsgParam:= byte(s[1]) - ord('0')
     end
 end;
@@ -491,13 +505,14 @@
 var slot: LongWord;
 begin
 if (s[0] <> #1) or CheckNoTeamOrHH then exit;
-bShowFinger:= false;
 slot:= byte(s[1]) - 49;
 if slot > cMaxSlotIndex then exit;
 if not CurrentTeam^.ExtDriven then SendIPC(char(byte(s[1]) + 79));
+if ReadyTimeLeft > 1 then ReadyTimeLeft:= 1;
+bShowFinger:= false;
 with CurrentHedgehog^.Gear^ do
     begin
-    Message:= Message or gm_Slot;
+    Message:= Message or gmSlot;
     MsgParam:= slot
     end
 end;
@@ -512,7 +527,7 @@
 
     with CurrentHedgehog^.Gear^ do
     begin
-        Message:= Message or gm_Weapon;
+        Message:= Message or gmWeapon;
         MsgParam:= byte(s[1]);
     end;
 end;
@@ -527,7 +542,7 @@
 
 with CurrentHedgehog^.Gear^ do
     begin
-    Message:= Message or gm_Animate;
+    Message:= Message or gmAnimate;
     MsgParam:= byte(s[1])
     end
 end;
@@ -564,18 +579,11 @@
 
 end;
 
-procedure chNewGrave;
-begin
-if CheckNoTeamOrHH or isPaused then exit;
-
-if not CurrentTeam^.ExtDriven then SendIPC('g');
-
-AddGear(hwRound(CurrentHedgehog^.Gear^.X), hwRound(CurrentHedgehog^.Gear^.Y), gtGrave, 0, _0, _0, 0)
-end;
-
 procedure doPut(putX, putY: LongInt; fromAI: boolean);
 begin
 if CheckNoTeamOrHH or isPaused then exit;
+if ReadyTimeLeft > 1 then ReadyTimeLeft:= 1;
+bShowFinger:= false;
 if not CurrentTeam^.ExtDriven and bShowAmmoMenu then
     begin
     bSelected:= true;
@@ -607,8 +615,8 @@
             end;
         {$IFDEF DEBUGFILE}AddFilelog('put: ' + inttostr(TargetPoint.X) + ', ' + inttostr(TargetPoint.Y));{$ENDIF}
         State:= State and not gstHHChooseTarget;
-        if (Ammo^[CurSlot, CurAmmo].Propz and ammoprop_AttackingPut) <> 0 then
-            Message:= Message or gm_Attack;
+        if (Ammoz[CurAmmoType].Ammo.Propz and ammoprop_AttackingPut) <> 0 then
+            Message:= Message or gmAttack;
         end
     else
         if CurrentTeam^.ExtDriven then
@@ -666,19 +674,22 @@
 procedure chAmmoMenu(var s: shortstring);
 begin
 s:= s; // avoid compiler hint
-if CheckNoTeamOrHH then 
-bShowAmmoMenu:= true
+if CheckNoTeamOrHH then
+    bShowAmmoMenu:= true
 else
-with CurrentTeam^ do
+    begin
+    with CurrentTeam^ do
         with Hedgehogs[CurrHedgehog] do
             begin
             bSelected:= false;
 
             if bShowAmmoMenu then bShowAmmoMenu:= false
             else if ((Gear^.State and (gstAttacking or gstAttacked)) <> 0) or 
-                    ((MultiShootAttacks > 0) and ((Ammo^[CurSlot, CurAmmo].Propz and ammoprop_NoRoundEndHint) = 0)) or
+                    ((MultiShootAttacks > 0) and ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_NoRoundEndHint) = 0)) or
                     ((Gear^.State and gstHHDriven) = 0) then else bShowAmmoMenu:= true
-            end
+            end;
+    if ReadyTimeLeft > 1 then ReadyTimeLeft:= 1
+    end
 end;
 
 procedure chFullScr(var s: shortstring);
@@ -779,6 +790,7 @@
 procedure chPause(var s: shortstring);
 begin
 s:= s; // avoid compiler hint
+if ReadyTimeLeft > 1 then ReadyTimeLeft:= 1;
 if gameType <> gmtNet then
     isPaused:= not isPaused;
 SDL_ShowCursor(ord(isPaused))
@@ -824,13 +836,13 @@
 
 procedure chChat(var s: shortstring);
 begin
-s:= s; // avoid compiler hint
-GameState:= gsChat;
-KeyPressChat(27)
+    s:= s; // avoid compiler hint
+    GameState:= gsChat;
+    KeyPressChat(27)
 end;
 
 procedure chHistory(var s: shortstring);
 begin
-s:= s; // avoid compiler hint
-uChat.showAll:= not uChat.showAll
+    s:= s; // avoid compiler hint
+    uChat.showAll:= not uChat.showAll
 end;
--- a/hedgewars/CMakeLists.txt	Thu Aug 26 23:59:18 2010 +0200
+++ b/hedgewars/CMakeLists.txt	Wed Oct 27 14:02:20 2010 +0200
@@ -31,7 +31,7 @@
 	endif()
 endif()
 
-#SOURCE AND PROGRAMS SECTION 
+#SOURCE AND PROGRAMS SECTION
 set(fpc_tryexe fpc)
 set(hwengine_project ${hedgewars_SOURCE_DIR}/hedgewars/hwengine.pas)
 
@@ -59,6 +59,7 @@
 	uLandTexture.pas
 	uLocale.pas
 	uMisc.pas
+	uMobile.pas
 	uRandom.pas
 	uScript.pas
 	adler32.pas
@@ -74,6 +75,7 @@
 	GearDrawing.inc
 	HHHandlers.inc
 	SinTable.inc
+	ArgParsers.inc
 	options.inc
 	${CMAKE_CURRENT_BINARY_DIR}/config.inc
 	)
--- a/hedgewars/GSHandlers.inc	Thu Aug 26 23:59:18 2010 +0200
+++ b/hedgewars/GSHandlers.inc	Wed Oct 27 14:02:20 2010 +0200
@@ -102,7 +102,9 @@
     skipSpeed, skipAngle, skipDecay: hwFloat;
     i, maxDrops: LongInt;
     particle: PVisualGear;
+    isSubmersible: boolean;
 begin
+    isSubmersible:= (Gear = CurrentHedgehog^.Gear) and (CurAmmoGear <> nil) and (CurAmmoGear^.AmmoType = amJetpack);
     // probably needs tweaking. might need to be in a case statement based upon gear type
     if cWaterLine < hwRound(Gear^.Y) + Gear^.Radius then
     begin
@@ -121,23 +123,35 @@
         end
         else
         begin
-            CheckGearDrowning := true;
-            Gear^.State := gstDrowning;
-            Gear^.RenderTimer := false;
-            if (Gear^.Kind <> gtSniperRifleShot) and (Gear^.Kind <> gtShotgunShot) and (Gear^.Kind <> gtDEagleShot) and (Gear^.Kind <> gtSineGunShot) then
-                Gear^.doStep := @doStepDrowningGear;
-            if Gear^.Kind = gtHedgehog then
+            if not isSubmersible then
             begin
-                Gear^.State := Gear^.State and (not gstHHDriven);
-                AddCaption(Format(GetEventString(eidDrowned), PHedgehog(Gear^.Hedgehog)^.Name),
-                cWhiteColor, capgrpMessage);
+                CheckGearDrowning := true;
+                Gear^.State := gstDrowning;
+                Gear^.RenderTimer := false;
+                if (Gear^.Kind <> gtSniperRifleShot) and (Gear^.Kind <> gtShotgunShot) and (Gear^.Kind <> gtDEagleShot) and (Gear^.Kind <> gtSineGunShot) then
+                    if Gear^.Kind = gtHedgehog then 
+                        begin
+                        if PHedgehog(Gear^.Hedgehog)^.Effects[heResurrectable] then
+                            ResurrectHedgehog(Gear)
+                        else
+                            begin
+                            Gear^.doStep := @doStepDrowningGear;
+                            Gear^.State := Gear^.State and (not gstHHDriven);
+                            AddCaption(Format(GetEventString(eidDrowned), PHedgehog(Gear^.Hedgehog)^.Name), cWhiteColor, capgrpMessage);
+                            end
+                        end
+                    else
+                        Gear^.doStep := @doStepDrowningGear
             end;
-            if hwRound(Gear^.Y) < cWaterLine + 64 + Gear^.Radius then
+            if ((not isSubmersible) and (hwRound(Gear^.Y) < cWaterLine + 64 + Gear^.Radius)) or
+               (isSubmersible and (hwRound(Gear^.Y) < cWaterLine + 2 + Gear^.Radius) and ((CurAmmoGear^.Pos = 0) and (CurAmmoGear^.dY < _0_01))) then
                 // don't play splash if they are already way past the surface
                 PlaySound(sndSplash)
         end;
 
-        if ((cReducedQuality and rqPlainSplash) = 0) and (hwRound(Gear^.Y) < cWaterLine + 64 + Gear^.Radius) then
+        if ((cReducedQuality and rqPlainSplash) = 0) and 
+           (((not isSubmersible) and (hwRound(Gear^.Y) < cWaterLine + 64 + Gear^.Radius)) or
+             (isSubmersible and (hwRound(Gear^.Y) < cWaterLine + 2 + Gear^.Radius) and ((CurAmmoGear^.Pos = 0) and (CurAmmoGear^.dY < _0_01)))) then
         begin
             AddVisualGear(hwRound(Gear^.X), cWaterLine, vgtSplash);
 
@@ -153,9 +167,10 @@
                 end
             end
         end;
+        if isSubmersible and (CurAmmoGear^.Pos = 0) then CurAmmoGear^.Pos := 1000
     end
     else
-        CheckGearDrowning := false
+        CheckGearDrowning := false;
 end;
 
 procedure CheckCollision(Gear: PGear);
@@ -175,6 +190,7 @@
     if _0_4 < Gear^.dY then
     begin
         dmg := ModifyDamage(1 + hwRound((hwAbs(Gear^.dY) - _0_4) * 70), Gear);
+        PlaySound(sndBump);
         if dmg < 1 then exit;
 
         for i:= min(12, (3 + dmg div 10)) downto 0 do
@@ -237,8 +253,9 @@
     tdX, tdY: hwFloat;
     collV, collH: LongInt;
 begin
-    if Gear^.dX > _0_995 then Gear^.dX := _0_995;
-    if Gear^.dY > _0_995 then Gear^.dY := _0_995;
+    // clip velocity at 1.9 - over 1 per pixel, but really shouldn't cause many actual problems.
+    if Gear^.dX.QWordValue > 8160437862 then Gear^.dX.QWordValue:= 8160437862;
+    if Gear^.dY.QWordValue > 8160437862 then Gear^.dY.QWordValue:= 8160437862;
     Gear^.State := Gear^.State and not gstCollision;
     collV := 0;
     collH := 0;
@@ -401,7 +418,12 @@
                     if i mod 2 <> 0 then Fire^.State := Fire^.State or gsttmpFlag;
                     end
                 end;
-            gtGasBomb: doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 20, EXPLAutoSound or EXPLPoisoned);
+            gtGasBomb:
+                begin
+                doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 20, EXPLAutoSound);
+                for i:= 0 to 2 do
+                    AddGear(int64(hwRound(Gear^.X)) - 30 + GetRandom(60), int64(hwRound(Gear^.Y)) - 20 + GetRandom(40), gtPoisonCloud, 0, _0, _0, 0);
+                end;
         end;
     DeleteGear(Gear);
     exit
@@ -688,7 +710,7 @@
         if ((y and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0)
            and (Land[y, x] <> 0) then inc(Gear^.Damage);
         if Gear^.Damage > 5 then
-            if Gear^.Ammo^.AmmoType = amDEagle then
+            if Gear^.AmmoType = amDEagle then
                 AmmoShove(Gear, 7, 20)
         else
             AmmoShove(Gear, Gear^.Timer, 20);
@@ -718,7 +740,7 @@
     begin
         if (Gear^.Kind = gtSniperRifleShot) and ((GameFlags and gfLaserSight) = 0) then
             cLaserSighting := false;
-        if (Gear^.Ammo^.NumPerTurn <= CurrentHedgehog^.MultiShootAttacks) and
+        if (Ammoz[Gear^.AmmoType].Ammo.NumPerTurn <= CurrentHedgehog^.MultiShootAttacks) and
            ((GameFlags and gfArtillery) = 0) then cArtillery := false;
         Gear^.doStep := @doStepShotIdle
     end;
@@ -747,7 +769,7 @@
         if (HHGear^.Angle - 32 >= 0) then dec(HHGear^.Angle,32)
     end;
 
-    if (HHGear^.Message and gm_Attack) <> 0 then
+    if (HHGear^.Message and gmAttack) <> 0 then
     begin
         shell := AddVisualGear(hwRound(Gear^.x), hwRound(Gear^.y), vgtShell);
         if shell <> nil then
@@ -831,12 +853,13 @@
     AllInactive := false;
     HHGear := PHedgehog(Gear^.Hedgehog)^.Gear;
     dec(Gear^.Timer);
-    if (Gear^.Timer = 0)or((Gear^.Message and gm_Destroy) <> 0)or((HHGear^.State and gstHHDriven) =
+    if (Gear^.Timer = 0)or((Gear^.Message and gmDestroy) <> 0)or((HHGear^.State and gstHHDriven) =
        0) then
     begin
         StopSound(Gear^.SoundChannel);
         DeleteGear(Gear);
         AfterAttack;
+        doStepHedgehogMoving(HHGear);  // for gfInfAttack
         exit
     end;
 
@@ -849,6 +872,8 @@
 
     if (Gear^.Timer mod 47) = 0 then
     begin
+        for i:= 0 to 1 do
+            AddVisualGear(hwRound(Gear^.X) - 5 + Random(10), hwRound(Gear^.Y) + 12, vgtDust);
         i := hwRound(Gear^.X) - Gear^.Radius - LongInt(GetRandom(2));
         ei := hwRound(Gear^.X) + Gear^.Radius + LongInt(GetRandom(2));
         while i <= ei do
@@ -882,14 +907,14 @@
     HHGear^.X := Gear^.X;
     HHGear^.Y := Gear^.Y - int2hwFloat(cHHRadius);
 
-    if (Gear^.Message and gm_Attack) <> 0 then
+    if (Gear^.Message and gmAttack) <> 0 then
         if (Gear^.State and gsttmpFlag) <> 0 then Gear^.Timer := 1
     else
     else
         if (Gear^.State and gsttmpFlag) = 0 then Gear^.State := Gear^.State or gsttmpFlag;
-    if ((Gear^.Message and gm_Left) <> 0) then Gear^.dX := - _0_3
+    if ((Gear^.Message and gmLeft) <> 0) then Gear^.dX := - _0_3
     else
-        if ((Gear^.Message and gm_Right) <> 0) then Gear^.dX := _0_3
+        if ((Gear^.Message and gmRight) <> 0) then Gear^.dX := _0_3
     else Gear^.dX := _0;
 end;
 
@@ -956,9 +981,9 @@
     begin
         b := true;
         if Gear^.dX.isNegative then
-            HHGear^.Message := (HHGear^.Message and (gm_Attack or gm_Up or gm_Down)) or gm_Left
+            HHGear^.Message := (HHGear^.Message and (gmAttack or gmUp or gmDown)) or gmLeft
         else
-            HHGear^.Message := (HHGear^.Message and (gm_Attack or gm_Up or gm_Down)) or gm_Right;
+            HHGear^.Message := (HHGear^.Message and (gmAttack or gmUp or gmDown)) or gmRight;
 
         if ((HHGear^.State and gstMoving) = 0) then
         begin
@@ -999,7 +1024,7 @@
         Gear^.dX, Gear^.dY,
         cHHRadius * 5, cHHRadius * 2 + 7);
 
-    if (Gear^.Timer = 0) or ((HHGear^.Message and gm_Attack) <> 0) then
+    if (Gear^.Timer = 0) or ((HHGear^.Message and gmAttack) <> 0) then
     begin
         HHGear^.Message := 0;
         HHGear^.State := HHGear^.State and (not gstNotKickable);
@@ -1049,7 +1074,7 @@
     HHGear^.Y := HHGear^.Y + HHGear^.dY;
     HHGear^.dY := HHGear^.dY + cGravity;
 
-    if (Gear^.Message and gm_Attack) <> 0 then
+    if (Gear^.Message and gmAttack) <> 0 then
     begin
         Gear^.X := HHGear^.X;
         Gear^.Y := HHGear^.Y;
@@ -1077,7 +1102,7 @@
 begin
     with HHGear^ do
     begin
-        Message := Message and not gm_Attack;
+        Message := Message and not gmAttack;
         State := (State or gstMoving) and not gstWinner;
     end;
     DeleteGear(Gear)
@@ -1087,7 +1112,7 @@
 begin
     with HHGear^ do
     begin
-        Message := Message and not gm_Attack;
+        Message := Message and not gmAttack;
         State := State or gstMoving;
     end;
     RopePoints.Count := 0;
@@ -1100,15 +1125,15 @@
 
     if ((HHGear^.State and gstHHDriven) = 0)
        or (CheckGearDrowning(HHGear)) then
-    begin
+        begin
         PlaySound(sndRopeRelease);
         DeleteMe;
         exit
-    end;
-
-    if (Gear^.Message and gm_Left  <> 0) then HHGear^.dX := HHGear^.dX - _0_0002
+        end;
+
+    if (Gear^.Message and gmLeft  <> 0) then HHGear^.dX := HHGear^.dX - _0_0002
     else
-        if (Gear^.Message and gm_Right <> 0) then HHGear^.dX := HHGear^.dX + _0_0002;
+        if (Gear^.Message and gmRight <> 0) then HHGear^.dX := HHGear^.dX + _0_0002;
 
     if not TestCollisionYwithGear(HHGear, 1) then HHGear^.dY := HHGear^.dY + cGravity;
 
@@ -1131,12 +1156,12 @@
     tx := HHGear^.X;
     ty := HHGear^.Y;
 
-    if ((Gear^.Message and gm_Down) <> 0) and (Gear^.Elasticity < Gear^.Friction) then
+    if ((Gear^.Message and gmDown) <> 0) and (Gear^.Elasticity < Gear^.Friction) then
         if not (TestCollisionXwithGear(HHGear, hwSign(ropeDx))
            or TestCollisionYwithGear(HHGear, hwSign(ropeDy))) then
             Gear^.Elasticity := Gear^.Elasticity + _0_3;
 
-    if ((Gear^.Message and gm_Up) <> 0) and (Gear^.Elasticity > _30) then
+    if ((Gear^.Message and gmUp) <> 0) and (Gear^.Elasticity > _30) then
         if not (TestCollisionXwithGear(HHGear, -hwSign(ropeDx))
            or TestCollisionYwithGear(HHGear, -hwSign(ropeDy))) then
             Gear^.Elasticity := Gear^.Elasticity - _0_3;
@@ -1159,30 +1184,29 @@
     ty := mdY * _0_3;
 
     while len > _3 do
-    begin
+        begin
         lx := hwRound(nx);
         ly := hwRound(ny);
-        if ((ly and LAND_HEIGHT_MASK) = 0) and ((lx and LAND_WIDTH_MASK) = 0) and (Land[ly, lx] <> 0
-           ) then
-        begin
+        if ((ly and LAND_HEIGHT_MASK) = 0) and ((lx and LAND_WIDTH_MASK) = 0) and (Land[ly, lx] <> 0) then
+            begin
             ny := _1 / Distance(ropeDx, ropeDy);
             // old rope pos
             nx := ropeDx * ny;
             ny := ropeDy * ny;
 
             with RopePoints.ar[RopePoints.Count] do
-            begin
+                begin
                 X := Gear^.X;
                 Y := Gear^.Y;
                 if RopePoints.Count = 0 then RopePoints.HookAngle := DxDy2Angle(Gear^.dY, Gear^.dX);
                 b := (nx * HHGear^.dY) > (ny * HHGear^.dX);
                 dLen := len
-            end;
+                end;
             with RopePoints.rounded[RopePoints.Count] do
-            begin
+                begin
                 X := hwRound(Gear^.X);
                 Y := hwRound(Gear^.Y);
-            end;
+                end;
 
             Gear^.X := Gear^.X + nx * len;
             Gear^.Y := Gear^.Y + ny * len;
@@ -1192,23 +1216,24 @@
             Gear^.Friction := Gear^.Friction - len;
             haveDivided := true;
             break
-        end;
+            end;
         nx := nx - tx;
         ny := ny - ty;
+        lx := hwRound(nx);
+        ly := hwRound(ny);
         // len := len - _0_3 // should be the same as increase step
         len.QWordValue := len.QWordValue - _0_3.QWordValue;
-    end;
+        end;
 
     if not haveDivided then
         if RopePoints.Count > 0 then // check whether the last dividing point could be removed
-        begin
+            begin
             tx := RopePoints.ar[Pred(RopePoints.Count)].X;
             ty := RopePoints.ar[Pred(RopePoints.Count)].Y;
             mdX := tx - Gear^.X;
             mdY := ty - Gear^.Y;
-            if RopePoints.ar[Pred(RopePoints.Count)].b xor (mdX * (ty - HHGear^.Y) > (tx - HHGear^.X
-               ) * mdY) then
-            begin
+            if RopePoints.ar[Pred(RopePoints.Count)].b xor (mdX * (ty - HHGear^.Y) > (tx - HHGear^.X) * mdY) then
+                begin
                 dec(RopePoints.Count);
                 Gear^.X := RopePoints.ar[RopePoints.Count].X;
                 Gear^.Y := RopePoints.ar[RopePoints.Count].Y;
@@ -1222,48 +1247,48 @@
 
                 HHGear^.X := Gear^.X - mdX * Gear^.Elasticity;
                 HHGear^.Y := Gear^.Y - mdY * Gear^.Elasticity;
-            end
-        end;
+                end
+            end;
 
     haveCollision := false;
     if TestCollisionXwithGear(HHGear, hwSign(HHGear^.dX)) then
-    begin
+        begin
         HHGear^.dX := -_0_6 * HHGear^.dX;
         haveCollision := true
-    end;
+        end;
     if TestCollisionYwithGear(HHGear, hwSign(HHGear^.dY)) then
-    begin
+        begin
         HHGear^.dY := -_0_6 * HHGear^.dY;
         haveCollision := true
-    end;
+        end;
 
     if haveCollision
-       and (Gear^.Message and (gm_Left or gm_Right) <> 0)
-       and (Gear^.Message and (gm_Up or gm_Down) <> 0) then
-    begin
+       and (Gear^.Message and (gmLeft or gmRight) <> 0)
+       and (Gear^.Message and (gmUp or gmDown) <> 0) then
+        begin
         HHGear^.dX := SignAs(hwAbs(HHGear^.dX) + _0_2, HHGear^.dX);
         HHGear^.dY := SignAs(hwAbs(HHGear^.dY) + _0_2, HHGear^.dY)
-    end;
+        end;
 
     len := hwSqr(HHGear^.dX) + hwSqr(HHGear^.dY);
     if len > _0_64 then
-    begin
+        begin
         len := _0_8 / hwSqrt(len);
         HHGear^.dX := HHGear^.dX * len;
         HHGear^.dY := HHGear^.dY * len;
-    end;
-
-
-    if (Gear^.Message and gm_Attack) <> 0 then
+        end;
+
+
+    if (Gear^.Message and gmAttack) <> 0 then
         if (Gear^.State and gsttmpFlag) <> 0 then
             with PHedgehog(Gear^.Hedgehog)^ do
-            begin
+                begin
                 PlaySound(sndRopeRelease);
-                if Ammo^[CurSlot, CurAmmo].AmmoType <> amParachute then
+                if CurAmmoType <> amParachute then
                     WaitCollision
                 else
                     DeleteMe
-            end
+                end
     else
     else
         if (Gear^.State and gsttmpFlag) = 0 then
@@ -1359,14 +1384,14 @@
     end;
 
     if (Gear^.Elasticity > Gear^.Friction)
-       or ((Gear^.Message and gm_Attack) = 0)
+       or ((Gear^.Message and gmAttack) = 0)
        or ((HHGear^.State and gstHHDriven) = 0)
        or (HHGear^.Damage > 0) then
     begin
         with PHedgehog(Gear^.Hedgehog)^.Gear^ do
         begin
             State := State and not gstAttacking;
-            Message := Message and not gm_Attack
+            Message := Message and not gmAttack
         end;
         DeleteGear(Gear)
     end
@@ -1432,6 +1457,49 @@
         dec(Gear^.Timer);
     end
     else // gsttmpFlag = 0
+        if (TurnTimeLeft = 0) or ((GameFlags and gfInfAttack) <> 0) then Gear^.State := Gear^.State or gsttmpFlag;
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepSMine(Gear: PGear);
+begin
+    DeleteCI(Gear);
+    // TODO: do real calculation?
+    if TestCollisionXwithGear(Gear, 2) or TestCollisionYwithGear(Gear, -2) or TestCollisionXwithGear(Gear, -2) or TestCollisionYwithGear(Gear, 2) then
+    begin
+        if (hwAbs(Gear^.dX) > _0) or (hwAbs(Gear^.dY) > _0) then
+            PlaySound(sndRopeAttach);
+        Gear^.dX:= _0;
+        Gear^.dY:= _0;
+    end
+    else
+    begin
+        doStepFallingGear(Gear);
+        AllInactive := false;
+        CalcRotationDirAngle(Gear);
+    end;
+    AddGearCI(Gear);
+
+    if ((Gear^.State and gsttmpFlag) <> 0) and (Gear^.Health <> 0) then
+        if ((Gear^.State and gstAttacking) = 0) then
+        begin
+            if ((GameTicks and $1F) = 0) then
+                if CheckGearNear(Gear, gtHedgehog, 46, 32) <> nil then Gear^.State := Gear^.State or
+                                                                                      gstAttacking
+        end
+    else // gstAttacking <> 0
+    begin
+        AllInactive := false;
+        if (Gear^.Timer and $FF) = 0 then PlaySound(sndMineTick);
+        if Gear^.Timer = 0 then
+        begin
+            doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 30, EXPLAutoSound);
+            DeleteGear(Gear);
+            exit
+        end;
+        dec(Gear^.Timer);
+    end
+    else // gsttmpFlag = 0
         if TurnTimeLeft = 0 then Gear^.State := Gear^.State or gsttmpFlag;
 end;
 
@@ -1542,14 +1610,14 @@
     k := Gear^.Kind;
     exBoom := false;
 
-    if (Gear^.Message and gm_Destroy) > 0 then
+    if (Gear^.Message and gmDestroy) > 0 then
     begin
         DeleteGear(Gear);
         FreeActionsList;
         SetAllToActive;
         // something (hh, mine, etc...) could be on top of the case
         with CurrentHedgehog^ do
-            if Gear <> nil then Gear^.Message := Gear^.Message and not (gm_LJump or gm_HJump);
+            if Gear <> nil then Gear^.Message := Gear^.Message and not (gmLJump or gmHJump);
         exit
     end;
 
@@ -1718,6 +1786,7 @@
 var 
     gX,gY,i: LongInt;
     sticky: Boolean;
+    vgt: PVisualGear;
 begin
     sticky:= (Gear^.State and gsttmpFlag) <> 0;
     if not sticky then AllInactive := false;
@@ -1725,6 +1794,20 @@
     if not TestCollisionYwithGear(Gear, 1) then
     begin
         AllInactive := false;
+
+        if ((GameTicks mod 100) = 0) then
+            begin
+            vgt:= AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtFire);
+            if vgt <> nil then
+                begin
+                vgt^.dx:= 0;
+                vgt^.dy:= 0;
+                vgt^.FrameTicks:= 1800 div (Gear^.Tag mod 3 + 2);
+                vgt^.State:= gstTmpFlag;
+                end;
+            end;
+
+
         if Gear^.dX.QWordValue > _0_01.QWordValue then
             Gear^.dX := Gear^.dX * _0_995;
         Gear^.dY := Gear^.dY + cGravity;
@@ -1828,7 +1911,7 @@
     HHGear: PGear;
 begin
     AllInactive := false;
-    if ((Gear^.Message and gm_Destroy) <> 0) then
+    if ((Gear^.Message and gmDestroy) <> 0) then
     begin
         DeleteGear(Gear);
         AfterAttack;
@@ -1895,7 +1978,7 @@
     if TestCollisionYwithGear(HHGear, 1)
        or ((HHGear^.State and gstHHDriven) = 0)
        or CheckGearDrowning(HHGear)
-       or ((Gear^.Message and gm_Attack) <> 0) then
+       or ((Gear^.Message and gmAttack) <> 0) then
     begin
         with HHGear^ do
         begin
@@ -1913,10 +1996,10 @@
     if not TestCollisionXwithGear(HHGear, hwSign(HHGear^.dX)) then
         HHGear^.X := HHGear^.X + cWindSpeed * 200;
 
-    if (Gear^.Message and gm_Left) <> 0 then HHGear^.X := HHGear^.X - cMaxWindSpeed * 80
-    else if (Gear^.Message and gm_Right) <> 0 then HHGear^.X := HHGear^.X + cMaxWindSpeed * 80;
-    if (Gear^.Message and gm_Up) <> 0 then HHGear^.Y := HHGear^.Y - cGravity * 40
-    else if (Gear^.Message and gm_Down) <> 0 then HHGear^.Y := HHGear^.Y + cGravity * 40;
+    if (Gear^.Message and gmLeft) <> 0 then HHGear^.X := HHGear^.X - cMaxWindSpeed * 80
+    else if (Gear^.Message and gmRight) <> 0 then HHGear^.X := HHGear^.X + cMaxWindSpeed * 80;
+    if (Gear^.Message and gmUp) <> 0 then HHGear^.Y := HHGear^.Y - cGravity * 40
+    else if (Gear^.Message and gmDown) <> 0 then HHGear^.Y := HHGear^.Y + cGravity * 40;
 
     HHGear^.Y := HHGear^.Y + cGravity * 100;
     Gear^.X := HHGear^.X;
@@ -1934,7 +2017,7 @@
     AfterAttack;
 
     HHGear^.State := HHGear^.State and not (gstAttacking or gstAttacked or gstMoving);
-    HHGear^.Message := HHGear^.Message and not gm_Attack;
+    HHGear^.Message := HHGear^.Message and not gmAttack;
 
     Gear^.doStep := @doStepParachuteWork;
 
@@ -2034,7 +2117,7 @@
        sprAmGirder, Gear^.State, true) then
     begin
         PlaySound(sndDenied);
-        HHGear^.Message := HHGear^.Message and not gm_Attack;
+        HHGear^.Message := HHGear^.Message and not gmAttack;
         HHGear^.State := HHGear^.State and not gstAttacking;
         HHGear^.State := HHGear^.State or gstHHChooseTarget;
         isCursorVisible := true;
@@ -2048,7 +2131,7 @@
     end;
 
     HHGear^.State := HHGear^.State and not (gstAttacking or gstAttacked);
-    HHGear^.Message := HHGear^.Message and not gm_Attack;
+    HHGear^.Message := HHGear^.Message and not gmAttack;
     TargetPoint.X := NoPointX
 end;
 
@@ -2093,7 +2176,7 @@
        TargetPoint.Y - SpritesData[sprHHTelepMask].Height div 2,
        sprHHTelepMask, 0, false) then
     begin
-        HHGear^.Message := HHGear^.Message and not gm_Attack;
+        HHGear^.Message := HHGear^.Message and not gmAttack;
         HHGear^.State := HHGear^.State and not gstAttacking;
         HHGear^.State := HHGear^.State or gstHHChooseTarget;
         DeleteGear(Gear);
@@ -2128,10 +2211,10 @@
 begin
     AllInactive := false;
 
-    if ((Gear^.Message and not gm_Switch) <> 0) or (TurnTimeLeft = 0) then
+    if ((Gear^.Message and not gmSwitch) <> 0) or (TurnTimeLeft = 0) then
     begin
         HHGear := PHedgehog(Gear^.Hedgehog)^.Gear;
-        Msg := Gear^.Message and not gm_Switch;
+        Msg := Gear^.Message and not gmSwitch;
         DeleteGear(Gear);
         OnUsedAmmo(PHedgehog(HHGear^.Hedgehog)^);
         ApplyAmmoChanges(PHedgehog(HHGear^.Hedgehog)^);
@@ -2142,11 +2225,11 @@
         exit
     end;
 
-    if (Gear^.Message and gm_Switch) <> 0 then
+    if (Gear^.Message and gmSwitch) <> 0 then
     begin
         HHGear := CurrentHedgehog^.Gear;
-        HHGear^.Message := HHGear^.Message and not gm_Switch;
-        Gear^.Message := Gear^.Message and not gm_Switch;
+        HHGear^.Message := HHGear^.Message and not gmSwitch;
+        Gear^.Message := Gear^.Message and not gmSwitch;
         State := HHGear^.State;
         HHGear^.State := 0;
         HHGear^.Active := false;
@@ -2185,7 +2268,7 @@
     with HHGear^ do
     begin
         State := State and not gstAttacking;
-        Message := Message and not gm_Attack
+        Message := Message and not gmAttack
     end
 end;
 
@@ -2236,6 +2319,9 @@
     HHGear^.State := HHGear^.State or gstNoDamage;
     DeleteCI(HHGear);
 
+    Gear^.X := HHGear^.X;
+    Gear^.Y := HHGear^.Y;
+
     i := 2;
     repeat
         Gear^.X := Gear^.X + HHGear^.dX;
@@ -2417,7 +2503,7 @@
     begin
         Gear^.Tag := 0;
         Gear^.X := Gear^.X + int2hwFloat(xx);
-        if not TestCollisionYwithGear(Gear, yyn) then
+        if not TestCollisionY(Gear, yyn) then
         begin
             Gear^.Y := Gear^.Y + int2hwFloat(yyn);
             NextAngle
@@ -2438,7 +2524,7 @@
     Gear^.Timer := Gear^.Health*10;
     Gear^.PortalCounter:= 0;
     // This is not seconds, but at least it is *some* feedback
-    if (Gear^.Health = 0) or ((Gear^.Message and gm_Attack) <> 0) then
+    if (Gear^.Health = 0) or ((Gear^.Message and gmAttack) <> 0) then
     begin
         FollowGear := Gear;
         Gear^.RenderTimer := false;
@@ -2490,8 +2576,9 @@
     AllInactive := false;
 
     HHGear := PHedgehog(Gear^.Hedgehog)^.Gear;
-    HHGear^.Message := HHGear^.Message and (not gm_Attack);
+    HHGear^.Message := HHGear^.Message and (not gmAttack);
     DeleteCI(HHGear);
+    Gear^.IntersectGear:= nil;
 
     FollowGear := Gear;
 
@@ -2607,7 +2694,7 @@
        or (not TestCollisionYWithGear(Gear, hwSign(Gear^.dY))
        and not TestCollisionXWithGear(Gear, hwSign(Gear^.dX)))
 // CheckLandValue returns true if the type isn't matched
-       or not CheckLandValue(hwRound(Gear^.Y), hwRound(Gear^.X), lfIndestructible) then
+       or not CheckLandValue(hwRound(Gear^.X), hwRound(Gear^.Y), lfIndestructible) then
     begin
         //out of time or exited ground
         StopSound(Gear^.SoundChannel);
@@ -2702,7 +2789,7 @@
     HHGear: PGear;
 begin
     HHGear := PHedgehog(Gear^.Hedgehog)^.Gear;
-    HHGear^.Message := HHGear^.Message and not (gm_Up or gm_Down);
+    HHGear^.Message := HHGear^.Message and not (gmUp or gmDown);
     HHGear^.State := HHGear^.State or gstNotKickable;
     Gear^.doStep := @doStepBallgunWork
 end;
@@ -2740,13 +2827,13 @@
     end
     else
     begin
-        if ((Gear^.Message and gm_Left) <> 0) then
+        if ((Gear^.Message and gmLeft) <> 0) then
         begin
             fChanged := true;
             Gear^.Angle := (Gear^.Angle + (4096 - cAngleSpeed)) mod 4096
         end;
 
-        if ((Gear^.Message and gm_Right) <> 0) then
+        if ((Gear^.Message and gmRight) <> 0) then
         begin
             fChanged := true;
             Gear^.Angle := (Gear^.Angle + cAngleSpeed) mod 4096
@@ -2776,15 +2863,15 @@
         else
             AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace);
 
-        if ((HHGear^.Message and gm_Attack) <> 0) and (Gear^.Health <> 0) then
+        if ((HHGear^.Message and gmAttack) <> 0) and (Gear^.Health <> 0) then
         begin
-            HHGear^.Message := HHGear^.Message and not gm_Attack;
+            HHGear^.Message := HHGear^.Message and not gmAttack;
             AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtAirBomb, 0, Gear^.dX * _0_5, Gear^.dY *
             _0_5, 0);
             dec(Gear^.Health)
         end;
 
-        if ((HHGear^.Message and gm_LJump) <> 0)
+        if ((HHGear^.Message and gmLJump) <> 0)
            and ((Gear^.State and gsttmpFlag) = 0) then
         begin
             Gear^.State := Gear^.State or gsttmpFlag;
@@ -2847,7 +2934,7 @@
 
         AfterAttack;
         CurAmmoGear := nil;
-        TurnTimeLeft := 14 * 125;
+        if (GameFlags and gfInfAttack) = 0 then TurnTimeLeft := 14 * 125;
 
         if (TrainingFlags and tfRCPlane) <> 0 then
             TurnTimeLeft := 0;
@@ -2874,37 +2961,71 @@
 procedure doStepJetpackWork(Gear: PGear);
 var 
     HHGear: PGear;
-    fuel: LongInt;
+    fuel, i: LongInt;
     move: hwFloat;
+    isUnderwater: Boolean;
+    bubble: PVisualGear;
 begin
+    isUnderwater:= cWaterLine < hwRound(Gear^.Y) + Gear^.Radius;
+    if Gear^.Pos > 0 then dec(Gear^.Pos);
     AllInactive := false;
     HHGear := PHedgehog(Gear^.Hedgehog)^.Gear;
     //dec(Gear^.Timer);
-    move := _0_1;
+    move := _0_2;
     fuel := 50;
-(*if (HHGear^.Message and gm_Precise) <> 0 then
+(*if (HHGear^.Message and gmPrecise) <> 0 then
     begin
     move:= _0_02;
     fuel:= 5;
     end;*)
 
-    if (HHGear^.Message and gm_Up) <> 0 then
-    begin
-        if (not HHGear^.dY.isNegative) or (HHGear^.Y > -_256) then
-            HHGear^.dY := HHGear^.dY - move;
-        HHGear^.dY := HHGear^.dY - move;
-        dec(Gear^.Health, fuel);
-        Gear^.MsgParam := Gear^.MsgParam or gm_Up;
-        Gear^.Timer := GameTicks
-    end;
-    if (HHGear^.Message and gm_Left) <> 0 then move.isNegative := true;
-    if (HHGear^.Message and (gm_Left or gm_Right)) <> 0 then
-    begin
-        HHGear^.dX := HHGear^.dX + (move * _0_2);
-        dec(Gear^.Health, fuel div 5);
-        Gear^.MsgParam := Gear^.MsgParam or (HHGear^.Message and (gm_Left or gm_Right));
-        Gear^.Timer := GameTicks
-    end;
+    if Gear^.Health > 0 then
+        begin
+        if (HHGear^.Message and gmUp) <> 0 then
+            begin
+            if (not HHGear^.dY.isNegative) or (HHGear^.Y > -_256) then
+                begin
+                if isUnderwater then
+                    begin
+                    HHGear^.dY := HHGear^.dY - (move * _0_7);
+                    for i:= random(10)+10 downto 0 do
+                        begin
+                        bubble := AddVisualGear(hwRound(HHGear^.X) - 8 + random(16), hwRound(HHGear^.Y) + 16 + random(8), vgtBubble);
+                        if bubble <> nil then bubble^.dY:= random(20)/10+0.1;
+                        end
+                    end
+                else HHGear^.dY := HHGear^.dY - move;
+                end;
+            dec(Gear^.Health, fuel);
+            Gear^.MsgParam := Gear^.MsgParam or gmUp;
+            Gear^.Timer := GameTicks
+            end;
+        move.isNegative := (HHGear^.Message and gmLeft) <> 0;
+        if (HHGear^.Message and (gmLeft or gmRight)) <> 0 then
+            begin
+            HHGear^.dX := HHGear^.dX + (move * _0_1);
+            if isUnderwater then
+                begin
+                for i:= random(5)+5 downto 0 do
+                    begin
+                    bubble := AddVisualGear(hwRound(HHGear^.X)+random(8), hwRound(HHGear^.Y) - 8 + random(16), vgtBubble);
+                    if bubble <> nil then 
+                        begin
+                        bubble^.dX:= (random(10)/10 + 0.02) * -1;
+                        if (move.isNegative) then
+                            begin
+                            bubble^.X := bubble^.X + 28;
+                            bubble^.dX *= -1
+                            end
+                        else bubble^.X := bubble^.X - 28;
+                        end;
+                    end
+                end;
+            dec(Gear^.Health, fuel div 5);
+            Gear^.MsgParam := Gear^.MsgParam or (HHGear^.Message and (gmLeft or gmRight));
+            Gear^.Timer := GameTicks
+            end
+        end;
 
     // erases them all at once :-/
     if (Gear^.Timer <> 0) and (GameTicks - Gear^.Timer > 250) then
@@ -2915,16 +3036,16 @@
 
     if Gear^.Health < 0 then Gear^.Health := 0;
     if (GameTicks and $3F) = 0 then
-    begin
+        begin
         //AddCaption('Fuel: '+inttostr(round(Gear^.Health/20))+'%', cWhiteColor, capgrpAmmostate);
         if Gear^.Tex <> nil then FreeTexture(Gear^.Tex);
         Gear^.Tex := RenderStringTex(trmsg[sidFuel] + ': ' + inttostr(round(Gear^.Health / 20)) +
                      '%', cWhiteColor, fntSmall)
-    end;
-
-    if HHGear^.Message and (gm_Attack or gm_Up or gm_Precise or gm_Left or gm_Right) <> 0 then Gear^
+        end;
+
+    if HHGear^.Message and (gmAttack or gmUp or gmPrecise or gmLeft or gmRight) <> 0 then Gear^
         .State := Gear^.State and not gsttmpFlag;
-    HHGear^.Message := HHGear^.Message and not (gm_Up or gm_Precise or gm_Left or gm_Right);
+    HHGear^.Message := HHGear^.Message and not (gmUp or gmPrecise or gmLeft or gmRight);
     HHGear^.State := HHGear^.State or gstMoving;
 
     Gear^.X := HHGear^.X;
@@ -2934,15 +3055,16 @@
 
     if ((Gear^.State and gsttmpFlag) = 0) or (HHGear^.dY < _0) then doStepHedgehogMoving(HHGear);
 
-    if  (Gear^.Health = 0)
-       or (HHGear^.Damage <> 0)
-       or CheckGearDrowning(HHGear)
-       or (TurnTimeLeft = 0)
-       // allow brief ground touches - to be fair on this, might need another counter
-       or (((GameTicks and $1FF) = 0) and (not HHGear^.dY.isNegative) and TestCollisionYwithGear(
-       HHGear, 1))
-       or ((Gear^.Message and gm_Attack) <> 0) then
-    begin
+    if // (Gear^.Health = 0)
+        (HHGear^.Damage <> 0)
+        //or CheckGearDrowning(HHGear)
+        or (cWaterLine + 512 < hwRound(HHGear^.Y))
+        or (TurnTimeLeft = 0)
+        // allow brief ground touches - to be fair on this, might need another counter
+        or (((GameTicks and $1FF) = 0) and (not HHGear^.dY.isNegative) and TestCollisionYwithGear(
+        HHGear, 1))
+        or ((Gear^.Message and gmAttack) <> 0) then
+        begin
         with HHGear^ do
         begin
             Message := 0;
@@ -2965,6 +3087,7 @@
 var 
     HHGear: PGear;
 begin
+    Gear^.Pos:= 0;
     Gear^.doStep := @doStepJetpackWork;
 
     HHGear := PHedgehog(Gear^.Hedgehog)^.Gear;
@@ -2973,7 +3096,7 @@
     with HHGear^ do
     begin
         State := State and not gstAttacking;
-        Message := Message and not (gm_Attack or gm_Up or gm_Precise or gm_Left or gm_Right);
+        Message := Message and not (gmAttack or gmUp or gmPrecise or gmLeft or gmRight);
         if (dY < _0_1) and (dY > -_0_1) then
         begin
             Gear^.State := Gear^.State or gsttmpFlag;
@@ -3004,12 +3127,12 @@
 begin
     HHGear := CurrentHedgehog^.Gear;
 
-    move := _0_1;
+    move := _0_2;
     fuel := 50;
 
     if Gear^.Pos > 0 then
         dec(Gear^.Pos, 1)
-    else if (HHGear^.Message and (gm_Left or gm_Right or gm_Up)) <> 0 then
+    else if (HHGear^.Message and (gmLeft or gmRight or gmUp)) <> 0 then
              Gear^.Pos := 500;
 
     if HHGear^.dX.isNegative then
@@ -3017,20 +3140,19 @@
     else
         Gear^.Tag := 1;
 
-    if (HHGear^.Message and gm_Up) <> 0 then
+    if (HHGear^.Message and gmUp) <> 0 then
     begin
         if (not HHGear^.dY.isNegative) or (HHGear^.Y > -_256) then
             HHGear^.dY := HHGear^.dY - move;
-        HHGear^.dY := HHGear^.dY - move;
         dec(Gear^.Health, fuel);
-        Gear^.MsgParam := Gear^.MsgParam or gm_Up;
+        Gear^.MsgParam := Gear^.MsgParam or gmUp;
     end;
-    if (HHGear^.Message and gm_Left) <> 0 then move.isNegative := true;
-    if (HHGear^.Message and (gm_Left or gm_Right)) <> 0 then
+    if (HHGear^.Message and gmLeft) <> 0 then move.isNegative := true;
+    if (HHGear^.Message and (gmLeft or gmRight)) <> 0 then
     begin
-        HHGear^.dX := HHGear^.dX + (move * _0_2);
+        HHGear^.dX := HHGear^.dX + (move * _0_1);
         dec(Gear^.Health, fuel div 5);
-        Gear^.MsgParam := Gear^.MsgParam or (HHGear^.Message and (gm_Left or gm_Right));
+        Gear^.MsgParam := Gear^.MsgParam or (HHGear^.Message and (gmLeft or gmRight));
     end;
 
     if Gear^.Health < 0 then Gear^.Health := 0;
@@ -3038,9 +3160,9 @@
         for i:= ((500-Gear^.Health) div 250) downto 0 do
             AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtFeather);
 
-    if (HHGear^.Message and gm_Attack <> 0) then
+    if (HHGear^.Message and gmAttack <> 0) then
     begin
-        HHGear^.Message := HHGear^.Message and not gm_Attack;
+        HHGear^.Message := HHGear^.Message and not gmAttack;
         if Gear^.FlightTime > 0 then
         begin
             AddGear(hwRound(Gear^.X), hwRound(Gear^.Y) + 32, gtEgg, 0, Gear^.dX * _0_5, Gear^.dY, 0)
@@ -3050,9 +3172,9 @@
         end;
     end;
 
-    if HHGear^.Message and (gm_Up or gm_Precise or gm_Left or gm_Right) <> 0 then 
+    if HHGear^.Message and (gmUp or gmPrecise or gmLeft or gmRight) <> 0 then 
         Gear^.State := Gear^.State and not gsttmpFlag;
-    HHGear^.Message := HHGear^.Message and not (gm_Up or gm_Precise or gm_Left or gm_Right);
+    HHGear^.Message := HHGear^.Message and not (gmUp or gmPrecise or gmLeft or gmRight);
     HHGear^.State := HHGear^.State or gstMoving;
 
     Gear^.X := HHGear^.X;
@@ -3069,7 +3191,7 @@
        // allow brief ground touches - to be fair on this, might need another counter
        or (((GameTicks and $1FF) = 0) and (not HHGear^.dY.isNegative) and TestCollisionYwithGear(
        HHGear, 1))
-       or ((Gear^.Message and gm_Attack) <> 0) then
+       or ((Gear^.Message and gmAttack) <> 0) then
     begin
         with HHGear^ do
         begin
@@ -3105,7 +3227,7 @@
             exit
         end;
     HHGear := CurrentHedgehog^.Gear;
-    HHGear^.Message := HHGear^.Message and not (gm_Up or gm_Precise or gm_Left or gm_Right);
+    HHGear^.Message := HHGear^.Message and not (gmUp or gmPrecise or gmLeft or gmRight);
     if abs(hwRound(HHGear^.Y - Gear^.Y)) > 32 then
     begin
         if Gear^.Timer = 0 then
@@ -3158,7 +3280,7 @@
     with HHGear^ do
     begin
         State := State and not gstAttacking;
-        Message := Message and not (gm_Attack or gm_Up or gm_Precise or gm_Left or gm_Right)
+        Message := Message and not (gmAttack or gmUp or gmPrecise or gmLeft or gmRight)
     end
 end;
 
@@ -3176,7 +3298,7 @@
 
     if (Gear^.State and gstCollision) <> 0 then
     begin
-        doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 11, EXPLPoisoned, $C000FFC0);
+        doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 11, EXPLPoisoned, $C0E0FFE0);
         PlaySound(sndEggBreak);
         AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtEgg);
         vg := AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtEgg);
@@ -3196,22 +3318,23 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 procedure doPortalColorSwitch();
-var
-    flags: LongWord;
+var flags: LongWord;
+    CurWeapon: PAmmo;
 begin
     if (CurrentHedgehog <> nil)
        and (CurrentHedgehog^.Gear <> nil)
-       and ((CurrentHedgehog^.Gear^.Message and gm_Switch) <> 0) then
+       and ((CurrentHedgehog^.Gear^.Message and gmSwitch) <> 0) then
         With CurrentHedgehog^ do
-            if (Ammo^[CurSlot, CurAmmo].AmmoType = amPortalGun) then
+            if (CurAmmoType = amPortalGun) then
             begin
-                CurrentHedgehog^.Gear^.Message := CurrentHedgehog^.Gear^.Message and not gm_Switch;
-
-                flags := Ammo^[CurSlot, CurAmmo].Timer and not 2;
+                CurrentHedgehog^.Gear^.Message := CurrentHedgehog^.Gear^.Message and not gmSwitch;
+                
+                CurWeapon:= GetAmmoEntry(CurrentHedgehog^);
+                flags := CurWeapon^.Timer and not 2;
                 if (flags and 1) = 0 then
-                    Ammo^[CurSlot, CurAmmo].Timer := flags or 1
+                    CurWeapon^.Timer := flags or 1
                 else
-                    Ammo^[CurSlot, CurAmmo].Timer := flags and not 1;
+                    CurWeapon^.Timer := flags and not 1;
             end;
 end;
 
@@ -3219,7 +3342,7 @@
 var 
     iterator, conPortal: PGear;
     s, acptRadius, nx, ny, ox, oy, poffs, noffs, pspeed, nspeed: hwFloat;
-    noTrap, hasdxy: Boolean;
+    hasdxy: Boolean;
 begin
     doPortalColorSwitch();
 
@@ -3378,13 +3501,13 @@
 
 {        // breaks (some) loops
         if Distance(iterator^.dX, iterator^.dY) > _0_96 then
-        begin
+            begin
             iterator^.dX := iterator^.dX + signAs(cGravity * getRandom(1000),iterator^.dX);
             iterator^.dY := iterator^.dY + signAs(cGravity * getRandom(1000),iterator^.dY);
             s := _0_96 / Distance(iterator^.dX, iterator^.dY);
             iterator^.dX := s * iterator^.dX;
             iterator^.dY := s * iterator^.dX;
-        end;
+            end;
 }
     end;
 end;
@@ -3397,20 +3520,24 @@
 procedure loadNewPortalBall(oldPortal: PGear; destroyGear: Boolean);
 var 
     flags: LongWord;
+    CurWeapon: PAmmo;
 begin
     if CurrentHedgehog <> nil then
-        With CurrentHedgehog^ do
-            if (Ammo^[CurSlot, CurAmmo].AmmoType = amPortalGun) then
+        with CurrentHedgehog^ do
             begin
-                flags := Ammo^[CurSlot, CurAmmo].Timer;
+            CurWeapon:= GetAmmoEntry(CurrentHedgehog^);
+            if (CurAmmoType = amPortalGun) then
+                begin
+                flags := CurWeapon^.Timer;
 
                 if destroyGear xor ((oldPortal^.Tag and 2) = 0) then
                     flags := flags or 1
                 else
                     flags := flags and not 1;
 
-                Ammo^[CurSlot, CurAmmo].Timer := flags and not 2;
+                CurWeapon^.Timer := flags and not 2;
                 // make the ball visible
+                end
             end;
 
     if destroyGear then oldPortal^.Timer:= 0;
@@ -3472,6 +3599,7 @@
 var 
     iterator: PGear;
     s: hwFloat;
+    CurWeapon: PAmmo;
 begin
     s:= Distance (newPortal^.dX, newPortal^.dY);
 
@@ -3488,6 +3616,7 @@
     if CurrentHedgehog <> nil then
         With CurrentHedgehog^ do
         begin
+            CurWeapon:= GetAmmoEntry(CurrentHedgehog^);
             // let's save the HH's dX's direction so we can decide where the "top" of the portal hole
             newPortal^.Elasticity.isNegative := CurrentHedgehog^.Gear^.dX.isNegative;
             // when doing a backjump the dx is the opposite of the facing direction
@@ -3495,10 +3624,10 @@
                 newPortal^.Elasticity.isNegative := not newPortal^.Elasticity.isNegative;
 
             // make portal gun look unloaded
-            Ammo^[CurSlot, CurAmmo].Timer := Ammo^[CurSlot, CurAmmo].Timer or 2;
+            CurWeapon^.Timer := CurWeapon^.Timer or 2;
 
             // set portal to the currently chosen color
-            if ((Ammo^[CurSlot, CurAmmo].Timer and 1) <> 0) then
+            if ((CurWeapon^.Timer and 1) <> 0) then
                 newPortal^.Tag := newPortal^.Tag or 2;
 
             iterator := GearsList;
@@ -3531,10 +3660,11 @@
 procedure doStepPiano(Gear: PGear);
 var 
     r0, r1: LongInt;
+    odY: hwFloat;
 begin
     AllInactive := false;
     if (CurrentHedgehog <> nil) and (CurrentHedgehog^.Gear <> nil) and ((CurrentHedgehog^.Gear^.
-       Message and gm_Slot) <> 0) then
+       Message and gmSlot) <> 0) then
     begin
         case CurrentHedgehog^.Gear^.MsgParam of 
             0: PlaySound(sndPiano0);
@@ -3547,14 +3677,15 @@
             7: PlaySound(sndPiano7);
             else PlaySound(sndPiano8);
         end;
+        AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtNote);
         CurrentHedgehog^.Gear^.MsgParam := 0;
-        CurrentHedgehog^.Gear^.Message := CurrentHedgehog^.Gear^.Message and not gm_Slot;
+        CurrentHedgehog^.Gear^.Message := CurrentHedgehog^.Gear^.Message and not gmSlot;
     end;
 
-    if ((Gear^.Pos = 3) and ((GameFlags and gfSolidLand) <> 0)) or (Gear^.Pos = 20) then
-        // bounce up to 20 times (3 times on gameflagged solid land) before dropping past landscape
+    if (*((Gear^.Pos = 3) and ((GameFlags and gfSolidLand) <> 0)) or*) (Gear^.Pos = 5) then
+        // bounce up to 10 times (3 times on gameflagged solid land) before dropping past landscape
     begin
-        Gear^.dY := Gear^.dY + cGravity * 3;
+        Gear^.dY := Gear^.dY + cGravity * 2;
         Gear^.Y := Gear^.Y + Gear^.dY;
         CheckGearDrowning(Gear);
         if (Gear^.State and gstDrowning) <> 0 then
@@ -3565,13 +3696,15 @@
                 CurrentHedgehog^.Gear^.Active := true;
                 CurrentHedgehog^.Gear^.X := Gear^.X;
                 CurrentHedgehog^.Gear^.Y := int2hwFloat(cWaterLine+cVisibleWater)+_128;
-                CurrentHedgehog^.Unplaced := false
+                CurrentHedgehog^.Unplaced := false;
+                TurnTimeLeft:= 0
             end;
             ResumeMusic
         end;
         exit
     end;
 
+    odY:= Gear^.dY;
     doStepFallingGear(Gear);
 
     if (Gear^.State and gstDrowning) <> 0 then
@@ -3582,7 +3715,8 @@
             CurrentHedgehog^.Gear^.Active := true;
             CurrentHedgehog^.Gear^.X := Gear^.X;
             CurrentHedgehog^.Gear^.Y := int2hwFloat(cWaterLine+cVisibleWater)+_128;
-            CurrentHedgehog^.Unplaced := false
+            CurrentHedgehog^.Unplaced := false;
+            TurnTimeLeft:= 0
         end;
         ResumeMusic
     end
@@ -3593,7 +3727,9 @@
             doMakeExplosion(hwRound(Gear^.X) - 30 - r0, hwRound(Gear^.Y) + 40, 40 + r1, 0);
             doMakeExplosion(hwRound(Gear^.X) + 30 + r1, hwRound(Gear^.Y) + 40, 40 + r0, 0);
             doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 80 + r0, EXPLAutoSound);
-            Gear^.dY := -_1;
+            for r0:= 0 to 4 do
+                AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtNote);
+            Gear^.dY := odY * -1 + cGravity * 2;
             Gear^.Pos := Gear^.Pos + 1;
         end
     else
@@ -3754,12 +3890,12 @@
     
     if (GameTicks and $FF) = 0 then
     begin
-        if (HHGear^.Message and gm_Right) <> 0 then
+        if (HHGear^.Message and gmRight) <> 0 then
         begin
             if HHGear^.dX.isNegative and (Gear^.Tag < 20) then inc(Gear^.Tag)
             else if Gear^.Tag > 5 then dec(Gear^.Tag);
         end
-        else if (HHGear^.Message and gm_Left) <> 0 then
+        else if (HHGear^.Message and gmLeft) <> 0 then
         begin
             if HHGear^.dX.isNegative and (Gear^.Tag > 5) then dec(Gear^.Tag)
             else if Gear^.Tag < 20 then inc(Gear^.Tag);
@@ -3807,9 +3943,230 @@
     HHGear: PGear;
 begin
     HHGear := PHedgehog(Gear^.Hedgehog)^.Gear;
-    HHGear^.Message := HHGear^.Message and not (gm_Up or gm_Down or gm_Left or gm_Right);
+    HHGear^.Message := HHGear^.Message and not (gmUp or gmDown or gmLeft or gmRight);
     HHGear^.State := HHGear^.State or gstNotKickable;
     Gear^.doStep := @doStepFlamethrowerWork
 end;
 
-
+procedure doStepPoisonCloud(Gear: PGear);
+begin
+    if Gear^.Timer = 0 then
+    begin
+        DeleteGear(Gear);
+        exit
+    end;
+    dec(Gear^.Timer);
+    Gear^.X:= Gear^.X + Gear^.dX;
+    Gear^.Y:= Gear^.Y + Gear^.dY;
+    Gear^.dX := Gear^.dX + cWindSpeed / 4;
+    Gear^.dY := Gear^.dY + cGravity / 100;
+    if (GameTicks mod 250) = 0 then
+        doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 20, EXPLDontDraw or EXPLNoGfx or EXPLNoDamage or EXPLDoNotTouchAny or EXPLPoisoned);
+    AllInactive:= false;
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepHammer(Gear: PGear);
+var HHGear, tmp, tmp2: PGear;
+         t: PGearArray;
+         i: LongInt;
+begin
+HHGear:= PHedgehog(Gear^.Hedgehog)^.Gear;
+HHGear^.State:= HHGear^.State or gstNoDamage;
+DeleteCI(HHGear);
+
+t:= CheckGearsCollision(Gear);
+
+for i:= 5 downto 0 do
+    AddVisualGear(hwRound(Gear^.X) - 5 + Random(10), hwRound(Gear^.Y) + 12, vgtDust);
+
+i:= t^.Count;
+while i > 0 do
+    begin
+    dec(i);
+    tmp:= t^.ar[i];
+    if (tmp^.State and gstNoDamage) = 0 then
+        if (tmp^.Kind = gtHedgehog) then
+            begin
+            //tmp^.State:= tmp^.State or gstFlatened;
+            ApplyDamage(tmp, tmp^.Health div 3, dsUnknown);
+            //DrawTunnel(tmp^.X, tmp^.Y - _1, _0, _0_5, cHHRadius * 6, cHHRadius * 3);
+            tmp2:= AddGear(hwRound(tmp^.X), hwRound(tmp^.Y), gtHammerHit, 0, _0, _0, 0);
+            tmp2^.Hedgehog:= tmp^.Hedgehog;
+            SetAllToActive
+            end
+        else
+            begin
+            end
+    end;
+
+HHGear^.State:= HHGear^.State and not gstNoDamage;
+Gear^.Timer:= 250;
+Gear^.doStep:= @doStepIdle
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepHammerHitWork(Gear: PGear);
+var 
+    i, ei: LongInt;
+    HHGear: PGear;
+begin
+    AllInactive := false;
+    HHGear := PHedgehog(Gear^.Hedgehog)^.Gear;
+    dec(Gear^.Timer);
+    if (HHGear = nil) or (Gear^.Timer = 0) or ((Gear^.Message and gmDestroy) <> 0) then
+    begin
+        DeleteGear(Gear);
+        exit
+    end;
+
+    if (Gear^.Timer mod 5) = 0 then
+    begin
+        AddVisualGear(hwRound(Gear^.X) - 5 + Random(10), hwRound(Gear^.Y) + 12, vgtDust);
+
+        i := hwRound(Gear^.X) - Gear^.Radius - LongInt(GetRandom(2));
+        ei := hwRound(Gear^.X) + Gear^.Radius + LongInt(GetRandom(2));
+        while i <= ei do
+        begin
+            DrawExplosion(i, hwRound(Gear^.Y) + 3, 3);
+            inc(i, 1)
+        end;
+
+        if CheckLandValue(hwRound(Gear^.X + Gear^.dX + SignAs(_6,Gear^.dX)), hwRound(Gear^.Y + _1_9)
+           , lfIndestructible) then
+        begin
+            Gear^.X := Gear^.X + Gear^.dX;
+            Gear^.Y := Gear^.Y + _1_9;
+        end;
+        SetAllHHToActive;
+    end;
+    if TestCollisionYwithGear(Gear, 1) then
+    begin
+        Gear^.dY := _0;
+        SetLittle(HHGear^.dX);
+        HHGear^.dY := _0;
+    end
+    else
+    begin
+        Gear^.dY := Gear^.dY + cGravity;
+        Gear^.Y := Gear^.Y + Gear^.dY;
+        if hwRound(Gear^.Y) > cWaterLine then Gear^.Timer := 1
+    end;
+
+    Gear^.X := Gear^.X + HHGear^.dX;
+    HHGear^.X := Gear^.X;
+    HHGear^.Y := Gear^.Y - int2hwFloat(cHHRadius);
+end;
+
+procedure doStepHammerHit(Gear: PGear);
+var 
+    i, y: LongInt;
+    ar: TRangeArray;
+    HHGear: PGear;
+begin
+    i := 0;
+    HHGear := PHedgehog(Gear^.Hedgehog)^.Gear;
+
+    y := hwRound(Gear^.Y) - cHHRadius * 2;
+    while y < hwRound(Gear^.Y) do
+    begin
+        ar[i].Left := hwRound(Gear^.X) - Gear^.Radius - LongInt(GetRandom(2));
+        ar[i].Right := hwRound(Gear^.X) + Gear^.Radius + LongInt(GetRandom(2));
+        inc(y, 2);
+        inc(i)
+    end;
+
+    DrawHLinesExplosions(@ar, 3, hwRound(Gear^.Y) - cHHRadius * 2, 2, Pred(i));
+    Gear^.dY := HHGear^.dY;
+    DeleteCI(HHGear);
+
+    doStepHammerHitWork(Gear);
+    Gear^.doStep := @doStepHammerHitWork
+end;
+
+
+procedure doStepResurrectorWork(Gear: PGear);
+var
+    graves: TPGearArray;
+    resgear: PGear;
+    hh: PHedgehog;
+    i: LongInt;
+begin
+    AllInactive := false;
+    hh := PHedgehog(Gear^.Hedgehog);
+    RenderHealth(hh^);
+    DrawCentered(hwRound(Gear^.X) + WorldDx, hwRound(Gear^.Y) + WorldDy -
+            cHHRadius - 14 - hh^.HealthTagTex^.h, hh^.HealthTagTex);
+    DrawCircle(hwRound(Gear^.X), hwRound(Gear^.Y), Gear^.Radius, 1.5, 0, 0, $FF,
+            $FF);
+
+    doStepHedgehogMoving(hh^.Gear);
+
+    if ((Gear^.Message and gmUp) <> 0) then begin
+        if (GameTicks and $F) <> 0 then exit;
+    end else begin
+        if (GameTicks and $1FF) <> 0 then exit;
+    end;
+
+    graves := GearsNear(hh^.Gear, gtGrave, Gear^.Radius);
+
+    if Length(graves) = 0 then begin
+        StopSound(Gear^.SoundChannel);
+        Gear^.Timer := 250;
+        Gear^.doStep := @doStepIdle;
+        exit;
+    end;
+
+    if ((Gear^.Message and gmAttack) <> 0) and (hh^.Gear^.Health > 0) then begin
+        i := getRandom(Length(graves));
+        dec(hh^.Gear^.Health);
+        inc(graves[i]^.Health);
+{-for i:= 0 to High(graves) do begin
+            if hh^.Gear^.Health > 0 then begin
+                dec(hh^.Gear^.Health);
+                inc(graves[i]^.Health);
+            end;
+        end; -}
+    end else begin
+        // now really resurrect the hogs with the hp saved in the graves
+        for i:= 0 to High(graves) do begin
+            if graves[i]^.Health > 0 then begin
+                resgear := AddGear(hwRound(graves[i]^.X), hwRound(graves[i]^.Y),
+                        gtHedgehog, gstWait, _0, _0, 0);
+                resgear^.Hedgehog := graves[i]^.Hedgehog;
+                resgear^.Health := graves[i]^.Health;
+                PHedgehog(graves[i]^.Hedgehog)^.Gear := resgear;
+                DeleteGear(graves[i]);
+                RenderHealth(PHedgehog(resgear^.Hedgehog)^);
+                RecountTeamHealth(Phedgehog(resgear^.Hedgehog)^.Team);
+            end;
+        end;
+        StopSound(Gear^.SoundChannel);
+        Gear^.Timer := 250;
+        Gear^.doStep := @doStepIdle;
+    end;
+end;
+
+procedure doStepResurrector(Gear: PGear);
+var
+    graves: TPGearArray;
+    hh: PHedgehog;
+    i: LongInt;
+begin
+    AllInactive := false;
+    hh := PHedgehog(Gear^.Hedgehog);
+    graves := GearsNear(hh^.Gear, gtGrave, Gear^.Radius);
+
+    if Length(graves) > 0 then begin
+        for i:= 0 to High(graves) do begin
+            PHedgehog(graves[i]^.Hedgehog)^.Gear := nil;
+            graves[i]^.Health := 0;
+        end;
+        Gear^.doStep := @doStepResurrectorWork;
+    end else begin
+        StopSound(Gear^.SoundChannel);
+        Gear^.Timer := 250;
+        Gear^.doStep := @doStepIdle;
+    end;
+end;
+
--- a/hedgewars/GearDrawing.inc	Thu Aug 26 23:59:18 2010 +0200
+++ b/hedgewars/GearDrawing.inc	Wed Oct 27 14:02:20 2010 +0200
@@ -6,6 +6,7 @@
     defaultPos, HatVisible: boolean;
     VertexBuffer: array [0..1] of TVertex2f;
     HH: PHedgehog;
+    CurWeapon: PAmmo;
 begin
 HH:= PHedgehog(Gear^.Hedgehog);
 if HH^.Unplaced then exit;
@@ -14,6 +15,9 @@
 if (Gear^.State and gstHHDeath) <> 0 then
     begin
     DrawSprite(sprHHDeath, hwRound(Gear^.X) - 16 + WorldDx, hwRound(Gear^.Y) - 26 + WorldDy, Gear^.Pos);
+    Tint(HH^.Team^.Clan^.Color);
+    DrawSprite(sprHHDeath, hwRound(Gear^.X) - 16 + WorldDx, hwRound(Gear^.Y) - 26 + WorldDy, Gear^.Pos + 8);
+    Tint($FF, $FF, $FF, $FF);
     exit
     end
 else if (Gear^.State and gstHHGone) <> 0 then
@@ -80,8 +84,8 @@
         dy:= -Cos(Gear^.Angle * pi / cMaxAngle);
         if cLaserSighting then
             begin
-            lx:= GetLaunchX(HH^.Ammo^[HH^.CurSlot, HH^.CurAmmo].AmmoType, hwSign(Gear^.dX) * m, Gear^.Angle);
-            ly:= GetLaunchY(HH^.Ammo^[HH^.CurSlot, HH^.CurAmmo].AmmoType, Gear^.Angle);
+            lx:= GetLaunchX(HH^.CurAmmoType, hwSign(Gear^.dX) * m, Gear^.Angle);
+            ly:= GetLaunchY(HH^.CurAmmoType, Gear^.Angle);
 
             // ensure we start outside the hedgehog (he's solid after all)
             while abs(lx * lx + ly * ly) < (Gear^.radius * Gear^.radius) do
@@ -139,8 +143,8 @@
                 end;
             end;
         // draw crosshair
-        cx:= Round(hwRound(Gear^.X) + dx * 80 + GetLaunchX(HH^.Ammo^[HH^.CurSlot, HH^.CurAmmo].AmmoType, hwSign(Gear^.dX) * m, Gear^.Angle));
-        cy:= Round(hwRound(Gear^.Y) + dy * 80 + GetLaunchY(HH^.Ammo^[HH^.CurSlot, HH^.CurAmmo].AmmoType, Gear^.Angle));
+        cx:= Round(hwRound(Gear^.X) + dx * 80 + GetLaunchX(HH^.CurAmmoType, hwSign(Gear^.dX) * m, Gear^.Angle));
+        cy:= Round(hwRound(Gear^.Y) + dy * 80 + GetLaunchY(HH^.CurAmmoType, Gear^.Angle));
         DrawRotatedTex(HH^.Team^.CrosshairTex,
                 12, 12, cx + WorldDx, cy + WorldDy, 0,
                 hwSign(Gear^.dX) * (Gear^.Angle * 180.0) / cMaxAngle);
@@ -195,7 +199,7 @@
                            begin
                            DrawRotatedTextureF(HatTex, 1.0, -1.0, -6.0, sx, sy, 0, i, 32, 32,
                                i*DxDy2Angle(CurAmmoGear^.dY, CurAmmoGear^.dX) + hAngle);
-                           if HatTex^.w > 32 then
+                           if HatTex^.w > 64 then
                                begin
                                Tint(HH^.Team^.Clan^.Color);
                                DrawRotatedTextureF(HatTex, 1.0, -1.0, -6.0, sx, sy, 32, i, 32, 32,
@@ -225,7 +229,7 @@
                             hwSign(Gear^.dX),
                             32,
                             32);
-                        if HatTex^.w > 32 then
+                        if HatTex^.w > 64 then
                             begin
                             Tint(HH^.Team^.Clan^.Color);
                             DrawTextureF(HatTex,
@@ -264,6 +268,20 @@
                         0);
                 defaultPos:= false
                 end;
+            gtHammer: begin
+                DrawRotatedF(sprHammer,
+                        sx,
+                        sy,
+                        1,
+                        hwSign(Gear^.dX),
+                        0);
+                defaultPos:= false
+                end;
+            gtResurrector: begin
+                DrawRotated(sprHandResurrector, hwRound(Gear^.X) + WorldDx,
+                        hwRound(Gear^.Y) + WorldDy, 0, 0); 
+                defaultPos := false;
+            end;
             gtKamikaze: begin
                 if CurAmmoGear^.Pos = 0 then
                     DrawHedgehog(sx, sy,
@@ -332,7 +350,7 @@
     defaultPos:= false
     end else
 
-    if (Gear^.Message and (gm_Left or gm_Right) <> 0) and (not isCursorVisible) then
+    if (Gear^.Message and (gmLeft or gmRight) <> 0) and (not isCursorVisible) then
         begin
         DrawHedgehog(sx, sy,
             hwSign(Gear^.dX),
@@ -372,7 +390,8 @@
             else aangle:= aangle+((240-aangle)*HH^.Timer/10);
             dec(HH^.Timer)
             end;
-        amt:= CurrentHedgehog^.Ammo^[CurrentHedgehog^.CurSlot, CurrentHedgehog^.CurAmmo].AmmoType;
+        amt:= CurrentHedgehog^.CurAmmoType;
+        CurWeapon:= GetAmmoEntry(HH^);
         case amt of
             amBazooka: DrawRotated(sprHandBazooka, hx, hy, hwSign(Gear^.dX), aangle);
             amMortar: DrawRotated(sprHandMortar, hx, hy, hwSign(Gear^.dX), aangle);
@@ -383,10 +402,10 @@
             amShotgun: DrawRotated(sprHandShotgun, hx, hy, hwSign(Gear^.dX), aangle);
             amDEagle: DrawRotated(sprHandDEagle, hx, hy, hwSign(Gear^.dX), aangle);
             amSineGun: DrawRotated(sprHandShotgun, hx, hy, hwSign(Gear^.dX), aangle);
-            amPortalGun: if (HH^.Ammo^[HH^.CurSlot, HH^.CurAmmo].Timer and 2) <> 0 then // Add a new Hedgehog value instead of abusing timer?
+            amPortalGun: if (CurWeapon^.Timer and 2) <> 0 then // Add a new Hedgehog value instead of abusing timer?
                             DrawRotatedF(sprPortalGun, hx, hy, 0, hwSign(Gear^.dX), aangle)
                       else
-                            DrawRotatedF(sprPortalGun, hx, hy, 1+(HH^.Ammo^[HH^.CurSlot, HH^.CurAmmo].Timer and 1), hwSign(Gear^.dX), aangle);
+                            DrawRotatedF(sprPortalGun, hx, hy, 1+(CurWeapon^.Timer and 1), hwSign(Gear^.dX), aangle);
             amSniperRifle: DrawRotatedF(sprSniperRifle, hx, hy, 0, hwSign(Gear^.dX), aangle);
             amBlowTorch: DrawRotated(sprHandBlowTorch, hx, hy, hwSign(Gear^.dX), aangle);
             amCake: DrawRotated(sprHandCake, hx, hy, hwSign(Gear^.dX), aangle);
@@ -398,6 +417,7 @@
             amHellishBomb: DrawRotated(sprHandHellish, hx, hy, hwSign(Gear^.dX), aangle);
             amGasBomb: DrawRotated(sprHandCheese, hx, hy, hwSign(Gear^.dX), aangle);
             amMine: DrawRotated(sprHandMine, hx, hy, hwSign(Gear^.dX), aangle);
+            amSMine: DrawRotated(sprHandSMine, hx, hy, hwSign(Gear^.dX), aangle);
             amSeduction: DrawRotated(sprHandSeduction, hx, hy, hwSign(Gear^.dX), aangle);
             amVampiric: DrawRotatedF(sprHandVamp, hx, hy, (RealTicks div 125) mod 4, hwSign(Gear^.dX), aangle);
             amRCPlane: begin
@@ -416,6 +436,10 @@
                 end;
             amBee: DrawRotatedF(sprHandBee, hx, hy, (RealTicks div 125) mod 4, hwSign(Gear^.dX), aangle);
             amFlamethrower: DrawRotatedF(sprHandFlamethrower, hx, hy, (RealTicks div 125) mod 4, hwSign(Gear^.dX), aangle);
+            amResurrector: begin
+                DrawCircle(hwRound(Gear^.X), hwRound(Gear^.y), 100, 1.5, 0, 0,
+                        $FF, $FF); // I'd rather not like to hardcore 100 here
+            end;
         end;
 
         case amt of
@@ -438,6 +462,12 @@
                         0,
                         hwSign(Gear^.dX),
                         0);
+            amHammer: DrawRotatedF(sprHammer,
+                        sx,
+                        sy,
+                        0,
+                        hwSign(Gear^.dX),
+                        0);
         else
             DrawHedgehog(sx, sy,
                 hwSign(Gear^.dX),
@@ -525,7 +555,7 @@
                 hwSign(Gear^.dX),
                 32,
                 32);
-            if HatTex^.w > 32 then
+            if HatTex^.w > 64 then
                 begin
                 Tint(HH^.Team^.Clan^.Color);
                 DrawTextureF(HatTex,
@@ -549,7 +579,7 @@
                 hwSign(Gear^.dX)*m,
                 32,
                 32);
-            if HatTex^.w > 32 then
+            if HatTex^.w > 64 then
                 begin
                 Tint(HH^.Team^.Clan^.Color);
                 DrawTextureF(HatTex,
@@ -568,7 +598,7 @@
     begin
 (*    if (CurAmmoGear = nil) then
         begin
-        amt:= CurrentHedgehog^.Ammo^[CurrentHedgehog^.CurSlot, CurrentHedgehog^.CurAmmo].AmmoType;
+        amt:= CurrentHedgehog^.CurAmmoType;
         case amt of
             amJetpack: DrawSprite(sprJetpack, sx-32, sy-32, 0);
             end
@@ -578,9 +608,12 @@
         case CurAmmoGear^.Kind of
             gtJetpack: begin
                        DrawSprite(sprJetpack, sx-32, sy-32, 0);
-                       if (CurAmmoGear^.MsgParam and gm_Up) <> 0 then DrawSprite(sprJetpack, sx-32, sy-32, 1);
-                       if (CurAmmoGear^.MsgParam and gm_Left) <> 0 then DrawSprite(sprJetpack, sx-32, sy-32, 2);
-                       if (CurAmmoGear^.MsgParam and gm_Right) <> 0 then DrawSprite(sprJetpack, sx-32, sy-32, 3);
+                       if cWaterLine > hwRound(Gear^.Y) + Gear^.Radius then
+                           begin
+                           if (CurAmmoGear^.MsgParam and gmUp) <> 0 then DrawSprite(sprJetpack, sx-32, sy-28, 1);
+                           if (CurAmmoGear^.MsgParam and gmLeft) <> 0 then DrawSprite(sprJetpack, sx-28, sy-28, 2);
+                           if (CurAmmoGear^.MsgParam and gmRight) <> 0 then DrawSprite(sprJetpack, sx-36, sy-28, 3)
+                           end;
                        if CurAmmoGear^.Tex <> nil then DrawCentered(sx, sy - 40, CurAmmoGear^.Tex);
                        DrawAltWeapon(Gear, sx, sy)
                        end;
@@ -692,6 +725,10 @@
                            DrawRotated(sprMineOff, hwRound(Gear^.X) + WorldDx, hwRound(Gear^.Y) + WorldDy, 0, Gear^.DirAngle)
                        else if Gear^.Health <> 0 then DrawRotated(sprMineOn, hwRound(Gear^.X) + WorldDx, hwRound(Gear^.Y) + WorldDy, 0, Gear^.DirAngle)
                        else DrawRotated(sprMineDead, hwRound(Gear^.X) + WorldDx, hwRound(Gear^.Y) + WorldDy, 0, Gear^.DirAngle);
+           gtSMine: if (((Gear^.State and gstAttacking) = 0)or((Gear^.Timer and $3FF) < 420)) and (Gear^.Health <> 0) then
+                           DrawRotated(sprSMineOff, hwRound(Gear^.X) + WorldDx, hwRound(Gear^.Y) + WorldDy, 0, Gear^.DirAngle)
+                       else if Gear^.Health <> 0 then DrawRotated(sprSMineOn, hwRound(Gear^.X) + WorldDx, hwRound(Gear^.Y) + WorldDy, 0, Gear^.DirAngle)
+                       else DrawRotated(sprMineDead, hwRound(Gear^.X) + WorldDx, hwRound(Gear^.Y) + WorldDy, 0, Gear^.DirAngle);
             gtCase: case Gear^.Pos of
                          posCaseAmmo  : begin
                                         i:= (GameTicks shr 6) mod 64;
@@ -727,7 +764,7 @@
         gtDynamite: DrawSprite2(sprDynamite, hwRound(Gear^.X) - 16 + WorldDx, hwRound(Gear^.Y) - 25 + WorldDy, Gear^.Tag and 1, Gear^.Tag shr 1);
      gtClusterBomb: DrawRotated(sprClusterBomb, hwRound(Gear^.X) + WorldDx, hwRound(Gear^.Y) + WorldDy, 0, Gear^.DirAngle);
          gtCluster: DrawSprite(sprClusterParticle, hwRound(Gear^.X) - 8 + WorldDx, hwRound(Gear^.Y) - 8 + WorldDy, 0);
-           gtFlame: DrawTextureF(SpritesData[sprFlame].Texture, 2 / (Gear^.Tag mod 3 + 2), hwRound(Gear^.X) + WorldDx, hwRound(Gear^.Y) + WorldDy, (GameTicks div 128 + LongWord(Gear^.Tag)) mod 8, 1, 16, 16);
+           gtFlame: DrawTextureF(SpritesData[sprFlame].Texture, 2 / (Gear^.Tag mod 3 + 2), hwRound(Gear^.X) + WorldDx, hwRound(Gear^.Y) + WorldDy, (GameTicks shr 7 + LongWord(Gear^.Tag)) mod 8, 1, 16, 16);
        gtParachute: begin
                     DrawSprite(sprParachute, hwRound(Gear^.X) - 24 + WorldDx, hwRound(Gear^.Y) - 48 + WorldDy, 0);
                     DrawAltWeapon(Gear, hwRound(Gear^.X) + 1 + WorldDx, hwRound(Gear^.Y) - 3 + WorldDy)
@@ -795,6 +832,16 @@
                         end;
                     DrawRotatedTextureF(SpritesData[sprPiano].Texture, 1, 0, 0, hwRound(Gear^.X) + WorldDx, hwRound(Gear^.Y) + WorldDy, 0, 1, 128, 128, 0);
                     end;
+     gtPoisonCloud: begin
+                    if Gear^.Timer < 1020 then
+                        Tint($C0, $C0, $00, Gear^.Timer div 8)
+                    else if Gear^.Timer > 3980 then
+                        Tint($C0, $C0, $00, (5000 - Gear^.Timer) div 8)
+                    else
+                        Tint($C0, $C0, $00, $C0);
+                    DrawRotatedTextureF(SpritesData[sprSmokeWhite].texture, 3, 0, 0, hwRound(Gear^.X) + WorldDx, hwRound(Gear^.Y) + WorldDy, 0, 1, 22, 22, (RealTicks shr 36 + Gear^.UID * 100) mod 360);
+                    Tint($FF, $FF, $FF, $FF)
+                    end;
          end;
       if Gear^.RenderTimer and (Gear^.Tex <> nil) then DrawCentered(hwRound(Gear^.X) + 8 + WorldDx, hwRound(Gear^.Y) + 8 + WorldDy, Gear^.Tex);
       Gear:= Gear^.NextGear
--- a/hedgewars/HHHandlers.inc	Thu Aug 26 23:59:18 2010 +0200
+++ b/hedgewars/HHHandlers.inc	Wed Oct 27 14:02:20 2010 +0200
@@ -40,37 +40,43 @@
     end
 end;
 
+// Shouldn't more of this ammo switching stuff be moved to uAmmos ?
 procedure ChangeAmmo(Gear: PGear);
 var slot, i: Longword;
+    ammoidx: LongInt;
 begin
 slot:= Gear^.MsgParam;
 
 with PHedgehog(Gear^.Hedgehog)^ do
     begin
-    Gear^.Message:= Gear^.Message and not gm_Slot;
+    Gear^.Message:= Gear^.Message and not gmSlot;
+    ammoidx:= 0;
+    while (ammoidx < cMaxSlotAmmoIndex) and (Ammo^[slot, ammoidx].AmmoType <> CurAmmoType) do inc(ammoidx);
 
     if ((Gear^.State and (gstAttacking or gstAttacked)) <> 0) or
-       ((MultiShootAttacks > 0) and ((Ammo^[CurSlot, CurAmmo].Propz and ammoprop_NoRoundEndHint) = 0)) or
+       ((MultiShootAttacks > 0) and (CurAmmoGear <> nil) and ((Ammoz[CurAmmoGear^.AmmoType].Ammo.Propz and ammoprop_NoRoundEndHint) = 0)) or
        ((Gear^.State and gstHHDriven) = 0) then exit;
 
-    if ((Ammo^[CurSlot, CurAmmo].Propz and ammoprop_NoRoundEndHint) <> 0) and (MultiShootAttacks > 0) then OnUsedAmmo(PHedgehog(Gear^.Hedgehog)^);
+    if ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_NoRoundEndHint) <> 0) and (MultiShootAttacks > 0) then OnUsedAmmo(PHedgehog(Gear^.Hedgehog)^);
 
     MultiShootAttacks:= 0;
-    Gear^.Message:= Gear^.Message and not (gm_LJump or gm_HJump);
-
-    if CurSlot = slot then
+    Gear^.Message:= Gear^.Message and not (gmLJump or gmHJump);
+    
+    if Ammoz[CurAmmoType].Slot = slot then
         begin
         i:= 0;
         repeat
-        inc(CurAmmo);
-        if (CurAmmo > cMaxSlotAmmoIndex) then
+        inc(ammoidx);
+        if (ammoidx > cMaxSlotAmmoIndex) then
             begin
-            CurAmmo:= 0;
             inc(i);
-            TryDo(i < 2, 'Engine bug: no ammo in current slot', true)
+            CurAmmoType:= amNothing;
+            ammoidx:= -1;
+            //TryDo(i < 2, 'Engine bug: no ammo in current slot', true)
             end;
-        until (Ammo^[slot, CurAmmo].Count > 0) and (Team^.Clan^.TurnNumber > Ammoz[Ammo^[slot, CurAmmo].AmmoType].SkipTurns)
-        end else
+        until ((Ammo^[slot, ammoidx].Count > 0) and (Team^.Clan^.TurnNumber > Ammoz[Ammo^[slot, ammoidx].AmmoType].SkipTurns)) or (i = 1)
+        end 
+    else
         begin
         i:= 0;
         // check whether there is ammo in slot
@@ -78,31 +84,31 @@
           and ((Ammo^[slot, i].Count = 0)
                or (Team^.Clan^.TurnNumber <= Ammoz[Ammo^[slot, i].AmmoType].SkipTurns)) do inc(i);
 
-        if i <= cMaxSlotAmmoIndex then
-            begin
-            CurSlot:= slot;
-            CurAmmo:= i
-            end
-        end
+        if i <= cMaxSlotAmmoIndex then ammoidx:= i
+        else ammoidx:= -1
+        end;
+        if ammoidx >= 0 then CurAmmoType:= Ammo^[slot, ammoidx].AmmoType;
     end
 end;
 
 procedure HHSetWeapon(Gear: PGear);
 var t: LongInt;
     weap: TAmmoType;
+    Hedgehog: PHedgehog;
 begin
 weap:= TAmmoType(Gear^.MsgParam);
+Hedgehog:= PHedgehog(Gear^.Hedgehog);
 
-if PHedgehog(Gear^.Hedgehog)^.Team^.Clan^.TurnNumber <= Ammoz[weap].SkipTurns then exit; // weapon is not activated yet
+if Hedgehog^.Team^.Clan^.TurnNumber <= Ammoz[weap].SkipTurns then exit; // weapon is not activated yet
 
 Gear^.MsgParam:= Ammoz[weap].Slot;
 
 t:= cMaxSlotAmmoIndex;
 
-Gear^.Message:= Gear^.Message and not gm_Weapon;
+Gear^.Message:= Gear^.Message and not gmWeapon;
 
-with PHedgehog(Gear^.Hedgehog)^ do
-    while (Ammo^[CurSlot, CurAmmo].AmmoType <> weap) and (t >= 0) do
+with Hedgehog^ do
+    while (CurAmmoType <> weap) and (t >= 0) do
         begin
         ChangeAmmo(Gear);
         dec(t)
@@ -112,12 +118,14 @@
 end;
 
 procedure HHSetTimer(Gear: PGear);
+var CurWeapon: PAmmo;
 begin
-Gear^.Message:= Gear^.Message and not gm_Timer;
+Gear^.Message:= Gear^.Message and not gmTimer;
+CurWeapon:= GetAmmoEntry(PHedgehog(Gear^.Hedgehog)^);
 with PHedgehog(Gear^.Hedgehog)^ do
-    if (Ammo^[CurSlot, CurAmmo].Propz and ammoprop_Timerable) <> 0 then
+    if (CurWeapon^.Propz and ammoprop_Timerable) <> 0 then
         begin
-        Ammo^[CurSlot, CurAmmo].Timer:= 1000 * Gear^.MsgParam;
+        CurWeapon^.Timer:= 1000 * Gear^.MsgParam;
         with CurrentTeam^ do
             ApplyAmmoChanges(Hedgehogs[CurrHedgehog]);
         end;
@@ -127,9 +135,10 @@
 procedure Attack(Gear: PGear);
 var xx, yy, lx, ly: hwFloat;
     tmpGear: PVisualGear;
-    tmpGear2: PGear;
+    CurWeapon: PAmmo;
 begin
 bShowFinger:= false;
+CurWeapon:= GetAmmoEntry(PHedgehog(Gear^.Hedgehog)^);
 with Gear^,
      PHedgehog(Gear^.Hedgehog)^ do
      begin
@@ -138,12 +147,12 @@
         (((State and gstMoving) = 0) or
             // Allow attacks while moving on ammo with AltAttack
             ((CurAmmoGear <> nil) and ((Ammoz[CurAmmoGear^.AmmoType].Ammo.Propz and ammoprop_AltAttack) <> 0)) or
-            ((Ammo^[CurSlot, CurAmmo].Propz and ammoprop_AttackInMove) <> 0)) and
-        ((TargetPoint.X <> NoPointX) or ((Ammo^[CurSlot, CurAmmo].Propz and ammoprop_NeedTarget) = 0)) then
+            ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_AttackInMove) <> 0)) and
+        ((TargetPoint.X <> NoPointX) or ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_NeedTarget) = 0)) then
         begin
         State:= State or gstAttacking;
-        if Power = cMaxPower then Message:= Message and not gm_Attack
-        else if (Ammo^[CurSlot, CurAmmo].Propz and ammoprop_Power) = 0 then Message:= Message and not gm_Attack
+        if Power = cMaxPower then Message:= Message and not gmAttack
+        else if (Ammoz[CurAmmoType].Ammo.Propz and ammoprop_Power) = 0 then Message:= Message and not gmAttack
         else begin
              if Power = 0 then
                 begin
@@ -152,9 +161,9 @@
                 end;
              inc(Power)
              end;
-        if ((Message and gm_Attack) <> 0) then exit;
+        if ((Message and gmAttack) <> 0) then exit;
 
-        if (Ammo^[CurSlot, CurAmmo].Propz and ammoprop_Power) <> 0 then
+        if (Ammoz[CurAmmoType].Ammo.Propz and ammoprop_Power) <> 0 then
            begin
            StopSound(sndThrowPowerUp);
            PlaySound(sndThrowRelease);
@@ -163,17 +172,17 @@
         xx:= SignAs(AngleSin(Angle), dX);
         yy:= -AngleCos(Angle);
 
-        lx:= X + int2hwfloat(round(GetLaunchX(Ammo^[CurSlot, CurAmmo].AmmoType, hwSign(dX), Angle)));
-        ly:= Y + int2hwfloat(round(GetLaunchY(Ammo^[CurSlot, CurAmmo].AmmoType, Angle)));
+        lx:= X + int2hwfloat(round(GetLaunchX(CurAmmoType, hwSign(dX), Angle)));
+        ly:= Y + int2hwfloat(round(GetLaunchY(CurAmmoType, Angle)));
 
         if ((Gear^.State and gstHHHJump) <> 0) and (not cArtillery) then xx:= - xx;
-        if Ammo^[CurSlot, CurAmmo].AttackVoice <> sndNone then
-           PlaySound(Ammo^[CurSlot, CurAmmo].AttackVoice, CurrentTeam^.voicepack);
-             case Ammo^[CurSlot, CurAmmo].AmmoType of
-                      amGrenade: FollowGear:= AddGear(hwRound(lx), hwRound(ly), gtAmmo_Bomb,    0, xx*Power/cPowerDivisor, yy*Power/cPowerDivisor, Ammo^[CurSlot, CurAmmo].Timer);
+        if Ammoz[CurAmmoType].Ammo.AttackVoice <> sndNone then
+           PlaySound(Ammoz[CurAmmoType].Ammo.AttackVoice, CurrentTeam^.voicepack);
+             case CurAmmoType of
+                      amGrenade: FollowGear:= AddGear(hwRound(lx), hwRound(ly), gtAmmo_Bomb,    0, xx*Power/cPowerDivisor, yy*Power/cPowerDivisor, CurWeapon^.Timer);
                       amMolotov: FollowGear:= AddGear(hwRound(lx), hwRound(ly), gtMolotov,      0, xx*Power/cPowerDivisor, yy*Power/cPowerDivisor, 0);
-                  amClusterBomb: FollowGear:= AddGear(hwRound(lx), hwRound(ly), gtClusterBomb,  0, xx*Power/cPowerDivisor, yy*Power/cPowerDivisor, Ammo^[CurSlot, CurAmmo].Timer);
-                      amGasBomb: FollowGear:= AddGear(hwRound(lx), hwRound(ly), gtGasBomb,    0, xx*Power/cPowerDivisor, yy*Power/cPowerDivisor, Ammo^[CurSlot, CurAmmo].Timer);
+                  amClusterBomb: FollowGear:= AddGear(hwRound(lx), hwRound(ly), gtClusterBomb,  0, xx*Power/cPowerDivisor, yy*Power/cPowerDivisor, CurWeapon^.Timer);
+                      amGasBomb: FollowGear:= AddGear(hwRound(lx), hwRound(ly), gtGasBomb,    0, xx*Power/cPowerDivisor, yy*Power/cPowerDivisor, CurWeapon^.Timer);
                       amBazooka: FollowGear:= AddGear(hwRound(lx), hwRound(ly), gtAmmo_Grenade, 0, xx*Power/cPowerDivisor, yy*Power/cPowerDivisor, 0);
                           amBee: FollowGear:= AddGear(hwRound(lx), hwRound(ly), gtBee,          0, xx*Power/cPowerDivisor, yy*Power/cPowerDivisor, 0);
                       amShotgun: begin
@@ -184,6 +193,7 @@
                          amSkip: ParseCommand('/skip', true);
                          amRope: CurAmmoGear:= AddGear(hwRound(lx), hwRound(ly), gtRope, 0, xx, yy, 0);
                          amMine: AddGear(hwRound(lx) + hwSign(dX) * 7, hwRound(ly), gtMine, gstWait, SignAs(_0_02, dX), _0, 3000);
+                        amSMine: FollowGear:= AddGear(hwRound(lx), hwRound(ly), gtSMine,    0, xx*Power/cPowerDivisor, yy*Power/cPowerDivisor, 0);
                        amDEagle: CurAmmoGear:= AddGear(hwRound(lx + xx * cHHRadius), hwRound(ly + yy * cHHRadius), gtDEagleShot, 0, xx * _0_5, yy * _0_5, 0);
                       amSineGun: CurAmmoGear:= AddGear(hwRound(lx + xx * cHHRadius), hwRound(ly + yy * cHHRadius), gtSineGunShot, 0, xx * _0_5, yy * _0_5, 0);
                     amPortalGun: AddGear(hwRound(lx + xx * cHHRadius), hwRound(ly + yy * cHHRadius), gtPortal, 0, xx * _0_6, yy * _0_6, 0);
@@ -197,17 +207,24 @@
                                  CurAmmoGear:= AddGear(hwRound(lx) + hwSign(dX) * 10, hwRound(ly), gtWhip, 0, SignAs(_1, dX), - _0_8, 0);
                                  PlaySound(sndWhipCrack)
                                  end;
+                       amHammer: begin
+                                 CurAmmoGear:= AddGear(hwRound(lx) + hwSign(dX) * 10, hwRound(ly), gtHammer, 0, SignAs(_1, dX), - _0_8, 0);
+                                 PlaySound(sndWhack)
+                                 end;
                   amBaseballBat: begin
                                  CurAmmoGear:= AddGear(hwRound(lx) + hwSign(dX) * 10, hwRound(ly), gtShover, gsttmpFlag, xx * _0_5, yy * _0_5, 0);
                                  PlaySound(sndBaseballBat) // TODO: Only play if something is hit?
                                  end;
-                    amParachute: CurAmmoGear:= AddGear(hwRound(lx), hwRound(ly), gtParachute, 0, _0, _0, 0);
-                    // we save Ammo^[CurSlot, CurAmmo].Pos (in this case: cursor direction) by using it as (otherwise irrelevant) X value of the new gear.
-                    amAirAttack: AddGear(Ammo^[CurSlot, CurAmmo].Pos, 0, gtAirAttack, 0, _0, _0, 0);
-                   amMineStrike: AddGear(Ammo^[CurSlot, CurAmmo].Pos, 0, gtAirAttack, 1, _0, _0, 0);
+                    amParachute: begin
+                                 CurAmmoGear:= AddGear(hwRound(lx), hwRound(ly), gtParachute, 0, _0, _0, 0);
+                                 PlaySound(sndParachute)
+                                 end;
+                    // we save CurWeapon^.Pos (in this case: cursor direction) by using it as (otherwise irrelevant) X value of the new gear.
+                    amAirAttack: AddGear(CurWeapon^.Pos, 0, gtAirAttack, 0, _0, _0, 0);
+                   amMineStrike: AddGear(CurWeapon^.Pos, 0, gtAirAttack, 1, _0, _0, 0);
                     amBlowTorch: CurAmmoGear:= AddGear(hwRound(lx), hwRound(ly), gtBlowTorch, 0, SignAs(_0_5, dX), _0, 0);
-                       amGirder: CurAmmoGear:= AddGear(0, 0, gtGirder, Ammo^[CurSlot, CurAmmo].Pos, _0, _0, 0);
-                     amTeleport: CurAmmoGear:= AddGear(Ammo^[CurSlot, CurAmmo].Pos, 0, gtTeleport, 0, _0, _0, 0);
+                       amGirder: CurAmmoGear:= AddGear(0, 0, gtGirder, CurWeapon^.Pos, _0, _0, 0);
+                     amTeleport: CurAmmoGear:= AddGear(CurWeapon^.Pos, 0, gtTeleport, 0, _0, _0, 0);
                        amSwitch: CurAmmoGear:= AddGear(hwRound(lx), hwRound(ly), gtSwitcher, 0, _0, _0, 0);
                        amMortar: begin
                                  playSound(sndMortar);
@@ -220,9 +237,9 @@
                        amKamikaze: CurAmmoGear:= AddGear(hwRound(lx), hwRound(ly), gtKamikaze, 0, xx * _0_5, yy * _0_5, 0);
                          amCake: CurAmmoGear:= AddGear(hwRound(lx) + hwSign(dX) * 3, hwRound(ly), gtCake, 0, xx, _0, 0);
                     amSeduction: CurAmmoGear:= AddGear(hwRound(lx + xx * cHHRadius * 2), hwRound(ly + yy * cHHRadius * 2), gtSeduction, 0, xx * _0_4, yy * _0_4, 0);
-                   amWatermelon: FollowGear:= AddGear(hwRound(lx), hwRound(ly), gtWatermelon,  0, xx*Power/cPowerDivisor, yy*Power/cPowerDivisor, Ammo^[CurSlot, CurAmmo].Timer);
+                   amWatermelon: FollowGear:= AddGear(hwRound(lx), hwRound(ly), gtWatermelon,  0, xx*Power/cPowerDivisor, yy*Power/cPowerDivisor, CurWeapon^.Timer);
                   amHellishBomb: FollowGear:= AddGear(hwRound(lx), hwRound(ly), gtHellishBomb,    0, xx*Power/cPowerDivisor, yy*Power/cPowerDivisor, 0);
-                       amNapalm: AddGear(Ammo^[CurSlot, CurAmmo].Pos, 0, gtAirAttack, 2, _0, _0, 0);
+                       amNapalm: AddGear(CurWeapon^.Pos, 0, gtAirAttack, 2, _0, _0, 0);
                         amDrill: FollowGear:= AddGear(hwRound(lx), hwRound(ly), gtDrill, 0, xx*Power/cPowerDivisor, yy*Power/cPowerDivisor, 0);
                       amBallgun: CurAmmoGear:= AddGear(hwRound(X), hwRound(Y), gtBallgun,  0, xx * _0_5, yy * _0_5, 0);
                     amJetpack: CurAmmoGear:= AddGear(hwRound(lx), hwRound(ly), gtJetpack, 0, _0, _0, 0);
@@ -251,9 +268,14 @@
                                PauseMusic
                                end;
                       amFlamethrower: CurAmmoGear:= AddGear(hwRound(X), hwRound(Y), gtFlamethrower,  0, xx * _0_5, yy * _0_5, 0);
+                    amResurrector: begin
+                        CurAmmoGear:= AddGear(hwRound(lx), hwRound(ly),
+                                gtResurrector, 0, _0, _0, 0);
+                        CurAmmoGear^.SoundChannel := LoopSound(sndResurrector);
+                    end;
                   end;
 
-        uStats.AmmoUsed(Ammo^[CurSlot, CurAmmo].AmmoType);
+        uStats.AmmoUsed(CurAmmoType);
 
         if not (SpeechText = '') then
             begin
@@ -269,56 +291,51 @@
 
         Power:= 0;
         if (CurAmmoGear <> nil)
-           and (((Ammo^[CurSlot, CurAmmo].Propz) and ammoprop_AltUse) = 0){check for dropping ammo from rope} then
+           and ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_AltUse) = 0){check for dropping ammo from rope} then
            begin
-           CurAmmoGear^.Ammo:= @(Ammo^[CurSlot, CurAmmo]);
-           CurAmmoGear^.AmmoType:= CurAmmoGear^.Ammo^.AmmoType;
-           Message:= Message or gm_Attack;
+           CurAmmoGear^.AmmoType:= CurAmmoType;
+           Message:= Message or gmAttack;
            CurAmmoGear^.Message:= Message
            end else begin
            if not CurrentTeam^.ExtDriven and
-             ((Ammo^[CurSlot, CurAmmo].Propz and ammoprop_Power) <> 0) then SendIPC('a');
+             ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_Power) <> 0) then SendIPC('a');
            AfterAttack;
            end
-        end else Message:= Message and not gm_Attack;
+        end else Message:= Message and not gmAttack;
      end
 end;
 
 procedure AfterAttack;
 var s: shortstring;
+    a: TAmmoType;
 begin
 with CurrentHedgehog^.Gear^,
         CurrentHedgehog^ do
     begin
+    a:= CurAmmoType;
     State:= State and not gstAttacking;
-    if ((Ammo^[CurSlot, CurAmmo].Propz) and ammoprop_Effect) = 0 then
+    if (Ammoz[a].Ammo.Propz and ammoprop_Effect) = 0 then
         begin
         Inc(MultiShootAttacks);
         
-        if (Ammo^[CurSlot, CurAmmo].NumPerTurn >= MultiShootAttacks) then
+        if (Ammoz[a].Ammo.NumPerTurn >= MultiShootAttacks) then
             begin
-            s:= inttostr(Ammo^[CurSlot, CurAmmo].NumPerTurn - MultiShootAttacks + 1);
+            s:= inttostr(Ammoz[a].Ammo.NumPerTurn - MultiShootAttacks + 1);
             AddCaption(format(trmsg[sidRemaining], s), cWhiteColor, capgrpAmmostate);
             end;
         
-        if (Ammo^[CurSlot, CurAmmo].NumPerTurn >= MultiShootAttacks) or
+        if (Ammoz[a].Ammo.NumPerTurn >= MultiShootAttacks) or
             ((GameFlags and gfMultiWeapon) <> 0) then
             begin
             isInMultiShoot:= true
             end
         else
             begin
-            if ((Ammo^[CurSlot, CurAmmo].Propz) and ammoprop_NoRoundEndHint) = 0 then
-                begin
-                OnUsedAmmo(CurrentHedgehog^);
-                TurnTimeLeft:= Ammoz[Ammo^[CurSlot, CurAmmo].AmmoType].TimeAfterTurn;
-                State:= State or gstAttacked
-                end
-            else
-                begin
-                OnUsedAmmo(CurrentHedgehog^);
-                ApplyAmmoChanges(CurrentHedgehog^)
-                end
+            OnUsedAmmo(CurrentHedgehog^);
+            if ((Ammoz[a].Ammo.Propz and ammoprop_NoRoundEndHint) = 0) and ((GameFlags and gfInfAttack) = 0) then
+                TurnTimeLeft:= Ammoz[a].TimeAfterTurn;
+            if ((Ammoz[a].Ammo.Propz and ammoprop_NoRoundEndHint) = 0) then State:= State or gstAttacked;
+            if (Ammoz[a].Ammo.Propz and ammoprop_NoRoundEndHint) <> 0 then ApplyAmmoChanges(CurrentHedgehog^)
             end;
         end
     else
@@ -326,7 +343,7 @@
         OnUsedAmmo(CurrentHedgehog^);
         ApplyAmmoChanges(CurrentHedgehog^);
         end;
-    AttackBar:= 0;
+    AttackBar:= 0
     end
 end;
 
@@ -397,7 +414,7 @@
     i: LongInt;
     vga: PVisualGear;
 begin
-Gear^.Message:= gm_Destroy;
+Gear^.Message:= gmDestroy;
 PlaySound(sndShotgunReload);
 case Gear^.Pos of
        posCaseUtility,
@@ -444,24 +461,26 @@
 
 procedure HedgehogStep(Gear: PGear);
 var PrevdX: LongInt;
+    CurWeapon: PAmmo;
 begin
+CurWeapon:= GetAmmoEntry(PHedgehog(Gear^.Hedgehog)^);
 if ((Gear^.State and (gstAttacking or gstMoving)) = 0) then
    begin
    if isCursorVisible then
       with PHedgehog(Gear^.Hedgehog)^ do
-        with Ammo^[CurSlot, CurAmmo] do
+        with CurWeapon^ do
           begin
-          if (Gear^.Message and gm_Left  ) <> 0 then
+          if (Gear^.Message and gmLeft  ) <> 0 then
              Pos:= (Pos - 1 + Ammoz[AmmoType].PosCount) mod Ammoz[AmmoType].PosCount
           else
-          if (Gear^.Message and gm_Right ) <> 0 then
+          if (Gear^.Message and gmRight ) <> 0 then
              Pos:= (Pos + 1) mod Ammoz[AmmoType].PosCount
           else exit;
           StepTicks:= 200;
           exit
           end;
 
-    if ((Gear^.Message and gm_Animate) <> 0) then
+    if ((Gear^.Message and gmAnimate) <> 0) then
         begin
         Gear^.Message:= 0;
         Gear^.State:= Gear^.State or gstAnimation;
@@ -470,9 +489,9 @@
         Gear^.Pos:= 0
         end;
 
-   if ((Gear^.Message and gm_LJump ) <> 0) then
+   if ((Gear^.Message and gmLJump ) <> 0) then
       begin
-      Gear^.Message:= Gear^.Message and not gm_LJump;
+      Gear^.Message:= Gear^.Message and not gmLJump;
       DeleteCI(Gear);
       if not TestCollisionYwithGear(Gear, -1) then
          if not TestCollisionXwithXYShift(Gear, _0, -2, hwSign(Gear^.dX)) then Gear^.Y:= Gear^.Y - _2 else
@@ -488,10 +507,10 @@
          end;
       end;
 
-   if ((Gear^.Message and gm_HJump ) <> 0) then
+   if ((Gear^.Message and gmHJump ) <> 0) then
       begin
       DeleteCI(Gear);
-      Gear^.Message:= Gear^.Message and not gm_HJump;
+      Gear^.Message:= Gear^.Message and not gmHJump;
 
       Gear^.dY:= -_0_2;
       SetLittle(Gear^.dX);
@@ -501,10 +520,10 @@
       end;
 
    PrevdX:= hwSign(Gear^.dX);
-   if (Gear^.Message and gm_Left  )<>0 then Gear^.dX:= -cLittle else
-   if (Gear^.Message and gm_Right )<>0 then Gear^.dX:=  cLittle else exit;
+   if (Gear^.Message and gmLeft  )<>0 then Gear^.dX:= -cLittle else
+   if (Gear^.Message and gmRight )<>0 then Gear^.dX:=  cLittle else exit;
 
-   if (Gear^.Message and (gm_Left or gm_Right)) <> 0 then
+   if (Gear^.Message and (gmLeft or gmRight)) <> 0 then
       begin
       StepSoundTimer:= cHHStepTicks;
       end;
@@ -534,7 +553,7 @@
          or TestCollisionYwithGear(Gear, -1)) then Gear^.Y:= Gear^.Y - _1;
       end;
 
-   if (not cArtillery) and ((Gear^.Message and gm_Precise) = 0) and (not TestCollisionXwithGear(Gear, hwSign(Gear^.dX))) then
+   if (not cArtillery) and ((Gear^.Message and gmPrecise) = 0) and (not TestCollisionXwithGear(Gear, hwSign(Gear^.dX))) then
       Gear^.X:= Gear^.X + SignAs(_1, Gear^.dX);
 
    SetAllHHToActive;
@@ -578,22 +597,24 @@
 var da: LongWord;
 begin
 with PHedgehog(Gear^.Hedgehog)^ do
-    if (Ammo^[CurSlot, CurAmmo].AmmoType = amRope)
+    if (CurAmmoType = amRope)
     and ((Gear^.State and (gstMoving or gstHHJumping)) = gstMoving) then da:= 2 else da:= 1;
 
-if (((Gear^.Message and gm_Precise) = 0) or ((GameTicks mod 5) = 1)) then
-    if ((Gear^.Message and gm_Up) <> 0) and (Gear^.Angle >= CurMinAngle + da) then dec(Gear^.Angle, da)
+if (((Gear^.Message and gmPrecise) = 0) or ((GameTicks mod 5) = 1)) then
+    if ((Gear^.Message and gmUp) <> 0) and (Gear^.Angle >= CurMinAngle + da) then dec(Gear^.Angle, da)
     else
-    if ((Gear^.Message and gm_Down) <> 0) and (Gear^.Angle + da <= CurMaxAngle) then inc(Gear^.Angle, da)
+    if ((Gear^.Message and gmDown) <> 0) and (Gear^.Angle + da <= CurMaxAngle) then inc(Gear^.Angle, da)
 end;
 
 procedure doStepHedgehog(Gear: PGear); forward;
 ////////////////////////////////////////////////////////////////////////////////
 procedure doStepHedgehogMoving(Gear: PGear);
-var isFalling: boolean;
+var isFalling, isUnderwater: boolean;
 begin
-if Gear^.dX > _0_995 then Gear^.dX:= _0_995;
-if Gear^.dY > _0_995 then Gear^.dY:= _0_995;
+isUnderwater:= cWaterLine < hwRound(Gear^.Y) + Gear^.Radius;
+if Gear^.dX.QWordValue > 8160437862 then Gear^.dX.QWordValue:= 8160437862;
+if Gear^.dY.QWordValue > 8160437862 then Gear^.dY.QWordValue:= 8160437862;
+
 if PHedgehog(Gear^.Hedgehog)^.Unplaced then
    begin
    Gear^.dY:= _0;
@@ -606,8 +627,10 @@
    begin
    if (Gear^.dY.isNegative) and TestCollisionYKick(Gear, -1) then Gear^.dY:= _0;
    Gear^.State:= Gear^.State or gstMoving;
-   Gear^.dY:= Gear^.dY + cGravity
-   end else
+   if isUnderwater then Gear^.dY:= Gear^.dY + cGravity / _2
+   else Gear^.dY:= Gear^.dY + cGravity
+   end 
+else
    begin
    if ((hwAbs(Gear^.dX) + hwAbs(Gear^.dY)) < _0_55)
       and ((Gear^.State and gstHHJumping) <> 0) then SetLittle(Gear^.dX);
@@ -628,6 +651,12 @@
 
 if (Gear^.State <> 0) then DeleteCI(Gear);
 
+if isUnderwater then
+   begin
+   Gear^.dY:= Gear^.dY * _0_999;
+   Gear^.dX:= Gear^.dX * _0_999;
+   end;
+
 if (Gear^.State and gstMoving) <> 0 then
    if TestCollisionXKick(Gear, hwSign(Gear^.dX)) then
       if not isFalling then
@@ -697,7 +726,9 @@
 procedure doStepHedgehogDriven(Gear: PGear);
 var t: PGear;
     wasJumping: boolean;
+    Hedgehog: PHedgehog;
 begin
+Hedgehog:= PHedgehog(Gear^.Hedgehog);
 if not isInMultiShoot then
    AllInactive:= false
 else
@@ -717,7 +748,7 @@
 if (Gear^.State and gstAnimation) <> 0 then
     begin
     Gear^.Message:= 0;
-    if (Gear^.Pos = Wavez[TWave(Gear^.Tag)].VoiceDelay) and (Gear^.Timer = 0) then PlaySound(Wavez[TWave(Gear^.Tag)].Voice, PHedgehog(Gear^.Hedgehog)^.Team^.voicepack);
+    if (Gear^.Pos = Wavez[TWave(Gear^.Tag)].VoiceDelay) and (Gear^.Timer = 0) then PlaySound(Wavez[TWave(Gear^.Tag)].Voice, Hedgehog^.Team^.voicepack);
     inc(Gear^.Timer);
     if Gear^.Timer = Wavez[TWave(Gear^.Tag)].Interval then
         begin
@@ -733,10 +764,10 @@
     or (StepTicks = cHHStepTicks)
     or (CurAmmoGear <> nil) then // we are moving
     begin
-    with PHedgehog(Gear^.Hedgehog)^ do
+    with Hedgehog^ do
         if (CurAmmoGear = nil)
         and (Gear^.dY > _0_39)
-        and (Ammo^[CurSlot, CurAmmo].AmmoType = amParachute) then Gear^.Message:= Gear^.Message or gm_Attack;
+        and (CurAmmoType = amParachute) then Gear^.Message:= Gear^.Message or gmAttack;
     // check for case with ammo
     t:= CheckGearNear(Gear, gtCase, 36, 36);
     if t <> nil then
@@ -744,31 +775,33 @@
     end;
 
 if (CurAmmoGear = nil) then
-    if (((Gear^.Message and gm_Attack) <> 0)
+    if (((Gear^.Message and gmAttack) <> 0)
         or ((Gear^.State and gstAttacking) <> 0)) then
         Attack(Gear) // should be before others to avoid desync with '/put' msg and changing weapon msgs
     else
-else with PHedgehog(Gear^.Hedgehog)^ do
-     if ((Ammoz[CurAmmoGear^.AmmoType].Ammo.Propz and ammoprop_AltAttack) <> 0)
-        and ((Gear^.Message and gm_LJump) <> 0)
-        and (((Ammo^[CurSlot, CurAmmo].Propz) and ammoprop_AltUse) <> 0) then
-        begin
-        Gear^.Message:= Gear^.Message and not gm_LJump;
-        Attack(Gear)
-        end;
+else 
+    with Hedgehog^ do
+        if ((Ammoz[CurAmmoGear^.AmmoType].Ammo.Propz and ammoprop_AltAttack) <> 0)
+            and ((Gear^.Message and gmLJump) <> 0)
+            and ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_AltUse) <> 0) then
+            begin
+            Gear^.Message:= Gear^.Message and not gmLJump;
+            Attack(Gear)
+            end;
 
 if (CurAmmoGear = nil)
-    or ((Ammoz[CurAmmoGear^.AmmoType].Ammo.Propz and ammoprop_AltAttack) <> 0) then
+    or ((Ammoz[CurAmmoGear^.AmmoType].Ammo.Propz and ammoprop_AltAttack) <> 0) 
+    or ((Ammoz[CurAmmoGear^.AmmoType].Ammo.Propz and ammoprop_NoRoundEndHint) <> 0) then
     begin
-    if ((Gear^.Message and gm_Slot) <> 0) then
+    if ((Gear^.Message and gmSlot) <> 0) then
         begin
         ChangeAmmo(Gear);
-        ApplyAmmoChanges(PHedgehog(Gear^.Hedgehog)^)
+        ApplyAmmoChanges(Hedgehog^)
         end;
 
-    if ((Gear^.Message and gm_Weapon) <> 0) then HHSetWeapon(Gear);
+    if ((Gear^.Message and gmWeapon) <> 0) then HHSetWeapon(Gear);
 
-    if ((Gear^.Message and gm_Timer) <> 0) then HHSetTimer(Gear);
+    if ((Gear^.Message and gmTimer) <> 0) then HHSetTimer(Gear);
     end;
 
 if CurAmmoGear <> nil then
@@ -784,7 +817,7 @@
     begin
     wasJumping:= ((Gear^.State and gstHHJumping) <> 0);
 
-    if ((Gear^.Message and gm_HJump) <> 0) and
+    if ((Gear^.Message and gmHJump) <> 0) and
         wasJumping and
         ((Gear^.State and gstHHHJump) = 0) then
         if (not (hwAbs(Gear^.dX) > cLittle)) and (Gear^.dY < -_0_02) then
@@ -792,10 +825,10 @@
             Gear^.State:= Gear^.State or gstHHHJump;
             Gear^.dY:= -_0_25;
             if not cArtillery then Gear^.dX:= -SignAs(_0_02, Gear^.dX);
-            PlaySound(sndJump2, PHedgehog(Gear^.Hedgehog)^.Team^.voicepack)
+            PlaySound(sndJump2, Hedgehog^.Team^.voicepack)
             end;
 
-    Gear^.Message:= Gear^.Message and not (gm_LJump or gm_HJump);
+    Gear^.Message:= Gear^.Message and not (gmLJump or gmHJump);
 
     if (not cArtillery) and wasJumping and
         TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) then SetLittle(Gear^.dX);
@@ -846,10 +879,14 @@
 
         if not PHedgehog(Gear^.Hedgehog)^.Team^.hasGone then
             begin
-            Gear^.State:= Gear^.State or gstHHDeath;
-            Gear^.doStep:= @doStepHedgehogDead;
-            // Death message
-            AddCaption(Format(GetEventString(eidDied), PHedgehog(Gear^.Hedgehog)^.Name), cWhiteColor, capgrpMessage);
+            if PHedgehog(Gear^.Hedgehog)^.Effects[heResurrectable] then begin
+                ResurrectHedgehog(Gear);
+            end else begin
+                Gear^.State:= Gear^.State or gstHHDeath;
+                Gear^.doStep:= @doStepHedgehogDead;
+                // Death message
+                AddCaption(Format(GetEventString(eidDied), PHedgehog(Gear^.Hedgehog)^.Name), cWhiteColor, capgrpMessage);
+            end;
             end
         else
             begin
@@ -884,7 +921,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 procedure doStepHedgehog(Gear: PGear);
 begin
-if (Gear^.Message and gm_Destroy) <> 0 then
+if (Gear^.Message and gmDestroy) <> 0 then
     begin
     DeleteGear(Gear);
     exit
--- a/hedgewars/PascalExports.pas	Thu Aug 26 23:59:18 2010 +0200
+++ b/hedgewars/PascalExports.pas	Wed Oct 27 14:02:20 2010 +0200
@@ -1,25 +1,35 @@
 (*
- *  PascalExports.pas
- *  hwengine
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2011 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
  *
- *  Created by Vittorio on 09/01/10.
- *  Copyright 2009 __MyCompanyName__. All rights reserved.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
  *)
 
-
 {$INCLUDE "options.inc"}
 
 unit PascalExports;
 
 interface
-uses uKeys, GLunit, uWorld, uMisc, uConsole, uTeams, uConsts, uChat, uGears, uSound, hwengine;
+uses uKeys, GLunit, uWorld, uMisc, uConsole, uTeams, uConsts, uChat, 
+     uGears, uSound, hwengine, uAmmos, uLocale; // don't change the order!
 
 {$INCLUDE "config.inc"}
+type PPByte = ^PByte;
 
 implementation
-
 {$IFDEF HWLIBRARY}
+var cZoomVal: GLfloat;
 
 // retrieve protocol information
 procedure HW_versionInfo(netProto: PShortInt; versionStr: PPChar); cdecl; export;
@@ -34,6 +44,17 @@
     leftClick:= true;
 end;
 
+procedure HW_ammoMenu; cdecl; export;
+begin
+    rightClick:= true;
+end;
+
+procedure HW_zoomSet(value: GLfloat); cdecl; export;
+begin
+    cZoomVal:= value;
+    ZoomValue:= value;
+end;
+
 procedure HW_zoomIn; cdecl; export;
 begin
     if wheelDown = false then
@@ -48,15 +69,21 @@
 
 procedure HW_zoomReset; cdecl; export;
 begin
-    middleClick:= true;
+    ZoomValue:= cZoomVal;
+    //middleClick:= true;
     // center the camera at current hog
     if CurrentHedgehog <> nil then
         followGear:= CurrentHedgehog^.Gear;
 end;
 
-procedure HW_ammoMenu; cdecl; export;
+function HW_zoomFactor: GLfloat; cdecl; export;
 begin
-    rightClick:= true;
+    exit( ZoomValue / cDefaultZoomLevel );
+end;
+
+function HW_zoomLevel: LongInt; cdecl; export;
+begin
+    exit( trunc((ZoomValue - cDefaultZoomLevel) / cZoomDelta) );
 end;
 
 procedure HW_walkingKeysUp; cdecl; export;
@@ -148,18 +175,6 @@
     if closeFrontend then alsoShutdownFrontend:= true;
 end;
 
-procedure HW_setLandscape(landscape: boolean); cdecl; export;
-begin
-    if landscape then
-    begin
-        cOffsetY:= 0;
-    end
-    else
-    begin
-        cOffsetY:= 120;
-    end;
-end;
-
 procedure HW_setCursor(x,y: LongInt); cdecl; export;
 begin
     CursorPoint.X:= x;
@@ -172,14 +187,69 @@
     y^:= CursorPoint.Y;
 end;
 
-procedure HW_setPianoSound(snd: LongInt); cdecl; export;
-var CurSlot, CurAmmo: LongWord;
+function HW_isAmmoMenuOpen: boolean; cdecl; export;
+begin
+    exit(bShowAmmoMenu);
+end;
+
+function HW_isAmmoMenuNotAllowed: boolean; cdecl; export;
+begin;
+    exit ( (TurnTimeLeft = 0) or (not CurrentTeam^.ExtDriven and (((CurAmmoGear = nil) or ((Ammoz[CurAmmoGear^.AmmoType].Ammo.Propz and ammoprop_AltAttack) = 0)) and hideAmmoMenu)) );
+end;
+
+function HW_isPaused: boolean; cdecl; export;
+begin
+    exit( isPaused );
+end;
+
+function HW_isWaiting: boolean; cdecl; export;
+begin
+    exit( ReadyTimeLeft > 0 );
+end;
+
+function HW_isWeaponRequiringClick: boolean; cdecl; export;
+begin
+    if (CurrentHedgehog <> nil) and (CurrentHedgehog^.Gear <> nil) and (CurrentHedgehog^.BotLevel = 0) then
+        exit( (CurrentHedgehog^.Gear^.State and gstHHChooseTarget) <> 0 )
+    else
+        exit(false);
+end;
+
+function HW_isWeaponTimerable: boolean; cdecl; export;
 begin
-    CurSlot:= CurrentHedgehog^.CurSlot;
-    CurAmmo:= CurrentHedgehog^.CurAmmo;
+    if (CurrentHedgehog <> nil) and (CurrentHedgehog^.Ammo <> nil) and (CurrentHedgehog^.BotLevel = 0) then
+        exit( (Ammoz[CurrentHedgehog^.CurAmmoType].Ammo.Propz and ammoprop_Timerable) <> 0)
+    else
+        exit(false);
+end;
+
+function HW_isWeaponSwitch: boolean cdecl; export;
+begin
+    if (CurAmmoGear <> nil) and (CurrentHedgehog^.BotLevel = 0) then
+        exit(CurAmmoGear^.AmmoType = amSwitch)
+    else
+        exit(false)
+end;
+
+function HW_isWeaponRope: boolean cdecl; export;
+begin
+    if (CurrentHedgehog <> nil) and (CurrentHedgehog^.Ammo <> nil) and (CurrentHedgehog^.BotLevel = 0) then
+        exit (CurrentHedgehog^.CurAmmoType = amRope)
+    else
+        exit(false);
+end;
+
+procedure HW_setGrenadeTime(time: LongInt); cdecl; export;
+begin
+    ParseCommand('/timer ' + inttostr(time), true);
+end;
+
+procedure HW_setPianoSound(snd: LongInt); cdecl; export;
+begin
     // this most likely won't work in network game
-    if (CurrentHedgehog^.Ammo^[CurSlot, CurAmmo].AmmoType = amPiano) then
-        case snd of 
+    if (CurrentHedgehog <> nil) and (CurrentHedgehog^.Ammo <> nil) and (CurrentHedgehog^.BotLevel = 0)
+       and (CurrentHedgehog^.CurAmmoType = amPiano) then
+        case snd of
             0: PlaySound(sndPiano0);
             1: PlaySound(sndPiano1);
             2: PlaySound(sndPiano2);
@@ -192,46 +262,76 @@
         end;
 end;
 
-function HW_isAmmoOpen: boolean; cdecl; export;
+function HW_getWeaponNameByIndex(whichone: LongInt): PChar; cdecl; export;
+begin
+    exit (str2pchar(trammo[Ammoz[TAmmoType(whichone+1)].NameId]));
+end;
+
+function HW_getWeaponCaptionByIndex(whichone: LongInt): PChar; cdecl; export;
 begin
-    exit(bShowAmmoMenu);
+    exit (str2pchar(trammoc[Ammoz[TAmmoType(whichone+1)].NameId]));
+end;
+
+function HW_getWeaponDescriptionByIndex(whichone: LongInt): PChar; cdecl; export;
+begin
+    exit (str2pchar(trammod[Ammoz[TAmmoType(whichone+1)].NameId]));
 end;
 
-function HW_isWeaponRequiringClick: boolean; cdecl; export;
+function HW_getNumberOfWeapons:LongInt; cdecl; export;
+begin
+    exit(ord(high(TAmmoType)));
+end;
+
+procedure HW_setWeapon(whichone: LongInt); cdecl; export;
 begin
-    if (CurrentHedgehog <> nil) and (CurrentHedgehog^.Gear <> nil) then
-        exit( (CurrentHedgehog^.Gear^.State and gstHHChooseTarget) <> 0 )
-    else
-        exit(false);
+    if (not CurrentTeam^.ExtDriven) and (CurrentTeam^.Hedgehogs[0].BotLevel = 0) then
+        SetWeapon(TAmmoType(whichone+1));
+end;
+
+function HW_isWeaponAnEffect(whichone: LongInt): boolean; cdecl; export;
+begin
+    exit(Ammoz[TAmmoType(whichone+1)].Ammo.Propz and ammoprop_Effect <> 0)
 end;
 
-function HW_isWeaponTimerable: boolean; cdecl; export;
-var CurSlot, CurAmmo: LongWord;
+function HW_getAmmoCounts(counts: PLongInt): LongInt; cdecl; export;
+var a : PHHAmmo;
+    slot, index: LongInt;
 begin
-    CurSlot:= CurrentHedgehog^.CurSlot;
-    CurAmmo:= CurrentHedgehog^.CurAmmo;
-    exit( (CurrentHedgehog^.Ammo^[CurSlot, CurAmmo].Propz and ammoprop_Timerable) <> 0)
+    if (CurrentTeam = nil) or
+       (CurrentHedgehog = nil) or
+       (CurrentTeam^.ExtDriven) or
+       (CurrentTeam^.Hedgehogs[0].BotLevel <> 0) then
+        exit(-1);
+
+    a:= CurrentHedgehog^.Ammo;
+    for slot:= 0 to cMaxSlotIndex do
+        for index:= 0 to cMaxSlotAmmoIndex do
+            if a^[slot,index].Count <> 0 then // yes, ammomenu is hell
+                counts[ord(a^[slot,index].AmmoType)-1]:= a^[slot,index].Count;
+    exit(0);
 end;
 
-function HW_isWeaponSwitch: boolean cdecl; export;
+procedure HW_getAmmoDelays (skipTurns: PByte); cdecl; export;
+var a : TAmmoType;
 begin
-    if CurAmmoGear <> nil then
-        exit(CurAmmoGear^.AmmoType = amSwitch) 
-    else
-        exit(false)
+    for a:= Low(TAmmoType) to High(TAmmoType) do
+        skipTurns[ord(a)-1]:= byte(Ammoz[a].SkipTurns);
 end;
 
-function HW_isPaused: boolean; cdecl; export;
+function HW_getTurnsForCurrentTeam: LongInt; cdecl; export;
 begin
-    exit( isPaused );
+    exit(CurrentTeam^.Clan^.TurnNumber);
 end;
 
-procedure HW_setGrenadeTime(time: LongInt); cdecl; export;
+function HW_getMaxNumberOfHogs: LongInt; cdecl; export;
 begin
-    ParseCommand('/timer ' + inttostr(time), true);
+    exit(cMaxHHIndex+1);
 end;
 
-//amSwitch
+function HW_getMaxNumberOfTeams: LongInt; cdecl; export;
+begin
+    exit(cMaxTeams);
+end;
 {$ENDIF}
 
 end.
--- a/hedgewars/SDLMain.m	Thu Aug 26 23:59:18 2010 +0200
+++ b/hedgewars/SDLMain.m	Wed Oct 27 14:02:20 2010 +0200
@@ -50,7 +50,7 @@
     dict = (const NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle());
     if (dict)
         appName = [dict objectForKey: @"CFBundleName"];
-    
+
     if (![appName length])
         appName = [[NSProcessInfo processInfo] processName];
 
@@ -131,10 +131,10 @@
     NSMenuItem *menuItem;
     NSString *title;
     NSString *appName;
-    
+
     appName = getApplicationName();
     appleMenu = [[NSMenu alloc] initWithTitle:@""];
-    
+
     /* Add menu items */
     title = [@"About " stringByAppendingString:appName];
     [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
@@ -154,7 +154,7 @@
     title = [@"Quit " stringByAppendingString:appName];
     [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"];
 
-    
+
     /* Put menu into the menubar */
     menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
     [menuItem setSubmenu:appleMenu];
@@ -176,17 +176,17 @@
     NSMenuItem  *menuItem;
 
     windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
-    
+
     /* "Minimize" item */
     menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"];
     [windowMenu addItem:menuItem];
     [menuItem release];
-    
+
     /* Put menu into the menubar */
     windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""];
     [windowMenuItem setSubmenu:windowMenu];
     [[NSApp mainMenu] addItem:windowMenuItem];
-    
+
     /* Tell the application object that this is now the window menu */
     [NSApp setWindowsMenu:windowMenu];
 
@@ -203,7 +203,7 @@
 
     /* Ensure the application object is initialised */
     [SDLApplication sharedApplication];
-    
+
 #ifdef SDL_USE_CPS
     {
         CPSProcessSerNum PSN;
@@ -223,10 +223,10 @@
     /* Create SDLMain and make it the app delegate */
     sdlMain = [[SDLMain alloc] init];
     [NSApp setDelegate:sdlMain];
-    
+
     /* Start the main event loop */
     [NSApp run];
-    
+
     [sdlMain release];
     [pool release];
 }
@@ -319,27 +319,27 @@
 
     bufferSize = selfLen + aStringLen - aRange.length;
     buffer = (unichar *)NSAllocateMemoryPages(bufferSize*sizeof(unichar));
-    
+
     /* Get first part into buffer */
     localRange.location = 0;
     localRange.length = aRange.location;
     [self getCharacters:buffer range:localRange];
-    
+
     /* Get middle part into buffer */
     localRange.location = 0;
     localRange.length = aStringLen;
     [aString getCharacters:(buffer+aRange.location) range:localRange];
-     
+
     /* Get last part into buffer */
     localRange.location = aRange.location + aRange.length;
     localRange.length = selfLen - localRange.location;
     [self getCharacters:(buffer+aRange.location+aStringLen) range:localRange];
-    
+
     /* Build output string */
     result = [NSString stringWithCharacters:buffer length:bufferSize];
-    
+
     NSDeallocateMemoryPages(buffer, bufferSize);
-    
+
     return result;
 }
 
--- a/hedgewars/SDLh.pas	Thu Aug 26 23:59:18 2010 +0200
+++ b/hedgewars/SDLh.pas	Wed Oct 27 14:02:20 2010 +0200
@@ -96,7 +96,7 @@
     SDL_SWSURFACE     = $00000000;
     SDL_HWSURFACE     = $00000001;
     SDL_SRCALPHA      = $00010000;
-    
+
     SDL_INIT_TIMER    = $00000001;
     SDL_INIT_AUDIO    = $00000010;
     SDL_INIT_VIDEO    = $00000020;
@@ -156,7 +156,7 @@
     SDL_VIDEORESIZE = 16; // TODO: outdated? no longer in SDL 1.3?
 {$ENDIF}
 {*end SDL_Event binding*}
-        
+
 {$IFDEF SDL13}
     SDL_ASYNCBLIT   = $08000000;
     SDL_ANYFORMAT   = $10000000;
@@ -209,12 +209,12 @@
     SDL_WINDOW_INPUT_FOCUS = $00000200;        //*< window has input focus */
     SDL_WINDOW_MOUSE_FOCUS = $00000400;        //*< window has mouse focus */
     SDL_WINDOW_FOREIGN = $00000800;            //*< window not created by SDL */
-    
+
     // SDL_WindowEventID (enum)
     SDL_WINDOWEVENT_NONE = 0;            //*< Never used
     SDL_WINDOWEVENT_SHOWN = 1;           //*< Window has been shown
     SDL_WINDOWEVENT_HIDDEN = 2;          //*< Window has been hidden
-    SDL_WINDOWEVENT_EXPOSED = 3;         //*< Window has been exposed and should be redrawn 
+    SDL_WINDOWEVENT_EXPOSED = 3;         //*< Window has been exposed and should be redrawn
     SDL_WINDOWEVENT_MOVED = 4;           //*< Window has been moved to data1, data2
     SDL_WINDOWEVENT_RESIZED = 5;         //*< Window size changed to data1xdata2
     SDL_WINDOWEVENT_MINIMIZED = 6;       //*< Window has been minimized
@@ -233,7 +233,7 @@
     MIX_INIT_MOD  = $00000002;
     MIX_INIT_MP3  = $00000004;
     MIX_INIT_OGG  = $00000008;
-    
+
     {* SDL_TTF *}
     TTF_STYLE_NORMAL = 0;
     TTF_STYLE_BOLD   = 1;
@@ -259,7 +259,7 @@
 ///////////////////////  TYPE DEFINITIONS ///////////////////////
 /////////////////////////////////////////////////////////////////
 
-type 
+type
     PSDL_Rect = ^TSDL_Rect;
     TSDL_Rect = record
 {$IFDEF SDL13}
@@ -357,9 +357,9 @@
 {* SDL_Event type definition *}
 
 {$IFDEF SDL13}
-    PSDL_Window = pointer;  
+    PSDL_Window = pointer;
     PSDL_Texture = pointer;
-    
+
     TSDL_WindowEvent = record
         type_: LongInt;
         windowID: LongInt;
@@ -367,7 +367,7 @@
         padding1, padding2, padding3: byte;
         data1, data2: LongInt;
         end;
-        
+
     TSDL_KeySym = record
         scancode,
         sym,
@@ -407,7 +407,7 @@
         padding1, padding2: byte;
         x, y, z, xrel, yrel : LongInt;
         pressure, pressure_max, pressure_min,
-        rotation, tilt, cursor: LongInt; 
+        rotation, tilt, cursor: LongInt;
 {$ELSE}
         type_: byte;
         x, y, xrel, yrel : word;
@@ -450,7 +450,7 @@
         x, y: LongInt;
         padding1, padding2, padding3: byte;
         end;
-        
+
     // implement SDL_ProximityEvent
 {$ENDIF}
 
@@ -465,10 +465,10 @@
 {$IFDEF SDL13}
         value: LongInt;
 {$ELSE}
-        value: word;
-{$ENDIF}    
+        value: Smallint;
+{$ENDIF}
         end;
-            
+
     TSDL_JoyBallEvent = record
         which: Byte;
         ball: Byte;
@@ -477,7 +477,7 @@
         xrel, yrel: LongInt;
 {$ELSE}
         type_: Byte;
-        xrel, yrel: word;
+        xrel, yrel: Smallint;
 {$ENDIF}
         end;
 
@@ -491,7 +491,7 @@
         hat: Byte;
         value: Byte;
         end;
-    
+
     TSDL_JoyButtonEvent = record
 {$IFDEF SDL13}
         type_: LongInt;
@@ -586,7 +586,7 @@
         );
 
 {$IFDEF SDL13}
-    TSDL_ArrayByteOrder = (  // array component order, low byte -> high byte 
+    TSDL_ArrayByteOrder = (  // array component order, low byte -> high byte
         SDL_ARRAYORDER_NONE,
         SDL_ARRAYORDER_RGB,
         SDL_ARRAYORDER_RGBA,
@@ -702,8 +702,8 @@
 function  SDL_SaveBMP_RW(surface: PSDL_Surface; dst: PSDL_RWops; freedst: LongInt): LongInt; cdecl; external SDLLibName;
 
 {$IFDEF SDL13}
-function  SDL_CreateWindow(title: PChar; x,y,w,h, flags: LongInt): PSDL_Window; cdecl; external SDLLibName;      
-function  SDL_CreateRenderer(window: PSDL_Window; index, flags: LongInt): LongInt; cdecl; external SDLLibName;   
+function  SDL_CreateWindow(title: PChar; x,y,w,h, flags: LongInt): PSDL_Window; cdecl; external SDLLibName;
+function  SDL_CreateRenderer(window: PSDL_Window; index, flags: LongInt): LongInt; cdecl; external SDLLibName;
 function  SDL_SetRenderDrawColor(r,g,b,a: byte): LongInt; cdecl; external SDLLibName;
 function  SDL_DestroyRenderer(window: PSDL_Window): LongInt; cdecl; external SDLLibName;
 function  SDL_DestroyWindow(window: PSDL_Window): LongInt; cdecl; external SDLLibName;
@@ -718,6 +718,7 @@
 function  SDL_GetRelativeMouseState(x, y: PLongInt): Byte; cdecl; external SDLLibName;
 function  SDL_GetNumMice: LongInt; cdecl; external SDLLibName;
 function  SDL_PixelFormatEnumToMasks(format: TSDL_ArrayByteOrder; bpp: PLongInt; Rmask, Gmask, Bmask, Amask: PLongInt): boolean; cdecl; external SDLLibName;
+function  SDL_RenderReadPixels(rect: PSDL_Rect; format: LongInt; pixels: pointer; pitch: LongInt): LongInt; cdecl; external SDLLibName;
 {$ENDIF}
 
 function  SDL_GetKeyState(numkeys: PLongInt): PByteArray; cdecl; external SDLLibName {$IFDEF SDL13} name 'SDL_GetKeyboardState'{$ENDIF};
@@ -841,13 +842,6 @@
 function  SDLNet_Read16(buf: pointer): Word;
 function  SDLNet_Read32(buf: pointer): LongWord;
 
-{$IFDEF IPHONEOS}
-(*  iPhone related calls  *)
-procedure clearView; cdecl; external;
-procedure startSpinning; cdecl; external;
-procedure stopSpinning; cdecl; external;
-function  isPhone: Boolean; cdecl; external;
-{$ENDIF}
 implementation
 
 function SDL_MustLock(Surface: PSDL_Surface): Boolean;
--- a/hedgewars/VGSHandlers.inc	Thu Aug 26 23:59:18 2010 +0200
+++ b/hedgewars/VGSHandlers.inc	Wed Oct 27 14:02:20 2010 +0200
@@ -34,9 +34,9 @@
     Y:= Y + (dY + tdY + cGravityf * vobFallSpeed) * Steps;
     Angle:= Angle + dAngle * Steps;
   
-    if (round(X) >= -cScreenWidth - 64) and
-       (round(X) <= cScreenWidth + LAND_WIDTH) and
-       (round(Y) <= (LAND_HEIGHT + 75)) and 
+    if (round(X) >= cLeftScreenBorder) and
+       (round(X) <= cRightScreenBorder) and
+       (round(Y) <= (int64(LAND_HEIGHT) + 75)) and
        (Timer > 0) and (Timer-Steps > 0) then
         begin
         if tdX > 0 then sign := 1
@@ -51,10 +51,10 @@
         end
     else
         begin
-        if round(X) < -cScreenWidth - 64 then X:= float(cScreenWidth + LAND_WIDTH) else
-        if round(X) > cScreenWidth + LAND_WIDTH then X:= float(-cScreenWidth - 64);
+        if round(X) < cLeftScreenBorder then X:= X + cScreenSpace else
+        if round(X) > cRightScreenBorder then X:= X - cScreenSpace;
         // if round(Y) < (LAND_HEIGHT - 1024 - 75) then Y:= Y + float(25); // For if flag is set for flakes rising upwards?
-        if round(Y) > (LAND_HEIGHT + 75) then Y:= Y - float(1024 + 150); // TODO - configure in theme (jellies for example could use limited range)
+        if round(Y) > (int64(LAND_HEIGHT) + 75) then Y:= Y - float(1024 + 150); // TODO - configure in theme (jellies for example could use limited range)
         Timer:= 0;
         tdX:= 0;
         tdY:= 0
@@ -77,17 +77,17 @@
 var s: Longword;
     t: float;
 begin
-Gear^.X:= Gear^.X + (cWindSpeedf * 200 + Gear^.dX) * Steps;
+Gear^.X:= Gear^.X + (cWindSpeedf * 750 * Gear^.dX) * Steps;
 
 // up-and-down-bounce magic
 s := (GameTicks + Gear^.Timer) mod 4096;
 t := 8 * AngleSin(s mod 2048).QWordValue / 4294967296;
 if (s < 2048) then t := -t;
 
-Gear^.Y := LAND_HEIGHT-1184 + Gear^.Timer mod 8 + t;
+Gear^.Y := int64(LAND_HEIGHT) - 1184 + Gear^.Timer mod 8 + t;
 
-if round(Gear^.X) < -cScreenWidth - 256 then Gear^.X:= float(cScreenWidth + LAND_WIDTH) else
-if round(Gear^.X) > cScreenWidth + LAND_WIDTH then Gear^.X:= float(-cScreenWidth - 256)
+if round(Gear^.X) < cLeftScreenBorder then Gear^.X:= Gear^.X + cScreenSpace else
+if round(Gear^.X) > cRightScreenBorder then Gear^.X:= Gear^.X - cScreenSpace
 end;
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -109,6 +109,24 @@
 end;
 
 ////////////////////////////////////////////////////////////////////////////////
+procedure doStepNote(Gear: PVisualGear; Steps: Longword);
+begin
+Gear^.X:= Gear^.X + Gear^.dX * Steps;
+
+Gear^.Y:= Gear^.Y + Gear^.dY * Steps;
+Gear^.dY:= Gear^.dY + cGravityf * Steps / 2;
+
+Gear^.Angle:= Gear^.Angle + (Gear^.Frame + 1) * Steps / 10;
+while Gear^.Angle > cMaxAngle do
+    Gear^.Angle:= Gear^.Angle - cMaxAngle;
+
+if Gear^.FrameTicks <= Steps then
+    DeleteVisualGear(Gear)
+else
+    dec(Gear^.FrameTicks, Steps)
+end;
+
+////////////////////////////////////////////////////////////////////////////////
 procedure doStepEgg(Gear: PVisualGear; Steps: Longword);
 begin
 Gear^.X:= Gear^.X + Gear^.dX * Steps;
@@ -126,11 +144,27 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 procedure doStepFire(Gear: PVisualGear; Steps: Longword);
+var vgt: PVisualGear;
 begin
 Gear^.X:= Gear^.X + Gear^.dX * Steps;
 
 Gear^.Y:= Gear^.Y + Gear^.dY * Steps;// + cGravityf * (Steps * Steps);
-Gear^.dY:= Gear^.dY + cGravityf * Steps;
+if (Gear^.State and gstTmpFlag) = 0 then
+    begin
+    Gear^.dY:= Gear^.dY + cGravityf * Steps;
+    if ((GameTicks mod 200) < Steps + 1) then
+        begin
+        vgt:= AddVisualGear(round(Gear^.X), round(Gear^.Y), vgtFire);
+        if vgt <> nil then
+            begin
+            vgt^.dx:= 0;
+            vgt^.dy:= 0;
+            vgt^.State:= gstTmpFlag;
+            end;
+        end
+    end
+else
+    inc(Steps, Steps);
 
 if Gear^.FrameTicks <= Steps then
        DeleteVisualGear(Gear)
@@ -167,9 +201,13 @@
 ////////////////////////////////////////////////////////////////////////////////
 procedure doStepBubble(Gear: PVisualGear; Steps: Longword);
 begin
-    Gear^.X:= Gear^.X + (cWindSpeedf * 100 + Gear^.dX) * Steps;
+    Gear^.X:= Gear^.X + Gear^.dX * Steps;
+    Gear^.Y:= Gear^.Y + Gear^.dY * Steps;
     Gear^.Y:= Gear^.Y - cDrownSpeedf * Steps;
 
+    Gear^.dX /= (1.001 * Steps);
+    Gear^.dY /= (1.001 * Steps);
+
     if (Gear^.FrameTicks <= Steps) or (round(Gear^.Y) < cWaterLine) then
         DeleteVisualGear(Gear)
     else
@@ -442,7 +480,7 @@
 
 procedure doStepHealthTagWorkUnderWater(Gear: PVisualGear; Steps: Longword);
 begin
-if round(Gear^.Y) < cWaterLine + 10 then
+if round(Gear^.Y) < int64(cWaterLine) + 10 then
     DeleteVisualGear(Gear)
 else
     Gear^.Y:= Gear^.Y - 0.08 * Steps;
@@ -478,12 +516,16 @@
 inc(Gear^.Timer, Steps );
 if Gear^.Timer > 64 then
     begin
+    if Gear^.State = 0 then
+      begin
+      DeleteVisualGear(Gear);
+      exit;
+      end;
     dec(Gear^.State, Gear^.Timer div 65);
     Gear^.Timer:= Gear^.Timer mod 65;
     end;
 Gear^.dX:= Gear^.dX + cWindSpeedf * Steps;
 Gear^.X:= Gear^.X + Gear^.dX;
-if Gear^.State = 0 then DeleteVisualGear(Gear);
 end;
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -543,3 +585,19 @@
 Gear^.doStep:= @doStepBigExplosionWork;
 if Steps > 1 then Gear^.doStep(Gear, Steps-1);
 end;
+
+procedure doStepChunk(Gear: PVisualGear; Steps: Longword);
+begin
+Gear^.X:= Gear^.X + Gear^.dX * Steps;
+
+Gear^.Y:= Gear^.Y + Gear^.dY * Steps;
+Gear^.dY:= Gear^.dY + cGravityf * Steps;
+
+Gear^.Angle:= round(Gear^.Angle + Steps) mod cMaxAngle;
+
+if round(Gear^.Y) > cWaterLine then
+    begin
+    AddVisualGear(round(Gear^.X), round(Gear^.Y), vgtDroplet);
+    DeleteVisualGear(Gear);
+    end
+end;
--- a/hedgewars/adler32.pas	Thu Aug 26 23:59:18 2010 +0200
+++ b/hedgewars/adler32.pas	Wed Oct 27 14:02:20 2010 +0200
@@ -75,7 +75,7 @@
 procedure Adler32Update(var adler: longint; Msg: pointer; Len: longint);
   //-update Adler32 with Msg data
 const
-  BASE = 65521; // max. prime < 65536 
+  BASE = 65521; // max. prime < 65536
   NMAX =  5552; // max. n with 255n(n+1)/2 + (n+1)(BASE-1) < 2^32
 type
   LH    = packed record
--- a/hedgewars/hwengine.pas	Thu Aug 26 23:59:18 2010 +0200
+++ b/hedgewars/hwengine.pas	Wed Oct 27 14:02:20 2010 +0200
@@ -29,10 +29,9 @@
 program hwengine;
 {$ENDIF}
 
-uses SDLh, uMisc, uConsole, uGame, uConsts, uLand, uAmmos, uVisualGears, uGears, uStore, uWorld, uKeys, uSound, 
-     uScript, uTeams, uStats, uIO, uLocale, uChat, uAI, uAIMisc, uRandom, uLandTexture, uCollisions, sysutils;
-     
-type arrayofpchar = array[0..9] of PChar;
+uses SDLh, uMisc, uConsole, uGame, uConsts, uLand, uAmmos, uVisualGears, uGears, uStore, uWorld, uKeys, uSound,
+     uScript, uTeams, uStats, uIO, uLocale, uChat, uAI, uAIMisc, uRandom, uLandTexture, uCollisions, uMobile, sysutils;
+
 var isTerminated: boolean = false;
     alsoShutdownFrontend: boolean = false;
 
@@ -136,7 +135,7 @@
 end;
 
 ///////////////////
-procedure MainLoop; 
+procedure MainLoop;
 var PrevTime, CurrTime: Longword;
     event: TSDL_Event;
 begin
@@ -176,11 +175,11 @@
         if isTerminated = false then
         begin
             CurrTime:= SDL_GetTicks;
-            if PrevTime + cTimerInterval <= CurrTime then
+            if PrevTime + longword(cTimerInterval) <= CurrTime then
             begin
                 DoTimer(CurrTime - PrevTime);
                 PrevTime:= CurrTime
-            end 
+            end
             else SDL_Delay(1);
             IPCCheckSock();
         end;
@@ -197,7 +196,7 @@
 
 ///////////////
 {$IFDEF HWLIBRARY}
-procedure Game(gameArgs: arrayofpchar); cdecl; export;
+procedure Game(gameArgs: PPChar); cdecl; export;
 {$ELSE}
 procedure Game;
 {$ENDIF}
@@ -215,24 +214,23 @@
 {$IFDEF DEBUGFILE}
     cShowFPS:= true;
 {$ELSE}
-    cShowFPS:= true;    // update me at release time
+    cShowFPS:= false;
 {$ENDIF}
-    cInitVolume:= 100;
-
-    UserNick:= gameArgs[0];
-    val(gameArgs[1], ipcPort);
-    isSoundEnabled:= gameArgs[2] = '1';
-    isMusicEnabled:= gameArgs[3] = '1';
+    val(gameArgs[0], ipcPort);
+    val(gameArgs[1], cScreenWidth);
+    val(gameArgs[2], cScreenHeight);
+    val(gameArgs[3], cReducedQuality);
     cLocaleFName:= gameArgs[4];
-    cAltDamage:= gameArgs[5] = '1';
-    val(gameArgs[6], cScreenHeight);
-    val(gameArgs[7], cScreenWidth);
-    recordFileName:= gameArgs[8];
-    
-    val(gameArgs[9], cReducedQuality);
+    UserNick:= gameArgs[5];
+    isSoundEnabled:= gameArgs[6] = '1';
+    isMusicEnabled:= gameArgs[7] = '1';
+    cAltDamage:= gameArgs[8] = '1';
+    val(gameArgs[9], rotationQt);
+    recordFileName:= gameArgs[10];
     cStereoMode:= smNone; // TODO: Enable anaglyph rendering on iPhone?
 {$ENDIF}
 
+    cLogfileBase:= 'game';
     initEverything(true);
 
     WriteLnToConsole('Hedgewars ' + cVersionString + ' engine (network protocol: ' + inttostr(cNetProtoVersion) + ')');
@@ -244,7 +242,7 @@
 
     for p:= Succ(Low(TPathType)) to High(TPathType) do
         if p <> ptMapCurrent then Pathz[p]:= PathPrefix + '/' + Pathz[p];
-        
+
     WriteToConsole('Init SDL... ');
     SDLTry(SDL_Init(SDL_INIT_VIDEO) >= 0, true);
     WriteLnToConsole(msgOK);
@@ -269,23 +267,26 @@
     ControllerInit(); // has to happen before InitKbdKeyTable to map keys
     InitKbdKeyTable();
 
-    if recordFileName = '' then
-        InitIPC;
-    WriteLnToConsole(msgGettingConfig);
-
     LoadLocale(Pathz[ptLocale] + '/en.txt');  // Do an initial load with english
     if cLocaleFName <> 'en.txt' then
     begin
         // Try two letter locale first before trying specific locale overrides
-        if (Length(cLocaleFName) > 6) and (Copy(cLocaleFName,1,2)+'.txt' <> 'en.txt') then 
+        if (Length(cLocaleFName) > 6) and (Copy(cLocaleFName,1,2)+'.txt' <> 'en.txt') then
             LoadLocale(Pathz[ptLocale] + '/' + Copy(cLocaleFName,1,2)+'.txt');
         LoadLocale(Pathz[ptLocale] + '/' + cLocaleFName);
     end;
 
+    WriteLnToConsole(msgGettingConfig);
     if recordFileName = '' then
-        SendIPCAndWaitReply('C')        // ask for game config
+    begin
+        InitIPC;
+        SendIPCAndWaitReply('C');        // ask for game config
+    end
     else
+    begin
         LoadRecordFromFile(recordFileName);
+        perfExt_SaveBeganSynching();
+    end;
 
     ScriptOnGameInit;
 
@@ -316,13 +317,13 @@
 begin
     Randomize();
 
-    uConsts.initModule;
+    // uConsts does not need initialization as they are all consts
     uMisc.initModule;
     uConsole.initModule;    // MUST happen after uMisc
 
     uLand.initModule;
     uIO.initModule;
-    
+
     if complete then
     begin
         uAI.initModule;
@@ -341,7 +342,7 @@
         //uLandTemplates does not need initialization
         uLandTexture.initModule;
         //uLocale does not need initialization
-        uRandom.initModule; 
+        uRandom.initModule;
         uScript.initModule;
         uSound.initModule;
         uStats.initModule;
@@ -381,19 +382,19 @@
         //uAIActions does not need to be freed
         uAI.freeModule;             //stub
     end;
-    
+
     uIO.freeModule;             //stub
     uLand.freeModule;
 
     uConsole.freeModule;
     uMisc.freeModule;           // uMisc closes the debug log.
-    uConsts.freeModule;         //stub
 end;
 
 /////////////////////////
 procedure GenLandPreview{$IFDEF HWLIBRARY}(port: LongInt); cdecl; export{$ENDIF};
 var Preview: TPreview;
 begin
+    cLogfileBase:= 'preview';
     initEverything(false);
 {$IFDEF HWLIBRARY}
     WriteLnToConsole('Preview connecting on port ' + inttostr(port));
@@ -419,134 +420,38 @@
 begin
     WriteLn('Wrong argument format: correct configurations is');
     WriteLn();
-    WriteLn('  hwengine <path to data folder> <path to replay file> [option]');
+    WriteLn('  hwengine <path to data folder> <path to replay file> [options]');
     WriteLn();
-    WriteLn('where [option] must be specified either as');
+    WriteLn('where [options] must be specified either as:');
     WriteLn(' --set-video [screen width] [screen height] [color dept]');
     WriteLn(' --set-audio [volume] [enable music] [enable sounds]');
     WriteLn(' --set-other [language file] [full screen] [show FPS]');
-    WriteLn(' --set-multimedia [screen height] [screen width] [color dept] [volume] [enable music] [enable sounds] [language file] [full screen]');
-    WriteLn(' --set-everything [screen height] [screen width] [color dept] [volume] [enable music] [enable sounds] [language file] [full screen] [show FPS] [alternate damage] [timer value] [reduced quality]');
+    WriteLn(' --set-multimedia [screen width] [screen height] [color dept] [volume] [enable music] [enable sounds] [language file] [full screen]');
+    WriteLn(' --set-everything [screen width] [screen height] [color dept] [volume] [enable music] [enable sounds] [language file] [full screen] [show FPS] [alternate damage] [timer value] [reduced quality]');
     WriteLn();
-    WriteLn('Read documentation online at http://www.hedgewars.org/node/1465 for more information');
-    Write('parsed command: ');
+    WriteLn('Read documentation online at http://code.google.com/p/hedgewars/wiki/CommandLineOptions for more information');
+    WriteLn();
+    Write('PARSED COMMAND: ');
     for i:=0 to ParamCount do
         Write(ParamStr(i) + ' ');
     WriteLn();
 end;
 
 ////////////////////
+{$INCLUDE "ArgParsers.inc"}
+
 procedure GetParams;
-var i : LongInt;
 begin
-    case ParamCount of
-        19: begin
-            val(ParamStr(2), cScreenWidth);
-            val(ParamStr(3), cScreenHeight);
-            cBitsStr:= ParamStr(4);
-            val(cBitsStr, cBits);
-            val(ParamStr(5), ipcPort);
-            cFullScreen:= ParamStr(6) = '1';
-            isSoundEnabled:= ParamStr(7) = '1';
-            //cVSyncInUse:= ParamStr(8) = '1';      //merged with rqFlags
-            //cWeaponTooltips:= ParamStr(9) = '1';  //merged with rqFlags
-            cLocaleFName:= ParamStr(10);
-            val(ParamStr(11), cInitVolume);
-            val(ParamStr(12), cTimerInterval);
-            PathPrefix:= ParamStr(13);
-            cShowFPS:= ParamStr(14) = '1';
-            cAltDamage:= ParamStr(15) = '1';
-            UserNick:= DecodeBase64(ParamStr(16));
-            isMusicEnabled:= ParamStr(17) = '1';
-            val(ParamStr(18), cReducedQuality);
-            val(ParamStr(19), i);
-            cStereoMode:= TStereoMode(max(0, min(ord(high(TStereoMode)), i)));
-        end;
-        3: begin
-            val(ParamStr(2), ipcPort);
-            GameType:= gmtLandPreview;
-            if ParamStr(3) <> 'landpreview' then 
-                OutError(errmsgShouldntRun, true);
-        end;
-        2: begin
-            PathPrefix:= ParamStr(1);
-            recordFileName:= ParamStr(2);
-        end;
-        6: begin
-            PathPrefix:= ParamStr(1);
-            recordFileName:= ParamStr(2);
-
-            if ParamStr(3) = '--set-video'  then
-            begin
-                val(ParamStr(4), cScreenWidth);
-                val(ParamStr(5), cScreenHeight);
-                cBitsStr:= ParamStr(6);
-                val(cBitsStr, cBits);
-            end
+    if (ParamCount < 2) then
+        GameType:= gmtSyntax
+    else
+        if (ParamCount = 3) then
+            internalSetGameTypeLandPreviewFromParameters()
+        else
+            if (ParamCount = cDefaultParamNum) then
+                internalStartGameWithParameters()
             else
-            begin
-                if ParamStr(3) = '--set-audio' then
-                begin
-                    val(ParamStr(4), cInitVolume);
-                    isMusicEnabled:= ParamStr(5) = '1';
-                    isSoundEnabled:= ParamStr(6) = '1';
-                end
-                else
-                begin
-                    if ParamStr(3) = '--set-other' then
-                    begin
-                        cLocaleFName:= ParamStr(4);
-                        cFullScreen:= ParamStr(5) = '1';
-                        cShowFPS:= ParamStr(6) = '1';
-                    end
-                    else GameType:= gmtSyntax;
-                end
-            end;
-        end;
-        11: begin
-            PathPrefix:= ParamStr(1);
-            recordFileName:= ParamStr(2);
-
-            if ParamStr(3) = '--set-multimedia' then
-            begin
-                val(ParamStr(4), cScreenWidth);
-                val(ParamStr(5), cScreenHeight);
-                cBitsStr:= ParamStr(6);
-                val(cBitsStr, cBits);
-                val(ParamStr(7), cInitVolume);
-                isMusicEnabled:= ParamStr(8) = '1';
-                isSoundEnabled:= ParamStr(9) = '1';
-                cLocaleFName:= ParamStr(10);
-                cFullScreen:= ParamStr(11) = '1';
-            end
-            else GameType:= gmtSyntax;
-        end;
-        15: begin
-            PathPrefix:= ParamStr(1);
-            recordFileName:= ParamStr(2);
-            if ParamStr(3) = '--set-everything' then
-            begin
-                val(ParamStr(4), cScreenWidth);
-                val(ParamStr(5), cScreenHeight);
-                cBitsStr:= ParamStr(6);
-                val(cBitsStr, cBits);
-                val(ParamStr(7), cInitVolume);
-                isMusicEnabled:= ParamStr(8) = '1';
-                isSoundEnabled:= ParamStr(9) = '1';
-                cLocaleFName:= ParamStr(10);
-                cFullScreen:= ParamStr(11) = '1';
-                cAltDamage:= ParamStr(12) = '1';
-                cShowFPS:= ParamStr(13) = '1';
-                val(ParamStr(14), cTimerInterval);
-                if (ParamStr(15) = '1') then        //HACK
-                    cReducedQuality:= $FFFFFFFF xor rqLowRes
-                else
-                    val(ParamStr(15), cReducedQuality);
-            end
-            else GameType:= gmtSyntax;
-        end;
-        else GameType:= gmtSyntax;
-    end;
+                playReplayFileWithParameters();
 end;
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -558,7 +463,7 @@
     if GameType = gmtLandPreview then GenLandPreview()
     else if GameType = gmtSyntax then DisplayUsage()
     else Game();
-    
+
     if GameType = gmtSyntax then
         ExitCode:= 1
     else
--- a/hedgewars/options.inc	Thu Aug 26 23:59:18 2010 +0200
+++ b/hedgewars/options.inc	Wed Oct 27 14:02:20 2010 +0200
@@ -25,7 +25,7 @@
 {$MODE OBJFPC}
 {$MACRO ON}
 
-{$DEFINE GLunit:=GL,GLext} 
+{$DEFINE GLunit:=GL,GLext}
 
 {$IFDEF IPHONEOS}
   {$DEFINE SDL13}
--- a/hedgewars/uAI.pas	Thu Aug 26 23:59:18 2010 +0200
+++ b/hedgewars/uAI.pas	Wed Oct 27 14:02:20 2010 +0200
@@ -71,7 +71,7 @@
     if (Targets.ar[i].Score >= 0) and (not StopThinking) then
        begin
        with CurrentHedgehog^ do
-            a:= Ammo^[CurSlot, CurAmmo].AmmoType;
+            a:= CurAmmoType;
        aa:= a;
        repeat
         if (CanUseAmmo[a]) and
@@ -212,7 +212,7 @@
     Pop(ticks, Actions, Me^);
 
     AddAction(Actions, Me^.Message, aim_push, 250, 0, 0);
-    if (Me^.Message and gm_Left) <> 0 then AddAction(Actions, aia_WaitXL, hwRound(Me^.X), 0, 0, 0)
+    if (Me^.Message and gmLeft) <> 0 then AddAction(Actions, aia_WaitXL, hwRound(Me^.X), 0, 0, 0)
                                       else AddAction(Actions, aia_WaitXR, hwRound(Me^.X), 0, 0, 0);
     steps:= 0;
 
--- a/hedgewars/uAIAmmoTests.pas	Thu Aug 26 23:59:18 2010 +0200
+++ b/hedgewars/uAIAmmoTests.pas	Wed Oct 27 14:02:20 2010 +0200
@@ -71,7 +71,8 @@
             (proc: nil;              flags: 0), // amMineStrike
             (proc: nil;              flags: 0), // amBlowTorch
             (proc: nil;              flags: 0), // amGirder
-            (proc: @TestTeleport;    flags: amtest_OnTurn), // amTeleport
+            (proc: nil;              flags: 0), // amTeleport
+            //(proc: @TestTeleport;    flags: amtest_OnTurn), // amTeleport
             (proc: nil;              flags: 0), // amSwitch
             (proc: @TestMortar;      flags: 0), // amMortar
             (proc: nil;              flags: 0), // amKamikaze
@@ -97,13 +98,16 @@
             (proc: nil;              flags: 0), // amPiano
             (proc: @TestGrenade;     flags: 0), // amGasBomb
             (proc: @TestShotgun;     flags: 0), // amSineGun
-            (proc: nil;              flags: 0)  // amFlamethrower
+            (proc: nil;              flags: 0), // amFlamethrower
+            (proc: @TestGrenade;     flags: 0), // amSMine
+            (proc: @TestFirePunch;   flags: 0), // amHammer
+            (proc: nil;              flags: 0) // amResurrector
             );
 
 const BadTurn = Low(LongInt) div 4;
 
 implementation
-uses uMisc, uAIMisc, uLand, uTeams;
+uses uMisc, uAIMisc, uLand;
 
 function Metric(x1, y1, x2, y2: LongInt): LongInt;
 begin
@@ -121,11 +125,8 @@
         t: LongInt;
         value: LongInt;
     begin
-    with PHedgehog(Me^.Hedgehog)^ do
-        begin
-        x:= Me^.X + int2hwfloat(round(GetLaunchX(Ammo^[CurSlot, CurAmmo].AmmoType, hwSign(Me^.dX), Me^.Angle)));
-        y:= Me^.Y + int2hwfloat(round(GetLaunchY(Ammo^[CurSlot, CurAmmo].AmmoType, Me^.Angle)))
-        end;
+    x:= Me^.X;
+    y:= Me^.Y;
     dX:= Vx;
     dY:= -Vy;
     t:= rTime;
@@ -179,11 +180,8 @@
     var x, y, dY: hwFloat;
         t: LongInt;
     begin
-    with PHedgehog(Me^.Hedgehog)^ do
-        begin
-        x:= Me^.X + int2hwfloat(round(GetLaunchX(Ammo^[CurSlot, CurAmmo].AmmoType, hwSign(Me^.dX), Me^.Angle)));
-        y:= Me^.Y + int2hwfloat(round(GetLaunchY(Ammo^[CurSlot, CurAmmo].AmmoType, Me^.Angle)))
-        end;
+    x:= Me^.X;
+    y:= Me^.Y;
     dY:= -Vy;
     t:= TestTime;
     repeat
@@ -234,11 +232,8 @@
     var x, y, dY: hwFloat;
         t: LongInt;
     begin
-    with PHedgehog(Me^.Hedgehog)^ do
-        begin
-        x:= Me^.X + int2hwfloat(round(GetLaunchX(Ammo^[CurSlot, CurAmmo].AmmoType, hwSign(Me^.dX), Me^.Angle)));
-        y:= Me^.Y + int2hwfloat(round(GetLaunchY(Ammo^[CurSlot, CurAmmo].AmmoType, Me^.Angle)))
-        end;
+    x:= Me^.X;
+    y:= Me^.Y;
     dY:= -Vy;
     t:= TestTime;
     repeat
@@ -289,11 +284,8 @@
     var x, y, dY: hwFloat;
         t: LongInt;
     begin
-    with PHedgehog(Me^.Hedgehog)^ do
-        begin
-        x:= Me^.X + int2hwfloat(round(GetLaunchX(Ammo^[CurSlot, CurAmmo].AmmoType, hwSign(Me^.dX), Me^.Angle)));
-        y:= Me^.Y + int2hwfloat(round(GetLaunchY(Ammo^[CurSlot, CurAmmo].AmmoType, Me^.Angle)))
-        end;
+    x:= Me^.X;
+    y:= Me^.Y;
     dY:= -Vy;
     t:= TestTime;
     repeat
@@ -348,11 +340,8 @@
     var x, y, dY: hwFloat;
         t: LongInt;
     begin
-    with PHedgehog(Me^.Hedgehog)^ do
-        begin
-        x:= Me^.X + int2hwfloat(round(GetLaunchX(Ammo^[CurSlot, CurAmmo].AmmoType, hwSign(Me^.dX), Me^.Angle)));
-        y:= Me^.Y + int2hwfloat(round(GetLaunchY(Ammo^[CurSlot, CurAmmo].AmmoType, Me^.Angle)))
-        end;
+    x:= Me^.X;
+    y:= Me^.Y;
     dY:= -Vy;
     t:= TestTime;
     repeat
@@ -381,7 +370,7 @@
      if valueResult < Score then
         begin
         ap.Angle:= DxDy2AttackAngle(Vx, Vy) + AIrndSign(random(Level));
-        ap.Power:= hwRound(r * cMaxPower) + AIrndSign(random(Level) * 15);
+        ap.Power:= hwRound(r * cMaxPower * _0_9) + AIrndSign(random(Level) * 15);
         ap.Time:= TestTime;
         ap.ExplR:= 300;
         ap.ExplX:= EX;
@@ -403,11 +392,8 @@
     var x, y, dY: hwFloat;
         value: LongInt;
     begin
-    with PHedgehog(Me^.Hedgehog)^ do
-        begin
-        x:= Me^.X + int2hwfloat(round(GetLaunchX(Ammo^[CurSlot, CurAmmo].AmmoType, hwSign(Me^.dX), Me^.Angle)));
-        y:= Me^.Y + int2hwfloat(round(GetLaunchY(Ammo^[CurSlot, CurAmmo].AmmoType, Me^.Angle)))
-        end;
+        x:= Me^.X;
+        y:= Me^.Y;
         dY:= -Vy;
 
         repeat
@@ -491,11 +477,8 @@
 ap.ExplR:= 0;
 ap.Time:= 0;
 ap.Power:= 1;
-with PHedgehog(Me^.Hedgehog)^ do
-    begin
-    x:= Me^.X + int2hwfloat(round(GetLaunchX(Ammo^[CurSlot, CurAmmo].AmmoType, hwSign(Me^.dX), Me^.Angle)));
-    y:= Me^.Y + int2hwfloat(round(GetLaunchY(Ammo^[CurSlot, CurAmmo].AmmoType, Me^.Angle)))
-    end;
+x:= Me^.X;
+y:= Me^.Y;
 range:= Metric(hwRound(x), hwRound(y), Targ.X, Targ.Y);
 if ( range < MIN_RANGE ) or ( range > MAX_RANGE ) then exit(BadTurn);
 Vx:= (int2hwFloat(Targ.X) - x) * _1div1024;
@@ -528,11 +511,8 @@
 ap.ExplR:= 0;
 ap.Time:= 0;
 ap.Power:= 1;
-with PHedgehog(Me^.Hedgehog)^ do
-    begin
-    x:= Me^.X + int2hwfloat(round(GetLaunchX(Ammo^[CurSlot, CurAmmo].AmmoType, hwSign(Me^.dX), Me^.Angle)));
-    y:= Me^.Y + int2hwfloat(round(GetLaunchY(Ammo^[CurSlot, CurAmmo].AmmoType, Me^.Angle)))
-    end;
+x:= Me^.X;
+y:= Me^.Y;
 if Abs(hwRound(Me^.X) - Targ.X) + Abs(hwRound(Me^.Y) - Targ.Y) < 80 then
    exit(BadTurn);
 t:= _0_5 / Distance(int2hwFloat(Targ.X) - x, int2hwFloat(Targ.Y) - y);
@@ -564,11 +544,8 @@
 
 ap.Time:= 0;
 ap.Power:= 1;
-with PHedgehog(Me^.Hedgehog)^ do
-    begin
-    x:= Me^.X + int2hwfloat(round(GetLaunchX(Ammo^[CurSlot, CurAmmo].AmmoType, hwSign(Me^.dX), Me^.Angle)));
-    y:= Me^.Y + int2hwfloat(round(GetLaunchY(Ammo^[CurSlot, CurAmmo].AmmoType, Me^.Angle)))
-    end;
+x:= Me^.X;
+y:= Me^.Y;
 if (Targ.X) - hwRound(x) >= 0 then ap.Angle:=   cMaxAngle div 4
                                   else ap.Angle:= - cMaxAngle div 4;
 valueResult:= RateShove(Me, hwRound(x) + 10 * hwSign(int2hwFloat(Targ.X) - x), hwRound(y), 15, 30);
@@ -585,11 +562,8 @@
 ap.Time:= 0;
 ap.Power:= 1;
 ap.Angle:= 0;
-with PHedgehog(Me^.Hedgehog)^ do
-    begin
-    x:= Me^.X + int2hwfloat(round(GetLaunchX(Ammo^[CurSlot, CurAmmo].AmmoType, hwSign(Me^.dX), Me^.Angle)));
-    y:= Me^.Y + int2hwfloat(round(GetLaunchY(Ammo^[CurSlot, CurAmmo].AmmoType, Me^.Angle)))
-    end;
+x:= Me^.X;
+y:= Me^.Y;
 if (Abs(hwRound(x) - Targ.X) > 25)
 or (Abs(hwRound(y) - 50 - Targ.Y) > 50) then
     begin
@@ -689,7 +663,7 @@
     FillBonuses(true, [gtCase]);
     if bonuses.Count = 0 then begin
         if Me^.Health <= 100  then begin
-            maxTop := Targ.Y - cHHRadius * 2; 
+            maxTop := Targ.Y - cHHRadius * 2;
             while not TestColl(Targ.X, maxTop, cHHRadius) and (maxTop > topY + cHHRadius * 2 + 1) do
             dec(maxTop, cHHRadius*2);
             if not TestColl(Targ.X, maxTop + cHHRadius, cHHRadius) then begin
@@ -701,7 +675,7 @@
     end
     else begin
         failNum := 0;
-        repeat 
+        repeat
             i := random(bonuses.Count);
             inc(failNum);
         until not TestColl(bonuses.ar[i].X, bonuses.ar[i].Y - cHHRadius - bonuses.ar[i].Radius, cHHRadius) or (failNum = bonuses.Count*2);
--- a/hedgewars/uAIMisc.pas	Thu Aug 26 23:59:18 2010 +0200
+++ b/hedgewars/uAIMisc.pas	Wed Oct 27 14:02:20 2010 +0200
@@ -76,7 +76,7 @@
 var friendlyfactor: LongInt = 300;
     KnownExplosion: record
                     X, Y, Radius: LongInt
-                    end = (X: 0; Y: 0; Radius: 0); 
+                    end = (X: 0; Y: 0; Radius: 0);
 
 procedure FillTargets;
 var i, t: Longword;
@@ -195,7 +195,7 @@
         MeX:= hwRound(Me^.X);
         MeY:= hwRound(Me^.Y);
         // We are still inside the hog. Skip radius test
-        if ((((x-MeX)*(x-MeX)) + ((y-MeY)*(y-MeY))) < 256) and 
+        if ((((x-MeX)*(x-MeX)) + ((y-MeY)*(y-MeY))) < 256) and
            ((Land[y, x] and $FF00) = 0) then exit(false);
         end;
     exit(TestColl(x, y, r))
@@ -404,8 +404,8 @@
       end;
    continue
    end;
-   if (Gear^.Message and gm_Left  )<>0 then Gear^.dX:= -cLittle else
-   if (Gear^.Message and gm_Right )<>0 then Gear^.dX:=  cLittle else exit(bRes);
+   if (Gear^.Message and gmLeft  )<>0 then Gear^.dX:= -cLittle else
+   if (Gear^.Message and gmRight )<>0 then Gear^.dX:=  cLittle else exit(bRes);
    if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) then
       begin
       if not (TestCollisionXwithXYShift(Gear, _0, -6, hwSign(Gear^.dX))
--- a/hedgewars/uAmmos.pas	Thu Aug 26 23:59:18 2010 +0200
+++ b/hedgewars/uAmmos.pas	Wed Oct 27 14:02:20 2010 +0200
@@ -42,16 +42,18 @@
 procedure DisableSomeWeapons;
 procedure ResetWeapons;
 function  GetAmmoByNum(num: Longword): PHHAmmo;
+function  GetAmmoEntry(var Hedgehog: THedgehog): PAmmo;
 
 var shoppa: boolean;
+    StoreCnt: Longword;
 
 implementation
-uses uMisc, uGears, uWorld, uLocale, uConsole;
+uses uMisc, uGears, uWorld, uLocale, uConsole, uMobile;
 
 type TAmmoCounts = array[TAmmoType] of Longword;
 var StoresList: array[0..Pred(cMaxHHs)] of PHHAmmo;
-    StoreCnt: Longword;
     ammoLoadout, ammoProbability, ammoDelay, ammoReinforcement: shortstring;
+    InitialCounts: array[0..Pred(cMaxHHs)] of TAmmoCounts;
 
 procedure FillAmmoStore(Ammo: PHHAmmo; var cnts: TAmmoCounts);
 var mi: array[0..cMaxSlotIndex] of byte;
@@ -67,21 +69,19 @@
        begin
        TryDo(mi[Ammoz[a].Slot] <= cMaxSlotAmmoIndex, 'Ammo slot overflow', true);
        Ammo^[Ammoz[a].Slot, mi[Ammoz[a].Slot]]:= Ammoz[a].Ammo;
-
-       Ammo^[Ammoz[a].Slot, mi[Ammoz[a].Slot]].Count:= cnts[a];
-       Ammo^[Ammoz[a].Slot, mi[Ammoz[a].Slot]].InitialCount:= cnts[a];
-
-       if ((GameFlags and gfPlaceHog) <> 0) and (a = amTeleport) then 
-           Ammo^[Ammoz[a].Slot, mi[Ammoz[a].Slot]].Count:= AMMO_INFINITE;
+       with Ammo^[Ammoz[a].Slot, mi[Ammoz[a].Slot]] do
+           begin
+           Count:= cnts[a];
+           if (TotalRounds < 0) and ((GameFlags and gfPlaceHog) <> 0) and (a = amTeleport) then Count:= AMMO_INFINITE;
+           end;
        inc(mi[Ammoz[a].Slot])
        end
-    else if (TotalRounds < 0) and ((GameFlags and gfPlaceHog) <> 0) and (a = amTeleport) then 
+    else if (TotalRounds < 0) and ((GameFlags and gfPlaceHog) <> 0) and (a = amTeleport) then
        begin
        TryDo(mi[Ammoz[a].Slot] <= cMaxSlotAmmoIndex, 'Ammo slot overflow', true);
        Ammo^[Ammoz[a].Slot, mi[Ammoz[a].Slot]]:= Ammoz[a].Ammo;
 
        Ammo^[Ammoz[a].Slot, mi[Ammoz[a].Slot]].Count:= AMMO_INFINITE;
-       Ammo^[Ammoz[a].Slot, mi[Ammoz[a].Slot]].InitialCount:= 0;
 
        inc(mi[Ammoz[a].Slot])
        end
@@ -99,7 +99,7 @@
 
 // FIXME - TEMPORARY hardcoded check on shoppa pending creation of crate *type* probability editor
 substr:= Copy(ammoLoadout,1,15);
-if (substr = '000000990000009') or 
+if (substr = '000000990000009') or
    (substr = '000000990000000') then
     shoppa:= true;
 
@@ -137,16 +137,16 @@
             end;
         ammos[a]:= cnt;
 
-        if ((GameFlags and gfKing) <> 0) and ((GameFlags and gfPlaceHog) = 0) and (Ammoz[a].SkipTurns = 0) and (a <> amTeleport) and (a <> amSkip) then 
+        if ((GameFlags and gfKing) <> 0) and ((GameFlags and gfPlaceHog) = 0) and (Ammoz[a].SkipTurns = 0) and (a <> amTeleport) and (a <> amSkip) then
             Ammoz[a].SkipTurns:= 1;
 
         if ((GameFlags and gfPlaceHog) <> 0) and
-            (a <> amTeleport) and (a <> amSkip) and 
+            (a <> amTeleport) and (a <> amSkip) and
             (Ammoz[a].SkipTurns < 10000) then inc(Ammoz[a].SkipTurns,10000)
-        end else
-        ammos[a]:= AMMO_INFINITE
+        end 
+    else ammos[a]:= AMMO_INFINITE;
+    InitialCounts[Pred(StoreCnt)][a]:= ammos[a];
     end;
-
 FillAmmoStore(StoresList[Pred(StoreCnt)], ammos)
 end;
 
@@ -156,6 +156,18 @@
 exit(StoresList[num])
 end;
 
+function GetAmmoEntry(var Hedgehog: THedgehog): PAmmo;
+var ammoidx, slot: LongWord;
+begin
+with Hedgehog do
+    begin
+    slot:= Ammoz[CurAmmoType].Slot;
+    ammoidx:= 0;
+    while (ammoidx < cMaxSlotAmmoIndex) and (Ammo^[slot, ammoidx].AmmoType <> CurAmmoType) do inc(ammoidx);
+    GetAmmoEntry:= @Ammo^[slot, ammoidx];
+    end
+end;
+
 procedure AssignStores;
 var t: LongInt;
     i: Longword;
@@ -165,7 +177,10 @@
       begin
       for i:= 0 to cMaxHHIndex do
           if Hedgehogs[i].Gear <> nil then
+             begin
              Hedgehogs[i].Ammo:= GetAmmoByNum(Hedgehogs[i].AmmoStore);
+             Hedgehogs[i].CurAmmoType:= amNothing;
+             end
       end
 end;
 
@@ -213,21 +228,26 @@
 end;
 
 procedure OnUsedAmmo(var Hedgehog: THedgehog);
+var CurWeapon: PAmmo;
 begin
+CurWeapon:= GetAmmoEntry(Hedgehog);
 with Hedgehog do
     begin
+
     MultiShootAttacks:= 0;
-    with Ammo^[CurSlot, CurAmmo] do
+    with CurWeapon^ do
         if Count <> AMMO_INFINITE then
             begin
             dec(Count);
             if Count = 0 then
                 begin
-                PackAmmo(Ammo, CurSlot);
-                SwitchNotHeldAmmo(Hedgehog)
+                PackAmmo(Ammo, Ammoz[AmmoType].Slot);
+                //SwitchNotHeldAmmo(Hedgehog);
+                CurAmmoType:= amNothing
                 end
             end
-    end
+    end;
+perfExt_AmmoUpdate;
 end;
 
 function  HHHasAmmo(var Hedgehog: THedgehog; Ammo: TAmmoType): boolean;
@@ -264,33 +284,37 @@
 end;
 
 procedure SwitchToFirstLegalAmmo(var Hedgehog: THedgehog);
+var slot, ammoidx: LongWord;
 begin
 with Hedgehog do
     begin
-    CurAmmo:= 0;
-    CurSlot:= 0;
-    while (CurSlot <= cMaxSlotIndex) and
-        ((Ammo^[CurSlot, CurAmmo].Count = 0) or
-        (Ammoz[Ammo^[CurSlot, CurAmmo].AmmoType].SkipTurns - CurrentTeam^.Clan^.TurnNumber >= 0))
+    CurAmmoType:= amNothing;
+    slot:= 0;
+    ammoidx:= 0;
+    while (slot <= cMaxSlotIndex) and
+        ((Ammo^[slot, ammoidx].Count = 0) or
+        (Ammoz[Ammo^[slot, ammoidx].AmmoType].SkipTurns - CurrentTeam^.Clan^.TurnNumber >= 0))
         do
         begin
-        while (CurAmmo <= cMaxSlotAmmoIndex) and
-            ((Ammo^[CurSlot, CurAmmo].Count = 0) or
-            (Ammoz[Ammo^[CurSlot, CurAmmo].AmmoType].SkipTurns - CurrentTeam^.Clan^.TurnNumber >= 0))
-            do inc(CurAmmo);
+        while (ammoidx <= cMaxSlotAmmoIndex) and
+            ((Ammo^[slot, ammoidx].Count = 0) or
+            (Ammoz[Ammo^[slot, ammoidx].AmmoType].SkipTurns - CurrentTeam^.Clan^.TurnNumber >= 0))
+            do inc(ammoidx);
 
-        if (CurAmmo > cMaxSlotAmmoIndex) then
+        if (ammoidx > cMaxSlotAmmoIndex) then
             begin
-            CurAmmo:= 0;
-            inc(CurSlot)
+            ammoidx:= 0;
+            inc(slot)
             end
         end;
-    TryDo(CurSlot <= cMaxSlotIndex, 'Ammo slot index overflow', true)
+    TryDo(slot <= cMaxSlotIndex, 'Ammo slot index overflow', true);
+    CurAmmoType:= Ammo^[slot, ammoidx].AmmoType;
     end
 end;
 
 procedure ApplyAmmoChanges(var Hedgehog: THedgehog);
 var s: shortstring;
+    CurWeapon: PAmmo;
 begin
 TargetPoint.X:= NoPointX;
 
@@ -298,13 +322,16 @@
     begin
     Timer:= 10;
 
-    if (Ammo^[CurSlot, CurAmmo].Count = 0) then
+    CurWeapon:= GetAmmoEntry(Hedgehog);
+
+    if (CurWeapon^.Count = 0) then
         SwitchToFirstLegalAmmo(Hedgehog);
 
-        //bad things could happen here in case CurSlot is overflowing
-    ApplyAngleBounds(Hedgehog, Ammo^[CurSlot, CurAmmo].AmmoType);
+    CurWeapon:= GetAmmoEntry(Hedgehog);
 
-    with Ammo^[CurSlot, CurAmmo] do
+    ApplyAngleBounds(Hedgehog, CurWeapon^.AmmoType);
+
+    with CurWeapon^ do
         begin
         if AmmoType <> amNothing then
             begin
@@ -323,19 +350,19 @@
             Gear^.State:= Gear^.State and not gstHHChooseTarget;
             isCursorVisible:= false
             end;
-        if (CurAmmoGear <> nil) and ((CurAmmoGear^.Ammo^.Propz and ammoprop_AltAttack) <> 0) then
-            ShowCrosshair:= (CurAmmoGear^.Ammo^.Propz and ammoprop_NoCrossHair) = 0
+        if (CurAmmoGear <> nil) and ((Ammoz[CurAmmoGear^.AmmoType].Ammo.Propz and ammoprop_AltAttack) <> 0) then
+            ShowCrosshair:= (Ammoz[CurAmmoGear^.AmmoType].Ammo.Propz and ammoprop_NoCrossHair) = 0
         else
             ShowCrosshair:= (Propz and ammoprop_NoCrosshair) = 0;
         end
-    end
+    end;
 end;
 
 procedure SwitchNotHeldAmmo(var Hedgehog: THedgehog);
 begin
 with Hedgehog do
-    if ((Ammo^[CurSlot, CurAmmo].Propz and ammoprop_DontHold) <> 0) or
-        (Ammoz[Ammo^[CurSlot, CurAmmo].AmmoType].SkipTurns - CurrentTeam^.Clan^.TurnNumber >= 0) then
+    if ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_DontHold) <> 0) or
+        (Ammoz[CurAmmoType].SkipTurns - CurrentTeam^.Clan^.TurnNumber >= 0) then
         SwitchToFirstLegalAmmo(Hedgehog);
 end;
 
@@ -353,10 +380,10 @@
         begin
         for a:= 0 to cMaxSlotAmmoIndex do
             with StoresList[i]^[slot, a] do
-                if (Propz and ammoprop_NotBorder) <> 0 then 
+                if (Propz and ammoprop_NotBorder) <> 0 then
                     begin
                     Count:= 0;
-                    InitialCount:= 0
+                    InitialCounts[i][AmmoType]:= 0
                     end;
 
         PackAmmo(StoresList[i], slot)
@@ -388,20 +415,17 @@
 
 // Restore indefinitely disabled weapons and initial weapon counts.  Only used for hog placement right now
 procedure ResetWeapons;
-var i, slot, a: Longword;
-    t: TAmmoType;
+var i, t: Longword;
+    a: TAmmoType;
 begin
-for i:= 0 to Pred(StoreCnt) do
-    for slot:= 0 to cMaxSlotIndex do
-        begin
-        for a:= 0 to cMaxSlotAmmoIndex do
-            with StoresList[i]^[slot, a] do
-                Count:= InitialCount;
+for t:= 0 to Pred(TeamsCount) do
+   with TeamsArray[t]^ do
+      for i:= 0 to cMaxHHIndex do
+          if Hedgehogs[i].Gear <> nil then
+             FillAmmoStore(Hedgehogs[i].Ammo, InitialCounts[Hedgehogs[i].AmmoStore]);
 
-        PackAmmo(StoresList[i], slot)
-        end;
-for t:= Low(TAmmoType) to High(TAmmoType) do
-    if Ammoz[t].SkipTurns >= 10000 then dec(Ammoz[t].SkipTurns,10000);
+for a:= Low(TAmmoType) to High(TAmmoType) do
+    if Ammoz[a].SkipTurns >= 10000 then dec(Ammoz[a].SkipTurns,10000)
 end;
 
 procedure initModule;
@@ -411,7 +435,8 @@
     ammoLoadout:= '';
     ammoProbability:= '';
     ammoDelay:= '';
-    ammoReinforcement:= ''
+    ammoReinforcement:= '';
+    FillChar(InitialCounts, sizeof(InitialCounts), 0)
 end;
 
 procedure freeModule;
--- a/hedgewars/uChat.pas	Thu Aug 26 23:59:18 2010 +0200
+++ b/hedgewars/uChat.pas	Wed Oct 27 14:02:20 2010 +0200
@@ -29,7 +29,7 @@
 procedure DrawChat;
 procedure KeyPressChat(Key: Longword);
 
-var UserNick: shortstring;
+var UserNick: shortstring = '';
     ChatReady: boolean;
     showAll: boolean;
 
@@ -253,11 +253,6 @@
             ParseCommand('/taunt ' + char(i), true);
             exit
             end;
-    if (s = '/newgrave') then
-        begin
-        ParseCommand('/newgrave', true);
-        exit
-        end;
     end
     else
         ParseCommand('/say ' + s, true);
@@ -316,7 +311,6 @@
 begin
     lastStr:= 0;
     visibleCount:= 0;
-    UserNick:= '';
     showAll:= false;
     ChatReady:= false;
     missedCount:= 0;
@@ -324,7 +318,7 @@
 
 procedure freeModule;
 begin
-
+    UserNick:= '';
 end;
 
 end.
--- a/hedgewars/uCollisions.pas	Thu Aug 26 23:59:18 2010 +0200
+++ b/hedgewars/uCollisions.pas	Wed Oct 27 14:02:20 2010 +0200
@@ -387,7 +387,7 @@
     for i:= 0 to 8 do
         begin
         // using mx,my as temporary value buffer here
-        
+
         jfr:= 8+li+1;
         jto:= 8+li-1;
 
--- a/hedgewars/uConsole.pas	Thu Aug 26 23:59:18 2010 +0200
+++ b/hedgewars/uConsole.pas	Wed Oct 27 14:02:20 2010 +0200
@@ -37,7 +37,7 @@
 procedure doPut(putX, putY: LongInt; fromAI: boolean);
 
 implementation
-uses uMisc, uStore, Types, uConsts, uGears, uTeams, uIO, uKeys, uWorld,
+uses uMisc, uStore, Types, uConsts, uGears, uTeams, uIO, uKeys, uWorld, uMobile,
      uRandom, uAmmos, uStats, uChat, SDLh, uSound, uVisualGears, uScript;
 
 const cLineWidth: LongInt = 0;
@@ -89,10 +89,11 @@
 var Len: LongInt;
     done: boolean;
 begin
+{$IFNDEF NOCONSOLE}
     {$IFDEF DEBUGFILE}AddFileLog('Console write: ' + s);{$ENDIF}
     Write(s);
     done:= false;
-    
+
     while not done do
     begin
         Len:= cLineWidth - Length(ConsoleLines[CurrLine].s);
@@ -106,16 +107,19 @@
         end;
         done:= (Length(s) = 0);
     end;
+{$ENDIF}
 end;
 
 procedure WriteLnToConsole(s: shortstring);
 begin
+{$IFNDEF NOCONSOLE}
     WriteToConsole(s);
     WriteLn;
     inc(CurrLine);
     if CurrLine = cLinesCount then
         CurrLine:= 0;
     PByte(@ConsoleLines[CurrLine].s)^:= 0
+{$ENDIF}
 end;
 
 procedure ParseCommand(CmdStr: shortstring; TrustedSource: boolean);
@@ -190,11 +194,11 @@
 
 procedure StopMessages(Message: Longword);
 begin
-if (Message and gm_Left) <> 0 then ParseCommand('/-left', true) else
-if (Message and gm_Right) <> 0 then ParseCommand('/-right', true) else
-if (Message and gm_Up) <> 0 then ParseCommand('/-up', true) else
-if (Message and gm_Down) <> 0 then ParseCommand('/-down', true) else
-if (Message and gm_Attack) <> 0 then ParseCommand('/-attack', true)
+if (Message and gmLeft) <> 0 then ParseCommand('/-left', true) else
+if (Message and gmRight) <> 0 then ParseCommand('/-right', true) else
+if (Message and gmUp) <> 0 then ParseCommand('/-up', true) else
+if (Message and gmDown) <> 0 then ParseCommand('/-down', true) else
+if (Message and gmAttack) <> 0 then ParseCommand('/-attack', true)
 end;
 
 {$INCLUDE "CCHandlers.inc"}
@@ -204,14 +208,17 @@
     CurrLine:= 0;
     Variables:= nil;
     isDeveloperMode:= true;
-    
+
     // initConsole
     cLineWidth:= cScreenWidth div 10;
     if cLineWidth > 255 then
         cLineWidth:= 255;
-    for i:= 0 to Pred(cLinesCount) do 
+    for i:= 0 to Pred(cLinesCount) do
         PByte(@ConsoleLines[i])^:= 0;
-    
+
+    // NOTE: please, keep most frequently used commands on bottom
+    RegisterVariable('flag'    , vtCommand, @chFlag         , false);
+    RegisterVariable('script'  , vtCommand, @chScript       , false);
     RegisterVariable('proto'   , vtCommand, @chCheckProto   , true );
     RegisterVariable('spectate', vtBoolean, @fastUntilLag   , false);
     RegisterVariable('capture' , vtCommand, @chCapture      , true );
@@ -225,6 +232,7 @@
     RegisterVariable('mapgen'  , vtLongInt, @cMapGen        , false);
     RegisterVariable('maze_size',vtLongInt, @cMazeSize      , false);
     RegisterVariable('delay'   , vtLongInt, @cInactDelay    , false);
+    RegisterVariable('ready'   , vtLongInt, @cReadyDelay    , false);
     RegisterVariable('casefreq', vtLongInt, @cCaseFactor    , false);
     RegisterVariable('sd_turns', vtLongInt, @cSuddenDTurns  , false);
     RegisterVariable('damagepct',vtLongInt, @cDamagePercent , false);
@@ -257,7 +265,6 @@
     RegisterVariable('skip'    , vtCommand, @chSkip         , false);
     RegisterVariable('history' , vtCommand, @chHistory      , true );
     RegisterVariable('chat'    , vtCommand, @chChat         , true );
-    RegisterVariable('newgrave', vtCommand, @chNewGrave     , false);
     RegisterVariable('say'     , vtCommand, @chSay          , true );
     RegisterVariable('hogsay'  , vtCommand, @chHogSay       , true );
     RegisterVariable('team'    , vtCommand, @chTeamSay      , true );
@@ -298,8 +305,6 @@
     RegisterVariable('-cur_l'  , vtCommand, @chCurL_m       , true );
     RegisterVariable('+cur_r'  , vtCommand, @chCurR_p       , true );
     RegisterVariable('-cur_r'  , vtCommand, @chCurR_m       , true );
-    RegisterVariable('flag'    , vtCommand, @chFlag         , false);
-    RegisterVariable('script'  , vtCommand, @chScript       , false);
 end;
 
 procedure freeModule;
--- a/hedgewars/uConsts.pas	Thu Aug 26 23:59:18 2010 +0200
+++ b/hedgewars/uConsts.pas	Wed Oct 27 14:02:20 2010 +0200
@@ -33,14 +33,14 @@
     HwColor4f = record
         r, g, b, a: byte
         end;
-        
+
     TGameState = (gsLandGen, gsStart, gsGame, gsChat, gsConfirm, gsExit);
 
     TGameType = (gmtLocal, gmtDemo, gmtNet, gmtSave, gmtLandPreview, gmtSyntax);
 
     TPathType = (ptNone, ptData, ptGraphics, ptThemes, ptCurrTheme, ptTeams, ptMaps,
             ptMapCurrent, ptDemos, ptSounds, ptGraves, ptFonts, ptForts,
-            ptLocale, ptAmmoMenu, ptHedgehog, ptVoices, ptHats, ptFlags);
+            ptLocale, ptAmmoMenu, ptHedgehog, ptVoices, ptHats, ptFlags, ptMissionMaps);
 
     TSprite = (sprWater, sprCloud, sprBomb, sprBigDigit, sprFrame,
             sprLag, sprArrow, sprGrenade, sprTargetP, sprBee,
@@ -71,11 +71,12 @@
             sprAmTeleport, sprSplash, sprDroplet, sprBirdy, sprHandCake, sprHandConstruction,
             sprHandGrenade, sprHandMelon, sprHandMortar, sprHandSkip, sprHandCluster,
             sprHandDynamite, sprHandHellish, sprHandMine, sprHandSeduction, sprHandVamp,
-            sprBigExplosion, sprSmokeRing, sprBeeTrace, sprEgg, sprTargetBee, sprHandBee, 
+            sprBigExplosion, sprSmokeRing, sprBeeTrace, sprEgg, sprTargetBee, sprHandBee,
             sprFeather, sprPiano, sprHandSineGun, sprPortalGun, sprPortal,
-            sprCheese, sprHandCheese, sprHandFlamethrower
+            sprCheese, sprHandCheese, sprHandFlamethrower, sprChunk, sprNote,
+            sprSMineOff, sprSMineOn, sprHandSMine, sprHammer, sprHandResurrector
             );
-    
+
     // Gears that interact with other Gears and/or Land
     TGearType = (gtAmmo_Bomb, gtHedgehog, gtAmmo_Grenade, gtGrave, gtBee, // 4
             gtShotgunShot, gtPickHammer, gtRope, gtMine, gtCase, // 9
@@ -86,7 +87,8 @@
             gtWhip, gtKamikaze, gtCake, gtSeduction, gtWatermelon, gtMelonPiece, // 34
             gtHellishBomb, gtWaterUp, gtDrill, gtBallGun, gtBall, gtRCPlane, // 40
             gtSniperRifleShot, gtJetpack, gtMolotov, gtExplosives, gtBirdy, // 45
-            gtEgg, gtPortal, gtPiano, gtGasBomb, gtSineGunShot, gtFlamethrower); // 51
+            gtEgg, gtPortal, gtPiano, gtGasBomb, gtSineGunShot, gtFlamethrower, // 51
+            gtSMine, gtPoisonCloud, gtHammer, gtHammerHit, gtResurrector);
 
     // Gears that are _only_ of visual nature (e.g. background stuff, visual effects, speechbubbles, etc.)
     TVisualGearType = (vgtFlake, vgtCloud, vgtExplPart, vgtExplPart2, vgtFire,
@@ -94,7 +96,7 @@
             vgtSteam, vgtAmmo, vgtSmoke, vgtSmokeWhite, vgtHealth, vgtShell,
             vgtDust, vgtSplash, vgtDroplet, vgtSmokeRing, vgtBeeTrace, vgtEgg,
             vgtFeather, vgtHealthTag, vgtSmokeTrace, vgtEvilTrace, vgtExplosion,
-            vgtBigExplosion);
+            vgtBigExplosion, vgtChunk, vgtNote);
 
     TGearsType = set of TGearType;
 
@@ -120,24 +122,29 @@
             sndMelonImpact, sndDroplet1, sndDroplet2, sndDroplet3, sndEggBreak, sndDrillRocket,
             sndPoisonCough, sndPoisonMoan, sndBirdyLay, sndWhistle, sndBeeWater,
             sndPiano0, sndPiano1, sndPiano2, sndPiano3, sndPiano4, sndPiano5, sndPiano6, sndPiano7, sndPiano8,
-            sndSkip, sndSineGun, sndOoff1, sndOoff2, sndOoff3);
+            sndSkip, sndSineGun, sndOoff1, sndOoff2, sndOoff3, sndWhack,
+            sndComeonthen, sndParachute, sndBump, sndResurrector);
 
-    TAmmoType  = (amNothing, amGrenade, amClusterBomb, amBazooka, amBee, amShotgun, amPickHammer,
-            amSkip, amRope, amMine, amDEagle, amDynamite, amFirePunch, amWhip,
-            amBaseballBat, amParachute, amAirAttack, amMineStrike, amBlowTorch,
-            amGirder, amTeleport, amSwitch, amMortar, amKamikaze, amCake,
-            amSeduction, amWatermelon, amHellishBomb, amNapalm, amDrill, amBallgun,
-            amRCPlane, amLowGravity, amExtraDamage, amInvulnerable, amExtraTime,
-            amLaserSight, amVampiric, amSniperRifle, amJetpack, amMolotov, amBirdy, amPortalGun,
-            amPiano, amGasBomb, amSineGun, amFlamethrower);
+    TAmmoType  = (amNothing, amGrenade, amClusterBomb, amBazooka, amBee, amShotgun, amPickHammer, // 6
+            amSkip, amRope, amMine, amDEagle, amDynamite, amFirePunch, amWhip, // 13
+            amBaseballBat, amParachute, amAirAttack, amMineStrike, amBlowTorch, // 18
+            amGirder, amTeleport, amSwitch, amMortar, amKamikaze, amCake, // 24
+            amSeduction, amWatermelon, amHellishBomb, amNapalm, amDrill, amBallgun, // 30
+            amRCPlane, amLowGravity, amExtraDamage, amInvulnerable, amExtraTime, // 35
+            amLaserSight, amVampiric, amSniperRifle, amJetpack, amMolotov, amBirdy, amPortalGun, // 42
+            amPiano, amGasBomb, amSineGun, amFlamethrower, amSMine, amHammer, // 48
+            amResurrector);
 
-    THWFont = (fnt16, fntBig, fntSmall, CJKfnt16, CJKfntBig, CJKfntSmall);
+    TCrateType = (HealthCrate, AmmoCrate, UtilityCrate);
+
+    THWFont = (fnt16, fntBig, fntSmall {$IFNDEF IPHONEOS}, CJKfnt16, CJKfntBig, CJKfntSmall{$ENDIF});
 
     TCapGroup = (capgrpGameState, capgrpAmmoinfo, capgrpVolume,
             capgrpMessage, capgrpAmmostate);
 
     TStatInfoType = (siGameResult, siMaxStepDamage, siMaxStepKills, siKilledHHs,
-            siClanHealth, siTeamStats);
+            siClanHealth, siTeamStats, siPlayerKills, siMaxTeamDamage,
+            siMaxTeamKills, siMaxTurnSkips );
 
     TWave = (waveRollup, waveSad, waveWave, waveHurrah, waveLemonade, waveShrug, waveJuggle);
 
@@ -157,7 +164,6 @@
             Count: LongWord;
 (* Using for place hedgehogs mode, but for any other situation where the initial count would be needed I guess.
 For example, say, a mode where the weaponset is reset each turn, or on sudden death *)
-            InitialCount: LongWord; 
             NumPerTurn: LongWord;
             Timer: LongWord;
             Pos: LongWord;
@@ -183,10 +189,12 @@
             PrevTexture, NextTexture: PTexture;
             end;
 
-    THogEffect = (heInvulnerable, hePoisoned);
+    THogEffect = (heInvulnerable, heResurrectable, hePoisoned);
 
     TScreenFade = (sfNone, sfInit, sfToBlack, sfFromBlack, sfToWhite, sfFromWhite);
-const sfMax = 1000;
+const
+    sfMax = 1000;
+    cDefaultParamNum = 17;
 
     // message constants
     errmsgCreateSurface   = 'Error creating SDL surface';
@@ -196,7 +204,6 @@
     errmsgIncorrectUse    = 'Incorrect use';
     errmsgShouldntRun     = 'This program shouldn''t be run manually';
     errmsgWrongNumber     = 'Wrong parameters number';
-    errmsgSlotsOverflow   = 'CurSlot overflowed';
 
     msgLoading           = 'Loading ';
     msgOK                = 'ok';
@@ -223,8 +230,8 @@
     rqLowRes      = $00000001;  // use half land array
     rqBlurryLand  = $00000002;  // downscaled terrain
     rqNoBackground= $00000004;  // don't draw background
-    rqSimpleRope  = $00000008;  // avoid drawing rope
-    rq2DWater     = $00000010;  // disabe 3D water effect
+    rqSimpleRope  = $00000008;  // draw rope using lines only
+    rq2DWater     = $00000010;  // disable 3D water effect
     rqFancyBoom   = $00000020;  // no fancy explosion effects
     rqKillFlakes  = $00000040;  // no flakes
     rqSlowMenu    = $00000080;  // ammomenu appears with no animation
@@ -259,13 +266,13 @@
     cPowerDivisor = 1500;
 
     MAXNAMELEN = 192;
-    
+
     // some opengl headers do not have these macros
     GL_BGR              = $80E0;
     GL_BGRA             = $80E1;
     GL_CLAMP_TO_EDGE    = $812F;
     GL_TEXTURE_PRIORITY = $8066;
-    
+
     cSendCursorPosTime  : LongWord = 50;
     cVisibleWater       : LongInt = 128;
     cCursorEdgesDist    : LongInt = 100;
@@ -301,7 +308,9 @@
 
     cKeyMaxIndex = 1023;
 
+    // do not change this value
     cDefaultZoomLevel = 2.0;
+
 {$IFDEF IPHONEOS}
     cMaxZoomLevel = 0.5;
     cMinZoomLevel = 3.5;
@@ -313,8 +322,6 @@
 {$ENDIF}
 
     cSendEmptyPacketTime = 1000;
-
-    // from uTriggers
     trigTurns = $80000001;
 
     // Training Flags
@@ -324,28 +331,31 @@
     tfSpawnTargets  = $00000004;
     tfIgnoreDelays  = $00000008;
     tfTargetRespawn = $00000010;
-    
-    gfAny            = $FFFFFFFF;
-    gfForts          = $00000001;
-    gfMultiWeapon    = $00000002;
-    gfSolidLand      = $00000004;
-    gfBorder         = $00000008;
-    gfDivideTeams    = $00000010;
-    gfLowGravity     = $00000020;
-    gfLaserSight     = $00000040;
-    gfInvulnerable   = $00000080;
-    gfMines          = $00000100;
-    gfVampiric       = $00000200;
-    gfKarma          = $00000400;
-    gfArtillery      = $00000800;
-    gfOneClanMode    = $00001000;
-    gfRandomOrder    = $00002000;
-    gfKing           = $00004000;
-    gfPlaceHog       = $00008000;
-    gfSharedAmmo     = $00010000;
-    gfDisableGirders = $00020000;
-    gfExplosives     = $00040000;
-    gfDisableLandObjects = $00080000;
+
+    gfAny                = $FFFFFFFF;
+    gfOneClanMode        = $00000001;           // used in trainings
+    gfMultiWeapon        = $00000002;           // used in trainings
+    gfSolidLand          = $00000004;
+    gfBorder             = $00000008;
+    gfDivideTeams        = $00000010;
+    gfLowGravity         = $00000020;
+    gfLaserSight         = $00000040;
+    gfInvulnerable       = $00000080;
+    gfMines              = $00000100;           // redundant? same effect as 'landadds 0'
+    gfVampiric           = $00000200;
+    gfKarma              = $00000400;
+    gfArtillery          = $00000800;
+    gfForts              = $00001000;
+    gfRandomOrder        = $00002000;
+    gfKing               = $00004000;
+    gfPlaceHog           = $00008000;
+    gfSharedAmmo         = $00010000;
+    gfDisableGirders     = $00020000;
+    gfDisableLandObjects = $00040000;
+    gfAISurvival         = $00080000;
+    gfInfAttack          = $00100000;
+    gfResetWeps          = $00200000;
+    gfPerHogAmmo         = $00400000;
     // NOTE: When adding new game flags, ask yourself
     // if a "game start notice" would be useful. If so,
     // add one in uWorld.pas - look for "AddGoal".
@@ -370,21 +380,21 @@
     gstLoser          = $00080000;
     gstHHGone         = $00100000;
 
-    gm_Left   = $00000001;
-    gm_Right  = $00000002;
-    gm_Up     = $00000004;
-    gm_Down   = $00000008;
-    gm_Switch = $00000010;
-    gm_Attack = $00000020;
-    gm_LJump  = $00000040;
-    gm_HJump  = $00000080;
-    gm_Destroy= $00000100;
-    gm_Slot   = $00000200; // with param
-    gm_Weapon = $00000400; // with param
-    gm_Timer  = $00000800; // with param
-    gm_Animate= $00001000; // with param
-    gm_Precise= $00002000;
-    gmAllStoppable = gm_Left or gm_Right or gm_Up or gm_Down or gm_Attack or gm_Precise;
+    gmLeft   = $00000001;
+    gmRight  = $00000002;
+    gmUp     = $00000004;
+    gmDown   = $00000008;
+    gmSwitch = $00000010;
+    gmAttack = $00000020;
+    gmLJump  = $00000040;
+    gmHJump  = $00000080;
+    gmDestroy= $00000100;
+    gmSlot   = $00000200; // with param
+    gmWeapon = $00000400; // with param
+    gmTimer  = $00000800; // with param
+    gmAnimate= $00001000; // with param
+    gmPrecise= $00002000;
+    gmAllStoppable = gmLeft or gmRight or gmUp or gmDown or gmAttack or gmPrecise;
 
     cMaxSlotIndex       = 9;
     cMaxSlotAmmoIndex   = 5;
@@ -403,7 +413,7 @@
     ammoprop_Utility      = $00001000;
     ammoprop_Effect       = $00002000;
     ammoprop_NoRoundEndHint=$10000000;
-    
+
     AMMO_INFINITE = 100;
 
     EXPLAllDamageInRadius = $00000001;
@@ -413,6 +423,7 @@
     EXPLDontDraw          = $00000010;
     EXPLNoGfx             = $00000020;
     EXPLPoisoned          = $00000040;
+    EXPLDoNotTouchAny     = $00000080;
 
     posCaseAmmo    = $00000001;
     posCaseHealth  = $00000002;
@@ -427,11 +438,11 @@
     htName        = $02;
     htHealth      = $04;
     htTransparent = $08;
-    
+
     cHHFileName = 'Hedgehog';
     cCHFileName = 'Crosshair';
     cThemeCFGFilename = 'theme.cfg';
-    
+
     FontBorder = 2;
     cPathz: array[TPathType] of shortstring = (
         '',                              // ptNone
@@ -452,19 +463,10 @@
         'Graphics/Hedgehog',             // ptHedgehog
         'Sounds/voices',                 // ptVoices
         'Graphics/Hats',                 // ptHats
-        'Graphics/Flags'                 // ptFlags
+        'Graphics/Flags',                // ptFlags
+        'Missions/Maps'                  // ptMissionMaps
     );
-    
-var PathPrefix: shortstring = './';
-    Pathz: array[TPathType] of shortstring;
-    CountTexz: array[1..Pred(AMMO_INFINITE)] of PTexture;
-    LAND_WIDTH  :longint;
-    LAND_HEIGHT :longint;
-    LAND_WIDTH_MASK  :longWord;
-    LAND_HEIGHT_MASK :longWord;
-    cMaxCaptions : LongInt;
 
-const
     cTagsMasks : array[0..15] of byte = (7, 0, 0, 0, 15, 6, 4, 5, 0, 0, 0, 0, 0, 14, 12, 13);
     cTagsMasksNoHealth: array[0..15] of byte = (3, 2, 11, 1, 0, 0, 0, 0, 0, 10, 0, 9, 0, 0, 0, 0);
 
@@ -480,7 +482,8 @@
             (Handle: nil;
             Height: 10;
             style: TTF_STYLE_NORMAL;
-            Name: 'DejaVuSans-Bold.ttf'),
+            Name: 'DejaVuSans-Bold.ttf')
+            {$IFNDEF IPHONEOS}, // remove chinese fonts for now
             (Handle: nil;
             Height: 12;
             style: TTF_STYLE_NORMAL;
@@ -493,6 +496,7 @@
             Height: 10;
             style: TTF_STYLE_NORMAL;
             Name: 'wqy-zenhei.ttc')
+            {$ENDIF}
             );
 
     SpritesData: array[TSprite] of record
@@ -725,7 +729,7 @@
             Width: 64; Height: 64; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprJetpack
             (FileName:  'Health'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil;
             Width: 16; Height: 16; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpHigh; getDimensions: false; getImageDimensions: true),// sprHealth
-            (FileName:  'amMolotov'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; 
+            (FileName:  'amMolotov'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil;
             Width: 32; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),//sprHandMolotov
             (FileName:  'Molotov'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil;
             Width: 16; Height: 16; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprMolotov
@@ -800,8 +804,24 @@
             (FileName:  'amCheese'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil;
             Width:  64; Height: 64; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprHandCheese
             (FileName:  'amFlamethrower'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil;
-            Width:  128; Height: 128; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true) // sprHandFlamethrower
-            );
+            Width:  128; Height: 128; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprHandFlamethrower
+            (FileName:  'Chunk'; Path: ptCurrTheme; AltPath: ptGraphics; Texture: nil; Surface: nil;
+            Width:  32; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprChunk
+            (FileName:  'Note'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil;
+            Width:  32; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprNote
+            (FileName:   'SMineOff'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil;
+            Width:   8; Height:  8; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprSMineOff
+            (FileName:    'SMineOn'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil;
+            Width:   8; Height:  8; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprSMineOn
+            (FileName:   'amSMine'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil;
+            Width:  64; Height: 64; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprHandSMine
+            (FileName:  'amHammer'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil;
+            Width: 128; Height: 64; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true), // sprWhip
+            (FileName: 'amResurrector'; Path: ptHedgehog; AltPath: ptNone;
+                Texture: nil; Surface: nil; Width: 32; Height: 32;
+                imageWidth: 0; imageHeight: 0; saveSurf: false; priority:
+                tpMedium; getDimensions: false; getImageDimensions: true) 
+            ); // sprHandResurrector
 
     Wavez: array [TWave] of record
             Sprite: TSprite;
@@ -908,7 +928,7 @@
             (FileName:             'Droplet2.ogg'; Path: ptSounds),// sndDroplet2
             (FileName:             'Droplet3.ogg'; Path: ptSounds),// sndDroplet3
             (FileName:                  'egg.ogg'; Path: ptSounds),// sndEggBreak
-            (FileName:           'pickhammer.ogg'; Path: ptSounds),// sndDrillRocket
+            (FileName:             'drillgun.ogg'; Path: ptSounds),// sndDrillRocket
             (FileName:          'PoisonCough.ogg'; Path: ptVoices),// sndPoisonCough
             (FileName:           'PoisonMoan.ogg'; Path: ptVoices),// sndPoisonMoan
             (FileName:             'BirdyLay.ogg'; Path: ptSounds),// sndBirdyLay
@@ -927,7 +947,12 @@
             (FileName:          'shotgunfire.ogg'; Path: ptSounds),// sndSineGun
             (FileName:                'Ooff1.ogg'; Path: ptVoices),// sndOoff1
             (FileName:                'Ooff2.ogg'; Path: ptVoices),// sndOoff2
-            (FileName:                'Ooff3.ogg'; Path: ptVoices) // sndOoff3
+            (FileName:                'Ooff3.ogg'; Path: ptVoices),// sndOoff3
+            (FileName:            'whipcrack.ogg'; Path: ptSounds),// sndWhack
+            (FileName:           'Comeonthen.ogg'; Path: ptVoices),// sndComeonthen
+            (FileName:            'parachute.ogg'; Path: ptSounds),// sndParachute
+            (FileName:                 'bump.ogg'; Path: ptSounds),// sndBump
+            (FileName: 'hogchant3.ogg'; Path: ptSounds) // sndResurrector
             );
 
     Ammoz: array [TAmmoType] of record
@@ -950,7 +975,6 @@
             NumberInCase: 0;
             Ammo: (Propz: ammoprop_NoCrosshair or ammoprop_DontHold or ammoprop_Effect;
                 Count: AMMO_INFINITE;
-                InitialCount: AMMO_INFINITE;
                 NumPerTurn: 0;
                 Timer: 0;
                 Pos: 0;
@@ -974,7 +998,6 @@
             NumberInCase: 1;
             Ammo: (Propz: ammoprop_Timerable or ammoprop_Power or ammoprop_AltUse;
                 Count: AMMO_INFINITE;
-                InitialCount: AMMO_INFINITE;
                 NumPerTurn: 0;
                 Timer: 3000;
                 Pos: 0;
@@ -998,7 +1021,6 @@
             NumberInCase: 3;
             Ammo: (Propz: ammoprop_Timerable or ammoprop_Power or ammoprop_AltUse;
                 Count: 5;
-                InitialCount: 5;
                 NumPerTurn: 0;
                 Timer: 3000;
                 Pos: 0;
@@ -1022,7 +1044,6 @@
             NumberInCase: 1;
             Ammo: (Propz: ammoprop_Power or ammoprop_AltUse;
                 Count: AMMO_INFINITE;
-                InitialCount: AMMO_INFINITE;
                 NumPerTurn: 0;
                 Timer: 0;
                 Pos: 0;
@@ -1046,7 +1067,6 @@
             NumberInCase: 1;
             Ammo: (Propz: ammoprop_Power or ammoprop_NeedTarget or ammoprop_DontHold;
                 Count: 2;
-                InitialCount: 2;
                 NumPerTurn: 0;
                 Timer: 0;
                 Pos: 0;
@@ -1070,7 +1090,6 @@
             NumberInCase: 1;
             Ammo: (Propz: ammoprop_ForwMsgs;
                 Count: AMMO_INFINITE;
-                InitialCount: AMMO_INFINITE;
                 NumPerTurn: 1;
                 Timer: 0;
                 Pos: 0;
@@ -1094,7 +1113,6 @@
             NumberInCase: 1;
             Ammo: (Propz: ammoprop_ForwMsgs or ammoprop_AttackInMove or ammoprop_NoCrosshair or ammoprop_DontHold;
                 Count: 2;
-                InitialCount: 2;
                 NumPerTurn: 0;
                 Timer: 0;
                 Pos: 0;
@@ -1118,7 +1136,6 @@
             NumberInCase: 1;
             Ammo: (Propz: ammoprop_NoCrosshair or ammoprop_DontHold;
                 Count: AMMO_INFINITE;
-                InitialCount: AMMO_INFINITE;
                 NumPerTurn: 0;
                 Timer: 0;
                 Pos: 0;
@@ -1146,7 +1163,6 @@
                           ammoprop_Utility or
                           ammoprop_AltAttack;
                     Count: 5;
-                    InitialCount: 5;
                     NumPerTurn: 0;
                     Timer: 0;
                     Pos: 0;
@@ -1170,7 +1186,6 @@
             NumberInCase: 1;
             Ammo: (Propz: ammoprop_NoCrosshair or ammoprop_AttackInMove or ammoprop_DontHold or ammoprop_AltUse;
                 Count: 2;
-                InitialCount: 2;
                 NumPerTurn: 0;
                 Timer: 0;
                 Pos: 0;
@@ -1194,7 +1209,6 @@
             NumberInCase: 2;
             Ammo: (Propz: 0;
                 Count: 3;
-                InitialCount: 3;
                 NumPerTurn: 3;
                 Timer: 0;
                 Pos: 0;
@@ -1218,7 +1232,6 @@
             NumberInCase: 1;
             Ammo: (Propz: ammoprop_NoCrosshair or ammoprop_AttackInMove or ammoprop_DontHold or ammoprop_AltUse;
                 Count: 1;
-                InitialCount: 1;
                 NumPerTurn: 0;
                 Timer: 0;
                 Pos: 0;
@@ -1242,7 +1255,6 @@
             NumberInCase: 1;
             Ammo: (Propz: ammoprop_NoCrosshair or ammoprop_ForwMsgs or ammoprop_AttackInMove;
                 Count: AMMO_INFINITE;
-                InitialCount: AMMO_INFINITE;
                 NumPerTurn: 0;
                 Timer: 0;
                 Pos: 0;
@@ -1266,7 +1278,6 @@
             NumberInCase: 1;
             Ammo: (Propz: ammoprop_NoCrosshair;
                 Count: AMMO_INFINITE;
-                InitialCount: AMMO_INFINITE;
                 NumPerTurn: 0;
                 Timer: 0;
                 Pos: 0;
@@ -1290,7 +1301,6 @@
             NumberInCase: 1;
             Ammo: (Propz: ammoprop_DontHold;
                 Count: 1;
-                InitialCount: 1;
                 NumPerTurn: 0;
                 Timer: 0;
                 Pos: 0;
@@ -1320,7 +1330,6 @@
                           ammoprop_Utility or
                           ammoprop_AltAttack;
                 Count: 2;
-                InitialCount: 2;
                 NumPerTurn: 0;
                 Timer: 0;
                 Pos: 0;
@@ -1348,7 +1357,6 @@
                             ammoprop_DontHold or
                             ammoprop_NotBorder;
                 Count: 1;
-                InitialCount: 1;
                 NumPerTurn: 0;
                 Timer: 0;
                 Pos: 0;
@@ -1376,7 +1384,6 @@
                             ammoprop_DontHold or
                             ammoprop_NotBorder;
                 Count: 1;
-                InitialCount: 1;
                 NumPerTurn: 0;
                 Timer: 0;
                 Pos: 0;
@@ -1400,7 +1407,6 @@
             NumberInCase: 2;
             Ammo: (Propz: ammoprop_ForwMsgs;
                 Count: 1;
-                InitialCount: 1;
                 NumPerTurn: 0;
                 Timer: 0;
                 Pos: 0;
@@ -1428,7 +1434,6 @@
                           ammoprop_Utility or
                           ammoprop_AttackingPut;
                     Count: 1;
-                    InitialCount: 1;
                     NumPerTurn: 0;
                     Timer: 0;
                     Pos: 0;
@@ -1457,7 +1462,6 @@
                           ammoprop_Utility or
                           ammoprop_DontHold;
                 Count: 2;
-                InitialCount: 2;
                 NumPerTurn: 0;
                 Timer: 0;
                 Pos: 0;
@@ -1485,7 +1489,6 @@
                           ammoprop_Utility or
                           ammoprop_DontHold;
                     Count: 3;
-                    InitialCount: 3;
                     NumPerTurn: 0;
                     Timer: 0;
                     Pos: 0;
@@ -1509,7 +1512,6 @@
             NumberInCase: 4;
             Ammo: (Propz: 0;
                 Count: 4;
-                InitialCount: 4;
                 NumPerTurn: 0;
                 Timer: 0;
                 Pos: 0;
@@ -1533,7 +1535,6 @@
             NumberInCase: 1;
             Ammo: (Propz: ammoprop_ForwMsgs or ammoprop_DontHold or ammoprop_AttackInMove;
                 Count: 1;
-                InitialCount: 1;
                 NumPerTurn: 0;
                 Timer: 0;
                 Pos: 0;
@@ -1557,7 +1558,6 @@
             NumberInCase: 1;
             Ammo: (Propz: ammoprop_ForwMsgs or ammoprop_NoCrosshair or ammoprop_DontHold;
                 Count: 1;
-                InitialCount: 1;
                 NumPerTurn: 0;
                 Timer: 0;
                 Pos: 0;
@@ -1581,7 +1581,6 @@
             NumberInCase: 1;
             Ammo: (Propz: ammoprop_ForwMsgs or ammoprop_DontHold;
                 Count: 1;
-                InitialCount: 1;
                 NumPerTurn: 0;
                 Timer: 0;
                 Pos: 0;
@@ -1605,7 +1604,6 @@
             NumberInCase: 1;
             Ammo: (Propz: ammoprop_Timerable or ammoprop_Power or ammoprop_AltUse;
                 Count: 0;
-                InitialCount: 0;
                 NumPerTurn: 0;
                 Timer: 3000;
                 Pos: 0;
@@ -1629,7 +1627,6 @@
             NumberInCase: 1;
             Ammo: (Propz:  ammoprop_Power or ammoprop_AltUse;
                 Count: 0;
-                InitialCount: 0;
                 NumPerTurn: 0;
                 Timer: 5000;
                 Pos: 0;
@@ -1657,7 +1654,6 @@
                             ammoprop_DontHold or
                             ammoprop_NotBorder;
                 Count: 1;
-                InitialCount: 1;
                 NumPerTurn: 0;
                 Timer: 0;
                 Pos: 0;
@@ -1681,7 +1677,6 @@
             NumberInCase: 1;
             Ammo: (Propz: ammoprop_Power or ammoprop_AltUse;
                 Count: AMMO_INFINITE;
-                InitialCount: AMMO_INFINITE;
                 NumPerTurn: 0;
                 Timer: 0;
                 Pos: 0;
@@ -1705,7 +1700,6 @@
             NumberInCase: 1;
             Ammo: (Propz:  ammoprop_ForwMsgs or ammoprop_DontHold;
                 Count: AMMO_INFINITE;
-                InitialCount: AMMO_INFINITE;
                 NumPerTurn: 0;
                 Timer: 5001;
                 Pos: 0;
@@ -1731,7 +1725,6 @@
                             ammoprop_DontHold or
                             ammoprop_AltAttack};
                 Count: 1;
-                InitialCount: 1;
                 NumPerTurn: 0;
                 Timer: 0;
                 Pos: 0;
@@ -1760,7 +1753,6 @@
                           ammoprop_Utility or
                           ammoprop_Effect;
                     Count: 1;
-                    InitialCount: 1;
                     NumPerTurn: 0;
                     Timer: 0;
                     Pos: 0;
@@ -1789,7 +1781,6 @@
                           ammoprop_Utility or
                           ammoprop_Effect;
                     Count: 1;
-                    InitialCount: 1;
                     NumPerTurn: 0;
                     Timer: 0;
                     Pos: 0;
@@ -1818,7 +1809,6 @@
                           ammoprop_Utility or
                           ammoprop_Effect;
                     Count: 1;
-                    InitialCount: 1;
                     NumPerTurn: 0;
                     Timer: 0;
                     Pos: 0;
@@ -1847,7 +1837,6 @@
                           ammoprop_Utility or
                           ammoprop_Effect;
                     Count: 1;
-                    InitialCount: 1;
                     NumPerTurn: 0;
                     Timer: 0;
                     Pos: 0;
@@ -1876,7 +1865,6 @@
                           ammoprop_Utility or
                           ammoprop_Effect;
                     Count: 1;
-                    InitialCount: 1;
                     NumPerTurn: 0;
                     Timer: 0;
                     Pos: 0;
@@ -1905,7 +1893,6 @@
                           ammoprop_Utility or
                           ammoprop_Effect;
                     Count: 1;
-                    InitialCount: 1;
                     NumPerTurn: 0;
                     Timer: 0;
                     Pos: 0;
@@ -1929,7 +1916,6 @@
             NumberInCase: 2;
             Ammo: (Propz: 0;
                 Count: 2;
-                InitialCount: 2;
                 NumPerTurn: 1;
                 Timer: 0;
                 Pos: 0;
@@ -1959,7 +1945,6 @@
                           ammoprop_Utility or
                           ammoprop_AltAttack;
                 Count: 1;
-                InitialCount: 1;
                 NumPerTurn: 0;
                 Timer: 0;
                 Pos: 0;
@@ -1983,7 +1968,6 @@
             NumberInCase: 1;
             Ammo: (Propz: ammoprop_Power or ammoprop_AltUse;
                 Count: AMMO_INFINITE;
-                InitialCount: AMMO_INFINITE;
                 NumPerTurn: 0;
                 Timer: 3000;
                 Pos: 0;
@@ -2009,7 +1993,6 @@
                           ammoprop_NoCrosshair or
                           ammoprop_DontHold;
                 Count: 1;
-                InitialCount: 1;
                 NumPerTurn: 0;
                 Timer: 0;
                 Pos: 0;
@@ -2036,7 +2019,6 @@
                           ammoprop_DontHold or
                           ammoprop_Utility;
                 Count: 1;
-                InitialCount: 1;
                 NumPerTurn: 3;
                 Timer: 0;
                 Pos: 0;
@@ -2064,7 +2046,6 @@
                             ammoprop_DontHold or
                             ammoprop_NotBorder;
                 Count: 1;
-                InitialCount: 1;
                 NumPerTurn: 0;
                 Timer: 0;
                 Pos: 0;
@@ -2088,7 +2069,6 @@
             NumberInCase: 1;
             Ammo: (Propz: ammoprop_Timerable or ammoprop_Power or ammoprop_AltUse;
                 Count: AMMO_INFINITE;
-                InitialCount: AMMO_INFINITE;
                 NumPerTurn: 0;
                 Timer: 3000;
                 Pos: 0;
@@ -2104,7 +2084,7 @@
             PosSprite: sprWater;
             ejectX: 0;
             ejectY: 0),
-            
+
 // SineGun
             (NameId: sidSineGun;
             NameTex: nil;
@@ -2112,7 +2092,6 @@
             NumberInCase: 2;
             Ammo: (Propz: ammoprop_AttackInMove;
                 Count: 1;
-                InitialCount: 1;
                 NumPerTurn: 0;
                 Timer: 0;
                 Pos: 0;
@@ -2136,7 +2115,6 @@
             NumberInCase: 1;
             Ammo: (Propz:  ammoprop_ForwMsgs or ammoprop_DontHold;
                 Count: 1;
-                InitialCount: 1;
                 NumPerTurn: 0;
                 Timer: 5001;
                 Pos: 0;
@@ -2151,8 +2129,77 @@
             PosCount: 1;
             PosSprite: sprWater;
             ejectX: 0; //20;
-            ejectY: -3)
-            );
+            ejectY: -3),
+
+// Sticky Mine
+            (NameId: sidSMine;
+            NameTex: nil;
+            Probability: 100;
+            NumberInCase: 1;
+            Ammo: (Propz: ammoprop_Power or ammoprop_AltUse;
+                Count: 1;
+                NumPerTurn: 1;
+                Timer: 0;
+                Pos: 0;
+                AmmoType: amSMine;
+                AttackVoice: sndLaugh);
+            Slot: 4;
+            TimeAfterTurn: 5000;
+            minAngle: 0;
+            maxAngle: 0;
+            isDamaging: true;
+            SkipTurns: 0;
+            PosCount: 1;
+            PosSprite: sprWater;
+            ejectX: 0;
+            ejectY: 0),
+
+// Hammer
+            (NameId: sidHammer;
+            NameTex: nil;
+            Probability: 0;
+            NumberInCase: 1;
+            Ammo: (Propz: ammoprop_NoCrosshair;
+                Count: 1;
+                NumPerTurn: 0;
+                Timer: 0;
+                Pos: 0;
+                AmmoType: amHammer;
+                AttackVoice: sndNone);
+            Slot: 3;
+            TimeAfterTurn: 1000;
+            MinAngle: 0;
+            maxAngle: 0;
+            isDamaging: true;
+            SkipTurns: 0;
+            PosCount: 1;
+            PosSprite: sprWater;
+            ejectX: 0;
+            ejectY: 0),
+
+        (NameId: sidResurrector;
+            NameTex: nil;
+            Probability: 0;
+            NumberInCase: 1;
+            Ammo: (Propz: ammoprop_NoCrosshair or ammoprop_NoRoundEndHint;
+                Count: 1;
+                NumPerTurn: 0;
+                Timer: 0;
+                Pos: 0;
+                AmmoType: amResurrector;
+                AttackVoice: sndNone);
+            Slot: 8;
+            TimeAfterTurn: 3000;
+            minAngle: 0;
+            maxAngle: 0;
+            isDamaging: true;
+            SkipTurns: 0;
+            PosCount: 1;
+            PosSprite: sprWater;
+            ejectX: 0;
+            ejectY: 0)
+        );
+
 
 
     conversionFormat: TSDL_PixelFormat = (
@@ -2181,48 +2228,7 @@
         colorkey: 0;
         alpha : 255
     );
-    
-procedure initModule;
-procedure freeModule;
 
 implementation
-uses uMisc;
-
-procedure initModule;
-begin
-    Pathz:= cPathz;
-        {*  REFERENCE
-      4096 -> $FFFFF000
-      2048 -> $FFFFF800
-      1024 -> $FFFFFC00
-       512 -> $FFFFFE00  *}
-    if (cReducedQuality and rqLowRes) <> 0 then
-    begin
-        LAND_WIDTH:= 2048;
-        LAND_HEIGHT:= 1024;
-        LAND_WIDTH_MASK:= $FFFFF800;
-        LAND_HEIGHT_MASK:= $FFFFFC00;
-    end
-    else
-    begin
-        LAND_WIDTH:= 4096;
-        LAND_HEIGHT:= 2048;
-        LAND_WIDTH_MASK:= $FFFFF000;
-        LAND_HEIGHT_MASK:= $FFFFF800
-    end;
-
-{$IFDEF IPHONEOS}    
-    if isPhone() then
-        cMaxCaptions:= 3
-    else
-{$ENDIF}
-        cMaxCaptions:= 4;
-
-end;
-
-procedure freeModule;
-begin
-    PathPrefix := './';
-end;
 
 end.
--- a/hedgewars/uFloat.pas	Thu Aug 26 23:59:18 2010 +0200
+++ b/hedgewars/uFloat.pas	Wed Oct 27 14:02:20 2010 +0200
@@ -22,7 +22,6 @@
 interface
 
 {$IFDEF FPC}
-{$INLINE ON}
 {$IFDEF ENDIAN_LITTLE}
 type hwFloat = record
                isNegative: boolean;
@@ -43,26 +42,26 @@
 
 operator + (const z1, z2: hwFloat) z : hwFloat; inline;
 operator - (const z1, z2: hwFloat) z : hwFloat; inline;
-operator - (const z1: hwFloat) z : hwFloat;
+operator - (const z1: hwFloat) z : hwFloat; inline;
 
-operator * (const z1, z2: hwFloat) z : hwFloat;
+operator * (const z1, z2: hwFloat) z : hwFloat; inline;
 operator * (const z1: hwFloat; const z2: LongInt) z : hwFloat; inline;
-operator / (const z1: hwFloat; z2: hwFloat) z : hwFloat;
-operator / (const z1: hwFloat; const z2: LongInt) z : hwFloat;
+operator / (const z1: hwFloat; z2: hwFloat) z : hwFloat; inline;
+operator / (const z1: hwFloat; const z2: LongInt) z : hwFloat; inline;
 
-operator < (const z1, z2: hwFloat) b : boolean;
-operator > (const z1, z2: hwFloat) b : boolean;
+operator < (const z1, z2: hwFloat) b : boolean; inline;
+operator > (const z1, z2: hwFloat) b : boolean; inline;
 
 function cstr(const z: hwFloat): shortstring;
-function hwRound(const t: hwFloat): LongInt;
-function hwAbs(const t: hwFloat): hwFloat;
+function hwRound(const t: hwFloat): LongInt; inline;
+function hwAbs(const t: hwFloat): hwFloat; inline;
 function hwSqr(const t: hwFloat): hwFloat; inline;
 function hwSqrt(const t: hwFloat): hwFloat; inline;
 function Distance(const dx, dy: hwFloat): hwFloat;
 function DistanceI(const dx, dy: LongInt): hwFloat;
 function AngleSin(const Angle: Longword): hwFloat;
 function AngleCos(const Angle: Longword): hwFloat;
-function SignAs(const num, signum: hwFloat): hwFloat;
+function SignAs(const num, signum: hwFloat): hwFloat; inline;
 
 {$IFDEF FPC}
 {$J-}
@@ -148,7 +147,7 @@
 {$ENDIF}
 
 implementation
-uses uMisc;
+//uses uMisc;
 
 
 {$IFDEF FPC}
@@ -348,7 +347,7 @@
 function AngleSin(const Angle: Longword): hwFloat;
 begin
 {$IFDEF DEBUGFILE}
-TryDo((Angle >= 0) and (Angle <= 2048), 'Sin param exceeds limits', true);
+//TryDo((Angle >= 0) and (Angle <= 2048), 'Sin param exceeds limits', true);
 {$ENDIF}
 AngleSin.isNegative:= false;
 if Angle < 1024 then AngleSin.QWordValue:= SinTable[Angle]
@@ -358,7 +357,7 @@
 function AngleCos(const Angle: Longword): hwFloat;
 begin
 {$IFDEF DEBUGFILE}
-TryDo((Angle >= 0) and (Angle <= 2048), 'Cos param exceeds limits', true);
+//TryDo((Angle >= 0) and (Angle <= 2048), 'Cos param exceeds limits', true);
 {$ENDIF}
 AngleCos.isNegative:= Angle > 1024;
 if Angle < 1024 then AngleCos.QWordValue:= SinTable[1024 - Angle]
--- a/hedgewars/uGame.pas	Thu Aug 26 23:59:18 2010 +0200
+++ b/hedgewars/uGame.pas	Wed Oct 27 14:02:20 2010 +0200
@@ -26,7 +26,7 @@
 ////////////////////
    implementation
 ////////////////////
-uses uMisc, uConsts, uKeys, uTeams, uIO, uAI, uGears, uScript;
+uses uMisc, uConsts, uKeys, uTeams, uIO, uAI, uGears, uScript, uSound, uMobile;
 
 procedure DoGameTick(Lag: LongInt);
 var i: LongInt;
@@ -65,7 +65,10 @@
                         SetBinds(CurrentTeam^.Binds);
                         //CurrentHedgehog^.Gear^.Message:= 0; <- produces bugs with further save restoring and demos
                         isSoundEnabled:= isSEBackup;
-                        GameType:= gmtLocal
+                        if isSoundEnabled then playMusic;
+                        GameType:= gmtLocal;
+                        InitIPC;
+                        perfExt_SaveFinishedSynching();
                         end;
                end
           else ProcessGears
--- a/hedgewars/uGears.pas	Thu Aug 26 23:59:18 2010 +0200
+++ b/hedgewars/uGears.pas	Wed Oct 27 14:02:20 2010 +0200
@@ -22,7 +22,7 @@
 interface
 uses SDLh, uConsts, uFloat, Math;
 
-    
+
 type
     PGear = ^TGear;
     TGearStepProcedure = procedure (Gear: PGear);
@@ -32,8 +32,7 @@
             AdvBounce: Longword;
             Invulnerable: Boolean;
             RenderTimer: Boolean;
-            Ammo : PAmmo;
-            AmmoType : TAmmoType;  // Used to track AmmoType at time of Gear creation, since Ammo can be reassigned
+            AmmoType : TAmmoType;
             State : Longword;
             X : hwFloat;
             Y : hwFloat;
@@ -63,6 +62,7 @@
             SoundChannel: LongInt;
             PortalCounter: LongWord  // Hopefully temporary, but avoids infinite portal loops in a guaranteed fashion.
         end;
+    TPGearArray = Array of PGear;
 
 var AllInactive: boolean;
     PrvInactive: boolean;
@@ -77,10 +77,12 @@
     PlacingHogs: boolean; // a convenience flag to indicate placement of hogs is still in progress
     StepSoundTimer: LongInt;
     StepSoundChannel: LongInt;
-    
+
 procedure initModule;
 procedure freeModule;
 function  AddGear(X, Y: LongInt; Kind: TGearType; State: Longword; dX, dY: hwFloat; Timer: LongWord): PGear;
+function SpawnCustomCrateAt(x, y: LongInt; crate: TCrateType; content: Longword ): PGear;
+procedure ResurrectHedgehog(gear: PGear);
 procedure ProcessGears;
 procedure EndTurnCleanup;
 procedure ApplyDamage(Gear: PGear; Damage: Longword; Source: TDamageSource);
@@ -113,12 +115,13 @@
                                   end;
                 rounded: array[0..MAXROPEPOINTS + 2] of TVertex2f;
                 end;
- 
+
 procedure DeleteGear(Gear: PGear); forward;
 procedure doMakeExplosion(X, Y, Radius: LongInt; Mask: LongWord); forward;
 procedure doMakeExplosion(X, Y, Radius: LongInt; Mask, Tint: LongWord); forward;
 procedure AmmoShove(Ammo: PGear; Damage, Power: LongInt); forward;
 //procedure AmmoFlameWork(Ammo: PGear); forward;
+function GearsNear(Gear: PGear; Kind: TGearType; r: LongInt): TPGearArray; forward;
 function  CheckGearNear(Gear: PGear; Kind: TGearType; rX, rY: LongInt): PGear; forward;
 procedure SpawnBoxOfSmth; forward;
 procedure AfterAttack; forward;
@@ -201,7 +204,12 @@
             @doStepPiano,
             @doStepBomb,
             @doStepSineGunShot,
-            @doStepFlamethrower
+            @doStepFlamethrower,
+            @doStepSMine,
+            @doStepPoisonCloud,
+            @doStepHammer,
+            @doStepHammerHit,
+            @doStepResurrector
             );
 
 procedure InsertGearToList(Gear: PGear);
@@ -214,7 +222,7 @@
         ptmp:= tmp;
         tmp:= tmp^.NextGear
         end;
-    
+
     if ptmp <> tmp then
         begin
         Gear^.NextGear:= ptmp^.NextGear;
@@ -313,6 +321,9 @@
                 gear^.Friction:= _0_999;
                 gear^.Angle:= cMaxAngle div 2;
                 gear^.Z:= cHHZ;
+                if (GameFlags and gfAISurvival) <> 0 then
+                    if PHedgehog(gear^.Hedgehog)^.BotLevel > 0 then
+                        PHedgehog(gear^.Hedgehog)^.Effects[heResurrectable] := true;
                 end;
 gtAmmo_Grenade: begin // bazooka
                 gear^.Radius:= 4;
@@ -338,6 +349,10 @@
                 gear^.Radius:= 10;
                 gear^.Timer:= 4000
                 end;
+   gtHammerHit: begin
+                gear^.Radius:= 8;
+                gear^.Timer:= 125
+                end;
         gtRope: begin
                 gear^.Radius:= 3;
                 gear^.Friction:= _450;
@@ -354,6 +369,14 @@
                 else
                     gear^.Timer:= cMinesTime*1;
                 end;
+       gtSMine: begin
+                gear^.Health:= 10;
+                gear^.State:= gear^.State or gstMoving;
+                gear^.Radius:= 2;
+                gear^.Elasticity:= _0_55;
+                gear^.Friction:= _0_995;
+                gear^.Timer:= 500;
+                end;
         gtCase: begin
                 gear^.ImpactSound:= sndGraveImpact;
                 gear^.nImpactSounds:= 1;
@@ -424,6 +447,7 @@
                 gear^.Friction:= _0_08
                 end;
         gtWhip: gear^.Radius:= 20;
+      gtHammer: gear^.Radius:= 20;
     gtKamikaze: begin
                 gear^.Health:= 2048;
                 gear^.Radius:= 20
@@ -471,7 +495,7 @@
      gtJetpack: begin
                 gear^.Health:= 2000;
                 end;
-     gtMolotov: begin 
+     gtMolotov: begin
                 gear^.Radius:= 6;
                 end;
        gtBirdy: begin
@@ -480,7 +504,7 @@
                 gear^.Health := 2000;
                 gear^.FlightTime := 2;
                 end;
-         gtEgg: begin 
+         gtEgg: begin
                 gear^.Radius:= 4;
                 gear^.Elasticity:= _0_6;
                 gear^.Friction:= _0_96;
@@ -508,7 +532,15 @@
                 gear^.Timer:= 10;
                 gear^.Health:= 500;
                 end;
-     end;
+ gtPoisonCloud: begin
+                gear^.Timer:= 5000;
+                gear^.dY:= int2hwfloat(-4 + longint(getRandom(8))) / 1000;
+                end;
+ gtResurrector: begin
+                gear^.Radius := 100;
+                end;
+    end;
+
 InsertGearToList(gear);
 AddGear:= gear;
 
@@ -541,8 +573,8 @@
 else if Gear^.Kind = gtHedgehog then
     if (CurAmmoGear <> nil) and (CurrentHedgehog^.Gear = Gear) then
         begin
-        Gear^.Message:= gm_Destroy;
-        CurAmmoGear^.Message:= gm_Destroy;
+        Gear^.Message:= gmDestroy;
+        CurAmmoGear^.Message:= gmDestroy;
         exit
         end
     else
@@ -645,20 +677,24 @@
             begin
             tmp:= 0;
             if PHedgehog(Gear^.Hedgehog)^.Effects[hePoisoned] then
-                inc(tmp, min(ModifyDamage(5,Gear), max(0,Gear^.Health - 1 - Gear^.Damage)));
-            inc(tmp, min(cHealthDecrease, max(0,Gear^.Health - 1 - Gear^.Damage)));
+                inc(tmp, ModifyDamage(5, Gear));
+            inc(tmp, cHealthDecrease);
             if PHedgehog(Gear^.Hedgehog)^.King then
                 begin
                 flag:= false;
                 team:= PHedgehog(Gear^.Hedgehog)^.Team;
                 for i:= 0 to Pred(team^.HedgehogsNumber) do
-                    if (team^.Hedgehogs[i].Gear <> nil) and 
-                        (not team^.Hedgehogs[i].King) and 
-                        (team^.Hedgehogs[i].Gear^.Health > team^.Hedgehogs[i].Gear^.Damage) 
+                    if (team^.Hedgehogs[i].Gear <> nil) and
+                        (not team^.Hedgehogs[i].King) and
+                        (team^.Hedgehogs[i].Gear^.Health > team^.Hedgehogs[i].Gear^.Damage)
                     then flag:= true;
-                if not flag then inc(tmp, min(5, max(0,Gear^.Health - 1 - Gear^.Damage)))
+                if not flag then inc(tmp, 5)
                 end;
-            if tmp > 0 then ApplyDamage(Gear, tmp, dsPoison);
+            if tmp > 0 then 
+                begin
+                inc(Gear^.Damage, min(tmp, max(0,Gear^.Health - 1 - Gear^.Damage)));
+                HHHurt(Gear^.Hedgehog, dsPoison);
+                end
             end;
 
         Gear:= Gear^.NextGear
@@ -667,6 +703,7 @@
 
 procedure ProcessGears;
 const delay: LongWord = 0;