// Grenade Handler.
// Worthless Bums 2012-2018.


// Throws a grenade.
function throwGrenade ()
{//echo("throwGrenade()");
	if ($squadReposition)
	{
		updateEventText($whiteColor @ "Squad is Repositioning - cannot attack" @ $defaultColor @ "!");
		return;
	}
	if (isObject($playerSquad[$activeCharacter]))
	{
		updateEventText($squadColor @ $playerSquad[$activeCharacter].name SPC $friendlyActionColor @ "throws grenade" @ $defaultColor @ "!");
		throwPlayerGrenade($playerSquad[$activeCharacter].facing);
		$grenadesUsed++;
	}
	handleHealthIndicators();
	updateMissionObjectives();
}

// Returns the indices of the tile a player thrown grenade will land on.
function getGrenadeTile ()
{//echo("getGrenadeTile()");
	%xIndex = $playerSquad[$activeCharacter].xIndex;
	%yIndex = $playerSquad[$activeCharacter].yIndex;
	%deltaX = 0;
	%deltaY = 0;
	for (%i = 1; %i <= $grenadeThrowRange; %i++)
	{
		switch ($playerSquad[$activeCharacter].facing)
		{
			case $northDirection:
				%yIndex--;
				%deltaY = 1;
			case $southDirection:
				%yIndex++;
				%deltaY = -1;
			case $eastDirection:
				%xIndex++;
				%deltaX = -1;
			case $westDirection:
				%xIndex--;
				%deltaX = 1;
		}
		if (isObject($mazeRoom[%xIndex, %yIndex]))
		{
			return (%xIndex + %deltaX) SPC (%yIndex + %deltaY);
		}
		else if (!tileClearOfMonsters(%xIndex, %yIndex))
		{
			return %xIndex SPC %yIndex;
		}
	}
	return %xIndex SPC %yIndex;
}

// Player Throws a Grenade.
function throwPlayerGrenade (%direction)
{//echo("throwPlayerGrenade()");
	%range = $grenadeThrowRange;
	%grenadeTile = getGrenadeTile();
	createThrownGrenadeAnimation($playerSquad[$activeCharacter], getWord(%grenadeTile, 0), getWord(%grenadeTile, 1));
	%grenadeDelay = $GrenadeBaseDelay;
	%distance = 8.0;//mAbs(VectorDist($playerSquad[%index].getPosition(), getTilePositionFromIndices(getWord(%grenadeTile, 0), getWord(%grenadeTile, 1))));
	if (%distance <= 14)
	{
		%grenadeDelay = 0.75 * $GrenadeBaseDelay;
	}
	if (%distance <= 10)
	{
		%grenadeDelay = 0.50 * $GrenadeBaseDelay;
	}
	if (%distance <=  6)
	{
		%grenadeDelay = 0.25 * $GrenadeBaseDelay;
	}
	schedule(%grenadeDelay, 0, "traceGrenadePath", $playerSquad[$activeCharacter].xIndex, $playerSquad[$activeCharacter].yIndex, %direction, %range);
	schedule(%grenadeDelay + 40, 0, "initializeReadout");
	schedule(%grenadeDelay + 80, 0, "scheduleMonsterTurn");
}

// Traces grenade path (after fire animation has finished).
function traceGrenadePath (%tileSourceX, %tileSourceY, %direction, %range)
{//echo("traceGrenadePath()");
	%x = %tileSourceX;
	%y = %tileSourceY;
	for (%i = 0; %i < %range; %i++)
	{
		%deltaX = 0;
		%deltaY = 0;
		switch (%direction)
		{
			case $northDirection:
				%y--;
				%deltaY = 1;
			case $southDirection:
				%y++;
				%deltaY = -1;
			case $eastDirection:
				%x++;
				%deltaX = -1;
			case $westDirection:
				%x--;
				%deltaX = 1;
		}
		if (%x < 0					||
			%y < 0					||
			%x > $mazeDimension - 1	||
			%y > $mazeDimension - 1)
		{
			grenadeEmptyAoePathDamage(%tileSourceX, %tileSourceY, %direction);
			handleGrenadierExplosion(%tileSourceX, %tileSourceY);
			return %tileSourceX SPC %tileSourceY;
		}
		else
		{
			if (!canFireThrough(%x, %y))
			{
				grenadeEmptyAoePathDamage(%x + %deltaX, %y + %deltaY, %direction);
				handleGrenadierExplosion(%x + %deltaX, %y + %deltaY);
				return %x + %deltaX SPC %y + %deltaY;					// Return the tile BEFORE the obstacle!
			}
			else
			{
				%monsterIndex = monsterAtPosition(%x, %y);
				if (%monsterIndex != -1)
				{
					grenadePathDamage(%monsterIndex, %direction);
					return %x SPC %y;
				}
			}
		}
	}
	grenadeAoeDamage(%x, %y, %direction);
	handleGrenadierExplosion(%x, %y);
	return %x SPC %y;
}

