Index: combat.c
===================================================================
--- combat.c	(revision 467)
+++ combat.c	(working copy)
@@ -104,9 +104,15 @@
 	//Watermelon:predicted X,Y offset per sec
 	SDWORD			predictX;
 	SDWORD			predictY;
-	//Watermelon:dirty dist
+	//Watermelon:sqrt dist
 	SDWORD			dist;
+	//Watermelon:vtolDist
+	SDWORD			vtolDist;
+	SDWORD			zDiff;
+	BOOL			bFlyingVTOL;
 
+	bFlyingVTOL = FALSE;
+
 	ASSERT( PTRVALID(psWeap, sizeof(WEAPON)),
 		"combFire: Invalid weapon pointer" );
 	ASSERT( PTRVALID(psAttacker, sizeof(BASE_OBJECT)),
@@ -343,8 +349,20 @@
 	xDiff = abs(psAttacker->x - psTarget->x);
 	yDiff = abs(psAttacker->y - psTarget->y);
 	distSquared = xDiff*xDiff + yDiff*yDiff;
-	//Watermelon:dirty dist
-	dist = dirtySqrt(psAttacker->x,psAttacker->y,psTarget->x,psTarget->y);
+	//Watermelon:actual dist
+	dist = sqrt(distSquared);
+
+	//Watermelon:need to calculate the vtol actual distance(affected by vector z)
+	if (psTarget->type == OBJ_DROID)
+	{
+		if (vtolDroid((DROID *)psTarget) && !(((DROID *)psTarget)->sMove.Status == MOVEINACTIVE))
+		{
+			zDiff = abs(psAttacker->z - psTarget->z);
+			vtolDist = (SDWORD)(sqrt(dist*dist + zDiff*zDiff));
+			bFlyingVTOL = TRUE;
+		}
+	}
+
 	longRange = proj_GetLongRange(psStats, (SDWORD)psAttacker->z-(SDWORD)psTarget->z);
 	if (distSquared <= (psStats->shortRange * psStats->shortRange) AND
 		distSquared >= (psStats->minRange * psStats->minRange))
@@ -367,12 +385,23 @@
 		{
 			/* Kerrrbaaang !!!!! a hit */
 			//Watermelon:Target prediction
-			if(psTarget->type == OBJ_DROID)
+			if (psTarget->type == OBJ_DROID)
 			{
-				predictX = (cos(((DROID *)psTarget)->sMove.dir) * ((DROID *)psTarget)->sMove.speed * sqrt(distSquared)) /psStats->flightSpeed;
-				predictX += psTarget->x;
-				predictY = (sin(((DROID *)psTarget)->sMove.dir) * ((DROID *)psTarget)->sMove.speed * sqrt(distSquared)) /psStats->flightSpeed;
-				predictY += psTarget->y;
+				//Watermelon:If it's a flying VTOL use vtolDist
+				if (bFlyingVTOL)
+				{
+					predictX = (SDWORD)((sin(((DROID *)psTarget)->sMove.dir) * ((DROID *)psTarget)->sMove.speed * vtolDist) /psStats->flightSpeed);
+					predictX += psTarget->x;
+					predictY = (SDWORD)((cos(((DROID *)psTarget)->sMove.dir) * ((DROID *)psTarget)->sMove.speed * vtolDist) /psStats->flightSpeed);
+					predictY += psTarget->y;
+				}
+				else
+				{
+					predictX = (SDWORD)((sin(((DROID *)psTarget)->sMove.dir) * ((DROID *)psTarget)->sMove.speed * dist) /psStats->flightSpeed);
+					predictX += psTarget->x;
+					predictY = (SDWORD)((cos(((DROID *)psTarget)->sMove.dir) * ((DROID *)psTarget)->sMove.speed * dist) /psStats->flightSpeed);
+					predictY += psTarget->y;
+				}
 			}
 			else
 			{
@@ -381,7 +410,7 @@
 			}
 			DBP3(("Shot hit (%d)\n", dice));
 			if (!proj_SendProjectile(psWeap, psAttacker, psAttacker->player,
-								predictX, predictY, psTarget->z, psTarget, FALSE))
+								predictX, predictY, psTarget->z, psTarget, FALSE, FALSE))
 			{
 				/* Out of memory - we can safely ignore this */
 				DBP3(("Out of memory"));
@@ -418,21 +447,24 @@
 		{
 			/* Kerrrbaaang !!!!! a hit */
 			//Watermelon:Target prediction
-			if(psTarget->type == OBJ_DROID)
+			//Watermelon:If it's a flying VTOL use vtolDist
+			if (bFlyingVTOL)
 			{
-				predictX = (cos(((DROID *)psTarget)->sMove.dir) * ((DROID *)psTarget)->sMove.speed * sqrt(distSquared)) /psStats->flightSpeed;
+				predictX = (SDWORD)((sin(((DROID *)psTarget)->sMove.dir) * ((DROID *)psTarget)->sMove.speed * vtolDist) /psStats->flightSpeed);
 				predictX += psTarget->x;
-				predictY = (sin(((DROID *)psTarget)->sMove.dir) * ((DROID *)psTarget)->sMove.speed * sqrt(distSquared)) /psStats->flightSpeed;
+				predictY = (SDWORD)((cos(((DROID *)psTarget)->sMove.dir) * ((DROID *)psTarget)->sMove.speed * vtolDist) /psStats->flightSpeed);
 				predictY += psTarget->y;
 			}
 			else
 			{
-				predictX = psTarget->x;
-				predictY = psTarget->y;
+				predictX = (SDWORD)((sin(((DROID *)psTarget)->sMove.dir) * ((DROID *)psTarget)->sMove.speed * dist) /psStats->flightSpeed);
+				predictX += psTarget->x;
+				predictY = (SDWORD)((cos(((DROID *)psTarget)->sMove.dir) * ((DROID *)psTarget)->sMove.speed * dist) /psStats->flightSpeed);
+				predictY += psTarget->y;
 			}
 			DBP3(("Shot hit (%d)\n", dice));
 			if (!proj_SendProjectile(psWeap, psAttacker, psAttacker->player,
-								predictX, predictY, psTarget->z, psTarget, FALSE))
+								predictX, predictY, psTarget->z, psTarget, FALSE, FALSE))
 			{
 				/* Out of memory - we can safely ignore this */
 				DBP3(("Out of memory"));
@@ -490,7 +522,7 @@
 	}
 
 	/* Fire off the bullet to the miss location */
