mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-17 11:18:01 +00:00
Merge branch 'season_of_the_witch' into 'master'
Add Season of the Witch See merge request core-developers/forge!4173
This commit is contained in:
@@ -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();
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
13
forge-gui/res/cardsfolder/s/season_of_the_witch.txt
Normal file
13
forge-gui/res/cardsfolder/s/season_of_the_witch.txt
Normal 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.
|
||||||
Reference in New Issue
Block a user