VanguardReMaster/server/src/Vanguard.Rules/Engine/Abilities/CardScripts.cs

351 lines
12 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Vanguard.Rules.Cards;
namespace Vanguard.Rules.Engine.Abilities;
/// <summary>Скрипты карт первого сета, подключённые к движку.</summary>
public static class CardScripts
{
public static IReadOnlyDictionary<string, CardScript> Default { get; } =
new Dictionary<string, CardScript>(StringComparer.Ordinal)
{
["barcgal"] = new BarcgalScript(),
["wingal"] = new WingalScript(),
["king-of-knights-alfred"] = new AlfredScript(),
["blaster-blade"] = new BlasterBladeScript(),
["lake-maiden-lien"] = new DrawOneScript("lake-maiden-lien"),
["dragon-monk-gojo"] = new DrawOneScript("dragon-monk-gojo"),
["screamin-and-dancin-announcer-shout"] = new DrawOneScript("screamin-and-dancin-announcer-shout"),
["lizard-soldier-conroe"] = new ConroeScript(),
["battle-sister-cocoa"] = new CocoaScript(),
["tyrant-deathrex"] = new DeathrexScript(),
["demon-eater"] = new DemonEaterScript(),
["maiden-of-libra"] = new MaidenOfLibraScript(),
["knight-of-rose-morgana"] = new MorganaScript(),
};
}
/// <summary>
/// Knight of Rose, Morgana: при атаке можно сбросить карту из руки и получить +4000 до конца хода.
/// </summary>
public sealed class MorganaScript : CardScript
{
public override string NameId => "knight-of-rose-morgana";
public override IEnumerable<AbilityDefinition> Abilities
{
get
{
yield return new AbilityDefinition
{
Trigger = AbilityTrigger.OnAttackDeclared,
Optional = true,
CanPay = ctx => ctx.State.Players[ctx.Owner].Hand.Count > 0,
Resolve = ctx => ctx.Engine.AskHandCardChoice(
ctx.Owner,
"Сбросьте карту из руки",
null,
card =>
{
var p = ctx.State.Players[ctx.Owner];
p.Hand.Remove(card);
p.Drop.Add(card);
ctx.Source.TemporaryPower += 4000;
}),
};
}
}
}
/// <summary>Tyrant, Deathrex: когда эта карта атакует, получает +5000 до конца боя.</summary>
public sealed class DeathrexScript : CardScript
{
public override string NameId => "tyrant-deathrex";
public override IEnumerable<AbilityDefinition> Abilities
{
get
{
yield return new AbilityDefinition
{
Trigger = AbilityTrigger.OnAttackDeclared,
Resolve = ctx => ctx.Engine.AddBattlePower(5000),
};
}
}
}
/// <summary>Demon Eater: в начале Основной фазы Soul Charge 1 и +2000 до конца хода.</summary>
public sealed class DemonEaterScript : CardScript
{
public override string NameId => "demon-eater";
public override IEnumerable<AbilityDefinition> Abilities
{
get
{
yield return new AbilityDefinition
{
Trigger = AbilityTrigger.OnPhaseStart,
Resolve = ctx =>
{
ctx.Engine.SoulCharge(ctx.Owner, 1);
ctx.Source.TemporaryPower += 2000;
},
};
}
}
}
/// <summary>Maiden of Libra: когда атака попадает, Counter Blast 2 и взять карту.</summary>
public sealed class MaidenOfLibraScript : CardScript
{
public override string NameId => "maiden-of-libra";
public override IEnumerable<AbilityDefinition> Abilities
{
get
{
yield return new AbilityDefinition
{
Trigger = AbilityTrigger.OnAttackHit,
Optional = true,
CanPay = ctx => ctx.Engine.CanCounterBlast(ctx.Owner, 2),
Pay = ctx => ctx.Engine.CounterBlast(ctx.Owner, 2),
Resolve = ctx => ctx.Engine.DrawCards(ctx.Owner, 1),
};
}
}
}
/// <summary>
/// Battle Sister, Cocoa: при размещении на VC/RC, если Авангард Oracle Think Tank,
/// посмотреть верхнюю карту и оставить её на верху или отправить в низ.
/// </summary>
public sealed class CocoaScript : CardScript
{
public override string NameId => "battle-sister-cocoa";
public override IEnumerable<AbilityDefinition> Abilities
{
get
{
yield return new AbilityDefinition
{
Trigger = AbilityTrigger.OnPlace,
Condition = ctx => ctx.Engine.VanguardClan(ctx.Owner) == Clan.OracleThinkTank,
Resolve = ctx => ctx.Engine.LookTopAndReorder(ctx.Owner, "Верхняя карта колоды"),
};
}
}
}
/// <summary>
/// Lizard Soldier, Conroe: [ACT](RC): Counter Blast 1 и уничтожить эту карту →
/// найти в колоде Kagero 1 ранга или ниже и добавить в руку.
/// </summary>
public sealed class ConroeScript : CardScript
{
public override string NameId => "lizard-soldier-conroe";
public override IEnumerable<ActivatedAbility> Activated
{
get
{
yield return new ActivatedAbility
{
CanActivate = ctx => ctx.Engine.CanCounterBlast(ctx.Owner, 1),
RetiresSelf = true,
Resolve = ctx =>
{
ctx.Engine.CounterBlast(ctx.Owner, 1);
ctx.Engine.SearchDeckToHand(
ctx.Owner,
"Найдите Kagero 1 ранга или ниже",
d => d.Clan == Clan.Kagero && d.Grade <= 1);
},
};
}
}
}
/// <summary>
/// «[ACT]: повернуть эту карту и сбросить карту из руки → взять карту».
/// Общий скрипт для Lake Maiden, Lien, Dragon Monk, Gojo и Shout.
/// </summary>
public sealed class DrawOneScript : CardScript
{
public DrawOneScript(string nameId) => NameId = nameId;
public override string NameId { get; }
public override IEnumerable<ActivatedAbility> Activated
{
get
{
yield return new ActivatedAbility
{
CanActivate = _ => true,
RestsSelf = true,
RequiresDiscard = true,
Resolve = ctx => ctx.Engine.DrawCards(ctx.Owner, 1),
};
}
}
}
/// <summary>
/// Blaster Blade: при размещении оплатить Counter Blast 2 и уничтожить Арьергард противника.
/// На Авангарде — любой, на Арьергарде — только 2 ранга или выше и при Авангарде Royal Paladin.
/// </summary>
public sealed class BlasterBladeScript : CardScript
{
public override string NameId => "blaster-blade";
public override IEnumerable<AbilityDefinition> Abilities
{
get
{
yield return new AbilityDefinition
{
Trigger = AbilityTrigger.OnPlace,
Optional = true,
Condition = ctx => ctx.Engine.IsVanguardOf(ctx.Source, ctx.Owner),
CanPay = ctx => ctx.Engine.CanCounterBlast(ctx.Owner, 2),
Pay = ctx => ctx.Engine.CounterBlast(ctx.Owner, 2),
Resolve = ctx =>
{
var opponent = 1 - ctx.Owner;
var slots = ctx.Engine.RearGuardSlots(opponent, _ => true);
if (slots.Count == 0)
return;
ctx.Engine.AskUnitChoice(
ctx.Owner,
opponent,
"Выберите Арьергард противника",
slots,
slot => ctx.Engine.RetireRearGuard(opponent, slot));
},
};
yield return new AbilityDefinition
{
Trigger = AbilityTrigger.OnPlace,
Optional = true,
Condition = ctx =>
!ctx.Engine.IsVanguardOf(ctx.Source, ctx.Owner) &&
ctx.Engine.VanguardClan(ctx.Owner) == Clan.RoyalPaladin,
CanPay = ctx => ctx.Engine.CanCounterBlast(ctx.Owner, 2),
Pay = ctx => ctx.Engine.CounterBlast(ctx.Owner, 2),
Resolve = ctx =>
{
var opponent = 1 - ctx.Owner;
var slots = ctx.Engine.RearGuardSlots(opponent, d => d.Grade >= 2);
if (slots.Count == 0)
return;
ctx.Engine.AskUnitChoice(
ctx.Owner,
opponent,
"Выберите Арьергард противника 2 ранга или выше",
slots,
slot => ctx.Engine.RetireRearGuard(opponent, slot));
},
};
}
}
}
/// <summary>
/// Barcgal: когда другой Royal Paladin сменяет эту карту, вы можете призвать её в круг Арьергарда.
/// </summary>
public sealed class BarcgalScript : CardScript
{
public override string NameId => "barcgal";
public override IEnumerable<AbilityDefinition> Abilities
{
get
{
yield return new AbilityDefinition
{
Trigger = AbilityTrigger.OnRideOver,
Optional = true,
Condition = ctx =>
ctx.Other is not null &&
ctx.Catalog.CardOf(ctx.Other.PrintingId).Clan == Clan.RoyalPaladin,
Resolve = ctx => ctx.Engine.CallFromSoul(ctx.Source, ctx.Owner),
};
}
}
}
/// <summary>
/// Wingal: когда эта карта поддерживает Blaster Blade, усиленная карта получает +4000 до конца боя.
/// </summary>
public sealed class WingalScript : CardScript
{
private const string BlasterBlade = "blaster-blade";
public override string NameId => "wingal";
public override IEnumerable<AbilityDefinition> Abilities
{
get
{
yield return new AbilityDefinition
{
Trigger = AbilityTrigger.OnBoost,
Condition = ctx =>
ctx.Other is not null &&
ctx.Catalog.CardOf(ctx.Other.PrintingId).NameId == BlasterBlade,
Resolve = ctx => ctx.Engine.AddBattlePower(4000),
};
}
}
}
/// <summary>
/// King of Knights, Alfred: в свой ход на круге Авангарда получает +2000
/// за каждый свой Арьергард Royal Paladin.
/// </summary>
public sealed class AlfredScript : CardScript
{
public override string NameId => "king-of-knights-alfred";
public override IEnumerable<ContinuousAbility> Continuous
{
get
{
yield return new ContinuousAbility
{
Applies = ctx =>
ctx.Engine.IsVanguardOf(ctx.Source, ctx.Owner) &&
ctx.State.ActivePlayer == ctx.Owner,
PowerBonus = ctx => 2000 * ctx.Engine.CountRearGuards(ctx.Owner, Clan.RoyalPaladin),
};
}
}
public override IEnumerable<ActivatedAbility> Activated
{
get
{
yield return new ActivatedAbility
{
CanActivate = ctx =>
ctx.Engine.CanCounterBlast(ctx.Owner, 3) &&
ctx.Engine.HasEmptyRearGuard(ctx.Owner),
Resolve = ctx =>
{
ctx.Engine.CounterBlast(ctx.Owner, 3);
ctx.Engine.SearchDeckToCall(
ctx.Owner,
"Найдите Royal Paladin 2 ранга или ниже",
d => d.Clan == Clan.RoyalPaladin && d.Grade <= 2);
},
};
}
}
}