-	if (!proj_SendProjectile( psWeap, psAttacker, psAttacker->player, missX,missY, psTarget->z, NULL, bMissVisible) )
+	if (!proj_SendProjectile( psWeap, psAttacker, psAttacker->player, missX,missY, psTarget->z, NULL, bMissVisible, FALSE) )
 	{
 		/* Out of memory */
 		DBP3(("Out of memory"));
Index: game.c
===================================================================
--- game.c	(revision 467)
+++ game.c	(working copy)
@@ -772,7 +772,7 @@
 	UDWORD	actionStarted;	\
 	UDWORD	actionPoints;	\
 	UWORD	actionHeight;	\
-	char	tarStatName[MAX_SAVE_NAME_SIZE];\
+	CHAR	tarStatName[MAX_SAVE_NAME_SIZE];\
     UDWORD	baseStructID;	\
 	UBYTE	group;			\
 	UBYTE	selected;		\
Index: multistat.c
===================================================================
--- multistat.c	(revision 467)
+++ multistat.c	(working copy)
@@ -621,7 +621,7 @@
 	//set stats.
 	memcpy(playerStats,&(st.stats), sizeof(PLAYERSTATS));	// get
 
-	//set the name. ASSUME STRING IS LONG ENOUGH!
+	//set the name. ASSUME char IS LONG ENOUGH!
 	strcpy(sPlayerName,st.name);
 
 	FREE(pFileData);
Index: multistruct.c
===================================================================
--- multistruct.c	(revision 467)
+++ multistruct.c	(working copy)
@@ -384,7 +384,7 @@
 	if(psStruct && psObj)
 	{
 		proj_SendProjectile(&psStruct->asWeaps[0], NULL, player, psObj->x,
-            psObj->y, psObj->z, psObj, TRUE);
+            psObj->y, psObj->z, psObj, TRUE, FALSE);
         //play 5 second countdown message
 		audio_QueueTrackPos( ID_SOUND_LAS_SAT_COUNTDOWN, psObj->x, psObj->y,
             psObj->z );
Index: order.c
===================================================================
--- order.c	(revision 467)
+++ order.c	(working copy)
@@ -649,13 +649,47 @@
 			}
 			else if ( ((psDroid->action == DACTION_MOVE) ||
 					   (psDroid->action == DACTION_MOVEFIRE)) &&
-					   actionVisibleTarget(psDroid, psDroid->psTarget) && !vtolDroid(psDroid))
+					   actionVisibleTarget(psDroid, psDroid->psTarget) > 1 && !vtolDroid(psDroid))
 			{
 				// moved near enough to attack change to attack action
 				actionDroidObj(psDroid, DACTION_ATTACK, psDroid->psTarget);
 			}
 			else if ( (psDroid->action == DACTION_MOVETOATTACK) &&
 					  !vtolDroid(psDroid) &&
+					  actionVisibleTarget(psDroid, psDroid->psTarget) == 1 )
+			{
+				// lost sight of the target while chasing it - change to a move action so
+				// that the unit will fire on other things while moving
+				actionDroidLoc(psDroid, DACTION_MOVE, psDroid->psTarget->x, psDroid->psTarget->y);
+			}
+			else if (!vtolDroid(psDroid) &&
+					 (psDroid->psTarget == psDroid->psActionTarget) &&
+					 ( actionInRange(psDroid, psDroid->psTarget) & (1 << i) ) &&
+					 visGetBlockingWall((BASE_OBJECT *)psDroid, psDroid->psTarget, &psWall) &&
+					 (psWall->player != psDroid->player))
+			{
+				// there is a wall in the way - attack that
+				actionDroidObj(psDroid, DACTION_ATTACK, (BASE_OBJECT *)psWall);
+			}
+			else if ((psDroid->action == DACTION_NONE) ||
+					 (psDroid->action == DACTION_CLEARREARMPAD))
+			{
+				if ((psDroid->order == DORDER_ATTACKTARGET) &&
+					secondaryGetState(psDroid, DSO_HALTTYPE, &state) && (state == DSS_HALT_HOLD) &&
+					!( actionInRange(psDroid, psDroid->psTarget) & (1 << i)) )
+				{
+					// on hold orders give up
+					psDroid->order = DORDER_NONE;
+					psDroid->psTarget = NULL;
+				}
+				else if (!vtolDroid(psDroid) ||
+					allVtolsRearmed(psDroid))
+				{
+					actionDroidObj(psDroid, DACTION_ATTACK, psDroid->psTarget);
+				}
+			}
+			else if ( (psDroid->action == DACTION_MOVETOATTACK) &&
+					  !vtolDroid(psDroid) &&
 					  !actionVisibleTarget(psDroid, psDroid->psTarget) )
 			{
 				// lost sight of the target while chasing it - change to a move action so
@@ -4600,7 +4634,7 @@
 			}
             //ok to fire - so fire away
             proj_SendProjectile(&psStruct->asWeaps[0], NULL,
-                player, psObj->x, psObj->y, psObj->z, psObj, TRUE);
+                player, psObj->x, psObj->y, psObj->z, psObj, TRUE, FALSE);
             //set up last fires time
             psStruct->asWeaps[0].lastFired =  gameTime;
 
