Hedgeroid: Final sprint to the deadline
authorMedo <smaxein@googlemail.com>
Mon, 20 Aug 2012 20:19:35 +0200
changeset 7582 714310efad8f
parent 7580 c92596feac0d
child 7584 7831c84cc644
Hedgeroid: Final sprint to the deadline - Changed local game setup to use the new fragments from the netroom - Pulled team editing into the main activity menu / action bar - Cleanups, renames, anything to make the code look better ;)
project_files/Android-build/SDL-android-project/AndroidManifest.xml
project_files/Android-build/SDL-android-project/res/drawable-mdpi/backbutton.png
project_files/Android-build/SDL-android-project/res/drawable-mdpi/button_disabled.9.png
project_files/Android-build/SDL-android-project/res/drawable-mdpi/button_focused.9.png
project_files/Android-build/SDL-android-project/res/drawable-mdpi/button_focused_disabled.9.png
project_files/Android-build/SDL-android-project/res/drawable-mdpi/button_normal.9.png
project_files/Android-build/SDL-android-project/res/drawable-mdpi/dropdown_disabled.9.png
project_files/Android-build/SDL-android-project/res/drawable-mdpi/dropdown_focused.9.png
project_files/Android-build/SDL-android-project/res/drawable-mdpi/dropdown_focused_disabled.9.png
project_files/Android-build/SDL-android-project/res/drawable-mdpi/dropdown_normal.9.png
project_files/Android-build/SDL-android-project/res/drawable-mdpi/savebutton.png
project_files/Android-build/SDL-android-project/res/layout-large/activity_lobby.xml
project_files/Android-build/SDL-android-project/res/layout-large/activity_localroom.xml
project_files/Android-build/SDL-android-project/res/layout-large/activity_netroom.xml
project_files/Android-build/SDL-android-project/res/layout-large/fragment_roomlist.xml
project_files/Android-build/SDL-android-project/res/layout-large/lobby_rooms_fragment.xml
project_files/Android-build/SDL-android-project/res/layout/activity_lobby.xml
project_files/Android-build/SDL-android-project/res/layout/activity_localroom.xml
project_files/Android-build/SDL-android-project/res/layout/activity_main.xml
project_files/Android-build/SDL-android-project/res/layout/activity_netroom.xml
project_files/Android-build/SDL-android-project/res/layout/activity_teamlist.xml
project_files/Android-build/SDL-android-project/res/layout/backbutton.xml
project_files/Android-build/SDL-android-project/res/layout/config.xml
project_files/Android-build/SDL-android-project/res/layout/fragment_map.xml
project_files/Android-build/SDL-android-project/res/layout/fragment_roomlist.xml
project_files/Android-build/SDL-android-project/res/layout/fragment_settings.xml
project_files/Android-build/SDL-android-project/res/layout/fragment_teamlist.xml
project_files/Android-build/SDL-android-project/res/layout/lobby_rooms_fragment.xml
project_files/Android-build/SDL-android-project/res/layout/main.xml
project_files/Android-build/SDL-android-project/res/layout/roomlist_player_team_count.xml
project_files/Android-build/SDL-android-project/res/layout/roomlist_player_team_count_header.xml
project_files/Android-build/SDL-android-project/res/layout/savebutton.xml
project_files/Android-build/SDL-android-project/res/layout/starting_game.xml
project_files/Android-build/SDL-android-project/res/layout/tab_indicator.xml
project_files/Android-build/SDL-android-project/res/layout/tab_indicator_vertical.xml
project_files/Android-build/SDL-android-project/res/layout/team_selection_dialog.xml
project_files/Android-build/SDL-android-project/res/layout/team_selector.xml
project_files/Android-build/SDL-android-project/res/menu/main_options.xml
project_files/Android-build/SDL-android-project/res/values/strings.xml
project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/BasicRoomState.java
project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/ChatFragment.java
project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/ChatlogAdapter.java
project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/ConnectingDialog.java
project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/ConnectionDependendDialogFragment.java
project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/EngineProtocol/PascalExports.java
project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/GameConnection.java
project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/LobbyActivity.java
project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/LobbyPlayerlistAdapter.java
project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/LobbyPlayerlistFragment.java
project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/LocalRoomActivity.java
project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/LocalRoomStateManager.java
project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/MainActivity.java
project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/MapFragment.java
project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/MapPreviewGenerator.java
project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/NetRoomActivity.java
project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/RoomActivity.java
project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/RoomPlayerlistFragment.java
project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/RoomStateManager.java
project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/RoomlistFragment.java
project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/SDLActivity.java
project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/SettingsFragment.java
project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/StartGameActivity.java
project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/TeamListActivity.java
project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/TeamSelectionActivity.java
project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/TeamlistAdapter.java
project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/TeamlistFragment.java
project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/frontlib/Flib.java
project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/frontlib/Frontlib.java
project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/MessageLog.java
project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/NetRoomState.java
project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/Netplay.java
project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/ThreadedNetConnection.java
project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/util/ObjectUtils.java
project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/util/TextInputDialog.java
project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/util/UiUtils.java
--- a/project_files/Android-build/SDL-android-project/AndroidManifest.xml	Mon Aug 20 20:16:37 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/AndroidManifest.xml	Mon Aug 20 20:19:35 2012 +0200
@@ -48,13 +48,12 @@
         <service android:name=".Downloader.DownloadService" />
 		
         <activity
-            android:name="StartGameActivity"
+            android:name=".LocalRoomActivity"
             android:label="@string/app_name"
-            android:screenOrientation="landscape"
-            android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >
+            android:screenOrientation="landscape" >
         </activity>
         <activity
-            android:name="TeamSelectionActivity"
+            android:name=".TeamListActivity"
             android:label="@string/app_name"
             android:screenOrientation="landscape"
             android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >
@@ -73,7 +72,7 @@
             android:windowSoftInputMode="adjustPan" >
         </activity>
         <activity
-            android:name=".RoomActivity"
+            android:name=".NetRoomActivity"
             android:label="@string/title_activity_room"
             android:screenOrientation="landscape"
             android:windowSoftInputMode="adjustPan" >
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/backbutton.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/button_disabled.9.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/button_focused.9.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/button_focused_disabled.9.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/button_normal.9.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/dropdown_disabled.9.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/dropdown_focused.9.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/dropdown_focused_disabled.9.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/dropdown_normal.9.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/savebutton.png has changed
--- a/project_files/Android-build/SDL-android-project/res/layout-large/activity_lobby.xml	Mon Aug 20 20:16:37 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/res/layout-large/activity_lobby.xml	Mon Aug 20 20:19:35 2012 +0200
@@ -24,7 +24,7 @@
 	            android:layout_width="fill_parent"
 	            android:layout_height="fill_parent"
 	            class="org.hedgewars.hedgeroid.RoomlistFragment"
-	            tools:layout="@layout/lobby_rooms_fragment" />
+	            tools:layout="@layout/fragment_roomlist" />
 	    </FrameLayout>
 	
 	    <RelativeLayout
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/layout-large/activity_localroom.xml	Mon Aug 20 20:19:35 2012 +0200
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent" >
+
+    <include layout="@layout/background" />
+
+    <RelativeLayout
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"
+        android:padding="2dp" >
+
+        <LinearLayout
+            android:id="@+id/upperFrame"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:layout_alignParentLeft="true"
+            android:layout_alignParentRight="true"
+            android:layout_alignParentTop="true"
+            android:layout_marginBottom="4dp"
+            android:layout_above="@+id/startGame"
+            android:baselineAligned="false"
+            android:minHeight="200dp" >
+
+            <FrameLayout
+                android:id="@+id/mapFrame"
+                android:layout_width="0dp"
+                android:layout_height="fill_parent"
+                android:layout_marginRight="4dp"
+                android:layout_weight="1"
+                android:background="@drawable/box" >
+
+                <fragment
+                    android:id="@+id/mapFragment"
+                    android:layout_width="fill_parent"
+                    android:layout_height="fill_parent"
+                    class="org.hedgewars.hedgeroid.MapFragment"
+                    tools:layout="@layout/fragment_map" />
+            </FrameLayout>
+
+            <FrameLayout
+                android:id="@+id/settingsFrame"
+                android:layout_width="0dp"
+                android:layout_height="fill_parent"
+                android:layout_marginRight="4dp"
+                android:layout_weight="1"
+                android:background="@drawable/box" >
+
+                <fragment
+                    android:id="@+id/settingsFragment"
+                    android:layout_width="fill_parent"
+                    android:layout_height="fill_parent"
+                    class="org.hedgewars.hedgeroid.SettingsFragment"
+                    tools:layout="@layout/fragment_settings" />
+            </FrameLayout>
+
+            <FrameLayout
+                android:id="@+id/teamsFrame"
+                android:layout_width="0dp"
+                android:layout_height="fill_parent"
+                android:layout_weight="1"
+                android:background="@drawable/box" >
+
+                <fragment
+                    android:id="@+id/teamsFragment"
+                    android:layout_width="fill_parent"
+                    android:layout_height="fill_parent"
+                    class="org.hedgewars.hedgeroid.TeamlistFragment"
+                    tools:layout="@layout/fragment_teamlist" />
+            </FrameLayout>
+        </LinearLayout>
+
+        <Button
+            android:id="@id/startGame"
+            android:layout_width="200dp"
+            android:layout_height="67dp"
+            android:layout_alignParentBottom="true"
+            android:layout_centerHorizontal="true"
+            android:background="@drawable/startgamebutton" />
+    </RelativeLayout>
+
+</FrameLayout>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/layout-large/activity_netroom.xml	Mon Aug 20 20:19:35 2012 +0200
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent" >
+
+    <include layout="@layout/background" />
+
+    <RelativeLayout
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"
+        android:padding="2dp" >
+
+        <LinearLayout
+            android:id="@+id/upperFrame"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:layout_alignParentLeft="true"
+            android:layout_alignParentRight="true"
+            android:layout_alignParentTop="true"
+            android:layout_marginBottom="4dp"
+            android:baselineAligned="false"
+            android:minHeight="200dp" >
+            
+            <FrameLayout
+                android:id="@+id/mapFrame"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_marginRight="4dp"
+                android:layout_weight="1"
+                android:background="@drawable/box" >
+
+                <fragment
+                    android:id="@+id/mapFragment"
+                    android:layout_width="fill_parent"
+                    android:layout_height="fill_parent"
+                    class="org.hedgewars.hedgeroid.MapFragment"
+                    tools:layout="@layout/fragment_map" />
+            </FrameLayout>
+
+            <FrameLayout
+                android:id="@+id/settingsFrame"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_marginRight="4dp"
+                android:layout_weight="1"
+                android:background="@drawable/box" >
+
+                <fragment
+                    android:id="@+id/settingsFragment"
+                    android:layout_width="fill_parent"
+                    android:layout_height="fill_parent"
+                    class="org.hedgewars.hedgeroid.SettingsFragment"
+                    tools:layout="@layout/fragment_settings" />
+            </FrameLayout>
+
+            <FrameLayout
+                android:id="@+id/teamsFrame"
+                android:layout_width="0dp"
+                android:layout_height="fill_parent"
+                android:layout_weight="1"
+                android:background="@drawable/box" >
+
+                <fragment
+                    android:id="@+id/teamsFragment"
+                    android:layout_width="fill_parent"
+                    android:layout_height="fill_parent"
+                    class="org.hedgewars.hedgeroid.TeamlistFragment"
+                    tools:layout="@layout/fragment_teamlist" />
+            </FrameLayout>
+        </LinearLayout>
+
+        <FrameLayout
+            android:id="@+id/playerFrame"
+            android:layout_width="200dp"
+            android:layout_height="fill_parent"
+            android:layout_above="@+id/startGame"
+            android:layout_alignParentRight="true"
+            android:layout_below="@id/upperFrame"
+            android:background="@drawable/box" >
+
+            <fragment
+                android:id="@+id/playerListFragment"
+                android:layout_width="fill_parent"
+                android:layout_height="fill_parent"
+                class="org.hedgewars.hedgeroid.RoomPlayerlistFragment"
+                tools:layout="@layout/fragment_playerlist" />
+        </FrameLayout>
+
+        <FrameLayout
+            android:layout_width="0dp"
+            android:layout_height="fill_parent"
+            android:layout_alignParentBottom="true"
+            android:layout_alignParentLeft="true"
+            android:layout_below="@id/upperFrame"
+            android:layout_marginRight="4dp"
+            android:layout_toLeftOf="@id/playerFrame"
+            android:background="@drawable/box" >
+
+            <fragment
+                android:id="@+id/chatFragment"
+                android:layout_width="fill_parent"
+                android:layout_height="fill_parent"
+                class="org.hedgewars.hedgeroid.ChatFragment"
+                tools:layout="@layout/fragment_chat" />
+        </FrameLayout>
+
+        <Button
+            android:id="@id/startGame"
+            android:layout_width="200dp"
+            android:layout_height="67dp"
+            android:layout_marginTop="4dp"
+            android:layout_alignParentBottom="true"
+            android:layout_alignParentRight="true"
+            android:background="@drawable/startgamebutton" />
+
+    </RelativeLayout>
+
+</FrameLayout>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/layout-large/fragment_roomlist.xml	Mon Aug 20 20:19:35 2012 +0200
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent" >
+
+    <FrameLayout
+        android:id="@+id/listHeader"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content" >
+	    <include layout="@layout/listview_room_header" />
+    </FrameLayout>
+
+    <ListView
+        android:id="@id/android:list"
+        android:layout_width="fill_parent"
+        android:layout_height="0dp"
+        android:layout_alignParentBottom="true"
+        android:layout_below="@+id/listHeader"
+        android:cacheColorHint="@android:color/transparent"
+        android:drawSelectorOnTop="false"
+        tools:listitem="@layout/listview_room" />
+
+    <TextView
+        android:id="@id/android:empty"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_centerHorizontal="true"
+        android:layout_centerVertical="true"
+        android:text="@string/no_rooms_in_list" />
+
+</RelativeLayout>
\ No newline at end of file
--- a/project_files/Android-build/SDL-android-project/res/layout-large/lobby_rooms_fragment.xml	Mon Aug 20 20:16:37 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent" >
-
-    <FrameLayout
-        android:id="@+id/listHeader"
-        android:layout_width="fill_parent"
-        android:layout_height="wrap_content" >
-	    <include layout="@layout/listview_room_header" />
-    </FrameLayout>
-
-    <ListView
-        android:id="@id/android:list"
-        android:layout_width="fill_parent"
-        android:layout_height="0dp"
-        android:layout_alignParentBottom="true"
-        android:layout_below="@+id/listHeader"
-        android:cacheColorHint="@android:color/transparent"
-        android:drawSelectorOnTop="false"
-        tools:listitem="@layout/listview_room" />
-
-    <TextView
-        android:id="@id/android:empty"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_centerHorizontal="true"
-        android:layout_centerVertical="true"
-        android:text="@string/no_rooms_in_list" />
-
-</RelativeLayout>
\ No newline at end of file
--- a/project_files/Android-build/SDL-android-project/res/layout/activity_lobby.xml	Mon Aug 20 20:16:37 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/res/layout/activity_lobby.xml	Mon Aug 20 20:19:35 2012 +0200
@@ -34,7 +34,7 @@
                     android:layout_width="fill_parent"
                     android:layout_height="fill_parent"
                     class="org.hedgewars.hedgeroid.RoomlistFragment"
-                    tools:layout="@layout/lobby_rooms_fragment" />
+                    tools:layout="@layout/fragment_roomlist" />
 
                 <fragment
                     android:id="@+id/chatFragment"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/layout/activity_localroom.xml	Mon Aug 20 20:19:35 2012 +0200
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent" >
+
+    <include layout="@layout/background" />
+
+    <TabHost
+        android:id="@android:id/tabhost"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" >
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:orientation="horizontal" >
+
+            <TabWidget
+                android:id="@android:id/tabs"
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                android:layout_weight="0" />
+
+            <FrameLayout
+                android:id="@android:id/tabcontent"
+                android:layout_width="0dip"
+                android:layout_height="match_parent"
+                android:layout_weight="1" >
+
+                <fragment
+                    android:id="@+id/mapFragment"
+                    android:layout_width="fill_parent"
+                    android:layout_height="fill_parent"
+                    class="org.hedgewars.hedgeroid.MapFragment"
+                    tools:layout="@layout/fragment_map" />
+
+                <fragment
+                    android:id="@+id/settingsFragment"
+                    android:layout_width="fill_parent"
+                    android:layout_height="fill_parent"
+                    class="org.hedgewars.hedgeroid.SettingsFragment"
+                    tools:layout="@layout/fragment_settings" />
+
+                
+                <LinearLayout
+                    android:id="@+id/teamlistContainer"
+                    android:layout_width="fill_parent"
+                    android:layout_height="fill_parent"
+                    android:orientation="vertical" >
+	                <fragment
+	                    android:id="@+id/teamlistFragment"
+	                    android:layout_width="fill_parent"
+	                    android:layout_height="0dp"
+	                    android:layout_weight="1"
+	                    class="org.hedgewars.hedgeroid.TeamlistFragment"
+	                    tools:layout="@layout/fragment_teamlist" />
+
+                    <Button
+                        android:id="@+id/startGame"
+                        android:layout_width="120dp"
+                        android:layout_height="40dp"
+                        android:layout_gravity="right"
+                        android:layout_marginTop="4dp"
+                        android:background="@drawable/startgamebutton" />
+                </LinearLayout>
+            </FrameLayout>
+        </LinearLayout>
+    </TabHost>
+
+</FrameLayout>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/layout/activity_main.xml	Mon Aug 20 20:19:35 2012 +0200
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent" >
+
+    <include layout="@layout/background" />
+
+    <RelativeLayout
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent" >
+
+        <View
+            android:id="@+id/placeholder"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:layout_centerInParent="true" />
+
+        <FrameLayout
+            android:id="@+id/frameLayout1"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentBottom="true"
+            android:layout_alignParentLeft="true"
+            android:layout_alignParentTop="true"
+            android:layout_toLeftOf="@id/placeholder" >
+
+            <Button
+                android:id="@+id/startGame"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:drawableTop="@drawable/button_local_play"
+                android:text="@string/main_button_localplay" />
+        </FrameLayout>
+
+        <FrameLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentBottom="true"
+            android:layout_alignParentRight="true"
+            android:layout_alignParentTop="true"
+            android:layout_toRightOf="@id/placeholder" >
+
+            <Button
+                android:id="@+id/joinLobby"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:drawableTop="@drawable/button_network_play"
+                android:text="@string/main_button_netplay" />
+        </FrameLayout>
+    </RelativeLayout>
+
+</FrameLayout>
\ No newline at end of file
--- a/project_files/Android-build/SDL-android-project/res/layout/activity_netroom.xml	Mon Aug 20 20:16:37 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/res/layout/activity_netroom.xml	Mon Aug 20 20:19:35 2012 +0200
@@ -6,29 +6,27 @@
 
     <include layout="@layout/background" />
 
-    <RelativeLayout
-        android:layout_width="fill_parent"
-        android:layout_height="fill_parent"
-        android:padding="5dp" >
+    <TabHost
+        android:id="@android:id/tabhost"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" >
 
         <LinearLayout
-            android:id="@+id/upperFrame"
-            android:layout_width="fill_parent"
-            android:layout_height="wrap_content"
-            android:layout_alignParentLeft="true"
-            android:layout_alignParentRight="true"
-            android:layout_alignParentTop="true"
-            android:layout_marginBottom="10dp"
-            android:baselineAligned="false"
-            android:minHeight="200dp" >
-            
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:orientation="horizontal" >
+
+            <TabWidget
+                android:id="@android:id/tabs"
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                android:layout_weight="0" />
+
             <FrameLayout
-                android:id="@+id/mapFrame"
-                android:layout_width="0dp"
-                android:layout_height="wrap_content"
-                android:layout_marginRight="10dp"
-                android:layout_weight="1"
-                android:background="@drawable/box" >
+                android:id="@android:id/tabcontent"
+                android:layout_width="0dip"
+                android:layout_height="match_parent"
+                android:layout_weight="1" >
 
                 <fragment
                     android:id="@+id/mapFragment"
@@ -36,15 +34,6 @@
                     android:layout_height="fill_parent"
                     class="org.hedgewars.hedgeroid.MapFragment"
                     tools:layout="@layout/fragment_map" />
-            </FrameLayout>
-
-            <FrameLayout
-                android:id="@+id/settingsFrame"
-                android:layout_width="0dp"
-                android:layout_height="wrap_content"
-                android:layout_marginRight="10dp"
-                android:layout_weight="1"
-                android:background="@drawable/box" >
 
                 <fragment
                     android:id="@+id/settingsFragment"
@@ -52,58 +41,45 @@
                     android:layout_height="fill_parent"
                     class="org.hedgewars.hedgeroid.SettingsFragment"
                     tools:layout="@layout/fragment_settings" />
-            </FrameLayout>
-
-            <FrameLayout
-                android:id="@+id/teamsFrame"
-                android:layout_width="0dp"
-                android:layout_height="fill_parent"
-                android:layout_weight="1"
-                android:background="@drawable/box" >
 
                 <fragment
-                    android:id="@+id/teamsFragment"
+                    android:id="@+id/teamlistFragment"
                     android:layout_width="fill_parent"
                     android:layout_height="fill_parent"
                     class="org.hedgewars.hedgeroid.TeamlistFragment"
                     tools:layout="@layout/fragment_teamlist" />
+
+                <fragment
+                    android:id="@+id/chatFragment"
+                    android:layout_width="fill_parent"
+                    android:layout_height="fill_parent"
+                    class="org.hedgewars.hedgeroid.ChatFragment"
+                    tools:layout="@layout/fragment_chat" />
+
+                <LinearLayout
+                    android:id="@+id/playerListContainer"
+                    android:layout_width="fill_parent"
+                    android:layout_height="fill_parent"
+                    android:orientation="vertical" >
+
+                    <fragment
+                        android:id="@+id/playerListFragment"
+                        android:layout_width="fill_parent"
+                        android:layout_height="0dp"
+                        android:layout_weight="1"
+                        class="org.hedgewars.hedgeroid.RoomPlayerlistFragment"
+                        tools:layout="@layout/fragment_playerlist" />
+
+                    <Button
+                        android:id="@+id/startGame"
+                        android:layout_width="120dp"
+                        android:layout_height="40dp"
+                        android:layout_gravity="right"
+                        android:layout_marginTop="4dp"
+                        android:background="@drawable/startgamebutton" />
+                </LinearLayout>
             </FrameLayout>
         </LinearLayout>
