#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 SoldiersListScreen.cs * @date Created: 2007/10/06 * @author File creator: David Cameron * @author Credits: none */ #endregion #region Using Statements using System; using System.Collections.Generic; using System.Diagnostics; using System.Text; using CeGui; using ProjectXenocide.Model.Geoscape; using ProjectXenocide.Utils; using CeGui.Widgets; using ProjectXenocide.Model.StaticData.Items; using ProjectXenocide.Model.Geoscape.Outposts; using ProjectXenocide.Model.Geoscape.Vehicles; using ProjectXenocide.Model.Battlescape.Combatants; using Xenocide.Resources; using ProjectXenocide.UI.Dialogs; #endregion namespace ProjectXenocide.UI.Screens { /// /// Lists soldiers currently at the base. /// public class SoldiersListScreen : Screen { /// /// Constructs a screen listing the soldiers stationed at the given base. /// public SoldiersListScreen(int selectedOutpostIndex) : base("SoldiersListScreen", @"Content\Textures\UI\BasesScreenBackground.png") { this.selectedOutpostIndex = selectedOutpostIndex; // can only equip the soldiers currently at the outpost soldiers = new List(); foreach (Person soldier in SelectedOutpost.ListStaff("ITEM_PERSON_SOLDIER")) { Aircraft aircraft = soldier.Aircraft; if ((null == aircraft) || (aircraft.InBase)) { soldiers.Add(soldier); } } } #region Create the CeGui widgets /// /// Add all the widgets to the screen. We'll delegate to a different method for each /// part of the screen. /// protected override void CreateCeguiWidgets() { InitializeSoldiersGrid(); InitializeSoldierDetailPanel(); CreateRightHandButtons(); } /// /// Section at the top of the left hand panel that shows the soldier's details. /// private void InitializeSoldierDetailPanel() { // edit box for soldier name nameEditBox = AddEditBox("EDITBOX_NAME", 0.01f, 0.06f, 0.70f, 0.12f); nameEditBox.Font = FontManager.Instance.GetFont("LargeBaseName"); nameEditBox.TextAccepted += new WindowEventHandler(OnSoldierNameChanged); // attributes attributesGrid = AddGrid(0.01f, 0.20f, 0.70f, 0.75f, Strings.SCREEN_SOLDIERS_LIST_COLUMN_ATTRIBUTE, 0.49f, Strings.SCREEN_SOLDIERS_LIST_COLUMN_VALUE, 0.50f ); PopulateSoldierDetailPanel(); } /// /// List of soldiers in the bottom of the left hand panel. /// private void InitializeSoldiersGrid() { soldiersListGrid = GuiBuilder.CreateListBox("soldiersListGrid"); AddWidget(soldiersListGrid, 0.7475f, 0.06f, 0.24f, 0.70f); soldiersListGrid.SelectionChanged += new WindowEventHandler(OnSelectedSoldierChanged); RefreshSoldiersGrid(); } /// /// Display (or redisplay) soldiers stationed at this base. If a soldier is selected /// when this is called, the same soldier will be selected afterwards. /// private void RefreshSoldiersGrid() { // if no soldier selected, select first one in list int selectedSoldierIndex = 0; if (null != SelectedSoldier) { selectedSoldierIndex = soldiers.IndexOf(SelectedSoldier); } soldiersListGrid.ResetList(); for (int i = 0; i < soldiers.Count; i++) { ListboxItem item = soldiersListGrid.AddItem(soldiers[i].Name); item.ID = i; item.Selected = (i == selectedSoldierIndex); } } /// /// Fill the details pannel with the details of the currently selected soldier /// private void PopulateSoldierDetailPanel() { if (null == SelectedSoldier) { nameEditBox.Text = String.Empty; } else { nameEditBox.Text = SelectedSoldier.Name; } PopulateAttributes(); } /// /// Populate the attributes Grid with the currently selected soldier's attributes /// private void PopulateAttributes() { Person person = SelectedSoldier; if ((null != person) && (null != attributesGrid)) { attributesGrid.ResetList(); // Psi Training if (Xenocide.GameState.GeoData.XCorp.TechManager.IsAvailable("FAC_PSIONIC_TRAINING_FACILITY")) { String training = Strings.SCREEN_SOLDIERS_LIST_NOT_PSI_TRAINING; if (person.PsiTraining) { training = Strings.SCREEN_SOLDIERS_LIST_IN_PSI_TRAINING; } AddAttributeRow(Strings.SCREEN_SOLDIERS_LIST_ROW_PSI_TRAINING, training); } // Craft Aircraft aircraft = person.Aircraft; string aircraftName = (null != aircraft) ? aircraft.Name : String.Empty; AddAttributeRow(Strings.SCREEN_SOLDIERS_LIST_ROW_AIRCRAFT, aircraftName); // Armor // nasty way of doing this, but I think it's the only place where we need it. Item armor = person.Combatant.Inventory.ItemAt(4, 3); string armorName = (null != armor) ? armor.Name : Strings.ARMOR_TYPE_NONE; AddAttributeRow(Strings.SCREEN_SOLDIERS_LIST_ROW_ARMOR, armorName); // Stats for (Statistic s = Statistic.TimeUnits; s <= Statistic.DaysHired; ++s) { AddStatistic(person.Combatant, s); } AddAttributeRow("In Psi Training", person.PsiTraining.ToString()); // Others ToDo AddAttributeRow("ToDo", "ToDo"); } } /// Add a soldier's statistic to the list of stats shown screen /// soldier who has statistic /// Statistic to show [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification = "Not possible to reduce")] private void AddStatistic(Combatant combatant, Statistic s) { string rowName; string rowValue; switch (s) { // these are not shown case Statistic.EnergyRecharge: case Statistic.VictoryPoints: case Statistic.Aggression: case Statistic.Melee: case Statistic.Intelligence: case Statistic.StandingHeight: case Statistic.KneelingHeight: case Statistic.FloatingHeight: case Statistic.MotionScannerBlipSize: case Statistic.TimeUnitsLeft: case Statistic.StunDamage: // ToDo: not shown at moment, should be moved out of stats into a FatalWounds class // Note, they're only relevant on the battlescape case Statistic.FatalWoundsHead: case Statistic.FatalWoundsBody: case Statistic.FatalWoundsLeftArm: case Statistic.FatalWoundsRightArm: case Statistic.FatalWoundsLeftLeg: case Statistic.FatalWoundsRightLeg: case Statistic.StaminaLeft: return; // these have simple hanlding (just show the number) case Statistic.InjuryDamage: case Statistic.Kills: case Statistic.Missions: rowName = StaticticNames.DisplayString(s); rowValue = Util.ToString(combatant.Stats[s]); break; // ToDo: these will show starting and current value case Statistic.TimeUnits: case Statistic.Stamina: case Statistic.Health: case Statistic.Bravery: case Statistic.Reactions: case Statistic.FiringAccuracy: case Statistic.ThrowingAccuracy: case Statistic.Strength: case Statistic.PsiStrength: case Statistic.PsiSkill: rowName = StaticticNames.DisplayString(s); rowValue = Util.ToString(combatant.Stats[s]); break; // special cases case Statistic.DaysHired: rowName = StaticticNames.DisplayString(s); rowValue = Util.ToString(combatant.Stats.DaysHired()); break; default: // should never get here Debug.Assert(false); return; } Debug.Assert(null != rowName); AddAttributeRow(rowName, rowValue); } /// /// Add a row to the attributes grid /// /// text to put in the attributes column /// text to put in the value column private void AddAttributeRow(string attribute, string value) { ListboxItem listboxItem = Util.CreateListboxItem(attribute); int row = attributesGrid.AddRow(listboxItem, 0); listboxItem.ID = row; Util.AddStringElementToGrid(attributesGrid, 1, row, value); } /// /// Adds buttons to the right hand panel of the screen. /// private void CreateRightHandButtons() { // Psi Training is only available if base has working facility if (SelectedOutpost.Floorplan.HasWorkingFacility("FAC_PSIONIC_TRAINING_FACILITY")) { psiTrainButton = AddButton("BUTTON_PSI_TRAIN", 0.7475f, 0.80f, 0.2275f, 0.04125f); psiTrainButton.Clicked += new CeGui.GuiEventHandler(OnPsiTraining); } craftButton = AddButton("BUTTON_ASSIGN_TO_CRAFT", 0.7475f, 0.85f, 0.2275f, 0.04125f); equipButton = AddButton("BUTTON_EQUIP_SOLDIER", 0.7475f, 0.90f, 0.2275f, 0.04125f); closeButton = AddButton("BUTTON_CLOSE", 0.7475f, 0.95f, 0.2275f, 0.04125f); craftButton.Clicked += new CeGui.GuiEventHandler(ShowAssignScreen); equipButton.Clicked += new CeGui.GuiEventHandler(OnEquipButton); closeButton.Clicked += new CeGui.GuiEventHandler(ShowBasesScreen); } private CeGui.Widgets.EditBox nameEditBox; private CeGui.Widgets.Listbox soldiersListGrid; private CeGui.Widgets.MultiColumnList attributesGrid; private CeGui.Widgets.PushButton craftButton; private CeGui.Widgets.PushButton equipButton; private CeGui.Widgets.PushButton psiTrainButton; private CeGui.Widgets.PushButton closeButton; #endregion #region Event Handlers /// /// Event handler called when the name edit box value is changed. /// /// not used /// not used private void OnSoldierNameChanged(object sender, CeGui.GuiEventArgs e) { if (null != SelectedSoldier) { SelectedSoldier.Rename(nameEditBox.Text); RefreshSoldiersGrid(); } } /// /// Called when a soldier is clicked in the list. Displays appropriate values in the /// soldier detail section. /// /// If the listbox is clicked on a row that doesn't contain a soldier, then SelectedSoldier /// will be null. /// /// not used /// not used private void OnSelectedSoldierChanged(object sender, CeGui.GuiEventArgs e) { PopulateSoldierDetailPanel(); } /// React to user pressing the Equip button /// Not used /// Not used private void OnEquipButton(object sender, CeGui.GuiEventArgs e) { ShowEquipSoldiersScreen(); } /// Replace this screen with matching BasesScreen /// Not used /// Not used private void ShowBasesScreen(object sender, CeGui.GuiEventArgs e) { ScreenManager.ScheduleScreen(new BasesScreen(selectedOutpostIndex)); } /// Replace this screen with matching Assign to craft screen /// Not used /// Not used private void ShowAssignScreen(object sender, CeGui.GuiEventArgs e) { ScreenManager.ScheduleScreen(new AssignToCraftScreen(selectedOutpostIndex)); } /// User has clicked on "Psi Training" button /// not used /// not used private void OnPsiTraining(object sender, CeGui.GuiEventArgs e) { TogglePsiTraining(); } #endregion private void TogglePsiTraining() { // if no soldier seleted, nothing to do Person person = SelectedSoldier; if (null != person) { if (!person.PsiTraining) { // Can only start training if it's the first of the month // and base has free psi training pods if (Xenocide.GameState.GeoData.GeoTime.Time.Day != 1) { Util.ShowMessageBox(Strings.MSGBOX_TOO_LATE_FOR_PSI_TRAINING); } else if (0 == SelectedOutpost.Statistics.Capacities["STORAGE_PSI_TRAINING"].Available) { Util.ShowMessageBox(Strings.MSGBOX_NO_PSI_TRAINING_SPACE); } else { person.PsiTraining = true; } } else { // ToDo: ask user to confirm cancel training YesNoDialog dlg = YesNoDialog.OkCancelDialog( Util.StringFormat(Strings.YESNOMSG_CANCEL_PSI_TRAINING, person.Name) ); dlg.YesAction += delegate() { person.PsiTraining = false; // ToDo: Remove after showing "In Psi Training" in list hack is removed PopulateAttributes(); }; Xenocide.ScreenManager.ShowDialog(dlg); } PopulateAttributes(); } } /// /// Show screen that allows player to equip the selected soldier /// private void ShowEquipSoldiersScreen() { if (null != SelectedSoldier) { ScreenManager.ScheduleScreen(new EquipSoldierScreen(soldiers, SelectedSoldier)); } } #region Fields /// /// Returns the domain object for the soldier currently selected in the list. /// private Person SelectedSoldier { get { ListboxItem selection = soldiersListGrid.GetFirstSelectedItem(); return (null == selection) ? null : soldiers[selection.ID]; } } /// /// The soldiers listed on this screen. /// private readonly List soldiers; /// /// The outpost this screen deals with. /// private readonly int selectedOutpostIndex; /// /// The outpost we're showing the details for /// private Outpost SelectedOutpost { get { return Xenocide.GameState.GeoData.Outposts[selectedOutpostIndex]; } } #endregion } }