using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using V3.Camera;
using V3.Effects;
using V3.Map;
namespace V3.Objects
{
///
/// Objects manager for all game objects, be is creatures or buildings or even simple landscape objects.
///
// ReSharper disable once ClassNeverInstantiated.Global
public class ObjectsManager : IObjectsManager
{
private List> mCreaturesByFactions;
private List mCreatureList;
private List mAddToSelectables;
private Quadtree mTextureQuadtree;
private Quadtree mInteractableQuadtree;
private readonly ContentManager mContentManager;
private readonly CreatureFactory mCreatureFactory;
private readonly IEffectsManager mEffectsManager;
private Rectangle mMapRectangle;
private List mAreas;
private readonly UpdatesPerSecond mFewerUpdates = new UpdatesPerSecond(15);
private readonly UpdatesPerSecond mEffectsCounter = new UpdatesPerSecond(0.2);
public List AddToSelectables => mAddToSelectables;
public List CreatureList => mCreatureList;
public List UndeadCreatures => mCreaturesByFactions[(int) Faction.Undead];
//public List KingdromCreatures => mCreaturesByFactions[(int) Faction.Kingdom];
//public List PlebCreatures => mCreaturesByFactions[(int) Faction.Plebs];
public ICreature PlayerCharacter { get; private set; }
public ICreature Boss { get; private set; }
public ICreature Prince { get; private set; }
public Castle Castle { get; private set; }
public ObjectsManager(ContentManager contentManager, CreatureFactory creatureFactory,
IEffectsManager effectsManager)
{
mContentManager = contentManager;
mCreatureFactory = creatureFactory;
mEffectsManager = effectsManager;
}
public void Initialize(IMapManager mapManager)
{
Clear();
mAddToSelectables = new List();
mCreatureList = new List();
mCreaturesByFactions = new List>();
// Make three lists because we have three factions.
for (int i = 0; i < 3; i++)
{
mCreaturesByFactions.Add(new List());
}
// Gets the initial values for the Quad Tree from the current map.
mInteractableQuadtree = new Quadtree(mapManager.SizeInPixel + new Point(128, 128));
mTextureQuadtree = new Quadtree(mapManager.SizeInPixel + new Point(128, 128));
mInteractableQuadtree.LoadContent(mContentManager);
mTextureQuadtree.LoadContent(mContentManager);
// Import map objects for drawing.
ImportMapObjects(mapManager.GetObjects());
// Save Map size in ObjectsManager.
mMapRectangle = new Rectangle(new Point(0), mapManager.SizeInPixel);
mAreas = mapManager.Areas;
}
public void Clear()
{
CreatureList?.Clear();
mCreaturesByFactions?.Clear();
for (int i = 0; i < 3; i++)
{
mCreaturesByFactions?.Add(new List());
}
PlayerCharacter = null;
Boss = null;
Prince = null;
Castle = null;
mInteractableQuadtree?.Clear();
mTextureQuadtree?.Clear();
}
public void CreatePlayerCharacter(Necromancer necromancer)
{
PlayerCharacter = necromancer;
AddCreature(necromancer);
}
public void CreateBoss(ICreature boss)
{
Boss = boss;
AddCreature(boss);
}
public void CreatePrince(ICreature prince)
{
Prince = prince;
AddCreature(prince);
}
public void CreateCreature(ICreature creature)
{
AddCreature(creature);
}
public void RemoveCreature(ICreature creature)
{
mCreatureList.Remove(creature);
mCreaturesByFactions[(int) creature.Faction].Remove(creature);
mInteractableQuadtree.RemoveItem(creature);
}
public void Draw(SpriteBatch spriteBatch, ICamera camera)
{
var objectsToDraw = mInteractableQuadtree.GetObjectsInRectangle(camera.ScreenRectangle);
var texturesToDraw = mTextureQuadtree.GetObjectsInRectangle(camera.ScreenRectangle);
IEnumerable ordered = from obj in objectsToDraw.Concat(texturesToDraw) orderby obj.Position.Y select obj;
foreach (var obj in ordered)
{
obj.Draw(spriteBatch);
}
}
public void DrawQuadtree(SpriteBatch spriteBatch)
{
mInteractableQuadtree.Draw(spriteBatch);
mTextureQuadtree.Draw(spriteBatch);
}
public void Update(GameTime gameTime, bool rightButtonPressed, Vector2 rightButtonPosition, ICamera camera)
{
foreach (var creature in mCreatureList)
{
if (creature.GetSelf() == null) continue;
creature.Update(gameTime, PlayerCharacter, rightButtonPressed, rightButtonPosition, mInteractableQuadtree, camera);
// Create a boss if castle is down
if (creature.IsAttackingBuilding != null && creature.IsAttackingBuilding.Name == "Burg")
{
if (creature.IsAttackingBuilding.Robustness <= 50 && Boss == null)
{
var king = mCreatureFactory.CreateKing(new Vector2(creature.IsAttackingBuilding.Position.X - 300, creature.IsAttackingBuilding.Position.Y + 130), MovementDirection.S); //
var knight1 = mCreatureFactory.CreateKnight(new Vector2(creature.IsAttackingBuilding.Position.X - 320, creature.IsAttackingBuilding.Position.Y + 110), MovementDirection.S); //
var knight2 = mCreatureFactory.CreateKnight(new Vector2(creature.IsAttackingBuilding.Position.X - 280, creature.IsAttackingBuilding.Position.Y + 150), MovementDirection.S); //
CreateBoss(king);
AddCreature(knight1);
AddCreature(knight2);
break;
}
//break;
}
// Checks if the creature moved out of the map and resets its position as appropriate.
if (!mMapRectangle.Contains(creature.Position))
{
creature.ResetPosition();
}
}
if (mFewerUpdates.IsItTime(gameTime))
{
mInteractableQuadtree.Update();
}
#region Boss Special Attack
// Play some cool effects when boss is spawned so he looks cooler.
// Added a small special attack which does at bit AoE damage.
if (mEffectsCounter.IsItTime(gameTime))
{
if (Boss != null && camera.ScreenRectangle.Contains(Boss.Position))
{
mEffectsManager.PlayOnce(new Quake(), Boss.Position.ToPoint(), new Point(256, 128));
var aoeRadius = new Rectangle(Boss.Position.ToPoint() - new Point(128), new Point(256));
var effectedCreatures = mInteractableQuadtree.GetObjectsInRectangle(aoeRadius);
foreach (var obj in effectedCreatures)
{
var creature = obj as ICreature;
if (creature != null && creature.Faction == Faction.Undead && creature.BoundaryRectangle.Intersects(aoeRadius))
{
creature.TakeDamage(10);
}
}
}
}
#endregion
#region Necromancer stuff
if (PlayerCharacter.IsSelected && rightButtonPressed)
{
var objectsUnderMouse =
mInteractableQuadtree.GetObjectsInRectangle(new Rectangle(rightButtonPosition.ToPoint(), new Point(1, 1)));
foreach (var obj in objectsUnderMouse)
{
var creature = obj as ICreature;
if (creature == null || !creature.SelectionRectangle.Contains(rightButtonPosition) || !creature.IsDead || creature.Faction == Faction.Undead) continue;
if (Vector2.Distance(PlayerCharacter.Position, creature.Position) > PlayerCharacter.AttackRadius) continue;
RemoveCreature(creature);
if (creature is KingsGuard || creature is King || creature is Prince)
{
CreateCreature(mCreatureFactory.CreateSkeletonElite(creature.Position, creature.MovementDirection));
}
else
{
CreateCreature(mCreatureFactory.CreateZombie(creature.Position, creature.MovementDirection));
}
PlayerCharacter.PlayAnimationOnce(MovementState.Special, TimeSpan.FromSeconds(0.5d));
mEffectsManager.PlayOnce(new BloodBang(), creature.Position.ToPoint(), new Point(128));
break;
}
}
#endregion Necromancer stuff
#region SkeletonRider
var recMouse = new Rectangle(rightButtonPosition.ToPoint(), new Point(1, 1));
foreach (var creature in UndeadCreatures)
{
Skeleton skeleton = creature as Skeleton;
if (skeleton != null)
{
if(skeleton.IsSelected && rightButtonPressed)
{
var atMousPosition = mInteractableQuadtree.GetObjectsInRectangle(recMouse);
foreach (var wannabehorse in atMousPosition)
{
var horse = wannabehorse as SkeletonHorse;
if (horse != null && Vector2.Distance(skeleton.Position, horse.Position) < 32)
{
horse.Mount(skeleton);
horse.IsSelected = true;
mAddToSelectables.Add(horse);
}
}
}
}
}
#endregion SkeletonRider
}
private void AddCreature(ICreature creature)
{
if (!mMapRectangle.Contains(creature.BoundaryRectangle)) return;
mCreatureList.Add(creature);
mCreaturesByFactions[(int) creature.Faction].Add(creature);
mInteractableQuadtree.Insert(creature);
}
public void ImportMapObjects(List textureObjects)
{
foreach (var obj in textureObjects)
{
if (obj is IBuilding)
{
mInteractableQuadtree.Insert(obj);
if (obj is Castle)
Castle = (Castle) obj;
}
else
{
mTextureQuadtree.Insert(obj);
}
}
}
public List GetObjectsInRectangle(Rectangle rectangle)
{
return mInteractableQuadtree.GetObjectsInRectangle(rectangle);
}
public List GetCreaturesInEllipse(Ellipse ellipse)
{
var setToReturn = new List();
foreach (var obj in mInteractableQuadtree.GetObjectsInRectangle(ellipse.BoundaryRectangle))
{
ICreature creature = obj as ICreature;
if (creature != null && ellipse.Contains(creature.Position))
{
setToReturn.Add(creature);
}
}
return setToReturn;
}
public void ExposeTheLiving()
{
foreach (var creature in mCreatureList)
{
if (creature.Faction == Faction.Plebs)
{
(creature as MalePeasant)?.RemoveArmor();
(creature as FemalePeasant)?.RemoveArmor();
}
else if (creature.Faction == Faction.Kingdom)
{
(creature as Knight)?.RemoveArmor();
(creature as KingsGuard)?.RemoveArmor();
}
}
}
public bool InGraveyardArea(ICreature creature)
{
return mAreas.Where(area => area.Type == AreaType.Graveyard).Select(area => area.Contains(creature)).Any(contains => contains);
}
}
}