// Deals grenade damage to the specified monster.
function grenadePathDamage (%monsterIndex, %direction)
{//echo("grenadePathDamage()");
	// Grab the monster.
	%monster = $monsterList.getObject(%monsterIndex);
	
	// Deal damage to primary target.
	%damage = $normalGrenadeAoeDamage;
	if (%monster.currentHealth <= %damage)
	{
		// Set new monster health.
		%monster.currentHealth = 0;
		
		// Check if this monster is a robot.
		if (%monster.isRobot)
		{
			// Trigger Armor repair.
			triggerArmorRepair();
		}
		
		// Update kill record.
		updateKillRecord($activeCharacter, %monster.name, %monster.level);
		// Kill the monster.
		handleMonsterDeath($activeCharacter, %monsterIndex);
		updateEventText($squadColor @ $playerSquad[$activeCharacter].name SPC $damageColor @ "kills" SPC $monsterColor @ %monster.name @ $defaultColor @ "!");
	}
	else
	{
		// Set new monster health.
		%monster.currentHealth -= %damage;
	}
	
	// Deal grenade aoe damage.
	grenadeAoePathDamage(%monsterIndex, %direction, null);
	
	// Play Grenadier explosion animation.
	handleGrenadierExplosion(%monster.xIndex, %monster.yIndex);
}

