diff --git a/lib/netplay/netlog.c b/lib/netplay/netlog.c
index 05b74eb..c184ee7 100644
--- a/lib/netplay/netlog.c
+++ b/lib/netplay/netlog.c
@@ -177,11 +177,6 @@ BOOL NETlogEntry(const char *str,UDWORD a,UDWORD b)
 	struct tm *newtime;
 	char buf[256];
 
-	if (!pFileHandle)
-	{
-		return false;
-	}
-
 #ifndef MASSIVELOGS
 	if(a ==9 || a==10)
 	{
diff --git a/src/cheat.c b/src/cheat.c
index 73e512a..7849907 100644
--- a/src/cheat.c
+++ b/src/cheat.c
@@ -75,7 +75,6 @@ static CHEAT_ENTRY cheatCodes[] =
 	{"tileinfo", kf_TileInfo}, // output debug info about a tile
 	{"showfps", kf_ToggleFPS},	//displays your average FPS
 	{"showsamples", kf_ToggleSamples}, //displays the # of Sound samples in Queue & List
-	{"showorders", kf_ToggleOrders}, //displays unit order/action state.
 };
 
 BOOL attemptCheatCode(const char* cheat_name)
diff --git a/src/combat.c b/src/combat.c
index ff2ee74..5235c48 100644
--- a/src/combat.c
+++ b/src/combat.c
@@ -344,13 +344,28 @@ void combFire(WEAPON *psWeap, BASE_OBJECT *psAttacker, BASE_OBJECT *psTarget, in
 			double flightTime;
 			SDWORD empTime = 0;
 
-			if (proj_Direct(psStats) || dist <= psStats->minRange)
+			if (proj_Direct(psStats) || dist <= psStats->minRange || dist <= TILE_UNITS*3)
 			{
 				flightTime = dist / psStats->flightSpeed;
 			}
 			else
 			{
-				flightTime = sqrt(dist) / 30;  /* Purely a guess, but surprisingly effective */
+				/* Copied out of proj_SendProjectile.  Simplified slightly. */
+				SDWORD dz = psTarget->pos.z - psAttacker->pos.z;
+				SDWORD iRadSq = distSquared + dz*dz;
+				SDWORD iVelSq = psStats->flightSpeed * psStats->flightSpeed;
+				double fA = ACC_GRAVITY * (double)iRadSq / (2.0 * iVelSq);
+				double fC = 4.0 * fA * (dz + fA);
+				double fS = (double)iRadSq - fC;
+
+				if (fS < 0.0)
+				{
+					flightTime = sqrt(dist) / 30;  /* Purely a guess, but surprisingly effective */
+				}
+				else
+				{
+					flightTime = dist / psStats->flightSpeed;
+				}
 			}
 
 			if (psTarget->lastHitWeapon == WSC_EMP)
diff --git a/src/display.c b/src/display.c
index 3dd146b..8dbfd71 100644
--- a/src/display.c
+++ b/src/display.c
@@ -84,8 +84,6 @@ struct	_dragBox dragBox3D,wallDrag;
 #define POSSIBLE_SELECTIONS		13
 #define POSSIBLE_TARGETS		23
 
-extern char DROIDDOING[512];		// holds the string on what the droid is doing
-
 UDWORD	arnMPointers[POSSIBLE_TARGETS][POSSIBLE_SELECTIONS] =
 {
 // empty terrain tile
@@ -1686,7 +1684,6 @@ static inline void dealWithLMBDroid(DROID* psDroid, SELECTION_TYPE selection)
 {
 	if (psDroid->player != selectedPlayer)
 	{
-		memset(DROIDDOING, 0x0 , sizeof(DROIDDOING)); // take over the other players droid by debug menu.
 		/* We've clicked on somebody else's droid */
 //		addConsoleMessage("Clicked on another player's droid",SYSTEM_MESSAGE);
 		orderSelectedObjAdd(selectedPlayer, (BASE_OBJECT*)psDroid, ctrlShiftDown());
@@ -2677,7 +2674,6 @@ static void dealWithRMB( void )
 			{
 				clearSelection();
 				intObjectSelected(NULL);
-				memset(DROIDDOING, 0x0 , sizeof(DROIDDOING));	// clear string when deselected
 			}
 		}
 	}
diff --git a/src/display3d.c b/src/display3d.c
index aeb3820..00ba6ec 100644
--- a/src/display3d.c
+++ b/src/display3d.c
@@ -208,10 +208,6 @@ bool showFPS = false;       //
  * default OFF, turn ON via console command 'showsamples'
  */
 bool showSAMPLES = false;
-/**  Show the current selected units order / action
- *  default OFF, turn ON via console command 'showorders'
- */
-bool showORDERS = false;	
 /** When we have a connection issue, we will flash a message on screen
 * 0 = no issue, 1= player leaving nicely, 2= player got disconnected
 */
@@ -219,10 +215,6 @@ int NET_PlayerConnectionStatus = 0;
 #define NETWORK_FORM_ID 0xFAAA
 #define NETWORK_BUT_ID 0xFAAB
 
-/** tells us in realtime, what droid is doing (order / action)
-*/
-char DROIDDOING[512];
-
 /// Geometric offset which will be passed to pie_SetGeometricOffset
 UDWORD geoOffset;
 /// The average terrain height for the center of the area the camera is looking at
@@ -456,14 +448,6 @@ void draw3DScene( void )
 
 		iV_DrawText(fps, pie_GetVideoBufferWidth() - width, pie_GetVideoBufferHeight() - height);
 	}
-	if (showORDERS)
-	{
-		unsigned int width, height;
-		width = iV_GetTextWidth(DROIDDOING);
-		height = iV_GetTextHeight(DROIDDOING);
-		iV_DrawText(DROIDDOING, 0, pie_GetVideoBufferHeight()- height);
-	}
-
 //	debug(LOG_ERROR,"%d NET_PlayerConnectionStatus",NET_PlayerConnectionStatus);
 	if (NET_PlayerConnectionStatus)
 	{
diff --git a/src/display3d.h b/src/display3d.h
index 50122ae..90042bd 100644
--- a/src/display3d.h
+++ b/src/display3d.h
@@ -50,7 +50,6 @@ typedef enum
 
 extern bool showFPS;
 extern bool showSAMPLES;
-extern bool showORDERS;
 
 extern void	setViewAngle(SDWORD angle);
 extern UDWORD getViewDistance(void);
diff --git a/src/keybind.c b/src/keybind.c
index 04e3d04..42f2b86 100644
--- a/src/keybind.c
+++ b/src/keybind.c
@@ -409,19 +409,11 @@ void kf_ToggleFPS(void) //This shows *just FPS* and is always visable (when acti
 }
 void kf_ToggleSamples(void) //Displays number of sound sample in the sound queues & lists.
 {
-	// Toggle the boolean value of showSAMPLES
+	// Toggle the boolean value of showFPS
 	showSAMPLES = !showSAMPLES;
 
 	CONPRINTF(ConsoleString, (ConsoleString, "Sound Samples displayed is %s", showSAMPLES ? "Enabled" : "Disabled"));
 }
-
-void kf_ToggleOrders(void)	// Displays orders & action of currently selected unit.
-{
-		// Toggle the boolean value of showORDERS
-		showORDERS = !showORDERS;
-		CONPRINTF(ConsoleString, (ConsoleString, "Unit Order/Action displayed is %s", showORDERS ? "Enabled" : "Disabled"));
-}
-
 /* Writes out the frame rate */
 void	kf_FrameRate( void )
 {
diff --git a/src/keybind.h b/src/keybind.h
index a259bb4..143ba57 100644
--- a/src/keybind.h
+++ b/src/keybind.h
@@ -28,9 +28,8 @@
 extern void	kf_HalveHeights( void );
 extern void	kf_DebugDroidInfo( void );
 extern void	kf_BuildInfo( void );
-extern void	kf_ToggleFPS(void);			//FPS counter NOT same as kf_Framerate! -Q
-extern void	kf_ToggleSamples(void);		// Displays # of sound samples in Queue/list.
-extern void kf_ToggleOrders(void);		//displays unit's Order/action state.
+extern void	kf_ToggleFPS(void);		//FPS counter NOT same as kf_Framerate! -Q
+extern void	kf_ToggleSamples(void);		// Displays # of sound samples in Q/list.
 extern void	kf_FrameRate( void );
 extern void	kf_ShowNumObjects( void );
 extern void	kf_ToggleRadar( void );
diff --git a/src/order.c b/src/order.c
index 6545b9d..09c0470 100644
--- a/src/order.c
+++ b/src/order.c
@@ -103,8 +103,7 @@ static UDWORD orderStarted;
 
 // whether an order effect has been displayed
 static BOOL bOrderEffectDisplayed = false;
-// what the droid's action / order is currently
-extern char DROIDDOING[512];
+
 //////////////////////////////////////////////////////////////////
 
 //////////////////////////////////////////////////////////////////
@@ -1256,13 +1255,6 @@ void orderUpdateDroid(DROID *psDroid)
 		psDroid->order = DORDER_REARM;
 		setDroidTarget(psDroid, psDroid->psActionTarget[0]);
 	}
-
-	if(psDroid->selected)
-	{
-		// Tell us what the droid is doing.
-		sprintf(DROIDDOING,"%.12s,id(%d) order(%d):%s action(%d):%s", droidGetName(psDroid), psDroid->id,
-			psDroid->order, getDroidOrderName(psDroid->order), psDroid->action, getDroidActionName(psDroid->action));
-	}
 }
 
 
