- 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;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import forge.StaticData;
import forge.card.CardStateName;
import forge.game.Game;
@@ -9,6 +12,9 @@ import forge.game.ability.AbilityFactory;
import forge.game.ability.effects.DetachedCardEffect;
import forge.game.card.*;
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.player.Player;
import forge.game.spellability.SpellAbility;
@@ -432,9 +438,7 @@ public abstract class GameState {
game.getPhaseHandler().devModeSet(newPhase, newPlayerTurn);
game.getTriggerHandler().suppressMode(TriggerType.ChangesZone);
game.getTriggerHandler().suppressMode(TriggerType.DamageDone);
game.getTriggerHandler().suppressMode(TriggerType.Unequip);
game.getTriggerHandler().setSuppressAllTriggers(true);
setupPlayerState(humanLife, humanCardTexts, human);
setupPlayerState(computerLife, aiCardTexts, ai);
@@ -446,16 +450,15 @@ public abstract class GameState {
handlePrecastSpells(game);
handleMarkedDamage();
game.getTriggerHandler().setSuppressAllTriggers(false);
// 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) {
boolean toDeclareBlockers = newPhase == PhaseType.COMBAT_DECLARE_BLOCKERS;
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.getAction().checkStateEffects(true); //ensure state based effects and triggers are updated
@@ -471,17 +474,46 @@ public abstract class GameState {
game.updateCombatForView();
}
Combat combat = game.getPhaseHandler().getCombat();
for (Entry<Card, Card> attackMap : cardAttackMap.entrySet()) {
Card attacker = attackMap.getKey();
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 (toDeclareBlockers) {
if (!combat.getAttackers().isEmpty()) {
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);
}
}

View File

@@ -137,6 +137,16 @@ public class TriggerHandler {
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) {
suppressedModes.remove(mode);
}