// Damage monster(s) and squad members in grenade aoe.
function grenadeAoePathDamage (%monsterIndex, %direction, %monster)			// May need the direction in the future!
{//echo("grenadeAoePathDamage()");
	// Grab the squad member who fired.
	%squadMember = $playerSquad[$activeCharacter];
	
	// Grab the monster taking damage.
	if (!isObject(%monster))
	{
		%monster = $monsterList.getObject(%monsterIndex);
	}
	
	// Grenadier inputs.
	%damage = $normalGrenadeAoeDamage;
	%attackRating = 100;
	
	// Roll a random hit number.
	%hitRoll = getRandom(1, 100);
	
	// Blood splatter the hit target.
	monsterHit(%monsterIndex, %damage, %direction, "grenade");
	
	// Eight (8) neighboring tiles that the Grenadier's aoe attack can hit.
	// x5, x5 is the middle (initial) attack target.
	%x5 = %monster.xIndex;
	%y5 = %monster.yIndex;
	
	// Compose the other positions to check.
	$validNeighboringTargets = new SimSet();
	
	// Up left.
	%x1 = %x5 - 1;
	%y1 = %y5 - 1;
	// Bounds check.
	if (%x1 >= 0				&&
		%x1 < $mazeDimension	&&
		%y1 >= 0				&&
		%y1 < $mazeDimension)
	{
		// Get all valid neighboring targets.
		getValidNeighborTargets(%x1, %y1);
		
		// Perform Grenadier terrain destruction action.
		grenadierDestroyTerrain(%x1, %y1);
		
		// Play Grenadier explosion animation.
		//handleGrenadierExplosion(%x1, %y1);
	}
	// Up middle.
	%x2 = %x5;
	%y2 = %y5 - 1;
	if (%x1 >= 0				&&
		%x1 < $mazeDimension	&&
		%y1 >= 0				&&
		%y1 < $mazeDimension)
	{
		// Get all valid neighboring targets.
		getValidNeighborTargets(%x2, %y2);
		
		// Perform Grenadier terrain destruction action.
		grenadierDestroyTerrain(%x2, %y2);
		
		// Play Grenadier explosion animation.
		//handleGrenadierExplosion(%x2, %y2);
	}
	// Up right.
	%x3 = %x5 + 1;
	%y3 = %y5 - 1;
	if (%x1 >= 0				&&
		%x1 < $mazeDimension	&&
		%y1 >= 0				&&
		%y1 < $mazeDimension)
	{
		// Get all valid neighboring targets.
		getValidNeighborTargets(%x3, %y3);
		
		// Perform Grenadier terrain destruction action.
		grenadierDestroyTerrain(%x3, %y3);
		
		// Play Grenadier explosion animation.
		//handleGrenadierExplosion(%x3, %y3);
	}
	
	// Middle left.
	%x4 = %x5 - 1;
	%y4 = %y5;
	if (%x1 >= 0				&&
		%x1 < $mazeDimension	&&
		%y1 >= 0				&&
		%y1 < $mazeDimension)
	{
		// Get all valid neighboring targets.
		getValidNeighborTargets(%x4, %y4);
		
		// Perform Grenadier terrain destruction action.
		grenadierDestroyTerrain(%x4, %y4);
		
		// Play Grenadier explosion animation.
		//handleGrenadierExplosion(%x4, %y4);
	}
	// Middle right.
	%x6 = %x5 + 1;
	%y6 = %y5;
	if (%x1 >= 0				&&
		%x1 < $mazeDimension	&&
		%y1 >= 0				&&
		%y1 < $mazeDimension)
	{
		// Get all valid neighboring targets.
		getValidNeighborTargets(%x6, %y6);
		
		// Perform Grenadier terrain destruction action.
		grenadierDestroyTerrain(%x6, %y6);
		
		// Play Grenadier explosion animation.
		//handleGrenadierExplosion(%x6, %y6);
	}
	
	// Down left.
	%x7 = %x5 - 1;
	%y7 = %y5 + 1;
	if (%x1 >= 0				&&
		%x1 < $mazeDimension	&&
		%y1 >= 0				&&
		%y1 < $mazeDimension)
	{
		// Get all valid neighboring targets.
		getValidNeighborTargets(%x7, %y7);
		
		// Perform Grenadier terrain destruction action.
		grenadierDestroyTerrain(%x7, %y7);
		
		// Play Grenadier explosion animation.
		//handleGrenadierExplosion(%x7, %y7);
	}
	// Down middle.
	%x8 = %x5;
	%y8 = %y5 + 1;
	if (%x1 >= 0				&&
		%x1 < $mazeDimension	&&
		%y1 >= 0				&&
		%y1 < $mazeDimension)
	{
		// Get all valid neighboring targets.
		getValidNeighborTargets(%x8, %y8);
		
		// Perform Grenadier terrain destruction action.
		grenadierDestroyTerrain(%x8, %y8);
		
		// Play Grenadier explosion animation.
		//handleGrenadierExplosion(%x8, %y8);
	}
	// Down right.
	%x9 = %x5 + 1;
	%y9 = %y5 + 1;
	if (%x1 >= 0				&&
		%x1 < $mazeDimension	&&
		%y1 >= 0				&&
		%y1 < $mazeDimension)
	{
		// Get all valid neighboring targets.
		getValidNeighborTargets(%x9, %y9);
		
		// Perform Grenadier terrain destruction action.
		grenadierDestroyTerrain(%x9, %y9);
		
		// Play Grenadier explosion animation.
		//handleGrenadierExplosion(%x9, %y9);
	}
	
	for (%i = 0; %i < $validNeighboringTargets.getCount(); %i++)
	{//echo("$validNeighboringTargets.getCount() =" SPC $validNeighboringTargets.getCount());
		// Get the target in the neighbor list.
		%monster = $validNeighboringTargets.getObject(%i);
		
		// If the character is a Grenadier with the Smart Bombs talent.
		if (%squadMember.characterClass == 2		&&
			getWord(%squadMember.talents, 7) == 1	&&
			isSquadMember(%monster))
		{
			$validNeighboringTargets.remove(%monster);
			%i--;
		}
		else
		{
			if (%hitRoll <= %attackRating)
			{
				updateEventText($squadColor @ %squadMember.name SPC $friendlyActionColor @ "damages" SPC $monsterColor @ %monster.name SPC $defaultColor @ "for" SPC $damageColor @ %damage SPC "damage" @ $defaultColor @ "!");
				// Make sure aoe splash damage does not kill secondary targets!
				if (%monster.currentHealth <= %damage)
				{
					// Check for Grenadier class talent Annihilation.
					if ($playerSquad[$activeCharacter].characterClass == 2	&&
						getWord($playerSquad[$activeCharacter].talents, 1) == 1)
					{
						%monster.currentHealth = 0;
						updateEventText($squadColor @ $playerSquad[$activeCharacter].name SPC $damageColor @ "kills" SPC $monsterColor @ %monster.name @ $defaultColor @ "!");
					}
					else
					{
						%monster.currentHealth = 1;			// AoE attacks cannot outright kill peripheral targets!
					}
				}
				else
				{
					%monster.currentHealth -= %damage;
				}
				monsterHit(%monsterIndex, %damage, %direction, "explosive");
				if (isSquadMember(%monster))
				{
					objectHit(%monster, %damage);
				}
			}
			else
			{
				scrollFloatingText(%monster, "miss", "miss");
				monsterAttackedReaction($monsterList.getObject(%monsterIndex));
				updateEventText($squadColor @ %squadMember.name SPC $greyColor @ "misses" SPC $monsterColor @ %monster.name @ $defaultColor @ "!");
			}
		}
	}
}

