From 024b95853930345c68ce43c0a90af8c2d9fa14eb Mon Sep 17 00:00:00 2001 From: Hans Mackowiak Date: Sun, 10 Mar 2024 15:18:40 +0100 Subject: [PATCH] RadiationRework: use Trigger for InternalRadiation (#4799) * RadiationRework: use Trigger for InternalRadiation * InternalRadiationEffect: use GameAction::mill * Radiation: use Num Param instead of Add/Remove like Poison * Update bloatfly_swarm.txt * Player: fix removeRadiationEffect on setCounter --------- Co-authored-by: tool4ever --- .../src/main/java/forge/ai/SpellApiToAi.java | 1 + .../java/forge/game/GameLogFormatter.java | 3 +- .../main/java/forge/game/ability/ApiType.java | 4 +- .../effects/InternalRadiationEffect.java | 57 +++++++++++++ .../game/ability/effects/RadiationEffect.java | 24 ++---- .../game/event/GameEventPlayerRadiation.java | 5 +- .../java/forge/game/phase/PhaseHandler.java | 35 -------- .../main/java/forge/game/player/Player.java | 82 +++++++++++-------- .../StaticAbilityGainLifeRadiation.java | 33 ++++++++ .../res/cardsfolder/a/acquired_mutation.txt | 2 +- .../res/cardsfolder/b/bloatfly_swarm.txt | 2 +- .../res/cardsfolder/c/contaminated_drink.txt | 2 +- forge-gui/res/cardsfolder/f/feral_ghoul.txt | 2 +- .../cardsfolder/m/mariposa_military_base.txt | 2 +- .../res/cardsfolder/t/the_wise_mothman.txt | 2 +- .../cardsfolder/upcoming/mirelurk_queen.txt | 2 +- .../upcoming/nightkin_ambusher.txt | 2 +- .../cardsfolder/upcoming/nuclear_fallout.txt | 2 +- .../upcoming/nuka_nuke_launcher.txt | 2 +- .../upcoming/strong_the_brutish_thespian.txt | 10 +++ forge-gui/res/languages/en-US.properties | 2 +- 21 files changed, 173 insertions(+), 103 deletions(-) create mode 100644 forge-game/src/main/java/forge/game/ability/effects/InternalRadiationEffect.java create mode 100644 forge-game/src/main/java/forge/game/staticability/StaticAbilityGainLifeRadiation.java create mode 100644 forge-gui/res/cardsfolder/upcoming/strong_the_brutish_thespian.txt diff --git a/forge-ai/src/main/java/forge/ai/SpellApiToAi.java b/forge-ai/src/main/java/forge/ai/SpellApiToAi.java index d77c1083027..c2f1dc3422d 100644 --- a/forge-ai/src/main/java/forge/ai/SpellApiToAi.java +++ b/forge-ai/src/main/java/forge/ai/SpellApiToAi.java @@ -201,6 +201,7 @@ public enum SpellApiToAi { .put(ApiType.DamageResolve, AlwaysPlayAi.class) .put(ApiType.InternalLegendaryRule, LegendaryRuleAi.class) .put(ApiType.InternalIgnoreEffect, CannotPlayAi.class) + .put(ApiType.InternalRadiation, AlwaysPlayAi.class) .build()); public SpellAbilityAi get(final ApiType api) { diff --git a/forge-game/src/main/java/forge/game/GameLogFormatter.java b/forge-game/src/main/java/forge/game/GameLogFormatter.java index 45ddc33218f..faf9fe64314 100644 --- a/forge-game/src/main/java/forge/game/GameLogFormatter.java +++ b/forge-game/src/main/java/forge/game/GameLogFormatter.java @@ -235,8 +235,7 @@ public class GameLogFormatter extends IGameEventVisitor.Base { ev.receiver.toString(), Lang.nounWithNumeralExceptOne(String.valueOf(change), radCtr), ev.source.toString()); else message = localizer.getMessage("lblLogPlayerRadRemove", - ev.receiver.toString(), Lang.nounWithNumeralExceptOne(String.valueOf(Math.abs(change)), radCtr), - ev.source.toString()); + ev.receiver.toString(), Lang.nounWithNumeralExceptOne(String.valueOf(Math.abs(change)), radCtr)); return new GameLogEntry(GameLogEntryType.DAMAGE, message); } diff --git a/forge-game/src/main/java/forge/game/ability/ApiType.java b/forge-game/src/main/java/forge/game/ability/ApiType.java index 7358802d7f2..a3dd09aa720 100644 --- a/forge-game/src/main/java/forge/game/ability/ApiType.java +++ b/forge-game/src/main/java/forge/game/ability/ApiType.java @@ -204,7 +204,9 @@ public enum ApiType { DamageResolve (DamageResolveEffect.class), ChangeZoneResolve (ChangeZoneResolveEffect.class), InternalLegendaryRule (CharmEffect.class), - InternalIgnoreEffect (CharmEffect.class); + InternalIgnoreEffect (CharmEffect.class), + InternalRadiation (InternalRadiationEffect.class), + ; private final SpellAbilityEffect instanceEffect; private final Class clsEffect; diff --git a/forge-game/src/main/java/forge/game/ability/effects/InternalRadiationEffect.java b/forge-game/src/main/java/forge/game/ability/effects/InternalRadiationEffect.java new file mode 100644 index 00000000000..acd621049aa --- /dev/null +++ b/forge-game/src/main/java/forge/game/ability/effects/InternalRadiationEffect.java @@ -0,0 +1,57 @@ +package forge.game.ability.effects; + +import java.util.Map; + +import com.google.common.base.Predicates; +import com.google.common.collect.Maps; + +import forge.game.Game; +import forge.game.ability.AbilityKey; +import forge.game.ability.SpellAbilityEffect; +import forge.game.card.CardCollectionView; +import forge.game.card.CardLists; +import forge.game.card.CardPredicates; +import forge.game.card.CardZoneTable; +import forge.game.card.CounterEnumType; +import forge.game.player.Player; +import forge.game.player.PlayerCollection; +import forge.game.spellability.SpellAbility; +import forge.game.staticability.StaticAbilityGainLifeRadiation; +import forge.game.trigger.TriggerType; +import forge.game.zone.ZoneType; + +public class InternalRadiationEffect extends SpellAbilityEffect { + + @Override + public void resolve(SpellAbility sa) { + final Player p = sa.getActivatingPlayer(); + final Game game = p.getGame(); + + int numRad = p.getCounters(CounterEnumType.RAD); + + Map moveParams = AbilityKey.newMap(); + final CardZoneTable table = AbilityKey.addCardZoneTableParams(moveParams, sa); + + final CardCollectionView milled = game.getAction().mill(new PlayerCollection(p), numRad, ZoneType.Graveyard, sa, moveParams); + table.triggerChangesZoneAll(game, sa); + int n = CardLists.count(milled, Predicates.not(CardPredicates.Presets.LANDS)); + + if (StaticAbilityGainLifeRadiation.gainLifeRadiation(p)) { + p.gainLife(n, sa.getHostCard(), sa); + } else { + final Map lossMap = Maps.newHashMap(); + final int lost = p.loseLife(n, false, false); + if (lost > 0) { + lossMap.put(p, lost); + } + if (!lossMap.isEmpty()) { // Run triggers if any player actually lost life + final Map runParams = AbilityKey.mapFromPIMap(lossMap); + game.getTriggerHandler().runTrigger(TriggerType.LifeLostAll, runParams, false); + } + } + + // and remove n rad counter + p.removeRadCounters(n); + } + +} diff --git a/forge-game/src/main/java/forge/game/ability/effects/RadiationEffect.java b/forge-game/src/main/java/forge/game/ability/effects/RadiationEffect.java index e9aa8ad0e11..99f8d52cf38 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/RadiationEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/RadiationEffect.java @@ -1,43 +1,33 @@ package forge.game.ability.effects; -import com.google.common.collect.Maps; import forge.game.Game; import forge.game.GameEntityCounterTable; import forge.game.ability.AbilityUtils; import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; -import forge.game.card.CounterEnumType; -import forge.game.event.GameEventPlayerRadiation; import forge.game.player.Player; import forge.game.spellability.SpellAbility; -import java.util.Map; - public class RadiationEffect extends SpellAbilityEffect { @Override public void resolve(SpellAbility sa) { final Card host = sa.getHostCard(); + final Player player = sa.getActivatingPlayer(); final Game game = host.getGame(); - final int toAdd = AbilityUtils.calculateAmount(host, sa.getParamOrDefault("Add", "0"), sa); - final int toRem = AbilityUtils.calculateAmount(host, sa.getParamOrDefault("Remove", "0"), sa); - final Map list = Maps.newHashMap(); + final int num = AbilityUtils.calculateAmount(host, sa.getParamOrDefault("Num", "0"), sa); GameEntityCounterTable table = new GameEntityCounterTable(); for (final Player p : getTargetPlayers(sa)) { if (!p.isInGame()) continue; - list.put(p, p.getCounters(CounterEnumType.RAD)); - if (toAdd >= 1) p.addRadCounters(toAdd, host, table); - else if (toRem >= 1) p.removeRadCounters(toRem, host); + if (num >= 1) { + p.addRadCounters(num, player, table); + } else { + p.removeRadCounters(-num); + } } table.replaceCounterEffect(game, sa, true); - for (final Player p : list.keySet()) { - int oldCount = list.get(p); - int newCount = p.getCounters(CounterEnumType.RAD); - if (newCount > 0 && !p.hasRadiationEffect()) p.createRadiationEffect(host.getSetCode()); - if (oldCount < newCount) game.fireEvent(new GameEventPlayerRadiation(p, host, newCount - oldCount)); - } } } diff --git a/forge-game/src/main/java/forge/game/event/GameEventPlayerRadiation.java b/forge-game/src/main/java/forge/game/event/GameEventPlayerRadiation.java index c7fa6dd0938..b9214b15b63 100644 --- a/forge-game/src/main/java/forge/game/event/GameEventPlayerRadiation.java +++ b/forge-game/src/main/java/forge/game/event/GameEventPlayerRadiation.java @@ -1,14 +1,13 @@ package forge.game.event; -import forge.game.card.Card; import forge.game.player.Player; public class GameEventPlayerRadiation extends GameEvent { public final Player receiver; - public final Card source; + public final Player source; public final int change; - public GameEventPlayerRadiation(Player recv, Card src, int chng) { + public GameEventPlayerRadiation(Player recv, Player src, int chng) { receiver = recv; source = src; change = chng; diff --git a/forge-game/src/main/java/forge/game/phase/PhaseHandler.java b/forge-game/src/main/java/forge/game/phase/PhaseHandler.java index 57a3fa99f73..640c62f13b3 100644 --- a/forge-game/src/main/java/forge/game/phase/PhaseHandler.java +++ b/forge-game/src/main/java/forge/game/phase/PhaseHandler.java @@ -17,7 +17,6 @@ */ package forge.game.phase; -import com.google.common.base.Predicates; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Lists; import com.google.common.collect.Maps; @@ -43,8 +42,6 @@ import forge.game.trigger.TriggerType; import forge.game.zone.Zone; import forge.game.zone.ZoneType; import forge.util.CollectionSuppliers; -import forge.util.Lang; -import forge.util.Localizer; import forge.util.TextUtil; import forge.util.maps.HashMapOfLists; import forge.util.maps.MapOfLists; @@ -283,9 +280,6 @@ public class PhaseHandler implements java.io.Serializable { if (playerTurn.isArchenemy()) { playerTurn.setSchemeInMotion(null); } - if (playerTurn.hasRadiationEffect()) { - handleRadiation(); - } GameEntityCounterTable table = new GameEntityCounterTable(); // all Saga get Lore counter at the begin of pre combat for (Card c : playerTurn.getCardsIn(ZoneType.Battlefield)) { @@ -527,35 +521,6 @@ public class PhaseHandler implements java.io.Serializable { } } - private void handleRadiation() { - int numRad = playerTurn.getCounters(CounterEnumType.RAD); - if (numRad == 0) playerTurn.removeRadiationEffect(); - else { - final CardZoneTable table = new CardZoneTable(game.getLastStateBattlefield(), game.getLastStateGraveyard()); - Map moveParams = AbilityKey.newMap(); - AbilityKey.addCardZoneTableParams(moveParams, table); - - final SpellAbility sa = new SpellAbility.EmptySa(playerTurn.getRadiationEffect(), playerTurn); - final CardCollectionView milled = playerTurn.mill(numRad, ZoneType.Graveyard, sa, moveParams); - game.getAction().reveal(milled, playerTurn, false, - Localizer.getInstance().getMessage("lblMilledCards", playerTurn), false); - game.getGameLog().add(GameLogEntryType.ZONE_CHANGE, playerTurn + " milled " + - Lang.joinHomogenous(milled) + "."); - table.triggerChangesZoneAll(game, sa); - int n = CardLists.filter(milled, Predicates.not(CardPredicates.Presets.LANDS)).size(); - final Map lossMap = Maps.newHashMap(); - final int lost = playerTurn.loseLife(n, false, false); - if (lost > 0) { - lossMap.put(playerTurn, lost); - } - if (!lossMap.isEmpty()) { // Run triggers if any player actually lost life - final Map runParams = AbilityKey.mapFromPIMap(lossMap); - game.getTriggerHandler().runTrigger(TriggerType.LifeLostAll, runParams, false); - } - playerTurn.removeRadCounters(n, playerTurn.getRadiationEffect()); - } - } - private void declareAttackersTurnBasedAction() { final Player whoDeclares = playerDeclaresAttackers == null || playerDeclaresAttackers.hasLost() ? playerTurn diff --git a/forge-game/src/main/java/forge/game/player/Player.java b/forge-game/src/main/java/forge/game/player/Player.java index 039c9962239..c3fbf399c30 100644 --- a/forge-game/src/main/java/forge/game/player/Player.java +++ b/forge-game/src/main/java/forge/game/player/Player.java @@ -640,7 +640,7 @@ public class Player extends GameEntity implements Comparable { return -1; } cnt -= lostEnergy; - this.setCounters(CounterEnumType.ENERGY, cnt, true); + this.setCounters(CounterEnumType.ENERGY, cnt, null, true); return cnt; } @@ -863,7 +863,16 @@ public class Player extends GameEntity implements Comparable { final int oldValue = getCounters(counterType); final int newValue = addAmount + oldValue; - this.setCounters(counterType, newValue, fireEvents); + this.setCounters(counterType, newValue, source, fireEvents); + + if (counterType.is(CounterEnumType.RAD) && newValue > 0) { + String setCode = null; + if (params.containsKey(AbilityKey.Cause)) { + SpellAbility cause = (SpellAbility) params.get(AbilityKey.Cause); + setCode = cause.getHostCard().getSetCode(); + } + createRadiationEffect(setCode); + } final Map runParams = AbilityKey.mapFromPlayer(this); runParams.put(AbilityKey.Source, source); @@ -892,7 +901,7 @@ public class Player extends GameEntity implements Comparable { final int delta = oldValue - newValue; if (delta == 0) { return; } - setCounters(counterName, newValue, true); + setCounters(counterName, newValue, null, true); /* TODO Run triggers when something cares int curCounters = oldValue; @@ -913,16 +922,25 @@ public class Player extends GameEntity implements Comparable { getGame().fireEvent(new GameEventPlayerCounters(this, null, 0, 0)); } - public void setCounters(final CounterEnumType counterType, final Integer num, boolean fireEvents) { - this.setCounters(CounterType.get(counterType), num, fireEvents); + public void setCounters(final CounterEnumType counterType, final Integer num, Player source, boolean fireEvents) { + this.setCounters(CounterType.get(counterType), num, source, fireEvents); } - public void setCounters(final CounterType counterType, final Integer num, boolean fireEvents) { + public void setCounters(final CounterType counterType, final Integer num, Player source, boolean fireEvents) { Integer old = getCounters(counterType); setCounters(counterType, num); view.updateCounters(this); if (fireEvents) { getGame().fireEvent(new GameEventPlayerCounters(this, counterType, old, num)); + if (counterType.is(CounterEnumType.POISON)) { + getGame().fireEvent(new GameEventPlayerPoisoned(this, source, old, num - old)); + } else if (counterType.is(CounterEnumType.RAD)) { + getGame().fireEvent(new GameEventPlayerRadiation(this, source, num - old)); + } + } + + if (counterType.is(CounterEnumType.RAD) && num <= 0) { + removeRadiationEffect(); } } @@ -931,18 +949,20 @@ public class Player extends GameEntity implements Comparable { counters = allCounters; view.updateCounters(this); getGame().fireEvent(new GameEventPlayerCounters(this, null, 0, 0)); + + // create Radiation Effect for GameState + if (counters.getOrDefault(CounterType.get(CounterEnumType.RAD), 0) > 0) { + this.createRadiationEffect(null); + } else { + this.removeRadiationEffect(); + } } - public final void addRadCounters(final int num, final Card source, GameEntityCounterTable table) { - addCounter(CounterEnumType.RAD, num, source.getController(), table); + public final void addRadCounters(final int num, final Player source, GameEntityCounterTable table) { + addCounter(CounterEnumType.RAD, num, source, table); } - public final void removeRadCounters(final int num, final Card source) { - int oldRad = getCounters(CounterEnumType.RAD); - if (oldRad != 0) subtractCounter(CounterEnumType.RAD, num); - - int newRad = getCounters(CounterEnumType.RAD); - if (newRad == 0) removeRadiationEffect(); - if (oldRad != newRad) game.fireEvent(new GameEventPlayerRadiation(this, source, newRad - oldRad)); + public final void removeRadCounters(final int num) { + subtractCounter(CounterEnumType.RAD, num); } // TODO Merge These calls into the primary counter calls @@ -950,25 +970,13 @@ public class Player extends GameEntity implements Comparable { return getCounters(CounterEnumType.POISON); } public final void setPoisonCounters(final int num, Player source) { - int oldPoison = getCounters(CounterEnumType.POISON); - setCounters(CounterEnumType.POISON, num, true); - game.fireEvent(new GameEventPlayerPoisoned(this, source, oldPoison, num)); + setCounters(CounterEnumType.POISON, num, source, true); } public final void addPoisonCounters(final int num, final Player source, GameEntityCounterTable table) { - int oldPoison = getCounters(CounterEnumType.POISON); addCounter(CounterEnumType.POISON, num, source, table); - - if (oldPoison != getCounters(CounterEnumType.POISON)) { - game.fireEvent(new GameEventPlayerPoisoned(this, source, oldPoison, num)); - } } public final void removePoisonCounters(final int num, final Player source) { - int oldPoison = getCounters(CounterEnumType.POISON); subtractCounter(CounterEnumType.POISON, num); - - if (oldPoison != getCounters(CounterEnumType.POISON)) { - game.fireEvent(new GameEventPlayerPoisoned(this, source, oldPoison, num)); - } } // ================ POISON Merged ================================= public final void addChangedKeywords(final List addKeywords, final List removeKeywords, final Long timestamp, final long staticId) { @@ -3453,12 +3461,18 @@ public class Player extends GameEntity implements Comparable { radiationEffect.setImmutable(true); radiationEffect.setImageKey("t:radiation"); radiationEffect.setName("Radiation"); - radiationEffect.setSetCode(setCode); - String desc = "Mode$ Continuous | Affected$ Card.Self | Description$ At the beginning of your precombat " + - "main phase, if you have any rad counters, mill that many cards. For each nonland card milled " + - "this way, you lose 1 life and a rad counter."; - StaticAbility st = StaticAbility.create(desc, radiationEffect, radiationEffect.getCurrentState(), true); - radiationEffect.addStaticAbility(st); + if (setCode != null) { + radiationEffect.setSetCode(setCode); + } + + String trigStr = "Mode$ Phase | PreCombatMain$ True | ValidPlayer$ You | TriggerZones$ Command | TriggerDescription$ " + + "At the beginning of your precombat main phase, if you have any rad counters, mill that many cards. For each nonland card milled this way, you lose 1 life and a rad counter."; + + Trigger tr = TriggerHandler.parseTrigger(trigStr, radiationEffect, true); + SpellAbility sa = AbilityFactory.getAbility("DB$ InternalRadiation", radiationEffect); + tr.setOverridingAbility(sa); + + radiationEffect.addTrigger(tr); radiationEffect.updateStateForView(); } com.add(radiationEffect); diff --git a/forge-game/src/main/java/forge/game/staticability/StaticAbilityGainLifeRadiation.java b/forge-game/src/main/java/forge/game/staticability/StaticAbilityGainLifeRadiation.java new file mode 100644 index 00000000000..ed1e3c2c2cf --- /dev/null +++ b/forge-game/src/main/java/forge/game/staticability/StaticAbilityGainLifeRadiation.java @@ -0,0 +1,33 @@ +package forge.game.staticability; + +import forge.game.Game; +import forge.game.card.Card; +import forge.game.player.Player; +import forge.game.zone.ZoneType; + +public class StaticAbilityGainLifeRadiation { + static String MODE = "GainLifeRadiation"; + + static public boolean gainLifeRadiation(Player player) { + final Game game = player.getGame(); + for (final Card ca : game.getCardsIn(ZoneType.STATIC_ABILITIES_SOURCE_ZONES)) { + for (final StaticAbility stAb : ca.getStaticAbilities()) { + if (!stAb.checkConditions(MODE)) { + continue; + } + if (applyGainLifeRadiation(stAb, player)) { + return true; + } + } + } + return false; + } + + static public boolean applyGainLifeRadiation(StaticAbility stAb, Player player) { + if (!stAb.matchesValidParam("ValidPlayer", player)) { + return false; + } + return true; + } + +} diff --git a/forge-gui/res/cardsfolder/a/acquired_mutation.txt b/forge-gui/res/cardsfolder/a/acquired_mutation.txt index 301adc9d21c..b3cb265063a 100644 --- a/forge-gui/res/cardsfolder/a/acquired_mutation.txt +++ b/forge-gui/res/cardsfolder/a/acquired_mutation.txt @@ -5,5 +5,5 @@ K:Enchant creature A:SP$ Attach | ValidTgts$ Creature | AILogic$ Pump S:Mode$ Continuous | Affected$ Creature.EnchantedBy | AddPower$ 2 | AddToughness$ 2 | Goad$ True | Description$ Enchanted creature gets +2/+2 and is goaded. (It attacks each combat if able and attacks a player other than you if able.) T:Mode$ Attacks | ValidCard$ Creature.EnchantedBy | Execute$ TrigRadiation | TriggerDescription$ Whenever enchanted creature attacks, defending player gets two rad counters. -SVar:TrigRadiation:DB$ Radiation | Defined$ TriggeredDefendingPlayer | Add$ 2 +SVar:TrigRadiation:DB$ Radiation | Defined$ TriggeredDefendingPlayer | Num$ 2 Oracle:Enchant creature\nEnchanted creature gets +2/+2 and is goaded. (It attacks each combat if able and attacks a player other than you if able.)\nWhenever enchanted creature attacks, defending player gets two rad counters. diff --git a/forge-gui/res/cardsfolder/b/bloatfly_swarm.txt b/forge-gui/res/cardsfolder/b/bloatfly_swarm.txt index 51f9bcd4507..8a6b2e6e175 100644 --- a/forge-gui/res/cardsfolder/b/bloatfly_swarm.txt +++ b/forge-gui/res/cardsfolder/b/bloatfly_swarm.txt @@ -6,7 +6,7 @@ K:Flying K:etbCounter:P1P1:5 R:Event$ DamageDone | ActiveZones$ Battlefield | ValidTarget$ Card.Self+counters_GE1_P1P1 | ReplaceWith$ Counters | PreventionEffect$ True | AlwaysReplace$ True | Description$ If damage would be dealt to CARDNAME while it has a +1/+1 counter on it, prevent that damage, remove that many +1/+1 counters it, then give each player a rad counter for each +1/+1 counter removed this way. SVar:Counters:DB$ RemoveCounter | Defined$ ReplacedTarget | CounterType$ P1P1 | CounterNum$ Y | RememberRemoved$ True | SubAbility$ DBRadiation -SVar:DBRadiation:DB$ Radiation | Defined$ Player | Add$ Y +SVar:DBRadiation:DB$ Radiation | Defined$ Player | Num$ Y | SubAbility$ DBCleanup SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True SVar:Y:ReplaceCount$DamageAmount DeckHas:Ability$Counters diff --git a/forge-gui/res/cardsfolder/c/contaminated_drink.txt b/forge-gui/res/cardsfolder/c/contaminated_drink.txt index 56bc9fd38b7..443ae8f67f0 100644 --- a/forge-gui/res/cardsfolder/c/contaminated_drink.txt +++ b/forge-gui/res/cardsfolder/c/contaminated_drink.txt @@ -2,7 +2,7 @@ Name:Contaminated Drink ManaCost:X U B Types:Instant A:SP$ Draw | NumCards$ X | SubAbility$ DBRadiation | SpellDescription$ Draw X cards, then you get half X rad counters, rounded up. -SVar:DBRadiation:DB$ Radiation | Defined$ You | Add$ HalfXUp +SVar:DBRadiation:DB$ Radiation | Defined$ You | Num$ HalfXUp SVar:X:Count$xPaid SVar:HalfXUp:Count$xPaid/HalfUp Oracle:Draw X cards, then you get half X rad counters, rounded up. diff --git a/forge-gui/res/cardsfolder/f/feral_ghoul.txt b/forge-gui/res/cardsfolder/f/feral_ghoul.txt index a717a90e89e..75a93667915 100644 --- a/forge-gui/res/cardsfolder/f/feral_ghoul.txt +++ b/forge-gui/res/cardsfolder/f/feral_ghoul.txt @@ -6,7 +6,7 @@ K:Menace T:Mode$ ChangesZone | ValidCard$ Creature.Other+YouCtrl | Origin$ Battlefield | Destination$ Graveyard | TriggerZones$ Battlefield | Execute$ TrigPutCounter | TriggerDescription$ Whenever another creature you control dies, put a +1/+1 counter on CARDNAME. SVar:TrigPutCounter:DB$ PutCounter | CounterType$ P1P1 | CounterNum$ 1 T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigRadiation | TriggerDescription$ When CARDNAME dies, each opponent gets a number of rad counters equal to its power. -SVar:TrigRadiation:DB$ Radiation | Defined$ Opponent | Add$ TriggeredCard$CardPower +SVar:TrigRadiation:DB$ Radiation | Defined$ Opponent | Num$ TriggeredCard$CardPower DeckHas:Ability$Counters DeckHints:Ability$Sacrifice Oracle:Menace\nWhenever another creature you control dies, put a +1/+1 counter on Feral Ghoul.\nWhen Feral Ghoul dies, each opponent gets a number of rad counters equal to its power. diff --git a/forge-gui/res/cardsfolder/m/mariposa_military_base.txt b/forge-gui/res/cardsfolder/m/mariposa_military_base.txt index bd8473a0b65..082441e0851 100644 --- a/forge-gui/res/cardsfolder/m/mariposa_military_base.txt +++ b/forge-gui/res/cardsfolder/m/mariposa_military_base.txt @@ -3,7 +3,7 @@ ManaCost:no cost Types:Land K:ETBReplacement:Other:DBTap:Optional SVar:DBTap:DB$ Tap | ETB$ True | Defined$ Self | SubAbility$ DBRadiation | SpellDescription$ You may have CARDNAME enter the battlefield tapped. If you do, you get two rad counters. -SVar:DBRadiation:DB$ Radiation | Defined$ You | Add$ 2 +SVar:DBRadiation:DB$ Radiation | Defined$ You | Num$ 2 A:AB$ Mana | Cost$ T | Produced$ C | SpellDescription$ Add {C}. A:AB$ Draw | Cost$ 5 T | NumCards$ 1 | ReduceCost$ X | SpellDescription$ Draw a card. This ability costs {1} less to activate for each rad counter you have. SVar:X:Count$YourCountersRAD diff --git a/forge-gui/res/cardsfolder/t/the_wise_mothman.txt b/forge-gui/res/cardsfolder/t/the_wise_mothman.txt index bc40d9c3720..326a9300243 100644 --- a/forge-gui/res/cardsfolder/t/the_wise_mothman.txt +++ b/forge-gui/res/cardsfolder/t/the_wise_mothman.txt @@ -5,7 +5,7 @@ PT:3/3 K:Flying T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigRadiation | TriggerDescription$ Whenever CARDNAME enters the battlefield or attacks, each player gets a rad counter. T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigRadiation | TriggerZones$ Battlefield | Secondary$ True | TriggerDescription$ Whenever CARDNAME enters the battlefield attacks, each player gets a rad counter. -SVar:TrigRadiation:DB$ Radiation | Defined$ Player | Add$ 1 +SVar:TrigRadiation:DB$ Radiation | Defined$ Player | Num$ 1 T:Mode$ MilledAll | ValidPlayer$ Player | ValidCard$ Card.nonLand | TriggerZones$ Battlefield | Execute$ TrigPutCounter | TriggerDescription$ Whenever one or more nonland cards are milled, put a +1/+1 counter on each of up to X target creatures, where X is the number of nonland cards milled this way. SVar:TrigPutCounter:DB$ PutCounter | CounterNum$ 1 | CounterType$ P1P1 | TargetMin$ 0 | TargetMax$ TriggerCount$Amount | ValidTgts$ Creature | TgtPrompt$ Select up to X target creatures DeckHints:Ability$Mill diff --git a/forge-gui/res/cardsfolder/upcoming/mirelurk_queen.txt b/forge-gui/res/cardsfolder/upcoming/mirelurk_queen.txt index 1fbfffd80f3..c2b722fca62 100644 --- a/forge-gui/res/cardsfolder/upcoming/mirelurk_queen.txt +++ b/forge-gui/res/cardsfolder/upcoming/mirelurk_queen.txt @@ -4,7 +4,7 @@ Types:Creature Crab Mutant PT:4/4 K:Vigilance T:Mode$ ChangesZone | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigRadiation | TriggerDescription$ When CARDNAME enters the battlefield, target player gets two rad counters. -SVar:TrigRadiation:DB$ Radiation | ValidTgts$ Player | Add$ 2 +SVar:TrigRadiation:DB$ Radiation | ValidTgts$ Player | Num$ 2 T:Mode$ MilledAll | ValidPlayer$ Player | ValidCard$ Card.nonLand | TriggerZones$ Battlefield | Execute$ TrigDraw | ActivationLimit$ 1 | TriggerDescription$ Whenever one or more nonland cards are milled, draw a card, then put a +1/+1 counter on CARDNAME. This ability triggers only once each turn. SVar:TrigDraw:DB$ Draw | Defined$ You | NumCards$ 1 | SubAbility$ DBPutCounter SVar:DBPutCounter:DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ 1 diff --git a/forge-gui/res/cardsfolder/upcoming/nightkin_ambusher.txt b/forge-gui/res/cardsfolder/upcoming/nightkin_ambusher.txt index 370f9bdb826..9f7533be08e 100644 --- a/forge-gui/res/cardsfolder/upcoming/nightkin_ambusher.txt +++ b/forge-gui/res/cardsfolder/upcoming/nightkin_ambusher.txt @@ -4,6 +4,6 @@ Types:Creature Mutant Warrior PT:4/4 K:Ward:2 T:Mode$ ChangesZone | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigRadiation | TriggerDescription$ When CARDNAME enters the battlefield, target player gets four rad counters. -SVar:TrigRadiation:DB$ Radiation | ValidTgts$ Player | Add$ 4 +SVar:TrigRadiation:DB$ Radiation | ValidTgts$ Player | Num$ 4 S:Mode$ CantBlockBy | ValidAttacker$ Card.Self | ValidDefender$ Player.Condition Counters.RAD | Description$ CARDNAME can't be blocked as long as defending player has a rad counter. Oracle:Ward {2} (Whenever this creature becomes the target of a spell or ability an opponent controls, counter it unless that player pays {2}.)\nWhen Nightkin Ambusher enters the battlefield, target player gets four rad counters.\nNightkin Ambusher can’t be blocked as long as defending player has a rad counter. diff --git a/forge-gui/res/cardsfolder/upcoming/nuclear_fallout.txt b/forge-gui/res/cardsfolder/upcoming/nuclear_fallout.txt index d28a47f943a..cc0745b0114 100644 --- a/forge-gui/res/cardsfolder/upcoming/nuclear_fallout.txt +++ b/forge-gui/res/cardsfolder/upcoming/nuclear_fallout.txt @@ -2,7 +2,7 @@ Name:Nuclear Fallout ManaCost:X B B Types:Sorcery A:SP$ PumpAll | ValidCards$ Creature | NumAtt$ -Y | NumDef$ -Y | SubAbility$ DBRadiation | SpellDescription$ Each creature gets twice -X/-X until end of turn -SVar:DBRadiation:DB$ Radiation | Defined$ Player | Add$ X | SpellDescription$ Each player gets X rad counters. +SVar:DBRadiation:DB$ Radiation | Defined$ Player | Num$ X | SpellDescription$ Each player gets X rad counters. SVar:X:Count$xPaid SVar:Y:SVar$X/Twice Oracle:Each creature gets twice -X/-X until end of turn. Each player gets X rad counters. diff --git a/forge-gui/res/cardsfolder/upcoming/nuka_nuke_launcher.txt b/forge-gui/res/cardsfolder/upcoming/nuka_nuke_launcher.txt index 739ac67014f..3498cf0e1a9 100644 --- a/forge-gui/res/cardsfolder/upcoming/nuka_nuke_launcher.txt +++ b/forge-gui/res/cardsfolder/upcoming/nuka_nuke_launcher.txt @@ -5,6 +5,6 @@ S:Mode$ Continuous | Affected$ Creature.EquippedBy | AddPower$ 3 | AddKeyword$ I T:Mode$ Attacks | ValidCard$ Card.EquippedBy | Execute$ TrigEffect | TriggerDescription$ Whenever equipped creature attacks, until the end of defending player's next turn, that player gets two rad counters whenever they cast a spell. SVar:TrigEffect:DB$ Effect | Duration$ UntilTheEndOfYourNextTurn | Triggers$ CastTrig | EffectOwner$ TriggeredDefendingPlayer SVar:CastTrig:Mode$ SpellCast | ValidCard$ Card | ValidActivatingPlayer$ You | Execute$ TrigRadiation | TriggerDescription$ When you cast a spell, you get two rad counters -SVar:TrigRadiation:DB$ Radiation | Defined$ You | Add$ 2 +SVar:TrigRadiation:DB$ Radiation | Defined$ You | Num$ 2 K:Equip:3 Oracle:Equipped creature gets +3/+0 and has intimidate. (It can’t be blocked except by artifact creatures and/or creatures that share a color with it.)\nWhenever equipped creature attacks, until the end of defending player’s next turn, that player gets two rad counters whenever they cast a spell.\nEquip {3} diff --git a/forge-gui/res/cardsfolder/upcoming/strong_the_brutish_thespian.txt b/forge-gui/res/cardsfolder/upcoming/strong_the_brutish_thespian.txt new file mode 100644 index 00000000000..c5ddd56ee28 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/strong_the_brutish_thespian.txt @@ -0,0 +1,10 @@ +Name:Strong, the Brutish Thespian +ManaCost:4 G G +Types:Legendary Creature Mutant Berserker +PT:7/7 +K:Ward:2 +T:Mode$ DamageDoneOnce | Execute$ TrigDamage | ValidTarget$ Card.Self | TriggerZones$ Battlefield | TriggerDescription$ Enrage — Whenever NICKNAME is dealt damage, you get three rad counters and put three +1/+1 counters on NICKNAME. +SVar:TrigDamage:DB$ Radiation | Defined$ You | Num$ 3 | SubAbility$ DBP1P1 +SVar:DBP1P1:DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ 3 +S:Mode$ GainLifeRadiation | ValidPlayer$ You | Description$ You gain life rather than lose life from radiation. +Oracle:Ward {2}\nEnrage — Whenever Strong is dealt damage, you get three rad counters and put three +1/+1 counters on Strong.\nYou gain life rather than lose life from radiation. diff --git a/forge-gui/res/languages/en-US.properties b/forge-gui/res/languages/en-US.properties index 9f414a6833a..21b5e0585c5 100644 --- a/forge-gui/res/languages/en-US.properties +++ b/forge-gui/res/languages/en-US.properties @@ -1516,7 +1516,7 @@ lblNonCombat=non-combat lblLogSourceDealsNDamageOfTypeToDest={0} deals {1} {2} damage to {3}{4}. lblLogPlayerReceivesNPosionCounterFrom={0} receives {1} poison counter from {2} lblLogPlayerRadiation={0} gets {1} from {2}. -lblLogPlayerRadRemove={0} removes {1} due to {2}. +lblLogPlayerRadRemove={0} removes {1}. lblLogPlayerAssignedAttackerToAttackTarget={0} assigned {1} to attack {2}. lblLogPlayerDidntBlockAttacker={0} didn''t block {1}. lblLogPlayerAssignedBlockerToBlockAttacker={0} assigned {1} to block {2}.