Create math.uc

Create math.uc

Converts math functions and operators

# math.uc - uCalc Transformation file
# This file was saved with uCalc Transform 2.5 on 1/16/2014 12:34:12 PM
# Comment: Converts math-related code from PowerBASIC to C++

ExternalKeywords: Exclude, Comment, Selected, ParentChild, FindMode, OutputFile, BatchAction, SEND
ExternalKeywords: Highlight, ForeColor, BackColor, FontName, FontSize, FontStyle
ExternalKeywords: FilterEndText, FilterSeparator, FilterSort, FilterSortFunc, FilterStartText, FilterUnique

FindMode: Replace

# Definitions

# Search Criteria

Criteria: 0
Enabled: False
Exclude: False
Comment: Converts math-related code from PowerBASIC to C++
Selected: False
Highlight: True
ForeColor: ControlText
BackColor: Aqua
FontName:
FontSize:
FontStyle:
CaseSensitive: False
QuoteSensitive: True
CodeBlockSensitive: True
FilterEndText:
FilterSeparator: {#10}
FilterSort: False
FilterSortFunc:
FilterStartText:
FilterUnique: False
Min: 0
Max: -1
MinSoft: 0
MaxSoft: -1
BatchAction: Transform
OutputFile:
SEND:
StartAfter: 0
StopAfter: -1
SkipOver: False
ParentChild: 0
Pass: 0
PassOnce: True
Precedence: 0
RightToLeft: False

Criteria: 1
Enabled: True
Find: {@Start}
      {@Note:
         Note that this conversion comes AFTER pb-to-cpp.uc
         ToDo: ^ \ exp10 frac sgn shift
               eqv imp bin hex oct
               and fix LCase for next version
      }
Replace: #include <math.h>{nl}

Criteria: 2
Enabled: True
Selected: True
SkipOver: True
Find: // {Comment:".*"}
Replace: [Skip over]

Criteria: 3
Enabled: False
Find: {func: Abs|Sin|Cos|Tan|Exp|Exp2|Log|Log2|Log10|Ceil}
Replace: {@Evaluate: LCase({func})}

Criteria: 4
Enabled: True
Find: Mod
Replace: %

Criteria: 5
Enabled: True
BackColor: Yellow
Find: Atn
Replace: atan

Criteria: 6
Enabled: True
BackColor: Lime
Find: Sqr
Replace: sqrt

Criteria: 7
Enabled: True
BackColor: Brown
Find: Fix
Replace: trunc

Criteria: 8
Enabled: True
BackColor: Pink
Find: Cint
Replace: lround

Criteria: 9
Enabled: True
BackColor: Red
Find: Incr {var} ;
Replace: {var}++;

Criteria: 10
Enabled: True
BackColor: RoyalBlue
Find: Decr {var} ;
Replace: {var}--;

# End Search

error: pathspec 'convert/math.uc' did not match any file(s) known to git


Fix duplicate psi ability training choices (#924)

A bug in `UIChoosePsiAbility.GetAbilities()` meant that under certain
circumstances, the screen could display the same ability twice, giving
the player only one other option to train.

The problem was that the local `AbilityName` variable was being
overridden by a new ability name before the code decided whether that
override would be displayed as a choice or not. This fix simply stores
each prerequisite ability name in a separate variable and only overrides
`AbilityName` if that prerequisite is actually replacing the original
ability as a choice.

Fixes #924.

//----------------------------------------------------------------------------
//  *********   FIRAXIS SOURCE CODE   ******************
//  FILE:    UIChoosePsiAbility.uc
//  AUTHOR:  Joe Weinhoffer
//  PURPOSE: Screen that allows the player to select the next Psi Ability they wish to train.
//----------------------------------------------------------------------------
//  Copyright (c) 2016 Firaxis Games, Inc. All rights reserved.
//----------------------------------------------------------------------------

class UIChoosePsiAbility extends UISimpleCommodityScreen;

var array<SoldierAbilityInfo> m_arrAbilities;

var int AbilitiesPerBranch;
var int MaxAbilitiesDisplayed;

var StateObjectReference m_UnitRef; // set in XComHQPresentationLayer
var StateObjectReference m_StaffSlotRef; // set in XComHQPresentationLayer

var public localized String m_strPaused;
var public localized String m_strResume;

//-------------- EVENT HANDLING --------------------------------------------------------
simulated function OnPurchaseClicked(UIList kList, int itemIndex)
{
	if (itemIndex != iSelectedItem)
	{
		iSelectedItem = itemIndex;
	}

	if (CanAffordItem(iSelectedItem))
	{
		if (OnAbilitySelected(iSelectedItem))
			Movie.Stack.Pop(self);
		//UpdateData();
	}
	else
	{
		PlayNegativeSound(); // bsg-jrebar (4/20/17): New PlayNegativeSound Function in Parent Class
	}
}

simulated function InitScreen(XComPlayerController InitController, UIMovie InitMovie, optional name InitName)
{
	super.InitScreen(InitController, InitMovie, InitName);

	ItemCard.Hide();
	Navigator.SetSelected(List);
	List.SetSelectedIndex(0);
}

simulated function PopulateData()
{
	local Commodity Template;
	local int i;

	List.ClearItems();
	List.bSelectFirstAvailable = false;

	for (i = 0; i < arrItems.Length; i++)
	{
		Template = arrItems[i];
		if (i < m_arrRefs.Length)
		{
			Spawn(class'UIInventory_ClassListItem', List.itemContainer).InitInventoryListCommodity(Template, m_arrRefs[i], GetButtonString(i), m_eStyle, , 125, true);
		}
		else
		{
			Spawn(class'UIInventory_ClassListItem', List.itemContainer).InitInventoryListCommodity(Template, , GetButtonString(i), m_eStyle, , 125, true);
		}
	}
}

simulated function PopulateResearchCard(optional Commodity ItemCommodity, optional StateObjectReference ItemRef)
{
}

//-------------- GAME DATA HOOKUP --------------------------------------------------------
simulated function GetItems()
{
	arrItems = ConvertAbilitiesToCommodities();
}

simulated function array<Commodity> ConvertAbilitiesToCommodities()
{
	local X2AbilityTemplate AbilityTemplate;
	local int iAbility;
	local array<Commodity> arrCommodoties;
	local Commodity AbilityComm;
	local bool bPausedProject;

	m_arrAbilities.Remove(0, m_arrAbilities.Length);
	m_arrAbilities = GetAbilities();
	m_arrAbilities.Sort(SortAbilitiesByRank);

	for (iAbility = 0; iAbility < m_arrAbilities.Length; iAbility++)
	{
		AbilityTemplate = m_arrAbilities[iAbility].AbilityTemplate;

		if (AbilityTemplate != none)
		{
			bPausedProject = XComHQ.HasPausedPsiAbilityTrainingProject(m_UnitRef, m_arrAbilities[iAbility]);

			AbilityComm.Title = AbilityTemplate.LocFriendlyName;
			if (bPausedProject)
			{
				AbilityComm.Title = AbilityComm.Title @ m_strPaused;
			}
			AbilityComm.Image = AbilityTemplate.IconImage;
			AbilityComm.Desc = AbilityTemplate.GetMyLongDescription(, XComGameState_Unit(`XCOMHISTORY.GetGameStateForObjectID(m_UnitRef.ObjectID)));
			AbilityComm.OrderHours = GetAbilityOrderDays(iAbility);

			arrCommodoties.AddItem(AbilityComm);
		}
	}

	return arrCommodoties;
}

simulated function int GetAbilityOrderDays(int iAbility)
{
	local XComGameState_HeadquartersProjectPsiTraining PsiProject;
	local XComGameState_Unit Unit;
	local int RankDifference;
	local int TrainingRateModifier;

	PsiProject = XComHQ.GetPausedPsiAbilityTrainingProject(m_UnitRef, m_arrAbilities[iAbility]);

	if (PsiProject != None)
	{
		return PsiProject.GetProjectedNumHoursRemaining();
	}
	else
	{
		Unit = XComGameState_Unit(`XCOMHISTORY.GetGameStateForObjectID(m_UnitRef.ObjectID));
		RankDifference = Max(m_arrAbilities[iAbility].iRank - Unit.GetRank(), 0);
		TrainingRateModifier = XComHQ.PsiTrainingRate / XComHQ.XComHeadquarters_DefaultPsiTrainingWorkPerHour;
		return (XComHQ.GetPsiTrainingDays() + Round(XComHQ.GetPsiTrainingScalar() * float(RankDifference))) * (24 / TrainingRateModifier);
	}
}

simulated function String GetButtonString(int ItemIndex)
{
	if (XComHQ.HasPausedPsiAbilityTrainingProject(m_UnitRef, m_arrAbilities[ItemIndex]))
	{
		return m_strResume;
	}
	else
	{
		return m_strBuy;
	}
}

//-----------------------------------------------------------------------------

//This is overwritten in the research archives.
simulated function array<SoldierAbilityInfo> GetAbilities()
{
	local X2AbilityTemplate AbilityTemplate;
	local SCATProgression ProgressAbility;
	local array<SoldierAbilityInfo> SoldierAbilities;
	local SoldierAbilityInfo SoldierAbility;
	local XComGameState_Unit Unit;
	local XComGameState_HeadquartersProjectPsiTraining AbilityProject;
	local array<name> AddedAbilityNames;
	local name AbilityName;
	local int iName;
	local bool bAddAbility;
	local name PreReqAbilityName;  // Issue #924

	Unit = XComGameState_Unit(`XCOMHISTORY.GetGameStateForObjectID(m_UnitRef.ObjectID));

	// First check to see if the PsiOp has a paused ability training project
	AbilityProject = XComHQ.GetPsiTrainingProject(m_UnitRef);
	if (AbilityProject != none && AbilityProject.bForcePaused)
	{
		// Only add the paused ability to the list as a choice to resume
		AbilityName = Unit.GetAbilityName(AbilityProject.iAbilityRank, AbilityProject.iAbilityBranch);
		AbilityTemplate = class'X2AbilityTemplateManager'.static.GetAbilityTemplateManager().FindAbilityTemplate(AbilityName);

		SoldierAbility.AbilityTemplate = AbilityTemplate;
		SoldierAbility.iRank = AbilityProject.iAbilityRank;
		SoldierAbility.iBranch = AbilityProject.iAbilityBranch;

		SoldierAbilities.AddItem(SoldierAbility);
		AddedAbilityNames.AddItem(AbilityName);
	}
	else
	{
		// Otherwise generate a list of ability choices
		foreach Unit.PsiAbilities(ProgressAbility)
		{
			if (SoldierAbilities.Length >= MaxAbilitiesDisplayed)
				break;

			bAddAbility = false;
			AbilityName = Unit.GetAbilityName(ProgressAbility.iRank, ProgressAbility.iBranch);
			if (AbilityName != '' && !Unit.HasSoldierAbility(AbilityName) && AddedAbilityNames.Find(AbilityName) == INDEX_NONE)
			{
				AbilityTemplate = class'X2AbilityTemplateManager'.static.GetAbilityTemplateManager().FindAbilityTemplate(AbilityName);
				if (AbilityTemplate != none)
				{
					bAddAbility = true;

					// Check to make sure that soldier has any prereq abilites required, and if not then add the prereq ability instead
					if (AbilityTemplate.PrerequisiteAbilities.Length > 0)
					{
						for (iName = 0; iName < AbilityTemplate.PrerequisiteAbilities.Length; iName++)
						{
							// Start Issue #924
							/// HL-Docs: ref:Bugfixes; issue:924
							/// Prevent the psi ability training screen from showing duplicate abilities
							PreReqAbilityName = AbilityTemplate.PrerequisiteAbilities[iName];
							if (!Unit.HasSoldierAbility(PreReqAbilityName)) // if the soldier does not have the prereq ability, replace it
							{
								AbilityName = PreReqAbilityName;
								// End Issue #924
								AbilityTemplate = class'X2AbilityTemplateManager'.static.GetAbilityTemplateManager().FindAbilityTemplate(AbilityName);
								ProgressAbility = Unit.GetSCATProgressionForAbility(AbilityName);

								if (AddedAbilityNames.Find(AbilityName) != INDEX_NONE)
								{
									// If the prereq ability was already added to the list, don't add it again
									bAddAbility = false;
								}

								break;
							}
						}
					}
				}

				if (bAddAbility)
				{
					SoldierAbility.AbilityTemplate = AbilityTemplate;
					SoldierAbility.iRank = ProgressAbility.iRank;
					SoldierAbility.iBranch = ProgressAbility.iBranch;

					SoldierAbilities.AddItem(SoldierAbility);
					AddedAbilityNames.AddItem(AbilityName);
				}
			}
		}
	}

	return SoldierAbilities;
}

function int SortAbilitiesByRank(SoldierAbilityInfo AbilityA, SoldierAbilityInfo AbilityB)
{
	if (AbilityA.iRank < AbilityB.iRank)
	{
		return 1;
	}
	else if (AbilityA.iRank > AbilityB.iBranch)
	{
		return -1;
	}
	else
	{
		return 0;
	}
}

function bool OnAbilitySelected(int iOption)
{
	local XComGameState NewGameState;
	local XComGameState_StaffSlot StaffSlotState;
	local XComGameState_FacilityXCom FacilityState;
	local XComGameState_HeadquartersProjectPsiTraining TrainPsiOpProject;
	local StaffUnitInfo UnitInfo;

	StaffSlotState = XComGameState_StaffSlot(History.GetGameStateForObjectID(m_StaffSlotRef.ObjectID));

	if (StaffSlotState != none)
	{
		UnitInfo.UnitRef = m_UnitRef;
		StaffSlotState.FillSlot(UnitInfo);

		// If a paused project already exists for this ability, resume it
		NewGameState = class'XComGameStateContext_ChangeContainer'.static.CreateChangeState("Staffing Train Psi Operative Slot");
		TrainPsiOpProject = XComHQ.GetPausedPsiAbilityTrainingProject(m_UnitRef, m_arrAbilities[iOption]);
		if (TrainPsiOpProject != None)
		{
			TrainPsiOpProject = XComGameState_HeadquartersProjectPsiTraining(NewGameState.ModifyStateObject(TrainPsiOpProject.Class, TrainPsiOpProject.ObjectID));
			TrainPsiOpProject.bForcePaused = false;
		}
		else
		{
			// Otherwise start a new psi ability training project
			TrainPsiOpProject = XComGameState_HeadquartersProjectPsiTraining(NewGameState.CreateNewStateObject(class'XComGameState_HeadquartersProjectPsiTraining'));
			TrainPsiOpProject.iAbilityRank = m_arrAbilities[iOption].iRank; // These need to be set first so project PointsToComplete can be calculated correctly
			TrainPsiOpProject.iAbilityBranch = m_arrAbilities[iOption].iBranch;
			TrainPsiOpProject.SetProjectFocus(UnitInfo.UnitRef, NewGameState, StaffSlotState.Facility);

			XComHQ = XComGameState_HeadquartersXCom(NewGameState.ModifyStateObject(class'XComGameState_HeadquartersXCom', XComHQ.ObjectID));
			XComHQ.Projects.AddItem(TrainPsiOpProject.GetReference());
		}

		`XCOMGAME.GameRuleset.SubmitGameState(NewGameState);

		`XSTRATEGYSOUNDMGR.PlaySoundEvent("StrategyUI_Staff_Assign");

		FacilityState = XComHQ.GetFacilityByName('PsiChamber');
		if (FacilityState.GetNumEmptyStaffSlots() > 0)
		{
			StaffSlotState = FacilityState.GetStaffSlot(FacilityState.GetEmptyStaffSlotIndex());

			if ((StaffSlotState.IsScientistSlot() && XComHQ.GetNumberOfUnstaffedScientists() > 0) ||
				(StaffSlotState.IsEngineerSlot() && XComHQ.GetNumberOfUnstaffedEngineers() > 0))
			{
				`HQPRES.UIStaffSlotOpen(FacilityState.GetReference(), StaffSlotState.GetMyTemplate());
			}
		}

		XComHQ.HandlePowerOrStaffingChange();

		RefreshFacility();
	}

	return true;
}

simulated function RefreshFacility()
{
	local UIScreen QueueScreen;

	QueueScreen = Movie.Stack.GetScreen(class'UIFacility_PsiLab');
	if (QueueScreen != None)
		UIFacility_PsiLab(QueueScreen).RealizeFacility();
}

//----------------------------------------------------------------
simulated function OnCancelButton(UIButton kButton) { OnCancel(); }
simulated function OnCancel()
{
	CloseScreen();
}

//==============================================================================

simulated function OnLoseFocus()
{
	super.OnLoseFocus();
	`HQPRES.m_kAvengerHUD.NavHelp.ClearButtonHelp();
}

defaultproperties
{
	InputState = eInputState_Consume;

	bHideOnLoseFocus = true;
	bSelectFirstAvailable = false;
	//bConsumeMouseEvents = true;

	DisplayTag = "UIDisplay_Academy"
	CameraTag = "UIDisplay_Academy"

	AbilitiesPerBranch=2
	MaxAbilitiesDisplayed=3
}

//----------------------------------------------------------------------------
//  *********   FIRAXIS SOURCE CODE   ******************
//  FILE:    UIChoosePsiAbility.uc
//  AUTHOR:  Joe Weinhoffer
//  PURPOSE: Screen that allows the player to select the next Psi Ability they wish to train.
//----------------------------------------------------------------------------
//  Copyright (c) 2016 Firaxis Games, Inc. All rights reserved.
//----------------------------------------------------------------------------

class UIChoosePsiAbility extends UISimpleCommodityScreen;

var array<SoldierAbilityInfo> m_arrAbilities;

var int AbilitiesPerBranch;
var int MaxAbilitiesDisplayed;

var StateObjectReference m_UnitRef; // set in XComHQPresentationLayer
var StateObjectReference m_StaffSlotRef; // set in XComHQPresentationLayer

var public localized String m_strPaused;
var public localized String m_strResume;

//-------------- EVENT HANDLING --------------------------------------------------------
simulated function OnPurchaseClicked(UIList kList, int itemIndex)
{
	if (itemIndex != iSelectedItem)
	{
		iSelectedItem = itemIndex;
	}

	if (CanAffordItem(iSelectedItem))
	{
		if (OnAbilitySelected(iSelectedItem))
			Movie.Stack.Pop(self);
		//UpdateData();
	}
	else
	{
		PlayNegativeSound(); // bsg-jrebar (4/20/17): New PlayNegativeSound Function in Parent Class
	}
}

simulated function InitScreen(XComPlayerController InitController, UIMovie InitMovie, optional name InitName)
{
	super.InitScreen(InitController, InitMovie, InitName);

	ItemCard.Hide();
	Navigator.SetSelected(List);
	List.SetSelectedIndex(0);
}

simulated function PopulateData()
{
	local Commodity Template;
	local int i;

	List.ClearItems();
	List.bSelectFirstAvailable = false;

	for (i = 0; i < arrItems.Length; i++)
	{
		Template = arrItems[i];
		if (i < m_arrRefs.Length)
		{
			Spawn(class'UIInventory_ClassListItem', List.itemContainer).InitInventoryListCommodity(Template, m_arrRefs[i], GetButtonString(i), m_eStyle, , 125, true);
		}
		else
		{
			Spawn(class'UIInventory_ClassListItem', List.itemContainer).InitInventoryListCommodity(Template, , GetButtonString(i), m_eStyle, , 125, true);
		}
	}
}

simulated function PopulateResearchCard(optional Commodity ItemCommodity, optional StateObjectReference ItemRef)
{
}

//-------------- GAME DATA HOOKUP --------------------------------------------------------
simulated function GetItems()
{
	arrItems = ConvertAbilitiesToCommodities();
}

simulated function array<Commodity> ConvertAbilitiesToCommodities()
{
	local X2AbilityTemplate AbilityTemplate;
	local int iAbility;
	local array<Commodity> arrCommodoties;
	local Commodity AbilityComm;
	local bool bPausedProject;

	m_arrAbilities.Remove(0, m_arrAbilities.Length);
	m_arrAbilities = GetAbilities();
	m_arrAbilities.Sort(SortAbilitiesByRank);

	for (iAbility = 0; iAbility < m_arrAbilities.Length; iAbility++)
	{
		AbilityTemplate = m_arrAbilities[iAbility].AbilityTemplate;

		if (AbilityTemplate != none)
		{
			bPausedProject = XComHQ.HasPausedPsiAbilityTrainingProject(m_UnitRef, m_arrAbilities[iAbility]);

			AbilityComm.Title = AbilityTemplate.LocFriendlyName;
			if (bPausedProject)
			{
				AbilityComm.Title = AbilityComm.Title @ m_strPaused;
			}
			AbilityComm.Image = AbilityTemplate.IconImage;
			AbilityComm.Desc = AbilityTemplate.GetMyLongDescription(, XComGameState_Unit(`XCOMHISTORY.GetGameStateForObjectID(m_UnitRef.ObjectID)));
			AbilityComm.OrderHours = GetAbilityOrderDays(iAbility);

			arrCommodoties.AddItem(AbilityComm);
		}
	}

	return arrCommodoties;
}

