Keyword: link StaticAbility into it (#6079)

* Keyword: link StaticAbility into it

* fix getKeywordMagnitude to check for StaticAbility
This commit is contained in:
Hans Mackowiak
2024-09-07 16:19:57 +02:00
committed by GitHub
parent e7b05b2c9b
commit 4862071db7
19 changed files with 66 additions and 50 deletions

View File

@@ -1759,7 +1759,7 @@ public class ComputerUtilCard {
pumped.addPTBoost(power + berserkPower, toughness, timestamp, 0); pumped.addPTBoost(power + berserkPower, toughness, timestamp, 0);
if (!kws.isEmpty()) { if (!kws.isEmpty()) {
pumped.addChangedCardKeywords(kws, null, false, timestamp, 0, false); pumped.addChangedCardKeywords(kws, null, false, timestamp, null, false);
} }
if (!hiddenKws.isEmpty()) { if (!hiddenKws.isEmpty()) {
pumped.addHiddenExtrinsicKeywords(timestamp, 0, hiddenKws); 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? 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()); pumped.updateKeywordsCache(pumped.getCurrentState());
applyStaticContPT(ai.getGame(), pumped, new CardCollection(c)); applyStaticContPT(ai.getGame(), pumped, new CardCollection(c));
return pumped; return pumped;

View File

@@ -567,6 +567,9 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView,
} }
protected IHasSVars getSVarFallback() { protected IHasSVars getSVarFallback() {
if (this.getKeyword() != null && this.getKeyword().getStatic() != null) {
return this.getKeyword().getStatic();
}
if (getCardState() != null) if (getCardState() != null)
return getCardState(); return getCardState();
return getHostCard(); return getHostCard();

View File

@@ -485,17 +485,17 @@ public class GameAction {
if (c.getCastSA() != null && !c.getCastSA().isIntrinsic() && c.getCastSA().getKeyword() != null) { if (c.getCastSA() != null && !c.getCastSA().isIntrinsic() && c.getCastSA().getKeyword() != null) {
KeywordInterface ki = c.getCastSA().getKeyword(); KeywordInterface ki = c.getCastSA().getKeyword();
ki.setHostCard(copied); 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 // TODO hot fix for non-intrinsic offspring
Multimap<Long, KeywordInterface> addKw = MultimapBuilder.hashKeys().arrayListValues().build(); Multimap<StaticAbility, KeywordInterface> addKw = MultimapBuilder.hashKeys().arrayListValues().build();
for (KeywordInterface kw : c.getKeywords(Keyword.OFFSPRING)) { for (KeywordInterface kw : c.getKeywords(Keyword.OFFSPRING)) {
if (!kw.isIntrinsic()) { if (!kw.isIntrinsic()) {
addKw.put(kw.getStaticId(), kw); addKw.put(kw.getStatic(), kw);
} }
} }
if (!addKw.isEmpty()) { if (!addKw.isEmpty()) {
for (Map.Entry<Long, Collection<KeywordInterface>> e : addKw.asMap().entrySet()) { for (Map.Entry<StaticAbility, Collection<KeywordInterface>> e : addKw.asMap().entrySet()) {
copied.addChangedCardKeywordsInternal(e.getValue(), null, false, copied.getGameTimestamp(), e.getKey(), true); 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 // 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 (zoneTo.is(ZoneType.Stack) && cause != null && cause.isSpell() && !cause.isIntrinsic() && c.equals(cause.getHostCard())) {
if (cause.getKeyword() != null && !copied.getKeywords().contains(cause.getKeyword())) { 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);
} }
} }

View File

@@ -126,7 +126,7 @@ public abstract class AnimateEffectBase extends SpellAbilityEffect {
params.put("Category", "Keywords"); params.put("Category", "Keywords");
c.addPerpetual(params); 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 // do this after changing types in case it wasn't a creature before

View File

@@ -672,7 +672,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
if (sa.hasParam("Unearth") && movedCard.isInPlay()) { if (sa.hasParam("Unearth") && movedCard.isInPlay()) {
movedCard.setUnearthed(true); movedCard.setUnearthed(true);
movedCard.addChangedCardKeywords(Lists.newArrayList("Haste"), null, false, movedCard.addChangedCardKeywords(Lists.newArrayList("Haste"), null, false,
game.getNextTimestamp(), 0, true); game.getNextTimestamp(), null, true);
registerDelayedTrigger(sa, "Exile", Lists.newArrayList(movedCard)); registerDelayedTrigger(sa, "Exile", Lists.newArrayList(movedCard));
addLeaveBattlefieldReplacement(movedCard, sa, "Exile"); addLeaveBattlefieldReplacement(movedCard, sa, "Exile");
} }

View File

@@ -151,7 +151,7 @@ public class CloneEffect extends SpellAbilityEffect {
} }
if (!pumpKeywords.isEmpty()) { if (!pumpKeywords.isEmpty()) {
tgtCard.addChangedCardKeywords(pumpKeywords, Lists.newArrayList(), false, ts, 0); tgtCard.addChangedCardKeywords(pumpKeywords, Lists.newArrayList(), false, ts, null);
TokenEffectBase.addPumpUntil(sa, tgtCard, ts); TokenEffectBase.addPumpUntil(sa, tgtCard, ts);
} }

View File

@@ -174,7 +174,7 @@ public class ControlGainEffect extends SpellAbilityEffect {
} }
if (keywords != null) { if (keywords != null) {
tgtC.addChangedCardKeywords(keywords, Lists.newArrayList(), false, tStamp, 0); tgtC.addChangedCardKeywords(keywords, Lists.newArrayList(), false, tStamp, null);
game.fireEvent(new GameEventCardStatsChanged(tgtC)); game.fireEvent(new GameEventCardStatsChanged(tgtC));
} }

View File

@@ -150,7 +150,7 @@ public class DebuffEffect extends SpellAbilityEffect {
} }
removedKW.addAll(kws); removedKW.addAll(kws);
tgtC.addChangedCardKeywords(addedKW, removedKW, false, timestamp, 0); tgtC.addChangedCardKeywords(addedKW, removedKW, false, timestamp, null);
if (!"Permanent".equals(sa.getParam("Duration"))) { if (!"Permanent".equals(sa.getParam("Duration"))) {
final GameCommand until = new GameCommand() { final GameCommand until = new GameCommand() {

View File

@@ -86,7 +86,7 @@ public class ProtectAllEffect extends SpellAbilityEffect {
CardCollectionView list = CardLists.getValidCards(game.getCardsIn(ZoneType.Battlefield), valid, sa.getActivatingPlayer(), host, sa); CardCollectionView list = CardLists.getValidCards(game.getCardsIn(ZoneType.Battlefield), valid, sa.getActivatingPlayer(), host, sa);
for (final Card tgtC : list) { 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 (!"Permanent".equals(sa.getParam("Duration"))) {
// If not Permanent, remove protection at EOT // If not Permanent, remove protection at EOT

View File

@@ -153,7 +153,7 @@ public class ProtectEffect extends SpellAbilityEffect {
continue; continue;
} }
tgtC.addChangedCardKeywords(gainsKWList, null, false, timestamp, 0, true); tgtC.addChangedCardKeywords(gainsKWList, null, false, timestamp, null, true);
if (!"Permanent".equals(sa.getParam("Duration"))) { if (!"Permanent".equals(sa.getParam("Duration"))) {
// If not Permanent, remove protection at EOT // If not Permanent, remove protection at EOT

View File

@@ -68,7 +68,7 @@ public class PumpAllEffect extends SpellAbilityEffect {
params.put("Category", "Keywords"); params.put("Category", "Keywords");
tgtC.addPerpetual(params); tgtC.addPerpetual(params);
} }
tgtC.addChangedCardKeywords(kws, null, false, timestamp, 0); tgtC.addChangedCardKeywords(kws, null, false, timestamp, null);
} }
if (redrawPT) { if (redrawPT) {
tgtC.updatePowerToughnessForView(); tgtC.updatePowerToughnessForView();

View File

@@ -81,7 +81,7 @@ public class PumpEffect extends SpellAbilityEffect {
params.put("Category", "Keywords"); params.put("Category", "Keywords");
gameCard.addPerpetual(params); gameCard.addPerpetual(params);
} }
gameCard.addChangedCardKeywords(kws, Lists.newArrayList(), false, timestamp, 0); gameCard.addChangedCardKeywords(kws, Lists.newArrayList(), false, timestamp, null);
} }
if (!hiddenKws.isEmpty()) { if (!hiddenKws.isEmpty()) {

View File

@@ -177,7 +177,7 @@ public abstract class TokenEffectBase extends SpellAbilityEffect {
} }
if (!pumpKeywords.isEmpty()) { if (!pumpKeywords.isEmpty()) {
moved.addChangedCardKeywords(pumpKeywords, Lists.newArrayList(), false, timestamp, 0); moved.addChangedCardKeywords(pumpKeywords, Lists.newArrayList(), false, timestamp, null);
addPumpUntil(sa, moved, timestamp); addPumpUntil(sa, moved, timestamp);
} }

View File

@@ -1696,7 +1696,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
if (!Keyword.smartValueOf(counterType.toString().split(":")[0]).isMultipleRedundant()) { if (!Keyword.smartValueOf(counterType.toString().split(":")[0]).isMultipleRedundant()) {
num = getCounters(counterType); 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; return true;
} }
@@ -4657,7 +4657,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
} else if (category.equals("Keywords")) { } else if (category.equals("Keywords")) {
boolean removeAll = p.containsKey("RemoveAll") && (boolean) p.get("RemoveAll") == true; boolean removeAll = p.containsKey("RemoveAll") && (boolean) p.get("RemoveAll") == true;
addChangedCardKeywords((List<String>) p.get("AddKeywords"), Lists.newArrayList(), removeAll, addChangedCardKeywords((List<String>) p.get("AddKeywords"), Lists.newArrayList(), removeAll,
(long) p.get("Timestamp"), (long) 0); (long) p.get("Timestamp"), null);
} else if (category.equals("Types")) { } else if (category.equals("Types")) {
addChangedCardTypes((CardType) p.get("AddTypes"), (CardType) p.get("RemoveTypes"), addChangedCardTypes((CardType) p.get("AddTypes"), (CardType) p.get("RemoveTypes"),
false, (Set<RemoveType>) p.get("RemoveXTypes"), false, (Set<RemoveType>) p.get("RemoveXTypes"),
@@ -4963,7 +4963,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
KeywordInterface result = storedKeywordByText.get(triple); KeywordInterface result = storedKeywordByText.get(triple);
if (result == null) { if (result == null) {
result = ki.copy(this, false); result = ki.copy(this, false);
result.setStaticId(stAb.getId()); result.setStatic(stAb);
result.setIdx(idx); result.setIdx(idx);
result.setIntrinsic(true); result.setIntrinsic(true);
storedKeywordByText.put(triple, result); storedKeywordByText.put(triple, result);
@@ -5086,11 +5086,11 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
} }
public final void addChangedCardKeywords(final List<String> keywords, final List<String> removeKeywords, public final void addChangedCardKeywords(final List<String> keywords, final List<String> removeKeywords,
final boolean removeAllKeywords, final long timestamp, final long staticId) { final boolean removeAllKeywords, final long timestamp, final StaticAbility st) {
addChangedCardKeywords(keywords, removeKeywords, removeAllKeywords, timestamp, staticId, true); addChangedCardKeywords(keywords, removeKeywords, removeAllKeywords, timestamp, st, true);
} }
public final void addChangedCardKeywords(final List<String> keywords, final List<String> removeKeywords, public final void addChangedCardKeywords(final List<String> keywords, final List<String> 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<KeywordInterface> kws = Lists.newArrayList(); List<KeywordInterface> kws = Lists.newArrayList();
if (keywords != null) { if (keywords != null) {
long idx = 1; long idx = 1;
@@ -5104,14 +5104,14 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
} }
} }
if (canHave) { if (canHave) {
kws.add(getKeywordForStaticAbility(kw, staticId, idx)); kws.add(getKeywordForStaticAbility(kw, st, idx));
} }
idx++; idx++;
} }
} }
final KeywordsChange newCks = new KeywordsChange(kws, removeKeywords, removeAllKeywords); final KeywordsChange newCks = new KeywordsChange(kws, removeKeywords, removeAllKeywords);
changedCardKeywords.put(timestamp, staticId, newCks); changedCardKeywords.put(timestamp, st == null ? 0l : st.getId(), newCks);
if (updateView) { if (updateView) {
updateKeywords(); updateKeywords();
@@ -5120,12 +5120,13 @@ public class Card extends GameEntity implements Comparable<Card>, 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; KeywordInterface result;
long staticId = st == null ? 0 : st.getId();
Triple<String, Long, Long> triple = Triple.of(kw, staticId, idx); Triple<String, Long, Long> triple = Triple.of(kw, staticId, idx);
if (staticId < 1 || !storedKeywords.containsKey(triple)) { if (staticId < 1 || !storedKeywords.containsKey(triple)) {
result = Keyword.getInstance(kw); result = Keyword.getInstance(kw);
result.setStaticId(staticId); result.setStatic(st);
result.setIdx(idx); result.setIdx(idx);
result.createTraits(this, false); result.createTraits(this, false);
if (staticId > 0) { if (staticId > 0) {
@@ -5138,8 +5139,8 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
} }
public final void addKeywordForStaticAbility(KeywordInterface kw) { public final void addKeywordForStaticAbility(KeywordInterface kw) {
if (kw.getStaticId() > 0) { if (kw.getStatic() != null) {
storedKeywords.put(Triple.of(kw.getOriginal(), kw.getStaticId(), kw.getIdx()), kw); storedKeywords.put(Triple.of(kw.getOriginal(), (long)kw.getStatic().getId(), kw.getIdx()), kw);
} }
} }
@@ -5184,8 +5185,9 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
public final void addChangedCardKeywordsInternal( public final void addChangedCardKeywordsInternal(
final Collection<KeywordInterface> keywords, final Collection<KeywordInterface> removeKeywords, final Collection<KeywordInterface> keywords, final Collection<KeywordInterface> removeKeywords,
final boolean removeAllKeywords, 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); final KeywordsChange newCks = new KeywordsChange(keywords, removeKeywords, removeAllKeywords);
long staticId = st == null ? 0 : st.getId();
changedCardKeywords.put(timestamp, staticId, newCks); changedCardKeywords.put(timestamp, staticId, newCks);
if (updateView) { if (updateView) {
@@ -5820,6 +5822,11 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
final String s = parse[1]; final String s = parse[1];
if (StringUtils.isNumeric(s)) { if (StringUtils.isNumeric(s)) {
count += Integer.parseInt(s); count += Integer.parseInt(s);
} else {
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 { } else {
String svar = StringUtils.join(parse); String svar = StringUtils.join(parse);
if (state.hasSVar(svar)) { if (state.hasSVar(svar)) {
@@ -5827,6 +5834,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
} }
} }
} }
}
return count; return count;
} }
@@ -6568,7 +6576,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
suspectedTimestamp = getGame().getNextTimestamp(); suspectedTimestamp = getGame().getNextTimestamp();
// use this for CantHaveKeyword // use this for CantHaveKeyword
addChangedCardKeywords(ImmutableList.of("Menace"), ImmutableList.<String>of(), false, suspectedTimestamp, 0, true); addChangedCardKeywords(ImmutableList.of("Menace"), ImmutableList.<String>of(), false, suspectedTimestamp, null, true);
if (suspectedStatic == null) { if (suspectedStatic == null) {
String effect = "Mode$ CantBlockBy | ValidBlocker$ Creature.Self | Description$ CARDNAME can't block."; String effect = "Mode$ CantBlockBy | ValidBlocker$ Creature.Self | Description$ CARDNAME can't block.";
@@ -6719,7 +6727,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
new CardType(Collections.singletonList("Creature"), true), new CardType(Collections.singletonList("Creature"), true),
false, EnumSet.of(RemoveType.EnchantmentTypes), bestowTimestamp, 0, updateView, false); false, EnumSet.of(RemoveType.EnchantmentTypes), bestowTimestamp, 0, updateView, false);
addChangedCardKeywords(Collections.singletonList("Enchant creature"), Lists.newArrayList(), addChangedCardKeywords(Collections.singletonList("Enchant creature"), Lists.newArrayList(),
false, bestowTimestamp, 0, updateView); false, bestowTimestamp, null, updateView);
} }
public final void unanimateBestow() { public final void unanimateBestow() {

View File

@@ -25,7 +25,7 @@ public abstract class KeywordInstance<T extends KeywordInstance<?>> implements K
private Keyword keyword; private Keyword keyword;
private String original; private String original;
private long staticId = 0; private StaticAbility st = null;
private long idx = -1; private long idx = -1;
private List<Trigger> triggers = Lists.newArrayList(); private List<Trigger> triggers = Lists.newArrayList();
@@ -367,11 +367,11 @@ public abstract class KeywordInstance<T extends KeywordInstance<?>> implements K
} }
} }
public long getStaticId() { public StaticAbility getStatic() {
return this.staticId; return this.st;
} }
public void setStaticId(long v) { public void setStatic(StaticAbility st) {
this.staticId = v; this.st = st;
} }
public long getIdx() { public long getIdx() {

View File

@@ -23,8 +23,10 @@ public interface KeywordInterface extends Cloneable {
String getReminderText(); String getReminderText();
int getAmount(); int getAmount();
long getStaticId();
void setStaticId(long v); StaticAbility getStatic();
void setStatic(StaticAbility st);
long getIdx(); long getIdx();
void setIdx(long i); void setIdx(long i);

View File

@@ -705,7 +705,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
mana.getSourceCard().getController(), mana.getSourceCard(), null)) { mana.getSourceCard().getController(), mana.getSourceCard(), null)) {
final long timestamp = host.getGame().getNextTimestamp(); final long timestamp = host.getGame().getNextTimestamp();
final List<String> kws = Arrays.asList(mana.getAddedKeywords().split(" & ")); final List<String> kws = Arrays.asList(mana.getAddedKeywords().split(" & "));
host.addChangedCardKeywords(kws, null, false, timestamp, 0); host.addChangedCardKeywords(kws, null, false, timestamp, null);
if (mana.addsKeywordsUntil()) { if (mana.addsKeywordsUntil()) {
final GameCommand untilEOT = new GameCommand() { final GameCommand untilEOT = new GameCommand() {
private static final long serialVersionUID = -8285169579025607693L; private static final long serialVersionUID = -8285169579025607693L;
@@ -2590,7 +2590,8 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
} }
public boolean hasOptionalKeywordAmount(KeywordInterface kw) { 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) { public boolean hasOptionalKeywordAmount(Keyword kw) {
return this.optionalKeywordAmount.containsRow(kw); return this.optionalKeywordAmount.containsRow(kw);
@@ -2600,13 +2601,15 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
} }
public int getOptionalKeywordAmount(KeywordInterface kw) { 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) { public int getOptionalKeywordAmount(Keyword kw) {
return this.optionalKeywordAmount.row(kw).values().stream().mapToInt(i->i).sum(); return this.optionalKeywordAmount.row(kw).values().stream().mapToInt(i->i).sum();
} }
public void setOptionalKeywordAmount(KeywordInterface kw, int amount) { 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() { public void clearOptionalKeywordAmount() {
optionalKeywordAmount.clear(); optionalKeywordAmount.clear();

View File

@@ -770,7 +770,7 @@ public final class StaticAbilityContinuous {
} }
affectedCard.addChangedCardKeywords(newKeywords, removeKeywords, affectedCard.addChangedCardKeywords(newKeywords, removeKeywords,
removeAllAbilities, se.getTimestamp(), stAb.getId(), true); removeAllAbilities, se.getTimestamp(), stAb, true);
} }
// add HIDDEN keywords // add HIDDEN keywords

View File

@@ -2,7 +2,7 @@ Name:Fumiko the Lowblood
ManaCost:2 R R ManaCost:2 R R
Types:Legendary Creature Human Samurai Types:Legendary Creature Human Samurai
PT:3/2 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. S:Mode$ Continuous | Affected$ Card.Self | AddKeyword$ Bushido:X | Description$ CARDNAME has bushido X, where X is the number of attacking creatures.
SVar:N:Count$Valid Creature.attacking SVar:X:Count$Valid Creature.attacking
S:Mode$ MustAttack | ValidCreature$ Creature.OppCtrl | Description$ Creatures your opponents control attack each combat if able. 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. 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.