Index: projectile.c
===================================================================
--- projectile.c	(revision 467)
+++ projectile.c	(working copy)
@@ -309,7 +309,7 @@
 
 BOOL
 proj_SendProjectile( WEAPON *psWeap, BASE_OBJECT *psAttacker, SDWORD player,
-					 UDWORD tarX, UDWORD tarY, UDWORD tarZ, BASE_OBJECT *psTarget, BOOL bVisible )
+					 UDWORD tarX, UDWORD tarY, UDWORD tarZ, BASE_OBJECT *psTarget, BOOL bVisible, BOOL bPenetrate )
 {
 	PROJ_OBJECT		*psObj;
 	SDWORD			tarHeight, srcHeight, iMinSq;
@@ -366,7 +366,15 @@
 	psObj->tarX			= tarX;
 	psObj->tarY			= tarY;
 	psObj->targetRadius = establishTargetRadius(psTarget);	// New - needed to backtrack FX
-	psObj->psSource		= psAttacker;
+	//Watermelon:use the source of the source of psObj :)
+	if (bPenetrate)
+	{
+		psObj->psSource		= ((PROJ_OBJECT *)psAttacker)->psSource;
+	}
+	else
+	{
+		psObj->psSource		= psAttacker;
+	}
 	psObj->psDest		= psTarget;
 	psObj->born			= gameTime;
 	psObj->player		= (UBYTE)player;
@@ -627,8 +635,12 @@
 	//Watermelon:given explosive weapons some 'hit collision' bonus
 	//esp the AAGun,or it will never hit anything with the new hit system
 	int				wpRadius = 1;
+	//Watermelon:Penetrate or not
+	BOOL			bPenetrate;
+	WEAPON			asWeap;
 
 	bMissile = FALSE;
+	bPenetrate = FALSE;
 
 	ASSERT( PTRVALID(psObj, sizeof(PROJ_OBJECT)),
 		"proj_InFlightDirectFunc: invalid projectile pointer" );
@@ -781,7 +793,6 @@
 
 	//Watermelon:weapon radius,or the 'real' projectile will never hit a moving target with the changes...
 	if (psStats->weaponSubClass == WSC_MGUN ||
-		psStats->weaponSubClass == WSC_FLAME ||
 		psStats->weaponSubClass == WSC_COMMAND)
 	{
 		wpRadius = 2;
@@ -789,6 +800,7 @@
 		extendRad = (SDWORD)rad * 1.2f;
 	}
 	else if (psStats->weaponSubClass == WSC_CANNON ||
+			psStats->weaponSubClass == WSC_FLAME ||
 			psStats->weaponSubClass == WSC_ENERGY ||
 			psStats->weaponSubClass == WSC_GAUSS ||
 			psStats->weaponSubClass == WSC_BOMB ||
@@ -806,6 +818,15 @@
 		extendRad = (SDWORD)rad * 2;
 	}
 
+	//Watermelon:these 3 types of weapon should have the ability to pentrate targets and damage the enemies behind
+	if (psStats->weaponSubClass == WSC_ELECTRONIC ||
+		psStats->weaponSubClass == WSC_FLAME ||
+		psStats->weaponSubClass == WSC_GAUSS)
+	{
+		//Watermelon:extended life span
+		bPenetrate = TRUE;
+	}
+
 	//Watermelon:test test
 	for (i = 0;i < numProjNaybors;i++)
 	{
@@ -831,18 +852,41 @@
 					continue;
 				}
 			}