-
-        <FrameLayout
-            android:id="@+id/playerFrame"
-            android:layout_width="200dp"
-            android:layout_height="fill_parent"
-            android:layout_alignParentBottom="true"
-            android:layout_alignParentRight="true"
-            android:layout_below="@id/upperFrame"
-            android:background="@drawable/box" >
-
-            <fragment
-                android:id="@+id/playerListFragment"
-                android:layout_width="fill_parent"
-                android:layout_height="fill_parent"
-                class="org.hedgewars.hedgeroid.RoomPlayerlistFragment"
-                tools:layout="@layout/fragment_playerlist" />
-        </FrameLayout>
-
-        <FrameLayout
-            android:layout_width="0dp"
-            android:layout_height="fill_parent"
-            android:layout_alignParentBottom="true"
-            android:layout_alignParentLeft="true"
-            android:layout_below="@id/upperFrame"
-            android:layout_marginRight="10dp"
-            android:layout_toLeftOf="@id/playerFrame"
-            android:background="@drawable/box" >
-
-            <fragment
-                android:id="@+id/chatFragment"
-                android:layout_width="fill_parent"
-                android:layout_height="fill_parent"
-                class="org.hedgewars.hedgeroid.ChatFragment"
-                tools:layout="@layout/fragment_chat" />
-        </FrameLayout>
-    </RelativeLayout>
+    </TabHost>
 
 </FrameLayout>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/layout/activity_teamlist.xml	Mon Aug 20 20:19:35 2012 +0200
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout
+  xmlns:android="http://schemas.android.com/apk/res/android"
+  android:layout_width="fill_parent"
+  android:layout_height="fill_parent">
+  
+  <include layout="@layout/background"/>
+
+  <TextView
+    android:id="@android:id/empty"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:gravity="center"
+    android:text="@string/teamlist_empty" />
+  
+  <ListView
+  	android:id="@android:id/list"
+  	android:layout_height="fill_parent"
+  	android:layout_width="wrap_content"
+  	android:layout_margin="3dp"
+  	android:background="@drawable/box" />
+
+  <ImageButton
+   	android:id="@+id/btnAdd"
+   	android:layout_width="wrap_content"
+   	android:layout_height="50dip"
+   	android:layout_alignParentBottom="true"
+   	android:layout_alignParentRight="true"
+   	android:adjustViewBounds="true"
+   	android:scaleType="centerInside"
+   	android:background="@android:color/transparent"
+   	android:src="@drawable/settings"
+   	android:contentDescription="@string/teamlist_add_content_description"/>
+
+</RelativeLayout>
--- a/project_files/Android-build/SDL-android-project/res/layout/backbutton.xml	Mon Aug 20 20:16:37 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<merge xmlns:android="http://schemas.android.com/apk/res/android">
-    <ImageButton
-    	android:id="@+id/btnBack"
-    	android:layout_width="120dip"
-    	android:layout_height="40dip"
-    	android:layout_alignParentBottom="true"
-    	android:layout_alignParentLeft="true"
-    	android:adjustViewBounds="true"
-    	android:scaleType="centerInside"
-    	android:background="@android:color/transparent"
-    	android:src="@drawable/backbutton"/>
-</merge>
\ No newline at end of file
--- a/project_files/Android-build/SDL-android-project/res/layout/config.xml	Mon Aug 20 20:16:37 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="fill_parent"
-    android:layout_height="fill_parent">
-    	
-    <ListView
-    	android:id="@+id/listView"
-    	android:layout_width="wrap_content"
-    	android:layout_height="fill_parent"/>
-    	
-</RelativeLayout>
-
--- a/project_files/Android-build/SDL-android-project/res/layout/fragment_map.xml	Mon Aug 20 20:16:37 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/res/layout/fragment_map.xml	Mon Aug 20 20:19:35 2012 +0200
@@ -15,7 +15,6 @@
         android:layout_height="128dip"
         android:layout_alignParentTop="true"
         android:layout_centerHorizontal="true"
-        android:layout_margin="5dip"
         android:background="@drawable/box"
         android:scaleType="fitCenter"
         android:src="@drawable/roomlist_preparing" />
@@ -27,7 +26,7 @@
         android:layout_below="@id/mapPreview"
         android:stretchColumns="1" >
 
-        <TableRow>
+        <TableRow android:layout_marginTop="5dip" >
 
             <TextView
                 android:layout_width="wrap_content"
@@ -38,10 +37,14 @@
                 android:id="@+id/spinMapType"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
+                android:layout_marginLeft = "5dip"
                 android:background="@drawable/dropdown" />
         </TableRow>
 
-        <TableRow android:id="@+id/rowMapName">
+        <TableRow
+            android:id="@+id/rowMapName"
+            android:layout_marginTop="5dip" >
+
             <TextView
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
@@ -52,34 +55,57 @@
                 android:id="@+id/spinMapName"
                 android:layout_width="fill_parent"
                 android:layout_height="wrap_content"
+                android:layout_marginLeft = "5dip"
                 android:background="@drawable/dropdown" />
         </TableRow>
-		<TableRow android:id="@+id/rowTemplateFilter">
-		    <TextView
+
+        <TableRow
+            android:id="@+id/rowTemplateFilter"
+            android:layout_marginTop="5dip"
+            android:visibility="gone" >
+
+            <TextView
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_gravity="center_vertical"
                 android:text="@string/map_template" />
-		    
+
             <Spinner
                 android:id="@+id/spinTemplateFilter"
                 android:layout_width="fill_parent"
                 android:layout_height="wrap_content"
+                android:layout_marginLeft = "5dip"
                 android:background="@drawable/dropdown" />
-		</TableRow>
-		<TableRow android:id="@+id/rowMazeSize">
-		    <TextView
+        </TableRow>
+
+        <TableRow
+            android:id="@+id/rowMazeSize"
+            android:layout_marginTop="5dip"
+            android:visibility="gone" >
+
+            <TextView
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_gravity="center_vertical"
                 android:text="@string/map_maze_size" />
-		    
+
             <Spinner
                 android:id="@+id/spinMazeSize"
                 android:layout_width="fill_parent"
                 android:layout_height="wrap_content"
+                android:layout_marginLeft = "5dip"
                 android:background="@drawable/dropdown" />
-		</TableRow>
+        </TableRow>
+
+        <Button
+            android:id="@+id/btnEditDrawnMap"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="5dip"
+            android:background="@drawable/button"
+            android:enabled="false"
+            android:text="@string/map_button_editdrawnmap"
+            android:visibility="gone" />
     </TableLayout>
 
 </RelativeLayout>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/layout/fragment_roomlist.xml	Mon Aug 20 20:19:35 2012 +0200
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    android:paddingLeft="8dp"
+    android:paddingRight="8dp" >
+
+    <ListView
+        android:id="@id/android:list"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:drawSelectorOnTop="false"
+        android:cacheColorHint="@android:color/transparent"
+        tools:listitem="@layout/listview_room" />
+
+    <TextView
+        android:id="@id/android:empty"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:text="@string/no_rooms_in_list" />
+
+</LinearLayout>
\ No newline at end of file
--- a/project_files/Android-build/SDL-android-project/res/layout/fragment_settings.xml	Mon Aug 20 20:16:37 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/res/layout/fragment_settings.xml	Mon Aug 20 20:19:35 2012 +0200
@@ -27,10 +27,11 @@
                 android:id="@+id/spinGameplay"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
+                android:layout_marginLeft="5dip"
                 android:background="@drawable/dropdown" />
         </TableRow>
 
-        <TableRow>
+        <TableRow android:layout_marginTop="5dip" >
 
             <TextView
                 android:id="@+id/txtGamescheme"
@@ -42,10 +43,11 @@
                 android:id="@+id/spinGamescheme"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
+                android:layout_marginLeft="5dip"
                 android:background="@drawable/dropdown" />
         </TableRow>
 
-        <TableRow>
+        <TableRow android:layout_marginTop="5dip" >
 
             <TextView
                 android:id="@+id/txtweapons"
@@ -57,6 +59,7 @@
                 android:id="@+id/spinweapons"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
+                android:layout_marginLeft="5dip"
                 android:background="@drawable/dropdown" />
         </TableRow>
     </TableLayout>
@@ -76,6 +79,7 @@
         android:layout_height="wrap_content"
         android:layout_alignParentRight="true"
         android:layout_below="@id/gameOptions"
+        android:layout_marginTop="5dip"
         android:layout_toRightOf="@+id/imgTheme"
         android:background="@drawable/dropdown" />
 
--- a/project_files/Android-build/SDL-android-project/res/layout/fragment_teamlist.xml	Mon Aug 20 20:16:37 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/res/layout/fragment_teamlist.xml	Mon Aug 20 20:19:35 2012 +0200
@@ -3,21 +3,32 @@
     xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:orientation="vertical" >
+    android:orientation="vertical"
+    android:paddingBottom="3dp"
+    android:paddingLeft="5dp"
+    android:paddingRight="3dp"
+    android:paddingTop="3dp" >
 
-    <ListView 
+    <ListView
         android:id="@android:id/list"
         android:layout_width="match_parent"
         android:layout_height="0dp"
-        android:layout_weight="1" 
-        android:cacheColorHint="@android:color/transparent"
-        />
+        android:layout_weight="1"
+        android:cacheColorHint="@android:color/transparent" />
 
-	<Button
+    <TextView
+        android:id="@id/android:empty"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1"
+        android:gravity="center"
+        android:text="@string/no_teams_in_list" />
+    
+    <Button
         android:id="@+id/addTeamButton"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:text="@string/teamlist_addteam"
-        android:background="@drawable/button" />
+        android:background="@drawable/button"
+        android:text="@string/teamlist_addteam" />
 
 </LinearLayout>
\ No newline at end of file
--- a/project_files/Android-build/SDL-android-project/res/layout/lobby_rooms_fragment.xml	Mon Aug 20 20:16:37 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:orientation="vertical"
-    android:paddingLeft="8dp"
-    android:paddingRight="8dp" >
-
-    <ListView
-        android:id="@id/android:list"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:drawSelectorOnTop="false"
-        android:cacheColorHint="@android:color/transparent"
-        tools:listitem="@layout/listview_room" />
-
-    <TextView
-        android:id="@id/android:empty"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:text="@string/no_rooms_in_list" />
-
-</LinearLayout>
\ No newline at end of file
--- a/project_files/Android-build/SDL-android-project/res/layout/main.xml	Mon Aug 20 20:16:37 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,54 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="fill_parent"
-    android:layout_height="fill_parent" >
-
-    <include layout="@layout/background" />
-
-    <RelativeLayout
-        android:layout_width="fill_parent"
-        android:layout_height="fill_parent" >
-
-        <View
-            android:id="@+id/placeholder"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:layout_centerInParent="true" />
-
-        <FrameLayout
-            android:id="@+id/frameLayout1"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_alignParentBottom="true"
-            android:layout_alignParentLeft="true"
-            android:layout_alignParentTop="true"
-            android:layout_toLeftOf="@id/placeholder" >
-
-            <Button
-                android:id="@+id/startGame"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_gravity="center"
-                android:drawableTop="@drawable/button_local_play"
-                android:text="@string/main_button_localplay" />
-        </FrameLayout>
-
-        <FrameLayout
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_alignParentBottom="true"
-            android:layout_alignParentRight="true"
-            android:layout_alignParentTop="true"
-            android:layout_toRightOf="@id/placeholder" >
-
-            <Button
-                android:id="@+id/joinLobby"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_gravity="center"
-                android:drawableTop="@drawable/button_network_play"
-                android:text="@string/main_button_netplay" />
-        </FrameLayout>
-    </RelativeLayout>
-
-</FrameLayout>
\ No newline at end of file
--- a/project_files/Android-build/SDL-android-project/res/layout/roomlist_player_team_count.xml	Mon Aug 20 20:16:37 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<merge xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools">
-</merge>
\ No newline at end of file
--- a/project_files/Android-build/SDL-android-project/res/layout/roomlist_player_team_count_header.xml	Mon Aug 20 20:16:37 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<merge xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools">
-</merge>
\ No newline at end of file
--- a/project_files/Android-build/SDL-android-project/res/layout/savebutton.xml	Mon Aug 20 20:16:37 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<merge xmlns:android="http://schemas.android.com/apk/res/android">
-    <ImageButton
-    	android:id="@+id/btnSave"
-    	android:layout_width="120dip"
-    	android:layout_height="40dip"
-    	android:layout_alignParentBottom="true"
-    	android:layout_alignParentRight="true"
-    	android:adjustViewBounds="true"
-    	android:scaleType="centerInside"
-    	android:background="@android:color/transparent"
-    	android:src="@drawable/savebutton"/>
-</merge>
\ No newline at end of file
--- a/project_files/Android-build/SDL-android-project/res/layout/starting_game.xml	Mon Aug 20 20:16:37 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,166 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="fill_parent"
-    android:layout_height="fill_parent">
-    <include
-    	layout="@layout/background"/>
-     
-    <ImageView
-    	android:id="@+id/mapPreview"
-    	android:layout_width="256dip"
-    	android:layout_height="128dip"
-    	android:layout_margin="5dip"
-    	android:scaleType="fitXY"
-    	android:background="@drawable/box"
-    	android:src="@drawable/backbutton"/>
-    
-    <Spinner 
-       	android:id="@+id/spinMaps"
-       	android:layout_height="wrap_content"
-       	android:layout_width="wrap_content"    
-       	android:layout_below="@id/mapPreview"
-       	android:layout_alignRight="@id/mapPreview"
-       	android:layout_toRightOf="@+id/txtMap"
-       	android:background="@drawable/dropdown"/>
-    <TextView
-		android:id="@id/txtMap"
-		android:layout_width="wrap_content"
-		android:layout_height="wrap_content"
-		android:text="@string/start_map"
-		android:layout_alignTop="@id/spinMaps"
-		android:layout_alignBottom="@id/spinMaps"
-		android:layout_alignLeft="@id/mapPreview"
-		android:gravity="center"/>	
-   	
-    <TableLayout 
-       	android:id="@+id/gameOptions" 
-       	android:layout_height="wrap_content" 
-       	android:layout_width="wrap_content"
-       	android:layout_centerHorizontal="true"
-       	android:layout_toRightOf="@id/mapPreview" 
-       	android:layout_alignParentRight="true"
-       	android:padding="3dip"
-       	android:layout_margin="5dip"
-       	android:background="@drawable/box"
-       	android:stretchColumns="0,2"
-       	android:shrinkColumns="1">
-	       	
-       	<TableRow>
-        	 <TextView 
-		        android:id="@+id/txtGameplay"
-		        android:layout_height="wrap_content"
-		        android:layout_width="wrap_content"
-		        android:text="@string/start_gameplay"/>
-        	<Spinner
-	        	android:id="@+id/spinGameplay"
-	        	android:layout_height="wrap_content"
-		        android:layout_width="wrap_content"
-		        android:background="@drawable/dropdown"
-		        />
-		</TableRow>  
-		<TableRow>
-		    <TextView 
-		        android:id="@+id/txtGamescheme"
-		        android:layout_height="wrap_content"
-		        android:layout_width="wrap_content"
-		        android:text="@string/start_gamescheme"/>
-		    <Spinner
-		       	android:id="@+id/spinGamescheme"
-		       	android:layout_height="wrap_content"
-		        android:layout_width="wrap_content"
-		        android:background="@drawable/dropdown"/>
-		    <ImageButton
-		    	android:id="@+id/btnGamescheme"
-		    	android:layout_height="wrap_content"
-		        android:layout_width="wrap_content"
-		        android:background="@drawable/edit"
-		        android:adjustViewBounds="true"
-		        android:scaleType="centerInside"
-		        android:layout_gravity="center"
-		        android:padding="3dip"/>
-		 </TableRow>
-		 <TableRow>    
-		     <TextView 
-		        android:id="@+id/txtweapons"
-		        android:layout_height="wrap_content"
-		        android:layout_width="wrap_content"
-		        android:layout_below="@id/txtGamescheme"
-		        android:layout_marginTop="5dip"
-		        android:text="@string/start_weapons"/>
-	        
-	        <Spinner
-	        	android:id="@+id/spinweapons"
-	        	android:layout_height="wrap_content"
-		        android:layout_width="wrap_content"
-		        android:background="@drawable/dropdown"/>
-		    
-		    <ImageButton
-		    	android:id="@+id/btnweapons"
-		    	android:layout_height="wrap_content"
-		        android:layout_width="wrap_content"
-		        android:background="@drawable/edit"
-		        android:adjustViewBounds="true"
-		        android:scaleType="centerInside"
-		        android:layout_gravity="center"
-		        android:padding="3dip"/>
-        </TableRow>	
-    </TableLayout>
-        
-    <ImageView 
-       	android:id="@+id/imgTheme"
-       	android:layout_height="wrap_content" 
-       	android:layout_width="wrap_content"
-       	android:layout_alignTop="@+id/spinTheme"
-       	android:layout_alignBottom="@id/spinTheme"
-       	android:layout_alignLeft="@id/gameOptions"
-       	android:adjustViewBounds="true"/>
-       
-    <Spinner
-        android:id="@id/spinTheme"
-        android:layout_height="wrap_content"
-        android:layout_width="wrap_content" 
-        android:layout_toRightOf="@+id/imgTheme"
-        android:layout_alignParentRight="true"
-       	android:layout_below="@id/gameOptions"
-       	android:background="@drawable/dropdown"/>
-        
-	<include layout="@layout/backbutton"/>
-    
-    <LinearLayout
-    	android:layout_width="wrap_content"
-    	android:layout_height="wrap_content"
-    	android:layout_alignParentBottom="true"
-    	android:layout_centerHorizontal="true"
-    	android:orientation="horizontal">
-    <ImageButton
-    	android:id="@+id/btnTeams"
-    	android:layout_width="120dip"
-    	android:layout_height="40dip"
-    	android:adjustViewBounds="true"
-    	android:scaleType="centerInside"
-    	android:background="@android:color/transparent"
-    	android:src="@drawable/teams"/>
-    <ImageView
-    	android:id="@+id/imgTeamsCount"
-    	android:layout_width="40dip"
-    	android:layout_height="40dip"
-    	android:adjustViewBounds="true"
-    	android:scaleType="centerInside"
-    	android:background="@android:color/transparent"
-    	android:src="@drawable/teams_number"/>
-        
-    </LinearLayout>
-
-    <ImageButton
-    	android:id="@+id/btnStart"
-    	android:layout_width="120dip"
-    	android:layout_height="40dip"
-    	android:layout_alignParentBottom="true"
-    	android:layout_alignParentRight="true"
-    	android:adjustViewBounds="true"
-    	android:scaleType="centerInside"
-    	android:background="@android:color/transparent"
-    	android:src="@drawable/startgamebutton"/>
-
-</RelativeLayout>
-
--- a/project_files/Android-build/SDL-android-project/res/layout/tab_indicator.xml	Mon Aug 20 20:16:37 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="fill_parent"
-    android:layout_height="0dp"
-    android:layout_weight="1"
-    android:orientation="vertical"
-    android:background="@drawable/box">
-
-    <ImageView android:id="@+id/icon"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_centerHorizontal="true"
-    />
-
-    <TextView android:id="@+id/title"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:scrollHorizontally="false"
-        android:padding="4dp"
-        android:layout_alignParentBottom="true"
-        android:layout_centerHorizontal="true"
-        style="?android:attr/tabWidgetStyle"
-    />
-</RelativeLayout>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/layout/tab_indicator_vertical.xml	Mon Aug 20 20:19:35 2012 +0200
@@ -0,0 +1,23 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="0dp"
+    android:layout_weight="1"
+    android:orientation="vertical"
+    android:background="@drawable/box">
+
+    <ImageView android:id="@+id/icon"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_centerHorizontal="true"
+    />
+
+    <TextView android:id="@+id/title"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:scrollHorizontally="false"
+        android:padding="4dp"
+        android:layout_alignParentBottom="true"
+        android:layout_centerHorizontal="true"
+        style="?android:attr/tabWidgetStyle"
+    />
+</RelativeLayout>
--- a/project_files/Android-build/SDL-android-project/res/layout/team_selection_dialog.xml	Mon Aug 20 20:16:37 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout
-  xmlns:android="http://schemas.android.com/apk/res/android"
-  android:orientation="vertical"
-  android:layout_width="wrap_content"
-  android:layout_height="wrap_content">
-  <TextView
-  	android:id="@+id/team_selection_dialog_select"
-  	android:layout_width="wrap_content"
-  	android:layout_height="wrap_content"
-  	android:text="@string/select"/>
-  <TextView
-  	android:id="@+id/team_selection_dialog_edit"
-  	android:layout_width="wrap_content"
-  	android:layout_height="wrap_content"
-  	android:text="@string/edit"/>
-  <TextView
-  	android:id="@+id/team_selection_dialog_delete"
-  	android:layout_width="wrap_content"
-  	android:layout_height="wrap_content"
-  	android:text="@string/delete"/>
-</LinearLayout>
--- a/project_files/Android-build/SDL-android-project/res/layout/team_selector.xml	Mon Aug 20 20:16:37 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout
-  xmlns:android="http://schemas.android.com/apk/res/android"
-  android:layout_width="fill_parent"
-  android:layout_height="fill_parent">
-  
-  <include layout="@layout/background"/>
-
-  <ImageButton
-   	android:id="@+id/btnAdd"
-   	android:layout_width="wrap_content"
-   	android:layout_height="50dip"
-   	android:layout_alignParentBottom="true"
-   	android:layout_alignParentRight="true"
-   	android:adjustViewBounds="true"
-   	android:scaleType="centerInside"
-   	android:background="@android:color/transparent"
-   	android:src="@drawable/settings"/>
- <TextView
-  	android:id="@+id/txtInfo"
-  	android:layout_height="wrap_content"
-  	android:layout_width="fill_parent"
-  	android:layout_alignParentBottom="true"
-  	android:layout_toRightOf="@id/btnBack"
-  	android:layout_toLeftOf="@id/btnAdd"
-  	android:layout_alignTop="@id/btnBack"
-  	android:layout_margin="3dp"
-  	android:gravity="center"
-  	android:background="@drawable/box"/>
-  	
-  
-
-  <LinearLayout
-  	android:orientation="horizontal"
-  	android:layout_width="fill_parent"
-  	android:layout_height="fill_parent"
-  	android:layout_above="@id/txtInfo"
-  	android:layout_margin="3dp">
-  	
-	  <ListView
-	  	android:id="@+id/selectedTeams"
-	  	android:layout_height="fill_parent"
-	  	android:layout_width="wrap_content"
-	  	android:layout_margin="3dp"
-	  	android:background="@drawable/box"
-	  	android:layout_weight="1"/>
-	  	
-	  <ListView
-	  	android:id="@+id/availableTeams"
-	  	android:layout_height="fill_parent"
-	  	android:layout_width="wrap_content"
-	  	android:layout_margin="3dp"
-	  	android:background="@drawable/box"
-	  	android:layout_weight="1"/>
-  </LinearLayout>
-</RelativeLayout>
--- a/project_files/Android-build/SDL-android-project/res/menu/main_options.xml	Mon Aug 20 20:16:37 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/res/menu/main_options.xml	Mon Aug 20 20:19:35 2012 +0200
@@ -10,6 +10,10 @@
         android:icon="@android:drawable/ic_menu_preferences"
         android:showAsAction="ifRoom|withText" />
     <item
+        android:id="@+id/edit_teams"
+        android:title="@string/edit_teams_menu"
+        android:showAsAction="ifRoom|withText" />
+    <item
         android:id="@+id/edit_weaponsets"
         android:title="@string/edit_weaponsets_menu"
         android:showAsAction="ifRoom|withText" />
--- a/project_files/Android-build/SDL-android-project/res/values/strings.xml	Mon Aug 20 20:16:37 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/res/values/strings.xml	Mon Aug 20 20:19:35 2012 +0200
@@ -36,14 +36,17 @@
     
     <!-- start game -->
     <string name="start_gameplay">Style</string>
