- 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:
Agetian
2017-08-08 04:07:18 +00:00
parent b57ecea305
commit 174d1f7838
2 changed files with 53 additions and 11 deletions

View File

@@ -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);
} }
} }

View File

@@ -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);
} }