mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-16 18:58:00 +00:00
Keyword: link StaticAbility into it (#6079)
* Keyword: link StaticAbility into it * fix getKeywordMagnitude to check for StaticAbility
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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<Long, KeywordInterface> addKw = MultimapBuilder.hashKeys().arrayListValues().build();
|
||||
Multimap<StaticAbility, KeywordInterface> 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<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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -1696,7 +1696,7 @@ public class Card extends GameEntity implements Comparable<Card>, 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<Card>, IHasSVars, ITr
|
||||
} else if (category.equals("Keywords")) {
|
||||
boolean removeAll = p.containsKey("RemoveAll") && (boolean) p.get("RemoveAll") == true;
|
||||
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")) {
|
||||
addChangedCardTypes((CardType) p.get("AddTypes"), (CardType) p.get("RemoveTypes"),
|
||||
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);
|
||||
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<Card>, IHasSVars, ITr
|
||||
}
|
||||
|
||||
public final void addChangedCardKeywords(final List<String> keywords, final List<String> 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<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();
|
||||
if (keywords != null) {
|
||||
long idx = 1;
|
||||
@@ -5104,14 +5104,14 @@ public class Card extends GameEntity implements Comparable<Card>, 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<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;
|
||||
long staticId = st == null ? 0 : st.getId();
|
||||
Triple<String, Long, Long> 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<Card>, 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<Card>, IHasSVars, ITr
|
||||
public final void addChangedCardKeywordsInternal(
|
||||
final Collection<KeywordInterface> keywords, final Collection<KeywordInterface> 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<Card>, 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<Card>, IHasSVars, ITr
|
||||
suspectedTimestamp = getGame().getNextTimestamp();
|
||||
|
||||
// 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) {
|
||||
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),
|
||||
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() {
|
||||
|
||||
@@ -25,7 +25,7 @@ public abstract class KeywordInstance<T extends KeywordInstance<?>> implements K
|
||||
|
||||
private Keyword keyword;
|
||||
private String original;
|
||||
private long staticId = 0;
|
||||
private StaticAbility st = null;
|
||||
private long idx = -1;
|
||||
|
||||
private List<Trigger> triggers = Lists.newArrayList();
|
||||
@@ -366,12 +366,12 @@ public abstract class KeywordInstance<T extends 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() {
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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<String> 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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user