Add boost attack gestures and Barcgal activated search
CI / test (push) Has been cancelled
Details
CI / test (push) Has been cancelled
Details
This commit is contained in:
parent
08c170e0d9
commit
aa330c6cfa
|
|
@ -90,6 +90,7 @@ namespace Vanguard.UI
|
||||||
private string _discardPrompt;
|
private string _discardPrompt;
|
||||||
private Action _discardCancelAction;
|
private Action _discardCancelAction;
|
||||||
private int _pendingBoosterSlot = -1;
|
private int _pendingBoosterSlot = -1;
|
||||||
|
private int _pendingBoostAttackerSlot = -2;
|
||||||
private int? _triggerPowerSlot;
|
private int? _triggerPowerSlot;
|
||||||
private readonly HashSet<int> _mulliganSelected = new HashSet<int>();
|
private readonly HashSet<int> _mulliganSelected = new HashSet<int>();
|
||||||
private bool _mulliganUsed;
|
private bool _mulliganUsed;
|
||||||
|
|
@ -278,6 +279,7 @@ namespace Vanguard.UI
|
||||||
_mulliganUsed = false;
|
_mulliganUsed = false;
|
||||||
_abilityDamageIndex = -1;
|
_abilityDamageIndex = -1;
|
||||||
_pendingBoosterSlot = -1;
|
_pendingBoosterSlot = -1;
|
||||||
|
_pendingBoostAttackerSlot = -2;
|
||||||
_triggerPowerSlot = null;
|
_triggerPowerSlot = null;
|
||||||
_showAllIntents = false;
|
_showAllIntents = false;
|
||||||
_autoFinishMulligan = false;
|
_autoFinishMulligan = false;
|
||||||
|
|
@ -1087,6 +1089,7 @@ namespace Vanguard.UI
|
||||||
_pendingIntents.Clear();
|
_pendingIntents.Clear();
|
||||||
_highlightSlots.Clear();
|
_highlightSlots.Clear();
|
||||||
_pendingBoosterSlot = -1;
|
_pendingBoosterSlot = -1;
|
||||||
|
_pendingBoostAttackerSlot = -2;
|
||||||
_triggerPowerSlot = null;
|
_triggerPowerSlot = null;
|
||||||
if (intent is FinishMulliganIntent or SkipRideIntent
|
if (intent is FinishMulliganIntent or SkipRideIntent
|
||||||
or EnterBattleIntent or EndTurnIntent)
|
or EnterBattleIntent or EndTurnIntent)
|
||||||
|
|
@ -2105,7 +2108,22 @@ namespace Vanguard.UI
|
||||||
var legal = _view.LegalIntents ?? new List<IntentPayload>();
|
var legal = _view.LegalIntents ?? new List<IntentPayload>();
|
||||||
IntentPayload intent = null;
|
IntentPayload intent = null;
|
||||||
|
|
||||||
if (source.Zone == BoardZone.Hand)
|
if (_pendingBoosterSlot >= 0 && source.IsField)
|
||||||
|
{
|
||||||
|
if (source.Slot != _pendingBoostAttackerSlot)
|
||||||
|
{
|
||||||
|
SetStatus(
|
||||||
|
"Поддержка уже объявлена: атаковать можно только поддерживаемой картой.",
|
||||||
|
new Color(1f, 0.55f, 0.45f));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
intent = legal.OfType<AttackIntent>()
|
||||||
|
.FirstOrDefault(item => item.AttackerSlot == source.Slot
|
||||||
|
&& item.TargetSlot == target.Slot
|
||||||
|
&& item.BoosterSlot == _pendingBoosterSlot);
|
||||||
|
}
|
||||||
|
else if (source.Zone == BoardZone.Hand)
|
||||||
{
|
{
|
||||||
if (target.Zone == BoardZone.Guardian)
|
if (target.Zone == BoardZone.Guardian)
|
||||||
{
|
{
|
||||||
|
|
@ -2139,6 +2157,15 @@ namespace Vanguard.UI
|
||||||
intent = legal.OfType<InterceptIntent>()
|
intent = legal.OfType<InterceptIntent>()
|
||||||
.FirstOrDefault(item => item.Slot == source.Slot);
|
.FirstOrDefault(item => item.Slot == source.Slot);
|
||||||
}
|
}
|
||||||
|
else if (target.Player == _view.You
|
||||||
|
&& source.Slot is 0 or 1 or 2
|
||||||
|
&& (target.Zone == BoardZone.Vanguard
|
||||||
|
|| (target.Zone == BoardZone.RearGuard
|
||||||
|
&& target.Slot is 3 or 4)))
|
||||||
|
{
|
||||||
|
BeginBoostAttack(source.Slot, target.Slot, legal);
|
||||||
|
return;
|
||||||
|
}
|
||||||
else if (target.Player == _view.You && target.Zone == BoardZone.RearGuard)
|
else if (target.Player == _view.You && target.Zone == BoardZone.RearGuard)
|
||||||
{
|
{
|
||||||
intent = legal.OfType<MoveIntent>()
|
intent = legal.OfType<MoveIntent>()
|
||||||
|
|
@ -2166,6 +2193,36 @@ namespace Vanguard.UI
|
||||||
OnIntentClicked(intent);
|
OnIntentClicked(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void BeginBoostAttack(
|
||||||
|
int boosterSlot,
|
||||||
|
int attackerSlot,
|
||||||
|
IReadOnlyList<IntentPayload> legal)
|
||||||
|
{
|
||||||
|
var attacks = legal.OfType<AttackIntent>()
|
||||||
|
.Where(intent => intent.BoosterSlot == boosterSlot
|
||||||
|
&& intent.AttackerSlot == attackerSlot)
|
||||||
|
.ToList();
|
||||||
|
if (attacks.Count == 0)
|
||||||
|
{
|
||||||
|
SetStatus(
|
||||||
|
"Эта карта не может поддержать выбранный круг.",
|
||||||
|
new Color(1f, 0.55f, 0.45f));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_pendingBoosterSlot = boosterSlot;
|
||||||
|
_pendingBoostAttackerSlot = attackerSlot;
|
||||||
|
_pendingIntents.Clear();
|
||||||
|
_pendingIntents.AddRange(attacks);
|
||||||
|
RebuildHighlights();
|
||||||
|
RebuildIntents(_view);
|
||||||
|
SetStatus(
|
||||||
|
"Поддержка: " + CardName(
|
||||||
|
CardAt(_view.You, boosterSlot)?.PrintingId ?? string.Empty)
|
||||||
|
+ ". Атакуйте только этой картой и выберите цель.",
|
||||||
|
new Color(0.98f, 0.82f, 0.42f));
|
||||||
|
}
|
||||||
|
|
||||||
private void OnBoard3DPileRightClicked(BoardCardRef pile)
|
private void OnBoard3DPileRightClicked(BoardCardRef pile)
|
||||||
{
|
{
|
||||||
if (_view == null || _inputLock.IsLocked)
|
if (_view == null || _inputLock.IsLocked)
|
||||||
|
|
@ -2260,6 +2317,11 @@ namespace Vanguard.UI
|
||||||
? "Выберите карту в руке для сброса."
|
? "Выберите карту в руке для сброса."
|
||||||
: _discardPrompt;
|
: _discardPrompt;
|
||||||
}
|
}
|
||||||
|
else if (_pendingBoosterSlot >= 0 && _pendingIntents.Count > 0)
|
||||||
|
{
|
||||||
|
title = "ПОДДЕРЖКА";
|
||||||
|
hint = "Атакуйте только поддерживаемой картой и выберите цель.";
|
||||||
|
}
|
||||||
else if (_pendingIntents.Count > 0)
|
else if (_pendingIntents.Count > 0)
|
||||||
{
|
{
|
||||||
title = "ВЫБОР ЦЕЛИ";
|
title = "ВЫБОР ЦЕЛИ";
|
||||||
|
|
@ -2809,6 +2871,7 @@ namespace Vanguard.UI
|
||||||
_pendingIntents.Clear();
|
_pendingIntents.Clear();
|
||||||
_highlightSlots.Clear();
|
_highlightSlots.Clear();
|
||||||
_pendingBoosterSlot = -1;
|
_pendingBoosterSlot = -1;
|
||||||
|
_pendingBoostAttackerSlot = -2;
|
||||||
_triggerPowerSlot = null;
|
_triggerPowerSlot = null;
|
||||||
if (rebuild && _view != null)
|
if (rebuild && _view != null)
|
||||||
RebuildIntents(_view);
|
RebuildIntents(_view);
|
||||||
|
|
|
||||||
|
|
@ -358,6 +358,24 @@ public sealed class BarcgalScript : CardScript
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<ActivatedAbility> Activated
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
yield return new ActivatedAbility
|
||||||
|
{
|
||||||
|
RestsSelf = true,
|
||||||
|
CanActivate = ctx =>
|
||||||
|
!ctx.Engine.IsVanguardOf(ctx.Source, ctx.Owner) &&
|
||||||
|
ctx.Engine.HasEmptyRearGuard(ctx.Owner),
|
||||||
|
Resolve = ctx => ctx.Engine.SearchDeckToCall(
|
||||||
|
ctx.Owner,
|
||||||
|
"Найдите Future Knight, Llew или Flogal",
|
||||||
|
definition => definition.NameId is "future-knight-llew" or "flogal"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
||||||
|
|
@ -1510,9 +1510,15 @@ public sealed class GameEngine
|
||||||
foreach (var target in targets)
|
foreach (var target in targets)
|
||||||
commands.Add(new AttackCommand(attackerSlot, target));
|
commands.Add(new AttackCommand(attackerSlot, target));
|
||||||
|
|
||||||
if (attackerSlot is 3 or 4)
|
var boosterSlot = attackerSlot switch
|
||||||
|
{
|
||||||
|
-1 => 1, // Vanguard is boosted from the centre back row.
|
||||||
|
3 => 0,
|
||||||
|
4 => 2,
|
||||||
|
_ => -1,
|
||||||
|
};
|
||||||
|
if (boosterSlot >= 0)
|
||||||
{
|
{
|
||||||
var boosterSlot = attackerSlot == 3 ? 0 : 2;
|
|
||||||
var booster = State.GetUnit(player, boosterSlot);
|
var booster = State.GetUnit(player, boosterSlot);
|
||||||
if (booster is not null && !booster.Rested && State.CanBoost(booster))
|
if (booster is not null && !booster.Rested && State.CanBoost(booster))
|
||||||
{
|
{
|
||||||
|
|
@ -1986,10 +1992,17 @@ public sealed class GameEngine
|
||||||
CardInstance? booster = null;
|
CardInstance? booster = null;
|
||||||
if (boosterSlot >= 0)
|
if (boosterSlot >= 0)
|
||||||
{
|
{
|
||||||
if (attackerSlot is not (3 or 4))
|
var expected = attackerSlot switch
|
||||||
return CommandResult.Reject("Поддерживать можно только атаку Арьергарда из переднего ряда.");
|
{
|
||||||
|
-1 => 1,
|
||||||
|
3 => 0,
|
||||||
|
4 => 2,
|
||||||
|
_ => -1,
|
||||||
|
};
|
||||||
|
if (expected < 0)
|
||||||
|
return CommandResult.Reject(
|
||||||
|
"Поддерживать можно только Авангард или Арьергард переднего ряда.");
|
||||||
|
|
||||||
var expected = attackerSlot == 3 ? 0 : 2;
|
|
||||||
if (boosterSlot != expected)
|
if (boosterSlot != expected)
|
||||||
return CommandResult.Reject("Поддержка возможна только из заднего ряда той же колонны.");
|
return CommandResult.Reject("Поддержка возможна только из заднего ряда той же колонны.");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -823,6 +823,51 @@ public class GameEngineTests
|
||||||
Assert.DoesNotContain(engine.State.Players[0].RearGuards, u => u?.PrintingId == Barcgal);
|
Assert.DoesNotContain(engine.State.Players[0].RearGuards, u => u?.PrintingId == Barcgal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Vanguard_Can_Be_Boosted_From_Centre_Back_Row()
|
||||||
|
{
|
||||||
|
var engine = StartedEngine();
|
||||||
|
Give(engine, 0, Marron);
|
||||||
|
engine.Execute(new RideCommand(Marron));
|
||||||
|
|
||||||
|
Give(engine, 0, Marron);
|
||||||
|
Assert.True(engine.Execute(new CallCommand(Marron, 1)).Accepted);
|
||||||
|
engine.State.Players[0].RearGuards[1]!.Rested = false;
|
||||||
|
|
||||||
|
SetVanguard(engine, 1, Gallatin);
|
||||||
|
engine.Execute(new EnterBattleCommand());
|
||||||
|
|
||||||
|
Assert.True(engine.Execute(new AttackCommand(-1, -1, 1)).Accepted);
|
||||||
|
Assert.NotNull(engine.State.Battle);
|
||||||
|
Assert.Equal(-1, engine.State.Battle!.AttackerSlot);
|
||||||
|
Assert.Equal(1, engine.State.Battle.BoosterSlot);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Barcgal_Activated_Searches_And_Calls_Unit_To_Chosen_Circle()
|
||||||
|
{
|
||||||
|
var engine = InMainPhase();
|
||||||
|
Give(engine, 0, Barcgal);
|
||||||
|
var barcgal = engine.State.Players[0].Hand
|
||||||
|
.Single(card => card.PrintingId == Barcgal);
|
||||||
|
|
||||||
|
Assert.True(engine.Execute(new CallCommand(Barcgal, 0)).Accepted);
|
||||||
|
barcgal.Rested = false;
|
||||||
|
Assert.True(engine.Execute(new ActivateAbilityCommand(barcgal.Id)).Accepted);
|
||||||
|
|
||||||
|
Assert.NotNull(engine.State.PendingChoice);
|
||||||
|
Assert.Equal(Step.Choice, engine.State.Step);
|
||||||
|
Assert.True(engine.Execute(new ChooseCommand(0)).Accepted);
|
||||||
|
|
||||||
|
Assert.NotNull(engine.State.PendingChoice);
|
||||||
|
Assert.True(engine.Execute(new ChooseCommand(1)).Accepted);
|
||||||
|
|
||||||
|
Assert.Equal(
|
||||||
|
Flogal,
|
||||||
|
engine.State.Players[0].RearGuards[2]?.PrintingId);
|
||||||
|
Assert.True(barcgal.Rested);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Wingal_Gives_BlasterBlade_4000_During_Battle()
|
public void Wingal_Gives_BlasterBlade_4000_During_Battle()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue