Add Season of the Witch

This commit is contained in:
Alumi
2021-03-11 14:30:17 +00:00
committed by Michael Kamensky
parent b93f68ef34
commit a305dc999e
4 changed files with 55 additions and 0 deletions

View File

@@ -682,6 +682,8 @@ public class AiAttackController {
final boolean bAssault = this.doAssault(ai); final boolean bAssault = this.doAssault(ai);
// TODO: detect Lightmine Field by presence of a card with a specific trigger // TODO: detect Lightmine Field by presence of a card with a specific trigger
final boolean lightmineField = ComputerUtilCard.isPresentOnBattlefield(ai.getGame(), "Lightmine Field"); final boolean lightmineField = ComputerUtilCard.isPresentOnBattlefield(ai.getGame(), "Lightmine Field");
// TODO: detect Season of the Witch by presence of a card with a specific trigger
final boolean seasonOfTheWitch = ComputerUtilCard.isPresentOnBattlefield(ai.getGame(), "Season of the Witch");
// Determine who will be attacked // Determine who will be attacked
GameEntity defender = this.chooseDefender(combat, bAssault); GameEntity defender = this.chooseDefender(combat, bAssault);
@@ -715,6 +717,9 @@ public class AiAttackController {
} else if (attacker.hasSVar("EndOfTurnLeavePlay") } else if (attacker.hasSVar("EndOfTurnLeavePlay")
&& isEffectiveAttacker(ai, attacker, combat)) { && isEffectiveAttacker(ai, attacker, combat)) {
mustAttack = true; mustAttack = true;
} else if (seasonOfTheWitch) {
// TODO: if there are other ways to tap this creature (like mana creature), then don't need to attack
mustAttack = true;
} else { } else {
for (KeywordInterface inst : attacker.getKeywords()) { for (KeywordInterface inst : attacker.getKeywords()) {
String s = inst.getOriginal(); String s = inst.getOriginal();

View File

@@ -17,6 +17,7 @@ import forge.game.ability.AbilityUtils;
import forge.game.card.CardPredicates.Presets; import forge.game.card.CardPredicates.Presets;
import forge.game.combat.AttackingBand; import forge.game.combat.AttackingBand;
import forge.game.combat.Combat; import forge.game.combat.Combat;
import forge.game.combat.CombatUtil;
import forge.game.keyword.Keyword; import forge.game.keyword.Keyword;
import forge.game.mana.Mana; import forge.game.mana.Mana;
import forge.game.player.Player; import forge.game.player.Player;
@@ -1622,6 +1623,9 @@ public class CardProperty {
if (band == null || !band.getAttackers().contains(card)) { if (band == null || !band.getAttackers().contains(card)) {
return false; return false;
} }
} else if (property.equals("couldAttackButNotAttacking")) {
if (!game.getPhaseHandler().isPlayerTurn(controller)) return false;
return CombatUtil.couldAttackButNotAttacking(combat, card);
} else if (property.startsWith("kicked")) { } else if (property.startsWith("kicked")) {
if (property.equals("kicked")) { if (property.equals("kicked")) {
if (card.getKickerMagnitude() == 0) { if (card.getKickerMagnitude() == 0) {

View File

@@ -45,6 +45,7 @@ import forge.util.collect.FCollectionView;
import forge.util.maps.MapToAmount; import forge.util.maps.MapToAmount;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -82,6 +83,38 @@ public class CombatUtil {
return myViolations <= bestAttack.getRight().intValue(); return myViolations <= bestAttack.getRight().intValue();
} }
/**
* Check if attacker could attack without violating any constraints.
*/
public static boolean couldAttackButNotAttacking(Combat combat, final Card attacker) {
// If the player didn't declare attackers, combat here will be null
if (combat == null) {
combat = new Combat(attacker.getController());
} else if (combat.isAttacking(attacker)) {
return false;
}
final AttackConstraints constraints = combat.getAttackConstraints();
final Pair<Map<Card, GameEntity>, Integer> bestAttack = constraints.getLegalAttackers();
final Map<Card, GameEntity> attackers = new HashMap<>(combat.getAttackersAndDefenders());
final Game game = attacker.getGame();
return Iterables.any(getAllPossibleDefenders(attacker.getController()), new Predicate<GameEntity>() {
@Override
public boolean apply(final GameEntity defender) {
if (!canAttack(attacker, defender) || getAttackCost(game, attacker, defender) != null) {
return false;
}
attackers.put(attacker, defender);
final int myViolations = constraints.countViolations(attackers);
if (myViolations == -1) {
return false;
}
return myViolations <= bestAttack.getRight().intValue();
}
});
}
/** /**
* <p> * <p>
* Check whether a player should be given the chance to attack this combat. * Check whether a player should be given the chance to attack this combat.

View File

@@ -0,0 +1,13 @@
Name:Season of the Witch
ManaCost:B B B
Types:Enchantment
K:UpkeepCost:PayLife<2>
T:Mode$ Phase | Mode$ Phase | Phase$ Declare Attackers | Execute$ TrigMarkCouldAttack | Static$ True
SVar:TrigMarkCouldAttack:DB$ PumpAll | ValidCards$ Creature.couldAttackButNotAttacking | RememberAllPumped$ True
T:Mode$ Phase | Phase$ End of Turn | TriggerZones$ Battlefield | Execute$ TrigDestroyAll | TriggerDescription$ At the beginning of the end step, destroy all untapped creatures that didn't attack this turn, except for creatures that couldn't attack.
SVar:TrigDestroyAll:DB$ DestroyAll | ValidCards$ Creature.untapped+IsRemembered
T:Mode$ Phase | Phase$ Cleanup | Execute$ TrigCleanup | Static$ True
SVar:TrigCleanup:DB$ Cleanup | ClearRemembered$ True
SVar:NonStackingEffect:True
AI:RemoveDeck:Random
Oracle:At the beginning of your upkeep, sacrifice Season of the Witch unless you pay 2 life.\nAt the beginning of the end step, destroy all untapped creatures that didn't attack this turn, except for creatures that couldn't attack.