diff --git a/src/power.c b/src/power.c
index 2d4ce10..fcb030b 100644
--- a/src/power.c
+++ b/src/power.c
@@ -434,15 +434,13 @@ int requestPowerFor(int player, float amount, int points)
 {
 	int pointsConsidered = randomRound(points * asPower[player].economyThrottle);
 	// only what it needs for the n amount of points we consider giving
-	float amountConsidered;
+	float amountConsidered = amount * (float) pointsConsidered / points;
 
-	if (points == 0 || amount < 0.01 || !powerCalculated)
+	if (amount < 0.01 || !powerCalculated)
 	{
 		return points;
 	}
 
-	amountConsidered = amount * (float) pointsConsidered / points;
-
 	// keep track on how much energy we could possibly spend
 	asPower[player].powerRequested += amount;
 	ASSERT(asPower[player].powerRequested < 1000, "you are asking too much");
diff --git a/src/projectile.c b/src/projectile.c
index edd4296..694cb5c 100644
--- a/src/projectile.c
+++ b/src/projectile.c
@@ -61,7 +61,6 @@
 #include "mapgrid.h"
 
 #define	PROJ_MAX_PITCH			30
-#define	ACC_GRAVITY				1000
 #define	DIRECT_PROJ_SPEED		500
 #define VTOL_HITBOX_MODIFICATOR 100
 
@@ -434,6 +433,8 @@ BOOL proj_SendProjectile(WEAPON *psWeap, BASE_OBJECT *psAttacker, int player, Ve
 	iRadSq = dx*dx + dy*dy + dz*dz;
 	fR = trigIntSqrt( iRadSq );
 	iMinSq = psStats->minRange * psStats->minRange;
+	if (psStats->minRange < TILE_UNITS*3)  /* Switch to direct fire rather than use very high angles */
+		iMinSq = TILE_UNITS*3 * TILE_UNITS*3;
 
 	if ( proj_Direct(psStats) ||
 		( !proj_Direct(psStats) && (iRadSq <= iMinSq) ) )
@@ -918,6 +919,11 @@ static void proj_InFlightIndirectFunc(PROJECTILE *psProj)
 				psProj->startY + (distanceRatio * move.y),
 				psProj->srcHeight + move.z
 			};
+			if (nextPos.z > UWORD_MAX / 2)  /* Assume it wrapped around */
+			{
+				/* XXX FIXME Unfortunately, this usually occurs because we skipped past our target. */
+				nextPos.z = 0;
+			}
 
 			/* impact if about to go off map else update coordinates */
 			if (!worldOnMap(nextPos.x, nextPos.y))
diff --git a/src/projectile.h b/src/projectile.h
index 32636f8..2661200 100644
--- a/src/projectile.h
+++ b/src/projectile.h
@@ -42,6 +42,7 @@ extern	BASE_OBJECT	*g_pProjLastAttacker;	///< The last unit that did damage - us
 #define BURNING		0x02	///< Whether an object has just left the fire, but is still burning.
 #define BURN_TIME	10000	///< How long an object burns for after leaving a fire.
 #define BURN_DAMAGE	15	///< How much damaga a second an object takes when it is burning.
+#define ACC_GRAVITY	1000	///< Downward force against projectiles.
 
 /** How long to display a single electronic warfare shimmmer. */
 #define ELEC_DAMAGE_DURATION    (GAME_TICKS_PER_SEC/5)
diff --git a/src/structure.c b/src/structure.c
index a540762..6b1880e 100644
--- a/src/structure.c
+++ b/src/structure.c
@@ -370,7 +370,7 @@ static STRUCTURE_TYPE structureType(const char* typeName)
 	ASSERT(!"unknown structure type", "Unknown Structure Type (%s)", typeName);
 
 	// Dummy value to prevent warnings about missing return from function
-	return NUM_DIFF_BUILDINGS;
+	return 0;
 }
 
 
@@ -645,19 +645,33 @@ BOOL loadStructureStats(const char *pStructData, UDWORD bufferSize)
 				pSensorType++;
 			}
 			//check not allocating a turret sensor if have weapons attached
-			ASSERT_OR_RETURN(false, psStructure->pSensor != NULL, "Should have a sensor attached to %s!", StructureName);
-			ASSERT_OR_RETURN(false, !(numWeaps && psStructure->pSensor->location == LOC_TURRET),
-			                 "Both turret sensor and weapon have been assigned to %s", StructureName);
+			ASSERT( psStructure->pSensor != NULL,
+				"loadStructureStats: should have a sensor attached to %s!", StructureName );
+			if (psStructure->pSensor->location == LOC_TURRET && numWeaps)
+			{
+				debug(LOG_ERROR, "a Turret Sensor and weapon have been assigned to %s", StructureName);
+				abort();
+			}
 		}
 
 		//get the IMD for the structure
 		psStructure->pIMD = (iIMDShape *) resGetData("IMD", GfxFile);
-		ASSERT_OR_RETURN(false, psStructure->pIMD != NULL, "Cannot find the structure PIE for record %s", getStructName(psStructure));
+		if (psStructure->pIMD == NULL)
+		{
+			debug( LOG_ERROR, "Cannot find the structure PIE for record %s", getStructName(psStructure) );
+			abort();
+			return false;
+		}
 
 		if (strcmp(baseIMD, "0"))
 		{
 			psStructure->pBaseIMD = (iIMDShape *) resGetData("IMD", baseIMD);
-			ASSERT_OR_RETURN(false, psStructure->pIMD != NULL, "Cannot find the structure base PIE for record %s", getStructName(psStructure));
+			if (psStructure->pIMD == NULL)
+			{
+				debug( LOG_ERROR, "Cannot find the structure base PIE for record %s", getStructName(psStructure) );
+				abort();
+				return false;
+			}
 		}
 		else
 		{
@@ -787,8 +801,11 @@ void setCurrentStructQuantity(BOOL displayError)
 			if (displayError)
 			{
 				//check quantity never exceeds the limit
-				ASSERT(psStructLimits[inc].currentQuantity <= psStructLimits[inc].limit,
-				       "There appears to be too many %s on this map!", getStructName(&asStructureStats[inc]));
+				if (psStructLimits[inc].currentQuantity > psStructLimits[inc].limit)
+				{
+					ASSERT( false, "There appears to be too many %s on this map!",
+						getStructName(&asStructureStats[inc] ) );
+				}
 			}
 		}
 	}
