mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-16 02:38:02 +00:00
DeclaresCombatants effect
This commit is contained in:
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -13977,6 +13977,7 @@ src/main/java/forge/card/ability/effects/DamagePreventAllEffect.java -text
|
|||||||
src/main/java/forge/card/ability/effects/DamagePreventEffect.java -text
|
src/main/java/forge/card/ability/effects/DamagePreventEffect.java -text
|
||||||
src/main/java/forge/card/ability/effects/DebuffAllEffect.java -text
|
src/main/java/forge/card/ability/effects/DebuffAllEffect.java -text
|
||||||
src/main/java/forge/card/ability/effects/DebuffEffect.java -text
|
src/main/java/forge/card/ability/effects/DebuffEffect.java -text
|
||||||
|
src/main/java/forge/card/ability/effects/DeclareCombatantsEffect.java -text
|
||||||
src/main/java/forge/card/ability/effects/DelayedTriggerEffect.java -text
|
src/main/java/forge/card/ability/effects/DelayedTriggerEffect.java -text
|
||||||
src/main/java/forge/card/ability/effects/DestroyAllEffect.java -text
|
src/main/java/forge/card/ability/effects/DestroyAllEffect.java -text
|
||||||
src/main/java/forge/card/ability/effects/DestroyEffect.java -text
|
src/main/java/forge/card/ability/effects/DestroyEffect.java -text
|
||||||
|
|||||||
@@ -138,6 +138,7 @@ public enum ApiType {
|
|||||||
DealDamage (DamageDealEffect.class, DamageDealAi.class),
|
DealDamage (DamageDealEffect.class, DamageDealAi.class),
|
||||||
Debuff (DebuffEffect.class, DebuffAi.class),
|
Debuff (DebuffEffect.class, DebuffAi.class),
|
||||||
DebuffAll (DebuffAllEffect.class, DebuffAllAi.class),
|
DebuffAll (DebuffAllEffect.class, DebuffAllAi.class),
|
||||||
|
DeclaresCombatants(DeclareCombatantsEffect.class, CannotPlayAi.class),
|
||||||
DelayedTrigger (DelayedTriggerEffect.class, DelayedTriggerAi.class),
|
DelayedTrigger (DelayedTriggerEffect.class, DelayedTriggerAi.class),
|
||||||
Destroy (DestroyEffect.class, DestroyAi.class),
|
Destroy (DestroyEffect.class, DestroyAi.class),
|
||||||
DestroyAll (DestroyAllEffect.class, DestroyAllAi.class),
|
DestroyAll (DestroyAllEffect.class, DestroyAllAi.class),
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package forge.card.ability.effects;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import forge.card.ability.SpellAbilityEffect;
|
||||||
|
import forge.card.spellability.SpellAbility;
|
||||||
|
import forge.game.phase.PhaseHandler;
|
||||||
|
import forge.game.player.Player;
|
||||||
|
import forge.util.Lang;
|
||||||
|
|
||||||
|
public class DeclareCombatantsEffect extends SpellAbilityEffect {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getStackDescription(SpellAbility sa) {
|
||||||
|
List<Player> tgtPlayers = getDefinedPlayersBeforeTargetOnes(sa);
|
||||||
|
|
||||||
|
boolean attackers = sa.hasParam("DeclareAttackers");
|
||||||
|
final String attDesc = "which creatures attack";
|
||||||
|
|
||||||
|
boolean blockers = sa.hasParam("DeclareBlockers");
|
||||||
|
final String defDesc = "which creatures block this turn and how those creatures block";
|
||||||
|
|
||||||
|
String what = Lang.joinHomogenous(attackers ? attDesc : null, blockers ? defDesc : null);
|
||||||
|
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return Lang.joinHomogenous(tgtPlayers) + " " + Lang.joinVerb(tgtPlayers, "choose") + " " + what + " this turn.";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void resolve(SpellAbility sa) {
|
||||||
|
List<Player> tgtPlayers = getDefinedPlayersBeforeTargetOnes(sa);
|
||||||
|
|
||||||
|
boolean attackers = sa.hasParam("DeclareAttackers");
|
||||||
|
boolean blockers = sa.hasParam("DeclareBlockers");
|
||||||
|
|
||||||
|
for(Player p : tgtPlayers) { // Obviuosly the last player will be applied
|
||||||
|
final PhaseHandler ph = p.getGame().getPhaseHandler();
|
||||||
|
if( attackers ) ph.setPlayerDeclaresAttackers(p);
|
||||||
|
if( blockers ) ph.setPlayerDeclaresBlockers(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -800,16 +800,17 @@ public class AiController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void declateBlockers() {
|
public void declateBlockers(Player defender) {
|
||||||
final List<Card> blockers = player.getCreaturesInPlay();
|
final List<Card> blockers = defender.getCreaturesInPlay();
|
||||||
game.setCombat(ComputerUtilBlock.getBlockers(player, game.getCombat(), blockers));
|
// When player != defender, AI should declare blockers for its benefit.
|
||||||
|
game.setCombat(ComputerUtilBlock.getBlockers(defender, game.getCombat(), blockers));
|
||||||
CombatUtil.orderMultipleCombatants(game.getCombat());
|
CombatUtil.orderMultipleCombatants(game.getCombat());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void declareAttackers() {
|
public void declareAttackers(Player attacker) {
|
||||||
// 12/2/10(sol) the decision making here has moved to getAttackers()
|
// 12/2/10(sol) the decision making here has moved to getAttackers()
|
||||||
game.setCombat(new AiAttackController(player, player.getOpponent()).getAttackers());
|
game.setCombat(new AiAttackController(attacker, attacker.getOpponent()).getAttackers());
|
||||||
|
|
||||||
for (final Card element : game.getCombat().getAttackers()) {
|
for (final Card element : game.getCombat().getAttackers()) {
|
||||||
// tapping of attackers happens after Propaganda is paid for
|
// tapping of attackers happens after Propaganda is paid for
|
||||||
@@ -818,7 +819,7 @@ public class AiController {
|
|||||||
Log.debug(sb.toString());
|
Log.debug(sb.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
player.getZone(ZoneType.Battlefield).updateObservers();
|
attacker.getZone(ZoneType.Battlefield).updateObservers();
|
||||||
|
|
||||||
// ai is about to attack, cancel all phase skipping
|
// ai is about to attack, cancel all phase skipping
|
||||||
for (Player p : game.getPlayers()) {
|
for (Player p : game.getPlayers()) {
|
||||||
|
|||||||
@@ -93,6 +93,9 @@ public class PhaseHandler implements java.io.Serializable {
|
|||||||
private Player pFirstPriority = null;
|
private Player pFirstPriority = null;
|
||||||
private boolean bCombat = false;
|
private boolean bCombat = false;
|
||||||
private boolean bRepeatCleanup = false;
|
private boolean bRepeatCleanup = false;
|
||||||
|
|
||||||
|
private Player playerDeclaresBlockers = null;
|
||||||
|
private Player playerDeclaresAttackers = null;
|
||||||
|
|
||||||
/** The need to next phase. */
|
/** The need to next phase. */
|
||||||
private boolean givePriorityToPlayer = false;
|
private boolean givePriorityToPlayer = false;
|
||||||
@@ -211,11 +214,7 @@ public class PhaseHandler implements java.io.Serializable {
|
|||||||
if (this.phase == PhaseType.UNTAP) {
|
if (this.phase == PhaseType.UNTAP) {
|
||||||
this.turn++;
|
this.turn++;
|
||||||
game.fireEvent(new GameEventTurnBegan(playerTurn, turn));
|
game.fireEvent(new GameEventTurnBegan(playerTurn, turn));
|
||||||
}
|
|
||||||
|
|
||||||
game.fireEvent(new GameEventTurnPhase(this.getPlayerTurn(), this.getPhase(), phaseType));
|
|
||||||
|
|
||||||
if (this.phase == PhaseType.UNTAP) {
|
|
||||||
// Here's what happens on new turn, regardless of skipped phases
|
// Here's what happens on new turn, regardless of skipped phases
|
||||||
game.getCombat().reset(playerTurn);
|
game.getCombat().reset(playerTurn);
|
||||||
|
|
||||||
@@ -232,8 +231,13 @@ public class PhaseHandler implements java.io.Serializable {
|
|||||||
|
|
||||||
final List<Card> lands = CardLists.filter(playerTurn.getLandsInPlay(), Presets.UNTAPPED);
|
final List<Card> lands = CardLists.filter(playerTurn.getLandsInPlay(), Presets.UNTAPPED);
|
||||||
playerTurn.setNumPowerSurgeLands(lands.size());
|
playerTurn.setNumPowerSurgeLands(lands.size());
|
||||||
|
|
||||||
|
// reset players controlling attack or defense
|
||||||
|
playerDeclaresAttackers = null;
|
||||||
|
playerDeclaresBlockers = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
game.fireEvent(new GameEventTurnPhase(this.getPlayerTurn(), this.getPhase(), phaseType));
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isSkippingPhase(PhaseType phase) {
|
private boolean isSkippingPhase(PhaseType phase) {
|
||||||
@@ -465,11 +469,11 @@ public class PhaseHandler implements java.io.Serializable {
|
|||||||
break;
|
break;
|
||||||
default: // no action
|
default: // no action
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void declateAttackTurnBasedActions() {
|
private void declateAttackTurnBasedActions() {
|
||||||
playerTurn.getController().declareAttackers();
|
Player whoDeclares = playerDeclaresAttackers == null || playerDeclaresAttackers.hasLost() ? playerTurn : playerDeclaresAttackers;
|
||||||
|
whoDeclares.getController().declareAttackers(playerTurn);
|
||||||
|
|
||||||
game.getCombat().removeAbsentCombatants();
|
game.getCombat().removeAbsentCombatants();
|
||||||
CombatUtil.checkAttackOrBlockAlone(game.getCombat());
|
CombatUtil.checkAttackOrBlockAlone(game.getCombat());
|
||||||
@@ -520,12 +524,14 @@ public class PhaseHandler implements java.io.Serializable {
|
|||||||
|
|
||||||
private void declareBlockersTurnBaseActions() {
|
private void declareBlockersTurnBaseActions() {
|
||||||
final Combat combat = game.getCombat();
|
final Combat combat = game.getCombat();
|
||||||
|
|
||||||
Player p = playerTurn;
|
Player p = playerTurn;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
p = game.getNextPlayerAfter(p);
|
p = game.getNextPlayerAfter(p);
|
||||||
|
// Apply Odric's effect here
|
||||||
|
Player whoDeclaresBlockers = playerDeclaresBlockers == null || playerDeclaresBlockers.hasLost() ? p : playerDeclaresBlockers;
|
||||||
if ( combat.isPlayerAttacked(p) )
|
if ( combat.isPlayerAttacked(p) )
|
||||||
p.getController().declareBlockers();
|
whoDeclaresBlockers.getController().declareBlockers(p);
|
||||||
} while(p != playerTurn);
|
} while(p != playerTurn);
|
||||||
|
|
||||||
combat.removeAbsentCombatants();
|
combat.removeAbsentCombatants();
|
||||||
@@ -936,4 +942,16 @@ public class PhaseHandler implements java.io.Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public final void setPlayerDeclaresBlockers(Player player) {
|
||||||
|
this.playerDeclaresBlockers = player;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public final void setPlayerDeclaresAttackers(Player player) {
|
||||||
|
this.playerDeclaresAttackers = player;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -135,8 +135,8 @@ public abstract class PlayerController {
|
|||||||
public abstract boolean confirmReplacementEffect(ReplacementEffect replacementEffect, SpellAbility effectSA, String question);
|
public abstract boolean confirmReplacementEffect(ReplacementEffect replacementEffect, SpellAbility effectSA, String question);
|
||||||
public abstract List<Card> getCardsToMulligan(boolean isCommander, Player firstPlayer);
|
public abstract List<Card> getCardsToMulligan(boolean isCommander, Player firstPlayer);
|
||||||
|
|
||||||
public abstract void declareAttackers();
|
public abstract void declareAttackers(Player attacker);
|
||||||
public abstract void declareBlockers();
|
public abstract void declareBlockers(Player defender);
|
||||||
public abstract void takePriority();
|
public abstract void takePriority();
|
||||||
|
|
||||||
public abstract List<Card> chooseCardsToDiscardToMaximumHandSize(int numDiscard);
|
public abstract List<Card> chooseCardsToDiscardToMaximumHandSize(int numDiscard);
|
||||||
|
|||||||
@@ -287,14 +287,14 @@ public class PlayerControllerAi extends PlayerController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void declareAttackers() {
|
public void declareAttackers(Player attacker) {
|
||||||
brains.declareAttackers();
|
brains.declareAttackers(attacker);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void declareBlockers() {
|
public void declareBlockers(Player defender) {
|
||||||
brains.declateBlockers();
|
brains.declateBlockers(defender);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -470,17 +470,17 @@ public class PlayerControllerHuman extends PlayerController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void declareAttackers() {
|
public void declareAttackers(Player attacker) {
|
||||||
game.getCombat().initiatePossibleDefenders(player.getOpponents());
|
game.getCombat().initiatePossibleDefenders(attacker.getOpponents());
|
||||||
// This input should not modify combat object itself, but should return user choice
|
// This input should not modify combat object itself, but should return user choice
|
||||||
InputSynchronized inpAttack = new InputAttack(player, game.getCombat());
|
InputSynchronized inpAttack = new InputAttack(player, game.getCombat());
|
||||||
Singletons.getControl().getInputQueue().setInputAndWait(inpAttack);
|
Singletons.getControl().getInputQueue().setInputAndWait(inpAttack);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void declareBlockers() {
|
public void declareBlockers(Player defender) {
|
||||||
// This input should not modify combat object itself, but should return user choice
|
// This input should not modify combat object itself, but should return user choice
|
||||||
InputSynchronized inpBlock = new InputBlock(player, game.getCombat());
|
InputSynchronized inpBlock = new InputBlock(player, defender, game.getCombat());
|
||||||
Singletons.getControl().getInputQueue().setInputAndWait(inpBlock);
|
Singletons.getControl().getInputQueue().setInputAndWait(inpBlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,14 +43,16 @@ public class InputBlock extends InputSyncronizedBase {
|
|||||||
private Card currentAttacker = null;
|
private Card currentAttacker = null;
|
||||||
private final HashMap<Card, List<Card>> allBlocking = new HashMap<Card, List<Card>>();
|
private final HashMap<Card, List<Card>> allBlocking = new HashMap<Card, List<Card>>();
|
||||||
private final Combat combat;
|
private final Combat combat;
|
||||||
private final Player player;
|
private final Player defender;
|
||||||
|
private final Player declarer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO: Write javadoc for Constructor.
|
* TODO: Write javadoc for Constructor.
|
||||||
* @param priority
|
* @param priority
|
||||||
*/
|
*/
|
||||||
public InputBlock(Player human, Combat combat) {
|
public InputBlock(Player whoDeclares, Player whoDefends, Combat combat) {
|
||||||
player = human;
|
defender = whoDefends;
|
||||||
|
declarer = whoDeclares;
|
||||||
this.combat = combat;
|
this.combat = combat;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,8 +65,11 @@ public class InputBlock extends InputSyncronizedBase {
|
|||||||
protected final void showMessage() {
|
protected final void showMessage() {
|
||||||
// could add "Reset Blockers" button
|
// could add "Reset Blockers" button
|
||||||
ButtonUtil.enableOnlyOk();
|
ButtonUtil.enableOnlyOk();
|
||||||
final StringBuilder sb = new StringBuilder();
|
|
||||||
sb.append(player.getName() + ", declare blockers.\n\n");
|
String prompt = declarer == defender ? "declare blockers." : "declare blockers for " + defender.getName();
|
||||||
|
|
||||||
|
final StringBuilder sb = new StringBuilder(declarer.getName());
|
||||||
|
sb.append(", ").append(prompt).append("\n\n");
|
||||||
|
|
||||||
if (this.currentAttacker == null) {
|
if (this.currentAttacker == null) {
|
||||||
sb.append("To Block, click on your opponent's attacker first, then your blocker(s).\n");
|
sb.append("To Block, click on your opponent's attacker first, then your blocker(s).\n");
|
||||||
@@ -84,7 +89,7 @@ public class InputBlock extends InputSyncronizedBase {
|
|||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
@Override
|
@Override
|
||||||
public final void onOk() {
|
public final void onOk() {
|
||||||
if (CombatUtil.finishedMandatoryBlocks(combat, player)) {
|
if (CombatUtil.finishedMandatoryBlocks(combat, defender)) {
|
||||||
// Done blocking
|
// Done blocking
|
||||||
ButtonUtil.reset();
|
ButtonUtil.reset();
|
||||||
CombatUtil.orderMultipleCombatants(combat);
|
CombatUtil.orderMultipleCombatants(combat);
|
||||||
@@ -100,7 +105,7 @@ public class InputBlock extends InputSyncronizedBase {
|
|||||||
public final void onCardSelected(final Card card, boolean isMetaDown) {
|
public final void onCardSelected(final Card card, boolean isMetaDown) {
|
||||||
|
|
||||||
if (isMetaDown) {
|
if (isMetaDown) {
|
||||||
if (card.getController() == player ) {
|
if (card.getController() == defender ) {
|
||||||
combat.removeFromCombat(card);
|
combat.removeFromCombat(card);
|
||||||
}
|
}
|
||||||
removeFromAllBlocking(card);
|
removeFromAllBlocking(card);
|
||||||
@@ -116,7 +121,7 @@ public class InputBlock extends InputSyncronizedBase {
|
|||||||
reminder = false;
|
reminder = false;
|
||||||
} else {
|
} else {
|
||||||
// Make sure this card is valid to even be a blocker
|
// Make sure this card is valid to even be a blocker
|
||||||
if (this.currentAttacker != null && card.isCreature() && player.getZone(ZoneType.Battlefield).contains(card)) {
|
if (this.currentAttacker != null && card.isCreature() && defender.getZone(ZoneType.Battlefield).contains(card)) {
|
||||||
// Create a new blockedBy list if it doesn't exist
|
// Create a new blockedBy list if it doesn't exist
|
||||||
if (!this.allBlocking.containsKey(card)) {
|
if (!this.allBlocking.containsKey(card)) {
|
||||||
this.allBlocking.put(card, new ArrayList<Card>());
|
this.allBlocking.put(card, new ArrayList<Card>());
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package forge.util;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import com.google.common.base.Function;
|
import com.google.common.base.Function;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -28,6 +30,12 @@ public class Lang {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static <T> String joinHomogenous(String s1, String s2) {
|
||||||
|
boolean has1 = StringUtils.isNotBlank(s1);
|
||||||
|
boolean has2 = StringUtils.isNotBlank(s2);
|
||||||
|
return has1 ? (has2 ? s1 + " and " + s2 : s1) : (has2 ? s2 : "");
|
||||||
|
}
|
||||||
|
|
||||||
public static <T> String joinHomogenous(Collection<T> objects) { return joinHomogenous(objects, null); }
|
public static <T> String joinHomogenous(Collection<T> objects) { return joinHomogenous(objects, null); }
|
||||||
public static <T> String joinHomogenous(Collection<T> objects, Function<T, String> accessor) {
|
public static <T> String joinHomogenous(Collection<T> objects, Function<T, String> accessor) {
|
||||||
int remaining = objects.size();
|
int remaining = objects.size();
|
||||||
|
|||||||
Reference in New Issue
Block a user