Index: src/display.c
===================================================================
--- src/display.c	(revision 9911)
+++ src/display.c	(working copy)
@@ -2196,10 +2196,11 @@
 		{
 			MAPTILE *psTile = mapTile(mouseTileX, mouseTileY);
 
-			CONPRINTF(ConsoleString, (ConsoleString, "%s tile %d, %d [%d, %d] continent(l%d, h%d) level %g illum %d",
+			CONPRINTF(ConsoleString, (ConsoleString, "%s tile %d, %d [%d, %d] continent(l%d, h%d) level %g illum %d watchers %d sensors %d jammers %d",
 			          tileIsExplored(psTile) ? "Explored" : "Unexplored",
 			          mouseTileX, mouseTileY, world_coord(mouseTileX), world_coord(mouseTileY),
-			          (int)psTile->limitedContinent, (int)psTile->hoverContinent, psTile->level, (int)psTile->illumination));
+			          (int)psTile->limitedContinent, (int)psTile->hoverContinent, psTile->level, (int)psTile->illumination,
+			          (int)psTile->watchers[selectedPlayer], (int)psTile->sensors[selectedPlayer], (int)psTile->jammers[selectedPlayer])); 
 		}
 
 		driveDisableTactical();
Index: src/combat.c
===================================================================
--- src/combat.c	(revision 9911)
+++ src/combat.c	(working copy)
@@ -58,9 +58,6 @@
 // maximum random pause for firing
 #define RANDOM_PAUSE	500
 
-// visibility level below which the to hit chances are reduced
-#define VIS_ATTACK_MOD_LEVEL	150
-
 /* direction array for missed bullets */
 typedef struct _bul_dir
 {
@@ -181,7 +178,7 @@
 		return;
 	}
 
-	if (!psTarget->visible[psAttacker->player])
+	if (psTarget->visible[psAttacker->player] != UBYTE_MAX)
 	{
 		// Can't see it - can't hit it
 		objTrace(psAttacker->id, "combFire(%u[%s]->%u): Object has no indirect sight of target", psAttacker->id, psStats->pName, psTarget->id);
@@ -319,13 +316,6 @@
 	// increment the shots counter
 	psWeap->shotsFired++;
 
-	// visibility modifiers
-	//if (psTarget->visible[psAttacker->player] < VIS_ATTACK_MOD_LEVEL)
-	if (psTarget->visible[psAttacker->player] == 0)		//not sure if this can ever be > 0 here
-	{
-		resultHitChance = INVISIBLE_ACCURACY_PENALTY * resultHitChance / 100;
-	}
-
 	dice = gameRand(100);
 
 	// see if we were lucky to hit the target
Index: src/map.c
===================================================================
--- src/map.c	(revision 9911)
+++ src/map.c	(working copy)
@@ -168,9 +168,12 @@
 		psTile->illumination = 255;
 		psTile->level = psTile->illumination;
 		memset(psTile->watchers, 0, sizeof(psTile->watchers));
+		memset(psTile->sensors, 0, sizeof(psTile->sensors));
+		memset(psTile->jammers, 0, sizeof(psTile->jammers));
 		psTile->colour= WZCOL_WHITE;
 		psTile->tileExploredBits = 0;
 		psTile->sensorBits = 0;
+		psTile->jammerBits = 0;
 		psTile++;
 	}
 
@@ -938,7 +941,10 @@
 
 		// Visibility stuff
 		memset(psMapTiles[i].watchers, 0, sizeof(psMapTiles[i].watchers));
+		memset(psMapTiles[i].sensors, 0, sizeof(psMapTiles[i].sensors));
+		memset(psMapTiles[i].jammers, 0, sizeof(psMapTiles[i].jammers));
 		psMapTiles[i].sensorBits = 0;
+		psMapTiles[i].jammerBits = 0;
 		psMapTiles[i].tileExploredBits = 0;
 	}
 
Index: src/map.h
===================================================================
--- src/map.h	(revision 9911)
+++ src/map.h	(working copy)
@@ -102,11 +102,14 @@
 {
 	uint8_t			tileInfoBits;
 	uint8_t			tileExploredBits;
+	uint8_t			jammerBits;		// bit per player, who is jamming tile
 	uint8_t			sensorBits;		// bit per player, who can see tile with sensor
 	float			height;			// The height at the top left of the tile
 	uint8_t			illumination;	// How bright is this tile?
 	uint16_t		texture;		// Which graphics texture is on this tile
+	uint8_t			sensors[MAX_PLAYERS];		// player sees this tile with this many radar sensors
 	uint8_t			watchers[MAX_PLAYERS];		// player sees through fog of war here with this many objects
+	uint8_t			jammers[MAX_PLAYERS];		// player jams the tile with this many objects
 	float			level;
 	BASE_OBJECT		*psObject;		// Any object sitting on the location (e.g. building)
 	PIELIGHT		colour;
Index: src/droid.h
===================================================================
--- src/droid.h	(revision 9911)
+++ src/droid.h	(working copy)
@@ -65,7 +65,6 @@
 
 /* Misc accuracy modifiers */
 #define	FOM_PARTIAL_ACCURACY_PENALTY	50	// penalty for not being fully able to fire while moving, in %
-#define	INVISIBLE_ACCURACY_PENALTY		50	// accuracy penalty for the unit firing at a target it can't see, in %
 
 /* Minumum number of droids a commander can control in its group */
 #define	MIN_CMD_GROUP_DROIDS	6
Index: src/visibility.c
===================================================================
--- src/visibility.c	(revision 9911)
+++ src/visibility.c	(working copy)
@@ -102,26 +102,6 @@
 	visLevelDecAcc -= visLevelDec;
 }
 
