diff --git a/Assets/Scripts/Model/Upgrades/Elite/Daredevil.cs b/Assets/Scripts/Model/Upgrades/Elite/Daredevil.cs index b73249012b..e4b5b1f511 100644 --- a/Assets/Scripts/Model/Upgrades/Elite/Daredevil.cs +++ b/Assets/Scripts/Model/Upgrades/Elite/Daredevil.cs @@ -1,5 +1,12 @@ -using Upgrade; -using UnityEngine; +using Abilities; +using ActionsList; +using GameModes; +using Ship; +using SubPhases; +using System; +using System.Linq; +using Tokens; +using Upgrade; namespace UpgradesList { @@ -11,7 +18,236 @@ public Daredevil() : base() Name = "Daredevil"; Cost = 3; - IsHidden = true; + UpgradeAbilities.Add(new DaredevilAbility()); } } } + +namespace Abilities +{ + public class DaredevilAbility : GenericAbility + { + public override void ActivateAbility() + { + HostShip.AfterGenerateAvailableActionsList += DaredevilAddAction; + } + + public override void DeactivateAbility() + { + HostShip.AfterGenerateAvailableActionsList -= DaredevilAddAction; + } + + private void DaredevilAddAction(GenericShip host) + { + GenericAction newAction = new DaredevilAction + { + ImageUrl = HostUpgrade.ImageUrl, + Host = HostShip + }; + host.AddAvailableAction(newAction); + } + } +} + +namespace ActionsList +{ + public class DaredevilAction : GenericAction + { + private bool _hasOneTurns = false; + + public DaredevilAction() + { + Name = EffectName = "Daredevil"; + } + + public override void ActionTake() + { + Phases.CurrentSubPhase.Pause(); + + Triggers.RegisterTrigger(new Trigger + { + Name = "Daredevil turn", + TriggerType = TriggerTypes.OnAbilityDirect, + TriggerOwner = Selection.ThisShip.Owner.PlayerNo, + EventHandler = SelectDaredevilManeuver + }); + + Triggers.ResolveTriggers(TriggerTypes.OnAbilityDirect, RegisterDaredevilExecutionTrigger); + } + + private void SelectDaredevilManeuver(object sender, EventArgs e) + { + TryAddManeuversForDaredevil("1.L.T"); + TryAddManeuversForDaredevil("1.R.T"); + + Selection.ThisShip.Owner.SelectManeuver(GameMode.CurrentGameMode.AssignManeuver, IsOneTurn); + } + + private void RegisterDaredevilExecutionTrigger() + { + Triggers.RegisterTrigger(new Trigger + { + Name = "Daredevil Execution", + TriggerType = TriggerTypes.OnManeuver, + TriggerOwner = Selection.ThisShip.Owner.PlayerNo, + EventHandler = PerformDaredevilManeuver + }); + + Triggers.ResolveTriggers(TriggerTypes.OnManeuver, ReceiveStress); + } + + private void PerformDaredevilManeuver(object sender, EventArgs e) + { + Messages.ShowInfoToHuman(string.Format("Performing Daredevil: {0} receives one stress token", Selection.ThisShip.PilotName)); + Selection.ThisShip.AssignedManeuver.Perform(); + + if (!_hasOneTurns) + { + RemoveManeuversForDaredevil("1.L.T"); + RemoveManeuversForDaredevil("1.R.T"); + } + } + + private void ReceiveStress() + { + Selection.ThisShip.Tokens.AssignToken(new StressToken(Selection.ThisShip), DoesHaveBoost); + } + + private void DoesHaveBoost() + { + if (Selection.ThisShip.GetAvailableActionsList().Any(action => action is BoostAction)) + { + PhaseCleanup(); + } + else + { + Messages.ShowInfoToHuman("This ship does not have the boost action, rolling for damage"); + DiceRollCheck( + delegate + { + Phases.FinishSubPhase(typeof(DaredevilSubPhase)); + PhaseCleanup(); + }); + } + } + + private void PhaseCleanup() + { + Phases.FinishSubPhase(typeof(ActionDecisonSubPhase)); + Triggers.FinishTrigger(); + } + + private void DiceRollCheck(Action callback) + { + Selection.ActiveShip = Selection.ThisShip; + DaredevilSubPhase dieSubPhase = (DaredevilSubPhase)Phases.StartTemporarySubPhaseNew( + Name, + typeof(DaredevilSubPhase), + callback); + + dieSubPhase.RequiredPlayer = Selection.ThisShip.Owner.PlayerNo; + dieSubPhase.Start(); + } + + private void TryAddManeuversForDaredevil(string maneuver) + { + if (Selection.ThisShip.Maneuvers.ContainsKey(maneuver)) + { + _hasOneTurns = true; + return; + } + Selection.ThisShip.Maneuvers.Add(maneuver, Movement.ManeuverColor.White); + } + + private void RemoveManeuversForDaredevil(string maneuver) + { + Selection.ThisShip.Maneuvers.Remove(maneuver); + } + + private bool IsOneTurn(string maneuverString) + { + bool result = true; + Movement.MovementStruct movement = new Movement.MovementStruct(maneuverString); + if (movement.Speed != Movement.ManeuverSpeed.Speed1) + { + result = false; + } + + if (movement.Bearing != Movement.ManeuverBearing.Turn) + { + result = false; + } + + return result; + } + + public override int GetActionPriority() + { + int result = 0; + return result; + } + } +} + +namespace SubPhases +{ + public class DaredevilSubPhase : DiceRollCheckSubPhase + { + public override void Prepare() + { + diceType = DiceKind.Attack; + diceCount = 2; + + finishAction = FinishAction; + } + + protected override void FinishAction() + { + HideDiceResultMenu(); + + CurrentDiceRoll.RemoveAllFailures(); + if (!CurrentDiceRoll.IsEmpty) + { + foreach (Die die in CurrentDiceRoll.DiceList) + { + if (die.Side == DieSide.Crit || die.Side == DieSide.Success) + { + SufferDamage(); + break; + } + } + } + + CallBack(); + } + + private void NoDamage() + { + CallBack(); + } + + private void SufferDamage() + { + for (int i = 0; i < CurrentDiceRoll.DiceList.Count; i++) + { + Selection.ActiveShip.AssignedDamageDiceroll.AddDice(CurrentDiceRoll.DiceList[i].Side); + + Triggers.RegisterTrigger(new Trigger() + { + Name = "Suffer Daredevil damage", + TriggerType = TriggerTypes.OnDamageIsDealt, + TriggerOwner = Selection.ActiveShip.Owner.PlayerNo, + EventHandler = Selection.ActiveShip.SufferDamage, + EventArgs = new DamageSourceEventArgs() + { + Source = "Daredevil", + DamageType = DamageTypes.CardAbility + }, + Skippable = true + }); + } + + Triggers.ResolveTriggers(TriggerTypes.OnDamageIsDealt, Phases.CurrentSubPhase.Resume); + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/Model/Upgrades/Elite/Decoy.cs b/Assets/Scripts/Model/Upgrades/Elite/Decoy.cs new file mode 100644 index 0000000000..ac18e0de07 --- /dev/null +++ b/Assets/Scripts/Model/Upgrades/Elite/Decoy.cs @@ -0,0 +1,124 @@ +using Abilities; +using Board; +using Ship; +using SubPhases; +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using Upgrade; + +namespace UpgradesList +{ + public class Decoy : GenericUpgrade + { + public Decoy() : base() + { + Type = UpgradeType.Elite; + Name = "Decoy"; + Cost = 1; + + UpgradeAbilities.Add(new DecoyAbility()); + } + } +} + +namespace Abilities +{ + //At the start of the Combat phase, you may choose 1 friendly ship at Range 1-2. + //Exchange your pilot skill with that ship's pilot skill until end of the phase. + public class DecoyAbility : GenericAbility + { + FriendlyPilotSkillModifier _hostShip; + FriendlyPilotSkillModifier _friendlyShip; + + public override void ActivateAbility() + { + Phases.OnCombatPhaseStart += CheckTrigger; + + Phases.OnCombatPhaseEnd += RegisterPilotSkillReset; + } + + public override void DeactivateAbility() + { + Phases.OnCombatPhaseStart -= CheckTrigger; + + Phases.OnCombatPhaseEnd -= RegisterPilotSkillReset; + } + + private void CheckTrigger() + { + List shipsInRange = BoardManager.GetShipsAtRange(HostShip, new Vector2(1, 2), Team.Type.Friendly); + shipsInRange.Remove(HostShip); + + if (shipsInRange.Count <= 0) + { + return; + } + + RegisterAbilityTrigger(TriggerTypes.OnCombatPhaseStart, delegate { AskToSwapPilotSkills(shipsInRange); }); + } + + private void RegisterPilotSkillReset() + { + RegisterAbilityTrigger(TriggerTypes.OnCombatPhaseEnd, ResetPilotSkills); + } + + private void ResetPilotSkills(object sender, EventArgs e) + { + _hostShip.RemoveModifier(); + _friendlyShip.RemoveModifier(); + + _friendlyShip = null; + _hostShip = null; + + Triggers.FinishTrigger(); + } + + private void AskToSwapPilotSkills(List shipsInRange) + { + SelectTargetForAbility(SwitchPilotSkills, new List { TargetTypes.OtherFriendly }, new Vector2(1, 2), Triggers.FinishTrigger); + } + + private void SwitchPilotSkills() + { + _hostShip = new FriendlyPilotSkillModifier(HostShip, TargetShip.PilotSkill); + _friendlyShip = new FriendlyPilotSkillModifier(TargetShip, HostShip.PilotSkill); + + _hostShip.AddPilotSkill(); + _friendlyShip.AddPilotSkill(); + + Messages.ShowInfoToHuman(string.Format("Swapped pilot skills of {0} and {1}", + HostShip.PilotName, TargetShip.PilotName)); + + DecisionSubPhase.ConfirmDecision(); + } + + private class FriendlyPilotSkillModifier : IModifyPilotSkill + { + private GenericShip _host; + private int _newPilotSkill; + + public FriendlyPilotSkillModifier(GenericShip host, int newPilotSkill) + { + _host = host; + _newPilotSkill = newPilotSkill; + } + + public void AddPilotSkill() + { + _host.AddPilotSkillModifier(this); + } + + public void ModifyPilotSkill(ref int pilotSkill) + { + pilotSkill = _newPilotSkill; + } + + public void RemoveModifier() + { + _host.RemovePilotSkillModifier(this); + } + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/Model/Upgrades/Elite/Decoy.cs.meta b/Assets/Scripts/Model/Upgrades/Elite/Decoy.cs.meta new file mode 100644 index 0000000000..39c05ed87c --- /dev/null +++ b/Assets/Scripts/Model/Upgrades/Elite/Decoy.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: 1d56a9751e77e3b4995deb758954fd99 +timeCreated: 1516504821 +licenseType: Free +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Model/Upgrades/Elite/Wingman.cs b/Assets/Scripts/Model/Upgrades/Elite/Wingman.cs new file mode 100644 index 0000000000..a55d0d8598 --- /dev/null +++ b/Assets/Scripts/Model/Upgrades/Elite/Wingman.cs @@ -0,0 +1,95 @@ +using Abilities; +using Board; +using Ship; +using SubPhases; +using System; +using System.Collections.Generic; +using Tokens; +using UnityEngine; +using Upgrade; + +namespace UpgradesList +{ + public class Wingman : GenericUpgrade + { + public Wingman() : base() + { + Type = UpgradeType.Elite; + Name = "Wingman"; + Cost = 2; + + UpgradeAbilities.Add(new WingmanAbility()); + } + } +} + +namespace Abilities +{ + //At the start of the Combat phase, remove 1 stress token from another friendly ship at Range 1. + public class WingmanAbility : GenericAbility + { + public override void ActivateAbility() + { + Phases.OnCombatPhaseStart += RegisterTrigger; + } + + public override void DeactivateAbility() + { + Phases.OnCombatPhaseStart -= RegisterTrigger; + } + + private void RegisterTrigger() + { + RegisterAbilityTrigger(TriggerTypes.OnCombatPhaseStart, CheckTrigger); + } + + private void CheckTrigger(object sender, EventArgs e) + { + List shipsInRange = BoardManager.GetShipsAtRange(HostShip, new Vector2(1, 2), Team.Type.Friendly); + shipsInRange.Remove(HostShip); + + int count = 0; + //If the ship doesn't have stress we shouldn't ask to remove a token. + foreach (GenericShip ship in shipsInRange) + { + if (ship.Tokens.HasToken(typeof(StressToken))) + { + count++; + } + } + + if (count <= 0) + { + Triggers.FinishTrigger(); + return; + } + + AskToRemoveStress(); + } + + private void AskToRemoveStress() + { + Messages.ShowInfoToHuman("Wingman: Select a friendly ship that has a stress token"); + + SelectTargetForAbility(RemoveFriendlyStress, new List { TargetTypes.OtherFriendly }, new Vector2(1, 1), Triggers.FinishTrigger); + } + + private void RemoveFriendlyStress() + { + if (TargetShip.Tokens.HasToken(typeof(StressToken))) + { + //The ship with Wingman equipped is the ship that is removing the stress token. + //If a ship with Wingman removes a stress token from another + //friendly ship that is equipped with Kyle Katarn (crew), that ship is not assigned a focus token from Kyle's ability. + //(X-Wing FAQ, Version 4.2.3, Updated 10/22/2016) + Messages.ShowInfoToHuman(string.Format("Stress token has been removed from {0}", TargetShip.PilotName)); + + TargetShip.Tokens.RemoveToken(typeof(StressToken), SelectShipSubPhase.FinishSelection); + } + else + { + Messages.ShowErrorToHuman("Select a ship with a Stress token"); + } + } + } +} diff --git a/Assets/Scripts/Model/Upgrades/Elite/Wingman.cs.meta b/Assets/Scripts/Model/Upgrades/Elite/Wingman.cs.meta new file mode 100644 index 0000000000..f57470c861 --- /dev/null +++ b/Assets/Scripts/Model/Upgrades/Elite/Wingman.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: f08b9b38a4c9e294599f0b642da13e95 +timeCreated: 1517023141 +licenseType: Free +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: