#region Copyright
/*
--------------------------------------------------------------------------------
This source file is part of Xenocide
by Project Xenocide Team
For the latest info on Xenocide, see http://www.projectxenocide.com/
This work is licensed under the Creative Commons
Attribution-NonCommercial-ShareAlike 2.5 License.
To view a copy of this license, visit
http://creativecommons.org/licenses/by-nc-sa/2.5/
or send a letter to Creative Commons, 543 Howard Street, 5th Floor,
San Francisco, California, 94105, USA.
--------------------------------------------------------------------------------
*/
/*
* @file EquipSoldierScreen.cs
* @date Created: 2007/11/17
* @author File creator: David Teviotdale
* @author Credits: none
*/
#endregion
#region Using Statements
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using ProjectXenocide.Utils;
using ProjectXenocide.Model.Geoscape;
using ProjectXenocide.Model.Geoscape.Outposts;
using ProjectXenocide.Model.StaticData.Items;
using ProjectXenocide.Model.Battlescape;
using ProjectXenocide.Model.Battlescape.Combatants;
using ProjectXenocide.UI.Scenes;
#endregion
// alias Vector2
using Vector2 = Microsoft.Xna.Framework.Vector2;
using Xenocide.Resources;
namespace ProjectXenocide.UI.Screens
{
///
/// This is the screen that lets player set the items a soldier carries
///
public partial class EquipSoldierScreen : Screen
{
///
/// Constructor used to equip soldiers in an outpost
///
/// Soldiers player can select from
/// Soldier in the list to initially show
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:ValidateArgumentsOfPublicMethods",
Justification = "Will throw if soldier is null")]
public EquipSoldierScreen(IEnumerable soldiers, Person soldier)
: base("EquipSoldierScreen", null)
{
itemSource = new OutpostItemSource(soldier.Outpost.Inventory);
controller = new InOutpostController(this, soldiers, soldier);
}
///
/// Constructor used to adjust combatants on a battlescape
///
/// Combatant who's inventory is being examined/adjusted
/// the battlescape
/// Is screen look only mode? (i.e. combatant is being psi probed)
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:ValidateArgumentsOfPublicMethods",
Justification = "Will throw if soldier is null")]
public EquipSoldierScreen(Combatant combatant, Battle battlescape, bool lookOnly)
: base("EquipSoldierScreen", null)
{
this.itemSource = new BattlescapeItemSource(battlescape, combatant.Position);
this.controller = new BattlescapeController(this, battlescape, combatant);
this.lookOnly = lookOnly;
}
//ToDo:
//A second constructor, used on the battlescape
///
/// Removes the frame from the display
///
protected override void Dispose(bool disposing)
{
try
{
if (disposing)
{
if (scene != null)
{
scene.Dispose();
scene = null;
}
}
}
finally
{
base.Dispose(disposing);
}
}
///
/// Load the Scene's graphic content
///
/// content manager that fetches the content
/// the display
public override void LoadContent(ContentManager content, GraphicsDevice device)
{
scene.LoadContent();
}
///
/// Render the 3D scene
///
/// time interval since last render
/// Device to render the screen to
public override void Draw(GameTime gameTime, GraphicsDevice device)
{
Rectangle sceneWindow = GetSceneRectangle(device);
scene.BeginDraw(sceneWindow);
scene.DrawSoldiersInventory(sceneWindow, controller.Combatant.Inventory);
scene.DrawItemBeingMoved(sceneWindow, movingItem, cursorPosition);
itemSource.Draw(sceneWindow, scene);
scene.EndDraw();
}
#region Create the CeGui widgets
///
/// add the buttons to the screen
///
protected override void CreateCeguiWidgets()
{
// Text detailing ammo in weapon/clip
ammoText = AddStaticText(0.7475f, 0.50f, 0.2275f, 0.08f);
ShowAmmoString();
// buttons
closeButton = AddButton("BUTTON_CLOSE", 0.7025f, 0.08f, 0.2275f, 0.04125f);
leftButton = AddButton("BUTTON_SCROLL_LEFT", 0.7025f, 0.13f, 0.2275f, 0.04125f);
rightButton = AddButton("BUTTON_SCROLL_RIGHT", 0.7025f, 0.18f, 0.2275f, 0.04125f);
closeButton.Clicked += new CeGui.GuiEventHandler( OnCloseButton);
leftButton.Clicked += new CeGui.GuiEventHandler( OnLeftButton);
rightButton.Clicked += new CeGui.GuiEventHandler( OnRightButton);
RootWidget.MouseButtonsDown += new CeGui.MouseEventHandler(OnMouseDownInScene);
RootWidget.MouseMove += new CeGui.MouseEventHandler(OnMouseMoveInScene);
AddStaticText("SCREEN_EQUIP_SOLDIER_LEFT_SHOULDER", 0.3054f, 0.130f, 0.2275f, 0.05f);
AddStaticText("SCREEN_EQUIP_SOLDIER_RIGHT_SHOULDER", 0.0734f, 0.130f, 0.2275f, 0.05f);
AddStaticText("SCREEN_EQUIP_SOLDIER_LEFT_HAND", 0.3174f, 0.230f, 0.2275f, 0.05f);
AddStaticText("SCREEN_EQUIP_SOLDIER_RIGHT_HAND", 0.0820f, 0.230f, 0.2275f, 0.05f);
AddStaticText("SCREEN_EQUIP_SOLDIER_LEFT_LEG", 0.3194f, 0.480f, 0.2275f, 0.05f);
AddStaticText("SCREEN_EQUIP_SOLDIER_RIGHT_LEG", 0.0825f, 0.480f, 0.2275f, 0.05f);
AddStaticText("SCREEN_EQUIP_SOLDIER_BACKPACK", 0.4934f, 0.230f, 0.2275f, 0.05f);
AddStaticText("SCREEN_EQUIP_SOLDIER_BELT", 0.5104f, 0.480f, 0.2275f, 0.05f);
controller.CreateCeguiWidgets();
}
private CeGui.Widgets.StaticText ammoText;
private CeGui.Widgets.PushButton closeButton;
private CeGui.Widgets.PushButton leftButton;
private CeGui.Widgets.PushButton rightButton;
#endregion Create the CeGui widgets
#region event handlers
/// React to user pressing the Close button
/// Not used
/// Not used
private void OnCloseButton(object sender, CeGui.GuiEventArgs e)
{
controller.OnCloseButton();
}
/// React to user pressing the Left button
/// Not used
/// Not used
private void OnLeftButton(object sender, CeGui.GuiEventArgs e)
{
itemSource.ScrollLeft();
}
/// React to user pressing the Right button
/// Not used
/// Not used
private void OnRightButton(object sender, CeGui.GuiEventArgs e)
{
itemSource.ScrollRight();
}
/// React to user moving the mouse in the 3D scene
/// Not used
/// Mouse information
private void OnMouseMoveInScene(object sender, CeGui.MouseEventArgs e)
{
// record the mouse position, we will need it later
cursorPosition = new Vector2(e.Position.X, e.Position.Y);
}
/// React to user clicking mouse in the 3D scene
/// CeGui widget sending the event
/// Mouse information
private void OnMouseDownInScene(object sender, CeGui.MouseEventArgs e)
{
// if in look only mode, then can't pick up/drop or move items
if (lookOnly)
{
return;
}
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
OnLeftMouseDown((int)e.Position.X, (int)e.Position.Y);
}
else if (e.Button == System.Windows.Forms.MouseButtons.Right)
{
OnRightMouseDown((int)e.Position.X, (int)e.Position.Y);
}
}
#endregion event handlers
///
/// Called when user has left clicked mouse
///
/// position of mouse when clicked
/// position of mouse when clicked
private void OnLeftMouseDown(int x, int y)
{
// figure out what mouse is pointing at
Rectangle sceneRect = GetSceneRectangle(Xenocide.Instance.GraphicsDevice);
InventoryLocation location = InventoryLocation.FromMousePosition(x, y, sceneRect);
Dump(location);
// user is either picking up or dropping an item (or we ignore the click)
if (null != location)
{
if (null == movingItem)
{
StartMovingItem(location);
}
else
{
PutItemDown(location);
}
}
ShowAmmoString();
}
///
/// Called when user has right clicked mouse
///
/// position of mouse when clicked
/// position of mouse when clicked
private void OnRightMouseDown(int x, int y)
{
// if there's alread a item being moved, ignore the event
if (null == movingItem)
{
// figure out what mouse is pointing at
Rectangle sceneRect = GetSceneRectangle(Xenocide.Instance.GraphicsDevice);
InventoryLocation location = InventoryLocation.FromMousePosition(x, y, sceneRect);
// if it's over an item, then user has asked us to unload it
if ((null != location) && (location.IsOnSoldier))
{
Item item = controller.Combatant.Inventory.ItemAt(location.X, location.Y);
if ((null != item) && (item.HoldsAmmo))
{
movingItem = item.Unload();
ShowAmmoString();
}
}
}
}
///
/// Try to pick up the item under the mouse
///
/// mouse location
private void StartMovingItem(InventoryLocation location)
{
Debug.Assert(null == movingItem);
if (location.IsOnSoldier)
{
CombatantInventory ci = controller.Combatant.Inventory;
movingItem = ci.ItemAt(location.X, location.Y);
if (null != movingItem)
{
ci.Remove(movingItem);
}
}
else
{
movingItem = itemSource.FetchItem(location.X, location.Y);
}
}
///
/// Try to put item down at mouse's current location
///
/// mouse location
private void PutItemDown(InventoryLocation location)
{
Debug.Assert(null != movingItem);
if (location.IsOnSoldier)
{
// put item into this location in the soldier's inventory
CombatantInventory ci = controller.Combatant.Inventory;
if (ci.CanFit(movingItem, location.X, location.Y))
{
ci.Insert(movingItem, location.X, location.Y);
movingItem = null;
}
else
{
// item can't fit.
// If location is occupied, perhaps user is trying to load a weapon
Item target = ci.ItemAt(location.X, location.Y);
if (null != target)
{
TryLoadingItem(target);
}
}
}
else
{
ReleaseMovingItem();
}
}
///
/// Get coordinates where scene will be drawn on window
///
/// Device to render the screen to
/// the co-ordinates
private static Rectangle GetSceneRectangle(GraphicsDevice device)
{
Viewport port = device.Viewport;
return new Rectangle(port.X, port.Y, port.Width, port.Height);
}
///
/// Show ammo state of currently selected item, if it holds ammo
///
private void ShowAmmoString()
{
StringBuilder description = new StringBuilder();
// if there's no item selected, or item doesn't hold ammo, string is empty
if ((null != movingItem) && (null != movingItem.ItemInfo.AmmoInfo))
{
// if can hold multiple ammo types, give type currently carrying
if ((1 < movingItem.ItemInfo.AmmoInfo.Ammos.Count) && movingItem.HoldsAmmo)
{
description.Append(Util.StringFormat(Strings.SCREEN_EQUIP_SOLDIER_AMMO_TYPE, movingItem.AmmoInfo.Name));
description.Append(Util.Linefeed);
}
// number of rounds
description.Append(Util.StringFormat(Strings.SCREEN_EQUIP_SOLDIER_AMMO_QUANTITY, movingItem.ShotsLeft));
}
ammoText.Text = description.ToString();
}
///
/// Try loading selected item with item we're moving
///
/// item we're trying to put clip into
private void TryLoadingItem(Item target)
{
// only works if we're trying to insert a clip, and target can use this clip type
if (target.IsAmmoValid(movingItem))
{
movingItem = target.Load(movingItem);
}
}
///
/// Put the item we moving where we're getting items from
///
private void ReleaseMovingItem()
{
if (null != movingItem)
{
itemSource.ReplaceItem(movingItem);
movingItem = null;
}
}
///
/// Quick and dirty function for testing location
///
[Conditional("DEBUG")]
private static void Dump(InventoryLocation location)
{
StringBuilder sb = new StringBuilder("Location = ");
if (null != location)
{
if (location.IsOnSoldier)
{
sb.Append(InventoryLayout.GetZone(location.X, location.Y).ToString());
}
else
{
sb.Append("on ground");
}
sb.Append(". x = ");
sb.Append(Util.ToString(location.X));
sb.Append(", y = ");
sb.Append(Util.ToString(location.Y));
}
Debug.WriteLine(sb.ToString());
}
#region Fields
///
/// Item currently being moved
///
public Item MovingItem
{
get { return movingItem; }
set
{
// it's an error if we're already moving an item
Debug.Assert(null == movingItem);
movingItem = value;
ShowAmmoString();
}
}
///
/// The view shown on the screen
///
private EquipSoldierScene scene = new EquipSoldierScene();
///
/// Item currently being moved
///
private Item movingItem;
///
/// Location of cursor on screen;
///
private Vector2 cursorPosition = new Vector2();
///
/// where we're getting the items we're adding to a soldier
///
private ItemSource itemSource;
/// Control screen behaviour that's specific to mode screen is running in
private Controller controller;
/// Is screen look only mode? (i.e. combatant is being psi probed)
private bool lookOnly;
#endregion Fields
}
}