-    <string name="start_gamescheme">Game scheme</string>
+    <string name="start_gamescheme">Scheme</string>
     <string name="start_weapons">Weapons</string>
     <string name="start_map">Map</string>
     <string name="start_filter">Filter</string>
 
     <!-- Teams -->
-    <string name="not_enough_teams">Not enough teams</string>
-    <string name="teams_info_template">Selected teams = %d</string>
+    <string name="not_enough_teams">You need at least two teams.</string>
+    <string name="not_enough_clans">You need at least two different team colors (clans).</string>
+    <string name="teamlist_empty">No teams</string>
+    <string name="teamlist_add_content_description">New team</string>
+    
     <!-- Settings -->
     <string name="name">Name</string>
     <string name="name_default">Unnamed</string>
@@ -76,6 +79,7 @@
     <string name="map_template">Type</string>
     <string name="map_maze_size">Type</string>
     <string name="map_mission_prefix">Mission: </string>
+    <string name="map_button_editdrawnmap">Edit drawn map</string>
     <string-array name="map_types">
         <item>Generated map</item>
         <item>Generated maze</item>
@@ -106,6 +110,8 @@
     <string name="teamlist_addteam">Add team</string>
     <string name="teamlist_color_button_description">Team color</string>
     <string name="teamlist_hogcount_button_description">Hog count</string>
+    <string name="no_teams_in_list">No teams</string>
+    <string name="edit_teams_menu">Edit Teams</string>
     
     <!-- Roomlist -->
     <string name="roomlist_header_roomname">Room Name</string>
@@ -177,4 +183,11 @@
     <string name="edit_weaponsets_menu">Edit Weaponsets</string>
     
     <string name="schemelist_add_button_text">New Scheme</string>
+    
+    <!-- Room activity tabs -->
+    <string name="room_tab_map">Map</string>
+    <string name="room_tab_settings">Game</string>
+    <string name="room_tab_teams">Teams</string>
+    <string name="room_tab_chat">Chat</string>
+    <string name="room_tab_players">Users</string>
 </resources>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/BasicRoomState.java	Mon Aug 20 20:19:35 2012 +0200
@@ -0,0 +1,161 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid;
+
+import static org.hedgewars.hedgeroid.util.ObjectUtils.equal;
+
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.hedgewars.hedgeroid.RoomStateManager;
+import org.hedgewars.hedgeroid.Datastructures.MapRecipe;
+import org.hedgewars.hedgeroid.Datastructures.Scheme;
+import org.hedgewars.hedgeroid.Datastructures.TeamInGame;
+import org.hedgewars.hedgeroid.Datastructures.Weaponset;
+
+/**
+ * Common base implementation for a roomstate that will call listeners on every
+ * change. The derived classes have to coordinate how state is changed to
+ * complete the implementation of the RoomStateManager interface.
+ * 
+ * See {@link RoomStateManager} for a description of what this is for.
+ */
+public abstract class BasicRoomState implements RoomStateManager {
+	private final List<RoomStateManager.Listener> observers = new LinkedList<RoomStateManager.Listener>();
+	
+	private boolean chief;
+	private String gameStyle;
+	private Scheme scheme;
+	private MapRecipe map;
+	private Weaponset weaponset;
+	private Map<String, TeamInGame> teams = Collections.emptyMap();
+	
+	public final MapRecipe getMapRecipe() {
+		return map;
+	}
+
+	public final boolean getChiefStatus() {
+		return chief;
+	}
+
+	public final Scheme getScheme() {
+		return scheme;
+	}
+
+	public final String getGameStyle() {
+		return gameStyle;
+	}
+
+	public final Weaponset getWeaponset() {
+		return weaponset;
+	}
+	
+	public final Map<String, TeamInGame> getTeams() {
+		return teams;
+	}
+	
+	public final void setWeaponset(Weaponset weaponset) {
+		if(!equal(weaponset, this.weaponset)) {
+			this.weaponset = weaponset;
+			for(RoomStateManager.Listener observer : observers) {
+				observer.onWeaponsetChanged(weaponset);
+			}
+		}
+	}
+	
+	public final void setMapRecipe(MapRecipe map) {
+		if(!equal(map, this.map)) { 
+			this.map = map;
+			for(RoomStateManager.Listener observer : observers) {
+				observer.onMapChanged(map);
+			}
+		}
+	}
+	
+	public final void setGameStyle(String gameStyle) {
+		if(!equal(gameStyle, this.gameStyle)) {
+			this.gameStyle = gameStyle;
+			for(RoomStateManager.Listener observer : observers) {
+				observer.onGameStyleChanged(gameStyle);
+			}
+		}
+	}
+	
+	public final void setScheme(Scheme scheme) {
+		if(!equal(scheme, this.scheme)) {
+			this.scheme = scheme;
+			for(RoomStateManager.Listener observer : observers) {
+				observer.onSchemeChanged(scheme);
+			}
+		}
+	}
+	
+	public final void setChief(boolean chief) {
+		if(chief != this.chief) {
+			this.chief = chief;
+			for(RoomStateManager.Listener observer : observers) {
+				observer.onChiefStatusChanged(chief);
+			}
+		}
+	}
+	
+	public final void putTeam(TeamInGame team) {
+		TeamInGame oldEntry = teams.get(team.team.name);
+		if(!equal(team, oldEntry)) {
+			Map<String, TeamInGame> changedMap = new TreeMap<String, TeamInGame>(teams);
+			changedMap.put(team.team.name, team);
+			teams = Collections.unmodifiableMap(changedMap);
+			for(RoomStateManager.Listener observer : observers) {
+				observer.onTeamsChanged(teams);
+			}
+		}
+	}
+	
+	public final void removeTeam(String teamname) {
+		if(teams.containsKey(teamname)) {
+			Map<String, TeamInGame> changedMap = new TreeMap<String, TeamInGame>(teams);
+			changedMap.remove(teamname);
+			teams = Collections.unmodifiableMap(changedMap);
+			for(RoomStateManager.Listener observer : observers) {
+				observer.onTeamsChanged(teams);
+			}
+		}
+	}
+	
+	public final void setTeams(Map<String, TeamInGame> newTeams) {
+		if(!newTeams.equals(teams)) {
+			teams = Collections.unmodifiableMap(new TreeMap<String, TeamInGame>(newTeams));
+			for(RoomStateManager.Listener observer : observers) {
+				observer.onTeamsChanged(teams);
+			}
+		}
+	}
+	
+	public final void addListener(Listener observer) {
+		observers.add(observer);
+	}
+
+	public final void removeListener(Listener observer) {
+		observers.remove(observer);
+	}
+}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/ChatFragment.java	Mon Aug 20 20:16:37 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/ChatFragment.java	Mon Aug 20 20:19:35 2012 +0200
@@ -1,3 +1,22 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package org.hedgewars.hedgeroid;
 
 import org.hedgewars.hedgeroid.R;
@@ -15,11 +34,13 @@
 import android.widget.TextView;
 import android.widget.TextView.OnEditorActionListener;
 
+/**
+ * This fragment displays a chatlog and text input field for chatting in either
+ * the lobby or a room.
+ */
 public class ChatFragment extends Fragment {
-	public static final String ARGUMENT_INROOM = "inRoom";
-	
 	private ChatlogAdapter adapter;
-	private Netplay netconn;
+	private Netplay netplay;
 	private MessageLog messageLog;
 	private boolean inRoom;
 	
@@ -30,22 +51,22 @@
 	@Override
 	public void onCreate(Bundle savedInstanceState) {
 		super.onCreate(savedInstanceState);
-		netconn = Netplay.getAppInstance(getActivity().getApplicationContext());
+		netplay = Netplay.getAppInstance(getActivity().getApplicationContext());
 		adapter = new ChatlogAdapter(getActivity());
 	}
 	
 	@Override
 	public void onStart() {
 		super.onStart();
-		messageLog = inRoom ? netconn.roomChatlog : netconn.lobbyChatlog;
+		messageLog = inRoom ? netplay.roomChatlog : netplay.lobbyChatlog;
     	adapter.setLog(messageLog.getLog());
-    	messageLog.registerObserver(adapter);
+    	messageLog.addListener(adapter);
 	}
 	
 	@Override
 	public void onStop() {
 		super.onStop();
-		messageLog.unregisterObserver(adapter);
+		messageLog.removeListener(adapter);
 	}
 	
 	@Override
@@ -70,7 +91,7 @@
 			String text = v.getText().toString();
 			if(text.length()>0) {
 				v.setText("");
-				netconn.sendChat(text);
+				netplay.sendChat(text);
 			}
 			return true;
 		}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/ChatlogAdapter.java	Mon Aug 20 20:16:37 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/ChatlogAdapter.java	Mon Aug 20 20:19:35 2012 +0200
@@ -1,10 +1,29 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package org.hedgewars.hedgeroid;
 
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 
-import org.hedgewars.hedgeroid.netplay.MessageLog.Observer;
+import org.hedgewars.hedgeroid.netplay.MessageLog;
 
 import android.content.Context;
 import android.text.method.LinkMovementMethod;
@@ -30,7 +49,14 @@
 	}
 }
 