// Damage monster(s) and squad members in grenade aoe.
function grenadeEmptyAoePathDamage (%xIndex, %yIndex, %direction)			// May need the direction in the future!
{//echo("grenadeEmptyAoePathDamage()");
	%squadMember = $playerSquad[$activeCharacter];
	%damage = $normalGrenadeAoeDamage;
	%attackRating = 100;
	%hitRoll = getRandom(1, 100);
	
	// Play Grenadier explosion animation.
	handleGrenadierExplosion(%xIndex, %yIndex);
	
	// Eight (8) neighboring tiles that the Grenadier's aoe attack can hit.
	// x5, x5 is the middle (initial) attack target.
	%x5 = %xIndex;//%monster.xIndex;
	%y5 = %yIndex;//%monster.yIndex;
	
	// If the character is a Grenadier with the Minesweeper talent.
	if (%squadMember.characterClass == 2	&&
		getWord(%squadMember.talents, 3) == 1)
	{
		// Destroy nearby landmines.
		%radius = 1;
		destroyMinesInRadius(%xIndex, %yIndex, %radius);
	}
	
	// Compose the other positions to check.
	$validNeighboringTargets = new SimSet();
	
	// Up left.
	%x1 = %x5 - 1;
	%y1 = %y5 - 1;
	// Bounds check.
	if (%x1 >= 0				&&
		%x1 < $mazeDimension	&&
		%y1 >= 0				&&
		%y1 < $mazeDimension)
	{
		getValidNeighborTargets(%x1, %y1);
		grenadierDestroyTerrain(%x1, %y1);
	}
	// Up middle.
	%x2 = %x5;
	%y2 = %y5 - 1;
	if (%x1 >= 0				&&
		%x1 < $mazeDimension	&&
		%y1 >= 0				&&
		%y1 < $mazeDimension)
	{
		getValidNeighborTargets(%x2, %y2);
		grenadierDestroyTerrain(%x2, %y2);
	}
	// Up right.
	%x3 = %x5 + 1;
	%y3 = %y5 - 1;
	if (%x1 >= 0				&&
		%x1 < $mazeDimension	&&
		%y1 >= 0				&&
		%y1 < $mazeDimension)
	{
		getValidNeighborTargets(%x3, %y3);
		grenadierDestroyTerrain(%x3, %y3);
	}
	
	// Middle left.
	%x4 = %x5 - 1;
	%y4 = %y5;
	if (%x1 >= 0				&&
		%x1 < $mazeDimension	&&
		%y1 >= 0				&&
		%y1 < $mazeDimension)
	{
		getValidNeighborTargets(%x4, %y4);
		grenadierDestroyTerrain(%x4, %y4);
	}
	// Middle right.
	%x6 = %x5 + 1;
	%y6 = %y5;
	if (%x1 >= 0				&&
		%x1 < $mazeDimension	&&
		%y1 >= 0				&&
		%y1 < $mazeDimension)
	{
		getValidNeighborTargets(%x6, %y6);
		grenadierDestroyTerrain(%x6, %y6);
	}
	
	// Down left.
	%x7 = %x5 - 1;
	%y7 = %y5 + 1;
	if (%x1 >= 0				&&
		%x1 < $mazeDimension	&&
		%y1 >= 0				&&
		%y1 < $mazeDimension)
	{
		getValidNeighborTargets(%x7, %y7);
		grenadierDestroyTerrain(%x7, %y7);
	}
	// Down middle.
	%x8 = %x5;
	%y8 = %y5 + 1;
	if (%x1 >= 0				&&
		%x1 < $mazeDimension	&&
		%y1 >= 0				&&
		%y1 < $mazeDimension)
	{
		getValidNeighborTargets(%x8, %y8);
		grenadierDestroyTerrain(%x8, %y8);
	}
	// Down right.
	%x9 = %x5 + 1;
	%y9 = %y5 + 1;
	if (%x1 >= 0				&&
		%x1 < $mazeDimension	&&
		%y1 >= 0				&&
		%y1 < $mazeDimension)
	{
		getValidNeighborTargets(%x9, %y9);
		grenadierDestroyTerrain(%x9, %y9);
	}
	for (%i = 0; %i < $validNeighboringTargets.getCount(); %i++)
	{//echo("$validNeighboringTargets.getCount() =" SPC $validNeighboringTargets.getCount());
		%monster = $validNeighboringTargets.getObject(%i);
		// If the character is a Grenadier with the Smart Bombs talent.
		if (%squadMember.characterClass == 2		&&
			getWord(%squadMember.talents, 7) == 1	&&
			isSquadMember(%monster))
		{
			$validNeighboringTargets.remove(%monster);
			%i--;
		}
		else
		{
			if (%hitRoll <= %attackRating)
			{
				updateEventText($squadColor @ %squadMember.name SPC $friendlyActionColor @ "damages" SPC $monsterColor @ %monster.name SPC $defaultColor @ "for" SPC $damageColor @ %damage SPC "damage" @ $defaultColor @ "!");
				// Make sure aoe splash damage does not kill secondary targets!
				if (%monster.currentHealth <= %damage)
				{
					// Check for Grenadier class talent Annihilation.
					if ($playerSquad[$activeCharacter].characterClass == 2	&&
						getWord($playerSquad[$activeCharacter].talents, 1) == 1)
					{
						%monster.currentHealth = 0;
						updateEventText($squadColor @ $playerSquad[$activeCharacter].name SPC $damageColor @ "kills" SPC $monsterColor @ %monster.name @ $defaultColor @ "!");
					}
					else
					{
						%monster.currentHealth = 1;			// AoE attacks cannot outright kill peripheral targets!
					}
				}
				else
				{
					%monster.currentHealth -= %damage;
					if (%monster.currentHealth <= 0)
					{
						%monster.currentHealth = 1;
					}
				}
				%monsterIndex = getMonsterIndex(%monster);
				if (%monsterIndex == -1)
				{
					%characterIndex = getSquadMemberIndex(%monster);
					if (%characterIndex != -1)
					{
						characterHit(%characterIndex, %damage, $playerSquad[%characterIndex], "explosive", "explosive");
						if ($playerSquad[%characterIndex].currentHealth <= 0)
						{//echo("Grenadier plastic explosive attacks squad member!");
							$playerSquad[%characterIndex].currentHealth = 1;	// Don't let plastic explosives kill squad members!
						}
					}
					else
					{
						return;
					}
				}
				else
				{
					monsterHit(%monsterIndex, %damage, %direction, "explosive");
				}
			}
			// Missed!
			else
			{
				scrollFloatingText(%monster, "miss", "miss");
				monsterAttackedReaction($monsterList.getObject(%monsterIndex));
				updateEventText($squadColor @ %squadMember.name SPC $greyColor @ "misses" SPC $monsterColor @ %monster.name @ $defaultColor @ "!");
			}
		}
	}
	handleHealthIndicators();
}

