mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-19 04:08:01 +00:00
- Puzzle mode improvements: no triggers will now run when the game state is set up; triggers will run in combat if attackers are declared.
This commit is contained in:
@@ -1,6 +1,9 @@
|
|||||||
package forge.ai;
|
package forge.ai;
|
||||||
|
|
||||||
|
import com.google.common.collect.ArrayListMultimap;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
|
import com.google.common.collect.Multimap;
|
||||||
import forge.StaticData;
|
import forge.StaticData;
|
||||||
import forge.card.CardStateName;
|
import forge.card.CardStateName;
|
||||||
import forge.game.Game;
|
import forge.game.Game;
|
||||||
@@ -9,6 +12,9 @@ import forge.game.ability.AbilityFactory;
|
|||||||
import forge.game.ability.effects.DetachedCardEffect;
|
import forge.game.ability.effects.DetachedCardEffect;
|
||||||
import forge.game.card.*;
|
import forge.game.card.*;
|
||||||
import forge.game.combat.Combat;
|
import forge.game.combat.Combat;
|
||||||
|
import forge.game.combat.CombatUtil;
|
||||||
|
import forge.game.event.GameEventAttackersDeclared;
|
||||||
|
import forge.game.event.GameEventCombatChanged;
|
||||||
import forge.game.phase.PhaseType;
|
import forge.game.phase.PhaseType;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
import forge.game.spellability.SpellAbility;
|
import forge.game.spellability.SpellAbility;
|
||||||
@@ -432,9 +438,7 @@ public abstract class GameState {
|
|||||||
|
|
||||||
game.getPhaseHandler().devModeSet(newPhase, newPlayerTurn);
|
game.getPhaseHandler().devModeSet(newPhase, newPlayerTurn);
|
||||||
|
|
||||||
game.getTriggerHandler().suppressMode(TriggerType.ChangesZone);
|
game.getTriggerHandler().setSuppressAllTriggers(true);
|
||||||
game.getTriggerHandler().suppressMode(TriggerType.DamageDone);
|
|
||||||
game.getTriggerHandler().suppressMode(TriggerType.Unequip);
|
|
||||||
|
|
||||||
setupPlayerState(humanLife, humanCardTexts, human);
|
setupPlayerState(humanLife, humanCardTexts, human);
|
||||||
setupPlayerState(computerLife, aiCardTexts, ai);
|
setupPlayerState(computerLife, aiCardTexts, ai);
|
||||||
@@ -446,16 +450,15 @@ public abstract class GameState {
|
|||||||
handlePrecastSpells(game);
|
handlePrecastSpells(game);
|
||||||
handleMarkedDamage();
|
handleMarkedDamage();
|
||||||
|
|
||||||
|
game.getTriggerHandler().setSuppressAllTriggers(false);
|
||||||
|
|
||||||
// Combat only works for 1v1 matches for now (which are the only matches dev mode supports anyway)
|
// Combat only works for 1v1 matches for now (which are the only matches dev mode supports anyway)
|
||||||
|
// Note: triggers may fire during combat declarations ("whenever X attacks, ...", etc.)
|
||||||
if (newPhase == PhaseType.COMBAT_DECLARE_ATTACKERS || newPhase == PhaseType.COMBAT_DECLARE_BLOCKERS) {
|
if (newPhase == PhaseType.COMBAT_DECLARE_ATTACKERS || newPhase == PhaseType.COMBAT_DECLARE_BLOCKERS) {
|
||||||
boolean toDeclareBlockers = newPhase == PhaseType.COMBAT_DECLARE_BLOCKERS;
|
boolean toDeclareBlockers = newPhase == PhaseType.COMBAT_DECLARE_BLOCKERS;
|
||||||
handleCombat(game, newPlayerTurn, newPlayerTurn.getSingleOpponent(), toDeclareBlockers);
|
handleCombat(game, newPlayerTurn, newPlayerTurn.getSingleOpponent(), toDeclareBlockers);
|
||||||
}
|
}
|
||||||
|
|
||||||
game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone);
|
|
||||||
game.getTriggerHandler().clearSuppression(TriggerType.DamageDone);
|
|
||||||
game.getTriggerHandler().clearSuppression(TriggerType.Unequip);
|
|
||||||
|
|
||||||
game.getStack().setResolving(false);
|
game.getStack().setResolving(false);
|
||||||
|
|
||||||
game.getAction().checkStateEffects(true); //ensure state based effects and triggers are updated
|
game.getAction().checkStateEffects(true); //ensure state based effects and triggers are updated
|
||||||
@@ -471,17 +474,46 @@ public abstract class GameState {
|
|||||||
game.updateCombatForView();
|
game.updateCombatForView();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Combat combat = game.getPhaseHandler().getCombat();
|
||||||
for (Entry<Card, Card> attackMap : cardAttackMap.entrySet()) {
|
for (Entry<Card, Card> attackMap : cardAttackMap.entrySet()) {
|
||||||
Card attacker = attackMap.getKey();
|
Card attacker = attackMap.getKey();
|
||||||
Card attacked = attackMap.getValue();
|
Card attacked = attackMap.getValue();
|
||||||
|
|
||||||
game.getPhaseHandler().getCombat().addAttacker(attacker, attacked == null ? defendingPlayer : attacked);
|
combat.addAttacker(attacker, attacked == null ? defendingPlayer : attacked);
|
||||||
}
|
}
|
||||||
|
|
||||||
game.updateCombatForView();
|
// Run the necessary combat events and triggers to set things up correctly as if the
|
||||||
|
// attack was actually declared by the attacking player
|
||||||
|
Multimap<GameEntity, Card> attackersMap = ArrayListMultimap.create();
|
||||||
|
for (GameEntity ge : combat.getDefenders()) {
|
||||||
|
attackersMap.putAll(ge, combat.getAttackersOf(ge));
|
||||||
|
}
|
||||||
|
game.fireEvent(new GameEventAttackersDeclared(attackingPlayer, attackersMap));
|
||||||
|
|
||||||
// Gracefully proceed to Declare Blockers, giving priority to the defending player
|
if (!combat.getAttackers().isEmpty()) {
|
||||||
if (toDeclareBlockers) {
|
List<GameEntity> attackedTarget = Lists.newArrayList();
|
||||||
|
for (final Card c : combat.getAttackers()) {
|
||||||
|
attackedTarget.add(combat.getDefenderByAttacker(c));
|
||||||
|
}
|
||||||
|
final Map<String, Object> runParams = Maps.newHashMap();
|
||||||
|
runParams.put("Attackers", combat.getAttackers());
|
||||||
|
runParams.put("AttackingPlayer", combat.getAttackingPlayer());
|
||||||
|
runParams.put("AttackedTarget", attackedTarget);
|
||||||
|
game.getTriggerHandler().runTrigger(TriggerType.AttackersDeclared, runParams, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (final Card c : combat.getAttackers()) {
|
||||||
|
CombatUtil.checkDeclaredAttacker(game, c, combat);
|
||||||
|
}
|
||||||
|
|
||||||
|
game.getTriggerHandler().resetActiveTriggers();
|
||||||
|
game.updateCombatForView();
|
||||||
|
game.fireEvent(new GameEventCombatChanged());
|
||||||
|
|
||||||
|
// Gracefully proceed to Declare Blockers, giving priority to the defending player,
|
||||||
|
// but only if the stack is empty (otherwise the game will crash).
|
||||||
|
game.getStack().addAllTriggeredAbilitiesToStack();
|
||||||
|
if (toDeclareBlockers && game.getStack().isEmpty()) {
|
||||||
game.getPhaseHandler().devAdvanceToPhase(PhaseType.COMBAT_DECLARE_BLOCKERS);
|
game.getPhaseHandler().devAdvanceToPhase(PhaseType.COMBAT_DECLARE_BLOCKERS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -137,6 +137,16 @@ public class TriggerHandler {
|
|||||||
suppressedModes.add(mode);
|
suppressedModes.add(mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final void setSuppressAllTriggers(final boolean suppress) {
|
||||||
|
for (TriggerType t : TriggerType.values()) {
|
||||||
|
if (suppress) {
|
||||||
|
suppressMode(t);
|
||||||
|
} else {
|
||||||
|
clearSuppression(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public final void clearSuppression(final TriggerType mode) {
|
public final void clearSuppression(final TriggerType mode) {
|
||||||
suppressedModes.remove(mode);
|
suppressedModes.remove(mode);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user