#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 AeroscapeScreen.cs
* @date Created: 2007/07/23
* @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 CeGui;
using ProjectXenocide.Utils;
using ProjectXenocide.Model.Geoscape;
using ProjectXenocide.Model.Geoscape.Outposts;
using ProjectXenocide.Model.Geoscape.Vehicles;
using ProjectXenocide.Model.StaticData.Items;
using ProjectXenocide.Model.Battlescape;
using Xenocide.Resources;
#endregion
namespace ProjectXenocide.UI.Screens
{
///
/// This is the screen where Ufos and Aircraft fight
///
public class AeroscapeScreen : Screen
{
///
/// Constructor (obviously)
///
/// The human aircraft
/// The Ufo
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:ValidateArgumentsOfPublicMethods",
Justification = "Want it to throw if aircraft or ufo is null")]
public AeroscapeScreen(Aircraft aircraft, Ufo ufo)
: base("AeroscapeScreen")
{
this.aircraft = aircraft;
this.ufo = ufo;
aircraft.OnDogfightStart();
ufo.OnDogfightStart();
}
#region Create the CeGui widgets
///
/// add the buttons to the screen
///
protected override void CreateCeguiWidgets()
{
// add text giving the craft name
craftNameText = GuiBuilder.CreateText(CeguiId + "_craftNameText");
AddWidget(craftNameText, 0.01f, 0.06f, 0.2275f, 0.04f);
craftNameText.Text = aircraft.Name;
// text giving craft damage
craftDamageText = GuiBuilder.CreateText(CeguiId + "_craftDamageText");
AddWidget(craftDamageText, 0.31f, 0.06f, 0.2275f, 0.04f);
// text describing Pod 1
pod1Text = GuiBuilder.CreateText(CeguiId + "_pod1Text");
AddWidget(pod1Text, 0.01f, 0.12f, 0.2275f, 0.16125f);
// text describing Pod 2
pod2Text = GuiBuilder.CreateText(CeguiId + "_pod2Text");
AddWidget(pod2Text, 0.31f, 0.12f, 0.2275f, 0.16125f);
// events this turn
logText = GuiBuilder.CreateText(CeguiId + "_logText");
AddWidget(logText, 0.31f, 0.30f, 0.70f, 0.60f);
DrawScreen();
// buttons
realTimeButton = AddButton("BUTTON_REAL_TIME", 0.7475f, 0.85f, 0.2275f, 0.04125f);
advanceTimeButton = AddButton("BUTTON_ADVANCE_TIME", 0.7475f, 0.90f, 0.2275f, 0.04125f);
closeButton = AddButton("BUTTON_CLOSE", 0.7475f, 0.95f, 0.2275f, 0.04125f);
realTimeButton.Clicked += new CeGui.GuiEventHandler(OnRealTimeButton);
advanceTimeButton.Clicked += new CeGui.GuiEventHandler(OnAdvanceTimeButton);
closeButton.Clicked += new CeGui.GuiEventHandler(OnCloseButton);
}
private CeGui.Widgets.StaticText craftNameText;
private CeGui.Widgets.StaticText craftDamageText;
private CeGui.Widgets.StaticText pod1Text;
private CeGui.Widgets.StaticText pod2Text;
private CeGui.Widgets.StaticText logText;
private CeGui.Widgets.PushButton realTimeButton;
private CeGui.Widgets.PushButton advanceTimeButton;
private CeGui.Widgets.PushButton closeButton;
#endregion Create the CeGui widgets
#region event handlers
/// Handle user clicking on the "Real Time" button
/// Not used
/// Not used
private void OnRealTimeButton(object sender, GuiEventArgs e)
{
runRealTime = true;
}
/// Handle user clicking on the "Advance Time" button
/// Not used
/// Not used
private void OnAdvanceTimeButton(object sender, GuiEventArgs e)
{
runRealTime = false;
UpdateDogfight();
}
/// React to user pressing the Close button
/// Not used
/// Not used
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope",
Justification = "FxCop False Positive")]
private void OnCloseButton(object sender, CeGui.GuiEventArgs e)
{
// Tell UFO & aircraft that fight's over
if (!ufo.IsDestroyed)
{
ufo.OnDogfightFinished();
}
if (!aircraft.IsDestroyed)
{
aircraft.OnDogfightFinished();
}
ScreenManager.ScheduleScreen(new GeoscapeScreen());
}
#endregion event handlers
///
/// Hook the main message pump
///
/// Provides a snapshot of timing values.
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:ValidateArgumentsOfPublicMethods",
Justification = "will throw if gameTime is null")]
public override void Update(GameTime gameTime)
{
// if we're running this dialog "real time" and sufficient time has passed
// then do another "round" of the aeroscape battle
if (runRealTime)
{
elapsed += gameTime.ElapsedGameTime.TotalMilliseconds;
if (1000.0 < elapsed)
{
UpdateDogfight();
}
}
}
///
/// Draw everything on the screen
///
private void DrawScreen()
{
DrawAircraftDamage();
DrawPodInformation();
DrawLog();
}
///
/// Show the state of the the human craft's hull
///
private void DrawAircraftDamage()
{
craftDamageText.Text =
Util.StringFormat(Strings.SCREEN_AEROSCAPE_HULL_LEFT, aircraft.HullPercent);
}
///
/// Show the information for the weapon pods for a craft
///
private void DrawPodInformation()
{
// Start assuming craft has no pods
pod1Text.Hide();
pod2Text.Hide();
// Document Pod 1, if it exists
if (0 < aircraft.WeaponPods.Count)
{
DrawPodInformation(pod1Text, aircraft.WeaponPods[0], 1);
}
// Document Pod 2, if it exists
if (1 < aircraft.WeaponPods.Count)
{
DrawPodInformation(pod2Text, aircraft.WeaponPods[1], 2);
}
}
///
/// Update the details for a specific weapon pod
///
/// Control to write details to
/// Pod to get information for
/// Pod 1 or Pod 2?
private static void DrawPodInformation(CeGui.Widgets.StaticText textControl, WeaponPod pod, int podId)
{
textControl.Show();
StringBuilder info = new StringBuilder(Util.StringFormat(Strings.SCREEN_EQUIP_CRAFT_POD_NAME, podId));
info.Append(Util.Linefeed);
// can't just call pod.PodInformationString(), because pod may be null
info.Append(WeaponPod.PodInformationString(pod));
textControl.Text = info.ToString();
}
///
/// Show what happened in the last second of the fight
///
private void DrawLog()
{
StringBuilder sb = new StringBuilder(Util.StringFormat(Strings.SCREEN_AEROSCAPE_LOG_TIME, log.Now));
foreach (BattleLog.LogEntry entry in log.Entries)
{
if (entry.Time == log.Now)
{
sb.Append(Util.Linefeed);
sb.Append(entry.Details);
}
}
logText.Text = sb.ToString();
}
///
/// Update the dogfight's state
///
private void UpdateDogfight()
{
// we're starting a new round
elapsed = 0.0;
// if fight's over, nothing to do
if (!dogfightOver)
{
// repeat until something happens
int logsize = log.Entries.Count;
do
{
// prepare log for events
log.UpdateTime(1.0);
// Aircraft and UFO trade blows
Attack(aircraft, ufo);
if (!dogfightOver)
{
// unarmed ufos can't attack
if (ufo.IsArmed)
{
Attack(ufo, aircraft);
}
}
} while (!dogfightOver && log.Entries.Count == logsize);
DrawScreen();
}
}
///
/// Have one craft try to attack other
///
/// craft doing the shooting
/// craft getting hit
private void Attack(Craft attacker, Craft target)
{
AttackResult result = attacker.Attack(target, log);
switch (result)
{
case AttackResult.OpponentCrashed:
case AttackResult.OpponentDestroyed:
case AttackResult.OpponentFled:
case AttackResult.OutOfAmmo:
dogfightOver = true;
break;
case AttackResult.Nothing:
// Nothing to do
break;
default:
// should never get here
Debug.Assert(false);
break;
}
}
#region Fields
///
/// Has the fight finished?
///
private bool dogfightOver;
///
/// The UFO
///
private Ufo ufo;
///
/// The human craft
///
private Aircraft aircraft;
///
/// What happens during the battle
///
private BattleLog log = new BattleLog();
///
/// Run aeroscape battle in "real time"
///
bool runRealTime;
///
/// Number of milliseconds that have elapsesed since last combat "round"
///
double elapsed;
#endregion Fields
}
}