-public class ChatlogAdapter extends BaseAdapter implements Observer {
+/**
+ * For performance reasons, the chatlog is implemented as ListView instead of a
+ * single TextView (although I later learned that TextView might also have
+ * facilities for efficient appending with limited backlog... oh well, this
+ * works). Every chat line is a line in the ListView, and this adapter prepares
+ * the textviews from a messagelog in an efficient way.
+ */
+public class ChatlogAdapter extends BaseAdapter implements MessageLog.Listener {
 	long idOffset = 0;
 	private List<CharSequence> log = new ArrayList<CharSequence>();
 	private Context context;
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/ConnectingDialog.java	Mon Aug 20 20:16:37 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/ConnectingDialog.java	Mon Aug 20 20:19:35 2012 +0200
@@ -1,3 +1,22 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package org.hedgewars.hedgeroid;
 
 import org.hedgewars.hedgeroid.netplay.Netplay;
@@ -12,13 +31,21 @@
 import android.content.IntentFilter;
 import android.os.Bundle;
 import android.support.v4.content.LocalBroadcastManager;
+import android.widget.Toast;
 
+/**
+ * Indeterminate progress dialog that is shown in the MainActivity while trying
+ * to connect to the server. If the connection fails (disconnect before we reach
+ * lobby state), an error toast with the disconnect message is shown.
+ * 
+ */
 public class ConnectingDialog extends ConnectionDependendDialogFragment {
 	@Override
 	public void onStart() {
 		super.onStart();
 		LocalBroadcastManager.getInstance(getActivity().getApplicationContext()).registerReceiver(connectedReceiver, new IntentFilter(Netplay.ACTION_CONNECTED));
-
+		LocalBroadcastManager.getInstance(getActivity().getApplicationContext()).registerReceiver(disconnectedReceiver, new IntentFilter(Netplay.ACTION_DISCONNECTED));
+		
 		if(Netplay.getAppInstance(getActivity().getApplicationContext()).getState() != State.CONNECTING) {
 			dismiss();
 		}
@@ -28,6 +55,7 @@
 	public void onStop() {
 		super.onStop();
 		LocalBroadcastManager.getInstance(getActivity().getApplicationContext()).unregisterReceiver(connectedReceiver);
+		LocalBroadcastManager.getInstance(getActivity().getApplicationContext()).unregisterReceiver(disconnectedReceiver);
 	}
 	
 	@Override
@@ -52,6 +80,13 @@
 		}
 	};
 	
+	private BroadcastReceiver disconnectedReceiver = new BroadcastReceiver() {
+		@Override
+		public void onReceive(Context context, Intent intent) {
+			Toast.makeText(getActivity(), intent.getExtras().getString(Netplay.EXTRA_MESSAGE), Toast.LENGTH_LONG).show();
+		}
+	};
+	
 	public void onCancel(DialogInterface dialog) {
 		super.onCancel(dialog);
 		Netplay.getAppInstance(getActivity().getApplicationContext()).disconnect();
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/ConnectionDependendDialogFragment.java	Mon Aug 20 20:16:37 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/ConnectionDependendDialogFragment.java	Mon Aug 20 20:19:35 2012 +0200
@@ -1,3 +1,22 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package org.hedgewars.hedgeroid;
 
 import org.hedgewars.hedgeroid.netplay.Netplay;
@@ -11,6 +30,11 @@
 import android.support.v4.app.DialogFragment;
 import android.support.v4.content.LocalBroadcastManager;
 
+/**
+ * Helper class for DialogFragments that are supposed to be dismissed when the
+ * network connection is lost. This is used for some dialog fragments that
+ * appear during connecting (e.g. username input)
+ */
 public class ConnectionDependendDialogFragment extends DialogFragment {
 	@Override
 	public void onStart() {
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/EngineProtocol/PascalExports.java	Mon Aug 20 20:16:37 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/EngineProtocol/PascalExports.java	Mon Aug 20 20:19:35 2012 +0200
@@ -19,6 +19,7 @@
 package org.hedgewars.hedgeroid.EngineProtocol;
 
 public class PascalExports {
+	public static Object engineMutex = new Object();
 
 	static{
 		System.loadLibrary("SDL");
@@ -32,8 +33,12 @@
 	}
 	
 	public static native int HWgetMaxNumberOfTeams();
-    public static native int HWterminate(boolean b);
-    public static native int HWGenLandPreview(int port);
+    private static native void HWGenLandPreview(int port);
+
+    public static void synchronizedGenLandPreview(int port) {
+    	synchronized(engineMutex) {
+    		HWGenLandPreview(port);
+    	}
+    }
     
-    public static Object engineMutex = new Object();
 }
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/GameConnection.java	Mon Aug 20 20:16:37 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/GameConnection.java	Mon Aug 20 20:19:35 2012 +0200
@@ -1,5 +1,26 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package org.hedgewars.hedgeroid;
 
+import java.net.ConnectException;
+
 import org.hedgewars.hedgeroid.Datastructures.GameConfig;
 import org.hedgewars.hedgeroid.frontlib.Flib;
 import org.hedgewars.hedgeroid.frontlib.Frontlib;
@@ -23,106 +44,95 @@
 import com.sun.jna.Memory;
 import com.sun.jna.Pointer;
 
+/**
+ * This class handles both talking to the engine (IPC) for running a game, and
+ * coordinating with the netconn if it is a netgame, using the frontlib for the
+ * actual IPC networking communication.
+ * 
+ * After creating the GameConnection object, it will communicate with the engine
+ * on its own thread. It shuts itself down as soon as the connection to the engine
+ * is lost.
+ */
 public final class GameConnection {
 	private static final Handler mainHandler = new Handler(Looper.getMainLooper());
 	
+	public final int port;
 	private final HandlerThread thread;
 	private final Handler handler;
-	private final TickHandler tickHandler;
+	private TickHandler tickHandler;
 	private final Netplay netplay; // ==null if not a netgame
 	private GameconnPtr conn;
-
-	/**
-	 * The actual connection has to be set up on a separate thread because networking
-	 * is not allowed on the UI thread, so the port can't be queried immediately after
-	 * creating the GameConnection object. Instead, one of these interface methods is
-	 * called once we know which port we are listening on (or once we fail to set this up).
-	 * Methods will be called on the UI thread.
-	 */
-	public static interface Listener {
-		/**
-		 * We are listening for the engine at $port, go start the engine.
-		 */
-		void gameConnectionReady(int port);
-		
-		/**
-		 * The connection has stopped, either because the game has ended or was interrupted,
-		 * or maybe we failed to create the connection at all (in that case gameConnectionReady wasn't called).
-		 */
-		void gameConnectionDisconnected(int reason);
+	
+	private GameConnection(GameconnPtr conn, Netplay netplay) {
+		this.conn = conn;
+		this.port = Flib.INSTANCE.flib_gameconn_getport(conn);
+		this.netplay = netplay;
+		this.thread = new HandlerThread("IPCThread");
+		thread.start();
+		this.handler = new Handler(thread.getLooper());
 	}
 	
-	private GameConnection(Netplay netplay) {
-		this.netplay = netplay;
-		thread = new HandlerThread("IPCThread");
-		thread.start();
-		handler = new Handler(thread.getLooper());
-		tickHandler = new TickHandler(thread.getLooper(), 50, new Runnable() {
-			public void run() {
-				if(conn != null) {
-					Flib.INSTANCE.flib_gameconn_tick(conn);
+	private void setupConnection() {
+		tickHandler = new TickHandler(thread.getLooper(), 50, tickCb);
+		tickHandler.start();
+		
+		if(netplay != null) {
+			mainHandler.post(new Runnable() {
+				public void run() { 
+					netplay.registerGameMessageListener(gameMessageListener);
 				}
-			}
-		});
-		tickHandler.start();
+			});
+			Flib.INSTANCE.flib_gameconn_onChat(conn, chatCb, null);
+			Flib.INSTANCE.flib_gameconn_onEngineMessage(conn, engineMessageCb, null);
+		}
+		Flib.INSTANCE.flib_gameconn_onConnect(conn, connectCb, null);
+		Flib.INSTANCE.flib_gameconn_onDisconnect(conn, disconnectCb, null);
+		Flib.INSTANCE.flib_gameconn_onErrorMessage(conn, errorMessageCb, null);
 	}
 	
-	public static GameConnection forNetgame(final GameConfig config, Netplay netplay, final Listener listener) {
-		final GameConnection result = new GameConnection(netplay);
+	/**
+	 * Start a new IPC server to communicate with the engine.
+	 * Performs networking operations, don't run on the UI thread.
+	 * @throws ConnectException if we can't set up the IPC server
+	 */
+	public static GameConnection forNetgame(final GameConfig config, Netplay netplay) throws ConnectException {
 		final String playerName = netplay.getPlayerName();
-		result.handler.post(new Runnable() {
-			public void run() {
-				GameconnPtr conn = Flib.INSTANCE.flib_gameconn_create(playerName, GameSetupPtr.createJavaOwned(config), true);
-				result.setupConnection(conn, true, listener);
-			}
-		});
+		GameconnPtr conn = Flib.INSTANCE.flib_gameconn_create(playerName, GameSetupPtr.createJavaOwned(config), true);
+		if(conn == null) {
+			throw new ConnectException();
+		}
+		GameConnection result = new GameConnection(conn, netplay);
+		result.setupConnection();
 		return result;
 	}
 	
-	public static GameConnection forLocalGame(final GameConfig config, final Listener listener) {
-		final GameConnection result = new GameConnection(null);
-		result.handler.post(new Runnable() {
-			public void run() {
-				GameconnPtr conn = Flib.INSTANCE.flib_gameconn_create("Player", GameSetupPtr.createJavaOwned(config), false);
-				result.setupConnection(conn, false, listener);
-			}
-		});
+	/**
+	 * Start a new IPC server to communicate with the engine.
+	 * Performs networking operations, don't run on the UI thread.
+	 * @throws ConnectException if we can't set up the IPC server
+	 */
+	public static GameConnection forLocalGame(final GameConfig config) throws ConnectException {
+		GameconnPtr conn = Flib.INSTANCE.flib_gameconn_create("Player", GameSetupPtr.createJavaOwned(config), false);
+		if(conn == null) {
+			throw new ConnectException();
+		}
+		GameConnection result = new GameConnection(conn, null);
+		result.setupConnection();
 		return result;
 	}
 	
-	// runs on the IPCThread
-	private void setupConnection(GameconnPtr conn, final boolean netgame, final Listener listener) {
-		if(conn == null) {
-			mainHandler.post(new Runnable() {
-				public void run() { listener.gameConnectionDisconnected(Frontlib.GAME_END_ERROR); }
-			});
-			shutdown();
-		} else {
-			this.conn = conn;
-			final int port = Flib.INSTANCE.flib_gameconn_getport(conn);
-			mainHandler.post(new Runnable() {
-				public void run() { 
-					listener.gameConnectionReady(port);
-					if(netgame) {
-						netplay.registerGameMessageListener(gameMessageListener);
-					}
-				}
-			});
-			Flib.INSTANCE.flib_gameconn_onConnect(conn, connectCb, null);
-			Flib.INSTANCE.flib_gameconn_onDisconnect(conn, disconnectCb, null);
-			Flib.INSTANCE.flib_gameconn_onErrorMessage(conn, errorMessageCb, null);
-			if(netgame) {
-				Flib.INSTANCE.flib_gameconn_onChat(conn, chatCb, null);
-				Flib.INSTANCE.flib_gameconn_onEngineMessage(conn, engineMessageCb, null);
-			}
+	private final Runnable tickCb = new Runnable() {
+		public void run() {
+			Flib.INSTANCE.flib_gameconn_tick(conn);
 		}
-	}
+	};
 	
 	// runs on the IPCThread
 	private void shutdown() {
 		tickHandler.stop();
 		thread.quit();
 		Flib.INSTANCE.flib_gameconn_destroy(conn);
+		conn = null;
 		if(netplay != null) {
 			mainHandler.post(new Runnable() {
 				public void run() {
@@ -179,7 +189,7 @@
 		public void onNetDisconnected() {
 			handler.post(new Runnable() {
 				public void run() {
-					shutdown();
+					Flib.INSTANCE.flib_gameconn_send_quit(conn);
 				}
 			});
 		}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/LobbyActivity.java	Mon Aug 20 20:16:37 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/LobbyActivity.java	Mon Aug 20 20:19:35 2012 +0200
@@ -1,27 +1,46 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package org.hedgewars.hedgeroid;
 
-import org.hedgewars.hedgeroid.R;
 import org.hedgewars.hedgeroid.NetplayStateFragment.NetplayStateListener;
 import org.hedgewars.hedgeroid.netplay.Netplay;
 import org.hedgewars.hedgeroid.netplay.Netplay.State;
 import org.hedgewars.hedgeroid.util.TextInputDialog;
 import org.hedgewars.hedgeroid.util.TextInputDialog.TextInputDialogListener;
+import org.hedgewars.hedgeroid.util.UiUtils;
 
-import android.content.Context;
 import android.content.Intent;
-import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.support.v4.app.FragmentActivity;
 import android.support.v4.app.FragmentTransaction;
-import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.MenuItem;
-import android.view.View;
-import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.TabHost;
-import android.widget.TextView;
 
+/**
+ * Activity for the server lobby of a hedgewars server. Allows you to chat, join
+ * and create rooms and interact with a list of players.
+ * 
+ * Most of the functionality is handled by various fragments.
+ */
 public class LobbyActivity extends FragmentActivity implements TextInputDialogListener, NetplayStateListener {
 	private static final int DIALOG_CREATE_ROOM = 0;
 	
@@ -42,14 +61,15 @@
         
         netplay = Netplay.getAppInstance(getApplicationContext());
         
+        // Set up a tabbed UI for medium and small screens
         tabHost = (TabHost)findViewById(android.R.id.tabhost);
         if(tabHost != null) {
 	        tabHost.setup();
 	        tabHost.getTabWidget().setOrientation(LinearLayout.VERTICAL);
 
-	        tabHost.addTab(tabHost.newTabSpec("rooms").setIndicator(createIndicatorView(tabHost, R.string.lobby_tab_rooms, getResources().getDrawable(R.drawable.roomlist_ingame))).setContent(R.id.roomListFragment));
-	        tabHost.addTab(tabHost.newTabSpec("chat").setIndicator(createIndicatorView(tabHost, R.string.lobby_tab_chat, getResources().getDrawable(R.drawable.edit))).setContent(R.id.chatFragment));
-	        tabHost.addTab(tabHost.newTabSpec("players").setIndicator(createIndicatorView(tabHost, R.string.lobby_tab_players, getResources().getDrawable(R.drawable.human))).setContent(R.id.playerListFragment));
+	        tabHost.addTab(tabHost.newTabSpec("rooms").setIndicator(UiUtils.createTabIndicator(tabHost, R.string.lobby_tab_rooms, R.drawable.roomlist_ingame)).setContent(R.id.roomListFragment));
+	        tabHost.addTab(tabHost.newTabSpec("chat").setIndicator(UiUtils.createTabIndicator(tabHost, R.string.lobby_tab_chat, R.drawable.edit)).setContent(R.id.chatFragment));
+	        tabHost.addTab(tabHost.newTabSpec("players").setIndicator(UiUtils.createTabIndicator(tabHost, R.string.lobby_tab_players, R.drawable.human)).setContent(R.id.playerListFragment));
 	
 	        if (icicle != null) {
 	            tabHost.setCurrentTabByTag(icicle.getString("currentTab"));
@@ -57,24 +77,6 @@
         }
     }
     
-    private View createIndicatorView(TabHost tabHost, int label, Drawable icon) {
-        LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-
-        View tabIndicator = inflater.inflate(R.layout.tab_indicator,
-                tabHost.getTabWidget(), // tab widget is the parent
-                false); // no inflate params
-
-        final TextView tv = (TextView) tabIndicator.findViewById(R.id.title);
-        tv.setText(label);
-        
-        if(icon != null) {
-	        final ImageView iconView = (ImageView) tabIndicator.findViewById(R.id.icon);
-	        iconView.setImageDrawable(icon);
-        }
-        
-        return tabIndicator;
-    }
-    
 	@Override
 	public boolean onCreateOptionsMenu(Menu menu) {
 		super.onCreateOptionsMenu(menu);
@@ -99,7 +101,6 @@
 	
 	@Override
 	public void onBackPressed() {
-		super.onBackPressed();
 		netplay.disconnect();
 	}
 	
@@ -127,8 +128,7 @@
     		finish();
     		break;
     	case ROOM:
-    	case INGAME:
-    		startActivity(new Intent(getApplicationContext(), RoomActivity.class));
+    		startActivity(new Intent(getApplicationContext(), NetRoomActivity.class));
     		break;
     	case LOBBY:
     		// Do nothing
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/LobbyPlayerlistAdapter.java	Mon Aug 20 20:16:37 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/LobbyPlayerlistAdapter.java	Mon Aug 20 20:19:35 2012 +0200
@@ -1,3 +1,22 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package org.hedgewars.hedgeroid;
 
 import java.util.Comparator;
@@ -11,6 +30,9 @@
 import android.view.ViewGroup;
 import android.widget.TextView;
 
+/**
+ * Simple adapter for displaying the list of players in the lobby.
+ */
 public class LobbyPlayerlistAdapter extends ObservableTreeMapAdapter<String, Player> {
 	@Override
 	protected Comparator<Player> getEntryOrder() {
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/LobbyPlayerlistFragment.java	Mon Aug 20 20:16:37 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/LobbyPlayerlistFragment.java	Mon Aug 20 20:19:35 2012 +0200
@@ -1,3 +1,22 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package org.hedgewars.hedgeroid;
 
 import org.hedgewars.hedgeroid.R;
@@ -15,6 +34,10 @@
 import android.view.ViewGroup;
 import android.widget.AdapterView.AdapterContextMenuInfo;
 
+/**
+ * Shows the list of players in the lobby and allows some interactions with them
+ * over the context menu.
+ */
 public class LobbyPlayerlistFragment extends ListFragment {
 	private Netplay netplay;
 	private LobbyPlayerlistAdapter adapter;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/LocalRoomActivity.java	Mon Aug 20 20:19:35 2012 +0200
@@ -0,0 +1,121 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid;
+
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.hedgewars.hedgeroid.Datastructures.GameConfig;
+import org.hedgewars.hedgeroid.Datastructures.Team;
+import org.hedgewars.hedgeroid.Datastructures.TeamInGame;
+import org.hedgewars.hedgeroid.netplay.Netplay;
+import org.hedgewars.hedgeroid.util.UiUtils;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.TabHost;
+import android.widget.Toast;
+
+/**
+ * This activity is used to set up a local game.
+ */
+public class LocalRoomActivity extends FragmentActivity implements RoomStateManager.Provider, TeamAddDialog.Listener {
+	private TabHost tabHost;
+	private RoomStateManager stateManager;
+	private Button startButton;
+	
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        // TODO find a better central location / way to set up the default scheme and weaponset
+        Netplay netplay = Netplay.getAppInstance(getApplicationContext());
+        stateManager = new LocalRoomStateManager(netplay.defaultScheme, netplay.defaultWeaponset);
+        
+        setContentView(R.layout.activity_localroom);
+        startButton = (Button)findViewById(R.id.startGame);
+        
+        startButton.setOnClickListener(startButtonClickListener);
+        
+        // Set up a tabbed UI for medium and small screens
+        tabHost = (TabHost)findViewById(android.R.id.tabhost);
+        if(tabHost != null) {
+	        tabHost.setup();
+	        tabHost.getTabWidget().setOrientation(LinearLayout.VERTICAL);
+
+	        tabHost.addTab(tabHost.newTabSpec("map").setIndicator(UiUtils.createTabIndicator(tabHost, R.string.room_tab_map, 0)).setContent(R.id.mapFragment));
+	        tabHost.addTab(tabHost.newTabSpec("settings").setIndicator(UiUtils.createTabIndicator(tabHost, R.string.room_tab_settings, 0)).setContent(R.id.settingsFragment));
+	        tabHost.addTab(tabHost.newTabSpec("teams").setIndicator(UiUtils.createTabIndicator(tabHost, R.string.room_tab_teams, 0)).setContent(R.id.teamlistContainer));
+	        
+	        if (icicle != null) {
+	            tabHost.setCurrentTabByTag(icicle.getString("currentTab"));
+	        }
+        }
+    }
+    
+    @Override
+    protected void onSaveInstanceState(Bundle icicle) {
+        super.onSaveInstanceState(icicle);
+        if(tabHost != null) {
+        	icicle.putString("currentTab", tabHost.getCurrentTabTag());
+        }
+    }
+    
+	public void onTeamAddDialogSubmitted(Team newTeam) {
+		stateManager.requestAddTeam(newTeam, TeamInGame.getUnusedOrRandomColorIndex(stateManager.getTeams().values()));
+	}
+	
+	public RoomStateManager getRoomStateManager() {
+		return stateManager;
+	}
+
+	private final OnClickListener startButtonClickListener = new OnClickListener() {
+		public void onClick(View v) {
+			Map<String, TeamInGame> teams = stateManager.getTeams();
+			Set<Integer> clanColors = new TreeSet<Integer>();
+			for(TeamInGame t : teams.values()) {
+				clanColors.add(t.ingameAttribs.colorIndex);
+			}
+			if(clanColors.size()<2) {
+				if(tabHost != null) {
+					tabHost.setCurrentTabByTag("teams");
+				}
+				int errortext = teams.size()<2 ? R.string.not_enough_teams : R.string.not_enough_clans;
+				Toast.makeText(getApplicationContext(), errortext, Toast.LENGTH_SHORT).show();
+				return;
+			}
+			
+			SDLActivity.startNetgame = false;
+			SDLActivity.startConfig = new GameConfig(
+					stateManager.getGameStyle(),
+					stateManager.getScheme(),
+					stateManager.getMapRecipe(),
+					new ArrayList<TeamInGame>(stateManager.getTeams().values()),
+					stateManager.getWeaponset());
+			startActivity(new Intent(LocalRoomActivity.this, SDLActivity.class));
+		}
+	};
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/LocalRoomStateManager.java	Mon Aug 20 20:19:35 2012 +0200
@@ -0,0 +1,95 @@
+package org.hedgewars.hedgeroid;
+
+import org.hedgewars.hedgeroid.Datastructures.GameConfig;
+import org.hedgewars.hedgeroid.Datastructures.MapRecipe;
+import org.hedgewars.hedgeroid.Datastructures.Scheme;
+import org.hedgewars.hedgeroid.Datastructures.Team;
+import org.hedgewars.hedgeroid.Datastructures.TeamInGame;
+import org.hedgewars.hedgeroid.Datastructures.TeamIngameAttributes;
+import org.hedgewars.hedgeroid.Datastructures.Weaponset;
+
+import android.util.Log;
+
+/**
+ * This RoomStateManager is responsible for keeping/changing the roomstate in local play.
+ * That is very straightforward, just react to every request by immediately changing the
+ * state.
+ */
+public class LocalRoomStateManager extends BasicRoomState {
+	private static final String TAG = LocalRoomStateManager.class.getSimpleName(); 
+
+	public LocalRoomStateManager(Scheme defaultScheme, Weaponset defaultWeaponset) {
+		setChief(true);
+		setGameStyle(GameConfig.DEFAULT_STYLE);
+		setMapRecipe(MapRecipe.makeRandomMap(0, MapRecipe.makeRandomSeed(), GameConfig.DEFAULT_THEME));
+		setScheme(defaultScheme);
+		setWeaponset(defaultWeaponset);
+	}
+	
+	public void changeMapRecipe(MapRecipe map) {
+		setMapRecipe(map);
+	}
+
+	public void changeMapTheme(String theme) {
+		setMapRecipe(getMapRecipe().withTheme(theme));
+	}
+
+	public void changeMapNameAndGenerator(String mapName) {
+		int newGenerator = MapRecipe.generatorForMapname(mapName);
+		setMapRecipe(getMapRecipe().withName(mapName).withMapgen(newGenerator));
+	}
+
+	public void changeMapTemplate(int template) {
+		setMapRecipe(getMapRecipe().withTemplateFilter(template));
+	}
+
+	public void changeMazeSize(int mazeSize) {
+		setMapRecipe(getMapRecipe().withMazeSize(mazeSize));
+	}
+
+	public void changeMapSeed(String seed) {
+		setMapRecipe(getMapRecipe().withSeed(seed));
+	}
+
+	public void changeMapDrawdata(byte[] drawdata) {
+		setMapRecipe(getMapRecipe().withDrawData(drawdata));
+	}
+
+	public void changeScheme(Scheme scheme) {
+		setScheme(scheme);
+	}
+
+	public void changeGameStyle(String style) {
+		setGameStyle(style);
+	}
+
+	public void changeWeaponset(Weaponset weaponset) {
+		setWeaponset(weaponset);
+	}
+
+	public void requestAddTeam(Team team, int colorIndex) {
+		putTeam(new TeamInGame(team, new TeamIngameAttributes("Player", colorIndex, TeamIngameAttributes.DEFAULT_HOG_COUNT, false)));
+	}
+
+	public void requestRemoveTeam(String teamname) {
+		removeTeam(teamname);
+	}
+
+	public void changeTeamColorIndex(String teamname, int colorIndex) {
+		TeamInGame oldTeam = getTeams().get(teamname);
+		if(oldTeam != null) {
+			putTeam(oldTeam.withAttribs(oldTeam.ingameAttribs.withColorIndex(colorIndex)));
+		} else {
+			Log.e(TAG, "Requested color change for unknown team "+ teamname);
+		}
+	}
+
+	public void changeTeamHogCount(String teamname, int hogcount) {
+		TeamInGame oldTeam = getTeams().get(teamname);
+		if(oldTeam != null) {
+			putTeam(oldTeam.withAttribs(oldTeam.ingameAttribs.withHogCount(hogcount)));
+		} else {
+			Log.e(TAG, "Requested hog count change for unknown team "+ teamname);
+		}
+	}
+}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/MainActivity.java	Mon Aug 20 20:16:37 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/MainActivity.java	Mon Aug 20 20:19:35 2012 +0200
@@ -24,7 +24,6 @@
 
 import org.hedgewars.hedgeroid.Downloader.DownloadAssets;
 import org.hedgewars.hedgeroid.Downloader.DownloadListActivity;
-import org.hedgewars.hedgeroid.frontlib.Flib;
 import org.hedgewars.hedgeroid.netplay.Netplay;
 import org.hedgewars.hedgeroid.netplay.Netplay.State;
 import org.hedgewars.hedgeroid.util.FileUtils;
@@ -56,7 +55,7 @@
 
 	public void onCreate(Bundle sis){
 		super.onCreate(sis);
-		setContentView(R.layout.main);
+		setContentView(R.layout.activity_main);
 
 		broadcastManager = LocalBroadcastManager.getInstance(getApplicationContext());
 		Button startLocalGame = (Button)findViewById(R.id.startGame);
@@ -120,13 +119,16 @@
 	public boolean onOptionsItemSelected(MenuItem item) {
 		switch(item.getItemId()) {
 		case R.id.download:
-			startActivityForResult(new Intent(getApplicationContext(), DownloadListActivity.class), 0);
+			startActivityForResult(new Intent(this, DownloadListActivity.class), 0);
 			return true;
 		case R.id.preferences:
 			Toast.makeText(this, R.string.not_implemented_yet, Toast.LENGTH_SHORT).show();
 			return true;
 		case R.id.edit_weaponsets:
-			startActivity(new Intent(getApplicationContext(), WeaponsetListActivity.class));
+			startActivity(new Intent(this, WeaponsetListActivity.class));
+			return true;
+		case R.id.edit_teams:
+			startActivity(new Intent(this, TeamListActivity.class));
 			return true;
 		default:
 			return super.onOptionsItemSelected(item);
@@ -164,7 +166,7 @@
 
 	private final OnClickListener startGameListener = new OnClickListener(){
 		public void onClick(View v){
-			startActivity(new Intent(getApplicationContext(), StartGameActivity.class));
+			startActivity(new Intent(getApplicationContext(), LocalRoomActivity.class));
 		}
 	};
 	
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/MapFragment.java	Mon Aug 20 20:16:37 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/MapFragment.java	Mon Aug 20 20:19:35 2012 +0200
@@ -10,8 +10,6 @@
 import org.hedgewars.hedgeroid.Datastructures.FrontendDataUtils;
 import org.hedgewars.hedgeroid.Datastructures.MapFile;
 import org.hedgewars.hedgeroid.Datastructures.MapRecipe;
-import org.hedgewars.hedgeroid.Datastructures.Scheme;
-import org.hedgewars.hedgeroid.Datastructures.Weaponset;
 import org.hedgewars.hedgeroid.frontlib.Frontlib;
 
 import android.content.Context;
@@ -33,7 +31,7 @@
 import android.widget.TableRow;
 import android.widget.Toast;
 
-public class MapFragment extends Fragment implements RoomStateManager.Observer {
+public class MapFragment extends Fragment {
 	private Spinner mapTypeSpinner, mapNameSpinner, templateSpinner, mazeSizeSpinner;
 	private TableRow nameRow, templateRow, mazeSizeRow;
 	private ImageView mapPreview;
@@ -91,7 +89,7 @@
 		templateSpinner = prepareSpinner(v, R.id.spinTemplateFilter, Arrays.asList(getResources().getStringArray(R.array.map_templates)), mapTemplateSelectedListener);
 		mazeSizeSpinner = prepareSpinner(v, R.id.spinMazeSize, Arrays.asList(getResources().getStringArray(R.array.map_maze_sizes)), mazeSizeSelectedListener);
 
-		stateManager.registerObserver(this);
+		stateManager.addListener(roomStateChangeListener);
 		currentMap = stateManager.getMapRecipe();
 		if(currentMap != null) {
 			updateDisplay(currentMap);
@@ -124,7 +122,7 @@
 	public void onDestroy() {
 		super.onDestroy();
 		mapPreviewHandler.stop();
-		stateManager.unregisterObserver(this);
+		stateManager.removeListener(roomStateChangeListener);
 	}
 	
 	private void setChiefState(boolean chiefState) {
@@ -207,27 +205,27 @@
 		}
 	};
 	
-	public void onChiefStatusChanged(boolean isChief) {
-		setChiefState(isChief);
-	}
-	
-	public void onMapChanged(MapRecipe recipe) {
-		if(currentMap==null
-				|| currentMap.mapgen != recipe.mapgen
-				|| currentMap.mazeSize != recipe.mazeSize
-				|| !currentMap.name.equals(recipe.name)
-				|| !currentMap.seed.equals(recipe.seed)
-				|| currentMap.templateFilter != recipe.templateFilter
-				|| !Arrays.equals(currentMap.getDrawData(), recipe.getDrawData())) {
-			mapPreviewHandler.activity();
-		}
-		updateDisplay(recipe);
-		currentMap = recipe;
-	}
-	
-	public void onGameStyleChanged(String gameStyle) { }
-	public void onSchemeChanged(Scheme scheme) { }
-	public void onWeaponsetChanged(Weaponset weaponset) { }
+	private final RoomStateManager.Listener roomStateChangeListener = new RoomStateManager.ListenerAdapter() {
+		@Override
+		public void onChiefStatusChanged(boolean isChief) {
+			setChiefState(isChief);
+		};
+		
+		@Override
+		public void onMapChanged(MapRecipe recipe) {
+			if(currentMap==null
+					|| currentMap.mapgen != recipe.mapgen
+					|| currentMap.mazeSize != recipe.mazeSize
+					|| !currentMap.name.equals(recipe.name)
+					|| !currentMap.seed.equals(recipe.seed)
+					|| currentMap.templateFilter != recipe.templateFilter
+					|| !Arrays.equals(currentMap.getDrawData(), recipe.getDrawData())) {
+				mapPreviewHandler.activity();
+			}
+			updateDisplay(recipe);
+			currentMap = recipe;
+		};
+	};
 	
 	private MapPreviewGenerator.Listener mapPreviewListener = new MapPreviewGenerator.Listener() {
 		public void onMapPreviewResult(Drawable preview) {
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/MapPreviewGenerator.java	Mon Aug 20 20:16:37 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/MapPreviewGenerator.java	Mon Aug 20 20:19:35 2012 +0200
@@ -89,7 +89,11 @@
 					} catch (InterruptedException e) {
 						// ignore
 					}
-				} while(!resultAvailable && System.nanoTime()-startTime < 15000000000l); // 15 seconds timeout
+					if(System.nanoTime()-startTime > 15000000000l) {
+						Log.w(TAG, "Error generating map preview: timeout");
+						resultAvailable = true;
+					}
+				} while(!resultAvailable); // 15 seconds timeout
 			} finally {
 				Flib.INSTANCE.flib_mapconn_destroy(conn);
 				postToListener(result);
@@ -117,9 +121,7 @@
 		new Thread(new Runnable() {
 			public void run() {
 				Log.d(TAG, "Starting engine "+port);
-				synchronized(PascalExports.engineMutex) {
-					PascalExports.HWGenLandPreview(port);
-				}
+				PascalExports.synchronizedGenLandPreview(port);
 				Log.d(TAG, "Engine finished");
 			}
 		}).start();
@@ -139,7 +141,6 @@
 	 */
 	private final MapimageCallback successCb = new MapimageCallback() {
 		public void callback(Pointer context, Pointer buffer, int hedgehogCount) {
-			Log.d(TAG, "Running success handler");
 			byte[] mapdata = buffer.getByteArray(0, Frontlib.MAPIMAGE_BYTES);
 			
 			int leftmostPixel = Frontlib.MAPIMAGE_WIDTH;
@@ -192,7 +193,7 @@
 	
 	private final StrCallback failureCb = new StrCallback() {
 		public void callback(Pointer context, String reason) {
-			Log.e(TAG, "Error generating map preview: "+reason);
+			Log.w(TAG, "Error generating map preview: "+reason);
 			result = null;
 			resultAvailable = true;
 		}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/NetRoomActivity.java	Mon Aug 20 20:19:35 2012 +0200
@@ -0,0 +1,129 @@
+package org.hedgewars.hedgeroid;
+
+import org.hedgewars.hedgeroid.R;
+import org.hedgewars.hedgeroid.Datastructures.GameConfig;
+import org.hedgewars.hedgeroid.Datastructures.Team;
+import org.hedgewars.hedgeroid.Datastructures.TeamInGame;
+import org.hedgewars.hedgeroid.NetplayStateFragment.NetplayStateListener;
+import org.hedgewars.hedgeroid.netplay.Netplay;
+import org.hedgewars.hedgeroid.netplay.RunGameListener;
+import org.hedgewars.hedgeroid.netplay.Netplay.State;
+import org.hedgewars.hedgeroid.util.UiUtils;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
+import android.support.v4.app.FragmentTransaction;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.TabHost;
+
+public class NetRoomActivity extends FragmentActivity implements NetplayStateListener, TeamAddDialog.Listener, RoomStateManager.Provider, RunGameListener {
+	private TabHost tabHost;
+	private Netplay netplay;
+	private RoomStateManager stateManager;
+	private Button startButton;
+	
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        netplay = Netplay.getAppInstance(getApplicationContext());
+        netplay.registerRunGameListener(this);
+        stateManager = netplay.getRoomStateManager();
+        stateManager.addListener(roomStateChangeListener);
+        
+        setContentView(R.layout.activity_netroom);
+        startButton = (Button)findViewById(R.id.startGame);
+        
+        ChatFragment chatFragment = (ChatFragment)getSupportFragmentManager().findFragmentById(R.id.chatFragment);
+        chatFragment.setInRoom(true);
+        
+        FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
+        trans.add(new NetplayStateFragment(), "netplayFragment");
+        trans.commit();
+        
+        startButton.setVisibility(netplay.isChief() ? View.VISIBLE : View.GONE);
+        startButton.setOnClickListener(startButtonClickListener);
+        
+        // Set up a tabbed UI for medium and small screens
+        tabHost = (TabHost)findViewById(android.R.id.tabhost);
+        if(tabHost != null) {
+	        tabHost.setup();
+	        tabHost.getTabWidget().setOrientation(LinearLayout.VERTICAL);
+
+	        tabHost.addTab(tabHost.newTabSpec("map").setIndicator(UiUtils.createTabIndicator(tabHost, R.string.room_tab_map, 0)).setContent(R.id.mapFragment));
+	        tabHost.addTab(tabHost.newTabSpec("settings").setIndicator(UiUtils.createTabIndicator(tabHost, R.string.room_tab_settings, 0)).setContent(R.id.settingsFragment));
+	        tabHost.addTab(tabHost.newTabSpec("teams").setIndicator(UiUtils.createTabIndicator(tabHost, R.string.room_tab_teams, 0)).setContent(R.id.teamlistFragment));
+	        tabHost.addTab(tabHost.newTabSpec("chat").setIndicator(UiUtils.createTabIndicator(tabHost, R.string.room_tab_chat, 0)).setContent(R.id.chatFragment));
+	        tabHost.addTab(tabHost.newTabSpec("players").setIndicator(UiUtils.createTabIndicator(tabHost, R.string.room_tab_players, 0)).setContent(R.id.playerListContainer));
+	        
+	        if (icicle != null) {
+	            tabHost.setCurrentTabByTag(icicle.getString("currentTab"));
+	        }
+        }
+    }
+
+    @Override
+    protected void onDestroy() {
+    	super.onDestroy();
+    	stateManager.removeListener(roomStateChangeListener);
+    	netplay.unregisterRunGameListener(this);
+    }
+    
+	@Override
+	public void onBackPressed() {
+		netplay.sendLeaveRoom(null);
+	}
+    
+    @Override
+    protected void onSaveInstanceState(Bundle icicle) {
+        super.onSaveInstanceState(icicle);
+        if(tabHost != null) {
+        	icicle.putString("currentTab", tabHost.getCurrentTabTag());
+        }
+    }
+    
+    public void onNetplayStateChanged(State newState) {
+    	switch(newState) {
+    	case NOT_CONNECTED:
+    	case CONNECTING:
+    	case LOBBY:
+    		finish();
+    		break;
+    	case ROOM:
+    		// Do nothing
+    		break;
+		default:
+			throw new IllegalStateException("Unknown connection state: "+newState);
+    	}
+    }
+    
+	public void onTeamAddDialogSubmitted(Team newTeam) {
+		stateManager.requestAddTeam(newTeam, TeamInGame.getUnusedOrRandomColorIndex(stateManager.getTeams().values()));
+	}
+	
+	public RoomStateManager getRoomStateManager() {
+		return stateManager;
+	}
+
+	private final OnClickListener startButtonClickListener = new OnClickListener() {
+		public void onClick(View v) {
+			netplay.sendStartGame();
+		}
+	};
+	
+	private final RoomStateManager.Listener roomStateChangeListener = new RoomStateManager.ListenerAdapter() {
+		@Override
+		public void onChiefStatusChanged(boolean isChief) {
+			startButton.setVisibility(isChief ? View.VISIBLE : View.GONE);
+		}
+	};
+	
+	public void runGame(GameConfig config) {
+		SDLActivity.startConfig = config;
+		SDLActivity.startNetgame = true;
+		startActivity(new Intent(this, SDLActivity.class));
+	}
+}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/RoomActivity.java	Mon Aug 20 20:16:37 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,86 +0,0 @@
-package org.hedgewars.hedgeroid;
-
-import org.hedgewars.hedgeroid.R;
-import org.hedgewars.hedgeroid.Datastructures.Team;
-import org.hedgewars.hedgeroid.Datastructures.TeamInGame;
-import org.hedgewars.hedgeroid.NetplayStateFragment.NetplayStateListener;
-import org.hedgewars.hedgeroid.netplay.Netplay;
-import org.hedgewars.hedgeroid.netplay.Netplay.State;
-
-import android.os.Bundle;
-import android.support.v4.app.FragmentActivity;
-import android.support.v4.app.FragmentTransaction;
-import android.widget.TabHost;
-import android.widget.Toast;
-
-public class RoomActivity extends FragmentActivity implements NetplayStateListener, TeamAddDialog.Listener, RoomStateManager.Provider {
-	private TabHost tabHost;
-	private Netplay netplay;
-	
-    @Override
-    protected void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-        netplay = Netplay.getAppInstance(getApplicationContext());
-        
-        setContentView(R.layout.activity_netroom);
-        ChatFragment chatFragment = (ChatFragment)getSupportFragmentManager().findFragmentById(R.id.chatFragment);
-        chatFragment.setInRoom(true);
-        
-        FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
-        trans.add(new NetplayStateFragment(), "netplayFragment");
-        trans.commit();
-        
-        /*tabHost = (TabHost)findViewById(android.R.id.tabhost);
-        if(tabHost != null) {
-	        tabHost.setup();
-	        tabHost.getTabWidget().setOrientation(LinearLayout.VERTICAL);
-
-	        //tabHost.addTab(tabHost.newTabSpec("chat").setIndicator(createIndicatorView(tabHost, R.string.lobby_tab_chat, getResources().getDrawable(R.drawable.edit))).setContent(R.id.chatFragment));
-	        //tabHost.addTab(tabHost.newTabSpec("players").setIndicator(createIndicatorView(tabHost, R.string.lobby_tab_players, getResources().getDrawable(R.drawable.human))).setContent(R.id.playerListFragment));
-	
-	        if (icicle != null) {
-	            tabHost.setCurrentTabByTag(icicle.getString("currentTab"));
-	        }
-        }*/
-    }
-
-	@Override
-	public void onBackPressed() {
-		netplay.sendLeaveRoom(null);
-	}
-    
-    @Override
-    protected void onSaveInstanceState(Bundle icicle) {
-        super.onSaveInstanceState(icicle);
-        if(tabHost != null) {
-        	icicle.putString("currentTab", tabHost.getCurrentTabTag());
-        }
-    }
-    
-    public void onNetplayStateChanged(State newState) {
-    	switch(newState) {
-    	case NOT_CONNECTED:
-    	case CONNECTING:
-    	case LOBBY:
-    		finish();
-    		break;
-    	case ROOM:
-    		// Do nothing
-    		break;
-    	case INGAME:
-    		//startActivity(new Intent(getApplicationContext(), RoomActivity.class));
-    		Toast.makeText(getApplicationContext(), R.string.not_implemented_yet, Toast.LENGTH_SHORT).show();
-    		break;
-		default:
-			throw new IllegalStateException("Unknown connection state: "+newState);
-    	}
-    }
-    
-	public void onTeamAddDialogSubmitted(Team newTeam) {
-		netplay.sendAddTeam(newTeam, TeamInGame.getUnusedOrRandomColorIndex(netplay.roomTeamlist.getMap().values()));
-	}
-	
-	public RoomStateManager getRoomStateManager() {
-		return netplay.getRoomStateManager();
-	}
-}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/RoomPlayerlistFragment.java	Mon Aug 20 20:16:37 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/RoomPlayerlistFragment.java	Mon Aug 20 20:19:35 2012 +0200
@@ -1,13 +1,10 @@
 package org.hedgewars.hedgeroid;
 
 import org.hedgewars.hedgeroid.R;
-import org.hedgewars.hedgeroid.Datastructures.GameConfig;
 import org.hedgewars.hedgeroid.Datastructures.Player;
 import org.hedgewars.hedgeroid.Datastructures.PlayerInRoom;
 import org.hedgewars.hedgeroid.netplay.Netplay;
-import org.hedgewars.hedgeroid.netplay.RunGameListener;
 
-import android.content.Intent;
 import android.os.Bundle;
 import android.support.v4.app.ListFragment;
 import android.view.ContextMenu;
@@ -21,7 +18,7 @@
 import android.widget.AdapterView.AdapterContextMenuInfo;
 import android.widget.AdapterView.OnItemClickListener;
 
-public class RoomPlayerlistFragment extends ListFragment implements OnItemClickListener, RunGameListener {
+public class RoomPlayerlistFragment extends ListFragment implements OnItemClickListener {
 	private Netplay netplay;
 	private RoomPlayerlistAdapter adapter;
 	
@@ -29,7 +26,6 @@
 	public void onCreate(Bundle savedInstanceState) {
 		super.onCreate(savedInstanceState);
 		netplay = Netplay.getAppInstance(getActivity().getApplicationContext());
-		netplay.registerRunGameListener(this);
 		adapter = new RoomPlayerlistAdapter();
 		adapter.setSource(netplay.roomPlayerlist);
 		setListAdapter(adapter);
@@ -39,7 +35,6 @@
 	public void onDestroy() {
 		super.onDestroy();
 		adapter.invalidate();
-		netplay.unregisterRunGameListener(this);
 	}
 	
 	@Override
@@ -93,11 +88,4 @@
 			netplay.sendToggleReady();
 		}
 	}
-	
-	// TODO this is really the wrong place for this...
-	public void runGame(GameConfig config) {
-		SDLActivity.startConfig = config;
-		SDLActivity.startNetgame = true;
-		startActivity(new Intent(getActivity().getApplicationContext(), SDLActivity.class));
-	}
 }
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/RoomStateManager.java	Mon Aug 20 20:16:37 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/RoomStateManager.java	Mon Aug 20 20:19:35 2012 +0200
@@ -1,24 +1,29 @@
 package org.hedgewars.hedgeroid;
 
+import java.util.Map;
+
 import org.hedgewars.hedgeroid.Datastructures.MapRecipe;
 import org.hedgewars.hedgeroid.Datastructures.Scheme;
+import org.hedgewars.hedgeroid.Datastructures.Team;
+import org.hedgewars.hedgeroid.Datastructures.TeamInGame;
 import org.hedgewars.hedgeroid.Datastructures.Weaponset;
 
 /**
- * This interface is supposed to abstract the handling of room state for several fragments
- * that can display and manipulate it. The purpose of this is to allow using these fragments
- * both for setting up networked and local games, despite the fact that for local games
- * the settings can be changed immediately in memory, while they have to be sent out to the
- * server for networked games.
+ * This interface is supposed to abstract the handling of room state for several
+ * fragments that can display and manipulate it. The purpose of this is to allow
+ * using these fragments both for setting up networked and local games, despite
+ * the fact that for local games the settings can be changed immediately in
+ * memory, while they have to be sent out to the server for networked games.
  * 
- * If/when the state changes as result of calling one of the "changeX" functions, that will
- * also trigger the corresponding change listener method. There is no guarantee that calling
- * a changeX method will actually change the setting (e.g. if you're not room chief).
+ * If/when the state changes as result of calling one of the "changeX" or
+ * "requestX" functions, that will also trigger the corresponding change
+ * listener method. There is no guarantee that calling a changeX method will
+ * actually change the setting (e.g. if you're not room chief).
  * 
  * For local games, getChiefStatus is always true.
  * 
- * Implementations of this interface are probably not thread safe and should only be used on
- * the UI thread.
+ * Implementations of this interface are probably not thread safe and should
+ * only be used on the UI thread.
  */
 public interface RoomStateManager {
 	// Query current state
@@ -27,6 +32,7 @@
 	Scheme getScheme();
 	String getGameStyle();
 	Weaponset getWeaponset();
+	Map<String, TeamInGame> getTeams();
 	
 	// Manipulate state
 	void changeMapRecipe(MapRecipe map);
@@ -52,16 +58,31 @@
 	void changeGameStyle(String style);
 	void changeWeaponset(Weaponset weaponset);
 	
-	// Observe state
-	void registerObserver(Observer observer);
-	void unregisterObserver(Observer observer);
+	void requestAddTeam(Team team, int colorIndex);
+	void requestRemoveTeam(String teamname);
+	void changeTeamColorIndex(String teamname, int colorIndex);
+	void changeTeamHogCount(String teamname, int hogcount);
 	
-	public interface Observer {
+	// Observe changes
+	void addListener(Listener observer);
+	void removeListener(Listener observer);
+	
+	public interface Listener {
 		void onMapChanged(MapRecipe recipe);
 		void onChiefStatusChanged(boolean isChief);
 		void onSchemeChanged(Scheme scheme);
 		void onGameStyleChanged(String gameStyle);
 		void onWeaponsetChanged(Weaponset weaponset);
+		void onTeamsChanged(Map<String, TeamInGame> teams);
+	}
+	
+	public static class ListenerAdapter implements Listener {
+		public void onMapChanged(MapRecipe recipe) {}
+		public void onChiefStatusChanged(boolean isChief) {}
+		public void onSchemeChanged(Scheme scheme) {}
+		public void onGameStyleChanged(String gameStyle) {}
+		public void onWeaponsetChanged(Weaponset weaponset) {}
+		public void onTeamsChanged(Map<String, TeamInGame> teams) {}
 	}
 	
 	public interface Provider {
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/RoomlistFragment.java	Mon Aug 20 20:16:37 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/RoomlistFragment.java	Mon Aug 20 20:19:35 2012 +0200
@@ -39,7 +39,7 @@
 	@Override
 	public View onCreateView(LayoutInflater inflater, ViewGroup container,
 			Bundle savedInstanceState) {
-		return inflater.inflate(R.layout.lobby_rooms_fragment, container, false);
+		return inflater.inflate(R.layout.fragment_roomlist, container, false);
 	}
 	
 	@Override
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/SDLActivity.java	Mon Aug 20 20:16:37 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/SDLActivity.java	Mon Aug 20 20:19:35 2012 +0200
@@ -1,7 +1,10 @@
 package org.hedgewars.hedgeroid;
-
+/*
+ * Copyright (c) 2004-2012 Andrey Korotaev <unC0Rr@gmail.com>
+ */
+import java.io.IOException;
 import java.io.UnsupportedEncodingException;
-import java.util.concurrent.atomic.AtomicBoolean;
+import java.net.ConnectException;
 
 import javax.microedition.khronos.egl.EGL10;
 import javax.microedition.khronos.egl.EGLConfig;
@@ -11,15 +14,8 @@
 
 import org.hedgewars.hedgeroid.Datastructures.GameConfig;
 import org.hedgewars.hedgeroid.EngineProtocol.PascalExports;
-import org.hedgewars.hedgeroid.frontlib.Flib;
-import org.hedgewars.hedgeroid.frontlib.Frontlib.GameSetupPtr;
-import org.hedgewars.hedgeroid.frontlib.Frontlib.GameconnPtr;
-import org.hedgewars.hedgeroid.frontlib.Frontlib.IntCallback;
 import org.hedgewars.hedgeroid.netplay.Netplay;
 import org.hedgewars.hedgeroid.util.FileUtils;
-import org.hedgewars.hedgeroid.util.TickHandler;
-
-import com.sun.jna.Pointer;
 
 import android.app.Activity;
 import android.content.Context;
@@ -33,9 +29,6 @@
 import android.media.AudioManager;
 import android.media.AudioTrack;
 import android.os.Bundle;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Message;
 import android.util.Base64;
 import android.util.DisplayMetrics;
 import android.util.Log;
@@ -61,9 +54,7 @@
 	// Main components
 	public static SDLActivity mSingleton;
 	private static SDLSurface mSurface;
-
-	// This is what SDL runs in. It invokes SDL_main(), eventually
-	private static Thread mSDLThread; // Guarded by SDLActivity.class
+	private static Thread mSDLThread;
 
 	// Audio
 	private static Thread mAudioThread;
@@ -79,15 +70,11 @@
 	// Load the .so
 	static {
 		System.loadLibrary("SDL");
-		//System.loadLibrary("SDL_image");
-		//System.loadLibrary("SDL_mixer");
-		//System.loadLibrary("SDL_ttf");
 		System.loadLibrary("main");
 	}
 
 	// Setup
 	protected void onCreate(Bundle savedInstanceState) {
-		//Log.v("SDL", "onCreate()");
 		super.onCreate(savedInstanceState);
 
 		// So we can call stuff from static callbacks
@@ -95,6 +82,7 @@
 
 		// Set up the surface
 		mSurface = new SDLSurface(getApplication(), startConfig, startNetgame);
+		startConfig = null;
 		setContentView(mSurface);
 	}
 
@@ -123,40 +111,18 @@
 		Log.v("SDL", "onDestroy()");
 		// Send a quit message to the application
 		SDLActivity.nativeQuit();
-
 		// Now wait for the SDL thread to quit
-		synchronized(SDLActivity.class) {
-			if (mSDLThread != null) {
-				try {
-					mSDLThread.join();
-				} catch(Exception e) {
-					Log.w("SDL", "Problem stopping thread: " + e);
-				}
-				mSDLThread = null;
+		if (mSDLThread != null) {
+			try {
+				mSDLThread.join();
+			} catch(Exception e) {
+				Log.w("SDL", "Problem stopping thread: " + e);
 			}
+			mSDLThread = null;
 		}
+		mSingleton = null;
 	}
-
-	// Messages from the SDLMain thread
-	static int COMMAND_CHANGE_TITLE = 1;
-
-	// Handler for the messages
-	Handler commandHandler = new Handler() {
-		public void handleMessage(Message msg) {
-			if (msg.arg1 == COMMAND_CHANGE_TITLE) {
-				setTitle((String)msg.obj);
-			}
-		}
-	};
-
-	// Send a message from the SDLMain thread
-	void sendCommand(int command, Object data) {
-		Message msg = commandHandler.obtainMessage();
-		msg.arg1 = command;
-		msg.obj = data;
-		commandHandler.sendMessage(msg);
-	}
-
+	
 	public static void synchronizedNativeInit(String...args) {
 		synchronized(PascalExports.engineMutex) {
 			nativeInit(args);
@@ -188,9 +154,13 @@
 		flipEGL();
 	}
 
-	public static void setActivityTitle(String title) {
+	public static void setActivityTitle(final String title) {
 		// Called from SDLMain() thread and can't directly affect the view
-		mSingleton.sendCommand(COMMAND_CHANGE_TITLE, title);
+		mSingleton.runOnUiThread(new Runnable() {
+			public void run() {
+				mSingleton.setTitle(title);
+			}
+		});
 	}
 
 	public static Context getContext() {
@@ -198,39 +168,18 @@
 	}
 
 	public static void startApp(final int width, final int height, GameConfig config, boolean netgame) {
-		synchronized(SDLActivity.class) {
-			// Start up the C app thread TODO this is silly code
-			if (mSDLThread == null) {
-				final AtomicBoolean gameconnStartDone = new AtomicBoolean(false);
-				GameConnection.Listener listener = new GameConnection.Listener() {
-					public void gameConnectionReady(int port) {
-						mSDLThread = new Thread(new SDLMain(width, height, port, "Medo"));
-						mSDLThread.start();
-						gameconnStartDone.set(true);
-					}
-					
-					public void gameConnectionDisconnected(int reason) {
-						Log.e("startApp", "disconnected: "+reason);
-						gameconnStartDone.set(true);
-					}
-				};
-				if(netgame) {
-					Netplay netplay = Netplay.getAppInstance(mSingleton.getApplicationContext());
-					GameConnection.forNetgame(config, netplay, listener);
-				} else {
-					GameConnection.forLocalGame(config, listener);
-				}
-			} else {
-				SDLActivity.nativeResume();
-			}
+		// Start up the C app thread
+		if (mSDLThread == null) {
+			mSDLThread = new Thread(new SDLMain(width, height, config, netgame));
+			mSDLThread.start();
+		} else {
+			SDLActivity.nativeResume();
 		}
 	}
 
 	// EGL functions
 	public static boolean initEGL(int majorVersion, int minorVersion) {
 		if (SDLActivity.mEGLDisplay == null) {
-			//Log.v("SDL", "Starting up OpenGL ES " + majorVersion + "." + minorVersion);
-
 			try {
 				EGL10 egl = (EGL10)EGLContext.getEGL();
 
@@ -248,7 +197,6 @@
 					renderableType = EGL_OPENGL_ES_BIT;
 				}
 				int[] configSpec = {
-						//EGL10.EGL_DEPTH_SIZE,   16,
 						EGL10.EGL_RENDERABLE_TYPE, renderableType,
 						EGL10.EGL_NONE
 				};
@@ -260,15 +208,6 @@
 				}
 				EGLConfig config = configs[0];
 
-				/*int EGL_CONTEXT_CLIENT_VERSION=0x3098;
-                int contextAttrs[] = new int[] { EGL_CONTEXT_CLIENT_VERSION, majorVersion, EGL10.EGL_NONE };
-                EGLContext ctx = egl.eglCreateContext(dpy, config, EGL10.EGL_NO_CONTEXT, contextAttrs);
-
-                if (ctx == EGL10.EGL_NO_CONTEXT) {
-                    Log.e("SDL", "Couldn't create context");
-                    return false;
-                }
-                SDLActivity.mEGLContext = ctx;*/
 				SDLActivity.mEGLDisplay = dpy;
 				SDLActivity.mEGLConfig = config;
 				SDLActivity.mGLMajor = majorVersion;
@@ -454,34 +393,74 @@
     Simple nativeInit() runnable
  */
 class SDLMain implements Runnable {
-
+	public static final String TAG = "SDLMain";
+	
+    public static final int RQ_LOWRES            = 0x00000001; // use half land array
+    public static final int RQ_BLURRY_LAND       = 0x00000002; // downscaled terrain
+    public static final int RQ_NO_BACKGROUND     = 0x00000004; // don't draw background
+    public static final int RQ_SIMPLE_ROPE       = 0x00000008; // avoid drawing rope
+    public static final int RQ_2D_WATER          = 0x00000010; // disabe 3D water effect
+    public static final int RQ_SIMPLE_EXPLOSIONS = 0x00000020; // no fancy explosion effects
+    public static final int RQ_NO_FLAKES         = 0x00000040; // no flakes
+    public static final int RQ_NO_MENU_ANIM      = 0x00000080; // ammomenu appears with no animation
+    public static final int RQ_NO_DROPLETS       = 0x00000100; // no droplets
+    public static final int RQ_NO_CLAMPING       = 0x00000200; // don't clamp textures
+    public static final int RQ_NO_TOOLTIPS       = 0x00000400; // tooltips are not drawn
+    public static final int RQ_NO_VSYNC          = 0x00000800; // don't sync on vblank
+	
 	private final int surfaceWidth, surfaceHeight;
-	private final int port;
 	private final String playerName;
-	HandlerThread thread = new HandlerThread("IPC thread");
+	private final GameConfig config;
+	private final boolean netgame;
 	
-	public SDLMain(int width, int height, int port, String playerName) {
+	public SDLMain(int width, int height, GameConfig config, boolean netgame) {
 		surfaceWidth = width;
 		surfaceHeight = height;
-		this.port = port;
-		this.playerName = playerName;
+		if(netgame) {
+			playerName = Netplay.getAppInstance(SDLActivity.getContext().getApplicationContext()).getPlayerName();
+		} else {
+			playerName = "Player";
+		}
+		this.config = config;
+		this.netgame = netgame;
 	}
 
 	public void run() {
 		//Set up the IPC socket server to communicate with the engine
-		String path = FileUtils.getDataPath(SDLActivity.mSingleton);//This represents the data directory
-		path = path.substring(0, path.length()-1);//remove the trailing '/'
-
-		Log.d("SDLMain", "Starting engine");
-		// Runs SDL_main() with added parameters
+		GameConnection gameConn;
+		String path;
 		try {
-			SDLActivity.synchronizedNativeInit(new String[] { String.valueOf(port),
-					String.valueOf(surfaceWidth), String.valueOf(surfaceHeight),
-					Integer.toString(0x40+0x10+0x100+0x2), "en.txt", Base64.encodeToString(playerName.getBytes("UTF-8"), 0), "1", "1", "1", path, ""  });
-		} catch (UnsupportedEncodingException e) {
-			throw new AssertionError(e); // never happens
+			if(netgame) {
+				Netplay netplay = Netplay.getAppInstance(SDLActivity.mSingleton.getApplicationContext());
+				gameConn = GameConnection.forNetgame(config, netplay);
+			} else {
+				gameConn = GameConnection.forLocalGame(config);
+			}
+			
+			path = FileUtils.getDataPathFile(SDLActivity.mSingleton).getAbsolutePath();
+			Log.d(TAG, "Starting engine");
+			// Runs SDL_main() with added parameters
+			try {
+				String pPort = String.valueOf(gameConn.port);
+				String pWidth = String.valueOf(surfaceWidth);
+				String pHeight = String.valueOf(surfaceHeight);
+				String pQuality = Integer.toString(RQ_NO_FLAKES|RQ_NO_DROPLETS|RQ_SIMPLE_EXPLOSIONS);
+				String pPlayerName = Base64.encodeToString(playerName.getBytes("UTF-8"), 0);
+				SDLActivity.synchronizedNativeInit(new String[] { pPort, pWidth, pHeight, pQuality, "en.txt", pPlayerName, "1", "1", "1", path, ""  });
+			} catch (UnsupportedEncodingException e) {
+				throw new AssertionError(e); // never happens
+			}
+			Log.d(TAG, "Engine stopped");
+		} catch(ConnectException e) {
+			Log.e(TAG, "Error starting IPC connection");
+		} catch (IOException e) {
+			Log.e(TAG, "Missing SDCard");
 		}
-		Log.d("SDLMain", "Engine stopped");
+		SDLActivity.mSingleton.runOnUiThread(new Runnable() { public void run() {
+			if(SDLActivity.mSingleton != null) {
+				SDLActivity.mSingleton.finish();
+			}
+		}});
 	}
 }
 
@@ -597,8 +576,9 @@
 	public boolean onKey(View  v, int keyCode, KeyEvent event) {
 		switch(keyCode){
 		case KeyEvent.KEYCODE_BACK:
-		        PascalExports.HWterminate(true);
-                        return true;
+			Log.d("SDL", "KEYCODE_BACK");
+			SDLActivity.nativeQuit();
+            return true;
 		case KeyEvent.KEYCODE_VOLUME_DOWN:
 		case KeyEvent.KEYCODE_VOLUME_UP:
 		case KeyEvent.KEYCODE_VOLUME_MUTE:
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/SettingsFragment.java	Mon Aug 20 20:16:37 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/SettingsFragment.java	Mon Aug 20 20:19:35 2012 +0200
@@ -5,12 +5,14 @@
 import java.io.IOException;
 import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 
 import org.hedgewars.hedgeroid.R;
 import org.hedgewars.hedgeroid.Datastructures.FrontendDataUtils;
 import org.hedgewars.hedgeroid.Datastructures.MapRecipe;
 import org.hedgewars.hedgeroid.Datastructures.Scheme;
 import org.hedgewars.hedgeroid.Datastructures.Schemes;
+import org.hedgewars.hedgeroid.Datastructures.TeamInGame;
 import org.hedgewars.hedgeroid.Datastructures.Weaponset;
 import org.hedgewars.hedgeroid.Datastructures.Weaponsets;
 import org.hedgewars.hedgeroid.util.FileUtils;
@@ -29,9 +31,7 @@
 import android.widget.Spinner;
 import android.widget.Toast;
 
-public class SettingsFragment extends Fragment implements RoomStateManager.Observer {
-	private static final String TAG = SettingsFragment.class.getSimpleName();
-	
+public class SettingsFragment extends Fragment {
 	private Spinner styleSpinner, schemeSpinner, weaponsetSpinner, themeSpinner;
 	private ImageView themeIcon;
 	
@@ -69,7 +69,7 @@
 		weaponsetSpinner = prepareSpinner(v, R.id.spinweapons, Weaponsets.toNameList(weaponsets), weaponsetSelectedListener);
 		themeSpinner = prepareSpinner(v, R.id.spinTheme, themes, themeSelectedListener);
 		
-		stateManager.registerObserver(this);
+		stateManager.addListener(roomStateChangeListener);
 
 		if(stateManager.getGameStyle() != null) {
 			styleSpinner.setSelection(styles.indexOf(stateManager.getGameStyle()), false);
@@ -111,7 +111,7 @@
 	@Override
 	public void onDestroy() {
 		super.onDestroy();
-		stateManager.unregisterObserver(this);
+		stateManager.removeListener(roomStateChangeListener);
 	}
 	
 	private static int getSchemePosition(List<Scheme> schemes, String scheme) {
@@ -182,23 +182,27 @@
 		public void onNothingSelected(AdapterView<?> arg0) {};
 	};
 	
-	public void onChiefStatusChanged(boolean isChief) {
-		setChiefState(isChief);
-	}
-	
-	public void onGameStyleChanged(String gameStyle) {
-		styleSpinner.setSelection(styles.indexOf(gameStyle));
-	}
-	
-	public void onMapChanged(MapRecipe recipe) {
-		themeSpinner.setSelection(themes.indexOf(recipe.theme));
-	}
-	
-	public void onSchemeChanged(Scheme scheme) {
-		schemeSpinner.setSelection(getSchemePosition(schemes, scheme.name));
-	}
-	
-	public void onWeaponsetChanged(Weaponset weaponset) {
-		weaponsetSpinner.setSelection(getWeaponsetPosition(weaponsets, weaponset.name));
-	}
+	private final RoomStateManager.Listener roomStateChangeListener = new RoomStateManager.Listener() {
+		public void onWeaponsetChanged(Weaponset weaponset) {
+			weaponsetSpinner.setSelection(getWeaponsetPosition(weaponsets, weaponset.name));
+		}
+		
+		public void onTeamsChanged(Map<String, TeamInGame> teams) {}
+		
+		public void onSchemeChanged(Scheme scheme) {
+			schemeSpinner.setSelection(getSchemePosition(schemes, scheme.name));
+		}
+		
+		public void onMapChanged(MapRecipe recipe) {
+			themeSpinner.setSelection(themes.indexOf(recipe.theme));
+		}
+		
+		public void onGameStyleChanged(String gameStyle) {
+			styleSpinner.setSelection(styles.indexOf(gameStyle));
+		}
+		
+		public void onChiefStatusChanged(boolean isChief) {
+			setChiefState(isChief);
+		}
+	};
 }
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/StartGameActivity.java	Mon Aug 20 20:16:37 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,217 +0,0 @@
-/*
- * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
- * Copyright (c) 2011-2012 Richard Deurwaarder <xeli@xelification.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-
-
-package org.hedgewars.hedgeroid;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.UUID;
-
-import org.hedgewars.hedgeroid.Datastructures.FrontendDataUtils;
-import org.hedgewars.hedgeroid.Datastructures.GameConfig;
-import org.hedgewars.hedgeroid.Datastructures.MapFile;
-import org.hedgewars.hedgeroid.Datastructures.MapRecipe;
-import org.hedgewars.hedgeroid.Datastructures.Scheme;
-import org.hedgewars.hedgeroid.Datastructures.Schemes;
-import org.hedgewars.hedgeroid.Datastructures.TeamInGame;
-import org.hedgewars.hedgeroid.Datastructures.Weaponset;
-import org.hedgewars.hedgeroid.Datastructures.Weaponsets;
-import org.hedgewars.hedgeroid.util.FileUtils;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.graphics.drawable.Drawable;
-import android.os.Bundle;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.AdapterView;
-import android.widget.AdapterView.OnItemSelectedListener;
-import android.widget.ArrayAdapter;
-import android.widget.ImageButton;
-import android.widget.ImageView;
-import android.widget.Spinner;
-import android.widget.Toast;
-
-public class StartGameActivity extends Activity {
-	public static final int ACTIVITY_TEAM_SELECTOR = 0;
-	
-	private ImageButton start, back, team;
-	private Spinner mapSpinner, styleSpinner, schemeSpinner, weaponsetSpinner, themeSpinner;
-	private ImageView themeIcon, mapPreview, teamCount;
-
-	private List<MapFile> mapFiles;
-	private List<String> styles;
-	private List<Scheme> schemes;
-	private List<Weaponset> weaponsets;
-	private List<String> themes;
-	
-	private List<TeamInGame> teams = new ArrayList<TeamInGame>();
-
-	public void onCreate(Bundle savedInstanceState){
-		super.onCreate(savedInstanceState);
-
-		setContentView(R.layout.starting_game);
-
-		back = (ImageButton) findViewById(R.id.btnBack);
-		team = (ImageButton) findViewById(R.id.btnTeams);
-		start = (ImageButton) findViewById(R.id.btnStart);
-
-		themeIcon = (ImageView) findViewById(R.id.imgTheme);
-		mapPreview = (ImageView) findViewById(R.id.mapPreview);
-		teamCount = (ImageView) findViewById(R.id.imgTeamsCount);
-
-		start.setOnClickListener(startClicker);
-		back.setOnClickListener(backClicker);
-		team.setOnClickListener(teamClicker);
-
-		try {
-			mapFiles = FrontendDataUtils.getMaps(this);
-			styles = FrontendDataUtils.getGameStyles(this);
-			schemes = Schemes.loadAllSchemes(this);
-			weaponsets = Weaponsets.loadAllWeaponsets(this);
-			themes = FrontendDataUtils.getThemes(this);
-		} catch (IOException e) {
-			Toast.makeText(getApplicationContext(), R.string.error_missing_sdcard_or_files, Toast.LENGTH_LONG).show();
-			finish();
-		}
-		
-		Collections.sort(mapFiles, MapFile.MISSIONS_FIRST_NAME_ORDER);
-		Collections.sort(styles, String.CASE_INSENSITIVE_ORDER);
-		Collections.sort(schemes, Scheme.NAME_ORDER);
-		Collections.sort(weaponsets, Weaponset.NAME_ORDER);
-		Collections.sort(themes, String.CASE_INSENSITIVE_ORDER);
-		
-		List<String> mapNames = MapFile.toDisplayNameList(mapFiles, getResources());
-		List<String> schemeNames = Schemes.toNameList(schemes);
-		List<String> weaponsetNames = Weaponsets.toNameList(weaponsets);
-		View rootView = findViewById(android.R.id.content);
-		mapSpinner = prepareSpinner(rootView, R.id.spinMaps, mapNames, mapsClicker);
-		styleSpinner = prepareSpinner(rootView, R.id.spinGameplay, styles, null);
-		schemeSpinner = prepareSpinner(rootView, R.id.spinGamescheme, schemeNames, null);
-		weaponsetSpinner = prepareSpinner(rootView, R.id.spinweapons, weaponsetNames, null);
-		themeSpinner = prepareSpinner(rootView, R.id.spinTheme, themes, themesClicker);
-		
-		// set map to first nonmission
-		for(int i = 0; i < mapFiles.size(); i++){
-			if(!mapFiles.get(i).isMission){
-				mapSpinner.setSelection(i, false);
-				break;
-			}
-		}
-		styleSpinner.setSelection(styles.indexOf(GameConfig.DEFAULT_STYLE), false);
-		schemeSpinner.setSelection(schemeNames.indexOf(GameConfig.DEFAULT_SCHEME), false);
-		weaponsetSpinner.setSelection(weaponsetNames.indexOf(GameConfig.DEFAULT_WEAPONSET), false);
-		themeSpinner.setSelection(themes.indexOf(GameConfig.DEFAULT_THEME), false);
-	}
-
-	private static Spinner prepareSpinner(View v, int id, List<String> items, OnItemSelectedListener itemSelectedListener) {
-		Spinner spinner = (Spinner)v.findViewById(id);
-		ArrayAdapter<String> adapter = new ArrayAdapter<String>(v.getContext(), R.layout.listview_item, items);
-		adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
-		spinner.setAdapter(adapter);
-		spinner.setOnItemSelectedListener(itemSelectedListener);
-		return spinner;
-	}
-	
-	private void startTeamsActivity(){
-		Intent i = new Intent(StartGameActivity.this, TeamSelectionActivity.class);
-		TeamSelectionActivity.activityParams = new ArrayList<TeamInGame>(teams);
-		startActivityForResult(i, ACTIVITY_TEAM_SELECTOR);
-	}
-
-	public void onActivityResult(int requestCode, int resultCode, Intent data){
-		switch(requestCode){
-		case ACTIVITY_TEAM_SELECTOR:
-			if(resultCode == Activity.RESULT_OK){
-				teams = new ArrayList<TeamInGame>(TeamSelectionActivity.activityReturn);
-				TeamSelectionActivity.activityReturn = Collections.emptyList();
-				teamCount.getDrawable().setLevel(teams.size());
-			}
-			break;
-		}
-	}
-
-
-	private OnItemSelectedListener themesClicker = new OnItemSelectedListener(){
-
-		public void onItemSelected(AdapterView<?> arg0, View view, int position, long rowId) {
-			String themeName = themes.get(position);
-			Drawable themeIconDrawable = Drawable.createFromPath(FileUtils.getDataPath(StartGameActivity.this) + "Themes/" + themeName + "/icon@2X.png");
-			themeIcon.setImageDrawable(themeIconDrawable);
-		}
-
-		public void onNothingSelected(AdapterView<?> arg0) {
-		}
-
-	};
-
-	private OnItemSelectedListener mapsClicker = new OnItemSelectedListener(){
-
-		public void onItemSelected(AdapterView<?> arg0, View view, int position,long rowId) {
-			MapFile map = mapFiles.get(position);
-			try {
-				File previewFile = map.getPreviewFile(getApplicationContext());
-				mapPreview.setImageDrawable(Drawable.createFromPath(previewFile.getAbsolutePath()));
-			} catch (FileNotFoundException e) {
-				mapPreview.setImageDrawable(null);
-			}
-		}
-
-		public void onNothingSelected(AdapterView<?> arg0) {
-		}
-
-	};
-
-	private OnClickListener startClicker = new OnClickListener(){
-		public void onClick(View v) {
-			if(teams.size() < 2) {
-				Toast.makeText(getApplicationContext(), R.string.not_enough_teams, Toast.LENGTH_LONG).show();
-				startTeamsActivity();
-			} else {
-				String style = styles.get(styleSpinner.getSelectedItemPosition());
-				Scheme scheme = schemes.get(schemeSpinner.getSelectedItemPosition());
-				String mapName = mapFiles.get(mapSpinner.getSelectedItemPosition()).name;
-				String theme = themes.get(themeSpinner.getSelectedItemPosition());
-				MapRecipe map = MapRecipe.makeMap(mapName, UUID.randomUUID().toString(), theme);
-				Weaponset weaponset = weaponsets.get(weaponsetSpinner.getSelectedItemPosition());
-				SDLActivity.startConfig = new GameConfig(style, scheme, map, teams, weaponset);
-				SDLActivity.startNetgame = false;
-				Intent i = new Intent(StartGameActivity.this, SDLActivity.class);
-				startActivity(i);
-			}
-		}
-	};
-
-	private OnClickListener backClicker = new OnClickListener(){
-		public void onClick(View v) {
-			finish();
-		}
-	};
-
-	private OnClickListener teamClicker = new OnClickListener(){
-		public void onClick(View v) {
-			startTeamsActivity();
-		}
-	};
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/TeamListActivity.java	Mon Aug 20 20:19:35 2012 +0200
@@ -0,0 +1,128 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (c) 2011-2012 Richard Deurwaarder <xeli@xelification.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+package org.hedgewars.hedgeroid;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.hedgewars.hedgeroid.Datastructures.FrontendDataUtils;
+import org.hedgewars.hedgeroid.Datastructures.Team;
+
+import android.app.ListActivity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.ContextMenu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.AdapterView;
+import android.widget.AdapterView.AdapterContextMenuInfo;
+import android.widget.AdapterView.OnItemClickListener;
+import android.widget.ImageButton;
+import android.widget.SimpleAdapter;
+
+public class TeamListActivity extends ListActivity implements OnItemClickListener {
+	private List<Team> teams;
+	private ImageButton addButton;
+
+	@Override
+	protected void onCreate(Bundle savedInstanceState) {
+		super.onCreate(savedInstanceState);
+		setContentView(R.layout.activity_teamlist);
+		addButton = (ImageButton)findViewById(R.id.btnAdd);
+		addButton.setOnClickListener(new OnClickListener() {
+			public void onClick(View v) {
+				editTeam(null);
+			}
+		});
+	}
+	
+	@Override
+	public void onResume() {
+		super.onResume();
+		updateList();
+		getListView().setOnItemClickListener(this);
+		registerForContextMenu(getListView());
+	}
+	
+	public void onItemClick(AdapterView<?> adapterView, View v, int position, long arg3) {
+		editTeam(teams.get(position).name);
+	}
+	
+	@Override
+	public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuinfo){
+		menu.add(ContextMenu.NONE, 0, ContextMenu.NONE, R.string.edit);
+		menu.add(ContextMenu.NONE, 1, ContextMenu.NONE, R.string.delete);
+	}
+	
+	@Override
+	public boolean onContextItemSelected(MenuItem item){
+		AdapterView.AdapterContextMenuInfo menuInfo = (AdapterContextMenuInfo) item.getMenuInfo();
+		int position = menuInfo.position;
+		Team team = teams.get(position);
+		switch(item.getItemId()){
+		case 0:
+			editTeam(team.name);
+			return true;
+		case 1:
+			Team.getTeamfileByName(getApplicationContext(), team.name).delete();
+			updateList();
+			return true;
+		}
+		return false;
+	}
+	
+	private void updateList() {
+		teams = FrontendDataUtils.getTeams(getApplicationContext());
+		Collections.sort(teams, Team.NAME_ORDER);
+		SimpleAdapter adapter = new SimpleAdapter(this, teamsToMaps(teams), R.layout.team_selection_entry_simple, new String[]{"txt", "img"}, new int[]{R.id.txtName, R.id.imgDifficulty});
+		setListAdapter(adapter);
+	}
+	
+	private void editTeam(String teamName) {
+		Intent i = new Intent(this, TeamCreatorActivity.class);
+		i.putExtra(TeamCreatorActivity.PARAMETER_EXISTING_TEAMNAME, teamName);
+		startActivity(i);
+	}
+
+	private static final int[] botlevelDrawables = new int[] {
+		R.drawable.human, R.drawable.bot5, R.drawable.bot4, R.drawable.bot3, R.drawable.bot2, R.drawable.bot1
+	};
+	
+	private List<Map<String, ?>> teamsToMaps(List<Team> teams) {
+		List<Map<String, ?>> result = new ArrayList<Map<String,?>>();
+		for(Team t : teams) {
+			HashMap<String, Object> map = new HashMap<String, Object>();
+			map.put("team", t);
+			map.put("txt", t.name);
+			int botlevel = t.hogs.get(0).level;
+			if(botlevel<0 || botlevel>=botlevelDrawables.length) {
+				map.put("img", R.drawable.bot1);
+			} else {
+				map.put("img", botlevelDrawables[botlevel]);
+			}
+			result.add(map);
+		}
+		return result;
+	}
+}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/TeamSelectionActivity.java	Mon Aug 20 20:16:37 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,287 +0,0 @@
-/*
- * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
- * Copyright (c) 2011-2012 Richard Deurwaarder <xeli@xelification.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-
-
-package org.hedgewars.hedgeroid;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-
-import org.hedgewars.hedgeroid.Datastructures.FrontendDataUtils;
-import org.hedgewars.hedgeroid.Datastructures.Team;
-import org.hedgewars.hedgeroid.Datastructures.TeamInGame;
-import org.hedgewars.hedgeroid.Datastructures.TeamIngameAttributes;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.os.Bundle;
-import android.view.ContextMenu;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.AdapterView;
-import android.widget.AdapterView.AdapterContextMenuInfo;
-import android.widget.AdapterView.OnItemClickListener;
-import android.widget.ImageButton;
-import android.widget.ImageView;
-import android.widget.ListView;
-import android.widget.SimpleAdapter;
-import android.widget.SimpleAdapter.ViewBinder;
-import android.widget.TextView;
-
-public class TeamSelectionActivity extends Activity implements Runnable{
-	private static final int ACTIVITY_TEAMCREATION = 0;
-	
-	public static volatile List<TeamInGame> activityParams;
-	public static volatile List<TeamInGame> activityReturn;
-
-	private ImageButton addTeam;
-	private ListView availableTeams, selectedTeams;
-	private List<HashMap<String, Object>> availableTeamsList, selectedTeamsList;
-	private TextView txtInfo;
-
-	public void onCreate(Bundle savedInstanceState){
-		super.onCreate(savedInstanceState);
-
-		setContentView(R.layout.team_selector);
-
-		addTeam = (ImageButton) findViewById(R.id.btnAdd);
-		txtInfo = (TextView) findViewById(R.id.txtInfo);
-		selectedTeams = (ListView) findViewById(R.id.selectedTeams);
-		availableTeams = (ListView) findViewById(R.id.availableTeams);
-		addTeam.setOnClickListener(addTeamClicker);
-
-		availableTeamsList = new ArrayList<HashMap<String, Object>>();
-		SimpleAdapter adapter = new SimpleAdapter(this, availableTeamsList, R.layout.team_selection_entry_simple, new String[]{"txt", "img"}, new int[]{R.id.txtName, R.id.imgDifficulty});
-		availableTeams.setAdapter(adapter);
-		availableTeams.setOnItemClickListener(availableClicker);
-		registerForContextMenu(availableTeams);
-
-		selectedTeamsList = new ArrayList<HashMap<String, Object>>();
-		adapter = new SimpleAdapter(this, selectedTeamsList, R.layout.team_selection_entry, new String[]{"txt", "img", "color", "count"}, new int[]{R.id.txtName, R.id.imgDifficulty, R.id.teamColor, R.id.teamCount});
-		adapter.setViewBinder(viewBinder);
-		selectedTeams.setAdapter(adapter);
-		selectedTeams.setOnItemClickListener(selectedClicker);
-
-		txtInfo.setText(String.format(getResources().getString(R.string.teams_info_template), selectedTeams.getChildCount()));
-
-		new Thread(this).start();//load the teams from xml async
-	}
-
-	public void run(){
-		List<Team> teams = FrontendDataUtils.getTeams(this);
-		List<TeamInGame> existingTeams = activityParams;
-		final List<TeamInGame> newSelectedList = new ArrayList<TeamInGame>();
-		final List<Team> newAvailableList = new ArrayList<Team>();
-		
-		for(Team team : teams){
-			boolean added = false;
-			for(TeamInGame existingTeam : existingTeams){
-				if(team.name.equals(existingTeam.team.name)){ // add to available or add to selected
-					newSelectedList.add(new TeamInGame(team, existingTeam.ingameAttribs));
-					added = true;
-					break;
-				}
-			}
-			if(!added) newAvailableList.add(team);
-		}
-
-		this.runOnUiThread(new Runnable(){
-			public void run() {
-				availableTeamsList.clear();
-				selectedTeamsList.clear();
-				for(TeamInGame t : newSelectedList) {
-					selectedTeamsList.add(toMap(t));
-				}
-				for(Team t : newAvailableList) {
-					availableTeamsList.add(toMap(t));
-				}
-				((SimpleAdapter)selectedTeams.getAdapter()).notifyDataSetChanged();
-				((SimpleAdapter)availableTeams.getAdapter()).notifyDataSetChanged();		
-			}
-		});
-	}
-
-	private ViewBinder viewBinder = new ViewBinder(){
-		public boolean setViewValue(View view, Object data,	String textRepresentation) {
-			switch(view.getId()){
-			case R.id.teamColor:
-				setTeamColor(view, (Integer)data);
-				return true;
-			case R.id.teamCount:
-				((ImageView)view).getDrawable().setLevel((Integer)data);
-				return true;
-			default:
-				return false;
-			}
-		}
-	};
-
-	public void onActivityResult(int requestCode, int resultCode, Intent data){
-		if(requestCode == ACTIVITY_TEAMCREATION){
-			if(resultCode == Activity.RESULT_OK){
-				updateListViews();
-			}
-		}else{
-			super.onActivityResult(requestCode, resultCode, data);
-		}
-	}
-
-	/*
-	 * Updates the list view when TeamCreationActivity is shutdown and the user returns to this point
-	 */
-	private void updateListViews(){
-		List<Team> teams = FrontendDataUtils.getTeams(this);
-		availableTeamsList.clear();
-		for(Team team : teams) {
-			availableTeamsList.add(toMap(team));
-		}
-		
-		ArrayList<HashMap<String, Object>> toBeRemoved = new ArrayList<HashMap<String, Object>>();
-		ArrayList<HashMap<String, Object>> toBeRemovedFromSelected = new ArrayList<HashMap<String, Object>>();
-		for(HashMap<String, Object> hashmap : selectedTeamsList){
-			String name = (String)hashmap.get("txt");
-			boolean exists = false;
-			for(HashMap<String, Object> hash : availableTeamsList){
-				if(name.equals((String)hash.get("txt"))){
-					toBeRemoved.add(hash);
-					exists = true;
-					break;
-				}
-			}
-			if(!exists) {
-				toBeRemovedFromSelected.add(hashmap);
-			}
-		}
-		for(HashMap<String, Object> hash: toBeRemoved) availableTeamsList.remove(hash);
-		for(HashMap<String, Object> hash: toBeRemovedFromSelected) selectedTeamsList.remove(hash);
-		((SimpleAdapter)selectedTeams.getAdapter()).notifyDataSetChanged();
-		((SimpleAdapter)availableTeams.getAdapter()).notifyDataSetChanged();
-	}
-
-	private void setTeamColor(View iv, int colorIndex){
-		iv.setBackgroundColor(0xFF000000 + TeamIngameAttributes.TEAM_COLORS[colorIndex]);
-	}
-
-	public void onBackPressed(){
-		returnTeams();
-		super.onBackPressed();
-	}
-
-	private OnClickListener addTeamClicker = new OnClickListener(){
-		public void onClick(View v) {
-			startActivityForResult(new Intent(TeamSelectionActivity.this, TeamCreatorActivity.class), ACTIVITY_TEAMCREATION);
-		}
-	};
-
-	private OnItemClickListener availableClicker = new OnItemClickListener(){
-		public void onItemClick(AdapterView<?> arg0, View arg1, int position,long arg3) {
-			selectAvailableTeamsItem(position);
-		}
-	};
-	private OnItemClickListener selectedClicker = new OnItemClickListener(){
-		public void onItemClick(AdapterView<?> arg0, View arg1, int position,long arg3) {
-			availableTeamsList.add((HashMap<String, Object>) selectedTeamsList.get(position));
-			selectedTeamsList.remove(position);
-			((SimpleAdapter)availableTeams.getAdapter()).notifyDataSetChanged();
-			((SimpleAdapter)selectedTeams.getAdapter()).notifyDataSetChanged();
-
-			txtInfo.setText(String.format(getResources().getString(R.string.teams_info_template), selectedTeamsList.size()));
-		}
-
-	};
-
-	public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuinfo){
-		menu.add(ContextMenu.NONE, 0, ContextMenu.NONE, R.string.select);
-		menu.add(ContextMenu.NONE, 2, ContextMenu.NONE, R.string.edit);
-		menu.add(ContextMenu.NONE, 1, ContextMenu.NONE, R.string.delete);
-
-	}
-	public boolean onContextItemSelected(MenuItem item){
-		AdapterView.AdapterContextMenuInfo menuInfo = (AdapterContextMenuInfo) item.getMenuInfo();
-		int position = menuInfo.position;
-		Team team = (Team)availableTeamsList.get(position).get("team");
-		switch(item.getItemId()){
-		case 0://select
-			selectAvailableTeamsItem(position);
-			return true;
-		case 1://delete
-			Team.getTeamfileByName(getApplicationContext(), team.name).delete();
-			availableTeamsList.remove(position);
-			((SimpleAdapter)availableTeams.getAdapter()).notifyDataSetChanged();
-			return true;
-		case 2://edit
-			Intent i = new Intent(TeamSelectionActivity.this, TeamCreatorActivity.class);
-			i.putExtra(TeamCreatorActivity.PARAMETER_EXISTING_TEAMNAME, team.name);
-			startActivityForResult(i, ACTIVITY_TEAMCREATION);
-			return true;
-		}
-		return false;
-	}
-
-	private void selectAvailableTeamsItem(int position){
-		HashMap<String, Object> hash = (HashMap<String, Object>) availableTeamsList.get(position);
-		int[] illegalcolors = new int[selectedTeamsList.size()];
-		for(int i = 0; i < selectedTeamsList.size(); i++){
-			illegalcolors[i] = (Integer)selectedTeamsList.get(i).get("color");
-		}
-		hash.put("color", TeamIngameAttributes.randomColorIndex(illegalcolors));
-		hash.put("count", TeamIngameAttributes.DEFAULT_HOG_COUNT);
-
-		selectedTeamsList.add(hash);
-		availableTeamsList.remove(position);
-		((SimpleAdapter)availableTeams.getAdapter()).notifyDataSetChanged();
-		((SimpleAdapter)selectedTeams.getAdapter()).notifyDataSetChanged();
-
-		txtInfo.setText(String.format(getResources().getString(R.string.teams_info_template), selectedTeamsList.size()));
-	}
-
-	private void returnTeams() {
-		List<TeamInGame> result = new ArrayList<TeamInGame>();
-		for(HashMap<String, Object> item : selectedTeamsList) {
-			result.add(new TeamInGame((Team)item.get("team"), new TeamIngameAttributes("Player", (Integer)item.get("color"), (Integer)item.get("count"), false)));
-		}
-		activityReturn = result;
-		setResult(Activity.RESULT_OK);
-	}
-	
-	private static final int[] botlevelDrawables = new int[] {
-		R.drawable.human, R.drawable.bot5, R.drawable.bot4, R.drawable.bot3, R.drawable.bot2, R.drawable.bot1
-	};
-		
-	private static HashMap<String, Object> toMap(Team t) {
-		HashMap<String, Object> map = new HashMap<String, Object>();
-		map.put("team", t);
-		map.put("txt", t.name);
-		int botlevel = t.hogs.get(0).level;
-		if(botlevel<0 || botlevel>=botlevelDrawables.length) {
-			map.put("img", R.drawable.bot1);
-		} else {
-			map.put("img", botlevelDrawables[botlevel]);
-		}	
-		return map;
-	}
-	
-	private static HashMap<String, Object> toMap(TeamInGame t) {
-		HashMap<String, Object> map = toMap(t.team);
-		map.put("color", t.ingameAttribs.colorIndex);
-		map.put("count", t.ingameAttribs.hogCount);
-		return map;
-	}
-}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/TeamlistAdapter.java	Mon Aug 20 20:16:37 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/TeamlistAdapter.java	Mon Aug 20 20:19:35 2012 +0200
@@ -1,11 +1,13 @@
 package org.hedgewars.hedgeroid;
 
-import java.util.Comparator;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
 
 import org.hedgewars.hedgeroid.R;
 import org.hedgewars.hedgeroid.Datastructures.TeamInGame;
 import org.hedgewars.hedgeroid.Datastructures.TeamIngameAttributes;
-import org.hedgewars.hedgeroid.util.ObservableTreeMapAdapter;
 
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
@@ -13,18 +15,15 @@
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.ViewGroup;
+import android.widget.BaseAdapter;
 import android.widget.ImageButton;
 import android.widget.TextView;
 
-public class TeamlistAdapter extends ObservableTreeMapAdapter<String, TeamInGame> {
+public class TeamlistAdapter extends BaseAdapter {
 	private boolean colorHogcountEnabled = false;
 	private Listener listener;
+	private List<TeamInGame> teams = new ArrayList<TeamInGame>();
 	
-	@Override
-	protected Comparator<TeamInGame> getEntryOrder() {
-		return TeamInGame.NAME_ORDER;
-	}
-
 	public void setColorHogcountEnabled(boolean colorHogcountEnabled) {
 		this.colorHogcountEnabled = colorHogcountEnabled;
 		notifyDataSetChanged();
@@ -34,6 +33,30 @@
 		this.listener = listener;
 	}
 	
+	public int getCount() {
+		return teams.size();
+	}
+	
+	public TeamInGame getItem(int position) {
+		return teams.get(position);
+	}
+	
+	public long getItemId(int position) {
+		return position;
+	}
+	
+	@Override
+	public boolean hasStableIds() {
+		return false;
+	}
+	
+	public void updateTeamlist(Collection<TeamInGame> newTeams) {
+		teams.clear();
+		teams.addAll(newTeams);
+		Collections.sort(teams, TeamInGame.NAME_ORDER);
+		notifyDataSetChanged();
+	}
+	
 	public View getView(int position, View convertView, ViewGroup parent) {
 		View v = convertView;
 		if (v == null) {
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/TeamlistFragment.java	Mon Aug 20 20:16:37 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/TeamlistFragment.java	Mon Aug 20 20:19:35 2012 +0200
@@ -3,17 +3,12 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
+import java.util.Map;
 
-import org.hedgewars.hedgeroid.R;
-import org.hedgewars.hedgeroid.Datastructures.MapRecipe;
-import org.hedgewars.hedgeroid.Datastructures.Scheme;
 import org.hedgewars.hedgeroid.Datastructures.Team;
 import org.hedgewars.hedgeroid.Datastructures.TeamInGame;
 import org.hedgewars.hedgeroid.Datastructures.TeamIngameAttributes;
-import org.hedgewars.hedgeroid.Datastructures.Weaponset;
-import org.hedgewars.hedgeroid.netplay.Netplay;
 
-import android.database.DataSetObserver;
 import android.os.Bundle;
 import android.support.v4.app.ListFragment;
 import android.view.LayoutInflater;
@@ -22,15 +17,9 @@
 import android.view.ViewGroup;
 import android.widget.Button;
 
-/**
- *  TODO use an interface for querying and manipulating the team list, to allow re-using this fragment
- *  in local play
- */
-public class TeamlistFragment extends ListFragment implements TeamlistAdapter.Listener, RoomStateManager.Observer {
-	private Netplay netplay;
+public class TeamlistFragment extends ListFragment implements TeamlistAdapter.Listener {
 	private TeamlistAdapter adapter;
 	private Button addTeamButton;
-	private DataSetObserver teamlistObserver;
 	private RoomStateManager stateManager;
 	
 	@Override
@@ -41,13 +30,12 @@
 		} catch(ClassCastException e) {
 			throw new RuntimeException("Hosting activity must implement RoomStateManager.Provider.", e);
 		}
-		netplay = Netplay.getAppInstance(getActivity().getApplicationContext());
 		adapter = new TeamlistAdapter();
-		adapter.setSource(netplay.roomTeamlist);
+		adapter.updateTeamlist(stateManager.getTeams().values());
 		adapter.setColorHogcountEnabled(stateManager.getChiefStatus());
 		adapter.setListener(this);
 		setListAdapter(adapter);
-		stateManager.registerObserver(this);
+		stateManager.addListener(roomStateChangeListener);
 	}
 
 	@Override
@@ -61,14 +49,7 @@
 			}
 		});
 		
-		teamlistObserver = new DataSetObserver() {
-			@Override
-			public void onChanged() {
-				addTeamButton.setEnabled(netplay.roomTeamlist.getMap().size() < Team.maxNumberOfTeams);
-			}
-		};
-		netplay.roomTeamlist.registerObserver(teamlistObserver);
-		teamlistObserver.onChanged();
+		addTeamButton.setEnabled(stateManager.getTeams().size() < Team.maxNumberOfTeams);
 		
 		return v;
 	}
@@ -76,27 +57,20 @@
 	@Override
 	public void onDestroy() {
 		super.onDestroy();
-		adapter.invalidate();
 		adapter.setListener(null);
-		netplay.roomTeamlist.unregisterObserver(teamlistObserver);
-		stateManager.unregisterObserver(this);
+		stateManager.removeListener(roomStateChangeListener);
 	}
 
-	@Override
-	public void onActivityCreated(Bundle savedInstanceState) {
-		super.onActivityCreated(savedInstanceState);
-	}
-	
 	private Collection<String> getCurrentTeamNames() {
 		List<String> names = new ArrayList<String>();
-		for(TeamInGame team : netplay.roomTeamlist.getMap().values()) {
+		for(TeamInGame team : stateManager.getTeams().values()) {
 			names.add(team.team.name);
 		}
 		return names;
 	}
 	
 	public void onColorClicked(TeamInGame team) {
-		netplay.changeTeamColorIndex(team.team.name, (team.ingameAttribs.colorIndex+1)%TeamIngameAttributes.TEAM_COLORS.length);
+		stateManager.changeTeamColorIndex(team.team.name, (team.ingameAttribs.colorIndex+1)%TeamIngameAttributes.TEAM_COLORS.length);
 	}
 	
 	public void onHogcountClicked(TeamInGame team) {
@@ -104,19 +78,23 @@
 		if(newHogCount>Team.HEDGEHOGS_PER_TEAM) {
 			newHogCount = 1;
 		}
-		netplay.changeTeamHogCount(team.team.name, newHogCount);
+		stateManager.changeTeamHogCount(team.team.name, newHogCount);
 	}
 	
 	public void onTeamClicked(TeamInGame team) {
-		netplay.sendRemoveTeam(team.team.name);
+		stateManager.requestRemoveTeam(team.team.name);
 	}
 	
-	public void onChiefStatusChanged(boolean isChief) {
-		adapter.setColorHogcountEnabled(isChief);
-	}
-	
-	public void onGameStyleChanged(String gameStyle) { }
-	public void onMapChanged(MapRecipe recipe) { }
-	public void onSchemeChanged(Scheme scheme) { }
-	public void onWeaponsetChanged(Weaponset weaponset) { }
+	private final RoomStateManager.Listener roomStateChangeListener = new RoomStateManager.ListenerAdapter() {
+		@Override
+		public void onChiefStatusChanged(boolean isChief) {
+			adapter.setColorHogcountEnabled(isChief);
+		};
+		
+		@Override
+		public void onTeamsChanged(Map<String, TeamInGame> teams) {
+			adapter.updateTeamlist(teams.values());
+			addTeamButton.setEnabled(teams.size() < Team.maxNumberOfTeams);
+		};
+	};
 }
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/frontlib/Flib.java	Mon Aug 20 20:16:37 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/frontlib/Flib.java	Mon Aug 20 20:19:35 2012 +0200
@@ -29,7 +29,7 @@
 		}
 	};
 	static {
-		INSTANCE.flib_log_setLevel(Frontlib.FLIB_LOGLEVEL_ALL);
+		INSTANCE.flib_log_setLevel(Frontlib.FLIB_LOGLEVEL_INFO);
 		INSTANCE.flib_log_setCallback(logCb);
 	}
 }
\ No newline at end of file
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/frontlib/Frontlib.java	Mon Aug 20 20:16:37 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/frontlib/Frontlib.java	Mon Aug 20 20:19:35 2012 +0200
@@ -1,6 +1,5 @@
 package org.hedgewars.hedgeroid.frontlib;
 import java.io.UnsupportedEncodingException;
-import java.nio.Buffer;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -1067,7 +1066,7 @@
 	void flib_netconn_onHogCountChanged(NetconnPtr conn, StrIntCallback callback, Pointer context);
 	void flib_netconn_onTeamColorChanged(NetconnPtr conn, StrIntCallback callback, Pointer context);
 	void flib_netconn_onEngineMessage(NetconnPtr conn, BytesCallback callback, Pointer context);
-	void flib_netconn_onCfgScheme(NetconnPtr conn, SchemeCallback callback, Pointer context);
+	void flib_netconn_onSchemeChanged(NetconnPtr conn, SchemeCallback callback, Pointer context);
 	void flib_netconn_onMapChanged(NetconnPtr conn, MapIntCallback callback, Pointer context);
 	void flib_netconn_onScriptChanged(NetconnPtr conn, StrCallback callback, Pointer context);
 	void flib_netconn_onWeaponsetChanged(NetconnPtr conn, WeaponsetCallback callback, Pointer context);
@@ -1081,8 +1080,8 @@
 	static final int GAME_END_ERROR = 3;
 	
 	GameconnPtr flib_gameconn_create(String playerName, GameSetupPtr setup, boolean netgame);
-	GameconnPtr flib_gameconn_create_playdemo(Buffer demo, NativeSizeT size);
-	GameconnPtr flib_gameconn_create_loadgame(String playerName, Buffer save, NativeSizeT size);
+	GameconnPtr flib_gameconn_create_playdemo(Pointer demo, NativeSizeT size);
+	GameconnPtr flib_gameconn_create_loadgame(String playerName, Pointer save, NativeSizeT size);
 	GameconnPtr flib_gameconn_create_campaign(String playerName, String seed, String script);
 
 	void flib_gameconn_destroy(GameconnPtr conn);
@@ -1093,6 +1092,7 @@
 	int flib_gameconn_send_textmsg(GameconnPtr conn, int msgtype, String msg);
 	int flib_gameconn_send_chatmsg(GameconnPtr conn, String playername, String msg);
 	int flib_gameconn_send_quit(GameconnPtr conn);
+	int flib_gameconn_send_cmd(GameconnPtr conn, String cmdString);
 	
 	void flib_gameconn_onConnect(GameconnPtr conn, VoidCallback callback, Pointer context);
 	void flib_gameconn_onDisconnect(GameconnPtr conn, IntCallback callback, Pointer context);
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/MessageLog.java	Mon Aug 20 20:16:37 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/MessageLog.java	Mon Aug 20 20:19:35 2012 +0200
@@ -35,7 +35,7 @@
 	private static final int ERROR_COLOR = Color.RED;
 	
 	private final Context context;
-	private List<Observer> observers = new LinkedList<Observer>();
+	private List<Listener> observers = new LinkedList<Listener>();
 	private List<CharSequence> log = new LinkedList<CharSequence>();
 	
 	public MessageLog(Context context) {
@@ -70,12 +70,12 @@
 	private void appendRaw(CharSequence msg) {
 		if(log.size() > BACKLOG_LINES) {
 			log.remove(0);
-			for(Observer o : observers) {
+			for(Listener o : observers) {
 				o.lineRemoved();
 			}
 		}
 		log.add(msg);
-		for(Observer o : observers) {
+		for(Listener o : observers) {
 			o.lineAdded(msg);
 		}
 	}
@@ -113,7 +113,6 @@
 			append(withColor("***"+msg, WARN_COLOR));
 			break;
 		case Frontlib.NETCONN_MSG_TYPE_PLAYERINFO:
-			// TODO Display in popup?
 			append(withColor(msg.replace("\n", " "), PLAYERINFO_COLOR));
 			break;
 		case Frontlib.NETCONN_MSG_TYPE_SERVERMESSAGE:
@@ -125,21 +124,21 @@
 	}
 	
 	void clear() {
-		for(Observer o : observers) {
+		for(Listener o : observers) {
 			o.clear();
 		}
 		log.clear();
 	}
 	
-	public void registerObserver(Observer o) {
+	public void addListener(Listener o) {
 		observers.add(o);
 	}
 	
-	public void unregisterObserver(Observer o) {
+	public void removeListener(Listener o) {
 		observers.remove(o);
 	}
 	
-	public static interface Observer {
+	public static interface Listener {
 		void lineAdded(CharSequence text);
 		void lineRemoved();
 		void clear();
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/NetRoomState.java	Mon Aug 20 20:16:37 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/NetRoomState.java	Mon Aug 20 20:19:35 2012 +0200
@@ -1,202 +1,130 @@
 package org.hedgewars.hedgeroid.netplay;
 
-import static org.hedgewars.hedgeroid.netplay.ThreadedNetConnection.ToNetMsgType.MSG_SEND_GAMESTYLE;
-import static org.hedgewars.hedgeroid.netplay.ThreadedNetConnection.ToNetMsgType.MSG_SEND_MAP;
-import static org.hedgewars.hedgeroid.netplay.ThreadedNetConnection.ToNetMsgType.MSG_SEND_MAP_DRAWDATA;
-import static org.hedgewars.hedgeroid.netplay.ThreadedNetConnection.ToNetMsgType.MSG_SEND_MAP_GENERATOR;
-import static org.hedgewars.hedgeroid.netplay.ThreadedNetConnection.ToNetMsgType.MSG_SEND_MAP_NAME;
-import static org.hedgewars.hedgeroid.netplay.ThreadedNetConnection.ToNetMsgType.MSG_SEND_MAP_SEED;
-import static org.hedgewars.hedgeroid.netplay.ThreadedNetConnection.ToNetMsgType.MSG_SEND_MAP_TEMPLATE;
-import static org.hedgewars.hedgeroid.netplay.ThreadedNetConnection.ToNetMsgType.MSG_SEND_MAP_THEME;
-import static org.hedgewars.hedgeroid.netplay.ThreadedNetConnection.ToNetMsgType.MSG_SEND_MAZE_SIZE;
-import static org.hedgewars.hedgeroid.netplay.ThreadedNetConnection.ToNetMsgType.MSG_SEND_SCHEME;
-import static org.hedgewars.hedgeroid.netplay.ThreadedNetConnection.ToNetMsgType.MSG_SEND_WEAPONSET;
+import static org.hedgewars.hedgeroid.netplay.ThreadedNetConnection.ToNetMsgType.*;
+import static org.hedgewars.hedgeroid.util.ObjectUtils.equal;
 
 import java.util.Arrays;
-import java.util.LinkedList;
-import java.util.List;
+import java.util.Collections;
+import java.util.Map;
+import java.util.TreeMap;
 
-import org.hedgewars.hedgeroid.RoomStateManager;
+import org.hedgewars.hedgeroid.BasicRoomState;
 import org.hedgewars.hedgeroid.Datastructures.GameConfig;
 import org.hedgewars.hedgeroid.Datastructures.MapRecipe;
 import org.hedgewars.hedgeroid.Datastructures.Scheme;
+import org.hedgewars.hedgeroid.Datastructures.Team;
+import org.hedgewars.hedgeroid.Datastructures.TeamInGame;
+import org.hedgewars.hedgeroid.Datastructures.TeamIngameAttributes;
 import org.hedgewars.hedgeroid.Datastructures.Weaponset;
 import org.hedgewars.hedgeroid.netplay.ThreadedNetConnection.ToNetMsgType;
 
 /**
  * This class manages the room state in a network game.
  */
-class NetRoomState implements RoomStateManager {
-	private List<RoomStateManager.Observer> observers = new LinkedList<RoomStateManager.Observer>();
+class NetRoomState extends BasicRoomState {
+	final Map<String, TeamInGame> requestedTeams = new TreeMap<String, TeamInGame>();
 	private Netplay netplay;
 	
-	boolean chief;
-	String gameStyle;
-	Scheme scheme;
-	MapRecipe map;
-	Weaponset weaponset;
-	
 	public NetRoomState(Netplay netplay) {
 		this.netplay = netplay;
-		this.map = MapRecipe.makeRandomMap(0, "seed", GameConfig.DEFAULT_THEME);
-	}
-
-	public MapRecipe getMapRecipe() {
-		return map;
-	}
-
-	public boolean getChiefStatus() {
-		return chief;
-	}
-
-	public Scheme getScheme() {
-		return scheme;
-	}
-
-	public String getGameStyle() {
-		return gameStyle;
-	}
-
-	public Weaponset getWeaponset() {
-		return weaponset;
+		initRoomState(false);
 	}
 
 	public void changeWeaponset(Weaponset weaponset) {
-		if(chief && !weaponset.equals(this.weaponset)) {
+		if(getChiefStatus() && !equal(weaponset, getWeaponset())) {
 			sendToNet(MSG_SEND_WEAPONSET, weaponset);
 			setWeaponset(weaponset);
 		}
 	}
 	
 	public void changeMapRecipe(MapRecipe mapRecipe) {
-		if(chief && !mapRecipe.equals(this.map)) {
+		if(getChiefStatus() && !equal(mapRecipe, getMapRecipe())) {
 			sendToNet(MSG_SEND_MAP, mapRecipe);
 			setMapRecipe(mapRecipe);
 		}
 	}
 	
 	public void changeMapNameAndGenerator(String mapName) {
-		if(chief && !mapName.equals(this.map.name)) {
+		if(getChiefStatus() && !equal(mapName, getMapRecipe().name)) {
 			int newGenerator = MapRecipe.generatorForMapname(mapName);
-			if(newGenerator != this.map.mapgen) {
+			if(newGenerator != getMapRecipe().mapgen) {
 				sendToNet(MSG_SEND_MAP_GENERATOR, newGenerator, null);
 			}
 			sendToNet(MSG_SEND_MAP_NAME, mapName);
-			setMapRecipe(map.withName(mapName).withMapgen(newGenerator));
+			setMapRecipe(getMapRecipe().withName(mapName).withMapgen(newGenerator));
 		}
 	}
 	
 	public void changeMapTemplate(int template) {
-		if(chief && template != this.map.templateFilter) {
+		if(getChiefStatus() && template != getMapRecipe().templateFilter) {
 			sendToNet(MSG_SEND_MAP_TEMPLATE, template, null);
-			setMapRecipe(map.withTemplateFilter(template));
+			setMapRecipe(getMapRecipe().withTemplateFilter(template));
 		}
 	}
 	
 	public void changeMazeSize(int mazeSize) {
-		if(chief && mazeSize != this.map.mazeSize) {
+		if(getChiefStatus() && mazeSize != getMapRecipe().mazeSize) {
 			sendToNet(MSG_SEND_MAZE_SIZE, mazeSize, 0);
-			setMapRecipe(map.withMazeSize(mazeSize));
+			setMapRecipe(getMapRecipe().withMazeSize(mazeSize));
 		}
 	}
 	
 	public void changeMapSeed(String seed) {
-		if(chief && !seed.equals(this.map.seed)) {
+		if(getChiefStatus() && !equal(seed, getMapRecipe().seed)) {
 			sendToNet(MSG_SEND_MAP_SEED, seed);
-			setMapRecipe(map.withSeed(seed));
+			setMapRecipe(getMapRecipe().withSeed(seed));
 		}
 	}
 	
 	public void changeMapTheme(String theme) {
-		if(chief && !theme.equals(this.map.theme)) {
+		if(getChiefStatus() && !equal(theme, getMapRecipe().theme)) {
 			sendToNet(MSG_SEND_MAP_THEME, theme);
-			setMapRecipe(map.withTheme(theme));
+			setMapRecipe(getMapRecipe().withTheme(theme));
 		}
 	}
 	
 	public void changeMapDrawdata(byte[] drawdata) {
-		if(chief && !Arrays.equals(drawdata, this.map.getDrawData())) {
+		if(getChiefStatus() && !Arrays.equals(drawdata, getMapRecipe().getDrawData())) {
 			sendToNet(MSG_SEND_MAP_DRAWDATA, drawdata);
-			setMapRecipe(map.withDrawData(drawdata));
+			setMapRecipe(getMapRecipe().withDrawData(drawdata));
 		}
 	}
 	
 	public void changeGameStyle(String gameStyle) {
-		if(chief && !gameStyle.equals(this.gameStyle)) {
+		if(getChiefStatus() && !equal(gameStyle, getGameStyle())) {
 			sendToNet(MSG_SEND_GAMESTYLE, gameStyle);
 			setGameStyle(gameStyle);
 		}
 	}
 	
 	public void changeScheme(Scheme scheme) {
-		if(chief && !scheme.equals(this.scheme)) {
+		if(getChiefStatus() && !equal(scheme, getScheme())) {
 			sendToNet(MSG_SEND_SCHEME, scheme);
 			setScheme(scheme);
 		}
 	}
 	
-	void setWeaponset(Weaponset weaponset) {
-		if(!weaponset.equals(this.weaponset)) {
-			this.weaponset = weaponset;
-			for(RoomStateManager.Observer observer : observers) {
-				observer.onWeaponsetChanged(weaponset);
-			}
-		}
-	}
-	
-	void setMapRecipe(MapRecipe map) {
-		if(!map.equals(this.map)) { 
-			this.map = map;
-			for(RoomStateManager.Observer observer : observers) {
-				observer.onMapChanged(map);
-			}
-		}
-	}
-	
-	void setGameStyle(String gameStyle) {
-		if(!gameStyle.equals(this.gameStyle)) {
-			this.gameStyle = gameStyle;
-			for(RoomStateManager.Observer observer : observers) {
-				observer.onGameStyleChanged(gameStyle);
-			}
-		}
-	}
-	
-	void setScheme(Scheme scheme) {
-		if(!scheme.equals(this.scheme)) {
-			this.scheme = scheme;
-			for(RoomStateManager.Observer observer : observers) {
-				observer.onSchemeChanged(scheme);
-			}
-		}
-	}
-	
-	void setChief(boolean chief) {
-		if(chief != this.chief) {
-			this.chief = chief;
-			for(RoomStateManager.Observer observer : observers) {
-				observer.onChiefStatusChanged(chief);
-			}
-		}
+	void initRoomState(boolean chief) {
+		setTeams(Collections.<String, TeamInGame>emptyMap());
+		requestedTeams.clear();
+		
+		setChief(chief);
+		setGameStyle(GameConfig.DEFAULT_STYLE);
+		setMapRecipe(MapRecipe.makeRandomMap(0, "seed", GameConfig.DEFAULT_THEME));
+		setScheme(netplay.defaultScheme);
+		setWeaponset(netplay.defaultWeaponset);
+		sendFullConfig();
 	}
 	
 	void sendFullConfig() {
-		if(chief) {
-			sendToNet(MSG_SEND_GAMESTYLE, gameStyle);
-			sendToNet(MSG_SEND_SCHEME, scheme);
-			sendToNet(MSG_SEND_WEAPONSET, weaponset);
-			sendToNet(MSG_SEND_MAP, map);
+		if(getChiefStatus()) {
+			sendToNet(MSG_SEND_GAMESTYLE, getGameStyle());
+			sendToNet(MSG_SEND_SCHEME, getScheme());
+			sendToNet(MSG_SEND_WEAPONSET, getWeaponset());
+			sendToNet(MSG_SEND_MAP, getMapRecipe());
 		}
 	}
 	
-	public void registerObserver(Observer observer) {
-		observers.add(observer);
-	}
-
-	public void unregisterObserver(Observer observer) {
-		observers.remove(observer);
-	}
-	
 	private boolean sendToNet(ToNetMsgType what, Object obj) {
 		return netplay.sendToNet(what, 0, obj);
 	}
@@ -204,4 +132,35 @@
 	private boolean sendToNet(ToNetMsgType what, int arg1, Object obj) {
 		return netplay.sendToNet(what, arg1, obj);
 	}
+
+	public void requestAddTeam(Team team, int colorIndex) {
+		TeamIngameAttributes tia = new TeamIngameAttributes(netplay.getPlayerName(), colorIndex, TeamIngameAttributes.DEFAULT_HOG_COUNT, false);
+		TeamInGame newTeamInGame = new TeamInGame(team, tia);
+		requestedTeams.put(team.name, newTeamInGame);
+		sendToNet(MSG_SEND_ADD_TEAM, newTeamInGame);
+	}
+
+	public void requestRemoveTeam(String teamname) {
+		sendToNet(MSG_SEND_REMOVE_TEAM, teamname);
+	}
+
+	public void changeTeamColorIndex(String teamname, int colorIndex) {
+		if(getChiefStatus()) {
+			TeamInGame team = getTeams().get(teamname);
+			if(team.ingameAttribs.colorIndex != colorIndex) {
+				sendToNet(MSG_SEND_TEAM_COLOR_INDEX, colorIndex, teamname);
+				putTeam(team.withAttribs(team.ingameAttribs.withColorIndex(colorIndex)));
+			}
+		}
+	}
+
+	public void changeTeamHogCount(String teamname, int hogcount) {
+		if(getChiefStatus()) {
+			TeamInGame team = getTeams().get(teamname);
+			if(team.ingameAttribs.hogCount != hogcount) {
+				sendToNet(MSG_SEND_TEAM_HOG_COUNT, hogcount, teamname);
+				putTeam(team.withAttribs(team.ingameAttribs.withHogCount(hogcount)));
+			}
+		}
+	}
 }
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/Netplay.java	Mon Aug 20 20:16:37 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/Netplay.java	Mon Aug 20 20:19:35 2012 +0200
@@ -7,8 +7,6 @@
 import java.util.Collections;
 import java.util.LinkedList;
 import java.util.List;
-import java.util.Map;
-import java.util.TreeMap;
 
 import org.hedgewars.hedgeroid.RoomStateManager;
 import org.hedgewars.hedgeroid.Datastructures.GameConfig;
@@ -18,7 +16,6 @@
 import org.hedgewars.hedgeroid.Datastructures.Room;
 import org.hedgewars.hedgeroid.Datastructures.Scheme;
 import org.hedgewars.hedgeroid.Datastructures.Schemes;
-import org.hedgewars.hedgeroid.Datastructures.Team;
 import org.hedgewars.hedgeroid.Datastructures.TeamInGame;
 import org.hedgewars.hedgeroid.Datastructures.TeamIngameAttributes;
 import org.hedgewars.hedgeroid.Datastructures.Weaponset;
@@ -42,7 +39,7 @@
  * This class manages the application's networking state.
  */
 public class Netplay {
-	public static enum State { NOT_CONNECTED, CONNECTING, LOBBY, ROOM, INGAME }
+	public static enum State { NOT_CONNECTED, CONNECTING, LOBBY, ROOM }
 	
 	// Extras in broadcasts
 	public static final String EXTRA_PLAYERNAME = "playerName";
@@ -64,6 +61,8 @@
 	private final Context appContext;
 	private final LocalBroadcastManager broadcastManager;
 	private final FromNetHandler fromNetHandler = new FromNetHandler();
+	public final Scheme defaultScheme;
+	public final Weaponset defaultWeaponset;
 	
 	private State state = State.NOT_CONNECTED;
 	private String playerName;
@@ -79,17 +78,17 @@
 	public final Roomlist roomList = new Roomlist();
 	public final MessageLog lobbyChatlog;
 	public final MessageLog roomChatlog;
-	public final ObservableTreeMap<String, TeamInGame> roomTeamlist = new ObservableTreeMap<String, TeamInGame>();
-	private final Map<String, TeamInGame> roomRequestedTeams = new TreeMap<String, TeamInGame>();
 	
 	private final List<GameMessageListener> gameMessageListeners = new LinkedList<GameMessageListener>();
 	private final List<RunGameListener> runGameListeners = new LinkedList<RunGameListener>();
 	
-	public Netplay(Context appContext) {
+	public Netplay(Context appContext, Scheme defaultScheme, Weaponset defaultWeaponset) {
 		this.appContext = appContext;
 		broadcastManager = LocalBroadcastManager.getInstance(appContext);
 		lobbyChatlog = new MessageLog(appContext);
 		roomChatlog = new MessageLog(appContext);
+		this.defaultScheme = defaultScheme;
+		this.defaultWeaponset = defaultWeaponset;
 	}
 	
 	public RoomStateManager getRoomStateManager() {
@@ -105,21 +104,7 @@
 	private void initRoomState(boolean chief) {
 		roomChatlog.clear();
 		roomPlayerlist.clear();
-		roomTeamlist.clear();
-		roomRequestedTeams.clear();
-		
-		try {
-			netRoomState.setChief(chief);
-			netRoomState.setGameStyle(GameConfig.DEFAULT_STYLE);
-			List<Scheme> schemes = Schemes.loadBuiltinSchemes(appContext);
-			netRoomState.setScheme(schemes.get(Schemes.toNameList(schemes).indexOf(GameConfig.DEFAULT_SCHEME)));
-			netRoomState.setMapRecipe(MapRecipe.makeRandomMap(0, MapRecipe.makeRandomSeed(), GameConfig.DEFAULT_THEME));
-			List<Weaponset> weaponsets = Weaponsets.loadBuiltinWeaponsets(appContext);
-			netRoomState.setWeaponset(weaponsets.get(Weaponsets.toNameList(weaponsets).indexOf(GameConfig.DEFAULT_WEAPONSET)));
-			netRoomState.sendFullConfig();
-		} catch(IOException e) {
-			throw new RuntimeException(e);
-		}
+		netRoomState.initRoomState(chief);
 	}
 	
 	public void registerGameMessageListener(GameMessageListener listener) {
@@ -176,30 +161,10 @@
 	public void sendCreateRoom(String name) { sendToNet(MSG_SEND_CREATE_ROOM, name); }
 	public void sendLeaveRoom(String message) { sendToNet(MSG_SEND_LEAVE_ROOM, message); }
 	public void sendKick(String player) { sendToNet(MSG_SEND_KICK, player); }
-	public void sendAddTeam(Team newTeam, int colorIndex) {
-		TeamIngameAttributes tia = new TeamIngameAttributes(playerName, colorIndex, TeamIngameAttributes.DEFAULT_HOG_COUNT, false);
-		TeamInGame newTeamInGame = new TeamInGame(newTeam, tia);
-		roomRequestedTeams.put(newTeam.name, newTeamInGame);
-		sendToNet(MSG_SEND_ADD_TEAM, newTeamInGame);
-	}
-	public void sendRemoveTeam(String teamName) { sendToNet(MSG_SEND_REMOVE_TEAM, teamName); }
-	public void changeTeamColorIndex(String teamName, int colorIndex) {
-		if(isChief()) {
-			sendToNet(MSG_SEND_TEAM_COLOR_INDEX, colorIndex, teamName);
-			TeamInGame team = roomTeamlist.get(teamName);
-			roomTeamlist.put(teamName, team.withAttribs(team.ingameAttribs.withColorIndex(colorIndex)));
-		}
-	}
-	public void changeTeamHogCount(String teamName, int hogCount) {
-		if(isChief()) {
-			sendToNet(MSG_SEND_TEAM_HOG_COUNT, hogCount, teamName);
-			TeamInGame team = roomTeamlist.get(teamName);
-			roomTeamlist.put(teamName, team.withAttribs(team.ingameAttribs.withHogCount(hogCount)));
-		}
-	}
 	public void sendEngineMessage(byte[] engineMessage) { sendToNet(MSG_SEND_ENGINE_MESSAGE, engineMessage); }
 	public void sendRoundFinished(boolean withoutError) { sendToNet(MSG_SEND_ROUND_FINISHED, Boolean.valueOf(withoutError)); }
 	public void sendToggleReady() { sendToNet(MSG_SEND_TOGGLE_READY); }
+	public void sendStartGame() { sendToNet(MSG_SEND_START_GAME); }
 	
 	public void disconnect() { sendToNet(MSG_DISCONNECT, "User Quit"); }
 	
@@ -218,7 +183,32 @@
 			if(Flib.INSTANCE.flib_init() != 0) {
 				throw new RuntimeException("Unable to start frontlib");
 			}
-			instance = new Netplay(applicationContext);
+			
+			// We will need some default values for rooms, best load them here
+			Scheme defaultScheme = null;
+			Weaponset defaultWeaponset = null;
+			try {
+				List<Scheme> schemes = Schemes.loadBuiltinSchemes(applicationContext);
+				for(Scheme scheme : schemes) {
+					if(scheme.name.equals(GameConfig.DEFAULT_SCHEME)) {
+						defaultScheme = scheme;
+					}
+				}
+				List<Weaponset> weaponsets = Weaponsets.loadBuiltinWeaponsets(applicationContext);
+				for(Weaponset weaponset : weaponsets) {
+					if(weaponset.name.equals(GameConfig.DEFAULT_WEAPONSET)) {
+						defaultWeaponset = weaponset;
+					}
+				}
+			} catch(IOException e) {
+				throw new RuntimeException(e);
+			}
+			
+			if(defaultScheme==null || defaultWeaponset==null) {
+				throw new RuntimeException("Unable to load default scheme or weaponset");
+			}
+			
+			instance = new Netplay(applicationContext, defaultScheme, defaultWeaponset);
 		}
 		return instance;
 	}
@@ -236,7 +226,7 @@
 	
 	public boolean isChief() {
 		if(netRoomState != null) {
-			return netRoomState.chief;
+			return netRoomState.getChiefStatus();
 		} else {
 			return false;
 		}
@@ -264,7 +254,7 @@
 	}
 	
 	private MessageLog getCurrentLog() {
-		if(state == State.ROOM || state == State.INGAME) {
+		if(state == State.ROOM) {
 			return roomChatlog;
 		} else {
 			return lobbyChatlog;
@@ -435,22 +425,22 @@
 			case MSG_TEAM_ADDED: {
 				TeamInGame newTeam = (TeamInGame)msg.obj;
 				if(isChief()) {
-					int freeColor = TeamInGame.getUnusedOrRandomColorIndex(roomTeamlist.getMap().values());
+					int freeColor = TeamInGame.getUnusedOrRandomColorIndex(netRoomState.getTeams().values());
 					sendToNet(MSG_SEND_TEAM_HOG_COUNT, newTeam.ingameAttribs.hogCount, newTeam.team.name);
 					sendToNet(MSG_SEND_TEAM_COLOR_INDEX, freeColor, newTeam.team.name);
 					newTeam = newTeam.withAttribs(newTeam.ingameAttribs.withColorIndex(freeColor));
 				}
-				roomTeamlist.put(newTeam.team.name, newTeam);
+				netRoomState.putTeam(newTeam);
 				break;
 			}
 			case MSG_TEAM_DELETED: {
-				roomTeamlist.remove((String)msg.obj);
+				netRoomState.removeTeam((String)msg.obj);
 				break;
 			}
 			case MSG_TEAM_ACCEPTED: {
-				TeamInGame requestedTeam = roomRequestedTeams.remove(msg.obj);
+				TeamInGame requestedTeam = netRoomState.requestedTeams.remove(msg.obj);
 				if(requestedTeam!=null) {
-					roomTeamlist.put(requestedTeam.team.name, requestedTeam);
+					netRoomState.putTeam(requestedTeam);
 					if(isChief()) {
 						// Not strictly necessary, but QtFrontend does it...
 						sendToNet(MSG_SEND_TEAM_HOG_COUNT, requestedTeam.ingameAttribs.hogCount, requestedTeam.team.name);
@@ -461,7 +451,7 @@
 				break;
 			}
 			case MSG_TEAM_COLOR_CHANGED: {
-				TeamInGame oldEntry = roomTeamlist.get((String)msg.obj);
+				TeamInGame oldEntry = netRoomState.getTeams().get((String)msg.obj);
 				if(oldEntry != null) {
 					/*
 					 * If we are chief, we ignore colors from the outside. They only come from the server
@@ -471,7 +461,7 @@
 					 */
 					if(!isChief()) {
 						TeamIngameAttributes newAttribs = oldEntry.ingameAttribs.withColorIndex(msg.arg1);
-						roomTeamlist.put(oldEntry.team.name, oldEntry.withAttribs(newAttribs));
+						netRoomState.putTeam(oldEntry.withAttribs(newAttribs));
 					}
 				} else {
 					Log.e("Netplay", "Color update for unknown team "+msg.obj);
@@ -479,10 +469,10 @@
 				break;
 			}
 			case MSG_HOG_COUNT_CHANGED: {
-				TeamInGame oldEntry = roomTeamlist.get((String)msg.obj);
+				TeamInGame oldEntry = netRoomState.getTeams().get((String)msg.obj);
 				if(oldEntry != null) {
 					TeamIngameAttributes newAttribs = oldEntry.ingameAttribs.withHogCount(msg.arg1);
-					roomTeamlist.put(oldEntry.team.name, oldEntry.withAttribs(newAttribs));
+					netRoomState.putTeam(oldEntry.withAttribs(newAttribs));
 				} else {
 					Log.e("Netplay", "Hog count update for unknown team "+msg.obj);
 				}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/ThreadedNetConnection.java	Mon Aug 20 20:16:37 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/ThreadedNetConnection.java	Mon Aug 20 20:19:35 2012 +0200
@@ -110,7 +110,7 @@
 				}
 
 				//FLIB.flib_netconn_onAdminAccess(conn, adminAccessCb, null)
-				FLIB.flib_netconn_onCfgScheme(conn, cfgSchemeCb, null);
+				FLIB.flib_netconn_onSchemeChanged(conn, cfgSchemeCb, null);
 				FLIB.flib_netconn_onChat(conn, chatCb, null);
 				FLIB.flib_netconn_onConnected(conn, connectedCb, null);
 				FLIB.flib_netconn_onDisconnected(conn, disconnectCb, null);
@@ -387,6 +387,7 @@
 		MSG_SEND_ENGINE_MESSAGE,
 		MSG_SEND_ROUND_FINISHED,
 		MSG_SEND_TOGGLE_READY,
+		MSG_SEND_START_GAME,
 		MSG_SEND_WEAPONSET,
 		MSG_SEND_MAP,
 		MSG_SEND_MAP_NAME,
@@ -505,6 +506,10 @@
 				FLIB.flib_netconn_send_toggleReady(conn);
 				break;
 			}
+			case MSG_SEND_START_GAME: {
+				FLIB.flib_netconn_send_startGame(conn);
+				break;
+			}
 			case MSG_SEND_WEAPONSET: {
 				FLIB.flib_netconn_send_weaponset(conn, WeaponsetPtr.createJavaOwned((Weaponset)msg.obj));
 				break;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/util/ObjectUtils.java	Mon Aug 20 20:19:35 2012 +0200
@@ -0,0 +1,13 @@
+package org.hedgewars.hedgeroid.util;
+
+public final class ObjectUtils {
+	public static boolean equal(Object o1, Object o2) {
+		if(o1==o2) {
+			return true;
+		} else if(o1==null || o2 == null) {
+			return false;
+		} else {
+			return o1.equals(o2);
+		}
+	}
+}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/util/TextInputDialog.java	Mon Aug 20 20:16:37 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/util/TextInputDialog.java	Mon Aug 20 20:19:35 2012 +0200
@@ -98,6 +98,7 @@
 		editText.setOnEditorActionListener(new OnEditorActionListener() {
 			public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
 				listener.onTextInputDialogSubmitted(dialogId, v.getText().toString());
+				dismiss();
 				return true;
 			}
 		});
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/util/UiUtils.java	Mon Aug 20 20:19:35 2012 +0200
@@ -0,0 +1,34 @@
+package org.hedgewars.hedgeroid.util;
+
+import org.hedgewars.hedgeroid.R;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.TabHost;
+import android.widget.TextView;
+
+public final class UiUtils {
+	private UiUtils() {
+		throw new AssertionError("This class is not meant to be instantiated");
+	}
+
+	public static View createTabIndicator(TabHost tabHost, int label, int icon) {
+		LayoutInflater inflater = (LayoutInflater) tabHost.getContext()
+				.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+		View view = inflater.inflate(R.layout.tab_indicator_vertical,
+				tabHost.getTabWidget(), false);
+
+		final TextView tv = (TextView) view.findViewById(R.id.title);
+		tv.setText(label);
+
+		if (icon != 0) {
+			ImageView iconView = (ImageView) view.findViewById(R.id.icon);
+			iconView.setImageResource(icon);
+		}
+
+		return view;
+	}
+}