// Damage monster(s) and squad members in grenade aoe.
function grenadeAoeDamage (%xIndex, %yIndex, %direction)			// May need the direction in the future!
{//echo("grenadeAoeDamage()");
	%squadMember = $playerSquad[$activeCharacter];
	%damage = $normalGrenadeAoeDamage;
	%attackRating = 100;
	%hitRoll = getRandom(1, 100);
	
	// Eight (8) neighboring tiles that the Grenadier's aoe attack can hit.
	// x5, x5 is the middle (initial) attack target.
	%x5 = %xIndex;//%monster.xIndex;
	%y5 = %yIndex;//%monster.yIndex;
	
	// If the character is a Grenadier with the Minesweeper talent.
	if (%squadMember.characterClass == 2	&&
		getWord(%squadMember.talents, 3) == 1)
	{
		// Destroy nearby landmines.
		%radius = 1;
		destroyMinesInRadius(%xIndex, %yIndex, %radius);
	}
	
	// Compose the other positions to check.
	$validNeighboringTargets = new SimSet();
	
	// Check the tile the grenade actually hit!
	getValidNeighborTargets(%x5, %y5);
	
	// Up left.
	%x1 = %x5 - 1;
	%y1 = %y5 - 1;
	// Bounds check.
	if (%x1 >= 0				&&
		%x1 < $mazeDimension	&&
		%y1 >= 0				&&
		%y1 < $mazeDimension)
	{
		getValidNeighborTargets(%x1, %y1);
		grenadierDestroyTerrain(%x1, %y1);
	}
	// Up middle.
	%x2 = %x5;
	%y2 = %y5 - 1;
	if (%x1 >= 0				&&
		%x1 < $mazeDimension	&&
		%y1 >= 0				&&
		%y1 < $mazeDimension)
	{
		getValidNeighborTargets(%x2, %y2);
		grenadierDestroyTerrain(%x2, %y2);
	}
	// Up right.
	%x3 = %x5 + 1;
	%y3 = %y5 - 1;
	if (%x1 >= 0				&&
		%x1 < $mazeDimension	&&
		%y1 >= 0				&&
		%y1 < $mazeDimension)
	{
		getValidNeighborTargets(%x3, %y3);
		grenadierDestroyTerrain(%x3, %y3);
	}
	
	// Middle left.
	%x4 = %x5 - 1;
	%y4 = %y5;
	if (%x1 >= 0				&&
		%x1 < $mazeDimension	&&
		%y1 >= 0				&&
		%y1 < $mazeDimension)
	{
		getValidNeighborTargets(%x4, %y4);
		grenadierDestroyTerrain(%x4, %y4);
	}
	// Middle right.
	%x6 = %x5 + 1;
	%y6 = %y5;
	if (%x1 >= 0				&&
		%x1 < $mazeDimension	&&
		%y1 >= 0				&&
		%y1 < $mazeDimension)
	{
		getValidNeighborTargets(%x6, %y6);
		grenadierDestroyTerrain(%x6, %y6);
	}
	
	// Down left.
	%x7 = %x5 - 1;
	%y7 = %y5 + 1;
	if (%x1 >= 0				&&
		%x1 < $mazeDimension	&&
		%y1 >= 0				&&
		%y1 < $mazeDimension)
	{
		getValidNeighborTargets(%x7, %y7);
		grenadierDestroyTerrain(%x7, %y7);
	}
	// Down middle.
	%x8 = %x5;
	%y8 = %y5 + 1;
	if (%x1 >= 0				&&
		%x1 < $mazeDimension	&&
		%y1 >= 0				&&
		%y1 < $mazeDimension)
	{
		getValidNeighborTargets(%x8, %y8);
		grenadierDestroyTerrain(%x8, %y8);
	}
	// Down right.
	%x9 = %x5 + 1;
	%y9 = %y5 + 1;
	if (%x1 >= 0				&&
		%x1 < $mazeDimension	&&
		%y1 >= 0				&&
		%y1 < $mazeDimension)
	{
		getValidNeighborTargets(%x9, %y9);
		grenadierDestroyTerrain(%x9, %y9);
	}
	
	for (%i = 0; %i < $validNeighboringTargets.getCount(); %i++)
	{//echo("$validNeighboringTargets.getCount() =" SPC $validNeighboringTargets.getCount());
		%monster = $validNeighboringTargets.getObject(%i);
		// If the character is a Grenadier with the Smart Bombs talent.
		if (%squadMember.characterClass == 2		&&
			getWord(%squadMember.talents, 7) == 1	&&
			isSquadMember(%monster))
		{
			$validNeighboringTargets.remove(%monster);
			%i--;
		}
		else
		{
			if (%hitRoll <= %attackRating)
			{
				updateEventText($squadColor @ %squadMember.name SPC $friendlyActionColor @ "damages" SPC $monsterColor @ %monster.name SPC $defaultColor @ "for" SPC $damageColor @ %damage SPC "damage" @ $defaultColor @ "!");
				// Make sure aoe splash damage does not kill secondary targets!
				if (%monster.currentHealth <= %damage)
				{
					// Check for Grenadier class talent Annihilation.
					if ($playerSquad[$activeCharacter].characterClass == 2	&&
						getWord($playerSquad[$activeCharacter].talents, 1) == 1)
					{
						%monster.currentHealth = 0;
						updateEventText($squadColor @ $playerSquad[$activeCharacter].name SPC $damageColor @ "kills" SPC $monsterColor @ %monster.name @ $defaultColor @ "!");
					}
					else
					{
						%monster.currentHealth = 1;			// AoE attacks cannot outright kill peripheral targets!
					}
				}
				else
				{
					%monster.currentHealth -= %damage;
					if (%monster.currentHealth <= 0)
					{
						%monster.currentHealth = 1;
					}
				}
				%monsterIndex = getMonsterIndex(%monster);
				monsterHit(%monsterIndex, %damage, %direction, "explosive");
			}
			else
			{
				scrollFloatingText(%monster, "miss", "miss");
				monsterAttackedReaction($monsterList.getObject(%monsterIndex));
				updateEventText($squadColor @ %squadMember.name SPC $greyColor @ "misses" SPC $monsterColor @ %monster.name @ $defaultColor @ "!");
			}
		}
	}
	handleHealthIndicators();
}

