// Determines whether there is a defensible obstacle between defender and assaulter or shooter.
// Returns type of obstacle: -1 = no obstacle, 0 = obstacle providing protection against cavalry but no cover, 1 = obstacle providing protection against cavalry plus cover (excpet vs artillery),
// 2 = obstacle providing a POA as well as protection against cavalry and cover (essentially field fortifications),
// 3 = can only be crossed from outside using scaling ladders (or if destroyed - not yet implemented)
// x1, y1 are location of defender, x2, y2 are location of attacker. Function assumes that a linear obstacle protects at anything more to the front than directly to the side
FUNCTION IsTileEdgeDefendibleObstacle(x1, y1, x2, y2)
{
	int dx;
	int dy;
	int ret;
	int type;
	int edgeObjectX;
	int edgeObjectY;
	int orientation;

	ret = -1;

	dx = x2 - x1;
	dy = y2 - y1;

	if (dx != 0)
		{
			edgeObjectY = y1;

			if (dx > 0)
				{
					orientation = 0;
					edgeObjectX = x1 + 1;
				}
			else
				{
					orientation = 2;
					edgeObjectX = x1;
				}

			type = FindObstacle(x1,y1,edgeObjectX,edgeObjectY,orientation,x2,y2);

			if (type > -1)
				{
					ret = type;
				}
		}

	if (dy != 0)
		{
			edgeObjectX = x1;

			if (dy > 0)
				{
					orientation = 1;
					edgeObjectY = y1 + 1;
				}
			else
				{
					orientation = 3;
					edgeObjectY = y1;
				}

			type = FindObstacle(x1,y1,edgeObjectX,edgeObjectY,orientation,x2,y2);

			if (type > -1)
				{
					ret = Max(ret, type);
				}
		}

	return ret;
}

// Helper function for IsTileEdgeDefendibleObstacle()
// orientation = Orientation of defended tile edge: 0 = long axis of obstacle is along y-axis (facing up x-axis), 1 = long axis of obstacle is along x-axis (facing up y-axis),
// 2 = long axis of obstacle is along y-axis (facing down x-axis), 3 = long axis of obstacle is along x-axis (facing down y-axis).
// Multi-sided fortifications offer defence on more than one side of the defended tile - depending on which sides are fortified.
// Type = -1 is none, 0 = chains, ditch, 1 = hedge, moderate wall, 2 = Fortification, 3 = Impassable
// x1, x2 is location of defender. x2, y2 is location of attacker - only needed for road bend hedges and inside foritication corners which can't be treated as perotecting a whole tile edge.
// edgeObjectX, edegeObjectY is location of edge object that might be defendible.