simulated function int GetAbilityOrderDays(int iAbility)
{
	local XComGameState_HeadquartersProjectPsiTraining PsiProject;
	local XComGameState_Unit Unit;
	local int RankDifference;
	local int TrainingRateModifier;

	PsiProject = XComHQ.GetPausedPsiAbilityTrainingProject(m_UnitRef, m_arrAbilities[iAbility]);

	if (PsiProject != None)
	{
		return PsiProject.GetProjectedNumHoursRemaining();
	}
	else
	{
		Unit = XComGameState_Unit(`XCOMHISTORY.GetGameStateForObjectID(m_UnitRef.ObjectID));
		RankDifference = Max(m_arrAbilities[iAbility].iRank - Unit.GetRank(), 0);
		TrainingRateModifier = XComHQ.PsiTrainingRate / XComHQ.XComHeadquarters_DefaultPsiTrainingWorkPerHour;
		return (XComHQ.GetPsiTrainingDays() + Round(XComHQ.GetPsiTrainingScalar() * float(RankDifference))) * (24 / TrainingRateModifier);
	}
}

simulated function String GetButtonString(int ItemIndex)
{
	if (XComHQ.HasPausedPsiAbilityTrainingProject(m_UnitRef, m_arrAbilities[ItemIndex]))
	{
		return m_strResume;
	}
	else
	{
		return m_strBuy;
	}
}

//-----------------------------------------------------------------------------

//This is overwritten in the research archives.
simulated function array<SoldierAbilityInfo> GetAbilities()
{
	local X2AbilityTemplate AbilityTemplate;
	local SCATProgression ProgressAbility;
	local array<SoldierAbilityInfo> SoldierAbilities;
	local SoldierAbilityInfo SoldierAbility;
	local XComGameState_Unit Unit;
	local XComGameState_HeadquartersProjectPsiTraining AbilityProject;
	local array<name> AddedAbilityNames;
	local name AbilityName;
	local int iName;
	local bool bAddAbility;

	Unit = XComGameState_Unit(`XCOMHISTORY.GetGameStateForObjectID(m_UnitRef.ObjectID));

	// First check to see if the PsiOp has a paused ability training project
	AbilityProject = XComHQ.GetPsiTrainingProject(m_UnitRef);
	if (AbilityProject != none && AbilityProject.bForcePaused)
	{
		// Only add the paused ability to the list as a choice to resume
		AbilityName = Unit.GetAbilityName(AbilityProject.iAbilityRank, AbilityProject.iAbilityBranch);
		AbilityTemplate = class'X2AbilityTemplateManager'.static.GetAbilityTemplateManager().FindAbilityTemplate(AbilityName);

		SoldierAbility.AbilityTemplate = AbilityTemplate;
		SoldierAbility.iRank = AbilityProject.iAbilityRank;
		SoldierAbility.iBranch = AbilityProject.iAbilityBranch;

		SoldierAbilities.AddItem(SoldierAbility);
		AddedAbilityNames.AddItem(AbilityName);
	}
	else
	{
		// Otherwise generate a list of ability choices
		foreach Unit.PsiAbilities(ProgressAbility)
		{
			if (SoldierAbilities.Length >= MaxAbilitiesDisplayed)
				break;

			bAddAbility = false;
			AbilityName = Unit.GetAbilityName(ProgressAbility.iRank, ProgressAbility.iBranch);
			if (AbilityName != '' && !Unit.HasSoldierAbility(AbilityName) && AddedAbilityNames.Find(AbilityName) == INDEX_NONE)
			{
				AbilityTemplate = class'X2AbilityTemplateManager'.static.GetAbilityTemplateManager().FindAbilityTemplate(AbilityName);
				if (AbilityTemplate != none)
				{
					bAddAbility = true;

					// Check to make sure that soldier has any prereq abilites required, and if not then add the prereq ability instead
					if (AbilityTemplate.PrerequisiteAbilities.Length > 0)
					{
						for (iName = 0; iName < AbilityTemplate.PrerequisiteAbilities.Length; iName++)
						{
							AbilityName = AbilityTemplate.PrerequisiteAbilities[iName];
							if (!Unit.HasSoldierAbility(AbilityName)) // if the soldier does not have the prereq ability, replace it
							{
								AbilityTemplate = class'X2AbilityTemplateManager'.static.GetAbilityTemplateManager().FindAbilityTemplate(AbilityName);
								ProgressAbility = Unit.GetSCATProgressionForAbility(AbilityName);

								if (AddedAbilityNames.Find(AbilityName) != INDEX_NONE)
								{
									// If the prereq ability was already added to the list, don't add it again
									bAddAbility = false;
								}

								break;
							}
						}
					}
				}

				if (bAddAbility)
				{
					SoldierAbility.AbilityTemplate = AbilityTemplate;
					SoldierAbility.iRank = ProgressAbility.iRank;
					SoldierAbility.iBranch = ProgressAbility.iBranch;

					SoldierAbilities.AddItem(SoldierAbility);
					AddedAbilityNames.AddItem(AbilityName);
				}
			}
		}
	}

	return SoldierAbilities;
}

function int SortAbilitiesByRank(SoldierAbilityInfo AbilityA, SoldierAbilityInfo AbilityB)
{
	if (AbilityA.iRank < AbilityB.iRank)
	{
		return 1;
	}
	else if (AbilityA.iRank > AbilityB.iBranch)
	{
		return -1;
	}
	else
	{
		return 0;
	}
}

function bool OnAbilitySelected(int iOption)
{
	local XComGameState NewGameState;
	local XComGameState_StaffSlot StaffSlotState;
	local XComGameState_FacilityXCom FacilityState;
	local XComGameState_HeadquartersProjectPsiTraining TrainPsiOpProject;
	local StaffUnitInfo UnitInfo;

	StaffSlotState = XComGameState_StaffSlot(History.GetGameStateForObjectID(m_StaffSlotRef.ObjectID));

	if (StaffSlotState != none)
	{
		UnitInfo.UnitRef = m_UnitRef;
		StaffSlotState.FillSlot(UnitInfo);

		// If a paused project already exists for this ability, resume it
		NewGameState = class'XComGameStateContext_ChangeContainer'.static.CreateChangeState("Staffing Train Psi Operative Slot");
		TrainPsiOpProject = XComHQ.GetPausedPsiAbilityTrainingProject(m_UnitRef, m_arrAbilities[iOption]);
		if (TrainPsiOpProject != None)
		{
			TrainPsiOpProject = XComGameState_HeadquartersProjectPsiTraining(NewGameState.ModifyStateObject(TrainPsiOpProject.Class, TrainPsiOpProject.ObjectID));
			TrainPsiOpProject.bForcePaused = false;
		}
		else
		{
			// Otherwise start a new psi ability training project
			TrainPsiOpProject = XComGameState_HeadquartersProjectPsiTraining(NewGameState.CreateNewStateObject(class'XComGameState_HeadquartersProjectPsiTraining'));
			TrainPsiOpProject.iAbilityRank = m_arrAbilities[iOption].iRank; // These need to be set first so project PointsToComplete can be calculated correctly
			TrainPsiOpProject.iAbilityBranch = m_arrAbilities[iOption].iBranch;
			TrainPsiOpProject.SetProjectFocus(UnitInfo.UnitRef, NewGameState, StaffSlotState.Facility);

			XComHQ = XComGameState_HeadquartersXCom(NewGameState.ModifyStateObject(class'XComGameState_HeadquartersXCom', XComHQ.ObjectID));
			XComHQ.Projects.AddItem(TrainPsiOpProject.GetReference());
		}

		`XCOMGAME.GameRuleset.SubmitGameState(NewGameState);

		`XSTRATEGYSOUNDMGR.PlaySoundEvent("StrategyUI_Staff_Assign");

		FacilityState = XComHQ.GetFacilityByName('PsiChamber');
		if (FacilityState.GetNumEmptyStaffSlots() > 0)
		{
			StaffSlotState = FacilityState.GetStaffSlot(FacilityState.GetEmptyStaffSlotIndex());

			if ((StaffSlotState.IsScientistSlot() && XComHQ.GetNumberOfUnstaffedScientists() > 0) ||
				(StaffSlotState.IsEngineerSlot() && XComHQ.GetNumberOfUnstaffedEngineers() > 0))
			{
				`HQPRES.UIStaffSlotOpen(FacilityState.GetReference(), StaffSlotState.GetMyTemplate());
			}
		}

		XComHQ.HandlePowerOrStaffingChange();

		RefreshFacility();
	}

	return true;
}

simulated function RefreshFacility()
{
	local UIScreen QueueScreen;

	QueueScreen = Movie.Stack.GetScreen(class'UIFacility_PsiLab');
	if (QueueScreen != None)
		UIFacility_PsiLab(QueueScreen).RealizeFacility();
}

//----------------------------------------------------------------
simulated function OnCancelButton(UIButton kButton) { OnCancel(); }
simulated function OnCancel()
{
	CloseScreen();
}

//==============================================================================

simulated function OnLoseFocus()
{
	super.OnLoseFocus();
	`HQPRES.m_kAvengerHUD.NavHelp.ClearButtonHelp();
}

defaultproperties
{
	InputState = eInputState_Consume;

	bHideOnLoseFocus = true;
	bSelectFirstAvailable = false;
	//bConsumeMouseEvents = true;

	DisplayTag = "UIDisplay_Academy"
	CameraTag = "UIDisplay_Academy"

	AbilitiesPerBranch=2
	MaxAbilitiesDisplayed=3
}


Fixed compiler warning about conflict fields

class TestCWRMapProfile extends UTUIResourceDataProvider
	dependson(TestCWRTemplate)
	PerObjectConfig;

var config string ProfileName;
var config string FriendlyName;
var config string Description;

var config string FullMapName;
var config string MapName;

var config array<TemplateInfo> WeaponsToReplace;
var config array<TemplateInfo> AmmoToReplace;

//**********************************************************************************
// Static functions
//**********************************************************************************

static simulated function bool GetMapProfileByName(string InProfileName, out TestCWRMapProfile out_MapProvider)
{
	local array<TestCWRMapProfile> MapProviders;
	local TestCWRMapProfile MapProvider;

	if (GetMapProfiles(MapProviders))
	{
		foreach MapProviders(MapProvider)
		{
			if (string(MapProvider.Name) ~= InProfileName || MapProvider.ProfileName ~= InProfileName)
			{
				out_MapProvider = MapProvider;
				break;
			}
		}
	}

	return out_MapProvider != none;
}

static simulated function bool GetMapProfilesByFullMapName(string InFullMapName, out array<TestCWRMapProfile> out_MapProviders)
{
	local array<TestCWRMapProfile> MapProviders;
	local TestCWRMapProfile MapProvider;

	GetMapProfiles(MapProviders);

	out_MapProviders.Length = 0;
	foreach MapProviders(MapProvider)
	{
		if (MapProvider.FullMapName ~= InFullMapName)
		{
			out_MapProviders.AddItem(MapProvider);
		}
	}

	return out_MapProviders.Length > 0;
}

static simulated function bool GetMapProfilesByMapName(string InMapName, out array<TestCWRMapProfile> out_MapProviders)
{
	local array<TestCWRMapProfile> MapProviders;
	local TestCWRMapProfile MapProvider;

	GetMapProfiles(MapProviders);

	out_MapProviders.Length = 0;
	foreach MapProviders(MapProvider)
	{
		if (MapProvider.MapName ~= InMapName || MapProvider.FullMapName ~= InMapName)
		{
			out_MapProviders.AddItem(MapProvider);
		}
	}

	return out_MapProviders.Length > 0;
}

static simulated function bool GetMapProfiles(out array<TestCWRMapProfile> out_MapProviders)
{
	local array<UTUIResourceDataProvider> MapProviders;
	local UTUIResourceDataProvider MapProvider;
	class'UTUIDataStore_MenuItems'.static.GetAllResourceDataProviders(Class'TestCWRMapProfile', MapProviders);

	if (MapProviders.Length > 0)
	{
		out_MapProviders.Length = 0;
		foreach MapProviders(MapProvider)
		{
			if (TestCWRMapProfile(MapProvider) != none)
			{
				out_MapProviders.AddItem(TestCWRMapProfile(MapProvider));
			}
		}

		return out_MapProviders.Length > 0;;
	}

	return false;
}

defaultproperties
{
	bSearchAllInis=True

	WeaponsToReplace.Add((OldClassName="UTWeapon",NewClassPath="UTGame.UTWeap_SniperRifle",Options=(bSubClasses=true,bNoDefaultInventory=true,bAddToDefault=true)))
	AmmoToReplace.Add((OldClassName="UTAmmoPickupFactory",NewClassPath="UTGame.UTAmmo_SniperRifle",Options=(bSubClasses=true)))
}

class TestCWRMapProfile extends UTUIResourceDataProvider
	dependson(TestCWRTemplate)
	PerObjectConfig;

var config string ProfileName;
var config string FriendlyName;
var config string Description;

var config string FullMapName;
var config string MapName;

var config array<TemplateInfo> WeaponsToReplace;
var config array<TemplateInfo> AmmoToReplace;

//**********************************************************************************
// Static functions
//**********************************************************************************

static simulated function bool GetMapProfileByName(string ProfileName, out TestCWRMapProfile out_MapProvider)
{
	local array<TestCWRMapProfile> MapProviders;
	local TestCWRMapProfile MapProvider;

	if (GetMapProfiles(MapProviders))
	{
		foreach MapProviders(MapProvider)
		{
			if (string(MapProvider.Name) ~= ProfileName || MapProvider.ProfileName ~= ProfileName)
			{
				out_MapProvider = MapProvider;
				break;
			}
		}
	}

	return out_MapProvider != none;
}

static simulated function bool GetMapProfilesByFullMapName(string FullMapName, out array<TestCWRMapProfile> out_MapProviders)
{
	local array<TestCWRMapProfile> MapProviders;
	local TestCWRMapProfile MapProvider;

	GetMapProfiles(MapProviders);

	out_MapProviders.Length = 0;
	foreach MapProviders(MapProvider)
	{
		if (MapProvider.FullMapName ~= FullMapName)
		{
			out_MapProviders.AddItem(MapProvider);
		}
	}

	return out_MapProviders.Length > 0;
}

static simulated function bool GetMapProfilesByMapName(string MapName, out array<TestCWRMapProfile> out_MapProviders)
{
	local array<TestCWRMapProfile> MapProviders;
	local TestCWRMapProfile MapProvider;

	GetMapProfiles(MapProviders);

	out_MapProviders.Length = 0;
	foreach MapProviders(MapProvider)
	{
		if (MapProvider.MapName ~= MapName || MapProvider.FullMapName ~= MapName)
		{
			out_MapProviders.AddItem(MapProvider);
		}
	}

	return out_MapProviders.Length > 0;
}

static simulated function bool GetMapProfiles(out array<TestCWRMapProfile> out_MapProviders)
{
	local array<UTUIResourceDataProvider> MapProviders;
	local UTUIResourceDataProvider MapProvider;
	class'UTUIDataStore_MenuItems'.static.GetAllResourceDataProviders(Class'TestCWRMapProfile', MapProviders);

	if (MapProviders.Length > 0)
	{
		out_MapProviders.Length = 0;
		foreach MapProviders(MapProvider)
		{
			if (TestCWRMapProfile(MapProvider) != none)
			{
				out_MapProviders.AddItem(TestCWRMapProfile(MapProvider));
			}
		}

		return out_MapProviders.Length > 0;;
	}

	return false;
}

defaultproperties
{
	bSearchAllInis=True

	WeaponsToReplace.Add((OldClassName="UTWeapon",NewClassPath="UTGame.UTWeap_SniperRifle",Options=(bSubClasses=true,bNoDefaultInventory=true,bAddToDefault=true)))
	AmmoToReplace.Add((OldClassName="UTAmmoPickupFactory",NewClassPath="UTGame.UTAmmo_SniperRifle",Options=(bSubClasses=true)))
}