mirror of
https://github.com/magefree/mage.git
synced 2025-12-20 10:40:06 -08:00
[40K] Implement Seeker of Slaanesh; added new must attack option (#12712)
* Add player-based "must attack" requirement check * Implement Seeker of Slaanesh and add (ignored) test * Fix check for ability of any controlled creatures to attack * rename misleading variable
This commit is contained in:
parent
060551ab48
commit
4259b7fa39
4 changed files with 120 additions and 1 deletions
|
|
@ -1916,6 +1916,10 @@ public class HumanPlayer extends PlayerImpl {
|
||||||
// check if enough attackers are declared
|
// check if enough attackers are declared
|
||||||
// check if players have to be attacked
|
// check if players have to be attacked
|
||||||
Set<UUID> playersToAttackIfAble = new HashSet<>();
|
Set<UUID> playersToAttackIfAble = new HashSet<>();
|
||||||
|
|
||||||
|
// or if active player must attack with anything
|
||||||
|
boolean mustAttack = false;
|
||||||
|
|
||||||
for (Map.Entry<RequirementEffect, Set<Ability>> entry : game.getContinuousEffects().getApplicableRequirementEffects(null, true, game).entrySet()) {
|
for (Map.Entry<RequirementEffect, Set<Ability>> entry : game.getContinuousEffects().getApplicableRequirementEffects(null, true, game).entrySet()) {
|
||||||
RequirementEffect effect = entry.getKey();
|
RequirementEffect effect = entry.getKey();
|
||||||
for (Ability ability : entry.getValue()) {
|
for (Ability ability : entry.getValue()) {
|
||||||
|
|
@ -1923,6 +1927,9 @@ public class HumanPlayer extends PlayerImpl {
|
||||||
if (playerToAttack != null) {
|
if (playerToAttack != null) {
|
||||||
playersToAttackIfAble.add(playerToAttack);
|
playersToAttackIfAble.add(playerToAttack);
|
||||||
}
|
}
|
||||||
|
if (effect.mustAttack(game)){
|
||||||
|
mustAttack = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!playersToAttackIfAble.isEmpty()) {
|
if (!playersToAttackIfAble.isEmpty()) {
|
||||||
|
|
@ -1960,6 +1967,16 @@ public class HumanPlayer extends PlayerImpl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mustAttack && game.getCombat().getAttackers().isEmpty()){
|
||||||
|
// no attackers, but required to attack with something -- check if anything can attack
|
||||||
|
for (Permanent attacker : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, getId(), game)) {
|
||||||
|
if (attacker.canAttackInPrinciple(null, game)){
|
||||||
|
game.informPlayer(this, "You are forced to attack with at least one creature, e.g. " + attacker.getIdName() + ".");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
83
Mage.Sets/src/mage/cards/s/SeekerOfSlaanesh.java
Normal file
83
Mage.Sets/src/mage/cards/s/SeekerOfSlaanesh.java
Normal file
|
|
@ -0,0 +1,83 @@
|
||||||
|
package mage.cards.s;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
import mage.MageInt;
|
||||||
|
import mage.abilities.Ability;
|
||||||
|
import mage.abilities.common.SimpleStaticAbility;
|
||||||
|
import mage.abilities.effects.RequirementEffect;
|
||||||
|
import mage.constants.Duration;
|
||||||
|
import mage.constants.SubType;
|
||||||
|
import mage.abilities.keyword.HasteAbility;
|
||||||
|
import mage.cards.CardImpl;
|
||||||
|
import mage.cards.CardSetInfo;
|
||||||
|
import mage.constants.CardType;
|
||||||
|
import mage.constants.Zone;
|
||||||
|
import mage.game.Game;
|
||||||
|
import mage.game.permanent.Permanent;
|
||||||
|
import mage.players.Player;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author jimga150
|
||||||
|
*/
|
||||||
|
public final class SeekerOfSlaanesh extends CardImpl {
|
||||||
|
|
||||||
|
public SeekerOfSlaanesh(UUID ownerId, CardSetInfo setInfo) {
|
||||||
|
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}");
|
||||||
|
|
||||||
|
this.subtype.add(SubType.DEMON);
|
||||||
|
this.power = new MageInt(3);
|
||||||
|
this.toughness = new MageInt(3);
|
||||||
|
|
||||||
|
// Haste
|
||||||
|
this.addAbility(HasteAbility.getInstance());
|
||||||
|
|
||||||
|
// Allure of Slaanesh -- Each opponent must attack with at least one creature each combat if able.
|
||||||
|
addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new SeekerOfSlaaneshForceAttackEffect(Duration.WhileOnBattlefield))
|
||||||
|
.withFlavorWord("Allure of Slaanesh"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private SeekerOfSlaanesh(final SeekerOfSlaanesh card) {
|
||||||
|
super(card);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SeekerOfSlaanesh copy() {
|
||||||
|
return new SeekerOfSlaanesh(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Based on TroveOfTemptationForceAttackEffect
|
||||||
|
class SeekerOfSlaaneshForceAttackEffect extends RequirementEffect {
|
||||||
|
|
||||||
|
SeekerOfSlaaneshForceAttackEffect(Duration duration) {
|
||||||
|
super(duration, true);
|
||||||
|
staticText = "Each opponent must attack with at least one creature each combat if able.";
|
||||||
|
}
|
||||||
|
|
||||||
|
private SeekerOfSlaaneshForceAttackEffect(final SeekerOfSlaaneshForceAttackEffect effect) {
|
||||||
|
super(effect);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SeekerOfSlaaneshForceAttackEffect copy() {
|
||||||
|
return new SeekerOfSlaaneshForceAttackEffect(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mustAttack(Game game) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mustBlock(Game game) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean applies(Permanent permanent, Ability source, Game game) {
|
||||||
|
Player controller = game.getPlayer(source.getControllerId());
|
||||||
|
return controller != null && controller.hasOpponent(game.getActivePlayerId(), game);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -224,6 +224,7 @@ public final class Warhammer40000 extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Scoured Barrens", 293, Rarity.COMMON, mage.cards.s.ScouredBarrens.class));
|
cards.add(new SetCardInfo("Scoured Barrens", 293, Rarity.COMMON, mage.cards.s.ScouredBarrens.class));
|
||||||
cards.add(new SetCardInfo("Screamer-Killer", 84, Rarity.RARE, mage.cards.s.ScreamerKiller.class));
|
cards.add(new SetCardInfo("Screamer-Killer", 84, Rarity.RARE, mage.cards.s.ScreamerKiller.class));
|
||||||
cards.add(new SetCardInfo("Sculpting Steel", 247, Rarity.RARE, mage.cards.s.SculptingSteel.class));
|
cards.add(new SetCardInfo("Sculpting Steel", 247, Rarity.RARE, mage.cards.s.SculptingSteel.class));
|
||||||
|
cards.add(new SetCardInfo("Seeker of Slaanesh", 85, Rarity.UNCOMMON, mage.cards.s.SeekerOfSlaanesh.class));
|
||||||
cards.add(new SetCardInfo("Shadow in the Warp", 140, Rarity.RARE, mage.cards.s.ShadowInTheWarp.class));
|
cards.add(new SetCardInfo("Shadow in the Warp", 140, Rarity.RARE, mage.cards.s.ShadowInTheWarp.class));
|
||||||
cards.add(new SetCardInfo("Shard of the Nightbringer", 55, Rarity.RARE, mage.cards.s.ShardOfTheNightbringer.class));
|
cards.add(new SetCardInfo("Shard of the Nightbringer", 55, Rarity.RARE, mage.cards.s.ShardOfTheNightbringer.class));
|
||||||
cards.add(new SetCardInfo("Shard of the Void Dragon", 56, Rarity.RARE, mage.cards.s.ShardOfTheVoidDragon.class));
|
cards.add(new SetCardInfo("Shard of the Void Dragon", 56, Rarity.RARE, mage.cards.s.ShardOfTheVoidDragon.class));
|
||||||
|
|
|
||||||
|
|
@ -174,7 +174,7 @@ public class AttackAndBlockByAITest extends CardTestPlayerBaseAI {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Ignore // TODO: need to fix Trove of Temptation effect (player must attack by one creature)
|
@Ignore // TODO: need to fix Trove of Temptation effect (player must be attacked by one creature)
|
||||||
public void test_ForceAttack_1_small_vs_1_big_b() {
|
public void test_ForceAttack_1_small_vs_1_big_b() {
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Arbor Elf", 1); // 1/1
|
addCard(Zone.BATTLEFIELD, playerA, "Arbor Elf", 1); // 1/1
|
||||||
addCard(Zone.BATTLEFIELD, playerB, "Ancient Brontodon", 1); // 9/9
|
addCard(Zone.BATTLEFIELD, playerB, "Ancient Brontodon", 1); // 9/9
|
||||||
|
|
@ -193,6 +193,24 @@ public class AttackAndBlockByAITest extends CardTestPlayerBaseAI {
|
||||||
assertLife(playerB, 20);
|
assertLife(playerB, 20);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Ignore // TODO: need to fix Seeker of Slaanesh effect (players must attack by one creature)
|
||||||
|
public void test_ForceAttack_any() {
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Arbor Elf", 1); // 1/1
|
||||||
|
// Each opponent must attack with at least one creature each combat if able.
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, "Seeker of Slaanesh", 1); // 3/3
|
||||||
|
|
||||||
|
block(1, playerB, "Seeker of Slaanesh", "Arbor Elf");
|
||||||
|
|
||||||
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertGraveyardCount(playerA, "Arbor Elf", 1);
|
||||||
|
assertLife(playerA, 20);
|
||||||
|
assertLife(playerB, 20);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_Attack_1_with_counters_vs_1() {
|
public void test_Attack_1_with_counters_vs_1() {
|
||||||
// chainbreaker real stats is 1/1, it's can be saftly attacked
|
// chainbreaker real stats is 1/1, it's can be saftly attacked
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue