/*
* LOSCheckAI.cs
* Authors: Karl Orosz
* Copyright (c) 2007-2008 Cornell University
This program 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.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
using System.Collections.Generic;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
namespace StarJack
{
///
/// This class will check if a Game Object is in this objects line of site.
///
public class LOSCheckAI : AI, DrawableAI, DefferedTurn
{
private static Entity mMouse;
public static Entity Mouse
{
get { return mMouse; }
set { mMouse = value; }
}
private static bool mMouseOver;
public static bool MouseOver
{
get { return mMouseOver; }
set { mMouseOver = value; }
}
private static bool mLOSDraw = false;
public static void ToggleLOSDraw()
{
mLOSDraw = !mLOSDraw;
}
private bool mDraw = false;
Tile mLOS;
bool[,] mLosGrid;
List view;
private GameObject mMe;
private GameObject mThem;
public GameObject LookFor
{
get { return mThem; }
set { mThem = value; }
}
private GameObject.Direction mLook;
int[] sides;
int[] temp;
int[] myPos;
int[] dir;
public LOSCheckAI(GameObject tied, GameObject lookFor)
{
mMe = tied;
mThem = lookFor;
curPriority = Priority.Low;
mLook = mMe.Facing;
sides = new int[2] { 0, 0 };
dir = new int[2] { 0, 0 };
temp =new int[2]{0,0};
myPos = new int[2] { 0, 0 };
mLOS = new Tile("LOS");
mLOS.Depth = Room.Depth.Tile - 0.001f ;
mLOS.TextureName = "LOS";
mLosGrid = new bool[Room.TILECOUNT, Room.TILECOUNT];
}
///
/// This routine will calculate a line between the 2 objects and determine
/// if there's any collidable tiles blocking it's view.
///
///
public override void TakeTurn(int pTurn, bool deffered)
{
mDraw = false;
//break out if the target un undetectable
//if (!mThem.Detectable) { return; }
//Resets the los array;
for(int a = 0; a < Room.TILECOUNT; a++)
{
for (int b = 0; b < Room.TILECOUNT; b++)
{
mLosGrid[a,b] = false;
}
}
//Check direction
dir[0]=0;
dir[1] = 0;
switch (mMe.Facing)
{
case GameObject.Direction.Down:
dir[1] = 1;
break;
case GameObject.Direction.Up:
dir[1] = -1;
break;
case GameObject.Direction.Left:
dir[0] = -1;
break;
case GameObject.Direction.Right:
dir[0] = 1;
break;
}
mMe.Position.CopyTo(myPos, 0);
myPos[0] += dir[0];
myPos[1] += dir[1];
view = new List();
view.Add(mMe.Position.Clone() as int[]);
if (!mMe.MyRoom.CheckCollision(mMe, myPos))
{
sides[0] = 0;
sides[1] = 0;
//Determines width of view
//Up or down
if (dir[0] == 0)
{
bool left;
bool leftAdd = false;
bool right;
bool rightAdd = false;
do
{
//left
temp[0] = myPos[0] - sides[0] - 1;
temp[1] = myPos[1] + sides[0] * dir[1] + 1 * dir[1];
left = mMe.MyRoom.CheckCollision(mMe, temp);
if (!left)
{
view.Add(temp.Clone() as int[]);
sides[0]++;
}
else if( !leftAdd)
{
if (temp[0] == mThem.Position[0] && temp[1] == mThem.Position[1])
{
view.Add(temp.Clone() as int[]);
}
leftAdd = true;
}
//right
temp[0] = myPos[0] + sides[1] + 1;
temp[1] = myPos[1] + sides[1] * dir[1] + 1 * dir[1];
right = mMe.MyRoom.CheckCollision(mMe, temp);
if (!right)
{
view.Add(temp.Clone() as int[]);
sides[1]++;
}
else if (!rightAdd)
{
if (temp[0] == mThem.Position[0] && temp[1] == mThem.Position[1])
{
view.Add(temp.Clone() as int[]);
}
rightAdd = true;
}
}
while (!left || !right);
}
else
{
bool up;
bool upAdd = false;
bool down;
bool downAdd = false;
do
{
temp[0] = myPos[0] + sides[0] * dir[0] + 1 * dir[0];
temp[1] = myPos[1] - sides[0] - 1;
down = mMe.MyRoom.CheckCollision(mMe, temp);
if (!down)
{
view.Add(temp.Clone() as int[]);
sides[0]++;
}
else if (!downAdd)
{
if (temp[0] == mThem.Position[0] && temp[1] == mThem.Position[1])
{
view.Add(temp.Clone() as int[]);
}
downAdd = true;
}
temp[0] = myPos[0] + sides[1] * dir[0] + 1 * dir[0];
temp[1] = myPos[1] + sides[1] + 1;
up = mMe.MyRoom.CheckCollision(mMe, temp);
if (!up)
{
view.Add(temp.Clone() as int[]);
sides[1]++;
}
else if (!upAdd)
{
if (temp[0] == mThem.Position[0] && temp[1] == mThem.Position[1])
{
view.Add(temp.Clone() as int[]);
}
upAdd = true;
}
}
while (!down || !up);
}
}
CheckLOS();
}
private void CheckLOS()
{
bool end = false;
int[] checkRadial = new int[] { 0, 0 };
foreach (int[] pos in view)
{
temp = pos.Clone() as int[];
do
{
end = mMe.MyRoom.CheckCollision(mMe, temp);
if (temp[0] == mThem.Position[0] && temp[1] == mThem.Position[1])
{
if (mThem.Detectable)
{
mThem.Detected = true;
mDraw = true;
mLosGrid[temp[0], temp[1]] = true;
}
}
else
{
//Checks if the player is within 1 unit of the LOS
if (!end &&( (temp[0] - 1 == mThem.Position[0] && temp[1] == mThem.Position[1])
|| (temp[0] + 1 == mThem.Position[0] && temp[1] == mThem.Position[1])
|| (temp[0] - 1 == mThem.Position[0] && temp[1] - 1 == mThem.Position[1])
|| (temp[0] + 1 == mThem.Position[0] && temp[1] - 1 == mThem.Position[1])
|| (temp[0] - 1 == mThem.Position[0] && temp[1] + 1 == mThem.Position[1])
|| (temp[0] + 1 == mThem.Position[0] && temp[1] + 1 == mThem.Position[1])
|| (temp[0] == mThem.Position[0] && temp[1] - 1 == mThem.Position[1])
|| (temp[0] == mThem.Position[0] && temp[1] + 1 == mThem.Position[1])))
{
mDraw = true;
}
}
if (!end)
{
mLosGrid[temp[0], temp[1]] = true;
}
temp[0] += dir[0];
temp[1] += dir[1];
} while (!end);
}
}
public override void Reset()
{
//nothing
}
#region DrawableAI Members
public void Draw(SpriteBatch pSpriteBatch)
{
bool draw = false;
if (mMouseOver)
{
int[] tile = Room.CalcTileCoord(new int[] { mMouse.X, mMouse.Y });
if (tile[0] == 8 && tile[1] == 1)
{
}
if (tile[0] == mMe.Position[0] && tile[1] == mMe.Position[1])
{
draw = true;
}
}
draw = mDraw;
if (mLOSDraw)
{
draw = true;
}
if (draw)
{
int[] pos = new int[] { 0, 0 };
//Draws the los array;
for (int a = 0; a < Room.TILECOUNT; a++)
{
for (int b = 0; b < Room.TILECOUNT; b++)
{
if (mLosGrid[a, b])
{
pos[0] = a;
pos[1] = b;
mLOS.Position = pos;
mLOS.Draw(pSpriteBatch);
}
}
}
}
}
public void LoadContent(ContentManager pContent)
{
mLOS.LoadContent(pContent);
}
#endregion
}
}