-// Adjust power by range
-static int adjustPowerByRange(int x1, int y1, int x2, int y2, int range, int power)
-{
-	// Original Pumpkin algorithm cleaned up and put into use
-	int	distSq = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2);
-	int	rangeSq = range * range;
-	float	mod;
-
-	if (rangeSq > 0 && distSq > 0 && power > 0)
-	{
-		mod = distSq / rangeSq;
-	}
-	else
-	{
-		return 0;
-	}
-
-	return	power - power * mod;
-}
-
 static int visObjHeight(const BASE_OBJECT * psObject)
 {
 	switch (psObject->type)
@@ -138,25 +118,61 @@
 	}
 }
 
+static inline void updateTileVis(MAPTILE *psTile)
+{
+	int i;
+
+	for (i = 0; i < MAX_PLAYERS; i++)
+	{
+		/// The definition of whether a player can see something on a given tile or not
+		if (psTile->watchers[i] > 0 || (psTile->sensors[i] > 0 && !(psTile->jammerBits & ~alliancebits[i])))
+		{
+			psTile->sensorBits |= (1 << i);		// mark it as being seen
+		}
+		else
+		{
+			psTile->sensorBits &= ~(1 << i);	// mark as hidden
+		}
+	}
+}
+
 /* Record all tiles that some object confers visibility to. Only record each tile
  * once. Note that there is both a limit to how many objects can watch any given
  * tile, and a limit to how many tiles each object can watch. Strange but non fatal
- * things will happen if these limits are exceeded. This function uses icky globals. */
-static inline void visMarkTile(int mapX, int mapY, MAPTILE *psTile, int rayPlayer, TILEPOS *recordTilePos, int *lastRecordTilePos)
+ * things will happen if these limits are exceeded. */
+static inline void visMarkTile(const BASE_OBJECT *psObj, int mapX, int mapY, MAPTILE *psTile, TILEPOS *recordTilePos, int *lastRecordTilePos)
 {
-	if (psTile->watchers[rayPlayer] < UBYTE_MAX && *lastRecordTilePos < MAX_SEEN_TILES)
+	const int rayPlayer = psObj->player;
+	const int xdiff = map_coord(psObj->pos.x) - mapX;
+	const int ydiff = map_coord(psObj->pos.y) - mapY;
+	const int distSq = xdiff * xdiff + ydiff * ydiff;
+	const bool inRange = (distSq < 16);
+	uint8_t *visionType = inRange ? psTile->watchers : psTile->sensors;
+
+	if (visionType[rayPlayer] < UBYTE_MAX && *lastRecordTilePos < MAX_SEEN_TILES)
 	{
-		TILEPOS tilePos = {mapX, mapY};
-		psTile->watchers[rayPlayer]++;                  // we see this tile
-		psTile->sensorBits |= (1 << rayPlayer);		// mark it as being seen
+		TILEPOS tilePos = { mapX, mapY, inRange };
+
+		visionType[rayPlayer]++;                  	// we observe this tile
+		if (objJammerPower(psObj) > 0)			// we are a jammer object
+		{
+			psTile->jammers[rayPlayer]++;
+			psTile->jammerBits |= (1 << rayPlayer);	// mark it as being jammed
+		}
+		updateTileVis(psTile);
 		recordTilePos[*lastRecordTilePos] = tilePos;    // record having seen it
 		++*lastRecordTilePos;
 	}
 }
 
 /* The terrain revealing ray callback */
-static void doWaveTerrain(int sx, int sy, int sz, unsigned radius, int rayPlayer, TILEPOS *recordTilePos, int *lastRecordTilePos)
+static void doWaveTerrain(const BASE_OBJECT *psObj, TILEPOS *recordTilePos, int *lastRecordTilePos)
 {
+	const int sx = psObj->pos.x;
+	const int sy = psObj->pos.y;
+	const int sz = psObj->pos.z + visObjHeight(psObj);
+	const unsigned radius = objSensorRange(psObj);
+	const int rayPlayer = psObj->player;
 	size_t i;
 	size_t size;
 	const WAVECAST_TILE *tiles = getWavecastTable(radius, &size);
@@ -230,7 +246,7 @@
 		{
 			// Can see this tile.
 			psTile->tileExploredBits |= alliancebits[rayPlayer];                            // Share exploration with allies too
-			visMarkTile(mapX, mapY, psTile, rayPlayer, recordTilePos, lastRecordTilePos);   // Mark this tile as seen by our sensor
+			visMarkTile(psObj, mapX, mapY, psTile, recordTilePos, lastRecordTilePos);   // Mark this tile as seen by our sensor
 		}
 	}
 }
