Fix battles attacking/blocking (#7075)

* Add battle SBA

---------

Co-authored-by: tool4EvEr <tool4EvEr@192.168.0.59>
Co-authored-by: tool4EvEr <tool4EvEr@192.168.0.60>
This commit is contained in:
tool4ever
2025-02-24 16:03:58 +01:00
committed by GitHub
parent 0e46d436de
commit 0a15a0352d
6 changed files with 27 additions and 14 deletions

View File

@@ -1659,11 +1659,23 @@ public class GameAction {
private boolean stateBasedAction_Battle(Card c, CardCollection removeList) { private boolean stateBasedAction_Battle(Card c, CardCollection removeList) {
boolean checkAgain = false; boolean checkAgain = false;
if (!c.getType().isBattle()) { if (!c.isBattle()) {
return false; return checkAgain;
}
if (((c.getProtectingPlayer() == null || !c.getProtectingPlayer().isInGame()) &&
(game.getCombat() == null || game.getCombat().getAttackersOf(c).isEmpty())) ||
(c.getType().hasStringType("Siege") && c.getController().equals(c.getProtectingPlayer()))) {
Player newProtector = c.getController().getController().chooseSingleEntityForEffect(c.getController().getOpponents(), null, "Choose an opponent to protect this battle", null);
// seems unlikely unless range of influence gets implemented
if (newProtector == null) {
removeList.add(c);
} else {
c.setProtectingPlayer(newProtector);
}
checkAgain = true;
} }
if (c.getCounters(CounterEnumType.DEFENSE) > 0) { if (c.getCounters(CounterEnumType.DEFENSE) > 0) {
return false; return checkAgain;
} }
// 704.5v If a battle has defense 0 and it isn't the source of an ability that has triggered but not yet left the stack, // 704.5v If a battle has defense 0 and it isn't the source of an ability that has triggered but not yet left the stack,
// its put into its owners graveyard. // its put into its owners graveyard.

View File

@@ -519,14 +519,6 @@ public class CardFactoryUtil {
return filteredkw; return filteredkw;
} }
public static int getCardTypesFromList(final CardCollectionView list) {
EnumSet<CardType.CoreType> types = EnumSet.noneOf(CardType.CoreType.class);
for (Card c1 : list) {
c1.getType().getCoreTypes().forEach(types::add);
}
return types.size();
}
/** /**
* Adds the ability factory abilities. * Adds the ability factory abilities.
* *

View File

@@ -201,6 +201,10 @@ public class CombatUtil {
private static boolean canAttack(final Card attacker, final GameEntity defender, final boolean forNextTurn) { private static boolean canAttack(final Card attacker, final GameEntity defender, final boolean forNextTurn) {
final Game game = attacker.getGame(); final Game game = attacker.getGame();
if (attacker.isBattle()) {
return false;
}
// Basic checks (unless is for next turn) // Basic checks (unless is for next turn)
if (!forNextTurn && ( if (!forNextTurn && (
!attacker.isCreature() !attacker.isCreature()
@@ -480,6 +484,10 @@ public class CombatUtil {
return false; return false;
} }
if (blocker.isBattle()) {
return false;
}
if (!nextTurn && blocker.isTapped() && !blocker.hasKeyword("CARDNAME can block as though it were untapped.")) { if (!nextTurn && blocker.isTapped() && !blocker.hasKeyword("CARDNAME can block as though it were untapped.")) {
return false; return false;
} }

View File

@@ -222,7 +222,7 @@ public class CostExile extends CostPartWithList {
int amount = this.getAbilityAmount(ability); int amount = this.getAbilityAmount(ability);
if (nTypes > -1) { if (nTypes > -1) {
if (CardFactoryUtil.getCardTypesFromList(list) < nTypes) return false; if (AbilityUtils.countCardTypesFromList(list, false) < nTypes) return false;
} }
if (sharedType) { // will need more logic if cost ever wants more than 2 that share a type if (sharedType) { // will need more logic if cost ever wants more than 2 that share a type

View File

@@ -26,6 +26,7 @@ import forge.card.mana.ManaCostShard;
import forge.game.*; import forge.game.*;
import forge.game.ability.AbilityFactory; import forge.game.ability.AbilityFactory;
import forge.game.ability.AbilityKey; import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType; import forge.game.ability.ApiType;
import forge.game.ability.effects.DetachedCardEffect; import forge.game.ability.effects.DetachedCardEffect;
import forge.game.ability.effects.RollDiceEffect; import forge.game.ability.effects.RollDiceEffect;
@@ -2176,7 +2177,7 @@ public class Player extends GameEntity implements Comparable<Player> {
} }
public final boolean hasDelirium() { public final boolean hasDelirium() {
return CardFactoryUtil.getCardTypesFromList(getCardsIn(ZoneType.Graveyard)) >= 4; return AbilityUtils.countCardTypesFromList(getCardsIn(ZoneType.Graveyard), false) >= 4;
} }
public final boolean hasLandfall() { public final boolean hasLandfall() {

View File

@@ -303,7 +303,7 @@ public class HumanCostDecision extends CostDecisionMakerBase {
inp.setCancelAllowed(true); inp.setCancelAllowed(true);
inp.showAndWait(); inp.showAndWait();
if (inp.hasCancelled() || if (inp.hasCancelled() ||
!Expressions.compare(CardFactoryUtil.getCardTypesFromList(list), "GE", nTypes)) { !Expressions.compare(AbilityUtils.countCardTypesFromList(list, false), "GE", nTypes)) {
return null; return null;
} }
return PaymentDecision.card(inp.getSelected()); return PaymentDecision.card(inp.getSelected());