mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-16 10:48:00 +00:00
Merge branch 'refactor_fog_protection' into 'master'
Refactor Damage Prevention - Step 3 See merge request core-developers/forge!4680
This commit is contained in:
@@ -79,7 +79,7 @@ public class EffectAi extends SpellAbilityAi {
|
||||
if (!game.getStack().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
if (game.getPhaseHandler().isPreventCombatDamageThisTurn()) {
|
||||
if (game.getReplacementHandler().isPreventCombatDamageThisTurn()) {
|
||||
return false;
|
||||
}
|
||||
if (!ComputerUtilCombat.lifeInDanger(ai, game.getCombat())) {
|
||||
|
||||
@@ -29,7 +29,7 @@ public class FogAi extends SpellAbilityAi {
|
||||
final Card hostCard = sa.getHostCard();
|
||||
|
||||
// Don't cast it, if the effect is already in place
|
||||
if (game.getPhaseHandler().isPreventCombatDamageThisTurn()) {
|
||||
if (game.getReplacementHandler().isPreventCombatDamageThisTurn()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -480,7 +480,7 @@ public abstract class PumpAiBase extends SpellAbilityAi {
|
||||
}
|
||||
}); // leaves all creatures that will be destroyed
|
||||
} // -X/-X end
|
||||
else if (attack < 0 && !game.getPhaseHandler().isPreventCombatDamageThisTurn()) {
|
||||
else if (attack < 0 && !game.getReplacementHandler().isPreventCombatDamageThisTurn()) {
|
||||
// spells that give -X/0
|
||||
boolean isMyTurn = game.getPhaseHandler().isPlayerTurn(ai);
|
||||
if (isMyTurn) {
|
||||
|
||||
@@ -113,7 +113,7 @@ public class PumpAllAi extends PumpAiBase {
|
||||
if (phase.isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS)
|
||||
|| phase.isBefore(PhaseType.COMBAT_DECLARE_ATTACKERS)
|
||||
|| game.getPhaseHandler().isPlayerTurn(sa.getActivatingPlayer())
|
||||
|| game.getPhaseHandler().isPreventCombatDamageThisTurn()) {
|
||||
|| game.getReplacementHandler().isPreventCombatDamageThisTurn()) {
|
||||
return false;
|
||||
}
|
||||
int totalPower = 0;
|
||||
|
||||
@@ -187,9 +187,6 @@ public abstract class GameEntity extends GameObject implements IIdentifiable {
|
||||
restDamage = 0;
|
||||
}
|
||||
|
||||
// then apply static Damage Prevention effects
|
||||
restDamage = staticDamagePrevention(restDamage, source, isCombat, false);
|
||||
|
||||
// if damage is greater than restDamage, damage was prevented
|
||||
if (damage > restDamage) {
|
||||
int prevent = damage - restDamage;
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
package forge.game.ability.effects;
|
||||
|
||||
import forge.GameCommand;
|
||||
import forge.game.Game;
|
||||
import forge.game.ability.SpellAbilityEffect;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.replacement.ReplacementEffect;
|
||||
import forge.game.replacement.ReplacementHandler;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.trigger.TriggerType;
|
||||
import forge.game.zone.ZoneType;
|
||||
|
||||
public class FogEffect extends SpellAbilityEffect {
|
||||
|
||||
@@ -13,7 +20,28 @@ public class FogEffect extends SpellAbilityEffect {
|
||||
|
||||
@Override
|
||||
public void resolve(SpellAbility sa) {
|
||||
// Expand Fog keyword here depending on what we need out of it.
|
||||
sa.getActivatingPlayer().getGame().getPhaseHandler().setPreventCombatDamageThisTurn();
|
||||
final Card hostCard = sa.getHostCard();
|
||||
final Game game = hostCard.getGame();
|
||||
final String name = hostCard.getName() + "'s Effect";
|
||||
final String image = hostCard.getImageKey();
|
||||
StringBuilder sb = new StringBuilder("Event$ DamageDone | ActiveZones$ Command | IsCombat$ True");
|
||||
sb.append(" | Prevent$ True | Description$ Prevent all combat damage this turn.");
|
||||
String repeffstr = sb.toString();
|
||||
|
||||
final Card eff = createEffect(sa, hostCard.getController(), name, image);
|
||||
ReplacementEffect re = ReplacementHandler.parseReplacement(repeffstr, eff, true);
|
||||
eff.addReplacementEffect(re);
|
||||
eff.updateStateForView();
|
||||
|
||||
game.getTriggerHandler().suppressMode(TriggerType.ChangesZone);
|
||||
game.getAction().moveTo(ZoneType.Command, eff, sa);
|
||||
game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone);
|
||||
|
||||
game.getEndOfTurn().addUntil(new GameCommand() {
|
||||
@Override
|
||||
public void run() {
|
||||
game.getAction().exile(eff, null);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5212,7 +5212,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
||||
return damageIn;
|
||||
}
|
||||
|
||||
if (isCombat && getGame().getPhaseHandler().isPreventCombatDamageThisTurn()) {
|
||||
if (isCombat && getGame().getReplacementHandler().isPreventCombatDamageThisTurn()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -2228,6 +2228,59 @@ public class CardFactoryUtil {
|
||||
return re;
|
||||
}
|
||||
|
||||
// Create damage prevention replacement effect for protection keyword
|
||||
private static ReplacementEffect createProtectionReplacement(final CardState card, final String kw, final boolean intrinsic) {
|
||||
Card host = card.getCard();
|
||||
String validSource = "Card.";
|
||||
|
||||
if (kw.startsWith("Protection:")) {
|
||||
final String[] kws = kw.split(":");
|
||||
String characteristic = kws[1];
|
||||
if (characteristic.startsWith("Player")) {
|
||||
validSource += "ControlledBy " + characteristic;
|
||||
} else {
|
||||
if (characteristic.endsWith("White") || characteristic.endsWith("Blue")
|
||||
|| characteristic.endsWith("Black") || characteristic.endsWith("Red")
|
||||
|| characteristic.endsWith("Green") || characteristic.endsWith("Colorless")
|
||||
|| characteristic.endsWith("MonoColor") || characteristic.endsWith("MultiColor")) {
|
||||
characteristic += "Source";
|
||||
}
|
||||
validSource = characteristic;
|
||||
}
|
||||
} else if (kw.startsWith("Protection from ")) {
|
||||
String protectType = kw.substring("Protection from ".length());
|
||||
if (protectType.equals("white")) {
|
||||
validSource += "WhiteSource";
|
||||
} else if (protectType.equals("blue")) {
|
||||
validSource += "BlueSource";
|
||||
} else if (protectType.equals("black")) {
|
||||
validSource += "BlackSource";
|
||||
} else if (protectType.equals("red")) {
|
||||
validSource += "RedSource";
|
||||
} else if (protectType.equals("green")) {
|
||||
validSource += "GreenSource";
|
||||
} else if (protectType.equals("all colors")) {
|
||||
validSource += "nonColorless";
|
||||
} else if (protectType.equals("everything")) {
|
||||
validSource = "";
|
||||
} else if (protectType.startsWith("opponent of ")) {
|
||||
final String playerName = protectType.substring("opponent of ".length());
|
||||
validSource += "ControlledBy Player.OpponentOf PlayerNamed_" + playerName;
|
||||
} else {
|
||||
validSource = CardType.getSingularType(protectType);
|
||||
}
|
||||
}
|
||||
|
||||
String rep = "Event$ DamageDone | Prevent$ True | ActiveZones$ Battlefield | ValidTarget$ Card.Self";
|
||||
if (!validSource.isEmpty()) {
|
||||
rep += " | ValidSource$ " + validSource;
|
||||
}
|
||||
rep += " | Secondary$ True | TiedToKeyword$ " + kw + " | Description$ " + kw;
|
||||
|
||||
ReplacementEffect re = ReplacementHandler.parseReplacement(rep, host, intrinsic, card);
|
||||
return re;
|
||||
}
|
||||
|
||||
public static ReplacementEffect makeEtbCounter(final String kw, final CardState card, final boolean intrinsic)
|
||||
{
|
||||
String parse = kw;
|
||||
@@ -3915,6 +3968,10 @@ public class CardFactoryUtil {
|
||||
inst.addReplacement(re);
|
||||
}
|
||||
}
|
||||
else if (keyword.startsWith("Protection")) {
|
||||
ReplacementEffect re = createProtectionReplacement(card, keyword, intrinsic);
|
||||
inst.addReplacement(re);
|
||||
}
|
||||
|
||||
else if (keyword.startsWith("If CARDNAME would be put into a graveyard "
|
||||
+ "from anywhere, reveal CARDNAME and shuffle it into its owner's library instead.")) {
|
||||
|
||||
@@ -92,7 +92,6 @@ public class PhaseHandler implements java.io.Serializable {
|
||||
private int nUpkeepsThisGame = 0;
|
||||
private int nCombatsThisTurn = 0;
|
||||
private int nMain2sThisTurn = 0;
|
||||
private boolean bPreventCombatDamageThisTurn = false;
|
||||
private int planarDiceRolledthisTurn = 0;
|
||||
|
||||
private transient Player playerTurn = null;
|
||||
@@ -520,7 +519,6 @@ public class PhaseHandler implements java.io.Serializable {
|
||||
break;
|
||||
|
||||
case CLEANUP:
|
||||
bPreventCombatDamageThisTurn = false;
|
||||
if (!bRepeatCleanup) {
|
||||
// only call onCleanupPhase when Cleanup is not repeated
|
||||
game.onCleanupPhase();
|
||||
@@ -834,10 +832,6 @@ public class PhaseHandler implements java.io.Serializable {
|
||||
return noCost || blocker.getController().getController().payManaOptional(blocker, blockCost, fakeSA, "Pay cost to declare " + blocker + " a blocker. ", ManaPaymentPurpose.DeclareBlocker);
|
||||
}
|
||||
|
||||
public final boolean isPreventCombatDamageThisTurn() {
|
||||
return bPreventCombatDamageThisTurn;
|
||||
}
|
||||
|
||||
private Player handleNextTurn() {
|
||||
game.getStack().onNextTurn();
|
||||
// reset mustAttackEntity
|
||||
@@ -1222,10 +1216,6 @@ public class PhaseHandler implements java.io.Serializable {
|
||||
onPhaseBegin();
|
||||
}
|
||||
|
||||
public final void setPreventCombatDamageThisTurn() {
|
||||
bPreventCombatDamageThisTurn = true;
|
||||
}
|
||||
|
||||
public int getPlanarDiceRolledthisTurn() {
|
||||
return planarDiceRolledthisTurn;
|
||||
}
|
||||
|
||||
@@ -719,7 +719,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
return damage;
|
||||
}
|
||||
|
||||
if (isCombat && game.getPhaseHandler().isPreventCombatDamageThisTurn()) {
|
||||
if (isCombat && game.getReplacementHandler().isPreventCombatDamageThisTurn()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1195,7 +1195,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
|
||||
|
||||
public boolean hasProtectionFromDamage(final Card source) {
|
||||
return hasProtectionFrom(source, false, false);
|
||||
return hasProtectionFrom(source, false, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
package forge.game.player;
|
||||
|
||||
import forge.card.CardType;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.keyword.KeywordInterface;
|
||||
import forge.game.replacement.ReplacementEffect;
|
||||
import forge.game.replacement.ReplacementHandler;
|
||||
import forge.game.staticability.StaticAbility;
|
||||
|
||||
public class PlayerFactoryUtil {
|
||||
@@ -39,6 +42,58 @@ public class PlayerFactoryUtil {
|
||||
}
|
||||
|
||||
public static void addReplacementEffect(final KeywordInterface inst, Player player) {
|
||||
String keyword = inst.getOriginal();
|
||||
String effect = null;
|
||||
|
||||
if (keyword.startsWith("Protection")) {
|
||||
String validSource = "Card.";
|
||||
if (keyword.startsWith("Protection:")) {
|
||||
final String[] kws = keyword.split(":");
|
||||
String characteristic = kws[1];
|
||||
if (characteristic.startsWith("Player")) {
|
||||
validSource += "ControlledBy " + characteristic;
|
||||
} else {
|
||||
if (characteristic.endsWith("White") || characteristic.endsWith("Blue")
|
||||
|| characteristic.endsWith("Black") || characteristic.endsWith("Red")
|
||||
|| characteristic.endsWith("Green") || characteristic.endsWith("Colorless")
|
||||
|| characteristic.endsWith("MonoColor") || characteristic.endsWith("MultiColor")) {
|
||||
characteristic += "Source";
|
||||
}
|
||||
validSource = characteristic;
|
||||
}
|
||||
} else if (keyword.startsWith("Protection from ")) {
|
||||
String protectType = keyword.substring("Protection from ".length());
|
||||
if (protectType.equals("white")) {
|
||||
validSource += "WhiteSource";
|
||||
} else if (protectType.equals("blue")) {
|
||||
validSource += "BlueSource";
|
||||
} else if (protectType.equals("black")) {
|
||||
validSource += "BlackSource";
|
||||
} else if (protectType.equals("red")) {
|
||||
validSource += "RedSource";
|
||||
} else if (protectType.equals("green")) {
|
||||
validSource += "GreenSource";
|
||||
} else if (protectType.equals("all colors")) {
|
||||
validSource += "nonColorless";
|
||||
} else if (protectType.equals("everything")) {
|
||||
validSource = "";
|
||||
} else {
|
||||
validSource = CardType.getSingularType(protectType);
|
||||
}
|
||||
}
|
||||
|
||||
effect = "Event$ DamageDone | Prevent$ True | ActiveZones$ Command | ValidTarget$ You";
|
||||
if (!validSource.isEmpty()) {
|
||||
effect += " | ValidSource$ " + validSource;
|
||||
}
|
||||
effect += " | Secondary$ True | Description$ " + keyword;
|
||||
}
|
||||
|
||||
if (effect != null) {
|
||||
final Card card = player.getKeywordCard();
|
||||
ReplacementEffect re = ReplacementHandler.parseReplacement(effect, card, false, card.getCurrentState());
|
||||
inst.addReplacement(re);
|
||||
}
|
||||
}
|
||||
|
||||
public static void addSpellAbility(final KeywordInterface inst, Player player) {
|
||||
|
||||
@@ -482,4 +482,28 @@ public class ReplacementHandler {
|
||||
}
|
||||
return totalAmount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to check if combat damage is prevented this turn (fog effect)
|
||||
* @return true if there is some resolved fog effect
|
||||
*/
|
||||
public final boolean isPreventCombatDamageThisTurn() {
|
||||
final List<ReplacementEffect> list = Lists.newArrayList();
|
||||
game.forEachCardInGame(new Visitor<Card>() {
|
||||
@Override
|
||||
public boolean visit(Card c) {
|
||||
for (final ReplacementEffect re : c.getReplacementEffects()) {
|
||||
if (re.getMode() == ReplacementType.DamageDone
|
||||
&& re.getLayer() == ReplacementLayer.Other
|
||||
&& re.hasParam("Prevent") && re.getParam("Prevent").equals("True")
|
||||
&& re.hasParam("IsCombat") && re.getParam("IsCombat").equals("True")
|
||||
&& re.zonesCheck(game.getZoneOf(c))) {
|
||||
list.add(re);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
return !list.isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user