@@ -293,19 +309,34 @@
 {
 	if (psObj->watchedTiles && psObj->numWatchedTiles > 0)
 	{
-		int i = 0;
+		int i;
 
 		for (i = 0; i < psObj->numWatchedTiles; i++)
 		{
 			const TILEPOS pos = psObj->watchedTiles[i];
 			MAPTILE *psTile = mapTile(pos.x, pos.y);
 
-			ASSERT(psTile->watchers > 0, "Not watching watched tile (%d, %d)", (int)pos.x, (int)pos.y);
-			psTile->watchers[psObj->player]--;
-			if (psTile->watchers[psObj->player] == 0)
+			ASSERT(pos.type < 2, "Invalid visibility type %d", (int)pos.type);
+			if (pos.type == 1)
 			{
-				psTile->sensorBits &= ~(1 << psObj->player);
+				ASSERT(psTile->watchers[psObj->player] > 0, "Not watching watched tile (%d, %d)", (int)pos.x, (int)pos.y);
+				psTile->watchers[psObj->player]--;
 			}
+			else
+			{
+				ASSERT(psTile->sensors[psObj->player] > 0, "No sensor on tile (%d, %d)", (int)pos.x, (int)pos.y);
+				psTile->sensors[psObj->player]--;
+			}
+			if (objJammerPower(psObj) > 0)			// we are a jammer object
+			{
+				ASSERT(psTile->jammers[psObj->player] > 0, "Not jamming watched tile (%d, %d)", (int)pos.x, (int)pos.y);
+				psTile->jammers[psObj->player]--;
+				if (psTile->jammers[psObj->player] == 0)
+				{
+					psTile->jammerBits &= ~(1 << psObj->player);
+				}
+			}
+			updateTileVis(psTile);
 		}
 		free(psObj->watchedTiles);
 		psObj->watchedTiles = NULL;
@@ -343,7 +374,7 @@
 	}
 
 	// Do the whole circle in ∞ steps. No more pretty moiré patterns.
-	doWaveTerrain(psObj->pos.x, psObj->pos.y, psObj->pos.z + visObjHeight(psObj), objSensorRange(psObj), psObj->player, recordTilePos, &lastRecordTilePos);
+	doWaveTerrain(psObj, recordTilePos, &lastRecordTilePos);
 
 	// Record new map visibility provided by object
 	if (lastRecordTilePos > 0)
@@ -383,7 +414,8 @@
 {
 	Vector3i pos, dest, diff;
 	int range, distSq;
-	int	power;
+	bool tileSeen, jammed;
+	MAPTILE *psTile;
 
 	ASSERT(psViewer != NULL, "Invalid viewer pointer!");
 	ASSERT(psTarget != NULL, "Invalid viewed pointer!");
@@ -399,17 +431,13 @@
 	diff = Vector3i_Sub(dest, pos);
 	range = objSensorRange(psViewer);
 
-	/* Get the sensor Range and power */
+	/* Get the sensor range */
 	switch (psViewer->type)
 	{
 		case OBJ_DROID:
 		{
 			DROID *psDroid = (DROID *)psViewer;
 
-			if (psDroid->droidType == DROID_COMMAND)
-			{
-				range = 3 * range / 2;
-			}
 			if (psDroid->psTarget == psTarget
 			    && (cbSensorDroid(psDroid) || objRadarDetector((BASE_OBJECT *)psDroid)))
 			{
@@ -442,15 +470,6 @@
 				// it is automatically seen
 				return UBYTE_MAX;
 			}
-
-			// increase the sensor range for AA sites
-			// AA sites are defensive structures that can only shoot in the air
-			if (psStruct->pStructureType->type == REF_DEFENSE
-				&& asWeaponStats[psStruct->asWeaps[0].nStat].surfaceToAir == SHOOT_IN_AIR)
-			{
-				range = 3 * range / 2;
-			}
-
 			break;
 		}
 		default:
@@ -459,12 +478,6 @@
 			break;
 	}
 
-	// Structures can be seen from further away
-	if (psTarget->type == OBJ_STRUCTURE)
-	{
-		range = 4 * range / 3;
-	}
-
 	/* First see if the target is in sensor range */
 	distSq = Vector3i_ScalarP(diff, diff);
 	if (distSq == 0)
@@ -473,44 +486,39 @@
 		return UBYTE_MAX;
 	}
 
-	if (distSq > (range*range))
+	psTile = mapTile(map_coord(psTarget->pos.x), map_coord(psTarget->pos.y));
+	jammed = psTile->jammerBits & ~alliancebits[psViewer->player];
+	tileSeen = psTile->watchers[psViewer->player] > 0 || (psTile->sensors[psViewer->player] > 0 && !jammed);
+
+	// Special rule for jammer objects - we can locate them easily by their massive and disruptive EM emissions
+	if (!tileSeen && objJammerPower(psTarget) > 0 && distSq < (range * range))
 	{
 		/* Out of sensor range */
-		return 0;
+		return UBYTE_MAX / 2;
 	}
 
-	power = adjustPowerByRange(psViewer->pos.x, psViewer->pos.y, psTarget->pos.x, psTarget->pos.y, range, objSensorPower(psViewer));
+	// Special rule for VTOLs
+	if (psTarget->type == OBJ_DROID && isVtolDroid((DROID *)psTarget))
 	{
-		// initialise the callback variables
-		VisibleObjectHelp_t help = { true, wallsBlock, distSq, pos.z + visObjHeight(psViewer), { map_coord(dest.x), map_coord(dest.y) }, 0, 0, -UBYTE_MAX * GRAD_MUL * ELEVATION_SCALE, 0, { 0, 0 } };
-		int targetGrad, top;
+		// increase vision range of AA vs VTOL
+		// asWeaponStats[psStruct->asWeaps[0].nStat].surfaceToAir == SHOOT_IN_AIR
+		// range = 3 * range / 2;
 
-		// Cast a ray from the viewer to the target
-		rayCast(pos, diff, range, rayLOSCallback, &help);
-
-		if (gWall != NULL && gNumWalls != NULL) // Out globals are set
+		if (distSq < (range * range))
 		{
-			*gWall = help.wall;
-			*gNumWalls = help.numWalls;
+			return UBYTE_MAX;
 		}
+	}
 
-		// See if the target can be seen
-		top = dest.z + visObjHeight(psTarget) - help.startHeight;
-		targetGrad = top * GRAD_MUL / MAX(1, help.lastDist);
+#if 0
+// if we want jam-hidden units to appear as radar blips...
+	if (!tileSeen && psTile->sensors[psViewer->player] > 0 && jammed)
+	{
+		return UBYTE_MAX / 2;
+	}
+#endif
 
-		if (targetGrad >= help.currGrad)
-		{
-			if (power > objJammerPower(psTarget))
-			{
-				return UBYTE_MAX;
-			}
-			else
-			{
-				return UBYTE_MAX / 2;
-			}
-		}
-	}
-	return 0;
+	return tileSeen ? UBYTE_MAX : 0;
 }
 
 