-			xdiff = (SDWORD)psObj->x - (SDWORD)psTempObj->x;
-			ydiff = (SDWORD)psObj->y - (SDWORD)psTempObj->y;
-			zdiff = (SDWORD)psObj->z - (SDWORD)psTempObj->z;
 
 			//Watermelon:dont apply the 'hitbox' bonus if the target is a building
-			if ( psTempObj->type == OBJ_STRUCTURE )
+			if ( psTempObj->type == OBJ_STRUCTURE || psTempObj->type == OBJ_FEATURE)
 			{
 				wpRadius = 1;
+				//Watermelon:AA weapon shouldnt hit buildings
+				if ( psObj->psWStats->surfaceToAir == SHOOT_IN_AIR )
+				{
+					continue;
+				}
 			}
 
+			xdiff = (SDWORD)psObj->x - (SDWORD)psTempObj->x;
+			ydiff = (SDWORD)psObj->y - (SDWORD)psTempObj->y;
+
 			if ((xdiff*xdiff + ydiff*ydiff) < (wpRadius * (SDWORD)(establishTargetRadius(psTempObj)) * (SDWORD)(establishTargetRadius(psTempObj))) )
 			{
+				if ( psObj->psWStats->surfaceToAir == SHOOT_IN_AIR )
+				{
+					if (psTempObj->type == OBJ_DROID && !vtolDroid((DROID *)psTempObj))
+					{
+						continue;
+					}
+				}
+
+				if (bPenetrate && psTempObj->type != OBJ_STRUCTURE)
+				{
+					if ( (abs(psObj->x - psObj->startX) + abs(psObj->y - psObj->startY)) > 100 && timeSoFar > 500)
+					{
+						continue;
+					}
+					asWeap.nStat = psObj->psWStats - asWeaponStats;
+					proj_SendProjectile( &asWeap, psObj, psObj->player, (psObj->startX + (UDWORD)(extendRad * dx /rad)),(psObj->startY + (UDWORD)(extendRad * dy /rad)), psObj->z, NULL, TRUE, bPenetrate );
+				}
+
 				psNewTarget = psTempObj;
 				psObj->psDest = psNewTarget;
 		  		psObj->state = PROJ_IMPACT;
@@ -2325,4 +2369,3 @@
 	}
 }
 
-
Index: projectile.h
===================================================================
--- projectile.h	(revision 467)
+++ projectile.h	(working copy)
@@ -42,8 +42,9 @@
 PROJ_OBJECT *	proj_GetNext( void );
 
 void	proj_FreeAllProjectiles( void );
+//Watermelon:added another BOOL value bPenetrate
 BOOL	proj_SendProjectile( WEAPON *psWeap, BASE_OBJECT *psAttacker, SDWORD player,
-					 UDWORD tarX, UDWORD tarY, UDWORD tarZ, BASE_OBJECT *psTarget, BOOL bVisible );
+					 UDWORD tarX, UDWORD tarY, UDWORD tarZ, BASE_OBJECT *psTarget, BOOL bVisible, BOOL bPenetrate );
 
 // return whether a weapon is direct or indirect
 BOOL	proj_Direct(WEAPON_STATS *psStats);