@@ -1279,10 +1296,11 @@ BOOL structSetManufacture(STRUCTURE *psStruct, DROID_TEMPLATE *psTempl, UBYTE qu
 
 	CHECK_STRUCTURE(psStruct);
 
-	ASSERT_OR_RETURN(false, psStruct != NULL && psStruct->type == OBJ_STRUCTURE, "Invalid factory pointer");
-	ASSERT_OR_RETURN(false, psStruct->pStructureType->type == REF_FACTORY || psStruct->pStructureType->type == REF_CYBORG_FACTORY
-	                 || psStruct->pStructureType->type == REF_VTOL_FACTORY, "Invalid structure type %d for factory",
-	                 (int)psStruct->pStructureType->type);
+	ASSERT( psStruct != NULL && psStruct->type == OBJ_STRUCTURE &&
+			(psStruct->pStructureType->type == REF_FACTORY ||
+			psStruct->pStructureType->type == REF_CYBORG_FACTORY ||
+			psStruct->pStructureType->type == REF_VTOL_FACTORY),
+		"structSetManufacture: invalid Factory pointer" );
 	/* psTempl might be NULL if the build is being cancelled in the middle */
 
 	//assign it to the Factory
@@ -1530,7 +1548,8 @@ STRUCTURE* buildStructure(STRUCTURE_STATS* pStructureType, UDWORD x, UDWORD y, U
 {
 	STRUCTURE	*psBuilding = NULL;
 
-	ASSERT_OR_RETURN(NULL, pStructureType && pStructureType->type != REF_DEMOLISH, "You cannot build demolition!");
+	assert(pStructureType);
+	ASSERT(pStructureType->type != REF_DEMOLISH, "You cannot build demolition!");
 
 	if (IsStatExpansionModule(pStructureType)==false)
 	{
@@ -1540,8 +1559,11 @@ STRUCTURE* buildStructure(STRUCTURE_STATS* pStructureType, UDWORD x, UDWORD y, U
 		UDWORD	width, breadth;
 		int	i;
 
-		ASSERT_OR_RETURN(NULL, max <= numStructureStats, "Invalid structure type");
-
+		if (max > numStructureStats)
+		{
+			ASSERT(!"invalid structure type", "buildStructure: Invalid structure type");
+			return NULL;
+		}
 		// Don't allow more than interface limits
 		if (asStructLimits[player][max].currentQuantity + 1 > asStructLimits[player][max].limit)
 		{
@@ -1829,8 +1851,11 @@ STRUCTURE* buildStructure(STRUCTURE_STATS* pStructureType, UDWORD x, UDWORD y, U
 		//don't create the Structure use existing one
 		psBuilding = getTileStructure(map_coord(x), map_coord(y));
 
-		ASSERT_OR_RETURN(NULL, psBuilding != NULL, "No owning structure for this module - %s", getStructName(pStructureType));
-
+		if (psBuilding == NULL)
+		{
+			ASSERT(!"module has no owning structure", "No owning structure for this module - %s", getStructName(pStructureType));
+			return false;
+		}
 		if (pStructureType->type == REF_FACTORY_MODULE)
 		{
 			if (psBuilding->pStructureType->type != REF_FACTORY &&
@@ -2066,7 +2091,13 @@ BOOL setFunctionality(STRUCTURE	*psBuilding, STRUCTURE_TYPE functionType)
 		case REF_REARM_PAD:
 			// Allocate space for the buildings functionality
 			psBuilding->pFunctionality = calloc(1, sizeof(*psBuilding->pFunctionality));
-			ASSERT_OR_RETURN(false, psBuilding != NULL, "Out of memory");
+
+			if (psBuilding->pFunctionality == NULL)
+			{
+				debug(LOG_ERROR, "Out of memory");
+				abort();
+				return false;
+			}
 			break;
 
 		default:
@@ -2118,7 +2149,7 @@ BOOL setFunctionality(STRUCTURE	*psBuilding, STRUCTURE_TYPE functionType)
 					setFlagPositionInc(psBuilding->pFunctionality, psBuilding->player, VTOL_FLAG);
 					break;
 				default:
-					ASSERT_OR_RETURN(false, false, "Invalid factory type");
+					ASSERT(!"invalid factory type", "Invalid factory type");
 			}
 
 			// Take advantage of upgrades
@@ -2779,7 +2810,6 @@ static void aiUpdateStructure(STRUCTURE *psStructure, bool mission)
 	BASE_STATS			*pSubject = NULL;
 	UDWORD				pointsToAdd;//, iPower;
 	PLAYER_RESEARCH		*pPlayerRes = asPlayerResList[psStructure->player];
-	RESEARCH			*pResearch;
 	UDWORD				structureMode = 0;
 	DROID				*psDroid;
 	BASE_OBJECT			*psChosenObjs[STRUCT_MAXWEAPS] = {NULL};
@@ -3167,7 +3197,6 @@ static void aiUpdateStructure(STRUCTURE *psStructure, bool mission)
 			//check research has not already been completed by another structure
 			if (IsResearchCompleted(pPlayerRes)==0)
 			{
-				pResearch = (RESEARCH *)pSubject;
 				// don't update if not responsible (106)
 				if(bMultiPlayer && !myResponsibility(psStructure->player))
 				{
@@ -3183,18 +3212,16 @@ static void aiUpdateStructure(STRUCTURE *psStructure, bool mission)
 				ASSERT_OR_RETURN(, gameTime >= psResFacility->timeStarted, "research seems to have started in the future");
 				pointsToAdd = (psResFacility->researchPoints * (gameTime -
 					psResFacility->timeStarted)) / GAME_TICKS_PER_SEC;
-				pointsToAdd = MIN(pointsToAdd, pResearch->researchPoints - pPlayerRes->currentPoints);
 
-				if (pointsToAdd > 0 &&
-				    pResearch->researchPoints > 0) // might be a "free" research
+				if (pointsToAdd > 0)
 				{
-					float powerNeeded = (pResearch->researchPower * pointsToAdd) / (float)pResearch->researchPoints;
+					float powerNeeded = (((RESEARCH *)pSubject)->researchPower * pointsToAdd) / (float)((RESEARCH *)pSubject)->researchPoints;
 					pPlayerRes->currentPoints += requestPowerFor(psStructure->player, powerNeeded, pointsToAdd);
 					psResFacility->timeStarted = gameTime;
 				}
 
 				//check if Research is complete
-				if (pPlayerRes->currentPoints >= pResearch->researchPoints)
+				if (pPlayerRes->currentPoints > ((RESEARCH *)pSubject)->researchPoints)
 				{
 					if(bMultiPlayer)
 					{
@@ -3208,7 +3235,7 @@ static void aiUpdateStructure(STRUCTURE *psStructure, bool mission)
 					}
 					else
 					{
-						if (pResearch->researchPoints >
+						if (((RESEARCH *)psResFacility->psSubject)->researchPoints >
 							((RESEARCH *)psResFacility->psBestTopic)->researchPoints)
 						{
 							psResFacility->psSubject = psResFacility->psSubject;
@@ -4509,7 +4536,12 @@ BOOL getDroidDestination(BASE_STATS *psStats, UDWORD structX,
 		width = ((FEATURE_STATS *)psStats)->baseWidth;
 		breadth = ((FEATURE_STATS *)psStats)->baseBreadth;
 	}
-	ASSERT_OR_RETURN(false, width + breadth > 0, "Weird droid destination");
+	ASSERT(width+breadth, "weird object passed to getDroidDestination");
+	if (width + breadth == 0)
+	{
+		debug(LOG_SYNC, "weird object passed to getDroidDestination");
+		return false;
+	}
 
 	//get a random starting place 0=top left
 	start = (UWORD)(rand() % ((width + breadth) * 2));
@@ -4659,7 +4691,7 @@ BOOL checkWidth(UDWORD maxRange, UDWORD x, UDWORD y, UDWORD *pDroidX, UDWORD *pD
 			*pDroidX = world_coord(x + side);
 			*pDroidY = world_coord(y);
 
-			ASSERT_OR_RETURN(false, worldOnMap(*pDroidX,*pDroidY), "Insane droid position generated at width (%u, %u)", *pDroidX, *pDroidY);
+			ASSERT( worldOnMap(*pDroidX,*pDroidY),"checkWidth : Insane droid position" );
 
 			return true;
 		}
@@ -4680,7 +4712,7 @@ BOOL checkLength(UDWORD maxRange, UDWORD x, UDWORD y, UDWORD *pDroidX, UDWORD *p
 			*pDroidX = world_coord(x);
 			*pDroidY = world_coord(y + side);
 
-			ASSERT_OR_RETURN(false, worldOnMap(*pDroidX,*pDroidY), "Insane droid position generated at length (%u, %u)", *pDroidX, *pDroidY);
+			ASSERT( worldOnMap(*pDroidX,*pDroidY),"checkHeight : Insane droid position" );
 
 			return true;
 		}
@@ -4723,7 +4755,7 @@ BOOL removeStruct(STRUCTURE *psDel, BOOL bDestroy)
 	SDWORD		cluster;
 	FLAG_POSITION	*psAssemblyPoint=NULL;
 
-	ASSERT_OR_RETURN(false, psDel != NULL, "Invalid structure pointer");
+	ASSERT(psDel != NULL, "invalid structure pointer");
 
 	if (bDestroy)
 	{
@@ -5151,7 +5183,8 @@ BOOL checkSpecificStructExists(UDWORD structInc, UDWORD player)
 	STRUCTURE	*psStructure;
 	BOOL		found = false;
 
-	ASSERT_OR_RETURN(false, structInc < numStructureStats, "Invalid structure inc");
+	ASSERT( structInc < numStructureStats,
+		"checkSpecificStructExists: invalid structure inc" );
 
 	for (psStructure = apsStructLists[player]; psStructure != NULL;
 		psStructure = psStructure->psNext)
@@ -5366,7 +5399,7 @@ void structureCompletedCallback(STRUCTURE_STATS *psStructType)
 
 STRUCTURE_STATS * structGetDemolishStat( void )
 {
-	ASSERT_OR_RETURN(NULL, g_psStatDestroyStruct != NULL , "Demolish stat not initialised");
+	ASSERT(g_psStatDestroyStruct != NULL , "stat not initialised");
 	return g_psStatDestroyStruct;
 }
 
@@ -5759,7 +5792,7 @@ void buildingComplete(STRUCTURE *psBuilding)
 /*for a given structure, return a pointer to its module stat */
 STRUCTURE_STATS* getModuleStat(const STRUCTURE* psStruct)
 {
-	ASSERT_OR_RETURN(NULL, psStruct != NULL, "Invalid structure pointer");
+	ASSERT(psStruct != NULL, "Invalid structure pointer");
 
 	switch (psStruct->pStructureType->type)
 	{
@@ -6005,8 +6038,12 @@ BOOL electronicDamage(BASE_OBJECT *psTarget, UDWORD damage, UBYTE attackPlayer)
 	Vector3i	pos;
 	UDWORD		i;
 
-	ASSERT_OR_RETURN(false, attackPlayer < MAX_PLAYERS, "Invalid player id %d", (int)attackPlayer);
-	ASSERT_OR_RETURN(false, psTarget != NULL, "Target is NULL");
+	ASSERT(attackPlayer < MAX_PLAYERS, "electronicDamage: invalid player id %d", (int)attackPlayer);
+	ASSERT(psTarget != NULL, "electronicDamage: target is NULL");
+	if (attackPlayer >= MAX_PLAYERS || psTarget == NULL)
+	{
+		return false;
+	}
 
 	//structure electronic damage
 	if (psTarget->type == OBJ_STRUCTURE)
@@ -6062,7 +6099,11 @@ BOOL electronicDamage(BASE_OBJECT *psTarget, UDWORD damage, UBYTE attackPlayer)
 		//in multiPlayer cannot attack a Transporter with EW
 		if (bMultiPlayer)
 		{
-			ASSERT_OR_RETURN(true, psDroid->droidType != DROID_TRANSPORTER, "Cannot attack a Transporter in multiPlayer");
+			if (psDroid->droidType == DROID_TRANSPORTER)
+			{
+				ASSERT(!"can't attack a Transporter while in multiplayer", "electronicDamage: Cannot attack a Transporter in multiPlayer");
+				return true;
+			}
 		}
 
 		if (psDroid->resistance == ACTION_START_TIME)
@@ -6151,7 +6192,7 @@ BOOL validStructResistance(STRUCTURE *psStruct)
 {
 	BOOL    bTarget = false;
 
-	ASSERT_OR_RETURN(false, psStruct != NULL, "Invalid structure pointer");
+	ASSERT( psStruct != NULL, "invalidStructResistance: invalid structure pointer" );
 
 	if (psStruct->pStructureType->resistance != 0)
 	{
@@ -6214,14 +6255,14 @@ UDWORD structureBaseBody(const STRUCTURE *psStructure)
 {
 	const STRUCTURE_STATS *psStats = psStructure->pStructureType;
 
-	ASSERT_OR_RETURN(0, psStructure != NULL, "Invalid structure pointer");
+	ASSERT( psStructure != NULL, "structureBaseBody: invalid structure pointer" );
 
 	switch(psStats->type)
 	{
 		// modules may be attached:
 		case REF_FACTORY:
 		case REF_VTOL_FACTORY:
-			ASSERT_OR_RETURN(0, psStructure->pFunctionality != NULL, "Invalid structure functionality pointer for factory base body");
+			ASSERT(psStructure->pFunctionality != NULL, "structureBaseBody: invalid structure functionality pointer");
 			if (psStructure->pFunctionality->factory.capacity > 0)
 			{
 				//add on the default for the factory
@@ -6233,7 +6274,7 @@ UDWORD structureBaseBody(const STRUCTURE *psStructure)
 				return psStats->bodyPoints;
 			}
 		case REF_RESEARCH:
-			ASSERT_OR_RETURN(0, psStructure->pFunctionality != NULL, "Invalid structure functionality pointer for research base body");
+			ASSERT(psStructure->pFunctionality != NULL, "structureBaseBody: invalid structure functionality pointer");
 			if (psStructure->pFunctionality->researchFacility.capacity > 0)
 			{
 				//add on the default for the factory
@@ -6245,7 +6286,7 @@ UDWORD structureBaseBody(const STRUCTURE *psStructure)
 				return psStats->bodyPoints;
 			}
 		case REF_POWER_GEN:
-			ASSERT_OR_RETURN(0, psStructure->pFunctionality != NULL, "Invalid structure functionality pointer for power gen base body");
+			ASSERT(psStructure->pFunctionality != NULL, "structureBaseBody: invalid structure functionality pointer");
 			if (psStructure->pFunctionality->powerGenerator.capacity > 0)
 			{
 				//add on the default for the factory
@@ -6694,7 +6735,8 @@ DROID_TEMPLATE * factoryProdUpdate(STRUCTURE *psStructure, DROID_TEMPLATE *psTem
 	FACTORY		*psFactory;
 
 	CHECK_STRUCTURE(psStructure);
-	ASSERT_OR_RETURN(NULL, psStructure->player == productionPlayer, "%s called for incorrect player", __FUNCTION__);
+	ASSERT( psStructure->player == productionPlayer,
+		"factoryProdUpdate: called for incorrect player" );
 
 	psFactory = &psStructure->pFunctionality->factory;
 	factoryType = psFactory->psAssemblyPoint->factoryType;
@@ -6958,7 +7000,8 @@ UWORD countAssignableFactories(UBYTE player,UWORD factoryType)
 	UWORD		factoryInc;
 	UBYTE		mask = 1, quantity = 0;
 
-	ASSERT_OR_RETURN(0, player == selectedPlayer, "%s should only be called for selectedPlayer", __FUNCTION__);
+	ASSERT( player == selectedPlayer,
+		"countAssignableFactories: should only be called for selectedPlayer" );
 
 	for (factoryInc = 0; factoryInc < MAX_FACTORY; factoryInc++)
 	{
@@ -6977,8 +7020,10 @@ UWORD countAssignableFactories(UBYTE player,UWORD factoryType)
 // check whether a factory of a certain number and type exists
 BOOL checkFactoryExists(UDWORD player, UDWORD factoryType, UDWORD inc)
 {
-	ASSERT_OR_RETURN(false, player < MAX_PLAYERS, "Invalid player");
-	ASSERT_OR_RETURN(false, factoryType < NUM_FACTORY_TYPES, "Invalid factoryType");
+	ASSERT( player < MAX_PLAYERS,
+		"checkFactoryExists: invalid player" );
+	ASSERT( factoryType < NUM_FACTORY_TYPES,
+		"checkFactoryExists: invalid factoryType" );
 
 	return (factoryNumFlag[player][factoryType] & (1 << inc)) != 0;
 }
@@ -7410,9 +7455,13 @@ STRUCTURE * giftSingleStructure(STRUCTURE *psStructure, UBYTE attackPlayer, BOOL
 	//this is not the case for EW in multiPlayer mode
 	if (!bMultiPlayer)
 	{
-		//added 'selectedPlayer != 0' to be able to test the game by changing player...
+		//added 'selectedPlayer == 0' to be able to test the game by changing player...
 		//in this version of Warzone, the attack Player can NEVER be the selectedPlayer (unless from the script)
-		ASSERT_OR_RETURN(NULL, bFromScript || selectedPlayer != 0 || attackPlayer != selectedPlayer, "EW attack by selectedPlayer on a structure");
+		if (!bFromScript && selectedPlayer == 0 && attackPlayer == selectedPlayer)
+		{
+			ASSERT(bFromScript || selectedPlayer != 0 || attackPlayer != selectedPlayer, "giftSingleStructure: EW attack by selectedPlayer on a structure");
+			return NULL;
+		}
 	}
 
 	//don't want the hassle in multiplayer either
@@ -7504,6 +7553,9 @@ STRUCTURE * giftSingleStructure(STRUCTURE *psStructure, UBYTE attackPlayer, BOOL
 				psStructure->visible[selectedPlayer] = UBYTE_MAX;
 			}
 		}
+
+		//ASSERT( false,
+		//    "giftSingleStructure: EW attack in multiplayer" );
 		return NULL;
 	}
 
@@ -7672,15 +7724,23 @@ BOOL checkStructureStats(void)
 			for (inc = 0; inc < asStructureStats[structInc].numFuncs; inc++)
 			{
 
-				ASSERT_OR_RETURN(false, asStructureStats[structInc].asFuncList[inc] != NULL,
-				                 "Invalid function for structure %s", asStructureStats[structInc].pName);
+				ASSERT( asStructureStats[structInc].asFuncList[inc] != NULL,
+			"checkStructureStats: \
+					Invalid function for structure %s",
+					asStructureStats[structInc].pName );
 
 			}
 		}
 		else
 		{
-			ASSERT_OR_RETURN(false, asStructureStats[structInc].asFuncList == NULL, "Invalid functions attached to structure %s",
-			                 asStructureStats[structInc].pName);
+			if (asStructureStats[structInc].asFuncList != NULL)
+			{
+
+				ASSERT( false, "checkStructureStats:Invalid functions attached to structure %s",
+					asStructureStats[structInc].pName );
+
+				return false;
+			}
 		}
 	}
 	return true;
diff --git a/src/wrappers.c b/src/wrappers.c
index 126af1e..34cdd44 100644
--- a/src/wrappers.c
+++ b/src/wrappers.c
@@ -124,9 +124,6 @@ TITLECODE titleLoop(void)
 		// then check --join and if neither, run the normal game menu.
 		if( hostlaunch )
 		{
-			ingame.bHostSetup = true;
-			bMultiPlayer = true;
-			game.type = SKIRMISH;		// needed?
 			changeTitleMode(MULTIOPTION);
 			hostlaunch = false;			// reset the bool to default state.
 		}
diff --git a/tools/masterserver/client.py b/tools/masterserver/client.py
new file mode 100644
index 0000000..c234ee3
--- /dev/null
+++ b/tools/masterserver/client.py
@@ -0,0 +1,120 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# vim: set et sts=4 sw=4 encoding=utf-8:
+#
+# This file is part of Warzone 2100.
+# Copyright (C) 2009  Gerard Krol
+# Copyright (C) 2009  Warzone Resurrection Project
+#
+# Warzone 2100 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.
+#
+# Warzone 2100 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 Warzone 2100; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+#
+
+from __future__ import with_statement
+from contextlib import contextmanager
+from pkg_resources import parse_version
+import socket
+import struct
+
+__all__ = ['masterserver_connection', 'game']
+
+@contextmanager
+def _socket(family = socket.AF_INET, type = socket.SOCK_STREAM, proto = 0):
+    s = socket.socket(family, type, proto)
+    try:
+        yield s
+    finally:
+        s.close()
+
+def _swap_endianness(i):
+    return struct.unpack(">I", struct.pack("<I", i))
+
+class masterserver_connection:
+    # >= 2.0 data
+    name_length          = 64
+    host_length          = 16
+
+    # >= 2.2 data
+    misc_length          = 64
+    extra_length         = 255
+    versionstring_length = 64
+    modlist_length       = 255
+
+    host = None
+    port = None
+
+    def __init__(self, host, port, version = '2.2'):
+        # Binary struct format to use (GAMESTRUCT)
+        if parse_version(version) >= parse_version('2.0'):
+            self.gameFormat = "!%dsII%ds6I" % (self.name_length, self.host_length)
+        if parse_version(version) >= parse_version('2.2'):
+            self.gameFormat += '%ds%ds%ds%ds10I' % (self.misc_length, self.extra_length, self.versionstring_length, self.modlist_length)
+
+        self.host    = host
+        self.port    = port
+        self.version = version
+
+    def list(self, allowException = False):
+        with _socket(socket.AF_INET, socket.SOCK_STREAM) as s:
+            games = []
+            try:
+                s.settimeout(10)
+                s.connect( (self.host, self.port) )
+
+                self._send(s, "list\0")
+                (count,) = self._recv(s, "!I")
+                for i in xrange(0,count):
+                    (description, size, flags, host, maxPlayers, currentPlayers,
+                    user1, user2, user3, user4) = self._recv(s, self.gameFormat)
+                    description = description.strip("\0")
+                    host = host.strip("\0")
+                    # Workaround for the fact that some of the
+                    # 2.0.x versions don't perform endian swapping
+                    if maxPlayers > 100:
+                        maxPlayers = _swap_endianness(maxPlayers)
+                        currentPlayers = _swap_endianness(currentPlayers)
+                    g = game(description, host, maxPlayers, currentPlayers)
+                    games.append(g)
+            except (socket.error, socket.herror, socket.gaierror, socket.timeout):
+                if allowException:
+                    raise
+
+            return games
+
+    def _send(self, s, command):
+        s.send(command)
+        s.send("\0")
+
+    def _recv(self, s, format):
+        data = struct.Struct(format)
+        return data.unpack(s.recv(data.size))
+
+class game:
+    announce = True
+
+    def __init__(self, description, host, maxPlayers, currentPlayers):
+        self.description = description
+        self.host = host
+        self.maxPlayers = maxPlayers
+        self.currentPlayers = currentPlayers
+
+def main():
+    lobbies = [(version, masterserver_connection("lobby.wz2100.net", port).list()) for (version, port) in [("2.0", 9998),
+                                                                                                           ("2.1", 9997)]]
+    for (version, lobby) in lobbies:
+        print "%s lobby" % version
+        print lobby
+
+if __name__ == "__main__":
+    main()
diff --git a/tools/masterserver/game.py b/tools/masterserver/game.py
index 92e3a86..f89eeff 100755
--- a/tools/masterserver/game.py
+++ b/tools/masterserver/game.py
@@ -27,6 +27,8 @@ import logging
 
 __all__ = ['Game']
 
+gamePort  = 2100         # Gameserver port.
+
 #
 ################################################################################
 # Game class
@@ -63,9 +65,6 @@ class Game(object):
 	def _setPrivate(self, v):
 		self.data['private'] = bool(v)
 
-	def _setAnnounce(self, v):
-		self.data['announced'] = not bool(v)
-
 	description        = property(fget = lambda self:    self.data['name'],
 	                              fset = lambda self, v: self._setDescription(v))
 
@@ -93,10 +92,7 @@ class Game(object):
 	private            = property(fget = lambda self:    self.data['private'],
 	                              fset = lambda self, v: self._setPrivate(v))
 
-	announce           = property(fget = lambda self: not self.private and (not 'announced' in self.data or not self.data['announced']),
-	                              fset = lambda self, v: self._setAnnounce(v))
-
-	def __init__(self):
+	def __init__(self, requestHandler):
 		self.data = {'name':                None,
 		             'host':                None,
 		             'maxPlayers':          None,
@@ -123,8 +119,23 @@ class Game(object):
 		self.future3 = None			# for future use
 		self.future4 = None			# for future use
 
+		self.requestHandler = requestHandler
+
 	def __str__(self):
 		if self.private == 1:
 		   return "(private) Game: %16s %s %s %s" % ( self.host, self.description, self.maxPlayers, self.currentPlayers)
 		else:
 		   return "Game: %16s %s %s %s" % ( self.host, self.description, self.maxPlayers, self.currentPlayers)
+
+	def check(self):
+		# Check we can connect to the host
+		s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+		try:
+			logging.debug("Checking %s's vitality..." % self.host)
+			s.settimeout(10.0)
+			s.connect((self.host, gamePort))
+			s.close()
+			return True
+		except:
+			logging.debug("%s did not respond!" % self.host)
+			return False
diff --git a/tools/masterserver/ircbot.py b/tools/masterserver/ircbot.py
index 94b4ccf..093ce70 100755
--- a/tools/masterserver/ircbot.py
+++ b/tools/masterserver/ircbot.py
@@ -30,7 +30,7 @@ import socket
 import struct
 import threading
 import time
-from protocol import *
+from client import *
 
 irc_server          = "irc.freenode.net"
 irc_port            = 6667
@@ -40,15 +40,14 @@ irc_nick            = "wzlobbybot"
 irc_nickpass        = None
 
 def main():
-    bot = Bot(irc_server, irc_port, irc_serve_channels, irc_silent_channels, irc_nick, irc_nickpass, "lobby.wz2100.net", '2.1')
+    bot = Bot(irc_server, irc_port, irc_serve_channels, irc_silent_channels, irc_nick, irc_nickpass, "lobby.wz2100.net", 9997)
     bot.start()
 
 class Bot:
-    def __init__(self, ircServer, ircPort, ircServeChannels, ircSilentChannels, ircNick, nickPass, lobbyServer, lobbyVersion):
+    def __init__(self, ircServer, ircPort, ircServeChannels, ircSilentChannels, ircNick, nickPass, lobbyServer, lobbyPort):
         self.commands = BotCommands(self)
         self.irc          = bot_connection(self.commands, ircServer, ircPort, ircServeChannels, ircSilentChannels, ircNick, nickPass)
-        self.lobby        = BinaryProtocol(lobbyVersion)
-        self.lobby.host = lobbyServer
+        self.lobby        = masterserver_connection(lobbyServer, lobbyPort, version='2.1')
         self.check        = change_notifier(self.irc, self.lobby)
 
     def start(self):
@@ -109,7 +108,7 @@ class BotCommands:
 
     def list(self, nick, write):
         try:
-            games = [game for game in self.bot.lobby.list(self.bot.lobby.host)]
+            games = self.bot.lobby.list(allowException = True)
             if not games:
                 write("%s: No games in lobby" % (nick))
             else:
@@ -121,7 +120,7 @@ class BotCommands:
                 message += ", ".join(l)
                 write("%s: %s" % (nick, message))
         except (socket.error, socket.herror, socket.gaierror, socket.timeout), e:
-            write("%s: Failed to communicate with the lobby (%s:%d): %s" % (nick, self.bot.lobby.host, self.bot.lobby.gamePort, e))
+            write("%s: Failed to communicate with the lobby (%s:%d): %s" % (nick, self.bot.lobby.host, self.bot.lobby.port, e))
 
     # TODO: if message.startswith("show") # join a game and show information about it
 
@@ -143,10 +142,7 @@ class change_notifier(threading.Thread):
     def run(self):
         self.stopChecking.clear()
         while not self.stopChecking.isSet():
-            try:
-                new_games = [game for game in self.lobby.list(self.lobby.host)]
-            except:
-                new_games = []
+            new_games = self.lobby.list()
             if self.games == None:
                 self.games = {}
                 for g in new_games:
@@ -154,7 +150,7 @@ class change_notifier(threading.Thread):
             else:
                 new_game_dict = {}
                 for g in new_games:
-                    if g.host in self.games and g.announce:
+                    if g.host in self.games and g.announce == True:
                         g.announce = False
                         message = "New game: \x02%s\x02 (%i players)" % (g.description, g.maxPlayers)
                         if not g.host in self.timestamps:
diff --git a/tools/masterserver/protocol.py b/tools/masterserver/protocol.py
index 3d22f16..4b5fb09 100755
--- a/tools/masterserver/protocol.py
+++ b/tools/masterserver/protocol.py
@@ -19,87 +19,15 @@ from __future__ import with_statement
 #
 ################################################################################
 # Get the things we need.
-from contextlib import contextmanager
-import logging
-import socket
 import struct
-from StringIO import StringIO
 from pkg_resources import parse_version
 from game import *
 
-__all__ = ['Protocol']
+__all__ = ['Protocol', 'BinaryProtocol']
 
-@contextmanager
-def _socket(family = socket.AF_INET, type = socket.SOCK_STREAM, proto = 0):
-	s = socket.socket(family, type, proto)
-	try:
-		yield s
-	finally:
-		s.close()
-
-def _encodeCString(string, buf_len):
-	# If we haven't got a string return an empty one
-	if not string:
-		return str('\0' * buf_len)
-
-	# Make sure the string fits
-	string = string[:buf_len - 1]
-
-	# Add a terminating NUL and fill the rest of the buffer with NUL bytes
-	string = string.ljust(buf_len, "\0")
-
-	# Make sure *not* to use a unicode string
-	return str(string)
-
-def _swap_endianness(i):
-	return struct.unpack(">I", struct.pack("<I", i))
-
-@contextmanager
-def writeable(output):
-	if   hasattr(output, 'write'):
-		# File IO
-		yield output
-	else:
-		try:
-			# Socket IO
-			io = output.makefile()
-			yield io
-		except AttributeError:
-			# String, lets use StringIO instead
-			io = StringIO(output)
-			yield io
-		finally:
-			io.close()
-
-@contextmanager
-def readable(input):
-	if   hasattr(input, 'read'):
-		# File IO
-		yield input
-	else:
-		try:
-			# Socket IO
-			io = output.makefile()
-			yield io
-		except AttributeError:
-			# String IO (no, not the StringIO class, that would have been matched as "File IO")
-			io = None
-			yield io
-		finally:
-			if io:
-				io.close
-
-class BaseProtocol(object):
-	# Gameserver port.
-	gamePort = {'2.0': 9999,
-	            '2.2': 2100}
-	# Lobby server port.
-	lobbyPort = {'2.0': 9998,
-	             '2.1': 9997,
-	             '2.2': 9990}
-
-	def __init__(self, version):
-		self.version = version
+class Protocol(object):
+	# Size of a single game is undefined at compile time
+	size = None
 
 	def encodeSingle(data):
 		pass
@@ -107,200 +35,66 @@ class BaseProtocol(object):
 	def encodeMultiple(data):
 		pass
 
-	def decodeSingle(data, game = Game()):
+	def decodeSingle(data):
 		pass
 
 	def decodeMultiple(data):
 		pass
 
-	def check(self, game):
-		"""Check we can connect to the game's host."""
-		with _socket() as s:
-			try:
-				logging.debug("Checking %s's vitality..." % game.host)
-				s.settimeout(10.0)
-				s.connect((game.host, self.gamePort))
-				return True
-			except (socket.error, socket.herror, socket.gaierror, socket.timeout), e:
-				logging.debug("%s did not respond: %s" % (game.host, e))
-				return False
-
-	def list(self, host):
-		"""Retrieve a list of games from the lobby server."""
-		with _socket() as s:
-			s.settimeout(10.0)
-			s.connect((host, self.lobbyPort))
-
-			s.send("list\0")
-			for game in self.decodeMultiple(s):
-				yield game
-
-class BinaryProtocol20(BaseProtocol):
+class BinaryProtocol(Protocol):
 	# Binary struct format to use (GAMESTRUCT)
+	gameFormat = {}
 
 	# >= 2.0 data
 	name_length          = 64
 	host_length          = 16
 
-	gameFormat = struct.Struct('!%dsII%ds6I' % (name_length, host_length))
-
-	countFormat = struct.Struct('!I')
-
-	size = property(fget = lambda self: self.gameFormat.size)
-
-	gamePort = BaseProtocol.gamePort['2.0']
-	lobbyPort = BaseProtocol.lobbyPort['2.0']
-
-	def _encodeName(self, game):
-		return _encodeCString(game.description, self.name_length)
-
-	def _encodeHost(self, game):
-		return _encodeCString(game.host, self.host_length)
-
-	def encodeSingle(self, game, out = str()):
-		with writeable(out) as write:
-			# Workaround the fact that the 2.0.x versions don't
-			# perform endian swapping
-			maxPlayers     = _swap_endianness(maxPlayers)
-			currentPlayers = _swap_endianness(currentPlayers)
-
-			write.write(self.gameFormat.pack(
-				self._encodeName(game),
-				game.size or self.size, game.flags,
-				self._encodeHost(game),
-				maxPlayers, currentPlayers, game.user1, game.user2, game.user3, game.user4))
-
-			try:
-				return write.getvalue()
-			except AttributeError:
-				return out
-
-	def encodeMultiple(self, games, out = str()):
-		with writeable(out) as write:
-			write.write(self.countFormat.pack(len(games)))
-			for game in games:
-				self.encodeSingle(game, write)
-
-			try:
-				return write.getvalue()
-			except AttributeError:
-				return out
-
-	def decodeSingle(self, input, game = Game(), offset = None):
-		with readable(input) as read:
-			decData = {}
-
-			if   offset != None and read == None:
-				def unpack():
-					return self.gameFormat.unpack_from(out, offset)
-			elif not read:
-				def unpack():
-					return self.gameFormat.unpack(input)
-			else:
-				def unpack():
-					data = read.read(self.size)
-					if len(data) != self.size:
-						return None
-					return self.gameFormat.unpack(data)
-
-			data = unpack()
-			if not data:
-				return None
-
-			(decData['name'], game.size, game.flags, decData['host'], game.maxPlayers, game.currentPlayers,
-				game.user1, game.user2, game.user3, game.user4) = data
-
-			# Workaround the fact that the 2.0.x versions don't
-			# perform endian swapping
-			game.maxPlayers = _swap_endianness(game.maxPlayers)
-			game.currentPlayers = _swap_endianness(game.currentPlayers)
-
-			for strKey in ['name', 'host']:
-				decData[strKey] = decData[strKey].strip("\0")
-
-			game.data.update(decData)
-			return game
-
-	def decodeMultiple(self, input):
-		with readable(input) as read:
-			if read:
-				(count,) = self.countFormat.unpack(read.read(self.countFormat.size))
-			else:
-				(count,) = self.countFormat.unpack_from(input)
-
-			for i in xrange(count):
-				yield self.decodeSingle(read or input, offset=(self.size * i + self.countFormat.size))
-
-class BinaryProtocol21(BinaryProtocol20):
-	lobbyPort = BaseProtocol.lobbyPort['2.1']
-
-	def encodeSingle(self, game, out = str()):
-		with writeable(out) as write:
-			write.write(self.gameFormat.pack(
-				self._encodeName(game),
-				game.size or self.size, game.flags,
-				self._encodeHost(game),
-				maxPlayers, currentPlayers, game.user1, game.user2, game.user3, game.user4))
-
-			try:
-				return write.getvalue()
-			except AttributeError:
-				return out
-
-	def decodeSingle(self, input, game = Game(), offset = None):
-		with readable(input) as read:
-			decData = {}
-
-			if   offset != None and read == None:
-				def unpack():
-					return self.gameFormat.unpack_from(out, offset)
-			elif not read:
-				def unpack():
-					return self.gameFormat.unpack(input)
-			else:
-				def unpack():
-					data = read.read(self.size)
-					if len(data) != self.size:
-						return None
-					return self.gameFormat.unpack(data)
-
-			data = unpack()
-			if not data:
-				return None
-
-			(decData['name'], game.size, game.flags, decData['host'], game.maxPlayers, game.currentPlayers,
-				game.user1, game.user2, game.user3, game.user4) = data
-
-			for strKey in ['name', 'host']:
-				decData[strKey] = decData[strKey].strip("\0")
+	gameFormat['2.0'] = '!%dsII%ds6I' % (name_length, host_length)
 
-			game.data.update(decData)
-			return game
-
-class BinaryProtocol22(BinaryProtocol21):
 	# >= 2.2 data
 	misc_length          = 64
 	extra_length         = 255
 	versionstring_length = 64
 	modlist_length       = 255
 
-	gameFormat = struct.Struct(BinaryProtocol21.gameFormat.format + '%ds%ds%ds%ds10I' % (misc_length, extra_length, versionstring_length, modlist_length))
+	gameFormat['2.2'] = gameFormat['2.0'] + '%ds%ds%ds%ds10I' misc_length, extra_length, versionstring_length, modlist_length)
+
+	countFormat = '!I'
+	countSize = struct.calcsize(countFormat)
+
+	def __init__(self, version = '2.2'):
+		# Size of a single game = sizeof(GAMESTRUCT)
+		if   parse_version(version) >= parse_version('2.0'):
+			self.size = struct.calcsize(self.gameFormat['2.0'])
+		elif parse_version(version) >= parse_version('2.2'):
+			self.size = struct.calcsize(self.gameFormat['2.2'])
+
+		self.version = version
+
+	def _encodeName(self, game):
+		return game.description[:self.name_length - 1].ljust(self.name_length, "\0")
 
-	gamePort = BaseProtocol.gamePort['2.2']
-	lobbyPort = BaseProtocol.lobbyPort['2.2']
+	def _encodeHost(self, game):
+		return game.host[:self.host_length - 1].ljust(self.host_length, "\0")
 
 	def _encodeMisc(self, game):
-		return _encodeCString(game.misc, self.misc_length)
+		return game.misc[:self.misc_length - 1].ljust(self.misc_length, "\0")
 
 	def _encodeExtra(self, game):
-		return _encodeCString(game.extra, self.extra_length)
+		return game.extra[:self.extra_length - 1].ljust(self.extra_length, "\0")
 
 	def _encodeVersionString(self, game):
-		return _encodeCString(game.multiplayerVersion, self.versionstring_length)
+		return game.multiplayerVersion[:self.versionstring_length - 1].ljust(self.versionstring_length, "\0")
 
-	def encodeSingle(self, game, out = str()):
-		with writeable(out) as write:
-			write.write(self.gameFormat.pack(
+	def encodeSingle(self, game):
+		if   parse_version(self.version) >= parse_version('2.0'):
+			return struct.pack(self.gameFormat,
+				self._encodeName(game),
+				game.size or self.size, game.flags,
+				self._encodeHost(game),
+				game.maxPlayers, game.currentPlayers, game.user1, game.user2, game.user3, game.user4)
+		elif parse_version(self.version) >= parse_version('2.2'):
+			return struct.pack(self.gameFormat,
 				self._encodeName(game),
 				game.size or self.size, game.flags,
 				self._encodeHost(game),
@@ -310,54 +104,39 @@ class BinaryProtocol22(BinaryProtocol21):
 				self._encodeVersionString(game),
 				game.modlist,
 				game.lobbyVersion, game.game_version_major, game.game_version_minor, game.private,
-				game.pure, game.Mods, game.future1, game.future2, game.future3, game.future4))
-
-			try:
-				return write.getvalue()
-			except AttributeError:
-				return out
+				game.pure, game.Mods, game.future1, game.future2, game.future3, game.future4)
 
-	def decodeSingle(self, input, game = Game(), offset = None):
-		with readable(input) as read:
-			decData = {}
+	def encodeMultiple(self, games):
+		message = struct.pack(self.countFormat, len(games))
+		for game in games:
+			message += self.encodeSingle(game)
+		return message
 
-			if   offset != None and read == None:
-				def unpack():
-					return self.gameFormat.unpack_from(out, offset)
-			elif not read:
-				def unpack():
-					return self.gameFormat.unpack(input)
-			else:
-				def unpack():
-					data = read.read(self.size)
-					if len(data) != self.size:
-						return None
-					return self.gameFormat.unpack(data)
-
-			data = unpack()
-			if not data:
-				return None
+	def decodeSingle(self, data, game = Game(None)):
+		decData = {}
 
+		if   parse_version(self.version) >= parse_version('2.0'):
+			(decData['name'], game.size, game.flags, decData['host'], game.maxPlayers, game.currentPlayers,
+				game.user1, game.user2, game.user3, game.user4) = struct.unpack(self.gameFormat, data)
+		elif parse_version(self.version) >= parse_version('2.2'):
 			(decData['name'], game.size, game.flags, decData['host'], game.maxPlayers, game.currentPlayers,
 				game.user1, game.user2, game.user3, game.user4,
 				game.misc, game.extra, decData['multiplayer-version'], game.modlist, game.lobbyVersion,
 				game.game_version_major, game.game_version_minor, game.private, game.pure, game.Mods, game.future1,
-				game.future2, game.future3, game.future4) = data
+				game.future2, game.future3, game.future4) = struct.unpack(self.gameFormat, data)
 
-			for strKey in ['name', 'host', 'multiplayer-version']:
-				decData[strKey] = decData[strKey].strip("\0")
+		for strKey in ['name', 'host', 'multiplayer-version']:
+			decData[strKey] = decData[strKey].strip("\0")
 
-			game.misc = game.misc.strip("\0")
-			game.extra = game.extra.strip("\0")
-			game.modlist = game.modlist.strip("\0")
+		game.misc = game.misc.strip("\0")
+		game.extra = game.extra.strip("\0")
+		game.modlist = game.modlist.strip("\0")
 
-			game.data.update(decData)
-			return game
+		game.data.update(decData)
+		return game
 
-def Protocol(version = '2.2'):
-	if   parse_version('2.0') <= parse_version(version) < parse_version('2.1'):
-		return BinaryProtocol20(version)
-	elif parse_version('2.1') <= parse_version(version) < parse_version('2.2'):
-		return BinaryProtocol21(version)
-	elif parse_version('2.2') <= parse_version(version):
-		return BinaryProtocol22(version)
+	def decodeMultiple(self, data):
+		countMsg = data[:countSize]
+		data = data[countSize:]
+		count = struct.pack(self.countFormat, countMsg)
+		return [self.decodeSingle(data[size * i: size * i + size]) for i in range(count)]
diff --git a/tools/masterserver/wzmasterserver.py b/tools/masterserver/wzmasterserver.py
index 4a53149..67aa2b3 100755
--- a/tools/masterserver/wzmasterserver.py
+++ b/tools/masterserver/wzmasterserver.py
@@ -44,7 +44,6 @@ import socket
 from threading import Lock, Thread, Event, Timer
 import select
 import logging
-import traceback
 import cmd
 from game import *
 from protocol import *
@@ -52,6 +51,7 @@ from protocol import *
 ################################################################################
 # Settings.
 
+lobbyPort = 9990         # Lobby port.
 checkInterval = 100      # Interval between requests causing a gamedb check
 
 MOTDstring = None        # our message of the day (max 255 bytes)
@@ -123,7 +123,7 @@ class GameDB:
 
 requests = 0
 requestlock = Lock()
-protocol = Protocol()
+protocol = BinaryProtocol()
 
 class RequestHandler(SocketServer.ThreadingMixIn, SocketServer.StreamRequestHandler):
 	def handle(self):
@@ -163,34 +163,33 @@ class RequestHandler(SocketServer.ThreadingMixIn, SocketServer.StreamRequestHand
 				logging.debug("(%s) Adding gameserver..." % gameHost)
 				try:
 					# create a game object
-					g = Game()
-					g.requestHandler = self
+					g = Game(self)
 					# put it in the database
 					gamedb.addGame(g)
 
 					# and start receiving updates about the game
 					while True:
-						newGameData = protocol.decodeSingle(self.rfile, g)
+						newGameData = self.rfile.read(protocol.size)
 						if not newGameData:
 							logging.debug("(%s) Removing aborted game" % gameHost)
 							return
 
-						logging.debug("(%s) Updated game: %s" % (gameHost, g))
+						logging.debug("(%s) Updating game..." % gameHost)
+						#set Gamedata
+						protocol.decodeSingle(newGameData, g)
+						logging.debug(g)
 						#set gamehost
 						g.host = gameHost
 
-						if not protocol.check(g):
+						if not g.check():
 							logging.debug("(%s) Removing unreachable game" % gameHost)
 							return
 
 						gamedb.listGames()
 				except struct.error, e:
-					logging.warning("(%s) Data decoding error: %s" % (gameHost, traceback.format_exc()))
+					logging.warning("(%s) Data decoding error: %s" % (gameHost, e))
 				except KeyError, e:
-					logging.warning("(%s) Communication error: %s" % (gameHost, traceback.format_exc()))
-				except:
-					logging.error("(%s) Unhandled exception: %s" % (gameHost, traceback.format_exc()))
-					raise
+					logging.warning("(%s) Communication error: %s" % (gameHost, e))
 				finally:
 					if g:
 						gamedb.removeGame(g)
@@ -199,18 +198,14 @@ class RequestHandler(SocketServer.ThreadingMixIn, SocketServer.StreamRequestHand
 			elif netCommand == 'list':
 				# Lock the gamelist to prevent new games while output.
 				with gamedblock:
-					try:
-						gamesCount = len(gamedb.getGames())
-						logging.debug("(%s) Gameserver list: %i game(s)" % (gameHost, gamesCount))
-
-						# Transmit the games.
-						for game in gamedb.getGames():
-							logging.debug(" %s" % game)
-						protocol.encodeMultiple(gamedb.getGames(), self.wfile)
-						break
-					except:
-						logging.error("(%s) Unhandled exception: %s" % (gameHost, traceback.format_exc()))
-						raise
+					gamesCount = len(gamedb.getGames())
+					logging.debug("(%s) Gameserver list: %i game(s)" % (gameHost, gamesCount))
+
+					# Transmit the games.
+					for game in gamedb.getGames():
+						logging.debug(" %s" % game)
+					self.wfile.write(protocol.encodeMultiple(gamedb.getGames()))
+					break
 
 			# If something unknown appears.
 			else:
@@ -221,7 +216,7 @@ class RequestHandler(SocketServer.ThreadingMixIn, SocketServer.StreamRequestHand
 # The legendary Main.
 
 if __name__ == '__main__':
-	logging.info("Starting Warzone 2100 lobby server on port %d" % (protocol.lobbyPort))
+	logging.info("Starting Warzone 2100 lobby server on port %d" % lobbyPort)
 
 	# Read in the Message of the Day, max is 1 line, 255 chars
 	in_file = open("motd.txt", "r")
@@ -233,7 +228,7 @@ if __name__ == '__main__':
 	gamedb = GameDB()
 
 	SocketServer.ThreadingTCPServer.allow_reuse_address = True
-	tcpserver = SocketServer.ThreadingTCPServer(('0.0.0.0', protocol.lobbyPort), RequestHandler)
+	tcpserver = SocketServer.ThreadingTCPServer(('0.0.0.0', lobbyPort), RequestHandler)
 	try:
 		while True:
 			tcpserver.handle_request()
diff --git a/tools/masterserver/wztest.py b/tools/masterserver/wztest.py
index 48f1b41..e5fb6d1 100755
--- a/tools/masterserver/wztest.py
+++ b/tools/masterserver/wztest.py
@@ -17,10 +17,6 @@
 # --------------------------------------------------------------------------
 #
 ################################################################################
-# import from __future__
-from __future__ import with_statement
-
-################################################################################
 #
 
 __author__ = "Gerhard Schaden"
@@ -33,18 +29,15 @@ This script simulates a Warzone 2100 2.x client to test the masterserver
 ################################################################################
 #
 
+import wzmasterserver as wz
+import socket
 import logging
 from threading import Timer
 import SocketServer
 import time
 import struct
-from game import *
-from protocol import *
-from protocol import _socket as socket
 
 server="lobby.wz2100.net"
-protocol = BinaryProtocol('2.2')
-logging.basicConfig(level = logging.DEBUG, format = "%(asctime)-15s %(levelname)s %(message)s")
 
 # simulate a gameserver
 class RequestHandler(SocketServer.ThreadingMixIn, SocketServer.StreamRequestHandler):
@@ -53,14 +46,16 @@ class RequestHandler(SocketServer.ThreadingMixIn, SocketServer.StreamRequestHand
 
 def simulateGameServer():
 	SocketServer.ThreadingTCPServer.allow_reuse_address = True
-	tcpserver = SocketServer.ThreadingTCPServer(('0.0.0.0', protocol.gamePort), RequestHandler)
+	tcpserver = SocketServer.ThreadingTCPServer(('0.0.0.0', wz.gamePort), RequestHandler)
 	tcpserver.handle_request()
 	tcpserver.server_close()
 
+
 # thread with simulates adding a game
 def doAddGame():
+
 	# gamestrucuure
-	g = Game()
+	g=wz.Game()
 	g.description = "description"
 	g.size = 0
 	g.flags = 0
@@ -71,33 +66,33 @@ def doAddGame():
 	g.user2 = 0
 	g.user3 = 0
 	g.user4 = 0
-	g.multiplayerVersion = protocol.version
-	g.modlist = '\0'
-	g.lobbyVersion = 2
-	g.game_version_major = int(protocol.version[0])
-	g.game_version_minor = int(protocol.version[2])
-	g.private = 0
-	g.pure = 0
-	g.Mods = 0
-	g.future1 = 0
-	g.future2 = 0
-	g.future3 = 0
-	g.future4 = 0
 
-	with socket() as s:
-		logging.debug("connect to lobby")
-		s.settimeout(10.0)
-		s.connect((server, protocol.lobbyPort))
-		s.send("addg\0")
-		protocol.encodeSingle(g, s)
-		#hold the game open for 10 seconds
-		time.sleep(10)
+	s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+	logging.debug("connect to lobby")
+	s.settimeout(10.0)
+	s.connect((server, wz.lobbyPort))
+	s.send("addg ")
+	s.send(g.getData())
+	#hold the game open for 10 seconds
+	time.sleep(10)
+	s.close()
 
 #thread with simulates listing the available games
 def doListGames():
-	logging.debug("Listing games...")
-	for game in protocol.list(server):
-		logging.debug("Game: %s" % (game))
+	s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+	logging.debug("connect to lobby")
+	s.settimeout(10.0)
+	s.connect((server, wz.lobbyPort))
+	s.send("list ")
+	n = struct.unpack("!I", s.recv(4))[0]
+	logging.debug("read %d games" % n)
+	for i in range(n):
+		g = wz.Game()
+		g.setData(s.recv(wz.gsSize))
+		logging.debug("%s" % g)
+
+	#hold the game open for 10 seconds
+	s.close()
 
 #start gameserver
 t=Timer(0, simulateGameServer)