Index: src/ai.c
===================================================================
--- src/ai.c	(revision 9911)
+++ src/ai.c	(working copy)
@@ -293,7 +293,7 @@
 			targetInQuestion = NULL;
 
 			/* Can we see what it is doing? */
-			if(friendlyObj->visible[psDroid->player])
+			if(friendlyObj->visible[psDroid->player] == UBYTE_MAX)
 			{
 				if(friendlyObj->type == OBJ_DROID)
 				{
@@ -332,7 +332,7 @@
 		if (targetInQuestion != NULL
 		    && targetInQuestion != (BASE_OBJECT *)psDroid		// in case friendly unit had me as target
 		    && (targetInQuestion->type == OBJ_DROID || targetInQuestion->type == OBJ_STRUCTURE || targetInQuestion->type == OBJ_FEATURE)
-		    && targetInQuestion->visible[psDroid->player]
+		    && targetInQuestion->visible[psDroid->player] == UBYTE_MAX
 		    && !aiCheckAlliances(targetInQuestion->player,psDroid->player)
 		    && validTarget((BASE_OBJECT *)psDroid, targetInQuestion, weapon_slot)
 		    && aiDroidHasRange(psDroid, targetInQuestion, weapon_slot))
@@ -866,7 +866,7 @@
 				/* Check that it is a valid target */
 				if (psCurr->type != OBJ_FEATURE && !aiObjectIsProbablyDoomed(psCurr) && aiStructHasRange((STRUCTURE *)psObj, psCurr, weapon_slot)
 				    && !aiCheckAlliances(psCurr->player, psObj->player)
-				    && validTarget(psObj, psCurr, weapon_slot) && psCurr->visible[psObj->player])
+				    && validTarget(psObj, psCurr, weapon_slot) && psCurr->visible[psObj->player] == UBYTE_MAX)
 				{
 					// See if in sensor range and visible
 					int distSq = objPosDiffSq(psCurr->pos, psObj->pos);
@@ -995,7 +995,7 @@
 					const int ydiff = psCurr->pos.y - psObj->pos.y;
 					const unsigned int distSq = xdiff * xdiff + ydiff * ydiff;
 
-					if (distSq < radSquared && psCurr->visible[psObj->player] && distSq < tarDist)
+					if (distSq < radSquared && psCurr->visible[psObj->player] == UBYTE_MAX && distSq < tarDist)
 					{
 						psTemp = psCurr;
 						tarDist = distSq;
Index: src/visibility.h
===================================================================
--- src/visibility.h	(revision 9911)
+++ src/visibility.h	(working copy)
@@ -84,7 +84,7 @@
 
 static inline int objJammerPower(WZ_DECL_UNUSED const BASE_OBJECT* psObj)
 {
-	return 0;
+	return psObj->ECMMod;
 }
 
 static inline int objJammerRange(WZ_DECL_UNUSED const BASE_OBJECT* psObj)
@@ -94,7 +94,7 @@
 
 static inline int objConcealment(const BASE_OBJECT* psObj)
 {
-	return psObj->ECMMod;
+	return 0;
 }
 
 void objSensorCache(BASE_OBJECT *psObj, SENSOR_STATS *psSensor);
Index: src/basedef.h
===================================================================
--- src/basedef.h	(revision 9911)
+++ src/basedef.h	(working copy)
@@ -49,6 +49,7 @@
 typedef struct _tilePos
 {
 	UBYTE x, y;
+	UBYTE type;	///< Type of vision given to this tile
 } TILEPOS;
 
 /*
Index: data/base/wrf/limiter_tex.wrf
===================================================================
--- data/base/wrf/limiter_tex.wrf	(revision 9911)
+++ data/base/wrf/limiter_tex.wrf	(working copy)
@@ -25,3 +25,4 @@
 file		TEXPAGE	"page-24-fx.png"
 file		TEXPAGE "page-28-naval.png"
 file		TEXPAGE "page-59-more-weapons.png"
+file		TEXPAGE "page-29-ecm.png"
Index: data/mp/components/weapons/miecm.pie
===================================================================
--- data/mp/components/weapons/miecm.pie	(revision 0)
+++ data/mp/components/weapons/miecm.pie	(revision 0)
@@ -0,0 +1,230 @@
+PIE 3
+TYPE 0
+TEXTURE 0 page-29-ecm.png 0 0
+LEVELS 1
+LEVEL 1
+POINTS 86 
+	-3 18 5 
+	-6 21 0 
+	-3 18 -5 
+	6 21 0 
+	3 18 5 
+	3 18 -5 
+	-15 14 25 
+	-17 13 25 
+	-17 15 25 
+	7 19 -6 
+	7 19 -22 
+	0 14 -6 
+	0 14 -22 
+	-7 19 -6 
+	-7 19 -22 
+	-4 27 -6 
+	-4 27 -22 
+	4 27 -6 
+	4 27 -22 
+	-4 20 -6 
+	-2 25 -6 
+	2 25 -6 
+	4 20 -6 
+	2 25 13 
+	4 20 13 
+	0 16 -6 
+	0 16 13 
+	-4 20 13 
+	-2 25 13 
+	-19 28 12 
+	-19 20 8 
+	-20 28 2 
+	-20 21 0 
+	-19 13 12 
+	-20 13 2 
+	20 1 0 
+	10 1 17 
+	19 4 0 
+	9 4 16 
+	-10 1 17 
+	-20 1 0 
+	-9 4 16 
+	-19 4 0 
+	-10 1 -17 
+	10 1 -17 
+	-9 4 -16 
+	9 4 -16 
+	3 9 5 
+	-3 9 5 
+	-6 9 0 
+	-3 9 -5 
+	3 9 -5 
+	6 9 0 
+	-19 13 10 
+	-19 15 10 
+	0 13 21 
+	19 13 12 
+	0 13 10 
+	20 13 2 
+	19 20 8 
+	0 20 17 
+	19 28 12 
+	0 28 21 
+	0 21 8 
+	20 28 2 
+	20 21 0 
+	-18 14 10 
+	0 28 10 
+	-15 27 25 
+	-17 26 25 
+	-17 28 25 
+	-19 26 10 
+	-19 28 10 
+	-18 27 10 
+	15 14 25 
+	17 15 25 
+	17 13 25 
+	19 13 10 
+	19 15 10 
+	18 14 10 
+	15 27 25 
+	17 28 25 
+	17 26 25 
+	19 26 10 
+	19 28 10 
+	18 27 10
+POLYGONS 137
+	200 3 0 1 2 224 141 230 153 224 166
+	200 3 3 4 5 205 153 211 141 211 166
+	200 3 6 7 8 129 79 133 86 137 78
+	200 3 9 10 11 209 70 209 1 187 70
+	200 3 12 11 10 187 1 187 70 209 1
+	200 3 13 14 15 172 70 172 1 152 70
+	200 3 16 15 14 152 1 152 70 172 1
+	200 3 17 18 9 232 70 232 1 209 70
+	200 3 10 9 18 209 1 209 70 232 1
+	200 3 13 15 19 172 70 152 70 172 85
+	200 3 20 19 15 152 85 172 85 152 70
+	200 3 17 9 21 232 70 209 70 232 85
+	200 3 22 21 9 209 85 232 85 209 70
+	200 3 21 22 23 232 85 209 85 232 138
+	200 3 24 23 22 209 138 232 138 209 85
+	200 3 25 19 26 187 85 172 85 187 138
+	200 3 27 26 19 172 138 187 138 172 85
+	200 3 20 21 28 253 85 232 85 253 138
+	200 3 23 28 21 232 138 253 138 232 85
+	200 3 29 30 31 111 35 111 18 70 32
+	200 3 32 31 30 70 16 70 32 111 18
+	200 3 33 34 30 111 4 70 1 111 18
+	200 3 32 30 34 70 16 111 18 70 1
+	200 3 35 36 37 0 194 0 209 4 194
+	200 3 38 37 36 4 209 4 194 0 209
+	200 3 39 40 41 0 225 0 240 4 225
+	200 3 42 41 40 4 240 4 225 0 240
+	200 3 43 44 45 0 164 0 179 4 164
+	200 3 46 45 44 4 179 4 164 0 179
+	200 3 38 41 47 4 209 4 225 14 209
+	200 3 48 47 41 14 225 14 209 4 225
+	200 3 42 45 49 4 240 4 255 14 240
+	200 3 50 49 45 14 255 14 240 4 255
+	200 3 46 37 51 4 179 4 194 14 179
+	200 3 52 51 37 14 194 14 179 4 194
+	200 3 3 52 4 25 194 14 194 20 209
+	200 3 47 4 52 14 209 20 209 14 194
+	200 3 1 0 49 25 240 20 225 14 240
+	200 3 49 0 48 14 240 20 225 14 225
+	200 3 50 51 2 14 164 14 179 20 164
+	200 3 5 2 51 20 179 20 164 14 179
+	200 3 4 0 5 211 141 224 141 211 166
+	200 3 5 0 2 211 166 224 141 224 166
+	200 3 7 53 8 121 78 121 3 113 78
+	200 3 54 8 53 113 3 113 78 121 3
+	200 3 55 56 57 144 120 144 93 135 120
+	200 3 58 57 56 135 87 135 120 144 93
+	200 3 55 57 33 144 120 135 120 144 148
+	200 3 34 33 57 135 154 144 148 135 120
+	200 3 59 60 61 36 150 36 75 8 146
+	200 3 62 61 60 8 76 8 146 36 75
+	200 3 62 60 29 8 76 36 75 8 6
+	200 3 30 29 60 36 1 8 6 36 75
+	200 3 57 63 34 135 120 124 120 135 154
+	200 3 32 34 63 124 154 135 154 124 120
+	200 3 30 60 33 36 1 36 75 66 5
+	200 3 55 33 60 66 74 66 5 36 75
+	200 3 10 18 12 206 228 216 199 230 247
+	200 3 14 12 18 254 228 230 247 216 199
+	200 3 18 16 14 216 199 245 199 254 228
+	200 3 11 12 13 187 70 187 1 172 70
+	200 3 14 13 12 172 1 172 70 187 1
+	200 3 15 16 17 253 70 253 1 232 70
+	200 3 18 17 16 232 1 232 70 253 1
+	200 3 13 19 11 172 70 172 85 187 70
+	200 3 25 11 19 187 85 187 70 172 85
+	200 3 15 17 20 253 70 232 70 253 85
+	200 3 21 20 17 232 85 253 85 232 70
+	200 3 9 11 22 209 70 187 70 209 85
+	200 3 25 22 11 187 85 209 85 187 70
+	200 3 22 25 24 209 85 187 85 209 138
+	200 3 26 24 25 187 138 209 138 187 85
+	200 3 19 20 27 172 85 152 85 172 138
+	200 3 28 27 20 152 138 172 138 152 85
+	200 3 61 64 59 111 116 70 119 111 133
+	200 3 65 59 64 70 134 111 133 70 119
+	200 3 56 59 58 111 147 111 133 70 150
+	200 3 65 58 59 70 134 70 150 111 133
+	200 3 35 44 36 222 174 230 190 230 158
+	200 3 39 36 44 246 158 230 158 230 190
+	200 3 44 43 39 230 190 246 190 246 158
+	200 3 40 39 43 254 174 246 158 246 190
+	200 3 36 39 38 0 209 0 225 4 209
+	200 3 41 38 39 4 225 4 209 0 225
+	200 3 40 43 42 0 240 0 255 4 240
+	200 3 45 42 43 4 255 4 240 0 255
+	200 3 44 35 46 0 179 0 194 4 179
+	200 3 37 46 35 4 194 4 179 0 194
+	200 3 41 42 48 4 225 4 240 14 225
+	200 3 49 48 42 14 240 14 225 4 240
+	200 3 45 46 50 4 164 4 179 14 164
+	200 3 51 50 46 14 179 14 164 4 179
+	200 3 37 38 52 4 194 4 209 14 194
+	200 3 47 52 38 14 209 14 194 4 209
+	200 3 47 48 4 14 209 14 225 20 209
+	200 3 0 4 48 20 225 20 209 14 225
+	200 3 1 49 2 25 240 14 240 20 255
+	200 3 50 2 49 14 255 20 255 14 240
+	200 3 3 5 52 25 194 20 179 14 194
+	200 3 51 52 5 14 179 14 194 20 179
+	200 3 66 53 6 129 3 121 3 129 79
+	200 3 7 6 53 121 78 129 79 121 3
+	200 3 54 66 8 137 3 129 3 137 78
+	200 3 6 8 66 129 79 137 78 129 3
+	200 3 62 67 61 111 75 70 75 111 116
+	200 3 64 61 67 70 119 111 116 70 75
+	200 3 62 29 67 111 75 111 35 70 75
+	200 3 31 67 29 70 32 70 75 111 35
+	200 3 65 64 63 124 87 114 89 124 120
+	200 3 67 63 64 114 120 124 120 114 89
+	200 3 67 31 63 114 120 114 152 124 120
+	200 3 32 63 31 124 154 124 120 114 152
+	200 3 65 63 58 124 87 124 120 135 87
+	200 3 57 58 63 135 120 135 87 124 120
+	200 3 55 60 56 66 74 36 75 66 145
+	200 3 59 56 60 36 150 66 145 36 75
+	200 3 68 69 70 129 79 133 86 137 78
+	200 3 69 71 70 121 78 121 3 113 78
+	200 3 72 70 71 113 3 113 78 121 3
+	200 3 73 71 68 129 3 121 3 129 79
+	200 3 69 68 71 121 78 129 79 121 3
+	200 3 72 73 70 137 3 129 3 137 78
+	200 3 68 70 73 129 79 137 78 129 3
+	200 3 74 75 76 129 79 137 78 133 86
+	200 3 76 75 77 121 78 113 78 121 3
+	200 3 78 77 75 113 3 121 3 113 78
+	200 3 79 74 77 129 3 129 79 121 3
+	200 3 76 77 74 121 78 121 3 129 79
+	200 3 78 75 79 137 3 137 78 129 3
+	200 3 74 79 75 129 79 129 3 137 78
+	200 3 80 81 82 129 79 137 78 133 86
+	200 3 82 81 83 121 78 113 78 121 3
+	200 3 84 83 81 113 3 121 3 113 78
+	200 3 85 80 83 129 3 129 79 121 3
+	200 3 82 83 80 121 78 121 3 129 79
+	200 3 84 81 85 137 3 137 78 129 3
+	200 3 80 85 81 129 79 129 3 137 78
\ No newline at end of file
Index: data/mp/messages/strings/names.txt
===================================================================
--- data/mp/messages/strings/names.txt	(revision 9911)
+++ data/mp/messages/strings/names.txt	(working copy)
@@ -1929,3 +1929,8 @@
 
 ViperLtMGHalfTracks			_("Machinegun Viper Half-Tracks")
 ViperFlameHalfTracks		_("Flamer Viper Half-Tracks")
+
+R-Sys-ECM-Upgrade01			_("ECM Upgrade")
+ECM1PylonMk1				_("Jammer Tower")
+ECM1TurretMk1				_("Jammer Turret")
+
Index: data/mp/stats/ecm.txt
===================================================================
--- data/mp/stats/ecm.txt	(revision 9911)
+++ data/mp/stats/ecm.txt	(working copy)
@@ -1,2 +1,3 @@
-ZNULLECM,Level All,0,0,0,0,0,0,0,0,DEFAULT,50,0,0
+ZNULLECM,Level All,0,0,0,0,0,0,0,0,DEFAULT,0,0,0
 RepairCentre,Level All,0,0,0,0,0,0,GNHREPAR.PIE,0,TURRET,0,0,0
+ECM1TurretMk1,Level All,0,0,0,0,0,0,miecm.pie,0,TURRET,100,4096,1
Index: data/mp/stats/research/multiplayer/resultcomponent.txt
===================================================================
--- data/mp/stats/research/multiplayer/resultcomponent.txt	(revision 9911)
+++ data/mp/stats/research/multiplayer/resultcomponent.txt	(working copy)
@@ -121,3 +121,4 @@
 R-Vehicle-Prop-VTOL,V-Tol,PROPULSION,0,0,5
 R-Vehicle-Prop-Wheels,wheeled01,PROPULSION,0,0,5
 R-Sys-RadarDetector01,RadarDetector,SENSOR,0,0,8
+R-Sys-ECM-Upgrade01,ECM1TurretMk1,ECM,0,0,0
Index: data/mp/stats/research/multiplayer/research.txt
===================================================================
--- data/mp/stats/research/multiplayer/research.txt	(revision 9911)
+++ data/mp/stats/research/multiplayer/research.txt	(working copy)
@@ -449,3 +449,4 @@
 R-Wpn-MG-Damage08,Level One,IMAGE_RES_GRPDAM,1,IMAGE_RES_WEAPONTECH,0,0,0,0,MG1Mk1,WEAPON,15200,0,2,1,0,0,0,0,0
 R-Sys-Sensor-Upgrade03,Level All,IMAGE_RES_GRPUPG,0,IMAGE_RES_SYSTEMTECH,GNLSNSR1.PIE,0,RES_SY_SU3,0,0,BODY,7200,1,2,1,0,0,0,0,0
 R-Sys-RadarDetector01,Level All,0,0,IMAGE_RES_SYSTEMTECH,0,0,RES_SY_RDST1,0,RadarDetector,SENSOR,900,0,1,0,0,0,1,0,1
+R-Sys-ECM-Upgrade01,Level All,IMAGE_RES_GRPUPG,0,IMAGE_RES_SYSTEMTECH,gnmecm1.pie,0,RES_SY_SU1,0,0,0,1800,1,1,0,0,0,1,0,1
Index: data/mp/stats/research/multiplayer/prresearch.txt
===================================================================
--- data/mp/stats/research/multiplayer/prresearch.txt	(revision 9911)
+++ data/mp/stats/research/multiplayer/prresearch.txt	(working copy)
@@ -592,3 +592,4 @@
 R-Wpn-RocketSlow-ROF02,R-Wpn-RocketSlow-ROF01,943
 R-Wpn-RocketSlow-ROF03,R-Wpn-RocketSlow-ROF02,944
 R-Sys-RadarDetector01,R-Sys-Sensor-Upgrade01,945
+R-Sys-ECM-Upgrade01,R-Sys-Sensor-Upgrade01,0
Index: data/mp/stats/research/multiplayer/resultstructure.txt
===================================================================
--- data/mp/stats/research/multiplayer/resultstructure.txt	(revision 9911)
+++ data/mp/stats/research/multiplayer/resultstructure.txt	(working copy)
@@ -83,3 +83,4 @@
 R-Sys-VTOLStrike-Tower01,Sys-VTOL-RadarTower01,0,212
 R-Wpn-LasSat,A0LasSatCommand,0,328
 R-Sys-RadarDetector01,Sys-RadarDetector01,0,0
+R-Sys-ECM-Upgrade01,ECM1PylonMk1,0,0
Index: data/mp/stats/structures.txt
===================================================================
--- data/mp/stats/structures.txt	(revision 9911)
+++ data/mp/stats/structures.txt	(working copy)
@@ -150,3 +150,4 @@
 X-Super-Missile,DOOR,Level All,HARD,0,2,2,Concrete,1600,3,15,3200,10,1600,10,100,255,1,ZNULLECM,FortressSensor,1,STWPFCAN.PIE,0,0,1
 X-Super-Rocket,DOOR,Level All,HARD,0,2,2,Concrete,1600,3,15,3200,10,1250,10,100,255,1,ZNULLECM,FortressSensor,1,STWPFCAN.PIE,0,0,1
 Sys-RadarDetector01,DEFENSE,Level All,MEDIUM,0,1,1,Concrete,400,2,15,600,10,100,10,150,255,1,ZNULLECM,RadarDetector,0,BLGUARDR.pie,0,0,0
+ECM1PylonMk1,DEFENSE,Level All,MEDIUM,0,1,1,Concrete,300,3,10,300,0,60,10,150,255,0,ECM1TurretMk1,DefaultSensor1Mk1,0,blguardr.pie,0,0,0
Index: data/mp/wrf/vidmemc.wrf
===================================================================
--- data/mp/wrf/vidmemc.wrf	(revision 9911)
+++ data/mp/wrf/vidmemc.wrf	(working copy)
@@ -34,3 +34,4 @@
 file		TEXPAGE	"page-23-fx.png"
 file		TEXPAGE	"page-24-fx.png"
 file		TEXPAGE "page-28-naval.png"
+file		TEXPAGE	"page-29-ecm.png"
Index: data/mp/wrf/piestats.wrf
===================================================================
--- data/mp/wrf/piestats.wrf	(revision 9911)
+++ data/mp/wrf/piestats.wrf	(working copy)
@@ -148,6 +148,7 @@
 file		IMD	"mifactry.pie"
 file		IMD	"miairtrf.pie"
 directory	"components/weapons"
+file		IMD	"miecm.pie"
 file		IMD	"gnmecm1.pie"
 file		IMD	"trmecm1.pie"
 file		IMD	"trlcon.pie"
Index: data/mp/wrf/vidmem2.wrf
===================================================================
--- data/mp/wrf/vidmem2.wrf	(revision 9911)
+++ data/mp/wrf/vidmem2.wrf	(working copy)
@@ -41,3 +41,4 @@
 file		TEXPAGE	"page-52-plants-on-rock.png"
 file		TEXPAGE	"page-80-water-1.png"
 file		TEXPAGE	"page-81-water-2.png"
+file		TEXPAGE	"page-29-ecm.png"
Index: data/mp/wrf/vidmem3.wrf
===================================================================
--- data/mp/wrf/vidmem3.wrf	(revision 9911)
+++ data/mp/wrf/vidmem3.wrf	(working copy)
@@ -46,3 +46,4 @@
 file		TEXPAGE	"page-47-tiles.png"
 file		TEXPAGE	"page-80-water-1.png"
 file		TEXPAGE	"page-81-water-2.png"
+file		TEXPAGE	"page-29-ecm.png"
Index: data/mp/wrf/vidmem.wrf
===================================================================
--- data/mp/wrf/vidmem.wrf	(revision 9911)
+++ data/mp/wrf/vidmem.wrf	(working copy)
@@ -42,3 +42,4 @@
 file		TEXPAGE	"page-42-rock.png"
 file		TEXPAGE	"page-80-water-1.png"
 file		TEXPAGE	"page-81-water-2.png"
+file		TEXPAGE	"page-29-ecm.png"