Index: scriptfuncs.c
===================================================================
--- scriptfuncs.c	(revision 467)
+++ scriptfuncs.c	(working copy)
@@ -6173,7 +6173,7 @@
 	sWeapon.nStat = wIndex;
 
 	// send the projectile using the selectedPlayer so that it can always be seen
-	proj_SendProjectile(&sWeapon, NULL, selectedPlayer, psTarget->x,psTarget->y,psTarget->z, psTarget, TRUE);
+	proj_SendProjectile(&sWeapon, NULL, selectedPlayer, psTarget->x,psTarget->y,psTarget->z, psTarget, TRUE, FALSE);
 
 	return TRUE;
 }
@@ -6193,7 +6193,7 @@
 	sWeapon.nStat = wIndex;
 
 	// send the projectile using the selectedPlayer so that it can always be seen
-	proj_SendProjectile(&sWeapon, NULL, selectedPlayer, x,y,map_Height(x,y), NULL, TRUE);
+	proj_SendProjectile(&sWeapon, NULL, selectedPlayer, x,y,map_Height(x,y), NULL, TRUE, FALSE);
 
 	return TRUE;
 }
Index: structure.c
===================================================================
--- structure.c	(revision 467)
+++ structure.c	(working copy)
@@ -9137,33 +9137,38 @@
 {
 	//Standard Sensor Tower + indirect weapon droid (non VTOL)
 	//else if (structStandardSensor(psStruct) AND (psDroid->numWeaps AND
-    if (structStandardSensor(psStruct) AND (psDroid->asWeaps[0].nStat > 0 AND
-		!proj_Direct(asWeaponStats + psDroid->asWeaps[0].nStat)) AND
-		!vtolDroid(psDroid))
+	//Watermelon:another crash when nStat is marked as 0xcd...
+	//Added a safety check
+	if (psDroid->numWeaps > 0)
 	{
-		return TRUE;
-	}
-	//CB Sensor Tower + indirect weapon droid (non VTOL)
-	//if (structCBSensor(psStruct) AND (psDroid->numWeaps AND
-    else if (structCBSensor(psStruct) AND (psDroid->asWeaps[0].nStat > 0 AND
-		!proj_Direct(asWeaponStats + psDroid->asWeaps[0].nStat)) AND
-		!vtolDroid(psDroid))
-	{
-		return TRUE;
-	}
-	//VTOL Intercept Sensor Tower + any weapon VTOL droid
-	//else if (structVTOLSensor(psStruct) AND psDroid->numWeaps AND
-    else if (structVTOLSensor(psStruct) AND psDroid->asWeaps[0].nStat > 0 AND
-		vtolDroid(psDroid))
-	{
-		return TRUE;
-	}
-	//VTOL CB Sensor Tower + any weapon VTOL droid
-	//else if (structVTOLCBSensor(psStruct) AND psDroid->numWeaps AND
-    else if (structVTOLCBSensor(psStruct) AND psDroid->asWeaps[0].nStat > 0 AND
+		if (structStandardSensor(psStruct) AND (psDroid->asWeaps[0].nStat > 0 AND
+			!proj_Direct(asWeaponStats + psDroid->asWeaps[0].nStat)) AND
+			!vtolDroid(psDroid))
+		{
+			return TRUE;
+		}
+		//CB Sensor Tower + indirect weapon droid (non VTOL)
+		//if (structCBSensor(psStruct) AND (psDroid->numWeaps AND
+		else if (structCBSensor(psStruct) AND (psDroid->asWeaps[0].nStat > 0 AND
+			!proj_Direct(asWeaponStats + psDroid->asWeaps[0].nStat)) AND
+			!vtolDroid(psDroid))
+		{
+			return TRUE;
+		}
+		//VTOL Intercept Sensor Tower + any weapon VTOL droid
+		//else if (structVTOLSensor(psStruct) AND psDroid->numWeaps AND
+		else if (structVTOLSensor(psStruct) AND psDroid->asWeaps[0].nStat > 0 AND
 			vtolDroid(psDroid))
-	{
-		return TRUE;
+		{
+			return TRUE;
+		}
+		//VTOL CB Sensor Tower + any weapon VTOL droid
+		//else if (structVTOLCBSensor(psStruct) AND psDroid->numWeaps AND
+		else if (structVTOLCBSensor(psStruct) AND psDroid->asWeaps[0].nStat > 0 AND
+				vtolDroid(psDroid))
+		{
+			return TRUE;
+		}
 	}
 
 	//case not matched
