From 4862071db75bf30a94cc27a82e2e98ff430494b9 Mon Sep 17 00:00:00 2001 From: Hans Mackowiak Date: Sat, 7 Sep 2024 16:19:57 +0200 Subject: [PATCH] Keyword: link StaticAbility into it (#6079) * Keyword: link StaticAbility into it * fix getKeywordMagnitude to check for StaticAbility --- .../main/java/forge/ai/ComputerUtilCard.java | 4 +- .../main/java/forge/game/CardTraitBase.java | 3 ++ .../src/main/java/forge/game/GameAction.java | 10 ++--- .../ability/effects/AnimateEffectBase.java | 2 +- .../ability/effects/ChangeZoneEffect.java | 2 +- .../game/ability/effects/CloneEffect.java | 2 +- .../ability/effects/ControlGainEffect.java | 2 +- .../game/ability/effects/DebuffEffect.java | 2 +- .../ability/effects/ProtectAllEffect.java | 2 +- .../game/ability/effects/ProtectEffect.java | 2 +- .../game/ability/effects/PumpAllEffect.java | 2 +- .../game/ability/effects/PumpEffect.java | 2 +- .../game/ability/effects/TokenEffectBase.java | 2 +- .../src/main/java/forge/game/card/Card.java | 44 +++++++++++-------- .../forge/game/keyword/KeywordInstance.java | 12 ++--- .../forge/game/keyword/KeywordInterface.java | 6 ++- .../forge/game/spellability/SpellAbility.java | 11 +++-- .../StaticAbilityContinuous.java | 2 +- .../res/cardsfolder/f/fumiko_the_lowblood.txt | 4 +- 19 files changed, 66 insertions(+), 50 deletions(-) diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtilCard.java b/forge-ai/src/main/java/forge/ai/ComputerUtilCard.java index 4f80defc430..9035cd85adf 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtilCard.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtilCard.java @@ -1759,7 +1759,7 @@ public class ComputerUtilCard { pumped.addPTBoost(power + berserkPower, toughness, timestamp, 0); if (!kws.isEmpty()) { - pumped.addChangedCardKeywords(kws, null, false, timestamp, 0, false); + pumped.addChangedCardKeywords(kws, null, false, timestamp, null, false); } if (!hiddenKws.isEmpty()) { pumped.addHiddenExtrinsicKeywords(timestamp, 0, hiddenKws); @@ -1780,7 +1780,7 @@ public class ComputerUtilCard { } } final long timestamp2 = c.getGame().getNextTimestamp(); //is this necessary or can the timestamp be re-used? - pumped.addChangedCardKeywordsInternal(toCopy, null, false, timestamp2, 0, false); + pumped.addChangedCardKeywordsInternal(toCopy, null, false, timestamp2, null, false); pumped.updateKeywordsCache(pumped.getCurrentState()); applyStaticContPT(ai.getGame(), pumped, new CardCollection(c)); return pumped; diff --git a/forge-game/src/main/java/forge/game/CardTraitBase.java b/forge-game/src/main/java/forge/game/CardTraitBase.java index 36d9206bc36..958e04dc31d 100644 --- a/forge-game/src/main/java/forge/game/CardTraitBase.java +++ b/forge-game/src/main/java/forge/game/CardTraitBase.java @@ -567,6 +567,9 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView, } protected IHasSVars getSVarFallback() { + if (this.getKeyword() != null && this.getKeyword().getStatic() != null) { + return this.getKeyword().getStatic(); + } if (getCardState() != null) return getCardState(); return getHostCard(); diff --git a/forge-game/src/main/java/forge/game/GameAction.java b/forge-game/src/main/java/forge/game/GameAction.java index e28cf5572ca..473f86c0985 100644 --- a/forge-game/src/main/java/forge/game/GameAction.java +++ b/forge-game/src/main/java/forge/game/GameAction.java @@ -485,17 +485,17 @@ public class GameAction { if (c.getCastSA() != null && !c.getCastSA().isIntrinsic() && c.getCastSA().getKeyword() != null) { KeywordInterface ki = c.getCastSA().getKeyword(); ki.setHostCard(copied); - copied.addChangedCardKeywordsInternal(ImmutableList.of(ki), null, false, copied.getGameTimestamp(), 0, true); + copied.addChangedCardKeywordsInternal(ImmutableList.of(ki), null, false, copied.getGameTimestamp(), null, true); } // TODO hot fix for non-intrinsic offspring - Multimap addKw = MultimapBuilder.hashKeys().arrayListValues().build(); + Multimap addKw = MultimapBuilder.hashKeys().arrayListValues().build(); for (KeywordInterface kw : c.getKeywords(Keyword.OFFSPRING)) { if (!kw.isIntrinsic()) { - addKw.put(kw.getStaticId(), kw); + addKw.put(kw.getStatic(), kw); } } if (!addKw.isEmpty()) { - for (Map.Entry> e : addKw.asMap().entrySet()) { + for (Map.Entry> e : addKw.asMap().entrySet()) { copied.addChangedCardKeywordsInternal(e.getValue(), null, false, copied.getGameTimestamp(), e.getKey(), true); } } @@ -601,7 +601,7 @@ public class GameAction { // 400.7g try adding keyword back into card if it doesn't already have it if (zoneTo.is(ZoneType.Stack) && cause != null && cause.isSpell() && !cause.isIntrinsic() && c.equals(cause.getHostCard())) { if (cause.getKeyword() != null && !copied.getKeywords().contains(cause.getKeyword())) { - copied.addChangedCardKeywordsInternal(ImmutableList.of(cause.getKeyword()), null, false, game.getNextTimestamp(), 0, true); + copied.addChangedCardKeywordsInternal(ImmutableList.of(cause.getKeyword()), null, false, game.getNextTimestamp(), null, true); } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/AnimateEffectBase.java b/forge-game/src/main/java/forge/game/ability/effects/AnimateEffectBase.java index 2bd45869040..02c685f628f 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/AnimateEffectBase.java +++ b/forge-game/src/main/java/forge/game/ability/effects/AnimateEffectBase.java @@ -126,7 +126,7 @@ public abstract class AnimateEffectBase extends SpellAbilityEffect { params.put("Category", "Keywords"); c.addPerpetual(params); } - c.addChangedCardKeywords(keywords, removeKeywords, removeAll, timestamp, 0); + c.addChangedCardKeywords(keywords, removeKeywords, removeAll, timestamp, null); } // do this after changing types in case it wasn't a creature before diff --git a/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java index be89e9d11c5..8d19b7bbeb4 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java @@ -672,7 +672,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect { if (sa.hasParam("Unearth") && movedCard.isInPlay()) { movedCard.setUnearthed(true); movedCard.addChangedCardKeywords(Lists.newArrayList("Haste"), null, false, - game.getNextTimestamp(), 0, true); + game.getNextTimestamp(), null, true); registerDelayedTrigger(sa, "Exile", Lists.newArrayList(movedCard)); addLeaveBattlefieldReplacement(movedCard, sa, "Exile"); } diff --git a/forge-game/src/main/java/forge/game/ability/effects/CloneEffect.java b/forge-game/src/main/java/forge/game/ability/effects/CloneEffect.java index dcf15da41da..f811834cf00 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/CloneEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/CloneEffect.java @@ -151,7 +151,7 @@ public class CloneEffect extends SpellAbilityEffect { } if (!pumpKeywords.isEmpty()) { - tgtCard.addChangedCardKeywords(pumpKeywords, Lists.newArrayList(), false, ts, 0); + tgtCard.addChangedCardKeywords(pumpKeywords, Lists.newArrayList(), false, ts, null); TokenEffectBase.addPumpUntil(sa, tgtCard, ts); } diff --git a/forge-game/src/main/java/forge/game/ability/effects/ControlGainEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ControlGainEffect.java index 42e9d573111..219fde3d177 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ControlGainEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ControlGainEffect.java @@ -174,7 +174,7 @@ public class ControlGainEffect extends SpellAbilityEffect { } if (keywords != null) { - tgtC.addChangedCardKeywords(keywords, Lists.newArrayList(), false, tStamp, 0); + tgtC.addChangedCardKeywords(keywords, Lists.newArrayList(), false, tStamp, null); game.fireEvent(new GameEventCardStatsChanged(tgtC)); } diff --git a/forge-game/src/main/java/forge/game/ability/effects/DebuffEffect.java b/forge-game/src/main/java/forge/game/ability/effects/DebuffEffect.java index 186774e5cc5..8fa6a875df5 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/DebuffEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/DebuffEffect.java @@ -150,7 +150,7 @@ public class DebuffEffect extends SpellAbilityEffect { } removedKW.addAll(kws); - tgtC.addChangedCardKeywords(addedKW, removedKW, false, timestamp, 0); + tgtC.addChangedCardKeywords(addedKW, removedKW, false, timestamp, null); if (!"Permanent".equals(sa.getParam("Duration"))) { final GameCommand until = new GameCommand() { diff --git a/forge-game/src/main/java/forge/game/ability/effects/ProtectAllEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ProtectAllEffect.java index e342dd64834..5f7700b86ff 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ProtectAllEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ProtectAllEffect.java @@ -86,7 +86,7 @@ public class ProtectAllEffect extends SpellAbilityEffect { CardCollectionView list = CardLists.getValidCards(game.getCardsIn(ZoneType.Battlefield), valid, sa.getActivatingPlayer(), host, sa); for (final Card tgtC : list) { - tgtC.addChangedCardKeywords(gainsKWList, null, false, timestamp, 0, true); + tgtC.addChangedCardKeywords(gainsKWList, null, false, timestamp, null, true); if (!"Permanent".equals(sa.getParam("Duration"))) { // If not Permanent, remove protection at EOT diff --git a/forge-game/src/main/java/forge/game/ability/effects/ProtectEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ProtectEffect.java index 5f71cb24246..10235488e75 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ProtectEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ProtectEffect.java @@ -153,7 +153,7 @@ public class ProtectEffect extends SpellAbilityEffect { continue; } - tgtC.addChangedCardKeywords(gainsKWList, null, false, timestamp, 0, true); + tgtC.addChangedCardKeywords(gainsKWList, null, false, timestamp, null, true); if (!"Permanent".equals(sa.getParam("Duration"))) { // If not Permanent, remove protection at EOT diff --git a/forge-game/src/main/java/forge/game/ability/effects/PumpAllEffect.java b/forge-game/src/main/java/forge/game/ability/effects/PumpAllEffect.java index 46a029edeaf..28df9b4a6cb 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/PumpAllEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/PumpAllEffect.java @@ -68,7 +68,7 @@ public class PumpAllEffect extends SpellAbilityEffect { params.put("Category", "Keywords"); tgtC.addPerpetual(params); } - tgtC.addChangedCardKeywords(kws, null, false, timestamp, 0); + tgtC.addChangedCardKeywords(kws, null, false, timestamp, null); } if (redrawPT) { tgtC.updatePowerToughnessForView(); diff --git a/forge-game/src/main/java/forge/game/ability/effects/PumpEffect.java b/forge-game/src/main/java/forge/game/ability/effects/PumpEffect.java index 2e305e87dec..c8982425fc7 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/PumpEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/PumpEffect.java @@ -81,7 +81,7 @@ public class PumpEffect extends SpellAbilityEffect { params.put("Category", "Keywords"); gameCard.addPerpetual(params); } - gameCard.addChangedCardKeywords(kws, Lists.newArrayList(), false, timestamp, 0); + gameCard.addChangedCardKeywords(kws, Lists.newArrayList(), false, timestamp, null); } if (!hiddenKws.isEmpty()) { diff --git a/forge-game/src/main/java/forge/game/ability/effects/TokenEffectBase.java b/forge-game/src/main/java/forge/game/ability/effects/TokenEffectBase.java index 71cf31a43d9..52bd14f6216 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/TokenEffectBase.java +++ b/forge-game/src/main/java/forge/game/ability/effects/TokenEffectBase.java @@ -177,7 +177,7 @@ public abstract class TokenEffectBase extends SpellAbilityEffect { } if (!pumpKeywords.isEmpty()) { - moved.addChangedCardKeywords(pumpKeywords, Lists.newArrayList(), false, timestamp, 0); + moved.addChangedCardKeywords(pumpKeywords, Lists.newArrayList(), false, timestamp, null); addPumpUntil(sa, moved, timestamp); } diff --git a/forge-game/src/main/java/forge/game/card/Card.java b/forge-game/src/main/java/forge/game/card/Card.java index 313e39561a1..16abe732e94 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -1696,7 +1696,7 @@ public class Card extends GameEntity implements Comparable, IHasSVars, ITr if (!Keyword.smartValueOf(counterType.toString().split(":")[0]).isMultipleRedundant()) { num = getCounters(counterType); } - addChangedCardKeywords(Collections.nCopies(num, counterType.toString()), null, false, timestamp, 0, updateView); + addChangedCardKeywords(Collections.nCopies(num, counterType.toString()), null, false, timestamp, null, updateView); return true; } @@ -4657,7 +4657,7 @@ public class Card extends GameEntity implements Comparable, IHasSVars, ITr } else if (category.equals("Keywords")) { boolean removeAll = p.containsKey("RemoveAll") && (boolean) p.get("RemoveAll") == true; addChangedCardKeywords((List) p.get("AddKeywords"), Lists.newArrayList(), removeAll, - (long) p.get("Timestamp"), (long) 0); + (long) p.get("Timestamp"), null); } else if (category.equals("Types")) { addChangedCardTypes((CardType) p.get("AddTypes"), (CardType) p.get("RemoveTypes"), false, (Set) p.get("RemoveXTypes"), @@ -4963,7 +4963,7 @@ public class Card extends GameEntity implements Comparable, IHasSVars, ITr KeywordInterface result = storedKeywordByText.get(triple); if (result == null) { result = ki.copy(this, false); - result.setStaticId(stAb.getId()); + result.setStatic(stAb); result.setIdx(idx); result.setIntrinsic(true); storedKeywordByText.put(triple, result); @@ -5086,11 +5086,11 @@ public class Card extends GameEntity implements Comparable, IHasSVars, ITr } public final void addChangedCardKeywords(final List keywords, final List removeKeywords, - final boolean removeAllKeywords, final long timestamp, final long staticId) { - addChangedCardKeywords(keywords, removeKeywords, removeAllKeywords, timestamp, staticId, true); + final boolean removeAllKeywords, final long timestamp, final StaticAbility st) { + addChangedCardKeywords(keywords, removeKeywords, removeAllKeywords, timestamp, st, true); } public final void addChangedCardKeywords(final List keywords, final List removeKeywords, - final boolean removeAllKeywords, final long timestamp, final long staticId, final boolean updateView) { + final boolean removeAllKeywords, final long timestamp, final StaticAbility st, final boolean updateView) { List kws = Lists.newArrayList(); if (keywords != null) { long idx = 1; @@ -5104,14 +5104,14 @@ public class Card extends GameEntity implements Comparable, IHasSVars, ITr } } if (canHave) { - kws.add(getKeywordForStaticAbility(kw, staticId, idx)); + kws.add(getKeywordForStaticAbility(kw, st, idx)); } idx++; } } final KeywordsChange newCks = new KeywordsChange(kws, removeKeywords, removeAllKeywords); - changedCardKeywords.put(timestamp, staticId, newCks); + changedCardKeywords.put(timestamp, st == null ? 0l : st.getId(), newCks); if (updateView) { updateKeywords(); @@ -5120,12 +5120,13 @@ public class Card extends GameEntity implements Comparable, IHasSVars, ITr } } - public final KeywordInterface getKeywordForStaticAbility(String kw, final long staticId, final long idx) { + public final KeywordInterface getKeywordForStaticAbility(String kw, final StaticAbility st, final long idx) { KeywordInterface result; + long staticId = st == null ? 0 : st.getId(); Triple triple = Triple.of(kw, staticId, idx); if (staticId < 1 || !storedKeywords.containsKey(triple)) { result = Keyword.getInstance(kw); - result.setStaticId(staticId); + result.setStatic(st); result.setIdx(idx); result.createTraits(this, false); if (staticId > 0) { @@ -5138,8 +5139,8 @@ public class Card extends GameEntity implements Comparable, IHasSVars, ITr } public final void addKeywordForStaticAbility(KeywordInterface kw) { - if (kw.getStaticId() > 0) { - storedKeywords.put(Triple.of(kw.getOriginal(), kw.getStaticId(), kw.getIdx()), kw); + if (kw.getStatic() != null) { + storedKeywords.put(Triple.of(kw.getOriginal(), (long)kw.getStatic().getId(), kw.getIdx()), kw); } } @@ -5184,8 +5185,9 @@ public class Card extends GameEntity implements Comparable, IHasSVars, ITr public final void addChangedCardKeywordsInternal( final Collection keywords, final Collection removeKeywords, final boolean removeAllKeywords, - final long timestamp, final long staticId, final boolean updateView) { + final long timestamp, final StaticAbility st, final boolean updateView) { final KeywordsChange newCks = new KeywordsChange(keywords, removeKeywords, removeAllKeywords); + long staticId = st == null ? 0 : st.getId(); changedCardKeywords.put(timestamp, staticId, newCks); if (updateView) { @@ -5821,9 +5823,15 @@ public class Card extends GameEntity implements Comparable, IHasSVars, ITr if (StringUtils.isNumeric(s)) { count += Integer.parseInt(s); } else { - String svar = StringUtils.join(parse); - if (state.hasSVar(svar)) { - count += AbilityUtils.calculateAmount(this, state.getSVar(svar), null); + StaticAbility st = inst.getStatic(); + // TODO make keywordinterface inherit from CardTrait somehow, or invent new interface + if (st != null && st.hasSVar(s)) { + count += AbilityUtils.calculateAmount(this, st.getSVar(s), null); + } else { + String svar = StringUtils.join(parse); + if (state.hasSVar(svar)) { + count += AbilityUtils.calculateAmount(this, state.getSVar(svar), null); + } } } } @@ -6568,7 +6576,7 @@ public class Card extends GameEntity implements Comparable, IHasSVars, ITr suspectedTimestamp = getGame().getNextTimestamp(); // use this for CantHaveKeyword - addChangedCardKeywords(ImmutableList.of("Menace"), ImmutableList.of(), false, suspectedTimestamp, 0, true); + addChangedCardKeywords(ImmutableList.of("Menace"), ImmutableList.of(), false, suspectedTimestamp, null, true); if (suspectedStatic == null) { String effect = "Mode$ CantBlockBy | ValidBlocker$ Creature.Self | Description$ CARDNAME can't block."; @@ -6719,7 +6727,7 @@ public class Card extends GameEntity implements Comparable, IHasSVars, ITr new CardType(Collections.singletonList("Creature"), true), false, EnumSet.of(RemoveType.EnchantmentTypes), bestowTimestamp, 0, updateView, false); addChangedCardKeywords(Collections.singletonList("Enchant creature"), Lists.newArrayList(), - false, bestowTimestamp, 0, updateView); + false, bestowTimestamp, null, updateView); } public final void unanimateBestow() { diff --git a/forge-game/src/main/java/forge/game/keyword/KeywordInstance.java b/forge-game/src/main/java/forge/game/keyword/KeywordInstance.java index ddf50034acc..659f6c8c221 100644 --- a/forge-game/src/main/java/forge/game/keyword/KeywordInstance.java +++ b/forge-game/src/main/java/forge/game/keyword/KeywordInstance.java @@ -25,7 +25,7 @@ public abstract class KeywordInstance> implements K private Keyword keyword; private String original; - private long staticId = 0; + private StaticAbility st = null; private long idx = -1; private List triggers = Lists.newArrayList(); @@ -366,12 +366,12 @@ public abstract class KeywordInstance> implements K sa.setIntrinsic(value); } } - - public long getStaticId() { - return this.staticId; + + public StaticAbility getStatic() { + return this.st; } - public void setStaticId(long v) { - this.staticId = v; + public void setStatic(StaticAbility st) { + this.st = st; } public long getIdx() { diff --git a/forge-game/src/main/java/forge/game/keyword/KeywordInterface.java b/forge-game/src/main/java/forge/game/keyword/KeywordInterface.java index 2143903e42f..f2352a7129c 100644 --- a/forge-game/src/main/java/forge/game/keyword/KeywordInterface.java +++ b/forge-game/src/main/java/forge/game/keyword/KeywordInterface.java @@ -23,8 +23,10 @@ public interface KeywordInterface extends Cloneable { String getReminderText(); int getAmount(); - long getStaticId(); - void setStaticId(long v); + + StaticAbility getStatic(); + void setStatic(StaticAbility st); + long getIdx(); void setIdx(long i); diff --git a/forge-game/src/main/java/forge/game/spellability/SpellAbility.java b/forge-game/src/main/java/forge/game/spellability/SpellAbility.java index 2031a3f7a92..3fd91a5f9b5 100644 --- a/forge-game/src/main/java/forge/game/spellability/SpellAbility.java +++ b/forge-game/src/main/java/forge/game/spellability/SpellAbility.java @@ -705,7 +705,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit mana.getSourceCard().getController(), mana.getSourceCard(), null)) { final long timestamp = host.getGame().getNextTimestamp(); final List kws = Arrays.asList(mana.getAddedKeywords().split(" & ")); - host.addChangedCardKeywords(kws, null, false, timestamp, 0); + host.addChangedCardKeywords(kws, null, false, timestamp, null); if (mana.addsKeywordsUntil()) { final GameCommand untilEOT = new GameCommand() { private static final long serialVersionUID = -8285169579025607693L; @@ -2590,7 +2590,8 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit } public boolean hasOptionalKeywordAmount(KeywordInterface kw) { - return this.optionalKeywordAmount.contains(kw.getKeyword(), Pair.of(kw.getIdx(), kw.getStaticId())); + long staticId = kw.getStatic() == null ? 0 : kw.getStatic().getId(); + return this.optionalKeywordAmount.contains(kw.getKeyword(), Pair.of(kw.getIdx(), staticId)); } public boolean hasOptionalKeywordAmount(Keyword kw) { return this.optionalKeywordAmount.containsRow(kw); @@ -2600,13 +2601,15 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit } public int getOptionalKeywordAmount(KeywordInterface kw) { - return ObjectUtils.firstNonNull(this.optionalKeywordAmount.get(kw.getKeyword(), Pair.of(kw.getIdx(), kw.getStaticId())), 0); + long staticId = kw.getStatic() == null ? 0 : kw.getStatic().getId(); + return ObjectUtils.firstNonNull(this.optionalKeywordAmount.get(kw.getKeyword(), Pair.of(kw.getIdx(), staticId)), 0); } public int getOptionalKeywordAmount(Keyword kw) { return this.optionalKeywordAmount.row(kw).values().stream().mapToInt(i->i).sum(); } public void setOptionalKeywordAmount(KeywordInterface kw, int amount) { - this.optionalKeywordAmount.put(kw.getKeyword(), Pair.of(kw.getIdx(), kw.getStaticId()), amount); + long staticId = kw.getStatic() == null ? 0 : kw.getStatic().getId(); + this.optionalKeywordAmount.put(kw.getKeyword(), Pair.of(kw.getIdx(), staticId), amount); } public void clearOptionalKeywordAmount() { optionalKeywordAmount.clear(); diff --git a/forge-game/src/main/java/forge/game/staticability/StaticAbilityContinuous.java b/forge-game/src/main/java/forge/game/staticability/StaticAbilityContinuous.java index 6d14171d2af..2a323934c65 100644 --- a/forge-game/src/main/java/forge/game/staticability/StaticAbilityContinuous.java +++ b/forge-game/src/main/java/forge/game/staticability/StaticAbilityContinuous.java @@ -770,7 +770,7 @@ public final class StaticAbilityContinuous { } affectedCard.addChangedCardKeywords(newKeywords, removeKeywords, - removeAllAbilities, se.getTimestamp(), stAb.getId(), true); + removeAllAbilities, se.getTimestamp(), stAb, true); } // add HIDDEN keywords diff --git a/forge-gui/res/cardsfolder/f/fumiko_the_lowblood.txt b/forge-gui/res/cardsfolder/f/fumiko_the_lowblood.txt index 8c803c8c690..9357ef692d8 100644 --- a/forge-gui/res/cardsfolder/f/fumiko_the_lowblood.txt +++ b/forge-gui/res/cardsfolder/f/fumiko_the_lowblood.txt @@ -2,7 +2,7 @@ Name:Fumiko the Lowblood ManaCost:2 R R Types:Legendary Creature Human Samurai PT:3/2 -S:Mode$ Continuous | Affected$ Card.Self | AddKeyword$ Bushido:N | CalcKeywordN$ N | Description$ CARDNAME has bushido X, where X is the number of attacking creatures. -SVar:N:Count$Valid Creature.attacking +S:Mode$ Continuous | Affected$ Card.Self | AddKeyword$ Bushido:X | Description$ CARDNAME has bushido X, where X is the number of attacking creatures. +SVar:X:Count$Valid Creature.attacking S:Mode$ MustAttack | ValidCreature$ Creature.OppCtrl | Description$ Creatures your opponents control attack each combat if able. Oracle:Fumiko the Lowblood has bushido X, where X is the number of attacking creatures. (Whenever this creature blocks or becomes blocked, it gets +X/+X until end of turn.)\nCreatures your opponents control attack each combat if able.