Function FindObstacle(x1, y1, edgeObjectX, edgeObjectY, orientation, x2, y2)
{
	int i;
	int object;
	int type;
	int ret;
	int linear;
	int corner;
	int three_sided;
	int four_sided;
	int edgePos;
	int rotation;
	int attempts;
	int half;
	int adjX;
	int adjY;

	ret = -1;
	attempts = 50;

	// Possible to miss an obstacle if a tile has more than 50 objects

	// Centred objects - with defender on same tile as object.

	for (i = 0; i < attempts; i++)
	{
		linear = 0;
		corner = 0;
		three_sided = 0;
		four_sided = 0;

		object = GetTileObject(x1, y1, i);
		if (object == -1)
			{
				i = attempts;
			}
		else
			{
				type = -1;

				// Landscape Linear features with centred objects on same tile as defender.
				if ((IsObjectName(object, "LowWallBroken") == 1) || (IsObjectName(object, "Chains") == 1) || (IsObjectName(object, "Ditch") == 1)) // Note: the Chains & Ditch objects do not currently exist.
					{
						type = 0;
						linear = 1;
					}

				if ((IsObjectName(object, "LowWall") == 1) || (IsObjectName(object, "LowWallGate") == 1) || (IsObjectName(object, "HighWallBroken") == 1) || (IsObjectName(object, "HighWallGate") == 1))
					{
						type = 1;
						linear = 1;
					}

				if (IsObjectName(object, "HighWall") == 1)
					{
						type = 3;
						linear = 1;
					}

				// Fortifications

				// Linear
				if ((IsObjectName(object, "LightWall") == 1) || (IsObjectName(object, "LightLunette") == 1) || (IsObjectName(object, "MediumWall") == 1) || (IsObjectName(object, "MediumLunette") == 1))
					{
						type = 2;
						linear = 1;
					}

				if ((IsObjectName(object, "HeavyWall") == 1) || (IsObjectName(object, "HeavyWallTowerA") == 1) || (IsObjectName(object, "HeavyWallTowerB") == 1) || (IsObjectName(object, "HeavyWallTowerABlocking") == 1) || (IsObjectName(object, "HeavyWallTowerBBlocking") == 1) || (IsObjectName(object, "HeavyGateA") == 1)  || (IsObjectName(object, "HeavyGateB") == 1))
					{
						type = 2;
						linear = 1;
					}

				// Corner
				if ((IsObjectName(object, "LightOutsideCorner") == 1) || (IsObjectName(object, "MediumOutsideCorner") == 1) || (IsObjectName(object, "MediumBastion") == 1))
					{
						type = 2;
						corner = 1;
					}

				// Three-sided
				if ((IsObjectName(object, "LightRedan") == 1) || (IsObjectName(object, "MediumRedan") == 1))
					{
						type = 2;
						three_sided = 1;
					}

				// Four-sided
				if ((IsObjectName(object, "LightRedoubt") == 1) || (IsObjectName(object, "MediumRedoubt") == 1) || (IsObjectName(object, "HeavyCastleA") == 1) || (IsObjectName(object, "HeavyCastleB") == 1) || (IsObjectName(object, "HeavyKeep") == 1))
					{
						type = 2;
						four_sided = 1;
					}


				if (type > -1)
					{
						if (linear == 1)
							{
								rotation = GetObjectRotation(object);

								if (orientation == 0)
									{
										if (rotation == 0)
											{
												ret = Max(ret,type);
											}
									}

								if (orientation == 1)
									{
										if (rotation == 157)
											{
												ret = Max(ret,type);
											}
									}

								if (orientation == 2)
									{
										if (rotation == 314)
											{
												ret = Max(ret,type);
											}
									}

								if (orientation == 3)
									{
										if (rotation == 471)
											{
												ret = Max(ret,type);
											}
									}

							}

						if (corner == 1)
							{
								rotation = GetObjectRotation(object);

								if (orientation == 0)
									{
										if ((rotation == 0) || (rotation == 157))
											{
												ret = Max(ret,type);
											}
									}

								if (orientation == 1)
									{
										if ((rotation == 157) || (rotation == 314))
											{
												ret = Max(ret,type);
											}
									}

								if (orientation == 2)
									{
										if ((rotation == 314) || (rotation == 471))
											{
												ret = Max(ret,type);
											}
									}

								if (orientation == 3)
									{
										if ((rotation == 471) || (rotation == 0))
											{
												ret = Max(ret,type);
											}
									}
							}

						if (three_sided == 1)
							{
								rotation = GetObjectRotation(object);

								if (orientation == 0)
									{
										if ((rotation == 0) || (rotation == 157) || (rotation == 471))
											{
												ret = Max(ret,type);
											}
									}

								if (orientation == 1)
									{
										if ((rotation == 0) || (rotation == 157) || (rotation == 314))
											{
												ret = Max(ret,type);
											}
									}

								if (orientation == 2)
									{
										if ((rotation == 157) || (rotation == 314) || (rotation == 471))
											{
												ret = Max(ret,type);
											}
									}

								if (orientation == 3)
									{
										if ((rotation == 0) || (rotation == 314) || (rotation == 471))
											{
												ret = Max(ret,type);
											}
									}
							}


						if (four_sided == 1)
							{
								ret = Max(ret, type);
							}
					}

				// Fortification inside corners - uses non-standard method.
				if ((IsObjectName(object, "LightInsideCorner") == 1) || (IsObjectName(object, "MediumInsideCorner") == 1))
					{
						type = 2;
						rotation = GetObjectRotation(object);

						if (rotation == 314)
							{
								if ((x2 < x1) && (y2 > y1))
									{
										ret = Max(ret,type);
									}
							}

						if (rotation == 471)
							{
								if ((x2 < x1) && (y2 < y1))
									{
										ret = Max(ret,type);
									}
							}

						if (rotation == 0)
							{
								if ((x2 > x1) && (y2 < y1))
									{
										ret = Max(ret,type);
									}
							}

						if (rotation == 157)
							{
								if ((x2 > x1) && (y2 > y1))
									{
										ret = Max(ret,type);
									}
							}
					}

				// Road straight hedges
				if (IsObjectName(object, "ShrubsRoadStraight") == 1)
					{
						type = 1;
						rotation = GetObjectRotation(object);

						if ((orientation == 0) || (orientation == 2))
							{
								if ((rotation == 157) || (rotation == 471))
									{
										ret = Max(ret,type);
									}
							}

						if ((orientation == 1) || (orientation == 3))
							{
								if ((rotation == 0) || (rotation == 314))
									{
										ret = Max(ret,type);
									}
							}
					}

				// Road bend hedges - perforce uses non-standard method
				if (IsObjectName(object, "ShrubsRoadBend") == 1)
					{
						type = 1;
						rotation = GetObjectRotation(object);

						if (rotation == 471)
							{
								if ((x2 <= x1) && (y2 >= y1))
									{
										ret = Max(ret,type);
									}
							}

						if (rotation == 0)
							{
								if ((x2 <= x1) && (y2 <= y1))
									{
										ret = Max(ret,type);
									}
							}

						if (rotation == 157)
							{
								if ((x2 >= x1) && (y2 <= y1))
									{
										ret = Max(ret,type);
									}
							}

						if (rotation == 314)
							{
								if ((x2 >= x1) && (y2 >= y1))
									{
										ret = Max(ret,type);
									}
							}
					}

				// T-hedges and X-hedges (Both of which probably give all round protection)
				if ((IsObjectName(object, "ShrubsRoadTSection") == 1) || (IsObjectName(object, "ShrubsRoadCrossroads") == 1))
					{
						type = 1;
						ret = Max(ret, type);
					}
			}
	}

	// Centred objects - reversible linear landscape objects on adjacent tile to defender's tile.

	adjX = x1;
	adjY = y1;
	if (orientation == 0)
		{
			adjX += 1;
		}
	if (orientation == 1)
		{
			adjY += 1;
		}
	if (orientation == 2)
		{
			adjX -= 1;
		}
	if (orientation == 3)
		{
			adjY -= 1;
		}

	for (i = 0; i < attempts; i++)
	{
		object = GetTileObject(adjX, adjY, i);
		if (object == -1)
			{
				i = attempts;
			}
		else
			{
				type = -1;

				// Reversible landscape Linear features with centred objects.
				if ((IsObjectName(object, "LowWallBroken") == 1) || (IsObjectName(object, "Chains") == 1) || (IsObjectName(object, "Ditch") == 1)) // Note: the Chains & Ditch objects do not currently exist.
					{
						type = 0;
					}

				if ((IsObjectName(object, "LowWall") == 1) || (IsObjectName(object, "LowWallGate") == 1) || (IsObjectName(object, "HighWallBroken") == 1) || (IsObjectName(object, "HighWallGate") == 1))
					{
						type = 1;
					}

				if (IsObjectName(object, "HighWall") == 1)
					{
						type = 3;
					}

				if (type > -1)
					{
						rotation = GetObjectRotation(object);

						// Orientations are the reverse of when defender is on same tile as object.

						if (orientation == 2)
							{
								if (rotation == 0)
									{
										ret = Max(ret,type);
									}
							}

						if (orientation == 3)
							{
								if (rotation == 157)
									{
										ret = Max(ret,type);
									}
							}

						if (orientation == 0)
							{
								if (rotation == 314)
									{
										ret = Max(ret,type);
									}
							}

						if (orientation == 1)
							{
								if (rotation == 471)
									{
										ret = Max(ret,type);
									}
							}

					}

			}
	}


	// Edge objects
	for (i = 0; i < attempts; i++)
	{
		half = 0;

		object = GetTileObject(edgeObjectX, edgeObjectY, i);
		if (object == -1)
			{
				i = attempts;
			}
		else
			{
				type = -1;

				if (IsObjectName(object, "ShrubsEdgeDense") == 1)
					{
						type = 1;
					}

				if (IsObjectName(object, "ShrubsEdgeDenseHalf") == 1)
					{
						type = 1;
						half = 1;
					}

				if (type > -1)
					{
						rotation = GetObjectRotation(object);
						if ((orientation == 0) || (orientation == 2))
							{
								edgePos = edgeObjectX * 100;

								if (GetObjectPositionX(object) == edgePos)
									{
										if (half == 1)
											{
//                        Log("orientation, rotation, x2, x1", orientation, rotation, x2, x1);
//                        Log("object, objx, objy", object, GetObjectPositionX(object), GetObjectPositionY(object));
												if (rotation == 157)
													{
														if (y2 >= y1)
															{
																ret = Max(ret,type);
															}
													}

												if (rotation == 471)
													{
														if (y2 <= y1)
															{
																ret = Max(ret,type);
															}
													}
											}
										else
											{
												ret = Max(ret,type);
											}
									}
							}

						if ((orientation == 1) || (orientation == 3))
							{
								edgePos = edgeObjectY * 100;

								if (GetObjectPositionY(object) == edgePos)
									{
										if (half == 1)
											{
//                        Log("orientation, rotation, x2, x1", orientation, rotation, x2, x1);
//                        Log("object, objx, objy", object, GetObjectPositionX(object), GetObjectPositionY(object));
												if (rotation == 0)
													{
														if (x2 >= x1)
															{
																ret = Max(ret,type);
															}
													}

												if (rotation == 314)
													{
														if (x2 <= x1)
															{
																ret = Max(ret,type);
															}
													}
											}
										else
											{
												ret = Max(ret,type);
											}
									}
							}
					}
			}
	}

	return ret;
}

// DEBUG
// Print defensive obstacle data - if we want to use this for UI purposes will need to define strings in localisation files.
FUNCTION PrintObstacleStatus(me, tilex, tiley)
{
	int type;

	type = IsTileEdgeDefendibleObstacle(GetUnitX(me), GetUnitY(me), tilex, tiley);
	if (type > -1)
		{
			PrintStringLiteral("\nDefended by ");
			PrintStringIndexed("IDS_OBSTACLETYPE", type);
			PrintStringLiteral(" against attack from this square\n");
		}
}
// END DEBUG