// Damage monster(s) and squad members in Grenadier class aoe.
function grenadeClassEmptyAoePathDamage (%xIndex, %yIndex, %direction, %hitCenter, %character)
{//echo("grenadeClassEmptyAoePathDamage()");//echo("%hitCenter =" SPC %hitCenter);
	// Grab the squad member who fired.
	%squadMember = %character;//$playerSquad[$activeCharacter];
	
	// Grab the monster taking damage.
	//%monster = $monsterList.getObject(%monsterIndex);
	
	// Grenadier inputs.
	%damage = (%squadMember.weapon).damage;
	%attackRating = (%squadMember.weapon).accuracy;
	
	// Roll a random hit number.
	%hitRoll = getRandom(1, 100);
	
	// Eight (8) neighboring tiles that the Grenadier's aoe attack can hit.
	// x5, x5 is the middle (initial) attack target.
	%x5 = %xIndex;
	%y5 = %yIndex;
	
	// Compose the other positions to check.
	$validNeighboringTargets = new SimSet();
	
	if (%hitCenter)
	{
		// Check the tile the grenade actually hit!
		getValidNeighborTargets(%x5, %y5);
	}
	
	// If the character is a Grenadier with the Minesweeper talent.
	if (%squadMember.characterClass == 2	&&
		getWord(%squadMember.talents, 3) == 1)
	{
		%radius = 1;
		destroyMinesInRadius(%xIndex, %yIndex, %radius);
	}
	
	// Center.
//echo("DESTROYING CENTER TILE!");
	//grenadierDestroyTerrain(%xIndex, %yIndex);	// Added in T2D v3.0 because of destroyTerrainTile() funnelling issues!
	destroyTerrainTile(%xIndex, %yIndex);	// Added in T2D v3.0 because of destroyTerrainTile() funnelling issues!
	
	// Up left.
	%x1 = %x5 - 1;
	%y1 = %y5 - 1;
	// Bounds check.
	if (%x1 >= 0				&&
		%x1 < $mazeDimension	&&
		%y1 >= 0				&&
		%y1 < $mazeDimension)
	{
		// Get all valid neighboring targets.
		getValidNeighborTargets(%x1, %y1);
		
		// Perform Grenadier terrain destruction action.
		grenadierDestroyTerrain(%x1, %y1);
		
		// Play Grenadier explosion animation.
		//handleGrenadierExplosion(%x1, %y1);
	}
	// Up middle.
	%x2 = %x5;
	%y2 = %y5 - 1;
	if (%x1 >= 0				&&
		%x1 < $mazeDimension	&&
		%y1 >= 0				&&
		%y1 < $mazeDimension)
	{
		// Get all valid neighboring targets.
		getValidNeighborTargets(%x2, %y2);
		
		// Perform Grenadier terrain destruction action.
		grenadierDestroyTerrain(%x2, %y2);
		
		// Play Grenadier explosion animation.
		//handleGrenadierExplosion(%x2, %y2);
	}
	// Up right.
	%x3 = %x5 + 1;
	%y3 = %y5 - 1;
	if (%x1 >= 0				&&
		%x1 < $mazeDimension	&&
		%y1 >= 0				&&
		%y1 < $mazeDimension)
	{
		// Get all valid neighboring targets.
		getValidNeighborTargets(%x3, %y3);
		
		// Perform Grenadier terrain destruction action.
		grenadierDestroyTerrain(%x3, %y3);
		
		// Play Grenadier explosion animation.
		//handleGrenadierExplosion(%x3, %y3);
	}
	
	// Middle left.
	%x4 = %x5 - 1;
	%y4 = %y5;
	if (%x1 >= 0				&&
		%x1 < $mazeDimension	&&
		%y1 >= 0				&&
		%y1 < $mazeDimension)
	{
		// Get all valid neighboring targets.
		getValidNeighborTargets(%x4, %y4);
		
		// Perform Grenadier terrain destruction action.
		grenadierDestroyTerrain(%x4, %y4);
		
		// Play Grenadier explosion animation.
		//handleGrenadierExplosion(%x4, %y4);
	}
	// Middle right.
	%x6 = %x5 + 1;
	%y6 = %y5;
	if (%x1 >= 0				&&
		%x1 < $mazeDimension	&&
		%y1 >= 0				&&
		%y1 < $mazeDimension)
	{
		// Get all valid neighboring targets.
		getValidNeighborTargets(%x6, %y6);
		
		// Perform Grenadier terrain destruction action.
		grenadierDestroyTerrain(%x6, %y6);
		
		// Play Grenadier explosion animation.
		//handleGrenadierExplosion(%x6, %y6);
	}
	
	// Down left.
	%x7 = %x5 - 1;
	%y7 = %y5 + 1;
	if (%x1 >= 0				&&
		%x1 < $mazeDimension	&&
		%y1 >= 0				&&
		%y1 < $mazeDimension)
	{
		// Get all valid neighboring targets.
		getValidNeighborTargets(%x7, %y7);
		
		// Perform Grenadier terrain destruction action.
		grenadierDestroyTerrain(%x7, %y7);
		
		// Play Grenadier explosion animation.
		//handleGrenadierExplosion(%x7, %y7);
	}
	// Down middle.
	%x8 = %x5;
	%y8 = %y5 + 1;
	if (%x1 >= 0				&&
		%x1 < $mazeDimension	&&
		%y1 >= 0				&&
		%y1 < $mazeDimension)
	{
		// Get all valid neighboring targets.
		getValidNeighborTargets(%x8, %y8);
		
		// Perform Grenadier terrain destruction action.
		grenadierDestroyTerrain(%x8, %y8);
		
		// Play Grenadier explosion animation.
		//handleGrenadierExplosion(%x8, %y8);
	}
	// Down right.
	%x9 = %x5 + 1;
	%y9 = %y5 + 1;
	if (%x1 >= 0				&&
		%x1 < $mazeDimension	&&
		%y1 >= 0				&&
		%y1 < $mazeDimension)
	{
		// Get all valid neighboring targets.
		getValidNeighborTargets(%x9, %y9);
		
		// Perform Grenadier terrain destruction action.
		grenadierDestroyTerrain(%x9, %y9);
		
		// Play Grenadier explosion animation.
		//handleGrenadierExplosion(%x9, %y9);
	}
	
	for (%i = 0; %i < $validNeighboringTargets.getCount(); %i++)
	{//echo("$validNeighboringTargets.getCount() =" SPC $validNeighboringTargets.getCount());
		// Get the target in the neighbor list.
		%monster = $validNeighboringTargets.getObject(%i);
		
		// If the character is a Grenadier with the Smart Bombs talent.
		if (%squadMember.characterClass == 2		&&
			getWord(%squadMember.talents, 7) == 1	&&
			isSquadMember(%monster))
		{//echo("removing squad member!");
			$validNeighboringTargets.remove(%monster);
			%i--;
		}
		else
		{
			if (%hitRoll <= %attackRating)
			{//echo("grenadeclasempty!");
				// Update event log.
				updateEventText($squadColor @ %squadMember.name SPC $friendlyActionColor @ "damages" SPC $monsterColor @ %monster.name SPC $defaultColor @ "for" SPC $damageColor @ %damage SPC "damage" @ $defaultColor @ "!");
				
				// Make sure aoe splash damage does not kill secondary targets!
				if (%monster.currentHealth <= %damage)
				{
					// Check for Grenadier class talent Annihilation.
					// Use active character or pass down current character index?
					//echo("$activeCharacter =" SPC $activeCharacter);
					if ($playerSquad[$activeCharacter].characterClass == 2	&&
						getWord($playerSquad[$activeCharacter].talents, 1) == 1)
					{//echo("Annihiliation detected!");
						%monster.currentHealth = 0;
						//echo("%monster.currentHealth =" SPC %monster.currentHealth);
						updateEventText($squadColor @ $playerSquad[$activeCharacter].name SPC $damageColor @ "kills" SPC $monsterColor @ %monster.name @ $defaultColor @ "!");
					}
					else
					{
						%monster.currentHealth = 1;			// AoE attacks cannot outright kill peripheral targets!
					}
				}
				else
				{
					%monster.currentHealth -= %damage;
				}
				%monsterIndex = getMonsterIndex(%monster);
				monsterHit(%monsterIndex, %damage, %direction, "explosive");
				if (isSquadMember(%monster))
				{
					objectHit(%monster, %damage);
					// Only execute the squad member if the Grenadier does NOT have Smart Bombs!
					if ($playerSquad[$activeCharacter].characterClass == 2	&&
						getWord($playerSquad[$activeCharacter].talents, 7) == 1)
					{
						%characterIndex = getSquadMemberIndex(%monster);
						executeSquadMemberDeath(%characterIndex, false, "[Explosion]");
					}
					else
					{
						%monster.currentHealth = 1;	// Don't fall below 1 health!
					}
				}
			}
			else
			{
				scrollFloatingText(%monster, "miss", "miss");
				updateEventText($squadColor @ %squadMember.name SPC $greyColor @ "misses" SPC $monsterColor @ %monster.name @ $defaultColor @ "!");
			}
		}
	}
	monsterAttackedReaction(%monster);
	handleHealthIndicators();
}
function squadHasGrenade ()
{//echo("squadHasGrenade()");
	for (%i = 0; %i < $squadInventory.getCount(); %i++)
	{
		%item = $squadInventory.getObject(%i);
		if (%item.name $= "Grenade")
		{
			return %i;
		}
	}
	return -1;
}
function getMonsterIndex (%monster)
{//echo("getMonsterIndex()");
	for (%i = 0; %i < $monsterList.getCount(); %i++)
	{
		if (%monster == $monsterList.getObject(%i))
		{
			return %i;
		}
	}
	return -1;
}